前面介绍利用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中利用DXVA2(DXVA的第二版)实现GPU解码的详细步骤。DXVA2是Windows操作系统中的一种接口,允许应用程序利用显卡硬件加速视频解码过程,支持H.264、VC-1...
总结来说,"ffmpeg使用dxva2硬解码DEMO(vs2010)"是一个展示如何在Windows环境中利用FFmpeg和DXVA2实现硬件加速解码的示例工程。通过理解硬件加速的基本原理和FFmpeg的API用法,你可以根据这个DEMO进行自己的项目开发...
1. 初始化FFmpeg库:使用`av_register_all()`注册所有内置的编解码器,`avformat_network_init()`初始化网络功能。 2. 打开输入文件:通过`avformat_open_input()`打开视频文件,然后调用`avformat_find_stream_...
FFmpeg支持多种硬件加速技术,其中DXVA是Windows平台上的一种,主要针对DirectX环境,用于在GPU上执行视频解码任务,以提升播放效率和降低功耗。DXVA分为两个主要版本:DXVA1和DXVA2,后者提供了更多的功能和更高的...
DXVA2是微软开发的一种技术,旨在利用现代图形处理单元(GPU)进行视频解码,以减轻CPU的负担,提供更流畅的播放体验。 首先,我们要明白H264和H265的区别。H264,也称为AVC(Advanced Video Coding),是目前广泛...
FFmpeg是一个开源的多媒体处理框架,它包含了众多的编解码库、音视频处理工具,以及用于音频视频处理的API。在本项目中,“基于ffmpeg实现硬件解码功能”是利用FFmpeg库来实现视频的硬件加速解码,旨在提高视频处理...
在使用这些源代码时,开发者需要对FFmpeg的内部工作原理有深入理解,包括其编解码器结构、上下文管理以及如何集成硬件加速功能。他们还需要熟悉DirectX API,特别是Dxva2的相关接口,以便正确地在FFmpeg中启用和利用...
FFmpeg是一款强大的开源跨平台工具集,包含了用于处理音频、视频的编解码库以及命令行工具。FFmpeg支持多种编码格式和标准,并且能够利用硬件加速功能,如DXVA2,来提升解码性能。通过FFmpeg,开发者和用户可以在...
DXVA-H264是DXVA的一个子集,专门针对H.264编码的视频设计。通过这个接口,FFmpeg能够利用支持DXVA的显卡来执行解码过程中的大部分计算任务,如运动估计、熵解码等,从而将工作负载从CPU转移到GPU上,提高播放效率并...
DXVA是微软为Windows操作系统开发的一种视频硬件加速接口,它可以将视频解码任务交给GPU来执行,从而释放CPU资源,提升播放流畅度。 标题“ffmpeg+dxva解码,优化dxva拷贝速度”表明我们将在FFmpeg中集成DXVA解码...
在FFmpeg中,硬解码是一种利用GPU硬件加速来提高视频解码效率的技术,可以显著降低CPU的负载,尤其对于高清或高码率的视频来说,硬解码的优势更为明显。DXVA2(DirectX Video Acceleration 2)是微软提供的一个接口...
如果是,它会创建一个DXVA2设备,并通过该设备与GPU通信,将解码任务交给显卡执行。硬件解码完成后,解码后的视频帧将以纹理的形式存储在显存中,接下来的任务是将这些纹理渲染到屏幕上。 渲染过程通常涉及多个步骤...
在FFmpeg中,DXVA2(DirectX Video Acceleration 2)是一种硬件加速技术,利用图形处理单元(GPU)来减轻CPU的负担,提高视频处理效率,尤其在进行高清或4K视频播放时,其优势尤为显著。本项目是基于VS2013的Windows...
1. **DirectX Video Acceleration (DXVA)**:DXVA提供了多种硬件加速模式,如DXVA-HD用于高清视频,以及不同的编码格式支持,如H.264、MPEG-2等。理解如何选择合适的解码配置以优化性能是关键。 2. **Direct3D 9**...
DXVA2是微软提供的一个接口,允许应用程序利用GPU进行视频解码,主要适用于Windows系统。在FFmpeg中,可以使用libavcodec库的特定选项和API来开启DXVA2解码。 “ffmpeg-demo-master.zip”可能是一个包含FFmpeg...
FFMpeg是一个开源的多媒体处理库,提供了视频和音频的编解码、采集、转码和处理等功能。FFMpeg的源码是由C语言编写的,可以在多种平台上运行。 三、DXVA2的概念解释 DXVA2是DirectX Video Acceleration 2.0规范,...
【GPU解码数据快速拷贝的应用研究】 高清视频在客户端播放过程中,面临的主要问题是CPU占用率高和图像数据拷贝速度慢。为了改善这一状况,本文提出了一种基于GPU解码数据快速拷贝的方法,旨在优化视频解码过程,...
在本文中,我们将深入探讨如何使用DirectX Video Acceleration 2 (DXVA2) 和 High-Level Shader Language (HLSL) 对解码后的视频数据进行简单的图像处理。DXVA2 是微软开发的一种技术,旨在利用图形处理器(GPU)的...
在网上下载的很多ffmpeg_dxva2原码包,都是各种问题跑不了,dxva2_...我这份修改好了,在vs2019 win10 64下配好各种库的路径可以直接运行了,选择一个mp4视频,就可以直接解码渲染出来了,在资源管理器可以看到GPU在跳
此项目集成了ffmpeg库,并实现了使用DXVA2进行GPU解码和Direct3D渲染的逻辑。 综上所述,"vs2015_ffmpeg_dxva2.rar"项目是通过Visual Studio 2015开发的一个多媒体应用程序,它利用ffmpeg库与DXVA2接口,实现了GPU...