| @@ -157,14 +157,19 @@ static void hwframe_ctx_free(void *opaque, uint8_t *data) · 156 unmodified lines |
| 157 | { | 157 | { |
| 158 | AVHWFramesContext *ctx = (AVHWFramesContext*)data; | 158 | AVHWFramesContext *ctx = (AVHWFramesContext*)data; |
| 159 | | 159 | |
| 160 | if (ctx->internal->pool_internal) | 160 | if (ctx->internal->source_frames) { |
| 161 | av_buffer_pool_uninit(&ctx->internal->pool_internal); | 161 | av_buffer_unref(&ctx->internal->source_frames); |
| 162 | | 162 | |
| 163 | if (ctx->internal->hw_type->frames_uninit) | 163 | } else { |
| 164 | ctx->internal->hw_type->frames_uninit(ctx); | 164 | if (ctx->internal->pool_internal) |
| | 165 | av_buffer_pool_uninit(&ctx->internal->pool_internal); |
| 165 | | 166 | |
| 166 | if (ctx->free) | 167 | if (ctx->internal->hw_type->frames_uninit) |
| 167 | ctx->free(ctx); | 168 | ctx->internal->hw_type->frames_uninit(ctx); |
| | 169 | |
| | 170 | if (ctx->free) |
| | 171 | ctx->free(ctx); |
| | 172 | } |
| 168 | | 173 | |
| 169 | av_buffer_unref(&ctx->device_ref); | 174 | av_buffer_unref(&ctx->device_ref); |
| 170 | | 175 | |
| @@ -266,6 +271,11 @@ int av_hwframe_ctx_init(AVBufferRef *ref) · 95 unmodified lines |
| 266 | const enum AVPixelFormat *pix_fmt; | 271 | const enum AVPixelFormat *pix_fmt; |
| 267 | int ret; | 272 | int ret; |
| 268 | | 273 | |
| | 274 | if (ctx->internal->source_frames) { |
| | 275 | /* A derived frame context is already initialised. */ |
| | 276 | return 0; |
| | 277 | } |
| | 278 | |
| 269 | /* validate the pixel format */ | 279 | /* validate the pixel format */ |
| 270 | for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) { | 280 | for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) { |
| 271 | if (*pix_fmt == ctx->format) | 281 | if (*pix_fmt == ctx->format) |
| @@ -396,6 +406,35 @@ int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) · 124 unmodified lines |
| 396 | AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; | 406 | AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; |
| 397 | int ret; | 407 | int ret; |
| 398 | | 408 | |
| | 409 | if (ctx->internal->source_frames) { |
| | 410 | // This is a derived frame context, so we allocate in the source |
| | 411 | // and map the frame immediately. |
| | 412 | AVFrame *src_frame; |
| | 413 | |
| | 414 | src_frame = av_frame_alloc(); |
| | 415 | if (!src_frame) |
| | 416 | return AVERROR(ENOMEM); |
| | 417 | |
| | 418 | ret = av_hwframe_get_buffer(ctx->internal->source_frames, |
| | 419 | src_frame, 0); |
| | 420 | if (ret < 0) |
| | 421 | return ret; |
| | 422 | |
| | 423 | ret = av_hwframe_map(frame, src_frame, 0); |
| | 424 | if (ret) { |
| | 425 | av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived " |
| | 426 | "frame context: %d.\n", ret); |
| | 427 | av_frame_free(&src_frame); |
| | 428 | return ret; |
| | 429 | } |
| | 430 | |
| | 431 | // Free the source frame immediately - the mapped frame still |
| | 432 | // contains a reference to it. |
| | 433 | av_frame_free(&src_frame); |
| | 434 | |
| | 435 | return 0; |
| | 436 | } |
| | 437 | |
| 399 | if (!ctx->internal->hw_type->frames_get_buffer) | 438 | if (!ctx->internal->hw_type->frames_get_buffer) |
| 400 | return AVERROR(ENOSYS); | 439 | return AVERROR(ENOSYS); |
| 401 | | 440 | |
| @@ -495,3 +534,191 @@ fail: · 93 unmodified lines |
| 495 | *pdevice_ref = NULL; | 534 | *pdevice_ref = NULL; |
| 496 | return ret; | 535 | return ret; |
| 497 | } | 536 | } |
| | 537 | |
| | 538 | static void ff_hwframe_unmap(void *opaque, uint8_t *data) |
| | 539 | { |
| | 540 | HWMapDescriptor *hwmap = (HWMapDescriptor*)data; |
| | 541 | AVHWFramesContext *ctx = opaque; |
| | 542 | |
| | 543 | if (hwmap->unmap) |
| | 544 | hwmap->unmap(ctx, hwmap); |
| | 545 | |
| | 546 | av_frame_free(&hwmap->source); |
| | 547 | |
| | 548 | av_buffer_unref(&hwmap->hw_frames_ctx); |
| | 549 | |
| | 550 | av_free(hwmap); |
| | 551 | } |
| | 552 | |
| | 553 | int ff_hwframe_map_create(AVBufferRef *hwframe_ref, |
| | 554 | AVFrame *dst, const AVFrame *src, |
| | 555 | void (*unmap)(AVHWFramesContext *ctx, |
| | 556 | HWMapDescriptor *hwmap), |
| | 557 | void *priv) |
| | 558 | { |
| | 559 | AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; |
| | 560 | HWMapDescriptor *hwmap; |
| | 561 | int ret; |
| | 562 | |
| | 563 | hwmap = av_mallocz(sizeof(*hwmap)); |
| | 564 | if (!hwmap) { |
| | 565 | ret = AVERROR(ENOMEM); |
| | 566 | goto fail; |
| | 567 | } |
| | 568 | |
| | 569 | hwmap->source = av_frame_alloc(); |
| | 570 | if (!hwmap->source) { |
| | 571 | ret = AVERROR(ENOMEM); |
| | 572 | goto fail; |
| | 573 | } |
| | 574 | ret = av_frame_ref(hwmap->source, src); |
| | 575 | if (ret < 0) |
| | 576 | goto fail; |
| | 577 | |
| | 578 | hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref); |
| | 579 | if (!hwmap->hw_frames_ctx) { |
| | 580 | ret = AVERROR(ENOMEM); |
| | 581 | goto fail; |
| | 582 | } |
| | 583 | |
| | 584 | hwmap->unmap = unmap; |
| | 585 | hwmap->priv = priv; |
| | 586 | |
| | 587 | dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap), |
| | 588 | &ff_hwframe_unmap, ctx, 0); |
| | 589 | if (!dst->buf[0]) { |
| | 590 | ret = AVERROR(ENOMEM); |
| | 591 | goto fail; |
| | 592 | } |
| | 593 | |
| | 594 | return 0; |
| | 595 | |
| | 596 | fail: |
| | 597 | if (hwmap) { |
| | 598 | av_buffer_unref(&hwmap->hw_frames_ctx); |
| | 599 | av_frame_free(&hwmap->source); |
| | 600 | } |
| | 601 | av_free(hwmap); |
| | 602 | return ret; |
| | 603 | } |
| | 604 | |
| | 605 | int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags) |
| | 606 | { |
| | 607 | AVHWFramesContext *src_frames, *dst_frames; |
| | 608 | HWMapDescriptor *hwmap; |
| | 609 | int ret; |
| | 610 | |
| | 611 | if (src->hw_frames_ctx && dst->hw_frames_ctx) { |
| | 612 | src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data; |
| | 613 | dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data; |
| | 614 | |
| | 615 | if ((src_frames == dst_frames && |
| | 616 | src->format == dst_frames->sw_format && |
| | 617 | dst->format == dst_frames->format) || |
| | 618 | (src_frames->internal->source_frames && |
| | 619 | src_frames->internal->source_frames->data == |
| | 620 | (uint8_t*)dst_frames)) { |
| | 621 | // This is an unmap operation. We don't need to directly |
| | 622 | // do anything here other than fill in the original frame, |
| | 623 | // because the real unmap will be invoked when the last |
| | 624 | // reference to the mapped frame disappears. |
| | 625 | if (!src->buf[0]) { |
| | 626 | av_log(src_frames, AV_LOG_ERROR, "Invalid mapping " |
| | 627 | "found when attempting unmap.\n"); |
| | 628 | return AVERROR(EINVAL); |
| | 629 | } |
| | 630 | hwmap = (HWMapDescriptor*)src->buf[0]->data; |
| | 631 | av_frame_unref(dst); |
| | 632 | return av_frame_ref(dst, hwmap->source); |
| | 633 | } |
| | 634 | } |
| | 635 | |
| | 636 | if (src->hw_frames_ctx) { |
| | 637 | src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data; |
| | 638 | |
| | 639 | if (src_frames->format == src->format && |
| | 640 | src_frames->internal->hw_type->map_from) { |
| | 641 | ret = src_frames->internal->hw_type->map_from(src_frames, |
| | 642 | dst, src, flags); |
| | 643 | if (ret != AVERROR(ENOSYS)) |
| | 644 | return ret; |
| | 645 | } |
| | 646 | } |
| | 647 | |
| | 648 | if (dst->hw_frames_ctx) { |
| | 649 | dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data; |
| | 650 | |
| | 651 | if (dst_frames->format == dst->format && |
| | 652 | dst_frames->internal->hw_type->map_to) { |
| | 653 | ret = dst_frames->internal->hw_type->map_to(dst_frames, |
| | 654 | dst, src, flags); |
| | 655 | if (ret != AVERROR(ENOSYS)) |
| | 656 | return ret; |
| | 657 | } |
| | 658 | } |
| | 659 | |
| | 660 | return AVERROR(ENOSYS); |
| | 661 | } |
| | 662 | |
| | 663 | int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, |
| | 664 | enum AVPixelFormat format, |
| | 665 | AVBufferRef *derived_device_ctx, |
| | 666 | AVBufferRef *source_frame_ctx, |
| | 667 | int flags) |
| | 668 | { |
| | 669 | AVBufferRef *dst_ref = NULL; |
| | 670 | AVHWFramesContext *dst = NULL; |
| | 671 | AVHWFramesContext *src = (AVHWFramesContext*)source_frame_ctx->data; |
| | 672 | int ret; |
| | 673 | |
| | 674 | if (src->internal->source_frames) { |
| | 675 | AVHWFramesContext *src_src = |
| | 676 | (AVHWFramesContext*)src->internal->source_frames->data; |
| | 677 | AVHWDeviceContext *dst_dev = |
| | 678 | (AVHWDeviceContext*)derived_device_ctx->data; |
| | 679 | |
| | 680 | if (src_src->device_ctx == dst_dev) { |
| | 681 | // This is actually an unmapping, so we just return a |
| | 682 | // reference to the source frame context. |
| | 683 | *derived_frame_ctx = |
| | 684 | av_buffer_ref(src->internal->source_frames); |
| | 685 | if (!*derived_frame_ctx) { |
| | 686 | ret = AVERROR(ENOMEM); |
| | 687 | goto fail; |
| | 688 | } |
| | 689 | return 0; |
| | 690 | } |
| | 691 | } |
| | 692 | |
| | 693 | dst_ref = av_hwframe_ctx_alloc(derived_device_ctx); |
| | 694 | if (!dst_ref) { |
| | 695 | ret = AVERROR(ENOMEM); |
| | 696 | goto fail; |
| | 697 | } |
| | 698 | |
| | 699 | dst = (AVHWFramesContext*)dst_ref->data; |
| | 700 | |
| | 701 | dst->format = format; |
| | 702 | dst->sw_format = src->sw_format; |
| | 703 | dst->width = src->width; |
| | 704 | dst->height = src->height; |
| | 705 | |
| | 706 | dst->internal->source_frames = av_buffer_ref(source_frame_ctx); |
| | 707 | if (!dst->internal->source_frames) { |
| | 708 | ret = AVERROR(ENOMEM); |
| | 709 | goto fail; |
| | 710 | } |
| | 711 | |
| | 712 | ret = av_hwframe_ctx_init(dst_ref); |
| | 713 | if (ret) |
| | 714 | goto fail; |
| | 715 | |
| | 716 | *derived_frame_ctx = dst_ref; |
| | 717 | return 0; |
| | 718 | |
| | 719 | fail: |
| | 720 | if (dst) |
| | 721 | av_buffer_unref(&dst->internal->source_frames); |
| | 722 | av_buffer_unref(&dst_ref); |
| | 723 | return ret; |
| | 724 | } |