gpt4 book ai didi

c++ - NVencs 输出比特流不可读

转载 作者:行者123 更新时间:2023-11-28 02:02:54 32 4
gpt4 key购买 nike

我有一个与 Nvidias NVenc API 相关的问题。我想使用 API 对一些 OpenGL 图形进行编码。我的问题是,API 在整个程序中没有报告任何错误,一切似乎都很好。但是生成的输出不可读,例如可见光通信。如果我尝试播放生成的文件,VLC 会闪烁大约 0.5 秒的黑屏,然后结束播放。Video 的长度为 0,Vid 的大小似乎也很小。分辨率为1280*720,5秒录像大小仅为700kb。这现实吗?

申请流程如下:

  1. 渲染到辅助帧缓冲区
  2. 将帧缓冲区下载到两个 PBO 之一 (glReadPixels())
  3. 映射前一帧的 PBO,以获得 Cuda 可以理解的指针。
  4. 调用一个简单的 CudaKernel 将 OpenGLs RGBA 转换为 ARGB,根据 this,NVenc 应该可以理解它(第 18 页)。内核读取 PBO 的内容并将转换后的内容写入 CudaArray(使用 cudaMalloc 创建),该数组在 NVenc 中注册为 InputResource。
  5. 转换数组的内容被编码。完成事件加上相应的输出比特流缓冲区排队。
  6. 辅助线程监听排队的输出事件,如果发出一个事件信号,输出比特流将被映射并写入硬盘。

NVenc-Encoder的初始化:

InitParams* ip = new InitParams();
m_initParams = ip;
memset(ip, 0, sizeof(InitParams));
ip->version = NV_ENC_INITIALIZE_PARAMS_VER;
ip->encodeGUID = m_encoderGuid; //Used Codec
ip->encodeWidth = width; // Frame Width
ip->encodeHeight = height; // Frame Height
ip->maxEncodeWidth = 0; // Zero means no dynamic res changes
ip->maxEncodeHeight = 0;
ip->darWidth = width; // Aspect Ratio
ip->darHeight = height;
ip->frameRateNum = 60; // 60 fps
ip->frameRateDen = 1;
ip->reportSliceOffsets = 0; // According to programming guide
ip->enableSubFrameWrite = 0;
ip->presetGUID = m_presetGuid; // Used Preset for Encoder Config

NV_ENC_PRESET_CONFIG presetCfg; // Load the Preset Config
memset(&presetCfg, 0, sizeof(NV_ENC_PRESET_CONFIG));
presetCfg.version = NV_ENC_PRESET_CONFIG_VER;
presetCfg.presetCfg.version = NV_ENC_CONFIG_VER;
CheckApiError(m_apiFunctions.nvEncGetEncodePresetConfig(m_Encoder,
m_encoderGuid, m_presetGuid, &presetCfg));
memcpy(&m_encodingConfig, &presetCfg.presetCfg, sizeof(NV_ENC_CONFIG));
// And add information about Bitrate etc
m_encodingConfig.rcParams.averageBitRate = 500000;
m_encodingConfig.rcParams.maxBitRate = 600000;
m_encodingConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_CBR;
ip->encodeConfig = &m_encodingConfig;
ip->enableEncodeAsync = 1; // Async Encoding
ip->enablePTD = 1; // Encoder handles picture ordering

CudaResource的注册

m_cuContext->SetCurrent(); // Make the clients cuCtx current
NV_ENC_REGISTER_RESOURCE res;
memset(&res, 0, sizeof(NV_ENC_REGISTER_RESOURCE));
NV_ENC_REGISTERED_PTR resPtr; // handle to the cuda resource for future use
res.bufferFormat = m_inputFormat; // Format is ARGB
res.height = m_height;
res.width = m_width;
// NOTE: I've set the pitch to the width of the frame, because the resource is a non-pitched
//cudaArray. Is this correct? Pitch = 0 would produce no output.
res.pitch = pitch;
res.resourceToRegister = (void*) (uintptr_t) resourceToRegister; //CUdevptr to resource
res.resourceType =
NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR;
res.version = NV_ENC_REGISTER_RESOURCE_VER;
CheckApiError(m_apiFunctions.nvEncRegisterResource(m_Encoder, &res));
m_registeredInputResources.push_back(res.registeredResource);

编码

m_cuContext->SetCurrent(); // Make Clients context current
MapInputResource(id); //Map the CudaInputResource
NV_ENC_PIC_PARAMS temp;
memset(&temp, 0, sizeof(NV_ENC_PIC_PARAMS));
temp.version = NV_ENC_PIC_PARAMS_VER;
unsigned int currentBufferAndEvent = m_counter % m_registeredEvents.size(); //Counter is inc'ed in every Frame
temp.bufferFmt = m_currentlyMappedInputBuffer.mappedBufferFmt;
temp.inputBuffer = m_currentlyMappedInputBuffer.mappedResource; //got set by MapInputResource
temp.completionEvent = m_registeredEvents[currentBufferAndEvent];
temp.outputBitstream = m_registeredOutputBuffers[currentBufferAndEvent];
temp.inputWidth = m_width;
temp.inputHeight = m_height;
temp.inputPitch = m_width;
temp.inputTimeStamp = m_counter;
temp.pictureStruct = NV_ENC_PIC_STRUCT_FRAME; // According to samples
temp.qpDeltaMap = NULL;
temp.qpDeltaMapSize = 0;

EventWithId latestEvent(currentBufferAndEvent,
m_registeredEvents[currentBufferAndEvent]);
PushBackEncodeEvent(latestEvent); // Store the Event with its ID in a Queue

CheckApiError(m_apiFunctions.nvEncEncodePicture(m_Encoder, &temp));
m_counter++;
UnmapInputResource(id); // Unmap

非常感谢每一个小提示,在哪里看。我想不出可能出了什么问题。

非常感谢!

最佳答案

hall822的帮助下从 nvidia 论坛我设法解决了这个问题。

主要错误是我注册了我的 cuda 资源,间距等于帧的大小。我正在使用 Framebuffer-Renderbuffer 来绘制我的内容。其数据是一个普通的、未倾斜的数组。我的第一个想法是将音高设置为零,但失败了。编码器什么也没做。下一个想法是将它设置为框架的宽度,四分之一的图像被编码。

// NOTE: I've set the pitch to the width of the frame, because the resource is a non-pitched 
//cudaArray. Is this correct? Pitch = 0 would produce no output.
res.pitch = pitch;

回答这个问题:是的,它是正确的。但是音高是以字节为单位的。所以因为我正在编码 RGBA 帧,所以正确的间距必须是 FRAME_WIDTH * 4

第二个错误是我的颜色 channel 不正确(参见我开篇文章中的第 4 点)。 NVidia 枚举表示编码器需要 ARGB 格式的 channel ,但实际上是 BGRA,因此始终为 255 的 alpha channel 污染了蓝色 channel 。

编辑:这可能是因为 NVidia 在内部使用小端。我在写我的像素数据转换为字节数组,选择其他类型(如 int32)可能允许传递实际的 ARGB 数据。

关于c++ - NVencs 输出比特流不可读,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38658129/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com