Skip to content

Commit 3d36cb1

Browse files
alastor0325kinetiknz
authored andcommitted
Accept multiple colr boxes in a video sample entry
ISO/IEC 14496-12:2015 § 12.1.5.1 permits one or more ColourInformationBoxes in a VisualSampleEntry and assigns them no normative behaviour; a reader may keep the first (most accurate) box and ignore the rest. Rejecting a sample entry that carries a second colr box therefore breaks valid files, such as the backward-compatible HLG dual-colr signaling convention. Demote the duplicate-colr case from a hard parse error under Normal strictness to warn-and-keep-first, rejecting only under Strict. The first box's CICP data is still surfaced unchanged.
1 parent fb7ed9e commit 3d36cb1

3 files changed

Lines changed: 31 additions & 1 deletion

File tree

mp4parse/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5772,9 +5772,13 @@ fn read_video_sample_entry<T: Read>(
57725772
}
57735773
BoxType::ColourInformationBox => {
57745774
if colour_info.is_some() {
5775+
// ISO/IEC 14496-12:2015 § 12.1.5.1 permits one or more colr boxes
5776+
// in a VisualSampleEntry and assigns them no normative behaviour;
5777+
// a reader may keep the first (most accurate) and ignore the rest.
5778+
// Only reject under Strict.
57755779
warn!("Multiple colr boxes in video sample entry, keeping first");
57765780
fail_with_status_if(
5777-
strictness != ParseStrictness::Permissive,
5781+
strictness == ParseStrictness::Strict,
57785782
Status::ColrBadQuantityBMFF,
57795783
)?;
57805784
skip_box_content(&mut b)?;

mp4parse_capi/tests/test_colour_info.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,32 @@ fn video_colr_nclx_rgb_identity_matrix() {
135135
}
136136
}
137137

138+
/// Two adjacent nclx colr boxes in one video sample entry (the backward-compatible
139+
/// HLG signaling convention). ISO/IEC 14496-12:2015 § 12.1.5.1 permits "one or more"
140+
/// ColourInformationBoxes and assigns them no normative behaviour; the reader keeps the
141+
/// first (most accurate) box. The parse must succeed and surface the first box (HLG,
142+
/// transfer=18), not the second (transfer=14).
143+
#[test]
144+
fn video_colr_nclx_two_colr() {
145+
unsafe {
146+
let parser = open_parser("tests/video_colr_nclx_two_colr.mp4");
147+
148+
let mut video = Mp4parseTrackVideoInfo::default();
149+
let rv = mp4parse_get_track_video_info(parser, 0, &mut video);
150+
assert_eq!(rv, Mp4parseStatus::Ok);
151+
152+
assert_eq!(video.sample_info_count, 1);
153+
let sample = &*video.sample_info;
154+
assert!(sample.has_colour_info);
155+
assert_eq!(sample.colour_primaries, 9);
156+
assert_eq!(sample.transfer_characteristics, 18); // first box (HLG) wins
157+
assert_eq!(sample.matrix_coefficients, 9);
158+
assert!(!sample.full_range_flag);
159+
160+
mp4parse_free(parser);
161+
}
162+
}
163+
138164
/// No colr box: has_colour_info=false, CICP fields are zero
139165
#[test]
140166
fn video_no_colr_box() {
1.65 KB
Binary file not shown.

0 commit comments

Comments
 (0)