Commit 0ec6a0872d for ffmpeg

commit 0ec6a0872d2aadbf664820487d037479957fd108
Author: Tom Needham <06needhamt@gmail.com>
Date:   Sat Sep 5 22:19:14 2026 +0000

    libavcodec: Add Infinity IMM6 Decoder

    Signed-off-by: Tom Needham <06needhamt@gmail.com>

diff --git a/Changelog b/Changelog
index 32e7c8bfe7..c4f1c4689e 100644
--- a/Changelog
+++ b/Changelog
@@ -19,6 +19,7 @@ version <next>:
 - Panasonic RW2 decoder
 - xHE-AAC encoding via libfdk-xhe-aac
 - jpegapp bitstream filter
+- Infinity IMM6 video decoder


 version 9.0:
diff --git a/configure b/configure
index b724e10929..d2a69d7783 100755
--- a/configure
+++ b/configure
@@ -3185,6 +3185,7 @@ iac_decoder_select="imc_decoder"
 imc_decoder_select="bswapdsp sinewin"
 imm4_decoder_select="bswapdsp idctdsp"
 imm5_decoder_select="h264_decoder hevc_decoder"
+imm6_decoder_select="h264_decoder"
 indeo3_decoder_select="hpeldsp"
 indeo4_decoder_select="ividsp"
 indeo5_decoder_select="ividsp"
diff --git a/doc/APIchanges b/doc/APIchanges
index da21e47e88..4e02c0996d 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2026-06-23.

 API changes, most recent first:

+2026-10-18 - xxxxxxxxxx - lavc 63.21.100 - codec_id.h
+  Add AV_CODEC_ID_IMM6.
+
 2026-10-xx - xxxxxxxxxx - lavf 63.11.100 - avio.h
   Add avio_open_dir2().

diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index 7032f140c6..50bc41c18b 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -1136,6 +1136,8 @@ following image formats are supported:
 @item IFF ByteRun1           @tab     @tab  X
     @tab IFF run length encoded bitmap
 @item Infinity IMM4          @tab     @tab  X
+@item Infinity IMM5          @tab     @tab  X
+@item Infinity IMM6          @tab     @tab  X
 @item Intel H.263            @tab     @tab  X
 @item Intel Indeo 2          @tab     @tab  X
 @item Intel Indeo 3          @tab     @tab  X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 249b0fe0b8..3d0be56320 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -500,6 +500,7 @@ OBJS-$(CONFIG_ILBC_DECODER)            += ilbcdec.o
 OBJS-$(CONFIG_IMC_DECODER)             += imc.o
 OBJS-$(CONFIG_IMM4_DECODER)            += imm4.o
 OBJS-$(CONFIG_IMM5_DECODER)            += imm5.o
+OBJS-$(CONFIG_IMM6_DECODER)            += imm6.o
 OBJS-$(CONFIG_INDEO2_DECODER)          += indeo2.o
 OBJS-$(CONFIG_INDEO3_DECODER)          += indeo3.o
 OBJS-$(CONFIG_INDEO4_DECODER)          += indeo4.o ivi.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index c344cb539e..b12dcc405a 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -173,6 +173,7 @@ extern const FFCodec ff_idcin_decoder;
 extern const FFCodec ff_iff_ilbm_decoder;
 extern const FFCodec ff_imm4_decoder;
 extern const FFCodec ff_imm5_decoder;
+extern const FFCodec ff_imm6_decoder;
 extern const FFCodec ff_indeo2_decoder;
 extern const FFCodec ff_indeo3_decoder;
 extern const FFCodec ff_indeo4_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index e91366f43b..70d8df71f0 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2009,6 +2009,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
         .mime_types= MT("image/x-panasonic-rw2"),
     },
+    {
+	.id        = AV_CODEC_ID_IMM6,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "imm6",
+        .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM6"),
+        .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
+    },

     /* various PCM "codecs" */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 0133751d31..a4e8e30dfd 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -326,6 +326,7 @@ enum AVCodecID {
     AV_CODEC_ID_WEBP_ANIM,
     AV_CODEC_ID_ASTC,
     AV_CODEC_ID_RW2,
+    AV_CODEC_ID_IMM6,

     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/imm6.c b/libavcodec/imm6.c
new file mode 100644
index 0000000000..caca0459c9
--- /dev/null
+++ b/libavcodec/imm6.c
@@ -0,0 +1,196 @@
+/*
+ * Infinity IMM6 video decoder
+ *
+ * Copyright (c) 2026 Tom Needham
+ *
+ * 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
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/attributes_internal.h"
+#include "libavutil/intreadwrite.h"
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "decode.h"
+
+typedef struct IMM6Context {
+    AVCodecContext *h264_avctx;
+    int draining;
+} IMM6Context;
+
+static av_cold int imm6_init(AVCodecContext *avctx)
+{
+    IMM6Context *s = avctx->priv_data;
+    int ret;
+
+    EXTERN const FFCodec ff_h264_decoder;
+
+    s->h264_avctx = avcodec_alloc_context3(&ff_h264_decoder.p);
+    if (!s->h264_avctx)
+        return AVERROR(ENOMEM);
+
+    /* The wrapper delegates threading to the nested H.264 decoder. */
+    s->h264_avctx->thread_count     = avctx->thread_count;
+    s->h264_avctx->thread_type      = avctx->thread_type;
+    s->h264_avctx->flags            = avctx->flags;
+    s->h264_avctx->flags2           = avctx->flags2;
+    s->h264_avctx->max_pixels       = avctx->max_pixels;
+    s->h264_avctx->pkt_timebase     = avctx->pkt_timebase;
+    s->h264_avctx->skip_frame       = avctx->skip_frame;
+    s->h264_avctx->skip_loop_filter = avctx->skip_loop_filter;
+    s->h264_avctx->apply_cropping   = 0;
+
+    ret = avcodec_open2(s->h264_avctx, NULL, NULL);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int imm6_send_packet(AVCodecContext *avctx, AVPacket *pkt)
+{
+    IMM6Context *s = avctx->priv_data;
+    AVPacket h264_pkt;
+    uint32_t payload_size;
+    int ret;
+
+    if (pkt->size < 24) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Packet too small for IMM6 header: %d bytes\n", pkt->size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (pkt->data[8] > 1) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Invalid IMM6 mode %u\n", pkt->data[8]);
+        return AVERROR_INVALIDDATA;
+    }
+
+    payload_size = AV_RL32(pkt->data + 4);
+    if (payload_size > (unsigned)pkt->size - 24) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Invalid IMM6 payload size %u in %d-byte packet\n",
+               payload_size, pkt->size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    h264_pkt       = *pkt;
+    h264_pkt.data += 24;
+    h264_pkt.size  = payload_size;
+
+    s->h264_avctx->skip_frame       = avctx->skip_frame;
+    s->h264_avctx->skip_loop_filter = avctx->skip_loop_filter;
+
+    ret = avcodec_send_packet(s->h264_avctx, &h264_pkt);
+    if (ret < 0 && ret != AVERROR(EAGAIN))
+        av_log(avctx, AV_LOG_ERROR,
+               "Error submitting IMM6 H.264 payload for decoding\n");
+
+    return ret;
+}
+
+static void imm6_update_context(AVCodecContext *avctx)
+{
+    IMM6Context *s = avctx->priv_data;
+    AVCodecContext *h264 = s->h264_avctx;
+
+    avctx->pix_fmt                = h264->pix_fmt;
+    avctx->coded_width            = h264->coded_width;
+    avctx->coded_height           = h264->coded_height;
+    avctx->width                  = h264->width;
+    avctx->height                 = h264->height;
+    avctx->delay                  = h264->delay;
+    avctx->colorspace             = h264->colorspace;
+    avctx->color_range            = h264->color_range;
+    avctx->color_trc              = h264->color_trc;
+    avctx->color_primaries        = h264->color_primaries;
+    avctx->chroma_sample_location = h264->chroma_sample_location;
+    avctx->sample_aspect_ratio    = h264->sample_aspect_ratio;
+    avctx->has_b_frames           = h264->has_b_frames;
+}
+
+static int imm6_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+    IMM6Context *s = avctx->priv_data;
+    AVPacket pkt = { 0 };
+    int ret;
+
+    for (;;) {
+        ret = avcodec_receive_frame(s->h264_avctx, frame);
+        if (ret >= 0) {
+            imm6_update_context(avctx);
+            return 0;
+        }
+        if (ret == AVERROR_EOF)
+            return ret;
+        if (ret != AVERROR(EAGAIN))
+            return ret;
+
+        if (s->draining)
+            return AVERROR(EAGAIN);
+
+        ret = ff_decode_get_packet(avctx, &pkt);
+        if (ret == AVERROR(EAGAIN))
+            return ret;
+        if (ret == AVERROR_EOF) {
+            s->draining = 1;
+            ret = avcodec_send_packet(s->h264_avctx, NULL);
+            if (ret < 0 && ret != AVERROR_EOF && ret != AVERROR(EAGAIN))
+                return ret;
+            continue;
+        }
+        if (ret < 0)
+            return ret;
+
+        ret = imm6_send_packet(avctx, &pkt);
+        av_packet_unref(&pkt);
+        if (ret < 0)
+            return ret;
+    }
+}
+
+static av_cold void imm6_flush(AVCodecContext *avctx)
+{
+    IMM6Context *s = avctx->priv_data;
+
+    avcodec_flush_buffers(s->h264_avctx);
+    s->draining = 0;
+}
+
+static av_cold int imm6_close(AVCodecContext *avctx)
+{
+    IMM6Context *s = avctx->priv_data;
+
+    avcodec_free_context(&s->h264_avctx);
+
+    return 0;
+}
+
+const FFCodec ff_imm6_decoder = {
+    .p.name         = "imm6",
+    CODEC_LONG_NAME("Infinity IMM6"),
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_IMM6,
+    .init           = imm6_init,
+    FF_CODEC_RECEIVE_FRAME_CB(imm6_receive_frame),
+    .close          = imm6_close,
+    .flush          = imm6_flush,
+    .priv_data_size = sizeof(IMM6Context),
+    .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS,
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index ef9018e70b..9f3de34a5c 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,8 +29,8 @@

 #include "version_major.h"

-#define LIBAVCODEC_VERSION_MINOR  20
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR  2
+#define LIBAVCODEC_VERSION_MICRO 100

 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \