`
chriszeng87
  • 浏览: 717238 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【GPU编解码】GPU硬解码---DXVA

阅读更多

前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码。

一、DXVA介绍

DXVA是微软公司专门定制的视频加速规范,是一种接口规范。DXVA规范制定硬件加速解码可分四级:VLD,控制BitStream;IDCT,反余弦变换;Mocomp,运动补偿,Pixel Prediction;PostProc,显示后处理。其中,VLD加速等级最高,所以其包含IDCTMoCoopmPostProcIDCT加速次之,包含MoCoopmPostProc;最后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的定义如下:

  1. AVCodec ff_h264_dxva2_decoder = { 
  2.     .name           = "h264_dxva2"
  3.     .type           = AVMEDIA_TYPE_VIDEO, 
  4.     .id             = AV_CODEC_ID_H264, 
  5.     .priv_data_size = sizeof(DXVA2_DecoderContext), 
  6.     .init           = h264_dxva2dec_init, 
  7.     .close          = h264_dxva2dec_close, 
  8.     .decode         = h264_dxva2dec_decode, 
  9.     .capabilities   = CODEC_CAP_DELAY, 
  10.     .flush          = h264_dxva2dec_flush, 
  11.     .long_name      = NULL_IF_CONFIG_SMALL("H.264 (DXVA2 acceleration)"), 
  12. }; 

ff_h264_dxva2_decoder的函数指针对应的函数定义如下:

  1. static int h264_dxva2dec_decode(AVCodecContext *avctx, void *data, int *got_frame, 
  2.                                   AVPacket *avpkt) 
  3.     return ff_dxva2dec_decode(avctx,data,got_frame,avpkt,&ff_h264_decoder); 
  4.  
  5. static av_cold int h264_dxva2dec_close(AVCodecContext *avctx) 
  6.     return ff_dxva2dec_close(avctx,&ff_h264_decoder); 
  7.  
  8. static av_cold int h264_dxva2dec_init(AVCodecContext *avctx) 
  9.     return ff_dxva2dec_init(avctx,&ff_h264_dxva2_decoder,&ff_h264_decoder); 
  10.  
  11. static void h264_dxva2dec_flush(AVCodecContext *avctx) 
  12.     ff_dxva2dec_flush(avctx,&ff_h264_decoder); 

上述代码,只是 ff_dxva2dec_init(),ff_dxva2dec_flush(),ff_dxva2dec_decode(),ff_dxva2dec_close() 的封装,具体解码的实现,由ff_dxva2dec_xxx相关函数完成,其代码实现如下:

  1. static int get_buffer(struct AVCodecContext *avctx, AVFrame *pic) 
  2.     int ret; 
  3.     DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data; 
  4.     dxva2_context *dxva2_ctx = &ctx->dxva2_ctx; 
  5.     avctx->pix_fmt = ctx->pix_fmt; 
  6.     ff_init_buffer_info(avctx, pic); 
  7.     if ((ret = ctx->get_buffer(avctx,pic)) < 0) { 
  8.         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 
  9.         return ret; 
  10.     } 
  11.     if (dxva2_ctx) { 
  12.         if (av_get_dxva2_surface(dxva2_ctx, pic)) { 
  13.             av_log(NULL, AV_LOG_ERROR, "VaGrabSurface failed"); 
  14.             return -1; 
  15.         } 
  16.         return 0; 
  17.     } else { 
  18.         av_log(NULL, AV_LOG_ERROR, "No dxva2 context, get buffer failed"); 
  19.         return -1; 
  20.     } 
  21.  
  22. static void release_buffer(struct AVCodecContext *avctx, AVFrame *pic) 
  23.     DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data; 
  24.     dxva2_context *dxva2_ctx = &ctx->dxva2_ctx; 
  25.     if (dxva2_ctx) { 
  26.         av_release_dxva2_surface(dxva2_ctx, pic); 
  27.     } 
  28.     ctx->release_buffer(avctx,pic); 
  29.     for (int i = 0; i < 4; i++) 
  30.         pic->data[i] = NULL; 
  31.  
  32. static enum PixelFormat get_format(AVCodecContext *p_context, 
  33.                                        const enum PixelFormat *pi_fmt) 
  34.      return AV_PIX_FMT_DXVA2_VLD; 
  35. static int check_format(AVCodecContext *avctx) 
  36.     uint8_t *pout; 
  37.     int psize; 
  38.     int index; 
  39.     H264Context *h; 
  40.     int ret = -1; 
  41.     AVCodecParserContext *parser = NULL; 
  42.     /* check if support */ 
  43.     switch (avctx->codec_id) { 
  44.     case AV_CODEC_ID_H264: 
  45.         /* init parser & parse file */ 
  46.         parser = av_parser_init(avctx->codec->id); 
  47.         if (!parser) { 
  48.             av_log(avctx, AV_LOG_ERROR, "Failed to open parser.\n"); 
  49.             break
  50.         } 
  51.         parser->flags = PARSER_FLAG_COMPLETE_FRAMES; 
  52.         index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0, 0); 
  53.         if (index < 0) { 
  54.             av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n"); 
  55.             av_parser_close(parser); 
  56.         } 
  57.         h = parser->priv_data; 
  58.         if (8 == h->sps.bit_depth_luma) { 
  59.             if (!CHROMA444 && !CHROMA422) { 
  60.                 // only this will decoder switch to hwaccel 
  61.                 av_parser_close(parser); 
  62.                 ret = 0; 
  63.                 break
  64.             } 
  65.         } else { 
  66.             av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n"); 
  67.             av_parser_close(parser); 
  68.             break
  69.         } 
  70.         break
  71.     case AV_CODEC_ID_MPEG2VIDEO: 
  72.         if (CHROMA_420 == get_mpeg2_video_format(avctx)) { 
  73.             ret = 0; 
  74.             break
  75.         } else { 
  76.             av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n"); 
  77.             break
  78.         } 
  79.     default
  80.         ret = 0; 
  81.         break
  82.     } 
  83.     return ret; 
  84.  
  85. int ff_dxva2dec_decode(AVCodecContext *avctx, void *data, int *got_frame, 
  86.                                   AVPacket *avpkt,AVCodec *codec) 
  87.     DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data; 
  88.     AVFrame *pic = data; 
  89.     int ret; 
  90.     ret = codec->decode(avctx, data, got_frame, avpkt); 
  91.     if (*got_frame) { 
  92.         pic->format = ctx->pix_fmt; 
  93.         av_extract_dxva2(&(ctx->dxva2_ctx),pic); 
  94.     } 
  95.     avctx->pix_fmt = ctx->pix_fmt; 
  96.     return ret; 
  97.  
  98. int ff_dxva2dec_close(AVCodecContext *avctx,AVCodec *codec) 
  99.     DXVA2_DecoderContext *ctx = avctx->priv_data; 
  100.     /* release buffers and decoder */ 
  101.     av_release_dxva2(&ctx->dxva2_ctx); 
  102.     /* close decoder */ 
  103.     codec->close(avctx); 
  104.     return 0; 
  105.  
  106.  
  107. int ff_dxva2dec_init(AVCodecContext *avctx,AVCodec *hwcodec,AVCodec *codec) 
  108.     DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data; 
  109.     dxva2_context *dxva2_ctx = (dxva2_context *)(&ctx->dxva2_ctx); 
  110.     int ret; 
  111.     ctx->initialized = 0; 
  112.     /* init pix_fmts of codec */ 
  113.     if (!(hwcodec->pix_fmts)) { 
  114.         hwcodec->pix_fmts = dxva2_pixfmts; 
  115.     } 
  116.     /* check if DXVA2 supports this file */ 
  117.     if (check_format(avctx) < 0) 
  118.         goto failed; 
  119.  
  120.     /* init vda */ 
  121.     memset(dxva2_ctx, 0, sizeof(dxva2_context)); 
  122.     ret = av_create_dxva2(avctx->codec_id,dxva2_ctx); 
  123.     if (ret < 0) { 
  124.         av_log(NULL,AV_LOG_ERROR,"create dxva2 error\n"); 
  125.         return 0; 
  126.     } 
  127.     ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts); 
  128.     ret = av_setup_dxva2(dxva2_ctx, &avctx->hwaccel_context
  129. , &avctx->pix_fmt, avctx->width, avctx->height); 
  130.     if (ret < 0) { 
  131.         av_log(NULL,AV_LOG_ERROR,"error DXVA setup %d\n", ret); 
  132.         goto failed; 
  133.     } 
  134.     /* changes callback functions */ 
  135.     ctx->get_buffer = avctx->get_buffer; 
  136.     avctx->get_format = get_format; 
  137.     avctx->get_buffer = get_buffer; 
  138.     avctx->release_buffer = release_buffer; 
  139.     /* init decoder */ 
  140.     ret = codec->init(avctx); 
  141.     if (ret < 0) { 
  142.         av_log(avctx, AV_LOG_ERROR, "Failed to open decoder.\n"); 
  143.         goto failed; 
  144.     } 
  145.     ctx->initialized = 1; 
  146.     return 0; 
  147. failed: 
  148.     ff_dxva2dec_close(avctx,codec); 
  149.     return -1; 
  150.  
  151. void ff_dxva2dec_flush(AVCodecContext *avctx,AVCodec *codec) 
  152.     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)
:文章转载自:罗索实验室 [http://www.rosoo.net/a/201506/17336.html]
本文出处:博客园 作者:dwdxdy 原文
分享到:
评论

相关推荐

    ffmpeg dxva gpu 解码的完整demo

    ffmpeg dxva gpu 解码的完整demo,下载后即可顺利编译运行

    基于ffmpeg实现硬件解码功能

    基于ffmpeg实现硬件解码,支持cuda/dxva2/qsv/d3dllva/opencl类型GPU设备。资源包括完成的vs工程代码,解压后可直接编译运行,依赖的ffmpeg开发包也在资源包中。

    DXVA Checker 4.2.1.rar

    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 ...

    HwDecSdk.zip_GPU_HwDecSdk_ffmpeg dxva2_ffmpeg_dxva2_ffmpeg实现dxva

    使用ffmpeg+dxva2实现H.264硬解码 SDK,支持同时多路并行解码。

    DXVA Checker v4.0.0(显卡硬件加速检测工具)

    DXVA Checker是一个显卡硬件加速检测工具,用于检测显卡的DirectX视频加速(DXVA)功能,DXVA是微软公司专门定制的视频加速规范,DXVA Checker能够检查当前显卡GPU支持的解码器、DXVA解码性能和视频处理性能、...

    vs2015_ffmpeg_dxva2.rar

    使用ffmpeg dxva2实现gpu硬件解码,使用d3d直接渲染显存中的解码数据。vs2015开发

    ffmpeg_dxva2_demo(fixed).rar

    在网上下载的很多ffmpeg_dxva2原码包,都是各种问题跑不了,dxva2_...我这份修改好了,在vs2019 win10 64下配好各种库的路径可以直接运行了,选择一个mp4视频,就可以直接解码渲染出来了,在资源管理器可以看到GPU在跳

    QT下开发的音视频播放器,支持单路与多路播放,软硬解码,本地与实时视频播放,录像截图,YUV与RGB显示,音量调节,进度条跳转等

    本播放器支持软硬解码,硬解码采用的DXVA2, ffmpeg解码后,通过重写QOpenGLWidget,可以让YUV转RGB在GPU进行处理,减少对CPU的使用。音频播放采用的是QAudioOutput,通过setVolumn接口可以控制音量的大小。本播放器...

    DirectShow分离器和音视解码器(LAV Filters) v0.60.1.rar

    - 为最近的 Intel GPU 增加 VC-1/WMV3 DXVA2 解码支持 (如 Ivy Bridge/Haswell,需要最新的驱动程序) - 修复 AMD 平台在 DXVA2 Native 模式下停止播放或搜索时的崩溃问题 - 修复 WMVA 视频在软件解码模式下的...

    CoreAVC Pro v2.0

    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

    GPU_Player

    利用rtsp 获取数据源 dxva 解码渲染

    khhguhffzuom.zip视频桌面软件

    设置界面,视频播放器强烈建议在安装 LAVFilters 后选择 DirectShow 并在 LAV Video Configuration 中开启 DXVA2 硬解码。在 reizhi 的系统上,开启硬解后播放 140M 13Mbps 的 2K 60fps 视频,CPU 占用仅1%,内存...

    DXVAChecker32_2.5.0

    *确认解码设备和处理器设备可以使用GPU。 系统需求 操作系统 Windows7/Vista/XP 运行 Microsoft。NET框架2.0(X86 /适用于x64) 微软的Visual C2008 SP1运行(X86 /针对x64) 解码器的名称 对于AMD /...

    Flutter Windows通过嵌入Native窗口实现渲染视频

    如果能使用win32窗口,直接通过句柄渲染,那就可以达到与原生Windows渲染使用一致的效果,可以使用sdl渲染yuv,以及dxva2解码后d3d9表面直接渲染到窗口全程在gpu上操作。本文将介绍如何在flutter程序嵌入win32窗口...

    基于Qt+FFmpeg的视频监控系统源码+项目说明+sln解决方案.zip

    1.项目代码均经过功能验证ok,确保稳定...* 使用DXVA2+D3d9实现纯GPU解码渲染 ## 环境依赖 ### windows VS:推荐VS2019以后的版本 Qt:推荐Qt5.12以后的版本 解决方案仅支持64位的Debug/Release,32位可自行适配

    射手影音播放器_3.6.0.1849

     支持2种GPU加速:DXVA和CUDA 高画质  独创ShaderEngineTM图像增强引擎,4倍速驱动,降低画面噪点,锐利画质呈现,低画质视频照样全屏放 独创LiveColorTM彩色增强算法,画面色彩更艳丽 独创SmartAmplifyTM智能音场...

    mpv.net::film_frames:mpv.net是适用于Windows的现代媒体播放器,其作用类似于mpv

    利用FFmpeg hwaccel API支持DXVA2视频解码加速。 积极发展 mpv.net正在积极开发中。 基于libmpv mpv.net基于libmpv,它提供了一个直接的C API,该API是从头开始设计的,目的是使mpv可用作库,并便于轻松集成到其他...

    C++ HLSL实现简单的图像处理功能

    由于对于dxva2解码得到的数据不宜copy回内存给CPU处理,所以最好的办法是在GPU上直接进行处理。D3D的像素着色器能够对像素直接进行操作,实现点运算极其简单方便,简单的卷积运算效果也非常好。但D3D9的限制也很多,...

Global site tag (gtag.js) - Google Analytics