mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-24 10:10:05 -06:00
Merge pull request #2144 from ssandweiss/fix/2142-sdr-colr-export
fix(export): tag SDR exports with a colr box (#2142)
This commit is contained in:
@@ -199,3 +199,17 @@ fn the_software_h264_sei_is_the_static_metadata_laid_out_as_messages() {
|
||||
want.push(0x80);
|
||||
assert_eq!(sei, want);
|
||||
}
|
||||
|
||||
/// #2142: SDR gets its `colr` box as well (nclc in MOV, nclx in MP4), and no HDR metadata.
|
||||
#[test]
|
||||
fn sdr_gets_a_colr_box_and_no_hdr_metadata() {
|
||||
let mut e = filmcraft_isobmff::SampleEntry::prores(filmcraft_isobmff::FourCc(*b"apch"), 64, 64);
|
||||
ColorSignal::default().apply_to(&mut e, true);
|
||||
let v = e.video.as_ref().unwrap();
|
||||
assert_eq!(v.color, Some(filmcraft_isobmff::ColorInfo::Nclc { primaries: 1, transfer: 1, matrix: 1 }));
|
||||
assert!(v.mastering_display.is_none() && v.content_light.is_none());
|
||||
let mut e = filmcraft_isobmff::SampleEntry::hevc(Default::default(), 64, 64);
|
||||
ColorSignal::default().apply_to(&mut e, false);
|
||||
let v = e.video.as_ref().unwrap();
|
||||
assert_eq!(v.color, Some(filmcraft_isobmff::ColorInfo::Nclx { primaries: 1, transfer: 1, matrix: 1, full_range: false }));
|
||||
}
|
||||
|
||||
@@ -520,11 +520,10 @@ impl ColorSignal {
|
||||
if self.matrix == 9 { (0.2627, 0.0593) } else { (0.2126, 0.0722) }
|
||||
}
|
||||
/// Sample-entry boxes: `colr` (nclx for MP4, nclc for MOV) plus `mdcv`/`clli` for PQ
|
||||
/// (mastering display BT.2020/D65, 1000/0.0001 cd/m²; MaxCLL/MaxFALL 0 = unknown).
|
||||
/// (mastering display BT.2020/D65, 1000/0.0001 cd/m²; MaxCLL/MaxFALL 0 = unknown). SDR gets
|
||||
/// its `colr` too: Apple's media stack (QuickTime Player, Final Cut Pro) reads the colour of
|
||||
/// ProRes, DNxHR and APV only from this box, not from their frame headers (#2142).
|
||||
pub fn apply_to(&self, e: &mut SampleEntry, mov: bool) {
|
||||
if !self.is_hdr() {
|
||||
return;
|
||||
}
|
||||
if let Some(v) = e.video.as_mut() {
|
||||
let (p, t, m) = (self.primaries as u16, self.transfer as u16, self.matrix as u16);
|
||||
v.color = Some(if mov {
|
||||
|
||||
@@ -126,6 +126,31 @@ fn prores_export_roundtrip() {
|
||||
assert!(f[0] > 240 && f[1] < 15 && f[2] < 15, "{:?}", &f[..4]);
|
||||
}
|
||||
|
||||
/// #2142: SDR ProRes, DNxHR and APV (MOV) and H.264 (MP4) exports carry a `colr` box with the
|
||||
/// export's BT.709 colour: Apple's media stack reads the colour of the MOV codecs only from there.
|
||||
#[test]
|
||||
fn sdr_exports_carry_a_colr_box() {
|
||||
use filmcraft_isobmff::ColorInfo;
|
||||
let (p, seq, m) = project();
|
||||
let nclc = ColorInfo::Nclc { primaries: 1, transfer: 1, matrix: 1 };
|
||||
let nclx = ColorInfo::Nclx { primaries: 1, transfer: 1, matrix: 1, full_range: false };
|
||||
for (format, name, want) in [
|
||||
(Format::ProRes, "colr-prores.mov", nclc.clone()),
|
||||
(Format::DnxHr, "colr-dnxhr.mov", nclc.clone()),
|
||||
(Format::Apv, "colr-apv.mov", nclc.clone()),
|
||||
(Format::H264, "colr-h264.mp4", nclx),
|
||||
] {
|
||||
let path = tmp(name);
|
||||
export(&p, seq, &ExportSettings { format, path: path.clone(), include_audio: false, ..Default::default() }, &m, &Progress::default()).unwrap();
|
||||
let bytes = std::fs::read(&path).unwrap();
|
||||
let file = filmcraft_isobmff::open(bytes).unwrap();
|
||||
let t = file.track_of_kind(filmcraft_isobmff::TrackKind::Video).unwrap();
|
||||
let v = file.tracks[t].entries[0].video.as_ref().unwrap();
|
||||
assert_eq!(v.color.as_ref(), Some(&want), "{name}");
|
||||
assert!(v.mastering_display.is_none() && v.content_light.is_none(), "{name}: no HDR metadata on SDR");
|
||||
}
|
||||
}
|
||||
|
||||
/// ProRes 4444 / 4444 XQ export (#342): 4:4:4 frames under the `ap4h` / `ap4x` codes, and with
|
||||
/// Include Alpha Channel the picture's alpha survives instead of being flattened over black.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user