qsvdec: fix a memleak of async_fifo
[ffmpeg.git] / libavcodec / qsvdec.c
index 03e31c5..ef781d9 100644 (file)
 
 #include "avcodec.h"
 #include "internal.h"
+#include "qsv_internal.h"
 #include "qsvdec.h"
 
-int ff_qsv_error(int mfx_err)
-{
-    switch (mfx_err) {
-    case MFX_ERR_NONE:
-        return 0;
-    case MFX_ERR_MEMORY_ALLOC:
-    case MFX_ERR_NOT_ENOUGH_BUFFER:
-        return AVERROR(ENOMEM);
-    case MFX_ERR_INVALID_HANDLE:
-        return AVERROR(EINVAL);
-    case MFX_ERR_DEVICE_FAILED:
-    case MFX_ERR_DEVICE_LOST:
-    case MFX_ERR_LOCK_MEMORY:
-        return AVERROR(EIO);
-    case MFX_ERR_NULL_PTR:
-    case MFX_ERR_UNDEFINED_BEHAVIOR:
-    case MFX_ERR_NOT_INITIALIZED:
-        return AVERROR_BUG;
-    case MFX_ERR_UNSUPPORTED:
-    case MFX_ERR_NOT_FOUND:
-        return AVERROR(ENOSYS);
-    case MFX_ERR_MORE_DATA:
-    case MFX_ERR_MORE_SURFACE:
-    case MFX_ERR_MORE_BITSTREAM:
-        return AVERROR(EAGAIN);
-    case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
-    case MFX_ERR_INVALID_VIDEO_PARAM:
-        return AVERROR(EINVAL);
-    case MFX_ERR_ABORTED:
-    case MFX_ERR_UNKNOWN:
-    default:
-        return AVERROR_UNKNOWN;
-    }
-}
-
 int ff_qsv_map_pixfmt(enum AVPixelFormat format)
 {
     switch (format) {
@@ -82,58 +48,13 @@ int ff_qsv_map_pixfmt(enum AVPixelFormat format)
     }
 }
 
-static int codec_id_to_mfx(enum AVCodecID codec_id)
-{
-    switch (codec_id) {
-    case AV_CODEC_ID_H264:
-        return MFX_CODEC_AVC;
-    case AV_CODEC_ID_MPEG1VIDEO:
-    case AV_CODEC_ID_MPEG2VIDEO:
-        return MFX_CODEC_MPEG2;
-    case AV_CODEC_ID_VC1:
-        return MFX_CODEC_VC1;
-    default:
-        break;
-    }
-
-    return AVERROR(ENOSYS);
-}
-
 static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session)
 {
     if (!session) {
         if (!q->internal_session) {
-            mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
-            mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
-
-            const char *desc;
-            int ret;
-
-            ret = MFXInit(impl, &ver, &q->internal_session);
-            if (ret < 0) {
-                av_log(avctx, AV_LOG_ERROR, "Error initializing an internal MFX session\n");
-                return ff_qsv_error(ret);
-            }
-
-            MFXQueryIMPL(q->internal_session, &impl);
-
-            switch (MFX_IMPL_BASETYPE(impl)) {
-            case MFX_IMPL_SOFTWARE:
-                desc = "software";
-                break;
-            case MFX_IMPL_HARDWARE:
-            case MFX_IMPL_HARDWARE2:
-            case MFX_IMPL_HARDWARE3:
-            case MFX_IMPL_HARDWARE4:
-                desc = "hardware accelerated";
-                break;
-            default:
-                desc = "unknown";
-            }
-
-            av_log(avctx, AV_LOG_VERBOSE,
-                   "Initialized an internal MFX session using %s implementation\n",
-                   desc);
+            int ret = ff_qsv_init_internal_session(avctx, &q->internal_session, NULL);
+            if (ret < 0)
+                return ret;
         }
 
         q->session = q->internal_session;
@@ -147,11 +68,18 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
     return 0;
 }
 
-int ff_qsv_init(AVCodecContext *avctx, QSVContext *q, mfxSession session)
+int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q, mfxSession session)
 {
     mfxVideoParam param = { { 0 } };
     int ret;
 
+    if (!q->async_fifo) {
+        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");
@@ -159,7 +87,7 @@ int ff_qsv_init(AVCodecContext *avctx, QSVContext *q, mfxSession session)
     }
 
 
-    ret = codec_id_to_mfx(avctx->codec_id);
+    ret = ff_qsv_codec_id_to_mfx(avctx->codec_id);
     if (ret < 0)
         return ret;
 
@@ -221,7 +149,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);
         }
@@ -270,12 +198,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;
@@ -285,6 +213,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;
@@ -318,22 +247,45 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
         return ff_qsv_error(ret);
     }
 
-    if (sync) {
-        AVFrame *src_frame;
+    /* make sure we do not enter an infinite loop if the SDK
+     * did not consume any data and did not return anything */
+    if (!sync && !bs.DataOffset) {
+        av_log(avctx, AV_LOG_WARNING, "A decode call did not consume any data\n");
+        bs.DataOffset = avpkt->size;
+    }
 
-        MFXVideoCORE_SyncOperation(q->session, sync, 60000);
+    if (sync) {
+        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 =
@@ -351,7 +303,7 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
     return bs.DataOffset;
 }
 
-int ff_qsv_close(QSVContext *q)
+int ff_qsv_decode_close(QSVContext *q)
 {
     QSVFrame *cur = q->work_frames;
 
@@ -362,6 +314,9 @@ int ff_qsv_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);