[vlc-commits] codec: avcodec: really drain video (ref #22929)

Francois Cartegnie git at videolan.org
Fri Oct 11 17:28:35 CEST 2019


vlc/vlc-3.0 | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Oct 10 16:51:12 2019 +0200| [f7fa484b8ef5c2bbd96d24a85dc731a016affae1] | committer: Francois Cartegnie

codec: avcodec: really drain video (ref #22929)

could only drain once because of double drain
request/null pkt enqueuing.

> http://git.videolan.org/gitweb.cgi/vlc/vlc-3.0.git/?a=commit;h=f7fa484b8ef5c2bbd96d24a85dc731a016affae1
---

 modules/codec/avcodec/video.c | 95 +++++++++++++++++++++++++------------------
 1 file changed, 55 insertions(+), 40 deletions(-)

diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index c5899fd736..b99eb56e4a 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -80,6 +80,7 @@ struct decoder_sys_t
     /* Hack to force display of still pictures */
     bool b_first_frame;
 
+    bool b_draining;
 
     /* */
     bool palette_sent;
@@ -603,6 +604,7 @@ int InitVideoDec( vlc_object_t *obj )
     p_sys->b_first_frame = true;
     p_sys->i_late_frames = 0;
     p_sys->b_from_preroll = false;
+    p_sys->b_draining = false;
 
     /* Set output properties */
     if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS )
@@ -655,6 +657,7 @@ static void Flush( decoder_t *p_dec )
 
     date_Set(&p_sys->pts, VLC_TS_INVALID); /* To make sure we recover properly */
     p_sys->i_late_frames = 0;
+    p_sys->b_draining = false;
     cc_Flush( &p_sys->cc );
 
     /* Abort pictures in order to unblock all avcodec workers threads waiting
@@ -1001,57 +1004,61 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
                 FF_INPUT_BUFFER_PADDING_SIZE );
     }
 
-    while( !p_block || p_block->i_buffer > 0 || eos_spotted )
+    do
     {
-        int i_used;
-        AVPacket pkt;
+        int ret;
+        int i_used = 0;
+        const bool b_has_data = ( p_block && p_block->i_buffer > 0 );
+        const bool b_start_drain = ((pp_block == NULL) || eos_spotted) && !p_sys->b_draining;
 
         post_mt( p_sys );
 
-        av_init_packet( &pkt );
-        if( p_block && p_block->i_buffer > 0 )
+        if( b_has_data || b_start_drain )
         {
-            pkt.data = p_block->p_buffer;
-            pkt.size = p_block->i_buffer;
-            pkt.pts = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : AV_NOPTS_VALUE;
-            pkt.dts = p_block->i_dts > VLC_TS_INVALID ? p_block->i_dts : AV_NOPTS_VALUE;
-        }
-        else
-        {
-            /* Return delayed frames if codec has CODEC_CAP_DELAY */
-            pkt.data = NULL;
-            pkt.size = 0;
-        }
-
-        if( !p_sys->palette_sent )
-        {
-            uint8_t *pal = av_packet_new_side_data(&pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
-            if (pal) {
-                memcpy(pal, p_dec->fmt_in.video.p_palette->palette, AVPALETTE_SIZE);
-                p_sys->palette_sent = true;
+            AVPacket pkt;
+            av_init_packet( &pkt );
+            if( b_has_data )
+            {
+                pkt.data = p_block->p_buffer;
+                pkt.size = p_block->i_buffer;
+                pkt.pts = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : AV_NOPTS_VALUE;
+                pkt.dts = p_block->i_dts > VLC_TS_INVALID ? p_block->i_dts : AV_NOPTS_VALUE;
+
+                /* Make sure we don't reuse the same timestamps twice */
+                p_block->i_pts =
+                p_block->i_dts = VLC_TS_INVALID;
+            }
+            else /* start drain */
+            {
+                /* Return delayed frames if codec has CODEC_CAP_DELAY */
+                pkt.data = NULL;
+                pkt.size = 0;
+                p_sys->b_draining = true;
             }
-        }
 
-        /* Make sure we don't reuse the same timestamps twice */
-        if( p_block )
-        {
-            p_block->i_pts =
-            p_block->i_dts = VLC_TS_INVALID;
-        }
+            if( !p_sys->palette_sent )
+            {
+                uint8_t *pal = av_packet_new_side_data(&pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+                if (pal) {
+                    memcpy(pal, p_dec->fmt_in.video.p_palette->palette, AVPALETTE_SIZE);
+                    p_sys->palette_sent = true;
+                }
+            }
 
-        int ret = avcodec_send_packet(p_context, &pkt);
-        if( ret != 0 && ret != AVERROR(EAGAIN) )
-        {
-            if (ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))
+            ret = avcodec_send_packet(p_context, &pkt);
+            if( ret != 0 && ret != AVERROR(EAGAIN) )
             {
-                msg_Err(p_dec, "avcodec_send_packet critical error");
-                *error = true;
+                if (ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))
+                {
+                    msg_Err(p_dec, "avcodec_send_packet critical error");
+                    *error = true;
+                }
+                av_packet_unref( &pkt );
+                break;
             }
+            i_used = ret != AVERROR(EAGAIN) ? pkt.size : 0;
             av_packet_unref( &pkt );
-            break;
         }
-        i_used = ret != AVERROR(EAGAIN) ? pkt.size : 0;
-        av_packet_unref( &pkt );
 
         AVFrame *frame = av_frame_alloc();
         if (unlikely(frame == NULL))
@@ -1071,7 +1078,10 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
             av_frame_free(&frame);
             /* After draining, we need to reset decoder with a flush */
             if( ret == AVERROR_EOF )
+            {
                 avcodec_flush_buffers( p_sys->p_context );
+                p_sys->b_draining = false;
+            }
             break;
         }
         bool not_received_frame = ret;
@@ -1232,10 +1242,15 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
         }
         else
             picture_Release( p_pic );
-    }
+    } while( true );
 
     if( p_block )
         block_Release( p_block );
+    if( p_sys->b_draining )
+    {
+        avcodec_flush_buffers( p_sys->p_context );
+        p_sys->b_draining = false;
+    }
     return NULL;
 }
 



More information about the vlc-commits mailing list