Commit 3a4f40a5 for libheif
commit 3a4f40a5edc480e3aa9e64bd8411fe36b10c5ad6
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Fri May 15 22:37:49 2026 +0200
heif-info: show number of editlist repetitions (#1777)
diff --git a/examples/heif_info.cc b/examples/heif_info.cc
index d391abe6..1dd43107 100644
--- a/examples/heif_info.cc
+++ b/examples/heif_info.cc
@@ -1064,6 +1064,22 @@ int main(int argc, char** argv)
std::cout << " resolution: " << w << "x" << h << "\n";
}
+ uint32_t repetitions = heif_track_get_number_of_repetitions(track);
+ std::cout << " repetitions: ";
+ if (repetitions == 0) {
+ std::cout << "unsupported editlist\n";
+ }
+ else if (repetitions == heif_sequence_track_number_of_repetitions_infinite) {
+ std::cout << "infinite\n";
+ }
+ else {
+ std::cout << repetitions;
+ if (repetitions == 1) {
+ std::cout << " (single playback)";
+ }
+ std::cout << "\n";
+ }
+
uint32_t sampleEntryType = heif_track_get_sample_entry_type_of_first_cluster(track);
std::cout << " sample entry type: " << heif_examples::fourcc_to_string(sampleEntryType) << "\n";
diff --git a/libheif/api/libheif/heif_sequences.h b/libheif/api/libheif/heif_sequences.h
index aee2e3cc..3637cba4 100644
--- a/libheif/api/libheif/heif_sequences.h
+++ b/libheif/api/libheif/heif_sequences.h
@@ -170,8 +170,9 @@ uint32_t heif_track_get_timescale(const heif_track*);
* How many times the media segment should be played according to the track's edit list.
*
* Returns:
- * - 0 if the edit list is absent or follows a pattern that libheif does not interpret
+ * - 0 if an edit list box is present but follows a pattern libheif does not interpret
* as a loop count. Callers should fall back to a single playback in that case.
+ * - 1 when no edit list is present. The media plays exactly once.
* - `heif_sequence_track_number_of_repetitions_infinite` (= UINT32_MAX) when the file
* signals indefinite playback (mvhd duration is the all-1s sentinel together with an
* editlist in repeat mode), or when the repetition count does not fit in uint32_t.
diff --git a/libheif/sequences/track.cc b/libheif/sequences/track.cc
index 9a5da292..e08923bb 100644
--- a/libheif/sequences/track.cc
+++ b/libheif/sequences/track.cc
@@ -1088,7 +1088,10 @@ Error Track::init_sample_timing_table()
if (fallback) {
m_presentation_timeline = media_timeline;
m_num_output_samples = media_timeline.size();
- m_num_repetitions = 0; // editlist absent or not understood
+ // No editlist box at all: the media plays exactly once.
+ // Editlist box present but its pattern isn't one libheif interprets: report
+ // 0 so callers know they should not rely on a repetition count.
+ m_num_repetitions = m_elst ? 0 : 1;
}
return {};
diff --git a/libheif/sequences/track.h b/libheif/sequences/track.h
index 494161ca..e7ec2beb 100644
--- a/libheif/sequences/track.h
+++ b/libheif/sequences/track.h
@@ -222,11 +222,12 @@ protected:
std::vector<SampleTiming> m_presentation_timeline;
uint64_t m_num_output_samples = 0; // Can be larger than the vector. It then repeats the playback.
- // How many times the media timeline is repeated as dictated by the editlist.
- // 0 = no editlist / editlist pattern not supported (caller should assume a single playback).
+ // How many times the media timeline is repeated.
+ // 0 = editlist is present but its pattern is not understood (caller should assume a single playback).
+ // 1 = no editlist: media plays exactly once.
// UINT32_MAX = infinite (mvhd duration is the indefinite-sentinel and the editlist is in repeat mode).
// N = the media segment is played N times.
- uint32_t m_num_repetitions = 0;
+ uint32_t m_num_repetitions = 1;
// Continuous counting through all repetitions. You have to take the modulo operation to get the
// index into m_presentation_timeline SampleTiming table.