This adds common code to query driver support and set appropriate address/size information for each slice. It only supports rectangular slices for now, since that is the most common use-case.
Showing the changes to libavcodec (2 of 3 files). Show all
Unified · Split
| @@ -319,16 +319,60 @@ static int vaapi_encode_issue(AVCodecContext *avctx, · 318 unmodified lines | ||
| 319 | 319 | } |
| 320 | 320 | } |
| 321 | 321 | |
| 322 | + if (pic->nb_slices == 0) | |
| 323 | + pic->nb_slices = ctx->nb_slices; | |
| 322 | 324 | if (pic->nb_slices > 0) { |
| 325 | + int rounding; | |
| 326 | + | |
| 323 | 327 | pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); |
| 324 | 328 | if (!pic->slices) { |
| 325 | 329 | err = AVERROR(ENOMEM); |
| 326 | 330 | goto fail; |
| 327 | 331 | } |
| 332 | + | |
| 333 | + for (i = 0; i < pic->nb_slices; i++) | |
| 334 | + pic->slices[i].row_size = ctx->slice_size; | |
| 335 | + | |
| 336 | + rounding = ctx->slice_block_rows - ctx->nb_slices * ctx->slice_size; | |
| 337 | + if (rounding > 0) { | |
| 338 | + // Place rounding error at top and bottom of frame. | |
| 339 | + av_assert0(rounding < pic->nb_slices); | |
| 340 | + // Some Intel drivers contain a bug where the encoder will fail | |
| 341 | + // if the last slice is smaller than the one before it. Since | |
| 342 | + // that's straightforward to avoid here, just do so. | |
| 343 | + if (rounding <= 2) { | |
| 344 | + for (i = 0; i < rounding; i++) | |
| 345 | + ++pic->slices[i].row_size; | |
| 346 | + } else { | |
| 347 | + for (i = 0; i < (rounding + 1) / 2; i++) | |
| 348 | + ++pic->slices[pic->nb_slices - i - 1].row_size; | |
| 349 | + for (i = 0; i < rounding / 2; i++) | |
| 350 | + ++pic->slices[i].row_size; | |
| 351 | + } | |
| 352 | + } else if (rounding < 0) { | |
| 353 | + // Remove rounding error from last slice only. | |
| 354 | + av_assert0(rounding < ctx->slice_size); | |
| 355 | + pic->slices[pic->nb_slices - 1].row_size += rounding; | |
| 356 | + } | |
| 328 | 357 | } |
| 329 | 358 | for (i = 0; i < pic->nb_slices; i++) { |
| 330 | 359 | slice = &pic->slices[i]; |
| 331 | 360 | slice->index = i; |
| 361 | + if (i == 0) { | |
| 362 | + slice->row_start = 0; | |
| 363 | + slice->block_start = 0; | |
| 364 | + } else { | |
| 365 | + const VAAPIEncodeSlice *prev = &pic->slices[i - 1]; | |
| 366 | + slice->row_start = prev->row_start + prev->row_size; | |
| 367 | + slice->block_start = prev->block_start + prev->block_size; | |
| 368 | + } | |
| 369 | + slice->block_size = slice->row_size * ctx->slice_block_cols; | |
| 370 | + | |
| 371 | + av_log(avctx, AV_LOG_DEBUG, "Slice %d: %d-%d (%d rows), " | |
| 372 | + "%d-%d (%d blocks).\n", i, slice->row_start, | |
| 373 | + slice->row_start + slice->row_size - 1, slice->row_size, | |
| 374 | + slice->block_start, slice->block_start + slice->block_size - 1, | |
| 375 | + slice->block_size); | |
| 332 | 376 | |
| 333 | 377 | if (ctx->codec->slice_params_size > 0) { |
| 334 | 378 | slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); |
| @@ -1444,6 +1488,106 @@ static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) · 1109 unmodified lines | ||
| 1444 | 1488 | return 0; |
| 1445 | 1489 | } |
| 1446 | 1490 | |
| 1491 | +static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) | |
| 1492 | +{ | |
| 1493 | + VAAPIEncodeContext *ctx = avctx->priv_data; | |
| 1494 | + VAConfigAttrib attr[2] = { { VAConfigAttribEncMaxSlices }, | |
| 1495 | + { VAConfigAttribEncSliceStructure } }; | |
| 1496 | + VAStatus vas; | |
| 1497 | + uint32_t max_slices, slice_structure; | |
| 1498 | + int req_slices; | |
| 1499 | + | |
| 1500 | + if (!(ctx->codec->flags & FLAG_SLICE_CONTROL)) { | |
| 1501 | + if (avctx->slices > 0) { | |
| 1502 | + av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested " | |
| 1503 | + "but this codec does not support controlling slices.\n"); | |
| 1504 | + } | |
| 1505 | + return 0; | |
| 1506 | + } | |
| 1507 | + | |
| 1508 | + ctx->slice_block_rows = (avctx->height + ctx->slice_block_height - 1) / | |
| 1509 | + ctx->slice_block_height; | |
| 1510 | + ctx->slice_block_cols = (avctx->width + ctx->slice_block_width - 1) / | |
| 1511 | + ctx->slice_block_width; | |
| 1512 | + | |
| 1513 | + if (avctx->slices <= 1) { | |
| 1514 | + ctx->nb_slices = 1; | |
| 1515 | + ctx->slice_size = ctx->slice_block_rows; | |
| 1516 | + return 0; | |
| 1517 | + } | |
| 1518 | + | |
| 1519 | + vas = vaGetConfigAttributes(ctx->hwctx->display, | |
| 1520 | + ctx->va_profile, | |
| 1521 | + ctx->va_entrypoint, | |
| 1522 | + attr, FF_ARRAY_ELEMS(attr)); | |
| 1523 | + if (vas != VA_STATUS_SUCCESS) { | |
| 1524 | + av_log(avctx, AV_LOG_ERROR, "Failed to query slice " | |
| 1525 | + "attributes: %d (%s).\n", vas, vaErrorStr(vas)); | |
| 1526 | + return AVERROR_EXTERNAL; | |
| 1527 | + } | |
| 1528 | + max_slices = attr[0].value; | |
| 1529 | + slice_structure = attr[1].value; | |
| 1530 | + if (max_slices == VA_ATTRIB_NOT_SUPPORTED || | |
| 1531 | + slice_structure == VA_ATTRIB_NOT_SUPPORTED) { | |
| 1532 | + av_log(avctx, AV_LOG_ERROR, "Driver does not support encoding " | |
| 1533 | + "pictures as multiple slices.\n."); | |
| 1534 | + return AVERROR(EINVAL); | |
| 1535 | + } | |
| 1536 | + | |
| 1537 | + // For fixed-size slices currently we only support whole rows, making | |
| 1538 | + // rectangular slices. This could be extended to arbitrary runs of | |
| 1539 | + // blocks, but since slices tend to be a conformance requirement and | |
| 1540 | + // most cases (such as broadcast or bluray) want rectangular slices | |
| 1541 | + // only it would need to be gated behind another option. | |
| 1542 | + if (avctx->slices > ctx->slice_block_rows) { | |
| 1543 | + av_log(avctx, AV_LOG_WARNING, "Not enough rows to use " | |
| 1544 | + "configured number of slices (%d < %d); using " | |
| 1545 | + "maximum.\n", ctx->slice_block_rows, avctx->slices); | |
| 1546 | + req_slices = ctx->slice_block_rows; | |
| 1547 | + } else { | |
| 1548 | + req_slices = avctx->slices; | |
| 1549 | + } | |
| 1550 | + if (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS || | |
| 1551 | + slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) { | |
| 1552 | + ctx->nb_slices = req_slices; | |
| 1553 | + ctx->slice_size = ctx->slice_block_rows / ctx->nb_slices; | |
| 1554 | + } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) { | |
| 1555 | + int k; | |
| 1556 | + for (k = 1;; k *= 2) { | |
| 1557 | + if (2 * k * (req_slices - 1) + 1 >= ctx->slice_block_rows) | |
| 1558 | + break; | |
| 1559 | + } | |
| 1560 | + ctx->nb_slices = (ctx->slice_block_rows + k - 1) / k; | |
| 1561 | + ctx->slice_size = k; | |
| 1562 | +#if VA_CHECK_VERSION(1, 0, 0) | |
| 1563 | + } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS) { | |
| 1564 | + ctx->nb_slices = ctx->slice_block_rows; | |
| 1565 | + ctx->slice_size = 1; | |
| 1566 | +#endif | |
| 1567 | + } else { | |
| 1568 | + av_log(avctx, AV_LOG_ERROR, "Driver does not support any usable " | |
| 1569 | + "slice structure modes (%#x).\n", slice_structure); | |
| 1570 | + return AVERROR(EINVAL); | |
| 1571 | + } | |
| 1572 | + | |
| 1573 | + if (ctx->nb_slices > avctx->slices) { | |
| 1574 | + av_log(avctx, AV_LOG_WARNING, "Slice count rounded up to " | |
| 1575 | + "%d (from %d) due to driver constraints on slice " | |
| 1576 | + "structure.\n", ctx->nb_slices, avctx->slices); | |
| 1577 | + } | |
| 1578 | + if (ctx->nb_slices > max_slices) { | |
| 1579 | + av_log(avctx, AV_LOG_ERROR, "Driver does not support " | |
| 1580 | + "encoding with %d slices (max %"PRIu32").\n", | |
| 1581 | + ctx->nb_slices, max_slices); | |
| 1582 | + return AVERROR(EINVAL); | |
| 1583 | + } | |
| 1584 | + | |
| 1585 | + av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d slices " | |
| 1586 | + "(default size %d block rows).\n", | |
| 1587 | + ctx->nb_slices, ctx->slice_size); | |
| 1588 | + return 0; | |
| 1589 | +} | |
| 1590 | + | |
| 1447 | 1591 | static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx) |
| 1448 | 1592 | { |
| 1449 | 1593 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| @@ -1734,6 +1878,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) · 284 unmodified lines | ||
| 1734 | 1878 | if (err < 0) |
| 1735 | 1879 | goto fail; |
| 1736 | 1880 | |
| 1881 | + err = vaapi_encode_init_slice_structure(avctx); | |
| 1882 | + if (err < 0) | |
| 1883 | + goto fail; | |
| 1884 | + | |
| 1737 | 1885 | err = vaapi_encode_init_packed_headers(avctx); |
| 1738 | 1886 | if (err < 0) |
| 1739 | 1887 | goto fail; |
| @@ -52,6 +52,10 @@ enum { · 51 unmodified lines | ||
| 52 | 52 | |
| 53 | 53 | typedef struct VAAPIEncodeSlice { |
| 54 | 54 | int index; |
| 55 | + int row_start; | |
| 56 | + int row_size; | |
| 57 | + int block_start; | |
| 58 | + int block_size; | |
| 55 | 59 | void *priv_data; |
| 56 | 60 | void *codec_slice_params; |
| 57 | 61 | } VAAPIEncodeSlice; |
| @@ -125,6 +129,10 @@ typedef struct VAAPIEncodeContext { · 67 unmodified lines | ||
| 125 | 129 | int surface_width; |
| 126 | 130 | int surface_height; |
| 127 | 131 | |
| 132 | + // The block size for slice calculations. | |
| 133 | + int slice_block_width; | |
| 134 | + int slice_block_height; | |
| 135 | + | |
| 128 | 136 | // Everything above this point must be set before calling |
| 129 | 137 | // ff_vaapi_encode_init(). |
| 130 | 138 | |
| @@ -224,6 +232,12 @@ typedef struct VAAPIEncodeContext { · 93 unmodified lines | ||
| 224 | 232 | int64_t dts_pts_diff; |
| 225 | 233 | int64_t ts_ring[MAX_REORDER_DELAY * 3]; |
| 226 | 234 | |
| 235 | + // Slice structure. | |
| 236 | + int slice_block_rows; | |
| 237 | + int slice_block_cols; | |
| 238 | + int nb_slices; | |
| 239 | + int slice_size; | |
| 240 | + | |
| 227 | 241 | // Frame type decision. |
| 228 | 242 | int gop_size; |
| 229 | 243 | int p_per_i; |
| @@ -234,11 +248,19 @@ typedef struct VAAPIEncodeContext { · 4 unmodified lines | ||
| 234 | 248 | int end_of_stream; |
| 235 | 249 | } VAAPIEncodeContext; |
| 236 | 250 | |
| 251 | +enum { | |
| 252 | + // Codec supports controlling the subdivision of pictures into slices. | |
| 253 | + FLAG_SLICE_CONTROL = 1 << 0, | |
| 254 | +}; | |
| 255 | + | |
| 237 | 256 | typedef struct VAAPIEncodeType { |
| 238 | 257 | // List of supported profiles and corresponding VAAPI profiles. |
| 239 | 258 | // (Must end with FF_PROFILE_UNKNOWN.) |
| 240 | 259 | const VAAPIEncodeProfile *profiles; |
| 241 | 260 | |
| 261 | + // Codec feature flags. | |
| 262 | + int flags; | |
| 263 | + | |
| 242 | 264 | // Perform any extra codec-specific configuration after the |
| 243 | 265 | // codec context is initialised (set up the private data and |
| 244 | 266 | // add any necessary global parameters). |