[vlc-devel] [PATCH 13/13] WIP qsv: add support for encoding from D3D11 source textures

Steve Lhomme robux4 at ycbcr.xyz
Mon Dec 23 16:49:37 CET 2019


---
 modules/codec/Makefile.am |   1 +
 modules/codec/qsv.c       | 377 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 362 insertions(+), 16 deletions(-)

diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 06d6095ac45..4eecde778aa 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -582,6 +582,7 @@ libqsv_plugin_la_SOURCES = codec/qsv.c codec/vlc_fifo_helper.h demux/mpeg/timest
 libqsv_plugin_la_CFLAGS = $(AM_CFLAGS) $(MFX_CFLAGS)
 libqsv_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
 libqsv_plugin_la_LIBADD = $(MFX_LIBS)
+libqsv_plugin_la_LIBADD += libd3d11_common.la $(LIBCOM) -luuid
 EXTRA_LTLIBRARIES += libqsv_plugin.la
 codec_LTLIBRARIES += $(LTLIBqsv)
 
diff --git a/modules/codec/qsv.c b/modules/codec/qsv.c
index b9e69bb3220..ea80197fb64 100644
--- a/modules/codec/qsv.c
+++ b/modules/codec/qsv.c
@@ -38,6 +38,13 @@
 #include <mfx/mfxvideo.h>
 #include "../demux/mpeg/timestamps.h"
 
+#if HAVE_AVCODEC_D3D11VA
+#define COBJMACROS
+#include <initguid.h>
+#include <d3d11.h>
+#include "../video_chroma/d3d11_fmt.h"
+#endif
+
 #define SOUT_CFG_PREFIX     "sout-qsv-"
 
 #define QSV_HAVE_CO2 (MFX_VERSION_MAJOR > 1 || (MFX_VERSION_MAJOR == 1 && MFX_VERSION_MINOR >= 6))
@@ -271,6 +278,7 @@ typedef struct _QSVFrame
     mfxFrameSurface1  surface;
     mfxEncodeCtrl     enc_ctrl;
     int               used;
+    int               Type;
 } QSVFrame;
 
 typedef struct async_task_t
@@ -288,6 +296,10 @@ typedef struct
     mfxSession       session;             // Intel Media SDK Session.
     mfxVideoParam    params;              // Encoding parameters.
     QSVFrame         *work_frames;        // IntelMediaSDK's frame pool.
+#if HAVE_AVCODEC_D3D11VA
+    size_t           numAllocated;
+    QSVFrame         *allocatedFrames[16];
+#endif
     uint64_t         dts_warn_counter;    // DTS warning counter for rate-limiting of msg;
     uint64_t         busy_warn_counter;   // Device Busy warning counter for rate-limiting of msg;
     uint64_t         async_depth;         // Number of parallel encoding operations.
@@ -297,6 +309,13 @@ typedef struct
 
     picture_pool_t   *input_pool;         // pool of pictures to feed the decoder
                                           //  as it doesn't like constantly changing buffers
+
+    mfxFrameAllocator frame_allocator;
+    vlc_decoder_device *dec_device;
+#if HAVE_AVCODEC_D3D11VA
+    /* Direct3D11 */
+    ID3D11Texture2D     *copy_pool[64]; /* shadow pool because it needs textures with only one slice */
+#endif
 } encoder_sys_t;
 
 static block_t *Encode(encoder_t *, picture_t *);
@@ -371,6 +390,243 @@ static uint64_t qsv_params_get_value(const char *const *text,
     return list[result];
 }
 
+static const d3d_format_t *GetTexture(DXGI_FORMAT format, vlc_fourcc_t fcc)
+{
+    for (const d3d_format_t *output_format = GetRenderFormatList();
+         output_format->name != NULL; ++output_format)
+    {
+        if ( output_format->formatTexture == format &&
+             (!fcc || fcc == output_format->fourcc) )
+        {
+            return output_format;
+        }
+    }
+    return NULL;
+}
+
+static inline mfxMemId qsvfMemId(QSVFrame *qf)
+{
+    return (mfxMemId)qf;
+}
+
+static inline QSVFrame *memIdQsv(mfxMemId mId)
+{
+    return (QSVFrame*)mId;
+}
+
+static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *request, mfxFrameAllocResponse *response)
+{
+    if (request->Type & MFX_MEMTYPE_SYSTEM_MEMORY)
+        return MFX_ERR_MEMORY_ALLOC;
+
+    encoder_t *enc = pthis;
+    encoder_sys_t *p_sys = enc->p_sys;
+    mfxMemId *mids = calloc(request->NumFrameSuggested, sizeof(mfxMemId));
+    if (unlikely(mids == NULL))
+        return MFX_ERR_MEMORY_ALLOC;
+
+    d3d11_decoder_device_t *d3d11_dev = GetD3D11OpaqueDevice(p_sys->dec_device);
+    d3d11_device_t d3d_dev;
+
+    D3D11_CreateDeviceExternal(VLC_OBJECT(enc), d3d11_dev->device, false, &d3d_dev);
+
+    for (size_t i=0; i < request->NumFrameSuggested &&
+                     (i + request->NumFrameSuggested) < ARRAYSIZE(p_sys->allocatedFrames); i++)
+    {
+        QSVFrame *qf = calloc(1,sizeof(QSVFrame));
+
+        video_format_t surface_fmt   = enc->fmt_in.video;
+        surface_fmt.i_chroma         = VLC_CODEC_D3D11_OPAQUE;
+        surface_fmt.i_bits_per_pixel = 12;
+        surface_fmt.i_width          = request->Info.Width;
+        surface_fmt.i_height         = request->Info.Height;
+
+        if (request->Info.FourCC == MFX_FOURCC_NV12)
+            qf->pic = D3D11_AllocPicture(VLC_OBJECT(enc), &d3d_dev, &surface_fmt, NULL/*TODO*/, GetTexture(DXGI_FORMAT_NV12, VLC_CODEC_NV12));
+        else if (request->Info.FourCC == MFX_FOURCC_P8)
+        {
+            D3D11_BUFFER_DESC desc = { 0 };
+
+            desc.ByteWidth           = request->Info.Width * request->Info.Height;
+            desc.Usage               = D3D11_USAGE_STAGING;
+            desc.BindFlags           = 0;
+            desc.CPUAccessFlags      = D3D11_CPU_ACCESS_READ;
+            desc.MiscFlags           = 0;
+            desc.StructureByteStride = 0;
+
+            ID3D11Buffer *buffer = NULL;
+            HRESULT hr = ID3D11Device_CreateBuffer(d3d_dev.d3ddevice, &desc, 0, &buffer);
+            if (FAILED(hr))
+            {
+                for (;;)
+                {
+                    qf = p_sys->allocatedFrames[--i + p_sys->numAllocated];
+                    ID3D11Buffer *buffer = qf->surface.Data.MemId;
+                    ID3D11Buffer_Release(buffer);
+                    if (i == 0)
+                    {
+                        free(mids);
+                        D3D11_ReleaseDevice(&d3d_dev);
+                        return MFX_ERR_NOT_ENOUGH_BUFFER;
+                    }
+                }
+            }
+            qf->surface.Data.MemId = buffer;
+        }
+        else
+            assert(0); /* not supported yet */
+
+        qf->Type = request->Type;
+        p_sys->allocatedFrames[i + p_sys->numAllocated] = qf;
+        mids[i] = qsvfMemId(qf);
+    }
+    D3D11_ReleaseDevice(&d3d_dev);
+    response->mids = mids;
+    response->NumFrameActual = request->NumFrameSuggested;
+    p_sys->numAllocated += request->NumFrameSuggested;
+    return MFX_ERR_NONE;
+}
+
+static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *response)
+{
+    encoder_t *enc = pthis;
+    encoder_sys_t *p_sys = enc->p_sys;
+    mfxMemId *mids = response->mids;
+    QSVFrame *qf = memIdQsv(mids[0]);
+    for (size_t i = 0; i < p_sys->numAllocated; i++)
+    {
+        qf = p_sys->allocatedFrames[i];
+        if (qf == memIdQsv(mids[0]))
+        {
+            for (size_t j=0; j<response->NumFrameActual; j++)
+            {
+                qf = p_sys->allocatedFrames[i + j];
+                if (qf->pic)
+                    picture_Release(qf->pic);
+                else if (qf->surface.Data.MemId)
+                {
+                    ID3D11Buffer *buffer = qf->surface.Data.MemId;
+                    ID3D11Buffer_Release(buffer);
+                }
+                free(qf);
+                p_sys->allocatedFrames[i + j] = NULL;
+            }
+            break;
+        }
+    }
+    free(mids);
+    return MFX_ERR_NONE;
+}
+
+static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
+{
+    encoder_t *enc = pthis;
+    encoder_sys_t *p_sys = enc->p_sys;
+    d3d11_decoder_device_t *d3d11_dev = GetD3D11OpaqueDevice(p_sys->dec_device);
+    QSVFrame *qf = memIdQsv(mid);
+    D3D11_MAPPED_SUBRESOURCE mappedResource;
+    HRESULT hr;
+    hr = ID3D11DeviceContext_Map(d3d11_dev->device, qf->surface.Data.MemId, 0, D3D11_MAP_READ, D3D11_MAP_FLAG_DO_NOT_WAIT, &mappedResource);
+    if (FAILED(hr))
+        return MFX_ERR_LOCK_MEMORY;
+    if (likely(!qf->pic))
+    {
+        /* P8 buffer */
+        ptr->Pitch = (mfxU16)mappedResource.RowPitch;
+        ptr->Y     = (mfxU8*)mappedResource.pData;
+        ptr->U     = 0;
+        ptr->V     = 0;
+    }
+    return MFX_ERR_NONE;
+}
+
+static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
+{
+    VLC_UNUSED(ptr);
+    encoder_t *enc = pthis;
+    encoder_sys_t *p_sys = enc->p_sys;
+    d3d11_decoder_device_t *d3d11_dev = GetD3D11OpaqueDevice(p_sys->dec_device);
+    QSVFrame *qf = memIdQsv(mid);
+    ID3D11DeviceContext_Unmap(d3d11_dev->device, qf->surface.Data.MemId, 0);
+    return MFX_ERR_NONE;
+}
+
+static int assert_D3D11ShadowPool( encoder_t *enc, unsigned pool_size )
+{
+    encoder_sys_t *sys = enc->p_sys;
+
+    if (sys->copy_pool[0])
+        return VLC_SUCCESS;
+
+    pool_size += 10 + vlc_GetCPUCount(); /* we need more pictures since we keep some active longer
+                                          * see clear_unused_frames() */
+
+    video_format_t surface_fmt = enc->fmt_in.video;
+    /* worst case scenario we need 128 alignment for HEVC */
+    // surface_fmt.i_width  = (surface_fmt.i_width  + 0x7F) & ~0x7F;
+    // surface_fmt.i_height = (surface_fmt.i_height + 0x7F) & ~0x7F;
+
+    const d3d_format_t *textureFmt = GetTexture(DXGI_FORMAT_NV12, VLC_CODEC_D3D11_OPAQUE);
+    if (unlikely(textureFmt==NULL))
+        goto error;
+
+    d3d11_device_t d3d_dev;
+    d3d11_decoder_device_t *d3d11_dev = GetD3D11OpaqueDevice(sys->dec_device);
+    D3D11_CreateDeviceExternal(VLC_OBJECT(enc), d3d11_dev->device, false, &d3d_dev);
+
+    unsigned i;
+    for (i=0; i<pool_size; i++)
+        if (AllocateTextures(enc, &d3d_dev, textureFmt,
+                                &surface_fmt, 1, &sys->copy_pool[i], NULL) != VLC_SUCCESS)
+        {
+            while (i-- != 0)
+                ID3D11Texture2D_Release(sys->copy_pool[i]);
+            break;
+        }
+    for (; i<ARRAY_SIZE(sys->copy_pool); i++)
+        sys->copy_pool[i] = NULL;
+
+    return VLC_SUCCESS;
+error:
+    D3D11_ReleaseDevice(&d3d_dev);
+
+    return VLC_EGENERIC;
+}
+
+static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
+{
+    encoder_t *enc = pthis;
+    if (NULL == hdl)
+        return MFX_ERR_INVALID_HANDLE;
+    QSVFrame *qf = memIdQsv(mid);
+    mfxHDLPair *pPair  =  (mfxHDLPair*)hdl;
+    if (!qf->pic)
+        pPair->first = qf->surface.Data.MemId;
+    else
+    {
+        picture_sys_d3d11_t *p_sys = ActiveD3D11PictureSys(qf->pic);
+        if (qf->Type & MFX_MEMTYPE_INTERNAL_FRAME)
+            pPair->first = p_sys->resource[KNOWN_DXGI_INDEX];
+        else
+        {
+            encoder_sys_t *sys = enc->p_sys;
+            D3D11_TEXTURE2D_DESC texDesc;
+            ID3D11Texture2D_GetDesc(p_sys->texture[0], &texDesc);
+            assert_D3D11ShadowPool(enc, texDesc.ArraySize );
+            d3d11_decoder_device_t *d3d11_dev = GetD3D11OpaqueDevice(sys->dec_device);
+            ID3D11DeviceContext_CopySubresourceRegion(d3d11_dev->device,
+                                                      (ID3D11Resource*)sys->copy_pool[p_sys->slice_index],
+                                                      0, 0, 0, 0,
+                                                      p_sys->resource[KNOWN_DXGI_INDEX],
+                                                      p_sys->slice_index,
+                                                      NULL);
+            pPair->first = sys->copy_pool[p_sys->slice_index];
+        }
+    }
+    pPair->second = 0;
+    return MFX_ERR_NONE;
+}
+
 static int Open(vlc_object_t *this)
 {
     encoder_t *enc = (encoder_t *)this;
@@ -407,7 +663,7 @@ static int Open(vlc_object_t *this)
 #endif
     };
     mfxVersion    ver = { { 1, 1 } };
-    mfxIMPL       impl;
+    mfxIMPL       impl = MFX_IMPL_HARDWARE_ANY;
     mfxVideoParam param_out = { 0 };
 
     uint8_t *p_extra;
@@ -428,14 +684,23 @@ static int Open(vlc_object_t *this)
     if (unlikely(!sys))
         return VLC_ENOMEM;
 
+    if (enc->vctx_in)
+        sys->dec_device = vlc_video_context_HoldDevice(enc->vctx_in);
+    else
+        sys->dec_device = encoder_GetDecoderDevice(enc);
+    if ( sys->dec_device && GetD3D11OpaqueDevice(sys->dec_device) != NULL )
+        impl = MFX_IMPL_HARDWARE_ANY | MFX_IMPL_VIA_D3D11;
+
     /* Initialize dispatcher, it will loads the actual SW/HW Implementation */
-    sts = MFXInit(MFX_IMPL_AUTO_ANY, &ver, &sys->session);
+    sts = MFXInit(impl, &ver, &sys->session);
 
     if (sts != MFX_ERR_NONE) {
         if (sts == MFX_ERR_UNSUPPORTED)
             msg_Err(enc, "Intel Media SDK implementation not supported, is your card plugged?");
         else
             msg_Err(enc, "Unable to find an Intel Media SDK implementation (%d).", sts);
+        if (sys->dec_device)
+            vlc_decoder_device_Release(sys->dec_device);
         free(sys);
         return VLC_EGENERIC;
     }
@@ -457,8 +722,35 @@ static int Open(vlc_object_t *this)
     /* Input picture format description */
     sys->params.mfx.FrameInfo.FrameRateExtN = enc->fmt_in.video.i_frame_rate;
     sys->params.mfx.FrameInfo.FrameRateExtD = enc->fmt_in.video.i_frame_rate_base;
-    sys->params.mfx.FrameInfo.FourCC        = MFX_FOURCC_NV12;
-    sys->params.mfx.FrameInfo.ChromaFormat  = MFX_CHROMAFORMAT_YUV420;
+
+    if (GetD3D11OpaqueDevice(sys->dec_device) && (impl & MFX_IMPL_VIA_D3D11))
+    {
+        d3d11_decoder_device_t *d3d11_dev = GetD3D11OpaqueDevice(sys->dec_device);
+        ID3D11Device *d3device;
+        ID3D11DeviceContext_GetDevice(d3d11_dev->device, &d3device);
+
+        ID3D10Multithread *pMultithread;
+        HRESULT hr = ID3D11Device_QueryInterface( d3device, &IID_ID3D10Multithread, (void **)&pMultithread);
+        if (SUCCEEDED(hr)) {
+            ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
+            ID3D10Multithread_Release(pMultithread);
+        }
+
+        mfxHDL handle = d3device;
+        sts = MFXVideoCORE_SetHandle(sys->session, MFX_HANDLE_D3D11_DEVICE, handle);
+        ID3D11Device_Release(d3device);
+        if (sts != MFX_ERR_NONE) {
+            msg_Err(enc, "No direct3d11 handle available.");
+            goto error;
+        }
+        sys->params.mfx.FrameInfo.FourCC        = MFX_FOURCC_NV12;
+        sys->params.mfx.FrameInfo.ChromaFormat  = MFX_CHROMAFORMAT_YUV420;
+    }
+    else
+    {
+        sys->params.mfx.FrameInfo.FourCC        = MFX_FOURCC_NV12;
+        sys->params.mfx.FrameInfo.ChromaFormat  = MFX_CHROMAFORMAT_YUV420;
+    }
     sys->params.mfx.FrameInfo.Width         = QSV_ALIGN(16, enc->fmt_in.video.i_width);
     sys->params.mfx.FrameInfo.Height        = QSV_ALIGN(32, enc->fmt_in.video.i_height);
     sys->params.mfx.FrameInfo.CropW         = enc->fmt_in.video.i_visible_width;
@@ -470,7 +762,11 @@ static int Open(vlc_object_t *this)
     sys->params.mfx.FrameInfo.BitDepthLuma   = 8; /* for VLC_CODEC_NV12 */
 
     /* Parsing options common to all RC methods and codecs */
-    sys->params.IOPattern       = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
+    sys->params.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
+    if (impl & MFX_IMPL_VIA_D3D11)
+        sys->params.IOPattern |=  MFX_IOPATTERN_IN_VIDEO_MEMORY;
+    else
+        sys->params.IOPattern |= MFX_IOPATTERN_IN_SYSTEM_MEMORY;
     sys->params.AsyncDepth      = var_InheritInteger(enc, SOUT_CFG_PREFIX "async-depth");
     sys->params.mfx.GopOptFlag  = 1; /* TODO */
     sys->params.mfx.GopPicSize  = var_InheritInteger(enc, SOUT_CFG_PREFIX "gop-size");
@@ -551,6 +847,27 @@ static int Open(vlc_object_t *this)
         goto error;
     }
 
+#if HAVE_AVCODEC_D3D11VA
+    if (impl & MFX_IMPL_VIA_D3D11)
+    {
+        mfxFrameAllocator frame_allocator = {
+            .pthis  = enc,
+            .GetHDL = qsv_frame_get_hdl,
+            .Alloc  = qsv_frame_alloc,
+            .Free   = qsv_frame_free,
+            .Lock   = qsv_frame_lock,
+            .Unlock = qsv_frame_unlock,
+        };
+        sys->frame_allocator = frame_allocator;
+
+        sts = MFXVideoCORE_SetFrameAllocator(sys->session, &sys->frame_allocator);
+        if (sts != MFX_ERR_NONE)
+        {
+            msg_Err(enc, "Failed to set D3D11 frame allocator");
+        }
+    }
+#endif
+
     /* Request number of surface needed and creating frame pool */
     if (MFXVideoENCODE_QueryIOSurf(sys->session, &sys->params, &alloc_request)!= MFX_ERR_NONE)
     {
@@ -621,8 +938,18 @@ static int Open(vlc_object_t *this)
     async_task_t_fifo_Init(&sys->packets);
 
     /* Vlc module configuration */
-    enc->fmt_in.i_codec                = VLC_CODEC_NV12; // Intel Media SDK requirement
-    enc->fmt_in.video.i_bits_per_pixel = 12;
+    if (impl & MFX_IMPL_VIA_D3D11)
+    {
+        enc->fmt_in.i_codec                = VLC_CODEC_D3D11_OPAQUE;
+        enc->fmt_in.video.i_chroma         = VLC_CODEC_D3D11_OPAQUE;
+        enc->fmt_in.video.i_bits_per_pixel = 12;
+    }
+    else
+    {
+        enc->fmt_in.i_codec                = VLC_CODEC_NV12; // Intel Media SDK requirement
+        enc->fmt_in.video.i_chroma         = VLC_CODEC_NV12;
+        enc->fmt_in.video.i_bits_per_pixel = 12;
+    }
     enc->fmt_in.video.i_width          = sys->params.mfx.FrameInfo.Width;
     enc->fmt_in.video.i_height         = sys->params.mfx.FrameInfo.Height;
 
@@ -647,11 +974,21 @@ static void Close(vlc_object_t *this)
 
     MFXVideoENCODE_Close(sys->session);
     MFXClose(sys->session);
+
+#if HAVE_AVCODEC_D3D11VA
+    for (unsigned i=0; i<ARRAY_SIZE(sys->copy_pool); i++)
+    {
+        if ( sys->copy_pool[i] )
+            ID3D11Texture2D_Release( sys->copy_pool[i] );
+    }
+#endif
     /* if (enc->fmt_out.p_extra) */
     /*     free(enc->fmt_out.p_extra); */
     async_task_t_fifo_Release(&sys->packets);
     if (sys->input_pool)
         picture_pool_Release(sys->input_pool);
+    if (sys->dec_device)
+        vlc_decoder_device_Release(sys->dec_device);
     free(sys);
 }
 
@@ -741,16 +1078,21 @@ static int submit_frame(encoder_t *enc, picture_t *pic, QSVFrame **new_frame)
         return ret;
     }
 
-    qf->pic = picture_pool_Get( sys->input_pool );
-    if (unlikely(!qf->pic))
+    if (pic->context != NULL)
+        qf->pic = picture_Hold( pic );
+    else
     {
-        msg_Warn(enc, "Unable to find an unlocked surface in the pool");
-        qf->used = 0;
-        return ret;
-    }
-    picture_Copy( qf->pic, pic );
+        qf->pic = picture_pool_Get( sys->input_pool );
+        if (unlikely(!qf->pic))
+        {
+            msg_Warn(enc, "Unable to find an unlocked surface in the pool");
+            qf->used = 0;
+            return ret;
+        }
+        picture_Copy( qf->pic, pic );
 
-    assert(qf->pic->p[0].p_pixels + (qf->pic->p[0].i_pitch * qf->pic->p[0].i_lines) == qf->pic->p[1].p_pixels);
+        assert(qf->pic->p[0].p_pixels + (qf->pic->p[0].i_pitch * qf->pic->p[0].i_lines) == qf->pic->p[1].p_pixels);
+    }
 
     qf->surface.Info = sys->params.mfx.FrameInfo;
 
@@ -764,6 +1106,7 @@ static int submit_frame(encoder_t *enc, picture_t *pic, QSVFrame **new_frame)
 
     //qf->surface.Data.Pitch = QSV_ALIGN(16, qf->surface.Info.Width);
 
+    qf->surface.Data.MemId     = qf;
     qf->surface.Data.PitchLow  = qf->pic->p[0].i_pitch;
     qf->surface.Data.Y         = qf->pic->p[0].p_pixels;
     qf->surface.Data.UV        = qf->pic->p[1].p_pixels;
@@ -781,6 +1124,7 @@ static async_task_t *encode_frame(encoder_t *enc, picture_t *pic)
     mfxStatus sts = MFX_ERR_MEMORY_ALLOC;
     QSVFrame *qsv_frame = NULL;
     mfxFrameSurface1 *surf = NULL;
+    mfxEncodeCtrl* enc_ctrl = NULL;
     async_task_t *task = calloc(1, sizeof(*task));
     if (unlikely(task == NULL))
         goto done;
@@ -815,10 +1159,11 @@ static async_task_t *encode_frame(encoder_t *enc, picture_t *pic)
 
     if (qsv_frame) {
         surf = &qsv_frame->surface;
+        enc_ctrl = &qsv_frame->enc_ctrl;
     }
 
     for (;;) {
-        sts = MFXVideoENCODE_EncodeFrameAsync(sys->session, 0, surf, &task->bs, task->syncp);
+        sts = MFXVideoENCODE_EncodeFrameAsync(sys->session, enc_ctrl, surf, &task->bs, task->syncp);
         if (sts != MFX_WRN_DEVICE_BUSY && sts != MFX_WRN_IN_EXECUTION)
             break;
         if (sys->busy_warn_counter++ % 16 == 0)
-- 
2.17.1



More information about the vlc-devel mailing list