Skip to main content

mp4_track/
types.rs

1use std::fmt;
2
3/// A four-byte ISO box or sample-entry code.
4#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
5pub struct FourCc(pub [u8; 4]);
6
7impl FourCc {
8    /// Creates a code from its four bytes.
9    pub const fn new(bytes: [u8; 4]) -> Self {
10        Self(bytes)
11    }
12
13    /// Returns the code bytes.
14    pub const fn into_bytes(self) -> [u8; 4] {
15        self.0
16    }
17
18    /// Returns printable text, replacing invalid bytes.
19    pub fn as_lossy_str(&self) -> String {
20        String::from_utf8_lossy(&self.0).into_owned()
21    }
22}
23
24impl Default for FourCc {
25    fn default() -> Self {
26        Self(*b"    ")
27    }
28}
29
30impl From<[u8; 4]> for FourCc {
31    fn from(value: [u8; 4]) -> Self {
32        Self(value)
33    }
34}
35
36impl TryFrom<&str> for FourCc {
37    type Error = &'static str;
38
39    fn try_from(value: &str) -> Result<Self, Self::Error> {
40        let bytes: [u8; 4] = value
41            .as_bytes()
42            .try_into()
43            .map_err(|_| "a fourcc must contain four bytes")?;
44        Ok(Self(bytes))
45    }
46}
47
48impl fmt::Display for FourCc {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        for byte in self.0 {
51            if byte.is_ascii_graphic() || byte == b' ' {
52                write!(f, "{}", char::from(byte))?;
53            } else {
54                write!(f, "\\x{byte:02x}")?;
55            }
56        }
57        Ok(())
58    }
59}
60
61impl fmt::Debug for FourCc {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        write!(f, "FourCc({self})")
64    }
65}
66
67/// A track identifier stored in track and fragment headers.
68#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
69pub struct TrackId(pub u32);
70
71/// File-type brands from the `ftyp` box.
72#[derive(Clone, Debug, PartialEq, Eq, Default)]
73pub struct Brands {
74    /// Primary file brand.
75    pub major: FourCc,
76    /// Brand minor version.
77    pub minor_version: u32,
78    /// Compatible brands in stored order.
79    pub compatible: Vec<FourCc>,
80}
81
82/// The media role of a track.
83#[derive(Clone, Copy, Debug, PartialEq, Eq)]
84pub enum TrackKind {
85    /// Video media.
86    Video,
87    /// Audio media.
88    Audio,
89    /// Timed text or subtitle media.
90    Subtitle,
91    /// Another handler type.
92    Other(FourCc),
93}
94
95/// Codec configuration from a sample description.
96#[derive(Clone, Debug, PartialEq)]
97pub enum Codec {
98    /// AVC configuration for an `avc1` or `avc3` entry.
99    H264 {
100        /// Stored sample-entry code.
101        entry: FourCc,
102        /// Decoder configuration.
103        config: AvcConfig,
104    },
105    /// HEVC configuration for an `hvc1` or `hev1` entry.
106    H265 {
107        /// Stored sample-entry code.
108        entry: FourCc,
109        /// Decoder configuration.
110        config: HevcConfig,
111    },
112    /// AAC configuration from an `mp4a` entry.
113    Aac {
114        /// Decoder configuration.
115        config: AacConfig,
116    },
117    /// Opus configuration from an `Opus` entry.
118    Opus {
119        /// Decoder configuration.
120        config: OpusConfig,
121    },
122    /// An unrecognized sample entry whose body is preserved.
123    Other {
124        /// Stored sample-entry code.
125        entry: FourCc,
126        /// Complete sample-entry body after the size and code fields.
127        raw: Vec<u8>,
128    },
129}
130
131/// A preserved sample-entry child box.
132#[derive(Clone, Debug, PartialEq, Eq)]
133pub struct SidecarBox {
134    /// Box code.
135    pub kind: FourCc,
136    /// Box body bytes.
137    pub payload: Vec<u8>,
138}
139
140/// AVC decoder configuration.
141#[derive(Clone, Debug, PartialEq, Eq)]
142pub struct AvcConfig {
143    /// Complete `avcC` payload.
144    pub raw: Vec<u8>,
145    /// AVC profile indication.
146    pub profile: u8,
147    /// Profile compatibility flags.
148    pub profile_compat: u8,
149    /// AVC level indication.
150    pub level: u8,
151    /// NAL unit length field width in bytes.
152    pub nal_length_size: u8,
153    /// Sequence parameter sets.
154    pub sps: Vec<Vec<u8>>,
155    /// Picture parameter sets.
156    pub pps: Vec<Vec<u8>>,
157    /// Preserved `pasp`, `btrt`, `fiel`, and `colr` boxes in stored order.
158    pub sidecars: Vec<SidecarBox>,
159}
160
161/// One HEVC NAL array.
162#[derive(Clone, Debug, PartialEq, Eq)]
163pub struct NalArray {
164    /// NAL unit type.
165    pub nal_type: u8,
166    /// NAL units in stored order.
167    pub nals: Vec<Vec<u8>>,
168}
169
170/// HEVC decoder configuration.
171#[derive(Clone, Debug, PartialEq, Eq)]
172pub struct HevcConfig {
173    /// Complete `hvcC` payload.
174    pub raw: Vec<u8>,
175    /// NAL unit length field width in bytes.
176    pub nal_length_size: u8,
177    /// Parameter-set arrays in stored order.
178    pub arrays: Vec<NalArray>,
179    /// Preserved `pasp`, `btrt`, `fiel`, and `colr` boxes in stored order.
180    pub sidecars: Vec<SidecarBox>,
181}
182
183/// AAC decoder configuration.
184#[derive(Clone, Debug, PartialEq, Eq)]
185pub struct AacConfig {
186    /// Complete `esds` payload, including full-box fields.
187    pub raw_esds: Vec<u8>,
188    /// MPEG-4 object type indication.
189    pub object_type: u8,
190    /// Decoder-specific AudioSpecificConfig bytes.
191    pub audio_specific_config: Vec<u8>,
192    /// Channel count from the audio sample entry.
193    pub channels: u16,
194    /// Sample rate from the audio sample entry, or the media timescale when
195    /// the entry stores no rate.
196    pub sample_rate: u32,
197    /// Preserved `pasp`, `btrt`, `fiel`, and `colr` boxes in stored order.
198    pub sidecars: Vec<SidecarBox>,
199}
200
201/// Opus decoder configuration.
202#[derive(Clone, Debug, PartialEq, Eq)]
203pub struct OpusConfig {
204    /// Complete `dOps` payload.
205    pub raw: Vec<u8>,
206    /// Output channel count.
207    pub channels: u8,
208    /// Decoder pre-skip in samples.
209    pub pre_skip: u16,
210    /// Input sample rate from the identification header.
211    pub input_sample_rate: u32,
212    /// Output gain in Q7.8 decibels.
213    pub output_gain: i16,
214    /// Channel mapping family.
215    pub mapping_family: u8,
216    /// Preserved `pasp`, `btrt`, `fiel`, and `colr` boxes in stored order.
217    pub sidecars: Vec<SidecarBox>,
218}
219
220/// One movie edit-list entry.
221#[derive(Clone, Debug, PartialEq)]
222pub struct Edit {
223    /// Segment duration in movie timescale units.
224    pub segment_duration: u64,
225    /// Media start time, or `None` for an empty edit.
226    pub media_time: Option<u64>,
227    /// Playback rate stored as 16.16 fixed point.
228    pub media_rate: f32,
229}
230
231/// The box used for chunk offsets.
232#[derive(Clone, Copy, Debug, PartialEq, Eq)]
233pub enum ChunkOffsetKind {
234    /// 32-bit offsets.
235    Stco,
236    /// 64-bit offsets.
237    Co64,
238    /// No progressive chunk offsets.
239    None,
240}
241
242/// Parsed track metadata.
243#[derive(Clone, Debug, PartialEq)]
244pub struct Track {
245    /// Track identifier.
246    pub id: TrackId,
247    /// Handler role.
248    pub kind: TrackKind,
249    /// Handler display name.
250    pub handler_name: String,
251    /// Media timescale.
252    pub timescale: u32,
253    /// Sum of sample durations in media units.
254    pub duration: u64,
255    /// ISO 639-2/T language code.
256    pub language: String,
257    /// Whether the track is enabled.
258    pub enabled: bool,
259    /// Display width.
260    pub width: f64,
261    /// Display height.
262    pub height: f64,
263    /// Primary sample description.
264    pub codec: Codec,
265    /// Movie edit list.
266    pub edit_list: Vec<Edit>,
267    /// Number of samples.
268    pub sample_count: u32,
269    /// Stored chunk-offset width.
270    pub chunk_offsets: ChunkOffsetKind,
271    /// Stored sync-sample count, or `None` when every sample is sync.
272    pub sync_sample_count: Option<u32>,
273}
274
275impl Track {
276    /// Returns the media time of the single non-empty edit.
277    pub fn presentation_offset(&self) -> Option<u64> {
278        let mut non_empty = self
279            .edit_list
280            .iter()
281            .filter(|edit| edit.media_time.is_some());
282        let first = non_empty.next()?;
283        if non_empty.next().is_some() {
284            return None;
285        }
286        first.media_time
287    }
288}
289
290/// Location and timing for one sample.
291#[derive(Clone, Copy, Debug, PartialEq, Eq)]
292pub struct SampleInfo {
293    /// Zero-based track sample index.
294    pub index: u32,
295    /// Absolute byte offset.
296    pub offset: u64,
297    /// Sample size in bytes.
298    pub size: u32,
299    /// Decode time in media units.
300    pub dts: u64,
301    /// Signed composition-time offset.
302    pub cts_offset: i64,
303    /// Presentation time before edit-list mapping.
304    pub pts: i64,
305    /// Sample duration in media units.
306    pub duration: u32,
307    /// Whether this is a random-access sample.
308    pub is_sync: bool,
309    /// Zero-based chunk index, or fragment index for fragmented input.
310    pub chunk: u32,
311    /// One-based sample-description index.
312    pub description_index: u32,
313}
314
315/// Sample bytes and parsed metadata.
316#[derive(Clone, Debug, PartialEq, Eq)]
317pub struct Sample {
318    /// Parsed sample metadata.
319    pub info: SampleInfo,
320    /// Encoded sample bytes.
321    pub data: Vec<u8>,
322}
323
324/// One parsed movie fragment.
325#[derive(Clone, Debug, PartialEq, Eq)]
326pub struct Fragment {
327    /// Fragment sequence number.
328    pub sequence_number: u32,
329    /// Absolute `moof` offset.
330    pub moof_offset: u64,
331    /// Track runs in stored order.
332    pub runs: Vec<TrackRun>,
333}
334
335/// Samples from one fragment track run.
336#[derive(Clone, Debug, PartialEq, Eq)]
337pub struct TrackRun {
338    /// Referenced track.
339    pub track: TrackId,
340    /// Expanded samples.
341    pub samples: Vec<SampleInfo>,
342}
343
344/// A top-level event message.
345#[derive(Clone, Debug, PartialEq, Eq)]
346pub struct Event {
347    /// Event scheme identifier URI.
348    pub scheme_id_uri: String,
349    /// Scheme-specific value.
350    pub value: String,
351    /// Event timescale.
352    pub timescale: u32,
353    /// Presentation time.
354    pub presentation_time: u64,
355    /// Event duration.
356    pub event_duration: u32,
357    /// Event identifier.
358    pub id: u32,
359    /// Scheme-specific message bytes.
360    pub message_data: Vec<u8>,
361}
362
363/// Parsed user metadata.
364#[derive(Clone, Debug, PartialEq, Eq, Default)]
365pub struct Metadata {
366    /// Metadata entries in stored order.
367    pub entries: Vec<(MetaKey, MetaValue)>,
368}
369
370/// A recognized metadata key.
371#[derive(Clone, Debug, PartialEq, Eq)]
372pub enum MetaKey {
373    /// Title.
374    Title,
375    /// Artist.
376    Artist,
377    /// Album.
378    Album,
379    /// Album artist.
380    AlbumArtist,
381    /// Composer.
382    Composer,
383    /// Genre.
384    Genre,
385    /// Comment.
386    Comment,
387    /// Release date.
388    Date,
389    /// Another four-byte key.
390    Other(FourCc),
391}
392
393/// A metadata value.
394#[derive(Clone, Debug, PartialEq, Eq)]
395pub enum MetaValue {
396    /// UTF-8 text.
397    Text(String),
398    /// Uninterpreted bytes.
399    Binary(Vec<u8>),
400    /// Big-endian integer.
401    Integer(i64),
402}
403
404/// A tolerated file oddity.
405#[derive(Clone, Debug, PartialEq, Eq)]
406pub enum Warning {
407    /// Bytes remain after the last complete top-level box.
408    TrailingBytes {
409        /// Offset where trailing data begins.
410        at: u64,
411        /// Number of trailing bytes.
412        count: u64,
413    },
414    /// An unknown box was skipped.
415    UnknownBox {
416        /// Unknown box code.
417        kind: FourCc,
418        /// Enclosing box code, when known.
419        parent: Option<FourCc>,
420    },
421}
422
423/// Resource bounds applied while opening and reading.
424#[non_exhaustive]
425#[derive(Clone, Copy, Debug, PartialEq, Eq)]
426pub struct Limits {
427    /// Maximum accepted movie box size. Defaults to 256 MiB.
428    pub max_moov_bytes: u64,
429    /// Maximum accepted fragment box size. Defaults to 64 MiB.
430    pub max_moof_bytes: u64,
431    /// Maximum bytes read for one sample. Defaults to 64 MiB.
432    pub max_sample_bytes: u32,
433    /// Maximum fragment count. Defaults to one million.
434    pub max_fragments: u32,
435    /// Maximum expanded sample count for one track. Defaults to 500,000.
436    pub max_sample_count: u32,
437    /// Maximum structural nesting. Defaults to 32.
438    pub max_depth: u8,
439}
440
441impl Default for Limits {
442    fn default() -> Self {
443        Self {
444            max_moov_bytes: 256 * 1024 * 1024,
445            max_moof_bytes: 64 * 1024 * 1024,
446            max_sample_bytes: 64 * 1024 * 1024,
447            max_fragments: 1_000_000,
448            max_sample_count: 500_000,
449            max_depth: 32,
450        }
451    }
452}
453
454/// Writer selection for chunk-offset boxes.
455#[derive(Clone, Copy, Debug, PartialEq, Eq)]
456pub enum ChunkOffsetChoice {
457    /// Select the narrowest valid offset box.
458    Auto,
459    /// Always write 64-bit offsets.
460    Co64,
461}
462
463/// File-level writer settings.
464#[derive(Clone, Debug, PartialEq, Eq)]
465pub struct WriterConfig {
466    /// Movie timescale. Defaults to 1000.
467    pub movie_timescale: u32,
468    /// Primary output brand.
469    pub major_brand: FourCc,
470    /// Compatible output brands.
471    pub compatible_brands: Vec<FourCc>,
472    /// Chunk-offset width selection.
473    pub chunk_offsets: ChunkOffsetChoice,
474}
475
476impl Default for WriterConfig {
477    fn default() -> Self {
478        Self {
479            movie_timescale: 1000,
480            major_brand: FourCc(*b"isom"),
481            compatible_brands: vec![FourCc(*b"isom"), FourCc(*b"iso2"), FourCc(*b"mp41")],
482            chunk_offsets: ChunkOffsetChoice::Auto,
483        }
484    }
485}
486
487/// Track settings supplied to the writer.
488#[derive(Clone, Debug, PartialEq)]
489pub struct TrackConfig {
490    /// Handler role.
491    pub kind: TrackKind,
492    /// Media timescale.
493    pub timescale: u32,
494    /// ISO 639-2/T language code.
495    pub language: String,
496    /// Handler display name.
497    pub handler_name: String,
498    /// Sample description.
499    pub codec: Codec,
500    /// Display width.
501    pub width: f64,
502    /// Display height.
503    pub height: f64,
504    /// Movie edit list.
505    pub edit_list: Vec<Edit>,
506}
507
508/// One sample supplied to the writer.
509#[derive(Clone, Copy, Debug, PartialEq, Eq)]
510pub struct SampleInput<'a> {
511    /// Encoded sample bytes.
512    pub data: &'a [u8],
513    /// Decode duration in media units.
514    pub duration: u32,
515    /// Signed composition-time offset.
516    pub cts_offset: i32,
517    /// Whether this is a random-access sample.
518    pub is_sync: bool,
519}