scuffle_mp4/boxes/types/
tfdt.rs1use 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)]
10pub struct Tfdt {
13 pub header: FullBoxHeader,
14 pub base_media_decode_time: u64,
15}
16
17impl Tfdt {
18 pub fn new(base_media_decode_time: u64) -> Self {
19 let version = if base_media_decode_time > u32::MAX as u64 { 1 } else { 0 };
20
21 Self {
22 header: FullBoxHeader::new(Self::NAME, version, 0),
23 base_media_decode_time,
24 }
25 }
26}
27
28impl BoxType for Tfdt {
29 const NAME: [u8; 4] = *b"tfdt";
30
31 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
32 let mut reader = io::Cursor::new(data);
33
34 let header = FullBoxHeader::demux(header, &mut reader)?;
35
36 let base_media_decode_time = if header.version == 1 {
37 reader.read_u64::<BigEndian>()?
38 } else {
39 reader.read_u32::<BigEndian>()? as u64
40 };
41
42 Ok(Self {
43 header,
44 base_media_decode_time,
45 })
46 }
47
48 fn primitive_size(&self) -> u64 {
49 self.header.size() + if self.header.version == 1 { 8 } else { 4 }
50 }
51
52 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
53 self.header.mux(writer)?;
54
55 if self.header.version == 1 {
56 writer.write_u64::<BigEndian>(self.base_media_decode_time)?;
57 } else {
58 writer.write_u32::<BigEndian>(self.base_media_decode_time as u32)?;
59 }
60
61 Ok(())
62 }
63
64 fn validate(&self) -> io::Result<()> {
65 if self.header.version > 1 {
66 return Err(io::Error::new(io::ErrorKind::InvalidData, "tfdt version must be 0 or 1"));
67 }
68
69 if self.header.flags != 0 {
70 return Err(io::Error::new(io::ErrorKind::InvalidData, "tfdt flags must be 0"));
71 }
72
73 if self.header.version == 0 && self.base_media_decode_time > u32::MAX as u64 {
74 return Err(io::Error::new(
75 io::ErrorKind::InvalidData,
76 "tfdt base_data_offset must be less than 2^32",
77 ));
78 }
79
80 Ok(())
81 }
82}