Browse Source

h264: fully support cropping.

Based on a patch by Vittorio Giovara <vittorio.giovara@gmail.com>

Fixes Bug 378.
tags/n2.0
Anton Khirnov 13 years ago
parent
commit
5e83d9aced
7 changed files with 108 additions and 39 deletions
  1. +3
    -0
      doc/APIchanges
  2. +5
    -0
      libavcodec/avcodec.h
  3. +68
    -19
      libavcodec/h264.c
  4. +3
    -0
      libavcodec/h264.h
  5. +27
    -19
      libavcodec/h264_ps.c
  6. +1
    -0
      libavcodec/options_table.h
  7. +1
    -1
      libavcodec/version.h

+ 3
- 0
doc/APIchanges View File

@@ -13,6 +13,9 @@ libavutil: 2012-10-22

API changes, most recent first:

2013-03-xx - xxxxxxx - lavc 55.2.0 - avcodec.h
Add CODEC_FLAG_UNALIGNED to allow decoders to produce unaligned output.

2013-xx-xx - lavfi 3.8.0
Move all content from avfiltergraph.h to avfilter.h. Deprecate
avfilterhraph.h, user applications should include just avfilter.h


+ 5
- 0
libavcodec/avcodec.h View File

@@ -609,6 +609,11 @@ typedef struct RcOverride{
Note: Not everything is supported yet.
*/

/**
* Allow decoders to produce frames with data planes that are not aligned
* to CPU requirements (e.g. due to cropping).
*/
#define CODEC_FLAG_UNALIGNED 0x0001
#define CODEC_FLAG_QSCALE 0x0002 ///< Use fixed qscale.
#define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed / advanced prediction for H.263.
#define CODEC_FLAG_QPEL 0x0010 ///< Use qpel MC.


+ 68
- 19
libavcodec/h264.c View File

@@ -1426,9 +1426,6 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)

h->avctx = avctx;

h->width = h->avctx->width;
h->height = h->avctx->height;

h->bit_depth_luma = 8;
h->chroma_format_idc = 1;

@@ -2978,14 +2975,49 @@ static enum AVPixelFormat get_pixel_format(H264Context *h)
}
}

/* export coded and cropped frame dimensions to AVCodecContext */
static int init_dimensions(H264Context *h)
{
int width = h->width - (h->sps.crop_right + h->sps.crop_left);
int height = h->height - (h->sps.crop_top + h->sps.crop_bottom);

/* handle container cropping */
if (!h->sps.crop &&
FFALIGN(h->avctx->width, 16) == h->width &&
FFALIGN(h->avctx->height, 16) == h->height) {
width = h->avctx->width;
height = h->avctx->height;
}

if (width <= 0 || height <= 0) {
av_log(h->avctx, AV_LOG_ERROR, "Invalid cropped dimensions: %dx%d.\n",
width, height);
if (h->avctx->err_recognition & AV_EF_EXPLODE)
return AVERROR_INVALIDDATA;

av_log(h->avctx, AV_LOG_WARNING, "Ignoring cropping information.\n");
h->sps.crop_bottom = h->sps.crop_top = h->sps.crop_right = h->sps.crop_left = 0;
h->sps.crop = 0;

width = h->width;
height = h->height;
}

h->avctx->coded_width = h->width;
h->avctx->coded_height = h->height;
h->avctx->width = width;
h->avctx->height = height;

return 0;
}

static int h264_slice_header_init(H264Context *h, int reinit)
{
int nb_slices = (HAVE_THREADS &&
h->avctx->active_thread_type & FF_THREAD_SLICE) ?
h->avctx->thread_count : 1;
int i;
int i, ret;

avcodec_set_dimensions(h->avctx, h->width, h->height);
h->avctx->sample_aspect_ratio = h->sps.sar;
av_assert0(h->avctx->sample_aspect_ratio.den);
av_pix_fmt_get_chroma_sub_sample(h->avctx->pix_fmt,
@@ -3196,17 +3228,12 @@ static int decode_slice_header(H264Context *h, H264Context *h0)

h->chroma_y_shift = h->sps.chroma_format_idc <= 1; // 400 uses yuv420p

h->width = 16 * h->mb_width - (2 >> CHROMA444(h)) * FFMIN(h->sps.crop_right, (8 << CHROMA444(h)) - 1);
if (h->sps.frame_mbs_only_flag)
h->height = 16 * h->mb_height - (1 << h->chroma_y_shift) * FFMIN(h->sps.crop_bottom, (16 >> h->chroma_y_shift) - 1);
else
h->height = 16 * h->mb_height - (2 << h->chroma_y_shift) * FFMIN(h->sps.crop_bottom, (16 >> h->chroma_y_shift) - 1);
h->width = 16 * h->mb_width;
h->height = 16 * h->mb_height;

if (FFALIGN(h->avctx->width, 16) == h->width &&
FFALIGN(h->avctx->height, 16) == h->height) {
h->width = h->avctx->width;
h->height = h->avctx->height;
}
ret = init_dimensions(h);
if (ret < 0)
return ret;

if (h->sps.video_signal_type_present_flag) {
h->avctx->color_range = h->sps.full_range ? AVCOL_RANGE_JPEG
@@ -3221,8 +3248,8 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
}

if (h->context_initialized &&
(h->width != h->avctx->width ||
h->height != h->avctx->height ||
(h->width != h->avctx->coded_width ||
h->height != h->avctx->coded_height ||
needs_reinit)) {

if (h != h0) {
@@ -4611,6 +4638,26 @@ static int get_consumed_bytes(int pos, int buf_size)
return pos;
}

static int output_frame(H264Context *h, AVFrame *dst, AVFrame *src)
{
int i;
int ret = av_frame_ref(dst, src);
if (ret < 0)
return ret;

if (!h->sps.crop)
return 0;

for (i = 0; i < 3; i++) {
int hshift = (i > 0) ? h->chroma_x_shift : 0;
int vshift = (i > 0) ? h->chroma_y_shift : 0;
int off = ((h->sps.crop_left >> hshift) << h->pixel_shift) +
(h->sps.crop_top >> vshift) * dst->linesize[i];
dst->data[i] += off;
}
return 0;
}

static int decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
@@ -4648,7 +4695,8 @@ out:
h->delayed_pic[i] = h->delayed_pic[i + 1];

if (out) {
if ((ret = av_frame_ref(pict, &out->f)) < 0)
ret = output_frame(h, pict, &out->f);
if (ret < 0)
return ret;
*got_frame = 1;
}
@@ -4683,7 +4731,8 @@ out:
/* Wait for second field. */
*got_frame = 0;
} else {
if ((ret = av_frame_ref(pict, &h->next_output_pic->f)) < 0)
ret = output_frame(h, pict, &h->next_output_pic->f);
if (ret < 0)
return ret;
*got_frame = 1;
}


+ 3
- 0
libavcodec/h264.h View File

@@ -164,6 +164,8 @@ typedef struct SPS {
int mb_aff; ///< mb_adaptive_frame_field_flag
int direct_8x8_inference_flag;
int crop; ///< frame_cropping_flag

/* those 4 are already in luma samples */
unsigned int crop_left; ///< frame_cropping_rect_left_offset
unsigned int crop_right; ///< frame_cropping_rect_right_offset
unsigned int crop_top; ///< frame_cropping_rect_top_offset
@@ -272,6 +274,7 @@ typedef struct H264Context {

int qp_thresh; ///< QP threshold to skip loopfilter

/* coded dimensions -- 16 * mb w/h */
int width, height;
int linesize, uvlinesize;
int chroma_x_shift, chroma_y_shift;


+ 27
- 19
libavcodec/h264_ps.c View File

@@ -413,37 +413,45 @@ int ff_h264_decode_seq_parameter_set(H264Context *h){
#endif
sps->crop= get_bits1(&h->gb);
if(sps->crop){
int crop_vertical_limit = sps->chroma_format_idc & 2 ? 16 : 8;
int crop_horizontal_limit = sps->chroma_format_idc == 3 ? 16 : 8;
sps->crop_left = get_ue_golomb(&h->gb);
sps->crop_right = get_ue_golomb(&h->gb);
sps->crop_top = get_ue_golomb(&h->gb);
sps->crop_bottom= get_ue_golomb(&h->gb);
int crop_left = get_ue_golomb(&h->gb);
int crop_right = get_ue_golomb(&h->gb);
int crop_top = get_ue_golomb(&h->gb);
int crop_bottom = get_ue_golomb(&h->gb);

if (h->avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) {
av_log(h->avctx, AV_LOG_DEBUG,
"discarding sps cropping, "
"original values are l:%u r:%u t:%u b:%u\n",
sps->crop_left,
sps->crop_right,
sps->crop_top,
sps->crop_bottom);
av_log(h->avctx, AV_LOG_DEBUG, "discarding sps cropping, original "
"values are l:%u r:%u t:%u b:%u\n", crop_left, crop_right,
crop_top, crop_bottom);

sps->crop_left =
sps->crop_right =
sps->crop_top =
sps->crop_bottom = 0;
}
if(sps->crop_left || sps->crop_top){
av_log(h->avctx, AV_LOG_ERROR, "insane cropping not completely supported, this could look slightly wrong ...\n");
}
if(sps->crop_right >= crop_horizontal_limit || sps->crop_bottom >= crop_vertical_limit){
av_log(h->avctx, AV_LOG_ERROR, "brainfart cropping not supported, this could look slightly wrong ...\n");
} else {
int vsub = (sps->chroma_format_idc == 1) ? 1 : 0;
int hsub = (sps->chroma_format_idc == 1 || sps->chroma_format_idc == 2) ? 1 : 0;
int step_x = 1 << hsub;
int step_y = (2 - sps->frame_mbs_only_flag) << vsub;

if (crop_left & (0x1F >> (sps->bit_depth_luma > 8)) &&
!(h->avctx->flags & CODEC_FLAG_UNALIGNED)) {
crop_left &= ~(0x1F >> (sps->bit_depth_luma > 8));
av_log(h->avctx, AV_LOG_WARNING, "Reducing left cropping to %d "
"chroma samples to preserve alignment.\n",
crop_left);
}

sps->crop_left = crop_left * step_x;
sps->crop_right = crop_right * step_x;
sps->crop_top = crop_top * step_y;
sps->crop_bottom = crop_bottom * step_y;
}
}else{
sps->crop_left =
sps->crop_right =
sps->crop_top =
sps->crop_bottom= 0;
sps->crop = 0;
}

sps->vui_parameters_present_flag= get_bits1(&h->gb);


+ 1
- 0
libavcodec/options_table.h View File

@@ -46,6 +46,7 @@ static const AVOption options[]={
"to minimum/maximum bitrate. Lowering tolerance too much has an adverse effect on quality.",
OFFSET(bit_rate_tolerance), AV_OPT_TYPE_INT, {.i64 = AV_CODEC_DEFAULT_BITRATE*20 }, 1, INT_MAX, V|E},
{"flags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, UINT_MAX, V|A|E|D, "flags"},
{"unaligned", "allow decoders to produce unaligned output", 0, AV_OPT_TYPE_CONST, { .i64 = CODEC_FLAG_UNALIGNED }, INT_MIN, INT_MAX, V | D, "flags" },
{"mv4", "use four motion vectors per macroblock (MPEG-4)", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_4MV }, INT_MIN, INT_MAX, V|E, "flags"},
{"qpel", "use 1/4-pel motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_QPEL }, INT_MIN, INT_MAX, V|E, "flags"},
{"loop", "use loop filter", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_LOOP_FILTER }, INT_MIN, INT_MAX, V|E, "flags"},


+ 1
- 1
libavcodec/version.h View File

@@ -27,7 +27,7 @@
*/

#define LIBAVCODEC_VERSION_MAJOR 55
#define LIBAVCODEC_VERSION_MINOR 1
#define LIBAVCODEC_VERSION_MINOR 2
#define LIBAVCODEC_VERSION_MICRO 0

#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \


Loading…
Cancel
Save