dxva2+ffmpeg硬件解码(Windows)重要笔记2

参考了csdn上Win32Project1_ffmpeg_dxva2这个例子,很不错,直接就可以运行。

但是,有几个问题:

1、窗口无法正常缩放,缩放后,图像大小并没有一起缩放

2、H265的编码格式,显示下面有一块绿色。

3、无法从显卡获取YUV420P数据或者NV12数据

3、找了很久网上也没有相关代码实现从显卡获取数据到内存(有些方法相当慢,基本无法使用!)

4、新遇到问题(2019.11),如果编码端采用硬件(GPU)编码后,会生成1088P的图像,你没看错,是1088,不是1080P,这时候解码如果直接显示会在屏幕下边产生8个像素高的绿条。

 

第2个问题,看了特征,心想应该是对齐方式问题,修改源码:

ffmpeg_dxva2.cpp下的static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame)函数:

原函数是这样的:

static int dxva2_create_decoder(AVCodecContext *s)
{
    InputStream  *ist = (InputStream *)s->opaque;
    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;
    struct dxva_context *dxva_ctx = (dxva_context *)s->hwaccel_context;
    GUID *guid_list = NULL;
    unsigned guid_count = 0, i, j;
    GUID device_guid = GUID_NULL;
    D3DFORMAT target_format = D3DFMT_UNKNOWN;
    DXVA2_VideoDesc desc = { 0 };
    DXVA2_ConfigPictureDecode config;
    HRESULT hr;
    int surface_alignment;
    int ret;

    //hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
    hr = ctx->decoder_service->GetDecoderDeviceGuids(&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);
        hr = ctx->decoder_service->GetDecoderRenderTargets(*mode->guid, &target_count, &target_list);
        if (FAILED(hr)) {
            continue;
        }

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

        system("pause");

        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 if (s->codec_id == AV_CODEC_ID_VP9)
        ctx->num_surfaces += 8;
    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 = (LPDIRECT3DSURFACE9 *)av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));
    ctx->surface_infos = (surface_info *)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);*/
    hr = ctx->decoder_service->CreateSurface(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);*/
    hr = ctx->decoder_service->CreateVideoDecoder(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);
}

 

修改为:

static int dxva2_create_decoder(AVCodecContext *s)
{
    InputStream  *ist = (InputStream *)s->opaque;
    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;
    struct dxva_context *dxva_ctx = (dxva_context *)s->hwaccel_context;
    GUID *guid_list = NULL;
    unsigned guid_count = 0, i, j;
    GUID device_guid = GUID_NULL;
    D3DFORMAT target_format = D3DFMT_UNKNOWN;
    DXVA2_VideoDesc desc = { 0 };
    DXVA2_ConfigPictureDecode config;
    HRESULT hr;
    int surface_alignment;
    int ret;

    //hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
    hr = ctx->decoder_service->GetDecoderDeviceGuids(&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);
        hr = ctx->decoder_service->GetDecoderRenderTargets(*mode->guid, &target_count, &target_list);
        if (FAILED(hr)) {
            continue;
        }

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

        system("pause");

        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 if (s->codec_id == AV_CODEC_ID_VP9)
        ctx->num_surfaces += 8;
    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 = (LPDIRECT3DSURFACE9 *)av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));
    ctx->surface_infos = (surface_info *)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);*/
    hr = ctx->decoder_service->CreateSurface(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);*/
    hr = ctx->decoder_service->CreateVideoDecoder(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);
}

统一为16位对齐,测试下,可以了。。。

下一篇文章讲第3个问题,我的QQ35744025,windows下播放器已完成,需要合作的或者技术交流的可以加我QQ哦

(播放器支持dxva2硬解码,D3D+OPENGL显示,音频用DSOUND播放,支持快放慢放,支持输出YV12视频和PCM音频数据)

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论
FFmpeg是一种开源的多媒体处理工具,其中包含了dxva2解码功能。DXVA2是DirectX Video Acceleration 2的缩写,它是一种能够充分利用显卡硬件加速的视频解码技术。 使用FFmpeg进行dxva2解码时,可以获得以下几个优势: 1. 提高解码效率:dxva2解码能够使用显卡的硬件加速能力,从而大大提高视频解码的效率。相较于软解码,在相同的硬件条件下,dxva2解码可以更快地完成对视频的解码工作。 2. 减轻CPU负担:由于dxva2解码利用显卡进行解码,可以减轻CPU的负担,从而为其他任务提供更多的计算资源。这对于同时进行多任务处理的用户来说,尤其是一些对计算性能要求较高的场景,是非常有益的。 3. 优化视频播放体验:dxva2解码可以提供更平滑和流畅的视频播放体验。它能够更好地处理高分辨率、高比特率的视频文件,避免视频卡顿或者出现掉帧的情况。 然而,dxva2解码也存在一些限制和要求: 1. 硬件支持要求:要使用dxva2解码功能,需要具备支持DXVA2的显卡硬件。不同显卡型号和厂商支持的dxva2版本可能会有所不同,所以在使用前需要确认自己的显卡是否支持dxva2解码。 2. FFmpeg版本要求:为了能够使用dxva2解码功能,需要使用支持dxva2FFmpeg版本。更新的FFmpeg版本通常会修复一些bug并加入新的功能,所以建议使用最新版本的FFmpeg。 总结来说,通过FFmpegdxva2解码功能,我们可以提高解码效率、减轻CPU负担,并获得更好的视频播放体验。需要注意的是,确保硬件和软件环境支持dxva2解码,并及时更新FFmpeg版本可以保证最佳的使用效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周星星的星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值