From a02ae1c6837a54ed9e7735da2b1f789b2f4b6e13 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 18 Dec 2016 21:11:47 +0100 Subject: [PATCH 1/4] hevcdec: export cropping information instead of handling it internally --- libavcodec/hevc_parser.c | 6 ++++-- libavcodec/hevc_ps.c | 33 ++++++++++++--------------------- libavcodec/hevc_ps.h | 2 -- libavcodec/hevc_refs.c | 19 ++++--------------- libavcodec/hevcdec.c | 7 ++++--- libavcodec/hevcdec.h | 2 -- 6 files changed, 24 insertions(+), 45 deletions(-) diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c index 49e712269b..74a0257073 100644 --- a/libavcodec/hevc_parser.c +++ b/libavcodec/hevc_parser.c @@ -49,6 +49,7 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, HEVCPPS *pps; HEVCSPS *sps; + HEVCWindow *ow; unsigned int pps_id; get_bits1(gb); // first slice in pic @@ -62,12 +63,13 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, } pps = (HEVCPPS*)ctx->ps.pps_list[pps_id]->data; sps = (HEVCSPS*)ctx->ps.sps_list[pps->sps_id]->data; + ow = &sps->output_window; /* export the stream parameters */ s->coded_width = sps->width; s->coded_height = sps->height; - s->width = sps->output_width; - s->height = sps->output_height; + s->width = sps->width - ow->left_offset - ow->right_offset; + s->height = sps->height - ow->top_offset - ow->bottom_offset; s->format = sps->pix_fmt; avctx->profile = sps->ptl.general_ptl.profile_idc; avctx->level = sps->ptl.general_ptl.level_idc; diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c index 2471907077..4a5a47e20e 100644 --- a/libavcodec/hevc_ps.c +++ b/libavcodec/hevc_ps.c @@ -682,6 +682,7 @@ static int map_pixel_format(AVCodecContext *avctx, HEVCSPS *sps) int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, int apply_defdispwin, AVBufferRef **vps_list, AVCodecContext *avctx) { + HEVCWindow *ow; int ret = 0; int log2_diff_max_min_transform_block_size; int bit_depth_chroma, start, vui_present, sublayer_ordering_info; @@ -902,32 +903,21 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->output_window.top_offset += sps->vui.def_disp_win.top_offset; sps->output_window.bottom_offset += sps->vui.def_disp_win.bottom_offset; } - if (sps->output_window.left_offset & (0x1F >> (sps->pixel_shift)) && - !(avctx->flags & AV_CODEC_FLAG_UNALIGNED)) { - sps->output_window.left_offset &= ~(0x1F >> (sps->pixel_shift)); - av_log(avctx, AV_LOG_WARNING, "Reducing left output window to %d " - "chroma samples to preserve alignment.\n", - sps->output_window.left_offset); - } - sps->output_width = sps->width - - (sps->output_window.left_offset + sps->output_window.right_offset); - sps->output_height = sps->height - - (sps->output_window.top_offset + sps->output_window.bottom_offset); - if (sps->output_width <= 0 || sps->output_height <= 0) { - av_log(avctx, AV_LOG_WARNING, "Invalid visible frame dimensions: %dx%d.\n", - sps->output_width, sps->output_height); + + ow = &sps->output_window; + if (ow->left_offset >= INT_MAX - ow->right_offset || + ow->top_offset >= INT_MAX - ow->bottom_offset || + ow->left_offset + ow->right_offset >= sps->width || + ow->top_offset + ow->bottom_offset >= sps->height) { + av_log(avctx, AV_LOG_WARNING, "Invalid cropping offsets: %u/%u/%u/%u\n", + ow->left_offset, ow->right_offset, ow->top_offset, ow->bottom_offset); if (avctx->err_recognition & AV_EF_EXPLODE) { ret = AVERROR_INVALIDDATA; goto err; } av_log(avctx, AV_LOG_WARNING, "Displaying the whole video surface.\n"); - sps->output_window.left_offset = - sps->output_window.right_offset = - sps->output_window.top_offset = - sps->output_window.bottom_offset = 0; - sps->output_width = sps->width; - sps->output_height = sps->height; + memset(ow, 0, sizeof(*ow)); } // Inferred parameters @@ -1008,7 +998,8 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, "Parsed SPS: id %d; coded wxh: %dx%d; " "cropped wxh: %dx%d; pix_fmt: %s.\n", sps_id, sps->width, sps->height, - sps->output_width, sps->output_height, + sps->width - (sps->output_window.left_offset + sps->output_window.right_offset), + sps->height - (sps->output_window.top_offset + sps->output_window.bottom_offset), av_get_pix_fmt_name(sps->pix_fmt)); } diff --git a/libavcodec/hevc_ps.h b/libavcodec/hevc_ps.h index d95aa519e6..89a481ba8e 100644 --- a/libavcodec/hevc_ps.h +++ b/libavcodec/hevc_ps.h @@ -141,8 +141,6 @@ typedef struct HEVCSPS { int chroma_format_idc; uint8_t separate_colour_plane_flag; - ///< output (i.e. cropped) values - int output_width, output_height; HEVCWindow output_window; HEVCWindow pic_conf_win; diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c index 30409bae5f..0c1918793e 100644 --- a/libavcodec/hevc_refs.c +++ b/libavcodec/hevc_refs.c @@ -162,7 +162,10 @@ int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc) ref->poc = poc; ref->sequence = s->seq_decode; - ref->window = s->ps.sps->output_window; + ref->frame->crop_left = s->ps.sps->output_window.left_offset; + ref->frame->crop_right = s->ps.sps->output_window.right_offset; + ref->frame->crop_top = s->ps.sps->output_window.top_offset; + ref->frame->crop_bottom = s->ps.sps->output_window.bottom_offset; return 0; } @@ -193,26 +196,12 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush) if (nb_output) { HEVCFrame *frame = &s->DPB[min_idx]; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->frame->format); - int pixel_shift; - - if (!desc) - return AVERROR_BUG; - - pixel_shift = desc->comp[0].depth > 8; ret = av_frame_ref(out, frame->frame); ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT); if (ret < 0) return ret; - for (i = 0; i < 3; i++) { - int hshift = (i > 0) ? desc->log2_chroma_w : 0; - int vshift = (i > 0) ? desc->log2_chroma_h : 0; - int off = ((frame->window.left_offset >> hshift) << pixel_shift) + - (frame->window.top_offset >> vshift) * out->linesize[i]; - out->data[i] += off; - } av_log(s->avctx, AV_LOG_DEBUG, "Output frame with POC %d.\n", frame->poc); return 1; diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 700b5f09a0..a4c936ee05 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -338,13 +338,14 @@ static void export_stream_params(AVCodecContext *avctx, const HEVCParamSets *ps, const HEVCSPS *sps) { const HEVCVPS *vps = (const HEVCVPS*)ps->vps_list[sps->vps_id]->data; + const HEVCWindow *ow = &sps->output_window; unsigned int num = 0, den = 0; avctx->pix_fmt = sps->pix_fmt; avctx->coded_width = sps->width; avctx->coded_height = sps->height; - avctx->width = sps->output_width; - avctx->height = sps->output_height; + avctx->width = sps->width - ow->left_offset - ow->right_offset; + avctx->height = sps->height - ow->top_offset - ow->bottom_offset; avctx->has_b_frames = sps->temporal_layer[sps->max_sub_layers - 1].num_reorder_pics; avctx->profile = sps->ptl.general_ptl.profile_idc; avctx->level = sps->ptl.general_ptl.level_idc; @@ -2864,7 +2865,6 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src) dst->poc = src->poc; dst->ctb_count = src->ctb_count; - dst->window = src->window; dst->flags = src->flags; dst->sequence = src->sequence; @@ -3092,4 +3092,5 @@ AVCodec ff_hevc_decoder = { .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS, .profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles), + .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING, }; diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h index 82adad20c6..ff192f67ae 100644 --- a/libavcodec/hevcdec.h +++ b/libavcodec/hevcdec.h @@ -374,8 +374,6 @@ typedef struct HEVCFrame { int poc; struct HEVCFrame *collocated_ref; - HEVCWindow window; - AVBufferRef *tab_mvf_buf; AVBufferRef *rpl_tab_buf; AVBufferRef *rpl_buf; From 4fded0480f20f4d7ca5e776a85574de34dfead14 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 27 Dec 2016 19:07:18 +0100 Subject: [PATCH 2/4] h264dec: be more explicit in handling container cropping The current condition can trigger in cases where it shouldn't, with unexpected results. Make sure that: - container cropping is really based on the original dimensions from the caller - those dimenions are discarded on size change The code is still quite hacky and eventually should be deprecated and removed, with the decision about which cropping is used delegated to the caller. --- libavcodec/h264_slice.c | 15 +++++++++++---- libavcodec/h264dec.c | 3 +++ libavcodec/h264dec.h | 5 +++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 1b35c2baaf..a54d3816e4 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -378,6 +378,8 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->avctx->coded_width = h1->avctx->coded_width; h->avctx->width = h1->avctx->width; h->avctx->height = h1->avctx->height; + h->width_from_caller = h1->width_from_caller; + h->height_from_caller = h1->height_from_caller; h->coded_picture_number = h1->coded_picture_number; h->first_field = h1->first_field; h->picture_structure = h1->picture_structure; @@ -797,10 +799,15 @@ static int init_dimensions(H264Context *h) int height = h->height - (sps->crop_top + sps->crop_bottom); /* handle container cropping */ - if (FFALIGN(h->avctx->width, 16) == FFALIGN(width, 16) && - FFALIGN(h->avctx->height, 16) == FFALIGN(height, 16)) { - width = h->avctx->width; - height = h->avctx->height; + if (h->width_from_caller > 0 && h->height_from_caller > 0 && + !sps->crop_top && !sps->crop_left && + FFALIGN(h->width_from_caller, 16) == FFALIGN(width, 16) && + FFALIGN(h->height_from_caller, 16) == FFALIGN(height, 16)) { + width = h->width_from_caller; + height = h->height_from_caller; + } else { + h->width_from_caller = 0; + h->height_from_caller = 0; } h->avctx->coded_width = h->width; diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index e111d40c35..3209c1d4df 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -285,6 +285,9 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h) h->avctx = avctx; + h->width_from_caller = avctx->width; + h->height_from_caller = avctx->height; + h->picture_structure = PICT_FRAME; h->workaround_bugs = avctx->workaround_bugs; h->flags = avctx->flags; diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 5957e795e6..0a9896ac8a 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -514,6 +514,11 @@ typedef struct H264Context { * the slice data */ int field_started; + /* original AVCodecContext dimensions, used to handle container + * cropping */ + int width_from_caller; + int height_from_caller; + AVFrame *output_frame; int enable_er; From c3e84820d67cb1d8cfb4196f9b43971308a81571 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 18 Dec 2016 21:11:47 +0100 Subject: [PATCH 3/4] h264dec: export cropping information instead of handling it internally --- libavcodec/h264_ps.c | 9 --------- libavcodec/h264_slice.c | 21 +++++++++++++++++++-- libavcodec/h264dec.c | 26 +++----------------------- libavcodec/h264dec.h | 5 +++++ 4 files changed, 27 insertions(+), 34 deletions(-) diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index 8a64a33780..7ee3876c8b 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -498,15 +498,6 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, int step_x = 1 << hsub; int step_y = (2 - sps->frame_mbs_only_flag) << vsub; - if (crop_left & (0x1F >> (sps->bit_depth_luma > 8)) && - !(avctx->flags & AV_CODEC_FLAG_UNALIGNED)) { - crop_left &= ~(0x1F >> (sps->bit_depth_luma > 8)); - av_log(avctx, AV_LOG_WARNING, - "Reducing left cropping to %d " - "chroma samples to preserve alignment.\n", - crop_left); - } - if (INT_MAX / step_x <= crop_left || INT_MAX / step_x - crop_left <= crop_right || 16 * sps->mb_width <= step_x * (crop_left + crop_right) || diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index a54d3816e4..3749d1f2ca 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -473,6 +473,11 @@ static int h264_frame_start(H264Context *h) pic->f->pict_type = h->slice_ctx[0].slice_type; + pic->f->crop_left = h->crop_left; + pic->f->crop_right = h->crop_right; + pic->f->crop_top = h->crop_top; + pic->f->crop_bottom = h->crop_bottom; + if (CONFIG_ERROR_RESILIENCE && h->enable_er) ff_er_frame_start(&h->slice_ctx[0].er); @@ -795,8 +800,12 @@ static enum AVPixelFormat get_pixel_format(H264Context *h) static int init_dimensions(H264Context *h) { SPS *sps = h->ps.sps; - int width = h->width - (sps->crop_right + sps->crop_left); - int height = h->height - (sps->crop_top + sps->crop_bottom); + int cr = sps->crop_right; + int cl = sps->crop_left; + int ct = sps->crop_top; + int cb = sps->crop_bottom; + int width = h->width - (cr + cl); + int height = h->height - (ct + cb); /* handle container cropping */ if (h->width_from_caller > 0 && h->height_from_caller > 0 && @@ -805,6 +814,10 @@ static int init_dimensions(H264Context *h) FFALIGN(h->height_from_caller, 16) == FFALIGN(height, 16)) { width = h->width_from_caller; height = h->height_from_caller; + cl = 0; + ct = 0; + cr = h->width - width; + cb = h->height - height; } else { h->width_from_caller = 0; h->height_from_caller = 0; @@ -814,6 +827,10 @@ static int init_dimensions(H264Context *h) h->avctx->coded_height = h->height; h->avctx->width = width; h->avctx->height = height; + h->crop_right = cr; + h->crop_left = cl; + h->crop_top = ct; + h->crop_bottom = cb; return 0; } diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 3209c1d4df..834c60c38c 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -661,26 +661,6 @@ 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->ps.sps || !h->ps.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->ps.sps->crop_left >> hshift) << h->pixel_shift) + - (h->ps.sps->crop_top >> vshift) * dst->linesize[i]; - dst->data[i] += off; - } - return 0; -} - static int h264_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { @@ -722,7 +702,7 @@ out: h->delayed_pic[i] = h->delayed_pic[i + 1]; if (out) { - ret = output_frame(h, pict, out->f); + ret = av_frame_ref(pict, out->f); if (ret < 0) return ret; *got_frame = 1; @@ -765,7 +745,7 @@ out: *got_frame = 0; if (h->output_frame->buf[0]) { - ret = output_frame(h, pict, h->output_frame) ; + ret = av_frame_ref(pict, h->output_frame); av_frame_unref(h->output_frame); if (ret < 0) return ret; @@ -804,7 +784,7 @@ AVCodec ff_h264_decoder = { .capabilities = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, - .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, .flush = flush_dpb, .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context), diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 0a9896ac8a..fc7beeb994 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -372,6 +372,11 @@ typedef struct H264Context { */ int picture_idr; + int crop_left; + int crop_right; + int crop_top; + int crop_bottom; + int8_t(*intra4x4_pred_mode); H264PredContext hpc; From 1202b712690c14f0efb06e4ad8b06c5b3df6822a Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 18 Dec 2016 21:11:47 +0100 Subject: [PATCH 4/4] theora: export cropping information instead of handling it internally --- libavcodec/vp3.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index 26374cc5d3..cb8925ba4c 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -1983,6 +1983,7 @@ static int vp3_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { + AVFrame *frame = data; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; Vp3DecodeContext *s = avctx->priv_data; @@ -2122,12 +2123,12 @@ static int vp3_decode_frame(AVCodecContext *avctx, /* output frame, offset as needed */ if ((ret = av_frame_ref(data, s->current_frame.f)) < 0) return ret; - for (i = 0; i < 3; i++) { - AVFrame *dst = data; - int off = (s->offset_x >> (i && s->chroma_y_shift)) + - (s->offset_y >> (i && s->chroma_y_shift)) * dst->linesize[i]; - dst->data[i] += off; - } + + frame->crop_left = s->offset_x; + frame->crop_right = avctx->coded_width - avctx->width - s->offset_x; + frame->crop_top = s->offset_y; + frame->crop_bottom = avctx->coded_height - avctx->height - s->offset_y; + *got_frame = 1; if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME)) { @@ -2290,13 +2291,6 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb) // to normal axis ([0,0] upper left) s->offset_x = offset_x; s->offset_y = s->height - visible_height - offset_y; - - if ((s->offset_x & 0x1F) && !(avctx->flags & AV_CODEC_FLAG_UNALIGNED)) { - s->offset_x &= ~0x1F; - av_log(avctx, AV_LOG_WARNING, "Reducing offset_x from %d to %d" - "chroma samples to preserve alignment.\n", - offset_x, s->offset_x); - } } if (colorspace == 1) @@ -2499,7 +2493,8 @@ AVCodec ff_theora_decoder = { AV_CODEC_CAP_FRAME_THREADS, .flush = vp3_decode_flush, .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp3_init_thread_copy), - .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context) + .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context), + .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING, }; #endif