#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-codec-av1x -- AV1 OBU (Open Bitstream Unit) Parser
#[derive(Debug)] pub enum Av1Error { InvalidObu(String), TruncatedData(String) }
impl std::fmt::Display for Av1Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidObu(e)|Self::TruncatedData(e) => write!(f, "{e}") } } }
impl std::error::Error for Av1Error {}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ObuType { SeqHeader=1, TempDelimiter=2, FrameHeader=3, TileGroup=4, Metadata=5, Frame=6, RedundantFrameHeader=7, TileList=8, Padding=15, Unknown=0 }
impl ObuType { pub fn from_u8(v: u8) -> Self { match v { 1=>Self::SeqHeader,2=>Self::TempDelimiter,3=>Self::FrameHeader,4=>Self::TileGroup,5=>Self::Metadata,6=>Self::Frame,7=>Self::RedundantFrameHeader,8=>Self::TileList,15=>Self::Padding,_=>Self::Unknown } } }
#[derive(Debug, Clone)] pub struct Obu { pub obu_type: ObuType, pub has_size: bool, pub size: u64, pub temporal_id: u8, pub spatial_id: u8, pub payload: Vec<u8> }
pub fn read_leb128(data: &[u8]) -> Result<(u64, usize), Av1Error> {
    let mut value: u64 = 0; let mut bytes_read = 0;
    for (i, &byte) in data.iter().enumerate().take(8) {
        value |= ((byte & 0x7F) as u64) << (i * 7);
        bytes_read = i + 1;
        if byte & 0x80 == 0 { return Ok((value, bytes_read)); }
    }
    if bytes_read == 0 { Err(Av1Error::TruncatedData("Empty".into())) } else { Ok((value, bytes_read)) }
}
pub struct Av1Parser;
impl Av1Parser {
    pub fn parse_obu(data: &[u8]) -> Result<Obu, Av1Error> {
        if data.is_empty() { return Err(Av1Error::TruncatedData("Empty".into())); }
        let header = data[0];
        let obu_type = ObuType::from_u8((header >> 3) & 0x0F);
        let has_extension = (header >> 2) & 1 == 1;
        let has_size = (header >> 1) & 1 == 1;
        let mut offset = 1usize;
        let (temporal_id, spatial_id) = if has_extension {
            if offset >= data.len() { return Err(Av1Error::TruncatedData("No ext".into())); }
            let ext = data[offset]; offset += 1;
            ((ext >> 5) & 0x07, (ext >> 3) & 0x03)
        } else { (0, 0) };
        let size = if has_size {
            let (s, n) = read_leb128(&data[offset..])?; offset += n; s
        } else { (data.len() - offset) as u64 };
        let end = (offset + size as usize).min(data.len());
        Ok(Obu { obu_type, has_size, size, temporal_id, spatial_id, payload: data[offset..end].to_vec() })
    }
}
#[cfg(test)] mod tests {
    use super::*;
    #[test] fn test_leb128() { let (v, n) = read_leb128(&[0x80, 0x01]).unwrap(); assert_eq!(v, 128); assert_eq!(n, 2); }
    #[test] fn test_leb128_single() { let (v, n) = read_leb128(&[42]).unwrap(); assert_eq!(v, 42); assert_eq!(n, 1); }
    #[test] fn test_parse_obu() { let data = [0x0A, 0x03, 0xAA, 0xBB, 0xCC]; let obu = Av1Parser::parse_obu(&data).unwrap(); assert_eq!(obu.obu_type, ObuType::SeqHeader); }
}
