Windows下基于NVIDIA SDK的C++异步HEVC编码:DXGI纹理输出到stdout
配置NVENC编码会话对接DXGI帧并输出到stdout
核心流程步骤
从DXGI捕获帧到输出HEVC码流到stdout的核心链路:初始化NVENC上下文→创建与DXGI纹理兼容的输入表面→配置异步编码参数→阻塞式获取编码结果→输出到stdout。
1. 初始化NVENC编码会话
首先初始化编码器参数,指定HEVC编码格式、开启异步模式,并关联DXGI对应的D3D11设备(避免跨GPU内存拷贝):
NV_ENC_INITIALIZE_PARAMS initParams = { NV_ENC_INITIALIZE_PARAMS_VER }; initParams.encodeGUID = NV_ENC_CODEC_HEVC_GUID; initParams.presetGUID = NV_ENC_PRESET_P7_GUID; // 按需选择预设(P7是质量优先,P1是速度优先) initParams.enableAsyncEncoding = true; initParams.d3d11Device = yourD3D11Device; // 从DXGI资源关联的D3D设备获取 initParams.width = captureWidth; // 匹配DXGI捕获的分辨率 initParams.height = captureHeight; initParams.frameRateNum = 60; // 按需设置帧率 initParams.frameRateDen = 1; initParams.bitrate = 8000000; // 目标比特率,单位bps // 初始化编码器 nvEncInitializeEncoder(encoderHandle, &initParams);
2. 注册DXGI纹理为NVENC输入资源
将捕获到的IDXGIResource转成ID3D11Texture2D,直接注册为NVENC的输入资源(无需拷贝GPU内存):
ID3D11Texture2D* dxgiTexture = nullptr; yourCapturedDxgiResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&dxgiTexture); NV_ENC_CREATE_INPUT_RESOURCE inputResParams = { NV_ENC_CREATE_INPUT_RESOURCE_VER }; inputResParams.width = captureWidth; inputResParams.height = captureHeight; inputResParams.format = NV_ENC_BUFFER_FORMAT_ABGR; // 匹配DXGI常用的B8G8R8A8_UNORM格式 inputResParams.resourceToRegister = dxgiTexture; // 创建NVENC输入资源句柄 nvEncCreateInputResource(encoderHandle, &inputResParams, &nvencInputResHandle);
3. 配置异步编码参数
设置异步编码标记,指定待编码的输入资源:
NV_ENC_ENCODE_PIC_PARAMS encodeParams = { NV_ENC_ENCODE_PIC_PARAMS_VER }; encodeParams.inputResource = nvencInputResHandle; encodeParams.asyncEncode = true; encodeParams.picType = NV_ENC_PIC_TYPE_AUTO; // 让编码器自动判断I/P帧 encodeParams.inputTimeStamp = frameTimestamp; // 按需设置时间戳,用于码流同步
4. 阻塞获取编码结果并输出到stdout
调用编码接口后,阻塞等待编码完成,直接将NAL单元写入stdout:
// 发起异步编码请求(非阻塞,但后续lock会等待完成) nvEncEncodePicture(encoderHandle, &encodeParams); NV_ENC_LOCK_BITSTREAM lockParams = { NV_ENC_LOCK_BITSTREAM_VER }; // 阻塞等待编码完成,获取压缩后的比特流 nvEncLockBitstream(encoderHandle, &lockParams); // 直接输出到stdout,实时推送给父进程 fwrite(lockParams.bitstreamBufferPtr, 1, lockParams.bitstreamSize, stdout); fflush(stdout); // 强制刷新缓冲区,避免父进程延迟接收 // 解锁比特流,释放编码器资源 nvEncUnlockBitstream(encoderHandle, &lockParams);
关键注意事项
- 资源生命周期:编码完成前不要释放DXGI纹理,NVENC会直接访问GPU内存中的帧数据。
- 格式匹配:必须保证DXGI纹理的像素格式、分辨率与NVENC输入资源完全一致,否则会触发编码错误。
- 线程安全:如果多线程处理帧,需为每个线程创建独立的NVENC编码器实例,避免并发调用冲突。
- 缓冲区处理:输出到stdout后必须调用
fflush,否则数据会暂存在用户态缓冲区,导致Go主进程无法实时接收。
内容的提问来源于stack exchange,提问作者Tiger Yang
相关产品推荐
相关产品推荐

