From 67fc8a15e4182ea111cfcd05897709f09d99a33a Mon Sep 17 00:00:00 2001 From: Vittorio Giovara Date: Fri, 12 Dec 2014 20:27:46 +0000 Subject: theora: support different visible and coded frame size Signed-off-by: Vittorio Giovara --- libavcodec/vp3.c | 61 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 16 deletions(-) (limited to 'libavcodec/vp3.c') diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index fec8766f3b..52c68d2b2c 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -171,6 +171,8 @@ typedef struct Vp3DecodeContext { Vp3Fragment *all_fragments; int fragment_start[3]; int data_offset[3]; + uint8_t offset_x; + uint8_t offset_y; int8_t (*motion_val[2])[2]; @@ -1405,14 +1407,14 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y) int offset[AV_NUM_DATA_POINTERS]; if (HAVE_THREADS && s->avctx->active_thread_type & FF_THREAD_FRAME) { - int y_flipped = s->flipped_image ? s->avctx->height - y : y; + int y_flipped = s->flipped_image ? s->height - y : y; /* At the end of the frame, report INT_MAX instead of the height of * the frame. This makes the other threads' ff_thread_await_progress() * calls cheaper, because they don't have to clip their values. */ ff_thread_report_progress(&s->current_frame, - y_flipped == s->avctx->height ? INT_MAX - : y_flipped - 1, + y_flipped == s->height ? INT_MAX + : y_flipped - 1, 0); } @@ -1424,7 +1426,7 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y) y -= h; if (!s->flipped_image) - y = s->avctx->height - y - h; + y = s->height - y - h; cy = y >> s->chroma_y_shift; offset[0] = s->current_frame.f->linesize[0] * y; @@ -1721,8 +1723,8 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) s->version = 1; s->avctx = avctx; - s->width = FFALIGN(avctx->width, 16); - s->height = FFALIGN(avctx->height, 16); + s->width = FFALIGN(avctx->coded_width, 16); + s->height = FFALIGN(avctx->coded_height, 16); if (avctx->pix_fmt == AV_PIX_FMT_NONE) avctx->pix_fmt = AV_PIX_FMT_YUV420P; avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; @@ -2115,10 +2117,17 @@ static int vp3_decode_frame(AVCodecContext *avctx, int row = (s->height >> (3 + (i && s->chroma_y_shift))) - 1; apply_loop_filter(s, i, row, row + 1); } - vp3_draw_horiz_band(s, s->avctx->height); + vp3_draw_horiz_band(s, s->height); + /* 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; + } *got_frame = 1; if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME)) { @@ -2198,7 +2207,7 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb) { Vp3DecodeContext *s = avctx->priv_data; int visible_width, visible_height, colorspace; - int offset_x = 0, offset_y = 0; + uint8_t offset_x = 0, offset_y = 0; int ret; AVRational fps, aspect; @@ -2226,6 +2235,17 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb) offset_y = get_bits(gb, 8); /* offset y, from bottom */ } + /* sanity check */ + if (av_image_check_size(visible_width, visible_height, 0, avctx) < 0 || + visible_width + offset_x > s->width || + visible_height + offset_y > s->height) { + av_log(s, AV_LOG_ERROR, + "Invalid frame dimensions - w:%d h:%d x:%d y:%d (%dx%d).\n", + visible_width, visible_height, offset_x, offset_y, + s->width, s->height); + return AVERROR_INVALIDDATA; + } + fps.num = get_bits_long(gb, 32); fps.den = get_bits_long(gb, 32); if (fps.num && fps.den) { @@ -2259,16 +2279,25 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb) skip_bits(gb, 3); /* reserved */ } -// align_get_bits(gb); - - if (visible_width <= s->width && visible_width > s->width - 16 && - visible_height <= s->height && visible_height > s->height - 16 && - !offset_x && (offset_y == s->height - visible_height)) - ret = ff_set_dimensions(avctx, visible_width, visible_height); - else - ret = ff_set_dimensions(avctx, s->width, s->height); + ret = ff_set_dimensions(avctx, s->width, s->height); if (ret < 0) return ret; + if (!(avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) && + (visible_width != s->width || visible_height != s->height)) { + avctx->width = visible_width; + avctx->height = visible_height; + // translate offsets from theora axis ([0,0] lower left) + // 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 & 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) avctx->color_primaries = AVCOL_PRI_BT470M; -- cgit v1.2.3