| @@ -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 | if (pic->nb_slices > 0) { | 324 | if (pic->nb_slices > 0) { |
| | 325 | int rounding; |
| | 326 | |
| 323 | pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); | 327 | pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); |
| 324 | if (!pic->slices) { | 328 | if (!pic->slices) { |
| 325 | err = AVERROR(ENOMEM); | 329 | err = AVERROR(ENOMEM); |
| 326 | goto fail; | 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 | for (i = 0; i < pic->nb_slices; i++) { | 358 | for (i = 0; i < pic->nb_slices; i++) { |
| 330 | slice = &pic->slices[i]; | 359 | slice = &pic->slices[i]; |
| 331 | slice->index = i; | 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 | if (ctx->codec->slice_params_size > 0) { | 377 | if (ctx->codec->slice_params_size > 0) { |
| 334 | slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); | 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 | return 0; | 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 | static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx) | 1591 | static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx) |
| 1448 | { | 1592 | { |
| 1449 | VAAPIEncodeContext *ctx = avctx->priv_data; | 1593 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| @@ -1734,6 +1878,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) · 284 unmodified lines |
| 1734 | if (err < 0) | 1878 | if (err < 0) |
| 1735 | goto fail; | 1879 | goto fail; |
| 1736 | | 1880 | |
| | 1881 | err = vaapi_encode_init_slice_structure(avctx); |
| | 1882 | if (err < 0) |
| | 1883 | goto fail; |
| | 1884 | |
| 1737 | err = vaapi_encode_init_packed_headers(avctx); | 1885 | err = vaapi_encode_init_packed_headers(avctx); |
| 1738 | if (err < 0) | 1886 | if (err < 0) |
| 1739 | goto fail; | 1887 | goto fail; |