diff --git a/Cargo.lock b/Cargo.lock index 6b522db9..4055dc29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,6 +204,12 @@ dependencies = [ "syn", ] +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + [[package]] name = "async-broadcast" version = "0.7.2" @@ -341,6 +347,26 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atomig" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0f41f4bb89f5c6450325e283fb78c4a3d042181b54f3855ee2f872919f9863" +dependencies = [ + "atomig-macro", +] + +[[package]] +name = "atomig-macro" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49c98dba06b920588de7d63f6acc23f1e6a9fade5fd6198e564506334fb5a4f5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "audiopus_sys" version = "0.2.2" @@ -544,6 +570,12 @@ dependencies = [ "syn", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "byteorder-lite" version = "0.1.0" @@ -1846,7 +1878,7 @@ checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", - "zerocopy", + "zerocopy 0.8.52", ] [[package]] @@ -2591,6 +2623,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "706bf8a5e8c8ddb99128c3291d31bd21f4bcde17f0f4c20ec678d85c74faa149" dependencies = [ + "jobserver", "log", ] @@ -2990,9 +3023,12 @@ dependencies = [ "ash", "async-channel", "ffmpeg-next", + "libc", "libloading", "mdns-sd", + "openh264", "opus", + "pf-bitstream", "pf-dxvadec", "pf-ffvk", "pf-update-check", @@ -3002,6 +3038,7 @@ dependencies = [ "punktfunk-core", "pyrowave-sys", "rand 0.9.4", + "rav1d", "rustls", "sdl3", "serde", @@ -3435,7 +3472,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.52", ] [[package]] @@ -3594,7 +3631,7 @@ dependencies = [ "tokio", "tracing", "windows-sys 0.59.0", - "zerocopy", + "zerocopy 0.8.52", "zeroize", ] @@ -3889,6 +3926,36 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rav1d" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1932f060d5e7bd49dc9f8b272c1dc5e9ce0ffe141c28be900265d3989b36c9ed" +dependencies = [ + "assert_matches", + "atomig", + "bitflags 2.13.0", + "cc", + "cfg-if", + "libc", + "nasm-rs", + "parking_lot", + "paste", + "raw-cpuid", + "strum", + "to_method", + "zerocopy 0.7.35", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.13.0", +] + [[package]] name = "raw-window-handle" version = "0.6.2" @@ -4684,6 +4751,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "subtle" version = "2.6.1" @@ -4887,6 +4976,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "to_method" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" + [[package]] name = "tokio" version = "1.52.3" @@ -6345,13 +6440,34 @@ dependencies = [ "zvariant", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.35", +] + [[package]] name = "zerocopy" version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.8.52", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt index 288d1670..d5d9ff56 100644 --- a/THIRD-PARTY-NOTICES.txt +++ b/THIRD-PARTY-NOTICES.txt @@ -7,7 +7,7 @@ below. Each is distributed under its own permissive license; the full license te follow the manifest. This file is generated by scripts/gen-third-party-notices.py (or `cargo about`, see about.toml) — do not edit by hand. -Total third-party crates: 566 +Total third-party crates: 590 ---------------------------------------------------------------------------- VENDORED THIRD-PARTY SOURCE (inside first-party crates) @@ -43,6 +43,7 @@ MANIFEST (crate version — SPDX license — source) asn1-rs 0.6.2 — MIT OR Apache-2.0 — https://github.com/rusticata/asn1-rs.git asn1-rs-derive 0.5.1 — MIT OR Apache-2.0 — https://github.com/rusticata/asn1-rs.git asn1-rs-impl 0.2.0 — MIT/Apache-2.0 — https://github.com/rusticata/asn1-rs.git + assert_matches 1.5.0 — MIT/Apache-2.0 — https://github.com/murarth/assert_matches async-broadcast 0.7.2 — MIT OR Apache-2.0 — https://github.com/smol-rs/async-broadcast async-channel 2.5.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-channel async-executor 1.14.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-executor @@ -54,6 +55,8 @@ MANIFEST (crate version — SPDX license — source) async-task 4.7.1 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-task async-trait 0.1.89 — MIT OR Apache-2.0 — https://github.com/dtolnay/async-trait atomic-waker 1.1.2 — Apache-2.0 OR MIT — https://github.com/smol-rs/atomic-waker + atomig 0.4.3 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ + atomig-macro 0.4.0 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ audiopus_sys 0.2.2 — ISC — https://github.com/lakelezz/audiopus_sys.git autocfg 1.5.1 — Apache-2.0 OR MIT — https://github.com/cuviper/autocfg axum 0.8.9 — MIT — https://github.com/tokio-rs/axum @@ -64,6 +67,7 @@ MANIFEST (crate version — SPDX license — source) bindgen 0.72.1 — BSD-3-Clause — https://github.com/rust-lang/rust-bindgen bit-set 0.8.0 — Apache-2.0 OR MIT — https://github.com/contain-rs/bit-set bit-vec 0.8.0 — Apache-2.0 OR MIT — https://github.com/contain-rs/bit-vec + bitflags 1.3.2 — MIT/Apache-2.0 — https://github.com/bitflags/bitflags bitflags 2.13.0 — MIT OR Apache-2.0 — https://github.com/bitflags/bitflags block-buffer 0.10.4 — MIT OR Apache-2.0 — https://github.com/RustCrypto/utils block-padding 0.3.3 — MIT OR Apache-2.0 — https://github.com/RustCrypto/utils @@ -71,6 +75,7 @@ MANIFEST (crate version — SPDX license — source) bumpalo 3.20.3 — MIT OR Apache-2.0 — https://github.com/fitzgen/bumpalo bytemuck 1.25.0 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck bytemuck_derive 1.10.2 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck + byteorder 1.5.0 — Unlicense OR MIT — https://github.com/BurntSushi/byteorder byteorder-lite 0.1.0 — Unlicense OR MIT — https://github.com/image-rs/byteorder-lite bytes 1.12.0 — MIT — https://github.com/tokio-rs/bytes cairo-rs 0.22.0 — MIT — https://github.com/gtk-rs/gtk-rs-core @@ -115,6 +120,9 @@ MANIFEST (crate version — SPDX license — source) curve25519-dalek 4.1.3 — BSD-3-Clause — https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek curve25519-dalek-derive 0.1.1 — MIT/Apache-2.0 — https://github.com/dalek-cryptography/curve25519-dalek data-encoding 2.11.0 — MIT — https://github.com/ia0/data-encoding + defmt 1.1.1 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt + defmt-macros 1.1.1 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt + defmt-parser 1.0.0 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt der 0.7.10 — Apache-2.0 OR MIT — https://github.com/RustCrypto/formats/tree/master/der der-parser 9.0.0 — MIT/Apache-2.0 — https://github.com/rusticata/der-parser.git deranged 0.5.8 — MIT OR Apache-2.0 — https://github.com/jhpratt/deranged @@ -126,6 +134,8 @@ MANIFEST (crate version — SPDX license — source) enumflags2 0.7.12 — MIT OR Apache-2.0 — https://github.com/meithecatte/enumflags2 enumflags2_derive 0.7.12 — MIT OR Apache-2.0 — https://github.com/meithecatte/enumflags2 env_filter 0.1.4 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger + env_filter 2.0.0 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger + env_logger 0.11.11 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger equivalent 1.0.2 — Apache-2.0 OR MIT — https://github.com/indexmap-rs/equivalent errno 0.3.14 — MIT OR Apache-2.0 — https://github.com/lambda-fairy/rust-errno event-listener 5.4.1 — Apache-2.0 OR MIT — https://github.com/smol-rs/event-listener @@ -221,6 +231,9 @@ MANIFEST (crate version — SPDX license — source) itertools 0.10.5 — MIT/Apache-2.0 — https://github.com/rust-itertools/itertools itertools 0.13.0 — MIT OR Apache-2.0 — https://github.com/rust-itertools/itertools itoa 1.0.18 — MIT OR Apache-2.0 — https://github.com/dtolnay/itoa + jiff 0.2.35 — Unlicense OR MIT — https://github.com/BurntSushi/jiff + jiff-core 0.1.0 — Unlicense OR MIT — https://github.com/BurntSushi/jiff + jiff-static 0.2.35 — Unlicense OR MIT — https://github.com/BurntSushi/jiff jni 0.21.1 — MIT/Apache-2.0 — https://github.com/jni-rs/jni-rs jni-sys 0.3.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys jni-sys 0.4.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys @@ -304,6 +317,8 @@ MANIFEST (crate version — SPDX license — source) polling 3.11.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/polling poly1305 0.8.0 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes polyval 0.6.2 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes + portable-atomic 1.14.0 — Apache-2.0 OR MIT — https://github.com/taiki-e/portable-atomic + portable-atomic-util 0.2.7 — Apache-2.0 OR MIT — https://github.com/taiki-e/portable-atomic-util potential_utf 0.1.5 — Unicode-3.0 — https://github.com/unicode-org/icu4x powerfmt 0.2.0 — MIT OR Apache-2.0 — https://github.com/jhpratt/powerfmt ppv-lite86 0.2.21 — MIT OR Apache-2.0 — https://github.com/cryptocorrosion/cryptocorrosion @@ -327,6 +342,8 @@ MANIFEST (crate version — SPDX license — source) rand_core 0.6.4 — MIT OR Apache-2.0 — https://github.com/rust-random/rand rand_core 0.9.5 — MIT OR Apache-2.0 — https://github.com/rust-random/rand rand_xorshift 0.4.0 — MIT OR Apache-2.0 — https://github.com/rust-random/rngs + rav1d 1.1.0 — BSD-2-Clause — https://github.com/memorysafety/rav1d + raw-cpuid 11.6.0 — MIT — https://github.com/gz/rust-cpuid raw-window-handle 0.6.2 — MIT OR Apache-2.0 OR Zlib — https://github.com/rust-windowing/raw-window-handle rcgen 0.13.2 — MIT OR Apache-2.0 — https://github.com/rustls/rcgen readme-rustdocifier 0.1.1 — MIT — https://github.com/malaire/readme-rustdocifier @@ -404,6 +421,8 @@ MANIFEST (crate version — SPDX license — source) sqlite-wasm-rs 0.5.5 — MIT — https://github.com/Spxg/sqlite-wasm-rs stable_deref_trait 1.2.1 — MIT OR Apache-2.0 — https://github.com/storyyeller/stable_deref_trait strsim 0.11.1 — MIT — https://github.com/rapidfuzz/strsim-rs + strum 0.26.3 — MIT — https://github.com/Peternator7/strum + strum_macros 0.26.4 — MIT — https://github.com/Peternator7/strum subtle 2.6.1 — BSD-3-Clause — https://github.com/dalek-cryptography/subtle syn 2.0.118 — MIT OR Apache-2.0 — https://github.com/dtolnay/syn sync_wrapper 1.0.2 — Apache-2.0 — https://github.com/Actyx/sync_wrapper @@ -425,6 +444,7 @@ MANIFEST (crate version — SPDX license — source) tinytemplate 1.2.1 — Apache-2.0 OR MIT — https://github.com/bheisler/TinyTemplate tinyvec 1.11.0 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/tinyvec tinyvec_macros 0.1.1 — MIT OR Apache-2.0 OR Zlib — https://github.com/Soveu/tinyvec_macros + to_method 1.1.0 — CC0-1.0 — https://github.com/whentze/to_method tokio 1.52.3 — MIT — https://github.com/tokio-rs/tokio tokio-macros 2.7.0 — MIT — https://github.com/tokio-rs/tokio tokio-rustls 0.26.4 — MIT OR Apache-2.0 — https://github.com/rustls/tokio-rustls @@ -449,6 +469,7 @@ MANIFEST (crate version — SPDX license — source) tracing-log 0.2.0 — MIT — https://github.com/tokio-rs/tracing tracing-subscriber 0.3.23 — MIT — https://github.com/tokio-rs/tracing typenum 1.20.1 — MIT OR Apache-2.0 — https://github.com/paholg/typenum + uac-host 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso uds_windows 1.2.1 — MIT — https://github.com/haraldh/rust_uds_windows unarray 0.1.4 — MIT OR Apache-2.0 — https://github.com/cameron1024/unarray unicode-ident 1.0.24 — (MIT OR Apache-2.0) AND Unicode-3.0 — https://github.com/dtolnay/unicode-ident @@ -458,6 +479,7 @@ MANIFEST (crate version — SPDX license — source) untrusted 0.9.0 — ISC — https://github.com/briansmith/untrusted ureq 2.12.1 — MIT OR Apache-2.0 — https://github.com/algesten/ureq url 2.5.8 — MIT OR Apache-2.0 — https://github.com/servo/rust-url + usbfs-iso 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso utf8_iter 1.0.4 — Apache-2.0 OR MIT — https://github.com/hsivonen/utf8_iter utf8parse 0.2.2 — Apache-2.0 OR MIT — https://github.com/alacritty/vte utoipa 5.5.0 — MIT OR Apache-2.0 — https://github.com/juhaku/utoipa @@ -575,7 +597,9 @@ MANIFEST (crate version — SPDX license — source) zbus 5.16.0 — MIT — https://github.com/z-galaxy/zbus/ zbus_macros 5.16.0 — MIT — https://github.com/z-galaxy/zbus/ zbus_names 4.3.2 — MIT — https://github.com/z-galaxy/zbus/ + zerocopy 0.7.35 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerocopy 0.8.52 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy + zerocopy-derive 0.7.35 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerocopy-derive 0.8.52 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerofrom 0.1.8 — Unicode-3.0 — https://github.com/unicode-org/icu4x zerofrom-derive 0.1.7 — Unicode-3.0 — https://github.com/unicode-org/icu4x @@ -595,7 +619,9 @@ Crates whose package did not embed a license file (SPDX + source only) ---------------------------------------------------------------------------- anes 0.1.6 — MIT OR Apache-2.0 — https://github.com/zrzka/anes-rs asn1-rs-impl 0.2.0 — MIT/Apache-2.0 — https://github.com/rusticata/asn1-rs.git + atomig-macro 0.4.0 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ cookie-factory 0.3.3 — MIT — https://github.com/rust-bakery/cookie-factory + defmt-parser 1.0.0 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt ffmpeg-sys-next 8.1.0 — WTFPL — https://github.com/zmwangx/rust-ffmpeg-sys jni-sys-macros 0.4.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys ndk 0.9.0 — MIT OR Apache-2.0 — https://github.com/rust-mobile/ndk @@ -612,6 +638,8 @@ Crates whose package did not embed a license file (SPDX + source only) skia-bindings 0.87.0 — MIT — https://github.com/rust-skia/rust-skia skia-safe 0.87.0 — MIT — https://github.com/rust-skia/rust-skia test_reactor 0.0.0 — UNKNOWN + uac-host 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso + usbfs-iso 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso valuable 0.1.1 — MIT — https://github.com/tokio-rs/valuable winapi-i686-pc-windows-gnu 0.4.0 — MIT/Apache-2.0 — https://github.com/retep998/winapi-rs winapi-x86_64-pc-windows-gnu 0.4.0 — MIT/Apache-2.0 — https://github.com/retep998/winapi-rs @@ -845,7 +873,7 @@ limitations under the License. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: adler2 2.0.1, anyhow 1.0.103, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, async-trait 0.1.89, atomic-waker 1.1.2, blocking 1.6.2, concurrent-queue 2.5.0, curve25519-dalek-derive 0.1.1, displaydoc 0.2.6, endi 1.1.1, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, flume 0.12.0, fs-err 3.3.0, futures-lite 2.6.1, hermit-abi 0.5.2, is-terminal 0.4.17, itoa 1.0.18, khronos-egl 6.0.0, linux-raw-sys 0.12.1, minimal-lexical 0.2.1, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, ordered-stream 0.2.0, parking 2.2.1, paste 1.0.15, pastey 0.2.3, pin-project-lite 0.2.17, piper 0.2.5, polling 3.11.0, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.46, reis 0.6.1, relm4 0.11.0, relm4-css 0.11.0, relm4-macros 0.11.0, rsa 0.9.10, rustc-hash 2.1.2, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.150, serde_path_to_error 0.1.20, serde_repr 0.1.20, syn 2.0.118, system-deps 7.0.8, thiserror 1.0.69, thiserror 2.0.18, thiserror-impl 1.0.69, thiserror-impl 2.0.18, unicode-ident 1.0.24, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, zmij 1.0.21, zvariant_utils 3.4.0 +The following license (LICENSE-MIT) applies to: adler2 2.0.1, anyhow 1.0.103, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, async-trait 0.1.89, atomic-waker 1.1.2, blocking 1.6.2, concurrent-queue 2.5.0, curve25519-dalek-derive 0.1.1, displaydoc 0.2.6, endi 1.1.1, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, flume 0.12.0, fs-err 3.3.0, futures-lite 2.6.1, hermit-abi 0.5.2, is-terminal 0.4.17, itoa 1.0.18, khronos-egl 6.0.0, linux-raw-sys 0.12.1, minimal-lexical 0.2.1, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, ordered-stream 0.2.0, parking 2.2.1, paste 1.0.15, pastey 0.2.3, pin-project-lite 0.2.17, piper 0.2.5, polling 3.11.0, portable-atomic 1.14.0, portable-atomic-util 0.2.7, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.46, reis 0.6.1, relm4 0.11.0, relm4-css 0.11.0, relm4-macros 0.11.0, rsa 0.9.10, rustc-hash 2.1.2, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.150, serde_path_to_error 0.1.20, serde_repr 0.1.20, syn 2.0.118, system-deps 7.0.8, thiserror 1.0.69, thiserror 2.0.18, thiserror-impl 1.0.69, thiserror-impl 2.0.18, unicode-ident 1.0.24, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, zmij 1.0.21, zvariant_utils 3.4.0 ---------------------------------------------------------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -1170,7 +1198,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (COPYING) applies to: aho-corasick 1.1.4, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 +The following license (COPYING) applies to: aho-corasick 1.1.4, byteorder 1.5.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 ---------------------------------------------------------------------------- This project is dual-licensed under the Unlicense and MIT licenses. @@ -1178,7 +1206,7 @@ You may use this code under the terms of either license. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, memchr 2.8.2, walkdir 2.5.0 +The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, byteorder 1.5.0, byteorder-lite 0.1.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, memchr 2.8.2, walkdir 2.5.0 ---------------------------------------------------------------------------- The MIT License (MIT) @@ -1204,7 +1232,7 @@ THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (UNLICENSE) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 +The following license (UNLICENSE) applies to: aho-corasick 1.1.4, byteorder 1.5.0, byteorder-lite 0.1.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 ---------------------------------------------------------------------------- This is free and unencumbered software released into the public domain. @@ -1693,7 +1721,7 @@ SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, crc32fast 1.5.0, env_filter 0.1.4, fallible-iterator 0.3.0, fallible-streaming-iterator 0.1.9, hex 0.4.3, is_terminal_polyfill 1.70.2, jni-sys 0.3.1, jni-sys 0.4.1, once_cell_polyfill 1.70.2, quick-error 1.2.3, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0, winapi 0.3.9 +The following license (LICENSE-APACHE) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, crc32fast 1.5.0, env_filter 0.1.4, env_filter 2.0.0, env_logger 0.11.11, fallible-iterator 0.3.0, fallible-streaming-iterator 0.1.9, hex 0.4.3, is_terminal_polyfill 1.70.2, jni-sys 0.3.1, jni-sys 0.4.1, once_cell_polyfill 1.70.2, quick-error 1.2.3, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0, winapi 0.3.9 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -1899,7 +1927,7 @@ Apache License ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, env_filter 0.1.4, is_terminal_polyfill 1.70.2, once_cell_polyfill 1.70.2, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0 +The following license (LICENSE-MIT) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, env_filter 0.1.4, env_filter 2.0.0, env_logger 0.11.11, is_terminal_polyfill 1.70.2, once_cell_polyfill 1.70.2, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0 ---------------------------------------------------------------------------- Copyright (c) Individual contributors @@ -2232,7 +2260,7 @@ SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, png 0.18.1, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, weezl 0.1.12, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 +The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, assert_matches 1.5.0, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 1.3.2, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, png 0.18.1, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, weezl 0.1.12, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -2467,6 +2495,36 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: assert_matches 1.5.0 +---------------------------------------------------------------------------- +Copyright (c) 2016 Murarth + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-APACHE) applies to: async-broadcast 0.7.2 ---------------------------------------------------------------------------- @@ -2738,6 +2796,242 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-APACHE) applies to: atomig 0.4.3, bit-set 0.8.0, bit-vec 0.8.0, cfg-expr 0.20.8, defmt 1.1.1, defmt-macros 1.1.1, downcast-rs 1.2.1, hashlink 0.12.0, minimal-lexical 0.2.1 +---------------------------------------------------------------------------- +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. + + +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: atomig 0.4.3 +---------------------------------------------------------------------------- +Copyright (c) 2016 Project Developers + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE.md) applies to: audiopus_sys 0.2.2 ---------------------------------------------------------------------------- @@ -2984,212 +3278,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: bit-set 0.8.0, bit-vec 0.8.0, cfg-expr 0.20.8, downcast-rs 1.2.1, hashlink 0.12.0, minimal-lexical 0.2.1 ----------------------------------------------------------------------------- -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. - - ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: bit-set 0.8.0, bit-vec 0.8.0 ---------------------------------------------------------------------------- @@ -3221,7 +3309,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: bitflags 2.13.0, glob 0.3.3, log 0.4.33, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11 +The following license (LICENSE-MIT) applies to: bitflags 1.3.2, bitflags 2.13.0, glob 0.3.3, log 0.4.33, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11 ---------------------------------------------------------------------------- Copyright (c) 2014 The Rust Project Developers @@ -5153,6 +5241,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: defmt 1.1.1, defmt-macros 1.1.1 +---------------------------------------------------------------------------- +Copyright (c) Ferrous Systems + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: der 0.7.10, pkcs8 0.10.2 ---------------------------------------------------------------------------- @@ -5848,7 +5966,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: fdeflate 0.3.7, field-offset 0.3.6, half 2.7.1, image 0.25.10, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 +The following license (LICENSE-APACHE) applies to: fdeflate 0.3.7, field-offset 0.3.6, half 2.7.1, image 0.25.10, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, portable-atomic 1.14.0, portable-atomic-util 0.2.7, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -11397,6 +11515,61 @@ APPENDIX: How to apply the Apache License to your work. identification within third-party archives. +---------------------------------------------------------------------------- +The following license (COPYING) applies to: rav1d 1.1.0 +---------------------------------------------------------------------------- +Copyright © 2018-2019, VideoLAN and dav1d authors +Copyright © 2023-2024, VideoLAN, dav1d authors, and Internet Security Research Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------------------------------------------------------------------- +The following license (LICENSE.md) applies to: raw-cpuid 11.6.0 +---------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015 Gerd Zellweger + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT.md) applies to: raw-window-handle 0.6.2 ---------------------------------------------------------------------------- @@ -13264,6 +13437,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: strum 0.26.3, strum_macros 0.26.4 +---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2019 Peter Glotfelty + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: subtle 2.6.1 ---------------------------------------------------------------------------- @@ -13690,6 +13889,132 @@ freely, subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: to_method 1.1.0 +---------------------------------------------------------------------------- +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: tokio 1.52.3, tokio-util 0.7.18 ---------------------------------------------------------------------------- @@ -16105,7 +16430,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-APACHE) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -16311,7 +16636,7 @@ Apache License ---------------------------------------------------------------------------- -The following license (LICENSE-BSD) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-BSD) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Copyright 2019 The Fuchsia Authors. @@ -16340,7 +16665,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-MIT) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Copyright 2023 The Fuchsia Authors diff --git a/clients/android/app/src/main/assets/THIRD-PARTY-NOTICES.txt b/clients/android/app/src/main/assets/THIRD-PARTY-NOTICES.txt index 288d1670..d5d9ff56 100644 --- a/clients/android/app/src/main/assets/THIRD-PARTY-NOTICES.txt +++ b/clients/android/app/src/main/assets/THIRD-PARTY-NOTICES.txt @@ -7,7 +7,7 @@ below. Each is distributed under its own permissive license; the full license te follow the manifest. This file is generated by scripts/gen-third-party-notices.py (or `cargo about`, see about.toml) — do not edit by hand. -Total third-party crates: 566 +Total third-party crates: 590 ---------------------------------------------------------------------------- VENDORED THIRD-PARTY SOURCE (inside first-party crates) @@ -43,6 +43,7 @@ MANIFEST (crate version — SPDX license — source) asn1-rs 0.6.2 — MIT OR Apache-2.0 — https://github.com/rusticata/asn1-rs.git asn1-rs-derive 0.5.1 — MIT OR Apache-2.0 — https://github.com/rusticata/asn1-rs.git asn1-rs-impl 0.2.0 — MIT/Apache-2.0 — https://github.com/rusticata/asn1-rs.git + assert_matches 1.5.0 — MIT/Apache-2.0 — https://github.com/murarth/assert_matches async-broadcast 0.7.2 — MIT OR Apache-2.0 — https://github.com/smol-rs/async-broadcast async-channel 2.5.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-channel async-executor 1.14.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-executor @@ -54,6 +55,8 @@ MANIFEST (crate version — SPDX license — source) async-task 4.7.1 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-task async-trait 0.1.89 — MIT OR Apache-2.0 — https://github.com/dtolnay/async-trait atomic-waker 1.1.2 — Apache-2.0 OR MIT — https://github.com/smol-rs/atomic-waker + atomig 0.4.3 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ + atomig-macro 0.4.0 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ audiopus_sys 0.2.2 — ISC — https://github.com/lakelezz/audiopus_sys.git autocfg 1.5.1 — Apache-2.0 OR MIT — https://github.com/cuviper/autocfg axum 0.8.9 — MIT — https://github.com/tokio-rs/axum @@ -64,6 +67,7 @@ MANIFEST (crate version — SPDX license — source) bindgen 0.72.1 — BSD-3-Clause — https://github.com/rust-lang/rust-bindgen bit-set 0.8.0 — Apache-2.0 OR MIT — https://github.com/contain-rs/bit-set bit-vec 0.8.0 — Apache-2.0 OR MIT — https://github.com/contain-rs/bit-vec + bitflags 1.3.2 — MIT/Apache-2.0 — https://github.com/bitflags/bitflags bitflags 2.13.0 — MIT OR Apache-2.0 — https://github.com/bitflags/bitflags block-buffer 0.10.4 — MIT OR Apache-2.0 — https://github.com/RustCrypto/utils block-padding 0.3.3 — MIT OR Apache-2.0 — https://github.com/RustCrypto/utils @@ -71,6 +75,7 @@ MANIFEST (crate version — SPDX license — source) bumpalo 3.20.3 — MIT OR Apache-2.0 — https://github.com/fitzgen/bumpalo bytemuck 1.25.0 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck bytemuck_derive 1.10.2 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck + byteorder 1.5.0 — Unlicense OR MIT — https://github.com/BurntSushi/byteorder byteorder-lite 0.1.0 — Unlicense OR MIT — https://github.com/image-rs/byteorder-lite bytes 1.12.0 — MIT — https://github.com/tokio-rs/bytes cairo-rs 0.22.0 — MIT — https://github.com/gtk-rs/gtk-rs-core @@ -115,6 +120,9 @@ MANIFEST (crate version — SPDX license — source) curve25519-dalek 4.1.3 — BSD-3-Clause — https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek curve25519-dalek-derive 0.1.1 — MIT/Apache-2.0 — https://github.com/dalek-cryptography/curve25519-dalek data-encoding 2.11.0 — MIT — https://github.com/ia0/data-encoding + defmt 1.1.1 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt + defmt-macros 1.1.1 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt + defmt-parser 1.0.0 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt der 0.7.10 — Apache-2.0 OR MIT — https://github.com/RustCrypto/formats/tree/master/der der-parser 9.0.0 — MIT/Apache-2.0 — https://github.com/rusticata/der-parser.git deranged 0.5.8 — MIT OR Apache-2.0 — https://github.com/jhpratt/deranged @@ -126,6 +134,8 @@ MANIFEST (crate version — SPDX license — source) enumflags2 0.7.12 — MIT OR Apache-2.0 — https://github.com/meithecatte/enumflags2 enumflags2_derive 0.7.12 — MIT OR Apache-2.0 — https://github.com/meithecatte/enumflags2 env_filter 0.1.4 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger + env_filter 2.0.0 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger + env_logger 0.11.11 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger equivalent 1.0.2 — Apache-2.0 OR MIT — https://github.com/indexmap-rs/equivalent errno 0.3.14 — MIT OR Apache-2.0 — https://github.com/lambda-fairy/rust-errno event-listener 5.4.1 — Apache-2.0 OR MIT — https://github.com/smol-rs/event-listener @@ -221,6 +231,9 @@ MANIFEST (crate version — SPDX license — source) itertools 0.10.5 — MIT/Apache-2.0 — https://github.com/rust-itertools/itertools itertools 0.13.0 — MIT OR Apache-2.0 — https://github.com/rust-itertools/itertools itoa 1.0.18 — MIT OR Apache-2.0 — https://github.com/dtolnay/itoa + jiff 0.2.35 — Unlicense OR MIT — https://github.com/BurntSushi/jiff + jiff-core 0.1.0 — Unlicense OR MIT — https://github.com/BurntSushi/jiff + jiff-static 0.2.35 — Unlicense OR MIT — https://github.com/BurntSushi/jiff jni 0.21.1 — MIT/Apache-2.0 — https://github.com/jni-rs/jni-rs jni-sys 0.3.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys jni-sys 0.4.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys @@ -304,6 +317,8 @@ MANIFEST (crate version — SPDX license — source) polling 3.11.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/polling poly1305 0.8.0 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes polyval 0.6.2 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes + portable-atomic 1.14.0 — Apache-2.0 OR MIT — https://github.com/taiki-e/portable-atomic + portable-atomic-util 0.2.7 — Apache-2.0 OR MIT — https://github.com/taiki-e/portable-atomic-util potential_utf 0.1.5 — Unicode-3.0 — https://github.com/unicode-org/icu4x powerfmt 0.2.0 — MIT OR Apache-2.0 — https://github.com/jhpratt/powerfmt ppv-lite86 0.2.21 — MIT OR Apache-2.0 — https://github.com/cryptocorrosion/cryptocorrosion @@ -327,6 +342,8 @@ MANIFEST (crate version — SPDX license — source) rand_core 0.6.4 — MIT OR Apache-2.0 — https://github.com/rust-random/rand rand_core 0.9.5 — MIT OR Apache-2.0 — https://github.com/rust-random/rand rand_xorshift 0.4.0 — MIT OR Apache-2.0 — https://github.com/rust-random/rngs + rav1d 1.1.0 — BSD-2-Clause — https://github.com/memorysafety/rav1d + raw-cpuid 11.6.0 — MIT — https://github.com/gz/rust-cpuid raw-window-handle 0.6.2 — MIT OR Apache-2.0 OR Zlib — https://github.com/rust-windowing/raw-window-handle rcgen 0.13.2 — MIT OR Apache-2.0 — https://github.com/rustls/rcgen readme-rustdocifier 0.1.1 — MIT — https://github.com/malaire/readme-rustdocifier @@ -404,6 +421,8 @@ MANIFEST (crate version — SPDX license — source) sqlite-wasm-rs 0.5.5 — MIT — https://github.com/Spxg/sqlite-wasm-rs stable_deref_trait 1.2.1 — MIT OR Apache-2.0 — https://github.com/storyyeller/stable_deref_trait strsim 0.11.1 — MIT — https://github.com/rapidfuzz/strsim-rs + strum 0.26.3 — MIT — https://github.com/Peternator7/strum + strum_macros 0.26.4 — MIT — https://github.com/Peternator7/strum subtle 2.6.1 — BSD-3-Clause — https://github.com/dalek-cryptography/subtle syn 2.0.118 — MIT OR Apache-2.0 — https://github.com/dtolnay/syn sync_wrapper 1.0.2 — Apache-2.0 — https://github.com/Actyx/sync_wrapper @@ -425,6 +444,7 @@ MANIFEST (crate version — SPDX license — source) tinytemplate 1.2.1 — Apache-2.0 OR MIT — https://github.com/bheisler/TinyTemplate tinyvec 1.11.0 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/tinyvec tinyvec_macros 0.1.1 — MIT OR Apache-2.0 OR Zlib — https://github.com/Soveu/tinyvec_macros + to_method 1.1.0 — CC0-1.0 — https://github.com/whentze/to_method tokio 1.52.3 — MIT — https://github.com/tokio-rs/tokio tokio-macros 2.7.0 — MIT — https://github.com/tokio-rs/tokio tokio-rustls 0.26.4 — MIT OR Apache-2.0 — https://github.com/rustls/tokio-rustls @@ -449,6 +469,7 @@ MANIFEST (crate version — SPDX license — source) tracing-log 0.2.0 — MIT — https://github.com/tokio-rs/tracing tracing-subscriber 0.3.23 — MIT — https://github.com/tokio-rs/tracing typenum 1.20.1 — MIT OR Apache-2.0 — https://github.com/paholg/typenum + uac-host 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso uds_windows 1.2.1 — MIT — https://github.com/haraldh/rust_uds_windows unarray 0.1.4 — MIT OR Apache-2.0 — https://github.com/cameron1024/unarray unicode-ident 1.0.24 — (MIT OR Apache-2.0) AND Unicode-3.0 — https://github.com/dtolnay/unicode-ident @@ -458,6 +479,7 @@ MANIFEST (crate version — SPDX license — source) untrusted 0.9.0 — ISC — https://github.com/briansmith/untrusted ureq 2.12.1 — MIT OR Apache-2.0 — https://github.com/algesten/ureq url 2.5.8 — MIT OR Apache-2.0 — https://github.com/servo/rust-url + usbfs-iso 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso utf8_iter 1.0.4 — Apache-2.0 OR MIT — https://github.com/hsivonen/utf8_iter utf8parse 0.2.2 — Apache-2.0 OR MIT — https://github.com/alacritty/vte utoipa 5.5.0 — MIT OR Apache-2.0 — https://github.com/juhaku/utoipa @@ -575,7 +597,9 @@ MANIFEST (crate version — SPDX license — source) zbus 5.16.0 — MIT — https://github.com/z-galaxy/zbus/ zbus_macros 5.16.0 — MIT — https://github.com/z-galaxy/zbus/ zbus_names 4.3.2 — MIT — https://github.com/z-galaxy/zbus/ + zerocopy 0.7.35 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerocopy 0.8.52 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy + zerocopy-derive 0.7.35 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerocopy-derive 0.8.52 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerofrom 0.1.8 — Unicode-3.0 — https://github.com/unicode-org/icu4x zerofrom-derive 0.1.7 — Unicode-3.0 — https://github.com/unicode-org/icu4x @@ -595,7 +619,9 @@ Crates whose package did not embed a license file (SPDX + source only) ---------------------------------------------------------------------------- anes 0.1.6 — MIT OR Apache-2.0 — https://github.com/zrzka/anes-rs asn1-rs-impl 0.2.0 — MIT/Apache-2.0 — https://github.com/rusticata/asn1-rs.git + atomig-macro 0.4.0 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ cookie-factory 0.3.3 — MIT — https://github.com/rust-bakery/cookie-factory + defmt-parser 1.0.0 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt ffmpeg-sys-next 8.1.0 — WTFPL — https://github.com/zmwangx/rust-ffmpeg-sys jni-sys-macros 0.4.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys ndk 0.9.0 — MIT OR Apache-2.0 — https://github.com/rust-mobile/ndk @@ -612,6 +638,8 @@ Crates whose package did not embed a license file (SPDX + source only) skia-bindings 0.87.0 — MIT — https://github.com/rust-skia/rust-skia skia-safe 0.87.0 — MIT — https://github.com/rust-skia/rust-skia test_reactor 0.0.0 — UNKNOWN + uac-host 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso + usbfs-iso 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso valuable 0.1.1 — MIT — https://github.com/tokio-rs/valuable winapi-i686-pc-windows-gnu 0.4.0 — MIT/Apache-2.0 — https://github.com/retep998/winapi-rs winapi-x86_64-pc-windows-gnu 0.4.0 — MIT/Apache-2.0 — https://github.com/retep998/winapi-rs @@ -845,7 +873,7 @@ limitations under the License. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: adler2 2.0.1, anyhow 1.0.103, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, async-trait 0.1.89, atomic-waker 1.1.2, blocking 1.6.2, concurrent-queue 2.5.0, curve25519-dalek-derive 0.1.1, displaydoc 0.2.6, endi 1.1.1, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, flume 0.12.0, fs-err 3.3.0, futures-lite 2.6.1, hermit-abi 0.5.2, is-terminal 0.4.17, itoa 1.0.18, khronos-egl 6.0.0, linux-raw-sys 0.12.1, minimal-lexical 0.2.1, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, ordered-stream 0.2.0, parking 2.2.1, paste 1.0.15, pastey 0.2.3, pin-project-lite 0.2.17, piper 0.2.5, polling 3.11.0, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.46, reis 0.6.1, relm4 0.11.0, relm4-css 0.11.0, relm4-macros 0.11.0, rsa 0.9.10, rustc-hash 2.1.2, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.150, serde_path_to_error 0.1.20, serde_repr 0.1.20, syn 2.0.118, system-deps 7.0.8, thiserror 1.0.69, thiserror 2.0.18, thiserror-impl 1.0.69, thiserror-impl 2.0.18, unicode-ident 1.0.24, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, zmij 1.0.21, zvariant_utils 3.4.0 +The following license (LICENSE-MIT) applies to: adler2 2.0.1, anyhow 1.0.103, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, async-trait 0.1.89, atomic-waker 1.1.2, blocking 1.6.2, concurrent-queue 2.5.0, curve25519-dalek-derive 0.1.1, displaydoc 0.2.6, endi 1.1.1, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, flume 0.12.0, fs-err 3.3.0, futures-lite 2.6.1, hermit-abi 0.5.2, is-terminal 0.4.17, itoa 1.0.18, khronos-egl 6.0.0, linux-raw-sys 0.12.1, minimal-lexical 0.2.1, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, ordered-stream 0.2.0, parking 2.2.1, paste 1.0.15, pastey 0.2.3, pin-project-lite 0.2.17, piper 0.2.5, polling 3.11.0, portable-atomic 1.14.0, portable-atomic-util 0.2.7, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.46, reis 0.6.1, relm4 0.11.0, relm4-css 0.11.0, relm4-macros 0.11.0, rsa 0.9.10, rustc-hash 2.1.2, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.150, serde_path_to_error 0.1.20, serde_repr 0.1.20, syn 2.0.118, system-deps 7.0.8, thiserror 1.0.69, thiserror 2.0.18, thiserror-impl 1.0.69, thiserror-impl 2.0.18, unicode-ident 1.0.24, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, zmij 1.0.21, zvariant_utils 3.4.0 ---------------------------------------------------------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -1170,7 +1198,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (COPYING) applies to: aho-corasick 1.1.4, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 +The following license (COPYING) applies to: aho-corasick 1.1.4, byteorder 1.5.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 ---------------------------------------------------------------------------- This project is dual-licensed under the Unlicense and MIT licenses. @@ -1178,7 +1206,7 @@ You may use this code under the terms of either license. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, memchr 2.8.2, walkdir 2.5.0 +The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, byteorder 1.5.0, byteorder-lite 0.1.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, memchr 2.8.2, walkdir 2.5.0 ---------------------------------------------------------------------------- The MIT License (MIT) @@ -1204,7 +1232,7 @@ THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (UNLICENSE) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 +The following license (UNLICENSE) applies to: aho-corasick 1.1.4, byteorder 1.5.0, byteorder-lite 0.1.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 ---------------------------------------------------------------------------- This is free and unencumbered software released into the public domain. @@ -1693,7 +1721,7 @@ SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, crc32fast 1.5.0, env_filter 0.1.4, fallible-iterator 0.3.0, fallible-streaming-iterator 0.1.9, hex 0.4.3, is_terminal_polyfill 1.70.2, jni-sys 0.3.1, jni-sys 0.4.1, once_cell_polyfill 1.70.2, quick-error 1.2.3, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0, winapi 0.3.9 +The following license (LICENSE-APACHE) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, crc32fast 1.5.0, env_filter 0.1.4, env_filter 2.0.0, env_logger 0.11.11, fallible-iterator 0.3.0, fallible-streaming-iterator 0.1.9, hex 0.4.3, is_terminal_polyfill 1.70.2, jni-sys 0.3.1, jni-sys 0.4.1, once_cell_polyfill 1.70.2, quick-error 1.2.3, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0, winapi 0.3.9 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -1899,7 +1927,7 @@ Apache License ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, env_filter 0.1.4, is_terminal_polyfill 1.70.2, once_cell_polyfill 1.70.2, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0 +The following license (LICENSE-MIT) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, env_filter 0.1.4, env_filter 2.0.0, env_logger 0.11.11, is_terminal_polyfill 1.70.2, once_cell_polyfill 1.70.2, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0 ---------------------------------------------------------------------------- Copyright (c) Individual contributors @@ -2232,7 +2260,7 @@ SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, png 0.18.1, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, weezl 0.1.12, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 +The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, assert_matches 1.5.0, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 1.3.2, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, png 0.18.1, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, weezl 0.1.12, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -2467,6 +2495,36 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: assert_matches 1.5.0 +---------------------------------------------------------------------------- +Copyright (c) 2016 Murarth + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-APACHE) applies to: async-broadcast 0.7.2 ---------------------------------------------------------------------------- @@ -2738,6 +2796,242 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-APACHE) applies to: atomig 0.4.3, bit-set 0.8.0, bit-vec 0.8.0, cfg-expr 0.20.8, defmt 1.1.1, defmt-macros 1.1.1, downcast-rs 1.2.1, hashlink 0.12.0, minimal-lexical 0.2.1 +---------------------------------------------------------------------------- +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. + + +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: atomig 0.4.3 +---------------------------------------------------------------------------- +Copyright (c) 2016 Project Developers + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE.md) applies to: audiopus_sys 0.2.2 ---------------------------------------------------------------------------- @@ -2984,212 +3278,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: bit-set 0.8.0, bit-vec 0.8.0, cfg-expr 0.20.8, downcast-rs 1.2.1, hashlink 0.12.0, minimal-lexical 0.2.1 ----------------------------------------------------------------------------- -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. - - ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: bit-set 0.8.0, bit-vec 0.8.0 ---------------------------------------------------------------------------- @@ -3221,7 +3309,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: bitflags 2.13.0, glob 0.3.3, log 0.4.33, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11 +The following license (LICENSE-MIT) applies to: bitflags 1.3.2, bitflags 2.13.0, glob 0.3.3, log 0.4.33, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11 ---------------------------------------------------------------------------- Copyright (c) 2014 The Rust Project Developers @@ -5153,6 +5241,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: defmt 1.1.1, defmt-macros 1.1.1 +---------------------------------------------------------------------------- +Copyright (c) Ferrous Systems + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: der 0.7.10, pkcs8 0.10.2 ---------------------------------------------------------------------------- @@ -5848,7 +5966,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: fdeflate 0.3.7, field-offset 0.3.6, half 2.7.1, image 0.25.10, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 +The following license (LICENSE-APACHE) applies to: fdeflate 0.3.7, field-offset 0.3.6, half 2.7.1, image 0.25.10, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, portable-atomic 1.14.0, portable-atomic-util 0.2.7, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -11397,6 +11515,61 @@ APPENDIX: How to apply the Apache License to your work. identification within third-party archives. +---------------------------------------------------------------------------- +The following license (COPYING) applies to: rav1d 1.1.0 +---------------------------------------------------------------------------- +Copyright © 2018-2019, VideoLAN and dav1d authors +Copyright © 2023-2024, VideoLAN, dav1d authors, and Internet Security Research Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------------------------------------------------------------------- +The following license (LICENSE.md) applies to: raw-cpuid 11.6.0 +---------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015 Gerd Zellweger + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT.md) applies to: raw-window-handle 0.6.2 ---------------------------------------------------------------------------- @@ -13264,6 +13437,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: strum 0.26.3, strum_macros 0.26.4 +---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2019 Peter Glotfelty + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: subtle 2.6.1 ---------------------------------------------------------------------------- @@ -13690,6 +13889,132 @@ freely, subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: to_method 1.1.0 +---------------------------------------------------------------------------- +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: tokio 1.52.3, tokio-util 0.7.18 ---------------------------------------------------------------------------- @@ -16105,7 +16430,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-APACHE) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -16311,7 +16636,7 @@ Apache License ---------------------------------------------------------------------------- -The following license (LICENSE-BSD) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-BSD) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Copyright 2019 The Fuchsia Authors. @@ -16340,7 +16665,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-MIT) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Copyright 2023 The Fuchsia Authors diff --git a/clients/apple/Sources/PunktfunkKit/Resources/THIRD-PARTY-NOTICES.txt b/clients/apple/Sources/PunktfunkKit/Resources/THIRD-PARTY-NOTICES.txt index 288d1670..d5d9ff56 100644 --- a/clients/apple/Sources/PunktfunkKit/Resources/THIRD-PARTY-NOTICES.txt +++ b/clients/apple/Sources/PunktfunkKit/Resources/THIRD-PARTY-NOTICES.txt @@ -7,7 +7,7 @@ below. Each is distributed under its own permissive license; the full license te follow the manifest. This file is generated by scripts/gen-third-party-notices.py (or `cargo about`, see about.toml) — do not edit by hand. -Total third-party crates: 566 +Total third-party crates: 590 ---------------------------------------------------------------------------- VENDORED THIRD-PARTY SOURCE (inside first-party crates) @@ -43,6 +43,7 @@ MANIFEST (crate version — SPDX license — source) asn1-rs 0.6.2 — MIT OR Apache-2.0 — https://github.com/rusticata/asn1-rs.git asn1-rs-derive 0.5.1 — MIT OR Apache-2.0 — https://github.com/rusticata/asn1-rs.git asn1-rs-impl 0.2.0 — MIT/Apache-2.0 — https://github.com/rusticata/asn1-rs.git + assert_matches 1.5.0 — MIT/Apache-2.0 — https://github.com/murarth/assert_matches async-broadcast 0.7.2 — MIT OR Apache-2.0 — https://github.com/smol-rs/async-broadcast async-channel 2.5.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-channel async-executor 1.14.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-executor @@ -54,6 +55,8 @@ MANIFEST (crate version — SPDX license — source) async-task 4.7.1 — Apache-2.0 OR MIT — https://github.com/smol-rs/async-task async-trait 0.1.89 — MIT OR Apache-2.0 — https://github.com/dtolnay/async-trait atomic-waker 1.1.2 — Apache-2.0 OR MIT — https://github.com/smol-rs/atomic-waker + atomig 0.4.3 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ + atomig-macro 0.4.0 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ audiopus_sys 0.2.2 — ISC — https://github.com/lakelezz/audiopus_sys.git autocfg 1.5.1 — Apache-2.0 OR MIT — https://github.com/cuviper/autocfg axum 0.8.9 — MIT — https://github.com/tokio-rs/axum @@ -64,6 +67,7 @@ MANIFEST (crate version — SPDX license — source) bindgen 0.72.1 — BSD-3-Clause — https://github.com/rust-lang/rust-bindgen bit-set 0.8.0 — Apache-2.0 OR MIT — https://github.com/contain-rs/bit-set bit-vec 0.8.0 — Apache-2.0 OR MIT — https://github.com/contain-rs/bit-vec + bitflags 1.3.2 — MIT/Apache-2.0 — https://github.com/bitflags/bitflags bitflags 2.13.0 — MIT OR Apache-2.0 — https://github.com/bitflags/bitflags block-buffer 0.10.4 — MIT OR Apache-2.0 — https://github.com/RustCrypto/utils block-padding 0.3.3 — MIT OR Apache-2.0 — https://github.com/RustCrypto/utils @@ -71,6 +75,7 @@ MANIFEST (crate version — SPDX license — source) bumpalo 3.20.3 — MIT OR Apache-2.0 — https://github.com/fitzgen/bumpalo bytemuck 1.25.0 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck bytemuck_derive 1.10.2 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck + byteorder 1.5.0 — Unlicense OR MIT — https://github.com/BurntSushi/byteorder byteorder-lite 0.1.0 — Unlicense OR MIT — https://github.com/image-rs/byteorder-lite bytes 1.12.0 — MIT — https://github.com/tokio-rs/bytes cairo-rs 0.22.0 — MIT — https://github.com/gtk-rs/gtk-rs-core @@ -115,6 +120,9 @@ MANIFEST (crate version — SPDX license — source) curve25519-dalek 4.1.3 — BSD-3-Clause — https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek curve25519-dalek-derive 0.1.1 — MIT/Apache-2.0 — https://github.com/dalek-cryptography/curve25519-dalek data-encoding 2.11.0 — MIT — https://github.com/ia0/data-encoding + defmt 1.1.1 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt + defmt-macros 1.1.1 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt + defmt-parser 1.0.0 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt der 0.7.10 — Apache-2.0 OR MIT — https://github.com/RustCrypto/formats/tree/master/der der-parser 9.0.0 — MIT/Apache-2.0 — https://github.com/rusticata/der-parser.git deranged 0.5.8 — MIT OR Apache-2.0 — https://github.com/jhpratt/deranged @@ -126,6 +134,8 @@ MANIFEST (crate version — SPDX license — source) enumflags2 0.7.12 — MIT OR Apache-2.0 — https://github.com/meithecatte/enumflags2 enumflags2_derive 0.7.12 — MIT OR Apache-2.0 — https://github.com/meithecatte/enumflags2 env_filter 0.1.4 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger + env_filter 2.0.0 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger + env_logger 0.11.11 — MIT OR Apache-2.0 — https://github.com/rust-cli/env_logger equivalent 1.0.2 — Apache-2.0 OR MIT — https://github.com/indexmap-rs/equivalent errno 0.3.14 — MIT OR Apache-2.0 — https://github.com/lambda-fairy/rust-errno event-listener 5.4.1 — Apache-2.0 OR MIT — https://github.com/smol-rs/event-listener @@ -221,6 +231,9 @@ MANIFEST (crate version — SPDX license — source) itertools 0.10.5 — MIT/Apache-2.0 — https://github.com/rust-itertools/itertools itertools 0.13.0 — MIT OR Apache-2.0 — https://github.com/rust-itertools/itertools itoa 1.0.18 — MIT OR Apache-2.0 — https://github.com/dtolnay/itoa + jiff 0.2.35 — Unlicense OR MIT — https://github.com/BurntSushi/jiff + jiff-core 0.1.0 — Unlicense OR MIT — https://github.com/BurntSushi/jiff + jiff-static 0.2.35 — Unlicense OR MIT — https://github.com/BurntSushi/jiff jni 0.21.1 — MIT/Apache-2.0 — https://github.com/jni-rs/jni-rs jni-sys 0.3.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys jni-sys 0.4.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys @@ -304,6 +317,8 @@ MANIFEST (crate version — SPDX license — source) polling 3.11.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/polling poly1305 0.8.0 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes polyval 0.6.2 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes + portable-atomic 1.14.0 — Apache-2.0 OR MIT — https://github.com/taiki-e/portable-atomic + portable-atomic-util 0.2.7 — Apache-2.0 OR MIT — https://github.com/taiki-e/portable-atomic-util potential_utf 0.1.5 — Unicode-3.0 — https://github.com/unicode-org/icu4x powerfmt 0.2.0 — MIT OR Apache-2.0 — https://github.com/jhpratt/powerfmt ppv-lite86 0.2.21 — MIT OR Apache-2.0 — https://github.com/cryptocorrosion/cryptocorrosion @@ -327,6 +342,8 @@ MANIFEST (crate version — SPDX license — source) rand_core 0.6.4 — MIT OR Apache-2.0 — https://github.com/rust-random/rand rand_core 0.9.5 — MIT OR Apache-2.0 — https://github.com/rust-random/rand rand_xorshift 0.4.0 — MIT OR Apache-2.0 — https://github.com/rust-random/rngs + rav1d 1.1.0 — BSD-2-Clause — https://github.com/memorysafety/rav1d + raw-cpuid 11.6.0 — MIT — https://github.com/gz/rust-cpuid raw-window-handle 0.6.2 — MIT OR Apache-2.0 OR Zlib — https://github.com/rust-windowing/raw-window-handle rcgen 0.13.2 — MIT OR Apache-2.0 — https://github.com/rustls/rcgen readme-rustdocifier 0.1.1 — MIT — https://github.com/malaire/readme-rustdocifier @@ -404,6 +421,8 @@ MANIFEST (crate version — SPDX license — source) sqlite-wasm-rs 0.5.5 — MIT — https://github.com/Spxg/sqlite-wasm-rs stable_deref_trait 1.2.1 — MIT OR Apache-2.0 — https://github.com/storyyeller/stable_deref_trait strsim 0.11.1 — MIT — https://github.com/rapidfuzz/strsim-rs + strum 0.26.3 — MIT — https://github.com/Peternator7/strum + strum_macros 0.26.4 — MIT — https://github.com/Peternator7/strum subtle 2.6.1 — BSD-3-Clause — https://github.com/dalek-cryptography/subtle syn 2.0.118 — MIT OR Apache-2.0 — https://github.com/dtolnay/syn sync_wrapper 1.0.2 — Apache-2.0 — https://github.com/Actyx/sync_wrapper @@ -425,6 +444,7 @@ MANIFEST (crate version — SPDX license — source) tinytemplate 1.2.1 — Apache-2.0 OR MIT — https://github.com/bheisler/TinyTemplate tinyvec 1.11.0 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/tinyvec tinyvec_macros 0.1.1 — MIT OR Apache-2.0 OR Zlib — https://github.com/Soveu/tinyvec_macros + to_method 1.1.0 — CC0-1.0 — https://github.com/whentze/to_method tokio 1.52.3 — MIT — https://github.com/tokio-rs/tokio tokio-macros 2.7.0 — MIT — https://github.com/tokio-rs/tokio tokio-rustls 0.26.4 — MIT OR Apache-2.0 — https://github.com/rustls/tokio-rustls @@ -449,6 +469,7 @@ MANIFEST (crate version — SPDX license — source) tracing-log 0.2.0 — MIT — https://github.com/tokio-rs/tracing tracing-subscriber 0.3.23 — MIT — https://github.com/tokio-rs/tracing typenum 1.20.1 — MIT OR Apache-2.0 — https://github.com/paholg/typenum + uac-host 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso uds_windows 1.2.1 — MIT — https://github.com/haraldh/rust_uds_windows unarray 0.1.4 — MIT OR Apache-2.0 — https://github.com/cameron1024/unarray unicode-ident 1.0.24 — (MIT OR Apache-2.0) AND Unicode-3.0 — https://github.com/dtolnay/unicode-ident @@ -458,6 +479,7 @@ MANIFEST (crate version — SPDX license — source) untrusted 0.9.0 — ISC — https://github.com/briansmith/untrusted ureq 2.12.1 — MIT OR Apache-2.0 — https://github.com/algesten/ureq url 2.5.8 — MIT OR Apache-2.0 — https://github.com/servo/rust-url + usbfs-iso 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso utf8_iter 1.0.4 — Apache-2.0 OR MIT — https://github.com/hsivonen/utf8_iter utf8parse 0.2.2 — Apache-2.0 OR MIT — https://github.com/alacritty/vte utoipa 5.5.0 — MIT OR Apache-2.0 — https://github.com/juhaku/utoipa @@ -575,7 +597,9 @@ MANIFEST (crate version — SPDX license — source) zbus 5.16.0 — MIT — https://github.com/z-galaxy/zbus/ zbus_macros 5.16.0 — MIT — https://github.com/z-galaxy/zbus/ zbus_names 4.3.2 — MIT — https://github.com/z-galaxy/zbus/ + zerocopy 0.7.35 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerocopy 0.8.52 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy + zerocopy-derive 0.7.35 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerocopy-derive 0.8.52 — BSD-2-Clause OR Apache-2.0 OR MIT — https://github.com/google/zerocopy zerofrom 0.1.8 — Unicode-3.0 — https://github.com/unicode-org/icu4x zerofrom-derive 0.1.7 — Unicode-3.0 — https://github.com/unicode-org/icu4x @@ -595,7 +619,9 @@ Crates whose package did not embed a license file (SPDX + source only) ---------------------------------------------------------------------------- anes 0.1.6 — MIT OR Apache-2.0 — https://github.com/zrzka/anes-rs asn1-rs-impl 0.2.0 — MIT/Apache-2.0 — https://github.com/rusticata/asn1-rs.git + atomig-macro 0.4.0 — MIT/Apache-2.0 — https://github.com/LukasKalbertodt/atomig/ cookie-factory 0.3.3 — MIT — https://github.com/rust-bakery/cookie-factory + defmt-parser 1.0.0 — MIT OR Apache-2.0 — https://github.com/knurling-rs/defmt ffmpeg-sys-next 8.1.0 — WTFPL — https://github.com/zmwangx/rust-ffmpeg-sys jni-sys-macros 0.4.1 — MIT OR Apache-2.0 — https://github.com/jni-rs/jni-sys ndk 0.9.0 — MIT OR Apache-2.0 — https://github.com/rust-mobile/ndk @@ -612,6 +638,8 @@ Crates whose package did not embed a license file (SPDX + source only) skia-bindings 0.87.0 — MIT — https://github.com/rust-skia/rust-skia skia-safe 0.87.0 — MIT — https://github.com/rust-skia/rust-skia test_reactor 0.0.0 — UNKNOWN + uac-host 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso + usbfs-iso 0.1.0 — MIT OR Apache-2.0 — https://github.com/unom-io/usbfs-iso valuable 0.1.1 — MIT — https://github.com/tokio-rs/valuable winapi-i686-pc-windows-gnu 0.4.0 — MIT/Apache-2.0 — https://github.com/retep998/winapi-rs winapi-x86_64-pc-windows-gnu 0.4.0 — MIT/Apache-2.0 — https://github.com/retep998/winapi-rs @@ -845,7 +873,7 @@ limitations under the License. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: adler2 2.0.1, anyhow 1.0.103, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, async-trait 0.1.89, atomic-waker 1.1.2, blocking 1.6.2, concurrent-queue 2.5.0, curve25519-dalek-derive 0.1.1, displaydoc 0.2.6, endi 1.1.1, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, flume 0.12.0, fs-err 3.3.0, futures-lite 2.6.1, hermit-abi 0.5.2, is-terminal 0.4.17, itoa 1.0.18, khronos-egl 6.0.0, linux-raw-sys 0.12.1, minimal-lexical 0.2.1, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, ordered-stream 0.2.0, parking 2.2.1, paste 1.0.15, pastey 0.2.3, pin-project-lite 0.2.17, piper 0.2.5, polling 3.11.0, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.46, reis 0.6.1, relm4 0.11.0, relm4-css 0.11.0, relm4-macros 0.11.0, rsa 0.9.10, rustc-hash 2.1.2, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.150, serde_path_to_error 0.1.20, serde_repr 0.1.20, syn 2.0.118, system-deps 7.0.8, thiserror 1.0.69, thiserror 2.0.18, thiserror-impl 1.0.69, thiserror-impl 2.0.18, unicode-ident 1.0.24, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, zmij 1.0.21, zvariant_utils 3.4.0 +The following license (LICENSE-MIT) applies to: adler2 2.0.1, anyhow 1.0.103, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, async-trait 0.1.89, atomic-waker 1.1.2, blocking 1.6.2, concurrent-queue 2.5.0, curve25519-dalek-derive 0.1.1, displaydoc 0.2.6, endi 1.1.1, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, flume 0.12.0, fs-err 3.3.0, futures-lite 2.6.1, hermit-abi 0.5.2, is-terminal 0.4.17, itoa 1.0.18, khronos-egl 6.0.0, linux-raw-sys 0.12.1, minimal-lexical 0.2.1, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, ordered-stream 0.2.0, parking 2.2.1, paste 1.0.15, pastey 0.2.3, pin-project-lite 0.2.17, piper 0.2.5, polling 3.11.0, portable-atomic 1.14.0, portable-atomic-util 0.2.7, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.46, reis 0.6.1, relm4 0.11.0, relm4-css 0.11.0, relm4-macros 0.11.0, rsa 0.9.10, rustc-hash 2.1.2, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.150, serde_path_to_error 0.1.20, serde_repr 0.1.20, syn 2.0.118, system-deps 7.0.8, thiserror 1.0.69, thiserror 2.0.18, thiserror-impl 1.0.69, thiserror-impl 2.0.18, unicode-ident 1.0.24, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, zmij 1.0.21, zvariant_utils 3.4.0 ---------------------------------------------------------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -1170,7 +1198,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (COPYING) applies to: aho-corasick 1.1.4, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 +The following license (COPYING) applies to: aho-corasick 1.1.4, byteorder 1.5.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 ---------------------------------------------------------------------------- This project is dual-licensed under the Unlicense and MIT licenses. @@ -1178,7 +1206,7 @@ You may use this code under the terms of either license. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, memchr 2.8.2, walkdir 2.5.0 +The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, byteorder 1.5.0, byteorder-lite 0.1.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, memchr 2.8.2, walkdir 2.5.0 ---------------------------------------------------------------------------- The MIT License (MIT) @@ -1204,7 +1232,7 @@ THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (UNLICENSE) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 +The following license (UNLICENSE) applies to: aho-corasick 1.1.4, byteorder 1.5.0, byteorder-lite 0.1.0, jiff 0.2.35, jiff-core 0.1.0, jiff-static 0.2.35, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 ---------------------------------------------------------------------------- This is free and unencumbered software released into the public domain. @@ -1693,7 +1721,7 @@ SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, crc32fast 1.5.0, env_filter 0.1.4, fallible-iterator 0.3.0, fallible-streaming-iterator 0.1.9, hex 0.4.3, is_terminal_polyfill 1.70.2, jni-sys 0.3.1, jni-sys 0.4.1, once_cell_polyfill 1.70.2, quick-error 1.2.3, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0, winapi 0.3.9 +The following license (LICENSE-APACHE) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, crc32fast 1.5.0, env_filter 0.1.4, env_filter 2.0.0, env_logger 0.11.11, fallible-iterator 0.3.0, fallible-streaming-iterator 0.1.9, hex 0.4.3, is_terminal_polyfill 1.70.2, jni-sys 0.3.1, jni-sys 0.4.1, once_cell_polyfill 1.70.2, quick-error 1.2.3, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0, winapi 0.3.9 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -1899,7 +1927,7 @@ Apache License ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, env_filter 0.1.4, is_terminal_polyfill 1.70.2, once_cell_polyfill 1.70.2, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0 +The following license (LICENSE-MIT) applies to: annotate-snippets 0.11.5, anstream 1.0.0, anstyle 1.0.14, anstyle-parse 1.0.0, anstyle-query 1.1.5, anstyle-wincon 3.0.11, clap 4.6.1, clap_builder 4.6.0, clap_lex 1.1.0, colorchoice 1.0.5, env_filter 0.1.4, env_filter 2.0.0, env_logger 0.11.11, is_terminal_polyfill 1.70.2, once_cell_polyfill 1.70.2, serde_spanned 0.6.9, serde_spanned 1.1.1, toml 0.8.23, toml 0.9.12+spec-1.1.0, toml 1.1.2+spec-1.1.0, toml_datetime 0.6.11, toml_datetime 0.7.5+spec-1.1.0, toml_datetime 1.1.1+spec-1.1.0, toml_edit 0.22.27, toml_edit 0.25.12+spec-1.1.0, toml_parser 1.1.2+spec-1.1.0, toml_write 0.1.2, toml_writer 1.1.1+spec-1.1.0 ---------------------------------------------------------------------------- Copyright (c) Individual contributors @@ -2232,7 +2260,7 @@ SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, png 0.18.1, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, weezl 0.1.12, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 +The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, assert_matches 1.5.0, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 1.3.2, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, png 0.18.1, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, weezl 0.1.12, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -2467,6 +2495,36 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: assert_matches 1.5.0 +---------------------------------------------------------------------------- +Copyright (c) 2016 Murarth + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-APACHE) applies to: async-broadcast 0.7.2 ---------------------------------------------------------------------------- @@ -2738,6 +2796,242 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-APACHE) applies to: atomig 0.4.3, bit-set 0.8.0, bit-vec 0.8.0, cfg-expr 0.20.8, defmt 1.1.1, defmt-macros 1.1.1, downcast-rs 1.2.1, hashlink 0.12.0, minimal-lexical 0.2.1 +---------------------------------------------------------------------------- +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. + + +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: atomig 0.4.3 +---------------------------------------------------------------------------- +Copyright (c) 2016 Project Developers + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE.md) applies to: audiopus_sys 0.2.2 ---------------------------------------------------------------------------- @@ -2984,212 +3278,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: bit-set 0.8.0, bit-vec 0.8.0, cfg-expr 0.20.8, downcast-rs 1.2.1, hashlink 0.12.0, minimal-lexical 0.2.1 ----------------------------------------------------------------------------- -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. - - ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: bit-set 0.8.0, bit-vec 0.8.0 ---------------------------------------------------------------------------- @@ -3221,7 +3309,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: bitflags 2.13.0, glob 0.3.3, log 0.4.33, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11 +The following license (LICENSE-MIT) applies to: bitflags 1.3.2, bitflags 2.13.0, glob 0.3.3, log 0.4.33, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11 ---------------------------------------------------------------------------- Copyright (c) 2014 The Rust Project Developers @@ -5153,6 +5241,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: defmt 1.1.1, defmt-macros 1.1.1 +---------------------------------------------------------------------------- +Copyright (c) Ferrous Systems + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: der 0.7.10, pkcs8 0.10.2 ---------------------------------------------------------------------------- @@ -5848,7 +5966,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: fdeflate 0.3.7, field-offset 0.3.6, half 2.7.1, image 0.25.10, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 +The following license (LICENSE-APACHE) applies to: fdeflate 0.3.7, field-offset 0.3.6, half 2.7.1, image 0.25.10, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, portable-atomic 1.14.0, portable-atomic-util 0.2.7, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -11397,6 +11515,61 @@ APPENDIX: How to apply the Apache License to your work. identification within third-party archives. +---------------------------------------------------------------------------- +The following license (COPYING) applies to: rav1d 1.1.0 +---------------------------------------------------------------------------- +Copyright © 2018-2019, VideoLAN and dav1d authors +Copyright © 2023-2024, VideoLAN, dav1d authors, and Internet Security Research Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------------------------------------------------------------------- +The following license (LICENSE.md) applies to: raw-cpuid 11.6.0 +---------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015 Gerd Zellweger + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT.md) applies to: raw-window-handle 0.6.2 ---------------------------------------------------------------------------- @@ -13264,6 +13437,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: strum 0.26.3, strum_macros 0.26.4 +---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2019 Peter Glotfelty + +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. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: subtle 2.6.1 ---------------------------------------------------------------------------- @@ -13690,6 +13889,132 @@ freely, subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: to_method 1.1.0 +---------------------------------------------------------------------------- +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: tokio 1.52.3, tokio-util 0.7.18 ---------------------------------------------------------------------------- @@ -16105,7 +16430,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-APACHE) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -16311,7 +16636,7 @@ Apache License ---------------------------------------------------------------------------- -The following license (LICENSE-BSD) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-BSD) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Copyright 2019 The Fuchsia Authors. @@ -16340,7 +16665,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: zerocopy 0.8.52, zerocopy-derive 0.8.52 +The following license (LICENSE-MIT) applies to: zerocopy 0.7.35, zerocopy 0.8.52, zerocopy-derive 0.7.35, zerocopy-derive 0.8.52 ---------------------------------------------------------------------------- Copyright 2023 The Fuchsia Authors diff --git a/clients/session/src/main.rs b/clients/session/src/main.rs index 5abfa882..1670a278 100644 --- a/clients/session/src/main.rs +++ b/clients/session/src/main.rs @@ -346,6 +346,10 @@ mod session_main { bitrate_kbps: settings.bitrate_kbps, audio_channels: settings.audio_channels, preferred_codec: settings.preferred_codec(), + // Nothing excluded on a fresh dial. Only the run loop's codec-fallback retry + // sets this, and it does so on a CLONE of these params — a Settings-level + // "never use HEVC" would be `preferred_codec`, not this. + exclude_codecs: 0, // HDR off = don't advertise 10-bit/HDR at all; the host then never upgrades. // MULTI_SLICE is decoder truth for THIS embedder: every desktop decode stack // (FFmpeg software, VAAPI, D3D11VA, Vulkan Video) handles AUs carrying several @@ -357,12 +361,14 @@ mod session_main { // HEVC, and a real GPU 4:4:4 encode probe, and answers the resolved chroma in the // Welcome BEFORE we build a decoder. Advertised whenever the user asks because // every path can DISPLAY it: the Vulkan presenter samples the 2-plane 4:4:4 pool - // formats (hardware RExt decode where the driver offers it — NVIDIA today) and - // swscale converts anything else for the software rung, with the decoder ladder - // demoting on its own. No capability probe gates the bit — software decode is the - // guaranteed floor — but the cost is VISIBLE, not silent: the Detailed stats - // overlay prints the resolved chroma ("4:4:4→4:2:0" when the host declined) and - // the decode path frames actually took. + // formats (hardware RExt decode where the driver offers it — NVIDIA today), + // with the decoder ladder demoting on its own. No capability probe gates the + // bit — but note (M8) that the software rung below it is 4:2:0 8-bit ONLY and + // refuses anything else rather than mis-scaling it, so on a box whose hardware + // 4:4:4 decode fails the floor is a codec fallback, not a converted picture. + // The cost stays VISIBLE, not silent: the Detailed stats overlay prints the + // resolved chroma ("4:4:4→4:2:0" when the host declined) and the decode path + // frames actually took. video_caps: punktfunk_core::quic::VIDEO_CAP_MULTI_SLICE | if settings.hdr_enabled { punktfunk_core::quic::VIDEO_CAP_10BIT | punktfunk_core::quic::VIDEO_CAP_HDR diff --git a/crates/pf-client-core/Cargo.toml b/crates/pf-client-core/Cargo.toml index 4c42bc45..76b011ac 100644 --- a/crates/pf-client-core/Cargo.toml +++ b/crates/pf-client-core/Cargo.toml @@ -23,8 +23,68 @@ pf-ffvk = { path = "../pf-ffvk" } # video_vk_native.rs, running pf-vkdecode's VkH264Decoder/VkH265Decoder/VkAv1Decoder on # the presenter's shared device. pf-vkdecode = { path = "../pf-vkdecode" } +# The one bitstream parser (M1): the SOFTWARE rung reads its per-picture colour +# signalling, IDR flag and recovery-point SEI from the same `AuPlan` every hardware rung +# already submits from (`video_software.rs`). That is what makes the swscale BT.601 +# default unrepresentable rather than merely fixed — there is no second colour source +# left to disagree with. +pf-bitstream = { path = "../pf-bitstream" } async-channel = "2" +# M8's software rung, the ladder's last one — no FFmpeg in either half. +# +# H.264: openh264 (BSD-2), already a workspace dependency (the HOST's GPU-less encoder, +# `pf-encode/src/enc/sw.rs`), so the licence posture and the bundled-source build are +# both already settled and already compiled by every `--workspace` leg. +# +# AV1: rav1d (BSD-2) — dav1d itself, ported to Rust by the ISRG/Prossimo memory-safety +# project. The plan of record names "dav1d"; the `dav1d` crate reaches it through +# `dav1d-sys`, which is `system-deps`-only (no vendored build): it needs `dav1d.pc` + +# headers at build time and `libdav1d.so`/`dav1d.dll` at run time on EVERY client +# package. That is a new system codec dependency added by the milestone family whose +# §6 excision checklist exists to delete exactly those. rav1d is the same decoder with +# none of that: pure Rust, no linker, nothing new in any package. +# +# ⚠ Both of these are NEW COMPILE COST on the client packaging legs, which is easy to +# miss because the workspace already built openh264: every client leg is `-p`-scoped and +# excludes pf-encode (flatpak's `cargo build -p punktfunk-client-linux -p +# punktfunk-client-session -p punktfunk-cli`, windows.yml/windows-msix.yml's +# `-p punktfunk-client-windows …`, deb.yml's client job, packaging/nix's +# `punktfunk-client`), so all of them compile the bundled OpenH264 tree for the FIRST +# time here. Only the `--workspace` CI legs and the host packages built it before. +# +# `default-features = false` drops two things deliberately: +# * `asm` — rav1d's hand-written assembly needs `nasm` at build time, and it is NOT the +# same trade openh264 makes next to it: openh264-sys2's `try_compile_nasm` returns +# quietly when nasm is missing ("Failed to compile NASM files, not using any +# assembly") and the C build still succeeds, whereas rav1d's build.rs PANICS ("NASM +# build failed. Make sure you have nasm installed or disable the \"asm\" feature"). +# So turning `asm` on makes nasm a hard build requirement of every client package, +# and `ci/rust-ci.Dockerfile` — the container the client .deb and the workspace CI +# build in — does not have it (arch, rpm, nix and the FFmpeg-building noble image +# all do; the flatpak GNOME SDK and the Windows runner are not provisioned by +# anything in this tree). Making the rung that only ever runs BECAUSE the GPU +# already failed a build-breaker for the legs that ship it is the wrong way round. +# Turn it back on the day every client leg provisions nasm — and expect a large +# speedup when you do; this is dav1d's asm, and the Rust fallbacks are much slower. +# * `bitdepth_16` — the CPU rung is 8-bit by contract (`video_software.rs` refuses +# anything else rather than mis-scaling it), so building the 10/12-bit half would be +# compiling a path the code refuses to take. +# +# One packaging risk this DOESN'T carry: rav1d exports dav1d's C ABI as `#[no_mangle]` +# symbols (`dav1d_open`, `dav1d_send_data`, …), which could in principle interpose on a +# real libdav1d loaded into the same process. It cannot here — these are Rust `staticlib` +# symbols in an executable with no `-rdynamic` and no dynamic export table entry, so the +# loader never offers them to anyone. That changes if pf-client-core ever becomes a +# `cdylib` or a leg adds `-rdynamic`/`--export-dynamic`; re-check it then. +openh264 = "0.9" +rav1d = { version = "1", default-features = false, features = ["bitdepth_8"] } +# errno names for rav1d's negated-`c_int` returns (`video_software.rs`): `ENOPROTOOPT` — +# the code a `bitdepth_8`-only build answers a 10-bit stream with — is 92 on Linux and +# 123 on Windows, and rav1d re-exports only `Dav1dResult`, so the typed enum that would +# otherwise name it is out of reach. Already in the tree (rav1d's own dependency). +libc = "0.2" + # Video decode (same FFmpeg pin as the host) and Opus for the audio planes. ffmpeg-next = "8" opus = "0.3" diff --git a/crates/pf-client-core/src/session.rs b/crates/pf-client-core/src/session.rs index c022aa4f..e7b5da75 100644 --- a/crates/pf-client-core/src/session.rs +++ b/crates/pf-client-core/src/session.rs @@ -16,6 +16,12 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::{Duration, Instant}; +/// `Clone` so an embedder can keep the params a session was started with and re-dial with +/// one field changed — which is what the codec fallback ([`SessionEvent::CodecFallback`]) +/// needs and the only reason the derive exists. Every field is either plain data or an +/// `Arc` the retry deliberately SHARES: the same `force_software` flag and the same +/// presenter-written `latch_grid`, because they belong to the presenter, not the session. +#[derive(Clone)] pub struct SessionParams { pub host: String, pub port: u16, @@ -28,6 +34,15 @@ pub struct SessionParams { /// The user's preferred video codec (a `quic::CODEC_*` bit, `0` = auto). Soft — the host honors /// it when it can emit it, else falls back; the resolved codec drives the decoder. pub preferred_codec: u8, + /// `quic::CODEC_*` bits to REMOVE from this session's advertised decode caps. + /// + /// `0` for every ordinary connect. It is set by a retry after + /// [`SessionEvent::CodecFallback`]: a session whose codec exhausted the decode ladder + /// (in practice HEVC, whose CPU rung M8 removed — no permissively licensed software + /// HEVC decoder exists) comes back advertising the codec set the host must pick + /// from instead. The codec is fixed at Welcome and the control stream renegotiates + /// shard payload only, so a fresh Hello is the ONLY lever; this field is it. + pub exclude_codecs: u8, /// The advertised `quic::VIDEO_CAP_*` bits. Normally 10-bit + HDR (Main10/PQ: the /// Vulkan presenter decodes P010 everywhere and presents PQ on an HDR10 swapchain /// where the desktop offers one, tonemapping in the CSC shader where it doesn't; @@ -254,9 +269,55 @@ pub enum SessionEvent { trust_rejected: bool, }, Ended(Option), + /// The session's negotiated codec ran out of decode rungs and the client can finish + /// this stream only as a DIFFERENT codec — terminal, like [`Self::Ended`], but with + /// the retry already computed. + /// + /// The one case in practice is HEVC on a box whose hardware HEVC decode failed: M8 + /// dropped software HEVC (no permissively licensed decoder exists), so the ladder's + /// last rung refuses instead of limping, and the answer is a reconnect advertising + /// [`Self::CodecFallback::retry_caps`] — which never contains the codec that just + /// failed. The other case is a picture SHAPE the CPU rung cannot decode (10-bit, + /// 4:4:4), which is a different diagnosis with the same available action; the two + /// pick different retry sets, and [`crate::video::last_rung_verdict`] is where that + /// is decided. + /// + /// An embedder that does not implement the retry MUST still show `msg` and stop — + /// treating it as an ordinary end is correct, just worse. It is a separate variant + /// rather than a flag on `Ended` so the compiler asks every embedder the question + /// once, which is how the two D3D11VA rungs' shared `stats:` tag went wrong when it + /// was not asked (`1573a987`). + CodecFallback { + /// What to pass as [`SessionParams::exclude_codecs`] on the retry — DERIVED from + /// [`Self::CodecFallback::retry_caps`], so applying it advertises exactly those + /// caps and nothing wider. + exclude_codecs: u8, + /// The caps the retry will advertise — non-empty by construction, and what + /// `exclude_codecs` above resolves to on the wire. + retry_caps: u8, + /// User-facing one-liner for the toast/status strip. + msg: String, + }, Stats(Stats), } +/// How many times THIS PROCESS has had a session's codec exhaust the decode ladder — the +/// telemetry counter the risk register asks for ("telemetry on frequency") for the +/// software-HEVC drop. +/// +/// Process-scoped and monotonic because the thing being counted is a property of the +/// machine, not of one session: a box whose hardware HEVC decode is broken produces one +/// of these per connect, and it is the RATE across a session history that says whether +/// dropping software HEVC hurt anybody. Read it with [`codec_fallbacks`]. +static CODEC_FALLBACKS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); + +/// See [`CODEC_FALLBACKS`]. Surfaced on the session's Detailed stats block as an +/// additive `codec_fallbacks ` line once it is nonzero — appended last, never +/// removed, never reordered (`run.rs`'s `stats_text`). +pub fn codec_fallbacks() -> u64 { + CODEC_FALLBACKS.load(Ordering::Relaxed) +} + /// The in-stream microphone mute (B4), shared between the embedder's toggle (a keyboard chord /// in the presenter) and the capture callback that reads it every quantum. /// @@ -409,6 +470,23 @@ fn pump( // on their arrivals, so this bit alone changes nothing without a wired DualSense. let pad_speaker_on = crate::pad_audio::speaker_active(¶ms.pad_speaker); let pad_audio_on = params.pad_haptics || pad_speaker_on; + // What this session advertises it can decode, minus anything a previous attempt + // proved it cannot FINISH (see `SessionParams::exclude_codecs`). Held for the whole + // pump because the reconnect rule needs to know what was on the table, not just what + // the host picked. + let advertised_codecs = crate::video::decodable_codecs_for( + params.vulkan.as_ref(), + // The decoder pin is part of the answer: a session pinned to software has no HEVC + // rung at all, so advertising HEVC would promise what this build cannot keep. + ¶ms.decoder, + ) & !params.exclude_codecs; + if params.exclude_codecs != 0 { + tracing::info!( + excluded = params.exclude_codecs, + advertising = advertised_codecs, + "retrying with reduced decode caps" + ); + } let connector = match NativeClient::connect( ¶ms.host, params.port, @@ -418,8 +496,9 @@ fn pump( params.bitrate_kbps, params.video_caps, params.audio_channels, - // FFmpeg's codecs plus CODEC_PYROWAVE when the presenter device passed the probe. - crate::video::decodable_codecs_for(params.vulkan.as_ref()), + // FFmpeg's codecs plus CODEC_PYROWAVE when the presenter device passed the probe, + // minus whatever a previous attempt proved undecodable end to end. + advertised_codecs, preferred, // the user's soft codec preference (0 = auto; see the pyrowave opt-in above) // This display's HDR volume → the host's virtual-display EDID. The env hatch wins so an // A/B run can pin an exact peak (PUNKTFUNK_CLIENT_PEAK_NITS=600). @@ -562,7 +641,29 @@ fn pump( let mut decoder = match built { Ok(d) => d, Err(e) => { - let _ = ev_tx.send_blocking(SessionEvent::Ended(Some(format!("video decoder: {e}")))); + // The ladder had NO rung for this codec at all — on a box with no hardware + // HEVC decode (or one that pinned `PUNKTFUNK_DECODER=software` on an HEVC + // session). Same answer as the mid-stream case below, one code path. + let refusal = e.downcast_ref::().map(|nr| { + codec_fallback_event( + connector.codec, + advertised_codecs, + nr.loss(), + &e.to_string(), + ) + }); + // Nothing has been spawned yet at this point — the audio / pad / clipboard + // threads and the mic uplink are all built BELOW — so "joined its threads" is + // vacuously true here. Set the stop flag and drop the connector anyway, in + // the same order the pump's end path does, so an embedder that reconnects on + // receipt of this event finds the same world whichever refusal site produced + // it (`run.rs` starts the retry the instant it reads one). + stop.store(true, Ordering::SeqCst); + mic.set_live(false); + drop(connector); + let _ = ev_tx.send_blocking( + refusal.unwrap_or_else(|| SessionEvent::Ended(Some(format!("video decoder: {e}")))), + ); return; } }; @@ -714,6 +815,10 @@ fn pump( // `window_dropped`: the decoder's counters are session-cumulative, the OSD shows // the delta. `None` on every lane that cannot answer — see `Stats::decode_integrity`. let mut window_health = decoder.decode_health(); + // Set when the ladder ran out of rungs for this codec (M8): the loop breaks and this + // event replaces the plain `Ended` at the bottom. `Some` is the only way the pump + // ends with a retry attached. + let mut codec_fallback: Option = None; let end: Option = loop { if stop.load(Ordering::SeqCst) { @@ -1046,6 +1151,25 @@ fn pump( tracing::debug!("requested keyframe (decoder produced no output)"); } } + // NOT survivable, and the only decode error that isn't: the ladder + // demoted to its last rung and there is no such rung for this codec. + // Feeding more AUs would freeze the screen forever — the exact + // "limping on software" outcome M8's HEVC drop replaces with an + // action. Break out of the pump; the terminal event below carries the + // retry the embedder reconnects with. + Err(e) if e.downcast_ref::().is_some() => { + let loss = e + .downcast_ref::() + .expect("just matched") + .loss(); + codec_fallback = Some(codec_fallback_event( + connector.codec, + advertised_codecs, + loss, + &e.to_string(), + )); + break None; + } // Survivable (loss until the next IDR/RFI recovery) — keep feeding. Err(e) => { tracing::debug!(error = %e, "decode error (recovering)"); @@ -1339,7 +1463,56 @@ fn pump( if let Some(t) = clipboard_thread { let _ = t.join(); // exits within its next_clip wait once `stop` is set } - let _ = ev_tx.send_blocking(SessionEvent::Ended(end)); + // The codec-exhaustion end has its own terminal event — sent HERE, after the audio / + // pad / clipboard threads have joined, so an embedder that reconnects on receipt + // never has two sessions' worth of threads on the same connector. + let _ = ev_tx.send_blocking(codec_fallback.unwrap_or(SessionEvent::Ended(end))); +} + +/// Build the terminal event for a session whose codec exhausted the decode ladder, and +/// bump the telemetry counter. +/// +/// One place, called from both refusal sites (decoder construction and the mid-stream +/// demotion), because the two must produce the SAME retry — a construction-time refusal +/// that reconnected onto a different codec set than the mid-stream one would make field +/// reports unreadable. +fn codec_fallback_event( + negotiated: u8, + advertised: u8, + loss: crate::video::RungLoss, + detail: &str, +) -> SessionEvent { + use crate::video::{last_rung_verdict, wire_codec_name, LastRungVerdict}; + CODEC_FALLBACKS.fetch_add(1, Ordering::Relaxed); + let codec = wire_codec_name(negotiated); + match last_rung_verdict(negotiated, advertised, loss) { + LastRungVerdict::Retry { caps } => { + tracing::warn!( + codec, + retry_caps = caps, + detail, + "video decode ran out of rungs — reconnecting without this codec" + ); + SessionEvent::CodecFallback { + // DERIVED from the verdict, never from the failed codec alone: the retry + // then advertises exactly `caps` (`decodable_codecs_for & !exclude` + // re-intersects to it), so the wire and the rule cannot disagree. They + // did before the M8 review — the rule dropped PyroWave and the wire + // re-offered it. + exclude_codecs: advertised & !caps, + retry_caps: caps, + msg: format!("{codec} decoding failed on this device — reconnecting"), + } + } + // Nothing left to advertise: reconnecting would negotiate the same dead end. End + // the session and say what actually happened, rather than loop. + LastRungVerdict::Dead => { + tracing::error!(codec, detail, "video decode ran out of rungs and of codecs"); + SessionEvent::Ended(Some(format!( + "{codec} can't be decoded on this device, and no other codec is available" + ))) + } + } } /// The dedicated audio thread: owns the Opus decoder, the PCM scratch, and the PipeWire @@ -1467,4 +1640,113 @@ mod tests { assert!(!mic.muted()); assert_eq!(mic.toggle(), None); } + + /// M8's HEVC reconnect, as the terminal event both refusal sites produce. + /// + /// This is the "reconnect flow tested as a first-class path" the plan's risk register + /// asks for, at the layer where it can be tested without a host: the pump's two + /// call sites (decoder construction and the mid-stream demotion) both go through + /// `codec_fallback_event`, so pinning its output pins the flow — the retry never + /// re-offers the codec that just failed, the message is user-facing, and the + /// telemetry counter moves exactly once per occurrence. + /// `CODEC_FALLBACKS` is process-global and `codec_fallback_event` bumps it, so the + /// test that asserts "counted exactly once" cannot run beside another that calls the + /// same builder. Both take this. + static FALLBACK_COUNTER: std::sync::Mutex<()> = std::sync::Mutex::new(()); + + #[test] + fn an_exhausted_codec_produces_a_retry_event_and_moves_the_counter() { + use crate::video::RungLoss; + use punktfunk_core::quic::{CODEC_AV1, CODEC_H264, CODEC_HEVC}; + let _guard = FALLBACK_COUNTER.lock().unwrap_or_else(|e| e.into_inner()); + let before = codec_fallbacks(); + + // The shipping shape: HEVC negotiated, H.264 also advertised. + let ev = codec_fallback_event( + CODEC_HEVC, + CODEC_H264 | CODEC_HEVC, + RungLoss::Codec, + "no software HEVC", + ); + match ev { + SessionEvent::CodecFallback { + exclude_codecs, + retry_caps, + ref msg, + } => { + assert_eq!(exclude_codecs, CODEC_HEVC, "the retry must drop HEVC"); + assert_eq!(retry_caps, CODEC_H264); + // The toast is for a person: it names the codec and says what happens + // next, and does NOT read as an error the user has to act on. + assert!(msg.contains("HEVC"), "{msg}"); + assert!(msg.contains("reconnect"), "{msg}"); + } + _ => panic!("expected a CodecFallback"), + } + assert_eq!(codec_fallbacks(), before + 1, "counted exactly once"); + + // Hardware AV1 advertised too: both survivors stay on the table. + match codec_fallback_event( + CODEC_HEVC, + CODEC_H264 | CODEC_HEVC | CODEC_AV1, + RungLoss::Codec, + "x", + ) { + SessionEvent::CodecFallback { retry_caps, .. } => { + assert_eq!(retry_caps, CODEC_H264 | CODEC_AV1); + } + _ => panic!("expected a CodecFallback"), + } + + // Nothing left to offer: end honestly instead of a reconnect loop. Still counted + // — the failure happened, and its frequency is exactly what the counter is for. + let before = codec_fallbacks(); + match codec_fallback_event(CODEC_HEVC, CODEC_HEVC, RungLoss::Codec, "x") { + SessionEvent::Ended(Some(msg)) => { + assert!(msg.contains("HEVC"), "{msg}"); + assert!(msg.contains("no other codec"), "{msg}"); + } + _ => panic!("expected a plain Ended"), + } + assert_eq!(codec_fallbacks(), before + 1); + } + + /// `exclude_codecs` and `retry_caps` describe the SAME retry — the review found them + /// disagreeing, and the wire follows `exclude_codecs`, so a mismatch means the tested + /// rule is not the shipped one. + /// + /// The property is exact, not approximate: the retry advertises + /// `decodable_codecs_for(vk) & !exclude_codecs`, and this session already advertised + /// `decodable_codecs_for(vk) & !old_exclude` — so re-intersecting with the derived + /// mask must land on `retry_caps` itself. + #[test] + fn the_retrys_exclusion_resolves_to_exactly_its_advertised_caps() { + use crate::video::RungLoss; + use punktfunk_core::quic::{CODEC_AV1, CODEC_H264, CODEC_HEVC, CODEC_PYROWAVE}; + let _guard = FALLBACK_COUNTER.lock().unwrap_or_else(|e| e.into_inner()); + for advertised in 0u8..16 { + for negotiated in [CODEC_H264, CODEC_HEVC, CODEC_AV1, CODEC_PYROWAVE] { + for loss in [RungLoss::Codec, RungLoss::Shape] { + let SessionEvent::CodecFallback { + exclude_codecs, + retry_caps, + .. + } = codec_fallback_event(negotiated, advertised, loss, "x") + else { + continue; // Dead — nothing is advertised at all + }; + assert_eq!( + advertised & !exclude_codecs, + retry_caps, + "advertised {advertised:#x} negotiated {negotiated:#x} {loss:?}" + ); + assert_eq!(retry_caps & negotiated, 0, "the failed codec came back"); + } + } + } + // Excluding twice is idempotent — a second fallback in the same run widens the + // set rather than resetting it (`run.rs` ORs into the existing value). + let full = CODEC_H264 | CODEC_HEVC | CODEC_AV1; + assert_eq!((full & !CODEC_HEVC) & !CODEC_HEVC, CODEC_H264 | CODEC_AV1); + } } diff --git a/crates/pf-client-core/src/video.rs b/crates/pf-client-core/src/video.rs index c3235489..00baf0e6 100644 --- a/crates/pf-client-core/src/video.rs +++ b/crates/pf-client-core/src/video.rs @@ -32,8 +32,12 @@ //! (nvidia-vaapi-driver is broken for this — Moonlight blacklists it); device //! creation fails there. A mid-session error falls back — the host's IDR/RFI //! recovery resynchronizes. -//! * **Software**: libavcodec on the CPU + swscale to RGBA (staging upload). -//! Slice threading only — frame threading would add a frame of latency per thread. +//! * **Software**: the CPU rung, FFmpeg-free since M8 — openh264 for H.264, rav1d +//! (dav1d) for AV1, planes uploaded straight to the presenter's planar CSC pass. It is +//! the LAST rung, so it never demotes further; and it has no HEVC decoder at all (none +//! exists under a permissive licence), which is a REFUSAL that reconnects the session +//! onto a codec this client can decode — see [`last_rung_verdict`] and +//! [`NoSoftwareRung`]. //! //! Both run `AV_CODEC_FLAG_LOW_DELAY`; the host encodes zero-reorder streams (no //! B-frames, in-band parameter sets on every IDR), so decode is strictly one-in/one-out. @@ -57,6 +61,9 @@ use ffmpeg_next as ffmpeg; use std::os::fd::RawFd; pub use crate::video_color::{csc_rows, ColorDesc}; +/// Re-exported so the SESSION layer (and its tests) can name the refusal by type — the +/// module itself stays private, like every other backend's. +pub use crate::video_software::NoSoftwareRung; use crate::video_software::SoftwareDecoder; #[cfg(target_os = "linux")] use crate::video_vaapi::VaapiDecoder; @@ -81,7 +88,16 @@ pub struct DecodedFrame { pub use crate::video_d3d11::D3d11Frame; pub enum DecodedImage { - Cpu(CpuFrame), + /// The SOFTWARE rung's output (M8): tightly-packed 8-bit I420 planes for the + /// presenter to upload and run its planar CSC pass over. + /// + /// It REPLACES the old `Cpu(CpuFrame)` RGBA variant rather than joining it — there is + /// exactly one CPU rung, and the swscale conversion it used to carry (and its BT.601 + /// default) is what this milestone deletes. Adding a second CPU variant would have + /// bought the [`DecodedImage::NativeDmabuf`] property below for a distinction that + /// does not exist: no `stats:` tag, no presenter path and no consumer would ever have + /// been able to reach the old one. + Cpu(CpuPlanarFrame), #[cfg(target_os = "linux")] Dmabuf(DmabufFrame), /// The NATIVE VAAPI rung's output (`pf-vaadec` + `video_vaapi_native`, M6) — @@ -545,14 +561,23 @@ impl DecodedImage { /// What the decoder's OWN bitstream parser saw about an intra-refresh heal on /// this frame's AU — the recovery point SEI, which no platform decoder exposes. /// - /// Only the native rung can answer: libavcodec parses the SEI internally and - /// surfaces nothing of it (its `AV_FRAME_FLAG_KEY` is IDR-only), MediaCodec and - /// VideoToolbox likewise. Everyone else reports + /// Only the rungs with their OWN parser can answer: libavcodec parses the SEI + /// internally and surfaces nothing of it (its `AV_FRAME_FLAG_KEY` is IDR-only), + /// MediaCodec and VideoToolbox likewise. That is the native Vulkan rung and — since + /// M8 — the CPU rung's H.264 leg, which plans every AU with the same `H264Planner` + /// and folds the SEI with the same `RecoveryWatch`. Everyone else reports /// [`LocalRecovery::NONE`](punktfunk_core::reanchor::LocalRecovery::NONE) and /// the pump's re-anchor behaviour on those lanes is byte-for-byte what it was. + /// + /// ⚠ The CPU rung reports no [`Self::decode_order`], so its mark cannot be dated + /// against the pump's arm the way the native rung's is. It does not need to be: + /// openh264 is one-AU-in, at-most-one-picture-out with no DPB flush that replays + /// pictures decoded before a loss, which is the only thing that ordinal defends + /// against. pub fn local_recovery(&self) -> punktfunk_core::reanchor::LocalRecovery { match self { DecodedImage::NativeVk(f) => f.recovery, + DecodedImage::Cpu(f) => f.recovery, _ => punktfunk_core::reanchor::LocalRecovery::NONE, } } @@ -586,19 +611,123 @@ impl DecodedImage { } } -/// RGBA pixels for `GdkMemoryTexture` (which takes a stride). -pub struct CpuFrame { +/// One software-decoded picture as 8-bit 4:2:0 PLANES (M8) — Y, Cb and Cr back to back +/// in one allocation, every plane tightly packed at its own width. +/// +/// "Tightly packed" is a load-bearing invariant, not a convenience: the presenter uploads +/// the buffer with a single `copy_nonoverlapping` and three `vkCmdCopyBufferToImage` +/// regions with `bufferRowLength = 0`, so a padded row here would shear the picture. The +/// decoders' own strides (openh264 pads for SIMD, dav1d aligns) are undone once, in +/// [`Self::from_i420`], which is also the only copy this rung makes per frame — where the +/// old RGBA path made a full swscale conversion pass and then handed over 4 bytes per +/// pixel instead of 1.5. +/// +/// Colour is NOT applied here. The planes carry the stream's own Y′CbCr and `color` +/// carries what the bitstream said about it; the presenter's planar CSC shader converts +/// with [`csc_rows`], the same coefficients every hardware rung's frames go through. That +/// is the whole point of the milestone: there is no second CSC implementation on this +/// lane to get the matrix or the range wrong. +pub struct CpuPlanarFrame { pub width: u32, pub height: u32, - /// RGBA row stride in bytes (≥ width*4 — swscale pads rows for SIMD). - pub stride: usize, - pub rgba: Vec, - /// Signaling of the source frame. swscale already undid the YUV matrix + range (the - /// pixels are full-range RGB), but a PQ/BT.2020 stream keeps its transfer + primaries - /// baked in — the presenter tags the texture so GTK tone-maps it. + /// Y, then Cb, then Cr — see [`Self::plane`]. + data: Vec, + /// Byte offset of each plane's first row in [`Self::data`]. + offsets: [usize; 3], + /// Signalling of the source frame, read from the bitstream (not from the decoder — + /// see `video_software`'s module docs). Drives the CSC matrix/range AND, for a PQ + /// stream, the presenter's tone-map mode. pub color: ColorDesc, - /// Intra keyframe (IDR/I) — the pump's post-loss re-anchor signal. See [`VkVideoFrame`]. + /// Intra keyframe (IDR) — the pump's post-loss re-anchor signal. See [`VkVideoFrame`]. pub keyframe: bool, + /// What this frame's AU said about intra-refresh RECOVERY — the same + /// `pf-vkdecode` [`RecoveryWatch`](pf_vkdecode::RecoveryWatch) fold the native rung + /// runs, over the same `AuPlan`. [`Self::keyframe`] cannot answer for an + /// intra-refresh session (the wave emits no IDR), so without this the pump freezes + /// until its 500 ms backstop forces the very IDR the wave exists to avoid. + /// + /// H.264 only: AV1 carries no equivalent SEI (see `video_software`'s AV1 leg), so + /// that half reports [`LocalRecovery::NONE`](punktfunk_core::reanchor::LocalRecovery) + /// and behaves exactly as it did. + pub recovery: punktfunk_core::reanchor::LocalRecovery, +} + +impl CpuPlanarFrame { + /// Chroma plane size for 4:2:0, rounding UP — an odd luma dimension still has a + /// chroma sample covering its last row/column, and rounding down would drop it. + pub fn chroma_dims(width: u32, height: u32) -> (u32, u32) { + (width.div_ceil(2), height.div_ceil(2)) + } + + /// Plane `i` (0 = Y, 1 = Cb, 2 = Cr), tightly packed. + pub fn plane(&self, i: usize) -> &[u8] { + let (w, h) = self.plane_dims(i); + let start = self.offsets[i]; + &self.data[start..start + (w * h) as usize] + } + + /// Plane `i`'s size in samples — `(width, height)` for luma, the 4:2:0 halves for + /// chroma. The presenter sizes its plane images from this. + pub fn plane_dims(&self, i: usize) -> (u32, u32) { + if i == 0 { + (self.width, self.height) + } else { + Self::chroma_dims(self.width, self.height) + } + } + + /// Copy a decoder's strided I420 output into one tightly-packed allocation. + /// + /// Refuses rather than truncates: a plane the decoder reported shorter than its own + /// geometry means the decoder and we disagree about the picture, and reading the rows + /// that ARE there would produce a plausible-looking picture over uninitialized + /// memory. + pub(crate) fn from_i420( + width: u32, + height: u32, + planes: [&[u8]; 3], + strides: [usize; 3], + color: ColorDesc, + keyframe: bool, + recovery: punktfunk_core::reanchor::LocalRecovery, + ) -> Result { + anyhow::ensure!(width > 0 && height > 0, "empty picture {width}x{height}"); + let (cw, ch) = Self::chroma_dims(width, height); + let dims = [(width, height), (cw, ch), (cw, ch)]; + let total: usize = dims.iter().map(|(w, h)| *w as usize * *h as usize).sum(); + let mut data = vec![0u8; total]; + let mut offsets = [0usize; 3]; + let mut at = 0usize; + for i in 0..3 { + let (w, h) = (dims[i].0 as usize, dims[i].1 as usize); + anyhow::ensure!( + strides[i] >= w, + "plane {i}: stride {} is narrower than {w} samples", + strides[i] + ); + anyhow::ensure!( + planes[i].len() >= (h - 1) * strides[i] + w, + "plane {i}: decoder reported {} bytes for {w}x{h} at stride {}", + planes[i].len(), + strides[i] + ); + offsets[i] = at; + for row in 0..h { + let src = row * strides[i]; + data[at..at + w].copy_from_slice(&planes[i][src..src + w]); + at += w; + } + } + Ok(CpuPlanarFrame { + width, + height, + data, + offsets, + color, + keyframe, + recovery, + }) + } } /// A decoded frame still on the GPU: dmabuf fds + plane layout for @@ -716,6 +845,9 @@ enum Backend { /// Boxed: the decoder (pinned create-info hold + plane ring) dwarfs the other variants. #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] PyroWave(Box), + /// The CPU rung (M8: openh264 / rav1d, no libavcodec). Last in every ladder, so it + /// never demotes — and the only rung that can fail to EXIST for a codec, which is a + /// different answer from failing to decode: see [`last_rung_verdict`]. Software(SoftwareDecoder), } @@ -758,6 +890,12 @@ pub struct Decoder { /// The negotiated codec (from the host's Welcome), so a mid-session VAAPI→software demotion /// rebuilds the software decoder for the SAME codec. codec_id: ffmpeg::codec::Id, + /// The same codec as the WIRE states it — what the software rung is built for and + /// what a refusal names. Derived once from [`Self::codec_id`] rather than carried + /// through a widened `Decoder::new` signature, because the ladder above still speaks + /// FFmpeg ids and will until M10 deletes its last FFmpeg rung; this field is the one + /// place the two vocabularies meet. + wire_codec: u8, /// Consecutive hardware decode errors (Vulkan or VAAPI) — a single transient failure /// (e.g. a reference-missing frame after packet loss) shouldn't cost the whole /// session its hardware decoder. @@ -962,6 +1100,120 @@ fn native_vulkan_gate( chosen && video_decode && decode_video_caps & codec_op != 0 } +/// The `quic::CODEC_*` bit's human name — for logs, errors and the user-visible +/// reconnect toast. `?` for a bit this build does not know, which is honest: an unknown +/// codec must not print as one of the known ones. +pub fn wire_codec_name(wire: u8) -> &'static str { + match wire { + punktfunk_core::quic::CODEC_H264 => "H.264", + punktfunk_core::quic::CODEC_HEVC => "HEVC", + punktfunk_core::quic::CODEC_AV1 => "AV1", + punktfunk_core::quic::CODEC_PYROWAVE => "PyroWave", + _ => "?", + } +} + +/// The `quic` codec bit for an FFmpeg decoder id — the inverse of [`ffmpeg_codec_id`], +/// for the one place that has an id in hand and needs the WIRE truth (the software rung's +/// refusal, which must name a codec the host understands). Dies with the ladder's last +/// FFmpeg id at M10. +fn wire_codec_of(id: ffmpeg::codec::Id) -> u8 { + match id { + ffmpeg::codec::Id::H264 => punktfunk_core::quic::CODEC_H264, + ffmpeg::codec::Id::AV1 => punktfunk_core::quic::CODEC_AV1, + _ => punktfunk_core::quic::CODEC_HEVC, + } +} + +/// The `quic` codec bits this build can decode ON THE CPU — the ladder's last rung, and +/// therefore the set a session is guaranteed to survive to the end of. +/// +/// One function so the answer cannot drift between the rung that refuses (the software +/// backend's own codec map) and the rule that decides what to reconnect as +/// ([`last_rung_verdict`]). +pub fn software_decodable_codecs() -> u8 { + punktfunk_core::quic::CODEC_H264 | punktfunk_core::quic::CODEC_AV1 +} + +/// What to do when the last rung has no decoder for the session's codec. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LastRungVerdict { + /// Reconnect advertising these caps instead — they are non-empty, and they exclude + /// the codec that just ran out of rungs, so the host must pick something else. + Retry { caps: u8 }, + /// Nothing is left to advertise: every codec this client offered has now exhausted + /// its rungs. Reconnecting would negotiate the same dead end, so the session ends + /// and says why. + Dead, +} + +/// WHY the last rung had no answer — the two diagnoses behind a [`NoSoftwareRung`], and +/// the reason [`last_rung_verdict`] needs more than "a codec failed". +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RungLoss { + /// The CODEC has no CPU rung in this build at all (HEVC). Every hardware rung for it + /// has already failed, so the retry may only offer codecs that DO have a CPU rung — + /// anything else is the same bet that just lost, one session later. + Codec, + /// The codec has a CPU rung; this stream's picture SHAPE is outside it (10-bit, + /// 4:4:4). The hardware rungs are not implicated at all — nothing failed, the CPU + /// decoder simply is not built for this picture — so every other advertised codec is + /// a genuine candidate and filtering by [`software_decodable_codecs`] here would end + /// sessions a plain HEVC retry would have finished. + Shape, +} + +/// The reconnect rule, in one pure function: an HEVC session whose hardware rungs are +/// exhausted must come back as a session this client can finish. +/// +/// The codec is fixed at Welcome and the control stream renegotiates shard payload only, +/// so there is no in-session move available — the only lever is what the NEXT Hello +/// advertises. `advertised` is what this session offered; the answer removes `negotiated` +/// from it, plus — for a [`RungLoss::Codec`] — any other codec that would land in the +/// same hole (one whose only remaining rung is a software one that does not exist). Two +/// sessions of the same failure is the shape this rules out. +/// +/// `caps` is what the retry ACTUALLY advertises: the pump derives its `exclude_codecs` +/// from this set rather than from the failed codec alone, so the wire and this verdict +/// cannot disagree (they did until the M8 review — the wire re-offered PyroWave the rule +/// had removed). +/// +/// Pure and total on purpose — this is the piece that gets tested as a first-class path, +/// because the on-glass version of it costs a real host with a real GPU failure. +pub fn last_rung_verdict(negotiated: u8, advertised: u8, loss: RungLoss) -> LastRungVerdict { + let survivors = advertised & !negotiated; + let caps = match loss { + // Everything still on the table that ALSO has a CPU rung underneath it. + RungLoss::Codec => survivors & software_decodable_codecs(), + RungLoss::Shape => survivors, + }; + // A retry the host's precedence ladder cannot PICK is not a retry: `resolve_codec` + // deliberately keeps PyroWave out of that ladder (it is opt-in only), so a Hello + // whose survivors are PyroWave alone resolves to nothing and the host refuses the + // session. Judge liveness on the pickable ones and carry the rest along. + const PICKABLE: u8 = punktfunk_core::quic::CODEC_H264 + | punktfunk_core::quic::CODEC_HEVC + | punktfunk_core::quic::CODEC_AV1; + if caps & PICKABLE == 0 { + LastRungVerdict::Dead + } else { + LastRungVerdict::Retry { caps } + } +} + +/// Is video decode PINNED to the CPU rung — the Settings "Video decoder" value, or the +/// `PUNKTFUNK_DECODER` override that wins over it? +/// +/// Same precedence as [`Decoder::new`] resolves (env first, then the setting), because a +/// second reading of the same two inputs is a second place for them to drift. +pub fn decode_pinned_to_software(pref: &str) -> bool { + std::env::var("PUNKTFUNK_DECODER") + .ok() + .filter(|v| !v.is_empty()) + .unwrap_or_else(|| pref.to_string()) + == "software" +} + /// Map a negotiated `quic` codec bit to the FFmpeg decoder id the client opens. pub fn ffmpeg_codec_id(wire: u8) -> ffmpeg::codec::Id { match wire { @@ -1058,6 +1310,16 @@ pub(crate) unsafe fn codec_name(codec: *const ffmpeg::ffi::AVCodec) -> String { /// /// ⚠ **AV1 here is a decoder EXISTING, not a decoder that can keep up.** Use /// [`decodable_codecs_for`], which gates it on hardware — see [`av1_hardware_decodable`]. +/// +/// ⚠ **HEVC here is a HARDWARE decoder existing**, and since M8 that is the only kind +/// there is: the CPU rung has no HEVC ([`software_decodable_codecs`]). Advertising it +/// anyway is deliberate and is the plan's — hardware HEVC is the path most hosts and most +/// clients actually take, and refusing it up front would cost every one of them the codec +/// to protect the few whose hardware later fails. The exhaustion case is handled where it +/// happens, by [`last_rung_verdict`], and it is the ONE codec whose advertisement is a +/// promise this client cannot keep unconditionally. Where the client can KNOW in advance +/// that it cannot keep it — decode pinned to software — [`decodable_codecs_for`] drops +/// the bit before the first Hello instead. pub fn decodable_codecs() -> u8 { let _ = ffmpeg::init(); let mut bits = 0u8; @@ -1111,10 +1373,11 @@ pub fn av1_hardware_decodable(vk: Option<&VulkanDecodeDevice>) -> bool { } /// [`decodable_codecs`] plus the PyroWave bit when the presenter's device passed the -/// compute-feature probe. Advertisement-only: `resolve_codec` never auto-picks PyroWave — -/// the session must also name it `preferred_codec` (plan §3), which the client does only -/// under its explicit opt-in. -pub fn decodable_codecs_for(vk: Option<&VulkanDecodeDevice>) -> u8 { +/// compute-feature probe, minus the codecs `decoder_pref` makes unreachable. +/// Advertisement-only: `resolve_codec` never auto-picks PyroWave — the session must also +/// name it `preferred_codec` (plan §3), which the client does only under its explicit +/// opt-in. +pub fn decodable_codecs_for(vk: Option<&VulkanDecodeDevice>, decoder_pref: &str) -> u8 { let mut bits = decodable_codecs(); // AV1 is hardware-gated (M7). Without this the bit rides on libdav1d's mere // presence and the host is told to send AV1 to a machine that would decode it on @@ -1126,6 +1389,24 @@ pub fn decodable_codecs_for(vk: Option<&VulkanDecodeDevice>) -> u8 { ); bits &= !punktfunk_core::quic::CODEC_AV1; } + // The one HEVC case the client can answer BEFORE the Hello (M8 review): decode is + // pinned to the CPU rung, and the CPU rung has no HEVC — so the advertisement would + // be a promise this build cannot keep for the whole session, exactly what + // `av1_hardware_decodable` exists to stop for AV1. Every other HEVC failure is a + // per-device fact only the session can learn, and `last_rung_verdict` answers it + // there. Guarded on something remaining: a Hello advertising ZERO codecs reads as + // "HEVC-only" to a host (`resolve_codec`'s pre-negotiation default), which would be + // the precise opposite of this. + if bits & punktfunk_core::quic::CODEC_HEVC != 0 + && bits & !punktfunk_core::quic::CODEC_HEVC != 0 + && decode_pinned_to_software(decoder_pref) + { + tracing::info!( + "HEVC not advertised: decode is pinned to software and there is no software \ + HEVC decoder in this build" + ); + bits &= !punktfunk_core::quic::CODEC_HEVC; + } #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] if vk.map(|v| v.pyrowave_decode).unwrap_or(false) { return bits | punktfunk_core::quic::CODEC_PYROWAVE; @@ -1244,6 +1525,7 @@ impl Decoder { Ok(Decoder { backend, codec_id, + wire_codec: wire_codec_of(codec_id), vaapi_fails: 0, first_fail: None, want_keyframe: false, @@ -1577,7 +1859,13 @@ impl Decoder { hardware decode not attempted" ); } - done(Backend::Software(SoftwareDecoder::new(codec_id)?)) + // `?` here can carry a `NoSoftwareRung` (an HEVC session that pinned software, or + // one whose device offered no hardware rung at all). It stays typed all the way + // to the pump, which turns it into the reconnect rather than a dead session — + // see [`last_rung_verdict`]. + done(Backend::Software(SoftwareDecoder::new(wire_codec_of( + codec_id, + ))?)) } /// Wait for a Vulkan-Video frame's GPU decode to complete (timeline semaphore) — @@ -1658,6 +1946,7 @@ impl Decoder { hdr16, )?)), codec_id: ffmpeg::codec::Id::HEVC, + wire_codec: punktfunk_core::quic::CODEC_PYROWAVE, vaapi_fails: 0, first_fail: None, want_keyframe: false, @@ -1689,7 +1978,9 @@ impl Decoder { return Ok(()); } tracing::warn!("presenter can't display hardware frames — demoting to software decode"); - self.backend = Backend::Software(SoftwareDecoder::new(self.codec_id)?); + // Same typed refusal as every other software-rung construction: on an HEVC + // session there is nothing below this and the pump reconnects. + self.backend = Backend::Software(SoftwareDecoder::new(self.wire_codec)?); self.vaapi_fails = 0; self.first_fail = None; self.delivered = false; @@ -1935,7 +2226,13 @@ impl Decoder { } tracing::warn!(error = %e, fails = self.vaapi_fails, "{which} decode failing repeatedly — demoting to software"); - self.backend = Backend::Software(SoftwareDecoder::new(self.codec_id)?); + // The ladder's bottom. On H.264/AV1 this always builds; on HEVC it + // NEVER does, and the `?` carries the typed `NoSoftwareRung` up to + // the pump, which reconnects with HEVC-less caps instead of leaving + // the session on a rung that cannot decode a single AU. That + // substitution — a refusal where a silently useless decoder used to + // sit — is the whole reason the drop of software HEVC is safe. + self.backend = Backend::Software(SoftwareDecoder::new(self.wire_codec)?); self.vaapi_fails = 0; self.first_fail = None; self.delivered = false; @@ -2158,6 +2455,185 @@ pub(crate) fn drm_fourcc_for(sw: ffmpeg_next::ffi::AVPixelFormat) -> Option #[cfg(test)] mod tests { use super::*; + use punktfunk_core::quic::{CODEC_AV1, CODEC_H264, CODEC_HEVC, CODEC_PYROWAVE}; + + /// The reconnect rule, as the invariant it is: an exhausted codec must come back as + /// one this client can decode ALL THE WAY DOWN, and must never come back as itself. + /// + /// This is the "first-class path" the risk register asks for, tested where it can be + /// tested exhaustively — the on-glass half needs a host, a GPU and a decode failure + /// nobody can schedule. + #[test] + fn an_exhausted_codec_reconnects_only_onto_one_with_a_cpu_rung() { + let sw = software_decodable_codecs(); + assert_eq!(sw, CODEC_H264 | CODEC_AV1, "M8's CPU rung set"); + assert_eq!(sw & CODEC_HEVC, 0, "software HEVC is what M8 dropped"); + + // The shipping case: a desktop advertises H.264+HEVC, HEVC runs out of rungs. + assert_eq!( + last_rung_verdict(CODEC_HEVC, CODEC_H264 | CODEC_HEVC, RungLoss::Codec), + LastRungVerdict::Retry { caps: CODEC_H264 } + ); + // With hardware AV1 also advertised, both survivors stay on the table — the host + // picks; we only ever REMOVE. + assert_eq!( + last_rung_verdict( + CODEC_HEVC, + CODEC_H264 | CODEC_HEVC | CODEC_AV1, + RungLoss::Codec + ), + LastRungVerdict::Retry { + caps: CODEC_H264 | CODEC_AV1 + } + ); + // A client that offered HEVC alone has nowhere to go: reconnecting would + // negotiate the same dead end, so say so instead of looping. + assert_eq!( + last_rung_verdict(CODEC_HEVC, CODEC_HEVC, RungLoss::Codec), + LastRungVerdict::Dead + ); + // The retry NEVER re-offers the codec that just failed... + for advertised in 0u8..16 { + for negotiated in [CODEC_H264, CODEC_HEVC, CODEC_AV1] { + if let LastRungVerdict::Retry { caps } = + last_rung_verdict(negotiated, advertised, RungLoss::Codec) + { + assert_eq!(caps & negotiated, 0, "{negotiated:#x} re-offered"); + // ...and, when the CODEC is what has no CPU rung, never offers one + // that would reach the same refusal a session later. + assert_eq!(caps & !software_decodable_codecs(), 0); + assert_ne!(caps, 0, "Retry must carry something to advertise"); + } + } + } + // PyroWave is not in the software set and never reaches this rule (its sessions + // renegotiate the codec on failure instead of demoting) — but if it ever did, the + // answer must be Dead, not a retry that offers a codec with no CPU decoder. + assert_eq!( + last_rung_verdict(CODEC_PYROWAVE, CODEC_PYROWAVE, RungLoss::Codec), + LastRungVerdict::Dead + ); + } + + /// A picture SHAPE the CPU rung cannot decode is not "this codec has no CPU rung", + /// and the review found the rule conflating them: a 4:4:4 H.264 session ended with + /// "no other codec is available" while an HEVC retry — whose hardware rungs never + /// even ran — would have worked. + #[test] + fn a_shape_refusal_may_retry_onto_a_codec_with_no_cpu_rung() { + // The one that used to die. HEVC has no CPU rung, but nothing about HEVC failed: + // this client asked for 4:4:4, the host resolved it, and only the CPU DECODER is + // 4:2:0-only. A reconnect without H.264 re-resolves the shape too. + assert_eq!( + last_rung_verdict(CODEC_H264, CODEC_H264 | CODEC_HEVC, RungLoss::Shape), + LastRungVerdict::Retry { caps: CODEC_HEVC } + ); + // Same inputs, the OTHER diagnosis: hardware H.264 exhausted and the CPU rung + // has no H.264 at all (impossible in this build, but the rule must not depend on + // that) — then HEVC really is the same losing bet and the session ends. + assert_eq!( + last_rung_verdict(CODEC_H264, CODEC_H264 | CODEC_HEVC, RungLoss::Codec), + LastRungVerdict::Dead + ); + // The user's PyroWave opt-in survives a shape refusal — but never ALONE: the + // host's `resolve_codec` keeps PyroWave out of its precedence ladder, so a Hello + // offering nothing else resolves to no codec and the host refuses the session. + assert_eq!( + last_rung_verdict( + CODEC_H264, + CODEC_H264 | CODEC_HEVC | CODEC_PYROWAVE, + RungLoss::Shape + ), + LastRungVerdict::Retry { + caps: CODEC_HEVC | CODEC_PYROWAVE + } + ); + assert_eq!( + last_rung_verdict(CODEC_H264, CODEC_H264 | CODEC_PYROWAVE, RungLoss::Shape), + LastRungVerdict::Dead + ); + // And a shape refusal still never re-offers the codec that raised it — the codec + // is fixed at Welcome, so it is the only lever there is. + for advertised in 0u8..16 { + for negotiated in [CODEC_H264, CODEC_HEVC, CODEC_AV1] { + if let LastRungVerdict::Retry { caps } = + last_rung_verdict(negotiated, advertised, RungLoss::Shape) + { + assert_eq!(caps & negotiated, 0, "{negotiated:#x} re-offered"); + assert_ne!(caps, 0, "Retry must carry something to advertise"); + } + } + } + } + + /// The one HEVC promise the client can refuse to make BEFORE the Hello: decode + /// pinned to software has no HEVC rung at any level, so advertising it guarantees + /// the reconnect flow rather than risking it. + #[test] + fn a_software_pin_takes_hevc_off_the_advertisement() { + // The pin is read the way `Decoder::new` reads it: env first, then the setting — + // so a run with the override actually set has nothing here to assert about. + if std::env::var_os("PUNKTFUNK_DECODER").is_some() { + return; + } + assert!(decode_pinned_to_software("software")); + assert!(!decode_pinned_to_software("auto")); + assert!(!decode_pinned_to_software("vulkan")); + assert!(!decode_pinned_to_software("")); + } + + /// The wire↔FFmpeg codec map must round-trip for every codec the software rung can + /// be built for. A mistake here builds an openh264 decoder for an AV1 session — which + /// then fails per AU rather than at construction, i.e. exactly the mid-stream burn + /// this ladder is written to avoid. + #[test] + fn the_wire_codec_of_an_ffmpeg_id_round_trips() { + for wire in [CODEC_H264, CODEC_HEVC, CODEC_AV1] { + assert_eq!(wire_codec_of(ffmpeg_codec_id(wire)), wire); + } + // PyroWave has no FFmpeg id (`ffmpeg_codec_id` folds it onto HEVC), so the + // inverse cannot round-trip it — the PyroWave decoder sets `wire_codec` itself. + assert_eq!(wire_codec_of(ffmpeg_codec_id(CODEC_PYROWAVE)), CODEC_HEVC); + } + + /// `CpuPlanarFrame` is what the presenter uploads with no stride: prove the copy + /// really does undo the decoder's padding, and that a short plane is REFUSED rather + /// than read past. + #[test] + fn planar_frames_are_tightly_packed_and_short_planes_are_refused() { + let color = ColorDesc { + primaries: 1, + transfer: 1, + matrix: 1, + full_range: false, + }; + // 4x2 luma, 2x1 chroma, all planes padded by 3 bytes per row. + let y: Vec = vec![1, 2, 3, 4, 9, 9, 9, 5, 6, 7, 8, 9, 9, 9]; + let u: Vec = vec![10, 11, 9, 9, 9]; + let v: Vec = vec![20, 21, 9, 9, 9]; + let none = punktfunk_core::reanchor::LocalRecovery::NONE; + let f = + CpuPlanarFrame::from_i420(4, 2, [&y, &u, &v], [7, 5, 5], color, true, none).unwrap(); + assert_eq!(f.plane(0), &[1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(f.plane(1), &[10, 11]); + assert_eq!(f.plane(2), &[20, 21]); + assert_eq!(f.plane_dims(0), (4, 2)); + assert_eq!(f.plane_dims(1), (2, 1)); + // Odd dimensions round the chroma plane UP — the last column/row still has a + // chroma sample and dropping it would read past the plane on the next frame. + assert_eq!(CpuPlanarFrame::chroma_dims(5, 3), (3, 2)); + // A plane shorter than its own geometry is a disagreement with the decoder, not + // something to truncate into a plausible picture. + let short: Vec = vec![1, 2, 3]; + assert!( + CpuPlanarFrame::from_i420(4, 2, [&short, &u, &v], [7, 5, 5], color, true, none) + .is_err() + ); + // A stride narrower than the picture is the same class of disagreement. + assert!( + CpuPlanarFrame::from_i420(4, 2, [&y, &u, &v], [2, 5, 5], color, true, none).is_err() + ); + } fn decode_device(vendor_id: u32, device_name: &str) -> VulkanDecodeDevice { VulkanDecodeDevice { diff --git a/crates/pf-client-core/src/video_color.rs b/crates/pf-client-core/src/video_color.rs index 87be7439..fec62941 100644 --- a/crates/pf-client-core/src/video_color.rs +++ b/crates/pf-client-core/src/video_color.rs @@ -55,7 +55,9 @@ impl ColorDesc { /// `65535/65472` recovers exact `code/1023`. pub fn csc_rows(desc: ColorDesc, depth: u8, msb_packed: bool) -> [[f32; 4]; 3] { // BT.601 (5/6), BT.2020 (9/10); everything else — incl. unspecified — is the host's - // BT.709 SDR default (mirrors the software path's swscale coefficient choice). + // BT.709 SDR default. Since M8 this is the ONLY coefficient choice in the client: + // the software rung's swscale (which defaulted to BT.601 and needed correcting) is + // gone, and its planes come through this function like every hardware lane's. let (kr, kb) = match desc.matrix { 5 | 6 => (0.299, 0.114), 9 | 10 => (0.2627, 0.0593), diff --git a/crates/pf-client-core/src/video_software.rs b/crates/pf-client-core/src/video_software.rs index e57bbb4a..ed8856b5 100644 --- a/crates/pf-client-core/src/video_software.rs +++ b/crates/pf-client-core/src/video_software.rs @@ -1,224 +1,818 @@ -//! CPU/libavcodec software decode backend (swscale → RGBA). +//! The CPU rung — the ladder's LAST one, and (M8) the first one with no FFmpeg in it. +//! +//! * **H.264 → openh264** (BSD-2). Already a workspace dependency: the host's GPU-less +//! encoder is the same library ([`pf-encode`'s `enc/sw.rs`]), so the licence posture and +//! the statically-bundled build were settled before this rung existed. +//! * **AV1 → rav1d** (BSD-2) — dav1d, ported to Rust. Picking it over the `dav1d` FFI +//! crate is a packaging decision, argued in `Cargo.toml`; picking it over *nothing* is +//! the plan's ("dav1d SW is the safety net"). Two properties come free with it: +//! there is no `avcodec_find_decoder(AV1)` to hand us libdav1d behind a +//! `hw_device_ctx` it silently ignores, and no C decoder in the process at all. +//! * **HEVC → dropped.** No permissively licensed software HEVC decoder exists (libde265 +//! is LGPL, which defeats the point of the excision). This rung REFUSES an HEVC +//! session with a typed [`NoSoftwareRung`], which is what the session layer turns into +//! a reconnect that advertises HEVC-less decode caps — see +//! [`crate::video::last_rung_verdict`]. Narrowing instead (limping on at 5 fps, or +//! freezing) is the failure mode this whole program exists to end. +//! +//! **Output is PLANES, not RGBA.** The decoder hands the presenter tightly-packed I420 +//! and the presenter's existing planar CSC shader does the colour, which deletes two +//! things at once: swscale's per-frame YUV→RGBA pass, and swscale's BT.601 default — +//! the footgun the old `convert_rgba` carried ~30 lines of correction code for. +//! +//! **Colour comes from pf-bitstream, not from the decoder.** openh264 reports no VUI at +//! all and rav1d reports its own sequence header, so a rung that trusted its decoder +//! would have two colour implementations to keep in step with the four hardware rungs' +//! one. Instead the H.264 leg plans every AU with [`H264Planner`] — the SAME planner +//! `pf-vkdecode`/`pf-dxvadec`/`pf-vaadec` submit from — and reads +//! `plan.picture.colour`. The signalled matrix/range therefore cannot differ between the +//! software rung and the hardware rungs, because it is literally the same code reading +//! the same SPS. The H.264 leg takes the recovery point SEI from the same plan, through +//! `pf-vkdecode`'s own [`RecoveryWatch`], so an intra-refresh session re-anchors here on +//! the same rule the native rung uses. +//! +//! **The picture envelope is checked BEFORE the decoder sees the AU, on both legs.** +//! 8-bit 4:2:0 only: openh264 has no wider support at all and rav1d is compiled +//! `bitdepth_8` here. H.264 reads it off the SPS the planner activated; AV1 reads it off +//! the sequence header with `dav1d_parse_sequence_header`. Both raise the SAME typed +//! [`NoSoftwareRung`] so the session reconnects. Letting the DECODER answer instead is +//! what the M8 review caught: rav1d refuses a 10-bit frame with `ENOPROTOOPT`, the pump +//! reads a generic error as survivable, and a Main 10 HDR stream — which is what hardware +//! AV1 sessions are — freezes forever, one keyframe request per identical AU. +//! +//! Threading: openh264's `num_threads` is documented upstream as "will probably just +//! segfault", so this stays single-threaded — the old FFmpeg rung's slice threading has +//! no equivalent here. rav1d gets the machine's cores: `max_frame_delay = 1` is the knob +//! that removes frame delay (dav1d's `get_num_threads` then computes `n_fc = min(1, n_tc)`, +//! so exactly one frame is ever in flight whatever `n_threads` says), and `n_threads` +//! drives the INTRA-frame tile/row workers, which cost no latency at all. Pinning it to 1 +//! bought nothing and gave the rung reached only because the GPU already failed a single +//! core to decode 4K with. -use crate::video::{averr, CpuFrame}; +use crate::video::{CpuPlanarFrame, RungLoss}; use crate::video_color::ColorDesc; -use anyhow::{anyhow, Context as _, Result}; -use ffmpeg::format::Pixel; -use ffmpeg::software::scaling; -use ffmpeg::util::frame::Video as AvFrame; -use ffmpeg_next as ffmpeg; -use std::ptr; +use anyhow::{anyhow, bail, Context as _, Result}; +use pf_bitstream::h264::{H264Planner, PlanError}; +use pf_vkdecode::RecoveryWatch; + +/// The codecs this rung can decode at all. Deliberately its own enum rather than an +/// `ffmpeg::codec::Id`: the whole point of M8 is that nothing in here speaks FFmpeg, and +/// the ladder above still does only because its other rungs are not swapped yet (M10). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum SwCodec { + H264, + Av1, +} + +impl SwCodec { + /// The wire codec bit this rung can serve, or `None` — the one place the + /// "which codecs does software cover" question is answered. + pub(crate) fn for_wire(codec: u8) -> Option { + match codec { + punktfunk_core::quic::CODEC_H264 => Some(SwCodec::H264), + punktfunk_core::quic::CODEC_AV1 => Some(SwCodec::Av1), + _ => None, + } + } +} + +/// This build has no software decoder for the session's stream — the ladder has run out +/// of rungs. +/// +/// A distinct type, not a formatted string, because the SESSION layer must be able to +/// tell this apart from every other decode failure: everything else is survivable (feed +/// the next AU, ask for an IDR), and this one is not survivable at all — it can only be +/// answered by reconnecting with something this client can actually decode. It rides out +/// through `anyhow` and is recovered with `downcast_ref`, so no signature in the ladder +/// changes shape for it. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NoSoftwareRung { + /// The `quic::CODEC_*` bit of the session that has no CPU rung. + pub codec: u8, + /// `None` — the CODEC itself has no CPU decoder (HEVC). `Some(what)` — the codec + /// does, but not for THIS stream's picture shape (10-bit, 4:4:4). + /// + /// The two are one type on purpose. They are different diagnoses but the SAME + /// available action: the codec is fixed at Welcome, so a shape this rung cannot + /// decode can only be escaped the way a codec it cannot decode is — a reconnect that + /// takes the codec off the table, after which the host resolves a new shape too. A + /// blunt instrument for the shape case, and the only one the wire offers. + /// + /// The shape case cannot be answered at construction alone: a Windows HDR desktop + /// flips to Main 10 IN-BAND with a new parameter set, so the Welcome's + /// [`crate::video::StreamFormat`] can say 8-bit for a session that becomes 10-bit + /// mid-stream. That is why this is raised from the per-AU path, off the bitstream's + /// own headers, rather than from a negotiated field. + pub shape: Option<&'static str>, +} + +impl NoSoftwareRung { + /// Which diagnosis this is, for the reconnect rule + /// ([`last_rung_verdict`](crate::video::last_rung_verdict)). The two answers differ: + /// a missing CODEC means every hardware rung already failed, a missing SHAPE means + /// none of them was even asked. + pub fn loss(&self) -> RungLoss { + match self.shape { + None => RungLoss::Codec, + Some(_) => RungLoss::Shape, + } + } +} + +impl std::fmt::Display for NoSoftwareRung { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let codec = crate::video::wire_codec_name(self.codec); + match self.shape { + None => write!( + f, + "no software decoder for {codec} — this build decodes H.264 and AV1 on \ + the CPU (there is no permissively licensed software HEVC decoder)" + ), + Some(shape) => write!( + f, + "the software {codec} decoder cannot decode this stream: {shape} \ + (the CPU rung is 8-bit 4:2:0 only)" + ), + } + } +} + +impl std::error::Error for NoSoftwareRung {} // --- software backend --------------------------------------------------------------- pub(crate) struct SoftwareDecoder { - decoder: ffmpeg::decoder::Video, - /// Rebuilt whenever the decoded format/size — or the colour signaling (a mid-stream - /// SDR↔HDR flip) — changes. - sws: Option<(scaling::Context, Pixel, u32, u32, ColorDesc)>, + inner: Inner, + /// Last colour signalling the stream actually stated. Held across AUs the metadata + /// parser could not read (see [`H264Software::colour_of`]) so a stream never silently + /// reverts to the SDR default mid-session; seeded with that default, which is what + /// "unspecified" resolves to anyway (`csc_rows`). + color: ColorDesc, +} + +enum Inner { + H264(H264Software), + Av1(Av1Software), } impl SoftwareDecoder { - pub(crate) fn new(codec_id: ffmpeg::codec::Id) -> Result { - let codec = ffmpeg::decoder::find(codec_id) - .ok_or_else(|| anyhow!("no {codec_id:?} decoder in libavcodec"))?; - let mut ctx = ffmpeg::codec::Context::new_with_codec(codec); - // SAFETY: `as_mut_ptr` yields the `AVCodecContext` behind the `ctx` allocated on the line - // above, which outlives these writes; each store is an in-bounds scalar field write on that - // live context, made before the decoder is opened and reads them. - unsafe { - let raw = ctx.as_mut_ptr(); - (*raw).flags |= ffmpeg::ffi::AV_CODEC_FLAG_LOW_DELAY as i32; - // Slice threading adds no frame delay (frame threading adds thread_count-1). - (*raw).thread_type = ffmpeg::ffi::FF_THREAD_SLICE; - (*raw).thread_count = 0; // auto - } - let decoder = ctx.decoder().video().context("open video decoder")?; - // Every construction site (session open, preference, mid-stream demotion) says - // which decoder actually opened: for AV1 the ID lookup means libdav1d here — - // deliberately (fastest CPU path; the native `av1` decoder has no software - // path at all) — and the name in the log is what keeps that distinguishable - // from the hardware lanes' capability-selected decoders. - tracing::info!(?codec_id, decoder = codec.name(), "software decoder opened"); - Ok(SoftwareDecoder { decoder, sws: None }) + /// Build the CPU rung for a WIRE codec bit. + /// + /// `Err` carrying a [`NoSoftwareRung`] means "there is no such rung", not "the rung + /// failed to start" — the two are different questions for the caller and must not + /// collapse into one string. + pub(crate) fn new(codec: u8) -> Result { + let Some(sw) = SwCodec::for_wire(codec) else { + return Err(NoSoftwareRung { codec, shape: None }.into()); + }; + let inner = match sw { + SwCodec::H264 => Inner::H264(H264Software::new()?), + SwCodec::Av1 => Inner::Av1(Av1Software::new()?), + }; + tracing::info!( + codec = crate::video::wire_codec_name(codec), + decoder = match sw { + SwCodec::H264 => "openh264", + SwCodec::Av1 => "rav1d", + }, + "software decoder opened (CPU, planar output)" + ); + Ok(SoftwareDecoder { + inner, + // "Unspecified" everywhere: `csc_rows` resolves that to BT.709 limited, the + // host's SDR default, which is also what E.2.1 inference produces for a + // stream whose VUI is silent. + color: ColorDesc { + primaries: 2, + transfer: 2, + matrix: 2, + full_range: false, + }, + }) } - pub(crate) fn decode(&mut self, au: &[u8]) -> Result> { - let packet = ffmpeg::Packet::copy(au); - self.decoder - .send_packet(&packet) - .map_err(|e| anyhow!("send_packet: {e}"))?; - let mut frame = AvFrame::empty(); - let mut out = None; - while self.decoder.receive_frame(&mut frame).is_ok() { - out = Some(self.convert_rgba(&frame)?); + pub(crate) fn decode(&mut self, au: &[u8]) -> Result> { + match &mut self.inner { + Inner::H264(h) => h.decode(au, &mut self.color), + Inner::Av1(a) => a.decode(au, &mut self.color), + } + } +} + +// --- H.264 (openh264) ---------------------------------------------------------------- + +struct H264Software { + decoder: openh264::decoder::Decoder, + /// The metadata half: colour signalling, the IDR flag and the display crop, from the + /// same planner every hardware rung submits from. It does NOT drive openh264 — + /// openh264 owns its own parsing — so a plan the narrow envelope refuses costs + /// metadata for that AU, never the picture. + /// + /// Boxed: the planner's DPB dwarfs everything else here, and `Backend` (which holds + /// this by value) is an enum whose other variants are pointer-sized — the same reason + /// the native rungs are boxed there. + planner: Box, + /// The recovery point SEI, folded per picture by the SAME rule the native Vulkan rung + /// uses (`pf-vkdecode`'s watch, unchanged and shared): an intra-refresh session never + /// emits an IDR, so without this the pump's post-loss freeze on THIS rung waits out + /// its 500 ms backstop and then forces the very IDR the wave exists to avoid. + recovery: RecoveryWatch, + /// One warn per session for a stream whose AUs will not plan: the picture is fine + /// (openh264 decodes it), but colour is then whatever the last plannable AU said, + /// and a support engineer must be able to see that from the log rather than infer it + /// from a hue. + plan_warned: bool, +} + +/// Everything the planner tells the software rung about the AU it is ABOUT to submit. +struct AuFacts { + is_idr: bool, + /// `None` = the AU did not plan; the caller keeps the last colour it saw. + color: Option, + recovery: punktfunk_core::reanchor::LocalRecovery, +} + +impl H264Software { + fn new() -> Result { + // Default config: error concealment OFF, logging quiet, one thread. Concealment + // is deliberately not enabled — this rung's contract is that its errors SURFACE + // (the pump turns an `Err` into a keyframe request through the same throttle as + // every other rung), and a decoder quietly inventing macroblocks is precisely + // the "looked clean, wasn't" shape M4's telemetry exists to make impossible. + let decoder = + openh264::decoder::Decoder::new().map_err(|e| anyhow!("openh264 decoder: {e}"))?; + Ok(H264Software { + decoder, + planner: Box::new(H264Planner::new()), + recovery: RecoveryWatch::new(), + plan_warned: false, + }) + } + + fn decode(&mut self, au: &[u8], color: &mut ColorDesc) -> Result> { + // Plan FIRST: the plan describes the AU we are about to decode, and reading it + // after would attribute this picture's colour to the next one on a decoder that + // buffers. + let facts = self.plan_facts(au)?; + if let Some(c) = facts.color { + *color = c; + } + let picture = self + .decoder + .decode(au) + .map_err(|e| anyhow!("openh264 decode: {e}"))?; + let Some(yuv) = picture else { + return Ok(None); + }; + use openh264::formats::YUVSource as _; + let (w, h) = yuv.dimensions(); + let (sy, su, sv) = yuv.strides(); + let frame = CpuPlanarFrame::from_i420( + w as u32, + h as u32, + [yuv.y(), yuv.u(), yuv.v()], + [sy, su, sv], + *color, + facts.is_idr, + facts.recovery, + )?; + Ok(Some(frame)) + } + + /// The IDR flag, the colour and the recovery mark for this AU, from the shared + /// planner. + /// + /// `colour` is `None` when the AU could not be planned — which is NORMAL for the + /// first AUs after a mid-session demotion onto this rung: the parameter sets arrive + /// in-band on the next IDR (which the demotion has already requested), so until it + /// lands the planner has no active SPS and says so. Answering `is_idr = false` there + /// is the conservative direction: it costs the re-anchor gate one frame of patience, + /// where a false `true` would lift a post-loss freeze onto a picture that is still + /// concealed — and the recovery mark is empty for the same reason. + /// + /// `Err` is reserved for the ONE thing that is not a metadata problem: a picture + /// shape this rung cannot decode. It travels as [`NoSoftwareRung`] so the session + /// reconnects instead of erroring per AU forever — see the type's `shape` field for + /// why that answer has to come from here rather than from the Welcome. + fn plan_facts(&mut self, au: &[u8]) -> Result { + match self.planner.plan_au(au) { + Ok(plan) => { + // The envelope, read from the SPS the planner activated for THIS picture + // — so an in-band flip to Main 10 (a Windows HDR desktop) is caught on + // the AU that carries it, not left to openh264 to fail on repeatedly. + if let Some(shape) = unsupported_shape( + plan.picture.chroma_format_idc, + plan.picture.bit_depth_luma_minus8, + ) { + return Err(NoSoftwareRung { + codec: punktfunk_core::quic::CODEC_H264, + shape: Some(shape), + } + .into()); + } + let c = plan.picture.colour; + // The wave's own verdict for this picture. Folded even when openh264 + // then produces nothing: the watch counts `frame_num` increments, so + // skipping a picture would leave the count owing forever. Losing the + // MARK of a picture that never came out only makes the lift late, which + // is the safe direction. + let mark = self.recovery.note_h264( + plan.picture.frame_num, + plan.picture.is_idr, + plan.picture.recovery_point, + ); + Ok(AuFacts { + is_idr: plan.picture.is_idr, + color: Some(ColorDesc { + primaries: c.colour_primaries, + transfer: c.transfer_characteristics, + matrix: c.matrix_coefficients, + full_range: c.video_full_range, + }), + recovery: punktfunk_core::reanchor::LocalRecovery { + sei_here: mark.sei_here, + is_recovery_point: mark.is_recovery_point, + }, + }) + } + Err(e) => { + // `NoActiveParamSet` before the first in-band IDR is expected and says + // nothing; anything else means the stream is outside the envelope the + // hardware rungs plan from, which is worth exactly one line. + if !matches!(e, PlanError::NoActiveParamSet { .. }) && !self.plan_warned { + self.plan_warned = true; + tracing::warn!( + error = %e, + "software rung: AU did not plan — colour signalling and the \ + keyframe flag now follow the last AU that did" + ); + } + Ok(AuFacts { + is_idr: false, + color: None, + recovery: punktfunk_core::reanchor::LocalRecovery::NONE, + }) + } + } + } +} + +/// The CPU rung's picture envelope: 8-bit 4:2:0 and nothing else. `Some(what)` names what +/// falls outside it, for [`NoSoftwareRung::shape`]. +/// +/// Stated once and shared by both legs. Neither decoder is BUILT for anything wider — +/// openh264 has no 4:2:2/4:4:4 or high-bit-depth support at all, and rav1d is compiled +/// here with `bitdepth_8` only — so this is a refusal that reflects the build, not a +/// policy that could drift from it. +fn unsupported_shape(chroma_format_idc: u8, bit_depth_minus8: u8) -> Option<&'static str> { + if bit_depth_minus8 != 0 { + return Some("10-bit or deeper"); + } + if chroma_format_idc != punktfunk_core::quic::CHROMA_IDC_420 { + return Some("chroma other than 4:2:0"); + } + None +} + +// --- AV1 (rav1d) ---------------------------------------------------------------------- + +// rav1d ships dav1d's C ABI as `#[no_mangle] extern "C"` Rust functions over `#[repr(C)]` +// types — there is no linker and no `.so` in sight, but the calling contract is still +// dav1d's, so the FFI discipline below is dav1d's too: every context/picture is owned by +// exactly one value here, and `Drop` closes it exactly once. +use rav1d::include::dav1d::data::Dav1dData; +use rav1d::include::dav1d::dav1d::{Dav1dContext, Dav1dSettings}; +use rav1d::include::dav1d::headers::{Dav1dSequenceHeader, DAV1D_PIXEL_LAYOUT_I420}; +use rav1d::include::dav1d::picture::Dav1dPicture; +use rav1d::src::lib::{ + dav1d_close, dav1d_data_create, dav1d_data_unref, dav1d_default_settings, dav1d_get_picture, + dav1d_open, dav1d_parse_sequence_header, dav1d_picture_unref, dav1d_send_data, +}; +use std::ptr::NonNull; + +struct Av1Software { + /// `None` only between `Drop` taking it and the close returning — every other + /// observer sees a live context. + ctx: Option, +} + +/// An owned `Dav1dData`, unref'd exactly once on drop. +/// +/// The same shape (and the same lesson) as the FFmpeg rungs' `AvBuffer`: the send loop +/// below has several fallible exits between allocating the buffer and dav1d taking its +/// reference, and hand-unref'ing on each one is how a leak per failed AU gets written. +/// dav1d zeroes the struct when it takes the reference, so an already-consumed `Dav1dData` +/// drops to a no-op and the double-unref this type prevents cannot happen either. +struct Av1Data(Dav1dData); + +impl Av1Data { + fn create(au: &[u8]) -> Result { + let mut data = Dav1dData::default(); + // SAFETY: `data` is a live local; `dav1d_data_create` either writes an allocated + // buffer of `au.len()` bytes into it and returns its start, or returns null. + let buf = unsafe { dav1d_data_create(NonNull::new(&mut data as *mut Dav1dData), au.len()) }; + if buf.is_null() { + bail!("rav1d: could not allocate {} bytes for an AU", au.len()); + } + // SAFETY: `buf` is the start of the `au.len()`-byte allocation just returned, and + // `au` is a distinct live slice of exactly that length. + unsafe { std::ptr::copy_nonoverlapping(au.as_ptr(), buf, au.len()) }; + Ok(Av1Data(data)) + } +} + +impl Drop for Av1Data { + fn drop(&mut self) { + // SAFETY: `self.0` is a live `Dav1dData` this value solely owns (no `Clone`, and + // `Drop` runs once). `dav1d_data_unref` releases whatever reference is left — none + // when a successful `dav1d_send_data` already took it — and rewrites the struct. + unsafe { dav1d_data_unref(NonNull::new(&mut self.0)) }; + } +} + +// SAFETY: `Dav1dContext` is a refcounted handle dav1d documents as usable from one +// thread at a time; this type owns it exclusively (no `Clone`, no `Sync`) and it lives +// on the pump thread with the rest of the decoder — the same promise every other backend +// in this crate makes for its device handles. +unsafe impl Send for Av1Software {} + +impl Av1Software { + fn new() -> Result { + let mut settings = std::mem::MaybeUninit::::uninit(); + // SAFETY: `dav1d_default_settings` fully initializes the `Dav1dSettings` behind + // the pointer it is given; the storage is a live local that outlives the call. + let mut settings = unsafe { + dav1d_default_settings(NonNull::new_unchecked(settings.as_mut_ptr())); + settings.assume_init() + }; + // No frame delay: a punktfunk stream is zero-reorder and real-time, so the + // throughput a FRAME-threaded decoder buys costs exactly the latency this client + // spends the rest of its budget defending. `max_frame_delay = 1` is the knob that + // says so — dav1d's `get_num_threads` derives `n_fc = min(max_frame_delay, n_tc)`, + // so one frame stays in flight no matter how many threads exist. Same reasoning + // as the old FFmpeg rung's `FF_THREAD_SLICE` + `AV_CODEC_FLAG_LOW_DELAY`, and + // `n_threads` is that rung's SLICE half: intra-frame tile/row workers, which add + // no delay. Capped at 8 — this is the rung reached because the GPU already + // failed, and it should not also take the machine over. + settings.max_frame_delay = 1; + settings.n_threads = std::thread::available_parallelism() + .map(|n| n.get().clamp(1, 8)) + .unwrap_or(1) as i32; + // Film grain synthesis is a post-process the hosts never signal and nobody can + // afford on the rung that exists because the GPU already failed. + settings.apply_grain = 0; + let mut ctx: Option = None; + // SAFETY: both pointers are live locals for the duration of the call, which is + // dav1d_open's whole contract: it reads `settings` and writes the context out. + let r = unsafe { + dav1d_open( + NonNull::new(&mut ctx as *mut Option), + NonNull::new(&mut settings as *mut Dav1dSettings), + ) + }; + if r.0 < 0 || ctx.is_none() { + bail!("rav1d (dav1d) decoder open failed: {}", r.0); + } + Ok(Av1Software { ctx }) + } + + fn decode(&mut self, au: &[u8], color: &mut ColorDesc) -> Result> { + let ctx = self.ctx.context("rav1d context closed")?; + if au.is_empty() { + return Ok(None); + } + // The envelope, off the BITSTREAM's own sequence header, before a byte reaches + // the decoder — exactly what the H.264 leg does with `plan_au`, and for the same + // reason. rav1d is compiled `bitdepth_8` only, so a 10-bit frame makes + // `rav1d_submit_frame` refuse with `ENOPROTOOPT`; that refusal is a per-AU error + // the pump would answer with a keyframe request forever, on a stream where every + // following AU is identically 10-bit. This is the shipping case, not a corner: + // AV1 is advertised only where hardware AV1 exists, hardware AV1 + HDR is Main 10, + // and a mid-session hardware failure demotes here. + if let Some(shape) = self.unsupported_sequence(au) { + return Err(NoSoftwareRung { + codec: punktfunk_core::quic::CODEC_AV1, + shape: Some(shape), + } + .into()); + } + // A `Dav1dData` that owns its own copy: `dav1d_data_create` allocates, we fill + // it, and `dav1d_send_data` takes the reference on success. Deliberately not + // `dav1d_data_wrap` over the caller's `au` — that would hand the decoder a + // borrow of a buffer the pump reuses on the next AU. + let mut data = Av1Data::create(au)?; + // dav1d consumes `data` incrementally: a partial send leaves bytes in it and asks + // to be re-sent. A punktfunk AU is one temporal unit and the decoder is drained + // every call, so the loop is bounded by the AU — but it is a LOOP, because + // `EAGAIN` here means "take pictures out first", not "the AU is bad". + // + // Only the NEWEST picture survives, which matches every other backend's + // `decode -> Option` contract (the old libav rung's `while receive_frame` + // did the same). It matters more here than elsewhere because an AV1 temporal unit + // really can carry several shown frames — but this is the rung reached after the + // hardware already failed, and showing the newest is the same answer the pump's + // newest-wins frame queue would give a moment later anyway. + let mut out: Option = None; + loop { + // SAFETY: `ctx` is the live context from `dav1d_open` (not yet closed) and + // `data.0` is a live local dav1d is allowed to read from and write to. Its + // reference is taken by dav1d on success; the guard's `Drop` releases only + // what is left. + let r = unsafe { dav1d_send_data(Some(ctx), NonNull::new(&mut data.0)) }; + let sent = r.0 >= 0; + if !sent && dav1d_errno(r) != Some(libc::EAGAIN) { + // A shape the build cannot decode reaches here only if it slipped past + // the sequence-header check above (an AU whose OBUs carry no sequence + // header of their own). Still typed rather than generic: the pump's + // survivable branch would ask for a keyframe and get the same refusal on + // every AU for the rest of the session — a permanent freeze with no + // fallback, which is the one outcome this rung exists to end. + if dav1d_errno(r) == Some(libc::ENOPROTOOPT) { + return Err(NoSoftwareRung { + codec: punktfunk_core::quic::CODEC_AV1, + shape: Some("10-bit or deeper"), + } + .into()); + } + bail!("rav1d send_data: {}", r.0); + } + match self.take_picture(ctx, color)? { + Some(f) => out = Some(f), + // Nothing more to take and the AU is fully consumed — done. + None if sent && data.0.sz == 0 => break, + // Nothing to take and the decoder still would not accept the rest: it + // has neither produced nor consumed, which is a wedge, not back-pressure. + None if !sent => bail!("rav1d: decoder accepted no data and produced no picture"), + None => {} + } } Ok(out) } - fn convert_rgba(&mut self, frame: &AvFrame) -> Result { - let (fmt, w, h) = (frame.format(), frame.width(), frame.height()); - // SAFETY: `frame.as_ptr()` is the decoder-owned live AVFrame for this call. - let color = unsafe { ColorDesc::from_raw(frame.as_ptr()) }; - let rebuild = !matches!(&self.sws, - Some((_, f, sw, sh, c)) if *f == fmt && *sw == w && *sh == h && *c == color); - if rebuild { - let mut ctx = - scaling::Context::get(fmt, w, h, Pixel::RGBA, w, h, scaling::Flags::POINT) - .context("swscale context")?; - // swscale defaults to BT.601 coefficients — set them from the FRAME's signaling - // (unspecified → BT.709 limited, the host's SDR default; a Windows HDR desktop - // streams BT.2020 in-band). Without this, YUV→RGB decodes with the wrong matrix - // and colours shift. Destination = full-range RGB; the transfer function stays - // baked in (the presenter tags PQ textures so GTK applies the EOTF). - const SWS_CS_ITU709: i32 = 1; - const SWS_CS_ITU601: i32 = 5; - const SWS_CS_BT2020: i32 = 9; - let cs = match color.matrix { - 9 | 10 => SWS_CS_BT2020, - 5 | 6 => SWS_CS_ITU601, - _ => SWS_CS_ITU709, - }; - // SAFETY: `sws_getCoefficients` returns a pointer into libav's own static coefficient - // tables — valid for the process, read-only — and `sws_setColorspaceDetails` takes it - // plus the live `SwsContext` behind `ctx` and plain scalars. - unsafe { - let coeffs = ffmpeg::ffi::sws_getCoefficients(cs); - ffmpeg::ffi::sws_setColorspaceDetails( - ctx.as_mut_ptr(), - coeffs, // inv_table: source (YUV) coefficients per the VUI - color.full_range as i32, // srcRange: 0 = limited/studio (MPEG) - coeffs, // table: destination coefficients (ignored for RGB output) - 1, // dstRange: 1 = full-range RGB - 0, - 1 << 16, - 1 << 16, // brightness, contrast, saturation (defaults) - ); - } - self.sws = Some((ctx, fmt, w, h, color)); - } - let (sws, ..) = self.sws.as_mut().unwrap(); - // Single-pass conversion: swscale writes straight into the Vec the texture will - // wrap. (The old path scaled into a scratch AVFrame and then copied `data(0)` out - // — a second full-frame pass per frame.) 64-byte row alignment keeps swscale on - // aligned SIMD stores; `GdkMemoryTexture` takes the resulting stride explicitly. - const ALIGN: i32 = 64; - use ffmpeg::ffi; - let dst_fmt = ffi::AVPixelFormat::AV_PIX_FMT_RGBA; - // SAFETY: pure size computation from format/dimensions; no pointers involved. - let size = unsafe { ffi::av_image_get_buffer_size(dst_fmt, w as i32, h as i32, ALIGN) }; - if size < 0 { - return Err(averr("av_image_get_buffer_size", size)); - } - let rgba = vec![0u8; size as usize]; - let mut dst_data: [*mut u8; 4] = [ptr::null_mut(); 4]; - let mut dst_linesize: [i32; 4] = [0; 4]; - // SAFETY: fill_arrays only derives plane pointers/strides into `rgba` (sized by - // av_image_get_buffer_size above, same format/align) — no allocation, no - // ownership transfer; `rgba` outlives the scale below. + /// This AU's sequence header against the build's envelope: `Some(what)` names what + /// falls outside it, `None` means "8-bit 4:2:0, or this AU carries no sequence header + /// of its own". + /// + /// An AU without one is the AV1 twin of the H.264 leg's `NoActiveParamSet`: it says + /// nothing, so it decodes against whatever sequence the decoder already holds — which + /// a previous AU was checked for. Punktfunk hosts re-send the sequence header on every + /// key frame, and the demotion onto this rung asks for one immediately, so the first + /// AU this rung ever decodes carries one. + fn unsupported_sequence(&self, au: &[u8]) -> Option<&'static str> { + let mut seq = std::mem::MaybeUninit::::uninit(); + // SAFETY: `out` is a live local this call either fully writes or leaves untouched + // (it writes only on success), and `au` is a live slice of exactly `au.len()` + // bytes. Nothing is allocated or referenced: dav1d fills the struct by value. let r = unsafe { - ffi::av_image_fill_arrays( - dst_data.as_mut_ptr(), - dst_linesize.as_mut_ptr(), - rgba.as_ptr(), - dst_fmt, - w as i32, - h as i32, - ALIGN, + dav1d_parse_sequence_header( + NonNull::new(seq.as_mut_ptr()), + NonNull::new(au.as_ptr().cast_mut()), + au.len(), ) }; - if r < 0 { - return Err(averr("av_image_fill_arrays", r)); + if r.0 < 0 { + return None; // no sequence header here (ENOENT), or an AU we cannot read } - // SAFETY: src pointers/strides belong to the decoder-owned `frame` (alive for the - // call); dst pointers were just filled over `rgba`, and sws_scale writes rows - // [0, h) only — exactly the buffer fill_arrays sized. - let r = unsafe { - ffi::sws_scale( - sws.as_mut_ptr(), - (*frame.as_ptr()).data.as_ptr() as *const *const u8, - (*frame.as_ptr()).linesize.as_ptr(), - 0, - h as i32, - dst_data.as_ptr(), - dst_linesize.as_ptr(), - ) - }; - if r < 0 { - return Err(averr("sws_scale", r)); + // SAFETY: the call returned success, which is its contract for having written + // the whole `Dav1dSequenceHeader`. + let seq = unsafe { seq.assume_init() }; + if seq.hbd != 0 { + return Some("10-bit or deeper"); } - Ok(CpuFrame { - width: w, - height: h, - stride: dst_linesize[0] as usize, - rgba, - color, - // `is_key()` reads the same intra flag `frame_is_keyframe` derives from pict_type - // for the hardware paths; ffmpeg-next handles the FFmpeg-version binding split. - keyframe: frame.is_key(), - }) + if seq.layout != DAV1D_PIXEL_LAYOUT_I420 { + return Some("chroma other than 4:2:0"); + } + None } + + /// One picture out of the decoder, converted. `None` = nothing ready yet. + fn take_picture( + &self, + ctx: Dav1dContext, + color: &mut ColorDesc, + ) -> Result> { + let mut pic = Dav1dPicture::default(); + // SAFETY: `ctx` is live and `pic` is a live local dav1d writes the picture into. + let r = + unsafe { dav1d_get_picture(Some(ctx), NonNull::new(&mut pic as *mut Dav1dPicture)) }; + if dav1d_errno(r) == Some(libc::EAGAIN) { + return Ok(None); + } + if r.0 < 0 { + bail!("rav1d get_picture: {}", r.0); + } + // From here the picture is OURS and must be unref'd on every exit — including the + // refusals below, which is why the conversion is a closure and the unref is not + // in a branch. + let converted = Self::convert(&pic, color); + // SAFETY: `pic` is the live picture `dav1d_get_picture` just wrote; this releases + // exactly the one reference it handed over, once. + unsafe { dav1d_picture_unref(NonNull::new(&mut pic as *mut Dav1dPicture)) }; + converted.map(Some) + } + + fn convert(pic: &Dav1dPicture, color: &mut ColorDesc) -> Result { + // 8-bit 4:2:0 only, stated as a refusal rather than assumed — and as the SAME + // typed refusal the H.264 leg raises, so a shape this rung cannot decode + // reconnects instead of erroring once per AU for the rest of the session. + // Treating a 4:4:4 picture's planes as 4:2:0 would decode correctly and display + // wrong, which is the class this program exists to refuse. + // + // A BELT, not the gate: `unsupported_sequence` refuses these shapes before the + // AU is submitted, and a `bitdepth_8`-only build cannot produce a 10-bit picture + // anyway (`rav1d_submit_frame` refuses the frame setup). Kept because it costs + // two comparisons and because the day this build gains `bitdepth_16` the layout + // half stops being redundant. + let shape = if pic.p.bpc != 8 { + Some("10-bit or deeper") + } else if pic.p.layout != DAV1D_PIXEL_LAYOUT_I420 { + Some("chroma other than 4:2:0") + } else { + None + }; + if let Some(shape) = shape { + return Err(NoSoftwareRung { + codec: punktfunk_core::quic::CODEC_AV1, + shape: Some(shape), + } + .into()); + } + let (w, h) = (pic.p.w.max(0) as u32, pic.p.h.max(0) as u32); + // Colour rides the SEQUENCE header, which AV1 re-sends whenever it changes — the + // same per-picture contract the H.264 leg gets from the SPS, so an in-band + // SDR↔HDR flip is followed rather than latched. + if let Some(seq) = pic.seq_hdr { + // SAFETY: `seq_hdr` belongs to the picture we hold a reference to, so it is + // live for this call; these are plain scalar field reads. + let seq = unsafe { seq.as_ref() }; + *color = ColorDesc { + primaries: seq.pri as u8, + transfer: seq.trc as u8, + matrix: seq.mtrx as u8, + full_range: seq.color_range != 0, + }; + } + let keyframe = pic.frame_hdr.is_some_and(|f| { + // SAFETY: same as `seq_hdr` above — owned by the live picture, scalar read. + unsafe { f.as_ref() }.frame_type == rav1d::include::dav1d::headers::DAV1D_FRAME_TYPE_KEY + }); + let (_, ch) = CpuPlanarFrame::chroma_dims(w, h); + // dav1d gives ONE chroma stride for both planes (`stride[1]`), which is why the + // triple below repeats it rather than looking for a third. + let strides = [ + pic.stride[0].max(0) as usize, + pic.stride[1].max(0) as usize, + pic.stride[1].max(0) as usize, + ]; + let sizes = [ + h as usize * strides[0], + ch as usize * strides[1], + ch as usize * strides[2], + ]; + let mut planes: [&[u8]; 3] = [&[], &[], &[]]; + for i in 0..3 { + let p = pic.data[i].with_context(|| format!("rav1d: plane {i} is null"))?; + // SAFETY: dav1d's picture contract is that plane `i` spans + // `height_of_plane * |stride|` bytes from `data[i]`, and the picture holds a + // reference to that allocation for as long as we do (unref'd by the caller, + // after this conversion returns). Negative strides (bottom-up pictures) are + // rejected above by the `max(0)` collapsing them to a zero size, which the + // copy below then refuses. + planes[i] = unsafe { std::slice::from_raw_parts(p.as_ptr().cast::(), sizes[i]) }; + } + // No local-recovery answer from this leg: AV1 has no recovery point SEI, and its + // intra-refresh equivalent (`frame_refs_short_signaling` / S-frames) is not + // something a punktfunk host emits — so the pump's re-anchor behaviour on AV1 is + // exactly the wire's, as it is on every lane but H.264/H.265. + CpuPlanarFrame::from_i420( + w, + h, + planes, + strides, + *color, + keyframe, + punktfunk_core::reanchor::LocalRecovery::NONE, + ) + } +} + +impl Drop for Av1Software { + fn drop(&mut self) { + if self.ctx.is_none() { + return; + } + // SAFETY: `self.ctx` is the one context `dav1d_open` produced and this is its + // sole owner, so this runs exactly once; `dav1d_close` takes it through the + // `&mut` and leaves `None`. + unsafe { dav1d_close(NonNull::new(&mut self.ctx as *mut Option)) }; + } +} + +/// The errno behind a `Dav1dResult`, or `None` for success. +/// +/// rav1d returns the NEGATED errno as a plain `c_int`, and the codes are `libc`'s own +/// (`Rav1dError::ENOPROTOOPT = libc::ENOPROTOOPT as u8`) — so they are matched against +/// `libc`'s rather than written out. Not a nicety: `EAGAIN` is 11 everywhere but +/// `ENOPROTOOPT` is **92 on Linux and 123 on Windows**, and a literal would therefore be +/// right on exactly one platform. The typed enum this would rather match on +/// (`Rav1dError`) lives in a `pub(crate)` module — rav1d re-exports only `Dav1dResult` — +/// so the errno is the only handle the crate actually offers. +fn dav1d_errno(r: rav1d::Dav1dResult) -> Option { + (r.0 < 0).then_some(-r.0) } #[cfg(test)] mod tests { use super::*; + use crate::video::csc_rows; - /// The wire → `ColorDesc` plumbing: an HDR10 stream's VUI (BT.2020 primaries, PQ - /// transfer, BT.2020-NCL matrix, limited range) must arrive on the decoded frame — - /// this is what the Windows host emits in-band for an HDR desktop, and mis-rendering - /// it as BT.709 is the washed-out-colors bug. Fixture: one 64×64 Main10 IDR - /// (`tests/pq-frame.h265`, x265 with explicit VUI). - #[test] - fn software_decode_carries_pq_signaling() { - let au = include_bytes!("../tests/pq-frame.h265"); - let mut dec = SoftwareDecoder::new(ffmpeg::codec::Id::HEVC).expect("hevc decoder"); - let mut got = dec.decode(au).expect("decode"); - if got.is_none() { - // Low-delay decoders may still hold the frame until a flush — send EOF. - dec.decoder.send_eof().ok(); - let mut frame = AvFrame::empty(); - if dec.decoder.receive_frame(&mut frame).is_ok() { - got = Some(dec.convert_rgba(&frame).expect("convert")); - } - } - let f = got.expect("no frame decoded from the PQ fixture"); - assert_eq!( - f.color, - ColorDesc { - primaries: 9, - transfer: 16, - matrix: 9, - full_range: false - } - ); - assert!(f.color.is_pq()); - assert_eq!((f.width, f.height), (64, 64)); + /// The nine bars every fixture encodes, in x order: eight fully-saturated + /// primaries/secondaries plus black and white, and then the one that carries the + /// RANGE axis. + /// + /// ⚠ `(192, 128, 64)` is not decoration. On saturated bars a limited↔full mismatch + /// only pushes values outside [0, 1], where the shader clamps — so the 709-FULL + /// fixture decoded with the WRONG range comes back with max error **0** over the + /// eight, and this test could not fail on range at all. Measured on these fixtures: + /// the mid-tone gives max error 11 under the wrong range. A 50% grey does not do the + /// job either (3, inside the ±4 tolerance) — it has to be OFF-neutral, so the chroma + /// scale is exercised and not just the luma one. + const BARS: [(u8, u8, u8); 9] = [ + (255, 255, 255), + (255, 255, 0), + (0, 255, 255), + (0, 255, 0), + (255, 0, 255), + (255, 0, 0), + (0, 0, 255), + (0, 0, 0), + (192, 128, 64), + ]; + + /// The presenter's planar CSC shader, on the CPU: sample the three planes and apply + /// `csc_rows` exactly as `planar_csc.frag` does (`rgb[i] = dot(r[i].xyz, yuv) + + /// r[i].w`, then clamp). 8-bit, no MSB packing — the software rung's only shape. + /// + /// This is a MODEL of the shader, and it is the honest one: `csc_rows` is the single + /// coefficient implementation the shader's push constants are filled from (and the + /// Windows client's constant buffer, and the Apple client's Swift port), so what this + /// exercises end to end is exactly what changes colour on screen — the decoder's + /// plane layout, and the `ColorDesc` it read out of the bitstream. Sampling is + /// nearest at bar centres, which is where the shader's quarter-texel 4:2:0 siting + /// correction and its linear filter both make no difference. + fn shader_rgb(f: &CpuPlanarFrame, x: u32, y: u32) -> [u8; 3] { + let rows = csc_rows(f.color, 8, false); + let (cw, _) = CpuPlanarFrame::chroma_dims(f.width, f.height); + let luma = f.plane(0)[(y * f.width + x) as usize]; + let (cx, cy) = (x / 2, y / 2); + let cb = f.plane(1)[(cy * cw + cx) as usize]; + let cr = f.plane(2)[(cy * cw + cx) as usize]; + let yuv = [luma as f32 / 255.0, cb as f32 / 255.0, cr as f32 / 255.0]; + core::array::from_fn(|i| { + let v = rows[i][0] * yuv[0] + rows[i][1] * yuv[1] + rows[i][2] * yuv[2] + rows[i][3]; + (v.clamp(0.0, 1.0) * 255.0).round() as u8 + }) } - /// Golden colour fixtures: one 256×64 LOSSLESS x265 IDR of 8 fully-saturated colour bars per - /// signaling variant (generated offline with ffmpeg/libx265; the RGB→YUV conversion matched - /// to the VUI each fixture declares, so the original RGB is recoverable ±1 code). Decoding - /// through the real CPU path (`SoftwareDecoder` → per-frame `ColorDesc` → swscale with the - /// signaled matrix/range) must reproduce the bars — the end-to-end guard for the - /// signaling-driven CSC across BT.601/709 × limited/full. A hardcoded-709 regression fails - /// the 601 fixture by tens of code points; a range mix-up fails the full-range one. + fn decode_one(codec: u8, au: &[u8]) -> CpuPlanarFrame { + let mut dec = SoftwareDecoder::new(codec).expect("software decoder"); + dec.decode(au) + .expect("decode") + .expect("no frame out of the fixture") + } + + /// **M8's exit criterion.** Three lossless-ish H.264 colour-bar fixtures whose VUIs + /// differ ONLY in matrix and range (see `tests/gen-bars.sh` for the recipe): decode + /// each through the real CPU rung, then convert with the real `csc_rows`, and require + /// the original RGB back. + /// + /// What it would have caught, one failure per axis: + /// + /// * **The BT.601 default** — the bug the deleted `convert_rgba` carried explicit + /// correction code for. swscale converts with BT.601 coefficients unless told + /// otherwise, so a rung that dropped the signalling (or hardcoded one matrix) + /// renders the 601 fixture with 709 coefficients or vice versa. On the saturated + /// bars that is tens of code points — e.g. pure red's green channel goes from 0 to + /// ~+40 — far outside the ±4 tolerance (measured on these fixtures: max error 22 + /// for 709 read as 601, 39 the other way). + /// * **Range** — the 709-full fixture differs from 709-limited by the 16..235 vs + /// 0..255 expansion only. ⚠ On the eight saturated bars this axis CANNOT fail: + /// every one of them is at an extreme, so a mismatch only pushes values outside + /// [0, 1] where the shader clamps, and the fixture decodes with max error **0** + /// under the wrong range. The ninth bar, `(192, 128, 64)`, is what makes the axis + /// testable (max error 11 wrong-range, ~1 right) — see [`BARS`]. + /// * **Plane order and stride** — a Cb/Cr swap turns red into blue, and a stride + /// mistake shears the bars sideways, so both show up as a wrong bar rather than a + /// wrong shade. + /// + /// It is deliberately NOT a "did it decode" test: every assertion is a pixel value + /// that depends on the colour signalling surviving the whole path. #[test] - fn software_decode_reproduces_golden_bars() { - const BARS: [(u8, u8, u8); 8] = [ - (255, 255, 255), - (255, 255, 0), - (0, 255, 255), - (0, 255, 0), - (255, 0, 255), - (255, 0, 0), - (0, 0, 255), - (0, 0, 0), - ]; + fn software_h264_reproduces_the_golden_bars_in_both_ranges() { let fixtures: [(&str, &[u8], ColorDesc); 3] = [ ( "601-limited", - include_bytes!("../tests/bars-601-limited.h265"), + include_bytes!("../tests/bars-601-limited.h264"), ColorDesc { primaries: 1, transfer: 1, @@ -228,7 +822,7 @@ mod tests { ), ( "709-limited", - include_bytes!("../tests/bars-709-limited.h265"), + include_bytes!("../tests/bars-709-limited.h264"), ColorDesc { primaries: 1, transfer: 1, @@ -238,39 +832,264 @@ mod tests { ), ( "709-full", - include_bytes!("../tests/bars-709-full.h265"), + include_bytes!("../tests/bars-709-full.h264"), ColorDesc { primaries: 1, transfer: 1, matrix: 1, - full_range: true, // the PUNKTFUNK_444_FULLRANGE experiment's signaling + full_range: true, }, ), ]; for (name, au, want_color) in fixtures { - let mut dec = SoftwareDecoder::new(ffmpeg::codec::Id::HEVC).expect("hevc decoder"); - let mut got = dec.decode(au).expect("decode"); - if got.is_none() { - dec.decoder.send_eof().ok(); - let mut frame = AvFrame::empty(); - if dec.decoder.receive_frame(&mut frame).is_ok() { - got = Some(dec.convert_rgba(&frame).expect("convert")); - } - } - let f = got.unwrap_or_else(|| panic!("{name}: no frame decoded")); - assert_eq!(f.color, want_color, "{name}: signaling"); - assert_eq!((f.width, f.height), (256, 64), "{name}: dims"); + let f = decode_one(punktfunk_core::quic::CODEC_H264, au); + assert_eq!(f.color, want_color, "{name}: signalling"); + assert_eq!((f.width, f.height), (288, 64), "{name}: dims"); + assert!(f.keyframe, "{name}: the fixture is a single IDR"); for (i, (r, g, b)) in BARS.iter().enumerate() { - let (cx, cy) = (i * 32 + 16, 32usize); - let o = cy * f.stride + cx * 4; - let px = &f.rgba[o..o + 3]; + let px = shader_rgb(&f, i as u32 * 32 + 16, 32); for (got, want) in px.iter().zip([r, g, b]) { assert!( - got.abs_diff(*want) <= 3, + got.abs_diff(*want) <= 4, "{name} bar {i}: got {px:?}, want ({r},{g},{b})" ); } } } } + + /// The same three fixtures, but asserting the thing a "it decoded" test cannot: the + /// 601 and 709 pictures are DIFFERENT pixels, so a rung that ignored the signalling + /// and converted both with one matrix would still pass a self-consistency check. + /// + /// Guards the fixtures themselves as much as the code — if a regeneration ever + /// produced two identical bitstreams the colour test above would go vacuously green. + #[test] + fn the_601_and_709_fixtures_really_do_carry_different_luma() { + let f601 = decode_one( + punktfunk_core::quic::CODEC_H264, + include_bytes!("../tests/bars-601-limited.h264"), + ); + let f709 = decode_one( + punktfunk_core::quic::CODEC_H264, + include_bytes!("../tests/bars-709-limited.h264"), + ); + // Pure red: Y = 0.299·255 ≈ 76 under 601, 0.2126·255 ≈ 54 under 709 (both then + // range-compressed to 16..235). Same displayed colour, different code points. + let (x, y) = (5 * 32 + 16, 32); + let a = f601.plane(0)[(y * f601.width + x) as usize]; + let b = f709.plane(0)[(y * f709.width + x) as usize]; + assert!( + a.abs_diff(b) > 10, + "601 luma {a} vs 709 luma {b} — the fixtures do not differ, so the colour \ + test above proves nothing" + ); + // ...and after the CSC both land on the same red. + for (f, name) in [(&f601, "601"), (&f709, "709")] { + let px = shader_rgb(f, x, y); + assert!( + px[0].abs_diff(255) <= 4 && px[1] <= 4 && px[2] <= 4, + "{name}: red bar came out {px:?}" + ); + } + } + + /// HEVC has no CPU rung and must say so with the TYPE the session layer keys its + /// reconnect off — not with a string, and not by quietly producing nothing. + #[test] + fn hevc_is_refused_with_the_typed_no_rung_error() { + let err = SoftwareDecoder::new(punktfunk_core::quic::CODEC_HEVC) + .err() + .expect("HEVC must not build a software decoder"); + let typed = err + .downcast_ref::() + .expect("the refusal must survive as NoSoftwareRung through anyhow"); + assert_eq!(typed.codec, punktfunk_core::quic::CODEC_HEVC); + assert_eq!(typed.shape, None, "the CODEC is missing, not a shape"); + assert!(err.to_string().contains("HEVC"), "{err}"); + // And the two codecs that DO have one still build. + assert!(SoftwareDecoder::new(punktfunk_core::quic::CODEC_H264).is_ok()); + assert!(SoftwareDecoder::new(punktfunk_core::quic::CODEC_AV1).is_ok()); + } + + /// A picture shape the CPU rung cannot decode must raise the SAME typed refusal as a + /// missing codec, because it has the same available answer (reconnect) and because + /// the alternative — an `Err` per AU forever, or 8-bit maths over 10-bit samples — is + /// respectively a frozen screen and a wrong one. + /// + /// Exercised as the pure rule plus the two shapes a punktfunk host can actually + /// resolve: Main 10 (an HDR desktop, flipped IN-BAND, which is why the check reads + /// the ACTIVE SPS and not the Welcome) and 4:4:4 (the "Full chroma" opt-in). + #[test] + fn a_shape_the_cpu_rung_cannot_decode_is_the_same_typed_refusal() { + use punktfunk_core::quic::{CHROMA_IDC_420, CHROMA_IDC_444}; + // 8-bit 4:2:0 is the whole envelope. + assert_eq!(unsupported_shape(CHROMA_IDC_420, 0), None); + assert_eq!( + unsupported_shape(CHROMA_IDC_420, 2), + Some("10-bit or deeper") + ); + assert_eq!( + unsupported_shape(CHROMA_IDC_444, 0), + Some("chroma other than 4:2:0") + ); + // Depth is reported FIRST when both are wrong: it is the one that silently + // mis-scales rather than merely mis-siting, so it is the more useful diagnosis. + assert_eq!( + unsupported_shape(CHROMA_IDC_444, 2), + Some("10-bit or deeper") + ); + // And the refusal reaches a caller as the type the session keys its reconnect + // off, with a message that says which stream, not just "decode failed". + let e: anyhow::Error = NoSoftwareRung { + codec: punktfunk_core::quic::CODEC_AV1, + shape: Some("10-bit or deeper"), + } + .into(); + let typed = e.downcast_ref::().expect("typed"); + assert_eq!(typed.shape, Some("10-bit or deeper")); + assert!(e.to_string().contains("AV1"), "{e}"); + assert!(e.to_string().contains("8-bit 4:2:0 only"), "{e}"); + } + + /// The 709-full fixture must be ABLE to fail on the range axis. It could not before + /// the M8 review — every bar was saturated, so a limited↔full mismatch only pushed + /// values past the shader's clamp and the decode came back byte-perfect with the + /// WRONG range honoured. + /// + /// Guards the fixture, not the code: if `BARS` ever loses its mid-tone (or a + /// regeneration drops the ninth bar), the range half of the test above goes vacuous + /// and this is what says so. + #[test] + fn the_full_range_fixture_is_decoded_wrong_by_the_wrong_range() { + let f = decode_one( + punktfunk_core::quic::CODEC_H264, + include_bytes!("../tests/bars-709-full.h264"), + ); + let wrong = ColorDesc { + full_range: false, + ..f.color + }; + let rows = csc_rows(wrong, 8, false); + let (cw, _) = CpuPlanarFrame::chroma_dims(f.width, f.height); + let mut worst = 0u8; + for (i, (r, g, b)) in BARS.iter().enumerate() { + let (x, y) = (i as u32 * 32 + 16, 32u32); + let luma = f.plane(0)[(y * f.width + x) as usize]; + let cb = f.plane(1)[((y / 2) * cw + x / 2) as usize]; + let cr = f.plane(2)[((y / 2) * cw + x / 2) as usize]; + let yuv = [luma as f32 / 255.0, cb as f32 / 255.0, cr as f32 / 255.0]; + let px: [u8; 3] = core::array::from_fn(|c| { + let v = + rows[c][0] * yuv[0] + rows[c][1] * yuv[1] + rows[c][2] * yuv[2] + rows[c][3]; + (v.clamp(0.0, 1.0) * 255.0).round() as u8 + }); + for (got, want) in px.iter().zip([r, g, b]) { + worst = worst.max(got.abs_diff(*want)); + } + } + assert!( + worst > 4, + "decoding the FULL-range fixture as LIMITED was off by only {worst}, inside \ + the ±4 tolerance — the fixture no longer tests the range axis at all" + ); + } + + /// **B1.** A 10-bit AV1 stream must be REFUSED with the typed error, not errored on + /// per AU forever. + /// + /// This is the shipping case, not a corner: AV1 is advertised only where hardware AV1 + /// exists, hardware AV1 + HDR is Main 10, and a mid-session hardware failure demotes + /// onto this rung. rav1d is built `bitdepth_8`, so its frame setup refuses with + /// `ENOPROTOOPT`; before the review that surfaced as a generic `anyhow` the pump read + /// as survivable — keyframe requested, next AU identically 10-bit, screen frozen for + /// the rest of the session with no fallback. + /// + /// The fixture is a whole 10-bit AV1 temporal unit (SVT-AV1, 64x64 red, one key + /// frame) inline rather than on disk: 38 bytes, and what is being tested is the + /// SEQUENCE HEADER inside it. + #[test] + fn a_10bit_av1_stream_is_refused_with_the_typed_no_rung_error() { + const TU_10BIT: [u8; 38] = [ + 0x12, 0x00, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x02, 0xaf, 0xff, 0x8d, 0x5f, 0x38, 0x08, + 0x32, 0x16, 0x10, 0x00, 0xba, 0x02, 0x0b, 0x2c, 0x51, 0x41, 0x00, 0x00, 0x08, 0x00, + 0x95, 0xd1, 0xe2, 0x7e, 0xac, 0x4f, 0x04, 0xad, 0xa4, 0x70, + ]; + let mut dec = SoftwareDecoder::new(punktfunk_core::quic::CODEC_AV1).expect("av1 decoder"); + let err = dec + .decode(&TU_10BIT) + .err() + .expect("a 10-bit AV1 AU must not decode on an 8-bit-only build"); + let typed = err.downcast_ref::().expect( + "the refusal must survive as NoSoftwareRung through anyhow — a generic \ + error here is the permanent freeze this test exists to prevent", + ); + assert_eq!(typed.codec, punktfunk_core::quic::CODEC_AV1); + assert_eq!(typed.shape, Some("10-bit or deeper")); + // ...and the session layer's rule reads it as a SHAPE loss, so the retry is not + // narrowed to codecs with a CPU rung. + assert_eq!(typed.loss(), crate::video::RungLoss::Shape); + // Every following AU raises the same refusal rather than the decoder wedging: + // the pump breaks out on the first one, but a stuck loop here is the failure + // mode, so prove it stays a refusal. + assert!(dec + .decode(&TU_10BIT) + .err() + .and_then(|e| e.downcast_ref::().copied()) + .is_some()); + } + + /// The AV1 leg decodes a real stream and reports the sequence header's own colour. + /// Fixture: the vendored cros-codecs AV1 vector (IVF), whose first temporal unit is a + /// key frame — enough to prove the rav1d FFI (open → send → get → unref → close), + /// the I420 plane copy and the colour read, none of which the H.264 leg exercises. + #[test] + fn software_av1_decodes_and_reports_its_sequence_colour() { + const IVF: &[u8] = include_bytes!( + "../../pf-bitstream/vendor/cros-codecs/src/codec/av1/test_data/test-25fps.ivf.av1" + ); + // IVF: 32-byte file header, then per-frame [u32 size][u64 pts][payload]. + let mut off = 32usize; + let mut dec = SoftwareDecoder::new(punktfunk_core::quic::CODEC_AV1).expect("av1 decoder"); + let mut first = None; + let (mut units, mut frames) = (0u32, 0u32); + // Drive the WHOLE vector, not just the first unit: the send loop runs once per + // temporal unit and its `Dav1dData` guard drops on every path through it, so a + // leak or a wedge shows up as the run failing rather than as a slow drift nobody + // reproduces. + while off + 12 <= IVF.len() { + let sz = u32::from_le_bytes(IVF[off..off + 4].try_into().unwrap()) as usize; + off += 12; + if off + sz > IVF.len() { + break; + } + units += 1; + if let Some(f) = dec.decode(&IVF[off..off + sz]).expect("av1 decode") { + frames += 1; + if first.is_none() { + first = Some(f); + } + } + off += sz; + } + assert!( + units > 100, + "expected the full 25 fps vector, got {units} units" + ); + assert_eq!(frames, units, "every temporal unit here shows a picture"); + let f = first.expect("no AV1 frame decoded"); + assert_eq!((f.width, f.height), (320, 240)); + assert!(f.keyframe, "the first temporal unit is a key frame"); + // The vector signals nothing, so E.2.1-equivalent "unspecified" (2) must come + // through UNTOUCHED — `csc_rows` is what resolves it to the BT.709 SDR default, + // and a decoder that resolved it early would make an in-band HDR flip invisible. + assert_eq!(f.color.matrix, 2, "unspecified matrix must survive as 2"); + assert!(!f.color.full_range); + // Planes are tightly packed at the picture's own size — the presenter uploads + // them with no stride, so this invariant is load-bearing, not cosmetic. + assert_eq!(f.plane(0).len(), (f.width * f.height) as usize); + let (cw, ch) = CpuPlanarFrame::chroma_dims(f.width, f.height); + assert_eq!(f.plane(1).len(), (cw * ch) as usize); + assert_eq!(f.plane(2).len(), (cw * ch) as usize); + } } diff --git a/crates/pf-client-core/tests/bars-601-limited.h264 b/crates/pf-client-core/tests/bars-601-limited.h264 new file mode 100644 index 00000000..c1bcf750 Binary files /dev/null and b/crates/pf-client-core/tests/bars-601-limited.h264 differ diff --git a/crates/pf-client-core/tests/bars-601-limited.h265 b/crates/pf-client-core/tests/bars-601-limited.h265 deleted file mode 100644 index 48654683..00000000 Binary files a/crates/pf-client-core/tests/bars-601-limited.h265 and /dev/null differ diff --git a/crates/pf-client-core/tests/bars-709-full.h264 b/crates/pf-client-core/tests/bars-709-full.h264 new file mode 100644 index 00000000..a2c78842 Binary files /dev/null and b/crates/pf-client-core/tests/bars-709-full.h264 differ diff --git a/crates/pf-client-core/tests/bars-709-full.h265 b/crates/pf-client-core/tests/bars-709-full.h265 deleted file mode 100644 index cc0da18d..00000000 Binary files a/crates/pf-client-core/tests/bars-709-full.h265 and /dev/null differ diff --git a/crates/pf-client-core/tests/bars-709-limited.h264 b/crates/pf-client-core/tests/bars-709-limited.h264 new file mode 100644 index 00000000..f99f2d3a Binary files /dev/null and b/crates/pf-client-core/tests/bars-709-limited.h264 differ diff --git a/crates/pf-client-core/tests/bars-709-limited.h265 b/crates/pf-client-core/tests/bars-709-limited.h265 deleted file mode 100644 index 9a1ad414..00000000 Binary files a/crates/pf-client-core/tests/bars-709-limited.h265 and /dev/null differ diff --git a/crates/pf-client-core/tests/gen-bars.sh b/crates/pf-client-core/tests/gen-bars.sh new file mode 100755 index 00000000..204cb842 --- /dev/null +++ b/crates/pf-client-core/tests/gen-bars.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# Regenerate the software rung's colour fixtures (`video_software.rs`'s M8 exit test). +# +# Three single-IDR H.264 streams of the same NINE colour bars, whose VUIs differ ONLY in +# matrix coefficients and range. That is the point: the pictures are DIFFERENT code points +# that must converge on the SAME RGB once the signalled matrix and range are honoured — +# which is what makes the test able to fail against a hardcoded matrix (the swscale BT.601 +# default the old libav rung needed correction code for). +# +# ⚠ The NINTH bar (192,128,64) is load-bearing and must not be dropped for tidiness. The +# eight before it are fully saturated primaries/secondaries plus black and white, and on +# THOSE a limited↔full range mistake only pushes values outside [0,1] — where the shader +# clamps — so the whole fixture set decodes with max error 0 under the WRONG range and the +# range axis could not fail. Measured on this fixture: (192,128,64) gives max error 13 +# under the wrong range, while a 50% grey gives only 3, which is inside the test's ±4 +# tolerance. So it has to be a non-neutral mid-tone, not just a mid-tone. +# +# Not lossless: x264 refuses qp 0 outside High 4:4:4 Predictive, which openh264 cannot +# decode. qp 1 over flat bars is exact to within a code point or two at the bar centres +# the test samples, and the test's tolerance is ±4. +# +# Needs: ffmpeg with libx264. Run from this directory; overwrites the three fixtures. +set -e + +python3 - <<'PY' +BARS = [(255,255,255),(255,255,0),(0,255,255),(0,255,0),(255,0,255),(255,0,0),(0,0,255),(0,0,0), + (192,128,64)] +W, H = 32 * len(BARS), 64 +row = bytearray() +for x in range(W): + row += bytes(BARS[x // 32]) +open('bars.rgb', 'wb').write(bytes(row) * H) +print(f'{W}x{H}') +PY + +# 288x64: nine 32-px bars. Both dimensions stay macroblock-aligned (18x4), so there is no +# encoder padding for the crop to have to undo. +for spec in "601-limited bt470bg tv" "709-limited bt709 tv" "709-full bt709 pc"; do + set -- $spec + name=$1; mtx=$2; rng=$3 + ffmpeg -y -hide_banner -loglevel error -f rawvideo -pix_fmt rgb24 -s 288x64 -i bars.rgb \ + -vf "scale=in_range=full:out_color_matrix=$mtx:out_range=$rng,format=yuv420p" \ + -frames:v 1 -c:v libx264 -qp 1 -profile:v high \ + -x264-params "keyint=1:no-scenecut=1:colorprim=bt709:transfer=bt709:colormatrix=$mtx" \ + -color_primaries bt709 -color_trc bt709 -colorspace "$mtx" -color_range "$rng" \ + -f h264 "bars-$name.h264" +done +rm -f bars.rgb +ls -l bars-*.h264 diff --git a/crates/pf-client-core/tests/pq-frame.h265 b/crates/pf-client-core/tests/pq-frame.h265 deleted file mode 100644 index a9f2c1ea..00000000 Binary files a/crates/pf-client-core/tests/pq-frame.h265 and /dev/null differ diff --git a/crates/pf-console-ui/src/shell.rs b/crates/pf-console-ui/src/shell.rs index 6994109f..1503bafe 100644 --- a/crates/pf-console-ui/src/shell.rs +++ b/crates/pf-console-ui/src/shell.rs @@ -72,6 +72,10 @@ pub(crate) struct Shell { deck: bool, pub(crate) in_stream: bool, connecting: Option, + /// The last host title a connect was raised for, kept past the connect itself so + /// [`Self::session_reconnecting`] can name the host it is re-dialing — that flow + /// raises no `Launch` of its own and therefore never passes a title through. + last_connect_title: Option, wake: Option, /// True while `wake` is the shell's own optimistic placeholder — raised the instant a /// screen queues `ConsoleCmd::Wake` (see [`Self::apply`]), before the service thread has @@ -119,6 +123,7 @@ impl Shell { deck: opts.deck, in_stream: false, connecting: None, + last_connect_title: None, wake: None, wake_optimistic: false, toast: None, @@ -151,6 +156,7 @@ impl Shell { pub(crate) fn set_connecting(&mut self, title: Option) { match title { Some(title) => { + self.last_connect_title = Some(title.clone()); self.connecting = Some(Connecting { title, canceling: false, @@ -181,6 +187,38 @@ impl Shell { } } + /// The stream stopped and the client is dialing again on its own (M8's codec + /// fallback). Says what changed — the picture is about to come back as a different + /// codec and silence would read as a glitch — and raises the connecting modal. + /// + /// The modal is not cosmetic. Nothing raises a `Launch` for this retry (the run loop + /// starts the pump itself), so without it the shell would be in a state no other flow + /// produces: not streaming, not connecting, and a live pump behind the console. All + /// three gates would open at once — menu events flowing, the console drawn + /// full-screen over a frozen picture, and no modal interlock — and pressing A would + /// launch a SECOND session on top of the running one. This is also what gives B + /// somewhere to go: the modal's Back raises `CancelConnect`, which the run loop + /// applies to the retry's pump exactly as it does to a first dial. + /// + /// `appear = 1.0`: the takeover is already the thing on screen (the retry follows a + /// live stream), so fading it in would read as a flash rather than a transition. + pub(crate) fn session_reconnecting(&mut self, msg: &str) { + self.in_stream = false; + self.connecting = Some(Connecting { + // The host this session was dialed to. `None` only if the shell never raised + // the connect itself (a `--connect` run has no console at all, so it never + // reaches here) — name the codec change instead of an empty string. + title: self + .last_connect_title + .clone() + .unwrap_or_else(|| "the host".to_string()), + canceling: false, + appear: 1.0, + request_access: false, + }); + self.show_toast(msg.to_string()); + } + fn show_toast(&mut self, text: String) { self.toast = Some(Toast { text, at: self.t() }); } diff --git a/crates/pf-console-ui/src/skia_overlay.rs b/crates/pf-console-ui/src/skia_overlay.rs index ea2c48cc..1debc4fa 100644 --- a/crates/pf-console-ui/src/skia_overlay.rs +++ b/crates/pf-console-ui/src/skia_overlay.rs @@ -333,6 +333,15 @@ impl Overlay for SkiaOverlay { shell.session_ended(reason); self.streaming_since = None; } + // The stream stopped but a new dial is already in flight: toast WHY (the + // codec changed under the user) AND raise the connecting takeover, because + // nothing else will — the run loop starts the retry's pump directly rather + // than through a `Launch`, so the shell would otherwise sit in a state where + // a menu press could start a second session over the running one. + SessionPhase::Reconnecting(msg) => { + shell.session_reconnecting(msg); + self.streaming_since = None; + } } } diff --git a/crates/pf-presenter/src/csc.rs b/crates/pf-presenter/src/csc.rs index 5e5bb48f..dfcccabe 100644 --- a/crates/pf-presenter/src/csc.rs +++ b/crates/pf-presenter/src/csc.rs @@ -40,9 +40,15 @@ impl CscPass { ) } - /// The planar 3-plane variant (separate Cb/Cr R8 planes — the PyroWave decode - /// output, design/pyrowave-codec-plan.md §4.5). Same push-constant contract. - #[cfg(feature = "pyrowave")] + /// The planar 3-plane variant (separate Cb/Cr R8 planes). Same push-constant + /// contract. + /// + /// Two producers now: the PyroWave decode output + /// (design/pyrowave-codec-plan.md §4.5) and — since M8 — the SOFTWARE rung, whose + /// I420 planes the presenter uploads and converts here instead of receiving swscale's + /// RGBA. That is why this is no longer feature-gated or probe-gated: the CPU rung is + /// the ladder's last one, so it must exist on every device, including the ones that + /// failed the pyrowave probe. pub fn new_planar(device: &ash::Device, attachment_format: vk::Format) -> Result { Self::build( device, @@ -222,14 +228,19 @@ impl CscPass { } /// Planar variant of [`bind_planes`](Self::bind_planes): three single-component - /// plane views in GENERAL layout (the pyrowave decode leaves them there; same - /// fence-wait safety contract). - #[cfg(feature = "pyrowave")] - pub fn bind_planes_planar(&self, device: &ash::Device, planes: [vk::ImageView; 3]) { + /// plane views, in the layout their producer left them in — GENERAL for the pyrowave + /// decode, `SHADER_READ_ONLY_OPTIMAL` for the software rung's uploaded planes. Same + /// fence-wait safety contract. + pub fn bind_planes_planar( + &self, + device: &ash::Device, + planes: [vk::ImageView; 3], + layout: vk::ImageLayout, + ) { let infos = planes.map(|view| { [vk::DescriptorImageInfo::default() .image_view(view) - .image_layout(vk::ImageLayout::GENERAL)] + .image_layout(layout)] }); let writes = [0u32, 1, 2].map(|b| { vk::WriteDescriptorSet::default() diff --git a/crates/pf-presenter/src/lib.rs b/crates/pf-presenter/src/lib.rs index db34f32f..c868e158 100644 --- a/crates/pf-presenter/src/lib.rs +++ b/crates/pf-presenter/src/lib.rs @@ -3,7 +3,9 @@ //! decoded frames, captures input on the `ui_stream` state-machine contract, and reports //! the unified stats window on stdout. No UI toolkit anywhere in the dependency tree. //! -//! Three frame paths: software (`CpuFrame` RGBA staging upload), Vulkan Video (the +//! Three frame paths: software (`CpuPlanarFrame` — I420 planes staged into three R8 +//! images and converted by the same CICP-driven CSC pass as the hardware lanes; before M8 +//! this lane arrived as swscale RGBA and skipped the pass entirely), Vulkan Video (the //! decoder's VkImage on THIS device — plane views + the CICP-driven CSC pass), and on //! Linux additionally VAAPI hardware (NV12 dmabuf imported per-plane — `dmabuf.rs`), //! all composited by a letterboxed blit. Devices without the import extensions, and any diff --git a/crates/pf-presenter/src/overlay.rs b/crates/pf-presenter/src/overlay.rs index 9bca9afa..ff2f929a 100644 --- a/crates/pf-presenter/src/overlay.rs +++ b/crates/pf-presenter/src/overlay.rs @@ -113,6 +113,15 @@ pub enum SessionPhase<'a> { Failed(&'a str), /// The session ran and ended (`Some` = abnormal reason for the status strip). Ended(Option<&'a str>), + /// The session ended and the client is DIALING AGAIN by itself — today only because + /// the negotiated codec ran out of decode rungs (M8's software-HEVC drop) and the + /// retry advertises a codec this device can actually finish. + /// + /// Distinct from [`Self::Ended`] and [`Self::Failed`] because the user's next action + /// is different: nothing. "Session ended — HEVC decoding failed" invites a manual + /// reconnect that is already in flight, and "Couldn't connect" is simply false — the + /// connect worked, the decode did not. + Reconnecting(&'a str), } /// The console-UI side. Object-safe; the session binary passes diff --git a/crates/pf-presenter/src/run.rs b/crates/pf-presenter/src/run.rs index ebb56d0d..44438961 100644 --- a/crates/pf-presenter/src/run.rs +++ b/crates/pf-presenter/src/run.rs @@ -221,10 +221,14 @@ struct StreamState { /// mid-stream re-syncs keep the end-to-end number honest after an NTP step / drift. clock_offset: Option>, hdr: bool, - /// The presented lane was the CPU/software one, where a PQ stream is shown RAW — the - /// software path has no tone-map pass at all (the presenter uploads swscale RGBA - /// as-is; the CSC mode-1 tonemap is hardware-lane only) — so the OSD badge reads - /// `HDR→SDR (raw)` there instead of claiming a tone-map that never ran. + /// The presented lane shows a PQ stream RAW — no tone-map pass ran — so the OSD badge + /// reads `HDR→SDR (raw)` instead of claiming one that never did. + /// + /// Nothing sets it since M8. It used to mark the software lane, which arrived as + /// swscale RGBA and skipped the CSC pass entirely; that lane now uploads planes into + /// the same planar CSC pass as the hardware lanes and tone-maps in mode 1 like them. + /// Kept — not deleted — because the badge's distinction is real and the next lane that + /// bypasses the pass must be able to say so rather than quietly claim a tone-map. hdr_untonemapped: bool, // Presenter-side 1 s window (design/stats-unification.md): end-to-end // capture→displayed (host-clock corrected) p50+p95, display = decoded→displayed p50. @@ -279,6 +283,10 @@ struct StreamState { /// warn on the first failure of a streak, then stay quiet until a present succeeds. #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] pyro_present_warned: bool, + /// The same latch for the SOFTWARE lane, which since M8 has real failure modes (three + /// plane images + their allocations and views, rebuilt on every size change, plus a + /// render pass) and — being the ladder's LAST rung — nothing left to demote to. + cpu_present_warned: bool, hw_fails: u32, /// The OSD's text (multi-line; rebuilt each Stats window and on a live tier cycle). osd_text: String, @@ -322,6 +330,15 @@ struct StreamState { /// `None` = nothing sent yet. Edge-detected each iteration from the live mouse model, so /// the chord, the M3 auto-flip, and engage/release all reconcile through one path. sent_client_draws: Option, + /// The params this session was started with, kept so a codec fallback can re-dial + /// with `exclude_codecs` widened — see [`SessionEvent::CodecFallback`]. Cloned once + /// per session start, so anything the SESSION changed after launch (an accepted mode + /// switch) is not in here and the retry re-reads it from the connector. + /// + /// The latch grid rides along by `Arc` on purpose — it is the presenter's, not the + /// session's. `force_software` does NOT: it is a per-session demote latch, and the + /// retry replaces it (a fallback would otherwise open on software). + params: SessionParams, } impl StreamState { @@ -343,6 +360,8 @@ impl StreamState { // pump reads (see `LatchGrid`), so keep the Arc before the params move. `None` // when the session didn't advertise the cap — the 1 Hz fold then skips the work. let latch_grid = params.phase_lock.then(|| params.latch_grid.clone()); + // Kept for a codec-fallback re-dial (`SessionEvent::CodecFallback`). + let retry_params = params.clone(); let handle = session::start(params); let (wake_tx, wake_rx) = async_channel::bounded(2); let pump_rx = handle.frames.clone(); @@ -392,6 +411,7 @@ impl StreamState { dmabuf_demoted: false, #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] pyro_present_warned: false, + cpu_present_warned: false, hw_fails: 0, osd_text: String::new(), last_stats: None, @@ -401,6 +421,7 @@ impl StreamState { shown_mode: None, resize_overlay: ResizeIndicator::default(), last_video: None, + params: retry_params, } } @@ -1187,6 +1208,22 @@ fn run_inner(mut opts: SessionOpts, mut mode: ModeCtl) -> Result opts.render_scale_max_dim, ); } + // A live pump here would be DETACHED by the assignment + // below — `StreamState` has no `Drop`, so its thread + // would keep decoding onto the shared Vulkan device that + // gets destroyed at exit. The console normally gates the + // launch behind `in_stream`/`connecting`, but M8's + // Reconnecting phase is the first state that is neither + // while the stream is still alive. Every other + // replacement site takes-and-shuts-down; so does this + // one. + if let Some(prev) = stream.take() { + tracing::warn!( + "launch while a session was still attached — \ + stopping it first" + ); + prev.shutdown(); + } stream = Some(StreamState::new( *params, force_software, @@ -1344,6 +1381,103 @@ fn run_inner(mut opts: SessionOpts, mut mode: ModeCtl) -> Result } } } + // M8's HEVC path, as a first-class flow rather than a dead session: the + // negotiated codec ran out of decode rungs, so re-dial the SAME host with + // that codec removed from the advertised caps and let the host pick + // again. The pump computed the retry (never re-offering the failed codec, + // and — when the CODEC is what has no CPU rung — never offering one + // without a CPU rung either) and left nothing of its own running before + // sending this: the mid-stream site joins the audio/pad/clipboard threads + // and drops the connector, the construction-time site never spawned them. + // So starting the new session here is a clean start, not an overlap. + // + // Applies in BOTH modes. In single (`--connect`) mode there is no console + // to fall back to, which is exactly where limping-on-software used to be + // the only option; browse mode gets the same retry plus a toast. + SessionEvent::CodecFallback { + exclude_codecs, + retry_caps, + msg, + } => { + tracing::warn!( + %msg, + exclude_codecs, + retry_caps, + "decode ladder exhausted — reconnecting with reduced codec caps" + ); + gamepad.detach(); + if let Some(cap) = &mut st.capture { + cap.release(true); + } + apply_capture(&mut window, &mouse, false, false, inhibit_shortcuts); + // Widen the exclusion rather than replace it: a second fallback in the + // same run must not re-offer what the first one already ruled out. + let mut params = st.params.clone(); + params.exclude_codecs |= exclude_codecs; + // The mode this session ENDED on, not the one it dialled with: a + // mid-session `Reconfigure` the host accepted lives only in the + // connector, and `st.params` is a clone taken at launch — re-sending + // it would silently undo the switch on the retry. + if let Some(c) = &st.connector { + params.mode = c.mode(); + } + // ...and then the window follower on top, exactly as + // `ActionOutcome::Start` does, so a retry lands on the size the + // window is NOW rather than the size it was at launch. + if opts.match_window.is_some() { + apply_match_window( + &mut params, + &window, + opts.render_scale, + opts.render_scale_max_dim, + ); + } + // A FRESH demote flag, like `ActionOutcome::Start` builds — never the + // old session's. `force_software` is a latch the presenter sets when + // the hardware PRESENT path fails three times; inheriting it made an + // HEVC→H.264 retry open a SOFTWARE H.264 decoder on a box with + // perfectly good hardware H.264. It is shared with `params` because + // both ends of it belong to this presenter. + let force_software = Arc::new(AtomicBool::new(false)); + params.force_software = force_software.clone(); + // ⚠ `params.launch` rides along VERBATIM, and that is a deliberate + // choice between two wrong answers, not an assumption of idempotence. + // The host has no "already running → attach" branch on the launch + // path (`punktfunk-host`'s `native/stream.rs` launches + // unconditionally; its "launched ONCE" guarantee is scoped to + // mid-stream rebuilds WITHIN a session), and the game survives the + // session end under the default `GameOnSessionEnd::Keep`. So the + // re-send is idempotent only where the LAUNCHER dedupes it — + // `steam://rungameid` focuses the running copy, an Epic/AUMID URI + // likewise — while a `gog:`/`custom:` target really does start a + // second copy. Dropping the field instead is worse where it matters + // most: on Linux the per-session gamescope is re-adopted through + // `pf-vdisplay`'s display registry, whose reuse key INCLUDES the + // launch command, so a retry without it would miss the lingering + // display and orphan the running game inside it. Keeping it is the + // only option that preserves that attach; the real fix is host-side + // (an idempotency key on `Hello::launch`, or a running-title check + // before the spawn) and is not M8's to make. + // + // Known and unfixed here for the same reason: the RETRY's game lease + // cannot adopt a game that predates its own launch stamp (`procscan` + // rejects anything started more than 2 s before it), so a reconnected + // session has no game-exit detection for the rest of its life. + if let Some(st) = stream.take() { + st.shutdown(); + } + if let Some(o) = overlay.as_mut() { + o.session_phase(SessionPhase::Reconnecting(&msg)); + } + stream = Some(StreamState::new( + params, + force_software, + events.event_sender(), + present_priority, + native.refresh_hz, + )); + break; + } } } @@ -1630,10 +1764,42 @@ fn run_inner(mut opts: SessionOpts, mut mode: ModeCtl) -> Result } DecodedImage::Cpu(c) => { st.hdr = c.color.is_pq(); - // The software lane shows PQ raw (no tone-map pass exists there) - // — the OSD badge must not claim `HDR→SDR` for it. - st.hdr_untonemapped = true; - presenter.present(&window, FrameInput::Cpu(&c), overlay_frame.as_ref())? + // Since M8 the software lane uploads planes into the SAME planar + // CSC pass as the hardware lanes, so a PQ stream is tone-mapped + // there exactly like theirs — the badge no longer has to warn + // that this lane shows PQ raw, because it does not. + st.hdr_untonemapped = false; + // Same treatment as the pyrowave arm below, and for the same + // reason: since M8 this arm allocates three plane images (plus + // memory and views) on every size change and runs a render pass, + // so it has failure modes a staging upload never had — and it is + // the LAST rung, so a present failure has nothing left to demote + // to. Drop the frame and keep the session; only a lost device + // ends it. + match presenter.present( + &window, + FrameInput::Cpu(&c), + overlay_frame.as_ref(), + ) { + Ok(p) => { + st.cpu_present_warned = false; + p + } + Err(e) => { + if device_lost(&e) { + return Err(e) + .context("GPU device lost — the session cannot continue"); + } + if !st.cpu_present_warned { + st.cpu_present_warned = true; + tracing::warn!( + error = %format!("{e:#}"), + "software present failed — suppressing repeats until it recovers" + ); + } + false + } + } } // Both VAAPI rungs — libavcodec's and M6's native one — hand over // the same thing: dmabuf fds plus a plane layout, with the guard @@ -2425,10 +2591,12 @@ const HINT_WITH_PAD: &str = "Click the stream to capture input · Ctrl+Alt+Shift /// /// The HDR tag is honest about the display path: `HDR` only when the swapchain actually /// runs HDR10 (`hdr_display`); a PQ stream tone-mapped onto an SDR surface (no HDR10 -/// format offered, HDR off in the compositor) shows `HDR→SDR`; and a PQ stream on the -/// software-decode lane (`hdr_untonemapped`) shows `HDR→SDR (raw)` — that lane has no -/// tone-map pass at all, so the washed-out picture is named for what it is rather than -/// passed off as a tone-map. +/// format offered, HDR off in the compositor) shows `HDR→SDR`; and a lane that shows PQ +/// with no tone-map pass at all (`hdr_untonemapped`) shows `HDR→SDR (raw)`, so a +/// washed-out picture is named for what it is rather than passed off as a tone-map. +/// ⚠ Since M8 no lane sets that flag — the software lane, which used to, now goes through +/// the same planar CSC pass as the hardware ones. The arm is kept for the next one that +/// does not; see `StreamState::hdr_untonemapped`. /// /// `profile` (the session's settings profile, `None` for the global defaults) closes the /// first line at every tier — the cheapest possible answer to "which profile am I on?" @@ -2622,6 +2790,19 @@ fn stats_text( text.push_str(&format!("\nintegrity: {}", parts.join(" · "))); } } + // M8's software-HEVC-drop telemetry ("telemetry on frequency", §7 risk register): + // how many times in THIS process a session's codec ran out of decode rungs and had + // to reconnect as another codec. Process-cumulative, appended LAST and only when + // nonzero — additive for the stdout `stats:` line's parsers, and invisible on the + // overwhelming majority of runs where it never happens. + // + // On the line rather than only in the log because the question it answers is a rate + // across a session history ("did dropping software HEVC cost anyone a stream?"), and + // a warn nobody greps for cannot answer it. + let fallbacks = pf_client_core::session::codec_fallbacks(); + if detailed && fallbacks > 0 { + text.push_str(&format!("\ncodec_fallbacks {fallbacks}")); + } text } @@ -3126,10 +3307,14 @@ mod tests { } } - /// The honest HDR badges: a PQ stream on the software-decode lane is shown WITHOUT - /// tone-mapping (that lane has no PQ→sRGB pass), so its badge must not read as the - /// hardware lane's `HDR→SDR` tone-map — and an HDR10 swapchain shows plain `HDR` - /// whatever the lane claims (a CPU frame forces the swapchain to SDR anyway). + /// The honest HDR badges. ⚠ **The `(raw)` arm is currently unreachable in + /// production**: `hdr_untonemapped` is written `false` on every present arm since M8 + /// took the software lane through the same planar CSC pass (and therefore the same + /// tone-map) as the hardware lanes — see `StreamState::hdr_untonemapped`. This tests + /// the FORMATTER, not a state the client can be in, and it is kept for the same + /// reason the field is: the next lane that bypasses the pass must be able to say so + /// rather than quietly claim a tone-map, and this is the assertion that will still be + /// here when it does. #[test] fn hdr_badge_names_the_untonemapped_cpu_lane() { let (s, p) = sample(); diff --git a/crates/pf-presenter/src/vk/mod.rs b/crates/pf-presenter/src/vk/mod.rs index 3d0f53f3..537ca777 100644 --- a/crates/pf-presenter/src/vk/mod.rs +++ b/crates/pf-presenter/src/vk/mod.rs @@ -1,13 +1,20 @@ -//! The Vulkan presenter: swapchain + two frame paths into one device-local RGBA video +//! The Vulkan presenter: swapchain + several frame paths into one device-local RGBA video //! image, then a letterboxed `vkCmdBlitImage` composite. //! -//! * **Software** (`FrameInput::Cpu`): staging upload + `copy_buffer_to_image` (row -//! stride via `buffer_row_length`) — transfer-only, runs on every GPU. +//! * **Software** (`FrameInput::Cpu`): since M8 the CPU rung hands over tightly-packed +//! 8-bit I420 PLANES, not RGBA. They are staged into three R8 images +//! (`CpuPlanes`, no `buffer_row_length` — the planes carry no stride) and converted by +//! the PLANAR CSC render pass, the same pass and the same `csc_rows` coefficients the +//! hardware lanes use. That is what deleted this lane's second colour implementation +//! (swscale's BT.601 default) and its missing tone-map along with it. //! * **Hardware** (`FrameInput::Dmabuf`): the decoder's NV12 dmabuf imported per-plane -//! (`dmabuf.rs`) and converted by the CSC render pass (`csc.rs`) — zero-copy, gated on -//! the four import extensions at device creation; boxes without them (NVIDIA +//! (`dmabuf.rs`) and converted by the two-plane CSC render pass (`csc.rs`) — zero-copy, +//! gated on the four import extensions at device creation; boxes without them (NVIDIA //! proprietary by design) report `supports_dmabuf() == false` and the caller keeps the //! decoder on software. +//! * Plus the lanes that arrive already on this device: `VkFrame`/`NativeVk` (Vulkan +//! Video), `D3d11` (Windows shared textures) and `PyroWave` (three compute-decoded +//! planes, through the same planar pass as the software lane). //! //! Pacing: one frame in flight (the submit fence is waited before each record), MAILBOX //! when available, FIFO otherwise (`PUNKTFUNK_PRESENT_MODE=fifo|mailbox|immediate` @@ -23,7 +30,7 @@ use crate::overlay::SharedDevice; use ash::vk; #[cfg(target_os = "linux")] use pf_client_core::video::DmabufFrame; -use pf_client_core::video::{CpuFrame, NativeVkFrame, VkVideoFrame}; +use pf_client_core::video::{CpuPlanarFrame, NativeVkFrame, VkVideoFrame}; mod gpu; mod overlay_pipe; @@ -39,7 +46,11 @@ pub use setup::{list_adapters, PresentPref}; pub enum FrameInput<'a> { /// No new frame — re-composite the retained video image (expose/resize). Redraw, - Cpu(&'a CpuFrame), + /// Software-decoded I420 planes (M8): uploaded into three R8 images and converted by + /// the planar CSC pass, exactly like the hardware lanes' planes — so PQ tone-mapping, + /// range and matrix all come from the ONE shader, and the CPU lane stops being the + /// odd one out that arrived pre-converted (and pre-converted wrong). + Cpu(&'a CpuPlanarFrame), #[cfg(target_os = "linux")] Dmabuf(DmabufFrame), /// FFmpeg Vulkan Video output — a VkImage already on THIS device (zero copy). @@ -107,8 +118,32 @@ struct OverlayPipe { framebuffers: Vec, } -/// The one video image (device-local RGBA the size of the decoded stream) + its staging. -/// `view`/`framebuffer` exist only on hw-capable devices (the CSC pass renders into it). +/// The software rung's plane images: three R8 pictures the CPU frame's tightly-packed +/// I420 is uploaded into, then sampled by the planar CSC pass. Sized to the LUMA picture +/// and its 4:2:0 chroma halves; rebuilt whenever the stream size changes. +/// +/// Owned by the presenter rather than parked in `Retired` like the imported hardware +/// frames: nothing outside this device ever refers to them, and the single in-flight +/// fence is waited before each record, so re-uploading into the same images is safe +/// without a ring. +struct CpuPlanes { + images: [vk::Image; 3], + memory: [vk::DeviceMemory; 3], + views: [vk::ImageView; 3], + /// Luma size; chroma is derived (`div_ceil(2)`), the same rule the frame uses. + width: u32, + height: u32, + /// True once the images have been transitioned out of UNDEFINED at least once — the + /// first upload must come from UNDEFINED (nothing to preserve), every later one from + /// SHADER_READ_ONLY_OPTIMAL (where the previous frame's CSC pass left them). + initialized: bool, +} + +/// The one video image: device-local RGBA the size of the decoded stream, the single +/// target every lane converges on before the letterboxed blit. `view` + `framebuffer` are +/// unconditional since M8 — the CSC pass renders into it on EVERY device, because the +/// software lane goes through the planar pass too and there is no lane left that writes +/// this image with a plain transfer. struct VideoImage { image: vk::Image, memory: vk::DeviceMemory, @@ -118,6 +153,8 @@ struct VideoImage { height: u32, } +/// The host-visible upload buffer the software rung's three planes are copied into before +/// the record step's `vkCmdCopyBufferToImage`s. Grows, never shrinks. struct Staging { buffer: vk::Buffer, memory: vk::DeviceMemory, @@ -146,10 +183,15 @@ pub struct Presenter { #[cfg(windows)] hw_win: Option, csc: CscPass, - /// The planar (3-plane) CSC variant for PyroWave frames; built only when the device - /// passed the pyrowave probe. - #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] - csc_planar: Option, + /// The planar (3-plane) CSC variant. Unconditional since M8: the SOFTWARE rung + /// renders through it, and the software rung is the ladder's last one — a device that + /// failed the pyrowave probe (or a build without the feature) still has to be able to + /// show a picture. + csc_planar: CscPass, + /// The software rung's three uploaded plane images (Y/Cb/Cr, R8), rebuilt on a + /// stream-size change. `None` until the first CPU frame — a hardware session never + /// allocates them. + cpu_planes: Option, /// FFmpeg Vulkan Video decode handles — `None` when the stack can't do it. video_export: Option, /// The console-UI composite quad (§6.1's presenter half). @@ -385,8 +427,8 @@ impl Drop for Presenter { #[cfg(target_os = "linux")] self.hw.take(); self.csc.destroy(&self.device); - #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] - if let Some(p) = &self.csc_planar { + self.csc_planar.destroy(&self.device); + if let Some(p) = self.cpu_planes.take() { p.destroy(&self.device); } self.overlay_pipe.destroy(&self.device); diff --git a/crates/pf-presenter/src/vk/present.rs b/crates/pf-presenter/src/vk/present.rs index 21e4eb7d..04138bbd 100644 --- a/crates/pf-presenter/src/vk/present.rs +++ b/crates/pf-presenter/src/vk/present.rs @@ -31,36 +31,17 @@ impl Presenter { // offers HDR10 — otherwise PQ stays on the SDR swapchain and the CSC shader // tonemaps (mode 1). // - // CPU frames NEVER take the HDR10 surface: software decode uploads swscale RGBA with - // no CSC/tonemap pass, so on a mode-0 swapchain that sRGB-encoded content would be - // composed as PQ — the field-reported psychedelic cyan/magenta picture (reproduced - // 2026-07-21: Fedora-class client, no hw HEVC decode, GNOME/Mesa offering HDR10 even - // on an SDR desktop). On the SDR swapchain the same frames are merely untonemapped - // (washed out) — wrong in the known, benign way until the CPU lane grows a real - // PQ→sRGB pass. + // The CPU lane used to be the exception here: it arrived as swscale RGBA with no + // CSC/tonemap pass at all, so it was pinned to the SDR swapchain (a mode-0 + // composite of sRGB content as PQ is the field-reported psychedelic cyan/magenta + // picture, reproduced 2026-07-21 on a Fedora-class client with no hw HEVC decode + // and GNOME/Mesa offering HDR10 on an SDR desktop) and a PQ stream simply came out + // washed out. Since M8 it goes through the SAME planar CSC pass as every hardware + // lane, so it gets the same answer as every hardware lane: PQ where the surface + // offers HDR10, the shader's mode-1 tonemap where it does not. let frame_pq = match &input { FrameInput::Redraw => None, - FrameInput::Cpu(f) => { - // The swapchain answer stays `false` (above) — but a PQ stream on this - // lane is then shown RAW: no PQ→sRGB pass exists here (the CSC mode-1 - // tonemap is hardware-lane only; CPU frames are a straight RGBA upload), - // so the picture is washed out and the pq-downgrade warn below never - // fires. Say so once, or the only trace is an OSD badge. (A process-once - // latch, same idiom as the decoders' first-frame layout dumps — the - // condition is a property of the lane, not of one Presenter.) - if f.color.is_pq() { - use std::sync::atomic::{AtomicBool, Ordering}; - static WARNED: AtomicBool = AtomicBool::new(false); - if !WARNED.swap(true, Ordering::Relaxed) { - tracing::warn!( - "HDR10 (PQ) stream on the software-decode lane — it has no \ - PQ→sRGB pass, so the picture is shown untonemapped (washed \ - out). Hardware decode restores correct colour." - ); - } - } - Some(false) - } + FrameInput::Cpu(f) => Some(f.color.is_pq()), #[cfg(target_os = "linux")] FrameInput::Dmabuf(d) => Some(d.color.is_pq()), FrameInput::VkFrame(v) => Some(v.color.is_pq()), @@ -100,6 +81,10 @@ impl Presenter { let mut native_frame: Option = None; #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] let mut pyro_frame: Option = None; + // A real frame that is NOT a CPU one — the signal that the software rung's plane + // images are dead weight (see below). `Redraw` is deliberately not one: it + // re-blits the retained video image and says nothing about which lane is decoding. + let mut hw_lane = false; let cpu_frame = match input { FrameInput::Redraw => None, FrameInput::Cpu(f) => Some(f), @@ -110,6 +95,7 @@ impl Presenter { .as_ref() .context("hardware frame without dmabuf support")?; hw_frame = Some(dmabuf::import(&self.device, &hw.ext_mem_fd, d)?); + hw_lane = true; None } #[cfg(windows)] @@ -119,22 +105,26 @@ impl Presenter { .as_ref() .context("D3D11 frame without win32 import support")?; win_frame = Some(crate::d3d11::import(&self.device, &hw.ext_mem_win32, &d)?); + hw_lane = true; None } FrameInput::VkFrame(v) => { let views = self.vkframe_plane_views(&v)?; vk_frame = Some((v, views)); + hw_lane = true; None } #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] FrameInput::PyroWave(f) => { pyro_frame = Some(f); + hw_lane = true; None } // Same device, and the decoder already made the per-plane views — no // import, no view creation, nothing that can fail out here. FrameInput::NativeVk(f) => { native_frame = Some(f); + hw_lane = true; None } }; @@ -153,10 +143,22 @@ impl Presenter { if let Some(old) = self.retired_hw.take() { old.destroy(&self.device); } - - if let Some(f) = cpu_frame { - self.stage_frame(f)?; + // A hardware frame after a software one: the plane images are ~12 MB at 4K and + // nothing will sample them again. This is not hypothetical — M8's codec fallback + // starts a NEW session on this same presenter, and that one can be hardware where + // the one that raised it was not. The fence wait above is what makes them + // unreferenced, so this is the first safe moment. + if hw_lane { + if let Some(p) = self.cpu_planes.take() { + tracing::debug!("freeing the software rung's plane images (hardware lane)"); + p.destroy(&self.device); + } } + + let cpu_offsets = match cpu_frame { + Some(f) => Some(self.stage_frame(f)?), + None => None, + }; #[cfg(target_os = "linux")] if let Some(f) = &hw_frame { if self @@ -235,11 +237,26 @@ impl Presenter { self.rebuild_video_image(f.width, f.height)?; tracing::info!(width = f.width, height = f.height, "video image (re)built"); } - let planar = self - .csc_planar + // The decode leaves them in GENERAL — the software rung's uploaded planes are + // the other producer for this pass and arrive in SHADER_READ_ONLY_OPTIMAL. + self.csc_planar.bind_planes_planar( + &self.device, + f.views.map(vk::ImageView::from_raw), + vk::ImageLayout::GENERAL, + ); + } + if cpu_offsets.is_some() { + // Safe while nothing in flight references the set — the fence wait above. + let views = self + .cpu_planes .as_ref() - .context("PyroWave frame but the device failed the pyrowave probe")?; - planar.bind_planes_planar(&self.device, f.views.map(vk::ImageView::from_raw)); + .context("software frame without plane images")? + .views; + self.csc_planar.bind_planes_planar( + &self.device, + views, + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + ); } if let Some(o) = overlay { // Point the composite at this overlay image (same fence-wait safety). @@ -476,40 +493,80 @@ impl Presenter { width: v.width, height: v.height, }; - self.record_csc_planar(v.framebuffer, extent, f.color); + // An HDR (PQ) pyrowave session carries P010-style 10-bit studio codes + // MSB-packed into 16-bit planes (design/pyrowave-444-hdr.md §2.2) — same + // sampling scale as the P010 path; SDR sessions are plain 8-bit BT.709 + // limited. Depth follows THIS codec's colour contract (negotiation + // couples 10-bit ⟺ PQ for it), which is why it is decided here and not + // inside the shared record. + let (depth, msb_packed) = if f.color.is_pq() { + (10, true) + } else { + (8, false) + }; + self.record_csc_planar(v.framebuffer, extent, f.color, depth, msb_packed); } - // New frame: staging → video image (stride carried by buffer_row_length). - if let (Some(f), Some(v), Some(s)) = (cpu_frame, &self.video, &self.staging) { - barrier( - &self.device, - self.cmd_buf, - v.image, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - ); - let region = vk::BufferImageCopy::default() - .buffer_row_length((f.stride / 4) as u32) - .image_subresource(subresource_layers()) - .image_extent(vk::Extent3D { - width: v.width, - height: v.height, - depth: 1, - }); - self.device.cmd_copy_buffer_to_image( - self.cmd_buf, - s.buffer, - v.image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &[region], - ); - barrier( - &self.device, - self.cmd_buf, - v.image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - ); + // Software frame (M8): staging → three R8 plane images → the planar CSC pass, + // the same pass and the same `csc_rows` coefficients the hardware lanes use. + // The planes are tightly packed by construction (`CpuPlanarFrame`), so no + // `buffer_row_length` is needed and none is set — a stride here would be a + // second place for the layout to be wrong. + if let (Some(f), Some(offsets), Some(v), Some(s), Some(p)) = ( + cpu_frame, + cpu_offsets, + &self.video, + &self.staging, + &self.cpu_planes, + ) { + // First upload into freshly built images comes from UNDEFINED (there is + // nothing to preserve); every later one from where the previous frame's + // CSC pass left them. + let from = if p.initialized { + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL + } else { + vk::ImageLayout::UNDEFINED + }; + for (i, offset) in offsets.iter().enumerate() { + let (w, h) = f.plane_dims(i); + barrier( + &self.device, + self.cmd_buf, + p.images[i], + from, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + ); + let region = vk::BufferImageCopy::default() + .buffer_offset(*offset as u64) + .image_subresource(subresource_layers()) + .image_extent(vk::Extent3D { + width: w, + height: h, + depth: 1, + }); + self.device.cmd_copy_buffer_to_image( + self.cmd_buf, + s.buffer, + p.images[i], + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[region], + ); + barrier( + &self.device, + self.cmd_buf, + p.images[i], + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + ); + } + let extent = vk::Extent2D { + width: v.width, + height: v.height, + }; + // Always 8-bit, no MSB packing — R8 planes, whatever the stream signals. + // A PQ AV1 stream on this rung therefore tone-maps through the shader's + // mode 1 like every other lane, instead of being read as 10-bit. + self.record_csc_planar(v.framebuffer, extent, f.color, 8, false); } // Swapchain image: discard old content, clear to black (the letterbox bars), @@ -628,6 +685,14 @@ impl Presenter { ); } self.device.end_command_buffer(self.cmd_buf)?; + // The plane images now have content and a real layout, so the NEXT upload + // must transition from SHADER_READ_ONLY_OPTIMAL rather than discard them from + // UNDEFINED. Recorded, not submitted — but the only path from here to another + // record goes through this command buffer, and a submit failure below tears + // the presenter down rather than re-recording. + if let Some(p) = self.cpu_planes.as_mut() { + p.initialized = true; + } let render_sem = self.render_sems[index as usize]; let cmd_bufs = [self.cmd_buf]; @@ -883,18 +948,22 @@ impl Presenter { } } - /// [`record_csc`] over the planar (PyroWave) pass — always 8-bit, no MSB packing. - #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] + /// [`record_csc`] over the planar (3-plane) pass — the PyroWave decode output and, + /// since M8, the software rung's uploaded I420. + /// + /// `depth`/`msb_packed` are the PRODUCER's, never inferred from the colour: pyrowave + /// couples 10-bit to PQ by negotiation, the software rung is 8-bit whatever it is + /// showing, and reading PQ as "therefore 10-bit MSB-packed" over an 8-bit plane + /// samples at a quarter scale — decoded correctly, displayed wrong. unsafe fn record_csc_planar( &self, framebuffer: vk::Framebuffer, extent: vk::Extent2D, color: pf_client_core::video::ColorDesc, + depth: u8, + msb_packed: bool, ) { - // The planar pass exists whenever a PyroWave frame reached us (checked at bind). - let Some(planar) = self.csc_planar.as_ref() else { - return; - }; + let planar = &self.csc_planar; // SAFETY: per the Vulkan contract above - recorded into a command buffer this code owns // and has begun, referencing handles it also owns; nothing is submitted until the // recording is ended. @@ -943,15 +1012,6 @@ impl Presenter { &[planar.desc_set], &[], ); - // An HDR (PQ) pyrowave session carries P010-style 10-bit studio codes MSB-packed - // into 16-bit planes (design/pyrowave-444-hdr.md §2.2) — same sampling scale as - // the P010 path; SDR sessions are plain 8-bit BT.709 limited. Depth follows the - // colour contract (negotiation couples 10-bit ⟺ PQ for this codec). - let (depth, msb_packed) = if color.is_pq() { - (10, true) - } else { - (8, false) - }; let rows = csc_rows(color, depth, msb_packed); // Mode 1 = PQ→SDR tonemap (PQ stream without an HDR10 surface); mode 0 passes // the transfer through — identical to the NV12 arm above. diff --git a/crates/pf-presenter/src/vk/reconfig.rs b/crates/pf-presenter/src/vk/reconfig.rs index 5e9d39a5..4ab6227a 100644 --- a/crates/pf-presenter/src/vk/reconfig.rs +++ b/crates/pf-presenter/src/vk/reconfig.rs @@ -274,14 +274,11 @@ impl Presenter { }; self.csc.destroy(&self.device); // fence-safe: only our cmd bufs reference it self.csc = CscPass::new(&self.device, self.video_format)?; - // The planar (PyroWave) pass renders to the same intermediate — rebuild it at the - // new format too (an HDR pyrowave session needs the 10-bit intermediate exactly - // like the H.26x path; 8-bit PQ bands visibly). - #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] - if let Some(p) = self.csc_planar.take() { - p.destroy(&self.device); - self.csc_planar = Some(CscPass::new_planar(&self.device, self.video_format)?); - } + // The planar pass (PyroWave + the software rung) renders to the same intermediate + // — rebuild it at the new format too (an HDR session needs the 10-bit + // intermediate exactly like the H.26x path; 8-bit PQ bands visibly). + self.csc_planar.destroy(&self.device); + self.csc_planar = CscPass::new_planar(&self.device, self.video_format)?; if let Some(v) = self.video.take() { // SAFETY: per the Vulkan contract above - this destroys objects this type owns, and // the GPU is known idle for them (the fence/queue-wait on the path here, or the diff --git a/crates/pf-presenter/src/vk/resources.rs b/crates/pf-presenter/src/vk/resources.rs index 4627e137..024ee469 100644 --- a/crates/pf-presenter/src/vk/resources.rs +++ b/crates/pf-presenter/src/vk/resources.rs @@ -1,10 +1,10 @@ //! Video-image / staging-buffer (re)build + retired-frame destruction. use super::gpu::subresource_range; -use super::{Presenter, Retired, Staging, VideoImage}; +use super::{CpuPlanes, Presenter, Retired, Staging, VideoImage}; use anyhow::Result; use ash::vk; -use pf_client_core::video::CpuFrame; +use pf_client_core::video::CpuPlanarFrame; impl Retired { pub(super) fn destroy(self, device: &ash::Device) { @@ -32,16 +32,49 @@ impl Retired { } } +/// Staging offset of plane `i` for a picture of this size, plus the total bytes needed. +/// +/// Each plane starts on a 16-byte boundary so `bufferOffset` satisfies the copy's +/// "multiple of 4" rule whatever the picture dimensions are — with a 1-byte-per-texel +/// format an odd width would otherwise land a later plane on an odd offset. +fn plane_staging_offsets(f: &CpuPlanarFrame) -> ([usize; 3], usize) { + let mut offsets = [0usize; 3]; + let mut at = 0usize; + for (i, off) in offsets.iter_mut().enumerate() { + let (w, h) = f.plane_dims(i); + *off = at; + at += (w as usize * h as usize).next_multiple_of(16); + } + (offsets, at) +} + +impl CpuPlanes { + /// Destroy every handle this value holds. Null handles are fine — Vulkan defines + /// destroy/free on `VK_NULL_HANDLE` as a no-op — which is what lets + /// [`Presenter::rebuild_cpu_planes`] unwind a build that failed part-way. + pub(super) fn destroy(self, device: &ash::Device) { + // SAFETY: per the Vulkan contract above - this destroys objects this type owns, and the + // GPU is known idle for them (the fence/queue-wait on the path here, or the swapchain + // being retired), which is the obligation that makes a destroy sound rather than the + // handle merely being non-null. + unsafe { + for i in 0..3 { + device.destroy_image_view(self.views[i], None); + device.destroy_image(self.images[i], None); + device.free_memory(self.memory[i], None); + } + } + } +} + impl Presenter { - /// Copy the frame's RGBA into the staging buffer and (re)build the video image on a - /// stream-size change. Rows keep their stride — `buffer_row_length` unpacks it. - pub(super) fn stage_frame(&mut self, f: &CpuFrame) -> Result<()> { - anyhow::ensure!( - f.stride % 4 == 0 && f.stride >= f.width as usize * 4, - "unexpected RGBA stride {} for width {}", - f.stride, - f.width - ); + /// Copy the frame's three tightly-packed planes into the staging buffer and (re)build + /// the plane images + video image on a stream-size change. + /// + /// Returns the per-plane staging offsets the record step copies from. Nothing here + /// touches the queue: a rebuild that fails must fail BEFORE the acquire, the same + /// rule the hardware imports follow. + pub(super) fn stage_frame(&mut self, f: &CpuPlanarFrame) -> Result<[usize; 3]> { if self .video .as_ref() @@ -50,15 +83,107 @@ impl Presenter { self.rebuild_video_image(f.width, f.height)?; tracing::info!(width = f.width, height = f.height, "video image (re)built"); } - let needed = f.stride * f.height as usize; + if self + .cpu_planes + .as_ref() + .is_none_or(|p| p.width != f.width || p.height != f.height) + { + self.rebuild_cpu_planes(f.width, f.height)?; + } + let (offsets, needed) = plane_staging_offsets(f); if self.staging.as_ref().is_none_or(|s| s.capacity < needed) { self.rebuild_staging(needed)?; } let s = self.staging.as_ref().unwrap(); - let n = f.rgba.len().min(needed); - // SAFETY: per the Vulkan contract above - the Vulkan handles used here are owned by this - // type and live for the call, and every builder struct is a local that outlives it. - unsafe { std::ptr::copy_nonoverlapping(f.rgba.as_ptr(), s.ptr, n) }; + for (i, off) in offsets.iter().enumerate() { + let plane = f.plane(i); + // SAFETY: per the Vulkan contract above - `s.ptr` maps a HOST_VISIBLE allocation of + // `s.capacity >= needed` bytes and `plane_staging_offsets` placed `off + plane.len()` + // inside `needed`; source and destination are distinct allocations. + unsafe { std::ptr::copy_nonoverlapping(plane.as_ptr(), s.ptr.add(*off), plane.len()) }; + } + Ok(offsets) + } + + /// (Re)build the software rung's three R8 plane images for a luma size. + fn rebuild_cpu_planes(&mut self, width: u32, height: u32) -> Result<()> { + // Fence-quiesce: the old images are only ever referenced by OUR command buffers. + self.quiesce_own()?; + if let Some(p) = self.cpu_planes.take() { + p.destroy(&self.device); + } + let (cw, ch) = CpuPlanarFrame::chroma_dims(width, height); + let dims = [(width, height), (cw, ch), (cw, ch)]; + // Built INTO the owning value, not into loose arrays: nine fallible steps (three + // images, three allocations, three views) used to `?` straight out and leak + // everything created before the one that failed — up to ~12 MB per size change at + // 4K, on the rung the client reaches because something already went wrong. + // `destroy` tolerates the nulls a partial build leaves (Vulkan defines + // destroy/free on `VK_NULL_HANDLE` as a no-op), so one call unwinds any prefix. + let mut planes = CpuPlanes { + images: [vk::Image::null(); 3], + memory: [vk::DeviceMemory::null(); 3], + views: [vk::ImageView::null(); 3], + width, + height, + initialized: false, + }; + for (i, dim) in dims.into_iter().enumerate() { + if let Err(e) = self.build_cpu_plane(&mut planes, i, dim) { + planes.destroy(&self.device); + return Err(e); + } + } + tracing::info!(width, height, "software plane images (re)built"); + self.cpu_planes = Some(planes); + Ok(()) + } + + /// One R8 plane of [`CpuPlanes`], written into `planes` as each handle is created so + /// a failure part-way leaves the caller something it can destroy. + fn build_cpu_plane(&self, planes: &mut CpuPlanes, i: usize, (w, h): (u32, u32)) -> Result<()> { + // SAFETY: per the Vulkan contract above - the Vulkan handles used here are owned by + // this type and live for the call, and every builder struct is a local that outlives + // it. + let image = unsafe { + self.device.create_image( + &vk::ImageCreateInfo::default() + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8_UNORM) + .extent(vk::Extent3D { + width: w, + height: h, + depth: 1, + }) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .usage(vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED) + .initial_layout(vk::ImageLayout::UNDEFINED), + None, + ) + }?; + planes.images[i] = image; + // SAFETY: per the Vulkan contract above - a read-only query on the live device. + let reqs = unsafe { self.device.get_image_memory_requirements(image) }; + planes.memory[i] = self.allocate(reqs, vk::MemoryPropertyFlags::DEVICE_LOCAL)?; + // SAFETY: per the Vulkan contract above - the Vulkan handles used here are owned by + // this type and live for the call. + unsafe { self.device.bind_image_memory(image, planes.memory[i], 0) }?; + // SAFETY: per the Vulkan contract above - the Vulkan handles used here are owned by + // this type and live for the call, and every builder struct is a local that outlives + // it. + planes.views[i] = unsafe { + self.device.create_image_view( + &vk::ImageViewCreateInfo::default() + .image(image) + .view_type(vk::ImageViewType::TYPE_2D) + .format(vk::Format::R8_UNORM) + .subresource_range(subresource_range()), + None, + ) + }?; Ok(()) } diff --git a/crates/pf-presenter/src/vk/setup.rs b/crates/pf-presenter/src/vk/setup.rs index 5ded5716..8977e39e 100644 --- a/crates/pf-presenter/src/vk/setup.rs +++ b/crates/pf-presenter/src/vk/setup.rs @@ -421,14 +421,14 @@ impl Presenter { ext_mem_win32: ash::khr::external_memory_win32::Device::new(&instance, &device), }); let csc = CscPass::new(&device, vk::Format::R8G8B8A8_UNORM)?; - // Starts SDR like `csc`; an HDR (PQ) pyrowave session rebuilds it at the 10-bit + // Starts SDR like `csc`; an HDR (PQ) session rebuilds it at the 10-bit // intermediate via `set_hdr_mode`, exactly like the H.26x pass. - #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] - let csc_planar = if pyrowave_ok { - Some(CscPass::new_planar(&device, vk::Format::R8G8B8A8_UNORM)?) - } else { - None - }; + // + // Unconditional since M8. It used to be built only for a device that passed the + // pyrowave probe; the SOFTWARE rung now renders through it too, and that rung is + // the ladder's last one — gating it on a probe would leave the boxes that failed + // the probe with no way to show a software-decoded frame at all. + let csc_planar = CscPass::new_planar(&device, vk::Format::R8G8B8A8_UNORM)?; // The exported handle bundle: FFmpeg Vulkan Video handles when the device can // decode, AND (Windows) the D3D11-interop facts — so it's built whenever EITHER @@ -590,8 +590,8 @@ impl Presenter { #[cfg(windows)] hw_win, csc, - #[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))] csc_planar, + cpu_planes: None, video_export, overlay_pipe, retired_hw: None,