Commit d07fb9cb for libheif

commit d07fb9cbfdaad84ec4b3a95d40ce7cca0d68db88
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Mon Jan 12 20:55:19 2026 +0100

    implement 'sdtp' box (decoding for informational purpose only)

diff --git a/libheif/box.cc b/libheif/box.cc
index ceafd974..76ba0f0a 100644
--- a/libheif/box.cc
+++ b/libheif/box.cc
@@ -880,6 +880,10 @@ Error Box::read(BitstreamRange& range, std::shared_ptr<Box>* result, const heif_
       box = std::make_shared<Box_tref>();
       break;

+    case fourcc("sdtp"):
+      box = std::make_shared<Box_sdtp>();
+      break;
+
     default:
       box = std::make_shared<Box_other>(hdr.get_short_type());
       break;
diff --git a/libheif/sequences/seq_boxes.cc b/libheif/sequences/seq_boxes.cc
index d9642c57..8f834c7c 100644
--- a/libheif/sequences/seq_boxes.cc
+++ b/libheif/sequences/seq_boxes.cc
@@ -2114,6 +2114,49 @@ Error Box_saio::parse(BitstreamRange& range, const heif_security_limits* limits)
 }


+std::string Box_sdtp::dump(Indent& indent) const
+{
+  std::stringstream sstr;
+  sstr << FullBox::dump(indent);
+
+  assert(m_sample_information.size() <= UINT32_MAX);
+
+  for (uint32_t i = 0; i < static_cast<uint32_t>(m_sample_information.size()); i++) {
+    const char* spaces = "            ";
+    int nSpaces = 6;
+    int k = i;
+    while (k >= 10 && nSpaces < 12) {
+      k /= 10;
+      nSpaces++;
+    }
+
+    spaces = spaces + 12 - nSpaces;
+
+    sstr << indent << "[" << i << "] : is_leading=" << (int) get_is_leading(i) << "\n"
+        << indent << spaces << "depends_on=" << (int) get_depends_on(i) << "\n"
+        << indent << spaces << "is_depended_on=" << (int) get_is_depended_on(i) << "\n"
+        << indent << spaces << "has_redundancy=" << (int) get_has_redundancy(i) << "\n";
+  }
+
+  return sstr.str();
+}
+
+
+Error Box_sdtp::parse(BitstreamRange& range, const heif_security_limits* limits)
+{
+  parse_full_box_header(range);
+
+  // We have no easy way to get the number of samples from 'saiz' or 'stz2' as specified
+  // in the standard. Instead, we read until the end of the box.
+  size_t nSamples = range.get_remaining_bytes();
+
+  m_sample_information.resize(nSamples);
+  range.read(m_sample_information.data(), nSamples);
+
+  return Error::Ok;
+}
+
+
 Error Box_tref::parse(BitstreamRange& range, const heif_security_limits* limits)
 {
   while (!range.eof()) {
diff --git a/libheif/sequences/seq_boxes.h b/libheif/sequences/seq_boxes.h
index effcd5c5..b12350dc 100644
--- a/libheif/sequences/seq_boxes.h
+++ b/libheif/sequences/seq_boxes.h
@@ -910,6 +910,35 @@ private:
 };


+class Box_sdtp : public FullBox {
+public:
+  Box_sdtp()
+  {
+    set_short_type(fourcc("sdtp"));
+  }
+
+  std::string dump(Indent&) const override;
+
+  const char* debug_box_name() const override { return "Independent and Disposable Samples"; }
+
+  // Error write(StreamWriter& writer) const override;
+
+  uint8_t get_is_leading(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx] >> 6) & 3; }
+
+  uint8_t get_depends_on(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx] >> 4) & 3; }
+
+  uint8_t get_is_depended_on(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx] >> 2) & 3; }
+
+  uint8_t get_has_redundancy(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx]) & 3; }
+
+protected:
+  Error parse(BitstreamRange& range, const heif_security_limits*) override;
+
+private:
+  std::vector<uint8_t> m_sample_information;
+};
+
+
 class Box_tref : public Box
 {
 public: