+static av_cold int vaapi_encode_init_row_slice_structure(AVCodecContext *avctx,
+ uint32_t slice_structure)
+{
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+ int req_slices;
+
+ // For fixed-size slices currently we only support whole rows, making
+ // rectangular slices. This could be extended to arbitrary runs of
+ // blocks, but since slices tend to be a conformance requirement and
+ // most cases (such as broadcast or bluray) want rectangular slices
+ // only it would need to be gated behind another option.
+ if (avctx->slices > ctx->slice_block_rows) {
+ av_log(avctx, AV_LOG_WARNING, "Not enough rows to use "
+ "configured number of slices (%d < %d); using "
+ "maximum.\n", ctx->slice_block_rows, avctx->slices);
+ req_slices = ctx->slice_block_rows;
+ } else {
+ req_slices = avctx->slices;
+ }
+ if (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS ||
+ slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) {
+ ctx->nb_slices = req_slices;
+ ctx->slice_size = ctx->slice_block_rows / ctx->nb_slices;
+ } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) {
+ int k;
+ for (k = 1;; k *= 2) {
+ if (2 * k * (req_slices - 1) + 1 >= ctx->slice_block_rows)
+ break;
+ }
+ ctx->nb_slices = (ctx->slice_block_rows + k - 1) / k;
+ ctx->slice_size = k;
+#if VA_CHECK_VERSION(1, 0, 0)
+ } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS) {
+ ctx->nb_slices = ctx->slice_block_rows;
+ ctx->slice_size = 1;
+#endif
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Driver does not support any usable "
+ "slice structure modes (%#x).\n", slice_structure);
+ return AVERROR(EINVAL);
+ }
+
+ 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;
+}
+