typedef NVENCSTATUS (NVENCAPI* PNVENCODEAPICREATEINSTANCE)(NV_ENCODE_API_FUNCTION_LIST *functionList);
+#if NVENCAPI_MAJOR_VERSION < 5
static const GUID dummy_license = { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } };
+#endif
typedef struct NvencInputSurface
{
char *preset;
int cbr;
int twopass;
- int gobpattern;
int gpu;
} NvencContext;
CUcontext cu_context_curr;
CUresult cu_res;
GUID encoder_preset = NV_ENC_PRESET_HQ_GUID;
- GUID license = dummy_license;
NVENCSTATUS nv_status = NV_ENC_SUCCESS;
int surfaceCount = 0;
int i, num_mbs;
int isLL = 0;
int res = 0;
+ int dw, dh;
+
+#if NVENCAPI_MAJOR_VERSION < 5
+ GUID license = dummy_license;
+#endif
NvencContext *ctx = avctx->priv_data;
NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
preset_config.presetCfg.version = NV_ENC_CONFIG_VER;
encode_session_params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
encode_session_params.apiVersion = NVENCAPI_VERSION;
+
+#if NVENCAPI_MAJOR_VERSION < 5
encode_session_params.clientKeyPtr = &license;
+#endif
if (ctx->gpu >= dl_fn->nvenc_device_count) {
av_log(avctx, AV_LOG_FATAL, "Requested GPU %d, but only %d GPUs are available!\n", ctx->gpu, dl_fn->nvenc_device_count);
ctx->init_encode_params.encodeGUID = NV_ENC_CODEC_H264_GUID;
ctx->init_encode_params.encodeHeight = avctx->height;
ctx->init_encode_params.encodeWidth = avctx->width;
- ctx->init_encode_params.darHeight = avctx->height;
- ctx->init_encode_params.darWidth = avctx->width;
+
+ if (avctx->sample_aspect_ratio.num && avctx->sample_aspect_ratio.den &&
+ (avctx->sample_aspect_ratio.num != 1 || avctx->sample_aspect_ratio.num != 1)) {
+ av_reduce(&dw, &dh,
+ avctx->width * avctx->sample_aspect_ratio.num,
+ avctx->height * avctx->sample_aspect_ratio.den,
+ 1024 * 1024);
+ ctx->init_encode_params.darHeight = dh;
+ ctx->init_encode_params.darWidth = dw;
+ } else {
+ ctx->init_encode_params.darHeight = avctx->height;
+ ctx->init_encode_params.darWidth = avctx->width;
+ }
+
ctx->init_encode_params.frameRateNum = avctx->time_base.den;
ctx->init_encode_params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
memcpy(&ctx->encode_config, &preset_config.presetCfg, sizeof(ctx->encode_config));
ctx->encode_config.version = NV_ENC_CONFIG_VER;
- if (avctx->gop_size >= 0) {
+ if (avctx->refs >= 0) {
+ /* 0 means "let the hardware decide" */
+ ctx->encode_config.encodeCodecConfig.h264Config.maxNumRefFrames = avctx->refs;
+ }
+
+ if (avctx->gop_size > 0) {
+ if (avctx->max_b_frames >= 0) {
+ /* 0 is intra-only, 1 is I/P only, 2 is one B Frame, 3 two B frames, and so on. */
+ ctx->encode_config.frameIntervalP = avctx->max_b_frames + 1;
+ }
+
ctx->encode_config.gopLength = avctx->gop_size;
ctx->encode_config.encodeCodecConfig.h264Config.idrPeriod = avctx->gop_size;
+ } else if (avctx->gop_size == 0) {
+ ctx->encode_config.frameIntervalP = 0;
+ ctx->encode_config.gopLength = 1;
+ ctx->encode_config.encodeCodecConfig.h264Config.idrPeriod = 1;
}
+ /* when there're b frames, set dts offset */
+ if (ctx->encode_config.frameIntervalP >= 2)
+ ctx->last_dts = -2;
+
if (avctx->bit_rate > 0)
ctx->encode_config.rcParams.averageBitRate = avctx->bit_rate;
break;
}
- if (ctx->gobpattern >= 0) {
- ctx->encode_config.frameIntervalP = 1;
- }
-
ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.colourDescriptionPresentFlag = 1;
ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.videoSignalTypePresentFlag = 1;
ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.videoFullRangeFlag = avctx->color_range == AVCOL_RANGE_JPEG;
ctx->encode_config.encodeCodecConfig.h264Config.disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
+ ctx->encode_config.encodeCodecConfig.h264Config.repeatSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
nv_status = p_nvenc->nvEncInitializeEncoder(ctx->nvencoder, &ctx->init_encode_params);
if (nv_status != NV_ENC_SUCCESS) {
pkt->pts = lock_params.outputTimeStamp;
pkt->dts = timestamp_queue_dequeue(&ctx->timestamp_list);
+ /* when there're b frame(s), set dts offset */
+ if (ctx->encode_config.frameIntervalP >= 2)
+ pkt->dts -= 1;
+
if (pkt->dts > pkt->pts)
pkt->dts = pkt->pts;
pic_params.inputDuration = 0;
pic_params.codecPicParams.h264PicParams.sliceMode = ctx->encode_config.encodeCodecConfig.h264Config.sliceMode;
pic_params.codecPicParams.h264PicParams.sliceModeData = ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData;
+
+#if NVENCAPI_MAJOR_VERSION < 5
memcpy(&pic_params.rcParams, &ctx->encode_config.rcParams, sizeof(NV_ENC_RC_PARAMS));
+#endif
res = timestamp_queue_enqueue(&ctx->timestamp_list, frame->pts);
{ "preset", "Set the encoding preset (one of hq, hp, bd, ll, llhq, llhp, default)", OFFSET(preset), AV_OPT_TYPE_STRING, { .str = "hq" }, 0, 0, VE },
{ "cbr", "Use cbr encoding mode", OFFSET(cbr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
{ "2pass", "Use 2pass cbr encoding mode (low latency mode only)", OFFSET(twopass), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE },
- { "goppattern", "Specifies the GOP pattern as follows: 0: I, 1: IPP, 2: IBP, 3: IBBP", OFFSET(gobpattern), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 3, VE },
{ "gpu", "Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on.", OFFSET(gpu), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
{ NULL }
};