Skip to content

Commit e3fb0f0

Browse files
committed
avcodec/nvenc: fix lossless tuning logic
Relying on the order of the enum is bad. It clashes with the new presets having to sit at the end of the list, so that they can be properly filtered out by the options parser on builds with older SDKs. So this refactors nvenc.c to instead rely on the internal NVENC_LOSSLESS flag. For this, the preset mapping has to happen much earlier, so it's moved from nvenc_setup_encoder to nvenc_setup_device and thus runs before the device capability check.
1 parent acb339b commit e3fb0f0

File tree

2 files changed

+74
-70
lines changed

2 files changed

+74
-70
lines changed

libavcodec/nvenc.c

+73-69
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,70 @@ static int nvenc_print_error(AVCodecContext *avctx, NVENCSTATUS err,
144144
return ret;
145145
}
146146

147+
typedef struct GUIDTuple {
148+
const GUID guid;
149+
int flags;
150+
} GUIDTuple;
151+
152+
#define PRESET_ALIAS(alias, name, ...) \
153+
[PRESET_ ## alias] = { NV_ENC_PRESET_ ## name ## _GUID, __VA_ARGS__ }
154+
155+
#define PRESET(name, ...) PRESET_ALIAS(name, name, __VA_ARGS__)
156+
157+
static void nvenc_map_preset(NvencContext *ctx)
158+
{
159+
GUIDTuple presets[] = {
160+
#ifdef NVENC_HAVE_NEW_PRESETS
161+
PRESET(P1),
162+
PRESET(P2),
163+
PRESET(P3),
164+
PRESET(P4),
165+
PRESET(P5),
166+
PRESET(P6),
167+
PRESET(P7),
168+
PRESET_ALIAS(SLOW, P7, NVENC_TWO_PASSES),
169+
PRESET_ALIAS(MEDIUM, P4, NVENC_ONE_PASS),
170+
PRESET_ALIAS(FAST, P1, NVENC_ONE_PASS),
171+
// Compat aliases
172+
PRESET_ALIAS(DEFAULT, P4, NVENC_DEPRECATED_PRESET),
173+
PRESET_ALIAS(HP, P1, NVENC_DEPRECATED_PRESET),
174+
PRESET_ALIAS(HQ, P7, NVENC_DEPRECATED_PRESET),
175+
PRESET_ALIAS(BD, P5, NVENC_DEPRECATED_PRESET),
176+
PRESET_ALIAS(LOW_LATENCY_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY),
177+
PRESET_ALIAS(LOW_LATENCY_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY),
178+
PRESET_ALIAS(LOW_LATENCY_HQ, P7, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY),
179+
PRESET_ALIAS(LOSSLESS_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS),
180+
PRESET_ALIAS(LOSSLESS_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS),
181+
#else
182+
PRESET(DEFAULT),
183+
PRESET(HP),
184+
PRESET(HQ),
185+
PRESET(BD),
186+
PRESET_ALIAS(SLOW, HQ, NVENC_TWO_PASSES),
187+
PRESET_ALIAS(MEDIUM, HQ, NVENC_ONE_PASS),
188+
PRESET_ALIAS(FAST, HP, NVENC_ONE_PASS),
189+
PRESET(LOW_LATENCY_DEFAULT, NVENC_LOWLATENCY),
190+
PRESET(LOW_LATENCY_HP, NVENC_LOWLATENCY),
191+
PRESET(LOW_LATENCY_HQ, NVENC_LOWLATENCY),
192+
PRESET(LOSSLESS_DEFAULT, NVENC_LOSSLESS),
193+
PRESET(LOSSLESS_HP, NVENC_LOSSLESS),
194+
#endif
195+
};
196+
197+
GUIDTuple *t = &presets[ctx->preset];
198+
199+
ctx->init_encode_params.presetGUID = t->guid;
200+
ctx->flags = t->flags;
201+
202+
#ifdef NVENC_HAVE_NEW_PRESETS
203+
if (ctx->tuning_info == NV_ENC_TUNING_INFO_LOSSLESS)
204+
ctx->flags |= NVENC_LOSSLESS;
205+
#endif
206+
}
207+
208+
#undef PRESET
209+
#undef PRESET_ALIAS
210+
147211
static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level)
148212
{
149213
#if NVENCAPI_CHECK_VERSION(11, 1)
@@ -358,7 +422,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx)
358422
}
359423

360424
ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE);
361-
if (ctx->preset >= PRESET_LOSSLESS_DEFAULT && ret <= 0) {
425+
if (ctx->flags & NVENC_LOSSLESS && ret <= 0) {
362426
av_log(avctx, AV_LOG_WARNING, "Lossless encoding not supported\n");
363427
return AVERROR(ENOSYS);
364428
}
@@ -548,6 +612,11 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx)
548612
return AVERROR_BUG;
549613
}
550614

615+
nvenc_map_preset(ctx);
616+
617+
if (ctx->flags & NVENC_DEPRECATED_PRESET)
618+
av_log(avctx, AV_LOG_WARNING, "The selected preset is deprecated. Use p1 to p7 + -tune or fast/medium/slow.\n");
619+
551620
if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11 || avctx->hw_frames_ctx || avctx->hw_device_ctx) {
552621
AVHWFramesContext *frames_ctx;
553622
AVHWDeviceContext *hwdev_ctx;
@@ -638,65 +707,6 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx)
638707
return 0;
639708
}
640709

641-
typedef struct GUIDTuple {
642-
const GUID guid;
643-
int flags;
644-
} GUIDTuple;
645-
646-
#define PRESET_ALIAS(alias, name, ...) \
647-
[PRESET_ ## alias] = { NV_ENC_PRESET_ ## name ## _GUID, __VA_ARGS__ }
648-
649-
#define PRESET(name, ...) PRESET_ALIAS(name, name, __VA_ARGS__)
650-
651-
static void nvenc_map_preset(NvencContext *ctx)
652-
{
653-
GUIDTuple presets[] = {
654-
#ifdef NVENC_HAVE_NEW_PRESETS
655-
PRESET(P1),
656-
PRESET(P2),
657-
PRESET(P3),
658-
PRESET(P4),
659-
PRESET(P5),
660-
PRESET(P6),
661-
PRESET(P7),
662-
PRESET_ALIAS(SLOW, P7, NVENC_TWO_PASSES),
663-
PRESET_ALIAS(MEDIUM, P4, NVENC_ONE_PASS),
664-
PRESET_ALIAS(FAST, P1, NVENC_ONE_PASS),
665-
// Compat aliases
666-
PRESET_ALIAS(DEFAULT, P4, NVENC_DEPRECATED_PRESET),
667-
PRESET_ALIAS(HP, P1, NVENC_DEPRECATED_PRESET),
668-
PRESET_ALIAS(HQ, P7, NVENC_DEPRECATED_PRESET),
669-
PRESET_ALIAS(BD, P5, NVENC_DEPRECATED_PRESET),
670-
PRESET_ALIAS(LOW_LATENCY_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY),
671-
PRESET_ALIAS(LOW_LATENCY_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY),
672-
PRESET_ALIAS(LOW_LATENCY_HQ, P7, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY),
673-
PRESET_ALIAS(LOSSLESS_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS),
674-
PRESET_ALIAS(LOSSLESS_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS),
675-
#else
676-
PRESET(DEFAULT),
677-
PRESET(HP),
678-
PRESET(HQ),
679-
PRESET(BD),
680-
PRESET_ALIAS(SLOW, HQ, NVENC_TWO_PASSES),
681-
PRESET_ALIAS(MEDIUM, HQ, NVENC_ONE_PASS),
682-
PRESET_ALIAS(FAST, HP, NVENC_ONE_PASS),
683-
PRESET(LOW_LATENCY_DEFAULT, NVENC_LOWLATENCY),
684-
PRESET(LOW_LATENCY_HP, NVENC_LOWLATENCY),
685-
PRESET(LOW_LATENCY_HQ, NVENC_LOWLATENCY),
686-
PRESET(LOSSLESS_DEFAULT, NVENC_LOSSLESS),
687-
PRESET(LOSSLESS_HP, NVENC_LOSSLESS),
688-
#endif
689-
};
690-
691-
GUIDTuple *t = &presets[ctx->preset];
692-
693-
ctx->init_encode_params.presetGUID = t->guid;
694-
ctx->flags = t->flags;
695-
}
696-
697-
#undef PRESET
698-
#undef PRESET_ALIAS
699-
700710
static av_cold void set_constqp(AVCodecContext *avctx)
701711
{
702712
NvencContext *ctx = avctx->priv_data;
@@ -1254,18 +1264,15 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
12541264

12551265
ctx->init_encode_params.encodeConfig = &ctx->encode_config;
12561266

1257-
nvenc_map_preset(ctx);
1258-
1259-
if (ctx->flags & NVENC_DEPRECATED_PRESET)
1260-
av_log(avctx, AV_LOG_WARNING, "The selected preset is deprecated. Use p1 to p7 + -tune or fast/medium/slow.\n");
1261-
12621267
preset_config.version = NV_ENC_PRESET_CONFIG_VER;
12631268
preset_config.presetCfg.version = NV_ENC_CONFIG_VER;
12641269

12651270
#ifdef NVENC_HAVE_NEW_PRESETS
12661271
ctx->init_encode_params.tuningInfo = ctx->tuning_info;
12671272

1268-
if (ctx->flags & NVENC_LOWLATENCY)
1273+
if (ctx->flags & NVENC_LOSSLESS)
1274+
ctx->init_encode_params.tuningInfo = NV_ENC_TUNING_INFO_LOSSLESS;
1275+
else if (ctx->flags & NVENC_LOWLATENCY)
12691276
ctx->init_encode_params.tuningInfo = NV_ENC_TUNING_INFO_LOW_LATENCY;
12701277

12711278
nv_status = p_nvenc->nvEncGetEncodePresetConfigEx(ctx->nvencoder,
@@ -1307,9 +1314,6 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
13071314
* */
13081315
if (ctx->rc_lookahead == 0 && ctx->encode_config.rcParams.enableLookahead)
13091316
ctx->rc_lookahead = ctx->encode_config.rcParams.lookaheadDepth;
1310-
1311-
if (ctx->init_encode_params.tuningInfo == NV_ENC_TUNING_INFO_LOSSLESS)
1312-
ctx->flags |= NVENC_LOSSLESS;
13131317
#endif
13141318

13151319
if (ctx->weighted_pred == 1)

libavcodec/nvenc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ enum {
103103
PRESET_LOW_LATENCY_DEFAULT ,
104104
PRESET_LOW_LATENCY_HQ ,
105105
PRESET_LOW_LATENCY_HP,
106-
PRESET_LOSSLESS_DEFAULT, // lossless presets must be the last ones
106+
PRESET_LOSSLESS_DEFAULT,
107107
PRESET_LOSSLESS_HP,
108108
#ifdef NVENC_HAVE_NEW_PRESETS
109109
PRESET_P1,

0 commit comments

Comments
 (0)