[04/14] nvenc: Delay frame output to increase encoding speed

Message ID 1463387343-5149-4-git-send-email-anton@khirnov.net
State New
Headers show

Commit Message

Anton Khirnov May 16, 2016, 8:28 a.m.
From: Timo Rothenpieler <timo@rothenpieler.org>

Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
 libavcodec/nvenc.c      | 10 +++++++++-
 libavcodec/nvenc.h      |  1 +
 libavcodec/nvenc_h264.c |  1 +
 libavcodec/nvenc_hevc.c |  1 +
 4 files changed, 12 insertions(+), 1 deletion(-)

Comments

Luca Barbato May 16, 2016, 9:04 a.m. | #1
On 16/05/16 10:28, Anton Khirnov wrote:
> From: Timo Rothenpieler <timo@rothenpieler.org>
> 
> Signed-off-by: Anton Khirnov <anton@khirnov.net>
> ---
>  libavcodec/nvenc.c      | 10 +++++++++-
>  libavcodec/nvenc.h      |  1 +
>  libavcodec/nvenc_h264.c |  1 +
>  libavcodec/nvenc_hevc.c |  1 +
>  4 files changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
> index 91951cd..e09f362 100644
> --- a/libavcodec/nvenc.c
> +++ b/libavcodec/nvenc.c
> @@ -840,6 +840,8 @@ static int nvenc_setup_surfaces(AVCodecContext *avctx)
>  
>      ctx->nb_surfaces = FFMAX(4 + avctx->max_b_frames,
>                               ctx->nb_surfaces);
> +    ctx->async_depth = FFMIN(ctx->async_depth, ctx->nb_surfaces - 1);
> +
>  
>      ctx->frames = av_mallocz_array(ctx->nb_surfaces, sizeof(*ctx->frames));
>      if (!ctx->frames)
> @@ -1301,13 +1303,19 @@ FF_ENABLE_DEPRECATION_WARNINGS
>  static int output_ready(AVCodecContext *avctx, int flush)
>  {
>      NVENCContext *ctx = avctx->priv_data;
> +    int nb_ready, nb_pending;
>  
>      /* when B-frames are enabled, we wait for two initial timestamps to
>       * calculate the first dts */
>      if (!flush && avctx->max_b_frames > 0 &&
>          (ctx->initial_pts[0] == AV_NOPTS_VALUE || ctx->initial_pts[1] == AV_NOPTS_VALUE))
>          return 0;
> -    return av_fifo_size(ctx->ready) > 0;
> +
> +    nb_ready   = av_fifo_size(ctx->ready)   / sizeof(NVENCFrame*);
> +    nb_pending = av_fifo_size(ctx->pending) / sizeof(NVENCFrame*);
> +    if (flush)
> +        return nb_ready > 0;
> +    return (nb_ready > 0) && (nb_ready + nb_pending >= ctx->async_depth);
>  }
>  
>  int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
> diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
> index c8f0745..4503fd1 100644
> --- a/libavcodec/nvenc.h
> +++ b/libavcodec/nvenc.h
> @@ -142,6 +142,7 @@ typedef struct NVENCContext {
>      int rc;
>      int device;
>      int flags;
> +    int async_depth;
>  } NVENCContext;
>  
>  int ff_nvenc_encode_init(AVCodecContext *avctx);
> diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
> index 7e4fbff..25f7ea5 100644
> --- a/libavcodec/nvenc_h264.c
> +++ b/libavcodec/nvenc_h264.c
> @@ -72,6 +72,7 @@ static const AVOption options[] = {
>      { "device",   "Select a specific NVENC device",       OFFSET(device),      AV_OPT_TYPE_INT,    { .i64 = -1 },                   -2, INT_MAX, VE, "device" },
>      { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
>      { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
> +    { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
>      { NULL }
>  };
>  
> diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
> index d49ae62..aa29fbd 100644
> --- a/libavcodec/nvenc_hevc.c
> +++ b/libavcodec/nvenc_hevc.c
> @@ -68,6 +68,7 @@ static const AVOption options[] = {
>      { "device",   "Select a specific NVENC device",       OFFSET(device),      AV_OPT_TYPE_INT,    { .i64 = -1 },                   -2, INT_MAX, VE, "device" },
>      { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
>      { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
> +    { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
>      { NULL }
>  };
>  
> 

Call it async_depth as it is called for qsv.

lu

Patch

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index 91951cd..e09f362 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -840,6 +840,8 @@  static int nvenc_setup_surfaces(AVCodecContext *avctx)
 
     ctx->nb_surfaces = FFMAX(4 + avctx->max_b_frames,
                              ctx->nb_surfaces);
+    ctx->async_depth = FFMIN(ctx->async_depth, ctx->nb_surfaces - 1);
+
 
     ctx->frames = av_mallocz_array(ctx->nb_surfaces, sizeof(*ctx->frames));
     if (!ctx->frames)
@@ -1301,13 +1303,19 @@  FF_ENABLE_DEPRECATION_WARNINGS
 static int output_ready(AVCodecContext *avctx, int flush)
 {
     NVENCContext *ctx = avctx->priv_data;
+    int nb_ready, nb_pending;
 
     /* when B-frames are enabled, we wait for two initial timestamps to
      * calculate the first dts */
     if (!flush && avctx->max_b_frames > 0 &&
         (ctx->initial_pts[0] == AV_NOPTS_VALUE || ctx->initial_pts[1] == AV_NOPTS_VALUE))
         return 0;
-    return av_fifo_size(ctx->ready) > 0;
+
+    nb_ready   = av_fifo_size(ctx->ready)   / sizeof(NVENCFrame*);
+    nb_pending = av_fifo_size(ctx->pending) / sizeof(NVENCFrame*);
+    if (flush)
+        return nb_ready > 0;
+    return (nb_ready > 0) && (nb_ready + nb_pending >= ctx->async_depth);
 }
 
 int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index c8f0745..4503fd1 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -142,6 +142,7 @@  typedef struct NVENCContext {
     int rc;
     int device;
     int flags;
+    int async_depth;
 } NVENCContext;
 
 int ff_nvenc_encode_init(AVCodecContext *avctx);
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index 7e4fbff..25f7ea5 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -72,6 +72,7 @@  static const AVOption options[] = {
     { "device",   "Select a specific NVENC device",       OFFSET(device),      AV_OPT_TYPE_INT,    { .i64 = -1 },                   -2, INT_MAX, VE, "device" },
     { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
     { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
+    { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
     { NULL }
 };
 
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index d49ae62..aa29fbd 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -68,6 +68,7 @@  static const AVOption options[] = {
     { "device",   "Select a specific NVENC device",       OFFSET(device),      AV_OPT_TYPE_INT,    { .i64 = -1 },                   -2, INT_MAX, VE, "device" },
     { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
     { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
+    { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
     { NULL }
 };