#![allow(clippy::match_same_arms)]
#![forbid(unsafe_code)]
pub mod convert;
pub mod metadata;
pub mod parser;
pub mod primaries;
pub mod transfer;
pub use convert::{
ColorGamutMapper, GamutMappingMode, HdrToSdrConverter, PqToHlgConverter, ToneMappingMode,
};
pub use metadata::{
ContentLightLevel, DolbyVisionMetadata, Hdr10PlusMetadata, HlgParameters,
MasteringDisplayColorVolume,
};
pub use parser::{Av1ColorConfig, HevcSeiParser, MatroskaColorElements, Vp9ColorConfig};
pub use primaries::{ColorPrimaries, Primaries, WhitePoint};
pub use transfer::TransferCharacteristic;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct HdrMetadata {
pub mdcv: Option<MasteringDisplayColorVolume>,
pub cll: Option<ContentLightLevel>,
pub hdr10_plus: Option<Hdr10PlusMetadata>,
pub dolby_vision: Option<DolbyVisionMetadata>,
pub hlg: Option<HlgParameters>,
pub transfer: TransferCharacteristic,
pub primaries: ColorPrimaries,
}
impl HdrMetadata {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn hdr10(max_luminance: f64, min_luminance: f64, max_cll: u16, max_fall: u16) -> Self {
Self {
mdcv: Some(MasteringDisplayColorVolume {
display_primaries: ColorPrimaries::BT2020.primaries(),
white_point: ColorPrimaries::BT2020.white_point(),
max_luminance,
min_luminance,
}),
cll: Some(ContentLightLevel { max_cll, max_fall }),
hdr10_plus: None,
dolby_vision: None,
hlg: None,
transfer: TransferCharacteristic::Pq,
primaries: ColorPrimaries::BT2020,
}
}
#[must_use]
pub fn hlg(application_version: u8) -> Self {
Self {
mdcv: None,
cll: None,
hdr10_plus: None,
dolby_vision: None,
hlg: Some(HlgParameters {
application_version,
}),
transfer: TransferCharacteristic::Hlg,
primaries: ColorPrimaries::BT2020,
}
}
#[must_use]
pub fn is_hdr(&self) -> bool {
matches!(
self.transfer,
TransferCharacteristic::Pq | TransferCharacteristic::Hlg
) || self.mdcv.is_some()
}
#[must_use]
pub fn is_hdr10(&self) -> bool {
self.transfer == TransferCharacteristic::Pq
&& self.primaries == ColorPrimaries::BT2020
&& self.mdcv.is_some()
}
#[must_use]
pub fn is_hdr10_plus(&self) -> bool {
self.is_hdr10() && self.hdr10_plus.is_some()
}
#[must_use]
pub fn is_hlg(&self) -> bool {
self.transfer == TransferCharacteristic::Hlg
}
#[must_use]
pub fn is_dolby_vision(&self) -> bool {
self.dolby_vision.is_some()
}
#[must_use]
pub fn estimate_peak_luminance(&self) -> f64 {
if let Some(cll) = &self.cll {
f64::from(cll.max_cll)
} else if let Some(mdcv) = &self.mdcv {
mdcv.max_luminance
} else {
match self.transfer {
TransferCharacteristic::Pq => 1000.0, TransferCharacteristic::Hlg => 1000.0, _ => 100.0, }
}
}
#[must_use]
pub fn estimate_min_luminance(&self) -> f64 {
if let Some(mdcv) = &self.mdcv {
mdcv.min_luminance
} else {
match self.transfer {
TransferCharacteristic::Pq | TransferCharacteristic::Hlg => 0.005,
_ => 0.1,
}
}
}
#[must_use]
pub fn format_name(&self) -> &str {
if self.is_dolby_vision() {
"Dolby Vision"
} else if self.is_hdr10_plus() {
"HDR10+"
} else if self.is_hdr10() {
"HDR10"
} else if self.is_hlg() {
"HLG"
} else if self.transfer == TransferCharacteristic::Pq {
"PQ (ST.2084)"
} else {
"SDR"
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_metadata() {
let metadata = HdrMetadata::default();
assert!(!metadata.is_hdr());
assert!(!metadata.is_hdr10());
assert!(!metadata.is_hlg());
}
#[test]
fn test_hdr10_metadata() {
let metadata = HdrMetadata::hdr10(1000.0, 0.005, 1000, 400);
assert!(metadata.is_hdr());
assert!(metadata.is_hdr10());
assert!(!metadata.is_hdr10_plus());
assert!(!metadata.is_hlg());
assert_eq!(metadata.format_name(), "HDR10");
}
#[test]
fn test_hlg_metadata() {
let metadata = HdrMetadata::hlg(0);
assert!(metadata.is_hdr());
assert!(metadata.is_hlg());
assert!(!metadata.is_hdr10());
assert_eq!(metadata.format_name(), "HLG");
}
#[test]
fn test_peak_luminance_estimation() {
let metadata = HdrMetadata::hdr10(1000.0, 0.005, 1200, 400);
assert!((metadata.estimate_peak_luminance() - 1200.0).abs() < 0.01);
let metadata = HdrMetadata::new();
assert!((metadata.estimate_peak_luminance() - 100.0).abs() < 0.01);
}
#[test]
fn test_min_luminance_estimation() {
let metadata = HdrMetadata::hdr10(1000.0, 0.005, 1000, 400);
assert!((metadata.estimate_min_luminance() - 0.005).abs() < 0.0001);
}
}