vaapi_decode.c (25724B)
1 /* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 #include "config_components.h" 20 21 #include "libavutil/avassert.h" 22 #include "libavutil/common.h" 23 #include "libavutil/mem.h" 24 #include "libavutil/pixdesc.h" 25 26 #include "avcodec.h" 27 #include "codec_desc.h" 28 #include "decode.h" 29 #include "internal.h" 30 #include "vaapi_decode.h" 31 #include "vaapi_hevc.h" 32 33 34 int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, 35 VAAPIDecodePicture *pic, 36 int type, 37 const void *data, 38 size_t size) 39 { 40 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; 41 VAStatus vas; 42 43 av_assert0(pic->nb_param_buffers <= pic->nb_param_buffers_allocated); 44 if (pic->nb_param_buffers == pic->nb_param_buffers_allocated) { 45 VABufferID *tmp = 46 av_realloc_array(pic->param_buffers, 47 pic->nb_param_buffers_allocated + 16, 48 sizeof(*pic->param_buffers)); 49 if (!tmp) 50 return AVERROR(ENOMEM); 51 52 pic->param_buffers = tmp; 53 pic->nb_param_buffers_allocated += 16; 54 } 55 av_assert0(pic->nb_param_buffers + 1 <= pic->nb_param_buffers_allocated); 56 57 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, 58 type, size, 1, (void*)data, 59 &pic->param_buffers[pic->nb_param_buffers]); 60 if (vas != VA_STATUS_SUCCESS) { 61 av_log(avctx, AV_LOG_ERROR, "Failed to create parameter " 62 "buffer (type %d): %d (%s).\n", 63 type, vas, vaErrorStr(vas)); 64 return AVERROR(EIO); 65 } 66 67 av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) " 68 "is %#x.\n", type, size, pic->param_buffers[pic->nb_param_buffers]); 69 70 ++pic->nb_param_buffers; 71 72 return 0; 73 } 74 75 int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, 76 VAAPIDecodePicture *pic, 77 const void *params_data, 78 int nb_params, 79 size_t params_size, 80 const void *slice_data, 81 size_t slice_size) 82 { 83 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; 84 VAStatus vas; 85 int index; 86 87 av_assert0(pic->nb_slices <= pic->nb_slice_buffers_allocated); 88 if (pic->nb_slices == pic->nb_slice_buffers_allocated) { 89 VABufferID *tmp = 90 av_realloc_array(pic->slice_buffers, 91 pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64, 92 2 * sizeof(*pic->slice_buffers)); 93 if (!tmp) 94 return AVERROR(ENOMEM); 95 96 pic->slice_buffers = tmp; 97 pic->nb_slice_buffers_allocated = pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64; 98 } 99 av_assert0(pic->nb_slices + 1 <= pic->nb_slice_buffers_allocated); 100 101 index = 2 * pic->nb_slices; 102 103 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, 104 VASliceParameterBufferType, 105 params_size, nb_params, (void*)params_data, 106 &pic->slice_buffers[index]); 107 if (vas != VA_STATUS_SUCCESS) { 108 av_log(avctx, AV_LOG_ERROR, "Failed to create slice " 109 "parameter buffer: %d (%s).\n", vas, vaErrorStr(vas)); 110 return AVERROR(EIO); 111 } 112 113 av_log(avctx, AV_LOG_DEBUG, "Slice %d param buffer (%zu bytes) " 114 "is %#x.\n", pic->nb_slices, params_size, 115 pic->slice_buffers[index]); 116 117 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, 118 VASliceDataBufferType, 119 slice_size, 1, (void*)slice_data, 120 &pic->slice_buffers[index + 1]); 121 if (vas != VA_STATUS_SUCCESS) { 122 av_log(avctx, AV_LOG_ERROR, "Failed to create slice " 123 "data buffer (size %zu): %d (%s).\n", 124 slice_size, vas, vaErrorStr(vas)); 125 vaDestroyBuffer(ctx->hwctx->display, 126 pic->slice_buffers[index]); 127 return AVERROR(EIO); 128 } 129 130 av_log(avctx, AV_LOG_DEBUG, "Slice %d data buffer (%zu bytes) " 131 "is %#x.\n", pic->nb_slices, slice_size, 132 pic->slice_buffers[index + 1]); 133 134 ++pic->nb_slices; 135 return 0; 136 } 137 138 static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx, 139 VAAPIDecodePicture *pic) 140 { 141 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; 142 VAStatus vas; 143 int i; 144 145 for (i = 0; i < pic->nb_param_buffers; i++) { 146 vas = vaDestroyBuffer(ctx->hwctx->display, 147 pic->param_buffers[i]); 148 if (vas != VA_STATUS_SUCCESS) { 149 av_log(avctx, AV_LOG_ERROR, "Failed to destroy " 150 "parameter buffer %#x: %d (%s).\n", 151 pic->param_buffers[i], vas, vaErrorStr(vas)); 152 } 153 } 154 155 for (i = 0; i < 2 * pic->nb_slices; i++) { 156 vas = vaDestroyBuffer(ctx->hwctx->display, 157 pic->slice_buffers[i]); 158 if (vas != VA_STATUS_SUCCESS) { 159 av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice " 160 "slice buffer %#x: %d (%s).\n", 161 pic->slice_buffers[i], vas, vaErrorStr(vas)); 162 } 163 } 164 } 165 166 int ff_vaapi_decode_issue(AVCodecContext *avctx, 167 VAAPIDecodePicture *pic) 168 { 169 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; 170 VAStatus vas; 171 int err; 172 173 if (pic->nb_slices <= 0) { 174 err = AVERROR(EINVAL); 175 goto fail; 176 } 177 178 av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n", 179 pic->output_surface); 180 181 vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, 182 pic->output_surface); 183 if (vas != VA_STATUS_SUCCESS) { 184 av_log(avctx, AV_LOG_ERROR, "Failed to begin picture decode " 185 "issue: %d (%s).\n", vas, vaErrorStr(vas)); 186 err = AVERROR(EIO); 187 goto fail_with_picture; 188 } 189 190 vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, 191 pic->param_buffers, pic->nb_param_buffers); 192 if (vas != VA_STATUS_SUCCESS) { 193 av_log(avctx, AV_LOG_ERROR, "Failed to upload decode " 194 "parameters: %d (%s).\n", vas, vaErrorStr(vas)); 195 err = AVERROR(EIO); 196 goto fail_with_picture; 197 } 198 199 vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, 200 pic->slice_buffers, 2 * pic->nb_slices); 201 if (vas != VA_STATUS_SUCCESS) { 202 av_log(avctx, AV_LOG_ERROR, "Failed to upload slices: " 203 "%d (%s).\n", vas, vaErrorStr(vas)); 204 err = AVERROR(EIO); 205 goto fail_with_picture; 206 } 207 208 vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); 209 if (vas != VA_STATUS_SUCCESS) { 210 av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode " 211 "issue: %d (%s).\n", vas, vaErrorStr(vas)); 212 err = AVERROR(EIO); 213 if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks & 214 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) 215 goto fail; 216 else 217 goto fail_at_end; 218 } 219 220 if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks & 221 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) 222 ff_vaapi_decode_destroy_buffers(avctx, pic); 223 224 err = 0; 225 goto exit; 226 227 fail_with_picture: 228 vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); 229 if (vas != VA_STATUS_SUCCESS) { 230 av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode " 231 "after error: %d (%s).\n", vas, vaErrorStr(vas)); 232 } 233 fail: 234 ff_vaapi_decode_destroy_buffers(avctx, pic); 235 fail_at_end: 236 exit: 237 pic->nb_param_buffers = 0; 238 pic->nb_param_buffers_allocated = 0; 239 av_freep(&pic->param_buffers); 240 pic->nb_slices = 0; 241 pic->nb_slice_buffers_allocated = 0; 242 av_freep(&pic->slice_buffers); 243 244 return err; 245 } 246 247 int ff_vaapi_decode_cancel(AVCodecContext *avctx, 248 VAAPIDecodePicture *pic) 249 { 250 ff_vaapi_decode_destroy_buffers(avctx, pic); 251 252 pic->nb_param_buffers = 0; 253 pic->nb_param_buffers_allocated = 0; 254 av_freep(&pic->param_buffers); 255 pic->nb_slices = 0; 256 pic->nb_slice_buffers_allocated = 0; 257 av_freep(&pic->slice_buffers); 258 259 return 0; 260 } 261 262 static const struct { 263 uint32_t fourcc; 264 enum AVPixelFormat pix_fmt; 265 } vaapi_format_map[] = { 266 #define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av } 267 // 4:0:0 268 MAP(Y800, GRAY8), 269 // 4:2:0 270 MAP(NV12, NV12), 271 MAP(YV12, YUV420P), 272 MAP(IYUV, YUV420P), 273 #ifdef VA_FOURCC_I420 274 MAP(I420, YUV420P), 275 #endif 276 MAP(IMC3, YUV420P), 277 // 4:1:1 278 MAP(411P, YUV411P), 279 // 4:2:2 280 MAP(422H, YUV422P), 281 #ifdef VA_FOURCC_YV16 282 MAP(YV16, YUV422P), 283 #endif 284 MAP(YUY2, YUYV422), 285 #ifdef VA_FOURCC_Y210 286 MAP(Y210, Y210), 287 #endif 288 #ifdef VA_FOURCC_Y212 289 MAP(Y212, Y212), 290 #endif 291 // 4:4:0 292 MAP(422V, YUV440P), 293 // 4:4:4 294 MAP(444P, YUV444P), 295 #ifdef VA_FOURCC_XYUV 296 MAP(XYUV, VUYX), 297 #endif 298 #ifdef VA_FOURCC_Y410 299 MAP(Y410, XV30), 300 #endif 301 #ifdef VA_FOURCC_Y412 302 MAP(Y412, XV36), 303 #endif 304 // 4:2:0 10-bit 305 #ifdef VA_FOURCC_P010 306 MAP(P010, P010), 307 #endif 308 #ifdef VA_FOURCC_P012 309 MAP(P012, P012), 310 #endif 311 #ifdef VA_FOURCC_I010 312 MAP(I010, YUV420P10), 313 #endif 314 #undef MAP 315 }; 316 317 static int vaapi_decode_find_best_format(AVCodecContext *avctx, 318 AVHWDeviceContext *device, 319 VAConfigID config_id, 320 AVHWFramesContext *frames) 321 { 322 AVVAAPIDeviceContext *hwctx = device->hwctx; 323 VAStatus vas; 324 VASurfaceAttrib *attr; 325 enum AVPixelFormat source_format, best_format, format; 326 uint32_t best_fourcc, fourcc; 327 int i, j, nb_attr; 328 329 source_format = avctx->sw_pix_fmt; 330 av_assert0(source_format != AV_PIX_FMT_NONE); 331 332 vas = vaQuerySurfaceAttributes(hwctx->display, config_id, 333 NULL, &nb_attr); 334 if (vas != VA_STATUS_SUCCESS) { 335 av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " 336 "%d (%s).\n", vas, vaErrorStr(vas)); 337 return AVERROR(ENOSYS); 338 } 339 340 attr = av_malloc_array(nb_attr, sizeof(*attr)); 341 if (!attr) 342 return AVERROR(ENOMEM); 343 344 vas = vaQuerySurfaceAttributes(hwctx->display, config_id, 345 attr, &nb_attr); 346 if (vas != VA_STATUS_SUCCESS) { 347 av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " 348 "%d (%s).\n", vas, vaErrorStr(vas)); 349 av_freep(&attr); 350 return AVERROR(ENOSYS); 351 } 352 353 best_format = AV_PIX_FMT_NONE; 354 355 for (i = 0; i < nb_attr; i++) { 356 if (attr[i].type != VASurfaceAttribPixelFormat) 357 continue; 358 359 fourcc = attr[i].value.value.i; 360 for (j = 0; j < FF_ARRAY_ELEMS(vaapi_format_map); j++) { 361 if (fourcc == vaapi_format_map[j].fourcc) 362 break; 363 } 364 if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) { 365 av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n", 366 fourcc); 367 continue; 368 } 369 format = vaapi_format_map[j].pix_fmt; 370 av_log(avctx, AV_LOG_DEBUG, "Considering format %#x -> %s.\n", 371 fourcc, av_get_pix_fmt_name(format)); 372 373 best_format = av_find_best_pix_fmt_of_2(format, best_format, 374 source_format, 0, NULL); 375 if (format == best_format) 376 best_fourcc = fourcc; 377 } 378 379 av_freep(&attr); 380 381 if (best_format == AV_PIX_FMT_NONE) { 382 av_log(avctx, AV_LOG_ERROR, "No usable formats for decoding!\n"); 383 return AVERROR(EINVAL); 384 } 385 386 av_log(avctx, AV_LOG_DEBUG, "Picked %s (%#x) as best match for %s.\n", 387 av_get_pix_fmt_name(best_format), best_fourcc, 388 av_get_pix_fmt_name(source_format)); 389 390 frames->sw_format = best_format; 391 if (avctx->internal->hwaccel_priv_data) { 392 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; 393 AVVAAPIFramesContext *avfc = frames->hwctx; 394 395 ctx->pixel_format_attribute = (VASurfaceAttrib) { 396 .type = VASurfaceAttribPixelFormat, 397 .flags = VA_SURFACE_ATTRIB_SETTABLE, 398 .value.type = VAGenericValueTypeInteger, 399 .value.value.i = best_fourcc, 400 }; 401 402 avfc->attributes = &ctx->pixel_format_attribute; 403 avfc->nb_attributes = 1; 404 } 405 406 return 0; 407 } 408 409 static const struct { 410 enum AVCodecID codec_id; 411 int codec_profile; 412 VAProfile va_profile; 413 VAProfile (*profile_parser)(AVCodecContext *avctx); 414 } vaapi_profile_map[] = { 415 #define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, AV_PROFILE_ ## p, VAProfile ## v, __VA_ARGS__ } 416 MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ), 417 MAP(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main ), 418 MAP(H263, UNKNOWN, H263Baseline), 419 MAP(MPEG4, MPEG4_SIMPLE, MPEG4Simple ), 420 MAP(MPEG4, MPEG4_ADVANCED_SIMPLE, 421 MPEG4AdvancedSimple), 422 MAP(MPEG4, MPEG4_MAIN, MPEG4Main ), 423 #if VA_CHECK_VERSION(1, 18, 0) 424 MAP(H264, H264_HIGH_10_INTRA, 425 H264High10 ), 426 MAP(H264, H264_HIGH_10, H264High10 ), 427 #endif 428 MAP(H264, H264_CONSTRAINED_BASELINE, 429 H264ConstrainedBaseline), 430 MAP(H264, H264_MAIN, H264Main ), 431 MAP(H264, H264_HIGH, H264High ), 432 #if VA_CHECK_VERSION(0, 37, 0) 433 MAP(HEVC, HEVC_MAIN, HEVCMain ), 434 MAP(HEVC, HEVC_MAIN_10, HEVCMain10 ), 435 MAP(HEVC, HEVC_MAIN_STILL_PICTURE, 436 HEVCMain ), 437 #endif 438 #if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL 439 MAP(HEVC, HEVC_REXT, None, 440 ff_vaapi_parse_hevc_rext_scc_profile ), 441 MAP(HEVC, HEVC_SCC, None, 442 ff_vaapi_parse_hevc_rext_scc_profile ), 443 #endif 444 MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT, 445 JPEGBaseline), 446 MAP(WMV3, VC1_SIMPLE, VC1Simple ), 447 MAP(WMV3, VC1_MAIN, VC1Main ), 448 MAP(WMV3, VC1_COMPLEX, VC1Advanced ), 449 MAP(WMV3, VC1_ADVANCED, VC1Advanced ), 450 MAP(VC1, VC1_SIMPLE, VC1Simple ), 451 MAP(VC1, VC1_MAIN, VC1Main ), 452 MAP(VC1, VC1_COMPLEX, VC1Advanced ), 453 MAP(VC1, VC1_ADVANCED, VC1Advanced ), 454 MAP(VP8, UNKNOWN, VP8Version0_3 ), 455 #if VA_CHECK_VERSION(0, 38, 0) 456 MAP(VP9, VP9_0, VP9Profile0 ), 457 #endif 458 #if VA_CHECK_VERSION(0, 39, 0) 459 MAP(VP9, VP9_1, VP9Profile1 ), 460 MAP(VP9, VP9_2, VP9Profile2 ), 461 MAP(VP9, VP9_3, VP9Profile3 ), 462 #endif 463 #if VA_CHECK_VERSION(1, 8, 0) 464 MAP(AV1, AV1_MAIN, AV1Profile0), 465 MAP(AV1, AV1_HIGH, AV1Profile1), 466 #endif 467 #if VA_CHECK_VERSION(1, 22, 0) 468 MAP(H266, VVC_MAIN_10, VVCMain10), 469 #endif 470 471 #undef MAP 472 }; 473 474 /* 475 * Set *va_config and the frames_ref fields from the current codec parameters 476 * in avctx. 477 */ 478 static int vaapi_decode_make_config(AVCodecContext *avctx, 479 AVBufferRef *device_ref, 480 VAConfigID *va_config, 481 AVBufferRef *frames_ref) 482 { 483 AVVAAPIHWConfig *hwconfig = NULL; 484 AVHWFramesConstraints *constraints = NULL; 485 VAStatus vas; 486 int err, i, j; 487 const AVCodecDescriptor *codec_desc; 488 VAProfile *profile_list = NULL, matched_va_profile, va_profile; 489 int profile_count, exact_match, matched_ff_profile, codec_profile; 490 491 AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data; 492 AVVAAPIDeviceContext *hwctx = device->hwctx; 493 494 codec_desc = avcodec_descriptor_get(avctx->codec_id); 495 if (!codec_desc) { 496 err = AVERROR(EINVAL); 497 goto fail; 498 } 499 500 profile_count = vaMaxNumProfiles(hwctx->display); 501 profile_list = av_malloc_array(profile_count, 502 sizeof(VAProfile)); 503 if (!profile_list) { 504 err = AVERROR(ENOMEM); 505 goto fail; 506 } 507 508 vas = vaQueryConfigProfiles(hwctx->display, 509 profile_list, &profile_count); 510 if (vas != VA_STATUS_SUCCESS) { 511 av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: " 512 "%d (%s).\n", vas, vaErrorStr(vas)); 513 err = AVERROR(ENOSYS); 514 goto fail; 515 } 516 517 matched_va_profile = VAProfileNone; 518 exact_match = 0; 519 520 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) { 521 int profile_match = 0; 522 if (avctx->codec_id != vaapi_profile_map[i].codec_id) 523 continue; 524 if (avctx->profile == vaapi_profile_map[i].codec_profile || 525 vaapi_profile_map[i].codec_profile == AV_PROFILE_UNKNOWN) 526 profile_match = 1; 527 528 va_profile = vaapi_profile_map[i].profile_parser ? 529 vaapi_profile_map[i].profile_parser(avctx) : 530 vaapi_profile_map[i].va_profile; 531 codec_profile = vaapi_profile_map[i].codec_profile; 532 533 for (j = 0; j < profile_count; j++) { 534 if (va_profile == profile_list[j]) { 535 exact_match = profile_match; 536 break; 537 } 538 } 539 if (j < profile_count) { 540 matched_va_profile = va_profile; 541 matched_ff_profile = codec_profile; 542 if (exact_match) 543 break; 544 } 545 } 546 av_freep(&profile_list); 547 548 if (matched_va_profile == VAProfileNone) { 549 av_log(avctx, AV_LOG_ERROR, "No support for codec %s " 550 "profile %d.\n", codec_desc->name, avctx->profile); 551 err = AVERROR(ENOSYS); 552 goto fail; 553 } 554 if (!exact_match) { 555 if (avctx->hwaccel_flags & 556 AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) { 557 av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " 558 "supported for hardware decode.\n", 559 codec_desc->name, avctx->profile); 560 av_log(avctx, AV_LOG_WARNING, "Using possibly-" 561 "incompatible profile %d instead.\n", 562 matched_ff_profile); 563 } else { 564 av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " 565 "supported for hardware decode.\n", 566 codec_desc->name, avctx->profile); 567 err = AVERROR(EINVAL); 568 goto fail; 569 } 570 } 571 572 vas = vaCreateConfig(hwctx->display, matched_va_profile, 573 VAEntrypointVLD, NULL, 0, 574 va_config); 575 if (vas != VA_STATUS_SUCCESS) { 576 av_log(avctx, AV_LOG_ERROR, "Failed to create decode " 577 "configuration: %d (%s).\n", vas, vaErrorStr(vas)); 578 err = AVERROR(EIO); 579 goto fail; 580 } 581 582 hwconfig = av_hwdevice_hwconfig_alloc(device_ref); 583 if (!hwconfig) { 584 err = AVERROR(ENOMEM); 585 goto fail; 586 } 587 hwconfig->config_id = *va_config; 588 589 constraints = 590 av_hwdevice_get_hwframe_constraints(device_ref, hwconfig); 591 if (!constraints) { 592 err = AVERROR(ENOMEM); 593 goto fail; 594 } 595 596 if (avctx->coded_width < constraints->min_width || 597 avctx->coded_height < constraints->min_height || 598 avctx->coded_width > constraints->max_width || 599 avctx->coded_height > constraints->max_height) { 600 av_log(avctx, AV_LOG_ERROR, "Hardware does not support image " 601 "size %dx%d (constraints: width %d-%d height %d-%d).\n", 602 avctx->coded_width, avctx->coded_height, 603 constraints->min_width, constraints->max_width, 604 constraints->min_height, constraints->max_height); 605 err = AVERROR(EINVAL); 606 goto fail; 607 } 608 if (!constraints->valid_sw_formats || 609 constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) { 610 av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any " 611 "usable surface formats.\n"); 612 err = AVERROR(EINVAL); 613 goto fail; 614 } 615 616 if (frames_ref) { 617 AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data; 618 619 frames->format = AV_PIX_FMT_VAAPI; 620 frames->width = avctx->coded_width; 621 frames->height = avctx->coded_height; 622 623 err = vaapi_decode_find_best_format(avctx, device, 624 *va_config, frames); 625 if (err < 0) 626 goto fail; 627 628 if (CONFIG_VAAPI_1) 629 frames->initial_pool_size = 0; 630 else { 631 frames->initial_pool_size = 1; 632 // Add per-codec number of surfaces used for storing reference frames. 633 switch (avctx->codec_id) { 634 case AV_CODEC_ID_H264: 635 case AV_CODEC_ID_H266: 636 case AV_CODEC_ID_HEVC: 637 case AV_CODEC_ID_AV1: 638 frames->initial_pool_size += 16; 639 break; 640 case AV_CODEC_ID_VP9: 641 frames->initial_pool_size += 8; 642 break; 643 case AV_CODEC_ID_VP8: 644 frames->initial_pool_size += 3; 645 break; 646 default: 647 frames->initial_pool_size += 2; 648 } 649 } 650 } 651 652 av_hwframe_constraints_free(&constraints); 653 av_freep(&hwconfig); 654 655 return 0; 656 657 fail: 658 av_hwframe_constraints_free(&constraints); 659 av_freep(&hwconfig); 660 if (*va_config != VA_INVALID_ID) { 661 vaDestroyConfig(hwctx->display, *va_config); 662 *va_config = VA_INVALID_ID; 663 } 664 av_freep(&profile_list); 665 return err; 666 } 667 668 int ff_vaapi_common_frame_params(AVCodecContext *avctx, 669 AVBufferRef *hw_frames_ctx) 670 { 671 AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data; 672 AVHWDeviceContext *device_ctx = hw_frames->device_ctx; 673 AVVAAPIDeviceContext *hwctx; 674 VAConfigID va_config = VA_INVALID_ID; 675 int err; 676 677 if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI) 678 return AVERROR(EINVAL); 679 hwctx = device_ctx->hwctx; 680 681 err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config, 682 hw_frames_ctx); 683 if (err) 684 return err; 685 686 if (va_config != VA_INVALID_ID) 687 vaDestroyConfig(hwctx->display, va_config); 688 689 return 0; 690 } 691 692 int ff_vaapi_decode_init(AVCodecContext *avctx) 693 { 694 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; 695 VAStatus vas; 696 int err; 697 698 ctx->va_config = VA_INVALID_ID; 699 ctx->va_context = VA_INVALID_ID; 700 701 err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI); 702 if (err < 0) 703 goto fail; 704 705 ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; 706 ctx->hwfc = ctx->frames->hwctx; 707 ctx->device = ctx->frames->device_ctx; 708 ctx->hwctx = ctx->device->hwctx; 709 710 err = vaapi_decode_make_config(avctx, ctx->frames->device_ref, 711 &ctx->va_config, NULL); 712 if (err) 713 goto fail; 714 715 vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, 716 avctx->coded_width, avctx->coded_height, 717 VA_PROGRESSIVE, 718 ctx->hwfc->surface_ids, 719 ctx->hwfc->nb_surfaces, 720 &ctx->va_context); 721 if (vas != VA_STATUS_SUCCESS) { 722 av_log(avctx, AV_LOG_ERROR, "Failed to create decode " 723 "context: %d (%s).\n", vas, vaErrorStr(vas)); 724 err = AVERROR(EIO); 725 goto fail; 726 } 727 728 av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: " 729 "%#x/%#x.\n", ctx->va_config, ctx->va_context); 730 731 return 0; 732 733 fail: 734 ff_vaapi_decode_uninit(avctx); 735 return err; 736 } 737 738 int ff_vaapi_decode_uninit(AVCodecContext *avctx) 739 { 740 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; 741 VAStatus vas; 742 743 if (ctx->va_context != VA_INVALID_ID) { 744 vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context); 745 if (vas != VA_STATUS_SUCCESS) { 746 av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode " 747 "context %#x: %d (%s).\n", 748 ctx->va_context, vas, vaErrorStr(vas)); 749 } 750 } 751 if (ctx->va_config != VA_INVALID_ID) { 752 vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config); 753 if (vas != VA_STATUS_SUCCESS) { 754 av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode " 755 "configuration %#x: %d (%s).\n", 756 ctx->va_config, vas, vaErrorStr(vas)); 757 } 758 } 759 760 return 0; 761 }