mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-15 03:34:56 +00: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:
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" },
|
||||
|
Loading…
Reference in New Issue
Block a user