前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码。
一、DXVA介绍
DXVA是微软公司专门定制的视频加速规范,是一种接口规范。DXVA规范制定硬件加速解码可分四级:VLD,控制BitStream;IDCT,反余弦变换;Mocomp,运动补偿,Pixel Prediction;PostProc,显示后处理。其中,VLD加速等级最高,所以其包含IDCT、MoCoopm和PostProc;IDCT加速次之,包含MoCoopm和PostProc;最后MoComp加速仅包含PostProc。一款显卡芯片在硬件支持DXVA规范,并不代表它就实现了DXVA所有功能。DXVA_Checker可用于检测硬件所支持的等级,DXVA_Checker运行示意图如下所示。
二、使用FFmpeg中DXVA技术硬解码
基本思路:
1.根据FFmpeg对编码器的描述,实现自定义的硬解码器。
2.通过REGISTER_ENCODEC(X,x)将自定义的视频编码器添加到视频编解码器。
3.在视频解码,根据编码器ID或编码器名称找到视频编解码器中自定义的视频解码器。
4.利用自定义的视频解码器,解码视频。
其关键步骤是:自定义解码器的实现,需要参考FFmpeg源码中,解码器的定义和接口设计。
基于DXVA的自定义解码器实现
1.熟悉FFmpeg中编解码的组织方式
下图是ffmpeg编解码组织的简单示意图。
由示意图可知,编解码器由全局链表组织,可根据编码器的名称或ID,获取编解码器。
编解码器的具体编解码的具体工作,由编解码器定义的函数指针完成。
自定义解码器时,需要按照AVCodec结构体,定义解码器的属性,然后注册到全局编解码器链表中。
2.基于DXVA解码器的定义实现
ff_h264_dxva2_decoder的定义如下:
- AVCodec ff_h264_dxva2_decoder = {
- .name = "h264_dxva2",
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_H264,
- .priv_data_size = sizeof(DXVA2_DecoderContext),
- .init = h264_dxva2dec_init,
- .close = h264_dxva2dec_close,
- .decode = h264_dxva2dec_decode,
- .capabilities = CODEC_CAP_DELAY,
- .flush = h264_dxva2dec_flush,
- .long_name = NULL_IF_CONFIG_SMALL("H.264 (DXVA2 acceleration)"),
- };
ff_h264_dxva2_decoder的函数指针对应的函数定义如下:
- static int h264_dxva2dec_decode(AVCodecContext *avctx, void *data, int *got_frame,
- AVPacket *avpkt)
- {
- return ff_dxva2dec_decode(avctx,data,got_frame,avpkt,&ff_h264_decoder);
- }
-
- static av_cold int h264_dxva2dec_close(AVCodecContext *avctx)
- {
- return ff_dxva2dec_close(avctx,&ff_h264_decoder);
- }
-
- static av_cold int h264_dxva2dec_init(AVCodecContext *avctx)
- {
- return ff_dxva2dec_init(avctx,&ff_h264_dxva2_decoder,&ff_h264_decoder);
- }
-
- static void h264_dxva2dec_flush(AVCodecContext *avctx)
- {
- ff_dxva2dec_flush(avctx,&ff_h264_decoder);
- }
上述代码,只是 ff_dxva2dec_init(),ff_dxva2dec_flush(),ff_dxva2dec_decode(),ff_dxva2dec_close() 的封装,具体解码的实现,由ff_dxva2dec_xxx相关函数完成,其代码实现如下:
- static int get_buffer(struct AVCodecContext *avctx, AVFrame *pic)
- {
- int ret;
- DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data;
- dxva2_context *dxva2_ctx = &ctx->dxva2_ctx;
- avctx->pix_fmt = ctx->pix_fmt;
- ff_init_buffer_info(avctx, pic);
- if ((ret = ctx->get_buffer(avctx,pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
- }
- if (dxva2_ctx) {
- if (av_get_dxva2_surface(dxva2_ctx, pic)) {
- av_log(NULL, AV_LOG_ERROR, "VaGrabSurface failed");
- return -1;
- }
- return 0;
- } else {
- av_log(NULL, AV_LOG_ERROR, "No dxva2 context, get buffer failed");
- return -1;
- }
- }
-
- static void release_buffer(struct AVCodecContext *avctx, AVFrame *pic)
- {
- DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data;
- dxva2_context *dxva2_ctx = &ctx->dxva2_ctx;
- if (dxva2_ctx) {
- av_release_dxva2_surface(dxva2_ctx, pic);
- }
- ctx->release_buffer(avctx,pic);
- for (int i = 0; i < 4; i++)
- pic->data[i] = NULL;
- }
-
- static enum PixelFormat get_format(AVCodecContext *p_context,
- const enum PixelFormat *pi_fmt)
- {
- return AV_PIX_FMT_DXVA2_VLD;
- }
- static int check_format(AVCodecContext *avctx)
- {
- uint8_t *pout;
- int psize;
- int index;
- H264Context *h;
- int ret = -1;
- AVCodecParserContext *parser = NULL;
-
- switch (avctx->codec_id) {
- case AV_CODEC_ID_H264:
-
- parser = av_parser_init(avctx->codec->id);
- if (!parser) {
- av_log(avctx, AV_LOG_ERROR, "Failed to open parser.\n");
- break;
- }
- parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
- index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0, 0);
- if (index < 0) {
- av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
- av_parser_close(parser);
- }
- h = parser->priv_data;
- if (8 == h->sps.bit_depth_luma) {
- if (!CHROMA444 && !CHROMA422) {
-
- av_parser_close(parser);
- ret = 0;
- break;
- }
- } else {
- av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
- av_parser_close(parser);
- break;
- }
- break;
- case AV_CODEC_ID_MPEG2VIDEO:
- if (CHROMA_420 == get_mpeg2_video_format(avctx)) {
- ret = 0;
- break;
- } else {
- av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
- break;
- }
- default:
- ret = 0;
- break;
- }
- return ret;
- }
-
- int ff_dxva2dec_decode(AVCodecContext *avctx, void *data, int *got_frame,
- AVPacket *avpkt,AVCodec *codec)
- {
- DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data;
- AVFrame *pic = data;
- int ret;
- ret = codec->decode(avctx, data, got_frame, avpkt);
- if (*got_frame) {
- pic->format = ctx->pix_fmt;
- av_extract_dxva2(&(ctx->dxva2_ctx),pic);
- }
- avctx->pix_fmt = ctx->pix_fmt;
- return ret;
- }
-
- int ff_dxva2dec_close(AVCodecContext *avctx,AVCodec *codec)
- {
- DXVA2_DecoderContext *ctx = avctx->priv_data;
-
- av_release_dxva2(&ctx->dxva2_ctx);
-
- codec->close(avctx);
- return 0;
- }
-
-
- int ff_dxva2dec_init(AVCodecContext *avctx,AVCodec *hwcodec,AVCodec *codec)
- {
- DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data;
- dxva2_context *dxva2_ctx = (dxva2_context *)(&ctx->dxva2_ctx);
- int ret;
- ctx->initialized = 0;
-
- if (!(hwcodec->pix_fmts)) {
- hwcodec->pix_fmts = dxva2_pixfmts;
- }
-
- if (check_format(avctx) < 0)
- goto failed;
-
-
- memset(dxva2_ctx, 0, sizeof(dxva2_context));
- ret = av_create_dxva2(avctx->codec_id,dxva2_ctx);
- if (ret < 0) {
- av_log(NULL,AV_LOG_ERROR,"create dxva2 error\n");
- return 0;
- }
- ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
- ret = av_setup_dxva2(dxva2_ctx, &avctx->hwaccel_context
- , &avctx->pix_fmt, avctx->width, avctx->height);
- if (ret < 0) {
- av_log(NULL,AV_LOG_ERROR,"error DXVA setup %d\n", ret);
- goto failed;
- }
-
- ctx->get_buffer = avctx->get_buffer;
- avctx->get_format = get_format;
- avctx->get_buffer = get_buffer;
- avctx->release_buffer = release_buffer;
-
- ret = codec->init(avctx);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Failed to open decoder.\n");
- goto failed;
- }
- ctx->initialized = 1;
- return 0;
- failed:
- ff_dxva2dec_close(avctx,codec);
- return -1;
- }
-
- void ff_dxva2dec_flush(AVCodecContext *avctx,AVCodec *codec)
- {
- return codec->flush(avctx);
- }
其中,在ff_dxva2dec_init()函数中,利用av_create_dxva2()函数创建dxva2_context,av_setup_dxva2()设置dxva2_context。
在ff_dxva2dec_close()函数中,利用av_release_dxva2()释放dxva2_context。
av_xxx_dxva2()相关函数,主要利用DXVA2的API接口,创建dxva2的上下文,并进行管理。
总体而言,经过四次封装,形成方便的硬解码接口。
DXVA2 API接口 ---> av_xxx_dxva2 ---> ff_dxva2dec_xxx ---> h264_dxva2dec_xxx ---> ff_h264_dxva2_decoder
参考资料:
http://web.archiveorange.com/archive/v/4q4BhNz4oevWmMtHL3eY
(dwdxdy) |
相关推荐
ffmpeg dxva gpu 解码的完整demo,下载后即可顺利编译运行
基于ffmpeg实现硬件解码,支持cuda/dxva2/qsv/d3dllva/opencl类型GPU设备。资源包括完成的vs工程代码,解压后可直接编译运行,依赖的ffmpeg开发包也在资源包中。
DXVA Checker 4.2.1 Version 4.2.1 (04/20/2019) •Fixed process crash issue when checking Media Foundatio decoder on GPU which does not support D3D11 video acceleration •Fixed issue when submitting ...
使用ffmpeg+dxva2实现H.264硬解码 SDK,支持同时多路并行解码。
DXVA Checker是一个显卡硬件加速检测工具,用于检测显卡的DirectX视频加速(DXVA)功能,DXVA是微软公司专门定制的视频加速规范,DXVA Checker能够检查当前显卡GPU支持的解码器、DXVA解码性能和视频处理性能、...
使用ffmpeg dxva2实现gpu硬件解码,使用d3d直接渲染显存中的解码数据。vs2015开发
在网上下载的很多ffmpeg_dxva2原码包,都是各种问题跑不了,dxva2_...我这份修改好了,在vs2019 win10 64下配好各种库的路径可以直接运行了,选择一个mp4视频,就可以直接解码渲染出来了,在资源管理器可以看到GPU在跳
本播放器支持软硬解码,硬解码采用的DXVA2, ffmpeg解码后,通过重写QOpenGLWidget,可以让YUV转RGB在GPU进行处理,减少对CPU的使用。音频播放采用的是QAudioOutput,通过setVolumn接口可以控制音量的大小。本播放器...
- 为最近的 Intel GPU 增加 VC-1/WMV3 DXVA2 解码支持 (如 Ivy Bridge/Haswell,需要最新的驱动程序) - 修复 AMD 平台在 DXVA2 Native 模式下停止播放或搜索时的崩溃问题 - 修复 WMVA 视频在软件解码模式下的...
ATI GPU Support (DXVA) Intel Media SDK Support (DXVA) Multicore ready (Unlimited CPU Cores) 8100x8100 Resolution Support Full Interlaced support Matroska MKV Support Haali Media Splitter Included
利用rtsp 获取数据源 dxva 解码渲染
设置界面,视频播放器强烈建议在安装 LAVFilters 后选择 DirectShow 并在 LAV Video Configuration 中开启 DXVA2 硬解码。在 reizhi 的系统上,开启硬解后播放 140M 13Mbps 的 2K 60fps 视频,CPU 占用仅1%,内存...
*确认解码设备和处理器设备可以使用GPU。 系统需求 操作系统 Windows7/Vista/XP 运行 Microsoft。NET框架2.0(X86 /适用于x64) 微软的Visual C2008 SP1运行(X86 /针对x64) 解码器的名称 对于AMD /...
如果能使用win32窗口,直接通过句柄渲染,那就可以达到与原生Windows渲染使用一致的效果,可以使用sdl渲染yuv,以及dxva2解码后d3d9表面直接渲染到窗口全程在gpu上操作。本文将介绍如何在flutter程序嵌入win32窗口...
1.项目代码均经过功能验证ok,确保稳定...* 使用DXVA2+D3d9实现纯GPU解码渲染 ## 环境依赖 ### windows VS:推荐VS2019以后的版本 Qt:推荐Qt5.12以后的版本 解决方案仅支持64位的Debug/Release,32位可自行适配
支持2种GPU加速:DXVA和CUDA 高画质 独创ShaderEngineTM图像增强引擎,4倍速驱动,降低画面噪点,锐利画质呈现,低画质视频照样全屏放 独创LiveColorTM彩色增强算法,画面色彩更艳丽 独创SmartAmplifyTM智能音场...
利用FFmpeg hwaccel API支持DXVA2视频解码加速。 积极发展 mpv.net正在积极开发中。 基于libmpv mpv.net基于libmpv,它提供了一个直接的C API,该API是从头开始设计的,目的是使mpv可用作库,并便于轻松集成到其他...
由于对于dxva2解码得到的数据不宜copy回内存给CPU处理,所以最好的办法是在GPU上直接进行处理。D3D的像素着色器能够对像素直接进行操作,实现点运算极其简单方便,简单的卷积运算效果也非常好。但D3D9的限制也很多,...