mirror of
				https://git.ffmpeg.org/ffmpeg.git
				synced 2025-11-04 01:30:56 +00:00 
			
		
		
		
	lavc, lavu: move frame cropping to a convenience function
Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
		
							parent
							
								
									80e919b174
								
							
						
					
					
						commit
						47399ccdfd
					
				
					 5 changed files with 140 additions and 88 deletions
				
			
		| 
						 | 
				
			
			@ -13,6 +13,9 @@ libavutil:     2017-03-23
 | 
			
		|||
 | 
			
		||||
API changes, most recent first:
 | 
			
		||||
 | 
			
		||||
2017-xx-xx - xxxxxxx - lavu 56.3.0 - frame.h
 | 
			
		||||
  Add av_frame_apply_cropping().
 | 
			
		||||
 | 
			
		||||
2017-xx-xx - xxxxxxx - lavc 58.4.0 - avcodec.h
 | 
			
		||||
  DXVA2 and D3D11 hardware accelerated decoding now supports the new hwaccel API,
 | 
			
		||||
  which can create the decoder context and allocate hardware frame automatically.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -446,44 +446,8 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame,
 | 
			
		||||
                                 const AVPixFmtDescriptor *desc)
 | 
			
		||||
{
 | 
			
		||||
    int i, j;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; frame->data[i]; i++) {
 | 
			
		||||
        const AVComponentDescriptor *comp = NULL;
 | 
			
		||||
        int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0;
 | 
			
		||||
        int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0;
 | 
			
		||||
 | 
			
		||||
        if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_PSEUDOPAL) && i == 1) {
 | 
			
		||||
            offsets[i] = 0;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* find any component descriptor for this plane */
 | 
			
		||||
        for (j = 0; j < desc->nb_components; j++) {
 | 
			
		||||
            if (desc->comp[j].plane == i) {
 | 
			
		||||
                comp = &desc->comp[j];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!comp)
 | 
			
		||||
            return AVERROR_BUG;
 | 
			
		||||
 | 
			
		||||
        offsets[i] = (frame->crop_top  >> shift_y) * frame->linesize[i] +
 | 
			
		||||
                     (frame->crop_left >> shift_x) * comp->step;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int apply_cropping(AVCodecContext *avctx, AVFrame *frame)
 | 
			
		||||
{
 | 
			
		||||
    const AVPixFmtDescriptor *desc;
 | 
			
		||||
    size_t offsets[4];
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    /* make sure we are noisy about decoders returning invalid cropping data */
 | 
			
		||||
    if (frame->crop_left >= INT_MAX - frame->crop_right        ||
 | 
			
		||||
        frame->crop_top  >= INT_MAX - frame->crop_bottom       ||
 | 
			
		||||
| 
						 | 
				
			
			@ -504,57 +468,8 @@ static int apply_cropping(AVCodecContext *avctx, AVFrame *frame)
 | 
			
		|||
    if (!avctx->apply_cropping)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    desc = av_pix_fmt_desc_get(frame->format);
 | 
			
		||||
    if (!desc)
 | 
			
		||||
        return AVERROR_BUG;
 | 
			
		||||
 | 
			
		||||
    /* Apply just the right/bottom cropping for hwaccel formats. Bitstream
 | 
			
		||||
     * formats cannot be easily handled here either (and corresponding decoders
 | 
			
		||||
     * should not export any cropping anyway), so do the same for those as well.
 | 
			
		||||
     * */
 | 
			
		||||
    if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) {
 | 
			
		||||
        frame->width      -= frame->crop_right;
 | 
			
		||||
        frame->height     -= frame->crop_bottom;
 | 
			
		||||
        frame->crop_right  = 0;
 | 
			
		||||
        frame->crop_bottom = 0;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* calculate the offsets for each plane */
 | 
			
		||||
    calc_cropping_offsets(offsets, frame, desc);
 | 
			
		||||
 | 
			
		||||
    /* adjust the offsets to avoid breaking alignment */
 | 
			
		||||
    if (!(avctx->flags & AV_CODEC_FLAG_UNALIGNED)) {
 | 
			
		||||
        int log2_crop_align = frame->crop_left ? av_ctz(frame->crop_left) : INT_MAX;
 | 
			
		||||
        int min_log2_align = INT_MAX;
 | 
			
		||||
 | 
			
		||||
        for (i = 0; frame->data[i]; i++) {
 | 
			
		||||
            int log2_align = offsets[i] ? av_ctz(offsets[i]) : INT_MAX;
 | 
			
		||||
            min_log2_align = FFMIN(log2_align, min_log2_align);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* we assume, and it should always be true, that the data alignment is
 | 
			
		||||
         * related to the cropping alignment by a constant power-of-2 factor */
 | 
			
		||||
        if (log2_crop_align < min_log2_align)
 | 
			
		||||
            return AVERROR_BUG;
 | 
			
		||||
 | 
			
		||||
        if (min_log2_align < 5) {
 | 
			
		||||
            frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1);
 | 
			
		||||
            calc_cropping_offsets(offsets, frame, desc);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; frame->data[i]; i++)
 | 
			
		||||
        frame->data[i] += offsets[i];
 | 
			
		||||
 | 
			
		||||
    frame->width      -= (frame->crop_left + frame->crop_right);
 | 
			
		||||
    frame->height     -= (frame->crop_top  + frame->crop_bottom);
 | 
			
		||||
    frame->crop_left   = 0;
 | 
			
		||||
    frame->crop_right  = 0;
 | 
			
		||||
    frame->crop_top    = 0;
 | 
			
		||||
    frame->crop_bottom = 0;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
    return av_frame_apply_cropping(frame, avctx->flags & AV_CODEC_FLAG_UNALIGNED ?
 | 
			
		||||
                                          AV_FRAME_CROP_UNALIGNED : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -596,3 +596,103 @@ void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame,
 | 
			
		||||
                                 const AVPixFmtDescriptor *desc)
 | 
			
		||||
{
 | 
			
		||||
    int i, j;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; frame->data[i]; i++) {
 | 
			
		||||
        const AVComponentDescriptor *comp = NULL;
 | 
			
		||||
        int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0;
 | 
			
		||||
        int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0;
 | 
			
		||||
 | 
			
		||||
        if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_PSEUDOPAL) && i == 1) {
 | 
			
		||||
            offsets[i] = 0;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* find any component descriptor for this plane */
 | 
			
		||||
        for (j = 0; j < desc->nb_components; j++) {
 | 
			
		||||
            if (desc->comp[j].plane == i) {
 | 
			
		||||
                comp = &desc->comp[j];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!comp)
 | 
			
		||||
            return AVERROR_BUG;
 | 
			
		||||
 | 
			
		||||
        offsets[i] = (frame->crop_top  >> shift_y) * frame->linesize[i] +
 | 
			
		||||
                     (frame->crop_left >> shift_x) * comp->step;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int av_frame_apply_cropping(AVFrame *frame, int flags)
 | 
			
		||||
{
 | 
			
		||||
    const AVPixFmtDescriptor *desc;
 | 
			
		||||
    size_t offsets[4];
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (!(frame->width > 0 && frame->height > 0))
 | 
			
		||||
        return AVERROR(EINVAL);
 | 
			
		||||
 | 
			
		||||
    if (frame->crop_left >= INT_MAX - frame->crop_right        ||
 | 
			
		||||
        frame->crop_top  >= INT_MAX - frame->crop_bottom       ||
 | 
			
		||||
        (frame->crop_left + frame->crop_right) >= frame->width ||
 | 
			
		||||
        (frame->crop_top + frame->crop_bottom) >= frame->height)
 | 
			
		||||
        return AVERROR(ERANGE);
 | 
			
		||||
 | 
			
		||||
    desc = av_pix_fmt_desc_get(frame->format);
 | 
			
		||||
    if (!desc)
 | 
			
		||||
        return AVERROR_BUG;
 | 
			
		||||
 | 
			
		||||
    /* Apply just the right/bottom cropping for hwaccel formats. Bitstream
 | 
			
		||||
     * formats cannot be easily handled here either (and corresponding decoders
 | 
			
		||||
     * should not export any cropping anyway), so do the same for those as well.
 | 
			
		||||
     * */
 | 
			
		||||
    if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) {
 | 
			
		||||
        frame->width      -= frame->crop_right;
 | 
			
		||||
        frame->height     -= frame->crop_bottom;
 | 
			
		||||
        frame->crop_right  = 0;
 | 
			
		||||
        frame->crop_bottom = 0;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* calculate the offsets for each plane */
 | 
			
		||||
    calc_cropping_offsets(offsets, frame, desc);
 | 
			
		||||
 | 
			
		||||
    /* adjust the offsets to avoid breaking alignment */
 | 
			
		||||
    if (!(flags & AV_FRAME_CROP_UNALIGNED)) {
 | 
			
		||||
        int log2_crop_align = frame->crop_left ? av_ctz(frame->crop_left) : INT_MAX;
 | 
			
		||||
        int min_log2_align = INT_MAX;
 | 
			
		||||
 | 
			
		||||
        for (i = 0; frame->data[i]; i++) {
 | 
			
		||||
            int log2_align = offsets[i] ? av_ctz(offsets[i]) : INT_MAX;
 | 
			
		||||
            min_log2_align = FFMIN(log2_align, min_log2_align);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* we assume, and it should always be true, that the data alignment is
 | 
			
		||||
         * related to the cropping alignment by a constant power-of-2 factor */
 | 
			
		||||
        if (log2_crop_align < min_log2_align)
 | 
			
		||||
            return AVERROR_BUG;
 | 
			
		||||
 | 
			
		||||
        if (min_log2_align < 5) {
 | 
			
		||||
            frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1);
 | 
			
		||||
            calc_cropping_offsets(offsets, frame, desc);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; frame->data[i]; i++)
 | 
			
		||||
        frame->data[i] += offsets[i];
 | 
			
		||||
 | 
			
		||||
    frame->width      -= (frame->crop_left + frame->crop_right);
 | 
			
		||||
    frame->height     -= (frame->crop_top  + frame->crop_bottom);
 | 
			
		||||
    frame->crop_left   = 0;
 | 
			
		||||
    frame->crop_right  = 0;
 | 
			
		||||
    frame->crop_top    = 0;
 | 
			
		||||
    frame->crop_bottom = 0;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -580,6 +580,40 @@ AVFrameSideData *av_frame_get_side_data(const AVFrame *frame,
 | 
			
		|||
 */
 | 
			
		||||
void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Flags for frame cropping.
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
    /**
 | 
			
		||||
     * Apply the maximum possible cropping, even if it requires setting the
 | 
			
		||||
     * AVFrame.data[] entries to unaligned pointers. Passing unaligned data
 | 
			
		||||
     * to Libav API is generally not allowed, and causes undefined behavior
 | 
			
		||||
     * (such as crashes). You can pass unaligned data only to Libav APIs that
 | 
			
		||||
     * are explicitly documented to accept it. Use this flag only if you
 | 
			
		||||
     * absolutely know what you are doing.
 | 
			
		||||
     */
 | 
			
		||||
    AV_FRAME_CROP_UNALIGNED     = 1 << 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Crop the given video AVFrame according to its crop_left/crop_top/crop_right/
 | 
			
		||||
 * crop_bottom fields. If cropping is successful, the function will adjust the
 | 
			
		||||
 * data pointers and the width/height fields, and set the crop fields to 0.
 | 
			
		||||
 *
 | 
			
		||||
 * In all cases, the cropping boundaries will be rounded to the inherent
 | 
			
		||||
 * alignment of the pixel format. In some cases, such as for opaque hwaccel
 | 
			
		||||
 * formats, the left/top cropping is ignored. The crop fields are set to 0 even
 | 
			
		||||
 * if the cropping was rounded or ignored.
 | 
			
		||||
 *
 | 
			
		||||
 * @param frame the frame which should be cropped
 | 
			
		||||
 * @param flags Some combination of AV_FRAME_CROP_* flags, or 0.
 | 
			
		||||
 *
 | 
			
		||||
 * @return >= 0 on success, a negative AVERROR on error. If the cropping fields
 | 
			
		||||
 * were invalid, AVERROR(ERANGE) is returned, and nothing is changed.
 | 
			
		||||
 */
 | 
			
		||||
int av_frame_apply_cropping(AVFrame *frame, int flags);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#define LIBAVUTIL_VERSION_MAJOR 56
 | 
			
		||||
#define LIBAVUTIL_VERSION_MINOR  2
 | 
			
		||||
#define LIBAVUTIL_VERSION_MINOR  3
 | 
			
		||||
#define LIBAVUTIL_VERSION_MICRO  0
 | 
			
		||||
 | 
			
		||||
#define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue