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

Unified · Split

3 files
  1. doc/encoders.texi +2 −0
  2. libavcodec/vaapi_encode.c +148 −0
  3. libavcodec/vaapi_encode.h +22 −0
doc/encoders.texi+2−0
@@ -2598,6 +2598,8 @@ Size / quality tradeoff: higher values are smaller / worse quality. · 2597 unmodified lines
25982598 @option{b_qfactor} / @option{b_quant_factor}
25992599 @item
26002600 @option{b_qoffset} / @option{b_quant_offset}
2601+@item
2602+@option{slices}
26012603 @end itemize
26022604
26032605 All encoders support the following options:
libavcodec/vaapi_encode.c+148−0
@@ -319,16 +319,60 @@ static int vaapi_encode_issue(AVCodecContext *avctx, · 318 unmodified lines
319319 }
320320 }
321321
322+ if (pic->nb_slices == 0)
323+ pic->nb_slices = ctx->nb_slices;
322324 if (pic->nb_slices > 0) {
325+ int rounding;
326+
323327 pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices));
324328 if (!pic->slices) {
325329 err = AVERROR(ENOMEM);
326330 goto fail;
327331 }
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+ }
328357 }
329358 for (i = 0; i < pic->nb_slices; i++) {
330359 slice = &pic->slices[i];
331360 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);
332376
333377 if (ctx->codec->slice_params_size > 0) {
334378 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
14441488 return 0;
14451489 }
14461490
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+
14471591 static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx)
14481592 {
14491593 VAAPIEncodeContext *ctx = avctx->priv_data;
@@ -1734,6 +1878,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) · 284 unmodified lines
17341878 if (err < 0)
17351879 goto fail;
17361880
1881+ err = vaapi_encode_init_slice_structure(avctx);
1882+ if (err < 0)
1883+ goto fail;
1884+
17371885 err = vaapi_encode_init_packed_headers(avctx);
17381886 if (err < 0)
17391887 goto fail;
libavcodec/vaapi_encode.h+22−0
@@ -52,6 +52,10 @@ enum { · 51 unmodified lines
5252
5353 typedef struct VAAPIEncodeSlice {
5454 int index;
55+ int row_start;
56+ int row_size;
57+ int block_start;
58+ int block_size;
5559 void *priv_data;
5660 void *codec_slice_params;
5761 } VAAPIEncodeSlice;
@@ -125,6 +129,10 @@ typedef struct VAAPIEncodeContext { · 67 unmodified lines
125129 int surface_width;
126130 int surface_height;
127131
132+ // The block size for slice calculations.
133+ int slice_block_width;
134+ int slice_block_height;
135+
128136 // Everything above this point must be set before calling
129137 // ff_vaapi_encode_init().
130138
@@ -224,6 +232,12 @@ typedef struct VAAPIEncodeContext { · 93 unmodified lines
224232 int64_t dts_pts_diff;
225233 int64_t ts_ring[MAX_REORDER_DELAY * 3];
226234
235+ // Slice structure.
236+ int slice_block_rows;
237+ int slice_block_cols;
238+ int nb_slices;
239+ int slice_size;
240+
227241 // Frame type decision.
228242 int gop_size;
229243 int p_per_i;
@@ -234,11 +248,19 @@ typedef struct VAAPIEncodeContext { · 4 unmodified lines
234248 int end_of_stream;
235249 } VAAPIEncodeContext;
236250
251+enum {
252+ // Codec supports controlling the subdivision of pictures into slices.
253+ FLAG_SLICE_CONTROL = 1 << 0,
254+};
255+
237256 typedef struct VAAPIEncodeType {
238257 // List of supported profiles and corresponding VAAPI profiles.
239258 // (Must end with FF_PROFILE_UNKNOWN.)
240259 const VAAPIEncodeProfile *profiles;
241260
261+ // Codec feature flags.
262+ int flags;
263+
242264 // Perform any extra codec-specific configuration after the
243265 // codec context is initialised (set up the private data and
244266 // add any necessary global parameters).

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