NVIDIA Video Codec SDK编解码

发布于:2025-05-09 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、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;
}

代码说明

  1. 初始化阶段:

    • 初始化CUDA上下文

    • 创建视频解析器并设置回调函数

  2. 回调函数:

    • HandleVideoSequence: 检测到新视频序列时调用

    • HandlePictureDecode: 解码前调用

    • HandlePictureDisplay: 解码后调用,处理帧数据

  3. 解码流程:

    • 读取输入视频文件

    • 将数据包发送给解析器

    • 解析器自动触发解码流程

  4. 资源清理:

    • 销毁解析器

    • 销毁CUDA上下文

编译说明

编译此代码需要:

  • NVIDIA CUDA Toolkit

  • NVIDIA Video Codec SDK

  • 链接nvcuvid


网站公告

今日签到

点亮在社区的每一天
去签到