History

vaapi_encode: Support configurable slices

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.

Mark Thompson committed 8 years ago

Commit 2923ed21 parent 40ac6223 files · +172 −0Browse files

Showing the changes to libavcodec/vaapi_encode.c (1 of 3 files). Show all

Unified · Split

libavcodec/vaapi_encode.c+148−0
@@ -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
1491static 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
1447static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx)1591static 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;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t