diff mbox series

[FFmpeg-devel,06/14] avcodec/mpeg12dec: Allocate dummy frames for non-I fields

Message ID GV1SPRMB0021352C081DBBE30BEACF028F1B2@GV1SPRMB0021.EURP250.PROD.OUTLOOK.COM
State New
Headers show
Series [FFmpeg-devel,01/14] avcodec/get_buffer: Remove redundant check | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished

Commit Message

Andreas Rheinhardt April 29, 2024, 12:35 a.m. UTC
MPEG-2 allows to pair an intra field (as first field) together
with a P-field. In this case a conformant bitstream has to satisfy
certain restrictions in order to ensure that only the I field
is used for prediction. See section 7.6.3.5 of the MPEG-2
specifications.

We do not check these restrictions; normally we simply allocate
dummy frames for reference in order to avoid checks lateron.
This happens in ff_mpv_frame_start() and therefore does not happen
for a second field. This is inconsistent. Fix this by allocating
these dummy frames for the second field, too.

This already fixes two bugs:
1. Undefined pointer arithmetic in prefetch_motion() in
mpegvideo_motion.c where it is simply presumed that the reference
frame exists.
2. Several MPEG-2 hardware accelerations rely on last_picture
being allocated for P pictures and next picture for B pictures;
e.g. VDPAU returns VDP_STATUS_INVALID_HANDLE when decoding
an I-P fields pair because the forward_reference was set incorrectly.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/mpeg12dec.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index 21a214ef5b..9940ff898c 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -1372,6 +1372,9 @@  static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
                 return ret;
             }
         }
+        ret = ff_mpv_alloc_dummy_frames(s);
+        if (ret < 0)
+            return ret;
 
         for (int i = 0; i < 3; i++) {
             s->current_picture.f->data[i] = s->current_picture_ptr->f->data[i];
@@ -1727,7 +1730,7 @@  static int slice_decode_thread(AVCodecContext *c, void *arg)
  * Handle slice ends.
  * @return 1 if it seems to be the last slice
  */
-static int slice_end(AVCodecContext *avctx, AVFrame *pict)
+static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output)
 {
     Mpeg1Context *s1  = avctx->priv_data;
     MpegEncContext *s = &s1->mpeg_enc_ctx;
@@ -1758,14 +1761,16 @@  static int slice_end(AVCodecContext *avctx, AVFrame *pict)
                 return ret;
             ff_print_debug_info(s, s->current_picture_ptr, pict);
             ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG2);
+            *got_output = 1;
         } else {
             /* latency of 1 frame for I- and P-frames */
-            if (s->last_picture_ptr) {
+            if (s->last_picture_ptr && !s->last_picture_ptr->dummy) {
                 int ret = av_frame_ref(pict, s->last_picture_ptr->f);
                 if (ret < 0)
                     return ret;
                 ff_print_debug_info(s, s->last_picture_ptr, pict);
                 ff_mpv_export_qp_table(s, pict, s->last_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG2);
+                *got_output = 1;
             }
         }
 
@@ -2204,14 +2209,9 @@  static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
                         s2->er.error_count += s2->thread_context[i]->er.error_count;
                 }
 
-                ret = slice_end(avctx, picture);
+                ret = slice_end(avctx, picture, got_output);
                 if (ret < 0)
                     return ret;
-                else if (ret) {
-                    // FIXME: merge with the stuff in mpeg_decode_slice
-                    if (s2->last_picture_ptr || s2->low_delay || s2->pict_type == AV_PICTURE_TYPE_B)
-                        *got_output = 1;
-                }
             }
             s2->pict_type = 0;