diff mbox series

[FFmpeg-devel,v2] lavc/vaapi_encode_h265: add private b_strategy option for hevc_vaapi

Message ID 1586853861-21221-1-git-send-email-linjie.fu@intel.com
State New
Headers show
Series [FFmpeg-devel,v2] lavc/vaapi_encode_h265: add private b_strategy option for hevc_vaapi
Related show

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Fu, Linjie April 14, 2020, 8:44 a.m. UTC
Allow user to choose between I/P/B frames:

- normal
    Ordinary IB..BPB..B GOP structure.
- low delay B-frames:
    Allows forward-predict only for all B frames, L0 == L1, supported
    on ICL+ platforms, required by VDENC(low_power).
- reference B-frames:
    Convert P-frames to low delay B-frames, normal B frames still have
    2 different ref_lists and allow bi-prediction.

Low delay B:
<http://what-when-how.com/Tutorial/topic-397pct9eq3/High-Efficiency-Video-Coding-HEVC-288.html>

There is an on-going work in libva and media-driver to add querys
support for low delay b, would add it once it's ready:
https://github.com/intel/libva/pull/220
https://github.com/intel/libva/pull/364
https://github.com/intel/media-driver/issues/721

Signed-off-by: Linjie Fu <linjie.fu@intel.com>
---
Further step for low delay B would be refining the reference management
to enable support for more forward-references in same ref_list.

 doc/encoders.texi              | 16 ++++++++++++++++
 libavcodec/vaapi_encode.c      | 20 +++++++++++++++-----
 libavcodec/vaapi_encode.h      |  1 +
 libavcodec/vaapi_encode_h265.c | 32 +++++++++++++++++++++++++++++++-
 4 files changed, 63 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/doc/encoders.texi b/doc/encoders.texi
index e23b6b3..1fb5ecf 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -3089,6 +3089,22 @@  Some combination of the following values:
 Include HDR metadata if the input frames have it
 (@emph{mastering_display_colour_volume} and @emph{content_light_level}
 messages).
+
+@item b_strategy
+Allow user to choose between I/P/B frames and specify the type of B-frames.
+@table @samp
+@item normal
+Normal IBBPBB strategy.
+
+@item low_delay_b
+Allows forward-predict only for all B frames, ref_list0 equals to ref_list1,
+supported on ICL+ platforms, required by VDENC(low_power).
+
+@item ref_b
+Convert P-frames to low delay B-frames as references, while normal B frames
+still have 2 different ref_lists and allow bi-prediction.
+@end table
+
 @end table
 
 @end table
diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
index 8ff720e..ea7efb6 100644
--- a/libavcodec/vaapi_encode.c
+++ b/libavcodec/vaapi_encode.c
@@ -1792,15 +1792,25 @@  static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx)
                "reference frames.\n");
         return AVERROR(EINVAL);
     } else if (!(ctx->codec->flags & FLAG_B_PICTURES) ||
-               ref_l1 < 1 || avctx->max_b_frames < 1) {
-        av_log(avctx, AV_LOG_VERBOSE, "Using intra and P-frames "
-               "(supported references: %d / %d).\n", ref_l0, ref_l1);
+               ref_l1 < 1 || avctx->max_b_frames < 1 ||
+               ctx->b_frame_strategy == 1) {
+        if (ctx->b_frame_strategy == 1)
+            av_log(avctx, AV_LOG_VERBOSE, "Using intra and B -frames "
+                   "(low delay) (supported references: %d / %d).\n",
+                   ref_l0, ref_l1);
+        else
+            av_log(avctx, AV_LOG_VERBOSE, "Using intra and P-frames "
+                   "(supported references: %d / %d).\n", ref_l0, ref_l1);
         ctx->gop_size = avctx->gop_size;
         ctx->p_per_i  = INT_MAX;
         ctx->b_per_p  = 0;
     } else {
-        av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames "
-               "(supported references: %d / %d).\n", ref_l0, ref_l1);
+        if (ctx->b_frame_strategy == 2)
+            av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames "
+                   "(supported references: %d / %d).\n", ref_l0, ref_l1);
+        else
+            av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames "
+                   "(supported references: %d / %d).\n", ref_l0, ref_l1);
         ctx->gop_size = avctx->gop_size;
         ctx->p_per_i  = INT_MAX;
         ctx->b_per_p  = avctx->max_b_frames;
diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
index b9a3def..1feca6c 100644
--- a/libavcodec/vaapi_encode.h
+++ b/libavcodec/vaapi_encode.h
@@ -310,6 +310,7 @@  typedef struct VAAPIEncodeContext {
     int idr_counter;
     int gop_counter;
     int end_of_stream;
+    int b_frame_strategy;
 
     // Whether the driver supports ROI at all.
     int             roi_allowed;
diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
index 97dc5a7..cecde73 100644
--- a/libavcodec/vaapi_encode_h265.c
+++ b/libavcodec/vaapi_encode_h265.c
@@ -62,6 +62,7 @@  typedef struct VAAPIEncodeH265Context {
     int tier;
     int level;
     int sei;
+    int b_frame_strategy;
 
     // Derived settings.
     int fixed_qp_idr;
@@ -894,6 +895,9 @@  static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
 
     sh->slice_type = hpic->slice_type;
 
+    if (sh->slice_type == HEVC_SLICE_P && priv->b_frame_strategy)
+        sh->slice_type = HEVC_SLICE_B;
+
     sh->slice_pic_order_cnt_lsb = hpic->pic_order_cnt &
         (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1;
 
@@ -1052,10 +1056,13 @@  static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
         av_assert0(pic->type == PICTURE_TYPE_P ||
                    pic->type == PICTURE_TYPE_B);
         vslice->ref_pic_list0[0] = vpic->reference_frames[0];
+        if (priv->b_frame_strategy == 1 && pic->type == PICTURE_TYPE_P)
+            // Reference for low delay B-frame, L0 == L1
+            vslice->ref_pic_list1[0] = vpic->reference_frames[0];
     }
     if (pic->nb_refs >= 2) {
-        // Forward reference for B-frame.
         av_assert0(pic->type == PICTURE_TYPE_B);
+        // Forward reference for B-frame.
         vslice->ref_pic_list1[0] = vpic->reference_frames[1];
     }
 
@@ -1181,6 +1188,21 @@  static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx)
     if (priv->qp > 0)
         ctx->explicit_qp = priv->qp;
 
+    // Low delay B-frames is required for low power encoding.
+    if (ctx->low_power && priv->b_frame_strategy != 1) {
+        priv->b_frame_strategy = 1;
+        av_log(avctx, AV_LOG_WARNING, "Low delay B-frames required "
+               "for low power encoding.\n");
+    }
+
+    if (priv->b_frame_strategy) {
+        ctx->b_frame_strategy = priv->b_frame_strategy;
+        if (ctx->b_frame_strategy == 1)
+            av_log(avctx, AV_LOG_VERBOSE, "Low delay B-frames enabled.\n");
+        else
+            av_log(avctx, AV_LOG_VERBOSE, "Reference B-frames enabled.\n");
+    }
+
     return ff_vaapi_encode_init(avctx);
 }
 
@@ -1256,6 +1278,14 @@  static const AVOption vaapi_encode_h265_options[] = {
       0, AV_OPT_TYPE_CONST,
       { .i64 = SEI_MASTERING_DISPLAY | SEI_CONTENT_LIGHT_LEVEL },
       INT_MIN, INT_MAX, FLAGS, "sei" },
+    { "b_strategy", "Strategy to choose between I/P/B-frames",
+      OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, FLAGS, "b_strategy" },
+        { "normal",      "Normal IB..BPB..B strategy",
+                          0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS, "b_strategy" },
+        { "low_delay_b", "Use low delay B-frames with forward-prediction only",
+                          0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "b_strategy" },
+        { "ref_b",       "Only convert P-frames to low delay B-frames as references",
+                          0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, FLAGS, "b_strategy" },
 
     { NULL },
 };