moq_karp/video/
vp9.rs

1use serde::{Deserialize, Serialize};
2
3use crate::Error;
4
5#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
6pub struct VP9 {
7	pub profile: u8,
8	pub level: u8,
9	pub bit_depth: u8,
10	pub chroma_subsampling: u8,
11	pub color_primaries: u8,
12	pub transfer_characteristics: u8,
13	pub matrix_coefficients: u8,
14	pub full_range: bool,
15}
16
17// vp09.<profile>.<level>.<bitDepth>.<chromaSubsampling>.
18// <colourPrimaries>.<transferCharacteristics>.<matrixCoefficients>.<videoFullRangeFlag>
19impl std::fmt::Display for VP9 {
20	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21		write!(f, "vp09.{:02}.{:02}.{:02}", self.profile, self.level, self.bit_depth)?;
22
23		let short = VP9 {
24			profile: self.profile,
25			level: self.level,
26			bit_depth: self.bit_depth,
27			..Default::default()
28		};
29
30		if self == &short {
31			return Ok(());
32		}
33
34		write!(
35			f,
36			".{:02}.{:02}.{:02}.{:02}.{:02}",
37			self.chroma_subsampling,
38			self.color_primaries,
39			self.transfer_characteristics,
40			self.matrix_coefficients,
41			self.full_range as u8,
42		)
43	}
44}
45
46impl std::str::FromStr for VP9 {
47	type Err = Error;
48
49	fn from_str(s: &str) -> Result<Self, Self::Err> {
50		let parts = s
51			.strip_prefix("vp09.")
52			.ok_or(Error::InvalidCodec)?
53			.split('.')
54			.map(u8::from_str)
55			.collect::<Result<Vec<_>, _>>()?;
56
57		if parts.len() < 3 {
58			return Err(Error::InvalidCodec);
59		}
60
61		let mut vp9 = VP9 {
62			profile: parts[0],
63			level: parts[1],
64			bit_depth: parts[2],
65			..Default::default()
66		};
67
68		if parts.len() == 3 {
69			return Ok(vp9);
70		} else if parts.len() != 8 {
71			return Err(Error::InvalidCodec);
72		}
73
74		vp9.chroma_subsampling = parts[3];
75		vp9.color_primaries = parts[4];
76		vp9.transfer_characteristics = parts[5];
77		vp9.matrix_coefficients = parts[6];
78		vp9.full_range = parts[7] == 1;
79
80		Ok(vp9)
81	}
82}
83
84impl Default for VP9 {
85	fn default() -> Self {
86		Self {
87			profile: 0,
88			level: 0,
89			bit_depth: 0,
90			chroma_subsampling: 1,
91			color_primaries: 1,
92			transfer_characteristics: 1,
93			matrix_coefficients: 1,
94			full_range: false,
95		}
96	}
97}
98
99#[cfg(test)]
100mod test {
101	use std::str::FromStr;
102
103	use super::*;
104
105	#[test]
106	fn test_vp9() {
107		let encoded = "vp09.02.10.10.01.09.16.09.01";
108		let decoded = VP9 {
109			profile: 2,
110			level: 10,
111			bit_depth: 10,
112			chroma_subsampling: 1,
113			color_primaries: 9,
114			transfer_characteristics: 16,
115			matrix_coefficients: 9,
116			full_range: true,
117		};
118
119		let output = VP9::from_str(encoded).expect("failed to parse");
120		assert_eq!(output, decoded);
121
122		let output = decoded.to_string();
123		assert_eq!(output, encoded);
124	}
125
126	#[test]
127	fn test_vp9_short() {
128		let encoded = "vp09.00.41.08";
129		let decoded = VP9 {
130			profile: 0,
131			level: 41,
132			bit_depth: 8,
133			..Default::default()
134		};
135
136		let output = VP9::from_str(encoded).expect("failed to parse");
137		assert_eq!(output, decoded);
138
139		let output = decoded.to_string();
140		assert_eq!(output, encoded);
141	}
142}