From 7c93401f7d76bffce49f1a6b49babc70864c449d Mon Sep 17 00:00:00 2001 From: Alastor Wu Date: Wed, 3 Jun 2026 14:23:52 -0700 Subject: [PATCH] Accept multiple colr boxes in a video sample entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- mp4parse/src/lib.rs | 6 +++- mp4parse_capi/tests/test_colour_info.rs | 26 ++++++++++++++++++ .../tests/video_colr_nclx_two_colr.mp4 | Bin 0 -> 1685 bytes 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 mp4parse_capi/tests/video_colr_nclx_two_colr.mp4 diff --git a/mp4parse/src/lib.rs b/mp4parse/src/lib.rs index 955e902f..6a404556 100644 --- a/mp4parse/src/lib.rs +++ b/mp4parse/src/lib.rs @@ -5772,9 +5772,13 @@ fn read_video_sample_entry( } BoxType::ColourInformationBox => { if colour_info.is_some() { + // ISO/IEC 14496-12:2015 § 12.1.5.1 permits one or more colr boxes + // in a VisualSampleEntry and assigns them no normative behaviour; + // a reader may keep the first (most accurate) and ignore the rest. + // Only reject under Strict. warn!("Multiple colr boxes in video sample entry, keeping first"); fail_with_status_if( - strictness != ParseStrictness::Permissive, + strictness == ParseStrictness::Strict, Status::ColrBadQuantityBMFF, )?; skip_box_content(&mut b)?; diff --git a/mp4parse_capi/tests/test_colour_info.rs b/mp4parse_capi/tests/test_colour_info.rs index 3d0312d1..eaed00e7 100644 --- a/mp4parse_capi/tests/test_colour_info.rs +++ b/mp4parse_capi/tests/test_colour_info.rs @@ -135,6 +135,32 @@ fn video_colr_nclx_rgb_identity_matrix() { } } +/// Two adjacent nclx colr boxes in one video sample entry (the backward-compatible +/// HLG signaling convention). ISO/IEC 14496-12:2015 § 12.1.5.1 permits "one or more" +/// ColourInformationBoxes and assigns them no normative behaviour; the reader keeps the +/// first (most accurate) box. The parse must succeed and surface the first box (HLG, +/// transfer=18), not the second (transfer=14). +#[test] +fn video_colr_nclx_two_colr() { + unsafe { + let parser = open_parser("tests/video_colr_nclx_two_colr.mp4"); + + let mut video = Mp4parseTrackVideoInfo::default(); + let rv = mp4parse_get_track_video_info(parser, 0, &mut video); + assert_eq!(rv, Mp4parseStatus::Ok); + + assert_eq!(video.sample_info_count, 1); + let sample = &*video.sample_info; + assert!(sample.has_colour_info); + assert_eq!(sample.colour_primaries, 9); + assert_eq!(sample.transfer_characteristics, 18); // first box (HLG) wins + assert_eq!(sample.matrix_coefficients, 9); + assert!(!sample.full_range_flag); + + mp4parse_free(parser); + } +} + /// No colr box: has_colour_info=false, CICP fields are zero #[test] fn video_no_colr_box() { diff --git a/mp4parse_capi/tests/video_colr_nclx_two_colr.mp4 b/mp4parse_capi/tests/video_colr_nclx_two_colr.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..23d1f715f4fb39cb5a6adadfb78ed10c48a2e6f3 GIT binary patch literal 1685 zcmZuy&5ImG6tCG$77al~SIA+7GDZ-|%y##zT>db*kZsI98q zoykcdhxHH8g9q`dh=*J}8CQrPcotmnVni`0dXrqt_UkPRqyvc>*KxZVT|$A zjdX77lCcFw93v3>(l7Oz&lr0oHA=zuOPL4<{`u0`@%YmpuipFe*W;ZpKDhh?KYs4d zzlK3?jkme1jp9C_>H6L}@A}H$NH<{E>A+$2jW@5p)?VXV*S6uAC<()Mtw)7Q9S=OO z+YY>-3uWe<-dtThI5_C+=ZUHdQFUt5U!_$#nJWwU)Y|2BWjDDLv5=w9jY`8VPgGpg zauE8P-loSzC5n+%p*QSqdPCpu@=}GF8gjcA1HH_(9U&BRWRlSDcnHG8%Y3Mkh%)+! zh>WQED)f6?W~MGhgixP5qlzN8K8t?X$h*Z@;Fd-um!j@yb^ZjtI9t+8Ui3-+7m@#ly0$_n|Aw{VV~Wqs8AK z3|WiO?}Yv%Kz&NSa^m@aXaNuE7Vc#LHuHt?7<>a>+pUD18~?;s`rw}(M~8<; z*KfXe=3{gRJvLE2p@r2j z(S~U(qt~a^xP6x~8tj5~O{D-EA9MqikuBo_sDebZ_!s1fFLe#{sAj{Lro4$=L98SN zXcjy5XB@U06H_zOdfxz@pAM`m>#3b$J&brSaRU5$sTxk^XXm>Don(a8RJe!K&L^$+ a{3ouagwNpbgpyEFhVrB+kKaRiyng{fL3|eg literal 0 HcmV?d00001