scuffle_mp4/boxes/types/
mdhd.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 Mdhd {
13 pub header: FullBoxHeader,
14 pub creation_time: u64,
15 pub modification_time: u64,
16 pub timescale: u32,
17 pub duration: u64,
18 pub language: u16,
19 pub pre_defined: u16,
20}
21
22impl Mdhd {
23 pub fn new(creation_time: u64, modification_time: u64, timescale: u32, duration: u64) -> Self {
24 let version = if creation_time > u32::MAX as u64 || modification_time > u32::MAX as u64 || duration > u32::MAX as u64
25 {
26 1
27 } else {
28 0
29 };
30
31 Self {
32 header: FullBoxHeader::new(Self::NAME, version, 0),
33 creation_time,
34 modification_time,
35 timescale,
36 duration,
37 language: 0x55c4, pre_defined: 0,
39 }
40 }
41}
42
43impl BoxType for Mdhd {
44 const NAME: [u8; 4] = *b"mdhd";
45
46 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
47 let mut reader = io::Cursor::new(data);
48
49 let header = FullBoxHeader::demux(header, &mut reader)?;
50
51 let (creation_time, modification_time, timescale, duration) = if header.version == 1 {
52 (
53 reader.read_u64::<BigEndian>()?, reader.read_u64::<BigEndian>()?, reader.read_u32::<BigEndian>()?, reader.read_u64::<BigEndian>()?, )
58 } else {
59 (
60 reader.read_u32::<BigEndian>()? as u64, reader.read_u32::<BigEndian>()? as u64, reader.read_u32::<BigEndian>()?, reader.read_u32::<BigEndian>()? as u64, )
65 };
66
67 let language = reader.read_u16::<BigEndian>()?;
68 let pre_defined = reader.read_u16::<BigEndian>()?;
69
70 Ok(Self {
71 header,
72 creation_time,
73 modification_time,
74 timescale,
75 duration,
76 language,
77 pre_defined,
78 })
79 }
80
81 fn primitive_size(&self) -> u64 {
82 self.header.size()
83 + if self.header.version == 1 {
84 8 + 8 + 4 + 8 } else {
86 4 + 4 + 4 + 4 }
88 + 2 + 2 }
91
92 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
93 self.header.mux(writer)?;
94
95 if self.header.version == 1 {
96 writer.write_u64::<BigEndian>(self.creation_time)?;
97 writer.write_u64::<BigEndian>(self.modification_time)?;
98 writer.write_u32::<BigEndian>(self.timescale)?;
99 writer.write_u64::<BigEndian>(self.duration)?;
100 } else {
101 writer.write_u32::<BigEndian>(self.creation_time as u32)?;
102 writer.write_u32::<BigEndian>(self.modification_time as u32)?;
103 writer.write_u32::<BigEndian>(self.timescale)?;
104 writer.write_u32::<BigEndian>(self.duration as u32)?;
105 }
106
107 writer.write_u16::<BigEndian>(self.language)?;
108 writer.write_u16::<BigEndian>(self.pre_defined)?;
109
110 Ok(())
111 }
112
113 fn validate(&self) -> io::Result<()> {
114 if self.header.flags != 0 {
115 return Err(io::Error::new(io::ErrorKind::InvalidData, "mdhd box flags must be 0"));
116 }
117
118 if self.header.version > 1 {
119 return Err(io::Error::new(io::ErrorKind::InvalidData, "mdhd box version must be 0 or 1"));
120 }
121
122 if self.header.version == 0 {
123 if self.creation_time > u32::MAX as u64 {
124 return Err(io::Error::new(
125 io::ErrorKind::InvalidData,
126 "mdhd box creation_time must be less than 2^32",
127 ));
128 }
129
130 if self.modification_time > u32::MAX as u64 {
131 return Err(io::Error::new(
132 io::ErrorKind::InvalidData,
133 "mdhd box modification_time must be less than 2^32",
134 ));
135 }
136
137 if self.duration > u32::MAX as u64 {
138 return Err(io::Error::new(
139 io::ErrorKind::InvalidData,
140 "mdhd box duration must be less than 2^32",
141 ));
142 }
143 }
144
145 if self.pre_defined != 0 {
146 return Err(io::Error::new(io::ErrorKind::InvalidData, "mdhd box pre_defined must be 0"));
147 }
148
149 Ok(())
150 }
151}