ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinha...@outlook.com> | 
Fri May  2 00:57:46 2025 +0200| [6ce86c9c110dd7a3e5c3537f9af7ddff095cba20] | 
committer: Andreas Rheinhardt

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.rheinha...@outlook.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=6ce86c9c110dd7a3e5c3537f9af7ddff095cba20
---

 libavcodec/h263dec.c       |  4 +---
 libavcodec/mpeg4videodec.c | 39 ++++++++++++++++++++++++++++++++-------
 libavcodec/mpeg4videodec.h |  2 +-
 3 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
index ddbada9841..fd1e36b68a 100644
--- a/libavcodec/h263dec.c
+++ b/libavcodec/h263dec.c
@@ -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);
     }
diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c
index 5d675d2a78..2eb663603c 100644
--- a/libavcodec/mpeg4videodec.c
+++ b/libavcodec/mpeg4videodec.c
@@ -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,
diff --git a/libavcodec/mpeg4videodec.h b/libavcodec/mpeg4videodec.h
index d3de81c5a9..59a7251ce2 100644
--- a/libavcodec/mpeg4videodec.h
+++ b/libavcodec/mpeg4videodec.h
@@ -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);

_______________________________________________
ffmpeg-cvslog mailing list
ffmpeg-cvslog@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog

To unsubscribe, visit link above, or email
ffmpeg-cvslog-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to