Commit f5c4d38c authored by Anton Khirnov's avatar Anton Khirnov

qsvdec: properly handle asynchronous decoding

Wait for async_depth frames before syncing.
parent 6b15874f
......@@ -40,6 +40,8 @@ typedef struct QSVFrame {
mfxFrameSurface1 surface_internal;
int queued;
struct QSVFrame *next;
} QSVFrame;
......
......@@ -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);
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment