aboutsummaryrefslogtreecommitdiffstats
path: root/libavutil/frame.c
diff options
context:
space:
mode:
authorwm4 <nfxjfg@googlemail.com>2017-07-22 23:05:13 +0200
committerwm4 <nfxjfg@googlemail.com>2017-08-08 13:35:09 +0200
commitcaa12027baf1180453846c58da08fc87accc0ff6 (patch)
tree2a5a5cd1ecb176dc9f368ad40144f818ae79c0e6 /libavutil/frame.c
parent45759540a5597bb6811afc749baa637f778a5ca0 (diff)
downloadffmpeg-caa12027baf1180453846c58da08fc87accc0ff6.tar.gz
lavc, lavu: move frame cropping to a convenience function
Signed-off-by: Anton Khirnov <anton@khirnov.net> Merged from Libav commit 47399ccdfd.
Diffstat (limited to 'libavutil/frame.c')
-rw-r--r--libavutil/frame.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 1f2b2356fc..85d89b9ed5 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -782,3 +782,103 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type)
}
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;
+}