From 3a3cae761c8456552f3e1e15c3b9e0c36b3a9c18 Mon Sep 17 00:00:00 2001 From: zaggy1024 Date: Fri, 27 Jan 2023 21:25:51 +0000 Subject: [PATCH] Bug 1788119 - Part 4 - Update mp4parse-rust for AVIS support. r=kinetik,glandium,supply-chain-reviewers Depends on D156652 Differential Revision: https://phabricator.services.mozilla.com/D156653 --- .cargo/config.in | 2 +- Cargo.lock | 38 +- Cargo.toml | 3 - build/rust/env_logger/Cargo.toml | 19 - build/rust/env_logger/lib.rs | 5 - supply-chain/config.toml | 4 - .../rust/humantime/.cargo-checksum.json | 1 - third_party/rust/humantime/Cargo.toml | 37 - third_party/rust/humantime/LICENSE-APACHE | 202 -- third_party/rust/humantime/LICENSE-MIT | 26 - third_party/rust/humantime/README.md | 68 - .../rust/humantime/benches/datetime_format.rs | 56 - .../rust/humantime/benches/datetime_parse.rs | 47 - third_party/rust/humantime/bulk.yaml | 8 - third_party/rust/humantime/src/date.rs | 623 ------ third_party/rust/humantime/src/duration.rs | 456 ----- third_party/rust/humantime/src/lib.rs | 34 - third_party/rust/humantime/src/wrapper.rs | 107 - third_party/rust/humantime/vagga.yaml | 92 - .../rust/mp4parse/.cargo-checksum.json | 2 +- third_party/rust/mp4parse/Cargo.toml | 5 +- .../rust/mp4parse/benches/avif_benchmark.rs | 4 +- .../workflows/encode-and-decode-daily.yml | 292 +-- .../link-u-avif-sample-images/.gitignore | 8 +- .../link-u-avif-sample-images/LICENSE.txt | 852 ++++---- .../link-u-avif-sample-images/Makefile | 1822 ++++++++--------- .../link-u-avif-sample-images/README.md | 1164 +++++------ .../link-u-avif-sample-images/images.html | 1490 +++++++------- .../plum-blossom.svg | 352 ++-- .../scripts/compare.sh | 46 +- .../link-u-avif-sample-images/star.input.txt | 18 +- .../link-u-avif-sample-images/star.svg | 166 +- third_party/rust/mp4parse/src/boxes.rs | 4 +- third_party/rust/mp4parse/src/lib.rs | 1296 +++++++----- third_party/rust/mp4parse/src/macros.rs | 2 +- third_party/rust/mp4parse/src/tests.rs | 74 +- third_party/rust/mp4parse/src/unstable.rs | 4 +- .../corrupt/invalid-transformation-order.avif | Bin 0 -> 345 bytes .../mp4parse/tests/corrupt/no-alpha-ispe.avif | Bin 0 -> 449 bytes .../corrupt/transformation-before-ispe.avif | Bin 0 -> 338 bytes .../tests/imir-missing-essential.avif | Bin 84996 -> 337 bytes .../tests/irot-missing-essential.avif | Bin 84837 -> 337 bytes third_party/rust/mp4parse/tests/public.rs | 185 +- .../rust/mp4parse_capi/.cargo-checksum.json | 2 +- third_party/rust/mp4parse_capi/Cargo.toml | 8 +- .../rust/mp4parse_capi/examples/dump.rs | 13 +- third_party/rust/mp4parse_capi/src/lib.rs | 319 ++- .../tests/test_chunk_out_of_range.rs | 1 - .../mp4parse_capi/tests/test_encryption.rs | 1 - .../rust/mp4parse_capi/tests/test_fragment.rs | 1 - .../rust/mp4parse_capi/tests/test_rotation.rs | 1 - .../mp4parse_capi/tests/test_sample_table.rs | 2 - .../tests/test_workaround_stsc.rs | 1 - toolkit/library/rust/shared/Cargo.toml | 2 +- 54 files changed, 4314 insertions(+), 5651 deletions(-) delete mode 100644 build/rust/env_logger/Cargo.toml delete mode 100644 build/rust/env_logger/lib.rs delete mode 100644 third_party/rust/humantime/.cargo-checksum.json delete mode 100644 third_party/rust/humantime/Cargo.toml delete mode 100644 third_party/rust/humantime/LICENSE-APACHE delete mode 100644 third_party/rust/humantime/LICENSE-MIT delete mode 100644 third_party/rust/humantime/README.md delete mode 100644 third_party/rust/humantime/benches/datetime_format.rs delete mode 100644 third_party/rust/humantime/benches/datetime_parse.rs delete mode 100644 third_party/rust/humantime/bulk.yaml delete mode 100644 third_party/rust/humantime/src/date.rs delete mode 100644 third_party/rust/humantime/src/duration.rs delete mode 100644 third_party/rust/humantime/src/lib.rs delete mode 100644 third_party/rust/humantime/src/wrapper.rs delete mode 100644 third_party/rust/humantime/vagga.yaml create mode 100644 third_party/rust/mp4parse/tests/corrupt/invalid-transformation-order.avif create mode 100644 third_party/rust/mp4parse/tests/corrupt/no-alpha-ispe.avif create mode 100644 third_party/rust/mp4parse/tests/corrupt/transformation-before-ispe.avif diff --git a/.cargo/config.in b/.cargo/config.in index ed972269ad4f..eb26f5e0771e 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -102,7 +102,7 @@ replace-with = "vendored-sources" [source."https://github.com/mozilla/mp4parse-rust"] git = "https://github.com/mozilla/mp4parse-rust" -rev = "3bfc47d9a571d0842676043ba60716318e946c06" +rev = "eb0b625bd7e888d05ebcfc7685e2501b34c3b374" replace-with = "vendored-sources" [source."https://github.com/mozilla/neqo"] diff --git a/Cargo.lock b/Cargo.lock index 39b456678685..45b70cf6e6f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e9dd62f37dea550caf48c77591dc50bd1a378ce08855be1a0c42a97b7550fb" dependencies = [ "android_log-sys", - "env_logger 0.9.3", + "env_logger", "log", "once_cell", ] @@ -1564,24 +1564,13 @@ dependencies = [ "syn", ] -[[package]] -name = "env_logger" -version = "0.8.999" -dependencies = [ - "env_logger 0.9.3", -] - [[package]] name = "env_logger" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ - "atty", - "humantime", "log", - "regex", - "termcolor", ] [[package]] @@ -2068,7 +2057,7 @@ name = "gecko_logger" version = "0.1.0" dependencies = [ "app_services_logger", - "env_logger 0.9.3", + "env_logger", "lazy_static", "log", ] @@ -2327,7 +2316,7 @@ dependencies = [ "bincode", "chrono", "crossbeam-channel", - "env_logger 0.9.3", + "env_logger", "flate2", "log", "once_cell", @@ -2623,12 +2612,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "0.14.23" @@ -3599,12 +3582,11 @@ dependencies = [ [[package]] name = "mp4parse" -version = "0.13.0" -source = "git+https://github.com/mozilla/mp4parse-rust?rev=3bfc47d9a571d0842676043ba60716318e946c06#3bfc47d9a571d0842676043ba60716318e946c06" +version = "0.16.0" +source = "git+https://github.com/mozilla/mp4parse-rust?rev=eb0b625bd7e888d05ebcfc7685e2501b34c3b374#eb0b625bd7e888d05ebcfc7685e2501b34c3b374" dependencies = [ "bitreader", "byteorder", - "env_logger 0.8.999", "fallible_collections", "log", "num-traits", @@ -3617,8 +3599,8 @@ version = "0.1.0" [[package]] name = "mp4parse_capi" -version = "0.13.0" -source = "git+https://github.com/mozilla/mp4parse-rust?rev=3bfc47d9a571d0842676043ba60716318e946c06#3bfc47d9a571d0842676043ba60716318e946c06" +version = "0.16.0" +source = "git+https://github.com/mozilla/mp4parse-rust?rev=eb0b625bd7e888d05ebcfc7685e2501b34c3b374#eb0b625bd7e888d05ebcfc7685e2501b34c3b374" dependencies = [ "byteorder", "fallible_collections", @@ -3659,7 +3641,7 @@ version = "0.6.3" source = "git+https://github.com/mozilla/neqo?tag=v0.6.3#4fe628bb911e4437169d974baa628c159e96f879" dependencies = [ "chrono", - "env_logger 0.9.3", + "env_logger", "lazy_static", "log", "qlog", @@ -4000,7 +3982,7 @@ version = "0.1.4" dependencies = [ "byteorder", "core-foundation", - "env_logger 0.9.3", + "env_logger", "lazy_static", "libloading", "log", @@ -5020,7 +5002,7 @@ name = "smoosh" version = "0.1.0" dependencies = [ "bumpalo", - "env_logger 0.9.3", + "env_logger", "jsparagus", "log", ] diff --git a/Cargo.toml b/Cargo.toml index 1e3fad1da5e3..325e1f29ee44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,9 +104,6 @@ memmap2 = { path = "build/rust/memmap2" } # Patch getrandom 0.7 to 0.8 rand = { path = "build/rust/rand" } -# Patch env_logger 0.8 to 0.9 -env_logger = { path = "build/rust/env_logger" } - # Patch parking_lot 0.12 down to 0.11, which is compatible for most crates that use it, to avoid # dependencies on windows-sys. parking_lot = { path = "build/rust/parking_lot" } diff --git a/build/rust/env_logger/Cargo.toml b/build/rust/env_logger/Cargo.toml deleted file mode 100644 index 11e387b5a4f1..000000000000 --- a/build/rust/env_logger/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "env_logger" -version = "0.8.999" -edition = "2018" -license = "MPL-2.0" - -[lib] -path = "lib.rs" - -[dependencies.env_logger] -version = "0.9" -default-features = false - -[features] -default = ["env_logger/default"] -termcolor = ["env_logger/termcolor"] -atty = ["env_logger/atty"] -humantime = ["env_logger/humantime"] -regex = ["env_logger/regex"] diff --git a/build/rust/env_logger/lib.rs b/build/rust/env_logger/lib.rs deleted file mode 100644 index cd291d6351f2..000000000000 --- a/build/rust/env_logger/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -pub use env_logger::*; diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 1545f377c89f..5904af63418a 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -671,10 +671,6 @@ criteria = "safe-to-run" version = "1.0.2" criteria = "safe-to-run" -[[exemptions.humantime]] -version = "2.1.0" -criteria = "safe-to-deploy" - [[exemptions.hyper]] version = "0.14.19" criteria = "safe-to-run" diff --git a/third_party/rust/humantime/.cargo-checksum.json b/third_party/rust/humantime/.cargo-checksum.json deleted file mode 100644 index 80dbdff4f914..000000000000 --- a/third_party/rust/humantime/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"c0d1443ae237dee3c09cb70185fa947d8d8cb660acfbcb8f650798bd4e0c019e","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"f6deca8261a8f4a3403dc74c725c46051157fd36c27cd4b100277eb1f303ad11","README.md":"e4bb65f28ddffb11d7eb337e9585947651f2fc11a5e4290f0ca126e21c582c1e","benches/datetime_format.rs":"ffe2e459e9b48e8fdbfb3686f6297257d66b29369ecd6750ae9fbba527ccc681","benches/datetime_parse.rs":"8039c4bd5f1795dbb54e1e39da5988f1d2df6c86c42d8fd378094fc78074d31e","bulk.yaml":"17c2548388e0cd3a63473021a2f1e4ddedee082d79d9167cb31ad06a1890d3fc","src/date.rs":"a8159494372ba8ec8a3a0a5b69c9b185f3e7ab007f283188bf96a6f071151f20","src/duration.rs":"4939ae2d1c3056424de421c4b124d0fb387e058d9abc82a21b83b38d66a40753","src/lib.rs":"ad4dbed28080d9a64ef0100c96b20ff4988d9dde908f56e28ece7252f5932990","src/wrapper.rs":"badc640e77379a42b2fcb728337d60a764b7f00a1b5b1d50c7372ddc20941967","vagga.yaml":"8396fe1510117c1c7bc3e896b62290dcf2dd300346071297018b0077ad9e45ce"},"package":"9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"} \ No newline at end of file diff --git a/third_party/rust/humantime/Cargo.toml b/third_party/rust/humantime/Cargo.toml deleted file mode 100644 index 950db73d35eb..000000000000 --- a/third_party/rust/humantime/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "humantime" -version = "2.1.0" -authors = ["Paul Colomiets "] -description = " A parser and formatter for std::time::{Duration, SystemTime}\n" -homepage = "https://github.com/tailhook/humantime" -documentation = "https://docs.rs/humantime" -readme = "README.md" -keywords = ["time", "human", "human-friendly", "parser", "duration"] -categories = ["date-and-time"] -license = "MIT/Apache-2.0" -repository = "https://github.com/tailhook/humantime" - -[lib] -name = "humantime" -path = "src/lib.rs" -[dev-dependencies.chrono] -version = "0.4" - -[dev-dependencies.rand] -version = "0.6" - -[dev-dependencies.time] -version = "0.1" diff --git a/third_party/rust/humantime/LICENSE-APACHE b/third_party/rust/humantime/LICENSE-APACHE deleted file mode 100644 index 8f71f43fee3f..000000000000 --- a/third_party/rust/humantime/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/third_party/rust/humantime/LICENSE-MIT b/third_party/rust/humantime/LICENSE-MIT deleted file mode 100644 index a099fbade45d..000000000000 --- a/third_party/rust/humantime/LICENSE-MIT +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2016 The humantime Developers - -Includes parts of http date with the following copyright: -Copyright (c) 2016 Pyfisch - -Includes portions of musl libc with the following copyright: -Copyright © 2005-2013 Rich Felker - - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/third_party/rust/humantime/README.md b/third_party/rust/humantime/README.md deleted file mode 100644 index 39156dcdc941..000000000000 --- a/third_party/rust/humantime/README.md +++ /dev/null @@ -1,68 +0,0 @@ -Human Time -========== - -**Status: stable** - -[Documentation](https://docs.rs/humantime) | -[Github](https://github.com/tailhook/humantime) | -[Crate](https://crates.io/crates/humantime) - - -Features: - -* Parses durations in free form like `15days 2min 2s` -* Formats durations in similar form `2years 2min 12us` -* Parses and formats timestamp in `rfc3339` format: `2018-01-01T12:53:00Z` -* Parses timestamps in a weaker format: `2018-01-01 12:53:00` - -Timestamp parsing/formatting is super-fast because format is basically -fixed. - -Here are some micro-benchmarks: - -``` -test result: ok. 0 passed; 0 failed; 26 ignored; 0 measured; 0 filtered out - - Running target/release/deps/datetime_format-8facb4ac832d9770 - -running 2 tests -test rfc3339_chrono ... bench: 737 ns/iter (+/- 37) -test rfc3339_humantime_seconds ... bench: 73 ns/iter (+/- 2) - -test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured; 0 filtered out - - Running target/release/deps/datetime_parse-342628f877d7867c - -running 6 tests -test datetime_utc_parse_millis ... bench: 228 ns/iter (+/- 11) -test datetime_utc_parse_nanos ... bench: 236 ns/iter (+/- 10) -test datetime_utc_parse_seconds ... bench: 204 ns/iter (+/- 18) -test rfc3339_humantime_millis ... bench: 28 ns/iter (+/- 1) -test rfc3339_humantime_nanos ... bench: 36 ns/iter (+/- 2) -test rfc3339_humantime_seconds ... bench: 24 ns/iter (+/- 1) - -test result: ok. 0 passed; 0 failed; 0 ignored; 6 measured; 0 filtered out -``` - -See [humantime-serde] for serde integration (previous crate [serde-humantime] looks unmaintained). - -[serde-humantime]: https://docs.rs/serde-humantime/0.1.1/serde_humantime/ -[humantime-serde]: https://docs.rs/humantime-serde - -License -======= - -Licensed under either of - -* Apache License, Version 2.0, (./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) -* MIT license (./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Contribution ------------- - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/third_party/rust/humantime/benches/datetime_format.rs b/third_party/rust/humantime/benches/datetime_format.rs deleted file mode 100644 index 77d47667c089..000000000000 --- a/third_party/rust/humantime/benches/datetime_format.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![feature(test)] -extern crate test; - -use std::io::Write; -use std::time::{Duration, UNIX_EPOCH}; - -use humantime::format_rfc3339; - -#[bench] -fn rfc3339_humantime_seconds(b: &mut test::Bencher) { - let time = UNIX_EPOCH + Duration::new(1_483_228_799, 0); - let mut buf = Vec::with_capacity(100); - b.iter(|| { - buf.truncate(0); - write!(&mut buf, "{}", format_rfc3339(time)).unwrap() - }); -} - -#[bench] -fn rfc3339_chrono(b: &mut test::Bencher) { - use chrono::{DateTime, NaiveDateTime, Utc}; - use chrono::format::Item; - use chrono::format::Item::*; - use chrono::format::Numeric::*; - use chrono::format::Fixed::*; - use chrono::format::Pad::*; - - let time = DateTime::::from_utc( - NaiveDateTime::from_timestamp(1_483_228_799, 0), Utc); - let mut buf = Vec::with_capacity(100); - - // formatting code from env_logger - const ITEMS: &[Item<'static>] = { - &[ - Numeric(Year, Zero), - Literal("-"), - Numeric(Month, Zero), - Literal("-"), - Numeric(Day, Zero), - Literal("T"), - Numeric(Hour, Zero), - Literal(":"), - Numeric(Minute, Zero), - Literal(":"), - Numeric(Second, Zero), - Fixed(TimezoneOffsetZ), - ] - }; - - - b.iter(|| { - buf.truncate(0); - write!(&mut buf, "{}", time.format_with_items(ITEMS.iter().cloned())) - .unwrap() - }); -} diff --git a/third_party/rust/humantime/benches/datetime_parse.rs b/third_party/rust/humantime/benches/datetime_parse.rs deleted file mode 100644 index 4248da281e60..000000000000 --- a/third_party/rust/humantime/benches/datetime_parse.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![feature(test)] -extern crate test; - -use chrono::{DateTime}; -use humantime::parse_rfc3339; - -#[bench] -fn rfc3339_humantime_seconds(b: &mut test::Bencher) { - b.iter(|| { - parse_rfc3339("2018-02-13T23:08:32Z").unwrap() - }); -} - -#[bench] -fn datetime_utc_parse_seconds(b: &mut test::Bencher) { - b.iter(|| { - DateTime::parse_from_rfc3339("2018-02-13T23:08:32Z").unwrap() - }); -} - -#[bench] -fn rfc3339_humantime_millis(b: &mut test::Bencher) { - b.iter(|| { - parse_rfc3339("2018-02-13T23:08:32.123Z").unwrap() - }); -} - -#[bench] -fn datetime_utc_parse_millis(b: &mut test::Bencher) { - b.iter(|| { - DateTime::parse_from_rfc3339("2018-02-13T23:08:32.123Z").unwrap() - }); -} - -#[bench] -fn rfc3339_humantime_nanos(b: &mut test::Bencher) { - b.iter(|| { - parse_rfc3339("2018-02-13T23:08:32.123456983Z").unwrap() - }); -} - -#[bench] -fn datetime_utc_parse_nanos(b: &mut test::Bencher) { - b.iter(|| { - DateTime::parse_from_rfc3339("2018-02-13T23:08:32.123456983Z").unwrap() - }); -} diff --git a/third_party/rust/humantime/bulk.yaml b/third_party/rust/humantime/bulk.yaml deleted file mode 100644 index cdb9763b67d6..000000000000 --- a/third_party/rust/humantime/bulk.yaml +++ /dev/null @@ -1,8 +0,0 @@ -minimum-bulk: v0.4.5 - -versions: - -- file: Cargo.toml - block-start: ^\[package\] - block-end: ^\[.*\] - regex: ^version\s*=\s*"(\S+)" diff --git a/third_party/rust/humantime/src/date.rs b/third_party/rust/humantime/src/date.rs deleted file mode 100644 index 9d28ee7d0bda..000000000000 --- a/third_party/rust/humantime/src/date.rs +++ /dev/null @@ -1,623 +0,0 @@ -use std::error::Error as StdError; -use std::fmt; -use std::str; -use std::time::{SystemTime, Duration, UNIX_EPOCH}; - -#[cfg(target_os="cloudabi")] -mod max { - pub const SECONDS: u64 = ::std::u64::MAX / 1_000_000_000; - #[allow(unused)] - pub const TIMESTAMP: &'static str = "2554-07-21T23:34:33Z"; -} -#[cfg(all( - target_pointer_width="32", - not(target_os="cloudabi"), - not(target_os="windows"), - not(all(target_arch="wasm32", not(target_os="emscripten"))) -))] -mod max { - pub const SECONDS: u64 = ::std::i32::MAX as u64; - #[allow(unused)] - pub const TIMESTAMP: &'static str = "2038-01-19T03:14:07Z"; -} - -#[cfg(any( - target_pointer_width="64", - target_os="windows", - all(target_arch="wasm32", not(target_os="emscripten")), -))] -mod max { - pub const SECONDS: u64 = 253_402_300_800-1; // last second of year 9999 - #[allow(unused)] - pub const TIMESTAMP: &str = "9999-12-31T23:59:59Z"; -} - -/// Error parsing datetime (timestamp) -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum Error { - /// Numeric component is out of range - OutOfRange, - /// Bad character where digit is expected - InvalidDigit, - /// Other formatting errors - InvalidFormat, -} - -impl StdError for Error {} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::OutOfRange => write!(f, "numeric component is out of range"), - Error::InvalidDigit => write!(f, "bad character where digit is expected"), - Error::InvalidFormat => write!(f, "timestamp format is invalid"), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum Precision { - Smart, - Seconds, - Millis, - Micros, - Nanos, -} - -/// A wrapper type that allows you to Display a SystemTime -#[derive(Debug, Clone)] -pub struct Rfc3339Timestamp(SystemTime, Precision); - -#[inline] -fn two_digits(b1: u8, b2: u8) -> Result { - if b1 < b'0' || b2 < b'0' || b1 > b'9' || b2 > b'9' { - return Err(Error::InvalidDigit); - } - Ok(((b1 - b'0')*10 + (b2 - b'0')) as u64) -} - -/// Parse RFC3339 timestamp `2018-02-14T00:28:07Z` -/// -/// Supported feature: any precision of fractional -/// digits `2018-02-14T00:28:07.133Z`. -/// -/// Unsupported feature: localized timestamps. Only UTC is supported. -pub fn parse_rfc3339(s: &str) -> Result { - if s.len() < "2018-02-14T00:28:07Z".len() { - return Err(Error::InvalidFormat); - } - let b = s.as_bytes(); - if b[10] != b'T' || b[b.len()-1] != b'Z' { - return Err(Error::InvalidFormat); - } - parse_rfc3339_weak(s) -} - -/// Parse RFC3339-like timestamp `2018-02-14 00:28:07` -/// -/// Supported features: -/// -/// 1. Any precision of fractional digits `2018-02-14 00:28:07.133`. -/// 2. Supports timestamp with or without either of `T` or `Z` -/// 3. Anything valid for `parse_3339` is valid for this function -/// -/// Unsupported feature: localized timestamps. Only UTC is supported, even if -/// `Z` is not specified. -/// -/// This function is intended to use for parsing human input. Whereas -/// `parse_rfc3339` is for strings generated programmatically. -pub fn parse_rfc3339_weak(s: &str) -> Result { - if s.len() < "2018-02-14T00:28:07".len() { - return Err(Error::InvalidFormat); - } - let b = s.as_bytes(); // for careless slicing - if b[4] != b'-' || b[7] != b'-' || (b[10] != b'T' && b[10] != b' ') || - b[13] != b':' || b[16] != b':' - { - return Err(Error::InvalidFormat); - } - let year = two_digits(b[0], b[1])? * 100 + two_digits(b[2], b[3])?; - let month = two_digits(b[5], b[6])?; - let day = two_digits(b[8], b[9])?; - let hour = two_digits(b[11], b[12])?; - let minute = two_digits(b[14], b[15])?; - let mut second = two_digits(b[17], b[18])?; - - if year < 1970 || hour > 23 || minute > 59 || second > 60 { - return Err(Error::OutOfRange); - } - // TODO(tailhook) should we check that leaps second is only on midnight ? - if second == 60 { - second = 59 - }; - let leap_years = ((year - 1) - 1968) / 4 - ((year - 1) - 1900) / 100 + - ((year - 1) - 1600) / 400; - let leap = is_leap_year(year); - let (mut ydays, mdays) = match month { - 1 => (0, 31), - 2 if leap => (31, 29), - 2 => (31, 28), - 3 => (59, 31), - 4 => (90, 30), - 5 => (120, 31), - 6 => (151, 30), - 7 => (181, 31), - 8 => (212, 31), - 9 => (243, 30), - 10 => (273, 31), - 11 => (304, 30), - 12 => (334, 31), - _ => return Err(Error::OutOfRange), - }; - if day > mdays || day == 0 { - return Err(Error::OutOfRange); - } - ydays += day - 1; - if leap && month > 2 { - ydays += 1; - } - let days = (year - 1970) * 365 + leap_years + ydays; - - let time = second + minute * 60 + hour * 3600; - - let mut nanos = 0; - let mut mult = 100_000_000; - if b.get(19) == Some(&b'.') { - for idx in 20..b.len() { - if b[idx] == b'Z' { - if idx == b.len()-1 { - break; - } else { - return Err(Error::InvalidDigit); - } - } - if b[idx] < b'0' || b[idx] > b'9' { - return Err(Error::InvalidDigit); - } - nanos += mult * (b[idx] - b'0') as u32; - mult /= 10; - } - } else if b.len() != 19 && (b.len() > 20 || b[19] != b'Z') { - return Err(Error::InvalidFormat); - } - - let total_seconds = time + days * 86400; - if total_seconds > max::SECONDS { - return Err(Error::OutOfRange); - } - - Ok(UNIX_EPOCH + Duration::new(total_seconds, nanos)) -} - -fn is_leap_year(y: u64) -> bool { - y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) -} - -/// Format an RFC3339 timestamp `2018-02-14T00:28:07Z` -/// -/// This function formats timestamp with smart precision: i.e. if it has no -/// fractional seconds, they aren't written at all. And up to nine digits if -/// they are. -/// -/// The value is always UTC and ignores system timezone. -pub fn format_rfc3339(system_time: SystemTime) -> Rfc3339Timestamp { - Rfc3339Timestamp(system_time, Precision::Smart) -} - -/// Format an RFC3339 timestamp `2018-02-14T00:28:07Z` -/// -/// This format always shows timestamp without fractional seconds. -/// -/// The value is always UTC and ignores system timezone. -pub fn format_rfc3339_seconds(system_time: SystemTime) -> Rfc3339Timestamp { - Rfc3339Timestamp(system_time, Precision::Seconds) -} - -/// Format an RFC3339 timestamp `2018-02-14T00:28:07.000Z` -/// -/// This format always shows milliseconds even if millisecond value is zero. -/// -/// The value is always UTC and ignores system timezone. -pub fn format_rfc3339_millis(system_time: SystemTime) -> Rfc3339Timestamp { - Rfc3339Timestamp(system_time, Precision::Millis) -} - -/// Format an RFC3339 timestamp `2018-02-14T00:28:07.000000Z` -/// -/// This format always shows microseconds even if microsecond value is zero. -/// -/// The value is always UTC and ignores system timezone. -pub fn format_rfc3339_micros(system_time: SystemTime) -> Rfc3339Timestamp { - Rfc3339Timestamp(system_time, Precision::Micros) -} - -/// Format an RFC3339 timestamp `2018-02-14T00:28:07.000000000Z` -/// -/// This format always shows nanoseconds even if nanosecond value is zero. -/// -/// The value is always UTC and ignores system timezone. -pub fn format_rfc3339_nanos(system_time: SystemTime) -> Rfc3339Timestamp { - Rfc3339Timestamp(system_time, Precision::Nanos) -} - -impl Rfc3339Timestamp { - /// Returns a reference to the [`SystemTime`][] that is being formatted. - pub fn get_ref(&self) -> &SystemTime { - &self.0 - } -} - -impl fmt::Display for Rfc3339Timestamp { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::Precision::*; - - let dur = self.0.duration_since(UNIX_EPOCH) - .expect("all times should be after the epoch"); - let secs_since_epoch = dur.as_secs(); - let nanos = dur.subsec_nanos(); - - if secs_since_epoch >= 253_402_300_800 { // year 9999 - return Err(fmt::Error); - } - - /* 2000-03-01 (mod 400 year, immediately after feb29 */ - const LEAPOCH: i64 = 11017; - const DAYS_PER_400Y: i64 = 365*400 + 97; - const DAYS_PER_100Y: i64 = 365*100 + 24; - const DAYS_PER_4Y: i64 = 365*4 + 1; - - let days = (secs_since_epoch / 86400) as i64 - LEAPOCH; - let secs_of_day = secs_since_epoch % 86400; - - let mut qc_cycles = days / DAYS_PER_400Y; - let mut remdays = days % DAYS_PER_400Y; - - if remdays < 0 { - remdays += DAYS_PER_400Y; - qc_cycles -= 1; - } - - let mut c_cycles = remdays / DAYS_PER_100Y; - if c_cycles == 4 { c_cycles -= 1; } - remdays -= c_cycles * DAYS_PER_100Y; - - let mut q_cycles = remdays / DAYS_PER_4Y; - if q_cycles == 25 { q_cycles -= 1; } - remdays -= q_cycles * DAYS_PER_4Y; - - let mut remyears = remdays / 365; - if remyears == 4 { remyears -= 1; } - remdays -= remyears * 365; - - let mut year = 2000 + - remyears + 4*q_cycles + 100*c_cycles + 400*qc_cycles; - - let months = [31,30,31,30,31,31,30,31,30,31,31,29]; - let mut mon = 0; - for mon_len in months.iter() { - mon += 1; - if remdays < *mon_len { - break; - } - remdays -= *mon_len; - } - let mday = remdays+1; - let mon = if mon + 2 > 12 { - year += 1; - mon - 10 - } else { - mon + 2 - }; - - let mut buf: [u8; 30] = [ - // Too long to write as: b"0000-00-00T00:00:00.000000000Z" - b'0', b'0', b'0', b'0', b'-', b'0', b'0', b'-', b'0', b'0', b'T', - b'0', b'0', b':', b'0', b'0', b':', b'0', b'0', - b'.', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'Z', - ]; - buf[0] = b'0' + (year / 1000) as u8; - buf[1] = b'0' + (year / 100 % 10) as u8; - buf[2] = b'0' + (year / 10 % 10) as u8; - buf[3] = b'0' + (year % 10) as u8; - buf[5] = b'0' + (mon / 10) as u8; - buf[6] = b'0' + (mon % 10) as u8; - buf[8] = b'0' + (mday / 10) as u8; - buf[9] = b'0' + (mday % 10) as u8; - buf[11] = b'0' + (secs_of_day / 3600 / 10) as u8; - buf[12] = b'0' + (secs_of_day / 3600 % 10) as u8; - buf[14] = b'0' + (secs_of_day / 60 / 10 % 6) as u8; - buf[15] = b'0' + (secs_of_day / 60 % 10) as u8; - buf[17] = b'0' + (secs_of_day / 10 % 6) as u8; - buf[18] = b'0' + (secs_of_day % 10) as u8; - - let offset = if self.1 == Seconds || nanos == 0 && self.1 == Smart { - buf[19] = b'Z'; - 19 - } else if self.1 == Millis { - buf[20] = b'0' + (nanos / 100_000_000) as u8; - buf[21] = b'0' + (nanos / 10_000_000 % 10) as u8; - buf[22] = b'0' + (nanos / 1_000_000 % 10) as u8; - buf[23] = b'Z'; - 23 - } else if self.1 == Micros { - buf[20] = b'0' + (nanos / 100_000_000) as u8; - buf[21] = b'0' + (nanos / 10_000_000 % 10) as u8; - buf[22] = b'0' + (nanos / 1_000_000 % 10) as u8; - buf[23] = b'0' + (nanos / 100_000 % 10) as u8; - buf[24] = b'0' + (nanos / 10_000 % 10) as u8; - buf[25] = b'0' + (nanos / 1_000 % 10) as u8; - buf[26] = b'Z'; - 26 - } else { - buf[20] = b'0' + (nanos / 100_000_000) as u8; - buf[21] = b'0' + (nanos / 10_000_000 % 10) as u8; - buf[22] = b'0' + (nanos / 1_000_000 % 10) as u8; - buf[23] = b'0' + (nanos / 100_000 % 10) as u8; - buf[24] = b'0' + (nanos / 10_000 % 10) as u8; - buf[25] = b'0' + (nanos / 1_000 % 10) as u8; - buf[26] = b'0' + (nanos / 100 % 10) as u8; - buf[27] = b'0' + (nanos / 10 % 10) as u8; - buf[28] = b'0' + (nanos / 1 % 10) as u8; - // 29th is 'Z' - 29 - }; - - // we know our chars are all ascii - f.write_str(str::from_utf8(&buf[..=offset]).expect("Conversion to utf8 failed")) - } -} - -#[cfg(test)] -mod test { - use std::str::from_utf8; - use std::time::{UNIX_EPOCH, SystemTime, Duration}; - - use rand::Rng; - - use super::{parse_rfc3339, parse_rfc3339_weak, format_rfc3339}; - use super::{format_rfc3339_millis, format_rfc3339_micros}; - use super::{format_rfc3339_nanos}; - use super::max; - - fn from_sec(sec: u64) -> (String, SystemTime) { - let s = time::at_utc(time::Timespec { sec: sec as i64, nsec: 0 }) - .rfc3339().to_string(); - let time = UNIX_EPOCH + Duration::new(sec, 0); - (s, time) - } - - #[test] - #[cfg(all(target_pointer_width="32", target_os="linux"))] - fn year_after_2038_fails_gracefully() { - // next second - assert_eq!(parse_rfc3339("2038-01-19T03:14:08Z").unwrap_err(), - super::Error::OutOfRange); - assert_eq!(parse_rfc3339("9999-12-31T23:59:59Z").unwrap_err(), - super::Error::OutOfRange); - } - - #[test] - fn smoke_tests_parse() { - assert_eq!(parse_rfc3339("1970-01-01T00:00:00Z").unwrap(), - UNIX_EPOCH + Duration::new(0, 0)); - assert_eq!(parse_rfc3339("1970-01-01T00:00:01Z").unwrap(), - UNIX_EPOCH + Duration::new(1, 0)); - assert_eq!(parse_rfc3339("2018-02-13T23:08:32Z").unwrap(), - UNIX_EPOCH + Duration::new(1_518_563_312, 0)); - assert_eq!(parse_rfc3339("2012-01-01T00:00:00Z").unwrap(), - UNIX_EPOCH + Duration::new(1_325_376_000, 0)); - } - - #[test] - fn smoke_tests_format() { - assert_eq!( - format_rfc3339(UNIX_EPOCH + Duration::new(0, 0)).to_string(), - "1970-01-01T00:00:00Z"); - assert_eq!( - format_rfc3339(UNIX_EPOCH + Duration::new(1, 0)).to_string(), - "1970-01-01T00:00:01Z"); - assert_eq!( - format_rfc3339(UNIX_EPOCH + Duration::new(1_518_563_312, 0)).to_string(), - "2018-02-13T23:08:32Z"); - assert_eq!( - format_rfc3339(UNIX_EPOCH + Duration::new(1_325_376_000, 0)).to_string(), - "2012-01-01T00:00:00Z"); - } - - #[test] - fn smoke_tests_format_millis() { - assert_eq!( - format_rfc3339_millis(UNIX_EPOCH + - Duration::new(0, 0)).to_string(), - "1970-01-01T00:00:00.000Z"); - assert_eq!( - format_rfc3339_millis(UNIX_EPOCH + - Duration::new(1_518_563_312, 123_000_000)).to_string(), - "2018-02-13T23:08:32.123Z"); - } - - #[test] - fn smoke_tests_format_micros() { - assert_eq!( - format_rfc3339_micros(UNIX_EPOCH + - Duration::new(0, 0)).to_string(), - "1970-01-01T00:00:00.000000Z"); - assert_eq!( - format_rfc3339_micros(UNIX_EPOCH + - Duration::new(1_518_563_312, 123_000_000)).to_string(), - "2018-02-13T23:08:32.123000Z"); - assert_eq!( - format_rfc3339_micros(UNIX_EPOCH + - Duration::new(1_518_563_312, 456_123_000)).to_string(), - "2018-02-13T23:08:32.456123Z"); - } - - #[test] - fn smoke_tests_format_nanos() { - assert_eq!( - format_rfc3339_nanos(UNIX_EPOCH + - Duration::new(0, 0)).to_string(), - "1970-01-01T00:00:00.000000000Z"); - assert_eq!( - format_rfc3339_nanos(UNIX_EPOCH + - Duration::new(1_518_563_312, 123_000_000)).to_string(), - "2018-02-13T23:08:32.123000000Z"); - assert_eq!( - format_rfc3339_nanos(UNIX_EPOCH + - Duration::new(1_518_563_312, 789_456_123)).to_string(), - "2018-02-13T23:08:32.789456123Z"); - } - - #[test] - fn upper_bound() { - let max = UNIX_EPOCH + Duration::new(max::SECONDS, 0); - assert_eq!(parse_rfc3339(&max::TIMESTAMP).unwrap(), max); - assert_eq!(format_rfc3339(max).to_string(), max::TIMESTAMP); - } - - #[test] - fn leap_second() { - assert_eq!(parse_rfc3339("2016-12-31T23:59:60Z").unwrap(), - UNIX_EPOCH + Duration::new(1_483_228_799, 0)); - } - - #[test] - fn first_731_days() { - let year_start = 0; // 1970 - for day in 0..= 365 * 2 { // scan leap year and non-leap year - let (s, time) = from_sec(year_start + day * 86400); - assert_eq!(parse_rfc3339(&s).unwrap(), time); - assert_eq!(format_rfc3339(time).to_string(), s); - } - } - - #[test] - fn the_731_consecutive_days() { - let year_start = 1_325_376_000; // 2012 - for day in 0..= 365 * 2 { // scan leap year and non-leap year - let (s, time) = from_sec(year_start + day * 86400); - assert_eq!(parse_rfc3339(&s).unwrap(), time); - assert_eq!(format_rfc3339(time).to_string(), s); - } - } - - #[test] - fn all_86400_seconds() { - let day_start = 1_325_376_000; - for second in 0..86400 { // scan leap year and non-leap year - let (s, time) = from_sec(day_start + second); - assert_eq!(parse_rfc3339(&s).unwrap(), time); - assert_eq!(format_rfc3339(time).to_string(), s); - } - } - - #[test] - fn random_past() { - let upper = SystemTime::now().duration_since(UNIX_EPOCH).unwrap() - .as_secs(); - for _ in 0..10000 { - let sec = rand::thread_rng().gen_range(0, upper); - let (s, time) = from_sec(sec); - assert_eq!(parse_rfc3339(&s).unwrap(), time); - assert_eq!(format_rfc3339(time).to_string(), s); - } - } - - #[test] - fn random_wide_range() { - for _ in 0..100_000 { - let sec = rand::thread_rng().gen_range(0, max::SECONDS); - let (s, time) = from_sec(sec); - assert_eq!(parse_rfc3339(&s).unwrap(), time); - assert_eq!(format_rfc3339(time).to_string(), s); - } - } - - #[test] - fn milliseconds() { - assert_eq!(parse_rfc3339("1970-01-01T00:00:00.123Z").unwrap(), - UNIX_EPOCH + Duration::new(0, 123_000_000)); - assert_eq!(format_rfc3339(UNIX_EPOCH + Duration::new(0, 123_000_000)) - .to_string(), "1970-01-01T00:00:00.123000000Z"); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn zero_month() { - parse_rfc3339("1970-00-01T00:00:00Z").unwrap(); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn big_month() { - parse_rfc3339("1970-32-01T00:00:00Z").unwrap(); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn zero_day() { - parse_rfc3339("1970-01-00T00:00:00Z").unwrap(); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn big_day() { - parse_rfc3339("1970-12-35T00:00:00Z").unwrap(); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn big_day2() { - parse_rfc3339("1970-02-30T00:00:00Z").unwrap(); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn big_second() { - parse_rfc3339("1970-12-30T00:00:78Z").unwrap(); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn big_minute() { - parse_rfc3339("1970-12-30T00:78:00Z").unwrap(); - } - - #[test] - #[should_panic(expected="OutOfRange")] - fn big_hour() { - parse_rfc3339("1970-12-30T24:00:00Z").unwrap(); - } - - #[test] - fn break_data() { - for pos in 0.."2016-12-31T23:59:60Z".len() { - let mut s = b"2016-12-31T23:59:60Z".to_vec(); - s[pos] = b'x'; - parse_rfc3339(from_utf8(&s).unwrap()).unwrap_err(); - } - } - - #[test] - fn weak_smoke_tests() { - assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00").unwrap(), - UNIX_EPOCH + Duration::new(0, 0)); - parse_rfc3339("1970-01-01 00:00:00").unwrap_err(); - - assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00.000123").unwrap(), - UNIX_EPOCH + Duration::new(0, 123_000)); - parse_rfc3339("1970-01-01 00:00:00.000123").unwrap_err(); - - assert_eq!(parse_rfc3339_weak("1970-01-01T00:00:00.000123").unwrap(), - UNIX_EPOCH + Duration::new(0, 123_000)); - parse_rfc3339("1970-01-01T00:00:00.000123").unwrap_err(); - - assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00.000123Z").unwrap(), - UNIX_EPOCH + Duration::new(0, 123_000)); - parse_rfc3339("1970-01-01 00:00:00.000123Z").unwrap_err(); - - assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00Z").unwrap(), - UNIX_EPOCH + Duration::new(0, 0)); - parse_rfc3339("1970-01-01 00:00:00Z").unwrap_err(); - } -} diff --git a/third_party/rust/humantime/src/duration.rs b/third_party/rust/humantime/src/duration.rs deleted file mode 100644 index a4a46ebb3915..000000000000 --- a/third_party/rust/humantime/src/duration.rs +++ /dev/null @@ -1,456 +0,0 @@ -use std::error::Error as StdError; -use std::fmt; -use std::str::Chars; -use std::time::Duration; - -/// Error parsing human-friendly duration -#[derive(Debug, PartialEq, Clone)] -pub enum Error { - /// Invalid character during parsing - /// - /// More specifically anything that is not alphanumeric is prohibited - /// - /// The field is an byte offset of the character in the string. - InvalidCharacter(usize), - /// Non-numeric value where number is expected - /// - /// This usually means that either time unit is broken into words, - /// e.g. `m sec` instead of `msec`, or just number is omitted, - /// for example `2 hours min` instead of `2 hours 1 min` - /// - /// The field is an byte offset of the errorneous character - /// in the string. - NumberExpected(usize), - /// Unit in the number is not one of allowed units - /// - /// See documentation of `parse_duration` for the list of supported - /// time units. - /// - /// The two fields are start and end (exclusive) of the slice from - /// the original string, containing errorneous value - UnknownUnit { - /// Start of the invalid unit inside the original string - start: usize, - /// End of the invalid unit inside the original string - end: usize, - /// The unit verbatim - unit: String, - /// A number associated with the unit - value: u64, - }, - /// The numeric value is too large - /// - /// Usually this means value is too large to be useful. If user writes - /// data in subsecond units, then the maximum is about 3k years. When - /// using seconds, or larger units, the limit is even larger. - NumberOverflow, - /// The value was an empty string (or consists only whitespace) - Empty, -} - -impl StdError for Error {} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::InvalidCharacter(offset) => write!(f, "invalid character at {}", offset), - Error::NumberExpected(offset) => write!(f, "expected number at {}", offset), - Error::UnknownUnit { unit, value, .. } if &unit == &"" => { - write!(f, - "time unit needed, for example {0}sec or {0}ms", - value, - ) - } - Error::UnknownUnit { unit, .. } => { - write!( - f, - "unknown time unit {:?}, \ - supported units: ns, us, ms, sec, min, hours, days, \ - weeks, months, years (and few variations)", - unit - ) - } - Error::NumberOverflow => write!(f, "number is too large"), - Error::Empty => write!(f, "value was empty"), - } - } -} - -/// A wrapper type that allows you to Display a Duration -#[derive(Debug, Clone)] -pub struct FormattedDuration(Duration); - -trait OverflowOp: Sized { - fn mul(self, other: Self) -> Result; - fn add(self, other: Self) -> Result; -} - -impl OverflowOp for u64 { - fn mul(self, other: Self) -> Result { - self.checked_mul(other).ok_or(Error::NumberOverflow) - } - fn add(self, other: Self) -> Result { - self.checked_add(other).ok_or(Error::NumberOverflow) - } -} - -struct Parser<'a> { - iter: Chars<'a>, - src: &'a str, - current: (u64, u64), -} - -impl<'a> Parser<'a> { - fn off(&self) -> usize { - self.src.len() - self.iter.as_str().len() - } - - fn parse_first_char(&mut self) -> Result, Error> { - let off = self.off(); - for c in self.iter.by_ref() { - match c { - '0'..='9' => { - return Ok(Some(c as u64 - '0' as u64)); - } - c if c.is_whitespace() => continue, - _ => { - return Err(Error::NumberExpected(off)); - } - } - } - Ok(None) - } - fn parse_unit(&mut self, n: u64, start: usize, end: usize) - -> Result<(), Error> - { - let (mut sec, nsec) = match &self.src[start..end] { - "nanos" | "nsec" | "ns" => (0u64, n), - "usec" | "us" => (0u64, n.mul(1000)?), - "millis" | "msec" | "ms" => (0u64, n.mul(1_000_000)?), - "seconds" | "second" | "secs" | "sec" | "s" => (n, 0), - "minutes" | "minute" | "min" | "mins" | "m" - => (n.mul(60)?, 0), - "hours" | "hour" | "hr" | "hrs" | "h" => (n.mul(3600)?, 0), - "days" | "day" | "d" => (n.mul(86400)?, 0), - "weeks" | "week" | "w" => (n.mul(86400*7)?, 0), - "months" | "month" | "M" => (n.mul(2_630_016)?, 0), // 30.44d - "years" | "year" | "y" => (n.mul(31_557_600)?, 0), // 365.25d - _ => { - return Err(Error::UnknownUnit { - start, end, - unit: self.src[start..end].to_string(), - value: n, - }); - } - }; - let mut nsec = self.current.1.add(nsec)?; - if nsec > 1_000_000_000 { - sec = sec.add(nsec / 1_000_000_000)?; - nsec %= 1_000_000_000; - } - sec = self.current.0.add(sec)?; - self.current = (sec, nsec); - Ok(()) - } - - fn parse(mut self) -> Result { - let mut n = self.parse_first_char()?.ok_or(Error::Empty)?; - 'outer: loop { - let mut off = self.off(); - while let Some(c) = self.iter.next() { - match c { - '0'..='9' => { - n = n.checked_mul(10) - .and_then(|x| x.checked_add(c as u64 - '0' as u64)) - .ok_or(Error::NumberOverflow)?; - } - c if c.is_whitespace() => {} - 'a'..='z' | 'A'..='Z' => { - break; - } - _ => { - return Err(Error::InvalidCharacter(off)); - } - } - off = self.off(); - } - let start = off; - let mut off = self.off(); - while let Some(c) = self.iter.next() { - match c { - '0'..='9' => { - self.parse_unit(n, start, off)?; - n = c as u64 - '0' as u64; - continue 'outer; - } - c if c.is_whitespace() => break, - 'a'..='z' | 'A'..='Z' => {} - _ => { - return Err(Error::InvalidCharacter(off)); - } - } - off = self.off(); - } - self.parse_unit(n, start, off)?; - n = match self.parse_first_char()? { - Some(n) => n, - None => return Ok( - Duration::new(self.current.0, self.current.1 as u32)), - }; - } - } - -} - -/// Parse duration object `1hour 12min 5s` -/// -/// The duration object is a concatenation of time spans. Where each time -/// span is an integer number and a suffix. Supported suffixes: -/// -/// * `nsec`, `ns` -- nanoseconds -/// * `usec`, `us` -- microseconds -/// * `msec`, `ms` -- milliseconds -/// * `seconds`, `second`, `sec`, `s` -/// * `minutes`, `minute`, `min`, `m` -/// * `hours`, `hour`, `hr`, `h` -/// * `days`, `day`, `d` -/// * `weeks`, `week`, `w` -/// * `months`, `month`, `M` -- defined as 30.44 days -/// * `years`, `year`, `y` -- defined as 365.25 days -/// -/// # Examples -/// -/// ``` -/// use std::time::Duration; -/// use humantime::parse_duration; -/// -/// assert_eq!(parse_duration("2h 37min"), Ok(Duration::new(9420, 0))); -/// assert_eq!(parse_duration("32ms"), Ok(Duration::new(0, 32_000_000))); -/// ``` -pub fn parse_duration(s: &str) -> Result { - Parser { - iter: s.chars(), - src: s, - current: (0, 0), - }.parse() -} - -/// Formats duration into a human-readable string -/// -/// Note: this format is guaranteed to have same value when using -/// parse_duration, but we can change some details of the exact composition -/// of the value. -/// -/// # Examples -/// -/// ``` -/// use std::time::Duration; -/// use humantime::format_duration; -/// -/// let val1 = Duration::new(9420, 0); -/// assert_eq!(format_duration(val1).to_string(), "2h 37m"); -/// let val2 = Duration::new(0, 32_000_000); -/// assert_eq!(format_duration(val2).to_string(), "32ms"); -/// ``` -pub fn format_duration(val: Duration) -> FormattedDuration { - FormattedDuration(val) -} - -fn item_plural(f: &mut fmt::Formatter, started: &mut bool, - name: &str, value: u64) - -> fmt::Result -{ - if value > 0 { - if *started { - f.write_str(" ")?; - } - write!(f, "{}{}", value, name)?; - if value > 1 { - f.write_str("s")?; - } - *started = true; - } - Ok(()) -} -fn item(f: &mut fmt::Formatter, started: &mut bool, name: &str, value: u32) - -> fmt::Result -{ - if value > 0 { - if *started { - f.write_str(" ")?; - } - write!(f, "{}{}", value, name)?; - *started = true; - } - Ok(()) -} - -impl FormattedDuration { - /// Returns a reference to the [`Duration`][] that is being formatted. - pub fn get_ref(&self) -> &Duration { - &self.0 - } -} - -impl fmt::Display for FormattedDuration { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let secs = self.0.as_secs(); - let nanos = self.0.subsec_nanos(); - - if secs == 0 && nanos == 0 { - f.write_str("0s")?; - return Ok(()); - } - - let years = secs / 31_557_600; // 365.25d - let ydays = secs % 31_557_600; - let months = ydays / 2_630_016; // 30.44d - let mdays = ydays % 2_630_016; - let days = mdays / 86400; - let day_secs = mdays % 86400; - let hours = day_secs / 3600; - let minutes = day_secs % 3600 / 60; - let seconds = day_secs % 60; - - let millis = nanos / 1_000_000; - let micros = nanos / 1000 % 1000; - let nanosec = nanos % 1000; - - let ref mut started = false; - item_plural(f, started, "year", years)?; - item_plural(f, started, "month", months)?; - item_plural(f, started, "day", days)?; - item(f, started, "h", hours as u32)?; - item(f, started, "m", minutes as u32)?; - item(f, started, "s", seconds as u32)?; - item(f, started, "ms", millis)?; - item(f, started, "us", micros)?; - item(f, started, "ns", nanosec)?; - Ok(()) - } -} - -#[cfg(test)] -mod test { - use std::time::Duration; - - use rand::Rng; - - use super::{parse_duration, format_duration}; - use super::Error; - - #[test] - #[allow(clippy::cognitive_complexity)] - fn test_units() { - assert_eq!(parse_duration("17nsec"), Ok(Duration::new(0, 17))); - assert_eq!(parse_duration("17nanos"), Ok(Duration::new(0, 17))); - assert_eq!(parse_duration("33ns"), Ok(Duration::new(0, 33))); - assert_eq!(parse_duration("3usec"), Ok(Duration::new(0, 3000))); - assert_eq!(parse_duration("78us"), Ok(Duration::new(0, 78000))); - assert_eq!(parse_duration("31msec"), Ok(Duration::new(0, 31_000_000))); - assert_eq!(parse_duration("31millis"), Ok(Duration::new(0, 31_000_000))); - assert_eq!(parse_duration("6ms"), Ok(Duration::new(0, 6_000_000))); - assert_eq!(parse_duration("3000s"), Ok(Duration::new(3000, 0))); - assert_eq!(parse_duration("300sec"), Ok(Duration::new(300, 0))); - assert_eq!(parse_duration("300secs"), Ok(Duration::new(300, 0))); - assert_eq!(parse_duration("50seconds"), Ok(Duration::new(50, 0))); - assert_eq!(parse_duration("1second"), Ok(Duration::new(1, 0))); - assert_eq!(parse_duration("100m"), Ok(Duration::new(6000, 0))); - assert_eq!(parse_duration("12min"), Ok(Duration::new(720, 0))); - assert_eq!(parse_duration("12mins"), Ok(Duration::new(720, 0))); - assert_eq!(parse_duration("1minute"), Ok(Duration::new(60, 0))); - assert_eq!(parse_duration("7minutes"), Ok(Duration::new(420, 0))); - assert_eq!(parse_duration("2h"), Ok(Duration::new(7200, 0))); - assert_eq!(parse_duration("7hr"), Ok(Duration::new(25200, 0))); - assert_eq!(parse_duration("7hrs"), Ok(Duration::new(25200, 0))); - assert_eq!(parse_duration("1hour"), Ok(Duration::new(3600, 0))); - assert_eq!(parse_duration("24hours"), Ok(Duration::new(86400, 0))); - assert_eq!(parse_duration("1day"), Ok(Duration::new(86400, 0))); - assert_eq!(parse_duration("2days"), Ok(Duration::new(172_800, 0))); - assert_eq!(parse_duration("365d"), Ok(Duration::new(31_536_000, 0))); - assert_eq!(parse_duration("1week"), Ok(Duration::new(604_800, 0))); - assert_eq!(parse_duration("7weeks"), Ok(Duration::new(4_233_600, 0))); - assert_eq!(parse_duration("52w"), Ok(Duration::new(31_449_600, 0))); - assert_eq!(parse_duration("1month"), Ok(Duration::new(2_630_016, 0))); - assert_eq!(parse_duration("3months"), Ok(Duration::new(3*2_630_016, 0))); - assert_eq!(parse_duration("12M"), Ok(Duration::new(31_560_192, 0))); - assert_eq!(parse_duration("1year"), Ok(Duration::new(31_557_600, 0))); - assert_eq!(parse_duration("7years"), Ok(Duration::new(7*31_557_600, 0))); - assert_eq!(parse_duration("17y"), Ok(Duration::new(536_479_200, 0))); - } - - #[test] - fn test_combo() { - assert_eq!(parse_duration("20 min 17 nsec "), Ok(Duration::new(1200, 17))); - assert_eq!(parse_duration("2h 15m"), Ok(Duration::new(8100, 0))); - } - - #[test] - fn all_86400_seconds() { - for second in 0..86400 { // scan leap year and non-leap year - let d = Duration::new(second, 0); - assert_eq!(d, - parse_duration(&format_duration(d).to_string()).unwrap()); - } - } - - #[test] - fn random_second() { - for _ in 0..10000 { - let sec = rand::thread_rng().gen_range(0, 253_370_764_800); - let d = Duration::new(sec, 0); - assert_eq!(d, - parse_duration(&format_duration(d).to_string()).unwrap()); - } - } - - #[test] - fn random_any() { - for _ in 0..10000 { - let sec = rand::thread_rng().gen_range(0, 253_370_764_800); - let nanos = rand::thread_rng().gen_range(0, 1_000_000_000); - let d = Duration::new(sec, nanos); - assert_eq!(d, - parse_duration(&format_duration(d).to_string()).unwrap()); - } - } - - #[test] - fn test_overlow() { - // Overflow on subseconds is earlier because of how we do conversion - // we could fix it, but I don't see any good reason for this - assert_eq!(parse_duration("100000000000000000000ns"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("100000000000000000us"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("100000000000000ms"), - Err(Error::NumberOverflow)); - - assert_eq!(parse_duration("100000000000000000000s"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("10000000000000000000m"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("1000000000000000000h"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("100000000000000000d"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("10000000000000000w"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("1000000000000000M"), - Err(Error::NumberOverflow)); - assert_eq!(parse_duration("10000000000000y"), - Err(Error::NumberOverflow)); - } - - #[test] - fn test_nice_error_message() { - assert_eq!(parse_duration("123").unwrap_err().to_string(), - "time unit needed, for example 123sec or 123ms"); - assert_eq!(parse_duration("10 months 1").unwrap_err().to_string(), - "time unit needed, for example 1sec or 1ms"); - assert_eq!(parse_duration("10nights").unwrap_err().to_string(), - "unknown time unit \"nights\", supported units: \ - ns, us, ms, sec, min, hours, days, weeks, months, \ - years (and few variations)"); - } -} diff --git a/third_party/rust/humantime/src/lib.rs b/third_party/rust/humantime/src/lib.rs deleted file mode 100644 index 9be6f2285263..000000000000 --- a/third_party/rust/humantime/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Human-friendly time parser and formatter -//! -//! Features: -//! -//! * Parses durations in free form like `15days 2min 2s` -//! * Formats durations in similar form `2years 2min 12us` -//! * Parses and formats timestamp in `rfc3339` format: `2018-01-01T12:53:00Z` -//! * Parses timestamps in a weaker format: `2018-01-01 12:53:00` -//! -//! Timestamp parsing/formatting is super-fast because format is basically -//! fixed. -//! -//! See [humantime-serde] for serde integration (previous crate [serde-humantime] looks unmaintained). -//! -//! [serde-humantime]: https://docs.rs/serde-humantime/0.1.1/serde_humantime/ -//! [humantime-serde]: https://docs.rs/humantime-serde - -#![forbid(unsafe_code)] -#![warn(missing_debug_implementations)] -#![warn(missing_docs)] - -mod duration; -mod wrapper; -mod date; - -pub use self::duration::{parse_duration, Error as DurationError}; -pub use self::duration::{format_duration, FormattedDuration}; -pub use self::wrapper::{Duration, Timestamp}; -pub use self::date::{parse_rfc3339, parse_rfc3339_weak, Error as TimestampError}; -pub use self::date::{ - format_rfc3339, format_rfc3339_micros, format_rfc3339_millis, format_rfc3339_nanos, - format_rfc3339_seconds, -}; -pub use self::date::{Rfc3339Timestamp}; diff --git a/third_party/rust/humantime/src/wrapper.rs b/third_party/rust/humantime/src/wrapper.rs deleted file mode 100644 index 99af6502ae8a..000000000000 --- a/third_party/rust/humantime/src/wrapper.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::str::FromStr; -use std::ops::Deref; -use std::fmt; -use std::time::{Duration as StdDuration, SystemTime}; - -use crate::duration::{self, parse_duration, format_duration}; -use crate::date::{self, parse_rfc3339_weak, format_rfc3339}; - -/// A wrapper for duration that has `FromStr` implementation -/// -/// This is useful if you want to use it somewhere where `FromStr` is -/// expected. -/// -/// See `parse_duration` for the description of the format. -/// -/// # Example -/// -/// ``` -/// use std::time::Duration; -/// let x: Duration; -/// x = "12h 5min 2ns".parse::().unwrap().into(); -/// assert_eq!(x, Duration::new(12*3600 + 5*60, 2)) -/// ``` -/// -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct Duration(StdDuration); - -/// A wrapper for SystemTime that has `FromStr` implementation -/// -/// This is useful if you want to use it somewhere where `FromStr` is -/// expected. -/// -/// See `parse_rfc3339_weak` for the description of the format. The "weak" -/// format is used as it's more pemissive for human input as this is the -/// expected use of the type (e.g. command-line parsing). -/// -/// # Example -/// -/// ``` -/// use std::time::SystemTime; -/// let x: SystemTime; -/// x = "2018-02-16T00:31:37Z".parse::().unwrap().into(); -/// assert_eq!(humantime::format_rfc3339(x).to_string(), "2018-02-16T00:31:37Z"); -/// ``` -/// -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Timestamp(SystemTime); - -impl AsRef for Duration { - fn as_ref(&self) -> &StdDuration { &self.0 } -} - -impl Deref for Duration { - type Target = StdDuration; - fn deref(&self) -> &StdDuration { &self.0 } -} - -impl Into for Duration { - fn into(self) -> StdDuration { self.0 } -} - -impl From for Duration { - fn from(dur: StdDuration) -> Duration { Duration(dur) } -} - -impl FromStr for Duration { - type Err = duration::Error; - fn from_str(s: &str) -> Result { - parse_duration(s).map(Duration) - } -} - -impl fmt::Display for Duration { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_duration(self.0).fmt(f) - } -} - -impl AsRef for Timestamp { - fn as_ref(&self) -> &SystemTime { &self.0 } -} - -impl Deref for Timestamp { - type Target = SystemTime; - fn deref(&self) -> &SystemTime { &self.0 } -} - -impl Into for Timestamp { - fn into(self) -> SystemTime { self.0 } -} - -impl From for Timestamp { - fn from(dur: SystemTime) -> Timestamp { Timestamp(dur) } -} - -impl FromStr for Timestamp { - type Err = date::Error; - fn from_str(s: &str) -> Result { - parse_rfc3339_weak(s).map(Timestamp) - } -} - -impl fmt::Display for Timestamp { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_rfc3339(self.0).fmt(f) - } -} diff --git a/third_party/rust/humantime/vagga.yaml b/third_party/rust/humantime/vagga.yaml deleted file mode 100644 index 8a6b5847e07e..000000000000 --- a/third_party/rust/humantime/vagga.yaml +++ /dev/null @@ -1,92 +0,0 @@ -commands: - - cargo: !Command - description: Run any cargo command - container: ubuntu - run: [cargo] - - make: !Command - description: Build the library - container: ubuntu - run: [cargo, build] - - test64: !Command - description: Test the 64bit library - container: ubuntu - environ: { RUST_BACKTRACE: 1 } - run: [cargo, test] - - test32: !Command - description: Test the 32bit library - container: ubuntu32 - environ: { RUST_BACKTRACE: 1 } - run: [cargo, test] - - test: !Command - description: Test the 64bit library - container: ubuntu - environ: { RUST_BACKTRACE: 1 } - prerequisites: [test64, test32] - run: [echo, okay] - - bench: !Command - description: Run benchmarks - container: bench - environ: { RUST_BACKTRACE: 1 } - run: [cargo, bench] - - _bulk: !Command - description: Run `bulk` command (for version bookkeeping) - container: ubuntu - run: [bulk] - -containers: - - ubuntu: - setup: - - !Ubuntu xenial - - !UbuntuUniverse - - !Install [ca-certificates, build-essential, vim] - - - !TarInstall - url: "https://static.rust-lang.org/dist/rust-1.31.0-x86_64-unknown-linux-gnu.tar.gz" - script: "./install.sh --prefix=/usr \ - --components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo" - - &bulk !Tar - url: "https://github.com/tailhook/bulk/releases/download/v0.4.10/bulk-v0.4.10.tar.gz" - sha256: 481513f8a0306a9857d045497fb5b50b50a51e9ff748909ecf7d2bda1de275ab - path: / - - environ: - HOME: /work/target - USER: pc - - ubuntu32: - setup: - - !UbuntuRelease - codename: xenial - arch: i386 - - !UbuntuUniverse - - !Install [ca-certificates, build-essential, vim] - - - !TarInstall - url: "https://static.rust-lang.org/dist/rust-1.31.0-i686-unknown-linux-gnu.tar.gz" - script: "./install.sh --prefix=/usr \ - --components=rustc,rust-std-i686-unknown-linux-gnu,cargo" - - environ: - HOME: /work/target - USER: pc - - bench: - setup: - - !Ubuntu xenial - - !Install [ca-certificates, wget, build-essential] - - !TarInstall - url: https://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz - script: | - ./install.sh --prefix=/usr \ - --components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo - environ: - HOME: /work/target - USER: pc diff --git a/third_party/rust/mp4parse/.cargo-checksum.json b/third_party/rust/mp4parse/.cargo-checksum.json index eff7dfbf0d9c..0a8608f6cd6e 100644 --- a/third_party/rust/mp4parse/.cargo-checksum.json +++ b/third_party/rust/mp4parse/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f283fc1597f492cd1e03cd08b9c77f042ae4494fc96b4dcb566ec0abbda65efc","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"86cb40854b93f988e3a63ce6fe39d2ce95367f8ca301a5ba50676ff98a0ad791","benches/avif_benchmark.rs":"cd99c0dde025ab40d2cd860f53dc697a1587a48c164c3e5c8adfd40add29d772","link-u-avif-sample-images/.github/workflows/encode-and-decode-daily.yml":"84b787f721024a100ce09ac5714a1d78a4811893861e89495313f435b9d02359","link-u-avif-sample-images/.gitignore":"ac16d40779ab2d608843a3cb1b0418a1ffdc0e71a06c4d140386fadf007a54a7","link-u-avif-sample-images/LICENSE.txt":"da89f9867822be4b8adb1e601d9e9226c195016c6508015eb7593e68ead0c98a","link-u-avif-sample-images/Makefile":"b5697e8685d2a9ce0f4b4c976a5f707022ed113782d16dc59ae280d3a8ce77b1","link-u-avif-sample-images/README.md":"d249fb7bef4f21359cfc4f2977e1b2f2c6e6dd6e57cb1cdc1da1f0edd8aa55d0","link-u-avif-sample-images/fox.jpg":"927997a90ae88ead007283bf9c1392159d0acd2e9890522146211fda2112a2d9","link-u-avif-sample-images/fox.odd-height.png":"6136247772bd1c0edd50426bca4f3485473ac25a784e5ec8777f7491598e96db","link-u-avif-sample-images/fox.odd-width.odd-height.png":"6f91dc21c137f318d0443ce28bbf3f74d5502180c254327b46e41040a33f1363","link-u-avif-sample-images/fox.odd-width.png":"a8b2328c8700c16280c5ab40a34147edac598d4d48ca101bef649e468ae1492e","link-u-avif-sample-images/fox.png":"c45bfb5780843c70a37426340020e3e7ff41d7cf1df9fec614a5cf429d078573","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.avif":"811af5e96631309030a14cbc30c3bacfaa667f2e36e16a4f30434b8f5a23310c","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.avif":"e35713343e9ee04c51ab9cfdc99a0c7d126a1917cb83f5b9a23c71ed59269be2","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.odd-height.avif":"485623f7838d8f442c47348c6492765e6aafbc3d5ccd8e90efc9c812ff15e265","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.odd-width.avif":"8e75b9a8975267359d827e4cbc6877b1674aa31b87f88f222dde03263f9254df","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif":"1fff5915a332d6aaa85d668f3f338bda6fad9c6ec1f380f2c46737d536cea5de","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.odd-height.avif":"cca9785f14c74d865453518c0962dabd6d1b92d2c6c5f5ac67efdbf5606acb83","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.odd-width.avif":"de3399d8b56431f0ed34e2f14200f31dd54544fddbb12f39b4d55449d5660c56","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.odd-width.odd-height.avif":"07507744cb76b74a3586b93fc3b273a98f998d75f7687db3e9cb3725d7b1fb9d","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.avif":"cb884c82ac7b6d4fa03b1f687e9e20abc346107095473e9c1d422aaf0de14eaf","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.avif":"15d84077066c47fdbe2a7b8ed583a17017d09a033144ac1b31486d6c8f6f5c82","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.odd-height.avif":"365439d2ee2fe5229e066362c03a73a182c7f6626772ecf5345b22752d32e681","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.odd-width.avif":"c623b9943123d6c47d3300444f7255cbdfebfe2b47a670287f2baeb717fac42b","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif":"dd069f3c3c4f7589f5f7ef1d7b6a91b8cb975d32663a4a92b6d75219edd72954","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.odd-height.avif":"75628450288ace3386651725411c8f0ffff7eb95f82c5307b0faa3350f09f50e","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.odd-width.avif":"f91b6f455412adabc5094011362eaaa1f6a9d5740de0b8a1be42a96c16e7617f","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.odd-width.odd-height.avif":"bb8695cacacaf8f2e13a739de75e5e8a9d970d68c3acdfb7d82171a9bac2f01e","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.avif":"a10de8204aee73ba1786daca6390546bd7aa6b069aaa644012219a1c11246a43","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.odd-height.avif":"734a5badc59a8bed19e8eb476911048ddb011ca7c9eac31b7a7ed20e0135ac2c","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.odd-width.avif":"68d15d76d95f268e810dfd87bbf96d8c3197580afce2d30b50bb1f07865077f3","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.odd-width.odd-height.avif":"01e469b33bacb7e07e15e23b2997907bbcf02d8fcc99885a027494d31c45547c","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.avif":"a0cdc981a6b056c8af2d177a1438c332d630040dacbfd1c89bb5e3e381ba5822","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.odd-height.avif":"77e0510def73213c00ebcf051cf45fa63cf27d7c69340cc145ab6d44ec77bb07","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.odd-width.avif":"12787042364bd13be01830f988cb714220bde340a3329baa808df27a269b83f8","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.odd-width.odd-height.avif":"fad3b6dd9cb99e6925858f69aafae3f68c861845f2c3d4a6d1c51c6161490134","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.avif":"e34f3bab5df802be2d422c685824464eb5f7e182b235ca99bde11c4c34ff3ac2","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.avif":"05804752621e2fd7a9d85b01e2995a50e3efd30693efd934152560622d66e841","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.odd-height.avif":"ef041f2efa0424d3a6dcfc5f0c3f619aea0e197aaeb5a050a2d877a457513921","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.odd-width.avif":"b711b321b8a4d3a41e08f80a17c2203b839458cb6346aff6fff3f8d7699032e6","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif":"e3f40aad0ddd6c04ffacf4a754a0525986c89d519119d37655282551e3ea3a59","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.odd-height.avif":"4ef74c37712b41d6e5269d939f9d52031bc10746f7c8c029db618c5935aff9a6","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.odd-width.avif":"4cf6c849f4a48a639217ad9a1e0d027f4fc804d524c03e6707ec9714a252532f","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.odd-width.odd-height.avif":"3d3978e8e8d07270f82a877d3535f9483b88fce93a1c4accb658b494452b1d36","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.avif":"626d73272e59722084c528b27b72a0920bec462a10749b3e87036e42bf8a24e5","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.avif":"caf50c467242b3fa0b895a2af131fa0d03dd7b34989f2b1a51d25b2246c98fab","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.odd-height.avif":"1e88b92df592c02af53ff5258fa898ac8fe1d71954e9a440500ef7879b8a1c46","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.odd-width.avif":"466efdd269f3be3b1c88afc093c839e50ba5eaf6bd0c2425e157000d02a3c21a","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif":"36014509d0688cb307e0ffcdb5b4c16ff6e6c79772c7fbbeea33b4d483a1566f","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.odd-height.avif":"d1786723a5d6ea1e1764b0045dc3f669fe3905ffc2913011a2b1b424d2393397","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.odd-width.avif":"a2d9178cc5622e28472a735650d9c4deaec6d27d69830110911f4158f9d4a04e","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.odd-width.odd-height.avif":"89a9fc7598d72251b903e0c7088ab3e7a7f316b5e02b85f8c69e51f8eb0c7e69","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.avif":"51476b8471e1c0a5ebbd1e7545709495bef619cc96c02d277aad32b1deff8ea9","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.avif":"caf50c467242b3fa0b895a2af131fa0d03dd7b34989f2b1a51d25b2246c98fab","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.odd-height.avif":"1e88b92df592c02af53ff5258fa898ac8fe1d71954e9a440500ef7879b8a1c46","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.odd-width.avif":"466efdd269f3be3b1c88afc093c839e50ba5eaf6bd0c2425e157000d02a3c21a","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif":"36014509d0688cb307e0ffcdb5b4c16ff6e6c79772c7fbbeea33b4d483a1566f","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.odd-height.avif":"4808960cdcd1207b29eb6ef5b4db81ae5e63c5d40ef92f7a1e8f4430e765bde4","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.odd-width.avif":"71f3c73737bc04c23d93ea2c61a8a07408f604192fe53fe12c65050927dacb4e","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.odd-width.odd-height.avif":"8f9649384fa09c70af0c2e9e0d94ecd17492c702e015d9d6290d3aefc57c548c","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.avif":"ed96eca6ed79863eaf91e4d666e4e220b5fa4e5a6cb1696477ba901ac12f5dde","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.avif":"caf50c467242b3fa0b895a2af131fa0d03dd7b34989f2b1a51d25b2246c98fab","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.odd-height.avif":"1e88b92df592c02af53ff5258fa898ac8fe1d71954e9a440500ef7879b8a1c46","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.odd-width.avif":"466efdd269f3be3b1c88afc093c839e50ba5eaf6bd0c2425e157000d02a3c21a","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif":"36014509d0688cb307e0ffcdb5b4c16ff6e6c79772c7fbbeea33b4d483a1566f","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.odd-height.avif":"c43b4c607e301e34eb953770133d89d15e77d63be8d6421a80d6212fbbbf3453","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.odd-width.avif":"0e6218ce250ee7f84a621f3af73286fd4dabea19e9898d3575c20c5955aa427d","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.odd-width.odd-height.avif":"9f19846d884ac7d161ac2ca15811bb22ff7f3847bc1ad5d7713971ea024631aa","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.avif":"2cb363d30f83bff58ee049874b1808b37cb1d35342edf16b3ce25cb243c9ea55","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.avif":"8217b88f350c5d3812d7f863fe9d710c4c1b846b0be8df29ce6b3eb30d2b8d8f","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.odd-height.avif":"51eccd8c1368ddec9bc1f3a7631dadb00682e985fbfea66c0a2f533f6a73b67e","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.odd-width.avif":"83fe4593ab839cf296a2ccb8a146daf826d1d602f4f239cb63ee020f2cc326f6","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif":"4e63b84a980a81adde586314a94d8f834ec763749d8797c286471415b6b75647","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.odd-height.avif":"efc70882aacbb533c0e833a4401949d152dceb364846442cdccca5048ad17a60","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.odd-width.avif":"c07575c88ef400c1725c9260a19439e0e784da41c7db3867059019ddbdb3bebe","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.odd-width.odd-height.avif":"86aee64fd7b11b9834537ea14b2eff234c062c98d32fab51ff14aba262d5b106","link-u-avif-sample-images/hato.16bpc.png":"53b550c587cd1d19a1997184e47f4a3ff2a05cedf7cb4e42a9466a6d6cb60d8d","link-u-avif-sample-images/hato.jpg":"6d4804e5e4adf36a6b138544c81b743ed7abdd9a495a43e883ec77689ca28943","link-u-avif-sample-images/hato.png":"313880f4cc51160fec522d78f1fb7f06df70fe1929a731fc86c68ecefd312277","link-u-avif-sample-images/hato.profile0.10bpc.yuv420.avif":"1e84598c94bc795c55a551bdf6f283b4eed4997bda15e5c4bb2e29d0dc70897b","link-u-avif-sample-images/hato.profile0.10bpc.yuv420.monochrome.avif":"25c19a187d10eac963bb51b3fae1ffe50f3ccbc7ad02e51948dc7467b397ce61","link-u-avif-sample-images/hato.profile0.8bpc.yuv420.avif":"07cd454de19dd638354f75d9e97aab08bc8a04dd45c4f7531cb62a1a5656c8c9","link-u-avif-sample-images/hato.profile0.8bpc.yuv420.monochrome.avif":"120a3f26f3d6cde80869fb52bdb8fdd55b443882c98070ea938575e4790982ff","link-u-avif-sample-images/hato.profile2.10bpc.yuv422.avif":"d54251d4bc023f2e53624a46cb18e56cbc45768bd1bd50394de191c2a42106e8","link-u-avif-sample-images/hato.profile2.10bpc.yuv422.monochrome.avif":"ed33dfdb5e663b3394298b6921f9b19b129e14788dead776430eee2f14780a73","link-u-avif-sample-images/hato.profile2.12bpc.yuv422.avif":"ad361ac7d94fbc6af7ef30cbd3601ff366bc360c304480387a58a4c6fecee9b6","link-u-avif-sample-images/hato.profile2.12bpc.yuv422.monochrome.avif":"e28b4cacda95750e465e205fbfcba6a6af1d8418dac649838730c555ff7d828f","link-u-avif-sample-images/hato.profile2.8bpc.yuv422.avif":"69c353c482c2eb3d3671bb55f7ccfc932e4d781c714a72116e9138ffc6f6c720","link-u-avif-sample-images/hato.profile2.8bpc.yuv422.monochrome.avif":"e7d6f7d42a8519e1482f225fe447b5642d19a54ee830529223eac114a0dec189","link-u-avif-sample-images/images.html":"9e18453dfe5b205600f158282c6896265281e3b04b2fbc332804fab1dbdb3faf","link-u-avif-sample-images/kimono.avif":"63412e0f67f37c8b6fcf0e8269a2afae0a017fa6a3a99d37d055c590b0be52d3","link-u-avif-sample-images/kimono.crop.avif":"f175dcd9c64813b759da185fa67076fb772b76059845b2aad3ddcfab257f75ad","link-u-avif-sample-images/kimono.crop.png":"0d5605bae0ec9d39aad9dc8e1a371d0327c6a224643983e3ee1f4d44cb00f19d","link-u-avif-sample-images/kimono.jpg":"a6ad58e3cea437ee0c841115ba67ae7354de7af734de50de9d0853dd4e571577","link-u-avif-sample-images/kimono.mirror-horizontal.avif":"2bbc004d91145488610158a5acdb4d706495a2b15511db20ff57bb9efd80885c","link-u-avif-sample-images/kimono.mirror-horizontal.png":"9af9e839fe6bf6342831970c20291f619570d2fc687951ae00cd81ea766f53fe","link-u-avif-sample-images/kimono.mirror-vertical.avif":"f10eb04791fcca3409868b367128649f32e6b6fffcf02484cdefa57909f6bb74","link-u-avif-sample-images/kimono.mirror-vertical.png":"4ed003c5868fd2e78c7b2dcbd54a67a0e7593dabb3ac82b1c9e5e2dbdf09b8ec","link-u-avif-sample-images/kimono.mirror-vertical.rotate270.avif":"33c36ec2274b00ac6f81c9f61e55c20cbfce1649ad27520afe635310f516ead1","link-u-avif-sample-images/kimono.mirror-vertical.rotate270.crop.avif":"90ca48f657455b8f8e4a4e1769a05af90a3e34dca11a8b3c32552daf378ee956","link-u-avif-sample-images/kimono.mirror-vertical.rotate270.png":"74b9b7ffa8955761f747a0e6e81d5b7ecb5e325383546110e1b6aa9986728035","link-u-avif-sample-images/kimono.png":"84fd6cfb97a27739608e21779f874b4ae7e80342b2588e8b0b092dee2d57c881","link-u-avif-sample-images/kimono.rotate270.avif":"79a99a0415276cc11f2e871d070a9df84df3385888a2f2fa3534320f6bed98ed","link-u-avif-sample-images/kimono.rotate270.png":"1918a47c02b378945a705301abd4250ddc65bb95afce9424572ffd0fdd1f45ef","link-u-avif-sample-images/kimono.rotate90.avif":"bd1157d8c840713c82b907b9d3ae80bc3817849e11c323d875f8016e035bd3cc","link-u-avif-sample-images/kimono.rotate90.png":"1a73c61692abe96d0a7a9accdb36a83d51bceac79bbb83a00571570f494cca49","link-u-avif-sample-images/plum-blossom-large.png":"af6ea005b726ca39f342e946aa53bed88e5a140413ce896d166bb35ab0aa3b4f","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif":"cf8e15ec4b210235f3d68332a1adeb64e35c41b8d8e1e7586ae38b6d9cd8926c","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif":"b413440309d5669a7aefa06f291f72de0d0c09972e3da9a385e6016d6a1c5562","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif":"64f6f2b1fda594af5c9e2d6e4bc752b55e8121000cdcedc0066018e53f76de40","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif":"2b175a600aed64c1c1de4b2d661fb405437b1ff000b964d4be6ac437ce73136f","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif":"21ebb3732186bf7c6c13cf7197155b64201e674b9c79cf613b6e5718bde14c2a","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif":"65917797e511c9033b3e225eb5d84f3c0440b7a496d4b8ab5674e123ad68aab7","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif":"f4809df9188fa46ed100f63c78c4cf42559d90a98351a8f69e177385920672b4","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif":"dffc213dc36f0b5ff3d86254f5185c2d1fb03380918a8fa39d186fb59cbba7cc","link-u-avif-sample-images/plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif":"0a615cfb673ab45e37da3582c17dd36f86d5da3d81246a32951d1db4ed90149d","link-u-avif-sample-images/plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif":"d1cc6a0db116a68e229676b289e8ced84d42a9f0e8d3ccd760fc92dbeb932547","link-u-avif-sample-images/plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif":"8626cf0b2c60fee51cf1df7fe4d8a18081b72e3604f7d3ff14cc5a35581927d9","link-u-avif-sample-images/plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif":"56bf18e4bcbfbea460c306ab900fc506169854d2b91690e1a48156a86fff3264","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif":"b56f3c33797e4c5bb80418ae25f6f2c6fc88ddc1f6965d82abc44059f052f36c","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif":"c3c6db4ce801c68e2afd7bfb72abacc13287cc2e247917a817ff5632bd4b18fb","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif":"095f57fff1dc037a6414c60263415dcfa86b10d81f58e8e4c3aef17cffae0e5f","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif":"ba3035a69296d12f47d1c450f2de8cc0c9059ebbf27bb8b0996ff6d1ab1132a1","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif":"a9551e1963049b874216b40aaf9be45bc44dc11887770712b77240862c6c08a9","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif":"a8a0ba881cd0aef45a5874f412e97812ca457eaf12e56b34bac2ba051e142828","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif":"6891b5bdbed7f541c673c66cec4584b191bb737a49b37cca16ae069830890b42","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif":"67e66826637e349e1c3c46316c7048d152aed8453d8cdd00c6b786f87fe176d8","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif":"a466503110f60dcadaafe78c2cb0a8ca58334c22868efe428c7ac12b69407c95","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif":"a8a0ba881cd0aef45a5874f412e97812ca457eaf12e56b34bac2ba051e142828","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif":"061b4c70707e7fc8866580656cca7ca2da2263645829a564dbf8f205d639f058","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif":"67e66826637e349e1c3c46316c7048d152aed8453d8cdd00c6b786f87fe176d8","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif":"4a03c8bcfcaadccdeb07432ed80680b06aba5ae5e616fc370b376acb478f6cd1","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif":"a8a0ba881cd0aef45a5874f412e97812ca457eaf12e56b34bac2ba051e142828","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif":"376625ce4e7ec3b57344a9f2185a34975fe380774c9f8e0dd4ef61c46da94fca","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif":"67e66826637e349e1c3c46316c7048d152aed8453d8cdd00c6b786f87fe176d8","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif":"1e17b7dd8e351cb667bc6ec0b81fdebca9fd30ad5e588b3eac57bf9f90a9b58b","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif":"f77588d2ff39e4461869a95ca236efdf4a3fdc17b8a6e3907e63b417e56c81b5","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif":"f2eabd3fc2db07b361d55b5af63023d28b5bdd0047a665e9d0685651ce9db94b","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif":"dd88c377b253d689bfd4600d7c3007448df0ed92f679b661d5d51e051a6916d8","link-u-avif-sample-images/plum-blossom-small.png":"c859fd97b647e494461f65835b9c1c3476807aee77076599adf18a832b3617a4","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif":"fe3379620f983e5da4210b0f7c5d164e86208b34106d6b11d56e2b52beee5dfe","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif":"9e6234686053dba2e44bb32192c641074095a61e45aa1bede85bb83751e6e157","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif":"60ffa59dd007aea3bb596cfb03853b3dad490b1ffd10471ad4fe1901ec819907","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif":"58abfa027525aca7339a705f311bc30b000aef9822c7c50b232894ece1ba9cb1","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif":"541ca66a11b1430d11f77b74a13f859239a3bd9f44976b8dfe163c5d7595a69f","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif":"6d7852c63c27a77bef94443e178ecf6b6a3da8cc846f9f0c1adc17f7fc35e1f3","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif":"3712216ffc7edb95a976b68469ead533fda6fe9f3d2e8cb09cbdb0d01d9c094b","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif":"59672af536b169ebf7e48129167dc91cb253925517c37db28b64539f7afba5d3","link-u-avif-sample-images/plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif":"561d5158425ad39425916a3be048b0202e82efef44cf1a9f711db57192d2ff01","link-u-avif-sample-images/plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif":"88336f29457c1dc4ae0b754ef14b791de4d8c337f2b44d7960aafcca08a5586e","link-u-avif-sample-images/plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif":"245a3dad6371dc702f29eb7e9735f843b63c525da871859728bedbe5bb274985","link-u-avif-sample-images/plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif":"490c216b5850c670f6088ee72c7fd906102b2dd0c8432c01a517b3328db27c75","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif":"0d0bbbcb0c9ade1c827317a6409ce6ba25027b36da1b6752379a5f5d4c8af056","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif":"418a9d4b7dcbc1f67fc4b95ccb2e7946c446fddd35a79f0d587b3f2165cb3f14","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif":"a41dcfabb3795ed93a05881a91bf4d1c5d1b9b0e5d0db728f12684b12613e0c9","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif":"4b6a18f4f608d1b00598e67c1c91a4e8f4943ae5acf0166ae0121cc21f3b7437","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif":"5e6b83adee3aeac4bba3f38e854e2ed7585aa1557a74b5fa66596098c53e26f2","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif":"fb0937564c08f4e1c22ebbde426a0eff6a1d388434c30148bc7e5582dc378caa","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif":"f42e780bff644167e27525fee65b23e70814f7665ea19b6d693eb127c5eeebd8","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif":"d41ead1d69d33d0cf5f6fe575beb5f60d9565300c535f9042113dd8a748c1d31","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif":"c6ee9234ee7783d0203f9512e3cc8fe76a694675bcf03c320ff8bab4684bd4e9","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif":"fb0937564c08f4e1c22ebbde426a0eff6a1d388434c30148bc7e5582dc378caa","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif":"21e1e51fc6da66e090e12e1df5aeabf1f478df64bcb8151caaa687ad262bdd9d","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif":"d41ead1d69d33d0cf5f6fe575beb5f60d9565300c535f9042113dd8a748c1d31","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif":"dfed73d646d7159d3ee4f9ce95ea628fdd33bf8bf1bb02a83d88302d088f4d97","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif":"fb0937564c08f4e1c22ebbde426a0eff6a1d388434c30148bc7e5582dc378caa","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif":"5539cd575256772ba31d6e87cb0136d5f465f84b041a4677b1023cfd6bee9956","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif":"d41ead1d69d33d0cf5f6fe575beb5f60d9565300c535f9042113dd8a748c1d31","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif":"f205cf2c05265b84e45ceb723e9a3707fd8749130166d4797e64c8c62b497f8c","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif":"ad2244cb7b2ac487a5104d6e5a07270f9ceb2550e4d56d3662fcc1868910ced5","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif":"7ef9468effdc970e4e6e8cc7533d66dc967686e357dda3dda186c021f9e6156b","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif":"3dd34d854ff83b6e27a2bf98301380a6cac272084ed863735285ab5dc8acda00","link-u-avif-sample-images/plum-blossom.svg":"be1f03dd05f63292c85a96b1c48fb06727283610cc69b1e116d547bab27b171d","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-10bpc.avif":"5842951d81118d256962384e08a986816e8ade6b05530269f0208c6b69cedb3b","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-12bpc.avif":"1f0c9f36d69b9aa13eff3897ada3e78b81099c613b329a402c27e09453e7e261","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-8bpc.avif":"3e6f2f4016e66e3c94707eaa8373e6f582321e005964cd35b64bc183e1bf10ea","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-lossy.avif":"79483242f2dca12c4ec18bd33ff8099216b3094fb55a26a909f046b2f9b4ce58","link-u-avif-sample-images/red-at-12-oclock-with-color-profile.jpg":"d56f809ea5eda74578af57e2f80b41856a1fe2ff436c741aa58757387af998bd","link-u-avif-sample-images/red-at-12-oclock-with-color-profile.png":"4eab95e358eb48e052c7b8c94d30a8c6cb1c9c3c2dfd9845240281dd5dd7b800","link-u-avif-sample-images/scripts/compare.sh":"0562689bcd40e9fc1322bf037d6f999aa4406a2229f19e74b96cc450e370e429","link-u-avif-sample-images/star-10bpc-with-alpha.avifs":"5643ac1f235ae6599186dd66c66507db6fa46a17b2b18e82ea9344870eb98a9b","link-u-avif-sample-images/star-10bpc.avifs":"c61d899a59dbd8c7b2f7bcfca9069a0e13ff1606899af227938a28502e6cbf88","link-u-avif-sample-images/star-12bpc-with-alpha.avifs":"88a350c3550ce36c1777fe7eb1e906c6829d3ed8b241aa1e0e46f1a4e2567c4b","link-u-avif-sample-images/star-12bpc.avifs":"c1a59db6f180208a3177d77c7f9ab08290e903c7bdaf929331b807a510f8c619","link-u-avif-sample-images/star-8bpc-with-alpha.avifs":"13a12908cb162a855cccc9221a5f9f736e8ea07902ffbdcf007f8fde5ed255f2","link-u-avif-sample-images/star-8bpc.avifs":"ae35b161de67a5afeb195ee401f369c34990f0ff8662f70ab4065bc6931f0a66","link-u-avif-sample-images/star.gif":"389cdd02efbdce4f0205cae6e91c1f64e34fa0ca1fe02351da1b37e16cbb642a","link-u-avif-sample-images/star.input.txt":"970163b942843618616f42233abe91d40fb68f6f5451860db259551711867b55","link-u-avif-sample-images/star.png":"18569167cf7ebd265ab6973d071d259aacfbb46c0408b7d4874c8cc9df9bb1ad","link-u-avif-sample-images/star.svg":"13089d0986b31b87919029fa69f2b68981af4023306bf0f79922f6772396008a","link-u-avif-sample-images/star180.png":"21bc11be2b51334fe4589634507612e7edce96d36e6a99219d029e440164e8b8","link-u-avif-sample-images/star270.png":"5c93f538dcdc70840b9925b4089083acc9c25e95265b3f3dea18d695451b441e","link-u-avif-sample-images/star90.png":"2defc5d21e70447653fec5dc14a697d9dd555d7a0c14e79cb2d9f80796a51a6d","src/boxes.rs":"270a3e3bf90279bfc83f95acadaba9611c25243280bca71dfa9c044d5441cf15","src/lib.rs":"73114a5c28472e77082ad259113ffafb418ed602c1741f26da3e10278b0bf93e","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"75fe5467109242b2cc7991f8228e2e2ad1de5be2f29272a4a7f08c4e21ab5fa4","src/unstable.rs":"c2cef9a3b2b08a4da66fa0305fce7a117bd99c9b8d57b0a044e1d99dbda6faf5","tests/1x1-black-alpha-50pct-premultiplied.avif":"31a8c235bf2cf601a593a7bc33f7f2779f2d5b2e0cd145897b931fce94b0c0b8","tests/a1lx.avif":"81a784c568e7619bd47c4e7153181e9a86c8a03221097aa63979f97affd7efbb","tests/a1op.avif":"184e50efd3ad226800c610da7bc470d29b548d9fa942fd1fd1848ed02e2e5f0a","tests/alpha_video_avif_major_avis_compatible.avif":"81771981248c4e0d708f0828eadb20e9e37e7c21280efe5726666958f899c237","tests/alpha_video_fixed.avif":"67051d1a4ccf9f3e38d4514d8a6b3a2e07f1beb979369cabdc60881a698a36ac","tests/alpha_video_no_avis.avif":"a95f0e7c818bc5bf646143cf43474b70722e17669d4f2a32874c125936207d6a","tests/amr_nb_1f.3gp":"d1423e3414ad06b69f8b58d5c916ec353ba2d0402d99dec9f1c88acc33b6a127","tests/amr_wb_1f.3gp":"be635b24097e8757b0c04d70ab28e00417ca113e86108b6c269b79b64b89bcd5","tests/av1C-missing-essential.avif":"a1501254c4071847b2269fe40b81409c389ff14e91cf7c0005a47e6ea97a6803","tests/bad-ipma-flags.avif":"ecde7997b97db1910b9dcc7ca8e3c8957da0e83681ea9008c66dc9f12b78ad19","tests/bad-ipma-version.avif":"7f9a1a0b4ebbf8d800d22eaae5ff78970cc6b811317db6c1467c6883952b7c9b","tests/bbb_sunflower_QCIF_30fps_h263_noaudio_1f.3gp":"03e5b1264d0a188d77b9e676ba3ce23a801b17aaa11c0343dfd851d6ea4e3a40","tests/clap-basic-1_3x3-to-1x1.avif":"83af9c8196fa93b2475163585a23d0eb5a8f8015d0db8da7a5d6de61adfb1876","tests/clap-missing-essential.avif":"4d61aacd2327661a456abc76d3d490e5ddd2b6f8cbfa52922a6c541c9d983193","tests/clusterfuzz-testcase-minimized-mp4-6093954524250112":"af7044a470732d4e7e34ac7ab5ff038c58b66f09702cbcd774931d7766bbfd35","tests/corrupt/a1lx-marked-essential.avif":"0d481240222450827ea335ae9a1a300777a0db4f9b0f4c17ed77c758c5133fa3","tests/corrupt/a1op-missing-essential.avif":"33c24d54f43f1a7be7a8334718881c8a0de24730c997c7842b9d7140e75017ea","tests/corrupt/alpha_video_moov_is_moop.avif":"89e0091edd6efc2c5b163525553c5abc56263fe1b3b885184bb07b9ea4bf346d","tests/corrupt/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/corrupt/bug-1661347.avif":"31c26561e1d9eafb60f7c5968b82a0859d203d73f17f26b29276256acee12966","tests/corrupt/clusterfuzz-testcase-minimized-avif-4914209301856256.avif":"34a142c7916e314881f3fb6394add1c543fac0e5b45109e3a425eeb4c68998d0","tests/corrupt/hdlr-not-first.avif":"2c29308af077209b9c984921b7e36f8fb7ca7cf379cf8eba4c7a91f65bc7a304","tests/corrupt/hdlr-not-pict.avif":"9fe37619606645a95725300a9e34fada9190d1e0b3919881db84353941ca9291","tests/corrupt/imir-before-clap.avif":"22d6b5dacf0ef0be59053beba7564b08037fed859ada2885e3476e0ff0d19c95","tests/corrupt/invalid-avif-colr-multiple-nclx.avif":"7990a995855120dc4f724a6098816595becc35077fcd9e0de8c68300b49c4f1f","tests/corrupt/invalid-avif-colr-multiple-prof.avif":"b077a6b58e3a13ad743ee3f19fbae53b521eab8727606e0dba9bf06384f3121c","tests/corrupt/invalid-avif-colr-multiple-rICC.avif":"88b24d4d588744b9f2cdc03944f28283e9315eb3de7d7d57773a0541137f6529","tests/corrupt/invalid-avif-colr-multiple.zip":"9abddcbc47fde6da20263a29b770c6a9e76c8ab8dc785ef8512f35d9cb3206ed","tests/corrupt/ipma-duplicate-item_id.avif":"ca8c5275b0b8b79c1068489a52d0a5c8f0b4453463971e72b694189f11c10745","tests/corrupt/ipma-duplicate-version-and-flags.avif":"cf8e15ec4b210235f3d68332a1adeb64e35c41b8d8e1e7586ae38b6d9cd8926c","tests/corrupt/ipma-invalid-property-index.avif":"2480e773fa716d22883032d05fd4cf2c6b00fba8796cf4ff286a5d1ba26adff6","tests/corrupt/lsel-missing-essential.avif":"43c3b1e4c4acecd7559a9a7197a7befd43c71705748f0f8c063bca3be1c6d074","tests/corrupt/no-alpha-av1C.avif":"ad3d34d6331db7d9bea0c5f37efb88923520e33e08e7c636a5df435a4575eae7","tests/corrupt/no-av1C.avif":"eeb4fc50930c91465999f787c4a2a3b12de20556da0857be72da5a1a9eaa3f01","tests/corrupt/no-ftyp.avif":"74b431f32b2e2761e77df7fdb260f623b4e8f7e3f4c8af8a42d6826911706d7b","tests/corrupt/no-hdlr.avif":"91a1eb70c7b6adf2104e471d7deeeb98084a591d64ce09ba106c27edfbc3a409","tests/corrupt/no-ispe.avif":"4b6edfd8c9b40c25dc40305a6057e32b5e65f40da4a9d810c58dbff53254113f","tests/corrupt/no-pitm.avif":"7960eeb9e6e5140fbe5eb6d281e6974efd6c3c0147562f3dcf06f6b009dc540a","tests/corrupt/no-pixi-for-alpha.avif":"f8adc3573c79ee25bf6d4dd2693c61661469b28f86a5c7b1d9e41b0e8d2d53bb","tests/corrupt/no-pixi.avif":"4b1776def440dc8b913c170e4479772ee6bbb299b8679f7c564704bd03c9597e","tests/hdlr-nonzero-reserved.avif":"b872dcd7b4f49c6808d6da109cf4fedc26a237c42e8529c5aa8f7130abaf40a9","tests/imir-missing-essential.avif":"b1226e4b1358528befbd3f1126b5caf0c5051b4354777b87e71f6001f3829f87","tests/invalid-avif-hdlr-name-multiple-nul.avif":"0d3e4a6ce42154ee288c18339c2b59ff2104fd890cd2d616e5dbf26375a90e98","tests/irot-missing-essential.avif":"b7da1fc1d1b45bb1b7ca3494476e052f711d794a6d010df6870872ed8b9da10e","tests/lsel.avif":"ef8ba6827709f48cd45f749efb580129162d9599ea98f3363d2140957502d806","tests/multiple-extents.avif":"b5549ac68793e155a726d754e565cea0da03fa17833d3545f45c79e13f4c9360","tests/no-mif1.avif":"1442aa6ffaeb9512724287768bfd1850d3aa29a651ef05abb33e5dec2b3ee5c2","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"8918d5190a36c697445aa4b140a31cd3032582f1e504b4c2527f75a2155f80ae","tests/valid-alpha.avif":"9d417a35b9b62ad3ff66ffbc55f16552aacf821a092aa5ef4adff7e746bd4c2f","tests/valid-avif-colr-nclx-and-prof-and-rICC.avif":"ab6f5e786d26f8bcade5993f8b9cca3cd004a3d7fcec76e829f5d0f98cb18e7b","tests/valid-avif-colr-nclx-and-prof.avif":"0e982818de61869fcb85a2a4c2b7b8aeecb3053cbfdc6276987f91204998eefb","tests/valid-avif-colr-nclx-and-rICC.avif":"8530ef1305ff956a0c2912d0b3d1e0fc3a68cf3103e70b04cc2574530389b030","tests/valid-avif-colr-nclx.avif":"345ab58b7b1cb48aba2e21eb8dc5ab0a751a78a752ce1896c59b4bf361992f38","tests/valid-avif-colr-prof-and-rICC.avif":"1f0f085141106885bda78b0879c768818420d8196b39440a36578456a7d50a6c","tests/valid-avif-colr-prof.avif":"5d7aaefb5204ebe1cc296456866b8e46e023748b921a38ee56fd6c776a9733ff","tests/valid-avif-colr-rICC.avif":"e1c7b49bfad5904b484bd5118e6b33b78e2dc708a31a10fcbb0e4a373ed8dbb7","tests/valid.avif":"f0b33e09bf01232e0877df325f47986c0bee7764f2a81c9c908ae109e7dc63c4"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"44d439e9f1564a6edd3aefa181fd218701fbf42ae12afe8428320c1700260923","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"86cb40854b93f988e3a63ce6fe39d2ce95367f8ca301a5ba50676ff98a0ad791","benches/avif_benchmark.rs":"17105ee0ec4ff0e3eec90699252939101edd5323514ceb404f367e67ef16cf95","link-u-avif-sample-images/.github/workflows/encode-and-decode-daily.yml":"ddf6cc5ceb39796f29a4f1a5e8ed0f346f860501a75585d65ff1e55dadb49eb3","link-u-avif-sample-images/.gitignore":"49a848a0328071e168b24fec43f09ae21663ad78d9be4d54eba9e5c53b3824d3","link-u-avif-sample-images/LICENSE.txt":"670e1c60f680d6bdbf512e35ae3034650328102eb37f67c666f86206ab93b0e8","link-u-avif-sample-images/Makefile":"ad8a0c46fd5ce4d4d8bc83370834974a7b10da2e1f57bed3af00c101da90cda2","link-u-avif-sample-images/README.md":"83128989413b87012a2602ab04bec62fd450c8039f39d650d1a6517bb9778a5e","link-u-avif-sample-images/fox.jpg":"927997a90ae88ead007283bf9c1392159d0acd2e9890522146211fda2112a2d9","link-u-avif-sample-images/fox.odd-height.png":"6136247772bd1c0edd50426bca4f3485473ac25a784e5ec8777f7491598e96db","link-u-avif-sample-images/fox.odd-width.odd-height.png":"6f91dc21c137f318d0443ce28bbf3f74d5502180c254327b46e41040a33f1363","link-u-avif-sample-images/fox.odd-width.png":"a8b2328c8700c16280c5ab40a34147edac598d4d48ca101bef649e468ae1492e","link-u-avif-sample-images/fox.png":"c45bfb5780843c70a37426340020e3e7ff41d7cf1df9fec614a5cf429d078573","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.avif":"811af5e96631309030a14cbc30c3bacfaa667f2e36e16a4f30434b8f5a23310c","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.avif":"e35713343e9ee04c51ab9cfdc99a0c7d126a1917cb83f5b9a23c71ed59269be2","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.odd-height.avif":"485623f7838d8f442c47348c6492765e6aafbc3d5ccd8e90efc9c812ff15e265","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.odd-width.avif":"8e75b9a8975267359d827e4cbc6877b1674aa31b87f88f222dde03263f9254df","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif":"1fff5915a332d6aaa85d668f3f338bda6fad9c6ec1f380f2c46737d536cea5de","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.odd-height.avif":"cca9785f14c74d865453518c0962dabd6d1b92d2c6c5f5ac67efdbf5606acb83","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.odd-width.avif":"de3399d8b56431f0ed34e2f14200f31dd54544fddbb12f39b4d55449d5660c56","link-u-avif-sample-images/fox.profile0.10bpc.yuv420.odd-width.odd-height.avif":"07507744cb76b74a3586b93fc3b273a98f998d75f7687db3e9cb3725d7b1fb9d","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.avif":"cb884c82ac7b6d4fa03b1f687e9e20abc346107095473e9c1d422aaf0de14eaf","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.avif":"15d84077066c47fdbe2a7b8ed583a17017d09a033144ac1b31486d6c8f6f5c82","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.odd-height.avif":"365439d2ee2fe5229e066362c03a73a182c7f6626772ecf5345b22752d32e681","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.odd-width.avif":"c623b9943123d6c47d3300444f7255cbdfebfe2b47a670287f2baeb717fac42b","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif":"dd069f3c3c4f7589f5f7ef1d7b6a91b8cb975d32663a4a92b6d75219edd72954","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.odd-height.avif":"75628450288ace3386651725411c8f0ffff7eb95f82c5307b0faa3350f09f50e","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.odd-width.avif":"f91b6f455412adabc5094011362eaaa1f6a9d5740de0b8a1be42a96c16e7617f","link-u-avif-sample-images/fox.profile0.8bpc.yuv420.odd-width.odd-height.avif":"bb8695cacacaf8f2e13a739de75e5e8a9d970d68c3acdfb7d82171a9bac2f01e","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.avif":"a10de8204aee73ba1786daca6390546bd7aa6b069aaa644012219a1c11246a43","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.odd-height.avif":"734a5badc59a8bed19e8eb476911048ddb011ca7c9eac31b7a7ed20e0135ac2c","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.odd-width.avif":"68d15d76d95f268e810dfd87bbf96d8c3197580afce2d30b50bb1f07865077f3","link-u-avif-sample-images/fox.profile1.10bpc.yuv444.odd-width.odd-height.avif":"01e469b33bacb7e07e15e23b2997907bbcf02d8fcc99885a027494d31c45547c","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.avif":"a0cdc981a6b056c8af2d177a1438c332d630040dacbfd1c89bb5e3e381ba5822","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.odd-height.avif":"77e0510def73213c00ebcf051cf45fa63cf27d7c69340cc145ab6d44ec77bb07","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.odd-width.avif":"12787042364bd13be01830f988cb714220bde340a3329baa808df27a269b83f8","link-u-avif-sample-images/fox.profile1.8bpc.yuv444.odd-width.odd-height.avif":"fad3b6dd9cb99e6925858f69aafae3f68c861845f2c3d4a6d1c51c6161490134","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.avif":"e34f3bab5df802be2d422c685824464eb5f7e182b235ca99bde11c4c34ff3ac2","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.avif":"05804752621e2fd7a9d85b01e2995a50e3efd30693efd934152560622d66e841","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.odd-height.avif":"ef041f2efa0424d3a6dcfc5f0c3f619aea0e197aaeb5a050a2d877a457513921","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.odd-width.avif":"b711b321b8a4d3a41e08f80a17c2203b839458cb6346aff6fff3f8d7699032e6","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif":"e3f40aad0ddd6c04ffacf4a754a0525986c89d519119d37655282551e3ea3a59","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.odd-height.avif":"4ef74c37712b41d6e5269d939f9d52031bc10746f7c8c029db618c5935aff9a6","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.odd-width.avif":"4cf6c849f4a48a639217ad9a1e0d027f4fc804d524c03e6707ec9714a252532f","link-u-avif-sample-images/fox.profile2.10bpc.yuv422.odd-width.odd-height.avif":"3d3978e8e8d07270f82a877d3535f9483b88fce93a1c4accb658b494452b1d36","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.avif":"626d73272e59722084c528b27b72a0920bec462a10749b3e87036e42bf8a24e5","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.avif":"caf50c467242b3fa0b895a2af131fa0d03dd7b34989f2b1a51d25b2246c98fab","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.odd-height.avif":"1e88b92df592c02af53ff5258fa898ac8fe1d71954e9a440500ef7879b8a1c46","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.odd-width.avif":"466efdd269f3be3b1c88afc093c839e50ba5eaf6bd0c2425e157000d02a3c21a","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif":"36014509d0688cb307e0ffcdb5b4c16ff6e6c79772c7fbbeea33b4d483a1566f","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.odd-height.avif":"d1786723a5d6ea1e1764b0045dc3f669fe3905ffc2913011a2b1b424d2393397","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.odd-width.avif":"a2d9178cc5622e28472a735650d9c4deaec6d27d69830110911f4158f9d4a04e","link-u-avif-sample-images/fox.profile2.12bpc.yuv420.odd-width.odd-height.avif":"89a9fc7598d72251b903e0c7088ab3e7a7f316b5e02b85f8c69e51f8eb0c7e69","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.avif":"51476b8471e1c0a5ebbd1e7545709495bef619cc96c02d277aad32b1deff8ea9","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.avif":"caf50c467242b3fa0b895a2af131fa0d03dd7b34989f2b1a51d25b2246c98fab","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.odd-height.avif":"1e88b92df592c02af53ff5258fa898ac8fe1d71954e9a440500ef7879b8a1c46","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.odd-width.avif":"466efdd269f3be3b1c88afc093c839e50ba5eaf6bd0c2425e157000d02a3c21a","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif":"36014509d0688cb307e0ffcdb5b4c16ff6e6c79772c7fbbeea33b4d483a1566f","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.odd-height.avif":"4808960cdcd1207b29eb6ef5b4db81ae5e63c5d40ef92f7a1e8f4430e765bde4","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.odd-width.avif":"71f3c73737bc04c23d93ea2c61a8a07408f604192fe53fe12c65050927dacb4e","link-u-avif-sample-images/fox.profile2.12bpc.yuv422.odd-width.odd-height.avif":"8f9649384fa09c70af0c2e9e0d94ecd17492c702e015d9d6290d3aefc57c548c","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.avif":"ed96eca6ed79863eaf91e4d666e4e220b5fa4e5a6cb1696477ba901ac12f5dde","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.avif":"caf50c467242b3fa0b895a2af131fa0d03dd7b34989f2b1a51d25b2246c98fab","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.odd-height.avif":"1e88b92df592c02af53ff5258fa898ac8fe1d71954e9a440500ef7879b8a1c46","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.odd-width.avif":"466efdd269f3be3b1c88afc093c839e50ba5eaf6bd0c2425e157000d02a3c21a","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif":"36014509d0688cb307e0ffcdb5b4c16ff6e6c79772c7fbbeea33b4d483a1566f","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.odd-height.avif":"c43b4c607e301e34eb953770133d89d15e77d63be8d6421a80d6212fbbbf3453","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.odd-width.avif":"0e6218ce250ee7f84a621f3af73286fd4dabea19e9898d3575c20c5955aa427d","link-u-avif-sample-images/fox.profile2.12bpc.yuv444.odd-width.odd-height.avif":"9f19846d884ac7d161ac2ca15811bb22ff7f3847bc1ad5d7713971ea024631aa","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.avif":"2cb363d30f83bff58ee049874b1808b37cb1d35342edf16b3ce25cb243c9ea55","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.avif":"8217b88f350c5d3812d7f863fe9d710c4c1b846b0be8df29ce6b3eb30d2b8d8f","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.odd-height.avif":"51eccd8c1368ddec9bc1f3a7631dadb00682e985fbfea66c0a2f533f6a73b67e","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.odd-width.avif":"83fe4593ab839cf296a2ccb8a146daf826d1d602f4f239cb63ee020f2cc326f6","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif":"4e63b84a980a81adde586314a94d8f834ec763749d8797c286471415b6b75647","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.odd-height.avif":"efc70882aacbb533c0e833a4401949d152dceb364846442cdccca5048ad17a60","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.odd-width.avif":"c07575c88ef400c1725c9260a19439e0e784da41c7db3867059019ddbdb3bebe","link-u-avif-sample-images/fox.profile2.8bpc.yuv422.odd-width.odd-height.avif":"86aee64fd7b11b9834537ea14b2eff234c062c98d32fab51ff14aba262d5b106","link-u-avif-sample-images/hato.16bpc.png":"53b550c587cd1d19a1997184e47f4a3ff2a05cedf7cb4e42a9466a6d6cb60d8d","link-u-avif-sample-images/hato.jpg":"6d4804e5e4adf36a6b138544c81b743ed7abdd9a495a43e883ec77689ca28943","link-u-avif-sample-images/hato.png":"313880f4cc51160fec522d78f1fb7f06df70fe1929a731fc86c68ecefd312277","link-u-avif-sample-images/hato.profile0.10bpc.yuv420.avif":"1e84598c94bc795c55a551bdf6f283b4eed4997bda15e5c4bb2e29d0dc70897b","link-u-avif-sample-images/hato.profile0.10bpc.yuv420.monochrome.avif":"25c19a187d10eac963bb51b3fae1ffe50f3ccbc7ad02e51948dc7467b397ce61","link-u-avif-sample-images/hato.profile0.8bpc.yuv420.avif":"07cd454de19dd638354f75d9e97aab08bc8a04dd45c4f7531cb62a1a5656c8c9","link-u-avif-sample-images/hato.profile0.8bpc.yuv420.monochrome.avif":"120a3f26f3d6cde80869fb52bdb8fdd55b443882c98070ea938575e4790982ff","link-u-avif-sample-images/hato.profile2.10bpc.yuv422.avif":"d54251d4bc023f2e53624a46cb18e56cbc45768bd1bd50394de191c2a42106e8","link-u-avif-sample-images/hato.profile2.10bpc.yuv422.monochrome.avif":"ed33dfdb5e663b3394298b6921f9b19b129e14788dead776430eee2f14780a73","link-u-avif-sample-images/hato.profile2.12bpc.yuv422.avif":"ad361ac7d94fbc6af7ef30cbd3601ff366bc360c304480387a58a4c6fecee9b6","link-u-avif-sample-images/hato.profile2.12bpc.yuv422.monochrome.avif":"e28b4cacda95750e465e205fbfcba6a6af1d8418dac649838730c555ff7d828f","link-u-avif-sample-images/hato.profile2.8bpc.yuv422.avif":"69c353c482c2eb3d3671bb55f7ccfc932e4d781c714a72116e9138ffc6f6c720","link-u-avif-sample-images/hato.profile2.8bpc.yuv422.monochrome.avif":"e7d6f7d42a8519e1482f225fe447b5642d19a54ee830529223eac114a0dec189","link-u-avif-sample-images/images.html":"d2a5157987ebc8b1264da41e079fa370602bf322bd73fbede534f96ba22f37ff","link-u-avif-sample-images/kimono.avif":"63412e0f67f37c8b6fcf0e8269a2afae0a017fa6a3a99d37d055c590b0be52d3","link-u-avif-sample-images/kimono.crop.avif":"f175dcd9c64813b759da185fa67076fb772b76059845b2aad3ddcfab257f75ad","link-u-avif-sample-images/kimono.crop.png":"0d5605bae0ec9d39aad9dc8e1a371d0327c6a224643983e3ee1f4d44cb00f19d","link-u-avif-sample-images/kimono.jpg":"a6ad58e3cea437ee0c841115ba67ae7354de7af734de50de9d0853dd4e571577","link-u-avif-sample-images/kimono.mirror-horizontal.avif":"2bbc004d91145488610158a5acdb4d706495a2b15511db20ff57bb9efd80885c","link-u-avif-sample-images/kimono.mirror-horizontal.png":"9af9e839fe6bf6342831970c20291f619570d2fc687951ae00cd81ea766f53fe","link-u-avif-sample-images/kimono.mirror-vertical.avif":"f10eb04791fcca3409868b367128649f32e6b6fffcf02484cdefa57909f6bb74","link-u-avif-sample-images/kimono.mirror-vertical.png":"4ed003c5868fd2e78c7b2dcbd54a67a0e7593dabb3ac82b1c9e5e2dbdf09b8ec","link-u-avif-sample-images/kimono.mirror-vertical.rotate270.avif":"33c36ec2274b00ac6f81c9f61e55c20cbfce1649ad27520afe635310f516ead1","link-u-avif-sample-images/kimono.mirror-vertical.rotate270.crop.avif":"90ca48f657455b8f8e4a4e1769a05af90a3e34dca11a8b3c32552daf378ee956","link-u-avif-sample-images/kimono.mirror-vertical.rotate270.png":"74b9b7ffa8955761f747a0e6e81d5b7ecb5e325383546110e1b6aa9986728035","link-u-avif-sample-images/kimono.png":"84fd6cfb97a27739608e21779f874b4ae7e80342b2588e8b0b092dee2d57c881","link-u-avif-sample-images/kimono.rotate270.avif":"79a99a0415276cc11f2e871d070a9df84df3385888a2f2fa3534320f6bed98ed","link-u-avif-sample-images/kimono.rotate270.png":"1918a47c02b378945a705301abd4250ddc65bb95afce9424572ffd0fdd1f45ef","link-u-avif-sample-images/kimono.rotate90.avif":"bd1157d8c840713c82b907b9d3ae80bc3817849e11c323d875f8016e035bd3cc","link-u-avif-sample-images/kimono.rotate90.png":"1a73c61692abe96d0a7a9accdb36a83d51bceac79bbb83a00571570f494cca49","link-u-avif-sample-images/plum-blossom-large.png":"af6ea005b726ca39f342e946aa53bed88e5a140413ce896d166bb35ab0aa3b4f","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif":"cf8e15ec4b210235f3d68332a1adeb64e35c41b8d8e1e7586ae38b6d9cd8926c","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif":"b413440309d5669a7aefa06f291f72de0d0c09972e3da9a385e6016d6a1c5562","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif":"64f6f2b1fda594af5c9e2d6e4bc752b55e8121000cdcedc0066018e53f76de40","link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif":"2b175a600aed64c1c1de4b2d661fb405437b1ff000b964d4be6ac437ce73136f","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif":"21ebb3732186bf7c6c13cf7197155b64201e674b9c79cf613b6e5718bde14c2a","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif":"65917797e511c9033b3e225eb5d84f3c0440b7a496d4b8ab5674e123ad68aab7","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif":"f4809df9188fa46ed100f63c78c4cf42559d90a98351a8f69e177385920672b4","link-u-avif-sample-images/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif":"dffc213dc36f0b5ff3d86254f5185c2d1fb03380918a8fa39d186fb59cbba7cc","link-u-avif-sample-images/plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif":"0a615cfb673ab45e37da3582c17dd36f86d5da3d81246a32951d1db4ed90149d","link-u-avif-sample-images/plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif":"d1cc6a0db116a68e229676b289e8ced84d42a9f0e8d3ccd760fc92dbeb932547","link-u-avif-sample-images/plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif":"8626cf0b2c60fee51cf1df7fe4d8a18081b72e3604f7d3ff14cc5a35581927d9","link-u-avif-sample-images/plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif":"56bf18e4bcbfbea460c306ab900fc506169854d2b91690e1a48156a86fff3264","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif":"b56f3c33797e4c5bb80418ae25f6f2c6fc88ddc1f6965d82abc44059f052f36c","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif":"c3c6db4ce801c68e2afd7bfb72abacc13287cc2e247917a817ff5632bd4b18fb","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif":"095f57fff1dc037a6414c60263415dcfa86b10d81f58e8e4c3aef17cffae0e5f","link-u-avif-sample-images/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif":"ba3035a69296d12f47d1c450f2de8cc0c9059ebbf27bb8b0996ff6d1ab1132a1","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif":"a9551e1963049b874216b40aaf9be45bc44dc11887770712b77240862c6c08a9","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif":"a8a0ba881cd0aef45a5874f412e97812ca457eaf12e56b34bac2ba051e142828","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif":"6891b5bdbed7f541c673c66cec4584b191bb737a49b37cca16ae069830890b42","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif":"67e66826637e349e1c3c46316c7048d152aed8453d8cdd00c6b786f87fe176d8","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif":"a466503110f60dcadaafe78c2cb0a8ca58334c22868efe428c7ac12b69407c95","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif":"a8a0ba881cd0aef45a5874f412e97812ca457eaf12e56b34bac2ba051e142828","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif":"061b4c70707e7fc8866580656cca7ca2da2263645829a564dbf8f205d639f058","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif":"67e66826637e349e1c3c46316c7048d152aed8453d8cdd00c6b786f87fe176d8","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif":"4a03c8bcfcaadccdeb07432ed80680b06aba5ae5e616fc370b376acb478f6cd1","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif":"a8a0ba881cd0aef45a5874f412e97812ca457eaf12e56b34bac2ba051e142828","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif":"376625ce4e7ec3b57344a9f2185a34975fe380774c9f8e0dd4ef61c46da94fca","link-u-avif-sample-images/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif":"67e66826637e349e1c3c46316c7048d152aed8453d8cdd00c6b786f87fe176d8","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif":"1e17b7dd8e351cb667bc6ec0b81fdebca9fd30ad5e588b3eac57bf9f90a9b58b","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif":"f77588d2ff39e4461869a95ca236efdf4a3fdc17b8a6e3907e63b417e56c81b5","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif":"f2eabd3fc2db07b361d55b5af63023d28b5bdd0047a665e9d0685651ce9db94b","link-u-avif-sample-images/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif":"dd88c377b253d689bfd4600d7c3007448df0ed92f679b661d5d51e051a6916d8","link-u-avif-sample-images/plum-blossom-small.png":"c859fd97b647e494461f65835b9c1c3476807aee77076599adf18a832b3617a4","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif":"fe3379620f983e5da4210b0f7c5d164e86208b34106d6b11d56e2b52beee5dfe","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif":"9e6234686053dba2e44bb32192c641074095a61e45aa1bede85bb83751e6e157","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif":"60ffa59dd007aea3bb596cfb03853b3dad490b1ffd10471ad4fe1901ec819907","link-u-avif-sample-images/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif":"58abfa027525aca7339a705f311bc30b000aef9822c7c50b232894ece1ba9cb1","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif":"541ca66a11b1430d11f77b74a13f859239a3bd9f44976b8dfe163c5d7595a69f","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif":"6d7852c63c27a77bef94443e178ecf6b6a3da8cc846f9f0c1adc17f7fc35e1f3","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif":"3712216ffc7edb95a976b68469ead533fda6fe9f3d2e8cb09cbdb0d01d9c094b","link-u-avif-sample-images/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif":"59672af536b169ebf7e48129167dc91cb253925517c37db28b64539f7afba5d3","link-u-avif-sample-images/plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif":"561d5158425ad39425916a3be048b0202e82efef44cf1a9f711db57192d2ff01","link-u-avif-sample-images/plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif":"88336f29457c1dc4ae0b754ef14b791de4d8c337f2b44d7960aafcca08a5586e","link-u-avif-sample-images/plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif":"245a3dad6371dc702f29eb7e9735f843b63c525da871859728bedbe5bb274985","link-u-avif-sample-images/plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif":"490c216b5850c670f6088ee72c7fd906102b2dd0c8432c01a517b3328db27c75","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif":"0d0bbbcb0c9ade1c827317a6409ce6ba25027b36da1b6752379a5f5d4c8af056","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif":"418a9d4b7dcbc1f67fc4b95ccb2e7946c446fddd35a79f0d587b3f2165cb3f14","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif":"a41dcfabb3795ed93a05881a91bf4d1c5d1b9b0e5d0db728f12684b12613e0c9","link-u-avif-sample-images/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif":"4b6a18f4f608d1b00598e67c1c91a4e8f4943ae5acf0166ae0121cc21f3b7437","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif":"5e6b83adee3aeac4bba3f38e854e2ed7585aa1557a74b5fa66596098c53e26f2","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif":"fb0937564c08f4e1c22ebbde426a0eff6a1d388434c30148bc7e5582dc378caa","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif":"f42e780bff644167e27525fee65b23e70814f7665ea19b6d693eb127c5eeebd8","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif":"d41ead1d69d33d0cf5f6fe575beb5f60d9565300c535f9042113dd8a748c1d31","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif":"c6ee9234ee7783d0203f9512e3cc8fe76a694675bcf03c320ff8bab4684bd4e9","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif":"fb0937564c08f4e1c22ebbde426a0eff6a1d388434c30148bc7e5582dc378caa","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif":"21e1e51fc6da66e090e12e1df5aeabf1f478df64bcb8151caaa687ad262bdd9d","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif":"d41ead1d69d33d0cf5f6fe575beb5f60d9565300c535f9042113dd8a748c1d31","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif":"dfed73d646d7159d3ee4f9ce95ea628fdd33bf8bf1bb02a83d88302d088f4d97","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif":"fb0937564c08f4e1c22ebbde426a0eff6a1d388434c30148bc7e5582dc378caa","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif":"5539cd575256772ba31d6e87cb0136d5f465f84b041a4677b1023cfd6bee9956","link-u-avif-sample-images/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif":"d41ead1d69d33d0cf5f6fe575beb5f60d9565300c535f9042113dd8a748c1d31","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif":"f205cf2c05265b84e45ceb723e9a3707fd8749130166d4797e64c8c62b497f8c","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif":"ad2244cb7b2ac487a5104d6e5a07270f9ceb2550e4d56d3662fcc1868910ced5","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif":"7ef9468effdc970e4e6e8cc7533d66dc967686e357dda3dda186c021f9e6156b","link-u-avif-sample-images/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif":"3dd34d854ff83b6e27a2bf98301380a6cac272084ed863735285ab5dc8acda00","link-u-avif-sample-images/plum-blossom.svg":"ea0c6cf04c0296a4ffa77f503e382a408e6764b9f384e5a319681e46b5733edc","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-10bpc.avif":"5842951d81118d256962384e08a986816e8ade6b05530269f0208c6b69cedb3b","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-12bpc.avif":"1f0c9f36d69b9aa13eff3897ada3e78b81099c613b329a402c27e09453e7e261","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-8bpc.avif":"3e6f2f4016e66e3c94707eaa8373e6f582321e005964cd35b64bc183e1bf10ea","link-u-avif-sample-images/red-at-12-oclock-with-color-profile-lossy.avif":"79483242f2dca12c4ec18bd33ff8099216b3094fb55a26a909f046b2f9b4ce58","link-u-avif-sample-images/red-at-12-oclock-with-color-profile.jpg":"d56f809ea5eda74578af57e2f80b41856a1fe2ff436c741aa58757387af998bd","link-u-avif-sample-images/red-at-12-oclock-with-color-profile.png":"4eab95e358eb48e052c7b8c94d30a8c6cb1c9c3c2dfd9845240281dd5dd7b800","link-u-avif-sample-images/scripts/compare.sh":"9268318aa2fc3cdc153bab6d8cdb9adc41e07497a7a4ca14b58afbd166b9dbae","link-u-avif-sample-images/star-10bpc-with-alpha.avifs":"5643ac1f235ae6599186dd66c66507db6fa46a17b2b18e82ea9344870eb98a9b","link-u-avif-sample-images/star-10bpc.avifs":"c61d899a59dbd8c7b2f7bcfca9069a0e13ff1606899af227938a28502e6cbf88","link-u-avif-sample-images/star-12bpc-with-alpha.avifs":"88a350c3550ce36c1777fe7eb1e906c6829d3ed8b241aa1e0e46f1a4e2567c4b","link-u-avif-sample-images/star-12bpc.avifs":"c1a59db6f180208a3177d77c7f9ab08290e903c7bdaf929331b807a510f8c619","link-u-avif-sample-images/star-8bpc-with-alpha.avifs":"13a12908cb162a855cccc9221a5f9f736e8ea07902ffbdcf007f8fde5ed255f2","link-u-avif-sample-images/star-8bpc.avifs":"ae35b161de67a5afeb195ee401f369c34990f0ff8662f70ab4065bc6931f0a66","link-u-avif-sample-images/star.gif":"389cdd02efbdce4f0205cae6e91c1f64e34fa0ca1fe02351da1b37e16cbb642a","link-u-avif-sample-images/star.input.txt":"8d8e1500645970bbc48d7f886d76faf0d573ae598dfb1ca8c1d5245a2318ccc8","link-u-avif-sample-images/star.png":"18569167cf7ebd265ab6973d071d259aacfbb46c0408b7d4874c8cc9df9bb1ad","link-u-avif-sample-images/star.svg":"62af71f498f0549b19674ba19b830714dd58efcd65c86e9d741fc268afa52dd0","link-u-avif-sample-images/star180.png":"21bc11be2b51334fe4589634507612e7edce96d36e6a99219d029e440164e8b8","link-u-avif-sample-images/star270.png":"5c93f538dcdc70840b9925b4089083acc9c25e95265b3f3dea18d695451b441e","link-u-avif-sample-images/star90.png":"2defc5d21e70447653fec5dc14a697d9dd555d7a0c14e79cb2d9f80796a51a6d","src/boxes.rs":"39e979bd0b08fe6a9f43e092984879fc19185a48284e9ff868e5d47cf8df4363","src/lib.rs":"81453500f4c7a45f09edc55fc5adf403aa502417934162fa669e7caf76eca72a","src/macros.rs":"498bef25c8ea468d8ae0cd89593807d9e9253385cb9456d04f8cb00b721a54cb","src/tests.rs":"9251e246f416e5c440f0b05ccba3bea4ba1510e62073af3faa4dc85998b8e36d","src/unstable.rs":"68338ecd8f797d7a1c554a15bca7b8a9c5a0e6d726360d2bc0d46c43c71b3d8b","tests/1x1-black-alpha-50pct-premultiplied.avif":"31a8c235bf2cf601a593a7bc33f7f2779f2d5b2e0cd145897b931fce94b0c0b8","tests/a1lx.avif":"81a784c568e7619bd47c4e7153181e9a86c8a03221097aa63979f97affd7efbb","tests/a1op.avif":"184e50efd3ad226800c610da7bc470d29b548d9fa942fd1fd1848ed02e2e5f0a","tests/alpha_video_avif_major_avis_compatible.avif":"81771981248c4e0d708f0828eadb20e9e37e7c21280efe5726666958f899c237","tests/alpha_video_fixed.avif":"67051d1a4ccf9f3e38d4514d8a6b3a2e07f1beb979369cabdc60881a698a36ac","tests/alpha_video_no_avis.avif":"a95f0e7c818bc5bf646143cf43474b70722e17669d4f2a32874c125936207d6a","tests/amr_nb_1f.3gp":"d1423e3414ad06b69f8b58d5c916ec353ba2d0402d99dec9f1c88acc33b6a127","tests/amr_wb_1f.3gp":"be635b24097e8757b0c04d70ab28e00417ca113e86108b6c269b79b64b89bcd5","tests/av1C-missing-essential.avif":"a1501254c4071847b2269fe40b81409c389ff14e91cf7c0005a47e6ea97a6803","tests/bad-ipma-flags.avif":"ecde7997b97db1910b9dcc7ca8e3c8957da0e83681ea9008c66dc9f12b78ad19","tests/bad-ipma-version.avif":"7f9a1a0b4ebbf8d800d22eaae5ff78970cc6b811317db6c1467c6883952b7c9b","tests/bbb_sunflower_QCIF_30fps_h263_noaudio_1f.3gp":"03e5b1264d0a188d77b9e676ba3ce23a801b17aaa11c0343dfd851d6ea4e3a40","tests/clap-basic-1_3x3-to-1x1.avif":"83af9c8196fa93b2475163585a23d0eb5a8f8015d0db8da7a5d6de61adfb1876","tests/clap-missing-essential.avif":"4d61aacd2327661a456abc76d3d490e5ddd2b6f8cbfa52922a6c541c9d983193","tests/clusterfuzz-testcase-minimized-mp4-6093954524250112":"af7044a470732d4e7e34ac7ab5ff038c58b66f09702cbcd774931d7766bbfd35","tests/corrupt/a1lx-marked-essential.avif":"0d481240222450827ea335ae9a1a300777a0db4f9b0f4c17ed77c758c5133fa3","tests/corrupt/a1op-missing-essential.avif":"33c24d54f43f1a7be7a8334718881c8a0de24730c997c7842b9d7140e75017ea","tests/corrupt/alpha_video_moov_is_moop.avif":"89e0091edd6efc2c5b163525553c5abc56263fe1b3b885184bb07b9ea4bf346d","tests/corrupt/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/corrupt/bug-1661347.avif":"31c26561e1d9eafb60f7c5968b82a0859d203d73f17f26b29276256acee12966","tests/corrupt/clusterfuzz-testcase-minimized-avif-4914209301856256.avif":"34a142c7916e314881f3fb6394add1c543fac0e5b45109e3a425eeb4c68998d0","tests/corrupt/hdlr-not-first.avif":"2c29308af077209b9c984921b7e36f8fb7ca7cf379cf8eba4c7a91f65bc7a304","tests/corrupt/hdlr-not-pict.avif":"9fe37619606645a95725300a9e34fada9190d1e0b3919881db84353941ca9291","tests/corrupt/imir-before-clap.avif":"22d6b5dacf0ef0be59053beba7564b08037fed859ada2885e3476e0ff0d19c95","tests/corrupt/invalid-avif-colr-multiple-nclx.avif":"7990a995855120dc4f724a6098816595becc35077fcd9e0de8c68300b49c4f1f","tests/corrupt/invalid-avif-colr-multiple-prof.avif":"b077a6b58e3a13ad743ee3f19fbae53b521eab8727606e0dba9bf06384f3121c","tests/corrupt/invalid-avif-colr-multiple-rICC.avif":"88b24d4d588744b9f2cdc03944f28283e9315eb3de7d7d57773a0541137f6529","tests/corrupt/invalid-avif-colr-multiple.zip":"9abddcbc47fde6da20263a29b770c6a9e76c8ab8dc785ef8512f35d9cb3206ed","tests/corrupt/invalid-transformation-order.avif":"22d6b5dacf0ef0be59053beba7564b08037fed859ada2885e3476e0ff0d19c95","tests/corrupt/ipma-duplicate-item_id.avif":"ca8c5275b0b8b79c1068489a52d0a5c8f0b4453463971e72b694189f11c10745","tests/corrupt/ipma-duplicate-version-and-flags.avif":"cf8e15ec4b210235f3d68332a1adeb64e35c41b8d8e1e7586ae38b6d9cd8926c","tests/corrupt/ipma-invalid-property-index.avif":"2480e773fa716d22883032d05fd4cf2c6b00fba8796cf4ff286a5d1ba26adff6","tests/corrupt/lsel-missing-essential.avif":"43c3b1e4c4acecd7559a9a7197a7befd43c71705748f0f8c063bca3be1c6d074","tests/corrupt/no-alpha-av1C.avif":"ad3d34d6331db7d9bea0c5f37efb88923520e33e08e7c636a5df435a4575eae7","tests/corrupt/no-alpha-ispe.avif":"94805fe40e0f5a3d9e5e98050020d4ffe62e5c703ece2867bc72bb1cdd775f77","tests/corrupt/no-av1C.avif":"eeb4fc50930c91465999f787c4a2a3b12de20556da0857be72da5a1a9eaa3f01","tests/corrupt/no-ftyp.avif":"74b431f32b2e2761e77df7fdb260f623b4e8f7e3f4c8af8a42d6826911706d7b","tests/corrupt/no-hdlr.avif":"91a1eb70c7b6adf2104e471d7deeeb98084a591d64ce09ba106c27edfbc3a409","tests/corrupt/no-ispe.avif":"4b6edfd8c9b40c25dc40305a6057e32b5e65f40da4a9d810c58dbff53254113f","tests/corrupt/no-pitm.avif":"7960eeb9e6e5140fbe5eb6d281e6974efd6c3c0147562f3dcf06f6b009dc540a","tests/corrupt/no-pixi-for-alpha.avif":"f8adc3573c79ee25bf6d4dd2693c61661469b28f86a5c7b1d9e41b0e8d2d53bb","tests/corrupt/no-pixi.avif":"4b1776def440dc8b913c170e4479772ee6bbb299b8679f7c564704bd03c9597e","tests/corrupt/transformation-before-ispe.avif":"7ac59dd68a4caa54c0cde9af0d57ff7832baada74d39174b50fbe0275a59a049","tests/hdlr-nonzero-reserved.avif":"b872dcd7b4f49c6808d6da109cf4fedc26a237c42e8529c5aa8f7130abaf40a9","tests/imir-missing-essential.avif":"6a5dfd4a9cc6dac96fbcaa759b976ec7246120455ab59f970a97606737bf31e9","tests/invalid-avif-hdlr-name-multiple-nul.avif":"0d3e4a6ce42154ee288c18339c2b59ff2104fd890cd2d616e5dbf26375a90e98","tests/irot-missing-essential.avif":"494589024dd277788b4de60b76352947b4fe7fe62bbe7ea6a47885ab126a8a2f","tests/lsel.avif":"ef8ba6827709f48cd45f749efb580129162d9599ea98f3363d2140957502d806","tests/multiple-extents.avif":"b5549ac68793e155a726d754e565cea0da03fa17833d3545f45c79e13f4c9360","tests/no-mif1.avif":"1442aa6ffaeb9512724287768bfd1850d3aa29a651ef05abb33e5dec2b3ee5c2","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"7c14c5742ebdc6d055f6e0a3139436f2cfa05a615c944fac89e6fff2bcab5040","tests/valid-alpha.avif":"9d417a35b9b62ad3ff66ffbc55f16552aacf821a092aa5ef4adff7e746bd4c2f","tests/valid-avif-colr-nclx-and-prof-and-rICC.avif":"ab6f5e786d26f8bcade5993f8b9cca3cd004a3d7fcec76e829f5d0f98cb18e7b","tests/valid-avif-colr-nclx-and-prof.avif":"0e982818de61869fcb85a2a4c2b7b8aeecb3053cbfdc6276987f91204998eefb","tests/valid-avif-colr-nclx-and-rICC.avif":"8530ef1305ff956a0c2912d0b3d1e0fc3a68cf3103e70b04cc2574530389b030","tests/valid-avif-colr-nclx.avif":"345ab58b7b1cb48aba2e21eb8dc5ab0a751a78a752ce1896c59b4bf361992f38","tests/valid-avif-colr-prof-and-rICC.avif":"1f0f085141106885bda78b0879c768818420d8196b39440a36578456a7d50a6c","tests/valid-avif-colr-prof.avif":"5d7aaefb5204ebe1cc296456866b8e46e023748b921a38ee56fd6c776a9733ff","tests/valid-avif-colr-rICC.avif":"e1c7b49bfad5904b484bd5118e6b33b78e2dc708a31a10fcbb0e4a373ed8dbb7","tests/valid.avif":"f0b33e09bf01232e0877df325f47986c0bee7764f2a81c9c908ae109e7dc63c4"},"package":null} \ No newline at end of file diff --git a/third_party/rust/mp4parse/Cargo.toml b/third_party/rust/mp4parse/Cargo.toml index 161043254e30..cebac7bb9f9a 100644 --- a/third_party/rust/mp4parse/Cargo.toml +++ b/third_party/rust/mp4parse/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mp4parse" -version = "0.13.0" +version = "0.16.0" authors = [ "Ralph Giles ", "Matthew Gregan ", @@ -13,7 +13,7 @@ description = "Parser for ISO base media file format (mp4)" documentation = "https://docs.rs/mp4parse/" license = "MPL-2.0" categories = ["multimedia::video"] - +edition = "2018" repository = "https://github.com/mozilla/mp4parse-rust" # Avoid complaints about trying to package test files. @@ -28,7 +28,6 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" } [dependencies] byteorder = "1.2.1" bitreader = { version = "0.3.2" } -env_logger = "0.8" fallible_collections = { version = "0.4", features = ["std_io"] } num-traits = "0.2.14" log = "0.4" diff --git a/third_party/rust/mp4parse/benches/avif_benchmark.rs b/third_party/rust/mp4parse/benches/avif_benchmark.rs index 0d8a48b63ced..f7810f8caf0b 100644 --- a/third_party/rust/mp4parse/benches/avif_benchmark.rs +++ b/third_party/rust/mp4parse/benches/avif_benchmark.rs @@ -1,8 +1,6 @@ // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -extern crate criterion; -extern crate mp4parse as mp4; use criterion::{criterion_group, criterion_main, Criterion}; use std::fs::File; @@ -19,5 +17,5 @@ fn avif_largest() { "av1-avif/testFiles/Netflix/avif/cosmos_frame05000_yuv444_12bpc_bt2020_pq_qlossless.avif", ) .expect("Unknown file"); - assert!(mp4::read_avif(input, mp4::ParseStrictness::Normal).is_ok()); + assert!(mp4parse::read_avif(input, mp4parse::ParseStrictness::Normal).is_ok()); } diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/.github/workflows/encode-and-decode-daily.yml b/third_party/rust/mp4parse/link-u-avif-sample-images/.github/workflows/encode-and-decode-daily.yml index 08733dec70d3..897b8ff5e9c7 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/.github/workflows/encode-and-decode-daily.yml +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/.github/workflows/encode-and-decode-daily.yml @@ -1,146 +1,146 @@ -name: Encode all images and decode them again weekly. - -on: - push: - schedule: - - cron: '0 20 * * 0' # https://crontab.guru/#0_2_*_*_0 - -jobs: - check-on-ubuntu: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-18.04, ubuntu-20.04] - include: - - os: ubuntu-18.04 - codename: 'bionic' - cavif-flag: '' - - os: ubuntu-20.04 - codename: 'focal' - cavif-flag: '' - steps: - - uses: actions/checkout@v2 - - name: Install required tools - run: sudo apt install -y curl jq unzip coreutils imagemagick - - name: Download latest cavif - shell: bash - run: | - runId=$(curl https://api.github.com/repos/link-u/cavif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') - artifactId=$(curl https://api.github.com/repos/link-u/cavif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "${{ matrix.codename }}")][0].id') - curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o cavif.zip -L https://api.github.com/repos/link-u/cavif/actions/artifacts/${artifactId}/zip - unzip cavif.zip - env: - #id of https://github.com/link-u/cavif/actions?query=workflow%3A%22Build+debian+package+on+push+or+release-tags.%22 - # curl https://api.github.com/repos/link-u/cavif/actions/workflows - WORKFLOW_ID: '4521995' - - name: Download latest davif - shell: bash - run: | - runId=$(curl https://api.github.com/repos/link-u/davif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') - artifactId=$(curl https://api.github.com/repos/link-u/davif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "${{ matrix.codename }}")][0].id') - curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o davif.zip -L https://api.github.com/repos/link-u/davif/actions/artifacts/${artifactId}/zip - unzip davif.zip - env: - #id of https://github.com/link-u/davif/actions?query=workflow%3A%22Build+debian+package+on+push+or+release-tags.%22 - # curl https://api.github.com/repos/link-u/davif/actions/workflows - WORKFLOW_ID: '452394' - - name: Install davif and cavif - run: sudo dpkg -i *.deb - - name: Use installed cavif and davif - run: | - sed -i -e 's/^CAVIF=.*$/CAVIF=cavif ${{ matrix.cavif-flag }}/' Makefile - sed -i -e 's/^DAVIF=.*$/DAVIF=davif/' Makefile - - name: Clean all images. - run: make clean - - name: Encode them all. - run: make all -j $(nproc) - - name: Decode them all. - run: make decode -j $(nproc) - - name: Copy images to upload. - run: | - mkdir -p ${{ matrix.codename }}/decoded - mkdir -p ${{ matrix.codename }}/encoded - cp decoded/* ${{ matrix.codename }}/decoded - cp *.avif ${{ matrix.codename }}/encoded - - name: Upload result - uses: actions/upload-artifact@v1 - with: - name: ${{ matrix.codename }} - path: ${{ matrix.codename }} - - name: Compare the result - run: make compare -j $(nproc) - check-on-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Install msys2 - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW64 - update: true - path-type: inherit - - name: Install dependencies - shell: msys2 {0} - run: | - set -eux - pacman --noconfirm -S make - pacman --noconfirm -S bc - pacman --noconfirm -S mingw-w64-x86_64-imagemagick - pacman --noconfirm -S mingw-w64-x86_64-curl - pacman --noconfirm -S mingw-w64-x86_64-jq - make --version - echo '2+2' | bc - magick -version - - name: Download latest cavif - shell: bash - run: | - runId=$(curl https://api.github.com/repos/link-u/cavif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') - artifactId=$(curl https://api.github.com/repos/link-u/cavif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "cavif-win64")][0].id') - curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o cavif.zip -L https://api.github.com/repos/link-u/cavif/actions/artifacts/${artifactId}/zip - unzip cavif.zip - rm cavif.zip - ./cavif.exe -h - env: - WORKFLOW_ID: '4517759' - - name: Download latest davif - shell: bash - run: | - runId=$(curl https://api.github.com/repos/link-u/davif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') - artifactId=$(curl https://api.github.com/repos/link-u/davif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "davif-win64")][0].id') - curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o davif.zip -L https://api.github.com/repos/link-u/davif/actions/artifacts/${artifactId}/zip - unzip davif.zip - rm davif.zip - ./davif.exe -h - env: - WORKFLOW_ID: '4521970' - - name: Rewrite Makefile to installed cavif and davif - shell: msys2 {0} - run: | - sed -i -e 's/^CAVIF=.*$/CAVIF=.\/cavif.exe/' Makefile - sed -i -e 's/^DAVIF=.*$/DAVIF=.\/davif.exe/' Makefile - - name: Clean all images. - shell: msys2 {0} - run: make clean - - name: Encode them all - shell: msys2 {0} - run: make all -j $(nproc) - - name: Decode them all - shell: msys2 {0} - run: make decode -j $(nproc) - - name: Copy images to upload. - shell: msys2 {0} - run: | - mkdir -p win64/decoded - mkdir -p win64/encoded - cp decoded/* win64/decoded - cp *.avif win64/encoded - - name: Upload result - uses: actions/upload-artifact@v1 - with: - name: win64 - path: win64 - - name: Compare the result - shell: msys2 {0} - run: | - export PATH="/mingw64/bin:${PATH}" - make compare -j $(nproc) +name: Encode all images and decode them again weekly. + +on: + push: + schedule: + - cron: '0 20 * * 0' # https://crontab.guru/#0_2_*_*_0 + +jobs: + check-on-ubuntu: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-18.04, ubuntu-20.04] + include: + - os: ubuntu-18.04 + codename: 'bionic' + cavif-flag: '' + - os: ubuntu-20.04 + codename: 'focal' + cavif-flag: '' + steps: + - uses: actions/checkout@v2 + - name: Install required tools + run: sudo apt install -y curl jq unzip coreutils imagemagick + - name: Download latest cavif + shell: bash + run: | + runId=$(curl https://api.github.com/repos/link-u/cavif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') + artifactId=$(curl https://api.github.com/repos/link-u/cavif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "${{ matrix.codename }}")][0].id') + curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o cavif.zip -L https://api.github.com/repos/link-u/cavif/actions/artifacts/${artifactId}/zip + unzip cavif.zip + env: + #id of https://github.com/link-u/cavif/actions?query=workflow%3A%22Build+debian+package+on+push+or+release-tags.%22 + # curl https://api.github.com/repos/link-u/cavif/actions/workflows + WORKFLOW_ID: '4521995' + - name: Download latest davif + shell: bash + run: | + runId=$(curl https://api.github.com/repos/link-u/davif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') + artifactId=$(curl https://api.github.com/repos/link-u/davif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "${{ matrix.codename }}")][0].id') + curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o davif.zip -L https://api.github.com/repos/link-u/davif/actions/artifacts/${artifactId}/zip + unzip davif.zip + env: + #id of https://github.com/link-u/davif/actions?query=workflow%3A%22Build+debian+package+on+push+or+release-tags.%22 + # curl https://api.github.com/repos/link-u/davif/actions/workflows + WORKFLOW_ID: '452394' + - name: Install davif and cavif + run: sudo dpkg -i *.deb + - name: Use installed cavif and davif + run: | + sed -i -e 's/^CAVIF=.*$/CAVIF=cavif ${{ matrix.cavif-flag }}/' Makefile + sed -i -e 's/^DAVIF=.*$/DAVIF=davif/' Makefile + - name: Clean all images. + run: make clean + - name: Encode them all. + run: make all -j $(nproc) + - name: Decode them all. + run: make decode -j $(nproc) + - name: Copy images to upload. + run: | + mkdir -p ${{ matrix.codename }}/decoded + mkdir -p ${{ matrix.codename }}/encoded + cp decoded/* ${{ matrix.codename }}/decoded + cp *.avif ${{ matrix.codename }}/encoded + - name: Upload result + uses: actions/upload-artifact@v1 + with: + name: ${{ matrix.codename }} + path: ${{ matrix.codename }} + - name: Compare the result + run: make compare -j $(nproc) + check-on-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Install msys2 + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + path-type: inherit + - name: Install dependencies + shell: msys2 {0} + run: | + set -eux + pacman --noconfirm -S make + pacman --noconfirm -S bc + pacman --noconfirm -S mingw-w64-x86_64-imagemagick + pacman --noconfirm -S mingw-w64-x86_64-curl + pacman --noconfirm -S mingw-w64-x86_64-jq + make --version + echo '2+2' | bc + magick -version + - name: Download latest cavif + shell: bash + run: | + runId=$(curl https://api.github.com/repos/link-u/cavif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') + artifactId=$(curl https://api.github.com/repos/link-u/cavif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "cavif-win64")][0].id') + curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o cavif.zip -L https://api.github.com/repos/link-u/cavif/actions/artifacts/${artifactId}/zip + unzip cavif.zip + rm cavif.zip + ./cavif.exe -h + env: + WORKFLOW_ID: '4517759' + - name: Download latest davif + shell: bash + run: | + runId=$(curl https://api.github.com/repos/link-u/davif/actions/workflows/${WORKFLOW_ID}/runs | jq '[.workflow_runs[] | select( .conclusion == "success")][0].id') + artifactId=$(curl https://api.github.com/repos/link-u/davif/actions/runs/${runId}/artifacts | jq '[.artifacts[] | select( .name == "davif-win64")][0].id') + curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o davif.zip -L https://api.github.com/repos/link-u/davif/actions/artifacts/${artifactId}/zip + unzip davif.zip + rm davif.zip + ./davif.exe -h + env: + WORKFLOW_ID: '4521970' + - name: Rewrite Makefile to installed cavif and davif + shell: msys2 {0} + run: | + sed -i -e 's/^CAVIF=.*$/CAVIF=.\/cavif.exe/' Makefile + sed -i -e 's/^DAVIF=.*$/DAVIF=.\/davif.exe/' Makefile + - name: Clean all images. + shell: msys2 {0} + run: make clean + - name: Encode them all + shell: msys2 {0} + run: make all -j $(nproc) + - name: Decode them all + shell: msys2 {0} + run: make decode -j $(nproc) + - name: Copy images to upload. + shell: msys2 {0} + run: | + mkdir -p win64/decoded + mkdir -p win64/encoded + cp decoded/* win64/decoded + cp *.avif win64/encoded + - name: Upload result + uses: actions/upload-artifact@v1 + with: + name: win64 + path: win64 + - name: Compare the result + shell: msys2 {0} + run: | + export PATH="/mingw64/bin:${PATH}" + make compare -j $(nproc) diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/.gitignore b/third_party/rust/mp4parse/link-u-avif-sample-images/.gitignore index 69b09be52ac0..5016ce43e30f 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/.gitignore +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/.gitignore @@ -1,4 +1,4 @@ -*.avif.png -/core -/decoded/ -/.alpha-masks/ +*.avif.png +/core +/decoded/ +/.alpha-masks/ diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/LICENSE.txt b/third_party/rust/mp4parse/link-u-avif-sample-images/LICENSE.txt index 33bec29d5181..87316c7a9ac5 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/LICENSE.txt +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/LICENSE.txt @@ -1,427 +1,427 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - - including for purposes of Section 3(b); and - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + Creative Commons may be contacted at creativecommons.org. \ No newline at end of file diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/Makefile b/third_party/rust/mp4parse/link-u-avif-sample-images/Makefile index 2cabb6101b1e..d3391171e04a 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/Makefile +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/Makefile @@ -1,911 +1,911 @@ -CAVIF=../cavif/cmake-build-debug/cavif -DAVIF=../davif/cmake-build-debug/davif - -all: hato kimono fox plum; - -HATO=\ - hato.profile2.8bpc.yuv422.avif \ - hato.profile2.8bpc.yuv422.monochrome.avif \ - hato.profile2.10bpc.yuv422.avif \ - hato.profile2.10bpc.yuv422.monochrome.avif \ - hato.profile2.12bpc.yuv422.avif \ - hato.profile2.12bpc.yuv422.monochrome.avif \ - hato.profile0.8bpc.yuv420.avif \ - hato.profile0.8bpc.yuv420.monochrome.avif \ - hato.profile0.10bpc.yuv420.avif \ - hato.profile0.10bpc.yuv420.monochrome.avif - -hato: $(HATO); - -KIMONO=\ - kimono.avif \ - kimono.rotate90.avif \ - kimono.rotate270.avif \ - kimono.mirror-horizontal.avif \ - kimono.mirror-vertical.avif \ - kimono.mirror-vertical.rotate270.avif \ - kimono.crop.avif \ - kimono.mirror-vertical.rotate270.crop.avif - -kimono: $(KIMONO); - -FOX=\ - fox.profile0.8bpc.yuv420.avif \ - fox.profile0.8bpc.yuv420.odd-width.avif \ - fox.profile0.8bpc.yuv420.odd-height.avif \ - fox.profile0.8bpc.yuv420.odd-width.odd-height.avif \ - fox.profile0.8bpc.yuv420.monochrome.avif \ - fox.profile0.8bpc.yuv420.monochrome.odd-width.avif \ - fox.profile0.8bpc.yuv420.monochrome.odd-height.avif \ - fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif \ - fox.profile0.10bpc.yuv420.avif \ - fox.profile0.10bpc.yuv420.odd-width.avif \ - fox.profile0.10bpc.yuv420.odd-height.avif \ - fox.profile0.10bpc.yuv420.odd-width.odd-height.avif \ - fox.profile0.10bpc.yuv420.monochrome.avif \ - fox.profile0.10bpc.yuv420.monochrome.odd-width.avif \ - fox.profile0.10bpc.yuv420.monochrome.odd-height.avif \ - fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif \ - fox.profile2.12bpc.yuv420.avif \ - fox.profile2.12bpc.yuv420.odd-width.avif \ - fox.profile2.12bpc.yuv420.odd-height.avif \ - fox.profile2.12bpc.yuv420.odd-width.odd-height.avif \ - fox.profile2.12bpc.yuv420.monochrome.avif \ - fox.profile2.12bpc.yuv420.monochrome.odd-width.avif \ - fox.profile2.12bpc.yuv420.monochrome.odd-height.avif \ - fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif \ - fox.profile2.8bpc.yuv422.avif \ - fox.profile2.8bpc.yuv422.odd-width.avif \ - fox.profile2.8bpc.yuv422.odd-height.avif \ - fox.profile2.8bpc.yuv422.odd-width.odd-height.avif \ - fox.profile2.8bpc.yuv422.monochrome.avif \ - fox.profile2.8bpc.yuv422.monochrome.odd-width.avif \ - fox.profile2.8bpc.yuv422.monochrome.odd-height.avif \ - fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif \ - fox.profile2.10bpc.yuv422.avif \ - fox.profile2.10bpc.yuv422.odd-width.avif \ - fox.profile2.10bpc.yuv422.odd-height.avif \ - fox.profile2.10bpc.yuv422.odd-width.odd-height.avif \ - fox.profile2.10bpc.yuv422.monochrome.avif \ - fox.profile2.10bpc.yuv422.monochrome.odd-width.avif \ - fox.profile2.10bpc.yuv422.monochrome.odd-height.avif \ - fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif \ - fox.profile2.12bpc.yuv422.avif \ - fox.profile2.12bpc.yuv422.odd-width.avif \ - fox.profile2.12bpc.yuv422.odd-height.avif \ - fox.profile2.12bpc.yuv422.odd-width.odd-height.avif \ - fox.profile2.12bpc.yuv422.monochrome.avif \ - fox.profile2.12bpc.yuv422.monochrome.odd-width.avif \ - fox.profile2.12bpc.yuv422.monochrome.odd-height.avif \ - fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif \ - fox.profile1.8bpc.yuv444.avif \ - fox.profile1.8bpc.yuv444.odd-width.avif \ - fox.profile1.8bpc.yuv444.odd-height.avif \ - fox.profile1.8bpc.yuv444.odd-width.odd-height.avif \ - fox.profile1.10bpc.yuv444.avif \ - fox.profile1.10bpc.yuv444.odd-width.avif \ - fox.profile1.10bpc.yuv444.odd-height.avif \ - fox.profile1.10bpc.yuv444.odd-width.odd-height.avif \ - fox.profile2.12bpc.yuv444.avif \ - fox.profile2.12bpc.yuv444.odd-width.avif \ - fox.profile2.12bpc.yuv444.odd-height.avif \ - fox.profile2.12bpc.yuv444.odd-width.odd-height.avif \ - fox.profile2.12bpc.yuv444.monochrome.avif \ - fox.profile2.12bpc.yuv444.monochrome.odd-width.avif \ - fox.profile2.12bpc.yuv444.monochrome.odd-height.avif \ - fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif - -fox: $(FOX); - -PLUM_LARGE=\ - plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif \ - plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif \ - plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif \ - plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif \ - plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif \ - plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif \ - plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif \ - plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif \ - plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif \ - plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif \ - plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif \ - plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif \ - plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif \ - plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif \ - plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif \ - plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif \ - plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif \ - plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif \ - plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif \ - plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif \ - plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif \ - plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif \ - plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif \ - plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif \ - plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif \ - plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif \ - plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif \ - plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif \ - plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif \ - plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif \ - plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif \ - plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif - -PLUM_SMALL=\ - plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif \ - plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif \ - plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif \ - plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif \ - plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif \ - plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif \ - plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif \ - plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif \ - plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif \ - plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif \ - plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif \ - plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif \ - plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif \ - plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif \ - plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif \ - plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif \ - plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif \ - plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif \ - plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif \ - plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif \ - plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif \ - plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif \ - plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif \ - plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif \ - plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif \ - plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif \ - plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif \ - plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif \ - plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif \ - plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif \ - plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif \ - plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif - -PLUM=$(PLUM_LARGE) $(PLUM_SMALL) - -plum: $(PLUM); - -STAR=\ - star-8bpc.avifs \ - star-8bpc-with-alpha.avifs \ - star-10bpc.avifs \ - star-10bpc-with-alpha.avifs \ - star-12bpc.avifs \ - star-12bpc-with-alpha.avifs - -star: $(STAR); - -ALL_AVIF=$(HATO) $(KIMONO) $(FOX) $(PLUM) -ALL_AVIFS=$(STAR) -DECODED_PNG=$(ALL_AVIF:%.avif=decoded/%.png) -DUMMY_CHECK_TARGETS=$(ALL_AVIF:%.avif=%.check) - -.PHONY: all clean \ - hato kimono fox plum \ - star \ - decode decode-clean decode-images \ - url hato-url kimono-url fox-url plum-url\ - compare $(DUMMY_CHECK_TARGETS) - -decode-clean: - rm -Rf decoded/ - -$(DECODED_PNG): | decoded - -decoded: - mkdir -p decoded - -decode-images: $(DECODED_PNG); - -decode: - $(MAKE) decode-clean - $(MAKE) decode-images - -compare: $(DUMMY_CHECK_TARGETS); - -decoded/%.png: %.avif - $(DAVIF) -i $< -o $@ - -$(DUMMY_CHECK_TARGETS): %.check: %.avif decoded/%.png - bash -e scripts/compare.sh $@ $(word 1,$^) $(word 2,$^) - -url: - cat Makefile | grep '^.*\?\.avif:' | sort -d | sed 's/^\(.*\)\:\s*\(.*\)$\/https\:\/\/raw.githubusercontent.com\/link-u\/avif-sample-images\/master\/\1, https\:\/\/raw.githubusercontent.com\/link-u\/avif-sample-images\/master\/\2/' - -hato-url: - $(MAKE) url | grep hato - -kimono-url: - $(MAKE) url | grep kimono - -fox-url: - $(MAKE) url | grep fox - -plum-url: - $(MAKE) url | grep plum-blossom - -clean: - rm -Rf *.avif decoded .alpha-masks - -## hato - -### YUV422 - -hato.profile2.8bpc.yuv422.avif: hato.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -hato.profile2.8bpc.yuv422.monochrome.avif: hato.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --monochrome --cpu-used 0 --rate-control q --crf 18 - -hato.profile2.10bpc.yuv422.avif: hato.16bpc.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -hato.profile2.10bpc.yuv422.monochrome.avif: hato.16bpc.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --monochrome --cpu-used 0 --rate-control q --crf 18 - -hato.profile2.12bpc.yuv422.avif: hato.16bpc.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -hato.profile2.12bpc.yuv422.monochrome.avif: hato.16bpc.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --monochrome --cpu-used 0 --rate-control q --crf 18 - -### YUV420 - -hato.profile0.8bpc.yuv420.avif: hato.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -hato.profile0.8bpc.yuv420.monochrome.avif: hato.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --monochrome --cpu-used 0 --rate-control q --crf 18 - -hato.profile0.10bpc.yuv420.avif: hato.16bpc.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -hato.profile0.10bpc.yuv420.monochrome.avif: hato.16bpc.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --monochrome --cpu-used 0 --rate-control q --crf 18 - -## Kimono - -kimono.avif: kimono.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -kimono.rotate90.avif: kimono.rotate90.png - $(CAVIF) -i $< -o $@ --rotation 270 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -kimono.rotate270.avif: kimono.rotate270.png - $(CAVIF) -i $< -o $@ --rotation 90 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -kimono.mirror-horizontal.avif: kimono.mirror-horizontal.png - $(CAVIF) -i $< -o $@ --mirror horizontal --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -kimono.mirror-vertical.avif: kimono.mirror-vertical.png - $(CAVIF) -i $< -o $@ --mirror vertical --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -kimono.mirror-vertical.rotate270.avif: kimono.mirror-vertical.rotate270.png - $(CAVIF) -i $< -o $@ --mirror vertical --rotation 90 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -kimono.crop.avif: kimono.png - $(CAVIF) -i $< -o $@ --crop-offset 103,-308 --crop-size 385,330 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -kimono.mirror-vertical.rotate270.crop.avif: kimono.mirror-vertical.rotate270.png - $(CAVIF) -i $< -o $@ --crop-offset -308,103 --crop-size 330,385 --mirror vertical --rotation 90 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -## Fox Parade - -### YUV420 - -#### 8bit - -fox.profile0.8bpc.yuv420.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.8bpc.yuv420.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.8bpc.yuv420.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.8bpc.yuv420.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.8bpc.yuv420.monochrome.avif: fox.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.8bpc.yuv420.monochrome.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.8bpc.yuv420.monochrome.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -#### 10bit - -fox.profile0.10bpc.yuv420.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.10bpc.yuv420.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.10bpc.yuv420.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.10bpc.yuv420.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.10bpc.yuv420.monochrome.avif: fox.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.10bpc.yuv420.monochrome.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.10bpc.yuv420.monochrome.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -#### 12bit - -fox.profile2.12bpc.yuv420.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv420.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv420.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv420.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv420.monochrome.avif: fox.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv420.monochrome.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv420.monochrome.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -### YUV422 - -#### 8bit - -fox.profile2.8bpc.yuv422.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.8bpc.yuv422.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.8bpc.yuv422.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.8bpc.yuv422.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.8bpc.yuv422.monochrome.avif: fox.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.8bpc.yuv422.monochrome.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.8bpc.yuv422.monochrome.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -#### 10bit - -fox.profile2.10bpc.yuv422.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.10bpc.yuv422.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.10bpc.yuv422.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.10bpc.yuv422.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.10bpc.yuv422.monochrome.avif: fox.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.10bpc.yuv422.monochrome.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.10bpc.yuv422.monochrome.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -#### 12bit - -fox.profile2.12bpc.yuv422.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv422.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv422.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv422.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv422.monochrome.avif: fox.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv422.monochrome.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv422.monochrome.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -### YUV444 - -#### 8bit - -fox.profile1.8bpc.yuv444.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile1.8bpc.yuv444.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile1.8bpc.yuv444.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile1.8bpc.yuv444.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -#### 10bit - -fox.profile1.10bpc.yuv444.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile1.10bpc.yuv444.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile1.10bpc.yuv444.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile1.10bpc.yuv444.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -#### 12bit - -fox.profile2.12bpc.yuv444.avif: fox.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv444.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv444.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv444.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv444.monochrome.avif: fox.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv444.monochrome.odd-width.avif: fox.odd-width.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv444.monochrome.odd-height.avif: fox.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png - $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -## Alpha mask - -.alpha-masks: - mkdir -p .alpha-masks - -$(PLUM): | .alpha-masks - -## Plum blossom - large version - -### YUV420 - -#### 8bit - -plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 10bit - -plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 12bit - -plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -## YUV422 - -#### 8bit - -plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 10bit - -plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 12bit - -plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -### YUV444 - -#### 8bit - -plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -#### 10bit - -plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -#### 12bit - -plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif: plum-blossom-large.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome - -## Plum blossom - small version - -### YUV420 - -#### 8bit - -plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 10bit - -plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 12bit - -plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome - -## YUV422 - -#### 8bit - -plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 10bit - -plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -#### 12bit - -plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome - -### YUV444 - -#### 8bit - -plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -#### 10bit - -plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -#### 12bit - -plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome - -plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 - -plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif: plum-blossom-small.png - $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range - $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome - -star-8bpc.avifs: star.input.txt - $(eval TMP := $(shell mktemp -d)) - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv420p -color_range jpeg -b:v 0 -crf 0 -lossless 1 $(TMP)/star.mp4 - # You need the latest version of gpac. - # Go to https://github.com/gpac/gpac - # then, `make deb -j32` - MP4Box -add-image $(TMP)/star.mp4:id=1:primary -new $@ - MP4Box -ab avis -ab msf1 -ab miaf -ab MA1B -rb mif1 -brand avis $@ - MP4Box -add $(TMP)/star.mp4:hdlr=pict:ccst:name="GPAC avifs" $@ - rm -Rfv $(TMP) - -# FIXME(ledya-z): WORK IN PROGRESS -star-8bpc-with-alpha.avifs: star.input.txt - $(eval TMP := $(shell mktemp -d)) - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv420p -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-video.mp4" - # FIXME(ledyba-z): It does not generate monochrome OBUs. - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt gray -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-alpha.mp4" - # You need the latest version of gpac. - # Go to https://github.com/gpac/gpac - # then, `make deb -j32` - - MP4Box -raw-layer "1:output=$(TMP)/star-video" "$(TMP)/star-video.mp4" - MP4Box -raw-layer "1:output=$(TMP)/star-alpha" "$(TMP)/star-alpha.mp4" - - MP4Box -add-image "$(TMP)/star-alpha.av1:id=3:ref=auxl,4:alpha:name=Alpha" -add-image "$(TMP)/star-video.av1:id=4:name=Color" -set-primary 4 -ab avif -new $@ - MP4Box -add "$(TMP)/star-video.av1:hdlr=pict:ccst:name=\"GPAC avifs\"" -add "$(TMP)/star-alpha.av1:hdlr=auxv:ccst:alpha:name=\"GPAC avifs alpha\"" -ref 2:auxl:1 -ab msf1 -ab miaf -ab MA1B -brand avis $@ - rm -Rfv $(TMP) - -star-10bpc.avifs: star.input.txt - $(eval TMP := $(shell mktemp -d)) - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv422p10 -color_range jpeg -b:v 0 -crf 0 -lossless 1 $(TMP)/star.mp4 - # You need the latest version of gpac. - # Go to https://github.com/gpac/gpac - # then, `make deb -j32` - MP4Box -add-image $(TMP)/star.mp4:id=1:primary -new $@ - MP4Box -ab avis -ab msf1 -ab miaf -ab MA1B -rb mif1 -brand avis $@ - MP4Box -add $(TMP)/star.mp4:hdlr=pict:ccst:name="GPAC avifs" $@ - rm -Rfv $(TMP) - -# FIXME(ledya-z): WORK IN PROGRESS -star-10bpc-with-alpha.avifs: star.input.txt - $(eval TMP := $(shell mktemp -d)) - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv422p10 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-video.mp4" - # FIXME(ledyba-z): It does not generate monochrome OBUs. - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt gray10 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-alpha.mp4" - # You need the latest version of gpac. - # Go to https://github.com/gpac/gpac - # then, `make deb -j32` - - MP4Box -raw-layer "1:output=$(TMP)/star-video" "$(TMP)/star-video.mp4" - MP4Box -raw-layer "1:output=$(TMP)/star-alpha" "$(TMP)/star-alpha.mp4" - - MP4Box -add-image "$(TMP)/star-alpha.av1:id=3:ref=auxl,4:alpha:name=Alpha" -add-image "$(TMP)/star-video.av1:id=4:name=Color" -set-primary 4 -ab avif -new $@ - MP4Box -add "$(TMP)/star-video.av1:hdlr=pict:ccst:name=\"GPAC avifs\"" -add "$(TMP)/star-alpha.av1:hdlr=auxv:ccst:alpha:name=\"GPAC avifs alpha\"" -ref 2:auxl:1 -ab msf1 -ab miaf -ab MA1B -brand avis $@ - rm -Rfv $(TMP) - -star-12bpc.avifs: star.input.txt - $(eval TMP := $(shell mktemp -d)) - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv444p12 -color_range jpeg -b:v 0 -crf 0 -lossless 1 $(TMP)/star.mp4 - # You need the latest version of gpac. - # Go to https://github.com/gpac/gpac - # then, `make deb -j32` - MP4Box -add-image $(TMP)/star.mp4:id=1:primary -new $@ - MP4Box -ab avis -ab msf1 -ab miaf -ab MA1B -rb mif1 -brand avis $@ - MP4Box -add $(TMP)/star.mp4:hdlr=pict:ccst:name="GPAC avifs" $@ - rm -Rfv $(TMP) - -# FIXME(ledya-z): WORK IN PROGRESS -star-12bpc-with-alpha.avifs: star.input.txt - $(eval TMP := $(shell mktemp -d)) - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv444p12 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-video.mp4" - # FIXME(ledyba-z): It does not generate monochrome OBUs. - ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt gray12 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-alpha.mp4" - # You need the latest version of gpac. - # Go to https://github.com/gpac/gpac - # then, `make deb -j32` - - MP4Box -raw-layer "1:output=$(TMP)/star-video" "$(TMP)/star-video.mp4" - MP4Box -raw-layer "1:output=$(TMP)/star-alpha" "$(TMP)/star-alpha.mp4" - - MP4Box -add-image "$(TMP)/star-alpha.av1:id=3:ref=auxl,4:alpha:name=Alpha" -add-image "$(TMP)/star-video.av1:id=4:name=Color" -set-primary 4 -ab avif -new $@ - MP4Box -add "$(TMP)/star-video.av1:hdlr=pict:ccst:name=\"GPAC avifs\"" -add "$(TMP)/star-alpha.av1:hdlr=auxv:ccst:alpha:name=\"GPAC avifs alpha\"" -ref 2:auxl:1 -ab msf1 -ab miaf -ab MA1B -brand avis $@ - rm -Rfv $(TMP) +CAVIF=../cavif/cmake-build-debug/cavif +DAVIF=../davif/cmake-build-debug/davif + +all: hato kimono fox plum; + +HATO=\ + hato.profile2.8bpc.yuv422.avif \ + hato.profile2.8bpc.yuv422.monochrome.avif \ + hato.profile2.10bpc.yuv422.avif \ + hato.profile2.10bpc.yuv422.monochrome.avif \ + hato.profile2.12bpc.yuv422.avif \ + hato.profile2.12bpc.yuv422.monochrome.avif \ + hato.profile0.8bpc.yuv420.avif \ + hato.profile0.8bpc.yuv420.monochrome.avif \ + hato.profile0.10bpc.yuv420.avif \ + hato.profile0.10bpc.yuv420.monochrome.avif + +hato: $(HATO); + +KIMONO=\ + kimono.avif \ + kimono.rotate90.avif \ + kimono.rotate270.avif \ + kimono.mirror-horizontal.avif \ + kimono.mirror-vertical.avif \ + kimono.mirror-vertical.rotate270.avif \ + kimono.crop.avif \ + kimono.mirror-vertical.rotate270.crop.avif + +kimono: $(KIMONO); + +FOX=\ + fox.profile0.8bpc.yuv420.avif \ + fox.profile0.8bpc.yuv420.odd-width.avif \ + fox.profile0.8bpc.yuv420.odd-height.avif \ + fox.profile0.8bpc.yuv420.odd-width.odd-height.avif \ + fox.profile0.8bpc.yuv420.monochrome.avif \ + fox.profile0.8bpc.yuv420.monochrome.odd-width.avif \ + fox.profile0.8bpc.yuv420.monochrome.odd-height.avif \ + fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif \ + fox.profile0.10bpc.yuv420.avif \ + fox.profile0.10bpc.yuv420.odd-width.avif \ + fox.profile0.10bpc.yuv420.odd-height.avif \ + fox.profile0.10bpc.yuv420.odd-width.odd-height.avif \ + fox.profile0.10bpc.yuv420.monochrome.avif \ + fox.profile0.10bpc.yuv420.monochrome.odd-width.avif \ + fox.profile0.10bpc.yuv420.monochrome.odd-height.avif \ + fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif \ + fox.profile2.12bpc.yuv420.avif \ + fox.profile2.12bpc.yuv420.odd-width.avif \ + fox.profile2.12bpc.yuv420.odd-height.avif \ + fox.profile2.12bpc.yuv420.odd-width.odd-height.avif \ + fox.profile2.12bpc.yuv420.monochrome.avif \ + fox.profile2.12bpc.yuv420.monochrome.odd-width.avif \ + fox.profile2.12bpc.yuv420.monochrome.odd-height.avif \ + fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif \ + fox.profile2.8bpc.yuv422.avif \ + fox.profile2.8bpc.yuv422.odd-width.avif \ + fox.profile2.8bpc.yuv422.odd-height.avif \ + fox.profile2.8bpc.yuv422.odd-width.odd-height.avif \ + fox.profile2.8bpc.yuv422.monochrome.avif \ + fox.profile2.8bpc.yuv422.monochrome.odd-width.avif \ + fox.profile2.8bpc.yuv422.monochrome.odd-height.avif \ + fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif \ + fox.profile2.10bpc.yuv422.avif \ + fox.profile2.10bpc.yuv422.odd-width.avif \ + fox.profile2.10bpc.yuv422.odd-height.avif \ + fox.profile2.10bpc.yuv422.odd-width.odd-height.avif \ + fox.profile2.10bpc.yuv422.monochrome.avif \ + fox.profile2.10bpc.yuv422.monochrome.odd-width.avif \ + fox.profile2.10bpc.yuv422.monochrome.odd-height.avif \ + fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif \ + fox.profile2.12bpc.yuv422.avif \ + fox.profile2.12bpc.yuv422.odd-width.avif \ + fox.profile2.12bpc.yuv422.odd-height.avif \ + fox.profile2.12bpc.yuv422.odd-width.odd-height.avif \ + fox.profile2.12bpc.yuv422.monochrome.avif \ + fox.profile2.12bpc.yuv422.monochrome.odd-width.avif \ + fox.profile2.12bpc.yuv422.monochrome.odd-height.avif \ + fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif \ + fox.profile1.8bpc.yuv444.avif \ + fox.profile1.8bpc.yuv444.odd-width.avif \ + fox.profile1.8bpc.yuv444.odd-height.avif \ + fox.profile1.8bpc.yuv444.odd-width.odd-height.avif \ + fox.profile1.10bpc.yuv444.avif \ + fox.profile1.10bpc.yuv444.odd-width.avif \ + fox.profile1.10bpc.yuv444.odd-height.avif \ + fox.profile1.10bpc.yuv444.odd-width.odd-height.avif \ + fox.profile2.12bpc.yuv444.avif \ + fox.profile2.12bpc.yuv444.odd-width.avif \ + fox.profile2.12bpc.yuv444.odd-height.avif \ + fox.profile2.12bpc.yuv444.odd-width.odd-height.avif \ + fox.profile2.12bpc.yuv444.monochrome.avif \ + fox.profile2.12bpc.yuv444.monochrome.odd-width.avif \ + fox.profile2.12bpc.yuv444.monochrome.odd-height.avif \ + fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif + +fox: $(FOX); + +PLUM_LARGE=\ + plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif \ + plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif \ + plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif \ + plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif \ + plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif \ + plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif \ + plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif \ + plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif \ + plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif \ + plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif \ + plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif \ + plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif \ + plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif \ + plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif \ + plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif \ + plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif \ + plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif \ + plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif \ + plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif \ + plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif \ + plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif \ + plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif \ + plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif \ + plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif \ + plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif \ + plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif \ + plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif \ + plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif \ + plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif \ + plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif \ + plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif \ + plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif + +PLUM_SMALL=\ + plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif \ + plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif \ + plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif \ + plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif \ + plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif \ + plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif \ + plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif \ + plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif \ + plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif \ + plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif \ + plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif \ + plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif \ + plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif \ + plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif \ + plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif \ + plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif \ + plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif \ + plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif \ + plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif \ + plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif \ + plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif \ + plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif \ + plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif \ + plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif \ + plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif \ + plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif \ + plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif \ + plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif \ + plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif \ + plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif \ + plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif \ + plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif + +PLUM=$(PLUM_LARGE) $(PLUM_SMALL) + +plum: $(PLUM); + +STAR=\ + star-8bpc.avifs \ + star-8bpc-with-alpha.avifs \ + star-10bpc.avifs \ + star-10bpc-with-alpha.avifs \ + star-12bpc.avifs \ + star-12bpc-with-alpha.avifs + +star: $(STAR); + +ALL_AVIF=$(HATO) $(KIMONO) $(FOX) $(PLUM) +ALL_AVIFS=$(STAR) +DECODED_PNG=$(ALL_AVIF:%.avif=decoded/%.png) +DUMMY_CHECK_TARGETS=$(ALL_AVIF:%.avif=%.check) + +.PHONY: all clean \ + hato kimono fox plum \ + star \ + decode decode-clean decode-images \ + url hato-url kimono-url fox-url plum-url\ + compare $(DUMMY_CHECK_TARGETS) + +decode-clean: + rm -Rf decoded/ + +$(DECODED_PNG): | decoded + +decoded: + mkdir -p decoded + +decode-images: $(DECODED_PNG); + +decode: + $(MAKE) decode-clean + $(MAKE) decode-images + +compare: $(DUMMY_CHECK_TARGETS); + +decoded/%.png: %.avif + $(DAVIF) -i $< -o $@ + +$(DUMMY_CHECK_TARGETS): %.check: %.avif decoded/%.png + bash -e scripts/compare.sh $@ $(word 1,$^) $(word 2,$^) + +url: + cat Makefile | grep '^.*\?\.avif:' | sort -d | sed 's/^\(.*\)\:\s*\(.*\)$\/https\:\/\/raw.githubusercontent.com\/link-u\/avif-sample-images\/master\/\1, https\:\/\/raw.githubusercontent.com\/link-u\/avif-sample-images\/master\/\2/' + +hato-url: + $(MAKE) url | grep hato + +kimono-url: + $(MAKE) url | grep kimono + +fox-url: + $(MAKE) url | grep fox + +plum-url: + $(MAKE) url | grep plum-blossom + +clean: + rm -Rf *.avif decoded .alpha-masks + +## hato + +### YUV422 + +hato.profile2.8bpc.yuv422.avif: hato.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +hato.profile2.8bpc.yuv422.monochrome.avif: hato.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --monochrome --cpu-used 0 --rate-control q --crf 18 + +hato.profile2.10bpc.yuv422.avif: hato.16bpc.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +hato.profile2.10bpc.yuv422.monochrome.avif: hato.16bpc.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --monochrome --cpu-used 0 --rate-control q --crf 18 + +hato.profile2.12bpc.yuv422.avif: hato.16bpc.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +hato.profile2.12bpc.yuv422.monochrome.avif: hato.16bpc.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --monochrome --cpu-used 0 --rate-control q --crf 18 + +### YUV420 + +hato.profile0.8bpc.yuv420.avif: hato.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +hato.profile0.8bpc.yuv420.monochrome.avif: hato.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --monochrome --cpu-used 0 --rate-control q --crf 18 + +hato.profile0.10bpc.yuv420.avif: hato.16bpc.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +hato.profile0.10bpc.yuv420.monochrome.avif: hato.16bpc.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --monochrome --cpu-used 0 --rate-control q --crf 18 + +## Kimono + +kimono.avif: kimono.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +kimono.rotate90.avif: kimono.rotate90.png + $(CAVIF) -i $< -o $@ --rotation 270 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +kimono.rotate270.avif: kimono.rotate270.png + $(CAVIF) -i $< -o $@ --rotation 90 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +kimono.mirror-horizontal.avif: kimono.mirror-horizontal.png + $(CAVIF) -i $< -o $@ --mirror horizontal --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +kimono.mirror-vertical.avif: kimono.mirror-vertical.png + $(CAVIF) -i $< -o $@ --mirror vertical --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +kimono.mirror-vertical.rotate270.avif: kimono.mirror-vertical.rotate270.png + $(CAVIF) -i $< -o $@ --mirror vertical --rotation 90 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +kimono.crop.avif: kimono.png + $(CAVIF) -i $< -o $@ --crop-offset 103,-308 --crop-size 385,330 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +kimono.mirror-vertical.rotate270.crop.avif: kimono.mirror-vertical.rotate270.png + $(CAVIF) -i $< -o $@ --crop-offset -308,103 --crop-size 330,385 --mirror vertical --rotation 90 --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +## Fox Parade + +### YUV420 + +#### 8bit + +fox.profile0.8bpc.yuv420.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.8bpc.yuv420.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.8bpc.yuv420.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.8bpc.yuv420.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.8bpc.yuv420.monochrome.avif: fox.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.8bpc.yuv420.monochrome.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.8bpc.yuv420.monochrome.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +#### 10bit + +fox.profile0.10bpc.yuv420.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.10bpc.yuv420.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.10bpc.yuv420.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.10bpc.yuv420.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.10bpc.yuv420.monochrome.avif: fox.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.10bpc.yuv420.monochrome.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.10bpc.yuv420.monochrome.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +#### 12bit + +fox.profile2.12bpc.yuv420.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv420.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv420.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv420.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv420.monochrome.avif: fox.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv420.monochrome.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv420.monochrome.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +### YUV422 + +#### 8bit + +fox.profile2.8bpc.yuv422.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.8bpc.yuv422.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.8bpc.yuv422.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.8bpc.yuv422.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.8bpc.yuv422.monochrome.avif: fox.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.8bpc.yuv422.monochrome.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.8bpc.yuv422.monochrome.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +#### 10bit + +fox.profile2.10bpc.yuv422.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.10bpc.yuv422.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.10bpc.yuv422.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.10bpc.yuv422.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.10bpc.yuv422.monochrome.avif: fox.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.10bpc.yuv422.monochrome.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.10bpc.yuv422.monochrome.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +#### 12bit + +fox.profile2.12bpc.yuv422.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv422.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv422.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv422.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv422.monochrome.avif: fox.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv422.monochrome.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv422.monochrome.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +### YUV444 + +#### 8bit + +fox.profile1.8bpc.yuv444.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile1.8bpc.yuv444.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile1.8bpc.yuv444.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile1.8bpc.yuv444.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +#### 10bit + +fox.profile1.10bpc.yuv444.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile1.10bpc.yuv444.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile1.10bpc.yuv444.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile1.10bpc.yuv444.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +#### 12bit + +fox.profile2.12bpc.yuv444.avif: fox.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv444.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv444.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv444.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv444.monochrome.avif: fox.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv444.monochrome.odd-width.avif: fox.odd-width.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv444.monochrome.odd-height.avif: fox.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif: fox.odd-width.odd-height.png + $(CAVIF) -i $< -o $@ --monochrome --tune psnr --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +## Alpha mask + +.alpha-masks: + mkdir -p .alpha-masks + +$(PLUM): | .alpha-masks + +## Plum blossom - large version + +### YUV420 + +#### 8bit + +plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 10bit + +plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 12bit + +plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +## YUV422 + +#### 8bit + +plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 10bit + +plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 12bit + +plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +### YUV444 + +#### 8bit + +plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +#### 10bit + +plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +#### 12bit + +plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif: plum-blossom-large.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome + +## Plum blossom - small version + +### YUV420 + +#### 8bit + +plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 8 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 10bit + +plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 0 --bit-depth 10 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 12bit + +plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv420 --cpu-used 0 --rate-control q --crf 18 --monochrome + +## YUV422 + +#### 8bit + +plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 10bit + +plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +#### 12bit + +plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv422 --cpu-used 0 --rate-control q --crf 18 --monochrome + +### YUV444 + +#### 8bit + +plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 8 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 8 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +#### 10bit + +plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 10 --pix-fmt yuv422 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 1 --bit-depth 10 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +#### 12bit + +plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome + +plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 + +plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif: plum-blossom-small.png + $(CAVIF) -i $< -o .alpha-masks/$@ --encode-target alpha --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --lossless --monochrome --enable-full-color-range + $(CAVIF) -i $< -o $@ --tune psnr --encode-target image --attach-alpha .alpha-masks/$@ --profile 2 --bit-depth 12 --pix-fmt yuv444 --cpu-used 0 --rate-control q --crf 18 --monochrome + +star-8bpc.avifs: star.input.txt + $(eval TMP := $(shell mktemp -d)) + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv420p -color_range jpeg -b:v 0 -crf 0 -lossless 1 $(TMP)/star.mp4 + # You need the latest version of gpac. + # Go to https://github.com/gpac/gpac + # then, `make deb -j32` + MP4Box -add-image $(TMP)/star.mp4:id=1:primary -new $@ + MP4Box -ab avis -ab msf1 -ab miaf -ab MA1B -rb mif1 -brand avis $@ + MP4Box -add $(TMP)/star.mp4:hdlr=pict:ccst:name="GPAC avifs" $@ + rm -Rfv $(TMP) + +# FIXME(ledya-z): WORK IN PROGRESS +star-8bpc-with-alpha.avifs: star.input.txt + $(eval TMP := $(shell mktemp -d)) + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv420p -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-video.mp4" + # FIXME(ledyba-z): It does not generate monochrome OBUs. + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt gray -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-alpha.mp4" + # You need the latest version of gpac. + # Go to https://github.com/gpac/gpac + # then, `make deb -j32` + + MP4Box -raw-layer "1:output=$(TMP)/star-video" "$(TMP)/star-video.mp4" + MP4Box -raw-layer "1:output=$(TMP)/star-alpha" "$(TMP)/star-alpha.mp4" + + MP4Box -add-image "$(TMP)/star-alpha.av1:id=3:ref=auxl,4:alpha:name=Alpha" -add-image "$(TMP)/star-video.av1:id=4:name=Color" -set-primary 4 -ab avif -new $@ + MP4Box -add "$(TMP)/star-video.av1:hdlr=pict:ccst:name=\"GPAC avifs\"" -add "$(TMP)/star-alpha.av1:hdlr=auxv:ccst:alpha:name=\"GPAC avifs alpha\"" -ref 2:auxl:1 -ab msf1 -ab miaf -ab MA1B -brand avis $@ + rm -Rfv $(TMP) + +star-10bpc.avifs: star.input.txt + $(eval TMP := $(shell mktemp -d)) + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv422p10 -color_range jpeg -b:v 0 -crf 0 -lossless 1 $(TMP)/star.mp4 + # You need the latest version of gpac. + # Go to https://github.com/gpac/gpac + # then, `make deb -j32` + MP4Box -add-image $(TMP)/star.mp4:id=1:primary -new $@ + MP4Box -ab avis -ab msf1 -ab miaf -ab MA1B -rb mif1 -brand avis $@ + MP4Box -add $(TMP)/star.mp4:hdlr=pict:ccst:name="GPAC avifs" $@ + rm -Rfv $(TMP) + +# FIXME(ledya-z): WORK IN PROGRESS +star-10bpc-with-alpha.avifs: star.input.txt + $(eval TMP := $(shell mktemp -d)) + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv422p10 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-video.mp4" + # FIXME(ledyba-z): It does not generate monochrome OBUs. + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt gray10 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-alpha.mp4" + # You need the latest version of gpac. + # Go to https://github.com/gpac/gpac + # then, `make deb -j32` + + MP4Box -raw-layer "1:output=$(TMP)/star-video" "$(TMP)/star-video.mp4" + MP4Box -raw-layer "1:output=$(TMP)/star-alpha" "$(TMP)/star-alpha.mp4" + + MP4Box -add-image "$(TMP)/star-alpha.av1:id=3:ref=auxl,4:alpha:name=Alpha" -add-image "$(TMP)/star-video.av1:id=4:name=Color" -set-primary 4 -ab avif -new $@ + MP4Box -add "$(TMP)/star-video.av1:hdlr=pict:ccst:name=\"GPAC avifs\"" -add "$(TMP)/star-alpha.av1:hdlr=auxv:ccst:alpha:name=\"GPAC avifs alpha\"" -ref 2:auxl:1 -ab msf1 -ab miaf -ab MA1B -brand avis $@ + rm -Rfv $(TMP) + +star-12bpc.avifs: star.input.txt + $(eval TMP := $(shell mktemp -d)) + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv444p12 -color_range jpeg -b:v 0 -crf 0 -lossless 1 $(TMP)/star.mp4 + # You need the latest version of gpac. + # Go to https://github.com/gpac/gpac + # then, `make deb -j32` + MP4Box -add-image $(TMP)/star.mp4:id=1:primary -new $@ + MP4Box -ab avis -ab msf1 -ab miaf -ab MA1B -rb mif1 -brand avis $@ + MP4Box -add $(TMP)/star.mp4:hdlr=pict:ccst:name="GPAC avifs" $@ + rm -Rfv $(TMP) + +# FIXME(ledya-z): WORK IN PROGRESS +star-12bpc-with-alpha.avifs: star.input.txt + $(eval TMP := $(shell mktemp -d)) + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt yuv444p12 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-video.mp4" + # FIXME(ledyba-z): It does not generate monochrome OBUs. + ~/umi/src/git.ffmpeg.org/ffmpeg/ffmpeg -r 10 -f concat -i star.input.txt -strict -2 -vcodec av1 -pix_fmt gray12 -color_range mpeg -b:v 0 -crf 0 -lossless 1 "$(TMP)/star-alpha.mp4" + # You need the latest version of gpac. + # Go to https://github.com/gpac/gpac + # then, `make deb -j32` + + MP4Box -raw-layer "1:output=$(TMP)/star-video" "$(TMP)/star-video.mp4" + MP4Box -raw-layer "1:output=$(TMP)/star-alpha" "$(TMP)/star-alpha.mp4" + + MP4Box -add-image "$(TMP)/star-alpha.av1:id=3:ref=auxl,4:alpha:name=Alpha" -add-image "$(TMP)/star-video.av1:id=4:name=Color" -set-primary 4 -ab avif -new $@ + MP4Box -add "$(TMP)/star-video.av1:hdlr=pict:ccst:name=\"GPAC avifs\"" -add "$(TMP)/star-alpha.av1:hdlr=auxv:ccst:alpha:name=\"GPAC avifs alpha\"" -ref 2:auxl:1 -ab msf1 -ab miaf -ab MA1B -brand avis $@ + rm -Rfv $(TMP) diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/README.md b/third_party/rust/mp4parse/link-u-avif-sample-images/README.md index 6b803ec823d0..3125518b98f2 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/README.md +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/README.md @@ -1,582 +1,582 @@ -# AVIF Example files. - -![Encode all images and decode them again weekly.](https://github.com/link-u/avif-sample-images/workflows/Encode%20all%20images%20and%20decode%20them%20again%20weekly./badge.svg) - -- All files do not contain Exif metadata. -- All files are tagged as MIAF compatible. -- All files are tagged as compatible with the AVIF Baseline or Advanced Profile if possible. -- All images have the "reduced_still_picture_header" and "still_picture" flags set to 1 in the AV1 Sequence Header. -- Most images are licensed under [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en), but some files are licensed different license. Please check. - -[Makefile](Makefile) describes how they were created. To generate files yourself, you have to install [cavif](https://github.com/link-u/cavif) and [davif](https://github.com/link-u/davif) - -## hato - -![hato.jpg](hato.jpg) - - - size: 3082x2048 - - License: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) - - Author: Kaede Fujisaki ([@ledyba](https://github.com/ledyba)) - - Retrieved from [her website](https://hexe.net/2017/11/27/12:27:02/). - -### AVIF version - -#### YUV 420 - -| profile | bit depth | Monochrome | file | -|---------|-----------|------------|--------------------------------------------------| -| 0 | 8 | | [here](hato.profile0.8bpc.yuv420.avif) | -| 0 | 8 | YES | [here](hato.profile0.8bpc.yuv420.monochromeavif) | -| 0 | 10 | | [here](hato.profile0.10bpc.yuv420.avif) | -| 0 | 10 | YES | [here](hato.profile0.10bpc.yuv420.avif) | - -#### YUV422 - -| profile | bit depth | Monochrome | file | -|---------|-----------|------------|---------------------------------------------------| -| 2 | 8 | | [here](hato.profile2.8bpc.yuv422.avif) | -| 2 | 8 | YES | [here](hato.profile2.8bpc.yuv422.monochrome.avif) | -| 2 | 10 | | [here](hato.profile2.10bpc.yuv422.avif) | -| 2 | 10 | YES | [here](hato.profile2.10bpc.yuv422.avif) | -| 2 | 12 | | [here](hato.profile2.12bpc.yuv422.avif) | -| 2 | 12 | YES | [here](hato.profile2.12bpc.yuv422.avif) | - -#### URLS - -You can obtain this list with `make hato-url`. - -``` -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.10bpc.yuv420.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.10bpc.yuv420.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.8bpc.yuv420.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.8bpc.yuv420.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.10bpc.yuv422.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.10bpc.yuv422.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.12bpc.yuv422.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.12bpc.yuv422.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.8bpc.yuv422.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.8bpc.yuv422.monochrome.avif -``` - -## Kimono - Transformation tests - -[kimono.jpg](kimono.jpg) - - - size: 722x1024 - - License: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) - - Authors: Momiji Jinzamomi([@momiji-san](https://github.com/momiji-san)) and Kaede Fujisaki ([@ledyba](https://github.com/ledyba)) - - Retrieved from [their website](https://hexe.net/2018/12/24/18:59:01/). - - -Test images for rotation(`irot`), mirroring(`imir`), cropping(`clap`). - -All AVIF images are encoded in these settings: - - - Profile 0 - - YUV420 - - 8 bits per component - -### FYI: Transform operation order - -[MIAF](https://www.iso.org/standard/74417.html) defines the transform operation order(p.16): - -> These properties, if used, shall be indicated to be applied in the following order: -> clean aperture first, then rotation, then mirror. - -### Identity - -[kimono.avif](./kimono.avif) - -No operation is applied. - -### Rotation 90 - -[kimono.rotate90.avif](./kimono.rotate90.avif) - -[Encoded image is rotated at 90 degree in counter-clockwise](kimono.rotate90.png), and marked to rotate it 270 degree in counter-clockwise when displaying. Thus, resulted image is as the same as the original. - -### Rotation 270 - -[kimono.rotate270.avif](./kimono.rotate270.avif) - -[Encoded image is rotated at 270 degree in counter-clockwise](kimono.rotate270.png), and marked to rotate it 90 degree in counter-clockwise when displaying. Thus, resulted image is as the same as the original. - - -### Mirroring horizontally - -[kimono.mirror-horizontal.avif](./kimono.mirror-horizontal.avif) - -[Encoded image is mirrored horizontally](kimono.mirror-horizontal.png), and marked to mirror it horizontally again when displaying. Thus, resulted image is as the same as the original. - -### Mirroring vertically - -[kimono.mirror-vertical.avif](./kimono.mirror-vertical.avif) - -Vertical version. Same as above. - -### Mirroring vertically + Rotating at 90 degrees. - -[kimono.mirror-vertical.rotate270.avif](./kimono.mirror-vertical.rotate270.avif) - -[Encoded image is mirrored vertically, then rorated at 90 degree in clockwise](kimono.mirror-vertical.rotate270.png), and marked to rotate it at 90 degree in counter-clockwise and then mirror it vertically when displaying. - -Thus, resulted image is as the same as the original. - -### Cropping - -[kimono.crop.avif](kimono.crop.avif) - -Displaying image will be cropped from the original image, using `CleanApertureBox`(See: ISO/IEC 14496-12:2015). - -Cropped under these condition: - - - cleanApertureWidthN: 385 - - cleanApertureWidthD: 1 - - cleanApertureHeightN: 330 - - cleanApertureHeightD: 1 - - horizOffN: 103 - - horizOffD: 1 - - vertOffN: -308 (This can be negative, as mensioned in ISO/IEC 14496-12:2015). - - vertOffD: 1 - -Resulted image should be: - -![kimono.crop.png](kimono.crop.png) - -### Cropping + Mirroring vertically + Rotating at 90 degrees. - -[kimono.mirror-vertical.rotate270.crop.avif](kimono.mirror-vertical.rotate270.crop.avif) - -[Encoded image is mirrored vertically, then rorated at 90 degree in clockwise](kimono.mirror-vertical.rotate270.png), and marked to crop it first, rotate it at 90 degree in counter-clockwise, and then mirror it vertically. - -Cropping condition is: - -- cleanApertureWidthN: 330 -- cleanApertureWidthD: 1 -- cleanApertureHeightN: 385 -- cleanApertureHeightD: 1 -- horizOffN: -308 -- horizOffD: 1 -- vertOffN: 103 -- vertOffD: 1 - -Resulted image should be as the same as above. - -![kimono.crop.png](kimono.crop.png) - -### URLS - -You can obtain this list with `make kimono-url`. - -``` -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.crop.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-horizontal.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-vertical.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-vertical.rotate270.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-vertical.rotate270.crop.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.rotate270.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.rotate90.avif -``` - -## Fox Parade - Odd dimensions images - -### Original - -[fox.jpg](fox.jpg) - - - size: 1204 x 800 - - License: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) - - Author: Kaede Fujisaki ([@ledyba](https://github.com/ledyba)) - - Retrieved from [her website](https://hexe.net/2017/12/02/16:33:53/). - -#### Odd-Width - - - [fox.odd-width.png](fox.odd-width.png) - - size: 1203 x 800 - -#### Odd-Height - - - [fox.odd-height.png](fox.odd-height.png) - - size: 1204 x 799 - -#### Odd-Width x Odd-Height - - - [fox.odd-width.odd-height.png](fox.odd-width.odd-height.png) - - size: 1203 x 799 - -### AVIF version - -| profile | bit depth | pix fmt | Monochrome | odd width | odd height | file | -|---------|-----------|---------|------------|-----------|------------|------------------------------------------------------------------------| -| 0 | 8 | YUV420 | | | | [here](fox.profile0.8bpc.yuv420.avif) | -| 0 | 8 | YUV420 | | YES | | [here](fox.profile0.8bpc.yuv420.odd-width.avif) | -| 0 | 8 | YUV420 | | | YES | [here](fox.profile0.8bpc.yuv420.odd-height.avif) | -| 0 | 8 | YUV420 | | YES | YES | [here](fox.profile0.8bpc.yuv420.odd-width.odd-height.avif) | -| 0 | 8 | YUV420 | YES | | | [here](fox.profile0.8bpc.yuv420.monochrome.avif) | -| 0 | 8 | YUV420 | YES | YES | | [here](fox.profile0.8bpc.yuv420.monochrome.odd-width.avif) | -| 0 | 8 | YUV420 | YES | | YES | [here](fox.profile0.8bpc.yuv420.monochrome.odd-height.avif) | -| 0 | 8 | YUV420 | YES | YES | YES | [here](fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif) | -| 0 | 10 | YUV420 | | | | [here](fox.profile0.10bpc.yuv420.avif) | -| 0 | 10 | YUV420 | | YES | | [here](fox.profile0.10bpc.yuv420.odd-width.avif) | -| 0 | 10 | YUV420 | | | YES | [here](fox.profile0.10bpc.yuv420.odd-height.avif) | -| 0 | 10 | YUV420 | | YES | YES | [here](fox.profile0.10bpc.yuv420.odd-width.odd-height.avif) | -| 0 | 10 | YUV420 | YES | | | [here](fox.profile0.10bpc.yuv420.monochrome.avif) | -| 0 | 10 | YUV420 | YES | YES | | [here](fox.profile0.10bpc.yuv420.monochrome.odd-width.avif) | -| 0 | 10 | YUV420 | YES | | YES | [here](fox.profile0.10bpc.yuv420.monochrome.odd-height.avif) | -| 0 | 10 | YUV420 | YES | YES | YES | [here](fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif) | -| 2 | 12 | YUV420 | | | | [here](fox.profile2.12bpc.yuv420.avif) | -| 2 | 12 | YUV420 | | YES | | [here](fox.profile2.12bpc.yuv420.odd-width.avif) | -| 2 | 12 | YUV420 | | | YES | [here](fox.profile2.12bpc.yuv420.odd-height.avif) | -| 2 | 12 | YUV420 | | YES | YES | [here](fox.profile2.12bpc.yuv420.odd-width.odd-height.avif) | -| 2 | 12 | YUV420 | YES | | | [here](fox.profile2.12bpc.yuv420.monochrome.avif) | -| 2 | 12 | YUV420 | YES | YES | | [here](fox.profile2.12bpc.yuv420.monochrome.odd-width.avif) | -| 2 | 12 | YUV420 | YES | | YES | [here](fox.profile2.12bpc.yuv420.monochrome.odd-height.avif) | -| 2 | 12 | YUV420 | YES | YES | YES | [here](fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif) | -| 2 | 8 | YUV422 | | | | [here](fox.profile2.8bpc.yuv422.avif) | -| 2 | 8 | YUV422 | | YES | | [here](fox.profile2.8bpc.yuv422.odd-width.avif) | -| 2 | 8 | YUV422 | | | YES | [here](fox.profile2.8bpc.yuv422.odd-height.avif) | -| 2 | 8 | YUV422 | | YES | YES | [here](fox.profile2.8bpc.yuv422.odd-width.odd-height.avif) | -| 2 | 8 | YUV422 | YES | | | [here](fox.profile2.8bpc.yuv422.monochrome.avif) | -| 2 | 8 | YUV422 | YES | YES | | [here](fox.profile2.8bpc.yuv422.monochrome.odd-width.avif) | -| 2 | 8 | YUV422 | YES | | YES | [here](fox.profile2.8bpc.yuv422.monochrome.odd-height.avif) | -| 2 | 8 | YUV422 | YES | YES | YES | [here](fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif) | -| 2 | 10 | YUV422 | | | | [here](fox.profile2.10bpc.yuv422.avif) | -| 2 | 10 | YUV422 | | YES | | [here](fox.profile2.10bpc.yuv422.odd-width.avif) | -| 2 | 10 | YUV422 | | | YES | [here](fox.profile2.10bpc.yuv422.odd-height.avif) | -| 2 | 10 | YUV422 | | YES | YES | [here](fox.profile2.10bpc.yuv422.odd-width.odd-height.avif) | -| 2 | 10 | YUV422 | YES | | | [here](fox.profile2.10bpc.yuv422.monochrome.avif) | -| 2 | 10 | YUV422 | YES | YES | | [here](fox.profile2.10bpc.yuv422.monochrome.odd-width.avif) | -| 2 | 10 | YUV422 | YES | | YES | [here](fox.profile2.10bpc.yuv422.monochrome.odd-height.avif) | -| 2 | 10 | YUV422 | YES | YES | YES | [here](fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif) | -| 2 | 12 | YUV422 | | | | [here](fox.profile2.12bpc.yuv422.avif) | -| 2 | 12 | YUV422 | | YES | | [here](fox.profile2.12bpc.yuv422.odd-width.avif) | -| 2 | 12 | YUV422 | | | YES | [here](fox.profile2.12bpc.yuv422.odd-height.avif) | -| 2 | 12 | YUV422 | | YES | YES | [here](fox.profile2.12bpc.yuv422.odd-width.odd-height.avif) | -| 2 | 12 | YUV422 | YES | | | [here](fox.profile2.12bpc.yuv422.monochrome.avif) | -| 2 | 12 | YUV422 | YES | YES | | [here](fox.profile2.12bpc.yuv422.monochrome.odd-width.avif) | -| 2 | 12 | YUV422 | YES | | YES | [here](fox.profile2.12bpc.yuv422.monochrome.odd-height.avif) | -| 2 | 12 | YUV422 | YES | YES | YES | [here](fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif) | -| 1 | 8 | YUV444 | | | | [here](fox.profile1.8bpc.yuv444.avif) | -| 1 | 8 | YUV444 | | YES | | [here](fox.profile1.8bpc.yuv444.odd-width.avif) | -| 1 | 8 | YUV444 | | | YES | [here](fox.profile1.8bpc.yuv444.odd-height.avif) | -| 1 | 8 | YUV444 | | YES | YES | [here](fox.profile1.8bpc.yuv444.odd-width.odd-height.avif) | -| 1 | 10 | YUV444 | | | | [here](fox.profile1.10bpc.yuv444.avif) | -| 1 | 10 | YUV444 | | YES | | [here](fox.profile1.10bpc.yuv444.odd-width.avif) | -| 1 | 10 | YUV444 | | | YES | [here](fox.profile1.10bpc.yuv444.odd-height.avif) | -| 1 | 10 | YUV444 | | YES | YES | [here](fox.profile1.10bpc.yuv444.odd-width.odd-height.avif) | -| 2 | 12 | YUV444 | | | | [here](fox.profile2.12bpc.yuv444.avif) | -| 2 | 12 | YUV444 | | YES | | [here](fox.profile2.12bpc.yuv444.odd-width.avif) | -| 2 | 12 | YUV444 | | | YES | [here](fox.profile2.12bpc.yuv444.odd-height.avif) | -| 2 | 12 | YUV444 | | YES | YES | [here](fox.profile2.12bpc.yuv444.odd-width.odd-height.avif) | -| 2 | 12 | YUV444 | YES | | | [here](fox.profile2.12bpc.yuv444.monochrome.avif) | -| 2 | 12 | YUV444 | YES | YES | | [here](fox.profile2.12bpc.yuv444.monochrome.odd-width.avif) | -| 2 | 12 | YUV444 | YES | | YES | [here](fox.profile2.12bpc.yuv444.monochrome.odd-height.avif) | -| 2 | 12 | YUV444 | YES | YES | YES | [here](fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif) | - -### URLs - -You can obtain this list with `make fox-url`. - -``` -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.odd-height.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.odd-width.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.odd-width.odd-height.avif -``` -## Plum blossom - test images for alpha planes - -### Original (SVG) - -[![plum-blossom.svg](./plum-blossom.svg)](plum-blossom.svg) - - - License: [CC-BY](https://creativecommons.org/licenses/by/4.0/deed.en) - - Author: Ryo Hirafuji ([@ledyba-z](https://github.com/ledyba-z)) - -#### Large Version (PNG) - - - [plum-blossom-large.png](plum-blossom-large.png) - - size: 2048x2048 - -#### Small Version (PNG) - - - [plum-blossom-small.png](plum-blossom-small.png) - - size: 128x128 - -### AVIF version (Large Version) - -#### Limited-ranged alpha - -| profile | bit depth | pix fmt | Monochrome | alpha | file | -|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| -| 0 | 8 | YUV420 | | limited | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif) | -| 0 | 8 | YUV420 | YES | limited | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif) | -| 0 | 10 | YUV420 | | limited | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif) | -| 0 | 10 | YUV420 | YES | limited | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif) | -| 2 | 12 | YUV420 | | limited | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif) | -| 2 | 12 | YUV420 | YES | limited | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif) | -| 2 | 8 | YUV422 | | limited | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif) | -| 2 | 8 | YUV422 | YES | limited | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif) | -| 2 | 10 | YUV422 | | limited | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif) | -| 2 | 10 | YUV422 | YES | limited | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif) | -| 2 | 12 | YUV422 | | limited | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif) | -| 2 | 12 | YUV422 | YES | limited | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif) | -| 1 | 8 | YUV444 | | limited | [here](plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif) | -| 1 | 10 | YUV444 | | limited | [here](plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif) | -| 2 | 12 | YUV444 | | limited | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif) | -| 2 | 12 | YUV444 | YES | limited | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif) | - -#### Full-ranged alpha - -| profile | bit depth | pix fmt | Monochrome | alpha | file | -|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| -| 0 | 8 | YUV420 | | full | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif) | -| 0 | 8 | YUV420 | YES | full | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif) | -| 0 | 10 | YUV420 | | full | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif) | -| 0 | 10 | YUV420 | YES | full | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif) | -| 2 | 12 | YUV420 | | full | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif) | -| 2 | 12 | YUV420 | YES | full | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif) | -| 2 | 8 | YUV422 | | full | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif) | -| 2 | 8 | YUV422 | YES | full | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif) | -| 2 | 10 | YUV422 | | full | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif) | -| 2 | 10 | YUV422 | YES | full | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif) | -| 2 | 12 | YUV422 | | full | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif) | -| 2 | 12 | YUV422 | YES | full | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif) | -| 1 | 8 | YUV444 | | full | [here](plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif) | -| 1 | 10 | YUV444 | | full | [here](plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif) | -| 2 | 12 | YUV444 | | full | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif) | -| 2 | 12 | YUV444 | YES | full | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif) | - -### AVIF version (Small Version) - -#### Limited-ranged alpha - -| profile | bit depth | pix fmt | Monochrome | alpha | file | -|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| -| 0 | 8 | YUV420 | | limited | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif) | -| 0 | 8 | YUV420 | YES | limited | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif) | -| 0 | 10 | YUV420 | | limited | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif) | -| 0 | 10 | YUV420 | YES | limited | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif) | -| 2 | 12 | YUV420 | | limited | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif) | -| 2 | 12 | YUV420 | YES | limited | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif) | -| 2 | 8 | YUV422 | | limited | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif) | -| 2 | 8 | YUV422 | YES | limited | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif) | -| 2 | 10 | YUV422 | | limited | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif) | -| 2 | 10 | YUV422 | YES | limited | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif) | -| 2 | 12 | YUV422 | | limited | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif) | -| 2 | 12 | YUV422 | YES | limited | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif) | -| 1 | 8 | YUV444 | | limited | [here](plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif) | -| 1 | 10 | YUV444 | | limited | [here](plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif) | -| 2 | 12 | YUV444 | | limited | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif) | -| 2 | 12 | YUV444 | YES | limited | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif) | - -#### Full-ranged alpha - -| profile | bit depth | pix fmt | Monochrome | alpha | file | -|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| -| 0 | 8 | YUV420 | | full | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif) | -| 0 | 8 | YUV420 | YES | full | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif) | -| 0 | 10 | YUV420 | | full | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif) | -| 0 | 10 | YUV420 | YES | full | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif) | -| 2 | 12 | YUV420 | | full | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif) | -| 2 | 12 | YUV420 | YES | full | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif) | -| 2 | 8 | YUV422 | | full | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif) | -| 2 | 8 | YUV422 | YES | full | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif) | -| 2 | 10 | YUV422 | | full | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif) | -| 2 | 10 | YUV422 | YES | full | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif) | -| 2 | 12 | YUV422 | | full | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif) | -| 2 | 12 | YUV422 | YES | full | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif) | -| 1 | 8 | YUV444 | | full | [here](plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif) | -| 1 | 10 | YUV444 | | full | [here](plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif) | -| 2 | 12 | YUV444 | | full | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif) | -| 2 | 12 | YUV444 | YES | full | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif) | - -### URLs - -You can obtain this list with `make plum-url`. - -``` -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif -https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif -``` - -## Red at 12 o'clock with color profile - ICC Profile tests - -![red-at-12-oclock-with-color-profile.jpg](red-at-12-oclock-with-color-profile) - - - License: GNU LGPL v2.1 or 2 claused BSD License - - Author: Tony Payne - - [commit](https://chromium.googlesource.com/chromium/src/+/e89ab1941644ff34b262cac05f23e82b7e249377) - -### AVIF version - - - [red-at-12-oclock-with-color-profile-lossy.avif](red-at-12-oclock-with-color-profile-lossy.avif) - - [red-at-12-oclock-with-color-profile-8bpc.avif](red-at-12-oclock-with-color-profile-8bpc.avif) - - [red-at-12-oclock-with-color-profile-10bpc.avif](red-at-12-oclock-with-color-profile-10bpc.avif) - - [red-at-12-oclock-with-color-profile-12bpc.avif](red-at-12-oclock-with-color-profile-12bpc.avif) - -## Twinkle Star - Image Sequence Test - -[![star.gif](star.gif)](star.gif) - - - [AV1 mp4 version](star.mp4) - -### Original (SVG) - -[![star.svg](./star.svg)](star.svg) - - - License: [CC-BY](https://creativecommons.org/licenses/by/4.0/deed.en) - - Author: Ryo Hirafuji ([@ledyba-z](https://github.com/ledyba-z)) - - Special Thanks: [Shigatake's Pixel Art Lesson](http://shigatake.sakura.ne.jp/gallery/dot/dot_1.html) - -### AVIFS version - -#### Normal - -- [star-8bpc.avifs](star-8bpc.avifs) - - YUV420 - - full-ranged color -- [star-10bpc.avifs](star-10bpc.avifs) - - YUV422 - - full-ranged color -- [star-12bpc.avifs](star-12bpc.avifs) - - YUV444 - - full-ranged color - -- [star-8bpc-with-alpha.avifs](star-8bpc-with-alpha.avifs) - - YUV420 - - 8bit - - limited-ranged color - - limited-ranged alpha -- [star-8bpc-with-alpha.avifs](star-10bpc-with-alpha.avifs) - - YUV422 - - 10bit - - limited-ranged color - - limited-ranged alpha -- [star-8bpc-with-alpha.avifs](star-12bpc-with-alpha.avifs) - - YUV444 - - 12bit - - limited-ranged color - - limited-ranged alpha +# AVIF Example files. + +![Encode all images and decode them again weekly.](https://github.com/link-u/avif-sample-images/workflows/Encode%20all%20images%20and%20decode%20them%20again%20weekly./badge.svg) + +- All files do not contain Exif metadata. +- All files are tagged as MIAF compatible. +- All files are tagged as compatible with the AVIF Baseline or Advanced Profile if possible. +- All images have the "reduced_still_picture_header" and "still_picture" flags set to 1 in the AV1 Sequence Header. +- Most images are licensed under [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en), but some files are licensed different license. Please check. + +[Makefile](Makefile) describes how they were created. To generate files yourself, you have to install [cavif](https://github.com/link-u/cavif) and [davif](https://github.com/link-u/davif) + +## hato + +![hato.jpg](hato.jpg) + + - size: 3082x2048 + - License: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) + - Author: Kaede Fujisaki ([@ledyba](https://github.com/ledyba)) + - Retrieved from [her website](https://hexe.net/2017/11/27/12:27:02/). + +### AVIF version + +#### YUV 420 + +| profile | bit depth | Monochrome | file | +|---------|-----------|------------|--------------------------------------------------| +| 0 | 8 | | [here](hato.profile0.8bpc.yuv420.avif) | +| 0 | 8 | YES | [here](hato.profile0.8bpc.yuv420.monochromeavif) | +| 0 | 10 | | [here](hato.profile0.10bpc.yuv420.avif) | +| 0 | 10 | YES | [here](hato.profile0.10bpc.yuv420.avif) | + +#### YUV422 + +| profile | bit depth | Monochrome | file | +|---------|-----------|------------|---------------------------------------------------| +| 2 | 8 | | [here](hato.profile2.8bpc.yuv422.avif) | +| 2 | 8 | YES | [here](hato.profile2.8bpc.yuv422.monochrome.avif) | +| 2 | 10 | | [here](hato.profile2.10bpc.yuv422.avif) | +| 2 | 10 | YES | [here](hato.profile2.10bpc.yuv422.avif) | +| 2 | 12 | | [here](hato.profile2.12bpc.yuv422.avif) | +| 2 | 12 | YES | [here](hato.profile2.12bpc.yuv422.avif) | + +#### URLS + +You can obtain this list with `make hato-url`. + +``` +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.10bpc.yuv420.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.10bpc.yuv420.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.8bpc.yuv420.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile0.8bpc.yuv420.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.10bpc.yuv422.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.10bpc.yuv422.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.12bpc.yuv422.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.12bpc.yuv422.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.8bpc.yuv422.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/hato.profile2.8bpc.yuv422.monochrome.avif +``` + +## Kimono - Transformation tests + +[kimono.jpg](kimono.jpg) + + - size: 722x1024 + - License: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) + - Authors: Momiji Jinzamomi([@momiji-san](https://github.com/momiji-san)) and Kaede Fujisaki ([@ledyba](https://github.com/ledyba)) + - Retrieved from [their website](https://hexe.net/2018/12/24/18:59:01/). + + +Test images for rotation(`irot`), mirroring(`imir`), cropping(`clap`). + +All AVIF images are encoded in these settings: + + - Profile 0 + - YUV420 + - 8 bits per component + +### FYI: Transform operation order + +[MIAF](https://www.iso.org/standard/74417.html) defines the transform operation order(p.16): + +> These properties, if used, shall be indicated to be applied in the following order: +> clean aperture first, then rotation, then mirror. + +### Identity + +[kimono.avif](./kimono.avif) + +No operation is applied. + +### Rotation 90 + +[kimono.rotate90.avif](./kimono.rotate90.avif) + +[Encoded image is rotated at 90 degree in counter-clockwise](kimono.rotate90.png), and marked to rotate it 270 degree in counter-clockwise when displaying. Thus, resulted image is as the same as the original. + +### Rotation 270 + +[kimono.rotate270.avif](./kimono.rotate270.avif) + +[Encoded image is rotated at 270 degree in counter-clockwise](kimono.rotate270.png), and marked to rotate it 90 degree in counter-clockwise when displaying. Thus, resulted image is as the same as the original. + + +### Mirroring horizontally + +[kimono.mirror-horizontal.avif](./kimono.mirror-horizontal.avif) + +[Encoded image is mirrored horizontally](kimono.mirror-horizontal.png), and marked to mirror it horizontally again when displaying. Thus, resulted image is as the same as the original. + +### Mirroring vertically + +[kimono.mirror-vertical.avif](./kimono.mirror-vertical.avif) + +Vertical version. Same as above. + +### Mirroring vertically + Rotating at 90 degrees. + +[kimono.mirror-vertical.rotate270.avif](./kimono.mirror-vertical.rotate270.avif) + +[Encoded image is mirrored vertically, then rorated at 90 degree in clockwise](kimono.mirror-vertical.rotate270.png), and marked to rotate it at 90 degree in counter-clockwise and then mirror it vertically when displaying. + +Thus, resulted image is as the same as the original. + +### Cropping + +[kimono.crop.avif](kimono.crop.avif) + +Displaying image will be cropped from the original image, using `CleanApertureBox`(See: ISO/IEC 14496-12:2015). + +Cropped under these condition: + + - cleanApertureWidthN: 385 + - cleanApertureWidthD: 1 + - cleanApertureHeightN: 330 + - cleanApertureHeightD: 1 + - horizOffN: 103 + - horizOffD: 1 + - vertOffN: -308 (This can be negative, as mensioned in ISO/IEC 14496-12:2015). + - vertOffD: 1 + +Resulted image should be: + +![kimono.crop.png](kimono.crop.png) + +### Cropping + Mirroring vertically + Rotating at 90 degrees. + +[kimono.mirror-vertical.rotate270.crop.avif](kimono.mirror-vertical.rotate270.crop.avif) + +[Encoded image is mirrored vertically, then rorated at 90 degree in clockwise](kimono.mirror-vertical.rotate270.png), and marked to crop it first, rotate it at 90 degree in counter-clockwise, and then mirror it vertically. + +Cropping condition is: + +- cleanApertureWidthN: 330 +- cleanApertureWidthD: 1 +- cleanApertureHeightN: 385 +- cleanApertureHeightD: 1 +- horizOffN: -308 +- horizOffD: 1 +- vertOffN: 103 +- vertOffD: 1 + +Resulted image should be as the same as above. + +![kimono.crop.png](kimono.crop.png) + +### URLS + +You can obtain this list with `make kimono-url`. + +``` +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.crop.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-horizontal.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-vertical.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-vertical.rotate270.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.mirror-vertical.rotate270.crop.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.rotate270.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/kimono.rotate90.avif +``` + +## Fox Parade - Odd dimensions images + +### Original + +[fox.jpg](fox.jpg) + + - size: 1204 x 800 + - License: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) + - Author: Kaede Fujisaki ([@ledyba](https://github.com/ledyba)) + - Retrieved from [her website](https://hexe.net/2017/12/02/16:33:53/). + +#### Odd-Width + + - [fox.odd-width.png](fox.odd-width.png) + - size: 1203 x 800 + +#### Odd-Height + + - [fox.odd-height.png](fox.odd-height.png) + - size: 1204 x 799 + +#### Odd-Width x Odd-Height + + - [fox.odd-width.odd-height.png](fox.odd-width.odd-height.png) + - size: 1203 x 799 + +### AVIF version + +| profile | bit depth | pix fmt | Monochrome | odd width | odd height | file | +|---------|-----------|---------|------------|-----------|------------|------------------------------------------------------------------------| +| 0 | 8 | YUV420 | | | | [here](fox.profile0.8bpc.yuv420.avif) | +| 0 | 8 | YUV420 | | YES | | [here](fox.profile0.8bpc.yuv420.odd-width.avif) | +| 0 | 8 | YUV420 | | | YES | [here](fox.profile0.8bpc.yuv420.odd-height.avif) | +| 0 | 8 | YUV420 | | YES | YES | [here](fox.profile0.8bpc.yuv420.odd-width.odd-height.avif) | +| 0 | 8 | YUV420 | YES | | | [here](fox.profile0.8bpc.yuv420.monochrome.avif) | +| 0 | 8 | YUV420 | YES | YES | | [here](fox.profile0.8bpc.yuv420.monochrome.odd-width.avif) | +| 0 | 8 | YUV420 | YES | | YES | [here](fox.profile0.8bpc.yuv420.monochrome.odd-height.avif) | +| 0 | 8 | YUV420 | YES | YES | YES | [here](fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif) | +| 0 | 10 | YUV420 | | | | [here](fox.profile0.10bpc.yuv420.avif) | +| 0 | 10 | YUV420 | | YES | | [here](fox.profile0.10bpc.yuv420.odd-width.avif) | +| 0 | 10 | YUV420 | | | YES | [here](fox.profile0.10bpc.yuv420.odd-height.avif) | +| 0 | 10 | YUV420 | | YES | YES | [here](fox.profile0.10bpc.yuv420.odd-width.odd-height.avif) | +| 0 | 10 | YUV420 | YES | | | [here](fox.profile0.10bpc.yuv420.monochrome.avif) | +| 0 | 10 | YUV420 | YES | YES | | [here](fox.profile0.10bpc.yuv420.monochrome.odd-width.avif) | +| 0 | 10 | YUV420 | YES | | YES | [here](fox.profile0.10bpc.yuv420.monochrome.odd-height.avif) | +| 0 | 10 | YUV420 | YES | YES | YES | [here](fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif) | +| 2 | 12 | YUV420 | | | | [here](fox.profile2.12bpc.yuv420.avif) | +| 2 | 12 | YUV420 | | YES | | [here](fox.profile2.12bpc.yuv420.odd-width.avif) | +| 2 | 12 | YUV420 | | | YES | [here](fox.profile2.12bpc.yuv420.odd-height.avif) | +| 2 | 12 | YUV420 | | YES | YES | [here](fox.profile2.12bpc.yuv420.odd-width.odd-height.avif) | +| 2 | 12 | YUV420 | YES | | | [here](fox.profile2.12bpc.yuv420.monochrome.avif) | +| 2 | 12 | YUV420 | YES | YES | | [here](fox.profile2.12bpc.yuv420.monochrome.odd-width.avif) | +| 2 | 12 | YUV420 | YES | | YES | [here](fox.profile2.12bpc.yuv420.monochrome.odd-height.avif) | +| 2 | 12 | YUV420 | YES | YES | YES | [here](fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif) | +| 2 | 8 | YUV422 | | | | [here](fox.profile2.8bpc.yuv422.avif) | +| 2 | 8 | YUV422 | | YES | | [here](fox.profile2.8bpc.yuv422.odd-width.avif) | +| 2 | 8 | YUV422 | | | YES | [here](fox.profile2.8bpc.yuv422.odd-height.avif) | +| 2 | 8 | YUV422 | | YES | YES | [here](fox.profile2.8bpc.yuv422.odd-width.odd-height.avif) | +| 2 | 8 | YUV422 | YES | | | [here](fox.profile2.8bpc.yuv422.monochrome.avif) | +| 2 | 8 | YUV422 | YES | YES | | [here](fox.profile2.8bpc.yuv422.monochrome.odd-width.avif) | +| 2 | 8 | YUV422 | YES | | YES | [here](fox.profile2.8bpc.yuv422.monochrome.odd-height.avif) | +| 2 | 8 | YUV422 | YES | YES | YES | [here](fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif) | +| 2 | 10 | YUV422 | | | | [here](fox.profile2.10bpc.yuv422.avif) | +| 2 | 10 | YUV422 | | YES | | [here](fox.profile2.10bpc.yuv422.odd-width.avif) | +| 2 | 10 | YUV422 | | | YES | [here](fox.profile2.10bpc.yuv422.odd-height.avif) | +| 2 | 10 | YUV422 | | YES | YES | [here](fox.profile2.10bpc.yuv422.odd-width.odd-height.avif) | +| 2 | 10 | YUV422 | YES | | | [here](fox.profile2.10bpc.yuv422.monochrome.avif) | +| 2 | 10 | YUV422 | YES | YES | | [here](fox.profile2.10bpc.yuv422.monochrome.odd-width.avif) | +| 2 | 10 | YUV422 | YES | | YES | [here](fox.profile2.10bpc.yuv422.monochrome.odd-height.avif) | +| 2 | 10 | YUV422 | YES | YES | YES | [here](fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif) | +| 2 | 12 | YUV422 | | | | [here](fox.profile2.12bpc.yuv422.avif) | +| 2 | 12 | YUV422 | | YES | | [here](fox.profile2.12bpc.yuv422.odd-width.avif) | +| 2 | 12 | YUV422 | | | YES | [here](fox.profile2.12bpc.yuv422.odd-height.avif) | +| 2 | 12 | YUV422 | | YES | YES | [here](fox.profile2.12bpc.yuv422.odd-width.odd-height.avif) | +| 2 | 12 | YUV422 | YES | | | [here](fox.profile2.12bpc.yuv422.monochrome.avif) | +| 2 | 12 | YUV422 | YES | YES | | [here](fox.profile2.12bpc.yuv422.monochrome.odd-width.avif) | +| 2 | 12 | YUV422 | YES | | YES | [here](fox.profile2.12bpc.yuv422.monochrome.odd-height.avif) | +| 2 | 12 | YUV422 | YES | YES | YES | [here](fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif) | +| 1 | 8 | YUV444 | | | | [here](fox.profile1.8bpc.yuv444.avif) | +| 1 | 8 | YUV444 | | YES | | [here](fox.profile1.8bpc.yuv444.odd-width.avif) | +| 1 | 8 | YUV444 | | | YES | [here](fox.profile1.8bpc.yuv444.odd-height.avif) | +| 1 | 8 | YUV444 | | YES | YES | [here](fox.profile1.8bpc.yuv444.odd-width.odd-height.avif) | +| 1 | 10 | YUV444 | | | | [here](fox.profile1.10bpc.yuv444.avif) | +| 1 | 10 | YUV444 | | YES | | [here](fox.profile1.10bpc.yuv444.odd-width.avif) | +| 1 | 10 | YUV444 | | | YES | [here](fox.profile1.10bpc.yuv444.odd-height.avif) | +| 1 | 10 | YUV444 | | YES | YES | [here](fox.profile1.10bpc.yuv444.odd-width.odd-height.avif) | +| 2 | 12 | YUV444 | | | | [here](fox.profile2.12bpc.yuv444.avif) | +| 2 | 12 | YUV444 | | YES | | [here](fox.profile2.12bpc.yuv444.odd-width.avif) | +| 2 | 12 | YUV444 | | | YES | [here](fox.profile2.12bpc.yuv444.odd-height.avif) | +| 2 | 12 | YUV444 | | YES | YES | [here](fox.profile2.12bpc.yuv444.odd-width.odd-height.avif) | +| 2 | 12 | YUV444 | YES | | | [here](fox.profile2.12bpc.yuv444.monochrome.avif) | +| 2 | 12 | YUV444 | YES | YES | | [here](fox.profile2.12bpc.yuv444.monochrome.odd-width.avif) | +| 2 | 12 | YUV444 | YES | | YES | [here](fox.profile2.12bpc.yuv444.monochrome.odd-height.avif) | +| 2 | 12 | YUV444 | YES | YES | YES | [here](fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif) | + +### URLs + +You can obtain this list with `make fox-url`. + +``` +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.10bpc.yuv420.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile0.8bpc.yuv420.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.10bpc.yuv444.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile1.8bpc.yuv444.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.10bpc.yuv422.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv420.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv422.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.12bpc.yuv444.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.odd-height.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.odd-width.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/fox.profile2.8bpc.yuv422.odd-width.odd-height.avif +``` +## Plum blossom - test images for alpha planes + +### Original (SVG) + +[![plum-blossom.svg](./plum-blossom.svg)](plum-blossom.svg) + + - License: [CC-BY](https://creativecommons.org/licenses/by/4.0/deed.en) + - Author: Ryo Hirafuji ([@ledyba-z](https://github.com/ledyba-z)) + +#### Large Version (PNG) + + - [plum-blossom-large.png](plum-blossom-large.png) + - size: 2048x2048 + +#### Small Version (PNG) + + - [plum-blossom-small.png](plum-blossom-small.png) + - size: 128x128 + +### AVIF version (Large Version) + +#### Limited-ranged alpha + +| profile | bit depth | pix fmt | Monochrome | alpha | file | +|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| +| 0 | 8 | YUV420 | | limited | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif) | +| 0 | 8 | YUV420 | YES | limited | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif) | +| 0 | 10 | YUV420 | | limited | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif) | +| 0 | 10 | YUV420 | YES | limited | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif) | +| 2 | 12 | YUV420 | | limited | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif) | +| 2 | 12 | YUV420 | YES | limited | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif) | +| 2 | 8 | YUV422 | | limited | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif) | +| 2 | 8 | YUV422 | YES | limited | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif) | +| 2 | 10 | YUV422 | | limited | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif) | +| 2 | 10 | YUV422 | YES | limited | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif) | +| 2 | 12 | YUV422 | | limited | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif) | +| 2 | 12 | YUV422 | YES | limited | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif) | +| 1 | 8 | YUV444 | | limited | [here](plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif) | +| 1 | 10 | YUV444 | | limited | [here](plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif) | +| 2 | 12 | YUV444 | | limited | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif) | +| 2 | 12 | YUV444 | YES | limited | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif) | + +#### Full-ranged alpha + +| profile | bit depth | pix fmt | Monochrome | alpha | file | +|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| +| 0 | 8 | YUV420 | | full | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif) | +| 0 | 8 | YUV420 | YES | full | [here](plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif) | +| 0 | 10 | YUV420 | | full | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif) | +| 0 | 10 | YUV420 | YES | full | [here](plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif) | +| 2 | 12 | YUV420 | | full | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif) | +| 2 | 12 | YUV420 | YES | full | [here](plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif) | +| 2 | 8 | YUV422 | | full | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif) | +| 2 | 8 | YUV422 | YES | full | [here](plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif) | +| 2 | 10 | YUV422 | | full | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif) | +| 2 | 10 | YUV422 | YES | full | [here](plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif) | +| 2 | 12 | YUV422 | | full | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif) | +| 2 | 12 | YUV422 | YES | full | [here](plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif) | +| 1 | 8 | YUV444 | | full | [here](plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif) | +| 1 | 10 | YUV444 | | full | [here](plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif) | +| 2 | 12 | YUV444 | | full | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif) | +| 2 | 12 | YUV444 | YES | full | [here](plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif) | + +### AVIF version (Small Version) + +#### Limited-ranged alpha + +| profile | bit depth | pix fmt | Monochrome | alpha | file | +|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| +| 0 | 8 | YUV420 | | limited | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif) | +| 0 | 8 | YUV420 | YES | limited | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif) | +| 0 | 10 | YUV420 | | limited | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif) | +| 0 | 10 | YUV420 | YES | limited | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif) | +| 2 | 12 | YUV420 | | limited | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif) | +| 2 | 12 | YUV420 | YES | limited | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif) | +| 2 | 8 | YUV422 | | limited | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif) | +| 2 | 8 | YUV422 | YES | limited | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif) | +| 2 | 10 | YUV422 | | limited | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif) | +| 2 | 10 | YUV422 | YES | limited | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif) | +| 2 | 12 | YUV422 | | limited | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif) | +| 2 | 12 | YUV422 | YES | limited | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif) | +| 1 | 8 | YUV444 | | limited | [here](plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif) | +| 1 | 10 | YUV444 | | limited | [here](plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif) | +| 2 | 12 | YUV444 | | limited | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif) | +| 2 | 12 | YUV444 | YES | limited | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif) | + +#### Full-ranged alpha + +| profile | bit depth | pix fmt | Monochrome | alpha | file | +|---------|-----------|---------|------------|-------- |--------------------------------------------------------------------------------| +| 0 | 8 | YUV420 | | full | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif) | +| 0 | 8 | YUV420 | YES | full | [here](plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif) | +| 0 | 10 | YUV420 | | full | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif) | +| 0 | 10 | YUV420 | YES | full | [here](plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif) | +| 2 | 12 | YUV420 | | full | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif) | +| 2 | 12 | YUV420 | YES | full | [here](plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif) | +| 2 | 8 | YUV422 | | full | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif) | +| 2 | 8 | YUV422 | YES | full | [here](plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif) | +| 2 | 10 | YUV422 | | full | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif) | +| 2 | 10 | YUV422 | YES | full | [here](plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif) | +| 2 | 12 | YUV422 | | full | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif) | +| 2 | 12 | YUV422 | YES | full | [here](plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif) | +| 1 | 8 | YUV444 | | full | [here](plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif) | +| 1 | 10 | YUV444 | | full | [here](plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif) | +| 2 | 12 | YUV444 | | full | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif) | +| 2 | 12 | YUV444 | YES | full | [here](plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif) | + +### URLs + +You can obtain this list with `make plum-url`. + +``` +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif +https://raw.githubusercontent.com/link-u/avif-sample-images/master/plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif +``` + +## Red at 12 o'clock with color profile - ICC Profile tests + +![red-at-12-oclock-with-color-profile.jpg](red-at-12-oclock-with-color-profile) + + - License: GNU LGPL v2.1 or 2 claused BSD License + - Author: Tony Payne + - [commit](https://chromium.googlesource.com/chromium/src/+/e89ab1941644ff34b262cac05f23e82b7e249377) + +### AVIF version + + - [red-at-12-oclock-with-color-profile-lossy.avif](red-at-12-oclock-with-color-profile-lossy.avif) + - [red-at-12-oclock-with-color-profile-8bpc.avif](red-at-12-oclock-with-color-profile-8bpc.avif) + - [red-at-12-oclock-with-color-profile-10bpc.avif](red-at-12-oclock-with-color-profile-10bpc.avif) + - [red-at-12-oclock-with-color-profile-12bpc.avif](red-at-12-oclock-with-color-profile-12bpc.avif) + +## Twinkle Star - Image Sequence Test + +[![star.gif](star.gif)](star.gif) + + - [AV1 mp4 version](star.mp4) + +### Original (SVG) + +[![star.svg](./star.svg)](star.svg) + + - License: [CC-BY](https://creativecommons.org/licenses/by/4.0/deed.en) + - Author: Ryo Hirafuji ([@ledyba-z](https://github.com/ledyba-z)) + - Special Thanks: [Shigatake's Pixel Art Lesson](http://shigatake.sakura.ne.jp/gallery/dot/dot_1.html) + +### AVIFS version + +#### Normal + +- [star-8bpc.avifs](star-8bpc.avifs) + - YUV420 + - full-ranged color +- [star-10bpc.avifs](star-10bpc.avifs) + - YUV422 + - full-ranged color +- [star-12bpc.avifs](star-12bpc.avifs) + - YUV444 + - full-ranged color + +- [star-8bpc-with-alpha.avifs](star-8bpc-with-alpha.avifs) + - YUV420 + - 8bit + - limited-ranged color + - limited-ranged alpha +- [star-8bpc-with-alpha.avifs](star-10bpc-with-alpha.avifs) + - YUV422 + - 10bit + - limited-ranged color + - limited-ranged alpha +- [star-8bpc-with-alpha.avifs](star-12bpc-with-alpha.avifs) + - YUV444 + - 12bit + - limited-ranged color + - limited-ranged alpha diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/images.html b/third_party/rust/mp4parse/link-u-avif-sample-images/images.html index e5a69ae6db44..c4ea99f86f78 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/images.html +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/images.html @@ -1,745 +1,745 @@ - - - - All images - - -

AVIF images

-

hato.profile2.8bpc.yuv422.avif

-

PNG version

- -

AVIF version

- -

hato.profile2.8bpc.yuv422.monochrome.avif

-

PNG version

- -

AVIF version

- -

hato.profile2.10bpc.yuv422.avif

-

PNG version

- -

AVIF version

- -

hato.profile2.10bpc.yuv422.monochrome.avif

-

PNG version

- -

AVIF version

- -

hato.profile2.12bpc.yuv422.avif

-

PNG version

- -

AVIF version

- -

hato.profile2.12bpc.yuv422.monochrome.avif

-

PNG version

- -

AVIF version

- -

hato.profile0.8bpc.yuv420.avif

-

PNG version

- -

AVIF version

- -

hato.profile0.8bpc.yuv420.monochrome.avif

-

PNG version

- -

AVIF version

- -

hato.profile0.10bpc.yuv420.avif

-

PNG version

- -

AVIF version

- -

hato.profile0.10bpc.yuv420.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.monochrome.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.monochrome.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.monochrome.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.monochrome.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.monochrome.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.monochrome.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.monochrome.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.monochrome.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.monochrome.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.monochrome.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.monochrome.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.monochrome.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.8bpc.yuv444.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.8bpc.yuv444.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.8bpc.yuv444.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.8bpc.yuv444.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.10bpc.yuv444.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.10bpc.yuv444.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.10bpc.yuv444.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile1.10bpc.yuv444.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.monochrome.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.monochrome.odd-width.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.monochrome.odd-height.avif

-

PNG version

- -

AVIF version

- -

fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif

-

PNG version

- -

AVIF version

- -

plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif

-

PNG version

- -

AVIF version

- -

kimono.avif

-

PNG version

- -

AVIF version

- -

kimono.rotate90.avif

-

PNG version

- -

AVIF version

- -

kimono.rotate270.avif

-

PNG version

- -

AVIF version

- -

kimono.mirror-horizontal.avif

-

PNG version

- -

AVIF version

- -

kimono.mirror-vertical.rotate270.avif

-

PNG version

- -

AVIF version

- -

kimono.crop.avif

-

PNG version

- -

AVIF version

- -

kimono.mirror-vertical.rotate270.crop.avif

-

PNG version

- -

AVIF version

- -

AVIFS images

-

star.avifs

-

GIF version

- -

AVIFS version (without alpha)

- -

star-with-alpha.avifs

-

GIF version

- -

AVIFS version (with alpha)

- - - + + + + All images + + +

AVIF images

+

hato.profile2.8bpc.yuv422.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile2.8bpc.yuv422.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile2.10bpc.yuv422.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile2.10bpc.yuv422.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile2.12bpc.yuv422.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile2.12bpc.yuv422.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile0.8bpc.yuv420.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile0.8bpc.yuv420.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile0.10bpc.yuv420.avif

+

PNG version

+ +

AVIF version

+ +

hato.profile0.10bpc.yuv420.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.monochrome.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.monochrome.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.8bpc.yuv420.monochrome.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.monochrome.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.monochrome.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile0.10bpc.yuv420.monochrome.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.monochrome.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.monochrome.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv420.monochrome.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.monochrome.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.monochrome.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.8bpc.yuv422.monochrome.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.monochrome.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.monochrome.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.10bpc.yuv422.monochrome.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.monochrome.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.monochrome.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv422.monochrome.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.8bpc.yuv444.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.8bpc.yuv444.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.8bpc.yuv444.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.8bpc.yuv444.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.10bpc.yuv444.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.10bpc.yuv444.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.10bpc.yuv444.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile1.10bpc.yuv444.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.monochrome.odd-width.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.monochrome.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

fox.profile2.12bpc.yuv444.monochrome.odd-width.odd-height.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.8bpc.yuv420.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.8bpc.yuv420.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.8bpc.yuv420.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv420.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv420.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv420.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.8bpc.yuv422.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.8bpc.yuv422.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.8bpc.yuv422.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.10bpc.yuv422.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.10bpc.yuv422.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.10bpc.yuv422.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv422.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv422.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv422.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile1.8bpc.yuv444.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile1.8bpc.yuv444.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile1.10bpc.yuv444.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile1.10bpc.yuv444.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv444.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv444.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-large.profile2.12bpc.yuv444.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.8bpc.yuv420.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.8bpc.yuv420.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.8bpc.yuv420.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.10bpc.yuv420.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.10bpc.yuv420.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile0.10bpc.yuv420.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv420.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv420.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv420.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.8bpc.yuv422.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.8bpc.yuv422.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.8bpc.yuv422.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.10bpc.yuv422.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.10bpc.yuv422.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.10bpc.yuv422.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv422.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv422.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv422.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile1.8bpc.yuv444.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile1.8bpc.yuv444.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile1.10bpc.yuv444.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile1.10bpc.yuv444.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv444.alpha-limited.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv444.alpha-full.avif

+

PNG version

+ +

AVIF version

+ +

plum-blossom-small.profile2.12bpc.yuv444.alpha-full.monochrome.avif

+

PNG version

+ +

AVIF version

+ +

kimono.avif

+

PNG version

+ +

AVIF version

+ +

kimono.rotate90.avif

+

PNG version

+ +

AVIF version

+ +

kimono.rotate270.avif

+

PNG version

+ +

AVIF version

+ +

kimono.mirror-horizontal.avif

+

PNG version

+ +

AVIF version

+ +

kimono.mirror-vertical.rotate270.avif

+

PNG version

+ +

AVIF version

+ +

kimono.crop.avif

+

PNG version

+ +

AVIF version

+ +

kimono.mirror-vertical.rotate270.crop.avif

+

PNG version

+ +

AVIF version

+ +

AVIFS images

+

star.avifs

+

GIF version

+ +

AVIFS version (without alpha)

+ +

star-with-alpha.avifs

+

GIF version

+ +

AVIFS version (with alpha)

+ + + diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/plum-blossom.svg b/third_party/rust/mp4parse/link-u-avif-sample-images/plum-blossom.svg index e6b9b07f2f6d..561310bc0bf9 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/plum-blossom.svg +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/plum-blossom.svg @@ -1,176 +1,176 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/scripts/compare.sh b/third_party/rust/mp4parse/link-u-avif-sample-images/scripts/compare.sh index 513d19fd2b2f..34b72019d4a6 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/scripts/compare.sh +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/scripts/compare.sh @@ -1,23 +1,23 @@ -##!/usr/bin/env bash - -avif=$2 -decoded=$3 - -orig=$(cat Makefile | grep "^${avif}" | sed "s/^${avif}: \(.*\)$/\1/") - -if (echo ${avif} | grep "monochrome"); then - # FIMXE(ledyba-z): compare monochrome images. - score="100.0" -elif (echo ${avif} | grep "\(rotate\|mirror\|crop\)"); then - # FIMXE(ledyba-z): compare transformed images - score="100.0" -else - score=$(compare -metric PSNR ${orig} ${decoded} NULL: 2>&1 || true) -fi -if test $(echo "${score} >= 35.0" | bc -l) -eq 1; then - echo "Passing: ${decoded}: ${score}" - exit 0 -else - echo "Failed: ${decoded}: ${score} (vs ${orig})" - exit -1 -fi +##!/usr/bin/env bash + +avif=$2 +decoded=$3 + +orig=$(cat Makefile | grep "^${avif}" | sed "s/^${avif}: \(.*\)$/\1/") + +if (echo ${avif} | grep "monochrome"); then + # FIMXE(ledyba-z): compare monochrome images. + score="100.0" +elif (echo ${avif} | grep "\(rotate\|mirror\|crop\)"); then + # FIMXE(ledyba-z): compare transformed images + score="100.0" +else + score=$(compare -metric PSNR ${orig} ${decoded} NULL: 2>&1 || true) +fi +if test $(echo "${score} >= 35.0" | bc -l) -eq 1; then + echo "Passing: ${decoded}: ${score}" + exit 0 +else + echo "Failed: ${decoded}: ${score} (vs ${orig})" + exit -1 +fi diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/star.input.txt b/third_party/rust/mp4parse/link-u-avif-sample-images/star.input.txt index ce797225f603..93d691e5079f 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/star.input.txt +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/star.input.txt @@ -1,9 +1,9 @@ -file 'star.png' -duration 0.1 -file 'star90.png' -duration 0.1 -file 'star180.png' -duration 0.1 -file 'star270.png' -duration 0.1 -file 'star.png' +file 'star.png' +duration 0.1 +file 'star90.png' +duration 0.1 +file 'star180.png' +duration 0.1 +file 'star270.png' +duration 0.1 +file 'star.png' diff --git a/third_party/rust/mp4parse/link-u-avif-sample-images/star.svg b/third_party/rust/mp4parse/link-u-avif-sample-images/star.svg index 8bca22a42055..e1352bc0bffa 100644 --- a/third_party/rust/mp4parse/link-u-avif-sample-images/star.svg +++ b/third_party/rust/mp4parse/link-u-avif-sample-images/star.svg @@ -1,83 +1,83 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/third_party/rust/mp4parse/src/boxes.rs b/third_party/rust/mp4parse/src/boxes.rs index ef4ba658e208..838df5db1940 100644 --- a/third_party/rust/mp4parse/src/boxes.rs +++ b/third_party/rust/mp4parse/src/boxes.rs @@ -15,7 +15,7 @@ struct String; macro_rules! box_database { ($($(#[$attr:meta])* $boxenum:ident $boxtype:expr),*,) => { - #[derive(Clone, Copy, PartialEq)] + #[derive(Clone, Copy, PartialEq, Eq)] pub enum BoxType { $($(#[$attr])* $boxenum),*, UnknownBox(u32), @@ -110,6 +110,8 @@ box_database!( MovieHeaderBox 0x6d76_6864, // "mvhd" TrackBox 0x7472_616b, // "trak" TrackHeaderBox 0x746b_6864, // "tkhd" + TrackReferenceBox 0x7472_6566, // "tref" + AuxiliaryBox 0x6175_786C, // "auxl" EditBox 0x6564_7473, // "edts" MediaBox 0x6d64_6961, // "mdia" EditListBox 0x656c_7374, // "elst" diff --git a/third_party/rust/mp4parse/src/lib.rs b/third_party/rust/mp4parse/src/lib.rs index b5852dc7e695..290ff61ee432 100644 --- a/third_party/rust/mp4parse/src/lib.rs +++ b/third_party/rust/mp4parse/src/lib.rs @@ -35,7 +35,7 @@ use std::io::{Read, Take}; mod macros; mod boxes; -use boxes::{BoxType, FourCC}; +use crate::boxes::{BoxType, FourCC}; // Unit tests. #[cfg(test)] @@ -137,6 +137,7 @@ impl<'a, T> Offset for OffsetReader<'a, T> { impl<'a, T: Read> Read for OffsetReader<'a, T> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let bytes_read = self.reader.read(buf)?; + trace!("Read {} bytes at offset {}", bytes_read, self.offset); self.offset = self .offset .checked_add(bytes_read.to_u64()) @@ -164,7 +165,7 @@ struct String; /// Any detail that needs to be communicated to the caller must be encoded here /// since the [`Error`] type's associated data is part of the FFI. #[repr(C)] -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Status { Ok = 0, BadArg = 1, @@ -173,25 +174,108 @@ pub enum Status { Eof = 4, Io = 5, Oom = 6, - MissingBrand, - FtypNotFirst, - NoImage, - MultipleMoov, - NoMoov, - LselNoEssential, - A1opNoEssential, A1lxEssential, - TxformNoEssential, - NoPrimaryItem, - ImageItemType, - ItemTypeMissing, + A1opNoEssential, + AlacBadMagicCookieSize, + AlacFlagsNonzero, + Av1cMissing, + BitReaderError, + BoxBadSize, + BoxBadWideSize, + CheckParserStateErr, + ColrBadQuantity, + ColrBadSize, + ColrBadType, + ColrReservedNonzero, ConstructionMethod, - ItemLocNotFound, - NoItemDataBox, + CttsBadSize, + CttsBadVersion, + DflaBadMetadataBlockSize, + DflaFlagsNonzero, + DflaMissingMetadata, + DflaStreamInfoBadSize, + DflaStreamInfoNotFirst, + DopsChannelMappingWriteErr, + DopsOpusHeadWriteErr, + ElstBadVersion, + EsdsBadAudioSampleEntry, + EsdsBadDescriptor, + EsdsDecSpecificIntoTagQuantity, + FtypBadSize, + FtypNotFirst, + HdlrNameMultipleNul, + HdlrNameNoNul, + HdlrNameNotUtf8, + HdlrNotFirst, + HdlrPredefinedNonzero, + HdlrReservedNonzero, + HdlrTypeNotPict, + HdlrUnsupportedVersion, + HdrlBadQuantity, + IdatBadQuantity, + IdatMissing, + IinfBadChild, + IinfBadQuantity, + IlocBadConstructionMethod, + IlocBadExtent, + IlocBadExtentCount, + IlocBadFieldSize, + IlocBadQuantity, + IlocBadSize, + IlocDuplicateItemId, + IlocMissing, + IlocNotFound, + IlocOffsetOverflow, + ImageItemType, + InfeFlagsNonzero, + InvalidUtf8, + IpcoIndexOverflow, + IpmaBadIndex, + IpmaBadItemOrder, + IpmaBadQuantity, + IpmaBadVersion, + IpmaDuplicateItemId, + IpmaFlagsNonzero, + IpmaIndexZeroNoEssential, + IpmaTooBig, + IpmaTooSmall, + IprpBadChild, + IprpBadQuantity, + IprpConflict, + IrefBadQuantity, + IrefRecursion, + IspeMissing, + ItemTypeMissing, + LselNoEssential, + MdhdBadTimescale, + MdhdBadVersion, + MehdBadVersion, + MetaBadQuantity, + MissingAvifOrAvisBrand, + MissingMif1Brand, + MoovBadQuantity, + MoovMissing, + MultipleAlpha, + MvhdBadTimescale, + MvhdBadVersion, + NoImage, + PitmBadQuantity, + PitmMissing, + PixiBadChannelCount, + PixiMissing, + PsshSizeOverflow, + ReadBufErr, + SchiQuantity, + StsdBadAudioSampleEntry, + StsdBadVideoSampleEntry, + TkhdBadVersion, + TxformBeforeIspe, + TxformNoEssential, + TxformOrder, } #[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Feature { A1lx, A1op, @@ -215,19 +299,14 @@ impl Feature { match self { Self::Auxc | Self::Av1c + | Self::Avis | Self::Colr | Self::Imir | Self::Irot | Self::Ispe | Self::Pasp | Self::Pixi => true, - Self::A1lx - | Self::A1op - | Self::Clap - | Self::Grid - | Self::Ipro - | Self::Lsel - | Self::Avis => false, + Self::A1lx | Self::A1op | Self::Clap | Self::Grid | Self::Ipro | Self::Lsel => false, } } } @@ -300,17 +379,15 @@ impl UnsupportedFeatures { impl From for Result { /// A convenience method to enable shortcuts like /// ``` - /// # extern crate mp4parse; /// # use mp4parse::{Result,Status}; /// # let _: Result<()> = - /// Status::MissingBrand.into(); + /// Status::MissingAvifOrAvisBrand.into(); /// ``` /// instead of /// ``` - /// # extern crate mp4parse; /// # use mp4parse::{Error,Result,Status}; /// # let _: Result<()> = - /// Err(Error::from(Status::MissingBrand)); + /// Err(Error::from(Status::MissingAvifOrAvisBrand)); /// ``` /// Note that `Status::Ok` can't be supported this way and will panic. fn from(parse_status: Status) -> Self { @@ -333,23 +410,9 @@ impl From for Error { | Status::Eof | Status::Io | Status::Oom => { - panic!("Status -> Error is only for Status:InvalidDataDetail errors") + panic!("Status -> Error is only for Status:InvalidData errors") } - Status::MissingBrand - | Status::FtypNotFirst - | Status::NoImage - | Status::MultipleMoov - | Status::NoMoov - | Status::LselNoEssential - | Status::A1opNoEssential - | Status::A1lxEssential - | Status::TxformNoEssential - | Status::NoPrimaryItem - | Status::ImageItemType - | Status::ItemTypeMissing - | Status::ConstructionMethod - | Status::ItemLocNotFound - | Status::NoItemDataBox => Self::InvalidDataDetail(parse_status), + _ => Self::InvalidData(parse_status), } } } @@ -366,37 +429,346 @@ impl From for &str { | Status::Oom => { panic!("Status -> Error is only for specific parsing errors") } - Status::MissingBrand => { - "The file shall list 'avif' or 'avis' in the compatible_brands field - of the FileTypeBox \ - per https://aomediacodec.github.io/av1-avif/#file-constraints" - } - Status::FtypNotFirst => { - "The FileTypeBox shall be placed as early as possible in the file \ - per ISOBMFF (ISO 14496-12:2020) § 4.3.1" - } - Status::NoImage => "No primary image or image sequence found", - Status::NoMoov => { - "No moov box found; \ - files with avis or msf1 brands shall contain exactly one moov box \ - per ISOBMFF (ISO 14496-12:2020) § 8.2.1.1" - } - Status::MultipleMoov => { - "Multiple moov boxes found; \ - files with avis or msf1 brands shall contain exactly one moov box \ - per ISOBMFF (ISO 14496-12:2020) § 8.2.1.1" - } - Status::LselNoEssential => { - "LayerSelectorProperty (lsel) shall be marked as essential \ - per HEIF (ISO/IEC 23008-12:2017) § 6.5.11.1" + Status::A1lxEssential => { + "AV1LayeredImageIndexingProperty (a1lx) shall not be marked as essential \ + per https://aomediacodec.github.io/av1-avif/#layered-image-indexing-property-description" } Status::A1opNoEssential => { "OperatingPointSelectorProperty (a1op) shall be marked as essential \ per https://aomediacodec.github.io/av1-avif/#operating-point-selector-property-description" } - Status::A1lxEssential => { - "AV1LayeredImageIndexingProperty (a1lx) shall not be marked as essential \ - per https://aomediacodec.github.io/av1-avif/#layered-image-indexing-property-description" + Status::AlacBadMagicCookieSize => { + "ALACSpecificBox magic cookie is the wrong size" + } + Status::AlacFlagsNonzero => { + "no-zero alac (ALAC) flags" + } + Status::Av1cMissing => { + "One AV1 Item Configuration Property (av1C) is mandatory for an \ + image item of type 'av01' \ + per AVIF specification § 2.2.1" + } + Status::BitReaderError => { + "Bitwise read failed" + } + Status::BoxBadSize => { + "malformed size" + } + Status::BoxBadWideSize => { + "malformed wide size" + } + Status::CheckParserStateErr => { + "unread box content or bad parser sync" + } + Status::ColrBadQuantity => { + "Each item shall have at most one property association with a + ColourInformationBox (colr) for a given value of colour_type \ + per HEIF (ISO/IEC DIS 23008-12) § 6.5.5.1" + } + Status::ColrBadSize => { + "Unexpected size for colr box" + } + Status::ColrBadType => { + "Unsupported colour_type for ColourInformationBox" + } + Status::ColrReservedNonzero => { + "The 7 reserved bits at the end of the ColourInformationBox \ + for colour_type == 'nclx' must be 0 \ + per ISOBMFF (ISO 14496-12:2020) § 12.1.5.2" + } + Status::ConstructionMethod => { + "construction_method shall be 0 (file) or 1 (idat) per MIAF (ISO 23000-22:2019) § 7.2.1.7" + } + Status::CttsBadSize => { + "insufficient data in 'ctts' box" + } + Status::CttsBadVersion => { + "unsupported version in 'ctts' box" + } + Status::DflaBadMetadataBlockSize => { + "FLACMetadataBlock larger than parent box" + } + Status::DflaFlagsNonzero => { + "no-zero dfLa (FLAC) flags" + } + Status::DflaMissingMetadata => { + "FLACSpecificBox missing metadata" + } + Status::DflaStreamInfoBadSize => { + "FLACSpecificBox STREAMINFO block is the wrong size" + } + Status::DflaStreamInfoNotFirst => { + "FLACSpecificBox must have STREAMINFO metadata first" + } + Status::DopsChannelMappingWriteErr => { + "Couldn't write channel mapping table data." + } + Status::DopsOpusHeadWriteErr => { + "Couldn't write OpusHead tag." + } + Status::ElstBadVersion => { + "unhandled elst version" + } + Status::EsdsBadAudioSampleEntry => { + "malformed audio sample entry" + } + Status::EsdsBadDescriptor => { + "Invalid descriptor." + } + Status::EsdsDecSpecificIntoTagQuantity => { + "There can be only one DecSpecificInfoTag descriptor" + } + Status::FtypBadSize => { + "invalid ftyp size" + } + Status::FtypNotFirst => { + "The FileTypeBox shall be placed as early as possible in the file \ + per ISOBMFF (ISO 14496-12:2020) § 4.3.1" + } + Status::HdlrNameMultipleNul => { + "The HandlerBox 'name' field shall have a NUL byte \ + only in the final position \ + per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2" + } + Status::HdlrNameNoNul => { + "The HandlerBox 'name' field shall be null-terminated \ + per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2" + } + Status::HdlrNameNotUtf8 => { + "The HandlerBox 'name' field shall be valid utf8 \ + per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2" + } + Status::HdlrNotFirst => { + "The HandlerBox shall be the first contained box within the MetaBox \ + per MIAF (ISO 23000-22:2019) § 7.2.1.5" + } + Status::HdlrPredefinedNonzero => { + "The HandlerBox 'pre_defined' field shall be 0 \ + per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2" + } + Status::HdlrReservedNonzero => { + "The HandlerBox 'reserved' fields shall be 0 \ + per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2" + } + Status::HdlrTypeNotPict => { + "The HandlerBox handler_type must be 'pict' \ + per MIAF (ISO 23000-22:2019) § 7.2.1.5" + } + Status::HdlrUnsupportedVersion => { + "The HandlerBox version shall be 0 (zero) \ + per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2" + } + Status::HdrlBadQuantity => { + "There shall be exactly one hdlr box \ + per ISOBMFF (ISO 14496-12:2020) § 8.4.3.1" + } + Status::IdatBadQuantity => { + "There shall be zero or one idat boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.11" + } + Status::IdatMissing => { + "ItemLocationBox (iloc) construction_method indicates 1 (idat), \ + but no idat box is present." + } + Status::IinfBadChild => { + "iinf box shall contain only infe boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.6.2" + } + Status::IinfBadQuantity => { + "There shall be zero or one iinf boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.6.1" + } + Status::IlocBadConstructionMethod => { + "construction_method is taken from the set 0, 1 or 2 \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.3.3" + } + Status::IlocBadExtent => { + "extent_count != 1 requires explicit offset and length \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.3.3" + } + Status::IlocBadExtentCount => { + "extent_count must have a value 1 or greater \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.3.3" + } + Status::IlocBadFieldSize => { + "value must be in the set {0, 4, 8}" + } + Status::IlocBadQuantity => { + "There shall be zero or one iloc boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.3.1" + } + Status::IlocBadSize => { + "invalid iloc size" + } + Status::IlocDuplicateItemId => { + "duplicate item_ID in iloc" + } + Status::IlocMissing => { + "iloc missing" + } + Status::IlocNotFound => { + "ItemLocationBox (iloc) contains an extent not present in any mdat or idat box" + } + Status::IlocOffsetOverflow => { + "offset calculation overflow" + } + Status::ImageItemType => { + "Image item type is neither 'av01' nor 'grid'" + } + Status::InfeFlagsNonzero => { + "'infe' flags field shall be 0 \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.6.2" + } + Status::InvalidUtf8 => { + "invalid utf8" + } + Status::IpcoIndexOverflow => { + "ipco index overflow" + } + Status::IpmaBadIndex => { + "Invalid property index in ipma" + } + Status::IpmaBadItemOrder => { + "Each ItemPropertyAssociation box shall be ordered by increasing item_ID" + } + Status::IpmaBadQuantity => { + "There shall be at most one ItemPropertyAssociationbox with a given pair of \ + values of version and flags \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1" + } + Status::IpmaBadVersion => { + "The ipma version 0 should be used unless 32-bit item_ID values are needed \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1" + } + Status::IpmaDuplicateItemId => { + "There shall be at most one occurrence of a given item_ID, \ + in the set of ItemPropertyAssociationBox boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1" + } + Status::IpmaFlagsNonzero => { + "Unless there are more than 127 properties in the ItemPropertyContainerBox, \ + flags should be equal to 0 \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1" + } + Status::IpmaIndexZeroNoEssential => { + "the essential indicator shall be 0 for property index 0 \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.14.3" + } + Status::IpmaTooBig => { + "ipma box exceeds maximum size for entry_count" + } + Status::IpmaTooSmall => { + "ipma box below minimum size for entry_count" + } + Status::IprpBadChild => { + "unexpected iprp child" + } + Status::IprpBadQuantity => { + "There shall be zero or one iprp boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1" + } + Status::IprpConflict => { + "conflicting item property values" + } + Status::IrefBadQuantity => { + "There shall be zero or one iref boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.12.1" + } + Status::IrefRecursion => { + "from_item_id and to_item_id must be different" + } + Status::IspeMissing => { + "Missing 'ispe' property for image item, required \ + per HEIF (ISO/IEC 23008-12:2017) § 6.5.3.1" + } + Status::ItemTypeMissing => { + "No ItemInfoEntry for item_ID" + } + Status::LselNoEssential => { + "LayerSelectorProperty (lsel) shall be marked as essential \ + per HEIF (ISO/IEC 23008-12:2017) § 6.5.11.1" + } + Status::MdhdBadTimescale => { + "zero timescale in mdhd" + } + Status::MdhdBadVersion => { + "unhandled mdhd version" + } + Status::MehdBadVersion => { + "unhandled mehd version" + } + Status::MetaBadQuantity => { + "There should be zero or one meta boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.1.1" + } + Status::MissingAvifOrAvisBrand => { + "The file shall list 'avif' or 'avis' in the compatible_brands field + of the FileTypeBox \ + per https://aomediacodec.github.io/av1-avif/#file-constraints" + } + Status::MissingMif1Brand => { + "The FileTypeBox should contain 'mif1' in the compatible_brands list \ + per MIAF (ISO 23000-22:2019/Amd. 2:2021) § 7.2.1.2" + } + Status::MoovBadQuantity => { + "Multiple moov boxes found; \ + files with avis or msf1 brands shall contain exactly one moov box \ + per ISOBMFF (ISO 14496-12:2020) § 8.2.1.1" + } + Status::MoovMissing => { + "No moov box found; \ + files with avis or msf1 brands shall contain exactly one moov box \ + per ISOBMFF (ISO 14496-12:2020) § 8.2.1.1" + } + Status::MultipleAlpha => { + "multiple alpha planes" + } + Status::MvhdBadTimescale => { + "zero timescale in mvhd" + } + Status::MvhdBadVersion => { + "unhandled mvhd version" + } + Status::NoImage => "No primary image or image sequence found", + Status::PitmBadQuantity => { + "There shall be zero or one pitm boxes \ + per ISOBMFF (ISO 14496-12:2020) § 8.11.4.1" + } + Status::PitmMissing => { + "Missing required PrimaryItemBox (pitm), required \ + per HEIF (ISO/IEC 23008-12:2017) § 10.2.1" + } + Status::PixiBadChannelCount => { + "invalid num_channels" + } + Status::PixiMissing => { + "The pixel information property shall be associated with every image \ + that is displayable (not hidden) \ + per MIAF (ISO/IEC 23000-22:2019) specification § 7.3.6.6" + } + Status::PsshSizeOverflow => { + "overflow in read_pssh" + } + Status::ReadBufErr => { + "failed buffer read" + } + Status::SchiQuantity => { + "tenc box should be only one at most in sinf box" + } + Status::StsdBadAudioSampleEntry => { + "malformed audio sample entry" + } + Status::StsdBadVideoSampleEntry => { + "malformed video sample entry" + } + Status::TkhdBadVersion => { + "unhandled tkhd version" + } + Status::TxformBeforeIspe => { + "Every image item shall be associated with one property of \ + type ImageSpatialExtentsProperty (ispe), prior to the \ + association of all transformative properties. \ + per HEIF (ISO/IEC 23008-12:2017) § 6.5.3.1" } Status::TxformNoEssential => { "All transformative properties associated with coded and \ @@ -404,25 +776,11 @@ impl From for &str { document shall be marked as essential \ per MIAF (ISO 23000-22:2019) § 7.3.9" } - Status::NoPrimaryItem => { - "Missing required PrimaryItemBox (pitm), required \ - per HEIF (ISO/IEC 23008-12:2017) § 10.2.1" - } - Status::ImageItemType => { - "Image item type is neither 'av01' nor 'grid'" - } - Status::ItemTypeMissing => { - "No ItemInfoEntry for item_ID" - } - Status::ConstructionMethod => { - "construction_method shall be 0 (file) or 1 (idat) per MIAF (ISO 23000-22:2019) § 7.2.1.7" - } - Status::ItemLocNotFound => { - "ItemLocationBox (iloc) contains an extent not present in any mdat or idat box" - } - Status::NoItemDataBox => { - "ItemLocationBox (iloc) construction_method indicates 1 (idat), \ - but no idat box is present." + Status::TxformOrder => { + "These properties, if used, shall be indicated to be applied \ + in the following order: clean aperture first, then rotation, \ + then mirror. \ + per MIAF (ISO/IEC 23000-22:2019) § 7.3.6.7" } } } @@ -431,9 +789,8 @@ impl From for &str { impl From for Status { fn from(error: Error) -> Self { match error { - Error::InvalidData(_) => Self::Invalid, Error::Unsupported(_) => Self::Unsupported, - Error::InvalidDataDetail(parse_status) => parse_status, + Error::InvalidData(parse_status) => parse_status, Error::UnexpectedEOF => Self::Eof, Error::Io(_) => { // Getting std::io::ErrorKind::UnexpectedEof is normal @@ -441,7 +798,7 @@ impl From for Status { // those to our Error::UnexpectedEOF variant. Self::Io } - Error::NoMoov => Self::NoMoov, + Error::MoovMissing => Self::MoovMissing, Error::OutOfMemory => Self::Oom, } } @@ -485,11 +842,8 @@ impl From for Status { #[derive(Debug)] pub enum Error { /// Parse error caused by corrupt or malformed data. - InvalidData(&'static str), - /// Similar to [`Self::InvalidData`], but for errors that have a specific - /// [`Status`] variant for communicating the detail across FFI. /// See the helper [`From for Error`](enum.Error.html#impl-From) - InvalidDataDetail(Status), + InvalidData(Status), /// Parse error caused by limited parser support rather than invalid data. Unsupported(&'static str), /// Reflect `std::io::ErrorKind::UnexpectedEof` for short data. @@ -497,7 +851,7 @@ pub enum Error { /// Propagate underlying errors from `std::io`. Io(std::io::Error), /// read_mp4 terminated without detecting a moov box. - NoMoov, + MoovMissing, /// Out of memory OutOfMemory, } @@ -512,7 +866,7 @@ impl std::error::Error for Error {} impl From for Error { fn from(_: bitreader::BitReaderError) -> Error { - Error::InvalidData("invalid data") + Status::BitReaderError.into() } } @@ -527,13 +881,13 @@ impl From for Error { impl From for Error { fn from(_: std::string::FromUtf8Error) -> Error { - Error::InvalidData("invalid utf8") + Status::InvalidUtf8.into() } } impl From for Error { fn from(_: std::str::Utf8Error) -> Error { - Error::InvalidData("invalid utf8") + Status::InvalidUtf8.into() } } @@ -546,7 +900,6 @@ impl From for Error { impl From for std::io::Error { fn from(err: Error) -> Self { let kind = match err { - Error::InvalidData(_) => std::io::ErrorKind::InvalidData, Error::UnexpectedEOF => std::io::ErrorKind::UnexpectedEof, Error::Io(io_err) => return io_err, _ => std::io::ErrorKind::Other, @@ -742,6 +1095,29 @@ pub enum SampleEntry { Unknown, } +#[derive(Debug)] +pub struct TrackReferenceBox { + pub references: TryVec, +} + +impl TrackReferenceBox { + pub fn has_auxl_reference(&self, track_id: u32) -> bool { + self.references.iter().any(|entry| match entry { + TrackReferenceEntry::Auxiliary(aux_entry) => aux_entry.track_ids.contains(&track_id), + }) + } +} + +#[derive(Debug)] +pub enum TrackReferenceEntry { + Auxiliary(TrackReference), +} + +#[derive(Debug)] +pub struct TrackReference { + pub track_ids: TryVec, +} + /// An Elementary Stream Descriptor /// See MPEG-4 Systems (ISO 14496-1:2010) § 7.2.6.5 #[allow(non_camel_case_types)] @@ -1146,10 +1522,10 @@ pub struct MediaContext { /// An ISOBMFF item as described by an iloc box. For the sake of avoiding copies, /// this can either be represented by the `Location` variant, which indicates -/// where the data exists within a `MediaDataBox` stored separately, or the -/// `Data` variant which owns the data. Unfortunately, it's not simple to -/// represent this as a [`std::borrow::Cow`], or other reference-based type, because -/// multiple instances may references different parts of the same [`MediaDataBox`] +/// where the data exists within a `DataBox` stored separately, or the `Data` +/// variant which owns the data. Unfortunately, it's not simple to represent +/// this as a [`std::borrow::Cow`], or other reference-based type, because +/// multiple instances may references different parts of the same [`DataBox`] /// and we want to avoid the copy that splitting the storage would entail. enum IsobmffItem { MdatLocation(Extent), @@ -1192,12 +1568,17 @@ impl AvifItem { } } -#[derive(Debug)] +#[derive(Default, Debug)] pub struct AvifContext { /// Level of deviation from the specification before failing the parse strictness: ParseStrictness, - /// Referred to by the `IsobmffItem::*Location` variants of the `AvifItem`s in this struct - media_storage: TryVec, + /// Storage elements which can be located anywhere within the "file" identified by + /// [`BoxType::ItemLocationBox`]es using [`ConstructionMethod::File`]. + /// Referred to by the [`IsobmffItem`]`::*Location` variants of the `AvifItem`s in this struct + media_storage: TryVec, + /// Similar to `media_storage`, but for a single optional chunk of storage within the + /// MetaBox itentified by [`BoxType::ItemLocationBox`]es using [`ConstructionMethod::Idat`]. + item_data_box: Option, /// The item indicated by the `pitm` box, See ISOBMFF (ISO 14496-12:2020) § 8.11.4 /// May be `None` in the pure image sequence case. primary_item: Option, @@ -1211,13 +1592,17 @@ pub struct AvifContext { /// Should probably only ever be [`AVIF_BRAND`] or [`AVIS_BRAND`], but other values /// are legal as long as one of the two is the `compatible_brand` list. pub major_brand: FourCC, - /// True if a `moov` box is present - pub has_sequence: bool, + /// Information on the sequence contained in the image, or None if not present + pub sequence: Option, /// A collection of unsupported features encountered during the parse pub unsupported_features: UnsupportedFeatures, } impl AvifContext { + pub fn primary_item_is_present(&self) -> bool { + self.primary_item.is_some() + } + pub fn primary_item_coded_data(&self) -> Option<&[u8]> { self.primary_item .as_ref() @@ -1230,6 +1615,10 @@ impl AvifContext { .map(|item| self.image_bits_per_channel(item.id)) } + pub fn alpha_item_is_present(&self) -> bool { + self.alpha_item.is_some() + } + pub fn alpha_item_coded_data(&self) -> Option<&[u8]> { self.alpha_item .as_ref() @@ -1262,9 +1651,9 @@ impl AvifContext { Some(ItemProperty::ImageSpatialExtents(ispe)) => Ok(ispe), Some(other_property) => panic!("property key mismatch: {:?}", other_property), None => { - fail_if( + fail_with_status_if( self.strictness != ParseStrictness::Permissive, - "ispe is a mandatory property", + Status::IspeMissing, )?; Ok(std::ptr::null()) } @@ -1376,10 +1765,15 @@ impl AvifContext { } } unreachable!( - "IsobmffItem::Location requires the location exists in AvifContext::media_storage" + "IsobmffItem::MdatLocation requires the location exists in AvifContext::media_storage" ); } - IsobmffItem::IdatLocation(_) => unimplemented!(), + IsobmffItem::IdatLocation(extent) => { + self.item_data_box + .as_ref() + .and_then(|idat| idat.get(extent)) + .unwrap_or_else(|| unreachable!("IsobmffItem::IdatLocation equires the location exists in AvifContext::item_data_box")) + } IsobmffItem::Data(data) => data.as_slice(), } } @@ -1393,29 +1787,31 @@ struct AvifMeta { primary_item_id: Option, item_infos: TryVec, iloc_items: TryHashMap, - item_data_box: Option, + item_data_box: Option, } -/// An Item Data Box -/// See ISOBMFF (ISO 14496-12:2020) § 8.11.11 -struct ItemDataBox { +#[derive(Debug)] +enum DataBoxMetadata { + Idat, + Mdat { + /// Offset of `data` from the beginning of the "file". See ConstructionMethod::File. + /// Note: the file may not be an actual file, read_avif supports any `&mut impl Read` + /// source for input. However we try to match the terminology used in the spec. + file_offset: u64, + }, +} + +/// Represents either an Item Data Box (ISOBMFF (ISO 14496-12:2020) § 8.11.11) +/// Or a Media Data Box (ISOBMFF (ISO 14496-12:2020) § 8.1.1) +struct DataBox { + metadata: DataBoxMetadata, data: TryVec, } -/// A Media Data Box -/// See ISOBMFF (ISO 14496-12:2020) § 8.1.1 -struct MediaDataBox { - /// Offset of `data` from the beginning of the "file". See ConstructionMethod::File. - /// Note: the file may not be an actual file, read_avif supports any `&mut impl Read` - /// source for input. However we try to match the terminology used in the spec. - file_offset: u64, - data: TryVec, -} - -impl fmt::Debug for MediaDataBox { +impl fmt::Debug for DataBox { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("MediaDataBox") - .field("file_offset", &self.file_offset) + f.debug_struct("DataBox") + .field("metadata", &self.metadata) .field("data", &format_args!("{} bytes", self.data.len())) .finish() } @@ -1431,18 +1827,49 @@ fn u64_to_usize_logged(x: u64) -> Option { } } -/// Generalizes the different data boxes a [`ItemLocationBoxItem`] can refer to -trait DataBox { - fn data(&self) -> &[u8]; +impl DataBox { + fn from_mdat(file_offset: u64, data: TryVec) -> Self { + Self { + metadata: DataBoxMetadata::Mdat { file_offset }, + data, + } + } + + fn from_idat(data: TryVec) -> Self { + Self { + metadata: DataBoxMetadata::Idat, + data, + } + } + + fn data(&self) -> &[u8] { + &self.data + } /// Convert an absolute offset to an offset relative to the beginning of the /// slice [`DataBox::data`] returns. Returns None if the offset would be /// negative or if the offset would overflow a `usize`. - fn start(&self, offset: u64) -> Option; + fn start(&self, offset: u64) -> Option { + match self.metadata { + DataBoxMetadata::Idat => u64_to_usize_logged(offset), + DataBoxMetadata::Mdat { file_offset } => { + let start = offset.checked_sub(file_offset); + if start.is_none() { + error!("Overflow subtracting {} + {}", offset, file_offset); + } + u64_to_usize_logged(start?) + } + } + } /// Returns an appropriate variant of [`IsobmffItem`] to describe the extent /// referencing data within this type of box. - fn location(&self, extent: &Extent) -> IsobmffItem; + fn location(&self, extent: &Extent) -> IsobmffItem { + match self.metadata { + DataBoxMetadata::Idat => IsobmffItem::IdatLocation(extent.clone()), + DataBoxMetadata::Mdat { .. } => IsobmffItem::MdatLocation(extent.clone()), + } + } /// Return a slice from the DataBox specified by the provided `extent`. /// Returns `None` if the extent isn't fully contained by the DataBox or if @@ -1466,46 +1893,14 @@ trait DataBox { } } -impl DataBox for ItemDataBox { - fn data(&self) -> &[u8] { - &self.data - } - - fn start(&self, offset: u64) -> Option { - u64_to_usize_logged(offset) - } - - fn location(&self, extent: &Extent) -> IsobmffItem { - IsobmffItem::IdatLocation(extent.clone()) - } -} - -impl DataBox for MediaDataBox { - fn data(&self) -> &[u8] { - &self.data - } - - fn start(&self, offset: u64) -> Option { - let start = offset.checked_sub(self.file_offset); - if start.is_none() { - error!("Overflow subtracting {} + {}", offset, self.file_offset); - } - u64_to_usize_logged(start?) - } - - fn location(&self, extent: &Extent) -> IsobmffItem { - IsobmffItem::MdatLocation(extent.clone()) - } -} - #[cfg(test)] mod media_data_box_tests { use super::*; - impl MediaDataBox { + impl DataBox { fn at_offset(file_offset: u64, data: std::vec::Vec) -> Self { - MediaDataBox { - file_offset, + DataBox { + metadata: DataBoxMetadata::Mdat { file_offset }, data: data.into(), } } @@ -1513,7 +1908,7 @@ mod media_data_box_tests { #[test] fn extent_with_length_before_mdat_returns_none() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::WithLength { offset: 0, len: 2 }; assert!(mdat.get(&extent).is_none()); @@ -1521,7 +1916,7 @@ mod media_data_box_tests { #[test] fn extent_to_end_before_mdat_returns_none() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::ToEnd { offset: 0 }; assert!(mdat.get(&extent).is_none()); @@ -1529,7 +1924,7 @@ mod media_data_box_tests { #[test] fn extent_with_length_crossing_front_mdat_boundary_returns_none() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::WithLength { offset: 99, len: 3 }; assert!(mdat.get(&extent).is_none()); @@ -1537,7 +1932,7 @@ mod media_data_box_tests { #[test] fn extent_with_length_which_is_subset_of_mdat() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::WithLength { offset: 101, len: 2, @@ -1548,7 +1943,7 @@ mod media_data_box_tests { #[test] fn extent_to_end_which_is_subset_of_mdat() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::ToEnd { offset: 101 }; assert_eq!(mdat.get(&extent), Some(&[1, 1, 1, 1][..])); @@ -1556,7 +1951,7 @@ mod media_data_box_tests { #[test] fn extent_with_length_which_is_all_of_mdat() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::WithLength { offset: 100, len: 5, @@ -1567,7 +1962,7 @@ mod media_data_box_tests { #[test] fn extent_to_end_which_is_all_of_mdat() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::ToEnd { offset: 100 }; assert_eq!(mdat.get(&extent), Some(mdat.data.as_slice())); @@ -1575,7 +1970,7 @@ mod media_data_box_tests { #[test] fn extent_with_length_crossing_back_mdat_boundary_returns_none() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::WithLength { offset: 103, len: 3, @@ -1586,7 +1981,7 @@ mod media_data_box_tests { #[test] fn extent_with_length_after_mdat_returns_none() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::WithLength { offset: 200, len: 2, @@ -1597,7 +1992,7 @@ mod media_data_box_tests { #[test] fn extent_to_end_after_mdat_returns_none() { - let mdat = MediaDataBox::at_offset(100, vec![1; 5]); + let mdat = DataBox::at_offset(100, vec![1; 5]); let extent = Extent::ToEnd { offset: 200 }; assert!(mdat.get(&extent).is_none()); @@ -1605,7 +2000,7 @@ mod media_data_box_tests { #[test] fn extent_with_length_which_overflows_usize() { - let mdat = MediaDataBox::at_offset(std::u64::MAX - 1, vec![1; 5]); + let mdat = DataBox::at_offset(std::u64::MAX - 1, vec![1; 5]); let extent = Extent::WithLength { offset: std::u64::MAX, len: std::usize::MAX, @@ -1618,7 +2013,7 @@ mod media_data_box_tests { // because the range end is unbounded, we don't calculate it. #[test] fn extent_to_end_which_overflows_usize() { - let mdat = MediaDataBox::at_offset(std::u64::MAX - 1, vec![1; 5]); + let mdat = DataBox::at_offset(std::u64::MAX - 1, vec![1; 5]); let extent = Extent::ToEnd { offset: std::u64::MAX, }; @@ -1661,7 +2056,7 @@ struct SingleItemTypeReferenceBox { /// Potential sizes (in bytes) of variable-sized fields of the 'iloc' box /// See ISOBMFF (ISO 14496-12:2020) § 8.11.3 -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum IlocFieldSize { Zero, Four, @@ -1686,12 +2081,12 @@ impl TryFrom for IlocFieldSize { 0 => Ok(Self::Zero), 4 => Ok(Self::Four), 8 => Ok(Self::Eight), - _ => Err(Error::InvalidData("value must be in the set {0, 4, 8}")), + _ => Status::IlocBadFieldSize.into(), } } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] enum IlocVersion { Zero, One, @@ -1728,7 +2123,7 @@ struct ItemLocationBoxItem { /// > MIAF image items are constrained as follows:
/// > — `construction_method` shall be equal to 0 for MIAF image items that are coded image items.
/// > — `construction_method` shall be equal to 0 or 1 for MIAF image items that are derived image items. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] enum ConstructionMethod { File = 0, Idat = 1, @@ -1737,7 +2132,7 @@ enum ConstructionMethod { /// Describes a region where a item specified by an `ItemLocationBoxItem` is stored. /// The offset is `u64` since that's the maximum possible size and since the relative -/// nature of `MediaDataBox` means this can still possibly succeed even in the case +/// nature of `DataBox` means this can still possibly succeed even in the case /// that the raw value exceeds std::usize::MAX on platforms where that type is smaller /// than u64. However, `len` is stored as a `usize` since no value larger than /// `std::usize::MAX` can be used in a successful indexing operation in rust. @@ -1749,10 +2144,12 @@ enum Extent { ToEnd { offset: u64 }, } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum TrackType { Audio, Video, + Picture, + AuxiliaryVideo, Metadata, Unknown, } @@ -1766,25 +2163,21 @@ impl Default for TrackType { // This type is used by mp4parse_capi since it needs to be passed from FFI consumers // The C-visible struct is renamed via mp4parse_capi/cbindgen.toml to match naming conventions #[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ParseStrictness { Permissive, // Error only on ambiguous inputs Normal, // Error on "shall" directives, log warnings for "should" Strict, // Error on "should" directives } -/// Prefer [`fail_with_error_if`] so all the explanatory strings can be collected -/// in `From for &str`. -fn fail_if(violation: bool, message: &'static str) -> Result<()> { - if violation { - Err(Error::InvalidData(message)) - } else { - warn!("{}", message); - Ok(()) +impl Default for ParseStrictness { + fn default() -> Self { + ParseStrictness::Normal } } -fn fail_with_error_if(violation: bool, error: Error) -> Result<()> { +fn fail_with_status_if(violation: bool, status: Status) -> Result<()> { + let error = Error::from(status); if violation { Err(error) } else { @@ -1793,7 +2186,7 @@ fn fail_with_error_if(violation: bool, error: Error) -> Result<()> { } } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CodecType { Unknown, MP3, @@ -1823,21 +2216,21 @@ impl Default for CodecType { } /// The media's global (mvhd) timescale in units per second. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct MediaTimeScale(pub u64); /// A time to be scaled by the media's global (mvhd) timescale. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct MediaScaledTime(pub u64); /// The track's local (mdhd) timescale. /// Members are timescale units per second and the track id. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct TrackTimeScale(pub T, pub usize); /// A time to be scaled by the track's local (mdhd) timescale. /// Members are time in scale units and the track id. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct TrackScaledTime(pub T, pub usize); impl std::ops::Add for TrackScaledTime @@ -1868,6 +2261,7 @@ pub struct Track { pub stco: Option, // It is for stco or co64. pub stss: Option, pub ctts: Option, + pub tref: Option, } impl Track { @@ -1965,17 +2359,18 @@ fn read_box_header(src: &mut T) -> Result { 1 => { let size64 = be_u64(src)?; if size64 < BoxHeader::MIN_LARGE_SIZE { - return Err(Error::InvalidData("malformed wide size")); + return Status::BoxBadWideSize.into(); } size64 } _ => { if u64::from(size32) < BoxHeader::MIN_SIZE { - return Err(Error::InvalidData("malformed size")); + return Status::BoxBadSize.into(); } u64::from(size32) } }; + trace!("read_box_header: name: {:?}, size: {}", name, size); let mut offset = match size32 { 1 => BoxHeader::MIN_LARGE_SIZE, _ => BoxHeader::MIN_SIZE, @@ -2081,8 +2476,6 @@ impl AvifImageType { /// Read the contents of an AVIF file pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result { - let _ = env_logger::try_init(); - debug!("read_avif(strictness: {:?})", strictness); let mut f = OffsetReader::new(f); @@ -2115,21 +2508,16 @@ pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result(f: &mut T, strictness: ParseStrictness) -> Result(f: &mut T, strictness: ParseStrictness) -> Result { if meta.is_some() { - return Err(Error::InvalidData( - "There should be zero or one meta boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.1.1", - )); + return Status::MetaBadQuantity.into(); } meta = Some(read_avif_meta( &mut b, @@ -2166,16 +2548,14 @@ pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result { if image_sequence.is_some() { - return Status::MultipleMoov.into(); + return Status::MoovBadQuantity.into(); } image_sequence = Some(read_moov(&mut b, None)?); } BoxType::MediaDataBox => { - if b.bytes_left() > 0 { - let file_offset = b.offset(); - let data = b.read_into_try_vec()?; - media_storage.push(MediaDataBox { file_offset, data })?; - } + let file_offset = b.offset(); + let data = b.read_into_try_vec()?; + media_storage.push(DataBox::from_mdat(file_offset, data))?; } _ => skip_box_content(&mut b)?, } @@ -2190,7 +2570,7 @@ pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result(f: &mut T, strictness: ParseStrictness) -> Result(f: &mut T, strictness: ParseStrictness) -> Result Result { + let mut find_and_add_to_item = |extent: &Extent, dat: &DataBox| -> Result { if let Some(extent_slice) = dat.get(extent) { match item { None => { @@ -2294,7 +2674,7 @@ pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result(f: &mut T, strictness: ParseStrictness) -> Result { - fail_with_error_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - Status::ConstructionMethod.into(), + Status::ConstructionMethod, )?; } } @@ -2325,18 +2705,18 @@ pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result(f: &mut T, strictness: ParseStrictness) -> Result| -> Result<()> { let item_id = item.as_ref().map(|item| item.id); @@ -2371,11 +2742,9 @@ pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result { if missing_property_for(item_id, BoxType::AV1CodecConfigurationBox) { - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "One AV1 Item Configuration Property (av1C) is mandatory for an \ - image item of type 'av01' \ - per AVIF specification § 2.2.1", + Status::Av1cMissing, )?; } @@ -2384,15 +2753,20 @@ pub fn read_avif(f: &mut T, strictness: ParseStrictness) -> Result(f: &mut T, strictness: ParseStrictness) -> Result( trace!("read_avif_meta parsing {:?} box", b.head.name); if !read_handler_box && b.head.name != BoxType::HandlerBox { - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "The HandlerBox shall be the first contained box within the MetaBox \ - per MIAF (ISO 23000-22:2019) § 7.2.1.5", + Status::HdlrNotFirst, )?; } match b.head.name { BoxType::HandlerBox => { if read_handler_box { - return Err(Error::InvalidData( - "There shall be exactly one hdlr box per ISOBMFF (ISO 14496-12:2020) § 8.4.3.1", - )); + return Status::HdrlBadQuantity.into(); } let HandlerBox { handler_type } = read_hdlr(&mut b, strictness)?; if handler_type != b"pict" { - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "The HandlerBox handler_type must be 'pict' \ - per MIAF (ISO 23000-22:2019) § 7.2.1.5", + Status::HdlrTypeNotPict, )?; } read_handler_box = true; } BoxType::ItemInfoBox => { if item_infos.is_some() { - return Err(Error::InvalidData( - "There shall be zero or one iinf boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.6.1", - )); + return Status::IinfBadQuantity.into(); } item_infos = Some(read_iinf(&mut b, strictness, unsupported_features)?); } BoxType::ItemLocationBox => { if iloc_items.is_some() { - return Err(Error::InvalidData( - "There shall be zero or one iloc boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.3.1", - )); + return Status::IlocBadQuantity.into(); } iloc_items = Some(read_iloc(&mut b)?); } BoxType::PrimaryItemBox => { if primary_item_id.is_some() { - return Err(Error::InvalidData( - "There shall be zero or one pitm boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.4.1", - )); + return Status::PitmBadQuantity.into(); } primary_item_id = Some(read_pitm(&mut b)?); } BoxType::ItemReferenceBox => { if item_references.is_some() { - return Err(Error::InvalidData("There shall be zero or one iref boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.12.1")); + return Status::IrefBadQuantity.into(); } item_references = Some(read_iref(&mut b)?); } BoxType::ItemPropertiesBox => { if item_properties.is_some() { - return Err(Error::InvalidData("There shall be zero or one iprp boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1")); + return Status::IprpBadQuantity.into(); } item_properties = Some(read_iprp( &mut b, @@ -2530,13 +2895,10 @@ fn read_avif_meta( } BoxType::ItemDataBox => { if item_data_box.is_some() { - return Err(Error::InvalidData( - "There shall be zero or one idat boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.11", - )); + return Status::IdatBadQuantity.into(); } - item_data_box = Some(ItemDataBox { - data: b.read_into_try_vec()?, - }); + let data = b.read_into_try_vec()?; + item_data_box = Some(DataBox::from_idat(data)); } _ => skip_box_content(&mut b)?, } @@ -2549,7 +2911,7 @@ fn read_avif_meta( item_references: item_references.unwrap_or_default(), primary_item_id, item_infos: item_infos.unwrap_or_default(), - iloc_items: iloc_items.ok_or(Error::InvalidData("iloc missing"))?, + iloc_items: iloc_items.ok_or_else(|| Error::from(Status::IlocMissing))?, item_data_box, }) } @@ -2592,9 +2954,7 @@ fn read_iinf( let mut iter = src.box_iter(); while let Some(mut b) = iter.next_box()? { if b.head.name != BoxType::ItemInfoEntry { - return Err(Error::InvalidData( - "iinf box shall contain only infe boxes per ISOBMFF (ISO 14496-12:2020) § 8.11.6.2", - )); + return Status::IinfBadChild.into(); } if let Some(infe) = read_infe(&mut b, strictness, unsupported_features)? { @@ -2633,10 +2993,9 @@ fn read_infe( // least one sample AVIF image has a nonzero value. // See https://github.com/AOMediaCodec/av1-avif/issues/146 if flags != 0 { - fail_if( + fail_with_status_if( strictness == ParseStrictness::Strict, - "'infe' flags field shall be 0 \ - per ISOBMFF (ISO 14496-12:2020) § 8.11.6.2", + Status::InfeFlagsNonzero, )?; } @@ -2681,9 +3040,7 @@ fn read_iref(src: &mut BMFFBox) -> Result(src: &mut BMFFBox) -> Result( Some(mut b) if b.head.name == BoxType::ItemPropertyContainerBox => { read_ipco(&mut b, strictness) } - Some(_) => Err(Error::InvalidData("unexpected iprp child")), + Some(_) => Status::IprpBadChild.into(), None => Err(Error::UnexpectedEOF), }?; @@ -2732,24 +3089,20 @@ fn read_iprp( while let Some(mut b) = iter.next_box()? { if b.head.name != BoxType::ItemPropertyAssociationBox { - return Err(Error::InvalidData("unexpected iprp child")); + return Status::IprpBadChild.into(); } let (version, flags) = read_fullbox_extra(&mut b)?; if ipma_version_and_flag_values_seen.contains(&(version, flags)) { - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "There shall be at most one ItemPropertyAssociationbox with a given pair of \ - values of version and flags \ - per ISOBMFF (ISO 14496-12:2020 § 8.11.14.1", + Status::IpmaBadQuantity, )?; } if flags != 0 && properties.len() <= 127 { - fail_if( + fail_with_status_if( strictness == ParseStrictness::Strict, - "Unless there are more than 127 properties in the ItemPropertyContainerBox, \ - flags should be equal to 0 \ - per ISOBMFF (ISO 14496-12:2020 § 8.11.14.1", + Status::IpmaFlagsNonzero, )?; } ipma_version_and_flag_values_seen.push((version, flags))?; @@ -2772,19 +3125,11 @@ fn read_iprp( // It's technically possible to make sense of this situation by merging ipma // boxes, but this is a "shall" requirement, so we'd only do it in // ParseStrictness::Permissive mode, and this hasn't shown up in the wild - return Err(Error::InvalidData( - "There shall be at most one occurrence of a given item_ID, \ - in the set of ItemPropertyAssociationBox boxes \ - per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1", - )); + return Status::IpmaDuplicateItemId.into(); } - const TRANSFORM_ORDER_ERROR: &str = - "These properties, if used, shall be indicated to be applied \ - in the following order: clean aperture first, then rotation, \ - then mirror. \ - per MIAF (ISO/IEC 23000-22:2019) § 7.3.6.7"; const TRANSFORM_ORDER: &[BoxType] = &[ + BoxType::ImageSpatialExtentsProperty, BoxType::CleanApertureBox, BoxType::ImageRotation, BoxType::ImageMirror, @@ -2797,10 +3142,9 @@ fn read_iprp( for a in &association_entry.associations { if a.property_index == PropertyIndex(0) { if a.essential { - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "the essential indicator shall be 0 for property index 0 \ - per ISOBMFF (ISO 14496-12:2020 § 8.11.14.3", + Status::IpmaIndexZeroNoEssential, )?; } continue; @@ -2850,9 +3194,9 @@ fn read_iprp( // This is a "shall", but it is likely to change, so only // fail if using strict parsing. // See https://github.com/mozilla/mp4parse-rust/issues/284 - fail_with_error_if( + fail_with_status_if( strictness == ParseStrictness::Strict, - Status::TxformNoEssential.into(), + Status::TxformNoEssential, )?; } } @@ -2869,11 +3213,9 @@ fn read_iprp( a.property_index, prev_colr_index ); - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "Each item shall have at most one property association with a - ColourInformationBox (colr) for a given value of colour_type \ - per HEIF (ISO/IEC DIS 23008-12) § 6.5.5.1", + Status::ColrBadQuantity, )?; } else { colour_type_indexes.insert(colour_type, a.property_index)?; @@ -2885,9 +3227,9 @@ fn read_iprp( ItemProperty::LayeredImageIndexing => { assert!(feature.is_ok() && unsupported_features.contains(feature?)); if a.essential { - fail_with_error_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - Status::A1lxEssential.into(), + Status::A1lxEssential, )?; } } @@ -2900,9 +3242,9 @@ fn read_iprp( || strictness == ParseStrictness::Permissive ); } else { - fail_with_error_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - Status::LselNoEssential.into(), + Status::LselNoEssential, )?; } } @@ -2915,9 +3257,9 @@ fn read_iprp( || strictness == ParseStrictness::Permissive ); } else { - fail_with_error_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - Status::A1opNoEssential.into(), + Status::A1opNoEssential, )?; } } @@ -2934,10 +3276,19 @@ fn read_iprp( if let Some(prev) = prev_transform_index { if prev >= transform_index { error!( - "{:?} after {:?}", + "Invalid property order: {:?} after {:?}", TRANSFORM_ORDER[transform_index], TRANSFORM_ORDER[prev] ); - return Err(Error::InvalidData(TRANSFORM_ORDER_ERROR)); + fail_with_status_if( + strictness != ParseStrictness::Permissive, + if TRANSFORM_ORDER[transform_index] + == BoxType::ImageSpatialExtentsProperty + { + Status::TxformBeforeIspe + } else { + Status::TxformOrder + }, + )?; } } prev_transform_index = Some(transform_index); @@ -2947,9 +3298,9 @@ fn read_iprp( "Missing property at {:?} for {:?}", a.property_index, association_entry.item_id ); - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "Invalid property index in ipma", + Status::IpmaBadIndex, )?; } } @@ -2968,7 +3319,7 @@ fn read_iprp( Ok(iprp) } -/// See ISOBMFF (ISO 14496-12:2020 § 8.11.14.1 +/// See ISOBMFF (ISO 14496-12:2020) § 8.11.14.1 /// Variants with no associated data are recognized but not necessarily supported. /// See [`Feature`] to determine support. #[derive(Debug)] @@ -3016,14 +3367,14 @@ struct ItemPropertyAssociationEntry { } /// For storing ItemPropertyAssociation data -/// See ISOBMFF (ISO 14496-12:2020 § 8.11.14.1 +/// See ISOBMFF (ISO 14496-12:2020) § 8.11.14.1 #[derive(Debug)] struct Association { essential: bool, property_index: PropertyIndex, } -/// See ISOBMFF (ISO 14496-12:2020 § 8.11.14.1 +/// See ISOBMFF (ISO 14496-12:2020) § 8.11.14.1 /// /// The properties themselves are stored in `properties`, but the items they're /// associated with are stored in `association_entries`. It's necessary to @@ -3077,7 +3428,7 @@ impl ItemPropertiesBox { property_type, multiple_values ); // TODO: add test - Err(Error::InvalidData("conflicting item property values")) + Status::IprpConflict.into() } } } @@ -3158,7 +3509,7 @@ macro_rules! impl_bounded_product { } mod bounded_uints { - use UpperBounded; + use crate::UpperBounded; impl_bounded!(U8, u8); impl_bounded!(U16, u16); @@ -3173,7 +3524,7 @@ mod bounded_uints { } } -use bounded_uints::*; +use crate::bounded_uints::*; /// Implement the multiplication operator for $lhs * $rhs giving $output, which /// is internally represented as $inner. The operation is statically checked @@ -3184,8 +3535,13 @@ macro_rules! impl_mul { type Output = $output; fn mul(self, rhs: $rhs) -> Self::Output { - static_assertions::const_assert!(<$output>::MAX <= <$inner>::MAX as u64); - static_assertions::const_assert!(<$lhs>::MAX * <$rhs>::MAX <= <$output>::MAX); + static_assertions::const_assert!( + <$output as UpperBounded>::MAX <= <$inner>::MAX as u64 + ); + static_assertions::const_assert!( + <$lhs as UpperBounded>::MAX * <$rhs as UpperBounded>::MAX + <= <$output as UpperBounded>::MAX + ); let lhs: $inner = self.get().into(); let rhs: $inner = rhs.get().into(); @@ -3219,7 +3575,7 @@ const MAX_IPMA_ASSOCIATION_COUNT: U8 = U8::new(u8::MAX); /// types implementing the UpperBounded trait. Types are declared explicitly to /// show there isn't any accidental inference to primitive types. /// -/// See ISOBMFF (ISO 14496-12:2020 § 8.11.14.1 +/// See ISOBMFF (ISO 14496-12:2020) § 8.11.14.1 fn calculate_ipma_total_associations( version: u8, bytes_left: u64, @@ -3236,9 +3592,7 @@ fn calculate_ipma_total_associations( // All the storage for the `essential` and `property_index` parts (assuming a valid ipma box size) difference } else { - return Err(Error::InvalidData( - "ipma box below minimum size for entry_count", - )); + return Status::IpmaTooSmall.into(); }; let max_association_bytes_per_entry: U16 = MAX_IPMA_ASSOCIATION_COUNT * num_association_bytes; @@ -3246,9 +3600,7 @@ fn calculate_ipma_total_associations( let max_bytes_left: U64 = total_non_association_bytes + max_total_association_bytes; if bytes_left > max_bytes_left.get() { - return Err(Error::InvalidData( - "ipma box exceeds maximum size for entry_count", - )); + return Status::IpmaTooBig.into(); } let total_associations: u64 = total_association_bytes / u64::from(num_association_bytes.get()); @@ -3258,7 +3610,7 @@ fn calculate_ipma_total_associations( /// Parse an ItemPropertyAssociation box /// -/// See ISOBMFF (ISO 14496-12:2020 § 8.11.14.1 +/// See ISOBMFF (ISO 14496-12:2020) § 8.11.14.1 fn read_ipma( src: &mut BMFFBox, strictness: ParseStrictness, @@ -3290,11 +3642,9 @@ fn read_ipma( if let Some(previous_association) = entries.last() { #[allow(clippy::comparison_chain)] if previous_association.item_id > item_id { - return Err(Error::InvalidData( - "Each ItemPropertyAssociation box shall be ordered by increasing item_ID", - )); + return Status::IpmaBadItemOrder.into(); } else if previous_association.item_id == item_id { - return Err(Error::InvalidData("There shall be at most one association box for each item_ID, in any ItemPropertyAssociation box")); + return Status::IpmaDuplicateItemId.into(); } } @@ -3329,10 +3679,9 @@ fn read_ipma( }) = entries.last() { if *max_item_id <= ItemId(u16::MAX.into()) { - fail_if( + fail_with_status_if( strictness == ParseStrictness::Strict, - "The ipma version 0 should be used unless 32-bit item_ID values are needed \ - per ISOBMFF (ISO 14496-12:2020 § 8.11.14.1", + Status::IpmaBadVersion, )?; } } @@ -3345,7 +3694,7 @@ fn read_ipma( /// Parse an ItemPropertyContainerBox /// -/// See ISOBMFF (ISO 14496-12:2020 § 8.11.14.1 +/// See ISOBMFF (ISO 14496-12:2020) § 8.11.14.1 fn read_ipco( src: &mut BMFFBox, strictness: ParseStrictness, @@ -3391,7 +3740,7 @@ fn read_ipco( index .0 .checked_add(1) // must include ignored properties to have correct indexes - .ok_or(Error::InvalidData("ipco index overflow"))?, + .ok_or_else(|| Error::from(Status::IpcoIndexOverflow))?, ); check_parser_state!(b.content); @@ -3401,7 +3750,7 @@ fn read_ipco( } #[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ImageSpatialExtentsProperty { image_width: u32, image_height: u32, @@ -3463,7 +3812,7 @@ fn read_pixi(src: &mut BMFFBox) -> Result { let num_channels_read = src.try_read_to_end(&mut bits_per_channel)?; if u8::try_from(num_channels_read)? != num_channels { - return Err(Error::InvalidData("invalid num_channels")); + return Status::PixiBadChannelCount.into(); } check_parser_state!(src.content); @@ -3539,14 +3888,12 @@ fn read_colr( NUM_RESERVED_BITS, bit_reader.remaining() ); - return Err(Error::InvalidData("Unexpected size for colr box")); + return Status::ColrBadSize.into(); } if bit_reader.read_u8(NUM_RESERVED_BITS)? != 0 { - fail_if( + fail_with_status_if( strictness != ParseStrictness::Permissive, - "The 7 reserved bits at the end of the ColourInformationBox \ - for colour_type == 'nclx' must be 0 \ - per ISOBMFF (ISO 14496-12:2020) § 12.1.5.2", + Status::ColrReservedNonzero, )?; } @@ -3565,9 +3912,7 @@ fn read_colr( )), _ => { error!("read_colr colour_type: {:?}", colour_type); - Err(Error::InvalidData( - "Unsupported colour_type for ColourInformationBox", - )) + Status::ColrBadType.into() } } } @@ -3676,7 +4021,7 @@ fn read_auxc(src: &mut BMFFBox) -> Result { if let Some(nul_byte_pos) = aux.iter().position(|&b| b == b'\0') { let (a, b) = aux.as_slice().split_at(nul_byte_pos); aux_type = a.try_into()?; - aux_subtype = (&b[1..]).try_into()?; + aux_subtype = (b[1..]).try_into()?; } else { aux_type = aux; aux_subtype = TryVec::new(); @@ -3734,7 +4079,7 @@ fn read_iloc(src: &mut BMFFBox) -> Result ConstructionMethod::File, 1 => ConstructionMethod::Idat, 2 => ConstructionMethod::Item, - _ => return Err(Error::InvalidData("construction_method is taken from the set 0, 1 or 2 per ISOBMFF (ISO 14496-12:2020) § 8.11.3.3")) + _ => return Status::IlocBadConstructionMethod.into(), } } }; @@ -3749,9 +4094,7 @@ fn read_iloc(src: &mut BMFFBox) -> Result(src: &mut BMFFBox) -> Result(src: &mut BMFFBox) -> Result(src: &mut BMFFBox) -> Result(f: &mut T) -> Result { // XXX(kinetik): This isn't perfect, as a "moov" with no contents is // treated as okay but we haven't found anything useful. Needs more // thought for clearer behaviour here. - context.ok_or(Error::NoMoov) + context.ok_or(Error::MoovMissing) } /// Parse a Movie Header Box @@ -3882,7 +4223,7 @@ fn parse_mvhd(f: &mut BMFFBox) -> Result> { let mvhd = read_mvhd(f)?; debug!("{:?}", mvhd); if mvhd.timescale == 0 { - return Err(Error::InvalidData("zero timescale in mdhd")); + return Status::MvhdBadTimescale.into(); } let timescale = Some(MediaTimeScale(u64::from(mvhd.timescale))); Ok(timescale) @@ -3961,9 +4302,15 @@ fn read_pssh(src: &mut BMFFBox) -> Result::new(); if version > 0 { - let count = be_u32(pssh)?; + const KID_ELEMENT_SIZE: usize = 16; + let count = be_u32(pssh)?.to_usize(); + kid.reserve( + count + .checked_mul(KID_ELEMENT_SIZE) + .ok_or_else(|| Error::from(Status::PsshSizeOverflow))?, + )?; for _ in 0..count { - let item = read_buf(pssh, 16)?; + let item = read_buf(pssh, KID_ELEMENT_SIZE.to_u64())?; kid.push(item)?; } } @@ -4009,7 +4356,7 @@ fn read_mehd(src: &mut BMFFBox) -> Result { let fragment_duration = match version { 1 => be_u64(src)?, 0 => u64::from(be_u32(src)?), - _ => return Err(Error::InvalidData("unhandled mehd version")), + _ => return Status::MehdBadVersion.into(), }; Ok(MediaScaledTime(fragment_duration)) } @@ -4028,6 +4375,7 @@ fn read_trak(f: &mut BMFFBox, track: &mut Track) -> Result<()> { } BoxType::EditBox => read_edts(&mut b, track)?, BoxType::MediaBox => read_mdia(&mut b, track)?, + BoxType::TrackReferenceBox => track.tref = Some(read_tref(&mut b)?), _ => skip_box_content(&mut b)?, }; check_parser_state!(b.content); @@ -4091,7 +4439,7 @@ fn parse_mdhd( duration => Some(TrackScaledTime::(duration, track.id)), }; if mdhd.timescale == 0 { - return Err(Error::InvalidData("zero timescale in mdhd")); + return Status::MdhdBadTimescale.into(); } let timescale = Some(TrackTimeScale::(u64::from(mdhd.timescale), track.id)); Ok((mdhd, duration, timescale)) @@ -4112,6 +4460,8 @@ fn read_mdia(f: &mut BMFFBox, track: &mut Track) -> Result<()> { match hdlr.handler_type.value.as_ref() { b"vide" => track.track_type = TrackType::Video, + b"pict" => track.track_type = TrackType::Picture, + b"auxv" => track.track_type = TrackType::AuxiliaryVideo, b"soun" => track.track_type = TrackType::Audio, b"meta" => track.track_type = TrackType::Metadata, _ => (), @@ -4126,6 +4476,32 @@ fn read_mdia(f: &mut BMFFBox, track: &mut Track) -> Result<()> { Ok(()) } +fn read_tref(f: &mut BMFFBox) -> Result { + // Will likely only see trefs with one auxl + let mut references = TryVec::with_capacity(1)?; + let mut iter = f.box_iter(); + while let Some(mut b) = iter.next_box()? { + match b.head.name { + BoxType::AuxiliaryBox => { + references.push(TrackReferenceEntry::Auxiliary(read_tref_auxl(&mut b)?))? + } + _ => skip_box_content(&mut b)?, + }; + check_parser_state!(b.content); + } + Ok(TrackReferenceBox { references }) +} + +fn read_tref_auxl(f: &mut BMFFBox) -> Result { + let num_track_ids = (f.bytes_left() / std::mem::size_of::().to_u64()).try_into()?; + let mut track_ids = TryVec::with_capacity(num_track_ids)?; + for _ in 0..num_track_ids { + track_ids.push(be_u32(f)?)?; + } + + Ok(TrackReference { track_ids }) +} + fn read_minf(f: &mut BMFFBox, track: &mut Track) -> Result<()> { let mut iter = f.box_iter(); while let Some(mut b) = iter.next_box()? { @@ -4196,7 +4572,7 @@ fn read_ftyp(src: &mut BMFFBox) -> Result { let minor = be_u32(src)?; let bytes_left = src.bytes_left(); if bytes_left % 4 != 0 { - return Err(Error::InvalidData("invalid ftyp size")); + return Status::FtypBadSize.into(); } // Is a brand_count of zero valid? let brand_count = bytes_left / 4; @@ -4223,7 +4599,7 @@ fn read_mvhd(src: &mut BMFFBox) -> Result { 0 => { skip(src, 8)?; } - _ => return Err(Error::InvalidData("unhandled mvhd version")), + _ => return Status::MvhdBadVersion.into(), } let timescale = be_u32(src)?; let duration = match version { @@ -4236,7 +4612,7 @@ fn read_mvhd(src: &mut BMFFBox) -> Result { u64::from(d) } } - _ => return Err(Error::InvalidData("unhandled mvhd version")), + _ => unreachable!("Should have returned Status::MvhdBadVersion"), }; // Skip remaining fields. skip(src, 80)?; @@ -4259,14 +4635,14 @@ fn read_tkhd(src: &mut BMFFBox) -> Result { 0 => { skip(src, 8)?; } - _ => return Err(Error::InvalidData("unhandled tkhd version")), + _ => return Status::TkhdBadVersion.into(), } let track_id = be_u32(src)?; skip(src, 4)?; let duration = match version { 1 => be_u64(src)?, 0 => u64::from(be_u32(src)?), - _ => return Err(Error::InvalidData("unhandled tkhd version")), + _ => unreachable!("Should have returned Status::TkhdBadVersion"), }; // Skip uninteresting fields. skip(src, 16)?; @@ -4311,7 +4687,7 @@ fn read_elst(src: &mut BMFFBox) -> Result { // 32 bit segment duration and media times. (u64::from(be_u32(src)?), i64::from(be_i32(src)?)) } - _ => return Err(Error::InvalidData("unhandled elst version")), + _ => return Status::ElstBadVersion.into(), }; let media_rate_integer = be_i16(src)?; let media_rate_fraction = be_i16(src)?; @@ -4359,7 +4735,7 @@ fn read_mdhd(src: &mut BMFFBox) -> Result { }; (timescale, duration) } - _ => return Err(Error::InvalidData("unhandled mdhd version")), + _ => return Status::MdhdBadVersion.into(), }; // Skip uninteresting fields. @@ -4453,7 +4829,7 @@ fn read_ctts(src: &mut BMFFBox) -> Result { .checked_mul(8) .map_or(true, |bytes| u64::from(bytes) > src.bytes_left()) { - return Err(Error::InvalidData("insufficient data in 'ctts' box")); + return Status::CttsBadSize.into(); } let mut offsets = TryVec::with_capacity(counts.to_usize())?; @@ -4468,7 +4844,7 @@ fn read_ctts(src: &mut BMFFBox) -> Result { (count, offset) } _ => { - return Err(Error::InvalidData("unsupported version in 'ctts' box")); + return Status::CttsBadVersion.into(); } }; offsets.push(TimeOffset { @@ -4652,9 +5028,7 @@ fn read_flac_metadata(src: &mut BMFFBox) -> Result src.bytes_left() { - return Err(Error::InvalidData( - "FLACMetadataBlock larger than parent box", - )); + return Status::DflaBadMetadataBlockSize.into(); } let data = read_buf(src, length)?; Ok(FLACMetadataBlock { block_type, data }) @@ -4694,7 +5068,7 @@ fn find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> { } if end.to_usize() > remains.len() || u64::from(end) < des.position() { - return Err(Error::InvalidData("Invalid descriptor.")); + return Status::EsdsBadDescriptor.into(); } let descriptor = &remains[des.position().try_into()?..end.to_usize()]; @@ -4889,9 +5263,7 @@ fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> { esds.audio_sample_rate = Some(sample_frequency_value); esds.audio_channel_count = Some(channel_counts); if !esds.decoder_specific_data.is_empty() { - return Err(Error::InvalidData( - "There can be only one DecSpecificInfoTag descriptor", - )); + return Status::EsdsDecSpecificIntoTagQuantity.into(); } esds.decoder_specific_data.extend_from_slice(data)?; @@ -4995,7 +5367,7 @@ fn read_dfla(src: &mut BMFFBox) -> Result { return Err(Error::Unsupported("unknown dfLa (FLAC) version")); } if flags != 0 { - return Err(Error::InvalidData("no-zero dfLa (FLAC) flags")); + return Status::DflaFlagsNonzero.into(); } let mut blocks = TryVec::new(); while src.bytes_left() > 0 { @@ -5005,15 +5377,11 @@ fn read_dfla(src: &mut BMFFBox) -> Result { // The box must have at least one meta block, and the first block // must be the METADATA_BLOCK_STREAMINFO if blocks.is_empty() { - return Err(Error::InvalidData("FLACSpecificBox missing metadata")); + return Status::DflaMissingMetadata.into(); } else if blocks[0].block_type != 0 { - return Err(Error::InvalidData( - "FLACSpecificBox must have STREAMINFO metadata first", - )); + return Status::DflaStreamInfoNotFirst.into(); } else if blocks[0].data.len() != 34 { - return Err(Error::InvalidData( - "FLACSpecificBox STREAMINFO block is the wrong size", - )); + return Status::DflaStreamInfoBadSize.into(); } Ok(FLACSpecificBox { version, blocks }) } @@ -5071,7 +5439,7 @@ pub fn serialize_opus_header( Err(e) => return Err(Error::from(e)), Ok(bytes) => { if bytes != 8 { - return Err(Error::InvalidData("Couldn't write OpusHead tag.")); + return Status::DopsOpusHeadWriteErr.into(); } } } @@ -5094,9 +5462,7 @@ pub fn serialize_opus_header( Err(e) => return Err(Error::from(e)), Ok(bytes) => { if bytes != table.channel_mapping.len() { - return Err(Error::InvalidData( - "Couldn't write channel mapping table data.", - )); + return Status::DopsChannelMappingWriteErr.into(); } } } @@ -5112,15 +5478,13 @@ fn read_alac(src: &mut BMFFBox) -> Result { return Err(Error::Unsupported("unknown alac (ALAC) version")); } if flags != 0 { - return Err(Error::InvalidData("no-zero alac (ALAC) flags")); + return Status::AlacFlagsNonzero.into(); } let length = match src.bytes_left() { x @ 24 | x @ 48 => x, _ => { - return Err(Error::InvalidData( - "ALACSpecificBox magic cookie is the wrong size", - )) + return Status::AlacBadMagicCookieSize.into(); } }; let data = read_buf(src, length)?; @@ -5133,15 +5497,14 @@ fn read_alac(src: &mut BMFFBox) -> Result { /// See [\[ISOBMFF\]: reserved (field = 0;) handling is ambiguous](https://github.com/MPEGGroup/FileFormat/issues/36) fn read_hdlr(src: &mut BMFFBox, strictness: ParseStrictness) -> Result { if read_fullbox_version_no_flags(src)? != 0 { - return Err(Error::Unsupported("hdlr version")); + return Status::HdlrUnsupportedVersion.into(); } let pre_defined = be_u32(src)?; if pre_defined != 0 { - fail_if( + fail_with_status_if( strictness == ParseStrictness::Strict, - "The HandlerBox 'pre_defined' field shall be 0 \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", + Status::HdlrPredefinedNonzero, )?; } @@ -5150,10 +5513,9 @@ fn read_hdlr(src: &mut BMFFBox, strictness: ParseStrictness) -> Resu for _ in 1..=3 { let reserved = be_u32(src)?; if reserved != 0 { - fail_if( + fail_with_status_if( strictness == ParseStrictness::Strict, - "The HandlerBox 'reserved' fields shall be 0 \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", + Status::HdlrReservedNonzero, )?; } } @@ -5161,29 +5523,25 @@ fn read_hdlr(src: &mut BMFFBox, strictness: ParseStrictness) -> Resu match std::str::from_utf8(src.read_into_try_vec()?.as_slice()) { Ok(name) => { match name.bytes().filter(|&b| b == b'\0').count() { - 0 => fail_if( + 0 => fail_with_status_if( strictness != ParseStrictness::Permissive, - "The HandlerBox 'name' field shall be null-terminated \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", + Status::HdlrNameNoNul, )?, 1 => (), n => // See https://github.com/MPEGGroup/FileFormat/issues/35 { error!("Found {} nul bytes in {:x?}", n, name); - fail_if( + fail_with_status_if( strictness == ParseStrictness::Strict, - "The HandlerBox 'name' field shall have a NUL byte \ - only in the final position \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", + Status::HdlrNameMultipleNul, )? } } } - Err(_) => fail_if( + Err(_) => fail_with_status_if( strictness != ParseStrictness::Permissive, - "The HandlerBox 'name' field shall be valid utf8 \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", + Status::HdlrNameNotUtf8, )?, } @@ -5233,7 +5591,7 @@ fn read_video_sample_entry(src: &mut BMFFBox) -> Result && name != BoxType::ProtectedVisualSampleEntry) || codec_specific.is_some() { - return Err(Error::InvalidData("malformed video sample entry")); + return Status::StsdBadVideoSampleEntry.into(); } let avcc_size = b .head @@ -5247,7 +5605,7 @@ fn read_video_sample_entry(src: &mut BMFFBox) -> Result } BoxType::H263SpecificBox => { if (name != BoxType::H263SampleEntry) || codec_specific.is_some() { - return Err(Error::InvalidData("malformed video sample entry")); + return Status::StsdBadVideoSampleEntry.into(); } let h263_dec_spec_struc_size = b .head @@ -5266,21 +5624,21 @@ fn read_video_sample_entry(src: &mut BMFFBox) -> Result && name != BoxType::ProtectedVisualSampleEntry) || codec_specific.is_some() { - return Err(Error::InvalidData("malformed video sample entry")); + return Status::StsdBadVideoSampleEntry.into(); } let vpcc = read_vpcc(&mut b)?; codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc)); } BoxType::AV1CodecConfigurationBox => { if name != BoxType::AV1SampleEntry && name != BoxType::ProtectedVisualSampleEntry { - return Err(Error::InvalidData("malformed video sample entry")); + return Status::StsdBadVideoSampleEntry.into(); } let av1c = read_av1c(&mut b)?; codec_specific = Some(VideoCodecSpecific::AV1Config(av1c)); } BoxType::ESDBox => { if name != BoxType::MP4VideoSampleEntry || codec_specific.is_some() { - return Err(Error::InvalidData("malformed video sample entry")); + return Status::StsdBadVideoSampleEntry.into(); } #[cfg(not(feature = "mp4v"))] { @@ -5298,7 +5656,7 @@ fn read_video_sample_entry(src: &mut BMFFBox) -> Result #[cfg(feature = "mp4v")] { // Read ES_Descriptor inside an esds box. - // See ISOBMFF (ISO 14496-1:2010 §7.2.6.5) + // See ISOBMFF (ISO 14496-1:2010) § 7.2.6.5 let esds = read_esds(&mut b)?; codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds.decoder_specific_data)); @@ -5306,7 +5664,7 @@ fn read_video_sample_entry(src: &mut BMFFBox) -> Result } BoxType::ProtectionSchemeInfoBox => { if name != BoxType::ProtectedVisualSampleEntry { - return Err(Error::InvalidData("malformed video sample entry")); + return Status::StsdBadVideoSampleEntry.into(); } let sinf = read_sinf(&mut b)?; debug!("{:?} (sinf)", sinf); @@ -5347,7 +5705,7 @@ fn read_qt_wave_atom(src: &mut BMFFBox) -> Result { } } - codec_specific.ok_or(Error::InvalidData("malformed audio sample entry")) + codec_specific.ok_or_else(|| Error::from(Status::EsdsBadAudioSampleEntry)) } /// Parse an audio description inside an stsd box. @@ -5424,7 +5782,7 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result && name != BoxType::ProtectedAudioSampleEntry) || codec_specific.is_some() { - return Err(Error::InvalidData("malformed audio sample entry")); + return Status::StsdBadAudioSampleEntry.into(); } let esds = read_esds(&mut b)?; codec_type = esds.audio_codec; @@ -5434,7 +5792,7 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result if (name != BoxType::FLACSampleEntry && name != BoxType::ProtectedAudioSampleEntry) || codec_specific.is_some() { - return Err(Error::InvalidData("malformed audio sample entry")); + return Status::StsdBadAudioSampleEntry.into(); } let dfla = read_dfla(&mut b)?; codec_type = CodecType::FLAC; @@ -5444,7 +5802,7 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result if (name != BoxType::OpusSampleEntry && name != BoxType::ProtectedAudioSampleEntry) || codec_specific.is_some() { - return Err(Error::InvalidData("malformed audio sample entry")); + return Status::StsdBadAudioSampleEntry.into(); } let dops = read_dops(&mut b)?; codec_type = CodecType::Opus; @@ -5452,7 +5810,7 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result } BoxType::ALACSpecificBox => { if name != BoxType::ALACSpecificBox || codec_specific.is_some() { - return Err(Error::InvalidData("malformed audio sample entry")); + return Status::StsdBadAudioSampleEntry.into(); } let alac = read_alac(&mut b)?; codec_type = CodecType::ALAC; @@ -5465,7 +5823,7 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result } BoxType::ProtectionSchemeInfoBox => { if name != BoxType::ProtectedAudioSampleEntry { - return Err(Error::InvalidData("malformed audio sample entry")); + return Status::StsdBadAudioSampleEntry.into(); } let sinf = read_sinf(&mut b)?; debug!("{:?} (sinf)", sinf); @@ -5475,7 +5833,7 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result #[cfg(feature = "3gpp")] BoxType::AMRSpecificBox => { if codec_type != CodecType::AMRNB && codec_type != CodecType::AMRWB { - return Err(Error::InvalidData("malformed audio sample entry")); + return Status::StsdBadAudioSampleEntry.into(); } let amr_dec_spec_struc_size = b .head @@ -5513,16 +5871,25 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result /// See ISOBMFF (ISO 14496-12:2020) § 8.5.2 /// See MP4 (ISO 14496-14:2020) § 6.7.2 fn read_stsd(src: &mut BMFFBox, track: &mut Track) -> Result { - let (_, _) = read_fullbox_extra(src)?; + let (_, flags) = read_fullbox_extra(src)?; - let description_count = be_u32(src)?; - let mut descriptions = TryVec::new(); + if flags != 0 { + warn!( + "Unexpected `flags` value for SampleDescriptionBox (stsd): {}", + flags + ); + } - { - let mut iter = src.box_iter(); - while let Some(mut b) = iter.next_box()? { + let description_count = be_u32(src)?.to_usize(); + let mut descriptions = TryVec::with_capacity(description_count)?; + + let mut iter = src.box_iter(); + while descriptions.len() < description_count { + if let Some(mut b) = iter.next_box()? { let description = match track.track_type { TrackType::Video => read_video_sample_entry(&mut b), + TrackType::Picture => read_video_sample_entry(&mut b), + TrackType::AuxiliaryVideo => read_video_sample_entry(&mut b), TrackType::Audio => read_audio_sample_entry(&mut b), TrackType::Metadata => Err(Error::Unsupported("metadata track")), TrackType::Unknown => Err(Error::Unsupported("unknown track type")), @@ -5541,9 +5908,8 @@ fn read_stsd(src: &mut BMFFBox, track: &mut Track) -> Result(src: &mut BMFFBox) -> Result match b.head.name { BoxType::TrackEncryptionBox => { if tenc.is_some() { - return Err(Error::InvalidData( - "tenc box should be only one at most in sinf box", - )); + return Status::SchiQuantity.into(); } tenc = Some(read_tenc(&mut b)?); } @@ -5777,7 +6141,7 @@ fn read_ilst(src: &mut BMFFBox, meta: &mut MetadataBox) -> Result<() BoxType::CompilationEntry => meta.compilation = read_ilst_bool_data(&mut b)?, BoxType::AdvisoryEntry => { meta.advisory = read_ilst_u8_data(&mut b)?.and_then(|rtng| { - Some(match rtng.get(0)? { + Some(match rtng.first()? { 2 => AdvisoryRating::Clean, 0 => AdvisoryRating::Inoffensive, r => AdvisoryRating::Explicit(*r), @@ -5786,7 +6150,7 @@ fn read_ilst(src: &mut BMFFBox, meta: &mut MetadataBox) -> Result<() } BoxType::MediaTypeEntry => { meta.media_type = read_ilst_u8_data(&mut b)?.and_then(|stik| { - Some(match stik.get(0)? { + Some(match stik.first()? { 0 => MediaType::Movie, 1 => MediaType::Normal, 2 => MediaType::AudioBook, @@ -5817,7 +6181,7 @@ fn read_ilst(src: &mut BMFFBox, meta: &mut MetadataBox) -> Result<() } fn read_ilst_bool_data(src: &mut BMFFBox) -> Result> { - Ok(read_ilst_u8_data(src)?.and_then(|d| Some(d.get(0)? == &1))) + Ok(read_ilst_u8_data(src)?.and_then(|d| Some(d.first()? == &1))) } fn read_ilst_string_data(src: &mut BMFFBox) -> Result> { @@ -5861,7 +6225,7 @@ fn skip(src: &mut T, bytes: u64) -> Result<()> { fn read_buf(src: &mut T, size: u64) -> Result> { let buf = src.take(size).read_into_try_vec()?; if buf.len().to_u64() != size { - return Err(Error::InvalidData("failed buffer read")); + return Status::ReadBufErr.into(); } Ok(buf) diff --git a/third_party/rust/mp4parse/src/macros.rs b/third_party/rust/mp4parse/src/macros.rs index a893f7e1ac9a..15244a316fb8 100644 --- a/third_party/rust/mp4parse/src/macros.rs +++ b/third_party/rust/mp4parse/src/macros.rs @@ -6,7 +6,7 @@ macro_rules! check_parser_state { ( $src:expr ) => { if $src.limit() > 0 { debug!("bad parser state: {} content bytes left", $src.limit()); - return Err(Error::InvalidData("unread box content or bad parser sync")); + return Status::CheckParserStateErr.into(); } }; } diff --git a/third_party/rust/mp4parse/src/tests.rs b/third_party/rust/mp4parse/src/tests.rs index 0f2276002019..fa8d69e3e104 100644 --- a/third_party/rust/mp4parse/src/tests.rs +++ b/third_party/rust/mp4parse/src/tests.rs @@ -6,17 +6,16 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use super::read_mp4; -use super::Error; use super::ParseStrictness; +use super::{Error, Status}; use fallible_collections::TryRead as _; use std::convert::TryInto as _; use std::io::Cursor; use std::io::Read as _; -extern crate test_assembler; -use self::test_assembler::*; +use test_assembler::*; -use boxes::BoxType; +use crate::boxes::BoxType; enum BoxSize { Short(u32), @@ -122,7 +121,7 @@ fn read_box_header_short_unknown_size() { fn read_box_header_short_invalid_size() { let mut stream = make_box(BoxSize::UncheckedShort(2), b"test", |s| s); match super::read_box_header(&mut stream) { - Err(Error::InvalidData(s)) => assert_eq!(s, "malformed size"), + Err(Error::InvalidData(s)) => assert_eq!(s, Status::BoxBadSize), _ => panic!("unexpected result reading box with invalid size"), }; } @@ -131,7 +130,7 @@ fn read_box_header_short_invalid_size() { fn read_box_header_long_invalid_size() { let mut stream = make_box(BoxSize::UncheckedLong(2), b"test", |s| s); match super::read_box_header(&mut stream) { - Err(Error::InvalidData(s)) => assert_eq!(s, "malformed wide size"), + Err(Error::InvalidData(s)) => assert_eq!(s, Status::BoxBadWideSize), _ => panic!("unexpected result reading box with invalid size"), }; } @@ -490,7 +489,10 @@ fn read_hdlr_multiple_nul_in_name() { let mut stream = iter.next_box().unwrap().unwrap(); assert_eq!(stream.head.name, BoxType::HandlerBox); assert_eq!(stream.head.size, 45); - assert!(super::read_hdlr(&mut stream, ParseStrictness::Strict).is_err()); + assert_eq!( + super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Strict)), + super::Status::HdlrNameMultipleNul, + ); } #[test] @@ -515,13 +517,10 @@ fn read_hdlr_unsupported_version() { let mut stream = iter.next_box().unwrap().unwrap(); assert_eq!(stream.head.name, BoxType::HandlerBox); assert_eq!(stream.head.size, 32); - match super::read_hdlr(&mut stream, ParseStrictness::Normal) { - Err(Error::Unsupported(msg)) => assert_eq!("hdlr version", msg), - result => { - eprintln!("{:?}", result); - panic!("expected Error::Unsupported") - } - } + assert_eq!( + super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Normal)), + super::Status::HdlrUnsupportedVersion, + ); } #[test] @@ -533,17 +532,10 @@ fn read_hdlr_invalid_pre_defined_field() { let mut stream = iter.next_box().unwrap().unwrap(); assert_eq!(stream.head.name, BoxType::HandlerBox); assert_eq!(stream.head.size, 32); - match super::read_hdlr(&mut stream, ParseStrictness::Strict) { - Err(Error::InvalidData(msg)) => assert_eq!( - "The HandlerBox 'pre_defined' field shall be 0 \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", - msg - ), - result => { - eprintln!("{:?}", result); - panic!("expected Error::InvalidData") - } - } + assert_eq!( + super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Strict)), + super::Status::HdlrPredefinedNonzero, + ); } #[test] @@ -555,17 +547,10 @@ fn read_hdlr_invalid_reserved_field() { let mut stream = iter.next_box().unwrap().unwrap(); assert_eq!(stream.head.name, BoxType::HandlerBox); assert_eq!(stream.head.size, 32); - match super::read_hdlr(&mut stream, ParseStrictness::Strict) { - Err(Error::InvalidData(msg)) => assert_eq!( - "The HandlerBox 'reserved' fields shall be 0 \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", - msg - ), - result => { - eprintln!("{:?}", result); - panic!("expected Error::InvalidData") - } - } + assert_eq!( + super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Strict)), + super::Status::HdlrReservedNonzero, + ); } #[test] @@ -577,17 +562,10 @@ fn read_hdlr_zero_length_name() { let mut stream = iter.next_box().unwrap().unwrap(); assert_eq!(stream.head.name, BoxType::HandlerBox); assert_eq!(stream.head.size, 32); - match super::read_hdlr(&mut stream, ParseStrictness::Normal) { - Err(Error::InvalidData(msg)) => assert_eq!( - "The HandlerBox 'name' field shall be null-terminated \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2", - msg - ), - result => { - eprintln!("{:?}", result); - panic!("expected Error::InvalidData") - } - } + assert_eq!( + super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Normal)), + super::Status::HdlrNameNoNul, + ); } #[test] @@ -1278,7 +1256,7 @@ fn read_esds_invalid_descriptor() { let mut stream = iter.next_box().unwrap().unwrap(); match super::read_esds(&mut stream) { - Err(Error::InvalidData(s)) => assert_eq!(s, "Invalid descriptor."), + Err(Error::InvalidData(s)) => assert_eq!(s, Status::EsdsBadDescriptor), _ => panic!("unexpected result with invalid descriptor"), } } diff --git a/third_party/rust/mp4parse/src/unstable.rs b/third_party/rust/mp4parse/src/unstable.rs index eeb16f8ed80f..da9d479366bc 100644 --- a/third_party/rust/mp4parse/src/unstable.rs +++ b/third_party/rust/mp4parse/src/unstable.rs @@ -106,7 +106,7 @@ impl PartialEq for CheckedInteger { /// sample data offset (start and end), composition time in microseconds /// (start and end) and whether it is a sync sample #[repr(C)] -#[derive(Default, Debug, PartialEq)] +#[derive(Default, Debug, PartialEq, Eq)] pub struct Indice { /// The byte offset in the file where the indexed sample begins. pub start_offset: CheckedInteger, @@ -489,7 +489,7 @@ where }) } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct Microseconds(pub T); /// Convert `time` in media's global (mvhd) timescale to microseconds, diff --git a/third_party/rust/mp4parse/tests/corrupt/invalid-transformation-order.avif b/third_party/rust/mp4parse/tests/corrupt/invalid-transformation-order.avif new file mode 100644 index 0000000000000000000000000000000000000000..d02ef72424fcb07afdeb1f06086d7f193849491d GIT binary patch literal 345 zcmYk1y-or_5XWZ^VonM|VGI&tV&#R(v$P_yGQ5G^ZQsFX3C9JUbrH1x4sN)dDzYCv|j8(B9$T>{kK*h#j}#Y=o>R@96_8#ybuKhy1Yb6}G=(B~$9{LF|torlrK=6{_GXpCA<IIh+pP(+;pkIZXfn literal 0 HcmV?d00001 diff --git a/third_party/rust/mp4parse/tests/corrupt/no-alpha-ispe.avif b/third_party/rust/mp4parse/tests/corrupt/no-alpha-ispe.avif new file mode 100644 index 0000000000000000000000000000000000000000..0183a608314654c7970f2a977d3c87adcf367767 GIT binary patch literal 449 zcmYLF!AiqG5S=6?7Kx>Zh?XAWUBvWMa*OG~gMP%4ZtOs|S&}p~M-eZcym;~lJozzx zk#AB$2WH=U`(}1_mx#i=>8xrwCxoEkJTk2E=OjvqoZ9F{iHEq^tc&VEi7aQ$zz3XI zZcHy6thZd0nWzet_4|2lWj+L#~*&xs)Kpn?Y(J(xck@C@qV!pM7*-i<1;~ zqoi`imF}MbK2f`U(NC2_f7wk+g@ z$R|=ah0z@EU|FUJKq+=6vV;M`Iuk(I+Yxu?`Hkbd()e4nRp_&5(LfL7K|_Nm0mipT zSy3})`Y40PkLh~7+ObJ+8A#iBvm1z$@RKoj`Soi?G#p;eURJ+Pep bY>q`88zb-L^b{}`zu>J|caw%4w^@fJxkN%po{=ZylHd3k zwR%)Y4bxRM-801y(QV=1)Jc&NV9bpaPPib7?p^NL&VljEs;p0vNG08r(;=1A_{A9>YI{!$BdcE0XyZ_s@M)Zh*fy%3ZsU61_ ZGZb}f9>8C&qR-CPH}s8LvHySffsRSKIII8w literal 84996 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 diff --git a/third_party/rust/mp4parse/tests/irot-missing-essential.avif b/third_party/rust/mp4parse/tests/irot-missing-essential.avif index 8c62e55ecc8c8028fce66de79f1a3e5cbd2ac841..07c32e3604c3139cc9abb180b9792af3e0420893 100644 GIT binary patch literal 337 zcmYjM!D_-l5S^F`(S!6*M5MIz7CbdQdJ^oVztGzdlXf6$hI9#fsT6EK!%y(izv;(l z-)t57mYw(B&g?#xh^|Y&RwrdffHAjHI^mKix^;zTI|uGw7gh5oiBxib)@L55co$5B zdLvbxn|s7NSXL>Tg9q5D$Pxj7b;dA7=j6D(&z>B=6y|rLje_4r^BR05ZyFjz32gj~ zlI9g-<^nQg?2V7d!^s(#LH;T8PU(iFhVE_N_1N{O?IykHV literal 84837 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 diff --git a/third_party/rust/mp4parse/tests/public.rs b/third_party/rust/mp4parse/tests/public.rs index a35cef666649..28ef1ba1e33b 100644 --- a/third_party/rust/mp4parse/tests/public.rs +++ b/third_party/rust/mp4parse/tests/public.rs @@ -2,9 +2,9 @@ // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -extern crate mp4parse as mp4; +use mp4parse as mp4; -use mp4::{Error, ParseStrictness, Status}; +use crate::mp4::{ParseStrictness, Status}; use std::convert::TryInto; use std::fs::File; use std::io::{Cursor, Read, Seek, SeekFrom}; @@ -53,6 +53,9 @@ static IMAGE_AVIF_NO_PITM: &str = "tests/corrupt/no-pitm.avif"; static IMAGE_AVIF_NO_PIXI: &str = "tests/corrupt/no-pixi.avif"; static IMAGE_AVIF_NO_AV1C: &str = "tests/corrupt/no-av1C.avif"; static IMAGE_AVIF_NO_ISPE: &str = "tests/corrupt/no-ispe.avif"; +static IMAGE_AVIF_NO_ALPHA_ISPE: &str = "tests/corrupt/no-alpha-ispe.avif"; +static IMAGE_AVIF_TRANSFORM_ORDER: &str = "tests/corrupt/invalid-transformation-order.avif"; +static IMAGE_AVIF_TRANSFORM_BEFORE_ISPE: &str = "tests/corrupt/transformation-before-ispe.avif"; static IMAGE_AVIF_NO_ALPHA_AV1C: &str = "tests/corrupt/no-alpha-av1C.avif"; static IMAGE_AVIF_NO_ALPHA_PIXI: &str = "tests/corrupt/no-pixi-for-alpha.avif"; static IMAGE_AVIF_AV1C_MISSING_ESSENTIAL: &str = "tests/av1C-missing-essential.avif"; @@ -92,8 +95,6 @@ static AVIF_UNSUPPORTED_IMAGES: &[&str] = &[ AVIF_GRID, AVIF_GRID_A1LX, AVIF_LSEL, - AVIF_AVIS_MAJOR_NO_PITM, - AVIF_AVIS_MAJOR_WITH_PITM_AND_ALPHA, "av1-avif/testFiles/Apple/multilayer_examples/animals_00_multilayer_a1lx.avif", "av1-avif/testFiles/Apple/multilayer_examples/animals_00_multilayer_a1op.avif", "av1-avif/testFiles/Apple/multilayer_examples/animals_00_multilayer_a1op_lsel.avif", @@ -104,7 +105,6 @@ static AVIF_UNSUPPORTED_IMAGES: &[&str] = &[ "av1-avif/testFiles/Microsoft/Chimera_10bit_cropped_to_1920x1008.avif", "av1-avif/testFiles/Microsoft/Chimera_10bit_cropped_to_1920x1008_with_HDR_metadata.avif", "av1-avif/testFiles/Microsoft/Chimera_8bit_cropped_480x256.avif", - "av1-avif/testFiles/Netflix/avis/alpha_video.avif", "av1-avif/testFiles/Xiph/abandoned_filmgrain.avif", "av1-avif/testFiles/Xiph/fruits_2layer_thumbsize.avif", "av1-avif/testFiles/Xiph/quebec_3layer_op2.avif", @@ -112,18 +112,27 @@ static AVIF_UNSUPPORTED_IMAGES: &[&str] = &[ "av1-avif/testFiles/Xiph/tiger_3layer_3res.avif", "link-u-avif-sample-images/kimono.crop.avif", "link-u-avif-sample-images/kimono.mirror-vertical.rotate270.crop.avif", - "link-u-avif-sample-images/star-10bpc-with-alpha.avifs", - "link-u-avif-sample-images/star-10bpc.avifs", - "link-u-avif-sample-images/star-12bpc-with-alpha.avifs", - "link-u-avif-sample-images/star-12bpc.avifs", - "link-u-avif-sample-images/star-8bpc-with-alpha.avifs", - "link-u-avif-sample-images/star-8bpc.avifs", ]; /// See https://github.com/AOMediaCodec/av1-avif/issues/150 /// https://github.com/AOMediaCodec/av1-avif/issues/174 -/// and https://github.com/AOMediaCodec/av1-avif/issues/177 +/// https://github.com/AOMediaCodec/av1-avif/issues/177 +/// and https://github.com/AOMediaCodec/av1-avif/issues/178 // TODO: make this into a map of expected errors? static AV1_AVIF_CORRUPT_IMAGES: &[&str] = &[ + "av1-avif/testFiles/Link-U/kimono.crop.avif", + "av1-avif/testFiles/Link-U/kimono.mirror-horizontal.avif", + "av1-avif/testFiles/Link-U/kimono.mirror-vertical.avif", + "av1-avif/testFiles/Link-U/kimono.mirror-vertical.rotate270.avif", + "av1-avif/testFiles/Link-U/kimono.mirror-vertical.rotate270.crop.avif", + "av1-avif/testFiles/Link-U/kimono.rotate90.avif", + "av1-avif/testFiles/Link-U/kimono.rotate270.avif", + "link-u-avif-sample-images/kimono.crop.avif", + "link-u-avif-sample-images/kimono.mirror-horizontal.avif", + "link-u-avif-sample-images/kimono.mirror-vertical.avif", + "link-u-avif-sample-images/kimono.mirror-vertical.rotate270.avif", + "link-u-avif-sample-images/kimono.mirror-vertical.rotate270.crop.avif", + "link-u-avif-sample-images/kimono.rotate90.avif", + "link-u-avif-sample-images/kimono.rotate270.avif", "link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.avif", "link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-full.monochrome.avif", "link-u-avif-sample-images/plum-blossom-large.profile0.10bpc.yuv420.alpha-limited.avif", @@ -328,7 +337,7 @@ fn public_api() { assert!(a.samplesize > 0); assert!(a.samplerate > 0.0); } - mp4::TrackType::Metadata | mp4::TrackType::Unknown => {} + _ => {} } } } @@ -849,7 +858,7 @@ fn public_mp4_bug_1185230() { fn public_mp4_ctts_overflow() { let input = &mut File::open("tests/clusterfuzz-testcase-minimized-mp4-6093954524250112") .expect("Unknown file"); - assert_invalid_data(mp4::read_mp4(input), "insufficient data in 'ctts' box"); + assert_eq!(Status::from(mp4::read_mp4(input)), Status::CttsBadSize); } #[test] @@ -911,22 +920,6 @@ fn public_avif_bug_1661347() { assert!(mp4::read_avif(input, ParseStrictness::Normal).is_err()); } -fn assert_invalid_data(result: mp4::Result, expected_msg: &str) { - match result { - Err(Error::InvalidData(msg)) if msg == expected_msg => {} - Err(Error::InvalidData(msg)) if msg != expected_msg => { - panic!( - "Error message mismatch\nExpected: {}\nFound: {}", - expected_msg, msg - ); - } - r => panic!( - "Expected Err(Error::InvalidData({:?}), found {:?}", - expected_msg, r - ), - } -} - fn for_strictness_result( path: &str, check: impl Fn(ParseStrictness, mp4::Result), @@ -944,18 +937,7 @@ fn for_strictness_result( } /// Check that input generates the expected error only in strict parsing mode -fn assert_avif_should(path: &str, expected_msg: &str) { - let input = &mut File::open(path).expect("Unknown file"); - assert_invalid_data(mp4::read_avif(input, ParseStrictness::Strict), expected_msg); - input.seek(SeekFrom::Start(0)).expect("rewind failed"); - mp4::read_avif(input, ParseStrictness::Normal).expect("ParseStrictness::Normal failed"); - input.seek(SeekFrom::Start(0)).expect("rewind failed"); - mp4::read_avif(input, ParseStrictness::Permissive).expect("ParseStrictness::Permissive failed"); -} - -/// Check that input generates the expected error only in strict parsing mode -// TODO: replace assert_avif_should -fn assert_avif_should2(path: &str, expected: Status) { +fn assert_avif_should(path: &str, expected: Status) { for_strictness_result(path, |strictness, result| { if strictness == ParseStrictness::Strict { assert_eq!(expected, Status::from(result)); @@ -966,17 +948,7 @@ fn assert_avif_should2(path: &str, expected: Status) { } /// Check that input generates the expected error unless in permissive parsing mode -fn assert_avif_shall(path: &str, expected_msg: &str) { - let input = &mut File::open(path).expect("Unknown file"); - assert_invalid_data(mp4::read_avif(input, ParseStrictness::Strict), expected_msg); - input.seek(SeekFrom::Start(0)).expect("rewind failed"); - assert_invalid_data(mp4::read_avif(input, ParseStrictness::Normal), expected_msg); - input.seek(SeekFrom::Start(0)).expect("rewind failed"); - mp4::read_avif(input, ParseStrictness::Permissive).expect("ParseStrictness::Permissive failed"); -} - -// TODO: replace assert_avif_shall -fn assert_avif_shall2(path: &str, expected: Status) { +fn assert_avif_shall(path: &str, expected: Status) { for_strictness_result(path, |strictness, result| { if strictness == ParseStrictness::Permissive { assert!(result.is_ok()); @@ -992,7 +964,7 @@ fn assert_avif_shall2(path: &str, expected: Status) { #[test] fn public_avif_av1c_missing_essential() { - assert_avif_should2(IMAGE_AVIF_AV1C_MISSING_ESSENTIAL, Status::TxformNoEssential); + assert_avif_should(IMAGE_AVIF_AV1C_MISSING_ESSENTIAL, Status::TxformNoEssential); } #[test] @@ -1008,36 +980,30 @@ fn public_avif_clap_missing_essential() { #[test] fn public_avif_imir_missing_essential() { - assert_avif_should2(IMAGE_AVIF_IMIR_MISSING_ESSENTIAL, Status::TxformNoEssential); + assert_avif_should(IMAGE_AVIF_IMIR_MISSING_ESSENTIAL, Status::TxformNoEssential); } #[test] fn public_avif_irot_missing_essential() { - assert_avif_should2(IMAGE_AVIF_IROT_MISSING_ESSENTIAL, Status::TxformNoEssential); + assert_avif_should(IMAGE_AVIF_IROT_MISSING_ESSENTIAL, Status::TxformNoEssential); } #[test] fn public_avif_ipma_bad_version() { - let expected_msg = "The ipma version 0 should be used unless 32-bit \ - item_ID values are needed \ - per ISOBMFF (ISO 14496-12:2020 § 8.11.14.1"; - assert_avif_should(IMAGE_AVIF_IPMA_BAD_VERSION, expected_msg); + assert_avif_should(IMAGE_AVIF_IPMA_BAD_VERSION, Status::IpmaBadVersion); } #[test] fn public_avif_ipma_bad_flags() { - let expected_msg = "Unless there are more than 127 properties in the \ - ItemPropertyContainerBox, flags should be equal to 0 \ - per ISOBMFF (ISO 14496-12:2020 § 8.11.14.1"; - assert_avif_should(IMAGE_AVIF_IPMA_BAD_FLAGS, expected_msg); + assert_avif_should(IMAGE_AVIF_IPMA_BAD_FLAGS, Status::IpmaFlagsNonzero); } #[test] fn public_avif_ipma_duplicate_version_and_flags() { - let expected_msg = "There shall be at most one ItemPropertyAssociationbox \ - with a given pair of values of version and flags \ - per ISOBMFF (ISO 14496-12:2020 § 8.11.14.1"; - assert_avif_shall(IMAGE_AVIF_IPMA_DUPLICATE_VERSION_AND_FLAGS, expected_msg); + assert_avif_shall( + IMAGE_AVIF_IPMA_DUPLICATE_VERSION_AND_FLAGS, + Status::IpmaBadQuantity, + ); } #[test] @@ -1046,101 +1012,90 @@ fn public_avif_ipma_duplicate_version_and_flags() { // which is kind of annoying to make pass the "should" requirements on flags and version // as well as the "shall" requirement on duplicate version and flags fn public_avif_ipma_duplicate_item_id() { - let expected_msg = "There shall be at most one occurrence of a given item_ID, \ - in the set of ItemPropertyAssociationBox boxes \ - per ISOBMFF (ISO 14496-12:2020) § 8.11.14.1"; let input = &mut File::open(IMAGE_AVIF_IPMA_DUPLICATE_ITEM_ID).expect("Unknown file"); - assert_invalid_data( - mp4::read_avif(input, ParseStrictness::Permissive), - expected_msg, + assert_eq!( + Status::from(mp4::read_avif(input, ParseStrictness::Permissive)), + Status::IpmaDuplicateItemId ) } #[test] fn public_avif_ipma_invalid_property_index() { - let expected_msg = "Invalid property index in ipma"; - assert_avif_shall(IMAGE_AVIF_IPMA_INVALID_PROPERTY_INDEX, expected_msg); + assert_avif_shall(IMAGE_AVIF_IPMA_INVALID_PROPERTY_INDEX, Status::IpmaBadIndex); } #[test] fn public_avif_hdlr_first_in_meta() { - let expected_msg = "The HandlerBox shall be the first contained box within \ - the MetaBox \ - per MIAF (ISO 23000-22:2019) § 7.2.1.5"; - assert_avif_shall(IMAGE_AVIF_NO_HDLR, expected_msg); - assert_avif_shall(IMAGE_AVIF_HDLR_NOT_FIRST, expected_msg); + assert_avif_shall(IMAGE_AVIF_NO_HDLR, Status::HdlrNotFirst); + assert_avif_shall(IMAGE_AVIF_HDLR_NOT_FIRST, Status::HdlrNotFirst); } #[test] fn public_avif_hdlr_is_pict() { - let expected_msg = "The HandlerBox handler_type must be 'pict' \ - per MIAF (ISO 23000-22:2019) § 7.2.1.5"; - assert_avif_shall(IMAGE_AVIF_HDLR_NOT_PICT, expected_msg); + assert_avif_shall(IMAGE_AVIF_HDLR_NOT_PICT, Status::HdlrTypeNotPict); } #[test] fn public_avif_hdlr_nonzero_reserved() { - let expected_msg = "The HandlerBox 'reserved' fields shall be 0 \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2"; // This is a "should" despite the spec indicating a (somewhat ambiguous) // requirement that this field is set to zero. // See comments in read_hdlr - assert_avif_should(IMAGE_AVIF_HDLR_NONZERO_RESERVED, expected_msg); + assert_avif_should( + IMAGE_AVIF_HDLR_NONZERO_RESERVED, + Status::HdlrReservedNonzero, + ); } #[test] fn public_avif_hdlr_multiple_nul() { - let expected_msg = "The HandlerBox 'name' field shall have a NUL byte \ - only in the final position \ - per ISOBMFF (ISO 14496-12:2020) § 8.4.3.2"; - // This is a "should" despite the spec indicating a (somewhat ambiguous) // requirement about extra data in boxes // See comments in read_hdlr - assert_avif_should(IMAGE_AVIF_HDLR_MULTIPLE_NUL, expected_msg); + assert_avif_should(IMAGE_AVIF_HDLR_MULTIPLE_NUL, Status::HdlrNameMultipleNul); } #[test] fn public_avif_no_mif1() { - let expected_msg = "The FileTypeBox should contain 'mif1' in the compatible_brands list \ - per MIAF (ISO 23000-22:2019) § 7.2.1.2"; - assert_avif_should(IMAGE_AVIF_NO_MIF1, expected_msg); + assert_avif_should(IMAGE_AVIF_NO_MIF1, Status::MissingMif1Brand); } #[test] fn public_avif_no_pitm() { - assert_avif_shall2(IMAGE_AVIF_NO_PITM, Status::NoPrimaryItem); + assert_avif_shall(IMAGE_AVIF_NO_PITM, Status::PitmMissing); } #[test] fn public_avif_pixi_present_for_displayable_images() { - let expected_msg = "The pixel information property shall be associated with every image \ - that is displayable (not hidden) \ - per MIAF (ISO/IEC 23000-22:2019) specification § 7.3.6.6"; let pixi_test = if cfg!(feature = "missing-pixi-permitted") { assert_avif_should } else { assert_avif_shall }; - pixi_test(IMAGE_AVIF_NO_PIXI, expected_msg); - pixi_test(IMAGE_AVIF_NO_ALPHA_PIXI, expected_msg); + pixi_test(IMAGE_AVIF_NO_PIXI, Status::PixiMissing); + pixi_test(IMAGE_AVIF_NO_ALPHA_PIXI, Status::PixiMissing); } #[test] fn public_avif_av1c_present_for_av01() { - let expected_msg = "One AV1 Item Configuration Property (av1C) \ - is mandatory for an image item of type 'av01' \ - per AVIF specification § 2.2.1"; - assert_avif_shall(IMAGE_AVIF_NO_AV1C, expected_msg); - assert_avif_shall(IMAGE_AVIF_NO_ALPHA_AV1C, expected_msg); + assert_avif_shall(IMAGE_AVIF_NO_AV1C, Status::Av1cMissing); + assert_avif_shall(IMAGE_AVIF_NO_ALPHA_AV1C, Status::Av1cMissing); } #[test] fn public_avif_ispe_present() { - let expected_msg = "Missing 'ispe' property for primary item, required \ - per HEIF (ISO/IEC 23008-12:2017) § 6.5.3.1"; - assert_avif_shall(IMAGE_AVIF_NO_ISPE, expected_msg); + assert_avif_shall(IMAGE_AVIF_NO_ISPE, Status::IspeMissing); + assert_avif_shall(IMAGE_AVIF_NO_ALPHA_ISPE, Status::IspeMissing); +} + +#[test] +fn public_avif_transform_before_ispe() { + assert_avif_shall(IMAGE_AVIF_TRANSFORM_BEFORE_ISPE, Status::TxformBeforeIspe); +} + +#[test] +fn public_avif_transform_order() { + assert_avif_shall(IMAGE_AVIF_TRANSFORM_ORDER, Status::TxformOrder); } fn assert_unsupported_nonfatal(result: &mp4::Result, feature: mp4::Feature) { @@ -1192,7 +1147,7 @@ fn public_avif_a1lx() { #[test] fn public_avif_a1lx_marked_essential() { - assert_avif_shall2(IMAGE_AVIF_A1LX_MARKED_ESSENTIAL, Status::A1lxEssential); + assert_avif_shall(IMAGE_AVIF_A1LX_MARKED_ESSENTIAL, Status::A1lxEssential); } #[test] @@ -1202,7 +1157,7 @@ fn public_avif_a1op() { #[test] fn public_avif_a1op_missing_essential() { - assert_avif_shall2(IMAGE_AVIF_A1OP_MISSING_ESSENTIAL, Status::A1opNoEssential); + assert_avif_shall(IMAGE_AVIF_A1OP_MISSING_ESSENTIAL, Status::A1opNoEssential); } #[test] @@ -1212,7 +1167,7 @@ fn public_avif_lsel() { #[test] fn public_avif_lsel_missing_essential() { - assert_avif_shall2(IMAGE_AVIF_LSEL_MISSING_ESSENTIAL, Status::LselNoEssential); + assert_avif_shall(IMAGE_AVIF_LSEL_MISSING_ESSENTIAL, Status::LselNoEssential); } #[test] @@ -1237,8 +1192,8 @@ fn public_avis_major_no_pitm() { match mp4::read_avif(input, ParseStrictness::Normal) { Ok(context) => { assert_eq!(context.major_brand, mp4::AVIS_BRAND); - assert!(context.unsupported_features.contains(mp4::Feature::Avis)); assert!(context.primary_item_coded_data().is_none()); + assert!(context.sequence.is_some()); } Err(e) => panic!("Expected Ok(_), found {:?}", e), } @@ -1250,9 +1205,9 @@ fn public_avis_major_with_pitm_and_alpha() { match mp4::read_avif(input, ParseStrictness::Normal) { Ok(context) => { assert_eq!(context.major_brand, mp4::AVIS_BRAND); - assert!(context.unsupported_features.contains(mp4::Feature::Avis)); assert!(context.primary_item_coded_data().is_some()); assert!(context.alpha_item_coded_data().is_some()); + assert!(context.sequence.is_some()); } Err(e) => panic!("Expected Ok(_), found {:?}", e), } @@ -1260,7 +1215,7 @@ fn public_avis_major_with_pitm_and_alpha() { #[test] fn public_avif_avis_major_no_moov() { - assert_avif_shall2(AVIF_AVIS_MAJOR_NO_MOOV, Status::NoMoov); + assert_avif_shall(AVIF_AVIS_MAJOR_NO_MOOV, Status::MoovMissing); } #[test] diff --git a/third_party/rust/mp4parse_capi/.cargo-checksum.json b/third_party/rust/mp4parse_capi/.cargo-checksum.json index e6f11e0f5863..a3484b4bb656 100644 --- a/third_party/rust/mp4parse_capi/.cargo-checksum.json +++ b/third_party/rust/mp4parse_capi/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"5074d01f075fd3c870f6e7f864e5a9b1ac7eb2af671110b58d9b1f3b830f72df","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"f776ed4bbb7b58a5684402a9c5c28dfe1fa02b6b184139b2c2c49384cc1e3723","cbindgen.toml":"62066cd34285ab9e7f1cc5db8950a51e9e080f5a85bd55ad43d7022e4eae2758","examples/dump.rs":"a22630f5f1434d4832f9113dcb18161c0248465e8844d470da3c76bb9910677a","src/lib.rs":"21d0b024037be9ced0f4647925bde55ca5e3fd4272a89847a4431235244b2e34","tests/test_chunk_out_of_range.rs":"73ffb5b60e826f6136d22142c030d17d0f72b85c675ccbf1300c84f9deb73131","tests/test_encryption.rs":"196ba22efc3e693c940bcc1e45d29bec9cf290b81cf77a68c1d254f6b38e6ae3","tests/test_fragment.rs":"a4b275d7159c50b265db583a1cc8255bd0a141e3a44432355713b895a7970d37","tests/test_rotation.rs":"a5aa6cc88a327ec90d6898b2c4f5ac397667ce349d829deae1af46c230be9cb6","tests/test_sample_table.rs":"d191fe5836c58d4bdffd7390da029bb5371f8afb5b1a8d636e15ae0dd6b5f4c8","tests/test_workaround_stsc.rs":"85cd2546224b5c4891a60d86e2d302a56e0c0798c2636ad241603a00ebfa46b5"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"31d4cece36ac4235873bc71953c450805290ddc7277e834d4d56fc7571dac4ed","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"f776ed4bbb7b58a5684402a9c5c28dfe1fa02b6b184139b2c2c49384cc1e3723","cbindgen.toml":"62066cd34285ab9e7f1cc5db8950a51e9e080f5a85bd55ad43d7022e4eae2758","examples/dump.rs":"7bc2898bc52b2f7feb5e0ddbe13bd93270dfc71b871067c35011902e5a8f4477","src/lib.rs":"0f4e5cf85a2c784d47bf13e4e720aca6efc86520e49835a0deea42025c5be120","tests/test_chunk_out_of_range.rs":"4039d0db0ee5973787e4ca14cea510fd958ae5d21856a79240a5e7b826caa18d","tests/test_encryption.rs":"f62131a36b0516caf9e2c48f8aea060d300b0f5c8a32bc54d31cbc97aa25b4e6","tests/test_fragment.rs":"b87fe0a967c5a3184f9264955b08209e64769e6358ff670665fc719380f22157","tests/test_rotation.rs":"23fa4898eca2e17255bc1ba2f538707a6554fb4644bb75f80548ae56a7cd2d44","tests/test_sample_table.rs":"6e2f5eaadede1e37a5ced722bc071506fd0eecf3cd17310479d3c9692632a2cd","tests/test_workaround_stsc.rs":"1d17a394f55e1524c30888bfe1e57e2b0457444b79c23eb91b02d2edf859c9ad"},"package":null} \ No newline at end of file diff --git a/third_party/rust/mp4parse_capi/Cargo.toml b/third_party/rust/mp4parse_capi/Cargo.toml index 57ae8fcfa12b..6b95a3ecb049 100644 --- a/third_party/rust/mp4parse_capi/Cargo.toml +++ b/third_party/rust/mp4parse_capi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mp4parse_capi" -version = "0.13.0" +version = "0.16.0" authors = [ "Ralph Giles ", "Matthew Gregan ", @@ -12,7 +12,7 @@ authors = [ description = "Parser for ISO base media file format (mp4)" documentation = "https://docs.rs/mp4parse_capi/" license = "MPL-2.0" - +edition = "2018" repository = "https://github.com/mozilla/mp4parse-rust" # Avoid complaints about trying to package test files. @@ -27,11 +27,11 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" } byteorder = "1.2.1" fallible_collections = { version = "0.4", features = ["std_io"] } log = "0.4" -mp4parse = { version = "0.13.0", path = "../mp4parse", features = ["unstable-api"] } +mp4parse = { version = "0.16.0", path = "../mp4parse", features = ["unstable-api"] } num-traits = "0.2.14" [dev-dependencies] -env_logger = "0.8" +env_logger = "0.9" [features] missing-pixi-permitted = ["mp4parse/missing-pixi-permitted"] diff --git a/third_party/rust/mp4parse_capi/examples/dump.rs b/third_party/rust/mp4parse_capi/examples/dump.rs index 1392b304f80b..f61693b9f9ec 100644 --- a/third_party/rust/mp4parse_capi/examples/dump.rs +++ b/third_party/rust/mp4parse_capi/examples/dump.rs @@ -1,11 +1,4 @@ -extern crate mp4parse; -extern crate mp4parse_capi; - -#[macro_use] -extern crate log; - -extern crate env_logger; - +use log::info; use mp4parse::ParseStrictness; use mp4parse_capi::*; use std::env; @@ -119,7 +112,9 @@ fn dump_file(filename: &str, strictness: ParseStrictness) { } } } - Mp4parseTrackType::Video => { + Mp4parseTrackType::Video + | Mp4parseTrackType::Picture + | Mp4parseTrackType::AuxiliaryVideo => { let mut video_info = Mp4parseTrackVideoInfo::default(); match mp4parse_get_track_video_info(parser, i, &mut video_info) { Mp4parseStatus::Ok => { diff --git a/third_party/rust/mp4parse_capi/src/lib.rs b/third_party/rust/mp4parse_capi/src/lib.rs index 627015e69f88..90a71e939d36 100644 --- a/third_party/rust/mp4parse_capi/src/lib.rs +++ b/third_party/rust/mp4parse_capi/src/lib.rs @@ -5,7 +5,6 @@ //! # Examples //! //! ```rust -//! extern crate mp4parse_capi; //! use std::io::Read; //! //! extern fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize { @@ -35,11 +34,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -extern crate byteorder; -extern crate log; -extern crate mp4parse; -extern crate num_traits; - use byteorder::WriteBytesExt; use std::convert::TryFrom; use std::convert::TryInto; @@ -51,6 +45,7 @@ use mp4parse::serialize_opus_header; use mp4parse::unstable::{ create_sample_table, media_time_to_us, track_time_to_us, CheckedInteger, Indice, Microseconds, }; +use mp4parse::AV1ConfigBox; use mp4parse::AudioCodecSpecific; use mp4parse::AvifContext; use mp4parse::CodecType; @@ -59,6 +54,7 @@ use mp4parse::MediaContext; pub use mp4parse::ParseStrictness; use mp4parse::SampleEntry; pub use mp4parse::Status as Mp4parseStatus; +use mp4parse::Track; use mp4parse::TrackType; use mp4parse::TryBox; use mp4parse::TryHashMap; @@ -76,11 +72,13 @@ struct HashMap; struct String; #[repr(C)] -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum Mp4parseTrackType { Video = 0, - Audio = 1, - Metadata = 2, + Picture = 1, + AuxiliaryVideo = 2, + Audio = 3, + Metadata = 4, } impl Default for Mp4parseTrackType { @@ -91,7 +89,7 @@ impl Default for Mp4parseTrackType { #[allow(non_camel_case_types, clippy::upper_case_acronyms)] #[repr(C)] -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum Mp4parseCodec { Unknown, Aac, @@ -120,7 +118,7 @@ impl Default for Mp4parseCodec { } #[repr(C)] -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum Mp4ParseEncryptionSchemeType { None, Cenc, @@ -202,7 +200,7 @@ pub struct Mp4parsePsshInfo { } #[repr(u8)] -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum OptionalFourCc { None, Some([u8; 4]), @@ -316,15 +314,10 @@ pub struct Mp4parseParser { #[repr(C)] #[derive(Debug)] -pub struct Mp4parseAvifImageItem { - pub coded_data: Mp4parseByteData, - pub bits_per_channel: Mp4parseByteData, -} - -#[repr(C)] -#[derive(Debug)] -pub struct Mp4parseAvifImage { - pub primary_image: Mp4parseAvifImageItem, +pub struct Mp4parseAvifInfo { + pub premultiplied_alpha: bool, + pub major_brand: [u8; 4], + pub unsupported_features_bitfield: u32, /// The size of the image; should never be null unless using permissive parsing pub spatial_extents: *const mp4parse::ImageSpatialExtentsProperty, pub nclx_colour_information: *const mp4parse::NclxColourInformation, @@ -332,12 +325,33 @@ pub struct Mp4parseAvifImage { pub image_rotation: mp4parse::ImageRotation, pub image_mirror: *const mp4parse::ImageMirror, pub pixel_aspect_ratio: *const mp4parse::PixelAspectRatio, - /// If no alpha item exists, members' `.length` will be 0 and `.data` will be null - pub alpha_image: Mp4parseAvifImageItem, - pub premultiplied_alpha: bool, - pub major_brand: [u8; 4], + + /// Whether there is a `pitm` reference to the color image present. + pub has_primary_item: bool, + /// Bit depth for the item referenced by `pitm`, or 0 if values are inconsistent. + pub primary_item_bit_depth: u8, + /// Whether there is an `auxl` reference to the `pitm`-accompanying + /// alpha image present. + pub has_alpha_item: bool, + /// Bit depth for the alpha item used by the `pitm`, or 0 if values are inconsistent. + pub alpha_item_bit_depth: u8, + + /// Whether there is a sequence. Can be true with no primary image. pub has_sequence: bool, - pub unsupported_features_bitfield: u32, + /// The color track's ID, which must be valid if has_sequence is true. + pub color_track_id: u32, + pub color_track_bit_depth: u8, + /// The track ID of the alpha track, will be 0 if no alpha track is present. + pub alpha_track_id: u32, + pub alpha_track_bit_depth: u8, +} + +#[repr(C)] +#[derive(Debug)] +pub struct Mp4parseAvifImage { + pub primary_image: Mp4parseByteData, + /// If no alpha item exists, members' `.length` will be 0 and `.data` will be null + pub alpha_image: Mp4parseByteData, } /// A unified interface for the parsers which have different contexts, but @@ -381,8 +395,10 @@ impl ContextParser for Mp4parseParser { } } +#[derive(Default)] pub struct Mp4parseAvifParser { context: AvifContext, + sample_table: TryHashMap>, } impl Mp4parseAvifParser { @@ -395,7 +411,10 @@ impl ContextParser for Mp4parseAvifParser { type Context = AvifContext; fn with_context(context: Self::Context) -> Self { - Self { context } + Self { + context, + ..Default::default() + } } fn read(io: &mut T, strictness: ParseStrictness) -> mp4parse::Result { @@ -601,6 +620,8 @@ pub unsafe extern "C" fn mp4parse_get_track_info( info.track_type = match context.tracks[track_index].track_type { TrackType::Video => Mp4parseTrackType::Video, + TrackType::Picture => Mp4parseTrackType::Picture, + TrackType::AuxiliaryVideo => Mp4parseTrackType::AuxiliaryVideo, TrackType::Audio => Mp4parseTrackType::Audio, TrackType::Metadata => Mp4parseTrackType::Metadata, TrackType::Unknown => return Mp4parseStatus::Unsupported, @@ -1024,6 +1045,158 @@ fn mp4parse_get_track_video_info_safe( Ok(()) } +/// Return a struct containing meta information read by previous +/// `mp4parse_avif_new()` call. +/// +/// `color_track_id`and `alpha_track_id` will be 0 if has_sequence is false. +/// `alpha_track_id` will be 0 if no alpha aux track is present. +/// +/// # Safety +/// +/// This function is unsafe because it dereferences both the parser and +/// avif_info raw pointers passed into it. Callers should ensure the parser +/// pointer points to a valid `Mp4parseAvifParser`, and that the avif_info +/// pointer points to a valid `Mp4parseAvifInfo`. +#[no_mangle] +pub unsafe extern "C" fn mp4parse_avif_get_info( + parser: *const Mp4parseAvifParser, + avif_info: *mut Mp4parseAvifInfo, +) -> Mp4parseStatus { + if parser.is_null() || avif_info.is_null() { + return Mp4parseStatus::BadArg; + } + + if let Ok(info) = mp4parse_avif_get_info_safe((*parser).context()) { + *avif_info = info; + Mp4parseStatus::Ok + } else { + Mp4parseStatus::Invalid + } +} + +fn mp4parse_avif_get_info_safe(context: &AvifContext) -> mp4parse::Result { + let info = Mp4parseAvifInfo { + premultiplied_alpha: context.premultiplied_alpha, + major_brand: context.major_brand.value, + unsupported_features_bitfield: context.unsupported_features.into_bitfield(), + spatial_extents: context.spatial_extents_ptr()?, + nclx_colour_information: context + .nclx_colour_information_ptr() + .unwrap_or(Ok(std::ptr::null()))?, + icc_colour_information: Mp4parseByteData::with_data( + context.icc_colour_information().unwrap_or(Ok(&[]))?, + ), + image_rotation: context.image_rotation()?, + image_mirror: context.image_mirror_ptr()?, + pixel_aspect_ratio: context.pixel_aspect_ratio_ptr()?, + + has_primary_item: context.primary_item_is_present(), + primary_item_bit_depth: 0, + has_alpha_item: context.alpha_item_is_present(), + alpha_item_bit_depth: 0, + + has_sequence: false, + color_track_id: 0, + color_track_bit_depth: 0, + alpha_track_id: 0, + alpha_track_bit_depth: 0, + }; + + fn get_bit_depth(data: &[u8]) -> u8 { + if !data.is_empty() && data.iter().all(|v| *v == data[0]) { + data[0] + } else { + 0 + } + } + let primary_item_bit_depth = + get_bit_depth(context.primary_item_bits_per_channel().unwrap_or(Ok(&[]))?); + let alpha_item_bit_depth = + get_bit_depth(context.primary_item_bits_per_channel().unwrap_or(Ok(&[]))?); + + if let Some(sequence) = &context.sequence { + // Tracks must have track_id and samples + fn get_track(tracks: &TryVec, pred: T) -> Option<&Track> + where + T: Fn(&Track) -> bool, + { + tracks.iter().find(|track| { + if track.track_id.is_none() { + return false; + } + match &track.stsc { + Some(stsc) => { + if stsc.samples.is_empty() { + return false; + } + if !pred(track) { + return false; + } + stsc.samples.iter().any(|chunk| chunk.samples_per_chunk > 0) + } + _ => false, + } + }) + } + + // Color track will be the first track found + let color_track = match get_track(&sequence.tracks, |_| true) { + Some(v) => v, + _ => return Ok(info), + }; + + // Alpha track will be the first track found with auxl.aux_for_track_id set to color_track's id + let alpha_track = get_track(&sequence.tracks, |track| match &track.tref { + Some(tref) => tref.has_auxl_reference(color_track.track_id.unwrap()), + _ => false, + }); + + fn get_av1c(track: &Track) -> Option<&AV1ConfigBox> { + if let Some(stsd) = &track.stsd { + for entry in &stsd.descriptions { + if let SampleEntry::Video(video_entry) = entry { + if let VideoCodecSpecific::AV1Config(av1c) = &video_entry.codec_specific { + return Some(av1c); + } + } + } + } + + None + } + + let color_track_id = color_track.track_id.unwrap(); + let color_track_bit_depth = match get_av1c(color_track) { + Some(av1c) => av1c.bit_depth, + _ => return Ok(info), + }; + + let (alpha_track_id, alpha_track_bit_depth) = match alpha_track { + Some(track) => ( + track.track_id.unwrap(), + match get_av1c(track) { + Some(av1c) => av1c.bit_depth, + _ => return Ok(info), + }, + ), + _ => (0, 0), + }; + + return Ok(Mp4parseAvifInfo { + primary_item_bit_depth, + alpha_item_bit_depth, + has_sequence: true, + color_track_id, + color_track_bit_depth, + alpha_track_id, + alpha_track_bit_depth, + ..info + }); + } + + Ok(info) +} + /// Return a pointer to the primary item parsed by previous `mp4parse_avif_new()` call. /// /// # Safety @@ -1057,39 +1230,11 @@ pub fn mp4parse_avif_get_image_safe( parser: &Mp4parseAvifParser, ) -> mp4parse::Result { let context = parser.context(); - - let primary_image = Mp4parseAvifImageItem { - coded_data: Mp4parseByteData::with_data(context.primary_item_coded_data().unwrap_or(&[])), - bits_per_channel: Mp4parseByteData::with_data( - context.primary_item_bits_per_channel().unwrap_or(Ok(&[]))?, - ), - }; - - // If there is no alpha present, all the `Mp4parseByteData`s will be zero length - let alpha_image = Mp4parseAvifImageItem { - coded_data: Mp4parseByteData::with_data(context.alpha_item_coded_data().unwrap_or(&[])), - bits_per_channel: Mp4parseByteData::with_data( - context.alpha_item_bits_per_channel().unwrap_or(Ok(&[]))?, - ), - }; - Ok(Mp4parseAvifImage { - primary_image, - spatial_extents: context.spatial_extents_ptr()?, - nclx_colour_information: context - .nclx_colour_information_ptr() - .unwrap_or(Ok(std::ptr::null()))?, - icc_colour_information: Mp4parseByteData::with_data( - context.icc_colour_information().unwrap_or(Ok(&[]))?, + primary_image: Mp4parseByteData::with_data( + context.primary_item_coded_data().unwrap_or(&[]), ), - image_rotation: context.image_rotation()?, - image_mirror: context.image_mirror_ptr()?, - pixel_aspect_ratio: context.pixel_aspect_ratio_ptr()?, - alpha_image, - premultiplied_alpha: context.premultiplied_alpha, - major_brand: context.major_brand.value, - has_sequence: context.has_sequence, - unsupported_features_bitfield: context.unsupported_features.into_bitfield(), + alpha_image: Mp4parseByteData::with_data(context.alpha_item_coded_data().unwrap_or(&[])), }) } @@ -1114,26 +1259,66 @@ pub unsafe extern "C" fn mp4parse_get_indice_table( // Initialize fields to default values to ensure all fields are always valid. *indices = Default::default(); - get_indice_table(&mut *parser, track_id, &mut *indices).into() + get_indice_table( + &(*parser).context, + &mut (*parser).sample_table, + track_id, + &mut *indices, + ) + .into() +} + +/// Fill the supplied `Mp4parseByteData` with index information from `track`. +/// +/// # Safety +/// +/// This function is unsafe because it dereferences both the parser and +/// indices raw pointers passed to it. Callers should ensure the parser +/// points to a valid `Mp4parseAvifParser` and indices points to a valid +/// `Mp4parseByteData`. +#[no_mangle] +pub unsafe extern "C" fn mp4parse_avif_get_indice_table( + parser: *mut Mp4parseAvifParser, + track_id: u32, + indices: *mut Mp4parseByteData, +) -> Mp4parseStatus { + if parser.is_null() { + return Mp4parseStatus::BadArg; + } + + if indices.is_null() { + return Mp4parseStatus::BadArg; + } + + // Initialize fields to default values to ensure all fields are always valid. + *indices = Default::default(); + + if let Some(sequence) = &(*parser).context.sequence { + return get_indice_table( + sequence, + &mut (*parser).sample_table, + track_id, + &mut *indices, + ) + .into(); + } + + Mp4parseStatus::BadArg } fn get_indice_table( - parser: &mut Mp4parseParser, + context: &MediaContext, + sample_table_cache: &mut TryHashMap>, track_id: u32, indices: &mut Mp4parseByteData, ) -> Result<(), Mp4parseStatus> { - let Mp4parseParser { - context, - sample_table: index_table, - .. - } = parser; let tracks = &context.tracks; let track = match tracks.iter().find(|track| track.track_id == Some(track_id)) { Some(t) => t, _ => return Err(Mp4parseStatus::Invalid), }; - if let Some(v) = index_table.get(&track_id) { + if let Some(v) = sample_table_cache.get(&track_id) { indices.set_indices(v); return Ok(()); } @@ -1165,7 +1350,7 @@ fn get_indice_table( if let Some(v) = create_sample_table(track, offset_time) { indices.set_indices(&v); - index_table.insert(track_id, v)?; + sample_table_cache.insert(track_id, v)?; return Ok(()); } diff --git a/third_party/rust/mp4parse_capi/tests/test_chunk_out_of_range.rs b/third_party/rust/mp4parse_capi/tests/test_chunk_out_of_range.rs index b3a9543b4092..26c2f506e17a 100644 --- a/third_party/rust/mp4parse_capi/tests/test_chunk_out_of_range.rs +++ b/third_party/rust/mp4parse_capi/tests/test_chunk_out_of_range.rs @@ -1,4 +1,3 @@ -extern crate mp4parse_capi; use mp4parse_capi::*; use std::io::Read; diff --git a/third_party/rust/mp4parse_capi/tests/test_encryption.rs b/third_party/rust/mp4parse_capi/tests/test_encryption.rs index 1a47e329fcd5..03f59630445d 100644 --- a/third_party/rust/mp4parse_capi/tests/test_encryption.rs +++ b/third_party/rust/mp4parse_capi/tests/test_encryption.rs @@ -1,4 +1,3 @@ -extern crate mp4parse_capi; use mp4parse_capi::*; use std::io::Read; diff --git a/third_party/rust/mp4parse_capi/tests/test_fragment.rs b/third_party/rust/mp4parse_capi/tests/test_fragment.rs index d6ebe1f177d5..e4a018bc2a8c 100644 --- a/third_party/rust/mp4parse_capi/tests/test_fragment.rs +++ b/third_party/rust/mp4parse_capi/tests/test_fragment.rs @@ -1,4 +1,3 @@ -extern crate mp4parse_capi; use mp4parse_capi::*; use std::io::Read; diff --git a/third_party/rust/mp4parse_capi/tests/test_rotation.rs b/third_party/rust/mp4parse_capi/tests/test_rotation.rs index 918c9fbeaea7..2ea47a5d52aa 100644 --- a/third_party/rust/mp4parse_capi/tests/test_rotation.rs +++ b/third_party/rust/mp4parse_capi/tests/test_rotation.rs @@ -1,4 +1,3 @@ -extern crate mp4parse_capi; use mp4parse_capi::*; use std::io::Read; diff --git a/third_party/rust/mp4parse_capi/tests/test_sample_table.rs b/third_party/rust/mp4parse_capi/tests/test_sample_table.rs index ad030a94c545..ab42a12a6ba1 100644 --- a/third_party/rust/mp4parse_capi/tests/test_sample_table.rs +++ b/third_party/rust/mp4parse_capi/tests/test_sample_table.rs @@ -1,5 +1,3 @@ -extern crate mp4parse; -extern crate mp4parse_capi; use mp4parse::unstable::Indice; use mp4parse_capi::*; use std::io::Read; diff --git a/third_party/rust/mp4parse_capi/tests/test_workaround_stsc.rs b/third_party/rust/mp4parse_capi/tests/test_workaround_stsc.rs index 99c92a7fef99..197024086f40 100644 --- a/third_party/rust/mp4parse_capi/tests/test_workaround_stsc.rs +++ b/third_party/rust/mp4parse_capi/tests/test_workaround_stsc.rs @@ -1,4 +1,3 @@ -extern crate mp4parse_capi; use mp4parse_capi::*; use std::io::Read; diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index b566df980f91..aaa28954f201 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -12,7 +12,7 @@ mozglue-static = { path = "../../../../mozglue/static/rust" } geckoservo = { path = "../../../../servo/ports/geckolib" } kvstore = { path = "../../../components/kvstore" } lmdb-rkv-sys = { version = "0.11", features = ["mdb_idl_logn_9"] } -mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "3bfc47d9a571d0842676043ba60716318e946c06", features = ["missing-pixi-permitted"] } +mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "eb0b625bd7e888d05ebcfc7685e2501b34c3b374", features = ["missing-pixi-permitted"] } nserror = { path = "../../../../xpcom/rust/nserror" } nsstring = { path = "../../../../xpcom/rust/nsstring" } netwerk_helper = { path = "../../../../netwerk/base/rust-helper" }