]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/qsvdec.c
Merge commit '7fc8d8a1b3da1666176b3d92e989ee74f3ef014e'
[ffmpeg] / libavcodec / qsvdec.c
index 52df028ce3fdc2f2914c43083f77d87489c40e3a..26467313fcd45da6b02da3e56e4a5b063e80c158 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "avcodec.h"
 #include "internal.h"
+#include "qsv.h"
 #include "qsv_internal.h"
 #include "qsvdec.h"
 
@@ -48,37 +49,33 @@ int ff_qsv_map_pixfmt(enum AVPixelFormat format)
     }
 }
 
-static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session)
+int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q)
 {
-    if (!session) {
-        if (!q->internal_qs.session) {
-            int ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, NULL);
-            if (ret < 0)
-                return ret;
-        }
-
-        q->session = q->internal_qs.session;
-    } else {
-        q->session = session;
-    }
+    mfxVideoParam param = { { 0 } };
+    int ret;
 
-    /* make sure the decoder is uninitialized */
-    MFXVideoDECODE_Close(q->session);
+    q->async_fifo = av_fifo_alloc((1 + q->async_depth) *
+                                  (sizeof(mfxSyncPoint) + sizeof(QSVFrame*)));
+    if (!q->async_fifo)
+        return AVERROR(ENOMEM);
 
-    return 0;
-}
+    q->iopattern  = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
 
-int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q, mfxSession session)
-{
-    mfxVideoParam param = { { 0 } };
-    int ret;
+    if (avctx->hwaccel_context) {
+        AVQSVContext *qsv = avctx->hwaccel_context;
 
-    ret = qsv_init_session(avctx, q, session);
-    if (ret < 0) {
-        av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n");
-        return ret;
+        q->session        = qsv->session;
+        q->iopattern      = qsv->iopattern;
+        q->ext_buffers    = qsv->ext_buffers;
+        q->nb_ext_buffers = qsv->nb_ext_buffers;
     }
+    if (!q->session) {
+        ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, NULL);
+        if (ret < 0)
+            return ret;
 
+        q->session = q->internal_qs.session;
+    }
 
     ret = ff_qsv_codec_id_to_mfx(avctx->codec_id);
     if (ret < 0)
@@ -142,7 +139,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 +188,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 +203,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 +238,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 =
@@ -282,6 +296,13 @@ int ff_qsv_decode_close(QSVContext *q)
         av_freep(&cur);
         cur = q->work_frames;
     }
+
+    av_fifo_free(q->async_fifo);
+    q->async_fifo = NULL;
+
+    MFXVideoDECODE_Close(q->session);
+    q->session = NULL;
+
     ff_qsv_close_internal_session(&q->internal_qs);
 
     return 0;