Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_graphics/src/mp4.rs

158 KiB, 366 runs

created by r1870400018:20054, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! An MP4 writer: the ISO base media file format boxes that wrap an already-encoded video track.
2//!
3//! This module writes a container around a stream it can neither encode nor decode. That is
4//! unusual for a graphics crate and it is deliberate. A video codec is months of rate control,
5//! motion estimation and entropy coding, at a quality that would be visibly worse than the encoder
6//! already sitting in every browser and in most machines' silicon; a container is a few hundred
7//! lines of length-prefixed boxes with no compression in it at all, and it is the part that
8//! describes *our* frames and *our* timing. So the caller encodes -- through `VideoEncoder` in a
9//! browser, or through whatever hardware path it has -- and hands the encoded samples and the
10//! decoder configuration here, and gets back a file.
11//!
12//! # What is written
13//!
14//! `ftyp`, then `moov` carrying one video track's whole sample table, then `mdat` carrying the
15//! samples. Not fragmented: the caller holds every sample's size and duration before the first byte
16//! is written, so the sample table can be exact and the file needs no `moof` machinery, no
17//! duration-unknown placeholder and no rewrite at the end.
18//!
19//! `moov` is written *before* `mdat`, which is what a progressive download wants: a reader has the
20//! whole index in hand after the first few kilobytes and can start playing without seeking to the
21//! end. It costs a second pass over the box tree, because the chunk offsets in `stco` are absolute
22//! file offsets and cannot be known until the size of the index that precedes them is.
23//!
24//! [`Fragments`] writes the other shape, for the film a writer cannot hold: `ftyp` and a `moov`
25//! that names the streams and states no duration, then one `moof` and `mdat` for each run of
26//! samples handed over. Every sample's timing is stated in the fragment that carries it, so nothing
27//! is kept back and nothing is rewritten at the end, and a film of unknown length -- several hours
28//! of it, or several streams of it -- can be written a fragment at a time.
29//!
30//! # What is refused
31//!
32//! A track with no samples; a timescale of zero; a sample of zero duration; a sample whose bytes
33//! are not exactly tiled by the length-prefixed NAL units the decoder configuration says they are;
34//! a decoder configuration record that is malformed or truncated; frame dimensions that disagree
35//! with the ones coded in the sequence parameter set; a first sample that is not a sync sample,
36//! since a track no reader can begin decoding is not a track; and a total duration too large for
37//! the 32-bit fields the version-0 header boxes carry.
38//!
39//! # References
40//!
41//! `ftyp`, `moov` and everything under it, and `mdat`, are ISO/IEC 14496-12 (the ISO base media
42//! file format). The `avc1` sample entry and the `avcC` configuration box it carries are ISO/IEC
43//! 14496-15 (the AVC file format), and the `hvc1` entry and its `hvcC` box are ISO/IEC 14496-15
44//! §8.3 and §8.4. The sequence parameter set whose geometry is checked against the caller's
45//! declared dimensions is ITU-T H.264 §7.3.2.1.1 for AVC and ITU-T H.265 §7.3.2.2 for HEVC, the
46//! latter read by [`crate::hevc`]. Each non-obvious constant below names the clause it comes from.
47//!
48//! [Written with AI entirely](https://need2know.ai/entirely-ai/code)\
49//! Anthropic Claude
50
51use crate::hevc;
52
53use oxedyne_fe2o3_core::prelude::*;
54
55use std::{
56 fs::File,
57 io::{
58 Read,
59 Seek,
60 SeekFrom,
61 },
62};
63
64// The most samples one track may hold, a ceiling against a length that is a mistake. A million
65// frames is about eleven and a half hours at twenty-four a second, which is longer than anything
66// a single non-fragmented file is the right shape for.
67pub const MAX_SAMPLES: usize = 1_000_000;
68
69// The timescale of the movie header, in ticks a second. The movie has a timescale of its own,
70// separate from each track's, and every duration in mvhd and tkhd is expressed in it while every
71// duration in mdhd and stts is expressed in the track's. A thousand -- milliseconds -- is the
72// conventional choice and is what makes the movie header readable when a second track arrives on
73// a different timescale from the first.
74pub const MOVIE_TIMESCALE: u32 = 1000;
75
76// The unity transformation a tkhd and an mvhd carry: nine values in the order a, b, u, c, d, v,
77// x, y, w (ISO/IEC 14496-12 §8.2.2.3 for mvhd and §8.3.2.3 for tkhd). The six that scale and
78// rotate are 16.16 fixed point, so one is 0x00010000; the three of the projection column are 2.30,
79// so one is 0x40000000. Written as unity because a track that is played the way it was drawn needs
80// no transformation, and a non-unity matrix here is how a video ends up rotated in one player and
81// not another.
82const UNITY: [u32; 9] = [
83 0x0001_0000, 0, 0,
84 0, 0x0001_0000, 0,
85 0, 0, 0x4000_0000,
86];
87
88// The language of the media, packed as three five-bit letters offset from 0x60, per ISO/IEC
89// 14496-12 §8.4.2.3: und, undetermined, which is what a video track without speech in it is.
90// u is 21, n is 14 and d is 4, so the packed value is (21 << 10) | (14 << 5) | 4.
91const LANG_UND: u16 = 0x55C4;
92
93// The horizontal and vertical resolution of a visual sample entry, in 16.16 fixed point dots an
94// inch: 72, which ISO/IEC 14496-12 §8.5.2.3 gives as the value to write.
95const RESOLUTION_72: u32 = 0x0048_0000;
96
97/// A sample of an encoded track: the bytes of one access unit, how long it is shown, and whether a
98/// reader may begin decoding at it.
99///
100/// A sample is one coded picture. Its duration is in the track's timescale rather than in seconds,
101/// because the rates that matter divide badly -- a 24000/1001 frame rate is exact on a timescale of
102/// 24000 and is nothing at all in milliseconds -- and because that is the unit the sample table
103/// stores.
104#[derive(Clone, Debug, PartialEq, Eq)]
105pub struct Sample {
106 pub data: Vec<u8>, // the coded bytes, as a chain of length-prefixed NAL units
107 pub dur: u32, // how long it is shown, in the track's timescale
108 pub sync: bool, // may decoding begin here? an IDR for AVC, an IRAP for HEVC
109 // How far after its decoding time this sample is shown, in the track's timescale. Nought for
110 // a stream whose pictures are shown in the order they are decoded, which is what a screen
111 // recording or a poster is. A film is not such a stream. Where B-pictures are used a picture
112 // is decoded before the ones it is shown between, so the two orders differ and the container
113 // has to state both: stts gives the decoding times and this gives the difference. Writing a
114 // reordered stream with this left at nought produces a file that opens, reports the right
115 // number of frames, and plays them in the wrong order.
116 pub off: i32,
117}
118
119impl Sample {
120
121 /// A sync sample: one a reader may begin decoding at.
122 pub fn key(data: Vec<u8>, dur: u32) -> Self {
123 Self { data, dur, sync: true, off: 0 }
124 }
125
126 /// A sample that depends on those before it.
127 pub fn delta(data: Vec<u8>, dur: u32) -> Self {
128 Self { data, dur, sync: false, off: 0 }
129 }
130
131 /// The same sample, shown the given distance after it is decoded.
132 ///
133 /// See [`composition_offsets`], which works the offsets out from the presentation times a
134 /// container states, since that is the form a film arrives in.
135 pub fn shown_after(mut self, off: i32) -> Self {
136 self.off = off;
137 self
138 }
139
140 pub fn len(&self) -> usize {
141 self.data.len()
142 }
143
144 /// Does the sample carry no bytes? No legal coded picture does.
145 pub fn is_empty(&self) -> bool {
146 self.data.is_empty()
147 }
148}
149
150/// What a stream carries.
151///
152/// The distinction decides which media header a track is given, which handler declares it, and the
153/// shape of its sample entry -- three boxes that must agree, because a reader told two different
154/// things about one track believes whichever it reads last.
155#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156pub enum Media {
157 Picture { // moving pictures of the given size
158 w: u16,
159 h: u16,
160 },
161 Sound { // sound of the given channel count and rate
162 channels: u16,
163 // Samples a second. A track's timescale is usually this same number, so that a
164 // sample's duration is a count of sound samples and no rounding enters.
165 rate: u32,
166 },
167}
168
169/// One stream of a film, as its header describes it.
170#[derive(Clone, Debug, PartialEq, Eq)]
171pub struct Stream {
172 pub media: Media, // what it carries
173 // Ticks a second the stream's own durations are counted in. Not required to be the sampling
174 // rate of a sound stream, though it often is. A repackaging keeps the source's unit so that
175 // no time is rescaled between the two containers, and a millisecond timescale against a
176 // 44,100 Hz stream is therefore ordinary rather than wrong.
177 pub timescale: u32,
178 pub codec: Codec, // how the samples are coded, and what a decoder needs
179 // The decode time the stream's first sample lands at, in this stream's own timescale. Nearly
180 // always nought, and it exists for the case that is not: the streams of a film do not begin
181 // together. A film's first sound frame is rarely on the same instant as its first picture,
182 // and a picture track shifted so that none of its composition offsets is negative has moved
183 // relative to sound that was not shifted with it. Without this the two are nailed to a common
184 // zero and the film carries an offset between picture and sound that no caller can remove --
185 // which is the characteristic fault of a bad repackaging and the one nobody notices until the
186 // film is being watched.
187 pub start: u64,
188}
189
190/// How a track's samples are coded, and the decoder configuration that goes with them.
191///
192/// An enum rather than a trait object, so that adding a codec is a variant and a match arm rather
193/// than a second dispatch mechanism, and so that a caller can see from the type what the writer
194/// will accept. There is deliberately no catch-all arm anywhere it is matched on: the next codec
195/// added must be considered at every site rather than take whatever the last one does.
196#[derive(Clone, Debug, PartialEq, Eq)]
197pub enum Codec {
198 // H.264, carrying the AVCDecoderConfigurationRecord of ISO/IEC 14496-15 §5.3.3.1 verbatim:
199 // the bytes a VideoEncoder hands back as its output's description, or the avcC box body
200 // lifted out of another file.
201 Avc(Vec<u8>),
202 // HEVC, carrying the HEVCDecoderConfigurationRecord of ISO/IEC 14496-15 §8.3.3.1 verbatim --
203 // the hvcC box body lifted out of another file.
204 Hevc(Vec<u8>),
205 // AAC, carrying the AudioSpecificConfig of ISO/IEC 14496-3 §1.6.2.1 verbatim: two bytes for
206 // the common profiles, naming the object type, the sampling frequency and the channel
207 // configuration. It is what a Matroska track entry's CodecPrivate holds for A_AAC, so a
208 // repackaging copies it across exactly as the picture's record is copied.
209 //
210 // The sample bytes are raw AAC frames, not ADTS: an ADTS header states again, once a frame,
211 // what this record states once for the track, and a decoder handed both refuses.
212 Aac(Vec<u8>),
213}
214
215impl Codec {
216
217 /// Is the stream a picture? That decides the boxes its track is described by.
218 pub fn is_picture(&self) -> bool {
219 match self {
220 Self::Avc(_) => true,
221 Self::Hevc(_) => true,
222 Self::Aac(_) => false,
223 }
224 }
225
226 /// The four-character code of the sample entry this codec is described by: ISO/IEC 14496-15
227 /// §5.4.2.1 for AVC and §8.4.1 for HEVC.
228 ///
229 /// `hvc1` rather than `hev1`. The two differ in one promise: `hvc1` states that every parameter
230 /// set is in the sample entry and none arrives in the samples, while `hev1` allows them in
231 /// either place. A repackaging from a container that keeps the sets in a `CodecPrivate` -- which
232 /// is what Matroska does, and what this writer is handed -- produces exactly the first, so that
233 /// is what is claimed. `hev1` would be true as well but weaker, and it makes a reader look for
234 /// sets in the samples that are not there.
235 fn entry(&self) -> &'static [u8; 4] {
236 match self {
237 Self::Avc(_) => b"avc1",
238 Self::Hevc(_) => b"hvc1",
239 Self::Aac(_) => b"mp4a",
240 }
241 }
242
243 /// The four-character code of the configuration box carried inside that sample entry.
244 fn config(&self) -> &'static [u8; 4] {
245 match self {
246 Self::Avc(_) => b"avcC",
247 Self::Hevc(_) => b"hvcC",
248 Self::Aac(_) => b"esds",
249 }
250 }
251
252 /// The configuration record's bytes, written into the configuration box unchanged.
253 fn record(&self) -> &[u8] {
254 match self {
255 Self::Avc(rec) => rec,
256 Self::Hevc(rec) => rec,
257 Self::Aac(rec) => rec,
258 }
259 }
260
261 /// The name a visual sample entry's compressor field displays.
262 ///
263 /// Descriptive only -- nothing decodes from it -- but it is a field some viewers show, so it
264 /// says what the stream is rather than what the first codec this writer supported was. An empty
265 /// name is written as a count of nought, which is what a file with nothing to say there should
266 /// carry, and is what sound gets because sound has no visual sample entry to name.
267 fn picture_name(&self) -> &'static str {
268 match self {
269 Self::Avc(_) => "AVC Coding",
270 Self::Hevc(_) => "HEVC Coding",
271 Self::Aac(_) => "",
272 }
273 }
274
275 /// How many bytes prefix each NAL unit in a sample, which the configuration record states and
276 /// the sample data must obey.
277 fn nal_len(&self) -> Outcome<usize> {
278 match self {
279 Self::Avc(rec) => {
280 if rec.len() < 7 {
281 return Err(err!(
282 "An AVC decoder configuration record is at least 7 bytes and this one is \
283 {}.", rec.len();
284 Invalid, Input, Size));
285 }
286 // `lengthSizeMinusOne` occupies the low two bits of byte 4; a value of 2, naming a
287 // three-byte length, is forbidden by ISO/IEC 14496-15 §5.3.3.1.
288 let n = (rec[4] & 0x03) as usize + 1;
289 if n == 3 {
290 return Err(err!(
291 "The AVC decoder configuration record names a NAL length of 3 bytes, which \
292 ISO/IEC 14496-15 does not allow; it must be 1, 2 or 4.";
293 Invalid, Input));
294 }
295 Ok(n)
296 },
297 // The whole record is walked to reach a field that sits at a fixed offset in it,
298 // because [`crate::hevc::config`] is the reader this crate already holds to the
299 // specification and a second hand-rolled one would be a second thing to be wrong. It
300 // also means a malformed record is refused here rather than trusted as far as byte 21.
301 Self::Hevc(rec) => Ok(res!(hevc::config(rec)).length_size),
302 Self::Aac(_) => Err(err!(
303 "A sound sample is a coded frame and is not tiled by NAL length prefixes, so \
304 asking for its prefix width is a question about the wrong kind of stream.";
305 Invalid, Input)),
306 }
307 }
308
309 /// Checks the configuration record is well formed, and gives the frame geometry it codes.
310 ///
311 /// The record is walked rather than trusted, because every field of the sample table below is
312 /// derived from it and a truncated record produces a file that is well formed and unplayable.
313 fn geometry(&self) -> Outcome<(u16, u16)> {
314 match self {
315 Self::Aac(_) => Err(err!(
316 "A sound stream codes no frame geometry, so a track built from one cannot be \
317 checked against a declared picture size.";
318 Invalid, Input)),
319 Self::Avc(rec) => {
320 let _ = res!(self.nal_len());
321 if rec[0] != 1 {
322 return Err(err!(
323 "The AVC decoder configuration record's version is {}, and 1 is the only \
324 one ISO/IEC 14496-15 defines.", rec[0];
325 Invalid, Input));
326 }
327 // Byte 5's top three bits are reserved and set, and its low five hold the count of
328 // sequence parameter sets.
329 let n_sps = (rec[5] & 0x1F) as usize;
330 if n_sps == 0 {
331 return Err(err!(
332 "The AVC decoder configuration record carries no sequence parameter set, \
333 so the frame geometry it should describe is absent.";
334 Invalid, Input, Missing));
335 }
336 let mut at = 6usize;
337 let mut first: Option<&[u8]> = None;
338 for i in 0..n_sps {
339 if at + 2 > rec.len() {
340 return Err(err!(
341 "The AVC decoder configuration record ends {} bytes into a run of {} \
342 sequence parameter sets, before the length of set {}.",
343 at, n_sps, i;
344 Invalid, Input, Size));
345 }
346 let len = ((rec[at] as usize) << 8) | rec[at + 1] as usize;
347 at += 2;
348 if at + len > rec.len() {
349 return Err(err!(
350 "Sequence parameter set {} of the AVC decoder configuration record \
351 claims {} bytes but only {} remain.", i, len, rec.len() - at;
352 Invalid, Input, Size));
353 }
354 if first.is_none() {
355 first = Some(&rec[at..at + len]);
356 }
357 at += len;
358 }
359 if at >= rec.len() {
360 return Err(err!(
361 "The AVC decoder configuration record ends after its sequence parameter \
362 sets, before the count of picture parameter sets.";
363 Invalid, Input, Size));
364 }
365 let n_pps = rec[at] as usize;
366 at += 1;
367 if n_pps == 0 {
368 return Err(err!(
369 "The AVC decoder configuration record carries no picture parameter set.";
370 Invalid, Input, Missing));
371 }
372 for i in 0..n_pps {
373 if at + 2 > rec.len() {
374 return Err(err!(
375 "The AVC decoder configuration record ends before the length of \
376 picture parameter set {}.", i;
377 Invalid, Input, Size));
378 }
379 let len = ((rec[at] as usize) << 8) | rec[at + 1] as usize;
380 at += 2;
381 if at + len > rec.len() {
382 return Err(err!(
383 "Picture parameter set {} of the AVC decoder configuration record \
384 claims {} bytes but only {} remain.", i, len, rec.len() - at;
385 Invalid, Input, Size));
386 }
387 at += len;
388 }
389 let sps = match first {
390 Some(s) => s,
391 None => return Err(err!(
392 "The first sequence parameter set was not taken."; Bug, Unreachable)),
393 };
394 sps_geometry(sps)
395 },
396 Self::Hevc(rec) => {
397 let cfg = res!(hevc::config(rec));
398 // The first sequence parameter set the record carries. A film's record often carries
399 // several, and a slice names which of them it was coded against, but every set in
400 // one record describes the same pictures at the same size -- a change of geometry
401 // mid-film is a new sample entry, not a new set in this one.
402 //
403 // `Unit::body` is the payload with the emulation prevention **already** undone:
404 // `hevc::unit` builds it through `hevc::rbsp` and keeps the escaped form beside it
405 // as `Unit::raw`. So nothing is unescaped again here. Doing it twice would take a
406 // genuine `00 00 03` out of the syntax and give a size that is wrong and plausible.
407 let mut sps = None;
408 let mut found: Vec<String> = Vec::with_capacity(cfg.sets.len());
409 for unit in &cfg.sets {
410 if unit.kind == hevc::nal::SPS && sps.is_none() {
411 sps = Some(res!(hevc::sps(&unit.body)));
412 }
413 found.push(unit.kind.to_string());
414 }
415 let sps = match sps {
416 Some(s) => s,
417 None => {
418 let carries = if found.is_empty() {
419 fmt!("no parameter sets at all")
420 } else {
421 fmt!("NAL unit types {}", found.join(", "))
422 };
423 return Err(err!(
424 "The HEVC decoder configuration record carries no sequence parameter \
425 set, which is NAL unit type {}, so the frame geometry it should \
426 describe is absent. It carries {}.", hevc::nal::SPS, carries;
427 Invalid, Input, Missing));
428 },
429 };
430 // `hevc::sps` refuses a picture wider or taller than 16,384, so this cannot fire
431 // today. It is written because the cast below is silent where that ceiling is not,
432 // and the two are in different crates' worth of code from each other.
433 if sps.width > u16::MAX as u32 || sps.height > u16::MAX as u32 {
434 return Err(err!(
435 "The sequence parameter set codes a frame of {} by {} pixels, beyond what a \
436 visual sample entry can state.", sps.width, sps.height;
437 Invalid, Input, Excessive));
438 }
439 Ok((sps.width as u16, sps.height as u16))
440 },
441 }
442 }
443
444 /// Checks that a sample's bytes are exactly tiled by length-prefixed NAL units.
445 ///
446 /// The tiling is the test, and a start code at the front is only a diagnosis of why it failed.
447 /// It cannot be the test: a four-byte length between `0x00000100` and `0x000001FF` -- any NAL
448 /// between 256 and 511 bytes, which is a great many of them -- has the same first three bytes
449 /// as a three-byte start code, so a sample refused on that alone would be a perfectly good one.
450 /// A sample that genuinely does not tile is nearly always Annex B, an elementary stream
451 /// separated by start codes rather than lengths, handed straight through; that produces a file
452 /// every demuxer accepts and no decoder plays, so it is worth naming.
453 fn check_sample(&self, i: usize, data: &[u8]) -> Outcome<()> {
454 match self {
455 // A coded sound frame has no internal framing to check against: its length is
456 // the whole of what says where it ends. Refusing an empty one is done by the
457 // caller, and there is nothing else here that can be told from the bytes.
458 Self::Aac(_) => return Ok(()),
459 // Both picture codecs are checked by the same walk, because both are tiled by
460 // length prefixes and the framing is the whole of what is being tested. The NAL
461 // unit types inside differ and nothing here reads one. Written as a match rather
462 // than a test for sound, so that a codec added later has to say which it is.
463 Self::Avc(_) | Self::Hevc(_) => {},
464 }
465 let n = res!(self.nal_len());
466 let mut at = 0usize;
467 let mut nals = 0usize;
468 let mut why: Option<String> = None;
469 while at < data.len() {
470 if at + n > data.len() {
471 why = Some(fmt!(
472 "it ends {} bytes into a {}-byte length field, after {} whole NAL units",
473 data.len() - at, n, nals));
474 break;
475 }
476 let mut len = 0usize;
477 for k in 0..n {
478 len = (len << 8) | data[at + k] as usize;
479 }
480 at += n;
481 if len == 0 {
482 why = Some(fmt!("NAL unit {} declares a length of zero", nals));
483 break;
484 }
485 if at + len > data.len() {
486 why = Some(fmt!(
487 "NAL unit {} declares {} bytes and only {} remain",
488 nals, len, data.len() - at));
489 break;
490 }
491 at += len;
492 nals += 1;
493 }
494 if why.is_none() && nals == 0 {
495 why = Some(fmt!("it carries no NAL units at all"));
496 }
497 match why {
498 None => Ok(()),
499 Some(why) => {
500 let start = data.len() >= 4 && data[0] == 0 && data[1] == 0
501 && (data[2] == 1 || (data[2] == 0 && data[3] == 1));
502 if start {
503 Err(err!(
504 "Sample {} is not tiled by {}-byte NAL length prefixes -- {} -- and it \
505 begins with an Annex B start code, so it is most likely an elementary \
506 stream handed over without conversion.", i, n, why;
507 Invalid, Input, Mismatch))
508 } else {
509 Err(err!(
510 "Sample {} is not tiled by {}-byte NAL length prefixes: {}.", i, n, why;
511 Invalid, Input, Size))
512 }
513 },
514 }
515 }
516}
517
518/// A video track, written as a whole MP4: samples pushed one at a time, and the file's bytes taken
519/// at the end.
520///
521/// One track is the whole of what this writes today, so the track is the file. A second track --
522/// narration, which wants its own timescale and its own sample table beside this one -- is a
523/// `Movie` taking two of these, and is not built until there is audio to put in it.
524///
525/// # Why the samples are held
526///
527/// The sample table states every sample's size, its duration and the file offset of the chunk it
528/// sits in, and the offsets are absolute, so none of them is known until the size of the table
529/// itself is. Holding the samples is what buys an exact table and a `moov` that precedes the media,
530/// which is the layout a reader can start playing before the download finishes.
531pub struct Track {
532 w: u16, // frame width in pixels
533 h: u16, // frame height in pixels
534 timescale: u32, // ticks a second, in which every sample duration is expressed
535 codec: Codec, // the codec and its decoder configuration
536 samples: Vec<Sample>, // decode order, which without B-pictures is display order
537 bytes: u64, // the samples' total size, kept as they arrive
538 ticks: u64, // and their total duration, in the track's timescale
539}
540
541impl Track {
542
543 /// Begins a video track of the given size and timescale, coded as the given codec says.
544 ///
545 /// The dimensions are checked against the geometry coded in the decoder configuration's
546 /// sequence parameter set, and a disagreement is refused: the two describe the same pictures,
547 /// and where they differ it is the caller's bookkeeping that is wrong, not the stream's.
548 pub fn new(w: u16, h: u16, timescale: u32, codec: Codec) -> Outcome<Self> {
549 if w == 0 || h == 0 {
550 return Err(err!(
551 "A track of {} by {} pixels has no picture in it.", w, h;
552 Invalid, Input, Range));
553 }
554 if timescale == 0 {
555 return Err(err!(
556 "A timescale of zero ticks a second names no rate, so no sample duration written \
557 against it would mean anything.";
558 Invalid, Input, Range));
559 }
560 let (cw, ch) = res!(codec.geometry());
561 if cw != w || ch != h {
562 return Err(err!(
563 "The track is declared {} by {} pixels, but the sequence parameter set in the \
564 decoder configuration codes {} by {}.", w, h, cw, ch;
565 Invalid, Input, Mismatch));
566 }
567 Ok(Self {
568 w,
569 h,
570 timescale,
571 codec,
572 samples: Vec::new(),
573 bytes: 0,
574 ticks: 0,
575 })
576 }
577
578 pub fn push(&mut self, s: Sample) -> Outcome<()> {
579 let i = self.samples.len();
580 if i >= MAX_SAMPLES {
581 return Err(err!(
582 "A track may hold {} samples, and this is sample {}.", MAX_SAMPLES, i + 1;
583 Invalid, Input, Excessive));
584 }
585 if s.dur == 0 {
586 return Err(err!(
587 "Sample {} is given a duration of zero ticks, so it is shown for no time at all.",
588 i;
589 Invalid, Input, Range));
590 }
591 if s.data.is_empty() {
592 return Err(err!("Sample {} carries no bytes.", i; Invalid, Input, Missing));
593 }
594 res!(self.codec.check_sample(i, &s.data));
595 self.bytes += s.data.len() as u64;
596 self.ticks += s.dur as u64;
597 self.samples.push(s);
598 Ok(())
599 }
600
601 pub fn samples(&self) -> usize {
602 self.samples.len()
603 }
604
605 pub fn is_empty(&self) -> bool {
606 self.samples.is_empty()
607 }
608
609 /// The total duration so far, in the track's own timescale.
610 pub fn duration(&self) -> u64 {
611 self.ticks
612 }
613
614 pub fn media_bytes(&self) -> u64 {
615 self.bytes
616 }
617
618 pub fn finish(self) -> Outcome<Vec<u8>> {
619 if self.samples.is_empty() {
620 return Err(err!(
621 "A track must hold at least one sample, and none were pushed.";
622 Invalid, Input, Missing));
623 }
624 if !self.samples[0].sync {
625 return Err(err!(
626 "Sample 0 is not a sync sample, so there is nowhere in the track a reader may \
627 begin decoding.";
628 Invalid, Input));
629 }
630 if self.ticks > u32::MAX as u64 {
631 return Err(err!(
632 "The track runs {} ticks at {} a second, which will not fit the 32-bit duration a \
633 version-0 media header carries.", self.ticks, self.timescale;
634 Invalid, Input, Excessive));
635 }
636 let movie_ticks = res!(rescale(self.ticks, self.timescale, MOVIE_TIMESCALE));
637 if movie_ticks > u32::MAX as u64 {
638 return Err(err!(
639 "The track runs {} milliseconds, which will not fit the 32-bit duration a \
640 version-0 movie header carries.", movie_ticks;
641 Invalid, Input, Excessive));
642 }
643
644 let ftyp = res!(ftyp(&self.codec));
645 // The `mdat` header is eight bytes, unless the media will not fit a 32-bit size, in which
646 // case ISO/IEC 14496-12 §4.2 puts a 64-bit `largesize` after the type and writes 1 in the
647 // size field.
648 let mdat_hdr = if self.bytes + 8 > u32::MAX as u64 { 16u64 } else { 8u64 };
649
650 // Two passes. The first sizes the index with a 32-bit offset table and zeroed offsets; if
651 // the last byte of media then falls beyond what a 32-bit offset can name, the second uses
652 // the 64-bit table instead. Widening the table only pushes the media further out, so this
653 // settles after one look.
654 let probe = res!(self.moov(0, false));
655 let head = ftyp.len() as u64 + probe.len() as u64 + mdat_hdr;
656 let wide = head + self.bytes > u32::MAX as u64;
657 let index = if wide {
658 let probe64 = res!(self.moov(0, true));
659 let head64 = ftyp.len() as u64 + probe64.len() as u64 + mdat_hdr;
660 res!(self.moov(head64, true))
661 } else {
662 res!(self.moov(head, false))
663 };
664
665 // The rebuilt index must be the size the offsets were computed against, or every one of
666 // them is wrong by the difference. The table's entries are a fixed width, so this holds by
667 // construction; it is asserted rather than assumed because nothing downstream would catch
668 // it.
669 let probe_len = if wide { res!(self.moov(0, true)).len() } else { probe.len() };
670 if index.len() != probe_len {
671 return Err(err!(
672 "The movie index came to {} bytes when sized and {} bytes when written, so the \
673 chunk offsets in it are wrong by {}.",
674 probe_len, index.len(), index.len() as i64 - probe_len as i64;
675 Bug, Unreachable));
676 }
677
678 let total = ftyp.len() as u64 + index.len() as u64 + mdat_hdr + self.bytes;
679 let mut out = Vec::with_capacity(total as usize);
680 out.extend_from_slice(&ftyp);
681 out.extend_from_slice(&index);
682 if mdat_hdr == 16 {
683 out.extend_from_slice(&1u32.to_be_bytes());
684 out.extend_from_slice(b"mdat");
685 out.extend_from_slice(&(self.bytes + 16).to_be_bytes());
686 } else {
687 out.extend_from_slice(&((self.bytes + 8) as u32).to_be_bytes());
688 out.extend_from_slice(b"mdat");
689 }
690 for s in &self.samples {
691 out.extend_from_slice(&s.data);
692 }
693 Ok(out)
694 }
695
696 /// The `moov` box, with the chunk offsets placed against a media that begins at `base`.
697 fn moov(&self, base: u64, wide: bool) -> Outcome<Vec<u8>> {
698 let movie_ticks = res!(rescale(self.ticks, self.timescale, MOVIE_TIMESCALE)) as u32;
699 let mut body = Vec::new();
700 body.extend_from_slice(&res!(self.mvhd(movie_ticks)));
701 body.extend_from_slice(&res!(self.trak(movie_ticks, base, wide)));
702 bx(b"moov", &body)
703 }
704
705 /// The movie header, ISO/IEC 14496-12 §8.2.2, in its version-0 form with 32-bit times.
706 fn mvhd(&self, movie_ticks: u32) -> Outcome<Vec<u8>> {
707 let mut b = Vec::with_capacity(100);
708 b.extend_from_slice(&full(0, 0));
709 b.extend_from_slice(&0u32.to_be_bytes()); // Creation time, unset.
710 b.extend_from_slice(&0u32.to_be_bytes()); // Modification time, unset.
711 b.extend_from_slice(&MOVIE_TIMESCALE.to_be_bytes());
712 b.extend_from_slice(&movie_ticks.to_be_bytes());
713 b.extend_from_slice(&0x0001_0000u32.to_be_bytes()); // Rate: 1.0 in 16.16.
714 b.extend_from_slice(&0x0100u16.to_be_bytes()); // Volume: 1.0 in 8.8.
715 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
716 b.extend_from_slice(&[0u8; 8]); // Reserved.
717 for v in UNITY {
718 b.extend_from_slice(&v.to_be_bytes());
719 }
720 b.extend_from_slice(&[0u8; 24]); // Pre-defined.
721 b.extend_from_slice(&2u32.to_be_bytes()); // Next track ID: one past the only track.
722 bx(b"mvhd", &b)
723 }
724
725 /// The track box: its header and its media.
726 fn trak(&self, movie_ticks: u32, base: u64, wide: bool) -> Outcome<Vec<u8>> {
727 let mut body = Vec::new();
728 body.extend_from_slice(&res!(self.tkhd(movie_ticks)));
729 body.extend_from_slice(&res!(self.mdia(base, wide)));
730 bx(b"trak", &body)
731 }
732
733 /// The track header, ISO/IEC 14496-12 §8.3.2, version 0.
734 ///
735 /// The flags are `0x000007`: enabled, in the movie, and in the preview. A track written without
736 /// `track_enabled` is present in the file and played by nothing.
737 fn tkhd(&self, movie_ticks: u32) -> Outcome<Vec<u8>> {
738 let mut b = Vec::with_capacity(84);
739 b.extend_from_slice(&full(0, 0x0000_0007));
740 b.extend_from_slice(&0u32.to_be_bytes()); // Creation time, unset.
741 b.extend_from_slice(&0u32.to_be_bytes()); // Modification time, unset.
742 b.extend_from_slice(&1u32.to_be_bytes()); // Track ID; zero is not allowed.
743 b.extend_from_slice(&0u32.to_be_bytes()); // Reserved.
744 b.extend_from_slice(&movie_ticks.to_be_bytes());
745 b.extend_from_slice(&[0u8; 8]); // Reserved.
746 b.extend_from_slice(&0u16.to_be_bytes()); // Layer: the front.
747 b.extend_from_slice(&0u16.to_be_bytes()); // Alternate group: no alternatives.
748 b.extend_from_slice(&0u16.to_be_bytes()); // Volume, which is zero for a visual track.
749 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
750 for v in UNITY {
751 b.extend_from_slice(&v.to_be_bytes());
752 }
753 // The presentation size, in 16.16 fixed point. It is the size the track is drawn at, which
754 // need not be the coded size the sample entry carries -- an anamorphic stream differs in
755 // exactly this field -- but for square pixels the two agree.
756 b.extend_from_slice(&((self.w as u32) << 16).to_be_bytes());
757 b.extend_from_slice(&((self.h as u32) << 16).to_be_bytes());
758 bx(b"tkhd", &b)
759 }
760
761 /// The media box: the media header, the handler, and the media information.
762 fn mdia(&self, base: u64, wide: bool) -> Outcome<Vec<u8>> {
763 let mut body = Vec::new();
764 body.extend_from_slice(&res!(self.mdhd()));
765 body.extend_from_slice(&res!(hdlr()));
766 body.extend_from_slice(&res!(self.minf(base, wide)));
767 bx(b"mdia", &body)
768 }
769
770 /// The media header, ISO/IEC 14496-12 §8.4.2, version 0, carrying the track's own timescale.
771 fn mdhd(&self) -> Outcome<Vec<u8>> {
772 let mut b = Vec::with_capacity(24);
773 b.extend_from_slice(&full(0, 0));
774 b.extend_from_slice(&0u32.to_be_bytes()); // Creation time, unset.
775 b.extend_from_slice(&0u32.to_be_bytes()); // Modification time, unset.
776 b.extend_from_slice(&self.timescale.to_be_bytes());
777 b.extend_from_slice(&(self.ticks as u32).to_be_bytes());
778 b.extend_from_slice(&LANG_UND.to_be_bytes());
779 b.extend_from_slice(&0u16.to_be_bytes()); // Pre-defined.
780 bx(b"mdhd", &b)
781 }
782
783 /// The media information box: the video media header, where the media lives, and the sample
784 /// table.
785 fn minf(&self, base: u64, wide: bool) -> Outcome<Vec<u8>> {
786 let mut body = Vec::new();
787 body.extend_from_slice(&res!(vmhd()));
788 body.extend_from_slice(&res!(dinf()));
789 body.extend_from_slice(&res!(self.stbl(base, wide)));
790 bx(b"minf", &body)
791 }
792
793 /// The sample table: what the samples are, how long each lasts, how big it is, which chunk it
794 /// is in, where the chunks are, and which samples a reader may begin at.
795 fn stbl(&self, base: u64, wide: bool) -> Outcome<Vec<u8>> {
796 let mut body = Vec::new();
797 body.extend_from_slice(&res!(self.stsd()));
798 body.extend_from_slice(&res!(self.stts()));
799 if let Some(ctts) = res!(self.ctts()) {
800 body.extend_from_slice(&ctts);
801 }
802 body.extend_from_slice(&res!(self.stsz()));
803 body.extend_from_slice(&res!(stsc()));
804 body.extend_from_slice(&res!(self.offsets(base, wide)));
805 if let Some(stss) = res!(self.stss()) {
806 body.extend_from_slice(&stss);
807 }
808 bx(b"stbl", &body)
809 }
810
811 /// The sample description: one entry, describing every sample in the track.
812 fn stsd(&self) -> Outcome<Vec<u8>> {
813 let mut b = Vec::new();
814 b.extend_from_slice(&full(0, 0));
815 b.extend_from_slice(&1u32.to_be_bytes()); // Entry count.
816 b.extend_from_slice(&res!(self.entry()));
817 bx(b"stsd", &b)
818 }
819
820 /// The visual sample entry, ISO/IEC 14496-12 §8.5.2, carrying the codec's configuration box.
821 fn entry(&self) -> Outcome<Vec<u8>> {
822 let mut b = Vec::with_capacity(86);
823 b.extend_from_slice(&[0u8; 6]); // Reserved.
824 b.extend_from_slice(&1u16.to_be_bytes()); // Data reference index: the first `dref` entry.
825 b.extend_from_slice(&0u16.to_be_bytes()); // Pre-defined.
826 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
827 b.extend_from_slice(&[0u8; 12]); // Pre-defined.
828 b.extend_from_slice(&self.w.to_be_bytes());
829 b.extend_from_slice(&self.h.to_be_bytes());
830 b.extend_from_slice(&RESOLUTION_72.to_be_bytes());
831 b.extend_from_slice(&RESOLUTION_72.to_be_bytes());
832 b.extend_from_slice(&0u32.to_be_bytes()); // Reserved.
833 b.extend_from_slice(&1u16.to_be_bytes()); // Frames a sample: one coded picture each.
834 // A fixed 32-byte field holding a counted string: a length byte, then that many bytes of
835 // name, then padding. Not a null-terminated string, and writing one there is a common way
836 // to put rubbish in front of a viewer that displays the field. The name comes from the
837 // codec, because a fixed one would go on saying "AVC Coding" over an HEVC track.
838 let name = self.codec.picture_name().as_bytes();
839 let mut cname = [0u8; 32];
840 cname[0] = name.len() as u8;
841 cname[1..1 + name.len()].copy_from_slice(name);
842 b.extend_from_slice(&cname);
843 b.extend_from_slice(&0x0018u16.to_be_bytes()); // Depth: colour with no alpha.
844 b.extend_from_slice(&0xFFFFu16.to_be_bytes()); // Pre-defined: -1.
845 b.extend_from_slice(&res!(bx(self.codec.config(), self.codec.record())));
846 bx(self.codec.entry(), &b)
847 }
848
849 /// The decoding time to sample table, ISO/IEC 14496-12 §8.6.1.2, run-length coded.
850 ///
851 /// Consecutive samples of equal duration share one entry, so a track at a constant frame rate
852 /// has exactly one entry however many frames it holds.
853 fn stts(&self) -> Outcome<Vec<u8>> {
854 let mut runs: Vec<(u32, u32)> = Vec::new();
855 for s in &self.samples {
856 match runs.last_mut() {
857 Some((n, d)) if *d == s.dur => *n += 1,
858 _ => runs.push((1, s.dur)),
859 }
860 }
861 let mut b = Vec::with_capacity(8 + runs.len() * 8);
862 b.extend_from_slice(&full(0, 0));
863 b.extend_from_slice(&(runs.len() as u32).to_be_bytes());
864 for (n, d) in runs {
865 b.extend_from_slice(&n.to_be_bytes());
866 b.extend_from_slice(&d.to_be_bytes());
867 }
868 bx(b"stts", &b)
869 }
870
871 /// The composition time to sample table, ISO/IEC 14496-12 §8.6.1.3, run-length coded.
872 ///
873 /// `None` where every sample is shown in the order it is decoded, because a track that never
874 /// reorders must not carry the box at all -- an absent `ctts` is the statement that the two
875 /// orders are the same, and writing a table of zeroes says the same thing at the cost of four
876 /// bytes a sample.
877 ///
878 /// Written at version 1, whose offsets are **signed**. Version 0's are unsigned, which forces
879 /// every decoding time to sit at or before the earliest presentation time and makes the first
880 /// pictures of a reordered stream inexpressible without shifting the whole track.
881 /// [`composition_offsets`] shifts anyway, so version 0 would serve -- but a signed table states
882 /// what is true rather than what has been arranged to be true, and a caller that works its own
883 /// offsets out is not forced into the same arrangement.
884 fn ctts(&self) -> Outcome<Option<Vec<u8>>> {
885 if self.samples.iter().all(|s| s.off == 0) {
886 return Ok(None);
887 }
888 let mut runs: Vec<(u32, i32)> = Vec::new();
889 for s in &self.samples {
890 match runs.last_mut() {
891 Some((n, o)) if *o == s.off => *n += 1,
892 _ => runs.push((1, s.off)),
893 }
894 }
895 let mut b = Vec::with_capacity(8 + runs.len() * 8);
896 b.extend_from_slice(&full(1, 0));
897 b.extend_from_slice(&(runs.len() as u32).to_be_bytes());
898 for (n, o) in runs {
899 b.extend_from_slice(&n.to_be_bytes());
900 b.extend_from_slice(&o.to_be_bytes());
901 }
902 Ok(Some(res!(bx(b"ctts", &b))))
903 }
904
905 /// The sample size table, ISO/IEC 14496-12 §8.7.3.2.
906 ///
907 /// The common size field is written as zero, meaning the sizes vary and are listed one by one.
908 /// A coded picture stream where every sample is the same length would be a remarkable
909 /// coincidence, so the branch that would save the table is not taken.
910 fn stsz(&self) -> Outcome<Vec<u8>> {
911 let mut b = Vec::with_capacity(12 + self.samples.len() * 4);
912 b.extend_from_slice(&full(0, 0));
913 b.extend_from_slice(&0u32.to_be_bytes()); // Sizes vary.
914 b.extend_from_slice(&(self.samples.len() as u32).to_be_bytes());
915 for s in &self.samples {
916 if s.data.len() > u32::MAX as usize {
917 return Err(err!(
918 "A sample of {} bytes will not fit the 32-bit size a sample size table holds.",
919 s.data.len();
920 Invalid, Input, Excessive));
921 }
922 b.extend_from_slice(&(s.data.len() as u32).to_be_bytes());
923 }
924 bx(b"stsz", &b)
925 }
926
927 /// The chunk offset table, as either the 32-bit `stco` or the 64-bit `co64` of ISO/IEC
928 /// 14496-12 §8.7.5.
929 ///
930 /// One sample a chunk. That costs four bytes a sample over packing the whole track into one
931 /// chunk, and it buys a table a second track can be interleaved into without the first being
932 /// rewritten -- which is what adding narration will want.
933 fn offsets(&self, base: u64, wide: bool) -> Outcome<Vec<u8>> {
934 let n = self.samples.len();
935 let mut b = Vec::with_capacity(8 + n * if wide { 8 } else { 4 });
936 b.extend_from_slice(&full(0, 0));
937 b.extend_from_slice(&(n as u32).to_be_bytes());
938 let mut at = base;
939 for s in &self.samples {
940 if wide {
941 b.extend_from_slice(&at.to_be_bytes());
942 } else {
943 if at > u32::MAX as u64 {
944 return Err(err!(
945 "A chunk begins at byte {}, beyond what the 32-bit offset table can name.",
946 at;
947 Invalid, Input, Excessive));
948 }
949 b.extend_from_slice(&(at as u32).to_be_bytes());
950 }
951 at += s.data.len() as u64;
952 }
953 bx(if wide { b"co64" } else { b"stco" }, &b)
954 }
955
956 /// The sync sample table, ISO/IEC 14496-12 §8.6.2, or `None` where every sample is a sync
957 /// sample.
958 ///
959 /// Its absence is not an omission: the specification says that where there is no sync sample
960 /// box, every sample is a sync sample. Writing one that lists all of them says the same thing
961 /// at four bytes a frame.
962 fn stss(&self) -> Outcome<Option<Vec<u8>>> {
963 if self.samples.iter().all(|s| s.sync) {
964 return Ok(None);
965 }
966 let keys: Vec<u32> = self.samples.iter()
967 .enumerate()
968 .filter(|(_, s)| s.sync)
969 .map(|(i, _)| i as u32 + 1) // Sample numbers are one-based.
970 .collect();
971 let mut b = Vec::with_capacity(8 + keys.len() * 4);
972 b.extend_from_slice(&full(0, 0));
973 b.extend_from_slice(&(keys.len() as u32).to_be_bytes());
974 for k in keys {
975 b.extend_from_slice(&k.to_be_bytes());
976 }
977 Ok(Some(res!(bx(b"stss", &b))))
978 }
979}
980
981// ------------------------------------------------------------------------- a fragmented film
982
983// The flags a sync sample carries in a track run: sample_depends_on = 2, meaning it refers to no
984// other picture, and sample_is_non_sync_sample = 0. ISO/IEC 14496-12 §8.8.3.1.
985const SAMPLE_SYNC: u32 = 0x0200_0000;
986
987// The flags a sample that is not a sync sample carries: sample_depends_on = 1, meaning it refers
988// to other pictures, and sample_is_non_sync_sample = 1. Both halves are stated: a reader deciding
989// where it may begin reads one or the other, and not always the same one, so a sample that says it
990// depends on nothing while also saying it is not a sync sample is a contradiction each reader
991// settles its own way.
992const SAMPLE_DELTA: u32 = 0x0101_0000;
993
994/// A film written as a header followed by fragments.
995///
996/// The counterpart of [`Track`], for the film whose samples are not all in hand. The header states
997/// what the streams are and states no duration at all, and each fragment after it carries its own
998/// timing for the samples it holds, so nothing is held back and nothing is rewritten at the end:
999/// the bytes can go out as they are produced, to a file being appended to or to a reader already
1000/// playing the fragments before them.
1001///
1002/// What that costs against [`Track`] is the index. A fragmented film has no whole-film sample
1003/// table, so a reader seeking into one walks the fragments to find where it is going. What it buys
1004/// is that the writer never holds the film, and that a film of unknown length can be written.
1005pub struct Fragments {
1006 streams: Vec<Stream>, // in the order given; track ids are positions plus one
1007 // Each stream's next decode time, in that stream's own timescale. Kept here because a
1008 // fragment states the decode time of its first sample outright, and nothing in the fragments
1009 // before it says where that time has got to: a reader handed only fragment fifty must be
1010 // able to place it, which is the whole point of the field.
1011 times: Vec<u64>,
1012 seq: u32, // the sequence number the next fragment carries, from one
1013}
1014
1015impl Fragments {
1016
1017 /// Begins a film of the given streams. Track ids are 1..=n in the order given.
1018 ///
1019 /// Everything about a stream that can be checked is checked here rather than at the first
1020 /// fragment, because the header describing it has by then been handed to a reader and cannot be
1021 /// taken back.
1022 pub fn new(streams: Vec<Stream>) -> Outcome<Self> {
1023 if streams.is_empty() {
1024 return Err(err!(
1025 "A film is made of streams and none were given.";
1026 Invalid, Input, Missing));
1027 }
1028 for (i, s) in streams.iter().enumerate() {
1029 if s.timescale == 0 {
1030 return Err(err!(
1031 "Stream {} is given a timescale of zero ticks a second, so no sample duration \
1032 written against it would mean anything.", i;
1033 Invalid, Input, Range));
1034 }
1035 match s.media {
1036 Media::Picture { w, h } => {
1037 if !s.codec.is_picture() {
1038 return Err(err!(
1039 "Stream {} is declared as pictures and coded by a sound codec, so the \
1040 handler, the media header and the sample entry its track carries cannot \
1041 all be right.", i;
1042 Invalid, Input, Mismatch));
1043 }
1044 let (cw, ch) = match s.codec.geometry() {
1045 Ok(g) => g,
1046 Err(e) => return Err(err!(e,
1047 "Stream {}'s decoder configuration could not be read.", i;
1048 Invalid, Input)),
1049 };
1050 if cw != w || ch != h {
1051 return Err(err!(
1052 "Stream {} is declared {} by {} pixels, but the sequence parameter set \
1053 in its decoder configuration codes {} by {}.", i, w, h, cw, ch;
1054 Invalid, Input, Mismatch));
1055 }
1056 },
1057 Media::Sound { rate, .. } => {
1058 if s.codec.is_picture() {
1059 return Err(err!(
1060 "Stream {} is declared as sound and coded by a picture codec, so the \
1061 handler, the media header and the sample entry its track carries cannot \
1062 all be right.", i;
1063 Invalid, Input, Mismatch));
1064 }
1065 // The sample entry states the rate in 16.16 fixed point, whose whole part is
1066 // sixteen bits. There is a version 1 entry that carries a wider one, and it is
1067 // not written here, so a rate that will not fit is refused rather than truncated
1068 // into a file that plays at the wrong speed.
1069 if rate >= 1 << 16 {
1070 return Err(err!(
1071 "Stream {} is sampled at {} Hz, and the 16.16 fixed point field a sound \
1072 sample entry states its rate in stops one short of 65536.", i, rate;
1073 Invalid, Input, Excessive));
1074 }
1075 },
1076 }
1077 }
1078 let times = streams.iter().map(|s| s.start).collect();
1079 Ok(Self {
1080 streams,
1081 times,
1082 seq: 1,
1083 })
1084 }
1085
1086 /// `ftyp` + `moov`: the initialisation segment, carrying no samples.
1087 ///
1088 /// Every duration in it is nought, and in a fragmented film that is a statement rather than a
1089 /// gap left to be filled: the length is not known, and a reader is told to take the timing from
1090 /// the fragments. The sample tables under `stbl` are written empty for the same reason, and they
1091 /// are written rather than left out because ISO/IEC 14496-12 §8.5.1 requires them present.
1092 pub fn head(&self) -> Outcome<Vec<u8>> {
1093 let ftyp = res!(ftyp_frag());
1094 let moov = res!(self.moov());
1095 let mut out = Vec::with_capacity(ftyp.len() + moov.len());
1096 out.extend_from_slice(&ftyp);
1097 out.extend_from_slice(&moov);
1098 Ok(out)
1099 }
1100
1101 /// One `moof` + `mdat` pair carrying the given samples.
1102 ///
1103 /// Each entry is (index into the streams given to [`Fragments::new`], that stream's samples in
1104 /// decode order). The samples are taken by value because they are moved into the media box and
1105 /// not copied: a `Vec` behind a shared reference cannot be moved out of, so borrowing here would
1106 /// clone every sample's bytes and carry the whole fragment twice.
1107 ///
1108 /// An empty `Vec` of samples for a listed stream is legal and writes a track fragment whose
1109 /// `sample_count` is nought. A stream with nothing in this fragment is ordinary -- sound and
1110 /// pictures do not divide at the same instants -- and the empty run still says the stream is
1111 /// there and where its decode time has got to.
1112 ///
1113 /// Each fragment's decode times carry on from the fragments before it, so the same samples
1114 /// handed over in two calls and in one produce the same timing.
1115 pub fn next(&mut self, runs: Vec<(usize, Vec<Sample>)>) -> Outcome<Vec<u8>> {
1116 let frag = self.seq;
1117 let mut seen = vec![false; self.streams.len()];
1118 let mut total = 0u64;
1119 for (i, samples) in &runs {
1120 let i = *i;
1121 if i >= self.streams.len() {
1122 return Err(err!(
1123 "Fragment {} names stream {}, and the film has {}.",
1124 frag, i, self.streams.len();
1125 Invalid, Input, Index));
1126 }
1127 if seen[i] {
1128 return Err(err!(
1129 "Fragment {} names stream {} twice, and a stream has at most one track fragment \
1130 in a movie fragment.", frag, i;
1131 Invalid, Input, Duplicate));
1132 }
1133 seen[i] = true;
1134 let codec = &self.streams[i].codec;
1135 for (k, sam) in samples.iter().enumerate() {
1136 if sam.data.is_empty() {
1137 return Err(err!(
1138 "Sample {} of stream {} in fragment {} carries no bytes.", k, i, frag;
1139 Invalid, Input, Missing));
1140 }
1141 if sam.dur == 0 {
1142 return Err(err!(
1143 "Sample {} of stream {} in fragment {} is given a duration of zero ticks, \
1144 so it is shown for no time at all.", k, i, frag;
1145 Invalid, Input, Range));
1146 }
1147 if sam.data.len() > u32::MAX as usize {
1148 return Err(err!(
1149 "Sample {} of stream {} in fragment {} is {} bytes, which will not fit the \
1150 32-bit size a track run states.", k, i, frag, sam.data.len();
1151 Invalid, Input, Excessive));
1152 }
1153 if let Err(e) = codec.check_sample(k, &sam.data) {
1154 return Err(err!(e,
1155 "Sample {} of stream {} in fragment {} is not coded the way the stream's \
1156 decoder configuration says it is.", k, i, frag;
1157 Invalid, Input));
1158 }
1159 total += sam.data.len() as u64;
1160 }
1161 }
1162
1163 // The media box's header is eight bytes, unless its payload will not fit a 32-bit size, in
1164 // which case ISO/IEC 14496-12 §4.2 writes 1 in the size field and a 64-bit `largesize` after
1165 // the type. The width is settled here and not at the writing, because every data offset
1166 // below is measured across it.
1167 let mdat_hdr = if total + 8 > u32::MAX as u64 { 16u64 } else { 8u64 };
1168
1169 // Where each stream stands before this fragment adds to it. Taken now because the movie
1170 // fragment box is built twice and both passes must state the same times.
1171 let bases: Vec<u64> = runs.iter().map(|(i, _)| self.times[*i]).collect();
1172
1173 // Two passes. A track run's data offset is measured from the first byte of the movie
1174 // fragment box that holds it, so it cannot be known until that box's size is -- and the size
1175 // depends on the offsets only through fields of a fixed width, so sizing the box against
1176 // placeholders and writing it again with the real values settles at once.
1177 let blank = vec![0i32; runs.len()];
1178 let probe = res!(self.moof(frag, &runs, &bases, &blank));
1179 let mut offs = Vec::with_capacity(runs.len());
1180 let mut at = probe.len() as u64 + mdat_hdr;
1181 for (_, samples) in &runs {
1182 if at > i32::MAX as u64 {
1183 return Err(err!(
1184 "Fragment {} puts a track run's data {} bytes past the movie fragment it is \
1185 measured from, and that offset is a signed 32-bit field.", frag, at;
1186 Invalid, Input, Excessive));
1187 }
1188 offs.push(at as i32);
1189 for s in samples {
1190 at += s.data.len() as u64;
1191 }
1192 }
1193 let moof = res!(self.moof(frag, &runs, &bases, &offs));
1194
1195 // The rebuilt box must be the size the offsets were measured against, or every one of them
1196 // is wrong by the difference. It holds by construction, and it is asserted because a file
1197 // whose offsets are all out by a few bytes is well formed, opens, and plays rubbish.
1198 if moof.len() != probe.len() {
1199 return Err(err!(
1200 "Fragment {}'s movie fragment box came to {} bytes when sized and {} bytes when \
1201 written, so every data offset in it is out by {}.",
1202 frag, probe.len(), moof.len(), moof.len() as i64 - probe.len() as i64;
1203 Bug, Unreachable));
1204 }
1205 // And the walk that laid the offsets out must have covered exactly the samples that are
1206 // about to be written, or a later track run points past the end of the media box.
1207 if at != moof.len() as u64 + mdat_hdr + total {
1208 return Err(err!(
1209 "Fragment {} laid its data offsets out to byte {}, and the fragment ends at {}.",
1210 frag, at, moof.len() as u64 + mdat_hdr + total;
1211 Bug, Unreachable));
1212 }
1213
1214 let mut out = Vec::with_capacity(moof.len() + mdat_hdr as usize + total as usize);
1215 out.extend_from_slice(&moof);
1216 if mdat_hdr == 16 {
1217 out.extend_from_slice(&1u32.to_be_bytes());
1218 out.extend_from_slice(b"mdat");
1219 out.extend_from_slice(&(total + 16).to_be_bytes());
1220 } else {
1221 out.extend_from_slice(&((total + 8) as u32).to_be_bytes());
1222 out.extend_from_slice(b"mdat");
1223 }
1224 // Track fragment order, then sample order: all of the first stream's bytes, then all of the
1225 // second's. That is the order the offsets above were counted in.
1226 for (_, samples) in &runs {
1227 for s in samples {
1228 out.extend_from_slice(&s.data);
1229 }
1230 }
1231
1232 // Only now is anything of the film's state moved on, so a refused fragment leaves the writer
1233 // where it was and the caller may hand over a corrected one.
1234 for (i, samples) in &runs {
1235 let mut ticks = 0u64;
1236 for s in samples {
1237 ticks += s.dur as u64;
1238 }
1239 self.times[*i] += ticks;
1240 }
1241 self.seq += 1;
1242 Ok(out)
1243 }
1244
1245 /// The movie box: the movie header, one track for each stream, and the extends box that says
1246 /// the sample descriptions are completed by fragments rather than by the tables above them.
1247 fn moov(&self) -> Outcome<Vec<u8>> {
1248 let mut body = Vec::new();
1249 body.extend_from_slice(&res!(self.mvhd()));
1250 for (i, s) in self.streams.iter().enumerate() {
1251 body.extend_from_slice(&res!(self.trak(i, s)));
1252 }
1253 body.extend_from_slice(&res!(self.mvex()));
1254 bx(b"moov", &body)
1255 }
1256
1257 /// The movie header, ISO/IEC 14496-12 §8.2.2, version 0, stating no duration.
1258 ///
1259 /// A duration of nought is the fragmented film's way of saying the length is not known yet; a
1260 /// reader that wants it adds the fragments up, or reads an `mfra` at the end if one was written.
1261 fn mvhd(&self) -> Outcome<Vec<u8>> {
1262 let mut b = Vec::with_capacity(100);
1263 b.extend_from_slice(&full(0, 0));
1264 b.extend_from_slice(&0u32.to_be_bytes()); // Creation time, unset.
1265 b.extend_from_slice(&0u32.to_be_bytes()); // Modification time, unset.
1266 b.extend_from_slice(&MOVIE_TIMESCALE.to_be_bytes());
1267 b.extend_from_slice(&0u32.to_be_bytes()); // Duration, not yet known.
1268 b.extend_from_slice(&0x0001_0000u32.to_be_bytes()); // Rate: 1.0 in 16.16.
1269 b.extend_from_slice(&0x0100u16.to_be_bytes()); // Volume: 1.0 in 8.8.
1270 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
1271 b.extend_from_slice(&[0u8; 8]); // Reserved.
1272 for v in UNITY {
1273 b.extend_from_slice(&v.to_be_bytes());
1274 }
1275 b.extend_from_slice(&[0u8; 24]); // Pre-defined.
1276 // One past the highest track id in use, which is what the field is defined as. ffmpeg
1277 // writes the track count itself -- 2 for two tracks, whose ids are 1 and 2 -- and that is a
1278 // violation: a tool adding a track would take an id already taken. Written correctly here.
1279 b.extend_from_slice(&(self.streams.len() as u32 + 1).to_be_bytes());
1280 bx(b"mvhd", &b)
1281 }
1282
1283 /// One track: its header and its media.
1284 fn trak(&self, i: usize, s: &Stream) -> Outcome<Vec<u8>> {
1285 let mut body = Vec::new();
1286 body.extend_from_slice(&res!(self.tkhd(i, s)));
1287 body.extend_from_slice(&res!(self.mdia(i, s)));
1288 bx(b"trak", &body)
1289 }
1290
1291 /// The track header, ISO/IEC 14496-12 §8.3.2, version 0, stating no duration.
1292 ///
1293 /// The flags are `0x000003`: enabled, and in the movie. The whole-file writer above sets
1294 /// `track_in_preview` as well; nothing here writes a preview, so the bit is left clear, and
1295 /// what matters is `track_enabled` -- a track without it is in the file and played by nothing.
1296 fn tkhd(&self, i: usize, s: &Stream) -> Outcome<Vec<u8>> {
1297 let mut b = Vec::with_capacity(84);
1298 b.extend_from_slice(&full(0, 0x0000_0003));
1299 b.extend_from_slice(&0u32.to_be_bytes()); // Creation time, unset.
1300 b.extend_from_slice(&0u32.to_be_bytes()); // Modification time, unset.
1301 b.extend_from_slice(&(i as u32 + 1).to_be_bytes()); // Track id; zero is not allowed.
1302 b.extend_from_slice(&0u32.to_be_bytes()); // Reserved.
1303 b.extend_from_slice(&0u32.to_be_bytes()); // Duration, not yet known.
1304 b.extend_from_slice(&[0u8; 8]); // Reserved.
1305 b.extend_from_slice(&0u16.to_be_bytes()); // Layer: the front.
1306 match s.media {
1307 // A sound track is put in alternate group 1 and a picture track in none. The group says
1308 // "play one of these, not both", which is right for the sound tracks of a film in
1309 // several languages and wrong for a picture track, whose group must not name any
1310 // alternative to it.
1311 Media::Picture { .. } => b.extend_from_slice(&0u16.to_be_bytes()),
1312 Media::Sound { .. } => b.extend_from_slice(&1u16.to_be_bytes()),
1313 }
1314 match s.media {
1315 Media::Picture { .. } => b.extend_from_slice(&0u16.to_be_bytes()),
1316 Media::Sound { .. } => b.extend_from_slice(&0x0100u16.to_be_bytes()), // 1.0 in 8.8.
1317 }
1318 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
1319 for v in UNITY {
1320 b.extend_from_slice(&v.to_be_bytes());
1321 }
1322 // The presentation size in 16.16 fixed point, and nought by nought for sound, which is
1323 // drawn nowhere. A non-zero size on a sound track makes some players lay out a blank
1324 // rectangle for it.
1325 match s.media {
1326 Media::Picture { w, h } => {
1327 b.extend_from_slice(&((w as u32) << 16).to_be_bytes());
1328 b.extend_from_slice(&((h as u32) << 16).to_be_bytes());
1329 },
1330 Media::Sound { .. } => {
1331 b.extend_from_slice(&0u32.to_be_bytes());
1332 b.extend_from_slice(&0u32.to_be_bytes());
1333 },
1334 }
1335 bx(b"tkhd", &b)
1336 }
1337
1338 /// The media box: the media header, the handler that declares what the track is, and the media
1339 /// information.
1340 fn mdia(&self, i: usize, s: &Stream) -> Outcome<Vec<u8>> {
1341 let mut body = Vec::new();
1342 body.extend_from_slice(&res!(self.mdhd(s)));
1343 body.extend_from_slice(&res!(match s.media {
1344 Media::Picture { .. } => handler(b"vide", "VideoHandler"),
1345 Media::Sound { .. } => handler(b"soun", "SoundHandler"),
1346 }));
1347 body.extend_from_slice(&res!(self.minf(i, s)));
1348 bx(b"mdia", &body)
1349 }
1350
1351 /// The media header, ISO/IEC 14496-12 §8.4.2, version 0, carrying the stream's own timescale.
1352 ///
1353 /// The timescale is the stream's and not the movie's, and it is the unit every duration in
1354 /// every fragment of this track is counted in, so it is the one number here a fragment depends
1355 /// on being right.
1356 fn mdhd(&self, s: &Stream) -> Outcome<Vec<u8>> {
1357 let mut b = Vec::with_capacity(24);
1358 b.extend_from_slice(&full(0, 0));
1359 b.extend_from_slice(&0u32.to_be_bytes()); // Creation time, unset.
1360 b.extend_from_slice(&0u32.to_be_bytes()); // Modification time, unset.
1361 b.extend_from_slice(&s.timescale.to_be_bytes());
1362 b.extend_from_slice(&0u32.to_be_bytes()); // Duration, not yet known.
1363 b.extend_from_slice(&LANG_UND.to_be_bytes());
1364 b.extend_from_slice(&0u16.to_be_bytes()); // Pre-defined.
1365 bx(b"mdhd", &b)
1366 }
1367
1368 /// The media information box: the media header its kind requires, where the media lives, and
1369 /// the sample table.
1370 fn minf(&self, i: usize, s: &Stream) -> Outcome<Vec<u8>> {
1371 let mut body = Vec::new();
1372 body.extend_from_slice(&res!(match s.media {
1373 Media::Picture { .. } => vmhd(),
1374 Media::Sound { .. } => smhd(),
1375 }));
1376 body.extend_from_slice(&res!(dinf()));
1377 body.extend_from_slice(&res!(self.stbl(i, s)));
1378 bx(b"minf", &body)
1379 }
1380
1381 /// The sample table: what the samples are, and four empty tables where a whole-file writer
1382 /// would put the timing, the sizes and the offsets.
1383 ///
1384 /// No `ctts` and no `stss`. A fragmented film states composition offsets and sync flags once a
1385 /// sample in its track runs, so a table here would be a second, empty, statement of the same
1386 /// thing -- and an empty `stss` in particular reads as "no sample is a sync sample", which would
1387 /// leave a reader with nowhere to begin.
1388 fn stbl(&self, i: usize, s: &Stream) -> Outcome<Vec<u8>> {
1389 let mut body = Vec::new();
1390 body.extend_from_slice(&res!(self.stsd(i, s)));
1391 body.extend_from_slice(&res!(empty_table(b"stts")));
1392 body.extend_from_slice(&res!(empty_table(b"stsc")));
1393 body.extend_from_slice(&res!(empty_stsz()));
1394 body.extend_from_slice(&res!(empty_table(b"stco")));
1395 bx(b"stbl", &body)
1396 }
1397
1398 /// The sample description: one entry, describing every sample the fragments will carry for this
1399 /// stream.
1400 fn stsd(&self, i: usize, s: &Stream) -> Outcome<Vec<u8>> {
1401 let entry = match s.media {
1402 Media::Picture { w, h } => res!(picture_entry(&s.codec, w, h)),
1403 Media::Sound { channels, rate } => res!(sound_entry(
1404 &s.codec, i as u32 + 1, channels, rate)),
1405 };
1406 let mut b = Vec::with_capacity(8 + entry.len());
1407 b.extend_from_slice(&full(0, 0));
1408 b.extend_from_slice(&1u32.to_be_bytes()); // Entry count.
1409 b.extend_from_slice(&entry);
1410 bx(b"stsd", &b)
1411 }
1412
1413 /// The movie extends box: one `trex` a track, and no `mehd`.
1414 ///
1415 /// Its presence is what tells a reader that the empty sample tables above are not an empty film
1416 /// but a film continued in fragments. `mehd` would state the whole duration, which is the one
1417 /// thing a writer that has not seen the end cannot say.
1418 fn mvex(&self) -> Outcome<Vec<u8>> {
1419 let mut body = Vec::new();
1420 for i in 0..self.streams.len() {
1421 body.extend_from_slice(&res!(trex(i as u32 + 1)));
1422 }
1423 bx(b"mvex", &body)
1424 }
1425
1426 /// The movie fragment box: its header, then one track fragment for each entry of `runs`, in the
1427 /// order given.
1428 ///
1429 /// `bases` and `offs` are read positionally against `runs`: the decode time each track fragment
1430 /// begins at, and the offset of its samples from the first byte of this box.
1431 fn moof(
1432 &self,
1433 seq: u32,
1434 runs: &[(usize, Vec<Sample>)],
1435 bases: &[u64],
1436 offs: &[i32],
1437 )
1438 -> Outcome<Vec<u8>>
1439 {
1440 let mut body = Vec::new();
1441 body.extend_from_slice(&res!(mfhd(seq)));
1442 for (n, (i, samples)) in runs.iter().enumerate() {
1443 let base = match bases.get(n) {
1444 Some(t) => *t,
1445 None => return Err(err!(
1446 "Fragment {} has {} track runs and {} decode times to place them at.",
1447 seq, runs.len(), bases.len();
1448 Bug, Unreachable)),
1449 };
1450 let off = match offs.get(n) {
1451 Some(o) => *o,
1452 None => return Err(err!(
1453 "Fragment {} has {} track runs and {} data offsets for them.",
1454 seq, runs.len(), offs.len();
1455 Bug, Unreachable)),
1456 };
1457 body.extend_from_slice(&res!(traf(*i as u32 + 1, base, off, samples)));
1458 }
1459 bx(b"moof", &body)
1460 }
1461}
1462
1463/// The file type box of a fragmented film.
1464///
1465/// Written separately from [`ftyp`] rather than by a flag on it, because the two make different
1466/// promises and the whole-file writer's must not move: `avc1` in that list promises a track whose
1467/// sample table is in `moov`, which is exactly what this file does not have. `iso5` with a minor
1468/// version of 512, and `iso5`, `iso6` and `mp41` behind it, is what ffmpeg writes for a fragmented
1469/// file and so is the list the readers of one have been tried against.
1470///
1471/// **No `hvc1` for an HEVC film**, for three reasons. The brand is a conformance claim about the
1472/// whole file (ISO/IEC 14496-15 §8.4.1) and a [`Fragments`] may carry several streams, only one of
1473/// which is the picture; nothing here is handed the codec anyway, which is the same reason `avc1`
1474/// is absent; and ffmpeg writes these same three brands and no fourth for a fragmented HEVC file,
1475/// so adding one would be a list no reader of such a file has been tried against. A reader finds
1476/// the codec in the sample entry, which is where the answer belongs.
1477fn ftyp_frag() -> Outcome<Vec<u8>> {
1478 let mut b = Vec::with_capacity(20);
1479 b.extend_from_slice(b"iso5");
1480 b.extend_from_slice(&512u32.to_be_bytes());
1481 b.extend_from_slice(b"iso5");
1482 b.extend_from_slice(b"iso6");
1483 b.extend_from_slice(b"mp41");
1484 bx(b"ftyp", &b)
1485}
1486
1487/// A sample table box with no entries: a full box and a count of nought.
1488///
1489/// `stts`, `stsc` and `stco` all take that shape, and a fragmented film writes all three empty.
1490/// They are written rather than left out because ISO/IEC 14496-12 §8.5.1 requires them in every
1491/// sample table, and readers that check do refuse a table missing one.
1492fn empty_table(kind: &[u8; 4]) -> Outcome<Vec<u8>> {
1493 let mut b = Vec::with_capacity(8);
1494 b.extend_from_slice(&full(0, 0));
1495 b.extend_from_slice(&0u32.to_be_bytes()); // Entry count.
1496 bx(kind, &b)
1497}
1498
1499/// The sample size table with nothing in it.
1500///
1501/// Not the same shape as the other three: it carries a common size before its count, and both are
1502/// nought here -- no common size, and no samples to give one to.
1503fn empty_stsz() -> Outcome<Vec<u8>> {
1504 let mut b = Vec::with_capacity(12);
1505 b.extend_from_slice(&full(0, 0));
1506 b.extend_from_slice(&0u32.to_be_bytes()); // Sizes vary, so each is listed.
1507 b.extend_from_slice(&0u32.to_be_bytes()); // Sample count.
1508 bx(b"stsz", &b)
1509}
1510
1511/// The visual sample entry of a fragmented film, ISO/IEC 14496-12 §8.5.2, carrying the codec's
1512/// configuration box.
1513///
1514/// The same 78-byte lead-in as the whole-file writer's, with one difference: the compressor name is
1515/// left as 32 zero bytes. The field is a counted string, so a leading nought is a name of no
1516/// characters, which is what a file that has nothing to say there should write -- and it is what
1517/// ffmpeg writes for a fragmented file.
1518fn picture_entry(codec: &Codec, w: u16, h: u16) -> Outcome<Vec<u8>> {
1519 if !codec.is_picture() {
1520 return Err(err!(
1521 "A visual sample entry was asked for around a sound codec."; Bug, Invalid));
1522 }
1523 let mut b = Vec::with_capacity(86);
1524 b.extend_from_slice(&[0u8; 6]); // Reserved.
1525 b.extend_from_slice(&1u16.to_be_bytes()); // Data reference index: the first `dref` entry.
1526 b.extend_from_slice(&0u16.to_be_bytes()); // Pre-defined.
1527 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
1528 b.extend_from_slice(&[0u8; 12]); // Pre-defined.
1529 b.extend_from_slice(&w.to_be_bytes());
1530 b.extend_from_slice(&h.to_be_bytes());
1531 b.extend_from_slice(&RESOLUTION_72.to_be_bytes());
1532 b.extend_from_slice(&RESOLUTION_72.to_be_bytes());
1533 b.extend_from_slice(&0u32.to_be_bytes()); // Reserved.
1534 b.extend_from_slice(&1u16.to_be_bytes()); // Frames a sample: one coded picture each.
1535 b.extend_from_slice(&[0u8; 32]); // Compressor name: none given.
1536 b.extend_from_slice(&0x0018u16.to_be_bytes()); // Depth: colour with no alpha.
1537 b.extend_from_slice(&0xFFFFu16.to_be_bytes()); // Pre-defined: -1.
1538 b.extend_from_slice(&res!(bx(codec.config(), codec.record())));
1539 bx(codec.entry(), &b)
1540}
1541
1542/// The sound sample entry, ISO/IEC 14496-12 §8.5.2, carrying the elementary stream descriptor.
1543///
1544/// The channel count and the rate are stated here as well as inside the `AudioSpecificConfig` the
1545/// descriptor carries, and the two must agree: a reader shows what this says and a decoder produces
1546/// what the configuration says, so a disagreement is a file that reports stereo and plays mono.
1547/// They are not checked against each other here because parsing the configuration is a decoder's
1548/// job, and the caller that copied both out of one source container has them consistent already.
1549fn sound_entry(codec: &Codec, track_id: u32, channels: u16, rate: u32) -> Outcome<Vec<u8>> {
1550 if codec.is_picture() {
1551 return Err(err!(
1552 "A sound sample entry was asked for around a picture codec."; Bug, Invalid));
1553 }
1554 if rate >= 1 << 16 {
1555 return Err(err!(
1556 "Track {} is sampled at {} Hz, which will not fit the whole part of the 16.16 fixed \
1557 point field a sound sample entry states its rate in.", track_id, rate;
1558 Invalid, Input, Excessive));
1559 }
1560 let mut b = Vec::with_capacity(64);
1561 b.extend_from_slice(&[0u8; 6]); // Reserved.
1562 b.extend_from_slice(&1u16.to_be_bytes()); // Data reference index: the first `dref` entry.
1563 b.extend_from_slice(&[0u8; 8]); // Reserved.
1564 b.extend_from_slice(&channels.to_be_bytes());
1565 b.extend_from_slice(&16u16.to_be_bytes()); // Sample size in bits, which this field fixes at 16.
1566 b.extend_from_slice(&0u16.to_be_bytes()); // Pre-defined.
1567 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
1568 b.extend_from_slice(&(rate << 16).to_be_bytes());
1569 b.extend_from_slice(&res!(esds(track_id, codec.record())));
1570 bx(codec.entry(), &b)
1571}
1572
1573/// A descriptor's length, in the four-byte form ISO/IEC 14496-1 §8.3.3 allows.
1574///
1575/// A length is a run of bytes carrying seven bits each, the top bit saying another follows, so
1576/// anything under 128 could be written in one byte. Four are written whatever the length, padded
1577/// with `0x80` bytes that contribute nothing: that is what ffmpeg writes, and a reader that assumed
1578/// the fixed width and stepped four bytes on regardless has been met often enough that the padded
1579/// form is the safe one to write.
1580fn desc_len(n: usize) -> Outcome<[u8; 4]> {
1581 if n >= 1 << 28 {
1582 return Err(err!(
1583 "A descriptor of {} bytes will not fit the four seven-bit length bytes a descriptor \
1584 header carries.", n;
1585 Invalid, Input, Excessive));
1586 }
1587 Ok([
1588 0x80 | ((n >> 21) & 0x7F) as u8,
1589 0x80 | ((n >> 14) & 0x7F) as u8,
1590 0x80 | ((n >> 7) & 0x7F) as u8,
1591 (n & 0x7F) as u8,
1592 ])
1593}
1594
1595/// The elementary stream descriptor box of a sound sample entry, ISO/IEC 14496-1 §7.2.6.
1596///
1597/// Its contents are a tree of descriptors rather than boxes, so nothing inside is length-prefixed
1598/// the way the rest of the file is, and each length has to be added up from the ones below it. They
1599/// are computed here rather than written down: 34 and 20 are right for the two-byte configuration
1600/// of common AAC-LC and wrong for every longer one, and a wrong length there produces a file whose
1601/// box tree is perfectly well formed and whose audio decoder will not start.
1602fn esds(track_id: u32, config: &[u8]) -> Outcome<Vec<u8>> {
1603 if config.is_empty() {
1604 return Err(err!(
1605 "Track {} carries no AudioSpecificConfig, and a decoder cannot be started without one.",
1606 track_id;
1607 Invalid, Input, Missing));
1608 }
1609 // Each descriptor is one tag byte, four length bytes, and its payload, so a descriptor adds
1610 // five bytes to whatever it holds.
1611 let dsi = config.len();
1612 let dcd = 13 + 5 + dsi;
1613 let es = 3 + 5 + dcd + 5 + 1;
1614 let mut b = Vec::with_capacity(4 + 5 + es);
1615 b.extend_from_slice(&full(0, 0));
1616
1617 b.push(0x03); // ES_Descriptor.
1618 b.extend_from_slice(&res!(desc_len(es)));
1619 // The elementary stream's id, which is the track's: two numbering schemes for one thing, and
1620 // they are kept equal so that nothing has to map between them.
1621 b.extend_from_slice(&(track_id as u16).to_be_bytes());
1622 b.push(0x00); // No stream dependence, no URL, no OCR stream, priority 0.
1623
1624 b.push(0x04); // DecoderConfigDescriptor.
1625 b.extend_from_slice(&res!(desc_len(dcd)));
1626 b.push(0x40); // Object type: MPEG-4 audio.
1627 // Stream type 5, AudioStream, in the top six bits; upstream 0; and the reserved bit, which the
1628 // specification requires set. A zero there is what a hand-written `0x14` gives, and some
1629 // decoders take the whole descriptor as malformed.
1630 b.push(0x15);
1631 b.extend_from_slice(&[0u8; 3]); // Decoding buffer size, unstated.
1632 b.extend_from_slice(&0u32.to_be_bytes()); // Maximum bitrate, unstated.
1633 b.extend_from_slice(&0u32.to_be_bytes()); // Average bitrate, unstated.
1634
1635 b.push(0x05); // DecoderSpecificInfo.
1636 b.extend_from_slice(&res!(desc_len(dsi)));
1637 b.extend_from_slice(config);
1638
1639 b.push(0x06); // SLConfigDescriptor.
1640 b.extend_from_slice(&res!(desc_len(1)));
1641 b.push(0x02); // Predefined: the MP4 file setting.
1642
1643 bx(b"esds", &b)
1644}
1645
1646/// A track extends box, ISO/IEC 14496-12 §8.8.3: the defaults a track fragment falls back on.
1647///
1648/// Every default but the sample description index is nought, and nothing falls back on them,
1649/// because each track run below states every value for every sample. Defaults are how a fragmented
1650/// file is usually made smaller; they are also how a fragment ends up timed by a value set in a
1651/// header written hours earlier, and the saving is four bytes a sample.
1652fn trex(track_id: u32) -> Outcome<Vec<u8>> {
1653 let mut b = Vec::with_capacity(24);
1654 b.extend_from_slice(&full(0, 0));
1655 b.extend_from_slice(&track_id.to_be_bytes());
1656 b.extend_from_slice(&1u32.to_be_bytes()); // Sample description index; one-based.
1657 b.extend_from_slice(&0u32.to_be_bytes()); // Default sample duration.
1658 b.extend_from_slice(&0u32.to_be_bytes()); // Default sample size.
1659 b.extend_from_slice(&0u32.to_be_bytes()); // Default sample flags.
1660 bx(b"trex", &b)
1661}
1662
1663/// The movie fragment header, ISO/IEC 14496-12 §8.8.5, carrying the fragment's sequence number.
1664///
1665/// The numbers count from one and rise by one, which is what lets a reader that has been handed
1666/// fragments out of order, or has missed one, say so.
1667fn mfhd(seq: u32) -> Outcome<Vec<u8>> {
1668 let mut b = Vec::with_capacity(8);
1669 b.extend_from_slice(&full(0, 0));
1670 b.extend_from_slice(&seq.to_be_bytes());
1671 bx(b"mfhd", &b)
1672}
1673
1674/// One track's part of a fragment: which track it is, where its decode time has got to, and the
1675/// run of samples itself.
1676fn traf(track_id: u32, base: u64, off: i32, samples: &[Sample]) -> Outcome<Vec<u8>> {
1677 let mut body = Vec::new();
1678 body.extend_from_slice(&res!(tfhd(track_id)));
1679 body.extend_from_slice(&res!(tfdt(base)));
1680 body.extend_from_slice(&res!(trun(off, samples)));
1681 bx(b"traf", &body)
1682}
1683
1684/// The track fragment header, ISO/IEC 14496-12 §8.8.7.
1685///
1686/// The flags are `0x020000`, `default-base-is-moof`, and nothing else. That fixes the origin every
1687/// data offset below is measured from at the first byte of the enclosing `moof`, which is a
1688/// position the fragment knows about itself -- the alternative bases are file offsets, and a
1689/// fragment that has been cut out and served on its own no longer knows where in a file it was.
1690///
1691/// Deliberately simpler than ffmpeg, which also sets the default duration, size and flags. Every
1692/// per-sample value is written in the track run instead: four bytes a sample against a class of
1693/// fault where a sample takes a default nobody meant it to have.
1694fn tfhd(track_id: u32) -> Outcome<Vec<u8>> {
1695 let mut b = Vec::with_capacity(8);
1696 b.extend_from_slice(&full(0, 0x0002_0000));
1697 b.extend_from_slice(&track_id.to_be_bytes());
1698 bx(b"tfhd", &b)
1699}
1700
1701/// The track fragment decode time, ISO/IEC 14496-12 §8.8.12, version 1.
1702///
1703/// The absolute decode time of the fragment's first sample, in the track's own timescale. Version 1
1704/// carries it in 64 bits: a 32-bit field overflows after thirteen hours at 90 kHz, which is a
1705/// running time a recording reaches, and the box exists precisely so that a reader handed one
1706/// fragment can place it without the fragments before it.
1707fn tfdt(base: u64) -> Outcome<Vec<u8>> {
1708 let mut b = Vec::with_capacity(12);
1709 b.extend_from_slice(&full(1, 0));
1710 b.extend_from_slice(&base.to_be_bytes());
1711 bx(b"tfdt", &b)
1712}
1713
1714/// The track run, ISO/IEC 14496-12 §8.8.8: the samples of this fragment, one row each.
1715///
1716/// Version 1, so that the composition offsets are **signed**. That is the point of the version: a
1717/// version-0 run states them unsigned, so a picture shown before the one decoded before it cannot
1718/// be expressed without shifting the whole track, and [`Sample::off`] is an `i32` exactly because
1719/// the shift is the caller's business and not the container's.
1720///
1721/// The flags are `0x000F01`: the data offset, then a duration, a size, flags and a composition
1722/// offset for every sample. Nothing is defaulted, so nothing depends on a header written earlier.
1723fn trun(off: i32, samples: &[Sample]) -> Outcome<Vec<u8>> {
1724 let mut b = Vec::with_capacity(16 + samples.len() * 16);
1725 b.extend_from_slice(&full(1, 0x0000_0F01));
1726 b.extend_from_slice(&(samples.len() as u32).to_be_bytes());
1727 b.extend_from_slice(&off.to_be_bytes());
1728 for s in samples {
1729 if s.data.len() > u32::MAX as usize {
1730 return Err(err!(
1731 "A sample of {} bytes will not fit the 32-bit size a track run states.",
1732 s.data.len();
1733 Invalid, Input, Excessive));
1734 }
1735 b.extend_from_slice(&s.dur.to_be_bytes());
1736 b.extend_from_slice(&(s.data.len() as u32).to_be_bytes());
1737 b.extend_from_slice(&(if s.sync { SAMPLE_SYNC } else { SAMPLE_DELTA }).to_be_bytes());
1738 b.extend_from_slice(&s.off.to_be_bytes());
1739 }
1740 bx(b"trun", &b)
1741}
1742
1743/// The file type box, ISO/IEC 14496-12 §4.3.
1744///
1745/// `isom` as the major brand with a minor version of 512 is what the reference muxers write, and
1746/// the compatible brands list `isom`, `iso2`, `avc1` and `mp41`: a reader that knows only the AVC
1747/// file format, and one that knows only version 1 of MP4, can both see a brand they recognise.
1748/// The third brand names the coding, and naming the wrong one is a false claim.
1749///
1750/// A brand in this list is a statement that the file conforms to that specification, so `avc1` on a
1751/// film coded in HEVC says something untrue about it -- harmlessly to most readers, and the sort of
1752/// untruth a strict one is entitled to refuse. ffmpeg agrees it matters: for a whole-file HEVC film
1753/// it writes `isom iso2 mp41` and drops `avc1`, which it does include for H.264.
1754fn ftyp(codec: &Codec) -> Outcome<Vec<u8>> {
1755 let mut b = Vec::with_capacity(24);
1756 b.extend_from_slice(b"isom");
1757 b.extend_from_slice(&512u32.to_be_bytes());
1758 b.extend_from_slice(b"isom");
1759 b.extend_from_slice(b"iso2");
1760 match codec {
1761 Codec::Avc(_) => b.extend_from_slice(b"avc1"),
1762 Codec::Hevc(_) => b.extend_from_slice(b"hvc1"),
1763 // Sound alone claims no picture coding, and the brand count changes with
1764 // it rather than a placeholder being written.
1765 Codec::Aac(_) => {},
1766 }
1767 b.extend_from_slice(b"mp41");
1768 bx(b"ftyp", &b)
1769}
1770
1771/// The handler reference, ISO/IEC 14496-12 §8.4.3, declaring a visual track.
1772///
1773/// The trailing name is a null-terminated UTF-8 string. A counted string is written there by some
1774/// tools, following an older convention, and a reader that takes the specification at its word then
1775/// shows the count byte as the first character of the name.
1776fn hdlr() -> Outcome<Vec<u8>> {
1777 handler(b"vide", "VideoHandler")
1778}
1779
1780/// The handler reference for a track of the given kind.
1781///
1782/// `vide` for a picture and `soun` for sound, which is the field a reader uses to decide which
1783/// media header to expect and how to present the track at all.
1784fn handler(kind: &[u8; 4], name: &str) -> Outcome<Vec<u8>> {
1785 let mut b = Vec::with_capacity(32 + name.len());
1786 b.extend_from_slice(&full(0, 0));
1787 b.extend_from_slice(&0u32.to_be_bytes()); // Pre-defined.
1788 b.extend_from_slice(kind);
1789 b.extend_from_slice(&[0u8; 12]); // Reserved.
1790 b.extend_from_slice(name.as_bytes());
1791 b.push(0);
1792 bx(b"hdlr", &b)
1793}
1794
1795/// The sound media header, ISO/IEC 14496-12 §8.4.5.3.
1796///
1797/// The counterpart of [`vmhd`], and a track carries exactly one of the two: which one is what
1798/// `hdlr` has just declared, and a reader meeting the wrong one has been told two different things
1799/// about the same track.
1800fn smhd() -> Outcome<Vec<u8>> {
1801 let mut b = Vec::with_capacity(8);
1802 b.extend_from_slice(&full(0, 0));
1803 b.extend_from_slice(&0u16.to_be_bytes()); // Balance: centre.
1804 b.extend_from_slice(&0u16.to_be_bytes()); // Reserved.
1805 bx(b"smhd", &b)
1806}
1807
1808/// The video media header, ISO/IEC 14496-12 §8.4.5.2.
1809///
1810/// Its flags must be 1, which the specification states outright and gives no meaning for; a zero
1811/// there is rejected by some readers.
1812fn vmhd() -> Outcome<Vec<u8>> {
1813 let mut b = Vec::with_capacity(12);
1814 b.extend_from_slice(&full(0, 1));
1815 b.extend_from_slice(&0u16.to_be_bytes()); // Graphics mode: copy.
1816 b.extend_from_slice(&[0u8; 6]); // Operation colour, unused by copy.
1817 bx(b"vmhd", &b)
1818}
1819
1820/// The data information box: where the media of this track is to be found.
1821///
1822/// One `url ` entry with the self-contained flag set, meaning the media is in this file. The
1823/// four-character code has a trailing space, which is not a typographic accident.
1824fn dinf() -> Outcome<Vec<u8>> {
1825 let url = res!(bx(b"url ", &full(0, 1)));
1826 let mut dref = Vec::with_capacity(8 + url.len());
1827 dref.extend_from_slice(&full(0, 0));
1828 dref.extend_from_slice(&1u32.to_be_bytes()); // Entry count.
1829 dref.extend_from_slice(&url);
1830 let dref = res!(bx(b"dref", &dref));
1831 bx(b"dinf", &dref)
1832}
1833
1834/// The sample to chunk table, ISO/IEC 14496-12 §8.7.4, for one sample a chunk.
1835///
1836/// A single entry: from chunk 1 onward, one sample a chunk, described by sample description 1.
1837/// Entries are only written where the run changes, so one entry covers every chunk in the track.
1838/// Works out each sample's composition offset from the times a source container states.
1839///
1840/// # Why a caller needs this at all
1841///
1842/// Matroska, and the other containers a film arrives in, state **only when a picture is shown**.
1843/// MP4 states when it is decoded and how long after that it is shown. The decoding times are
1844/// already fixed by the durations the caller is writing -- sample `i` is decoded after the sum of
1845/// the durations before it -- so the offset is the difference, and this computes it.
1846///
1847/// `times` are presentation times **in decode order**, which is the order the frames come out of a
1848/// container and the order they must be written in, in whatever unit the durations are given in.
1849///
1850/// # They must be relative to the track's start, and this does not rebase them
1851///
1852/// A composition offset is the distance between a picture's decoding and its showing, and it is
1853/// meant to be a handful of frames. Decoding here begins at nought, so handing this the *absolute*
1854/// times of a film that starts an hour in gives every sample an offset of an hour: representable,
1855/// wrong in meaning, and the sort of thing that plays correctly on the machine that wrote it and
1856/// puzzles everything else. Subtract the first sample's time before calling, and put where the
1857/// track actually begins in [`Stream::start`], which is what that field is for.
1858///
1859/// This deliberately does **not** rebase, because it cannot tell the two cases apart: the smallest
1860/// raw difference is a real measurement when a track begins at nought, and rebasing on it would
1861/// quietly discard a genuine reordering delay.
1862///
1863/// # The shift, and why the whole track moves
1864///
1865/// A picture may be shown *before* a later-decoded picture that precedes it in decode order, so the
1866/// raw difference is negative for the pictures at the head of a reordered run: they are decoded
1867/// early precisely so the ones they are shown between can refer to them. A negative offset says a
1868/// picture is shown before it is decoded, which is not something a decoder can do.
1869///
1870/// So every offset is raised by one constant -- the largest shortfall -- which delays the whole
1871/// track by that much and leaves the intervals between pictures exactly as they were. Nothing about
1872/// the film changes but the instant it starts, by a few frames.
1873pub fn composition_offsets(times: &[i64], durs: &[u32]) -> Outcome<Vec<i32>> {
1874 if times.len() != durs.len() {
1875 return Err(err!(
1876 "There are {} presentation times and {} durations, and each sample needs one of each.",
1877 times.len(), durs.len();
1878 Invalid, Input, Mismatch));
1879 }
1880 let mut raw = Vec::with_capacity(times.len());
1881 let mut dts = 0i64;
1882 let mut least = 0i64;
1883 for (i, t) in times.iter().enumerate() {
1884 let d = t - dts;
1885 if d < least {
1886 least = d;
1887 }
1888 raw.push(d);
1889 dts += durs[i] as i64;
1890 }
1891 let mut out = Vec::with_capacity(raw.len());
1892 for d in raw {
1893 let v = d - least;
1894 if v > i32::MAX as i64 {
1895 return Err(err!(
1896 "A composition offset of {} ticks will not fit the 32 bits the table holds, so the \
1897 presentation times given are not those of one film.", v;
1898 Invalid, Input, Excessive));
1899 }
1900 out.push(v as i32);
1901 }
1902 Ok(out)
1903}
1904
1905fn stsc() -> Outcome<Vec<u8>> {
1906 let mut b = Vec::with_capacity(20);
1907 b.extend_from_slice(&full(0, 0));
1908 b.extend_from_slice(&1u32.to_be_bytes()); // Entry count.
1909 b.extend_from_slice(&1u32.to_be_bytes()); // First chunk; one-based.
1910 b.extend_from_slice(&1u32.to_be_bytes()); // Samples a chunk.
1911 b.extend_from_slice(&1u32.to_be_bytes()); // Sample description index; one-based.
1912 bx(b"stsc", &b)
1913}
1914
1915/// Wraps a payload in a box header: a 32-bit size covering the whole box, then its four-character
1916/// type. ISO/IEC 14496-12 §4.2.
1917fn bx(kind: &[u8; 4], body: &[u8]) -> Outcome<Vec<u8>> {
1918 let size = body.len() + 8;
1919 if size > u32::MAX as usize {
1920 return Err(err!(
1921 "The '{}' box comes to {} bytes, which will not fit the 32-bit size a box header \
1922 carries; only 'mdat' is written in the 64-bit form.",
1923 String::from_utf8_lossy(kind), size;
1924 Invalid, Input, Excessive));
1925 }
1926 let mut out = Vec::with_capacity(size);
1927 out.extend_from_slice(&(size as u32).to_be_bytes());
1928 out.extend_from_slice(kind);
1929 out.extend_from_slice(body);
1930 Ok(out)
1931}
1932
1933/// The version and flags a full box begins with: one byte of version, then three of flags. ISO/IEC
1934/// 14496-12 §4.2.
1935fn full(ver: u8, flags: u32) -> [u8; 4] {
1936 let f = flags.to_be_bytes();
1937 [ver, f[1], f[2], f[3]]
1938}
1939
1940/// A duration counted in one timescale, expressed in another, rounded to nearest.
1941fn rescale(ticks: u64, from: u32, to: u32) -> Outcome<u64> {
1942 if from == 0 {
1943 return Err(err!("A duration cannot be rescaled from a timescale of zero."; Invalid, Input));
1944 }
1945 let n = (ticks as u128) * (to as u128) + (from as u128) / 2;
1946 Ok((n / from as u128) as u64)
1947}
1948
1949/// The raw byte sequence payload of a NAL unit: its body with the emulation prevention bytes taken
1950/// out, so that a `00 00 03` written to keep a start code out of the stream reads back as the
1951/// `00 00` it stands for. ITU-T H.264 §7.4.1.
1952fn rbsp(nal: &[u8]) -> Vec<u8> {
1953 let mut out = Vec::with_capacity(nal.len());
1954 let mut zeros = 0usize;
1955 for &b in nal {
1956 if zeros >= 2 && b == 0x03 {
1957 zeros = 0;
1958 continue;
1959 }
1960 out.push(b);
1961 zeros = if b == 0 { zeros + 1 } else { 0 };
1962 }
1963 out
1964}
1965
1966/// A reader of the bits of an RBSP, most significant first, which is how H.264 codes its syntax
1967/// elements.
1968struct Bits<'a> {
1969 buf: &'a [u8],
1970 pos: usize, // the next bit, counted from the first bit of the first byte
1971}
1972
1973impl<'a> Bits<'a> {
1974
1975 fn new(buf: &'a [u8]) -> Self {
1976 Self { buf, pos: 0 }
1977 }
1978
1979 /// The next `n` bits as an unsigned integer, most significant first.
1980 fn u(&mut self, n: usize) -> Outcome<u32> {
1981 if n > 32 {
1982 return Err(err!("A field of {} bits was asked for, and 32 is the widest.", n; Bug));
1983 }
1984 let mut v = 0u32;
1985 for _ in 0..n {
1986 let byte = self.pos >> 3;
1987 if byte >= self.buf.len() {
1988 return Err(err!(
1989 "The sequence parameter set ends after {} bits, before its frame geometry was \
1990 read.", self.buf.len() * 8;
1991 Invalid, Input, Decode));
1992 }
1993 let bit = (self.buf[byte] >> (7 - (self.pos & 7))) & 1;
1994 v = (v << 1) | bit as u32;
1995 self.pos += 1;
1996 }
1997 Ok(v)
1998 }
1999
2000 fn flag(&mut self) -> Outcome<bool> {
2001 Ok(res!(self.u(1)) == 1)
2002 }
2003
2004 /// An unsigned Exp-Golomb code, ITU-T H.264 §9.1.
2005 fn ue(&mut self) -> Outcome<u32> {
2006 let mut zeros = 0usize;
2007 while res!(self.u(1)) == 0 {
2008 zeros += 1;
2009 if zeros > 31 {
2010 return Err(err!(
2011 "An Exp-Golomb code in the sequence parameter set is prefixed by more than 31 \
2012 zeroes, which no legal value is.";
2013 Invalid, Input, Decode));
2014 }
2015 }
2016 if zeros == 0 {
2017 return Ok(0);
2018 }
2019 let rest = res!(self.u(zeros)) as u64;
2020 let v = (1u64 << zeros) - 1 + rest;
2021 if v > u32::MAX as u64 {
2022 return Err(err!(
2023 "An Exp-Golomb code in the sequence parameter set decodes to {}, beyond what any \
2024 of its fields may hold.", v;
2025 Invalid, Input, Decode));
2026 }
2027 Ok(v as u32)
2028 }
2029
2030 /// A signed Exp-Golomb code, ITU-T H.264 §9.1.1.
2031 fn se(&mut self) -> Outcome<i32> {
2032 let k = res!(self.ue());
2033 let m = ((k as i64 + 1) / 2) as i32;
2034 Ok(if k % 2 == 1 { m } else { -m })
2035 }
2036}
2037
2038/// Steps over a scaling list without keeping it, ITU-T H.264 §7.3.2.1.1.1.
2039///
2040/// The list has to be walked rather than skipped by a byte count, because it is coded as a run of
2041/// variable-length differences and its end is only found by decoding all of them.
2042fn skip_scaling_list(b: &mut Bits, size: usize) -> Outcome<()> {
2043 let mut last = 8i32;
2044 let mut next = 8i32;
2045 for _ in 0..size {
2046 if next != 0 {
2047 let delta = res!(b.se());
2048 next = (last + delta + 256).rem_euclid(256);
2049 }
2050 last = if next == 0 { last } else { next };
2051 }
2052 Ok(())
2053}
2054
2055/// The frame width and height coded in a sequence parameter set, in pixels.
2056///
2057/// This reads the geometry and nothing else: the macroblock counts, whether the stream is coded in
2058/// frames or in fields, and the cropping window. It is not a decoder and does not become one -- the
2059/// point of it is that the caller's declared dimensions can be checked against the stream's own,
2060/// rather than written into the container on trust.
2061///
2062/// The frame is `(pic_width_in_mbs_minus1 + 1) * 16` wide before cropping, and
2063/// `(2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * 16` high, and the crop
2064/// offsets are then subtracted in units of the chroma sampling, per ITU-T H.264 §7.4.2.1.1.
2065fn sps_geometry(sps: &[u8]) -> Outcome<(u16, u16)> {
2066 if sps.is_empty() {
2067 return Err(err!("The sequence parameter set is empty."; Invalid, Input, Missing));
2068 }
2069 let kind = sps[0] & 0x1F;
2070 if kind != 7 {
2071 return Err(err!(
2072 "The first parameter set in the decoder configuration is NAL unit type {}, and a \
2073 sequence parameter set is type 7.", kind;
2074 Invalid, Input, Mismatch));
2075 }
2076 let body = rbsp(&sps[1..]);
2077 let mut b = Bits::new(&body);
2078
2079 let profile = res!(b.u(8));
2080 let _constraints = res!(b.u(8));
2081 let _level = res!(b.u(8));
2082 let _sps_id = res!(b.ue());
2083
2084 // The profiles that carry a chroma format and scaling lists in the parameter set, ITU-T H.264
2085 // §7.3.2.1.1. Every other profile is 4:2:0 with no lists.
2086 let mut chroma = 1u32;
2087 let mut separate_planes = false;
2088 if matches!(profile, 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135) {
2089 chroma = res!(b.ue());
2090 if chroma == 3 {
2091 separate_planes = res!(b.flag());
2092 }
2093 let _bit_depth_luma = res!(b.ue());
2094 let _bit_depth_chroma = res!(b.ue());
2095 let _qpprime_bypass = res!(b.flag());
2096 if res!(b.flag()) {
2097 let lists = if chroma != 3 { 8 } else { 12 };
2098 for i in 0..lists {
2099 if res!(b.flag()) {
2100 res!(skip_scaling_list(&mut b, if i < 6 { 16 } else { 64 }));
2101 }
2102 }
2103 }
2104 }
2105
2106 let _log2_max_frame_num = res!(b.ue());
2107 let poc_type = res!(b.ue());
2108 match poc_type {
2109 0 => {
2110 let _log2_max_poc_lsb = res!(b.ue());
2111 },
2112 1 => {
2113 let _delta_always_zero = res!(b.flag());
2114 let _offset_non_ref = res!(b.se());
2115 let _offset_top_bottom = res!(b.se());
2116 let cycle = res!(b.ue());
2117 if cycle > 255 {
2118 return Err(err!(
2119 "The sequence parameter set names {} entries in its picture order count cycle, \
2120 and 255 is the most allowed.", cycle;
2121 Invalid, Input, Decode));
2122 }
2123 for _ in 0..cycle {
2124 let _offset = res!(b.se());
2125 }
2126 },
2127 2 => {},
2128 other => return Err(err!(
2129 "The sequence parameter set names picture order count type {}, and 0, 1 and 2 are the \
2130 only ones defined.", other;
2131 Invalid, Input, Decode)),
2132 }
2133
2134 let _max_ref_frames = res!(b.ue());
2135 let _gaps_allowed = res!(b.flag());
2136 let mbs_wide = res!(b.ue()) as u64 + 1;
2137 let map_units_high = res!(b.ue()) as u64 + 1;
2138 let frame_mbs_only = res!(b.flag());
2139 if !frame_mbs_only {
2140 let _mb_adaptive = res!(b.flag());
2141 }
2142 let _direct_8x8 = res!(b.flag());
2143
2144 let (mut left, mut right, mut top, mut bottom) = (0u64, 0u64, 0u64, 0u64);
2145 if res!(b.flag()) {
2146 left = res!(b.ue()) as u64;
2147 right = res!(b.ue()) as u64;
2148 top = res!(b.ue()) as u64;
2149 bottom = res!(b.ue()) as u64;
2150 }
2151
2152 // The crop offsets are counted in chroma samples, so they scale by the chroma subsampling.
2153 // Monochrome, and a stream whose colour planes are coded separately, crop in luma samples.
2154 let (sub_w, sub_h) = match chroma {
2155 0 => (1u64, 1u64),
2156 1 => (2, 2),
2157 2 => (2, 1),
2158 3 => (1, 1),
2159 other => return Err(err!(
2160 "The sequence parameter set names chroma format {}, and 0 to 3 are the only ones \
2161 defined.", other;
2162 Invalid, Input, Decode)),
2163 };
2164 let (crop_x, crop_y) = if chroma == 0 || separate_planes {
2165 (1u64, if frame_mbs_only { 1 } else { 2 })
2166 } else {
2167 (sub_w, sub_h * if frame_mbs_only { 1 } else { 2 })
2168 };
2169
2170 let raw_w = mbs_wide * 16;
2171 let raw_h = map_units_high * 16 * if frame_mbs_only { 1 } else { 2 };
2172 let cut_w = crop_x * (left + right);
2173 let cut_h = crop_y * (top + bottom);
2174 if cut_w >= raw_w || cut_h >= raw_h {
2175 return Err(err!(
2176 "The sequence parameter set crops {} by {} coded pixels down to nothing, taking {} \
2177 from the width and {} from the height.", raw_w, raw_h, cut_w, cut_h;
2178 Invalid, Input, Range));
2179 }
2180 let w = raw_w - cut_w;
2181 let h = raw_h - cut_h;
2182 if w > u16::MAX as u64 || h > u16::MAX as u64 {
2183 return Err(err!(
2184 "The sequence parameter set codes a frame of {} by {} pixels, beyond what a visual \
2185 sample entry can state.", w, h;
2186 Invalid, Input, Excessive));
2187 }
2188 Ok((w as u16, h as u16))
2189}
2190
2191// ------------------------------------------------------------------------- reading a film
2192
2193const MAX_DEPTH: usize = 16; // the deepest a box tree may nest before it is called a mistake
2194
2195/// Which codec a track's samples are coded in, as its sample entry names it.
2196///
2197/// An enum rather than the four-character code, so that a caller matches on a thing the reader has
2198/// already recognised rather than on a byte string of its own.
2199#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2200pub enum Kind {
2201 Avc, // H.264, described by an avcC record
2202 Hevc, // HEVC, described by an hvcC record
2203 Mjpeg, // every sample a whole JPEG, with no configuration record at all
2204 Other([u8; 4]), // carries its code so that a refusal can name it
2205}
2206
2207impl Kind {
2208
2209 /// The codec a sample entry's four-character code names.
2210 fn of(code: [u8; 4]) -> Self {
2211 match &code {
2212 // `avc1` carries its parameter sets in the configuration record only; `avc3` may also
2213 // carry them in the samples. Both are read the same way here, because the sample is
2214 // walked for parameter sets in either case.
2215 b"avc1" | b"avc3" => Self::Avc,
2216 b"hvc1" | b"hev1" => Self::Hevc,
2217 b"jpeg" | b"mjpa" | b"mjpb" => Self::Mjpeg,
2218 _ => Self::Other(code),
2219 }
2220 }
2221}
2222
2223/// One video track of a film, as its sample table describes it.
2224///
2225/// This is the reading half of this module, and it exists for one job: telling a decoder where a
2226/// film's first coded picture is. It holds an **index and not the film**: the sample table of a
2227/// four-gigabyte film is a few tens of kilobytes, and a caller that wants one frame of it should
2228/// never have to hold the other four gigabytes to get it. So the samples are spans, and the bytes
2229/// they name are the caller's to fetch.
2230#[derive(Clone, Debug)]
2231pub struct Film {
2232 kind: Kind, // which codec the track is coded in
2233 config: Vec<u8>, // the configuration record, where the codec has one
2234 width: u16, // the coded width the sample entry declares
2235 height: u16, // and the coded height
2236 rotation: u16, // how far to turn the picture, degrees clockwise
2237 aperture: Option<(u32, u32, u32, u32)>, // left, top, width, height of the real picture
2238 samples: Vec<(u64, u32)>, // each sample's offset in the file and its length
2239 // Which samples a reader may begin decoding at, as stss lists them, counted from nought.
2240 // Empty means the box was absent, which per ISO/IEC 14496-12 §8.6.2 means every sample is a
2241 // sync sample -- the opposite of what an empty list would otherwise suggest, and the reason
2242 // this is not an Option the caller has to remember to check.
2243 sync: Vec<u32>,
2244}
2245
2246impl Film {
2247
2248 /// Reads a film's first video track out of a whole file.
2249 ///
2250 /// A file with no video track, or with one whose sample table is incomplete, is refused: a
2251 /// track whose samples cannot be located is not a track a picture can be drawn from.
2252 pub fn read(bytes: &[u8]) -> Outcome<Self> {
2253 let mut at = 0usize;
2254 while at + 8 <= bytes.len() {
2255 let (size, head) = res!(box_head(bytes, at, bytes.len()));
2256 if &bytes[at + 4..at + 8] == b"moov" {
2257 return match res!(movie(bytes, at + head, at + size)) {
2258 Some(f) => Ok(f),
2259 None => Err(err!(
2260 "The file's movie box carries no video track. A film needs a track whose \
2261 handler is `vide`.";
2262 Invalid, Input, Missing)),
2263 };
2264 }
2265 at += size;
2266 }
2267 Err(err!(
2268 "The file carries no `moov` box, so nothing says where its samples are.";
2269 Invalid, Input, Missing))
2270 }
2271
2272 /// The same, from a `moov` box a caller has lifted out of a file on its own.
2273 ///
2274 /// This is what a caller with a file handle rather than a buffer uses: the chunk offsets in
2275 /// `stco` are absolute file offsets, so the index does not depend on where the movie box itself
2276 /// sat, and a film of any size can be indexed by reading its metadata alone. QuickTime writes
2277 /// `moov` at the end of the file as often as at the front, so this is not a rare path.
2278 pub fn from_moov(moov: &[u8]) -> Outcome<Self> {
2279 match res!(movie(moov, 0, moov.len())) {
2280 Some(f) => Ok(f),
2281 None => Err(err!(
2282 "The movie box carries no video track. A film needs a track whose handler is \
2283 `vide`.";
2284 Invalid, Input, Missing)),
2285 }
2286 }
2287
2288 pub fn kind(&self) -> Kind {
2289 self.kind
2290 }
2291
2292 /// The decoder configuration record out of the sample entry: `avcC` or `hvcC`.
2293 pub fn config(&self) -> &[u8] {
2294 &self.config
2295 }
2296
2297 /// The coded size the sample entry declares, which is not the cropped size the parameter set
2298 /// implies and should not be shown as though it were.
2299 pub fn size(&self) -> (u16, u16) {
2300 (self.width, self.height)
2301 }
2302
2303 /// How far the picture is to be turned before it is shown: 0, 90, 180 or 270 degrees clockwise.
2304 ///
2305 /// A phone writes the angle it was held at into the track header's transformation matrix rather
2306 /// than turning the samples, so a decoder's output is the picture as it was *coded* and this is
2307 /// what a viewer must do with it. Ignoring it shows a great many holiday films on their side.
2308 /// It also hides itself well at ninety degrees, where the turned picture has exactly as many
2309 /// samples as the untured one.
2310 pub fn rotation(&self) -> u16 {
2311 self.rotation
2312 }
2313
2314 /// The rectangle of the coded picture that is actually the picture: left, top, width, height.
2315 ///
2316 /// `None` where the track states none, which means the whole of it. A phone stabilises a film
2317 /// by coding a picture larger than it shows and moving a window about inside it; the window is
2318 /// the clean aperture, and a viewer that ignores it shows about nine per cent more of the
2319 /// frame than the film means to show, wobbling margin and all.
2320 pub fn aperture(&self) -> Option<(u32, u32, u32, u32)> {
2321 self.aperture
2322 }
2323
2324 pub fn samples(&self) -> usize {
2325 self.samples.len()
2326 }
2327
2328 /// Where one sample sits in the file, and how long it is.
2329 pub fn span(&self, i: usize) -> Outcome<(u64, u32)> {
2330 match self.samples.get(i) {
2331 Some(s) => Ok(*s),
2332 None => Err(err!(
2333 "Sample {} was asked for and the track holds {}.", i, self.samples.len();
2334 Invalid, Input, Range)),
2335 }
2336 }
2337
2338 /// One sample's bytes, out of the file the index was read from.
2339 pub fn sample<'b>(&self, bytes: &'b [u8], i: usize) -> Outcome<&'b [u8]> {
2340 let (off, len) = res!(self.span(i));
2341 let from = off as usize;
2342 let to = match from.checked_add(len as usize) {
2343 Some(to) if to <= bytes.len() => to,
2344 _ => return Err(err!(
2345 "Sample {} sits at byte {} and is {} long, in a buffer of {}. A file read in part \
2346 cannot give up its samples.", i, off, len, bytes.len();
2347 Invalid, Input, Decode)),
2348 };
2349 Ok(&bytes[from..to])
2350 }
2351
2352 /// Which sample a decoder may begin at.
2353 ///
2354 /// Almost always the first sample of the track, since a film that cannot be played from its
2355 /// start is a film no player will open, but a track whose `stss` says otherwise is followed
2356 /// rather than assumed about.
2357 pub fn first_sync(&self) -> Outcome<usize> {
2358 match self.sync.first() {
2359 Some(n) => Ok(*n as usize),
2360 // An absent `stss` means every sample is a sync sample.
2361 None if !self.samples.is_empty() => Ok(0),
2362 None => Err(err!("The track holds no samples."; Invalid, Input, Missing)),
2363 }
2364 }
2365
2366 /// Reads a film's first video track out of a file, holding none of the film.
2367 ///
2368 /// This is the form a caller wanting one frame of a large film uses: the top-level boxes are
2369 /// walked by their headers, the `moov` box alone is read, and the handle is left open so that
2370 /// [`Film::read_sample`] can fetch the one sample the index names. A film of four gigabytes
2371 /// costs its metadata, and a caller that cannot hold the file -- which is most callers, since
2372 /// most films are past any sensible buffer -- is not shut out of its first frame.
2373 pub fn of(f: &mut File) -> Outcome<Self> {
2374 let moov = match res!(moov_of(f)) {
2375 Some(m) => m,
2376 None => return Err(err!(
2377 "The file carries no `moov` box, so nothing says where its samples are.";
2378 Invalid, Input, Missing)),
2379 };
2380 Self::from_moov(&moov)
2381 }
2382
2383 /// One sample's bytes, read out of the file the index was read from.
2384 ///
2385 /// The counterpart of [`Film::sample`] for a caller with a handle rather than a buffer. The
2386 /// offsets in a sample table are absolute file offsets, so this needs nothing of where the
2387 /// movie box sat.
2388 pub fn read_sample(&self, f: &mut File, i: usize) -> Outcome<Vec<u8>> {
2389 let (off, len) = res!(self.span(i));
2390 if len > SAMPLE_MAX {
2391 return Err(err!(
2392 "Sample {} says it is {} bytes long, and {} is this reader's ceiling for one \
2393 coded picture.", i, len, SAMPLE_MAX;
2394 Invalid, Input, Excessive));
2395 }
2396 let mut buf = vec![0u8; len as usize];
2397 res!(f.seek(SeekFrom::Start(off)), IO, File);
2398 res!(f.read_exact(&mut buf), IO, File);
2399 Ok(buf)
2400 }
2401
2402 /// The bytes of the first sample a decoder may begin at.
2403 ///
2404 /// The one call a poster frame needs: which sample to start at, and its bytes.
2405 pub fn read_first_sync(&self, f: &mut File) -> Outcome<Vec<u8>> {
2406 let i = res!(self.first_sync());
2407 self.read_sample(f, i)
2408 }
2409}
2410
2411// ------------------------------------------------------------- a film's index, out of a file
2412
2413// The most bytes a movie box may occupy before the file is called a mistake. A moov is an index
2414// and not media: the sample tables of a track at this reader's ceiling of a million samples come
2415// to a few tens of megabytes, and anything past this is a length field read out of the wrong place
2416// rather than a film.
2417pub const MOOV_MAX: u64 = 64 * 1024 * 1024;
2418
2419// The most bytes one sample may occupy: one coded picture. A 4K intra frame is a few megabytes;
2420// this is a ceiling against a length that is a mistake, since the length is what a buffer is sized
2421// from.
2422pub const SAMPLE_MAX: u32 = 64 * 1024 * 1024;
2423
2424// how much of a movie header is read back, more than either version of the box occupies
2425pub const MVHD_BYTES: u64 = 256;
2426
2427const MAX_BOXES: usize = 4096; // the most boxes walked at one level looking for one of them
2428
2429/// The body of the first box of a given type between two offsets in a file, as its offset and its
2430/// length.
2431///
2432/// **Only the box headers are read**: eight bytes each, or the sixteen a 64-bit length needs. An
2433/// `mdat` holding two gigabytes of film is stepped over by its declared length and never touched,
2434/// which is what makes finding a film's index affordable on a file nobody wants in memory.
2435///
2436/// A length that does not fit inside the range being walked ends the walk and answers `None`
2437/// rather than failing. A file truncated in transfer is a thing to report absence for, and the
2438/// caller asking this question has a plain answer for absence: the box is not there.
2439pub fn find_box(f: &mut File, want: &[u8; 4], from: u64, to: u64)
2440 -> Outcome<Option<(u64, u64)>>
2441{
2442 let mut at = from;
2443 for _ in 0..MAX_BOXES {
2444 if at + 8 > to {
2445 return Ok(None);
2446 }
2447 res!(f.seek(SeekFrom::Start(at)), IO, File);
2448 let mut head = [0u8; 16];
2449 if res!(fill(f, &mut head[..8])) != 8 {
2450 return Ok(None);
2451 }
2452 let size = u32::from_be_bytes([head[0], head[1], head[2], head[3]]) as u64;
2453 let mut kind = [0u8; 4];
2454 kind.copy_from_slice(&head[4..8]);
2455 // A size of nought means the box runs to the end of its parent; a size of one means the
2456 // real length is the eight bytes after the type (ISO/IEC 14496-12 §4.2).
2457 let (body, next) = match size {
2458 0 => (at + 8, to),
2459 1 => {
2460 if res!(fill(f, &mut head[8..16])) != 8 {
2461 return Ok(None);
2462 }
2463 let mut wide = [0u8; 8];
2464 wide.copy_from_slice(&head[8..16]);
2465 let wide = u64::from_be_bytes(wide);
2466 if wide < 16 {
2467 return Ok(None);
2468 }
2469 (at + 16, at.saturating_add(wide))
2470 },
2471 n if n < 8 => return Ok(None),
2472 n => (at + 8, at.saturating_add(n)),
2473 };
2474 if next > to || next <= at || body > next {
2475 return Ok(None);
2476 }
2477 if &kind == want {
2478 return Ok(Some((body, next - body)));
2479 }
2480 at = next;
2481 }
2482 Ok(None)
2483}
2484
2485/// The body of a film's movie box, lifted out of a file.
2486///
2487/// What comes back is the box's **children**, which is what [`Film::from_moov`] reads. QuickTime
2488/// writes `moov` at the end of a file as often as at the front, and either is reached by the same
2489/// walk over the top-level headers.
2490pub fn moov_of(f: &mut File) -> Outcome<Option<Vec<u8>>> {
2491 let end = res!(f.metadata(), IO, File).len();
2492 let (body, len) = match res!(find_box(f, b"moov", 0, end)) {
2493 Some(span) => span,
2494 None => return Ok(None),
2495 };
2496 if len > MOOV_MAX {
2497 return Err(err!(
2498 "A movie box of {} bytes, and {} is this reader's ceiling. A `moov` is an index and \
2499 not media.", len, MOOV_MAX;
2500 Invalid, Input, Excessive));
2501 }
2502 let mut buf = vec![0u8; len as usize];
2503 res!(f.seek(SeekFrom::Start(body)), IO, File);
2504 res!(f.read_exact(&mut buf), IO, File);
2505 Ok(Some(buf))
2506}
2507
2508/// The payload of a film's movie header, lifted out of a file.
2509///
2510/// The header is `moov`'s first child and carries the timescale, the duration and the times the
2511/// film was recorded and last changed. Reaching it costs a handful of eight-byte reads and as many
2512/// seeks, and it is deliberately not the whole of `moov`: a caller asking only how long a film runs
2513/// should not read a long film's sample tables to find out.
2514pub fn mvhd_of(f: &mut File) -> Outcome<Option<Vec<u8>>> {
2515 let end = res!(f.metadata(), IO, File).len();
2516 let (moov, moov_len) = match res!(find_box(f, b"moov", 0, end)) {
2517 Some(span) => span,
2518 None => return Ok(None),
2519 };
2520 let (body, len) = match res!(find_box(f, b"mvhd", moov, moov + moov_len)) {
2521 Some(span) => span,
2522 None => return Ok(None),
2523 };
2524 let take = len.min(MVHD_BYTES) as usize;
2525 res!(f.seek(SeekFrom::Start(body)), IO, File);
2526 let mut buf = vec![0u8; take];
2527 let got = res!(fill(f, &mut buf));
2528 buf.truncate(got);
2529 Ok(Some(buf))
2530}
2531
2532/// The timescale and the duration a movie header carries: ticks a second, and ticks.
2533///
2534/// The two are only meaningful together, since the header counts in units of its own choosing.
2535/// Version 1 of the box widens both the times and the duration while the timescale stays 32 bits in
2536/// both. A timescale of nought, a duration of nought, and the all-ones a writer that did not know
2537/// the duration leaves behind are all absence rather than numbers to divide.
2538pub fn movie_ticks(mvhd: &[u8]) -> Option<(u32, u64)> {
2539 let (scale, ticks) = match mvhd.first() {
2540 Some(0) => {
2541 if mvhd.len() < 20 {
2542 return None;
2543 }
2544 let scale = u32::from_be_bytes([mvhd[12], mvhd[13], mvhd[14], mvhd[15]]);
2545 let ticks = u32::from_be_bytes([mvhd[16], mvhd[17], mvhd[18], mvhd[19]]);
2546 if ticks == u32::MAX {
2547 return None;
2548 }
2549 (scale, ticks as u64)
2550 },
2551 Some(1) => {
2552 if mvhd.len() < 32 {
2553 return None;
2554 }
2555 let scale = u32::from_be_bytes([mvhd[20], mvhd[21], mvhd[22], mvhd[23]]);
2556 let mut wide = [0u8; 8];
2557 wide.copy_from_slice(&mvhd[24..32]);
2558 let ticks = u64::from_be_bytes(wide);
2559 if ticks == u64::MAX {
2560 return None;
2561 }
2562 (scale, ticks)
2563 },
2564 _ => return None,
2565 };
2566 if scale == 0 || ticks == 0 {
2567 None
2568 } else {
2569 Some((scale, ticks))
2570 }
2571}
2572
2573/// Reads until the buffer is full or the file ends, answering how many bytes arrived.
2574///
2575/// A single `read` may come back short of what was asked for without anything being wrong, and a
2576/// box header read short by one byte is a film refused for nothing.
2577fn fill(f: &mut File, buf: &mut [u8]) -> Outcome<usize> {
2578 let mut got = 0usize;
2579 while got < buf.len() {
2580 match res!(f.read(&mut buf[got..]), IO, File) {
2581 0 => break,
2582 n => got += n,
2583 }
2584 }
2585 Ok(got)
2586}
2587
2588/// Reads a box header, giving its whole length and the length of the header itself.
2589fn box_head(bytes: &[u8], at: usize, to: usize) -> Outcome<(usize, usize)> {
2590 if at + 8 > to {
2591 return Err(err!("A box header runs past the end of its parent."; Invalid, Input, Decode));
2592 }
2593 let size = u32::from_be_bytes([bytes[at], bytes[at + 1], bytes[at + 2], bytes[at + 3]]);
2594 let (size, head) = match size {
2595 // A size of one means the real one is the next eight bytes (ISO/IEC 14496-12 §4.2).
2596 1 => {
2597 if at + 16 > to {
2598 return Err(err!(
2599 "A box says its length is sixty-four bits and its parent ends inside it.";
2600 Invalid, Input, Decode));
2601 }
2602 let mut wide = [0u8; 8];
2603 wide.copy_from_slice(&bytes[at + 8..at + 16]);
2604 (u64::from_be_bytes(wide) as usize, 16usize)
2605 },
2606 // A size of zero means the box runs to the end of its parent.
2607 0 => (to - at, 8usize),
2608 n => (n as usize, 8usize),
2609 };
2610 if size < head || at.saturating_add(size) > to {
2611 return Err(err!(
2612 "A {} box at byte {} says it is {} bytes long, and its parent ends at {}.",
2613 String::from_utf8_lossy(&bytes[at + 4..at + 8]), at, size, to;
2614 Invalid, Input, Decode));
2615 }
2616 Ok((size, head))
2617}
2618
2619/// Walks the children of a box, handing each one's four-character code and body to a visitor.
2620///
2621/// The visitor answers whether the walk should descend into it. Every box is length-prefixed and
2622/// the lengths have to tile the parent; a box that claims to end beyond its parent is a malformed
2623/// file, and is refused rather than clamped, since clamping turns one wrong length into a
2624/// plausible-looking picture.
2625fn walk<F>(bytes: &[u8], parent: [u8; 4], from: usize, to: usize, depth: usize, visit: &mut F)
2626 -> Outcome<()>
2627where
2628 F: FnMut([u8; 4], [u8; 4], usize, usize) -> Outcome<bool>,
2629{
2630 if depth > MAX_DEPTH {
2631 return Err(err!(
2632 "The box tree nests more than {} deep, which no legal file does.", MAX_DEPTH;
2633 Invalid, Input, Decode));
2634 }
2635 let mut at = from;
2636 while at + 8 <= to {
2637 let (size, head) = res!(box_head(bytes, at, to));
2638 let mut kind = [0u8; 4];
2639 kind.copy_from_slice(&bytes[at + 4..at + 8]);
2640 if res!(visit(kind, parent, at + head, at + size)) {
2641 res!(walk(bytes, kind, at + head, at + size, depth + 1, visit));
2642 }
2643 at += size;
2644 }
2645 Ok(())
2646}
2647
2648/// Reads a four-byte big-endian number out of a box body.
2649fn be32(bytes: &[u8], at: usize) -> Outcome<u32> {
2650 match bytes.get(at..at + 4) {
2651 Some(s) => Ok(u32::from_be_bytes([s[0], s[1], s[2], s[3]])),
2652 None => Err(err!("A box ends inside a four-byte field."; Invalid, Input, Decode)),
2653 }
2654}
2655
2656/// Reads an eight-byte big-endian number out of a box body.
2657fn be64(bytes: &[u8], at: usize) -> Outcome<u64> {
2658 match bytes.get(at..at + 8) {
2659 Some(s) => Ok(u64::from_be_bytes(
2660 [s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]])),
2661 None => Err(err!("A box ends inside an eight-byte field."; Invalid, Input, Decode)),
2662 }
2663}
2664
2665/// The tables one track's sample table holds, before they are turned into sample positions.
2666#[derive(Default)]
2667struct Tables {
2668 handler: [u8; 4], // vide for a video track
2669 stsd: Option<(usize, usize)>, // read once the handler says this is video
2670 kind: Option<Kind>, // the codec, from the sample entry
2671 config: Option<(usize, usize)>, // the configuration record's span in the file
2672 clap: Option<(f64, f64, f64, f64)>, // width, height, offsets of the centre
2673 size: (u16, u16), // the coded size the sample entry declares
2674 sizes: Vec<u32>, // each sample's length in bytes, from stsz
2675 runs: Vec<(u32, u32)>, // (first_chunk, samples_per_chunk) from stsc
2676 chunks: Vec<u64>, // each chunk's offset, from stco or co64
2677 sync: Vec<u32>, // sync sample numbers, from one as stss writes them
2678 rotation: u16, // from the track header's matrix, degrees clockwise
2679}
2680
2681/// Reads the first video track out of a `moov` box.
2682fn movie(bytes: &[u8], from: usize, to: usize) -> Outcome<Option<Film>> {
2683 let mut out: Option<Film> = None;
2684 let mut at = from;
2685 while at + 8 <= to {
2686 let (size, head) = res!(box_head(bytes, at, to));
2687 if &bytes[at + 4..at + 8] == b"trak" {
2688 let mut t = Tables::default();
2689 res!(track(bytes, at + head, at + size, &mut t));
2690 if &t.handler == b"vide" {
2691 if let Some((body, end)) = t.stsd {
2692 res!(sample_description(bytes, body, end, &mut t));
2693 }
2694 out = Some(res!(assemble(bytes, t)));
2695 break;
2696 }
2697 }
2698 at += size;
2699 }
2700 Ok(out)
2701}
2702
2703/// Reads one track's handler and sample table.
2704fn track(bytes: &[u8], from: usize, to: usize, t: &mut Tables) -> Outcome<()> {
2705 walk(bytes, *b"trak", from, to, 0, &mut |kind, parent, body, end| {
2706 match &kind {
2707 b"mdia" | b"minf" | b"stbl" => return Ok(true),
2708 b"hdlr" => {
2709 // version and flags, then a pre-defined word, then the handler type.
2710 //
2711 // **Only the one directly inside `mdia`.** QuickTime puts a second `hdlr` inside
2712 // `minf` naming the *data* handler -- `alis` for a file, `url ` for a reference --
2713 // and a walk that takes whichever it meets last decides a video track is not one.
2714 // That is how a 2003 camcorder's film comes to be refused as having no video in it.
2715 if &parent == b"mdia" {
2716 if let Some(s) = bytes.get(body + 8..body + 12) {
2717 t.handler.copy_from_slice(s);
2718 }
2719 }
2720 },
2721 b"tkhd" => {
2722 t.rotation = rotation_of(&bytes[body..end.min(bytes.len())]);
2723 },
2724 b"stsd" => {
2725 // Not read here. A track's boxes arrive in whatever order the writer chose, and a
2726 // sound track's sample entry is not a visual one; reading every `stsd` as though it
2727 // were refuses a film for the shape of a track nobody asked about.
2728 t.stsd = Some((body, end));
2729 },
2730 b"stsz" => {
2731 let sample_size = res!(be32(bytes, body + 4));
2732 let count = res!(be32(bytes, body + 8)) as usize;
2733 if count > MAX_SAMPLES {
2734 return Err(err!(
2735 "A track holds {} samples, and {} is this reader's ceiling.",
2736 count, MAX_SAMPLES;
2737 Invalid, Input, Excessive));
2738 }
2739 t.sizes = if sample_size != 0 {
2740 vec![sample_size; count]
2741 } else {
2742 let mut v = Vec::with_capacity(count);
2743 for i in 0..count {
2744 v.push(res!(be32(bytes, body + 12 + i * 4)));
2745 }
2746 v
2747 };
2748 },
2749 b"stsc" => {
2750 let count = res!(be32(bytes, body + 4)) as usize;
2751 if count > MAX_SAMPLES {
2752 return Err(err!(
2753 "A sample-to-chunk table holds {} runs, and {} is this reader's ceiling.",
2754 count, MAX_SAMPLES;
2755 Invalid, Input, Excessive));
2756 }
2757 t.runs = Vec::with_capacity(count);
2758 for i in 0..count {
2759 let first = res!(be32(bytes, body + 8 + i * 12));
2760 let per = res!(be32(bytes, body + 12 + i * 12));
2761 t.runs.push((first, per));
2762 }
2763 },
2764 b"stco" | b"co64" => {
2765 let wide = &kind == b"co64";
2766 let count = res!(be32(bytes, body + 4)) as usize;
2767 if count > MAX_SAMPLES {
2768 return Err(err!(
2769 "A chunk offset table holds {} entries, and {} is this reader's ceiling.",
2770 count, MAX_SAMPLES;
2771 Invalid, Input, Excessive));
2772 }
2773 t.chunks = Vec::with_capacity(count);
2774 for i in 0..count {
2775 t.chunks.push(if wide {
2776 res!(be64(bytes, body + 8 + i * 8))
2777 } else {
2778 res!(be32(bytes, body + 8 + i * 4)) as u64
2779 });
2780 }
2781 },
2782 b"stss" => {
2783 let count = res!(be32(bytes, body + 4)) as usize;
2784 if count > MAX_SAMPLES {
2785 return Err(err!(
2786 "A sync sample table holds {} entries, and {} is this reader's ceiling.",
2787 count, MAX_SAMPLES;
2788 Invalid, Input, Excessive));
2789 }
2790 t.sync = Vec::with_capacity(count);
2791 for i in 0..count {
2792 t.sync.push(res!(be32(bytes, body + 8 + i * 4)));
2793 }
2794 },
2795 _ => {},
2796 }
2797 Ok(false)
2798 })
2799}
2800
2801/// How far a track header's transformation matrix turns the picture, in degrees clockwise.
2802///
2803/// A phone writes the angle it was held at here rather than turning the samples, so this is what a
2804/// viewer must do with a decoder's output. The matrix sits at a fixed offset that depends on the
2805/// version -- the version-1 header carries 64-bit times and is twelve bytes longer -- and only the
2806/// four entries that rotate are read, because a matrix that is not a rotation is not something a
2807/// picture library can act on anyway. Anything else answers nought, which shows the picture as it
2808/// was coded.
2809///
2810/// `tkhd` is the box's payload, from its version byte onwards.
2811pub fn rotation_of(tkhd: &[u8]) -> u16 {
2812 let ver = match tkhd.first() {
2813 Some(v) => *v,
2814 None => return 0,
2815 };
2816 let at = if ver == 1 { 52 } else { 40 };
2817 // The matrix is nine values in the order a, b, u, c, d, v, x, y, w (§8.3.2.3), and the four
2818 // that rotate are a, b, c and d -- which are **not** the first four: the projection entry `u`
2819 // sits between b and c. Reading four in a row instead takes `u` for `c`, and since `u` is
2820 // nought in every matrix any camera writes, every rotation then looks like no rotation at all.
2821 let one = 0x0001_0000i32;
2822 let mut m = [0i32; 4];
2823 for (i, off) in [0usize, 4, 12, 16].iter().enumerate() {
2824 m[i] = match tkhd.get(at + off..at + off + 4) {
2825 Some(s) => i32::from_be_bytes([s[0], s[1], s[2], s[3]]),
2826 None => return 0,
2827 };
2828 }
2829 match (m[0], m[1], m[2], m[3]) {
2830 (0, x, y, 0) if x == one && y == -one => 90,
2831 (x, 0, 0, y) if x == -one && y == -one => 180,
2832 (0, x, y, 0) if x == -one && y == one => 270,
2833 _ => 0,
2834 }
2835}
2836
2837/// Reads the first sample entry of a sample description, and the configuration record inside it.
2838fn sample_description(bytes: &[u8], body: usize, end: usize, t: &mut Tables) -> Outcome<()> {
2839 let count = res!(be32(bytes, body + 4));
2840 if count == 0 {
2841 return Ok(());
2842 }
2843 let at = body + 8;
2844 let (size, head) = res!(box_head(bytes, at, end));
2845 let mut code = [0u8; 4];
2846 code.copy_from_slice(&bytes[at + 4..at + 8]);
2847 t.kind = Some(Kind::of(code));
2848 // A visual sample entry: six reserved bytes and a two-byte data reference index, then 70 bytes
2849 // of visual fields, of which the width and height sit at 16 and 18 (ISO/IEC 14496-12 §8.5.2).
2850 let visual = at + head + 8;
2851 if visual + 70 > at + size {
2852 return Err(err!(
2853 "A {} sample entry is too short to be a visual one.", String::from_utf8_lossy(&code);
2854 Invalid, Input, Decode));
2855 }
2856 t.size = (
2857 u16::from_be_bytes([bytes[visual + 16], bytes[visual + 17]]),
2858 u16::from_be_bytes([bytes[visual + 18], bytes[visual + 19]]),
2859 );
2860 // The configuration box sits among the sample entry's own children.
2861 let mut conf = None;
2862 let mut clap: Option<(f64, f64, f64, f64)> = None;
2863 res!(walk(bytes, code, visual + 70, at + size, 0, &mut |kind, _parent, cbody, cend| {
2864 if matches!(&kind, b"avcC" | b"hvcC") && conf.is_none() {
2865 conf = Some((cbody, cend));
2866 }
2867 // The clean aperture: the rectangle of the coded picture that is the picture. A phone
2868 // stabilises a film by coding it larger than it shows and moving the window about inside
2869 // it, and this is where the result is written -- eight rationals, four of which are the
2870 // width and height and four the offset of the window's centre from the picture's
2871 // (ISO/IEC 14496-12 §12.1.4.3).
2872 if &kind == b"clap" && clap.is_none() && cend >= cbody + 32 {
2873 let mut v = [0i64; 8];
2874 for (i, n) in v.iter_mut().enumerate() {
2875 *n = match bytes.get(cbody + i * 4..cbody + i * 4 + 4) {
2876 Some(s) => i32::from_be_bytes([s[0], s[1], s[2], s[3]]) as i64,
2877 None => return Ok(false),
2878 };
2879 }
2880 // The denominators are the odd entries, and a zero one is a box to be ignored rather
2881 // than divided by.
2882 if v[1] != 0 && v[3] != 0 && v[5] != 0 && v[7] != 0 {
2883 clap = Some((
2884 v[0] as f64 / v[1] as f64,
2885 v[2] as f64 / v[3] as f64,
2886 v[4] as f64 / v[5] as f64,
2887 v[6] as f64 / v[7] as f64,
2888 ));
2889 }
2890 }
2891 Ok(false)
2892 }));
2893 t.config = conf;
2894 t.clap = clap;
2895 Ok(())
2896}
2897
2898/// Turns a sample table into the position and length of every sample.
2899fn assemble(bytes: &[u8], t: Tables) -> Outcome<Film> {
2900 let kind = match t.kind {
2901 Some(k) => k,
2902 None => return Err(err!(
2903 "A video track carries no sample description, so nothing says how it is coded.";
2904 Invalid, Input, Missing)),
2905 };
2906 if t.runs.is_empty() || t.chunks.is_empty() {
2907 return Err(err!(
2908 "A video track's sample table has no sample-to-chunk or chunk offset box, so no \
2909 sample can be located.";
2910 Invalid, Input, Missing));
2911 }
2912 // Walk the runs, laying samples into chunks. `stsc` names the first chunk of each run counted
2913 // from one, and a run continues until the next one begins (ISO/IEC 14496-12 §8.7.4).
2914 let mut samples: Vec<(u64, u32)> = Vec::with_capacity(t.sizes.len());
2915 let mut n = 0usize;
2916 for (r, (first, per)) in t.runs.iter().enumerate() {
2917 if *first == 0 {
2918 return Err(err!(
2919 "A sample-to-chunk run begins at chunk 0, and the chunks are counted from one.";
2920 Invalid, Input, Decode));
2921 }
2922 let start = (*first - 1) as usize;
2923 let stop = match t.runs.get(r + 1) {
2924 Some((next, _)) if *next >= 1 => ((*next - 1) as usize).min(t.chunks.len()),
2925 _ => t.chunks.len(),
2926 };
2927 for c in start..stop {
2928 let base = t.chunks[c];
2929 let mut off = base;
2930 for _ in 0..*per {
2931 let len = match t.sizes.get(n) {
2932 Some(l) => *l,
2933 // A chunk table that runs on past the sample sizes is not a fault: the sizes
2934 // are the authority on how many samples there are.
2935 None => break,
2936 };
2937 samples.push((off, len));
2938 off = off.saturating_add(len as u64);
2939 n += 1;
2940 }
2941 }
2942 }
2943 if samples.len() != t.sizes.len() {
2944 return Err(err!(
2945 "A sample table lays out {} samples and names the size of {}. The two disagree, so \
2946 no sample can be trusted to be where the table says.", samples.len(), t.sizes.len();
2947 Invalid, Input, Mismatch));
2948 }
2949 let config = match t.config {
2950 Some((from, to)) => match bytes.get(from..to) {
2951 Some(s) => s.to_vec(),
2952 None => return Err(err!(
2953 "A decoder configuration record runs past the end of the file.";
2954 Invalid, Input, Decode)),
2955 },
2956 // Motion JPEG has none, and needs none.
2957 None => Vec::new(),
2958 };
2959 // `stss` counts from one and everything else here counts from nought.
2960 let mut sync = Vec::with_capacity(t.sync.len());
2961 for s in &t.sync {
2962 if *s == 0 {
2963 return Err(err!(
2964 "A sync sample table names sample 0, and the samples are counted from one.";
2965 Invalid, Input, Decode));
2966 }
2967 sync.push(*s - 1);
2968 }
2969 // The aperture is stated as a size and the offset of its centre from the picture's, so the
2970 // corner it starts at is worked out here rather than by every caller.
2971 let aperture = t.clap.and_then(|(w, h, dx, dy)| {
2972 let (full_w, full_h) = (t.size.0 as f64, t.size.1 as f64);
2973 if w <= 0.0 || h <= 0.0 || w > full_w || h > full_h {
2974 return None;
2975 }
2976 let x = ((full_w - w) / 2.0 + dx).round();
2977 let y = ((full_h - h) / 2.0 + dy).round();
2978 if x < 0.0 || y < 0.0 || x + w > full_w || y + h > full_h {
2979 return None;
2980 }
2981 Some((x as u32, y as u32, w.round() as u32, h.round() as u32))
2982 });
2983 Ok(Film {
2984 kind,
2985 config,
2986 width: t.size.0,
2987 height: t.size.1,
2988 rotation: t.rotation,
2989 aperture,
2990 samples,
2991 sync,
2992 })
2993}
2994
2995#[cfg(test)]
2996mod tests {
2997 use super::*;
2998
2999 #[test]
3000 fn test_a_quarter_turn_in_a_track_header_is_read_00() -> Outcome<()> {
3001 // The four entries that rotate are a, b, c and d, and they are not four in a row: the
3002 // projection entry `u` sits between b and c, and it is nought in every matrix a camera
3003 // writes. A reader that takes four in a row therefore answers "no rotation" for every
3004 // turned film there is, which is what this decoder did until a film held sideways said so.
3005 let one = 0x0001_0000u32;
3006 let neg = (-(one as i32)) as u32;
3007 let head = |a: u32, b: u32, c: u32, d: u32| {
3008 let mut body = vec![0u8; 84];
3009 body[40..44].copy_from_slice(&a.to_be_bytes());
3010 body[44..48].copy_from_slice(&b.to_be_bytes());
3011 // 48 is `u`, and stays nought.
3012 body[52..56].copy_from_slice(&c.to_be_bytes());
3013 body[56..60].copy_from_slice(&d.to_be_bytes());
3014 body
3015 };
3016 req!(rotation_of(&head(0, one, neg, 0)), 90u16, "a quarter turn clockwise");
3017 req!(rotation_of(&head(neg, 0, 0, neg)), 180u16, "a half turn");
3018 req!(rotation_of(&head(0, neg, one, 0)), 270u16, "three quarters clockwise");
3019 req!(rotation_of(&head(one, 0, 0, one)), 0u16, "unity is no turn");
3020 // A matrix that is not a rotation is shown as it was coded rather than guessed at.
3021 req!(rotation_of(&head(one, one, one, one)), 0u16, "a matrix that is not a rotation");
3022 req!(rotation_of(&[]), 0u16, "an empty header");
3023 Ok(())
3024 }
3025
3026 /// The sequence parameter set of a 64 by 48 stream, as libx264 wrote it: the NAL unit that
3027 /// followed the first start code of
3028 /// `ffmpeg -f lavfi -i testsrc=size=64x48:rate=10 -c:v libx264 -f h264`.
3029 ///
3030 /// It carries an emulation prevention byte -- the `03` in `00 00 03 00` at offset 11 -- so
3031 /// reading its geometry exercises the unescaping as well as the bit reader.
3032 const SPS: [u8; 21] = [
3033 0x67, 0x42, 0xC0, 0x0A, 0xDA, 0x11, 0xEC, 0x04, 0x40, 0x00, 0x00,
3034 0x03, 0x00, 0x40, 0x00, 0x00, 0x05, 0x03, 0xC4, 0x89, 0xA8,
3035 ];
3036
3037 /// The matching picture parameter set.
3038 const PPS: [u8; 4] = [0x68, 0xCE, 0x0F, 0xC8];
3039
3040 /// An `AVCDecoderConfigurationRecord` around the fixture parameter sets, with a four-byte NAL
3041 /// length: version 1, the three profile bytes copied from the set, `0xFF` for the reserved bits
3042 /// and a length of four, `0xE1` for the reserved bits and one sequence parameter set.
3043 fn avcc() -> Vec<u8> {
3044 let mut rec = vec![1, SPS[1], SPS[2], SPS[3], 0xFF, 0xE1];
3045 rec.extend_from_slice(&(SPS.len() as u16).to_be_bytes());
3046 rec.extend_from_slice(&SPS);
3047 rec.push(1);
3048 rec.extend_from_slice(&(PPS.len() as u16).to_be_bytes());
3049 rec.extend_from_slice(&PPS);
3050 rec
3051 }
3052
3053 /// A sample of `n` bytes, wrapped as one NAL unit with a four-byte length prefix.
3054 fn nal(n: usize) -> Vec<u8> {
3055 let mut v = ((n as u32).to_be_bytes()).to_vec();
3056 v.extend(std::iter::repeat(0x41).take(n));
3057 v
3058 }
3059
3060 /// Finds the first box of the given type at the top level of `buf`, giving its body.
3061 fn top(buf: &[u8], kind: &[u8; 4]) -> Option<Vec<u8>> {
3062 let mut at = 0usize;
3063 while at + 8 <= buf.len() {
3064 let size = u32::from_be_bytes([buf[at], buf[at + 1], buf[at + 2], buf[at + 3]]) as usize;
3065 if size < 8 || at + size > buf.len() {
3066 return None;
3067 }
3068 if &buf[at + 4..at + 8] == kind {
3069 return Some(buf[at + 8..at + size].to_vec());
3070 }
3071 at += size;
3072 }
3073 None
3074 }
3075
3076 /// Finds the first box of the given type anywhere in `buf`, giving the offset of its body, and
3077 /// fails the test where there is none.
3078 fn want_box(buf: &[u8], kind: &[u8; 4]) -> Outcome<usize> {
3079 match buf.windows(4).position(|w| w == kind) {
3080 Some(i) => Ok(i + 4),
3081 None => Err(err!(
3082 "No '{}' box was written.", String::from_utf8_lossy(kind); Test, Missing)),
3083 }
3084 }
3085
3086 /// The sequence parameter set of a 64 by 48 stream reads back as 64 by 48. The value is not
3087 /// this crate's: it is the size given to FFmpeg on the command line that produced the bytes.
3088 #[test]
3089 fn test_sps_geometry_00() -> Outcome<()> {
3090 let (w, h) = res!(sps_geometry(&SPS));
3091 req!(w, 64u16);
3092 req!(h, 48u16);
3093 Ok(())
3094 }
3095
3096 /// The geometry read through the configuration record is the same as the geometry read from the
3097 /// set directly, and the record's NAL length field says four.
3098 #[test]
3099 fn test_avcc_walk_01() -> Outcome<()> {
3100 let c = Codec::Avc(avcc());
3101 req!(res!(c.geometry()), (64u16, 48u16));
3102 req!(res!(c.nal_len()), 4usize);
3103 Ok(())
3104 }
3105
3106 /// Every field of the header boxes has a size the specification fixes, so the boxes have sizes
3107 /// that can be added up by hand.
3108 ///
3109 /// `ftyp`: 8 header + 4 major brand + 4 minor version + 4 compatible brands of 4 = 32.
3110 /// `mvhd`: 8 header + 4 version and flags + 4 + 4 + 4 + 4 times and scales + 4 rate + 2 volume
3111 /// + 2 reserved + 8 reserved + 36 matrix + 24 pre-defined + 4 next track = 108.
3112 /// `tkhd`: 8 + 4 + 4 + 4 + 4 + 4 + 4 + 8 + 2 + 2 + 2 + 2 + 36 + 4 + 4 = 92.
3113 /// `mdhd`: 8 + 4 + 4 + 4 + 4 + 4 + 2 + 2 = 32.
3114 /// `hdlr`: 8 + 4 + 4 + 4 + 12 + 13 for "VideoHandler" and its terminator = 45.
3115 /// `vmhd`: 8 + 4 + 2 + 6 = 20.
3116 /// `stsc`: 8 + 4 + 4 count + 12 for the one entry = 28.
3117 #[test]
3118 fn test_fixed_box_sizes_02() -> Outcome<()> {
3119 // Four brands for either picture coding, so the size is the same and it
3120 // is the third brand that differs; sound alone drops one and is shorter.
3121 req!(res!(ftyp(&Codec::Avc(avcc()))).len(), 32usize);
3122 req!(res!(ftyp(&Codec::Hevc(hvcc(&[(hevc::nal::SPS, &HEVC_SPS[2..])])))).len(), 32usize);
3123 req!(res!(ftyp(&Codec::Aac(vec![0x11, 0x90]))).len(), 28usize);
3124 req!(res!(hdlr()).len(), 45usize);
3125 req!(res!(vmhd()).len(), 20usize);
3126 req!(res!(stsc()).len(), 28usize);
3127
3128 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3129 res!(t.push(Sample::key(nal(10), 100)));
3130 req!(res!(t.mvhd(100)).len(), 108usize);
3131 req!(res!(t.tkhd(100)).len(), 92usize);
3132 req!(res!(t.mdhd()).len(), 32usize);
3133 Ok(())
3134 }
3135
3136 /// `stts` merges consecutive samples of equal duration into one entry.
3137 ///
3138 /// Durations 10, 10, 10, 20, 20, 10 give three entries -- (3, 10), (2, 20), (1, 10) -- so the
3139 /// box is 8 header + 4 version and flags + 4 entry count + 3 times 8 = 40 bytes, and the last
3140 /// entry's count is 1.
3141 #[test]
3142 fn test_stts_run_length_03() -> Outcome<()> {
3143 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3144 for (i, d) in [10u32, 10, 10, 20, 20, 10].into_iter().enumerate() {
3145 res!(t.push(Sample { data: nal(4 + i), dur: d, sync: i == 0, off: 0 }));
3146 }
3147 let b = res!(t.stts());
3148 req!(b.len(), 40usize);
3149 req!(&b[4..8], b"stts" as &[u8]);
3150 req!(u32::from_be_bytes([b[12], b[13], b[14], b[15]]), 3u32);
3151 let entries: Vec<(u32, u32)> = b[16..].chunks_exact(8)
3152 .map(|c| (
3153 u32::from_be_bytes([c[0], c[1], c[2], c[3]]),
3154 u32::from_be_bytes([c[4], c[5], c[6], c[7]]),
3155 ))
3156 .collect();
3157 req!(entries, vec![(3u32, 10u32), (2, 20), (1, 10)]);
3158 Ok(())
3159 }
3160
3161 /// A run of samples of one duration gives exactly one `stts` entry, however many there are.
3162 #[test]
3163 fn test_stts_constant_rate_is_one_entry_04() -> Outcome<()> {
3164 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3165 for i in 0..500 {
3166 res!(t.push(Sample { data: nal(4), dur: 40, sync: i == 0, off: 0 }));
3167 }
3168 let b = res!(t.stts());
3169 req!(b.len(), 24usize);
3170 req!(u32::from_be_bytes([b[12], b[13], b[14], b[15]]), 1u32);
3171 req!(u32::from_be_bytes([b[16], b[17], b[18], b[19]]), 500u32);
3172 Ok(())
3173 }
3174
3175 /// `stss` is absent where every sample is a sync sample, since the specification reads that
3176 /// absence as exactly that claim, and present listing one-based sample numbers otherwise.
3177 #[test]
3178 fn test_stss_presence_05() -> Outcome<()> {
3179 let mut all = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3180 for _ in 0..3 {
3181 res!(all.push(Sample::key(nal(4), 10)));
3182 }
3183 req!(res!(all.stss()).is_none(), true);
3184
3185 let mut some = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3186 for i in 0..5 {
3187 res!(some.push(Sample { data: nal(4), dur: 10, sync: i == 0 || i == 3, off: 0 }));
3188 }
3189 let b = match res!(some.stss()) {
3190 Some(b) => b,
3191 None => return Err(err!(
3192 "The sync sample table should have been written."; Test)),
3193 };
3194 // 8 header + 4 version and flags + 4 count + 2 entries of 4 = 24.
3195 req!(b.len(), 24usize);
3196 req!(u32::from_be_bytes([b[12], b[13], b[14], b[15]]), 2u32);
3197 req!(u32::from_be_bytes([b[16], b[17], b[18], b[19]]), 1u32);
3198 req!(u32::from_be_bytes([b[20], b[21], b[22], b[23]]), 4u32);
3199 Ok(())
3200 }
3201
3202 /// Every chunk offset names the first byte of its sample, and the first names the first byte
3203 /// after the `mdat` header.
3204 #[test]
3205 fn test_chunk_offsets_point_at_the_samples_06() -> Outcome<()> {
3206 let sizes = [11usize, 5, 23, 7];
3207 let mut t = res!(Track::new(64, 48, 600, Codec::Avc(avcc())));
3208 for (i, n) in sizes.into_iter().enumerate() {
3209 res!(t.push(Sample { data: nal(n), dur: 60, sync: i == 0, off: 0 }));
3210 }
3211 let file = res!(t.finish());
3212
3213 let at = res!(want_box(&file, b"stco"));
3214 let count = u32::from_be_bytes([file[at + 4], file[at + 5], file[at + 6], file[at + 7]]);
3215 req!(count, 4u32);
3216
3217 let mdat = res!(want_box(&file, b"mdat"));
3218 let mut want = mdat as u32;
3219 for (i, n) in sizes.into_iter().enumerate() {
3220 let o = at + 8 + i * 4;
3221 let got = u32::from_be_bytes([file[o], file[o + 1], file[o + 2], file[o + 3]]);
3222 req!(got, want);
3223 // The sample's own first byte is its NAL length field, which is what was written.
3224 let len = u32::from_be_bytes([
3225 file[got as usize], file[got as usize + 1],
3226 file[got as usize + 2], file[got as usize + 3],
3227 ]);
3228 req!(len, n as u32);
3229 want += (n + 4) as u32;
3230 }
3231 req!(want as usize, file.len());
3232 Ok(())
3233 }
3234
3235 /// The top-level layout is `ftyp`, then `moov`, then `mdat`, and the three account for the
3236 /// whole file.
3237 #[test]
3238 fn test_top_level_layout_07() -> Outcome<()> {
3239 let mut t = res!(Track::new(64, 48, 90_000, Codec::Avc(avcc())));
3240 res!(t.push(Sample::key(nal(30), 3000)));
3241 res!(t.push(Sample::delta(nal(9), 3000)));
3242 let file = res!(t.finish());
3243
3244 let mut kinds = Vec::new();
3245 let mut at = 0usize;
3246 while at + 8 <= file.len() {
3247 let size = u32::from_be_bytes([file[at], file[at + 1], file[at + 2], file[at + 3]])
3248 as usize;
3249 kinds.push(String::from_utf8_lossy(&file[at + 4..at + 8]).to_string());
3250 at += size;
3251 }
3252 req!(at, file.len());
3253 req!(kinds, vec!["ftyp".to_string(), "moov".to_string(), "mdat".to_string()]);
3254
3255 // The media box holds exactly the samples: two NAL units of 30 and 9 bytes, each with a
3256 // four-byte length in front of it.
3257 let mdat = match top(&file, b"mdat") {
3258 Some(b) => b,
3259 None => return Err(err!("No media box was written."; Test)),
3260 };
3261 req!(mdat.len(), 47usize);
3262 Ok(())
3263 }
3264
3265 /// The media header keeps the track's timescale, and the movie header restates the same
3266 /// duration in milliseconds.
3267 ///
3268 /// Thirty samples of 3003 ticks at 90000 a second is 90090 ticks, which is 1001 milliseconds.
3269 #[test]
3270 fn test_durations_in_their_own_timescales_08() -> Outcome<()> {
3271 let mut t = res!(Track::new(64, 48, 90_000, Codec::Avc(avcc())));
3272 for i in 0..30 {
3273 res!(t.push(Sample { data: nal(6), dur: 3003, sync: i == 0, off: 0 }));
3274 }
3275 req!(t.duration(), 90_090u64);
3276 let file = res!(t.finish());
3277
3278 let mdhd = res!(want_box(&file, b"mdhd"));
3279 req!(u32::from_be_bytes([
3280 file[mdhd + 12], file[mdhd + 13], file[mdhd + 14], file[mdhd + 15],
3281 ]), 90_000u32);
3282 req!(u32::from_be_bytes([
3283 file[mdhd + 16], file[mdhd + 17], file[mdhd + 18], file[mdhd + 19],
3284 ]), 90_090u32);
3285
3286 let mvhd = res!(want_box(&file, b"mvhd"));
3287 req!(u32::from_be_bytes([
3288 file[mvhd + 12], file[mvhd + 13], file[mvhd + 14], file[mvhd + 15],
3289 ]), 1000u32);
3290 req!(u32::from_be_bytes([
3291 file[mvhd + 16], file[mvhd + 17], file[mvhd + 18], file[mvhd + 19],
3292 ]), 1001u32);
3293 Ok(())
3294 }
3295
3296 /// The track header carries the unity matrix and the frame size in 16.16 fixed point.
3297 #[test]
3298 fn test_tkhd_matrix_and_size_09() -> Outcome<()> {
3299 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3300 res!(t.push(Sample::key(nal(8), 40)));
3301 let b = res!(t.tkhd(40));
3302 // 8 header + 4 version and flags + 36 fixed fields brings the matrix to offset 48.
3303 let m: Vec<u32> = b[48..84].chunks_exact(4)
3304 .map(|c| u32::from_be_bytes([c[0], c[1], c[2], c[3]]))
3305 .collect();
3306 req!(m, vec![0x0001_0000u32, 0, 0, 0, 0x0001_0000, 0, 0, 0, 0x4000_0000]);
3307 req!(u32::from_be_bytes([b[84], b[85], b[86], b[87]]), 64u32 << 16);
3308 req!(u32::from_be_bytes([b[88], b[89], b[90], b[91]]), 48u32 << 16);
3309 Ok(())
3310 }
3311
3312 /// A track that names dimensions the stream does not code is refused, and the message names
3313 /// both.
3314 #[test]
3315 fn test_refuses_a_geometry_mismatch_10() -> Outcome<()> {
3316 match Track::new(1920, 1080, 1000, Codec::Avc(avcc())) {
3317 Ok(_) => Err(err!("A 1920 by 1080 track over a 64 by 48 stream was accepted."; Test)),
3318 Err(e) => {
3319 let msg = e.to_string();
3320 req!(msg.contains("1920"), true, "The message does not name the declared width.");
3321 req!(msg.contains("64"), true, "The message does not name the coded width.");
3322 Ok(())
3323 },
3324 }
3325 }
3326
3327 /// A timescale of zero, a zero dimension, an empty track, a sample of no duration, a track that
3328 /// does not begin at a sync sample, and a sample handed over in Annex B are each refused.
3329 #[test]
3330 fn test_refusals_11() -> Outcome<()> {
3331 req!(Track::new(64, 48, 0, Codec::Avc(avcc())).is_err(), true, "A zero timescale passed.");
3332 req!(Track::new(0, 48, 1000, Codec::Avc(avcc())).is_err(), true, "A zero width passed.");
3333
3334 let empty = res!(Track::new(64, 48, 1000, Codec::Avc(avcc()))).finish().is_err();
3335 req!(empty, true, "A track with no samples passed.");
3336
3337 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3338 req!(t.push(Sample::key(nal(4), 0)).is_err(), true, "A sample of no duration passed.");
3339 req!(t.push(Sample::key(Vec::new(), 40)).is_err(), true, "A sample of no bytes passed.");
3340
3341 let mut annexb = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3342 let e = annexb.push(Sample::key(vec![0, 0, 0, 1, 0x65, 0x88, 0x84], 40));
3343 match e {
3344 Ok(_) => return Err(err!("An Annex B sample was accepted."; Test)),
3345 Err(e) => req!(e.to_string().contains("Annex B"), true,
3346 "The message does not name the format that was handed over."),
3347 }
3348
3349 let mut short = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3350 req!(short.push(Sample::key(vec![0x00, 0x00, 0x00, 0x40, 0x65], 40)).is_err(), true,
3351 "A sample whose NAL runs past its end passed.");
3352
3353 let mut nokey = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3354 res!(nokey.push(Sample::delta(nal(4), 40)));
3355 let begun = nokey.finish().is_err();
3356 req!(begun, true, "A track that begins at a delta sample passed.");
3357 Ok(())
3358 }
3359
3360 /// A configuration record that is truncated, versioned wrongly, or names the forbidden
3361 /// three-byte NAL length is refused before a file is built around it.
3362 #[test]
3363 fn test_refuses_a_bad_configuration_record_12() -> Outcome<()> {
3364 let stub = Codec::Avc(vec![1, 66, 192, 10]).geometry().is_err();
3365 req!(stub, true, "A stub record passed.");
3366
3367 let mut bad_ver = avcc();
3368 bad_ver[0] = 2;
3369 let bad_ver = Codec::Avc(bad_ver).geometry().is_err();
3370 req!(bad_ver, true, "Version 2 passed.");
3371
3372 let mut bad_len = avcc();
3373 bad_len[4] = 0xFE; // lengthSizeMinusOne = 2, a three-byte length.
3374 let bad_len = Codec::Avc(bad_len).nal_len().is_err();
3375 req!(bad_len, true, "A three-byte NAL length passed.");
3376
3377 let mut cut = avcc();
3378 cut.truncate(12);
3379 let cut = Codec::Avc(cut).geometry().is_err();
3380 req!(cut, true, "A truncated parameter set passed.");
3381
3382 let mut no_pps = vec![1, SPS[1], SPS[2], SPS[3], 0xFF, 0xE1];
3383 no_pps.extend_from_slice(&(SPS.len() as u16).to_be_bytes());
3384 no_pps.extend_from_slice(&SPS);
3385 no_pps.push(0);
3386 let no_pps = Codec::Avc(no_pps).geometry().is_err();
3387 req!(no_pps, true, "A record with no picture set passed.");
3388 Ok(())
3389 }
3390
3391 /// Rescaling rounds to nearest rather than truncating, so a duration does not creep short.
3392 ///
3393 /// 90090 ticks at 90000 a second is 1001 milliseconds exactly; 1 tick at 3 a second is 333.33
3394 /// milliseconds, which rounds to 333; 2 ticks at 3 is 666.67, which rounds to 667.
3395 #[test]
3396 fn test_rescale_rounds_to_nearest_13() -> Outcome<()> {
3397 req!(res!(rescale(90_090, 90_000, 1000)), 1001u64);
3398 req!(res!(rescale(1, 3, 1000)), 333u64);
3399 req!(res!(rescale(2, 3, 1000)), 667u64);
3400 req!(res!(rescale(0, 1000, 1000)), 0u64);
3401 req!(rescale(1, 0, 1000).is_err(), true, "A zero source timescale passed.");
3402 Ok(())
3403 }
3404
3405 /// The emulation prevention bytes come out and nothing else does: `00 00 03 00` is `00 00 00`,
3406 /// and a `03` that does not follow two zeroes is kept.
3407 #[test]
3408 fn test_rbsp_unescaping_14() -> Outcome<()> {
3409 req!(rbsp(&[0x00, 0x00, 0x03, 0x00, 0x01]), vec![0x00u8, 0x00, 0x00, 0x01]);
3410 req!(rbsp(&[0x01, 0x03, 0x02]), vec![0x01u8, 0x03, 0x02]);
3411 req!(rbsp(&[0x00, 0x00, 0x03, 0x03]), vec![0x00u8, 0x00, 0x03]);
3412 Ok(())
3413 }
3414
3415 /// The 64-bit chunk offset table is the same table in a wider field: the same entry count, eight
3416 /// bytes an entry rather than four, under the type `co64`.
3417 ///
3418 /// The choice between the two is made in `finish` by where the last byte of media falls, so it
3419 /// cannot be reached without building a file of four gibibytes. The table itself is written
3420 /// here directly instead, which is the part that would be wrong.
3421 #[test]
3422 fn test_the_64_bit_offset_table_16() -> Outcome<()> {
3423 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3424 for i in 0..3 {
3425 res!(t.push(Sample { data: nal(20), dur: 40, sync: i == 0, off: 0 }));
3426 }
3427 let base = 5_000_000_000u64;
3428 let b = res!(t.offsets(base, true));
3429 // 8 header + 4 version and flags + 4 count + 3 entries of 8 = 40.
3430 req!(b.len(), 40usize);
3431 req!(&b[4..8], b"co64" as &[u8]);
3432 req!(u32::from_be_bytes([b[12], b[13], b[14], b[15]]), 3u32);
3433 let entries: Vec<u64> = b[16..].chunks_exact(8)
3434 .map(|c| u64::from_be_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]]))
3435 .collect();
3436 req!(entries, vec![base, base + 24, base + 48]);
3437
3438 // The 32-bit table refuses the same offsets rather than truncating them.
3439 req!(t.offsets(base, false).is_err(), true, "A 32-bit table took a 5 GB offset.");
3440 Ok(())
3441 }
3442
3443 /// A file written twice from the same samples is the same file: the header times are written as
3444 /// unset rather than taken from the clock, so a build is reproducible.
3445 #[test]
3446 fn test_output_is_deterministic_15() -> Outcome<()> {
3447 let build = || -> Outcome<Vec<u8>> {
3448 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3449 for i in 0..8 {
3450 res!(t.push(Sample { data: nal(12 + i), dur: 40, sync: i % 4 == 0, off: 0 }));
3451 }
3452 t.finish()
3453 };
3454 req!(res!(build()), res!(build()));
3455 Ok(())
3456 }
3457 #[test]
3458 fn test_a_written_film_reads_back_17() -> Outcome<()> {
3459 // The two halves of this module, held to each other. The writer lays out a sample table and
3460 // the reader walks it back, and what they must agree on is the thing neither can check
3461 // alone: where each sample's bytes actually are. A chunk offset measured from the wrong
3462 // origin, or a sample-to-chunk run read as though its first chunk were counted from nought,
3463 // produces a perfectly well-formed index that points at the wrong bytes.
3464 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3465 let mut wrote: Vec<Vec<u8>> = Vec::new();
3466 for i in 0..6usize {
3467 let data = nal(20 + i);
3468 wrote.push(data.clone());
3469 res!(t.push(Sample { data, dur: 40, sync: i == 0, off: 0 }));
3470 }
3471 let file = res!(t.finish());
3472 let film = res!(Film::read(&file));
3473 req!(film.kind(), Kind::Avc);
3474 req!(film.samples(), wrote.len());
3475 req!(film.size(), (64u16, 48u16));
3476 for (i, want) in wrote.iter().enumerate() {
3477 let got = res!(film.sample(&file, i));
3478 req!(got, &want[..], "sample {} came back from the wrong place", i);
3479 }
3480 // The first sample is the only sync sample, and a reader must begin there.
3481 req!(res!(film.first_sync()), 0usize);
3482 // A sample past the end is refused rather than answered.
3483 req!(film.span(wrote.len()).is_err(), true, "a sample past the end was handed out");
3484 Ok(())
3485 }
3486
3487 #[test]
3488 fn test_a_track_that_is_turned_says_so_18() -> Outcome<()> {
3489 // The writer writes a unity matrix, so a film it wrote is shown as it was coded. What is
3490 // asserted here is the reading of the four entries that matter, because the fault this
3491 // guards against hides perfectly: a picture turned by ninety degrees has exactly as many
3492 // samples as one that is not, so a decoder and a viewer that disagree about the angle
3493 // produce output of the right size and the wrong shape.
3494 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3495 res!(t.push(Sample { data: nal(24), dur: 40, sync: true, off: 0 }));
3496 let mut file = res!(t.finish());
3497 req!(res!(Film::read(&file)).rotation(), 0u16, "a unity matrix was read as a rotation");
3498
3499 // Turn it a quarter clockwise by writing the matrix a phone would: a = 0, b = 1, c = -1,
3500 // d = 0, in 16.16 fixed point.
3501 //
3502 // **The four are not four in a row.** The matrix is a, b, u, c, d, v, x, y, w, so c and d
3503 // are the fourth and fifth entries; this test used to write them third and fourth, which
3504 // is exactly where the reader used to look for them, so the two agreed with each other and
3505 // with no real film. Every rotated film in a library of seven thousand was read as
3506 // upright. The positions below are the specification's.
3507 let at = match file.windows(4).position(|w| w == b"tkhd") {
3508 Some(at) => at + 4 + 40,
3509 None => return Err(err!("the writer emitted no track header."; Test, Missing)),
3510 };
3511 let put = |file: &mut Vec<u8>, i: usize, v: i32| {
3512 file[at + i * 4..at + i * 4 + 4].copy_from_slice(&(v as u32).to_be_bytes());
3513 };
3514 let one = 0x0001_0000i32;
3515 let matrix = |file: &mut Vec<u8>, a: i32, b: i32, c: i32, d: i32| {
3516 put(file, 0, a);
3517 put(file, 1, b);
3518 put(file, 3, c);
3519 put(file, 4, d);
3520 };
3521 matrix(&mut file, 0, one, -one, 0);
3522 req!(res!(Film::read(&file)).rotation(), 90u16);
3523 // And a half turn.
3524 matrix(&mut file, -one, 0, 0, -one);
3525 req!(res!(Film::read(&file)).rotation(), 180u16);
3526 // And three quarters.
3527 matrix(&mut file, 0, -one, one, 0);
3528 req!(res!(Film::read(&file)).rotation(), 270u16);
3529 Ok(())
3530 }
3531
3532 /// The presentation times are a real film's, read off the first frames of
3533 /// `Dominion2018.mkv`: shown at 0, 160, 80, 40, 120 while decoded at 0, 40,
3534 /// 80, 120, 160. A stream that never reordered would state the same list
3535 /// twice.
3536 #[test]
3537 fn test_a_reordered_run_is_offset_forwards_19() -> Outcome<()> {
3538 let times = [0i64, 160, 80, 40, 120];
3539 let durs = [40u32; 5];
3540 let offs = res!(composition_offsets(&times, &durs));
3541
3542 // Not one of them may be negative, whatever the film does: a negative
3543 // offset says a picture is shown before it is decoded.
3544 for (i, o) in offs.iter().enumerate() {
3545 assert!(*o >= 0, "offset {} of sample {} is negative", o, i);
3546 }
3547 // And the intervals must survive: every picture keeps its distance from
3548 // every other, so the whole run is the source's list plus one constant.
3549 let mut dts = 0i64;
3550 let mut shift = None;
3551 for i in 0..times.len() {
3552 let shown = dts + offs[i] as i64;
3553 match shift {
3554 None => shift = Some(shown - times[i]),
3555 Some(s) => req!(shown - times[i], s),
3556 }
3557 dts += durs[i] as i64;
3558 }
3559 req!(shift, Some(80i64));
3560 Ok(())
3561 }
3562
3563 /// A track whose pictures are shown in the order they are decoded must
3564 /// carry no `ctts` at all -- an absent box is the statement that the two
3565 /// orders agree, and a table of zeroes says it again for four bytes a
3566 /// sample.
3567 #[test]
3568 fn test_a_stream_in_order_writes_no_offset_table_20() -> Outcome<()> {
3569 let times = [0i64, 40, 80, 120];
3570 let durs = [40u32; 4];
3571 let offs = res!(composition_offsets(&times, &durs));
3572 req!(offs, vec![0i32, 0, 0, 0]);
3573
3574 let mut t = res!(Track::new(64, 48, 1000, Codec::Avc(avcc())));
3575 for i in 0..4 {
3576 res!(t.push(Sample { data: nal(8), dur: 40, sync: i == 0, off: 0 }));
3577 }
3578 req!(res!(t.ctts()).is_none(), true);
3579 Ok(())
3580 }
3581
3582 /// An `AudioSpecificConfig` for AAC-LC at 44,100 Hz in two channels, ISO/IEC 14496-3 §1.6.2.1:
3583 /// object type 2 in five bits, sampling frequency index 4 in four, channel configuration 2 in
3584 /// four, and three bits of padding.
3585 const AAC_LC_44100_STEREO: [u8; 2] = [0x12, 0x10];
3586
3587 /// A picture stream of the fixture geometry, on a millisecond timescale.
3588 fn picture_stream() -> Stream {
3589 Stream {
3590 media: Media::Picture { w: 64, h: 48 },
3591 timescale: 1000,
3592 codec: Codec::Avc(avcc()),
3593 start: 0,
3594 }
3595 }
3596
3597 /// A sound stream on its own sampling rate as its timescale, beginning after the pictures do.
3598 fn sound_stream(start: u64) -> Stream {
3599 Stream {
3600 media: Media::Sound { channels: 2, rate: 44_100 },
3601 timescale: 44_100,
3602 codec: Codec::Aac(AAC_LC_44100_STEREO.to_vec()),
3603 start,
3604 }
3605 }
3606
3607 /// How many boxes of the given type sit at the top level of a box body.
3608 fn count_boxes(buf: &[u8], kind: &[u8; 4]) -> Outcome<usize> {
3609 let mut at = 0usize;
3610 let mut n = 0usize;
3611 while at + 8 <= buf.len() {
3612 let size = u32::from_be_bytes([buf[at], buf[at + 1], buf[at + 2], buf[at + 3]]) as usize;
3613 if size < 8 || at + size > buf.len() {
3614 return Err(err!(
3615 "A box of {} bytes at offset {} does not fit the {} bytes given.",
3616 size, at, buf.len();
3617 Test, Invalid));
3618 }
3619 if &buf[at + 4..at + 8] == kind {
3620 n += 1;
3621 }
3622 at += size;
3623 }
3624 Ok(n)
3625 }
3626
3627 /// Each track fragment of a fragment, as the decode time its `tfdt` states and the `data_offset`
3628 /// its `trun` states, in the order the track fragments are written.
3629 ///
3630 /// The boxes are walked by their sizes rather than found by searching for their names, because
3631 /// a fragment holds two of each and a search finds only the first.
3632 fn frag_runs(frag: &[u8]) -> Outcome<Vec<(u64, i32)>> {
3633 if frag.len() < 8 || &frag[4..8] != b"moof" {
3634 return Err(err!("A fragment must begin with a movie fragment box."; Test, Invalid));
3635 }
3636 let end = u32::from_be_bytes([frag[0], frag[1], frag[2], frag[3]]) as usize;
3637 if end > frag.len() {
3638 return Err(err!(
3639 "The movie fragment box claims {} bytes and the whole fragment is {}.",
3640 end, frag.len();
3641 Test, Invalid));
3642 }
3643 let mut out = Vec::new();
3644 let mut at = 8usize;
3645 while at + 8 <= end {
3646 let n = u32::from_be_bytes([frag[at], frag[at + 1], frag[at + 2], frag[at + 3]]) as usize;
3647 if n < 8 || at + n > end {
3648 return Err(err!(
3649 "A box of {} bytes at offset {} does not fit the movie fragment.", n, at;
3650 Test, Invalid));
3651 }
3652 if &frag[at + 4..at + 8] == b"traf" {
3653 let mut time: Option<u64> = None;
3654 let mut off: Option<i32> = None;
3655 let mut k = at + 8;
3656 while k + 8 <= at + n {
3657 let m = u32::from_be_bytes([frag[k], frag[k + 1], frag[k + 2], frag[k + 3]])
3658 as usize;
3659 if m < 8 || k + m > at + n {
3660 return Err(err!(
3661 "A box of {} bytes at offset {} does not fit the track fragment.", m, k;
3662 Test, Invalid));
3663 }
3664 // A `tfdt` body is a full box and a 64-bit time; a `trun` body is a full box,
3665 // the sample count, and then the offset.
3666 if &frag[k + 4..k + 8] == b"tfdt" && m >= 20 {
3667 let o = k + 12;
3668 time = Some(u64::from_be_bytes([
3669 frag[o], frag[o + 1], frag[o + 2], frag[o + 3],
3670 frag[o + 4], frag[o + 5], frag[o + 6], frag[o + 7],
3671 ]));
3672 }
3673 if &frag[k + 4..k + 8] == b"trun" && m >= 20 {
3674 let o = k + 16;
3675 off = Some(i32::from_be_bytes([
3676 frag[o], frag[o + 1], frag[o + 2], frag[o + 3],
3677 ]));
3678 }
3679 k += m;
3680 }
3681 match (time, off) {
3682 (Some(t), Some(o)) => out.push((t, o)),
3683 _ => return Err(err!(
3684 "The track fragment at offset {} carries no decode time or no track run.",
3685 at;
3686 Test, Missing)),
3687 }
3688 }
3689 at += n;
3690 }
3691 Ok(out)
3692 }
3693
3694 /// The initialisation segment describes every stream once: a `trak` each under `moov` and a
3695 /// `trex` each under `mvex`, and a next track id one past the highest in use.
3696 ///
3697 /// A missing `trex` is the failure worth guarding: the file opens, the track is listed, and
3698 /// every fragment of it is ignored, because without the extends box the empty sample tables in
3699 /// `moov` are the whole of what the track is said to hold.
3700 #[test]
3701 fn test_a_fragmented_head_describes_every_stream_21() -> Outcome<()> {
3702 let f = res!(Fragments::new(vec![picture_stream(), sound_stream(0)]));
3703 let head = res!(f.head());
3704
3705 let ftyp = match top(&head, b"ftyp") {
3706 Some(b) => b,
3707 None => return Err(err!("No file type box was written."; Test, Missing)),
3708 };
3709 req!(&ftyp[0..4], b"iso5" as &[u8], "the major brand is not the fragmented one");
3710
3711 let moov = match top(&head, b"moov") {
3712 Some(b) => b,
3713 None => return Err(err!("No movie box was written."; Test, Missing)),
3714 };
3715 req!(res!(count_boxes(&moov, b"trak")), 2usize, "one track a stream");
3716 req!(res!(count_boxes(&moov, b"mvex")), 1usize, "one movie extends box");
3717
3718 let mvex = match top(&moov, b"mvex") {
3719 Some(b) => b,
3720 None => return Err(err!("No movie extends box was written."; Test, Missing)),
3721 };
3722 req!(res!(count_boxes(&mvex, b"trex")), 2usize, "one track extends box a stream");
3723
3724 // The next track id is the last field of the movie header, and it must exceed both ids in
3725 // use rather than count them.
3726 let mvhd = match top(&moov, b"mvhd") {
3727 Some(b) => b,
3728 None => return Err(err!("No movie header was written."; Test, Missing)),
3729 };
3730 let n = mvhd.len();
3731 req!(u32::from_be_bytes([mvhd[n - 4], mvhd[n - 3], mvhd[n - 2], mvhd[n - 1]]), 3u32);
3732 Ok(())
3733 }
3734
3735 /// The first track run's data offset clears the movie fragment box and its media header, and
3736 /// the media box holds exactly the samples.
3737 ///
3738 /// The offset is measured from the first byte of the `moof`, because `default-base-is-moof` is
3739 /// the only flag the track fragment header sets. An offset measured from anywhere else is a
3740 /// file that opens, reports the right number of frames, and decodes rubbish.
3741 #[test]
3742 fn test_the_first_data_offset_clears_the_moof_22() -> Outcome<()> {
3743 let mut f = res!(Fragments::new(vec![picture_stream()]));
3744 let sizes = [30usize, 9, 17];
3745 let mut samples = Vec::new();
3746 for (i, n) in sizes.into_iter().enumerate() {
3747 samples.push(Sample { data: nal(n), dur: 40, sync: i == 0, off: 0 });
3748 }
3749 let frag = res!(f.next(vec![(0, samples)]));
3750
3751 req!(&frag[4..8], b"moof" as &[u8]);
3752 let moof = u32::from_be_bytes([frag[0], frag[1], frag[2], frag[3]]) as usize;
3753 let runs = res!(frag_runs(&frag));
3754 req!(runs.len(), 1usize);
3755 req!(runs[0].1, moof as i32 + 8, "the data offset does not clear the moof and mdat header");
3756
3757 // The media box follows the movie fragment immediately, and its payload is the samples and
3758 // nothing else: each is its own bytes with a four-byte NAL length in front.
3759 req!(&frag[moof + 4..moof + 8], b"mdat" as &[u8]);
3760 let payload: usize = sizes.iter().map(|n| n + 4).sum();
3761 req!(u32::from_be_bytes([
3762 frag[moof], frag[moof + 1], frag[moof + 2], frag[moof + 3],
3763 ]) as usize, payload + 8);
3764 req!(frag.len(), moof + 8 + payload);
3765
3766 // And the offset names the first byte of the first sample, which is its NAL length field.
3767 let at = runs[0].1 as usize;
3768 req!(u32::from_be_bytes([
3769 frag[at], frag[at + 1], frag[at + 2], frag[at + 3],
3770 ]) as usize, sizes[0]);
3771 Ok(())
3772 }
3773
3774 /// A second track fragment's data offset is the first's plus the first's sample bytes, and each
3775 /// fragment states where its own streams have got to.
3776 ///
3777 /// The two halves are one fault in two places. Both offsets are measured from the same origin,
3778 /// so the second is only right if the first's samples have been counted exactly; and both
3779 /// streams' decode times carry on across fragments, each in its own timescale and from its own
3780 /// start, so a stream that began late must still be late in the second fragment.
3781 #[test]
3782 fn test_a_later_traf_starts_after_the_earlier_bytes_23() -> Outcome<()> {
3783 let mut f = res!(Fragments::new(vec![picture_stream(), sound_stream(512)]));
3784 let pictures = |first: bool| -> Vec<Sample> {
3785 let mut v = Vec::new();
3786 for i in 0..3usize {
3787 v.push(Sample { data: nal(20 + i), dur: 40, sync: first && i == 0, off: 0 });
3788 }
3789 v
3790 };
3791 let sound = || -> Vec<Sample> {
3792 vec![Sample::key(vec![0x21; 30], 1024), Sample::key(vec![0x21; 27], 1024)]
3793 };
3794 let first = res!(f.next(vec![(0, pictures(true)), (1, sound())]));
3795
3796 let moof = u32::from_be_bytes([first[0], first[1], first[2], first[3]]) as usize;
3797 let runs = res!(frag_runs(&first));
3798 req!(runs.len(), 2usize);
3799 req!(runs[0].1, moof as i32 + 8);
3800 // The pictures come to three NAL units of 20, 21 and 22 bytes, each with a four-byte length
3801 // in front of it: 75 bytes, after which the sound begins.
3802 req!(runs[1].1 - runs[0].1, 75i32, "the second run does not follow the first's bytes");
3803 req!(runs[0].0, 0u64, "the pictures do not begin at nought");
3804 req!(runs[1].0, 512u64, "the sound does not begin where its stream says");
3805
3806 // The second fragment carries the next sequence number, and each stream's decode time has
3807 // moved on by that stream's own durations: three pictures of 40 ticks at 1000 a second, and
3808 // two sound frames of 1024 at 44,100.
3809 let second = res!(f.next(vec![(0, pictures(false)), (1, sound())]));
3810 let seq = res!(want_box(&second, b"mfhd"));
3811 req!(u32::from_be_bytes([
3812 second[seq + 4], second[seq + 5], second[seq + 6], second[seq + 7],
3813 ]), 2u32);
3814 let runs = res!(frag_runs(&second));
3815 req!(runs.len(), 2usize);
3816 req!(runs[0].0, 120u64);
3817 req!(runs[1].0, 512u64 + 2048);
3818 Ok(())
3819 }
3820
3821 /// The sequence parameter set of a 96 by 64 HEVC stream, as libx265 wrote it: the NAL unit of
3822 /// type 33 out of `ffmpeg -f lavfi -i testsrc=size=96x64:rate=10 -frames:v 2 -pix_fmt yuv420p
3823 /// -c:v libx265 -f hevc`. Main profile, 8-bit 4:2:0, one temporal layer.
3824 ///
3825 /// Four of its bytes are emulation prevention -- the `03` of each `00 00 03`, at offsets 7, 12,
3826 /// 15 and 33 -- and the first of them sits well before the field that codes the width, so a
3827 /// reading that left them in place answers some other size rather than failing. The unescaped
3828 /// payload happens to carry no `03` at all, so the opposite fault, unescaping twice, is a
3829 /// no-op on this particular set and is **not** exercised by it. The two bytes at the front are
3830 /// the NAL unit header, which is what a record's parameter set array carries.
3831 const HEVC_SPS: [u8; 40] = [
3832 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90,
3833 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x1E, 0xA0, 0x30,
3834 0x81, 0x05, 0x96, 0x56, 0x69, 0x24, 0xCA, 0xF0, 0x16, 0x80,
3835 0x80, 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x05, 0x04,
3836 ];
3837
3838 /// The matching picture parameter set, from the same stream.
3839 ///
3840 /// Nothing under test reads it. It is here so that the record has the shape a real one has, and
3841 /// so that the refusal below has a parameter set to carry that is not a sequence parameter set.
3842 const HEVC_PPS: [u8; 7] = [0x44, 0x01, 0xC1, 0x72, 0xB4, 0x22, 0x40];
3843
3844 /// The 22 fixed fields of an `HEVCDecoderConfigurationRecord`, copied verbatim out of the
3845 /// `hvcC` box ffmpeg wrote when it muxed that same stream into an MP4.
3846 ///
3847 /// Version 1, then the profile, tier and level of the sets above, then the sampling and the
3848 /// depths, and finally `0x0F`: one temporal layer, nested, and a four-byte NAL length.
3849 const HVCC_HEAD: [u8; 22] = [
3850 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00,
3851 0x00, 0x1E, 0xF0, 0x00, 0xFC, 0xFD, 0xF8, 0xF8, 0x00, 0x00, 0x0F,
3852 ];
3853
3854 /// A record around the given parameter sets, each as `(NAL unit type, bytes)`, one array
3855 /// apiece: the array's type byte, a count of one, and the set behind a two-byte length.
3856 ///
3857 /// The type byte's top bit is `array_completeness`, which is set because a `hvc1` entry states
3858 /// that these are all the sets there are; the bit below it is reserved and nought. That is the
3859 /// byte ffmpeg writes -- `0xA0`, `0xA1`, `0xA2` for the three arrays of the record above.
3860 fn hvcc(sets: &[(u8, &[u8])]) -> Vec<u8> {
3861 let mut rec = HVCC_HEAD.to_vec();
3862 rec.push(sets.len() as u8);
3863 for &(kind, set) in sets {
3864 rec.push(0x80 | kind);
3865 rec.extend_from_slice(&1u16.to_be_bytes()); // One set in this array.
3866 rec.extend_from_slice(&(set.len() as u16).to_be_bytes());
3867 rec.extend_from_slice(set);
3868 }
3869 rec
3870 }
3871
3872 /// An `hvcC` gives the size its sequence parameter set codes, and a track is held to it.
3873 ///
3874 /// The size is not this crate's: 96 by 64 is what FFmpeg was given on the command line that
3875 /// produced the parameter set, and what `ffprobe` reads back out of the stream it produced.
3876 /// The set carries emulation prevention bytes before the field that codes the width, so a
3877 /// reading that left them in place answers some other size rather than failing.
3878 #[test]
3879 fn test_an_hvcc_yields_the_size_its_sps_codes_24() -> Outcome<()> {
3880 let sets: [(u8, &[u8]); 2] = [(33, &HEVC_SPS[..]), (34, &HEVC_PPS[..])];
3881 let c = Codec::Hevc(hvcc(&sets));
3882 req!(res!(c.geometry()), (96u16, 64u16));
3883 req!(res!(c.nal_len()), 4usize);
3884 req!(c.is_picture(), true);
3885 req!(c.entry(), b"hvc1");
3886 req!(c.config(), b"hvcC");
3887
3888 // A track is accepted at the size the set codes and refused at any other, which is the
3889 // whole-file writer's existing check working over HEVC with nothing added to it.
3890 req!(Track::new(96, 64, 1000, c.clone()).is_ok(), true, "the coded size was refused");
3891 req!(Track::new(64, 48, 1000, c.clone()).is_err(), true,
3892 "a track declared 64 by 48 over a 96 by 64 stream was accepted");
3893
3894 // And the tiling check is reached for HEVC as it is for AVC. An elementary stream handed
3895 // straight through is the fault worth naming: it produces a file every demuxer accepts and
3896 // no decoder plays.
3897 let mut t = res!(Track::new(96, 64, 1000, c));
3898 match t.push(Sample::key(vec![0, 0, 0, 1, 0x26, 0x01, 0xAF], 40)) {
3899 Ok(_) => return Err(err!("An Annex B HEVC sample was accepted."; Test)),
3900 Err(e) => req!(e.to_string().contains("Annex B"), true,
3901 "The message does not name the format that was handed over."),
3902 }
3903 Ok(())
3904 }
3905
3906 /// A record carrying no sequence parameter set is refused, and the refusal names the type that
3907 /// is missing and the types that are there.
3908 ///
3909 /// Naming both is the point. "No geometry" on its own leaves a caller guessing whether the
3910 /// record was empty, truncated, or full of the wrong sets, and the three are fixed differently.
3911 #[test]
3912 fn test_an_hvcc_with_no_sps_is_refused_by_name_25() -> Outcome<()> {
3913 let only_pps: [(u8, &[u8]); 1] = [(34, &HEVC_PPS[..])];
3914 let msg = match Codec::Hevc(hvcc(&only_pps)).geometry() {
3915 Ok((w, h)) => return Err(err!(
3916 "A record carrying only a picture parameter set gave a geometry of {} by {}.",
3917 w, h; Test)),
3918 Err(e) => e.to_string(),
3919 };
3920 req!(msg.contains("33"), true, "The message does not name the set that is missing.");
3921 req!(msg.contains("34"), true, "The message does not name what the record does carry.");
3922
3923 let msg = match Codec::Hevc(hvcc(&[])).geometry() {
3924 Ok((w, h)) => return Err(err!(
3925 "A record carrying no parameter sets at all gave a geometry of {} by {}.",
3926 w, h; Test)),
3927 Err(e) => e.to_string(),
3928 };
3929 req!(msg.contains("no parameter sets at all"), true,
3930 "The message does not say that the record carries nothing.");
3931 Ok(())
3932 }
3933}