Ich habe eine Frage im Zusammenhang mit Nvidias NVenc API. Ich möchte die API verwenden, um einige OpenGL-Grafiken zu kodieren. Mein Problem ist, dass die API während des gesamten Programms keinen Fehler meldet, alles scheint in Ordnung zu sein. Die erzeugte Ausgabe ist jedoch z. B. nicht lesbar. VLC. Wenn ich versuche, die generierte Datei abzuspielen, würde VLC für etwa 0,5 Sekunden einen schwarzen Bildschirm blinken lassen und dann die Wiedergabe beenden. Das Video hat die Länge 0, die Größe des Vid scheint auch ziemlich klein zu sein. Auflösung ist 1280 * 720 und die Größe von 5 Sekunden Aufnahme ist nur 700kb. Ist das realistisch?NVencs Output Bitstream ist nicht lesbar
Der Ablauf der Anwendung ist wie folgt:
- Render zur sekundären Framebuffer
- Herunterladen Framebuffer zu einem von zwei PBOs (glReadPixels())
- die PBO des vorherigen Rahmens Karte, zu einen Zeiger von Cuda verstehen lassen.
- Rufen Sie einen einfachen CudaKernel, der OpenGLs RGBA in ARGB konvertiert, was von NVenc gemäß this (S.18) verständlich sein sollte. Der Kernel liest den Inhalt des PBO und schreibt den konvertierten Inhalt in ein CudaArray (erstellt mit cudaMalloc), das als InputResource mit NVenc registriert ist.
- Der Inhalt des konvertierten Arrays wird codiert. Ein Abschlussereignis und der entsprechende Ausgabe-Bitstream-Puffer werden in die Warteschlange gestellt.
- Ein sekundärer Thread überwacht die Ereignisse in der Warteschlange, wenn ein Ereignis signalisiert wird, wird der Ausgabe-Bitstream zugeordnet und auf die Festplatte geschrieben.
Die initializion von 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
Registrierung von 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);
Encoding
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
Jeder kleine Hinweis, wo zu sehen ist, wird sehr geschätzt. Mir gehen die Ideen aus, was falsch sein könnte.
Vielen Dank!
Sie geben nicht viele Details, aber klingt wie ein allgemeines Problem für VLC im Umgang mit RAW Bitstreams: VLC kann sie nicht wiedergeben, wenn es nicht den Codec mitgeteilt wird. Versuchen Sie dazu, der Datei das richtige Ende zu geben, z. "Dateiname.h264" für h264-Codec. – kunzmi
Okay, wenn ich das mache, bekomme ich folgendes Ergebnis: [click] (https://s31.postimg.org/vvgbiqg0b/Encoded_File.png). – Christoph
Es scheint, dass einige Probleme im [Cross-Posting] (https://devtalk.nvidia.com/default/topic/953041/gpu-accelerated-libraries/nvencs-output-bitstream-is-not-readable) behoben wurden /). –