Commit 9d6c50f258 for ffmpeg

commit 9d6c50f258a94911969924098e20c32b613b5487
Author: Devin Heitmueller <dheitmueller@ltnglobal.com>
Date:   Mon Sep 21 15:44:09 2026 -0400

    avcodec/bitpacked: refactor to support assembly optimizations

    Move the packed YUV422P10 unpacking loop behind a function pointer and keep the existing C implementation as the default.

    Process multiples of eight through the DSP-style interface while retaining the C path for any remaining pixels. This provides a directly testable interface for later architecture-specific implementations without changing decoded output.

diff --git a/libavcodec/bitpacked_dec.c b/libavcodec/bitpacked_dec.c
index a1d3b7b505..8d88c556cc 100644
--- a/libavcodec/bitpacked_dec.c
+++ b/libavcodec/bitpacked_dec.c
@@ -27,15 +27,12 @@
  */

 #include "avcodec.h"
+#include "bitpacked_dec.h"
+#include "bitpacked_dec_init.h"
 #include "codec_internal.h"
 #include "libavutil/imgutils.h"
 #include "thread.h"

-struct BitpackedContext {
-    int (*decode)(AVCodecContext *avctx, AVFrame *frame,
-                  const AVPacket *pkt);
-};
-
 /* For this format, it's a simple passthrough */
 static int bitpacked_decode_uyvy422(AVCodecContext *avctx, AVFrame *frame,
                                     const AVPacket *avpkt)
@@ -62,11 +59,13 @@ static int bitpacked_decode_uyvy422(AVCodecContext *avctx, AVFrame *frame,
 static int bitpacked_decode_yuv422p10(AVCodecContext *avctx, AVFrame *frame,
                                       const AVPacket *avpkt)
 {
+    struct BitpackedContext *bc = avctx->priv_data;
     uint64_t frame_size = (uint64_t)avctx->width * (uint64_t)avctx->height * 20;
     uint64_t packet_size = (uint64_t)avpkt->size * 8;
-    uint8_t *src;
+    const uint8_t *src;
     uint16_t *y, *u, *v;
-    int ret, i, j;
+    const int bulk = avctx->width & ~7;
+    int ret, i;

     ret = ff_thread_get_buffer(avctx, frame, 0);
     if (ret < 0)
@@ -84,13 +83,16 @@ static int bitpacked_decode_yuv422p10(AVCodecContext *avctx, AVFrame *frame,
         u = (uint16_t*)(frame->data[1] + i * frame->linesize[1]);
         v = (uint16_t*)(frame->data[2] + i * frame->linesize[2]);

-        for (j = 0; j < avctx->width; j += 2) {
-            *u++ = (src[0] << 2) | (src[1] >> 6);
-            *v++ = ((src[2] << 6) | (src[3] >> 2)) & 0x3ff;
-            *y++ = ((src[1] << 4) | (src[2] >> 4)) & 0x3ff;
-            *y++ = ((src[3] << 8) | (src[4]))      & 0x3ff;
-            src += 5;
+        if (bulk) {
+            bc->unpack_yuv422p10(src, y, u, v, bulk);
+            src += bulk * 5 / 2;
+            y   += bulk;
+            u   += bulk / 2;
+            v   += bulk / 2;
         }
+
+        bitpacked_unpack_yuv422p10_c(src, y, u, v, avctx->width - bulk);
+        src += (avctx->width - bulk) * 5 / 2;
     }

     return 0;
@@ -103,6 +105,8 @@ static av_cold int bitpacked_init_decoder(AVCodecContext *avctx)
     if (!avctx->codec_tag || !avctx->width || !avctx->height)
         return AVERROR_INVALIDDATA;

+    ff_bitpackeddec_init(bc);
+
     if (avctx->codec_tag == MKTAG('U', 'Y', 'V', 'Y')) {
         if (avctx->bits_per_coded_sample == 16 &&
             avctx->pix_fmt == AV_PIX_FMT_UYVY422)
diff --git a/libavcodec/bitpacked_dec.h b/libavcodec/bitpacked_dec.h
new file mode 100644
index 0000000000..a92c94ab29
--- /dev/null
+++ b/libavcodec/bitpacked_dec.h
@@ -0,0 +1,39 @@
+/*
+ * Unpack bit-packed streams to formats supported by FFmpeg
+ * Copyright (c) 2026 Devin Heitmueller <dheitmueller@ltnglobal.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_BITPACKED_DEC_H
+#define AVCODEC_BITPACKED_DEC_H
+
+#include <stdint.h>
+
+#include "avcodec.h"
+
+struct BitpackedContext {
+    int (*decode)(AVCodecContext *avctx, AVFrame *frame,
+                  const AVPacket *pkt);
+
+    /* width must be a positive multiple of 8; src contains width * 5 / 2 bytes. */
+    void (*unpack_yuv422p10)(const uint8_t *src,
+                             uint16_t *y, uint16_t *u, uint16_t *v,
+                             int width);
+};
+
+#endif /* AVCODEC_BITPACKED_DEC_H */
diff --git a/libavcodec/bitpacked_dec_init.h b/libavcodec/bitpacked_dec_init.h
new file mode 100644
index 0000000000..a7a0d257c3
--- /dev/null
+++ b/libavcodec/bitpacked_dec_init.h
@@ -0,0 +1,51 @@
+/*
+ * Bitpacked decoder DSP init
+ * Copyright (c) 2017 Savoir-faire Linux, Inc
+ * Copyright (c) 2026 Devin Heitmueller <dheitmueller@ltnglobal.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_BITPACKED_DEC_INIT_H
+#define AVCODEC_BITPACKED_DEC_INIT_H
+
+#include <stdint.h>
+
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "bitpacked_dec.h"
+
+static void bitpacked_unpack_yuv422p10_c(const uint8_t *src,
+                                         uint16_t *y, uint16_t *u, uint16_t *v,
+                                         int width)
+{
+    for (int i = 0; i < width; i += 2) {
+        *u++ =  (src[0] << 2) | (src[1] >> 6);
+        *v++ = ((src[2] << 6) | (src[3] >> 2)) & 0x3ff;
+        *y++ = ((src[1] << 4) | (src[2] >> 4)) & 0x3ff;
+        *y++ = ((src[3] << 8) |  src[4])       & 0x3ff;
+        src += 5;
+    }
+}
+
+av_unused static av_cold void ff_bitpackeddec_init(struct BitpackedContext *s)
+{
+    s->unpack_yuv422p10 = bitpacked_unpack_yuv422p10_c;
+
+}
+
+#endif /* AVCODEC_BITPACKED_DEC_INIT_H */