Ejemplo n.º 1
0
static void dump_decoder_info(struct lavc_ctx *s,
                              GUID *device_guids, UINT n_guids)
{
    struct priv *p = s->hwdec_priv;
    MP_VERBOSE(p, "%u decoder devices:\n", (unsigned)n_guids);
    for (UINT i = 0; i < n_guids; i++) {
        GUID *guid = &device_guids[i];
        char *description = d3d_decoder_guid_to_desc(guid);

        D3DFORMAT *formats = NULL;
        UINT     n_formats = 0;
        HRESULT hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(
            p->decoder_service, guid, &n_formats, &formats);
        if (FAILED(hr)) {
            MP_ERR(p, "Failed to get render targets for decoder %s:%s\n",
                   description, mp_HRESULT_to_str(hr));
        }

        char fmts[256] = {0};
        for (UINT j = 0; j < n_formats; j++) {
            mp_snprintf_cat(fmts, sizeof(fmts),
                            " %s", mp_tag_str(formats[j]));
        }
        CoTaskMemFree(formats);

        MP_VERBOSE(p, "%s %s\n", description, fmts);
    }
}
Ejemplo n.º 2
0
Archivo: dxva2.c Proyecto: 2ion/mpv
static DWORD get_dxfmt_cb(struct lavc_ctx *s, const GUID *guid, int depth)
{
    DWORD ret = 0;
    struct priv *p = s->hwdec_priv;
    D3DFORMAT *formats = NULL;
    UINT     n_formats = 0;
    HRESULT hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(
        p->decoder_service, guid, &n_formats, &formats);
    if (FAILED(hr)) {
        MP_ERR(p, "Callback failed to get render targets for decoder %s: %s",
               d3d_decoder_guid_to_desc(guid), mp_HRESULT_to_str(hr));
        return 0;
    }

    for (int i = 0; i < MP_ARRAY_SIZE(d3d9_formats); i++) {
        const struct d3d9_format *d3d9_fmt = &d3d9_formats[i];
        if (d3d9_fmt->depth < depth)
            continue;

        for (UINT j = 0; j < n_formats; j++) {
            if (formats[i] == d3d9_fmt->format) {
                ret = formats[i];
                MP_VERBOSE(p, "Selecting %s %s\n",
                           d3d_decoder_guid_to_desc(guid),
                           mp_tag_str(ret));
                goto done;
            }
        }
    }
done:
    CoTaskMemFree(formats);
    return ret;
}
static void test_decoder(IDirectXVideoDecoderService *service, REFGUID const guid, UINT width, UINT height,
                         UINT surface_count)
{
    HRESULT hr;
    D3DFORMAT *formats;
    D3DFORMAT test_format;
    UINT count;

    if (0) /* crashes on windows */
    {
        hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(service, guid, NULL, NULL);
        ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %x\n", hr);

        hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(service, guid, &count, NULL);
        ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %x\n", hr);

        hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(service, guid, NULL, &formats);
        ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %x\n", hr);
    }

    hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(service, &GUID_NULL, &count, &formats);
    ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %x\n", hr);

    hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(service, guid, &count, &formats);
    ok(!hr, "Failed to get formats for codec %s\n", convert_decoderguid_to_str(guid));
    if (hr) return;

    if (!count)
    {
        skip("Decoder for %s does not support a single output format? Skipping test\n",
             convert_decoderguid_to_str(guid));
        return;
    }

    test_format = formats[0];
    CoTaskMemFree(formats);

    test_decoder_resolution(service, guid, test_format, width, height, surface_count);
}
Ejemplo n.º 4
0
Archivo: dxva2.c Proyecto: tguillem/vlc
static int DxSetupOutput(vlc_va_t *va, const GUID *input, const video_format_t *fmt)
{
    VLC_UNUSED(fmt);
    int err = VLC_EGENERIC;
    UINT      output_count = 0;
    D3DFORMAT *output_list = NULL;
    if (FAILED(IDirectXVideoDecoderService_GetDecoderRenderTargets(va->sys->dx_sys.d3ddec,
                                                                   input,
                                                                   &output_count,
                                                                   &output_list))) {
        msg_Err(va, "IDirectXVideoDecoderService_GetDecoderRenderTargets failed");
        return VLC_EGENERIC;
    }

    for (unsigned j = 0; j < output_count; j++) {
        const D3DFORMAT f = output_list[j];
        const d3d_format_t *format = D3dFindFormat(f);
        if (format) {
            msg_Dbg(va, "%s is supported for output", format->name);
        } else {
            msg_Dbg(va, "%d is supported for output (%4.4s)", f, (const char*)&f);
        }
    }

    /* */
    for (unsigned pass = 0; pass < 2 && err != VLC_SUCCESS; ++pass)
    {
        for (unsigned j = 0; d3d_formats[j].name; j++) {
            const d3d_format_t *format = &d3d_formats[j];

            /* */
            bool is_supported = false;
            for (unsigned k = 0; !is_supported && k < output_count; k++) {
                is_supported = format->format == output_list[k];
            }
            if (!is_supported)
                continue;
            if (pass == 0 && format->format != va->sys->render)
                continue;

            /* We have our solution */
            msg_Dbg(va, "Using decoder output '%s'", format->name);
            va->sys->render = format->format;
            err = VLC_SUCCESS;
            break;
        }
    }
    CoTaskMemFree(output_list);
    return err;
}
Ejemplo n.º 5
0
bool DXVA2Decoder::TestTarget(const GUID &guid)
{
    if (!m_service)
        return false;
    uint       output_count = 0;
    D3DFORMAT *output_list  = nullptr;
    IDirectXVideoDecoderService_GetDecoderRenderTargets(
        m_service, guid, &output_count, &output_list);
    for(uint i = 0; i < output_count; i++)
    {
        if(output_list[i] == MAKEFOURCC('Y','V','1','2') ||
           output_list[i] == MAKEFOURCC('N','V','1','2'))
        {
            m_input         = guid;
            m_format.Format = output_list[i];
            return true;
        }
    }
    return false;
}
Ejemplo n.º 6
0
static bool dxva2_format_supported(struct lavc_ctx *s, const GUID *guid,
                                   const struct d3d_decoded_format *format)
{
    bool ret = false;
    struct priv *p = s->hwdec_priv;
    D3DFORMAT *formats = NULL;
    UINT     n_formats = 0;
    HRESULT hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(
        p->decoder_service, guid, &n_formats, &formats);
    if (FAILED(hr)) {
        MP_ERR(p, "Callback failed to get render targets for decoder %s: %s",
               d3d_decoder_guid_to_desc(guid), mp_HRESULT_to_str(hr));
        return 0;
    }

    for (int i = 0; i < n_formats; i++) {
        ret = formats[i] == format->dxfmt;
        if (ret)
            break;
    }

    CoTaskMemFree(formats);
    return ret;
}
Ejemplo n.º 7
0
/**
 * Find the best suited decoder mode GUID and render format.
 */
static int DxFindVideoServiceConversion(vlc_va_dxva2_t *va, GUID *input, D3DFORMAT *output)
{
    /* Retreive supported modes from the decoder service */
    UINT input_count = 0;
    GUID *input_list = NULL;
    if (FAILED(IDirectXVideoDecoderService_GetDecoderDeviceGuids(va->vs,
                                                                 &input_count,
                                                                 &input_list))) {
        msg_Err(va->log, "IDirectXVideoDecoderService_GetDecoderDeviceGuids failed");
        return VLC_EGENERIC;
    }
    for (unsigned i = 0; i < input_count; i++) {
        const GUID *g = &input_list[i];
        const dxva2_mode_t *mode = Dxva2FindMode(g);
        if (mode) {
            msg_Dbg(va->log, "- '%s' is supported by hardware", mode->name);
        } else {
            msg_Warn(va->log, "- Unknown GUID = %08X-%04x-%04x-XXXX",
                     (unsigned)g->Data1, g->Data2, g->Data3);
        }
    }

    /* Try all supported mode by our priority */
    for (unsigned i = 0; dxva2_modes[i].name; i++) {
        const dxva2_mode_t *mode = &dxva2_modes[i];
        if (!mode->codec || mode->codec != va->codec_id)
            continue;

        /* */
        bool is_suported = false;
        for (const GUID *g = &input_list[0]; !is_suported && g < &input_list[input_count]; g++) {
            is_suported = IsEqualGUID(mode->guid, g);
        }
        if (!is_suported)
            continue;

        /* */
        msg_Dbg(va->log, "Trying to use '%s' as input", mode->name);
        UINT      output_count = 0;
        D3DFORMAT *output_list = NULL;
        if (FAILED(IDirectXVideoDecoderService_GetDecoderRenderTargets(va->vs, mode->guid,
                                                                       &output_count,
                                                                       &output_list))) {
            msg_Err(va->log, "IDirectXVideoDecoderService_GetDecoderRenderTargets failed");
            continue;
        }
        for (unsigned j = 0; j < output_count; j++) {
            const D3DFORMAT f = output_list[j];
            const d3d_format_t *format = D3dFindFormat(f);
            if (format) {
                msg_Dbg(va->log, "%s is supported for output", format->name);
            } else {
                msg_Dbg(va->log, "%d is supported for output (%4.4s)", f, (const char*)&f);
            }
        }

        /* */
        for (unsigned j = 0; d3d_formats[j].name; j++) {
            const d3d_format_t *format = &d3d_formats[j];

            /* */
            bool is_suported = false;
            for (unsigned k = 0; !is_suported && k < output_count; k++) {
                is_suported = format->format == output_list[k];
            }
            if (!is_suported)
                continue;

            /* We have our solution */
            msg_Dbg(va->log, "Using '%s' to decode to '%s'", mode->name, format->name);
            *input  = *mode->guid;
            *output = format->format;
            CoTaskMemFree(output_list);
            CoTaskMemFree(input_list);
            return VLC_SUCCESS;
        }
        CoTaskMemFree(output_list);
    }
    CoTaskMemFree(input_list);
    return VLC_EGENERIC;
}
Ejemplo n.º 8
0
static int dxva2_create_decoder(AVCodecContext *s)
{
    HwAccelContext  *hac = s->opaque;
    DXVA2Context *ctx = hac->hwaccel_ctx;
    struct dxva_context *dxva_ctx = s->hwaccel_context;
    GUID *guid_list = NULL;
    unsigned guid_count = 0, i, j;
    GUID device_guid = GUID_NULL;
    D3DFORMAT target_format = 0;
    DXVA2_VideoDesc desc = { 0 };
    DXVA2_ConfigPictureDecode config;
    HRESULT hr;
    int surface_alignment;
    int ret;

    hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
    if (FAILED(hr)) {
        av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n");
        goto fail;
    }

    for (i = 0; dxva2_modes[i].guid; i++) {
        D3DFORMAT *target_list = NULL;
        unsigned target_count = 0;
        const dxva2_mode *mode = &dxva2_modes[i];
        if (mode->codec != s->codec_id)
            continue;

        for (j = 0; j < guid_count; j++) {
            if (IsEqualGUID(mode->guid, &guid_list[j]))
                break;
        }
        if (j == guid_count)
            continue;

        hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list);
        if (FAILED(hr)) {
            continue;
        }
        for (j = 0; j < target_count; j++) {
            const D3DFORMAT format = target_list[j];
            if (format == MKTAG('N','V','1','2')) {
                target_format = format;
                break;
            }
        }
        CoTaskMemFree(target_list);
        if (target_format) {
            device_guid = *mode->guid;
            break;
        }
    }
    CoTaskMemFree(guid_list);

    if (IsEqualGUID(&device_guid, &GUID_NULL)) {
        av_log(NULL, loglevel, "No decoder device for codec found\n");
        goto fail;
    }

    desc.SampleWidth  = s->coded_width;
    desc.SampleHeight = s->coded_height;
    desc.Format       = target_format;

    ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config);
    if (ret < 0) {
        goto fail;
    }

    /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
       but it causes issues for H.264 on certain AMD GPUs..... */
    if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO)
        surface_alignment = 32;
    /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
       all coding features have enough room to work with */
    else if  (s->codec_id == AV_CODEC_ID_HEVC)
        surface_alignment = 128;
    else
        surface_alignment = 16;

    /* 4 base work surfaces */
    ctx->num_surfaces = 4;

    /* add surfaces based on number of possible refs */
    if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC)
        ctx->num_surfaces += 16;
    else
        ctx->num_surfaces += 2;

    /* add extra surfaces for frame threading */
    if (s->active_thread_type & FF_THREAD_FRAME)
        ctx->num_surfaces += s->thread_count;

    ctx->surfaces      = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));
    ctx->surface_infos = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos));

    if (!ctx->surfaces || !ctx->surface_infos) {
        av_log(NULL, loglevel, "Unable to allocate surface arrays\n");
        goto fail;
    }

    hr = IDirectXVideoDecoderService_CreateSurface(ctx->decoder_service,
                                                   FFALIGN(s->coded_width, surface_alignment),
                                                   FFALIGN(s->coded_height, surface_alignment),
                                                   ctx->num_surfaces - 1,
                                                   target_format, D3DPOOL_DEFAULT, 0,
                                                   DXVA2_VideoDecoderRenderTarget,
                                                   ctx->surfaces, NULL);
    if (FAILED(hr)) {
        av_log(NULL, loglevel, "Failed to create %d video surfaces\n", ctx->num_surfaces);
        goto fail;
    }

    hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid,
                                                        &desc, &config, ctx->surfaces,
                                                        ctx->num_surfaces, &ctx->decoder);
    if (FAILED(hr)) {
        av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n");
        goto fail;
    }

    ctx->decoder_guid   = device_guid;
    ctx->decoder_config = config;

    dxva_ctx->cfg           = &ctx->decoder_config;
    dxva_ctx->decoder       = ctx->decoder;
    dxva_ctx->surface       = ctx->surfaces;
    dxva_ctx->surface_count = ctx->num_surfaces;

    if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E))
        dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;

    return 0;
fail:
    dxva2_destroy_decoder(s);
    return AVERROR(EINVAL);
}
Ejemplo n.º 9
0
static int dxva2_create_decoder(struct lavc_ctx *s, int w, int h,
                                enum AVCodecID codec_id, int profile)
{
    DXVA2Context *ctx = s->hwdec_priv;
    struct dxva_context *dxva_ctx = s->avctx->hwaccel_context;
    GUID *guid_list = NULL;
    unsigned guid_count = 0, i, j;
    GUID device_guid = GUID_NULL;
    D3DFORMAT target_format = 0;
    DXVA2_VideoDesc desc = { 0 };
    DXVA2_ConfigPictureDecode config;
    HRESULT hr;
    int surface_alignment;
    int ret;

    hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
    if (FAILED(hr)) {
        MP_ERR(ctx, "Failed to retrieve decoder device GUIDs\n");
        goto fail;
    }

    // dump all decoder info
    MP_VERBOSE(ctx, "%d decoder devices:\n", (int)guid_count);
    for (j = 0; j < guid_count; j++) {
        GUID *guid = &guid_list[j];

        const char *name = "<unknown>";
        for (i = 0; dxva2_modes[i].guid; i++) {
            if (IsEqualGUID(dxva2_modes[i].guid, guid))
                name = dxva2_modes[i].name;
        }

        D3DFORMAT *target_list = NULL;
        unsigned target_count = 0;
        hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, guid, &target_count, &target_list);
        if (FAILED(hr))
            continue;
        char fmts[256] = {0};
        for (i = 0; i < target_count; i++)
            mp_snprintf_cat(fmts, sizeof(fmts), " %s", mp_tag_str(target_list[i]));
        CoTaskMemFree(target_list);
        MP_VERBOSE(ctx, "%s %s %s\n", mp_GUID_to_str(guid), name, fmts);
    }

    // find a suitable decoder
    for (i = 0; dxva2_modes[i].guid; i++) {
        D3DFORMAT *target_list = NULL;
        unsigned target_count = 0;
        const dxva2_mode *mode = &dxva2_modes[i];
        if (mode->codec != codec_id)
            continue;

        for (j = 0; j < guid_count; j++) {
            if (IsEqualGUID(mode->guid, &guid_list[j]))
                break;
        }
        if (j == guid_count)
            continue;

        hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list);
        if (FAILED(hr)) {
            continue;
        }
        for (j = 0; j < target_count; j++) {
            const D3DFORMAT format = target_list[j];
            if (format == MKTAG('N','V','1','2')) {
                target_format = format;
                break;
            }
        }
        CoTaskMemFree(target_list);
        if (target_format) {
            device_guid = *mode->guid;
            break;
        }
    }
    CoTaskMemFree(guid_list);

    if (IsEqualGUID(&device_guid, &GUID_NULL)) {
        MP_ERR(ctx, "No decoder device for codec found\n");
        goto fail;
    }

    desc.SampleWidth  = w;
    desc.SampleHeight = h;
    desc.Format       = target_format;

    ret = dxva2_get_decoder_configuration(s, codec_id, &device_guid, &desc, &config);
    if (ret < 0) {
        goto fail;
    }

    /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
       but it causes issues for H.264 on certain AMD GPUs..... */
    if (codec_id == AV_CODEC_ID_MPEG2VIDEO)
        surface_alignment = 32;
    /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
       all coding features have enough room to work with */
    else if  (codec_id == AV_CODEC_ID_HEVC)
        surface_alignment = 128;
    else
        surface_alignment = 16;

    /* 4 base work surfaces */
    ctx->num_surfaces = 4 + ADDTIONAL_SURFACES;

    /* add surfaces based on number of possible refs */
    if (codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_HEVC)
        ctx->num_surfaces += 16;
    else
        ctx->num_surfaces += 2;

    ctx->surfaces      = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));
    ctx->surface_infos = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos));

    if (!ctx->surfaces || !ctx->surface_infos) {
        MP_ERR(ctx, "Unable to allocate surface arrays\n");
        goto fail;
    }

    hr = IDirectXVideoDecoderService_CreateSurface(ctx->decoder_service,
                                                   FFALIGN(w, surface_alignment),
                                                   FFALIGN(h, surface_alignment),
                                                   ctx->num_surfaces - 1,
                                                   target_format, D3DPOOL_DEFAULT, 0,
                                                   DXVA2_VideoDecoderRenderTarget,
                                                   ctx->surfaces, NULL);
    if (FAILED(hr)) {
        MP_ERR(ctx, "Failed to create %d video surfaces\n", ctx->num_surfaces);
        goto fail;
    }

    hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid,
                                                        &desc, &config, ctx->surfaces,
                                                        ctx->num_surfaces, &ctx->decoder);
    if (FAILED(hr)) {
        MP_ERR(ctx, "Failed to create DXVA2 video decoder\n");
        goto fail;
    }

    ctx->decoder_guid   = device_guid;
    ctx->decoder_config = config;

    dxva_ctx->cfg           = &ctx->decoder_config;
    dxva_ctx->decoder       = ctx->decoder;
    dxva_ctx->surface       = ctx->surfaces;
    dxva_ctx->surface_count = ctx->num_surfaces;

    if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E))
        dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;

    return 0;
fail:
    dxva2_destroy_decoder(s);
    return -1;
}
Ejemplo n.º 10
0
/**
 * Find the best suited decoder mode GUID and render format.
 */
static int hb_dx_find_video_service_conversion( hb_va_dxva2_t *dxva2, GUID *input, D3DFORMAT *output )
{
    unsigned int input_count = 0;
    GUID *input_list = NULL;
    if( FAILED( IDirectXVideoDecoderService_GetDecoderDeviceGuids( dxva2->vs, &input_count, &input_list )))
    {
        hb_log( "dxva2:IDirectXVideoDecoderService_GetDecoderDeviceGuids failed" );
        return HB_WORK_ERROR;
    }
    unsigned i, j;
    for( i = 0; i < input_count; i++ )
    {
        const GUID *g = &input_list[i];
        const hb_dx_mode_t *mode = hb_dx_find_mode( g );
     }

    for( i = 0; dxva2_modes[i].name; i++ )
    {
        const hb_dx_mode_t *mode = &dxva2_modes[i];
        if( !mode->codec || mode->codec != dxva2->codec_id )
            continue;

        int is_suported = 0;
        const GUID *g;
        for( g = &input_list[0]; !is_suported && g < &input_list[input_count]; g++ )
        {
            is_suported = IsEqualGUID( mode->guid, g );
        }
        if( !is_suported )
            continue;

        unsigned int output_count = 0;
        D3DFORMAT *output_list = NULL;
        if( FAILED( IDirectXVideoDecoderService_GetDecoderRenderTargets( dxva2->vs, mode->guid, &output_count, &output_list )))
        {
            hb_log( "dxva2:IDirectXVideoDecoderService_GetDecoderRenderTargets failed" );
            continue;
        }
        for( j = 0; j < output_count; j++ )
        {
            const D3DFORMAT f = output_list[j];
            const hb_d3d_format_t *format = hb_d3d_find_format( f );
            if( format )
            {
                //hb_log( "dxva2:%s is supported for output", format->name );
            }
            else
            {
                hb_log( "dxvar2:%d is supported for output (%4.4s)", f, (const char*)&f );
            }
        }

        for( j = 0; d3d_formats[j].name; j++ )
        {
            const hb_d3d_format_t *format = &d3d_formats[j];
            int is_suported = 0;
            unsigned k;
            for( k = 0; !is_suported && k < output_count; k++ )
            {
                is_suported = format->format == output_list[k];
            }
            if( !is_suported )
                continue;
            *input  = *mode->guid;
            *output = format->format;
            return HB_WORK_OK;
        }
    }
    return HB_WORK_ERROR;
}
Ejemplo n.º 11
0
static int dxva2_create_decoder(AVCodecContext *s)
{
    InputStream  *ist = s->opaque;
    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
    DXVA2Context *ctx = ist->hwaccel_ctx;
    struct dxva_context *dxva_ctx = s->hwaccel_context;
    GUID *guid_list = NULL;
    unsigned guid_count = 0, i, j;
    GUID device_guid = GUID_NULL;
    const D3DFORMAT surface_format = s->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ?
                                     MKTAG('P', '0', '1', '0') : MKTAG('N', 'V', '1', '2');
    D3DFORMAT target_format = 0;
    DXVA2_VideoDesc desc = { 0 };
    DXVA2_ConfigPictureDecode config;
    HRESULT hr;
    int surface_alignment, num_surfaces;
    int ret;

    AVDXVA2FramesContext *frames_hwctx;
    AVHWFramesContext *frames_ctx;

    hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
    if (FAILED(hr)) {
        av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n");
        goto fail;
    }

    for (i = 0; dxva2_modes[i].guid; i++) {
        D3DFORMAT *target_list = NULL;
        unsigned target_count = 0;
        const dxva2_mode *mode = &dxva2_modes[i];
        if (mode->codec != s->codec_id)
            continue;

        for (j = 0; j < guid_count; j++) {
            if (IsEqualGUID(mode->guid, &guid_list[j]))
                break;
        }
        if (j == guid_count)
            continue;

        hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list);
        if (FAILED(hr)) {
            continue;
        }
        for (j = 0; j < target_count; j++) {
            const D3DFORMAT format = target_list[j];
            if (format == surface_format) {
                target_format = format;
                break;
            }
        }
        CoTaskMemFree(target_list);
        if (target_format) {
            device_guid = *mode->guid;
            break;
        }
    }
    CoTaskMemFree(guid_list);

    if (IsEqualGUID(&device_guid, &GUID_NULL)) {
        av_log(NULL, loglevel, "No decoder device for codec found\n");
        goto fail;
    }

    desc.SampleWidth  = s->coded_width;
    desc.SampleHeight = s->coded_height;
    desc.Format       = target_format;

    ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config);
    if (ret < 0) {
        goto fail;
    }

    /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
       but it causes issues for H.264 on certain AMD GPUs..... */
    if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO)
        surface_alignment = 32;
    /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
       all coding features have enough room to work with */
    else if  (s->codec_id == AV_CODEC_ID_HEVC)
        surface_alignment = 128;
    else
        surface_alignment = 16;

    /* 4 base work surfaces */
    num_surfaces = 4;

    /* add surfaces based on number of possible refs */
    if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC)
        num_surfaces += 16;
    else
        num_surfaces += 2;

    /* add extra surfaces for frame threading */
    if (s->active_thread_type & FF_THREAD_FRAME)
        num_surfaces += s->thread_count;

    ctx->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->hw_device_ctx);
    if (!ctx->hw_frames_ctx)
        goto fail;
    frames_ctx   = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
    frames_hwctx = frames_ctx->hwctx;

    frames_ctx->format            = AV_PIX_FMT_DXVA2_VLD;
    frames_ctx->sw_format         = s->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ?
                                    AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
    frames_ctx->width             = FFALIGN(s->coded_width, surface_alignment);
    frames_ctx->height            = FFALIGN(s->coded_height, surface_alignment);
    frames_ctx->initial_pool_size = num_surfaces;

    frames_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget;

    ret = av_hwframe_ctx_init(ctx->hw_frames_ctx);
    if (ret < 0) {
        av_log(NULL, loglevel, "Failed to initialize the HW frames context\n");
        goto fail;
    }

    hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid,
                                                        &desc, &config, frames_hwctx->surfaces,
                                                        frames_hwctx->nb_surfaces, &frames_hwctx->decoder_to_release);
    if (FAILED(hr)) {
        av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n");
        goto fail;
    }

    ctx->decoder_guid   = device_guid;
    ctx->decoder_config = config;

    dxva_ctx->cfg           = &ctx->decoder_config;
    dxva_ctx->decoder       = frames_hwctx->decoder_to_release;
    dxva_ctx->surface       = frames_hwctx->surfaces;
    dxva_ctx->surface_count = frames_hwctx->nb_surfaces;

    if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E))
        dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;

    return 0;
fail:
    av_buffer_unref(&ctx->hw_frames_ctx);
    return AVERROR(EINVAL);
}