Bug 1624057 - Update mp4parse-rust to 63ca8c6. r=kinetik
authorJon Bauman <jbauman@mozilla.com>
Thu, 26 Mar 2020 02:08:51 +0000
changeset 520461 7ec1ce6883d618cedef66190d605b1bbd4118e2e
parent 520460 07d5ad6378e0dc98c17f4a5e72d4ca5a45e17900
child 520462 171275c408d177c075a5bf88c21898a7e4ae455e
push id37251
push usermalexandru@mozilla.com
push dateThu, 26 Mar 2020 09:33:08 +0000
treeherdermozilla-central@3e5a7430c8d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1624057
milestone76.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1624057 - Update mp4parse-rust to 63ca8c6. r=kinetik Also update the update-rust.sh script in a couple ways: - Stop copying the source for mp4parse_fallible into the tree; use crates.io - Include submodules in mp4parse-rust checkout; needed for tests - Exclude unnecessary build.rs from mp4parse_fallible, it was causing problems - Update mp4rust_capi/Cargo.toml patch to exclude cdylib. It's only necessary for test_ffi and causes build problems otherwise Differential Revision: https://phabricator.services.mozilla.com/D68139
Cargo.lock
Cargo.toml
dom/media/gtest/mp4_demuxer/TestMP4.cpp
dom/media/mp4/MP4Metadata.cpp
media/mp4parse-rust/mp4parse-cargo.patch
media/mp4parse-rust/mp4parse/Cargo.toml
media/mp4parse-rust/mp4parse/src/boxes.rs
media/mp4parse-rust/mp4parse/src/lib.rs
media/mp4parse-rust/mp4parse/src/macros.rs
media/mp4parse-rust/mp4parse/src/tests.rs
media/mp4parse-rust/mp4parse/tests/afl.rs
media/mp4parse-rust/mp4parse/tests/public.rs
media/mp4parse-rust/mp4parse_capi/Cargo.toml
media/mp4parse-rust/mp4parse_capi/build.rs
media/mp4parse-rust/mp4parse_capi/src/lib.rs
media/mp4parse-rust/mp4parse_fallible/Cargo.toml
media/mp4parse-rust/mp4parse_fallible/README
media/mp4parse-rust/mp4parse_fallible/lib.rs
media/mp4parse-rust/update-rust.sh
third_party/rust/bitreader/.cargo-checksum.json
third_party/rust/bitreader/Cargo.toml
third_party/rust/bitreader/README.md
third_party/rust/bitreader/src/lib.rs
third_party/rust/bitreader/src/tests.rs
third_party/rust/cfg-if/.cargo-checksum.json
third_party/rust/cfg-if/Cargo.toml
third_party/rust/cfg-if/README.md
third_party/rust/cfg-if/src/lib.rs
third_party/rust/cfg-if/tests/xcrate.rs
third_party/rust/mp4parse_fallible/.cargo-checksum.json
third_party/rust/mp4parse_fallible/CODE_OF_CONDUCT.md
third_party/rust/mp4parse_fallible/Cargo.toml
third_party/rust/mp4parse_fallible/LICENSE
third_party/rust/mp4parse_fallible/README
third_party/rust/mp4parse_fallible/lib.rs
third_party/rust/nom/.cargo-checksum.json
third_party/rust/nom/.travis.yml
tools/lint/clippy.yml
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -289,19 +289,22 @@ dependencies = [
 [[package]]
 name = "bitflags"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
 
 [[package]]
 name = "bitreader"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fa7f0adf37cd5472c978a1ff4be89c1880a923d10df4cfef6a10855a666e09b"
+dependencies = [
+ "cfg-if",
+]
 
 [[package]]
 name = "bits"
 version = "0.2.0"
 dependencies = [
  "comedy",
  "filetime_win",
  "guid_win",
@@ -495,19 +498,19 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
 dependencies = [
  "nom",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 
 [[package]]
 name = "chardetng"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "293267de29bad310dc2cdf4a7d256de9ec27618e3a1a39a395a52ae7f1eef786"
 dependencies = [
  "encoding_rs",
@@ -2712,19 +2715,19 @@ dependencies = [
  "byteorder",
  "log",
  "mp4parse",
  "num-traits",
 ]
 
 [[package]]
 name = "mp4parse_fallible"
-version = "0.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "704f773471ac3e7110427b6bdf93184932b19319c9b7717688da5424e519b10a"
 
 [[package]]
 name = "msdos_time"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
 dependencies = [
  "time",
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,17 +37,16 @@ exclude = [
   "media/cubeb-rs",
 
   # Excluded because they are used only as dependencies, not top-level targets,
   # so we don't need to vendor their dev-dependencies.
   "dom/webauthn/u2f-hid-rs",
   "gfx/webrender_bindings",
   "media/mp4parse-rust/mp4parse",
   "media/mp4parse-rust/mp4parse_capi",
-  "media/mp4parse-rust/mp4parse_fallible",
   "xpcom/rust/gkrust_utils",
   "tools/lint/test/files/clippy",
   "tools/fuzzing/rust",
 ]
 
 # Explicitly specify what our profiles use.  The opt-level setting here is
 # a total fiction; see the setup of MOZ_RUST_DEFAULT_FLAGS for what the
 # opt-level setting will be as a result of various other configure flags.
--- a/dom/media/gtest/mp4_demuxer/TestMP4.cpp
+++ b/dom/media/gtest/mp4_demuxer/TestMP4.cpp
@@ -50,85 +50,81 @@ static intptr_t vector_reader(uint8_t* b
   source->location += length;
   return length;
 }
 
 TEST(rust, MP4MetadataEmpty)
 {
   Mp4parseStatus rv;
   Mp4parseIo io;
+  Mp4parseParser* parser = nullptr;
 
   // Shouldn't be able to read with no context.
-  rv = mp4parse_read(nullptr);
+  rv = mp4parse_new(nullptr, nullptr);
   EXPECT_EQ(rv, MP4PARSE_STATUS_BAD_ARG);
 
   // Shouldn't be able to wrap an Mp4parseIo with null members.
   io = {nullptr, nullptr};
-  Mp4parseParser* context = mp4parse_new(&io);
-  EXPECT_EQ(context, nullptr);
+  rv = mp4parse_new(&io, &parser);
+  EXPECT_EQ(rv, MP4PARSE_STATUS_BAD_ARG);
+  EXPECT_EQ(parser, nullptr);
 
   io = {nullptr, &io};
-  context = mp4parse_new(&io);
-  EXPECT_EQ(context, nullptr);
+  rv = mp4parse_new(&io, &parser);
+  EXPECT_EQ(rv, MP4PARSE_STATUS_BAD_ARG);
+  EXPECT_EQ(parser, nullptr);
 
   // FIXME: this should probably be accepted.
   io = {error_reader, nullptr};
-  context = mp4parse_new(&io);
-  EXPECT_EQ(context, nullptr);
+  rv = mp4parse_new(&io, &parser);
+  EXPECT_EQ(rv, MP4PARSE_STATUS_BAD_ARG);
+  EXPECT_EQ(parser, nullptr);
 
   // Read method errors should propagate.
   io = {error_reader, &io};
-  context = mp4parse_new(&io);
-  ASSERT_NE(context, nullptr);
-  rv = mp4parse_read(context);
+  rv = mp4parse_new(&io, &parser);
+  ASSERT_EQ(parser, nullptr);
   EXPECT_EQ(rv, MP4PARSE_STATUS_IO);
-  mp4parse_free(context);
 
   // Short buffers should fail.
   read_vector buf(0);
   io = {vector_reader, &buf};
-  context = mp4parse_new(&io);
-  ASSERT_NE(context, nullptr);
-  rv = mp4parse_read(context);
+  rv = mp4parse_new(&io, &parser);
+  ASSERT_EQ(parser, nullptr);
   EXPECT_EQ(rv, MP4PARSE_STATUS_INVALID);
-  mp4parse_free(context);
 
   buf.buffer.reserve(4097);
-  context = mp4parse_new(&io);
-  ASSERT_NE(context, nullptr);
-  rv = mp4parse_read(context);
+  rv = mp4parse_new(&io, &parser);
+  ASSERT_EQ(parser, nullptr);
   EXPECT_EQ(rv, MP4PARSE_STATUS_INVALID);
-  mp4parse_free(context);
 
   // Empty buffers should fail.
   buf.buffer.resize(4097, 0);
-  context = mp4parse_new(&io);
-  rv = mp4parse_read(context);
+  rv = mp4parse_new(&io, &parser);
+  ASSERT_EQ(parser, nullptr);
   EXPECT_EQ(rv, MP4PARSE_STATUS_UNSUPPORTED);
-  mp4parse_free(context);
 }
 
 TEST(rust, MP4Metadata)
 {
   FILE* f = fopen("street.mp4", "rb");
   ASSERT_TRUE(f != nullptr);
   // Read just the moov header to work around the parser
   // treating mid-box eof as an error.
   // read_vector reader = read_vector(f, 1061);
   struct stat s;
   ASSERT_EQ(0, fstat(fileno(f), &s));
   read_vector reader = read_vector(f, s.st_size);
   fclose(f);
 
   Mp4parseIo io = {vector_reader, &reader};
-  Mp4parseParser* context = mp4parse_new(&io);
-  ASSERT_NE(nullptr, context);
-
-  Mp4parseStatus rv = mp4parse_read(context);
+  Mp4parseParser* parser = nullptr;
+  Mp4parseStatus rv = mp4parse_new(&io, &parser);
+  ASSERT_NE(nullptr, parser);
   EXPECT_EQ(MP4PARSE_STATUS_OK, rv);
 
   uint32_t tracks = 0;
-  rv = mp4parse_get_track_count(context, &tracks);
+  rv = mp4parse_get_track_count(parser, &tracks);
   EXPECT_EQ(MP4PARSE_STATUS_OK, rv);
   EXPECT_EQ(2U, tracks);
 
-  mp4parse_free(context);
+  mp4parse_free(parser);
 }
--- a/dom/media/mp4/MP4Metadata.cpp
+++ b/dom/media/mp4/MP4Metadata.cpp
@@ -85,31 +85,33 @@ static intptr_t read_source(uint8_t* buf
     return -1;
   }
   return bytes_read;
 }
 
 MP4Metadata::MP4Metadata(ByteStream* aSource)
     : mSource(aSource), mSourceAdaptor(aSource) {
   DDLINKCHILD("source", aSource);
-
-  Mp4parseIo io = {read_source, &mSourceAdaptor};
-  mParser.reset(mp4parse_new(&io));
-  MOZ_ASSERT(mParser);
 }
 
 MP4Metadata::~MP4Metadata() = default;
 
 nsresult MP4Metadata::Parse() {
-  Mp4parseStatus rv = mp4parse_read(mParser.get());
-  if (rv != MP4PARSE_STATUS_OK) {
+  Mp4parseIo io = {read_source, &mSourceAdaptor};
+  Mp4parseParser* parser = nullptr;
+  Mp4parseStatus status = mp4parse_new(&io, &parser);
+  if (status == MP4PARSE_STATUS_OK && parser) {
+    mParser.reset(parser);
+    MOZ_ASSERT(mParser);
+  } else {
+    MOZ_ASSERT(!mParser);
     MOZ_LOG(gMP4MetadataLog, LogLevel::Debug,
-            ("Parse failed, return code %d\n", rv));
-    return rv == MP4PARSE_STATUS_OOM ? NS_ERROR_OUT_OF_MEMORY
-                                     : NS_ERROR_DOM_MEDIA_METADATA_ERR;
+            ("Parse failed, return code %d\n", status));
+    return status == MP4PARSE_STATUS_OOM ? NS_ERROR_OUT_OF_MEMORY
+                                         : NS_ERROR_DOM_MEDIA_METADATA_ERR;
   }
 
   UpdateCrypto();
 
   return NS_OK;
 }
 
 void MP4Metadata::UpdateCrypto() {
--- a/media/mp4parse-rust/mp4parse-cargo.patch
+++ b/media/mp4parse-rust/mp4parse-cargo.patch
@@ -1,23 +1,24 @@
-diff --git a/media/mp4parse-rust/mp4parse_capi/Cargo.toml b/media/mp4parse-rust/mp4parse_capi/Cargo.toml
-index f04ad37ac568..a04b1e977735 100644
---- a/media/mp4parse-rust/mp4parse_capi/Cargo.toml
+diff --git a/media/mp4parse-rust/_upstream/mp4parse/mp4parse_capi/Cargo.toml b/media/mp4parse-rust/mp4parse_capi/Cargo.toml
+index 2c606b4..895739f 100644
+--- a/media/mp4parse-rust/_upstream/mp4parse/mp4parse_capi/Cargo.toml
 +++ b/media/mp4parse-rust/mp4parse_capi/Cargo.toml
-@@ -18,6 +18,8 @@ exclude = [
+@@ -18,8 +18,7 @@ exclude = [
    "*.mp4",
  ]
  
-+build = false
-+
+-[lib]
+-crate-type = ["lib", "cdylib"]
++build = false # See bug 1611431 - Generate mp4parse-rust bindings as part of mach build
+ 
  [badges]
  travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
- 
-@@ -30,9 +32,6 @@ num-traits = "0.2.0"
+@@ -33,9 +32,6 @@ num-traits = "0.2.0"
  [dev-dependencies]
- env_logger = "0.5.3"
+ env_logger = "0.7.1"
  
 -[build-dependencies]
 -cbindgen = "0.5.2"
 -
  [features]
- fuzz = ["mp4parse/fuzz"]
  # Enable mp4parse_fallible to use fallible memory allocation rather than
+ # panicking on OOM.  Note that this is only safe within Gecko where the system
--- a/media/mp4parse-rust/mp4parse/Cargo.toml
+++ b/media/mp4parse-rust/mp4parse/Cargo.toml
@@ -1,15 +1,16 @@
 [package]
 name = "mp4parse"
 version = "0.11.4"
 authors = [
   "Ralph Giles <giles@mozilla.com>",
   "Matthew Gregan <kinetik@flim.org>",
   "Alfredo Yang <ayang@mozilla.com>",
+  "Jon Bauman <jbauman@mozilla.com>",
 ]
 
 description = "Parser for ISO base media file format (mp4)"
 documentation = "https://docs.rs/mp4parse/"
 license = "MPL-2.0"
 categories = ["multimedia::video"]
 
 repository = "https://github.com/mozilla/mp4parse-rust"
@@ -19,21 +20,17 @@ exclude = [
   "*.mp4",
 ]
 
 [badges]
 travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
 
 [dependencies]
 byteorder = "1.2.1"
-afl = { version = "0.3", optional = true }
-abort_on_panic = { version = "1.0.0", optional = true }
-bitreader = { version = "0.3.0" }
+bitreader = { version = "0.3.2" }
 num-traits = "0.2.0"
-mp4parse_fallible = { version = "0.0.1", optional = true }
+mp4parse_fallible = { version = "0.0.3", optional = true }
 log = "0.4"
 static_assertions = "1.1.0"
 
 [dev-dependencies]
 test-assembler = "0.1.2"
-
-[features]
-fuzz = ["afl", "abort_on_panic"]
+env_logger = "0.7.1"
--- a/media/mp4parse-rust/mp4parse/src/boxes.rs
+++ b/media/mp4parse-rust/mp4parse/src/boxes.rs
@@ -37,50 +37,48 @@ macro_rules! box_database {
                 write!(f, "{}", fourcc)
             }
         }
     }
 }
 
 #[derive(Default, PartialEq, Clone)]
 pub struct FourCC {
-    pub value: String
+    pub value: String,
 }
 
 impl From<u32> for FourCC {
     fn from(number: u32) -> FourCC {
         let mut box_chars = Vec::new();
         for x in 0..4 {
             let c = (number >> (x * 8) & 0x0000_00FF) as u8;
             box_chars.push(c);
         }
         box_chars.reverse();
 
         let box_string = match String::from_utf8(box_chars) {
             Ok(t) => t,
             _ => String::from("null"), // error to retrieve fourcc
         };
 
-        FourCC {
-            value: box_string
-        }
+        FourCC { value: box_string }
     }
 }
 
 impl From<BoxType> for FourCC {
     fn from(t: BoxType) -> FourCC {
         let box_num: u32 = Into::into(t);
         From::from(box_num)
     }
 }
 
 impl<'a> From<&'a str> for FourCC {
     fn from(v: &'a str) -> FourCC {
         FourCC {
-            value: v.to_owned()
+            value: v.to_owned(),
         }
     }
 }
 
 impl fmt::Debug for FourCC {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.value)
     }
@@ -89,16 +87,21 @@ impl fmt::Debug for FourCC {
 impl fmt::Display for FourCC {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.value)
     }
 }
 
 box_database!(
     FileTypeBox                       0x6674_7970, // "ftyp"
+    MediaDataBox                      0x6d64_6174, // "mdat"
+    PrimaryItemBox                    0x7069_746d, // "pitm"
+    ItemInfoBox                       0x6969_6e66, // "iinf"
+    ItemInfoEntry                     0x696e_6665, // "infe"
+    ItemLocationBox                   0x696c_6f63, // "iloc"
     MovieBox                          0x6d6f_6f76, // "moov"
     MovieHeaderBox                    0x6d76_6864, // "mvhd"
     TrackBox                          0x7472_616b, // "trak"
     TrackHeaderBox                    0x746b_6864, // "tkhd"
     EditBox                           0x6564_7473, // "edts"
     MediaBox                          0x6d64_6961, // "mdia"
     EditListBox                       0x656c_7374, // "elst"
     MediaHeaderBox                    0x6d64_6864, // "mdhd"
@@ -130,31 +133,30 @@ box_database!(
     ProtectedVisualSampleEntry        0x656e_6376, // "encv" - Need to check official name in spec.
     ProtectedAudioSampleEntry         0x656e_6361, // "enca" - Need to check official name in spec.
     MovieExtendsBox                   0x6d76_6578, // "mvex"
     MovieExtendsHeaderBox             0x6d65_6864, // "mehd"
     QTWaveAtom                        0x7761_7665, // "wave" - quicktime atom
     ProtectionSystemSpecificHeaderBox 0x7073_7368, // "pssh"
     SchemeInformationBox              0x7363_6869, // "schi"
     TrackEncryptionBox                0x7465_6e63, // "tenc"
-    ProtectionSchemeInformationBox    0x7369_6e66, // "sinf"
+    ProtectionSchemeInfoBox           0x7369_6e66, // "sinf"
     OriginalFormatBox                 0x6672_6d61, // "frma"
     SchemeTypeBox                     0x7363_686d, // "schm"
     MP3AudioSampleEntry               0x2e6d_7033, // ".mp3" - from F4V.
     CompositionOffsetBox              0x6374_7473, // "ctts"
     LPCMAudioSampleEntry              0x6C70_636D, // "lpcm" - quicktime atom
     ALACSpecificBox                   0x616C_6163, // "alac" - Also used by ALACSampleEntry
     UuidBox                           0x7575_6964, // "uuid"
     MetadataBox                       0x6d65_7461, // "meta"
     MetadataHeaderBox                 0x6d68_6472, // "mhdr"
     MetadataItemKeysBox               0x6b65_7973, // "keys"
     MetadataItemListEntry             0x696c_7374, // "ilst"
     MetadataItemDataEntry             0x6461_7461, // "data"
     MetadataItemNameBox               0x6e61_6d65, // "name"
-    MetadataItemInformationBox        0x6974_6966, // "itif"
     UserdataBox                       0x7564_7461, // "udta"
     AlbumEntry                        0xa961_6c62, // "©alb"
     ArtistEntry                       0xa941_5254, // "©ART"
     ArtistLowercaseEntry              0xa961_7274, // "©art"
     AlbumArtistEntry                  0x6141_5254, // "aART"
     CommentEntry                      0xa963_6d74, // "©cmt"
     DateEntry                         0xa964_6179, // "©day"
     TitleEntry                        0xa96e_616d, // "©nam"
--- a/media/mp4parse-rust/mp4parse/src/lib.rs
+++ b/media/mp4parse-rust/mp4parse/src/lib.rs
@@ -1,28 +1,27 @@
 //! Module for parsing ISO Base Media Format aka video/mp4 streams.
 
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
-#[cfg(feature = "fuzz")]
-extern crate afl;
 
 #[macro_use]
 extern crate log;
 
+extern crate bitreader;
 extern crate byteorder;
-extern crate bitreader;
 extern crate num_traits;
-use byteorder::{ReadBytesExt, WriteBytesExt};
 use bitreader::{BitReader, ReadInto};
-use std::convert::TryInto as _;
+use byteorder::{ReadBytesExt, WriteBytesExt};
+use num_traits::Num;
+use std::convert::{TryFrom, TryInto as _};
+use std::io::Cursor;
 use std::io::{Read, Take};
-use std::io::Cursor;
-use num_traits::Num;
+use std::ops::{Range, RangeFrom};
 
 #[cfg(feature = "mp4parse_fallible")]
 extern crate mp4parse_fallible;
 
 #[cfg(feature = "mp4parse_fallible")]
 use mp4parse_fallible::FallibleVec;
 
 #[macro_use]
@@ -31,34 +30,36 @@ mod macros;
 mod boxes;
 use boxes::{BoxType, FourCC};
 
 // Unit tests.
 #[cfg(test)]
 mod tests;
 
 // Arbitrary buffer size limit used for raw read_bufs on a box.
-const BUF_SIZE_LIMIT: usize = 10 * 1024 * 1024;
-
-// Max table length. Calculating in worth case for one week long video, one
+const BUF_SIZE_LIMIT: u64 = 10 * 1024 * 1024;
+
+// Max table length. Calculating in worst case for one week long video, one
 // frame per table entry in 30 fps.
 const TABLE_SIZE_LIMIT: u32 = 30 * 60 * 60 * 24 * 7;
 
 /// A trait to indicate a type can be infallibly converted to `u64`.
 /// This should only be implemented for infallible conversions, so only unsigned types are valid.
 trait ToU64 {
     fn to_u64(self) -> u64;
 }
 
 /// Statically verify that the platform `usize` can fit within a `u64`.
 /// If the size won't fit on the given platform, this will fail at compile time, but if a type
 /// which can fail TryInto<usize> is used, it may panic.
 impl ToU64 for usize {
     fn to_u64(self) -> u64 {
-        static_assertions::const_assert!(std::mem::size_of::<usize>() <= std::mem::size_of::<u64>());
+        static_assertions::const_assert!(
+            std::mem::size_of::<usize>() <= std::mem::size_of::<u64>()
+        );
         self.try_into().expect("usize -> u64 conversion failed")
     }
 }
 
 /// A trait to indicate a type can be infallibly converted to `usize`.
 /// This should only be implemented for infallible conversions, so only unsigned types are valid.
 trait ToUsize {
     fn to_usize(self) -> usize;
@@ -66,51 +67,131 @@ trait ToUsize {
 
 /// Statically verify that the given type can fit within a `usize`.
 /// If the size won't fit on the given platform, this will fail at compile time, but if a type
 /// which can fail TryInto<usize> is used, it may panic.
 macro_rules! impl_to_usize_from {
     ( $from_type:ty ) => {
         impl ToUsize for $from_type {
             fn to_usize(self) -> usize {
-                static_assertions::const_assert!(std::mem::size_of::<$from_type>() <= std::mem::size_of::<usize>());
-                self.try_into().expect(concat!(stringify!($from_type), " -> usize conversion failed"))
+                static_assertions::const_assert!(
+                    std::mem::size_of::<$from_type>() <= std::mem::size_of::<usize>()
+                );
+                self.try_into().expect(concat!(
+                    stringify!($from_type),
+                    " -> usize conversion failed"
+                ))
             }
         }
-    }
+    };
 }
 
 impl_to_usize_from!(u8);
 impl_to_usize_from!(u16);
 impl_to_usize_from!(u32);
 
+/// Indicate the current offset (i.e., bytes already read) in a reader
+trait Offset {
+    fn offset(&self) -> u64;
+}
+
+/// Wraps a reader to track the current offset
+struct OffsetReader<'a, T: 'a> {
+    reader: &'a mut T,
+    offset: u64,
+}
+
+impl<'a, T> OffsetReader<'a, T> {
+    fn new(reader: &'a mut T) -> Self {
+        Self { reader, offset: 0 }
+    }
+}
+
+impl<'a, T> Offset for OffsetReader<'a, T> {
+    fn offset(&self) -> u64 {
+        self.offset
+    }
+}
+
+impl<'a, T: Read> Read for OffsetReader<'a, T> {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        let bytes_read = self.reader.read(buf)?;
+        self.offset = self
+            .offset
+            .checked_add(bytes_read.to_u64())
+            .expect("total bytes read too large for offset type");
+        Ok(bytes_read)
+    }
+}
+
 // TODO: vec_push() needs to be replaced when Rust supports fallible memory
 // allocation in raw_vec.
 #[allow(unreachable_code)]
 pub fn vec_push<T>(vec: &mut Vec<T>, val: T) -> std::result::Result<(), ()> {
     #[cfg(feature = "mp4parse_fallible")]
     {
         return FallibleVec::try_push(vec, val);
     }
 
     vec.push(val);
     Ok(())
 }
 
-#[allow(unreachable_code)]
-fn allocate_read_buf(size: usize) -> std::result::Result<Vec<u8>, ()> {
+fn vec_with_capacity<T>(capacity: usize) -> std::result::Result<Vec<T>, ()> {
+    #[cfg(feature = "mp4parse_fallible")]
+    {
+        let mut v = Vec::new();
+        FallibleVec::try_reserve(&mut v, capacity)?;
+        Ok(v)
+    }
+    #[cfg(not(feature = "mp4parse_fallible"))]
+    {
+        Ok(Vec::with_capacity(capacity))
+    }
+}
+
+pub fn extend_from_slice<T: Clone>(vec: &mut Vec<T>, other: &[T]) -> std::result::Result<(), ()> {
     #[cfg(feature = "mp4parse_fallible")]
     {
-        let mut buf: Vec<u8> = Vec::new();
-        FallibleVec::try_reserve(&mut buf, size)?;
-        buf.extend(std::iter::repeat(0).take(size));
-        return Ok(buf);
+        FallibleVec::try_extend_from_slice(vec, other)
+    }
+    #[cfg(not(feature = "mp4parse_fallible"))]
+    {
+        vec.extend_from_slice(other);
+        Ok(())
     }
-
-    Ok(vec![0; size])
+}
+
+/// With the `mp4parse_fallible` feature enabled, this function reserves the
+/// upper limit of what `src` can generate before reading all bytes until EOF
+/// in this source, placing them into buf. If the allocation is unsuccessful,
+/// or reading from the source generates an error before reaching EOF, this
+/// will return an error. Otherwise, it will return the number of bytes read.
+///
+/// Since `src.limit()` may return a value greater than the number of bytes
+/// which can be read from the source, it's possible this function may fail
+/// in the allocation phase even though allocating the number of bytes available
+/// to read would have succeeded. In general, it is assumed that the callers
+/// have accurate knowledge of the number of bytes of interest and have created
+/// `src` accordingly.
+///
+/// With the `mp4parse_fallible` feature disabled, this is wrapper around
+/// `std::io::Read::read_to_end()`.
+fn read_to_end<T: Read>(src: &mut Take<T>, buf: &mut Vec<u8>) -> std::result::Result<usize, ()> {
+    #[cfg(feature = "mp4parse_fallible")]
+    {
+        let limit: usize = src.limit().try_into().map_err(|_| ())?;
+        FallibleVec::try_reserve(buf, limit)?;
+        let bytes_read = src.read_to_end(buf).map_err(|_| ())?;
+        Ok(bytes_read)
+    }
+    #[cfg(not(feature = "mp4parse_fallible"))]
+    {
+        src.read_to_end(buf).map_err(|_| ())
+    }
 }
 
 /// Describes parser failures.
 ///
 /// This enum wraps the standard `io::Error` type, unified with
 /// our own parser error states and those of crates we use.
 #[derive(Debug)]
 pub enum Error {
@@ -499,17 +580,17 @@ pub struct ProtectionSchemeInfoBox {
     pub tenc: Option<TrackEncryptionBox>,
 }
 
 /// Represents a userdata box 'udta'.
 /// Currently, only the metadata atom 'meta'
 /// is parsed.
 #[derive(Debug, Default, Clone)]
 pub struct UserdataBox {
-    pub meta: Option<MetadataBox>
+    pub meta: Option<MetadataBox>,
 }
 
 /// Represents possible contents of the
 /// ©gen or gnre atoms within a metadata box.
 /// 'udta.meta.ilst' may only have either a
 /// standard genre box 'gnre' or a custom
 /// genre box '©gen', but never both at once.
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -684,48 +765,231 @@ pub struct MediaContext {
 }
 
 impl MediaContext {
     pub fn new() -> MediaContext {
         Default::default()
     }
 }
 
+#[derive(Debug, Default)]
+pub struct AvifContext {
+    /// The collected data indicated by the `pitm` box, See ISO 14496-12:2015 § 8.11.4
+    pub primary_item: Vec<u8>,
+}
+
+impl AvifContext {
+    pub fn new() -> Self {
+        Default::default()
+    }
+}
+
+/// A Media Data Box
+/// See ISO 14496-12:2015 § 8.1.1
+struct MediaDataBox {
+    /// Offset of `data` from the beginning of the file. See ConstructionMethod::File
+    offset: u64,
+    data: Vec<u8>,
+}
+
+impl MediaDataBox {
+    /// Check whether the beginning of `extent` is within the bounds of the `MediaDataBox`.
+    /// We assume extents to not cross box boundaries. If so, this will cause an error
+    /// in `read_extent`.
+    fn contains_extent(&self, extent: &ExtentRange) -> bool {
+        if self.offset <= extent.start() {
+            let start_offset = extent.start() - self.offset;
+            start_offset < self.data.len().to_u64()
+        } else {
+            false
+        }
+    }
+
+    /// Check whether `extent` covers the `MediaDataBox` exactly.
+    fn matches_extent(&self, extent: &ExtentRange) -> bool {
+        if self.offset == extent.start() {
+            match extent {
+                ExtentRange::WithLength(range) => {
+                    if let Some(end) = self.offset.checked_add(self.data.len().to_u64()) {
+                        end == range.end
+                    } else {
+                        false
+                    }
+                }
+                ExtentRange::ToEnd(_) => true,
+            }
+        } else {
+            false
+        }
+    }
+
+    /// Copy the range specified by `extent` to the end of `buf` or return an error if the range
+    /// is not fully contained within `MediaDataBox`.
+    fn read_extent(&mut self, extent: &ExtentRange, buf: &mut Vec<u8>) -> Result<()> {
+        let start_offset = extent
+            .start()
+            .checked_sub(self.offset)
+            .expect("mdat does not contain extent");
+        let slice = match extent {
+            ExtentRange::WithLength(range) => {
+                let range_len = range
+                    .end
+                    .checked_sub(range.start)
+                    .expect("range start > end");
+                let end = start_offset
+                    .checked_add(range_len)
+                    .expect("extent end overflow");
+                self.data.get(start_offset.try_into()?..end.try_into()?)
+            }
+            ExtentRange::ToEnd(_) => self.data.get(start_offset.try_into()?..),
+        };
+        let slice = slice.ok_or(Error::InvalidData("extent crosses box boundary"))?;
+        extend_from_slice(buf, slice)?;
+        Ok(())
+    }
+}
+
+/// Used for 'infe' boxes within 'iinf' boxes
+/// See ISO 14496-12:2015 § 8.11.6
+/// Only versions {2, 3} are supported
+#[derive(Debug)]
+struct ItemInfoEntry {
+    item_id: u32,
+    item_type: u32,
+}
+
+/// Potential sizes (in bytes) of variable-sized fields of the 'iloc' box
+/// See ISO 14496-12:2015 § 8.11.3
+enum IlocFieldSize {
+    Zero,
+    Four,
+    Eight,
+}
+
+impl IlocFieldSize {
+    fn to_bits(&self) -> u8 {
+        match self {
+            IlocFieldSize::Zero => 0,
+            IlocFieldSize::Four => 32,
+            IlocFieldSize::Eight => 64,
+        }
+    }
+}
+
+impl TryFrom<u8> for IlocFieldSize {
+    type Error = Error;
+
+    fn try_from(value: u8) -> Result<Self> {
+        match value {
+            0 => Ok(Self::Zero),
+            4 => Ok(Self::Four),
+            8 => Ok(Self::Eight),
+            _ => Err(Error::InvalidData("value must be in the set {0, 4, 8}")),
+        }
+    }
+}
+
+#[derive(PartialEq)]
+enum IlocVersion {
+    Zero,
+    One,
+    Two,
+}
+
+impl TryFrom<u8> for IlocVersion {
+    type Error = Error;
+
+    fn try_from(value: u8) -> Result<Self> {
+        match value {
+            0 => Ok(Self::Zero),
+            1 => Ok(Self::One),
+            2 => Ok(Self::Two),
+            _ => Err(Error::Unsupported("unsupported version in 'iloc' box")),
+        }
+    }
+}
+
+/// Used for 'iloc' boxes
+/// See ISO 14496-12:2015 § 8.11.3
+/// `base_offset` is omitted since it is integrated into the ranges in `extents`
+/// `data_reference_index` is omitted, since only 0 (i.e., this file) is supported
+#[derive(Clone, Debug)]
+struct ItemLocationBoxItem {
+    item_id: u32,
+    construction_method: ConstructionMethod,
+    /// Unused for ConstructionMethod::Idat
+    extents: Vec<ItemLocationBoxExtent>,
+}
+
+#[derive(Clone, Copy, Debug)]
+enum ConstructionMethod {
+    File,
+    Idat,
+    #[allow(dead_code)] // TODO: see https://github.com/mozilla/mp4parse-rust/issues/196
+    Item,
+}
+
+/// `extent_index` is omitted since it's only used for ConstructionMethod::Item which
+/// is currently not implemented.
+#[derive(Clone, Debug)]
+struct ItemLocationBoxExtent {
+    extent_range: ExtentRange,
+}
+
+#[derive(Clone, Debug)]
+enum ExtentRange {
+    WithLength(Range<u64>),
+    ToEnd(RangeFrom<u64>),
+}
+
+impl ExtentRange {
+    fn start(&self) -> u64 {
+        match self {
+            Self::WithLength(r) => r.start,
+            Self::ToEnd(r) => r.start,
+        }
+    }
+}
+
 #[derive(Debug, PartialEq)]
 pub enum TrackType {
     Audio,
     Video,
     Metadata,
     Unknown,
 }
 
 impl Default for TrackType {
-    fn default() -> Self { TrackType::Unknown }
+    fn default() -> Self {
+        TrackType::Unknown
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum CodecType {
     Unknown,
     MP3,
     AAC,
     FLAC,
     Opus,
-    H264,   // 14496-10
-    MP4V,   // 14496-2
+    H264, // 14496-10
+    MP4V, // 14496-2
     AV1,
     VP9,
     VP8,
     EncryptedVideo,
     EncryptedAudio,
-    LPCM,   // QT
+    LPCM, // QT
     ALAC,
 }
 
 impl Default for CodecType {
-    fn default() -> Self { CodecType::Unknown }
+    fn default() -> Self {
+        CodecType::Unknown
+    }
 }
 
 /// The media's global (mvhd) timescale in units per second.
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct MediaTimeScale(pub u64);
 
 /// A time to be scaled by the media's global (mvhd) timescale.
 #[derive(Debug, Copy, Clone, PartialEq)]
@@ -736,17 +1000,20 @@ pub struct MediaScaledTime(pub u64);
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct TrackTimeScale<T: Num>(pub T, pub usize);
 
 /// A time to be scaled by the track's local (mdhd) timescale.
 /// Members are time in scale units and the track id.
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct TrackScaledTime<T: Num>(pub T, pub usize);
 
-impl <T> std::ops::Add for TrackScaledTime<T> where T: Num {
+impl<T> std::ops::Add for TrackScaledTime<T>
+where
+    T: Num,
+{
     type Output = TrackScaledTime<T>;
 
     fn add(self, other: TrackScaledTime<T>) -> TrackScaledTime<T> {
         TrackScaledTime::<T>(self.0 + other.0, self.1)
     }
 }
 
 #[derive(Debug, Default)]
@@ -758,24 +1025,27 @@ pub struct Track {
     pub timescale: Option<TrackTimeScale<u64>>,
     pub duration: Option<TrackScaledTime<u64>>,
     pub track_id: Option<u32>,
     pub tkhd: Option<TrackHeaderBox>, // TODO(kinetik): find a nicer way to export this.
     pub stsd: Option<SampleDescriptionBox>,
     pub stts: Option<TimeToSampleBox>,
     pub stsc: Option<SampleToChunkBox>,
     pub stsz: Option<SampleSizeBox>,
-    pub stco: Option<ChunkOffsetBox>,   // It is for stco or co64.
+    pub stco: Option<ChunkOffsetBox>, // It is for stco or co64.
     pub stss: Option<SyncSampleBox>,
     pub ctts: Option<CompositionOffsetBox>,
 }
 
 impl Track {
     fn new(id: usize) -> Track {
-        Track { id, ..Default::default() }
+        Track {
+            id,
+            ..Default::default()
+        }
     }
 }
 
 struct BMFFBox<'a, T: 'a> {
     head: BoxHeader,
     content: Take<&'a mut T>,
 }
 
@@ -802,30 +1072,76 @@ impl<'a, T: Read> BoxIter<'a, T> {
 }
 
 impl<'a, T: Read> Read for BMFFBox<'a, T> {
     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
         self.content.read(buf)
     }
 }
 
+impl<'a, T: Offset> Offset for BMFFBox<'a, T> {
+    fn offset(&self) -> u64 {
+        self.content.get_ref().offset()
+    }
+}
+
 impl<'a, T: Read> BMFFBox<'a, T> {
     fn bytes_left(&self) -> u64 {
         self.content.limit()
     }
 
     fn get_header(&self) -> &BoxHeader {
         &self.head
     }
 
     fn box_iter<'b>(&'b mut self) -> BoxIter<BMFFBox<'a, T>> {
         BoxIter::new(self)
     }
 }
 
+impl<'a, T: Read + Offset> BMFFBox<'a, T> {
+    /// Check whether the beginning of `extent` is within the bounds of the `BMFFBox`.
+    /// We assume extents to not cross box boundaries. If so, this will cause an error
+    /// in `read_extent`.
+    fn contains_extent(&self, extent: &ExtentRange) -> bool {
+        if self.offset() <= extent.start() {
+            let start_offset = extent.start() - self.offset();
+            start_offset < self.bytes_left()
+        } else {
+            false
+        }
+    }
+
+    /// Read the range specified by `extent` into `buf` or return an error if the range is not
+    /// fully contained within the `BMFFBox`.
+    fn read_extent(&mut self, extent: &ExtentRange, buf: &mut Vec<u8>) -> Result<()> {
+        let start_offset = extent
+            .start()
+            .checked_sub(self.offset())
+            .expect("box does not contain extent");
+        skip(self, start_offset)?;
+        match extent {
+            ExtentRange::WithLength(range) => {
+                let len = range
+                    .end
+                    .checked_sub(range.start)
+                    .expect("range start > end");
+                if len > self.bytes_left() {
+                    return Err(Error::InvalidData("extent crosses box boundary"));
+                }
+                read_to_end(&mut self.take(len), buf)?;
+            }
+            ExtentRange::ToEnd(_) => {
+                read_to_end(&mut self.take(self.bytes_left()), buf)?;
+            }
+        }
+        Ok(())
+    }
+}
+
 impl<'a, T> Drop for BMFFBox<'a, T> {
     fn drop(&mut self) {
         if self.content.limit() > 0 {
             let name: FourCC = From::from(self.head.name);
             debug!("Dropping {} bytes in '{}'", self.content.limit(), name);
         }
     }
 }
@@ -844,17 +1160,17 @@ fn read_box_header<T: ReadBytesExt>(src:
         0 => return Err(Error::Unsupported("unknown sized box")),
         1 => {
             let size64 = be_u64(src)?;
             if size64 < 16 {
                 return Err(Error::InvalidData("malformed wide size"));
             }
             size64
         }
-        2 ..= 7 => return Err(Error::InvalidData("malformed size")),
+        2..=7 => return Err(Error::InvalidData("malformed size")),
         _ => u64::from(size32),
     };
     let mut offset = match size32 {
         1 => 4 + 4 + 8,
         _ => 4 + 4,
     };
     let uuid = if name == BoxType::UuidBox {
         if size >= offset + 16 {
@@ -884,43 +1200,443 @@ fn read_box_header<T: ReadBytesExt>(src:
 }
 
 /// Parse the extra header fields for a full box.
 fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> Result<(u8, u32)> {
     let version = src.read_u8()?;
     let flags_a = src.read_u8()?;
     let flags_b = src.read_u8()?;
     let flags_c = src.read_u8()?;
-    Ok((version,
-        u32::from(flags_a) << 16 | u32::from(flags_b) << 8 | u32::from(flags_c)))
+    Ok((
+        version,
+        u32::from(flags_a) << 16 | u32::from(flags_b) << 8 | u32::from(flags_c),
+    ))
+}
+
+// Parse the extra fields for a full box whose flag fields must be zero.
+fn read_fullbox_version_no_flags<T: ReadBytesExt>(src: &mut T) -> Result<u8> {
+    let (version, flags) = read_fullbox_extra(src)?;
+
+    if flags != 0 {
+        return Err(Error::Unsupported("expected flags to be 0"));
+    }
+
+    Ok(version)
 }
 
 /// Skip over the entire contents of a box.
 fn skip_box_content<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
     // Skip the contents of unknown chunks.
     let to_skip = {
         let header = src.get_header();
         debug!("{:?} (skipped)", header);
-        header.size.checked_sub(header.offset).expect("header offset > size")
+        header
+            .size
+            .checked_sub(header.offset)
+            .expect("header offset > size")
     };
     assert_eq!(to_skip, src.bytes_left());
     skip(src, to_skip)
 }
 
 /// Skip over the remain data of a box.
 fn skip_box_remain<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
     let remain = {
         let header = src.get_header();
         let len = src.bytes_left();
         debug!("remain {} (skipped) in {:?}", len, header);
         len
     };
     skip(src, remain)
 }
 
+/// Read the contents of an AVIF file
+///
+/// Metadata is accumulated in the passed-through `AvifContext` struct,
+/// which can be examined later.
+pub fn read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()> {
+    let mut f = OffsetReader::new(f);
+
+    let mut iter = BoxIter::new(&mut f);
+
+    // 'ftyp' box must occur first; see ISO 14496-12:2015 § 4.3.1
+    if let Some(mut b) = iter.next_box()? {
+        if b.head.name == BoxType::FileTypeBox {
+            let ftyp = read_ftyp(&mut b)?;
+            if !ftyp.compatible_brands.contains(&FourCC::from("mif1")) {
+                return Err(Error::InvalidData("compatible_brands must contain 'mif1'"));
+            }
+        } else {
+            return Err(Error::InvalidData("'ftyp' box must occur first"));
+        }
+    }
+
+    let mut read_meta = false;
+    let mut mdats = vec![];
+    let mut primary_item_extents = None;
+    let mut primary_item_extents_data: Vec<Vec<u8>> = vec![];
+
+    while let Some(mut b) = iter.next_box()? {
+        match b.head.name {
+            BoxType::MetadataBox => {
+                if read_meta {
+                    return Err(Error::InvalidData(
+                        "There should be zero or one meta boxes per ISO 14496-12:2015 § 8.11.1.1",
+                    ));
+                }
+                read_meta = true;
+                let primary_item_loc = read_avif_meta(&mut b)?;
+                match primary_item_loc.construction_method {
+                    ConstructionMethod::File => {
+                        primary_item_extents = Some(primary_item_loc.extents);
+                        primary_item_extents_data =
+                            primary_item_extents.iter().map(|_| vec![]).collect();
+                    }
+                    _ => return Err(Error::Unsupported("unsupported construction_method")),
+                }
+            }
+            BoxType::MediaDataBox => {
+                // See ISO 14496-12:2015 § 8.1.1
+                // If we know our primary item location by this point, try to read it out of this
+                // mdat directly and avoid a copy
+                if let Some(extents) = &primary_item_extents {
+                    for (extent, data) in extents.iter().zip(primary_item_extents_data.iter_mut()) {
+                        if b.contains_extent(&extent.extent_range) {
+                            b.read_extent(&extent.extent_range, data)?;
+                        }
+                    }
+                }
+
+                // Store any remaining data for potential later extraction
+                if b.bytes_left() > 0 {
+                    let offset = b.offset();
+                    let mut data = vec_with_capacity(b.bytes_left().try_into()?)?;
+                    b.read_to_end(&mut data)?;
+                    vec_push(&mut mdats, MediaDataBox { offset, data })?;
+                }
+            }
+            _ => skip_box_content(&mut b)?,
+        }
+
+        check_parser_state!(b.content);
+    }
+
+    // If the `mdat` box came before the `meta` box, we need to fill in our primary item data
+    let primary_item_extents =
+        primary_item_extents.ok_or(Error::InvalidData("primary item extents missing"))?;
+    for (extent, data) in primary_item_extents
+        .iter()
+        .zip(primary_item_extents_data.iter_mut())
+    {
+        if data.is_empty() {
+            // try to find an overlapping mdat
+            for mdat in &mut mdats {
+                if mdat.matches_extent(&extent.extent_range) {
+                    data.append(&mut mdat.data)
+                } else if mdat.contains_extent(&extent.extent_range) {
+                    mdat.read_extent(&extent.extent_range, data)?;
+                }
+            }
+        }
+    }
+
+    context.primary_item = primary_item_extents_data.concat();
+
+    Ok(())
+}
+
+/// Parse a metadata box in the context of an AVIF
+/// Currently requires the primary item to be an av01 item type and generates
+/// an error otherwise.
+/// See ISO 14496-12:2015 § 8.11.1
+fn read_avif_meta<T: Read + Offset>(src: &mut BMFFBox<T>) -> Result<ItemLocationBoxItem> {
+    let version = read_fullbox_version_no_flags(src)?;
+
+    if version != 0 {
+        return Err(Error::Unsupported("unsupported meta version"));
+    }
+
+    let mut primary_item_id = None;
+    let mut item_infos = None;
+    let mut iloc_items = None;
+
+    let mut iter = src.box_iter();
+    while let Some(mut b) = iter.next_box()? {
+        match b.head.name {
+            BoxType::ItemInfoBox => {
+                if item_infos.is_some() {
+                    return Err(Error::InvalidData(
+                        "There should be zero or one iinf boxes per ISO 14496-12:2015 § 8.11.6.1",
+                    ));
+                }
+                item_infos = Some(read_iinf(&mut b)?);
+            }
+            BoxType::ItemLocationBox => {
+                if iloc_items.is_some() {
+                    return Err(Error::InvalidData(
+                        "There should be zero or one iloc boxes per ISO 14496-12:2015 § 8.11.3.1",
+                    ));
+                }
+                iloc_items = Some(read_iloc(&mut b)?);
+            }
+            BoxType::PrimaryItemBox => {
+                if primary_item_id.is_some() {
+                    return Err(Error::InvalidData(
+                        "There should be zero or one iloc boxes per ISO 14496-12:2015 § 8.11.4.1",
+                    ));
+                }
+                primary_item_id = Some(read_pitm(&mut b)?);
+            }
+            _ => skip_box_content(&mut b)?,
+        }
+
+        check_parser_state!(b.content);
+    }
+
+    let primary_item_id = primary_item_id.ok_or(Error::InvalidData(
+        "Required pitm box not present in meta box",
+    ))?;
+
+    if let Some(item_info) = item_infos
+        .iter()
+        .flatten()
+        .find(|x| x.item_id == primary_item_id)
+    {
+        if &item_info.item_type.to_be_bytes() != b"av01" {
+            warn!(
+                "primary_item_id type: {}",
+                be_u32_to_string(item_info.item_type)
+            );
+            return Err(Error::InvalidData("primary_item_id type is not av01"));
+        }
+    } else {
+        return Err(Error::InvalidData(
+            "primary_item_id not present in iinf box",
+        ));
+    }
+
+    if let Some(loc) = iloc_items
+        .iter()
+        .flatten()
+        .find(|loc| loc.item_id == primary_item_id)
+    {
+        Ok(loc.clone())
+    } else {
+        Err(Error::InvalidData(
+            "primary_item_id not present in iloc box",
+        ))
+    }
+}
+
+/// Parse a Primary Item Box
+/// See ISO 14496-12:2015 § 8.11.4
+fn read_pitm<T: Read>(src: &mut BMFFBox<T>) -> Result<u32> {
+    let version = read_fullbox_version_no_flags(src)?;
+
+    let item_id = match version {
+        0 => be_u16(src)?.into(),
+        1 => be_u32(src)?,
+        _ => return Err(Error::Unsupported("unsupported pitm version")),
+    };
+
+    Ok(item_id)
+}
+
+/// Parse an Item Information Box
+/// See ISO 14496-12:2015 § 8.11.6
+fn read_iinf<T: Read>(src: &mut BMFFBox<T>) -> Result<Vec<ItemInfoEntry>> {
+    let version = read_fullbox_version_no_flags(src)?;
+
+    match version {
+        0 | 1 => (),
+        _ => return Err(Error::Unsupported("unsupported iinf version")),
+    }
+
+    let entry_count = if version == 0 {
+        be_u16(src)?.to_usize()
+    } else {
+        be_u32(src)?.to_usize()
+    };
+    let mut item_infos = vec_with_capacity(entry_count)?;
+
+    let mut iter = src.box_iter();
+    while let Some(mut b) = iter.next_box()? {
+        if b.head.name != BoxType::ItemInfoEntry {
+            return Err(Error::InvalidData(
+                "iinf box should contain only infe boxes",
+            ));
+        }
+
+        vec_push(&mut item_infos, read_infe(&mut b)?)?;
+
+        check_parser_state!(b.content);
+    }
+
+    Ok(item_infos)
+}
+
+fn be_u32_to_string(src: u32) -> String {
+    String::from_utf8(src.to_be_bytes().to_vec()).unwrap_or(format!("{:x?}", src))
+}
+
+/// Parse an Item Info Entry
+/// See ISO 14496-12:2015 § 8.11.6.2
+fn read_infe<T: Read>(src: &mut BMFFBox<T>) -> Result<ItemInfoEntry> {
+    // According to the standard, it seems the flags field should be 0, but
+    // at least one sample AVIF image has a nonzero value.
+    let (version, _) = read_fullbox_extra(src)?;
+
+    // mif1 brand (see ISO 23008-12:2017 § 10.2.1) only requires v2 and 3
+    let item_id = match version {
+        2 => be_u16(src)?.into(),
+        3 => be_u32(src)?,
+        _ => return Err(Error::Unsupported("unsupported version in 'infe' box")),
+    };
+
+    let item_protection_index = be_u16(src)?;
+
+    if item_protection_index != 0 {
+        return Err(Error::Unsupported(
+            "protected items (infe.item_protection_index != 0) are not supported",
+        ));
+    }
+
+    let item_type = be_u32(src)?;
+    debug!(
+        "infe item_id {} item_type: {}",
+        item_id,
+        be_u32_to_string(item_type)
+    );
+
+    // There are some additional fields here, but they're not of interest to us
+    skip_box_remain(src)?;
+
+    Ok(ItemInfoEntry { item_id, item_type })
+}
+
+/// Parse an item location box inside a meta box
+/// See ISO 14496-12:2015 § 8.11.3
+fn read_iloc<T: Read>(src: &mut BMFFBox<T>) -> Result<Vec<ItemLocationBoxItem>> {
+    let version: IlocVersion = read_fullbox_version_no_flags(src)?.try_into()?;
+
+    let mut iloc = vec_with_capacity(src.bytes_left().try_into()?)?;
+    src.read_to_end(&mut iloc)?;
+    let mut iloc = BitReader::new(iloc.as_slice());
+
+    let offset_size: IlocFieldSize = iloc.read_u8(4)?.try_into()?;
+    let length_size: IlocFieldSize = iloc.read_u8(4)?.try_into()?;
+    let base_offset_size: IlocFieldSize = iloc.read_u8(4)?.try_into()?;
+
+    let index_size: Option<IlocFieldSize> = match version {
+        IlocVersion::One | IlocVersion::Two => Some(iloc.read_u8(4)?.try_into()?),
+        IlocVersion::Zero => {
+            let _reserved = iloc.read_u8(4)?;
+            None
+        }
+    };
+
+    let item_count = match version {
+        IlocVersion::Zero | IlocVersion::One => iloc.read_u32(16)?,
+        IlocVersion::Two => iloc.read_u32(32)?,
+    };
+
+    let mut items = vec_with_capacity(item_count.to_usize())?;
+
+    for _ in 0..item_count {
+        let item_id = match version {
+            IlocVersion::Zero | IlocVersion::One => iloc.read_u32(16)?,
+            IlocVersion::Two => iloc.read_u32(32)?,
+        };
+
+        // The spec isn't entirely clear how an `iloc` should be interpreted for version 0,
+        // which has no `construction_method` field. It does say:
+        // "For maximum compatibility, version 0 of this box should be used in preference to
+        //  version 1 with `construction_method==0`, or version 2 when possible."
+        // We take this to imply version 0 can be interpreted as using file offsets.
+        let construction_method = match version {
+            IlocVersion::Zero => ConstructionMethod::File,
+            IlocVersion::One | IlocVersion::Two => {
+                let _reserved = iloc.read_u16(12)?;
+                match iloc.read_u16(4)? {
+                    0 => ConstructionMethod::File,
+                    1 => ConstructionMethod::Idat,
+                    2 => return Err(Error::Unsupported("construction_method 'item_offset' is not supported")),
+                    _ => return Err(Error::InvalidData("construction_method is taken from the set 0, 1 or 2 per ISO 14496-12:2015 § 8.11.3.3"))
+                }
+            }
+        };
+
+        let data_reference_index = iloc.read_u16(16)?;
+
+        if data_reference_index != 0 {
+            return Err(Error::Unsupported(
+                "external file references (iloc.data_reference_index != 0) are not supported",
+            ));
+        }
+
+        let base_offset = iloc.read_u64(base_offset_size.to_bits())?;
+        let extent_count = iloc.read_u16(16)?;
+
+        if extent_count < 1 {
+            return Err(Error::InvalidData(
+                "extent_count must have a value 1 or greater per ISO 14496-12:2015 § 8.11.3.3",
+            ));
+        }
+
+        let mut extents = vec_with_capacity(extent_count.to_usize())?;
+
+        for _ in 0..extent_count {
+            // Parsed but currently ignored, see `ItemLocationBoxExtent`
+            let _extent_index = match &index_size {
+                None | Some(IlocFieldSize::Zero) => None,
+                Some(index_size) => {
+                    debug_assert!(version == IlocVersion::One || version == IlocVersion::Two);
+                    Some(iloc.read_u64(index_size.to_bits())?)
+                }
+            };
+
+            // Per ISO 14496-12:2015 § 8.11.3.1:
+            // "If the offset is not identified (the field has a length of zero), then the
+            //  beginning of the source (offset 0) is implied"
+            // This behavior will follow from BitReader::read_u64(0) -> 0.
+            let extent_offset = iloc.read_u64(offset_size.to_bits())?;
+            let extent_length = iloc.read_u64(length_size.to_bits())?;
+
+            // "If the length is not specified, or specified as zero, then the entire length of
+            //  the source is implied" (ibid)
+            let start = base_offset
+                .checked_add(extent_offset)
+                .ok_or(Error::InvalidData("offset calculation overflow"))?;
+            let extent_range = if extent_length == 0 {
+                ExtentRange::ToEnd(RangeFrom { start })
+            } else {
+                let end = start
+                    .checked_add(extent_length)
+                    .ok_or(Error::InvalidData("end calculation overflow"))?;
+                ExtentRange::WithLength(Range { start, end })
+            };
+
+            vec_push(&mut extents, ItemLocationBoxExtent { extent_range })?;
+        }
+
+        vec_push(
+            &mut items,
+            ItemLocationBoxItem {
+                item_id,
+                construction_method,
+                extents,
+            },
+        )?;
+    }
+
+    debug_assert_eq!(iloc.remaining(), 0);
+
+    Ok(items)
+}
+
 /// Read the contents of a box, including sub boxes.
 ///
 /// Metadata is accumulated in the passed-through `MediaContext` struct,
 /// which can be examined later.
 pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
     let mut found_ftyp = false;
     let mut found_moov = false;
     // TODO(kinetik): Top-level parsing should handle zero-sized boxes
@@ -951,21 +1667,24 @@ pub fn read_mp4<T: Read>(f: &mut T, cont
             BoxType::MovieBox => {
                 read_moov(&mut b, context)?;
                 found_moov = true;
             }
             _ => skip_box_content(&mut b)?,
         };
         check_parser_state!(b.content);
         if found_moov {
-            debug!("found moov {}, could stop pure 'moov' parser now", if found_ftyp {
-                "and ftyp"
-            } else {
-                "but no ftyp"
-            });
+            debug!(
+                "found moov {}, could stop pure 'moov' parser now",
+                if found_ftyp {
+                    "and ftyp"
+                } else {
+                    "but no ftyp"
+                }
+            );
         }
     }
 
     // XXX(kinetik): This isn't perfect, as a "moov" with no contents is
     // treated as okay but we haven't found anything useful.  Needs more
     // thought for clearer behaviour here.
     if found_moov {
         Ok(())
@@ -1015,17 +1734,17 @@ fn read_moov<T: Read>(f: &mut BMFFBox<T>
             _ => skip_box_content(&mut b)?,
         };
         check_parser_state!(b.content);
     }
     Ok(())
 }
 
 fn read_pssh<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSystemSpecificHeaderBox> {
-    let len = src.bytes_left().try_into()?;
+    let len = src.bytes_left();
     let mut box_content = read_buf(src, len)?;
     let (system_id, kid, data) = {
         let pssh = &mut Cursor::new(box_content.as_slice());
 
         let (version, _) = read_fullbox_extra(pssh)?;
 
         let system_id = read_buf(pssh, 16)?;
 
@@ -1033,18 +1752,18 @@ fn read_pssh<T: Read>(src: &mut BMFFBox<
         if version > 0 {
             let count = be_u32_with_limit(pssh)?;
             for _ in 0..count {
                 let item = read_buf(pssh, 16)?;
                 vec_push(&mut kid, item)?;
             }
         }
 
-        let data_size = be_u32_with_limit(pssh)?.to_usize();
-        let data = read_buf(pssh, data_size)?;
+        let data_size = be_u32_with_limit(pssh)?;
+        let data = read_buf(pssh, data_size.into())?;
 
         (system_id, kid, data)
     };
 
     let mut pssh_box = Vec::new();
     write_be_u32(&mut pssh_box, src.head.size.try_into()?)?;
     pssh_box.extend_from_slice(b"pssh");
     pssh_box.append(&mut box_content);
@@ -1060,23 +1779,21 @@ fn read_pssh<T: Read>(src: &mut BMFFBox<
 fn read_mvex<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieExtendsBox> {
     let mut iter = src.box_iter();
     let mut fragment_duration = None;
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::MovieExtendsHeaderBox => {
                 let duration = read_mehd(&mut b)?;
                 fragment_duration = Some(duration);
-            },
+            }
             _ => skip_box_content(&mut b)?,
         }
     }
-    Ok(MovieExtendsBox {
-        fragment_duration,
-    })
+    Ok(MovieExtendsBox { fragment_duration })
 }
 
 fn read_mehd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaScaledTime> {
     let (version, _) = read_fullbox_extra(src)?;
     let fragment_duration = match version {
         1 => be_u64(src)?,
         0 => u64::from(be_u32(src)?),
         _ => return Err(Error::InvalidData("unhandled mehd version")),
@@ -1123,32 +1840,41 @@ fn read_edts<T: Read>(f: &mut BMFFBox<T>
                     empty_duration = elst.edits[idx].segment_duration;
                     idx += 1;
                 }
                 track.empty_duration = Some(MediaScaledTime(empty_duration));
                 let media_time = elst.edits[idx].media_time;
                 if media_time < 0 {
                     debug!("unexpected negative media time in edit");
                 }
-                track.media_time = Some(TrackScaledTime::<u64>(std::cmp::max(0, media_time) as u64,
-                                                        track.id));
+                track.media_time = Some(TrackScaledTime::<u64>(
+                    std::cmp::max(0, media_time) as u64,
+                    track.id,
+                ));
                 if elst.edits.len() > 2 {
                     debug!("ignoring edit list with {} entries", elst.edits.len());
                 }
                 debug!("{:?}", elst);
             }
             _ => skip_box_content(&mut b)?,
         };
         check_parser_state!(b.content);
     }
     Ok(())
 }
 
 #[allow(clippy::type_complexity)] // Allow the complex return, maybe rework in future
-fn parse_mdhd<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<(MediaHeaderBox, Option<TrackScaledTime<u64>>, Option<TrackTimeScale<u64>>)> {
+fn parse_mdhd<T: Read>(
+    f: &mut BMFFBox<T>,
+    track: &mut Track,
+) -> Result<(
+    MediaHeaderBox,
+    Option<TrackScaledTime<u64>>,
+    Option<TrackTimeScale<u64>>,
+)> {
     let mdhd = read_mdhd(f)?;
     let duration = match mdhd.duration {
         std::u64::MAX => None,
         duration => Some(TrackScaledTime::<u64>(duration, track.id)),
     };
     if mdhd.timescale == 0 {
         return Err(Error::InvalidData("zero timescale in mdhd"));
     }
@@ -1324,20 +2050,26 @@ fn read_tkhd<T: Read>(src: &mut BMFFBox<
     let duration = match version {
         1 => be_u64(src)?,
         0 => u64::from(be_u32(src)?),
         _ => return Err(Error::InvalidData("unhandled tkhd version")),
     };
     // Skip uninteresting fields.
     skip(src, 16)?;
 
-    let matrix = Matrix{
-        a: be_i32(src)?, b: be_i32(src)?, u: be_i32(src)?,
-        c: be_i32(src)?, d: be_i32(src)?, v: be_i32(src)?,
-        x: be_i32(src)?, y: be_i32(src)?, w: be_i32(src)?,
+    let matrix = Matrix {
+        a: be_i32(src)?,
+        b: be_i32(src)?,
+        u: be_i32(src)?,
+        c: be_i32(src)?,
+        d: be_i32(src)?,
+        v: be_i32(src)?,
+        x: be_i32(src)?,
+        y: be_i32(src)?,
+        w: be_i32(src)?,
     };
 
     let width = be_u32(src)?;
     let height = be_u32(src)?;
     Ok(TrackHeaderBox {
         track_id,
         disabled,
         duration,
@@ -1361,30 +2093,31 @@ fn read_elst<T: Read>(src: &mut BMFFBox<
             0 => {
                 // 32 bit segment duration and media times.
                 (u64::from(be_u32(src)?), i64::from(be_i32(src)?))
             }
             _ => return Err(Error::InvalidData("unhandled elst version")),
         };
         let media_rate_integer = be_i16(src)?;
         let media_rate_fraction = be_i16(src)?;
-        vec_push(&mut edits, Edit {
-            segment_duration,
-            media_time,
-            media_rate_integer,
-            media_rate_fraction,
-        })?;
+        vec_push(
+            &mut edits,
+            Edit {
+                segment_duration,
+                media_time,
+                media_rate_integer,
+                media_rate_fraction,
+            },
+        )?;
     }
 
     // Padding could be added in some contents.
     skip_box_remain(src)?;
 
-    Ok(EditListBox {
-        edits,
-    })
+    Ok(EditListBox { edits })
 }
 
 /// Parse a mdhd box.
 fn read_mdhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox> {
     let (version, _) = read_fullbox_extra(src)?;
     let (timescale, duration) = match version {
         1 => {
             // Skip 64-bit creation and modification times.
@@ -1431,77 +2164,72 @@ fn read_stco<T: Read>(src: &mut BMFFBox<
     let mut offsets = Vec::new();
     for _ in 0..offset_count {
         vec_push(&mut offsets, u64::from(be_u32(src)?))?;
     }
 
     // Padding could be added in some contents.
     skip_box_remain(src)?;
 
-    Ok(ChunkOffsetBox {
-        offsets,
-    })
+    Ok(ChunkOffsetBox { offsets })
 }
 
 /// Parse a co64 box.
 fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
     let (_, _) = read_fullbox_extra(src)?;
     let offset_count = be_u32_with_limit(src)?;
     let mut offsets = Vec::new();
     for _ in 0..offset_count {
         vec_push(&mut offsets, be_u64(src)?)?;
     }
 
     // Padding could be added in some contents.
     skip_box_remain(src)?;
 
-    Ok(ChunkOffsetBox {
-        offsets,
-    })
+    Ok(ChunkOffsetBox { offsets })
 }
 
 /// Parse a stss box.
 fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
     let (_, _) = read_fullbox_extra(src)?;
     let sample_count = be_u32_with_limit(src)?;
     let mut samples = Vec::new();
     for _ in 0..sample_count {
         vec_push(&mut samples, be_u32(src)?)?;
     }
 
     // Padding could be added in some contents.
     skip_box_remain(src)?;
 
-    Ok(SyncSampleBox {
-        samples,
-    })
+    Ok(SyncSampleBox { samples })
 }
 
 /// Parse a stsc box.
 fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
     let (_, _) = read_fullbox_extra(src)?;
     let sample_count = be_u32_with_limit(src)?;
     let mut samples = Vec::new();
     for _ in 0..sample_count {
         let first_chunk = be_u32(src)?;
         let samples_per_chunk = be_u32_with_limit(src)?;
         let sample_description_index = be_u32(src)?;
-        vec_push(&mut samples, SampleToChunk {
-            first_chunk,
-            samples_per_chunk,
-            sample_description_index,
-        })?;
+        vec_push(
+            &mut samples,
+            SampleToChunk {
+                first_chunk,
+                samples_per_chunk,
+                sample_description_index,
+            },
+        )?;
     }
 
     // Padding could be added in some contents.
     skip_box_remain(src)?;
 
-    Ok(SampleToChunkBox {
-        samples,
-    })
+    Ok(SampleToChunkBox { samples })
 }
 
 fn read_ctts<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox> {
     let (version, _) = read_fullbox_extra(src)?;
 
     let counts = u64::from(be_u32_with_limit(src)?);
 
     if src.bytes_left() < counts.checked_mul(8).expect("counts -> bytes overflow") {
@@ -1509,36 +2237,37 @@ fn read_ctts<T: Read>(src: &mut BMFFBox<
     }
 
     let mut offsets = Vec::new();
     for _ in 0..counts {
         let (sample_count, time_offset) = match version {
             // According to spec, Version0 shoule be used when version == 0;
             // however, some buggy contents have negative value when version == 0.
             // So we always use Version1 here.
-            0 ..= 1 => {
+            0..=1 => {
                 let count = be_u32_with_limit(src)?;
                 let offset = TimeOffsetVersion::Version1(be_i32(src)?);
                 (count, offset)
-            },
+            }
             _ => {
                 return Err(Error::InvalidData("unsupported version in 'ctts' box"));
             }
         };
-        vec_push(&mut offsets, TimeOffset {
-            sample_count,
-            time_offset,
-        })?;
+        vec_push(
+            &mut offsets,
+            TimeOffset {
+                sample_count,
+                time_offset,
+            },
+        )?;
     }
 
     skip_box_remain(src)?;
 
-    Ok(CompositionOffsetBox {
-        samples: offsets,
-    })
+    Ok(CompositionOffsetBox { samples: offsets })
 }
 
 /// Parse a stsz box.
 fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
     let (_, _) = read_fullbox_extra(src)?;
     let sample_size = be_u32(src)?;
     let sample_count = be_u32_with_limit(src)?;
     let mut sample_sizes = Vec::new();
@@ -1560,86 +2289,87 @@ fn read_stsz<T: Read>(src: &mut BMFFBox<
 /// Parse a stts box.
 fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
     let (_, _) = read_fullbox_extra(src)?;
     let sample_count = be_u32_with_limit(src)?;
     let mut samples = Vec::new();
     for _ in 0..sample_count {
         let sample_count = be_u32_with_limit(src)?;
         let sample_delta = be_u32(src)?;
-        vec_push(&mut samples, Sample {
-            sample_count,
-            sample_delta,
-        })?;
+        vec_push(
+            &mut samples,
+            Sample {
+                sample_count,
+                sample_delta,
+            },
+        )?;
     }
 
     // Padding could be added in some contents.
     skip_box_remain(src)?;
 
-    Ok(TimeToSampleBox {
-        samples,
-    })
+    Ok(TimeToSampleBox { samples })
 }
 
 /// Parse a VPx Config Box.
 fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> {
     let (version, _) = read_fullbox_extra(src)?;
     let supported_versions = [0, 1];
-    if ! supported_versions.contains(&version) {
+    if !supported_versions.contains(&version) {
         return Err(Error::Unsupported("unknown vpcC version"));
     }
 
     let profile = src.read_u8()?;
     let level = src.read_u8()?;
     let (
         bit_depth,
         colour_primaries,
         chroma_subsampling,
         transfer_characteristics,
         matrix_coefficients,
-        video_full_range_flag
+        video_full_range_flag,
     ) = if version == 0 {
         let (bit_depth, colour_primaries) = {
             let byte = src.read_u8()?;
             ((byte >> 4) & 0x0f, byte & 0x0f)
         };
         // Note, transfer_characteristics was known as transfer_function in v0
         let (chroma_subsampling, transfer_characteristics, video_full_range_flag) = {
             let byte = src.read_u8()?;
             ((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
         };
         (
             bit_depth,
             colour_primaries,
             chroma_subsampling,
             transfer_characteristics,
             None,
-            video_full_range_flag
+            video_full_range_flag,
         )
     } else {
         let (bit_depth, chroma_subsampling, video_full_range_flag) = {
             let byte = src.read_u8()?;
             ((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
         };
         let colour_primaries = src.read_u8()?;
         let transfer_characteristics = src.read_u8()?;
         let matrix_coefficients = src.read_u8()?;
 
         (
             bit_depth,
             colour_primaries,
             chroma_subsampling,
             transfer_characteristics,
             Some(matrix_coefficients),
-            video_full_range_flag
+            video_full_range_flag,
         )
     };
 
     let codec_init_size = be_u16(src)?;
-    let codec_init = read_buf(src, codec_init_size.to_usize())?;
+    let codec_init = read_buf(src, codec_init_size.into())?;
 
     // TODO(rillian): validate field value ranges.
     Ok(VPxConfigBox {
         profile,
         level,
         bit_depth,
         colour_primaries,
         chroma_subsampling,
@@ -1661,116 +2391,113 @@ fn read_av1c<T: Read>(src: &mut BMFFBox<
     let profile_byte = src.read_u8()?;
     let profile = (profile_byte & 0xe0) >> 5;
     let level = profile_byte & 0x1f;
     let flags_byte = src.read_u8()?;
     let tier = (flags_byte & 0x80) >> 7;
     let bit_depth = match flags_byte & 0x60 {
         0x60 => 12,
         0x40 => 10,
-        _ => 8
+        _ => 8,
     };
     let monochrome = flags_byte & 0x10 == 0x10;
     let chroma_subsampling_x = (flags_byte & 0x08) >> 3;
     let chroma_subsampling_y = (flags_byte & 0x04) >> 2;
     let chroma_sample_position = flags_byte & 0x03;
     let delay_byte = src.read_u8()?;
     let initial_presentation_delay_present = (delay_byte & 0x10) == 0x10;
-    let initial_presentation_delay_minus_one =
-        if initial_presentation_delay_present {
-            delay_byte & 0x0f
-        } else {
-            0
-        };
+    let initial_presentation_delay_minus_one = if initial_presentation_delay_present {
+        delay_byte & 0x0f
+    } else {
+        0
+    };
 
     let config_obus_size = src.bytes_left();
-    let config_obus = read_buf(src, config_obus_size.try_into()?)?;
+    let config_obus = read_buf(src, config_obus_size)?;
 
     Ok(AV1ConfigBox {
         profile,
         level,
         tier,
         bit_depth,
         monochrome,
         chroma_subsampling_x,
         chroma_subsampling_y,
         chroma_sample_position,
         initial_presentation_delay_present,
         initial_presentation_delay_minus_one,
-        config_obus
+        config_obus,
     })
 }
 
 fn read_flac_metadata<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACMetadataBlock> {
     let temp = src.read_u8()?;
     let block_type = temp & 0x7f;
-    let length = be_u24(src)?;
-    if u64::from(length) > src.bytes_left() {
+    let length = be_u24(src)?.into();
+    if length > src.bytes_left() {
         return Err(Error::InvalidData(
-                "FLACMetadataBlock larger than parent box"));
+            "FLACMetadataBlock larger than parent box",
+        ));
     }
-    let data = read_buf(src, length.to_usize())?;
-    Ok(FLACMetadataBlock {
-        block_type,
-        data,
-    })
+    let data = read_buf(src, length)?;
+    Ok(FLACMetadataBlock { block_type, data })
 }
 
 fn find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
     // Tags for elementary stream description
-    const ESDESCR_TAG: u8          = 0x03;
-    const DECODER_CONFIG_TAG: u8   = 0x04;
+    const ESDESCR_TAG: u8 = 0x03;
+    const DECODER_CONFIG_TAG: u8 = 0x04;
     const DECODER_SPECIFIC_TAG: u8 = 0x05;
 
     let mut remains = data;
 
     // Descriptor length should be more than 2 bytes.
     while remains.len() > 2 {
         let des = &mut Cursor::new(remains);
         let tag = des.read_u8()?;
 
-        let mut end: u32 = 0;   // It's u8 without declaration type that is incorrect.
-        // MSB of extend_or_len indicates more bytes, up to 4 bytes.
+        let mut end: u32 = 0; // It's u8 without declaration type that is incorrect.
+                              // MSB of extend_or_len indicates more bytes, up to 4 bytes.
         for _ in 0..4 {
             if des.position() == remains.len().to_u64() {
                 // There's nothing more to read, the 0x80 was actually part of
                 // the content, and not an extension size.
                 end = des.position() as u32;
                 break;
             }
             let extend_or_len = des.read_u8()?;
             end = (end << 7) + u32::from(extend_or_len & 0x7F);
             if (extend_or_len & 0x80) == 0 {
                 end += des.position() as u32;
                 break;
             }
-        };
+        }
 
         if end.to_usize() > remains.len() || u64::from(end) < des.position() {
             return Err(Error::InvalidData("Invalid descriptor."));
         }
 
-        let descriptor = &remains[des.position().try_into()? .. end.to_usize()];
+        let descriptor = &remains[des.position().try_into()?..end.to_usize()];
 
         match tag {
             ESDESCR_TAG => {
                 read_es_descriptor(descriptor, esds)?;
-            },
+            }
             DECODER_CONFIG_TAG => {
                 read_dc_descriptor(descriptor, esds)?;
-            },
+            }
             DECODER_SPECIFIC_TAG => {
                 read_ds_descriptor(descriptor, esds)?;
-            },
+            }
             _ => {
                 debug!("Unsupported descriptor, tag {}", tag);
-            },
+            }
         }
 
-        remains = &remains[end.to_usize() .. remains.len()];
+        remains = &remains[end.to_usize()..remains.len()];
     }
 
     Ok(())
 }
 
 fn get_audio_object_type(bit_reader: &mut BitReader) -> Result<u16> {
     let mut audio_object_type: u16 = ReadInto::read(bit_reader, 5)?;
 
@@ -1778,156 +2505,168 @@ fn get_audio_object_type(bit_reader: &mu
     if audio_object_type == 31 {
         let audio_object_type_ext: u16 = ReadInto::read(bit_reader, 6)?;
         audio_object_type = 32 + audio_object_type_ext;
     }
     Ok(audio_object_type)
 }
 
 fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
-    let frequency_table =
-        vec![(0x0, 96000), (0x1, 88200), (0x2, 64000), (0x3, 48000),
-             (0x4, 44100), (0x5, 32000), (0x6, 24000), (0x7, 22050),
-             (0x8, 16000), (0x9, 12000), (0xa, 11025), (0xb, 8000),
-             (0xc, 7350)];
+    let frequency_table = vec![
+        (0x0, 96000),
+        (0x1, 88200),
+        (0x2, 64000),
+        (0x3, 48000),
+        (0x4, 44100),
+        (0x5, 32000),
+        (0x6, 24000),
+        (0x7, 22050),
+        (0x8, 16000),
+        (0x9, 12000),
+        (0xa, 11025),
+        (0xb, 8000),
+        (0xc, 7350),
+    ];
 
     let bit_reader = &mut BitReader::new(data);
 
     let mut audio_object_type = get_audio_object_type(bit_reader)?;
 
     let sample_index: u32 = ReadInto::read(bit_reader, 4)?;
 
     // Sample frequency could be from table, or retrieved from stream directly
     // if index is 0x0f.
     let sample_frequency = match sample_index {
-        0x0F => {
-            Some(ReadInto::read(bit_reader, 24)?)
-        },
-        _ => {
-            frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1)
-        },
+        0x0F => Some(ReadInto::read(bit_reader, 24)?),
+        _ => frequency_table
+            .iter()
+            .find(|item| item.0 == sample_index)
+            .map(|x| x.1),
     };
 
     let channel_configuration: u16 = ReadInto::read(bit_reader, 4)?;
 
     let extended_audio_object_type = match audio_object_type {
         5 | 29 => Some(5),
         _ => None,
     };
 
     if audio_object_type == 5 || audio_object_type == 29 {
         // We have an explicit signaling for BSAC extension, should the decoder
         // decode the BSAC extension (all Gecko's AAC decoders do), then this is
         // what the stream will actually look like once decoded.
         let _extended_sample_index = ReadInto::read(bit_reader, 4)?;
         let _extended_sample_frequency: Option<u32> = match _extended_sample_index {
             0x0F => Some(ReadInto::read(bit_reader, 24)?),
-            _ => frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1)
+            _ => frequency_table
+                .iter()
+                .find(|item| item.0 == sample_index)
+                .map(|x| x.1),
         };
         audio_object_type = get_audio_object_type(bit_reader)?;
         let _extended_channel_configuration = match audio_object_type {
             22 => ReadInto::read(bit_reader, 4)?,
-            _ => channel_configuration
+            _ => channel_configuration,
         };
     };
 
     match audio_object_type {
-        1 ..= 4 | 6 | 7 | 17 | 19 ..= 23 => {
+        1..=4 | 6 | 7 | 17 | 19..=23 => {
             if sample_frequency.is_none() {
                 return Err(Error::Unsupported("unknown frequency"));
             }
 
             // parsing GASpecificConfig
 
             // If the sampling rate is not one of the rates listed in the right
             // column in Table 4.82, the sampling frequency dependent tables
             // (code tables, scale factor band tables etc.) must be deduced in
             // order for the bitstream payload to be parsed. Since a given
             // sampling frequency is associated with only one sampling frequency
             // table, and since maximum flexibility is desired in the range of
             // possible sampling frequencies, the following table shall be used
             // to associate an implied sampling frequency with the desired
             // sampling frequency dependent tables.
             let sample_frequency_value = match sample_frequency.unwrap() {
-                0 ..= 9390 => 8000,
-                9391 ..= 11501 => 11025,
-                11502 ..= 13855 => 12000,
-                13856 ..= 18782 => 16000,
-                18783 ..= 23003 => 22050,
-                23004 ..= 27712 => 24000,
-                27713 ..= 37565 => 32000,
-                37566 ..= 46008 => 44100,
-                46009 ..= 55425 => 48000,
-                55426 ..= 75131 => 64000,
-                75132 ..= 92016 => 88200,
-                _ => 96000
+                0..=9390 => 8000,
+                9391..=11501 => 11025,
+                11502..=13855 => 12000,
+                13856..=18782 => 16000,
+                18783..=23003 => 22050,
+                23004..=27712 => 24000,
+                27713..=37565 => 32000,
+                37566..=46008 => 44100,
+                46009..=55425 => 48000,
+                55426..=75131 => 64000,
+                75132..=92016 => 88200,
+                _ => 96000,
             };
 
-            bit_reader.skip(1)?;        // frameLengthFlag
+            bit_reader.skip(1)?; // frameLengthFlag
             let depend_on_core_order: u8 = ReadInto::read(bit_reader, 1)?;
             if depend_on_core_order > 0 {
-                bit_reader.skip(14)?;   // codeCoderDelay
+                bit_reader.skip(14)?; // codeCoderDelay
             }
-            bit_reader.skip(1)?;        // extensionFlag
+            bit_reader.skip(1)?; // extensionFlag
 
             let channel_counts = match channel_configuration {
                 0 => {
                     debug!("Parsing program_config_element for channel counts");
 
-                    bit_reader.skip(4)?;    // element_instance_tag
-                    bit_reader.skip(2)?;    // object_type
-                    bit_reader.skip(4)?;    // sampling_frequency_index
+                    bit_reader.skip(4)?; // element_instance_tag
+                    bit_reader.skip(2)?; // object_type
+                    bit_reader.skip(4)?; // sampling_frequency_index
                     let num_front_channel: u8 = ReadInto::read(bit_reader, 4)?;
                     let num_side_channel: u8 = ReadInto::read(bit_reader, 4)?;
-                    let num_back_channel:u8 = ReadInto::read(bit_reader, 4)?;
+                    let num_back_channel: u8 = ReadInto::read(bit_reader, 4)?;
                     let num_lfe_channel: u8 = ReadInto::read(bit_reader, 2)?;
-                    bit_reader.skip(3)?;    // num_assoc_data
-                    bit_reader.skip(4)?;    // num_valid_cc
+                    bit_reader.skip(3)?; // num_assoc_data
+                    bit_reader.skip(4)?; // num_valid_cc
 
                     let mono_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
                     if mono_mixdown_present {
-                        bit_reader.skip(4)?;    // mono_mixdown_element_number
+                        bit_reader.skip(4)?; // mono_mixdown_element_number
                     }
 
                     let stereo_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
                     if stereo_mixdown_present {
-                        bit_reader.skip(4)?;    // stereo_mixdown_element_number
+                        bit_reader.skip(4)?; // stereo_mixdown_element_number
                     }
 
                     let matrix_mixdown_idx_present: bool = ReadInto::read(bit_reader, 1)?;
                     if matrix_mixdown_idx_present {
-                        bit_reader.skip(2)?;    // matrix_mixdown_idx
-                        bit_reader.skip(1)?;    // pseudo_surround_enable
+                        bit_reader.skip(2)?; // matrix_mixdown_idx
+                        bit_reader.skip(1)?; // pseudo_surround_enable
                     }
                     let mut _channel_counts = 0;
                     _channel_counts += read_surround_channel_count(bit_reader, num_front_channel)?;
                     _channel_counts += read_surround_channel_count(bit_reader, num_side_channel)?;
                     _channel_counts += read_surround_channel_count(bit_reader, num_back_channel)?;
                     _channel_counts += read_surround_channel_count(bit_reader, num_lfe_channel)?;
                     _channel_counts
-                },
-                1 ..= 7 => channel_configuration,
+                }
+                1..=7 => channel_configuration,
                 // Amendment 4 of the AAC standard in 2013 below
-                11 => 7, // 6.1 Amendment 4 of the AAC standard in 2013
+                11 => 7,      // 6.1 Amendment 4 of the AAC standard in 2013
                 12 | 14 => 8, // 7.1 (a/d) of ITU BS.2159
                 _ => {
                     return Err(Error::Unsupported("invalid channel configuration"));
                 }
             };
 
             esds.audio_object_type = Some(audio_object_type);
             esds.extended_audio_object_type = extended_audio_object_type;
             esds.audio_sample_rate = Some(sample_frequency_value);
             esds.audio_channel_count = Some(channel_counts);
             assert!(esds.decoder_specific_data.is_empty());
             esds.decoder_specific_data.extend_from_slice(data);
 
             Ok(())
-        },
-        _ => Err(Error::Unsupported("unknown aac audio object type"))
+        }
+        _ => Err(Error::Unsupported("unknown aac audio object type")),
     }
 }
 
 fn read_surround_channel_count(bit_reader: &mut BitReader, channels: u8) -> Result<u16> {
     let mut count = 0;
     for _ in 0..channels {
         let is_cpe: bool = ReadInto::read(bit_reader, 1)?;
         count += if is_cpe { 2 } else { 1 };
@@ -1939,17 +2678,17 @@ fn read_surround_channel_count(bit_reade
 fn read_dc_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
     let des = &mut Cursor::new(data);
     let object_profile = des.read_u8()?;
 
     // Skip uninteresting fields.
     skip(des, 12)?;
 
     if data.len().to_u64() > des.position() {
-        find_descriptor(&data[des.position().try_into()? .. data.len()], esds)?;
+        find_descriptor(&data[des.position().try_into()?..data.len()], esds)?;
     }
 
     esds.audio_codec = match object_profile {
         0x40 | 0x41 => CodecType::AAC,
         0x6B => CodecType::MP3,
         _ => CodecType::Unknown,
     };
 
@@ -1972,29 +2711,33 @@ fn read_es_descriptor(data: &[u8], esds:
     // Url flag, second bit from left most.
     if esds_flags & 0x40 > 0 {
         // Skip uninteresting fields.
         let skip_es_len = u64::from(des.read_u8()?) + 2;
         skip(des, skip_es_len)?;
     }
 
     if data.len().to_u64() > des.position() {
-        find_descriptor(&data[des.position().try_into()? .. data.len()], esds)?;
+        find_descriptor(&data[des.position().try_into()?..data.len()], esds)?;
     }
 
     Ok(())
 }
 
 fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
     let (_, _) = read_fullbox_extra(src)?;
 
     // Subtract 4 extra to offset the members of fullbox not accounted for in
     // head.offset
-    let esds_size = src.head.size.checked_sub(src.head.offset + 4).expect("offset invalid");
-    let esds_array = read_buf(src, esds_size.try_into()?)?;
+    let esds_size = src
+        .head
+        .size
+        .checked_sub(src.head.offset + 4)
+        .expect("offset invalid");
+    let esds_array = read_buf(src, esds_size)?;
 
     let mut es_data = ES_Descriptor::default();
     find_descriptor(&esds_array, &mut es_data)?;
 
     es_data.codec_esds = esds_array;
 
     Ok(es_data)
 }
@@ -2014,25 +2757,24 @@ fn read_dfla<T: Read>(src: &mut BMFFBox<
         vec_push(&mut blocks, block)?;
     }
     // The box must have at least one meta block, and the first block
     // must be the METADATA_BLOCK_STREAMINFO
     if blocks.is_empty() {
         return Err(Error::InvalidData("FLACSpecificBox missing metadata"));
     } else if blocks[0].block_type != 0 {
         return Err(Error::InvalidData(
-                "FLACSpecificBox must have STREAMINFO metadata first"));
+            "FLACSpecificBox must have STREAMINFO metadata first",
+        ));
     } else if blocks[0].data.len() != 34 {
         return Err(Error::InvalidData(
-                "FLACSpecificBox STREAMINFO block is the wrong size"));
+            "FLACSpecificBox STREAMINFO block is the wrong size",
+        ));
     }
-    Ok(FLACSpecificBox {
-        version,
-        blocks,
-    })
+    Ok(FLACSpecificBox { version, blocks })
 }
 
 /// Parse `OpusSpecificBox`.
 fn read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox> {
     let version = src.read_u8()?;
     if version != 0 {
         return Err(Error::Unsupported("unknown dOps (Opus) version"));
     }
@@ -2043,17 +2785,17 @@ fn read_dops<T: Read>(src: &mut BMFFBox<
     let output_gain = be_i16(src)?;
     let channel_mapping_family = src.read_u8()?;
 
     let channel_mapping_table = if channel_mapping_family == 0 {
         None
     } else {
         let stream_count = src.read_u8()?;
         let coupled_count = src.read_u8()?;
-        let channel_mapping = read_buf(src, output_channel_count.to_usize())?;
+        let channel_mapping = read_buf(src, output_channel_count.into())?;
 
         Some(ChannelMappingTable {
             stream_count,
             coupled_count,
             channel_mapping,
         })
     };
 
@@ -2070,17 +2812,20 @@ fn read_dops<T: Read>(src: &mut BMFFBox<
 }
 
 /// Re-serialize the Opus codec-specific config data as an `OpusHead` packet.
 ///
 /// Some decoders expect the initialization data in the format used by the
 /// Ogg and WebM encapsulations. To support this we prepend the `OpusHead`
 /// tag and byte-swap the data from big- to little-endian relative to the
 /// dOps box.
-pub fn serialize_opus_header<W: byteorder::WriteBytesExt + std::io::Write>(opus: &OpusSpecificBox, dst: &mut W) -> Result<()> {
+pub fn serialize_opus_header<W: byteorder::WriteBytesExt + std::io::Write>(
+    opus: &OpusSpecificBox,
+    dst: &mut W,
+) -> Result<()> {
     match dst.write(b"OpusHead") {
         Err(e) => return Err(Error::from(e)),
         Ok(bytes) => {
             if bytes != 8 {
                 return Err(Error::InvalidData("Couldn't write OpusHead tag."));
             }
         }
     }
@@ -2098,17 +2843,19 @@ pub fn serialize_opus_header<W: byteorde
         None => {}
         Some(ref table) => {
             dst.write_u8(table.stream_count)?;
             dst.write_u8(table.coupled_count)?;
             match dst.write(&table.channel_mapping) {
                 Err(e) => return Err(Error::from(e)),
                 Ok(bytes) => {
                     if bytes != table.channel_mapping.len() {
-                        return Err(Error::InvalidData("Couldn't write channel mapping table data."));
+                        return Err(Error::InvalidData(
+                            "Couldn't write channel mapping table data.",
+                        ));
                     }
                 }
             }
         }
     };
     Ok(())
 }
 
@@ -2118,25 +2865,26 @@ fn read_alac<T: Read>(src: &mut BMFFBox<
     if version != 0 {
         return Err(Error::Unsupported("unknown alac (ALAC) version"));
     }
     if flags != 0 {
         return Err(Error::InvalidData("no-zero alac (ALAC) flags"));
     }
 
     let length = match src.bytes_left() {
-        x @ 24 | x @ 48 => x.try_into().expect("infallible conversion to usize"),
-        _ => return Err(Error::InvalidData("ALACSpecificBox magic cookie is the wrong size")),
+        x @ 24 | x @ 48 => x,
+        _ => {
+            return Err(Error::InvalidData(
+                "ALACSpecificBox magic cookie is the wrong size",
+            ))
+        }
     };
     let data = read_buf(src, length)?;
 
-    Ok(ALACSpecificBox {
-        version,
-        data,
-    })
+    Ok(ALACSpecificBox { version, data })
 }
 
 /// Parse a hdlr box.
 fn read_hdlr<T: Read>(src: &mut BMFFBox<T>) -> Result<HandlerBox> {
     let (_, _) = read_fullbox_extra(src)?;
 
     // Skip uninteresting fields.
     skip(src, 4)?;
@@ -2144,19 +2892,17 @@ fn read_hdlr<T: Read>(src: &mut BMFFBox<
     let handler_type = FourCC::from(be_u32(src)?);
 
     // Skip uninteresting fields.
     skip(src, 12)?;
 
     // Skip name.
     skip_box_remain(src)?;
 
-    Ok(HandlerBox {
-        handler_type,
-    })
+    Ok(HandlerBox { handler_type })
 }
 
 /// Parse an video description inside an stsd box.
 fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry> {
     let name = src.get_header().name;
     let codec_type = match name {
         BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
         BoxType::MP4VideoSampleEntry => CodecType::MP4V,
@@ -2186,93 +2932,106 @@ fn read_video_sample_entry<T: Read>(src:
 
     // Skip clap/pasp/etc. for now.
     let mut codec_specific = None;
     let mut protection_info = Vec::new();
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::AVCConfigurationBox => {
-                if (name != BoxType::AVCSampleEntry &&
-                    name != BoxType::AVC3SampleEntry &&
-                    name != BoxType::ProtectedVisualSampleEntry) ||
-                    codec_specific.is_some() {
-                        return Err(Error::InvalidData("malformed video sample entry"));
-                    }
-                let avcc_size = b.head.size.checked_sub(b.head.offset).expect("offset invalid");
-                let avcc = read_buf(&mut b.content, avcc_size.try_into()?)?;
+                if (name != BoxType::AVCSampleEntry
+                    && name != BoxType::AVC3SampleEntry
+                    && name != BoxType::ProtectedVisualSampleEntry)
+                    || codec_specific.is_some()
+                {
+                    return Err(Error::InvalidData("malformed video sample entry"));
+                }
+                let avcc_size = b
+                    .head
+                    .size
+                    .checked_sub(b.head.offset)
+                    .expect("offset invalid");
+                let avcc = read_buf(&mut b.content, avcc_size)?;
                 debug!("{:?} (avcc)", avcc);
                 // TODO(kinetik): Parse avcC box?  For now we just stash the data.
                 codec_specific = Some(VideoCodecSpecific::AVCConfig(avcc));
             }
-            BoxType::VPCodecConfigurationBox => { // vpcC
-                if (name != BoxType::VP8SampleEntry &&
-                    name != BoxType::VP9SampleEntry &&
-                    name != BoxType::ProtectedVisualSampleEntry) ||
-                    codec_specific.is_some() {
-                        return Err(Error::InvalidData("malformed video sample entry"));
-                    }
+            BoxType::VPCodecConfigurationBox => {
+                // vpcC
+                if (name != BoxType::VP8SampleEntry
+                    && name != BoxType::VP9SampleEntry
+                    && name != BoxType::ProtectedVisualSampleEntry)
+                    || codec_specific.is_some()
+                {
+                    return Err(Error::InvalidData("malformed video sample entry"));
+                }
                 let vpcc = read_vpcc(&mut b)?;
                 codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc));
             }
             BoxType::AV1CodecConfigurationBox => {
-              if name != BoxType::AV1SampleEntry  {
-                return Err(Error::InvalidData("malformed video sample entry"));
-              }
-              let av1c = read_av1c(&mut b)?;
-              codec_specific = Some(VideoCodecSpecific::AV1Config(av1c));
+                if name != BoxType::AV1SampleEntry {
+                    return Err(Error::InvalidData("malformed video sample entry"));
+                }
+                let av1c = read_av1c(&mut b)?;
+                codec_specific = Some(VideoCodecSpecific::AV1Config(av1c));
             }
             BoxType::ESDBox => {
                 if name != BoxType::MP4VideoSampleEntry || codec_specific.is_some() {
                     return Err(Error::InvalidData("malformed video sample entry"));
                 }
                 let (_, _) = read_fullbox_extra(&mut b.content)?;
                 // Subtract 4 extra to offset the members of fullbox not
                 // accounted for in head.offset
-                let esds_size = b.head.size.checked_sub(b.head.offset + 4).expect("offset invalid");
-                let esds = read_buf(&mut b.content, esds_size.try_into()?)?;
+                let esds_size = b
+                    .head
+                    .size
+                    .checked_sub(b.head.offset + 4)
+                    .expect("offset invalid");
+                let esds = read_buf(&mut b.content, esds_size)?;
                 codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds));
             }
-            BoxType::ProtectionSchemeInformationBox => {
+            BoxType::ProtectionSchemeInfoBox => {
                 if name != BoxType::ProtectedVisualSampleEntry {
                     return Err(Error::InvalidData("malformed video sample entry"));
                 }
                 let sinf = read_sinf(&mut b)?;
                 debug!("{:?} (sinf)", sinf);
                 vec_push(&mut protection_info, sinf)?;
             }
             _ => {
                 debug!("Unsupported video codec, box {:?} found", b.head.name);
                 skip_box_content(&mut b)?;
             }
         }
         check_parser_state!(b.content);
     }
 
-    Ok(codec_specific.map_or(SampleEntry::Unknown,
-        |codec_specific| SampleEntry::Video(VideoSampleEntry {
-            codec_type,
-            data_reference_index,
-            width,
-            height,
-            codec_specific,
-            protection_info,
-        }))
+    Ok(
+        codec_specific.map_or(SampleEntry::Unknown, |codec_specific| {
+            SampleEntry::Video(VideoSampleEntry {
+                codec_type,
+                data_reference_index,
+                width,
+                height,
+                codec_specific,
+                protection_info,
+            })
+        }),
     )
 }
 
 fn read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
     let mut codec_specific = None;
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::ESDBox => {
                 let esds = read_esds(&mut b)?;
                 codec_specific = Some(esds);
-            },
+            }
             _ => skip_box_content(&mut b)?,
         }
     }
 
     codec_specific.ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
 }
 
 /// Parse an audio description inside an stsd box.
@@ -2302,107 +3061,113 @@ fn read_audio_sample_entry<T: Read>(src:
     let mut samplerate = f64::from(be_u32(src)? >> 16); // 16.16 fixed point;
 
     match version {
         0 => (),
         1 => {
             // Quicktime sound sample description version 1.
             // Skip uninteresting fields.
             skip(src, 16)?;
-        },
+        }
         2 => {
             // Quicktime sound sample description version 2.
             skip(src, 4)?;
             samplerate = f64::from_bits(be_u64(src)?);
             channelcount = be_u32(src)?;
             skip(src, 20)?;
         }
-        _ => return Err(Error::Unsupported("unsupported non-isom audio sample entry")),
+        _ => {
+            return Err(Error::Unsupported(
+                "unsupported non-isom audio sample entry",
+            ))
+        }
     }
 
     let (mut codec_type, mut codec_specific) = match name {
         BoxType::MP3AudioSampleEntry => (CodecType::MP3, Some(AudioCodecSpecific::MP3)),
         BoxType::LPCMAudioSampleEntry => (CodecType::LPCM, Some(AudioCodecSpecific::LPCM)),
         _ => (CodecType::Unknown, None),
     };
     let mut protection_info = Vec::new();
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::ESDBox => {
-                if (name != BoxType::MP4AudioSampleEntry &&
-                    name != BoxType::ProtectedAudioSampleEntry) ||
-                    codec_specific.is_some() {
+                if (name != BoxType::MP4AudioSampleEntry
+                    && name != BoxType::ProtectedAudioSampleEntry)
+                    || codec_specific.is_some()
+                {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let esds = read_esds(&mut b)?;
                 codec_type = esds.audio_codec;
                 codec_specific = Some(AudioCodecSpecific::ES_Descriptor(esds));
             }
             BoxType::FLACSpecificBox => {
-                if (name != BoxType::FLACSampleEntry &&
-                    name != BoxType::ProtectedAudioSampleEntry) ||
-                    codec_specific.is_some() {
+                if (name != BoxType::FLACSampleEntry && name != BoxType::ProtectedAudioSampleEntry)
+                    || codec_specific.is_some()
+                {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let dfla = read_dfla(&mut b)?;
                 codec_type = CodecType::FLAC;
                 codec_specific = Some(AudioCodecSpecific::FLACSpecificBox(dfla));
             }
             BoxType::OpusSpecificBox => {
-                if (name != BoxType::OpusSampleEntry &&
-                    name != BoxType::ProtectedAudioSampleEntry) ||
-                    codec_specific.is_some() {
+                if (name != BoxType::OpusSampleEntry && name != BoxType::ProtectedAudioSampleEntry)
+                    || codec_specific.is_some()
+                {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let dops = read_dops(&mut b)?;
                 codec_type = CodecType::Opus;
                 codec_specific = Some(AudioCodecSpecific::OpusSpecificBox(dops));
             }
             BoxType::ALACSpecificBox => {
-                if name != BoxType::ALACSpecificBox ||
-                    codec_specific.is_some() {
+                if name != BoxType::ALACSpecificBox || codec_specific.is_some() {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let alac = read_alac(&mut b)?;
                 codec_type = CodecType::ALAC;
                 codec_specific = Some(AudioCodecSpecific::ALACSpecificBox(alac));
             }
             BoxType::QTWaveAtom => {
                 let qt_esds = read_qt_wave_atom(&mut b)?;
                 codec_type = qt_esds.audio_codec;
                 codec_specific = Some(AudioCodecSpecific::ES_Descriptor(qt_esds));
             }
-            BoxType::ProtectionSchemeInformationBox => {
+            BoxType::ProtectionSchemeInfoBox => {
                 if name != BoxType::ProtectedAudioSampleEntry {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let sinf = read_sinf(&mut b)?;
                 debug!("{:?} (sinf)", sinf);
                 codec_type = CodecType::EncryptedAudio;
                 vec_push(&mut protection_info, sinf)?;
             }
             _ => {
                 debug!("Unsupported audio codec, box {:?} found", b.head.name);
                 skip_box_content(&mut b)?;
             }
         }
         check_parser_state!(b.content);
     }
 
-    Ok(codec_specific.map_or(SampleEntry::Unknown,
-        |codec_specific| SampleEntry::Audio(AudioSampleEntry {
-            codec_type,
-            data_reference_index,
-            channelcount,
-            samplesize,
-            samplerate,
-            codec_specific,
-            protection_info,
-        }))
+    Ok(
+        codec_specific.map_or(SampleEntry::Unknown, |codec_specific| {
+            SampleEntry::Audio(AudioSampleEntry {
+                codec_type,
+                data_reference_index,
+                channelcount,
+                samplesize,
+                samplerate,
+                codec_specific,
+                protection_info,
+            })
+        }),
     )
 }
 
 /// Parse a stsd box.
 fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleDescriptionBox> {
     let (_, _) = read_fullbox_extra(src)?;
 
     let description_count = be_u32(src)?;
@@ -2421,71 +3186,71 @@ fn read_stsd<T: Read>(src: &mut BMFFBox<
                 Ok(desc) => desc,
                 Err(Error::Unsupported(_)) => {
                     // read_{audio,video}_desc may have returned Unsupported
                     // after partially reading the box content, so we can't
                     // simply use skip_box_content here.
                     let to_skip = b.bytes_left();
                     skip(&mut b, to_skip)?;
                     SampleEntry::Unknown
-                },
+                }
                 Err(e) => return Err(e),
             };
             vec_push(&mut descriptions, description)?;
             check_parser_state!(b.content);
             if descriptions.len() == description_count.to_usize() {
                 break;
             }
         }
     }
 
     // Padding could be added in some contents.
     skip_box_remain(src)?;
 
-    Ok(SampleDescriptionBox {
-        descriptions,
-    })
+    Ok(SampleDescriptionBox { descriptions })
 }
 
 fn read_sinf<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSchemeInfoBox> {
     let mut sinf = ProtectionSchemeInfoBox::default();
 
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::OriginalFormatBox => {
                 let frma = read_frma(&mut b)?;
                 sinf.code_name = frma;
-            },
+            }
             BoxType::SchemeTypeBox => {
                 sinf.scheme_type = Some(read_schm(&mut b)?);
             }
             BoxType::SchemeInformationBox => {
                 // We only need tenc box in schi box so far.
                 sinf.tenc = read_schi(&mut b)?;
-            },
+            }
             _ => skip_box_content(&mut b)?,
         }
         check_parser_state!(b.content);
     }
 
     Ok(sinf)
 }
 
 fn read_schi<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<TrackEncryptionBox>> {
     let mut tenc = None;
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::TrackEncryptionBox => {
                 if tenc.is_some() {
-                    return Err(Error::InvalidData("tenc box should be only one at most in sinf box"));
+                    return Err(Error::InvalidData(
+                        "tenc box should be only one at most in sinf box",
+                    ));
                 }
                 tenc = Some(read_tenc(&mut b)?);
-            },
+            }
             _ => skip_box_content(&mut b)?,
         }
     }
 
     Ok(tenc)
 }
 
 fn read_tenc<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackEncryptionBox> {
@@ -2493,56 +3258,56 @@ fn read_tenc<T: Read>(src: &mut BMFFBox<
 
     // reserved byte
     skip(src, 1)?;
     // the next byte is used to signal the default pattern in version >= 1
     let (default_crypt_byte_block, default_skip_byte_block) = match version {
         0 => {
             skip(src, 1)?;
             (None, None)
-        },
+        }
         _ => {
             let pattern_byte = src.read_u8()?;
             let crypt_bytes = pattern_byte >> 4;
             let skip_bytes = pattern_byte & 0x0f;
             (Some(crypt_bytes), Some(skip_bytes))
         }
     };
     let default_is_encrypted = src.read_u8()?;
     let default_iv_size = src.read_u8()?;
     let default_kid = read_buf(src, 16)?;
     // If default_is_encrypted == 1 && default_iv_size == 0 we expect a default_constant_iv
     let default_constant_iv = match (default_is_encrypted, default_iv_size) {
         (1, 0) => {
             let default_constant_iv_size = src.read_u8()?;
-            Some(read_buf(src, default_constant_iv_size.to_usize())?)
-        },
+            Some(read_buf(src, default_constant_iv_size.into())?)
+        }
         _ => None,
     };
 
     Ok(TrackEncryptionBox {
         is_encrypted: default_is_encrypted,
         iv_size: default_iv_size,
         kid: default_kid,
         crypt_byte_block_count: default_crypt_byte_block,
         skip_byte_block_count: default_skip_byte_block,
-        constant_iv: default_constant_iv
+        constant_iv: default_constant_iv,
     })
 }
 
 fn read_frma<T: Read>(src: &mut BMFFBox<T>) -> Result<String> {
     let code_name = read_buf(src, 4)?;
     String::from_utf8(code_name).map_err(From::from)
 }
 
 fn read_schm<T: Read>(src: &mut BMFFBox<T>) -> Result<SchemeTypeBox> {
     // Flags can be used to signal presence of URI in the box, but we don't
     // use the URI so don't bother storing the flags.
     let (_, _) = read_fullbox_extra(src)?;
-    let scheme_type =  FourCC::from(be_u32(src)?);
+    let scheme_type = FourCC::from(be_u32(src)?);
     let scheme_version = be_u32(src)?;
     // Null terminated scheme URI may follow, but we don't use it right now.
     skip_box_remain(src)?;
     Ok(SchemeTypeBox {
         scheme_type,
         scheme_version,
     })
 }
@@ -2552,55 +3317,59 @@ fn read_udta<T: Read>(src: &mut BMFFBox<
     let mut iter = src.box_iter();
     let mut udta = UserdataBox { meta: None };
 
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::MetadataBox => {
                 let meta = read_meta(&mut b)?;
                 udta.meta = Some(meta);
-            },
+            }
             _ => skip_box_content(&mut b)?,
         };
         check_parser_state!(b.content);
     }
     Ok(udta)
 }
 
 /// Parse a metadata box inside a udta box
 fn read_meta<T: Read>(src: &mut BMFFBox<T>) -> Result<MetadataBox> {
     let (_, _) = read_fullbox_extra(src)?;
     let mut iter = src.box_iter();
     let mut meta = MetadataBox::default();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::MetadataItemListEntry => read_ilst(&mut b, &mut meta)?,
-            _ => skip_box_content(&mut b)?
+            _ => skip_box_content(&mut b)?,
         };
         check_parser_state!(b.content);
     }
     Ok(meta)
 }
 
 /// Parse a metadata box inside a udta box
 fn read_ilst<T: Read>(src: &mut BMFFBox<T>, meta: &mut MetadataBox) -> Result<()> {
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::AlbumEntry => meta.album = read_ilst_string_data(&mut b)?,
-            BoxType::ArtistEntry | BoxType::ArtistLowercaseEntry =>
-                meta.artist = read_ilst_string_data(&mut b)?,
+            BoxType::ArtistEntry | BoxType::ArtistLowercaseEntry => {
+                meta.artist = read_ilst_string_data(&mut b)?
+            }
             BoxType::AlbumArtistEntry => meta.album_artist = read_ilst_string_data(&mut b)?,
             BoxType::CommentEntry => meta.comment = read_ilst_string_data(&mut b)?,
             BoxType::DateEntry => meta.year = read_ilst_string_data(&mut b)?,
             BoxType::TitleEntry => meta.title = read_ilst_string_data(&mut b)?,
-            BoxType::CustomGenreEntry => meta.genre = read_ilst_string_data(&mut b)?
-                .map(Genre::CustomGenre),
-            BoxType::StandardGenreEntry => meta.genre = read_ilst_u8_data(&mut b)?
-                .and_then(|gnre| Some(Genre::StandardGenre(gnre.get(1).copied()?))),
+            BoxType::CustomGenreEntry => {
+                meta.genre = read_ilst_string_data(&mut b)?.map(Genre::CustomGenre)
+            }
+            BoxType::StandardGenreEntry => {
+                meta.genre = read_ilst_u8_data(&mut b)?
+                    .and_then(|gnre| Some(Genre::StandardGenre(gnre.get(1).copied()?)))
+            }
             BoxType::ComposerEntry => meta.composer = read_ilst_string_data(&mut b)?,
             BoxType::EncoderEntry => meta.encoder = read_ilst_string_data(&mut b)?,
             BoxType::EncodedByEntry => meta.encoded_by = read_ilst_string_data(&mut b)?,
             BoxType::CopyrightEntry => meta.copyright = read_ilst_string_data(&mut b)?,
             BoxType::GroupingEntry => meta.grouping = read_ilst_string_data(&mut b)?,
             BoxType::CategoryEntry => meta.category = read_ilst_string_data(&mut b)?,
             BoxType::KeywordEntry => meta.keyword = read_ilst_string_data(&mut b)?,
             BoxType::PodcastUrlEntry => meta.podcast_url = read_ilst_string_data(&mut b)?,
@@ -2613,130 +3382,134 @@ fn read_ilst<T: Read>(src: &mut BMFFBox<
             BoxType::TVShowNameEntry => meta.tv_show_name = read_ilst_string_data(&mut b)?,
             BoxType::PurchaseDateEntry => meta.purchase_date = read_ilst_string_data(&mut b)?,
             BoxType::RatingEntry => meta.rating = read_ilst_string_data(&mut b)?,
             BoxType::OwnerEntry => meta.owner = read_ilst_string_data(&mut b)?,
             BoxType::HDVideoEntry => meta.hd_video = read_ilst_bool_data(&mut b)?,
             BoxType::SortNameEntry => meta.sort_name = read_ilst_string_data(&mut b)?,
             BoxType::SortArtistEntry => meta.sort_artist = read_ilst_string_data(&mut b)?,
             BoxType::SortAlbumEntry => meta.sort_album = read_ilst_string_data(&mut b)?,
-            BoxType::SortAlbumArtistEntry => meta.sort_album_artist = read_ilst_string_data(&mut b)?,
+            BoxType::SortAlbumArtistEntry => {
+                meta.sort_album_artist = read_ilst_string_data(&mut b)?
+            }
             BoxType::SortComposerEntry => meta.sort_composer = read_ilst_string_data(&mut b)?,
             BoxType::TrackNumberEntry => {
                 if let Some(trkn) = read_ilst_u8_data(&mut b)? {
                     meta.track_number = trkn.get(3).copied();
                     meta.total_tracks = trkn.get(5).copied();
                 };
-            },
+            }
             BoxType::DiskNumberEntry => {
                 if let Some(disk) = read_ilst_u8_data(&mut b)? {
                     meta.disc_number = disk.get(3).copied();
                     meta.total_discs = disk.get(5).copied();
                 };
-            },
-            BoxType::TempoEntry => meta.beats_per_minute = read_ilst_u8_data(&mut b)?
-                .and_then(|tmpo| tmpo.get(1).copied()),
+            }
+            BoxType::TempoEntry => {
+                meta.beats_per_minute =
+                    read_ilst_u8_data(&mut b)?.and_then(|tmpo| tmpo.get(1).copied())
+            }
             BoxType::CompilationEntry => meta.compilation = read_ilst_bool_data(&mut b)?,
-            BoxType::AdvisoryEntry => meta.advisory = read_ilst_u8_data(&mut b)?
-                .and_then(|rtng| {
+            BoxType::AdvisoryEntry => {
+                meta.advisory = read_ilst_u8_data(&mut b)?.and_then(|rtng| {
                     Some(match rtng.get(0)? {
                         2 => AdvisoryRating::Clean,
                         0 => AdvisoryRating::Inoffensive,
                         r => AdvisoryRating::Explicit(*r),
                     })
-                }),
-            BoxType::MediaTypeEntry => meta.media_type = read_ilst_u8_data(&mut b)?
-                .and_then(|stik| {
+                })
+            }
+            BoxType::MediaTypeEntry => {
+                meta.media_type = read_ilst_u8_data(&mut b)?.and_then(|stik| {
                     Some(match stik.get(0)? {
                         0 => MediaType::Movie,
                         1 => MediaType::Normal,
                         2 => MediaType::AudioBook,
                         5 => MediaType::WhackedBookmark,
                         6 => MediaType::MusicVideo,
                         9 => MediaType::ShortFilm,
                         10 => MediaType::TVShow,
                         11 => MediaType::Booklet,
-                        s => MediaType::Unknown(*s)
+                        s => MediaType::Unknown(*s),
                     })
-                }),
+                })
+            }
             BoxType::PodcastEntry => meta.podcast = read_ilst_bool_data(&mut b)?,
-            BoxType::TVSeasonNumberEntry => meta.tv_season = read_ilst_u8_data(&mut b)?
-                .and_then(|tvsn| tvsn.get(3).copied()),
-            BoxType::TVEpisodeNumberEntry => meta.tv_episode_number = read_ilst_u8_data(&mut b)?
-                .and_then(|tves| tves.get(3).copied()),
+            BoxType::TVSeasonNumberEntry => {
+                meta.tv_season = read_ilst_u8_data(&mut b)?.and_then(|tvsn| tvsn.get(3).copied())
+            }
+            BoxType::TVEpisodeNumberEntry => {
+                meta.tv_episode_number =
+                    read_ilst_u8_data(&mut b)?.and_then(|tves| tves.get(3).copied())
+            }
             BoxType::GaplessPlaybackEntry => meta.gapless_playback = read_ilst_bool_data(&mut b)?,
             BoxType::CoverArtEntry => meta.cover_art = read_ilst_multiple_u8_data(&mut b).ok(),
             _ => skip_box_content(&mut b)?,
-
         };
         check_parser_state!(b.content);
     }
     Ok(())
 }
 
 fn read_ilst_bool_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<bool>> {
     Ok(read_ilst_u8_data(src)?.and_then(|d| Some(d.get(0)? == &1)))
 }
 
 fn read_ilst_string_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<String>> {
-    read_ilst_u8_data(src)?
-        .map_or(Ok(None),
-                |d| String::from_utf8(d)
-                    .map_err(From::from)
-                    .map(Some)
-        )
+    read_ilst_u8_data(src)?.map_or(Ok(None), |d| {
+        String::from_utf8(d).map_err(From::from).map(Some)
+    })
 }
 
 fn read_ilst_u8_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<Vec<u8>>> {
     // For all non-covr atoms, there must only be one data atom.
     Ok(read_ilst_multiple_u8_data(src)?.pop())
 }
 
 fn read_ilst_multiple_u8_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Vec<Vec<u8>>> {
     let mut iter = src.box_iter();
     let mut data = Vec::new();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::MetadataItemDataEntry => {
-                data.push(read_ilst_data(&mut b)?);
+                vec_push(&mut data, read_ilst_data(&mut b)?)?;
             }
             _ => skip_box_content(&mut b)?,
         };
         check_parser_state!(b.content);
     }
     Ok(data)
 }
 
 fn read_ilst_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Vec<u8>> {
     // Skip past the padding bytes
     skip(&mut src.content, src.head.offset)?;
-    let size = src.content.limit().try_into()?;
+    let size = src.content.limit();
     read_buf(&mut src.content, size)
 }
 
 /// Skip a number of bytes that we don't care to parse.
 fn skip<T: Read>(src: &mut T, bytes: u64) -> Result<()> {
     std::io::copy(&mut src.take(bytes), &mut std::io::sink())?;
     Ok(())
 }
 
 /// Read size bytes into a Vector or return error.
-fn read_buf<T: ReadBytesExt>(src: &mut T, size: usize) -> Result<Vec<u8>> {
+fn read_buf<T: Read>(src: &mut T, size: u64) -> Result<Vec<u8>> {
     if size > BUF_SIZE_LIMIT {
         return Err(Error::InvalidData("read_buf size exceeds BUF_SIZE_LIMIT"));
     }
-    if let Ok(mut buf) = allocate_read_buf(size) {
-        let r = src.read(&mut buf)?;
-        if r != size {
-          return Err(Error::InvalidData("failed buffer read"));
-        }
-        return Ok(buf);
+
+    let mut buf = vec![];
+    let r: u64 = read_to_end(&mut src.take(size), &mut buf)?.try_into()?;
+    if r != size {
+        return Err(Error::InvalidData("failed buffer read"));
     }
 
-    Err(Error::OutOfMemory)
+    Ok(buf)
 }
 
 fn be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16> {
     src.read_i16::<byteorder::BigEndian>().map_err(From::from)
 }
 
 fn be_i32<T: ReadBytesExt>(src: &mut T) -> Result<i32> {
     src.read_i32::<byteorder::BigEndian>().map_err(From::from)
@@ -2768,10 +3541,11 @@ fn be_u32_with_limit<T: ReadBytesExt>(sr
     })
 }
 
 fn be_u64<T: ReadBytesExt>(src: &mut T) -> Result<u64> {
     src.read_u64::<byteorder::BigEndian>().map_err(From::from)
 }
 
 fn write_be_u32<T: WriteBytesExt>(des: &mut T, num: u32) -> Result<()> {
-    des.write_u32::<byteorder::BigEndian>(num).map_err(From::from)
+    des.write_u32::<byteorder::BigEndian>(num)
+        .map_err(From::from)
 }
--- a/media/mp4parse-rust/mp4parse/src/macros.rs
+++ b/media/mp4parse-rust/mp4parse/src/macros.rs
@@ -3,10 +3,10 @@
 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
 
 macro_rules! check_parser_state {
     ( $src:expr ) => {
         if $src.limit() > 0 {
             debug!("bad parser state: {} content bytes left", $src.limit());
             return Err(Error::InvalidData("unread box content or bad parser sync"));
         }
-    }
+    };
 }
--- a/media/mp4parse-rust/mp4parse/src/tests.rs
+++ b/media/mp4parse-rust/mp4parse/src/tests.rs
@@ -1,35 +1,39 @@
 //! Module for parsing ISO Base Media Format aka video/mp4 streams.
 //! Internal unit tests.
 
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
 
+use super::read_mp4;
+use super::Error;
+use super::MediaContext;
+#[cfg(feature = "mp4parse_fallible")]
+use std::convert::TryInto as _;
 use std::io::Cursor;
-use super::read_mp4;
-use super::MediaContext;
-use super::Error;
+use std::io::Read as _;
 extern crate test_assembler;
 use self::test_assembler::*;
 
 use boxes::{BoxType, FourCC};
 
 enum BoxSize {
     Short(u32),
     Long(u64),
     UncheckedShort(u32),
     UncheckedLong(u64),
     Auto,
 }
 
 #[allow(clippy::trivially_copy_pass_by_ref)] // TODO: Consider reworking to a copy
 fn make_box<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
-    where F: Fn(Section) -> Section
+where
+    F: Fn(Section) -> Section,
 {
     let mut section = Section::new();
     let box_size = Label::new();
     section = match size {
         BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
         BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
         BoxSize::Auto => section.B32(&box_size),
     };
@@ -49,47 +53,46 @@ fn make_box<F>(size: BoxSize, name: &[u8
     match size {
         BoxSize::Short(size) => {
             if size > 0 {
                 assert_eq!(u64::from(size), section.size())
             }
         }
         BoxSize::Long(size) => assert_eq!(size, section.size()),
         BoxSize::Auto => {
-            assert!(section.size() <= u64::from(u32::max_value()),
-                    "Tried to use a long box with BoxSize::Auto");
+            assert!(
+                section.size() <= u64::from(u32::max_value()),
+                "Tried to use a long box with BoxSize::Auto"
+            );
             box_size.set_const(section.size());
         }
         // Skip checking BoxSize::Unchecked* cases.
         _ => (),
     }
     Cursor::new(section.get_contents().unwrap())
 }
 
 fn make_uuid_box<F>(size: BoxSize, uuid: &[u8; 16], func: F) -> Cursor<Vec<u8>>
-    where F: Fn(Section) -> Section
+where
+    F: Fn(Section) -> Section,
 {
     make_box(size, b"uuid", |mut s| {
         for b in uuid {
             s = s.B8(*b);
         }
         func(s)
     })
 }
 
 #[allow(clippy::trivially_copy_pass_by_ref)] // TODO: Consider reworking to a copy
 fn make_fullbox<F>(size: BoxSize, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
-    where F: Fn(Section) -> Section
+where
+    F: Fn(Section) -> Section,
 {
-    make_box(size, name, |s| {
-        func(s.B8(version)
-              .B8(0)
-              .B8(0)
-              .B8(0))
-    })
+    make_box(size, name, |s| func(s.B8(version).B8(0).B8(0).B8(0)))
 }
 
 #[test]
 fn read_box_header_short() {
     let mut stream = make_box(BoxSize::Short(8), b"test", |s| s);
     let header = super::read_box_header(&mut stream).unwrap();
     assert_eq!(header.name, BoxType::UnknownBox(0x7465_7374)); // "test"
     assert_eq!(header.size, 8);
@@ -130,55 +133,51 @@ fn read_box_header_long_invalid_size() {
         Err(Error::InvalidData(s)) => assert_eq!(s, "malformed wide size"),
         _ => panic!("unexpected result reading box with invalid size"),
     };
 }
 
 #[test]
 fn read_box_header_uuid() {
     const HEADER_UUID: [u8; 16] = [
-        0x85, 0xc0, 0xb6,0x87,
-        0x82, 0x0f,
-        0x11, 0xe0,
-        0x81, 0x11,
-        0xf4, 0xce, 0x46, 0x2b, 0x6a, 0x48 ];
+        0x85, 0xc0, 0xb6, 0x87, 0x82, 0x0f, 0x11, 0xe0, 0x81, 0x11, 0xf4, 0xce, 0x46, 0x2b, 0x6a,
+        0x48,
+    ];
 
     let mut stream = make_uuid_box(BoxSize::Short(24), &HEADER_UUID, |s| s);
     let mut iter = super::BoxIter::new(&mut stream);
     let stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::UuidBox);
     assert_eq!(stream.head.size, 24);
     assert!(stream.head.uuid.is_some());
     assert_eq!(stream.head.uuid.unwrap(), HEADER_UUID);
 }
 
 #[test]
 fn read_box_header_truncated_uuid() {
     const HEADER_UUID: [u8; 16] = [
-        0x85, 0xc0, 0xb6,0x87,
-        0x82, 0x0f,
-        0x11, 0xe0,
-        0x81, 0x11,
-        0xf4, 0xce, 0x46, 0x2b, 0x6a, 0x48 ];
+        0x85, 0xc0, 0xb6, 0x87, 0x82, 0x0f, 0x11, 0xe0, 0x81, 0x11, 0xf4, 0xce, 0x46, 0x2b, 0x6a,
+        0x48,
+    ];
 
     let mut stream = make_uuid_box(BoxSize::UncheckedShort(23), &HEADER_UUID, |s| s);
     let mut iter = super::BoxIter::new(&mut stream);
     let stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::UuidBox);
     assert_eq!(stream.head.size, 23);
     assert!(stream.head.uuid.is_none());
 }
 
 #[test]
 fn read_ftyp() {
     let mut stream = make_box(BoxSize::Short(24), b"ftyp", |s| {
         s.append_bytes(b"mp42")
-         .B32(0) // minor version
-         .append_bytes(b"isom")
-         .append_bytes(b"mp42")
+            .B32(0) // minor version
+            .append_bytes(b"isom")
+            .append_bytes(b"mp42")
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::FileTypeBox);
     assert_eq!(stream.head.size, 24);
     let parsed = super::read_ftyp(&mut stream).unwrap();
     assert_eq!(parsed.major_brand, FourCC::from("mp42")); // mp42
     assert_eq!(parsed.minor_version, 0);
@@ -208,19 +207,19 @@ fn read_ftyp_case() {
     // Brands in BMFF are represented as a u32, so it would seem clear that
     // 0x6d703432 ("mp42") is not equal to 0x4d503432 ("MP42"), but some
     // demuxers treat these as case-insensitive strings, e.g. street.mp4's
     // major brand is "MP42".  I haven't seen case-insensitive
     // compatible_brands (which we also test here), but it doesn't seem
     // unlikely given the major_brand behaviour.
     let mut stream = make_box(BoxSize::Auto, b"ftyp", |s| {
         s.append_bytes(b"MP42")
-         .B32(0) // minor version
-         .append_bytes(b"ISOM")
-         .append_bytes(b"MP42")
+            .B32(0) // minor version
+            .append_bytes(b"ISOM")
+            .append_bytes(b"MP42")
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::FileTypeBox);
     assert_eq!(stream.head.size, 24);
     let parsed = super::read_ftyp(&mut stream).unwrap();
     assert_eq!(parsed.major_brand, FourCC::from("MP42"));
     assert_eq!(parsed.minor_version, 0);
@@ -228,21 +227,21 @@ fn read_ftyp_case() {
     assert_eq!(parsed.compatible_brands[0], FourCC::from("ISOM")); // ISOM
     assert_eq!(parsed.compatible_brands[1], FourCC::from("MP42")); // MP42
 }
 
 #[test]
 fn read_elst_v0() {
     let mut stream = make_fullbox(BoxSize::Short(28), b"elst", 0, |s| {
         s.B32(1) // list count
-          // first entry
-         .B32(1234) // duration
-         .B32(5678) // time
-         .B16(12) // rate integer
-         .B16(34) // rate fraction
+            // first entry
+            .B32(1234) // duration
+            .B32(5678) // time
+            .B16(12) // rate integer
+            .B16(34) // rate fraction
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::EditListBox);
     assert_eq!(stream.head.size, 28);
     let parsed = super::read_elst(&mut stream).unwrap();
     assert_eq!(parsed.edits.len(), 1);
     assert_eq!(parsed.edits[0].segment_duration, 1234);
@@ -250,26 +249,26 @@ fn read_elst_v0() {
     assert_eq!(parsed.edits[0].media_rate_integer, 12);
     assert_eq!(parsed.edits[0].media_rate_fraction, 34);
 }
 
 #[test]
 fn read_elst_v1() {
     let mut stream = make_fullbox(BoxSize::Short(56), b"elst", 1, |s| {
         s.B32(2) // list count
-         // first entry
-         .B64(1234) // duration
-         .B64(5678) // time
-         .B16(12) // rate integer
-         .B16(34) // rate fraction
-         // second entry
-         .B64(1234) // duration
-         .B64(5678) // time
-         .B16(12) // rate integer
-         .B16(34) // rate fraction
+            // first entry
+            .B64(1234) // duration
+            .B64(5678) // time
+            .B16(12) // rate integer
+            .B16(34) // rate fraction
+            // second entry
+            .B64(1234) // duration
+            .B64(5678) // time
+            .B16(12) // rate integer
+            .B16(34) // rate fraction
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::EditListBox);
     assert_eq!(stream.head.size, 56);
     let parsed = super::read_elst(&mut stream).unwrap();
     assert_eq!(parsed.edits.len(), 2);
     assert_eq!(parsed.edits[1].segment_duration, 1234);
@@ -277,282 +276,265 @@ fn read_elst_v1() {
     assert_eq!(parsed.edits[1].media_rate_integer, 12);
     assert_eq!(parsed.edits[1].media_rate_fraction, 34);
 }
 
 #[test]
 fn read_mdhd_v0() {
     let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd", 0, |s| {
         s.B32(0)
-         .B32(0)
-         .B32(1234) // timescale
-         .B32(5678) // duration
-         .B32(0)
+            .B32(0)
+            .B32(1234) // timescale
+            .B32(5678) // duration
+            .B32(0)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
     assert_eq!(stream.head.size, 32);
     let parsed = super::read_mdhd(&mut stream).unwrap();
     assert_eq!(parsed.timescale, 1234);
     assert_eq!(parsed.duration, 5678);
 }
 
 #[test]
 fn read_mdhd_v1() {
     let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd", 1, |s| {
         s.B64(0)
-         .B64(0)
-         .B32(1234) // timescale
-         .B64(5678) // duration
-         .B32(0)
+            .B64(0)
+            .B32(1234) // timescale
+            .B64(5678) // duration
+            .B32(0)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
     assert_eq!(stream.head.size, 44);
     let parsed = super::read_mdhd(&mut stream).unwrap();
     assert_eq!(parsed.timescale, 1234);
     assert_eq!(parsed.duration, 5678);
 }
 
 #[test]
 fn read_mdhd_unknown_duration() {
     let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd", 0, |s| {
         s.B32(0)
-         .B32(0)
-         .B32(1234) // timescale
-         .B32(::std::u32::MAX) // duration
-         .B32(0)
+            .B32(0)
+            .B32(1234) // timescale
+            .B32(::std::u32::MAX) // duration
+            .B32(0)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
     assert_eq!(stream.head.size, 32);
     let parsed = super::read_mdhd(&mut stream).unwrap();
     assert_eq!(parsed.timescale, 1234);
     assert_eq!(parsed.duration, ::std::u64::MAX);
 }
 
 #[test]
 fn read_mdhd_invalid_timescale() {
     let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd", 1, |s| {
         s.B64(0)
-         .B64(0)
-         .B32(0) // timescale
-         .B64(5678) // duration
-         .B32(0)
+            .B64(0)
+            .B32(0) // timescale
+            .B64(5678) // duration
+            .B32(0)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
     assert_eq!(stream.head.size, 44);
     let r = super::parse_mdhd(&mut stream, &mut super::Track::new(0));
     assert_eq!(r.is_err(), true);
 }
 
 #[test]
 fn read_mvhd_v0() {
     let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd", 0, |s| {
-        s.B32(0)
-         .B32(0)
-         .B32(1234)
-         .B32(5678)
-         .append_repeated(0, 80)
+        s.B32(0).B32(0).B32(1234).B32(5678).append_repeated(0, 80)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
     assert_eq!(stream.head.size, 108);
     let parsed = super::read_mvhd(&mut stream).unwrap();
     assert_eq!(parsed.timescale, 1234);
     assert_eq!(parsed.duration, 5678);
 }
 
 #[test]
 fn read_mvhd_v1() {
     let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd", 1, |s| {
-        s.B64(0)
-         .B64(0)
-         .B32(1234)
-         .B64(5678)
-         .append_repeated(0, 80)
+        s.B64(0).B64(0).B32(1234).B64(5678).append_repeated(0, 80)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
     assert_eq!(stream.head.size, 120);
     let parsed = super::read_mvhd(&mut stream).unwrap();
     assert_eq!(parsed.timescale, 1234);
     assert_eq!(parsed.duration, 5678);
 }
 
 #[test]
 fn read_mvhd_invalid_timescale() {
     let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd", 1, |s| {
-        s.B64(0)
-         .B64(0)
-         .B32(0)
-         .B64(5678)
-         .append_repeated(0, 80)
+        s.B64(0).B64(0).B32(0).B64(5678).append_repeated(0, 80)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
     assert_eq!(stream.head.size, 120);
     let r = super::parse_mvhd(&mut stream);
     assert_eq!(r.is_err(), true);
 }
 
 #[test]
 fn read_mvhd_unknown_duration() {
     let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd", 0, |s| {
         s.B32(0)
-         .B32(0)
-         .B32(1234)
-         .B32(::std::u32::MAX)
-         .append_repeated(0, 80)
+            .B32(0)
+            .B32(1234)
+            .B32(::std::u32::MAX)
+            .append_repeated(0, 80)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
     assert_eq!(stream.head.size, 108);
     let parsed = super::read_mvhd(&mut stream).unwrap();
     assert_eq!(parsed.timescale, 1234);
     assert_eq!(parsed.duration, ::std::u64::MAX);
 }
 
 #[test]
 fn read_vpcc_version_0() {
     let data_length = 12u16;
     let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 0, |s| {
         s.B8(2)
-         .B8(0)
-         .B8(0x82)
-         .B8(0)
-         .B16(data_length)
-         .append_repeated(42, data_length as usize)
+            .B8(0)
+            .B8(0x82)
+            .B8(0)
+            .B16(data_length)
+            .append_repeated(42, data_length as usize)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::VPCodecConfigurationBox);
     let r = super::read_vpcc(&mut stream);
     assert!(r.is_ok());
 }
 
 // TODO: it'd be better to find a real sample here.
 #[test]
 #[allow(clippy::inconsistent_digit_grouping)] // Allow odd grouping for test readability.
 fn read_vpcc_version_1() {
     let data_length = 12u16;
     let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 1, |s| {
-        s.B8(2)     // profile
-         .B8(0)     // level
-         .B8(0b1000_011_0)  // bitdepth (4 bits), chroma (3 bits), video full range (1 bit)
-         .B8(1)     // color primaries
-         .B8(1)     // transfer characteristics
-         .B8(1)     // matrix
-         .B16(data_length)
-         .append_repeated(42, data_length as usize)
+        s.B8(2) // profile
+            .B8(0) // level
+            .B8(0b1000_011_0) // bitdepth (4 bits), chroma (3 bits), video full range (1 bit)
+            .B8(1) // color primaries
+            .B8(1) // transfer characteristics
+            .B8(1) // matrix
+            .B16(data_length)
+            .append_repeated(42, data_length as usize)
     });
 
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::VPCodecConfigurationBox);
     let r = super::read_vpcc(&mut stream);
     match r {
         Ok(vpcc) => {
             assert_eq!(vpcc.bit_depth, 8);
             assert_eq!(vpcc.chroma_subsampling, 3);
             assert_eq!(vpcc.video_full_range_flag, false);
             assert_eq!(vpcc.matrix_coefficients.unwrap(), 1);
-        },
+        }
         _ => panic!("vpcc parsing error"),
     }
 }
 
 #[test]
 fn read_hdlr() {
     let mut stream = make_fullbox(BoxSize::Short(45), b"hdlr", 0, |s| {
         s.B32(0)
-         .append_bytes(b"vide")
-         .B32(0)
-         .B32(0)
-         .B32(0)
-         .append_bytes(b"VideoHandler")
-         .B8(0) // null-terminate string
+            .append_bytes(b"vide")
+            .B32(0)
+            .B32(0)
+            .B32(0)
+            .append_bytes(b"VideoHandler")
+            .B8(0) // null-terminate string
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::HandlerBox);
     assert_eq!(stream.head.size, 45);
     let parsed = super::read_hdlr(&mut stream).unwrap();
     assert_eq!(parsed.handler_type, FourCC::from("vide"));
 }
 
 #[test]
 fn read_hdlr_short_name() {
     let mut stream = make_fullbox(BoxSize::Short(33), b"hdlr", 0, |s| {
-        s.B32(0)
-         .append_bytes(b"vide")
-         .B32(0)
-         .B32(0)
-         .B32(0)
-         .B8(0) // null-terminate string
+        s.B32(0).append_bytes(b"vide").B32(0).B32(0).B32(0).B8(0) // null-terminate string
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::HandlerBox);
     assert_eq!(stream.head.size, 33);
     let parsed = super::read_hdlr(&mut stream).unwrap();
     assert_eq!(parsed.handler_type, FourCC::from("vide"));
 }
 
 #[test]
 fn read_hdlr_zero_length_name() {
     let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr", 0, |s| {
-        s.B32(0)
-         .append_bytes(b"vide")
-         .B32(0)
-         .B32(0)
-         .B32(0)
+        s.B32(0).append_bytes(b"vide").B32(0).B32(0).B32(0)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::HandlerBox);
     assert_eq!(stream.head.size, 32);
     let parsed = super::read_hdlr(&mut stream).unwrap();
     assert_eq!(parsed.handler_type, FourCC::from("vide"));
 }
 
 fn flac_streaminfo() -> Vec<u8> {
     vec![
-        0x10, 0x00, 0x10, 0x00, 0x00, 0x0a, 0x11, 0x00,
-        0x38, 0x32, 0x0a, 0xc4, 0x42, 0xf0, 0x00, 0xc9,
-        0xdf, 0xae, 0xb5, 0x66, 0xfc, 0x02, 0x15, 0xa3,
-        0xb1, 0x54, 0x61, 0x47, 0x0f, 0xfb, 0x05, 0x00,
-        0x33, 0xad,
+        0x10, 0x00, 0x10, 0x00, 0x00, 0x0a, 0x11, 0x00, 0x38, 0x32, 0x0a, 0xc4, 0x42, 0xf0, 0x00,
+        0xc9, 0xdf, 0xae, 0xb5, 0x66, 0xfc, 0x02, 0x15, 0xa3, 0xb1, 0x54, 0x61, 0x47, 0x0f, 0xfb,
+        0x05, 0x00, 0x33, 0xad,
     ]
 }
 
 #[test]
 fn read_flac() {
     let mut stream = make_box(BoxSize::Auto, b"fLaC", |s| {
         s.append_repeated(0, 6) // reserved
-         .B16(1) // data reference index
-         .B32(0) // reserved
-         .B32(0) // reserved
-         .B16(2) // channel count
-         .B16(16) // bits per sample
-         .B16(0) // pre_defined
-         .B16(0) // reserved
-         .B32(44100 << 16) // Sample rate
-         .append_bytes(&make_dfla(FlacBlockType::StreamInfo, true,
-                                  &flac_streaminfo(), FlacBlockLength::Correct)
-         .into_inner())
+            .B16(1) // data reference index
+            .B32(0) // reserved
+            .B32(0) // reserved
+            .B16(2) // channel count
+            .B16(16) // bits per sample
+            .B16(0) // pre_defined
+            .B16(0) // reserved
+            .B32(44100 << 16) // Sample rate
+            .append_bytes(
+                &make_dfla(
+                    FlacBlockType::StreamInfo,
+                    true,
+                    &flac_streaminfo(),
+                    FlacBlockLength::Correct,
+                )
+                .into_inner(),
+            )
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     let r = super::read_audio_sample_entry(&mut stream);
     assert!(r.is_ok());
 }
 
 #[derive(Clone, Copy)]
@@ -568,86 +550,97 @@ enum FlacBlockType {
     _Invalid = 127,
 }
 
 enum FlacBlockLength {
     Correct,
     Incorrect(usize),
 }
 
-fn make_dfla(block_type: FlacBlockType, last: bool, data: &[u8],
-             data_length: FlacBlockLength) -> Cursor<Vec<u8>> {
-    assert!(data.len() < 1<<24);
+fn make_dfla(
+    block_type: FlacBlockType,
+    last: bool,
+    data: &[u8],
+    data_length: FlacBlockLength,
+) -> Cursor<Vec<u8>> {
+    assert!(data.len() < 1 << 24);
     make_fullbox(BoxSize::Auto, b"dfLa", 0, |s| {
         let flag = if last { 1 } else { 0 };
         let size = match data_length {
             FlacBlockLength::Correct => (data.len() as u32) & 0x00ff_ffff,
             FlacBlockLength::Incorrect(size) => {
-                assert!(size < 1<<24);
+                assert!(size < 1 << 24);
                 (size as u32) & 0x00ff_ffff
             }
         };
         let block_type = (block_type as u32) & 0x7f;
         s.B32(flag << 31 | block_type << 24 | size)
-         .append_bytes(data)
+            .append_bytes(data)
     })
 }
 
 #[test]
 fn read_dfla() {
-    let mut stream = make_dfla(FlacBlockType::StreamInfo, true,
-                               &flac_streaminfo(), FlacBlockLength::Correct);
+    let mut stream = make_dfla(
+        FlacBlockType::StreamInfo,
+        true,
+        &flac_streaminfo(),
+        FlacBlockLength::Correct,
+    );
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
     let dfla = super::read_dfla(&mut stream).unwrap();
     assert_eq!(dfla.version, 0);
 }
 
 #[test]
 fn long_flac_metadata() {
     let streaminfo = flac_streaminfo();
-    let mut stream = make_dfla(FlacBlockType::StreamInfo, true,
-                               &streaminfo,
-                               FlacBlockLength::Incorrect(streaminfo.len() + 4));
+    let mut stream = make_dfla(
+        FlacBlockType::StreamInfo,
+        true,
+        &streaminfo,
+        FlacBlockLength::Incorrect(streaminfo.len() + 4),
+    );
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
     let r = super::read_dfla(&mut stream);
     assert!(r.is_err());
 }
 
 #[test]
 fn read_opus() {
     let mut stream = make_box(BoxSize::Auto, b"Opus", |s| {
         s.append_repeated(0, 6)
-         .B16(1) // data reference index
-         .B32(0)
-         .B32(0)
-         .B16(2) // channel count
-         .B16(16) // bits per sample
-         .B16(0)
-         .B16(0)
-         .B32(48000 << 16) // Sample rate is always 48 kHz for Opus.
-         .append_bytes(&make_dops().into_inner())
+            .B16(1) // data reference index
+            .B32(0)
+            .B32(0)
+            .B16(2) // channel count
+            .B16(16) // bits per sample
+            .B16(0)
+            .B16(0)
+            .B32(48000 << 16) // Sample rate is always 48 kHz for Opus.
+            .append_bytes(&make_dops().into_inner())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     let r = super::read_audio_sample_entry(&mut stream);
     assert!(r.is_ok());
 }
 
 fn make_dops() -> Cursor<Vec<u8>> {
     make_box(BoxSize::Auto, b"dOps", |s| {
         s.B8(0) // version
-         .B8(2) // channel count
-         .B16(348) // pre-skip
-         .B32(44100) // original sample rate
-         .B16(0) // gain
-         .B8(0) // channel mapping
+            .B8(2) // channel count
+            .B16(348) // pre-skip
+            .B32(44100) // original sample rate
+            .B16(0) // gain
+            .B8(0) // channel mapping
     })
 }
 
 #[test]
 fn read_dops() {
     let mut stream = make_dops();
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
@@ -665,166 +658,164 @@ fn serialize_opus_header() {
         input_sample_rate: 24000,
         output_gain: 0,
         channel_mapping_family: 0,
         channel_mapping_table: None,
     };
     let mut v = Vec::<u8>::new();
     super::serialize_opus_header(&opus, &mut v).unwrap();
     assert_eq!(v.len(), 19);
-    assert_eq!(v, vec![
-            0x4f, 0x70, 0x75, 0x73, 0x48,0x65, 0x61, 0x64,
-            0x01, 0x01, 0x56, 0x01,
-            0xc0, 0x5d, 0x00, 0x00,
-            0x00, 0x00, 0x00,
-    ]);
+    assert_eq!(
+        v,
+        vec![
+            0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x01, 0x56, 0x01, 0xc0, 0x5d,
+            0x00, 0x00, 0x00, 0x00, 0x00,
+        ]
+    );
     let opus = super::OpusSpecificBox {
         version: 0,
         output_channel_count: 6,
         pre_skip: 152,
         input_sample_rate: 48000,
         output_gain: 0,
         channel_mapping_family: 1,
         channel_mapping_table: Some(super::ChannelMappingTable {
             stream_count: 4,
             coupled_count: 2,
             channel_mapping: vec![0, 4, 1, 2, 3, 5],
         }),
     };
     let mut v = Vec::<u8>::new();
     super::serialize_opus_header(&opus, &mut v).unwrap();
     assert_eq!(v.len(), 27);
-    assert_eq!(v, vec![
-            0x4f, 0x70, 0x75, 0x73, 0x48,0x65, 0x61, 0x64,
-            0x01, 0x06, 0x98, 0x00,
-            0x80, 0xbb, 0x00, 0x00,
-            0x00, 0x00, 0x01, 0x04, 0x02,
-            0x00, 0x04, 0x01, 0x02, 0x03, 0x05,
-    ]);
+    assert_eq!(
+        v,
+        vec![
+            0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x06, 0x98, 0x00, 0x80, 0xbb,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x02, 0x00, 0x04, 0x01, 0x02, 0x03, 0x05,
+        ]
+    );
 }
 
 #[test]
 fn read_alac() {
     let mut stream = make_box(BoxSize::Auto, b"alac", |s| {
         s.append_repeated(0, 6) // reserved
-         .B16(1) // data reference index
-         .B32(0) // reserved
-         .B32(0) // reserved
-         .B16(2) // channel count
-         .B16(16) // bits per sample
-         .B16(0) // pre_defined
-         .B16(0) // reserved
-         .B32(44100 << 16) // Sample rate
-         .append_bytes(&make_fullbox(BoxSize::Auto, b"alac", 0, |s| {
-             s.append_bytes(&[0xfa; 24])
-         }).into_inner())
+            .B16(1) // data reference index
+            .B32(0) // reserved
+            .B32(0) // reserved
+            .B16(2) // channel count
+            .B16(16) // bits per sample
+            .B16(0) // pre_defined
+            .B16(0) // reserved
+            .B32(44100 << 16) // Sample rate
+            .append_bytes(
+                &make_fullbox(BoxSize::Auto, b"alac", 0, |s| s.append_bytes(&[0xfa; 24]))
+                    .into_inner(),
+            )
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     let r = super::read_audio_sample_entry(&mut stream);
     assert!(r.is_ok());
 }
 
 #[test]
 fn avcc_limit() {
     let mut stream = make_box(BoxSize::Auto, b"avc1", |s| {
         s.append_repeated(0, 6)
-         .B16(1)
-         .append_repeated(0, 16)
-         .B16(320)
-         .B16(240)
-         .append_repeated(0, 14)
-         .append_repeated(0, 32)
-         .append_repeated(0, 4)
-         .B32(0xffff_ffff)
-         .append_bytes(b"avcC")
-         .append_repeated(0, 100)
+            .B16(1)
+            .append_repeated(0, 16)
+            .B16(320)
+            .B16(240)
+            .append_repeated(0, 14)
+            .append_repeated(0, 32)
+            .append_repeated(0, 4)
+            .B32(0xffff_ffff)
+            .append_bytes(b"avcC")
+            .append_repeated(0, 100)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     match super::read_video_sample_entry(&mut stream) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "read_buf size exceeds BUF_SIZE_LIMIT"),
         Ok(_) => panic!("expected an error result"),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn esds_limit() {
     let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
         s.append_repeated(0, 6)
-         .B16(1)
-         .B32(0)
-         .B32(0)
-         .B16(2)
-         .B16(16)
-         .B16(0)
-         .B16(0)
-         .B32(48000 << 16)
-         .B32(0xffff_ffff)
-         .append_bytes(b"esds")
-         .append_repeated(0, 100)
+            .B16(1)
+            .B32(0)
+            .B32(0)
+            .B16(2)
+            .B16(16)
+            .B16(0)
+            .B16(0)
+            .B32(48000 << 16)
+            .B32(0xffff_ffff)
+            .append_bytes(b"esds")
+            .append_repeated(0, 100)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     match super::read_audio_sample_entry(&mut stream) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "read_buf size exceeds BUF_SIZE_LIMIT"),
         Ok(_) => panic!("expected an error result"),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn esds_limit_2() {
     let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
         s.append_repeated(0, 6)
-         .B16(1)
-         .B32(0)
-         .B32(0)
-         .B16(2)
-         .B16(16)
-         .B16(0)
-         .B16(0)
-         .B32(48000 << 16)
-         .B32(8)
-         .append_bytes(b"esds")
-         .append_repeated(0, 4)
+            .B16(1)
+            .B32(0)
+            .B32(0)
+            .B16(2)
+            .B16(16)
+            .B16(0)
+            .B16(0)
+            .B32(48000 << 16)
+            .B32(8)
+            .append_bytes(b"esds")
+            .append_repeated(0, 4)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     match super::read_audio_sample_entry(&mut stream) {
         Err(Error::UnexpectedEOF) => (),
         Ok(_) => panic!("expected an error result"),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn read_elst_zero_entries() {
-    let mut stream = make_fullbox(BoxSize::Auto, b"elst", 0, |s| {
-        s.B32(0)
-         .B16(12)
-         .B16(34)
-    });
+    let mut stream = make_fullbox(BoxSize::Auto, b"elst", 0, |s| s.B32(0).B16(12).B16(34));
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     match super::read_elst(&mut stream) {
         Ok(elst) => assert_eq!(elst.edits.len(), 0),
         _ => panic!("expected no error"),
     }
 }
 
 fn make_elst() -> Cursor<Vec<u8>> {
     make_fullbox(BoxSize::Auto, b"elst", 1, |s| {
         s.B32(1)
-        // first entry
-         .B64(1234) // duration
-         .B64(0xffff_ffff_ffff_ffff) // time
-         .B16(12) // rate integer
-         .B16(34) // rate fraction
+            // first entry
+            .B64(1234) // duration
+            .B64(0xffff_ffff_ffff_ffff) // time
+            .B16(12) // rate integer
+            .B16(34) // rate fraction
     })
 }
 
 #[test]
 fn read_edts_bogus() {
     // First edit list entry has a media_time of -1, so we expect a second
     // edit list entry to be present to provide a valid media_time.
     // Bogus edts are ignored.
@@ -853,123 +844,121 @@ fn skip_padding_in_boxes() {
         let mut stream = make_fullbox(BoxSize::Auto, name, 1, |s| {
             s.append_repeated(0, 100) // add padding data
         });
         let mut iter = super::BoxIter::new(&mut stream);
         let mut stream = iter.next_box().unwrap().unwrap();
         match name {
             b"stts" => {
                 super::read_stts(&mut stream).expect("fail to skip padding: stts");
-            },
+            }
             b"stsc" => {
                 super::read_stsc(&mut stream).expect("fail to skip padding: stsc");
-            },
+            }
             b"stsz" => {
                 super::read_stsz(&mut stream).expect("fail to skip padding: stsz");
-            },
+            }
             b"stco" => {
                 super::read_stco(&mut stream).expect("fail to skip padding: stco");
-            },
+            }
             b"co64" => {
                 super::read_co64(&mut stream).expect("fail to skip padding: co64");
-            },
+            }
             b"stss" => {
                 super::read_stss(&mut stream).expect("fail to skip padding: stss");
-            },
+            }
             _ => (),
         }
     }
 }
 
 #[test]
 fn skip_padding_in_stsd() {
     // Padding data could be added in the end of stsd boxes. Parser needs to skip
     // them instead of returning error.
     let avc = make_box(BoxSize::Auto, b"avc1", |s| {
         s.append_repeated(0, 6)
-         .B16(1)
-         .append_repeated(0, 16)
-         .B16(320)
-         .B16(240)
-         .append_repeated(0, 14)
-         .append_repeated(0, 32)
-         .append_repeated(0, 4)
-         .B32(0xffff_ffff)
-         .append_bytes(b"avcC")
-         .append_repeated(0, 100)
-    }).into_inner();
+            .B16(1)
+            .append_repeated(0, 16)
+            .B16(320)
+            .B16(240)
+            .append_repeated(0, 14)
+            .append_repeated(0, 32)
+            .append_repeated(0, 4)
+            .B32(0xffff_ffff)
+            .append_bytes(b"avcC")
+            .append_repeated(0, 100)
+    })
+    .into_inner();
     let mut stream = make_fullbox(BoxSize::Auto, b"stsd", 0, |s| {
         s.B32(1)
-         .append_bytes(avc.as_slice())
-         .append_repeated(0, 100) // add padding data
+            .append_bytes(avc.as_slice())
+            .append_repeated(0, 100) // add padding data
     });
 
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    super::read_stsd(&mut stream, &mut super::Track::new(0))
-          .expect("fail to skip padding: stsd");
+    super::read_stsd(&mut stream, &mut super::Track::new(0)).expect("fail to skip padding: stsd");
 }
 
 #[test]
 fn read_qt_wave_atom() {
     let esds = make_fullbox(BoxSize::Auto, b"esds", 0, |s| {
-        s.B8(0x03)  // elementary stream descriptor tag
-         .B8(0x12)  // esds length
-         .append_repeated(0, 2)
-         .B8(0x00)  // flags
-         .B8(0x04)  // decoder config descriptor tag
-         .B8(0x0d)  // dcds length
-         .B8(0x6b)  // mp3
-         .append_repeated(0, 12)
-    }).into_inner();
+        s.B8(0x03) // elementary stream descriptor tag
+            .B8(0x12) // esds length
+            .append_repeated(0, 2)
+            .B8(0x00) // flags
+            .B8(0x04) // decoder config descriptor tag
+            .B8(0x0d) // dcds length
+            .B8(0x6b) // mp3
+            .append_repeated(0, 12)
+    })
+    .into_inner();
     let chan = make_box(BoxSize::Auto, b"chan", |s| {
-        s.append_repeated(0, 10)    // we don't care its data.
-    }).into_inner();
-    let wave = make_box(BoxSize::Auto, b"wave", |s| {
-        s.append_bytes(esds.as_slice())
-    }).into_inner();
+        s.append_repeated(0, 10) // we don't care its data.
+    })
+    .into_inner();
+    let wave = make_box(BoxSize::Auto, b"wave", |s| s.append_bytes(esds.as_slice())).into_inner();
     let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
         s.append_repeated(0, 6)
-         .B16(1)    // data_reference_count
-         .B16(1)    // verion: qt -> 1
-         .append_repeated(0, 6)
-         .B16(2)
-         .B16(16)
-         .append_repeated(0, 4)
-         .B32(48000 << 16)
-         .append_repeated(0, 16)
-         .append_bytes(wave.as_slice())
-         .append_bytes(chan.as_slice())
+            .B16(1) // data_reference_count
+            .B16(1) // verion: qt -> 1
+            .append_repeated(0, 6)
+            .B16(2)
+            .B16(16)
+            .append_repeated(0, 4)
+            .B32(48000 << 16)
+            .append_repeated(0, 16)
+            .append_bytes(wave.as_slice())
+            .append_bytes(chan.as_slice())
     });
 
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let sample_entry = super::read_audio_sample_entry(&mut stream)
-          .expect("fail to read qt wave atom");
+    let sample_entry =
+        super::read_audio_sample_entry(&mut stream).expect("fail to read qt wave atom");
     match sample_entry {
-        super::SampleEntry::Audio(sample_entry) =>
-          assert_eq!(sample_entry.codec_type, super::CodecType::MP3),
+        super::SampleEntry::Audio(sample_entry) => {
+            assert_eq!(sample_entry.codec_type, super::CodecType::MP3)
+        }
         _ => panic!("fail to read audio sample enctry"),
     }
 }
 
 #[test]
 fn read_descriptor_80() {
-    let aac_esds =
-        vec![
-            0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x02, 0x00,
-            0x04, 0x80, 0x80, 0x80, 0x17, 0x40, 0x15, 0x00,
-            0x00, 0x00, 0x00, 0x03, 0x22, 0xBC, 0x00, 0x01,
-            0xF5, 0x83, 0x05, 0x80, 0x80, 0x80, 0x02, 0x11,
-            0x90, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02
-        ];
-    let aac_dc_descriptor = &aac_esds[31 .. 33];
+    let aac_esds = vec![
+        0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x02, 0x00, 0x04, 0x80, 0x80, 0x80, 0x17, 0x40, 0x15,
+        0x00, 0x00, 0x00, 0x00, 0x03, 0x22, 0xBC, 0x00, 0x01, 0xF5, 0x83, 0x05, 0x80, 0x80, 0x80,
+        0x02, 0x11, 0x90, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02,
+    ];
+    let aac_dc_descriptor = &aac_esds[31..33];
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
-         .append_bytes(aac_esds.as_slice())
+            .append_bytes(aac_esds.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     let es = super::read_esds(&mut stream).unwrap();
 
     assert_eq!(es.audio_codec, super::CodecType::AAC);
     assert_eq!(es.audio_object_type, Some(2));
@@ -977,29 +966,26 @@ fn read_descriptor_80() {
     assert_eq!(es.audio_sample_rate, Some(48000));
     assert_eq!(es.audio_channel_count, Some(2));
     assert_eq!(es.codec_esds, aac_esds);
     assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
 }
 
 #[test]
 fn read_esds() {
-    let aac_esds =
-        vec![
-            0x03, 0x24, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x40,
-            0x15, 0x00, 0x12, 0x00, 0x00, 0x01, 0xf4, 0x00,
-            0x00, 0x01, 0xf4, 0x00, 0x05, 0x0d, 0x13, 0x00,
-            0x05, 0x88, 0x05, 0x00, 0x48, 0x21, 0x10, 0x00,
-            0x56, 0xe5, 0x98, 0x06, 0x01, 0x02,
-        ];
-    let aac_dc_descriptor = &aac_esds[22 .. 35];
+    let aac_esds = vec![
+        0x03, 0x24, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x40, 0x15, 0x00, 0x12, 0x00, 0x00, 0x01, 0xf4,
+        0x00, 0x00, 0x01, 0xf4, 0x00, 0x05, 0x0d, 0x13, 0x00, 0x05, 0x88, 0x05, 0x00, 0x48, 0x21,
+        0x10, 0x00, 0x56, 0xe5, 0x98, 0x06, 0x01, 0x02,
+    ];
+    let aac_dc_descriptor = &aac_esds[22..35];
 
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
-         .append_bytes(aac_esds.as_slice())
+            .append_bytes(aac_esds.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     let es = super::read_esds(&mut stream).unwrap();
 
     assert_eq!(es.audio_codec, super::CodecType::AAC);
     assert_eq!(es.audio_object_type, Some(2));
@@ -1007,32 +993,28 @@ fn read_esds() {
     assert_eq!(es.audio_sample_rate, Some(24000));
     assert_eq!(es.audio_channel_count, Some(6));
     assert_eq!(es.codec_esds, aac_esds);
     assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
 }
 
 #[test]
 fn read_esds_aac_type5() {
-    let aac_esds =
-        vec![
-            0x03, 0x80, 0x80, 0x80,
-            0x2F, 0x00, 0x00, 0x00, 0x04, 0x80, 0x80, 0x80,
-            0x21, 0x40, 0x15, 0x00, 0x15, 0x00, 0x00, 0x03,
-            0xED, 0xAA, 0x00, 0x03, 0x6B, 0x00, 0x05, 0x80,
-            0x80, 0x80, 0x0F, 0x2B, 0x01, 0x88, 0x02, 0xC4,
-            0x04, 0x90, 0x2C, 0x10, 0x8C, 0x80, 0x00, 0x00,
-            0xED, 0x40, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02,
-        ];
+    let aac_esds = vec![
+        0x03, 0x80, 0x80, 0x80, 0x2F, 0x00, 0x00, 0x00, 0x04, 0x80, 0x80, 0x80, 0x21, 0x40, 0x15,
+        0x00, 0x15, 0x00, 0x00, 0x03, 0xED, 0xAA, 0x00, 0x03, 0x6B, 0x00, 0x05, 0x80, 0x80, 0x80,
+        0x0F, 0x2B, 0x01, 0x88, 0x02, 0xC4, 0x04, 0x90, 0x2C, 0x10, 0x8C, 0x80, 0x00, 0x00, 0xED,
+        0x40, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02,
+    ];
 
-    let aac_dc_descriptor = &aac_esds[31 .. 46];
+    let aac_dc_descriptor = &aac_esds[31..46];
 
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
-         .append_bytes(aac_esds.as_slice())
+            .append_bytes(aac_esds.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     let es = super::read_esds(&mut stream).unwrap();
 
     assert_eq!(es.audio_codec, super::CodecType::AAC);
     assert_eq!(es.audio_object_type, Some(2));
@@ -1040,75 +1022,66 @@ fn read_esds_aac_type5() {
     assert_eq!(es.audio_sample_rate, Some(24000));
     assert_eq!(es.audio_channel_count, Some(8));
     assert_eq!(es.codec_esds, aac_esds);
     assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
 }
 
 #[test]
 fn read_stsd_mp4v() {
-    let mp4v =
-        vec![
-                                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x01, 0xe0, 0x00, 0x48,
-            0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x18, 0xff, 0xff,
-            0x00, 0x00, 0x00, 0x4c, 0x65, 0x73, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00,
-            0x03, 0x3e, 0x00, 0x00, 0x1f, 0x04, 0x36, 0x20, 0x11, 0x01, 0x77, 0x00,
-            0x00, 0x03, 0xe8, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x05, 0x27, 0x00, 0x00,
-            0x01, 0xb0, 0x05, 0x00, 0x00, 0x01, 0xb5, 0x0e, 0xcf, 0x00, 0x00, 0x01,
-            0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x86, 0xe0, 0x00, 0x2e, 0xa6, 0x60,
-            0x16, 0xf4, 0x01, 0xf4, 0x24, 0xc8, 0x01, 0xe5, 0x16, 0x84, 0x3c, 0x14,
-            0x63, 0x06, 0x01, 0x02,
-        ];
+    let mp4v = vec![
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x01, 0xe0, 0x00, 0x48,
+        0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+        0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x73, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00,
+        0x03, 0x3e, 0x00, 0x00, 0x1f, 0x04, 0x36, 0x20, 0x11, 0x01, 0x77, 0x00, 0x00, 0x03, 0xe8,
+        0x00, 0x00, 0x03, 0xe8, 0x00, 0x05, 0x27, 0x00, 0x00, 0x01, 0xb0, 0x05, 0x00, 0x00, 0x01,
+        0xb5, 0x0e, 0xcf, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x86, 0xe0, 0x00,
+        0x2e, 0xa6, 0x60, 0x16, 0xf4, 0x01, 0xf4, 0x24, 0xc8, 0x01, 0xe5, 0x16, 0x84, 0x3c, 0x14,
+        0x63, 0x06, 0x01, 0x02,
+    ];
 
-    let esds_specific_data = &mp4v[90 ..];
+    let esds_specific_data = &mp4v[90..];
     println!("esds_specific_data {:?}", esds_specific_data);
 
-    let mut stream = make_box(BoxSize::Auto, b"mp4v", |s| {
-        s.append_bytes(mp4v.as_slice())
-    });
+    let mut stream = make_box(BoxSize::Auto, b"mp4v", |s| s.append_bytes(mp4v.as_slice()));
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     let sample_entry = super::read_video_sample_entry(&mut stream).unwrap();
 
     match sample_entry {
         super::SampleEntry::Video(v) => {
             assert_eq!(v.codec_type, super::CodecType::MP4V);
             assert_eq!(v.width, 720);
             assert_eq!(v.height, 480);
             match v.codec_specific {
                 super::VideoCodecSpecific::ESDSConfig(esds_data) => {
                     assert_eq!(esds_data, esds_specific_data.to_vec());
-                },
+                }
                 _ => panic!("it should be ESDSConfig!"),
             }
-        },
+        }
         _ => panic!("it should be a video sample entry!"),
     }
-
 }
 
 #[test]
 fn read_esds_one_byte_extension_descriptor() {
-    let esds =
-        vec![
-            0x00, 0x03, 0x80, 0x1b, 0x00, 0x00, 0x00, 0x04,
-            0x80, 0x12, 0x40, 0x15, 0x00, 0x06, 0x00, 0x00,
-            0x01, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x05,
-            0x80, 0x02, 0x11, 0x90, 0x06, 0x01, 0x02,
-        ];
+    let esds = vec![
+        0x00, 0x03, 0x80, 0x1b, 0x00, 0x00, 0x00, 0x04, 0x80, 0x12, 0x40, 0x15, 0x00, 0x06, 0x00,
+        0x00, 0x01, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x11, 0x90, 0x06, 0x01,
+        0x02,
+    ];
 
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
-         .append_bytes(esds.as_slice())
+            .append_bytes(esds.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     let es = super::read_esds(&mut stream).unwrap();
 
     assert_eq!(es.audio_codec, super::CodecType::AAC);
     assert_eq!(es.audio_object_type, Some(2));
@@ -1116,228 +1089,220 @@ fn read_esds_one_byte_extension_descript
     assert_eq!(es.audio_sample_rate, Some(48000));
     assert_eq!(es.audio_channel_count, Some(2));
 }
 
 #[test]
 fn read_esds_byte_extension_descriptor() {
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
-         .B16(0x0003)
-         .B16(0x8181)   // extension byte length 0x81
-         .append_repeated(0, 0x81)
+            .B16(0x0003)
+            .B16(0x8181) // extension byte length 0x81
+            .append_repeated(0, 0x81)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     match super::read_esds(&mut stream) {
         Ok(_) => (),
         _ => panic!("fail to parse descriptor extension byte length"),
     }
 }
 
 #[test]
 fn read_f4v_stsd() {
     let mut stream = make_box(BoxSize::Auto, b".mp3", |s| {
         s.append_repeated(0, 6)
-         .B16(1)
-         .B16(0)
-         .append_repeated(0, 6)
-         .B16(2)
-         .B16(16)
-         .append_repeated(0, 4)
-         .B32(48000 << 16)
+            .B16(1)
+            .B16(0)
+            .append_repeated(0, 6)
+            .B16(2)
+            .B16(16)
+            .append_repeated(0, 4)
+            .B32(48000 << 16)
     });
 
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let sample_entry = super::read_audio_sample_entry(&mut stream)
-          .expect("failed to read f4v stsd atom");
+    let sample_entry =
+        super::read_audio_sample_entry(&mut stream).expect("failed to read f4v stsd atom");
     match sample_entry {
-        super::SampleEntry::Audio(sample_entry) =>
-          assert_eq!(sample_entry.codec_type, super::CodecType::MP3),
+        super::SampleEntry::Audio(sample_entry) => {
+            assert_eq!(sample_entry.codec_type, super::CodecType::MP3)
+        }
         _ => panic!("fail to read audio sample enctry"),
     }
 }
 
 #[test]
 fn max_table_limit() {
     let elst = make_fullbox(BoxSize::Auto, b"elst", 1, |s| {
         s.B32(super::TABLE_SIZE_LIMIT + 1)
-    }).into_inner();
-    let mut stream = make_box(BoxSize::Auto, b"edts", |s| {
-        s.append_bytes(elst.as_slice())
-    });
+    })
+    .into_inner();
+    let mut stream = make_box(BoxSize::Auto, b"edts", |s| s.append_bytes(elst.as_slice()));
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     let mut track = super::Track::new(0);
     match super::read_edts(&mut stream, &mut track) {
         Err(Error::OutOfMemory) => (),
         Ok(_) => panic!("expected an error result"),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn unknown_video_sample_entry() {
-    let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| {
-        s.append_repeated(0, 16)
-    }).into_inner();
+    let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| s.append_repeated(0, 16)).into_inner();
     let mut stream = make_box(BoxSize::Auto, b"xxxx", |s| {
         s.append_repeated(0, 6)
-         .B16(1)
-         .append_repeated(0, 16)
-         .B16(0)
-         .B16(0)
-         .append_repeated(0, 14)
-         .append_repeated(0, 32)
-         .append_repeated(0, 4)
-         .append_bytes(unknown_codec.as_slice())
+            .B16(1)
+            .append_repeated(0, 16)
+            .B16(0)
+            .B16(0)
+            .append_repeated(0, 14)
+            .append_repeated(0, 32)
+            .append_repeated(0, 4)
+            .append_bytes(unknown_codec.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     match super::read_video_sample_entry(&mut stream) {
         Ok(super::SampleEntry::Unknown) => (),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn unknown_audio_sample_entry() {
-    let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| {
-        s.append_repeated(0, 16)
-    }).into_inner();
+    let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| s.append_repeated(0, 16)).into_inner();
     let mut stream = make_box(BoxSize::Auto, b"xxxx", |s| {
         s.append_repeated(0, 6)
-         .B16(1)
-         .B32(0)
-         .B32(0)
-         .B16(2)
-         .B16(16)
-         .B16(0)
-         .B16(0)
-         .B32(48000 << 16)
-         .append_bytes(unknown_codec.as_slice())
+            .B16(1)
+            .B32(0)
+            .B32(0)
+            .B16(2)
+            .B16(16)
+            .B16(0)
+            .B16(0)
+            .B32(48000 << 16)
+            .append_bytes(unknown_codec.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     match super::read_audio_sample_entry(&mut stream) {
         Ok(super::SampleEntry::Unknown) => (),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn read_esds_invalid_descriptor() {
     // tag 0x06, 0xff, 0x7f is incorrect.
-    let esds =
-        vec![
-                  0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x00,
-            0x00, 0x04, 0x80, 0x80, 0x80, 0x14, 0x40, 0x01,
-            0x00, 0x04, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00,
-            0x00, 0xfa, 0x00, 0x05, 0x80, 0x80, 0x80, 0x02,
-            0xe8, 0x35, 0x06, 0xff, 0x7f, 0x00, 0x00,
-        ];
+    let esds = vec![
+        0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x00, 0x00, 0x04, 0x80, 0x80, 0x80, 0x14, 0x40, 0x01,
+        0x00, 0x04, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x05, 0x80, 0x80, 0x80,
+        0x02, 0xe8, 0x35, 0x06, 0xff, 0x7f, 0x00, 0x00,
+    ];
 
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
-         .append_bytes(esds.as_slice())
+            .append_bytes(esds.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     match super::read_esds(&mut stream) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "Invalid descriptor."),
         _ => panic!("unexpected result with invalid descriptor"),
     }
 }
 
 #[test]
 fn read_esds_redundant_descriptor() {
     // the '2' at the end is redundant data.
-    let esds =
-        vec![  3, 25,   0, 1, 0, 4, 19, 64,
-              21,  0,   0, 0, 0, 0,  0,  0,
-               0,  1, 119, 0, 5, 2, 18, 16,
-               6,  1,   2,
-            ];
+    let esds = vec![
+        3, 25, 0, 1, 0, 4, 19, 64, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 119, 0, 5, 2, 18, 16, 6, 1, 2,
+    ];
 
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
-         .append_bytes(esds.as_slice())
+            .append_bytes(esds.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     match super::read_esds(&mut stream) {
         Ok(esds) => assert_eq!(esds.audio_codec, super::CodecType::AAC),
         _ => panic!("unexpected result with invalid descriptor"),
     }
 }
 
 #[test]
 fn read_invalid_pssh() {
     // invalid pssh header length
-    let pssh =
-        vec![
-                              0x00, 0x00, 0x00, 0x01, 0x70,
-            0x73, 0x73, 0x68, 0x01, 0x00, 0x00, 0x00, 0x10,
-            0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac,
-            0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b, 0x00,
-            0x00, 0x00, 0x02, 0x7e, 0x57, 0x1d, 0x01, 0x7e,
-        ];
+    let pssh = vec![
+        0x00, 0x00, 0x00, 0x01, 0x70, 0x73, 0x73, 0x68, 0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef,
+        0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00,
+        0x00, 0x02, 0x7e, 0x57, 0x1d, 0x01, 0x7e,
+    ];
 
-    let mut stream = make_box(BoxSize::Auto, b"moov", |s| {
-        s.append_bytes(pssh.as_slice())
-    });
+    let mut stream = make_box(BoxSize::Auto, b"moov", |s| s.append_bytes(pssh.as_slice()));
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     let mut context = super::MediaContext::new();
 
     match super::read_moov(&mut stream, &mut context) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "read_buf size exceeds BUF_SIZE_LIMIT"),
         _ => panic!("unexpected result with invalid descriptor"),
     }
 }
 
 #[test]
 fn read_stsd_lpcm() {
     // Extract from sample converted by ffmpeg.
     // "ffmpeg -i ./gizmo-short.mp4 -acodec pcm_s16le -ar 96000 -vcodec copy -f mov gizmo-short.mov"
-    let lpcm =
-        vec![
-                              0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0xff,
-            0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x48, 0x40, 0xf7, 0x70, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
-            0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00,
-            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x63,
-            0x68, 0x61, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00,
-        ];
+    let lpcm = vec![
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x03, 0x00, 0x10, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x48, 0x40, 0xf7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02,
+        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x63, 0x68, 0x61, 0x6e, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    ];
 
-    let mut stream = make_box(BoxSize::Auto, b"lpcm", |s| {
-        s.append_bytes(lpcm.as_slice())
-    });
+    let mut stream = make_box(BoxSize::Auto, b"lpcm", |s| s.append_bytes(lpcm.as_slice()));
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     let sample_entry = super::read_audio_sample_entry(&mut stream).unwrap();
 
     match sample_entry {
         #[allow(clippy::float_cmp)] // The float comparison below is valid and intended.
         super::SampleEntry::Audio(a) => {
             assert_eq!(a.codec_type, super::CodecType::LPCM);
             assert_eq!(a.samplerate, 96000.0);
             assert_eq!(a.channelcount, 1);
             match a.codec_specific {
                 super::AudioCodecSpecific::LPCM => (),
                 _ => panic!("it should be LPCM!"),
             }
-        },
+        }
         _ => panic!("it should be a audio sample entry!"),
     }
+}
 
+#[test]
+fn read_to_end_() {
+    let mut src = b"1234567890".take(5);
+    let mut buf = vec![];
+    let bytes_read = super::read_to_end(&mut src, &mut buf).unwrap();
+    assert_eq!(bytes_read, 5);
+    assert_eq!(buf, b"12345");
 }
+
+#[test]
+#[cfg(feature = "mp4parse_fallible")]
+fn read_to_end_oom() {
+    let mut src = b"1234567890".take(std::usize::MAX.try_into().expect("usize < u64"));
+    let mut buf = vec![];
+    assert!(super::read_to_end(&mut src, &mut buf).is_err());
+}
deleted file mode 100644
--- a/media/mp4parse-rust/mp4parse/tests/afl.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-/// Regression tests from American Fuzzy Lop test cases.
-
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-/// These all caused panics at some point during development.
-
-extern crate mp4parse;
-
-use std::io::Cursor;
-
-/// https://github.com/mozilla/mp4parse-rust/issues/2
-///
-/// Test a box with 4-byte size, smaller than the smallest header.
-#[test]
-fn fuzz_2() {
-    let mut c = Cursor::new(b"\x00\x00\x00\x04\xa6\x00\x04\xa6".to_vec());
-    let mut context = mp4parse::MediaContext::new();
-    let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
-
-/// https://github.com/mozilla/mp4parse-rust/issues/4
-///
-/// Test a large (64 bit) box header with zero declared size.
-#[test]
-fn fuzz_4() {
-    let mut c = Cursor::new(b"\x00\x00\x00\x01\x30\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00".to_vec());
-    let mut context = mp4parse::MediaContext::new();
-    let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
-
-/// https://github.com/mozilla/mp4parse-rust/issues/5
-///
-/// Declares 202116104 compatible brands but does not supply them,
-/// verifying read is properly bounded at the end of the stream.
-#[test]
-fn fuzz_5() {
-    let mut c = Cursor::new(b"\x30\x30\x30\x30\x66\x74\x79\x70\x30\x30\x30\x30\x30\x30\x30\x30".to_vec());
-    let mut context = mp4parse::MediaContext::new();
-    let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
-
-/// https://github.com/mozilla/mp4parse-rust/issues/6
-///
-/// Declares an ftyp box with a single invalid (short - 3 byte) compatible
-/// brand and excludes the extra 3 bytes from the stream.
-#[test]
-fn fuzz_6() {
-    let mut c = Cursor::new(b"\x00\x00\x00\x13\x66\x74\x79\x70\x30\x30\x30\x30\x30\x30\x30\x30".to_vec());
-    let mut context = mp4parse::MediaContext::new();
-    let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
--- a/media/mp4parse-rust/mp4parse/tests/public.rs
+++ b/media/mp4parse-rust/mp4parse/tests/public.rs
@@ -1,18 +1,17 @@
 /// Check if needed fields are still public.
-
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
 extern crate mp4parse as mp4;
 
+use std::fs::File;
 use std::io::{Cursor, Read};
-use std::fs::File;
+use std::path::Path;
 
 static MINI_MP4: &str = "tests/minimal.mp4";
 static MINI_MP4_WITH_METADATA: &str = "tests/metadata.mp4";
 static MINI_MP4_WITH_METADATA_STD_GENRE: &str = "tests/metadata_gnre.mp4";
 
 static AUDIO_EME_CENC_MP4: &str = "tests/bipbop-cenc-audioinit.mp4";
 static VIDEO_EME_CENC_MP4: &str = "tests/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4";
 // The cbcs files were created via shaka-packager from Firefox's test suite's bipbop.mp4 using:
@@ -22,16 +21,20 @@ static VIDEO_EME_CENC_MP4: &str = "tests
 // --protection_scheme cbcs --enable_raw_key_encryption
 // --keys label=:key_id=7e571d047e571d047e571d047e571d21:key=7e5744447e5744447e5744447e574421
 // --iv 11223344556677889900112233445566
 // --generate_static_mpd --mpd_output bipbop_cbcs.mpd
 // note: only the init files are needed for these tests
 static AUDIO_EME_CBCS_MP4: &str = "tests/bipbop_cbcs_audio_init.mp4";
 static VIDEO_EME_CBCS_MP4: &str = "tests/bipbop_cbcs_video_init.mp4";
 static VIDEO_AV1_MP4: &str = "tests/tiny_av1.mp4";
+static IMAGE_AVIF: &str = "av1-avif/testFiles/Microsoft/Monochrome.avif";
+static IMAGE_AVIF_GRID: &str = "av1-avif/testFiles/Microsoft/Summer_in_Tomsk_720p_5x4_grid.avif";
+static MICROSOFT_AVIF_TEST_DIR: &str = "av1-avif/testFiles/Microsoft";
+static NETFLIX_AVIF_TEST_DIR: &str = "av1-avif/testFiles/Netflix/avif";
 
 // Adapted from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
 #[test]
 #[allow(clippy::cognitive_complexity)] // TODO: Consider simplifying this
 fn public_api() {
     let mut fd = File::open(MINI_MP4).expect("Unknown file");
     let mut buf = Vec::new();
     fd.read_to_end(&mut buf).expect("File error");
@@ -59,37 +62,40 @@ fn public_api() {
                 // track.stsd part
                 let stsd = track.stsd.expect("expected an stsd");
                 let v = match stsd.descriptions.first().expect("expected a SampleEntry") {
                     mp4::SampleEntry::Video(v) => v,
                     _ => panic!("expected a VideoSampleEntry"),
                 };
                 assert_eq!(v.width, 320);
                 assert_eq!(v.height, 240);
-                assert_eq!(match v.codec_specific {
-                    mp4::VideoCodecSpecific::AVCConfig(ref avc) => {
-                        assert!(!avc.is_empty());
-                        "AVC"
-                    }
-                    mp4::VideoCodecSpecific::VPxConfig(ref vpx) => {
-                        // We don't enter in here, we just check if fields are public.
-                        assert!(vpx.bit_depth > 0);
-                        assert!(vpx.colour_primaries > 0);
-                        assert!(vpx.chroma_subsampling > 0);
-                        assert!(!vpx.codec_init.is_empty());
-                        "VPx"
-                    }
-                    mp4::VideoCodecSpecific::ESDSConfig(ref mp4v) => {
-                        assert!(!mp4v.is_empty());
-                        "MP4V"
-                    }
-                    mp4::VideoCodecSpecific::AV1Config(ref _av1c) => {
-                        "AV1"
-                    }
-                }, "AVC");
+                assert_eq!(
+                    match v.codec_specific {
+                        mp4::VideoCodecSpecific::AVCConfig(ref avc) => {
+                            assert!(!avc.is_empty());
+                            "AVC"
+                        }
+                        mp4::VideoCodecSpecific::VPxConfig(ref vpx) => {
+                            // We don't enter in here, we just check if fields are public.
+                            assert!(vpx.bit_depth > 0);
+                            assert!(vpx.colour_primaries > 0);
+                            assert!(vpx.chroma_subsampling > 0);
+                            assert!(!vpx.codec_init.is_empty());
+                            "VPx"
+                        }
+                        mp4::VideoCodecSpecific::ESDSConfig(ref mp4v) => {
+                            assert!(!mp4v.is_empty());
+                            "MP4V"
+                        }
+                        mp4::VideoCodecSpecific::AV1Config(ref _av1c) => {
+                            "AV1"
+                        }
+                    },
+                    "AVC"
+                );
             }
             mp4::TrackType::Audio => {
                 // track part
                 assert_eq!(track.duration, Some(mp4::TrackScaledTime(2944, 1)));
                 assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                 assert_eq!(track.media_time, Some(mp4::TrackScaledTime(1024, 1)));
                 assert_eq!(track.timescale, Some(mp4::TrackTimeScale(48000, 1)));
 
@@ -101,46 +107,49 @@ fn public_api() {
                 assert_eq!(tkhd.height, 0);
 
                 // track.stsd part
                 let stsd = track.stsd.expect("expected an stsd");
                 let a = match stsd.descriptions.first().expect("expected a SampleEntry") {
                     mp4::SampleEntry::Audio(a) => a,
                     _ => panic!("expected a AudioSampleEntry"),
                 };
-                assert_eq!(match a.codec_specific {
-                    mp4::AudioCodecSpecific::ES_Descriptor(ref esds) => {
-                        assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
-                        assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
-                        assert_eq!(esds.audio_object_type.unwrap(), 2);
-                        "ES"
-                    }
-                    mp4::AudioCodecSpecific::FLACSpecificBox(ref flac) => {
-                        // STREAMINFO block must be present and first.
-                        assert!(!flac.blocks.is_empty());
-                        assert_eq!(flac.blocks[0].block_type, 0);
-                        assert_eq!(flac.blocks[0].data.len(), 34);
-                        "FLAC"
-                    }
-                    mp4::AudioCodecSpecific::OpusSpecificBox(ref opus) => {
-                        // We don't enter in here, we just check if fields are public.
-                        assert!(opus.version > 0);
-                        "Opus"
-                    }
-                    mp4::AudioCodecSpecific::ALACSpecificBox(ref alac) => {
-                        assert!(alac.data.len() == 24 || alac.data.len() == 48);
-                        "ALAC"
-                    }
-                    mp4::AudioCodecSpecific::MP3 => {
-                        "MP3"
-                    }
-                    mp4::AudioCodecSpecific::LPCM => {
-                        "LPCM"
-                    }
-                }, "ES");
+                assert_eq!(
+                    match a.codec_specific {
+                        mp4::AudioCodecSpecific::ES_Descriptor(ref esds) => {
+                            assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
+                            assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
+                            assert_eq!(esds.audio_object_type.unwrap(), 2);
+                            "ES"
+                        }
+                        mp4::AudioCodecSpecific::FLACSpecificBox(ref flac) => {
+                            // STREAMINFO block must be present and first.
+                            assert!(!flac.blocks.is_empty());
+                            assert_eq!(flac.blocks[0].block_type, 0);
+                            assert_eq!(flac.blocks[0].data.len(), 34);
+                            "FLAC"
+                        }
+                        mp4::AudioCodecSpecific::OpusSpecificBox(ref opus) => {
+                            // We don't enter in here, we just check if fields are public.
+                            assert!(opus.version > 0);
+                            "Opus"
+                        }
+                        mp4::AudioCodecSpecific::ALACSpecificBox(ref alac) => {
+                            assert!(alac.data.len() == 24 || alac.data.len() == 48);
+                            "ALAC"
+                        }
+                        mp4::AudioCodecSpecific::MP3 => {
+                            "MP3"
+                        }
+                        mp4::AudioCodecSpecific::LPCM => {
+                            "LPCM"
+                        }
+                    },
+                    "ES"
+                );
                 assert!(a.samplesize > 0);
                 assert!(a.samplerate > 0.0);
             }
             mp4::TrackType::Metadata | mp4::TrackType::Unknown => {}
         }
     }
 }
 
@@ -149,25 +158,30 @@ fn public_api() {
 fn public_metadata() {
     let mut fd = File::open(MINI_MP4_WITH_METADATA).expect("Unknown file");
     let mut buf = Vec::new();
     fd.read_to_end(&mut buf).expect("File error");
 
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
-    let udta = context.userdata.expect("didn't find udta")
+    let udta = context
+        .userdata
+        .expect("didn't find udta")
         .expect("failed to parse udta");
     let meta = udta.meta.expect("didn't find meta");
     assert_eq!(meta.title.unwrap(), "Title");
     assert_eq!(meta.artist.unwrap(), "Artist");
     assert_eq!(meta.album_artist.unwrap(), "Album Artist");
     assert_eq!(meta.comment.unwrap(), "Comments");
     assert_eq!(meta.year.unwrap(), "2019");
-    assert_eq!(meta.genre.unwrap(), mp4::Genre::CustomGenre("Custom Genre".to_string()));
+    assert_eq!(
+        meta.genre.unwrap(),
+        mp4::Genre::CustomGenre("Custom Genre".to_string())
+    );
     assert_eq!(meta.encoder.unwrap(), "Lavf56.40.101");
     assert_eq!(meta.encoded_by.unwrap(), "Encoded-by");
     assert_eq!(meta.copyright.unwrap(), "Copyright");
     assert_eq!(meta.track_number.unwrap(), 3);
     assert_eq!(meta.total_tracks.unwrap(), 6);
     assert_eq!(meta.disc_number.unwrap(), 5);
     assert_eq!(meta.total_discs.unwrap(), 10);
     assert_eq!(meta.beats_per_minute.unwrap(), 128);
@@ -212,17 +226,19 @@ fn public_metadata() {
 fn public_metadata_gnre() {
     let mut fd = File::open(MINI_MP4_WITH_METADATA_STD_GENRE).expect("Unknown file");
     let mut buf = Vec::new();
     fd.read_to_end(&mut buf).expect("File error");
 
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
-    let udta = context.userdata.expect("didn't find udta")
+    let udta = context
+        .userdata
+        .expect("didn't find udta")
         .expect("failed to parse udta");
     let meta = udta.meta.expect("didn't find meta");
     assert_eq!(meta.title.unwrap(), "Title");
     assert_eq!(meta.artist.unwrap(), "Artist");
     assert_eq!(meta.album_artist.unwrap(), "Album Artist");
     assert_eq!(meta.comment.unwrap(), "Comments");
     assert_eq!(meta.year.unwrap(), "2019");
     assert_eq!(meta.genre.unwrap(), mp4::Genre::StandardGenre(3));
@@ -267,19 +283,20 @@ fn public_metadata_gnre() {
     bytes[0] = cover[0];
     bytes[1] = cover[1];
     bytes[2] = cover[2];
     assert_eq!(u32::from_le_bytes(bytes), 0x00ff_d8ff);
 }
 
 #[test]
 fn public_audio_tenc() {
-    let kid =
-        vec![0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
-             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04];
+    let kid = vec![
+        0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d,
+        0x04,
+    ];
 
     let mut fd = File::open(AUDIO_EME_CENC_MP4).expect("Unknown file");
     let mut buf = Vec::new();
     fd.read_to_end(&mut buf).expect("File error");
 
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
@@ -303,42 +320,42 @@ fn public_audio_tenc() {
                     assert_eq!(tenc.iv_size, 16);
                     assert_eq!(tenc.kid, kid);
                     assert_eq!(tenc.crypt_byte_block_count, None);
                     assert_eq!(tenc.skip_byte_block_count, None);
                     assert_eq!(tenc.constant_iv, None);
                 } else {
                     panic!("Invalid test condition");
                 }
-            },
-            _=> {
+            }
+            _ => {
                 panic!("Invalid test condition");
-            },
+            }
         }
     }
 }
 
 #[test]
 fn public_video_cenc() {
-    let system_id =
-        vec![0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
-             0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b];
-
-    let kid =
-        vec![0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
-             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11];
+    let system_id = vec![
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb,
+        0x4b,
+    ];
 
-    let pssh_box =
-        vec![0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
-             0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef, 0xec,
-             0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
-             0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01,
-             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
-             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11,
-             0x00, 0x00, 0x00, 0x00];
+    let kid = vec![
+        0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d,
+        0x11,
+    ];
+
+    let pssh_box = vec![
+        0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68, 0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef,
+        0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00,
+        0x00, 0x01, 0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03, 0x7e,
+        0x57, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+    ];
 
     let mut fd = File::open(VIDEO_EME_CENC_MP4).expect("Unknown file");
     let mut buf = Vec::new();
     fd.read_to_end(&mut buf).expect("File error");
 
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
@@ -362,55 +379,56 @@ fn public_video_cenc() {
                     assert_eq!(tenc.iv_size, 16);
                     assert_eq!(tenc.kid, kid);
                     assert_eq!(tenc.crypt_byte_block_count, None);
                     assert_eq!(tenc.skip_byte_block_count, None);
                     assert_eq!(tenc.constant_iv, None);
                 } else {
                     panic!("Invalid test condition");
                 }
-            },
-            _=> {
+            }
+            _ => {
                 panic!("Invalid test condition");
             }
         }
     }
 
     for pssh in context.psshs {
         assert_eq!(pssh.system_id, system_id);
         for kid_id in pssh.kid {
             assert_eq!(kid_id, kid);
         }
         assert!(pssh.data.is_empty());
         assert_eq!(pssh.box_content, pssh_box);
     }
 }
 
 #[test]
-fn publicaudio_cbcs() {
-    let system_id =
-        vec![0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
-             0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b];
+fn public_audio_cbcs() {
+    let system_id = vec![
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb,
+        0x4b,
+    ];
 
-    let kid =
-        vec![0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
-             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x21];
+    let kid = vec![
+        0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d,
+        0x21,
+    ];
 
-    let default_iv =
-        vec![0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
-             0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
+    let default_iv = vec![
+        0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+        0x66,
+    ];
 
-    let pssh_box =
-        vec![0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
-             0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef, 0xec,
-             0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
-             0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01,
-             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
-             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x21,
-             0x00, 0x00, 0x00, 0x00];
+    let pssh_box = vec![
+        0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68, 0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef,
+        0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00,
+        0x00, 0x01, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e,
+        0x57, 0x1d, 0x21, 0x00, 0x00, 0x00, 0x00,
+    ];
 
     let mut fd = File::open(AUDIO_EME_CBCS_MP4).expect("Unknown file");
     let mut buf = Vec::new();
     fd.read_to_end(&mut buf).expect("File error");
 
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
@@ -438,59 +456,62 @@ fn publicaudio_cbcs() {
                             // to indicate full encryption.
                             assert_eq!(tenc.crypt_byte_block_count, Some(0));
                             assert_eq!(tenc.skip_byte_block_count, Some(0));
                             assert_eq!(tenc.constant_iv, Some(default_iv.clone()));
                         } else {
                             panic!("Invalid test condition");
                         }
                     }
-                },
+                }
                 _ => {
                     panic!("expected a VideoSampleEntry");
-                },
+                }
             }
         }
-        assert!(found_encrypted_sample_description,
-                "Should have found an encrypted sample description");
+        assert!(
+            found_encrypted_sample_description,
+            "Should have found an encrypted sample description"
+        );
     }
 
     for pssh in context.psshs {
         assert_eq!(pssh.system_id, system_id);
         for kid_id in pssh.kid {
             assert_eq!(kid_id, kid);
         }
         assert!(pssh.data.is_empty());
         assert_eq!(pssh.box_content, pssh_box);
     }
 }
 
 #[test]
 #[allow(clippy::cognitive_complexity)] // TODO: Consider simplifying this
 fn public_video_cbcs() {
-    let system_id =
-        vec![0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
-             0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b];
+    let system_id = vec![
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb,
+        0x4b,
+    ];
 
-    let kid =
-        vec![0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
-             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x21];
+    let kid = vec![
+        0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d,
+        0x21,
+    ];
 
-    let default_iv =
-        vec![0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
-             0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
+    let default_iv = vec![
+        0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+        0x66,
+    ];
 
-    let pssh_box =
-        vec![0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
-             0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef, 0xec,
-             0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
-             0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01,
-             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
-             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x21,
-             0x00, 0x00, 0x00, 0x00];
+    let pssh_box = vec![
+        0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68, 0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef,
+        0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00,
+        0x00, 0x01, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e,
+        0x57, 0x1d, 0x21, 0x00, 0x00, 0x00, 0x00,
+    ];
 
     let mut fd = File::open(VIDEO_EME_CBCS_MP4).expect("Unknown file");
     let mut buf = Vec::new();
     fd.read_to_end(&mut buf).expect("File error");
 
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
@@ -517,24 +538,26 @@ fn public_video_cbcs() {
                             assert_eq!(tenc.kid, kid);
                             assert_eq!(tenc.crypt_byte_block_count, Some(1));
                             assert_eq!(tenc.skip_byte_block_count, Some(9));
                             assert_eq!(tenc.constant_iv, Some(default_iv.clone()));
                         } else {
                             panic!("Invalid test condition");
                         }
                     }
-                },
+                }
                 _ => {
                     panic!("expected a VideoSampleEntry");
-                },
+                }
             }
         }
-        assert!(found_encrypted_sample_description,
-                "Should have found an encrypted sample description");
+        assert!(
+            found_encrypted_sample_description,
+            "Should have found an encrypted sample description"
+        );
     }
 
     for pssh in context.psshs {
         assert_eq!(pssh.system_id, system_id);
         for kid_id in pssh.kid {
             assert_eq!(kid_id, kid);
         }
         assert!(pssh.data.is_empty());
@@ -551,17 +574,17 @@ fn public_video_av1() {
 
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
     for track in context.tracks {
         // track part
         assert_eq!(track.duration, Some(mp4::TrackScaledTime(512, 0)));
         assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
-        assert_eq!(track.media_time, Some(mp4::TrackScaledTime(0,0)));
+        assert_eq!(track.media_time, Some(mp4::TrackScaledTime(0, 0)));
         assert_eq!(track.timescale, Some(mp4::TrackTimeScale(12288, 0)));
 
         // track.tkhd part
         let tkhd = track.tkhd.unwrap();
         assert_eq!(tkhd.disabled, false);
         assert_eq!(tkhd.duration, 42);
         assert_eq!(tkhd.width, 4_194_304);
         assert_eq!(tkhd.height, 4_194_304);
@@ -584,13 +607,56 @@ fn public_video_av1() {
                 assert_eq!(av1c.tier, 0);
                 assert_eq!(av1c.bit_depth, 8);
                 assert_eq!(av1c.monochrome, false);
                 assert_eq!(av1c.chroma_subsampling_x, 1);
                 assert_eq!(av1c.chroma_subsampling_y, 1);
                 assert_eq!(av1c.chroma_sample_position, 0);
                 assert_eq!(av1c.initial_presentation_delay_present, false);
                 assert_eq!(av1c.initial_presentation_delay_minus_one, 0);
-            },
+            }
             _ => panic!("Invalid test condition"),
         }
     }
 }
+
+#[test]
+fn public_avif_primary_item() {
+    let context = &mut mp4::AvifContext::new();
+    let input = &mut File::open(IMAGE_AVIF).expect("Unknown file");
+    mp4::read_avif(input, context).expect("read_avif failed");
+    assert_eq!(context.primary_item.len(), 6979);
+    assert_eq!(context.primary_item[0..4], [0x12, 0x00, 0x0a, 0x0a]);
+}
+
+#[test]
+#[ignore] // Remove when we add support; see https://github.com/mozilla/mp4parse-rust/issues/198
+fn public_avif_primary_item_is_grid() {
+    let context = &mut mp4::AvifContext::new();
+    let input = &mut File::open(IMAGE_AVIF_GRID).expect("Unknown file");
+    mp4::read_avif(input, context).expect("read_avif failed");
+    // Add some additional checks
+}
+
+#[test]
+fn public_avif_read_samples() {
+    env_logger::init();
+    let microsoft = Path::new(MICROSOFT_AVIF_TEST_DIR)
+        .read_dir()
+        .expect("Cannot read AVIF test dir");
+    let netflix = Path::new(NETFLIX_AVIF_TEST_DIR)
+        .read_dir()
+        .expect("Cannot read AVIF test dir");
+    for entry in microsoft.chain(netflix) {
+        let path = entry.expect("AVIF entry").path();
+        if path.extension().expect("no extension") != "avif" {
+            eprintln!("Skipping {:?}", path);
+            continue; // Skip ReadMe.txt, etc.
+        }
+        if path == Path::new(IMAGE_AVIF_GRID) {
+            eprintln!("Skipping {:?}", path);
+            continue; // Remove when public_avif_primary_item_is_grid passes
+        }
+        let context = &mut mp4::AvifContext::new();
+        let input = &mut File::open(path).expect("Unknow file");
+        mp4::read_avif(input, context).expect("read_avif failed");
+    }
+}
--- a/media/mp4parse-rust/mp4parse_capi/Cargo.toml
+++ b/media/mp4parse-rust/mp4parse_capi/Cargo.toml
@@ -13,29 +13,28 @@ license = "MPL-2.0"
 
 repository = "https://github.com/mozilla/mp4parse-rust"
 
 # Avoid complaints about trying to package test files.
 exclude = [
   "*.mp4",
 ]
 
-build = false
+build = false # See bug 1611431 - Generate mp4parse-rust bindings as part of mach build
 
 [badges]
 travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
 
 [dependencies]
 byteorder = "1.2.1"
 log = "0.4"
 mp4parse = {version = "0.11.2", path = "../mp4parse"}
 num-traits = "0.2.0"
 
 [dev-dependencies]
-env_logger = "0.5.3"
+env_logger = "0.7.1"
 
 [features]
-fuzz = ["mp4parse/fuzz"]
 # Enable mp4parse_fallible to use fallible memory allocation rather than
 # panicking on OOM.  Note that this is only safe within Gecko where the system
 # allocator has been globally overridden (see BMO 1457359).
 mp4parse_fallible = ["mp4parse/mp4parse_fallible"]
 
deleted file mode 100644
--- a/media/mp4parse-rust/mp4parse_capi/build.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-extern crate cbindgen;
-
-use cbindgen::{Config, RenameRule};
-
-fn main() {
-    let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
-
-    println!("cargo:rerun-if-changed=src/lib.rs");
-
-    let config = {
-        let mut c: Config = Default::default();
-        c.header = Some(r##"
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-"##.trim().into());
-        c.trailer = Some(r##"
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-"##.trim().into());
-        c.include_guard = Some("MP4PARSE_CAPI_H".to_owned());
-        c.autogen_warning = Some(
-            "// THIS FILE IS AUTOGENERATED BY mp4parse_capi/build.rs - DO NOT EDIT".to_owned(),
-        );
-        c.language = cbindgen::Language::C;
-        c.enumeration.rename_variants = Some(RenameRule::QualifiedScreamingSnakeCase);
-        c
-    };
-
-    // Generate mp4parse.h.
-    cbindgen::generate_with_config(&crate_dir, config)
-        .expect("Could not generate header")
-        .write_to_file("include/mp4parse.h");
-}
--- a/media/mp4parse-rust/mp4parse_capi/src/lib.rs
+++ b/media/mp4parse-rust/mp4parse_capi/src/lib.rs
@@ -17,53 +17,57 @@
 //!    }
 //! }
 //!
 //! let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
 //! let io = mp4parse_capi::Mp4parseIo {
 //!     read: Some(buf_read),
 //!     userdata: &mut file as *mut _ as *mut std::os::raw::c_void
 //! };
+//! let mut parser = std::ptr::null_mut();
 //! unsafe {
-//!     let parser = mp4parse_capi::mp4parse_new(&io);
-//!     let rv = mp4parse_capi::mp4parse_read(parser);
+//!     let rv = mp4parse_capi::mp4parse_new(&io, &mut parser);
 //!     assert_eq!(rv, mp4parse_capi::Mp4parseStatus::Ok);
+//!     assert!(!parser.is_null());
 //!     mp4parse_capi::mp4parse_free(parser);
 //! }
 //! ```
 
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
 
+extern crate byteorder;
 extern crate mp4parse;
-extern crate byteorder;
 extern crate num_traits;
 
-use std::io::Read;
-use std::collections::HashMap;
 use byteorder::WriteBytesExt;
 use num_traits::{PrimInt, Zero};
+use std::collections::HashMap;
+use std::io::Read;
 
 // Symbols we need from our rust api.
-use mp4parse::MediaContext;
-use mp4parse::TrackType;
+use mp4parse::extend_from_slice;
+use mp4parse::read_avif;
 use mp4parse::read_mp4;
+use mp4parse::serialize_opus_header;
+use mp4parse::vec_push;
+use mp4parse::AudioCodecSpecific;
+use mp4parse::AvifContext;
+use mp4parse::CodecType;
 use mp4parse::Error;
-use mp4parse::SampleEntry;
-use mp4parse::AudioCodecSpecific;
-use mp4parse::VideoCodecSpecific;
+use mp4parse::MediaContext;
+use mp4parse::MediaScaledTime;
 use mp4parse::MediaTimeScale;
-use mp4parse::MediaScaledTime;
-use mp4parse::TrackTimeScale;
+use mp4parse::SampleEntry;
+use mp4parse::Track;
 use mp4parse::TrackScaledTime;
-use mp4parse::serialize_opus_header;
-use mp4parse::CodecType;
-use mp4parse::Track;
-use mp4parse::vec_push;
+use mp4parse::TrackTimeScale;
+use mp4parse::TrackType;
+use mp4parse::VideoCodecSpecific;
 
 #[repr(C)]
 #[derive(PartialEq, Debug)]
 pub enum Mp4parseStatus {
     Ok = 0,
     BadArg = 1,
     Invalid = 2,
     Unsupported = 3,
@@ -76,67 +80,73 @@ pub enum Mp4parseStatus {
 #[derive(PartialEq, Debug)]
 pub enum Mp4parseTrackType {
     Video = 0,
     Audio = 1,
     Metadata = 2,
 }
 
 impl Default for Mp4parseTrackType {
-    fn default() -> Self { Mp4parseTrackType::Video }
+    fn default() -> Self {
+        Mp4parseTrackType::Video
+    }
 }
 
 #[allow(non_camel_case_types)]
 #[repr(C)]
 #[derive(PartialEq, Debug)]
 pub enum Mp4parseCodec {
     Unknown,
     Aac,
     Flac,
     Opus,
     Avc,
     Vp9,
     Av1,
     Mp3,
     Mp4v,
-    Jpeg,   // for QT JPEG atom in video track
+    Jpeg, // for QT JPEG atom in video track
     Ac3,
     Ec3,
     Alac,
 }
 
 impl Default for Mp4parseCodec {
-    fn default() -> Self { Mp4parseCodec::Unknown }
+    fn default() -> Self {
+        Mp4parseCodec::Unknown
+    }
 }
 
 #[repr(C)]
 #[derive(PartialEq, Debug)]
 pub enum Mp4ParseEncryptionSchemeType {
     None,
     Cenc,
     Cbc1,
     Cens,
     Cbcs,
     // Schemes also have a version component. At the time of writing, this does
     // not impact handling, so we do not expose it. Note that this may need to
     // be exposed in future, should the spec change.
 }
 
 impl Default for Mp4ParseEncryptionSchemeType {
-    fn default() -> Self { Mp4ParseEncryptionSchemeType::None }
+    fn default() -> Self {
+        Mp4ParseEncryptionSchemeType::None
+    }
 }
 
 #[repr(C)]
 #[derive(Default, Debug)]
 pub struct Mp4parseTrackInfo {
     pub track_type: Mp4parseTrackType,
     pub track_id: u32,
     pub duration: u64,
     pub media_time: i64, // wants to be u64? understand how elst adjustment works
-    // TODO(kinetik): include crypto guff
+                         // TODO(kinetik): include crypto guff
 }
 
 #[repr(C)]
 #[derive(Default, Debug, PartialEq)]
 pub struct Mp4parseIndice {
     /// The byte offset in the file where the indexed sample begins.
     pub start_offset: u64,
     /// The byte offset in the file where the indexed sample ends. This is
@@ -277,183 +287,270 @@ impl Default for Mp4parseTrackVideoInfo 
 #[repr(C)]
 #[derive(Default, Debug)]
 pub struct Mp4parseFragmentInfo {
     pub fragment_duration: u64,
     // TODO:
     // info in trex box.
 }
 
+#[derive(Default)]
 pub struct Mp4parseParser {
     context: MediaContext,
-    io: Mp4parseIo,
-    poisoned: bool,
     opus_header: HashMap<u32, Vec<u8>>,
     pssh_data: Vec<u8>,
     sample_table: HashMap<u32, Vec<Mp4parseIndice>>,
     // Store a mapping from track index (not id) to associated sample
     // descriptions. Because each track has a variable number of sample
     // descriptions, and because we need the data to live long enough to be
     // copied out by callers, we store these on the parser struct.
     audio_track_sample_descriptions: HashMap<u32, Vec<Mp4parseTrackAudioSampleInfo>>,
     video_track_sample_descriptions: HashMap<u32, Vec<Mp4parseTrackVideoSampleInfo>>,
 }
 
+/// A unified interface for the parsers which have different contexts, but
+/// share the same pattern of construction. This allows unification of
+/// argument validation from C and minimizes the surface of unsafe code.
+trait ContextParser
+where
+    Self: Sized,
+{
+    type Context: Default;
+
+    fn with_context(context: Self::Context) -> Self;
+
+    fn read<T: Read>(io: &mut T, context: &mut Self::Context) -> mp4parse::Result<()>;
+}
+
 impl Mp4parseParser {
     fn context(&self) -> &MediaContext {
         &self.context
     }
 
     fn context_mut(&mut self) -> &mut MediaContext {
         &mut self.context
     }
 
-    fn io_mut(&mut self) -> &mut Mp4parseIo {
-        &mut self.io
-    }
-
-    fn poisoned(&self) -> bool {
-        self.poisoned
-    }
-
-    fn set_poisoned(&mut self, poisoned: bool) {
-        self.poisoned = poisoned;
-    }
-
     fn opus_header_mut(&mut self) -> &mut HashMap<u32, Vec<u8>> {
         &mut self.opus_header
     }
 
     fn pssh_data_mut(&mut self) -> &mut Vec<u8> {
         &mut self.pssh_data
     }
 
     fn sample_table_mut(&mut self) -> &mut HashMap<u32, Vec<Mp4parseIndice>> {
         &mut self.sample_table
     }
 }
 
+impl ContextParser for Mp4parseParser {
+    type Context = MediaContext;
+
+    fn with_context(context: Self::Context) -> Self {
+        Self {
+            context,
+            ..Default::default()
+        }
+    }
+
+    fn read<T: Read>(io: &mut T, context: &mut Self::Context) -> mp4parse::Result<()> {
+        read_mp4(io, context)
+    }
+}
+
+#[derive(Default)]
+pub struct Mp4parseAvifParser {
+    context: AvifContext,
+}
+
+impl Mp4parseAvifParser {
+    fn context(&self) -> &AvifContext {
+        &self.context
+    }
+}
+
+impl ContextParser for Mp4parseAvifParser {
+    type Context = AvifContext;
+
+    fn with_context(context: Self::Context) -> Self {
+        Self { context }
+    }
+
+    fn read<T: Read>(io: &mut T, context: &mut Self::Context) -> mp4parse::Result<()> {
+        read_avif(io, context)
+    }
+}
+
 #[repr(C)]
 #[derive(Clone)]
 pub struct Mp4parseIo {
-    pub read: Option<extern fn(buffer: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize>,
+    pub read: Option<
+        extern "C" fn(buffer: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize,
+    >,
     pub userdata: *mut std::os::raw::c_void,
 }
 
 impl Read for Mp4parseIo {
     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
         if buf.len() > isize::max_value() as usize {
-            return Err(std::io::Error::new(std::io::ErrorKind::Other, "buf length overflow in Mp4parseIo Read impl"));
+            return Err(std::io::Error::new(
+                std::io::ErrorKind::Other,
+                "buf length overflow in Mp4parseIo Read impl",
+            ));
         }
         let rv = self.read.unwrap()(buf.as_mut_ptr(), buf.len(), self.userdata);
         if rv >= 0 {
             Ok(rv as usize)
         } else {
-            Err(std::io::Error::new(std::io::ErrorKind::Other, "I/O error in Mp4parseIo Read impl"))
+            Err(std::io::Error::new(
+                std::io::ErrorKind::Other,
+                "I/O error in Mp4parseIo Read impl",
+            ))
         }
     }
 }
 
 // C API wrapper functions.
 
-/// Allocate an `Mp4parseParser*` to read from the supplied `Mp4parseIo`.
+/// Allocate an `Mp4parseParser*` to read from the supplied `Mp4parseIo` and
+/// parse the content from the `Mp4parseIo` argument until EOF or error.
+///
+/// # Safety
+///
+/// This function is unsafe because it dereferences the `io` and `parser_out`
+/// pointers given to it. The caller should ensure that the `Mp4ParseIo`
+/// struct passed in is a valid pointer. The caller should also ensure the
+/// members of io are valid: the `read` function should be sanely implemented,
+/// and the `userdata` pointer should be valid. The `parser_out` should be a
+/// valid pointer to a location containing a null pointer. Upon successful
+/// return (`Mp4parseStatus::Ok`), that location will contain the address of
+/// an `Mp4parseParser` allocated by this function.
+///
+/// To avoid leaking memory, any successful return of this function must be
+/// paired with a call to `mp4parse_free`. In the event of error, no memory
+/// will be allocated and `mp4parse_free` must *not* be called.
+#[no_mangle]
+pub unsafe extern "C" fn mp4parse_new(
+    io: *const Mp4parseIo,
+    parser_out: *mut *mut Mp4parseParser,
+) -> Mp4parseStatus {
+    mp4parse_new_common(io, parser_out)
+}
+
+/// Allocate an `Mp4parseAvifParser*` to read from the supplied `Mp4parseIo`.
+///
+/// See mp4parse_new; this function is identical except that it allocates an
+/// `Mp4parseAvifParser`, which (when successful) must be paired with a call
+/// to mp4parse_avif_free.
 ///
 /// # Safety
 ///
-/// This function is unsafe because it dereferences the io pointer given to it.
-/// The caller should ensure that the `Mp4ParseIo` struct passed in is a valid
-/// pointer. The caller should also ensure the members of io are valid: the
-/// `read` function should be sanely implemented, and the `userdata` pointer
-/// should be valid.
+/// Same as mp4parse_new.
 #[no_mangle]
-pub unsafe extern fn mp4parse_new(io: *const Mp4parseIo) -> *mut Mp4parseParser {
-    if io.is_null() || (*io).userdata.is_null() {
-        return std::ptr::null_mut();
-    }
-    if (*io).read.is_none() {
-        return std::ptr::null_mut();
+pub unsafe extern "C" fn mp4parse_avif_new(
+    io: *const Mp4parseIo,
+    parser_out: *mut *mut Mp4parseAvifParser,
+) -> Mp4parseStatus {
+    mp4parse_new_common(io, parser_out)
+}
+
+unsafe fn mp4parse_new_common<P: ContextParser>(
+    io: *const Mp4parseIo,
+    parser_out: *mut *mut P,
+) -> Mp4parseStatus {
+    // Validate arguments from C.
+    if io.is_null()
+        || (*io).userdata.is_null()
+        || (*io).read.is_none()
+        || parser_out.is_null()
+        || !(*parser_out).is_null()
+    {
+        Mp4parseStatus::BadArg
+    } else {
+        match mp4parse_new_common_safe(&mut (*io).clone()) {
+            Ok(parser) => {
+                *parser_out = parser;
+                Mp4parseStatus::Ok
+            }
+            Err(status) => status,
+        }
     }
-    let parser = Box::new(Mp4parseParser {
-        context: MediaContext::new(),
-        io: (*io).clone(),
-        poisoned: false,
-        opus_header: HashMap::new(),
-        pssh_data: Vec::new(),
-        sample_table: HashMap::new(),
-        audio_track_sample_descriptions: HashMap::new(),
-        video_track_sample_descriptions: HashMap::new(),
-    });
+}
+
+fn mp4parse_new_common_safe<T: Read, P: ContextParser>(
+    io: &mut T,
+) -> Result<*mut P, Mp4parseStatus> {
+    let mut context = P::Context::default();
+
+    P::read(io, &mut context)
+        .map(|_| P::with_context(context))
+        .map(Box::new)
+        .map(Box::into_raw)
+        .map_err(Mp4parseStatus::from)
+}
 
-    Box::into_raw(parser)
+impl From<mp4parse::Error> for Mp4parseStatus {
+    fn from(error: mp4parse::Error) -> Self {
+        match error {
+            Error::NoMoov | Error::InvalidData(_) => Mp4parseStatus::Invalid,
+            Error::Unsupported(_) => Mp4parseStatus::Unsupported,
+            Error::UnexpectedEOF => Mp4parseStatus::Eof,
+            Error::Io(_) => {
+                // Getting std::io::ErrorKind::UnexpectedEof is normal
+                // but our From trait implementation should have converted
+                // those to our Error::UnexpectedEOF variant.
+                Mp4parseStatus::Io
+            }
+            Error::OutOfMemory => Mp4parseStatus::Oom,
+        }
+    }
 }
 
 /// Free an `Mp4parseParser*` allocated by `mp4parse_new()`.
 ///
 /// # Safety
 ///
 /// This function is unsafe because it creates a box from a raw pointer.
 /// Callers should ensure that the parser pointer points to a valid
 /// `Mp4parseParser` created by `mp4parse_new`.
 #[no_mangle]
-pub unsafe extern fn mp4parse_free(parser: *mut Mp4parseParser) {
+pub unsafe extern "C" fn mp4parse_free(parser: *mut Mp4parseParser) {
     assert!(!parser.is_null());
     let _ = Box::from_raw(parser);
 }
 
-/// Run the `Mp4parseParser*` allocated by `mp4parse_new()` until EOF or error.
+/// Free an `Mp4parseAvifParser*` allocated by `mp4parse_avif_new()`.
 ///
 /// # Safety
 ///
-/// This function is unsafe because it dereferences the raw parser pointer
-/// passed to it. Callers should ensure that the parser pointer points to a
-/// valid `Mp4parseParser`.
+/// This function is unsafe because it creates a box from a raw pointer.
+/// Callers should ensure that the parser pointer points to a valid
+/// `Mp4parseAvifParser` created by `mp4parse_avif_new`.
 #[no_mangle]
-pub unsafe extern fn mp4parse_read(parser: *mut Mp4parseParser) -> Mp4parseStatus {
-    // Validate arguments from C.
-    if parser.is_null() || (*parser).poisoned() {
-        return Mp4parseStatus::BadArg;
-    }
-
-    let context = (*parser).context_mut();
-    let io = (*parser).io_mut();
-
-    let r = read_mp4(io, context);
-    match r {
-        Ok(_) => Mp4parseStatus::Ok,
-        Err(Error::NoMoov) | Err(Error::InvalidData(_)) => {
-            // Block further calls. We've probable lost sync.
-            (*parser).set_poisoned(true);
-            Mp4parseStatus::Invalid
-        }
-        Err(Error::Unsupported(_)) => Mp4parseStatus::Unsupported,
-        Err(Error::UnexpectedEOF) => Mp4parseStatus::Eof,
-        Err(Error::Io(_)) => {
-            // Block further calls after a read failure.
-            // Getting std::io::ErrorKind::UnexpectedEof is normal
-            // but our From trait implementation should have converted
-            // those to our Error::UnexpectedEOF variant.
-            (*parser).set_poisoned(true);
-            Mp4parseStatus::Io
-        },
-        Err(Error::OutOfMemory) => Mp4parseStatus::Oom,
-    }
+pub unsafe extern "C" fn mp4parse_avif_free(parser: *mut Mp4parseAvifParser) {
+    assert!(!parser.is_null());
+    let _ = Box::from_raw(parser);
 }
 
 /// Return the number of tracks parsed by previous `mp4parse_read()` call.
 ///
 /// # Safety
 ///
 /// This function is unsafe because it dereferences both the parser and count
 /// raw pointers passed into it. Callers should ensure the parser pointer
 /// points to a valid `Mp4parseParser`, and that the count pointer points an
 /// appropriate memory location to have a `u32` written to.
 #[no_mangle]
-pub unsafe extern fn mp4parse_get_track_count(parser: *const Mp4parseParser, count: *mut u32) -> Mp4parseStatus {
+pub unsafe extern "C" fn mp4parse_get_track_count(
+    parser: *const Mp4parseParser,
+    count: *mut u32,
+) -> Mp4parseStatus {
     // Validate arguments from C.
-    if parser.is_null() || count.is_null() || (*parser).poisoned() {
+    if parser.is_null() || count.is_null() {
         return Mp4parseStatus::BadArg;
     }
     let context = (*parser).context();
 
     // Make sure the track count fits in a u32.
     if context.tracks.len() > u32::max_value() as usize {
         return Mp4parseStatus::Invalid;
     }
@@ -465,55 +562,63 @@ pub unsafe extern fn mp4parse_get_track_
 ///
 /// Applying the associativity of integer arithmetic, we divide first
 /// and add the remainder after multiplying each term separately
 /// to preserve precision while leaving more headroom. That is,
 /// (n * s) / d is split into floor(n / d) * s + (n % d) * s / d.
 ///
 /// Return None on overflow or if the denominator is zero.
 fn rational_scale<T, S>(numerator: T, denominator: T, scale2: S) -> Option<T>
-    where T: PrimInt + Zero, S: PrimInt {
+where
+    T: PrimInt + Zero,
+    S: PrimInt,
+{
     if denominator.is_zero() {
         return None;
     }
 
     let integer = numerator / denominator;
     let remainder = numerator % denominator;
-    num_traits::cast(scale2).and_then(|s| {
-        match integer.checked_mul(&s) {
-            Some(integer) => remainder.checked_mul(&s)
-                .and_then(|remainder| (remainder/denominator).checked_add(&integer)),
-            None => None,
-        }
+    num_traits::cast(scale2).and_then(|s| match integer.checked_mul(&s) {
+        Some(integer) => remainder
+            .checked_mul(&s)
+            .and_then(|remainder| (remainder / denominator).checked_add(&integer)),
+        None => None,
     })
 }
 
 fn media_time_to_us(time: MediaScaledTime, scale: MediaTimeScale) -> Option<u64> {
     let microseconds_per_second = 1_000_000;
     rational_scale::<u64, u64>(time.0, scale.0, microseconds_per_second)
 }
 
 fn track_time_to_us<T>(time: TrackScaledTime<T>, scale: TrackTimeScale<T>) -> Option<T>
-    where T: PrimInt + Zero {
+where
+    T: PrimInt + Zero,
+{
     assert_eq!(time.1, scale.1);
     let microseconds_per_second = 1_000_000;
     rational_scale::<T, u64>(time.0, scale.0, microseconds_per_second)
 }
 
 /// Fill the supplied `Mp4parseTrackInfo` with metadata for `track`.
 ///
 /// # Safety
 ///
 /// This function is unsafe because it dereferences the the parser and info raw
 /// pointers passed to it. Callers should ensure the parser pointer points to a
 /// valid `Mp4parseParser` and that the info pointer points to a valid
 /// `Mp4parseTrackInfo`.
 #[no_mangle]
-pub unsafe extern fn mp4parse_get_track_info(parser: *mut Mp4parseParser, track_index: u32, info: *mut Mp4parseTrackInfo) -> Mp4parseStatus {
-    if parser.is_null() || info.is_null() || (*parser).poisoned() {
+pub unsafe extern "C" fn mp4parse_get_track_info(
+    parser: *mut Mp4parseParser,
+    track_index: u32,
+    info: *mut Mp4parseTrackInfo,
+) -> Mp4parseStatus {
+    if parser.is_null() || info.is_null() {
         return Mp4parseStatus::BadArg;
     }
 
     // Initialize fields to default values to ensure all fields are always valid.
     *info = Default::default();
 
     let context = (*parser).context_mut();
     let track_index: usize = track_index as usize;
@@ -527,44 +632,42 @@ pub unsafe extern fn mp4parse_get_track_
         TrackType::Video => Mp4parseTrackType::Video,
         TrackType::Audio => Mp4parseTrackType::Audio,
         TrackType::Metadata => Mp4parseTrackType::Metadata,
         TrackType::Unknown => return Mp4parseStatus::Unsupported,
     };
 
     let track = &context.tracks[track_index];
 
-    if let (Some(track_timescale),
-            Some(context_timescale)) = (track.timescale,
-                                        context.timescale) {
-        let media_time =
-            match track.media_time.map_or(Some(0), |media_time| {
-                    track_time_to_us(media_time, track_timescale) }) {
-                Some(time) => time as i64,
-                None => return Mp4parseStatus::Invalid,
-            };
-        let empty_duration =
-            match track.empty_duration.map_or(Some(0), |empty_duration| {
-                    media_time_to_us(empty_duration, context_timescale) }) {
-                Some(time) => time as i64,
-                None => return Mp4parseStatus::Invalid,
-            };
+    if let (Some(track_timescale), Some(context_timescale)) = (track.timescale, context.timescale) {
+        let media_time = match track.media_time.map_or(Some(0), |media_time| {
+            track_time_to_us(media_time, track_timescale)
+        }) {
+            Some(time) => time as i64,
+            None => return Mp4parseStatus::Invalid,
+        };
+        let empty_duration = match track.empty_duration.map_or(Some(0), |empty_duration| {
+            media_time_to_us(empty_duration, context_timescale)
+        }) {
+            Some(time) => time as i64,
+            None => return Mp4parseStatus::Invalid,
+        };
         info.media_time = media_time - empty_duration;
 
         if let Some(track_duration) = track.duration {
             match track_time_to_us(track_duration, track_timescale) {
                 Some(duration) => info.duration = duration,
                 None => return Mp4parseStatus::Invalid,
             }
         } else {
             // Duration unknown; stagefright returns 0 for this.
             info.duration = 0
         }
     } else {
-        return Mp4parseStatus::Invalid
+        return Mp4parseStatus::Invalid;
     }
 
     info.track_id = match track.track_id {
         Some(track_id) => track_id,
         None => return Mp4parseStatus::Invalid,
     };
 
     Mp4parseStatus::Ok
@@ -574,18 +677,22 @@ pub unsafe extern fn mp4parse_get_track_
 ///
 /// # Safety
 ///
 /// This function is unsafe because it dereferences the the parser and info raw
 /// pointers passed to it. Callers should ensure the parser pointer points to a
 /// valid `Mp4parseParser` and that the info pointer points to a valid
 /// `Mp4parseTrackAudioInfo`.
 #[no_mangle]
-pub unsafe extern fn mp4parse_get_track_audio_info(parser: *mut Mp4parseParser, track_index: u32, info: *mut Mp4parseTrackAudioInfo) -> Mp4parseStatus {
-    if parser.is_null() || info.is_null() || (*parser).poisoned() {
+pub unsafe extern "C" fn mp4parse_get_track_audio_info(
+    parser: *mut Mp4parseParser,
+    track_index: u32,
+    info: *mut Mp4parseTrackAudioInfo,
+) -> Mp4parseStatus {
+    if parser.is_null() || info.is_null() {
         return Mp4parseStatus::BadArg;
     }
 
     // Initialize fields to default values to ensure all fields are always valid.
     *info = Default::default();
 
     let context = (*parser).context();
 
@@ -604,40 +711,39 @@ pub unsafe extern fn mp4parse_get_track_
         Some(ref stsd) => stsd,
         None => return Mp4parseStatus::Invalid, // Stsd should be present
     };
 
     if stsd.descriptions.is_empty() {
         return Mp4parseStatus::Invalid; // Should have at least 1 description
     }
 
-    let mut audio_sample_infos = Vec:: with_capacity(stsd.descriptions.len());
+    let mut audio_sample_infos = Vec::with_capacity(stsd.descriptions.len());
     for description in stsd.descriptions.iter() {
         let mut sample_info = Mp4parseTrackAudioSampleInfo::default();
         let audio = match description {
             SampleEntry::Audio(a) => a,
             _ => return Mp4parseStatus::Invalid,
         };
 
         // UNKNOWN for unsupported format.
         sample_info.codec_type = match audio.codec_specific {
-            AudioCodecSpecific::OpusSpecificBox(_) =>
-                Mp4parseCodec::Opus,
-            AudioCodecSpecific::FLACSpecificBox(_) =>
-                Mp4parseCodec::Flac,
-            AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::AAC =>
-                Mp4parseCodec::Aac,
-            AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 =>
-                Mp4parseCodec::Mp3,
-            AudioCodecSpecific::ES_Descriptor(_) | AudioCodecSpecific::LPCM =>
-                Mp4parseCodec::Unknown,
-            AudioCodecSpecific::MP3 =>
-                Mp4parseCodec::Mp3,
-            AudioCodecSpecific::ALACSpecificBox(_) =>
-                Mp4parseCodec::Alac,
+            AudioCodecSpecific::OpusSpecificBox(_) => Mp4parseCodec::Opus,
+            AudioCodecSpecific::FLACSpecificBox(_) => Mp4parseCodec::Flac,
+            AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::AAC => {
+                Mp4parseCodec::Aac
+            }
+            AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 => {
+                Mp4parseCodec::Mp3
+            }
+            AudioCodecSpecific::ES_Descriptor(_) | AudioCodecSpecific::LPCM => {
+                Mp4parseCodec::Unknown
+            }
+            AudioCodecSpecific::MP3 => Mp4parseCodec::Mp3,
+            AudioCodecSpecific::ALACSpecificBox(_) => Mp4parseCodec::Alac,
         };
         sample_info.channels = audio.channelcount as u16;
         sample_info.bit_depth = audio.samplesize;
         sample_info.sample_rate = audio.samplerate as u32;
         // sample_info.profile is handled below on a per case basis
 
         match audio.codec_specific {
             AudioCodecSpecific::ES_Descriptor(ref esds) => {
@@ -654,17 +760,17 @@ pub unsafe extern fn mp4parse_get_track_
                 if let Some(channels) = esds.audio_channel_count {
                     sample_info.channels = channels;
                 }
                 if let Some(profile) = esds.audio_object_type {
                     sample_info.profile = profile;
                 }
                 sample_info.extended_profile = match esds.extended_audio_object_type {
                     Some(extended_profile) => extended_profile,
-                    _ => sample_info.profile
+                    _ => sample_info.profile,
                 };
             }
             AudioCodecSpecific::FLACSpecificBox(ref flac) => {
                 // Return the STREAMINFO metadata block in the codec_specific.
                 let streaminfo = &flac.blocks[0];
                 if streaminfo.block_type != 0 || streaminfo.data.len() != 34 {
                     return Mp4parseStatus::Invalid;
                 }
@@ -692,28 +798,32 @@ pub unsafe extern fn mp4parse_get_track_
             }
             AudioCodecSpecific::ALACSpecificBox(ref alac) => {
                 sample_info.codec_specific_config.length = alac.data.len() as u32;
                 sample_info.codec_specific_config.data = alac.data.as_ptr();
             }
             AudioCodecSpecific::MP3 | AudioCodecSpecific::LPCM => (),
         }
 
-        if let Some(p) = audio.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
+        if let Some(p) = audio
+            .protection_info
+            .iter()
+            .find(|sinf| sinf.tenc.is_some())
+        {
             sample_info.protected_data.scheme_type = match p.scheme_type {
                 Some(ref scheme_type_box) => {
                     match scheme_type_box.scheme_type.value.as_ref() {
                         "cenc" => Mp4ParseEncryptionSchemeType::Cenc,
                         "cbcs" => Mp4ParseEncryptionSchemeType::Cbcs,
                         // We don't support other schemes, and shouldn't reach
                         // this case. Try to gracefully handle by treating as
                         // no encryption case.
                         _ => Mp4ParseEncryptionSchemeType::None,
                     }
-                },
+                }
                 None => Mp4ParseEncryptionSchemeType::None,
             };
             if let Some(ref tenc) = p.tenc {
                 sample_info.protected_data.is_encrypted = tenc.is_encrypted;
                 sample_info.protected_data.iv_size = tenc.iv_size;
                 sample_info.protected_data.kid.set_data(&(tenc.kid));
                 sample_info.protected_data.crypt_byte_block = match tenc.crypt_byte_block_count {
                     Some(n) => n,
@@ -726,47 +836,56 @@ pub unsafe extern fn mp4parse_get_track_
                 if let Some(ref iv_vec) = tenc.constant_iv {
                     if iv_vec.len() > std::u32::MAX as usize {
                         return Mp4parseStatus::Invalid;
                     }
                     sample_info.protected_data.constant_iv.set_data(iv_vec);
                 };
             }
         }
-        audio_sample_infos.push(sample_info);
+        let res = vec_push(&mut audio_sample_infos, sample_info);
+        if res.is_err() {
+            return Mp4parseStatus::Oom;
+        }
     }
 
-    (*parser).audio_track_sample_descriptions.insert(track_index, audio_sample_infos);
+    (*parser)
+        .audio_track_sample_descriptions
+        .insert(track_index, audio_sample_infos);
     match (*parser).audio_track_sample_descriptions.get(&track_index) {
         Some(sample_info) => {
             if sample_info.len() > std::u32::MAX as usize {
                 // Should never happen due to upper limits on number of sample
                 // descriptions a track can have, but lets be safe.
                 return Mp4parseStatus::Invalid;
             }
             (*info).sample_info_count = sample_info.len() as u32;
             (*info).sample_info = sample_info.as_ptr();
-        },
+        }
         None => return Mp4parseStatus::Invalid, // Shouldn't happen, we just inserted the info!
     }
 
     Mp4parseStatus::Ok
 }
 
 /// Fill the supplied `Mp4parseTrackVideoInfo` with metadata for `track`.
 ///
 /// # Safety
 ///
 /// This function is unsafe because it dereferences the the parser and info raw
 /// pointers passed to it. Callers should ensure the parser pointer points to a
 /// valid `Mp4parseParser` and that the info pointer points to a valid
 /// `Mp4parseTrackVideoInfo`.
 #[no_mangle]
-pub unsafe extern fn mp4parse_get_track_video_info(parser: *mut Mp4parseParser, track_index: u32, info: *mut Mp4parseTrackVideoInfo) -> Mp4parseStatus {
-    if parser.is_null() || info.is_null() || (*parser).poisoned() {
+pub unsafe extern "C" fn mp4parse_get_track_video_info(
+    parser: *mut Mp4parseParser,
+    track_index: u32,
+    info: *mut Mp4parseTrackVideoInfo,
+) -> Mp4parseStatus {
+    if parser.is_null() || info.is_null() {
         return Mp4parseStatus::BadArg;
     }
 
     // Initialize fields to default values to ensure all fields are always valid.
     *info = Default::default();
 
     let context = (*parser).context();
 
@@ -779,79 +898,87 @@ pub unsafe extern fn mp4parse_get_track_
     if track.track_type != TrackType::Video {
         return Mp4parseStatus::Invalid;
     }
 
     // Handle track.tkhd
     if let Some(ref tkhd) = track.tkhd {
         (*info).display_width = tkhd.width >> 16; // 16.16 fixed point
         (*info).display_height = tkhd.height >> 16; // 16.16 fixed point
-        let matrix = (tkhd.matrix.a >> 16, tkhd.matrix.b >> 16,
-                      tkhd.matrix.c >> 16, tkhd.matrix.d >> 16);
+        let matrix = (
+            tkhd.matrix.a >> 16,
+            tkhd.matrix.b >> 16,
+            tkhd.matrix.c >> 16,
+            tkhd.matrix.d >> 16,
+        );
         (*info).rotation = match matrix {
-            ( 0,  1, -1,  0) => 90, // rotate 90 degrees
-            (-1,  0,  0, -1) => 180, // rotate 180 degrees
-            ( 0, -1,  1,  0) => 270, // rotate 270 degrees
+            (0, 1, -1, 0) => 90,   // rotate 90 degrees
+            (-1, 0, 0, -1) => 180, // rotate 180 degrees
+            (0, -1, 1, 0) => 270,  // rotate 270 degrees
             _ => 0,
         };
     } else {
         return Mp4parseStatus::Invalid;
     }
 
     // Handle track.stsd
     let stsd = match track.stsd {
         Some(ref stsd) => stsd,
         None => return Mp4parseStatus::Invalid, // Stsd should be present
     };
 
     if stsd.descriptions.is_empty() {
         return Mp4parseStatus::Invalid; // Should have at least 1 description
     }
 
-    let mut video_sample_infos = Vec:: with_capacity(stsd.descriptions.len());
+    let mut video_sample_infos = Vec::with_capacity(stsd.descriptions.len());
     for description in stsd.descriptions.iter() {
         let mut sample_info = Mp4parseTrackVideoSampleInfo::default();
         let video = match description {
             SampleEntry::Video(v) => v,
             _ => return Mp4parseStatus::Invalid,
         };
 
         // UNKNOWN for unsupported format.
         sample_info.codec_type = match video.codec_specific {
-            VideoCodecSpecific::VPxConfig(_) =>
-                Mp4parseCodec::Vp9,
-            VideoCodecSpecific::AV1Config(_) =>
-                Mp4parseCodec::Av1,
-            VideoCodecSpecific::AVCConfig(_) =>
-                Mp4parseCodec::Avc,
-            VideoCodecSpecific::ESDSConfig(_) => // MP4V (14496-2) video is unsupported.
-                Mp4parseCodec::Unknown,
+            VideoCodecSpecific::VPxConfig(_) => Mp4parseCodec::Vp9,
+            VideoCodecSpecific::AV1Config(_) => Mp4parseCodec::Av1,
+            VideoCodecSpecific::AVCConfig(_) => Mp4parseCodec::Avc,
+            VideoCodecSpecific::ESDSConfig(_) =>
+            // MP4V (14496-2) video is unsupported.
+            {
+                Mp4parseCodec::Unknown
+            }
         };
         sample_info.image_width = video.width;
         sample_info.image_height = video.height;
 
         match video.codec_specific {
             VideoCodecSpecific::AVCConfig(ref data) | VideoCodecSpecific::ESDSConfig(ref data) => {
                 sample_info.extra_data.set_data(data);
-            },
+            }
             _ => {}
         }
 
-        if let Some(p) = video.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
+        if let Some(p) = video
+            .protection_info
+            .iter()
+            .find(|sinf| sinf.tenc.is_some())
+        {
             sample_info.protected_data.scheme_type = match p.scheme_type {
                 Some(ref scheme_type_box) => {
                     match scheme_type_box.scheme_type.value.as_ref() {
                         "cenc" => Mp4ParseEncryptionSchemeType::Cenc,
                         "cbcs" => Mp4ParseEncryptionSchemeType::Cbcs,
                         // We don't support other schemes, and shouldn't reach
                         // this case. Try to gracefully handle by treating as
                         // no encryption case.
                         _ => Mp4ParseEncryptionSchemeType::None,
                     }
-                },
+                }
                 None => Mp4ParseEncryptionSchemeType::None,
             };
             if let Some(ref tenc) = p.tenc {
                 sample_info.protected_data.is_encrypted = tenc.is_encrypted;
                 sample_info.protected_data.iv_size = tenc.iv_size;
                 sample_info.protected_data.kid.set_data(&(tenc.kid));
                 sample_info.protected_data.crypt_byte_block = match tenc.crypt_byte_block_count {
                     Some(n) => n,
@@ -864,46 +991,85 @@ pub unsafe extern fn mp4parse_get_track_
                 if let Some(ref iv_vec) = tenc.constant_iv {
                     if iv_vec.len() > std::u32::MAX as usize {
                         return Mp4parseStatus::Invalid;
                     }
                     sample_info.protected_data.constant_iv.set_data(iv_vec);
                 };
             }
         }
-        video_sample_infos.push(sample_info);
+        let res = vec_push(&mut video_sample_infos, sample_info);
+        if res.is_err() {
+            return Mp4parseStatus::Oom;
+        }
     }
 
-    (*parser).video_track_sample_descriptions.insert(track_index, video_sample_infos);
+    (*parser)
+        .video_track_sample_descriptions
+        .insert(track_index, video_sample_infos);
     match (*parser).video_track_sample_descriptions.get(&track_index) {
         Some(sample_info) => {
             if sample_info.len() > std::u32::MAX as usize {
                 // Should never happen due to upper limits on number of sample
                 // descriptions a track can have, but lets be safe.
                 return Mp4parseStatus::Invalid;
             }
             (*info).sample_info_count = sample_info.len() as u32;
             (*info).sample_info = sample_info.as_ptr();
-        },
+        }
         None => return Mp4parseStatus::Invalid, // Shouldn't happen, we just inserted the info!
     }
     Mp4parseStatus::Ok
 }
 
+/// Return a pointer to the primary item parsed by previous `mp4parse_avif_new()` call.
+///
+/// # Safety
+///
+/// This function is unsafe because it dereferences both the parser and
+/// primary_item raw pointers passed into it. Callers should ensure the parser
+/// pointer points to a valid `Mp4parseAvifParser`, and that the primary_item
+/// pointer points to a valid `Mp4parseByteData`. If there was not a previous
+/// successful call to `mp4parse_avif_read()`, no guarantees are made as to
+/// the state of `primary_item`.
+#[no_mangle]
+pub unsafe extern "C" fn mp4parse_avif_get_primary_item(
+    parser: *mut Mp4parseAvifParser,
+    primary_item: *mut Mp4parseByteData,
+) -> Mp4parseStatus {
+    if parser.is_null() {
+        return Mp4parseStatus::BadArg;
+    }
+
+    // Initialize fields to default values to ensure all fields are always valid.
+    *primary_item = Default::default();
+
+    let context = (*parser).context();
+
+    // TODO: check for a valid parsed context. See https://github.com/mozilla/mp4parse-rust/issues/195
+    (*primary_item).set_data(&context.primary_item);
+
+    Mp4parseStatus::Ok
+}
+
 /// Fill the supplied `Mp4parseByteData` with index information from `track`.
 ///
 /// # Safety
 ///
 /// This function is unsafe because it dereferences the the parser and indices
 /// raw pointers passed to it. Callers should ensure the parser pointer points
 /// to a valid `Mp4parseParser` and that the indices pointer points to a valid
 /// `Mp4parseByteData`.
 #[no_mangle]
-pub unsafe extern fn mp4parse_get_indice_table(parser: *mut Mp4parseParser, track_id: u32, indices: *mut Mp4parseByteData) -> Mp4parseStatus {
-    if parser.is_null() || (*parser).poisoned() {
+pub unsafe extern "C" fn mp4parse_get_indice_table(
+    parser: *mut Mp4parseParser,
+    track_id: u32,
+    indices: *mut Mp4parseByteData,
+) -> Mp4parseStatus {
+    if parser.is_null() {
         return Mp4parseStatus::BadArg;
     }
 
     // Initialize fields to default values to ensure all fields are always valid.
     *indices = Default::default();
 
     let context = (*parser).context();
     let tracks = &context.tracks;
@@ -914,27 +1080,23 @@ pub unsafe extern fn mp4parse_get_indice
 
     let index_table = (*parser).sample_table_mut();
     if let Some(v) = index_table.get(&track_id) {
         (*indices).set_indices(v);
         return Mp4parseStatus::Ok;
     }
 
     let media_time = match (&track.media_time, &track.timescale) {
-        (&Some(t), &Some(s)) => {
-            track_time_to_us(t, s).map(|v| v as i64)
-        },
+        (&Some(t), &Some(s)) => track_time_to_us(t, s).map(|v| v as i64),
         _ => None,
     };
 
     let empty_duration = match (&track.empty_duration, &context.timescale) {
-        (&Some(e), &Some(s)) => {
-            media_time_to_us(e, s).map(|v| v as i64)
-        },
-        _ => None
+        (&Some(e), &Some(s)) => media_time_to_us(e, s).map(|v| v as i64),
+        _ => None,
     };
 
     // Find the track start offset time from 'elst'.
     // 'media_time' maps start time onward, 'empty_duration' adds time offset
     // before first frame is displayed.
     let offset_time = match (empty_duration, media_time) {
         (Some(e), Some(m)) => e - m,
         (Some(e), None) => e,
@@ -962,42 +1124,41 @@ struct TimeOffsetIterator<'a> {
     ctts_iter: Option<std::slice::Iter<'a, mp4parse::TimeOffset>>,
     track_id: usize,
 }
 
 impl<'a> Iterator for TimeOffsetIterator<'a> {
     type Item = i64;
 
     fn next(&mut self) -> Option<i64> {
-        let has_sample = self.cur_sample_range.next()
-            .or_else(|| {
-                // At end of current TimeOffset, find the next TimeOffset.
-                let iter = match self.ctts_iter {
-                    Some(ref mut v) => v,
-                    _ => return None,
-                };
-                let offset_version;
-                self.cur_sample_range = match iter.next() {
-                    Some(v) => {
-                        offset_version = v.time_offset;
-                        0 .. v.sample_count
-                    },
-                    _ => {
-                        offset_version = mp4parse::TimeOffsetVersion::Version0(0);
-                        0 .. 0
-                    },
-                };
+        let has_sample = self.cur_sample_range.next().or_else(|| {
+            // At end of current TimeOffset, find the next TimeOffset.
+            let iter = match self.ctts_iter {
+                Some(ref mut v) => v,
+                _ => return None,
+            };
+            let offset_version;
+            self.cur_sample_range = match iter.next() {
+                Some(v) => {
+                    offset_version = v.time_offset;
+                    0..v.sample_count
+                }
+                _ => {
+                    offset_version = mp4parse::TimeOffsetVersion::Version0(0);
+                    0..0
+                }
+            };
 
-                self.cur_offset = match offset_version {
-                    mp4parse::TimeOffsetVersion::Version0(i) => i64::from(i),
-                    mp4parse::TimeOffsetVersion::Version1(i) => i64::from(i),
-                };
+            self.cur_offset = match offset_version {
+                mp4parse::TimeOffsetVersion::Version0(i) => i64::from(i),
+                mp4parse::TimeOffsetVersion::Version1(i) => i64::from(i),
+            };
 
-                self.cur_sample_range.next()
-            });
+            self.cur_sample_range.next()
+        });
 
         has_sample.and(Some(self.cur_offset))
     }
 }
 
 impl<'a> TimeOffsetIterator<'a> {
     fn next_offset_time(&mut self) -> TrackScaledTime<i64> {
         match self.next() {
@@ -1019,28 +1180,27 @@ struct TimeToSampleIterator<'a> {
     stts_iter: std::slice::Iter<'a, mp4parse::Sample>,
     track_id: usize,
 }
 
 impl<'a> Iterator for TimeToSampleIterator<'a> {
     type Item = u32;
 
     fn next(&mut self) -> Option<u32> {
-        let has_sample = self.cur_sample_count.next()
-            .or_else(|| {
-                self.cur_sample_count = match self.stts_iter.next() {
-                    Some(v) => {
-                        self.cur_sample_delta = v.sample_delta;
-                        0 .. v.sample_count
-                    },
-                    _ => 0 .. 0,
-                };
+        let has_sample = self.cur_sample_count.next().or_else(|| {
+            self.cur_sample_count = match self.stts_iter.next() {
+                Some(v) => {
+                    self.cur_sample_delta = v.sample_delta;
+                    0..v.sample_count
+                }
+                _ => 0..0,
+            };
 
-                self.cur_sample_count.next()
-            });
+            self.cur_sample_count.next()
+        });
 
         has_sample.and(Some(self.cur_sample_delta))
     }
 }
 
 impl<'a> TimeToSampleIterator<'a> {
     fn next_delta(&mut self) -> TrackScaledTime<i64> {
         match self.next() {
@@ -1067,144 +1227,150 @@ struct SampleToChunkIterator<'a> {
     stsc_peek_iter: std::iter::Peekable<std::slice::Iter<'a, mp4parse::SampleToChunk>>,
     remain_chunk_count: u32, // total chunk number from 'stco'.
 }
 
 impl<'a> Iterator for SampleToChunkIterator<'a> {
     type Item = (u32, u32);
 
     fn next(&mut self) -> Option<(u32, u32)> {
-        let has_chunk = self.chunks.next()
-            .or_else(|| {
-                self.chunks = self.locate();
-                self.remain_chunk_count.checked_sub(self.chunks.len() as u32).and_then(|res| {
+        let has_chunk = self.chunks.next().or_else(|| {
+            self.chunks = self.locate();
+            self.remain_chunk_count
+                .checked_sub(self.chunks.len() as u32)
+                .and_then(|res| {
                     self.remain_chunk_count = res;
                     self.chunks.next()
                 })
-            });
+        });
 
-        has_chunk.map(|id| { (id, self.sample_count) })
+        has_chunk.map(|id| (id, self.sample_count))
     }
 }
 
 impl<'a> SampleToChunkIterator<'a> {
     fn locate(&mut self) -> std::ops::Range<u32> {
         loop {
             return match (self.stsc_peek_iter.next(), self.stsc_peek_iter.peek()) {
                 (Some(next), Some(peek)) if next.first_chunk == peek.first_chunk => {
                     // Invalid entry, skip it and will continue searching at
                     // next loop iteration.
-                    continue
-                },
+                    continue;
+                }
                 (Some(next), Some(peek)) if next.first_chunk > 0 && peek.first_chunk > 0 => {
                     self.sample_count = next.samples_per_chunk;
-                    (next.first_chunk - 1) .. (peek.first_chunk - 1)
-                },
+                    (next.first_chunk - 1)..(peek.first_chunk - 1)
+                }
                 (Some(next), None) if next.first_chunk > 0 => {
                     self.sample_count = next.samples_per_chunk;
                     // Total chunk number in 'stsc' could be different to 'stco',
                     // there could be more chunks at the last 'stsc' record.
                     match next.first_chunk.checked_add(self.remain_chunk_count) {
-                        Some(r) => (next.first_chunk - 1) .. r - 1,
-                        _ => 0 .. 0,
+                        Some(r) => (next.first_chunk - 1)..r - 1,
+                        _ => 0..0,
                     }
-                },
-                _ => 0 .. 0
+                }
+                _ => 0..0,
             };
-        };
+        }
     }
 }
 
 fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<Mp4parseIndice>> {
     let timescale = match track.timescale {
         Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
-        _ => TrackTimeScale::<i64>(0, 0),
+        _ => return None,
     };
 
-    let (stsc, stco, stsz, stts) =
-        match (&track.stsc, &track.stco, &track.stsz, &track.stts) {
-            (&Some(ref a), &Some(ref b), &Some(ref c), &Some(ref d)) => (a, b, c, d),
-            _ => return None,
-        };
+    let (stsc, stco, stsz, stts) = match (&track.stsc, &track.stco, &track.stsz, &track.stts) {
+        (&Some(ref a), &Some(ref b), &Some(ref c), &Some(ref d)) => (a, b, c, d),
+        _ => return None,
+    };
 
     // According to spec, no sync table means every sample is sync sample.
     let has_sync_table = match track.stss {
         Some(_) => true,
         _ => false,
     };
 
     let mut sample_table = Vec::new();
     let mut sample_size_iter = stsz.sample_sizes.iter();
 
     // Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
     // offset address.
     let stsc_iter = SampleToChunkIterator {
-        chunks: (0 .. 0),
+        chunks: (0..0),
         sample_count: 0,
         stsc_peek_iter: stsc.samples.as_slice().iter().peekable(),
         remain_chunk_count: stco.offsets.len() as u32,
     };
 
     for i in stsc_iter {
         let chunk_id = i.0 as usize;
         let sample_counts = i.1;
         let mut cur_position = match stco.offsets.get(chunk_id) {
             Some(&i) => i,
             _ => return None,
         };
-        for _ in 0 .. sample_counts {
+        for _ in 0..sample_counts {
             let start_offset = cur_position;
             let end_offset = match (stsz.sample_size, sample_size_iter.next()) {
                 (_, Some(t)) => start_offset + u64::from(*t),
                 (t, _) if t > 0 => start_offset + u64::from(t),
                 _ => 0,
             };
             if end_offset == 0 {
                 return None;
             }
             cur_position = end_offset;
 
-            let res = vec_push(&mut sample_table, Mp4parseIndice {
-                start_offset,
-                end_offset,
-                start_composition: 0,
-                end_composition: 0,
-                start_decode: 0,
-                sync: !has_sync_table,
-            });
+            let res = vec_push(
+                &mut sample_table,
+                Mp4parseIndice {
+                    start_offset,
+                    end_offset,
+                    start_composition: 0,
+                    end_composition: 0,
+                    start_decode: 0,
+                    sync: !has_sync_table,
+                },
+            );
             if res.is_err() {
                 return None;
             }
         }
     }
 
     // Mark the sync sample in sample_table according to 'stss'.
     if let Some(ref v) = track.stss {
         for iter in &v.samples {
-            match iter.checked_sub(1).and_then(|idx| { sample_table.get_mut(idx as usize) }) {
+            match iter
+                .checked_sub(1)
+                .and_then(|idx| sample_table.get_mut(idx as usize))
+            {
                 Some(elem) => elem.sync = true,
                 _ => return None,
             }
         }
     }
 
     let ctts_iter = match track.ctts {
         Some(ref v) => Some(v.samples.as_slice().iter()),
         _ => None,
     };
 
     let mut ctts_offset_iter = TimeOffsetIterator {
-        cur_sample_range: (0 .. 0),
+        cur_sample_range: (0..0),
         cur_offset: 0,
         ctts_iter,
         track_id: track.id,
     };
 
     let mut stts_iter = TimeToSampleIterator {
-        cur_sample_count: (0 .. 0),
+        cur_sample_count: (0..0),
         cur_sample_delta: 0,
         stts_iter: stts.samples.as_slice().iter(),
         track_id: track.id,
     };
 
     // sum_delta is the sum of stts_iter delta.
     // According to sepc:
     //      decode time => DT(n) = DT(n-1) + STTS(n)
@@ -1225,45 +1391,41 @@ fn create_sample_table(track: &Track, tr
 
         let start_decode = track_time_to_us(decode_time, timescale);
 
         match (start_composition, end_composition, start_decode) {
             (Some(s_c), Some(e_c), Some(s_d)) => {
                 sample.start_composition = s_c + track_offset_time;
                 sample.end_composition = e_c + track_offset_time;
                 sample.start_decode = s_d;
-            },
+            }
             _ => return None,
         }
     }
 
     // Correct composition end time due to 'ctts' causes composition time re-ordering.
     //
     // Composition end time is not in specification. However, gecko needs it, so we need to
     // calculate to correct the composition end time.
     if !sample_table.is_empty() {
         // Create an index table refers to sample_table and sorted by start_composisiton time.
         let mut sort_table = Vec::new();
-        for i in 0 .. sample_table.len() {
+        for i in 0..sample_table.len() {
             if vec_push(&mut sort_table, i).is_err() {
                 return None;
             }
         }
 
-        sort_table.sort_by_key(|i| {
-            match sample_table.get(*i) {
-                Some(v) => {
-                    v.start_composition
-                },
-                _ => 0,
-            }
+        sort_table.sort_by_key(|i| match sample_table.get(*i) {
+            Some(v) => v.start_composition,
+            _ => 0,
         });
 
         let iter = sort_table.iter();
-        for i in 0 .. (iter.len() - 1) {
+        for i in 0..(iter.len() - 1) {
             let current_index = sort_table[i];
             let peek_index = sort_table[i + 1];
             let next_start_composition_time = sample_table[peek_index].start_composition;
             let sample = &mut sample_table[current_index];
             sample.end_composition = next_start_composition_time;
         }
     }
 
@@ -1275,18 +1437,21 @@ fn create_sample_table(track: &Track, tr
 /// # Safety
 ///
 /// This function is unsafe because it dereferences the the parser and
 /// info raw pointers passed to it. Callers should ensure the parser
 /// pointer points to a valid `Mp4parseParser` and that the info pointer points
 /// to a valid `Mp4parseFragmentInfo`.
 
 #[no_mangle]
-pub unsafe extern fn mp4parse_get_fragment_info(parser: *mut Mp4parseParser, info: *mut Mp4parseFragmentInfo) -> Mp4parseStatus {
-    if parser.is_null() || info.is_null() || (*parser).poisoned() {
+pub unsafe extern "C" fn mp4parse_get_fragment_info(
+    parser: *mut Mp4parseParser,
+    info: *mut Mp4parseFragmentInfo,
+) -> Mp4parseStatus {
+    if parser.is_null() || info.is_null() {
         return Mp4parseStatus::BadArg;
     }
 
     // Initialize fields to default values to ensure all fields are always valid.
     *info = Default::default();
 
     let context = (*parser).context();
     let info: &mut Mp4parseFragmentInfo = &mut *info;
@@ -1313,39 +1478,49 @@ pub unsafe extern fn mp4parse_get_fragme
 ///
 /// # Safety
 ///
 /// This function is unsafe because it dereferences the the parser and
 /// fragmented raw pointers passed to it. Callers should ensure the parser
 /// pointer points to a valid `Mp4parseParser` and that the fragmented pointer
 /// points to an appropriate memory location to have a `u8` written to.
 #[no_mangle]
-pub unsafe extern fn mp4parse_is_fragmented(parser: *mut Mp4parseParser, track_id: u32, fragmented: *mut u8) -> Mp4parseStatus {
-    if parser.is_null() || (*parser).poisoned() {
+pub unsafe extern "C" fn mp4parse_is_fragmented(
+    parser: *mut Mp4parseParser,
+    track_id: u32,
+    fragmented: *mut u8,
+) -> Mp4parseStatus {
+    if parser.is_null() {
         return Mp4parseStatus::BadArg;
     }
 
     let context = (*parser).context_mut();
     let tracks = &context.tracks;
     (*fragmented) = false as u8;
 
     if context.mvex.is_none() {
         return Mp4parseStatus::Ok;
     }
 
     // check sample tables.
     let mut iter = tracks.iter();
-    iter.find(|track| track.track_id == Some(track_id)).map_or(Mp4parseStatus::BadArg, |track| {
-        match (&track.stsc, &track.stco, &track.stts) {
-            (&Some(ref stsc), &Some(ref stco), &Some(ref stts))
-                if stsc.samples.is_empty() && stco.offsets.is_empty() && stts.samples.is_empty() => (*fragmented) = true as u8,
-            _ => {},
-        };
-        Mp4parseStatus::Ok
-    })
+    iter.find(|track| track.track_id == Some(track_id))
+        .map_or(Mp4parseStatus::BadArg, |track| {
+            match (&track.stsc, &track.stco, &track.stts) {
+                (&Some(ref stsc), &Some(ref stco), &Some(ref stts))
+                    if stsc.samples.is_empty()
+                        && stco.offsets.is_empty()
+                        && stts.samples.is_empty() =>
+                {
+                    (*fragmented) = true as u8
+                }
+                _ => {}
+            };
+            Mp4parseStatus::Ok
+        })
 }
 
 /// Get 'pssh' system id and 'pssh' box content for eme playback.
 ///
 /// The data format of the `info` struct passed to gecko is:
 ///
 /// - system id (16 byte uuid)
 /// - pssh box size (32-bit native endian)
@@ -1353,18 +1528,21 @@ pub unsafe extern fn mp4parse_is_fragmen
 ///
 /// # Safety
 ///
 /// This function is unsafe because it dereferences the the parser and
 /// info raw pointers passed to it. Callers should ensure the parser
 /// pointer points to a valid `Mp4parseParser` and that the fragmented pointer
 /// points to a valid `Mp4parsePsshInfo`.
 #[no_mangle]
-pub unsafe extern fn mp4parse_get_pssh_info(parser: *mut Mp4parseParser, info: *mut Mp4parsePsshInfo) -> Mp4parseStatus {
-    if parser.is_null() || info.is_null() || (*parser).poisoned() {
+pub unsafe extern "C" fn mp4parse_get_pssh_info(
+    parser: *mut Mp4parseParser,
+    info: *mut Mp4parsePsshInfo,
+) -> Mp4parseStatus {
+    if parser.is_null() || info.is_null() {
         return Mp4parseStatus::BadArg;
     }
 
     // Initialize fields to default values to ensure all fields are always valid.
     *info = Default::default();
 
     let context = (*parser).context_mut();
     let pssh_data = (*parser).pssh_data_mut();
@@ -1372,291 +1550,373 @@ pub unsafe extern fn mp4parse_get_pssh_i
 
     pssh_data.clear();
     for pssh in &context.psshs {
         let content_len = pssh.box_content.len();
         if content_len > std::u32::MAX as usize {
             return Mp4parseStatus::Invalid;
         }
         let mut data_len = Vec::new();
-        if data_len.write_u32::<byteorder::NativeEndian>(content_len as u32).is_err() {
+        if data_len
+            .write_u32::<byteorder::NativeEndian>(content_len as u32)
+            .is_err()
+        {
             return Mp4parseStatus::Io;
         }
         pssh_data.extend_from_slice(pssh.system_id.as_slice());
         pssh_data.extend_from_slice(data_len.as_slice());
-        pssh_data.extend_from_slice(pssh.box_content.as_slice());
+        // The previous two calls have known, small sizes, but pssh_data has
+        // arbitrary size based on untrusted input, so use fallible allocation
+        let res = extend_from_slice(pssh_data, pssh.box_content.as_slice());
+
+        if res.is_err() {
+            return Mp4parseStatus::Oom;
+        }
     }
 
     info.data.set_data(pssh_data);
 
     Mp4parseStatus::Ok
 }
 
 #[cfg(test)]
-extern fn panic_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
-    panic!("panic_read shouldn't be called in these tests");
-}
-
-#[cfg(test)]
-extern fn error_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
+extern "C" fn error_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
     -1
 }
 
 #[cfg(test)]
-extern fn valid_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
+extern "C" fn valid_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
     let input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
 
     let mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
     match input.read(&mut buf) {
         Ok(n) => n as isize,
         Err(_) => -1,
     }
 }
 
 #[test]
-fn new_parser() {
-    let mut dummy_value: u32 = 42;
-    let io = Mp4parseIo {
-        read: Some(panic_read),
-        userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
-    };
-    unsafe {
-        let parser = mp4parse_new(&io);
-        assert!(!parser.is_null());
-        mp4parse_free(parser);
-    }
-}
-
-#[test]
 fn get_track_count_null_parser() {
     unsafe {
         let mut count: u32 = 0;
         let rv = mp4parse_get_track_count(std::ptr::null(), std::ptr::null_mut());
         assert_eq!(rv, Mp4parseStatus::BadArg);
         let rv = mp4parse_get_track_count(std::ptr::null(), &mut count);
         assert_eq!(rv, Mp4parseStatus::BadArg);
     }
 }
 
 #[test]
 fn arg_validation() {
     unsafe {
+        let rv = mp4parse_new(std::ptr::null(), std::ptr::null_mut());
+        assert_eq!(rv, Mp4parseStatus::BadArg);
+
         // Passing a null Mp4parseIo is an error.
-        let parser = mp4parse_new(std::ptr::null());
+        let mut parser = std::ptr::null_mut();
+        let rv = mp4parse_new(std::ptr::null(), &mut parser);
+        assert_eq!(rv, Mp4parseStatus::BadArg);
         assert!(parser.is_null());
 
         let null_mut: *mut std::os::raw::c_void = std::ptr::null_mut();
 
         // Passing an Mp4parseIo with null members is an error.
-        let io = Mp4parseIo { read: None,
-                               userdata: null_mut };
-        let parser = mp4parse_new(&io);
-        assert!(parser.is_null());
-
-        let io = Mp4parseIo { read: Some(panic_read),
-                               userdata: null_mut };
-        let parser = mp4parse_new(&io);
+        let io = Mp4parseIo {
+            read: None,
+            userdata: null_mut,
+        };
+        let mut parser = std::ptr::null_mut();
+        let rv = mp4parse_new(&io, &mut parser);
+        assert_eq!(rv, Mp4parseStatus::BadArg);
         assert!(parser.is_null());
 
         let mut dummy_value = 42;
         let io = Mp4parseIo {
             read: None,
             userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
         };
-        let parser = mp4parse_new(&io);
+        let mut parser = std::ptr::null_mut();
+        let rv = mp4parse_new(&io, &mut parser);
+        assert_eq!(rv, Mp4parseStatus::BadArg);
         assert!(parser.is_null());
 
-        // Passing a null Mp4parseParser is an error.
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_read(std::ptr::null_mut()));
-
         let mut dummy_info = Mp4parseTrackInfo {
             track_type: Mp4parseTrackType::Video,
             track_id: 0,
             duration: 0,
             media_time: 0,
         };
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_info(std::ptr::null_mut(), 0, &mut dummy_info));
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_info(std::ptr::null_mut(), 0, &mut dummy_info)
+        );
 
         let mut dummy_video = Mp4parseTrackVideoInfo {
             display_width: 0,
             display_height: 0,
             rotation: 0,
             sample_info_count: 0,
             sample_info: std::ptr::null(),
         };
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_video_info(std::ptr::null_mut(), 0, &mut dummy_video));
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_video_info(std::ptr::null_mut(), 0, &mut dummy_video)
+        );
 
         let mut dummy_audio = Default::default();
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_audio_info(std::ptr::null_mut(), 0, &mut dummy_audio));
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_audio_info(std::ptr::null_mut(), 0, &mut dummy_audio)
+        );
     }
 }
 
 #[test]
+fn parser_input_must_be_null() {
+    let mut dummy_value = 42;
+    let io = Mp4parseIo {
+        read: Some(error_read),
+        userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
+    };
+    let mut parser = 0xDEADBEEF as *mut _;
+    let rv = unsafe { mp4parse_new(&io, &mut parser) };
+    assert_eq!(rv, Mp4parseStatus::BadArg);
+}
+
+#[test]
 fn arg_validation_with_parser() {
     unsafe {
         let mut dummy_value = 42;
         let io = Mp4parseIo {
             read: Some(error_read),
             userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
         };
-        let parser = mp4parse_new(&io);
-        assert!(!parser.is_null());
-
-        // Our Mp4parseIo read should simply fail with an error.
-        assert_eq!(Mp4parseStatus::Io, mp4parse_read(parser));
-
-        // The parser is now poisoned and unusable.
-        assert_eq!(Mp4parseStatus::BadArg,  mp4parse_read(parser));
+        let mut parser = std::ptr::null_mut();
+        let rv = mp4parse_new(&io, &mut parser);
+        assert_eq!(rv, Mp4parseStatus::Io);
+        assert!(parser.is_null());
 
         // Null info pointers are an error.
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_info(parser, 0, std::ptr::null_mut()));
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_video_info(parser, 0, std::ptr::null_mut()));
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_audio_info(parser, 0, std::ptr::null_mut()));
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_info(parser, 0, std::ptr::null_mut())
+        );
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_video_info(parser, 0, std::ptr::null_mut())
+        );
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_audio_info(parser, 0, std::ptr::null_mut())
+        );
 
         let mut dummy_info = Mp4parseTrackInfo {
             track_type: Mp4parseTrackType::Video,
             track_id: 0,
             duration: 0,
             media_time: 0,
         };
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_info(parser, 0, &mut dummy_info));
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_info(parser, 0, &mut dummy_info)
+        );
 
         let mut dummy_video = Mp4parseTrackVideoInfo {
             display_width: 0,
             display_height: 0,
             rotation: 0,
             sample_info_count: 0,
             sample_info: std::ptr::null(),
         };
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_video_info(parser, 0, &mut dummy_video));
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_video_info(parser, 0, &mut dummy_video)
+        );
 
         let mut dummy_audio = Default::default();
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_audio_info(parser, 0, &mut dummy_audio));
+        assert_eq!(
+            Mp4parseStatus::BadArg,
+            mp4parse_get_track_audio_info(parser, 0, &mut dummy_audio)
+        );
+    }
+}
 
+#[cfg(test)]
+fn parse_minimal_mp4() -> *mut Mp4parseParser {
+    let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
+    let io = Mp4parseIo {
+        read: Some(valid_read),
+        userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
+    };
+    let mut parser = std::ptr::null_mut();
+    let rv = unsafe { mp4parse_new(&io, &mut parser) };
+    assert_eq!(Mp4parseStatus::Ok, rv);
+    parser
+}
+
+#[test]
+fn minimal_mp4_parse_ok() {
+    let parser = parse_minimal_mp4();
+
+    assert!(!parser.is_null());
+
+    unsafe {
         mp4parse_free(parser);
     }
 }
 
 #[test]
-fn get_track_count_poisoned_parser() {
+fn minimal_mp4_get_track_cout() {
+    let parser = parse_minimal_mp4();
+
+    let mut count: u32 = 0;
+    assert_eq!(Mp4parseStatus::Ok, unsafe {
+        mp4parse_get_track_count(parser, &mut count)
+    });
+    assert_eq!(2, count);
+
     unsafe {
-        let mut dummy_value = 42;
-        let io = Mp4parseIo {
-            read: Some(error_read),
-            userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
-        };
-        let parser = mp4parse_new(&io);
-        assert!(!parser.is_null());
-
-        // Our Mp4parseIo read should simply fail with an error.
-        assert_eq!(Mp4parseStatus::Io, mp4parse_read(parser));
-
-        let mut count: u32 = 0;
-        let rv = mp4parse_get_track_count(parser, &mut count);
-        assert_eq!(rv, Mp4parseStatus::BadArg);
-
         mp4parse_free(parser);
     }
 }
 
 #[test]
-#[allow(clippy::cognitive_complexity)] // TODO: Consider simplifying this
-fn arg_validation_with_data() {
-    unsafe {
-        let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
-        let io = Mp4parseIo { read: Some(valid_read),
-                               userdata: &mut file as *mut _ as *mut std::os::raw::c_void };
-        let parser = mp4parse_new(&io);
-        assert!(!parser.is_null());
+fn minimal_mp4_get_track_info() {
+    let parser = parse_minimal_mp4();
 
-        assert_eq!(Mp4parseStatus::Ok, mp4parse_read(parser));
-
-        let mut count: u32 = 0;
-        assert_eq!(Mp4parseStatus::Ok, mp4parse_get_track_count(parser, &mut count));
-        assert_eq!(2, count);
+    let mut info = Mp4parseTrackInfo {
+        track_type: Mp4parseTrackType::Video,
+        track_id: 0,
+        duration: 0,
+        media_time: 0,
+    };
+    assert_eq!(Mp4parseStatus::Ok, unsafe {
+        mp4parse_get_track_info(parser, 0, &mut info)
+    });
+    assert_eq!(info.track_type, Mp4parseTrackType::Video);
+    assert_eq!(info.track_id, 1);
+    assert_eq!(info.duration, 40000);
+    assert_eq!(info.media_time, 0);
 
-        let mut info = Mp4parseTrackInfo {
-            track_type: Mp4parseTrackType::Video,
-            track_id: 0,
-            duration: 0,
-            media_time: 0,
-        };
-        assert_eq!(Mp4parseStatus::Ok, mp4parse_get_track_info(parser, 0, &mut info));
-        assert_eq!(info.track_type, Mp4parseTrackType::Video);
-        assert_eq!(info.track_id, 1);
-        assert_eq!(info.duration, 40000);
-        assert_eq!(info.media_time, 0);
+    assert_eq!(Mp4parseStatus::Ok, unsafe {
+        mp4parse_get_track_info(parser, 1, &mut info)
+    });
+    assert_eq!(info.track_type, Mp4parseTrackType::Audio);
+    assert_eq!(info.track_id, 2);
+    assert_eq!(info.duration, 61333);
+    assert_eq!(info.media_time, 21333);
+
+    unsafe {
+        mp4parse_free(parser);
+    }
+}
 
-        assert_eq!(Mp4parseStatus::Ok, mp4parse_get_track_info(parser, 1, &mut info));
-        assert_eq!(info.track_type, Mp4parseTrackType::Audio);
-        assert_eq!(info.track_id, 2);
-        assert_eq!(info.duration, 61333);
-        assert_eq!(info.media_time, 21333);
+#[test]
+fn minimal_mp4_get_track_video_info() {
+    let parser = parse_minimal_mp4();
 
-        let mut video = Mp4parseTrackVideoInfo::default();
-        assert_eq!(Mp4parseStatus::Ok, mp4parse_get_track_video_info(parser, 0, &mut video));
-        assert_eq!(video.display_width, 320);
-        assert_eq!(video.display_height, 240);
-        assert_eq!(video.sample_info_count, 1);
+    let mut video = Mp4parseTrackVideoInfo::default();
+    assert_eq!(Mp4parseStatus::Ok, unsafe {
+        mp4parse_get_track_video_info(parser, 0, &mut video)
+    });
+    assert_eq!(video.display_width, 320);
+    assert_eq!(video.display_height, 240);
+    assert_eq!(video.sample_info_count, 1);
 
+    unsafe {
         assert_eq!((*video.sample_info).image_width, 320);
         assert_eq!((*video.sample_info).image_height, 240);
+    }
 
-        let mut audio = Mp4parseTrackAudioInfo::default();
-        assert_eq!(Mp4parseStatus::Ok, mp4parse_get_track_audio_info(parser, 1, &mut audio));
-        assert_eq!(audio.sample_info_count, 1);
+    unsafe {
+        mp4parse_free(parser);
+    }
+}
 
+#[test]
+fn minimal_mp4_get_track_audio_info() {
+    let parser = parse_minimal_mp4();
+
+    let mut audio = Mp4parseTrackAudioInfo::default();
+    assert_eq!(Mp4parseStatus::Ok, unsafe {
+        mp4parse_get_track_audio_info(parser, 1, &mut audio)
+    });
+    assert_eq!(audio.sample_info_count, 1);
+
+    unsafe {
         assert_eq!((*audio.sample_info).channels, 1);
         assert_eq!((*audio.sample_info).bit_depth, 16);
         assert_eq!((*audio.sample_info).sample_rate, 48000);
+    }
 
-        // Test with an invalid track number.
-        let mut info = Mp4parseTrackInfo {
-            track_type: Mp4parseTrackType::Video,
-            track_id: 0,
-            duration: 0,
-            media_time: 0,
-        };
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_info(parser, 3, &mut info));
-        assert_eq!(info.track_type, Mp4parseTrackType::Video);
-        assert_eq!(info.track_id, 0);
-        assert_eq!(info.duration, 0);
-        assert_eq!(info.media_time, 0);
+    unsafe {
+        mp4parse_free(parser);
+    }
+}
+
+#[test]
+fn minimal_mp4_get_track_info_invalid_track_number() {
+    let parser = parse_minimal_mp4();
 
-        let mut video = Mp4parseTrackVideoInfo::default();
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_video_info(parser, 3, &mut video));
-        assert_eq!(video.display_width, 0);
-        assert_eq!(video.display_height, 0);
-        assert_eq!(video.sample_info_count, 0);
+    let mut info = Mp4parseTrackInfo {
+        track_type: Mp4parseTrackType::Video,
+        track_id: 0,
+        duration: 0,
+        media_time: 0,
+    };
+    assert_eq!(Mp4parseStatus::BadArg, unsafe {
+        mp4parse_get_track_info(parser, 3, &mut info)
+    });
+    assert_eq!(info.track_type, Mp4parseTrackType::Video);
+    assert_eq!(info.track_id, 0);
+    assert_eq!(info.duration, 0);
+    assert_eq!(info.media_time, 0);
 
-        let mut audio = Default::default();
-        assert_eq!(Mp4parseStatus::BadArg, mp4parse_get_track_audio_info(parser, 3, &mut audio));
-        assert_eq!(audio.sample_info_count, 0);
+    let mut video = Mp4parseTrackVideoInfo::default();
+    assert_eq!(Mp4parseStatus::BadArg, unsafe {
+        mp4parse_get_track_video_info(parser, 3, &mut video)
+    });
+    assert_eq!(video.display_width, 0);
+    assert_eq!(video.display_height, 0);
+    assert_eq!(video.sample_info_count, 0);
 
+    let mut audio = Default::default();
+    assert_eq!(Mp4parseStatus::BadArg, unsafe {
+        mp4parse_get_track_audio_info(parser, 3, &mut audio)
+    });
+    assert_eq!(audio.sample_info_count, 0);
+
+    unsafe {
         mp4parse_free(parser);
     }
 }
 
 #[test]
 fn rational_scale_overflow() {
     assert_eq!(rational_scale::<u64, u64>(17, 3, 1000), Some(5666));
     let large = 0x4000_0000_0000_0000;
     assert_eq!(rational_scale::<u64, u64>(large, 2, 2), Some(large));
     assert_eq!(rational_scale::<u64, u64>(large, 4, 4), Some(large));
     assert_eq!(rational_scale::<u64, u64>(large, 2, 8), None);
-    assert_eq!(rational_scale::<u64, u64>(large, 8, 4), Some(large/2));
-    assert_eq!(rational_scale::<u64, u64>(large + 1, 4, 4), Some(large+1));
+    assert_eq!(rational_scale::<u64, u64>(large, 8, 4), Some(large / 2));
+    assert_eq!(rational_scale::<u64, u64>(large + 1, 4, 4), Some(large + 1));
     assert_eq!(rational_scale::<u64, u64>(large, 40, 1000), None);
 }
 
 #[test]
 fn media_time_overflow() {
-  let scale = MediaTimeScale(90000);
-  let duration = MediaScaledTime(9_007_199_254_710_000);
-  assert_eq!(media_time_to_us(duration, scale), Some(100_079_991_719_000_000));
+    let scale = MediaTimeScale(90000);
+    let duration = MediaScaledTime(9_007_199_254_710_000);
+    assert_eq!(
+        media_time_to_us(duration, scale),
+        Some(100_079_991_719_000_000)
+    );
 }
 
 #[test]
 fn track_time_overflow() {
-  let scale = TrackTimeScale(44100u64, 0);
-  let duration = TrackScaledTime(4_413_527_634_807_900u64, 0);
-  assert_eq!(track_time_to_us(duration, scale), Some(100_079_991_719_000_000));
+    let scale = TrackTimeScale(44100u64, 0);
+    let duration = TrackScaledTime(4_413_527_634_807_900u64, 0);
+    assert_eq!(
+        track_time_to_us(duration, scale),
+        Some(100_079_991_719_000_000)
+    );
 }
deleted file mode 100644
--- a/media/mp4parse-rust/mp4parse_fallible/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "mp4parse_fallible"
-version = "0.0.1"
-authors = ["The Servo Project Developers"]
-license = "MPL-2.0"
-publish = false
-
-[lib]
-name = "mp4parse_fallible"
-path = "lib.rs"
deleted file mode 100644
--- a/media/mp4parse-rust/mp4parse_fallible/README
+++ /dev/null
@@ -1,7 +0,0 @@
-This is from https://github.com/servo/servo/tree/master/components/fallible
-with modificaion for mp4 demuxer.
-
-The purpose of this crate is to solve infallible memory allocation problem
-which causes OOM easily on win32. This is more like a temporary solution.
-Once rust supports fallible memory allocation in its stdlib, this can be
-retired.
deleted file mode 100644
--- a/media/mp4parse-rust/mp4parse_fallible/lib.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use std::mem;
-use std::vec::Vec;
-
-extern "C" {
-    fn realloc(ptr: *mut u8, bytes: usize) -> *mut u8;
-    fn malloc(bytes: usize) -> *mut u8;
-}
-
-pub trait FallibleVec<T> {
-    /// Append |val| to the end of |vec|.  Returns Ok(()) on success,
-    /// Err(()) if it fails, which can only be due to lack of memory.
-    fn try_push(&mut self, value: T) -> Result<(), ()>;
-
-    /// Expand the vector size. Return Ok(()) on success, Err(()) if it
-    /// fails.
-    fn try_reserve(&mut self, new_cap: usize) -> Result<(), ()>;
-}
-
-/////////////////////////////////////////////////////////////////
-// Vec
-
-impl<T> FallibleVec<T> for Vec<T> {
-    #[inline]
-    fn try_push(&mut self, val: T) -> Result<(), ()> {
-        if self.capacity() == self.len() {
-            let old_cap: usize = self.capacity();
-            let new_cap: usize
-                = if old_cap == 0 { 4 } else { old_cap.checked_mul(2).ok_or(()) ? };
-
-            try_extend_vec(self, new_cap)?;
-            debug_assert!(self.capacity() > self.len());
-        }
-        self.push(val);
-        Ok(())
-    }
-
-    #[inline]
-    fn try_reserve(&mut self, cap: usize) -> Result<(), ()> {
-        let new_cap = cap + self.capacity();
-        try_extend_vec(self, new_cap)?;
-        debug_assert!(self.capacity() == new_cap);
-        Ok(())
-    }
-}
-
-#[inline(never)]
-#[cold]
-fn try_extend_vec<T>(vec: &mut Vec<T>, new_cap: usize) -> Result<(), ()> {
-    let old_ptr = vec.as_mut_ptr();
-    let old_len = vec.len();
-
-    let old_cap: usize = vec.capacity();
-
-    if old_cap >= new_cap {
-        return Ok(());
-    }
-
-    let new_size_bytes
-        = new_cap.checked_mul(mem::size_of::<T>()).ok_or(()) ? ;
-
-    let new_ptr = unsafe {
-        if old_cap == 0 {
-            malloc(new_size_bytes)
-        } else {
-            realloc(old_ptr as *mut u8, new_size_bytes)
-        }
-    };
-
-    if new_ptr.is_null() {
-        return Err(());
-    }
-
-    let new_vec = unsafe {
-        Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap)
-    };
-
-    mem::forget(mem::replace(vec, new_vec));
-    Ok(())
-}
-
-#[test]
-fn oom_test() {
-    let mut vec: Vec<char> = Vec::new();
-    match vec.try_reserve(std::usize::MAX) {
-        Ok(_) => panic!("it should be OOM"),
-        _ => (),
-    }
-}
--- a/media/mp4parse-rust/update-rust.sh
+++ b/media/mp4parse-rust/update-rust.sh
@@ -1,25 +1,25 @@
 #!/bin/bash
 # Script to update mp4parse-rust sources to latest upstream
 
 set -e
 
 # Default version.
-VER="3e0f34a2eb53c6d892b5061f76c8290e5d39e920"
+VER="63ca8c6bde27b39dea87fb15e2922a23cb38c8df"
 
 # Accept version or commit from the command line.
 if test -n "$1"; then
   VER=$1
 fi
 
 echo "Fetching sources..."
 rm -rf _upstream
-git clone https://github.com/mozilla/mp4parse-rust _upstream/mp4parse
-git clone https://github.com/alfredoyang/mp4parse_fallible _upstream/mp4parse_fallible
+git clone --recurse-submodules https://github.com/mozilla/mp4parse-rust _upstream/mp4parse
+
 pushd _upstream/mp4parse
 git checkout ${VER}
 echo "Verifying sources..."
 cargo test
 popd
 rm -rf mp4parse
 mkdir -p mp4parse/src
 cp _upstream/mp4parse/mp4parse/Cargo.toml mp4parse/
@@ -27,21 +27,17 @@ cp _upstream/mp4parse/mp4parse/src/*.rs 
 mkdir -p mp4parse/tests
 cp _upstream/mp4parse/mp4parse/tests/*.rs mp4parse/tests/
 cp _upstream/mp4parse/mp4parse/tests/*.mp4 mp4parse/tests/
 # Remove everything but the cbindgen.toml, since it's needed to configure the
 # creation of the bindings as part of moz.build
 find mp4parse_capi -not -name cbindgen.toml -delete
 mkdir -p mp4parse_capi/src
 cp _upstream/mp4parse/mp4parse_capi/Cargo.toml mp4parse_capi/
-cp _upstream/mp4parse/mp4parse_capi/build.rs mp4parse_capi/
 cp _upstream/mp4parse/mp4parse_capi/src/*.rs mp4parse_capi/src/
-rm -rf mp4parse_fallible
-mkdir -p mp4parse_fallible
-cp _upstream/mp4parse_fallible/* mp4parse_fallible/
 
 echo "Applying patches..."
 patch -p3 < mp4parse-cargo.patch
 
 echo "Cleaning up..."
 rm -rf _upstream
 
 echo "Updating gecko Cargo.lock..."
--- a/third_party/rust/bitreader/.cargo-checksum.json
+++ b/third_party/rust/bitreader/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"4ea2fe4a12740a572f459cc5c51ca721b1a7b256a0976be561c9b0a9fce0dcc7","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"8583712ee2b062ff3d4d6d3e16f19ff0f92bc3a0a4beeec11a81ef00146fbd4f","README.md":"a8bfdd9509bb3bb30b30bbe308a717e9827cf97d7a97e5fb5cd69bdd3c88a490","src/lib.rs":"a7ed9d2607f47b7d5d11ccaccf23486a21d072435231d09f4548ad0c4ad62f5b","src/tests.rs":"c4e99780432b3ad05f625961699da72239a975f838cb0ab1cf2501424baed38c"},"package":"80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"}
\ No newline at end of file
+{"files":{"Cargo.toml":"27cfa3fe44cc78bce30786d727dedef7967e399c0cdec1282e8dafc9c38a6c10","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"8583712ee2b062ff3d4d6d3e16f19ff0f92bc3a0a4beeec11a81ef00146fbd4f","README.md":"28986de2e8d457e76ae3303d80094697e6ef4ad8da06a4a3178bb1b52bff63d5","src/lib.rs":"6947e329a2f20dca35ea14b6f483c23b4812ae55b6851a276355c31fb7dd65e9","src/tests.rs":"b3ed3ae22daa348dc786219b6e2c4f2b1d3ba35d7d4401ea05f773773fdf8807"},"package":"5fa7f0adf37cd5472c978a1ff4be89c1880a923d10df4cfef6a10855a666e09b"}
\ No newline at end of file
--- a/third_party/rust/bitreader/Cargo.toml
+++ b/third_party/rust/bitreader/Cargo.toml
@@ -1,19 +1,28 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
 [package]
 name = "bitreader"
-version = "0.3.0"
+version = "0.3.2"
 authors = ["Ilkka Rauta <ilkka.rauta@gmail.com>"]
-
-description = """
-BitReader helps reading individual bits from a slice of bytes.
+description = "BitReader helps reading individual bits from a slice of bytes.\n\nYou can read \"unusual\" numbers of bits from the byte slice, for example 13 bits\nat once. The reader internally keeps track of position within the buffer.\n"
+homepage = "https://github.com/irauta/bitreader"
+documentation = "https://docs.rs/bitreader"
+keywords = ["bit", "bits", "bitstream"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/irauta/bitreader"
+[dependencies.cfg-if]
+version = "0.1.9"
 
-You can read "unusual" numbers of bits from the byte slice, for example 13 bits
-at once. The reader internally keeps track of position within the buffer.
-"""
-
-documentation = "https://docs.rs/bitreader"
-homepage = "https://github.com/irauta/bitreader"
-repository = "https://github.com/irauta/bitreader"
-
-keywords = ["bit", "bits", "bitstream"]
-
-license = "MIT OR Apache-2.0"
+[features]
+default = ["std"]
+std = []
--- a/third_party/rust/bitreader/README.md
+++ b/third_party/rust/bitreader/README.md
@@ -15,13 +15,13 @@ Here is how you read first a single bit,
 
     // You obviously should use try! or some other error handling mechanism here
     let a_single_bit = reader.read_u8(1).unwrap(); // 1
     let more_bits = reader.read_u8(3).unwrap(); // 0
     let last_bits_of_byte = reader.read_u8(4).unwrap(); // 0b1111
 
 You can naturally read bits from longer buffer of data than just a single byte.
 
-As you read bits, the internal cursor of BitReader moves on along the stream of bits. Little endian format is assumed when reading the multi-byte values. BitReader supports reading maximum of 64 bits at a time (with read_u64).
+As you read bits, the internal cursor of BitReader moves on along the stream of bits. Big endian format is assumed when reading the multi-byte values. BitReader supports reading maximum of 64 bits at a time (with read_u64).
 
 ## License
 
 Licensed under the Apache License, Version 2.0 or the MIT license, at your option.
--- a/third_party/rust/bitreader/src/lib.rs
+++ b/third_party/rust/bitreader/src/lib.rs
@@ -25,36 +25,45 @@
 //! let more_bits = reader.read_u8(3).unwrap();
 //! assert_eq!(more_bits, 0);
 //!
 //! let last_bits_of_byte = reader.read_u8(4).unwrap();
 //! assert_eq!(last_bits_of_byte, 0b1111);
 //! ```
 //! You can naturally read bits from longer buffer of data than just a single byte.
 //!
-//! As you read bits, the internal cursor of BitReader moves on along the stream of bits. Little
+//! As you read bits, the internal cursor of BitReader moves on along the stream of bits. Big
 //! endian format is assumed when reading the multi-byte values. BitReader supports reading maximum
 //! of 64 bits at a time (with read_u64). Reading signed values directly is not supported at the
 //! moment.
 //!
 //! The reads do not need to be aligned in any particular way.
 //!
 //! Reading zero bits is a no-op.
 //!
 //! You can also skip over a number of bits, in which case there is no arbitrary small limits like
 //! when reading the values to a variable. However, you can not seek past the end of the slice,
 //! either when reading or when skipping bits.
 //!
 //! Note that the code will likely not work correctly if the slice is longer than 2^61 bytes, but
 //! exceeding that should be pretty unlikely. Let's get back to this when people read exabytes of
 //! information one bit at a time.
-
-use std::fmt;
-use std::error::Error;
-use std::result;
+#![no_std]
+cfg_if::cfg_if!{
+    if #[cfg(feature = "std")] {
+        extern crate std;
+        use std::prelude::v1::*;
+        use std::fmt;
+        use std::error::Error;
+        use std::result;
+    } else {
+        use core::result;
+        use core::fmt;
+    }
+}
 
 #[cfg(test)]
 mod tests;
 
 /// BitReader reads data from a byte slice at the granularity of a single bit.
 pub struct BitReader<'a> {
     bytes: &'a [u8],
     /// Position from the start of the slice, counted as bits instead of bytes
@@ -100,70 +109,89 @@ impl<'a> BitReader<'a> {
             bytes: self.bytes,
             position: self.position,
             relative_offset: self.position,
         }
     }
 
     /// Read at most 8 bits into a u8.
     pub fn read_u8(&mut self, bit_count: u8) -> Result<u8> {
-        let value = try!(self.read_value(bit_count, 8));
+        let value = self.read_value(bit_count, 8)?;
         Ok((value & 0xff) as u8)
     }
 
+    /// Fills the entire `output_bytes` slice. If there aren't enough bits remaining
+    /// after the internal cursor's current position, the cursor won't be moved forward
+    /// and the contents of `output_bytes` won't be modified.
+    pub fn read_u8_slice(&mut self, output_bytes: &mut [u8]) -> Result<()> {
+        let requested = output_bytes.len() as u64 * 8;
+        if requested > self.remaining() {
+            Err(BitReaderError::NotEnoughData {
+                position: self.position,
+                length: (self.bytes.len() * 8) as u64,
+                requested: requested,
+            })
+        } else {
+            for byte in output_bytes.iter_mut() {
+                *byte = self.read_u8(8)?;
+            }
+            Ok(())
+        }
+    }
+
     /// Read at most 16 bits into a u16.
     pub fn read_u16(&mut self, bit_count: u8) -> Result<u16> {
-        let value = try!(self.read_value(bit_count, 16));
+        let value = self.read_value(bit_count, 16)?;
         Ok((value & 0xffff) as u16)
     }
 
     /// Read at most 32 bits into a u32.
     pub fn read_u32(&mut self, bit_count: u8) -> Result<u32> {
-        let value = try!(self.read_value(bit_count, 32));
+        let value = self.read_value(bit_count, 32)?;
         Ok((value & 0xffffffff) as u32)
     }
 
     /// Read at most 64 bits into a u64.
     pub fn read_u64(&mut self, bit_count: u8) -> Result<u64> {
-        let value = try!(self.read_value(bit_count, 64));
+        let value = self.read_value(bit_count, 64)?;
         Ok(value)
     }
 
     /// Read at most 8 bits into a i8.
     /// Assumes the bits are stored in two's complement format.
     pub fn read_i8(&mut self, bit_count: u8) -> Result<i8> {
-        let value = try!(self.read_signed_value(bit_count, 8));
+        let value = self.read_signed_value(bit_count, 8)?;
         Ok((value & 0xff) as i8)
     }
 
     /// Read at most 16 bits into a i16.
     /// Assumes the bits are stored in two's complement format.
     pub fn read_i16(&mut self, bit_count: u8) -> Result<i16> {
-        let value = try!(self.read_signed_value(bit_count, 16));
+        let value = self.read_signed_value(bit_count, 16)?;
         Ok((value & 0xffff) as i16)
     }
 
     /// Read at most 32 bits into a i32.
     /// Assumes the bits are stored in two's complement format.
     pub fn read_i32(&mut self, bit_count: u8) -> Result<i32> {
-        let value = try!(self.read_signed_value(bit_count, 32));
+        let value = self.read_signed_value(bit_count, 32)?;
         Ok((value & 0xffffffff) as i32)
     }
 
     /// Read at most 64 bits into a i64.
     /// Assumes the bits are stored in two's complement format.
     pub fn read_i64(&mut self, bit_count: u8) -> Result<i64> {
-        let value = try!(self.read_signed_value(bit_count, 64));
+        let value = self.read_signed_value(bit_count, 64)?;
         Ok(value)
     }
 
     /// Read a single bit as a boolean value.
     /// Interprets 1 as true and 0 as false.
     pub fn read_bool(&mut self) -> Result<bool> {
-        match try!(self.read_value(1, 1)) {
+        match self.read_value(1, 1)? {
             0 => Ok(false),
             _ => Ok(true),
         }
     }
 
     /// Skip arbitrary number of bits. However, you can skip at most to the end of the byte slice.
     pub fn skip(&mut self, bit_count: u64) -> Result<()> {
         let end_position = self.position + bit_count;
@@ -178,32 +206,38 @@ impl<'a> BitReader<'a> {
         Ok(())
     }
 
     /// Returns the position of the cursor, or how many bits have been read so far.
     pub fn position(&self) -> u64 {
         self.position - self.relative_offset
     }
 
+    /// Returns the number of bits not yet read from the underlying slice.
+    pub fn remaining(&self) -> u64 {
+        let total_bits = self.bytes.len() as u64 * 8;
+        total_bits - self.position
+    }
+
     /// Helper to make sure the "bit cursor" is exactly at the beginning of a byte, or at specific
     /// multi-byte alignment position.
     ///
     /// For example `reader.is_aligned(1)` returns true if exactly n bytes, or n * 8 bits, has been
     /// read. Similarly, `reader.is_aligned(4)` returns true if exactly n * 32 bits, or n 4-byte
     /// sequences has been read.
     ///
     /// This function can be used to validate the data is being read properly, for example by
     /// adding invocations wrapped into `debug_assert!()` to places where it is known the data
     /// should be n-byte aligned.
     pub fn is_aligned(&self, alignment_bytes: u32) -> bool {
         self.position % (alignment_bytes as u64 * 8) == 0
     }
 
     fn read_signed_value(&mut self, bit_count: u8, maximum_count: u8) -> Result<i64> {
-        let unsigned = try!(self.read_value(bit_count, maximum_count));
+        let unsigned = self.read_value(bit_count, maximum_count)?;
         // Fill the bits above the requested bits with all ones or all zeros,
         // depending on the sign bit.
         let sign_bit = unsigned >> (bit_count - 1) & 1;
         let high_bits = if sign_bit == 1 { -1 } else { 0 };
         Ok(high_bits << bit_count | unsigned as i64)
     }
 
     fn read_value(&mut self, bit_count: u8, maximum_count: u8) -> Result<u64> {
@@ -258,16 +292,17 @@ pub enum BitReaderError {
     /// reading into a u8.
     TooManyBitsForType {
         position: u64,
         requested: u8,
         allowed: u8,
     }
 }
 
+#[cfg(feature = "std")]
 impl Error for BitReaderError {
     fn description(&self) -> &str {
         match *self {
             BitReaderError::NotEnoughData {..} => "Requested more bits than the byte slice has left",
             BitReaderError::TooManyBitsForType {..} => "Requested more bits than the requested integer type can hold",
         }
     }
 }
@@ -334,14 +369,14 @@ impl_read_into!(u64, read_u64);
 impl_read_into!(i8, read_i8);
 impl_read_into!(i16, read_i16);
 impl_read_into!(i32, read_i32);
 impl_read_into!(i64, read_i64);
 
 // We can't cast to bool, so this requires a separate method.
 impl ReadInto for bool {
     fn read(reader: &mut BitReader, bits: u8) -> Result<Self> {
-        match try!(reader.read_u8(bits)) {
+        match reader.read_u8(bits)? {
             0 => Ok(false),
             _ => Ok(true),
         }
     }
 }
--- a/third_party/rust/bitreader/src/tests.rs
+++ b/third_party/rust/bitreader/src/tests.rs
@@ -16,24 +16,30 @@ fn read_buffer() {
     ];
 
     let mut reader = BitReader::new(bytes);
 
     assert_eq!(reader.read_u8(1).unwrap(), 0b1);
     assert_eq!(reader.read_u8(1).unwrap(), 0b0);
     assert_eq!(reader.read_u8(2).unwrap(), 0b11);
 
+    assert_eq!(reader.position(), 4);
+    assert_eq!(reader.remaining(), 60);
+
     assert_eq!(reader.read_u8(4).unwrap(), 0b0101);
 
     assert!(reader.is_aligned(1));
 
     assert_eq!(reader.read_u8(3).unwrap(), 0b11);
     assert_eq!(reader.read_u16(10).unwrap(), 0b01_0101_0101);
     assert_eq!(reader.read_u8(3).unwrap(), 0b100);
 
+    assert_eq!(reader.position(), 24);
+    assert_eq!(reader.remaining(), 40);
+
     assert!(reader.is_aligned(1));
 
     assert_eq!(reader.read_u32(32).unwrap(), 0b1001_1001_1001_1001_1001_1001_1001_1001);
 
     assert_eq!(reader.read_u8(4).unwrap(), 0b1110);
     assert_eq!(reader.read_u8(3).unwrap(), 0b011);
     assert_eq!(reader.read_bool().unwrap(), true);
 
@@ -145,8 +151,57 @@ fn boolean_values() {
         assert_eq!(reader.read_bool().unwrap(), false);
         reader.skip(3).unwrap();
         assert_eq!(reader.read_bool().unwrap(), v & 0x08 == 8);
         assert_eq!(reader.read_bool().unwrap(), v & 0x04 == 4);
         assert_eq!(reader.read_bool().unwrap(), v & 0x02 == 2);
         assert_eq!(reader.read_bool().unwrap(), v & 0x01 == 1);
     }
 }
+
+#[test]
+fn read_slice() {
+    let bytes = &[
+        0b1111_0000, 0b0000_1111, 0b1111_0000,
+        0b0000_1000, 0b0000_0100, 0b0000_0011,
+        0b1111_1100, 0b0000_0011, 0b1101_1000,
+    ];
+    let mut reader = BitReader::new(bytes);
+    assert_eq!(reader.read_u8(4).unwrap(), 0b1111);
+    // Just some pattern that's definitely not in the bytes array
+    let mut output = [0b1010_1101; 3];
+    reader.read_u8_slice(&mut output).unwrap();
+    assert_eq!(&output, &[0u8, 255u8, 0u8]);
+
+    assert_eq!(reader.read_u8(1).unwrap(), 1);
+
+    reader.read_u8_slice(&mut output[1..2]).unwrap();
+    assert_eq!(&output, &[0u8, 0u8, 0u8]);
+
+    assert_eq!(reader.read_u8(1).unwrap(), 1);
+
+    output = [0b1010_1101; 3];
+    reader.read_u8_slice(&mut output).unwrap();
+    assert_eq!(&output, &[0u8, 255u8, 0u8]);
+
+    reader.read_u8_slice(&mut output[0..1]).unwrap();
+    assert_eq!(output[0], 0b1111_0110);
+
+    assert_eq!(reader.read_u8(2).unwrap(), 0);
+}
+
+#[test]
+fn read_slice_too_much() {
+    let bytes = &[
+        0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111,
+    ];
+    let mut reader = BitReader::new(bytes);
+    assert_eq!(reader.read_u8(1).unwrap(), 1);
+
+    let mut output = [0u8; 4];
+    let should_be_error = reader.read_u8_slice(&mut output);
+    assert_eq!(should_be_error.unwrap_err(), BitReaderError::NotEnoughData {
+        position: 1,
+        length: (bytes.len() * 8) as u64,
+        requested: (&output.len() * 8) as u64
+    });
+    assert_eq!(&output, &[0u8; 4]);
+}
--- a/third_party/rust/cfg-if/.cargo-checksum.json
+++ b/third_party/rust/cfg-if/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"090d983ec20ad09e59f6b7679b48b9b54e9c0841cf2922b81cba485edcd40876","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"1cd0ebc3b30a9c9eddb0fda5515b5a52ec2b85a087328f0ee9f4d68cbb28afc2","src/lib.rs":"f02d6e295109365cf54884e5282a3e7d1e1f62857c700f23cd013e94a56bd803","tests/xcrate.rs":"30dcb70fbb9c96fda2b7825592558279f534776f72e2a8a0a3e26df4dedb3caa"},"package":"082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"}
\ No newline at end of file
+{"files":{"Cargo.toml":"2cb2370b62c56a7d51b51f9e405b2f377b3ad6f7f8d33bc69e20eb819ad66012","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"2406e83ee174e30aa67f8ab266836fa78545012b196395aff37c152321e2c713","src/lib.rs":"8dfd667d32d8b06e529643c975dfa14c29ce9a894a80e381a1bd867252e65e56","tests/xcrate.rs":"c0734dae6e63beafcd60bf53546115a2320735b51035c9e2387fdf9301580934"},"package":"4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"}
\ No newline at end of file
--- a/third_party/rust/cfg-if/Cargo.toml
+++ b/third_party/rust/cfg-if/Cargo.toml
@@ -1,24 +1,36 @@
 # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
 #
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g. crates.io) dependencies
+# to registry (e.g., crates.io) dependencies
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
+edition = "2018"
 name = "cfg-if"
-version = "0.1.6"
+version = "0.1.10"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 description = "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n"
 homepage = "https://github.com/alexcrichton/cfg-if"
 documentation = "https://docs.rs/cfg-if"
 readme = "README.md"
 license = "MIT/Apache-2.0"
 repository = "https://github.com/alexcrichton/cfg-if"
+[dependencies.compiler_builtins]
+version = "0.1.2"
+optional = true
+
+[dependencies.core]
+version = "1.0.0"
+optional = true
+package = "rustc-std-workspace-core"
+
+[features]
+rustc-dep-of-std = ["core", "compiler_builtins"]
 [badges.travis-ci]
 repository = "alexcrichton/cfg-if"
--- a/third_party/rust/cfg-if/README.md
+++ b/third_party/rust/cfg-if/README.md
@@ -1,30 +1,25 @@
 # cfg-if
 
-[![Build Status](https://travis-ci.org/alexcrichton/cfg-if.svg?branch=master)](https://travis-ci.org/alexcrichton/cfg-if)
-
 [Documentation](https://docs.rs/cfg-if)
 
 A macro to ergonomically define an item depending on a large number of #[cfg]
 parameters. Structured like an if-else chain, the first matching branch is the
 item that gets emitted.
 
 ```toml
 [dependencies]
 cfg-if = "0.1"
 ```
 
 ## Example
 
 ```rust
-#[macro_use]
-extern crate cfg_if;
-
-cfg_if! {
+cfg_if::cfg_if! {
     if #[cfg(unix)] {
         fn foo() { /* unix specific functionality */ }
     } else if #[cfg(target_pointer_width = "32")] {
         fn foo() { /* non-unix, 32-bit functionality */ }
     } else {
         fn foo() { /* fallback implementation */ }
     }
 }
@@ -43,10 +38,10 @@ This project is licensed under either of
  * MIT license ([LICENSE-MIT](LICENSE-MIT) or
    http://opensource.org/licenses/MIT)
 
 at your option.
 
 ### Contribution
 
 Unless you explicitly state otherwise, any contribution intentionally submitted
-for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
+for inclusion in `cfg-if` by you, as defined in the Apache-2.0 license, shall be
 dual licensed as above, without any additional terms or conditions.
--- a/third_party/rust/cfg-if/src/lib.rs
+++ b/third_party/rust/cfg-if/src/lib.rs
@@ -5,90 +5,89 @@
 //! emitting the implementation which matches first.
 //!
 //! This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
 //! without having to rewrite each clause multiple times.
 //!
 //! # Example
 //!
 //! ```
-//! #[macro_use]
-//! extern crate cfg_if;
-//!
-//! cfg_if! {
+//! cfg_if::cfg_if! {
 //!     if #[cfg(unix)] {
 //!         fn foo() { /* unix specific functionality */ }
 //!     } else if #[cfg(target_pointer_width = "32")] {
 //!         fn foo() { /* non-unix, 32-bit functionality */ }
 //!     } else {
 //!         fn foo() { /* fallback implementation */ }
 //!     }
 //! }
 //!
 //! # fn main() {}
 //! ```
 
 #![no_std]
-
 #![doc(html_root_url = "https://docs.rs/cfg-if")]
 #![deny(missing_docs)]
 #![cfg_attr(test, deny(warnings))]
 
-#[macro_export(local_inner_macros)]
+/// The main macro provided by this crate. See crate documentation for more
+/// information.
+#[macro_export]
 macro_rules! cfg_if {
     // match if/else chains with a final `else`
     ($(
-        if #[cfg($($meta:meta),*)] { $($it:item)* }
+        if #[cfg($($meta:meta),*)] { $($tokens:tt)* }
     ) else * else {
-        $($it2:item)*
+        $($tokens2:tt)*
     }) => {
-        cfg_if! {
+        $crate::cfg_if! {
             @__items
             () ;
-            $( ( ($($meta),*) ($($it)*) ), )*
-            ( () ($($it2)*) ),
+            $( ( ($($meta),*) ($($tokens)*) ), )*
+            ( () ($($tokens2)*) ),
         }
     };
 
     // match if/else chains lacking a final `else`
     (
-        if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
+        if #[cfg($($i_met:meta),*)] { $($i_tokens:tt)* }
         $(
-            else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
+            else if #[cfg($($e_met:meta),*)] { $($e_tokens:tt)* }
         )*
     ) => {
-        cfg_if! {
+        $crate::cfg_if! {
             @__items
             () ;
-            ( ($($i_met),*) ($($i_it)*) ),
-            $( ( ($($e_met),*) ($($e_it)*) ), )*
+            ( ($($i_met),*) ($($i_tokens)*) ),
+            $( ( ($($e_met),*) ($($e_tokens)*) ), )*
             ( () () ),
         }
     };
 
     // Internal and recursive macro to emit all the items
     //
     // Collects all the negated cfgs in a list at the beginning and after the
     // semicolon is all the remaining items
     (@__items ($($not:meta,)*) ; ) => {};
-    (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
-        // Emit all items within one block, applying an approprate #[cfg]. The
+    (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => {
+        // Emit all items within one block, applying an appropriate #[cfg]. The
         // #[cfg] will require all `$m` matchers specified and must also negate
         // all previous matchers.
-        cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* }
+        #[cfg(all($($m,)* not(any($($not),*))))] $crate::cfg_if! { @__identity $($tokens)* }
 
         // Recurse to emit all other items in `$rest`, and when we do so add all
         // our `$m` matchers to the list of `$not` matchers as future emissions
         // will have to negate everything we just matched as well.
-        cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
+        $crate::cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
     };
 
-    // Internal macro to Apply a cfg attribute to a list of items
-    (@__apply $m:meta, $($it:item)*) => {
-        $(#[$m] $it)*
+    // Internal macro to make __apply work out right for different match types,
+    // because of how macros matching/expand stuff.
+    (@__identity $($tokens:tt)*) => {
+        $($tokens)*
     };
 }
 
 #[cfg(test)]
 mod tests {
     cfg_if! {
         if #[cfg(test)] {
             use core::option::Option as Option2;
@@ -134,9 +133,44 @@ mod tests {
     #[test]
     fn it_works() {
         assert!(works1().is_some());
         assert!(works2());
         assert!(works3());
         assert!(works4().is_some());
         assert!(works5());
     }
+
+    #[test]
+    #[allow(clippy::assertions_on_constants)]
+    fn test_usage_within_a_function() {
+        cfg_if! {if #[cfg(debug_assertions)] {
+            // we want to put more than one thing here to make sure that they
+            // all get configured properly.
+            assert!(cfg!(debug_assertions));
+            assert_eq!(4, 2+2);
+        } else {
+            assert!(works1().is_some());
+            assert_eq!(10, 5+5);
+        }}
+    }
+
+    trait Trait {
+        fn blah(&self);
+    }
+
+    #[allow(dead_code)]
+    struct Struct;
+
+    impl Trait for Struct {
+        cfg_if! {
+            if #[cfg(feature = "blah")] {
+                fn blah(&self) {
+                    unimplemented!();
+                }
+            } else {
+                fn blah(&self) {
+                    unimplemented!();
+                }
+            }
+        }
+    }
 }
--- a/third_party/rust/cfg-if/tests/xcrate.rs
+++ b/third_party/rust/cfg-if/tests/xcrate.rs
@@ -1,12 +1,9 @@
-#[macro_use]
-extern crate cfg_if;
-
-cfg_if! {
+cfg_if::cfg_if! {
     if #[cfg(foo)] {
         fn works() -> bool { false }
     } else if #[cfg(test)] {
         fn works() -> bool { true }
     } else {
         fn works() -> bool { false }
     }
 }
--- a/third_party/rust/mp4parse_fallible/.cargo-checksum.json
+++ b/third_party/rust/mp4parse_fallible/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"7e0306d977c63a491bea39dde354455f23c7eb283abf874d0122a664bbc082d3","README":"1ff38c3749ba83c9b364c6bb35b95525dd956449ec7386a50faf8fcfdd5a7de4","lib.rs":"3c54447b497f808ab7fa7659f1379acf4c5c3def37fc4cc7778281273b84eabb"},"package":"6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"}
\ No newline at end of file
+{"files":{"CODE_OF_CONDUCT.md":"902d5357af363426631d907e641e220b3ec89039164743f8442b3f120479b7cf","Cargo.toml":"2edecc4249f6ff011255fe3c92892050e466246b23ee6d002243b0df760625c7","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README":"6f28a5c89ff7c018760402038a991a581771b8f66869268a7288f64915f192a6","lib.rs":"70f5bec52c586809882a1edce407552e8a5c3d0f126eaa92abd676484395cfc8"},"package":"704f773471ac3e7110427b6bdf93184932b19319c9b7717688da5424e519b10a"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mp4parse_fallible/CODE_OF_CONDUCT.md
@@ -0,0 +1,15 @@
+# Community Participation Guidelines
+
+This repository is governed by Mozilla's code of conduct and etiquette guidelines. 
+For more details, please read the
+[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 
+
+## How to Report
+For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.
+
+<!--
+## Project Specific Etiquette
+
+In some cases, there will be additional project etiquette i.e.: (https://bugzilla.mozilla.org/page.cgi?id=etiquette.html).
+Please update for your project.
+-->
--- a/third_party/rust/mp4parse_fallible/Cargo.toml
+++ b/third_party/rust/mp4parse_fallible/Cargo.toml
@@ -1,23 +1,23 @@
 # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
 #
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g. crates.io) dependencies
+# to registry (e.g., crates.io) dependencies
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "mp4parse_fallible"
-version = "0.0.1"
+version = "0.0.3"
 authors = ["The Servo Project Developers"]
 description = "Fallible replacement for Vec"
 documentation = "https://docs.rs/mp4parse_fallible/"
 license = "MPL-2.0"
 repository = "https://github.com/mozilla/mp4parse_fallible"
 
 [lib]
 name = "mp4parse_fallible"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/mp4parse_fallible/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in 
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
--- a/third_party/rust/mp4parse_fallible/README
+++ b/third_party/rust/mp4parse_fallible/README
@@ -1,7 +1,7 @@
 This is from https://github.com/servo/servo/tree/master/components/fallible
-with modificaion for mp4 demuxer.
+with modification for mp4 demuxer.
 
 The purpose of this crate is to solve infallible memory allocation problem
 which causes OOM easily on win32. This is more like a temporary solution.
 Once rust supports fallible memory allocation in its stdlib, this can be
 retired.
--- a/third_party/rust/mp4parse_fallible/lib.rs
+++ b/third_party/rust/mp4parse_fallible/lib.rs
@@ -10,19 +10,27 @@ extern "C" {
     fn malloc(bytes: usize) -> *mut u8;
 }
 
 pub trait FallibleVec<T> {
     /// Append |val| to the end of |vec|.  Returns Ok(()) on success,
     /// Err(()) if it fails, which can only be due to lack of memory.
     fn try_push(&mut self, value: T) -> Result<(), ()>;
 
-    /// Expand the vector size. Return Ok(()) on success, Err(()) if it
-    /// fails.
-    fn try_reserve(&mut self, new_cap: usize) -> Result<(), ()>;
+    /// Reserves capacity for at least `additional` more elements to
+    /// be inserted in the vector. Does nothing if capacity is already
+    /// sufficient. Return Ok(()) on success, Err(()) if it fails either
+    /// due to lack of memory, or overflowing the `usize` used to store
+    /// the capacity.
+    fn try_reserve(&mut self, additional: usize) -> Result<(), ()>;
+
+    /// Clones and appends all elements in a slice to the Vec.
+    /// Returns Ok(()) on success, Err(()) if it fails, which can
+    /// only be due to lack of memory.
+    fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> where T: Clone;
 }
 
 /////////////////////////////////////////////////////////////////
 // Vec
 
 impl<T> FallibleVec<T> for Vec<T> {
     #[inline]
     fn try_push(&mut self, val: T) -> Result<(), ()> {
@@ -34,20 +42,31 @@ impl<T> FallibleVec<T> for Vec<T> {
             try_extend_vec(self, new_cap)?;
             debug_assert!(self.capacity() > self.len());
         }
         self.push(val);
         Ok(())
     }
 
     #[inline]
-    fn try_reserve(&mut self, cap: usize) -> Result<(), ()> {
-        let new_cap = cap + self.capacity();
-        try_extend_vec(self, new_cap)?;
-        debug_assert!(self.capacity() == new_cap);
+    fn try_reserve(&mut self, additional: usize) -> Result<(), ()> {
+        let available = self.capacity().checked_sub(self.len()).expect("capacity >= len");
+        if additional > available {
+            let increase = additional.checked_sub(available).expect("additional > available");
+            let new_cap = self.capacity().checked_add(increase).ok_or(())?;
+            try_extend_vec(self, new_cap)?;
+            debug_assert!(self.capacity() == new_cap);
+        }
+        Ok(())
+    }
+
+    #[inline]
+    fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> where T: Clone {
+        FallibleVec::try_reserve(self, other.len())?;
+        self.extend_from_slice(other);
         Ok(())
     }
 }
 
 #[inline(never)]
 #[cold]
 fn try_extend_vec<T>(vec: &mut Vec<T>, new_cap: usize) -> Result<(), ()> {
     let old_ptr = vec.as_mut_ptr();
@@ -78,15 +97,51 @@ fn try_extend_vec<T>(vec: &mut Vec<T>, n
         Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap)
     };
 
     mem::forget(mem::replace(vec, new_vec));
     Ok(())
 }
 
 #[test]
-fn oom_test() {
+fn oom() {
     let mut vec: Vec<char> = Vec::new();
-    match vec.try_reserve(std::usize::MAX) {
+    match FallibleVec::try_reserve(&mut vec, std::usize::MAX) {
         Ok(_) => panic!("it should be OOM"),
         _ => (),
     }
 }
+
+#[test]
+fn try_reserve() {
+    let mut vec = vec![1];
+    let old_cap = vec.capacity();
+    let new_cap = old_cap + 1;
+    FallibleVec::try_reserve(&mut vec, new_cap).unwrap();
+    assert!(vec.capacity() >= new_cap);
+}
+
+#[test]
+fn try_reserve_idempotent() {
+    let mut vec = vec![1];
+    let old_cap = vec.capacity();
+    let new_cap = old_cap + 1;
+    FallibleVec::try_reserve(&mut vec, new_cap).unwrap();
+    let cap_after_reserve = vec.capacity();
+    FallibleVec::try_reserve(&mut vec, new_cap).unwrap();
+    assert_eq!(cap_after_reserve, vec.capacity());
+}
+
+#[test]
+fn capacity_overflow() {
+    let mut vec = vec![1];
+    match FallibleVec::try_reserve(&mut vec, std::usize::MAX) {
+        Ok(_) => panic!("capacity calculation should overflow"),
+        _ => (),
+    }
+}
+
+#[test]
+fn extend_from_slice() {
+    let mut vec = b"foo".to_vec();
+    FallibleVec::try_extend_from_slice(&mut vec, b"bar").unwrap();
+    assert_eq!(&vec, b"foobar");
+}
--- a/third_party/rust/nom/.cargo-checksum.json
+++ b/third_party/rust/nom/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".travis.yml":"124c5613de02fe2088a7410a7057b0e0ed49dcbc8509704b690de98e83b289e0","CHANGELOG.md":"f4015ae48bb8f7c672c4fdf1ca4bdde5910f1b423ddc12e9fe80395911759d3e","Cargo.lock":"d7985e783bf7275009ab524f13aac37adc7291838a1956e1f092413ff3b8ea04","Cargo.toml":"72afa6607971579c7009dff34b6b334d4893b1a9f1983cd80364c5e318e4ec2b","LICENSE":"4dbda04344456f09a7a588140455413a9ac59b6b26a1ef7cdf9c800c012d87f0","build.rs":"fd66799ca3bd6a83b10f18a62e6ffc3b1ac94074fe65de4e4c1c447bf71d6ebb","src/bits/complete.rs":"8a60ae4cd6aaf32cb232b598b1a3dda7858c619944ba12ebdb01a31c75243293","src/bits/macros.rs":"8d9ba23f237b4fc01e3b2106002d0f6d59930a42f34d80662c61e0057dfb4a5b","src/bits/mod.rs":"4ca0148b4ef2de4e88796da7831eaa5c4fcbc5515a101eae1b0bc4853c80b5e7","src/bits/streaming.rs":"7c587808476edee57caeccca7dccd744bdfdbb13ae1156400fb4961980fa325d","src/branch/macros.rs":"8b885185725c16369d90954fed8450070bcd4bf8ae7de1df1bb46bb378450d71","src/branch/mod.rs":"d0c871ad7b74428ddccef445a10254249c3907528005a00275e8eb6516255f2f","src/bytes/complete.rs":"107f776885161e48a596962925d2b1628f20fd4bbe5b3777bb34ec175b97e280","src/bytes/macros.rs":"914a821761bbf49f04425068b7426bdd60394e8cc30e7c2193160b16e06c266f","src/bytes/mod.rs":"577231e6e6bd51726a877a73292d8f1c626f6b32ebe4a57943acaed8a8a2975d","src/bytes/streaming.rs":"4b2e577e6057fda932d1edc2ebe53c5df71a21417a304b35d5230dd7221411f3","src/character/complete.rs":"bb80656f3405eca79ba93c674cae7cd296733d784928e5c45754ee27963b7325","src/character/macros.rs":"f330ab60d469802b1664dcbbccd4bfe3e1ca87b348e92609ef34e25b4d475983","src/character/mod.rs":"9f520d535a88849726eac8648aa5c8b86193ab2f3a984d63c8371b846cc0b72c","src/character/streaming.rs":"9be7051951e8d0a54e294542baaf115aeb6efb818521f045386cd3a1777ca6a0","src/combinator/macros.rs":"df9ba1157bda21313a9c23826baeefd99f54e92c47d60c8dbb25697fe4d52686","src/combinator/mod.rs":"d1b2073683be1c9c4a06d1d3764ac789027ad7401ec726805d1505c1ad8ab1fd","src/error.rs":"ef7feb06b9689aa2f4b11a367b6f7058df8fd151b673c7482edd6600e55e38da","src/internal.rs":"c4029b0e32d41eb6407e517f3102a41a3a80a6a69df4767008ac5656b28d7ab0","src/lib.rs":"f01cdc23cc17201f978796d2d80fb6bba5a9b81ffb4653286e1e53f904079911","src/methods.rs":"56099c30123e92f9f6bacb16017f29fcdbc6546afbf0f80cf4951d2d8093ba83","src/multi/macros.rs":"01d15ae913921bd1ed0ff579a868ea39a314a866e6b5a365ef6b448a75f9b3a8","src/multi/mod.rs":"342c30e0c601558c867df215f7094bc9e43534a7793f2e8b19c114fe07cfea41","src/number/complete.rs":"560dfb2ffbbfe7fe276389b60eec2d717fec20eab68cc72d10d87ff6e2195352","src/number/macros.rs":"e614ee142658c126902a466f29ef250a77016fa126b8dfd59db0c6657a0ef205","src/number/mod.rs":"e432c317ee839a2f928cd0e8e583acadb165ed84fb649e681688a0fcd84b0a75","src/number/streaming.rs":"4c6fbce64e0d535f69d2c928314e1d0a019480db5a09e4f47a654a2e8fd56e8c","src/regexp.rs":"ac6fc61c2e7b629e6786638b44d63d15139c50f9d6a38acd044e4c2b3a699e08","src/sequence/macros.rs":"0e72871cdb2f1bf804f7f637def117c8e531f78cc7da5a6a0e343f0dbfb04271","src/sequence/mod.rs":"ec34b969462703252c4f00c27a03928c9580da612c71b7100e0902190a633ab9","src/str.rs":"fcae4d6f2f7bc921cafe3d0ce682d0566618cbe5f3b3e4b51ca34d11cb0e3e93","src/traits.rs":"2a84c3aa40f1cf78e0149e344da8b85486f7b6c0ddff8f23689bccce0def2260","src/util.rs":"bcedca3c88ac24f11f73e836efd8fe00014562163cc3d43d0cec9d726a4687c3","src/whitespace.rs":"53bddd9d559dc7793effcb828f9c196a7f098338edb0877940d1246834761308","tests/arithmetic.rs":"c57bc547110e498e7bddc973a94202f22356bc525fed55dac4f03daf16eb54f7","tests/arithmetic_ast.rs":"8fbc4c5d8850fa1cf0a16f97e8718d5427b2657f12ca4a0b3b6c1b47fd9e67d4","tests/blockbuf-arithmetic.rs":"099fdf75da97ae032006d8c82ea2207265c5161a08d1370e1ddddb01e73afaf4","tests/css.rs":"b13466eb6a0831f98ede83ffdd752ba821f7d03db724fd92b5bfbc0b9f804a65","tests/custom_errors.rs":"3d2511f8a8d0eb20d9efc19f29ae4ab34389bdd33214a421989d0c47b540b7fd","tests/escaped.rs":"03ecb10828472e4de2ace05a12cb49997b47a113b6a3b0eea3d56bc2bafd8446","tests/float.rs":"92947cc112a6b865f5e19d80edbf300ddc0d0ca4b4e4543eda15337b5c60eedf","tests/inference.rs":"fe476d1367fce9f0baf82295dc037c79321ededf12b9bcc0c5acdc7cefff4720","tests/ini.rs":"04ebf3ead0008974b3bedc387e889bab5942efd0c9c8563fe47e056a9b90bbab","tests/ini_str.rs":"2831a4ee26b37734dba8862cc2972a3a1433abf4fcab253b6cf4fb43f120301d","tests/issues.rs":"142c8d206089b04cf2fd0cbd90f87421ded435ce300516c029294b056354e00f","tests/json.rs":"25476ec2daca19295f5f99b621eecc859a5db5789ac35be381eaf8703a70bce8","tests/mp4.rs":"d0e61bfc93ff40676ca7e9d7813a5ad7c73b1db874599d8f3ea784115bfcab87","tests/multiline.rs":"6a5321cb53c7f88778fa100499533abfa602bada7a6b1d0fbba7ef77b9c110f5","tests/named_args.rs":"bd8095c3abc6fb806c9181c6025c0111d1e7f3b7269ea89ae122bf3bb8ed7e7d","tests/overflow.rs":"d1d6d8ce9b34ed47b42a5f7250ce711805a397691dc6cad3cc8945ec230da161","tests/reborrow_fold.rs":"9328deafc2143c2a2d1a0be86e2448b644cffcb5f0935c8b24eb469f1f9477c0","tests/test1.rs":"06fc9e52638f16bfc3ef69cd26b927e0cf55706d6f132ab7c0f1072208475853"},"package":"0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"f4015ae48bb8f7c672c4fdf1ca4bdde5910f1b423ddc12e9fe80395911759d3e","Cargo.lock":"d7985e783bf7275009ab524f13aac37adc7291838a1956e1f092413ff3b8ea04","Cargo.toml":"72afa6607971579c7009dff34b6b334d4893b1a9f1983cd80364c5e318e4ec2b","LICENSE":"4dbda04344456f09a7a588140455413a9ac59b6b26a1ef7cdf9c800c012d87f0","build.rs":"fd66799ca3bd6a83b10f18a62e6ffc3b1ac94074fe65de4e4c1c447bf71d6ebb","src/bits/complete.rs":"8a60ae4cd6aaf32cb232b598b1a3dda7858c619944ba12ebdb01a31c75243293","src/bits/macros.rs":"8d9ba23f237b4fc01e3b2106002d0f6d59930a42f34d80662c61e0057dfb4a5b","src/bits/mod.rs":"4ca0148b4ef2de4e88796da7831eaa5c4fcbc5515a101eae1b0bc4853c80b5e7","src/bits/streaming.rs":"7c587808476edee57caeccca7dccd744bdfdbb13ae1156400fb4961980fa325d","src/branch/macros.rs":"8b885185725c16369d90954fed8450070bcd4bf8ae7de1df1bb46bb378450d71","src/branch/mod.rs":"d0c871ad7b74428ddccef445a10254249c3907528005a00275e8eb6516255f2f","src/bytes/complete.rs":"107f776885161e48a596962925d2b1628f20fd4bbe5b3777bb34ec175b97e280","src/bytes/macros.rs":"914a821761bbf49f04425068b7426bdd60394e8cc30e7c2193160b16e06c266f","src/bytes/mod.rs":"577231e6e6bd51726a877a73292d8f1c626f6b32ebe4a57943acaed8a8a2975d","src/bytes/streaming.rs":"4b2e577e6057fda932d1edc2ebe53c5df71a21417a304b35d5230dd7221411f3","src/character/complete.rs":"bb80656f3405eca79ba93c674cae7cd296733d784928e5c45754ee27963b7325","src/character/macros.rs":"f330ab60d469802b1664dcbbccd4bfe3e1ca87b348e92609ef34e25b4d475983","src/character/mod.rs":"9f520d535a88849726eac8648aa5c8b86193ab2f3a984d63c8371b846cc0b72c","src/character/streaming.rs":"9be7051951e8d0a54e294542baaf115aeb6efb818521f045386cd3a1777ca6a0","src/combinator/macros.rs":"df9ba1157bda21313a9c23826baeefd99f54e92c47d60c8dbb25697fe4d52686","src/combinator/mod.rs":"d1b2073683be1c9c4a06d1d3764ac789027ad7401ec726805d1505c1ad8ab1fd","src/error.rs":"ef7feb06b9689aa2f4b11a367b6f7058df8fd151b673c7482edd6600e55e38da","src/internal.rs":"c4029b0e32d41eb6407e517f3102a41a3a80a6a69df4767008ac5656b28d7ab0","src/lib.rs":"f01cdc23cc17201f978796d2d80fb6bba5a9b81ffb4653286e1e53f904079911","src/methods.rs":"56099c30123e92f9f6bacb16017f29fcdbc6546afbf0f80cf4951d2d8093ba83","src/multi/macros.rs":"01d15ae913921bd1ed0ff579a868ea39a314a866e6b5a365ef6b448a75f9b3a8","src/multi/mod.rs":"342c30e0c601558c867df215f7094bc9e43534a7793f2e8b19c114fe07cfea41","src/number/complete.rs":"560dfb2ffbbfe7fe276389b60eec2d717fec20eab68cc72d10d87ff6e2195352","src/number/macros.rs":"e614ee142658c126902a466f29ef250a77016fa126b8dfd59db0c6657a0ef205","src/number/mod.rs":"e432c317ee839a2f928cd0e8e583acadb165ed84fb649e681688a0fcd84b0a75","src/number/streaming.rs":"4c6fbce64e0d535f69d2c928314e1d0a019480db5a09e4f47a654a2e8fd56e8c","src/regexp.rs":"ac6fc61c2e7b629e6786638b44d63d15139c50f9d6a38acd044e4c2b3a699e08","src/sequence/macros.rs":"0e72871cdb2f1bf804f7f637def117c8e531f78cc7da5a6a0e343f0dbfb04271","src/sequence/mod.rs":"ec34b969462703252c4f00c27a03928c9580da612c71b7100e0902190a633ab9","src/str.rs":"fcae4d6f2f7bc921cafe3d0ce682d0566618cbe5f3b3e4b51ca34d11cb0e3e93","src/traits.rs":"2a84c3aa40f1cf78e0149e344da8b85486f7b6c0ddff8f23689bccce0def2260","src/util.rs":"bcedca3c88ac24f11f73e836efd8fe00014562163cc3d43d0cec9d726a4687c3","src/whitespace.rs":"53bddd9d559dc7793effcb828f9c196a7f098338edb0877940d1246834761308","tests/arithmetic.rs":"c57bc547110e498e7bddc973a94202f22356bc525fed55dac4f03daf16eb54f7","tests/arithmetic_ast.rs":"8fbc4c5d8850fa1cf0a16f97e8718d5427b2657f12ca4a0b3b6c1b47fd9e67d4","tests/blockbuf-arithmetic.rs":"099fdf75da97ae032006d8c82ea2207265c5161a08d1370e1ddddb01e73afaf4","tests/css.rs":"b13466eb6a0831f98ede83ffdd752ba821f7d03db724fd92b5bfbc0b9f804a65","tests/custom_errors.rs":"3d2511f8a8d0eb20d9efc19f29ae4ab34389bdd33214a421989d0c47b540b7fd","tests/escaped.rs":"03ecb10828472e4de2ace05a12cb49997b47a113b6a3b0eea3d56bc2bafd8446","tests/float.rs":"92947cc112a6b865f5e19d80edbf300ddc0d0ca4b4e4543eda15337b5c60eedf","tests/inference.rs":"fe476d1367fce9f0baf82295dc037c79321ededf12b9bcc0c5acdc7cefff4720","tests/ini.rs":"04ebf3ead0008974b3bedc387e889bab5942efd0c9c8563fe47e056a9b90bbab","tests/ini_str.rs":"2831a4ee26b37734dba8862cc2972a3a1433abf4fcab253b6cf4fb43f120301d","tests/issues.rs":"142c8d206089b04cf2fd0cbd90f87421ded435ce300516c029294b056354e00f","tests/json.rs":"25476ec2daca19295f5f99b621eecc859a5db5789ac35be381eaf8703a70bce8","tests/mp4.rs":"d0e61bfc93ff40676ca7e9d7813a5ad7c73b1db874599d8f3ea784115bfcab87","tests/multiline.rs":"6a5321cb53c7f88778fa100499533abfa602bada7a6b1d0fbba7ef77b9c110f5","tests/named_args.rs":"bd8095c3abc6fb806c9181c6025c0111d1e7f3b7269ea89ae122bf3bb8ed7e7d","tests/overflow.rs":"d1d6d8ce9b34ed47b42a5f7250ce711805a397691dc6cad3cc8945ec230da161","tests/reborrow_fold.rs":"9328deafc2143c2a2d1a0be86e2448b644cffcb5f0935c8b24eb469f1f9477c0","tests/test1.rs":"06fc9e52638f16bfc3ef69cd26b927e0cf55706d6f132ab7c0f1072208475853"},"package":"0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6"}
\ No newline at end of file
deleted file mode 100644
--- a/third_party/rust/nom/.travis.yml
+++ /dev/null
@@ -1,101 +0,0 @@
-language: rust
-# sudo is required to enable kcov to use the personality syscall
-sudo: required
-dist: trusty
-cache: cargo
-
-rust:
-  - nightly
-  - beta
-  - stable
-  - 1.31.0
-
-env:
-  matrix:
-    - FEATURES='--features "regexp regexp_macros"'
-
-before_script:
-  - eval git pull --rebase https://github.com/Geal/nom master
-  - eval git log --pretty=oneline HEAD~5..HEAD
-
-matrix:
-  include:
-    - rust: nightly
-      env: FEATURES='--no-default-features'
-    - rust: nightly
-      env: FEATURES='--no-default-features --features "alloc"'
-    - rust: stable
-      env: FEATURES=''
-    - rust: nightly
-      env: DOC_FEATURES='--features "std lexical regexp regexp_macros" --no-default-features'
-      before_script:
-        - export PATH=$HOME/.cargo/bin:$PATH
-      script:
-        - eval cargo doc --verbose $DOC_FEATURES
-    - rust: nightly
-      env: FEATURES=''
-      before_script:
-        - export PATH=$HOME/.cargo/bin:$PATH
-        - cargo install cargo-update   || echo "cargo-update already installed"
-        - cargo install cargo-travis   || echo "cargo-travis already installed"
-        - cargo install-update -a
-        - mkdir -p target/kcov-master
-      script:
-        cargo coveralls --verbose --all-features
-  allow_failures:
-    - rust: stable
-      env: FEATURES=''
-      before_script:
-        - export PATH=$HOME/.cargo/bin:$PATH
-        - rustup component add rustfmt-preview
-      script:
-        - eval cargo fmt -- --write-mode=diff
-
-notifications:
-  webhooks:
-    urls:
-      - https://webhooks.gitter.im/e/9c035a194ac4fd4cc061
-    on_success: change
-    on_failure: always
-    on_start: false
-
-
-addons:
-  apt:
-    packages:
-      - libcurl4-openssl-dev
-      - libelf-dev
-      - libdw-dev
-      - binutils-dev
-      - cmake
-    sources:
-      - kalakris-cmake
-
-cache:
-  directories:
-    - /home/travis/.cargo
-
-before_cache:
-  - rm -rf /home/travis/.cargo/registry
-
-script:
-  - eval cargo build --verbose $FEATURES
-  - eval cargo test --verbose $FEATURES
-
-after_success: |
-  case "$TRAVIS_RUST_VERSION" in
-    nightly)
-      if [ "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}" != "master" ]; then
-        git fetch &&
-        git checkout master &&
-        cargo bench --verbose
-      fi
-
-      if [ "$FEATURES" == '--features "regexp regexp_macros"' ]; then
-        cargo bench --verbose
-      fi
-      ;;
-
-    *)
-      ;;
-  esac
--- a/tools/lint/clippy.yml
+++ b/tools/lint/clippy.yml
@@ -14,17 +14,16 @@ clippy:
         - gfx/wr/wr_malloc_size_of/
         - js/src/
         - js/src/frontend/binast/
         - js/src/rust/shared/
         - js/src/wasm/cranelift/
         - media/audioipc/
         - media/mp4parse-rust/mp4parse/
         - media/mp4parse-rust/mp4parse_capi/
-        - media/mp4parse-rust/mp4parse_fallible/
         - modules/libpref/init/static_prefs/
         - mozglue/static/rust/
         - netwerk/base/mozurl/
         - security/manager/ssl/osclientcerts/
         - servo/components/derive_common/
         - servo/components/selectors/
         - servo/components/servo_arc/
         - servo/components/size_of_test/