use crate::frame::PixelFormat;
mod bitreader;
mod h264;
mod hevc;
mod av1;
mod mpeg2;
#[cfg(test)]
mod tests;
pub use h264::*;
pub use hevc::*;
pub use av1::*;
pub use mpeg2::*;
pub fn detect(codec: &str, samples: &[Vec<u8>]) -> PixelFormat {
if samples.is_empty() {
return PixelFormat::Yuv420p;
}
let result = match codec.to_lowercase().as_str() {
"h264" | "avc1" | "avc" => h264::detect_h264(&samples[0]),
"h265" | "hevc" | "hvc1" | "hev1" => hevc::detect_hevc(&samples[0]),
"vp9" | "vp09" => detect_vp9(&samples[0]),
"av1" | "av01" => av1::detect_av1(&samples[0]),
_ => None,
};
result.unwrap_or(PixelFormat::Yuv420p)
}
pub fn detect_dims(codec: &str, samples: &[Vec<u8>]) -> Option<(u32, u32)> {
if samples.is_empty() {
return None;
}
let sample = &samples[0];
match codec.to_lowercase().as_str() {
"h264" | "avc1" | "avc" | "avc3" => {
let info = parse_h264_sps(sample)?;
Some((info.width?, info.height?))
}
"h265" | "hevc" | "hvc1" | "hev1" | "hvc2" | "hev2" => {
let info = parse_hevc_sps(sample)?;
Some((info.width?, info.height?))
}
"mpeg2" | "mpeg2video" | "mp2v" => {
let info = parse_mpeg2_sequence_header(sample)?;
Some((info.width, info.height))
}
_ => None,
}
}
fn detect_vp9(sample: &[u8]) -> Option<PixelFormat> {
if sample.len() < 2 {
return None;
}
let mut br = bitreader::BitReader::new(sample);
let frame_marker = br.read_bits(2)?;
if frame_marker != 2 {
return None;
}
let profile_low = br.read_bits(1)?;
let profile_high = br.read_bits(1)?;
let profile = (profile_high << 1) | profile_low;
if profile == 3 {
let _reserved_zero = br.read_bits(1)?;
}
let show_existing_frame = br.read_bits(1)?;
if show_existing_frame == 1 {
return None;
}
let frame_type = br.read_bits(1)?;
let _show_frame = br.read_bits(1)?;
let _error_resilient = br.read_bits(1)?;
if frame_type != 0 {
return None;
}
let sync = br.read_bits(24)?;
if sync != 0x498342 {
return None;
}
let bit_depth = if profile >= 2 {
if br.read_bits(1)? == 0 { 10 } else { 12 }
} else {
8
};
let _color_space = br.read_bits(3)?;
let (sx, sy) = if profile == 1 || profile == 3 {
let _color_range = br.read_bits(1)?;
let sx = br.read_bits(1)?;
let sy = br.read_bits(1)?;
(sx, sy)
} else {
(1, 1) };
let chroma_idc = match (sx, sy) {
(1, 1) => 1, (1, 0) => 2, (0, 0) => 3, _ => 1,
};
Some(PixelFormat::from_chroma_and_depth(chroma_idc, bit_depth))
}