diff mbox series

[FFmpeg-devel,02/13] lavu/hwcontext_qsv: create dynamic frame pool if required

Message ID 20230906060052.698620-2-haihao.xiang@intel.com
State New
Headers show
Series [FFmpeg-devel,01/13] lavu/hwcontext_qsv: update AVQSVFramesContext to support dynamic frame pools | expand

Commit Message

Xiang, Haihao Sept. 6, 2023, 6 a.m. UTC
From: Haihao Xiang <haihao.xiang@intel.com>

When AVHWFramesContext.initial_pool_size is 0, a dynamic frame pool is
required. We may support this under certain conditions, e.g. oneVPL 2.9+
support dynamic frame allocation, we needn't provide a fixed frame pool
in the mfxFrameAllocator.Alloc callback.

Signed-off-by: Haihao Xiang <haihao.xiang@intel.com>
---
 libavutil/hwcontext_qsv.c | 157 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index b76a89d13a..21ce4225bd 100644
--- a/libavutil/hwcontext_qsv.c
+++ b/libavutil/hwcontext_qsv.c
@@ -104,8 +104,15 @@  typedef struct QSVFramesContext {
 #endif
     AVFrame realigned_upload_frame;
     AVFrame realigned_download_frame;
+
+    mfxFrameInfo frame_info;
 } QSVFramesContext;
 
+typedef struct QSVSurface {
+    mfxFrameSurface1 mfx_surface;
+    AVFrame *child_frame;
+} QSVSurface;
+
 static const struct {
     enum AVPixelFormat pix_fmt;
     uint32_t           fourcc;
@@ -151,6 +158,8 @@  extern int ff_qsv_get_surface_base_handle(mfxFrameSurface1 *surf,
                                           enum AVHWDeviceType base_dev_type,
                                           void **base_handle);
 
+static int qsv_init_surface(AVHWFramesContext *ctx, mfxFrameSurface1 *surf);
+
 /**
  * Caller needs to allocate enough space for base_handle pointer.
  **/
@@ -359,7 +368,32 @@  static void qsv_pool_release_dummy(void *opaque, uint8_t *data)
 {
 }
 
-static AVBufferRef *qsv_pool_alloc(void *opaque, size_t size)
+static void qsv_pool_release(void *opaque, uint8_t *data)
+{
+    AVHWFramesContext *ctx = (AVHWFramesContext*)opaque;
+    QSVFramesContext *s = ctx->internal->priv;
+    QSVSurface *qsv_surface = (QSVSurface *)data;
+    mfxHDLPair *hdl_pair = (mfxHDLPair *)qsv_surface->mfx_surface.Data.MemId;
+    AVHWFramesContext *child_frames_ctx;
+
+    if (!s->child_frames_ref)
+        return;
+
+    child_frames_ctx = (AVHWFramesContext*)s->child_frames_ref->data;
+    if (!child_frames_ctx->device_ctx)
+        return;
+
+#if CONFIG_VAAPI
+    if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_VAAPI)
+        av_freep(&hdl_pair->first);
+#endif
+
+    av_freep(&hdl_pair);
+    av_frame_free(&qsv_surface->child_frame);
+    av_freep(&qsv_surface);
+}
+
+static AVBufferRef *qsv_fixed_pool_alloc(void *opaque, size_t size)
 {
     AVHWFramesContext    *ctx = (AVHWFramesContext*)opaque;
     QSVFramesContext       *s = ctx->internal->priv;
@@ -374,6 +408,104 @@  static AVBufferRef *qsv_pool_alloc(void *opaque, size_t size)
     return NULL;
 }
 
+static AVBufferRef *qsv_dynamic_pool_alloc(void *opaque, size_t size)
+{
+    AVHWFramesContext    *ctx = (AVHWFramesContext*)opaque;
+    QSVFramesContext       *s = ctx->internal->priv;
+    AVHWFramesContext *child_frames_ctx;
+    QSVSurface *qsv_surface = NULL;
+    mfxHDLPair *handle_pairs_internal = NULL;
+    int ret;
+
+    if (!s->child_frames_ref)
+        goto fail;
+
+    child_frames_ctx = (AVHWFramesContext*)s->child_frames_ref->data;
+    if (!child_frames_ctx->device_ctx)
+        goto fail;
+
+#if CONFIG_DXVA2
+    if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
+        av_log(ctx, AV_LOG_ERROR,
+               "QSV on dxva2 requires a fixed frame pool size\n");
+        goto fail;
+    }
+#endif
+
+    qsv_surface = av_calloc(1, sizeof(*qsv_surface));
+    if (!qsv_surface)
+        goto fail;
+
+    qsv_surface->child_frame = av_frame_alloc();
+    if (!qsv_surface->child_frame)
+        goto fail;
+
+    ret = av_hwframe_get_buffer(s->child_frames_ref, qsv_surface->child_frame, 0);
+    if (ret < 0)
+        goto fail;
+
+    handle_pairs_internal = av_calloc(1, sizeof(*handle_pairs_internal));
+    if (!handle_pairs_internal)
+        goto fail;
+
+    ret = qsv_init_surface(ctx, &qsv_surface->mfx_surface);
+    if (ret < 0)
+        goto fail;
+
+#if CONFIG_VAAPI
+    if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_VAAPI) {
+        VASurfaceID *surface_id_internal;
+
+        surface_id_internal = av_calloc(1, sizeof(*surface_id_internal));
+        if (!surface_id_internal)
+            return NULL;
+
+        *surface_id_internal = (VASurfaceID)(uintptr_t)qsv_surface->child_frame->data[3];
+        handle_pairs_internal->first = (mfxHDL)surface_id_internal;
+        handle_pairs_internal->second = (mfxMemId)MFX_INFINITE;
+    }
+#endif
+
+#if CONFIG_D3D11VA
+    if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
+        AVD3D11VAFramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
+        handle_pairs_internal->first = (mfxMemId)qsv_surface->child_frame->data[0];
+
+        if (child_frames_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET)
+            handle_pairs_internal->second = (mfxMemId)MFX_INFINITE;
+        else
+            handle_pairs_internal->second = (mfxMemId)qsv_surface->child_frame->data[1];
+
+    }
+#endif
+
+    qsv_surface->mfx_surface.Data.MemId = (mfxMemId)handle_pairs_internal;
+    return av_buffer_create((uint8_t *)qsv_surface, sizeof(*qsv_surface),
+                            qsv_pool_release, ctx, 0);
+
+fail:
+    if (qsv_surface) {
+        av_frame_free(&qsv_surface->child_frame);
+    }
+
+    av_freep(&qsv_surface);
+    av_freep(&handle_pairs_internal);
+
+    return NULL;
+}
+
+static AVBufferRef *qsv_pool_alloc(void *opaque, size_t size)
+{
+    AVHWFramesContext    *ctx = (AVHWFramesContext*)opaque;
+    AVQSVFramesContext *hwctx = ctx->hwctx;
+
+    if (hwctx->nb_surfaces == 0) {
+        return qsv_dynamic_pool_alloc(opaque, size);
+    } else {
+        return qsv_fixed_pool_alloc(opaque, size);
+    }
+}
+
 static int qsv_init_child_ctx(AVHWFramesContext *ctx)
 {
     AVQSVFramesContext     *hwctx = ctx->hwctx;
@@ -562,9 +694,28 @@  static int qsv_init_pool(AVHWFramesContext *ctx, uint32_t fourcc)
 
     int i, ret = 0;
 
-    if (ctx->initial_pool_size <= 0) {
-        av_log(ctx, AV_LOG_ERROR, "QSV requires a fixed frame pool size\n");
+    if (ctx->initial_pool_size < 0) {
+        av_log(ctx, AV_LOG_ERROR, "Invalid frame pool size\n");
         return AVERROR(EINVAL);
+    } else if (ctx->initial_pool_size == 0) {
+        mfxFrameSurface1 mfx_surf1;
+
+        ret = qsv_init_child_ctx(ctx);
+        if (ret < 0)
+            return ret;
+
+        ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(mfxFrameSurface1),
+                                                            ctx, qsv_pool_alloc, NULL);
+        if (!ctx->internal->pool_internal)
+            return AVERROR(ENOMEM);
+
+        memset(&mfx_surf1, 0, sizeof(mfx_surf1));
+        qsv_init_surface(ctx, &mfx_surf1);
+        s->frame_info = mfx_surf1.Info;
+        frames_hwctx->info = &s->frame_info;
+        frames_hwctx->nb_surfaces = 0;
+
+        return 0;
     }
 
     s->handle_pairs_internal = av_calloc(ctx->initial_pool_size,