Also, add generic code for handling cropping, so the decoders can export
just the cropping size and not bother with the rest.
---
doc/APIchanges | 4 ++
libavcodec/avcodec.h | 26 +++++++++++++
libavcodec/decode.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++
libavcodec/options_table.h | 1 +
libavcodec/version.h | 2 +-
5 files changed, 128 insertions(+), 1 deletion(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index ca95308..011e4ab 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,10 @@ libavutil: 2015-08-28
API changes, most recent first:
+2016-xx-xx - xxxxxxx - lavc 57.31.0 - avcodec.h
+ Add AVCodecContext.apply_cropping to control whether cropping
+ is handled by libavcodec or the caller.
+
2016-xx-xx - xxxxxxx - lavu 55.30.0 - frame.h
Add AVFrame.crop_left/crop_top fields for attaching cropping information to
video frames.
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 0997141..b02b394 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -3112,6 +3112,32 @@ typedef struct AVCodecContext {
* This field should be set before avcodec_open2() is called.
*/
AVBufferRef *hw_frames_ctx;
+
+ /**
+ * Video decoding only. Certain video codecs support cropping, meaning that
+ * only a sub-rectangle of the decoded frame is intended for display.
+ * Cropping from the right/bottom amounts to simply decreasing the
+ * width/height of the output frames and is always done internally by
+ * libavcodec. However cropping from the left/top border requires modifying
+ * the data pointers and cannot be handled by libavcodec in certain cases
+ * (e.g. opaque frames with hardware acceleration or where such an offset
+ * would break data alignment).
+ *
+ * This option controls how left/top cropping is handled by libavcodec.
+ *
+ * When set to 1 (the default), libavcodec will offset the data pointers
+ * (only by as much as possible while preserving alignment, or by the full
+ * amount if the AV_CODEC_FLAG_UNALIGNED flag is set). The left/top_offset
+ * fields of the output frames will be zero.
+ *
+ * When set to 0, libavcodec will set the left/top_offset fields on the
+ * output frames and leave applying the left/top cropping to the caller.
+ *
+ * When hardware acceleration with opaque output frames is used, the actual
+ * value of this option is disregarded and libavcodec behaves as if it was
+ * set to 0.
+ */
+ int apply_cropping;
} AVCodecContext;
/**
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 0fd41ab..76fb0ff 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -29,6 +29,7 @@
#include "libavutil/frame.h"
#include "libavutil/hwcontext.h"
#include "libavutil/imgutils.h"
+#include "libavutil/intmath.h"
#include "avcodec.h"
#include "bytestream.h"
@@ -450,6 +451,93 @@ 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;
+
+ /* 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 >= frame->width || frame->crop_top >= frame->height) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid cropping information set by a decoder: %zu/%zu "
+ "(frame size %dx%d). This is a bug, please report it\n",
+ frame->crop_left, frame->crop_top, frame->width, frame->height);
+ frame->crop_left = 0;
+ frame->crop_top = 0;
+ return 0;
+ }
+
+ if (!avctx->apply_cropping)
+ return 0;
+
+ desc = av_pix_fmt_desc_get(frame->format);
+ if (!desc)
+ return AVERROR_BUG;
+
+ /* Do nothing for hwaccel formats.
+ * Bitstream formats cannot be easily handled here either (and
corresponding
+ * decoders should not export any cropping anyway), so also do nothing for
+ * those. */
+ if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL))
+ 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 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);
+ }
+
+ if (min_log2_align < 5) {
+ frame->crop_left &= ~((1 << 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->height -= frame->crop_top;
+ frame->crop_left = 0;
+ frame->crop_top = 0;
+
+ return 0;
+}
+
int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame
*frame)
{
AVCodecInternal *avci = avctx->internal;
@@ -472,6 +560,14 @@ int attribute_align_arg
avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
return ret;
}
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ret = apply_cropping(avctx, frame);
+ if (ret < 0) {
+ av_frame_unref(frame);
+ return ret;
+ }
+ }
+
avctx->frame_number++;
return 0;
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index 4deb223..3ac53fb 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -531,6 +531,7 @@ static const AVOption avcodec_options[] = {
#if FF_API_SIDEDATA_ONLY_PKT
{"side_data_only_packets", NULL, OFFSET(side_data_only_packets),
AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, A|V|E },
#endif
+{"apply_cropping", NULL, OFFSET(apply_cropping), AV_OPT_TYPE_INT, { .i64 = 1
}, 0, 1, V | D },
{NULL},
};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index adab9b4..df0c01f 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 30
+#define LIBAVCODEC_VERSION_MINOR 31
#define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
--
2.0.0
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel