PR #22306 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22306
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22306.patch


>From 4477316805d6d305cfbf9642d41582b9dcdfef0a Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Fri, 27 Feb 2026 06:51:59 +0100
Subject: [PATCH 1/4] avcodec/mpegvideo_enc: Remove redundant emms_c

It is unnecessary since d91b1559e0f61b7ee486c46854013d6c9ddb3e84
(before that the sad_cmp[0] call in get_intra_count() may
have clobbered the floating point state without cleaning it up
itself).

Also remove some commented out emms_c from places where
the floating point state is guaranteed not to have been clobbered
by us.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/mpegvideo_enc.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
index 46c8863a14..aad78eed4a 100644
--- a/libavcodec/mpegvideo_enc.c
+++ b/libavcodec/mpegvideo_enc.c
@@ -1531,7 +1531,6 @@ static int estimate_best_b_count(MPVMainEncContext *const 
m)
     if (!pkt)
         return AVERROR(ENOMEM);
 
-    //emms_c();
     p_lambda = m->last_lambda_for[AV_PICTURE_TYPE_P];
     //p_lambda * FFABS(s->c.avctx->b_quant_factor) + 
s->c.avctx->b_quant_offset;
     b_lambda = m->last_lambda_for[AV_PICTURE_TYPE_B];
@@ -1750,8 +1749,6 @@ static int set_bframe_chain_length(MPVMainEncContext 
*const m)
             }
         }
 
-        emms_c();
-
         for (int i = b_frames - 1; i >= 0; i--) {
             int type = m->input_picture[i]->f->pict_type;
             if (type && type != AV_PICTURE_TYPE_B)
@@ -1975,7 +1972,6 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket 
*pkt,
         }
 
         s->c.pict_type = s->new_pic->pict_type;
-        //emms_c();
         frame_start(m);
 vbv_retry:
         ret = encode_picture(m, pkt);
-- 
2.52.0


>From 459d8380b481bd4bd99492dff81351a3a48211d7 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Fri, 27 Feb 2026 07:08:02 +0100
Subject: [PATCH 2/4] avcodec/snowenc: Add emms_c before allocations

Needed for the allocations in ff_snow_common_init_after_header()
(as well as for calculate_visual_weight() if
spatial_decomposition_count could change).

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/snowenc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c
index f34130f184..43412bb974 100644
--- a/libavcodec/snowenc.c
+++ b/libavcodec/snowenc.c
@@ -1945,6 +1945,7 @@ redo_frame:
                 pic->pict_type= AV_PICTURE_TYPE_I;
                 s->keyframe=1;
                 s->current_picture->flags |= AV_FRAME_FLAG_KEY;
+                emms_c();
                 goto redo_frame;
             }
 
-- 
2.52.0


>From 787ace6551286dd690cc721cd310099fbd55aa22 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Fri, 27 Feb 2026 08:14:12 +0100
Subject: [PATCH 3/4] avutil/emms: Add ff_assert[01]_fpu()

These will be used to mark and check parts of the code
where the floating point state is supposed to be not
clobbered. They are an improvement on the (deprecated)
av_assert0_fpu() because of proper file and line number
information; they also reset the floating point state
if the assert is actually triggered.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavutil/emms.h | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/libavutil/emms.h b/libavutil/emms.h
index 4ec0127457..2b9a456223 100644
--- a/libavutil/emms.h
+++ b/libavutil/emms.h
@@ -19,8 +19,12 @@
 #ifndef AVUTIL_EMMS_H
 #define AVUTIL_EMMS_H
 
+#include <stdint.h>
+#include <stdlib.h>
+
 #include "config.h"
 #include "libavutil/attributes.h"
+#include "libavutil/log.h"
 
 #if ARCH_X86
 
@@ -50,6 +54,28 @@ static av_always_inline void emms_c(void)
 #endif
         __asm__ volatile ("emms" ::: "memory");
 }
+
+static inline void ff_assert0_fpu(const char *file, int line_number)
+{
+    uint16_t state[14];
+     __asm__ volatile (
+        "fstenv %0 \n\t"
+        : "+m" (state)
+        :
+        : "memory"
+    );
+    if ((state[4] & 3) != 3) {
+        emms_c();
+        av_log(NULL, AV_LOG_PANIC,
+               "Invalid floating point state assertion "
+               "triggered at line %u in file %s\n",
+               line_number, file);
+        abort();
+    }
+}
+
+#define ff_assert0_fpu() ff_assert0_fpu(__FILE__, __LINE__)
+
 #elif HAVE_MMX && HAVE_MM_EMPTY
 #   include <mmintrin.h>
 #   define emms_c _mm_empty
@@ -63,4 +89,14 @@ static av_always_inline void emms_c(void)
 #   define emms_c() do {} while(0)
 #endif
 
+#ifndef ff_assert0_fpu
+#define ff_assert0_fpu() ((void)0)
+#endif
+
+#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 1
+#define ff_assert1_fpu() ff_assert0_fpu()
+#else
+#define ff_assert1_fpu() ((void)0)
+#endif
+
 #endif /* AVUTIL_EMMS_H */
-- 
2.52.0


>From d7eb1fedda6d51b0607c0538592962127c198b8a Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Fri, 27 Feb 2026 08:31:05 +0100
Subject: [PATCH 4/4] avcodec/encode: Don't issue emms after encode callback

It is no longer necessary: Most encoders don't use any MMX code
at all any more and the ones that do issue emms on their own.
Instead add an ff_asser1_fpu() to check that it stays that way.

To add some more information, only the halfpel (and fullpel),
qpel and motion estimation APIs use MMX in addition to the
ffvhuff, SBC and Snow specific dsp code. halfpel is used
by the mpegvideo encoders, SVQ1 and Snow encoders. The same
encoders in addition to the AC-3 ones and dvvideo use me_cmp.
qpel is only used by the MPEG4 encoder which is part of
mpegvideo. None of these codecs need the generic emms_c (even on
errors):

a) The AC-3 encoders only use a width 16 me_cmp function which
can no longer use MMX since d91b1559e0f61b7ee486c46854013d6c9ddb3e84.
b) dvvideo, ffvhuff and SBC emit emms on their own and
have no error paths after the start of the part that can use MMX.
c) SVQ1 calls emms_c() on its own, even on all error paths
that need it.
d) Snow calls emms_c() on its ordinary (success) return path;
it has only one error path in the part of the code that uses MMX,
but even it is fine as ratecontrol_1pass() always calls emms_c()
itself.
e) For mpegvideo, the MMX code is mostly confined to the part
of the code reachable from the worker threads (if slice threading
is in use). The exception to this is in skip_check() which always
calls emms_c() itself. Because encode_picture() always calls
emms_c() itself after executing the worker threads and before any
error condition, the floating point state is clean upon exit from
encode_picture().

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/encode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index 407bd8920f..f1a65a9b23 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -236,7 +236,7 @@ int ff_encode_encode_cb(AVCodecContext *avctx, AVPacket 
*avpkt,
     int ret;
 
     ret = codec->cb.encode(avctx, avpkt, frame, got_packet);
-    emms_c();
+    ff_assert1_fpu();
     av_assert0(ret <= 0);
 
     if (!ret && *got_packet) {
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to