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;
+
+ if (fdd->post_process) {
+ ret = fdd->post_process(avctx, frame);
+ if (ret < 0) {
+ av_frame_unref(frame);
+ return ret;
+ }
+ }
+
+ 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;
}
return 0;
}
+static void decode_data_free(void *opaque, uint8_t *data)
+{
+ FrameDecodeData *fdd = (FrameDecodeData*)data;
+
+ av_buffer_unref(&fdd->user_opaque_ref);
+
+ if (fdd->post_process_opaque_free)
+ fdd->post_process_opaque_free(fdd->post_process_opaque);
+
+ if (fdd->hwaccel_priv_free)
+ fdd->hwaccel_priv_free(fdd->hwaccel_priv);
+
+ 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;
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 &&
frame->height = avctx->height;
}
+ if (ret < 0)
+ av_frame_unref(frame);
+
return ret;
}