Commit 10cd9794 for libheif

commit 10cd9794a098ec33867738d0648f7cab544ad9d8
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Sun Feb 8 20:19:30 2026 +0100

    unci: refactor AbstractDecoder and subclasses to unc_decoder similar to unc_encoder

diff --git a/libheif/CMakeLists.txt b/libheif/CMakeLists.txt
index 8954a72c..6e789e0b 100644
--- a/libheif/CMakeLists.txt
+++ b/libheif/CMakeLists.txt
@@ -293,18 +293,18 @@ if (WITH_UNCOMPRESSED_CODEC)
             codecs/uncompressed/unc_dec.cc
             codecs/uncompressed/unc_enc.h
             codecs/uncompressed/unc_enc.cc
-            codecs/uncompressed/decoder_abstract.h
-            codecs/uncompressed/decoder_abstract.cc
-            codecs/uncompressed/decoder_component_interleave.h
-            codecs/uncompressed/decoder_component_interleave.cc
-            codecs/uncompressed/decoder_pixel_interleave.h
-            codecs/uncompressed/decoder_pixel_interleave.cc
-            codecs/uncompressed/decoder_mixed_interleave.h
-            codecs/uncompressed/decoder_mixed_interleave.cc
-            codecs/uncompressed/decoder_row_interleave.h
-            codecs/uncompressed/decoder_row_interleave.cc
-            codecs/uncompressed/decoder_tile_component_interleave.h
-            codecs/uncompressed/decoder_tile_component_interleave.cc
+            codecs/uncompressed/unc_decoder.h
+            codecs/uncompressed/unc_decoder.cc
+            codecs/uncompressed/unc_decoder_component_interleave.h
+            codecs/uncompressed/unc_decoder_component_interleave.cc
+            codecs/uncompressed/unc_decoder_pixel_interleave.h
+            codecs/uncompressed/unc_decoder_pixel_interleave.cc
+            codecs/uncompressed/unc_decoder_mixed_interleave.h
+            codecs/uncompressed/unc_decoder_mixed_interleave.cc
+            codecs/uncompressed/unc_decoder_row_interleave.h
+            codecs/uncompressed/unc_decoder_row_interleave.cc
+            codecs/uncompressed/unc_decoder_tile_component_interleave.h
+            codecs/uncompressed/unc_decoder_tile_component_interleave.cc
             codecs/uncompressed/unc_encoder.h
             codecs/uncompressed/unc_encoder.cc
             codecs/uncompressed/unc_encoder_rgb3_rgba.cc
diff --git a/libheif/codecs/uncompressed/unc_codec.cc b/libheif/codecs/uncompressed/unc_codec.cc
index a8dfb7e4..cde86830 100644
--- a/libheif/codecs/uncompressed/unc_codec.cc
+++ b/libheif/codecs/uncompressed/unc_codec.cc
@@ -27,12 +27,8 @@
 #include "unc_types.h"
 #include "unc_boxes.h"

-#include "decoder_abstract.h"
-#include "decoder_component_interleave.h"
-#include "decoder_pixel_interleave.h"
-#include "decoder_mixed_interleave.h"
-#include "decoder_row_interleave.h"
-#include "decoder_tile_component_interleave.h"
+#include "unc_decoder.h"
+#include "codecs/decoder.h"

 #include <algorithm>
 #include <map>
@@ -445,25 +441,6 @@ bool map_uncompressed_component_to_channel(const std::shared_ptr<const Box_cmpd>



-static AbstractDecoder* makeDecoder(uint32_t width, uint32_t height, const std::shared_ptr<const Box_cmpd>& cmpd, const std::shared_ptr<const Box_uncC>& uncC)
-{
-  switch (uncC->get_interleave_type()) {
-    case interleave_mode_component:
-      return new ComponentInterleaveDecoder(width, height, cmpd, uncC);
-    case interleave_mode_pixel:
-      return new PixelInterleaveDecoder(width, height, cmpd, uncC);
-    case interleave_mode_mixed:
-      return new MixedInterleaveDecoder(width, height, cmpd, uncC);
-    case interleave_mode_row:
-      return new RowInterleaveDecoder(width, height, cmpd, uncC);
-    case interleave_mode_tile_component:
-      return new TileComponentInterleaveDecoder(width, height, cmpd, uncC);
-    default:
-      return nullptr;
-  }
-}
-
-
 Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(const std::shared_ptr<const Box_cmpd> cmpd,
                                                                              const std::shared_ptr<const Box_uncC> uncC,
                                                                              uint32_t width,
@@ -543,26 +520,21 @@ Error UncompressedImageCodec::decode_uncompressed_image_tile(const HeifContext*

   img = *createImgResult;

-
-  AbstractDecoder* decoder = makeDecoder(ispe->get_width(), ispe->get_height(), cmpd, uncC);
-  if (decoder == nullptr) {
-    std::stringstream sstr;
-    sstr << "Uncompressed interleave_type of " << ((int) uncC->get_interleave_type()) << " is not implemented yet";
-    return Error(heif_error_Unsupported_feature,
-                 heif_suberror_Unsupported_data_version,
-                 sstr.str());
+  auto decoderResult = unc_decoder_factory::get_unc_decoder(ispe->get_width(), ispe->get_height(), cmpd, uncC);
+  if (!decoderResult) {
+    return decoderResult.error();
   }

+  auto& decoder = *decoderResult;
+
   decoder->buildChannelList(img);

   DataExtent dataExtent;
   dataExtent.set_from_image_item(file, ID);

-  Error result = decoder->decode_tile(dataExtent, properties, img, 0, 0,
-                                      ispe->get_width(), ispe->get_height(),
-                                      tile_x0, tile_y0);
-  delete decoder;
-  return result;
+  return decoder->decode_tile(dataExtent, properties, img, 0, 0,
+                              ispe->get_width(), ispe->get_height(),
+                              tile_x0, tile_y0);
 }


@@ -685,44 +657,15 @@ Error UncompressedImageCodec::decode_uncompressed_image(const HeifContext* conte
     };
   }

-  Result<std::shared_ptr<HeifPixelImage>> createImgResult = create_image(cmpd, uncC, width, height, context->get_security_limits());
-  if (!createImgResult) {
-    return createImgResult.error();
-  }
-  else {
-    img = *createImgResult;
-  }
-
-  AbstractDecoder* decoder = makeDecoder(width, height, cmpd, uncC);
-  if (decoder == nullptr) {
-    std::stringstream sstr;
-    sstr << "Uncompressed interleave_type of " << ((int) uncC->get_interleave_type()) << " is not implemented yet";
-    return Error(heif_error_Unsupported_feature,
-                 heif_suberror_Unsupported_data_version,
-                 sstr.str());
-  }
-
-  decoder->buildChannelList(img);
-
-  uint32_t tile_width = width / uncC->get_number_of_tile_columns();
-  uint32_t tile_height = height / uncC->get_number_of_tile_rows();
-
   DataExtent dataExtent;
   dataExtent.set_from_image_item(context->get_heif_file(), ID);

-  for (uint32_t tile_y0 = 0; tile_y0 < height; tile_y0 += tile_height)
-    for (uint32_t tile_x0 = 0; tile_x0 < width; tile_x0 += tile_width) {
-      error = decoder->decode_tile(dataExtent, properties, img, tile_x0, tile_y0,
-                                   width, height,
-                                   tile_x0 / tile_width, tile_y0 / tile_height);
-      if (error) {
-        delete decoder;
-        return error;
-      }
-    }
+  auto result = unc_decoder::decode_full_image(properties, dataExtent, context->get_security_limits());
+  if (!result) {
+    return result.error();
+  }

-  //Error result = decoder->decode(source_data, img);
-  delete decoder;
+  img = *result;
   return Error::Ok;
 }

@@ -742,8 +685,6 @@ UncompressedImageCodec::decode_uncompressed_image(const UncompressedImageCodec::
                                                   const DataExtent& extent,
                                                   const heif_security_limits* securityLimits)
 {
-  std::shared_ptr<HeifPixelImage> img;
-
   const std::shared_ptr<const Box_ispe>& ispe = properties.ispe;
   const std::shared_ptr<const Box_cmpd>& cmpd = properties.cmpd;
   const std::shared_ptr<const Box_uncC>& uncC = properties.uncC;
@@ -777,40 +718,5 @@ UncompressedImageCodec::decode_uncompressed_image(const UncompressedImageCodec::
     };
   }

-  Result<std::shared_ptr<HeifPixelImage>> createImgResult = create_image(cmpd, uncC, width, height, securityLimits);
-  if (!createImgResult) {
-    return createImgResult.error();
-  }
-  else {
-    img = *createImgResult;
-  }
-
-  AbstractDecoder* decoder = makeDecoder(width, height, cmpd, uncC);
-  if (decoder == nullptr) {
-    std::stringstream sstr;
-    sstr << "Uncompressed interleave_type of " << ((int) uncC->get_interleave_type()) << " is not implemented yet";
-    return Error(heif_error_Unsupported_feature,
-                 heif_suberror_Unsupported_data_version,
-                 sstr.str());
-  }
-
-  decoder->buildChannelList(img);
-
-  uint32_t tile_width = width / uncC->get_number_of_tile_columns();
-  uint32_t tile_height = height / uncC->get_number_of_tile_rows();
-
-  for (uint32_t tile_y0 = 0; tile_y0 < height; tile_y0 += tile_height)
-    for (uint32_t tile_x0 = 0; tile_x0 < width; tile_x0 += tile_width) {
-      error = decoder->decode_tile(extent, properties, img, tile_x0, tile_y0,
-                                   width, height,
-                                   tile_x0 / tile_width, tile_y0 / tile_height);
-      if (error) {
-        delete decoder;
-        return error;
-      }
-    }
-
-  //Error result = decoder->decode(source_data, img);
-  delete decoder;
-  return img;
+  return unc_decoder::decode_full_image(properties, extent, securityLimits);
 }
diff --git a/libheif/codecs/uncompressed/decoder_abstract.cc b/libheif/codecs/uncompressed/unc_decoder.cc
similarity index 70%
rename from libheif/codecs/uncompressed/decoder_abstract.cc
rename to libheif/codecs/uncompressed/unc_decoder.cc
index 2927dc54..bffd52f3 100644
--- a/libheif/codecs/uncompressed/decoder_abstract.cc
+++ b/libheif/codecs/uncompressed/unc_decoder.cc
@@ -38,12 +38,18 @@
 #include "unc_types.h"
 #include "unc_boxes.h"
 #include "unc_codec.h"
-#include "decoder_abstract.h"
+#include "unc_decoder.h"
+#include "unc_decoder_component_interleave.h"
+#include "unc_decoder_pixel_interleave.h"
+#include "unc_decoder_mixed_interleave.h"
+#include "unc_decoder_row_interleave.h"
+#include "unc_decoder_tile_component_interleave.h"
 #include "codecs/decoder.h"
 #include "codecs/uncompressed/unc_codec.h"
+#include "security_limits.h"


-AbstractDecoder::AbstractDecoder(uint32_t width, uint32_t height, const std::shared_ptr<const Box_cmpd> cmpd, const std::shared_ptr<const Box_uncC> uncC) :
+unc_decoder::unc_decoder(uint32_t width, uint32_t height, const std::shared_ptr<const Box_cmpd> cmpd, const std::shared_ptr<const Box_uncC> uncC) :
     m_width(width),
     m_height(height),
     m_cmpd(std::move(cmpd)),
@@ -56,7 +62,7 @@ AbstractDecoder::AbstractDecoder(uint32_t width, uint32_t height, const std::sha
   assert(m_tile_height > 0);
 }

-void AbstractDecoder::buildChannelList(std::shared_ptr<HeifPixelImage>& img)
+void unc_decoder::buildChannelList(std::shared_ptr<HeifPixelImage>& img)
 {
   for (Box_uncC::Component component : m_uncC->get_components()) {
     ChannelListEntry entry = buildChannelListEntry(component, img);
@@ -64,7 +70,7 @@ void AbstractDecoder::buildChannelList(std::shared_ptr<HeifPixelImage>& img)
   }
 }

-void AbstractDecoder::memcpy_to_native_endian(uint8_t* dst, uint32_t value, uint32_t bytes_per_sample)
+void unc_decoder::memcpy_to_native_endian(uint8_t* dst, uint32_t value, uint32_t bytes_per_sample)
 {
   // TODO: this assumes that the file endianness is always big-endian. The endianness flags in the uncC header are not taken into account yet.

@@ -84,7 +90,7 @@ void AbstractDecoder::memcpy_to_native_endian(uint8_t* dst, uint32_t value, uint
   }
 }

-void AbstractDecoder::processComponentSample(UncompressedBitReader& srcBits, const ChannelListEntry& entry, uint64_t dst_row_offset, uint32_t tile_column, uint32_t tile_x)
+void unc_decoder::processComponentSample(UncompressedBitReader& srcBits, const ChannelListEntry& entry, uint64_t dst_row_offset, uint32_t tile_column, uint32_t tile_x)
 {
   uint64_t dst_col_number = static_cast<uint64_t>(tile_column) * entry.tile_width + tile_x;
   uint64_t dst_column_offset = dst_col_number * entry.bytes_per_component_sample;
@@ -96,7 +102,7 @@ void AbstractDecoder::processComponentSample(UncompressedBitReader& srcBits, con
 // Not valid for Pixel interleave
 // Not valid for the Cb/Cr channels in Mixed Interleave
 // Not valid for multi-Y pixel interleave
-void AbstractDecoder::processComponentRow(ChannelListEntry& entry, UncompressedBitReader& srcBits, uint64_t dst_row_offset, uint32_t tile_column)
+void unc_decoder::processComponentRow(ChannelListEntry& entry, UncompressedBitReader& srcBits, uint64_t dst_row_offset, uint32_t tile_column)
 {
   for (uint32_t tile_x = 0; tile_x < entry.tile_width; tile_x++) {
     if (entry.component_alignment != 0) {
@@ -109,7 +115,7 @@ void AbstractDecoder::processComponentRow(ChannelListEntry& entry, UncompressedB
   srcBits.skip_to_byte_boundary();
 }

-void AbstractDecoder::processComponentTileSample(UncompressedBitReader& srcBits, const ChannelListEntry& entry, uint64_t dst_offset, uint32_t tile_x)
+void unc_decoder::processComponentTileSample(UncompressedBitReader& srcBits, const ChannelListEntry& entry, uint64_t dst_offset, uint32_t tile_x)
 {
   uint64_t dst_sample_offset = uint64_t{tile_x} * entry.bytes_per_component_sample;
   int val = srcBits.get_bits(entry.bits_per_component_sample);
@@ -120,7 +126,7 @@ void AbstractDecoder::processComponentTileSample(UncompressedBitReader& srcBits,
 // Not valid for Pixel interleave
 // Not valid for the Cb/Cr channels in Mixed Interleave
 // Not valid for multi-Y pixel interleave
-void AbstractDecoder::processComponentTileRow(ChannelListEntry& entry, UncompressedBitReader& srcBits, uint64_t dst_offset)
+void unc_decoder::processComponentTileRow(ChannelListEntry& entry, UncompressedBitReader& srcBits, uint64_t dst_offset)
 {
   for (uint32_t tile_x = 0; tile_x < entry.tile_width; tile_x++) {
     if (entry.component_alignment != 0) {
@@ -134,8 +140,8 @@ void AbstractDecoder::processComponentTileRow(ChannelListEntry& entry, Uncompres
 }


-AbstractDecoder::ChannelListEntry AbstractDecoder::buildChannelListEntry(Box_uncC::Component component,
-                                                                         std::shared_ptr<HeifPixelImage>& img)
+unc_decoder::ChannelListEntry unc_decoder::buildChannelListEntry(Box_uncC::Component component,
+                                                                  std::shared_ptr<HeifPixelImage>& img)
 {
   ChannelListEntry entry;
   entry.use_channel = map_uncompressed_component_to_channel(m_cmpd, m_uncC, component, &(entry.channel));
@@ -166,12 +172,12 @@ AbstractDecoder::ChannelListEntry AbstractDecoder::buildChannelListEntry(Box_unc
 }


-const Error AbstractDecoder::get_compressed_image_data_uncompressed(const DataExtent& dataExtent,
-                                                                    const UncompressedImageCodec::unci_properties& properties,
-                                                                    std::vector<uint8_t>* data,
-                                                                    uint64_t range_start_offset, uint64_t range_size,
-                                                                    uint32_t tile_idx,
-                                                                    const Box_iloc::Item* item) const
+const Error unc_decoder::get_compressed_image_data_uncompressed(const DataExtent& dataExtent,
+                                                                 const UncompressedImageCodec::unci_properties& properties,
+                                                                 std::vector<uint8_t>* data,
+                                                                 uint64_t range_start_offset, uint64_t range_size,
+                                                                 uint32_t tile_idx,
+                                                                 const Box_iloc::Item* item) const
 {
   // --- get codec configuration

@@ -289,8 +295,8 @@ const Error AbstractDecoder::get_compressed_image_data_uncompressed(const DataEx
 }


-Result<std::vector<uint8_t>> AbstractDecoder::do_decompress_data(std::shared_ptr<const Box_cmpC>& cmpC_box,
-                                                                 std::vector<uint8_t> compressed_data) const
+Result<std::vector<uint8_t>> unc_decoder::do_decompress_data(std::shared_ptr<const Box_cmpC>& cmpC_box,
+                                                              std::vector<uint8_t> compressed_data) const
 {
   if (cmpC_box->get_compression_type() == fourcc("brot")) {
 #if HAVE_BROTLI
@@ -333,3 +339,93 @@ Result<std::vector<uint8_t>> AbstractDecoder::do_decompress_data(std::shared_ptr
                  sstr.str());
   }
 }
+
+
+// --- unc_decoder_factory ---
+
+Result<std::unique_ptr<unc_decoder>> unc_decoder_factory::get_unc_decoder(
+    uint32_t width, uint32_t height,
+    const std::shared_ptr<const Box_cmpd>& cmpd,
+    const std::shared_ptr<const Box_uncC>& uncC)
+{
+  static unc_decoder_factory_component_interleave dec_component;
+  static unc_decoder_factory_pixel_interleave dec_pixel;
+  static unc_decoder_factory_mixed_interleave dec_mixed;
+  static unc_decoder_factory_row_interleave dec_row;
+  static unc_decoder_factory_tile_component_interleave dec_tile_component;
+
+  static const unc_decoder_factory* decoders[]{
+    &dec_component, &dec_pixel, &dec_mixed, &dec_row, &dec_tile_component
+  };
+
+  for (const unc_decoder_factory* dec : decoders) {
+    if (dec->can_decode(uncC)) {
+      return {dec->create(width, height, cmpd, uncC)};
+    }
+  }
+
+  std::stringstream sstr;
+  sstr << "Uncompressed interleave_type of " << ((int) uncC->get_interleave_type()) << " is not implemented yet";
+  return Error{heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, sstr.str()};
+}
+
+
+// --- decode orchestration ---
+
+Result<std::shared_ptr<HeifPixelImage>> unc_decoder::decode_full_image(
+    const UncompressedImageCodec::unci_properties& properties,
+    const DataExtent& extent,
+    const heif_security_limits* limits)
+{
+  const std::shared_ptr<const Box_ispe>& ispe = properties.ispe;
+  const std::shared_ptr<const Box_cmpd>& cmpd = properties.cmpd;
+  const std::shared_ptr<const Box_uncC>& uncC = properties.uncC;
+
+  assert(ispe);
+  uint32_t width = ispe->get_width();
+  uint32_t height = ispe->get_height();
+
+  Result<std::shared_ptr<HeifPixelImage>> createImgResult = UncompressedImageCodec::create_image(cmpd, uncC, width, height, limits);
+  if (!createImgResult) {
+    return createImgResult.error();
+  }
+
+  auto img = *createImgResult;
+
+  auto decoderResult = unc_decoder_factory::get_unc_decoder(width, height, cmpd, uncC);
+  if (!decoderResult) {
+    return decoderResult.error();
+  }
+
+  auto& decoder = *decoderResult;
+
+  decoder->buildChannelList(img);
+
+  Error error = decoder->decode_image(extent, properties, img);
+  if (error) {
+    return error;
+  }
+
+  return img;
+}
+
+
+Error unc_decoder::decode_image(const DataExtent& extent,
+                                const UncompressedImageCodec::unci_properties& properties,
+                                std::shared_ptr<HeifPixelImage>& img)
+{
+  uint32_t tile_width = m_width / m_uncC->get_number_of_tile_columns();
+  uint32_t tile_height = m_height / m_uncC->get_number_of_tile_rows();
+
+  for (uint32_t tile_y0 = 0; tile_y0 < m_height; tile_y0 += tile_height)
+    for (uint32_t tile_x0 = 0; tile_x0 < m_width; tile_x0 += tile_width) {
+      Error error = decode_tile(extent, properties, img, tile_x0, tile_y0,
+                                m_width, m_height,
+                                tile_x0 / tile_width, tile_y0 / tile_height);
+      if (error) {
+        return error;
+      }
+    }
+
+  return Error::Ok;
+}
diff --git a/libheif/codecs/uncompressed/decoder_abstract.h b/libheif/codecs/uncompressed/unc_decoder.h
similarity index 84%
rename from libheif/codecs/uncompressed/decoder_abstract.h
rename to libheif/codecs/uncompressed/unc_decoder.h
index 80a25899..2796136a 100644
--- a/libheif/codecs/uncompressed/decoder_abstract.h
+++ b/libheif/codecs/uncompressed/unc_decoder.h
@@ -18,8 +18,8 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#ifndef UNCI_DECODER_ABSTRACT_H
-#define UNCI_DECODER_ABSTRACT_H
+#ifndef LIBHEIF_UNC_DECODER_H
+#define LIBHEIF_UNC_DECODER_H

 #include <cstdint>
 #include <cstring>
@@ -128,10 +128,10 @@ template<typename T> void skip_to_alignment(T& position, uint32_t alignment)
 }


-class AbstractDecoder
+class unc_decoder
 {
 public:
-  virtual ~AbstractDecoder() = default;
+  virtual ~unc_decoder() = default;

   virtual Error decode_tile(const DataExtent& dataExtent,
                             const UncompressedImageCodec::unci_properties& properties,
@@ -142,10 +142,19 @@ public:

   void buildChannelList(std::shared_ptr<HeifPixelImage>& img);

+  static Result<std::shared_ptr<HeifPixelImage>> decode_full_image(
+      const UncompressedImageCodec::unci_properties& properties,
+      const DataExtent& extent,
+      const heif_security_limits* limits);
+
+  Error decode_image(const DataExtent& extent,
+                     const UncompressedImageCodec::unci_properties& properties,
+                     std::shared_ptr<HeifPixelImage>& img);
+
 protected:
-  AbstractDecoder(uint32_t width, uint32_t height,
-                  const std::shared_ptr<const Box_cmpd> cmpd,
-                  const std::shared_ptr<const Box_uncC> uncC);
+  unc_decoder(uint32_t width, uint32_t height,
+              const std::shared_ptr<const Box_cmpd> cmpd,
+              const std::shared_ptr<const Box_uncC> uncC);

   const uint32_t m_width;
   const uint32_t m_height;
@@ -219,4 +228,24 @@ private:
   ChannelListEntry buildChannelListEntry(Box_uncC::Component component, std::shared_ptr<HeifPixelImage>& img);
 };

+
+class unc_decoder_factory
+{
+public:
+  virtual ~unc_decoder_factory() = default;
+
+  static Result<std::unique_ptr<unc_decoder>> get_unc_decoder(
+      uint32_t width, uint32_t height,
+      const std::shared_ptr<const Box_cmpd>& cmpd,
+      const std::shared_ptr<const Box_uncC>& uncC);
+
+private:
+  virtual bool can_decode(const std::shared_ptr<const Box_uncC>& uncC) const = 0;
+
+  virtual std::unique_ptr<unc_decoder> create(
+      uint32_t width, uint32_t height,
+      const std::shared_ptr<const Box_cmpd>& cmpd,
+      const std::shared_ptr<const Box_uncC>& uncC) const = 0;
+};
+
 #endif
diff --git a/libheif/codecs/uncompressed/decoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
similarity index 70%
rename from libheif/codecs/uncompressed/decoder_component_interleave.cc
rename to libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
index 6d18b9c8..b6ae03cd 100644
--- a/libheif/codecs/uncompressed/decoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
@@ -18,7 +18,7 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#include "decoder_component_interleave.h"
+#include "unc_decoder_component_interleave.h"
 #include "context.h"
 #include "error.h"

@@ -26,15 +26,15 @@
 #include <vector>


-Error ComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
-                                              const UncompressedImageCodec::unci_properties& properties,
-                                              std::shared_ptr<HeifPixelImage>& img,
-                                              uint32_t out_x0, uint32_t out_y0,
-                                              uint32_t image_width, uint32_t image_height,
-                                              uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_component_interleave::decode_tile(const DataExtent& dataExtent,
+                                                     const UncompressedImageCodec::unci_properties& properties,
+                                                     std::shared_ptr<HeifPixelImage>& img,
+                                                     uint32_t out_x0, uint32_t out_y0,
+                                                     uint32_t image_width, uint32_t image_height,
+                                                     uint32_t tile_x, uint32_t tile_y)
 {
   if (m_tile_width == 0) {
-    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: ComponentInterleaveDecoder tile_width=0"};
+    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_component_interleave tile_width=0"};
   }

   // --- compute which file range we need to read for the tile
@@ -67,7 +67,6 @@ Error ComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
   // --- read required file range

   std::vector<uint8_t> src_data;
-  //Error err = context->get_heif_file()->append_data_from_iloc(image_id, src_data, tile_start_offset, total_tile_size);
   Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
   if (err) {
     return err;
@@ -94,3 +93,17 @@ Error ComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,

   return Error::Ok;
 }
+
+
+bool unc_decoder_factory_component_interleave::can_decode(const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return uncC->get_interleave_type() == interleave_mode_component;
+}
+
+std::unique_ptr<unc_decoder> unc_decoder_factory_component_interleave::create(
+    uint32_t width, uint32_t height,
+    const std::shared_ptr<const Box_cmpd>& cmpd,
+    const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return std::make_unique<unc_decoder_component_interleave>(width, height, cmpd, uncC);
+}
diff --git a/libheif/codecs/uncompressed/decoder_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
similarity index 57%
rename from libheif/codecs/uncompressed/decoder_component_interleave.h
rename to libheif/codecs/uncompressed/unc_decoder_component_interleave.h
index 7408a1b5..81f70121 100644
--- a/libheif/codecs/uncompressed/decoder_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
@@ -18,21 +18,21 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#ifndef UNCI_DECODER_COMPONENT_INTERLEAVE_H
-#define UNCI_DECODER_COMPONENT_INTERLEAVE_H
+#ifndef LIBHEIF_UNC_DECODER_COMPONENT_INTERLEAVE_H
+#define LIBHEIF_UNC_DECODER_COMPONENT_INTERLEAVE_H

-#include "decoder_abstract.h"
+#include "unc_decoder.h"
 #include <memory>
 #include <utility>


-class ComponentInterleaveDecoder : public AbstractDecoder
+class unc_decoder_component_interleave : public unc_decoder
 {
 public:
-  ComponentInterleaveDecoder(uint32_t width, uint32_t height,
-                             std::shared_ptr<const Box_cmpd> cmpd,
-                             std::shared_ptr<const Box_uncC> uncC) :
-      AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) {}
+  unc_decoder_component_interleave(uint32_t width, uint32_t height,
+                                    std::shared_ptr<const Box_cmpd> cmpd,
+                                    std::shared_ptr<const Box_uncC> uncC) :
+      unc_decoder(width, height, std::move(cmpd), std::move(uncC)) {}

   Error decode_tile(const DataExtent& dataExtent,
                     const UncompressedImageCodec::unci_properties& properties,
@@ -42,4 +42,16 @@ public:
                     uint32_t tile_x, uint32_t tile_y) override;
 };

-#endif // UNCI_DECODER_COMPONENT_INTERLEAVE_H
+
+class unc_decoder_factory_component_interleave : public unc_decoder_factory
+{
+private:
+  bool can_decode(const std::shared_ptr<const Box_uncC>& uncC) const override;
+
+  std::unique_ptr<unc_decoder> create(
+      uint32_t width, uint32_t height,
+      const std::shared_ptr<const Box_cmpd>& cmpd,
+      const std::shared_ptr<const Box_uncC>& uncC) const override;
+};
+
+#endif // LIBHEIF_UNC_DECODER_COMPONENT_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/decoder_mixed_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
similarity index 77%
rename from libheif/codecs/uncompressed/decoder_mixed_interleave.cc
rename to libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
index f3d656e8..be117de4 100644
--- a/libheif/codecs/uncompressed/decoder_mixed_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
@@ -18,7 +18,7 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#include "decoder_mixed_interleave.h"
+#include "unc_decoder_mixed_interleave.h"
 #include "context.h"
 #include "error.h"

@@ -27,15 +27,15 @@
 #include <vector>


-Error MixedInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
-                                          const UncompressedImageCodec::unci_properties& properties,
-                                          std::shared_ptr<HeifPixelImage>& img,
-                                          uint32_t out_x0, uint32_t out_y0,
-                                          uint32_t image_width, uint32_t image_height,
-                                          uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_mixed_interleave::decode_tile(const DataExtent& dataExtent,
+                                                 const UncompressedImageCodec::unci_properties& properties,
+                                                 std::shared_ptr<HeifPixelImage>& img,
+                                                 uint32_t out_x0, uint32_t out_y0,
+                                                 uint32_t image_width, uint32_t image_height,
+                                                 uint32_t tile_x, uint32_t tile_y)
 {
   if (m_tile_width == 0) {
-    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: MixedInterleaveDecoder tile_width=0"};
+    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_mixed_interleave tile_width=0"};
   }

   // --- compute which file range we need to read for the tile
@@ -78,7 +78,6 @@ Error MixedInterleaveDecoder::decode_tile(const DataExtent& dataExtent,

   std::vector<uint8_t> src_data;
   Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, tile_size, tileIdx, nullptr);
-  //Error err = context->get_heif_file()->append_data_from_iloc(image_id, src_data, tile_start_offset, tile_size);
   if (err) {
     return err;
   }
@@ -91,7 +90,7 @@ Error MixedInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
 }


-void MixedInterleaveDecoder::processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column, uint32_t out_x0, uint32_t out_y0)
+void unc_decoder_mixed_interleave::processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column, uint32_t out_x0, uint32_t out_y0)
 {
   bool haveProcessedChromaForThisTile = false;
   for (ChannelListEntry& entry : channelList) {
@@ -130,3 +129,17 @@ void MixedInterleaveDecoder::processTile(UncompressedBitReader& srcBits, uint32_
     }
   }
 }
+
+
+bool unc_decoder_factory_mixed_interleave::can_decode(const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return uncC->get_interleave_type() == interleave_mode_mixed;
+}
+
+std::unique_ptr<unc_decoder> unc_decoder_factory_mixed_interleave::create(
+    uint32_t width, uint32_t height,
+    const std::shared_ptr<const Box_cmpd>& cmpd,
+    const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return std::make_unique<unc_decoder_mixed_interleave>(width, height, cmpd, uncC);
+}
diff --git a/libheif/codecs/uncompressed/decoder_row_interleave.h b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
similarity index 63%
rename from libheif/codecs/uncompressed/decoder_row_interleave.h
rename to libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
index d39ed47d..e9f4969d 100644
--- a/libheif/codecs/uncompressed/decoder_row_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
@@ -18,21 +18,19 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#ifndef UNCI_DECODER_ROW_INTERLEAVE_H
-#define UNCI_DECODER_ROW_INTERLEAVE_H
+#ifndef LIBHEIF_UNC_DECODER_MIXED_INTERLEAVE_H
+#define LIBHEIF_UNC_DECODER_MIXED_INTERLEAVE_H

-#include "decoder_abstract.h"
+#include "unc_decoder.h"
 #include <memory>
 #include <utility>


-class RowInterleaveDecoder : public AbstractDecoder
+class unc_decoder_mixed_interleave : public unc_decoder
 {
 public:
-  RowInterleaveDecoder(uint32_t width, uint32_t height,
-                       std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
-      AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) {}
-
+  unc_decoder_mixed_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
+      unc_decoder(width, height, std::move(cmpd), std::move(uncC)) {}

   Error decode_tile(const DataExtent& dataExtent,
                     const UncompressedImageCodec::unci_properties& properties,
@@ -41,9 +39,20 @@ public:
                     uint32_t image_width, uint32_t image_height,
                     uint32_t tile_x, uint32_t tile_y) override;

-private:
   void processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column,
                    uint32_t out_x0, uint32_t out_y0);
 };

-#endif // UNCI_DECODER_ROW_INTERLEAVE_H
+
+class unc_decoder_factory_mixed_interleave : public unc_decoder_factory
+{
+private:
+  bool can_decode(const std::shared_ptr<const Box_uncC>& uncC) const override;
+
+  std::unique_ptr<unc_decoder> create(
+      uint32_t width, uint32_t height,
+      const std::shared_ptr<const Box_cmpd>& cmpd,
+      const std::shared_ptr<const Box_uncC>& uncC) const override;
+};
+
+#endif // LIBHEIF_UNC_DECODER_MIXED_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/decoder_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
similarity index 74%
rename from libheif/codecs/uncompressed/decoder_pixel_interleave.cc
rename to libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
index 33364544..2b1944c0 100644
--- a/libheif/codecs/uncompressed/decoder_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
@@ -18,7 +18,7 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#include "decoder_pixel_interleave.h"
+#include "unc_decoder_pixel_interleave.h"
 #include "context.h"
 #include "error.h"

@@ -26,15 +26,15 @@
 #include <vector>


-Error PixelInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
-                                          const UncompressedImageCodec::unci_properties& properties,
-                                          std::shared_ptr<HeifPixelImage>& img,
-                                          uint32_t out_x0, uint32_t out_y0,
-                                          uint32_t image_width, uint32_t image_height,
-                                          uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_pixel_interleave::decode_tile(const DataExtent& dataExtent,
+                                                 const UncompressedImageCodec::unci_properties& properties,
+                                                 std::shared_ptr<HeifPixelImage>& img,
+                                                 uint32_t out_x0, uint32_t out_y0,
+                                                 uint32_t image_width, uint32_t image_height,
+                                                 uint32_t tile_x, uint32_t tile_y)
 {
   if (m_tile_width == 0) {
-    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: PixelInterleaveDecoder tile_width=0"};
+    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_pixel_interleave tile_width=0"};
   }

   // --- compute which file range we need to read for the tile
@@ -83,7 +83,6 @@ Error PixelInterleaveDecoder::decode_tile(const DataExtent& dataExtent,

   std::vector<uint8_t> src_data;
   Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
-  //Error err = context->get_heif_file()->append_data_from_iloc(image_id, src_data, tile_start_offset, total_tile_size);
   if (err) {
     return err;
   }
@@ -99,7 +98,7 @@ Error PixelInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
 }


-Error PixelInterleaveDecoder::processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column, uint32_t out_x0, uint32_t out_y0)
+Error unc_decoder_pixel_interleave::processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column, uint32_t out_x0, uint32_t out_y0)
 {
   for (uint32_t tile_y = 0; tile_y < m_tile_height; tile_y++) {
     srcBits.markRowStart();
@@ -130,3 +129,17 @@ Error PixelInterleaveDecoder::processTile(UncompressedBitReader& srcBits, uint32

   return {};
 }
+
+
+bool unc_decoder_factory_pixel_interleave::can_decode(const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return uncC->get_interleave_type() == interleave_mode_pixel;
+}
+
+std::unique_ptr<unc_decoder> unc_decoder_factory_pixel_interleave::create(
+    uint32_t width, uint32_t height,
+    const std::shared_ptr<const Box_cmpd>& cmpd,
+    const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return std::make_unique<unc_decoder_pixel_interleave>(width, height, cmpd, uncC);
+}
diff --git a/libheif/codecs/uncompressed/decoder_pixel_interleave.h b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
similarity index 63%
rename from libheif/codecs/uncompressed/decoder_pixel_interleave.h
rename to libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
index f6004231..0174b4ec 100644
--- a/libheif/codecs/uncompressed/decoder_pixel_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
@@ -18,38 +18,19 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#ifndef UNCI_DECODER_PIXEL_INTERLEAVE_H
-#define UNCI_DECODER_PIXEL_INTERLEAVE_H
+#ifndef LIBHEIF_UNC_DECODER_PIXEL_INTERLEAVE_H
+#define LIBHEIF_UNC_DECODER_PIXEL_INTERLEAVE_H

-#include <cstdint>
-#include <cstring>
-#include <algorithm>
-#include <map>
-#include <iostream>
-#include <cassert>
-#include <utility>
-
-#include "common_utils.h"
-#include "context.h"
-#include "compression.h"
-#include "error.h"
-#include "libheif/heif.h"
-#include "unc_types.h"
-#include "unc_boxes.h"
-#include "unc_codec.h"
-#include "unc_dec.h"
-
-#include "decoder_abstract.h"
-#include "decoder_component_interleave.h"
+#include "unc_decoder.h"
 #include <memory>
 #include <utility>


-class PixelInterleaveDecoder : public AbstractDecoder
+class unc_decoder_pixel_interleave : public unc_decoder
 {
 public:
-  PixelInterleaveDecoder(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
-      AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) {}
+  unc_decoder_pixel_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
+      unc_decoder(width, height, std::move(cmpd), std::move(uncC)) {}

   Error decode_tile(const DataExtent& dataExtent,
                     const UncompressedImageCodec::unci_properties& properties,
@@ -62,4 +43,16 @@ public:
                                   uint32_t out_x0, uint32_t out_y0);
 };

-#endif // UNCI_DECODER_PIXEL_INTERLEAVE_H
+
+class unc_decoder_factory_pixel_interleave : public unc_decoder_factory
+{
+private:
+  bool can_decode(const std::shared_ptr<const Box_uncC>& uncC) const override;
+
+  std::unique_ptr<unc_decoder> create(
+      uint32_t width, uint32_t height,
+      const std::shared_ptr<const Box_cmpd>& cmpd,
+      const std::shared_ptr<const Box_uncC>& uncC) const override;
+};
+
+#endif // LIBHEIF_UNC_DECODER_PIXEL_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/decoder_row_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
similarity index 72%
rename from libheif/codecs/uncompressed/decoder_row_interleave.cc
rename to libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
index 0502b026..8851e207 100644
--- a/libheif/codecs/uncompressed/decoder_row_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
@@ -18,7 +18,7 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#include "decoder_row_interleave.h"
+#include "unc_decoder_row_interleave.h"
 #include "context.h"
 #include "error.h"

@@ -26,15 +26,15 @@
 #include <vector>


-Error RowInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
-                                        const UncompressedImageCodec::unci_properties& properties,
-                                        std::shared_ptr<HeifPixelImage>& img,
-                                        uint32_t out_x0, uint32_t out_y0,
-                                        uint32_t image_width, uint32_t image_height,
-                                        uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_row_interleave::decode_tile(const DataExtent& dataExtent,
+                                               const UncompressedImageCodec::unci_properties& properties,
+                                               std::shared_ptr<HeifPixelImage>& img,
+                                               uint32_t out_x0, uint32_t out_y0,
+                                               uint32_t image_width, uint32_t image_height,
+                                               uint32_t tile_x, uint32_t tile_y)
 {
   if (m_tile_width == 0) {
-    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: RowInterleaveDecoder tile_width=0"};
+    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_row_interleave tile_width=0"};
   }

   // --- compute which file range we need to read for the tile
@@ -84,7 +84,6 @@ Error RowInterleaveDecoder::decode_tile(const DataExtent& dataExtent,

   std::vector<uint8_t> src_data;
   Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
-  //Error err = context->get_heif_file()->append_data_from_iloc(image_id, src_data, tile_start_offset, total_tile_size);
   if (err) {
     return err;
   }
@@ -97,7 +96,7 @@ Error RowInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
 }


-void RowInterleaveDecoder::processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column, uint32_t out_x0, uint32_t out_y0)
+void unc_decoder_row_interleave::processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column, uint32_t out_x0, uint32_t out_y0)
 {
   for (uint32_t tile_y = 0; tile_y < m_tile_height; tile_y++) {
     for (ChannelListEntry& entry : channelList) {
@@ -114,3 +113,16 @@ void RowInterleaveDecoder::processTile(UncompressedBitReader& srcBits, uint32_t
   }
 }

+
+bool unc_decoder_factory_row_interleave::can_decode(const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return uncC->get_interleave_type() == interleave_mode_row;
+}
+
+std::unique_ptr<unc_decoder> unc_decoder_factory_row_interleave::create(
+    uint32_t width, uint32_t height,
+    const std::shared_ptr<const Box_cmpd>& cmpd,
+    const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return std::make_unique<unc_decoder_row_interleave>(width, height, cmpd, uncC);
+}
diff --git a/libheif/codecs/uncompressed/decoder_mixed_interleave.h b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
similarity index 61%
rename from libheif/codecs/uncompressed/decoder_mixed_interleave.h
rename to libheif/codecs/uncompressed/unc_decoder_row_interleave.h
index ab327bac..05bad259 100644
--- a/libheif/codecs/uncompressed/decoder_mixed_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
@@ -18,19 +18,21 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#ifndef UNCI_DECODER_MIXED_INTERLEAVE_H
-#define UNCI_DECODER_MIXED_INTERLEAVE_H
+#ifndef LIBHEIF_UNC_DECODER_ROW_INTERLEAVE_H
+#define LIBHEIF_UNC_DECODER_ROW_INTERLEAVE_H

-#include "decoder_abstract.h"
+#include "unc_decoder.h"
 #include <memory>
 #include <utility>


-class MixedInterleaveDecoder : public AbstractDecoder
+class unc_decoder_row_interleave : public unc_decoder
 {
 public:
-  MixedInterleaveDecoder(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
-      AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) {}
+  unc_decoder_row_interleave(uint32_t width, uint32_t height,
+                              std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
+      unc_decoder(width, height, std::move(cmpd), std::move(uncC)) {}
+

   Error decode_tile(const DataExtent& dataExtent,
                     const UncompressedImageCodec::unci_properties& properties,
@@ -39,8 +41,21 @@ public:
                     uint32_t image_width, uint32_t image_height,
                     uint32_t tile_x, uint32_t tile_y) override;

+private:
   void processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column,
                    uint32_t out_x0, uint32_t out_y0);
 };

-#endif // UNCI_DECODER_MIXED_INTERLEAVE_H
+
+class unc_decoder_factory_row_interleave : public unc_decoder_factory
+{
+private:
+  bool can_decode(const std::shared_ptr<const Box_uncC>& uncC) const override;
+
+  std::unique_ptr<unc_decoder> create(
+      uint32_t width, uint32_t height,
+      const std::shared_ptr<const Box_cmpd>& cmpd,
+      const std::shared_ptr<const Box_uncC>& uncC) const override;
+};
+
+#endif // LIBHEIF_UNC_DECODER_ROW_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/decoder_tile_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_tile_component_interleave.cc
similarity index 73%
rename from libheif/codecs/uncompressed/decoder_tile_component_interleave.cc
rename to libheif/codecs/uncompressed/unc_decoder_tile_component_interleave.cc
index 4a4c5f81..c7e26edc 100644
--- a/libheif/codecs/uncompressed/decoder_tile_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_tile_component_interleave.cc
@@ -19,7 +19,7 @@
  */


-#include "decoder_tile_component_interleave.h"
+#include "unc_decoder_tile_component_interleave.h"
 #include "context.h"
 #include "error.h"

@@ -28,32 +28,27 @@
 #include <vector>


-Error TileComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
-                                                  const UncompressedImageCodec::unci_properties& properties,
-                                                  std::shared_ptr<HeifPixelImage>& img,
-                                                  uint32_t out_x0, uint32_t out_y0,
-                                                  uint32_t image_width, uint32_t image_height,
-                                                  uint32_t tile_column, uint32_t tile_row)
+Error unc_decoder_tile_component_interleave::decode_tile(const DataExtent& dataExtent,
+                                                          const UncompressedImageCodec::unci_properties& properties,
+                                                          std::shared_ptr<HeifPixelImage>& img,
+                                                          uint32_t out_x0, uint32_t out_y0,
+                                                          uint32_t image_width, uint32_t image_height,
+                                                          uint32_t tile_column, uint32_t tile_row)
 {
   if (m_tile_width == 0) {
-    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: TileComponentInterleaveDecoder tile_width=0"};
+    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_tile_component_interleave tile_width=0"};
   }
   if (m_tile_height == 0) {
-    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: TileComponentInterleaveDecoder tile_height=0"};
+    return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_tile_component_interleave tile_height=0"};
   }

   // --- compute which file range we need to read for the tile

   std::map<heif_channel, uint64_t> channel_tile_size;

-  //uint64_t total_tile_size = 0;
-
   for (ChannelListEntry& entry : channelList) {
     uint32_t bits_per_pixel = entry.bits_per_component_sample;
     if (entry.component_alignment > 0) {
-      // start at byte boundary
-      //bits_per_row = (bits_per_row + 7) & ~7U;
-
       uint32_t bytes_per_component = (bits_per_pixel + 7) / 8;
       skip_to_alignment(bytes_per_component, entry.component_alignment);
       bits_per_pixel = bytes_per_component * 8;
@@ -78,8 +73,6 @@ Error TileComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
     }

     channel_tile_size[entry.channel] = component_tile_size;
-
-    //total_tile_size += component_tile_size;
   }

   uint64_t component_start_offset = 0;
@@ -88,12 +81,7 @@ Error TileComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
   assert(m_tile_height > 0);

   for (ChannelListEntry& entry : channelList) {
-    //processTile(srcBits, tile_y, tile_x, out_x0, out_y0);
-
     if (!entry.use_channel) {
-      //uint64_t bytes_per_component = entry.get_bytes_per_tile() * m_uncC->get_number_of_tile_columns() * m_uncC->get_number_of_tile_rows();
-      //srcBits.skip_bytes((int)bytes_per_component);
-
       component_start_offset += channel_tile_size[entry.channel] * (m_width / m_tile_width) * (m_height / m_tile_height);
       continue;
     }
@@ -105,7 +93,6 @@ Error TileComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,

     std::vector<uint8_t> src_data;
     Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, channel_tile_size[entry.channel], tileIdx, nullptr);
-    //Error err = context->get_heif_file()->append_data_from_iloc(image_id, src_data, tile_start_offset, channel_tile_size[entry.channel]);
     if (err) {
       return err;
     }
@@ -129,3 +116,15 @@ Error TileComponentInterleaveDecoder::decode_tile(const DataExtent& dataExtent,
 }


+bool unc_decoder_factory_tile_component_interleave::can_decode(const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return uncC->get_interleave_type() == interleave_mode_tile_component;
+}
+
+std::unique_ptr<unc_decoder> unc_decoder_factory_tile_component_interleave::create(
+    uint32_t width, uint32_t height,
+    const std::shared_ptr<const Box_cmpd>& cmpd,
+    const std::shared_ptr<const Box_uncC>& uncC) const
+{
+  return std::make_unique<unc_decoder_tile_component_interleave>(width, height, cmpd, uncC);
+}
diff --git a/libheif/codecs/uncompressed/decoder_tile_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_tile_component_interleave.h
similarity index 57%
rename from libheif/codecs/uncompressed/decoder_tile_component_interleave.h
rename to libheif/codecs/uncompressed/unc_decoder_tile_component_interleave.h
index d78e12be..ed083f9e 100644
--- a/libheif/codecs/uncompressed/decoder_tile_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_tile_component_interleave.h
@@ -18,20 +18,20 @@
  * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
  */

-#ifndef UNCI_DECODER_TILE_COMPONENT_INTERLEAVE_H
-#define UNCI_DECODER_TILE_COMPONENT_INTERLEAVE_H
+#ifndef LIBHEIF_UNC_DECODER_TILE_COMPONENT_INTERLEAVE_H
+#define LIBHEIF_UNC_DECODER_TILE_COMPONENT_INTERLEAVE_H

-#include "decoder_abstract.h"
+#include "unc_decoder.h"
 #include <memory>
 #include <utility>


-class TileComponentInterleaveDecoder : public AbstractDecoder
+class unc_decoder_tile_component_interleave : public unc_decoder
 {
 public:
-  TileComponentInterleaveDecoder(uint32_t width, uint32_t height,
-                                 std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
-      AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) {}
+  unc_decoder_tile_component_interleave(uint32_t width, uint32_t height,
+                                         std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
+      unc_decoder(width, height, std::move(cmpd), std::move(uncC)) {}

   Error decode_tile(const DataExtent& dataExtent,
                     const UncompressedImageCodec::unci_properties& properties,
@@ -41,4 +41,16 @@ public:
                     uint32_t tile_column, uint32_t tile_row) override;
 };

-#endif // UNCI_DECODER_TILE_COMPONENT_INTERLEAVE_H
+
+class unc_decoder_factory_tile_component_interleave : public unc_decoder_factory
+{
+private:
+  bool can_decode(const std::shared_ptr<const Box_uncC>& uncC) const override;
+
+  std::unique_ptr<unc_decoder> create(
+      uint32_t width, uint32_t height,
+      const std::shared_ptr<const Box_cmpd>& cmpd,
+      const std::shared_ptr<const Box_uncC>& uncC) const override;
+};
+
+#endif // LIBHEIF_UNC_DECODER_TILE_COMPONENT_INTERLEAVE_H