diff mbox series

[FFmpeg-devel,v2,3/4] lavc/vaapi_encode: add tile slice encoding support

Message ID 1589291233-5342-3-git-send-email-linjie.fu@intel.com
State Accepted
Commit a7c2cdf0f6bc53d2bdf05fc92f20415a3de7045f
Headers show
Series [FFmpeg-devel,v2,1/4] lavc/vaapi_encode: add EQUAL_MULTI_ROWS support for slice structure
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 May 12, 2020, 1:47 p.m. UTC
Add functions to initialize tile slice structure and make tile slice:
 - vaapi_encode_init_tile_slice_structure
 - vaapi_encode_make_tile_slice

Tile slice is not allowed to cross the boundary of a tile due to
the constraints of media-driver. Currently adding support for one
slice per tile.

N x N tile encoding is supposed to be supported with the the
capability of ARBITRARY_MACROBLOCKS slice structures.

N X 1 tile encoding should also work in ARBITRARY_ROWS slice
structure.

Signed-off-by: Linjie Fu <linjie.fu@intel.com>
---
 libavcodec/vaapi_encode.c | 128 +++++++++++++++++++++++++++++++++++++++++++---
 libavcodec/vaapi_encode.h |  16 ++++++
 2 files changed, 136 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
index 8deec02..2eb8b48 100644
--- a/libavcodec/vaapi_encode.c
+++ b/libavcodec/vaapi_encode.c
@@ -217,6 +217,33 @@  static int vaapi_encode_make_row_slice(AVCodecContext *avctx,
     return 0;
 }
 
+static int vaapi_encode_make_tile_slice(AVCodecContext *avctx,
+                                        VAAPIEncodePicture *pic)
+{
+    VAAPIEncodeContext *ctx = avctx->priv_data;
+    VAAPIEncodeSlice *slice;
+    int i, j, index;
+
+    for (i = 0; i < ctx->tile_cols; i++) {
+        for (j = 0; j < ctx->tile_rows; j++) {
+            index        = j * ctx->tile_cols + i;
+            slice        = &pic->slices[index];
+            slice->index = index;
+
+            pic->slices[index].block_start = ctx->col_bd[i] +
+                                             ctx->row_bd[j] * ctx->slice_block_cols;
+            pic->slices[index].block_size  = ctx->row_height[j] * ctx->col_width[i];
+
+            av_log(avctx, AV_LOG_DEBUG, "Slice %2d: (%2d, %2d) start at: %4d "
+               "width:%2d height:%2d (%d blocks).\n", index, ctx->col_bd[i],
+               ctx->row_bd[j], slice->block_start, ctx->col_width[i],
+               ctx->row_height[j], slice->block_size);
+        }
+    }
+
+    return 0;
+}
+
 static int vaapi_encode_issue(AVCodecContext *avctx,
                               VAAPIEncodePicture *pic)
 {
@@ -406,7 +433,10 @@  static int vaapi_encode_issue(AVCodecContext *avctx,
             goto fail;
         }
 
-        vaapi_encode_make_row_slice(avctx, pic);
+        if (ctx->tile_rows && ctx->tile_cols)
+            vaapi_encode_make_tile_slice(avctx, pic);
+        else
+            vaapi_encode_make_row_slice(avctx, pic);
     }
 
     for (i = 0; i < pic->nb_slices; i++) {
@@ -1891,11 +1921,76 @@  static av_cold int vaapi_encode_init_row_slice_structure(AVCodecContext *avctx,
     return 0;
 }
 
+static av_cold int vaapi_encode_init_tile_slice_structure(AVCodecContext *avctx,
+                                                          uint32_t slice_structure)
+{
+    VAAPIEncodeContext *ctx = avctx->priv_data;
+    int i, req_tiles;
+
+    if (!(slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS ||
+         (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS &&
+          ctx->tile_cols == 1))) {
+        av_log(avctx, AV_LOG_ERROR, "Supported slice structure (%#x) doesn't work for "
+               "current tile requirement.\n", slice_structure);
+        return AVERROR(EINVAL);
+    }
+
+    if (ctx->tile_rows > ctx->slice_block_rows ||
+        ctx->tile_cols > ctx->slice_block_cols) {
+        av_log(avctx, AV_LOG_WARNING, "Not enough block rows/cols (%d x %d) "
+               "for configured number of tile (%d x %d); ",
+               ctx->slice_block_rows, ctx->slice_block_cols,
+               ctx->tile_rows, ctx->tile_cols);
+        ctx->tile_rows = ctx->tile_rows > ctx->slice_block_rows ?
+                                          ctx->slice_block_rows : ctx->tile_rows;
+        ctx->tile_cols = ctx->tile_cols > ctx->slice_block_cols ?
+                                          ctx->slice_block_cols : ctx->tile_cols;
+        av_log(avctx, AV_LOG_WARNING, "using allowed maximum (%d x %d).\n",
+               ctx->tile_rows, ctx->tile_cols);
+    }
+
+    req_tiles = ctx->tile_rows * ctx->tile_cols;
+
+    // Tile slice is not allowed to cross the boundary of a tile due to
+    // the constraints of media-driver. Currently we support one slice
+    // per tile. This could be extended to multiple slices per tile.
+    if (avctx->slices != req_tiles)
+        av_log(avctx, AV_LOG_WARNING, "The number of requested slices "
+               "mismatches with configured number of tile (%d != %d); "
+               "using requested tile number for slice.\n",
+               avctx->slices, req_tiles);
+
+    ctx->nb_slices = req_tiles;
+
+    // Default in uniform spacing
+    // 6-3, 6-5
+    for (i = 0; i < ctx->tile_cols; i++) {
+        ctx->col_width[i] = ( i + 1 ) * ctx->slice_block_cols / ctx->tile_cols -
+                                    i * ctx->slice_block_cols / ctx->tile_cols;
+        ctx->col_bd[i + 1]  = ctx->col_bd[i] + ctx->col_width[i];
+    }
+    // 6-4, 6-6
+    for (i = 0; i < ctx->tile_rows; i++) {
+        ctx->row_height[i] = ( i + 1 ) * ctx->slice_block_rows / ctx->tile_rows -
+                                     i * ctx->slice_block_rows / ctx->tile_rows;
+        ctx->row_bd[i + 1] = ctx->row_bd[i] + ctx->row_height[i];
+    }
+
+    av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d x %d tile.\n",
+           ctx->tile_rows, ctx->tile_cols);
+
+    return 0;
+}
+
 static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx)
 {
     VAAPIEncodeContext *ctx = avctx->priv_data;
-    VAConfigAttrib attr[2] = { { VAConfigAttribEncMaxSlices },
-                               { VAConfigAttribEncSliceStructure } };
+    VAConfigAttrib attr[3] = { { VAConfigAttribEncMaxSlices },
+                               { VAConfigAttribEncSliceStructure },
+#if VA_CHECK_VERSION(1, 1, 0)
+                               { VAConfigAttribEncTileSupport },
+#endif
+                             };
     VAStatus vas;
     uint32_t max_slices, slice_structure;
     int ret;
@@ -1913,7 +2008,7 @@  static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx)
     ctx->slice_block_cols = (avctx->width  + ctx->slice_block_width  - 1) /
                              ctx->slice_block_width;
 
-    if (avctx->slices <= 1) {
+    if (avctx->slices <= 1 && !ctx->tile_rows && !ctx->tile_cols) {
         ctx->nb_slices  = 1;
         ctx->slice_size = ctx->slice_block_rows;
         return 0;
@@ -1937,7 +2032,25 @@  static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx)
         return AVERROR(EINVAL);
     }
 
-    ret = vaapi_encode_init_row_slice_structure(avctx, slice_structure);
+    if (ctx->tile_rows && ctx->tile_cols) {
+#if VA_CHECK_VERSION(1, 1, 0)
+        uint32_t tile_support = attr[2].value;
+        if (tile_support == VA_ATTRIB_NOT_SUPPORTED) {
+            av_log(avctx, AV_LOG_ERROR, "Driver does not support encoding "
+                   "pictures as multiple tiles.\n.");
+            return AVERROR(EINVAL);
+        }
+#else
+        av_log(avctx, AV_LOG_ERROR, "Tile encoding option is "
+            "not supported with this VAAPI version.\n");
+        return AVERROR(EINVAL);
+#endif
+    }
+
+    if (ctx->tile_rows && ctx->tile_cols)
+        ret = vaapi_encode_init_tile_slice_structure(avctx, slice_structure);
+    else
+        ret = vaapi_encode_init_row_slice_structure(avctx, slice_structure);
     if (ret < 0)
         return ret;
 
@@ -1953,9 +2066,8 @@  static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx)
         return AVERROR(EINVAL);
     }
 
-    av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d slices "
-           "(default size %d block rows).\n",
-           ctx->nb_slices, ctx->slice_size);
+    av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d slices.\n",
+           ctx->nb_slices);
     return 0;
 }
 
diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
index 1329f64..10cffce 100644
--- a/libavcodec/vaapi_encode.h
+++ b/libavcodec/vaapi_encode.h
@@ -43,6 +43,10 @@  enum {
     MAX_PICTURE_REFERENCES = 2,
     MAX_REORDER_DELAY      = 16,
     MAX_PARAM_BUFFER_SIZE  = 1024,
+    // A.4.1: table A.6 allows at most 22 tile rows for any level.
+    MAX_TILE_ROWS          = 22,
+    // A.4.1: table A.6 allows at most 20 tile columns for any level.
+    MAX_TILE_COLS          = 20,
 };
 
 extern const AVCodecHWConfigInternal *ff_vaapi_encode_hw_configs[];
@@ -302,6 +306,18 @@  typedef struct VAAPIEncodeContext {
     int nb_slices;
     int slice_size;
 
+    // Tile encoding.
+    int tile_rows;
+    int tile_cols;
+    // Tile width of the i-th column.
+    int col_width[MAX_TILE_COLS];
+    // Tile height of i-th row.
+    int row_height[MAX_TILE_ROWS];
+    // Location of the i-th tile column boundary.
+    int col_bd[MAX_TILE_COLS + 1];
+    // Location of the i-th tile row boundary.
+    int row_bd[MAX_TILE_ROWS + 1];
+
     // Frame type decision.
     int gop_size;
     int closed_gop;