Brooklyn/rdp-acceleraed/Server/NvEncoder/NvHWEncoder.cpp

1269 lines
39 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Copyright 1993-2014 NVIDIA Corporation. All rights reserved.
//
// Please refer to the NVIDIA end user license agreement (EULA) associated
// with this source code for terms and conditions that govern your use of
// this software. Any use, reproduction, disclosure, or distribution of
// this software and related documentation outside the terms of the EULA
// is strictly prohibited.
//
////////////////////////////////////////////////////////////////////////////
#include "NvHWEncoder.h"
NVENCSTATUS CNvHWEncoder::NvEncOpenEncodeSession(void* device, uint32_t deviceType)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncOpenEncodeSession(device, deviceType, &m_hEncoder);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodeGUIDCount(uint32_t* encodeGUIDCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodeGUIDCount(m_hEncoder, encodeGUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodeProfileGUIDCount(GUID encodeGUID, uint32_t* encodeProfileGUIDCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodeProfileGUIDCount(m_hEncoder, encodeGUID, encodeProfileGUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodeProfileGUIDs(GUID encodeGUID, GUID* profileGUIDs, uint32_t guidArraySize, uint32_t* GUIDCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodeProfileGUIDs(m_hEncoder, encodeGUID, profileGUIDs, guidArraySize, GUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodeGUIDs(GUID* GUIDs, uint32_t guidArraySize, uint32_t* GUIDCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodeGUIDs(m_hEncoder, GUIDs, guidArraySize, GUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetInputFormatCount(GUID encodeGUID, uint32_t* inputFmtCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetInputFormatCount(m_hEncoder, encodeGUID, inputFmtCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetInputFormats(GUID encodeGUID, NV_ENC_BUFFER_FORMAT* inputFmts, uint32_t inputFmtArraySize, uint32_t* inputFmtCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetInputFormats(m_hEncoder, encodeGUID, inputFmts, inputFmtArraySize, inputFmtCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodeCaps(GUID encodeGUID, NV_ENC_CAPS_PARAM* capsParam, int* capsVal)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodeCaps(m_hEncoder, encodeGUID, capsParam, capsVal);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodePresetCount(GUID encodeGUID, uint32_t* encodePresetGUIDCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodePresetCount(m_hEncoder, encodeGUID, encodePresetGUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodePresetGUIDs(GUID encodeGUID, GUID* presetGUIDs, uint32_t guidArraySize, uint32_t* encodePresetGUIDCount)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodePresetGUIDs(m_hEncoder, encodeGUID, presetGUIDs, guidArraySize, encodePresetGUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodePresetConfig(GUID encodeGUID, GUID presetGUID, NV_ENC_PRESET_CONFIG* presetConfig)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodePresetConfig(m_hEncoder, encodeGUID, presetGUID, presetConfig);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncCreateInputBuffer(uint32_t width, uint32_t height, void** inputBuffer, uint32_t isYuv444)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_CREATE_INPUT_BUFFER createInputBufferParams;
memset(&createInputBufferParams, 0, sizeof(createInputBufferParams));
SET_VER(createInputBufferParams, NV_ENC_CREATE_INPUT_BUFFER);
createInputBufferParams.width = width;
createInputBufferParams.height = height;
createInputBufferParams.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
createInputBufferParams.bufferFmt = isYuv444 ? NV_ENC_BUFFER_FORMAT_YUV444_PL : NV_ENC_BUFFER_FORMAT_NV12_PL;
nvStatus = m_pEncodeAPI->nvEncCreateInputBuffer(m_hEncoder, &createInputBufferParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
*inputBuffer = createInputBufferParams.inputBuffer;
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncDestroyInputBuffer(NV_ENC_INPUT_PTR inputBuffer)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
if (inputBuffer)
{
nvStatus = m_pEncodeAPI->nvEncDestroyInputBuffer(m_hEncoder, inputBuffer);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncCreateBitstreamBuffer(uint32_t size, void** bitstreamBuffer)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_CREATE_BITSTREAM_BUFFER createBitstreamBufferParams;
memset(&createBitstreamBufferParams, 0, sizeof(createBitstreamBufferParams));
SET_VER(createBitstreamBufferParams, NV_ENC_CREATE_BITSTREAM_BUFFER);
createBitstreamBufferParams.size = size;
createBitstreamBufferParams.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
nvStatus = m_pEncodeAPI->nvEncCreateBitstreamBuffer(m_hEncoder, &createBitstreamBufferParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
*bitstreamBuffer = createBitstreamBufferParams.bitstreamBuffer;
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncDestroyBitstreamBuffer(NV_ENC_OUTPUT_PTR bitstreamBuffer)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
if (bitstreamBuffer)
{
nvStatus = m_pEncodeAPI->nvEncDestroyBitstreamBuffer(m_hEncoder, bitstreamBuffer);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncLockBitstream(NV_ENC_LOCK_BITSTREAM* lockBitstreamBufferParams)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncLockBitstream(m_hEncoder, lockBitstreamBufferParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncUnlockBitstream(NV_ENC_OUTPUT_PTR bitstreamBuffer)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncUnlockBitstream(m_hEncoder, bitstreamBuffer);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncLockInputBuffer(void* inputBuffer, void** bufferDataPtr, uint32_t* pitch)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_LOCK_INPUT_BUFFER lockInputBufferParams;
memset(&lockInputBufferParams, 0, sizeof(lockInputBufferParams));
SET_VER(lockInputBufferParams, NV_ENC_LOCK_INPUT_BUFFER);
lockInputBufferParams.inputBuffer = inputBuffer;
nvStatus = m_pEncodeAPI->nvEncLockInputBuffer(m_hEncoder, &lockInputBufferParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
*bufferDataPtr = lockInputBufferParams.bufferDataPtr;
*pitch = lockInputBufferParams.pitch;
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncUnlockInputBuffer(NV_ENC_INPUT_PTR inputBuffer)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncUnlockInputBuffer(m_hEncoder, inputBuffer);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetEncodeStats(NV_ENC_STAT* encodeStats)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetEncodeStats(m_hEncoder, encodeStats);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncGetSequenceParams(NV_ENC_SEQUENCE_PARAM_PAYLOAD* sequenceParamPayload)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncGetSequenceParams(m_hEncoder, sequenceParamPayload);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncRegisterAsyncEvent(void** completionEvent)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_EVENT_PARAMS eventParams;
memset(&eventParams, 0, sizeof(eventParams));
SET_VER(eventParams, NV_ENC_EVENT_PARAMS);
#if defined (NV_WINDOWS)
eventParams.completionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
#else
eventParams.completionEvent = NULL;
#endif
nvStatus = m_pEncodeAPI->nvEncRegisterAsyncEvent(m_hEncoder, &eventParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
*completionEvent = eventParams.completionEvent;
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncUnregisterAsyncEvent(void* completionEvent)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_EVENT_PARAMS eventParams;
if (completionEvent)
{
memset(&eventParams, 0, sizeof(eventParams));
SET_VER(eventParams, NV_ENC_EVENT_PARAMS);
eventParams.completionEvent = completionEvent;
nvStatus = m_pEncodeAPI->nvEncUnregisterAsyncEvent(m_hEncoder, &eventParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncMapInputResource(void* registeredResource, void** mappedResource)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_MAP_INPUT_RESOURCE mapInputResParams;
memset(&mapInputResParams, 0, sizeof(mapInputResParams));
SET_VER(mapInputResParams, NV_ENC_MAP_INPUT_RESOURCE);
mapInputResParams.registeredResource = registeredResource;
nvStatus = m_pEncodeAPI->nvEncMapInputResource(m_hEncoder, &mapInputResParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
*mappedResource = mapInputResParams.mappedResource;
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncUnmapInputResource(NV_ENC_INPUT_PTR mappedInputBuffer)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
if (mappedInputBuffer)
{
nvStatus = m_pEncodeAPI->nvEncUnmapInputResource(m_hEncoder, mappedInputBuffer);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncDestroyEncoder()
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
if (m_bEncoderInitialized)
{
nvStatus = m_pEncodeAPI->nvEncDestroyEncoder(m_hEncoder);
m_bEncoderInitialized = false;
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncInvalidateRefFrames(const NvEncPictureCommand *pEncPicCommand)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
for (uint32_t i = 0; i < pEncPicCommand->numRefFramesToInvalidate; i++)
{
nvStatus = m_pEncodeAPI->nvEncInvalidateRefFrames(m_hEncoder, pEncPicCommand->refFrameNumbers[i]);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncOpenEncodeSessionEx(void* device, NV_ENC_DEVICE_TYPE deviceType)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS openSessionExParams;
memset(&openSessionExParams, 0, sizeof(openSessionExParams));
SET_VER(openSessionExParams, NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS);
openSessionExParams.device = device;
openSessionExParams.deviceType = deviceType;
openSessionExParams.reserved = NULL;
openSessionExParams.apiVersion = NVENCAPI_VERSION;
nvStatus = m_pEncodeAPI->nvEncOpenEncodeSessionEx(&openSessionExParams, &m_hEncoder);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncRegisterResource(NV_ENC_INPUT_RESOURCE_TYPE resourceType, void* resourceToRegister, uint32_t width, uint32_t height, uint32_t pitch, void** registeredResource)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_REGISTER_RESOURCE registerResParams;
memset(&registerResParams, 0, sizeof(registerResParams));
SET_VER(registerResParams, NV_ENC_REGISTER_RESOURCE);
registerResParams.resourceType = resourceType;
registerResParams.resourceToRegister = resourceToRegister;
registerResParams.width = width;
registerResParams.height = height;
registerResParams.pitch = pitch;
nvStatus = m_pEncodeAPI->nvEncRegisterResource(m_hEncoder, &registerResParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
*registeredResource = registerResParams.registeredResource;
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncUnregisterResource(NV_ENC_REGISTERED_PTR registeredRes)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
nvStatus = m_pEncodeAPI->nvEncUnregisterResource(m_hEncoder, registeredRes);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::NvEncReconfigureEncoder(const NvEncPictureCommand *pEncPicCommand)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
if (pEncPicCommand->bBitrateChangePending || pEncPicCommand->bResolutionChangePending)
{
if (pEncPicCommand->bResolutionChangePending)
{
m_uCurWidth = pEncPicCommand->newWidth;
m_uCurHeight = pEncPicCommand->newHeight;
if ((m_uCurWidth > m_uMaxWidth) || (m_uCurHeight > m_uMaxHeight))
{
return NV_ENC_ERR_INVALID_PARAM;
}
m_stCreateEncodeParams.encodeWidth = m_uCurWidth;
m_stCreateEncodeParams.encodeHeight = m_uCurHeight;
m_stCreateEncodeParams.darWidth = m_uCurWidth;
m_stCreateEncodeParams.darHeight = m_uCurHeight;
}
if (pEncPicCommand->bBitrateChangePending)
{
m_stEncodeConfig.rcParams.averageBitRate = pEncPicCommand->newBitrate;
m_stEncodeConfig.rcParams.maxBitRate = pEncPicCommand->newBitrate;
m_stEncodeConfig.rcParams.vbvBufferSize = pEncPicCommand->newVBVSize != 0 ? pEncPicCommand->newVBVSize : (pEncPicCommand->newBitrate * m_stCreateEncodeParams.frameRateDen) / m_stCreateEncodeParams.frameRateNum;
m_stEncodeConfig.rcParams.vbvInitialDelay = m_stEncodeConfig.rcParams.vbvBufferSize;
}
NV_ENC_RECONFIGURE_PARAMS stReconfigParams;
memset(&stReconfigParams, 0, sizeof(stReconfigParams));
memcpy(&stReconfigParams.reInitEncodeParams, &m_stCreateEncodeParams, sizeof(m_stCreateEncodeParams));
stReconfigParams.version = NV_ENC_RECONFIGURE_PARAMS_VER;
stReconfigParams.forceIDR = pEncPicCommand->bResolutionChangePending ? 1 : 0;
nvStatus = m_pEncodeAPI->nvEncReconfigureEncoder(m_hEncoder, &stReconfigParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
}
return nvStatus;
}
CNvHWEncoder::CNvHWEncoder()
{
m_hEncoder = NULL;
m_bEncoderInitialized = false;
m_pEncodeAPI = NULL;
m_hinstLib = NULL;
m_EncodeIdx = 0;
m_uCurWidth = 0;
m_uCurHeight = 0;
m_uMaxWidth = 0;
m_uMaxHeight = 0;
memset(&m_stCreateEncodeParams, 0, sizeof(m_stCreateEncodeParams));
SET_VER(m_stCreateEncodeParams, NV_ENC_INITIALIZE_PARAMS);
memset(&m_stEncodeConfig, 0, sizeof(m_stEncodeConfig));
SET_VER(m_stEncodeConfig, NV_ENC_CONFIG);
}
CNvHWEncoder::~CNvHWEncoder()
{
// clean up encode API resources here
if (m_pEncodeAPI)
{
delete m_pEncodeAPI;
m_pEncodeAPI = NULL;
}
if (m_hinstLib)
{
#if defined (NV_WINDOWS)
FreeLibrary(m_hinstLib);
#else
dlclose(m_hinstLib);
#endif
m_hinstLib = NULL;
}
}
NVENCSTATUS CNvHWEncoder::ValidateEncodeGUID (GUID inputCodecGuid)
{
unsigned int i, codecFound, encodeGUIDCount, encodeGUIDArraySize;
NVENCSTATUS nvStatus;
GUID *encodeGUIDArray;
nvStatus = m_pEncodeAPI->nvEncGetEncodeGUIDCount(m_hEncoder, &encodeGUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
return nvStatus;
}
encodeGUIDArray = new GUID[encodeGUIDCount];
memset(encodeGUIDArray, 0, sizeof(GUID)* encodeGUIDCount);
encodeGUIDArraySize = 0;
nvStatus = m_pEncodeAPI->nvEncGetEncodeGUIDs(m_hEncoder, encodeGUIDArray, encodeGUIDCount, &encodeGUIDArraySize);
if (nvStatus != NV_ENC_SUCCESS)
{
delete[] encodeGUIDArray;
assert(0);
return nvStatus;
}
assert(encodeGUIDArraySize <= encodeGUIDCount);
codecFound = 0;
for (i = 0; i < encodeGUIDArraySize; i++)
{
if (inputCodecGuid == encodeGUIDArray[i])
{
codecFound = 1;
break;
}
}
delete[] encodeGUIDArray;
if (codecFound)
return NV_ENC_SUCCESS;
else
return NV_ENC_ERR_INVALID_PARAM;
}
NVENCSTATUS CNvHWEncoder::ValidatePresetGUID(GUID inputPresetGuid, GUID inputCodecGuid)
{
uint32_t i, presetFound, presetGUIDCount, presetGUIDArraySize;
NVENCSTATUS nvStatus;
GUID *presetGUIDArray;
nvStatus = m_pEncodeAPI->nvEncGetEncodePresetCount(m_hEncoder, inputCodecGuid, &presetGUIDCount);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
return nvStatus;
}
presetGUIDArray = new GUID[presetGUIDCount];
memset(presetGUIDArray, 0, sizeof(GUID)* presetGUIDCount);
presetGUIDArraySize = 0;
nvStatus = m_pEncodeAPI->nvEncGetEncodePresetGUIDs(m_hEncoder, inputCodecGuid, presetGUIDArray, presetGUIDCount, &presetGUIDArraySize);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
delete[] presetGUIDArray;
return nvStatus;
}
assert(presetGUIDArraySize <= presetGUIDCount);
presetFound = 0;
for (i = 0; i < presetGUIDArraySize; i++)
{
if (inputPresetGuid == presetGUIDArray[i])
{
presetFound = 1;
break;
}
}
delete[] presetGUIDArray;
if (presetFound)
return NV_ENC_SUCCESS;
else
return NV_ENC_ERR_INVALID_PARAM;
}
NVENCSTATUS CNvHWEncoder::CreateEncoder(const EncodeConfig *pEncCfg)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
if (pEncCfg == NULL)
{
return NV_ENC_ERR_INVALID_PARAM;
}
m_uCurWidth = pEncCfg->width;
m_uCurHeight = pEncCfg->height;
m_uMaxWidth = (pEncCfg->maxWidth > 0 ? pEncCfg->maxWidth : pEncCfg->width);
m_uMaxHeight = (pEncCfg->maxHeight > 0 ? pEncCfg->maxHeight : pEncCfg->height);
if ((m_uCurWidth > m_uMaxWidth) || (m_uCurHeight > m_uMaxHeight)) {
return NV_ENC_ERR_INVALID_PARAM;
}
if (!pEncCfg->width || !pEncCfg->height)
{
return NV_ENC_ERR_INVALID_PARAM;
}
GUID inputCodecGUID = pEncCfg->codec == NV_ENC_H264 ? NV_ENC_CODEC_H264_GUID : NV_ENC_CODEC_HEVC_GUID;
nvStatus = ValidateEncodeGUID(inputCodecGUID);
if (nvStatus != NV_ENC_SUCCESS)
{
PRINTERR("codec not supported \n");
return nvStatus;
}
codecGUID = inputCodecGUID;
m_stCreateEncodeParams.encodeGUID = inputCodecGUID;
m_stCreateEncodeParams.presetGUID = pEncCfg->presetGUID;
m_stCreateEncodeParams.encodeWidth = pEncCfg->width;
m_stCreateEncodeParams.encodeHeight = pEncCfg->height;
m_stCreateEncodeParams.darWidth = pEncCfg->width;
m_stCreateEncodeParams.darHeight = pEncCfg->height;
m_stCreateEncodeParams.frameRateNum = pEncCfg->fps;
m_stCreateEncodeParams.frameRateDen = 1;
#if defined(NV_WINDOWS)
m_stCreateEncodeParams.enableEncodeAsync = 1;
#else
m_stCreateEncodeParams.enableEncodeAsync = 0;
#endif
m_stCreateEncodeParams.enablePTD = 1;
m_stCreateEncodeParams.reportSliceOffsets = 0;
m_stCreateEncodeParams.enableSubFrameWrite = 0;
m_stCreateEncodeParams.encodeConfig = &m_stEncodeConfig;
m_stCreateEncodeParams.maxEncodeWidth = m_uMaxWidth;
m_stCreateEncodeParams.maxEncodeHeight = m_uMaxHeight;
// apply preset
NV_ENC_PRESET_CONFIG stPresetCfg;
memset(&stPresetCfg, 0, sizeof(NV_ENC_PRESET_CONFIG));
SET_VER(stPresetCfg, NV_ENC_PRESET_CONFIG);
SET_VER(stPresetCfg.presetCfg, NV_ENC_CONFIG);
nvStatus = m_pEncodeAPI->nvEncGetEncodePresetConfig(m_hEncoder, m_stCreateEncodeParams.encodeGUID, m_stCreateEncodeParams.presetGUID, &stPresetCfg);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
return nvStatus;
}
memcpy(&m_stEncodeConfig, &stPresetCfg.presetCfg, sizeof(NV_ENC_CONFIG));
m_stEncodeConfig.gopLength = pEncCfg->gopLength;
m_stEncodeConfig.frameIntervalP = pEncCfg->numB + 1;
if (pEncCfg->pictureStruct == NV_ENC_PIC_STRUCT_FRAME)
{
m_stEncodeConfig.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
}
else
{
m_stEncodeConfig.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
}
m_stEncodeConfig.mvPrecision = NV_ENC_MV_PRECISION_QUARTER_PEL;
if (pEncCfg->bitrate || pEncCfg->vbvMaxBitrate)
{
m_stEncodeConfig.rcParams.rateControlMode = (NV_ENC_PARAMS_RC_MODE)pEncCfg->rcMode;
m_stEncodeConfig.rcParams.averageBitRate = pEncCfg->bitrate;
m_stEncodeConfig.rcParams.maxBitRate = pEncCfg->vbvMaxBitrate;
m_stEncodeConfig.rcParams.vbvBufferSize = pEncCfg->vbvSize;
m_stEncodeConfig.rcParams.vbvInitialDelay = pEncCfg->vbvSize * 9 / 10;
}
else
{
m_stEncodeConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
}
if (pEncCfg->rcMode == 0)
{
m_stEncodeConfig.rcParams.constQP.qpInterP = pEncCfg->presetGUID == NV_ENC_PRESET_LOSSLESS_HP_GUID? 0 : pEncCfg->qp;
m_stEncodeConfig.rcParams.constQP.qpInterB = pEncCfg->presetGUID == NV_ENC_PRESET_LOSSLESS_HP_GUID? 0 : pEncCfg->qp;
m_stEncodeConfig.rcParams.constQP.qpIntra = pEncCfg->presetGUID == NV_ENC_PRESET_LOSSLESS_HP_GUID? 0 : pEncCfg->qp;
}
if (pEncCfg->isYuv444)
{
m_stEncodeConfig.encodeCodecConfig.h264Config.chromaFormatIDC = 3;
}
else
{
m_stEncodeConfig.encodeCodecConfig.h264Config.chromaFormatIDC = 1;
}
if (pEncCfg->intraRefreshEnableFlag)
{
if (pEncCfg->codec == NV_ENC_HEVC)
{
m_stEncodeConfig.encodeCodecConfig.hevcConfig.enableIntraRefresh = 1;
m_stEncodeConfig.encodeCodecConfig.hevcConfig.intraRefreshPeriod = pEncCfg->intraRefreshPeriod;
m_stEncodeConfig.encodeCodecConfig.hevcConfig.intraRefreshCnt = pEncCfg->intraRefreshDuration;
}
else
{
m_stEncodeConfig.encodeCodecConfig.h264Config.enableIntraRefresh = 1;
m_stEncodeConfig.encodeCodecConfig.h264Config.intraRefreshPeriod = pEncCfg->intraRefreshPeriod;
m_stEncodeConfig.encodeCodecConfig.h264Config.intraRefreshCnt = pEncCfg->intraRefreshDuration;
}
}
if (pEncCfg->invalidateRefFramesEnableFlag)
{
if (pEncCfg->codec == NV_ENC_HEVC)
{
m_stEncodeConfig.encodeCodecConfig.hevcConfig.maxNumRefFramesInDPB = 16;
}
else
{
m_stEncodeConfig.encodeCodecConfig.h264Config.maxNumRefFrames = 16;
}
}
if (pEncCfg->qpDeltaMapFile)
{
m_stEncodeConfig.rcParams.enableExtQPDeltaMap = 1;
}
if (pEncCfg->codec == NV_ENC_H264)
{
m_stEncodeConfig.encodeCodecConfig.h264Config.idrPeriod = pEncCfg->gopLength;
}
else if (pEncCfg->codec == NV_ENC_HEVC)
{
m_stEncodeConfig.encodeCodecConfig.hevcConfig.idrPeriod = pEncCfg->gopLength;
}
nvStatus = m_pEncodeAPI->nvEncInitializeEncoder(m_hEncoder, &m_stCreateEncodeParams);
if (nvStatus != NV_ENC_SUCCESS)
return nvStatus;
m_bEncoderInitialized = true;
return nvStatus;
}
GUID CNvHWEncoder::GetPresetGUID(char* encoderPreset, int codec)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
GUID presetGUID = NV_ENC_PRESET_DEFAULT_GUID;
if (encoderPreset && (stricmp(encoderPreset, "hq") == 0))
{
presetGUID = NV_ENC_PRESET_HQ_GUID;
}
else if (encoderPreset && (stricmp(encoderPreset, "lowLatencyHP") == 0))
{
presetGUID = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
}
else if (encoderPreset && (stricmp(encoderPreset, "hp") == 0))
{
presetGUID = NV_ENC_PRESET_HP_GUID;
}
else if (encoderPreset && (stricmp(encoderPreset, "lowLatencyHQ") == 0))
{
presetGUID = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
}
else if (encoderPreset && (stricmp(encoderPreset, "lossless") == 0))
{
presetGUID = NV_ENC_PRESET_LOSSLESS_HP_GUID;
}
else
{
presetGUID = NV_ENC_PRESET_DEFAULT_GUID;
}
GUID inputCodecGUID = codec == NV_ENC_H264 ? NV_ENC_CODEC_H264_GUID : NV_ENC_CODEC_HEVC_GUID;
nvStatus = ValidatePresetGUID(presetGUID, inputCodecGUID);
if (nvStatus != NV_ENC_SUCCESS)
{
presetGUID = NV_ENC_PRESET_DEFAULT_GUID;
PRINTERR("Unsupported preset guid %s\n", encoderPreset);
}
return presetGUID;
}
NVENCSTATUS CNvHWEncoder::ProcessOutput(const EncodeBuffer *pEncodeBuffer, DataPacket* dataPacket)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
if (pEncodeBuffer->stOutputBfr.hBitstreamBuffer == NULL && pEncodeBuffer->stOutputBfr.bEOSFlag == FALSE)
{
return NV_ENC_ERR_INVALID_PARAM;
}
if (pEncodeBuffer->stOutputBfr.bWaitOnEvent == TRUE)
{
if (!pEncodeBuffer->stOutputBfr.hOutputEvent)
{
return NV_ENC_ERR_INVALID_PARAM;
}
#if defined(NV_WINDOWS)
WaitForSingleObject(pEncodeBuffer->stOutputBfr.hOutputEvent, INFINITE);
#endif
}
if (pEncodeBuffer->stOutputBfr.bEOSFlag)
return NV_ENC_SUCCESS;
nvStatus = NV_ENC_SUCCESS;
NV_ENC_LOCK_BITSTREAM lockBitstreamData;
memset(&lockBitstreamData, 0, sizeof(lockBitstreamData));
SET_VER(lockBitstreamData, NV_ENC_LOCK_BITSTREAM);
lockBitstreamData.outputBitstream = pEncodeBuffer->stOutputBfr.hBitstreamBuffer;
lockBitstreamData.doNotWait = false;
nvStatus = m_pEncodeAPI->nvEncLockBitstream(m_hEncoder, &lockBitstreamData);
if (nvStatus == NV_ENC_SUCCESS)
{
dataPacket->size = lockBitstreamData.bitstreamSizeInBytes;
memcpy(dataPacket->data, lockBitstreamData.bitstreamBufferPtr, dataPacket->size);
nvStatus = m_pEncodeAPI->nvEncUnlockBitstream(m_hEncoder, pEncodeBuffer->stOutputBfr.hBitstreamBuffer);
}
else
{
PRINTERR("lock bitstream function failed \n");
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::Initialize(void* device, NV_ENC_DEVICE_TYPE deviceType)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
MYPROC nvEncodeAPICreateInstance; // function pointer to create instance in nvEncodeAPI
#if defined(NV_WINDOWS)
#if defined (_WIN64)
m_hinstLib = LoadLibrary(TEXT("nvEncodeAPI64.dll"));
#else
m_hinstLib = LoadLibrary(TEXT("nvEncodeAPI.dll"));
#endif
#else
m_hinstLib = dlopen("libnvidia-encode.so.1", RTLD_LAZY);
#endif
if (m_hinstLib == NULL)
return NV_ENC_ERR_OUT_OF_MEMORY;
#if defined(NV_WINDOWS)
nvEncodeAPICreateInstance = (MYPROC)GetProcAddress(m_hinstLib, "NvEncodeAPICreateInstance");
#else
nvEncodeAPICreateInstance = (MYPROC)dlsym(m_hinstLib, "NvEncodeAPICreateInstance");
#endif
if (nvEncodeAPICreateInstance == NULL)
return NV_ENC_ERR_OUT_OF_MEMORY;
m_pEncodeAPI = new NV_ENCODE_API_FUNCTION_LIST;
if (m_pEncodeAPI == NULL)
return NV_ENC_ERR_OUT_OF_MEMORY;
memset(m_pEncodeAPI, 0, sizeof(NV_ENCODE_API_FUNCTION_LIST));
m_pEncodeAPI->version = NV_ENCODE_API_FUNCTION_LIST_VER;
nvStatus = nvEncodeAPICreateInstance(m_pEncodeAPI);
if (nvStatus != NV_ENC_SUCCESS)
return nvStatus;
nvStatus = NvEncOpenEncodeSessionEx(device, deviceType);
if (nvStatus != NV_ENC_SUCCESS)
return nvStatus;
return NV_ENC_SUCCESS;
}
NVENCSTATUS CNvHWEncoder::NvEncEncodeFrame(EncodeBuffer *pEncodeBuffer, NvEncPictureCommand *encPicCommand,
uint32_t width, uint32_t height, NV_ENC_PIC_STRUCT ePicStruct,
int8_t *qpDeltaMapArray, uint32_t qpDeltaMapArraySize)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_PIC_PARAMS encPicParams;
memset(&encPicParams, 0, sizeof(encPicParams));
SET_VER(encPicParams, NV_ENC_PIC_PARAMS);
encPicParams.inputBuffer = pEncodeBuffer->stInputBfr.hInputSurface;
encPicParams.bufferFmt = pEncodeBuffer->stInputBfr.bufferFmt;
encPicParams.inputWidth = width;
encPicParams.inputHeight = height;
encPicParams.outputBitstream = pEncodeBuffer->stOutputBfr.hBitstreamBuffer;
encPicParams.completionEvent = pEncodeBuffer->stOutputBfr.hOutputEvent;
encPicParams.inputTimeStamp = m_EncodeIdx;
encPicParams.pictureStruct = ePicStruct;
encPicParams.qpDeltaMap = qpDeltaMapArray;
encPicParams.qpDeltaMapSize = qpDeltaMapArraySize;
if (encPicCommand)
{
if (encPicCommand->bForceIDR)
{
encPicParams.encodePicFlags |= NV_ENC_PIC_FLAG_FORCEIDR;
}
if (encPicCommand->bForceIntraRefresh)
{
if (codecGUID == NV_ENC_CODEC_HEVC_GUID)
{
encPicParams.codecPicParams.hevcPicParams.forceIntraRefreshWithFrameCnt = encPicCommand->intraRefreshDuration;
}
else
{
encPicParams.codecPicParams.h264PicParams.forceIntraRefreshWithFrameCnt = encPicCommand->intraRefreshDuration;
}
}
}
nvStatus = m_pEncodeAPI->nvEncEncodePicture(m_hEncoder, &encPicParams);
if (nvStatus != NV_ENC_SUCCESS && nvStatus != NV_ENC_ERR_NEED_MORE_INPUT)
{
assert(0);
return nvStatus;
}
m_EncodeIdx++;
return NV_ENC_SUCCESS;
}
NVENCSTATUS CNvHWEncoder::NvEncFlushEncoderQueue(void *hEOSEvent)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_PIC_PARAMS encPicParams;
memset(&encPicParams, 0, sizeof(encPicParams));
SET_VER(encPicParams, NV_ENC_PIC_PARAMS);
encPicParams.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
encPicParams.completionEvent = hEOSEvent;
nvStatus = m_pEncodeAPI->nvEncEncodePicture(m_hEncoder, &encPicParams);
if (nvStatus != NV_ENC_SUCCESS)
{
assert(0);
}
return nvStatus;
}
NVENCSTATUS CNvHWEncoder::ParseArguments(EncodeConfig *encodeConfig, int argc, char *argv[])
{
for (int i = 1; i < argc; i++)
{
if (stricmp(argv[i], "-bmpfilePath") == 0)
{
if (++i >= argc)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
encodeConfig->inputFilePath = argv[i];
}
else if (stricmp(argv[i], "-i") == 0)
{
if (++i >= argc)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
encodeConfig->inputFileName = argv[i];
}
else if (stricmp(argv[i], "-o") == 0)
{
if (++i >= argc)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
encodeConfig->outputFileName = argv[i];
}
else if (stricmp(argv[i], "-size") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->width) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->height) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 2]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-maxSize") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->maxWidth) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->maxHeight) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 2]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-bitrate") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->bitrate) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-vbvMaxBitrate") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->vbvMaxBitrate) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-vbvSize") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->vbvSize) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-fps") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->fps) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-startf") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->startFrameIdx) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-endf") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->endFrameIdx) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-rcmode") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->rcMode) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-goplength") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->gopLength) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-numB") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->numB) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-qp") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->qp) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-preset") == 0)
{
if (++i >= argc)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
encodeConfig->encoderPreset = argv[i];
}
else if (stricmp(argv[i], "-devicetype") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->deviceType) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-codec") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->codec) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-encCmdFile") == 0)
{
if (++i >= argc)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
encodeConfig->encCmdFileName = argv[i];
}
else if (stricmp(argv[i], "-intraRefresh") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->intraRefreshEnableFlag) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-intraRefreshPeriod") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->intraRefreshPeriod) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-intraRefreshDuration") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->intraRefreshDuration) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-picStruct") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->pictureStruct) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-deviceID") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->deviceID) != 1)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-yuv444") == 0)
{
if (++i >= argc || sscanf(argv[i], "%d", &encodeConfig->isYuv444) != 1)
{
fprintf(stderr, "invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
else if (stricmp(argv[i], "-qpDeltaMapFile") == 0)
{
if (++i >= argc)
{
PRINTERR("invalid parameter for %s\n", argv[i - 1]);
return NV_ENC_ERR_INVALID_PARAM;
}
encodeConfig->qpDeltaMapFile = argv[i];
}
else if (stricmp(argv[i], "-help") == 0)
{
return NV_ENC_ERR_INVALID_PARAM;
}
else
{
PRINTERR("invalid parameter %s\n", argv[i++]);
return NV_ENC_ERR_INVALID_PARAM;
}
}
return NV_ENC_SUCCESS;
}