From 155375123c1f2e41f97057f00e65bcbb20f7833a Mon Sep 17 00:00:00 2001 From: pkviet Date: Thu, 3 May 2018 02:15:52 +0200 Subject: [PATCH] avcodec/nvenc: support dynamic bitrate changes The patch enables dynamic bitrate through ReconfigureEncoder method from nvenc API. This is useful for live streaming in case of network congestion. Signed-off-by: pkviet Signed-off-by: Timo Rothenpieler --- libavcodec/nvenc.c | 59 +++++++++++++++++++++++++++++++++++++++++++--- libavcodec/nvenc.h | 2 ++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 7daf8b3bc0..765e8cf5ca 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -394,6 +394,8 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) } #endif + ctx->support_dyn_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE); + return 0; } @@ -873,7 +875,7 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx) if (avctx->rc_buffer_size > 0) { ctx->encode_config.rcParams.vbvBufferSize = avctx->rc_buffer_size; } else if (ctx->encode_config.rcParams.averageBitRate > 0) { - ctx->encode_config.rcParams.vbvBufferSize = 2 * ctx->encode_config.rcParams.averageBitRate; + avctx->rc_buffer_size = ctx->encode_config.rcParams.vbvBufferSize = 2 * ctx->encode_config.rcParams.averageBitRate; } if (ctx->aq) { @@ -1944,6 +1946,7 @@ static int reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) NV_ENC_RECONFIGURE_PARAMS params = { 0 }; int needs_reconfig = 0; int needs_encode_config = 0; + int reconfig_bitrate = 0, reconfig_dar = 0; int dw, dh; params.version = NV_ENC_RECONFIGURE_PARAMS_VER; @@ -1960,6 +1963,47 @@ static int reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) params.reInitEncodeParams.darWidth = dw; needs_reconfig = 1; + reconfig_dar = 1; + } + + if (ctx->rc != NV_ENC_PARAMS_RC_CONSTQP && ctx->support_dyn_bitrate) { + if (avctx->bit_rate > 0 && params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate != avctx->bit_rate) { + av_log(avctx, AV_LOG_VERBOSE, + "avg bitrate change: %d -> %d\n", + params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate, + (uint32_t)avctx->bit_rate); + + params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate = avctx->bit_rate; + reconfig_bitrate = 1; + } + + if (avctx->rc_max_rate > 0 && ctx->encode_config.rcParams.maxBitRate != avctx->rc_max_rate) { + av_log(avctx, AV_LOG_VERBOSE, + "max bitrate change: %d -> %d\n", + params.reInitEncodeParams.encodeConfig->rcParams.maxBitRate, + (uint32_t)avctx->rc_max_rate); + + params.reInitEncodeParams.encodeConfig->rcParams.maxBitRate = avctx->rc_max_rate; + reconfig_bitrate = 1; + } + + if (avctx->rc_buffer_size > 0 && ctx->encode_config.rcParams.vbvBufferSize != avctx->rc_buffer_size) { + av_log(avctx, AV_LOG_VERBOSE, + "vbv buffer size change: %d -> %d\n", + params.reInitEncodeParams.encodeConfig->rcParams.vbvBufferSize, + avctx->rc_buffer_size); + + params.reInitEncodeParams.encodeConfig->rcParams.vbvBufferSize = avctx->rc_buffer_size; + reconfig_bitrate = 1; + } + + if (reconfig_bitrate) { + params.resetEncoder = 1; + params.forceIDR = 1; + + needs_encode_config = 1; + needs_reconfig = 1; + } } if (!needs_encode_config) @@ -1970,8 +2014,17 @@ static int reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) if (ret != NV_ENC_SUCCESS) { nvenc_print_error(avctx, ret, "failed to reconfigure nvenc"); } else { - ctx->init_encode_params.darHeight = dh; - ctx->init_encode_params.darWidth = dw; + if (reconfig_dar) { + ctx->init_encode_params.darHeight = dh; + ctx->init_encode_params.darWidth = dw; + } + + if (reconfig_bitrate) { + ctx->encode_config.rcParams.averageBitRate = params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate; + ctx->encode_config.rcParams.maxBitRate = params.reInitEncodeParams.encodeConfig->rcParams.maxBitRate; + ctx->encode_config.rcParams.vbvBufferSize = params.reInitEncodeParams.encodeConfig->rcParams.vbvBufferSize; + } + } } diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index c7506d6a15..b29fbf282a 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -152,6 +152,8 @@ typedef struct NvencContext int64_t initial_pts[2]; int first_packet_output; + int support_dyn_bitrate; + void *nvencoder; int preset; -- GitLab