From f5c4d38c78347b09478e21a661befff4b2d44643 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 14 Jul 2015 18:16:26 +0200 Subject: qsvdec: properly handle asynchronous decoding Wait for async_depth frames before syncing. --- libavcodec/qsvdec.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'libavcodec/qsvdec.c') diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index 6fd9442b7f..da9b082d09 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -73,6 +73,11 @@ int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q, mfxSession session) mfxVideoParam param = { { 0 } }; int ret; + q->async_fifo = av_fifo_alloc((1 + q->async_depth) * + (sizeof(mfxSyncPoint) + sizeof(QSVFrame*))); + if (!q->async_fifo) + return AVERROR(ENOMEM); + ret = qsv_init_session(avctx, q, session); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n"); @@ -142,7 +147,7 @@ static void qsv_clear_unused_frames(QSVContext *q) { QSVFrame *cur = q->work_frames; while (cur) { - if (cur->surface && !cur->surface->Data.Locked) { + if (cur->surface && !cur->surface->Data.Locked && !cur->queued) { cur->surface = NULL; av_frame_unref(cur->frame); } @@ -191,12 +196,12 @@ static int get_surface(AVCodecContext *avctx, QSVContext *q, mfxFrameSurface1 ** return 0; } -static AVFrame *find_frame(QSVContext *q, mfxFrameSurface1 *surf) +static QSVFrame *find_frame(QSVContext *q, mfxFrameSurface1 *surf) { QSVFrame *cur = q->work_frames; while (cur) { if (surf == cur->surface) - return cur->frame; + return cur; cur = cur->next; } return NULL; @@ -206,6 +211,7 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q, AVFrame *frame, int *got_frame, AVPacket *avpkt) { + QSVFrame *out_frame; mfxFrameSurface1 *insurf; mfxFrameSurface1 *outsurf; mfxSyncPoint sync; @@ -240,21 +246,37 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q, } if (sync) { - AVFrame *src_frame; - - MFXVideoCORE_SyncOperation(q->session, sync, 60000); + QSVFrame *out_frame = find_frame(q, outsurf); - src_frame = find_frame(q, outsurf); - if (!src_frame) { + if (!out_frame) { av_log(avctx, AV_LOG_ERROR, "The returned surface does not correspond to any frame\n"); return AVERROR_BUG; } + out_frame->queued = 1; + av_fifo_generic_write(q->async_fifo, &out_frame, sizeof(out_frame), NULL); + av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL); + } + + if (!av_fifo_space(q->async_fifo) || + (!avpkt->size && av_fifo_size(q->async_fifo))) { + AVFrame *src_frame; + + av_fifo_generic_read(q->async_fifo, &out_frame, sizeof(out_frame), NULL); + av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL); + out_frame->queued = 0; + + MFXVideoCORE_SyncOperation(q->session, sync, 60000); + + src_frame = out_frame->frame; + ret = av_frame_ref(frame, src_frame); if (ret < 0) return ret; + outsurf = out_frame->surface; + frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp; frame->repeat_pict = @@ -283,6 +305,9 @@ int ff_qsv_decode_close(QSVContext *q) cur = q->work_frames; } + av_fifo_free(q->async_fifo); + q->async_fifo = NULL; + if (q->internal_session) MFXClose(q->internal_session); -- cgit v1.2.3