[vlc-devel] [PATCH] demux/mp4: (asking for pre-review) add support of fMP4

Frédéric Yhuel fyhuel at viotech.net
Wed Jan 25 15:55:18 CET 2012


This is not a patch to be merged, I'm just seeking advices before
continuing further.

This also to answer a "pix or didn't happen" on irc ;-)

Most of the modifications are framed by #ifdef fMP4 / #endif, because it
was an easy way to hack into the MP4 demux.

It works with Smooth Streaming, but probably not (yet) with DASH.

Moreover it works only with constant quality streams, though the aim of
this work is to enable adaptation in Smooth Streaming and DASH.
---
 modules/demux/mp4/libmp4.c |   64 +++++++++
 modules/demux/mp4/libmp4.h |   11 ++-
 modules/demux/mp4/mp4.c    |  323 +++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 380 insertions(+), 18 deletions(-)

diff --git a/modules/demux/mp4/libmp4.c b/modules/demux/mp4/libmp4.c
index 600c171..dca755f 100644
--- a/modules/demux/mp4/libmp4.c
+++ b/modules/demux/mp4/libmp4.c
@@ -311,6 +311,10 @@ static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
         if( !p_container->p_first ) p_container->p_first = p_box;
         else p_container->p_last->p_next = p_box;
         p_container->p_last = p_box;
+#ifdef fMP4
+        if( p_box->i_type == ATOM_moov )
+            break;
+#endif
 
     } while( MP4_NextBox( p_stream, p_box ) == 1 );
 
@@ -3327,6 +3331,66 @@ void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
     free( p_box );
 }
 
+MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s, unsigned i_tk_id )
+{
+    /* p_chunk is a virtual root container for the moof and mdat boxes */
+    MP4_Box_t *p_chunk;
+    MP4_Box_t *p_moof;
+    MP4_Box_t *p_mdat;
+
+    p_chunk = malloc( sizeof( MP4_Box_t ) );
+    p_mdat = malloc( sizeof( MP4_Box_t ) );
+    if( unlikely( p_chunk == NULL || p_mdat == NULL ) )
+        return NULL;
+
+    p_chunk->i_type = ATOM_root;
+    p_chunk->i_shortsize = 1;
+
+    p_chunk->data.p_data = NULL;
+    p_chunk->p_father    = NULL;
+    p_chunk->p_first     = NULL;
+    p_chunk->p_last      = NULL;
+    p_chunk->p_next      = NULL;
+
+    p_moof = MP4_ReadBox( s, p_chunk );
+    /* we need to know the size of the mdat */
+    MP4_ReadBoxCommon( s, p_mdat );
+
+    if( p_moof )
+    {
+        p_chunk->p_first = p_moof;
+        p_moof->p_next = p_mdat;
+        p_chunk->p_last = p_mdat;
+    }
+    else
+    {
+        msg_Warn( s, "no moof box found!");
+        return NULL;
+    }
+
+    if( i_tk_id == 0)
+        goto end;
+
+    MP4_Box_t *p_tfhd = MP4_BoxGet( p_moof, "traf/tfhd");
+    if( p_tfhd == NULL)
+    {
+        msg_Warn( s, "no tfhd box found!");
+        return NULL;
+    }
+    unsigned i_track_ID = p_tfhd->data.p_tfhd->i_track_ID;
+    if( i_track_ID == i_tk_id )
+        goto end;
+
+    stream_Read( s, NULL, p_mdat->i_size );
+    MP4_BoxFree( s, p_chunk );
+    msg_Dbg( s, "re-entering MP4_BoxGetNextChunk" );
+    return MP4_BoxGetNextChunk( s, i_tk_id );
+
+end:
+    return p_chunk;
+}
+
+
 /*****************************************************************************
  * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
  *****************************************************************************
diff --git a/modules/demux/mp4/libmp4.h b/modules/demux/mp4/libmp4.h
index 99c81c9..c9c534d 100644
--- a/modules/demux/mp4/libmp4.h
+++ b/modules/demux/mp4/libmp4.h
@@ -245,7 +245,8 @@
 #define ATOM_chap VLC_FOURCC( 'c', 'h', 'a', 'p' )
 
 /* Do you want some debug information on all read boxes ? */
-//#define MP4_VERBOSE  1
+#define MP4_VERBOSE  1
+#define fMP4 1
 
 
 struct MP4_Box_s;
@@ -1157,6 +1158,14 @@ typedef struct MP4_Box_s
 } MP4_Box_t;
 
 
+/*****************************************************************************
+ * MP4_BoxGetNextChunk : Parse the entire moof box.
+ *****************************************************************************
+ *  The first box is a virtual box "root".
+ *  if i_tk_id > 0, then seek to the next chunk, until
+ *  i_tk_id match the tfhd's id of the traf box.
+ *****************************************************************************/
+MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s, unsigned i_tk_id);
 
 /*****************************************************************************
  * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c
index 1a27482..41445bb 100644
--- a/modules/demux/mp4/mp4.c
+++ b/modules/demux/mp4/mp4.c
@@ -35,6 +35,7 @@
 #include <vlc_charset.h>                           /* EnsureUTF8 */
 #include <vlc_meta.h>                              /* vlc_meta_t, vlc_meta_ */
 #include <vlc_input.h>
+#include <assert.h>
 
 #include "libmp4.h"
 #include "drms.h"
@@ -67,6 +68,7 @@ static int   Control ( demux_t *, int, va_list );
 typedef struct
 {
     uint64_t     i_offset; /* absolute position of this chunk in the file */
+    uint64_t     i_next_ck_offset;
     uint32_t     i_sample_description_index; /* index for SampleEntry to use */
     uint32_t     i_sample_count; /* how many samples in this chunk */
     uint32_t     i_sample_first; /* index of the first sample in this chunk */
@@ -83,6 +85,7 @@ typedef struct
     uint32_t     *p_sample_count_pts;
     int32_t      *p_sample_offset_pts;  /* pts-dts */
 
+    uint32_t     *p_sample_size;
     /* TODO if needed add pts
         but quickly *add* support for edts and seeking */
 
@@ -136,6 +139,7 @@ typedef struct
     MP4_Box_t *p_sample;/* point on actual sdsd */
 
     bool b_drms;
+    bool end_of_chunk;
     void      *p_drms;
     MP4_Box_t *p_skcr;
 
@@ -155,6 +159,14 @@ struct demux_sys_t
     unsigned int i_tracks;       /* number of tracks */
     mp4_track_t  *track;         /* array of track */
     float        f_fps;          /* number of frame per seconds */
+    mp4_chunk_t **chunks;        /* chunks[i] is a pointer to the current
+                                    chunk of the track whose track_ID is i */
+    uint32_t    *pi_sample_first;/* i_sample_first of the next chunk */
+    uint64_t    *pi_first_dts;    /* i_first_dts of the next chunk */
+
+                                /* XXX use dictionaries instead */
+    int *map;                   /* map track_IDs to table indexes. map[0]
+                            is the last index used (track_ID cannot be 0) */
 
     /* */
     MP4_Box_t    *p_tref_chap;
@@ -166,6 +178,7 @@ struct demux_sys_t
 /*****************************************************************************
  * Declaration of local function
  *****************************************************************************/
+static int GetChunk( demux_t *, MP4_Box_t * );
 static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t  *, bool b_force_enable );
 static void MP4_TrackDestroy(  mp4_track_t * );
 
@@ -174,8 +187,8 @@ static void MP4_TrackUnselect(demux_t *, mp4_track_t * );
 
 static int  MP4_TrackSeek   ( demux_t *, mp4_track_t *, mtime_t );
 
-static uint64_t MP4_TrackGetPos    ( mp4_track_t * );
-static int      MP4_TrackSampleSize( mp4_track_t * );
+static uint64_t MP4_TrackGetPos    ( demux_t *, mp4_track_t * );
+static int      MP4_TrackSampleSize( demux_t *, mp4_track_t * );
 static int      MP4_TrackNextSample( demux_t *, mp4_track_t * );
 static void     MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );
 
@@ -185,9 +198,17 @@ static const char *MP4_ConvertMacCode( uint16_t );
 /* Return time in s of a track */
 static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
 {
+#ifdef fMP4
+#define index p_sys->map[p_track->i_track_ID]
+#define chunk (*(p_sys->chunks[index]))
+#else
 #define chunk p_track->chunk[p_track->i_chunk]
+#endif
+
 
+    demux_sys_t *p_sys = p_demux->p_sys;
     unsigned int i_index = 0;
+    assert( p_track->i_sample >= chunk.i_sample_first );
     unsigned int i_sample = p_track->i_sample - chunk.i_sample_first;
     int64_t i_dts = chunk.i_first_dts;
 
@@ -208,6 +229,9 @@ static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
     }
 
 #undef chunk
+#ifdef fMP4
+#undef index
+#endif
 
     /* now handle elst */
     if( p_track->p_elst )
@@ -233,9 +257,15 @@ static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
     return INT64_C(1000000) * i_dts / p_track->i_timescale;
 }
 
-static inline int64_t MP4_TrackGetPTSDelta( mp4_track_t *p_track )
+static inline int64_t MP4_TrackGetPTSDelta( demux_t *p_demux, mp4_track_t *p_track )
 {
+    demux_sys_t *p_sys = p_demux->p_sys;
+#ifndef fMP4
     mp4_chunk_t *ck = &p_track->chunk[p_track->i_chunk];
+#else
+    int ind = p_sys->map[p_track->i_track_ID];
+    mp4_chunk_t *ck = p_sys->chunks[ind];
+#endif
     unsigned int i_index = 0;
     unsigned int i_sample = p_track->i_sample - ck->i_sample_first;
 
@@ -252,6 +282,7 @@ static inline int64_t MP4_TrackGetPTSDelta( mp4_track_t *p_track )
     }
 }
 
+/* PTS is in micro-seconds */
 static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys )
 {
     return INT64_C(1000000) * p_sys->i_time / p_sys->i_timescale;
@@ -299,7 +330,11 @@ static int Open( vlc_object_t * p_this )
     }
 
     /* I need to seek */
+#ifdef fMP4
+    stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable );
+#else
     stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable );
+#endif
     if( !b_seekable )
     {
         msg_Warn( p_demux, "MP4 plugin discarded (not fastseekable)" );
@@ -490,7 +525,22 @@ static int Open( vlc_object_t * p_this )
     p_sys->track = calloc( p_sys->i_tracks, sizeof( mp4_track_t ) );
     if( p_sys->track == NULL )
         goto error;
-    memset( p_sys->track, 0, p_sys->i_tracks * sizeof( mp4_track_t ) );
+#ifdef fMP4
+    p_sys->chunks = calloc( p_sys->i_tracks, sizeof( mp4_chunk_t *) );
+    if( unlikely( p_sys->chunks == NULL ) )
+        goto error;
+    p_sys->pi_sample_first = calloc( p_sys->i_tracks, sizeof( uint32_t ) );
+    p_sys->pi_first_dts = calloc( p_sys->i_tracks, sizeof( uint64_t ) );
+    if( unlikely( !p_sys->pi_sample_first || !p_sys->pi_first_dts ) )
+        goto error;
+    /* I suppose the greatest track_ID ever will be less than 256 */
+    p_sys->map = malloc( 256 * sizeof( int ) );
+    if( unlikely( p_sys->map == NULL ) )
+        goto error;
+    for( int i=1; i < 256; i++)
+        p_sys->map[i] = -1;
+    p_sys->map[0] = 0;
+#endif
 
     /* Search the first chap reference (like quicktime) and
      * check that at least 1 stream is enabled */
@@ -556,6 +606,19 @@ static int Open( vlc_object_t * p_this )
         }
     }
 
+#ifdef fMP4
+    /* loading the first chunks */
+    for( unsigned int i = 0; i < p_sys->i_tracks; i++ )
+    {
+        MP4_Box_t *p_chunk = MP4_BoxGetNextChunk( p_demux->s, 0 );
+        if( GetChunk( p_demux, p_chunk ) != VLC_SUCCESS )
+            return VLC_EGENERIC;
+        /* skip mdat */
+        if( i < p_sys->i_tracks - 1 )
+            stream_Read( p_demux->s, NULL, p_chunk->p_last->i_size );
+    }
+#endif
+
     /* */
     LoadChapter( p_demux );
 
@@ -570,6 +633,115 @@ error:
     return VLC_EGENERIC;
 }
 
+static int ChunkDestroy( mp4_chunk_t *chunk )
+{
+    if( !chunk || !chunk->p_sample_size || !chunk->p_sample_count_dts ||
+                  !chunk->p_sample_delta_dts || !chunk->p_sample_count_pts ||
+                  !chunk->p_sample_offset_pts )
+        return VLC_SUCCESS;
+
+    FREENULL( chunk->p_sample_count_dts );
+    FREENULL( chunk->p_sample_delta_dts );
+    FREENULL( chunk->p_sample_count_pts );
+    FREENULL( chunk->p_sample_offset_pts );
+    FREENULL( chunk->p_sample_size );
+    FREENULL( chunk );
+    return VLC_SUCCESS;
+}
+
+static int GetChunk( demux_t *p_demux, MP4_Box_t *p_chunk )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+
+    mp4_chunk_t *ret = malloc( sizeof( mp4_chunk_t ) );
+    if( unlikely( ret == NULL ) )
+        return VLC_ENOMEM;
+
+    MP4_Box_t *p_moof = MP4_BoxGet( p_chunk, "moof");
+    if( p_moof == NULL)
+    {
+        msg_Warn( p_demux, "no moof box found!");
+        return VLC_EGENERIC;
+    }
+    ret->i_offset = p_moof->i_pos;
+    ret->i_next_ck_offset = p_moof->i_pos + p_moof->i_size;
+    ret->i_next_ck_offset += p_chunk->p_last->i_size;
+
+    /* There is only one traf per moof in fMP4 */
+    MP4_Box_t *p_traf = MP4_BoxGet( p_moof, "traf");
+    if( p_traf == NULL)
+    {
+        msg_Warn( p_demux, "no traf box found!");
+        return VLC_EGENERIC;
+    }
+    MP4_Box_t *p_tfhd = MP4_BoxGet( p_traf, "tfhd");
+    if( p_traf == NULL)
+    {
+        msg_Warn( p_demux, "no tfhd box found!");
+        return VLC_EGENERIC;
+    }
+    unsigned int i_track_ID = p_tfhd->data.p_tfhd->i_track_ID;
+    assert( i_track_ID < 256 );
+    assert( i_track_ID > 0 );
+    if( p_sys->map[i_track_ID] == -1 )
+    {
+        msg_Info( p_demux, "GetChunk: new track ID (%li)", i_track_ID );
+        p_sys->map[i_track_ID] = p_sys->map[0];
+        p_sys->map[0] += 1;
+    }
+    int ind = p_sys->map[i_track_ID];
+
+    MP4_Box_t *p_trun = MP4_BoxGet( p_traf, "trun");
+    if( p_trun == NULL)
+    {
+        msg_Warn( p_demux, "no trun box found!");
+        return VLC_EGENERIC;
+    }
+    MP4_Box_data_trun_t *p_trun_data = p_trun->data.p_trun;
+
+    ret->i_offset += p_trun_data->i_data_offset;
+    ret->i_sample_count = p_trun_data->i_sample_count;
+    ret->i_sample_description_index = 1; /* FIXME */
+    ret->i_sample_first = p_sys->pi_sample_first[ind];
+    p_sys->pi_sample_first[ind] += ret->i_sample_count;
+
+    ret->i_first_dts = p_sys->pi_first_dts[ind];
+
+    ret->p_sample_count_dts = calloc( ret->i_sample_count, sizeof( uint32_t ) );
+    ret->p_sample_delta_dts = calloc( ret->i_sample_count, sizeof( uint32_t ) );
+
+    if( !ret->p_sample_count_dts || !ret->p_sample_delta_dts )
+        return VLC_ENOMEM;
+
+    ret->p_sample_count_pts = calloc( ret->i_sample_count, sizeof( uint32_t ) );
+    ret->p_sample_offset_pts = calloc( ret->i_sample_count, sizeof( int32_t ) );
+
+    if( !ret->p_sample_count_pts || !ret->p_sample_offset_pts )
+        return VLC_ENOMEM;
+
+    ret->p_sample_size = calloc( ret->i_sample_count, sizeof( uint32_t ) );
+    if( !ret->p_sample_size )
+        return VLC_ENOMEM;
+
+    uint32_t dur;
+    for( uint32_t i = 0; i < ret->i_sample_count; i++)
+    {
+        dur = p_trun_data->p_samples[i].i_duration;
+        ret->p_sample_delta_dts[i] = dur;
+        p_sys->pi_first_dts[ind] += dur;
+        ret->p_sample_count_dts[i] = 1;
+        ret->p_sample_count_pts[i] = 1;
+        ret->p_sample_offset_pts[i] = 0; /* FIXME */
+        ret->p_sample_size[i] = p_trun_data->p_samples[i].i_size;
+    }
+    ret->i_last_dts = p_sys->pi_first_dts[ind] - dur;
+
+    ChunkDestroy( p_sys->chunks[ind] );
+    p_sys->chunks[ind] = ret;
+
+    return VLC_SUCCESS;
+}
+
 /*****************************************************************************
  * Demux: read packet and send them to decoders
  *****************************************************************************
@@ -577,6 +749,7 @@ error:
  *****************************************************************************/
 static int Demux( demux_t *p_demux )
 {
+    msg_Dbg( p_demux, "Entering demux" );
     demux_sys_t *p_sys = p_demux->p_sys;
     unsigned int i_track;
 
@@ -638,8 +811,13 @@ static int Demux( demux_t *p_demux )
 
     p_sys->i_pcr = MP4_GetMoviePTS( p_sys );
 
+#ifdef fMP4
+    /* maybe we've got better perfs if we read more than 100 ms? */
+    p_sys->i_time += __MAX( p_sys->i_timescale / 4 , 1 );
+#else
     /* we will read 100ms for each stream so ...*/
-    p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
+    p_sys->i_time += __MAX( p_sys->i_timescale / 10, 1 );
+#endif
 
     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
     {
@@ -650,19 +828,32 @@ static int Demux( demux_t *p_demux )
 
         while( MP4_TrackGetDTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) )
         {
-#if 0
-            msg_Dbg( p_demux, "tk(%i)=%lld mv=%lld", i_track,
+#ifdef fMP4
+            /* Don't read more than one chunk at a time */
+            if( tk->end_of_chunk )
+            {
+                if( MP4_TrackNextSample( p_demux, tk ) != VLC_SUCCESS )
+                    break;
+                else
+                    tk->end_of_chunk = false;
+            }
+#endif
+#if 1
+            msg_Info( p_demux, "tk(%i)=%lld mv=%lld", i_track,
                      MP4_TrackGetDTS( p_demux, tk ),
                      MP4_GetMoviePTS( p_sys ) );
 #endif
 
-            if( MP4_TrackSampleSize( tk ) > 0 )
+            if( MP4_TrackSampleSize( p_demux, tk ) > 0 )
             {
                 block_t *p_block;
                 int64_t i_delta;
 
                 /* go,go go ! */
-                if( stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) )
+                msg_Dbg( p_demux,
+                        "go go go! seek to pos %"PRIu64", was at pos %"PRIu64"",
+                        MP4_TrackGetPos( p_demux, tk ), stream_Tell( p_demux->s ) );
+                if( stream_Seek( p_demux->s, MP4_TrackGetPos( p_demux, tk ) ) )
                 {
                     msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
                               tk->i_track_ID );
@@ -671,8 +862,8 @@ static int Demux( demux_t *p_demux )
                 }
 
                 /* now read pes */
-                if( !(p_block =
-                         stream_Block( p_demux->s, MP4_TrackSampleSize(tk) )) )
+                if( !(p_block = stream_Block( p_demux->s,
+                                MP4_TrackSampleSize( p_demux, tk) )) )
                 {
                     msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
                               tk->i_track_ID );
@@ -733,7 +924,7 @@ static int Demux( demux_t *p_demux )
                 /* dts */
                 p_block->i_dts = VLC_TS_0 + MP4_TrackGetDTS( p_demux, tk );
                 /* pts */
-                i_delta = MP4_TrackGetPTSDelta( tk );
+                i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
                 if( i_delta != -1 )
                     p_block->i_pts = p_block->i_dts + i_delta;
                 else if( tk->fmt.i_cat != VIDEO_ES )
@@ -745,6 +936,21 @@ static int Demux( demux_t *p_demux )
                     es_out_Send( p_demux->out, tk->p_es, p_block );
             }
 
+#ifdef fMP4
+            /* don't read more than one chunk iat a time */
+            if( !tk->end_of_chunk )
+            {
+                int index = p_sys->map[tk->i_track_ID];
+                mp4_chunk_t *ck = p_sys->chunks[index];
+                if( tk->i_sample >= ck->i_sample_first +
+                                         ck->i_sample_count - 1 )
+                {
+                    tk->end_of_chunk = true;
+                    break;
+                }
+            }
+#endif
+
             /* Next sample */
             if( MP4_TrackNextSample( p_demux, tk ) )
                 break;
@@ -780,6 +986,7 @@ static void MP4_UpdateSeekpoint( demux_t *p_demux )
 ******************************************************************************/
 static int Seek( demux_t *p_demux, mtime_t i_date )
 {
+    msg_Dbg( p_demux, "Entering Seek" );
     demux_sys_t *p_sys = p_demux->p_sys;
     unsigned int i_track;
 
@@ -1097,10 +1304,10 @@ static void LoadChapterApple( demux_t  *p_demux, mp4_track_t *tk )
     for( tk->i_sample = 0; tk->i_sample < tk->i_sample_count; tk->i_sample++ )
     {
         const int64_t i_dts = MP4_TrackGetDTS( p_demux, tk );
-        const int64_t i_pts_delta = MP4_TrackGetPTSDelta( tk );
-        const unsigned int i_size = MP4_TrackSampleSize( tk );
+        const int64_t i_pts_delta = MP4_TrackGetPTSDelta( p_demux, tk );
+        const unsigned int i_size = MP4_TrackSampleSize( p_demux, tk );
 
-        if( i_size > 0 && !stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) )
+        if( i_size > 0 && !stream_Seek( p_demux->s, MP4_TrackGetPos( p_demux, tk ) ) )
         {
             char p_buffer[256];
             const int i_read = stream_Read( p_demux->s, p_buffer, __MIN( sizeof(p_buffer), i_size ) );
@@ -1505,8 +1712,14 @@ static void TrackGetESSampleRate( unsigned *pi_num, unsigned *pi_den,
 static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
                           unsigned int i_chunk, es_out_id_t **pp_es )
 {
+#ifndef fMP4
     const unsigned i_sample_description_index =
         p_track->chunk[i_chunk].i_sample_description_index;
+#else
+    /* FIXME */
+    const unsigned i_sample_description_index = 1;
+#endif
+
     MP4_Box_t   *p_sample;
     MP4_Box_t   *p_esds;
     MP4_Box_t   *p_frma;
@@ -1659,12 +1872,14 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
         p_track->fmt.video.i_visible_width = p_track->fmt.video.i_width;
         p_track->fmt.video.i_visible_height = p_track->fmt.video.i_height;
 
+#ifndef fMP4
         /* Frame rate */
         TrackGetESSampleRate( &p_track->fmt.video.i_frame_rate,
                               &p_track->fmt.video.i_frame_rate_base,
                               p_track, i_sample_description_index, i_chunk );
         p_demux->p_sys->f_fps = (float)p_track->fmt.video.i_frame_rate /
                                 (float)p_track->fmt.video.i_frame_rate_base;
+#endif
         break;
 
     case AUDIO_ES:
@@ -2060,6 +2275,12 @@ static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track,
     unsigned int i_chunk;
     int          i_index;
 
+#ifdef fMP4
+    *pi_chunk = 0;
+    *pi_sample = 0;
+    return VLC_SUCCESS;
+#endif
+
     /* FIXME see if it's needed to check p_track->i_chunk_count */
     if( p_track->i_chunk_count == 0 )
         return( VLC_EGENERIC );
@@ -2197,8 +2418,10 @@ static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track,
                  "Sample Box (stss)", p_track->i_track_ID );
     }
 
+#ifndef fMP4
     *pi_chunk  = i_chunk;
     *pi_sample = i_sample;
+#endif
 
     return VLC_SUCCESS;
 }
@@ -2208,6 +2431,7 @@ static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track,
 {
     bool b_reselect = false;
 
+#ifndef fMP4
     /* now see if actual es is ok */
     if( p_track->i_chunk >= p_track->i_chunk_count ||
         p_track->chunk[p_track->i_chunk].i_sample_description_index !=
@@ -2233,10 +2457,12 @@ static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track,
             return VLC_EGENERIC;
         }
     }
+#endif
 
     /* select again the new decoder */
     if( b_reselect )
     {
+        msg_Info( p_demux, "es_out_Control is called!!!" );
         es_out_Control( p_demux->out, ES_OUT_SET_ES, p_track->p_es );
     }
 
@@ -2435,12 +2661,19 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
         }
     }
 
+#ifndef fMP4
     /* Create chunk index table and sample index table */
     if( TrackCreateChunksIndex( p_demux,p_track  ) ||
         TrackCreateSamplesIndex( p_demux, p_track ) )
     {
         return; /* cannot create chunks index */
     }
+#else
+    p_track->i_sample_count = UINT32_MAX;
+    p_track->i_sample_size = 0;
+    p_track->chunk = NULL;
+    p_track->end_of_chunk = false;
+#endif
 
     p_track->i_chunk  = 0;
     p_track->i_sample = 0;
@@ -2545,6 +2778,7 @@ static int MP4_TrackSelect( demux_t *p_demux, mp4_track_t *p_track,
         return VLC_SUCCESS;
     }
 
+    msg_Dbg( p_demux, "i_start is %lli", i_start );
     return MP4_TrackSeek( p_demux, p_track, i_start );
 }
 
@@ -2589,6 +2823,8 @@ static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
         return VLC_EGENERIC;
     }
 
+    msg_Info( p_demux, "MP4_TrackSeek: i_chunk is %lu and i_sample is %lu",
+                                                         i_chunk, i_sample );
     p_track->b_selected = true;
 
     if( !TrackGotoChunkSample( p_demux, p_track, i_chunk, i_sample ) )
@@ -2603,11 +2839,23 @@ static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
  *
  */
 #define QT_V0_MAX_SAMPLES 1024
-static int MP4_TrackSampleSize( mp4_track_t *p_track )
+static int MP4_TrackSampleSize( demux_t *p_demux, mp4_track_t *p_track )
 {
+    demux_sys_t *p_sys = p_demux->p_sys;
     int i_size;
     MP4_Box_data_sample_soun_t *p_soun;
 
+#ifdef fMP4
+    if( p_track->i_sample_size == 0 )
+    {
+        /* most simple case */
+        mp4_chunk_t *ck = p_sys->chunks[p_sys->map[p_track->i_track_ID]];
+        uint32_t i_sample = p_track->i_sample - ck->i_sample_first;
+        return ck->p_sample_size[i_sample];
+    }
+    else return 0;
+#endif
+
     if( p_track->i_sample_size == 0 )
     {
         /* most simple case */
@@ -2649,12 +2897,19 @@ static int MP4_TrackSampleSize( mp4_track_t *p_track )
     return i_size;
 }
 
-static uint64_t MP4_TrackGetPos( mp4_track_t *p_track )
+static uint64_t MP4_TrackGetPos( demux_t *p_demux, mp4_track_t *p_track )
 {
+    demux_sys_t *p_sys = p_demux->p_sys;
     unsigned int i_sample;
     uint64_t i_pos;
 
+#ifdef fMP4
+    unsigned index = p_sys->map[p_track->i_track_ID];
+    mp4_chunk_t *ck = p_sys->chunks[index];
+    i_pos = ck->i_offset;
+#else
     i_pos = p_track->chunk[p_track->i_chunk].i_offset;
+#endif
 
     if( p_track->i_sample_size )
     {
@@ -2677,11 +2932,21 @@ static uint64_t MP4_TrackGetPos( mp4_track_t *p_track )
     }
     else
     {
+#ifdef fMP4
+        uint32_t i_index = 0;
+        for( i_sample = ck->i_sample_first;
+             i_sample < p_track->i_sample; i_sample++ )
+        {
+            i_index = i_sample - ck->i_sample_first;
+            i_pos += ck->p_sample_size[i_index];
+        }
+#else
         for( i_sample = p_track->chunk[p_track->i_chunk].i_sample_first;
              i_sample < p_track->i_sample; i_sample++ )
         {
             i_pos += p_track->p_sample_size[i_sample];
         }
+#endif
     }
 
     return i_pos;
@@ -2689,6 +2954,8 @@ static uint64_t MP4_TrackGetPos( mp4_track_t *p_track )
 
 static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
 {
+    demux_sys_t *p_sys = p_demux->p_sys;
+    msg_Dbg( p_demux, "Entering MP4_TrackNextSample" );
     if( p_track->fmt.i_cat == AUDIO_ES && p_track->i_sample_size != 0 )
     {
         MP4_Box_data_sample_soun_t *p_soun;
@@ -2725,6 +2992,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
     }
     else
     {
+        msg_Dbg( p_demux, "p_track->i_sample was %lu", p_track->i_sample );
         p_track->i_sample++;
     }
 
@@ -2732,6 +3000,8 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
         return VLC_EGENERIC;
 
     /* Have we changed chunk ? */
+
+#ifndef fMP4
     if( p_track->i_sample >=
             p_track->chunk[p_track->i_chunk].i_sample_first +
             p_track->chunk[p_track->i_chunk].i_sample_count )
@@ -2745,7 +3015,25 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
             return VLC_EGENERIC;
         }
     }
+#else
+    int index = p_sys->map[p_track->i_track_ID];
+    if( p_track->i_sample >=
+            p_sys->chunks[index]->i_sample_first +
+            p_sys->chunks[index]->i_sample_count )
+    {
+        mp4_chunk_t *current_ck = p_sys->chunks[index];
+        stream_Seek( p_demux->s, current_ck->i_next_ck_offset );
+        assert( p_track->i_track_ID > 0 );
+        MP4_Box_t *p_chunk = MP4_BoxGetNextChunk( p_demux->s, p_track->i_track_ID );
+        if( !p_chunk )
+            return VLC_EGENERIC;
+        if( GetChunk( p_demux, p_chunk ) != VLC_SUCCESS )
+            return VLC_EGENERIC;
+    }
 
+#endif
+
+#ifndef fMP4
     /* Have we changed elst */
     if( p_track->p_elst && p_track->p_elst->data.p_elst->i_entry_count > 0 )
     {
@@ -2762,6 +3050,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
                               MP4_TrackGetDTS( p_demux, p_track ) );
         }
     }
+#endif
 
     return VLC_SUCCESS;
 }
-- 
1.7.5.4




More information about the vlc-devel mailing list