GPU硬解码---DXVA
来源:互联网 发布:正确看待网络新一代 编辑:程序博客网 时间:2024/04/29 04:39
一、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; /* 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, 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) { // only this will decoder switch to hwaccel 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; /* release buffers and decoder */ av_release_dxva2(&ctx->dxva2_ctx); /* close decoder */ 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; /* init pix_fmts of codec */ if (!(hwcodec->pix_fmts)) { hwcodec->pix_fmts = dxva2_pixfmts; } /* check if DXVA2 supports this file */ if (check_format(avctx) < 0) goto failed; /* init vda */ 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; } /* 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 < 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- GPU硬解码---DXVA
- 【视频开发】GPU编解码:GPU硬解码---DXVA
- 【计算机视觉】【并行计算与CUDA开发】GPU硬解码---DXVA
- GPU硬解码---CUVID
- GPU编解码 - 硬编码
- GPU编解码 - 硬解码---CUVID
- GPU编解码 - 硬解码 - CUVID
- 高清视频相关知识和、KMPlayer 硬解码(DXVA)设置、Z520+US15W+GMA500硬解码测试
- 树莓派 FFmpeg 支持GPU硬解码
- 树莓派 FFmpeg 支持GPU硬解码
- 打开DXVA(显卡硬解码H.264与VC-1)已如此简单
- DXVA硬件加速解码
- DXVA硬件加速解码
- 使用ffmpeg dxva技术解码
- 使用ffmpeg dxva技术解码
- Dxva
- 硬解码软解码
- 硬解码软解码
- 反渗透设备:反渗透设备应用范围
- 海量数据面试题----分而治之/hash映射 + hash统计 + 堆/快速/归并排序
- 3.12
- 二叉树的镜像
- Android中的多选列表项对话框的一个细节问题
- GPU硬解码---DXVA
- POJ 3592 Instantaneous Transference(建图强连通+单源最长路)
- Android应用程序开发以及背后的设计思想深度剖析(5)
- Sencha Touch学习笔记(六)设备配置
- 类的知识点的归纳绘图
- Oracle ORA-01033: ORACLE initialization or shutdown in progress 错误解决办法
- Spring2+struts2+ibatis整合
- 解决ECShop首页缩略图和产品页图片模糊方法
- JFreeChart的使用