lavc, lavu: move frame cropping to a convenience function

Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
wm4 2017-07-22 23:05:13 +02:00 committed by Anton Khirnov
parent 80e919b174
commit 47399ccdfd
5 changed files with 140 additions and 88 deletions

View File

@ -13,6 +13,9 @@ libavutil: 2017-03-23
API changes, most recent first: 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 2017-xx-xx - xxxxxxx - lavc 58.4.0 - avcodec.h
DXVA2 and D3D11 hardware accelerated decoding now supports the new hwaccel API, DXVA2 and D3D11 hardware accelerated decoding now supports the new hwaccel API,
which can create the decoder context and allocate hardware frame automatically. which can create the decoder context and allocate hardware frame automatically.

View File

@ -446,44 +446,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 ||
@ -504,57 +468,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 ? 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;
} }
int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)

View File

@ -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;
}

View File

@ -580,6 +580,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);
/** /**
* @} * @}
*/ */

View File

@ -54,7 +54,7 @@
*/ */
#define LIBAVUTIL_VERSION_MAJOR 56 #define LIBAVUTIL_VERSION_MAJOR 56
#define LIBAVUTIL_VERSION_MINOR 2 #define LIBAVUTIL_VERSION_MINOR 3
#define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_MICRO 0
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \