History

h264: fully support cropping.

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

Anton Khirnov committed 13 years ago

Commit 5e83d9a1 parent a7f46587 files · +108 −39Browse files

Unified · Split

7 files
  1. doc/APIchanges +3 −0
  2. libavcodec/avcodec.h +5 −0
  3. libavcodec/h264.c +68 −19
  4. libavcodec/h264.h +3 −0
  5. libavcodec/h264_ps.c +27 −19
  6. libavcodec/options_table.h +1 −0
  7. libavcodec/version.h +1 −1
doc/APIchanges+3−0
@@ -13,6 +13,9 @@ libavutil: 2012-10-22 · 12 unmodified lines
1313
1414 API changes, most recent first:
1515
16+2013-03-xx - xxxxxxx - lavc 55.2.0 - avcodec.h
17+ Add CODEC_FLAG_UNALIGNED to allow decoders to produce unaligned output.
18+
1619 2013-xx-xx - lavfi 3.8.0
1720 Move all content from avfiltergraph.h to avfilter.h. Deprecate
1821 avfilterhraph.h, user applications should include just avfilter.h
libavcodec/avcodec.h+5−0
@@ -609,6 +609,11 @@ typedef struct RcOverride{ · 608 unmodified lines
609609 Note: Not everything is supported yet.
610610 */
611611
612+/**
613+ * Allow decoders to produce frames with data planes that are not aligned
614+ * to CPU requirements (e.g. due to cropping).
615+ */
616+#define CODEC_FLAG_UNALIGNED 0x0001
612617 #define CODEC_FLAG_QSCALE 0x0002 ///< Use fixed qscale.
613618 #define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed / advanced prediction for H.263.
614619 #define CODEC_FLAG_QPEL 0x0010 ///< Use qpel MC.
libavcodec/h264.c+68−19
@@ -1426,9 +1426,6 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx) · 1425 unmodified lines
14261426
14271427 h->avctx = avctx;
14281428
1429− h->width = h->avctx->width;
1430− h->height = h->avctx->height;
1431−
14321429 h->bit_depth_luma = 8;
14331430 h->chroma_format_idc = 1;
14341431
@@ -2978,14 +2975,49 @@ static enum AVPixelFormat get_pixel_format(H264Context *h) · 1543 unmodified lines
29782975 }
29792976 }
29802977
2978+/* export coded and cropped frame dimensions to AVCodecContext */
2979+static int init_dimensions(H264Context *h)
2980+{
2981+ int width = h->width - (h->sps.crop_right + h->sps.crop_left);
2982+ int height = h->height - (h->sps.crop_top + h->sps.crop_bottom);
2983+
2984+ /* handle container cropping */
2985+ if (!h->sps.crop &&
2986+ FFALIGN(h->avctx->width, 16) == h->width &&
2987+ FFALIGN(h->avctx->height, 16) == h->height) {
2988+ width = h->avctx->width;
2989+ height = h->avctx->height;
2990+ }
2991+
2992+ if (width <= 0 || height <= 0) {
2993+ av_log(h->avctx, AV_LOG_ERROR, "Invalid cropped dimensions: %dx%d.\n",
2994+ width, height);
2995+ if (h->avctx->err_recognition & AV_EF_EXPLODE)
2996+ return AVERROR_INVALIDDATA;
2997+
2998+ av_log(h->avctx, AV_LOG_WARNING, "Ignoring cropping information.\n");
2999+ h->sps.crop_bottom = h->sps.crop_top = h->sps.crop_right = h->sps.crop_left = 0;
3000+ h->sps.crop = 0;
3001+
3002+ width = h->width;
3003+ height = h->height;
3004+ }
3005+
3006+ h->avctx->coded_width = h->width;
3007+ h->avctx->coded_height = h->height;
3008+ h->avctx->width = width;
3009+ h->avctx->height = height;
3010+
3011+ return 0;
3012+}
3013+
29813014 static int h264_slice_header_init(H264Context *h, int reinit)
29823015 {
29833016 int nb_slices = (HAVE_THREADS &&
29843017 h->avctx->active_thread_type & FF_THREAD_SLICE) ?
29853018 h->avctx->thread_count : 1;
2986− int i;
3019+ int i, ret;
29873020
2988− avcodec_set_dimensions(h->avctx, h->width, h->height);
29893021 h->avctx->sample_aspect_ratio = h->sps.sar;
29903022 av_assert0(h->avctx->sample_aspect_ratio.den);
29913023 av_pix_fmt_get_chroma_sub_sample(h->avctx->pix_fmt,
@@ -3196,17 +3228,12 @@ static int decode_slice_header(H264Context *h, H264Context *h0) · 204 unmodified lines
31963228
31973229 h->chroma_y_shift = h->sps.chroma_format_idc <= 1; // 400 uses yuv420p
31983230
3199− h->width = 16 * h->mb_width - (2 >> CHROMA444(h)) * FFMIN(h->sps.crop_right, (8 << CHROMA444(h)) - 1);
3200− if (h->sps.frame_mbs_only_flag)
3201− h->height = 16 * h->mb_height - (1 << h->chroma_y_shift) * FFMIN(h->sps.crop_bottom, (16 >> h->chroma_y_shift) - 1);
3202− else
3203− h->height = 16 * h->mb_height - (2 << h->chroma_y_shift) * FFMIN(h->sps.crop_bottom, (16 >> h->chroma_y_shift) - 1);
3231+ h->width = 16 * h->mb_width;
3232+ h->height = 16 * h->mb_height;
32043233
3205− if (FFALIGN(h->avctx->width, 16) == h->width &&
3206− FFALIGN(h->avctx->height, 16) == h->height) {
3207− h->width = h->avctx->width;
3208− h->height = h->avctx->height;
3209− }
3234+ ret = init_dimensions(h);
3235+ if (ret < 0)
3236+ return ret;
32103237
32113238 if (h->sps.video_signal_type_present_flag) {
32123239 h->avctx->color_range = h->sps.full_range ? AVCOL_RANGE_JPEG
@@ -3221,8 +3248,8 @@ static int decode_slice_header(H264Context *h, H264Context *h0) · 8 unmodified lines
32213248 }
32223249
32233250 if (h->context_initialized &&
3224− (h->width != h->avctx->width ||
3225− h->height != h->avctx->height ||
3251+ (h->width != h->avctx->coded_width ||
3252+ h->height != h->avctx->coded_height ||
32263253 needs_reinit)) {
32273254
32283255 if (h != h0) {
@@ -4611,6 +4638,26 @@ static int get_consumed_bytes(int pos, int buf_size) · 1382 unmodified lines
46114638 return pos;
46124639 }
46134640
4641+static int output_frame(H264Context *h, AVFrame *dst, AVFrame *src)
4642+{
4643+ int i;
4644+ int ret = av_frame_ref(dst, src);
4645+ if (ret < 0)
4646+ return ret;
4647+
4648+ if (!h->sps.crop)
4649+ return 0;
4650+
4651+ for (i = 0; i < 3; i++) {
4652+ int hshift = (i > 0) ? h->chroma_x_shift : 0;
4653+ int vshift = (i > 0) ? h->chroma_y_shift : 0;
4654+ int off = ((h->sps.crop_left >> hshift) << h->pixel_shift) +
4655+ (h->sps.crop_top >> vshift) * dst->linesize[i];
4656+ dst->data[i] += off;
4657+ }
4658+ return 0;
4659+}
4660+
46144661 static int decode_frame(AVCodecContext *avctx, void *data,
46154662 int *got_frame, AVPacket *avpkt)
46164663 {
@@ -4648,7 +4695,8 @@ out: · 31 unmodified lines
46484695 h->delayed_pic[i] = h->delayed_pic[i + 1];
46494696
46504697 if (out) {
4651− if ((ret = av_frame_ref(pict, &out->f)) < 0)
4698+ ret = output_frame(h, pict, &out->f);
4699+ if (ret < 0)
46524700 return ret;
46534701 *got_frame = 1;
46544702 }
@@ -4683,7 +4731,8 @@ out: · 28 unmodified lines
46834731 /* Wait for second field. */
46844732 *got_frame = 0;
46854733 } else {
4686− if ((ret = av_frame_ref(pict, &h->next_output_pic->f)) < 0)
4734+ ret = output_frame(h, pict, &h->next_output_pic->f);
4735+ if (ret < 0)
46874736 return ret;
46884737 *got_frame = 1;
46894738 }
libavcodec/h264.h+3−0
@@ -164,6 +164,8 @@ typedef struct SPS { · 163 unmodified lines
164164 int mb_aff; ///< mb_adaptive_frame_field_flag
165165 int direct_8x8_inference_flag;
166166 int crop; ///< frame_cropping_flag
167+
168+ /* those 4 are already in luma samples */
167169 unsigned int crop_left; ///< frame_cropping_rect_left_offset
168170 unsigned int crop_right; ///< frame_cropping_rect_right_offset
169171 unsigned int crop_top; ///< frame_cropping_rect_top_offset
@@ -272,6 +274,7 @@ typedef struct H264Context { · 102 unmodified lines
272274
273275 int qp_thresh; ///< QP threshold to skip loopfilter
274276
277+ /* coded dimensions -- 16 * mb w/h */
275278 int width, height;
276279 int linesize, uvlinesize;
277280 int chroma_x_shift, chroma_y_shift;
libavcodec/h264_ps.c+27−19
@@ -413,37 +413,45 @@ int ff_h264_decode_seq_parameter_set(H264Context *h){ · 412 unmodified lines
413413 #endif
414414 sps->crop= get_bits1(&h->gb);
415415 if(sps->crop){
416− int crop_vertical_limit = sps->chroma_format_idc & 2 ? 16 : 8;
417− int crop_horizontal_limit = sps->chroma_format_idc == 3 ? 16 : 8;
418− sps->crop_left = get_ue_golomb(&h->gb);
419− sps->crop_right = get_ue_golomb(&h->gb);
420− sps->crop_top = get_ue_golomb(&h->gb);
421− sps->crop_bottom= get_ue_golomb(&h->gb);
416+ int crop_left = get_ue_golomb(&h->gb);
417+ int crop_right = get_ue_golomb(&h->gb);
418+ int crop_top = get_ue_golomb(&h->gb);
419+ int crop_bottom = get_ue_golomb(&h->gb);
420+
422421 if (h->avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) {
423− av_log(h->avctx, AV_LOG_DEBUG,
424− "discarding sps cropping, "
425− "original values are l:%u r:%u t:%u b:%u\n",
426− sps->crop_left,
427− sps->crop_right,
428− sps->crop_top,
429− sps->crop_bottom);
422+ av_log(h->avctx, AV_LOG_DEBUG, "discarding sps cropping, original "
423+ "values are l:%u r:%u t:%u b:%u\n", crop_left, crop_right,
424+ crop_top, crop_bottom);
430425
431426 sps->crop_left =
432427 sps->crop_right =
433428 sps->crop_top =
434429 sps->crop_bottom = 0;
435− }
436− if(sps->crop_left || sps->crop_top){
437− av_log(h->avctx, AV_LOG_ERROR, "insane cropping not completely supported, this could look slightly wrong ...\n");
438− }
439− if(sps->crop_right >= crop_horizontal_limit || sps->crop_bottom >= crop_vertical_limit){
440− av_log(h->avctx, AV_LOG_ERROR, "brainfart cropping not supported, this could look slightly wrong ...\n");
430+ } else {
431+ int vsub = (sps->chroma_format_idc == 1) ? 1 : 0;
432+ int hsub = (sps->chroma_format_idc == 1 || sps->chroma_format_idc == 2) ? 1 : 0;
433+ int step_x = 1 << hsub;
434+ int step_y = (2 - sps->frame_mbs_only_flag) << vsub;
435+
436+ if (crop_left & (0x1F >> (sps->bit_depth_luma > 8)) &&
437+ !(h->avctx->flags & CODEC_FLAG_UNALIGNED)) {
438+ crop_left &= ~(0x1F >> (sps->bit_depth_luma > 8));
439+ av_log(h->avctx, AV_LOG_WARNING, "Reducing left cropping to %d "
440+ "chroma samples to preserve alignment.\n",
441+ crop_left);
442+ }
443+
444+ sps->crop_left = crop_left * step_x;
445+ sps->crop_right = crop_right * step_x;
446+ sps->crop_top = crop_top * step_y;
447+ sps->crop_bottom = crop_bottom * step_y;
441448 }
442449 }else{
443450 sps->crop_left =
444451 sps->crop_right =
445452 sps->crop_top =
446453 sps->crop_bottom= 0;
454+ sps->crop = 0;
447455 }
448456
449457 sps->vui_parameters_present_flag= get_bits1(&h->gb);
libavcodec/options_table.h+1−0
@@ -46,6 +46,7 @@ static const AVOption options[]={ · 45 unmodified lines
4646 "to minimum/maximum bitrate. Lowering tolerance too much has an adverse effect on quality.",
4747 OFFSET(bit_rate_tolerance), AV_OPT_TYPE_INT, {.i64 = AV_CODEC_DEFAULT_BITRATE*20 }, 1, INT_MAX, V|E},
4848 {"flags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, UINT_MAX, V|A|E|D, "flags"},
49+{"unaligned", "allow decoders to produce unaligned output", 0, AV_OPT_TYPE_CONST, { .i64 = CODEC_FLAG_UNALIGNED }, INT_MIN, INT_MAX, V | D, "flags" },
4950 {"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"},
5051 {"qpel", "use 1/4-pel motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_QPEL }, INT_MIN, INT_MAX, V|E, "flags"},
5152 {"loop", "use loop filter", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_LOOP_FILTER }, INT_MIN, INT_MAX, V|E, "flags"},
libavcodec/version.h+1−1
@@ -27,7 +27,7 @@ · 26 unmodified lines
2727 */
2828
2929 #define LIBAVCODEC_VERSION_MAJOR 55
30−#define LIBAVCODEC_VERSION_MINOR 1
30+#define LIBAVCODEC_VERSION_MINOR 2
3131 #define LIBAVCODEC_VERSION_MICRO 0
3232
3333 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t