Commit a3681a2ed7 for ffmpeg

commit a3681a2ed7b49e0d865d95b5e7ebcaabba29dba3
Author: Niklas Haas <git@haasn.dev>
Date:   Mon Jul 6 15:03:07 2026 +0200

    swscale/uops: move expand_bit from translation stage to optimizer

    In anticipation of SWS_OP_SCALE being nuked.

    Sponsored-by: Sovereign Tech Fund
    Signed-off-by: Niklas Haas <git@haasn.dev>
    Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>

diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c
index a11fee293a..8a48c01fb1 100644
--- a/libswscale/ops_optimizer.c
+++ b/libswscale/ops_optimizer.c
@@ -1011,7 +1011,8 @@ static int solve_shuffle(const SwsUOpList *const uops, SwsUOp *out)
     return AVERROR(EINVAL);
 }

-static int is_integer_scale(const SwsUOp *op, int64_t val)
+/* Only checks exact integer scale ops */
+static bool is_scale(const SwsUOp *op, int64_t val)
 {
     if (op->uop != SWS_UOP_SCALE)
         return false;
@@ -1035,7 +1036,7 @@ retry:

         switch (op->uop) {
         case SWS_UOP_TO_U16:
-            if (is_integer_scale(next, 0x101)) {
+            if (ff_sws_pixel_type_is_int(op->type) && is_scale(next, 0x101)) {
                 op->uop = SWS_UOP_EXPAND_PAIR;
                 ff_sws_uop_list_remove_at(uops, i + 1, 1);
                 goto retry;
@@ -1043,12 +1044,23 @@ retry:
             break;

         case SWS_UOP_TO_U32:
-            if (is_integer_scale(next, 0x1010101)) {
+            if (ff_sws_pixel_type_is_int(op->type) && is_scale(next, 0x1010101)) {
                 op->uop = SWS_UOP_EXPAND_QUAD;
                 ff_sws_uop_list_remove_at(uops, i + 1, 1);
                 goto retry;
             }
             break;
+
+        case SWS_UOP_SCALE:
+            if (flags & SWS_UOP_FLAG_EXPAND_BIT) {
+                const int bits = 8 * ff_sws_pixel_type_size(op->type);
+                if (is_scale(op, UINT64_MAX >> (64 - bits))) {
+                    op->uop = SWS_UOP_EXPAND_BIT;
+                    memset(&op->par, 0, sizeof(op->par));
+                    goto retry;
+                }
+            }
+            break;
         }
     }

diff --git a/libswscale/uops.c b/libswscale/uops.c
index dbcdc07d89..bd9c729402 100644
--- a/libswscale/uops.c
+++ b/libswscale/uops.c
@@ -547,24 +547,6 @@ static int translate_linear_op(SwsContext *ctx, SwsUOpList *ops,
     return ff_sws_uop_list_append(ops, &uop);
 }

-static bool is_expand_bit(SwsPixelType type, AVRational64 factor)
-{
-    if (factor.den != 1)
-        return false;
-
-    switch (type) {
-    case SWS_PIXEL_U8:  return factor.num == UINT8_MAX;
-    case SWS_PIXEL_U16: return factor.num == UINT16_MAX;
-    case SWS_PIXEL_U32: return factor.num == UINT32_MAX;
-    case SWS_PIXEL_F32: return false;
-    case SWS_PIXEL_NONE:
-    case SWS_PIXEL_TYPE_NB: break;
-    }
-
-    av_unreachable("Invalid pixel type!");
-    return false;
-}
-
 static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags,
                         const SwsOp *op, const SwsComps *input)
 {
@@ -633,12 +615,8 @@ static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags,
         }
         break;
     case SWS_OP_SCALE:
-        if ((flags & SWS_UOP_FLAG_EXPAND_BIT) && is_expand_bit(op->type, op->scale.factor)) {
-            uop.uop = SWS_UOP_EXPAND_BIT;
-        } else {
-            uop.uop = SWS_UOP_SCALE;
-            uop.data.scalar = Q2PIXEL(op->scale.factor);
-        }
+        uop.uop = SWS_UOP_SCALE;
+        uop.data.scalar = Q2PIXEL(op->scale.factor);
         break;
     case SWS_OP_MIN:
     case SWS_OP_MAX: