Wrap current whole-row slice codes into following functions: - vaapi_encode_make_row_slice() - vaapi_encode_init_row_slice_structure()
Showing the changes to libavcodec/vaapi_encode.c (1 of 1 file). Show all
Unified · Split
| @@ -163,6 +163,61 @@ static int vaapi_encode_wait(AVCodecContext *avctx, · 162 unmodified lines | ||
| 163 | 163 | return 0; |
| 164 | 164 | } |
| 165 | 165 | |
| 166 | +static int vaapi_encode_make_row_slice(AVCodecContext *avctx, | |
| 167 | + VAAPIEncodePicture *pic) | |
| 168 | +{ | |
| 169 | + VAAPIEncodeContext *ctx = avctx->priv_data; | |
| 170 | + VAAPIEncodeSlice *slice; | |
| 171 | + int i, rounding; | |
| 172 | + | |
| 173 | + for (i = 0; i < pic->nb_slices; i++) | |
| 174 | + pic->slices[i].row_size = ctx->slice_size; | |
| 175 | + | |
| 176 | + rounding = ctx->slice_block_rows - ctx->nb_slices * ctx->slice_size; | |
| 177 | + if (rounding > 0) { | |
| 178 | + // Place rounding error at top and bottom of frame. | |
| 179 | + av_assert0(rounding < pic->nb_slices); | |
| 180 | + // Some Intel drivers contain a bug where the encoder will fail | |
| 181 | + // if the last slice is smaller than the one before it. Since | |
| 182 | + // that's straightforward to avoid here, just do so. | |
| 183 | + if (rounding <= 2) { | |
| 184 | + for (i = 0; i < rounding; i++) | |
| 185 | + ++pic->slices[i].row_size; | |
| 186 | + } else { | |
| 187 | + for (i = 0; i < (rounding + 1) / 2; i++) | |
| 188 | + ++pic->slices[pic->nb_slices - i - 1].row_size; | |
| 189 | + for (i = 0; i < rounding / 2; i++) | |
| 190 | + ++pic->slices[i].row_size; | |
| 191 | + } | |
| 192 | + } else if (rounding < 0) { | |
| 193 | + // Remove rounding error from last slice only. | |
| 194 | + av_assert0(rounding < ctx->slice_size); | |
| 195 | + pic->slices[pic->nb_slices - 1].row_size += rounding; | |
| 196 | + } | |
| 197 | + | |
| 198 | + for (i = 0; i < pic->nb_slices; i++) { | |
| 199 | + slice = &pic->slices[i]; | |
| 200 | + slice->index = i; | |
| 201 | + if (i == 0) { | |
| 202 | + slice->row_start = 0; | |
| 203 | + slice->block_start = 0; | |
| 204 | + } else { | |
| 205 | + const VAAPIEncodeSlice *prev = &pic->slices[i - 1]; | |
| 206 | + slice->row_start = prev->row_start + prev->row_size; | |
| 207 | + slice->block_start = prev->block_start + prev->block_size; | |
| 208 | + } | |
| 209 | + slice->block_size = slice->row_size * ctx->slice_block_cols; | |
| 210 | + | |
| 211 | + av_log(avctx, AV_LOG_DEBUG, "Slice %d: %d-%d (%d rows), " | |
| 212 | + "%d-%d (%d blocks).\n", i, slice->row_start, | |
| 213 | + slice->row_start + slice->row_size - 1, slice->row_size, | |
| 214 | + slice->block_start, slice->block_start + slice->block_size - 1, | |
| 215 | + slice->block_size); | |
| 216 | + } | |
| 217 | + | |
| 218 | + return 0; | |
| 219 | +} | |
| 220 | + | |
| 166 | 221 | static int vaapi_encode_issue(AVCodecContext *avctx, |
| 167 | 222 | VAAPIEncodePicture *pic) |
| 168 | 223 | { |
| @@ -346,57 +401,17 @@ static int vaapi_encode_issue(AVCodecContext *avctx, · 177 unmodified lines | ||
| 346 | 401 | if (pic->nb_slices == 0) |
| 347 | 402 | pic->nb_slices = ctx->nb_slices; |
| 348 | 403 | if (pic->nb_slices > 0) { |
| 349 | − int rounding; | |
| 350 | − | |
| 351 | 404 | pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); |
| 352 | 405 | if (!pic->slices) { |
| 353 | 406 | err = AVERROR(ENOMEM); |
| 354 | 407 | goto fail; |
| 355 | 408 | } |
| 356 | 409 | |
| 357 | − for (i = 0; i < pic->nb_slices; i++) | |
| 358 | − pic->slices[i].row_size = ctx->slice_size; | |
| 359 | − | |
| 360 | − rounding = ctx->slice_block_rows - ctx->nb_slices * ctx->slice_size; | |
| 361 | − if (rounding > 0) { | |
| 362 | − // Place rounding error at top and bottom of frame. | |
| 363 | − av_assert0(rounding < pic->nb_slices); | |
| 364 | − // Some Intel drivers contain a bug where the encoder will fail | |
| 365 | − // if the last slice is smaller than the one before it. Since | |
| 366 | − // that's straightforward to avoid here, just do so. | |
| 367 | − if (rounding <= 2) { | |
| 368 | − for (i = 0; i < rounding; i++) | |
| 369 | − ++pic->slices[i].row_size; | |
| 370 | − } else { | |
| 371 | − for (i = 0; i < (rounding + 1) / 2; i++) | |
| 372 | − ++pic->slices[pic->nb_slices - i - 1].row_size; | |
| 373 | − for (i = 0; i < rounding / 2; i++) | |
| 374 | − ++pic->slices[i].row_size; | |
| 375 | − } | |
| 376 | − } else if (rounding < 0) { | |
| 377 | − // Remove rounding error from last slice only. | |
| 378 | − av_assert0(rounding < ctx->slice_size); | |
| 379 | − pic->slices[pic->nb_slices - 1].row_size += rounding; | |
| 380 | − } | |
| 410 | + vaapi_encode_make_row_slice(avctx, pic); | |
| 381 | 411 | } |
| 412 | + | |
| 382 | 413 | for (i = 0; i < pic->nb_slices; i++) { |
| 383 | 414 | slice = &pic->slices[i]; |
| 384 | − slice->index = i; | |
| 385 | − if (i == 0) { | |
| 386 | − slice->row_start = 0; | |
| 387 | − slice->block_start = 0; | |
| 388 | − } else { | |
| 389 | − const VAAPIEncodeSlice *prev = &pic->slices[i - 1]; | |
| 390 | − slice->row_start = prev->row_start + prev->row_size; | |
| 391 | − slice->block_start = prev->block_start + prev->block_size; | |
| 392 | − } | |
| 393 | − slice->block_size = slice->row_size * ctx->slice_block_cols; | |
| 394 | − | |
| 395 | − av_log(avctx, AV_LOG_DEBUG, "Slice %d: %d-%d (%d rows), " | |
| 396 | − "%d-%d (%d blocks).\n", i, slice->row_start, | |
| 397 | − slice->row_start + slice->row_size - 1, slice->row_size, | |
| 398 | − slice->block_start, slice->block_start + slice->block_size - 1, | |
| 399 | − slice->block_size); | |
| 400 | 415 | |
| 401 | 416 | if (ctx->codec->slice_params_size > 0) { |
| 402 | 417 | slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); |
| @@ -1840,6 +1855,54 @@ static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) · 1437 unmodified lines | ||
| 1840 | 1855 | return 0; |
| 1841 | 1856 | } |
| 1842 | 1857 | |
| 1858 | +static av_cold int vaapi_encode_init_row_slice_structure(AVCodecContext *avctx, | |
| 1859 | + uint32_t slice_structure) | |
| 1860 | +{ | |
| 1861 | + VAAPIEncodeContext *ctx = avctx->priv_data; | |
| 1862 | + int req_slices; | |
| 1863 | + | |
| 1864 | + // For fixed-size slices currently we only support whole rows, making | |
| 1865 | + // rectangular slices. This could be extended to arbitrary runs of | |
| 1866 | + // blocks, but since slices tend to be a conformance requirement and | |
| 1867 | + // most cases (such as broadcast or bluray) want rectangular slices | |
| 1868 | + // only it would need to be gated behind another option. | |
| 1869 | + if (avctx->slices > ctx->slice_block_rows) { | |
| 1870 | + av_log(avctx, AV_LOG_WARNING, "Not enough rows to use " | |
| 1871 | + "configured number of slices (%d < %d); using " | |
| 1872 | + "maximum.\n", ctx->slice_block_rows, avctx->slices); | |
| 1873 | + req_slices = ctx->slice_block_rows; | |
| 1874 | + } else { | |
| 1875 | + req_slices = avctx->slices; | |
| 1876 | + } | |
| 1877 | + if (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS || | |
| 1878 | +#if VA_CHECK_VERSION(1, 8, 0) | |
| 1879 | + slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_MULTI_ROWS || | |
| 1880 | +#endif | |
| 1881 | + slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) { | |
| 1882 | + ctx->nb_slices = req_slices; | |
| 1883 | + ctx->slice_size = ctx->slice_block_rows / ctx->nb_slices; | |
| 1884 | + } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) { | |
| 1885 | + int k; | |
| 1886 | + for (k = 1;; k *= 2) { | |
| 1887 | + if (2 * k * (req_slices - 1) + 1 >= ctx->slice_block_rows) | |
| 1888 | + break; | |
| 1889 | + } | |
| 1890 | + ctx->nb_slices = (ctx->slice_block_rows + k - 1) / k; | |
| 1891 | + ctx->slice_size = k; | |
| 1892 | +#if VA_CHECK_VERSION(1, 0, 0) | |
| 1893 | + } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS) { | |
| 1894 | + ctx->nb_slices = ctx->slice_block_rows; | |
| 1895 | + ctx->slice_size = 1; | |
| 1896 | +#endif | |
| 1897 | + } else { | |
| 1898 | + av_log(avctx, AV_LOG_ERROR, "Driver does not support any usable " | |
| 1899 | + "slice structure modes (%#x).\n", slice_structure); | |
| 1900 | + return AVERROR(EINVAL); | |
| 1901 | + } | |
| 1902 | + | |
| 1903 | + return 0; | |
| 1904 | +} | |
| 1905 | + | |
| 1843 | 1906 | static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) |
| 1844 | 1907 | { |
| 1845 | 1908 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| @@ -1847,7 +1910,7 @@ static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) · 1 unmodified line | ||
| 1847 | 1910 | { VAConfigAttribEncSliceStructure } }; |
| 1848 | 1911 | VAStatus vas; |
| 1849 | 1912 | uint32_t max_slices, slice_structure; |
| 1850 | − int req_slices; | |
| 1913 | + int ret; | |
| 1851 | 1914 | |
| 1852 | 1915 | if (!(ctx->codec->flags & FLAG_SLICE_CONTROL)) { |
| 1853 | 1916 | if (avctx->slices > 0) { |
| @@ -1886,44 +1949,9 @@ static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) · 32 unmodified lines | ||
| 1886 | 1949 | return AVERROR(EINVAL); |
| 1887 | 1950 | } |
| 1888 | 1951 | |
| 1889 | − // For fixed-size slices currently we only support whole rows, making | |
| 1890 | − // rectangular slices. This could be extended to arbitrary runs of | |
| 1891 | − // blocks, but since slices tend to be a conformance requirement and | |
| 1892 | − // most cases (such as broadcast or bluray) want rectangular slices | |
| 1893 | − // only it would need to be gated behind another option. | |
| 1894 | − if (avctx->slices > ctx->slice_block_rows) { | |
| 1895 | − av_log(avctx, AV_LOG_WARNING, "Not enough rows to use " | |
| 1896 | − "configured number of slices (%d < %d); using " | |
| 1897 | − "maximum.\n", ctx->slice_block_rows, avctx->slices); | |
| 1898 | − req_slices = ctx->slice_block_rows; | |
| 1899 | − } else { | |
| 1900 | − req_slices = avctx->slices; | |
| 1901 | − } | |
| 1902 | − if (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS || | |
| 1903 | −#if VA_CHECK_VERSION(1, 8, 0) | |
| 1904 | − slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_MULTI_ROWS || | |
| 1905 | −#endif | |
| 1906 | − slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) { | |
| 1907 | − ctx->nb_slices = req_slices; | |
| 1908 | − ctx->slice_size = ctx->slice_block_rows / ctx->nb_slices; | |
| 1909 | − } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) { | |
| 1910 | − int k; | |
| 1911 | − for (k = 1;; k *= 2) { | |
| 1912 | − if (2 * k * (req_slices - 1) + 1 >= ctx->slice_block_rows) | |
| 1913 | − break; | |
| 1914 | − } | |
| 1915 | − ctx->nb_slices = (ctx->slice_block_rows + k - 1) / k; | |
| 1916 | − ctx->slice_size = k; | |
| 1917 | −#if VA_CHECK_VERSION(1, 0, 0) | |
| 1918 | − } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS) { | |
| 1919 | − ctx->nb_slices = ctx->slice_block_rows; | |
| 1920 | − ctx->slice_size = 1; | |
| 1921 | −#endif | |
| 1922 | − } else { | |
| 1923 | − av_log(avctx, AV_LOG_ERROR, "Driver does not support any usable " | |
| 1924 | − "slice structure modes (%#x).\n", slice_structure); | |
| 1925 | − return AVERROR(EINVAL); | |
| 1926 | − } | |
| 1952 | + ret = vaapi_encode_init_row_slice_structure(avctx, slice_structure); | |
| 1953 | + if (ret < 0) | |
| 1954 | + return ret; | |
| 1927 | 1955 | |
| 1928 | 1956 | if (ctx->nb_slices > avctx->slices) { |
| 1929 | 1957 | av_log(avctx, AV_LOG_WARNING, "Slice count rounded up to " |