* block: added
authorLaurent Aimar <fenrir@videolan.org>
Mon, 21 Feb 2005 09:03:07 +0000 (09:03 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Mon, 21 Feb 2005 09:03:07 +0000 (09:03 +0000)
    - BLOCK_FLAG_CORRUPTED : signal corrupted data (do not use anymore
 BLOCK_FLAG_DISCONTINUITY in that case)
    - BLOCK_FLAG_PREROLL : mark this block to be decoded (no matter what).
 * ffmpeg, libmpeg2: support BLOCK_FLAG_PREROLL (ie disable frame dropping).
 * input: added ES_OUT_SET_NEXT_DISPLAY_TIME to ease the work for preroll
 (untested).
 * mp4: added support for CTTS table (pts, needed for h264+bframe).
 * decoders: for now handle discontinuity and corrupted block the same way.

17 files changed:
include/vlc_block.h
include/vlc_es_out.h
modules/codec/a52.c
modules/codec/dts.c
modules/codec/faad.c
modules/codec/ffmpeg/audio.c
modules/codec/ffmpeg/video.c
modules/codec/flac.c
modules/codec/libmpeg2.c
modules/codec/mpeg_audio.c
modules/codec/theora.c
modules/demux/mp4/mp4.c
modules/demux/ts.c
src/input/decoder.c
src/input/es_out.c
src/input/input.c
src/input/input_internal.h

index 831f372..cb58901 100644 (file)
@@ -68,6 +68,10 @@ typedef struct block_sys_t block_sys_t;
 #define BLOCK_FLAG_CLOCK         0x0200
 /** This block is scrambled */
 #define BLOCK_FLAG_SCRAMBLED     0x0400
+/** This block has to be decoded but not be displayed */
+#define BLOCK_FLAG_PREROLL       0x0800
+/** This block is corrupted and/or there is data loss  */
+#define BLOCK_FLAG_CORRUPTED     0x1000
 
 #define BLOCK_FLAG_PRIVATE_MASK  0xffff0000
 #define BLOCK_FLAG_PRIVATE_SHIFT 16
index 13dc518..5af2b77 100644 (file)
@@ -59,7 +59,12 @@ enum es_out_query_e
     ES_OUT_SET_GROUP,   /* arg1= int                            */
     ES_OUT_GET_GROUP,   /* arg1= int*                           */
 
-    /* PCR handling, dts/pts will be automatically computed using thoses PCR */
+    /* PCR handling, dts/pts will be automatically computed using thoses PCR
+     * XXX: SET_PCR(_GROUP) is in charge of the pace control. They will wait to slow
+     * down the demuxer to read at the right speed.
+     * XXX: if you want PREROLL just call RESET_PCR and ES_OUT_SET_NEXT_DISPLAY_TIME and send
+     * data to the decoder *without* calling SET_PCR until preroll is finished.
+     */
     ES_OUT_SET_PCR,             /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/
     ES_OUT_SET_GROUP_PCR,       /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/
     ES_OUT_RESET_PCR,           /* no arg */
@@ -69,7 +74,10 @@ enum es_out_query_e
     ES_OUT_GET_TS,             /* arg1=int64_t i_ts(microsecond!) (using default group 0), arg2=int64_t* converted i_ts */
 
     /* Try not to use this one as it is a bit hacky */
-    ES_OUT_SET_FMT      /* arg1= es_out_id_t* arg2=es_format_t* */
+    ES_OUT_SET_FMT,     /* arg1= es_out_id_t* arg2=es_format_t* */
+
+    /* Allow preroll of data (data with dts/pts < i_pts for one ES will be decoded but not displayed */
+    ES_OUT_SET_NEXT_DISPLAY_TIME,   /* arg1=es_out_id_t* arg2=int64_t i_pts(microsecond) */
 };
 
 struct es_out_t
index 6c37c87..82a8610 100644 (file)
@@ -174,7 +174,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         return NULL;
     }
 
-    if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY )
+    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
         p_sys->i_state = STATE_NOSYNC;
     }
index 6c651c9..c6adbc0 100644 (file)
@@ -175,7 +175,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         return NULL;
     }
 
-    if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY )
+    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
         p_sys->i_state = STATE_NOSYNC;
     }
index cc75d8a..6cc457b 100644 (file)
@@ -181,7 +181,7 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 
     p_block = *pp_block;
 
-    if( p_block->i_flags&BLOCK_FLAG_DISCONTINUITY )
+    if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
         block_Release( p_block );
         return NULL;
index 5b33b95..1a3c3b5 100644 (file)
@@ -209,7 +209,7 @@ aout_buffer_t *E_( DecodeAudio )( decoder_t *p_dec, block_t **pp_block )
         return NULL;
     }
 
-    if( p_block->i_buffer <= 0 || p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
+    if( p_block->i_buffer <= 0 || ( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) )
     {
         block_Release( p_block );
         return NULL;
index 9207138..8e58d37 100644 (file)
@@ -438,7 +438,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
 
     p_block = *pp_block;
 
-    if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
+    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
         p_sys->i_buffer = 0;
         p_sys->i_pts = 0; /* To make sure we recover properly */
@@ -450,6 +450,14 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
         return NULL;
     }
 
+    if( p_block->i_flags & BLOCK_FLAG_PREROLL )
+    {
+        /* Do not care about late frames when prerolling
+         * TODO avoid decoding of non reference frame
+         * (ie all B except for H264 where it depends only on nal_ref_idc) */
+        p_sys->i_late_frames = 0;
+    }
+
     if( !p_dec->b_pace_control && p_sys->i_late_frames > 0 &&
         mdate() - p_sys->i_late_frames_start > I64C(5000000) )
     {
@@ -579,8 +587,9 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
             continue;
         }
 
-        /* Update frame late count*/
-        if( p_sys->i_pts && p_sys->i_pts <= mdate() )
+        /* Update frame late count (except when doing preroll) */
+        if( p_sys->i_pts && p_sys->i_pts <= mdate() &&
+            !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
         {
             p_sys->i_late_frames++;
             if( p_sys->i_late_frames == 1 )
@@ -630,6 +639,10 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
         {
             p_pic->date = p_sys->i_pts;
 
+            static int64_t i_old = 0;
+            msg_Dbg( p_dec, "pts=%lld diff=%lld", p_pic->date, p_pic->date - i_old );
+            i_old = p_pic->date;
+
             /* interpolate the next PTS */
             if( p_sys->p_context->frame_rate > 0 )
             {
@@ -657,6 +670,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
         else
         {
             p_dec->pf_vout_buffer_del( p_dec, p_pic );
+            msg_Dbg( p_dec, "pts=0" );
         }
     }
 
index ded735a..8c7b95f 100644 (file)
@@ -295,7 +295,7 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
         aout_DateSet( &p_sys->end_date, (*pp_block)->i_pts );
     }
 
-    if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY )
+    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
         p_sys->i_state = STATE_NOSYNC;
     }
index 1fa6761..167c754 100644 (file)
@@ -65,6 +65,8 @@ struct decoder_sys_t
                                                * the sequence header ?    */
     vlc_bool_t       b_slice_i;             /* intra-slice refresh stream */
 
+    vlc_bool_t      b_preroll;
+
     /*
      * Output properties
      */
@@ -137,6 +139,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_sys->b_garbage_pic = 0;
     p_sys->b_slice_i  = 0;
     p_sys->b_skip     = 0;
+    p_sys->b_preroll = VLC_FALSE;
 
 #if defined( __i386__ )
     if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
@@ -213,7 +216,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                 return NULL;
             }
 
-            if( (p_block->i_flags&BLOCK_FLAG_DISCONTINUITY) &&
+            if( (p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) &&
                 p_sys->p_synchro &&
                 p_sys->p_info->sequence &&
                 p_sys->p_info->sequence->width != (unsigned)-1 )
@@ -244,6 +247,17 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                 }
             }
 
+            if( p_block->i_flags & BLOCK_FLAG_PREROLL )
+            {
+                p_sys->b_preroll = VLC_TRUE;
+            }
+            else if( p_sys->b_preroll )
+            {
+                p_sys->b_preroll = VLC_FALSE;
+                /* Reset synchro */
+                vout_SynchroReset( p_sys->p_synchro );
+            }
+
 #ifdef PIC_FLAG_PTS
             if( p_block->i_pts )
             {
@@ -432,7 +446,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                 p_sys->p_info->current_picture->nb_fields, i_pts, i_dts,
                 p_sys->i_current_rate );
 
-            if( !p_dec->b_pace_control &&
+            if( !p_dec->b_pace_control && !p_sys->b_preroll &&
                 !(p_sys->b_slice_i
                    && ((p_sys->p_info->current_picture->flags
                          & PIC_MASK_CODING_TYPE) == P_CODING_TYPE))
index 2a1d1a1..f7dbd46 100644 (file)
@@ -196,7 +196,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         return NULL;
     }
 
-    if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY )
+    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
         p_sys->i_state = STATE_NOSYNC;
     }
index 92fb279..d242516 100644 (file)
@@ -386,7 +386,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
     block_t *p_block = *pp_block;
     void *p_buf;
 
-    if( ( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) != 0 )
+    if( ( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) != 0 )
     {
         /* Don't send the the first packet after a discontinuity to
          * theora_decode, otherwise we get purple/green display artifacts
index 6c7bf87..f912eca 100644 (file)
@@ -74,7 +74,10 @@ typedef struct
     /* with this we can calculate dts/pts without waste memory */
     uint64_t     i_first_dts;
     uint32_t     *p_sample_count_dts;
-    uint32_t     *p_sample_delta_dts; /* dts delta */
+    uint32_t     *p_sample_delta_dts;   /* dts delta */
+
+    uint32_t     *p_sample_count_pts;
+    uint32_t     *p_sample_offset_pts;  /* pts-dts */
 
     /* TODO if needed add pts
         but quickly *add* support for edts and seeking */
@@ -162,7 +165,7 @@ static int      MP4_TrackNextSample( demux_t *, mp4_track_t * );
 static void     MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );
 
 /* Return time in ┬Ás of a track */
-static inline int64_t MP4_TrackGetPTS( demux_t *p_demux, mp4_track_t *p_track )
+static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
 {
 #define chunk p_track->chunk[p_track->i_chunk]
 
@@ -213,6 +216,24 @@ static inline int64_t MP4_TrackGetPTS( demux_t *p_demux, mp4_track_t *p_track )
     return I64C(1000000) * i_dts / p_track->i_timescale;
 }
 
+static inline int64_t MP4_TrackGetPTSDelta( demux_t *p_demux, mp4_track_t *p_track )
+{
+    mp4_chunk_t *ck = &p_track->chunk[p_track->i_chunk];
+    unsigned int i_index = 0;
+    unsigned int i_sample = p_track->i_sample - ck->i_sample_first;
+
+    if( ck->p_sample_count_pts == NULL || ck->p_sample_offset_pts == NULL )
+        return -1;
+
+    for( i_index = 0;; i_index++ )
+    {
+        if( i_sample < ck->p_sample_count_pts[i_index] )
+            return ck->p_sample_offset_pts[i_index] * I64C(1000000) / p_track->i_timescale;
+
+        i_sample -= ck->p_sample_count_pts[i_index];
+    }
+}
+
 static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys )
 {
     return I64C(1000000) * p_sys->i_time / p_sys->i_timescale;
@@ -604,17 +625,18 @@ static int Demux( demux_t *p_demux )
             continue;
         }
 
-        while( MP4_TrackGetPTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) )
+        while( MP4_TrackGetDTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) )
         {
 #if 0
             msg_Dbg( p_demux, "tk(%i)=%lld mv=%lld", i_track,
-                     MP4_TrackGetPTS( p_demux, tk ),
+                     MP4_TrackGetDTS( p_demux, tk ),
                      MP4_GetMoviePTS( p_sys ) );
 #endif
 
             if( MP4_TrackSampleSize( tk ) > 0 )
             {
                 block_t *p_block;
+                int64_t i_delta;
 
                 /* go,go go ! */
                 if( stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) )
@@ -669,15 +691,22 @@ static int Demux( demux_t *p_demux )
                         }
                     }
                 }
-                p_block->i_dts = MP4_TrackGetPTS( p_demux, tk ) + 1;
+                /* dts */
+                p_block->i_dts = MP4_TrackGetDTS( p_demux, tk ) + 1;
+                /* pts */
+                i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
+                if( i_delta >= 0 )
+                    p_block->i_pts = p_block->i_dts + i_delta;
+                else if( tk->fmt.i_cat != VIDEO_ES )
+                    p_block->i_pts = p_block->i_dts;
+                else
+                    p_block->i_pts = 0;
 
-                p_block->i_pts = tk->fmt.i_cat == VIDEO_ES ?
-                    0 : p_block->i_dts + 1;
+                if( tk->fmt.i_cat == VIDEO_ES )
+                    msg_Dbg( p_demux, "pts=%lld dts=%lld", p_block->i_pts, p_block->i_dts );
 
                 if( !tk->b_drms || ( tk->b_drms && tk->p_drms ) )
-                {
                     es_out_Send( p_demux->out, tk->p_es, p_block );
-                }
             }
 
             /* Next sample */
@@ -918,8 +947,15 @@ static int TrackCreateChunksIndex( demux_t *p_demux,
     /* first we read chunk offset */
     for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
     {
-        p_demux_track->chunk[i_chunk].i_offset =
-                p_co64->data.p_co64->i_chunk_offset[i_chunk];
+        mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
+
+        ck->i_offset = p_co64->data.p_co64->i_chunk_offset[i_chunk];
+
+        ck->i_first_dts = 0;
+        ck->p_sample_count_dts = NULL;
+        ck->p_sample_delta_dts = NULL;
+        ck->p_sample_count_pts = NULL;
+        ck->p_sample_offset_pts = NULL;
     }
 
     /* now we read index for SampleEntry( soun vide mp4a mp4v ...)
@@ -963,12 +999,9 @@ static int TrackCreateChunksIndex( demux_t *p_demux,
 static int TrackCreateSamplesIndex( demux_t *p_demux,
                                     mp4_track_t *p_demux_track )
 {
-    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
-                          ctts make same mapping but for composition time,
-                          not yet used and probably not usefull */
-    MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2
-                          that uses a compressed form FIXME make them in libmp4
-                          as a unique type */
+    MP4_Box_t *p_box;
+    MP4_Box_data_stsz_t *stsz;
+    MP4_Box_data_stts_t *stts;
     /* TODO use also stss and stsh table for seeking */
     /* FIXME use edit table */
     int64_t i_sample;
@@ -979,23 +1012,35 @@ static int TrackCreateSamplesIndex( demux_t *p_demux,
 
     int64_t i_last_dts;
 
-    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
-    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
-
-    if( ( !p_stts )||( !p_stsz ) )
+    /* Find stsz
+     *  Gives the sample size for each samples. There is also a stz2 table
+     *  (compressed form) that we need to implement TODO */
+    p_box = MP4_BoxGet( p_demux_track->p_stbl, "stsz" );
+    if( !p_box )
     {
-        msg_Warn( p_demux, "cannot read sample table" );
-        return( VLC_EGENERIC );
+        /* FIXME and stz2 */
+        msg_Warn( p_demux, "cannot find STSZ box" );
+        return VLC_EGENERIC;
     }
+    stsz = p_box->data.p_stsz;
 
-    p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count;
-
+    /* Find stts
+     *  Gives mapping between sample and decoding time
+     */
+    p_box = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
+    if( !p_box )
+    {
+        msg_Warn( p_demux, "cannot find STTS box" );
+        return VLC_EGENERIC;
+    }
+    stts = p_box->data.p_stts;
 
-    /* for sample size, there are 2 case */
-    if( p_stsz->data.p_stsz->i_sample_size )
+    /* Use stsz table to create a sample number -> sample size table */
+    p_demux_track->i_sample_count = stsz->i_sample_count;
+    if( stsz->i_sample_size )
     {
         /* 1: all sample have the same size, so no need to construct a table */
-        p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size;
+        p_demux_track->i_sample_size = stsz->i_sample_size;
         p_demux_track->p_sample_size = NULL;
     }
     else
@@ -1008,75 +1053,65 @@ static int TrackCreateSamplesIndex( demux_t *p_demux,
         for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
         {
             p_demux_track->p_sample_size[i_sample] =
-                    p_stsz->data.p_stsz->i_entry_size[i_sample];
+                    stsz->i_entry_size[i_sample];
         }
     }
-    /* we have extracted all the information from stsz, now use stts */
 
-    /* if we don't want to waste too much memory, we can't expand
-       the box! so each chunk will contain an "extract" of this table
-       for fast research */
+    /* Use stts table to crate a sample number -> dts table.
+     * XXX: if we don't want to waste too much memory, we can't expand
+     *  the box! so each chunk will contain an "extract" of this table
+     *  for fast research (problem with raw stream where a sample is sometime
+     *  just channels*bits_per_sample/8 */
 
     i_last_dts = 0;
     i_index = 0; i_index_sample_used = 0;
-
-    /* create and init last data for each chunk */
     for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
     {
-
+        mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
         int64_t i_entry, i_sample_count, i;
 
         /* save last dts */
-        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
+        ck->i_first_dts = i_last_dts;
 
         /* count how many entries are needed for this chunk
          * for p_sample_delta_dts and p_sample_count_dts */
-        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
+        i_sample_count = ck->i_sample_count;
 
         i_entry = 0;
         while( i_sample_count > 0 )
         {
-            i_sample_count -=
-                p_stts->data.p_stts->i_sample_count[i_index+i_entry];
+            i_sample_count -= stts->i_sample_count[i_index+i_entry];
+            /* don't count already used sample in this entry */
             if( i_entry == 0 )
-            {
-                /* don't count already used sample in this entry */
                 i_sample_count += i_index_sample_used;
-            }
+
             i_entry++;
         }
 
         /* allocate them */
-        p_demux_track->chunk[i_chunk].p_sample_count_dts =
-            calloc( i_entry, sizeof( uint32_t ) );
-        p_demux_track->chunk[i_chunk].p_sample_delta_dts =
-            calloc( i_entry, sizeof( uint32_t ) );
+        ck->p_sample_count_dts = calloc( i_entry, sizeof( uint32_t ) );
+        ck->p_sample_delta_dts = calloc( i_entry, sizeof( uint32_t ) );
 
         /* now copy */
-        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
+        i_sample_count = ck->i_sample_count;
         for( i = 0; i < i_entry; i++ )
         {
             int64_t i_used;
             int64_t i_rest;
 
-            i_rest = p_stts->data.p_stts->i_sample_count[i_index] -
-                i_index_sample_used;
+            i_rest = stts->i_sample_count[i_index] - i_index_sample_used;
 
             i_used = __MIN( i_rest, i_sample_count );
 
             i_index_sample_used += i_used;
             i_sample_count -= i_used;
 
-            p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used;
+            ck->p_sample_count_dts[i] = i_used;
+            ck->p_sample_delta_dts[i] = stts->i_sample_delta[i_index];
 
-            p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] =
-                p_stts->data.p_stts->i_sample_delta[i_index];
+            i_last_dts += i_used * ck->p_sample_delta_dts[i];
 
-            i_last_dts += i_used *
-                p_demux_track->chunk[i_chunk].p_sample_delta_dts[i];
-
-            if( i_index_sample_used >=
-                p_stts->data.p_stts->i_sample_count[i_index] )
+            if( i_index_sample_used >= stts->i_sample_count[i_index] )
             {
                 i_index++;
                 i_index_sample_used = 0;
@@ -1084,6 +1119,70 @@ static int TrackCreateSamplesIndex( demux_t *p_demux,
         }
     }
 
+    /* Find ctts
+     *  Gives the delta between decoding time (dts) and composition table (pts)
+     */
+    p_box = MP4_BoxGet( p_demux_track->p_stbl, "ctts" );
+    if( p_box )
+    {
+        MP4_Box_data_ctts_t *ctts = p_box->data.p_ctts;
+
+        msg_Warn( p_demux, "CTTS table" );
+
+        /* Create pts-dts table per chunk */
+        i_index = 0; i_index_sample_used = 0;
+        for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
+        {
+            mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
+            int64_t i_entry, i_sample_count, i;
+
+            /* count how many entries are needed for this chunk
+             * for p_sample_delta_dts and p_sample_count_dts */
+            i_sample_count = ck->i_sample_count;
+
+            i_entry = 0;
+            while( i_sample_count > 0 )
+            {
+                i_sample_count -= ctts->i_sample_count[i_index+i_entry];
+
+                /* don't count already used sample in this entry */
+                if( i_entry == 0 )
+                    i_sample_count += i_index_sample_used;
+
+                i_entry++;
+            }
+
+            /* allocate them */
+            ck->p_sample_count_pts = calloc( i_entry, sizeof( uint32_t ) );
+            ck->p_sample_offset_pts = calloc( i_entry, sizeof( uint32_t ) );
+
+            /* now copy */
+            i_sample_count = ck->i_sample_count;
+            for( i = 0; i < i_entry; i++ )
+            {
+                int64_t i_used;
+                int64_t i_rest;
+
+                i_rest = ctts->i_sample_count[i_index] -
+                    i_index_sample_used;
+
+                i_used = __MIN( i_rest, i_sample_count );
+
+                i_index_sample_used += i_used;
+                i_sample_count -= i_used;
+
+                ck->p_sample_count_pts[i] = i_used;
+                ck->p_sample_offset_pts[i] = ctts->i_sample_offset[i_index];
+
+                if( i_index_sample_used >= ctts->i_sample_count[i_index] )
+                {
+                    i_index++;
+                    i_index_sample_used = 0;
+                }
+            }
+        }
+    }
+
     msg_Dbg( p_demux, "track[Id 0x%x] read %d samples length:"I64Fd"s",
              p_demux_track->i_track_ID, p_demux_track->i_sample_count,
              i_last_dts / p_demux_track->i_timescale );
@@ -1821,6 +1920,9 @@ static void MP4_TrackDestroy( demux_t *p_demux, mp4_track_t *p_track )
         {
            FREE(p_track->chunk[i_chunk].p_sample_count_dts);
            FREE(p_track->chunk[i_chunk].p_sample_delta_dts );
+
+           FREE(p_track->chunk[i_chunk].p_sample_count_pts);
+           FREE(p_track->chunk[i_chunk].p_sample_offset_pts );
         }
     }
     FREE( p_track->chunk );
@@ -2055,7 +2157,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
     {
         demux_sys_t *p_sys = p_demux->p_sys;
         MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst;
-        int64_t i_mvt = MP4_TrackGetPTS( p_demux, p_track ) *
+        int64_t i_mvt = MP4_TrackGetDTS( p_demux, p_track ) *
                         p_sys->i_timescale / (int64_t)1000000;
 
         if( p_track->i_elst < elst->i_entry_count &&
@@ -2063,7 +2165,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
                      elst->i_segment_duration[p_track->i_elst] )
         {
             MP4_TrackSetELST( p_demux, p_track,
-                              MP4_TrackGetPTS( p_demux, p_track ) );
+                              MP4_TrackGetDTS( p_demux, p_track ) );
         }
     }
 
index 75cd306..dac7057 100644 (file)
@@ -1420,7 +1420,7 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
             {
                 /* Small video artifacts are usually better then
                  * dropping full frames */
-                pid->es->p_pes->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+                pid->es->p_pes->i_flags |= BLOCK_FLAG_CORRUPTED;
             }
         }
     }
index 6447cce..3eee429 100644 (file)
@@ -60,6 +60,8 @@ struct decoder_owner_sys_t
 {
     vlc_bool_t      b_own_thread;
 
+    int64_t         i_preroll_end;
+
     input_thread_t  *p_input;
 
     aout_instance_t *p_aout;
@@ -276,6 +278,11 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
     return VLC_TRUE;
 }
 
+void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end )
+{
+    p_dec->p_owner->i_preroll_end = i_preroll_end;
+}
+
 #if 0
 /**
  * Create a NULL packet for padding in case of a data loss
@@ -392,6 +399,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
         return NULL;
     }
     p_dec->p_owner->b_own_thread = VLC_TRUE;
+    p_dec->p_owner->i_preroll_end = -1;
     p_dec->p_owner->p_input = p_input;
     p_dec->p_owner->p_aout = NULL;
     p_dec->p_owner->p_aout_input = NULL;
@@ -610,9 +618,21 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
                     while( (p_aout_buf = p_dec->pf_decode_audio( p_dec,
                                                        &p_packetized_block )) )
                     {
-                        aout_DecPlay( p_dec->p_owner->p_aout,
-                                      p_dec->p_owner->p_aout_input,
-                                      p_aout_buf );
+                        /* FIXME the best would be to handle the case start_date < preroll < end_date
+                         * but that's not easy with non raw audio stream */
+                        if( p_dec->p_owner->i_preroll_end > 0 &&
+                            p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
+                        {
+                            aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
+                                                  p_dec->p_owner->p_aout_input, p_aout_buf );
+                        }
+                        else
+                        {
+                            p_dec->p_owner->i_preroll_end = -1;
+                            aout_DecPlay( p_dec->p_owner->p_aout,
+                                          p_dec->p_owner->p_aout_input,
+                                          p_aout_buf );
+                        }
                     }
 
                     p_packetized_block = p_next;
@@ -621,8 +641,19 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
         }
         else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
         {
-            aout_DecPlay( p_dec->p_owner->p_aout,
-                          p_dec->p_owner->p_aout_input, p_aout_buf );
+            if( p_dec->p_owner->i_preroll_end > 0 &&
+                p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
+            {
+                aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
+                                      p_dec->p_owner->p_aout_input, p_aout_buf );
+            }
+            else
+            {
+                p_dec->p_owner->i_preroll_end = -1;
+                aout_DecPlay( p_dec->p_owner->p_aout,
+                              p_dec->p_owner->p_aout_input,
+                              p_aout_buf );
+            }
         }
     }
     else if( p_dec->fmt_in.i_cat == VIDEO_ES )
@@ -646,9 +677,18 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
                     while( (p_pic = p_dec->pf_decode_video( p_dec,
                                                        &p_packetized_block )) )
                     {
-                        vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
-                                          p_pic->date );
-                        vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
+                        if( p_dec->p_owner->i_preroll_end > 0 &&
+                            p_pic->date < p_dec->p_owner->i_preroll_end )
+                        {
+                            vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
+                        }
+                        else
+                        {
+                            p_dec->p_owner->i_preroll_end = -1;
+                            vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
+                                              p_pic->date );
+                            vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
+                        }
                     }
 
                     p_packetized_block = p_next;
@@ -657,8 +697,17 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
         }
         else while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
         {
-            vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date );
-            vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
+            if( p_dec->p_owner->i_preroll_end > 0 &&
+                p_pic->date < p_dec->p_owner->i_preroll_end )
+            {
+                vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
+            }
+            else
+            {
+                p_dec->p_owner->i_preroll_end = -1;
+                vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date );
+                vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
+            }
         }
     }
     else if( p_dec->fmt_in.i_cat == SPU_ES )
@@ -667,6 +716,15 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
         subpicture_t *p_spu;
         while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) )
         {
+            if( p_dec->p_owner->i_preroll_end > 0 &&
+                p_spu->i_start < p_dec->p_owner->i_preroll_end &&
+                ( p_spu->i_stop <= 0 || p_spu->i_stop <= p_dec->p_owner->i_preroll_end ) )
+            {
+                spu_DestroySubpicture( p_dec->p_owner->p_vout->p_spu, p_spu );
+                continue;
+            }
+
+            p_dec->p_owner->i_preroll_end = -1;
             p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
             if( p_vout )
             {
index e0ca088..0c562fb 100644 (file)
@@ -61,6 +61,9 @@ struct es_out_id_t
     int       i_id;
     es_out_pgrm_t *p_pgrm;
 
+    /* */
+    int64_t i_preroll_end;
+
     /* Channel in the track type */
     int         i_channel;
     es_format_t fmt;
@@ -517,6 +520,8 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
     es->i_id = fmt->i_id;
     es->p_pgrm = p_pgrm;
     es_format_Copy( &es->fmt, fmt );
+    es->i_preroll_end = -1;
+
     switch( fmt->i_cat )
     {
     case AUDIO_ES:
@@ -601,6 +606,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es )
         }
     }
 
+    es->i_preroll_end = -1;
     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
         return;
@@ -859,6 +865,18 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
     }
 
     p_block->i_rate = p_input->i_rate;
+    /* Mark preroll blocks */
+    if( es->i_preroll_end >= 0 )
+    {
+        int64_t i_date = p_block->i_pts;
+        if( i_date <= 0 )
+            i_date = p_block->i_dts;
+
+        if( i_date < es->i_preroll_end )
+            p_block->i_flags |= BLOCK_FLAG_PREROLL;
+        else
+            es->i_preroll_end = -1;
+    }
 
     /* TODO handle mute */
     if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
@@ -1169,6 +1187,22 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
             return VLC_SUCCESS;
         }
 
+        case ES_OUT_SET_NEXT_DISPLAY_TIME:
+        {
+            int64_t i_date;
+
+            es = (es_out_id_t*) va_arg( args, es_out_id_t * );
+            i_date = (int64_t)va_arg( args, int64_t );
+
+            if( !es || !es->p_dec )
+                return VLC_EGENERIC;
+
+            es->i_preroll_end = i_date;
+            input_DecoderPreroll( es->p_dec, i_date );
+
+            return VLC_SUCCESS;
+        }
+
         default:
             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
             return VLC_EGENERIC;
index 4543c48..436bff7 100644 (file)
@@ -1210,6 +1210,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             }
             if( f_pos < 0.0 ) f_pos = 0.0;
             if( f_pos > 1.0 ) f_pos = 1.0;
+            /* Reset the decoders states and clock synch (before calling the demuxer */
+            es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+            input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
             if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
                                 f_pos ) )
             {
@@ -1221,8 +1224,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 if( p_input->i_slave > 0 )
                     SlaveSeek( p_input );
 
-                input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
-                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                //es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
                 b_force_update = VLC_TRUE;
             }
             break;
@@ -1246,6 +1249,11 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 i_time += val.i_time;
             }
             if( i_time < 0 ) i_time = 0;
+
+            /* Reset the decoders states and clock synch (before calling the demuxer */
+            es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+            input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+
             i_ret = demux2_Control( p_input->input.p_demux,
                                     DEMUX_SET_TIME, i_time );
             if( i_ret )
@@ -1272,9 +1280,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 if( p_input->i_slave > 0 )
                     SlaveSeek( p_input );
 
-                input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
-
-                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                //es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
                 b_force_update = VLC_TRUE;
             }
             break;
index 78adb94..7846f91 100644 (file)
@@ -110,6 +110,7 @@ void stream_AccessUpdate( stream_t *s );
 /* decoder.c FIXME make it public ?*/
 void       input_DecoderDiscontinuity( decoder_t * p_dec );
 vlc_bool_t input_DecoderEmpty( decoder_t * p_dec );
+void       input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end );
 
 /* es_out.c */
 es_out_t  *input_EsOutNew( input_thread_t * );