es_out: do not flush decoder fifo when unwanted (fix broken picture on pause)
authorLaurent Aimar <fenrir@videolan.org>
Wed, 30 May 2007 18:01:15 +0000 (18:01 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Wed, 30 May 2007 18:01:15 +0000 (18:01 +0000)
        do not convert pts/dts of prerolled samples
decoder: fixed ES_OUT_SET_NEXT_DISPLAY_TIME implementation (improved seek)
         proper handling of DISCONTINUITY
         reset video picture heap on seek/pause/rate change (avoid old
         pictures)
Please report any regression.

src/input/decoder.c
src/input/es_out.c
src/input/input.c
src/input/input_internal.h

index 88d31c1..8c8eee1 100644 (file)
@@ -263,19 +263,20 @@ void input_DecoderDecode( decoder_t * p_dec, block_t *p_block )
     }
 }
 
-void input_DecoderDiscontinuity( decoder_t * p_dec )
+void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush )
 {
     block_t *p_null;
 
     /* Empty the fifo */
-    if( p_dec->p_owner->b_own_thread )
-    {
+    if( p_dec->p_owner->b_own_thread && b_flush )
         block_FifoEmpty( p_dec->p_owner->p_fifo );
-    }
 
     /* Send a special block */
     p_null = block_New( p_dec, 128 );
     p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+    /* FIXME check for p_packetizer or b_packitized from es_format_t of input ? */
+    if( p_dec->p_owner->p_packetizer && b_flush )
+        p_null->i_flags |= BLOCK_FLAG_CORRUPTED;
     memset( p_null->p_buffer, 0, p_null->i_buffer );
 
     input_DecoderDecode( p_dec, p_null );
@@ -290,10 +291,6 @@ 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;
-}
 /**
  * Create a decoder object
  *
@@ -440,16 +437,11 @@ static int DecoderThread( decoder_t * p_dec )
     return 0;
 }
 
-/**
- * Decode a block
- *
- * \param p_dec the decoder object
- * \param p_block the block to decode
- * \return VLC_SUCCESS or an error code
- */
 static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p )
 {
-    if( p->i_pts > 0 )
+    if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) )
+        *pi_preroll = INT64_MAX;
+    else if( p->i_pts > 0 )
         *pi_preroll = __MIN( *pi_preroll, p->i_pts );
     else if( p->i_dts > 0 )
         *pi_preroll = __MIN( *pi_preroll, p->i_dts );
@@ -459,65 +451,110 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
     input_thread_t *p_input = p_dec->p_owner->p_input;
     aout_buffer_t *p_aout_buf;
 
-    //DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
     while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
     {
         vlc_mutex_lock( &p_input->p->counters.counters_lock );
         stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_audio, 1, NULL );
         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
 
-        /* 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 )
-//            msg_Err( p_dec, "Prerolling %lld - %lld", p_dec->p_owner->i_preroll_end, p_aout_buf->start_date );
-
-        if( p_dec->p_owner->i_preroll_end > 0 &&
-            p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
+        if( 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 );
+            continue;
         }
-        else
+
+        if( p_dec->p_owner->i_preroll_end > 0 )
         {
+            /* FIXME TODO flush audio output (don't know how to do that) */
+            msg_Dbg( p_dec, "End of audio preroll" );
             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 );
         }
+        aout_DecPlay( p_dec->p_owner->p_aout,
+                      p_dec->p_owner->p_aout_input,
+                      p_aout_buf );
     }
 }
+static void VoutDisplayedPicture( vout_thread_t *p_vout, picture_t *p_pic )
+{
+    vlc_mutex_lock( &p_vout->picture_lock );
+
+    if( p_pic->i_status == READY_PICTURE )
+    {
+        /* Grr cannot destroy ready picture by myself so be sure vout won't like it */
+        p_pic->date = 1;
+    }
+    else if( p_pic->i_refcount > 0 )
+    {
+        p_pic->i_status = DISPLAYED_PICTURE;
+    }
+    else
+    {
+        p_pic->i_status = DESTROYED_PICTURE;
+        p_vout->i_heap_size--;
+    }
+
+    vlc_mutex_unlock( &p_vout->picture_lock );
+}
+static void VoutFlushPicture( vout_thread_t *p_vout )
+{
+    int i;
+    vlc_mutex_lock( &p_vout->picture_lock );
+    for( i = 0; i < p_vout->render.i_pictures; i++ )
+    {
+        picture_t *p_pic = p_vout->render.pp_picture[i];
+
+        if( p_pic->i_status != READY_PICTURE )
+        {
+            /* We cannot change picture status if it is in READY_PICTURE state,
+             * Just make sure they won't be displayed */
+            p_pic->date = 1;
+        }
+    }
+    vlc_mutex_unlock( &p_vout->picture_lock );
+}
 static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
 {
     input_thread_t *p_input = p_dec->p_owner->p_input;
     picture_t *p_pic;
 
-    //DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
     while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
     {
         vlc_mutex_lock( &p_input->p->counters.counters_lock );
         stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_video, 1, NULL );
         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
 
-        if( p_dec->p_owner->i_preroll_end > 0 &&
-            p_pic->date < p_dec->p_owner->i_preroll_end )
+        if( p_pic->date < p_dec->p_owner->i_preroll_end )
         {
-            vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
+            VoutDisplayedPicture( p_dec->p_owner->p_vout, p_pic );
+            continue;
         }
-        else
+
+        if( p_dec->p_owner->i_preroll_end > 0 )
         {
+            msg_Dbg( p_dec, "End of video preroll" );
+            if( p_dec->p_owner->p_vout )
+                VoutFlushPicture( p_dec->p_owner->p_vout );
+            /* */
             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 );
         }
+
+        vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
+                          p_pic->date );
+        vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
     }
 }
 
-
+/**
+ * Decode a block
+ *
+ * \param p_dec the decoder object
+ * \param p_block the block to decode
+ * \return VLC_SUCCESS or an error code
+ */
 static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
 {
-    int i_rate = p_block ? p_block->i_rate : 1000;
+    const int i_rate = p_block ? p_block->i_rate : INPUT_RATE_DEFAULT;
 
     if( p_block && p_block->i_buffer <= 0 )
     {
@@ -596,6 +633,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
     }
     else if( p_dec->fmt_in.i_cat == AUDIO_ES )
     {
+        DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
+
         if( p_dec->p_owner->p_packetizer )
         {
             block_t *p_packetized_block;
@@ -629,6 +668,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
     }
     else if( p_dec->fmt_in.i_cat == VIDEO_ES )
     {
+        DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
+
         if( p_dec->p_owner->p_packetizer )
         {
             block_t *p_packetized_block;
@@ -665,22 +706,22 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
         input_thread_t *p_input = p_dec->p_owner->p_input;
         vout_thread_t *p_vout;
         subpicture_t *p_spu;
-        //DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
+
+        DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
+
         while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) )
         {
             vlc_mutex_lock( &p_input->p->counters.counters_lock );
             stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_sub, 1, NULL );
             vlc_mutex_unlock( &p_input->p->counters.counters_lock );
 
-            if( p_dec->p_owner->i_preroll_end > 0 &&
-                p_spu->i_start < p_dec->p_owner->i_preroll_end &&
+            if( 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 )
             {
@@ -977,7 +1018,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec )
 
 static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic )
 {
-    vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
+    VoutDisplayedPicture( p_dec->p_owner->p_vout, p_pic );
 }
 
 static void vout_link_picture( decoder_t *p_dec, picture_t *p_pic )
index 77b8204..504fff8 100644 (file)
@@ -70,9 +70,6 @@ struct es_out_id_t
     int       i_id;
     es_out_pgrm_t *p_pgrm;
 
-    /* Signal a discontinuity in the timeline for every PID */
-    vlc_bool_t b_discontinuity;
-
     /* Misc. */
     int64_t i_preroll_end;
 
@@ -302,7 +299,7 @@ es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
     return NULL;
 }
 
-void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
+void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio )
 {
     es_out_sys_t      *p_sys = out->p_sys;
     int i;
@@ -310,14 +307,11 @@ void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
     for( i = 0; i < p_sys->i_es; i++ )
     {
         es_out_id_t *es = p_sys->es[i];
-        es->b_discontinuity = VLC_TRUE; /* signal discontinuity */
 
         /* Send a dummy block to let decoder know that
          * there is a discontinuity */
         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
-        {
-            input_DecoderDiscontinuity( es->p_dec );
-        }
+            input_DecoderDiscontinuity( es->p_dec, b_flush );
     }
 }
 
@@ -851,7 +845,6 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
     es->p_pgrm = p_pgrm;
     es_format_Copy( &es->fmt, fmt );
     es->i_preroll_end = -1;
-    es->b_discontinuity = VLC_FALSE;
 
     switch( fmt->i_cat )
     {
@@ -1225,13 +1218,21 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
     }
 
     /* +11 -> avoid null value with non null dts/pts */
-    if( p_block->i_dts > 0 )
+    if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
+    {
+        p_block->i_dts += i_delay;
+    }
+    else if( p_block->i_dts > 0 )
     {
         p_block->i_dts =
             input_ClockGetTS( p_input, &p_pgrm->clock,
                               ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
     }
-    if( p_block->i_pts > 0 )
+    if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
+    {
+        p_block->i_pts += i_delay;
+    }
+    else if( p_block->i_pts > 0 )
     {
         p_block->i_pts =
             input_ClockGetTS( p_input, &p_pgrm->clock,
@@ -1607,8 +1608,10 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
             if( !es || !es->p_dec )
                 return VLC_EGENERIC;
 
+            /* XXX We should call input_ClockGetTS but PCR has been reseted
+             * and it will return 0, so we won't call input_ClockGetTS on all preroll samples
+             * but that's ugly(more time discontinuity), it need to be improved -- fenrir */
             es->i_preroll_end = i_date;
-            input_DecoderPreroll( es->p_dec, i_date );
 
             return VLC_SUCCESS;
         }
index 73c4d57..4e59924 100644 (file)
@@ -1480,7 +1480,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             if( f_pos > 1.0 ) f_pos = 1.0;
             /* Reset the decoders states and clock sync (before calling the demuxer */
             es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
-            input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
+            input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
             if( demux2_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION,
                                 f_pos ) )
             {
@@ -1518,7 +1518,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
 
             /* Reset the decoders states and clock sync (before calling the demuxer */
             es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
-            input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
+            input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
 
             i_ret = demux2_Control( p_input->p->input.p_demux,
                                     DEMUX_SET_TIME, i_time );
@@ -1609,11 +1609,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 p_input->i_state = val.i_int;
                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
 
-#if 0 /* This will need modifications to decoders to work properly. */
                 /* Send discontinuity to decoders (it will allow them to flush
                  * if implemented */
-                input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
-#endif
+                input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE, VLC_FALSE );
             }
             else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause )
             {
@@ -1666,7 +1664,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
 
                 /* We will not send audio data if new rate != default */
                 if( i_rate != INPUT_RATE_DEFAULT && p_input->p->i_rate == INPUT_RATE_DEFAULT )
-                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE );
+                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_TRUE );
 
                 p_input->p->i_rate  = i_rate;
 
@@ -1726,8 +1724,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
 
                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
                 {
-                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
+                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
 
                     demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
                     input_ControlVarTitle( p_input, i_title );
@@ -1747,8 +1745,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
 
                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
                 {
-                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
+                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
 
                     access2_Control( p_access, ACCESS_SET_TITLE, i_title );
                     stream_AccessReset( p_input->p->input.p_stream );
@@ -1788,8 +1786,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 if( i_seekpoint >= 0 && i_seekpoint <
                     p_input->p->input.title[p_demux->info.i_title]->i_seekpoint )
                 {
-                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
+                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
 
                     demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
                 }
@@ -1824,8 +1822,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 if( i_seekpoint >= 0 && i_seekpoint <
                     p_input->p->input.title[p_access->info.i_title]->i_seekpoint )
                 {
-                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
+                    input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
 
                     access2_Control( p_access, ACCESS_SET_SEEKPOINT,
                                     i_seekpoint );
index ff63425..6b56a88 100644 (file)
@@ -246,15 +246,14 @@ void stream_AccessReset( stream_t *s );
 void stream_AccessUpdate( stream_t *s );
 
 /* decoder.c */
-void       input_DecoderDiscontinuity( decoder_t * p_dec );
+void       input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush );
 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 * );
 void       input_EsOutDelete( es_out_t * );
 es_out_id_t *input_EsOutGetFromID( es_out_t *, int i_id );
-void       input_EsOutDiscontinuity( es_out_t *, vlc_bool_t b_audio );
+void       input_EsOutDiscontinuity( es_out_t *, vlc_bool_t b_flush, vlc_bool_t b_audio );
 void       input_EsOutSetDelay( es_out_t *, int i_cat, int64_t );
 vlc_bool_t input_EsOutDecodersEmpty( es_out_t * );