[vlc-commits] demux: avi: lazy load indexes if not fastseekable
Francois Cartegnie
git at videolan.org
Thu Apr 24 19:25:07 CEST 2014
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Apr 24 19:21:50 2014 +0200| [665f88b453dd7c8073b7b54448b9e7420026a973] | committer: Francois Cartegnie
demux: avi: lazy load indexes if not fastseekable
refs #1532
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=665f88b453dd7c8073b7b54448b9e7420026a973
---
modules/demux/avi/avi.c | 55 +++++++++++++++++++++++++++++++++++++++-----
modules/demux/avi/libavi.c | 50 ++++++++++++++++++++++++++++++++++++++++
modules/demux/avi/libavi.h | 1 +
3 files changed, 100 insertions(+), 6 deletions(-)
diff --git a/modules/demux/avi/avi.c b/modules/demux/avi/avi.c
index 8c23d1e..b468bb1 100644
--- a/modules/demux/avi/avi.c
+++ b/modules/demux/avi/avi.c
@@ -175,6 +175,8 @@ struct demux_sys_t
bool b_seekable;
bool b_fastseekable;
+ bool b_indexloaded; /* if we read indexes from end of file before starting */
+ uint32_t i_avih_flags;
avi_chunk_t ck_root;
bool b_odml;
@@ -374,6 +376,7 @@ static int Open( vlc_object_t * p_this )
p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
AVI_MetaLoad( p_demux, p_riff, p_avih );
+ p_sys->i_avih_flags = p_avih->i_flags;
/* now read info on each stream and create ES */
for( i = 0 ; i < i_track; i++ )
@@ -1426,19 +1429,48 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent )
if( p_sys->b_seekable )
{
+ int64_t i_pos_backup = stream_Tell( p_demux->s );
+
+ /* Check and lazy load indexes if it was not done (not fastseekable) */
+ if ( !p_sys->b_indexloaded && ( p_sys->i_avih_flags & AVIF_HASINDEX ) )
+ {
+ avi_chunk_t *p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0 );
+ if (unlikely( !p_riff ))
+ return VLC_EGENERIC;
+
+ int i_ret = AVI_ChunkFetchIndexes( p_demux->s, p_riff );
+ if ( i_ret )
+ {
+ /* Go back to position before index failure */
+ if ( stream_Tell( p_demux->s ) - i_pos_backup )
+ stream_Seek( p_demux->s, i_pos_backup );
+
+ if ( p_sys->i_avih_flags & AVIF_MUSTUSEINDEX )
+ return VLC_EGENERIC;
+ }
+ else AVI_IndexLoad( p_demux );
+
+ p_sys->b_indexloaded = true; /* we don't want to try each time */
+ }
+
if( !p_sys->i_length )
{
avi_track_t *p_stream = NULL;
unsigned i_stream = 0;
int64_t i_pos;
+ if ( !p_sys->i_movi_lastchunk_pos && /* set when index is successfully loaded */
+ ! ( p_sys->i_avih_flags & AVIF_ISINTERLEAVED ) )
+ {
+ msg_Err( p_demux, "seeking without index at %d%%"
+ " only works for interleaved files", i_percent );
+ goto failandresetpos;
+ }
/* use i_percent to create a true i_date */
- msg_Warn( p_demux, "seeking without index at %d%%"
- " only works for interleaved files", i_percent );
if( i_percent >= 100 )
{
msg_Warn( p_demux, "cannot seek so far !" );
- return VLC_EGENERIC;
+ goto failandresetpos;
}
i_percent = __MAX( i_percent, 0 );
@@ -1460,14 +1492,14 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent )
if( p_stream == NULL )
{
msg_Warn( p_demux, "cannot find any selected stream" );
- return VLC_EGENERIC;
+ goto failandresetpos;
}
/* be sure that the index exist */
if( AVI_StreamChunkSet( p_demux, i_stream, 0 ) )
{
msg_Warn( p_demux, "cannot seek" );
- return VLC_EGENERIC;
+ goto failandresetpos;
}
while( i_pos >= p_stream->idx.p_entry[p_stream->i_idxposc].i_pos +
@@ -1478,7 +1510,7 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent )
i_stream, p_stream->i_idxposc + 1 ) )
{
msg_Warn( p_demux, "cannot seek" );
- return VLC_EGENERIC;
+ goto failandresetpos;
}
}
@@ -1501,6 +1533,13 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent )
p_sys->i_time = i_date;
msg_Dbg( p_demux, "seek: %"PRId64" seconds", p_sys->i_time /1000000 );
return VLC_SUCCESS;
+
+failandresetpos:
+ /* Go back to position before index failure */
+ if ( stream_Tell( p_demux->s ) - i_pos_backup )
+ stream_Seek( p_demux->s, i_pos_backup );
+
+ return VLC_EGENERIC;
}
else
{
@@ -2296,6 +2335,8 @@ static int AVI_IndexLoad_idx1( demux_t *p_demux,
if( AVI_IndexFind_idx1( p_demux, &p_idx1, &i_offset ) )
return VLC_EGENERIC;
+ p_sys->b_indexloaded = true;
+
for( unsigned i_index = 0; i_index < p_idx1->i_entry_count; i_index++ )
{
unsigned i_cat;
@@ -2325,6 +2366,8 @@ static void __Parse_indx( demux_t *p_demux, avi_index_t *p_index, off_t *pi_max_
{
avi_entry_t index;
+ p_demux->p_sys->b_indexloaded = true;
+
msg_Dbg( p_demux, "loading subindex(0x%x) %d entries", p_indx->i_indextype, p_indx->i_entriesinuse );
if( p_indx->i_indexsubtype == 0 )
{
diff --git a/modules/demux/avi/libavi.c b/modules/demux/avi/libavi.c
index d237cfa..c8a1eff 100644
--- a/modules/demux/avi/libavi.c
+++ b/modules/demux/avi/libavi.c
@@ -202,6 +202,56 @@ static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container )
return VLC_SUCCESS;
}
+/* 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;
+
+ stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
+ if ( !b_seekable || 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 &&
+ ( 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;
+}
+
#define AVI_READCHUNK_ENTER \
int64_t i_read = __EVEN(p_chk->common.i_chunk_size ) + 8; \
if( i_read > 100000000 ) \
diff --git a/modules/demux/avi/libavi.h b/modules/demux/avi/libavi.h
index 2149223..83f004d 100644
--- a/modules/demux/avi/libavi.h
+++ b/modules/demux/avi/libavi.h
@@ -259,6 +259,7 @@ void *_AVI_ChunkFind ( avi_chunk_t *, vlc_fourcc_t, int );
int AVI_ChunkReadRoot( stream_t *, avi_chunk_t *p_root );
void AVI_ChunkFreeRoot( stream_t *, avi_chunk_t *p_chk );
+int AVI_ChunkFetchIndexes( stream_t *, avi_chunk_t *p_riff );
#define AVI_ChunkCount( p_chk, i_fourcc ) \
_AVI_ChunkCount( AVI_CHUNK(p_chk), i_fourcc )
More information about the vlc-commits
mailing list