From d2f119a1f2d2d72b0001fcdf2cc051b022bf6528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Delm=C3=A1s?= Date: Sat, 27 Aug 2011 19:37:26 +0200 Subject: [PATCH] VC1: Support dynamic dimension changes Fixes SA00072, SA00073, SA10150, SA10151, Issue2076 Improves SA10153 Signed-off-by: Anton Khirnov --- libavcodec/vc1.c | 17 ++-- libavcodec/vc1dec.c | 202 +++++++++++++++++++++++--------------------- 2 files changed, 118 insertions(+), 101 deletions(-) diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c index c3649ac383..870feaaa76 100644 --- a/libavcodec/vc1.c +++ b/libavcodec/vc1.c @@ -453,9 +453,6 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb) v->finterpflag = get_bits1(gb); skip_bits1(gb); // reserved - v->s.h_edge_pos = v->s.avctx->coded_width; - v->s.v_edge_pos = v->s.avctx->coded_height; - av_log(v->s.avctx, AV_LOG_DEBUG, "Advanced Profile level %i:\nfrmrtq_postproc=%i, bitrtq_postproc=%i\n" "LoopFilter=%i, ChromaFormat=%i, Pulldown=%i, Interlace: %i\n" @@ -474,8 +471,8 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb) if(get_bits1(gb)) { //Display Info - decoding is not affected by it int w, h, ar = 0; av_log(v->s.avctx, AV_LOG_DEBUG, "Display extended info:\n"); - v->s.avctx->width = w = get_bits(gb, 14) + 1; - v->s.avctx->height = h = get_bits(gb, 14) + 1; + w = get_bits(gb, 14) + 1; + h = get_bits(gb, 14) + 1; av_log(v->s.avctx, AV_LOG_DEBUG, "Display dimensions: %ix%i\n", w, h); if(get_bits1(gb)) ar = get_bits(gb, 4); @@ -485,6 +482,12 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb) w = get_bits(gb, 8) + 1; h = get_bits(gb, 8) + 1; v->s.avctx->sample_aspect_ratio = (AVRational){w, h}; + } else { + av_reduce(&v->s.avctx->sample_aspect_ratio.num, + &v->s.avctx->sample_aspect_ratio.den, + v->s.avctx->height * w, + v->s.avctx->width * h, + 1<<30); } av_log(v->s.avctx, AV_LOG_DEBUG, "Aspect: %i:%i\n", v->s.avctx->sample_aspect_ratio.num, v->s.avctx->sample_aspect_ratio.den); @@ -552,8 +555,8 @@ int vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContext * } if(get_bits1(gb)){ - avctx->coded_width = (get_bits(gb, 12)+1)<<1; - avctx->coded_height = (get_bits(gb, 12)+1)<<1; + avctx->width = avctx->coded_width = (get_bits(gb, 12)+1)<<1; + avctx->height = avctx->coded_height = (get_bits(gb, 12)+1)<<1; } if(v->extended_mv) v->extended_dmv = get_bits1(gb); diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index f4d6f997f8..095f08011b 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -3551,6 +3551,58 @@ static void vc1_sprite_flush(AVCodecContext *avctx) #endif +static av_cold int vc1_decode_init_alloc_tables(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int i; + + /* Allocate mb bitplanes */ + v->mv_type_mb_plane = av_malloc(s->mb_stride * s->mb_height); + v->direct_mb_plane = av_malloc(s->mb_stride * s->mb_height); + v->acpred_plane = av_malloc(s->mb_stride * s->mb_height); + v->over_flags_plane = av_malloc(s->mb_stride * s->mb_height); + + v->n_allocated_blks = s->mb_width + 2; + v->block = av_malloc(sizeof(*v->block) * v->n_allocated_blks); + v->cbp_base = av_malloc(sizeof(v->cbp_base[0]) * 2 * s->mb_stride); + v->cbp = v->cbp_base + s->mb_stride; + v->ttblk_base = av_malloc(sizeof(v->ttblk_base[0]) * 2 * s->mb_stride); + v->ttblk = v->ttblk_base + s->mb_stride; + v->is_intra_base = av_malloc(sizeof(v->is_intra_base[0]) * 2 * s->mb_stride); + v->is_intra = v->is_intra_base + s->mb_stride; + v->luma_mv_base = av_malloc(sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride); + v->luma_mv = v->luma_mv_base + s->mb_stride; + + /* allocate block type info in that way so it could be used with s->block_index[] */ + v->mb_type_base = av_malloc(s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2); + v->mb_type[0] = v->mb_type_base + s->b8_stride + 1; + v->mb_type[1] = v->mb_type_base + s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride + 1; + v->mb_type[2] = v->mb_type[1] + s->mb_stride * (s->mb_height + 1); + + /* Init coded blocks info */ + if (v->profile == PROFILE_ADVANCED) + { +// if (alloc_bitplane(&v->over_flags_plane, s->mb_width, s->mb_height) < 0) +// return -1; +// if (alloc_bitplane(&v->ac_pred_plane, s->mb_width, s->mb_height) < 0) +// return -1; + } + + ff_intrax8_common_init(&v->x8,s); + + if (s->avctx->codec_id == CODEC_ID_WMV3IMAGE || s->avctx->codec_id == CODEC_ID_VC1IMAGE) { + for (i = 0; i < 4; i++) + if (!(v->sr_rows[i>>1][i%2] = av_malloc(v->output_width))) return -1; + } + + if (!v->mv_type_mb_plane || !v->direct_mb_plane || !v->acpred_plane || !v->over_flags_plane || + !v->block || !v->cbp_base || !v->ttblk_base || !v->is_intra_base || !v->luma_mv_base || + !v->mb_type_base) + return -1; + + return 0; +} + /** Initialize a VC1/WMV3 decoder * @todo TODO: Handle VC-1 IDUs (Transport level?) * @todo TODO: Decypher remaining bits in extra_data @@ -3560,7 +3612,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) VC1Context *v = avctx->priv_data; MpegEncContext *s = &v->s; GetBitContext gb; - int i, cur_width, cur_height; + int i; /* save the container output size for WMImage */ v->output_width = avctx->width; @@ -3580,13 +3632,9 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) avctx->idct_algo=FF_IDCT_WMV2; } - if(ff_msmpeg4_decode_init(avctx) < 0) - return -1; if (vc1_init_common(v) < 0) return -1; ff_vc1dsp_init(&v->vc1dsp); - cur_width = avctx->coded_width = avctx->width; - cur_height = avctx->coded_height = avctx->height; if (avctx->codec_id == CODEC_ID_WMV3 || avctx->codec_id == CODEC_ID_WMV3IMAGE) { int count = 0; @@ -3657,25 +3705,12 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) } v->res_sprite = (avctx->codec_tag == MKTAG('W','V','P','2')); } - // Sequence header information may not have been parsed - // yet when ff_msmpeg4_decode_init was called the fist time - // above. If sequence information changes, we need to call - // it again. - if (cur_width != avctx->width || - cur_height != avctx->height) { - MPV_common_end(s); - if(ff_msmpeg4_decode_init(avctx) < 0) - return -1; - avctx->coded_width = avctx->width; - avctx->coded_height = avctx->height; - } avctx->profile = v->profile; if (v->profile == PROFILE_ADVANCED) avctx->level = v->level; avctx->has_b_frames= !!(avctx->max_b_frames); - s->low_delay = !avctx->has_b_frames; s->mb_width = (avctx->coded_width+15)>>4; s->mb_height = (avctx->coded_height+15)>>4; @@ -3696,46 +3731,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) v->top_blk_sh = 0; } - /* Allocate mb bitplanes */ - v->mv_type_mb_plane = av_malloc(s->mb_stride * s->mb_height); - v->direct_mb_plane = av_malloc(s->mb_stride * s->mb_height); - v->acpred_plane = av_malloc(s->mb_stride * s->mb_height); - v->over_flags_plane = av_malloc(s->mb_stride * s->mb_height); - - v->n_allocated_blks = s->mb_width + 2; - v->block = av_malloc(sizeof(*v->block) * v->n_allocated_blks); - v->cbp_base = av_malloc(sizeof(v->cbp_base[0]) * 2 * s->mb_stride); - v->cbp = v->cbp_base + s->mb_stride; - v->ttblk_base = av_malloc(sizeof(v->ttblk_base[0]) * 2 * s->mb_stride); - v->ttblk = v->ttblk_base + s->mb_stride; - v->is_intra_base = av_malloc(sizeof(v->is_intra_base[0]) * 2 * s->mb_stride); - v->is_intra = v->is_intra_base + s->mb_stride; - v->luma_mv_base = av_malloc(sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride); - v->luma_mv = v->luma_mv_base + s->mb_stride; - - /* allocate block type info in that way so it could be used with s->block_index[] */ - v->mb_type_base = av_malloc(s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2); - v->mb_type[0] = v->mb_type_base + s->b8_stride + 1; - v->mb_type[1] = v->mb_type_base + s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride + 1; - v->mb_type[2] = v->mb_type[1] + s->mb_stride * (s->mb_height + 1); - - /* Init coded blocks info */ - if (v->profile == PROFILE_ADVANCED) - { -// if (alloc_bitplane(&v->over_flags_plane, s->mb_width, s->mb_height) < 0) -// return -1; -// if (alloc_bitplane(&v->ac_pred_plane, s->mb_width, s->mb_height) < 0) -// return -1; - } - - ff_intrax8_common_init(&v->x8,s); - if (avctx->codec_id == CODEC_ID_WMV3IMAGE || avctx->codec_id == CODEC_ID_VC1IMAGE) { - for (i = 0; i < 4; i++) - if (!(v->sr_rows[i>>1][i%2] = av_malloc(v->output_width))) return -1; - - s->low_delay = 1; - v->sprite_width = avctx->coded_width; v->sprite_height = avctx->coded_height; @@ -3751,6 +3747,36 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) return 0; } +/** Close a VC1/WMV3 decoder + * @warning Initial try at using MpegEncContext stuff + */ +static av_cold int vc1_decode_end(AVCodecContext *avctx) +{ + VC1Context *v = avctx->priv_data; + int i; + + if ((avctx->codec_id == CODEC_ID_WMV3IMAGE || avctx->codec_id == CODEC_ID_VC1IMAGE) + && v->sprite_output_frame.data[0]) + avctx->release_buffer(avctx, &v->sprite_output_frame); + for (i = 0; i < 4; i++) + av_freep(&v->sr_rows[i>>1][i%2]); + av_freep(&v->hrd_rate); + av_freep(&v->hrd_buffer); + MPV_common_end(&v->s); + av_freep(&v->mv_type_mb_plane); + av_freep(&v->direct_mb_plane); + av_freep(&v->acpred_plane); + av_freep(&v->over_flags_plane); + av_freep(&v->mb_type_base); + av_freep(&v->block); + av_freep(&v->cbp_base); + av_freep(&v->ttblk_base); + av_freep(&v->is_intra_base); // FIXME use v->mb_type[] + av_freep(&v->luma_mv_base); + ff_intrax8_common_end(&v->x8); + return 0; +} + /** Decode a VC1/WMV3 frame * @todo TODO: Handle VC-1 IDUs (Transport level?) @@ -3785,13 +3811,6 @@ static int vc1_decode_frame(AVCodecContext *avctx, return 0; } - /* We need to set current_picture_ptr before reading the header, - * otherwise we cannot store anything in there. */ - if (s->current_picture_ptr == NULL || s->current_picture_ptr->f.data[0]) { - int i= ff_find_unused_picture(s, 0); - s->current_picture_ptr= &s->picture[i]; - } - if (s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU){ if (v->profile < PROFILE_ADVANCED) avctx->pix_fmt = PIX_FMT_VDPAU_WMV3; @@ -3880,6 +3899,31 @@ static int vc1_decode_frame(AVCodecContext *avctx, } } + if (s->context_initialized && + (s->width != avctx->coded_width || + s->height != avctx->coded_height)) { + vc1_decode_end(avctx); + } + + if (!s->context_initialized) { + if (ff_msmpeg4_decode_init(avctx) < 0 || vc1_decode_init_alloc_tables(v) < 0) + return -1; + + s->low_delay = !avctx->has_b_frames || v->res_sprite; + + if (v->profile == PROFILE_ADVANCED) { + s->h_edge_pos = avctx->coded_width; + s->v_edge_pos = avctx->coded_height; + } + } + + /* We need to set current_picture_ptr before reading the header, + * otherwise we cannot store anything in there. */ + if (s->current_picture_ptr == NULL || s->current_picture_ptr->f.data[0]) { + int i= ff_find_unused_picture(s, 0); + s->current_picture_ptr= &s->picture[i]; + } + // do parse frame header if(v->profile < PROFILE_ADVANCED) { if(vc1_parse_frame_header(v, &s->gb) == -1) { @@ -4011,36 +4055,6 @@ err: } -/** Close a VC1/WMV3 decoder - * @warning Initial try at using MpegEncContext stuff - */ -static av_cold int vc1_decode_end(AVCodecContext *avctx) -{ - VC1Context *v = avctx->priv_data; - int i; - - if ((avctx->codec_id == CODEC_ID_WMV3IMAGE || avctx->codec_id == CODEC_ID_VC1IMAGE) - && v->sprite_output_frame.data[0]) - avctx->release_buffer(avctx, &v->sprite_output_frame); - for (i = 0; i < 4; i++) - av_freep(&v->sr_rows[i>>1][i%2]); - av_freep(&v->hrd_rate); - av_freep(&v->hrd_buffer); - MPV_common_end(&v->s); - av_freep(&v->mv_type_mb_plane); - av_freep(&v->direct_mb_plane); - av_freep(&v->acpred_plane); - av_freep(&v->over_flags_plane); - av_freep(&v->mb_type_base); - av_freep(&v->block); - av_freep(&v->cbp_base); - av_freep(&v->ttblk_base); - av_freep(&v->is_intra_base); // FIXME use v->mb_type[] - av_freep(&v->luma_mv_base); - ff_intrax8_common_end(&v->x8); - return 0; -} - static const AVProfile profiles[] = { { FF_PROFILE_VC1_SIMPLE, "Simple" }, { FF_PROFILE_VC1_MAIN, "Main" },