Nvidias NVenc API와 관련된 한 가지 질문이 있습니다. API를 사용하여 일부 OpenGL 그래픽을 인코딩하려고합니다. 내 문제는 API가 전체 프로그램에서 오류를보고하지 않는다는 것입니다. 모든 것이 정상적인 것 같습니다. 그러나 생성 된 출력은 예를 들어. VLC. 생성 된 파일을 재생하려고하면 VLC가 약 0.5 초 동안 검은 색 화면을 깜박이고 재생이 끝납니다. 비디오의 길이는 0이며 Vid의 크기는 약간 작습니다. 해상도는 1280 * 720이며 5 초 녹음의 크기는 700kb에 불과합니다. 이게 현실적인가요?NVencs 출력 비트 스트림을 읽을 수 없습니다.
응용 프로그램의 흐름은 다음과 같습니다 :
- 렌더링이 PBOs 중 하나에 보조 프레임 버퍼
- 다운로드 프레임 버퍼에 (glReadPixels())
- 에 이전 프레임의 PBO지도 Cuda가 이해할 수있는 포인터를 얻는다.
- this (p.18)에 따라 NVenc에서 이해할 수있는 OpenGLs RGBA를 ARGB로 변환하는 간단한 CudaKernel을 호출하십시오. 커널은 PBO의 내용을 읽고 변환 된 내용을 CudaArray (cudaMalloc을 사용하여 생성됨)에 기록합니다.이 CudaArray는 NVenc와 함께 InputResource로 등록됩니다.
- 변환 된 배열의 내용이 인코딩됩니다. 완료 이벤트와 해당 출력 비트 스트림 버퍼가 대기열에 추가됩니다.
- 보조 스레드가 대기중인 출력 이벤트를 수신하면 하나의 이벤트가 신호를 보내면 출력 비트 스트림이 매핑되고 hdd에 기록됩니다.
NVenc 인코더의 initializion : CudaResource의
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
등록
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
모든 작은 힌트는 어디에서보아야하는지 매우 높이 평가됩니다. 나는 틀릴 수도있는 아이디어가 부족합니다.
고맙습니다.
RAW 비트 스트림을 처리 할 때 VLC의 일반적인 문제처럼 들리지만 VLC는 코덱에 알려지지 않은 경우 VLC에서 재생할 수 없습니다. 이렇게하려면 파일에 오른쪽 끝자리 (예 : h264 코덱의 경우 "filename.h264"입니다. – kunzmi
좋아, 그렇게하면 다음 결과를 얻습니다. [click] (https://s31.postimg.org/vvgbiqg0b/Encoded_File.png). – Christoph
일부 문제는 [교차 게시] (https://devtalk.nvidia.com/default/topic/953041/gpu-accelerated-libraries/nvencs-output-bitstream-is-not-readable)에 정리되어있는 것으로 보입니다. /). –