Signed-off-by: Anton Khirnov <anton@khirnov.net> Merged from Libav commit 47399ccdfd.
Unified · Split
| @@ -15,6 +15,9 @@ libavutil: 2015-08-28 · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | API changes, most recent first: |
| 17 | 17 | |
| 18 | +2017-08-08 - xxxxxxx - lavu 55.71.100 - frame.h | |
| 19 | + Add av_frame_apply_cropping(). | |
| 20 | + | |
| 18 | 21 | 2017-07-25 - 24de4fddca - lavu 55.69.100 - frame.h |
| 19 | 22 | Add AV_FRAME_DATA_ICC_PROFILE side data type. |
| 20 | 23 | |
| @@ -683,44 +683,8 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke · 682 unmodified lines | ||
| 683 | 683 | return 0; |
| 684 | 684 | } |
| 685 | 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 | 686 | static int apply_cropping(AVCodecContext *avctx, AVFrame *frame) |
| 719 | 687 | { |
| 720 | − const AVPixFmtDescriptor *desc; | |
| 721 | − size_t offsets[4]; | |
| 722 | − int i; | |
| 723 | − | |
| 724 | 688 | /* make sure we are noisy about decoders returning invalid cropping data */ |
| 725 | 689 | if (frame->crop_left >= INT_MAX - frame->crop_right || |
| 726 | 690 | frame->crop_top >= INT_MAX - frame->crop_bottom || |
| @@ -742,57 +706,8 @@ static int apply_cropping(AVCodecContext *avctx, AVFrame *frame) · 15 unmodified lines | ||
| 742 | 706 | if (!avctx->apply_cropping) |
| 743 | 707 | return 0; |
| 744 | 708 | |
| 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 log2_crop_align = frame->crop_left ? ff_ctz(frame->crop_left) : INT_MAX; | |
| 767 | − int min_log2_align = INT_MAX; | |
| 768 | − | |
| 769 | − for (i = 0; frame->data[i]; i++) { | |
| 770 | − int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX; | |
| 771 | − min_log2_align = FFMIN(log2_align, min_log2_align); | |
| 772 | − } | |
| 773 | − | |
| 774 | − /* we assume, and it should always be true, that the data alignment is | |
| 775 | − * related to the cropping alignment by a constant power-of-2 factor */ | |
| 776 | − if (log2_crop_align < min_log2_align) | |
| 777 | − return AVERROR_BUG; | |
| 778 | − | |
| 779 | − if (min_log2_align < 5) { | |
| 780 | − frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1); | |
| 781 | − calc_cropping_offsets(offsets, frame, desc); | |
| 782 | − } | |
| 783 | − } | |
| 784 | − | |
| 785 | − for (i = 0; frame->data[i]; i++) | |
| 786 | − frame->data[i] += offsets[i]; | |
| 787 | − | |
| 788 | − frame->width -= (frame->crop_left + frame->crop_right); | |
| 789 | − frame->height -= (frame->crop_top + frame->crop_bottom); | |
| 790 | − frame->crop_left = 0; | |
| 791 | − frame->crop_right = 0; | |
| 792 | − frame->crop_top = 0; | |
| 793 | − frame->crop_bottom = 0; | |
| 794 | − | |
| 795 | − return 0; | |
| 709 | + return av_frame_apply_cropping(frame, avctx->flags & AV_CODEC_FLAG_UNALIGNED ? | |
| 710 | + AV_FRAME_CROP_UNALIGNED : 0); | |
| 796 | 711 | } |
| 797 | 712 | |
| 798 | 713 | int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) |
| @@ -782,3 +782,103 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type) · 781 unmodified lines | ||
| 782 | 782 | } |
| 783 | 783 | return NULL; |
| 784 | 784 | } |
| 785 | + | |
| 786 | +static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, | |
| 787 | + const AVPixFmtDescriptor *desc) | |
| 788 | +{ | |
| 789 | + int i, j; | |
| 790 | + | |
| 791 | + for (i = 0; frame->data[i]; i++) { | |
| 792 | + const AVComponentDescriptor *comp = NULL; | |
| 793 | + int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0; | |
| 794 | + int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; | |
| 795 | + | |
| 796 | + if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_PSEUDOPAL) && i == 1) { | |
| 797 | + offsets[i] = 0; | |
| 798 | + break; | |
| 799 | + } | |
| 800 | + | |
| 801 | + /* find any component descriptor for this plane */ | |
| 802 | + for (j = 0; j < desc->nb_components; j++) { | |
| 803 | + if (desc->comp[j].plane == i) { | |
| 804 | + comp = &desc->comp[j]; | |
| 805 | + break; | |
| 806 | + } | |
| 807 | + } | |
| 808 | + if (!comp) | |
| 809 | + return AVERROR_BUG; | |
| 810 | + | |
| 811 | + offsets[i] = (frame->crop_top >> shift_y) * frame->linesize[i] + | |
| 812 | + (frame->crop_left >> shift_x) * comp->step; | |
| 813 | + } | |
| 814 | + | |
| 815 | + return 0; | |
| 816 | +} | |
| 817 | + | |
| 818 | +int av_frame_apply_cropping(AVFrame *frame, int flags) | |
| 819 | +{ | |
| 820 | + const AVPixFmtDescriptor *desc; | |
| 821 | + size_t offsets[4]; | |
| 822 | + int i; | |
| 823 | + | |
| 824 | + if (!(frame->width > 0 && frame->height > 0)) | |
| 825 | + return AVERROR(EINVAL); | |
| 826 | + | |
| 827 | + if (frame->crop_left >= INT_MAX - frame->crop_right || | |
| 828 | + frame->crop_top >= INT_MAX - frame->crop_bottom || | |
| 829 | + (frame->crop_left + frame->crop_right) >= frame->width || | |
| 830 | + (frame->crop_top + frame->crop_bottom) >= frame->height) | |
| 831 | + return AVERROR(ERANGE); | |
| 832 | + | |
| 833 | + desc = av_pix_fmt_desc_get(frame->format); | |
| 834 | + if (!desc) | |
| 835 | + return AVERROR_BUG; | |
| 836 | + | |
| 837 | + /* Apply just the right/bottom cropping for hwaccel formats. Bitstream | |
| 838 | + * formats cannot be easily handled here either (and corresponding decoders | |
| 839 | + * should not export any cropping anyway), so do the same for those as well. | |
| 840 | + * */ | |
| 841 | + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) { | |
| 842 | + frame->width -= frame->crop_right; | |
| 843 | + frame->height -= frame->crop_bottom; | |
| 844 | + frame->crop_right = 0; | |
| 845 | + frame->crop_bottom = 0; | |
| 846 | + return 0; | |
| 847 | + } | |
| 848 | + | |
| 849 | + /* calculate the offsets for each plane */ | |
| 850 | + calc_cropping_offsets(offsets, frame, desc); | |
| 851 | + | |
| 852 | + /* adjust the offsets to avoid breaking alignment */ | |
| 853 | + if (!(flags & AV_FRAME_CROP_UNALIGNED)) { | |
| 854 | + int log2_crop_align = frame->crop_left ? ff_ctz(frame->crop_left) : INT_MAX; | |
| 855 | + int min_log2_align = INT_MAX; | |
| 856 | + | |
| 857 | + for (i = 0; frame->data[i]; i++) { | |
| 858 | + int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX; | |
| 859 | + min_log2_align = FFMIN(log2_align, min_log2_align); | |
| 860 | + } | |
| 861 | + | |
| 862 | + /* we assume, and it should always be true, that the data alignment is | |
| 863 | + * related to the cropping alignment by a constant power-of-2 factor */ | |
| 864 | + if (log2_crop_align < min_log2_align) | |
| 865 | + return AVERROR_BUG; | |
| 866 | + | |
| 867 | + if (min_log2_align < 5) { | |
| 868 | + frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1); | |
| 869 | + calc_cropping_offsets(offsets, frame, desc); | |
| 870 | + } | |
| 871 | + } | |
| 872 | + | |
| 873 | + for (i = 0; frame->data[i]; i++) | |
| 874 | + frame->data[i] += offsets[i]; | |
| 875 | + | |
| 876 | + frame->width -= (frame->crop_left + frame->crop_right); | |
| 877 | + frame->height -= (frame->crop_top + frame->crop_bottom); | |
| 878 | + frame->crop_left = 0; | |
| 879 | + frame->crop_right = 0; | |
| 880 | + frame->crop_top = 0; | |
| 881 | + frame->crop_bottom = 0; | |
| 882 | + | |
| 883 | + return 0; | |
| 884 | +} | |
| @@ -773,6 +773,40 @@ AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, · 772 unmodified lines | ||
| 773 | 773 | */ |
| 774 | 774 | void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); |
| 775 | 775 | |
| 776 | + | |
| 777 | +/** | |
| 778 | + * Flags for frame cropping. | |
| 779 | + */ | |
| 780 | +enum { | |
| 781 | + /** | |
| 782 | + * Apply the maximum possible cropping, even if it requires setting the | |
| 783 | + * AVFrame.data[] entries to unaligned pointers. Passing unaligned data | |
| 784 | + * to Libav API is generally not allowed, and causes undefined behavior | |
| 785 | + * (such as crashes). You can pass unaligned data only to Libav APIs that | |
| 786 | + * are explicitly documented to accept it. Use this flag only if you | |
| 787 | + * absolutely know what you are doing. | |
| 788 | + */ | |
| 789 | + AV_FRAME_CROP_UNALIGNED = 1 << 0, | |
| 790 | +}; | |
| 791 | + | |
| 792 | +/** | |
| 793 | + * Crop the given video AVFrame according to its crop_left/crop_top/crop_right/ | |
| 794 | + * crop_bottom fields. If cropping is successful, the function will adjust the | |
| 795 | + * data pointers and the width/height fields, and set the crop fields to 0. | |
| 796 | + * | |
| 797 | + * In all cases, the cropping boundaries will be rounded to the inherent | |
| 798 | + * alignment of the pixel format. In some cases, such as for opaque hwaccel | |
| 799 | + * formats, the left/top cropping is ignored. The crop fields are set to 0 even | |
| 800 | + * if the cropping was rounded or ignored. | |
| 801 | + * | |
| 802 | + * @param frame the frame which should be cropped | |
| 803 | + * @param flags Some combination of AV_FRAME_CROP_* flags, or 0. | |
| 804 | + * | |
| 805 | + * @return >= 0 on success, a negative AVERROR on error. If the cropping fields | |
| 806 | + * were invalid, AVERROR(ERANGE) is returned, and nothing is changed. | |
| 807 | + */ | |
| 808 | +int av_frame_apply_cropping(AVFrame *frame, int flags); | |
| 809 | + | |
| 776 | 810 | /** |
| 777 | 811 | * @return a string identifying the side data type |
| 778 | 812 | */ |
| @@ -80,7 +80,7 @@ · 79 unmodified lines | ||
| 80 | 80 | |
| 81 | 81 | |
| 82 | 82 | #define LIBAVUTIL_VERSION_MAJOR 55 |
| 83 | −#define LIBAVUTIL_VERSION_MINOR 70 | |
| 83 | +#define LIBAVUTIL_VERSION_MINOR 71 | |
| 84 | 84 | #define LIBAVUTIL_VERSION_MICRO 100 |
| 85 | 85 | |
| 86 | 86 | #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ |