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
58impl From<Cicp> for Vec<u8> {
59    fn from(value: Cicp) -> Self {
60        vec![
61            value.color_primaries.into(),
62            value.transfer_characteristics.into(),
63            value.matrix_coefficients.into(),
64            value.video_full_range_flag.into(),
65        ]
66    }
67}
68
69utils::convertible_enum!(
70    #[repr(u8)]
71    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
72    pub enum ColorPrimaries {
73        Srgb = 1,
74        Unspecified = 2,
75        Rec2020 = 9,
76        DciP3 = 12,
77    }
78);
79
80utils::convertible_enum!(
81    #[repr(u8)]
82    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
83    pub enum TransferCharacteristics {
84        /// Gamma=2.2 curve
85        Gamma22 = 1,
86        Unspecified = 2,
87        /// Gamma=2.2 curve
88        Gamma22_ = 6,
89        /// Linear
90        Linear = 8,
91        /// Gamma=2.4 curve per IEC 61966-2-1 sRGB
92        Gamma24 = 13,
93        /// Gamma=2.2 curve 10 bit
94        Gamma22Bit10 = 14,
95        /// Gamma=2.2 curve 12 bit
96        Gamma22Bit12 = 15,
97        /// Perceptual quantization (PQ) system
98        Pq = 16,
99        /// Hybrid log-gamma (HLG) system
100        Hlg = 18,
101    }
102);
103
104utils::convertible_enum!(
105    #[repr(u8)]
106    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
107    pub enum MatrixCoefficients {
108        Identity = 0,
109        Unspecified = 2,
110        ICtCp = 14,
111    }
112);
113
114utils::maybe_convertible_enum!(
115    #[repr(u8)]
116    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
117    pub enum VideoRangeFlag {
118        Narrow = 0,
119        Full = 1,
120    }
121);
122
123#[derive(Debug, thiserror::Error)]
124pub enum CicpError {
125    #[error("Invalid video full range flag '{0}'. Expected '0' or '1'.")]
126    InvalidVideoFullRangeFlag(u8),
127}