diff mbox

[FFmpeg-devel,v4] avocdec/nvenc: Reconfigure bitrate on the fly

Message ID cf36c6f3-27df-94e0-52f3-3602cb32592c@gmail.com
State New
Headers show

Commit Message

pkv.stream May 3, 2018, 7:51 a.m. UTC
Hi,
in previous versions ReconfigureEncoder was called at each frame once 
bitrate was changed.
Fixed that.
The patch was rebased against 
https://github.com/BtbN/FFmpeg/commit/4e8265e3a63a71a40730e8eb575d8aa760bdcddc
Sorry about the back and forth.
Regards
From 7c9653faabfe5a9413b2fdcdb7e218991c25ef46 Mon Sep 17 00:00:00 2001
From: pkviet <pkv.stream@gmail.com>
Date: Thu, 3 May 2018 02:15:52 +0200
Subject: [PATCH] avcodec/nvenc: Change bitrate on the fly

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 <pkv.stream@gmail.com>
---
 libavcodec/nvenc.c | 38 ++++++++++++++++++++++++++++----------
 libavcodec/nvenc.h |  1 +
 2 files changed, 29 insertions(+), 10 deletions(-)

Comments

Timo Rothenpieler May 3, 2018, 5:43 p.m. UTC | #1
Am 03.05.2018 um 09:51 schrieb pkv.stream:
> Hi,
> in previous versions ReconfigureEncoder was called at each frame once 
> bitrate was changed.
> Fixed that.
> The patch was rebased against 
> https://github.com/BtbN/FFmpeg/commit/4e8265e3a63a71a40730e8eb575d8aa760bdcddc 

Slightly modified the approach and pushed it here:
https://github.com/BtbN/FFmpeg/commit/660a137b4dad03e6b9f5f87b5ff946ced297a7f2

Will push tomorrow if no issues with it come up.
pkv.stream May 3, 2018, 7:52 p.m. UTC | #2
Le 03/05/2018 à 7:43 PM, Timo Rothenpieler a écrit :
> Am 03.05.2018 um 09:51 schrieb pkv.stream:
>> Hi,
>> in previous versions ReconfigureEncoder was called at each frame once 
>> bitrate was changed.
>> Fixed that.
>> The patch was rebased against 
>> https://github.com/BtbN/FFmpeg/commit/4e8265e3a63a71a40730e8eb575d8aa760bdcddc 
>
>
> Slightly modified the approach and pushed it here:
> https://github.com/BtbN/FFmpeg/commit/660a137b4dad03e6b9f5f87b5ff946ced297a7f2 
>

thanks a lot for the marked improvements !

for dynamic resolution, maybe add a check ?

ctx->support_dyn_res = nvenc_check_cap(avctx, 
NV_ENC_CAPS_SUPPORT_DYN_RES_CHANGE);

and:
if (dw != ctx->init_encode_params.darWidth || dh != 
ctx->init_encode_params.darHeight)

==>
if ( (dw != ctx->init_encode_params.darWidth || dh != 
ctx->init_encode_params.darHeight) && ctx->support_dyn_res)

Regards
Timo Rothenpieler May 4, 2018, 8:32 a.m. UTC | #3
> for dynamic resolution, maybe add a check ?
> 
> ctx->support_dyn_res = nvenc_check_cap(avctx,
> NV_ENC_CAPS_SUPPORT_DYN_RES_CHANGE);
> 
> and:
> if (dw != ctx->init_encode_params.darWidth || dh !=
> ctx->init_encode_params.darHeight)
> 
> ==>
> if ( (dw != ctx->init_encode_params.darWidth || dh !=
> ctx->init_encode_params.darHeight) && ctx->support_dyn_res)

That's not a resolution change, only a dar change.
I'm not sure if actual resolution changes are even supported by avcodec.
Timo Rothenpieler May 4, 2018, 10:20 p.m. UTC | #4
applied
Carl Eugen Hoyos May 5, 2018, midnight UTC | #5
2018-05-04 10:32 GMT+02:00, Timo Rothenpieler <timo@rothenpieler.org>:

> I'm not sure if actual resolution changes are even supported
> by avcodec.

There are better (read: DVB) samples but I can't find them atm:
https://trac.ffmpeg.org/raw-attachment/ticket/1507/Wrong_aspect_after_resolution_change.rmvb

Carl Eugen
Timo Rothenpieler May 5, 2018, 11:41 a.m. UTC | #6
Am 05.05.2018 um 02:00 schrieb Carl Eugen Hoyos:
> 2018-05-04 10:32 GMT+02:00, Timo Rothenpieler <timo@rothenpieler.org>:
> 
>> I'm not sure if actual resolution changes are even supported
>> by avcodec.
> 
> There are better (read: DVB) samples but I can't find them atm:
> https://trac.ffmpeg.org/raw-attachment/ticket/1507/Wrong_aspect_after_resolution_change.rmvb

I was under the impression that the ones in DVB/mpegts work by ending 
one stream, and starting another one? So essentially spinning up an 
entire new de/encoder, and not by just changing the width/height in the 
AVCodecContext mid stream, hoping the encoder does something reasonable?

At least libx264.c does not check for width/height changes in its 
reconfigure function.
diff mbox

Patch

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index 3313c376fe..c19b600c4c 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -457,6 +457,8 @@  static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx)
     if ((ret = nvenc_check_capabilities(avctx)) < 0)
         goto fail3;
 
+    ctx->dynamic_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE);
+
     av_log(avctx, loglevel, "supports NVENC\n");
 
     dl_fn->nvenc_device_count++;
@@ -550,6 +552,8 @@  static av_cold int nvenc_setup_device(AVCodecContext *avctx)
             av_log(avctx, AV_LOG_FATAL, "Provided device doesn't support required NVENC features\n");
             return ret;
         }
+        ctx->dynamic_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE);
+
     } else {
         int i, nb_devices = 0;
 
@@ -1935,36 +1939,50 @@  static int reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
     NVENCSTATUS ret;
 
     NV_ENC_RECONFIGURE_PARAMS params = { 0 };
-    int needs_reconfig = 0;
-    int needs_encode_config = 0;
     int dw, dh;
+    int reconfig_dar, reconfig_bitrate;
 
     params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
     params.reInitEncodeParams = ctx->init_encode_params;
 
     compute_dar(avctx, &dw, &dh);
-    if (dw != ctx->init_encode_params.darWidth || dh != ctx->init_encode_params.darHeight) {
+    reconfig_dar = dw != ctx->init_encode_params.darWidth || dh != ctx->init_encode_params.darHeight;
+    if (reconfig_dar) {
         av_log(avctx, AV_LOG_VERBOSE,
                "aspect ratio change (DAR): %d:%d -> %d:%d\n",
                ctx->init_encode_params.darWidth,
                ctx->init_encode_params.darHeight, dw, dh);
-
         params.reInitEncodeParams.darHeight = dh;
         params.reInitEncodeParams.darWidth = dw;
-
-        needs_reconfig = 1;
+    }
+    reconfig_bitrate = ctx->dynamic_bitrate > 0 && ctx->rc != NV_ENC_PARAMS_RC_CONSTQP
+        && ctx->encode_config.rcParams.averageBitRate != avctx->bit_rate;
+    if (reconfig_bitrate) {
+        params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
+        params.resetEncoder = 1;
+        params.forceIDR = 1;
+        params.reInitEncodeParams = ctx->init_encode_params;
+        params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate = avctx->bit_rate;
     }
 
-    if (!needs_encode_config)
+    if (!reconfig_bitrate)
         params.reInitEncodeParams.encodeConfig = NULL;
 
-    if (needs_reconfig) {
+    if (reconfig_dar || reconfig_bitrate) {
         ret = p_nvenc->nvEncReconfigureEncoder(ctx->nvencoder, &params);
         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;
+                av_log(avctx, AV_LOG_VERBOSE, "dar reconfigured\n");
+            }
+            if (reconfig_bitrate) {
+                ctx->encode_config.rcParams.averageBitRate = avctx->bit_rate;
+                av_log(avctx, AV_LOG_VERBOSE, "bitrate reconfigured\n");
+            }
+
         }
     }
 
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index c7506d6a15..fd2350aaa6 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -184,6 +184,7 @@  typedef struct NvencContext
     int weighted_pred;
     int coder;
     int b_ref_mode;
+    int dynamic_bitrate;
 } NvencContext;
 
 int ff_nvenc_encode_init(AVCodecContext *avctx);