NVENC Nvidia Encoder D3D11 Неправильный размер изображения и другие вопросы

Сначала несколько основных сведений:

ОС: Win7 64Bit | GPU: GTX970

У меня есть постановка ID3D11Texture2D, которую я хотел бы кодировать.

Я хотел бы использовать текстуру напрямую через nvEncRegisterResource но кажется, что я мог передать только D3D9 и без текстуры D3D11. В противном случае я получаю NV_ENC_ERR_UNIMPLEMENTED.

Выше я создаю входной буфер и заполняю его вручную.

Текстура в формате DXGI_FORMAT_R8G8B8A8_UNORM. Формат DXGI_FORMAT_NV12 возможно только с Windows 8 года.

Формат входного буфера NV_ENC_BUFFER_FORMAT_ARGB. Это также должно быть 8 бит на цветовой канал. Поскольку альфа-значение взаимозаменяемо, я ожидаю неправильное изображение, но оно все равно должно быть закодировано.

Мой процесс до сих пор:

  • Создать ID3D11Texture2D рендер текстуры
  • Создайте промежуточную текстуру ID3D11Texture2D
  • Создать входной буфер NVENC с помощью nvEncCreateInputBuffer
  • Создать выходной буфер NVENC с помощью nvEncCreateBitstreamBuffer

:: Обновление рутины ::

  • Визуализация в визуализации текстуры
  • CopyResource () для создания текстуры
  • Заполнить входной буфер NVENC от промежуточной текстуры
  • Кодировать кадр
  • Получить данные из выходного буфера NVENC

Как видите, я кодирую только один кадр на обновление.

Пока все работает без ошибок, но если я посмотрю на кадр, размер изображения будет неправильным.

введите описание изображения здесь

Это должно быть 1280 x 720. Если я также пытаюсь пропустить более одного кадра, я получаю поврежденный файл.

Я понимаю, что в H.264 мой первый кадр — это I-кадр, а следующий должен быть P-кадром.

Теперь мой код:

:: Создать входной буфер

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;
}

:: Создать выходной буфер

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;
}

:: Заполнить входной буфер

NVENCSTATUS RenderManager::WriteInputBuffer(ID3D11Texture2D* pTexture)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
HRESULT result = S_OK;

// get data from 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 to A8R8G8B8

// write into buffer
memcpy(lockInputBufferParams.bufferDataPtr, mappedResource.pData, m_height * mappedResource.RowPitch);

// unlock input buffer
nvStatus = m_pEncodeAPI->nvEncUnlockInputBuffer(m_pEncoder, m_pEncoderInputBuffer);

return nvStatus;
}

:: Кодировать кадр

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;
}

:: Чтение из выходного буфера

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 from 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.

Почему размер изображения неправильный и как я должен заполнить входной буфер более чем одним кадром?

Большое спасибо за вашу помощь,

Александр

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]