From 359a8a3e2d1194b52b6c386f94fd0929567dfb67 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 1 Jul 2017 11:12:44 +0200 Subject: [PATCH] decode: add a method for attaching lavc-internal data to frames Use the AVFrame.opaque_ref field. The original user's opaque_ref is wrapped in the lavc struct and then unwrapped before the frame is returned to the caller. This new struct will be useful in the following commits. --- libavcodec/decode.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ libavcodec/decode.h | 13 +++++++++++ 2 files changed, 70 insertions(+) diff --git a/libavcodec/decode.c b/libavcodec/decode.c index f7cd7f6870..bcc119c829 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -406,6 +406,26 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) if (ret == AVERROR_EOF) avci->draining_done = 1; + /* unwrap the per-frame decode data and restore the original opaque_ref*/ + if (!ret) { + /* the only case where decode data is not set should be decoders + * that do not call ff_get_buffer() */ + av_assert0((frame->opaque_ref && frame->opaque_ref->size == sizeof(FrameDecodeData)) || + !(avctx->codec->capabilities & AV_CODEC_CAP_DR1)); + + if (frame->opaque_ref) { + FrameDecodeData *fdd; + AVBufferRef *user_opaque_ref; + + fdd = (FrameDecodeData*)frame->opaque_ref->data; + + user_opaque_ref = fdd->user_opaque_ref; + fdd->user_opaque_ref = NULL; + av_buffer_unref(&frame->opaque_ref); + frame->opaque_ref = user_opaque_ref; + } + } + return ret; } @@ -988,6 +1008,37 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } +static void decode_data_free(void *opaque, uint8_t *data) +{ + FrameDecodeData *fdd = (FrameDecodeData*)data; + + av_buffer_unref(&fdd->user_opaque_ref); + + av_freep(&fdd); +} + +static int attach_decode_data(AVFrame *frame) +{ + AVBufferRef *fdd_buf; + FrameDecodeData *fdd; + + fdd = av_mallocz(sizeof(*fdd)); + if (!fdd) + return AVERROR(ENOMEM); + + fdd_buf = av_buffer_create((uint8_t*)fdd, sizeof(*fdd), decode_data_free, + NULL, AV_BUFFER_FLAG_READONLY); + if (!fdd_buf) { + av_freep(&fdd); + return AVERROR(ENOMEM); + } + + fdd->user_opaque_ref = frame->opaque_ref; + frame->opaque_ref = fdd_buf; + + return 0; +} + int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) { const AVHWAccel *hwaccel = avctx->hwaccel; @@ -1061,6 +1112,12 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) avctx->sw_pix_fmt = avctx->pix_fmt; ret = avctx->get_buffer2(avctx, frame, flags); + if (ret < 0) + goto end; + + ret = attach_decode_data(frame); + if (ret < 0) + goto end; end: if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions && diff --git a/libavcodec/decode.h b/libavcodec/decode.h index 2f29cf6107..61b53b2445 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -21,8 +21,21 @@ #ifndef AVCODEC_DECODE_H #define AVCODEC_DECODE_H +#include "libavutil/buffer.h" + #include "avcodec.h" +/** + * This struct stores per-frame lavc-internal data and is attached to it via + * opaque_ref. + */ +typedef struct FrameDecodeData { + /** + * The original user-set opaque_ref. + */ + AVBufferRef *user_opaque_ref; +} FrameDecodeData; + /** * Called by decoders to get the next packet for decoding. *