codec/pixel_format/
mod.rs1use crate::frame::PixelFormat;
16
17mod bitreader;
18mod h264;
19mod hevc;
20mod av1;
21mod mpeg2;
22
23#[cfg(test)]
24mod tests;
25
26pub use h264::*;
27pub use hevc::*;
28pub use av1::*;
29pub use mpeg2::*;
30
31pub fn detect(codec: &str, samples: &[Vec<u8>]) -> PixelFormat {
36 if samples.is_empty() {
37 return PixelFormat::Yuv420p;
38 }
39
40 let result = match codec.to_lowercase().as_str() {
41 "h264" | "avc1" | "avc" => h264::detect_h264(&samples[0]),
42 "h265" | "hevc" | "hvc1" | "hev1" => hevc::detect_hevc(&samples[0]),
43 "vp9" | "vp09" => detect_vp9(&samples[0]),
44 "av1" | "av01" => av1::detect_av1(&samples[0]),
45 _ => None,
46 };
47
48 result.unwrap_or(PixelFormat::Yuv420p)
49}
50
51pub fn detect_dims(codec: &str, samples: &[Vec<u8>]) -> Option<(u32, u32)> {
60 if samples.is_empty() {
61 return None;
62 }
63 let sample = &samples[0];
64 match codec.to_lowercase().as_str() {
65 "h264" | "avc1" | "avc" | "avc3" => {
66 let info = parse_h264_sps(sample)?;
67 Some((info.width?, info.height?))
68 }
69 "h265" | "hevc" | "hvc1" | "hev1" | "hvc2" | "hev2" => {
70 let info = parse_hevc_sps(sample)?;
71 Some((info.width?, info.height?))
72 }
73 "mpeg2" | "mpeg2video" | "mp2v" => {
74 let info = parse_mpeg2_sequence_header(sample)?;
75 Some((info.width, info.height))
76 }
77 _ => None,
78 }
79}
80
81fn detect_vp9(sample: &[u8]) -> Option<PixelFormat> {
86 if sample.len() < 2 {
87 return None;
88 }
89 let mut br = bitreader::BitReader::new(sample);
90 let frame_marker = br.read_bits(2)?;
91 if frame_marker != 2 {
92 return None;
93 }
94 let profile_low = br.read_bits(1)?;
95 let profile_high = br.read_bits(1)?;
96 let profile = (profile_high << 1) | profile_low;
97 if profile == 3 {
98 let _reserved_zero = br.read_bits(1)?;
99 }
100 let show_existing_frame = br.read_bits(1)?;
101 if show_existing_frame == 1 {
102 return None;
103 }
104 let frame_type = br.read_bits(1)?;
105 let _show_frame = br.read_bits(1)?;
106 let _error_resilient = br.read_bits(1)?;
107
108 if frame_type != 0 {
110 return None;
111 }
112
113 let sync = br.read_bits(24)?;
115 if sync != 0x498342 {
116 return None;
117 }
118
119 let bit_depth = if profile >= 2 {
120 if br.read_bits(1)? == 0 { 10 } else { 12 }
121 } else {
122 8
123 };
124 let _color_space = br.read_bits(3)?;
125 let (sx, sy) = if profile == 1 || profile == 3 {
129 let _color_range = br.read_bits(1)?;
130 let sx = br.read_bits(1)?;
131 let sy = br.read_bits(1)?;
132 (sx, sy)
133 } else {
134 (1, 1) };
136
137 let chroma_idc = match (sx, sy) {
138 (1, 1) => 1, (1, 0) => 2, (0, 0) => 3, _ => 1,
142 };
143
144 Some(PixelFormat::from_chroma_and_depth(chroma_idc, bit_depth))
145}