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 | return 0; | 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 | static int vaapi_encode_issue(AVCodecContext *avctx, | 221 | static int vaapi_encode_issue(AVCodecContext *avctx, |
| 167 | VAAPIEncodePicture *pic) | 222 | VAAPIEncodePicture *pic) |
| 168 | { | 223 | { |
| @@ -346,57 +401,17 @@ static int vaapi_encode_issue(AVCodecContext *avctx, · 177 unmodified lines | |||
| 346 | if (pic->nb_slices == 0) | 401 | if (pic->nb_slices == 0) |
| 347 | pic->nb_slices = ctx->nb_slices; | 402 | pic->nb_slices = ctx->nb_slices; |
| 348 | if (pic->nb_slices > 0) { | 403 | if (pic->nb_slices > 0) { |
| 349 | int rounding; | ||
| 350 | |||
| 351 | pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); | 404 | pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); |
| 352 | if (!pic->slices) { | 405 | if (!pic->slices) { |
| 353 | err = AVERROR(ENOMEM); | 406 | err = AVERROR(ENOMEM); |
| 354 | goto fail; | 407 | goto fail; |
| 355 | } | 408 | } |
| 356 | 409 | ||
| 357 | for (i = 0; i < pic->nb_slices; i++) | 410 | vaapi_encode_make_row_slice(avctx, pic); |
| 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 | } | ||
| 381 | } | 411 | } |
| 412 | |||
| 382 | for (i = 0; i < pic->nb_slices; i++) { | 413 | for (i = 0; i < pic->nb_slices; i++) { |
| 383 | slice = &pic->slices[i]; | 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 | if (ctx->codec->slice_params_size > 0) { | 416 | if (ctx->codec->slice_params_size > 0) { |
| 402 | slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); | 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 | return 0; | 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 | static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) | 1906 | static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) |
| 1844 | { | 1907 | { |
| 1845 | VAAPIEncodeContext *ctx = avctx->priv_data; | 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 | { VAConfigAttribEncSliceStructure } }; | 1910 | { VAConfigAttribEncSliceStructure } }; |
| 1848 | VAStatus vas; | 1911 | VAStatus vas; |
| 1849 | uint32_t max_slices, slice_structure; | 1912 | uint32_t max_slices, slice_structure; |
| 1850 | int req_slices; | 1913 | int ret; |
| 1851 | 1914 | ||
| 1852 | if (!(ctx->codec->flags & FLAG_SLICE_CONTROL)) { | 1915 | if (!(ctx->codec->flags & FLAG_SLICE_CONTROL)) { |
| 1853 | if (avctx->slices > 0) { | 1916 | if (avctx->slices > 0) { |
| @@ -1886,44 +1949,9 @@ static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) · 32 unmodified lines | |||
| 1886 | return AVERROR(EINVAL); | 1949 | return AVERROR(EINVAL); |
| 1887 | } | 1950 | } |
| 1888 | 1951 | ||
| 1889 | // For fixed-size slices currently we only support whole rows, making | 1952 | ret = vaapi_encode_init_row_slice_structure(avctx, slice_structure); |
| 1890 | // rectangular slices. This could be extended to arbitrary runs of | 1953 | if (ret < 0) |
| 1891 | // blocks, but since slices tend to be a conformance requirement and | 1954 | return ret; |
| 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 | } | ||
| 1927 | 1955 | ||
| 1928 | if (ctx->nb_slices > avctx->slices) { | 1956 | if (ctx->nb_slices > avctx->slices) { |
| 1929 | av_log(avctx, AV_LOG_WARNING, "Slice count rounded up to " | 1957 | av_log(avctx, AV_LOG_WARNING, "Slice count rounded up to " |