[FFmpeg-devel] [PATCH 1/3] libaomenc: Add support for tiles

Mark Thompson sw at jkqxz.net
Mon Sep 10 01:08:10 EEST 2018


Adds an option to specify the number of tile rows and columns, then uses
equal-sized tiles to fill the frame.
---
Useful for testing to make arbitrary arrangements of tiles, though the requirement to set the superblock size for the whole stream at the top level rather than letting it be set dynamically is slightly unfortunate.

The rounding error is placed at the left/top here, it might be better to place it around the sides instead?  (The most important detail is likely to be in the centre of the frame, so make the tiles there smaller?  I'm not sure whether this argument is actually valid, though.)


 libavcodec/libaomenc.c | 55 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c
index 9431179886..0b4fa71fc7 100644
--- a/libavcodec/libaomenc.c
+++ b/libavcodec/libaomenc.c
@@ -68,6 +68,7 @@ typedef struct AOMEncoderContext {
     int static_thresh;
     int drop_threshold;
     int noise_sensitivity;
+    int tile_cols, tile_rows;
 } AOMContext;
 
 static const char *const ctlidstr[] = {
@@ -79,6 +80,7 @@ static const char *const ctlidstr[] = {
     [AV1E_SET_COLOR_PRIMARIES]  = "AV1E_SET_COLOR_PRIMARIES",
     [AV1E_SET_MATRIX_COEFFICIENTS] = "AV1E_SET_MATRIX_COEFFICIENTS",
     [AV1E_SET_TRANSFER_CHARACTERISTICS] = "AV1E_SET_TRANSFER_CHARACTERISTICS",
+    [AV1E_SET_SUPERBLOCK_SIZE]  = "AV1E_SET_SUPERBLOCK_SIZE",
 };
 
 static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc)
@@ -143,6 +145,10 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx,
            width, "kf_mode:",     cfg->kf_mode,
            width, "kf_min_dist:", cfg->kf_min_dist,
            width, "kf_max_dist:", cfg->kf_max_dist);
+    av_log(avctx, level, "tile settings\n"
+                         "  %*s%d\n  %*s%d\n",
+           width, "tile_width_count:",  cfg->tile_width_count,
+           width, "tile_height_count:", cfg->tile_height_count);
     av_log(avctx, level, "\n");
 }
 
@@ -294,6 +300,7 @@ static av_cold int aom_init(AVCodecContext *avctx,
     int res;
     aom_img_fmt_t img_fmt;
     aom_codec_caps_t codec_caps = aom_codec_get_caps(iface);
+    aom_superblock_size_t superblock_size = AOM_SUPERBLOCK_SIZE_DYNAMIC;
 
     av_log(avctx, AV_LOG_INFO, "%s\n", aom_codec_version_str());
     av_log(avctx, AV_LOG_VERBOSE, "%s\n", aom_codec_build_config());
@@ -431,6 +438,51 @@ static av_cold int aom_init(AVCodecContext *avctx,
 
     enccfg.g_error_resilient = ctx->error_resilient;
 
+    if (ctx->tile_cols && ctx->tile_rows) {
+        int sb_size, sb_width, sb_height;
+        int cols_per_tile, cols_step, rows_per_tile, rows_step, i;
+
+        if (avctx->width / ctx->tile_cols < 128 ||
+            avctx->width / ctx->tile_rows < 128) {
+            // User has requested more tiles than would fit with 128x128
+            // superblocks, so assume they want 64x64.
+            sb_size = 64;
+            superblock_size = AOM_SUPERBLOCK_SIZE_64X64;
+        } else {
+            sb_size = 128;
+            superblock_size = AOM_SUPERBLOCK_SIZE_128X128;
+        }
+
+        if (avctx->width  / ctx->tile_cols < sb_size ||
+            avctx->height / ctx->tile_rows < sb_size) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: tiles must be "
+                   "at least one superblock wide and high.\n");
+            return AVERROR(EINVAL);
+        }
+        if (ctx->tile_cols > MAX_TILE_WIDTHS ||
+            ctx->tile_rows > MAX_TILE_HEIGHTS) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: at most %dx%d "
+                   "tiles allowed.\n", MAX_TILE_WIDTHS, MAX_TILE_HEIGHTS);
+            return AVERROR(EINVAL);
+        }
+
+        enccfg.tile_width_count  = ctx->tile_cols;
+        enccfg.tile_height_count = ctx->tile_rows;
+
+        sb_width   = (avctx->width  + sb_size - 1) / sb_size;
+        sb_height  = (avctx->height + sb_size - 1) / sb_size;
+
+        cols_per_tile = sb_width / ctx->tile_cols;
+        cols_step     = sb_width % ctx->tile_cols;
+        for (i = 0; i < ctx->tile_cols; i++)
+            enccfg.tile_widths[i] = cols_per_tile + (i < cols_step);
+
+        rows_per_tile = sb_height / ctx->tile_rows;
+        rows_step     = sb_height % ctx->tile_rows;
+        for (i = 0; i < ctx->tile_rows; i++)
+            enccfg.tile_heights[i] = rows_per_tile + (i < rows_step);
+    }
+
     dump_enc_cfg(avctx, &enccfg);
     /* Construct Encoder Context */
     res = aom_codec_enc_init(&ctx->encoder, iface, &enccfg, flags);
@@ -454,6 +506,8 @@ static av_cold int aom_init(AVCodecContext *avctx,
     codecctl_int(avctx, AV1E_SET_TRANSFER_CHARACTERISTICS, avctx->color_trc);
     set_color_range(avctx);
 
+    codecctl_int(avctx, AV1E_SET_SUPERBLOCK_SIZE, superblock_size);
+
     // provide dummy value to initialize wrapper, values will be updated each _encode()
     aom_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1,
                  (unsigned char*)1);
@@ -746,6 +800,7 @@ static const AVOption options[] = {
     { "static-thresh",    "A change threshold on blocks below which they will be skipped by the encoder", OFFSET(static_thresh), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
     { "drop-threshold",   "Frame drop threshold", offsetof(AOMContext, drop_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, VE },
     { "noise-sensitivity", "Noise sensitivity", OFFSET(noise_sensitivity), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 4, VE},
+    { "tiles",            "Tile rows x columns", OFFSET(tile_cols), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, VE },
     { NULL }
 };
 
-- 
2.18.0



More information about the ffmpeg-devel mailing list