[vlc-devel] [PATCH] avcodec: repeat the pictures marked as repeating

Steve Lhomme robux4 at ycbcr.xyz
Mon Nov 16 14:12:45 CET 2020


The libavutil doc for "repeat_pict" says:
    When decoding, this signals how much the picture must be delayed.
    extra_delay = repeat_pict / (2*fps)

But the one in AVCodecParserContext says:
    This field is used for proper frame duration computation in lavf.
    It signals, how much longer the frame duration of the current frame is
    compared to normal frame duration.

    frame_duration = (1 + repeat_pict) * time_base

    It is used by codecs like H.264 to display telecined material.

In practice it only sets a few values:
- 0 1 picture  in progressive / 1 or 2 fields in interlaced
- 1                             2      fields in interlaced + 1 repeated field
- 2 2 pictures in progressive
- 4 3 pictures in progressive

It should make it easier to remux or reencode on containers with a fixed frame
rate that don't handle gaps between pictures. Each picture has the same base
duration.

In addition the interpolate_next_pts() used the repeat_pict incorrectly as the
value is 2 per progressive picture. So every additional picture was counted as
2 ticks.
---
 modules/codec/avcodec/video.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index 23d1d469394..33b5d2272bb 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -679,7 +679,7 @@ static block_t * filter_earlydropped_blocks( decoder_t *p_dec, block_t *block )
     return block;
 }
 
-static vlc_tick_t interpolate_next_pts( decoder_t *p_dec, AVFrame *frame )
+static vlc_tick_t interpolate_next_pts( decoder_t *p_dec )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     AVCodecContext *p_context = p_sys->p_context;
@@ -693,7 +693,7 @@ static vlc_tick_t interpolate_next_pts( decoder_t *p_dec, AVFrame *frame )
         i_tick = 1;
 
     /* interpolate the next PTS */
-    return date_Increment( &p_sys->pts, i_tick + frame->repeat_pict );
+    return date_Increment( &p_sys->pts, i_tick );
 }
 
 static void update_late_frame_count( decoder_t *p_dec, block_t *p_block,
@@ -1093,7 +1093,7 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         if( i_pts != VLC_TICK_INVALID )
             date_Set( &p_sys->pts, i_pts );
 
-        const vlc_tick_t i_next_pts = interpolate_next_pts(p_dec, frame);
+        const vlc_tick_t i_next_pts = interpolate_next_pts(p_dec);
 
         if( b_first_output_sequence )
         {
@@ -1214,13 +1214,14 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             // interlaced HEVC decoding sends 1 field at a time and isn't signaled by lavc
             p_pic->i_nb_fields = 1;
         else
-            p_pic->i_nb_fields = 2 + frame->repeat_pict;
+            p_pic->i_nb_fields = 2 + frame->repeat_pict % 2;
         p_pic->b_progressive = !frame->interlaced_frame;
         p_pic->b_top_field_first = frame->top_field_first;
 
         if (DecodeSidedata(p_dec, frame, p_pic))
             i_pts = VLC_TICK_INVALID;
 
+        int repeat_pict = frame->repeat_pict / 2;
         av_frame_free(&frame);
 
         /* Send decoded frame to vout */
@@ -1231,6 +1232,13 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             p_sys->b_first_frame = false;
             vlc_mutex_unlock(&p_sys->lock);
             decoder_QueueVideo( p_dec, p_pic );
+            while ( repeat_pict > 0 )
+            {
+                picture_t *p_repeat = picture_Clone( p_pic );
+                p_repeat->date = interpolate_next_pts( p_dec );
+                decoder_QueueVideo( p_dec, p_repeat );
+                repeat_pict --;
+            }
         }
         else
         {
-- 
2.26.2



More information about the vlc-devel mailing list