gufo_common/
cicp.rs

1//! Coding-independent code points
2//!
3//! - [ITU-T H.273: Coding-independent code points for video signal type identification](https://www.itu.int/rec/T-REC-H.273)
4
5use crate::utils;
6
7/// Coding-independent code points
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub struct Cicp {
10    pub color_primaries: ColorPrimaries,
11    pub transfer_characteristics: TransferCharacteristics,
12    pub matrix_coefficients: MatrixCoefficients,
13    pub video_full_range_flag: VideoRangeFlag,
14}
15
16impl Cicp {
17    pub const SRGB: Cicp = Cicp {
18        color_primaries: ColorPrimaries::Srgb,
19        transfer_characteristics: TransferCharacteristics::Gamma24,
20        matrix_coefficients: MatrixCoefficients::Identity,
21        video_full_range_flag: VideoRangeFlag::Full,
22    };
23
24    pub const REC2020_LINEAR: Cicp = Cicp {
25        color_primaries: ColorPrimaries::Rec2020,
26        transfer_characteristics: TransferCharacteristics::Linear,
27        matrix_coefficients: MatrixCoefficients::Identity,
28        video_full_range_flag: VideoRangeFlag::Full,
29    };
30
31    /// Get CICP from bytes in the order of struct definition
32    ///
33    /// ```
34    /// # use gufo_common::cicp::*;
35    /// let cicp = Cicp::from_bytes(&[0x09, 0x10, 0x00, 0x01]).unwrap();
36    ///
37    /// assert_eq!(cicp.color_primaries, ColorPrimaries::Rec2020);
38    /// assert_eq!(cicp.transfer_characteristics, TransferCharacteristics::Pq);
39    /// assert_eq!(cicp.matrix_coefficients, MatrixCoefficients::Identity);
40    /// assert_eq!(cicp.video_full_range_flag, VideoRangeFlag::Full);
41    /// ```
42    pub fn from_bytes(bytes: &[u8; 4]) -> Result<Self, CicpError> {
43        let color_primaries = ColorPrimaries::from(bytes[0]);
44        let transfer_characteristics = TransferCharacteristics::from(bytes[1]);
45        let matrix_coefficients: MatrixCoefficients = MatrixCoefficients::from(bytes[2]);
46        let video_full_range_flag = VideoRangeFlag::try_from(bytes[3])
47            .map_err(|err| CicpError::InvalidVideoFullRangeFlag(err.0))?;
48
49        Ok(Self {
50            color_primaries,
51            transfer_characteristics,
52            matrix_coefficients,
53            video_full_range_flag,
54        })
55    }
56
57    /// Get CICP values as bytes
58    ///
59    /// ```
60    /// # use gufo_common::cicp::*;
61    /// let bytes = [0x09, 0x10, 0x00, 0x01];
62    /// let cicp = Cicp::from_bytes(&bytes).unwrap();
63    ///
64    /// assert_eq!(cicp.to_bytes(), bytes);
65    /// ```
66    pub fn to_bytes(&self) -> [u8; 4] {
67        [
68            self.color_primaries.into(),
69            self.transfer_characteristics.into(),
70            self.matrix_coefficients.into(),
71            self.video_full_range_flag.into(),
72        ]
73    }
74}
75
76impl From<Cicp> for Vec<u8> {
77    fn from(value: Cicp) -> Self {
78        vec![
79            value.color_primaries.into(),
80            value.transfer_characteristics.into(),
81            value.matrix_coefficients.into(),
82            value.video_full_range_flag.into(),
83        ]
84    }
85}
86
87utils::convertible_enum!(
88    #[repr(u8)]
89    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
90    pub enum ColorPrimaries {
91        Srgb = 1,
92        Unspecified = 2,
93        Rec2020 = 9,
94        DciP3 = 11,
95        DisplayP3 = 12,
96    }
97);
98
99utils::convertible_enum!(
100    #[repr(u8)]
101    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
102    pub enum TransferCharacteristics {
103        /// Gamma=2.2 curve
104        Gamma22 = 1,
105        Unspecified = 2,
106        /// Gamma=2.2 curve
107        Gamma22_ = 6,
108        /// Linear
109        Linear = 8,
110        /// Gamma=2.4 curve per IEC 61966-2-1 sRGB
111        Gamma24 = 13,
112        /// Gamma=2.2 curve 10 bit
113        Gamma22Bit10 = 14,
114        /// Gamma=2.2 curve 12 bit
115        Gamma22Bit12 = 15,
116        /// Perceptual quantization (PQ) system
117        Pq = 16,
118        /// SMPTE ST 428-1
119        Dci = 17,
120        /// Hybrid log-gamma (HLG) system
121        Hlg = 18,
122    }
123);
124
125utils::convertible_enum!(
126    #[repr(u8)]
127    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
128    pub enum MatrixCoefficients {
129        Identity = 0,
130        Unspecified = 2,
131        ICtCp = 14,
132    }
133);
134
135utils::maybe_convertible_enum!(
136    #[repr(u8)]
137    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
138    pub enum VideoRangeFlag {
139        Narrow = 0,
140        Full = 1,
141    }
142);
143
144#[derive(Debug, thiserror::Error)]
145pub enum CicpError {
146    #[error("Invalid video full range flag '{0}'. Expected '0' or '1'.")]
147    InvalidVideoFullRangeFlag(u8),
148}