1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-08-04 22:03:09 +02:00

avcodec/mpeg4videodec: Permute quant matrices directly upon IDCT reinit

When switching to the XviD IDCT, the IDCT permutation can change.
Given that we already permute the quant matrices when parsing
them, they need to be permuted, too. Up until now this has not been
done; instead the header has been parsed again in the expectation
that the currently active quant matrix is contained in this header.

This expectation is wrong; it is for example wrong when the VOL
header is only available via extradata (such a file can be easily
created from xvid_vlc_trac7411.h263 (in the FATE suite) via the
remove_extra BSF). It could also be wrong if the XviD user data
is only available in a subsequent packet.

This commit therefore switches to permuting the relevant matrices
directly. It also stops parsing the header a second time
when switching to the XviD IDCT.

(I wonder whether ff_mpv_idct_init() should take alternate_scan
into account when initializing permutated_intra_h_scantable
as the decoder does. Does the MPEG-4 encoder use a wrong scantable
in this case?)

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
Andreas Rheinhardt
2025-05-02 00:57:46 +02:00
parent ca36689b39
commit 6ce86c9c11
3 changed files with 34 additions and 11 deletions

View File

@ -449,7 +449,6 @@ int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict,
return 0;
}
retry:
// s->gb might be overridden in ff_mpeg4_decode_picture_header() below.
ret = init_get_bits8(&s->gb, buf, buf_size);
if (ret < 0)
@ -505,8 +504,7 @@ retry:
if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) {
if (s->pict_type != AV_PICTURE_TYPE_B && s->mb_num/2 > get_bits_left(&s->gb))
return AVERROR_INVALIDDATA;
if (ff_mpeg4_workaround_bugs(avctx) == 1)
goto retry;
ff_mpeg4_workaround_bugs(avctx);
if (s->studio_profile != (s->idsp.idct == NULL))
ff_mpv_idct_init(s);
}

View File

@ -3021,7 +3021,36 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb)
return 0;
}
int ff_mpeg4_workaround_bugs(AVCodecContext *avctx)
static av_cold void permute_quant_matrix(uint16_t matrix[64],
const uint8_t new_perm[64],
const uint8_t old_perm[64])
{
uint16_t tmp[64];
memcpy(tmp, matrix, sizeof(tmp));
for (int i = 0; i < 64; ++i)
matrix[new_perm[i]] = tmp[old_perm[i]];
}
static av_cold void switch_to_xvid_idct(AVCodecContext *const avctx,
MpegEncContext *const s)
{
uint8_t old_permutation[64];
memcpy(old_permutation, s->idsp.idct_permutation, sizeof(old_permutation));
avctx->idct_algo = FF_IDCT_XVID;
ff_mpv_idct_init(s);
ff_permute_scantable(s->permutated_intra_h_scantable,
s->alternate_scan ? ff_alternate_vertical_scan : ff_alternate_horizontal_scan,
s->idsp.idct_permutation);
// Normal (i.e. non-studio) MPEG-4 does not use the chroma matrices.
permute_quant_matrix(s->inter_matrix, s->idsp.idct_permutation, old_permutation);
permute_quant_matrix(s->intra_matrix, s->idsp.idct_permutation, old_permutation);
}
void ff_mpeg4_workaround_bugs(AVCodecContext *avctx)
{
Mpeg4DecContext *ctx = avctx->priv_data;
MpegEncContext *s = &ctx->m;
@ -3129,13 +3158,9 @@ int ff_mpeg4_workaround_bugs(AVCodecContext *avctx)
ctx->divx_version, ctx->divx_build, s->divx_packed ? "p" : "");
if (CONFIG_MPEG4_DECODER && ctx->xvid_build >= 0 &&
avctx->idct_algo == FF_IDCT_AUTO) {
avctx->idct_algo = FF_IDCT_XVID;
ff_mpv_idct_init(s);
return 1;
avctx->idct_algo == FF_IDCT_AUTO && !s->studio_profile) {
switch_to_xvid_idct(avctx, s);
}
return 0;
}
static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb,

View File

@ -111,7 +111,7 @@ void ff_mpeg4_mcsel_motion(MpegEncContext *s,
int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx);
int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx);
int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx);
int ff_mpeg4_workaround_bugs(AVCodecContext *avctx);
void ff_mpeg4_workaround_bugs(AVCodecContext *avctx);
void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n,
int dir);
int ff_mpeg4_frame_end(AVCodecContext *avctx, const AVPacket *pkt);