前面介绍利用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)) < ) {
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 -;
}
return ;
} else {
av_log(NULL, AV_LOG_ERROR, "No dxva2 context, get buffer failed");
return -;
}
} 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 = ; i < ; 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 = -;
AVCodecParserContext *parser = NULL;
/* check if support */
switch (avctx->codec_id) {
case AV_CODEC_ID_H264:
/* init parser & parse file */
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, , , , );
if (index < ) {
av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
av_parser_close(parser);
}
h = parser->priv_data;
if ( == h->sps.bit_depth_luma) {
if (!CHROMA444 && !CHROMA422) {
// only this will decoder switch to hwaccel
av_parser_close(parser);
ret = ;
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 = ;
break;
} else {
av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
break;
}
default:
ret = ;
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;
/* release buffers and decoder */
av_release_dxva2(&ctx->dxva2_ctx);
/* close decoder */
codec->close(avctx);
return ;
} 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 = ;
/* init pix_fmts of codec */
if (!(hwcodec->pix_fmts)) {
hwcodec->pix_fmts = dxva2_pixfmts;
}
/* check if DXVA2 supports this file */
if (check_format(avctx) < )
goto failed; /* init vda */
memset(dxva2_ctx, , sizeof(dxva2_context));
ret = av_create_dxva2(avctx->codec_id,dxva2_ctx);
if (ret < ) {
av_log(NULL,AV_LOG_ERROR,"create dxva2 error\n");
return ;
}
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 < ) {
av_log(NULL,AV_LOG_ERROR,"error DXVA setup %d\n", ret);
goto failed;
}
/* changes callback functions */
ctx->get_buffer = avctx->get_buffer;
avctx->get_format = get_format;
avctx->get_buffer = get_buffer;
avctx->release_buffer = release_buffer;
/* init decoder */
ret = codec->init(avctx);
if (ret < ) {
av_log(avctx, AV_LOG_ERROR, "Failed to open decoder.\n");
goto failed;
}
ctx->initialized = ;
return ;
failed:
ff_dxva2dec_close(avctx,codec);
return -;
} 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

【GPU编解码】GPU硬解码---DXVA的更多相关文章

  1. 【视频开发】GPU编解码:GPU硬解码---DXVA

    GPU编解码:GPU硬解码---DXVA 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解码可分四级:VLD,控制BitStream;IDCT,反 ...

  2. 【GPU编解码】GPU硬解码---DXVA (转)

    前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...

  3. 【GPU编解码】GPU硬解码---CUVID

    问题描述:项目中,需要对高清监控视频分析处理,经测试,其解码过程所占CPU资源较多,导致整个系统处理效率不高,解码成为系统的瓶颈. 解决思路: 利用GPU解码高清视频,降低解码所占用CPU资源,加速解 ...

  4. 【计算机视觉】【并行计算与CUDA开发】GPU硬解码---DXVA

    前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...

  5. 【GPU编解码】GPU硬编码

    一.OpenCV中的硬编码 OpenCV2.4.6中,已实现利用GPU进行写视频,编码过程由cv::gpu::VideoWriter_GPU完成,其示例程序如下. int main(int argc, ...

  6. 【GPU编解码】GPU硬编码 (转)

    一.OpenCV中的硬编码 OpenCV2.4.6中,已实现利用GPU进行写视频,编码过程由cv::gpu::VideoWriter_GPU完成,其示例程序如下. 1 int main(int arg ...

  7. 【计算机视觉】【并行计算与CUDA开发】GPU硬解码---CUVID

    问题描述:项目中,需要对高清监控视频分析处理,经测试,其解码过程所占CPU资源较多,导致整个系统处理效率不高,解码成为系统的瓶颈. 解决思路: 利用GPU解码高清视频,降低解码所占用CPU资源,加速解 ...

  8. MediaCodec在Android视频硬解码组件的应用

    https://yq.aliyun.com/articles/632892 云栖社区> 博客列表> 正文 MediaCodec在Android视频硬解码组件的应用   cheenc 201 ...

  9. vlc源码分析(六) 调用OpenMAX硬解码H.265

    H.265(HEVC)编码格式能够在得到相同编码质量视频的前提下,使用相当于H.264(AVC)一半的存储容量,虽然H.265的算法复杂度比H.264高一个数量级,但是硬件水平在不断提高,因此H.26 ...

随机推荐

  1. Android开发(51) 摄像头自动对焦。在OpenCV图像识别中连续拍照时自动对焦和拍照。

    概述 对焦,这里所说的“焦”是指“焦距”.在拍照时,一定是需要调焦的.一般会在目标位置最清晰的时候会停止对焦.最近在处理OpenCV进行图像识别时,需要连续的调焦(对焦),并在对焦完成后进行拍照,获取 ...

  2. 理解WebSocket

    WebSocket的动机是什么? 目前的Web通信使用的是HTTP协议,HTTP协议是基于TCP协议的应用层协议,HTTP协议的工作模式是request/response模式.在一次通信中,必须首先由 ...

  3. Vim安装jedi-vim提示的一个错误

    (仅为了提醒自己) 第一次的安装方法好像是通过 bundle安装的,好像是通过这个安装的并不是最新的版本,然后删除了通过下面的方法,最重要的是要执行 git submodule update --in ...

  4. Mvc 拼接Html 导出 Excel(服务器不用安装呦!支持2007以上版本)

    新公司,新接触,老方法,更实用. 之前接触过Webform,winfrom 的导出Excel方法 ,优点:省事.缺点:服务器必须安装Office 这几天做项目 和 大牛学习了一下 新的方法,自己加以总 ...

  5. Flash Media Server 4.5 序列号 (fms4.5 激活码)

    激活码一枚   ,网上找不到的..我今天放出来了哦... 1462-5864-7783-6034-8316-3718    (亲测 可用) 安装前找到系统盘下windows/system32/driv ...

  6. POJ 1816 Wild Words

    Wild Words Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4412   Accepted: 1149 Descri ...

  7. php 图片添加文字水印 以及 图片合成(微信快码传播)

    1.图片添加文字水印: $bigImgPath = 'backgroud.png'; $img = imagecreatefromstring(file_get_contents($bigImgPat ...

  8. 一点一滴之NHibernate

    之前介绍了Dapper,速度很快,很轻量,很好用. 但是Dapper其实有自己的弊端,比如在数据关系复杂,数据库表非常多,多数据库支持,数据库结构变动频繁的时候总是很无奈.尽管有代码生成器,但是代码生 ...

  9. php生成随机密码(php自定义函数)转自先锋教程网

    php生成随机密码(php自定义函数) 时间:2015-12-16 20:43:49来源:网络 导读:php随机密码的生成代码,使用php自定义函数生成指定长度的随机密码,密码规则为小写字母与数字的随 ...

  10. css hack 整理

    <ul> <li>"_" ------ IE6</li> <li>"-" ------ IE6</li&g ...