From 862994217b264f2f2cb75bfc2fc895538f027d1f Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 23 Sep 2024 09:52:10 +0200 Subject: [PATCH 01/32] Add Cargo.lock to git --- .gitignore | 1 - Cargo.lock | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 3f946ee..da8a060 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/Cargo.lock /target **/*.rs.bk *.exe diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6967e58 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,185 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "re_mp4" +version = "0.1.0" +dependencies = [ + "byteorder", + "bytes", + "log", + "num-rational", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" From 9ce40943b3714f0cc02ebdd8b5e1e1bd7adb53c2 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 23 Sep 2024 09:53:31 +0200 Subject: [PATCH 02/32] Add `Cargo.lock` to `.gitattributes` --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b1f5e11 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto eol=lf +Cargo.lock linguist-generated=false From 5a250464ec169e6b0a3427f510cc0008d292f64f Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 23 Sep 2024 09:57:14 +0200 Subject: [PATCH 03/32] Add `.typos.toml` and fix some typos --- .typos.toml | 16 ++++++++++++++++ tests/mp4box.mjs | 40 ++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 20 deletions(-) create mode 100644 .typos.toml diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 0000000..6c97628 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,16 @@ +# https://github.com/crate-ci/typos +# install: cargo install typos-cli +# run: typos + +[default.extend-words] +# There are some weird words in this repository: +alignement = "alignement" +ALS = "ALS" +alst = "alst" +CLL = "CLL" +fiel = "fiel" +intialization = "intialization" +numer = "numer" +trak = "trak" +trun = "trun" +truns = "truns" diff --git a/tests/mp4box.mjs b/tests/mp4box.mjs index 92c0c21..123812d 100644 --- a/tests/mp4box.mjs +++ b/tests/mp4box.mjs @@ -860,7 +860,7 @@ DataStream.prototype.readCString = function (length) { return s; }; -/* +/* TODO: fix endianness for 24/64-bit fields TODO: check range/support for 64-bits numbers in JavaScript */ @@ -884,7 +884,7 @@ DataStream.prototype.readUint24 = function () { /** Saves the DataStream contents to the given filename. Uses Chrome's anchor download property to initiate download. - + @param {string} filename Filename to save as. @return {null} */ @@ -1676,7 +1676,7 @@ MultiBufferStream.prototype.insertBuffer = function (ab) { /* The new buffer overlaps with an existing buffer */ if (ab.byteLength > b.byteLength) { /* the new buffer is bigger than the existing one - remove the existing buffer and try again to insert + remove the existing buffer and try again to insert the new buffer to check overlap with the next ones */ this.buffers.splice(i, 1); i--; @@ -1706,7 +1706,7 @@ MultiBufferStream.prototype.insertBuffer = function (ab) { "Appending new buffer (fileStart: " + ab.fileStart + " - Length: " + ab.byteLength + ")" ); this.buffers.splice(i, 0, ab); - /* if this new buffer is inserted in the first place in the list of the buffer, + /* if this new buffer is inserted in the first place in the list of the buffer, and the DataStream is initialized, make it the buffer used for parsing */ if (i === 0) { this.buffer = ab; @@ -1735,7 +1735,7 @@ MultiBufferStream.prototype.insertBuffer = function (ab) { "Appending new buffer (fileStart: " + ab.fileStart + " - Length: " + ab.byteLength + ")" ); this.buffers.push(ab); - /* if this new buffer is inserted in the first place in the list of the buffer, + /* if this new buffer is inserted in the first place in the list of the buffer, and the DataStream is initialized, make it the buffer used for parsing */ if (i === 0) { this.buffer = ab; @@ -1851,7 +1851,7 @@ MultiBufferStream.prototype.mergeNextBuffer = function () { * @param {Number} filePosition position in the file to seek to * @param {Boolean} markAsUsed indicates if the bytes in between the current position and the seek position * should be marked as used for garbage collection - * @return {Number} the index of the buffer holding the seeked file position, -1 if not found. + * @return {Number} the index of the buffer holding the sought file position, -1 if not found. */ MultiBufferStream.prototype.findPosition = function (fromStart, filePosition, markAsUsed) { var i; @@ -2628,7 +2628,7 @@ BoxParser.Box.prototype.parse = function (stream) { } }; -/* Used to parse a box without consuming its data, to allow detailled parsing +/* Used to parse a box without consuming its data, to allow detailed parsing Useful for boxes for which a write method is not yet implemented */ BoxParser.Box.prototype.parseDataAndRewind = function (stream) { this.data = stream.readUint8Array(this.size - this.hdr_size); @@ -3051,7 +3051,7 @@ BoxParser.createFullBoxCtor("ctts", function (stream) { for (i = 0; i < entry_count; i++) { this.sample_counts.push(stream.readUint32()); /* some files are buggy and declare version=0 while using signed offsets. - The likelyhood of using the most significant bit in a 32-bits time offset is very low, + The likelihood of using the most significant bit in a 32-bits time offset is very low, so using signed value here as well */ var value = stream.readInt32(); if (value < 0) { @@ -3690,7 +3690,7 @@ BoxParser.createFullBoxCtor("leva", function (stream) { level.sub_track_id = stream.readUint32(); break; default: - console.warn("BoxParser", "Unknown leva assignement type"); + console.warn("BoxParser", "Unknown leva assignment type"); } } }); @@ -6527,7 +6527,7 @@ Textin4Parser.prototype.parseConfig = function (data) { * License: BSD-3-Clause (see LICENSE file) */ var ISOFile = function (stream) { - /* MutiBufferStream object used to parse boxes */ + /* MultiBufferStream object used to parse boxes */ this.stream = stream || new MultiBufferStream(); /* Array of all boxes (in order) found in the file */ this.boxes = []; @@ -7281,7 +7281,7 @@ ISOFile.prototype.lastBoxStartPosition = 0; /* indicator if the parsing is stuck in the middle of an mdat box */ ISOFile.prototype.parsingMdat = null; /* next file position that the parser needs: - - 0 until the first buffer (i.e. fileStart ===0) has been received + - 0 until the first buffer (i.e. fileStart ===0) has been received - otherwise, the next box start until the moov box has been parsed - otherwise, the position of the next sample to fetch */ @@ -7298,7 +7298,7 @@ ISOFile.prototype.processIncompleteBox = function (ret) { if (ret.type === "mdat") { /* we had enough bytes to get its type and size and it's an 'mdat' */ - /* special handling for mdat boxes, since we don't actually need to parse it linearly + /* special handling for mdat boxes, since we don't actually need to parse it linearly we create the box */ box = new BoxParser[ret.type + "Box"](ret.size); this.parsingMdat = box; @@ -7321,12 +7321,12 @@ ISOFile.prototype.processIncompleteBox = function (ret) { /* 'mdat' end not found in the existing buffers */ /* determine the next position in the file to start parsing from */ if (!this.moovStartFound) { - /* moov not find yet, - the file probably has 'mdat' at the beginning, and 'moov' at the end, + /* moov not find yet, + the file probably has 'mdat' at the beginning, and 'moov' at the end, indicate that the downloader should not try to download those bytes now */ this.nextParsePosition = box.start + box.size; } else { - /* we have the start of the moov box, + /* we have the start of the moov box, the next bytes should try to complete the current 'mdat' */ this.nextParsePosition = this.stream.findEndContiguousBuf(); } @@ -7344,12 +7344,12 @@ ISOFile.prototype.processIncompleteBox = function (ret) { } /* either it's not an mdat box (and we need to parse it, we cannot skip it) (TODO: we could skip 'free' boxes ...) - or we did not have enough data to parse the type and size of the box, + or we did not have enough data to parse the type and size of the box, we try to concatenate the current buffer with the next buffer to restart parsing */ merged = this.stream.mergeNextBuffer ? this.stream.mergeNextBuffer() : false; if (merged) { /* The next buffer was contiguous, the merging succeeded, - we can now continue parsing, + we can now continue parsing, the next best position to parse is at the end of this new buffer */ this.nextParsePosition = this.stream.getEndPosition(); return true; @@ -7362,7 +7362,7 @@ ISOFile.prototype.processIncompleteBox = function (ret) { this.nextParsePosition = this.stream.getEndPosition(); } else { /* we had enough bytes to parse size and type of the incomplete box - if we haven't found yet the moov box, skip this one and try the next one + if we haven't found yet the moov box, skip this one and try the next one if we have found the moov box, let's continue linear parsing */ if (this.moovStartFound) { this.nextParsePosition = this.stream.getEndPosition(); @@ -7394,8 +7394,8 @@ ISOFile.prototype.processIncompleteMdat = function () { /* we can parse more in this buffer */ return true; } else { - /* we don't have the end of this mdat yet, - indicate that the next byte to fetch is the end of the buffers we have so far, + /* we don't have the end of this mdat yet, + indicate that the next byte to fetch is the end of the buffers we have so far, return and wait for more buffer to come */ this.nextParsePosition = this.stream.findEndContiguousBuf(); return false; From c474138493c20fe0b8602dba024dc8824e5dc4d5 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 23 Sep 2024 09:57:51 +0200 Subject: [PATCH 04/32] Add typos CI step --- .github/workflows/typos.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/typos.yml diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml new file mode 100644 index 0000000..3055f87 --- /dev/null +++ b/.github/workflows/typos.yml @@ -0,0 +1,19 @@ +# Copied from https://github.com/rerun-io/rerun_template + +# https://github.com/crate-ci/typos +# Add exceptions to `.typos.toml` +# install and run locally: cargo install typos-cli && typos + +name: Spell Check +on: [pull_request] + +jobs: + run: + name: Spell Check + runs-on: ubuntu-latest + steps: + - name: Checkout Actions Repository + uses: actions/checkout@v4 + + - name: Check spelling of entire workspace + uses: crate-ci/typos@master From 7b6296e3e7c81cbd0381262e297c45cc7026f3b1 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 23 Sep 2024 09:59:20 +0200 Subject: [PATCH 05/32] Add link checker to CI --- .github/workflows/links.yml | 34 ++++++++++++++++ lychee.toml | 79 +++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 .github/workflows/links.yml create mode 100644 lychee.toml diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 0000000..aeb663d --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,34 @@ +# Copied from https://github.com/rerun-io/rerun_template +on: + push: + branches: + - "main" + pull_request: + types: [ opened, synchronize ] + +name: Link checker + +jobs: + link-checker: + name: Check links + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Restore link checker cache + uses: actions/cache@v3 + with: + path: .lycheecache + key: cache-lychee-${{ github.sha }} + restore-keys: cache-lychee- + + # Check https://github.com/lycheeverse/lychee on how to run locally. + - name: Link Checker + id: lychee + uses: lycheeverse/lychee-action@v1.9.0 + with: + fail: true + lycheeVersion: "0.14.3" + # When given a directory, lychee checks only markdown, html and text files, everything else we have to glob in manually. + args: | + --base . --cache --max-cache-age 1d . "**/*.rs" "**/*.toml" "**/*.hpp" "**/*.cpp" "**/CMakeLists.txt" "**/*.py" "**/*.yml" diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 0000000..49e47ef --- /dev/null +++ b/lychee.toml @@ -0,0 +1,79 @@ +# Copied from https://github.com/rerun-io/rerun_template + +################################################################################ +# Config for the link checker lychee. +# +# Download & learn more at: +# https://github.com/lycheeverse/lychee +# +# Example config: +# https://github.com/lycheeverse/lychee/blob/master/lychee.example.toml +# +# Run `lychee . --dump` to list all found links that are being checked. +# +# Note that by default lychee will only check markdown and html files, +# to check any other files you have to point to them explicitly, e.g.: +# `lychee **/*.rs` +# To make things worse, `exclude_path` is ignored for these globs, +# so local runs with lots of gitignored files will be slow. +# (https://github.com/lycheeverse/lychee/issues/1405) +# +# This unfortunately doesn't list anything for non-glob checks. +################################################################################ + +# Maximum number of concurrent link checks. +# Workaround for "too many open files" error on MacOS, see https://github.com/lycheeverse/lychee/issues/1248 +max_concurrency = 32 + +# Check links inside `` and `
` blocks as well as Markdown code blocks.
+include_verbatim = true
+
+# Proceed for server connections considered insecure (invalid TLS).
+insecure = true
+
+# Exclude these filesystem paths from getting checked.
+exclude_path = [
+  # Unfortunately lychee doesn't yet read .gitignore https://github.com/lycheeverse/lychee/issues/1331
+  # The following entries are there because of that:
+  ".git",
+  "__pycache__",
+  "_deps/",
+  ".pixi",
+  "build",
+  "target_ra",
+  "target_wasm",
+  "target",
+  "venv",
+]
+
+# Exclude URLs and mail addresses from checking (supports regex).
+exclude = [
+  # Skip speculative links
+  '.*?speculative-link',
+
+  # Strings with replacements.
+  '/__VIEWER_VERSION__/', # Replacement variable __VIEWER_VERSION__.
+  '/\$',                  # Replacement variable $.
+  '/GIT_HASH/',           # Replacement variable GIT_HASH.
+  '\{\}',                 # Ignore links with string interpolation.
+  '\$relpath\^',          # Relative paths as used by rerun_cpp's doc header.
+  '%7B.+%7D',             # Ignore strings that look like ready to use links but contain a replacement strings. The URL escaping is for '{.+}' (this seems to be needed for html embedded urls since lychee assumes they use this encoding).
+  '%7B%7D',               # Ignore links with string interpolation, escaped variant.
+
+  # Local links that require further setup.
+  'http://127.0.0.1',
+  'http://localhost',
+  'recording:/',      # rrd recording link.
+  'ws:/',
+  're_viewer.js',     # Build artifact that html is linking to.
+
+  # Api endpoints.
+  'https://fonts.googleapis.com/', # Font API entrypoint, not a link.
+  'https://fonts.gstatic.com/',    # Font API entrypoint, not a link.
+  'https://tel.rerun.io/',         # Analytics endpoint.
+
+  # Avoid rate limiting.
+  'https://crates.io/crates/.*',                  # Avoid crates.io rate-limiting
+  'https://github.com/rerun-io/rerun/commit/\.*', # Ignore links to our own commits (typically in changelog).
+  'https://github.com/rerun-io/rerun/pull/\.*',   # Ignore links to our own pull requests (typically in changelog).
+]

From 0e29d16767417277c000383cc035613146a7b978 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 09:59:38 +0200
Subject: [PATCH 06/32] Add a PR template

---
 .github/pull_request_template.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 .github/pull_request_template.md

diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..52f1457
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,13 @@
+
+
+* Closes #ISSUE_NUMBER

From ff3c2675d80a77a278ad4d1c9b5b9f70cb8c93ff Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 09:59:45 +0200
Subject: [PATCH 07/32] Add a label checker CI step

---
 .github/workflows/labels.yml | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 .github/workflows/labels.yml

diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml
new file mode 100644
index 0000000..2c67f7b
--- /dev/null
+++ b/.github/workflows/labels.yml
@@ -0,0 +1,34 @@
+# Copied from https://github.com/rerun-io/rerun_template
+
+# https://github.com/marketplace/actions/require-labels
+# Check for existence of labels
+# See all our labels at https://github.com/rerun-io/rerun/issues/labels
+
+name: PR Labels
+
+on:
+  pull_request:
+    types:
+      - opened
+      - synchronize
+      - reopened
+      - labeled
+      - unlabeled
+
+jobs:
+  label:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Check for a "do-not-merge" label
+        uses: mheap/github-action-required-labels@v3
+        with:
+          mode: exactly
+          count: 0
+          labels: "do-not-merge"
+
+      - name: Require label "include in changelog" or "exclude from changelog"
+        uses: mheap/github-action-required-labels@v3
+        with:
+          mode: minimum
+          count: 1
+          labels: "exclude from changelog, include in changelog"

From 7137b617a37d095cd9b3343b2d14e78877407470 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:01:22 +0200
Subject: [PATCH 08/32] Use rust CI step from rerun_template

---
 .github/workflows/rust.yml | 129 ++++++++++++++++++++++++++++++-------
 1 file changed, 105 insertions(+), 24 deletions(-)

diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index e2d357d..ea37861 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -1,50 +1,131 @@
-name: Rust
-
+# Copied from https://github.com/rerun-io/rerun_template
 on:
   push:
-    branches: [ master ]
+    branches:
+      - "main"
   pull_request:
-    branches: [ master ]
+    types: [ opened, synchronize ]
+
+name: Rust
 
 env:
-  CARGO_TERM_COLOR: always
+  RUSTFLAGS: -D warnings
+  RUSTDOCFLAGS: -D warnings
 
 jobs:
-  build:
+  rust-check:
+    name: Rust
     runs-on: ubuntu-latest
     steps:
-      - name: Checkout sources
-        uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
-      - name: Install rust toolchain
-        uses: actions-rs/toolchain@v1
+      - uses: actions-rs/toolchain@v1
         with:
-          profile: minimal
-          toolchain: stable
+          profile: default
+          toolchain: 1.76.0
           override: true
-          components: rustfmt, clippy
 
-      - name: Setup rust smart caching
-        uses: Swatinem/rust-cache@v1.3.0
+      - name: Set up cargo cache
+        uses: Swatinem/rust-cache@v2
 
-      - name: Cargo fmt
+      - name: Rustfmt
         uses: actions-rs/cargo@v1
         with:
           command: fmt
           args: --all -- --check
 
-      - name: Cargo clippy
+      - name: check --all-features
         uses: actions-rs/cargo@v1
         with:
-          command: clippy
-          args: --no-deps -- -D warnings
-      
-      - name: Cargo build
+          command: check
+          args: --all-features --all-targets
+
+      - name: check default features
+        uses: actions-rs/cargo@v1
+        with:
+          command: check
+          args: --all-targets
+
+      - name: check --no-default-features
         uses: actions-rs/cargo@v1
         with:
-          command: build
-      
-      - name: Cargo test
+          command: check
+          args: --no-default-features --lib --all-targets
+
+      - name: Test doc-tests
         uses: actions-rs/cargo@v1
         with:
           command: test
+          args: --doc --all-features
+
+      - name: cargo doc --lib
+        uses: actions-rs/cargo@v1
+        with:
+          command: doc
+          args: --lib --no-deps --all-features
+
+      - name: cargo doc --document-private-items
+        uses: actions-rs/cargo@v1
+        with:
+          command: doc
+          args: --document-private-items --no-deps --all-features
+
+      - name: Build tests
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --all-features --no-run
+
+      - name: Run test
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --all-features
+
+      - name: Clippy
+        uses: actions-rs/cargo@v1
+        with:
+          command: clippy
+          args: --all-targets --all-features -- -D warnings
+
+  # ---------------------------------------------------------------------------
+
+  check_wasm:
+    name: Check wasm32
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: 1.76.0
+          target: wasm32-unknown-unknown
+          override: true
+          components: clippy
+
+      - name: Set up cargo cache
+        uses: Swatinem/rust-cache@v2
+
+      - name: Check wasm32
+        uses: actions-rs/cargo@v1
+        with:
+          command: check
+          args: --target wasm32-unknown-unknown --lib
+
+      - name: Clippy wasm32
+        env:
+          CLIPPY_CONF_DIR: "scripts/clippy_wasm" # Use scripts/clippy_wasm/clippy.toml
+        run: cargo clippy --target wasm32-unknown-unknown --lib -- -D warnings
+
+  # ---------------------------------------------------------------------------
+
+  cargo-deny:
+    name: Check Rust dependencies (cargo-deny)
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v3
+    - uses: EmbarkStudios/cargo-deny-action@v1
+      with:
+        rust-version: "1.76.0"
+        log-level: warn
+        command: check

From b1b358f3f137ad2dcea1116035c40a1e4044e5cf Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:04:36 +0200
Subject: [PATCH 09/32] Sort dependencies

---
 Cargo.toml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 3f1aa02..5e9d689 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,10 +13,10 @@ license = "MIT"
 include = ["src", "Cargo.toml", "README", "LICENSE"]
 
 [dependencies]
-thiserror = "^1.0"
 byteorder = "1"
 bytes = "1.1.0"
+log = "0.4.17"
 num-rational = { version = "0.4.0", features = ["serde"] }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
-log = "0.4.17"
+thiserror = "^1.0"

From 4b89b093cb56725679af6cb09ea9299be03dec71 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:06:34 +0200
Subject: [PATCH 10/32] Update `Cargo.toml`

---
 Cargo.toml | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 5e9d689..d40d881 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,16 +1,27 @@
 [package]
-name = "re_mp4"
-version = "0.1.0"
 authors = ["rerun.io "]
-edition = "2018"
+categories = ["Multimedia", "Video"]
 description = "MP4 parser"
-documentation = "https://docs.rs/re_mp4"
-readme = "README.md"
-homepage = "https://github.com/rerun-io/mp4"
-repository = "https://github.com/rerun-io/mp4"
+edition = "2021"
+homepage = "https://github.com/rerun-io/re_mp4"
+include = ["src", "Cargo.toml", "README", "LICENSE"]
 keywords = ["mp4", "iso-mp4", "isobmff", "video", "multimedia"]
 license = "MIT"
-include = ["src", "Cargo.toml", "README", "LICENSE"]
+name = "re_mp4"
+publish = true
+readme = "README.md"
+repository = "https://github.com/rerun-io/re_mp4"
+rust-version = "1.76"
+version = "0.1.0"
+
+[package.metadata.docs.rs]
+all-features = true
+targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]
+
+
+[features]
+default = []
+
 
 [dependencies]
 byteorder = "1"

From d3463b334e637aba9ade98966ada791de2a03937 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:06:40 +0200
Subject: [PATCH 11/32] Add a rust-toolchain

---
 rust-toolchain | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 rust-toolchain

diff --git a/rust-toolchain b/rust-toolchain
new file mode 100644
index 0000000..ae5c85c
--- /dev/null
+++ b/rust-toolchain
@@ -0,0 +1,10 @@
+# If you see this, run "rustup self update" to get rustup 1.23 or newer.
+
+# NOTE: above comment is for older `rustup` (before TOML support was added),
+# which will treat the first line as the toolchain name, and therefore show it
+# to the user in the error, instead of "error: invalid channel name '[toolchain]'".
+
+[toolchain]
+channel = "1.76"  # Avoid specifying a patch version here; see https://github.com/emilk/eframe_template/issues/145
+components = ["rustfmt", "clippy"]
+targets = ["wasm32-unknown-unknown"]

From 51a9b19b440c7a53078ec0d595e4ba387e4fa46f Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:06:57 +0200
Subject: [PATCH 12/32] Add cargo deny.toml

---
 deny.toml | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 deny.toml

diff --git a/deny.toml b/deny.toml
new file mode 100644
index 0000000..756b9e1
--- /dev/null
+++ b/deny.toml
@@ -0,0 +1,86 @@
+# Copied from https://github.com/rerun-io/rerun_template
+#
+# https://github.com/EmbarkStudios/cargo-deny
+#
+# cargo-deny checks our dependency tree for copy-left licenses,
+# duplicate dependencies, and rustsec advisories (https://rustsec.org/advisories).
+#
+# Install: `cargo install cargo-deny`
+# Check: `cargo deny check`.
+
+
+# Note: running just `cargo deny check` without a `--target` can result in
+# false positives due to https://github.com/EmbarkStudios/cargo-deny/issues/324
+[graph]
+targets = [
+  { triple = "aarch64-apple-darwin" },
+  { triple = "i686-pc-windows-gnu" },
+  { triple = "i686-pc-windows-msvc" },
+  { triple = "i686-unknown-linux-gnu" },
+  { triple = "wasm32-unknown-unknown" },
+  { triple = "x86_64-apple-darwin" },
+  { triple = "x86_64-pc-windows-gnu" },
+  { triple = "x86_64-pc-windows-msvc" },
+  { triple = "x86_64-unknown-linux-gnu" },
+  { triple = "x86_64-unknown-linux-musl" },
+  { triple = "x86_64-unknown-redox" },
+]
+all-features = true
+
+
+[advisories]
+version = 2
+ignore = []
+
+
+[bans]
+multiple-versions = "deny"
+wildcards = "deny"
+deny = [
+  { name = "openssl", reason = "Use rustls" },
+  { name = "openssl-sys", reason = "Use rustls" },
+]
+skip = []
+skip-tree = []
+
+
+[licenses]
+version = 2
+private = { ignore = true }
+confidence-threshold = 0.93 # We want really high confidence when inferring licenses from text
+allow = [
+  "Apache-2.0 WITH LLVM-exception", # https://spdx.org/licenses/LLVM-exception.html
+  "Apache-2.0",                     # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
+  "BSD-2-Clause",                   # https://tldrlegal.com/license/bsd-2-clause-license-(freebsd)
+  "BSD-3-Clause",                   # https://tldrlegal.com/license/bsd-3-clause-license-(revised)
+  "BSL-1.0",                        # https://tldrlegal.com/license/boost-software-license-1.0-explained
+  "CC0-1.0",                        # https://creativecommons.org/publicdomain/zero/1.0/
+  "ISC",                            # https://www.tldrlegal.com/license/isc-license
+  "LicenseRef-UFL-1.0",             # no official SPDX, see https://github.com/emilk/egui/issues/2321
+  "MIT-0",                          # https://choosealicense.com/licenses/mit-0/
+  "MIT",                            # https://tldrlegal.com/license/mit-license
+  "MPL-2.0",                        # https://www.mozilla.org/en-US/MPL/2.0/FAQ/ - see Q11. Used by webpki-roots on Linux.
+  "OFL-1.1",                        # https://spdx.org/licenses/OFL-1.1.html
+  "OpenSSL",                        # https://www.openssl.org/source/license.html - used on Linux
+  "Unicode-DFS-2016",               # https://spdx.org/licenses/Unicode-DFS-2016.html
+  "Zlib",                           # https://tldrlegal.com/license/zlib-libpng-license-(zlib)
+]
+exceptions = []
+
+[[licenses.clarify]]
+name = "webpki"
+expression = "ISC"
+license-files = [{ path = "LICENSE", hash = 0x001c7e6c }]
+
+[[licenses.clarify]]
+name = "ring"
+expression = "MIT AND ISC AND OpenSSL"
+license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
+
+
+[sources]
+unknown-registry = "deny"
+unknown-git = "deny"
+
+[sources.allow-org]
+github = ["emilk", "rerun-io"]

From 7aa36bf1ff9208458544c95b3df24739b3e463b5 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:07:11 +0200
Subject: [PATCH 13/32] Add code of conduct

---
 CODE_OF_CONDUCT.md | 132 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)
 create mode 100644 CODE_OF_CONDUCT.md

diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..1fbf07c
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,132 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+  community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+  any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+  without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+opensource@rerun.io.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations

From 6e6818d0ff7da7ce37d95d7a9a9fb353609ec0f2 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:07:27 +0200
Subject: [PATCH 14/32] Update .gitignore

---
 .gitignore | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/.gitignore b/.gitignore
index da8a060..747604c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,10 @@
-/target
-**/*.rs.bk
-*.exe
-*.pdb
-*.mp4
-.idea/
-.vscode/
-!tests/samples/*.mp4
+# Mac stuff:
+.DS_Store
+
+# Rust compile target directories:
+target
+target_ra
+target_wasm
+
+# https://github.com/lycheeverse/lychee
+.lycheecache

From d555b3d5d0c6ade9fab24328e5333744feba54aa Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:07:32 +0200
Subject: [PATCH 15/32] Add changelog generator

---
 scripts/generate_changelog.py | 181 ++++++++++++++++++++++++++++++++++
 1 file changed, 181 insertions(+)
 create mode 100755 scripts/generate_changelog.py

diff --git a/scripts/generate_changelog.py b/scripts/generate_changelog.py
new file mode 100755
index 0000000..77f2563
--- /dev/null
+++ b/scripts/generate_changelog.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python3
+# Copied from https://github.com/rerun-io/rerun_template
+
+"""
+Summarizes recent PRs based on their GitHub labels.
+
+The result can be copy-pasted into CHANGELOG.md,
+though it often needs some manual editing too.
+"""
+
+from __future__ import annotations
+
+import argparse
+import multiprocessing
+import os
+import re
+import sys
+from dataclasses import dataclass
+from typing import Any, Optional
+
+import requests
+from git import Repo  # pip install GitPython
+from tqdm import tqdm
+
+OWNER = "rerun-io"
+REPO = "re_mp4"
+INCLUDE_LABELS = False  # It adds quite a bit of visual noise
+
+
+@dataclass
+class PrInfo:
+    gh_user_name: str
+    pr_title: str
+    labels: list[str]
+
+
+@dataclass
+class CommitInfo:
+    hexsha: str
+    title: str
+    pr_number: Optional[int]
+
+
+def get_github_token() -> str:
+    token = os.environ.get("GH_ACCESS_TOKEN", "")
+    if token != "":
+        return token
+
+    home_dir = os.path.expanduser("~")
+    token_file = os.path.join(home_dir, ".githubtoken")
+
+    try:
+        with open(token_file, encoding="utf8") as f:
+            token = f.read().strip()
+        return token
+    except Exception:
+        pass
+
+    print("ERROR: expected a GitHub token in the environment variable GH_ACCESS_TOKEN or in ~/.githubtoken")
+    sys.exit(1)
+
+
+# Slow
+def fetch_pr_info_from_commit_info(commit_info: CommitInfo) -> Optional[PrInfo]:
+    if commit_info.pr_number is None:
+        return None
+    else:
+        return fetch_pr_info(commit_info.pr_number)
+
+
+# Slow
+def fetch_pr_info(pr_number: int) -> Optional[PrInfo]:
+    url = f"https://api.github.com/repos/{OWNER}/{REPO}/pulls/{pr_number}"
+    gh_access_token = get_github_token()
+    headers = {"Authorization": f"Token {gh_access_token}"}
+    response = requests.get(url, headers=headers)
+    json = response.json()
+
+    # Check if the request was successful (status code 200)
+    if response.status_code == 200:
+        labels = [label["name"] for label in json["labels"]]
+        gh_user_name = json["user"]["login"]
+        return PrInfo(gh_user_name=gh_user_name, pr_title=json["title"], labels=labels)
+    else:
+        print(f"ERROR {url}: {response.status_code} - {json['message']}")
+        return None
+
+
+def get_commit_info(commit: Any) -> CommitInfo:
+    match = re.match(r"(.*) \(#(\d+)\)", commit.summary)
+    if match:
+        title = str(match.group(1))
+        pr_number = int(match.group(2))
+        return CommitInfo(hexsha=commit.hexsha, title=title, pr_number=pr_number)
+    else:
+        return CommitInfo(hexsha=commit.hexsha, title=commit.summary, pr_number=None)
+
+
+def remove_prefix(text: str, prefix: str) -> str:
+    if text.startswith(prefix):
+        return text[len(prefix) :]
+    return text  # or whatever
+
+
+def print_section(crate: str, items: list[str]) -> None:
+    if 0 < len(items):
+        print(f"#### {crate}")
+        for line in items:
+            print(f"* {line}")
+    print()
+
+
+def main() -> None:
+    parser = argparse.ArgumentParser(description="Generate a changelog.")
+    parser.add_argument("--commit-range", help="e.g. 0.1.0..HEAD", required=True)
+    args = parser.parse_args()
+
+    repo = Repo(".")
+    commits = list(repo.iter_commits(args.commit_range))
+    commits.reverse()  # Most recent last
+    commit_infos = list(map(get_commit_info, commits))
+
+    pool = multiprocessing.Pool()
+    pr_infos = list(
+        tqdm(
+            pool.imap(fetch_pr_info_from_commit_info, commit_infos),
+            total=len(commit_infos),
+            desc="Fetch PR info commits",
+        )
+    )
+
+    prs = []
+    unsorted_commits = []
+
+    for commit_info, pr_info in zip(commit_infos, pr_infos):
+        hexsha = commit_info.hexsha
+        title = commit_info.title
+        title = title.rstrip(".").strip()  # Some PR end with an unnecessary period
+        pr_number = commit_info.pr_number
+
+        if pr_number is None:
+            # Someone committed straight to main:
+            summary = f"{title} [{hexsha[:7]}](https://github.com/{OWNER}/{REPO}/commit/{hexsha})"
+            unsorted_commits.append(summary)
+        else:
+            # We prefer the PR title if available
+            title = pr_info.pr_title if pr_info else title
+            labels = pr_info.labels if pr_info else []
+
+            if "exclude from changelog" in labels:
+                continue
+            if "typo" in labels:
+                # We get so many typo PRs. Let's not flood the changelog with them.
+                continue
+
+            summary = f"{title} [#{pr_number}](https://github.com/{OWNER}/{REPO}/pull/{pr_number})"
+
+            if INCLUDE_LABELS and 0 < len(labels):
+                summary += f" ({', '.join(labels)})"
+
+            if pr_info is not None:
+                gh_user_name = pr_info.gh_user_name
+                summary += f" by [@{gh_user_name}](https://github.com/{gh_user_name})"
+
+            prs.append(summary)
+
+    # Clean up:
+    for i in range(len(prs)):
+        line = prs[i]
+        line = line[0].upper() + line[1:]  # Upper-case first letter
+        prs[i] = line
+
+    print()
+    print(f"Full diff at https://github.com/{OWNER}/{REPO}/compare/{args.commit_range}")
+    print()
+    print_section("PRs", prs)
+    print_section("Unsorted commits", unsorted_commits)
+
+
+if __name__ == "__main__":
+    main()

From 86927f373ce7e297ed8e2cc2bc6ce125e35c9910 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:07:44 +0200
Subject: [PATCH 16/32] Add script to update from rerun_template

---
 scripts/template_update.py | 191 +++++++++++++++++++++++++++++++++++++
 1 file changed, 191 insertions(+)
 create mode 100755 scripts/template_update.py

diff --git a/scripts/template_update.py b/scripts/template_update.py
new file mode 100755
index 0000000..201871e
--- /dev/null
+++ b/scripts/template_update.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python3
+# Copied from https://github.com/rerun-io/rerun_template
+
+"""
+The script has two purposes.
+
+After using `rerun_template` as a template, run this to clean out things you don't need.
+Use `scripts/template_update.py init --languages cpp,rust,python` for this.
+
+Update an existing repository with the latest changes from the template.
+Use `scripts/template_update.py update --languages cpp,rust,python` for this.
+
+In either case, make sure the list of languages matches the languages you want to support.
+You can also use `--dry-run` to see what would happen without actually changing anything.
+"""
+
+from __future__ import annotations
+
+import argparse
+import os
+import shutil
+import tempfile
+
+from git import Repo  # pip install GitPython
+
+OWNER = "rerun-io"
+
+# Don't overwrite these when updating existing repository from the template
+DO_NOT_OVERWRITE = {
+    "Cargo.lock",
+    "CHANGELOG.md",
+    "main.py",
+    "pixi.lock",
+    "README.md",
+    "requirements.txt",
+}
+
+# Files required by C++, but not by _both_ Python and Rust
+CPP_FILES = {
+    ".clang-format",
+    ".github/workflows/cpp.yml",
+    "CMakeLists.txt",
+    "pixi.lock",  # Pixi is only C++ & Python - For Rust we only use cargo
+    "pixi.toml",  # Pixi is only C++ & Python - For Rust we only use cargo
+    "src/",
+    "src/main.cpp",
+}
+
+# Files required by Python, but not by _both_ C++ and Rust
+PYTHON_FILES = {
+    ".github/workflows/python.yml",
+    ".mypy.ini",
+    "main.py",
+    "pixi.lock",  # Pixi is only C++ & Python - For Rust we only use cargo
+    "pixi.toml",  # Pixi is only C++ & Python - For Rust we only use cargo
+    "pyproject.toml",
+    "requirements.txt",
+}
+
+# Files required by Rust, but not by _both_ C++ and Python
+RUST_FILES = {
+    ".github/workflows/rust.yml",
+    "bacon.toml",
+    "Cargo.lock",
+    "Cargo.toml",
+    "CHANGELOG.md",  # We only keep a changelog for Rust crates at the moment
+    "clippy.toml",
+    "Cranky.toml",
+    "deny.toml",
+    "rust-toolchain",
+    "scripts/clippy_wasm/",
+    "scripts/clippy_wasm/clippy.toml",
+    "scripts/generate_changelog.py",  # We only keep a changelog for Rust crates at the moment
+    "src/",
+    "src/lib.rs",
+    "src/main.rs",
+}
+
+# Files we used to have, but have been removed in never version of rerun_template
+DEAD_FILES = ["bacon.toml", "Cranky.toml"]
+
+
+def parse_languages(lang_str: str) -> set[str]:
+    languages = lang_str.split(",") if lang_str else []
+    for lang in languages:
+        assert lang in ["cpp", "python", "rust"], f"Unsupported language: {lang}"
+    return set(languages)
+
+
+def calc_deny_set(languages: set[str]) -> set[str]:
+    """The set of files to delete/ignore."""
+    files_to_delete = CPP_FILES | PYTHON_FILES | RUST_FILES
+    if "cpp" in languages:
+        files_to_delete -= CPP_FILES
+    if "python" in languages:
+        files_to_delete -= PYTHON_FILES
+    if "rust" in languages:
+        files_to_delete -= RUST_FILES
+    return files_to_delete
+
+
+def init(languages: set[str], dry_run: bool) -> None:
+    print("Removing all language-specific files not needed for languages {languages}.")
+    files_to_delete = calc_deny_set(languages)
+    delete_files_and_folder(files_to_delete, dry_run)
+
+
+def remove_file(filepath: str) -> None:
+    try:
+        os.remove(filepath)
+    except FileNotFoundError:
+        pass
+
+
+def delete_files_and_folder(paths: set[str], dry_run: bool) -> None:
+    repo_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+    for path in paths:
+        full_path = os.path.join(repo_path, path)
+        if os.path.exists(full_path):
+            if os.path.isfile(full_path):
+                print(f"Removing file {full_path}…")
+                if not dry_run:
+                    remove_file(full_path)
+            elif os.path.isdir(full_path):
+                print(f"Removing folder {full_path}…")
+                if not dry_run:
+                    shutil.rmtree(full_path)
+
+
+def update(languages: set[str], dry_run: bool) -> None:
+    for file in DEAD_FILES:
+        print(f"Removing dead file {file}…")
+        if not dry_run:
+            remove_file(file)
+
+    files_to_ignore = calc_deny_set(languages) | DO_NOT_OVERWRITE
+    repo_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+
+    with tempfile.TemporaryDirectory() as temp_dir:
+        Repo.clone_from("https://github.com/rerun-io/rerun_template.git", temp_dir)
+        for root, dirs, files in os.walk(temp_dir):
+            for file in files:
+                src_path = os.path.join(root, file)
+                rel_path = os.path.relpath(src_path, temp_dir)
+
+                if rel_path.startswith(".git/"):
+                    continue
+                if rel_path.startswith("src/"):
+                    continue
+                if rel_path in files_to_ignore:
+                    continue
+
+                dest_path = os.path.join(repo_path, rel_path)
+
+                print(f"Updating {rel_path}…")
+                if not dry_run:
+                    os.makedirs(os.path.dirname(dest_path), exist_ok=True)
+                    shutil.copy2(src_path, dest_path)
+
+
+def main() -> None:
+    parser = argparse.ArgumentParser(description="Handle the Rerun template.")
+    subparsers = parser.add_subparsers(dest="command")
+
+    init_parser = subparsers.add_parser("init", help="Initialize a new checkout of the template.")
+    init_parser.add_argument(
+        "--languages", default="", nargs="?", const="", help="The languages to support (e.g. `cpp,python,rust`)."
+    )
+    init_parser.add_argument("--dry-run", action="store_true", help="Don't actually delete any files.")
+
+    update_parser = subparsers.add_parser(
+        "update", help="Update all existing Rerun repositories with the latest changes from the template"
+    )
+    update_parser.add_argument(
+        "--languages", default="", nargs="?", const="", help="The languages to support (e.g. `cpp,python,rust`)."
+    )
+    update_parser.add_argument("--dry-run", action="store_true", help="Don't actually delete any files.")
+
+    args = parser.parse_args()
+
+    if args.command == "init":
+        init(parse_languages(args.languages), args.dry_run)
+    elif args.command == "update":
+        update(parse_languages(args.languages), args.dry_run)
+    else:
+        parser.print_help()
+        exit(1)
+
+
+if __name__ == "__main__":
+    main()

From 36ece63df86036cc313dd98d5ddda2fdddb60c39 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:15:17 +0200
Subject: [PATCH 17/32] `cargo clippy --fix`

---
 src/mp4box/av01.rs |   9 +-
 src/mp4box/avc1.rs |  17 ++-
 src/mp4box/co64.rs |   7 +-
 src/mp4box/ctts.rs |   7 +-
 src/mp4box/data.rs |   6 +-
 src/mp4box/dinf.rs |  15 +-
 src/mp4box/edts.rs |  10 +-
 src/mp4box/elst.rs |   7 +-
 src/mp4box/emsg.rs |   7 +-
 src/mp4box/ftyp.rs |   8 +-
 src/mp4box/hdlr.rs |   7 +-
 src/mp4box/hvc1.rs |  13 +-
 src/mp4box/ilst.rs |   9 +-
 src/mp4box/mdhd.rs |  11 +-
 src/mp4box/mdia.rs |   7 +-
 src/mp4box/mehd.rs |   7 +-
 src/mp4box/meta.rs |  11 +-
 src/mp4box/mfhd.rs |   9 +-
 src/mp4box/minf.rs |   7 +-
 src/mp4box/mod.rs  |   9 +-
 src/mp4box/moof.rs |   9 +-
 src/mp4box/moov.rs |   9 +-
 src/mp4box/mp4a.rs |  19 +--
 src/mp4box/mvex.rs |   9 +-
 src/mp4box/mvhd.rs |   9 +-
 src/mp4box/smhd.rs |   9 +-
 src/mp4box/stbl.rs |   7 +-
 src/mp4box/stco.rs |   7 +-
 src/mp4box/stsc.rs |  11 +-
 src/mp4box/stsd.rs |   8 +-
 src/mp4box/stss.rs |   7 +-
 src/mp4box/stsz.rs |   7 +-
 src/mp4box/stts.rs |   7 +-
 src/mp4box/tfdt.rs |   7 +-
 src/mp4box/tfhd.rs |  27 ++--
 src/mp4box/tkhd.rs |   9 +-
 src/mp4box/traf.rs |   7 +-
 src/mp4box/trak.rs |   7 +-
 src/mp4box/trex.rs |   7 +-
 src/mp4box/trun.rs |  51 +++----
 src/mp4box/tx3g.rs |   6 +-
 src/mp4box/udta.rs |   7 +-
 src/mp4box/vmhd.rs |   7 +-
 src/mp4box/vp08.rs |   5 +-
 src/mp4box/vp09.rs |   5 +-
 src/mp4box/vpcc.rs |   5 +-
 src/reader.rs      |  10 +-
 src/types.rs       | 342 ++++++++++++++++++++++-----------------------
 tests/lib.rs       |   6 +-
 49 files changed, 473 insertions(+), 336 deletions(-)

diff --git a/src/mp4box/av01.rs b/src/mp4box/av01.rs
index d3ac0a0..e0ada0c 100644
--- a/src/mp4box/av01.rs
+++ b/src/mp4box/av01.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_bytes, skip_bytes_to, value_u32, BoxHeader, BoxType, Error, FixedPointU16,
+    Mp4Box, RawBox, ReadBox, Result, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct Av01Box {
@@ -81,7 +84,7 @@ impl ReadBox<&mut R> for Av01Box {
 
             skip_bytes_to(reader, start + size)?;
 
-            Ok(Av01Box {
+            Ok(Self {
                 data_reference_index,
                 width,
                 height,
@@ -171,7 +174,7 @@ impl ReadBox<&mut R> for Av1CBox {
         let mut config_obus = vec![0u8; config_obus_size as usize];
         reader.read_exact(&mut config_obus)?;
 
-        Ok(Av1CBox {
+        Ok(Self {
             profile,
             level,
             tier,
diff --git a/src/mp4box/avc1.rs b/src/mp4box/avc1.rs
index a021538..25f6208 100644
--- a/src/mp4box/avc1.rs
+++ b/src/mp4box/avc1.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_bytes, skip_bytes_to, value_u32, BoxHeader, BoxType, Error, FixedPointU16,
+    Mp4Box, RawBox, ReadBox, Result, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct Avc1Box {
@@ -22,7 +25,7 @@ pub struct Avc1Box {
 
 impl Default for Avc1Box {
     fn default() -> Self {
-        Avc1Box {
+        Self {
             data_reference_index: 0,
             width: 0,
             height: 0,
@@ -106,7 +109,7 @@ impl ReadBox<&mut R> for Avc1Box {
 
                 skip_bytes_to(reader, start + size)?;
 
-                return Ok(Avc1Box {
+                return Ok(Self {
                     data_reference_index,
                     width,
                     height,
@@ -157,10 +160,10 @@ impl Mp4Box for AvcCBox {
 
     fn box_size(&self) -> u64 {
         let mut size = HEADER_SIZE + 7;
-        for sps in self.sequence_parameter_sets.iter() {
+        for sps in &self.sequence_parameter_sets {
             size += sps.size() as u64;
         }
-        for pps in self.picture_parameter_sets.iter() {
+        for pps in &self.picture_parameter_sets {
             size += pps.size() as u64;
         }
         size
@@ -206,7 +209,7 @@ impl ReadBox<&mut R> for AvcCBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(AvcCBox {
+        Ok(Self {
             configuration_version,
             avc_profile_indication,
             profile_compatibility,
@@ -241,6 +244,6 @@ impl NalUnit {
         let length = reader.read_u16::()? as usize;
         let mut bytes = vec![0u8; length];
         reader.read_exact(&mut bytes)?;
-        Ok(NalUnit { bytes })
+        Ok(Self { bytes })
     }
 }
diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs
index b0ab79d..d164551 100644
--- a/src/mp4box/co64.rs
+++ b/src/mp4box/co64.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct Co64Box {
@@ -71,7 +74,7 @@ impl ReadBox<&mut R> for Co64Box {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(Co64Box {
+        Ok(Self {
             version,
             flags,
             entries,
diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs
index c413ab3..bd855ca 100644
--- a/src/mp4box/ctts.rs
+++ b/src/mp4box/ctts.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct CttsBox {
@@ -81,7 +84,7 @@ impl ReadBox<&mut R> for CttsBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(CttsBox {
+        Ok(Self {
             version,
             flags,
             entries,
diff --git a/src/mp4box/data.rs b/src/mp4box/data.rs
index 505307e..8ae57f4 100644
--- a/src/mp4box/data.rs
+++ b/src/mp4box/data.rs
@@ -5,7 +5,9 @@ use std::{
 
 use serde::Serialize;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, BigEndian, BoxType, DataType, Mp4Box, ReadBox, ReadBytesExt, Result, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct DataBox {
@@ -58,6 +60,6 @@ impl ReadBox<&mut R> for DataBox {
         let mut data = vec![0u8; (start + size - current) as usize];
         reader.read_exact(&mut data)?;
 
-        Ok(DataBox { data, data_type })
+        Ok(Self { data, data_type })
     }
 }
diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs
index cc05a5c..6aaad7d 100644
--- a/src/mp4box/dinf.rs
+++ b/src/mp4box/dinf.rs
@@ -1,7 +1,10 @@
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_box, skip_bytes_to, BigEndian, BoxHeader, BoxType, Error,
+    Mp4Box, ReadBox, ReadBytesExt, Result, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct DinfBox {
@@ -74,7 +77,7 @@ impl ReadBox<&mut R> for DinfBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(DinfBox {
+        Ok(Self {
             dref: dref.unwrap(),
         })
     }
@@ -91,7 +94,7 @@ pub struct DrefBox {
 
 impl Default for DrefBox {
     fn default() -> Self {
-        DrefBox {
+        Self {
             version: 0,
             flags: 0,
             url: Some(UrlBox::default()),
@@ -172,7 +175,7 @@ impl ReadBox<&mut R> for DrefBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(DrefBox {
+        Ok(Self {
             version,
             flags,
             url,
@@ -189,7 +192,7 @@ pub struct UrlBox {
 
 impl Default for UrlBox {
     fn default() -> Self {
-        UrlBox {
+        Self {
             version: 0,
             flags: 1,
             location: String::default(),
@@ -251,7 +254,7 @@ impl ReadBox<&mut R> for UrlBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(UrlBox {
+        Ok(Self {
             version,
             flags,
             location,
diff --git a/src/mp4box/edts.rs b/src/mp4box/edts.rs
index 82427eb..d80ef03 100644
--- a/src/mp4box/edts.rs
+++ b/src/mp4box/edts.rs
@@ -2,7 +2,9 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 
 use crate::mp4box::elst::ElstBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct EdtsBox {
@@ -10,7 +12,7 @@ pub struct EdtsBox {
 }
 
 impl EdtsBox {
-    pub(crate) fn new() -> EdtsBox {
+    pub(crate) fn new() -> Self {
         Default::default()
     }
 
@@ -50,7 +52,7 @@ impl ReadBox<&mut R> for EdtsBox {
     fn read_box(reader: &mut R, size: u64) -> Result {
         let start = box_start(reader)?;
 
-        let mut edts = EdtsBox::new();
+        let mut edts = Self::new();
 
         let header = BoxHeader::read(reader)?;
         let BoxHeader { name, size: s } = header;
@@ -60,7 +62,7 @@ impl ReadBox<&mut R> for EdtsBox {
             ));
         }
 
-        if let BoxType::ElstBox = name {
+        if name == BoxType::ElstBox {
             let elst = ElstBox::read_box(reader, s)?;
             edts.elst = Some(elst);
         }
diff --git a/src/mp4box/elst.rs b/src/mp4box/elst.rs
index 83444da..d34b0ca 100644
--- a/src/mp4box/elst.rs
+++ b/src/mp4box/elst.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct ElstBox {
@@ -111,7 +114,7 @@ impl ReadBox<&mut R> for ElstBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(ElstBox {
+        Ok(Self {
             version,
             flags,
             entries,
diff --git a/src/mp4box/emsg.rs b/src/mp4box/emsg.rs
index 27540b8..0554516 100644
--- a/src/mp4box/emsg.rs
+++ b/src/mp4box/emsg.rs
@@ -4,7 +4,10 @@ use std::io::{Read, Seek};
 use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct EmsgBox {
@@ -105,7 +108,7 @@ impl ReadBox<&mut R> for EmsgBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(EmsgBox {
+        Ok(Self {
             version,
             flags,
             timescale,
diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs
index f195e67..5e972f5 100644
--- a/src/mp4box/ftyp.rs
+++ b/src/mp4box/ftyp.rs
@@ -2,7 +2,9 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_bytes_to, BoxType, Error, FourCC, Mp4Box, ReadBox, Result, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct FtypBox {
@@ -36,7 +38,7 @@ impl Mp4Box for FtypBox {
 
     fn summary(&self) -> Result {
         let mut compatible_brands = Vec::new();
-        for brand in self.compatible_brands.iter() {
+        for brand in &self.compatible_brands {
             compatible_brands.push(brand.to_string());
         }
         let s = format!(
@@ -68,7 +70,7 @@ impl ReadBox<&mut R> for FtypBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(FtypBox {
+        Ok(Self {
             major_brand: From::from(major),
             minor_version: minor,
             compatible_brands: brands,
diff --git a/src/mp4box/hdlr.rs b/src/mp4box/hdlr.rs
index d4c1378..1ab2b91 100644
--- a/src/mp4box/hdlr.rs
+++ b/src/mp4box/hdlr.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes, skip_bytes_to, BoxType, Error, FourCC, Mp4Box,
+    ReadBox, Result, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct HdlrBox {
@@ -65,7 +68,7 @@ impl ReadBox<&mut R> for HdlrBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(HdlrBox {
+        Ok(Self {
             version,
             flags,
             handler_type: From::from(handler),
diff --git a/src/mp4box/hvc1.rs b/src/mp4box/hvc1.rs
index 0538798..915722a 100644
--- a/src/mp4box/hvc1.rs
+++ b/src/mp4box/hvc1.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_bytes, skip_bytes_to, value_u32, BoxHeader, BoxType, Error, FixedPointU16,
+    Mp4Box, RawBox, ReadBox, Result, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct Hvc1Box {
@@ -22,7 +25,7 @@ pub struct Hvc1Box {
 
 impl Default for Hvc1Box {
     fn default() -> Self {
-        Hvc1Box {
+        Self {
             data_reference_index: 0,
             width: 0,
             height: 0,
@@ -100,7 +103,7 @@ impl ReadBox<&mut R> for Hvc1Box {
 
             skip_bytes_to(reader, start + size)?;
 
-            Ok(Hvc1Box {
+            Ok(Self {
                 data_reference_index,
                 width,
                 height,
@@ -240,7 +243,7 @@ impl ReadBox<&mut R> for HvcCBox {
 
                 reader.read_exact(&mut data)?;
 
-                nalus.push(HvcCArrayNalu { size, data })
+                nalus.push(HvcCArrayNalu { size, data });
             }
 
             arrays.push(HvcCArray {
@@ -250,7 +253,7 @@ impl ReadBox<&mut R> for HvcCBox {
             });
         }
 
-        Ok(HvcCBox {
+        Ok(Self {
             configuration_version,
             general_profile_space,
             general_tier_flag,
diff --git a/src/mp4box/ilst.rs b/src/mp4box/ilst.rs
index 1a7abad..b3f7c20 100644
--- a/src/mp4box/ilst.rs
+++ b/src/mp4box/ilst.rs
@@ -6,7 +6,10 @@ use byteorder::ByteOrder;
 use serde::Serialize;
 
 use crate::mp4box::data::DataBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BigEndian, BoxHeader, BoxType, DataType, Error, Metadata,
+    MetadataKey, Mp4Box, ReadBox, ReadBytesExt, Result, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct IlstBox {
@@ -88,7 +91,7 @@ impl ReadBox<&mut R> for IlstBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(IlstBox { items })
+        Ok(Self { items })
     }
 }
 
@@ -140,7 +143,7 @@ impl ReadBox<&mut R> for IlstItemBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(IlstItemBox {
+        Ok(Self {
             data: data.unwrap(),
         })
     }
diff --git a/src/mp4box/mdhd.rs b/src/mp4box/mdhd.rs
index 8cfc42f..31e6ec7 100644
--- a/src/mp4box/mdhd.rs
+++ b/src/mp4box/mdhd.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct MdhdBox {
@@ -36,7 +39,7 @@ impl MdhdBox {
 
 impl Default for MdhdBox {
     fn default() -> Self {
-        MdhdBox {
+        Self {
             version: 0,
             flags: 0,
             creation_time: 0,
@@ -98,7 +101,7 @@ impl ReadBox<&mut R> for MdhdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MdhdBox {
+        Ok(Self {
             version,
             flags,
             creation_time,
@@ -118,7 +121,7 @@ fn language_string(language: u16) -> String {
     lang[2] = ((language) & 0x1F) + 0x60;
 
     // Decode utf-16 encoded bytes into a string.
-    let lang_str = decode_utf16(lang.iter().cloned())
+    let lang_str = decode_utf16(lang.iter().copied())
         .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
         .collect::();
 
diff --git a/src/mp4box/mdia.rs b/src/mp4box/mdia.rs
index d4f8b52..e2b991f 100644
--- a/src/mp4box/mdia.rs
+++ b/src/mp4box/mdia.rs
@@ -1,7 +1,10 @@
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{hdlr::HdlrBox, mdhd::MdhdBox, minf::MinfBox};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -91,7 +94,7 @@ impl ReadBox<&mut R> for MdiaBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MdiaBox {
+        Ok(Self {
             mdhd: mdhd.unwrap(),
             hdlr: hdlr.unwrap(),
             minf: minf.unwrap(),
diff --git a/src/mp4box/mehd.rs b/src/mp4box/mehd.rs
index 41bb5d6..dd0edd8 100644
--- a/src/mp4box/mehd.rs
+++ b/src/mp4box/mehd.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
 pub struct MehdBox {
@@ -62,7 +65,7 @@ impl ReadBox<&mut R> for MehdBox {
         };
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MehdBox {
+        Ok(Self {
             version,
             flags,
             fragment_duration,
diff --git a/src/mp4box/meta.rs b/src/mp4box/meta.rs
index ae2fbc3..4571b74 100644
--- a/src/mp4box/meta.rs
+++ b/src/mp4box/meta.rs
@@ -4,7 +4,10 @@ use serde::Serialize;
 
 use crate::mp4box::hdlr::HdlrBox;
 use crate::mp4box::ilst::IlstBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, BigEndian, BoxHeader, BoxType, Error, FourCC, Mp4Box, ReadBox,
+    ReadBytesExt, Result, SeekFrom, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 #[serde(tag = "hdlr")]
@@ -46,7 +49,7 @@ impl MetaBox {
                     + data
                         .iter()
                         .map(|(_, data)| data.len() as u64 + HEADER_SIZE)
-                        .sum::()
+                        .sum::();
             }
         }
         size
@@ -160,7 +163,7 @@ impl ReadBox<&mut R> for MetaBox {
                     current = reader.stream_position()?;
                 }
 
-                Ok(MetaBox::Mdir { ilst })
+                Ok(Self::Mdir { ilst })
             }
             _ => {
                 let mut data = Vec::new();
@@ -185,7 +188,7 @@ impl ReadBox<&mut R> for MetaBox {
                     current = reader.stream_position()?;
                 }
 
-                Ok(MetaBox::Unknown { hdlr, data })
+                Ok(Self::Unknown { hdlr, data })
             }
         }
     }
diff --git a/src/mp4box/mfhd.rs b/src/mp4box/mfhd.rs
index 6b90c6a..9f58e09 100644
--- a/src/mp4box/mfhd.rs
+++ b/src/mp4box/mfhd.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct MfhdBox {
@@ -13,7 +16,7 @@ pub struct MfhdBox {
 
 impl Default for MfhdBox {
     fn default() -> Self {
-        MfhdBox {
+        Self {
             version: 0,
             flags: 0,
             sequence_number: 1,
@@ -59,7 +62,7 @@ impl ReadBox<&mut R> for MfhdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MfhdBox {
+        Ok(Self {
             version,
             flags,
             sequence_number,
diff --git a/src/mp4box/minf.rs b/src/mp4box/minf.rs
index d4e0d9f..0e454a7 100644
--- a/src/mp4box/minf.rs
+++ b/src/mp4box/minf.rs
@@ -1,7 +1,10 @@
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{dinf::DinfBox, smhd::SmhdBox, stbl::StblBox, vmhd::VmhdBox};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -106,7 +109,7 @@ impl ReadBox<&mut R> for MinfBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MinfBox {
+        Ok(Self {
             vmhd,
             smhd,
             dinf: dinf.unwrap(),
diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs
index 1335221..7278618 100644
--- a/src/mp4box/mod.rs
+++ b/src/mp4box/mod.rs
@@ -61,7 +61,10 @@ use serde::Serialize;
 use std::convert::TryInto;
 use std::io::{Read, Seek, SeekFrom};
 
-use crate::*;
+use crate::{
+    AacConfig, DataType, Error, FixedPointI8, FixedPointU16, FixedPointU8, FourCC, Metadata,
+    MetadataKey, Result, TrackKind,
+};
 
 pub(crate) mod av01;
 pub(crate) mod avc1;
@@ -292,7 +295,7 @@ impl BoxHeader {
             reader.read_exact(&mut buf)?;
             let largesize = u64::from_be_bytes(buf);
 
-            Ok(BoxHeader {
+            Ok(Self {
                 name: BoxType::from(typ),
 
                 // Subtract the length of the serialized largesize, as callers assume `size - HEADER_SIZE` is the length
@@ -305,7 +308,7 @@ impl BoxHeader {
                 },
             })
         } else {
-            Ok(BoxHeader {
+            Ok(Self {
                 name: BoxType::from(typ),
                 size: size as u64,
             })
diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs
index 641936b..516294d 100644
--- a/src/mp4box/moof.rs
+++ b/src/mp4box/moof.rs
@@ -1,7 +1,10 @@
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{mfhd::MfhdBox, traf::TrafBox};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -22,7 +25,7 @@ impl MoofBox {
 
     pub fn get_size(&self) -> u64 {
         let mut size = HEADER_SIZE + self.mfhd.box_size();
-        for traf in self.trafs.iter() {
+        for traf in &self.trafs {
             size += traf.box_size();
         }
         size
@@ -89,7 +92,7 @@ impl ReadBox<&mut R> for MoofBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MoofBox {
+        Ok(Self {
             start,
             mfhd: mfhd.unwrap(),
             trafs,
diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs
index a65d354..2302fe5 100644
--- a/src/mp4box/moov.rs
+++ b/src/mp4box/moov.rs
@@ -2,7 +2,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 
 use crate::meta::MetaBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{mvex::MvexBox, mvhd::MvhdBox, trak::TrakBox, udta::UdtaBox};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -29,7 +32,7 @@ impl MoovBox {
 
     pub fn get_size(&self) -> u64 {
         let mut size = HEADER_SIZE + self.mvhd.box_size();
-        for trak in self.traks.iter() {
+        for trak in &self.traks {
             size += trak.box_size();
         }
         if let Some(meta) = &self.meta {
@@ -115,7 +118,7 @@ impl ReadBox<&mut R> for MoovBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MoovBox {
+        Ok(Self {
             mvhd: mvhd.unwrap(),
             meta,
             udta,
diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs
index fa9c83e..ccdb18b 100644
--- a/src/mp4box/mp4a.rs
+++ b/src/mp4box/mp4a.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes, skip_bytes_to, value_u32, AacConfig, BoxHeader,
+    BoxType, Error, FixedPointU16, Mp4Box, ReadBox, Result, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct Mp4aBox {
@@ -125,7 +128,7 @@ impl ReadBox<&mut R> for Mp4aBox {
 
         skip_bytes_to(reader, end)?;
 
-        Ok(Mp4aBox {
+        Ok(Self {
             data_reference_index,
             channelcount,
             samplesize,
@@ -201,7 +204,7 @@ impl ReadBox<&mut R> for EsdsBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(EsdsBox {
+        Ok(Self {
             version,
             flags,
             es_desc: es_desc.unwrap(),
@@ -304,7 +307,7 @@ impl ReadDesc<&mut R> for ESDescriptor {
             current = reader.stream_position()?;
         }
 
-        Ok(ESDescriptor {
+        Ok(Self {
             es_id,
             dec_config: dec_config.unwrap_or_default(),
             sl_config: sl_config.unwrap_or_default(),
@@ -379,7 +382,7 @@ impl ReadDesc<&mut R> for DecoderConfigDescriptor {
             current = reader.stream_position()?;
         }
 
-        Ok(DecoderConfigDescriptor {
+        Ok(Self {
             object_type_indication,
             stream_type,
             up_stream,
@@ -463,7 +466,7 @@ impl ReadDesc<&mut R> for DecoderSpecificDescriptor {
             chan_conf = get_chan_conf(reader, byte_b, freq_index, false)?;
         }
 
-        Ok(DecoderSpecificDescriptor {
+        Ok(Self {
             profile,
             freq_index,
             chan_conf,
@@ -476,7 +479,7 @@ pub struct SLConfigDescriptor {}
 
 impl SLConfigDescriptor {
     pub fn new() -> Self {
-        SLConfigDescriptor {}
+        Self {}
     }
 }
 
@@ -494,6 +497,6 @@ impl ReadDesc<&mut R> for SLConfigDescriptor {
     fn read_desc(reader: &mut R, _size: u32) -> Result {
         reader.read_u8()?; // pre-defined
 
-        Ok(SLConfigDescriptor {})
+        Ok(Self {})
     }
 }
diff --git a/src/mp4box/mvex.rs b/src/mp4box/mvex.rs
index b6d366a..e60013f 100644
--- a/src/mp4box/mvex.rs
+++ b/src/mp4box/mvex.rs
@@ -1,7 +1,10 @@
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{mehd::MehdBox, trex::TrexBox};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -17,7 +20,7 @@ impl MvexBox {
 
     pub fn get_size(&self) -> u64 {
         HEADER_SIZE
-            + self.mehd.as_ref().map(|x| x.box_size()).unwrap_or(0)
+            + self.mehd.as_ref().map_or(0, |x| x.box_size())
             + self.trexs.iter().map(|x| x.box_size()).sum::()
     }
 }
@@ -82,6 +85,6 @@ impl ReadBox<&mut R> for MvexBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MvexBox { mehd, trexs })
+        Ok(Self { mehd, trexs })
     }
 }
diff --git a/src/mp4box/mvhd.rs b/src/mp4box/mvhd.rs
index 2388fdb..2b2c734 100644
--- a/src/mp4box/mvhd.rs
+++ b/src/mp4box/mvhd.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes, skip_bytes_to, tkhd, value_u32, value_u8, BoxType,
+    Error, FixedPointU16, FixedPointU8, Mp4Box, ReadBox, Result, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct MvhdBox {
@@ -42,7 +45,7 @@ impl MvhdBox {
 
 impl Default for MvhdBox {
     fn default() -> Self {
-        MvhdBox {
+        Self {
             version: 0,
             flags: 0,
             creation_time: 0,
@@ -134,7 +137,7 @@ impl ReadBox<&mut R> for MvhdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(MvhdBox {
+        Ok(Self {
             version,
             flags,
             creation_time,
diff --git a/src/mp4box/smhd.rs b/src/mp4box/smhd.rs
index 43b07b8..7c4c44c 100644
--- a/src/mp4box/smhd.rs
+++ b/src/mp4box/smhd.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, value_i16, BoxType, FixedPointI8, Mp4Box,
+    ReadBox, Result, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct SmhdBox {
@@ -25,7 +28,7 @@ impl SmhdBox {
 
 impl Default for SmhdBox {
     fn default() -> Self {
-        SmhdBox {
+        Self {
             version: 0,
             flags: 0,
             balance: FixedPointI8::new_raw(0),
@@ -62,7 +65,7 @@ impl ReadBox<&mut R> for SmhdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(SmhdBox {
+        Ok(Self {
             version,
             flags,
             balance,
diff --git a/src/mp4box/stbl.rs b/src/mp4box/stbl.rs
index 5b1240e..4a196af 100644
--- a/src/mp4box/stbl.rs
+++ b/src/mp4box/stbl.rs
@@ -1,7 +1,10 @@
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{
     co64::Co64Box, ctts::CttsBox, stco::StcoBox, stsc::StscBox, stsd::StsdBox, stss::StssBox,
     stsz::StszBox, stts::SttsBox,
@@ -149,7 +152,7 @@ impl ReadBox<&mut R> for StblBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(StblBox {
+        Ok(Self {
             stsd: stsd.unwrap(),
             stts: stts.unwrap(),
             ctts,
diff --git a/src/mp4box/stco.rs b/src/mp4box/stco.rs
index 142a8c4..82b02a4 100644
--- a/src/mp4box/stco.rs
+++ b/src/mp4box/stco.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, co64, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct StcoBox {
@@ -71,7 +74,7 @@ impl ReadBox<&mut R> for StcoBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(StcoBox {
+        Ok(Self {
             version,
             flags,
             entries,
diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs
index 02b09c4..484957c 100644
--- a/src/mp4box/stsc.rs
+++ b/src/mp4box/stsc.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct StscBox {
@@ -85,12 +88,12 @@ impl ReadBox<&mut R> for StscBox {
         let mut sample_id = 1;
         for i in 0..entry_count {
             let (first_chunk, samples_per_chunk) = {
-                let entry = entries.get_mut(i as usize).unwrap();
+                let entry = &mut entries[i as usize];
                 entry.first_sample = sample_id;
                 (entry.first_chunk, entry.samples_per_chunk)
             };
             if i < entry_count - 1 {
-                let next_entry = entries.get(i as usize + 1).unwrap();
+                let next_entry = &entries[i as usize + 1];
                 sample_id = next_entry
                     .first_chunk
                     .checked_sub(first_chunk)
@@ -104,7 +107,7 @@ impl ReadBox<&mut R> for StscBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(StscBox {
+        Ok(Self {
             version,
             flags,
             entries,
diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs
index f7e98ec..f10f33d 100644
--- a/src/mp4box/stsd.rs
+++ b/src/mp4box/stsd.rs
@@ -2,7 +2,11 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, Av01Box, Avc1Box, BoxHeader, BoxType, Error,
+    Hvc1Box, Mp4Box, Mp4aBox, ReadBox, Result, TrackKind, Tx3gBox, Vp08Box, Vp09Box,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct StsdBox {
@@ -152,7 +156,7 @@ impl ReadBox<&mut R> for StsdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(StsdBox {
+        Ok(Self {
             version,
             flags,
             av01,
diff --git a/src/mp4box/stss.rs b/src/mp4box/stss.rs
index d11d4aa..6f99abf 100644
--- a/src/mp4box/stss.rs
+++ b/src/mp4box/stss.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct StssBox {
@@ -71,7 +74,7 @@ impl ReadBox<&mut R> for StssBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(StssBox {
+        Ok(Self {
             version,
             flags,
             entries,
diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs
index be08078..7610661 100644
--- a/src/mp4box/stsz.rs
+++ b/src/mp4box/stsz.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct StszBox {
@@ -86,7 +89,7 @@ impl ReadBox<&mut R> for StszBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(StszBox {
+        Ok(Self {
             version,
             flags,
             sample_size,
diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs
index ec9f777..9866529 100644
--- a/src/mp4box/stts.rs
+++ b/src/mp4box/stts.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct SttsBox {
@@ -80,7 +83,7 @@ impl ReadBox<&mut R> for SttsBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(SttsBox {
+        Ok(Self {
             version,
             flags,
             entries,
diff --git a/src/mp4box/tfdt.rs b/src/mp4box/tfdt.rs
index 733f923..3ad7881 100644
--- a/src/mp4box/tfdt.rs
+++ b/src/mp4box/tfdt.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct TfdtBox {
@@ -62,7 +65,7 @@ impl ReadBox<&mut R> for TfdtBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(TfdtBox {
+        Ok(Self {
             version,
             flags,
             base_media_decode_time,
diff --git a/src/mp4box/tfhd.rs b/src/mp4box/tfhd.rs
index 7ad8530..057e614 100644
--- a/src/mp4box/tfhd.rs
+++ b/src/mp4box/tfhd.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
 pub struct TfhdBox {
@@ -31,19 +34,19 @@ impl TfhdBox {
 
     pub fn get_size(&self) -> u64 {
         let mut sum = HEADER_SIZE + HEADER_EXT_SIZE + 4;
-        if TfhdBox::FLAG_BASE_DATA_OFFSET & self.flags > 0 {
+        if Self::FLAG_BASE_DATA_OFFSET & self.flags > 0 {
             sum += 8;
         }
-        if TfhdBox::FLAG_SAMPLE_DESCRIPTION_INDEX & self.flags > 0 {
+        if Self::FLAG_SAMPLE_DESCRIPTION_INDEX & self.flags > 0 {
             sum += 4;
         }
-        if TfhdBox::FLAG_DEFAULT_SAMPLE_DURATION & self.flags > 0 {
+        if Self::FLAG_DEFAULT_SAMPLE_DURATION & self.flags > 0 {
             sum += 4;
         }
-        if TfhdBox::FLAG_DEFAULT_SAMPLE_SIZE & self.flags > 0 {
+        if Self::FLAG_DEFAULT_SAMPLE_SIZE & self.flags > 0 {
             sum += 4;
         }
-        if TfhdBox::FLAG_DEFAULT_SAMPLE_FLAGS & self.flags > 0 {
+        if Self::FLAG_DEFAULT_SAMPLE_FLAGS & self.flags > 0 {
             sum += 4;
         }
         sum
@@ -75,27 +78,27 @@ impl ReadBox<&mut R> for TfhdBox {
 
         let (version, flags) = read_box_header_ext(reader)?;
         let track_id = reader.read_u32::()?;
-        let base_data_offset = if TfhdBox::FLAG_BASE_DATA_OFFSET & flags > 0 {
+        let base_data_offset = if Self::FLAG_BASE_DATA_OFFSET & flags > 0 {
             Some(reader.read_u64::()?)
         } else {
             None
         };
-        let sample_description_index = if TfhdBox::FLAG_SAMPLE_DESCRIPTION_INDEX & flags > 0 {
+        let sample_description_index = if Self::FLAG_SAMPLE_DESCRIPTION_INDEX & flags > 0 {
             Some(reader.read_u32::()?)
         } else {
             None
         };
-        let default_sample_duration = if TfhdBox::FLAG_DEFAULT_SAMPLE_DURATION & flags > 0 {
+        let default_sample_duration = if Self::FLAG_DEFAULT_SAMPLE_DURATION & flags > 0 {
             Some(reader.read_u32::()?)
         } else {
             None
         };
-        let default_sample_size = if TfhdBox::FLAG_DEFAULT_SAMPLE_SIZE & flags > 0 {
+        let default_sample_size = if Self::FLAG_DEFAULT_SAMPLE_SIZE & flags > 0 {
             Some(reader.read_u32::()?)
         } else {
             None
         };
-        let default_sample_flags = if TfhdBox::FLAG_DEFAULT_SAMPLE_FLAGS & flags > 0 {
+        let default_sample_flags = if Self::FLAG_DEFAULT_SAMPLE_FLAGS & flags > 0 {
             Some(reader.read_u32::()?)
         } else {
             None
@@ -103,7 +106,7 @@ impl ReadBox<&mut R> for TfhdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(TfhdBox {
+        Ok(Self {
             version,
             flags,
             track_id,
diff --git a/src/mp4box/tkhd.rs b/src/mp4box/tkhd.rs
index 284f759..ab87b48 100644
--- a/src/mp4box/tkhd.rs
+++ b/src/mp4box/tkhd.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, value_u32, value_u8, BoxType, Error,
+    FixedPointU16, FixedPointU8, Mp4Box, ReadBox, Result, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 pub enum TrackFlag {
     TrackEnabled = 0x000001,
@@ -34,7 +37,7 @@ pub struct TkhdBox {
 
 impl Default for TkhdBox {
     fn default() -> Self {
-        TkhdBox {
+        Self {
             version: 0,
             flags: TrackFlag::TrackEnabled as u32,
             creation_time: 0,
@@ -193,7 +196,7 @@ impl ReadBox<&mut R> for TkhdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(TkhdBox {
+        Ok(Self {
             version,
             flags,
             creation_time,
diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs
index a0a3cf1..a7dd840 100644
--- a/src/mp4box/traf.rs
+++ b/src/mp4box/traf.rs
@@ -1,7 +1,10 @@
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{tfdt::TfdtBox, tfhd::TfhdBox, trun::TrunBox};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -93,7 +96,7 @@ impl ReadBox<&mut R> for TrafBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(TrafBox {
+        Ok(Self {
             tfhd: tfhd.unwrap(),
             tfdt,
             truns,
diff --git a/src/mp4box/trak.rs b/src/mp4box/trak.rs
index d81d0c9..c9ed5a2 100644
--- a/src/mp4box/trak.rs
+++ b/src/mp4box/trak.rs
@@ -2,7 +2,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 
 use crate::meta::MetaBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 use crate::mp4box::{edts::EdtsBox, mdia::MdiaBox, tkhd::TkhdBox};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -105,7 +108,7 @@ impl ReadBox<&mut R> for TrakBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(TrakBox {
+        Ok(Self {
             tkhd: tkhd.unwrap(),
             edts,
             meta,
diff --git a/src/mp4box/trex.rs b/src/mp4box/trex.rs
index ae5a871..b1e7c5a 100644
--- a/src/mp4box/trex.rs
+++ b/src/mp4box/trex.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct TrexBox {
@@ -61,7 +64,7 @@ impl ReadBox<&mut R> for TrexBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(TrexBox {
+        Ok(Self {
             version,
             flags,
             track_id,
diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs
index 7ca5544..26baae0 100644
--- a/src/mp4box/trun.rs
+++ b/src/mp4box/trun.rs
@@ -3,7 +3,10 @@ use serde::Serialize;
 use std::io::{Read, Seek};
 use std::mem::size_of;
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct TrunBox {
@@ -37,22 +40,22 @@ impl TrunBox {
 
     pub fn get_size(&self) -> u64 {
         let mut sum = HEADER_SIZE + HEADER_EXT_SIZE + 4;
-        if TrunBox::FLAG_DATA_OFFSET & self.flags > 0 {
+        if Self::FLAG_DATA_OFFSET & self.flags > 0 {
             sum += 4;
         }
-        if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & self.flags > 0 {
+        if Self::FLAG_FIRST_SAMPLE_FLAGS & self.flags > 0 {
             sum += 4;
         }
-        if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 {
+        if Self::FLAG_SAMPLE_DURATION & self.flags > 0 {
             sum += 4 * self.sample_count as u64;
         }
-        if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 {
+        if Self::FLAG_SAMPLE_SIZE & self.flags > 0 {
             sum += 4 * self.sample_count as u64;
         }
-        if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 {
+        if Self::FLAG_SAMPLE_FLAGS & self.flags > 0 {
             sum += 4 * self.sample_count as u64;
         }
-        if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 {
+        if Self::FLAG_SAMPLE_CTS & self.flags > 0 {
             sum += 4 * self.sample_count as u64;
         }
         sum
@@ -86,22 +89,22 @@ impl ReadBox<&mut R> for TrunBox {
 
         let header_size = HEADER_SIZE + HEADER_EXT_SIZE;
         let other_size = size_of::() // sample_count
-            + if TrunBox::FLAG_DATA_OFFSET & flags > 0 { size_of::() } else { 0 } // data_offset
-            + if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & flags > 0 { size_of::() } else { 0 }; // first_sample_flags
-        let sample_size = if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 { size_of::() } else { 0 } // sample_duration
-            + if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 { size_of::() } else { 0 } // sample_size
-            + if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 { size_of::() } else { 0 } // sample_flags
-            + if TrunBox::FLAG_SAMPLE_CTS & flags > 0 { size_of::() } else { 0 }; // sample_composition_time_offset
+            + if Self::FLAG_DATA_OFFSET & flags > 0 { size_of::() } else { 0 } // data_offset
+            + if Self::FLAG_FIRST_SAMPLE_FLAGS & flags > 0 { size_of::() } else { 0 }; // first_sample_flags
+        let sample_size = if Self::FLAG_SAMPLE_DURATION & flags > 0 { size_of::() } else { 0 } // sample_duration
+            + if Self::FLAG_SAMPLE_SIZE & flags > 0 { size_of::() } else { 0 } // sample_size
+            + if Self::FLAG_SAMPLE_FLAGS & flags > 0 { size_of::() } else { 0 } // sample_flags
+            + if Self::FLAG_SAMPLE_CTS & flags > 0 { size_of::() } else { 0 }; // sample_composition_time_offset
 
         let sample_count = reader.read_u32::()?;
 
-        let data_offset = if TrunBox::FLAG_DATA_OFFSET & flags > 0 {
+        let data_offset = if Self::FLAG_DATA_OFFSET & flags > 0 {
             Some(reader.read_i32::()?)
         } else {
             None
         };
 
-        let first_sample_flags = if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & flags > 0 {
+        let first_sample_flags = if Self::FLAG_FIRST_SAMPLE_FLAGS & flags > 0 {
             Some(reader.read_u32::()?)
         } else {
             None
@@ -120,36 +123,36 @@ impl ReadBox<&mut R> for TrunBox {
                 "trun sample_count indicates more values than could fit in the box",
             ));
         }
-        if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 {
+        if Self::FLAG_SAMPLE_DURATION & flags > 0 {
             sample_durations.reserve(sample_count as usize);
         }
-        if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 {
+        if Self::FLAG_SAMPLE_SIZE & flags > 0 {
             sample_sizes.reserve(sample_count as usize);
         }
-        if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 {
+        if Self::FLAG_SAMPLE_FLAGS & flags > 0 {
             sample_flags.reserve(sample_count as usize);
         }
-        if TrunBox::FLAG_SAMPLE_CTS & flags > 0 {
+        if Self::FLAG_SAMPLE_CTS & flags > 0 {
             sample_cts.reserve(sample_count as usize);
         }
 
         for _ in 0..sample_count {
-            if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 {
+            if Self::FLAG_SAMPLE_DURATION & flags > 0 {
                 let duration = reader.read_u32::()?;
                 sample_durations.push(duration);
             }
 
-            if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 {
+            if Self::FLAG_SAMPLE_SIZE & flags > 0 {
                 let sample_size = reader.read_u32::()?;
                 sample_sizes.push(sample_size);
             }
 
-            if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 {
+            if Self::FLAG_SAMPLE_FLAGS & flags > 0 {
                 let sample_flag = reader.read_u32::()?;
                 sample_flags.push(sample_flag);
             }
 
-            if TrunBox::FLAG_SAMPLE_CTS & flags > 0 {
+            if Self::FLAG_SAMPLE_CTS & flags > 0 {
                 let cts = reader.read_u32::()?;
                 sample_cts.push(cts);
             }
@@ -157,7 +160,7 @@ impl ReadBox<&mut R> for TrunBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(TrunBox {
+        Ok(Self {
             version,
             flags,
             sample_count,
diff --git a/src/mp4box/tx3g.rs b/src/mp4box/tx3g.rs
index 89c6cb6..a489e80 100644
--- a/src/mp4box/tx3g.rs
+++ b/src/mp4box/tx3g.rs
@@ -2,7 +2,7 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{box_start, skip_bytes_to, BoxType, Mp4Box, ReadBox, Result, HEADER_SIZE};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub struct Tx3gBox {
@@ -25,7 +25,7 @@ pub struct RgbaColor {
 
 impl Default for Tx3gBox {
     fn default() -> Self {
-        Tx3gBox {
+        Self {
             data_reference_index: 0,
             display_flags: 0,
             horizontal_justification: 1,
@@ -114,7 +114,7 @@ impl ReadBox<&mut R> for Tx3gBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(Tx3gBox {
+        Ok(Self {
             data_reference_index,
             display_flags,
             horizontal_justification,
diff --git a/src/mp4box/udta.rs b/src/mp4box/udta.rs
index b9e4d14..1ae2005 100644
--- a/src/mp4box/udta.rs
+++ b/src/mp4box/udta.rs
@@ -3,7 +3,10 @@ use std::io::{Read, Seek};
 use serde::Serialize;
 
 use crate::mp4box::meta::MetaBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, skip_box, skip_bytes_to, BoxHeader, BoxType, Error, Mp4Box, ReadBox, Result,
+    HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct UdtaBox {
@@ -76,6 +79,6 @@ impl ReadBox<&mut R> for UdtaBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(UdtaBox { meta })
+        Ok(Self { meta })
     }
 }
diff --git a/src/mp4box/vmhd.rs b/src/mp4box/vmhd.rs
index 8193c8c..9ba48bd 100644
--- a/src/mp4box/vmhd.rs
+++ b/src/mp4box/vmhd.rs
@@ -2,7 +2,10 @@ use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
 use std::io::{Read, Seek};
 
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BoxType, Mp4Box, ReadBox, Result,
+    HEADER_EXT_SIZE, HEADER_SIZE,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
 pub struct VmhdBox {
@@ -66,7 +69,7 @@ impl ReadBox<&mut R> for VmhdBox {
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(VmhdBox {
+        Ok(Self {
             version,
             flags,
             graphics_mode,
diff --git a/src/mp4box/vp08.rs b/src/mp4box/vp08.rs
index 8ac9f09..4e3418c 100644
--- a/src/mp4box/vp08.rs
+++ b/src/mp4box/vp08.rs
@@ -1,5 +1,8 @@
 use crate::mp4box::vpcc::VpccBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BigEndian, BoxHeader, BoxType, Error, RawBox,
+    Read, ReadBox, ReadBytesExt, Result, Seek,
+};
 use crate::Mp4Box;
 use serde::Serialize;
 
diff --git a/src/mp4box/vp09.rs b/src/mp4box/vp09.rs
index cfffa26..076b172 100644
--- a/src/mp4box/vp09.rs
+++ b/src/mp4box/vp09.rs
@@ -1,5 +1,8 @@
 use crate::mp4box::vpcc::VpccBox;
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BigEndian, BoxHeader, BoxType, Error, RawBox,
+    Read, ReadBox, ReadBytesExt, Result, Seek,
+};
 use crate::Mp4Box;
 use serde::Serialize;
 
diff --git a/src/mp4box/vpcc.rs b/src/mp4box/vpcc.rs
index 08e2122..4631c80 100644
--- a/src/mp4box/vpcc.rs
+++ b/src/mp4box/vpcc.rs
@@ -1,4 +1,7 @@
-use crate::mp4box::*;
+use crate::mp4box::{
+    box_start, read_box_header_ext, skip_bytes_to, BigEndian, BoxType, Read, ReadBox, ReadBytesExt,
+    Result, Seek, HEADER_EXT_SIZE, HEADER_SIZE,
+};
 use crate::Mp4Box;
 use serde::Serialize;
 
diff --git a/src/reader.rs b/src/reader.rs
index 7f1d281..a193a9c 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -3,7 +3,11 @@ use std::fmt::Write as _;
 use std::io::SeekFrom;
 use std::io::{Read, Seek};
 
-use crate::*;
+use crate::{
+    skip_box, Av01Box, Avc1Box, BoxHeader, BoxType, EmsgBox, Error, FtypBox, Hvc1Box, MetaBox,
+    Metadata, MoofBox, MoovBox, ReadBox, Result, StblBox, TfhdBox, TrackKind, TrakBox, TrunBox,
+    Vp08Box, Vp09Box,
+};
 
 #[derive(Debug)]
 pub struct Mp4 {
@@ -79,7 +83,7 @@ impl Mp4 {
             return Err(Error::BoxNotFound(BoxType::MoovBox));
         }
 
-        let mut this = Mp4 {
+        let mut this = Self {
             ftyp: ftyp.unwrap(),
             moov: moov.unwrap(),
             moofs,
@@ -515,7 +519,7 @@ impl Track {
                 reversed <<= 1;
                 val >>= 1;
             }
-            write!(&mut codec, ".{:X}", reversed).ok();
+            write!(&mut codec, ".{reversed:X}").ok();
 
             if hvcc.general_tier_flag {
                 codec.push_str(".H");
diff --git a/src/types.rs b/src/types.rs
index 5c450b9..48c3ae6 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -3,8 +3,8 @@ use std::borrow::Cow;
 use std::convert::TryFrom;
 use std::fmt;
 
-use crate::mp4box::*;
-use crate::*;
+use crate::mp4box::{BoxType, Mp4Box};
+use crate::{Error, Result};
 
 pub use bytes::Bytes;
 pub use num_rational::Ratio;
@@ -107,32 +107,32 @@ impl std::str::FromStr for FourCC {
 
 impl From for FourCC {
     fn from(number: u32) -> Self {
-        FourCC {
+        Self {
             value: number.to_be_bytes(),
         }
     }
 }
 
 impl From for u32 {
-    fn from(fourcc: FourCC) -> u32 {
+    fn from(fourcc: FourCC) -> Self {
         (&fourcc).into()
     }
 }
 
 impl From<&FourCC> for u32 {
-    fn from(fourcc: &FourCC) -> u32 {
-        u32::from_be_bytes(fourcc.value)
+    fn from(fourcc: &FourCC) -> Self {
+        Self::from_be_bytes(fourcc.value)
     }
 }
 
 impl From<[u8; 4]> for FourCC {
-    fn from(value: [u8; 4]) -> FourCC {
-        FourCC { value }
+    fn from(value: [u8; 4]) -> Self {
+        Self { value }
     }
 }
 
 impl From for FourCC {
-    fn from(t: BoxType) -> FourCC {
+    fn from(t: BoxType) -> Self {
         let box_num: u32 = Into::into(t);
         From::from(box_num)
     }
@@ -175,9 +175,9 @@ pub enum TrackKind {
 impl fmt::Display for TrackKind {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let s = match self {
-            TrackKind::Video => DISPLAY_TYPE_VIDEO,
-            TrackKind::Audio => DISPLAY_TYPE_AUDIO,
-            TrackKind::Subtitle => DISPLAY_TYPE_SUBTITLE,
+            Self::Video => DISPLAY_TYPE_VIDEO,
+            Self::Audio => DISPLAY_TYPE_AUDIO,
+            Self::Subtitle => DISPLAY_TYPE_SUBTITLE,
         };
         write!(f, "{s}")
     }
@@ -185,11 +185,11 @@ impl fmt::Display for TrackKind {
 
 impl TryFrom<&str> for TrackKind {
     type Error = Error;
-    fn try_from(handler: &str) -> Result {
+    fn try_from(handler: &str) -> Result {
         match handler {
-            HANDLER_TYPE_VIDEO => Ok(TrackKind::Video),
-            HANDLER_TYPE_AUDIO => Ok(TrackKind::Audio),
-            HANDLER_TYPE_SUBTITLE => Ok(TrackKind::Subtitle),
+            HANDLER_TYPE_VIDEO => Ok(Self::Video),
+            HANDLER_TYPE_AUDIO => Ok(Self::Audio),
+            HANDLER_TYPE_SUBTITLE => Ok(Self::Subtitle),
             _ => Err(Error::InvalidData("unsupported handler type")),
         }
     }
@@ -197,18 +197,18 @@ impl TryFrom<&str> for TrackKind {
 
 impl TryFrom<&FourCC> for TrackKind {
     type Error = Error;
-    fn try_from(fourcc: &FourCC) -> Result {
+    fn try_from(fourcc: &FourCC) -> Result {
         match fourcc.value {
-            HANDLER_TYPE_VIDEO_FOURCC => Ok(TrackKind::Video),
-            HANDLER_TYPE_AUDIO_FOURCC => Ok(TrackKind::Audio),
-            HANDLER_TYPE_SUBTITLE_FOURCC => Ok(TrackKind::Subtitle),
+            HANDLER_TYPE_VIDEO_FOURCC => Ok(Self::Video),
+            HANDLER_TYPE_AUDIO_FOURCC => Ok(Self::Audio),
+            HANDLER_TYPE_SUBTITLE_FOURCC => Ok(Self::Subtitle),
             _ => Err(Error::InvalidData("unsupported handler type")),
         }
     }
 }
 
 impl From for FourCC {
-    fn from(t: TrackKind) -> FourCC {
+    fn from(t: TrackKind) -> Self {
         match t {
             TrackKind::Video => HANDLER_TYPE_VIDEO_FOURCC.into(),
             TrackKind::Audio => HANDLER_TYPE_AUDIO_FOURCC.into(),
@@ -241,13 +241,13 @@ impl fmt::Display for MediaType {
 
 impl TryFrom<&str> for MediaType {
     type Error = Error;
-    fn try_from(media: &str) -> Result {
+    fn try_from(media: &str) -> Result {
         match media {
-            MEDIA_TYPE_H264 => Ok(MediaType::H264),
-            MEDIA_TYPE_H265 => Ok(MediaType::H265),
-            MEDIA_TYPE_VP9 => Ok(MediaType::VP9),
-            MEDIA_TYPE_AAC => Ok(MediaType::AAC),
-            MEDIA_TYPE_TTXT => Ok(MediaType::TTXT),
+            MEDIA_TYPE_H264 => Ok(Self::H264),
+            MEDIA_TYPE_H265 => Ok(Self::H265),
+            MEDIA_TYPE_VP9 => Ok(Self::VP9),
+            MEDIA_TYPE_AAC => Ok(Self::AAC),
+            MEDIA_TYPE_TTXT => Ok(Self::TTXT),
             _ => Err(Error::InvalidData("unsupported media type")),
         }
     }
@@ -289,15 +289,15 @@ pub enum AvcProfile {
 
 impl TryFrom<(u8, u8)> for AvcProfile {
     type Error = Error;
-    fn try_from(value: (u8, u8)) -> Result {
+    fn try_from(value: (u8, u8)) -> Result {
         let profile = value.0;
         let constraint_set1_flag = (value.1 & 0x40) >> 7;
         match (profile, constraint_set1_flag) {
-            (66, 1) => Ok(AvcProfile::AvcConstrainedBaseline),
-            (66, 0) => Ok(AvcProfile::AvcBaseline),
-            (77, _) => Ok(AvcProfile::AvcMain),
-            (88, _) => Ok(AvcProfile::AvcExtended),
-            (100, _) => Ok(AvcProfile::AvcHigh),
+            (66, 1) => Ok(Self::AvcConstrainedBaseline),
+            (66, 0) => Ok(Self::AvcBaseline),
+            (77, _) => Ok(Self::AvcMain),
+            (88, _) => Ok(Self::AvcExtended),
+            (100, _) => Ok(Self::AvcHigh),
             _ => Err(Error::InvalidData("unsupported avc profile")),
         }
     }
@@ -306,11 +306,11 @@ impl TryFrom<(u8, u8)> for AvcProfile {
 impl fmt::Display for AvcProfile {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let profile = match self {
-            AvcProfile::AvcConstrainedBaseline => "Constrained Baseline",
-            AvcProfile::AvcBaseline => "Baseline",
-            AvcProfile::AvcMain => "Main",
-            AvcProfile::AvcExtended => "Extended",
-            AvcProfile::AvcHigh => "High",
+            Self::AvcConstrainedBaseline => "Constrained Baseline",
+            Self::AvcBaseline => "Baseline",
+            Self::AvcMain => "Main",
+            Self::AvcExtended => "Extended",
+            Self::AvcHigh => "High",
         };
         write!(f, "{profile}")
     }
@@ -364,50 +364,50 @@ pub enum AudioObjectType {
 
 impl TryFrom for AudioObjectType {
     type Error = Error;
-    fn try_from(value: u8) -> Result {
+    fn try_from(value: u8) -> Result {
         match value {
-            1 => Ok(AudioObjectType::AacMain),
-            2 => Ok(AudioObjectType::AacLowComplexity),
-            3 => Ok(AudioObjectType::AacScalableSampleRate),
-            4 => Ok(AudioObjectType::AacLongTermPrediction),
-            5 => Ok(AudioObjectType::SpectralBandReplication),
-            6 => Ok(AudioObjectType::AACScalable),
-            7 => Ok(AudioObjectType::TwinVQ),
-            8 => Ok(AudioObjectType::CodeExcitedLinearPrediction),
-            9 => Ok(AudioObjectType::HarmonicVectorExcitationCoding),
-            12 => Ok(AudioObjectType::TextToSpeechtInterface),
-            13 => Ok(AudioObjectType::MainSynthetic),
-            14 => Ok(AudioObjectType::WavetableSynthesis),
-            15 => Ok(AudioObjectType::GeneralMIDI),
-            16 => Ok(AudioObjectType::AlgorithmicSynthesis),
-            17 => Ok(AudioObjectType::ErrorResilientAacLowComplexity),
-            19 => Ok(AudioObjectType::ErrorResilientAacLongTermPrediction),
-            20 => Ok(AudioObjectType::ErrorResilientAacScalable),
-            21 => Ok(AudioObjectType::ErrorResilientAacTwinVQ),
-            22 => Ok(AudioObjectType::ErrorResilientAacBitSlicedArithmeticCoding),
-            23 => Ok(AudioObjectType::ErrorResilientAacLowDelay),
-            24 => Ok(AudioObjectType::ErrorResilientCodeExcitedLinearPrediction),
-            25 => Ok(AudioObjectType::ErrorResilientHarmonicVectorExcitationCoding),
-            26 => Ok(AudioObjectType::ErrorResilientHarmonicIndividualLinesNoise),
-            27 => Ok(AudioObjectType::ErrorResilientParametric),
-            28 => Ok(AudioObjectType::SinuSoidalCoding),
-            29 => Ok(AudioObjectType::ParametricStereo),
-            30 => Ok(AudioObjectType::MpegSurround),
-            32 => Ok(AudioObjectType::MpegLayer1),
-            33 => Ok(AudioObjectType::MpegLayer2),
-            34 => Ok(AudioObjectType::MpegLayer3),
-            35 => Ok(AudioObjectType::DirectStreamTransfer),
-            36 => Ok(AudioObjectType::AudioLosslessCoding),
-            37 => Ok(AudioObjectType::ScalableLosslessCoding),
-            38 => Ok(AudioObjectType::ScalableLosslessCodingNoneCore),
-            39 => Ok(AudioObjectType::ErrorResilientAacEnhancedLowDelay),
-            40 => Ok(AudioObjectType::SymbolicMusicRepresentationSimple),
-            41 => Ok(AudioObjectType::SymbolicMusicRepresentationMain),
-            42 => Ok(AudioObjectType::UnifiedSpeechAudioCoding),
-            43 => Ok(AudioObjectType::SpatialAudioObjectCoding),
-            44 => Ok(AudioObjectType::LowDelayMpegSurround),
-            45 => Ok(AudioObjectType::SpatialAudioObjectCodingDialogueEnhancement),
-            46 => Ok(AudioObjectType::AudioSync),
+            1 => Ok(Self::AacMain),
+            2 => Ok(Self::AacLowComplexity),
+            3 => Ok(Self::AacScalableSampleRate),
+            4 => Ok(Self::AacLongTermPrediction),
+            5 => Ok(Self::SpectralBandReplication),
+            6 => Ok(Self::AACScalable),
+            7 => Ok(Self::TwinVQ),
+            8 => Ok(Self::CodeExcitedLinearPrediction),
+            9 => Ok(Self::HarmonicVectorExcitationCoding),
+            12 => Ok(Self::TextToSpeechtInterface),
+            13 => Ok(Self::MainSynthetic),
+            14 => Ok(Self::WavetableSynthesis),
+            15 => Ok(Self::GeneralMIDI),
+            16 => Ok(Self::AlgorithmicSynthesis),
+            17 => Ok(Self::ErrorResilientAacLowComplexity),
+            19 => Ok(Self::ErrorResilientAacLongTermPrediction),
+            20 => Ok(Self::ErrorResilientAacScalable),
+            21 => Ok(Self::ErrorResilientAacTwinVQ),
+            22 => Ok(Self::ErrorResilientAacBitSlicedArithmeticCoding),
+            23 => Ok(Self::ErrorResilientAacLowDelay),
+            24 => Ok(Self::ErrorResilientCodeExcitedLinearPrediction),
+            25 => Ok(Self::ErrorResilientHarmonicVectorExcitationCoding),
+            26 => Ok(Self::ErrorResilientHarmonicIndividualLinesNoise),
+            27 => Ok(Self::ErrorResilientParametric),
+            28 => Ok(Self::SinuSoidalCoding),
+            29 => Ok(Self::ParametricStereo),
+            30 => Ok(Self::MpegSurround),
+            32 => Ok(Self::MpegLayer1),
+            33 => Ok(Self::MpegLayer2),
+            34 => Ok(Self::MpegLayer3),
+            35 => Ok(Self::DirectStreamTransfer),
+            36 => Ok(Self::AudioLosslessCoding),
+            37 => Ok(Self::ScalableLosslessCoding),
+            38 => Ok(Self::ScalableLosslessCodingNoneCore),
+            39 => Ok(Self::ErrorResilientAacEnhancedLowDelay),
+            40 => Ok(Self::SymbolicMusicRepresentationSimple),
+            41 => Ok(Self::SymbolicMusicRepresentationMain),
+            42 => Ok(Self::UnifiedSpeechAudioCoding),
+            43 => Ok(Self::SpatialAudioObjectCoding),
+            44 => Ok(Self::LowDelayMpegSurround),
+            45 => Ok(Self::SpatialAudioObjectCodingDialogueEnhancement),
+            46 => Ok(Self::AudioSync),
             _ => Err(Error::InvalidData("invalid audio object type")),
         }
     }
@@ -416,48 +416,48 @@ impl TryFrom for AudioObjectType {
 impl fmt::Display for AudioObjectType {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let type_str = match self {
-            AudioObjectType::AacMain => "AAC Main",
-            AudioObjectType::AacLowComplexity => "LC",
-            AudioObjectType::AacScalableSampleRate => "SSR",
-            AudioObjectType::AacLongTermPrediction => "LTP",
-            AudioObjectType::SpectralBandReplication => "SBR",
-            AudioObjectType::AACScalable => "Scalable",
-            AudioObjectType::TwinVQ => "TwinVQ",
-            AudioObjectType::CodeExcitedLinearPrediction => "CELP",
-            AudioObjectType::HarmonicVectorExcitationCoding => "HVXC",
-            AudioObjectType::TextToSpeechtInterface => "TTSI",
-            AudioObjectType::MainSynthetic => "Main Synthetic",
-            AudioObjectType::WavetableSynthesis => "Wavetable Synthesis",
-            AudioObjectType::GeneralMIDI => "General MIDI",
-            AudioObjectType::AlgorithmicSynthesis => "Algorithmic Synthesis",
-            AudioObjectType::ErrorResilientAacLowComplexity => "ER AAC LC",
-            AudioObjectType::ErrorResilientAacLongTermPrediction => "ER AAC LTP",
-            AudioObjectType::ErrorResilientAacScalable => "ER AAC scalable",
-            AudioObjectType::ErrorResilientAacTwinVQ => "ER AAC TwinVQ",
-            AudioObjectType::ErrorResilientAacBitSlicedArithmeticCoding => "ER AAC BSAC",
-            AudioObjectType::ErrorResilientAacLowDelay => "ER AAC LD",
-            AudioObjectType::ErrorResilientCodeExcitedLinearPrediction => "ER CELP",
-            AudioObjectType::ErrorResilientHarmonicVectorExcitationCoding => "ER HVXC",
-            AudioObjectType::ErrorResilientHarmonicIndividualLinesNoise => "ER HILN",
-            AudioObjectType::ErrorResilientParametric => "ER Parametric",
-            AudioObjectType::SinuSoidalCoding => "SSC",
-            AudioObjectType::ParametricStereo => "Parametric Stereo",
-            AudioObjectType::MpegSurround => "MPEG surround",
-            AudioObjectType::MpegLayer1 => "MPEG Layer 1",
-            AudioObjectType::MpegLayer2 => "MPEG Layer 2",
-            AudioObjectType::MpegLayer3 => "MPEG Layer 3",
-            AudioObjectType::DirectStreamTransfer => "DST",
-            AudioObjectType::AudioLosslessCoding => "ALS",
-            AudioObjectType::ScalableLosslessCoding => "SLS",
-            AudioObjectType::ScalableLosslessCodingNoneCore => "SLS Non-core",
-            AudioObjectType::ErrorResilientAacEnhancedLowDelay => "ER AAC ELD",
-            AudioObjectType::SymbolicMusicRepresentationSimple => "SMR Simple",
-            AudioObjectType::SymbolicMusicRepresentationMain => "SMR Main",
-            AudioObjectType::UnifiedSpeechAudioCoding => "USAC",
-            AudioObjectType::SpatialAudioObjectCoding => "SAOC",
-            AudioObjectType::LowDelayMpegSurround => "LD MPEG Surround",
-            AudioObjectType::SpatialAudioObjectCodingDialogueEnhancement => "SAOC-DE",
-            AudioObjectType::AudioSync => "Audio Sync",
+            Self::AacMain => "AAC Main",
+            Self::AacLowComplexity => "LC",
+            Self::AacScalableSampleRate => "SSR",
+            Self::AacLongTermPrediction => "LTP",
+            Self::SpectralBandReplication => "SBR",
+            Self::AACScalable => "Scalable",
+            Self::TwinVQ => "TwinVQ",
+            Self::CodeExcitedLinearPrediction => "CELP",
+            Self::HarmonicVectorExcitationCoding => "HVXC",
+            Self::TextToSpeechtInterface => "TTSI",
+            Self::MainSynthetic => "Main Synthetic",
+            Self::WavetableSynthesis => "Wavetable Synthesis",
+            Self::GeneralMIDI => "General MIDI",
+            Self::AlgorithmicSynthesis => "Algorithmic Synthesis",
+            Self::ErrorResilientAacLowComplexity => "ER AAC LC",
+            Self::ErrorResilientAacLongTermPrediction => "ER AAC LTP",
+            Self::ErrorResilientAacScalable => "ER AAC scalable",
+            Self::ErrorResilientAacTwinVQ => "ER AAC TwinVQ",
+            Self::ErrorResilientAacBitSlicedArithmeticCoding => "ER AAC BSAC",
+            Self::ErrorResilientAacLowDelay => "ER AAC LD",
+            Self::ErrorResilientCodeExcitedLinearPrediction => "ER CELP",
+            Self::ErrorResilientHarmonicVectorExcitationCoding => "ER HVXC",
+            Self::ErrorResilientHarmonicIndividualLinesNoise => "ER HILN",
+            Self::ErrorResilientParametric => "ER Parametric",
+            Self::SinuSoidalCoding => "SSC",
+            Self::ParametricStereo => "Parametric Stereo",
+            Self::MpegSurround => "MPEG surround",
+            Self::MpegLayer1 => "MPEG Layer 1",
+            Self::MpegLayer2 => "MPEG Layer 2",
+            Self::MpegLayer3 => "MPEG Layer 3",
+            Self::DirectStreamTransfer => "DST",
+            Self::AudioLosslessCoding => "ALS",
+            Self::ScalableLosslessCoding => "SLS",
+            Self::ScalableLosslessCodingNoneCore => "SLS Non-core",
+            Self::ErrorResilientAacEnhancedLowDelay => "ER AAC ELD",
+            Self::SymbolicMusicRepresentationSimple => "SMR Simple",
+            Self::SymbolicMusicRepresentationMain => "SMR Main",
+            Self::UnifiedSpeechAudioCoding => "USAC",
+            Self::SpatialAudioObjectCoding => "SAOC",
+            Self::LowDelayMpegSurround => "LD MPEG Surround",
+            Self::SpatialAudioObjectCodingDialogueEnhancement => "SAOC-DE",
+            Self::AudioSync => "Audio Sync",
         };
         write!(f, "{type_str}")
     }
@@ -482,21 +482,21 @@ pub enum SampleFreqIndex {
 
 impl TryFrom for SampleFreqIndex {
     type Error = Error;
-    fn try_from(value: u8) -> Result {
+    fn try_from(value: u8) -> Result {
         match value {
-            0x0 => Ok(SampleFreqIndex::Freq96000),
-            0x1 => Ok(SampleFreqIndex::Freq88200),
-            0x2 => Ok(SampleFreqIndex::Freq64000),
-            0x3 => Ok(SampleFreqIndex::Freq48000),
-            0x4 => Ok(SampleFreqIndex::Freq44100),
-            0x5 => Ok(SampleFreqIndex::Freq32000),
-            0x6 => Ok(SampleFreqIndex::Freq24000),
-            0x7 => Ok(SampleFreqIndex::Freq22050),
-            0x8 => Ok(SampleFreqIndex::Freq16000),
-            0x9 => Ok(SampleFreqIndex::Freq12000),
-            0xa => Ok(SampleFreqIndex::Freq11025),
-            0xb => Ok(SampleFreqIndex::Freq8000),
-            0xc => Ok(SampleFreqIndex::Freq7350),
+            0x0 => Ok(Self::Freq96000),
+            0x1 => Ok(Self::Freq88200),
+            0x2 => Ok(Self::Freq64000),
+            0x3 => Ok(Self::Freq48000),
+            0x4 => Ok(Self::Freq44100),
+            0x5 => Ok(Self::Freq32000),
+            0x6 => Ok(Self::Freq24000),
+            0x7 => Ok(Self::Freq22050),
+            0x8 => Ok(Self::Freq16000),
+            0x9 => Ok(Self::Freq12000),
+            0xa => Ok(Self::Freq11025),
+            0xb => Ok(Self::Freq8000),
+            0xc => Ok(Self::Freq7350),
             _ => Err(Error::InvalidData("invalid sampling frequency index")),
         }
     }
@@ -505,19 +505,19 @@ impl TryFrom for SampleFreqIndex {
 impl SampleFreqIndex {
     pub fn freq(&self) -> u32 {
         match *self {
-            SampleFreqIndex::Freq96000 => 96000,
-            SampleFreqIndex::Freq88200 => 88200,
-            SampleFreqIndex::Freq64000 => 64000,
-            SampleFreqIndex::Freq48000 => 48000,
-            SampleFreqIndex::Freq44100 => 44100,
-            SampleFreqIndex::Freq32000 => 32000,
-            SampleFreqIndex::Freq24000 => 24000,
-            SampleFreqIndex::Freq22050 => 22050,
-            SampleFreqIndex::Freq16000 => 16000,
-            SampleFreqIndex::Freq12000 => 12000,
-            SampleFreqIndex::Freq11025 => 11025,
-            SampleFreqIndex::Freq8000 => 8000,
-            SampleFreqIndex::Freq7350 => 7350,
+            Self::Freq96000 => 96000,
+            Self::Freq88200 => 88200,
+            Self::Freq64000 => 64000,
+            Self::Freq48000 => 48000,
+            Self::Freq44100 => 44100,
+            Self::Freq32000 => 32000,
+            Self::Freq24000 => 24000,
+            Self::Freq22050 => 22050,
+            Self::Freq16000 => 16000,
+            Self::Freq12000 => 12000,
+            Self::Freq11025 => 11025,
+            Self::Freq8000 => 8000,
+            Self::Freq7350 => 7350,
         }
     }
 }
@@ -535,15 +535,15 @@ pub enum ChannelConfig {
 
 impl TryFrom for ChannelConfig {
     type Error = Error;
-    fn try_from(value: u8) -> Result {
+    fn try_from(value: u8) -> Result {
         match value {
-            0x1 => Ok(ChannelConfig::Mono),
-            0x2 => Ok(ChannelConfig::Stereo),
-            0x3 => Ok(ChannelConfig::Three),
-            0x4 => Ok(ChannelConfig::Four),
-            0x5 => Ok(ChannelConfig::Five),
-            0x6 => Ok(ChannelConfig::FiveOne),
-            0x7 => Ok(ChannelConfig::SevenOne),
+            0x1 => Ok(Self::Mono),
+            0x2 => Ok(Self::Stereo),
+            0x3 => Ok(Self::Three),
+            0x4 => Ok(Self::Four),
+            0x5 => Ok(Self::Five),
+            0x6 => Ok(Self::FiveOne),
+            0x7 => Ok(Self::SevenOne),
             _ => Err(Error::InvalidData("invalid channel configuration")),
         }
     }
@@ -552,13 +552,13 @@ impl TryFrom for ChannelConfig {
 impl fmt::Display for ChannelConfig {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let s = match self {
-            ChannelConfig::Mono => "mono",
-            ChannelConfig::Stereo => "stereo",
-            ChannelConfig::Three => "three",
-            ChannelConfig::Four => "four",
-            ChannelConfig::Five => "five",
-            ChannelConfig::FiveOne => "five.one",
-            ChannelConfig::SevenOne => "seven.one",
+            Self::Mono => "mono",
+            Self::Stereo => "stereo",
+            Self::Three => "three",
+            Self::Four => "four",
+            Self::Five => "five",
+            Self::FiveOne => "five.one",
+            Self::SevenOne => "seven.one",
         };
         write!(f, "{s}")
     }
@@ -668,18 +668,18 @@ pub enum DataType {
 #[allow(clippy::derivable_impls)]
 impl std::default::Default for DataType {
     fn default() -> Self {
-        DataType::Binary
+        Self::Binary
     }
 }
 
 impl TryFrom for DataType {
     type Error = Error;
-    fn try_from(value: u32) -> Result {
+    fn try_from(value: u32) -> Result {
         match value {
-            0x000000 => Ok(DataType::Binary),
-            0x000001 => Ok(DataType::Text),
-            0x00000D => Ok(DataType::Image),
-            0x000015 => Ok(DataType::TempoCpil),
+            0x000000 => Ok(Self::Binary),
+            0x000001 => Ok(Self::Text),
+            0x00000D => Ok(Self::Image),
+            0x000015 => Ok(Self::TempoCpil),
             _ => Err(Error::InvalidData("invalid data type")),
         }
     }
diff --git a/tests/lib.rs b/tests/lib.rs
index 63eac97..4484d79 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -48,15 +48,15 @@ fn assert_video_snapshot(file_path: &str) {
     for (id, track) in video.tracks() {
         if track.kind == re_mp4::TrackKind::Video {
             assert_snapshot(
-                &base_path.join(format!("{}.track_{id}.bin", file_path)),
+                &base_path.join(format!("{file_path}.track_{id}.bin")),
                 &track.data,
             );
             assert_snapshot(
-                &base_path.join(format!("{}.track_{id}.segments", file_path)),
+                &base_path.join(format!("{file_path}.track_{id}.segments")),
                 format!(r#"{:#?}"#, track.samples).as_bytes(),
             );
             assert_snapshot(
-                &base_path.join(format!("{}.track_{id}.json", file_path)),
+                &base_path.join(format!("{file_path}.track_{id}.json")),
                 format!(
                     r#"{{ "codec": {:?}, "width": {}, "height": {}, "num_samples": {}, "description": {:?} }}"#,
                     track.codec_string(&video).unwrap_or("unknown".to_string()),

From 5e07986268fe5ca7ddbc0c3cf29ae23bd15130bd Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:15:24 +0200
Subject: [PATCH 18/32] Add clippy.toml

---
 clippy.toml                     | 79 +++++++++++++++++++++++++++++++++
 scripts/clippy_wasm/clippy.toml | 75 +++++++++++++++++++++++++++++++
 2 files changed, 154 insertions(+)
 create mode 100644 clippy.toml
 create mode 100644 scripts/clippy_wasm/clippy.toml

diff --git a/clippy.toml b/clippy.toml
new file mode 100644
index 0000000..9673121
--- /dev/null
+++ b/clippy.toml
@@ -0,0 +1,79 @@
+# Copied from https://github.com/rerun-io/rerun_template
+#
+# There is also a scripts/clippy_wasm/clippy.toml which forbids some methods that are not available in wasm.
+
+# -----------------------------------------------------------------------------
+# Section identical to scripts/clippy_wasm/clippy.toml:
+
+msrv = "1.76"
+
+allow-unwrap-in-tests = true
+
+# https://doc.rust-lang.org/nightly/clippy/lint_configuration.html#avoid-breaking-exported-api
+# We want suggestions, even if it changes public API.
+avoid-breaking-exported-api = false
+
+excessive-nesting-threshold = 8
+
+max-fn-params-bools = 1
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#/large_include_file
+max-include-file-size = 1000000
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#/large_stack_frames
+stack-size-threshold = 512000
+
+too-many-lines-threshold = 200
+
+# -----------------------------------------------------------------------------
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
+disallowed-macros = ['dbg']
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
+disallowed-methods = [
+  { path = "egui_extras::TableBody::row", reason = "`row` doesn't scale. Use `rows` instead." },
+  { path = "glam::Vec2::normalize", reason = "normalize() can create NaNs. Use try_normalize or normalize_or_zero" },
+  { path = "glam::Vec3::normalize", reason = "normalize() can create NaNs. Use try_normalize or normalize_or_zero" },
+  { path = "sha1::Digest::new", reason = "SHA1 is cryptographically broken" },
+  { path = "std::env::temp_dir", reason = "Use the tempdir crate instead" },
+  { path = "std::panic::catch_unwind", reason = "We compile with `panic = 'abort'`" },
+  { path = "std::thread::spawn", reason = "Use `std::thread::Builder` and name the thread" },
+
+  # There are many things that aren't allowed on wasm,
+  # but we cannot disable them all here (because of e.g. https://github.com/rust-lang/rust-clippy/issues/10406)
+  # so we do that in `scripts/clippy_wasm/clippy.toml` instead.
+]
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names
+disallowed-names = []
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
+disallowed-types = [
+  { path = "ring::digest::SHA1_FOR_LEGACY_USE_ONLY", reason = "SHA1 is cryptographically broken" },
+
+  { path = "std::sync::Condvar", reason = "Use parking_lot instead" },
+  { path = "std::sync::Mutex", reason = "Use parking_lot instead" },
+  { path = "std::sync::RwLock", reason = "Use parking_lot instead" },
+
+  # "std::sync::Once",  # enabled for now as the `log_once` macro uses it internally
+]
+
+# Allow-list of words for markdown in docstrings https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
+doc-valid-idents = [
+  # You must also update the same list in `scripts/clippy_wasm/clippy.toml`!
+  "GitHub",
+  "GLB",
+  "GLTF",
+  "iOS",
+  "macOS",
+  "NaN",
+  "OBJ",
+  "OpenGL",
+  "PyPI",
+  "sRGB",
+  "sRGBA",
+  "WebGL",
+  "WebSocket",
+  "WebSockets",
+]
diff --git a/scripts/clippy_wasm/clippy.toml b/scripts/clippy_wasm/clippy.toml
new file mode 100644
index 0000000..5b7bf9d
--- /dev/null
+++ b/scripts/clippy_wasm/clippy.toml
@@ -0,0 +1,75 @@
+# Copied from https://github.com/rerun-io/rerun_template
+
+# This is used by the CI so we can forbid some methods that are not available in wasm.
+#
+# We cannot forbid all these methods in the main `clippy.toml` because of
+# https://github.com/rust-lang/rust-clippy/issues/10406
+
+# -----------------------------------------------------------------------------
+# Section identical to the main clippy.toml:
+
+msrv = "1.76"
+
+allow-unwrap-in-tests = true
+
+# https://doc.rust-lang.org/nightly/clippy/lint_configuration.html#avoid-breaking-exported-api
+# We want suggestions, even if it changes public API.
+avoid-breaking-exported-api = false
+
+excessive-nesting-threshold = 8
+
+max-fn-params-bools = 1
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#/large_include_file
+max-include-file-size = 1000000
+
+too-many-lines-threshold = 200
+
+# -----------------------------------------------------------------------------
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
+disallowed-methods = [
+  { path = "crossbeam::channel::Receiver::into_iter", reason = "Cannot block on Web" },
+  { path = "crossbeam::channel::Receiver::iter", reason = "Cannot block on Web" },
+  { path = "crossbeam::channel::Receiver::recv_timeout", reason = "Cannot block on Web" },
+  { path = "crossbeam::channel::Receiver::recv", reason = "Cannot block on Web" },
+  { path = "poll_promise::Promise::block_and_take", reason = "Cannot block on Web" },
+  { path = "poll_promise::Promise::block_until_ready_mut", reason = "Cannot block on Web" },
+  { path = "poll_promise::Promise::block_until_ready", reason = "Cannot block on Web" },
+  { path = "rayon::spawn", reason = "Cannot spawn threads on wasm" },
+  { path = "std::sync::mpsc::Receiver::into_iter", reason = "Cannot block on Web" },
+  { path = "std::sync::mpsc::Receiver::iter", reason = "Cannot block on Web" },
+  { path = "std::sync::mpsc::Receiver::recv_timeout", reason = "Cannot block on Web" },
+  { path = "std::sync::mpsc::Receiver::recv", reason = "Cannot block on Web" },
+  { path = "std::thread::spawn", reason = "Cannot spawn threads on wasm" },
+  { path = "std::time::Duration::elapsed", reason = "use `web-time` crate instead for wasm/web compatibility" },
+  { path = "std::time::Instant::now", reason = "use `web-time` crate instead for wasm/web compatibility" },
+  { path = "std::time::SystemTime::now", reason = "use `web-time` or `time` crates instead for wasm/web compatibility" },
+]
+
+# https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
+disallowed-types = [
+  { path = "instant::SystemTime", reason = "Known bugs. Use web-time." },
+  { path = "std::thread::Builder", reason = "Cannot spawn threads on wasm" },
+  # { path = "std::path::PathBuf", reason = "Can't read/write files on web" }, // Used in build.rs files (which is fine).
+]
+
+# Allow-list of words for markdown in docstrings https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
+doc-valid-idents = [
+  # You must also update the same list in the root `clippy.toml`!
+  "..",
+  "GitHub",
+  "GLB",
+  "GLTF",
+  "iOS",
+  "macOS",
+  "NaN",
+  "OBJ",
+  "OpenGL",
+  "PyPI",
+  "sRGB",
+  "sRGBA",
+  "WebGL",
+  "WebSocket",
+  "WebSockets",
+]

From b51d2712d0a8bc0bed5b9507296305f4e054f69a Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:19:07 +0200
Subject: [PATCH 19/32] Add back some implicit lifetimes

---
 src/mp4box/ilst.rs |  8 ++++----
 src/types.rs       | 34 +++++++++++++++++-----------------
 2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/src/mp4box/ilst.rs b/src/mp4box/ilst.rs
index b3f7c20..b4147f0 100644
--- a/src/mp4box/ilst.rs
+++ b/src/mp4box/ilst.rs
@@ -8,7 +8,7 @@ use serde::Serialize;
 use crate::mp4box::data::DataBox;
 use crate::mp4box::{
     box_start, skip_box, skip_bytes_to, BigEndian, BoxHeader, BoxType, DataType, Error, Metadata,
-    MetadataKey, Mp4Box, ReadBox, ReadBytesExt, Result, HEADER_SIZE,
+    MetadataKey, Mp4Box, ReadBox, Result, HEADER_SIZE,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
@@ -150,7 +150,7 @@ impl ReadBox<&mut R> for IlstItemBox {
 }
 
 impl<'a> Metadata<'a> for IlstBox {
-    fn title(&self) -> Option> {
+    fn title(&self) -> Option> {
         self.items.get(&MetadataKey::Title).map(item_to_str)
     }
 
@@ -162,7 +162,7 @@ impl<'a> Metadata<'a> for IlstBox {
         self.items.get(&MetadataKey::Poster).map(item_to_bytes)
     }
 
-    fn summary(&self) -> Option> {
+    fn summary(&self) -> Option> {
         self.items.get(&MetadataKey::Summary).map(item_to_str)
     }
 }
@@ -171,7 +171,7 @@ fn item_to_bytes(item: &IlstItemBox) -> &[u8] {
     &item.data.data
 }
 
-fn item_to_str(item: &IlstItemBox) -> Cow {
+fn item_to_str(item: &IlstItemBox) -> Cow<'_, str> {
     String::from_utf8_lossy(&item.data.data)
 }
 
diff --git a/src/types.rs b/src/types.rs
index 48c3ae6..54f7af0 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -3,7 +3,7 @@ use std::borrow::Cow;
 use std::convert::TryFrom;
 use std::fmt;
 
-use crate::mp4box::{BoxType, Mp4Box};
+use crate::mp4box::BoxType;
 use crate::{Error, Result};
 
 pub use bytes::Bytes;
@@ -73,14 +73,14 @@ impl FixedPointU16 {
 }
 
 impl fmt::Debug for BoxType {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let fourcc: FourCC = From::from(*self);
         write!(f, "{fourcc}")
     }
 }
 
 impl fmt::Display for BoxType {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let fourcc: FourCC = From::from(*self);
         write!(f, "{fourcc}")
     }
@@ -139,7 +139,7 @@ impl From for FourCC {
 }
 
 impl fmt::Debug for FourCC {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let code: u32 = self.into();
         let string = String::from_utf8_lossy(&self.value[..]);
         write!(f, "{string} / {code:#010X}")
@@ -147,7 +147,7 @@ impl fmt::Debug for FourCC {
 }
 
 impl fmt::Display for FourCC {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", String::from_utf8_lossy(&self.value[..]))
     }
 }
@@ -173,7 +173,7 @@ pub enum TrackKind {
 }
 
 impl fmt::Display for TrackKind {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s = match self {
             Self::Video => DISPLAY_TYPE_VIDEO,
             Self::Audio => DISPLAY_TYPE_AUDIO,
@@ -233,7 +233,7 @@ pub enum MediaType {
 }
 
 impl fmt::Display for MediaType {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s: &str = self.into();
         write!(f, "{s}")
     }
@@ -304,7 +304,7 @@ impl TryFrom<(u8, u8)> for AvcProfile {
 }
 
 impl fmt::Display for AvcProfile {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let profile = match self {
             Self::AvcConstrainedBaseline => "Constrained Baseline",
             Self::AvcBaseline => "Baseline",
@@ -414,7 +414,7 @@ impl TryFrom for AudioObjectType {
 }
 
 impl fmt::Display for AudioObjectType {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let type_str = match self {
             Self::AacMain => "AAC Main",
             Self::AacLowComplexity => "LC",
@@ -550,7 +550,7 @@ impl TryFrom for ChannelConfig {
 }
 
 impl fmt::Display for ChannelConfig {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s = match self {
             Self::Mono => "mono",
             Self::Stereo => "stereo",
@@ -635,7 +635,7 @@ impl PartialEq for Mp4Sample {
 }
 
 impl fmt::Display for Mp4Sample {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
             "start_time {}, duration {}, rendering_offset {}, is_sync {}, length {}",
@@ -695,17 +695,17 @@ pub enum MetadataKey {
 
 pub trait Metadata<'a> {
     /// The video's title
-    fn title(&self) -> Option>;
+    fn title(&self) -> Option>;
     /// The video's release year
     fn year(&self) -> Option;
     /// The video's poster (cover art)
     fn poster(&self) -> Option<&[u8]>;
     /// The video's summary
-    fn summary(&self) -> Option>;
+    fn summary(&self) -> Option>;
 }
 
 impl<'a, T: Metadata<'a>> Metadata<'a> for &'a T {
-    fn title(&self) -> Option> {
+    fn title(&self) -> Option> {
         (**self).title()
     }
 
@@ -717,13 +717,13 @@ impl<'a, T: Metadata<'a>> Metadata<'a> for &'a T {
         (**self).poster()
     }
 
-    fn summary(&self) -> Option> {
+    fn summary(&self) -> Option> {
         (**self).summary()
     }
 }
 
 impl<'a, T: Metadata<'a>> Metadata<'a> for Option {
-    fn title(&self) -> Option> {
+    fn title(&self) -> Option> {
         self.as_ref().and_then(|t| t.title())
     }
 
@@ -735,7 +735,7 @@ impl<'a, T: Metadata<'a>> Metadata<'a> for Option {
         self.as_ref().and_then(|t| t.poster())
     }
 
-    fn summary(&self) -> Option> {
+    fn summary(&self) -> Option> {
         self.as_ref().and_then(|t| t.summary())
     }
 }

From 228e2fcf29e3c56bde3d6615dce36ce91d45a76f Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:20:55 +0200
Subject: [PATCH 20/32] Use `.expect()` when failing to convert to JSON

---
 src/mp4box/av01.rs | 4 ++--
 src/mp4box/avc1.rs | 4 ++--
 src/mp4box/co64.rs | 2 +-
 src/mp4box/ctts.rs | 2 +-
 src/mp4box/data.rs | 2 +-
 src/mp4box/dinf.rs | 6 +++---
 src/mp4box/edts.rs | 2 +-
 src/mp4box/elst.rs | 2 +-
 src/mp4box/emsg.rs | 2 +-
 src/mp4box/ftyp.rs | 2 +-
 src/mp4box/hdlr.rs | 2 +-
 src/mp4box/hvc1.rs | 6 +++---
 src/mp4box/ilst.rs | 2 +-
 src/mp4box/mdhd.rs | 2 +-
 src/mp4box/mdia.rs | 2 +-
 src/mp4box/mehd.rs | 2 +-
 src/mp4box/meta.rs | 2 +-
 src/mp4box/mfhd.rs | 2 +-
 src/mp4box/minf.rs | 2 +-
 src/mp4box/moof.rs | 2 +-
 src/mp4box/moov.rs | 2 +-
 src/mp4box/mp4a.rs | 4 ++--
 src/mp4box/mvex.rs | 2 +-
 src/mp4box/mvhd.rs | 2 +-
 src/mp4box/smhd.rs | 2 +-
 src/mp4box/stbl.rs | 2 +-
 src/mp4box/stco.rs | 2 +-
 src/mp4box/stsc.rs | 2 +-
 src/mp4box/stsd.rs | 2 +-
 src/mp4box/stss.rs | 2 +-
 src/mp4box/stsz.rs | 2 +-
 src/mp4box/stts.rs | 2 +-
 src/mp4box/tfdt.rs | 2 +-
 src/mp4box/tfhd.rs | 2 +-
 src/mp4box/tkhd.rs | 2 +-
 src/mp4box/traf.rs | 2 +-
 src/mp4box/trak.rs | 2 +-
 src/mp4box/trex.rs | 2 +-
 src/mp4box/trun.rs | 2 +-
 src/mp4box/tx3g.rs | 2 +-
 src/mp4box/udta.rs | 2 +-
 src/mp4box/vmhd.rs | 2 +-
 src/mp4box/vp08.rs | 2 +-
 src/mp4box/vp09.rs | 2 +-
 src/mp4box/vpcc.rs | 2 +-
 45 files changed, 52 insertions(+), 52 deletions(-)

diff --git a/src/mp4box/av01.rs b/src/mp4box/av01.rs
index e0ada0c..212ac81 100644
--- a/src/mp4box/av01.rs
+++ b/src/mp4box/av01.rs
@@ -43,7 +43,7 @@ impl Mp4Box for Av01Box {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
@@ -125,7 +125,7 @@ impl Mp4Box for Av1CBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/avc1.rs b/src/mp4box/avc1.rs
index 25f6208..866e839 100644
--- a/src/mp4box/avc1.rs
+++ b/src/mp4box/avc1.rs
@@ -58,7 +58,7 @@ impl Mp4Box for Avc1Box {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
@@ -170,7 +170,7 @@ impl Mp4Box for AvcCBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs
index d164551..299fbfa 100644
--- a/src/mp4box/co64.rs
+++ b/src/mp4box/co64.rs
@@ -37,7 +37,7 @@ impl Mp4Box for Co64Box {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs
index bd855ca..1f5e6ba 100644
--- a/src/mp4box/ctts.rs
+++ b/src/mp4box/ctts.rs
@@ -43,7 +43,7 @@ impl Mp4Box for CttsBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/data.rs b/src/mp4box/data.rs
index 8ae57f4..a73ac5d 100644
--- a/src/mp4box/data.rs
+++ b/src/mp4box/data.rs
@@ -39,7 +39,7 @@ impl Mp4Box for DataBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs
index 6aaad7d..5130c60 100644
--- a/src/mp4box/dinf.rs
+++ b/src/mp4box/dinf.rs
@@ -31,7 +31,7 @@ impl Mp4Box for DinfBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
@@ -126,7 +126,7 @@ impl Mp4Box for DrefBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
@@ -226,7 +226,7 @@ impl Mp4Box for UrlBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/edts.rs b/src/mp4box/edts.rs
index d80ef03..f366426 100644
--- a/src/mp4box/edts.rs
+++ b/src/mp4box/edts.rs
@@ -39,7 +39,7 @@ impl Mp4Box for EdtsBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/elst.rs b/src/mp4box/elst.rs
index d34b0ca..c8a2c95 100644
--- a/src/mp4box/elst.rs
+++ b/src/mp4box/elst.rs
@@ -51,7 +51,7 @@ impl Mp4Box for ElstBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/emsg.rs b/src/mp4box/emsg.rs
index 0554516..74e9fdb 100644
--- a/src/mp4box/emsg.rs
+++ b/src/mp4box/emsg.rs
@@ -52,7 +52,7 @@ impl Mp4Box for EmsgBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs
index 5e972f5..fc10fcb 100644
--- a/src/mp4box/ftyp.rs
+++ b/src/mp4box/ftyp.rs
@@ -33,7 +33,7 @@ impl Mp4Box for FtypBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/hdlr.rs b/src/mp4box/hdlr.rs
index 1ab2b91..3a19d99 100644
--- a/src/mp4box/hdlr.rs
+++ b/src/mp4box/hdlr.rs
@@ -35,7 +35,7 @@ impl Mp4Box for HdlrBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/hvc1.rs b/src/mp4box/hvc1.rs
index 915722a..61ed198 100644
--- a/src/mp4box/hvc1.rs
+++ b/src/mp4box/hvc1.rs
@@ -58,7 +58,7 @@ impl Mp4Box for Hvc1Box {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
@@ -166,11 +166,11 @@ impl Mp4Box for HvcCBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
-        Ok(format!("configuration_version={} general_profile_space={} general_tier_flag={} general_profile_idc={} general_profile_compatibility_flags={} general_constraint_indicator_flag={} general_level_idc={} min_spatial_segmentation_idc={} parallelism_type={} chroma_format_idc={} bit_depth_luma_minus8={} bit_depth_chroma_minus8={} avg_frame_rate={} constant_frame_rate={} num_temporal_layers={} temporal_id_nested={} length_size_minus_one={}", 
+        Ok(format!("configuration_version={} general_profile_space={} general_tier_flag={} general_profile_idc={} general_profile_compatibility_flags={} general_constraint_indicator_flag={} general_level_idc={} min_spatial_segmentation_idc={} parallelism_type={} chroma_format_idc={} bit_depth_luma_minus8={} bit_depth_chroma_minus8={} avg_frame_rate={} constant_frame_rate={} num_temporal_layers={} temporal_id_nested={} length_size_minus_one={}",
             self.configuration_version,
             self.general_profile_space,
             self.general_tier_flag,
diff --git a/src/mp4box/ilst.rs b/src/mp4box/ilst.rs
index b4147f0..71727d7 100644
--- a/src/mp4box/ilst.rs
+++ b/src/mp4box/ilst.rs
@@ -40,7 +40,7 @@ impl Mp4Box for IlstBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/mdhd.rs b/src/mp4box/mdhd.rs
index 31e6ec7..2947c71 100644
--- a/src/mp4box/mdhd.rs
+++ b/src/mp4box/mdhd.rs
@@ -61,7 +61,7 @@ impl Mp4Box for MdhdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/mdia.rs b/src/mp4box/mdia.rs
index e2b991f..5f785fd 100644
--- a/src/mp4box/mdia.rs
+++ b/src/mp4box/mdia.rs
@@ -34,7 +34,7 @@ impl Mp4Box for MdiaBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/mehd.rs b/src/mp4box/mehd.rs
index dd0edd8..abfeeb8 100644
--- a/src/mp4box/mehd.rs
+++ b/src/mp4box/mehd.rs
@@ -41,7 +41,7 @@ impl Mp4Box for MehdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/meta.rs b/src/mp4box/meta.rs
index 4571b74..bbcea02 100644
--- a/src/mp4box/meta.rs
+++ b/src/mp4box/meta.rs
@@ -66,7 +66,7 @@ impl Mp4Box for MetaBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/mfhd.rs b/src/mp4box/mfhd.rs
index 9f58e09..8793f0f 100644
--- a/src/mp4box/mfhd.rs
+++ b/src/mp4box/mfhd.rs
@@ -44,7 +44,7 @@ impl Mp4Box for MfhdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/minf.rs b/src/mp4box/minf.rs
index 0e454a7..14d078d 100644
--- a/src/mp4box/minf.rs
+++ b/src/mp4box/minf.rs
@@ -48,7 +48,7 @@ impl Mp4Box for MinfBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs
index 516294d..1b83132 100644
--- a/src/mp4box/moof.rs
+++ b/src/mp4box/moof.rs
@@ -42,7 +42,7 @@ impl Mp4Box for MoofBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs
index 2302fe5..ec8c880 100644
--- a/src/mp4box/moov.rs
+++ b/src/mp4box/moov.rs
@@ -55,7 +55,7 @@ impl Mp4Box for MoovBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs
index ccdb18b..1c0ca3e 100644
--- a/src/mp4box/mp4a.rs
+++ b/src/mp4box/mp4a.rs
@@ -64,7 +64,7 @@ impl Mp4Box for Mp4aBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
@@ -169,7 +169,7 @@ impl Mp4Box for EsdsBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/mvex.rs b/src/mp4box/mvex.rs
index e60013f..803de9e 100644
--- a/src/mp4box/mvex.rs
+++ b/src/mp4box/mvex.rs
@@ -35,7 +35,7 @@ impl Mp4Box for MvexBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/mvhd.rs b/src/mp4box/mvhd.rs
index 2b2c734..b96649f 100644
--- a/src/mp4box/mvhd.rs
+++ b/src/mp4box/mvhd.rs
@@ -70,7 +70,7 @@ impl Mp4Box for MvhdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/smhd.rs b/src/mp4box/smhd.rs
index 7c4c44c..4ef9405 100644
--- a/src/mp4box/smhd.rs
+++ b/src/mp4box/smhd.rs
@@ -46,7 +46,7 @@ impl Mp4Box for SmhdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/stbl.rs b/src/mp4box/stbl.rs
index 4a196af..769772f 100644
--- a/src/mp4box/stbl.rs
+++ b/src/mp4box/stbl.rs
@@ -67,7 +67,7 @@ impl Mp4Box for StblBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/stco.rs b/src/mp4box/stco.rs
index 82b02a4..b8f1294 100644
--- a/src/mp4box/stco.rs
+++ b/src/mp4box/stco.rs
@@ -37,7 +37,7 @@ impl Mp4Box for StcoBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs
index 484957c..3aedff5 100644
--- a/src/mp4box/stsc.rs
+++ b/src/mp4box/stsc.rs
@@ -45,7 +45,7 @@ impl Mp4Box for StscBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs
index f10f33d..f839461 100644
--- a/src/mp4box/stsd.rs
+++ b/src/mp4box/stsd.rs
@@ -93,7 +93,7 @@ impl Mp4Box for StsdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/stss.rs b/src/mp4box/stss.rs
index 6f99abf..06e8763 100644
--- a/src/mp4box/stss.rs
+++ b/src/mp4box/stss.rs
@@ -37,7 +37,7 @@ impl Mp4Box for StssBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs
index 7610661..a0204ec 100644
--- a/src/mp4box/stsz.rs
+++ b/src/mp4box/stsz.rs
@@ -39,7 +39,7 @@ impl Mp4Box for StszBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs
index 9866529..9cd0413 100644
--- a/src/mp4box/stts.rs
+++ b/src/mp4box/stts.rs
@@ -43,7 +43,7 @@ impl Mp4Box for SttsBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/tfdt.rs b/src/mp4box/tfdt.rs
index 3ad7881..4cbfd58 100644
--- a/src/mp4box/tfdt.rs
+++ b/src/mp4box/tfdt.rs
@@ -40,7 +40,7 @@ impl Mp4Box for TfdtBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/tfhd.rs b/src/mp4box/tfhd.rs
index 057e614..f01e7a7 100644
--- a/src/mp4box/tfhd.rs
+++ b/src/mp4box/tfhd.rs
@@ -63,7 +63,7 @@ impl Mp4Box for TfhdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/tkhd.rs b/src/mp4box/tkhd.rs
index ab87b48..acc4192 100644
--- a/src/mp4box/tkhd.rs
+++ b/src/mp4box/tkhd.rs
@@ -129,7 +129,7 @@ impl Mp4Box for TkhdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs
index a7dd840..0c0da9d 100644
--- a/src/mp4box/traf.rs
+++ b/src/mp4box/traf.rs
@@ -42,7 +42,7 @@ impl Mp4Box for TrafBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/trak.rs b/src/mp4box/trak.rs
index c9ed5a2..13ef116 100644
--- a/src/mp4box/trak.rs
+++ b/src/mp4box/trak.rs
@@ -47,7 +47,7 @@ impl Mp4Box for TrakBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/trex.rs b/src/mp4box/trex.rs
index b1e7c5a..62b1870 100644
--- a/src/mp4box/trex.rs
+++ b/src/mp4box/trex.rs
@@ -38,7 +38,7 @@ impl Mp4Box for TrexBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs
index 26baae0..68df5c1 100644
--- a/src/mp4box/trun.rs
+++ b/src/mp4box/trun.rs
@@ -72,7 +72,7 @@ impl Mp4Box for TrunBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/tx3g.rs b/src/mp4box/tx3g.rs
index a489e80..18ee432 100644
--- a/src/mp4box/tx3g.rs
+++ b/src/mp4box/tx3g.rs
@@ -62,7 +62,7 @@ impl Mp4Box for Tx3gBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/udta.rs b/src/mp4box/udta.rs
index 1ae2005..ad5b212 100644
--- a/src/mp4box/udta.rs
+++ b/src/mp4box/udta.rs
@@ -38,7 +38,7 @@ impl Mp4Box for UdtaBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/vmhd.rs b/src/mp4box/vmhd.rs
index 9ba48bd..642fb6d 100644
--- a/src/mp4box/vmhd.rs
+++ b/src/mp4box/vmhd.rs
@@ -42,7 +42,7 @@ impl Mp4Box for VmhdBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/vp08.rs b/src/mp4box/vp08.rs
index 4e3418c..61d7d56 100644
--- a/src/mp4box/vp08.rs
+++ b/src/mp4box/vp08.rs
@@ -35,7 +35,7 @@ impl Mp4Box for Vp08Box {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/vp09.rs b/src/mp4box/vp09.rs
index 076b172..a9d6ff2 100644
--- a/src/mp4box/vp09.rs
+++ b/src/mp4box/vp09.rs
@@ -36,7 +36,7 @@ impl Mp4Box for Vp09Box {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {
diff --git a/src/mp4box/vpcc.rs b/src/mp4box/vpcc.rs
index 4631c80..547b0b0 100644
--- a/src/mp4box/vpcc.rs
+++ b/src/mp4box/vpcc.rs
@@ -35,7 +35,7 @@ impl Mp4Box for VpccBox {
     }
 
     fn to_json(&self) -> Result {
-        Ok(serde_json::to_string(&self).unwrap())
+        Ok(serde_json::to_string(&self).expect("Failed to convert to JSON"))
     }
 
     fn summary(&self) -> Result {

From c109d2b025e7d187a27c409abee9e21d12a5d202 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:25:02 +0200
Subject: [PATCH 21/32] Use `.to_owned()`

---
 src/mp4box/meta.rs | 2 +-
 src/reader.rs      | 2 +-
 tests/lib.rs       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/mp4box/meta.rs b/src/mp4box/meta.rs
index bbcea02..2054869 100644
--- a/src/mp4box/meta.rs
+++ b/src/mp4box/meta.rs
@@ -71,7 +71,7 @@ impl Mp4Box for MetaBox {
 
     fn summary(&self) -> Result {
         let s = match self {
-            Self::Mdir { .. } => "hdlr=ilst".to_string(),
+            Self::Mdir { .. } => "hdlr=ilst".to_owned(),
             Self::Unknown { hdlr, data } => {
                 format!("hdlr={} data_len={}", hdlr.handler_type, data.len())
             }
diff --git a/src/reader.rs b/src/reader.rs
index a193a9c..e7ea86f 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -499,7 +499,7 @@ impl Track {
 
             format!("avc1.{profile:02X}{constraint:02X}{level:02X}")
         } else if let Some(Hvc1Box { hvcc, .. }) = &sample_description.hvc1 {
-            let mut codec = "hvc1".to_string();
+            let mut codec = "hvc1".to_owned();
             match hvcc.general_profile_space {
                 0 => {}
                 1 => codec.push_str(".A"),
diff --git a/tests/lib.rs b/tests/lib.rs
index 4484d79..9d8288b 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -59,7 +59,7 @@ fn assert_video_snapshot(file_path: &str) {
                 &base_path.join(format!("{file_path}.track_{id}.json")),
                 format!(
                     r#"{{ "codec": {:?}, "width": {}, "height": {}, "num_samples": {}, "description": {:?} }}"#,
-                    track.codec_string(&video).unwrap_or("unknown".to_string()),
+                    track.codec_string(&video).unwrap_or("unknown".to_owned()),
                     track.width,
                     track.height,
                     track.samples.len(),

From daa9062a2fc7dd1963edfd75b9d84fe77dd01f7a Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:44:42 +0200
Subject: [PATCH 22/32] Some manual clippy fixes

---
 clippy.toml        |  1 +
 src/mp4box/emsg.rs |  4 ++-
 src/mp4box/ilst.rs |  6 +---
 src/mp4box/meta.rs | 72 +++++++++++++++++++++-------------------------
 src/mp4box/mod.rs  |  9 +++---
 src/reader.rs      | 13 ++++-----
 6 files changed, 48 insertions(+), 57 deletions(-)

diff --git a/clippy.toml b/clippy.toml
index 9673121..1a23265 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -71,6 +71,7 @@ doc-valid-idents = [
   "OBJ",
   "OpenGL",
   "PyPI",
+  "QuickTime",
   "sRGB",
   "sRGBA",
   "WebGL",
diff --git a/src/mp4box/emsg.rs b/src/mp4box/emsg.rs
index 74e9fdb..8c69b37 100644
--- a/src/mp4box/emsg.rs
+++ b/src/mp4box/emsg.rs
@@ -132,8 +132,10 @@ fn read_null_terminated_utf8_string(reader: &mut R) -> Result u64 {
-        let mut size = HEADER_SIZE;
-        for item in self.items.values() {
-            size += item.get_size();
-        }
-        size
+        HEADER_SIZE + self.items.values().map(|item| item.get_size()).sum::()
     }
 }
 
diff --git a/src/mp4box/meta.rs b/src/mp4box/meta.rs
index 2054869..93b8f0f 100644
--- a/src/mp4box/meta.rs
+++ b/src/mp4box/meta.rs
@@ -143,53 +143,47 @@ impl ReadBox<&mut R> for MetaBox {
 
         let mut ilst = None;
 
-        match hdlr.handler_type {
-            MDIR => {
-                while current < end {
-                    // Get box header.
-                    let header = BoxHeader::read(reader)?;
-                    let BoxHeader { name, size: s } = header;
-
-                    match name {
-                        BoxType::IlstBox => {
-                            ilst = Some(IlstBox::read_box(reader, s)?);
-                        }
-                        _ => {
-                            // XXX warn!()
-                            skip_box(reader, s)?;
-                        }
+        if hdlr.handler_type == MDIR {
+            while current < end {
+                // Get box header.
+                let header = BoxHeader::read(reader)?;
+                let BoxHeader { name, size: s } = header;
+
+                match name {
+                    BoxType::IlstBox => {
+                        ilst = Some(IlstBox::read_box(reader, s)?);
+                    }
+                    _ => {
+                        // XXX warn!()
+                        skip_box(reader, s)?;
                     }
-
-                    current = reader.stream_position()?;
                 }
 
-                Ok(Self::Mdir { ilst })
+                current = reader.stream_position()?;
             }
-            _ => {
-                let mut data = Vec::new();
-
-                while current < end {
-                    // Get box header.
-                    let header = BoxHeader::read(reader)?;
-                    let BoxHeader { name, size: s } = header;
-
-                    match name {
-                        BoxType::HdlrBox => {
-                            skip_box(reader, s)?;
-                        }
-                        _ => {
-                            let mut box_data = vec![0; (s - HEADER_SIZE) as usize];
-                            reader.read_exact(&mut box_data)?;
-
-                            data.push((name, box_data));
-                        }
-                    }
 
-                    current = reader.stream_position()?;
+            Ok(Self::Mdir { ilst })
+        } else {
+            let mut data = Vec::new();
+
+            while current < end {
+                // Get box header.
+                let header = BoxHeader::read(reader)?;
+                let BoxHeader { name, size: s } = header;
+
+                if name == BoxType::HdlrBox {
+                    skip_box(reader, s)?;
+                } else {
+                    let mut box_data = vec![0; (s - HEADER_SIZE) as usize];
+                    reader.read_exact(&mut box_data)?;
+
+                    data.push((name, box_data));
                 }
 
-                Ok(Self::Unknown { hdlr, data })
+                current = reader.stream_position()?;
             }
+
+            Ok(Self::Unknown { hdlr, data })
         }
     }
 }
diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs
index 7278618..7987fa9 100644
--- a/src/mp4box/mod.rs
+++ b/src/mp4box/mod.rs
@@ -5,11 +5,12 @@
 //! * ISO/IEC 14496-17 - Streaming text format
 //! * [ISO 23009-1](https://www.iso.org/standard/79329.html) -Dynamic adaptive streaming over HTTP (DASH)
 //!
-//! http://developer.apple.com/documentation/QuickTime/QTFF/index.html
-//! http://www.adobe.com/devnet/video/articles/mp4_movie_atom.html
-//! http://mp4ra.org/#/atoms
+//! * 
+//! * 
+//! * 
 //!
 //! Supported Atoms:
+//! ```text
 //! ftyp
 //! moov
 //!     mvhd
@@ -54,7 +55,7 @@
 //!         trun
 //! mdat
 //! free
-//!
+//! ```
 
 use byteorder::{BigEndian, ReadBytesExt};
 use serde::Serialize;
diff --git a/src/reader.rs b/src/reader.rs
index e7ea86f..7da3fdb 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -417,15 +417,13 @@ impl Mp4 {
                 sample.offset = data_offset as u64;
             }
 
-            track.duration = if track.duration == 0 {
-                track
+            if track.duration == 0 {
+                track.duration = track
                     .samples
                     .last()
                     .map(|v| v.timestamp + v.duration)
-                    .unwrap_or_default()
-            } else {
-                track.duration
-            };
+                    .unwrap_or_default();
+            }
         }
 
         Ok(())
@@ -501,7 +499,6 @@ impl Track {
         } else if let Some(Hvc1Box { hvcc, .. }) = &sample_description.hvc1 {
             let mut codec = "hvc1".to_owned();
             match hvcc.general_profile_space {
-                0 => {}
                 1 => codec.push_str(".A"),
                 2 => codec.push_str(".B"),
                 3 => codec.push_str(".C"),
@@ -596,7 +593,7 @@ impl Mp4 {
         self.moov.udta.as_ref().and_then(|udta| {
             udta.meta.as_ref().and_then(|meta| match meta {
                 MetaBox::Mdir { ilst } => ilst.as_ref(),
-                _ => None,
+                MetaBox::Unknown { .. } => None,
             })
         })
     }

From 7c95787a13ae55428ecfdf75e82936cabf63e0f0 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:44:52 +0200
Subject: [PATCH 23/32] Add clippy lints to Cargo.toml

---
 Cargo.toml | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)

diff --git a/Cargo.toml b/Cargo.toml
index d40d881..d67b0af 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,3 +31,182 @@ num-rational = { version = "0.4.0", features = ["serde"] }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 thiserror = "^1.0"
+
+
+[dev-dependencies]
+
+
+[patch.crates-io]
+
+
+[lints]
+workspace = true
+
+
+[workspace.lints.rust]
+unsafe_code = "deny"
+
+elided_lifetimes_in_paths = "warn"
+future_incompatible = "warn"
+nonstandard_style = "warn"
+rust_2018_idioms = "warn"
+rust_2021_prelude_collisions = "warn"
+semicolon_in_expressions_from_macros = "warn"
+trivial_numeric_casts = "warn"
+unsafe_op_in_unsafe_fn = "warn"               # `unsafe_op_in_unsafe_fn` may become the default in future Rust versions: https://github.com/rust-lang/rust/issues/71668
+unused_extern_crates = "warn"
+unused_import_braces = "warn"
+unused_lifetimes = "warn"
+
+trivial_casts = "allow"
+unused_qualifications = "allow"
+
+[workspace.lints.rustdoc]
+all = "warn"
+missing_crate_level_docs = "warn"
+
+# See also clippy.toml
+[workspace.lints.clippy]
+as_ptr_cast_mut = "warn"
+await_holding_lock = "warn"
+bool_to_int_with_if = "warn"
+char_lit_as_u8 = "warn"
+checked_conversions = "warn"
+clear_with_drain = "warn"
+cloned_instead_of_copied = "warn"
+dbg_macro = "warn"
+debug_assert_with_mut_call = "warn"
+derive_partial_eq_without_eq = "warn"
+disallowed_macros = "warn"                  # See clippy.toml
+disallowed_methods = "warn"                 # See clippy.toml
+disallowed_names = "warn"                   # See clippy.toml
+disallowed_script_idents = "warn"           # See clippy.toml
+disallowed_types = "warn"                   # See clippy.toml
+doc_link_with_quotes = "warn"
+doc_markdown = "warn"
+empty_enum = "warn"
+enum_glob_use = "warn"
+equatable_if_let = "warn"
+exit = "warn"
+expl_impl_clone_on_copy = "warn"
+explicit_deref_methods = "warn"
+explicit_into_iter_loop = "warn"
+explicit_iter_loop = "warn"
+fallible_impl_from = "warn"
+filter_map_next = "warn"
+flat_map_option = "warn"
+float_cmp_const = "warn"
+fn_params_excessive_bools = "warn"
+fn_to_numeric_cast_any = "warn"
+from_iter_instead_of_collect = "warn"
+get_unwrap = "warn"
+if_let_mutex = "warn"
+implicit_clone = "warn"
+imprecise_flops = "warn"
+index_refutable_slice = "warn"
+inefficient_to_string = "warn"
+infinite_loop = "warn"
+into_iter_without_iter = "warn"
+invalid_upcast_comparisons = "warn"
+iter_not_returning_iterator = "warn"
+iter_on_empty_collections = "warn"
+iter_on_single_items = "warn"
+iter_without_into_iter = "warn"
+large_digit_groups = "warn"
+large_include_file = "warn"
+large_stack_arrays = "warn"
+large_stack_frames = "warn"
+large_types_passed_by_value = "warn"
+let_underscore_must_use = "warn"
+let_underscore_untyped = "warn"
+let_unit_value = "warn"
+linkedlist = "warn"
+lossy_float_literal = "warn"
+macro_use_imports = "warn"
+manual_assert = "warn"
+manual_clamp = "warn"
+manual_instant_elapsed = "warn"
+manual_let_else = "warn"
+manual_ok_or = "warn"
+manual_string_new = "warn"
+map_err_ignore = "warn"
+map_flatten = "warn"
+map_unwrap_or = "warn"
+match_bool = "warn"
+match_on_vec_items = "warn"
+match_same_arms = "warn"
+match_wild_err_arm = "warn"
+match_wildcard_for_single_variants = "warn"
+mem_forget = "warn"
+mismatched_target_os = "warn"
+mismatching_type_param_order = "warn"
+missing_assert_message = "warn"
+missing_enforced_import_renames = "warn"
+missing_safety_doc = "warn"
+mut_mut = "warn"
+mutex_integer = "warn"
+needless_borrow = "warn"
+needless_continue = "warn"
+needless_for_each = "warn"
+needless_pass_by_ref_mut = "warn"
+needless_pass_by_value = "warn"
+negative_feature_names = "warn"
+nonstandard_macro_braces = "warn"
+option_option = "warn"
+path_buf_push_overwrite = "warn"
+ptr_as_ptr = "warn"
+ptr_cast_constness = "warn"
+pub_without_shorthand = "warn"
+rc_mutex = "warn"
+readonly_write_lock = "warn"
+redundant_type_annotations = "warn"
+ref_option_ref = "warn"
+rest_pat_in_fully_bound_structs = "warn"
+same_functions_in_if_condition = "warn"
+semicolon_if_nothing_returned = "warn"
+should_panic_without_expect = "warn"
+significant_drop_tightening = "warn"
+single_match_else = "warn"
+str_to_string = "warn"
+string_add = "warn"
+string_add_assign = "warn"
+string_lit_as_bytes = "warn"
+string_lit_chars_any = "warn"
+string_to_string = "warn"
+suspicious_command_arg_space = "warn"
+suspicious_xor_used_as_pow = "warn"
+todo = "warn"
+too_many_lines = "warn"
+trailing_empty_array = "warn"
+trait_duplication_in_bounds = "warn"
+tuple_array_conversions = "warn"
+unchecked_duration_subtraction = "warn"
+undocumented_unsafe_blocks = "warn"
+unimplemented = "warn"
+uninhabited_references = "warn"
+uninlined_format_args = "warn"
+unnecessary_box_returns = "warn"
+unnecessary_safety_doc = "warn"
+unnecessary_struct_initialization = "warn"
+unnecessary_wraps = "warn"
+unnested_or_patterns = "warn"
+unused_peekable = "warn"
+unused_rounding = "warn"
+use_self = "warn"
+useless_transmute = "warn"
+verbose_file_reads = "warn"
+wildcard_dependencies = "warn"
+wildcard_imports = "warn"
+zero_sized_map_values = "warn"
+
+manual_range_contains = "allow" # this one is just worse imho
+ref_patterns = "allow"          # It's nice to avoid ref pattern, but there are some situations that are hard (impossible?) to express without.
+
+# TODO(emilk): consider enabling these:
+enum_variant_names = "allow"
+excessive_nesting = "allow"
+iter_over_hash_type = "allow"
+missing_errors_doc = "allow"
+unused_self = "allow"
+unwrap_used = "allow"
+upper_case_acronyms = "allow"

From 2d0ff947a29f636519ed7458a43289a6765113a1 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:52:02 +0200
Subject: [PATCH 24/32] Remove some `unwrap`s

---
 src/mp4box/dinf.rs |  8 +++-----
 src/mp4box/ilst.rs |  8 +++-----
 src/mp4box/mdia.rs | 18 +++++++-----------
 src/mp4box/minf.rs | 12 ++++++------
 src/mp4box/moof.rs | 10 +++-------
 src/mp4box/moov.rs |  6 +++---
 src/mp4box/mp4a.rs |  6 +++---
 src/mp4box/stbl.rs | 24 ++++++++++++------------
 src/mp4box/traf.rs | 10 +++-------
 src/mp4box/trak.rs | 12 ++++++------
 src/reader.rs      | 12 ++++++------
 11 files changed, 55 insertions(+), 71 deletions(-)

diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs
index 5130c60..0a58fec 100644
--- a/src/mp4box/dinf.rs
+++ b/src/mp4box/dinf.rs
@@ -71,15 +71,13 @@ impl ReadBox<&mut R> for DinfBox {
             current = reader.stream_position()?;
         }
 
-        if dref.is_none() {
+        let Some(dref) = dref else {
             return Err(Error::BoxNotFound(BoxType::DrefBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(Self {
-            dref: dref.unwrap(),
-        })
+        Ok(Self { dref })
     }
 }
 
diff --git a/src/mp4box/ilst.rs b/src/mp4box/ilst.rs
index 3ee619a..c94314b 100644
--- a/src/mp4box/ilst.rs
+++ b/src/mp4box/ilst.rs
@@ -133,15 +133,13 @@ impl ReadBox<&mut R> for IlstItemBox {
             current = reader.stream_position()?;
         }
 
-        if data.is_none() {
+        let Some(data) = data else {
             return Err(Error::BoxNotFound(BoxType::DataBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(Self {
-            data: data.unwrap(),
-        })
+        Ok(Self { data })
     }
 }
 
diff --git a/src/mp4box/mdia.rs b/src/mp4box/mdia.rs
index 5f785fd..fe2e5a2 100644
--- a/src/mp4box/mdia.rs
+++ b/src/mp4box/mdia.rs
@@ -82,22 +82,18 @@ impl ReadBox<&mut R> for MdiaBox {
             current = reader.stream_position()?;
         }
 
-        if mdhd.is_none() {
+        let Some(mdhd) = mdhd else {
             return Err(Error::BoxNotFound(BoxType::MdhdBox));
-        }
-        if hdlr.is_none() {
+        };
+        let Some(hdlr) = hdlr else {
             return Err(Error::BoxNotFound(BoxType::HdlrBox));
-        }
-        if minf.is_none() {
+        };
+        let Some(minf) = minf else {
             return Err(Error::BoxNotFound(BoxType::MinfBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(Self {
-            mdhd: mdhd.unwrap(),
-            hdlr: hdlr.unwrap(),
-            minf: minf.unwrap(),
-        })
+        Ok(Self { mdhd, hdlr, minf })
     }
 }
diff --git a/src/mp4box/minf.rs b/src/mp4box/minf.rs
index 14d078d..6aab985 100644
--- a/src/mp4box/minf.rs
+++ b/src/mp4box/minf.rs
@@ -100,20 +100,20 @@ impl ReadBox<&mut R> for MinfBox {
             current = reader.stream_position()?;
         }
 
-        if dinf.is_none() {
+        let Some(dinf) = dinf else {
             return Err(Error::BoxNotFound(BoxType::DinfBox));
-        }
-        if stbl.is_none() {
+        };
+        let Some(stbl) = stbl else {
             return Err(Error::BoxNotFound(BoxType::StblBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
         Ok(Self {
             vmhd,
             smhd,
-            dinf: dinf.unwrap(),
-            stbl: stbl.unwrap(),
+            dinf,
+            stbl,
         })
     }
 }
diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs
index 1b83132..6a3d9b4 100644
--- a/src/mp4box/moof.rs
+++ b/src/mp4box/moof.rs
@@ -86,16 +86,12 @@ impl ReadBox<&mut R> for MoofBox {
             current = reader.stream_position()?;
         }
 
-        if mfhd.is_none() {
+        let Some(mfhd) = mfhd else {
             return Err(Error::BoxNotFound(BoxType::MfhdBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(Self {
-            start,
-            mfhd: mfhd.unwrap(),
-            trafs,
-        })
+        Ok(Self { start, mfhd, trafs })
     }
 }
diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs
index ec8c880..9a2a181 100644
--- a/src/mp4box/moov.rs
+++ b/src/mp4box/moov.rs
@@ -112,14 +112,14 @@ impl ReadBox<&mut R> for MoovBox {
             current = reader.stream_position()?;
         }
 
-        if mvhd.is_none() {
+        let Some(mvhd) = mvhd else {
             return Err(Error::BoxNotFound(BoxType::MvhdBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
         Ok(Self {
-            mvhd: mvhd.unwrap(),
+            mvhd,
             meta,
             udta,
             mvex,
diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs
index 1c0ca3e..76d8ce0 100644
--- a/src/mp4box/mp4a.rs
+++ b/src/mp4box/mp4a.rs
@@ -198,16 +198,16 @@ impl ReadBox<&mut R> for EsdsBox {
             current = reader.stream_position()?;
         }
 
-        if es_desc.is_none() {
+        let Some(es_desc) = es_desc else {
             return Err(Error::InvalidData("ESDescriptor not found"));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
         Ok(Self {
             version,
             flags,
-            es_desc: es_desc.unwrap(),
+            es_desc,
         })
     }
 }
diff --git a/src/mp4box/stbl.rs b/src/mp4box/stbl.rs
index 769772f..050b9ac 100644
--- a/src/mp4box/stbl.rs
+++ b/src/mp4box/stbl.rs
@@ -134,18 +134,18 @@ impl ReadBox<&mut R> for StblBox {
             current = reader.stream_position()?;
         }
 
-        if stsd.is_none() {
+        let Some(stsd) = stsd else {
             return Err(Error::BoxNotFound(BoxType::StsdBox));
-        }
-        if stts.is_none() {
+        };
+        let Some(stts) = stts else {
             return Err(Error::BoxNotFound(BoxType::SttsBox));
-        }
-        if stsc.is_none() {
+        };
+        let Some(stsc) = stsc else {
             return Err(Error::BoxNotFound(BoxType::StscBox));
-        }
-        if stsz.is_none() {
+        };
+        let Some(stsz) = stsz else {
             return Err(Error::BoxNotFound(BoxType::StszBox));
-        }
+        };
         if stco.is_none() && co64.is_none() {
             return Err(Error::Box2NotFound(BoxType::StcoBox, BoxType::Co64Box));
         }
@@ -153,12 +153,12 @@ impl ReadBox<&mut R> for StblBox {
         skip_bytes_to(reader, start + size)?;
 
         Ok(Self {
-            stsd: stsd.unwrap(),
-            stts: stts.unwrap(),
+            stsd,
+            stts,
             ctts,
             stss,
-            stsc: stsc.unwrap(),
-            stsz: stsz.unwrap(),
+            stsc,
+            stsz,
             stco,
             co64,
         })
diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs
index 0c0da9d..230df7f 100644
--- a/src/mp4box/traf.rs
+++ b/src/mp4box/traf.rs
@@ -90,16 +90,12 @@ impl ReadBox<&mut R> for TrafBox {
             current = reader.stream_position()?;
         }
 
-        if tfhd.is_none() {
+        let Some(tfhd) = tfhd else {
             return Err(Error::BoxNotFound(BoxType::TfhdBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
-        Ok(Self {
-            tfhd: tfhd.unwrap(),
-            tfdt,
-            truns,
-        })
+        Ok(Self { tfhd, tfdt, truns })
     }
 }
diff --git a/src/mp4box/trak.rs b/src/mp4box/trak.rs
index 13ef116..9586b92 100644
--- a/src/mp4box/trak.rs
+++ b/src/mp4box/trak.rs
@@ -99,20 +99,20 @@ impl ReadBox<&mut R> for TrakBox {
             current = reader.stream_position()?;
         }
 
-        if tkhd.is_none() {
+        let Some(tkhd) = tkhd else {
             return Err(Error::BoxNotFound(BoxType::TkhdBox));
-        }
-        if mdia.is_none() {
+        };
+        let Some(mdia) = mdia else {
             return Err(Error::BoxNotFound(BoxType::MdiaBox));
-        }
+        };
 
         skip_bytes_to(reader, start + size)?;
 
         Ok(Self {
-            tkhd: tkhd.unwrap(),
+            tkhd,
             edts,
             meta,
-            mdia: mdia.unwrap(),
+            mdia,
         })
     }
 }
diff --git a/src/reader.rs b/src/reader.rs
index 7da3fdb..5608fff 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -76,16 +76,16 @@ impl Mp4 {
             current = reader.stream_position()?;
         }
 
-        if ftyp.is_none() {
+        let Some(ftyp) = ftyp else {
             return Err(Error::BoxNotFound(BoxType::FtypBox));
-        }
-        if moov.is_none() {
+        };
+        let Some(moov) = moov else {
             return Err(Error::BoxNotFound(BoxType::MoovBox));
-        }
+        };
 
         let mut this = Self {
-            ftyp: ftyp.unwrap(),
-            moov: moov.unwrap(),
+            ftyp,
+            moov,
             moofs,
             emsgs,
             tracks: HashMap::new(),

From 6b8aae7a39d2503b5dfefeecfff91aaa9203e863 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:53:28 +0200
Subject: [PATCH 25/32] Ignore dead code in tests

---
 tests/lib.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/lib.rs b/tests/lib.rs
index 9d8288b..2d4b75c 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -1,3 +1,6 @@
+#![allow(dead_code)] // TODO(#3): enable tests again
+#![allow(clippy::unwrap_used)]
+
 use std::path::Path;
 
 fn assert_snapshot(snapshot_path: &Path, contents: &[u8]) {

From ca460afc82ff2f3a2c10915d1a25b8ee7ae6c762 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:55:13 +0200
Subject: [PATCH 26/32] QuickTime is a valid word

---
 scripts/clippy_wasm/clippy.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/scripts/clippy_wasm/clippy.toml b/scripts/clippy_wasm/clippy.toml
index 5b7bf9d..41dc9f5 100644
--- a/scripts/clippy_wasm/clippy.toml
+++ b/scripts/clippy_wasm/clippy.toml
@@ -67,6 +67,7 @@ doc-valid-idents = [
   "OBJ",
   "OpenGL",
   "PyPI",
+  "QuickTime",
   "sRGB",
   "sRGBA",
   "WebGL",

From f753aff34706728155d3842f9a430241e5dfe5e9 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 10:58:11 +0200
Subject: [PATCH 27/32] Remove dead links

---
 src/mp4box/mod.rs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs
index 7987fa9..417685e 100644
--- a/src/mp4box/mod.rs
+++ b/src/mp4box/mod.rs
@@ -5,8 +5,6 @@
 //! * ISO/IEC 14496-17 - Streaming text format
 //! * [ISO 23009-1](https://www.iso.org/standard/79329.html) -Dynamic adaptive streaming over HTTP (DASH)
 //!
-//! * 
-//! * 
 //! * 
 //!
 //! Supported Atoms:

From 43e6f313d8f8925603ab2be6ae86982c2f37372e Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 11:27:35 +0200
Subject: [PATCH 28/32] Remove an `unwrap`

---
 src/reader.rs | 7 +++----
 tests/lib.rs  | 2 +-
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/reader.rs b/src/reader.rs
index 5608fff..a526425 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -449,12 +449,11 @@ impl Track {
         (self.duration as f64 * 1e3) / self.timescale as f64
     }
 
-    pub fn trak<'a>(&self, mp4: &'a Mp4) -> &'a TrakBox {
+    pub fn trak<'a>(&self, mp4: &'a Mp4) -> Option<&'a TrakBox> {
         mp4.moov
             .traks
             .iter()
             .find(|trak| trak.tkhd.track_id == self.track_id)
-            .unwrap()
     }
 
     pub fn read_sample(&self, sample_id: u32) -> &[u8] {
@@ -463,7 +462,7 @@ impl Track {
     }
 
     pub fn raw_codec_config(&self, mp4: &Mp4) -> Option> {
-        let sample_description = &self.trak(mp4).mdia.minf.stbl.stsd;
+        let sample_description = &self.trak(mp4)?.mdia.minf.stbl.stsd;
 
         if let Some(Av01Box { av1c, .. }) = &sample_description.av01 {
             Some(av1c.raw.clone())
@@ -481,7 +480,7 @@ impl Track {
     }
 
     pub fn codec_string(&self, mp4: &Mp4) -> Option {
-        let sample_description = &self.trak(mp4).mdia.minf.stbl.stsd;
+        let sample_description = &self.trak(mp4)?.mdia.minf.stbl.stsd;
 
         let s = if let Some(Av01Box { av1c, .. }) = &sample_description.av01 {
             let profile = av1c.profile;
diff --git a/tests/lib.rs b/tests/lib.rs
index 2d4b75c..c59620f 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -66,7 +66,7 @@ fn assert_video_snapshot(file_path: &str) {
                     track.width,
                     track.height,
                     track.samples.len(),
-                    get_track_description(track.trak(&video)),
+                    get_track_description(track.trak(&video).unwrap()),
                 )
                 .as_bytes(),
             );

From a5414eac9903ba61318d98922cb7362faf593648 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 11:33:47 +0200
Subject: [PATCH 29/32] allow `unwrap_used` in a place where it is fine to do
 so

---
 src/mp4box/mod.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs
index 417685e..57db66a 100644
--- a/src/mp4box/mod.rs
+++ b/src/mp4box/mod.rs
@@ -282,12 +282,12 @@ impl BoxHeader {
         reader.read_exact(&mut buf)?;
 
         // Get size.
-        let s = buf[0..4].try_into().unwrap();
-        let size = u32::from_be_bytes(s);
+        #[allow(clippy::unwrap_used)] // [u8; 4] from a slice that is 4 long cannot fail
+        let size = u32::from_be_bytes(buf[0..4].try_into().unwrap());
 
         // Get box type string.
-        let t = buf[4..8].try_into().unwrap();
-        let typ = u32::from_be_bytes(t);
+        #[allow(clippy::unwrap_used)] // [u8; 4] from a slice that is 4 long cannot fail
+        let typ = u32::from_be_bytes(buf[4..8].try_into().unwrap());
 
         // Get largesize if size is 1
         if size == 1 {

From 6926080d486655682f6d670019a71ee878521f66 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 11:42:01 +0200
Subject: [PATCH 30/32] Enable `clippy::iter_over_hash_type`

---
 Cargo.toml    | 2 +-
 src/reader.rs | 1 +
 tests/lib.rs  | 2 ++
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/Cargo.toml b/Cargo.toml
index d67b0af..0d79f42 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -111,6 +111,7 @@ invalid_upcast_comparisons = "warn"
 iter_not_returning_iterator = "warn"
 iter_on_empty_collections = "warn"
 iter_on_single_items = "warn"
+iter_over_hash_type = "warn"
 iter_without_into_iter = "warn"
 large_digit_groups = "warn"
 large_include_file = "warn"
@@ -205,7 +206,6 @@ ref_patterns = "allow"          # It's nice to avoid ref pattern, but there are
 # TODO(emilk): consider enabling these:
 enum_variant_names = "allow"
 excessive_nesting = "allow"
-iter_over_hash_type = "allow"
 missing_errors_doc = "allow"
 unused_self = "allow"
 unwrap_used = "allow"
diff --git a/src/reader.rs b/src/reader.rs
index a526425..4a2ce8e 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -400,6 +400,7 @@ impl Mp4 {
     ///
     /// After this function is called, each track's [`Track::data`] may only be indexed by one of its samples' [`Sample::offset`]s.
     fn load_track_data(&mut self, reader: &mut R) -> Result<()> {
+        #[allow(clippy::iter_over_hash_type)] // what we do in the iteration is not order-dependend
         for track in self.tracks.values_mut() {
             for sample in &mut track.samples {
                 let data_offset = track.data.len();
diff --git a/tests/lib.rs b/tests/lib.rs
index c59620f..f38e55e 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -48,6 +48,8 @@ fn assert_video_snapshot(file_path: &str) {
     let base_path = Path::new(BASE);
     let bytes = std::fs::read(base_path.join(file_path)).unwrap();
     let video = re_mp4::read(&bytes).unwrap();
+
+    #[allow(clippy::iter_over_hash_type)] // what we do in the iteration is not order-dependend
     for (id, track) in video.tracks() {
         if track.kind == re_mp4::TrackKind::Video {
             assert_snapshot(

From f5e4a2b84a00df19e9ad737db42f6a3fa8e855bf Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 11:42:12 +0200
Subject: [PATCH 31/32] Add some vertical spacing

---
 src/error.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/error.rs b/src/error.rs
index 11690f0..9354c6f 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -6,24 +6,34 @@ use crate::mp4box::BoxType;
 pub enum Error {
     #[error("{0}")]
     IoError(#[from] std::io::Error),
+
     #[error("{0}")]
     InvalidData(&'static str),
+
     #[error("{0} not found")]
     BoxNotFound(BoxType),
+
     #[error("{0} and {1} not found")]
     Box2NotFound(BoxType, BoxType),
+
     #[error("trak[{0}] not found")]
     TrakNotFound(u32),
+
     #[error("trak[{0}].{1} not found")]
     BoxInTrakNotFound(u32, BoxType),
+
     #[error("traf[{0}].{1} not found")]
     BoxInTrafNotFound(u32, BoxType),
+
     #[error("trak[{0}].stbl.{1} not found")]
     BoxInStblNotFound(u32, BoxType),
+
     #[error("trak[{0}].stbl.{1}.entry[{2}] not found")]
     EntryInStblNotFound(u32, BoxType, u32),
+
     #[error("traf[{0}].trun.{1}.entry[{2}] not found")]
     EntryInTrunNotFound(u32, BoxType, u32),
+
     #[error("{0} version {1} is not supported")]
     UnsupportedBoxVersion(BoxType, u8),
 }

From baaa2e83d608e85b3a31e8be1a9807dc83eaa8e3 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt 
Date: Mon, 23 Sep 2024 11:44:42 +0200
Subject: [PATCH 32/32] Fix typos

---
 src/reader.rs | 2 +-
 tests/lib.rs  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/reader.rs b/src/reader.rs
index 4a2ce8e..43868fe 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -400,7 +400,7 @@ impl Mp4 {
     ///
     /// After this function is called, each track's [`Track::data`] may only be indexed by one of its samples' [`Sample::offset`]s.
     fn load_track_data(&mut self, reader: &mut R) -> Result<()> {
-        #[allow(clippy::iter_over_hash_type)] // what we do in the iteration is not order-dependend
+        #[allow(clippy::iter_over_hash_type)] // what we do in the iteration is not order-dependent
         for track in self.tracks.values_mut() {
             for sample in &mut track.samples {
                 let data_offset = track.data.len();
diff --git a/tests/lib.rs b/tests/lib.rs
index f38e55e..e44cac4 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -49,7 +49,7 @@ fn assert_video_snapshot(file_path: &str) {
     let bytes = std::fs::read(base_path.join(file_path)).unwrap();
     let video = re_mp4::read(&bytes).unwrap();
 
-    #[allow(clippy::iter_over_hash_type)] // what we do in the iteration is not order-dependend
+    #[allow(clippy::iter_over_hash_type)] // what we do in the iteration is not order-dependent
     for (id, track) in video.tracks() {
         if track.kind == re_mp4::TrackKind::Video {
             assert_snapshot(