c++ - NVENC Nvidia Encoder D3D11 Wrong image dimension and other questions -
first few basic information:
os: win7 64bit | gpu: gtx970
i have staging id3d11texture2d wich encode.
i use texture directly via nvencregisterresource seems pass d3d9 , no d3d11 texture. otherwise nv_enc_err_unimplemented.
thefore, create input buffer , fill manually.
the texture in format dxgi_format_r8g8b8a8_unorm. format dxgi_format_nv12 possibly windows 8 onwards.
the input buffer format nv_enc_buffer_format_argb. should 8 bits per color channel. since alpha value interchanged expect wrong picture should still encoded.
my process far:
- create id3d11texture2d render texture
- create id3d11texture2d staging texture
- create nvenc input buffer nvenccreateinputbuffer
- create nvenc output buffer nvenccreatebitstreambuffer
:: update routine ::
- render render texture
- copyresource() staging texture
- fill nvenc input buffer staging texture
- encode frame
- get data nvenc output buffer
as can see, encode 1 frame per update.
so far works without error, if @ frame picture size wrong.
that should 1280 x 720. if try pass more 1 frame broken file.
i understand in h.264 first frame i-frame , following should p-frame.
now code:
:: create input buffer
nvencstatus rendermanager::createinputbuffer() { nvencstatus nvstatus = nv_enc_success; nv_enc_create_input_buffer createinputbufferparams = {}; createinputbufferparams.version = nv_enc_create_input_buffer_ver; createinputbufferparams.width = m_width; createinputbufferparams.height = m_height; createinputbufferparams.memoryheap = nv_enc_memory_heap_sysmem_cached; createinputbufferparams.bufferfmt = nv_enc_buffer_format_argb; nvstatus = m_pencodeapi->nvenccreateinputbuffer(m_pencoder, &createinputbufferparams); if (nvstatus != nv_enc_success) return nvstatus; m_pencoderinputbuffer = createinputbufferparams.inputbuffer; return nvstatus; }
:: create output buffer
nvencstatus rendermanager::createoutputbuffer() { nvencstatus nvstatus = nv_enc_success; nv_enc_create_bitstream_buffer createbitstreambufferparams = {}; createbitstreambufferparams.version = nv_enc_create_bitstream_buffer_ver; createbitstreambufferparams.size = 2 * 1024 * 1024; createbitstreambufferparams.memoryheap = nv_enc_memory_heap_sysmem_cached; nvstatus = m_pencodeapi->nvenccreatebitstreambuffer(m_pencoder, &createbitstreambufferparams); if (nvstatus != nv_enc_success) return nvstatus; m_pencoderoutputbuffer = createbitstreambufferparams.bitstreambuffer; return nvstatus; }
:: fill input buffer
nvencstatus rendermanager::writeinputbuffer(id3d11texture2d* ptexture) { nvencstatus nvstatus = nv_enc_success; hresult result = s_ok; // data staging texture d3d11_mapped_subresource mappedresource; result = m_pcontext->map(ptexture, 0, d3d11_map_read, 0, &mappedresource); if (failed(result)) return nv_enc_err_generic; m_pcontext->unmap(ptexture, 0); // lock input buffer nv_enc_lock_input_buffer lockinputbufferparams = {}; lockinputbufferparams.version = nv_enc_lock_input_buffer_ver; lockinputbufferparams.inputbuffer = m_pencoderinputbuffer; nvstatus = m_pencodeapi->nvenclockinputbuffer(m_pencoder, &lockinputbufferparams); if (nvstatus != nv_enc_success) return nvstatus; unsigned int pitch = lockinputbufferparams.pitch; //todo: convert r8g8b8a8 a8r8g8b8 // write buffer memcpy(lockinputbufferparams.bufferdataptr, mappedresource.pdata, m_height * mappedresource.rowpitch); // unlock input buffer nvstatus = m_pencodeapi->nvencunlockinputbuffer(m_pencoder, m_pencoderinputbuffer); return nvstatus; }
:: encode frame
nvencstatus rendermanager::encodeframe() { nvencstatus nvstatus = nv_enc_success; int8_t* qpdeltamaparray = null; unsigned int qpdeltamaparraysize = 0; nv_enc_pic_params encpicparams = {}; encpicparams.version = nv_enc_pic_params_ver; encpicparams.inputwidth = m_width; encpicparams.inputheight = m_height; encpicparams.inputbuffer = m_pencoderinputbuffer; encpicparams.outputbitstream = m_pencoderoutputbuffer; encpicparams.bufferfmt = nv_enc_buffer_format_argb; encpicparams.picturestruct = nv_enc_pic_struct_frame; encpicparams.qpdeltamap = qpdeltamaparray; encpicparams.qpdeltamapsize = qpdeltamaparraysize; nvstatus = m_pencodeapi->nvencencodepicture(m_pencoder, &encpicparams); return nvstatus; }
:: read output buffer
nvencstatus rendermanager::readoutputbuffer() { nvencstatus nvstatus = nv_enc_success; // lock output buffer nv_enc_lock_bitstream lockbitstreambufferparams = {}; lockbitstreambufferparams.version = nv_enc_lock_bitstream_ver; lockbitstreambufferparams.donotwait = 0; lockbitstreambufferparams.outputbitstream = m_pencoderoutputbuffer; nvstatus = m_pencodeapi->nvenclockbitstream(m_pencoder, &lockbitstreambufferparams); if (nvstatus != nv_enc_success) return nvstatus; void* pdata = lockbitstreambufferparams.bitstreambufferptr; unsigned int size = lockbitstreambufferparams.bitstreamsizeinbytes; // read buffer platformmanager::savetofile("test", static_cast<char*>(pdata), size); // unlock output buffer nvstatus = m_pencodeapi->nvencunlockbitstream(m_pencoder, m_pencoderoutputbuffer); return nvstatus; }
m_width , m_height 1280 , 720.
why image size wrong , how have fill input buffer more 1 frame ?
many help,
alexander
Comments
Post a Comment