欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【硬件解码系列】之DXVA2

程序员文章站 2022-07-05 13:23:07
...

 本文小编也是在学习dxva2解码,所以很多资料都是来源网上搜集加自己理解。

1. DXVA2解码过程

(1)、调用DXVA2CreateDirect3DDeviceManager9函数获取到IDirect3DDeviceManager9接口的一个对象。
(2)、调用IDirect3DDeviceManager9::OpenDeviceHandle 函数获取到一个Direct3D 设备对象句柄。
(3)、调用IDirect3DDeviceManager9::GetVideoService 函数并且传递Direct3D设备句柄,这个函数返回IDirectXVideoDecoderService接口对象指针。
(4)、调用 IDirectXVideoDecoderService::GetDecoderDeviceGuids 函数返回解码设备GUID的数组。
(5)、循环遍历解码设备GUID数组找到一个目前硬件驱动能支持的GUID解码设备。例如,如果驱动只支持MPEG-2 解码,则需要找到DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT, or DXVA2_ModeMPEG2_VLD这几个GUID才能解码。
(6)、如果你找到了一个解码设备GUID,传递这个GUID给IDirectXVideoDecoderService::GetDecoderRenderTargets 函数,这个函数返回一个类型为D3DFORMAT 的渲染目标格式数组(render target format)。
(7)、循环遍历渲染目标格式数组,找到一个匹配的输出格式。通常一个解码设备只支持一个渲染目标输出格式。
(8)、调用IDirectXVideoDecoderService::GetDecoderConfigurations函数,并且传递解码设备GUID和DXVA2_VideoDesc结构体(描述视频信息)。这个函数返回一个 DXVA2_ConfigPictureDecode结构体的数组,这个数组中的每一项描述一个可能的解码配置信息。
(9)、调用IDirectXVideoDecoderService::CreateVideoDecoder函数,并且传递解码设备GUID和DXVA2_VideoDesc结构体, DXVA2_ConfigPictureDecode,渲染目标surface数组。这个函数将返回一个IDirectXVideoDecoder 接口对象。
(10)、调用函数 IDirectXVideoDecoder::BeginFrame
(11)、调用下面过程多次:

  1. 调用IDirectXVideoDecoder::GetBuffer 函数得到一个DXVA解码缓冲区( DXVA decoder buffer )。
  2. 将数据填充到这个DXVA解码缓冲区中。
  3. 调用 IDirectXVideoDecoder::ReleaseBuffer 释放这个DXVA解码缓冲区。

(12)、调用 IDirectXVideoDecoder::Execute 函数执行这一帧的解码操作。
(13)、调用IDirectXVideoDecoder::EndFrame

注意:在每一帧解码之前必须调用函数IDirect3DDeviceManager9::TestDevice测试设备句柄是否修改。如果设备已经修改,此函数将返回DXVA2_E_NEW_VIDEO_DEVICE。如果这种情况发生,执行下面操作:

  1. 通过调用IDirect3DDeviceManager9::CloseDeviceHandle函数关闭设备句柄对象。
  2. 释放 IDirectXVideoDecoderServiceIDirectXVideoDecoder 对象指针。
  3. 打开一个新的设备句柄。
  4. 协商一个新的解码配置项。
  5. 创建一个新的解码设备。

摘抄自参考网址:https://www.cnblogs.com/betterwgo/p/6125507.html , 此参考网址将dxva的调用流程说的很清楚。

上面的函数是为创建IDirectXVideoDecoder 接口对象使用的。而实际的解码函数,主要由2个函数组成:

ff_dxva2_common_end_frame
ff_dxva2_commit_buffer

此2个函数由不同的函数调用,例如对于h264格式的码流是由ff_h264_dxva2_hwaccel 中的.end_frame = dxva2_h264_end_frame函数调用。

AVHWAccel ff_h264_dxva2_hwaccel = {
    .name           = "h264_dxva2",
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_H264,
    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
    .start_frame    = dxva2_h264_start_frame,
    .decode_slice   = dxva2_h264_decode_slice,
    .end_frame      = dxva2_h264_end_frame,
    .frame_priv_data_size = sizeof(struct dxva2_picture_context),
};

ff_h264_dxva2_hwaccel结构体是由int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)函数中的if (!setup_hwaccel(avctx, ret, desc->name)) 调用(此函数源自 libavcodec/utils.c),

可参考目前网上已有的工程:
也可参考ffmpeg自带的sample:例如ffmpeg-3.2中的ffmpeg_dxva2.c

参考网址:https://blog.csdn.net/xiaoyafang123/article/details/82905452
参考网址:https://blog.csdn.net/lishuzhai/article/details/52497110