mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
[fix] fix nvidia encoder crash during reconfigure the resolution
This commit is contained in:
256
src/media/nvcodec/Logger.h
Normal file
256
src/media/nvcodec/Logger.h
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <mutex>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#include <windows.h>
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#undef ERROR
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#define SOCKET int
|
||||
#define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
enum LogLevel {
|
||||
TRACE,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
FATAL
|
||||
};
|
||||
|
||||
namespace simplelogger{
|
||||
class Logger {
|
||||
public:
|
||||
Logger(LogLevel level, bool bPrintTimeStamp) : level(level), bPrintTimeStamp(bPrintTimeStamp) {}
|
||||
virtual ~Logger() {}
|
||||
virtual std::ostream& GetStream() = 0;
|
||||
virtual void FlushStream() {}
|
||||
bool ShouldLogFor(LogLevel l) {
|
||||
return l >= level;
|
||||
}
|
||||
char* GetLead(LogLevel l, const char *szFile, int nLine, const char *szFunc) {
|
||||
if (l < TRACE || l > FATAL) {
|
||||
sprintf(szLead, "[?????] ");
|
||||
return szLead;
|
||||
}
|
||||
const char *szLevels[] = {"TRACE", "INFO", "WARN", "ERROR", "FATAL"};
|
||||
if (bPrintTimeStamp) {
|
||||
time_t t = time(NULL);
|
||||
struct tm *ptm = localtime(&t);
|
||||
sprintf(szLead, "[%-5s][%02d:%02d:%02d] ",
|
||||
szLevels[l], ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
|
||||
} else {
|
||||
sprintf(szLead, "[%-5s] ", szLevels[l]);
|
||||
}
|
||||
return szLead;
|
||||
}
|
||||
void EnterCriticalSection() {
|
||||
mtx.lock();
|
||||
}
|
||||
void LeaveCriticalSection() {
|
||||
mtx.unlock();
|
||||
}
|
||||
private:
|
||||
LogLevel level;
|
||||
char szLead[80];
|
||||
bool bPrintTimeStamp;
|
||||
std::mutex mtx;
|
||||
};
|
||||
|
||||
class LoggerFactory {
|
||||
public:
|
||||
static Logger* CreateFileLogger(std::string strFilePath,
|
||||
LogLevel level = INFO, bool bPrintTimeStamp = true) {
|
||||
return new FileLogger(strFilePath, level, bPrintTimeStamp);
|
||||
}
|
||||
static Logger* CreateConsoleLogger(LogLevel level = INFO,
|
||||
bool bPrintTimeStamp = true) {
|
||||
return new ConsoleLogger(level, bPrintTimeStamp);
|
||||
}
|
||||
static Logger* CreateUdpLogger(char *szHost, unsigned uPort, LogLevel level = INFO,
|
||||
bool bPrintTimeStamp = true) {
|
||||
return new UdpLogger(szHost, uPort, level, bPrintTimeStamp);
|
||||
}
|
||||
private:
|
||||
LoggerFactory() {}
|
||||
|
||||
class FileLogger : public Logger {
|
||||
public:
|
||||
FileLogger(std::string strFilePath, LogLevel level, bool bPrintTimeStamp)
|
||||
: Logger(level, bPrintTimeStamp) {
|
||||
pFileOut = new std::ofstream();
|
||||
pFileOut->open(strFilePath.c_str());
|
||||
}
|
||||
~FileLogger() {
|
||||
pFileOut->close();
|
||||
}
|
||||
std::ostream& GetStream() {
|
||||
return *pFileOut;
|
||||
}
|
||||
private:
|
||||
std::ofstream *pFileOut;
|
||||
};
|
||||
|
||||
class ConsoleLogger : public Logger {
|
||||
public:
|
||||
ConsoleLogger(LogLevel level, bool bPrintTimeStamp)
|
||||
: Logger(level, bPrintTimeStamp) {}
|
||||
std::ostream& GetStream() {
|
||||
return std::cout;
|
||||
}
|
||||
};
|
||||
|
||||
class UdpLogger : public Logger {
|
||||
private:
|
||||
class UdpOstream : public std::ostream {
|
||||
public:
|
||||
UdpOstream(char *szHost, unsigned short uPort) : std::ostream(&sb), socket(INVALID_SOCKET){
|
||||
#ifdef _WIN32
|
||||
WSADATA w;
|
||||
if (WSAStartup(0x0101, &w) != 0) {
|
||||
fprintf(stderr, "WSAStartup() failed.\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (socket == INVALID_SOCKET) {
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
fprintf(stderr, "socket() failed.\n");
|
||||
return;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
unsigned int b1, b2, b3, b4;
|
||||
sscanf(szHost, "%u.%u.%u.%u", &b1, &b2, &b3, &b4);
|
||||
struct in_addr addr = {(unsigned char)b1, (unsigned char)b2, (unsigned char)b3, (unsigned char)b4};
|
||||
#else
|
||||
struct in_addr addr = {inet_addr(szHost)};
|
||||
#endif
|
||||
struct sockaddr_in s = {AF_INET, htons(uPort), addr};
|
||||
server = s;
|
||||
}
|
||||
~UdpOstream() throw() {
|
||||
if (socket == INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
closesocket(socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(socket);
|
||||
#endif
|
||||
}
|
||||
void Flush() {
|
||||
if (sendto(socket, sb.str().c_str(), (int)sb.str().length() + 1,
|
||||
0, (struct sockaddr *)&server, (int)sizeof(sockaddr_in)) == -1) {
|
||||
fprintf(stderr, "sendto() failed.\n");
|
||||
}
|
||||
sb.str("");
|
||||
}
|
||||
|
||||
private:
|
||||
std::stringbuf sb;
|
||||
SOCKET socket;
|
||||
struct sockaddr_in server;
|
||||
};
|
||||
public:
|
||||
UdpLogger(char *szHost, unsigned uPort, LogLevel level, bool bPrintTimeStamp)
|
||||
: Logger(level, bPrintTimeStamp), udpOut(szHost, (unsigned short)uPort) {}
|
||||
UdpOstream& GetStream() {
|
||||
return udpOut;
|
||||
}
|
||||
virtual void FlushStream() {
|
||||
udpOut.Flush();
|
||||
}
|
||||
private:
|
||||
UdpOstream udpOut;
|
||||
};
|
||||
};
|
||||
|
||||
class LogTransaction {
|
||||
public:
|
||||
LogTransaction(Logger *pLogger, LogLevel level, const char *szFile, const int nLine, const char *szFunc) : pLogger(pLogger), level(level) {
|
||||
if (!pLogger) {
|
||||
std::cout << "[-----] ";
|
||||
return;
|
||||
}
|
||||
if (!pLogger->ShouldLogFor(level)) {
|
||||
return;
|
||||
}
|
||||
pLogger->EnterCriticalSection();
|
||||
pLogger->GetStream() << pLogger->GetLead(level, szFile, nLine, szFunc);
|
||||
}
|
||||
~LogTransaction() {
|
||||
if (!pLogger) {
|
||||
std::cout << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!pLogger->ShouldLogFor(level)) {
|
||||
return;
|
||||
}
|
||||
pLogger->GetStream() << std::endl;
|
||||
pLogger->FlushStream();
|
||||
pLogger->LeaveCriticalSection();
|
||||
if (level == FATAL) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
std::ostream& GetStream() {
|
||||
if (!pLogger) {
|
||||
return std::cout;
|
||||
}
|
||||
if (!pLogger->ShouldLogFor(level)) {
|
||||
return ossNull;
|
||||
}
|
||||
return pLogger->GetStream();
|
||||
}
|
||||
private:
|
||||
Logger *pLogger;
|
||||
LogLevel level;
|
||||
std::ostringstream ossNull;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern simplelogger::Logger *logger;
|
||||
#define LOG(level) simplelogger::LogTransaction(logger, level, __FILE__, __LINE__, __FUNCTION__).GetStream()
|
||||
577
src/media/nvcodec/NvCodecUtils.h
Normal file
577
src/media/nvcodec/NvCodecUtils.h
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \file NvCodecUtils.h
|
||||
//! \brief Miscellaneous classes and error checking functions.
|
||||
//!
|
||||
//! Used by Transcode/Encode samples apps for reading input files,
|
||||
//! mutithreading, performance measurement or colorspace conversion while
|
||||
//! decoding.
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __cuda_cuda_h__
|
||||
inline bool check(CUresult e, int iLine, const char *szFile) {
|
||||
if (e != CUDA_SUCCESS) {
|
||||
const char *szErrName = NULL;
|
||||
cuGetErrorName(e, &szErrName);
|
||||
std::cout << "CUDA driver API error " << szErrName << " at line " << iLine
|
||||
<< " in file " << szFile;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __CUDA_RUNTIME_H__
|
||||
inline bool check(cudaError_t e, int iLine, const char *szFile) {
|
||||
if (e != cudaSuccess) {
|
||||
std::cout << "CUDA runtime API error " << cudaGetErrorName(e) << " at line "
|
||||
<< iLine << " in file " << szFile;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _NV_ENCODEAPI_H_
|
||||
inline bool check(NVENCSTATUS e, int iLine, const char *szFile) {
|
||||
const char *aszErrName[] = {
|
||||
"NV_ENC_SUCCESS",
|
||||
"NV_ENC_ERR_NO_ENCODE_DEVICE",
|
||||
"NV_ENC_ERR_UNSUPPORTED_DEVICE",
|
||||
"NV_ENC_ERR_INVALID_ENCODERDEVICE",
|
||||
"NV_ENC_ERR_INVALID_DEVICE",
|
||||
"NV_ENC_ERR_DEVICE_NOT_EXIST",
|
||||
"NV_ENC_ERR_INVALID_PTR",
|
||||
"NV_ENC_ERR_INVALID_EVENT",
|
||||
"NV_ENC_ERR_INVALID_PARAM",
|
||||
"NV_ENC_ERR_INVALID_CALL",
|
||||
"NV_ENC_ERR_OUT_OF_MEMORY",
|
||||
"NV_ENC_ERR_ENCODER_NOT_INITIALIZED",
|
||||
"NV_ENC_ERR_UNSUPPORTED_PARAM",
|
||||
"NV_ENC_ERR_LOCK_BUSY",
|
||||
"NV_ENC_ERR_NOT_ENOUGH_BUFFER",
|
||||
"NV_ENC_ERR_INVALID_VERSION",
|
||||
"NV_ENC_ERR_MAP_FAILED",
|
||||
"NV_ENC_ERR_NEED_MORE_INPUT",
|
||||
"NV_ENC_ERR_ENCODER_BUSY",
|
||||
"NV_ENC_ERR_EVENT_NOT_REGISTERD",
|
||||
"NV_ENC_ERR_GENERIC",
|
||||
"NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY",
|
||||
"NV_ENC_ERR_UNIMPLEMENTED",
|
||||
"NV_ENC_ERR_RESOURCE_REGISTER_FAILED",
|
||||
"NV_ENC_ERR_RESOURCE_NOT_REGISTERED",
|
||||
"NV_ENC_ERR_RESOURCE_NOT_MAPPED",
|
||||
};
|
||||
if (e != NV_ENC_SUCCESS) {
|
||||
std::cout << "NVENC error " << aszErrName[e] << " at line " << iLine
|
||||
<< " in file " << szFile;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WINERROR_
|
||||
inline bool check(HRESULT e, int iLine, const char *szFile) {
|
||||
if (e != S_OK) {
|
||||
std::stringstream stream;
|
||||
stream << std::hex << std::uppercase << e;
|
||||
std::cout << "HRESULT error 0x" << stream.str() << " at line " << iLine
|
||||
<< " in file " << szFile;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__gl_h_) || defined(__GL_H__)
|
||||
inline bool check(GLenum e, int iLine, const char *szFile) {
|
||||
if (e != 0) {
|
||||
std::cout << "GLenum error " << e << " at line " << iLine << " in file "
|
||||
<< szFile;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool check(int e, int iLine, const char *szFile) {
|
||||
if (e < 0) {
|
||||
std::cout << "General error " << e << " at line " << iLine << " in file "
|
||||
<< szFile;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define ck(call) check(call, __LINE__, __FILE__)
|
||||
#define MAKE_FOURCC(ch0, ch1, ch2, ch3) \
|
||||
((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \
|
||||
((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24))
|
||||
|
||||
/**
|
||||
* @brief Wrapper class around std::thread
|
||||
*/
|
||||
class NvThread {
|
||||
public:
|
||||
NvThread() = default;
|
||||
NvThread(const NvThread &) = delete;
|
||||
NvThread &operator=(const NvThread &other) = delete;
|
||||
|
||||
NvThread(std::thread &&thread) : t(std::move(thread)) {}
|
||||
|
||||
NvThread(NvThread &&thread) : t(std::move(thread.t)) {}
|
||||
|
||||
NvThread &operator=(NvThread &&other) {
|
||||
t = std::move(other.t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~NvThread() { join(); }
|
||||
|
||||
void join() {
|
||||
if (t.joinable()) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::thread t;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
#define _stricmp strcasecmp
|
||||
#define _stat64 stat64
|
||||
#endif
|
||||
|
||||
// /**
|
||||
// * @brief Utility class to allocate buffer memory. Helps avoid I/O during the
|
||||
// * encode/decode loop in case of performance tests.
|
||||
// */
|
||||
// class BufferedFileReader {
|
||||
// public:
|
||||
// /**
|
||||
// * @brief Constructor function to allocate appropriate memory and copy file
|
||||
// * contents into it
|
||||
// */
|
||||
// BufferedFileReader(const char *szFileName, bool bPartial = false) {
|
||||
// struct _stat64 st;
|
||||
|
||||
// if (_stat64(szFileName, &st) != 0) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// nSize = st.st_size;
|
||||
// while (nSize) {
|
||||
// try {
|
||||
// pBuf = new uint8_t[(size_t)nSize];
|
||||
// if (nSize != st.st_size) {
|
||||
// std::cout << "File is too large - only " << std::setprecision(4)
|
||||
// << 100.0 * nSize / st.st_size << "% is loaded";
|
||||
// }
|
||||
// break;
|
||||
// } catch (std::bad_alloc) {
|
||||
// if (!bPartial) {
|
||||
// std::cout << "Failed to allocate memory in BufferedReader";
|
||||
// return;
|
||||
// }
|
||||
// nSize = (uint32_t)(nSize * 0.9);
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::ifstream fpIn(szFileName, std::ifstream::in |
|
||||
// std::ifstream::binary); if (!fpIn) {
|
||||
// std::cout << "Unable to open input file: " << szFileName;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// std::streamsize nRead =
|
||||
// fpIn.read(reinterpret_cast<char *>(pBuf), nSize).gcount();
|
||||
// fpIn.close();
|
||||
|
||||
// assert(nRead == nSize);
|
||||
// }
|
||||
// ~BufferedFileReader() {
|
||||
// if (pBuf) {
|
||||
// delete[] pBuf;
|
||||
// }
|
||||
// }
|
||||
// bool GetBuffer(uint8_t **ppBuf, uint64_t *pnSize) {
|
||||
// if (!pBuf) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// *ppBuf = pBuf;
|
||||
// *pnSize = nSize;
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// private:
|
||||
// uint8_t *pBuf = NULL;
|
||||
// uint64_t nSize = 0;
|
||||
// };
|
||||
|
||||
/**
|
||||
* @brief Template class to facilitate color space conversion
|
||||
*/
|
||||
template <typename T>
|
||||
class YuvConverter {
|
||||
public:
|
||||
YuvConverter(int nWidth, int nHeight) : nWidth(nWidth), nHeight(nHeight) {
|
||||
pQuad = new T[((nWidth + 1) / 2) * ((nHeight + 1) / 2)];
|
||||
}
|
||||
~YuvConverter() { delete[] pQuad; }
|
||||
void PlanarToUVInterleaved(T *pFrame, int nPitch = 0) {
|
||||
if (nPitch == 0) {
|
||||
nPitch = nWidth;
|
||||
}
|
||||
|
||||
// sizes of source surface plane
|
||||
int nSizePlaneY = nPitch * nHeight;
|
||||
int nSizePlaneU = ((nPitch + 1) / 2) * ((nHeight + 1) / 2);
|
||||
int nSizePlaneV = nSizePlaneU;
|
||||
|
||||
T *puv = pFrame + nSizePlaneY;
|
||||
if (nPitch == nWidth) {
|
||||
memcpy(pQuad, puv, nSizePlaneU * sizeof(T));
|
||||
} else {
|
||||
for (int i = 0; i < (nHeight + 1) / 2; i++) {
|
||||
memcpy(pQuad + ((nWidth + 1) / 2) * i, puv + ((nPitch + 1) / 2) * i,
|
||||
((nWidth + 1) / 2) * sizeof(T));
|
||||
}
|
||||
}
|
||||
T *pv = puv + nSizePlaneU;
|
||||
for (int y = 0; y < (nHeight + 1) / 2; y++) {
|
||||
for (int x = 0; x < (nWidth + 1) / 2; x++) {
|
||||
puv[y * nPitch + x * 2] = pQuad[y * ((nWidth + 1) / 2) + x];
|
||||
puv[y * nPitch + x * 2 + 1] = pv[y * ((nPitch + 1) / 2) + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
void UVInterleavedToPlanar(T *pFrame, int nPitch = 0) {
|
||||
if (nPitch == 0) {
|
||||
nPitch = nWidth;
|
||||
}
|
||||
|
||||
// sizes of source surface plane
|
||||
int nSizePlaneY = nPitch * nHeight;
|
||||
int nSizePlaneU = ((nPitch + 1) / 2) * ((nHeight + 1) / 2);
|
||||
int nSizePlaneV = nSizePlaneU;
|
||||
|
||||
T *puv = pFrame + nSizePlaneY, *pu = puv, *pv = puv + nSizePlaneU;
|
||||
|
||||
// split chroma from interleave to planar
|
||||
for (int y = 0; y < (nHeight + 1) / 2; y++) {
|
||||
for (int x = 0; x < (nWidth + 1) / 2; x++) {
|
||||
pu[y * ((nPitch + 1) / 2) + x] = puv[y * nPitch + x * 2];
|
||||
pQuad[y * ((nWidth + 1) / 2) + x] = puv[y * nPitch + x * 2 + 1];
|
||||
}
|
||||
}
|
||||
if (nPitch == nWidth) {
|
||||
memcpy(pv, pQuad, nSizePlaneV * sizeof(T));
|
||||
} else {
|
||||
for (int i = 0; i < (nHeight + 1) / 2; i++) {
|
||||
memcpy(pv + ((nPitch + 1) / 2) * i, pQuad + ((nWidth + 1) / 2) * i,
|
||||
((nWidth + 1) / 2) * sizeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T *pQuad;
|
||||
int nWidth, nHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Class for writing IVF format header for AV1 codec
|
||||
*/
|
||||
class IVFUtils {
|
||||
public:
|
||||
void WriteFileHeader(std::vector<uint8_t> &vPacket, uint32_t nFourCC,
|
||||
uint32_t nWidth, uint32_t nHeight,
|
||||
uint32_t nFrameRateNum, uint32_t nFrameRateDen,
|
||||
uint32_t nFrameCnt) {
|
||||
char header[32];
|
||||
|
||||
header[0] = 'D';
|
||||
header[1] = 'K';
|
||||
header[2] = 'I';
|
||||
header[3] = 'F';
|
||||
mem_put_le16(header + 4, 0); // version
|
||||
mem_put_le16(header + 6, 32); // header size
|
||||
mem_put_le32(header + 8, nFourCC); // fourcc
|
||||
mem_put_le16(header + 12, nWidth); // width
|
||||
mem_put_le16(header + 14, nHeight); // height
|
||||
mem_put_le32(header + 16, nFrameRateNum); // rate
|
||||
mem_put_le32(header + 20, nFrameRateDen); // scale
|
||||
mem_put_le32(header + 24, nFrameCnt); // length
|
||||
mem_put_le32(header + 28, 0); // unused
|
||||
|
||||
vPacket.insert(vPacket.end(), &header[0], &header[32]);
|
||||
}
|
||||
|
||||
void WriteFrameHeader(std::vector<uint8_t> &vPacket, size_t nFrameSize,
|
||||
int64_t pts) {
|
||||
char header[12];
|
||||
mem_put_le32(header, (int)nFrameSize);
|
||||
mem_put_le32(header + 4, (int)(pts & 0xFFFFFFFF));
|
||||
mem_put_le32(header + 8, (int)(pts >> 32));
|
||||
|
||||
vPacket.insert(vPacket.end(), &header[0], &header[12]);
|
||||
}
|
||||
|
||||
private:
|
||||
static inline void mem_put_le32(void *vmem, int val) {
|
||||
unsigned char *mem = (unsigned char *)vmem;
|
||||
mem[0] = (unsigned char)((val >> 0) & 0xff);
|
||||
mem[1] = (unsigned char)((val >> 8) & 0xff);
|
||||
mem[2] = (unsigned char)((val >> 16) & 0xff);
|
||||
mem[3] = (unsigned char)((val >> 24) & 0xff);
|
||||
}
|
||||
|
||||
static inline void mem_put_le16(void *vmem, int val) {
|
||||
unsigned char *mem = (unsigned char *)vmem;
|
||||
mem[0] = (unsigned char)((val >> 0) & 0xff);
|
||||
mem[1] = (unsigned char)((val >> 8) & 0xff);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Utility class to measure elapsed time in seconds between the block of
|
||||
* executed code
|
||||
*/
|
||||
class StopWatch {
|
||||
public:
|
||||
void Start() { t0 = std::chrono::high_resolution_clock::now(); }
|
||||
double Stop() {
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch() -
|
||||
t0.time_since_epoch())
|
||||
.count() /
|
||||
1.0e9;
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::high_resolution_clock::time_point t0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ConcurrentQueue {
|
||||
public:
|
||||
ConcurrentQueue() : maxSize(0) {}
|
||||
ConcurrentQueue(size_t size) : maxSize(size) {}
|
||||
ConcurrentQueue(const ConcurrentQueue &) = delete;
|
||||
ConcurrentQueue &operator=(const ConcurrentQueue &) = delete;
|
||||
|
||||
void setSize(size_t s) { maxSize = s; }
|
||||
|
||||
void push_back(const T &value) {
|
||||
// Do not use a std::lock_guard here. We will need to explicitly
|
||||
// unlock before notify_one as the other waiting thread will
|
||||
// automatically try to acquire mutex once it wakes up
|
||||
// (which will happen on notify_one)
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
auto wasEmpty = m_List.empty();
|
||||
|
||||
while (full()) {
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
|
||||
m_List.push_back(value);
|
||||
if (wasEmpty && !m_List.empty()) {
|
||||
lock.unlock();
|
||||
m_cond.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
T pop_front() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
while (m_List.empty()) {
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
auto wasFull = full();
|
||||
T data = std::move(m_List.front());
|
||||
m_List.pop_front();
|
||||
|
||||
if (wasFull && !full()) {
|
||||
lock.unlock();
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
T front() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
while (m_List.empty()) {
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
|
||||
return m_List.front();
|
||||
}
|
||||
|
||||
size_t size() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
return m_List.size();
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
return m_List.empty();
|
||||
}
|
||||
void clear() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_List.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
bool full() {
|
||||
if (maxSize > 0 && m_List.size() == maxSize) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<T> m_List;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cond;
|
||||
size_t maxSize;
|
||||
};
|
||||
|
||||
// inline void CheckInputFile(const char *szInFilePath) {
|
||||
// std::ifstream fpIn(szInFilePath, std::ios::in | std::ios::binary);
|
||||
// if (fpIn.fail()) {
|
||||
// std::ostringstream err;
|
||||
// err << "Unable to open input file: " << szInFilePath << std::endl;
|
||||
// throw std::invalid_argument(err.str());
|
||||
// }
|
||||
// }
|
||||
|
||||
inline void ValidateResolution(int nWidth, int nHeight) {
|
||||
if (nWidth <= 0 || nHeight <= 0) {
|
||||
std::ostringstream err;
|
||||
err << "Please specify positive non zero resolution as -s WxH. Current "
|
||||
"resolution is "
|
||||
<< nWidth << "x" << nHeight << std::endl;
|
||||
throw std::invalid_argument(err.str());
|
||||
}
|
||||
}
|
||||
|
||||
template <class COLOR32>
|
||||
void Nv12ToColor32(uint8_t *dpNv12, int nNv12Pitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight, int iMatrix = 0);
|
||||
template <class COLOR64>
|
||||
void Nv12ToColor64(uint8_t *dpNv12, int nNv12Pitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight, int iMatrix = 0);
|
||||
|
||||
template <class COLOR32>
|
||||
void P016ToColor32(uint8_t *dpP016, int nP016Pitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight, int iMatrix = 4);
|
||||
template <class COLOR64>
|
||||
void P016ToColor64(uint8_t *dpP016, int nP016Pitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight, int iMatrix = 4);
|
||||
|
||||
template <class COLOR32>
|
||||
void YUV444ToColor32(uint8_t *dpYUV444, int nPitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight, int iMatrix = 0);
|
||||
template <class COLOR64>
|
||||
void YUV444ToColor64(uint8_t *dpYUV444, int nPitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight, int iMatrix = 0);
|
||||
|
||||
template <class COLOR32>
|
||||
void YUV444P16ToColor32(uint8_t *dpYUV444, int nPitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight,
|
||||
int iMatrix = 4);
|
||||
template <class COLOR64>
|
||||
void YUV444P16ToColor64(uint8_t *dpYUV444, int nPitch, uint8_t *dpBgra,
|
||||
int nBgraPitch, int nWidth, int nHeight,
|
||||
int iMatrix = 4);
|
||||
|
||||
template <class COLOR32>
|
||||
void Nv12ToColorPlanar(uint8_t *dpNv12, int nNv12Pitch, uint8_t *dpBgrp,
|
||||
int nBgrpPitch, int nWidth, int nHeight,
|
||||
int iMatrix = 0);
|
||||
template <class COLOR32>
|
||||
void P016ToColorPlanar(uint8_t *dpP016, int nP016Pitch, uint8_t *dpBgrp,
|
||||
int nBgrpPitch, int nWidth, int nHeight,
|
||||
int iMatrix = 4);
|
||||
|
||||
template <class COLOR32>
|
||||
void YUV444ToColorPlanar(uint8_t *dpYUV444, int nPitch, uint8_t *dpBgrp,
|
||||
int nBgrpPitch, int nWidth, int nHeight,
|
||||
int iMatrix = 0);
|
||||
template <class COLOR32>
|
||||
void YUV444P16ToColorPlanar(uint8_t *dpYUV444, int nPitch, uint8_t *dpBgrp,
|
||||
int nBgrpPitch, int nWidth, int nHeight,
|
||||
int iMatrix = 4);
|
||||
|
||||
void Bgra64ToP016(uint8_t *dpBgra, int nBgraPitch, uint8_t *dpP016,
|
||||
int nP016Pitch, int nWidth, int nHeight, int iMatrix = 4);
|
||||
|
||||
void ConvertUInt8ToUInt16(uint8_t *dpUInt8, uint16_t *dpUInt16, int nSrcPitch,
|
||||
int nDestPitch, int nWidth, int nHeight);
|
||||
void ConvertUInt16ToUInt8(uint16_t *dpUInt16, uint8_t *dpUInt8, int nSrcPitch,
|
||||
int nDestPitch, int nWidth, int nHeight);
|
||||
|
||||
void ResizeNv12(unsigned char *dpDstNv12, int nDstPitch, int nDstWidth,
|
||||
int nDstHeight, unsigned char *dpSrcNv12, int nSrcPitch,
|
||||
int nSrcWidth, int nSrcHeight,
|
||||
unsigned char *dpDstNv12UV = nullptr);
|
||||
void ResizeP016(unsigned char *dpDstP016, int nDstPitch, int nDstWidth,
|
||||
int nDstHeight, unsigned char *dpSrcP016, int nSrcPitch,
|
||||
int nSrcWidth, int nSrcHeight,
|
||||
unsigned char *dpDstP016UV = nullptr);
|
||||
|
||||
void ScaleYUV420(unsigned char *dpDstY, unsigned char *dpDstU,
|
||||
unsigned char *dpDstV, int nDstPitch, int nDstChromaPitch,
|
||||
int nDstWidth, int nDstHeight, unsigned char *dpSrcY,
|
||||
unsigned char *dpSrcU, unsigned char *dpSrcV, int nSrcPitch,
|
||||
int nSrcChromaPitch, int nSrcWidth, int nSrcHeight,
|
||||
bool bSemiplanar);
|
||||
|
||||
#ifdef __cuda_cuda_h__
|
||||
void ComputeCRC(uint8_t *pBuffer, uint32_t *crcValue,
|
||||
CUstream_st *outputCUStream);
|
||||
#endif
|
||||
@@ -1,12 +1,28 @@
|
||||
/*
|
||||
* Copyright 2017-2020 NVIDIA Corporation. All rights reserved.
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "NvDecoder.h"
|
||||
@@ -16,23 +32,22 @@
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
#include "nvcodec_api.h"
|
||||
#include "nvcuvid.h"
|
||||
|
||||
#define START_TIMER auto start = std::chrono::steady_clock::now();
|
||||
#define STOP_TIMER(print_message) \
|
||||
std::cout << print_message \
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>( \
|
||||
std::chrono::steady_clock::now() - start) \
|
||||
.count() \
|
||||
<< " ms " << std::endl;
|
||||
#define START_TIMER auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
#define STOP_TIMER(print_message) \
|
||||
int64_t elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>( \
|
||||
std::chrono::high_resolution_clock::now() - start) \
|
||||
.count(); \
|
||||
std::cout << print_message << elapsedTime << " ms " << std::endl;
|
||||
|
||||
#define CUDA_DRVAPI_CALL(call) \
|
||||
do { \
|
||||
CUresult err__ = call; \
|
||||
if (err__ != CUDA_SUCCESS) { \
|
||||
const char *szErrName = NULL; \
|
||||
cuGetErrorName_ld(err__, &szErrName); \
|
||||
cuGetErrorName(err__, &szErrName); \
|
||||
std::ostringstream errorLog; \
|
||||
errorLog << "CUDA driver API error " << szErrName; \
|
||||
throw NVDECException::makeNVDECException( \
|
||||
@@ -164,7 +179,7 @@ int NvDecoder::GetOperatingPoint(CUVIDOPERATINGPOINTINFO *pOPInfo) {
|
||||
* CUVIDPARSERPARAMS::ulMaxNumDecodeSurfaces while creating parser)
|
||||
*/
|
||||
int NvDecoder::HandleVideoSequence(CUVIDEOFORMAT *pVideoFormat) {
|
||||
START_TIMER
|
||||
// START_TIMER
|
||||
m_videoInfo.str("");
|
||||
m_videoInfo.clear();
|
||||
m_videoInfo << "Video Input Information" << std::endl
|
||||
@@ -200,9 +215,9 @@ int NvDecoder::HandleVideoSequence(CUVIDEOFORMAT *pVideoFormat) {
|
||||
decodecaps.eChromaFormat = pVideoFormat->chroma_format;
|
||||
decodecaps.nBitDepthMinus8 = pVideoFormat->bit_depth_luma_minus8;
|
||||
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidGetDecoderCaps_ld(&decodecaps));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidGetDecoderCaps(&decodecaps));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
|
||||
if (!decodecaps.bIsSupported) {
|
||||
NVDEC_THROW_ERROR("Codec not supported on this GPU",
|
||||
@@ -243,7 +258,7 @@ int NvDecoder::HandleVideoSequence(CUVIDEOFORMAT *pVideoFormat) {
|
||||
}
|
||||
|
||||
if (m_nWidth && m_nLumaHeight && m_nChromaHeight) {
|
||||
// cuvidCreateDecoder_ld() has been called before, and now there's possible
|
||||
// cuvidCreateDecoder() has been called before, and now there's possible
|
||||
// config change
|
||||
return ReconfigureDecoder(pVideoFormat);
|
||||
}
|
||||
@@ -379,10 +394,10 @@ int NvDecoder::HandleVideoSequence(CUVIDEOFORMAT *pVideoFormat) {
|
||||
"Adaptive"}[videoDecodeCreateInfo.DeinterlaceMode];
|
||||
m_videoInfo << std::endl;
|
||||
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidCreateDecoder_ld(&m_hDecoder, &videoDecodeCreateInfo));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
STOP_TIMER("Session Initialization Time: ");
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidCreateDecoder(&m_hDecoder, &videoDecodeCreateInfo));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
// STOP_TIMER("Session Initialization Time: ");
|
||||
return nDecodeSurface;
|
||||
}
|
||||
|
||||
@@ -506,11 +521,11 @@ int NvDecoder::ReconfigureDecoder(CUVIDEOFORMAT *pVideoFormat) {
|
||||
|
||||
reconfigParams.ulNumDecodeSurfaces = nDecodeSurface;
|
||||
|
||||
START_TIMER
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidReconfigureDecoder_ld(m_hDecoder, &reconfigParams));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
STOP_TIMER("Session Reconfigure Time: ");
|
||||
// START_TIMER
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidReconfigureDecoder(m_hDecoder, &reconfigParams));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
// STOP_TIMER("Session Reconfigure Time: ");
|
||||
|
||||
return nDecodeSurface;
|
||||
}
|
||||
@@ -539,9 +554,9 @@ int NvDecoder::setReconfigParams(const Rect *pCropRect, const Dim *pResizeDim) {
|
||||
pFrame = m_vpFrame.back();
|
||||
m_vpFrame.pop_back();
|
||||
if (m_bUseDeviceFrame) {
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(m_cuContext));
|
||||
CUDA_DRVAPI_CALL(cuMemFree_ld((CUdeviceptr)pFrame));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(m_cuContext));
|
||||
CUDA_DRVAPI_CALL(cuMemFree((CUdeviceptr)pFrame));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
} else {
|
||||
delete pFrame;
|
||||
}
|
||||
@@ -559,9 +574,18 @@ int NvDecoder::HandlePictureDecode(CUVIDPICPARAMS *pPicParams) {
|
||||
return false;
|
||||
}
|
||||
m_nPicNumInDecodeOrder[pPicParams->CurrPicIdx] = m_nDecodePicCnt++;
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidDecodePicture_ld(m_hDecoder, pPicParams));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidDecodePicture(m_hDecoder, pPicParams));
|
||||
if (m_bForce_zero_latency &&
|
||||
((!pPicParams->field_pic_flag) || (pPicParams->second_field))) {
|
||||
CUVIDPARSERDISPINFO dispInfo;
|
||||
memset(&dispInfo, 0, sizeof(dispInfo));
|
||||
dispInfo.picture_index = pPicParams->CurrPicIdx;
|
||||
dispInfo.progressive_frame = !pPicParams->field_pic_flag;
|
||||
dispInfo.top_field_first = pPicParams->bottom_field_flag ^ 1;
|
||||
HandlePictureDisplay(&dispInfo);
|
||||
}
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -576,22 +600,87 @@ int NvDecoder::HandlePictureDisplay(CUVIDPARSERDISPINFO *pDispInfo) {
|
||||
videoProcessingParameters.unpaired_field = pDispInfo->repeat_first_field < 0;
|
||||
videoProcessingParameters.output_stream = m_cuvidStream;
|
||||
|
||||
if (m_bExtractSEIMessage) {
|
||||
if (m_SEIMessagesDisplayOrder[pDispInfo->picture_index].pSEIData) {
|
||||
// Write SEI Message
|
||||
uint8_t *seiBuffer =
|
||||
(uint8_t *)(m_SEIMessagesDisplayOrder[pDispInfo->picture_index]
|
||||
.pSEIData);
|
||||
uint32_t seiNumMessages =
|
||||
m_SEIMessagesDisplayOrder[pDispInfo->picture_index].sei_message_count;
|
||||
CUSEIMESSAGE *seiMessagesInfo =
|
||||
m_SEIMessagesDisplayOrder[pDispInfo->picture_index].pSEIMessage;
|
||||
if (m_fpSEI) {
|
||||
for (uint32_t i = 0; i < seiNumMessages; i++) {
|
||||
if ((m_eCodec == cudaVideoCodec_H264) ||
|
||||
(m_eCodec == cudaVideoCodec_H264_SVC) ||
|
||||
(m_eCodec == cudaVideoCodec_H264_MVC) ||
|
||||
(m_eCodec == cudaVideoCodec_HEVC) ||
|
||||
(m_eCodec == cudaVideoCodec_MPEG2)) {
|
||||
switch (seiMessagesInfo[i].sei_message_type) {
|
||||
case SEI_TYPE_TIME_CODE:
|
||||
case SEI_TYPE_TIME_CODE_H264: {
|
||||
if (m_eCodec != cudaVideoCodec_MPEG2) {
|
||||
TIMECODE *timecode = (TIMECODE *)seiBuffer;
|
||||
fwrite(timecode, sizeof(TIMECODE), 1, m_fpSEI);
|
||||
} else {
|
||||
TIMECODEMPEG2 *timecode = (TIMECODEMPEG2 *)seiBuffer;
|
||||
fwrite(timecode, sizeof(TIMECODEMPEG2), 1, m_fpSEI);
|
||||
}
|
||||
} break;
|
||||
case SEI_TYPE_USER_DATA_REGISTERED:
|
||||
case SEI_TYPE_USER_DATA_UNREGISTERED: {
|
||||
fwrite(seiBuffer, seiMessagesInfo[i].sei_message_size, 1,
|
||||
m_fpSEI);
|
||||
} break;
|
||||
case SEI_TYPE_MASTERING_DISPLAY_COLOR_VOLUME: {
|
||||
SEIMASTERINGDISPLAYINFO *masteringDisplayVolume =
|
||||
(SEIMASTERINGDISPLAYINFO *)seiBuffer;
|
||||
fwrite(masteringDisplayVolume, sizeof(SEIMASTERINGDISPLAYINFO),
|
||||
1, m_fpSEI);
|
||||
} break;
|
||||
case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO: {
|
||||
SEICONTENTLIGHTLEVELINFO *contentLightLevelInfo =
|
||||
(SEICONTENTLIGHTLEVELINFO *)seiBuffer;
|
||||
fwrite(contentLightLevelInfo, sizeof(SEICONTENTLIGHTLEVELINFO),
|
||||
1, m_fpSEI);
|
||||
} break;
|
||||
case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: {
|
||||
SEIALTERNATIVETRANSFERCHARACTERISTICS *transferCharacteristics =
|
||||
(SEIALTERNATIVETRANSFERCHARACTERISTICS *)seiBuffer;
|
||||
fwrite(transferCharacteristics,
|
||||
sizeof(SEIALTERNATIVETRANSFERCHARACTERISTICS), 1,
|
||||
m_fpSEI);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
if (m_eCodec == cudaVideoCodec_AV1) {
|
||||
fwrite(seiBuffer, seiMessagesInfo[i].sei_message_size, 1, m_fpSEI);
|
||||
}
|
||||
seiBuffer += seiMessagesInfo[i].sei_message_size;
|
||||
}
|
||||
}
|
||||
free(m_SEIMessagesDisplayOrder[pDispInfo->picture_index].pSEIData);
|
||||
free(m_SEIMessagesDisplayOrder[pDispInfo->picture_index].pSEIMessage);
|
||||
}
|
||||
}
|
||||
|
||||
CUdeviceptr dpSrcFrame = 0;
|
||||
unsigned int nSrcPitch = 0;
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidMapVideoFrame64_ld(m_hDecoder, pDispInfo->picture_index,
|
||||
&dpSrcFrame, &nSrcPitch,
|
||||
&videoProcessingParameters));
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(m_cuContext));
|
||||
NVDEC_API_CALL(cuvidMapVideoFrame(m_hDecoder, pDispInfo->picture_index,
|
||||
&dpSrcFrame, &nSrcPitch,
|
||||
&videoProcessingParameters));
|
||||
|
||||
CUVIDGETDECODESTATUS DecodeStatus;
|
||||
memset(&DecodeStatus, 0, sizeof(DecodeStatus));
|
||||
CUresult result = cuvidGetDecodeStatus_ld(
|
||||
m_hDecoder, pDispInfo->picture_index, &DecodeStatus);
|
||||
CUresult result =
|
||||
cuvidGetDecodeStatus(m_hDecoder, pDispInfo->picture_index, &DecodeStatus);
|
||||
if (result == CUDA_SUCCESS &&
|
||||
(DecodeStatus.decodeStatus == cuvidDecodeStatus_Error ||
|
||||
DecodeStatus.decodeStatus == cuvidDecodeStatus_Error_Concealed)) {
|
||||
// printf("Decode Error occurred for picture %d\n",
|
||||
// m_nPicNumInDecodeOrder[pDispInfo->picture_index]);
|
||||
printf("Decode Error occurred for picture %d\n",
|
||||
m_nPicNumInDecodeOrder[pDispInfo->picture_index]);
|
||||
}
|
||||
|
||||
uint8_t *pDecodedFrame = nullptr;
|
||||
@@ -603,12 +692,11 @@ int NvDecoder::HandlePictureDisplay(CUVIDPARSERDISPINFO *pDispInfo) {
|
||||
uint8_t *pFrame = NULL;
|
||||
if (m_bUseDeviceFrame) {
|
||||
if (m_bDeviceFramePitched) {
|
||||
CUDA_DRVAPI_CALL(cuMemAllocPitch_ld(
|
||||
CUDA_DRVAPI_CALL(cuMemAllocPitch(
|
||||
(CUdeviceptr *)&pFrame, &m_nDeviceFramePitch, GetWidth() * m_nBPP,
|
||||
m_nLumaHeight + (m_nChromaHeight * m_nNumChromaPlanes), 16));
|
||||
} else {
|
||||
CUDA_DRVAPI_CALL(
|
||||
cuMemAlloc_ld((CUdeviceptr *)&pFrame, GetFrameSize()));
|
||||
CUDA_DRVAPI_CALL(cuMemAlloc((CUdeviceptr *)&pFrame, GetFrameSize()));
|
||||
}
|
||||
} else {
|
||||
pFrame = new uint8_t[GetFrameSize()];
|
||||
@@ -629,7 +717,7 @@ int NvDecoder::HandlePictureDisplay(CUVIDPARSERDISPINFO *pDispInfo) {
|
||||
m.dstPitch = m_nDeviceFramePitch ? m_nDeviceFramePitch : GetWidth() * m_nBPP;
|
||||
m.WidthInBytes = GetWidth() * m_nBPP;
|
||||
m.Height = m_nLumaHeight;
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DAsync_ld(&m, m_cuvidStream));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DAsync(&m, m_cuvidStream));
|
||||
|
||||
// Copy chroma plane
|
||||
// NVDEC output has luma height aligned by 2. Adjust chroma offset by aligning
|
||||
@@ -639,7 +727,7 @@ int NvDecoder::HandlePictureDisplay(CUVIDPARSERDISPINFO *pDispInfo) {
|
||||
m.dstDevice =
|
||||
(CUdeviceptr)(m.dstHost = pDecodedFrame + m.dstPitch * m_nLumaHeight);
|
||||
m.Height = m_nChromaHeight;
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DAsync_ld(&m, m_cuvidStream));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DAsync(&m, m_cuvidStream));
|
||||
|
||||
if (m_nNumChromaPlanes == 2) {
|
||||
m.srcDevice = (CUdeviceptr)((uint8_t *)dpSrcFrame +
|
||||
@@ -647,36 +735,83 @@ int NvDecoder::HandlePictureDisplay(CUVIDPARSERDISPINFO *pDispInfo) {
|
||||
m.dstDevice = (CUdeviceptr)(m.dstHost = pDecodedFrame +
|
||||
m.dstPitch * m_nLumaHeight * 2);
|
||||
m.Height = m_nChromaHeight;
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DAsync_ld(&m, m_cuvidStream));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DAsync(&m, m_cuvidStream));
|
||||
}
|
||||
CUDA_DRVAPI_CALL(cuStreamSynchronize_ld(m_cuvidStream));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
CUDA_DRVAPI_CALL(cuStreamSynchronize(m_cuvidStream));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
|
||||
if ((int)m_vTimestamp.size() < m_nDecodedFrame) {
|
||||
m_vTimestamp.resize(m_vpFrame.size());
|
||||
}
|
||||
m_vTimestamp[m_nDecodedFrame - 1] = pDispInfo->timestamp;
|
||||
|
||||
NVDEC_API_CALL(cuvidUnmapVideoFrame64_ld(m_hDecoder, dpSrcFrame));
|
||||
NVDEC_API_CALL(cuvidUnmapVideoFrame(m_hDecoder, dpSrcFrame));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int NvDecoder::GetSEIMessage(CUVIDSEIMESSAGEINFO *pSEIMessageInfo) {
|
||||
uint32_t seiNumMessages = pSEIMessageInfo->sei_message_count;
|
||||
CUSEIMESSAGE *seiMessagesInfo = pSEIMessageInfo->pSEIMessage;
|
||||
size_t totalSEIBufferSize = 0;
|
||||
if ((pSEIMessageInfo->picIdx < 0) ||
|
||||
(pSEIMessageInfo->picIdx >= MAX_FRM_CNT)) {
|
||||
printf("Invalid picture index (%d)\n", pSEIMessageInfo->picIdx);
|
||||
return 0;
|
||||
}
|
||||
for (uint32_t i = 0; i < seiNumMessages; i++) {
|
||||
totalSEIBufferSize += seiMessagesInfo[i].sei_message_size;
|
||||
}
|
||||
if (!m_pCurrSEIMessage) {
|
||||
printf("Out of Memory, Allocation failed for m_pCurrSEIMessage\n");
|
||||
return 0;
|
||||
}
|
||||
m_pCurrSEIMessage->pSEIData = malloc(totalSEIBufferSize);
|
||||
if (!m_pCurrSEIMessage->pSEIData) {
|
||||
printf("Out of Memory, Allocation failed for SEI Buffer\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy(m_pCurrSEIMessage->pSEIData, pSEIMessageInfo->pSEIData,
|
||||
totalSEIBufferSize);
|
||||
m_pCurrSEIMessage->pSEIMessage =
|
||||
(CUSEIMESSAGE *)malloc(sizeof(CUSEIMESSAGE) * seiNumMessages);
|
||||
if (!m_pCurrSEIMessage->pSEIMessage) {
|
||||
free(m_pCurrSEIMessage->pSEIData);
|
||||
m_pCurrSEIMessage->pSEIData = NULL;
|
||||
return 0;
|
||||
}
|
||||
memcpy(m_pCurrSEIMessage->pSEIMessage, pSEIMessageInfo->pSEIMessage,
|
||||
sizeof(CUSEIMESSAGE) * seiNumMessages);
|
||||
m_pCurrSEIMessage->sei_message_count = pSEIMessageInfo->sei_message_count;
|
||||
m_SEIMessagesDisplayOrder[pSEIMessageInfo->picIdx] = *m_pCurrSEIMessage;
|
||||
return 1;
|
||||
}
|
||||
|
||||
NvDecoder::NvDecoder(CUcontext cuContext, bool bUseDeviceFrame,
|
||||
cudaVideoCodec eCodec, bool bLowLatency,
|
||||
bool bDeviceFramePitched, const Rect *pCropRect,
|
||||
const Dim *pResizeDim, int maxWidth, int maxHeight,
|
||||
unsigned int clkRate)
|
||||
const Dim *pResizeDim, bool extract_user_SEI_Message,
|
||||
int maxWidth, int maxHeight, unsigned int clkRate,
|
||||
bool force_zero_latency)
|
||||
: m_cuContext(cuContext),
|
||||
m_bUseDeviceFrame(bUseDeviceFrame),
|
||||
m_eCodec(eCodec),
|
||||
m_bDeviceFramePitched(bDeviceFramePitched),
|
||||
m_bExtractSEIMessage(extract_user_SEI_Message),
|
||||
m_nMaxWidth(maxWidth),
|
||||
m_nMaxHeight(maxHeight) {
|
||||
m_nMaxHeight(maxHeight),
|
||||
m_bForce_zero_latency(force_zero_latency) {
|
||||
if (pCropRect) m_cropRect = *pCropRect;
|
||||
if (pResizeDim) m_resizeDim = *pResizeDim;
|
||||
|
||||
NVDEC_API_CALL(cuvidCtxLockCreate_ld(&m_ctxLock, cuContext));
|
||||
NVDEC_API_CALL(cuvidCtxLockCreate(&m_ctxLock, cuContext));
|
||||
|
||||
ck(cuStreamCreate(&m_cuvidStream, CU_STREAM_DEFAULT));
|
||||
|
||||
if (m_bExtractSEIMessage) {
|
||||
m_fpSEI = fopen("sei_message.txt", "wb");
|
||||
m_pCurrSEIMessage = new CUVIDSEIMESSAGEINFO;
|
||||
memset(&m_SEIMessagesDisplayOrder, 0, sizeof(m_SEIMessagesDisplayOrder));
|
||||
}
|
||||
CUVIDPARSERPARAMS videoParserParameters = {};
|
||||
videoParserParameters.CodecType = eCodec;
|
||||
videoParserParameters.ulMaxNumDecodeSurfaces = 1;
|
||||
@@ -685,36 +820,49 @@ NvDecoder::NvDecoder(CUcontext cuContext, bool bUseDeviceFrame,
|
||||
videoParserParameters.pUserData = this;
|
||||
videoParserParameters.pfnSequenceCallback = HandleVideoSequenceProc;
|
||||
videoParserParameters.pfnDecodePicture = HandlePictureDecodeProc;
|
||||
videoParserParameters.pfnDisplayPicture = HandlePictureDisplayProc;
|
||||
videoParserParameters.pfnDisplayPicture =
|
||||
m_bForce_zero_latency ? NULL : HandlePictureDisplayProc;
|
||||
videoParserParameters.pfnGetOperatingPoint = HandleOperatingPointProc;
|
||||
NVDEC_API_CALL(cuvidCreateVideoParser_ld(&m_hParser, &videoParserParameters));
|
||||
videoParserParameters.pfnGetSEIMsg =
|
||||
m_bExtractSEIMessage ? HandleSEIMessagesProc : NULL;
|
||||
NVDEC_API_CALL(cuvidCreateVideoParser(&m_hParser, &videoParserParameters));
|
||||
}
|
||||
|
||||
NvDecoder::~NvDecoder() {
|
||||
START_TIMER
|
||||
// START_TIMER
|
||||
|
||||
if (m_pCurrSEIMessage) {
|
||||
delete m_pCurrSEIMessage;
|
||||
m_pCurrSEIMessage = NULL;
|
||||
}
|
||||
|
||||
if (m_fpSEI) {
|
||||
fclose(m_fpSEI);
|
||||
m_fpSEI = NULL;
|
||||
}
|
||||
|
||||
if (m_hParser) {
|
||||
cuvidDestroyVideoParser_ld(m_hParser);
|
||||
cuvidDestroyVideoParser(m_hParser);
|
||||
}
|
||||
cuCtxPushCurrent_ld(m_cuContext);
|
||||
cuCtxPushCurrent(m_cuContext);
|
||||
if (m_hDecoder) {
|
||||
cuvidDestroyDecoder_ld(m_hDecoder);
|
||||
cuvidDestroyDecoder(m_hDecoder);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mtxVPFrame);
|
||||
|
||||
for (uint8_t *pFrame : m_vpFrame) {
|
||||
if (m_bUseDeviceFrame) {
|
||||
cuMemFree_ld((CUdeviceptr)pFrame);
|
||||
cuMemFree((CUdeviceptr)pFrame);
|
||||
} else {
|
||||
delete[] pFrame;
|
||||
}
|
||||
}
|
||||
cuCtxPopCurrent_ld(NULL);
|
||||
cuCtxPopCurrent(NULL);
|
||||
|
||||
cuvidCtxLockDestroy_ld(m_ctxLock);
|
||||
cuvidCtxLockDestroy(m_ctxLock);
|
||||
|
||||
STOP_TIMER("Session Deinitialization Time: ");
|
||||
// STOP_TIMER("Session Deinitialization Time: ");
|
||||
}
|
||||
|
||||
int NvDecoder::Decode(const uint8_t *pData, int nSize, int nFlags,
|
||||
@@ -729,11 +877,7 @@ int NvDecoder::Decode(const uint8_t *pData, int nSize, int nFlags,
|
||||
if (!pData || nSize == 0) {
|
||||
packet.flags |= CUVID_PKT_ENDOFSTREAM;
|
||||
}
|
||||
// NVDEC_API_CALL(cuvidParseVideoData_ld(m_hParser, &packet));
|
||||
if (CUDA_SUCCESS != cuvidParseVideoData_ld(m_hParser, &packet)) {
|
||||
return 0;
|
||||
}
|
||||
m_cuvidStream = 0;
|
||||
NVDEC_API_CALL(cuvidParseVideoData(m_hParser, &packet));
|
||||
|
||||
return m_nDecodedFrame;
|
||||
}
|
||||
@@ -1,12 +1,28 @@
|
||||
/*
|
||||
* Copyright 2017-2020 NVIDIA Corporation. All rights reserved.
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -16,14 +32,27 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Utils/NvCodecUtils.h"
|
||||
#include "NvCodecUtils.h"
|
||||
#include "nvcuvid.h"
|
||||
|
||||
#define MAX_FRM_CNT 32
|
||||
|
||||
typedef enum {
|
||||
SEI_TYPE_TIME_CODE_H264 = 1,
|
||||
SEI_TYPE_USER_DATA_REGISTERED = 4,
|
||||
SEI_TYPE_USER_DATA_UNREGISTERED = 5,
|
||||
SEI_TYPE_TIME_CODE = 136,
|
||||
SEI_TYPE_MASTERING_DISPLAY_COLOR_VOLUME = 137,
|
||||
SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO = 144,
|
||||
SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147
|
||||
} SEI_H264_HEVC_MPEG2_PAYLOAD_TYPE;
|
||||
|
||||
/**
|
||||
* @brief Exception class for error reporting from the decode API.
|
||||
*/
|
||||
@@ -95,7 +124,9 @@ class NvDecoder {
|
||||
NvDecoder(CUcontext cuContext, bool bUseDeviceFrame, cudaVideoCodec eCodec,
|
||||
bool bLowLatency = false, bool bDeviceFramePitched = false,
|
||||
const Rect *pCropRect = NULL, const Dim *pResizeDim = NULL,
|
||||
int maxWidth = 0, int maxHeight = 0, unsigned int clkRate = 1000);
|
||||
bool extract_user_SEI_Message = false, int maxWidth = 0,
|
||||
int maxHeight = 0, unsigned int clkRate = 1000,
|
||||
bool force_zero_latency = false);
|
||||
~NvDecoder();
|
||||
|
||||
/**
|
||||
@@ -284,6 +315,13 @@ class NvDecoder {
|
||||
// stop the timer
|
||||
double stopTimer() { return m_stDecode_time.Stop(); }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief This function gets called when a sequence is ready to be decoded.
|
||||
The function also gets called when there is format change
|
||||
*/
|
||||
virtual int HandleVideoSequence(CUVIDEOFORMAT *pVideoFormat);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when
|
||||
@@ -322,10 +360,13 @@ class NvDecoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function gets called when a sequence is ready to be decoded.
|
||||
The function also gets called when there is format change
|
||||
*/
|
||||
int HandleVideoSequence(CUVIDEOFORMAT *pVideoFormat);
|
||||
* @brief Callback function to be registered for getting a callback when
|
||||
* all the unregistered user SEI Messages are parsed for a frame.
|
||||
*/
|
||||
static int CUDAAPI
|
||||
HandleSEIMessagesProc(void *pUserData, CUVIDSEIMESSAGEINFO *pSEIMessageInfo) {
|
||||
return ((NvDecoder *)pUserData)->GetSEIMessage(pSEIMessageInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function gets called when a picture is ready to be decoded.
|
||||
@@ -344,6 +385,13 @@ class NvDecoder {
|
||||
* one operating points
|
||||
*/
|
||||
int GetOperatingPoint(CUVIDOPERATINGPOINTINFO *pOPInfo);
|
||||
|
||||
/**
|
||||
* @brief This function gets called when all unregistered user SEI messages
|
||||
* are parsed for a frame
|
||||
*/
|
||||
int GetSEIMessage(CUVIDSEIMESSAGEINFO *pSEIMessageInfo);
|
||||
|
||||
/**
|
||||
* @brief This function reconfigure decoder if there is a change in
|
||||
* sequence params.
|
||||
@@ -374,7 +422,10 @@ class NvDecoder {
|
||||
// timestamps of decoded frames
|
||||
std::vector<int64_t> m_vTimestamp;
|
||||
int m_nDecodedFrame = 0, m_nDecodedFrameReturned = 0;
|
||||
int m_nDecodePicCnt = 0, m_nPicNumInDecodeOrder[32];
|
||||
int m_nDecodePicCnt = 0, m_nPicNumInDecodeOrder[MAX_FRM_CNT];
|
||||
CUVIDSEIMESSAGEINFO *m_pCurrSEIMessage = NULL;
|
||||
CUVIDSEIMESSAGEINFO m_SEIMessagesDisplayOrder[MAX_FRM_CNT];
|
||||
FILE *m_fpSEI = NULL;
|
||||
bool m_bEndDecodeDone = false;
|
||||
std::mutex m_mtxVPFrame;
|
||||
int m_nFrameAlloc = 0;
|
||||
@@ -392,4 +443,11 @@ class NvDecoder {
|
||||
|
||||
unsigned int m_nOperatingPoint = 0;
|
||||
bool m_bDispAllLayers = false;
|
||||
// In H.264, there is an inherent display latency for video contents
|
||||
// which do not have num_reorder_frames=0 in the VUI. This applies to
|
||||
// All-Intra and IPPP sequences as well. If the user wants zero display
|
||||
// latency for All-Intra and IPPP sequences, the below flag will enable
|
||||
// the display callback immediately after the decode callback.
|
||||
bool m_bForce_zero_latency = false;
|
||||
bool m_bExtractSEIMessage = false;
|
||||
};
|
||||
@@ -1,18 +1,32 @@
|
||||
/*
|
||||
* Copyright 2017-2020 NVIDIA Corporation. All rights reserved.
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "NvEncoder.h"
|
||||
|
||||
#include "nvcodec_api.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstring>
|
||||
static inline bool operator==(const GUID &guid1, const GUID &guid2) {
|
||||
@@ -28,7 +42,8 @@ NvEncoder::NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void *pDevice,
|
||||
uint32_t nWidth, uint32_t nHeight,
|
||||
NV_ENC_BUFFER_FORMAT eBufferFormat,
|
||||
uint32_t nExtraOutputDelay, bool bMotionEstimationOnly,
|
||||
bool bOutputInVideoMemory)
|
||||
bool bOutputInVideoMemory, bool bDX12Encode,
|
||||
bool bUseIVFContainer)
|
||||
: m_pDevice(pDevice),
|
||||
m_eDeviceType(eDeviceType),
|
||||
m_nWidth(nWidth),
|
||||
@@ -38,6 +53,8 @@ NvEncoder::NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void *pDevice,
|
||||
m_eBufferFormat(eBufferFormat),
|
||||
m_bMotionEstimationOnly(bMotionEstimationOnly),
|
||||
m_bOutputInVideoMemory(bOutputInVideoMemory),
|
||||
m_bIsDX12Encode(bDX12Encode),
|
||||
m_bUseIVFContainer(bUseIVFContainer),
|
||||
m_nExtraOutputDelay(nExtraOutputDelay),
|
||||
m_hEncoder(nullptr) {
|
||||
LoadNvEncApi();
|
||||
@@ -62,7 +79,7 @@ void NvEncoder::LoadNvEncApi() {
|
||||
uint32_t version = 0;
|
||||
uint32_t currentVersion =
|
||||
(NVENCAPI_MAJOR_VERSION << 4) | NVENCAPI_MINOR_VERSION;
|
||||
NVENC_API_CALL(NvEncodeAPIGetMaxSupportedVersion_ld(&version));
|
||||
NVENC_API_CALL(NvEncodeAPIGetMaxSupportedVersion(&version));
|
||||
if (currentVersion > version) {
|
||||
NVENC_THROW_ERROR(
|
||||
"Current Driver Version does not support this NvEncodeAPI version, "
|
||||
@@ -71,7 +88,7 @@ void NvEncoder::LoadNvEncApi() {
|
||||
}
|
||||
|
||||
m_nvenc = {NV_ENCODE_API_FUNCTION_LIST_VER};
|
||||
NVENC_API_CALL(NvEncodeAPICreateInstance_ld(&m_nvenc));
|
||||
NVENC_API_CALL(NvEncodeAPICreateInstance(&m_nvenc));
|
||||
}
|
||||
|
||||
NvEncoder::~NvEncoder() { DestroyHWEncoder(); }
|
||||
@@ -122,27 +139,21 @@ void NvEncoder::CreateDefaultEncoderParams(
|
||||
}
|
||||
#endif
|
||||
|
||||
NV_ENC_PRESET_CONFIG presetConfig = {NV_ENC_PRESET_CONFIG_VER,
|
||||
{NV_ENC_CONFIG_VER}};
|
||||
m_nvenc.nvEncGetEncodePresetConfig(m_hEncoder, codecGuid, presetGuid,
|
||||
&presetConfig);
|
||||
memcpy(pIntializeParams->encodeConfig, &presetConfig.presetCfg,
|
||||
sizeof(NV_ENC_CONFIG));
|
||||
pIntializeParams->encodeConfig->frameIntervalP = 1;
|
||||
pIntializeParams->encodeConfig->gopLength = NVENC_INFINITE_GOPLENGTH;
|
||||
|
||||
pIntializeParams->tuningInfo = tuningInfo;
|
||||
pIntializeParams->encodeConfig->rcParams.rateControlMode =
|
||||
NV_ENC_PARAMS_RC_CONSTQP;
|
||||
|
||||
if (!m_bMotionEstimationOnly) {
|
||||
pIntializeParams->tuningInfo = tuningInfo;
|
||||
NV_ENC_PRESET_CONFIG presetConfig = {NV_ENC_PRESET_CONFIG_VER,
|
||||
{NV_ENC_CONFIG_VER}};
|
||||
m_nvenc.nvEncGetEncodePresetConfigEx(m_hEncoder, codecGuid, presetGuid,
|
||||
tuningInfo, &presetConfig);
|
||||
memcpy(pIntializeParams->encodeConfig, &presetConfig.presetCfg,
|
||||
sizeof(NV_ENC_CONFIG));
|
||||
} else {
|
||||
// There are changes in the structure layout, therefore users are recommended
|
||||
// to be careful while moving their application to the new header. Following
|
||||
// initialization has changed for the same reason.
|
||||
NV_ENC_PRESET_CONFIG presetConfig = {
|
||||
NV_ENC_PRESET_CONFIG_VER, 0, {NV_ENC_CONFIG_VER}};
|
||||
m_nvenc.nvEncGetEncodePresetConfigEx(m_hEncoder, codecGuid, presetGuid,
|
||||
tuningInfo, &presetConfig);
|
||||
memcpy(pIntializeParams->encodeConfig, &presetConfig.presetCfg,
|
||||
sizeof(NV_ENC_CONFIG));
|
||||
|
||||
if (m_bMotionEstimationOnly) {
|
||||
m_encodeConfig.version = NV_ENC_CONFIG_VER;
|
||||
m_encodeConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
|
||||
m_encodeConfig.rcParams.constQP = {28, 31, 25};
|
||||
@@ -157,12 +168,13 @@ void NvEncoder::CreateDefaultEncoderParams(
|
||||
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;
|
||||
pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.inputBitDepth =
|
||||
pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig
|
||||
.outputBitDepth =
|
||||
(m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT ||
|
||||
m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT)
|
||||
? NV_ENC_BIT_DEPTH_10
|
||||
: NV_ENC_BIT_DEPTH_8;
|
||||
if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 ||
|
||||
m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) {
|
||||
pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig
|
||||
@@ -170,6 +182,22 @@ void NvEncoder::CreateDefaultEncoderParams(
|
||||
}
|
||||
pIntializeParams->encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod =
|
||||
pIntializeParams->encodeConfig->gopLength;
|
||||
} else if (pIntializeParams->encodeGUID == NV_ENC_CODEC_AV1_GUID) {
|
||||
pIntializeParams->encodeConfig->encodeCodecConfig.av1Config.inputBitDepth =
|
||||
(m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT)
|
||||
? NV_ENC_BIT_DEPTH_10
|
||||
: NV_ENC_BIT_DEPTH_8;
|
||||
pIntializeParams->encodeConfig->encodeCodecConfig.av1Config
|
||||
.chromaFormatIDC = 1;
|
||||
pIntializeParams->encodeConfig->encodeCodecConfig.av1Config.idrPeriod =
|
||||
pIntializeParams->encodeConfig->gopLength;
|
||||
if (m_bOutputInVideoMemory) {
|
||||
pIntializeParams->encodeConfig->frameIntervalP = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bIsDX12Encode) {
|
||||
pIntializeParams->bufferFormat = m_eBufferFormat;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -192,7 +220,8 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
}
|
||||
|
||||
if (pEncoderParams->encodeGUID != NV_ENC_CODEC_H264_GUID &&
|
||||
pEncoderParams->encodeGUID != NV_ENC_CODEC_HEVC_GUID) {
|
||||
pEncoderParams->encodeGUID != NV_ENC_CODEC_HEVC_GUID &&
|
||||
pEncoderParams->encodeGUID != NV_ENC_CODEC_AV1_GUID) {
|
||||
NVENC_THROW_ERROR("Invalid codec guid", NV_ENC_ERR_INVALID_PARAM);
|
||||
}
|
||||
|
||||
@@ -204,6 +233,14 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
}
|
||||
}
|
||||
|
||||
if (pEncoderParams->encodeGUID == NV_ENC_CODEC_AV1_GUID) {
|
||||
if (m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444 ||
|
||||
m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT) {
|
||||
NVENC_THROW_ERROR("YUV444 format isn't supported by AV1 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) &&
|
||||
@@ -219,8 +256,9 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT)
|
||||
? true
|
||||
: false;
|
||||
if (yuv10BitFormat && pEncoderParams->encodeConfig->encodeCodecConfig
|
||||
.hevcConfig.pixelBitDepthMinus8 != 2) {
|
||||
if (yuv10BitFormat &&
|
||||
pEncoderParams->encodeConfig->encodeCodecConfig.hevcConfig
|
||||
.inputBitDepth != NV_ENC_BIT_DEPTH_10) {
|
||||
NVENC_THROW_ERROR("Invalid PixelBitdepth", NV_ENC_ERR_INVALID_PARAM);
|
||||
}
|
||||
|
||||
@@ -232,6 +270,28 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
}
|
||||
}
|
||||
|
||||
if (pEncoderParams->encodeGUID == NV_ENC_CODEC_AV1_GUID) {
|
||||
bool yuv10BitFormat =
|
||||
(m_eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT) ? true : false;
|
||||
if (yuv10BitFormat &&
|
||||
pEncoderParams->encodeConfig->encodeCodecConfig.av1Config
|
||||
.inputBitDepth != NV_ENC_BIT_DEPTH_10) {
|
||||
NVENC_THROW_ERROR("Invalid PixelBitdepth", NV_ENC_ERR_INVALID_PARAM);
|
||||
}
|
||||
|
||||
if (pEncoderParams->encodeConfig->encodeCodecConfig.av1Config
|
||||
.chromaFormatIDC != 1) {
|
||||
NVENC_THROW_ERROR("Invalid ChromaFormatIDC", NV_ENC_ERR_INVALID_PARAM);
|
||||
}
|
||||
|
||||
if (m_bOutputInVideoMemory &&
|
||||
pEncoderParams->encodeConfig->frameIntervalP > 1) {
|
||||
NVENC_THROW_ERROR(
|
||||
"Alt Ref frames not supported for AV1 in case of OutputInVideoMemory",
|
||||
NV_ENC_ERR_INVALID_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&m_initializeParams, pEncoderParams, sizeof(m_initializeParams));
|
||||
m_initializeParams.version = NV_ENC_INITIALIZE_PARAMS_VER;
|
||||
|
||||
@@ -240,19 +300,31 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
sizeof(m_encodeConfig));
|
||||
m_encodeConfig.version = NV_ENC_CONFIG_VER;
|
||||
} else {
|
||||
NV_ENC_PRESET_CONFIG presetConfig = {NV_ENC_PRESET_CONFIG_VER,
|
||||
{NV_ENC_CONFIG_VER}};
|
||||
// There are changes in the structure layout, therefore users are
|
||||
// recommended to be careful while moving their application to the new
|
||||
// header. Following initialization has changed for the same reason.
|
||||
NV_ENC_PRESET_CONFIG presetConfig = {
|
||||
NV_ENC_PRESET_CONFIG_VER, 0, {NV_ENC_CONFIG_VER}};
|
||||
if (!m_bMotionEstimationOnly) {
|
||||
m_nvenc.nvEncGetEncodePresetConfigEx(
|
||||
m_hEncoder, pEncoderParams->encodeGUID, pEncoderParams->presetGUID,
|
||||
pEncoderParams->tuningInfo, &presetConfig);
|
||||
memcpy(&m_encodeConfig, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG));
|
||||
if (m_bOutputInVideoMemory &&
|
||||
pEncoderParams->encodeGUID == NV_ENC_CODEC_AV1_GUID) {
|
||||
m_encodeConfig.frameIntervalP = 1;
|
||||
}
|
||||
} else {
|
||||
m_encodeConfig.version = NV_ENC_CONFIG_VER;
|
||||
m_encodeConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
|
||||
m_encodeConfig.rcParams.constQP = {28, 31, 25};
|
||||
}
|
||||
}
|
||||
|
||||
if (((uint32_t)m_encodeConfig.frameIntervalP) > m_encodeConfig.gopLength) {
|
||||
m_encodeConfig.frameIntervalP = m_encodeConfig.gopLength;
|
||||
}
|
||||
|
||||
m_initializeParams.encodeConfig = &m_encodeConfig;
|
||||
|
||||
NVENC_API_CALL(
|
||||
@@ -268,7 +340,6 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
m_encodeConfig.rcParams.lookaheadDepth +
|
||||
m_nExtraOutputDelay;
|
||||
m_nOutputDelay = m_nEncoderBuffer - 1;
|
||||
m_vMappedInputBuffers.resize(m_nEncoderBuffer, nullptr);
|
||||
|
||||
if (!m_bOutputInVideoMemory) {
|
||||
m_vpCompletionEvent.resize(m_nEncoderBuffer, nullptr);
|
||||
@@ -277,12 +348,16 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
#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);
|
||||
if (!m_bIsDX12Encode) {
|
||||
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);
|
||||
|
||||
if (m_bMotionEstimationOnly) {
|
||||
m_vMappedRefBuffers.resize(m_nEncoderBuffer, nullptr);
|
||||
|
||||
@@ -290,7 +365,7 @@ void NvEncoder::CreateEncoder(const NV_ENC_INITIALIZE_PARAMS *pEncoderParams) {
|
||||
InitializeMVOutputBuffer();
|
||||
}
|
||||
} else {
|
||||
if (!m_bOutputInVideoMemory) {
|
||||
if (!m_bOutputInVideoMemory && !m_bIsDX12Encode) {
|
||||
m_vBitstreamOutputBuffer.resize(m_nEncoderBuffer, nullptr);
|
||||
InitializeBitstreamBuffer();
|
||||
}
|
||||
@@ -317,9 +392,11 @@ void NvEncoder::DestroyHWEncoder() {
|
||||
#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);
|
||||
if (!m_bIsDX12Encode) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@@ -329,7 +406,7 @@ void NvEncoder::DestroyHWEncoder() {
|
||||
if (m_bMotionEstimationOnly) {
|
||||
DestroyMVOutputBuffer();
|
||||
} else {
|
||||
DestroyBitstreamBuffer();
|
||||
if (!m_bIsDX12Encode) DestroyBitstreamBuffer();
|
||||
}
|
||||
|
||||
m_nvenc.nvEncDestroyEncoder(m_hEncoder);
|
||||
@@ -444,6 +521,7 @@ NVENCSTATUS NvEncoder::DoEncode(NV_ENC_INPUT_PTR inputBuffer,
|
||||
picParams.bufferFmt = GetPixelFormat();
|
||||
picParams.inputWidth = GetEncodeWidth();
|
||||
picParams.inputHeight = GetEncodeHeight();
|
||||
picParams.frameIdx = m_iToSend;
|
||||
picParams.outputBitstream = outputBuffer;
|
||||
picParams.completionEvent = GetCompletionEvent(m_iToSend % m_nEncoderBuffer);
|
||||
NVENCSTATUS nvStatus = m_nvenc.nvEncEncodePicture(m_hEncoder, &picParams);
|
||||
@@ -488,8 +566,25 @@ void NvEncoder::GetEncodedPacket(std::vector<NV_ENC_OUTPUT_PTR> &vOutputBuffer,
|
||||
vPacket.push_back(std::vector<uint8_t>());
|
||||
}
|
||||
vPacket[i].clear();
|
||||
|
||||
if ((m_initializeParams.encodeGUID == NV_ENC_CODEC_AV1_GUID) &&
|
||||
(m_bUseIVFContainer)) {
|
||||
if (m_bWriteIVFFileHeader) {
|
||||
m_IVFUtils.WriteFileHeader(vPacket[i], MAKE_FOURCC('A', 'V', '0', '1'),
|
||||
m_initializeParams.encodeWidth,
|
||||
m_initializeParams.encodeHeight,
|
||||
m_initializeParams.frameRateNum,
|
||||
m_initializeParams.frameRateDen, 0xFFFF);
|
||||
m_bWriteIVFFileHeader = false;
|
||||
}
|
||||
|
||||
m_IVFUtils.WriteFrameHeader(vPacket[i],
|
||||
lockBitstreamData.bitstreamSizeInBytes,
|
||||
lockBitstreamData.outputTimeStamp);
|
||||
}
|
||||
vPacket[i].insert(vPacket[i].end(), &pData[0],
|
||||
&pData[lockBitstreamData.bitstreamSizeInBytes]);
|
||||
|
||||
i++;
|
||||
|
||||
NVENC_API_CALL(m_nvenc.nvEncUnlockBitstream(
|
||||
@@ -533,7 +628,8 @@ bool NvEncoder::Reconfigure(
|
||||
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_BUFFER_USAGE bufferUsage,
|
||||
NV_ENC_FENCE_POINT_D3D12 *pInputFencePoint) {
|
||||
NV_ENC_REGISTER_RESOURCE registerResource = {NV_ENC_REGISTER_RESOURCE_VER};
|
||||
registerResource.resourceType = eResourceType;
|
||||
registerResource.resourceToRegister = pBuffer;
|
||||
@@ -542,6 +638,7 @@ NV_ENC_REGISTERED_PTR NvEncoder::RegisterResource(
|
||||
registerResource.pitch = pitch;
|
||||
registerResource.bufferFormat = bufferFormat;
|
||||
registerResource.bufferUsage = bufferUsage;
|
||||
registerResource.pInputFencePoint = pInputFencePoint;
|
||||
NVENC_API_CALL(m_nvenc.nvEncRegisterResource(m_hEncoder, ®isterResource));
|
||||
|
||||
return registerResource.registeredResource;
|
||||
@@ -1,12 +1,28 @@
|
||||
/*
|
||||
* Copyright 2017-2020 NVIDIA Corporation. All rights reserved.
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -20,6 +36,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "NvCodecUtils.h"
|
||||
#include "log.h"
|
||||
#include "nvEncodeAPI.h"
|
||||
|
||||
/**
|
||||
@@ -45,12 +63,74 @@ class NVENCException : public std::exception {
|
||||
NVENCSTATUS m_errorCode;
|
||||
};
|
||||
|
||||
inline const char* GetNvStatusString(NVENCSTATUS eStatus) {
|
||||
switch (eStatus) {
|
||||
case NV_ENC_SUCCESS:
|
||||
return "NV_ENC_SUCCESS";
|
||||
case NV_ENC_ERR_NO_ENCODE_DEVICE:
|
||||
return "NV_ENC_ERR_NO_ENCODE_DEVICE";
|
||||
case NV_ENC_ERR_UNSUPPORTED_DEVICE:
|
||||
return "NV_ENC_ERR_UNSUPPORTED_DEVICE";
|
||||
case NV_ENC_ERR_INVALID_ENCODERDEVICE:
|
||||
return "NV_ENC_ERR_INVALID_ENCODERDEVICE";
|
||||
case NV_ENC_ERR_INVALID_DEVICE:
|
||||
return "NV_ENC_ERR_INVALID_DEVICE";
|
||||
case NV_ENC_ERR_DEVICE_NOT_EXIST:
|
||||
return "NV_ENC_ERR_DEVICE_NOT_EXIST";
|
||||
case NV_ENC_ERR_INVALID_PTR:
|
||||
return "NV_ENC_ERR_INVALID_PTR";
|
||||
case NV_ENC_ERR_INVALID_EVENT:
|
||||
return "NV_ENC_ERR_INVALID_EVENT";
|
||||
case NV_ENC_ERR_INVALID_PARAM:
|
||||
return "NV_ENC_ERR_INVALID_PARAM";
|
||||
case NV_ENC_ERR_INVALID_CALL:
|
||||
return "NV_ENC_ERR_INVALID_CALL";
|
||||
case NV_ENC_ERR_OUT_OF_MEMORY:
|
||||
return "NV_ENC_ERR_OUT_OF_MEMORY";
|
||||
case NV_ENC_ERR_ENCODER_NOT_INITIALIZED:
|
||||
return "NV_ENC_ERR_ENCODER_NOT_INITIALIZED";
|
||||
case NV_ENC_ERR_UNSUPPORTED_PARAM:
|
||||
return "NV_ENC_ERR_UNSUPPORTED_PARAM";
|
||||
case NV_ENC_ERR_LOCK_BUSY:
|
||||
return "NV_ENC_ERR_LOCK_BUSY";
|
||||
case NV_ENC_ERR_NOT_ENOUGH_BUFFER:
|
||||
return "NV_ENC_ERR_NOT_ENOUGH_BUFFER";
|
||||
case NV_ENC_ERR_INVALID_VERSION:
|
||||
return "NV_ENC_ERR_INVALID_VERSION";
|
||||
case NV_ENC_ERR_MAP_FAILED:
|
||||
return "NV_ENC_ERR_MAP_FAILED";
|
||||
case NV_ENC_ERR_NEED_MORE_INPUT:
|
||||
return "NV_ENC_ERR_NEED_MORE_INPUT";
|
||||
case NV_ENC_ERR_ENCODER_BUSY:
|
||||
return "NV_ENC_ERR_ENCODER_BUSY";
|
||||
case NV_ENC_ERR_EVENT_NOT_REGISTERD:
|
||||
return "NV_ENC_ERR_EVENT_NOT_REGISTERD";
|
||||
case NV_ENC_ERR_GENERIC:
|
||||
return "NV_ENC_ERR_GENERIC";
|
||||
case NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY:
|
||||
return "NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY";
|
||||
case NV_ENC_ERR_UNIMPLEMENTED:
|
||||
return "NV_ENC_ERR_UNIMPLEMENTED";
|
||||
case NV_ENC_ERR_RESOURCE_REGISTER_FAILED:
|
||||
return "NV_ENC_ERR_RESOURCE_REGISTER_FAILED";
|
||||
case NV_ENC_ERR_RESOURCE_NOT_REGISTERED:
|
||||
return "NV_ENC_ERR_RESOURCE_NOT_REGISTERED";
|
||||
case NV_ENC_ERR_RESOURCE_NOT_MAPPED:
|
||||
return "NV_ENC_ERR_RESOURCE_NOT_MAPPED";
|
||||
case NV_ENC_ERR_NEED_MORE_OUTPUT:
|
||||
return "NV_ENC_ERR_NEED_MORE_OUTPUT";
|
||||
default:
|
||||
return "NVENC_UNKNOWN_ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
inline NVENCException NVENCException::makeNVENCException(
|
||||
const std::string& errorStr, const NVENCSTATUS errorCode,
|
||||
const std::string& functionName, const std::string& fileName, int lineNo) {
|
||||
std::ostringstream errorLog;
|
||||
errorLog << functionName << " : " << errorStr << " at " << fileName << ":"
|
||||
<< lineNo << std::endl;
|
||||
LOG_ERROR("{} failed due to {}", functionName, GetNvStatusString(errorCode));
|
||||
NVENCException exception(errorLog.str(), errorCode);
|
||||
return exception;
|
||||
}
|
||||
@@ -92,7 +172,7 @@ class NvEncoder {
|
||||
* Application must call this function to initialize the encoder, before
|
||||
* starting to encode any frames.
|
||||
*/
|
||||
void CreateEncoder(const NV_ENC_INITIALIZE_PARAMS* pEncodeParams);
|
||||
virtual void CreateEncoder(const NV_ENC_INITIALIZE_PARAMS* pEncodeParams);
|
||||
|
||||
/**
|
||||
* @brief This function is used to destroy the encoder session.
|
||||
@@ -100,7 +180,7 @@ class NvEncoder {
|
||||
* clean up any allocated resources. The application must call EndEncode()
|
||||
* function to get any queued encoded frames before calling DestroyEncoder().
|
||||
*/
|
||||
void DestroyEncoder();
|
||||
virtual void DestroyEncoder();
|
||||
|
||||
/**
|
||||
* @brief This function is used to reconfigure an existing encoder session.
|
||||
@@ -124,8 +204,8 @@ class NvEncoder {
|
||||
* data, which has been copied to an input buffer obtained from the
|
||||
* GetNextInputFrame() function.
|
||||
*/
|
||||
void EncodeFrame(std::vector<std::vector<uint8_t>>& vPacket,
|
||||
NV_ENC_PIC_PARAMS* pPicParams = nullptr);
|
||||
virtual void EncodeFrame(std::vector<std::vector<uint8_t>>& vPacket,
|
||||
NV_ENC_PIC_PARAMS* pPicParams = nullptr);
|
||||
|
||||
/**
|
||||
* @brief This function to flush the encoder queue.
|
||||
@@ -134,7 +214,7 @@ class NvEncoder {
|
||||
* from the encoder. The application must call this function before
|
||||
* destroying an encoder session.
|
||||
*/
|
||||
void EndEncode(std::vector<std::vector<uint8_t>>& vPacket);
|
||||
virtual void EndEncode(std::vector<std::vector<uint8_t>>& vPacket);
|
||||
|
||||
/**
|
||||
* @brief This function is used to query hardware encoder capabilities.
|
||||
@@ -272,6 +352,13 @@ class NvEncoder {
|
||||
*/
|
||||
uint32_t GetEncoderBufferCount() const { return m_nEncoderBuffer; }
|
||||
|
||||
/*
|
||||
* @brief This function returns initializeParams(width, height, fps etc).
|
||||
*/
|
||||
NV_ENC_INITIALIZE_PARAMS GetinitializeParams() const {
|
||||
return m_initializeParams;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief NvEncoder class constructor.
|
||||
@@ -280,7 +367,8 @@ class NvEncoder {
|
||||
NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void* pDevice, uint32_t nWidth,
|
||||
uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat,
|
||||
uint32_t nOutputDelay, bool bMotionEstimationOnly,
|
||||
bool bOutputInVideoMemory = false);
|
||||
bool bOutputInVideoMemory = false, bool bDX12Encode = false,
|
||||
bool bUseIVFContainer = true);
|
||||
|
||||
/**
|
||||
* @brief This function is used to check if hardware encoder is properly
|
||||
@@ -314,7 +402,8 @@ class NvEncoder {
|
||||
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_BUFFER_USAGE bufferUsage = NV_ENC_INPUT_IMAGE,
|
||||
NV_ENC_FENCE_POINT_D3D12* pInputFencePoint = NULL);
|
||||
|
||||
/**
|
||||
* @brief This function returns maximum width used to open the encoder
|
||||
@@ -448,8 +537,10 @@ class NvEncoder {
|
||||
protected:
|
||||
bool m_bMotionEstimationOnly = false;
|
||||
bool m_bOutputInVideoMemory = false;
|
||||
bool m_bIsDX12Encode = false;
|
||||
void* m_hEncoder = nullptr;
|
||||
NV_ENCODE_API_FUNCTION_LIST m_nvenc;
|
||||
NV_ENC_INITIALIZE_PARAMS m_initializeParams = {};
|
||||
std::vector<NvEncInputFrame> m_vInputFrames;
|
||||
std::vector<NV_ENC_REGISTERED_PTR> m_vRegisteredResources;
|
||||
std::vector<NvEncInputFrame> m_vReferenceFrames;
|
||||
@@ -462,6 +553,9 @@ class NvEncoder {
|
||||
int32_t m_iGot = 0;
|
||||
int32_t m_nEncoderBuffer = 0;
|
||||
int32_t m_nOutputDelay = 0;
|
||||
IVFUtils m_IVFUtils;
|
||||
bool m_bWriteIVFFileHeader = true;
|
||||
bool m_bUseIVFContainer = true;
|
||||
|
||||
private:
|
||||
uint32_t m_nWidth;
|
||||
@@ -469,7 +563,6 @@ class NvEncoder {
|
||||
NV_ENC_BUFFER_FORMAT m_eBufferFormat;
|
||||
void* m_pDevice;
|
||||
NV_ENC_DEVICE_TYPE m_eDeviceType;
|
||||
NV_ENC_INITIALIZE_PARAMS m_initializeParams = {};
|
||||
NV_ENC_CONFIG m_encodeConfig = {};
|
||||
bool m_bEncoderInitialized = false;
|
||||
uint32_t m_nExtraOutputDelay =
|
||||
840
src/media/nvcodec/NvEncoderCLIOptions.h
Normal file
840
src/media/nvcodec/NvEncoderCLIOptions.h
Normal file
@@ -0,0 +1,840 @@
|
||||
/*
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include "Logger.h"
|
||||
#include "nvEncodeAPI.h"
|
||||
|
||||
extern simplelogger::Logger *logger;
|
||||
|
||||
#ifndef _WIN32
|
||||
inline bool operator==(const GUID &guid1, const GUID &guid2) {
|
||||
return !memcmp(&guid1, &guid2, sizeof(GUID));
|
||||
}
|
||||
|
||||
inline bool operator!=(const GUID &guid1, const GUID &guid2) {
|
||||
return !(guid1 == guid2);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper class for parsing generic encoder options and preparing encoder
|
||||
* initialization parameters. This class also provides some utility methods
|
||||
* which generate verbose descriptions of the provided set of encoder
|
||||
* initialization parameters.
|
||||
*/
|
||||
class NvEncoderInitParam {
|
||||
public:
|
||||
NvEncoderInitParam(const char *szParam = "",
|
||||
std::function<void(NV_ENC_INITIALIZE_PARAMS *pParams)> *pfuncInit = NULL, bool _bLowLatency = false)
|
||||
: strParam(szParam), bLowLatency(_bLowLatency)
|
||||
{
|
||||
if (pfuncInit) {
|
||||
funcInit = *pfuncInit;
|
||||
}
|
||||
|
||||
std::transform(strParam.begin(), strParam.end(), strParam.begin(), tolower);
|
||||
std::istringstream ss(strParam);
|
||||
tokens = std::vector<std::string> {
|
||||
std::istream_iterator<std::string>(ss),
|
||||
std::istream_iterator<std::string>()
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < tokens.size(); i++)
|
||||
{
|
||||
if (tokens[i] == "-codec" && ++i != tokens.size())
|
||||
{
|
||||
ParseString("-codec", tokens[i], vCodec, szCodecNames, &guidCodec);
|
||||
continue;
|
||||
}
|
||||
if (tokens[i] == "-preset" && ++i != tokens.size()) {
|
||||
ParseString("-preset", tokens[i], vPreset, szPresetNames, &guidPreset);
|
||||
continue;
|
||||
}
|
||||
if (tokens[i] == "-tuninginfo" && ++i != tokens.size())
|
||||
{
|
||||
ParseString("-tuninginfo", tokens[i], vTuningInfo, szTuningInfoNames, &m_TuningInfo);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual ~NvEncoderInitParam() {}
|
||||
virtual bool IsCodecH264() {
|
||||
return GetEncodeGUID() == NV_ENC_CODEC_H264_GUID;
|
||||
}
|
||||
|
||||
virtual bool IsCodecHEVC() {
|
||||
return GetEncodeGUID() == NV_ENC_CODEC_HEVC_GUID;
|
||||
}
|
||||
|
||||
virtual bool IsCodecAV1() {
|
||||
return GetEncodeGUID() == NV_ENC_CODEC_AV1_GUID;
|
||||
}
|
||||
|
||||
std::string GetHelpMessage(bool bMeOnly = false, bool bUnbuffered = false, bool bHide444 = false, bool bOutputInVidMem = false)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
if (bOutputInVidMem && bMeOnly)
|
||||
{
|
||||
oss << "-codec Codec: " << "h264" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "-codec Codec: " << szCodecNames << std::endl;
|
||||
}
|
||||
|
||||
oss << "-preset Preset: " << szPresetNames << std::endl
|
||||
<< "-profile H264: " << szH264ProfileNames;
|
||||
|
||||
if (bOutputInVidMem && bMeOnly)
|
||||
{
|
||||
oss << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "; HEVC: " << szHevcProfileNames;
|
||||
oss << "; AV1: " << szAV1ProfileNames << std::endl;
|
||||
}
|
||||
|
||||
if (!bMeOnly)
|
||||
{
|
||||
if (bLowLatency == false)
|
||||
oss << "-tuninginfo TuningInfo: " << szTuningInfoNames << std::endl;
|
||||
else
|
||||
oss << "-tuninginfo TuningInfo: " << szLowLatencyTuningInfoNames << std::endl;
|
||||
oss << "-multipass Multipass: " << szMultipass << std::endl;
|
||||
}
|
||||
|
||||
if (!bHide444 && !bLowLatency)
|
||||
{
|
||||
oss << "-444 (Only for RGB input) YUV444 encode. Not valid for AV1 Codec" << std::endl;
|
||||
}
|
||||
if (bMeOnly) return oss.str();
|
||||
oss << "-fps Frame rate" << std::endl;
|
||||
|
||||
if (!bUnbuffered && !bLowLatency)
|
||||
{
|
||||
oss << "-bf Number of consecutive B-frames" << std::endl;
|
||||
}
|
||||
|
||||
if (!bLowLatency)
|
||||
{
|
||||
oss << "-rc Rate control mode: " << szRcModeNames << std::endl
|
||||
<< "-gop Length of GOP (Group of Pictures)" << std::endl
|
||||
<< "-bitrate Average bit rate, can be in unit of 1, K, M" << std::endl
|
||||
<< "Note: Fps or Average bit rate values for each session can be specified in the form of v1,v1,v3 (no space) for AppTransOneToN" << std::endl
|
||||
<< " If the number of 'bitrate' or 'fps' values specified are less than the number of sessions, then the last specified value will be considered for the remaining sessions" << std::endl
|
||||
<< "-maxbitrate Max bit rate, can be in unit of 1, K, M" << std::endl
|
||||
<< "-vbvbufsize VBV buffer size in bits, can be in unit of 1, K, M" << std::endl
|
||||
<< "-vbvinit VBV initial delay in bits, can be in unit of 1, K, M" << std::endl
|
||||
<< "-aq Enable spatial AQ and set its stength (range 1-15, 0-auto)" << std::endl
|
||||
<< "-temporalaq (No value) Enable temporal AQ" << std::endl
|
||||
<< "-cq Target constant quality level for VBR mode (range 1-51, 0-auto)" << std::endl;
|
||||
}
|
||||
if (!bUnbuffered && !bLowLatency)
|
||||
{
|
||||
oss << "-lookahead Maximum depth of lookahead (range 0-(31 - number of B frames))" << std::endl;
|
||||
}
|
||||
oss << "-qmin Min QP value" << std::endl
|
||||
<< "-qmax Max QP value" << std::endl
|
||||
<< "-initqp Initial QP value" << std::endl;
|
||||
if (!bLowLatency)
|
||||
{
|
||||
oss << "-constqp QP value for constqp rate control mode" << std::endl
|
||||
<< "Note: QP value can be in the form of qp_of_P_B_I or qp_P,qp_B,qp_I (no space)" << std::endl;
|
||||
}
|
||||
if (bUnbuffered && !bLowLatency)
|
||||
{
|
||||
oss << "Note: Options -bf and -lookahead are unavailable for this app" << std::endl;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate and return a string describing the values of the main/common
|
||||
* encoder initialization parameters
|
||||
*/
|
||||
std::string MainParamToString(const NV_ENC_INITIALIZE_PARAMS *pParams) {
|
||||
std::ostringstream os;
|
||||
os
|
||||
<< "Encoding Parameters:"
|
||||
<< std::endl << "\tcodec : " << ConvertValueToString(vCodec, szCodecNames, pParams->encodeGUID)
|
||||
<< std::endl << "\tpreset : " << ConvertValueToString(vPreset, szPresetNames, pParams->presetGUID);
|
||||
if (pParams->tuningInfo)
|
||||
{
|
||||
os << std::endl << "\ttuningInfo : " << ConvertValueToString(vTuningInfo, szTuningInfoNames, pParams->tuningInfo);
|
||||
}
|
||||
os
|
||||
<< std::endl << "\tprofile : " << ConvertValueToString(vProfile, szProfileNames, pParams->encodeConfig->profileGUID)
|
||||
<< std::endl << "\tchroma : " << ConvertValueToString(vChroma, szChromaNames, (pParams->encodeGUID == NV_ENC_CODEC_H264_GUID) ? pParams->encodeConfig->encodeCodecConfig.h264Config.chromaFormatIDC :
|
||||
(pParams->encodeGUID == NV_ENC_CODEC_HEVC_GUID) ? pParams->encodeConfig->encodeCodecConfig.hevcConfig.chromaFormatIDC :
|
||||
pParams->encodeConfig->encodeCodecConfig.av1Config.chromaFormatIDC)
|
||||
<< std::endl << "\tbitdepth : " << ((pParams->encodeGUID == NV_ENC_CODEC_H264_GUID) ? pParams->encodeConfig->encodeCodecConfig.h264Config.inputBitDepth : (pParams->encodeGUID == NV_ENC_CODEC_HEVC_GUID) ?
|
||||
pParams->encodeConfig->encodeCodecConfig.hevcConfig.inputBitDepth : pParams->encodeConfig->encodeCodecConfig.av1Config.inputBitDepth)
|
||||
<< std::endl << "\trc : " << ConvertValueToString(vRcMode, szRcModeNames, pParams->encodeConfig->rcParams.rateControlMode)
|
||||
;
|
||||
if (pParams->encodeConfig->rcParams.rateControlMode == NV_ENC_PARAMS_RC_CONSTQP) {
|
||||
os << " (P,B,I=" << pParams->encodeConfig->rcParams.constQP.qpInterP << "," << pParams->encodeConfig->rcParams.constQP.qpInterB << "," << pParams->encodeConfig->rcParams.constQP.qpIntra << ")";
|
||||
}
|
||||
os
|
||||
<< std::endl << "\tfps : " << pParams->frameRateNum << "/" << pParams->frameRateDen
|
||||
<< std::endl << "\tgop : " << (pParams->encodeConfig->gopLength == NVENC_INFINITE_GOPLENGTH ? "INF" : std::to_string(pParams->encodeConfig->gopLength))
|
||||
<< std::endl << "\tbf : " << pParams->encodeConfig->frameIntervalP - 1
|
||||
<< std::endl << "\tmultipass : " << pParams->encodeConfig->rcParams.multiPass
|
||||
<< std::endl << "\tsize : " << pParams->encodeWidth << "x" << pParams->encodeHeight
|
||||
<< std::endl << "\tbitrate : " << pParams->encodeConfig->rcParams.averageBitRate
|
||||
<< std::endl << "\tmaxbitrate : " << pParams->encodeConfig->rcParams.maxBitRate
|
||||
<< std::endl << "\tvbvbufsize : " << pParams->encodeConfig->rcParams.vbvBufferSize
|
||||
<< std::endl << "\tvbvinit : " << pParams->encodeConfig->rcParams.vbvInitialDelay
|
||||
<< std::endl << "\taq : " << (pParams->encodeConfig->rcParams.enableAQ ? (pParams->encodeConfig->rcParams.aqStrength ? std::to_string(pParams->encodeConfig->rcParams.aqStrength) : "auto") : "disabled")
|
||||
<< std::endl << "\ttemporalaq : " << (pParams->encodeConfig->rcParams.enableTemporalAQ ? "enabled" : "disabled")
|
||||
<< std::endl << "\tlookahead : " << (pParams->encodeConfig->rcParams.enableLookahead ? std::to_string(pParams->encodeConfig->rcParams.lookaheadDepth) : "disabled")
|
||||
<< std::endl << "\tcq : " << (unsigned int)pParams->encodeConfig->rcParams.targetQuality
|
||||
<< std::endl << "\tqmin : P,B,I=" << (int)pParams->encodeConfig->rcParams.minQP.qpInterP << "," << (int)pParams->encodeConfig->rcParams.minQP.qpInterB << "," << (int)pParams->encodeConfig->rcParams.minQP.qpIntra
|
||||
<< std::endl << "\tqmax : P,B,I=" << (int)pParams->encodeConfig->rcParams.maxQP.qpInterP << "," << (int)pParams->encodeConfig->rcParams.maxQP.qpInterB << "," << (int)pParams->encodeConfig->rcParams.maxQP.qpIntra
|
||||
<< std::endl << "\tinitqp : P,B,I=" << (int)pParams->encodeConfig->rcParams.initialRCQP.qpInterP << "," << (int)pParams->encodeConfig->rcParams.initialRCQP.qpInterB << "," << (int)pParams->encodeConfig->rcParams.initialRCQP.qpIntra
|
||||
;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual GUID GetEncodeGUID() { return guidCodec; }
|
||||
virtual GUID GetPresetGUID() { return guidPreset; }
|
||||
virtual NV_ENC_TUNING_INFO GetTuningInfo() { return m_TuningInfo; }
|
||||
|
||||
/*
|
||||
* @brief Set encoder initialization parameters based on input options
|
||||
* This method parses the tokens formed from the command line options
|
||||
* provided to the application and sets the fields from NV_ENC_INITIALIZE_PARAMS
|
||||
* based on the supplied values.
|
||||
*/
|
||||
|
||||
virtual void setTransOneToN(bool isTransOneToN)
|
||||
{
|
||||
bTransOneToN = isTransOneToN;
|
||||
}
|
||||
|
||||
virtual void SetInitParams(NV_ENC_INITIALIZE_PARAMS *pParams, NV_ENC_BUFFER_FORMAT eBufferFormat)
|
||||
{
|
||||
NV_ENC_CONFIG &config = *pParams->encodeConfig;
|
||||
int nGOPOption = 0, nBFramesOption = 0;
|
||||
for (unsigned i = 0; i < tokens.size(); i++)
|
||||
{
|
||||
if (
|
||||
tokens[i] == "-codec" && ++i ||
|
||||
tokens[i] == "-preset" && ++i ||
|
||||
tokens[i] == "-tuninginfo" && ++i ||
|
||||
tokens[i] == "-multipass" && ++i != tokens.size() && ParseString("-multipass", tokens[i], vMultiPass, szMultipass, &config.rcParams.multiPass) ||
|
||||
tokens[i] == "-profile" && ++i != tokens.size() && (IsCodecH264() ?
|
||||
ParseString("-profile", tokens[i], vH264Profile, szH264ProfileNames, &config.profileGUID) : IsCodecHEVC() ?
|
||||
ParseString("-profile", tokens[i], vHevcProfile, szHevcProfileNames, &config.profileGUID) :
|
||||
ParseString("-profile", tokens[i], vAV1Profile, szAV1ProfileNames, &config.profileGUID)) ||
|
||||
tokens[i] == "-rc" && ++i != tokens.size() && ParseString("-rc", tokens[i], vRcMode, szRcModeNames, &config.rcParams.rateControlMode) ||
|
||||
tokens[i] == "-fps" && ++i != tokens.size() && ParseInt("-fps", tokens[i], &pParams->frameRateNum) ||
|
||||
tokens[i] == "-bf" && ++i != tokens.size() && ParseInt("-bf", tokens[i], &config.frameIntervalP) && ++config.frameIntervalP && ++nBFramesOption ||
|
||||
tokens[i] == "-bitrate" && ++i != tokens.size() && ParseBitRate("-bitrate", tokens[i], &config.rcParams.averageBitRate) ||
|
||||
tokens[i] == "-maxbitrate" && ++i != tokens.size() && ParseBitRate("-maxbitrate", tokens[i], &config.rcParams.maxBitRate) ||
|
||||
tokens[i] == "-vbvbufsize" && ++i != tokens.size() && ParseBitRate("-vbvbufsize", tokens[i], &config.rcParams.vbvBufferSize) ||
|
||||
tokens[i] == "-vbvinit" && ++i != tokens.size() && ParseBitRate("-vbvinit", tokens[i], &config.rcParams.vbvInitialDelay) ||
|
||||
tokens[i] == "-cq" && ++i != tokens.size() && ParseInt("-cq", tokens[i], &config.rcParams.targetQuality) ||
|
||||
tokens[i] == "-initqp" && ++i != tokens.size() && ParseQp("-initqp", tokens[i], &config.rcParams.initialRCQP) && (config.rcParams.enableInitialRCQP = true) ||
|
||||
tokens[i] == "-qmin" && ++i != tokens.size() && ParseQp("-qmin", tokens[i], &config.rcParams.minQP) && (config.rcParams.enableMinQP = true) ||
|
||||
tokens[i] == "-qmax" && ++i != tokens.size() && ParseQp("-qmax", tokens[i], &config.rcParams.maxQP) && (config.rcParams.enableMaxQP = true) ||
|
||||
tokens[i] == "-constqp" && ++i != tokens.size() && ParseQp("-constqp", tokens[i], &config.rcParams.constQP) ||
|
||||
tokens[i] == "-temporalaq" && (config.rcParams.enableTemporalAQ = true)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (tokens[i] == "-lookahead" && ++i != tokens.size() && ParseInt("-lookahead", tokens[i], &config.rcParams.lookaheadDepth))
|
||||
{
|
||||
config.rcParams.enableLookahead = config.rcParams.lookaheadDepth > 0;
|
||||
continue;
|
||||
}
|
||||
int aqStrength;
|
||||
if (tokens[i] == "-aq" && ++i != tokens.size() && ParseInt("-aq", tokens[i], &aqStrength)) {
|
||||
config.rcParams.enableAQ = true;
|
||||
config.rcParams.aqStrength = aqStrength;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[i] == "-gop" && ++i != tokens.size() && ParseInt("-gop", tokens[i], &config.gopLength))
|
||||
{
|
||||
nGOPOption = 1;
|
||||
if (IsCodecH264())
|
||||
{
|
||||
config.encodeCodecConfig.h264Config.idrPeriod = config.gopLength;
|
||||
}
|
||||
else if (IsCodecHEVC())
|
||||
{
|
||||
config.encodeCodecConfig.hevcConfig.idrPeriod = config.gopLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
config.encodeCodecConfig.av1Config.idrPeriod = config.gopLength;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[i] == "-444")
|
||||
{
|
||||
if (IsCodecH264())
|
||||
{
|
||||
config.encodeCodecConfig.h264Config.chromaFormatIDC = 3;
|
||||
}
|
||||
else if (IsCodecHEVC())
|
||||
{
|
||||
config.encodeCodecConfig.hevcConfig.chromaFormatIDC = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream errmessage;
|
||||
errmessage << "Incorrect Parameter: YUV444 Input not supported with AV1 Codec" << std::endl;
|
||||
throw std::invalid_argument(errmessage.str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ostringstream errmessage;
|
||||
errmessage << "Incorrect parameter: " << tokens[i] << std::endl;
|
||||
errmessage << "Re-run the application with the -h option to get a list of the supported options.";
|
||||
errmessage << std::endl;
|
||||
|
||||
throw std::invalid_argument(errmessage.str());
|
||||
}
|
||||
|
||||
if (IsCodecHEVC())
|
||||
{
|
||||
if (eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT || eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV444_10BIT)
|
||||
{
|
||||
config.encodeCodecConfig.hevcConfig.inputBitDepth = NV_ENC_BIT_DEPTH_10;
|
||||
config.encodeCodecConfig.hevcConfig.outputBitDepth = NV_ENC_BIT_DEPTH_10;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCodecAV1())
|
||||
{
|
||||
if (eBufferFormat == NV_ENC_BUFFER_FORMAT_YUV420_10BIT)
|
||||
{
|
||||
config.encodeCodecConfig.av1Config.inputBitDepth = NV_ENC_BIT_DEPTH_10;
|
||||
config.encodeCodecConfig.av1Config.outputBitDepth = NV_ENC_BIT_DEPTH_10;
|
||||
}
|
||||
}
|
||||
|
||||
if (nGOPOption && nBFramesOption && (config.gopLength < ((uint32_t)config.frameIntervalP)))
|
||||
{
|
||||
std::ostringstream errmessage;
|
||||
errmessage << "gopLength (" << config.gopLength << ") must be greater or equal to frameIntervalP (number of B frames + 1) (" << config.frameIntervalP << ")\n";
|
||||
throw std::invalid_argument(errmessage.str());
|
||||
}
|
||||
|
||||
funcInit(pParams);
|
||||
LOG(INFO) << NvEncoderInitParam().MainParamToString(pParams);
|
||||
LOG(TRACE) << NvEncoderInitParam().FullParamToString(pParams);
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* Helper methods for parsing tokens (generated by splitting the command line)
|
||||
* and performing conversions to the appropriate target type/value.
|
||||
*/
|
||||
template<typename T>
|
||||
bool ParseString(const std::string &strName, const std::string &strValue, const std::vector<T> &vValue, const std::string &strValueNames, T *pValue) {
|
||||
std::vector<std::string> vstrValueName = split(strValueNames, ' ');
|
||||
auto it = std::find(vstrValueName.begin(), vstrValueName.end(), strValue);
|
||||
if (it == vstrValueName.end()) {
|
||||
LOG(ERROR) << strName << " options: " << strValueNames;
|
||||
return false;
|
||||
}
|
||||
*pValue = vValue[it - vstrValueName.begin()];
|
||||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
std::string ConvertValueToString(const std::vector<T> &vValue, const std::string &strValueNames, T value) {
|
||||
auto it = std::find(vValue.begin(), vValue.end(), value);
|
||||
if (it == vValue.end()) {
|
||||
LOG(ERROR) << "Invalid value. Can't convert to one of " << strValueNames;
|
||||
return std::string();
|
||||
}
|
||||
return split(strValueNames, ' ')[it - vValue.begin()];
|
||||
}
|
||||
bool ParseBitRate(const std::string &strName, const std::string &strValue, unsigned *pBitRate) {
|
||||
if(bTransOneToN)
|
||||
{
|
||||
std::vector<std::string> oneToNBitrate = split(strValue, ',');
|
||||
std::string currBitrate;
|
||||
if ((bitrateCnt + 1) > oneToNBitrate.size())
|
||||
{
|
||||
currBitrate = oneToNBitrate[oneToNBitrate.size() - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
currBitrate = oneToNBitrate[bitrateCnt];
|
||||
bitrateCnt++;
|
||||
}
|
||||
|
||||
try {
|
||||
size_t l;
|
||||
double r = std::stod(currBitrate, &l);
|
||||
char c = currBitrate[l];
|
||||
if (c != 0 && c != 'k' && c != 'm') {
|
||||
LOG(ERROR) << strName << " units: 1, K, M (lower case also allowed)";
|
||||
}
|
||||
*pBitRate = (unsigned)((c == 'm' ? 1000000 : (c == 'k' ? 1000 : 1)) * r);
|
||||
}
|
||||
catch (std::invalid_argument) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
try {
|
||||
size_t l;
|
||||
double r = std::stod(strValue, &l);
|
||||
char c = strValue[l];
|
||||
if (c != 0 && c != 'k' && c != 'm') {
|
||||
LOG(ERROR) << strName << " units: 1, K, M (lower case also allowed)";
|
||||
}
|
||||
*pBitRate = (unsigned)((c == 'm' ? 1000000 : (c == 'k' ? 1000 : 1)) * r);
|
||||
}
|
||||
catch (std::invalid_argument) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
template<typename T>
|
||||
bool ParseInt(const std::string &strName, const std::string &strValue, T *pInt) {
|
||||
if (bTransOneToN)
|
||||
{
|
||||
std::vector<std::string> oneToNFps = split(strValue, ',');
|
||||
std::string currFps;
|
||||
if ((fpsCnt + 1) > oneToNFps.size())
|
||||
{
|
||||
currFps = oneToNFps[oneToNFps.size() - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
currFps = oneToNFps[fpsCnt];
|
||||
fpsCnt++;
|
||||
}
|
||||
|
||||
try {
|
||||
*pInt = std::stoi(currFps);
|
||||
}
|
||||
catch (std::invalid_argument) {
|
||||
LOG(ERROR) << strName << " need a value of positive number";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
try {
|
||||
*pInt = std::stoi(strValue);
|
||||
}
|
||||
catch (std::invalid_argument) {
|
||||
LOG(ERROR) << strName << " need a value of positive number";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool ParseQp(const std::string &strName, const std::string &strValue, NV_ENC_QP *pQp) {
|
||||
std::vector<std::string> vQp = split(strValue, ',');
|
||||
try {
|
||||
if (vQp.size() == 1) {
|
||||
unsigned qp = (unsigned)std::stoi(vQp[0]);
|
||||
*pQp = {qp, qp, qp};
|
||||
} else if (vQp.size() == 3) {
|
||||
*pQp = {(unsigned)std::stoi(vQp[0]), (unsigned)std::stoi(vQp[1]), (unsigned)std::stoi(vQp[2])};
|
||||
} else {
|
||||
LOG(ERROR) << strName << " qp_for_P_B_I or qp_P,qp_B,qp_I (no space is allowed)";
|
||||
return false;
|
||||
}
|
||||
} catch (std::invalid_argument) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
std::vector<std::string> split(const std::string &s, char delim) {
|
||||
std::stringstream ss(s);
|
||||
std::string token;
|
||||
std::vector<std::string> tokens;
|
||||
while (getline(ss, token, delim)) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string strParam;
|
||||
std::function<void(NV_ENC_INITIALIZE_PARAMS *pParams)> funcInit = [](NV_ENC_INITIALIZE_PARAMS *pParams){};
|
||||
std::vector<std::string> tokens;
|
||||
GUID guidCodec = NV_ENC_CODEC_H264_GUID;
|
||||
GUID guidPreset = NV_ENC_PRESET_P3_GUID;
|
||||
NV_ENC_TUNING_INFO m_TuningInfo = NV_ENC_TUNING_INFO_HIGH_QUALITY;
|
||||
bool bLowLatency = false;
|
||||
uint32_t bitrateCnt = 0;
|
||||
uint32_t fpsCnt = 0;
|
||||
bool bTransOneToN = 0;
|
||||
|
||||
const char *szCodecNames = "h264 hevc av1";
|
||||
std::vector<GUID> vCodec = std::vector<GUID> {
|
||||
NV_ENC_CODEC_H264_GUID,
|
||||
NV_ENC_CODEC_HEVC_GUID,
|
||||
NV_ENC_CODEC_AV1_GUID
|
||||
};
|
||||
|
||||
const char *szChromaNames = "yuv420 yuv444";
|
||||
std::vector<uint32_t> vChroma = std::vector<uint32_t>
|
||||
{
|
||||
1, 3
|
||||
};
|
||||
|
||||
const char *szPresetNames = "p1 p2 p3 p4 p5 p6 p7";
|
||||
std::vector<GUID> vPreset = std::vector<GUID> {
|
||||
NV_ENC_PRESET_P1_GUID,
|
||||
NV_ENC_PRESET_P2_GUID,
|
||||
NV_ENC_PRESET_P3_GUID,
|
||||
NV_ENC_PRESET_P4_GUID,
|
||||
NV_ENC_PRESET_P5_GUID,
|
||||
NV_ENC_PRESET_P6_GUID,
|
||||
NV_ENC_PRESET_P7_GUID,
|
||||
};
|
||||
|
||||
const char *szH264ProfileNames = "baseline main high high444";
|
||||
std::vector<GUID> vH264Profile = std::vector<GUID> {
|
||||
NV_ENC_H264_PROFILE_BASELINE_GUID,
|
||||
NV_ENC_H264_PROFILE_MAIN_GUID,
|
||||
NV_ENC_H264_PROFILE_HIGH_GUID,
|
||||
NV_ENC_H264_PROFILE_HIGH_444_GUID,
|
||||
};
|
||||
const char *szHevcProfileNames = "main main10 frext";
|
||||
std::vector<GUID> vHevcProfile = std::vector<GUID> {
|
||||
NV_ENC_HEVC_PROFILE_MAIN_GUID,
|
||||
NV_ENC_HEVC_PROFILE_MAIN10_GUID,
|
||||
NV_ENC_HEVC_PROFILE_FREXT_GUID,
|
||||
};
|
||||
const char *szAV1ProfileNames = "main";
|
||||
std::vector<GUID> vAV1Profile = std::vector<GUID>{
|
||||
NV_ENC_AV1_PROFILE_MAIN_GUID,
|
||||
};
|
||||
|
||||
const char *szProfileNames = "(default) auto baseline(h264) main(h264) high(h264) high444(h264)"
|
||||
" stereo(h264) progressiv_high(h264) constrained_high(h264)"
|
||||
" main(hevc) main10(hevc) frext(hevc)"
|
||||
" main(av1) high(av1)";
|
||||
std::vector<GUID> vProfile = std::vector<GUID> {
|
||||
GUID{},
|
||||
NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID,
|
||||
NV_ENC_H264_PROFILE_BASELINE_GUID,
|
||||
NV_ENC_H264_PROFILE_MAIN_GUID,
|
||||
NV_ENC_H264_PROFILE_HIGH_GUID,
|
||||
NV_ENC_H264_PROFILE_HIGH_444_GUID,
|
||||
NV_ENC_H264_PROFILE_STEREO_GUID,
|
||||
NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID,
|
||||
NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID,
|
||||
NV_ENC_HEVC_PROFILE_MAIN_GUID,
|
||||
NV_ENC_HEVC_PROFILE_MAIN10_GUID,
|
||||
NV_ENC_HEVC_PROFILE_FREXT_GUID,
|
||||
NV_ENC_AV1_PROFILE_MAIN_GUID,
|
||||
};
|
||||
|
||||
const char *szLowLatencyTuningInfoNames = "lowlatency ultralowlatency";
|
||||
const char *szTuningInfoNames = "hq lowlatency ultralowlatency lossless uhq";
|
||||
std::vector<NV_ENC_TUNING_INFO> vTuningInfo = std::vector<NV_ENC_TUNING_INFO>{
|
||||
NV_ENC_TUNING_INFO_HIGH_QUALITY,
|
||||
NV_ENC_TUNING_INFO_LOW_LATENCY,
|
||||
NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY,
|
||||
NV_ENC_TUNING_INFO_LOSSLESS,
|
||||
NV_ENC_TUNING_INFO_ULTRA_HIGH_QUALITY
|
||||
};
|
||||
|
||||
const char *szRcModeNames = "constqp vbr cbr";
|
||||
std::vector<NV_ENC_PARAMS_RC_MODE> vRcMode = std::vector<NV_ENC_PARAMS_RC_MODE> {
|
||||
NV_ENC_PARAMS_RC_CONSTQP,
|
||||
NV_ENC_PARAMS_RC_VBR,
|
||||
NV_ENC_PARAMS_RC_CBR,
|
||||
};
|
||||
|
||||
const char *szMultipass = "disabled qres fullres";
|
||||
std::vector<NV_ENC_MULTI_PASS> vMultiPass = std::vector<NV_ENC_MULTI_PASS>{
|
||||
NV_ENC_MULTI_PASS_DISABLED,
|
||||
NV_ENC_TWO_PASS_QUARTER_RESOLUTION,
|
||||
NV_ENC_TWO_PASS_FULL_RESOLUTION,
|
||||
};
|
||||
|
||||
const char *szQpMapModeNames = "disabled emphasis_level_map delta_qp_map qp_map";
|
||||
std::vector<NV_ENC_QP_MAP_MODE> vQpMapMode = std::vector<NV_ENC_QP_MAP_MODE> {
|
||||
NV_ENC_QP_MAP_DISABLED,
|
||||
NV_ENC_QP_MAP_EMPHASIS,
|
||||
NV_ENC_QP_MAP_DELTA,
|
||||
NV_ENC_QP_MAP,
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
/*
|
||||
* Generates and returns a string describing the values for each field in
|
||||
* the NV_ENC_INITIALIZE_PARAMS structure (i.e. a description of the entire
|
||||
* set of initialization parameters supplied to the API).
|
||||
*/
|
||||
std::string FullParamToString(const NV_ENC_INITIALIZE_PARAMS *pInitializeParams) {
|
||||
std::ostringstream os;
|
||||
os << "NV_ENC_INITIALIZE_PARAMS:" << std::endl
|
||||
<< "encodeGUID: " << ConvertValueToString(vCodec, szCodecNames, pInitializeParams->encodeGUID) << std::endl
|
||||
<< "presetGUID: " << ConvertValueToString(vPreset, szPresetNames, pInitializeParams->presetGUID) << std::endl;
|
||||
if (pInitializeParams->tuningInfo)
|
||||
{
|
||||
os << "tuningInfo: " << ConvertValueToString(vTuningInfo, szTuningInfoNames, pInitializeParams->tuningInfo) << std::endl;
|
||||
}
|
||||
os
|
||||
<< "encodeWidth: " << pInitializeParams->encodeWidth << std::endl
|
||||
<< "encodeHeight: " << pInitializeParams->encodeHeight << std::endl
|
||||
<< "darWidth: " << pInitializeParams->darWidth << std::endl
|
||||
<< "darHeight: " << pInitializeParams->darHeight << std::endl
|
||||
<< "frameRateNum: " << pInitializeParams->frameRateNum << std::endl
|
||||
<< "frameRateDen: " << pInitializeParams->frameRateDen << std::endl
|
||||
<< "enableEncodeAsync: " << pInitializeParams->enableEncodeAsync << std::endl
|
||||
<< "reportSliceOffsets: " << pInitializeParams->reportSliceOffsets << std::endl
|
||||
<< "enableSubFrameWrite: " << pInitializeParams->enableSubFrameWrite << std::endl
|
||||
<< "enableExternalMEHints: " << pInitializeParams->enableExternalMEHints << std::endl
|
||||
<< "enableMEOnlyMode: " << pInitializeParams->enableMEOnlyMode << std::endl
|
||||
<< "enableWeightedPrediction: " << pInitializeParams->enableWeightedPrediction << std::endl
|
||||
<< "maxEncodeWidth: " << pInitializeParams->maxEncodeWidth << std::endl
|
||||
<< "maxEncodeHeight: " << pInitializeParams->maxEncodeHeight << std::endl
|
||||
<< "maxMEHintCountsPerBlock: " << pInitializeParams->maxMEHintCountsPerBlock << std::endl
|
||||
;
|
||||
NV_ENC_CONFIG *pConfig = pInitializeParams->encodeConfig;
|
||||
os << "NV_ENC_CONFIG:" << std::endl
|
||||
<< "profile: " << ConvertValueToString(vProfile, szProfileNames, pConfig->profileGUID) << std::endl
|
||||
<< "gopLength: " << pConfig->gopLength << std::endl
|
||||
<< "frameIntervalP: " << pConfig->frameIntervalP << std::endl
|
||||
<< "monoChromeEncoding: " << pConfig->monoChromeEncoding << std::endl
|
||||
<< "frameFieldMode: " << pConfig->frameFieldMode << std::endl
|
||||
<< "mvPrecision: " << pConfig->mvPrecision << std::endl
|
||||
<< "NV_ENC_RC_PARAMS:" << std::endl
|
||||
<< " rateControlMode: 0x" << std::hex << pConfig->rcParams.rateControlMode << std::dec << std::endl
|
||||
<< " constQP: " << pConfig->rcParams.constQP.qpInterP << ", " << pConfig->rcParams.constQP.qpInterB << ", " << pConfig->rcParams.constQP.qpIntra << std::endl
|
||||
<< " averageBitRate: " << pConfig->rcParams.averageBitRate << std::endl
|
||||
<< " maxBitRate: " << pConfig->rcParams.maxBitRate << std::endl
|
||||
<< " vbvBufferSize: " << pConfig->rcParams.vbvBufferSize << std::endl
|
||||
<< " vbvInitialDelay: " << pConfig->rcParams.vbvInitialDelay << std::endl
|
||||
<< " enableMinQP: " << pConfig->rcParams.enableMinQP << std::endl
|
||||
<< " enableMaxQP: " << pConfig->rcParams.enableMaxQP << std::endl
|
||||
<< " enableInitialRCQP: " << pConfig->rcParams.enableInitialRCQP << std::endl
|
||||
<< " enableAQ: " << pConfig->rcParams.enableAQ << std::endl
|
||||
<< " qpMapMode: " << ConvertValueToString(vQpMapMode, szQpMapModeNames, pConfig->rcParams.qpMapMode) << std::endl
|
||||
<< " multipass: " << ConvertValueToString(vMultiPass, szMultipass, pConfig->rcParams.multiPass) << std::endl
|
||||
<< " enableLookahead: " << pConfig->rcParams.enableLookahead << std::endl
|
||||
<< " disableIadapt: " << pConfig->rcParams.disableIadapt << std::endl
|
||||
<< " disableBadapt: " << pConfig->rcParams.disableBadapt << std::endl
|
||||
<< " enableTemporalAQ: " << pConfig->rcParams.enableTemporalAQ << std::endl
|
||||
<< " zeroReorderDelay: " << pConfig->rcParams.zeroReorderDelay << std::endl
|
||||
<< " enableNonRefP: " << pConfig->rcParams.enableNonRefP << std::endl
|
||||
<< " strictGOPTarget: " << pConfig->rcParams.strictGOPTarget << std::endl
|
||||
<< " aqStrength: " << pConfig->rcParams.aqStrength << std::endl
|
||||
<< " minQP: " << pConfig->rcParams.minQP.qpInterP << ", " << pConfig->rcParams.minQP.qpInterB << ", " << pConfig->rcParams.minQP.qpIntra << std::endl
|
||||
<< " maxQP: " << pConfig->rcParams.maxQP.qpInterP << ", " << pConfig->rcParams.maxQP.qpInterB << ", " << pConfig->rcParams.maxQP.qpIntra << std::endl
|
||||
<< " initialRCQP: " << pConfig->rcParams.initialRCQP.qpInterP << ", " << pConfig->rcParams.initialRCQP.qpInterB << ", " << pConfig->rcParams.initialRCQP.qpIntra << std::endl
|
||||
<< " temporallayerIdxMask: " << pConfig->rcParams.temporallayerIdxMask << std::endl
|
||||
<< " temporalLayerQP: " << (int)pConfig->rcParams.temporalLayerQP[0] << ", " << (int)pConfig->rcParams.temporalLayerQP[1] << ", " << (int)pConfig->rcParams.temporalLayerQP[2] << ", " << (int)pConfig->rcParams.temporalLayerQP[3] << ", " << (int)pConfig->rcParams.temporalLayerQP[4] << ", " << (int)pConfig->rcParams.temporalLayerQP[5] << ", " << (int)pConfig->rcParams.temporalLayerQP[6] << ", " << (int)pConfig->rcParams.temporalLayerQP[7] << std::endl
|
||||
<< " targetQuality: " << pConfig->rcParams.targetQuality << std::endl
|
||||
<< " lookaheadDepth: " << pConfig->rcParams.lookaheadDepth << std::endl;
|
||||
if (pInitializeParams->encodeGUID == NV_ENC_CODEC_H264_GUID) {
|
||||
os
|
||||
<< "NV_ENC_CODEC_CONFIG (H264):" << std::endl
|
||||
<< " enableStereoMVC: " << pConfig->encodeCodecConfig.h264Config.enableStereoMVC << std::endl
|
||||
<< " hierarchicalPFrames: " << pConfig->encodeCodecConfig.h264Config.hierarchicalPFrames << std::endl
|
||||
<< " hierarchicalBFrames: " << pConfig->encodeCodecConfig.h264Config.hierarchicalBFrames << std::endl
|
||||
<< " outputBufferingPeriodSEI: " << pConfig->encodeCodecConfig.h264Config.outputBufferingPeriodSEI << std::endl
|
||||
<< " outputPictureTimingSEI: " << pConfig->encodeCodecConfig.h264Config.outputPictureTimingSEI << std::endl
|
||||
<< " outputAUD: " << pConfig->encodeCodecConfig.h264Config.outputAUD << std::endl
|
||||
<< " disableSPSPPS: " << pConfig->encodeCodecConfig.h264Config.disableSPSPPS << std::endl
|
||||
<< " outputFramePackingSEI: " << pConfig->encodeCodecConfig.h264Config.outputFramePackingSEI << std::endl
|
||||
<< " outputRecoveryPointSEI: " << pConfig->encodeCodecConfig.h264Config.outputRecoveryPointSEI << std::endl
|
||||
<< " enableIntraRefresh: " << pConfig->encodeCodecConfig.h264Config.enableIntraRefresh << std::endl
|
||||
<< " enableConstrainedEncoding: " << pConfig->encodeCodecConfig.h264Config.enableConstrainedEncoding << std::endl
|
||||
<< " repeatSPSPPS: " << pConfig->encodeCodecConfig.h264Config.repeatSPSPPS << std::endl
|
||||
<< " enableVFR: " << pConfig->encodeCodecConfig.h264Config.enableVFR << std::endl
|
||||
<< " enableLTR: " << pConfig->encodeCodecConfig.h264Config.enableLTR << std::endl
|
||||
<< " qpPrimeYZeroTransformBypassFlag: " << pConfig->encodeCodecConfig.h264Config.qpPrimeYZeroTransformBypassFlag << std::endl
|
||||
<< " useConstrainedIntraPred: " << pConfig->encodeCodecConfig.h264Config.useConstrainedIntraPred << std::endl
|
||||
<< " level: " << pConfig->encodeCodecConfig.h264Config.level << std::endl
|
||||
<< " idrPeriod: " << pConfig->encodeCodecConfig.h264Config.idrPeriod << std::endl
|
||||
<< " separateColourPlaneFlag: " << pConfig->encodeCodecConfig.h264Config.separateColourPlaneFlag << std::endl
|
||||
<< " disableDeblockingFilterIDC: " << pConfig->encodeCodecConfig.h264Config.disableDeblockingFilterIDC << std::endl
|
||||
<< " numTemporalLayers: " << pConfig->encodeCodecConfig.h264Config.numTemporalLayers << std::endl
|
||||
<< " spsId: " << pConfig->encodeCodecConfig.h264Config.spsId << std::endl
|
||||
<< " ppsId: " << pConfig->encodeCodecConfig.h264Config.ppsId << std::endl
|
||||
<< " adaptiveTransformMode: " << pConfig->encodeCodecConfig.h264Config.adaptiveTransformMode << std::endl
|
||||
<< " fmoMode: " << pConfig->encodeCodecConfig.h264Config.fmoMode << std::endl
|
||||
<< " bdirectMode: " << pConfig->encodeCodecConfig.h264Config.bdirectMode << std::endl
|
||||
<< " entropyCodingMode: " << pConfig->encodeCodecConfig.h264Config.entropyCodingMode << std::endl
|
||||
<< " stereoMode: " << pConfig->encodeCodecConfig.h264Config.stereoMode << std::endl
|
||||
<< " intraRefreshPeriod: " << pConfig->encodeCodecConfig.h264Config.intraRefreshPeriod << std::endl
|
||||
<< " intraRefreshCnt: " << pConfig->encodeCodecConfig.h264Config.intraRefreshCnt << std::endl
|
||||
<< " maxNumRefFrames: " << pConfig->encodeCodecConfig.h264Config.maxNumRefFrames << std::endl
|
||||
<< " sliceMode: " << pConfig->encodeCodecConfig.h264Config.sliceMode << std::endl
|
||||
<< " sliceModeData: " << pConfig->encodeCodecConfig.h264Config.sliceModeData << std::endl
|
||||
<< " NV_ENC_CONFIG_H264_VUI_PARAMETERS:" << std::endl
|
||||
<< " overscanInfoPresentFlag: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.overscanInfoPresentFlag << std::endl
|
||||
<< " overscanInfo: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.overscanInfo << std::endl
|
||||
<< " videoSignalTypePresentFlag: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.videoSignalTypePresentFlag << std::endl
|
||||
<< " videoFormat: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.videoFormat << std::endl
|
||||
<< " videoFullRangeFlag: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.videoFullRangeFlag << std::endl
|
||||
<< " colourDescriptionPresentFlag: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.colourDescriptionPresentFlag << std::endl
|
||||
<< " colourPrimaries: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.colourPrimaries << std::endl
|
||||
<< " transferCharacteristics: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.transferCharacteristics << std::endl
|
||||
<< " colourMatrix: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.colourMatrix << std::endl
|
||||
<< " chromaSampleLocationFlag: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.chromaSampleLocationFlag << std::endl
|
||||
<< " chromaSampleLocationTop: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.chromaSampleLocationTop << std::endl
|
||||
<< " chromaSampleLocationBot: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.chromaSampleLocationBot << std::endl
|
||||
<< " bitstreamRestrictionFlag: " << pConfig->encodeCodecConfig.h264Config.h264VUIParameters.bitstreamRestrictionFlag << std::endl
|
||||
<< " ltrNumFrames: " << pConfig->encodeCodecConfig.h264Config.ltrNumFrames << std::endl
|
||||
<< " ltrTrustMode: " << pConfig->encodeCodecConfig.h264Config.ltrTrustMode << std::endl
|
||||
<< " chromaFormatIDC: " << pConfig->encodeCodecConfig.h264Config.chromaFormatIDC << std::endl
|
||||
<< " maxTemporalLayers: " << pConfig->encodeCodecConfig.h264Config.maxTemporalLayers << std::endl;
|
||||
} else if (pInitializeParams->encodeGUID == NV_ENC_CODEC_HEVC_GUID) {
|
||||
os
|
||||
<< "NV_ENC_CODEC_CONFIG (HEVC):" << std::endl
|
||||
<< " level: " << pConfig->encodeCodecConfig.hevcConfig.level << std::endl
|
||||
<< " tier: " << pConfig->encodeCodecConfig.hevcConfig.tier << std::endl
|
||||
<< " minCUSize: " << pConfig->encodeCodecConfig.hevcConfig.minCUSize << std::endl
|
||||
<< " maxCUSize: " << pConfig->encodeCodecConfig.hevcConfig.maxCUSize << std::endl
|
||||
<< " useConstrainedIntraPred: " << pConfig->encodeCodecConfig.hevcConfig.useConstrainedIntraPred << std::endl
|
||||
<< " disableDeblockAcrossSliceBoundary: " << pConfig->encodeCodecConfig.hevcConfig.disableDeblockAcrossSliceBoundary << std::endl
|
||||
<< " outputBufferingPeriodSEI: " << pConfig->encodeCodecConfig.hevcConfig.outputBufferingPeriodSEI << std::endl
|
||||
<< " outputPictureTimingSEI: " << pConfig->encodeCodecConfig.hevcConfig.outputPictureTimingSEI << std::endl
|
||||
<< " outputAUD: " << pConfig->encodeCodecConfig.hevcConfig.outputAUD << std::endl
|
||||
<< " enableLTR: " << pConfig->encodeCodecConfig.hevcConfig.enableLTR << std::endl
|
||||
<< " disableSPSPPS: " << pConfig->encodeCodecConfig.hevcConfig.disableSPSPPS << std::endl
|
||||
<< " repeatSPSPPS: " << pConfig->encodeCodecConfig.hevcConfig.repeatSPSPPS << std::endl
|
||||
<< " enableIntraRefresh: " << pConfig->encodeCodecConfig.hevcConfig.enableIntraRefresh << std::endl
|
||||
<< " chromaFormatIDC: " << pConfig->encodeCodecConfig.hevcConfig.chromaFormatIDC << std::endl
|
||||
<< " inputBitDepth: " << pConfig->encodeCodecConfig.hevcConfig.inputBitDepth << std::endl
|
||||
<< " outputBitDepth: " << pConfig->encodeCodecConfig.hevcConfig.outputBitDepth << std::endl
|
||||
<< " idrPeriod: " << pConfig->encodeCodecConfig.hevcConfig.idrPeriod << std::endl
|
||||
<< " intraRefreshPeriod: " << pConfig->encodeCodecConfig.hevcConfig.intraRefreshPeriod << std::endl
|
||||
<< " intraRefreshCnt: " << pConfig->encodeCodecConfig.hevcConfig.intraRefreshCnt << std::endl
|
||||
<< " maxNumRefFramesInDPB: " << pConfig->encodeCodecConfig.hevcConfig.maxNumRefFramesInDPB << std::endl
|
||||
<< " ltrNumFrames: " << pConfig->encodeCodecConfig.hevcConfig.ltrNumFrames << std::endl
|
||||
<< " vpsId: " << pConfig->encodeCodecConfig.hevcConfig.vpsId << std::endl
|
||||
<< " spsId: " << pConfig->encodeCodecConfig.hevcConfig.spsId << std::endl
|
||||
<< " ppsId: " << pConfig->encodeCodecConfig.hevcConfig.ppsId << std::endl
|
||||
<< " sliceMode: " << pConfig->encodeCodecConfig.hevcConfig.sliceMode << std::endl
|
||||
<< " sliceModeData: " << pConfig->encodeCodecConfig.hevcConfig.sliceModeData << std::endl
|
||||
<< " maxTemporalLayersMinus1: " << pConfig->encodeCodecConfig.hevcConfig.maxTemporalLayersMinus1 << std::endl
|
||||
<< " NV_ENC_CONFIG_HEVC_VUI_PARAMETERS:" << std::endl
|
||||
<< " overscanInfoPresentFlag: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.overscanInfoPresentFlag << std::endl
|
||||
<< " overscanInfo: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.overscanInfo << std::endl
|
||||
<< " videoSignalTypePresentFlag: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.videoSignalTypePresentFlag << std::endl
|
||||
<< " videoFormat: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.videoFormat << std::endl
|
||||
<< " videoFullRangeFlag: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.videoFullRangeFlag << std::endl
|
||||
<< " colourDescriptionPresentFlag: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.colourDescriptionPresentFlag << std::endl
|
||||
<< " colourPrimaries: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.colourPrimaries << std::endl
|
||||
<< " transferCharacteristics: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.transferCharacteristics << std::endl
|
||||
<< " colourMatrix: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.colourMatrix << std::endl
|
||||
<< " chromaSampleLocationFlag: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.chromaSampleLocationFlag << std::endl
|
||||
<< " chromaSampleLocationTop: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.chromaSampleLocationTop << std::endl
|
||||
<< " chromaSampleLocationBot: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.chromaSampleLocationBot << std::endl
|
||||
<< " bitstreamRestrictionFlag: " << pConfig->encodeCodecConfig.hevcConfig.hevcVUIParameters.bitstreamRestrictionFlag << std::endl
|
||||
<< " ltrTrustMode: " << pConfig->encodeCodecConfig.hevcConfig.ltrTrustMode << std::endl;
|
||||
} else if (pInitializeParams->encodeGUID == NV_ENC_CODEC_AV1_GUID) {
|
||||
os
|
||||
<< "NV_ENC_CODEC_CONFIG (AV1):" << std::endl
|
||||
<< " level: " << pConfig->encodeCodecConfig.av1Config.level << std::endl
|
||||
<< " tier: " << pConfig->encodeCodecConfig.av1Config.tier << std::endl
|
||||
<< " minPartSize: " << pConfig->encodeCodecConfig.av1Config.minPartSize << std::endl
|
||||
<< " maxPartSize: " << pConfig->encodeCodecConfig.av1Config.maxPartSize << std::endl
|
||||
<< " outputAnnexBFormat: " << pConfig->encodeCodecConfig.av1Config.outputAnnexBFormat << std::endl
|
||||
<< " enableTimingInfo: " << pConfig->encodeCodecConfig.av1Config.enableTimingInfo << std::endl
|
||||
<< " enableDecoderModelInfo: " << pConfig->encodeCodecConfig.av1Config.enableDecoderModelInfo << std::endl
|
||||
<< " enableFrameIdNumbers: " << pConfig->encodeCodecConfig.av1Config.enableFrameIdNumbers << std::endl
|
||||
<< " disableSeqHdr: " << pConfig->encodeCodecConfig.av1Config.disableSeqHdr << std::endl
|
||||
<< " repeatSeqHdr: " << pConfig->encodeCodecConfig.av1Config.repeatSeqHdr << std::endl
|
||||
<< " enableIntraRefresh: " << pConfig->encodeCodecConfig.av1Config.enableIntraRefresh << std::endl
|
||||
<< " chromaFormatIDC: " << pConfig->encodeCodecConfig.av1Config.chromaFormatIDC << std::endl
|
||||
<< " enableBitstreamPadding: " << pConfig->encodeCodecConfig.av1Config.enableBitstreamPadding << std::endl
|
||||
<< " enableCustomTileConfig: " << pConfig->encodeCodecConfig.av1Config.enableCustomTileConfig << std::endl
|
||||
<< " enableFilmGrainParams: " << pConfig->encodeCodecConfig.av1Config.enableFilmGrainParams << std::endl
|
||||
<< " inputBitDepth: " << pConfig->encodeCodecConfig.av1Config.inputBitDepth << std::endl
|
||||
<< " outputBitDepth: " << pConfig->encodeCodecConfig.av1Config.outputBitDepth << std::endl
|
||||
<< " idrPeriod: " << pConfig->encodeCodecConfig.av1Config.idrPeriod << std::endl
|
||||
<< " intraRefreshPeriod: " << pConfig->encodeCodecConfig.av1Config.intraRefreshPeriod << std::endl
|
||||
<< " intraRefreshCnt: " << pConfig->encodeCodecConfig.av1Config.intraRefreshCnt << std::endl
|
||||
<< " maxNumRefFramesInDPB: " << pConfig->encodeCodecConfig.av1Config.maxNumRefFramesInDPB << std::endl
|
||||
<< " numTileColumns: " << pConfig->encodeCodecConfig.av1Config.numTileColumns << std::endl
|
||||
<< " numTileRows: " << pConfig->encodeCodecConfig.av1Config.numTileRows << std::endl
|
||||
<< " maxTemporalLayersMinus1: " << pConfig->encodeCodecConfig.av1Config.maxTemporalLayersMinus1 << std::endl
|
||||
<< " colorPrimaries: " << pConfig->encodeCodecConfig.av1Config.colorPrimaries << std::endl
|
||||
<< " transferCharacteristics: " << pConfig->encodeCodecConfig.av1Config.transferCharacteristics << std::endl
|
||||
<< " matrixCoefficients: " << pConfig->encodeCodecConfig.av1Config.matrixCoefficients << std::endl
|
||||
<< " colorRange: " << pConfig->encodeCodecConfig.av1Config.colorRange << std::endl
|
||||
<< " chromaSamplePosition: " << pConfig->encodeCodecConfig.av1Config.chromaSamplePosition << std::endl
|
||||
<< " useBFramesAsRef: " << pConfig->encodeCodecConfig.av1Config.useBFramesAsRef << std::endl
|
||||
<< " numFwdRefs: " << pConfig->encodeCodecConfig.av1Config.numFwdRefs << std::endl
|
||||
<< " numBwdRefs: " << pConfig->encodeCodecConfig.av1Config.numBwdRefs << std::endl;
|
||||
if (pConfig->encodeCodecConfig.av1Config.filmGrainParams != NULL)
|
||||
{
|
||||
os
|
||||
<< " NV_ENC_FILM_GRAIN_PARAMS_AV1:" << std::endl
|
||||
<< " applyGrain: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->applyGrain << std::endl
|
||||
<< " chromaScalingFromLuma: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->chromaScalingFromLuma << std::endl
|
||||
<< " overlapFlag: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->overlapFlag << std::endl
|
||||
<< " clipToRestrictedRange: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->clipToRestrictedRange << std::endl
|
||||
<< " grainScalingMinus8: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->grainScalingMinus8 << std::endl
|
||||
<< " arCoeffLag: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->arCoeffLag << std::endl
|
||||
<< " numYPoints: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->numYPoints << std::endl
|
||||
<< " numCbPoints: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->numCbPoints << std::endl
|
||||
<< " numCrPoints: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->numCrPoints << std::endl
|
||||
<< " arCoeffShiftMinus6: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->arCoeffShiftMinus6 << std::endl
|
||||
<< " grainScaleShift: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->grainScaleShift << std::endl
|
||||
<< " cbMult: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->cbMult << std::endl
|
||||
<< " cbLumaMult: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->cbLumaMult << std::endl
|
||||
<< " cbOffset: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->cbOffset << std::endl
|
||||
<< " crMult: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->crMult << std::endl
|
||||
<< " crLumaMult: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->crLumaMult << std::endl
|
||||
<< " crOffset: " << pConfig->encodeCodecConfig.av1Config.filmGrainParams->crOffset << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return os.str();
|
||||
}
|
||||
};
|
||||
@@ -1,27 +1,41 @@
|
||||
/*
|
||||
* Copyright 2017-2020 NVIDIA Corporation. All rights reserved.
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "NvEncoderCuda.h"
|
||||
|
||||
#include "nvcodec_api.h"
|
||||
|
||||
NvEncoderCuda::NvEncoderCuda(CUcontext cuContext, uint32_t nWidth,
|
||||
uint32_t nHeight,
|
||||
NV_ENC_BUFFER_FORMAT eBufferFormat,
|
||||
uint32_t nExtraOutputDelay,
|
||||
bool bMotionEstimationOnly,
|
||||
bool bOutputInVideoMemory)
|
||||
bool bOutputInVideoMemory, bool bUseIVFContainer)
|
||||
: NvEncoder(NV_ENC_DEVICE_TYPE_CUDA, cuContext, nWidth, nHeight,
|
||||
eBufferFormat, nExtraOutputDelay, bMotionEstimationOnly,
|
||||
bOutputInVideoMemory),
|
||||
bOutputInVideoMemory, false, bUseIVFContainer),
|
||||
m_cuContext(cuContext) {
|
||||
if (!m_hEncoder) {
|
||||
NVENC_THROW_ERROR("Encoder Initialization failed",
|
||||
@@ -46,7 +60,7 @@ void NvEncoderCuda::AllocateInputBuffers(int32_t numInputBuffers) {
|
||||
int numCount = m_bMotionEstimationOnly ? 2 : 1;
|
||||
|
||||
for (int count = 0; count < numCount; count++) {
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(m_cuContext));
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(m_cuContext));
|
||||
std::vector<void *> inputFrames;
|
||||
for (int i = 0; i < numInputBuffers; i++) {
|
||||
CUdeviceptr pDeviceFrame;
|
||||
@@ -56,13 +70,13 @@ void NvEncoderCuda::AllocateInputBuffers(int32_t numInputBuffers) {
|
||||
if (GetPixelFormat() == NV_ENC_BUFFER_FORMAT_YV12 ||
|
||||
GetPixelFormat() == NV_ENC_BUFFER_FORMAT_IYUV)
|
||||
chromaHeight = GetChromaHeight(GetPixelFormat(), GetMaxEncodeHeight());
|
||||
CUDA_DRVAPI_CALL(cuMemAllocPitch_ld(
|
||||
CUDA_DRVAPI_CALL(cuMemAllocPitch(
|
||||
(CUdeviceptr *)&pDeviceFrame, &m_cudaPitch,
|
||||
GetWidthInBytes(GetPixelFormat(), GetMaxEncodeWidth()),
|
||||
GetMaxEncodeHeight() + chromaHeight, 16));
|
||||
inputFrames.push_back((void *)pDeviceFrame);
|
||||
}
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
|
||||
RegisterInputResources(
|
||||
inputFrames, NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR,
|
||||
@@ -90,24 +104,23 @@ void NvEncoderCuda::ReleaseCudaResources() {
|
||||
|
||||
UnregisterInputResources();
|
||||
|
||||
cuCtxPushCurrent_ld(m_cuContext);
|
||||
cuCtxPushCurrent(m_cuContext);
|
||||
|
||||
for (uint32_t i = 0; i < m_vInputFrames.size(); ++i) {
|
||||
if (m_vInputFrames[i].inputPtr) {
|
||||
cuMemFree_ld(reinterpret_cast<CUdeviceptr>(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_ld(
|
||||
reinterpret_cast<CUdeviceptr>(m_vReferenceFrames[i].inputPtr));
|
||||
cuMemFree(reinterpret_cast<CUdeviceptr>(m_vReferenceFrames[i].inputPtr));
|
||||
}
|
||||
}
|
||||
m_vReferenceFrames.clear();
|
||||
|
||||
cuCtxPopCurrent_ld(NULL);
|
||||
cuCtxPopCurrent(NULL);
|
||||
m_cuContext = nullptr;
|
||||
}
|
||||
|
||||
@@ -123,7 +136,7 @@ void NvEncoderCuda::CopyToDeviceFrame(
|
||||
NV_ENC_ERR_INVALID_PARAM);
|
||||
}
|
||||
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(device));
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(device));
|
||||
|
||||
uint32_t srcPitch =
|
||||
nSrcPitch ? nSrcPitch : NvEncoder::GetWidthInBytes(pixelFormat, width);
|
||||
@@ -141,10 +154,10 @@ void NvEncoderCuda::CopyToDeviceFrame(
|
||||
m.WidthInBytes = NvEncoder::GetWidthInBytes(pixelFormat, width);
|
||||
m.Height = height;
|
||||
if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) {
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned_ld(&m));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned(&m));
|
||||
} else {
|
||||
CUDA_DRVAPI_CALL(stream == NULL ? cuMemcpy2D_ld(&m)
|
||||
: cuMemcpy2DAsync_ld(&m, stream));
|
||||
CUDA_DRVAPI_CALL(stream == NULL ? cuMemcpy2D(&m)
|
||||
: cuMemcpy2DAsync(&m, stream));
|
||||
}
|
||||
|
||||
std::vector<uint32_t> srcChromaOffsets;
|
||||
@@ -170,14 +183,14 @@ void NvEncoderCuda::CopyToDeviceFrame(
|
||||
m.WidthInBytes = chromaWidthInBytes;
|
||||
m.Height = chromaHeight;
|
||||
if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) {
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned_ld(&m));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned(&m));
|
||||
} else {
|
||||
CUDA_DRVAPI_CALL(stream == NULL ? cuMemcpy2D_ld(&m)
|
||||
: cuMemcpy2DAsync_ld(&m, stream));
|
||||
CUDA_DRVAPI_CALL(stream == NULL ? cuMemcpy2D(&m)
|
||||
: cuMemcpy2DAsync(&m, stream));
|
||||
}
|
||||
}
|
||||
}
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
}
|
||||
|
||||
void NvEncoderCuda::CopyToDeviceFrame(
|
||||
@@ -192,7 +205,7 @@ void NvEncoderCuda::CopyToDeviceFrame(
|
||||
NV_ENC_ERR_INVALID_PARAM);
|
||||
}
|
||||
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent_ld(device));
|
||||
CUDA_DRVAPI_CALL(cuCtxPushCurrent(device));
|
||||
|
||||
uint32_t srcPitch =
|
||||
nSrcPitch ? nSrcPitch : NvEncoder::GetWidthInBytes(pixelFormat, width);
|
||||
@@ -210,9 +223,9 @@ void NvEncoderCuda::CopyToDeviceFrame(
|
||||
m.WidthInBytes = NvEncoder::GetWidthInBytes(pixelFormat, width);
|
||||
m.Height = height;
|
||||
if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) {
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned_ld(&m));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned(&m));
|
||||
} else {
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2D_ld(&m));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2D(&m));
|
||||
}
|
||||
|
||||
std::vector<uint32_t> srcChromaOffsets;
|
||||
@@ -237,11 +250,11 @@ void NvEncoderCuda::CopyToDeviceFrame(
|
||||
m.WidthInBytes = chromaWidthInBytes;
|
||||
m.Height = chromaHeight;
|
||||
if (bUnAlignedDeviceCopy && srcMemoryType == CU_MEMORYTYPE_DEVICE) {
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned_ld(&m));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2DUnaligned(&m));
|
||||
} else {
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2D_ld(&m));
|
||||
CUDA_DRVAPI_CALL(cuMemcpy2D(&m));
|
||||
}
|
||||
}
|
||||
}
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent_ld(NULL));
|
||||
CUDA_DRVAPI_CALL(cuCtxPopCurrent(NULL));
|
||||
}
|
||||
127
src/media/nvcodec/NvEncoderCuda.h
Normal file
127
src/media/nvcodec/NvEncoderCuda.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This copyright notice applies to this header file only:
|
||||
*
|
||||
* Copyright (c) 2010-2024 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the software, and to permit persons to whom the
|
||||
* software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <mutex>
|
||||
#include <cuda.h>
|
||||
#include "NvEncoder.h"
|
||||
|
||||
#define CUDA_DRVAPI_CALL( call ) \
|
||||
do \
|
||||
{ \
|
||||
CUresult err__ = call; \
|
||||
if (err__ != CUDA_SUCCESS) \
|
||||
{ \
|
||||
const char *szErrName = NULL; \
|
||||
cuGetErrorName(err__, &szErrName); \
|
||||
std::ostringstream errorLog; \
|
||||
errorLog << "CUDA driver API error " << szErrName ; \
|
||||
throw NVENCException::makeNVENCException(errorLog.str(), NV_ENC_ERR_GENERIC, __FUNCTION__, __FILE__, __LINE__); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/**
|
||||
* @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, bool bMotionEstimationOnly = false, bool bOPInVideoMemory = false, bool bUseIVFContainer = true);
|
||||
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 is a static function to copy input data from host memory to device memory.
|
||||
* Application must pass a seperate device pointer for each YUV plane.
|
||||
*/
|
||||
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,
|
||||
CUdeviceptr dstChromaPtr[],
|
||||
uint32_t dstChromaPitch,
|
||||
uint32_t numChromaPlanes,
|
||||
bool bUnAlignedDeviceCopy = false);
|
||||
|
||||
/**
|
||||
* @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;
|
||||
};
|
||||
110
src/media/nvcodec/nvcodec_common.cpp
Normal file
110
src/media/nvcodec/nvcodec_common.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "nvcodec_common.h"
|
||||
|
||||
void ShowHelpAndExit(const char *szBadOption) {
|
||||
std::ostringstream oss;
|
||||
bool bThrowError = false;
|
||||
if (szBadOption) {
|
||||
oss << "Error parsing \"" << szBadOption << "\"" << std::endl;
|
||||
bThrowError = true;
|
||||
}
|
||||
oss << "Options:" << std::endl
|
||||
<< "-i Input file path" << std::endl
|
||||
<< "-o Output file path" << std::endl
|
||||
<< "-s Input resolution in this form: WxH" << std::endl
|
||||
<< "-if Input format: iyuv nv12" << std::endl
|
||||
<< "-gpu Ordinal of GPU to use" << std::endl
|
||||
<< "-case 0: Encode frames with dynamic bitrate change"
|
||||
<< std::endl
|
||||
<< " 1: Encode frames with dynamic resolution change"
|
||||
<< std::endl;
|
||||
oss << NvEncoderInitParam("", nullptr, true).GetHelpMessage() << std::endl;
|
||||
if (bThrowError) {
|
||||
throw std::invalid_argument(oss.str());
|
||||
} else {
|
||||
std::cout << oss.str();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseCommandLine(int argc, char *argv[], char *szInputFileName,
|
||||
int &nWidth, int &nHeight, NV_ENC_BUFFER_FORMAT &eFormat,
|
||||
char *szOutputFileName, NvEncoderInitParam &initParam,
|
||||
int &iGpu, int &iCase, int &nFrame) {
|
||||
std::ostringstream oss;
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!_stricmp(argv[i], "-h")) {
|
||||
ShowHelpAndExit();
|
||||
}
|
||||
if (!_stricmp(argv[i], "-i")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-i");
|
||||
}
|
||||
sprintf(szInputFileName, "%s", argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!_stricmp(argv[i], "-o")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-o");
|
||||
}
|
||||
sprintf(szOutputFileName, "%s", argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!_stricmp(argv[i], "-s")) {
|
||||
if (++i == argc || 2 != sscanf(argv[i], "%dx%d", &nWidth, &nHeight)) {
|
||||
ShowHelpAndExit("-s");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::string> vszFileFormatName = {"iyuv", "nv12"};
|
||||
|
||||
NV_ENC_BUFFER_FORMAT aFormat[] = {
|
||||
NV_ENC_BUFFER_FORMAT_IYUV,
|
||||
NV_ENC_BUFFER_FORMAT_NV12,
|
||||
};
|
||||
|
||||
if (!_stricmp(argv[i], "-if")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-if");
|
||||
}
|
||||
auto it = std::find(vszFileFormatName.begin(), vszFileFormatName.end(),
|
||||
argv[i]);
|
||||
if (it == vszFileFormatName.end()) {
|
||||
ShowHelpAndExit("-if");
|
||||
}
|
||||
eFormat = aFormat[it - vszFileFormatName.begin()];
|
||||
continue;
|
||||
}
|
||||
if (!_stricmp(argv[i], "-gpu")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-gpu");
|
||||
}
|
||||
iGpu = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!_stricmp(argv[i], "-case")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-case");
|
||||
}
|
||||
iCase = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!_stricmp(argv[i], "-frame")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-frame");
|
||||
}
|
||||
nFrame = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
// Regard as encoder parameter
|
||||
if (argv[i][0] != '-') {
|
||||
ShowHelpAndExit(argv[i]);
|
||||
}
|
||||
oss << argv[i] << " ";
|
||||
while (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
oss << argv[++i] << " ";
|
||||
}
|
||||
}
|
||||
initParam = NvEncoderInitParam(oss.str().c_str(), nullptr, true);
|
||||
}
|
||||
26
src/media/nvcodec/nvcodec_common.h
Normal file
26
src/media/nvcodec/nvcodec_common.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2024-09-10
|
||||
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _NVCODEC_COMMON_H_
|
||||
#define _NVCODEC_COMMON_H_
|
||||
|
||||
#include <cuda.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "NvCodecUtils.h"
|
||||
#include "NvEncoderCLIOptions.h"
|
||||
#include "NvEncoderCuda.h"
|
||||
|
||||
void ShowHelpAndExit(const char *szBadOption = NULL);
|
||||
|
||||
void ParseCommandLine(int argc, char *argv[], char *szInputFileName,
|
||||
int &nWidth, int &nHeight, NV_ENC_BUFFER_FORMAT &eFormat,
|
||||
char *szOutputFileName, NvEncoderInitParam &initParam,
|
||||
int &iGpu, int &iCase, int &nFrame);
|
||||
|
||||
#endif
|
||||
@@ -362,7 +362,10 @@ int AomAv1Encoder::OnEncodedImage(char *encoded_packets, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AomAv1Encoder::ForceIdr() { force_i_frame_flags_ = AOM_EFLAG_FORCE_KF; }
|
||||
int AomAv1Encoder::ForceIdr() {
|
||||
force_i_frame_flags_ = AOM_EFLAG_FORCE_KF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AomAv1Encoder::Release() {
|
||||
if (frame_for_encode_ != nullptr) {
|
||||
|
||||
@@ -50,7 +50,7 @@ class AomAv1Encoder : public VideoEncoder {
|
||||
|
||||
int OnEncodedImage(char* encoded_packets, size_t size);
|
||||
|
||||
void ForceIdr();
|
||||
int ForceIdr();
|
||||
|
||||
private:
|
||||
template <typename P>
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cuda.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "NvEncoder.h"
|
||||
|
||||
#define CUDA_DRVAPI_CALL(call) \
|
||||
do { \
|
||||
CUresult err__ = call; \
|
||||
if (err__ != CUDA_SUCCESS) { \
|
||||
const char* szErrName = NULL; \
|
||||
cuGetErrorName_ld(err__, &szErrName); \
|
||||
std::ostringstream errorLog; \
|
||||
errorLog << "CUDA driver API error " << szErrName; \
|
||||
throw NVENCException::makeNVENCException( \
|
||||
errorLog.str(), NV_ENC_ERR_GENERIC, __FUNCTION__, __FILE__, \
|
||||
__LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @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,
|
||||
bool bMotionEstimationOnly = false,
|
||||
bool bOPInVideoMemory = false);
|
||||
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 is a static function to copy input data from host memory to
|
||||
* device memory. Application must pass a seperate device pointer for each YUV
|
||||
* plane.
|
||||
*/
|
||||
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,
|
||||
CUdeviceptr dstChromaPtr[], uint32_t dstChromaPitch,
|
||||
uint32_t numChromaPlanes, bool bUnAlignedDeviceCopy = false);
|
||||
|
||||
/**
|
||||
* @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;
|
||||
};
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "nvcodec_api.h"
|
||||
#include "nvcodec_common.h"
|
||||
|
||||
#define SAVE_RECEIVED_NV12_STREAM 0
|
||||
#define SAVE_ENCODED_H264_STREAM 0
|
||||
@@ -26,53 +27,82 @@ NvidiaVideoEncoder::~NvidiaVideoEncoder() {
|
||||
free(nv12_data_);
|
||||
nv12_data_ = nullptr;
|
||||
}
|
||||
|
||||
if (encoder_) {
|
||||
encoder_->DestroyEncoder();
|
||||
}
|
||||
}
|
||||
|
||||
int NvidiaVideoEncoder::Init() {
|
||||
// Init cuda context
|
||||
int num_of_GPUs = 0;
|
||||
CUdevice cuda_device;
|
||||
bool cuda_ctx_succeed =
|
||||
(index_of_GPU >= 0 && cuInit_ld(0) == CUresult::CUDA_SUCCESS &&
|
||||
cuDeviceGetCount_ld(&num_of_GPUs) == CUresult::CUDA_SUCCESS &&
|
||||
(num_of_GPUs > 0 && index_of_GPU < num_of_GPUs) &&
|
||||
cuDeviceGet_ld(&cuda_device, index_of_GPU) == CUresult::CUDA_SUCCESS &&
|
||||
cuCtxCreate_ld(&cuda_context_, 0, cuda_device) ==
|
||||
CUresult::CUDA_SUCCESS);
|
||||
if (!cuda_ctx_succeed) {
|
||||
ck(cuInit(0));
|
||||
int num_of_gpu = 0;
|
||||
ck(cuDeviceGetCount(&num_of_gpu));
|
||||
if (index_of_gpu_ < 0 || index_of_gpu_ >= num_of_gpu) {
|
||||
LOG_ERROR("GPU ordinal out of range. Should be within [0-{}]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ck(cuDeviceGet(&cuda_device_, index_of_gpu_));
|
||||
char device_name[80];
|
||||
ck(cuDeviceGetName(device_name, sizeof(device_name), cuda_device_));
|
||||
LOG_INFO("H.264 encoder using [{}]", device_name);
|
||||
ck(cuCtxCreate(&cuda_context_, 0, cuda_device_));
|
||||
|
||||
encoder_ = new NvEncoderCuda(cuda_context_, frame_width_, frame_height_,
|
||||
NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_NV12);
|
||||
buffer_format_, 0);
|
||||
|
||||
// Init encoder_ session
|
||||
NV_ENC_INITIALIZE_PARAMS init_params;
|
||||
init_params.version = NV_ENC_INITIALIZE_PARAMS_VER;
|
||||
NV_ENC_CONFIG encode_config = {NV_ENC_CONFIG_VER};
|
||||
init_params.encodeConfig = &encode_config;
|
||||
NV_ENC_INITIALIZE_PARAMS init_params = {NV_ENC_INITIALIZE_PARAMS_VER};
|
||||
NV_ENC_CONFIG encodeConfig = {NV_ENC_CONFIG_VER};
|
||||
init_params.encodeConfig = &encodeConfig;
|
||||
encoder_->CreateDefaultEncoderParams(&init_params, codec_guid_, preset_guid_,
|
||||
tuning_info_);
|
||||
|
||||
encoder_->CreateDefaultEncoderParams(&init_params, codec_guid, preset_guid,
|
||||
tuning_info);
|
||||
frame_width_max_ = encoder_->GetCapabilityValue(NV_ENC_CODEC_H264_GUID,
|
||||
NV_ENC_CAPS_WIDTH_MAX);
|
||||
frame_height_max_ = encoder_->GetCapabilityValue(NV_ENC_CODEC_H264_GUID,
|
||||
NV_ENC_CAPS_HEIGHT_MAX);
|
||||
// frame_width_min_ = encoder_->GetCapabilityValue(NV_ENC_CODEC_H264_GUID,
|
||||
// NV_ENC_CAPS_WIDTH_MIN);
|
||||
// frame_height_min_ = encoder_->GetCapabilityValue(NV_ENC_CODEC_H264_GUID,
|
||||
// NV_ENC_CAPS_HEIGHT_MIN);
|
||||
encode_level_max_ = encoder_->GetCapabilityValue(NV_ENC_CODEC_H264_GUID,
|
||||
NV_ENC_CAPS_LEVEL_MAX);
|
||||
encode_level_min_ = encoder_->GetCapabilityValue(NV_ENC_CODEC_H264_GUID,
|
||||
NV_ENC_CAPS_LEVEL_MIN);
|
||||
support_dynamic_resolution_ = encoder_->GetCapabilityValue(
|
||||
NV_ENC_CODEC_H264_GUID, NV_ENC_CAPS_SUPPORT_DYN_RES_CHANGE);
|
||||
support_dynamic_bitrate_ = encoder_->GetCapabilityValue(
|
||||
NV_ENC_CODEC_H264_GUID, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE);
|
||||
|
||||
init_params.encodeWidth = frame_width_;
|
||||
init_params.encodeHeight = frame_height_;
|
||||
init_params.encodeConfig->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
|
||||
init_params.encodeConfig->gopLength = keyFrameInterval_;
|
||||
init_params.encodeConfig->frameIntervalP = 1;
|
||||
init_params.encodeConfig->rcParams.rateControlMode =
|
||||
NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_VBR;
|
||||
init_params.encodeConfig->rcParams.maxBitRate = maxBitrate_ * 500;
|
||||
// init_params.encodeConfig->rcParams.enableMinQP = 1;
|
||||
// init_params.encodeConfig->rcParams.minQP.qpIntra = 10;
|
||||
init_params.encodeConfig->rcParams.enableMaxQP = 1;
|
||||
init_params.encodeConfig->rcParams.maxQP.qpIntra = 22;
|
||||
init_params.encodeConfig->encodeCodecConfig.h264Config.level =
|
||||
NV_ENC_LEVEL::NV_ENC_LEVEL_H264_31;
|
||||
init_params.encodeConfig->encodeCodecConfig.h264Config.sliceMode = 1;
|
||||
init_params.encodeConfig->encodeCodecConfig.h264Config.sliceModeData =
|
||||
max_payload_size_;
|
||||
// init_params.encodeConfig->encodeCodecConfig.h264Config.disableSPSPPS = 1;
|
||||
// init_params.encodeConfig->encodeCodecConfig.h264Config.repeatSPSPPS = 1;
|
||||
// must set max encode width and height otherwise will get crash when try to
|
||||
// reconfigure the resolution
|
||||
init_params.maxEncodeWidth = frame_width_max_;
|
||||
init_params.maxEncodeHeight = frame_height_max_;
|
||||
// init_params.darWidth = init_params.encodeWidth;
|
||||
// init_params.darHeight = init_params.encodeHeight;
|
||||
|
||||
encodeConfig.gopLength = key_frame_interval_;
|
||||
encodeConfig.frameIntervalP = 1;
|
||||
encodeConfig.encodeCodecConfig.h264Config.idrPeriod = key_frame_interval_;
|
||||
encodeConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
|
||||
// encodeConfig.rcParams.enableMaxQP = 1;
|
||||
// encodeConfig.rcParams.enableMinQP = 1;
|
||||
// encodeConfig.rcParams.maxQP.qpIntra = 22;
|
||||
// encodeConfig.rcParams.minQP.qpIntra = 10;
|
||||
encodeConfig.rcParams.averageBitRate = average_bitrate_;
|
||||
// use the default VBV buffer size
|
||||
encodeConfig.rcParams.vbvBufferSize = 0;
|
||||
encodeConfig.rcParams.maxBitRate = max_bitrate_;
|
||||
// use the default VBV initial delay
|
||||
encodeConfig.rcParams.vbvInitialDelay = 0;
|
||||
// enable adaptive quantization (Spatial)
|
||||
encodeConfig.rcParams.enableAQ = false;
|
||||
encodeConfig.encodeCodecConfig.h264Config.idrPeriod = encodeConfig.gopLength;
|
||||
encodeConfig.encodeCodecConfig.h264Config.level = encode_level_max_;
|
||||
// encodeConfig.encodeCodecConfig.h264Config.disableSPSPPS = 1;
|
||||
// encodeConfig.encodeCodecConfig.h264Config.repeatSPSPPS = 1;
|
||||
|
||||
encoder_->CreateEncoder(&init_params);
|
||||
|
||||
@@ -94,7 +124,7 @@ int NvidiaVideoEncoder::Init() {
|
||||
}
|
||||
|
||||
int NvidiaVideoEncoder::Encode(
|
||||
const uint8_t *pData, int nSize,
|
||||
const XVideoFrame *video_frame,
|
||||
std::function<int(char *encoded_packets, size_t size,
|
||||
VideoFrameType frame_type)>
|
||||
on_encoded_image) {
|
||||
@@ -104,7 +134,16 @@ int NvidiaVideoEncoder::Encode(
|
||||
}
|
||||
|
||||
if (SAVE_RECEIVED_NV12_STREAM) {
|
||||
fwrite(pData, 1, nSize, file_nv12_);
|
||||
fwrite(video_frame->data, 1, video_frame->size, file_nv12_);
|
||||
}
|
||||
|
||||
if (video_frame->width != frame_width_ ||
|
||||
video_frame->height != frame_height_) {
|
||||
if (support_dynamic_resolution_) {
|
||||
if (0 != ResetEncodeResolution(video_frame->width, video_frame->height)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VideoFrameType frame_type;
|
||||
@@ -120,10 +159,11 @@ int NvidiaVideoEncoder::Encode(
|
||||
#endif
|
||||
|
||||
const NvEncInputFrame *encoder_inputframe = encoder_->GetNextInputFrame();
|
||||
|
||||
// LOG_ERROR("w:{}, h:{}", encoder_->GetEncodeWidth(),
|
||||
// encoder_->GetEncodeHeight());
|
||||
NvEncoderCuda::CopyToDeviceFrame(
|
||||
cuda_context_,
|
||||
(void *)pData, // NOLINT
|
||||
(void *)video_frame->data, // NOLINT
|
||||
0, (CUdeviceptr)encoder_inputframe->inputPtr, encoder_inputframe->pitch,
|
||||
encoder_->GetEncodeWidth(), encoder_->GetEncodeHeight(),
|
||||
CU_MEMORYTYPE_HOST, encoder_inputframe->bufferFormat,
|
||||
@@ -161,20 +201,64 @@ int NvidiaVideoEncoder::OnEncodedImage(char *encoded_packets, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NvidiaVideoEncoder::ForceIdr() {
|
||||
NV_ENC_RECONFIGURE_PARAMS reconfig_params;
|
||||
reconfig_params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
|
||||
int NvidiaVideoEncoder::ForceIdr() {
|
||||
if (!encoder_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
NV_ENC_INITIALIZE_PARAMS init_params;
|
||||
NV_ENC_RECONFIGURE_PARAMS reconfig_params = {NV_ENC_RECONFIGURE_PARAMS_VER};
|
||||
NV_ENC_INITIALIZE_PARAMS init_params = {NV_ENC_INITIALIZE_PARAMS_VER};
|
||||
NV_ENC_CONFIG encode_config = {NV_ENC_CONFIG_VER};
|
||||
init_params.encodeConfig = &encode_config;
|
||||
encoder_->GetInitializeParams(&init_params);
|
||||
|
||||
reconfig_params.reInitEncodeParams = init_params;
|
||||
reconfig_params.forceIDR = 1;
|
||||
reconfig_params.resetEncoder = 1;
|
||||
|
||||
if (!encoder_->Reconfigure(&reconfig_params)) {
|
||||
LOG_ERROR("Failed to force I frame");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NvidiaVideoEncoder::ResetEncodeResolution(unsigned int width,
|
||||
unsigned int height) {
|
||||
if (!encoder_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (width > frame_width_max_ || height > frame_height_max_) {
|
||||
LOG_ERROR(
|
||||
"Target resolution is too large for this hardware encoder, which "
|
||||
"[{}x{}] and support max resolution is [{}x{}]",
|
||||
width, height, frame_width_max_, frame_height_max_);
|
||||
return -1;
|
||||
}
|
||||
|
||||
frame_width_ = width;
|
||||
frame_height_ = height;
|
||||
|
||||
NV_ENC_RECONFIGURE_PARAMS reconfig_params = {NV_ENC_RECONFIGURE_PARAMS_VER};
|
||||
NV_ENC_INITIALIZE_PARAMS init_params = {NV_ENC_INITIALIZE_PARAMS_VER};
|
||||
NV_ENC_CONFIG encode_config = {NV_ENC_CONFIG_VER};
|
||||
init_params.encodeConfig = &encode_config;
|
||||
encoder_->GetInitializeParams(&init_params);
|
||||
|
||||
reconfig_params.reInitEncodeParams = init_params;
|
||||
reconfig_params.reInitEncodeParams.encodeWidth = frame_width_;
|
||||
reconfig_params.reInitEncodeParams.encodeHeight = frame_height_;
|
||||
// reconfig_params.reInitEncodeParams.darWidth =
|
||||
// reconfig_params.reInitEncodeParams.encodeWidth;
|
||||
// reconfig_params.reInitEncodeParams.darHeight =
|
||||
// reconfig_params.reInitEncodeParams.encodeHeight;
|
||||
reconfig_params.forceIDR = 1;
|
||||
|
||||
if (!encoder_->Reconfigure(&reconfig_params)) {
|
||||
LOG_ERROR("Failed to reset resolution");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -13,31 +13,49 @@ class NvidiaVideoEncoder : public VideoEncoder {
|
||||
|
||||
int Init();
|
||||
int Encode(const uint8_t* pData, int nSize,
|
||||
std::function<int(char* encoded_packets, size_t size,
|
||||
VideoFrameType frame_type)>
|
||||
on_encoded_image);
|
||||
|
||||
int Encode(const XVideoFrame* video_frame,
|
||||
std::function<int(char* encoded_packets, size_t size,
|
||||
VideoFrameType frame_type)>
|
||||
on_encoded_image) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Encode(const XVideoFrame* video_frame,
|
||||
std::function<int(char* encoded_packets, size_t size,
|
||||
VideoFrameType frame_type)>
|
||||
on_encoded_image);
|
||||
|
||||
virtual int OnEncodedImage(char* encoded_packets, size_t size);
|
||||
|
||||
void ForceIdr();
|
||||
int ForceIdr();
|
||||
|
||||
private:
|
||||
int index_of_GPU = 0;
|
||||
GUID codec_guid = NV_ENC_CODEC_H264_GUID;
|
||||
GUID preset_guid = NV_ENC_PRESET_P2_GUID;
|
||||
NV_ENC_TUNING_INFO tuning_info =
|
||||
int ResetEncodeResolution(unsigned int width, unsigned int height);
|
||||
|
||||
private:
|
||||
int index_of_gpu_ = 0;
|
||||
CUdevice cuda_device_ = 0;
|
||||
|
||||
GUID codec_guid_ = NV_ENC_CODEC_H264_GUID;
|
||||
GUID preset_guid_ = NV_ENC_PRESET_P3_GUID;
|
||||
NV_ENC_TUNING_INFO tuning_info_ =
|
||||
NV_ENC_TUNING_INFO::NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY;
|
||||
int frame_width_ = 1280;
|
||||
int frame_height_ = 720;
|
||||
int keyFrameInterval_ = 3000;
|
||||
int maxBitrate_ = 1000;
|
||||
NV_ENC_BUFFER_FORMAT buffer_format_ =
|
||||
NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_NV12;
|
||||
|
||||
uint32_t frame_width_max_ = 0;
|
||||
uint32_t frame_height_max_ = 0;
|
||||
uint32_t frame_width_min_ = 0;
|
||||
uint32_t frame_height_min_ = 0;
|
||||
uint32_t encode_level_max_ = 0;
|
||||
uint32_t encode_level_min_ = 0;
|
||||
bool support_dynamic_resolution_ = false;
|
||||
bool support_dynamic_bitrate_ = false;
|
||||
|
||||
uint32_t frame_width_ = 1280;
|
||||
uint32_t frame_height_ = 720;
|
||||
uint32_t key_frame_interval_ = 3000;
|
||||
uint32_t average_bitrate_ = 2000000;
|
||||
uint32_t max_bitrate_ = 10000000;
|
||||
int max_payload_size_ = 3000;
|
||||
NvEncoder* encoder_ = nullptr;
|
||||
CUcontext cuda_context_ = nullptr;
|
||||
|
||||
@@ -358,10 +358,12 @@ int OpenH264Encoder::OnEncodedImage(char *encoded_packets, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OpenH264Encoder::ForceIdr() {
|
||||
int OpenH264Encoder::ForceIdr() {
|
||||
if (openh264_encoder_) {
|
||||
openh264_encoder_->ForceIntraFrame(true);
|
||||
return openh264_encoder_->ForceIntraFrame(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OpenH264Encoder::Release() {
|
||||
|
||||
@@ -37,7 +37,7 @@ class OpenH264Encoder : public VideoEncoder {
|
||||
|
||||
int OnEncodedImage(char* encoded_packets, size_t size);
|
||||
|
||||
void ForceIdr();
|
||||
int ForceIdr();
|
||||
|
||||
private:
|
||||
int InitEncoderParams(int width, int height);
|
||||
|
||||
@@ -29,7 +29,7 @@ class VideoEncoder {
|
||||
on_encoded_image) = 0;
|
||||
|
||||
virtual int OnEncodedImage(char* encoded_packets, size_t size) = 0;
|
||||
virtual void ForceIdr() = 0;
|
||||
virtual int ForceIdr() = 0;
|
||||
|
||||
VideoEncoder() = default;
|
||||
virtual ~VideoEncoder() {}
|
||||
|
||||
Reference in New Issue
Block a user