Commit db3b3e84 for libheif

commit db3b3e84c6fe09a0bbb566ff5196554a9d1e4b7e
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Tue Feb 24 15:21:06 2026 +0100

    add unif brand support (globally unique IDs)

diff --git a/examples/heif_enc.cc b/examples/heif_enc.cc
index 3b000be7..533540d0 100644
--- a/examples/heif_enc.cc
+++ b/examples/heif_enc.cc
@@ -114,6 +114,7 @@ bool force_enc_jpeg2000 = false;
 bool force_enc_htj2k = false;
 bool use_tiling = false;
 bool encode_sequence = false;
+bool option_unif = false;
 bool use_video_handler = false;
 std::string option_mime_item_type;
 std::string option_mime_item_file;
@@ -200,6 +201,7 @@ const int OPTION_USE_HEVC_COMPRESSION = 1037;
 const int OPTION_SET_OMAF_IMAGE_PROJECTION = 1038;
 #endif
 const int OPTION_ADD_COMPATIBLE_BRAND = 1039;
+const int OPTION_UNIF = 1040;

 static option long_options[] = {
     {(char* const) "help",                    no_argument,       0,              'h'},
@@ -272,6 +274,7 @@ static option long_options[] = {
     {(char* const) "omaf-image-projection",       required_argument,       nullptr, OPTION_SET_OMAF_IMAGE_PROJECTION},
 #endif
     {(char* const) "add-compatible-brand",        required_argument,       nullptr, OPTION_ADD_COMPATIBLE_BRAND},
+    {(char* const) "unif",                      no_argument,             nullptr, OPTION_UNIF},
     {0, 0,                                                           0,  0}
 };

@@ -329,6 +332,7 @@ void show_help(const char* argv0)
             << "      --mime-item-file FILE         use the specified FILE as the data to put into the mime item (experimental)\n"
 #endif
             << "      --add-compatible-brand BRAND  add a compatible brand to the output file (4 characters)\n"
+            << "      --unif                        use unified ID namespace (adds 'unif' compatible brand)\n"
             << "\n"
             << "codecs:\n"
             << "  -A, --avif                     encode as AVIF (not needed if output filename with .avif suffix is provided)\n"
@@ -1641,6 +1645,9 @@ int main(int argc, char** argv)
         }
         additional_compatible_brands.push_back(heif_fourcc_to_brand(optarg));
         break;
+      case OPTION_UNIF:
+        option_unif = true;
+        break;
     }
   }

@@ -1744,6 +1751,10 @@ int main(int argc, char** argv)
     return 1;
   }

+  if (option_unif) {
+    heif_context_set_unif(context.get(), 1);
+  }
+

 #define MAX_ENCODERS 10
   const heif_encoder_descriptor* encoder_descriptors[MAX_ENCODERS];
diff --git a/libheif/CMakeLists.txt b/libheif/CMakeLists.txt
index 2d65a5b0..4d00325a 100644
--- a/libheif/CMakeLists.txt
+++ b/libheif/CMakeLists.txt
@@ -63,6 +63,8 @@ set(libheif_sources
         region.h
         brands.cc
         brands.h
+        id_creator.cc
+        id_creator.h
         text.cc
         text.h
         api_structs.h
diff --git a/libheif/api/libheif/heif_brands.h b/libheif/api/libheif/heif_brands.h
index 81263d35..68cd89f9 100644
--- a/libheif/api/libheif/heif_brands.h
+++ b/libheif/api/libheif/heif_brands.h
@@ -250,6 +250,15 @@ typedef uint32_t heif_brand2;
 #define heif_brand2_avci   heif_fourcc('a','v','c','i')
 #define heif_brand2_avcs   heif_fourcc('a','v','c','s')

+/**
+ * Unified ID namespace (`unif`) brand.
+ *
+ * All IDs (item, track, entity group) share a single global namespace.
+ *
+ * See ISO/IEC 14496-12.
+ */
+#define heif_brand2_unif   heif_fourcc('u','n','i','f')
+
 #define heif_brand2_iso8   heif_fourcc('i','s','o','8')
 #define heif_brand2_isom   heif_fourcc('i','s','o','m')
 #define heif_brand2_mp41   heif_fourcc('m','p','4','1')
diff --git a/libheif/api/libheif/heif_encoding.cc b/libheif/api/libheif/heif_encoding.cc
index 3a0c13bb..609406ef 100644
--- a/libheif/api/libheif/heif_encoding.cc
+++ b/libheif/api/libheif/heif_encoding.cc
@@ -775,6 +775,12 @@ void heif_context_add_compatible_brand(heif_context* ctx,
 }


+void heif_context_set_unif(heif_context* ctx, int flag)
+{
+  ctx->context->set_unif(flag != 0);
+}
+
+
 // === DEPRECATED ===

 // DEPRECATED: typo in function name
diff --git a/libheif/api/libheif/heif_encoding.h b/libheif/api/libheif/heif_encoding.h
index 2261340d..5c91c416 100644
--- a/libheif/api/libheif/heif_encoding.h
+++ b/libheif/api/libheif/heif_encoding.h
@@ -364,6 +364,19 @@ LIBHEIF_API
 void heif_context_add_compatible_brand(heif_context* ctx,
                                        heif_brand2 compatible_brand);

+/**
+ * Enable the unified ID namespace ('unif' brand).
+ *
+ * When enabled, item IDs, track IDs, and entity group IDs share a single
+ * global counter so no ID value is reused across categories. The 'unif'
+ * compatible brand is automatically added to the output file.
+ *
+ * @param ctx the encoding context
+ * @param flag non-zero to enable, zero to disable
+ */
+LIBHEIF_API
+void heif_context_set_unif(heif_context* ctx, int flag);
+
 // --- deprecated functions ---

 // DEPRECATED, typo in function name
diff --git a/libheif/api/libheif/heif_regions.cc b/libheif/api/libheif/heif_regions.cc
index 625c00af..b54b6952 100644
--- a/libheif/api/libheif/heif_regions.cc
+++ b/libheif/api/libheif/heif_regions.cc
@@ -512,7 +512,11 @@ heif_error heif_image_handle_add_region_item(heif_image_handle* image_handle,
                                              uint32_t reference_width, uint32_t reference_height,
                                              heif_region_item** out_region_item)
 {
-  std::shared_ptr<RegionItem> regionItem = image_handle->context->add_region_item(reference_width, reference_height);
+  auto regionItemResult = image_handle->context->add_region_item(reference_width, reference_height);
+  if (!regionItemResult) {
+    return regionItemResult.error_struct(image_handle->context.get());
+  }
+  std::shared_ptr<RegionItem> regionItem = *regionItemResult;
   image_handle->image->add_region_item_id(regionItem->item_id);

   if (out_region_item) {
diff --git a/libheif/api/libheif/heif_text.cc b/libheif/api/libheif/heif_text.cc
index f4f3e204..4b0d6c30 100644
--- a/libheif/api/libheif/heif_text.cc
+++ b/libheif/api/libheif/heif_text.cc
@@ -36,7 +36,11 @@ heif_error heif_image_handle_add_text_item(heif_image_handle *image_handle,
                                            heif_text_item** out_text_item)
 {

-  std::shared_ptr<TextItem> textItem = image_handle->context->add_text_item(content_type, text);
+  auto textItemResult = image_handle->context->add_text_item(content_type, text);
+  if (!textItemResult) {
+    return textItemResult.error_struct(image_handle->context.get());
+  }
+  std::shared_ptr<TextItem> textItem = *textItemResult;
   image_handle->image->add_text_item_id(textItem->get_item_id());
   if (out_text_item) {
     heif_text_item* item = new heif_text_item();
diff --git a/libheif/brands.cc b/libheif/brands.cc
index ab8acb67..9aeb039c 100644
--- a/libheif/brands.cc
+++ b/libheif/brands.cc
@@ -165,6 +165,12 @@ std::vector<heif_brand2> compute_compatible_brands(const HeifContext* ctx, heif_
     }
   }

+  // --- "unif" brand
+
+  if (ctx->get_unif()) {
+    compatible_brands.push_back(heif_brand2_unif);
+  }
+
   return compatible_brands;
 }

diff --git a/libheif/context.cc b/libheif/context.cc
index 3bc91f8c..e12c43be 100644
--- a/libheif/context.cc
+++ b/libheif/context.cc
@@ -167,6 +167,24 @@ void HeifContext::set_security_limits(const heif_security_limits* limits)
 }


+void HeifContext::set_unif(bool flag)
+{
+  m_heif_file->get_id_creator().set_unif(flag);
+}
+
+
+bool HeifContext::get_unif() const
+{
+  return m_heif_file->get_id_creator().get_unif();
+}
+
+
+IDCreator& HeifContext::get_id_creator()
+{
+  return m_heif_file->get_id_creator();
+}
+
+
 Error HeifContext::read(const std::shared_ptr<StreamReader>& reader)
 {
   m_heif_file = std::make_shared<HeifFile>();
@@ -273,9 +291,13 @@ bool HeifContext::is_image(heif_item_id ID) const
 }


-std::shared_ptr<RegionItem> HeifContext::add_region_item(uint32_t reference_width, uint32_t reference_height)
+Result<std::shared_ptr<RegionItem>> HeifContext::add_region_item(uint32_t reference_width, uint32_t reference_height)
 {
-  std::shared_ptr<Box_infe> box = m_heif_file->add_new_infe_box(fourcc("rgan"));
+  auto boxResult = m_heif_file->add_new_infe_box(fourcc("rgan"));
+  if (!boxResult) {
+    return boxResult.error();
+  }
+  auto box = *boxResult;
   box->set_hidden_item(true);

   auto regionItem = std::make_shared<RegionItem>(box->get_item_ID(), reference_width, reference_height);
@@ -1702,7 +1724,11 @@ Error HeifContext::add_generic_metadata(const std::shared_ptr<ImageItem>& master
 {
   // create an infe box describing what kind of data we are storing (this also creates a new ID)

-  auto metadata_infe_box = m_heif_file->add_new_infe_box(item_type);
+  auto infe_result = m_heif_file->add_new_infe_box(item_type);
+  if (!infe_result) {
+    return infe_result.error();
+  }
+  auto metadata_infe_box = *infe_result;
   metadata_infe_box->set_hidden_item(true);
   if (content_type != nullptr) {
     metadata_infe_box->set_content_type(content_type);
@@ -1856,7 +1882,11 @@ Result<heif_item_id> HeifContext::add_pyramid_group(const std::vector<heif_item_
     ids.push_back(layer_item->get_id());
   }

-  heif_item_id group_id = m_heif_file->get_unused_item_id();
+  auto groupIdResult = m_heif_file->get_id_creator().get_new_id(IDCreator::Namespace::entity_group);
+  if (!groupIdResult) {
+    return groupIdResult.error();
+  }
+  heif_item_id group_id = *groupIdResult;

   pymd->set_group_id(group_id);
   pymd->set_layers((uint16_t)tile_w, (uint16_t)tile_h, layers, ids);
@@ -2070,9 +2100,13 @@ Result<std::shared_ptr<class Track_Metadata>> HeifContext::add_uri_metadata_sequ
   return trak;
 }

-std::shared_ptr<TextItem> HeifContext::add_text_item(const char* content_type, const char* text)
+Result<std::shared_ptr<TextItem>> HeifContext::add_text_item(const char* content_type, const char* text)
 {
-  std::shared_ptr<Box_infe> box = m_heif_file->add_new_infe_box(fourcc("mime"));
+  auto boxResult = m_heif_file->add_new_infe_box(fourcc("mime"));
+  if (!boxResult) {
+    return boxResult.error();
+  }
+  auto box = *boxResult;
   box->set_hidden_item(true);
   box->set_content_type(std::string(content_type));
   auto textItem = std::make_shared<TextItem>(box->get_item_ID(), text);
diff --git a/libheif/context.h b/libheif/context.h
index 45554459..de1bb859 100644
--- a/libheif/context.h
+++ b/libheif/context.h
@@ -88,6 +88,12 @@ public:
   std::shared_ptr<HeifFile> get_heif_file() const { return m_heif_file; }


+  void set_unif(bool flag);
+
+  bool get_unif() const;
+
+  IDCreator& get_id_creator();
+
   // === image items ===

   std::vector<std::shared_ptr<ImageItem>> get_top_level_images(bool return_error_images);
@@ -176,7 +182,7 @@ public:
     m_region_items.push_back(std::move(region_item));
   }

-  std::shared_ptr<RegionItem> add_region_item(uint32_t reference_width, uint32_t reference_height);
+  Result<std::shared_ptr<RegionItem>> add_region_item(uint32_t reference_width, uint32_t reference_height);

   std::shared_ptr<RegionItem> get_region_item(heif_item_id id) const
   {
@@ -222,7 +228,7 @@ public:
     m_text_items.push_back(std::move(text_item));
   }

-  std::shared_ptr<TextItem> add_text_item(const char* content_type, const char* text);
+  Result<std::shared_ptr<TextItem>> add_text_item(const char* content_type, const char* text);

   std::shared_ptr<TextItem> get_text_item(heif_item_id id) const
   {
diff --git a/libheif/file.cc b/libheif/file.cc
index 32aa902e..a652ae6a 100644
--- a/libheif/file.cc
+++ b/libheif/file.cc
@@ -852,35 +852,31 @@ Result<std::vector<uint8_t>> HeifFile::get_item_data(heif_item_id ID, heif_metad
 }


-// TODO: we should use a acquire() / release() approach here so that we can get multiple IDs before actually creating infe boxes
-heif_item_id HeifFile::get_unused_item_id() const
+Result<heif_item_id> HeifFile::get_unused_item_id()
 {
-  heif_item_id max_id = 0;
-
-  // TODO: replace with better algorithm and data-structure
-
-  for (const auto& infe : m_infe_boxes) {
-    max_id = std::max(max_id, infe.second->get_item_ID());
-  }
-
-  assert(max_id != 0xFFFFFFFF);
-
-  return max_id + 1;
+  return m_id_creator.get_new_id(IDCreator::Namespace::item);
 }


-heif_item_id HeifFile::add_new_image(uint32_t item_type)
+Result<heif_item_id> HeifFile::add_new_image(uint32_t item_type)
 {
-  auto box = add_new_infe_box(item_type);
-  return box->get_item_ID();
+  auto result = add_new_infe_box(item_type);
+  if (!result) {
+    return result.error();
+  }
+  return (*result)->get_item_ID();
 }


-std::shared_ptr<Box_infe> HeifFile::add_new_infe_box(uint32_t item_type)
+Result<std::shared_ptr<Box_infe>> HeifFile::add_new_infe_box(uint32_t item_type)
 {
   init_for_image();

-  heif_item_id id = get_unused_item_id();
+  auto idResult = get_unused_item_id();
+  if (!idResult) {
+    return idResult.error();
+  }
+  heif_item_id id = *idResult;

   auto infe = std::make_shared<Box_infe>();
   infe->set_item_ID(id);
@@ -992,7 +988,11 @@ Result<heif_item_id> HeifFile::add_infe(uint32_t item_type, const uint8_t* data,
 {
   // create an infe box describing what kind of data we are storing (this also creates a new ID)

-  auto infe_box = add_new_infe_box(item_type);
+  auto infe_result = add_new_infe_box(item_type);
+  if (!infe_result) {
+    return infe_result.error();
+  }
+  auto infe_box = *infe_result;
   infe_box->set_hidden_item(true);

   heif_item_id metadata_id = infe_box->get_item_ID();
@@ -1013,7 +1013,11 @@ Result<heif_item_id> HeifFile::add_infe_mime(const char* content_type, heif_meta
 {
   // create an infe box describing what kind of data we are storing (this also creates a new ID)

-  auto infe_box = add_new_infe_box(fourcc("mime"));
+  auto infe_result = add_new_infe_box(fourcc("mime"));
+  if (!infe_result) {
+    return infe_result.error();
+  }
+  auto infe_box = *infe_result;
   infe_box->set_hidden_item(true);
   infe_box->set_content_type(content_type);

@@ -1029,7 +1033,11 @@ Result<heif_item_id> HeifFile::add_precompressed_infe_mime(const char* content_t
 {
   // create an infe box describing what kind of data we are storing (this also creates a new ID)

-  auto infe_box = add_new_infe_box(fourcc("mime"));
+  auto infe_result = add_new_infe_box(fourcc("mime"));
+  if (!infe_result) {
+    return infe_result.error();
+  }
+  auto infe_box = *infe_result;
   infe_box->set_hidden_item(true);
   infe_box->set_content_type(content_type);

@@ -1045,7 +1053,11 @@ Result<heif_item_id> HeifFile::add_infe_uri(const char* item_uri_type, const uin
 {
   // create an infe box describing what kind of data we are storing (this also creates a new ID)

-  auto infe_box = add_new_infe_box(fourcc("uri "));
+  auto infe_result = add_new_infe_box(fourcc("uri "));
+  if (!infe_result) {
+    return infe_result.error();
+  }
+  auto infe_box = *infe_result;
   infe_box->set_hidden_item(true);
   infe_box->set_item_uri_type(item_uri_type);

diff --git a/libheif/file.h b/libheif/file.h
index df025717..c9360ec9 100644
--- a/libheif/file.h
+++ b/libheif/file.h
@@ -22,6 +22,7 @@
 #define LIBHEIF_FILE_H

 #include "box.h"
+#include "id_creator.h"
 #include "nclx.h"
 #include "image-items/avif.h"
 #include "image-items/hevc.h"
@@ -183,11 +184,15 @@ public:

   // --- writing ---

-  heif_item_id get_unused_item_id() const;
+  IDCreator& get_id_creator() { return m_id_creator; }

-  heif_item_id add_new_image(uint32_t item_type);
+  const IDCreator& get_id_creator() const { return m_id_creator; }

-  std::shared_ptr<Box_infe> add_new_infe_box(uint32_t item_type);
+  Result<heif_item_id> get_unused_item_id();
+
+  Result<heif_item_id> add_new_image(uint32_t item_type);
+
+  Result<std::shared_ptr<Box_infe>> add_new_infe_box(uint32_t item_type);

   void add_ispe_property(heif_item_id id, uint32_t width, uint32_t height, bool essential);

@@ -285,6 +290,7 @@ private:
   std::shared_ptr<Box_mvhd> m_mvhd_box;

   const heif_security_limits* m_limits = nullptr;
+  IDCreator m_id_creator;

   Error parse_heif_file();

diff --git a/libheif/id_creator.cc b/libheif/id_creator.cc
new file mode 100644
index 00000000..dc71d4d7
--- /dev/null
+++ b/libheif/id_creator.cc
@@ -0,0 +1,54 @@
+/*
+ * HEIF codec.
+ * Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com>
+ *
+ * This file is part of libheif.
+ *
+ * libheif 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 3 of
+ * the License, or (at your option) any later version.
+ *
+ * libheif 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 libheif.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "id_creator.h"
+
+Result<uint32_t> IDCreator::get_new_id(Namespace ns)
+{
+  if (m_unif) {
+    if (m_next_id_global == 0) {
+      return Error(heif_error_Usage_error,
+                   heif_suberror_Unspecified,
+                   "ID namespace overflow");
+    }
+    return m_next_id_global++;
+  }
+
+  uint32_t* counter;
+  switch (ns) {
+    case Namespace::item:
+      counter = &m_next_id_item;
+      break;
+    case Namespace::track:
+      counter = &m_next_id_track;
+      break;
+    case Namespace::entity_group:
+      counter = &m_next_id_entity_group;
+      break;
+  }
+
+  if (*counter == 0) {
+    return Error(heif_error_Usage_error,
+                 heif_suberror_Unspecified,
+                 "ID namespace overflow");
+  }
+
+  return (*counter)++;
+}
diff --git a/libheif/id_creator.h b/libheif/id_creator.h
new file mode 100644
index 00000000..fff8c97e
--- /dev/null
+++ b/libheif/id_creator.h
@@ -0,0 +1,50 @@
+/*
+ * HEIF codec.
+ * Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com>
+ *
+ * This file is part of libheif.
+ *
+ * libheif 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 3 of
+ * the License, or (at your option) any later version.
+ *
+ * libheif 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 libheif.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBHEIF_ID_CREATOR_H
+#define LIBHEIF_ID_CREATOR_H
+
+#include "error.h"
+#include <cstdint>
+
+class IDCreator
+{
+public:
+  enum class Namespace { item, track, entity_group };
+
+  void set_unif(bool flag) { m_unif = flag; }
+
+  bool get_unif() const { return m_unif; }
+
+  // Returns a new unique ID for the given namespace.
+  // In non-unif mode: separate counters per namespace.
+  // In unif mode: single global counter shared across all namespaces.
+  // Returns error on overflow (counter would exceed 0xFFFFFFFF).
+  Result<uint32_t> get_new_id(Namespace ns);
+
+private:
+  bool m_unif = false;
+  uint32_t m_next_id_item = 1;
+  uint32_t m_next_id_track = 1;
+  uint32_t m_next_id_entity_group = 1;
+  uint32_t m_next_id_global = 1;  // used in unif mode
+};
+
+#endif
diff --git a/libheif/image-items/grid.cc b/libheif/image-items/grid.cc
index 3eb94cb4..cfd6d83a 100644
--- a/libheif/image-items/grid.cc
+++ b/libheif/image-items/grid.cc
@@ -711,7 +711,11 @@ Result<std::shared_ptr<ImageItem_Grid>> ImageItem_Grid::add_new_grid_item(HeifCo
   // Create Grid Item

   std::shared_ptr<HeifFile> file = ctx->get_heif_file();
-  heif_item_id grid_id = file->add_new_image(fourcc("grid"));
+  auto grid_id_result = file->add_new_image(fourcc("grid"));
+  if (!grid_id_result) {
+    return grid_id_result.error();
+  }
+  heif_item_id grid_id = *grid_id_result;
   grid_image = std::make_shared<ImageItem_Grid>(ctx, grid_id);
   grid_image->set_encoding_options(encoding_options);
   grid_image->set_grid_spec(grid);
@@ -842,7 +846,11 @@ Result<std::shared_ptr<ImageItem_Grid>> ImageItem_Grid::add_and_encode_full_grid

   // Create Grid Item

-  heif_item_id grid_id = file->add_new_image(fourcc("grid"));
+  auto grid_id_result = file->add_new_image(fourcc("grid"));
+  if (!grid_id_result) {
+    return grid_id_result.error();
+  }
+  heif_item_id grid_id = *grid_id_result;
   griditem = std::make_shared<ImageItem_Grid>(ctx, grid_id);
   ctx->insert_image_item(grid_id, griditem);
   const int construction_method = 1; // 0=mdat 1=idat
diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc
index bb22a2a8..232b6c20 100644
--- a/libheif/image-items/image_item.cc
+++ b/libheif/image-items/image_item.cc
@@ -387,7 +387,11 @@ Error ImageItem::encode_to_item(HeifContext* ctx,

   Encoder::CodedImageData& codedImage = *codingResult;

-  auto infe_box = ctx->get_heif_file()->add_new_infe_box(get_infe_type());
+  auto infe_result = ctx->get_heif_file()->add_new_infe_box(get_infe_type());
+  if (!infe_result) {
+    return infe_result.error();
+  }
+  auto infe_box = *infe_result;
   heif_item_id image_id = infe_box->get_item_ID();
   set_id(image_id);

diff --git a/libheif/image-items/overlay.cc b/libheif/image-items/overlay.cc
index 168eb0a8..c45a0ceb 100644
--- a/libheif/image-items/overlay.cc
+++ b/libheif/image-items/overlay.cc
@@ -445,7 +445,11 @@ Result<std::shared_ptr<ImageItem_Overlay>> ImageItem_Overlay::add_new_overlay_it

   // Create IOVL Item

-  heif_item_id iovl_id = file->add_new_image(fourcc("iovl"));
+  auto iovl_id_result = file->add_new_image(fourcc("iovl"));
+  if (!iovl_id_result) {
+    return iovl_id_result.error();
+  }
+  heif_item_id iovl_id = *iovl_id_result;
   std::shared_ptr<ImageItem_Overlay> iovl_image = std::make_shared<ImageItem_Overlay>(ctx, iovl_id);
   ctx->insert_image_item(iovl_id, iovl_image);
   const int construction_method = 1; // 0=mdat 1=idat
diff --git a/libheif/image-items/tiled.cc b/libheif/image-items/tiled.cc
index dce157cc..25feaaf2 100644
--- a/libheif/image-items/tiled.cc
+++ b/libheif/image-items/tiled.cc
@@ -605,7 +605,11 @@ ImageItem_Tiled::add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_par

   auto file = ctx->get_heif_file();

-  heif_item_id tild_id = ctx->get_heif_file()->add_new_image(fourcc("tili"));
+  auto tild_id_result = ctx->get_heif_file()->add_new_image(fourcc("tili"));
+  if (!tild_id_result) {
+    return tild_id_result.error();
+  }
+  heif_item_id tild_id = *tild_id_result;
   auto tild_image = std::make_shared<ImageItem_Tiled>(ctx, tild_id);
   tild_image->set_resolution(parameters->image_width, parameters->image_height);
   ctx->insert_image_item(tild_id, tild_image);
diff --git a/libheif/image-items/unc_image.cc b/libheif/image-items/unc_image.cc
index 5151e00b..e482e6b1 100644
--- a/libheif/image-items/unc_image.cc
+++ b/libheif/image-items/unc_image.cc
@@ -128,7 +128,11 @@ Result<std::shared_ptr<ImageItem_uncompressed>> ImageItem_uncompressed::add_unci

   auto file = ctx->get_heif_file();

-  heif_item_id unci_id = ctx->get_heif_file()->add_new_image(fourcc("unci"));
+  auto unci_id_result = ctx->get_heif_file()->add_new_image(fourcc("unci"));
+  if (!unci_id_result) {
+    return unci_id_result.error();
+  }
+  heif_item_id unci_id = *unci_id_result;
   auto unci_image = std::make_shared<ImageItem_uncompressed>(ctx, unci_id);
   unci_image->set_resolution(parameters->image_width, parameters->image_height);
   unci_image->m_unc_encoder = std::move(*uncEncoder);
diff --git a/libheif/sequences/track.cc b/libheif/sequences/track.cc
index acb916fa..fdd8f2aa 100644
--- a/libheif/sequences/track.cc
+++ b/libheif/sequences/track.cc
@@ -524,15 +524,10 @@ Track::Track(HeifContext* ctx, uint32_t track_id, const TrackOptions* options, u
   // --- find next free track ID

   if (track_id == 0) {
-    track_id = 1; // minimum track ID
-
-    for (const auto& track : m_moov->get_child_boxes<Box_trak>()) {
-      auto tkhd = track->get_child_box<Box_tkhd>();
-
-      if (tkhd->get_track_id() >= track_id) {
-        track_id = tkhd->get_track_id() + 1;
-      }
-    }
+    auto idResult = ctx->get_id_creator().get_new_id(IDCreator::Namespace::track);
+    // Track constructor cannot return errors; assert on overflow (extremely unlikely).
+    assert(idResult);
+    track_id = *idResult;

     auto mvhd = m_moov->get_child_box<Box_mvhd>();
     mvhd->set_next_track_id(track_id + 1);