[PATCH 10/18] avcodec/h264_slice: do not reclaim the picture awaiting output
Dom Cobley via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
h264_select_output_frame() clears DELAYED_PIC_REF on the picture it selects, so from then until the caller hands it over at the end of the packet a non-reference picture has reference == 0 and nothing stops release_unused_pictures() from reclaiming it. No further picture starts in that window today, but one does as soon as a second picture of the same access unit starts, as an MVC dependent view does, so guard against it. The pointer must then be cleared once the picture has been handed over. It is otherwise still set when release_unused_pictures() runs at the top of the next frame_start(), and the guard keeps a picture that was already output occupying its DPB slot for another access unit. That is observable: it changes which buffer the next allocation reuses, and so changes the concealed output of a stream damaged enough to be relying on it. Signed-off-by: Dom Cobley <[email protected]> --- libavcodec/h264_slice.c | 1 + libavcodec/h264dec.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 33cb20f922..d1838f814b 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -122,6 +122,7 @@ static void release_unused_pictures(H264Context *h, int remove_current) /* release non reference frames */ for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) { if (h->DPB[i].f->buf[0] && !h->DPB[i].reference && + &h->DPB[i] != h->next_output_pic && (remove_current || &h->DPB[i] != h->cur_pic_ptr)) { ff_h264_unref_picture(&h->DPB[i]); } diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 17baef28d2..9f424aaf06 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -1147,6 +1147,11 @@ static int h264_decode_packet(AVCodecContext *avctx, AVPacket *avpkt) if (ret < 0) return ret; } + + /* Handed over; the hold release_unused_pictures() keeps on it must end + * here, or the next packet's frame_start() sees a stale pointer and + * leaves the picture occupying a DPB slot for another access unit. */ + h->next_output_pic = NULL; } ff_h264_unref_picture(&h->last_pic_for_ec); -- 2.53.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]