1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
|
/*
This file is part of jellything (https://codeberg.org/metamuffin/jellything)
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use crate::{BoxW, WriteBox};
macro_rules! container_box {
($typ:tt, $iden:literal) => {
pub struct $typ<T: Fn(&mut BoxW)>(pub T);
impl<T: Fn(&mut BoxW)> WriteBox for $typ<T> {
const BOXTYPE: [u8; 4] = *$iden;
fn write(&self, buf: &mut Vec<u8>) {
self.0(&mut BoxW(buf))
}
}
};
}
container_box!(Movie, b"moov");
container_box!(Track, b"trak");
container_box!(Edit, b"edts");
container_box!(Media, b"mdia");
container_box!(MediaInformation, b"minf");
container_box!(DataInformation, b"dinf");
container_box!(SampleTable, b"stbl");
container_box!(MovieFragment, b"stbl");
container_box!(TrackFragment, b"stbl");
pub struct FileType<'a> {
pub major_brand: [u8; 4],
pub minor_version: u32,
pub compatible_brands: &'a [[u8; 4]],
}
impl WriteBox for FileType<'_> {
const BOXTYPE: [u8; 4] = *b"ftyp";
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.major_brand);
buf.extend(self.minor_version.to_be_bytes());
for cb in self.compatible_brands {
buf.extend(cb);
}
}
}
pub struct MovieHeader {
pub creation_time: u64,
pub modification_time: u64,
pub timescale: u32,
pub duration: u64,
pub rate: u32,
pub volume: u16,
pub matrix: [u32; 9],
pub pre_defined: [u32; 6],
pub next_track_id: u32,
}
impl WriteBox for MovieHeader {
const BOXTYPE: [u8; 4] = *b"mvhd";
const VERSION: Option<u8> = Some(1);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.creation_time.to_be_bytes());
buf.extend(self.modification_time.to_be_bytes());
buf.extend(self.timescale.to_be_bytes());
buf.extend(self.duration.to_be_bytes());
buf.extend(self.rate.to_be_bytes());
buf.extend(self.volume.to_be_bytes());
buf.extend([0; 10]);
for e in self.matrix {
buf.extend(e.to_be_bytes());
}
buf.extend([0; 24]);
buf.extend(self.next_track_id.to_be_bytes());
}
}
impl Default for MovieHeader {
fn default() -> Self {
Self {
creation_time: 0,
modification_time: 0,
timescale: 0,
duration: 0,
rate: 0x00010000,
volume: 0x0100,
matrix: [0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x00010000],
pre_defined: [0; 6],
next_track_id: 0,
}
}
}
#[derive(Default)]
pub struct TrackHeader {
pub creation_time: u64,
pub modification_time: u64,
pub track_id: u32,
pub duration: u64,
pub layer: u16,
pub alternate_group: u16,
pub volume: u16,
pub matrix: [u32; 9],
pub width: u32,
pub height: u32,
}
impl WriteBox for TrackHeader {
const BOXTYPE: [u8; 4] = *b"tkhd";
const VERSION: Option<u8> = Some(1);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.creation_time.to_be_bytes());
buf.extend(self.modification_time.to_be_bytes());
buf.extend(self.track_id.to_be_bytes());
buf.extend([0; 4]);
buf.extend(self.duration.to_be_bytes());
buf.extend([0; 8]);
buf.extend(self.layer.to_be_bytes());
buf.extend(self.alternate_group.to_be_bytes());
buf.extend(self.volume.to_be_bytes());
buf.extend([0; 2]);
for e in self.matrix {
buf.extend(e.to_be_bytes());
}
buf.extend(self.width.to_be_bytes());
buf.extend(self.height.to_be_bytes());
}
}
pub struct EditList<'a> {
pub entries: &'a [EditListEntry],
}
pub struct EditListEntry {
pub edit_duration: u64,
pub media_time: u64,
pub media_rate: u32,
}
impl WriteBox for EditList<'_> {
const BOXTYPE: [u8; 4] = *b"elst";
fn write(&self, buf: &mut Vec<u8>) {
buf.extend((self.entries.len() as u32).to_be_bytes());
for e in self.entries {
buf.extend(e.edit_duration.to_be_bytes());
buf.extend(e.media_time.to_be_bytes());
buf.extend(e.media_rate.to_be_bytes());
}
}
}
#[derive(Default)]
pub struct MediaHeader {
pub creation_time: u64,
pub modification_time: u64,
pub timescale: u32,
pub duration: u64,
pub language: [u8; 3],
pub pre_defined: u16,
}
impl WriteBox for MediaHeader {
const BOXTYPE: [u8; 4] = *b"mdhd";
const VERSION: Option<u8> = Some(1);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.creation_time.to_be_bytes());
buf.extend(self.modification_time.to_be_bytes());
buf.extend(self.timescale.to_be_bytes());
buf.extend(self.duration.to_be_bytes());
buf.extend(
((self.language[0] as u16 & 0b11111 << 10)
| (self.language[1] as u16 & 0b11111 << 5)
| (self.language[2] as u16 & 0b11111 << 0))
.to_be_bytes(),
);
buf.extend([0; 2]);
}
}
pub struct Handler {
pub handler_type: u32,
pub name: String,
}
impl WriteBox for Handler {
const BOXTYPE: [u8; 4] = *b"hdlr";
const VERSION: Option<u8> = Some(0);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend([0; 4]);
buf.extend(self.handler_type.to_be_bytes());
buf.extend([0; 12]);
buf.extend(self.name.as_bytes());
}
}
#[derive(Default)]
pub struct VideoMediaHandler {
pub graphicsmode: u16,
pub opcolor: [u16; 3],
}
impl WriteBox for VideoMediaHandler {
const BOXTYPE: [u8; 4] = *b"vmhd";
const VERSION: Option<u8> = Some(0);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.graphicsmode.to_be_bytes());
buf.extend(self.opcolor[0].to_be_bytes());
buf.extend(self.opcolor[1].to_be_bytes());
buf.extend(self.opcolor[2].to_be_bytes());
}
}
#[derive(Default)]
pub struct SoundMediaHandler {
pub balance: u16,
}
impl WriteBox for SoundMediaHandler {
const BOXTYPE: [u8; 4] = *b"smhd";
const VERSION: Option<u8> = Some(0);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.balance.to_be_bytes());
}
}
pub struct DataReference<'a> {
pub entries: &'a [()],
}
impl WriteBox for DataReference<'_> {
const BOXTYPE: [u8; 4] = *b"dref";
const VERSION: Option<u8> = Some(0);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend([0; 4]);
}
}
pub struct MovieFragmentHeader {
pub sequence_number: u32,
}
impl WriteBox for MovieFragmentHeader {
const BOXTYPE: [u8; 4] = *b"mfhd";
const VERSION: Option<u8> = Some(0);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.sequence_number.to_be_bytes());
}
}
pub struct TrackFragmentHeader {
pub track_id: u32,
}
impl WriteBox for TrackFragmentHeader {
const BOXTYPE: [u8; 4] = *b"tfhd";
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.track_id.to_be_bytes());
}
}
pub struct TrackFragmentBaseMediaDecodeTime {
pub base_media_decode_time: u64,
}
impl WriteBox for TrackFragmentBaseMediaDecodeTime {
const BOXTYPE: [u8; 4] = *b"tfdt";
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.base_media_decode_time.to_be_bytes());
}
}
pub struct TrackRun {
pub data_offset: i32,
}
impl WriteBox for TrackRun {
const BOXTYPE: [u8; 4] = *b"trun";
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.data_offset.to_be_bytes());
}
}
|