Commit 019ab88a authored by Anton Khirnov's avatar Anton Khirnov

lavc: add an option for exporting cropping information to the caller

Also, add generic code for handling cropping, so the decoders can export
just the cropping size and not bother with the rest.
parent 52627248
......@@ -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/right/top/bottom fields for attaching cropping
information to video frames.
......
......@@ -3112,6 +3112,33 @@ 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. This
* option controls how cropping is handled by libavcodec.
*
* When set to 1 (the default), libavcodec will apply cropping internally.
* I.e. it will modify the output frame width/height fields and 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) so that
* the frames output by the decoder refer only to the cropped area. The
* crop_* fields of the output frames will be zero.
*
* When set to 0, the width/height fields of the output frames will be set
* to the coded dimensions and the crop_* fields will describe the cropping
* rectangle. Applying the cropping is left to the caller.
*
* @warning When hardware acceleration with opaque output frames is used,
* libavcodec is unable to apply cropping from the top/left border.
*
* @note when this option is set to zero, the width/height fields of the
* AVCodecContext and output AVFrames have different meanings. The codec
* context fields store display dimensions (with the coded dimensions in
* coded_width/height), while the frame fields store the coded dimensions
* (with the display dimensions being determined by the crop_* fields).
*/
int apply_cropping;
} AVCodecContext;
/**
......
......@@ -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,111 @@ 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 ||
(frame->crop_left + frame->crop_right) >= frame->width ||
(frame->crop_top + frame->crop_bottom) >= frame->height) {
av_log(avctx, AV_LOG_WARNING,
"Invalid cropping information set by a decoder: %zu/%zu/%zu/%zu "
"(frame size %dx%d). This is a bug, please report it\n",
frame->crop_left, frame->crop_right, frame->crop_top, frame->crop_bottom,
frame->width, frame->height);
frame->crop_left = 0;
frame->crop_right = 0;
frame->crop_top = 0;
frame->crop_bottom = 0;
return 0;
}
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 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->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)
{
AVCodecInternal *avci = avctx->internal;
......@@ -472,6 +578,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;
......@@ -1029,7 +1143,8 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
ret = avctx->get_buffer2(avctx, frame, flags);
end:
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions) {
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
!(avctx->codec->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) {
frame->width = avctx->width;
frame->height = avctx->height;
}
......
......@@ -53,6 +53,12 @@
* from the input AVPacket.
*/
#define FF_CODEC_CAP_SETS_PKT_DTS (1 << 2)
/**
* The decoder sets the cropping fields in the output frames manually.
* If this cap is set, the generic code will initialize output frame
* dimensions to coded rather than display values.
*/
#define FF_CODEC_CAP_EXPORTS_CROPPING (1 << 3)
#ifdef DEBUG
# define ff_dlog(ctx, ...) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__)
......
......@@ -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},
};
......
......@@ -28,8 +28,8 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MINOR 30
#define LIBAVCODEC_VERSION_MICRO 4
#define LIBAVCODEC_VERSION_MINOR 31
#define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment