use crate::error::{MjpegError as Error, Result};
use super::markers;
#[derive(Debug)]
pub struct MarkerSegment<'a> {
pub marker: u8,
pub payload: &'a [u8],
}
#[derive(Clone, Debug)]
pub struct SofInfo {
pub precision: u8,
pub height: u16,
pub width: u16,
pub components: Vec<SofComponent>,
}
#[derive(Clone, Copy, Debug)]
pub struct SofComponent {
pub id: u8,
pub h_factor: u8,
pub v_factor: u8,
pub qt_id: u8,
}
pub fn parse_sof(payload: &[u8]) -> Result<SofInfo> {
if payload.len() < 6 {
return Err(Error::invalid("SOF: too short"));
}
let precision = payload[0];
let height = u16::from_be_bytes([payload[1], payload[2]]);
let width = u16::from_be_bytes([payload[3], payload[4]]);
let nf = payload[5] as usize;
if payload.len() < 6 + nf * 3 {
return Err(Error::invalid("SOF: component list truncated"));
}
let mut components = Vec::with_capacity(nf);
for i in 0..nf {
let off = 6 + i * 3;
let id = payload[off];
let hv = payload[off + 1];
let qt = payload[off + 2];
components.push(SofComponent {
id,
h_factor: hv >> 4,
v_factor: hv & 0x0F,
qt_id: qt,
});
}
Ok(SofInfo {
precision,
height,
width,
components,
})
}
#[derive(Clone, Debug)]
pub struct SosInfo {
pub components: Vec<SosComponent>,
pub ss: u8,
pub se: u8,
pub ah: u8,
pub al: u8,
}
#[derive(Clone, Copy, Debug)]
pub struct SosComponent {
pub id: u8,
pub dc_table: u8,
pub ac_table: u8,
}
pub fn parse_sos(payload: &[u8]) -> Result<SosInfo> {
if payload.is_empty() {
return Err(Error::invalid("SOS: empty"));
}
let ns = payload[0] as usize;
if payload.len() < 1 + ns * 2 + 3 {
return Err(Error::invalid("SOS: truncated"));
}
let mut comps = Vec::with_capacity(ns);
for i in 0..ns {
let off = 1 + i * 2;
let id = payload[off];
let ta_td = payload[off + 1];
comps.push(SosComponent {
id,
dc_table: ta_td >> 4,
ac_table: ta_td & 0x0F,
});
}
let off = 1 + ns * 2;
let ss = payload[off];
let se = payload[off + 1];
let ah_al = payload[off + 2];
Ok(SosInfo {
components: comps,
ss,
se,
ah: ah_al >> 4,
al: ah_al & 0x0F,
})
}
#[derive(Clone, Copy, Debug)]
pub struct DacEntry {
pub tc: u8,
pub tb: u8,
pub cs: u8,
}
pub fn parse_dac(payload: &[u8]) -> Result<Vec<DacEntry>> {
if payload.len() % 2 != 0 {
return Err(Error::invalid("DAC: payload length must be even"));
}
let n = payload.len() / 2;
let mut out = Vec::with_capacity(n);
for i in 0..n {
let tc_tb = payload[i * 2];
let cs = payload[i * 2 + 1];
let tc = tc_tb >> 4;
let tb = tc_tb & 0x0F;
if tc > 1 {
return Err(Error::invalid("DAC: Tc must be 0 or 1"));
}
if tb > 3 {
return Err(Error::invalid("DAC: Tb must be 0..=3"));
}
if tc == 1 && !(1..=63).contains(&cs) {
return Err(Error::invalid("DAC: AC Kx must be 1..=63"));
}
out.push(DacEntry { tc, tb, cs });
}
Ok(out)
}
pub fn parse_dri(payload: &[u8]) -> Result<u16> {
if payload.len() < 2 {
return Err(Error::invalid("DRI: too short"));
}
Ok(u16::from_be_bytes([payload[0], payload[1]]))
}
pub fn parse_dnl(payload: &[u8]) -> Result<u16> {
if payload.len() < 2 {
return Err(Error::invalid("DNL: too short"));
}
let nl = u16::from_be_bytes([payload[0], payload[1]]);
if nl == 0 {
return Err(Error::invalid("DNL: NL = 0"));
}
Ok(nl)
}
pub struct MarkerWalker<'a> {
buf: &'a [u8],
pub pos: usize,
}
impl<'a> MarkerWalker<'a> {
pub fn new(buf: &'a [u8]) -> Self {
Self { buf, pos: 0 }
}
pub fn next_marker(&mut self) -> Result<Option<u8>> {
while self.pos < self.buf.len() {
if self.buf[self.pos] != 0xFF {
self.pos += 1;
continue;
}
while self.pos < self.buf.len() && self.buf[self.pos] == 0xFF {
self.pos += 1;
}
if self.pos >= self.buf.len() {
return Ok(None);
}
let m = self.buf[self.pos];
self.pos += 1;
if m == 0x00 {
continue;
}
return Ok(Some(m));
}
Ok(None)
}
pub fn read_segment_payload(&mut self) -> Result<&'a [u8]> {
if self.pos + 2 > self.buf.len() {
return Err(Error::invalid("marker segment: truncated length"));
}
let len = u16::from_be_bytes([self.buf[self.pos], self.buf[self.pos + 1]]) as usize;
if len < 2 {
return Err(Error::invalid("marker segment: length < 2"));
}
if self.pos + len > self.buf.len() {
return Err(Error::invalid("marker segment: payload truncated"));
}
let p = &self.buf[self.pos + 2..self.pos + len];
self.pos += len;
Ok(p)
}
pub fn read_scan_data(&mut self) -> Result<&'a [u8]> {
let start = self.pos;
while self.pos < self.buf.len() {
if self.buf[self.pos] == 0xFF {
if self.pos + 1 >= self.buf.len() {
return Err(Error::invalid("scan: truncated at 0xFF"));
}
let nxt = self.buf[self.pos + 1];
if nxt == 0x00 {
self.pos += 2;
continue;
}
if markers::is_rst(nxt) {
self.pos += 2;
continue;
}
return Ok(&self.buf[start..self.pos]);
}
self.pos += 1;
}
Ok(&self.buf[start..self.pos])
}
}