Skip to main content

pito_codecs/mp4/
boxes.rs

1use crate::media::{Error, Result};
2use crate::mp4::truncated;
3use std::fmt;
4
5#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
6pub struct FourCc(pub [u8; 4]);
7
8impl FourCc {
9    pub const fn new(b: &[u8; 4]) -> Self {
10        FourCc(*b)
11    }
12    pub fn as_u32(self) -> u32 {
13        u32::from_be_bytes(self.0)
14    }
15    pub fn to_string_lossy(self) -> String {
16        self.0
17            .iter()
18            .map(|&b| match b {
19                0xA9 => '©',
20                0x20..=0x7E => b as char,
21                _ => '?',
22            })
23            .collect()
24    }
25}
26
27impl fmt::Display for FourCc {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.write_str(&self.to_string_lossy())
30    }
31}
32impl fmt::Debug for FourCc {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        write!(f, "FourCc({:?})", self.to_string_lossy())
35    }
36}
37impl From<&[u8; 4]> for FourCc {
38    fn from(b: &[u8; 4]) -> Self {
39        FourCc(*b)
40    }
41}
42impl PartialEq<[u8; 4]> for FourCc {
43    fn eq(&self, other: &[u8; 4]) -> bool {
44        &self.0 == other
45    }
46}
47impl PartialEq<&[u8; 4]> for FourCc {
48    fn eq(&self, other: &&[u8; 4]) -> bool {
49        &self.0 == *other
50    }
51}
52impl PartialEq<&&[u8; 4]> for FourCc {
53    fn eq(&self, other: &&&[u8; 4]) -> bool {
54        &self.0 == **other
55    }
56}
57
58#[derive(Clone)]
59pub(crate) struct Cur<'a> {
60    pub data: &'a [u8],
61    pub pos: usize,
62    what: &'static str,
63}
64
65impl<'a> Cur<'a> {
66    pub fn new(data: &'a [u8], what: &'static str) -> Self {
67        Cur { data, pos: 0, what }
68    }
69    pub fn remaining(&self) -> usize {
70        self.data.len().saturating_sub(self.pos)
71    }
72    pub fn rest(&self) -> &'a [u8] {
73        self.data.get(self.pos..).unwrap_or(&[])
74    }
75    pub fn bytes(&mut self, n: usize) -> Result<&'a [u8]> {
76        let end = self
77            .pos
78            .checked_add(n)
79            .ok_or_else(|| truncated(self.what))?;
80        let s = self
81            .data
82            .get(self.pos..end)
83            .ok_or_else(|| truncated(self.what))?;
84        self.pos = end;
85        Ok(s)
86    }
87    pub fn skip(&mut self, n: usize) -> Result<()> {
88        self.bytes(n).map(|_| ())
89    }
90    pub fn array<const N: usize>(&mut self) -> Result<[u8; N]> {
91        let s = self.bytes(N)?;
92        let mut a = [0u8; N];
93        a.copy_from_slice(s);
94        Ok(a)
95    }
96    pub fn u8(&mut self) -> Result<u8> {
97        Ok(self.array::<1>()?[0])
98    }
99    pub fn u16(&mut self) -> Result<u16> {
100        Ok(u16::from_be_bytes(self.array()?))
101    }
102    pub fn u24(&mut self) -> Result<u32> {
103        let a = self.array::<3>()?;
104        Ok(((a[0] as u32) << 16) | ((a[1] as u32) << 8) | a[2] as u32)
105    }
106    pub fn u32(&mut self) -> Result<u32> {
107        Ok(u32::from_be_bytes(self.array()?))
108    }
109    pub fn i32(&mut self) -> Result<i32> {
110        Ok(i32::from_be_bytes(self.array()?))
111    }
112    pub fn u64(&mut self) -> Result<u64> {
113        Ok(u64::from_be_bytes(self.array()?))
114    }
115    pub fn i64(&mut self) -> Result<i64> {
116        Ok(i64::from_be_bytes(self.array()?))
117    }
118    pub fn f64(&mut self) -> Result<f64> {
119        Ok(f64::from_be_bytes(self.array()?))
120    }
121    pub fn fourcc(&mut self) -> Result<FourCc> {
122        Ok(FourCc(self.array()?))
123    }
124    pub fn full_header(&mut self) -> Result<(u8, u32)> {
125        let v = self.u32()?;
126        Ok(((v >> 24) as u8, v & 0x00FF_FFFF))
127    }
128    pub fn count(&mut self, entry_size: usize) -> Result<usize> {
129        let n = self.u32()? as usize;
130        self.check_count(n, entry_size)?;
131        Ok(n)
132    }
133    pub fn check_count(&self, n: usize, entry_size: usize) -> Result<()> {
134        match n.checked_mul(entry_size) {
135            Some(b) if b <= self.remaining() => Ok(()),
136            _ => Err(truncated(self.what)),
137        }
138    }
139}
140
141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
142pub(crate) struct BoxHeader {
143    pub kind: FourCc,
144    pub header_len: u64,
145    pub size: Option<u64>,
146}
147
148pub(crate) fn parse_box_header(buf: &[u8]) -> Result<BoxHeader> {
149    let mut c = Cur::new(buf, "box header");
150    let size32 = c.u32()?;
151    let kind = c.fourcc()?;
152    let mut header_len = 8u64;
153    let size = match size32 {
154        0 => None,
155        1 => {
156            header_len += 8;
157            let s = c.u64()?;
158            Some(s)
159        }
160        s => Some(s as u64),
161    };
162    if kind == b"uuid" {
163        header_len += 16;
164        c.array::<16>()?;
165    }
166    if let Some(s) = size
167        && s < header_len
168    {
169        return Err(Error::Invalid(format!(
170            "box '{kind}' size {s} smaller than its header"
171        )));
172    }
173    Ok(BoxHeader {
174        kind,
175        header_len,
176        size,
177    })
178}
179
180#[derive(Clone, Copy, Debug)]
181pub(crate) struct RawBox<'a> {
182    pub kind: FourCc,
183    pub payload: &'a [u8],
184}
185
186pub(crate) struct Boxes<'a> {
187    data: &'a [u8],
188    pos: usize,
189    done: bool,
190}
191
192pub(crate) fn boxes(data: &[u8]) -> Boxes<'_> {
193    Boxes {
194        data,
195        pos: 0,
196        done: false,
197    }
198}
199
200impl<'a> Iterator for Boxes<'a> {
201    type Item = Result<RawBox<'a>>;
202    fn next(&mut self) -> Option<Self::Item> {
203        if self.done {
204            return None;
205        }
206        let rest = &self.data[self.pos..];
207        if rest.is_empty() {
208            self.done = true;
209            return None;
210        }
211        if rest.len() < 8 {
212            self.done = true;
213            if rest.iter().all(|&b| b == 0) {
214                return None;
215            }
216            return Some(Err(truncated("box header")));
217        }
218        let h = match parse_box_header(rest) {
219            Ok(h) => h,
220            Err(e) => {
221                self.done = true;
222                return Some(Err(e));
223            }
224        };
225        let size = h.size.unwrap_or(rest.len() as u64);
226        if size > rest.len() as u64 {
227            self.done = true;
228            return Some(Err(Error::Invalid(format!(
229                "box '{}' size {} exceeds its container ({} bytes left)",
230                h.kind,
231                size,
232                rest.len()
233            ))));
234        }
235        let size = size as usize;
236        let payload = &rest[h.header_len as usize..size];
237        self.pos += size;
238        Some(Ok(RawBox {
239            kind: h.kind,
240            payload,
241        }))
242    }
243}
244
245pub(crate) fn find<'a>(data: &'a [u8], kind: &[u8; 4]) -> Option<&'a [u8]> {
246    boxes(data)
247        .map_while(|b| b.ok())
248        .find(|b| b.kind == kind)
249        .map(|b| b.payload)
250}
251
252#[derive(Default, Clone, Debug)]
253pub(crate) struct BoxBuf {
254    pub buf: Vec<u8>,
255}
256
257impl BoxBuf {
258    pub fn new() -> Self {
259        Self::default()
260    }
261    pub fn start(&mut self, kind: &[u8; 4]) -> usize {
262        let at = self.buf.len();
263        self.buf.extend_from_slice(&[0, 0, 0, 0]);
264        self.buf.extend_from_slice(kind);
265        at
266    }
267    pub fn start_full(&mut self, kind: &[u8; 4], version: u8, flags: u32) -> usize {
268        let at = self.start(kind);
269        self.u32(((version as u32) << 24) | (flags & 0xFF_FFFF));
270        at
271    }
272    pub fn end(&mut self, at: usize) {
273        let size = (self.buf.len() - at) as u32;
274        self.buf[at..at + 4].copy_from_slice(&size.to_be_bytes());
275    }
276    pub fn leaf(&mut self, kind: &[u8; 4], payload: &[u8]) {
277        let at = self.start(kind);
278        self.bytes(payload);
279        self.end(at);
280    }
281    pub fn u8(&mut self, v: u8) {
282        self.buf.push(v);
283    }
284    pub fn u16(&mut self, v: u16) {
285        self.buf.extend_from_slice(&v.to_be_bytes());
286    }
287    pub fn i16(&mut self, v: i16) {
288        self.buf.extend_from_slice(&v.to_be_bytes());
289    }
290    pub fn u32(&mut self, v: u32) {
291        self.buf.extend_from_slice(&v.to_be_bytes());
292    }
293    pub fn i32(&mut self, v: i32) {
294        self.buf.extend_from_slice(&v.to_be_bytes());
295    }
296    pub fn u64(&mut self, v: u64) {
297        self.buf.extend_from_slice(&v.to_be_bytes());
298    }
299    pub fn i64(&mut self, v: i64) {
300        self.buf.extend_from_slice(&v.to_be_bytes());
301    }
302    pub fn bytes(&mut self, b: &[u8]) {
303        self.buf.extend_from_slice(b);
304    }
305    pub fn zeros(&mut self, n: usize) {
306        self.buf.resize(self.buf.len() + n, 0);
307    }
308    pub fn len(&self) -> usize {
309        self.buf.len()
310    }
311}