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.h" 20 21#include "avassert.h" 22#include "buffer.h" 23#include "common.h" 24#include "hwcontext.h" 25#include "hwcontext_internal.h" 26#include "imgutils.h" 27#include "log.h" 28#include "mem.h" 29#include "pixdesc.h" 30#include "pixfmt.h" 31 32static const HWContextType * const hw_table[] = { 33#if CONFIG_CUDA 34 &ff_hwcontext_type_cuda, 35#endif 36#if CONFIG_D3D11VA 37 &ff_hwcontext_type_d3d11va, 38#endif 39#if CONFIG_LIBDRM 40 &ff_hwcontext_type_drm, 41#endif 42#if CONFIG_DXVA2 43 &ff_hwcontext_type_dxva2, 44#endif 45#if CONFIG_OPENCL 46 &ff_hwcontext_type_opencl, 47#endif 48#if CONFIG_QSV 49 &ff_hwcontext_type_qsv, 50#endif 51#if CONFIG_VAAPI 52 &ff_hwcontext_type_vaapi, 53#endif 54#if CONFIG_VDPAU 55 &ff_hwcontext_type_vdpau, 56#endif 57#if CONFIG_VIDEOTOOLBOX 58 &ff_hwcontext_type_videotoolbox, 59#endif 60#if CONFIG_MEDIACODEC 61 &ff_hwcontext_type_mediacodec, 62#endif 63#if CONFIG_VULKAN 64 &ff_hwcontext_type_vulkan, 65#endif 66 NULL, 67}; 68 69static const char *const hw_type_names[] = { 70 [AV_HWDEVICE_TYPE_CUDA] = "cuda", 71 [AV_HWDEVICE_TYPE_DRM] = "drm", 72 [AV_HWDEVICE_TYPE_DXVA2] = "dxva2", 73 [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va", 74 [AV_HWDEVICE_TYPE_OPENCL] = "opencl", 75 [AV_HWDEVICE_TYPE_QSV] = "qsv", 76 [AV_HWDEVICE_TYPE_VAAPI] = "vaapi", 77 [AV_HWDEVICE_TYPE_VDPAU] = "vdpau", 78 [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox", 79 [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec", 80 [AV_HWDEVICE_TYPE_VULKAN] = "vulkan", 81}; 82 83enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name) 84{ 85 int type; 86 for (type = 0; type < FF_ARRAY_ELEMS(hw_type_names); type++) { 87 if (hw_type_names[type] && !strcmp(hw_type_names[type], name)) 88 return type; 89 } 90 return AV_HWDEVICE_TYPE_NONE; 91} 92 93const char *av_hwdevice_get_type_name(enum AVHWDeviceType type) 94{ 95 if (type > AV_HWDEVICE_TYPE_NONE && 96 type < FF_ARRAY_ELEMS(hw_type_names)) 97 return hw_type_names[type]; 98 else 99 return NULL; 100} 101 102enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev) 103{ 104 enum AVHWDeviceType next; 105 int i, set = 0; 106 for (i = 0; hw_table[i]; i++) { 107 if (prev != AV_HWDEVICE_TYPE_NONE && hw_table[i]->type <= prev) 108 continue; 109 if (!set || hw_table[i]->type < next) { 110 next = hw_table[i]->type; 111 set = 1; 112 } 113 } 114 return set ? next : AV_HWDEVICE_TYPE_NONE; 115} 116 117static const AVClass hwdevice_ctx_class = { 118 .class_name = "AVHWDeviceContext", 119 .item_name = av_default_item_name, 120 .version = LIBAVUTIL_VERSION_INT, 121}; 122 123static void hwdevice_ctx_free(void *opaque, uint8_t *data) 124{ 125 AVHWDeviceContext *ctx = (AVHWDeviceContext*)data; 126 127 /* uninit might still want access the hw context and the user 128 * free() callback might destroy it, so uninit has to be called first */ 129 if (ctx->internal->hw_type->device_uninit) 130 ctx->internal->hw_type->device_uninit(ctx); 131 132 if (ctx->free) 133 ctx->free(ctx); 134 135 av_buffer_unref(&ctx->internal->source_device); 136 137 av_freep(&ctx->hwctx); 138 av_freep(&ctx->internal->priv); 139 av_freep(&ctx->internal); 140 av_freep(&ctx); 141} 142 143AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type) 144{ 145 AVHWDeviceContext *ctx; 146 AVBufferRef *buf; 147 const HWContextType *hw_type = NULL; 148 int i; 149 150 for (i = 0; hw_table[i]; i++) { 151 if (hw_table[i]->type == type) { 152 hw_type = hw_table[i]; 153 break; 154 } 155 } 156 if (!hw_type) 157 return NULL; 158 159 ctx = av_mallocz(sizeof(*ctx)); 160 if (!ctx) 161 return NULL; 162 163 ctx->internal = av_mallocz(sizeof(*ctx->internal)); 164 if (!ctx->internal) 165 goto fail; 166 167 if (hw_type->device_priv_size) { 168 ctx->internal->priv = av_mallocz(hw_type->device_priv_size); 169 if (!ctx->internal->priv) 170 goto fail; 171 } 172 173 if (hw_type->device_hwctx_size) { 174 ctx->hwctx = av_mallocz(hw_type->device_hwctx_size); 175 if (!ctx->hwctx) 176 goto fail; 177 } 178 179 buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), 180 hwdevice_ctx_free, NULL, 181 AV_BUFFER_FLAG_READONLY); 182 if (!buf) 183 goto fail; 184 185 ctx->type = type; 186 ctx->av_class = &hwdevice_ctx_class; 187 188 ctx->internal->hw_type = hw_type; 189 190 return buf; 191 192fail: 193 if (ctx->internal) 194 av_freep(&ctx->internal->priv); 195 av_freep(&ctx->internal); 196 av_freep(&ctx->hwctx); 197 av_freep(&ctx); 198 return NULL; 199} 200 201int av_hwdevice_ctx_init(AVBufferRef *ref) 202{ 203 AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; 204 int ret; 205 206 if (ctx->internal->hw_type->device_init) { 207 ret = ctx->internal->hw_type->device_init(ctx); 208 if (ret < 0) 209 goto fail; 210 } 211 212 return 0; 213fail: 214 if (ctx->internal->hw_type->device_uninit) 215 ctx->internal->hw_type->device_uninit(ctx); 216 return ret; 217} 218 219static const AVClass hwframe_ctx_class = { 220 .class_name = "AVHWFramesContext", 221 .item_name = av_default_item_name, 222 .version = LIBAVUTIL_VERSION_INT, 223}; 224 225static void hwframe_ctx_free(void *opaque, uint8_t *data) 226{ 227 AVHWFramesContext *ctx = (AVHWFramesContext*)data; 228 229 if (ctx->internal->pool_internal) 230 av_buffer_pool_uninit(&ctx->internal->pool_internal); 231 232 if (ctx->internal->hw_type->frames_uninit) 233 ctx->internal->hw_type->frames_uninit(ctx); 234 235 if (ctx->free) 236 ctx->free(ctx); 237 238 av_buffer_unref(&ctx->internal->source_frames); 239 240 av_buffer_unref(&ctx->device_ref); 241 242 av_freep(&ctx->hwctx); 243 av_freep(&ctx->internal->priv); 244 av_freep(&ctx->internal); 245 av_freep(&ctx); 246} 247 248AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in) 249{ 250 AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref_in->data; 251 const HWContextType *hw_type = device_ctx->internal->hw_type; 252 AVHWFramesContext *ctx; 253 AVBufferRef *buf, *device_ref = NULL; 254 255 ctx = av_mallocz(sizeof(*ctx)); 256 if (!ctx) 257 return NULL; 258 259 ctx->internal = av_mallocz(sizeof(*ctx->internal)); 260 if (!ctx->internal) 261 goto fail; 262 263 if (hw_type->frames_priv_size) { 264 ctx->internal->priv = av_mallocz(hw_type->frames_priv_size); 265 if (!ctx->internal->priv) 266 goto fail; 267 } 268 269 if (hw_type->frames_hwctx_size) { 270 ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size); 271 if (!ctx->hwctx) 272 goto fail; 273 } 274 275 device_ref = av_buffer_ref(device_ref_in); 276 if (!device_ref) 277 goto fail; 278 279 buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), 280 hwframe_ctx_free, NULL, 281 AV_BUFFER_FLAG_READONLY); 282 if (!buf) 283 goto fail; 284 285 ctx->av_class = &hwframe_ctx_class; 286 ctx->device_ref = device_ref; 287 ctx->device_ctx = device_ctx; 288 ctx->format = AV_PIX_FMT_NONE; 289 ctx->sw_format = AV_PIX_FMT_NONE; 290 291 ctx->internal->hw_type = hw_type; 292 293 return buf; 294 295fail: 296 if (device_ref) 297 av_buffer_unref(&device_ref); 298 if (ctx->internal) 299 av_freep(&ctx->internal->priv); 300 av_freep(&ctx->internal); 301 av_freep(&ctx->hwctx); 302 av_freep(&ctx); 303 return NULL; 304} 305 306static int hwframe_pool_prealloc(AVBufferRef *ref) 307{ 308 AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; 309 AVFrame **frames; 310 int i, ret = 0; 311 312 frames = av_calloc(ctx->initial_pool_size, sizeof(*frames)); 313 if (!frames) 314 return AVERROR(ENOMEM); 315 316 for (i = 0; i < ctx->initial_pool_size; i++) { 317 frames[i] = av_frame_alloc(); 318 if (!frames[i]) 319 goto fail; 320 321 ret = av_hwframe_get_buffer(ref, frames[i], 0); 322 if (ret < 0) 323 goto fail; 324 } 325 326fail: 327 for (i = 0; i < ctx->initial_pool_size; i++) 328 av_frame_free(&frames[i]); 329 av_freep(&frames); 330 331 return ret; 332} 333 334int av_hwframe_ctx_init(AVBufferRef *ref) 335{ 336 AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; 337 const enum AVPixelFormat *pix_fmt; 338 int ret; 339 340 if (ctx->internal->source_frames) { 341 /* A derived frame context is already initialised. */ 342 return 0; 343 } 344 345 /* validate the pixel format */ 346 for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) { 347 if (*pix_fmt == ctx->format) 348 break; 349 } 350 if (*pix_fmt == AV_PIX_FMT_NONE) { 351 av_log(ctx, AV_LOG_ERROR, 352 "The hardware pixel format '%s' is not supported by the device type '%s'\n", 353 av_get_pix_fmt_name(ctx->format), ctx->internal->hw_type->name); 354 return AVERROR(ENOSYS); 355 } 356 357 /* validate the dimensions */ 358 ret = av_image_check_size(ctx->width, ctx->height, 0, ctx); 359 if (ret < 0) 360 return ret; 361 362 /* format-specific init */ 363 if (ctx->internal->hw_type->frames_init) { 364 ret = ctx->internal->hw_type->frames_init(ctx); 365 if (ret < 0) 366 return ret; 367 } 368 369 if (ctx->internal->pool_internal && !ctx->pool) 370 ctx->pool = ctx->internal->pool_internal; 371 372 /* preallocate the frames in the pool, if requested */ 373 if (ctx->initial_pool_size > 0) { 374 ret = hwframe_pool_prealloc(ref); 375 if (ret < 0) 376 return ret; 377 } 378 379 return 0; 380} 381 382int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref, 383 enum AVHWFrameTransferDirection dir, 384 enum AVPixelFormat **formats, int flags) 385{ 386 AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; 387 388 if (!ctx->internal->hw_type->transfer_get_formats) 389 return AVERROR(ENOSYS); 390 391 return ctx->internal->hw_type->transfer_get_formats(ctx, dir, formats); 392} 393 394static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags) 395{ 396 AVHWFramesContext *ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; 397 AVFrame *frame_tmp; 398 int ret = 0; 399 400 frame_tmp = av_frame_alloc(); 401 if (!frame_tmp) 402 return AVERROR(ENOMEM); 403 404 /* if the format is set, use that 405 * otherwise pick the first supported one */ 406 if (dst->format >= 0) { 407 frame_tmp->format = dst->format; 408 } else { 409 enum AVPixelFormat *formats; 410 411 ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx, 412 AV_HWFRAME_TRANSFER_DIRECTION_FROM, 413 &formats, 0); 414 if (ret < 0) 415 goto fail; 416 frame_tmp->format = formats[0]; 417 av_freep(&formats); 418 } 419 frame_tmp->width = ctx->width; 420 frame_tmp->height = ctx->height; 421 422 ret = av_frame_get_buffer(frame_tmp, 0); 423 if (ret < 0) 424 goto fail; 425 426 ret = av_hwframe_transfer_data(frame_tmp, src, flags); 427 if (ret < 0) 428 goto fail; 429 430 frame_tmp->width = src->width; 431 frame_tmp->height = src->height; 432 433 av_frame_move_ref(dst, frame_tmp); 434 435fail: 436 av_frame_free(&frame_tmp); 437 return ret; 438} 439 440int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags) 441{ 442 AVHWFramesContext *ctx; 443 int ret; 444 445 if (!dst->buf[0]) 446 return transfer_data_alloc(dst, src, flags); 447 448 /* 449 * Hardware -> Hardware Transfer. 450 * Unlike Software -> Hardware or Hardware -> Software, the transfer 451 * function could be provided by either the src or dst, depending on 452 * the specific combination of hardware. 453 */ 454 if (src->hw_frames_ctx && dst->hw_frames_ctx) { 455 AVHWFramesContext *src_ctx = 456 (AVHWFramesContext*)src->hw_frames_ctx->data; 457 AVHWFramesContext *dst_ctx = 458 (AVHWFramesContext*)dst->hw_frames_ctx->data; 459 460 if (src_ctx->internal->source_frames) { 461 av_log(src_ctx, AV_LOG_ERROR, 462 "A device with a derived frame context cannot be used as " 463 "the source of a HW -> HW transfer."); 464 return AVERROR(ENOSYS); 465 } 466 467 if (dst_ctx->internal->source_frames) { 468 av_log(src_ctx, AV_LOG_ERROR, 469 "A device with a derived frame context cannot be used as " 470 "the destination of a HW -> HW transfer."); 471 return AVERROR(ENOSYS); 472 } 473 474 ret = src_ctx->internal->hw_type->transfer_data_from(src_ctx, dst, src); 475 if (ret == AVERROR(ENOSYS)) 476 ret = dst_ctx->internal->hw_type->transfer_data_to(dst_ctx, dst, src); 477 if (ret < 0) 478 return ret; 479 } else { 480 if (src->hw_frames_ctx) { 481 ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; 482 483 ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src); 484 if (ret < 0) 485 return ret; 486 } else if (dst->hw_frames_ctx) { 487 ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data; 488 489 ret = ctx->internal->hw_type->transfer_data_to(ctx, dst, src); 490 if (ret < 0) 491 return ret; 492 } else { 493 return AVERROR(ENOSYS); 494 } 495 } 496 return 0; 497} 498 499int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) 500{ 501 AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; 502 int ret; 503 504 if (ctx->internal->source_frames) { 505 // This is a derived frame context, so we allocate in the source 506 // and map the frame immediately. 507 AVFrame *src_frame; 508 509 frame->format = ctx->format; 510 frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); 511 if (!frame->hw_frames_ctx) 512 return AVERROR(ENOMEM); 513 514 src_frame = av_frame_alloc(); 515 if (!src_frame) 516 return AVERROR(ENOMEM); 517 518 ret = av_hwframe_get_buffer(ctx->internal->source_frames, 519 src_frame, 0); 520 if (ret < 0) { 521 av_frame_free(&src_frame); 522 return ret; 523 } 524 525 ret = av_hwframe_map(frame, src_frame, 526 ctx->internal->source_allocation_map_flags); 527 if (ret) { 528 av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived " 529 "frame context: %d.\n", ret); 530 av_frame_free(&src_frame); 531 return ret; 532 } 533 534 // Free the source frame immediately - the mapped frame still 535 // contains a reference to it. 536 av_frame_free(&src_frame); 537 538 return 0; 539 } 540 541 if (!ctx->internal->hw_type->frames_get_buffer) 542 return AVERROR(ENOSYS); 543 544 if (!ctx->pool) 545 return AVERROR(EINVAL); 546 547 frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); 548 if (!frame->hw_frames_ctx) 549 return AVERROR(ENOMEM); 550 551 ret = ctx->internal->hw_type->frames_get_buffer(ctx, frame); 552 if (ret < 0) { 553 av_buffer_unref(&frame->hw_frames_ctx); 554 return ret; 555 } 556 557 frame->extended_data = frame->data; 558 559 return 0; 560} 561 562void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref) 563{ 564 AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; 565 const HWContextType *hw_type = ctx->internal->hw_type; 566 567 if (hw_type->device_hwconfig_size == 0) 568 return NULL; 569 570 return av_mallocz(hw_type->device_hwconfig_size); 571} 572 573AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, 574 const void *hwconfig) 575{ 576 AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; 577 const HWContextType *hw_type = ctx->internal->hw_type; 578 AVHWFramesConstraints *constraints; 579 580 if (!hw_type->frames_get_constraints) 581 return NULL; 582 583 constraints = av_mallocz(sizeof(*constraints)); 584 if (!constraints) 585 return NULL; 586 587 constraints->min_width = constraints->min_height = 0; 588 constraints->max_width = constraints->max_height = INT_MAX; 589 590 if (hw_type->frames_get_constraints(ctx, hwconfig, constraints) >= 0) { 591 return constraints; 592 } else { 593 av_hwframe_constraints_free(&constraints); 594 return NULL; 595 } 596} 597 598void av_hwframe_constraints_free(AVHWFramesConstraints **constraints) 599{ 600 if (*constraints) { 601 av_freep(&(*constraints)->valid_hw_formats); 602 av_freep(&(*constraints)->valid_sw_formats); 603 } 604 av_freep(constraints); 605} 606 607int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, 608 const char *device, AVDictionary *opts, int flags) 609{ 610 AVBufferRef *device_ref = NULL; 611 AVHWDeviceContext *device_ctx; 612 int ret = 0; 613 614 device_ref = av_hwdevice_ctx_alloc(type); 615 if (!device_ref) { 616 ret = AVERROR(ENOMEM); 617 goto fail; 618 } 619 device_ctx = (AVHWDeviceContext*)device_ref->data; 620 621 if (!device_ctx->internal->hw_type->device_create) { 622 ret = AVERROR(ENOSYS); 623 goto fail; 624 } 625 626 ret = device_ctx->internal->hw_type->device_create(device_ctx, device, 627 opts, flags); 628 if (ret < 0) 629 goto fail; 630 631 ret = av_hwdevice_ctx_init(device_ref); 632 if (ret < 0) 633 goto fail; 634 635 *pdevice_ref = device_ref; 636 return 0; 637fail: 638 av_buffer_unref(&device_ref); 639 *pdevice_ref = NULL; 640 return ret; 641} 642 643int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr, 644 enum AVHWDeviceType type, 645 AVBufferRef *src_ref, 646 AVDictionary *options, int flags) 647{ 648 AVBufferRef *dst_ref = NULL, *tmp_ref; 649 AVHWDeviceContext *dst_ctx, *tmp_ctx; 650 int ret = 0; 651 652 tmp_ref = src_ref; 653 while (tmp_ref) { 654 tmp_ctx = (AVHWDeviceContext*)tmp_ref->data; 655 if (tmp_ctx->type == type) { 656 dst_ref = av_buffer_ref(tmp_ref); 657 if (!dst_ref) { 658 ret = AVERROR(ENOMEM); 659 goto fail; 660 } 661 goto done; 662 } 663 tmp_ref = tmp_ctx->internal->source_device; 664 } 665 666 dst_ref = av_hwdevice_ctx_alloc(type); 667 if (!dst_ref) { 668 ret = AVERROR(ENOMEM); 669 goto fail; 670 } 671 dst_ctx = (AVHWDeviceContext*)dst_ref->data; 672 673 tmp_ref = src_ref; 674 while (tmp_ref) { 675 tmp_ctx = (AVHWDeviceContext*)tmp_ref->data; 676 if (dst_ctx->internal->hw_type->device_derive) { 677 ret = dst_ctx->internal->hw_type->device_derive(dst_ctx, 678 tmp_ctx, 679 options, 680 flags); 681 if (ret == 0) { 682 dst_ctx->internal->source_device = av_buffer_ref(src_ref); 683 if (!dst_ctx->internal->source_device) { 684 ret = AVERROR(ENOMEM); 685 goto fail; 686 } 687 ret = av_hwdevice_ctx_init(dst_ref); 688 if (ret < 0) 689 goto fail; 690 goto done; 691 } 692 if (ret != AVERROR(ENOSYS)) 693 goto fail; 694 } 695 tmp_ref = tmp_ctx->internal->source_device; 696 } 697 698 ret = AVERROR(ENOSYS); 699 goto fail; 700 701done: 702 *dst_ref_ptr = dst_ref; 703 return 0; 704 705fail: 706 av_buffer_unref(&dst_ref); 707 *dst_ref_ptr = NULL; 708 return ret; 709} 710 711int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, 712 enum AVHWDeviceType type, 713 AVBufferRef *src_ref, int flags) 714{ 715 return av_hwdevice_ctx_create_derived_opts(dst_ref_ptr, type, src_ref, 716 NULL, flags); 717} 718 719static void ff_hwframe_unmap(void *opaque, uint8_t *data) 720{ 721 HWMapDescriptor *hwmap = (HWMapDescriptor*)data; 722 AVHWFramesContext *ctx = opaque; 723 724 if (hwmap->unmap) 725 hwmap->unmap(ctx, hwmap); 726 727 av_frame_free(&hwmap->source); 728 729 av_buffer_unref(&hwmap->hw_frames_ctx); 730 731 av_free(hwmap); 732} 733 734int ff_hwframe_map_create(AVBufferRef *hwframe_ref, 735 AVFrame *dst, const AVFrame *src, 736 void (*unmap)(AVHWFramesContext *ctx, 737 HWMapDescriptor *hwmap), 738 void *priv) 739{ 740 AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; 741 HWMapDescriptor *hwmap; 742 int ret; 743 744 hwmap = av_mallocz(sizeof(*hwmap)); 745 if (!hwmap) { 746 ret = AVERROR(ENOMEM); 747 goto fail; 748 } 749 750 hwmap->source = av_frame_alloc(); 751 if (!hwmap->source) { 752 ret = AVERROR(ENOMEM); 753 goto fail; 754 } 755 ret = av_frame_ref(hwmap->source, src); 756 if (ret < 0) 757 goto fail; 758 759 hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref); 760 if (!hwmap->hw_frames_ctx) { 761 ret = AVERROR(ENOMEM); 762 goto fail; 763 } 764 765 hwmap->unmap = unmap; 766 hwmap->priv = priv; 767 768 dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap), 769 &ff_hwframe_unmap, ctx, 0); 770 if (!dst->buf[0]) { 771 ret = AVERROR(ENOMEM); 772 goto fail; 773 } 774 775 return 0; 776 777fail: 778 if (hwmap) { 779 av_buffer_unref(&hwmap->hw_frames_ctx); 780 av_frame_free(&hwmap->source); 781 } 782 av_free(hwmap); 783 return ret; 784} 785 786int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags) 787{ 788 AVBufferRef *orig_dst_frames = dst->hw_frames_ctx; 789 enum AVPixelFormat orig_dst_fmt = dst->format; 790 AVHWFramesContext *src_frames, *dst_frames; 791 HWMapDescriptor *hwmap; 792 int ret; 793 794 if (src->hw_frames_ctx && dst->hw_frames_ctx) { 795 src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data; 796 dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data; 797 798 if ((src_frames == dst_frames && 799 src->format == dst_frames->sw_format && 800 dst->format == dst_frames->format) || 801 (src_frames->internal->source_frames && 802 src_frames->internal->source_frames->data == 803 (uint8_t*)dst_frames)) { 804 // This is an unmap operation. We don't need to directly 805 // do anything here other than fill in the original frame, 806 // because the real unmap will be invoked when the last 807 // reference to the mapped frame disappears. 808 if (!src->buf[0]) { 809 av_log(src_frames, AV_LOG_ERROR, "Invalid mapping " 810 "found when attempting unmap.\n"); 811 return AVERROR(EINVAL); 812 } 813 hwmap = (HWMapDescriptor*)src->buf[0]->data; 814 av_frame_unref(dst); 815 return av_frame_ref(dst, hwmap->source); 816 } 817 } 818 819 if (src->hw_frames_ctx) { 820 src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data; 821 822 if (src_frames->format == src->format && 823 src_frames->internal->hw_type->map_from) { 824 ret = src_frames->internal->hw_type->map_from(src_frames, 825 dst, src, flags); 826 if (ret >= 0) 827 return ret; 828 else if (ret != AVERROR(ENOSYS)) 829 goto fail; 830 } 831 } 832 833 if (dst->hw_frames_ctx) { 834 dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data; 835 836 if (dst_frames->format == dst->format && 837 dst_frames->internal->hw_type->map_to) { 838 ret = dst_frames->internal->hw_type->map_to(dst_frames, 839 dst, src, flags); 840 if (ret >= 0) 841 return ret; 842 else if (ret != AVERROR(ENOSYS)) 843 goto fail; 844 } 845 } 846 847 return AVERROR(ENOSYS); 848 849fail: 850 // if the caller provided dst frames context, it should be preserved 851 // by this function 852 av_assert0(orig_dst_frames == NULL || 853 orig_dst_frames == dst->hw_frames_ctx); 854 855 // preserve user-provided dst frame fields, but clean 856 // anything we might have set 857 dst->hw_frames_ctx = NULL; 858 av_frame_unref(dst); 859 860 dst->hw_frames_ctx = orig_dst_frames; 861 dst->format = orig_dst_fmt; 862 863 return ret; 864} 865 866int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, 867 enum AVPixelFormat format, 868 AVBufferRef *derived_device_ctx, 869 AVBufferRef *source_frame_ctx, 870 int flags) 871{ 872 AVBufferRef *dst_ref = NULL; 873 AVHWFramesContext *dst = NULL; 874 AVHWFramesContext *src = (AVHWFramesContext*)source_frame_ctx->data; 875 int ret; 876 877 if (src->internal->source_frames) { 878 AVHWFramesContext *src_src = 879 (AVHWFramesContext*)src->internal->source_frames->data; 880 AVHWDeviceContext *dst_dev = 881 (AVHWDeviceContext*)derived_device_ctx->data; 882 883 if (src_src->device_ctx == dst_dev) { 884 // This is actually an unmapping, so we just return a 885 // reference to the source frame context. 886 *derived_frame_ctx = 887 av_buffer_ref(src->internal->source_frames); 888 if (!*derived_frame_ctx) { 889 ret = AVERROR(ENOMEM); 890 goto fail; 891 } 892 return 0; 893 } 894 } 895 896 dst_ref = av_hwframe_ctx_alloc(derived_device_ctx); 897 if (!dst_ref) { 898 ret = AVERROR(ENOMEM); 899 goto fail; 900 } 901 902 dst = (AVHWFramesContext*)dst_ref->data; 903 904 dst->format = format; 905 dst->sw_format = src->sw_format; 906 dst->width = src->width; 907 dst->height = src->height; 908 909 dst->internal->source_frames = av_buffer_ref(source_frame_ctx); 910 if (!dst->internal->source_frames) { 911 ret = AVERROR(ENOMEM); 912 goto fail; 913 } 914 915 dst->internal->source_allocation_map_flags = 916 flags & (AV_HWFRAME_MAP_READ | 917 AV_HWFRAME_MAP_WRITE | 918 AV_HWFRAME_MAP_OVERWRITE | 919 AV_HWFRAME_MAP_DIRECT); 920 921 ret = AVERROR(ENOSYS); 922 if (src->internal->hw_type->frames_derive_from) 923 ret = src->internal->hw_type->frames_derive_from(dst, src, flags); 924 if (ret == AVERROR(ENOSYS) && 925 dst->internal->hw_type->frames_derive_to) 926 ret = dst->internal->hw_type->frames_derive_to(dst, src, flags); 927 if (ret == AVERROR(ENOSYS)) 928 ret = 0; 929 if (ret) 930 goto fail; 931 932 *derived_frame_ctx = dst_ref; 933 return 0; 934 935fail: 936 if (dst) 937 av_buffer_unref(&dst->internal->source_frames); 938 av_buffer_unref(&dst_ref); 939 return ret; 940} 941 942int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src) 943{ 944 HWMapDescriptor *hwmap = (HWMapDescriptor*)dst->buf[0]->data; 945 av_frame_unref(hwmap->source); 946 return av_frame_ref(hwmap->source, src); 947} 948