【视频开发】Nvidia硬解码总结
Nvidia硬解码总结
1.前言
本文的主要目的是对近期进行的nvidia硬件解码工作的记录和总结。至于为什么研究nvidia硬件解码的具体内容,其实主要是为了在项目中能够利用nvidia的硬件解码和编码能力,提高单机的编解码并行能力。截止当前,nvidia的硬件编码官方提供了nvenc的方法,且在ffmpeg中已经增加了对nvenc的编码库。对于硬件解码,官方提供了基于cuda的解码方法,但是ffmpeg中还没有相应的解码库。所以,我的目的就是调研一下这个硬解方案,并将其自定义增加到ffmpeg中。
官方提供的资料比较少,只包括一页的视频解码器介绍和示例代码。
吐槽一下:官网那个一页的介绍参考量真不大,主要还是参考例程代码。
2.例程介绍
官网提供的例程代码解压后如下图所示,因为是调用解码,所以主要参考了"NvDecodeD3D9"和"NvTranscoder"的代码。
总的来说,nvidia提供了source, parser, decoder三个基本模块。其中source是用来解析视频文件(例如:纯h.264文件),parser是用来解析视频并得到一帧帧的数据,decoder就是解码了。
这三个模块相辅相成,其主要操作流程如上图所示。source模块输出h264数据,parser解析这些h264数据,并通过3个重要的回调函数(pfnSequenceCallback, pfnDecodePicture, pfnDisplayPicture)完成解码及输出功能。其中,pfnSequenceCallback是parser解析到序列及图像参数信息时的回调函数,其传入的参数是parser解析好的视频参数,可以用于初始化解码器或重置解码器。pfnDecodePicture是parser解析到视频编码数据后的回调函数,其传入的参数parser处理好待解码的视频编码数据,需要在该函数中调用decoder的接口进行解码操作。pfnDisplayPicture是parser对解码后的数据处理的回调函数,可以在该回调中对已解码的数据进行获取(从显存到系统内存)并处理。
3.主要接口说明
cuvidCreateVideoSource : 该接口的作用是创建source,主要参数是设置视频文件路径和回调函数。source会去解析指定视频文件,并通过回调函数实现对视频数据的自定义处理。源码中在视频数据回调函数中,调用了cuvidParseVideoData,即向parser中传递数据。
//init video source
CUVIDSOURCEPARAMS oVideoSourceParameters;
memset(&oVideoSourceParameters, 0, sizeof(CUVIDSOURCEPARAMS));
oVideoSourceParameters.pUserData = this;
oVideoSourceParameters.pfnVideoDataHandler = HandleVideoData;
oVideoSourceParameters.pfnAudioDataHandler = NULL;
oResult = cuvidCreateVideoSource(&m_videoSource, videoPath, &oVideoSourceParameters);
if (oResult != CUDA_SUCCESS) {
fprintf(stderr, "cuvidCreateVideoSource failed\n");
fprintf(stderr, "Please check if the path exists, or the video is a valid H264 file\n");
exit(-1);
}
cuvidCreateVideoParser : 该接口是用来创建video parser,主要参数是设置三个回调函数,实现对解析出来的数据的处理。
//init video parser
CUVIDPARSERPARAMS oVideoParserParameters;
memset(&oVideoParserParameters, 0, sizeof(CUVIDPARSERPARAMS));
oVideoParserParameters.CodecType = oVideoDecodeCreateInfo.CodecType;
oVideoParserParameters.ulMaxNumDecodeSurfaces = oVideoDecodeCreateInfo.ulNumDecodeSurfaces;
oVideoParserParameters.ulMaxDisplayDelay = 1;
oVideoParserParameters.pUserData = this;
oVideoParserParameters.pfnSequenceCallback = HandleVideoSequence;
oVideoParserParameters.pfnDecodePicture = HandlePictureDecode;
oVideoParserParameters.pfnDisplayPicture = HandlePictureDisplay;
oResult = cuvidCreateVideoParser(&m_videoParser, &oVideoParserParameters);
if (oResult != CUDA_SUCCESS) {
fprintf(stderr, "cuvidCreateVideoParser failed, error code: %d\n", oResult);
exit(-1);
}
cuvidParseVideoData : 该接口是用来向parser塞数据,通过不断地塞h.264数据,parser会通过回调接口对解析出来的数据进行处理。在例程中,cuvidParseVideoData是在source的pfnVideoDataHandler回调中被使用的,即source获取到视频数据,就将其传递给parser。
// the callback of source pfnVideoDataHandler
static int CUDAAPI HandleVideoData(void* pUserData, CUVIDSOURCEDATAPACKET* pPacket)
{
assert(pUserData);
CudaDecoder* pDecoder = (CudaDecoder*)pUserData;
CUresult oResult = cuvidParseVideoData(pDecoder->m_videoParser, pPacket);
if(oResult != CUDA_SUCCESS) {
printf("error!\n");
}
return 1;
}
cuvidCreateDecoder : 该接口是用来创建decoder,通过设置一些解码参数,会返回一个decoder的句柄。这个句柄会在之后的解码接口中被使用。该接口的具体使用方法在例程中有详细的参数设置,这里就繁琐地描述了。
cuvidDecodePicture : 该接口就是向解码器传递待解码的数据。需要说明一下,该接口是异步解码,不能通过该接口得到解码后的视频数据,它只是向解码器传数据而已。解码后的数据,是通过parser的pfnDisplayPicture回调得到。
4.技术点说明
库的使用
nvidia解码需要使用cuda和nvcuvid两个库(在linux中是libcuda.so和libnvcuvid.so),使用的时候要加载它们,并使用其中一些接口。主要使用到的接口主要有:
cuInit
cuDeviceGetCount
cuDeviceGet
cuDeviceGetName
cuDeviceComputeCapability
cuCtxCreate
cuCtxPushCurrent
cuCtxPopCurrent
cuCtxDestroy
cuMemAllocHost
cuMemFreeHost
cuStreamCreate
cuStreamDestroy
cuMemcpyDtoHAsync
cuvidCreateDecoder
cuvidDestroyDecoder
cuvidDecodePicture
cuvidCtxLockCreate
cuvidCtxLockDestroy
cuvidCtxLock
cuvidCtxUnlock
cuvidMapVideoFrame
cuvidUnmapVideoFrame
cuvidCreateVideoParser
cuvidParseVideoData
cuvidDestroyVideoParser
注意:根据库的版本不同,接口有的需要使用v2版本。例如:cuCtxCreate和cuCtxCreate_v2。
device内存和system内存
使用nvidia进行硬件解码需要了解一下device内存(可以叫显存或设备内存)和系统内存的数据处理方法。在解码完成后,视频YUV数据是在device内存中的,所以需要使用nvidia提供的接口把数据弄出来。涉及的接口主要有:cuMemAllocHost, cuMemFreeHost, cuvidMapVideoFrame, cuvidUnmapVideoFrame, cuMemcpyDtoHAsync。其中,cuMemAllocHost是用来创建系统及显卡都可访问的系统内存。cuvidMapVideoFrame可以获取到设备内存中指定的YUV数据地址。最后通过cuMemcpyDtoHAsync将设备内存中指定的数据copy到系统内存中。
【视频开发】Nvidia硬解码总结的更多相关文章
- 【miscellaneous】硬解码与软解码
在显卡技术日益成熟的今天,一些概念我们都不是很清楚了,那么显卡硬件解码功能是什么意思呢?高清硬解和软件有什么不同呢?显卡配置需不需要考虑硬件解码呢?电脑爱好者为您分析. 什么是硬件解码? 显卡硬件解码 ...
- 基于FFmpeg的Dxva2硬解码及Direct3D显示(四)
初始化硬解码上下文 目录 初始化硬解码上下文 创建解码数据缓冲区 创建IDirectXVideoDecoder视频解码器 设置硬解码上下文 解码回调函数 创建解码数据缓冲区 这一步为了得到 LPDIR ...
- 【Android 直播软件开发:音视频硬解码篇】
开篇 炙手可热,望而生畏的音视频开发 时至今日,短视频App可谓是如日中天,一片兴兴向荣.随着短视频的兴起,音视频开发也越来越受到重视,但是由于音视频开发涉及知识面比较广,入门门槛相对较高,让许许多多 ...
- 【视频开发】GPU编解码:GPU硬解码---DXVA
GPU编解码:GPU硬解码---DXVA 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解码可分四级:VLD,控制BitStream;IDCT,反 ...
- Android 用MediaCodec实现视频硬解码
http://blog.csdn.net/halleyzhang3/article/details/11473961 http://www.360doc.com/content/14/0119/10/ ...
- 【计算机视觉】【并行计算与CUDA开发】GPU硬解码---DXVA
前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...
- WPF 视频硬解码渲染播放(无空域)(支持4K、8K、高帧率视频)
MediaWPF 基于 .NET 6 实现视频硬解码渲染Demo(无空域问题) 代码实现仅供学习参考 本项目视频渲染通过显卡进行视频解码,CPU几乎不参与工作,并且不存在令人烦躁的空域问题. 在播放摄 ...
- Android 用MediaCodec实现视频硬解码(转)
本文向你讲述如何用android标准的API (MediaCodec)实现视频的硬件编解码.例程将从摄像头采集视频开始,然后进行H264编码,再解码,然后显示.我将尽量讲得简短而清晰,不展示 那些不相 ...
- MediaCodec在Android视频硬解码组件的应用
https://yq.aliyun.com/articles/632892 云栖社区> 博客列表> 正文 MediaCodec在Android视频硬解码组件的应用 cheenc 201 ...
随机推荐
- numpy函数库中一些常用函数的记录
##numpy函数库中一些常用函数的记录 最近才开始接触Python,python中为我们提供了大量的库,不太熟悉,因此在<机器学习实战>的学习中,对遇到的一些函数的用法进行记录. (1) ...
- Mybatis框架-resultMap元素的自动映射级别
resultMap的自动映射级别:分为三种:NONE PARTIAL FULL 其中默认的属性是:PARTIAL:开启自动匹配,会自动匹配数据库中的字段名和实体类中的属性名,如果一致,就能匹配上, ...
- 03-Flutter移动电商实战-底部导航栏制作
1.cupertino_IOS风格介绍 在Flutter里是有两种内置风格的: material风格: Material Design 是由 Google 推出的全新设计语言,这种设计语言是为手机.平 ...
- Redis存储Set
与List不同Set不能存储相同元素,且数据没有顺序. 存储结构: 1.存储与查看数据: 2.删除指定的一个元素: 3.判断是否存在某一个元素(存在返回1,不存在返回0): 4.判断两个set中的特有 ...
- Java基础教程--安卓入门教程(七)
关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 欢迎大家关注我的微信公众号:「醉翁猫咪」 什么是接口? 接口的基本语法 接口的基本语法(一) 使用interface定义 接口当中 ...
- 02-线性结构3 Reversing Linked List (25 分)
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elem ...
- SQL语句操作数据试题
1.在SQL Server中,下列关于数据完整性的说法错误的是(). (选择一项) A:实体完整性要求表中的每一行数据都反映不同的试题,不能存在相同的数据行 B:域完整性是只给定列的输入有效性 C:在 ...
- mysql 遍历所有表并条件查询
use eepm_push; DROP PROCEDURE IF EXISTS FountTable; delimiter $$ create procedure FountTable() begin ...
- Linux 上配置 SQL Server Always On Availability Group
SQL Server Always On Availability Group 配置步骤:配置三台 Linux 集群节点创建 Availability Group配置 Cluster Resource ...
- ckplayer去掉/修改右上角logo(位置)
ckplayer.js中搜索:logo(ckplayer.xml中搜索<logo>) 1:去掉的方法是修改成logo:'null'(ckplayer.xml中修改成<logo> ...