Coverage Report

Created: 2026-03-07 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/avif-serialize-0.8.8/src/boxes.rs
Line
Count
Source
1
use crate::constants::{ColorPrimaries, MatrixCoefficients, TransferCharacteristics};
2
use crate::writer::{Writer, WriterBackend, IO};
3
use arrayvec::ArrayVec;
4
use std::io::Write;
5
use std::num::NonZeroU32;
6
use std::{fmt, io};
7
8
pub trait MpegBox {
9
    fn len(&self) -> usize;
10
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error>;
11
}
12
13
#[derive(Copy, Clone)]
14
pub struct FourCC(pub [u8; 4]);
15
16
impl fmt::Debug for FourCC {
17
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18
0
        match std::str::from_utf8(&self.0) {
19
0
            Ok(s) => s.fmt(f),
20
0
            Err(_) => self.0.fmt(f),
21
        }
22
0
    }
23
}
24
25
#[derive(Debug, Clone)]
26
pub struct AvifFile<'data> {
27
    pub ftyp: FtypBox,
28
    pub meta: MetaBox<'data>,
29
    pub mdat: MdatBox,
30
}
31
32
impl AvifFile<'_> {
33
    /// Where the primary data starts inside the `mdat` box, for `iloc`'s offset
34
0
    fn mdat_payload_start_offset(&self) -> u32 {
35
0
        (self.ftyp.len() + self.meta.len()
36
0
            + BASIC_BOX_SIZE) as u32 // mdat head
37
0
    }
38
39
    /// `iloc` is mostly unnecssary, high risk of out-of-buffer accesses in parsers that don't pay attention,
40
    /// and also awkward to serialize, because its content depends on its own serialized byte size.
41
0
    fn fix_iloc_positions(&mut self) {
42
0
        let start_offset = self.mdat_payload_start_offset();
43
0
        self.meta.iloc.absolute_offset_start = NonZeroU32::new(start_offset);
44
0
    }
45
46
0
    fn write_header(&mut self, out: &mut Vec<u8>) -> io::Result<()> {
47
0
        if self.meta.iprp.ipco.ispe().is_none_or(|b| b.width == 0 || b.height == 0) {
48
0
            return Err(io::Error::new(io::ErrorKind::InvalidInput, "missing width/height"));
49
0
        }
50
51
0
        self.fix_iloc_positions();
52
53
0
        out.try_reserve_exact(self.ftyp.len() + self.meta.len())?;
54
0
        let mut w = Writer::new(out);
55
0
        self.ftyp.write(&mut w).map_err(|_| io::ErrorKind::OutOfMemory)?;
56
0
        self.meta.write(&mut w).map_err(|_| io::ErrorKind::OutOfMemory)?;
57
0
        Ok(())
58
0
    }
59
60
0
    pub fn file_size(&self) -> usize {
61
0
        self.ftyp.len() + self.meta.len() + self.mdat.len(&self.meta.iloc)
62
0
    }
63
64
0
    pub fn write_to_vec(&mut self, out: &mut Vec<u8>) -> io::Result<()> {
65
0
        let expected_file_size = self.file_size();
66
0
        out.try_reserve_exact(expected_file_size)?;
67
0
        let initial = out.len();
68
0
        self.write_header(out)?;
69
70
0
        let _ = self.mdat.write(&mut Writer::new(out), &self.meta.iloc);
71
0
        let written = out.len() - initial;
72
0
        debug_assert_eq!(expected_file_size, written);
73
0
        Ok(())
74
0
    }
75
76
0
    pub fn write<W: Write>(&mut self, mut out: W) -> io::Result<()> {
77
0
        let mut tmp = Vec::new();
78
79
0
        self.write_header(&mut tmp)?;
80
0
        out.write_all(&tmp)?;
81
0
        drop(tmp);
82
83
0
        self.mdat.write(&mut Writer::new(&mut IO(out)), &self.meta.iloc)
84
0
    }
85
}
86
87
const BASIC_BOX_SIZE: usize = 8;
88
const FULL_BOX_SIZE: usize = BASIC_BOX_SIZE + 4;
89
90
#[derive(Debug, Clone)]
91
pub struct FtypBox {
92
    pub major_brand: FourCC,
93
    pub minor_version: u32,
94
    pub compatible_brands: ArrayVec<FourCC, 2>,
95
}
96
97
/// File Type box (chunk)
98
impl MpegBox for FtypBox {
99
    #[inline(always)]
100
0
    fn len(&self) -> usize {
101
0
        BASIC_BOX_SIZE
102
0
        + 4 // brand
103
0
        + 4 // ver
104
0
        + 4 * self.compatible_brands.len()
105
0
    }
106
107
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
108
0
        let mut b = w.basic_box(self.len(), *b"ftyp")?;
109
0
        b.push(&self.major_brand.0)?;
110
0
        b.u32(self.minor_version)?;
111
0
        for cb in &self.compatible_brands {
112
0
            b.push(&cb.0)?;
113
        }
114
0
        Ok(())
115
0
    }
116
}
117
118
/// Metadata box
119
#[derive(Debug, Clone)]
120
pub struct MetaBox<'data> {
121
    pub hdlr: HdlrBox,
122
    pub iloc: IlocBox<'data>,
123
    pub iinf: IinfBox,
124
    pub pitm: PitmBox,
125
    pub iprp: IprpBox,
126
    pub iref: IrefBox,
127
}
128
129
impl MpegBox for MetaBox<'_> {
130
    #[inline]
131
0
    fn len(&self) -> usize {
132
0
        FULL_BOX_SIZE
133
0
            + self.hdlr.len()
134
0
            + self.pitm.len()
135
0
            + self.iloc.len()
136
0
            + self.iinf.len()
137
0
            + self.iprp.len()
138
0
            + if !self.iref.is_empty() { self.iref.len() } else { 0 }
139
0
    }
140
141
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
142
0
        let mut b = w.full_box(self.len(), *b"meta", 0)?;
143
0
        self.hdlr.write(&mut b)?;
144
0
        self.pitm.write(&mut b)?;
145
0
        self.iloc.write(&mut b)?;
146
0
        self.iinf.write(&mut b)?;
147
0
        if !self.iref.is_empty() {
148
0
            self.iref.write(&mut b)?;
149
0
        }
150
0
        self.iprp.write(&mut b)
151
0
    }
152
}
153
154
/// Item Info box
155
#[derive(Debug, Clone)]
156
pub struct IinfBox {
157
    pub items: ArrayVec<InfeBox, 3>,
158
}
159
160
impl MpegBox for IinfBox {
161
    #[inline]
162
0
    fn len(&self) -> usize {
163
0
        FULL_BOX_SIZE
164
0
        + 2 // num items u16
165
0
        + self.items.iter().map(|item| item.len()).sum::<usize>()
166
0
    }
167
168
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
169
0
        let mut b = w.full_box(self.len(), *b"iinf", 0)?;
170
0
        b.u16(self.items.len() as _)?;
171
0
        for infe in &self.items {
172
0
            infe.write(&mut b)?;
173
        }
174
0
        Ok(())
175
0
    }
176
}
177
178
/// Item Info Entry box
179
#[derive(Debug, Copy, Clone)]
180
pub struct InfeBox {
181
    pub id: u16,
182
    pub typ: FourCC,
183
    pub name: &'static str,
184
}
185
186
impl MpegBox for InfeBox {
187
    #[inline(always)]
188
0
    fn len(&self) -> usize {
189
0
        FULL_BOX_SIZE
190
0
        + 2 // id
191
0
        + 2 // item_protection_index
192
0
        + 4 // type
193
0
        + self.name.len() + 1 // nul-terminated
194
0
    }
195
196
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
197
0
        let mut b = w.full_box(self.len(), *b"infe", 2)?;
198
0
        b.u16(self.id)?;
199
0
        b.u16(0)?;
200
0
        b.push(&self.typ.0)?;
201
0
        b.push(self.name.as_bytes())?;
202
0
        b.u8(0)
203
0
    }
204
}
205
206
#[derive(Debug, Clone)]
207
pub struct HdlrBox {
208
}
209
210
impl MpegBox for HdlrBox {
211
    #[inline(always)]
212
0
    fn len(&self) -> usize {
213
0
        FULL_BOX_SIZE + 4 + 4 + 13
214
0
    }
215
216
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
217
        // because an image format needs to be told it's an image format,
218
        // and it does it the way classic MacOS used to, because Quicktime.
219
0
        let mut b = w.full_box(self.len(), *b"hdlr", 0)?;
220
0
        b.u32(0)?; // old MacOS file type handler
221
0
        b.push(b"pict")?; // MacOS Quicktime subtype
222
0
        b.u32(0)?; // Firefox 92 wants all 0 here
223
0
        b.u32(0)?; // Reserved
224
0
        b.u32(0)?; // Reserved
225
0
        b.u8(0)?; // Pascal string for component name
226
0
        Ok(())
227
0
    }
228
}
229
230
/// Item properties + associations
231
#[derive(Debug, Clone)]
232
pub struct IprpBox {
233
    pub ipco: IpcoBox,
234
    pub ipma: IpmaBox,
235
}
236
237
impl MpegBox for IprpBox {
238
    #[inline(always)]
239
0
    fn len(&self) -> usize {
240
0
        BASIC_BOX_SIZE
241
0
            + self.ipco.len()
242
0
            + self.ipma.len()
243
0
    }
244
245
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
246
0
        let mut b = w.basic_box(self.len(), *b"iprp")?;
247
0
        self.ipco.write(&mut b)?;
248
0
        self.ipma.write(&mut b)
249
0
    }
250
}
251
252
#[derive(Debug, Clone)]
253
#[non_exhaustive]
254
pub enum IpcoProp {
255
    Av1C(Av1CBox),
256
    Pixi(PixiBox),
257
    Ispe(IspeBox),
258
    AuxC(AuxCBox),
259
    Colr(ColrBox),
260
    Clli(ClliBox),
261
    Mdcv(MdcvBox),
262
}
263
264
impl IpcoProp {
265
0
    pub fn len(&self) -> usize {
266
0
        match self {
267
0
            Self::Av1C(p) => p.len(),
268
0
            Self::Pixi(p) => p.len(),
269
0
            Self::Ispe(p) => p.len(),
270
0
            Self::AuxC(p) => p.len(),
271
0
            Self::Colr(p) => p.len(),
272
0
            Self::Clli(p) => p.len(),
273
0
            Self::Mdcv(p) => p.len(),
274
        }
275
0
    }
276
277
0
    pub fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
278
0
        match self {
279
0
            Self::Av1C(p) => p.write(w),
280
0
            Self::Pixi(p) => p.write(w),
281
0
            Self::Ispe(p) => p.write(w),
282
0
            Self::AuxC(p) => p.write(w),
283
0
            Self::Colr(p) => p.write(w),
284
0
            Self::Clli(p) => p.write(w),
285
0
            Self::Mdcv(p) => p.write(w),
286
        }
287
0
    }
288
}
289
290
/// Item Property Container box
291
#[derive(Debug, Clone)]
292
pub struct IpcoBox {
293
    props: ArrayVec<IpcoProp, 9>,
294
}
295
296
impl IpcoBox {
297
0
    pub fn new() -> Self {
298
0
        Self { props: ArrayVec::new() }
299
0
    }
300
301
    #[must_use]
302
0
    pub fn push(&mut self, prop: IpcoProp) -> Option<u8> {
303
0
        self.props.try_push(prop).ok()?;
304
0
        Some(self.props.len() as u8) // the spec wants them off by one
305
0
    }
306
307
0
    pub(crate) fn ispe(&self) -> Option<&IspeBox> {
308
0
        self.props.iter().find_map(|b| match b {
309
0
            IpcoProp::Ispe(i) => Some(i),
310
0
            _ => None,
311
0
        })
312
0
    }
313
}
314
315
impl MpegBox for IpcoBox {
316
    #[inline]
317
0
    fn len(&self) -> usize {
318
        BASIC_BOX_SIZE
319
0
            + self.props.iter().map(|a| a.len()).sum::<usize>()
320
0
    }
321
322
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
323
0
        let mut b = w.basic_box(self.len(), *b"ipco")?;
324
0
        for p in &self.props {
325
0
            p.write(&mut b)?;
326
        }
327
0
        Ok(())
328
0
    }
329
}
330
331
#[derive(Debug, Copy, Clone)]
332
pub struct AuxCBox {
333
    pub urn: &'static str,
334
}
335
336
impl AuxCBox {
337
0
    pub fn len(&self) -> usize {
338
0
        FULL_BOX_SIZE + self.urn.len() + 1
339
0
    }
340
341
0
    pub fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
342
0
        let mut b = w.full_box(self.len(), *b"auxC", 0)?;
343
0
        b.push(self.urn.as_bytes())?;
344
0
        b.u8(0)
345
0
    }
346
}
347
348
/// Pixies, I guess.
349
#[derive(Debug, Copy, Clone)]
350
pub struct PixiBox {
351
    pub depth: u8,
352
    pub channels: u8,
353
}
354
355
impl PixiBox {
356
0
    pub fn len(self) -> usize {
357
0
        FULL_BOX_SIZE
358
0
            + 1 + self.channels as usize
359
0
    }
360
361
0
    pub fn write<B: WriterBackend>(self, w: &mut Writer<B>) -> Result<(), B::Error> {
362
0
        let mut b = w.full_box(self.len(), *b"pixi", 0)?;
363
0
        b.u8(self.channels)?;
364
0
        for _ in 0..self.channels {
365
0
            b.u8(self.depth)?;
366
        }
367
0
        Ok(())
368
0
    }
369
}
370
371
/// This is HEVC-specific and not for AVIF, but Chrome wants it :(
372
#[derive(Debug, Copy, Clone)]
373
pub struct IspeBox {
374
    pub width: u32,
375
    pub height: u32,
376
}
377
378
impl MpegBox for IspeBox {
379
    #[inline(always)]
380
0
    fn len(&self) -> usize {
381
0
        FULL_BOX_SIZE + 4 + 4
382
0
    }
383
384
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
385
0
        let mut b = w.full_box(self.len(), *b"ispe", 0)?;
386
0
        b.u32(self.width)?;
387
0
        b.u32(self.height)
388
0
    }
389
}
390
391
/// Property→image associations
392
#[derive(Debug, Clone)]
393
pub struct IpmaEntry {
394
    pub item_id: u16,
395
    pub prop_ids: ArrayVec<u8, 7>,
396
}
397
398
#[derive(Debug, Clone)]
399
pub struct IpmaBox {
400
    pub entries: ArrayVec<IpmaEntry, 2>,
401
}
402
403
impl MpegBox for IpmaBox {
404
    #[inline]
405
0
    fn len(&self) -> usize {
406
0
        FULL_BOX_SIZE + 4 + self.entries.iter().map(|e| 2 + 1 + e.prop_ids.len()).sum::<usize>()
407
0
    }
408
409
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
410
0
        let mut b = w.full_box(self.len(), *b"ipma", 0)?;
411
0
        b.u32(self.entries.len() as _)?; // entry count
412
413
0
        for e in &self.entries {
414
0
            b.u16(e.item_id)?;
415
0
            b.u8(e.prop_ids.len() as u8)?; // assoc count
416
0
            for &p in &e.prop_ids {
417
0
                b.u8(p)?;
418
            }
419
        }
420
0
        Ok(())
421
0
    }
422
}
423
424
/// Item Reference box
425
#[derive(Debug, Copy, Clone)]
426
pub struct IrefEntryBox {
427
    pub from_id: u16,
428
    pub to_id: u16,
429
    pub typ: FourCC,
430
}
431
432
impl MpegBox for IrefEntryBox {
433
    #[inline(always)]
434
0
    fn len(&self) -> usize {
435
0
        BASIC_BOX_SIZE
436
0
            + 2 // from
437
0
            + 2 // refcount
438
0
            + 2 // to
439
0
    }
440
441
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
442
0
        let mut b = w.basic_box(self.len(), self.typ.0)?;
443
0
        b.u16(self.from_id)?;
444
0
        b.u16(1)?;
445
0
        b.u16(self.to_id)
446
0
    }
447
}
448
449
#[derive(Debug, Clone)]
450
pub struct IrefBox {
451
    pub entries: ArrayVec<IrefEntryBox, 3>,
452
}
453
454
impl IrefBox {
455
0
    pub fn is_empty(&self) -> bool {
456
0
        self.entries.is_empty()
457
0
    }
458
}
459
460
impl MpegBox for IrefBox {
461
    #[inline(always)]
462
0
    fn len(&self) -> usize {
463
0
        FULL_BOX_SIZE + self.entries.iter().map(|e| e.len()).sum::<usize>()
464
0
    }
465
466
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
467
0
        let mut b = w.full_box(self.len(), *b"iref", 0)?;
468
0
        for entry in &self.entries {
469
0
            entry.write(&mut b)?;
470
        }
471
0
        Ok(())
472
0
    }
473
}
474
475
/// Auxiliary item (alpha or depth map)
476
#[derive(Debug, Copy, Clone)]
477
#[allow(unused)]
478
pub struct AuxlBox {}
479
480
impl MpegBox for AuxlBox {
481
    #[inline(always)]
482
0
    fn len(&self) -> usize {
483
0
        FULL_BOX_SIZE
484
0
    }
485
486
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
487
0
        w.full_box(self.len(), *b"auxl", 0)?;
488
0
        Ok(())
489
0
    }
490
}
491
492
/// ColourInformationBox
493
#[derive(Debug, Copy, Clone, PartialEq)]
494
pub struct ColrBox {
495
    pub color_primaries: ColorPrimaries,
496
    pub transfer_characteristics: TransferCharacteristics,
497
    pub matrix_coefficients: MatrixCoefficients,
498
    pub full_range_flag: bool, // u1 + u7
499
}
500
501
impl Default for ColrBox {
502
0
    fn default() -> Self {
503
0
        Self {
504
0
            color_primaries: ColorPrimaries::Bt709,
505
0
            transfer_characteristics: TransferCharacteristics::Srgb,
506
0
            matrix_coefficients: MatrixCoefficients::Bt601,
507
0
            full_range_flag: true,
508
0
        }
509
0
    }
510
}
511
512
impl MpegBox for ColrBox {
513
    #[inline(always)]
514
0
    fn len(&self) -> usize {
515
0
        BASIC_BOX_SIZE + 4 + 2 + 2 + 2 + 1
516
0
    }
517
518
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
519
0
        let mut b = w.basic_box(self.len(), *b"colr")?;
520
0
        b.u32(u32::from_be_bytes(*b"nclx"))?;
521
0
        b.u16(self.color_primaries as u16)?;
522
0
        b.u16(self.transfer_characteristics as u16)?;
523
0
        b.u16(self.matrix_coefficients as u16)?;
524
0
        b.u8(if self.full_range_flag { 1 << 7 } else { 0 })
525
0
    }
526
}
527
528
/// Content Light Level Information box (`clli`), per ISOBMFF § 12.1.5 / CEA-861.3.
529
///
530
/// Signals the content light level of HDR content to the display.
531
/// Both values are in cd/m² (nits).
532
#[derive(Debug, Copy, Clone, PartialEq)]
533
pub struct ClliBox {
534
    /// Maximum light level of any single pixel in the content (MaxCLL).
535
    pub max_content_light_level: u16,
536
    /// Maximum average light level of any single frame in the content (MaxFALL).
537
    pub max_pic_average_light_level: u16,
538
}
539
540
impl MpegBox for ClliBox {
541
    #[inline(always)]
542
0
    fn len(&self) -> usize {
543
0
        BASIC_BOX_SIZE + 4
544
0
    }
545
546
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
547
0
        let mut b = w.basic_box(self.len(), *b"clli")?;
548
0
        b.u16(self.max_content_light_level)?;
549
0
        b.u16(self.max_pic_average_light_level)
550
0
    }
551
}
552
553
/// Mastering Display Colour Volume box (`mdcv`), per ISOBMFF § 12.1.5 / SMPTE ST 2086.
554
///
555
/// Describes the color volume of the mastering display used to author the content.
556
/// This does not describe the content itself — see [`ClliBox`] for that.
557
#[derive(Debug, Copy, Clone, PartialEq)]
558
pub struct MdcvBox {
559
    /// Display primaries in CIE 1931 xy chromaticity, encoded as the value × 50000.
560
    /// For example, D65 white (0.3127, 0.3290) encodes as (15635, 16450).
561
    /// Order: \[green, blue, red\] per SMPTE ST 2086.
562
    pub primaries: [(u16, u16); 3],
563
    /// White point in CIE 1931 xy chromaticity, same encoding as `primaries`.
564
    pub white_point: (u16, u16),
565
    /// Maximum luminance of the mastering display in cd/m² × 10000.
566
    /// For example, 1000 cd/m² = 10_000_000.
567
    pub max_luminance: u32,
568
    /// Minimum luminance of the mastering display in cd/m² × 10000.
569
    /// For example, 0.005 cd/m² = 50.
570
    pub min_luminance: u32,
571
}
572
573
impl MpegBox for MdcvBox {
574
    #[inline(always)]
575
0
    fn len(&self) -> usize {
576
0
        BASIC_BOX_SIZE + 24
577
0
    }
578
579
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
580
0
        let mut b = w.basic_box(self.len(), *b"mdcv")?;
581
0
        for &(x, y) in &self.primaries {
582
0
            b.u16(x)?;
583
0
            b.u16(y)?;
584
        }
585
0
        b.u16(self.white_point.0)?;
586
0
        b.u16(self.white_point.1)?;
587
0
        b.u32(self.max_luminance)?;
588
0
        b.u32(self.min_luminance)
589
0
    }
590
}
591
592
#[derive(Debug, Copy, Clone)]
593
pub struct Av1CBox {
594
    pub seq_profile: u8,
595
    pub seq_level_idx_0: u8,
596
    pub seq_tier_0: bool,
597
    pub high_bitdepth: bool,
598
    pub twelve_bit: bool,
599
    pub monochrome: bool,
600
    pub chroma_subsampling_x: bool,
601
    pub chroma_subsampling_y: bool,
602
    pub chroma_sample_position: u8,
603
}
604
605
impl MpegBox for Av1CBox {
606
    #[inline(always)]
607
0
    fn len(&self) -> usize {
608
0
        BASIC_BOX_SIZE + 4
609
0
    }
610
611
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
612
0
        let mut b = w.basic_box(self.len(), *b"av1C")?;
613
0
        let flags1 =
614
0
            u8::from(self.seq_tier_0) << 7 |
615
0
            u8::from(self.high_bitdepth) << 6 |
616
0
            u8::from(self.twelve_bit) << 5 |
617
0
            u8::from(self.monochrome) << 4 |
618
0
            u8::from(self.chroma_subsampling_x) << 3 |
619
0
            u8::from(self.chroma_subsampling_y) << 2 |
620
0
            self.chroma_sample_position;
621
622
0
        b.push(&[
623
0
            0x81, // marker and version
624
0
            (self.seq_profile << 5) | self.seq_level_idx_0, // x2d == 45
625
0
            flags1,
626
0
            0,
627
0
        ])
628
0
    }
629
}
630
631
#[derive(Debug, Copy, Clone)]
632
pub struct PitmBox(pub u16);
633
634
impl MpegBox for PitmBox {
635
    #[inline(always)]
636
0
    fn len(&self) -> usize {
637
0
        FULL_BOX_SIZE + 2
638
0
    }
639
640
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
641
0
        let mut b = w.full_box(self.len(), *b"pitm", 0)?;
642
0
        b.u16(self.0)
643
0
    }
644
}
645
646
#[derive(Debug, Clone)]
647
pub struct IlocBox<'data> {
648
    /// update before writing
649
    pub absolute_offset_start: Option<NonZeroU32>,
650
    pub items: ArrayVec<IlocItem<'data>, 3>,
651
}
652
653
#[derive(Debug, Clone)]
654
pub struct IlocItem<'data> {
655
    pub id: u16,
656
    pub extents: [IlocExtent<'data>; 1],
657
}
658
659
#[derive(Debug, Copy, Clone)]
660
pub struct IlocExtent<'data> {
661
    /// offset and len will be calculated when writing
662
    pub data: &'data [u8],
663
}
664
665
impl MpegBox for IlocBox<'_> {
666
    #[inline(always)]
667
    #[allow(unused_parens)]
668
0
    fn len(&self) -> usize {
669
0
        FULL_BOX_SIZE
670
0
        + 1 // offset_size, length_size
671
0
        + 1 // base_offset_size, reserved
672
0
        + 2 // num items
673
0
        + self.items.iter().map(|i| ( // for each item
674
0
            2 // id
675
0
            + 2 // dat ref idx
676
0
            + 0 // base_offset_size
677
0
            + 2 // extent count
678
0
            + i.extents.len() * ( // for each extent
679
0
               4 // extent_offset
680
0
               + 4 // extent_len
681
0
            )
682
0
        )).sum::<usize>()
683
0
    }
684
685
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>) -> Result<(), B::Error> {
686
0
        let mut b = w.full_box(self.len(), *b"iloc", 0)?;
687
0
        b.push(&[4 << 4 | 4, 0])?; // offset and length are 4 bytes
688
689
0
        b.u16(self.items.len() as _)?; // num items
690
0
        let mut next_start = if let Some(ok) = self.absolute_offset_start { ok.get() } else {
691
0
            debug_assert!(false);
692
0
            !0
693
        };
694
0
        for item in &self.items {
695
0
            b.u16(item.id)?;
696
0
            b.u16(0)?;
697
0
            b.u16(item.extents.len() as _)?; // num extents
698
0
            for ex in &item.extents {
699
0
                let len = ex.data.len() as u32;
700
0
                b.u32(next_start)?;
701
0
                next_start += len;
702
0
                b.u32(len)?;
703
            }
704
        }
705
0
        Ok(())
706
0
    }
707
}
708
709
#[derive(Debug, Clone)]
710
pub struct MdatBox;
711
712
impl MdatBox {
713
    #[inline(always)]
714
0
    fn len(&self, chunks: &IlocBox) -> usize {
715
0
        BASIC_BOX_SIZE + chunks.items.iter().flat_map(|c| &c.extents).map(|d| d.data.len()).sum::<usize>()
716
0
    }
717
718
0
    fn write<B: WriterBackend>(&self, w: &mut Writer<B>, chunks: &IlocBox) -> Result<(), B::Error> {
719
0
        let mut b = w.basic_box(self.len(chunks), *b"mdat")?;
720
0
        for ch in chunks.items.iter().flat_map(|c| &c.extents) {
721
0
            b.push(ch.data)?;
722
        }
723
0
        Ok(())
724
0
    }
725
}