scuffle_mp4/boxes/types/
co64.rs

1use std::io;
2
3use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
4use bytes::Bytes;
5
6use crate::boxes::header::{BoxHeader, FullBoxHeader};
7use crate::boxes::traits::BoxType;
8
9#[derive(Debug, Clone, PartialEq)]
10/// Chunk Large Offset Box
11/// ISO/IEC 14496-12:2022(E) - 8.7.5
12pub struct Co64 {
13    pub header: FullBoxHeader,
14    pub chunk_offset: Vec<u32>,
15}
16
17impl BoxType for Co64 {
18    const NAME: [u8; 4] = *b"co64";
19
20    fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
21        let mut reader = io::Cursor::new(data);
22
23        let header = FullBoxHeader::demux(header, &mut reader)?;
24
25        let entry_count = reader.read_u32::<BigEndian>()?;
26        let mut chunk_offset = Vec::with_capacity(entry_count as usize);
27        for _ in 0..entry_count {
28            let offset = reader.read_u32::<BigEndian>()?;
29            chunk_offset.push(offset);
30        }
31
32        Ok(Self { header, chunk_offset })
33    }
34
35    fn primitive_size(&self) -> u64 {
36        self.header.size()
37        + 4 // entry_count
38        + (self.chunk_offset.len() as u64 * 4) // chunk_offset
39    }
40
41    fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
42        self.header.mux(writer)?;
43
44        writer.write_u32::<BigEndian>(self.chunk_offset.len() as u32)?;
45        for offset in &self.chunk_offset {
46            writer.write_u32::<BigEndian>(*offset)?;
47        }
48
49        Ok(())
50    }
51
52    fn validate(&self) -> io::Result<()> {
53        if self.header.flags != 0 {
54            return Err(io::Error::new(io::ErrorKind::InvalidData, "co64 flags must be 0"));
55        }
56
57        if self.header.version != 0 {
58            return Err(io::Error::new(io::ErrorKind::InvalidData, "co64 version must be 0"));
59        }
60
61        Ok(())
62    }
63}