commit
9d84eaed80
13 changed files with 2277 additions and 1121 deletions
@ -1,10 +0,0 @@ |
||||
#ifdef HAVE_OPENCV_CUDACODEC |
||||
|
||||
#include "opencv2/cudacodec.hpp" |
||||
|
||||
typedef cudacodec::EncoderCallBack::PicType EncoderCallBack_PicType; |
||||
|
||||
CV_PY_TO_CLASS(cudacodec::EncoderParams); |
||||
CV_PY_FROM_CLASS(cudacodec::EncoderParams); |
||||
|
||||
#endif |
@ -0,0 +1,786 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "precomp.hpp" |
||||
|
||||
#if defined(HAVE_NVCUVENC) |
||||
#include "NvEncoder.h" |
||||
|
||||
namespace cv { namespace cudacodec { |
||||
#ifndef _WIN32 |
||||
#include <cstring> |
||||
static inline bool operator==(const GUID& guid1, const GUID& guid2) { |
||||
return !memcmp(&guid1, &guid2, sizeof(GUID)); |
||||
} |
||||
|
||||
static inline bool operator!=(const GUID& guid1, const GUID& guid2) { |
||||
return !(guid1 == guid2); |
||||
} |
||||
#endif |
||||
|
||||
NvEncoder::NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void* pDevice, uint32_t nWidth, uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat, |
||||
uint32_t nExtraOutputDelay) : |
||||
m_hEncoder(nullptr), |
||||
m_pDevice(pDevice), |
||||
m_eDeviceType(eDeviceType), |
||||
m_nWidth(nWidth), |
||||
m_nHeight(nHeight), |
||||
m_nMaxEncodeWidth(nWidth), |
||||
m_nMaxEncodeHeight(nHeight), |
||||
m_eBufferFormat(eBufferFormat), |
||||
m_nExtraOutputDelay(nExtraOutputDelay) |
||||
{ |
||||
LoadNvEncApi(); |
||||
|
||||
if (!m_nvenc.nvEncOpenEncodeSession) |
||||
{ |
||||
m_nEncoderBuffer = 0; |
||||
NVENC_THROW_ERROR("EncodeAPI not found", NV_ENC_ERR_NO_ENCODE_DEVICE); |
||||
} |
||||
|
||||
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS encodeSessionExParams = {}; |
||||
encodeSessionExParams.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER; |
||||
encodeSessionExParams.device = m_pDevice; |
||||
encodeSessionExParams.deviceType = m_eDeviceType; |
||||
encodeSessionExParams.apiVersion = NVENCAPI_VERSION; |
||||
void* hEncoder = NULL; |
||||
NVENC_API_CALL(m_nvenc.nvEncOpenEncodeSessionEx(&encodeSessionExParams, &hEncoder)); |
||||
m_hEncoder = hEncoder; |
||||
} |
||||
|
||||
void NvEncoder::LoadNvEncApi() |
||||
{ |
||||
|
||||
uint32_t version = 0; |
||||
uint32_t currentVersion = (NVENCAPI_MAJOR_VERSION << 4) | NVENCAPI_MINOR_VERSION; |
||||
NVENC_API_CALL(NvEncodeAPIGetMaxSupportedVersion(&version)); |
||||
if (currentVersion > version) |
||||
{ |
||||
NVENC_THROW_ERROR("Current Driver Version does not support this NvEncodeAPI version, please upgrade driver", NV_ENC_ERR_INVALID_VERSION); |
||||
} |
||||
|
||||
m_nvenc = {}; |
||||
m_nvenc.version = NV_ENCODE_API_FUNCTION_LIST_VER; |
||||
NVENC_API_CALL(NvEncodeAPICreateInstance(&m_nvenc)); |
||||
} |
||||
|
||||
NvEncoder::~NvEncoder() |
||||
{ |
||||
DestroyHWEncoder(); |
||||
} |
||||
|
||||
void NvEncoder::CreateDefaultEncoderParams(NV_ENC_INITIALIZE_PARAMS* pIntializeParams, GUID codecGuid, GUID presetGuid, NV_ENC_TUNING_INFO tuningInfo) |
||||
{ |
||||
if (!m_hEncoder) |
||||
{ |
||||
NVENC_THROW_ERROR("Encoder Initialization failed", NV_ENC_ERR_NO_ENCODE_DEVICE); |
||||
return; |
||||
} |
||||
|
||||
if (pIntializeParams == nullptr || pIntializeParams->encodeConfig == nullptr) |
||||
{ |
||||
NVENC_THROW_ERROR("pInitializeParams and pInitializeParams->encodeConfig can't be NULL", NV_ENC_ERR_INVALID_PTR); |
||||
} |
||||
|
||||
memset(pIntializeParams->encodeConfig, 0, sizeof(NV_ENC_CONFIG)); |
||||
auto pEncodeConfig = pIntializeParams->encodeConfig; |
||||
memset(pIntializeParams, 0, sizeof(NV_ENC_INITIALIZE_PARAMS)); |
||||
pIntializeParams->encodeConfig = pEncodeConfig; |
||||
|
||||
|
||||
pIntializeParams->encodeConfig->version = NV_ENC_CONFIG_VER; |
||||
pIntializeParams->version = NV_ENC_INITIALIZE_PARAMS_VER; |
||||
|
||||
pIntializeParams->encodeGUID = codecGuid; |
||||
pIntializeParams->presetGUID = presetGuid; |
||||
pIntializeParams->encodeWidth = m_nWidth; |
||||
pIntializeParams->encodeHeight = m_nHeight; |
||||
pIntializeParams->darWidth = m_nWidth; |
||||
pIntializeParams->darHeight = m_nHeight; |
||||
pIntializeParams->frameRateNum = 30; |
||||
pIntializeParams->frameRateDen = 1; |
||||
pIntializeParams->enablePTD = 1; |
||||
pIntializeParams->reportSliceOffsets = 0; |
||||
pIntializeParams->enableSubFrameWrite = 0; |
||||
pIntializeParams->maxEncodeWidth = m_nWidth; |
||||
pIntializeParams->maxEncodeHeight = m_nHeight; |
||||
pIntializeParams->enableMEOnlyMode = false; |
||||
pIntializeParams->enableOutputInVidmem = false; |
||||
#if defined(_WIN32) |
||||
pIntializeParams->enableEncodeAsync = GetCapabilityValue(codecGuid, NV_ENC_CAPS_ASYNC_ENCODE_SUPPORT); |
||||
#endif |
||||
pIntializeParams->tuningInfo = tuningInfo; |
||||
NV_ENC_PRESET_CONFIG presetConfig = {}; |
||||
presetConfig.version = NV_ENC_PRESET_CONFIG_VER; |
||||
presetConfig.presetCfg.version = NV_ENC_CONFIG_VER; |
||||
m_nvenc.nvEncGetEncodePresetConfigEx(m_hEncoder, codecGuid, presetGuid, tuningInfo, &presetConfig); |
||||
memcpy(pIntializeParams->encodeConfig, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG)); |
||||
|
||||
if (pIntializeParams->encodeGUID == NV_ENC_CODEC_H264_GUID) |
||||
{ |
||||
if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) |
||||
{ |
||||
pIntializeParams->encodeConfig->encodeCodecConfig.h264Config.chromaFormatIDC = 3; |
||||
} |
||||
pIntializeParams->encodeConfig->encodeCodecConfig.h264Config.idrPeriod = pIntializeParams->encodeConfig->gopLength; |
||||
} |
||||
else if (pIntializeParams->encodeGUID == NV_ENC_CODEC_HEVC_GUID) |
||||
{ |
||||
pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.pixelBitDepthMinus8 = |
||||
(m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) ? 2 : 0; |
||||
if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) |
||||
{ |
||||
pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.chromaFormatIDC = 3; |
||||
} |
||||
pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod = pIntializeParams->encodeConfig->gopLength; |
||||
} |
||||
|
||||
return; |
||||
} |
||||
|
||||
void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS* pEncoderParams) |
||||
{ |
||||
if (!m_hEncoder) |
||||
{ |
||||
NVENC_THROW_ERROR("Encoder Initialization failed", NV_ENC_ERR_NO_ENCODE_DEVICE); |
||||
} |
||||
|
||||
if (!pEncoderParams) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid NV_ENC_INITIALIZE_PARAMS ptr", NV_ENC_ERR_INVALID_PTR); |
||||
} |
||||
|
||||
if (pEncoderParams->encodeWidth == 0 || pEncoderParams->encodeHeight == 0) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid encoder width and height", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
|
||||
if (pEncoderParams->encodeGUID != NV_ENC_CODEC_H264_GUID && pEncoderParams->encodeGUID != NV_ENC_CODEC_HEVC_GUID) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid codec guid", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
|
||||
if (pEncoderParams->encodeGUID == NV_ENC_CODEC_H264_GUID) |
||||
{ |
||||
if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) |
||||
{ |
||||
NVENC_THROW_ERROR("10-bit format isn't supported by H264 encoder", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
// set other necessary params if not set yet
|
||||
if (pEncoderParams->encodeGUID == NV_ENC_CODEC_H264_GUID) |
||||
{ |
||||
if ((m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444) && |
||||
(pEncoderParams->encodeConfig->encodeCodecConfig.h264Config.chromaFormatIDC != 3)) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid ChromaFormatIDC", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
if (pEncoderParams->encodeGUID == NV_ENC_CODEC_HEVC_GUID) |
||||
{ |
||||
bool yuv10BitFormat = (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) ? true : false; |
||||
if (yuv10BitFormat && pEncoderParams->encodeConfig->encodeCodecConfig.hevcConfig.pixelBitDepthMinus8 != 2) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid PixelBitdepth", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
|
||||
if ((m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 || m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) && |
||||
(pEncoderParams->encodeConfig->encodeCodecConfig.hevcConfig.chromaFormatIDC != 3)) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid ChromaFormatIDC", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
memcpy(&m_initializeParams, pEncoderParams, sizeof(m_initializeParams)); |
||||
m_initializeParams.version = NV_ENC_INITIALIZE_PARAMS_VER; |
||||
|
||||
if (pEncoderParams->encodeConfig) |
||||
{ |
||||
memcpy(&m_encodeConfig, pEncoderParams->encodeConfig, sizeof(m_encodeConfig)); |
||||
m_encodeConfig.version = NV_ENC_CONFIG_VER; |
||||
} |
||||
else |
||||
{ |
||||
NV_ENC_PRESET_CONFIG presetConfig = {}; |
||||
presetConfig.version = NV_ENC_PRESET_CONFIG_VER; |
||||
presetConfig.presetCfg.version = NV_ENC_CONFIG_VER; |
||||
m_nvenc.nvEncGetEncodePresetConfigEx(m_hEncoder, pEncoderParams->encodeGUID, pEncoderParams->presetGUID, pEncoderParams->tuningInfo, &presetConfig); |
||||
memcpy(&m_encodeConfig, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG)); |
||||
} |
||||
m_initializeParams.encodeConfig = &m_encodeConfig; |
||||
NVENC_API_CALL(m_nvenc.nvEncInitializeEncoder(m_hEncoder, &m_initializeParams)); |
||||
m_bEncoderInitialized = true; |
||||
m_nWidth = m_initializeParams.encodeWidth; |
||||
m_nHeight = m_initializeParams.encodeHeight; |
||||
m_nMaxEncodeWidth = m_initializeParams.maxEncodeWidth; |
||||
m_nMaxEncodeHeight = m_initializeParams.maxEncodeHeight; |
||||
|
||||
m_nEncoderBuffer = m_encodeConfig.frameIntervalP + m_encodeConfig.rcParams.lookaheadDepth + m_nExtraOutputDelay; |
||||
m_nOutputDelay = m_nEncoderBuffer - 1; |
||||
|
||||
m_vpCompletionEvent.resize(m_nEncoderBuffer, nullptr); |
||||
|
||||
#if defined(_WIN32) |
||||
for (uint32_t i = 0; i < m_vpCompletionEvent.size(); i++) |
||||
{ |
||||
m_vpCompletionEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); |
||||
NV_ENC_EVENT_PARAMS eventParams = { NV_ENC_EVENT_PARAMS_VER }; |
||||
eventParams.completionEvent = m_vpCompletionEvent[i]; |
||||
m_nvenc.nvEncRegisterAsyncEvent(m_hEncoder, &eventParams); |
||||
} |
||||
#endif |
||||
|
||||
m_vMappedInputBuffers.resize(m_nEncoderBuffer, nullptr); |
||||
m_vBitstreamOutputBuffer.resize(m_nEncoderBuffer, nullptr); |
||||
InitializeBitstreamBuffer(); |
||||
AllocateInputBuffers(m_nEncoderBuffer); |
||||
} |
||||
|
||||
void NvEncoder::DestroyEncoder() |
||||
{ |
||||
if (!m_hEncoder) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
ReleaseInputBuffers(); |
||||
|
||||
DestroyHWEncoder(); |
||||
} |
||||
|
||||
void NvEncoder::DestroyHWEncoder() |
||||
{ |
||||
if (!m_hEncoder) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
#if defined(_WIN32) |
||||
for (uint32_t i = 0; i < m_vpCompletionEvent.size(); i++) |
||||
{ |
||||
if (m_vpCompletionEvent[i]) |
||||
{ |
||||
NV_ENC_EVENT_PARAMS eventParams = { NV_ENC_EVENT_PARAMS_VER }; |
||||
eventParams.completionEvent = m_vpCompletionEvent[i]; |
||||
m_nvenc.nvEncUnregisterAsyncEvent(m_hEncoder, &eventParams); |
||||
CloseHandle(m_vpCompletionEvent[i]); |
||||
} |
||||
} |
||||
m_vpCompletionEvent.clear(); |
||||
#endif |
||||
|
||||
DestroyBitstreamBuffer(); |
||||
|
||||
m_nvenc.nvEncDestroyEncoder(m_hEncoder); |
||||
|
||||
m_hEncoder = nullptr; |
||||
|
||||
m_bEncoderInitialized = false; |
||||
} |
||||
|
||||
const NvEncInputFrame* NvEncoder::GetNextInputFrame() |
||||
{ |
||||
int i = m_iToSend % m_nEncoderBuffer; |
||||
return &m_vInputFrames[i]; |
||||
} |
||||
|
||||
void NvEncoder::MapResources(uint32_t bfrIdx) |
||||
{ |
||||
NV_ENC_MAP_INPUT_RESOURCE mapInputResource = {}; |
||||
mapInputResource.version = NV_ENC_MAP_INPUT_RESOURCE_VER; |
||||
mapInputResource.registeredResource = m_vRegisteredResources[bfrIdx]; |
||||
NVENC_API_CALL(m_nvenc.nvEncMapInputResource(m_hEncoder, &mapInputResource)); |
||||
m_vMappedInputBuffers[bfrIdx] = mapInputResource.mappedResource; |
||||
} |
||||
|
||||
void NvEncoder::EncodeFrame(std::vector<std::vector<uint8_t>>& vPacket, NV_ENC_PIC_PARAMS* pPicParams) |
||||
{ |
||||
vPacket.clear(); |
||||
if (!IsHWEncoderInitialized()) |
||||
{ |
||||
NVENC_THROW_ERROR("Encoder device not found", NV_ENC_ERR_NO_ENCODE_DEVICE); |
||||
} |
||||
|
||||
int bfrIdx = m_iToSend % m_nEncoderBuffer; |
||||
|
||||
MapResources(bfrIdx); |
||||
|
||||
NVENCSTATUS nvStatus = DoEncode(m_vMappedInputBuffers[bfrIdx], m_vBitstreamOutputBuffer[bfrIdx], pPicParams); |
||||
|
||||
if (nvStatus == NV_ENC_SUCCESS || nvStatus == NV_ENC_ERR_NEED_MORE_INPUT) |
||||
{ |
||||
m_iToSend++; |
||||
GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, true); |
||||
} |
||||
else |
||||
{ |
||||
NVENC_THROW_ERROR("nvEncEncodePicture API failed", nvStatus); |
||||
} |
||||
} |
||||
|
||||
void NvEncoder::GetSequenceParams(std::vector<uint8_t>& seqParams) |
||||
{ |
||||
uint8_t spsppsData[1024]; // Assume maximum spspps data is 1KB or less
|
||||
memset(spsppsData, 0, sizeof(spsppsData)); |
||||
NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = {}; |
||||
payload.version = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER; |
||||
uint32_t spsppsSize = 0; |
||||
|
||||
payload.spsppsBuffer = spsppsData; |
||||
payload.inBufferSize = sizeof(spsppsData); |
||||
payload.outSPSPPSPayloadSize = &spsppsSize; |
||||
NVENC_API_CALL(m_nvenc.nvEncGetSequenceParams(m_hEncoder, &payload)); |
||||
seqParams.clear(); |
||||
seqParams.insert(seqParams.end(), &spsppsData[0], &spsppsData[spsppsSize]); |
||||
} |
||||
|
||||
NVENCSTATUS NvEncoder::DoEncode(NV_ENC_INPUT_PTR inputBuffer, NV_ENC_OUTPUT_PTR outputBuffer, NV_ENC_PIC_PARAMS* pPicParams) |
||||
{ |
||||
NV_ENC_PIC_PARAMS picParams = {}; |
||||
if (pPicParams) |
||||
{ |
||||
picParams = *pPicParams; |
||||
} |
||||
picParams.version = NV_ENC_PIC_PARAMS_VER; |
||||
picParams.pictureStruct = NV_ENC_PIC_STRUCT_FRAME; |
||||
picParams.inputBuffer = inputBuffer; |
||||
picParams.bufferFmt = GetPixelFormat(); |
||||
picParams.inputWidth = GetEncodeWidth(); |
||||
picParams.inputHeight = GetEncodeHeight(); |
||||
picParams.outputBitstream = outputBuffer; |
||||
picParams.completionEvent = GetCompletionEvent(m_iToSend % m_nEncoderBuffer); |
||||
NVENCSTATUS nvStatus = m_nvenc.nvEncEncodePicture(m_hEncoder, &picParams); |
||||
|
||||
return nvStatus; |
||||
} |
||||
|
||||
void NvEncoder::SendEOS() |
||||
{ |
||||
NV_ENC_PIC_PARAMS picParams = {}; |
||||
picParams.version = NV_ENC_PIC_PARAMS_VER; |
||||
|
||||
picParams.encodePicFlags = NV_ENC_PIC_FLAG_EOS; |
||||
picParams.completionEvent = GetCompletionEvent(m_iToSend % m_nEncoderBuffer); |
||||
NVENC_API_CALL(m_nvenc.nvEncEncodePicture(m_hEncoder, &picParams)); |
||||
} |
||||
|
||||
void NvEncoder::EndEncode(std::vector<std::vector<uint8_t>>& vPacket) |
||||
{ |
||||
vPacket.clear(); |
||||
if (!IsHWEncoderInitialized()) |
||||
{ |
||||
NVENC_THROW_ERROR("Encoder device not initialized", NV_ENC_ERR_ENCODER_NOT_INITIALIZED); |
||||
} |
||||
|
||||
SendEOS(); |
||||
|
||||
GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, false); |
||||
} |
||||
|
||||
void NvEncoder::GetEncodedPacket(std::vector<NV_ENC_OUTPUT_PTR>& vOutputBuffer, std::vector<std::vector<uint8_t>>& vPacket, bool bOutputDelay) |
||||
{ |
||||
unsigned i = 0; |
||||
int iEnd = bOutputDelay ? m_iToSend - m_nOutputDelay : m_iToSend; |
||||
for (; m_iGot < iEnd; m_iGot++) |
||||
{ |
||||
WaitForCompletionEvent(m_iGot % m_nEncoderBuffer); |
||||
NV_ENC_LOCK_BITSTREAM lockBitstreamData = {}; |
||||
lockBitstreamData.version = NV_ENC_LOCK_BITSTREAM_VER; |
||||
lockBitstreamData.outputBitstream = vOutputBuffer[m_iGot % m_nEncoderBuffer]; |
||||
lockBitstreamData.doNotWait = false; |
||||
NVENC_API_CALL(m_nvenc.nvEncLockBitstream(m_hEncoder, &lockBitstreamData)); |
||||
|
||||
uint8_t* pData = (uint8_t*)lockBitstreamData.bitstreamBufferPtr; |
||||
if (vPacket.size() < i + 1) |
||||
{ |
||||
vPacket.push_back(std::vector<uint8_t>()); |
||||
} |
||||
vPacket[i].clear(); |
||||
vPacket[i].insert(vPacket[i].end(), &pData[0], &pData[lockBitstreamData.bitstreamSizeInBytes]); |
||||
i++; |
||||
|
||||
NVENC_API_CALL(m_nvenc.nvEncUnlockBitstream(m_hEncoder, lockBitstreamData.outputBitstream)); |
||||
|
||||
if (m_vMappedInputBuffers[m_iGot % m_nEncoderBuffer]) |
||||
{ |
||||
NVENC_API_CALL(m_nvenc.nvEncUnmapInputResource(m_hEncoder, m_vMappedInputBuffers[m_iGot % m_nEncoderBuffer])); |
||||
m_vMappedInputBuffers[m_iGot % m_nEncoderBuffer] = nullptr; |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool NvEncoder::Reconfigure(const NV_ENC_RECONFIGURE_PARAMS* pReconfigureParams) |
||||
{ |
||||
NVENC_API_CALL(m_nvenc.nvEncReconfigureEncoder(m_hEncoder, const_cast<NV_ENC_RECONFIGURE_PARAMS*>(pReconfigureParams))); |
||||
|
||||
memcpy(&m_initializeParams, &(pReconfigureParams->reInitEncodeParams), sizeof(m_initializeParams)); |
||||
if (pReconfigureParams->reInitEncodeParams.encodeConfig) |
||||
{ |
||||
memcpy(&m_encodeConfig, pReconfigureParams->reInitEncodeParams.encodeConfig, sizeof(m_encodeConfig)); |
||||
} |
||||
|
||||
m_nWidth = m_initializeParams.encodeWidth; |
||||
m_nHeight = m_initializeParams.encodeHeight; |
||||
m_nMaxEncodeWidth = m_initializeParams.maxEncodeWidth; |
||||
m_nMaxEncodeHeight = m_initializeParams.maxEncodeHeight; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
NV_ENC_REGISTERED_PTR NvEncoder::RegisterResource(void* pBuffer, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, |
||||
int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, NV_ENC_BUFFER_USAGE bufferUsage, |
||||
NV_ENC_FENCE_POINT_D3D12* pInputFencePoint, NV_ENC_FENCE_POINT_D3D12* pOutputFencePoint) |
||||
{ |
||||
NV_ENC_REGISTER_RESOURCE registerResource = {}; |
||||
registerResource.version = NV_ENC_REGISTER_RESOURCE_VER; |
||||
registerResource.resourceType = eResourceType; |
||||
registerResource.resourceToRegister = pBuffer; |
||||
registerResource.width = width; |
||||
registerResource.height = height; |
||||
registerResource.pitch = pitch; |
||||
registerResource.bufferFormat = bufferFormat; |
||||
registerResource.bufferUsage = bufferUsage; |
||||
registerResource.pInputFencePoint = pInputFencePoint; |
||||
registerResource.pOutputFencePoint = pOutputFencePoint; |
||||
NVENC_API_CALL(m_nvenc.nvEncRegisterResource(m_hEncoder, ®isterResource)); |
||||
|
||||
return registerResource.registeredResource; |
||||
} |
||||
|
||||
void NvEncoder::RegisterInputResources(std::vector<void*> inputframes, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, |
||||
int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, bool bReferenceFrame) |
||||
{ |
||||
for (uint32_t i = 0; i < inputframes.size(); ++i) |
||||
{ |
||||
NV_ENC_REGISTERED_PTR registeredPtr = RegisterResource(inputframes[i], eResourceType, width, height, pitch, bufferFormat, NV_ENC_INPUT_IMAGE); |
||||
|
||||
std::vector<uint32_t> _chromaOffsets; |
||||
NvEncoder::GetChromaSubPlaneOffsets(bufferFormat, pitch, height, _chromaOffsets); |
||||
NvEncInputFrame inputframe = {}; |
||||
inputframe.inputPtr = (void*)inputframes[i]; |
||||
inputframe.chromaOffsets[0] = 0; |
||||
inputframe.chromaOffsets[1] = 0; |
||||
for (uint32_t ch = 0; ch < _chromaOffsets.size(); ch++) |
||||
{ |
||||
inputframe.chromaOffsets[ch] = _chromaOffsets[ch]; |
||||
} |
||||
inputframe.numChromaPlanes = NvEncoder::GetNumChromaPlanes(bufferFormat); |
||||
inputframe.pitch = pitch; |
||||
inputframe.chromaPitch = NvEncoder::GetChromaPitch(bufferFormat, pitch); |
||||
inputframe.bufferFormat = bufferFormat; |
||||
inputframe.resourceType = eResourceType; |
||||
|
||||
if (bReferenceFrame) |
||||
{ |
||||
m_vRegisteredResourcesForReference.push_back(registeredPtr); |
||||
m_vReferenceFrames.push_back(inputframe); |
||||
} |
||||
else |
||||
{ |
||||
m_vRegisteredResources.push_back(registeredPtr); |
||||
m_vInputFrames.push_back(inputframe); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void NvEncoder::FlushEncoder() |
||||
{ |
||||
try |
||||
{ |
||||
std::vector<std::vector<uint8_t>> vPacket; |
||||
EndEncode(vPacket); |
||||
} |
||||
catch (...) |
||||
{ |
||||
|
||||
} |
||||
} |
||||
|
||||
void NvEncoder::UnregisterInputResources() |
||||
{ |
||||
FlushEncoder(); |
||||
|
||||
m_vMappedRefBuffers.clear(); |
||||
|
||||
for (uint32_t i = 0; i < m_vMappedInputBuffers.size(); ++i) |
||||
{ |
||||
if (m_vMappedInputBuffers[i]) |
||||
{ |
||||
m_nvenc.nvEncUnmapInputResource(m_hEncoder, m_vMappedInputBuffers[i]); |
||||
} |
||||
} |
||||
m_vMappedInputBuffers.clear(); |
||||
|
||||
for (uint32_t i = 0; i < m_vRegisteredResources.size(); ++i) |
||||
{ |
||||
if (m_vRegisteredResources[i]) |
||||
{ |
||||
m_nvenc.nvEncUnregisterResource(m_hEncoder, m_vRegisteredResources[i]); |
||||
} |
||||
} |
||||
m_vRegisteredResources.clear(); |
||||
|
||||
|
||||
for (uint32_t i = 0; i < m_vRegisteredResourcesForReference.size(); ++i) |
||||
{ |
||||
if (m_vRegisteredResourcesForReference[i]) |
||||
{ |
||||
m_nvenc.nvEncUnregisterResource(m_hEncoder, m_vRegisteredResourcesForReference[i]); |
||||
} |
||||
} |
||||
m_vRegisteredResourcesForReference.clear(); |
||||
|
||||
} |
||||
|
||||
|
||||
void NvEncoder::WaitForCompletionEvent(int iEvent) |
||||
{ |
||||
#if defined(_WIN32) |
||||
// Check if we are in async mode. If not, don't wait for event;
|
||||
NV_ENC_CONFIG sEncodeConfig = { 0 }; |
||||
NV_ENC_INITIALIZE_PARAMS sInitializeParams = { 0 }; |
||||
sInitializeParams.encodeConfig = &sEncodeConfig; |
||||
GetInitializeParams(&sInitializeParams); |
||||
|
||||
if (0U == sInitializeParams.enableEncodeAsync) |
||||
{ |
||||
return; |
||||
} |
||||
#ifdef DEBUG |
||||
WaitForSingleObject(m_vpCompletionEvent[iEvent], INFINITE); |
||||
#else |
||||
// wait for 20s which is infinite on terms of gpu time
|
||||
if (WaitForSingleObject(m_vpCompletionEvent[iEvent], 20000) == WAIT_FAILED) |
||||
{ |
||||
NVENC_THROW_ERROR("Failed to encode frame", NV_ENC_ERR_GENERIC); |
||||
} |
||||
#endif |
||||
#endif |
||||
} |
||||
|
||||
uint32_t NvEncoder::GetWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t width) |
||||
{ |
||||
switch (bufferFormat) { |
||||
case NV_ENC_BUFFER_FORMAT_NV12: |
||||
case NV_ENC_BUFFER_FORMAT_YV12: |
||||
case NV_ENC_BUFFER_FORMAT_IYUV: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444: |
||||
return width; |
||||
case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: |
||||
return width * 2; |
||||
case NV_ENC_BUFFER_FORMAT_ARGB: |
||||
case NV_ENC_BUFFER_FORMAT_ARGB10: |
||||
case NV_ENC_BUFFER_FORMAT_AYUV: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR10: |
||||
return width * 4; |
||||
default: |
||||
NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
uint32_t NvEncoder::GetNumChromaPlanes(const NV_ENC_BUFFER_FORMAT bufferFormat) |
||||
{ |
||||
switch (bufferFormat) |
||||
{ |
||||
case NV_ENC_BUFFER_FORMAT_NV12: |
||||
case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: |
||||
return 1; |
||||
case NV_ENC_BUFFER_FORMAT_YV12: |
||||
case NV_ENC_BUFFER_FORMAT_IYUV: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: |
||||
return 2; |
||||
case NV_ENC_BUFFER_FORMAT_ARGB: |
||||
case NV_ENC_BUFFER_FORMAT_ARGB10: |
||||
case NV_ENC_BUFFER_FORMAT_AYUV: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR10: |
||||
return 0; |
||||
default: |
||||
NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
uint32_t NvEncoder::GetChromaPitch(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaPitch) |
||||
{ |
||||
switch (bufferFormat) |
||||
{ |
||||
case NV_ENC_BUFFER_FORMAT_NV12: |
||||
case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: |
||||
return lumaPitch; |
||||
case NV_ENC_BUFFER_FORMAT_YV12: |
||||
case NV_ENC_BUFFER_FORMAT_IYUV: |
||||
return (lumaPitch + 1) / 2; |
||||
case NV_ENC_BUFFER_FORMAT_ARGB: |
||||
case NV_ENC_BUFFER_FORMAT_ARGB10: |
||||
case NV_ENC_BUFFER_FORMAT_AYUV: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR10: |
||||
return 0; |
||||
default: |
||||
NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
void NvEncoder::GetChromaSubPlaneOffsets(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t pitch, const uint32_t height, std::vector<uint32_t>& chromaOffsets) |
||||
{ |
||||
chromaOffsets.clear(); |
||||
switch (bufferFormat) |
||||
{ |
||||
case NV_ENC_BUFFER_FORMAT_NV12: |
||||
case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: |
||||
chromaOffsets.push_back(pitch * height); |
||||
return; |
||||
case NV_ENC_BUFFER_FORMAT_YV12: |
||||
case NV_ENC_BUFFER_FORMAT_IYUV: |
||||
chromaOffsets.push_back(pitch * height); |
||||
chromaOffsets.push_back(chromaOffsets[0] + (NvEncoder::GetChromaPitch(bufferFormat, pitch) * GetChromaHeight(bufferFormat, height))); |
||||
return; |
||||
case NV_ENC_BUFFER_FORMAT_YUV444: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: |
||||
chromaOffsets.push_back(pitch * height); |
||||
chromaOffsets.push_back(chromaOffsets[0] + (pitch * height)); |
||||
return; |
||||
case NV_ENC_BUFFER_FORMAT_ARGB: |
||||
case NV_ENC_BUFFER_FORMAT_ARGB10: |
||||
case NV_ENC_BUFFER_FORMAT_AYUV: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR10: |
||||
return; |
||||
default: |
||||
NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
uint32_t NvEncoder::GetChromaHeight(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaHeight) |
||||
{ |
||||
switch (bufferFormat) |
||||
{ |
||||
case NV_ENC_BUFFER_FORMAT_YV12: |
||||
case NV_ENC_BUFFER_FORMAT_IYUV: |
||||
case NV_ENC_BUFFER_FORMAT_NV12: |
||||
case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: |
||||
return (lumaHeight + 1) / 2; |
||||
case NV_ENC_BUFFER_FORMAT_YUV444: |
||||
case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: |
||||
return lumaHeight; |
||||
case NV_ENC_BUFFER_FORMAT_ARGB: |
||||
case NV_ENC_BUFFER_FORMAT_ARGB10: |
||||
case NV_ENC_BUFFER_FORMAT_AYUV: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR10: |
||||
return 0; |
||||
default: |
||||
NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
uint32_t NvEncoder::GetChromaWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaWidth) |
||||
{ |
||||
switch (bufferFormat) |
||||
{ |
||||
case NV_ENC_BUFFER_FORMAT_YV12: |
||||
case NV_ENC_BUFFER_FORMAT_IYUV: |
||||
return (lumaWidth + 1) / 2; |
||||
case NV_ENC_BUFFER_FORMAT_NV12: |
||||
return lumaWidth; |
||||
case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: |
||||
return 2 * lumaWidth; |
||||
case NV_ENC_BUFFER_FORMAT_YUV444: |
||||
return lumaWidth; |
||||
case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: |
||||
return 2 * lumaWidth; |
||||
case NV_ENC_BUFFER_FORMAT_ARGB: |
||||
case NV_ENC_BUFFER_FORMAT_ARGB10: |
||||
case NV_ENC_BUFFER_FORMAT_AYUV: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR10: |
||||
return 0; |
||||
default: |
||||
NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
|
||||
int NvEncoder::GetCapabilityValue(GUID guidCodec, NV_ENC_CAPS capsToQuery) |
||||
{ |
||||
if (!m_hEncoder) |
||||
{ |
||||
return 0; |
||||
} |
||||
NV_ENC_CAPS_PARAM capsParam = {}; |
||||
capsParam.version = NV_ENC_CAPS_PARAM_VER; |
||||
capsParam.capsToQuery = capsToQuery; |
||||
int v; |
||||
m_nvenc.nvEncGetEncodeCaps(m_hEncoder, guidCodec, &capsParam, &v); |
||||
return v; |
||||
} |
||||
|
||||
int NvEncoder::GetFrameSize() const |
||||
{ |
||||
switch (GetPixelFormat()) |
||||
{ |
||||
case NV_ENC_BUFFER_FORMAT_YV12: |
||||
case NV_ENC_BUFFER_FORMAT_IYUV: |
||||
case NV_ENC_BUFFER_FORMAT_NV12: |
||||
return GetEncodeWidth() * (GetEncodeHeight() + (GetEncodeHeight() + 1) / 2); |
||||
case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: |
||||
return 2 * GetEncodeWidth() * (GetEncodeHeight() + (GetEncodeHeight() + 1) / 2); |
||||
case NV_ENC_BUFFER_FORMAT_YUV444: |
||||
return GetEncodeWidth() * GetEncodeHeight() * 3; |
||||
case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: |
||||
return 2 * GetEncodeWidth() * GetEncodeHeight() * 3; |
||||
case NV_ENC_BUFFER_FORMAT_ARGB: |
||||
case NV_ENC_BUFFER_FORMAT_ARGB10: |
||||
case NV_ENC_BUFFER_FORMAT_AYUV: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR: |
||||
case NV_ENC_BUFFER_FORMAT_ABGR10: |
||||
return 4 * GetEncodeWidth() * GetEncodeHeight(); |
||||
default: |
||||
NVENC_THROW_ERROR("Invalid Buffer format", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
} |
||||
|
||||
void NvEncoder::GetInitializeParams(NV_ENC_INITIALIZE_PARAMS* pInitializeParams) |
||||
{ |
||||
if (!pInitializeParams || !pInitializeParams->encodeConfig) |
||||
{ |
||||
NVENC_THROW_ERROR("Both pInitializeParams and pInitializeParams->encodeConfig can't be NULL", NV_ENC_ERR_INVALID_PTR); |
||||
} |
||||
NV_ENC_CONFIG* pEncodeConfig = pInitializeParams->encodeConfig; |
||||
*pEncodeConfig = m_encodeConfig; |
||||
*pInitializeParams = m_initializeParams; |
||||
pInitializeParams->encodeConfig = pEncodeConfig; |
||||
} |
||||
|
||||
void NvEncoder::InitializeBitstreamBuffer() |
||||
{ |
||||
for (int i = 0; i < m_nEncoderBuffer; i++) |
||||
{ |
||||
NV_ENC_CREATE_BITSTREAM_BUFFER createBitstreamBuffer = {}; |
||||
createBitstreamBuffer.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER; |
||||
NVENC_API_CALL(m_nvenc.nvEncCreateBitstreamBuffer(m_hEncoder, &createBitstreamBuffer)); |
||||
m_vBitstreamOutputBuffer[i] = createBitstreamBuffer.bitstreamBuffer; |
||||
} |
||||
} |
||||
|
||||
void NvEncoder::DestroyBitstreamBuffer() |
||||
{ |
||||
for (uint32_t i = 0; i < m_vBitstreamOutputBuffer.size(); i++) |
||||
{ |
||||
if (m_vBitstreamOutputBuffer[i]) |
||||
{ |
||||
m_nvenc.nvEncDestroyBitstreamBuffer(m_hEncoder, m_vBitstreamOutputBuffer[i]); |
||||
} |
||||
} |
||||
|
||||
m_vBitstreamOutputBuffer.clear(); |
||||
} |
||||
}} |
||||
#endif |
@ -0,0 +1,377 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_NVENCODER_HPP |
||||
#define OPENCV_NVENCODER_HPP |
||||
#include <vector> |
||||
#include "nvEncodeAPI.h" |
||||
#include <stdint.h> |
||||
#include <mutex> |
||||
#include <string> |
||||
#include <iostream> |
||||
#include <sstream> |
||||
#include <string.h> |
||||
|
||||
namespace cv { namespace cudacodec { |
||||
|
||||
#define NVENC_THROW_ERROR( errorStr, errorCode ) \ |
||||
do \
|
||||
{ \
|
||||
cv::String msg = cv::format("%s [Code = %d]", errorStr, errorCode); \
|
||||
cv::error(cv::Error::GpuApiCallError, msg, __FUNCTION__, __FILE__, __LINE__); \
|
||||
} while (0) |
||||
|
||||
|
||||
#define NVENC_API_CALL( nvencAPI ) \ |
||||
do \
|
||||
{ \
|
||||
NVENCSTATUS errorCode = nvencAPI; \
|
||||
if( errorCode != NV_ENC_SUCCESS) \
|
||||
{ \
|
||||
cv::String msg = cv::format("NVENC returned error [Code = %d]", errorCode); \
|
||||
cv::error(cv::Error::GpuApiCallError, msg, __FUNCTION__, __FILE__, __LINE__); \
|
||||
} \
|
||||
} while (0) |
||||
|
||||
struct NvEncInputFrame |
||||
{ |
||||
void* inputPtr = nullptr; |
||||
uint32_t chromaOffsets[2]; |
||||
uint32_t numChromaPlanes; |
||||
uint32_t pitch; |
||||
uint32_t chromaPitch; |
||||
NV_ENC_BUFFER_FORMAT bufferFormat; |
||||
NV_ENC_INPUT_RESOURCE_TYPE resourceType; |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Shared base class for different encoder interfaces. |
||||
*/ |
||||
class NvEncoder |
||||
{ |
||||
public: |
||||
/**
|
||||
* @brief This function is used to initialize the encoder session. |
||||
* Application must call this function to initialize the encoder, before |
||||
* starting to encode any frames. |
||||
*/ |
||||
virtual void CreateEncoder(const NV_ENC_INITIALIZE_PARAMS* pEncodeParams); |
||||
|
||||
/**
|
||||
* @brief This function is used to destroy the encoder session. |
||||
* Application must call this function to destroy the encoder session and |
||||
* clean up any allocated resources. The application must call EndEncode() |
||||
* function to get any queued encoded frames before calling DestroyEncoder(). |
||||
*/ |
||||
virtual void DestroyEncoder(); |
||||
|
||||
/**
|
||||
* @brief This function is used to reconfigure an existing encoder session. |
||||
* Application can use this function to dynamically change the bitrate, |
||||
* resolution and other QOS parameters. If the application changes the |
||||
* resolution, it must set NV_ENC_RECONFIGURE_PARAMS::forceIDR. |
||||
*/ |
||||
bool Reconfigure(const NV_ENC_RECONFIGURE_PARAMS* pReconfigureParams); |
||||
|
||||
/**
|
||||
* @brief This function is used to get the next available input buffer. |
||||
* Applications must call this function to obtain a pointer to the next |
||||
* input buffer. The application must copy the uncompressed data to the |
||||
* input buffer and then call EncodeFrame() function to encode it. |
||||
*/ |
||||
const NvEncInputFrame* GetNextInputFrame(); |
||||
|
||||
|
||||
/**
|
||||
* @brief This function is used to encode a frame. |
||||
* Applications must call EncodeFrame() function to encode the uncompressed |
||||
* data, which has been copied to an input buffer obtained from the |
||||
* GetNextInputFrame() function. |
||||
*/ |
||||
virtual void EncodeFrame(std::vector<std::vector<uint8_t>>& vPacket, NV_ENC_PIC_PARAMS* pPicParams = nullptr); |
||||
|
||||
/**
|
||||
* @brief This function to flush the encoder queue. |
||||
* The encoder might be queuing frames for B picture encoding or lookahead; |
||||
* the application must call EndEncode() to get all the queued encoded frames |
||||
* from the encoder. The application must call this function before destroying |
||||
* an encoder session. |
||||
*/ |
||||
virtual void EndEncode(std::vector<std::vector<uint8_t>>& vPacket); |
||||
|
||||
/**
|
||||
* @brief This function is used to query hardware encoder capabilities. |
||||
* Applications can call this function to query capabilities like maximum encode |
||||
* dimensions, support for lookahead or the ME-only mode etc. |
||||
*/ |
||||
int GetCapabilityValue(GUID guidCodec, NV_ENC_CAPS capsToQuery); |
||||
|
||||
/**
|
||||
* @brief This function is used to get the current device on which encoder is running. |
||||
*/ |
||||
void* GetDevice() const { return m_pDevice; } |
||||
|
||||
/**
|
||||
* @brief This function is used to get the current device type which encoder is running. |
||||
*/ |
||||
NV_ENC_DEVICE_TYPE GetDeviceType() const { return m_eDeviceType; } |
||||
|
||||
/**
|
||||
* @brief This function is used to get the current encode width. |
||||
* The encode width can be modified by Reconfigure() function. |
||||
*/ |
||||
int GetEncodeWidth() const { return m_nWidth; } |
||||
|
||||
/**
|
||||
* @brief This function is used to get the current encode height. |
||||
* The encode height can be modified by Reconfigure() function. |
||||
*/ |
||||
int GetEncodeHeight() const { return m_nHeight; } |
||||
|
||||
/**
|
||||
* @brief This function is used to get the current frame size based on pixel format. |
||||
*/ |
||||
int GetFrameSize() const; |
||||
|
||||
/**
|
||||
* @brief This function is used to initialize config parameters based on |
||||
* given codec and preset guids. |
||||
* The application can call this function to get the default configuration |
||||
* for a certain preset. The application can either use these parameters |
||||
* directly or override them with application-specific settings before |
||||
* using them in CreateEncoder() function. |
||||
*/ |
||||
void CreateDefaultEncoderParams(NV_ENC_INITIALIZE_PARAMS* pIntializeParams, GUID codecGuid, GUID presetGuid, NV_ENC_TUNING_INFO tuningInfo = NV_ENC_TUNING_INFO_UNDEFINED); |
||||
|
||||
/**
|
||||
* @brief This function is used to get the current initialization parameters, |
||||
* which had been used to configure the encoder session. |
||||
* The initialization parameters are modified if the application calls |
||||
* Reconfigure() function. |
||||
*/ |
||||
void GetInitializeParams(NV_ENC_INITIALIZE_PARAMS* pInitializeParams); |
||||
|
||||
/**
|
||||
* @brief This function is used to get sequence and picture parameter headers. |
||||
* Application can call this function after encoder is initialized to get SPS and PPS |
||||
* nalus for the current encoder instance. The sequence header data might change when |
||||
* application calls Reconfigure() function. |
||||
*/ |
||||
void GetSequenceParams(std::vector<uint8_t>& seqParams); |
||||
|
||||
/**
|
||||
* @brief NvEncoder class virtual destructor. |
||||
*/ |
||||
virtual ~NvEncoder(); |
||||
|
||||
public: |
||||
/**
|
||||
* @brief This a static function to get chroma offsets for YUV planar formats. |
||||
*/ |
||||
static void GetChromaSubPlaneOffsets(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t pitch, |
||||
const uint32_t height, std::vector<uint32_t>& chromaOffsets); |
||||
/**
|
||||
* @brief This a static function to get the chroma plane pitch for YUV planar formats. |
||||
*/ |
||||
static uint32_t GetChromaPitch(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaPitch); |
||||
|
||||
/**
|
||||
* @brief This a static function to get the number of chroma planes for YUV planar formats. |
||||
*/ |
||||
static uint32_t GetNumChromaPlanes(const NV_ENC_BUFFER_FORMAT bufferFormat); |
||||
|
||||
/**
|
||||
* @brief This a static function to get the chroma plane width in bytes for YUV planar formats. |
||||
*/ |
||||
static uint32_t GetChromaWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaWidth); |
||||
|
||||
/**
|
||||
* @brief This a static function to get the chroma planes height in bytes for YUV planar formats. |
||||
*/ |
||||
static uint32_t GetChromaHeight(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t lumaHeight); |
||||
|
||||
|
||||
/**
|
||||
* @brief This a static function to get the width in bytes for the frame. |
||||
* For YUV planar format this is the width in bytes of the luma plane. |
||||
*/ |
||||
static uint32_t GetWidthInBytes(const NV_ENC_BUFFER_FORMAT bufferFormat, const uint32_t width); |
||||
|
||||
/**
|
||||
* @brief This function returns the number of allocated buffers. |
||||
*/ |
||||
uint32_t GetEncoderBufferCount() const { return m_nEncoderBuffer; } |
||||
protected: |
||||
|
||||
/**
|
||||
* @brief NvEncoder class constructor. |
||||
* NvEncoder class constructor cannot be called directly by the application. |
||||
*/ |
||||
NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void* pDevice, uint32_t nWidth, uint32_t nHeight, |
||||
NV_ENC_BUFFER_FORMAT eBufferFormat, uint32_t nOutputDelay); |
||||
|
||||
/**
|
||||
* @brief This function is used to check if hardware encoder is properly initialized. |
||||
*/ |
||||
bool IsHWEncoderInitialized() const { return m_hEncoder != NULL && m_bEncoderInitialized; } |
||||
|
||||
/**
|
||||
* @brief This function is used to register CUDA, D3D or OpenGL input buffers with NvEncodeAPI. |
||||
* This is non public function and is called by derived class for allocating |
||||
* and registering input buffers. |
||||
*/ |
||||
void RegisterInputResources(std::vector<void*> inputframes, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, |
||||
int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, bool bReferenceFrame = false); |
||||
|
||||
/**
|
||||
* @brief This function is used to unregister resources which had been previously registered for encoding |
||||
* using RegisterInputResources() function. |
||||
*/ |
||||
void UnregisterInputResources(); |
||||
|
||||
/**
|
||||
* @brief This function is used to register CUDA, D3D or OpenGL input or output buffers with NvEncodeAPI. |
||||
*/ |
||||
NV_ENC_REGISTERED_PTR RegisterResource(void* pBuffer, NV_ENC_INPUT_RESOURCE_TYPE eResourceType, |
||||
int width, int height, int pitch, NV_ENC_BUFFER_FORMAT bufferFormat, NV_ENC_BUFFER_USAGE bufferUsage = NV_ENC_INPUT_IMAGE, |
||||
NV_ENC_FENCE_POINT_D3D12* pInputFencePoint = NULL, NV_ENC_FENCE_POINT_D3D12* pOutputFencePoint = NULL); |
||||
|
||||
/**
|
||||
* @brief This function returns maximum width used to open the encoder session. |
||||
* All encode input buffers are allocated using maximum dimensions. |
||||
*/ |
||||
uint32_t GetMaxEncodeWidth() const { return m_nMaxEncodeWidth; } |
||||
|
||||
/**
|
||||
* @brief This function returns maximum height used to open the encoder session. |
||||
* All encode input buffers are allocated using maximum dimensions. |
||||
*/ |
||||
uint32_t GetMaxEncodeHeight() const { return m_nMaxEncodeHeight; } |
||||
|
||||
/**
|
||||
* @brief This function returns the completion event. |
||||
*/ |
||||
void* GetCompletionEvent(uint32_t eventIdx) { return (m_vpCompletionEvent.size() == m_nEncoderBuffer) ? m_vpCompletionEvent[eventIdx] : nullptr; } |
||||
|
||||
/**
|
||||
* @brief This function returns the current pixel format. |
||||
*/ |
||||
NV_ENC_BUFFER_FORMAT GetPixelFormat() const { return m_eBufferFormat; } |
||||
|
||||
/**
|
||||
* @brief This function is used to submit the encode commands to the |
||||
* NVENC hardware. |
||||
*/ |
||||
NVENCSTATUS DoEncode(NV_ENC_INPUT_PTR inputBuffer, NV_ENC_OUTPUT_PTR outputBuffer, NV_ENC_PIC_PARAMS* pPicParams); |
||||
|
||||
/**
|
||||
* @brief This function is used to submit the encode commands to the |
||||
* NVENC hardware for ME only mode. |
||||
*/ |
||||
//NVENCSTATUS DoMotionEstimation(NV_ENC_INPUT_PTR inputBuffer, NV_ENC_INPUT_PTR inputBufferForReference, NV_ENC_OUTPUT_PTR outputBuffer);
|
||||
|
||||
/**
|
||||
* @brief This function is used to map the input buffers to NvEncodeAPI. |
||||
*/ |
||||
void MapResources(uint32_t bfrIdx); |
||||
|
||||
/**
|
||||
* @brief This function is used to wait for completion of encode command. |
||||
*/ |
||||
void WaitForCompletionEvent(int iEvent); |
||||
|
||||
/**
|
||||
* @brief This function is used to send EOS to HW encoder. |
||||
*/ |
||||
void SendEOS(); |
||||
|
||||
private: |
||||
/**
|
||||
* @brief This is a private function which is used to check if there is any |
||||
buffering done by encoder. |
||||
* The encoder generally buffers data to encode B frames or for lookahead |
||||
* or pipelining. |
||||
*/ |
||||
bool IsZeroDelay() { return m_nOutputDelay == 0; } |
||||
|
||||
/**
|
||||
* @brief This is a private function which is used to load the encode api shared library. |
||||
*/ |
||||
void LoadNvEncApi(); |
||||
|
||||
/**
|
||||
* @brief This is a private function which is used to get the output packets |
||||
* from the encoder HW. |
||||
* This is called by DoEncode() function. If there is buffering enabled, |
||||
* this may return without any output data. |
||||
*/ |
||||
void GetEncodedPacket(std::vector<NV_ENC_OUTPUT_PTR>& vOutputBuffer, std::vector<std::vector<uint8_t>>& vPacket, bool bOutputDelay); |
||||
|
||||
/**
|
||||
* @brief This is a private function which is used to initialize the bitstream buffers. |
||||
* This is only used in the encoding mode. |
||||
*/ |
||||
void InitializeBitstreamBuffer(); |
||||
|
||||
/**
|
||||
* @brief This is a private function which is used to destroy the bitstream buffers. |
||||
* This is only used in the encoding mode. |
||||
*/ |
||||
void DestroyBitstreamBuffer(); |
||||
|
||||
/**
|
||||
* @brief This is a private function which is used to destroy HW encoder. |
||||
*/ |
||||
void DestroyHWEncoder(); |
||||
|
||||
/**
|
||||
* @brief This function is used to flush the encoder queue. |
||||
*/ |
||||
void FlushEncoder(); |
||||
|
||||
private: |
||||
/**
|
||||
* @brief This is a pure virtual function which is used to allocate input buffers. |
||||
* The derived classes must implement this function. |
||||
*/ |
||||
virtual void AllocateInputBuffers(int32_t numInputBuffers) = 0; |
||||
|
||||
/**
|
||||
* @brief This is a pure virtual function which is used to destroy input buffers. |
||||
* The derived classes must implement this function. |
||||
*/ |
||||
virtual void ReleaseInputBuffers() = 0; |
||||
|
||||
protected: |
||||
void* m_hEncoder = nullptr; |
||||
NV_ENCODE_API_FUNCTION_LIST m_nvenc; |
||||
std::vector<NvEncInputFrame> m_vInputFrames; |
||||
std::vector<NV_ENC_REGISTERED_PTR> m_vRegisteredResources; |
||||
std::vector<NvEncInputFrame> m_vReferenceFrames; |
||||
std::vector<NV_ENC_REGISTERED_PTR> m_vRegisteredResourcesForReference; |
||||
std::vector<NV_ENC_INPUT_PTR> m_vMappedInputBuffers; |
||||
std::vector<NV_ENC_INPUT_PTR> m_vMappedRefBuffers; |
||||
std::vector<void*> m_vpCompletionEvent; |
||||
|
||||
int32_t m_iToSend = 0; |
||||
int32_t m_iGot = 0; |
||||
int32_t m_nEncoderBuffer = 0; |
||||
int32_t m_nOutputDelay = 0; |
||||
|
||||
private: |
||||
void* m_pDevice; |
||||
NV_ENC_DEVICE_TYPE m_eDeviceType; |
||||
uint32_t m_nWidth; |
||||
uint32_t m_nHeight; |
||||
uint32_t m_nMaxEncodeWidth = 0; |
||||
uint32_t m_nMaxEncodeHeight = 0; |
||||
NV_ENC_BUFFER_FORMAT m_eBufferFormat; |
||||
NV_ENC_INITIALIZE_PARAMS m_initializeParams = {}; |
||||
NV_ENC_CONFIG m_encodeConfig = {}; |
||||
bool m_bEncoderInitialized = false; |
||||
uint32_t m_nExtraOutputDelay = 3; // To ensure encode and graphics can work in parallel, m_nExtraOutputDelay should be set to at least 1
|
||||
std::vector<NV_ENC_OUTPUT_PTR> m_vBitstreamOutputBuffer; |
||||
}; |
||||
}} |
||||
#endif |
@ -0,0 +1,196 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "precomp.hpp" |
||||
|
||||
#if defined(HAVE_NVCUVENC) |
||||
#include "NvEncoderCuda.h" |
||||
|
||||
namespace cv { namespace cudacodec { |
||||
NvEncoderCuda::NvEncoderCuda(CUcontext cuContext, uint32_t nWidth, uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat, |
||||
uint32_t nExtraOutputDelay) : |
||||
NvEncoder(NV_ENC_DEVICE_TYPE_CUDA, cuContext, nWidth, nHeight, eBufferFormat, nExtraOutputDelay), |
||||
m_cuContext(cuContext) |
||||
{ |
||||
if (!m_hEncoder) |
||||
{ |
||||
NVENC_THROW_ERROR("Encoder Initialization failed", NV_ENC_ERR_INVALID_DEVICE); |
||||
} |
||||
|
||||
if (!m_cuContext) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid Cuda Context", NV_ENC_ERR_INVALID_DEVICE); |
||||
} |
||||
} |
||||
|
||||
NvEncoderCuda::~NvEncoderCuda() |
||||
{ |
||||
ReleaseCudaResources(); |
||||
} |
||||
|
||||
void NvEncoderCuda::AllocateInputBuffers(int32_t numInputBuffers) |
||||
{ |
||||
if (!IsHWEncoderInitialized()) |
||||
{ |
||||
NVENC_THROW_ERROR("Encoder intialization failed", NV_ENC_ERR_ENCODER_NOT_INITIALIZED); |
||||
} |
||||
|
||||
cuSafeCall(cuCtxPushCurrent(m_cuContext)); |
||||
std::vector<void*> inputFrames; |
||||
for (int i = 0; i < numInputBuffers; i++) |
||||
{ |
||||
CUdeviceptr pDeviceFrame; |
||||
uint32_t chromaHeight = GetNumChromaPlanes(GetPixelFormat()) * GetChromaHeight(GetPixelFormat(), GetMaxEncodeHeight()); |
||||
if (GetPixelFormat() == NV_ENC_BUFFER_FORMAT_YV12 || GetPixelFormat() == NV_ENC_BUFFER_FORMAT_IYUV) |
||||
chromaHeight = GetChromaHeight(GetPixelFormat(), GetMaxEncodeHeight()); |
||||
cuSafeCall(cuMemAllocPitch((CUdeviceptr*)&pDeviceFrame, |
||||
&m_cudaPitch, |
||||
GetWidthInBytes(GetPixelFormat(), GetMaxEncodeWidth()), |
||||
GetMaxEncodeHeight() + chromaHeight, 16)); |
||||
inputFrames.push_back((void*)pDeviceFrame); |
||||
} |
||||
cuSafeCall(cuCtxPopCurrent(NULL)); |
||||
|
||||
RegisterInputResources(inputFrames, |
||||
NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR, |
||||
GetMaxEncodeWidth(), |
||||
GetMaxEncodeHeight(), |
||||
(int)m_cudaPitch, |
||||
GetPixelFormat(), |
||||
false); |
||||
} |
||||
|
||||
void NvEncoderCuda::SetIOCudaStreams(NV_ENC_CUSTREAM_PTR inputStream, NV_ENC_CUSTREAM_PTR outputStream) |
||||
{ |
||||
NVENC_API_CALL(m_nvenc.nvEncSetIOCudaStreams(m_hEncoder, inputStream, outputStream)); |
||||
} |
||||
|
||||
void NvEncoderCuda::ReleaseInputBuffers() |
||||
{ |
||||
ReleaseCudaResources(); |
||||
} |
||||
|
||||
void NvEncoderCuda::ReleaseCudaResources() |
||||
{ |
||||
if (!m_hEncoder) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
if (!m_cuContext) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
UnregisterInputResources(); |
||||
|
||||
cuCtxPushCurrent(m_cuContext); |
||||
|
||||
for (uint32_t i = 0; i < m_vInputFrames.size(); ++i) |
||||
{ |
||||
if (m_vInputFrames[i].inputPtr) |
||||
{ |
||||
cuMemFree(reinterpret_cast<CUdeviceptr>(m_vInputFrames[i].inputPtr)); |
||||
} |
||||
} |
||||
m_vInputFrames.clear(); |
||||
|
||||
for (uint32_t i = 0; i < m_vReferenceFrames.size(); ++i) |
||||
{ |
||||
if (m_vReferenceFrames[i].inputPtr) |
||||
{ |
||||
cuMemFree(reinterpret_cast<CUdeviceptr>(m_vReferenceFrames[i].inputPtr)); |
||||
} |
||||
} |
||||
m_vReferenceFrames.clear(); |
||||
|
||||
cuCtxPopCurrent(NULL); |
||||
m_cuContext = nullptr; |
||||
} |
||||
|
||||
void NvEncoderCuda::CopyToDeviceFrame(CUcontext device, |
||||
void* pSrcFrame, |
||||
uint32_t nSrcPitch, |
||||
CUdeviceptr pDstFrame, |
||||
uint32_t dstPitch, |
||||
int width, |
||||
int height, |
||||
CUmemorytype srcMemoryType, |
||||
NV_ENC_BUFFER_FORMAT pixelFormat, |
||||
const uint32_t dstChromaOffsets[], |
||||
uint32_t numChromaPlanes, |
||||
bool bUnAlignedDeviceCopy, |
||||
CUstream stream) |
||||
{ |
||||
if (srcMemoryType != CU_MEMORYTYPE_HOST && srcMemoryType != CU_MEMORYTYPE_DEVICE) |
||||
{ |
||||
NVENC_THROW_ERROR("Invalid source memory type for copy", NV_ENC_ERR_INVALID_PARAM); |
||||
} |
||||
|
||||
cuSafeCall(cuCtxPushCurrent(device)); |
||||
|
||||
uint32_t srcPitch = nSrcPitch ? nSrcPitch : NvEncoder::GetWidthInBytes(pixelFormat, width); |
||||
CUDA_MEMCPY2D m = {}; |
||||
m.srcMemoryType = srcMemoryType; |
||||
if (srcMemoryType == CU_MEMORYTYPE_HOST) |
||||
{ |
||||
m.srcHost = pSrcFrame; |
||||
} |
||||
else |
||||
{ |
||||
m.srcDevice = (CUdeviceptr)pSrcFrame; |
||||
} |
||||
m.srcPitch = srcPitch; |
||||
m.dstMemoryType = CU_MEMORYTYPE_DEVICE; |
||||
m.dstDevice = pDstFrame; |
||||
m.dstPitch = dstPitch; |
||||
m.WidthInBytes = NvEncoder::GetWidthInBytes(pixelFormat, width); |
||||
m.Height = height; |
||||
if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) |
||||
{ |
||||
cuSafeCall(cuMemcpy2DUnaligned(&m)); |
||||
} |
||||
else |
||||
{ |
||||
cuSafeCall(stream == NULL ? cuMemcpy2D(&m) : cuMemcpy2DAsync(&m, stream)); |
||||
} |
||||
|
||||
std::vector<uint32_t> srcChromaOffsets; |
||||
NvEncoder::GetChromaSubPlaneOffsets(pixelFormat, srcPitch, height, srcChromaOffsets); |
||||
uint32_t chromaHeight = NvEncoder::GetChromaHeight(pixelFormat, height); |
||||
uint32_t destChromaPitch = NvEncoder::GetChromaPitch(pixelFormat, dstPitch); |
||||
uint32_t srcChromaPitch = NvEncoder::GetChromaPitch(pixelFormat, srcPitch); |
||||
uint32_t chromaWidthInBytes = NvEncoder::GetChromaWidthInBytes(pixelFormat, width); |
||||
|
||||
for (uint32_t i = 0; i < numChromaPlanes; ++i) |
||||
{ |
||||
if (chromaHeight) |
||||
{ |
||||
if (srcMemoryType == CU_MEMORYTYPE_HOST) |
||||
{ |
||||
m.srcHost = ((uint8_t*)pSrcFrame + srcChromaOffsets[i]); |
||||
} |
||||
else |
||||
{ |
||||
m.srcDevice = (CUdeviceptr)((uint8_t*)pSrcFrame + srcChromaOffsets[i]); |
||||
} |
||||
m.srcPitch = srcChromaPitch; |
||||
|
||||
m.dstDevice = (CUdeviceptr)((uint8_t*)pDstFrame + dstChromaOffsets[i]); |
||||
m.dstPitch = destChromaPitch; |
||||
m.WidthInBytes = chromaWidthInBytes; |
||||
m.Height = chromaHeight; |
||||
if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) |
||||
{ |
||||
cuSafeCall(cuMemcpy2DUnaligned(&m)); |
||||
} |
||||
else |
||||
{ |
||||
cuSafeCall(stream == NULL ? cuMemcpy2D(&m) : cuMemcpy2DAsync(&m, stream)); |
||||
} |
||||
} |
||||
} |
||||
cuSafeCall(cuCtxPopCurrent(NULL)); |
||||
} |
||||
}} |
||||
#endif |
@ -0,0 +1,75 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_NVENCODERCUDA_HPP |
||||
#define OPENCV_NVENCODERCUDA_HPP |
||||
#include <vector> |
||||
#include <stdint.h> |
||||
#include <mutex> |
||||
#include <cuda.h> |
||||
#include "NvEncoder.h" |
||||
|
||||
namespace cv { namespace cudacodec { |
||||
|
||||
/**
|
||||
* @brief Encoder for CUDA device memory. |
||||
*/ |
||||
class NvEncoderCuda : public NvEncoder |
||||
{ |
||||
public: |
||||
NvEncoderCuda(CUcontext cuContext, uint32_t nWidth, uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat, |
||||
uint32_t nExtraOutputDelay = 3); |
||||
virtual ~NvEncoderCuda(); |
||||
|
||||
/**
|
||||
* @brief This is a static function to copy input data from host memory to device memory. |
||||
* This function assumes YUV plane is a single contiguous memory segment. |
||||
*/ |
||||
static void CopyToDeviceFrame(CUcontext device, |
||||
void* pSrcFrame, |
||||
uint32_t nSrcPitch, |
||||
CUdeviceptr pDstFrame, |
||||
uint32_t dstPitch, |
||||
int width, |
||||
int height, |
||||
CUmemorytype srcMemoryType, |
||||
NV_ENC_BUFFER_FORMAT pixelFormat, |
||||
const uint32_t dstChromaOffsets[], |
||||
uint32_t numChromaPlanes, |
||||
bool bUnAlignedDeviceCopy = false, |
||||
CUstream stream = NULL); |
||||
|
||||
/**
|
||||
* @brief This function sets input and output CUDA streams |
||||
*/ |
||||
void SetIOCudaStreams(NV_ENC_CUSTREAM_PTR inputStream, NV_ENC_CUSTREAM_PTR outputStream); |
||||
|
||||
protected: |
||||
/**
|
||||
* @brief This function is used to release the input buffers allocated for encoding. |
||||
* This function is an override of virtual function NvEncoder::ReleaseInputBuffers(). |
||||
*/ |
||||
virtual void ReleaseInputBuffers() override; |
||||
|
||||
private: |
||||
/**
|
||||
* @brief This function is used to allocate input buffers for encoding. |
||||
* This function is an override of virtual function NvEncoder::AllocateInputBuffers(). |
||||
*/ |
||||
virtual void AllocateInputBuffers(int32_t numInputBuffers) override; |
||||
|
||||
private: |
||||
/**
|
||||
* @brief This is a private function to release CUDA device memory used for encoding. |
||||
*/ |
||||
void ReleaseCudaResources(); |
||||
|
||||
protected: |
||||
CUcontext m_cuContext; |
||||
|
||||
private: |
||||
size_t m_cudaPitch = 0; |
||||
}; |
||||
}} |
||||
#endif |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue