mirror of
				https://git.ffmpeg.org/ffmpeg.git
				synced 2025-10-30 23:30:55 +00:00 
			
		
		
		
	lavc, lavu: move frame cropping to a convenience function
Signed-off-by: Anton Khirnov <anton@khirnov.net>
Merged from Libav commit 47399ccdfd.
			
			
This commit is contained in:
		
							parent
							
								
									45759540a5
								
							
						
					
					
						commit
						caa12027ba
					
				
					 5 changed files with 140 additions and 88 deletions
				
			
		|  | @ -15,6 +15,9 @@ libavutil:     2015-08-28 | ||||||
| 
 | 
 | ||||||
| API changes, most recent first: | API changes, most recent first: | ||||||
| 
 | 
 | ||||||
|  | 2017-08-08 - xxxxxxx - lavu 55.71.100 - frame.h | ||||||
|  |   Add av_frame_apply_cropping(). | ||||||
|  | 
 | ||||||
| 2017-07-25 - 24de4fddca - lavu 55.69.100 - frame.h | 2017-07-25 - 24de4fddca - lavu 55.69.100 - frame.h | ||||||
|   Add AV_FRAME_DATA_ICC_PROFILE side data type. |   Add AV_FRAME_DATA_ICC_PROFILE side data type. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -683,44 +683,8 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke | ||||||
|     return 0; |     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) | 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 */ |     /* make sure we are noisy about decoders returning invalid cropping data */ | ||||||
|     if (frame->crop_left >= INT_MAX - frame->crop_right        || |     if (frame->crop_left >= INT_MAX - frame->crop_right        || | ||||||
|         frame->crop_top  >= INT_MAX - frame->crop_bottom       || |         frame->crop_top  >= INT_MAX - frame->crop_bottom       || | ||||||
|  | @ -742,57 +706,8 @@ static int apply_cropping(AVCodecContext *avctx, AVFrame *frame) | ||||||
|     if (!avctx->apply_cropping) |     if (!avctx->apply_cropping) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     desc = av_pix_fmt_desc_get(frame->format); |     return av_frame_apply_cropping(frame, avctx->flags & AV_CODEC_FLAG_UNALIGNED ? | ||||||
|     if (!desc) |                                           AV_FRAME_CROP_UNALIGNED : 0); | ||||||
|         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 ? ff_ctz(frame->crop_left) : INT_MAX; |  | ||||||
|         int min_log2_align = INT_MAX; |  | ||||||
| 
 |  | ||||||
|         for (i = 0; frame->data[i]; i++) { |  | ||||||
|             int log2_align = offsets[i] ? ff_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; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) | 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) | ||||||
|     } |     } | ||||||
|     return NULL; |     return NULL; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 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 ? ff_ctz(frame->crop_left) : INT_MAX; | ||||||
|  |         int min_log2_align = INT_MAX; | ||||||
|  | 
 | ||||||
|  |         for (i = 0; frame->data[i]; i++) { | ||||||
|  |             int log2_align = offsets[i] ? ff_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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -773,6 +773,40 @@ AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, | ||||||
|  */ |  */ | ||||||
| void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); | 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); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @return a string identifying the side data type |  * @return a string identifying the side data type | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -80,7 +80,7 @@ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define LIBAVUTIL_VERSION_MAJOR  55 | #define LIBAVUTIL_VERSION_MAJOR  55 | ||||||
| #define LIBAVUTIL_VERSION_MINOR  70 | #define LIBAVUTIL_VERSION_MINOR  71 | ||||||
| #define LIBAVUTIL_VERSION_MICRO 100 | #define LIBAVUTIL_VERSION_MICRO 100 | ||||||
| 
 | 
 | ||||||
| #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ | #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 wm4
						wm4