qsvenc: add an API for allocating opaque surfaces
authorAnton Khirnov <anton@khirnov.net>
Sun, 11 Oct 2015 20:02:26 +0000 (22:02 +0200)
committerAnton Khirnov <anton@khirnov.net>
Fri, 16 Oct 2015 18:00:40 +0000 (20:00 +0200)
doc/APIchanges
libavcodec/qsv.h
libavcodec/qsvenc.c
libavcodec/qsvenc.h

index 26f8816..5be090a 100644 (file)
@@ -13,6 +13,9 @@ libavutil:     2015-08-28
 
 API changes, most recent first:
 
+2015-xx-xx - xxxxxxx - lavc 57.0.0 - qsv.h
+  Add an API for allocating opaque surfaces.
+
 2015-xx-xx - xxxxxxx - lavu 55.2.0 - dict.h
   Change return type of av_dict_copy() from void to int, so that a proper
   error code can be reported.
index 922b858..1d1f8b4 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <mfx/mfxvideo.h>
 
+#include "libavutil/buffer.h"
+
 /**
  * This struct is used for communicating QSV parameters between libavcodec and
  * the caller. It is managed by the caller and must be assigned to
@@ -48,6 +50,51 @@ typedef struct AVQSVContext {
      */
     mfxExtBuffer **ext_buffers;
     int         nb_ext_buffers;
+
+    /**
+     * Encoding only. If this field is set to non-zero by the caller, libavcodec
+     * will create an mfxExtOpaqueSurfaceAlloc extended buffer and pass it to
+     * the encoder initialization. This only makes sense if iopattern is also
+     * set to MFX_IOPATTERN_IN_OPAQUE_MEMORY.
+     *
+     * The number of allocated opaque surfaces will be the sum of the number
+     * required by the encoder and the user-provided value nb_opaque_surfaces.
+     * The array of the opaque surfaces will be exported to the caller through
+     * the opaque_surfaces field.
+     */
+    int opaque_alloc;
+
+    /**
+     * Encoding only, and only if opaque_alloc is set to non-zero. Before
+     * calling avcodec_open2(), the caller should set this field to the number
+     * of extra opaque surfaces to allocate beyond what is required by the
+     * encoder.
+     *
+     * On return from avcodec_open2(), this field will be set by libavcodec to
+     * the total number of allocated opaque surfaces.
+     */
+    int nb_opaque_surfaces;
+
+    /**
+     * Encoding only, and only if opaque_alloc is set to non-zero. On return
+     * from avcodec_open2(), this field will be used by libavcodec to export the
+     * array of the allocated opaque surfaces to the caller, so they can be
+     * passed to other parts of the pipeline.
+     *
+     * The buffer reference exported here is owned and managed by libavcodec,
+     * the callers should make their own reference with av_buffer_ref() and free
+     * it with av_buffer_unref() when it is no longer needed.
+     *
+     * The buffer data is an nb_opaque_surfaces-sized array of mfxFrameSurface1.
+     */
+    AVBufferRef *opaque_surfaces;
+
+    /**
+     * Encoding only, and only if opaque_alloc is set to non-zero. On return
+     * from avcodec_open2(), this field will be set to the surface type used in
+     * the opaque allocation request.
+     */
+    int opaque_alloc_type;
 } AVQSVContext;
 
 /**
index 195713c..d17ceaa 100644 (file)
@@ -134,7 +134,7 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
         q->extco.CAVLC                = avctx->coder_type == FF_CODER_TYPE_VLC ?
                                         MFX_CODINGOPTION_ON : MFX_CODINGOPTION_UNKNOWN;
 
-        q->extparam_internal[0] = (mfxExtBuffer *)&q->extco;
+        q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco;
     }
 
     return 0;
@@ -187,8 +187,46 @@ static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q)
     return 0;
 }
 
+static int qsv_init_opaque_alloc(AVCodecContext *avctx, QSVEncContext *q)
+{
+    AVQSVContext *qsv = avctx->hwaccel_context;
+    mfxFrameSurface1 *surfaces;
+    int nb_surfaces, i;
+
+    nb_surfaces = qsv->nb_opaque_surfaces + q->req.NumFrameSuggested + q->async_depth;
+
+    q->opaque_alloc_buf = av_buffer_allocz(sizeof(*surfaces) * nb_surfaces);
+    if (!q->opaque_alloc_buf)
+        return AVERROR(ENOMEM);
+
+    q->opaque_surfaces = av_malloc_array(nb_surfaces, sizeof(*q->opaque_surfaces));
+    if (!q->opaque_surfaces)
+        return AVERROR(ENOMEM);
+
+    surfaces = (mfxFrameSurface1*)q->opaque_alloc_buf->data;
+    for (i = 0; i < nb_surfaces; i++) {
+        surfaces[i].Info      = q->req.Info;
+        q->opaque_surfaces[i] = surfaces + i;
+    }
+
+    q->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
+    q->opaque_alloc.Header.BufferSz = sizeof(q->opaque_alloc);
+    q->opaque_alloc.In.Surfaces     = q->opaque_surfaces;
+    q->opaque_alloc.In.NumSurface   = nb_surfaces;
+    q->opaque_alloc.In.Type         = q->req.Type;
+
+    q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->opaque_alloc;
+
+    qsv->nb_opaque_surfaces = nb_surfaces;
+    qsv->opaque_surfaces    = q->opaque_alloc_buf;
+    qsv->opaque_alloc_type  = q->req.Type;
+
+    return 0;
+}
+
 int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
 {
+    int opaque_alloc = 0;
     int ret;
 
     q->param.IOPattern  = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
@@ -204,6 +242,8 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
 
         q->session         = qsv->session;
         q->param.IOPattern = qsv->iopattern;
+
+        opaque_alloc = qsv->opaque_alloc;
     }
 
     if (!q->session) {
@@ -225,11 +265,17 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
         return ff_qsv_error(ret);
     }
 
+    if (opaque_alloc) {
+        ret = qsv_init_opaque_alloc(avctx, q);
+        if (ret < 0)
+            return ret;
+    }
+
     if (avctx->hwaccel_context) {
         AVQSVContext *qsv = avctx->hwaccel_context;
         int i, j;
 
-        q->extparam = av_mallocz_array(qsv->nb_ext_buffers + FF_ARRAY_ELEMS(q->extparam_internal),
+        q->extparam = av_mallocz_array(qsv->nb_ext_buffers + q->nb_extparam_internal,
                                        sizeof(*q->extparam));
         if (!q->extparam)
             return AVERROR(ENOMEM);
@@ -239,7 +285,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
             q->param.ExtParam[i] = qsv->ext_buffers[i];
         q->param.NumExtParam = qsv->nb_ext_buffers;
 
-        for (i = 0; i < FF_ARRAY_ELEMS(q->extparam_internal); i++) {
+        for (i = 0; i < q->nb_extparam_internal; i++) {
             for (j = 0; j < qsv->nb_ext_buffers; j++) {
                 if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]->BufferId)
                     break;
@@ -251,7 +297,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
         }
     } else {
         q->param.ExtParam    = q->extparam_internal;
-        q->param.NumExtParam = FF_ARRAY_ELEMS(q->extparam_internal);
+        q->param.NumExtParam = q->nb_extparam_internal;
     }
 
     ret = MFXVideoENCODE_Init(q->session, &q->param);
@@ -537,6 +583,9 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q)
     av_fifo_free(q->async_fifo);
     q->async_fifo = NULL;
 
+    av_freep(&q->opaque_surfaces);
+    av_buffer_unref(&q->opaque_alloc_buf);
+
     av_freep(&q->extparam);
 
     return 0;
index d240c7c..fdfc18b 100644 (file)
@@ -49,7 +49,14 @@ typedef struct QSVEncContext {
     mfxFrameAllocRequest req;
 
     mfxExtCodingOption  extco;
-    mfxExtBuffer  *extparam_internal[1];
+
+    mfxExtOpaqueSurfaceAlloc opaque_alloc;
+    mfxFrameSurface1       **opaque_surfaces;
+    AVBufferRef             *opaque_alloc_buf;
+
+    mfxExtBuffer  *extparam_internal[2];
+    int         nb_extparam_internal;
+
     mfxExtBuffer **extparam;
 
     AVFifoBuffer *async_fifo;