static bool FindLength( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; int64_t i_current_pos = -1, i_size = 0, i_end = 0; if( !var_CreateGetBool( p_demux, "ps-trust-timestamps" ) ) return true; if( p_sys->i_length == VLC_TICK_INVALID ) /* First time */ { p_sys->i_length = VLC_TICK_0; /* Check beginning */ int i = 0; i_current_pos = vlc_stream_Tell( p_demux->s ); while( i < 40 && Probe( p_demux, false ) > 0 ) i++; /* Check end */ i_size = stream_Size( p_demux->s ); i_end = VLC_CLIP( i_size, 0, 200000 ); if( vlc_stream_Seek( p_demux->s, i_size - i_end ) == VLC_SUCCESS ) { i = 0; while( i < 400 && Probe( p_demux, true ) > 0 ) i++; if( i_current_pos >= 0 && vlc_stream_Seek( p_demux->s, i_current_pos ) != VLC_SUCCESS ) return false; } else return false; } /* Find the longest track */ for( int i = 0; i < PS_TK_COUNT; i++ ) { ps_track_t *tk = &p_sys->tk[i]; if( tk->i_first_pts != VLC_TICK_INVALID && tk->i_last_pts > tk->i_first_pts ) { vlc_tick_t i_length = tk->i_last_pts - tk->i_first_pts; if( i_length > p_sys->i_length ) { p_sys->i_length = i_length; p_sys->i_time_track_index = i; msg_Dbg( p_demux, "we found a length of: %"PRId64 "s", SEC_FROM_VLC_TICK(p_sys->i_length) ); } } } return true; }
static ssize_t SeekCallback(struct archive *p_archive, void *p_object, ssize_t i_offset, int i_whence) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; access_sys_t *p_sys = p_data->p_access->p_sys; ssize_t i_pos; switch(i_whence) { case SEEK_CUR: i_pos = vlc_stream_Tell(p_sys->p_stream); break; case SEEK_SET: i_pos = 0; break; case SEEK_END: i_pos = stream_Size(p_sys->p_stream) - 1; break; default: return -1; } if (i_pos < 0) return -1; vlc_stream_Seek(p_sys->p_stream, i_pos + i_offset); /* We don't care about return val */ return vlc_stream_Tell(p_sys->p_stream); }
static int Seek(access_t *access, uint64_t position) { access_sys_t *sys = access->p_sys; const rar_file_t *file = sys->file; if (position > file->real_size) position = file->real_size; sys->position = position; /* Search the chunk */ const rar_file_chunk_t *old_chunk = sys->chunk; for (int i = 0; i < file->chunk_count; i++) { sys->chunk = file->chunk[i]; if (position < sys->chunk->cummulated_size + sys->chunk->size) break; } const uint64_t offset = sys->chunk->offset + (position - sys->chunk->cummulated_size); if (strcmp(old_chunk->mrl, sys->chunk->mrl)) { if (sys->s) vlc_stream_Delete(sys->s); sys->s = vlc_stream_NewMRL(access, sys->chunk->mrl); } return sys->s ? vlc_stream_Seek(sys->s, offset) : VLC_EGENERIC; }
static int Seek( stream_t *s, uint64_t offset ) { stream_sys_t *p_sys = s->p_sys; assert( p_sys->b_seek ); return vlc_stream_Seek( s->p_source, offset ); }
static int Seek( stream_t *p_stream, uint64_t i_pos ) { int i_ret = vlc_stream_Seek( p_stream->s, i_pos ); if ( i_ret == VLC_SUCCESS ) RemainFlush( p_stream->p_sys ); return i_ret; }
static ssize_t SkipCallback(struct archive *p_archive, void *p_object, ssize_t i_request) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; access_sys_t *p_sys = p_data->p_access->p_sys; ssize_t i_skipped = 0; /* be smart as small seeks converts to reads */ if (p_sys->b_source_canseek) { int64_t i_pos = vlc_stream_Tell(p_sys->p_stream); if (i_pos >=0) vlc_stream_Seek(p_sys->p_stream, i_pos + i_request); i_skipped = vlc_stream_Tell(p_sys->p_stream) - i_pos; } else while(i_request) { int i_skip = __MIN(INT32_MAX, i_request); int i_read = vlc_stream_Read(p_sys->p_stream, NULL, i_skip); if (i_read > 0) i_skipped += i_read; else break; i_request -= i_read; } return i_skipped; }
/***************************************************************************** * Control: *****************************************************************************/ static int Control( demux_t *p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; uint64_t i_old_offset = vlc_stream_Tell( p_demux->s ); int i_ret = demux_vaControlHelper( p_demux->s, 0, -1, 8*CDG_FRAME_SIZE*CDG_FRAME_RATE, CDG_FRAME_SIZE, i_query, args ); if( !i_ret && ( i_query == DEMUX_SET_POSITION || i_query == DEMUX_SET_TIME ) ) { date_Set( &p_sys->pts, PosToDate( p_demux ) ); if ( i_old_offset > vlc_stream_Tell( p_demux->s ) ) i_ret = vlc_stream_Seek( p_demux->s, 0 ); else i_ret = vlc_stream_Seek( p_demux->s, i_old_offset ); } return i_ret; }
/** ************************************************************************** * \brief seek in the stream * \param opaque should be the stream * \param stream stream created by ZipIO_Open * \param offset positive offset to seek * \param origin current position in stream * \return ¿ VLC_SUCCESS or an error code ? *****************************************************************************/ static long ZCALLBACK ZipIO_Seek ( void *opaque, void *stream, unsigned long offset, int origin ) { (void) stream; stream_t *s = (stream_t*) opaque; long l_ret; uint64_t pos = offset + origin; l_ret = (long) vlc_stream_Seek( s->p_source, pos ); return l_ret; }
/***************************************************************************** * Import_M3U: main import function *****************************************************************************/ int Import_M3U( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t *)p_this; const uint8_t *p_peek; char *(*pf_dup) (const char *) = GuessEncoding; int offset = 0; CHECK_FILE(); if( vlc_stream_Peek( p_demux->s, &p_peek, 3 ) == 3 && !memcmp( p_peek, "\xef\xbb\xbf", 3) ) { pf_dup = CheckUnicode; /* UTF-8 Byte Order Mark */ offset = 3; } if( demux_IsPathExtension( p_demux, ".m3u8" ) || demux_IsForced( p_demux, "m3u8" ) || CheckContentType( p_demux->s, "application/vnd.apple.mpegurl" ) ) pf_dup = CheckUnicode; /* UTF-8 file type */ else if( demux_IsPathExtension( p_demux, ".m3u" ) || demux_IsPathExtension( p_demux, ".vlc" ) || demux_IsForced( p_demux, "m3u" ) || ContainsURL( p_demux ) || CheckContentType( p_demux->s, "audio/x-mpegurl") ) ; /* Guess encoding */ else { if( vlc_stream_Peek( p_demux->s, &p_peek, 8 + offset ) < (8 + offset) ) return VLC_EGENERIC; p_peek += offset; if( !strncasecmp( (const char *)p_peek, "RTSPtext", 8 ) ) /* QuickTime */ pf_dup = CheckUnicode; /* UTF-8 */ else if( !memcmp( p_peek, "#EXTM3U", 7 ) ) ; /* Guess encoding */ else return VLC_EGENERIC; } vlc_stream_Seek( p_demux->s, offset ); STANDARD_DEMUX_INIT_MSG( "found valid M3U playlist" ); p_demux->p_sys->psz_prefix = FindPrefix( p_demux ); p_demux->p_sys->pf_dup = pf_dup; return VLC_SUCCESS; }
static int64_t IOSeek( void *opaque, int64_t offset, int whence ) { demux_t *p_demux = opaque; int64_t i_absolute; int64_t i_size = stream_Size( p_demux->s ); #ifdef AVFORMAT_DEBUG msg_Warn( p_demux, "IOSeek offset: %"PRId64", whence: %i", offset, whence ); #endif switch( whence ) { #ifdef AVSEEK_SIZE case AVSEEK_SIZE: return i_size; #endif case SEEK_SET: i_absolute = (int64_t)offset; break; case SEEK_CUR: i_absolute = vlc_stream_Tell( p_demux->s ) + (int64_t)offset; break; case SEEK_END: i_absolute = i_size + (int64_t)offset; break; default: return -1; } if( i_absolute < 0 ) { msg_Dbg( p_demux, "Trying to seek before the beginning" ); return -1; } if( i_size > 0 && i_absolute >= i_size ) { msg_Dbg( p_demux, "Trying to seek too far : EOF?" ); return -1; } if( vlc_stream_Seek( p_demux->s, i_absolute ) ) { msg_Warn( p_demux, "we were not allowed to seek, or EOF " ); return -1; } return vlc_stream_Tell( p_demux->s ); }
/* Allow to append indexes after starting playback */ int AVI_ChunkFetchIndexes( stream_t *s, avi_chunk_t *p_riff ) { avi_chunk_t *p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 ); if ( !p_movi ) return VLC_EGENERIC; avi_chunk_t *p_chk; uint64_t i_indexpos = 8 + p_movi->common.i_chunk_pos + p_movi->common.i_chunk_size; bool b_seekable = false; int i_ret = VLC_SUCCESS; vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable ); if ( !b_seekable || vlc_stream_Seek( s, i_indexpos ) ) return VLC_EGENERIC; for( ; ; ) { p_chk = xmalloc( sizeof( avi_chunk_t ) ); memset( p_chk, 0, sizeof( avi_chunk_t ) ); if (unlikely( !p_riff->common.p_first )) p_riff->common.p_first = p_chk; else p_riff->common.p_last->common.p_next = p_chk; p_riff->common.p_last = p_chk; i_ret = AVI_ChunkRead( s, p_chk, p_riff ); if( i_ret ) break; if( p_chk->common.p_father->common.i_chunk_size > 0 && ( vlc_stream_Tell( s ) > (off_t)p_chk->common.p_father->common.i_chunk_pos + (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) ) { break; } /* If we can't seek then stop when we 've found any index */ if( p_chk->common.i_chunk_fourcc == AVIFOURCC_indx || p_chk->common.i_chunk_fourcc == AVIFOURCC_idx1 ) { break; } } return i_ret; }
static int archive_extractor_reset( stream_extractor_t* p_extractor ) { private_sys_t* p_sys = p_extractor->p_sys; if( vlc_stream_Seek( p_extractor->source, 0 ) || archive_clean( p_sys ) || archive_init( p_sys, p_extractor->source ) || archive_seek_subentry( p_sys, p_extractor->identifier ) ) { p_sys->b_dead = true; return VLC_EGENERIC; } p_sys->i_offset = 0; p_sys->b_eof = false; p_sys->b_dead = false; return VLC_SUCCESS; }
static int libarchive_exit_cb( libarchive_t* p_arc, void* p_obj ) { VLC_UNUSED( p_arc ); libarchive_callback_t* p_cb = (libarchive_callback_t*)p_obj; if( p_cb->p_sys->source == p_cb->p_source ) { /* DO NOT CLOSE OUR MOTHER STREAM */ if( !p_cb->p_sys->b_dead && vlc_stream_Seek( p_cb->p_source, 0 ) ) return ARCHIVE_FATAL; } else if( p_cb->p_source ) { vlc_stream_Delete( p_cb->p_source ); p_cb->p_source = NULL; } return ARCHIVE_OK; }
static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk ) { avi_chunk_t chk; if( !p_chk ) { if( AVI_ChunkReadCommon( s, &chk ) ) { return VLC_EGENERIC; } p_chk = &chk; } if( p_chk->common.p_father ) { if( p_chk->common.p_father->common.i_chunk_pos + __EVEN( p_chk->common.p_father->common.i_chunk_size ) + 8 < p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8 ) { return VLC_EGENERIC; } } bool b_seekable = false; uint64_t i_offset = p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8; if ( !vlc_stream_Control(s, STREAM_CAN_SEEK, &b_seekable) && b_seekable ) { return vlc_stream_Seek( s, i_offset ); } else { ssize_t i_read = i_offset - vlc_stream_Tell( s ); return (i_read >=0 && vlc_stream_Read( s, NULL, i_read ) == i_read) ? VLC_SUCCESS : VLC_EGENERIC; } }
static int Control(demux_t *demux, int query, va_list args) { demux_sys_t *sys = demux->p_sys; switch(query) { case DEMUX_CAN_SEEK: return vlc_stream_vaControl(demux->s, query, args); case DEMUX_GET_LENGTH: { int64_t *l = va_arg(args, int64_t *); *l = sys->count > 0 ? sys->index[sys->count-1].stop : 0; return VLC_SUCCESS; } case DEMUX_GET_TIME: { int64_t *t = va_arg(args, int64_t *); *t = sys->current < sys->count ? sys->index[sys->count-1].start : 0; return VLC_SUCCESS; } case DEMUX_SET_NEXT_DEMUX_TIME: { sys->next_date = va_arg(args, int64_t); return VLC_SUCCESS; } case DEMUX_SET_TIME: { int64_t t = va_arg(args, int64_t); sys->current = 0; while (sys->current < sys->count) { if (sys->index[sys->current].stop > t) { vlc_stream_Seek(demux->s, 1024 + 128LL * sys->index[sys->current].index); break; } sys->current++; } return VLC_SUCCESS; } case DEMUX_SET_POSITION: case DEMUX_GET_POSITION: default: return VLC_EGENERIC; } }
static la_int64_t libarchive_skip_cb( libarchive_t* p_arc, void* p_obj, off_t i_request ) { VLC_UNUSED( p_arc ); libarchive_callback_t* p_cb = (libarchive_callback_t*)p_obj; stream_t* p_source = p_cb->p_source; private_sys_t* p_sys = p_cb->p_sys; /* TODO: fix b_seekable_source on libarchive_callback_t */ if( p_sys->b_seekable_source ) { if( vlc_stream_Seek( p_source, vlc_stream_Tell( p_source ) + i_request ) ) return ARCHIVE_FATAL; return i_request; } ssize_t i_read = vlc_stream_Read( p_source, NULL, i_request ); return i_read >= 0 ? i_read : ARCHIVE_FATAL; }
static la_int64_t libarchive_seek_cb( libarchive_t* p_arc, void* p_obj, la_int64_t offset, int whence ) { VLC_UNUSED( p_arc ); libarchive_callback_t* p_cb = (libarchive_callback_t*)p_obj; stream_t* p_source = p_cb->p_source; ssize_t whence_pos; switch( whence ) { case SEEK_SET: whence_pos = 0; break; case SEEK_CUR: whence_pos = vlc_stream_Tell( p_source ); break; case SEEK_END: whence_pos = stream_Size( p_source ); break; default: vlc_assert_unreachable(); } if( whence_pos < 0 || vlc_stream_Seek( p_source, whence_pos + offset ) ) return ARCHIVE_FATAL; return vlc_stream_Tell( p_source ); }
int RarAccessOpen(vlc_object_t *object) { access_t *access = (access_t*)object; const char *name = strchr(access->psz_location, '|'); if (name == NULL) return VLC_EGENERIC; char *base = strndup(access->psz_location, name - access->psz_location); if (unlikely(base == NULL)) return VLC_ENOMEM; name++; vlc_uri_decode(base); stream_t *s = vlc_stream_NewMRL(access, base); if (!s || RarProbe(s)) goto error; struct { int filescount; rar_file_t **files; unsigned int i_nbvols; } newscheme = { 0, NULL, 0 }, oldscheme = { 0, NULL, 0 }, *p_scheme; if (RarParse(s, &newscheme.filescount, &newscheme.files, &newscheme.i_nbvols, false) || newscheme.filescount < 1 || newscheme.i_nbvols < 2 ) { /* We might want to lookup old naming scheme, could be a part1.rar,part1.r00 */ vlc_stream_Seek(s, 0); RarParse(s, &oldscheme.filescount, &oldscheme.files, &oldscheme.i_nbvols, true); } if (oldscheme.filescount >= newscheme.filescount && oldscheme.i_nbvols > newscheme.i_nbvols) { for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); p_scheme = &oldscheme; msg_Dbg(s, "using rar old naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else if (newscheme.filescount) { for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); p_scheme = &newscheme; msg_Dbg(s, "using rar new naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else { msg_Info(s, "Invalid or unsupported RAR archive"); for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); goto error; } rar_file_t *file = NULL; for (int i = 0; i < p_scheme->filescount; i++) { if (!file && !strcmp(p_scheme->files[i]->name, name)) file = p_scheme->files[i]; else RarFileDelete(p_scheme->files[i]); } free(p_scheme->files); if (!file) goto error; access_sys_t *sys = access->p_sys = malloc(sizeof(*sys)); sys->s = s; sys->file = file; access->pf_read = Read; access->pf_block = NULL; access->pf_control = Control; access->pf_seek = Seek; rar_file_chunk_t dummy = { .mrl = base, }; sys->chunk = &dummy; Seek(access, 0); free(base); return VLC_SUCCESS; error: if (s) vlc_stream_Delete(s); free(base); return VLC_EGENERIC; }
/***************************************************************************** * Control: *****************************************************************************/ static int Control( demux_t *p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; double f, *pf; int64_t i64; int i_ret; switch( i_query ) { case DEMUX_CAN_SEEK: *va_arg( args, bool * ) = p_sys->b_seekable; return VLC_SUCCESS; case DEMUX_GET_TITLE: *va_arg( args, int * ) = p_sys->current_title; return VLC_SUCCESS; case DEMUX_GET_SEEKPOINT: *va_arg( args, int * ) = p_sys->current_seekpoint; return VLC_SUCCESS; case DEMUX_GET_POSITION: pf = va_arg( args, double * ); i64 = stream_Size( p_demux->s ) - p_sys->i_start_byte; if( i64 > 0 ) { double current = vlc_stream_Tell( p_demux->s ) - p_sys->i_start_byte; *pf = current / (double)i64; } else { *pf = 0.0; } return VLC_SUCCESS; case DEMUX_SET_POSITION: f = va_arg( args, double ); i64 = stream_Size( p_demux->s ) - p_sys->i_start_byte; p_sys->i_current_pts = VLC_TICK_INVALID; p_sys->i_scr = VLC_TICK_INVALID; if( p_sys->format == CDXA_PS ) { i64 = (int64_t)(i64 * f); /* Align to sector payload */ i64 = p_sys->i_start_byte + i64 - (i64 % CDXA_SECTOR_SIZE) + CDXA_SECTOR_HEADER_SIZE; } else { i64 = p_sys->i_start_byte + (int64_t)(i64 * f); } i_ret = vlc_stream_Seek( p_demux->s, i64 ); if( i_ret == VLC_SUCCESS ) { NotifyDiscontinuity( p_sys->tk, p_demux->out ); return i_ret; } break; case DEMUX_GET_TIME: if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID ) { *va_arg( args, vlc_tick_t * ) = p_sys->i_current_pts - p_sys->tk[p_sys->i_time_track_index].i_first_pts; return VLC_SUCCESS; } if( p_sys->i_first_scr != VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID ) { vlc_tick_t i_time = p_sys->i_scr - p_sys->i_first_scr; /* H.222 2.5.2.2 */ if( p_sys->i_mux_rate > 0 && p_sys->b_have_pack ) { uint64_t i_offset = vlc_stream_Tell( p_demux->s ) - p_sys->i_lastpack_byte; i_time += vlc_tick_from_samples(i_offset, p_sys->i_mux_rate * 50); } *va_arg( args, vlc_tick_t * ) = i_time; return VLC_SUCCESS; } *va_arg( args, vlc_tick_t * ) = 0; break; case DEMUX_GET_LENGTH: if( p_sys->i_length > VLC_TICK_0 ) { *va_arg( args, vlc_tick_t * ) = p_sys->i_length; return VLC_SUCCESS; } else if( p_sys->i_mux_rate > 0 ) { *va_arg( args, vlc_tick_t * ) = vlc_tick_from_samples( stream_Size( p_demux->s ) - p_sys->i_start_byte / 50, p_sys->i_mux_rate ); return VLC_SUCCESS; } *va_arg( args, vlc_tick_t * ) = 0; break; case DEMUX_SET_TIME: { if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID && p_sys->i_length > VLC_TICK_0) { vlc_tick_t i_time = va_arg( args, vlc_tick_t ); i_time -= p_sys->tk[p_sys->i_time_track_index].i_first_pts; return demux_Control( p_demux, DEMUX_SET_POSITION, (double) i_time / p_sys->i_length ); } break; } case DEMUX_GET_TITLE_INFO: { struct input_title_t ***v = va_arg( args, struct input_title_t*** ); int *c = va_arg( args, int * ); *va_arg( args, int* ) = 0; /* Title offset */ *va_arg( args, int* ) = 0; /* Chapter offset */ return vlc_stream_Control( p_demux->s, STREAM_GET_TITLE_INFO, v, c ); } case DEMUX_SET_TITLE: return vlc_stream_vaControl( p_demux->s, STREAM_SET_TITLE, args ); case DEMUX_SET_SEEKPOINT: return vlc_stream_vaControl( p_demux->s, STREAM_SET_SEEKPOINT, args ); case DEMUX_TEST_AND_CLEAR_FLAGS: { unsigned *restrict flags = va_arg(args, unsigned *); *flags &= p_sys->updates; p_sys->updates &= ~*flags; return VLC_SUCCESS; } case DEMUX_GET_META: return vlc_stream_vaControl( p_demux->s, STREAM_GET_META, args ); case DEMUX_GET_FPS: break; case DEMUX_CAN_PAUSE: case DEMUX_SET_PAUSE_STATE: case DEMUX_CAN_CONTROL_PACE: case DEMUX_GET_PTS_DELAY: return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args ); default: break; } return VLC_EGENERIC; }
static int ControlSetTime( demux_t *p_demux, int64_t i_time ) { demux_sys_t *p_sys = p_demux->p_sys; bool b_seekable; int i; /* */ vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable ); if( !b_seekable ) return VLC_EGENERIC; const mtime_t i_length = ControlGetLength( p_demux ); if( i_length <= 0 ) return VLC_EGENERIC; const uint64_t i_stream_size = stream_Size( p_demux->s ); if( i_stream_size <= p_sys->i_data_pos ) return VLC_EGENERIC; const double i_bytemicrorate = (double) i_length / (i_stream_size - p_sys->i_data_pos); if( i_bytemicrorate == 0 ) return VLC_EGENERIC; uint64_t i_lower = p_sys->i_data_pos; uint64_t i_upper = i_stream_size; uint64_t i_start_pos; assert( p_sys->i_seekpoint > 0 ); /* ReadMeta ensure at least (0,0) */ if( p_sys->i_seekpoint > 1 ) { /* lookup base offset */ for( i = p_sys->i_seekpoint-1; i >= 0; i-- ) { if( p_sys->seekpoint[i]->i_time_offset <= i_time ) break; } i_lower = p_sys->seekpoint[0]->i_byte_offset + p_sys->i_data_pos; if( i+1 < p_sys->i_seekpoint ) i_upper = p_sys->seekpoint[i+1]->i_byte_offset + p_sys->i_data_pos; i_start_pos = i_lower; } else { i_start_pos = i_time / i_bytemicrorate; } if( VLC_SUCCESS != vlc_stream_Seek( p_demux->s, i_start_pos ) ) return VLC_EGENERIC; int i_ret = RefineSeek( p_demux, i_time, i_bytemicrorate, i_lower, i_upper ); if( i_ret == VLC_SUCCESS ) { p_sys->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY; Reset( p_sys ); es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_time ); } return i_ret; }
static int RefineSeek( demux_t *p_demux, mtime_t i_time, double i_bytemicrorate, uint64_t i_lowpos, uint64_t i_highpos ) { demux_sys_t *p_sys = p_demux->p_sys; bool b_found = false; block_t *p_block_out; block_t *p_block_in; unsigned i_frame_size = FLAC_MIN_FRAME_SIZE; bool b_canfastseek = false; (int) vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_canfastseek ); uint64_t i_start_pos = vlc_stream_Tell( p_demux->s ); while( !b_found ) { FlushPacketizer( p_sys->p_packetizer ); p_block_out = NULL; p_block_in = NULL; while( !p_block_out ) { if( !p_block_in ) { if( !(p_block_in = vlc_stream_Block( p_demux->s, i_frame_size )) ) break; } p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in ); } if( !p_block_out ) { if( p_block_in ) block_Release( p_block_in ); break; } if( p_block_out->i_buffer > i_frame_size ) i_frame_size = p_block_out->i_buffer; /* If we are further than wanted block */ if( p_block_out->i_dts >= i_time ) { mtime_t i_diff = p_block_out->i_dts - i_time; /* Not in acceptable approximation range */ if( i_diff > CLOCK_FREQ / 10 && i_diff / i_bytemicrorate > i_frame_size ) { i_highpos = i_start_pos; i_start_pos -= ( i_diff / i_bytemicrorate ); i_start_pos = __MAX(i_start_pos, i_lowpos + i_frame_size); } else b_found = true; } else if( p_block_out->i_dts < i_time ) { mtime_t i_diff = i_time - p_block_out->i_dts; /* Not in acceptable NEXT_TIME demux range */ if( i_diff >= ((b_canfastseek) ? FLAC_MAX_PREROLL : FLAC_MAX_SLOW_PREROLL) && i_diff / i_bytemicrorate > i_frame_size ) { i_lowpos = i_start_pos; i_start_pos += ( i_diff / i_bytemicrorate ); i_start_pos = __MIN(i_start_pos, i_highpos - i_frame_size); } else b_found = true; } if( p_block_out ) block_Release( p_block_out ); if( p_block_in ) block_Release( p_block_in ); if( !b_found ) { if( i_highpos < i_lowpos || i_highpos - i_lowpos < i_frame_size ) break; if( VLC_SUCCESS != vlc_stream_Seek( p_demux->s, i_start_pos ) ) break; } } return b_found ? VLC_SUCCESS : VLC_EGENERIC; }
static int Seek( stream_t *s, uint64_t offset ) { return vlc_stream_Seek( s->p_source, offset ); }
static int Open(vlc_object_t *object) { demux_t *demux = (demux_t*)object; const uint8_t *peek; if (vlc_stream_Peek(demux->s, &peek, 11) != 11) return VLC_EGENERIC; bool is_stl_25 = !memcmp(&peek[3], "STL25.01", 8); bool is_stl_30 = !memcmp(&peek[3], "STL30.01", 8); if (!is_stl_25 && !is_stl_30) return VLC_EGENERIC; const double fps = is_stl_25 ? 25 : 30; uint8_t header[1024]; if (vlc_stream_Read(demux->s, header, sizeof(header)) != sizeof(header)) { msg_Err(demux, "Incomplete EBU STL header"); return VLC_EGENERIC; } const int cct = ParseInteger(&header[12], 2); const mtime_t program_start = ParseTextTimeCode(&header[256], fps); const int tti_count = ParseInteger(&header[238], 5); msg_Dbg(demux, "Detected EBU STL : CCT=%d TTI=%d start=%8.8s %"PRId64, cct, tti_count, &header[256], program_start); demux_sys_t *sys = xmalloc(sizeof(*sys)); sys->next_date = 0; sys->current = 0; sys->count = 0; sys->index = xcalloc(tti_count, sizeof(*sys->index)); bool comment = false; stl_entry_t *s = &sys->index[0]; s->count = 0; for (int i = 0; i < tti_count; i++) { uint8_t tti[16]; if (vlc_stream_Read(demux->s, tti, 16) != 16 || vlc_stream_Read(demux->s, NULL, 112) != 112) { msg_Warn(demux, "Incomplete EBU STL file"); break; } const int ebn = tti[3]; if (ebn >= 0xf0 && ebn <= 0xfd) continue; if (ebn == 0xfe) continue; if (s->count <= 0) { comment = tti[15] != 0; s->start = ParseTimeCode(&tti[5], fps) - program_start; s->stop = ParseTimeCode(&tti[9], fps) - program_start; s->index = i; } s->count++; if (ebn == 0xff && !comment) s = &sys->index[++sys->count]; if (ebn == 0xff && sys->count < tti_count) s->count = 0; } if (sys->count > 0) vlc_stream_Seek(demux->s, 1024 + 128LL * sys->index[0].index); es_format_t fmt; es_format_Init(&fmt, SPU_ES, VLC_CODEC_EBU_STL); fmt.i_extra = sizeof(header); fmt.p_extra = header; sys->es = es_out_Add(demux->out, &fmt); fmt.i_extra = 0; fmt.p_extra = NULL; es_format_Clean(&fmt); demux->p_sys = sys; demux->pf_demux = Demux; demux->pf_control = Control; return VLC_SUCCESS; }