diff options
author | Timo Rothenpieler <timo@rothenpieler.org> | 2021-04-18 11:17:54 +0200 |
---|---|---|
committer | Timo Rothenpieler <timo@rothenpieler.org> | 2021-04-18 11:43:52 +0200 |
commit | e3fb0f0c88f14cf382d005469242bd63338b862e (patch) | |
tree | 1a372be2daff80092b030f2f2e4d899a33a15c65 | |
parent | acb339bb88ca1a52ef4edb3a5f3df24ed05be82d (diff) | |
download | ffmpeg-e3fb0f0c88f14cf382d005469242bd63338b862e.tar.gz |
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.
-rw-r--r-- | libavcodec/nvenc.c | 142 | ||||
-rw-r--r-- | libavcodec/nvenc.h | 2 |
2 files changed, 74 insertions, 70 deletions
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index dddee8cac1..b09ddbe0fa 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -144,6 +144,70 @@ static int nvenc_print_error(AVCodecContext *avctx, NVENCSTATUS err, return ret; } +typedef struct GUIDTuple { + const GUID guid; + int flags; +} GUIDTuple; + +#define PRESET_ALIAS(alias, name, ...) \ + [PRESET_ ## alias] = { NV_ENC_PRESET_ ## name ## _GUID, __VA_ARGS__ } + +#define PRESET(name, ...) PRESET_ALIAS(name, name, __VA_ARGS__) + +static void nvenc_map_preset(NvencContext *ctx) +{ + GUIDTuple presets[] = { +#ifdef NVENC_HAVE_NEW_PRESETS + PRESET(P1), + PRESET(P2), + PRESET(P3), + PRESET(P4), + PRESET(P5), + PRESET(P6), + PRESET(P7), + PRESET_ALIAS(SLOW, P7, NVENC_TWO_PASSES), + PRESET_ALIAS(MEDIUM, P4, NVENC_ONE_PASS), + PRESET_ALIAS(FAST, P1, NVENC_ONE_PASS), + // Compat aliases + PRESET_ALIAS(DEFAULT, P4, NVENC_DEPRECATED_PRESET), + PRESET_ALIAS(HP, P1, NVENC_DEPRECATED_PRESET), + PRESET_ALIAS(HQ, P7, NVENC_DEPRECATED_PRESET), + PRESET_ALIAS(BD, P5, NVENC_DEPRECATED_PRESET), + PRESET_ALIAS(LOW_LATENCY_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), + PRESET_ALIAS(LOW_LATENCY_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), + PRESET_ALIAS(LOW_LATENCY_HQ, P7, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), + PRESET_ALIAS(LOSSLESS_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), + PRESET_ALIAS(LOSSLESS_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), +#else + PRESET(DEFAULT), + PRESET(HP), + PRESET(HQ), + PRESET(BD), + PRESET_ALIAS(SLOW, HQ, NVENC_TWO_PASSES), + PRESET_ALIAS(MEDIUM, HQ, NVENC_ONE_PASS), + PRESET_ALIAS(FAST, HP, NVENC_ONE_PASS), + PRESET(LOW_LATENCY_DEFAULT, NVENC_LOWLATENCY), + PRESET(LOW_LATENCY_HP, NVENC_LOWLATENCY), + PRESET(LOW_LATENCY_HQ, NVENC_LOWLATENCY), + PRESET(LOSSLESS_DEFAULT, NVENC_LOSSLESS), + PRESET(LOSSLESS_HP, NVENC_LOSSLESS), +#endif + }; + + GUIDTuple *t = &presets[ctx->preset]; + + ctx->init_encode_params.presetGUID = t->guid; + ctx->flags = t->flags; + +#ifdef NVENC_HAVE_NEW_PRESETS + if (ctx->tuning_info == NV_ENC_TUNING_INFO_LOSSLESS) + ctx->flags |= NVENC_LOSSLESS; +#endif +} + +#undef PRESET +#undef PRESET_ALIAS + static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) { #if NVENCAPI_CHECK_VERSION(11, 1) @@ -358,7 +422,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE); - if (ctx->preset >= PRESET_LOSSLESS_DEFAULT && ret <= 0) { + if (ctx->flags & NVENC_LOSSLESS && ret <= 0) { av_log(avctx, AV_LOG_WARNING, "Lossless encoding not supported\n"); return AVERROR(ENOSYS); } @@ -548,6 +612,11 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) return AVERROR_BUG; } + nvenc_map_preset(ctx); + + if (ctx->flags & NVENC_DEPRECATED_PRESET) + av_log(avctx, AV_LOG_WARNING, "The selected preset is deprecated. Use p1 to p7 + -tune or fast/medium/slow.\n"); + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11 || avctx->hw_frames_ctx || avctx->hw_device_ctx) { AVHWFramesContext *frames_ctx; AVHWDeviceContext *hwdev_ctx; @@ -638,65 +707,6 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) return 0; } -typedef struct GUIDTuple { - const GUID guid; - int flags; -} GUIDTuple; - -#define PRESET_ALIAS(alias, name, ...) \ - [PRESET_ ## alias] = { NV_ENC_PRESET_ ## name ## _GUID, __VA_ARGS__ } - -#define PRESET(name, ...) PRESET_ALIAS(name, name, __VA_ARGS__) - -static void nvenc_map_preset(NvencContext *ctx) -{ - GUIDTuple presets[] = { -#ifdef NVENC_HAVE_NEW_PRESETS - PRESET(P1), - PRESET(P2), - PRESET(P3), - PRESET(P4), - PRESET(P5), - PRESET(P6), - PRESET(P7), - PRESET_ALIAS(SLOW, P7, NVENC_TWO_PASSES), - PRESET_ALIAS(MEDIUM, P4, NVENC_ONE_PASS), - PRESET_ALIAS(FAST, P1, NVENC_ONE_PASS), - // Compat aliases - PRESET_ALIAS(DEFAULT, P4, NVENC_DEPRECATED_PRESET), - PRESET_ALIAS(HP, P1, NVENC_DEPRECATED_PRESET), - PRESET_ALIAS(HQ, P7, NVENC_DEPRECATED_PRESET), - PRESET_ALIAS(BD, P5, NVENC_DEPRECATED_PRESET), - PRESET_ALIAS(LOW_LATENCY_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), - PRESET_ALIAS(LOW_LATENCY_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), - PRESET_ALIAS(LOW_LATENCY_HQ, P7, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), - PRESET_ALIAS(LOSSLESS_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), - PRESET_ALIAS(LOSSLESS_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), -#else - PRESET(DEFAULT), - PRESET(HP), - PRESET(HQ), - PRESET(BD), - PRESET_ALIAS(SLOW, HQ, NVENC_TWO_PASSES), - PRESET_ALIAS(MEDIUM, HQ, NVENC_ONE_PASS), - PRESET_ALIAS(FAST, HP, NVENC_ONE_PASS), - PRESET(LOW_LATENCY_DEFAULT, NVENC_LOWLATENCY), - PRESET(LOW_LATENCY_HP, NVENC_LOWLATENCY), - PRESET(LOW_LATENCY_HQ, NVENC_LOWLATENCY), - PRESET(LOSSLESS_DEFAULT, NVENC_LOSSLESS), - PRESET(LOSSLESS_HP, NVENC_LOSSLESS), -#endif - }; - - GUIDTuple *t = &presets[ctx->preset]; - - ctx->init_encode_params.presetGUID = t->guid; - ctx->flags = t->flags; -} - -#undef PRESET -#undef PRESET_ALIAS - static av_cold void set_constqp(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; @@ -1254,18 +1264,15 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) ctx->init_encode_params.encodeConfig = &ctx->encode_config; - nvenc_map_preset(ctx); - - if (ctx->flags & NVENC_DEPRECATED_PRESET) - av_log(avctx, AV_LOG_WARNING, "The selected preset is deprecated. Use p1 to p7 + -tune or fast/medium/slow.\n"); - preset_config.version = NV_ENC_PRESET_CONFIG_VER; preset_config.presetCfg.version = NV_ENC_CONFIG_VER; #ifdef NVENC_HAVE_NEW_PRESETS ctx->init_encode_params.tuningInfo = ctx->tuning_info; - if (ctx->flags & NVENC_LOWLATENCY) + if (ctx->flags & NVENC_LOSSLESS) + ctx->init_encode_params.tuningInfo = NV_ENC_TUNING_INFO_LOSSLESS; + else if (ctx->flags & NVENC_LOWLATENCY) ctx->init_encode_params.tuningInfo = NV_ENC_TUNING_INFO_LOW_LATENCY; nv_status = p_nvenc->nvEncGetEncodePresetConfigEx(ctx->nvencoder, @@ -1307,9 +1314,6 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) * */ if (ctx->rc_lookahead == 0 && ctx->encode_config.rcParams.enableLookahead) ctx->rc_lookahead = ctx->encode_config.rcParams.lookaheadDepth; - - if (ctx->init_encode_params.tuningInfo == NV_ENC_TUNING_INFO_LOSSLESS) - ctx->flags |= NVENC_LOSSLESS; #endif if (ctx->weighted_pred == 1) diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index fefc5f7f0b..314c270e74 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -103,7 +103,7 @@ enum { PRESET_LOW_LATENCY_DEFAULT , PRESET_LOW_LATENCY_HQ , PRESET_LOW_LATENCY_HP, - PRESET_LOSSLESS_DEFAULT, // lossless presets must be the last ones + PRESET_LOSSLESS_DEFAULT, PRESET_LOSSLESS_HP, #ifdef NVENC_HAVE_NEW_PRESETS PRESET_P1, |