1use std::{fmt, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4
5use crate::Error;
6
7#[serde_with::serde_as]
8#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
9pub struct H264 {
10 pub profile: u8,
11 pub constraints: u8,
12 pub level: u8,
13}
14
15impl fmt::Display for H264 {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 write!(f, "avc1.{:02x}{:02x}{:02x}", self.profile, self.constraints, self.level)
18 }
19}
20
21impl FromStr for H264 {
22 type Err = Error;
23
24 fn from_str(s: &str) -> Result<Self, Self::Err> {
25 let mut parts = s.split('.');
26 if parts.next() != Some("avc1") {
27 return Err(Error::InvalidCodec);
28 }
29
30 let part = parts.next().ok_or(Error::InvalidCodec)?;
31 if part.len() != 6 {
32 return Err(Error::InvalidCodec);
33 }
34
35 Ok(Self {
36 profile: u8::from_str_radix(&part[0..2], 16)?,
37 constraints: u8::from_str_radix(&part[2..4], 16)?,
38 level: u8::from_str_radix(&part[4..6], 16)?,
39 })
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use std::str::FromStr;
46
47 use super::*;
48
49 #[test]
50 fn test_h264() {
51 let encoded = "avc1.42c01e";
52 let decoded = H264 {
53 profile: 0x42,
54 constraints: 0xc0,
55 level: 0x1e,
56 };
57
58 let output = H264::from_str(encoded).expect("failed to parse");
59 assert_eq!(output, decoded);
60
61 let output = decoded.to_string();
62 assert_eq!(output, encoded);
63 }
64}