aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2024-04-28 01:45:47 +0200
committerAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2024-06-12 10:50:12 +0200
commitc85508f5a91cc0caf18ba33c941536bf8b99b81b (patch)
tree0ccf7aba8369d00590493b10529e8e844eca03ea
parent73676dd47ac36f975b430f6a60a09144357523c3 (diff)
downloadffmpeg-c85508f5a91cc0caf18ba33c941536bf8b99b81b.tar.gz
avcodec/mpeg12dec: Allocate dummy frames for non-I fields
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>
-rw-r--r--libavcodec/mpeg12dec.c16
1 files changed, 8 insertions, 8 deletions
diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index 9fd765f030..f6ec528bce 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;