diff options
author | Anton Khirnov <anton@khirnov.net> | 2015-07-14 18:16:26 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2015-07-19 09:47:45 +0200 |
commit | f5c4d38c78347b09478e21a661befff4b2d44643 (patch) | |
tree | a7744aeda4fde5ee1c408fb02fe2ba50f7cb6aca | |
parent | 6b15874fc2c3f565732201f7907ae1112727d6ae (diff) | |
download | ffmpeg-f5c4d38c78347b09478e21a661befff4b2d44643.tar.gz |
qsvdec: properly handle asynchronous decoding
Wait for async_depth frames before syncing.
-rw-r--r-- | libavcodec/qsv_internal.h | 2 | ||||
-rw-r--r-- | libavcodec/qsvdec.c | 41 | ||||
-rw-r--r-- | libavcodec/qsvdec.h | 3 |
3 files changed, 38 insertions, 8 deletions
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index a0f4c7cef3..949f6ebf9b 100644 --- a/libavcodec/qsv_internal.h +++ b/libavcodec/qsv_internal.h @@ -40,6 +40,8 @@ typedef struct QSVFrame { mfxFrameSurface1 surface_internal; + int queued; + struct QSVFrame *next; } QSVFrame; 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); diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index 486a7e3c54..01f7690137 100644 --- a/libavcodec/qsvdec.h +++ b/libavcodec/qsvdec.h @@ -28,6 +28,7 @@ #include <mfx/mfxvideo.h> +#include "libavutil/fifo.h" #include "libavutil/frame.h" #include "libavutil/pixfmt.h" @@ -47,6 +48,8 @@ typedef struct QSVContext { */ QSVFrame *work_frames; + AVFifoBuffer *async_fifo; + // options set by the caller int async_depth; int iopattern; |