* commit '019ab88a95cb31b698506d90e8ce56695a7f1cc5': lavc: add an option for exporting cropping information to the caller
Unified · Split
| @@ -15,6 +15,10 @@ libavutil: 2015-08-28 · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | API changes, most recent first: |
| 17 | 17 | |
| 18 | +2017-xx-xx - xxxxxxx - lavc 57.95.100 / 57.31.0 - avcodec.h | |
| 19 | + Add AVCodecContext.apply_cropping to control whether cropping | |
| 20 | + is handled by libavcodec or the caller. | |
| 21 | + | |
| 18 | 22 | 2017-xx-xx - xxxxxxx - lavu 55.62.100 / 55.30.0 - frame.h |
| 19 | 23 | Add AVFrame.crop_left/right/top/bottom fields for attaching cropping |
| 20 | 24 | information to video frames. |
| @@ -3644,6 +3644,33 @@ typedef struct AVCodecContext { · 3643 unmodified lines | ||
| 3644 | 3644 | * AVCodecContext.get_format callback) |
| 3645 | 3645 | */ |
| 3646 | 3646 | int hwaccel_flags; |
| 3647 | + | |
| 3648 | + /** | |
| 3649 | + * Video decoding only. Certain video codecs support cropping, meaning that | |
| 3650 | + * only a sub-rectangle of the decoded frame is intended for display. This | |
| 3651 | + * option controls how cropping is handled by libavcodec. | |
| 3652 | + * | |
| 3653 | + * When set to 1 (the default), libavcodec will apply cropping internally. | |
| 3654 | + * I.e. it will modify the output frame width/height fields and offset the | |
| 3655 | + * data pointers (only by as much as possible while preserving alignment, or | |
| 3656 | + * by the full amount if the AV_CODEC_FLAG_UNALIGNED flag is set) so that | |
| 3657 | + * the frames output by the decoder refer only to the cropped area. The | |
| 3658 | + * crop_* fields of the output frames will be zero. | |
| 3659 | + * | |
| 3660 | + * When set to 0, the width/height fields of the output frames will be set | |
| 3661 | + * to the coded dimensions and the crop_* fields will describe the cropping | |
| 3662 | + * rectangle. Applying the cropping is left to the caller. | |
| 3663 | + * | |
| 3664 | + * @warning When hardware acceleration with opaque output frames is used, | |
| 3665 | + * libavcodec is unable to apply cropping from the top/left border. | |
| 3666 | + * | |
| 3667 | + * @note when this option is set to zero, the width/height fields of the | |
| 3668 | + * AVCodecContext and output AVFrames have different meanings. The codec | |
| 3669 | + * context fields store display dimensions (with the coded dimensions in | |
| 3670 | + * coded_width/height), while the frame fields store the coded dimensions | |
| 3671 | + * (with the display dimensions being determined by the crop_* fields). | |
| 3672 | + */ | |
| 3673 | + int apply_cropping; | |
| 3647 | 3674 | } AVCodecContext; |
| 3648 | 3675 | |
| 3649 | 3676 | AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx); |
| @@ -35,6 +35,7 @@ · 34 unmodified lines | ||
| 35 | 35 | #include "libavutil/hwcontext.h" |
| 36 | 36 | #include "libavutil/imgutils.h" |
| 37 | 37 | #include "libavutil/internal.h" |
| 38 | +#include "libavutil/intmath.h" | |
| 38 | 39 | |
| 39 | 40 | #include "avcodec.h" |
| 40 | 41 | #include "bytestream.h" |
| @@ -682,6 +683,112 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke · 641 unmodified lines | ||
| 682 | 683 | return 0; |
| 683 | 684 | } |
| 684 | 685 | |
| 686 | +static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, | |
| 687 | + const AVPixFmtDescriptor *desc) | |
| 688 | +{ | |
| 689 | + int i, j; | |
| 690 | + | |
| 691 | + for (i = 0; frame->data[i]; i++) { | |
| 692 | + const AVComponentDescriptor *comp = NULL; | |
| 693 | + int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0; | |
| 694 | + int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; | |
| 695 | + | |
| 696 | + if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_PSEUDOPAL) && i == 1) { | |
| 697 | + offsets[i] = 0; | |
| 698 | + break; | |
| 699 | + } | |
| 700 | + | |
| 701 | + /* find any component descriptor for this plane */ | |
| 702 | + for (j = 0; j < desc->nb_components; j++) { | |
| 703 | + if (desc->comp[j].plane == i) { | |
| 704 | + comp = &desc->comp[j]; | |
| 705 | + break; | |
| 706 | + } | |
| 707 | + } | |
| 708 | + if (!comp) | |
| 709 | + return AVERROR_BUG; | |
| 710 | + | |
| 711 | + offsets[i] = (frame->crop_top >> shift_y) * frame->linesize[i] + | |
| 712 | + (frame->crop_left >> shift_x) * comp->step; | |
| 713 | + } | |
| 714 | + | |
| 715 | + return 0; | |
| 716 | +} | |
| 717 | + | |
| 718 | +static int apply_cropping(AVCodecContext *avctx, AVFrame *frame) | |
| 719 | +{ | |
| 720 | + const AVPixFmtDescriptor *desc; | |
| 721 | + size_t offsets[4]; | |
| 722 | + int i; | |
| 723 | + | |
| 724 | + /* make sure we are noisy about decoders returning invalid cropping data */ | |
| 725 | + if (frame->crop_left >= INT_MAX - frame->crop_right || | |
| 726 | + frame->crop_top >= INT_MAX - frame->crop_bottom || | |
| 727 | + (frame->crop_left + frame->crop_right) >= frame->width || | |
| 728 | + (frame->crop_top + frame->crop_bottom) >= frame->height) { | |
| 729 | + av_log(avctx, AV_LOG_WARNING, | |
| 730 | + "Invalid cropping information set by a decoder: " | |
| 731 | + "%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER" " | |
| 732 | + "(frame size %dx%d). This is a bug, please report it\n", | |
| 733 | + frame->crop_left, frame->crop_right, frame->crop_top, frame->crop_bottom, | |
| 734 | + frame->width, frame->height); | |
| 735 | + frame->crop_left = 0; | |
| 736 | + frame->crop_right = 0; | |
| 737 | + frame->crop_top = 0; | |
| 738 | + frame->crop_bottom = 0; | |
| 739 | + return 0; | |
| 740 | + } | |
| 741 | + | |
| 742 | + if (!avctx->apply_cropping) | |
| 743 | + return 0; | |
| 744 | + | |
| 745 | + desc = av_pix_fmt_desc_get(frame->format); | |
| 746 | + if (!desc) | |
| 747 | + return AVERROR_BUG; | |
| 748 | + | |
| 749 | + /* Apply just the right/bottom cropping for hwaccel formats. Bitstream | |
| 750 | + * formats cannot be easily handled here either (and corresponding decoders | |
| 751 | + * should not export any cropping anyway), so do the same for those as well. | |
| 752 | + * */ | |
| 753 | + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) { | |
| 754 | + frame->width -= frame->crop_right; | |
| 755 | + frame->height -= frame->crop_bottom; | |
| 756 | + frame->crop_right = 0; | |
| 757 | + frame->crop_bottom = 0; | |
| 758 | + return 0; | |
| 759 | + } | |
| 760 | + | |
| 761 | + /* calculate the offsets for each plane */ | |
| 762 | + calc_cropping_offsets(offsets, frame, desc); | |
| 763 | + | |
| 764 | + /* adjust the offsets to avoid breaking alignment */ | |
| 765 | + if (!(avctx->flags & AV_CODEC_FLAG_UNALIGNED)) { | |
| 766 | + int min_log2_align = INT_MAX; | |
| 767 | + | |
| 768 | + for (i = 0; frame->data[i]; i++) { | |
| 769 | + int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX; | |
| 770 | + min_log2_align = FFMIN(log2_align, min_log2_align); | |
| 771 | + } | |
| 772 | + | |
| 773 | + if (min_log2_align < 5) { | |
| 774 | + frame->crop_left &= ~((1 << min_log2_align) - 1); | |
| 775 | + calc_cropping_offsets(offsets, frame, desc); | |
| 776 | + } | |
| 777 | + } | |
| 778 | + | |
| 779 | + for (i = 0; frame->data[i]; i++) | |
| 780 | + frame->data[i] += offsets[i]; | |
| 781 | + | |
| 782 | + frame->width -= (frame->crop_left + frame->crop_right); | |
| 783 | + frame->height -= (frame->crop_top + frame->crop_bottom); | |
| 784 | + frame->crop_left = 0; | |
| 785 | + frame->crop_right = 0; | |
| 786 | + frame->crop_top = 0; | |
| 787 | + frame->crop_bottom = 0; | |
| 788 | + | |
| 789 | + return 0; | |
| 790 | +} | |
| 791 | + | |
| 685 | 792 | int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) |
| 686 | 793 | { |
| 687 | 794 | AVCodecInternal *avci = avctx->internal; |
| @@ -704,6 +811,14 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr · 16 unmodified lines | ||
| 704 | 811 | return ret; |
| 705 | 812 | } |
| 706 | 813 | |
| 814 | + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { | |
| 815 | + ret = apply_cropping(avctx, frame); | |
| 816 | + if (ret < 0) { | |
| 817 | + av_frame_unref(frame); | |
| 818 | + return ret; | |
| 819 | + } | |
| 820 | + } | |
| 821 | + | |
| 707 | 822 | avctx->frame_number++; |
| 708 | 823 | |
| 709 | 824 | return 0; |
| @@ -1611,7 +1726,8 @@ static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) · 901 unmodified lines | ||
| 1611 | 1726 | validate_avframe_allocation(avctx, frame); |
| 1612 | 1727 | |
| 1613 | 1728 | end: |
| 1614 | − if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions) { | |
| 1729 | + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions && | |
| 1730 | + !(avctx->codec->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) { | |
| 1615 | 1731 | frame->width = avctx->width; |
| 1616 | 1732 | frame->height = avctx->height; |
| 1617 | 1733 | } |
| @@ -58,6 +58,12 @@ · 57 unmodified lines | ||
| 58 | 58 | * skipped due to the skip_frame setting. |
| 59 | 59 | */ |
| 60 | 60 | #define FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM (1 << 3) |
| 61 | +/** | |
| 62 | + * The decoder sets the cropping fields in the output frames manually. | |
| 63 | + * If this cap is set, the generic code will initialize output frame | |
| 64 | + * dimensions to coded rather than display values. | |
| 65 | + */ | |
| 66 | +#define FF_CODEC_CAP_EXPORTS_CROPPING (1 << 4) | |
| 61 | 67 | |
| 62 | 68 | #ifdef TRACE |
| 63 | 69 | # define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__) |
| @@ -561,6 +561,7 @@ static const AVOption avcodec_options[] = { · 560 unmodified lines | ||
| 561 | 561 | #if FF_API_SIDEDATA_ONLY_PKT |
| 562 | 562 | {"side_data_only_packets", NULL, OFFSET(side_data_only_packets), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, A|V|E }, |
| 563 | 563 | #endif |
| 564 | +{"apply_cropping", NULL, OFFSET(apply_cropping), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, V | D }, | |
| 564 | 565 | {"skip_alpha", "Skip processing alpha", OFFSET(skip_alpha), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, V|D }, |
| 565 | 566 | {"field_order", "Field order", OFFSET(field_order), AV_OPT_TYPE_INT, {.i64 = AV_FIELD_UNKNOWN }, 0, 5, V|D|E, "field_order" }, |
| 566 | 567 | {"progressive", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_PROGRESSIVE }, 0, 0, V|D|E, "field_order" }, |
| @@ -28,8 +28,8 @@ · 27 unmodified lines | ||
| 28 | 28 | #include "libavutil/version.h" |
| 29 | 29 | |
| 30 | 30 | #define LIBAVCODEC_VERSION_MAJOR 57 |
| 31 | −#define LIBAVCODEC_VERSION_MINOR 94 | |
| 32 | −#define LIBAVCODEC_VERSION_MICRO 101 | |
| 31 | +#define LIBAVCODEC_VERSION_MINOR 95 | |
| 32 | +#define LIBAVCODEC_VERSION_MICRO 100 | |
| 33 | 33 | |
| 34 | 34 | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ |
| 35 | 35 | LIBAVCODEC_VERSION_MINOR, \ |
| @@ -149,6 +149,7 @@ stream=0, decode=0 · 148 unmodified lines | ||
| 149 | 149 | sub_text_format=1 |
| 150 | 150 | refcounted_frames=false |
| 151 | 151 | side_data_only_packets=true |
| 152 | + apply_cropping=true | |
| 152 | 153 | skip_alpha=false |
| 153 | 154 | field_order=0 |
| 154 | 155 | dump_separator= |
| @@ -307,6 +308,7 @@ stream=0, decode=1 · 152 unmodified lines | ||
| 307 | 308 | sub_text_format=1 |
| 308 | 309 | refcounted_frames=false |
| 309 | 310 | side_data_only_packets=true |
| 311 | + apply_cropping=true | |
| 310 | 312 | skip_alpha=false |
| 311 | 313 | field_order=0 |
| 312 | 314 | dump_separator= |
| @@ -149,6 +149,7 @@ stream=0, decode=0 · 148 unmodified lines | ||
| 149 | 149 | sub_text_format=1 |
| 150 | 150 | refcounted_frames=false |
| 151 | 151 | side_data_only_packets=true |
| 152 | + apply_cropping=true | |
| 152 | 153 | skip_alpha=false |
| 153 | 154 | field_order=0 |
| 154 | 155 | dump_separator= |
| @@ -307,6 +308,7 @@ stream=0, decode=1 · 152 unmodified lines | ||
| 307 | 308 | sub_text_format=1 |
| 308 | 309 | refcounted_frames=false |
| 309 | 310 | side_data_only_packets=true |
| 311 | + apply_cropping=true | |
| 310 | 312 | skip_alpha=false |
| 311 | 313 | field_order=0 |
| 312 | 314 | dump_separator= |