I “think” I’ve got something working (well the ai did). I haven’t looked to see what change cured it as I’m off to bed.
This is the code:
// test_nvenc_fixed.cpp
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <dlfcn.h>
#include <cuda.h>
#include "nvEncodeAPI.h"
// Simple helpers
static void printGuid(const GUID &g) {
printf("{%08x-%04x-%04x-%02x%02x-", g.Data1, g.Data2, g.Data3,
(unsigned)g.Data4[0], (unsigned)g.Data4[1]);
for (int i = 2; i < 8; ++i) printf("%02x", (unsigned)g.Data4[i]);
printf("}");
}
static void dumpConfig(const NV_ENC_CONFIG &cfg) {
printf("=== NVENC CONFIG DUMP ===\n");
printf("version = 0x%x\n", cfg.version);
printf("profileGUID = "); printGuid(cfg.profileGUID); printf("\n");
printf("gopLength = %u\n", (unsigned)cfg.gopLength);
printf("frameIntervalP = %u\n", (unsigned)cfg.frameIntervalP);
printf("rateControlMode = %u\n", (unsigned)cfg.rcParams.rateControlMode);
printf("constQP: I=%u, P=%u, B=%u\n",
(unsigned)cfg.rcParams.constQP.qpIntra,
(unsigned)cfg.rcParams.constQP.qpInterP,
(unsigned)cfg.rcParams.constQP.qpInterB);
printf("avgBitRate = %u\n", (unsigned)cfg.rcParams.averageBitRate);
printf("maxBitRate = %u\n", (unsigned)cfg.rcParams.maxBitRate);
printf("vbvBufferSize = %u\n", (unsigned)cfg.rcParams.vbvBufferSize);
printf("=========================\n");
}
static void dumpInitParams(const NV_ENC_INITIALIZE_PARAMS &init) {
printf("=== NVENC INIT PARAMS ===\n");
printf("version = 0x%x\n", init.version);
printf("encodeGUID = "); printGuid(init.encodeGUID); printf("\n");
printf("presetGUID = "); printGuid(init.presetGUID); printf("\n");
printf("encodeWidth = %u\n", (unsigned)init.encodeWidth);
printf("encodeHeight = %u\n", (unsigned)init.encodeHeight);
printf("darWidth = %u\n", (unsigned)init.darWidth);
printf("darHeight = %u\n", (unsigned)init.darHeight);
printf("frameRateNum = %u\n", (unsigned)init.frameRateNum);
printf("frameRateDen = %u\n", (unsigned)init.frameRateDen);
printf("enablePTD = %u\n", (unsigned)init.enablePTD);
printf("bufferFormat = %u\n", (unsigned)init.bufferFormat);
printf("maxEncodeWidth = %u\n", (unsigned)init.maxEncodeWidth);
printf("maxEncodeHeight = %u\n", (unsigned)init.maxEncodeHeight);
printf("maxMEHintCountsPerBlock = %p\n", (void*)init.maxMEHintCountsPerBlock);
printf("=========================\n");
}
// Error helpers
static void checkCuda(CUresult r, const char *what) {
if (r != CUDA_SUCCESS) {
const char *name = nullptr;
cuGetErrorName(r, &name);
fprintf(stderr, "CUDA error %s: %d (%s)\n", what, (int)r, name?name:"?");
exit(1);
}
}
static void checkNvenc(NVENCSTATUS s, const char *what) {
if (s != NV_ENC_SUCCESS) {
fprintf(stderr, "NVENC error %s: %d\n", what, (int)s);
// We don't exit here to allow dumps after failures if desired
}
}
int main() {
// ---------- CUDA init + context ----------
checkCuda(cuInit(0), "cuInit");
CUdevice cuDev = 0;
checkCuda(cuDeviceGet(&cuDev, 0), "cuDeviceGet(0)");
CUcontext cuContext = nullptr;
// cuCtxCreate_v4 signature: CUresult cuCtxCreate_v4(CUcontext*, CUctxCreateParams*, unsigned int, CUdevice)
// params is optional on recent CUDA; passing nullptr is fine for a simple context.
checkCuda(cuCtxCreate_v4(&cuContext, nullptr, 0, cuDev), "cuCtxCreate_v4");
checkCuda(cuCtxSetCurrent(cuContext), "cuCtxSetCurrent");
printf("Created CUcontext %p on device 0\n", (void*)cuContext);
// ---------- load NVENC (dlopen + dlsym) ----------
void *lib = dlopen("libnvidia-encode.so.1", RTLD_NOW | RTLD_LOCAL);
if (!lib) {
fprintf(stderr, "dlopen(libnvidia-encode.so.1) failed: %s\n", dlerror());
return 1;
}
using PFN_NvEncodeAPICreateInstance = NVENCSTATUS(NVENCAPI*)(NV_ENCODE_API_FUNCTION_LIST*);
auto pNvEncodeAPICreateInstance = (PFN_NvEncodeAPICreateInstance)dlsym(lib, "NvEncodeAPICreateInstance");
if (!pNvEncodeAPICreateInstance) {
fprintf(stderr, "dlsym(NvEncodeAPICreateInstance) failed: %s\n", dlerror());
return 1;
}
NV_ENCODE_API_FUNCTION_LIST nvenc = { NV_ENCODE_API_FUNCTION_LIST_VER };
NVENCSTATUS st = pNvEncodeAPICreateInstance(&nvenc);
if (st != NV_ENC_SUCCESS) {
fprintf(stderr, "NvEncodeAPICreateInstance -> %d\n", (int)st);
return 1;
}
printf("Loaded NVENC API\n");
// ---------- open session ----------
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS openParams = {};
openParams.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
openParams.device = cuContext;
openParams.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
#ifdef NVENCAPI_VERSION
openParams.apiVersion = NVENCAPI_VERSION;
#endif
void *hEncoder = nullptr;
st = nvenc.nvEncOpenEncodeSessionEx(&openParams, &hEncoder);
checkNvenc(st, "nvEncOpenEncodeSessionEx");
if (st != NV_ENC_SUCCESS) return 1;
printf("Opened encode session: %p\n", hEncoder);
// assume nvenc, hEncoder, cuContext exist and are valid
// 1) get preset (as you already do)
NV_ENC_PRESET_CONFIG presetCfg;
memset(&presetCfg, 0, sizeof(presetCfg));
presetCfg.version = NV_ENC_PRESET_CONFIG_VER;
presetCfg.presetCfg.version = NV_ENC_CONFIG_VER;
GUID chosenPreset = NV_ENC_PRESET_P3_GUID; // P3 HQ
GUID codec = NV_ENC_CODEC_H264_GUID;
st = nvenc.nvEncGetEncodePresetConfigEx(
hEncoder, codec, chosenPreset, NV_ENC_TUNING_INFO_HIGH_QUALITY, &presetCfg);
if (st != NV_ENC_SUCCESS) {
fprintf(stderr, "nvEncGetEncodePresetConfigEx failed: %d\n", (int)st);
return 1;
}
// 2) sanitize preset: force H264 High profile & force CONSTQP (safe)
presetCfg.presetCfg.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
presetCfg.presetCfg.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
presetCfg.presetCfg.rcParams.constQP.qpIntra = 28;
presetCfg.presetCfg.rcParams.constQP.qpInterP = 31;
presetCfg.presetCfg.rcParams.constQP.qpInterB = 31;
presetCfg.presetCfg.gopLength = (uint32_t)250; // or keep as preset
presetCfg.presetCfg.frameIntervalP = 1; // single ref interval
// 3) init params (zeroed)
NV_ENC_INITIALIZE_PARAMS initParams;
memset(&initParams, 0, sizeof(initParams));
initParams.version = NV_ENC_INITIALIZE_PARAMS_VER;
initParams.encodeGUID = codec;
initParams.presetGUID = chosenPreset;
initParams.encodeWidth = 1920;
initParams.encodeHeight = 1080;
initParams.darWidth = 1920;
initParams.darHeight = 1080;
initParams.frameRateNum = 30;
initParams.frameRateDen = 1;
initParams.enablePTD = 1;
initParams.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
initParams.encodeConfig = &presetCfg.presetCfg;
initParams.tuningInfo = NV_ENC_TUNING_INFO_HIGH_QUALITY;
// 4) ensure context is current
cuCtxSetCurrent(cuContext);
// 5) dump and call
dumpConfig(presetCfg.presetCfg);
dumpInitParams(initParams);
st = nvenc.nvEncInitializeEncoder(hEncoder, &initParams);
printf("nvEncInitializeEncoder -> %d\n", (int)st);
// cleanup
nvenc.nvEncDestroyEncoder(hEncoder);
cuCtxDestroy(cuContext);
dlclose(lib);
return 0;
}
With output:
Created CUcontext 0x5c45ee8d8f10 on device 0
Loaded NVENC API
Opened encode session: 0x5c45ef464f80
=== NVENC CONFIG DUMP ===
version = 0xf009000d
profileGUID = {e7cbc309-4f7a-4b89-af2a-d537c92be310}
gopLength = 250
frameIntervalP = 1
rateControlMode = 0
constQP: I=28, P=31, B=31
avgBitRate = 0
maxBitRate = 0
vbvBufferSize = 0
=========================
=== NVENC INIT PARAMS ===
version = 0xf007000d
encodeGUID = {6bc82762-4e63-4ca4-aa85-1e50f321f6bf}
presetGUID = {36850110-3a07-441f-94d5-3670631f91f6}
encodeWidth = 1920
encodeHeight = 1080
darWidth = 1920
darHeight = 1080
frameRateNum = 30
frameRateDen = 1
enablePTD = 1
bufferFormat = 1
maxEncodeWidth = 0
maxEncodeHeight = 0
maxMEHintCountsPerBlock = 0x7ffd823d9a48
=========================
nvEncInitializeEncoder -> 0