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

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

前面介绍利用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的定义如下:

复制代码
 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 {
 4     return ff_dxva2dec_decode(avctx,data,got_frame,avpkt,&ff_h264_decoder);
 5 }
 6 
 7 static av_cold int h264_dxva2dec_close(AVCodecContext *avctx)
 8 {
 9     return ff_dxva2dec_close(avctx,&ff_h264_decoder);
10 }
11 
12 static av_cold int h264_dxva2dec_init(AVCodecContext *avctx)
13 {
14     return ff_dxva2dec_init(avctx,&ff_h264_dxva2_decoder,&ff_h264_decoder);
15 }
16 
17 static void h264_dxva2dec_flush(AVCodecContext *avctx)
18 {
19     ff_dxva2dec_flush(avctx,&ff_h264_decoder);
20 }
复制代码

上述代码,只是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 {  3 int ret;  4 DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data;  5 dxva2_context *dxva2_ctx = &ctx->dxva2_ctx;  6 avctx->pix_fmt = ctx->pix_fmt;  7  ff_init_buffer_info(avctx, pic);  8 if ((ret = ctx->get_buffer(avctx,pic)) < 0) {  9 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");  10 return ret;  11  }  12 if (dxva2_ctx) {  13 if (av_get_dxva2_surface(dxva2_ctx, pic)) {  14 av_log(NULL, AV_LOG_ERROR, "VaGrabSurface failed");  15 return -1;  16  }  17 return 0;  18 } else {  19 av_log(NULL, AV_LOG_ERROR, "No dxva2 context, get buffer failed");  20 return -1;  21  }  22 }  23  24 static void release_buffer(struct AVCodecContext *avctx, AVFrame *pic)  25 {  26 DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext *)avctx->priv_data;  27 dxva2_context *dxva2_ctx = &ctx->dxva2_ctx;  28 if (dxva2_ctx) {  29  av_release_dxva2_surface(dxva2_ctx, pic);  30  }  31 ctx->release_buffer(avctx,pic);  32 for (int i = 0; i < 4; i++)  33 pic->data[i] = NULL;  34 }  35  36 static enum PixelFormat get_format(AVCodecContext *p_context,  37 const enum PixelFormat *pi_fmt)  38 {  39 return AV_PIX_FMT_DXVA2_VLD;  40 }  41 static int check_format(AVCodecContext *avctx)  42 {  43 uint8_t *pout;  44 int psize;  45 int index;  46 H264Context *h;  47 int ret = -1;  48 AVCodecParserContext *parser = NULL;  49 /* check if support */  50 switch (avctx->codec_id) {  51 case AV_CODEC_ID_H264:  52 /* init parser & parse file */  53 parser = av_parser_init(avctx->codec->id);  54 if (!parser) {  55 av_log(avctx, AV_LOG_ERROR, "Failed to open parser.\n");  56 break;  57  }  58 parser->flags = PARSER_FLAG_COMPLETE_FRAMES;  59 index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0, 0);  60 if (index < 0) {  61 av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");  62  av_parser_close(parser);  63  }  64 h = parser->priv_data;  65 if (8 == h->sps.bit_depth_luma) {  66 if (!CHROMA444 && !CHROMA422) {  67 // only this will decoder switch to hwaccel  68  av_parser_close(parser);  69 ret = 0;  70 break;  71  }  72 } else {  73 av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");  74  av_parser_close(parser);  75 break;  76  }  77 break;  78 case AV_CODEC_ID_MPEG2VIDEO:  79 if (CHROMA_420 == get_mpeg2_video_format(avctx)) {  80 ret = 0;  81 break;  82 } else { 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值