一、NVIDIA Video Codec SDK 完整视频解码
以下是一个使用NVIDIA Video Codec SDK进行硬件加速视频解码的完整C++示例代码,包含初始化解码器、解析视频数据和帧处理等完整流程。
#include <iostream>
#include <fstream>
#include <vector>
#include <cuda.h>
#include <nvcuvid.h>
// 错误检查宏
#define CHECK_CUDA(call) \
do { \
CUresult err = call; \
if (err != CUDA_SUCCESS) { \
const char* errStr; \
cuGetErrorString(err, &errStr); \
std::cerr << "CUDA error at " << __FILE__ << ":" << __LINE__ << ": " << errStr << std::endl; \
exit(1); \
} \
} while(0)
#define CHECK_CUVID(call) \
do { \
CUresult err = call; \
if (err != CUDA_SUCCESS) { \
std::cerr << "CUVID error at " << __FILE__ << ":" << __LINE__ << std::endl; \
exit(1); \
} \
} while(0)
// 解码器回调函数
int CUDAAPI HandleVideoSequence(void* pUserData, CUVIDEOFORMAT* pFormat)
{
std::cout << "Video sequence detected: "
<< pFormat->coded_width << "x" << pFormat->coded_height
<< ", codec: " << pFormat->codec
<< std::endl;
return 1;
}
int CUDAAPI HandlePictureDecode(void* pUserData, CUVIDPICPARAMS* pPicParams)
{
// 这里可以添加解码前的处理逻辑
return 1;
}
int CUDAAPI HandlePictureDisplay(void* pUserData, CUVIDPARSERDISPINFO* pDispInfo)
{
// 这里处理解码后的帧数据
CUVIDPROCPARAMS videoProcessingParameters = {};
videoProcessingParameters.progressive_frame = pDispInfo->progressive_frame;
videoProcessingParameters.second_field = pDispInfo->repeat_first_field + 1;
videoProcessingParameters.top_field_first = pDispInfo->top_field_first;
videoProcessingParameters.unpaired_field = pDispInfo->repeat_first_field < 0;
CUdeviceptr pDecodedFrame = 0;
unsigned int nDecodedPitch = 0;
CHECK_CUVID(cuvidMapVideoFrame(reinterpret_cast<CUvideodecoder>(pUserData),
pDispInfo->picture_index,
&pDecodedFrame,
&nDecodedPitch,
&videoProcessingParameters));
// 这里可以处理解码后的帧数据(pDecodedFrame)
std::cout << "Decoded frame: " << pDispInfo->picture_index
<< ", pitch: " << nDecodedPitch << std::endl;
CHECK_CUVID(cuvidUnmapVideoFrame(reinterpret_cast<CUvideodecoder>(pUserData), pDecodedFrame));
return 1;
}
int main(int argc, char* argv[])
{
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <input.h264>" << std::endl;
return 1;
}
const char* inputFile = argv[1];
// 初始化CUDA
CHECK_CUDA(cuInit(0));
CUcontext cuContext;
CHECK_CUDA(cuCtxCreate(&cuContext, 0, 0));
// 初始化视频解析器
CUVIDPARSERPARAMS videoParserParameters = {};
videoParserParameters.CodecType = cudaVideoCodec_H264;
videoParserParameters.ulMaxNumDecodeSurfaces = 1;
videoParserParameters.ulMaxDisplayDelay = 0;
videoParserParameters.pUserData = nullptr;
videoParserParameters.pfnSequenceCallback = HandleVideoSequence;
videoParserParameters.pfnDecodePicture = HandlePictureDecode;
videoParserParameters.pfnDisplayPicture = HandlePictureDisplay;
CUvideoparser videoParser;
CHECK_CUVID(cuvidCreateVideoParser(&videoParser, &videoParserParameters));
// 读取输入文件
std::ifstream file(inputFile, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
std::cerr << "Failed to open input file: " << inputFile << std::endl;
return 1;
}
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
if (!file.read(buffer.data(), size)) {
std::cerr << "Failed to read input file" << std::endl;
return 1;
}
file.close();
// 解析视频数据
CUVIDSOURCEDATAPACKET packet = {};
packet.payload = reinterpret_cast<const unsigned char*>(buffer.data());
packet.payload_size = static_cast<unsigned long>(size);
packet.flags = CUVID_PKT_ENDOFSTREAM;
CHECK_CUVID(cuvidParseVideoData(videoParser, &packet));
// 清理资源
CHECK_CUVID(cuvidDestroyVideoParser(videoParser));
CHECK_CUDA(cuCtxDestroy(cuContext));
std::cout << "Video decoding completed successfully!" << std::endl;
return 0;
}
代码说明
初始化阶段:
初始化CUDA上下文
创建视频解析器并设置回调函数
回调函数:
HandleVideoSequence
: 检测到新视频序列时调用HandlePictureDecode
: 解码前调用HandlePictureDisplay
: 解码后调用,处理帧数据
解码流程:
读取输入视频文件
将数据包发送给解析器
解析器自动触发解码流程
资源清理:
销毁解析器
销毁CUDA上下文
编译说明
编译此代码需要:
NVIDIA CUDA Toolkit
NVIDIA Video Codec SDK
链接
nvcuvid
库