You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	VC1: Support dynamic dimension changes
Fixes SA00072, SA00073, SA10150, SA10151, Issue2076 Improves SA10153 Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
		
				
					committed by
					
						 Anton Khirnov
						Anton Khirnov
					
				
			
			
				
	
			
			
			
						parent
						
							a18e04bcf9
						
					
				
				
					commit
					d2f119a1f2
				
			| @@ -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); | ||||
|   | ||||
| @@ -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"     }, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user