From 6db374bb29ca7e84b717119d9ebe1994bcf55bc9 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 24 Sep 2026 19:03:42 -0700 Subject: [PATCH 1/5] quest: claim quest/m1/obs-moq-video/vpx Co-Authored-By: Claude Opus 5.5 From c93fe968654e3da41a1cb3c1b0ae4112fe660ef4 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 24 Sep 2026 19:30:45 -0700 Subject: [PATCH 2/5] feat(video): decode VP8 and VP9 through libvpx Co-Authored-By: Claude Opus 5.5 --- .github/workflows/nightly.yml | 5 + Cargo.lock | 36 ++ doc/bin/cli.md | 4 +- doc/lib/rs/moq-video.md | 5 +- flake.nix | 8 + quest/m1/obs-moq-video/README.md | 2 +- quest/m1/obs-moq-video/source.md | 2 +- quest/m1/obs-moq-video/vpx-obs.md | 19 + quest/m1/obs-moq-video/vpx.md | 17 - quest/m2/video-codec-coverage.md | 7 +- rs/moq-cli/Cargo.toml | 4 + rs/moq-video/Cargo.toml | 10 + rs/moq-video/README.md | 15 +- rs/moq-video/src/decode/backend/mediacodec.rs | 6 + .../src/decode/backend/mediafoundation.rs | 5 +- rs/moq-video/src/decode/backend/mod.rs | 25 +- rs/moq-video/src/decode/backend/nvdec.rs | 1 + .../src/decode/backend/videotoolbox.rs | 18 +- rs/moq-video/src/decode/backend/vpx.rs | 548 ++++++++++++++++++ rs/moq-video/src/decode/decoder.rs | 18 +- rs/moq-video/src/decode/mod.rs | 11 +- .../test_data/vp8_100x66_pattern_5f.ivf | Bin 0 -> 7952 bytes .../test_data/vp8_100x66_pattern_5f.yuv | 2 + .../decode/test_data/vp8_64x64_pattern_5f.ivf | Bin 0 -> 6804 bytes .../decode/test_data/vp8_64x64_pattern_5f.yuv | 2 + .../test_data/vp9_100x66_pattern_5f.ivf | Bin 0 -> 7452 bytes .../test_data/vp9_100x66_pattern_5f.yuv | 3 + .../decode/test_data/vp9_64x64_pattern_5f.ivf | Bin 0 -> 5284 bytes .../decode/test_data/vp9_64x64_pattern_5f.yuv | 1 + .../test_data/vp9_profile1_16x16_1f.ivf | Bin 0 -> 423 bytes rs/scripts/media-features.sh | 11 + 31 files changed, 734 insertions(+), 51 deletions(-) create mode 100644 quest/m1/obs-moq-video/vpx-obs.md delete mode 100644 quest/m1/obs-moq-video/vpx.md create mode 100644 rs/moq-video/src/decode/backend/vpx.rs create mode 100644 rs/moq-video/src/decode/test_data/vp8_100x66_pattern_5f.ivf create mode 100644 rs/moq-video/src/decode/test_data/vp8_100x66_pattern_5f.yuv create mode 100644 rs/moq-video/src/decode/test_data/vp8_64x64_pattern_5f.ivf create mode 100644 rs/moq-video/src/decode/test_data/vp8_64x64_pattern_5f.yuv create mode 100644 rs/moq-video/src/decode/test_data/vp9_100x66_pattern_5f.ivf create mode 100644 rs/moq-video/src/decode/test_data/vp9_100x66_pattern_5f.yuv create mode 100644 rs/moq-video/src/decode/test_data/vp9_64x64_pattern_5f.ivf create mode 100644 rs/moq-video/src/decode/test_data/vp9_64x64_pattern_5f.yuv create mode 100644 rs/moq-video/src/decode/test_data/vp9_profile1_16x16_1f.ivf diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9f73f46109..d63cfede2b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -327,5 +327,10 @@ jobs: - name: Install just run: cargo install --locked just@1.52.0 + # `--all-features` includes moq-video's `vpx`, whose build script finds + # libvpx through pkg-config. Nix provides it everywhere else. + - name: Install libvpx + run: brew install libvpx pkgconf + - name: Check run: just rs macos diff --git a/Cargo.lock b/Cargo.lock index c648a8d0a6..f74e1d9e6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3945,6 +3945,16 @@ dependencies = [ "system-deps", ] +[[package]] +name = "libvpx-native-sys" +version = "5.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "296dc47df55b51ac871fac5f30a61dd3c3ea3f56a076498a6785f5e6f2f6ea75" +dependencies = [ + "pkg-config", + "semver-parser", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -4906,6 +4916,7 @@ dependencies = [ "hang", "libc", "libloading 0.9.0", + "libvpx-native-sys", "linux-raw-sys 0.12.1", "moq-mux", "moq-net", @@ -6437,6 +6448,16 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d3aca230fad2e6f6317ca0a72724338c4960cb97168a85cdee66df4a9a21a8" +dependencies = [ + "memchr", + "ucd-trie", +] + [[package]] name = "pharos" version = "0.5.3" @@ -7718,6 +7739,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + [[package]] name = "send_wrapper" version = "0.6.0" @@ -9202,6 +9232,12 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "uds_windows" version = "1.2.1" diff --git a/doc/bin/cli.md b/doc/bin/cli.md index 01f38243ac..b479475b17 100644 --- a/doc/bin/cli.md +++ b/doc/bin/cli.md @@ -88,7 +88,9 @@ moq ... play --delay 500ms # trade latency for a jittery link ``` Decodes H.264, H.265, and AV1 video and Opus, PCM, and AAC-LC audio using -the platform hardware decoder where available. `--video-name` and +the platform hardware decoder where available. The opt-in `vpx` feature adds +software VP8 and VP9 (8-bit 4:2:0) through libvpx, which the build host must +provide. `--video-name` and `--audio-name` pick a rendition. Playback runs on a clock it owns. `--delay` (default 100 ms) is how far it diff --git a/doc/lib/rs/moq-video.md b/doc/lib/rs/moq-video.md index 11249d2e36..7249159b50 100644 --- a/doc/lib/rs/moq-video.md +++ b/doc/lib/rs/moq-video.md @@ -15,12 +15,12 @@ ffmpeg, no GStreamer, no system codec to install. | --- | --- | --- | | `capture` | Camera, display, window, or application frames | AVFoundation + ScreenCaptureKit (macOS), V4L2 + X11/portal + PipeWire (Linux), Media Foundation + DXGI (Windows) | | `encode` | Frames to H.264/H.265, published as a hang track | VideoToolbox, Media Foundation, NVENC, VAAPI, V4L2 M2M, MediaCodec (Android), openh264 | -| `decode` | A subscribed track back to frames | VideoToolbox, Media Foundation/DXVA, NVDEC, VAAPI, V4L2 M2M, MediaCodec (Android), openh264 | +| `decode` | A subscribed track back to frames | VideoToolbox, Media Foundation/DXVA, NVDEC, VAAPI, V4L2 M2M, MediaCodec (Android), openh264, libvpx | | `render` | A frame as a `wgpu` texture | wgpu, with zero-copy Metal and Vulkan imports | Highlights: -- **Automatic backend selection**, hardware first. Linux GPU libraries are `dlopen`ed at runtime, so one binary starts anywhere and warns when it falls back to software. openh264 (the default-on `openh264` feature) is statically linked as the H.264 fallback; H.265 is hardware-only; AV1 decodes via NVDEC. The VAAPI encoder, decoder, and GPU resize share one render node: the first whose driver does all three, or the one the `MOQ_VAAPI_DEVICE` environment variable names (for example `/dev/dri/renderD129`). +- **Automatic backend selection**, hardware first. Linux GPU libraries are `dlopen`ed at runtime, so one binary starts anywhere and warns when it falls back to software. openh264 (the default-on `openh264` feature) is statically linked as the H.264 fallback; H.265 is hardware-only; AV1 decodes via NVDEC. VP8 and VP9 decode in software through libvpx (the opt-in `vpx` feature), 8-bit 4:2:0 only: other VP9 profiles are refused rather than converted. The VAAPI encoder, decoder, and GPU resize share one render node: the first whose driver does all three, or the one the `MOQ_VAAPI_DEVICE` environment variable names (for example `/dev/dri/renderD129`). - **Publish on demand.** `encode::publish_capture` advertises the track up front and opens the camera only while someone subscribes. - **GPU ownership where the platform allows.** Matching codec backends consume their native GPU surfaces directly. The renderer imports `CVPixelBuffer` and supported DMA-BUF formats. Linux/NVIDIA producers can import dedicated Vulkan RGBA8 slots into CUDA with timeline-semaphore ordering and completion-driven slot return. Vulkan/CUDA surfaces deliberately have no CPU pixel fallback; other surfaces use the typed `Surface::into_i420()` and configured `Surface::to_rgba(config)` when needed. - **Live bitrate control** where the selected backend supports it, without forcing a keyframe. An unsupported backend keeps its opening rate. @@ -70,6 +70,7 @@ cargo add moq-video --features render # wgpu rendering cargo add moq-video --features v4l2 # Linux V4L2 M2M codecs, no system build deps cargo add moq-video --features vaapi # Linux VAAPI codecs (bindgen needs libclang) cargo add moq-video --features pipewire # Wayland screen + PipeWire cameras (links libpipewire) +cargo add moq-video --features vpx # VP8/VP9 decode (links libvpx; VPX_STATIC=1 for the archive) cargo add moq-video --no-default-features --features openh264 # software H.264 only cargo add moq-video --no-default-features --features nvidia # Linux NVIDIA only, no C++ or wgpu ``` diff --git a/flake.nix b/flake.nix index 028422fd1b..b88bb3bef5 100644 --- a/flake.nix +++ b/flake.nix @@ -109,6 +109,10 @@ glib libressl ffmpeg + # moq-video's `vpx` feature (VP8/VP9 software decode): libvpx-native-sys + # finds it through pkg-config, and `VPX_STATIC` below links the archive + # so nothing built here needs libvpx.so at runtime. + libvpx curl # MPEG-TS validation (tsp, tsanalyze) for the ts-compliance harness. tsduck @@ -515,6 +519,10 @@ # Exported rather than read back out of nix, so the guard costs a # variable lookup instead of a nested evaluation of this flake. OBS_LINKED_VERSION = obs-linked-version; + + # Link libvpx statically for moq-video's `vpx` feature, the shape the + # quest ships: no system codec library at runtime. + VPX_STATIC = "1"; } // pkgs.lib.optionalAttrs (!pkgs.stdenv.hostPlatform.isDarwin) { ALSA_PLUGIN_DIR = "${alsaPlugins}/lib/alsa-lib"; diff --git a/quest/m1/obs-moq-video/README.md b/quest/m1/obs-moq-video/README.md index 17660ac693..b34fd1228b 100644 --- a/quest/m1/obs-moq-video/README.md +++ b/quest/m1/obs-moq-video/README.md @@ -29,7 +29,7 @@ The quests separate portable decoding, platform GPU delivery, audio, and publish - [Rate control](/quest/m1/obs-moq-video/rate-control.md) - the plugin reserves its bitrate and retunes the OBS encoder to the grant - [macOS GPU input](/quest/m1/obs-moq-video/macos.md) - feed the encoder from the OBS compositor without CPU readback - [Windows GPU input](/quest/m1/obs-moq-video/windows.md) - import or blit OBS D3D11 textures with explicit synchronization -- [VP8/VP9 decoding](/quest/m1/obs-moq-video/vpx.md) - restore those playback codecs without an FFmpeg ABI dependency +- [VP8/VP9 in OBS](/quest/m1/obs-moq-video/vpx-obs.md) - play VP8 and VP9 through moq-video's libvpx backend on every OBS platform ## Related diff --git a/quest/m1/obs-moq-video/source.md b/quest/m1/obs-moq-video/source.md index bda7405331..17aab4a18c 100644 --- a/quest/m1/obs-moq-video/source.md +++ b/quest/m1/obs-moq-video/source.md @@ -21,4 +21,4 @@ The MoQ source loads and plays supported video without directly linking FFmpeg l - [Decoded frame ownership](/quest/m1/decoded-frames.md) - the decoded-frame consumer moq-ffi does not have yet ## Related -- [VP8/VP9 decoding](/quest/m1/obs-moq-video/vpx.md) - restores deferred codec coverage independently +- [VP8/VP9 in OBS](/quest/m1/obs-moq-video/vpx-obs.md) - restores deferred codec coverage once this lands diff --git a/quest/m1/obs-moq-video/vpx-obs.md b/quest/m1/obs-moq-video/vpx-obs.md new file mode 100644 index 0000000000..dc7fe46989 --- /dev/null +++ b/quest/m1/obs-moq-video/vpx-obs.md @@ -0,0 +1,19 @@ +# [M] VP8/VP9 in the OBS source + +## Goal + +The OBS MoQ source plays VP8 and VP9 (8-bit 4:2:0) on every platform it ships for, through moq-video's libvpx backend with libvpx statically linked, and no FFmpeg ABI or undeclared system codec library. + +## Plan + +- moq-video decodes both codecs behind its opt-in `vpx` feature, with libvpx supplied by the build host (`libvpx-native-sys`, `VPX_STATIC=1`). Turn it on in moq-ffi and libmoq for the OBS builds only, not for every binding artifact. +- macOS and Linux build through Nix, which already provides libvpx. The Windows MSVC build runs without Nix and needs a static libvpx: evaluate vcpkg's `libvpx:x64-windows-static` against an in-tree vendored libvpx build (C-only config first, SIMD later) and pick one. The vendored build is also what a crates.io consumer without libvpx would need. +- Verify decoded pixels in the source, CPU delivery, reconnect, and rendition changes, and inspect the plugin's imports for libvpx, avcodec, and avutil on each platform. + +## Required + +- [Video source replacement](/quest/m1/obs-moq-video/source.md) - the source decodes through moq-video first + +## Related + +- [Codec coverage](/quest/m2/video-codec-coverage.md) - hardware VP8/VP9 decode belongs to that review diff --git a/quest/m1/obs-moq-video/vpx.md b/quest/m1/obs-moq-video/vpx.md deleted file mode 100644 index 528d73b124..0000000000 --- a/quest/m1/obs-moq-video/vpx.md +++ /dev/null @@ -1,17 +0,0 @@ -# [L] Add VP8 and VP9 decoding to moq-video - -## Goal - -MoQ consumers, including the OBS source, decode VP8 and VP9 without depending on FFmpeg's ABI. This restores playback coverage deferred by the OBS decoder replacement; encoding is outside this quest. - -## Plan - -- Use vendored, statically linked libvpx as the initial portable decoder, preferring a maintained Rust binding over a bespoke wrapper. Its upstream SDK covers both VP8 and VP9. Pin a current stable release when implementing and validate licensing, packaged sources, supported profiles/bit depths, assembly tools, and Windows cross-build requirements. A dynamic FFmpeg wrapper does not meet the goal. See the [upstream build guide](https://chromium.googlesource.com/webm/libvpx/+/refs/heads/main/README). -- Integrate through moq-video's existing decode configuration and owned surface abstraction. Start with a portable software path; reuse native GPU output where available without making it a requirement for baseline support. Preserve timestamps, resolution changes, color metadata, keyframe recovery, and decoder reset behavior. -- Reconcile hang codec strings, existing VP8/VP9 mux metadata, catalog parsing, and binding documentation. Unsupported profiles must produce explicit errors rather than decode incorrectly. Add fixture coverage across key/delta frames, corruption, resolution changes, and end-of-stream. -- Verify actual decoded pixels in Rust and the OBS source, CPU fallback, reconnect, and resource ownership. Inspect plugin/library imports and Cargo package contents to ensure no FFmpeg ABI dependency or undeclared system codec library was introduced. - -## Related - -- [Video source replacement](/quest/m1/obs-moq-video/source.md) - consumer integration, not a blocker for codec implementation -- [Color model](/quest/m1/color-model.md) - share codec-neutral color metadata rather than introducing VP9-only conversions diff --git a/quest/m2/video-codec-coverage.md b/quest/m2/video-codec-coverage.md index 36b369303b..d7b05a2874 100644 --- a/quest/m2/video-codec-coverage.md +++ b/quest/m2/video-codec-coverage.md @@ -14,8 +14,9 @@ and a portable software AV1 fallback such as OS, extension, hardware, format, and fixture requirements; a browser playing a codec is not proof that our native backend can open it. -NVIDIA AV1 encode/10-bit, VAAPI expansion, and VP8/VP9 already have quests. -Keep those owners. Windows NVIDIA support needs a demonstrated advantage over +NVIDIA AV1 encode/10-bit and VAAPI expansion already have quests. Keep those +owners. Software VP8/VP9 decode is libvpx behind moq-video's `vpx` feature; +hardware VP8/VP9 decode is in scope here. Windows NVIDIA support needs a demonstrated advantage over the existing native path. If revisiting software AV1 encoding, measure the target real-time workload and build cost rather than assuming all presets or all hardware are equivalent. Optional codec dependencies stay optional. @@ -31,4 +32,4 @@ Public API and wire: no changes during this study. - [NVIDIA formats](/quest/m2/2147-moq-video-10-bit-hevc-and-av1-support-in-the-nvidia-codec.md) - existing AV1 encode and 10-bit scope - [VAAPI](/quest/m4/video-vaapi.md) - existing Linux codec expansion -- [VP8/VP9](/quest/m1/obs-moq-video/vpx.md) - existing portable decoder scope +- [VP8/VP9 in OBS](/quest/m1/obs-moq-video/vpx-obs.md) - the software decoder reaching the OBS source diff --git a/rs/moq-cli/Cargo.toml b/rs/moq-cli/Cargo.toml index 2772aba046..b74a8b0c9a 100644 --- a/rs/moq-cli/Cargo.toml +++ b/rs/moq-cli/Cargo.toml @@ -74,6 +74,10 @@ vaapi = ["moq-video?/vaapi", "moq-transcode?/vaapi"] # checks its bindings in. Only applies when `capture`, `transcode`, or `play` # pulls in moq-video. v4l2 = ["moq-video?/v4l2", "moq-transcode?/v4l2"] +# Software VP8 / VP9 decode through libvpx, opt-in like the moq-video feature it +# turns on because libvpx comes from the build host. Only applies when `play` +# pulls in moq-video. +vpx = ["moq-video?/vpx"] # Screen capture for `capture --display` on Linux (xdg-desktop-portal + PipeWire) # and PipeWire cameras for `capture --camera pipewire:`, opt-in like moq-video's own `pipewire` because it links libpipewire-0.3 at # build time. Only bites when `capture` pulls in moq-video and moq-audio. diff --git a/rs/moq-video/Cargo.toml b/rs/moq-video/Cargo.toml index e1b735dfc5..a67cfaa418 100644 --- a/rs/moq-video/Cargo.toml +++ b/rs/moq-video/Cargo.toml @@ -47,6 +47,13 @@ nvidia = ["dep:cudarc", "dep:moq-nvenc", "dep:libloading"] # Vendored, statically linked software H.264 encode/decode. Enabled by default, # but separable from native codecs for hardware-only and minimal builds. openh264 = ["dep:openh264", "dep:openh264-sys2"] +# Software VP8 and VP9 decode through libvpx, on every platform. Off by default +# because libvpx comes from the build host: libvpx-native-sys finds it through +# pkg-config (or `VPX_LIB_DIR` + `VPX_VERSION`) and ships pregenerated bindings, +# so no libclang is needed. Set `VPX_STATIC=1` to link the archive rather than +# libvpx.so, which is what the Nix dev shell does. Decodes 8-bit 4:2:0 only (VP8, +# and VP9 profile 0); anything else is refused rather than converted. +vpx = ["dep:libvpx-native-sys"] # Intel/AMD VAAPI hardware codecs (Linux): the H.264 encoder and decoder. Off by # default because moq-vaapi's build script runs bindgen over its vendored libva # headers, so the build host needs libclang. At runtime libva is dlopen'd: the @@ -106,6 +113,9 @@ bytes = { workspace = true } fast_image_resize = "6" # Catalog types (VideoConfig / VideoCodec) the decode consumer reads. hang = { workspace = true } +# libvpx bindings for the `vpx` feature. The library itself comes from the build +# host; see the feature above. +libvpx-native-sys = { version = "5.0.17", optional = true } moq-mux = { workspace = true } moq-net = { workspace = true } # Vendored, statically linked software H.264 fallback (no system dependency). diff --git a/rs/moq-video/README.md b/rs/moq-video/README.md index cc2ae3d1d3..1c0970c5fc 100644 --- a/rs/moq-video/README.md +++ b/rs/moq-video/README.md @@ -104,8 +104,10 @@ a working software H.264 fallback but compiles vendored C++; disable defaults and select native features to omit it. `nvidia` is Linux-only, `dlopen`s the driver at runtime, and needs no build-time toolkit. `vaapi` is opt-in because its bindgen needs libclang on the build host, while `v4l2` is opt-in only by -convention, since `moq-v4l` checks its bindings in. `render` is also opt-in so -codec-only consumers do not compile wgpu. +convention, since `moq-v4l` checks its bindings in. `vpx` is opt-in because +libvpx comes from the build host through pkg-config (set `VPX_STATIC=1` to link +the archive, as the Nix dev shell does). `render` is also opt-in so codec-only +consumers do not compile wgpu. ### Vulkan producers on NVIDIA @@ -151,7 +153,7 @@ instead of asserting a threshold. ## Decode `decode::Consumer` (the mirror of `moq_audio::decode::Consumer`) subscribes to an -H.264, H.265, or AV1 track and returns raw `Frame`s. A hardware-decoded frame stays +H.264, H.265, AV1, VP8, or VP9 track and returns raw `Frame`s. A hardware-decoded frame stays on the GPU: feeding it back to a compatible hardware `encode::Encoder` on the same device keeps it there (the transcode path), while `into_i420()` downloads it. An encoder that can't take that surface (openh264, or a different device) @@ -179,6 +181,7 @@ Backends are tried hardware-first, like encode: | H.264 | OpenH264 (feature `openh264`, default) | VideoToolbox | Media Foundation (DXVA) | NVDEC (feature `nvidia`), VAAPI (feature `vaapi`) | MediaCodec (feature `mediacodec`, API 26+) | | H.265 | none | VideoToolbox | Media Foundation (DXVA) | NVDEC (feature `nvidia`) | MediaCodec (feature `mediacodec`, API 26+) | | AV1 | none | none | none | NVDEC (feature `nvidia`) | MediaCodec (feature `mediacodec`, when the device provides it) | +| VP8, VP9 | libvpx (feature `vpx`) | none | none | none | none | On macOS VideoToolbox decodes H.264 and H.265 on hardware, pulling the parameter sets (SPS/PPS, plus VPS for H.265) out of each keyframe to build the format @@ -189,8 +192,10 @@ no software decoder, so it needs the GPU path (on Windows, an HEVC decoder MFT: the inbox HEVC Video Extensions or a vendor one). On Linux, NVDEC decodes H.264, H.265, and 8-bit 4:2:0 AV1 to CUDA NV12 frames; AV1 is decode-only and is useful for AV1 source to H.264/H.265 transcode rungs. VAAPI decodes H.264 to DMA-BUF -surfaces the renderer imports without a download. A non-H.264/H.265/AV1 -rendition yields `Error::UnsupportedCodec`. +surfaces the renderer imports without a download. libvpx decodes VP8 and VP9 +profile 0 to CPU I420 on every platform; other VP9 profiles (4:4:4, 10-bit) are +refused rather than narrowed to 8-bit 4:2:0. Any other rendition yields +`Error::UnsupportedCodec`. `decode::Config::output` says where decoded pictures live: `Output::Native` (the default) hands back whatever the backend decoded into, a GPU surface or diff --git a/rs/moq-video/src/decode/backend/mediacodec.rs b/rs/moq-video/src/decode/backend/mediacodec.rs index 6cd1340d4f..ec2076c4b6 100644 --- a/rs/moq-video/src/decode/backend/mediacodec.rs +++ b/rs/moq-video/src/decode/backend/mediacodec.rs @@ -160,6 +160,12 @@ impl MediaCodec { Codec::H264 => MIME_H264, Codec::H265 => MIME_H265, Codec::Av1 => MIME_AV1, + other => { + return Err(Error::Codec(anyhow::anyhow!( + "MediaCodec {} decode is not wired", + other.label() + ))); + } }; // `GPU_SAMPLED_IMAGE` is what a consumer importing the buffer as a texture diff --git a/rs/moq-video/src/decode/backend/mediafoundation.rs b/rs/moq-video/src/decode/backend/mediafoundation.rs index e136d73c4e..64ebfec3ac 100644 --- a/rs/moq-video/src/decode/backend/mediafoundation.rs +++ b/rs/moq-video/src/decode/backend/mediafoundation.rs @@ -106,9 +106,10 @@ impl MediaFoundation { let (input_subtype, label) = match codec { Codec::H264 => (MFVideoFormat_H264, "H.264"), Codec::H265 => (MFVideoFormat_HEVC, "H.265"), - Codec::Av1 => { + Codec::Av1 | Codec::Vp8 | Codec::Vp9 => { return Err(Error::Codec(anyhow::anyhow!( - "Media Foundation AV1 decode is not wired" + "Media Foundation {} decode is not wired", + codec.label() ))); } }; diff --git a/rs/moq-video/src/decode/backend/mod.rs b/rs/moq-video/src/decode/backend/mod.rs index 771364f22b..47435c5735 100644 --- a/rs/moq-video/src/decode/backend/mod.rs +++ b/rs/moq-video/src/decode/backend/mod.rs @@ -9,10 +9,11 @@ //! [`open`] picks the best backend for a [`Codec`] and [`Config`], trying //! hardware candidates (platform-gated: VideoToolbox on macOS, Media Foundation //! / DXVA on Windows, MediaCodec on Android, NVDEC, VAAPI, then V4L2 on Linux) before -//! the OpenH264 software fallback when this build enables it, exactly like the -//! encode side. Only backends that support the requested codec are considered: -//! there is no software H.265 or AV1 decoder, so those tracks have no fallback -//! below the hardware path. +//! the software decoders this build enables (OpenH264 for H.264, libvpx for VP8 +//! and VP9), exactly like the encode side. Only backends that support the +//! requested codec are considered: there is no software H.265 or AV1 decoder, so +//! those tracks have no fallback below the hardware path. VP8 / VP9 backends +//! take one coded frame per call. use bytes::Bytes; use moq_net::Timestamp; @@ -26,6 +27,9 @@ mod openh264; #[cfg(test)] pub(crate) mod probe; +#[cfg(feature = "vpx")] +mod vpx; + #[cfg(target_os = "macos")] mod videotoolbox; @@ -56,6 +60,10 @@ pub enum Codec { H265, /// AV1 video. Av1, + /// VP8 video. + Vp8, + /// VP9 video. + Vp9, } impl Codec { @@ -64,6 +72,8 @@ impl Codec { Codec::H264 => "H.264", Codec::H265 => "H.265", Codec::Av1 => "AV1", + Codec::Vp8 => "VP8", + Codec::Vp9 => "VP9", } } } @@ -103,6 +113,7 @@ pub const NAMES: &[&str] = &[ "vaapi", "v4l2", "openh264", + "vpx", ]; /// A backend opener: builds a decoder for a codec and config. @@ -166,6 +177,12 @@ const SOFTWARE: &[Candidate] = &[ supports: |c| matches!(c, Codec::H264), open: openh264::Openh264::open, }, + #[cfg(feature = "vpx")] + Candidate { + name: vpx::NAME, + supports: |c| matches!(c, Codec::Vp8 | Codec::Vp9), + open: vpx::Vpx::open, + }, ]; /// Test-only backends. Deliberately in neither list above, so `Auto` / diff --git a/rs/moq-video/src/decode/backend/nvdec.rs b/rs/moq-video/src/decode/backend/nvdec.rs index 0a1883b45b..c683d4f4a0 100644 --- a/rs/moq-video/src/decode/backend/nvdec.rs +++ b/rs/moq-video/src/decode/backend/nvdec.rs @@ -110,6 +110,7 @@ impl Nvdec { Codec::H264 => cudaVideoCodec::cudaVideoCodec_H264, Codec::H265 => cudaVideoCodec::cudaVideoCodec_HEVC, Codec::Av1 => cudaVideoCodec::cudaVideoCodec_AV1, + other => return Err(codec_err(format!("NVDEC {} decode is not wired", other.label()))), }; // `CudaContext::new` retains the device's primary context, the same one diff --git a/rs/moq-video/src/decode/backend/videotoolbox.rs b/rs/moq-video/src/decode/backend/videotoolbox.rs index ed531be6d7..3e959d4cd7 100644 --- a/rs/moq-video/src/decode/backend/videotoolbox.rs +++ b/rs/moq-video/src/decode/backend/videotoolbox.rs @@ -97,8 +97,11 @@ impl VideoToolbox { /// `config` is accepted for signature parity; VideoToolbox decodes at the /// stream's native size (callers scale the frames themselves). pub(crate) fn open(codec: Codec, _config: &Config) -> Result, Error> { - if codec == Codec::Av1 { - return Err(Error::Codec(anyhow::anyhow!("VideoToolbox AV1 decode is not wired"))); + if !matches!(codec, Codec::H264 | Codec::H265) { + return Err(Error::Codec(anyhow::anyhow!( + "VideoToolbox {} decode is not wired", + codec.label() + ))); } tracing::info!(decoder = NAME, codec = ?codec, "opened video decoder"); Ok(Box::new(Self { @@ -124,7 +127,7 @@ impl VideoToolbox { match self.codec { Codec::H264 => Some(vec![sps, pps]), Codec::H265 => Some(vec![self.vps.clone()?, sps, pps]), - Codec::Av1 => None, + Codec::Av1 | Codec::Vp8 | Codec::Vp9 => None, } } @@ -396,8 +399,11 @@ fn create_format_description(codec: Codec, params: &[Bytes]) -> Result { - return Err(Error::Codec(anyhow::anyhow!("VideoToolbox AV1 decode is not wired"))); + Codec::Av1 | Codec::Vp8 | Codec::Vp9 => { + return Err(Error::Codec(anyhow::anyhow!( + "VideoToolbox {} decode is not wired", + codec.label() + ))); } }; NonNull::new(format_ptr as *mut CMFormatDescription) @@ -519,7 +525,7 @@ fn nal_kind(nal: &[u8], codec: Codec) -> NalKind { 34 => NalKind::Pps, _ => NalKind::Slice, }, - Codec::Av1 => NalKind::Slice, + Codec::Av1 | Codec::Vp8 | Codec::Vp9 => NalKind::Slice, } } diff --git a/rs/moq-video/src/decode/backend/vpx.rs b/rs/moq-video/src/decode/backend/vpx.rs new file mode 100644 index 0000000000..5c93b2badf --- /dev/null +++ b/rs/moq-video/src/decode/backend/vpx.rs @@ -0,0 +1,548 @@ +//! Software VP8 and VP9 decode backend via libvpx. +//! +//! The portable path for both codecs, on every platform. Takes one coded frame +//! per call, exactly as a hang track carries it (a VP9 superframe stays one +//! unit), and returns packed I420. +//! +//! Only 8-bit 4:2:0 comes out: VP8, and VP9 profile 0. libvpx decodes the other +//! VP9 profiles too, but narrowing 4:4:4 or 10-bit samples to I420 would hand +//! back a different picture than the stream coded, so a picture in any other +//! format is refused rather than converted. + +use std::ffi::CStr; +use std::ptr; + +use bytes::Bytes; +use moq_net::Timestamp; +use vpx_sys::{ + VPX_DECODER_ABI_VERSION, vpx_codec_ctx_t, vpx_codec_dec_cfg_t, vpx_codec_dec_init_ver, vpx_codec_decode, + vpx_codec_destroy, vpx_codec_err_t, vpx_codec_err_to_string, vpx_codec_error_detail, vpx_codec_get_frame, + vpx_codec_iter_t, vpx_codec_vp8_dx, vpx_codec_vp9_dx, vpx_color_range, vpx_color_space, vpx_image_t, vpx_img_fmt, +}; + +use super::{Backend, Codec, Config}; +use crate::frame::{I420, Surface}; +use crate::{Color, Error, Frame, Size}; + +pub(crate) const NAME: &str = "vpx"; + +pub(crate) struct Vpx { + ctx: vpx_codec_ctx_t, + codec: Codec, + /// A frame was refused, so the reference chain is broken until the next + /// keyframe. Delta frames in between are dropped rather than decoded against + /// references that are missing or wrong. + broken: bool, + /// Frames dropped since the chain broke, so a run of them logs once. + lost: u64, +} + +impl Vpx { + pub(crate) fn open(codec: Codec, config: &Config) -> Result, Error> { + Ok(Box::new(Self::new(codec, config)?)) + } + + /// libvpx has no scaler, so `config` only matters to the front end. + fn new(codec: Codec, _config: &Config) -> Result { + // SAFETY: both return a pointer to a static interface table. + let iface = unsafe { + match codec { + Codec::Vp8 => vpx_codec_vp8_dx(), + Codec::Vp9 => vpx_codec_vp9_dx(), + other => { + return Err(Error::Codec(anyhow::anyhow!("{NAME} cannot decode {}", other.label()))); + } + } + }; + + // libvpx bounds this itself: VP8 to 8 threads, VP9 to its tile columns. + let threads = std::thread::available_parallelism().map_or(1, |n| n.get()); + let cfg = vpx_codec_dec_cfg_t { + threads: u32::try_from(threads).unwrap_or(1), + w: 0, + h: 0, + }; + + let mut ctx = vpx_codec_ctx_t::default(); + // SAFETY: `ctx` is zeroed and outlives the call; libvpx copies `cfg`. + let err = unsafe { vpx_codec_dec_init_ver(&mut ctx, iface, &cfg, 0, VPX_DECODER_ABI_VERSION as i32) }; + if err != vpx_codec_err_t::VPX_CODEC_OK { + return Err(Error::Codec(anyhow::anyhow!( + "{NAME} {} decoder init: {}", + codec.label(), + describe(err, None) + ))); + } + + tracing::info!(decoder = NAME, codec = codec.label(), "opened decoder"); + Ok(Self { + ctx, + codec, + broken: false, + lost: 0, + }) + } + + /// The error libvpx reported for the last call, with its detail string when it + /// left one. + fn error(&self, err: vpx_codec_err_t) -> String { + // SAFETY: the context is initialized, and the detail string is owned by it. + let detail = unsafe { + let detail = vpx_codec_error_detail(&self.ctx); + (!detail.is_null()).then(|| CStr::from_ptr(detail).to_string_lossy().into_owned()) + }; + describe(err, detail) + } + + /// Records a frame the decoder refused, or one dropped while waiting for a + /// keyframe, and logs the first of a run. + fn picture_lost(&mut self, reason: &str) { + self.broken = true; + self.lost += 1; + if self.lost == 1 { + tracing::warn!(decoder = NAME, codec = self.codec.label(), reason, "picture lost, waiting for the next keyframe"); + } else { + tracing::trace!(decoder = NAME, reason, "picture lost"); + } + } +} + +/// libvpx's name for `err`, plus the detail when there is one. +fn describe(err: vpx_codec_err_t, detail: Option) -> String { + // SAFETY: returns a pointer to a static string for every error code. + let name = unsafe { CStr::from_ptr(vpx_codec_err_to_string(err)) }.to_string_lossy(); + match detail { + Some(detail) => format!("{name}: {detail}"), + None => name.into_owned(), + } +} + +/// Whether `err` describes the frame rather than the decoder. +/// +/// A truncated or damaged frame is ordinary on a lossy path, and libvpx stays +/// usable after it: the next keyframe restores the picture. Anything else (out +/// of memory, a bad argument) says the decoder itself is in trouble. +fn describes_frame(err: vpx_codec_err_t) -> bool { + matches!( + err, + vpx_codec_err_t::VPX_CODEC_CORRUPT_FRAME | vpx_codec_err_t::VPX_CODEC_UNSUP_BITSTREAM + ) +} + +/// The color space libvpx reports for a picture, when [`Color`] can name it. +fn color(codec: Codec, img: &vpx_image_t) -> Option { + let full = img.range == vpx_color_range::VPX_CR_FULL_RANGE; + match (codec, img.cs) { + // VP8 defines one color space (RFC 6386 section 9.2): BT.601, studio + // swing. libvpx leaves `cs` unset for it. + (Codec::Vp8, _) => Some(Color::Bt601Limited), + (_, vpx_color_space::VPX_CS_BT_601 | vpx_color_space::VPX_CS_SMPTE_170) => Some(match full { + true => Color::Bt601Full, + false => Color::Bt601Limited, + }), + (_, vpx_color_space::VPX_CS_BT_709) => Some(match full { + true => Color::Bt709Full, + false => Color::Bt709Limited, + }), + _ => None, + } +} + +/// Copies one decoded picture out of libvpx's frame buffer. +fn picture(codec: Codec, img: &vpx_image_t, timestamp: Timestamp) -> Result { + if img.fmt != vpx_img_fmt::VPX_IMG_FMT_I420 || img.bit_depth != 8 { + return Err(Error::UnsupportedCodec(format!( + "{} picture in {:?} at {} bits; only 8-bit 4:2:0 is supported", + codec.label(), + img.fmt, + img.bit_depth + ))); + } + + let size = Size::new(img.d_w, img.d_h); + if !size.width.is_multiple_of(2) || !size.height.is_multiple_of(2) { + return Err(Error::Codec(anyhow::anyhow!( + "decoded frame has odd dimensions {size}, expected 4:2:0" + ))); + } + + let (w, h) = (size.width as usize, size.height as usize); + let mut data = vec![0u8; I420::len(size)?]; + let (luma, chroma) = data.split_at_mut(w * h); + let (u, v) = chroma.split_at_mut(w * h / 4); + for (plane, dst, width) in [(0, luma, w), (1, u, w / 2), (2, v, w / 2)] { + let stride = img.stride[plane] as usize; + for (row, dst) in dst.chunks_exact_mut(width).enumerate() { + // SAFETY: libvpx guarantees every row of an 8-bit I420 picture holds at + // least `width` samples, `stride` bytes after the one above it. + let src = unsafe { std::slice::from_raw_parts(img.planes[plane].add(row * stride), width) }; + dst.copy_from_slice(src); + } + } + + let mut i420 = I420::new(size, data)?; + i420.color = color(codec, img); + Ok(Frame::new(Surface::I420(i420), timestamp)) +} + +impl Backend for Vpx { + fn decode(&mut self, frame: Bytes, timestamp: Timestamp, keyframe: bool) -> Result, Error> { + if self.broken { + if !keyframe { + self.picture_lost("reference chain broken"); + return Ok(Vec::new()); + } + tracing::info!(decoder = NAME, lost = self.lost, "picture recovered"); + self.broken = false; + self.lost = 0; + } + + let len = u32::try_from(frame.len()).map_err(|_| { + Error::Codec(anyhow::anyhow!( + "{} frame of {} bytes is too large", + self.codec.label(), + frame.len() + )) + })?; + // SAFETY: `frame` outlives the call, and libvpx keeps no pointer into it. + let err = unsafe { vpx_codec_decode(&mut self.ctx, frame.as_ptr(), len, ptr::null_mut(), 0) }; + if err != vpx_codec_err_t::VPX_CODEC_OK { + let reason = self.error(err); + if !describes_frame(err) { + return Err(Error::Codec(anyhow::anyhow!("{NAME} decode: {reason}"))); + } + self.picture_lost(&reason); + return Ok(Vec::new()); + } + + // Without frame threading a call hands back at most the one picture it + // shows, so the input timestamp is that picture's. A frame that is not + // shown (a VP8 alt-ref coded on its own) hands back none. + let mut frames = Vec::new(); + let mut iter: vpx_codec_iter_t = ptr::null(); + // SAFETY: each image stays valid until the next decode call. + while let Some(img) = unsafe { vpx_codec_get_frame(&mut self.ctx, &mut iter).as_ref() } { + frames.push(picture(self.codec, img, timestamp)?); + } + Ok(frames) + } + + /// libvpx decodes without delay here, so nothing is ever held back. + fn flush(&mut self) -> Result, Error> { + Ok(Vec::new()) + } + + fn name(&self) -> &str { + NAME + } +} + +impl Drop for Vpx { + fn drop(&mut self) { + // SAFETY: the context was initialized in `new` and is destroyed once. + unsafe { vpx_codec_destroy(&mut self.ctx) }; + } +} + +#[cfg(test)] +mod tests { + //! Decodes committed libvpx streams and compares every sample against ffmpeg's + //! decode of the same stream. ffmpeg's VP8 and VP9 decoders are its own, not + //! libvpx, and both formats decode bit-exactly, so the comparison is exact. + //! + //! Realtime, 30fps, a keyframe every 4 frames (I P P P I), generated with: + //! + //! ```text + //! gen() { ffmpeg -f lavfi -i "testsrc2=s=$2:r=30" -frames:v 5 -c:v $1 \ + //! -deadline realtime -cpu-used 8 -lag-in-frames 0 -g 4 -keyint_min 4 \ + //! -b:v 200k -pix_fmt yuv420p -f ivf $3 + //! ffmpeg -i $3 -f rawvideo -pix_fmt yuv420p ${3%.ivf}.yuv; } + //! gen libvpx 64x64 vp8_64x64_pattern_5f.ivf + //! gen libvpx 100x66 vp8_100x66_pattern_5f.ivf + //! gen libvpx-vp9 64x64 vp9_64x64_pattern_5f.ivf + //! gen libvpx-vp9 100x66 vp9_100x66_pattern_5f.ivf + //! ffmpeg -f lavfi -i "testsrc2=s=16x16:r=30" -frames:v 1 -c:v libvpx-vp9 \ + //! -deadline realtime -pix_fmt yuv444p -f ivf vp9_profile1_16x16_1f.ivf + //! ``` + + use hang::catalog::{VP9, VideoCodec, VideoConfig}; + + use super::*; + use crate::decode::{Decoder, Kind}; + + /// A committed stream and the pictures it has to decode to. + struct Vector { + name: &'static str, + codec: Codec, + ivf: &'static [u8], + yuv: &'static [u8], + width: u32, + height: u32, + } + + impl Vector { + fn size(&self) -> Size { + Size::new(self.width, self.height) + } + } + + const VP8_64: Vector = Vector { + name: "vp8_64x64_pattern_5f", + codec: Codec::Vp8, + ivf: include_bytes!("../test_data/vp8_64x64_pattern_5f.ivf"), + yuv: include_bytes!("../test_data/vp8_64x64_pattern_5f.yuv"), + width: 64, + height: 64, + }; + + /// Not a multiple of the 16-pixel macroblock, so a decoder that hands back the + /// coded size instead of the display size fails. + const VP8_100: Vector = Vector { + name: "vp8_100x66_pattern_5f", + codec: Codec::Vp8, + ivf: include_bytes!("../test_data/vp8_100x66_pattern_5f.ivf"), + yuv: include_bytes!("../test_data/vp8_100x66_pattern_5f.yuv"), + width: 100, + height: 66, + }; + + const VP9_64: Vector = Vector { + name: "vp9_64x64_pattern_5f", + codec: Codec::Vp9, + ivf: include_bytes!("../test_data/vp9_64x64_pattern_5f.ivf"), + yuv: include_bytes!("../test_data/vp9_64x64_pattern_5f.yuv"), + width: 64, + height: 64, + }; + + const VP9_100: Vector = Vector { + name: "vp9_100x66_pattern_5f", + codec: Codec::Vp9, + ivf: include_bytes!("../test_data/vp9_100x66_pattern_5f.ivf"), + yuv: include_bytes!("../test_data/vp9_100x66_pattern_5f.yuv"), + width: 100, + height: 66, + }; + + const VECTORS: &[&Vector] = &[&VP8_64, &VP8_100, &VP9_64, &VP9_100]; + + /// VP9 profile 1: 8-bit 4:4:4, which has no I420 form. + const VP9_PROFILE1: &[u8] = include_bytes!("../test_data/vp9_profile1_16x16_1f.ivf"); + + /// The interval between fixture pictures: 30fps. + const FRAME_MICROS: u64 = 33_333; + + fn at(index: usize) -> Timestamp { + Timestamp::from_micros(index as u64 * FRAME_MICROS).expect("fixture timestamp") + } + + /// Splits an IVF file into its frames: a 32-byte file header, then each frame + /// behind a 4-byte little-endian size and an 8-byte timestamp. + fn frames(ivf: &'static [u8]) -> Vec { + assert_eq!(&ivf[..4], b"DKIF", "not an IVF file"); + let header = u16::from_le_bytes([ivf[6], ivf[7]]) as usize; + let ivf = Bytes::from_static(ivf); + let mut frames = Vec::new(); + let mut pos = header; + while pos < ivf.len() { + let size = u32::from_le_bytes(ivf[pos..pos + 4].try_into().unwrap()) as usize; + pos += 12; + frames.push(ivf.slice(pos..pos + size)); + pos += size; + } + frames + } + + /// Whether a frame is a keyframe, read from its first byte: VP8's + /// `frame_type` is bit 0 (RFC 6386 section 9.1), and VP9 profile 0 and 1 put + /// `show_existing_frame` and `frame_type` at bits 3 and 2 (VP9 section 6.2). + fn keyframe(codec: Codec, frame: &[u8]) -> bool { + match codec { + Codec::Vp8 => frame[0] & 0x01 == 0, + _ => frame[0] & 0x0c == 0, + } + } + + fn open(codec: Codec) -> Vpx { + Vpx::new(codec, &Config::new()).expect("libvpx always opens") + } + + /// The `index`th reference picture of `vector`. + fn reference(vector: &Vector, index: usize) -> &'static [u8] { + let len = I420::len(vector.size()).unwrap(); + &vector.yuv[index * len..(index + 1) * len] + } + + /// Decodes `frames` in order, replacing the payload at `index` where `damage` + /// says to, and returns each picture with the index of the frame it came from. + fn decode(decoder: &mut Vpx, vector: &Vector, damage: impl Fn(usize, Bytes) -> Bytes) -> Vec<(usize, Frame)> { + let mut out = Vec::new(); + for (index, frame) in frames(vector.ivf).into_iter().enumerate() { + let key = keyframe(vector.codec, &frame); + let pictures = decoder + .decode(damage(index, frame), at(index), key) + .unwrap_or_else(|e| panic!("{} frame {index} ended the stream: {e}", vector.name)); + out.extend(pictures.into_iter().map(|picture| (index, picture))); + } + out.extend(decoder.flush().unwrap().into_iter().map(|picture| (usize::MAX, picture))); + out + } + + fn assert_reference(vector: &Vector, index: usize, frame: &Frame) { + let Surface::I420(i420) = &frame.surface else { + panic!("{} produced a non-I420 surface", vector.name); + }; + assert_eq!((i420.width, i420.height), (vector.width, vector.height), "{}", vector.name); + assert!( + i420.data == reference(vector, index), + "{} picture {index} differs from the reference decode", + vector.name + ); + assert_eq!(frame.timestamp, at(index), "{} picture {index} mis-stamped", vector.name); + } + + #[test] + fn every_picture_matches_the_reference() { + for vector in VECTORS { + let pictures = decode(&mut open(vector.codec), vector, |_, frame| frame); + assert_eq!(pictures.len(), 5, "{} lost pictures", vector.name); + for (index, frame) in &pictures { + assert_reference(vector, *index, frame); + } + } + } + + /// VP8 has exactly one color space; VP9 names its own, and these fixtures + /// leave it unspecified. + #[test] + fn color_comes_from_the_bitstream() { + let color = |vector: &Vector| { + let (_, frame) = decode(&mut open(vector.codec), vector, |_, frame| frame).remove(0); + frame.surface.color() + }; + assert_eq!(color(&VP8_64), Some(Color::Bt601Limited)); + assert_eq!(color(&VP9_64), None); + } + + /// A keyframe at a new size switches the decoder over without reopening it. + #[test] + fn a_keyframe_changes_the_resolution() { + for (first, second) in [(&VP8_64, &VP8_100), (&VP9_64, &VP9_100), (&VP9_100, &VP9_64)] { + let mut decoder = open(first.codec); + for vector in [first, second] { + let pictures = decode(&mut decoder, vector, |_, frame| frame); + assert_eq!(pictures.len(), 5, "{} lost pictures after a switch", vector.name); + for (index, frame) in &pictures { + assert_reference(vector, *index, frame); + } + } + } + } + + /// A damaged delta frame costs pictures up to the next keyframe, not the + /// stream, and nothing decoded against the broken references comes out. + #[test] + fn a_damaged_frame_recovers_at_the_next_keyframe() { + for vector in VECTORS { + let damaged = 1; + // Keep the first bytes, so the frame still parses as a delta frame and + // the damage is found inside it. + let pictures = decode(&mut open(vector.codec), vector, |index, frame| match index == damaged { + true => { + let mut garbage = frame[..4].to_vec(); + garbage.extend(std::iter::repeat_n(0xa5, frame.len() / 2)); + Bytes::from(garbage) + } + false => frame, + }); + + let indices: Vec = pictures.iter().map(|(index, _)| *index).collect(); + assert_eq!(indices, [0, 4], "{} decoded across the damage", vector.name); + for (index, frame) in &pictures { + assert_reference(vector, *index, frame); + } + } + } + + /// A decoder that has been flushed takes a new stream from its keyframe. + #[test] + fn a_flushed_decoder_takes_another_stream() { + let mut decoder = open(Codec::Vp9); + for _ in 0..2 { + let pictures = decode(&mut decoder, &VP9_64, |_, frame| frame); + assert_eq!(pictures.len(), 5); + } + } + + /// A profile that decodes to something other than 8-bit 4:2:0 is refused, not + /// narrowed, even when the catalog claimed profile 0. + #[test] + fn a_picture_that_is_not_i420_is_refused() { + let frame = frames(VP9_PROFILE1).remove(0); + match open(Codec::Vp9).decode(frame, at(0), true) { + Err(Error::UnsupportedCodec(reason)) => assert!(reason.contains("I444"), "{reason}"), + Err(other) => panic!("expected UnsupportedCodec, got {other:?}"), + Ok(frames) => panic!("expected UnsupportedCodec, decoded {} pictures", frames.len()), + } + } + + /// The catalog is checked before anything is opened, so a VP9 track in a + /// profile this backend cannot represent fails at subscribe time. + #[test] + fn the_catalog_gates_vp9_profiles() { + let vp9 = |profile, bit_depth, chroma_subsampling| { + VideoConfig::new(VideoCodec::VP9(VP9 { + profile, + level: 10, + bit_depth, + chroma_subsampling, + ..VP9::default() + })) + }; + let config = crate::decode::Config { + kind: Kind::Named(NAME.to_owned()), + ..crate::decode::Config::new() + }; + + for catalog in [vp9(0, 8, 1), vp9(0, 8, 0), VideoConfig::new(VideoCodec::VP8)] { + let decoder = Decoder::new(&catalog, &config).expect("8-bit 4:2:0 opens"); + assert_eq!(decoder.name(), NAME); + } + for catalog in [vp9(1, 8, 3), vp9(2, 10, 1), vp9(0, 8, 2)] { + match Decoder::new(&catalog, &config) { + Err(Error::UnsupportedCodec(codec)) => assert!(codec.starts_with("vp09."), "{codec}"), + Err(other) => panic!("expected UnsupportedCodec, got {other:?}"), + Ok(_) => panic!("{} opened", catalog.codec), + } + } + } + + /// The front end passes VP9 frames through untouched and gates on the first + /// keyframe, so a subscriber that joins mid-group waits instead of decoding + /// against nothing. + #[test] + fn the_front_end_waits_for_a_keyframe() { + let catalog = VideoConfig::new(VideoCodec::VP9(VP9 { + profile: 0, + level: 10, + bit_depth: 8, + ..VP9::default() + })); + let config = crate::decode::Config { + kind: Kind::Software, + output: crate::Output::Cpu, + ..crate::decode::Config::new() + }; + let mut decoder = Decoder::new(&catalog, &config).expect("software VP9 decoder"); + + let mut decoded = Vec::new(); + // Join after the first keyframe: frames 1..3 are deltas, 4 a keyframe. + for (index, frame) in frames(VP9_64.ivf).into_iter().enumerate().skip(1) { + let key = keyframe(Codec::Vp9, &frame); + decoded.extend(decoder.decode(&frame, at(index), key).unwrap().into_iter().map(|f| (index, f))); + } + assert_eq!(decoded.len(), 1, "a delta frame was decoded before the keyframe"); + let (index, frame) = &decoded[0]; + assert_reference(&VP9_64, *index, frame); + } +} diff --git a/rs/moq-video/src/decode/decoder.rs b/rs/moq-video/src/decode/decoder.rs index 1c430c11ae..da47369dc5 100644 --- a/rs/moq-video/src/decode/decoder.rs +++ b/rs/moq-video/src/decode/decoder.rs @@ -4,7 +4,8 @@ //! converts out-of-band payloads (avc1 / hvc1: length-prefixed NALs with the //! parameter sets in the description) to Annex-B and injects those parameter sets //! ahead of keyframes, leaving in-band H.264 / H.265 payloads (avc3 / hev1, -//! already Annex-B inline) and AV1 OBU temporal units untouched. Gates output +//! already Annex-B inline), AV1 OBU temporal units, and VP8 / VP9 frames +//! untouched. Gates output //! until the first keyframe so the backend never sees a delta frame it can't //! decode. //! @@ -19,7 +20,7 @@ use std::marker::PhantomData; use std::rc::Rc; use bytes::Bytes; -use hang::catalog::{AV1, VideoCodec, VideoConfig}; +use hang::catalog::{AV1, VP9, VideoCodec, VideoConfig}; use moq_mux::codec::{annexb, h264, h265}; use moq_net::Timestamp; @@ -36,10 +37,10 @@ pub enum Kind { Auto, /// Hardware only; error if none is available. Hardware, - /// Software only (OpenH264 when its feature is enabled). + /// Software only (OpenH264 and libvpx, when their features are enabled). Software, /// A specific backend by name, e.g. `"videotoolbox"`, `"mediacodec"`, - /// `"nvdec"`, `"vaapi"`, `"v4l2"`, or `"openh264"`. + /// `"nvdec"`, `"vaapi"`, `"v4l2"`, `"openh264"`, or `"vpx"`. Named(String), } @@ -90,7 +91,7 @@ impl Config { /// How to turn a container payload into a backend access unit. enum Conversion { /// The payload is already in the backend's input framing: Annex-B for avc3 / - /// hev1, OBU temporal units for AV1. + /// hev1, OBU temporal units for AV1, one coded frame for VP8 / VP9. Passthrough, /// avc1 / hvc1: length-prefixed NALs with the parameter sets out-of-band (in /// the avcC / hvcC description). Replace the length prefixes with start codes @@ -164,6 +165,8 @@ impl Decoder { (Codec::H265, conversion) } VideoCodec::AV1(av1) if is_supported_av1(av1) => (Codec::Av1, Conversion::Passthrough), + VideoCodec::VP8 => (Codec::Vp8, Conversion::Passthrough), + VideoCodec::VP9(vp9) if is_supported_vp9(vp9) => (Codec::Vp9, Conversion::Passthrough), other => return Err(Error::UnsupportedCodec(other.to_string())), }; @@ -254,6 +257,11 @@ fn is_supported_av1(av1: &AV1) -> bool { av1.bitdepth == 8 && !av1.mono_chrome && av1.chroma_subsampling_x && av1.chroma_subsampling_y } +/// Profile 0 is 8-bit 4:2:0, with either chroma siting (`vpcC` 0 or 1). +fn is_supported_vp9(vp9: &VP9) -> bool { + vp9.profile == 0 && vp9.bit_depth == 8 && vp9.chroma_subsampling <= 1 +} + #[cfg(test)] mod tests { #![cfg_attr(not(feature = "openh264"), allow(dead_code, unused_imports))] diff --git a/rs/moq-video/src/decode/mod.rs b/rs/moq-video/src/decode/mod.rs index 1bfece02bf..2be093a629 100644 --- a/rs/moq-video/src/decode/mod.rs +++ b/rs/moq-video/src/decode/mod.rs @@ -1,15 +1,18 @@ -//! Subscribe to an H.264, H.265, or AV1 track and decode it to raw frames. +//! Subscribe to an H.264, H.265, AV1, VP8, or VP9 track and decode it to raw +//! frames. //! //! The decode counterpart to [`encode`](crate::encode), and the mirror of //! `moq_audio::decode::Consumer`. [`Consumer`] subscribes to a moq-mux video //! track and hands back decoded [`Frame`](crate::Frame)s; a native backend does the work //! (VideoToolbox on macOS, Media Foundation / DXVA on Windows, NVDEC or VAAPI -//! on Linux, and OpenH264 as the optional software fallback for H.264). +//! on Linux, OpenH264 as the optional software fallback for H.264, and libvpx as +//! the optional software decoder for VP8 and VP9). //! //! H.264 and H.265 are supported, symmetric with what [`encode`](crate::encode) //! produces. AV1 is decode-only on NVDEC. H.265 and AV1 are hardware-only (no -//! software fallback). Any other codec yields -//! [`Error::UnsupportedCodec`](crate::Error). +//! software fallback). VP8 and VP9 are decode-only and software-only, behind the +//! `vpx` feature, and only in 8-bit 4:2:0 (VP9 profile 0). Any other codec +//! yields [`Error::UnsupportedCodec`](crate::Error). // Crate-visible so the NVENC encode backend's round-trip test can decode its // output with the software decoder (an in-crate, ffmpeg-free encode->decode diff --git a/rs/moq-video/src/decode/test_data/vp8_100x66_pattern_5f.ivf b/rs/moq-video/src/decode/test_data/vp8_100x66_pattern_5f.ivf new file mode 100644 index 0000000000000000000000000000000000000000..d5ccd43e637ffef647d732b3057a10c82d3abcbc GIT binary patch literal 7952 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 Yb1sp{P?AA@@@@@@@&%'&&&&&&'%&'%&&6656968746669687KJ 憪拹3399拹拺==00000000/.悞拹@>B@悜憪@C@@@@@@搼挀搻挀&%'&&&&&%'拸悞&%57挀敁7546搾搾64KJ憯/搾37拻;?拻>00000000/悜01拹?A憫AB拻A@@@@@@悘悜悙悜&%'&&&&&&憭'(憪$8憪78悜76悜67彁6PQ$%摀**1/摀憫;;;=搼;<;拺90/拹0.00挀拻@AAA憭?@@弿?搾憮摀憮0/10./%&憫''&'憫拻8867憭拻8867憭PQ$%拻,+/0拺憫;<==搻<<:憫:10悞0//1憫拻@@A@拺@@A悙?搾拻摀拻0/1000''拺'&&'憭摂6975搾摂6975搾PQ$%敀+挀/搼搻<悜>拻;=9=9866攽3憭0拻拻@悜A憫@@@@@?憫搼憪憭搼憪0/100101彃&憫&拸彃8憪7憦彃8憪7憦PQ$%搻-搾0拸搻<憮>拺<=:;8867挀3拺1憪拻@彂@拹A?AAB?憭拺拹憮拺拹0/100010憮&悙%搻悢7拺5搹悢7拺5搹QR$$憯+-..搻拻<=?>拺<<;:8888憭5401搻憭A>?A敀@A@AA@憮搾憮搾11/10/11摀$%&'拺挀6577拹挀6577拹QR$$拻++00悜悞=<@<憯=<:憭987憭731/搾憪@??B彄A@A悙A憫憫憫拹.2.0/00/拺%'(&彄攽6687悞攽6687悞QR$$(憭,/憭49悞;=憭A=<:憭9876憭32憭02攽23摂4A@A悙A憪悜憪拺/0/1拻/100搻0(拺%9悜66拹99悜66拹9QR$$('拻搻2479憭憭>?<<;:888844憭拺/330拻攽24@A@AA@拻拻拻摂/2.00憫00.//拹拺&'55挀搾5655挀搾56QR%%&'*,//4488<>>>;;:977775543111111113333444466101000000000&&&&6666666666666666RQ"!..3266::>>>>;;:97777554311111111333344445667320/,,''0100000000&&&&6666666666666666RQ! /.3377;;????<<;:888866541111111133334444557631.-()('1000000000&&&&6666555555557777QR !;<>?@@=<;:888855431111111133334444555512..**&&!! &%%%00000000%&&&6666666684766758QR :92122224444555512..**&&"" !!##%%&&&&7777搾6777拹QR /000000000000011@@?@2322224444555512..**&&"" !!##%%%%%%6666彄6587悞QR /000000000000011@@?>@>@@@@4444555512..**&&"" !!##%%%%%%$$$$#憭56拹9QR /000000000000011@@???@????4444555512..**&&"" !!##%%%%%%######拹搾56QR /000000000000011@@@@@@@@@@@@@@??6522-,)*&("#!!##%%%%%%$$$$####!!!!QR /000000000000011@@@@@@@@@@@@@@?@6633//*+%'"#!!##%%%%%%$$$$####!!!!QR /000000000000011@@@@@@@@@@@@@@A@'&"#!!##%%%%%%$$$$####!!!!QR /000000000000011@@@@@@@@@@@@@@AA%%"#!!##%%%%%%$$$$####!!!!PQ"! 0000000000000000BBAAAAAAAAAAAA@A "!%#'%''&%%$###"!!"! OQ!! /0000000000000/0AA@@@@@@@@@@@@BA" "!&%&&%$%$#"%$#"! RRQPQQQQQQQQQQQQRQ憫憫憫憫憫憫憫拻乙佑佑佑佑佑佑矣))**))))))****((''hi55>?DDONTT^^dchgffba`_]\[ZWVUUQQPPQQQQQQQQQQQQQQ悙悙悙悙悙悙悙悙醒乙乙乙乙乙乙杂+)**))))))****))))gi67?@FGNNUU^^eeihggccba]]\[WVUTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjNMWW^^eeiigebc``]][YVVUTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjMMVW^`efiigebc``]][YVVUTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjkjkjiiggiigebc``]][YVVUTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjijikfhiigebc``]][YVVUTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjeda`]]ZYWVUTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjdca`]][[VUTTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj┆YZWVUTQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj┅[\VUTTQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙}}}}}}}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙}}}}}}}}~}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憭彁憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫悙憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj蒇圯\ZZ[Z65657757镳痧铑瘃鹕伤噬缮施ぇΖЕ槚梮wwwvolnnooonedfdeeed潧潩洓潧潙拻拻憭憟噲墘垑壽暀昿jmvwnonnmmmoddedcccd潨洓潩洖洅挃搼憭攪墛妸妷壿杸NE][AAWnoln]CCYX@CVccb潉PP倐PO儜攺攜ML|uKKttKJsZu6nk64ec7hONn5lo64dd6dKN�5洔44湞5厗儜5彂54妷44墘5[s6TQ66OM6dfih7QQ57ML5ddd�6hj66jj6倖剛6ed66b_55_`6Zs5oo62fe6e\Zk7lm66ee5fWX�5湝44湝5剟剝5敀67垑77墘5[tbED^\@AWfZ[j\CDbdBEhbYY渷ON倐NPq匽\僴IK|sKKttKHsZurooijhefffiikkmosuy|�儐潧殲湝湞渿亝厖厬拡墖妺垑塟wvunlhhedegiikkmosuy|�儎墝帒湞湝湋剟剟剴拤妶垐墘塟wxxvvvhebdhiikkmosuy|�儐妿審悥敍潛憚剟剴搳妸妸増塟wvuxwwuwmggiikkmosuy|�儏墜弿摃棛洔敀拻拻搲妷宺JKtZwwwwwwuvnnnliilnmtvy|�倗墠彁挅槡湝殮棓拻搱墛�7噲4Zwwwwwwuvnnnnmmnmqpsz|倓噳崗悞枠殰湚殬晸悜墘増5``6Zwwwwwwuvnnnnoonnffvw|儐垖帍憰棛洓櫃棖晹搻帀�5妷5Zwwwwwwuvnnnloolmfeddg~亞垖帍憰棛洓櫂槜棓拺強噊KIt[uwxwwwwxmoonoonncddcccc`妸帋憰枡潧槡櫀晼搻弾垍}yYwuwwwwwvolmmnnmnfcdddddd洔湝敁槡洕櫃櫁棓攽弸噮亄z[vwuwwwwxoolopponddaddddd灉湝洓湚潧湚槚晸敁帉噮�~zZ[Z\[[[[[75667766盹耨镲镳袷赉嘹仔兔俯湉倀hZZZZZZZZZ6�����65锺痧瘃瘃鹗伤韶中颓斧湋剉hZZZZZZZZZ6�����65锺痧瘃瘃鹗扇嗜适糖公瀻倂hZZZZZZZZZ6�����65锺痧瘃瘃鹗缮伤松狮ī湊倂hZZZZZZZZZ6�����65锺痧瘃瘃鹗伤耸嗜衰うΕ僽gZZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZZ6~�66痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZZ66575856痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZY67763566痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZZ83566856痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZY65666676耩痧瘃痫鹗怂耸仕师ΖΗウΖΘヮ痫铒#$!% $$#悜憮憫摀kmmmoomno捃苓哕掭墛潩煕渉ihihihj剝剟剟厒||}{||{~}殫棗棙枙eceeeebd妶憦姏瀓ijijikf厔剟剟剟|}}~||~}{棖棗棖櫁dcdccddc棾禐槼祾kgii┆敀碑搨厓|嵀瘝嵂皪枛枙⒍储|┇{{z餀脮懥膱吢湝j纉j吕儍纼ⅲ|纜}亮}|聇tq暳枙吕dd亮dd琉毬┅玖Γ纞{wv翖椑陇⒚厔儅罏溋翜灺sttu垃翋懤缿惵餀罃懧缊吜亶妛縧m懒剟羷搾{纝~亮~|羢rts習櫫纁e侣ef礼櫉返洐膊憕崑t叓珆~}剴�嵂睄嵄畤s洔s埈盯}ǐzz}饳棓悗媹剛{xuqnkhjgggfed{}z|{|}||tttttt棗ccfcebfd駵潨攷媹儌}~xuqnkhjgggfeedfjnz|||}檜tttt棗cdeeebde顨湝殯湀厑�{xuqnkhjgggfeebhilmts{{櫀ssss棙dddddhdc駵湜殰洔沨�~xuqnkhjgggfefeghjoruzz~枛枛枟梒cfd|z饹潨湝湜漣iimssmkjighfheedfjlortxz~�唸枠暀dddb羍d鲤洕湝湝洕iiihiihlhjgggededgjmoruy{亜垔崙朿deb翏懨饹潨湝湜漣iijiijh儎egffeedgjmoruy{亗墛悡晿梔b羋e鲤洕湝湝洕iiiikkil倓倓僪gddfilnqtxz~�剣嫃憯殭槡ぉ獆驖湠潩潩渒iihhhhh亜儎剟剟cfhnorvv|�剣妿挃棜殮殮洓餄洔湝湝渒lihhhhh儏剟剟剝z{~{nruw{~倕噳嫇枠櫃櫄殮汄潨洔湝湚hijjjjjj儏儎剟剠|{}||{|zz剣嫃挅槚櫄洕洓瘃铖镲镲�""#"""""拻搻悙悜mnnpmpllm軆摓仍捺沐栝铑痧痧痧痧�"�個�##拻憭拻拻nnmnnnnoo蒉蒉嗽哜徙觋祉痧痧痧痧�"�個�##拻憭拻拻nnmnnnnoo蒉葸葺拗哙忏珀祉痧痧痧痧�"�個�##拻憭拻拻nnmnnnnoo蒉坜咻噙滗骒腱痧痧痧痧�"�個�##拻憭拻拻nnmnnnnoo蒉哚苻掎殪眇痧痧痧痫"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"��""憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�!$!" !"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"" "!"#"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�#$"#"!!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"#!"!""!拻搾拻拻nnmnnnnoo蒉捱捱捱KKKKIIIIPPPPOOOORR憫憫憫憫憫憫憫挀矣乙乙乙乙乙乙已*)))))))))))))))))iiiijjjjjjjjhekg皑┅┅┅┆KJLJHHHHOOOOPPPPRQ憦憫憫憫憫憫憫憪蜒乙乙乙乙乙乙矣******************jjjjkkkkkkkkjhjs暴┅┅ěKL   10000000000000/0ABAAAAAAAAAAAAA?&&&&&&&&&&&&&%%'75555555567889::KJ  !1/111111111111/.A@AAAAAAAAAAAA@@''''&&&&&&&&&'#37555555556678999JI2034$($%.-00000000.1.301?B????@@@A@@@@@@&%'&&&&&&%$&(-"$93=686@B:/9:;640JI1164)0%&!/*00000000011021???@@>?AA@@@@@@@&%'&&&&&&'%')+%$9<976277996:2@43JI悘搼4478搾棑;800000000/.悞拹@>B@悜憪@C@@@@@@搼挀搻挀&%'&&&&&%'拸嫇"+6崠棎�;37姃殧�51JI悡0敁4<枖拻;=9=9866攽3憭0拻拻@悜A憫@@@@@?憫搼憪憭搼憪0/10././彃&憤*挄1:帍櫁921:帍悓<9RS&'拸,挀1搻攽=挀>拺<=:;8867挀3拺1憪拻@彂@拹A?AAB?憭拺拹憮拺拹0/10++,+憮&悈,棐24354摃42435:弽9RS%%挄,.00晵憫;拺<<;:8888憭5401搻憭A>FD憢@A@AA@憮搾憮搾11/10/11摀$%$'帣98/;9悡9=4+?8憫9RS%%摀,,22挀彂<;@<憯=<:憭987憭731/搾憪@?BC帎A@A悙A憫憫憫拹.2.0/00/拺%'+#崘8=8/.槑<<9438噳=RS%%)挀-1摂68彂:=憭A=<:憭9876憭32憭02攽20挄7A@A悙A憪悜憪拺/0/1拻/100搻0!憦!帋812晱3弸453枈;RS%%)(摀晵4668悜憭>?<<;:888844憭拺/330拻崕5;@A@AA@拻拻拻摂/2.00憫00.//拹拸%%:洆墣�;5<棌崕�;9RS&&((*+005577;;@@@@==<;777755430000000022223333CA-...1111////.)&"1653>55538565345RS$$(*.1//3366::????<<;:666644320000000022223333@=/./.1111///,*,*(6463588876554444SR#"#*///435599????<<;:666644320000000022223333:84286#%%./1111////"&$!6562122245444444SR" %/60/4466::@@@@==<;777755430000000022223333742.00&%/.1111///,)+&&6563566575653444RS!!!!!!3.>8;;;:>=<;7777443200000000222233334444/0,,))%%##$%1111////*+%6574577680><351.RS!!!!!!50D>8<=A>=<;7777443200000000222233334444/0,,))%%()%%1111///-)($!6574566658:1;44.RS!!!!!!! !6;>=<;7777443200000000222233334444/0,,))%%!! '")#''''%%%%&&%&76845677/59悐:-=<;7777443200000000222233334444/0,,))%%$$#"-')#''''%&&'()))66845677/7崚�70;PQ!!!!!!!! /0////319655550000000022223333666601--++''!!%&'(''(())*)77867877/寯攺449PQ!!!!!!!! /0////218844440000000022223333666601--++''!!"#$%''''&&''778678772:7弿349PQ!!!!!!!! /0////311022220000000022223333666601--++''!! !!!!!""#&58;9:;:861.晱349PQ!!!!!!!! /0////010111110000000022223333666601--++''!!!!!!##$%585-10599<:槒349PQ!!!!!!!!./////1111111100??-31756783333666601--++''!! """#$%5655;037.37弿569PQ!!!!!!!!./////1111111100??4:3864313333666601--++''!! """#$%788740127@6審-.9PQ!!!!!!!!./////1111111100??>?CBEA:53333666601--++''!! """#%$$%%&(,00296拸;<9PQ!!!!!!!!./////1111111100??EDCCE>4-3333666601--++''!! """#%%%&&&!(4;3帎棌挀:QR /000000000000011@@@@@@@@@@@@@@8;68804+&(%(!" ""#$%&&&&%$$"$#%*3333QR /000000000000011@@@@@@@@@@@@@@8<691+3-..&&!" ""#$%&&&&%$#"###"#5555QR /000000000000011@@@@@@@@@@@@@@:<)(#*$!" ""#$&&&&&%$#"#$" """"QR /000000000000011@@@@@@@@@@@@@@:=((*#)"!" ""#$&&&&&%$######"####PQ"! 0000000000000000BBAAAAAAAAAAAAAB!##%'))**)))'''%##$! OQ!! /0000000000000/0AA@@@@@@@@@@@@CB# !$$$%#$$"!##!! RRQPQQQQQQQQQQQQRQ憫憫憫憫憫憫憫拻乙佑佑佑佑佑佑釉**,,++********''&&4;18?@EEPOUV[_bceeecba`_\ZZYVUTTQQPPQQQQQQQQQQQQQQ悙悙悙悙悙悙悙悙醒乙乙乙乙乙乙赵,*,,++****''''((((0559@AGHOOVV^aehihhfddc`]]\YVUTSQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihHHHHLLXY[]bfiihda`^]]\ZWWWVUQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihEEEELKRR[_cfijhda`^]]\ZWWWVUQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihlllllf`]addgjkieb`^]]\ZWWWVUQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihiiiileZTgfcdffcba`^]]\YWWWVUQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihkkkkkkkkjglfljcnY`a``[Y]VUTSQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihkkkkkkkkjhlooikYcfe^U]]RUTSSQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihkkkkkkkkjhlm搏-^fY_WZVUTSQQPPQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙岩((****((((****((((ijihkkkkkkkkjhlm畅^_Yf[\UTSSQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjWVUTQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjVUTTQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙~~~~~~~~}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙}}}}}}}}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙}}}}}}}}~}憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憭彁憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫悙憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj蒇圯\ZZ[Z65657757镳痧铑瘃鹕伤噬稍啸く獫イマ槚梮wwwvolnnooonedfdeeed潧潩洓潧潙拻拻憭枒妸崅垑蹠檿pjmvwnonnmmmoddedcccd潨洓潩洖洅挃搼憢拕妶墕悎囕杸NE][AAWnoln]CCYX@CVccb潉PP倐PO儜攺攜MN�NXTzNaTxZu6nk64ec7hONn5lo64dd6dKN�5洔44湞5厗儜5彊3倗f]墝a\[s6TQ66OM6dfih7QQ57ML5ddd�6hj66jj6倖剛6ea1}`Gr坃IuZs5oo62fe6e\Zk7lm66ee5fWX�5湝44湝5剟剝5攱6儏eS噮j^[tbED^\@AWfZ[j\CDbdBEhbYY渷ON倐NPq匽\僴IO}J`MrKTKoZurooijhefffiikkmosuy|�僷枮湠湝湞渿亝厖厬搹墦噦妰奪wvunlhhedegiikkmosuy|�儔嫊湞湝湋剟剟厜實媻垔悡峑wxxvvvhebdhiikkmosuy|�儐剨憦悥敍潛憚剟剰帋媻寠剠媄wvuxwwuwmggiikkmosuy|�儊實垙摃棛洔敀拻挏悗墘�Ja匷wwwwwwuvnnnliilnmtvy|�倗墠彁挅槡湝殮棓拸帍垕唖Ga孼wwwwwwuvnnnnmmnmqpsz|倓噳崗悞枠殰湚殬晸憥帀寘坓\嘮wwwwwwuvnnnnoonnffvw|儐垖帍憰棛洓櫃棖晸憪帋噽]]塟wwwwwwuvnnnloolmfeddg~亞垖帍憰棛洓櫂槜枖拸巼寎RHs[uwxwwwwxmoonoonncddcccc�崈棊憰枲敊湚櫀枙拹弽噦y墔Ywuwwwwwvolmmnnmnfcdddddc嫓敁槢湗湙櫁枙搼帄噭|{[vwuwwwwxoolopponddadddd_殩摐洓湙湢櫄槚攽憪寜厔{wZ[Z\[[[[[75667766 矧铖镲矧遴捭嘹资平菠棆�vjZZZZZZZZZ6�����65锺痧瘃瘃鹗赦宗幸兴涧檸�vhZZZZZZZZZ6�����65锺痧瘃瘃鹗赡搜傩屠殝vhZZZZZZZZZ6�����65锺痧瘃瘃鹗缮赏吞瘸恭槍vhZZZZZZZZZ6�����65锺痧瘃瘃鹗膳鞘滔泞&|ugZZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗgZZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZZ6�����66痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZZ6~�66痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZZ66575856痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZY67763566痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZZ83566856痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZY65666676耩痧瘃痫鹗怂耸仕师ΖΗゥΖΘヮ痫铒#$!% $$#悜憮憫摀kmmmoomno捃苓哕萼 墛潩煕渉ihihihj剝剟剟厒||}{||{~}殫棗棙湋f]ceajad妶憦姏瀓ijijikf厔剟剟剟|}}~||~}{棖棗棖煏c^fcg^hi棾禐槼祾kgii┆敀碑搨厓|嵀瘝嵂皪枛枙⒍处皻餀脮懥膱吢湝j纉j吕儐箠煟|纜}亮}|聇tx伵摌芶h崗_e摃饸漏┚力@~{wv翖椑陇@垉儅罏溋翜灺stvh猫g崿|d挱�餀罃懧缊吜亶妛縧m懒剝膩敀{纝~亮~|羢rpp聫懢fd敋ap崝駲煼禌櫜矐~崑t叓珆~剗晳嵂睄嵄畤s洆w墺饥�獦畖饳棓悗媹噞唜xuqnkhjgggfe剙v}|}��亷otttt搾bm^ceemc駵潨攷媹��}xuqnkhjgggfeg_ix�|x{|榯tttt敇aaid]\\`顨湝殯湀剟}|xuqnkhjgggfegahmhmz}zz槙ssss帡b_k`^ikb駵湜殰洔榦y亁uqnkhjgggfe_bhipstu}槕枛枛湙gfkdjh饹潨湝湜漣iimssmjp_mgocjedfjlortxz~�搾湜敇ec^c{獟c饹潨湝湜漣iihiihhlqaeiadedgjmoruy{亜嫆槗杒abho彈i饹潨湝湜漣iijiijh妔oc^d_edgjmoruy{亊垗枠弇lh_g悥g饹潨湝湜漣iiikkii噭�tg\ddfilnqtxz~�噰噲墝槞杁v}驖湠潩潩渒iihhhhh亜儎剟刢^mfqpqs�z亜噴帓晿槚晼梚i餄洔湝湝渒lihhhhh儏剟剟剚xitku|rt}倕噳嫈枠槝棙槢涷潨洔湝湚hijjjjjj儏儎剟剟}{y�xuz||{剣嫀憯敂棙殯櫃瘃铖镲镲�""#"""""拻搻悙悪pmmmlqoqmu姄灝浩屹阝彐栾镳痧痧痧痫"�個�##拻憭拻拻nnmnnnnoo蒉洖Ь素溱汊脲祉痧痧痧痧�"�個�##拻憭拻拻nnmnnnnoo蒉孳酆套噙遘赙祉痧痧痧痧�"�個�##拻憭拻拻nnmnnnnoo蒉檩噤廛需彗犟腱痧痧痧痧�"�個�##拻憭拻拻nnmnnnnoo蒉兮苘咻 坂觎眇痧痧痧痫"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱祉痧痧痧痧�"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"����!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"��""憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�!$!" !"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"" "!"#"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�#$"#"!!"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"#!"!""!拻搾拻拻nnmnnnnoo蒉捱捱捱JJJJKKKKPPPPOOOOQQ悙悙悙悙悙悙悙挀矣乙乙乙乙乙乙已*)))))))))))))))))iiiijjjjjjjjifjb│Еī┅┆JIKIJJJJOOOOPPPPQP悗悙悙悙悙悙悙憪蜒乙乙乙乙乙乙矣******************jjjjkkkkkkkkkiih┇┅┆èéJK 0//////////////0ABAAAAAAAAAAAAA?&&&&&&&&&&&&&&%$7876655555787799JI 0.000000000000/.A@AAAAAAAAAAAA@@''''&&&&&&&&&'$*7;88655556667888JI" #$#&!7511111111,/,101?B????@@@A@@@@@@&%'&&&&&&%$&("((.=68<7:;9322>36:JI %# !0311111111.//.21???@@>?AA@@@@@@@&%'&&&&&&'%'&+!+?54526865:4.@887JI悘晸66=5槑棑6+11111111-,帎拹@>B@悜憪@C@@@@@@搼挀搻挀&%'&&&&&%'拸棏&:7崜�9:4實殦挅�.JI悡1晹5>崘,"敍211111111-帍.1拹?A憫AB拻A@@@@@@悘悜悙悜&%'&&&&&&憭'#攽%B弿3*:86搾?28敀=VT" 敂++20敂拻<<<>敀343姀7.-搼1/00挀拻@AAA憭?@@弿?搾憮摀憮0/1034*+憫''#(憫帀66529686686姌2VT" 摀-,01搾拻<=>>攽775審8/.憮10/1憫拻@@A@拺@@A悙?搾拻摀拻0/1022))拺'&)(悜搶7640:4,:6?;帇6645摂4搼1憪拻@彂@拹A?AAB?憭拺拹憮拺拹0/10++,+憮&悥$崓崠368帡6869拪7A:RS%%挄,.//攽摀=>>=憪;;:97777悜4301搻憭A>C=妶@A@AA@憮搾憮搾11/10/11摀$%*&姁攼./9晳796寫37C3RS%%摀,,11憭憮>=?;悡<;9悜876悜621/搾憪@?;F憠A@A悙A憫憫憫拹.2.0/00/拺%'+(拰憦2-9搸?31棌66>4RS%%)挀-0挀5:憮<<悜@<;9悜8765悜22憭02攽27彃>A@A悙A憪悜憪拺/0/1拻/100搻0$噸0搾<72噹<6:暁552;RS%%)(摀攽358:挀悜=>;;:9777733悜拺/330拻悤<>@A@AA@拻拻拻摂/2.00憫00.//拹摂"&7剫弽�3746潔467:RS&&(),.005599==????<<;:99994432111111234566>>>>:A,---1111////)( ':8877666666768::RS$$,,/0//3388<<>>>>;;:9888833211111112345789:;;@C.-.-1111///,)( ':887766666778898SR#"((((//4377;;>>>>;;:988883321111111234566777712#$$-.1111////)( ':887766666778899SR" -,,,0/4488<8<=:;=<;:666633211111112222445566666612..,'()%%0000111/(( '64555566;968724+RS!!!!!!%8=>:A==<;:666633211111112222445566666612..+)#"'")#&&&&'''')( '645555687姃洆�47RS!!!!!!!<;B=@;=<;:666633211111112222445566666612..*+()!! -')#&&&&'(()*( '6444667-厡;54崘9PQ  ./::::<69244332211112222445566666601--))%%%,'()*##$$*' '6444575:<<836憠7PQ  ./7777749833222211112222445566666601--))%%!&$%&'&&&&)' '6444573:=;;0墔41PQ  ./2222225511111111112222445566666601--))%% !"#%%%%(& (75555748;><拡<81PQ  ./////,05:00001011111222445566666601--))%%((((&$!(755557489+悞:=6/PQ  !!01....0000000000.--.1133445566666601--))%% ""!###664?400E(帒59..0PQ  !!01....0000000//134431123445566666601--))%% ""!"##664?9287槕6;:767PQ  !!01....00000000.3:>>:3.33445566666601--))%% """"######0200帟:5=悂6PQ  !!01....00000000-4>EE>4-33445566666601--))%% """"$$$$%$5454攳棐帒�3QR /000000000000000??????????:::::593//**')&) !""$$"#%%&&&$$##$&"=83333QR /000000000000000??????????====53:722..//'' !""$$"#%%&&&$#""#%385555QR /000000000000000??????????BBBBDD/.-.*,$ +% !""$##$%%&&&$#""$$ $#""""QR /000000000000000??????????EEEE?B/1/0..+$*# !""$##$%%&&&%####$%!####PQ"! 00000000000000//AA@@@@@@@@@@@@?@%,#!%%'*++*)))(''&&%&%! OQ!! /0000000000000./@@????????????A@!%!%""%&&%$#$#!"#$##" RRQPQQQQQQQQQQQQRQ憫憫憫憫憫憫憫憫蜒乙乙乙乙乙乙岩(((('')+-.,,,,61*%4;18?@EERQWX_cefeedba``^]\\YVUTTQQPPQQQQQQQQQQQQQQ悙悙悙悙悙悙悙弿闲蜒蜒蜒蜒蜒蜒右*(((''*)('))))>7-&0559@AGHQQXXbeijihgeddb_^_]YVUTSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((mk74GGGGOOZZ^afjlliecb``_]ZYWWVUQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((ni>6DDDDMMWX`cgjlliecb``_]ZYWWVUQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((imgjkkkkTSTVefgknmjfdb``_]ZYWWVUQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((kknlhhhhRRQRkfegiheecb_a_]\YWWVUQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((klkjjjjjkkkklmeghclid`]a`[\\VUTSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((klkjjjjjkkkkmjmcficah_]`ZaYTUTSSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((klkjjjjjkkkkmhhr哀ckac]^Z[VUTSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�拻矣佑佑佑佑佑佑矣))))))))))))))((((klkjjjjjkkkklfjh哀af\dbd][UTSSQQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj炊dfWVUTQQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj捶_aVUTTQQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj朝帛QQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj嘲QQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQR~}~�憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQRK亃~~~~~~~~�y倇憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQM厐~~~~~~~~~y唩憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQPO寢拻拻拻拻悙媼憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQOP憫拻拻拻拻彁憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQRR憫拻拻拻拻拻拻憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQRR憫拻拻拻拻拻拻憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQRR憫拻拻拻拻拻拻憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQRR憫拻拻拻拻拻拻憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj蒇圯\ZZ[Z65657757镳痧铑瘃鹕伤噬商效灖珷槚梮wwwvolnnooonedfdeeed潧潩洓潧潙拻拻憫晝墛媶噰壽暀昿jmvwnonnmmmoddedcccd潨洓潩洖洅挃搼憦攨崋垗寢壿杸NE][AAWnoln]CCYX@CVccb潉PP倐PO儜攺攜MH{uJt�*XB[Zu6nk64ec7hONn5lo64dd6dKN�5洔44湞5厗儜5彁36唲唽巁W[s6TQ66OM6dfih7QQ57ML5ddd�6hj66jj6倖剛6e[<9^Hj弐N刏s5oo62fe6e\Zk7lm66ee5fWX�5湝44湝5剟剝5敄84乚a婡搮[tbED^\@AWfZ[j\CDbdBEhbYY渷ON倐NPq匽\僴INvNcJs1厒Zurolfgeefffiikklotw}vmfk洠棥煙煗渿亝厖厯悎増寖寙媄wvukieeedegiikklotwz{~暉殧煚煖湋剟剟厯悏妵垗啅哯wxxssseebdhiikklotwy~剦�姁嫆摍棝潛憚剟剶憠妺媴崋塟wvuuttrwmggiikkknsvz|}}唶垗挅槡櫅湐拻拻搼墛憤IZTrZwwwwwwuvnnnliikknruz|亜噳崗悞枠殰湚殫敀搼噳厞帄DuZwwwwwwuvnnnnmmmmosv|儐噳崗悞枠殰湚殬晸悘垑唹圧r嘮wwwwwwuvnnnnoommosv|儐唸寧彂晽櫅洐櫁枙敀悓�Jq儕Zwwwwwwuvnnnlookjmqtz}亜唸寧彂晽櫅洐槝棔搾憥亸2[Lb[uwxwwwwxmoonoonncdd^hw亐憞棊憰枠湣敋櫀棖敁拸墏帄Ywuwwwwwvolmmnnmnfcdbdghk憣摐敁槢湗湙櫁棗枔悓墕亊}[vwuwwwwxoolopponddadb`^g湗洔洓湙湢櫄槚敂敀帇垎亂uZ[Z\[[[[[75667766 腩铖镲镪龛帚嘹滋蔷菠棆�qeZZZZZZZZV�儊億亖5锺痧瘃痫胂哜宗醒唐罚棆seZZZZZZZZV�儊億亖5锺痧瘃痦砦帜搜傥尉枅}seZZZZZZZZV�儊億亖5锺痧瘃痍锼巧赏退侠担晧}seZZZZZZZZV�儊億亖5锺痧瘃痂裆脚鞘涛尾&yrdZZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师Β獫~ugZZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师Ιぃ%ZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师Νⅴ饱ZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师ΙあˉZZZZZZZRp|�z�r6痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZa44638)66痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZP67449786痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZW2?;@4416痧耩瘃痧锼仕耸仕师ΖΗゥZZZZZZZY65666676耩痧瘃痫鹗怂耸仕师ΖΗゥΖΘン豸箫#$!% $$#悜憮憫摀kmmmoomno捃苓哕茑 墛洓潤渉ihihihj剝剟剟厒||}{||{~}殫棗棙洊e`eff^ee妶櫁挘瀓ijijikf厔剟剟剟|}}~||~}{棖棗棖潥c`acbjae棾稛櫞祾kgii┆敀碑搨厓|嵀瘝嵂皪枛枙⒍簹伄僱臎皭餀脮懥膱偪|櫆j纉j吕儐箠煟|纜}亮}|聇t|}翖撋穐dcka墡饸漏┚力牻{xwv翖椑陇@垉儅罏溋翜灺stzd楷缽瑔ax餀罃懧缊偩~妸w縧m懒剝膩敀{纝~亮~|羢rtl緭櫦竢崒\羉e駲煼禌櫜瘞{妺t叓珆~剗晳嵂睄嵄畤s洍s叐笩⿷k莊a饳棓檺墖�垀zxuqmihhhcm{厙u�xy|亷otttt櫁afdbj_ib駵潨墣憞唥~xuqmihhgghjlbuz|剙|{|榯tttt櫁bfff_e_f顨湝晭攳倖zxuqmihhhhfdbbbihlq~亃z槙ssss殬bfccjdid駵湜晿搷噰|xxuqmihhghikmbjpllopq}槕枛枛棗af_c渰饹潨湝湜瀗txmssmchhegijjedfjlort{}亙枔洏悤fhl_ie畕饹潨湝湜焟pqhiijkiimeeeeedgjmoru|~倓}垥煒梒jdee珁b饹潨湝湜igjiihgiiffgggedgjmoru|~倓厠姀帣knff﹚j^饹潨湝湜d`ikkic~~cffffddfilnqt{}亙剢垕湊枡mc笌驖湠潩潩渒iihhhhh亜儔qg`_ncnmnp|v{}噴崙摉槝暏歩ii餄洔湝湝渒lihhhhh儏剠剛�唈cnqhryvx亞垔審敄槜棙棐洓驖湜湝湝歨ijjjjjj儏儎唸妷|z~�|ur~��噴帒挃敃櫁洟櫃瘃铖镲镲�""#"""""拻搾悕姈ifjjinlmiq問”缴再荛镯轱镳痧痧痧痤儊個|��#拻憭拻拻nnmnnnnok輪洖仲蒌滗殪祉痧痧痧痧顑亗�|��#拻憭拻拻nnmnnnnnj揶葆娇疼汆嚯熹祉痧痧痧痧顑亗�|��#拻憭拻拻nnmnnnnkp刳圻谮坜汜组沆腱痧痧痧痧顑亗�|��#拻憭拻拻nnmnnnn|k葸垆剜嘬阼桧祉痧痧痧痧顑亗~|�"憮拻拻拻nnmnnnnoo蒉捱捱捱 莒眇痧痧痧痤儊倊|�"憮拻拻拻nnmnnnnoo蒉捱捱捱 痧痧痧痧顑亗~|�"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧顑亗~|�"憮拻拻拻nnmnnnnoo蒉捱捱捱 + 痧痧痧痧髗~�~唨z"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"%!(""憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�&&&& ('"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"#&" "憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"#!"!""!拻搾拻拻nnmnnnnoo蒉捱捱捱MMMMRRRRPPPPQQQQRR憫憫憫憫憫憫憫憭岩蜒蜒蜒蜒蜒蜒已*)))))))))))))++++iiiihhhhjjjjjgkcě┆è┅MLNLNNNNOOOORRRRRQ憦憫憫憫憫憫憫悘行蜒蜒蜒蜒蜒蜒矣**************,,,,jjjjiiiikkkkljjiΖΔMN!" !!!! 10000000000000./@A@@@@@@@@@@@@A?&&&&$$$$&&&&''&%8987766666895577ML""""""!1/111111111111.-@?@@@@@@@@@@@@@@''''$$$$&&&&'(%+8<99766667775666UY"!$# 6400000000+.+0/0>A>>>>???@????@@&%'&((((!#($*!+&-<57;/0.<7?6;7:1UY"  + /200000000-..-10>>>??=>@@?????@@&%'&((((,$#1*&(>4342@5/3'86262;UY"悘悗11"'晱枓5*00000000,+崗憦?=A?彁悘?B????@@搼挀搻悜&%'&((((/(*帢*"$96寬媿=@;>寭帓<@悙@A憫@????@@悘悜悙帍&%'&((((!-垘�,-#A帋23枍5=弸6*悗6XV$"憤 !彇拻<<;=搼232墡6-,拹0.11摂摀ABBB挀@AA悘?搾憮摀摃0/1056,-.彇敁%-$枬/4.2帞嚁-815悡XV$"搻%!!'悡拻<===搻664嫀7.-悞0/02拻摀AABA搾AAB憪?搾拻摀敂0/1044++&*)枊+'*拹05/;拠悳9-8<挍XV$"檾)崗,搾攽=憫>拻:<8<6533攽3憮1摀摀A憭B拻AAAA@?憫搼憪憭摀搾0/100101/3.敋%(!棑:殠9嫅憭<嫈=挀XV$"湑.憱2搹攽=挀>拺>?<=5534挀3拻2拺摀A悞A搼B@BBB?憭拺拹憮挀敀0/10--.-(2#晲("&潝2崘<殧拸4憤8悢[X&#悡*,//攽憫;拺<<;:8888憭5412攽實<9D>媺ABABA@憮搾憮憪11/1.-//443寧1%)搼775>敁晧42<3憢[X&#憫**11憭彂<;@<憯=<:憭987憭7320敁悘?>?<<;:888844憭搾0496槝憱=?ABABA@拻拻拻憭-0.00憦..,0悓挃崊+3<帗帤446.憱搶25WX++*+.0227777;;====<<;:77774432000000123455====A>*+++////////'&%86657666666768::WX))..12115566::<<<<;;:96666332100000012346789::@A,+,+///////,'&%8665766666778898XW('****11655599<<<<;;:9666633210000001234556666B>!""+,////////'&%8665766666778899XW'%/...216666::====<<;:777744320000001223444444@B#",+///////,'&%8654655555568999PQ#&*.11117;:;:<>?=<;:88883321000000112243434466663-##$%0000////(( '64667789<0;=/560PQ#'*3333@:@8>?<==<;:88883321000000111133445566662.$()%%0000///-(( '64557788=;8:724+PQ#& ./<<@400E->?57帗7PQ  !!01000000002221.023333512334455444401--))%%!! ""#$%%442=9287<<<45憴1PQ  !!01000000002222-29=344322334455444401--))%%!! ""$$%%55550200挀5>0彇7PQ  !!01000000002222,3=D233322334455444401--))%%!! ""$$&&55655454;殨憮�>4QR /000000000000011@@@@@@@9/(444439/422--')&) ! ""#$&&'''%")3<54646666QR /000000000000011@@@@@@?;4/777755215511//'' ! ""#$&&'''%"&-36.7;6666QR /000000000000011@@@@@@>=;9<<<<385901-/$ +% ! "!$%&&'''%$$'*"!7777QR /000000000000011@@@@@@=>@A????54752311+$*# ! "!$%&&'''&%$#!$&7777PQ"! 0000000000000000BBAAAAAAAAAAAA?@%,''&&!!##&)**)((()(('$#$#! OQ!! /0000000000000/0AA@@@@@@@@@@@@A@$(()(# # !$%%$#"#$"#$"!! RRQPQQQQQQQQQQQQRQ憫憫憫憫憫憫憫拻乙佑佑佑佑佑佑岩((*+,.'(('PMHE61*%6=3:?@EEPOUV^bdeddcabaa_[ZZWVUTTQQPPQQQQQQQQQQQQQQ悙悙悙悙悙悙悙悙醒乙乙乙乙乙乙右*(+*'&(())ROJG>7-&277;@AGHOOVVadhihgfdeec`\][WVUTSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((3455?CGJQQ\\_bgkjjgcba__^\YXVVUTQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((7998?BGJOOYZadhkjjgcba__^\YXVVUTQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((ghhg?BFJVUVXfghllkhdca__^\YXVVUTQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((lmkj>BFITTSTlgfhgfccba^`^\[XVVUTQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((ijihjjjjmf\T[dfplgpmb^[_^YZZVUTSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((ijihjjjjlga\acmggjdbf][^X_WRUTSSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((ijihjjjjkigfgceqmdlgai_a[\XYVUTSQQPPQQQQQQQQQQQQPQ}~~~~~~~~|}~�憫岩乙乙乙乙乙乙矣))))))))))))))((((ijihjjjjjklmjcebkbig_dZb`b[YVUTSQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj疮jda^\YVUTTQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj┋dj_\[WVUTTQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjj吵朝WVUTQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjǔ碑┃VUTTQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQPQ}~~~~~~~~~|}~憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQJ�y}}}}}}}}x亃憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQPL�}}}}}}}}}x厐憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQON媻憫憫憫憫弿妸憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQNO悙憫憫憫憫帍悙憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjQQQQQQQQQQQQQQQQQQ悙憫憫憫憫憫憫憫岩乙乙乙乙乙乙矣))))))))))))))))))jkjijjjjjjjjjjjjP__d[R\VZ65657757镳痧铑瘃鹕扇崖糖犀Ё0*猒枤悥vx{volnnooonedfdeeed潧潩洓潧潙拺晱拫憗墖啀墘媁敄晵ns~wnonnmmmoddedcccd潨洓潩洖洅挄悢悡梾寜崋媷匶噟JO`hGAWnoln]CCYX@CVccb潉PP倐PO儜敀崁J\�POypBQjU�8憮A0jc7hONn5lo64dd6dKN�5洔44湞5厗}儃Ma�7寢88巸2Mn2ZS:8LM6dfih7QQ57ML5ddd�6hj66jj6倖儌n^�3b^19d`3[q;sc87`e6e\Zk7lm66ee5fWX�5湝44湝5剟妬坈e婤帇9.倊=[x^EIc^=AWfZ[j\CDbdBEhbYY渷ON倐NPq匽^}wFPypKIspAKtZuroqkljefffiikklotwune^b櫄灐煙煗渿亝厖厯悎増寖寙媄wvumkggedegiikklotw}~亗j枤晹煚煖湋剟剟厯悏妵垗啅哯wxxqqqcebdhiikklotwv{亞厫彔挀櫁洕搼剟剟攽墛媼厤唹Zwvupoomwmggiikkknsv倓厖�悐枓枠殭洔敀拻挀憠姂岻ZTrZwwwwwwuvnnnliikknruz|亜噳崗悞枠殰湚棓憦搼噳寚増UfZwwwwwwuvnnnnmmmmosv|儐噳崗悞枠殰湚棔拹悘垑帀`IrZwwwwwwuvnnnnoommosv|儐唸寧彂晽櫅洐枖搾敀悓噥|奨aZwwwwwwuvnnnlookjmqtz}亜唸寧彂晽櫅洐晻敀搾憥剬F^Nn[uwxwwwwxmoonoonncddfp墕噾垨晻摌湣敋櫀棖敁拸墏崏Ywuwwwwwvolmmnnmnfcd_ade嫆晻憯湜湗湙櫁棗枔悓墕亝刐vwuwwwwxoolopponddagecab湗姂摌湙湢櫄槚敂敀帇垎亐|Z[Z\[[[[[75667766 镪铑殇彡龛帚嘹滋蔷菠棆�pdZZZZZZZZV�儊億亖5锺痧瘃痣鲛驽仝羡新棆pbZZZZZZZZV�儊億亖5锺痧瘃痫裢钨僬帐汤枅}pbZZZZZZZZV�儊億亖5锺痧瘃瘃钇门铺拖丫保晧}pbZZZZZZZZV�儊億亖5锺痧瘃痫裢嫌刑赡识yoaZZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师Α枆}seZZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师ΗΕdZZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师ⅴぃZZZZZZZV�儊億亖6痧耩瘃痧锼仕耸仕师ΜぃZZZZZZZRp|�z�r6痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZa44638)66痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZP67449786痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZW2?;@4416痧耩瘃痧锼仕耸仕师ΖΗウZZZZZZZY65666676耩痧瘃痫鹗怂耸仕师ΖΗウ︻腚痤篥#$!% $$#悜憮憫摀kmmmoomno捃苓哕茑鎹弶崱渉ihihihj剝剟剟厒||}{||{~}殫棗棙洊e`beechh飪枏嫕潬瀓ijijikf厔剟剟剟|}}~||~}{棖棗棖潥c`cdcf`d韼洯睗浐祾kgii┆敀碑搨厓|嵀瘝嵂皪枛枙⒍簹伄y罚冹柪拺聊垈縷櫃g絞j吕儐箠煟|纜}亮}|聇tsq珮篸b概ee捻椏Ι玖絳xts緮椑陇@垉儅罏溋翜灺stlqt鞍災憲几憯鹅柦憫吕垈緙妵t糹m懒剝膩敀{纝~亮~|羢ruop柇暳b`募bi令枩吹洐帛巤妶q偍珆~剗晳嵂睄嵄畤s洆n啱储x━亁ⅷu頄攽強墜�垀zxuqmihhhku儘儅u倅xyz~{寉tttt櫁afdbj_ib顧殭儗弴唥~xuqmihhgdegiyw{僾倓剒v杶tttt櫁bfff_e_f霔櫃晫悋倖zxuqmihhhkigej^kyy亐yt枱ssss殬bfccjdid顧櫂櫂崈噰|xxuqmihhgabdfdjnhrwz}|y枦枛枛棗af_c渰饹潨湝湜x|pvvpfaobgijjedfjlort}剮敚殮挏檉addfa攬饹潨湝湜沬lmkllmlflleeeeedgjmoruw{亝悞挀殟gaf_n幇w饹潨湝湜漡ecmllkflfgfgggedgjmoruyy{{剬彈枡icZdqh弿饹潨湝湜hdlnnl`厀fffffddfilnqt�}{墛媿棌hpe^�驖湠潩潩渒iihhhhh亜儈tf\gdqdismy|v{}噴崙枡洓攎chff餄洔湝湝渒lihhhhh儏剠剛�skjilll{vx亞垔審棛洑灃暀hh驖湜湝湝歨ijjjjjj儏儈�倓剝{koxny~��噴帒晽棙暅牉殮瘃铖镲镲�""#"""""拻摋晵彈lkqolZVmiq問”教总唔桄眇痧痧痧痧痤儊個|��#拻憭拻拻nnmnnnnjo崜殭泊逸皱滗殪祉痧痧痧痧顑亗�|��#拻憭拻拻nnmnnnnsn廨)哲汜嚯熹祉痧痧痧痧顑亗�|��#拻憭拻拻nnmnnnnpv捩噜劾脏茔组沆腱痧痧痧痧顑亗�|��#拻憭拻拻nnmnnnnhk谳捋坩佥咱阼桧祉痧痧痧痧顑亗~|�"憮拻拻拻nnmnnnnoo蒉捱捱捱驿潆祓痧痧痧痤儊倊|�"憮拻拻拻nnmnnnnoo蒉捱捱捱 祉痧痧痧痧顑亗~|�"憮拻拻拻nnmnnnnoo蒉捱捱捱 痧痧痧痧顑亗~|�"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧髗~�~唨z"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"%!(""憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�&&&& ('"憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"#&" "憮拻拻拻nnmnnnnoo蒉捱捱捱痧痧痧痧�"#!"!""!拻搾拻拻nnmnnnnoo蒉捱捱捱UTRQRSSSSSSSSSSRQQ彁悙悙悙悙悙悙悜涎矣佑佑佑佑友闲*+*)))))))))))))))iiiiiiiiiiiiiiiiSQSQQRRRRRRRRRRRPO拺憫憫憫憫憫憫悙乙佑佑佑佑佑佑乙++****************hhhhhhhhhhhhhhhhRS !-000000000000/.0=?@???????????=;''''''''''''''''6666666666666666RS     /222222222321102BAA??AA@@AA@@@?=%&&&&&&''%&%&'&'4565566334545774UW !! !#"1011112222212223CA@?=BC?@AA@@@@?#&&&&&&&&%&%&&%*3565587424556875WY !##"! !2//0000000/.431.ABAB77401+晳3悙0摃晹B晹A敂D@CDD@弽實弾彁帊悘-0111111/-(敁&((77弿悗9678弿悞96X\%'憦.拺/帎憯@帍@拸8>77304.枑2摀1拻挀B拺@搻?@B>>?憪摂拸悡敃憫-100001133.敀'('65426悢765535摀7Y[((搻.-10帍悞@<<@拹9=7:8455枓2001拻憫BCB@搹@@ACB?悜拺憮搻-3010.11331攽'&&55243拸954255拲:YZ('晬-,/4憭搹<@@<悢>;:搼93;憭6201悥搶F>=D悞D?B崒@憢寭拰憤,2143/0./0/憦$"&84;70敂683:73摀8YZ('-搸0/嫇9:搶BB崝=>;:搼93;2拸43悥2E寪CC崗DD?B崒@媿帊崕彁.421悙003421搻# &墢8:8憫5墡8::悙6YZ('*-拺悞45<<彅攼=><=8:866635攽憮21C@悙悕DCA?ACB@憭摀搾悕74312敁1/21悘彁弽(7悑悙�:76弸憫�98YZ(()++,0476::=>@@@><<99866433321000122137=@AAAAAA422//1/0011/,**(7777888777778887YZ((*++,/2579;>????>=;:9866533321000122236:>ABBBAA43210000000-(%%%6665444455554444YZ((*++,04678:=>???>=;:9866533321000122245676669>A%&(+.000000.)'''6666555555554444WX&&')+-.03579<=???>=;:9866533321000122234345669???>=;:9876533321000122233334666866421%&)+/111111/)%%(6666666765744725QR "&*-/247:=????>=;:987653332100012223333455555542.&&(*/222222/)%%)6666666557577:15QR  !""!!$&8:=????>=;:9876533321000122233334555555310,+)'''&&('&&&&&&&&&%%)666666679758帊65QR "#8:=????>=;:987653332100012223333455555542.-*((('%%'''''''''''%%(56666666675憮�76QR   !!!!!!"<<;::976654443100012223333455555542.-*)((%%%%&&''''''''&&'4666666677摀晹66QR  !!99:::976654443100012223333455555542.-*)(($ %%%%&'''''''''''366666666攱5搻96QR  !! 520//146654443100012223333455555542.-*)(($ ''''''''''''36666666彅<6摉96QR  !"2////034433332211012223333455555542.-*)(($ $%%%%&&'&&&&46666666悙晳搼�5QR  !"2/////01101112111122223333455555542/-+)('$  "#%&%%%%5775566665;3搼45QR  !"2/////////////./0122223333455555542/-+)('$  "$%%%%%687556655888拺97QR  !"2////////////026:=22223333455555542/-+)('$  "$%%%%%687556689888挆97QR  !"2////////////./3;>22226533355555542/-+)('$  !#$%%%%68755675588崜弾8QR  !"2////////////./1>@@@@@<:63344455542/-+)('$  !"$%%%%%%&%"7447789::8QR  !"2//////////////1@AAAAA?<96555555542/-+)('$  !$%%%%%%$##5433346777QR  !"2//////////////1@AAAABDDCBBBBB55542/-+)('$  !$%%%%%%&&#" !!!5555PQ !!!!!!!!!!!"!1000000000000//0?@@@@@??@A@@@=:7542/-*)('$  !#%%%%%%%&&"!! 6666OO !!!!!!!!!!! !/1222222222220/1?@????>>?@???@?;,+)('# !""#$'''&&%%%"#"!!!!!!!PQ !!!!!!!!!!! "-011111111111124?@AAAA@@ABAAA@><,-*('#!"  #$$%())(('&%#$"!!!"###ROQQRRRRRRRRRRRRRQ挀摀摀摀摀摀搾悗衔醒蜒行岩蜒蜒乙,+*(*)(('$TSGF42//0367BDGJORUY_beffeedcb``^\\YTRRRTQPPQQQQQQQQQQQRQR悙悙悙悙悙悙悜拺衔幸乙蜒矣乙已行+**)())('%USEC22000369BDIKPTWZ_cfffeedcb``\ZZXUSSSTQPPQQQQQQQQQQQPPR亐拺邢幸乙乙乙乙乙行*)))()((('''')-...147{yC`!bVV*$IiPMP$vIZ7h|2SA;Og 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 Y+c8_n;mL%auHyBL>4U}NZy4bJ0jyv;82|tP literal 0 HcmV?d00001 diff --git a/rs/moq-video/src/decode/test_data/vp8_64x64_pattern_5f.yuv b/rs/moq-video/src/decode/test_data/vp8_64x64_pattern_5f.yuv new file mode 100644 index 0000000000..867e52548e --- /dev/null +++ b/rs/moq-video/src/decode/test_data/vp8_64x64_pattern_5f.yuv @@ -0,0 +1,2 @@ +JJJJKKKKQQQQ悙悙憫憫悜岩蜒蜒乙乙))))))))))))iiiiiiiijk┆┅┅JIKIJJJJPPPP憫憫拻拻憪已乙乙佑佑************iiiiiiiikj┅┅JK!!!!0000000000BBAAAAAAAA&&&&&&&&%%5577776666JI 111100000/B@AAAA@@@@&&&&&&&&&$6466667777KJ99 20.011/1/0@@@@@@?@?@&&&&&&&&'(4855477475KJ 89! 12/2.202/0@@@@@@?@@>&&&&&&&&''8574654666KJ 憪拹>=>@憭拻0201AAAAAAB@悜憭拺憭&&&&&&&&'&悜敀7546搾KJ憯9憯?@憭1/彂/01AAAAAA@憫A彁悘彁&&&&&&&&(悙68悜66悜6QP'&搾3298拺拺;;78挀-1A拸?A?拻@A挀拻00挀-00憪''%敀6767憭拻88QP'&悡2297摀憭:<86敁/1A拹?A@拻@@搾挀/1悜01/搻'&%晹5875搾摂69QP'&搼4搻:憫拻:憫8拹12@@@?A@拻@悞拺悞拻0拻/00/01&'憭6憪7憦彃8慟P'&悞3搹9挀憮9搾6攼32@@A?AA拻@悞搻悡憫1憪11/101%&挀5拺5搹悢7扨Q&'搾2389悜拺::77拹230001@A憭@A搾憮0/挀00000000拺8677拹挀65PQ&'拺129;憫拻<:87悞14/憭1@?憮??憫憫1/挀/1/拺/1/憮6487悞攽66PQ&'-悡39挀>>敁:6拹914/憮0623憫A悜憪2拻./1/拺/1/0悡86拹99悜6PQ&'.-攽憭=>?>搾搾562300223322悙拻拻挀000000000000摂搾5655挀RP'%--0188>???;;765532102222335577/100000000006766666666PP&&-,2177=>>>::765532102222335578-.00000000006766666666SR"! !1278>>>>::765532102222335567/0*+00000000006766666666QR!" !2378>>>>::765532102222335556/1++00000000006755555555QR !!!!"!@>>=:97655321022223355750/**$$('000000/06766666666QR ??=<:87655321022223355750/**$$&&0000000/6666666666QR 11997655321022223355750/**$$%&&&&&&&5666666666QR !!!0/:97655321022223355750/**$$$&&&&&&%5566666666QR 0000/03511112222335566/0**$$%&%$6666666666QR 0000/02311112222335566/0**$$$%%$6666666666QR 0000000111112222335566/0**$$#"%$6666666666QR 00000///11112222335566/0**$$! %$6666666666QR 0000111100@@??2222557701++%%!"$$&&$#666767QR 0000111100@@@?43244666/0**$$!"$$&&#"757756QR 0000111100@@?@???>5466/0**$$!"$$&&%%###!65QR 0000111100@@??@@@@5566/0**$$!"$$&&$####"54QR 0000000000@@@@@@@@@@/0**%&!"$$&&$###""""QR 0000000000@@@@@@@@@@..)*#$!"$$&&$###""""QR 0000000000@@@@@@@@@@&%!"$$&&$###""""QR 0000000000@@@@@@@@@@%$!"$$&&$###""""PQ"! 000000000/A@@@@@@@@@ "%%&&$%#%!!!"OQ!! 00000000//@@@@@@@@@@!!##&'#$!##"""RRQPQQQQQQQQ憫憫憫憫拺已佑佑佑佑)*))))))****ii=>JKVXcdhidd_`[ZXWQQPPQQQQQQQQ憫憫憫憫憫研乙乙乙乙)*))))))))))jh>>KKWWbchjdc^^][YWQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))AI坴|墈墑噽妱攋刣c^_[[WWQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))zNRt唵ukx瀬{k}jdc^_[[WWQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))SU瀞坴渿um墦nup�dc^_[[WWQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))Kc9:梻k噡刵剅杙乨c^_[[WWQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))^JK唖r悥{v仛檢灋a_\[WVQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))恆[Ym塺妘妡榼帬┆猒_[ZVUQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))gkl�寁s崠p搣彚え┆¬TQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))N?@B唴梣歽厑噞洩QQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))MXG��w噮晞彍kΙQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))WY嘠攐晆x檰亞儩オ猀QPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))�+|L湒榿悘嫅唘ЗQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))湕\`厈m搱晄唘{ぁQQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))I刅iux噾zr{墱垼牚猀QPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))DnH檦k憲x坢�r潬QQPPQQQQQQQQ~~~~~~~~悙乙乙乙乙乙)*))))))6]?敄ms摍p}噯r牘QQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjkkkkljQQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjjjjjljQQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjjjjjljQQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjkkkkljQQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjjjjjjjQQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjjjjjjjQQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjjjjjjjQQPPQQQQQQQQ憫憫憫憫悜乙乙乙乙乙)*))))))))))jjjjjjjjjj蒇圯YZ86558痤铕耩缮仕狮ЕΗ迾枟wympnnkbeeed潧洕洕憭拺憠垑増蹠檿iwomonnecccd洕潧灈拻挃拪妸妸輺�NBXYCDancccVCP倐PO儜敁抸LKttKZu5ji76fh5nLLf6e�44渼5區c�5垑44塟s5QP65NP6ndbb7Mj66j\7剟厬6__55_Ys4lh54fi6k`fc5d�44渾6僶p�6垑77塟taBDYXAA_j_fxlAN倐NIp俽o噊JKttKZqplhfdgikmouy儔湝洖剛剟剢噴妸奪ywkgedfhjlntx~倝帒潧渼厙剟噳墘塝vyvweegikmouy儕審摍殧厓儏噳墘塝uxutyohjlnpvz�剤寬挅櫅拻晵媺墘塝wwwwwnnnjnpux�剨崙敇殰殬挀媻垏嘫wwwwwnnnmqps{~儔寪摋櫅檾敂妸妷嘫wwwwwnnnnmdez}剨崙敇殰殫敁悓妷塝wwwwwnnmppddec儔寪摋櫅檾枖悓剝塠vxxvuomnnodcccc湇悢枦殭棓搹媶儅Zxuwwwmnppnfdddd湜潠槣洑棓攼妱亄[wxuwwoopmmdcddc湝湚殭湗棓晵寙亃Z\Z[YY55765痤眇痤慑菰湍瑱僶Z[[ZZZ亖��6痧痧罓櫐珖湶瑯刾Z[[ZZZ亖��6痧痧匠殫癁瓨僷Z[[ZZZ亖��6痧痧磽瑥榾刵Z[[ZZZ亖��6痧痧晶敱垑渱ゥ╫Z[[ZZZ亖��6痧痧衫殶悧爮ΖΖZ[[ZZZ亖��6痧痧浆垟憯瀽ΖΖZ[[ZZZ亖��6痧痧幋獩灓檨ΖΖZ[[ZZZ亖��6痧痧堪槪槮珎ΖΖZ[[Z[Z76666痧痧痧缮适师ΖΖZ[[Z[Z76666痧痧痧缮适师ΖΖZ[[Z[Z76666痧痧痧缮适师ΖΖZ[[Z[Z76666痧痧痧缮适师ΖΖΖē耦$!#"$憯拺抦oomno捃哕�墛湠likji剠剟剓||{~}殫枟杁eeee妶嫕ihijg儍剠厏||~}{棖枛檈dccd棾矔挰瑍h剝倲崓崠枙棧┇{{柭憡缆{v耴%喞剗亮}s胵櫕樋dd亮d顤璃っ聻浝n剠偭亮湙縯uq櫭搼览戰椌弶谅}w羗~~劻倊亮~s聅噲r耬e侣e饢灤矔挵瓌k~f|氨崓碑噕唶s啰珃z様拤厒}wslhihgfg|}|}usssrrccccc駸洃媱儁wslhihgffim|||svrqtddddd餃灉潌亄vrlghgfedjnpu~杢turcdddd饻潧湞k{vrlghgfechnqt{枟槚edddd饻潨湝ihhrniihfedhmqvz儓枤cccee饻潨湝ihijhgjgegdhnqvz�儓彃ddadd饻潨湝ihiji剟ffddhmqvz儔帞棗cde饻潨湝ihiik亝厖fdhmqvz儔彆槝殯d駵潩灉khhjk剟儎剓ikrwy�剦彆棗櫅滎洔洕渋ggih剠剠厎}|rwz~倞彆枡櫄氿洕洓渋iiij剟儎剕z{{|{唹彆棛殯濐镲瘃�#"!$#搼悜憂olknm蹝┗堰徜殪瘃痧瘃����$挀拻抧nmnL8v対=p斥骁祓耩痧駙���$挀拻抧nmnNEuq�〃徨骓瘃痧瘃����$挀拻抧nmnAF甪橾o珀眇耩痧駙���$挀拻抧nmnP&&&&&&&&''8574654666KJ 憪拸?=11敁拻02/0@@@@@@B@悜憭拺憭&&&&&&&&'&悜敀7546搾KJ憯;摂@1憪1/彂//0@@@@@@@憫A彁悘彁&&&&&&&&(悙68悜66悜6TR'%搾3298拺搾<<13彃,0@憪@B@拻@A挀拻00挀-00憪''%敀6767憭拻88TR'%悡2297摀挀;=33摀.0@憫@BA拻@@搾挀/1悜01/搻'&%晹5875搾摂69TR'%搼4搻:憫摀;拵7搾01??A@BA拻@悞拺悞拻0拻/00/01&'憭6憪7憦彃8慣R'%悞3搹9挀挃:攽6枔21??B@BB拻@悞搻悡憫1憪11/101%&挀5拺5搹悢7扵S'&搾2389悜憪9977拹12//=?=C悞AB搾憮0/挀00000000拺8677拹挀65TS'&拺129;憫憫;987悞03.悡;BA敃@@憫憫1/挀/1/拺/1/憮6487悞攽66TS'&-悡39挀>=搾96拹903.悢.36:枔A悜憪2拻./1/拺/1/0悡86拹99悜6TS'&.-攽憭=>>=拺搾5612//102.<9搻拻拻挀000000000000摂搾5655挀RP'%*,3688>???;:86643201111234550/00000000004676666666PP&&,+1177=>>>:98664320111123455.100000000004676666666SR"!+)5378>>>>:98664320111123454362.2/000000005676666666QR!",(3/78>>>>:9866432011112345547013/000000005665555555QR !!!!97?=:=69766432011112345675..**"#"$-200001.6666666666QR 63@==?89866432011112345675..**"#'(/100001-6666666666QR ! 89::866432011112345675..**"##"&&&&&&'(7666666666QR !!;;=;866422011112345675..**"#&%'%%&&&&'7666666666QR 0002565211121112345575-/**"#$%%"&'6766666666QR 0112232001121112345575-/**"#%%'&&&6866666666QR 0000101011121112345675-/**"#&&6866666666QR 0000/./011121112345675-/**"#"%%6866666766QR 0000000011?@4205546686.0)*"""#$%%%42655666QR 0000111111?@5102235675-/()!!"##$%$35855447QR ! !0000111111?@>@AC:73775-/()!!"##$%$#!!$4484QR ! !0000111111?@=?@A853875-/(("!"##$%#""""5355PQ !  !1///000000@@@@@@@@@@27-.((#"!"$%$""##"#%%%PQ !  !1///000000@@@@@@@@@@265/++#&!"$%$""##" PQ "  "1///000000@@@@@@@@@@')$ !"$%$""##"!!!!QQ "  "1///000000@@@@@@@@@@$)'#!"$%$""##"!!!!QQ! "-02000000/A@@@@@@@@@ !$"$$)'%%$"!"""NO! !-0200000//@@@@@@@@@@#""#'%##$#!!!!TRSSRQQQQWPT搻搼憫憫拺已佑佑佑佑&+*)'''')*'+21AAHJSVcdgdcaa]YWWWPPRTRQQQQRPS搻搼憫憫憫研乙乙乙乙#**)))))**#+35??HLXZbfhfdcb`YWVVPPPQQQQQPP~}~}�~~~~~~釉乙乙乙乙(+()*+)'BTeyn}悊R~gw創t歞c__\XVUQQPQQQQQPP~}~}�~~~~~~釉乙乙乙乙(+()**()孧xguvs|Y唨sw寶qcd__\XVUQQPQQQQQPP~}~}�~~~~~~釉乙乙乙乙(+())))%M歐m劇搶殱ox噉俽dd__\XVUQQPQQQQQPP~}~}�~~~~~~釉乙乙乙乙(+()**)+q峅.歶択|mzt寎o俠d__[WVUQQPQQQQQPP~}~}�~~~~~~釉乙乙乙乙(+(*)*)"噾(.湏�寶弰}r洖ea_^[YVUQQPQQQQQPP~}~}�~~~~~~釉乙乙乙乙(+(*)*'0tnf1}垯z憏槜偄╥b]_[]OVQQPQQQQQPP~}~}~~~~~~釉乙乙乙乙(+()))(+y�``搙n{塺{sz帲オé猑ZVVQQPQQQQQPP~}~}~~~~~~釉乙乙乙乙(+()**(*i梑K潕噦塸湑hy\WSRQQPQQQQQPP~}~~~~~~~~釉乙乙乙乙(*()*+)'ib^Ym姎寕�嫐w牗QQPQQQQQPP~}~~~~~~~~釉乙乙乙乙(*((()*'m9/g搕l泈|{亷wェ┅īQQPQQQQQPP~}~~~~~~~~~釉乙乙乙乙(*((()*)|ucd乵宲攬妳弙灖┆QQPQQQQQPP~}~~~~~~~~~釉乙乙乙乙(*()+-'2Uj們湌|檔宮nq崸—┆玅QPQQQQQPP~}~~~~~~~~~釉乙乙乙乙(+()+,'.嶽婾宱剕�tiq晑イQQPQQQQQPP~}~~~~~~~~~釉乙乙乙乙(+(*)')(Kd�1t杺悡倧u墿灙猀QPQQQQQPP~}~~~~~~~~~釉乙乙乙乙(+())))(TLK3t~殤w悎噞導牚猀QPQQQQQPP~}~~~~~~~~~釉乙乙乙乙(+()*,*'JXmu~憣寯帣悪{々QQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(*())*)'))$0meknfjighhQQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(*()(((''(*'ljjgijjjli┆QQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(*()((((*+*)olmkjkkkki┆QQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(*()(((()**)ljkijkkkji┅QQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(+())))())),jikjjjjjjj┅┅QQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(+()))))*)),jiljjjjjjj┅┅QQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(+()))))*)),jiljjjjjjj┅┅QQPQQQQQQQQQ悙悙憫憫悜乙乙乙乙乙(+()))))*)),jiljjjjjjj┅┅蒇圯WY62558痤铕耩缮仕狮ЕΗ迾枟wylmnnkbeeed潧洕洕憭拺憠垑増蹠檿vwikonnecccd洕潧灈拻挃拪妸妸輺�NA]_DDancccVCP倐PO儜敁抸LKttKZu5ji76fh5nLOf6e�44渼5區c�5垑44塟s5QP65NP6ndbb4Mj66j\7剟厬6__55_Ys4lh54fi6k`Xf5d�44渾6僶p�6垑77塟taBDYXAA_k_fx_?N倐NIp俽o噊JKttKYsnmkcffillquz�剻洘殮�亞剟唸妸妸Y{ulhcdehklpty剦崨湚檮剢剠垑墘塜xwwjfhghlmquz�厖嫈晿洅們儏垑墘塜wvvuwdeklnrv{�厛妿晿槜摀晲妷増圷wwwwwnnmloqux�唻帓暀洔殩拺妷垐圸wwwwwnnnnqqu{亞妽憯槡洏敃拤妸垏Zwwwwwnnnnkbvz厠帓暀洔櫀敁弸妷塠wwwwwnnnqmccez垑崙敇殯棔枔強儍塠uwytvpknnodcccc寢帗槡殮櫁攼悈�x\vtxvwnmppnfdddd煖晵殬殮棖搸媴倇\vvvvwpnpmmdcddc櫅櫆棞灄枛攼墕倄XYY[YS44765镳盹瘃汔菡透珯俻Y[[ZZ��~耩耱笧甫暴悜珨�qZ[[ZZ��~痧耨樖彄暢湩獥�iZ[[ZZ��~痧蝻撢帠巺▕瑯僲Z[[ZZ��~痧耨惞嚚〝瑥И乯Z[[ZZ��~痧耱箍。棈ΖオZ[[ZZ��~痧耨棟櫙煄ΖΕZ[[ZZ��~耩蜢З潩暚渿ΖΖZ[[ZZ��~耩耩呕巿槏ΖΖZ[[ZYZ78666耨痱铐扇瓮泰ΖΖZ[[ZYZ78666耨痱耱耸缮圣ΖΖZ[[ZYZ78666蝰痱镳嗜适师ΖΖZ[[ZYZ78666蝰痱铑惹适师ΖΖΖē铖 !#"$憯拺抦oomno捃哕�墛櫉imkji剠剟剓||{~}殫枟杁eeee妶櫈kgijg儍剠厏||~}{棖枛檈dccd棾禆劕瑍h剝倲崓崠枙棧┇{{柭憡缆{o絟ⅰ偮唥亮}s胵櫕樋dd亮d顤璃っ聻椊l儎嚶亮湙縯uq櫭搼览戰椌弶谅}x羖|弬純~亮~s聅噲r耬e侣e饢灤矔挵眴k|}d幊睄嵄畤v唶s啰珃z枓悑垁~vqkihhgey{~z}osssqtecccc餄檹妴剏vqkihhgfai{}}ztwqqvfdddd須湚寘uqjghgfdehnq}榮ussedddd顨洐湝yyurkghggd`glrx}摃棙恉edee饻潨湝ihspmigefeeinrw{�創殧bddef饻潨湝ihhkkgdgdcejorw{亜墣攂dacf饻潨湝ihllm乮icefinrw{�剫晹梕dc`顪潨湝ihhgi儍唃heinrw{�剨帟殨渇c頌牄灉hkhjk剟儎刢jjux{�噵悢槡潤橉潩湡瀎lgih剠剠厏zpry}�亷悜枠櫃欘湞洓歨iiij剟儎剏z{}ty{倠彄槞槡氿耧铑�#"!$#搼悜憃nmnjr�敧坑茔珉腭耩镳個���挀拻抧pomI<秺u{\n骈祆瘃痫饌����挀拻抧pom6S`ii眛氫漕镳耩镳個���挀拻抧pol/fYr^E�噫桀瘃痫饌����挀拻抧pon0IS洆r�骜瘃痫饌����挀拻抧ponKQ媇剢l  瘃痫饌����挀拻抧pom<:r~l瘃痫饌����挀拻抧ppk@;墑r焫 瘃痫饌����挀拻抦oomLM塐fPh瘃痫锺"#"$#挀拻抦omnqp佘溧� 瘃痫锺"#"$#挀拻抣nmnoo捱揶�瘃痫锺"#"$#挀拻抣nmnmm苘噙�瘃痫锺"#"$#挀拻抣nmnoo捱苒�JJJJJJJJPPPP悙悙悙悙悜岩行行蜒蜒))))))))))))iiiiiiiijk┆┅┅JIKIIIIIOOOO憫憫憫憫憪已蜒蜒乙乙************iiiiiiiikj┅┅JK 0000////00BB@@@@@@@@&&&&&&&&%%5577776666JI1111////0/B@@@@@????&&&&&&&&&$6466667777JI%!(1/-2202/0@@?????@?@&&&&&&&&'(4855477475JI !!02.2/313/0@@?????@@>&&&&&&&&''8574654666JI 憪摂$"00搾摀1301AA@@@@B@悜憭拺憭&&&&&&&&'&悜敀7546搾JI憯>拻"0悘00悞001AA@@@@@憫A彁悘彁&&&&&&&&(悙68悜66悜6VT)'搾3298拺拵4013彃,0@憦?A?憫?@挀拻00挀-00憪''%敀6767憭拻88VT)'悡2297摀憪5533摀.0@憪?A@憫??搾挀/1悜01/搻'&%晹5875搾摂69VT)'搼4搻:憫拺8帋7搾01??@?A@憫?彃拺悞拻0拻/00/01&'憭6憪7憦彃8慥T)'悞3搹9挀悡9攽6枔21??A?AA憫?彃搻悡憫1憪11/101%&挀5拺5搹悢7扷T('敁349:憭拺::77拹61>;BB=@憮BC搾憮0/挀00000000拺8677拹挀65UT('搾23:<拻拻<:87悞05;晼>EC晼AA憫憫1/挀/1/拺/1/憮6487悞攽66UT('.憯4:摂?>敁:6拹930.敂1:@;棓B悜憪2拻./1/拺/1/0悡86拹99悜6UT('/.晵挀>??>搾搾56/2-,.2<==:攽拻拻挀000000000000摂搾5655挀WT($,.5899?@??;:755321/0111227=@0/00000000115776667777TS('.-3388>?>>:9755321/0111236:=.100000000115776667777TT%%-+7589??>>:9755321/011124577272/000000116776667777PS%(.*5189??>>:9755321/011124555543/000000116765556666QR ! 319;>A>?A:;755321/01112345675..)&'(/100000,5566665555QR !!<<:;<<755321/01112345675..('#"&&&&&&&'6566665555QR !" !" =;==?=755311/01112345675..((!"&%'%%&&&%&6566665555QR !!!!.26<787400011112345575-/**"#%%&''$&'6755556666QR !!!!/2594542/0011112345575-/**"#""'')(&&6855556666QR !!!!0012323200011112345675-/**"# !!&&6855556666QR !!!!00//101200011112345675-/**"# !$%%6855556766QR 0000/////0133-22546686.0)*""!"$$7554677888QR 000000001.205023235675-/()!!!"#%6655947669QR ! !00000000//CDB?52:73775-/()!!!"%#&##"3766:6QR ! !000000000-DBBB54853875,/((#!!"%&%$$!537577PQ !  !1///000000@@@@@@B>:747,0)(#!!#%'%$$$#%"!53PQ !  !1///000000@@@@@@A?<8332.*'" !#%'%$$$$""$45PQ "  "1///000000@@@@@@A@??/-0+" !#&'%$$$$"! " QQ "  "1///000000@@@@@@@AAB-5)''!!#&'%$$$$"#$"#QQ! "-02000000/A@@@@@????)$%#$%&&&&$#%%#"NO! !-0200000//@@@@@@???? &""#%%%%%$$#! TRSSRQQQQWPT搻搼憫憫拺已佑佑乙乙)&))**))))*)0.A''''&&&&''8574654666JI 憪摂$"00搾摀1301AA@@@@B@悜憭拺挀''''&&&&'&悜敀7546搾JI憯>拻"0悘00悞0/1AA@@@@@憫A彁悘悜''''&&&'(悙68悜66悜6KI挃!#98拺彁1313彃-0@憦?A?憫?@挀拻,*搾.11拺-&(敀6767憭拻88LJ憮! 97摀搾2233摀.0@憪?A@憫??搾挀++憪120攼*&'晹5875搾摂69WU*(拻4晲:憫弾:憥7搾01??@?A@憫?彃拺悞拵*搼01100/&&憭6憪7憦彃8慩V+)悜4搹9挀拹;憫6枔21??A?AA憫?彃搻悡憤+拸2102/+&"挀5拺5搹悢7扽V(&敁3489悜拺::77拹61>;CA>@憮BC搾憮+,憮11010000拺8677拹挀65YV(&搾239;憫拻<:87悞05;晻ABD晼AA憫憫,,憮020搼/1/憮6487悞攽66YV'&.憯49挀>>敁:6拹930.敃.=?;棓B悜憪-彂.020搼/1/0悡86拹99悜6YV'&/.晵憭=>?>搾搾56/2-,-3;>=:攽拻拻崘/01111000000摂搾5655挀UW'&,.5899?@??;:755321/0111227=@0/00000000115776667777WV'%.-3388>?>>:9755321/0111236:=.100000000115776667777RR((-+7589??>>:9755321/011124577162/000000116776667777SQ(&.*5189?@>>9:755321/011124555433/000000116665556666QR ! 319;>@>?A::755321/01112345664--)&()0200000,5566665555QR !!<<:;<;855321/01112345664--('$#''&&&&&'6566665555QR !! !" =;==?=766311/01112345664--((!"'&(&%&&&%&6566665555QR ! !!!!.26<776310011112345564,.))!"%%'((%%&5666665555QR !!!!/257654100011112345564,.))!"""((*)%%5766665555QR !!!!0012323200011112345664,.))!" !""%%5766665555QR !!!!00/0001100011112345664,.))!" !"%$$5766666665QR 00/0//0010003-22546675-/)*"""###6465766767QR 000000012/1-5023235664,.()!!"#"$5566:56558QR ! !0000000010BAB?52:73764,.()!!"#$"%"$#485595QR ! !000000001/C?BB54853864,.)(" "#$%$#%"646466PQ !  !1///00001/@@@@@AA>:765,.*'! "$%'%$$$#%#"64PQ !  !1///000000@@@@@@@?<83,++(%"! "$%'%$$$$"#%56PQ "  "1///000000@@@@@@A@??+/-'#  "$&'%$$$$""!#!QQ "  "1///000000@@@@@@@AAB,,$!% "$&'%$$$$##%#$QQ! "-02000000/A@@@@@????$!!%#$&'&&%##$%#"NO! !-0200000//@@@@@@????""" &!#$&%%$$###! TRSSRQQQQWPT搻搼憫憫拺已佑佑乙乙%+%(*,*)*)+',4BVjk刴w 瘃痫饌����挀拻抦onmHC坔}弴 瘃痫锺"#"$#挀拻抦onnpo後谲� 瘃痫锺"#"$#挀拻抣nmnnm茌咿�瘃痫锺"#"$#挀拻抣nmnnm茌苒� 瘃痫锺"#"$#挀拻抣nmnnm茌掭�QPQPPPPPPPPP拻拻拻拻敀友蜒蜒蜒蜒************jjjjjjjjlj┅┅┅┅PQPQPPPPPPPP悙悙悙悙悜醒蜒蜒蜒蜒))))))))****iiiiiiiiij┆QP! 0000000020A?????????&&&&&&&&(&7555555555PQ !1111111112@AAAAAAAAA%%%%%%%%%&4555555555ZY"./00010/01?@@@@@@@?B&&&&&&&&%%7557764667ZY 0/11231212@AAAAABA?@&&&&&&&&$&6766586457ZY 憭悘! 00彃搼3101?@@@@@BC彃悜憦悜&&&&&&&&'&彁悞8878拺ZY敀憯 2憫0/憭012@AAAAAC拻?拻拻拺&&&&&&&&'搹77彁67憪9ZY拺 摀拻/000拻/.B憫A?@憯??悡拹)+憮101拺1%(搼7887憭拻79ZY憭搾憭3321拻//A弿@@@拻@B悢攼*)摂201憪1&(拺7776拺憭78Y[')憪7悜;彄拺8拹1憯1/ACC@@A悡@帎拺憭悗*拸010220'&搼7憫7憭拻7扽[&)悜6悙;彃憫<敀1憮10@@A?AA憫A悘拻搼弿)搻110110''拺7悙6拹憭7慫Z')悡47;;憫憱::78敀12?@@@@@憭AB憪憭))憭00001111憯7468拺憭75ZZ')悙64;;憯摀;98:悙0/@拻@@?拹AB憭搼*,憫110搾012憤6887拹悞77ZZ').搾3<悞B?悜::彂3003悞@@?@悤A拻搾+憫2110搾012/憦88憫76悜9ZZ')./摀拹B@<>拹搼33./2/@@@@BA拺攽悡彃/20000111110彅拹7865憮ZZ')..43::??<;:9765400001234@@@@0110000000005577777777ZZ')..43::??<;:9765400001234@@@@1110000000005566666666ZZ')..4399?><;:9765400001234444410000000005566666666ZZ')..43;:@@=<;:765400001234444410000000005577777777RR!..54:;@?<;:9765400001234555544//&%1000001.7566666666RR!//53:;@?<;:9765400001234555544//&'0111112/7566666666RR! " :;@?<;:9765400001234555544//&%#"'%'%%%%%&'5666666666RR!!":;@?<;:9765400001234555544//)'$"&'&&&&&&''5666666666RR! ::::765400001234555544//''!"&&&&&&&&''5666666666RR! ::::765400001234555544//''!"&&&&&&&&''5666666666RR! 0000765400001234555544//''!"&&&&''5666666666RR! 0000765400001234555544//''!"&&&&''5666666666RR! 0000000000/01234555544//((!! "#'(7866666666RR! 0000000000101234555544//((!! "#'(4666666666RR! 00000000/1=?1234555544//((!! "#'%'&66666666RR! 0000000000?@1234555544//((!! "#&%$$66666666RR! 0000000000?@@@@@666635/.((!! "#&%$$$$$$6666RR! 0000000000?@@@@@666635/.((!! "#&%$$$$$$5555RR! 0000000000?@@@@@@@@@35/.((!! "#&%$$$$$$####RR! 0000000000?@@@@@@@@@35/.((!! "#&%$$$$$$""""OQ !!!!!!!!!00000000/1>B@@@@@@@@('"" ""'&%%&%$#$#"!RP" 0000000010@@AAAAAAAA'&"# "!&%$$$#"!""! PQPQQQQQQQQQ憫憫憫憫悞杏乙乙乙乙*())++()><*'68?ALNX[gfeedcbaXWVURPSPPPPPPPPP悙悙悙悙拹研乙乙乙乙+)**)*(*@>)(47@CMNX[hgffdcbaXXWVQRRQQQQQ}}~||||}}}}����乙乙乙乙*())))))Dul�>rH\x寕|剬殌bc__XYTTQRRQQQQQ}}~����}}}}乙乙乙乙*())))))MUm?R塈qtRr垕噸奲c__XYTTQRRQQQQQ}}~乙乙乙乙*())))))B卙Mj�剅Z�慬�p媫bc__XYTTQRRQQQQQ}}~~~~~~~~~乙乙乙乙*())))))_晹qn噒wb坘b廽mlbc__XYTTQRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))倫>zz悂殣檯t憤榪dd_^XYTTQRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))憡敃�w噳w坣姂h昫d_^XYTTQRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))0e橺洉vpw檞殯仼燿d_^XYTTQRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))j[Ie崜抺仠}棡嫟d_^XYTTQRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))FP>:}pry亹vmw┅┅ZXUSQRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))WSI殝n~o}張噉wЖYXVUQRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))tUv昷巰寭殦塸┅QRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))NY塋j噡泏{x渙|Ж┅QRRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))U姎@杢y殅梻悵埀*猀RRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))Yor~�zu啒殦敄帬Κ猀RRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))�淕kk�嫇歴敍t暎潽猀RRQQQQQ~~~~~~~~~~~~~~~~乙乙乙乙*())))))r@剺檹mqz晭坥枹灙猀RRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))iiiikkkkjkQRRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))iiiiiiiijkQRRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))iiiiiiiijkQRRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))iiiiiiiijkQRRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))jjjjjjjjkjQRRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))jjjjjjjjkjQRRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))jjjjjjjjkjQRRQQQQQQQQQ憫憫憫憫拻已乙乙乙乙*())))))))))jjjjjjjjkjZ^\[YX;8574眇痦耧倘仁嗓イぅ]晿棖vmlmkpebbcc湞潨潩悢敀拤妷墛V晹棖xslmlneeddd湝湝殯拹憮拤垔妶T晙POi^CE_ndbdWCP儍PQ倱悞攟KMssMU�6枙73on6mOLe6b�66潑6僠_�9噳66塖r5TP88MR8nbdd5Oi77i_7厓剶8``66`Up4ke65ih5kVVd6a�55渿5僶n�6唶88嘥r`BBWY@B]jbTeXDQ儍QIq乸p刾LIssITrnkgdghjknpxyfg湜殭槀剛剟厖垐垐Trmjgdghjknpu{�啔洔湜渿儎倓墘墘塟vnigdghjknpvy亙寫棞灈攧厔剢垐垐Yxusgdghjknpv|�唻崙敍洆憭晵媼媼媄vwwvtjgijlnvz�剫崙敇殧拻悘墘墘塟vwwxwnlkjmrw{亝寧挄殱槜晸拫妸妸Zvwwxxpnpoopv{亝寧挄槣櫂枖搶垐垐Zvwwvvonopldw{亞崗摉枤槝槚晱墘墘Yxwuxymmpnncdh亝妼憰櫈洏枖攳噯妷[zvzvupnnrodeded媿挅殰櫃枖攷崊亃Ywwxvwnnmnodcedf煕棓櫈洐晹攺寘亃X]\][X;8777镲瘃忭赆谟司|iYZ[[����痫痧精才拰|hYZ[[����痫痧。卑ē|hYZ[[����痫痧仐櫂彧垥|hYZ[[����痫痧户�⿴悎彠搢hZ[[Z��������痫痧平箼à~jZ[[Z��������痫痧禆珦枍皷ΘЁZ[[Z��������痫痧獱煖厞儑ēЁZ[[Z��������痫痧牅棦梿�ΘィZ[[ZZZ66775痫痧耨人墒失ΖΖZ[[ZZZ66775痫痧耨人墒失ΖΖZ[[ZZZ66775痫痧耨人墒失ΖΖZ[[ZZZ66775痫痧耨人墒失ΖΖ痤镱眄####$憫摀恘mmnnm谳捋�顚噵墱khiig儐厓儅}}}|}晿槜梔cccc閴噲墭jkljl儏厔儅||}{|枛棗昬eeee鑹暤拨�┈j剛儠崓氨彈晽槧||嬄媹美lj羑煛兛厎览}徖r櫆暯fe览e陻隶@繜敿j剝伬煘侣灘縯ts柭拻揪掕椏崍晾yv縦敄吚厎亮}娊t噰s羏e览e闀湶矒惎瓍k搩敳睄嵄祰t噯s埅﹞{╇枑帀�yuojigi�儅|~~~ruttsvdeeee霒憦墑yuojigfgfz}y|~}qsttsdeeee駴攽墑yuojijifegkx}}|攗vrscdddd餄洔墑yuojihfgehlos{|晻棗杋eeee餃洕潩|{tnkjgggggjosx|敇棗梕eeee餃洕潨jhwmlifffffinrwz倕槞攄cccc餃洕洕iijhjjgggggjosv|亞墦昫dddd餃洕洑kiiik乫ffffinruy倕嫅枠cccc駶湝潨gefji儐俲fgknsw|�剭悤槞檊f饻殮湝jihji儌剝卙hprv|倗嫄晿櫄殯顭潧湞hhhjg唴剠儃zrru{亣崜槜櫄潩蝽镱镫&!"$&彂拺抦knm^p啑诌沅觌痫耩���憫憫nnnnK?Tyei^`滏觏痫耩���憫憫nnnn9=ⅳj彁犱骊眇锺饊��憫憫nnnn%6ut`朓z滏觏痫耩���憫憫nnnnN@9歖cN滏觏痫耩�������拻拻nnnnRI灖坹�殛痫耩�������拻拻nnnnK2漚kZ�痫耩�������拻拻nnnn=7剓ESB痫耩�������拻拻nnnn77m巕I痫耩痫#"#"#拻拻抧nnnon苻揶�痫耩痫#"#"#拻拻抧nnnon苻揶�痫耩痫#"#"#拻拻抧nnnon苻揶�痫耩痫#"#"#拻拻抧nnnon苻揶� \ No newline at end of file diff --git a/rs/moq-video/src/decode/test_data/vp9_100x66_pattern_5f.ivf b/rs/moq-video/src/decode/test_data/vp9_100x66_pattern_5f.ivf new file mode 100644 index 0000000000000000000000000000000000000000..52567b8dcbdc3e48f8615fb5c7df82faff9aa081 GIT binary patch literal 7452 zcmV+%9pmCeOG!om03ZNXP&qJU073vB0000100005000000000m3;+NC000000001j zNrOTF1~3E`1~?=f7(xIAkWgYD@cxhgkL3Ly{y$smdVjpH#QC2y)cSvq&S$?f^L%f| z_pSV&qxAZ15AR!#ZbPf*jq_pEqx4><{jdji z004fGlSTiB%(R4pqGiu;2)H!;0w>PX$?*MR%k*9-@R;H`tG-nRN88hO;GzX;gxop_7 zLc8k+HWy@4^ZVSDqR<176%Ji@x9vavf{b?+#g>o9_Qz^J{knZLrA=MG^$CH#bX;{! zINIKt?v>w|K!xa{?Osy$V$NJe42&pPvj`dzo<}dCc)h+|$TJ$Nwga z#${bbA|}4BdrA+%NUr8Gb7}cl=HTEt`SZ}6N*t<1SJ(Ze`=5p4g1`i@a>N>w|+c%T97A~+GCJ^c8 zJ$Gd!Ay^}*tUWY2ES_3+R_edN+oe=k@EXRc3qpp)@oKjkwl)Kaq|`~$Skqy4p=93h zLZ3cO@;?FNgkB@i-aBR{GnY~Be;(YGw;~yo`t?hcFC@E$$MoTC6%!F<8Rl(D7mx}DITQLAHf|Nhcj@J4f7lPK# zaJ+I1s_7?yn!Uvoptwn`q5zC_9ruAJE7F-xDs{ufAoX77kT@f@?*Gh1m!YTh2e)Ka z7z)(ek2*aZi!5ZP)b*|HZHDsZFfM<=Hk(sNP&ZIcPY6VI^ze+M8^jL;#|y?n49vehk1_a~Rac_kXg0cPyi_jM1OYhx?V44TE@7PUHn;ks1jIj~ zjQBB#N-Z!|*(dX^^IU>!{jW=7ste~ph)WLL<)?5Qm3dCiRfCD(ius8Sq zCo|L-!Zdxwov{*O@Qu&URZx0>+<*GR_F9QV&8xX7~3m`X8k8dRhTV1a3|dQ!g)6)#82Q3JnlmgLzCebEW3QDG{(hcW#cCA zqrC`JQ`u_iHd7gJ9fDNjao7FDC~xdhiHU&y51~Y5+#R7oxO^-dkor}PUh!APH|7C< zmW`^ByC6(vKHQip>bE<*6tX3G*<0kDeIvxU`s0$-((_|>D>H?5NRlTN+zAnCMXRx) z<3&ztRo^3)oewhXb1f$L6b0|+jgy_@1FQP9eJXN!4X!-7|Ngm)^}p-_)vV(;{on%V zAZ#He|Nie9w|3}I-Pe~r`^P2{%tu>#y8WL(B>Ej-_spDRa~@QOsN5#NJK!k7xkyRN z4`4k%9H4yKCmm}09|nFLME>l^d*$9dX5vbwcwP(3BvgH&Zyr^cT7f+6CdW`vW(!Ir zMjp08g=qV_xvf)1v`fnm^prX_xPQDGBZE)Q$@GRAgXN0X1}?yx3o$h&?#UNeL0yl1 z3I{C;sNu($JtJQg@#}H}3hvtikLA2DEKz;&cnh31Y zk*GhW-=SM>d~g!CJ-Jdq2vH!FeJ+ErTp}Y$eL3=rm^f;zKqAvy8!(DEqskn$vFO`b zV}r8n_bdD+__Xi|+jx_{@(b6Dn_>9B!Mf-_gfoW#a${4`Ds14;%so21zhEd2#Ek0p z@+AcEuL8Eg%ce$d(Wx=FJ zG@Pk_=?$%a*NG&IV*aT(cPs^dRH>d8#et(8$rIq6^h>^3c$JJ+>m~QM7?_}vy=z!Q z&K!%R1_Saf%U+O1tEH%`zECfz_7DQgRpj-@wr-){m>_4PZBQd(K*Nk#175zYb2y5Y zKq$-{RThbgr}>ZTae$GC?kuMO)XEKTO>BIXM4DR(b>i(Up3I8z0Dk8*Q{)0*oGlj; z^_jCv2`hgGi$-P9l8V4#aiBlER{K%cs9-L?BV*70^@?*rT;B`kb9B_FP?LsR3!JSfpbyZ*MyS40 z6N25_e2($hW{jx*slY_dk7GNxy=!o4EjrQJHx&*~IqHc8LxZOg*p$MvM-mPtWS$B3 zQVp8ih`k#$iNcsO_d<(E9X@9Sj?D^EX{F;v3H&qpK+p znnrSJDyiWg&T)eJRp1J?H>Hx%znoy{w8`88{4!<_WQlJ$r z>+`;hEz;(z6tdwHlIlQ=E%uSewj<;d5~))KEdvu2*JJZQA6ih*!PF6XVA;M%+Oigu_aVx+U|3?*K>6L%WI#)XkP+T#}60IK>5c!Ny^H6 zEnq5d#$!vNnd>JhQQ$}w9n5q|wLw^J`sXl3Zyk9D8_v$i26LF>q zO`K5vFIVgvC=FVoR9;`VN6uR3T|}s77BE_wnAg!HDFg3{P zRp)EP%^;-=O9WgGHbDB>) zx9gFhH^fr-fl5+?jWw*Ft+ZO2>ICk``BEt>Q8ib5iL7m#)JA_mVY_xDN%gduBkg)c z1_~gb+qZ|YIsPPot$PkD3Xx_tnhA4a!pWuRk}|%2N`c|wt{2?$AOA&Oa!7gQ50pIV8-Kzvc zzEJeJW0!_vLH(%P2ee$f|4|eldJz#lKVq{U$leS$PP=Ii&sGr-&P8T1$M>)mlbf~diVIz`6LR0=%9J3q>47BGc@ zXrGEm=m+s%|6~_?%-6Ty;dsY)+4yT9wX@8_G0goeoT|aeI#NzIXK+;C(o>JpW!n3dsBuq3s?X` z0ssI3000000001n06>!Pp(OwSICh3#7$%yW3dT6XI{*NE+fM)tFpGL6&qtzGlE#FvBhHo!B-;VR`JvX7~y01lg3w#7VqnZ8D^2bZ@F1l zHpuU<7dv@V^OLL+ba5M#pszPx4D>)>7(b-hLBV_2hIq9mgihj;w@*8#kyf$)^Wvi; zRKeFjFr2~@|Cvd2FK-Yg9i<%AhW>0LplB@dK?_mrrSQUdG3!yHf)<4B^s(yxI?%g@ zV(8>0?WVM;q>G1MHWr&MfnXd93WJ1Pq{Ge_8*@ydTJNZS3n1CmS~-Tf@8_(OqWJ5# zupf9-QiRetJI z4FWyU=oe6LZ&kB7cYRBTV$QU`UobuwF$0J{!fM~z4+E#vv$PT%kYml%dyz{Gz3lBK z-)mkHmS{$nk6uSPloV@ zk7e_rQ@8=o;~NUJm(oZD<2BRJu;TzON(Y1?lxIq9q&*Uo4-xI{xfhoYqq{JZGC)Pj z`7p-^S`+2dC4OBo`|m=#C@&N6q(~z!)bCzlT0jS^4YF}b;ieg6>FpN%&qsjvyqFU> zFpHzp=GjkJV^RD%kLut&A8`3MyED(^9Gc?!v2%Cd6Tt*LtJd}#9HjmnZY&ra?~26u z;le)2q|Tw#(&S{sBQZMTv&x?g7Qr%{m-yfflGCXNBqTNQV$pEmPTyQ85>>J=!) zBsV>jgjlHu0g$V16fA;ll>-G_ukM301`9)#=UW`zy%J>3O~eS_%1|_u!8f>DnS*5> zO+d0?hq@^`Hkyw_4PcJx7Hf~&q3poIOk$0M#o17sQ1^u;vI3#B_e|pjpbTsnHG`y?V zF?8!80H?E-RI*~Xry-aj3DWZCIK~ia7Nx0V0_{g<_Z%o2F2qs)<7Ylte|)W&u8ADS z-$6O{&iHy@X{s5s%S;pC=}v-8zs<`f%N+*BpYw4}X2lcgx}9WVIP}!ujz8{tHITRe z^_3YfmRT188M3ech=dx#i;l_P@Wz6~?rzlvn~IkT5GFH;QsWD+7A}DkK7IJ&B9>Bqi`I=5+qP)`iH>!zW+H?xGV$IweA`C}xsu0*%A&#=2*n1AjK+ zzKmxu75`&&pUB%yIR1mlVU4lJyI{p@3_AIbvIsN<_dj7WNXU$ho2WZS6fRG#TdS#A z_7S><$imI>d!usKDOSzPfgv{3GG(@kW#nPw$?q%d$F~xA*|&F+UmD<^?^G7#r>kY} zLIES!+h_}eaXnLE`1L!$KoLT)P(qu(!2kX{f^zL~j@lxWWr2JKJp7Z>CxB8SC-_wz z-BGlMJaeD2-m`tgRK#vD)l9_}#gDbK$^?N8)%29!_IS^3U&OzAnplv~pT6It|36f} zbDLYkSC0G-JIlKCw@k053ptW(*m7R(*p$2BZLZu-b`qPXA@jOyU1|>qaz6ZjS>Wy5 zOh!CE@8G3cL} zH+!9TCM+?ud!PUpNumM=+6Za$t3{(r+~kU)jQ>!CS6K+GD&G%b(3F>w%xKMK8ylu*mFzLZ z=27NCaLw>a4rzC3KmgGS2MGo!MY)j290rwp(JeE8=qBkMg6|KS)cw$r+tAND2cw zAbtCf6$w_MrmG!(B^#POA<{S2v?U=q&KV|(TPVkSfcVTR#Y8kk-J&`-f>{PI&1;Xp zKmV>`{oR}9Y4BEQFW&PcIK)q!3;*u$fh>2aTyz6piS&cc&wsnNiu)%&xaO|o>Gzg_ zfhg!6EE0h=exK0wO=?gHiiDX3^>G4d%v;x=(q{!S0J08VlJj9E#bCJW(E$dMOgPmt zF!cQ>=qwRJ`Ey2&8SxODi8s=*AeM?kTjylbGjH!86cMA`CT!C5w&QyVGpl=Jd13R_ zwjXZ)Wlo}@?l35ts)e05D^Uj&4^QF zPW0_>`21CjX*w_dQ7%0~9{SGF;uWcn73p%fR{AsvCk-q;G0f`XpF-RToOQAvE_P^b z6CYhw)Br^pmI@xUgYJYn?!+>RAcx)sILo5MAj3(hP6ET?CA%lPw?pgo{A^3)rPg1f3+TiI z<@>hSB!i+${a75s+xX)d9fsJ#y3#j49ro5UsIx0+p-O^2OP~)?G)euzc`|jyE{85X z8I!m{s?&x8@VfsO z>UYm=S?MJt5K5+AbiF1s9pXP}Sn9`hTp&Q3z_^0cLyn~}G^Jq>b?eQ&g4(5-cOBji8>|K`akGWOK>Od^#Sx}F&SFrQzS z(%l_?2dNhd(6CnzQq)ZN+-*ntb|HErFh}r7V$A&Nfa92L3+pz&UWK3USi;_kcK#G5 zE{3#5#o3G$xxPOJIJyQEjoF24{Lufadcenv*2_n8hhEliBV6vM2&N2Z6&ZF85>x@5 z*JcT+9~5!=?uY^K=N~OA3H}uzedu6!{&WH0QmI zpCfh>@n%P+>oZa|ZNE#S z6K~ht!^01a-cl*Q9QBi#0P+vvj|9wR5en-w(4Eaz;2+AtUlWtfp=*7&M#M`Eaq6t# z3`Vk+VU|K_jDSiMHHiJL_s4JQNm=r~%o89Qv?Z?!v<3kVH81DTquZ%bXAqe*f)5Ag zIJIk^xtw@lU_HBLOcY#fn(ibOB^9qz2oEnsO8e?_EX$4?i+p$&EZ@Bdn%13#fr7X4HCECx{V_>OPuBFs`}CLTA=N($a0qNg1W1^WRUHZp4VkpVEdAin$!Ac>kk0D#9FMlXjjPh+&K&q9M^1Dpu}}y=YAS a4F$5!Rmn3EJ$912Fv~8!O{v&1^Wp%KCRaZI literal 0 HcmV?d00001 diff --git a/rs/moq-video/src/decode/test_data/vp9_100x66_pattern_5f.yuv b/rs/moq-video/src/decode/test_data/vp9_100x66_pattern_5f.yuv new file mode 100644 index 0000000000..4b900422c7 --- /dev/null +++ b/rs/moq-video/src/decode/test_data/vp9_100x66_pattern_5f.yuv @@ -0,0 +1,3 @@ +LJJJLJIKSQPQQQRRSP悘憤憫悘搹帒搾拻醒醒蜒乙乙颜砸延**((((((((()()(()*ikhijhikihikkijlěЗ┅KJKIKJMKSPTSSTORPQ悙弾彃憫拺憫悙悜兄友中孕有矣已已*'&(*'')(**()(())&hkhgfkkikillklklèí┅KG ! "21310///1301/.-/@A?@>AA@@A?>@CB?&'%''&'%&(&&&&&$:577657468976578LK!!!!  /2/110.2-12/00./@?@ABA?=??@>A>AA%&'&%(#'&&'&&(%&5867685767635978MK  .,5465" !1/3//.//01//1..0A@AA?AA@A>A@?@@?)$&$'%%#$(%&'''(7765667774788676HH   .+5365"#"0.-0./1102023422?>@>?AAAB@?A@@C>'%%'&%&(*'#&&$%(5666776796755697KL!!帓彄4377憭憭@?/01/.//-14悜悡BBA@弿彁B>??BB@?拻憦彂晳&'%$$&&'%&彂搾(&87拻憥9759彁崘86LM悞 1憪37憭;@拺@0-00110.1彄21憫@@搻=>憪>A@@@BA悞悞拹彂%$'('$%$*悜()悡&5挄57悞58崕78憦9QN '拻,,//搾憯;<=?悞=<:帗:0/帓3100彅晵@=C?悘@?@摀@敀挀搾憮2541/0%'拻&&($彁拻8676憮搼6759悜QN$"憭*+12憫摀;:>;憫=<8悡601悞2010拺悡@?AD挀AAB悞?悤憮搼拹2/11/2'&憭&&&'拺憭9478彄搹87:6憦PO%%晲,彄-悞悜9敀A憪;<<87858憫4拹2挀憯?拸?搼=?C?AC悜憮拻拻搼彂0/2//1--帞(憮&憫憮6拻7憦彂7拺8摃SP%$彁*悘0挀摀9搾>憫;:;;:696摀5拹3憫彅@拹B憭BA@?>@彂悙憫憫悜枑012001/0憫%帓&悢憪6憪7拻拻7悜8摀RQ'"憮-)0.搾憮89?@憰;>8=8976敀572.摀憮@A@A搹A@A?BC摀憮搼拸/3110//0悡#%&'憫敀6664拺憭4656悞QO##憫,,00拻悙:9?=憭<<:悙887搻3112拺悞??A@拵@>B彄A憭拺憭悜/./11/2.彄%&'&悞搼7656憫憫6575拻RR$"*憫-0搾49挄9A憦?;<<憮8896搾40帓02拻14彃2@A>憭A憮搾挀憫0120拺./12拹2(拺(4拹57搼77憮77搼7PP$#&&悡彂6376拻憭=>=<:>986867敁拻1.0.悞搾43ABB?B@憫拻拻悜11//1拻001.3拹悢)&96攼拻7447拻憫85PQ#$'**,005287>==<:::9575532210000111222333346/01//011//00%$%'6676555376576576SS$%'))*-05474>9=>==<<:998675533321111222333444420/13431110/01'&'(6655546787554647PP !"!".02467<;??>@<=98875655333211112223334443485520./+'%&00/..///12'&%&67878:7668666856PO  -/0666;9>>=?;=9998675643321111222333444335884/..)'$%0/010...//&&%&6666795586878876QQ !!!!!! ";<>=>=;=9::96755333211112223334444436641//+-$&!# &%&%*00--///'(%%5555666958754267OO ! "8<><@===9998564421100///1012123322457642/.)+&'!! %#&&+1200110)*%&6665656587777777PP ! !! ! ! !".09;:::967664332011112233234445677320.,*&&!!! $%&'('&%%%!'%'9865565877悞悘85QQ  !  019;:976576532210/0011123234333577/2..,*&%! %)&$&('%%'#'%&765567778帓67拸:QQ   !!!/.61/.04566532100.0211123234343577/2..,*&%! #$&%%%%&66555778摀8559悜QQ  ! !00432112355320/.0/251322324434447702.-,*&%! "#%$$$%&67655858搻68:6憦QQ  !!103111001221112200211112324534447702.-+)&%"!!!#"#$%'56655577憫6悜8摃QQ  ! !101000000000111100111112224566546612.-+)&&"! """"%(35556764憭6憫8摀QQ  ! !0000000000000101@@@?0012333222446611.-+)&&"!!!"#$$('&%8488棏8856悞QQ  !!!0/00000000001121A@>?2244443244436611.-+)&&"!  "##$%'&&%7757弿7775拻QQ  !!!//100/0000000001=@?A<<7455436621.-+)&&"! !"##%&%&&&%""#%拺77搼7QQ  ! "//0000000000//01>@AB>>AB@=7355536621.-+)%%"!!"##%&%&&&&#$$$&悙憫85QQ! !"1/0/0110100000/1@@@@?CCBBAAAAA@?461/,++,%%#"!"#"$%%&&'&%$$$$""!! QQ# ! !4.//3.//000000/0B??@@@@@@@@@@@?@5642//-)'&#"!!##"%%&&&&%%$$$#"!! RS"! ! .00/000/..00001->?@>>@@@@@@@@@A@%'#!! ##"&%&&%&%$####"!! OR!!" !211.0./00000//1.AA@@@@@@@@@@AAB?#$! !!##"%%%%%%$$####!!! QR! $$#""!! 0///02100000112.@@>@?BBBAAAA@@AA!##"%$$$$$$$####"!! PN!!!# 1/01-//01100//0-C?@C?@@@@@@@AABB!#$#&&&&%%$$$$$$#"! PRNOOQNPPPPPPPPPPS悜拵憮搾憫悜憫悢延闲延佑佑佑佑邢++*(++*)()))))*+),gh:6;=FGNPUV[]dfggffdb`_^][ZYXVURQNPQPSNNOOPPQQQOQ憦拺拸彁悜憫憫悙有以有醒岩乙矣蚁&((+'('&'*(*('(**)hh77<=FFLNRTZ^fhihfeda`_^]\ZYWUTRQQQQQQQQQQQQQQQPR悕剚亊~~}}~~憫悙有以友岩乙乙乙蚁&((+')))))))))'.'*ikhjkkjgOOWW_`efjghfdb`a^_ZXYWUTQQQQQQQQQQQQQQQQNR拺}}}}}~}}~~憫悙有矣友岩乙乙乙倚'((+()))))))))'$**lnjghkjfQQXY`cefhgffac]b[^YYYWUTQQQQQQQQQQQQQQQQPS摂}}~}~~}}~~憫悙友矣已乙乙乙乙已(())))))))))))***)klihhjloijjhghggjifgfcaa]]]ZXWUTQQQQQQQQQQQQQQQQPR憭��~~~}}~~憫悙友矣已乙乙乙乙乙)))))))))))))((+()ijjjjjjkkljjjjggjjggdf`_]\ZZYVUTQQQQQQQQQQQQQQQQOQ憪�}~~~~}}~~憫悙友乙乙乙乙乙乙右))))))))))))))())*ijkijlljkjjjjjlié┇da``]^\ZXVTTQQQQQQQQQQQQQQQQPR拺�}~~~~}}~~憫悘友乙乙乙乙乙乙佑*))))))))))))((**)ljkjjijimkkjihji┄ec`_]^ZZXVTTQQQQQQQQQQQQQQQQQR拺}~}~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))((**(mjljjijhjhkijkkj┅┅[[XVTTQQQQQQQQQQQQQQQQQP彂}}~|~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))))+*(kjjjjikjkhkhhkjjī┅┆Θ[\XVTTQQQQQQQQQQQQQQQQQP彂}}~|~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))))+*(kjjjjjkkjijhhkjjíQQQQQQQQQQQQQQQQQP悞}}~}~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))))+*(kjjjjjjjjjjiikjjQQQQQQQQQQQQQQQQQP悞~~~~~~}}~~憫悘右乙乙乙乙乙乙佑*)))))))))))))))))kjkjjjjjjjjiikjjQQQQQQQQQQQQQQQQQQ悞~~~~~~}}~~憫悘右乙乙乙乙乙乙佑*)))))))))))))))))jjjjjjjjjjjiikjjQQQQQQQQQQQQQQQQPQ憮~~~~~~}}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjjjjjj┅┆QQQQQQQQQQQQQQQQPQ憮~~~~~~}}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ憮~~~~~~~}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ憮~~~~~~~}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ悜~~~}~亅|}~彁悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ悘亐}~|~亶崘徲乙乙乙乙乙乙乙�)((())))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ悢帍悘彁彂弿拹悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQQP悡憫拺憪悡憮拺悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQPP彂憫拺憦悞悞憭悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ憫拸悘弿悜彂彁悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQQQ拻晵敁拹悙悞挀悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ憪搾拻憫憫拻憫悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ憪搾拻憫憫拻憪悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiijjjjjjjjjjj┅QQQQQQQQQQQQQQQQQQ憫拻拻憫憫憫憫悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiijjjjjjjjjjj┅葳圹[[ZZ\96775587眇耩铑痧钏松缮颂千ДΖイ櫂檟wwwupnlnnmloaeagecce洖灋灋灉瀾敃敁敀憠媷噰垔夀棖梞jmuuqmoonopodedeedbc湚湝湝湙洆搼拻拹悐唹墘垏壽杸LE\Z@A[pono^EEVWBFWddc渹MO儍OR�憰挀wNLysLMttMMsZv5mn54je9gKKk6no54df6eNM�2櫅66洔4唲償4搾46妷55墘6Zu6TR65NP6gffi7OO58MK6ffe�4ji88ii5剛唭7ef54_`66`_7\v9ok42gd5fZZj6ml56eg3eYX�6殯66洕9倐唴7拻73寛55垏8ZubDE][ACYfZYi^BC]aDHhcVX殌QP儍PQq匽^卲ILyrGKrrKKtYurolljgdcegiiklmorux|�儑殮湜洔灊潎剟剟剴憡墛垏噰塠wvtkliggeeghiklmorux|�儐崒悡櫇潧洃唫倐倰憡増垑妸圼xxwuysggeeghiklmorux|�儔妸帓挅湜洃拕剟剴憡墘増噰奩wwwxvuvvohfiiklmorux|�儑墡帎挃摍櫅敀拻拻拤垑宻KMtZwwvwwwwwnopjkkkmnru{|�倖墝帎挄棙櫄殭槚枖拪垐�6妷6[xwvwwwwwnopllllmmqwz}儑墝帎挄棛殮殭槚枙拰妶�5`_7[xwvwwwwwnopnnnnqegtxz�倗墝帎挄棛殮殭槚枙憪寢�8媶8[xwvwwwwwnopoooomfcecf�剣墝帎挄棛殮殭槚枙憭帉坥MKt\wyvvvvvwnpkoooonegbddddd噸悙摂敍洔洓櫁敀搾弶噧�|{[wvywwwwxonpoooonecfeeeed湝潣敁晿殰櫁棖枔攽寢垊倅xYtwwwwwwvlonnnnnlbedeeeec洔潩煘殩洔殮櫁敁搻寠噧�}yYY[\[[[[Z57666666镯耦铒蝠钍玢哔昭兔酣潔乻jZZZZZZZZY7����66瘃镳痧痧鹗仕邵匦似法洅倂hZZZZZZZZY7����66瘃镳痧痧鹗侍侍侍糖脯煇倂hZZZZZZZZY7����66瘃镳痧痧鹗仕趟掏搔Λ湋僾hZZZZZZZZY7����66瘃镳痧痧鹗仕适鞘失Еェ僾hZZZZZZZZY6��66瘃镳痧痧鹗仕墒噬骚ΖΖΕZZZZZZZY6��66瘃镳痧痧鹗适适适骚ΖΖΕZZZZZZZY6��66瘃镳痧痧鹗适适适骚ΖΖΕZZZZZZZX6��56瘃镳痧痧鹗适适适骚ΖΖΕZZZZZZZY5倎��56瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZ[58655766瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZX76887666瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZX56578666瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZY57666666瘃镳痧痧鹗适适适骚ΖΖΖΔウ痨痱%##!"#"$搻攽敂拺okqnnnnpn苓咻茌茌墜湠殰渋lhgijji噧剠剝儏{}}}{{}~z洏槞櫁槜cdbddcee▓墛拰寷渉ijjihhj�儎儎剟儃z|}~~}|}棖枙枟棛eddccddd柍窚柍硱iiif仺瓟挷瓡剠剗嵁瘣惎瘝棛棗3尝zИ{{}飾聮幜緢埨}潥h羐i牧剣纼ⅲ{縷}妹}~纒ut毬枠晾hd亮dd令柪í澜あ�}wv綌暳垄@剟唞翞澚翝澚tutr揩緭懤缿摼驓緯懨缷嚶倣寁纎k览厓績枖~纙|亮|縯stu罈椓耫f揪fd榴櫋斗殫背�崏s嚟�}~垟東彴皪嵃眳r湜r叚丁{|||駳枔憥崍剟~|xvqokjhgffffg{{{}||~|{rtssss棙ddefebbf駵洓彂妶們�~xvqokjhgffffdbglmz�{z|梥ssss棙ddbcccde駶潪湝檳厑}xvqokjhgffffgcjjlprr}|枖ssss棙ddedddcc駵洓灊櫄歭�}xvqojjhgffefeafmnqssw|�槚枛枟榙dcb~З|饻湝湝湝沯ijlttljihdiieedcfkmorsv{~亜嚁棔梔eeb羍e琉湝湝湝湜jijhjjhmgjgedfedcfkmorsvz~亝噹悞朿gee緬摼饻湝湝湝沯ijjiijj儍ghhfgdcfkmorsvz~亝垔崟敇梑e纃d溜湝湝湝湜jijgiigh倕剟乮fdcfkmorsvz~亜妺憭摋櫃棦|餃灇湝湝漟iiiiiij唵倓剟剠fgkoqsty{{倖垖帓棙枠櫄洓涱潫灉湝湚hkjhhhhh儎儍儍儌|}|}rouy{{�剣妽憱櫂槞殯湝頋潨湝湝済igjjjjh唲儏厖厓||y|z{}w}|儐妿挅櫂櫄洔洓镯镲镲痧�$#&####&憫悡摀搼pmoonoqpl軈挐试葩溴骅腱痧痧痧痧�!�~��"#憫拻拻拺nnnnnnnoo揶膺嗽噌沅桦眄痧痧痧痧�!�~��"#憫拻拻拺nnnnnnnoo揶咿葸拚哚邋桕祉痧痧痧痧�!�~��"#憫拻拻拺nnnnnnnoo揶揶咻捺徨珀眄痧痧痧痧�!�~��"#憫拻拻拺nnnnnnnoo揶咻葺噙腠眇痧痧痧痧"亐亖##憫拻拻拺nonnnnnnn葺掭揶咿痧痧痧痧�"亐亖##憫拻拻拺nonnnnnnn葺揶揶咿痧痧痧痧�"亐亖##憫拻拻拺nonnnnnnn葺揶揶咿痧痧痧痧�"亐亖##憫拻拻拺nonnnnnnn葺揶揶咿痧痧痧痧�!}倉##憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�"$!!""#憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�"$##""%#憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�#"$ $#!#憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�#""""""#憫拻拻拺nonnnnnnn葺揶揶咿LJJJLJINSQQSOPSPTN摃搹攼弿搹帒搾拻醒醒蜒乙乙颜砸延**((((((((()()(()*ikhijhikihijjlloЖ┊┆èKJKIKJMNPNTRLNOTQP摃憪拹悜拺憫悙悜兄友忠倚有矣已已*'&(*'')(**()(())&hkhfgkkikilljdknぉ┆ΚKG "!"!44422/./1301/.-/@A?@>AA@@A?>@CB?&'%''&'%&(&'(*#,:95577438?486578LK #"!! 03/12//2-12/00./@?@ABA?=??@>A>AA%&'%%(#'&&'&&'')674:945173235978MK  0.8/#"" !0.3/..//01//1..0A@AA?AA@A>A@?@@?)$&%&%%#$(%&%"'+62487654;0798676HH   1-80'&#".+,/,01102023422?>@>?AAAB@?A@@C>'%%'&%&(*'#%'(%&0824652974456697KL!!帓挀5689拸悡=:-..0///-14悜悡BBA@弿彁B>??BB@?拻憦彂晳&'%$$&&'%&彂棌#%8噿帊�453憦帊�86MM 悞 0崗69晽;?攷:.+11230.1彄21憫@@搻=>憪>@?@@BA悞悞拹彂($*))'%&*悜(#墢$挊74;殝7崗:28憦8QO $摀--//搾憯;<=?悞=<6帓7/.崙2000彅晵@=B?拹@>@敁@敀挀搾憮/51.--'(晹&%'(悤89897搼668884枓:RO%#挀+,12憫摀;:>;憫=<8悞5/0彂1/10拺悡@?@D摀A@B憭?悤憮搼拹2/10/2))敂&%%(帗:688;拺65792;拪>QP&&枒-悡-悞悜9敀A憪;<<86747悙3憪2挀憯?拹?拺=@C?AC悜憮拻拻搼彂0/2//2//悥)憭&憫96憪帞84/>帒崚=5TQ&%悜+憦0挀摀9搾>憫;:;;9585拻4憪3憫彅@拺B悜CB@>>@彂悙憫憫悜枑01201202搾&彂%拵0;;<7晭6857;4崠7SR(#挃.*0.搾憮89?@憰;>8;9865搼462.摀憮@A@A搹A@A?BC摀憮搼拸/3111001憯$'$)憦;9563崙686;87搹9RP$$拻--00拻悙:9?=憭<<:悘776拸2012拺悞???@攺?=<:<:85756搾拻1.0.悞帗:7::=DBA憫拻拻悜11-.0挄100-3敁彄+(4弿枎�674憫垚�<6TT%$&)*-006099;>@?=<=<:99857553211000111222365759@)*1./111//0-($%'6666665637645:76UT$$'*+-//76=;=9;><;;;:9986755332211122233344444@:(+2331110/0.)&'(665555567875434;PP!$%(,.3358:=@@>>:<::975655332211122233344435665500!"0//..///1/*&%&678778:766842467QP!"%+014997;?@>>8;;<:8675643221112223334443564:91/"$0/010..-,+)('&6666679558675328UT! !""#&!#448:=@A>9<;=<96755332211122233344445755603-.++''(&&&)00--//-)(%%5555566695876698TS" !$!!0049=?EA><:<:856442100///10111224441153721/-++'%*'$'+120011.+*%&6666666658779.74SR! !!"!"$68<;;<;967664321111122233344457927131-++'(#! "&&'('&%%##'%&98655565877悎@23RQ !"" ! "97<97766576532111/1012334444434416/60-++'''#!%&%&''%%%$'%&8756649688帓�:7:QQ ! !!  !!!/2842124566531000/0002334445443456/4.-+*'%! "#$$'&'##'%&876554:69晸挃;89QQ  ! !0043211235532/,-.////133444555447702.-+*&%! !""%%&##'%&766328469;9崘343QQ  !!103111001221110012//0233444555447702.-+*&%"!"##$$%%&666785=793;敀476QQ  ! !101000000000111/22//2212234555556612.-+)&&"! #$$$%&67654167798憱569QQ  ! !00000000000001/4?A:30/02332223446611.-+)&&"!"##$%'5665464/488帓956QQ  !!!0/00000000001125@B944223322233436611.-+)&&"! "###%(35578588;64帗533QQ  !!!//000/0000000024AE<=><85443346621.-+*&&#! "###$$('&%'"66<3=拹:>2QQ  ! "//0000000000//02?C<>?>:7266656621-,**%%#!!###$%'&&%%%713拡敃崑6QQ! !"1/0/0000100000/1@@>??CCB@?=A<;975833--++%%$"!##"$%%&&'&%$$$$""+797QQ# ! !4.0/3./0000000/0B??@@@@@@@@@@<782641/0/+'%$# !##"%%&&&&%%%$$#""(353RS"! ! .00/0000..00001->?@>>@@@@@@@@@>A'-%$('&#!##"&%&&%&%$####"!$(&!OR!!" !211.0./00000//1.AA@@@@@@@@@@AA@?'+$!'%(&"!##"%%%%%%$$$###!!"#"QR! $$#""!! 0///02100000112.@@>@?BBBAAAA@@=>""!##"%$$$$$$$####"!! PN!!!# 1/01-//01100//0-C?@C?@@@@@@@AABB!"!#$#&&&&%%%$$$$$#"  PRNOOQNPPPPPPPPPPS悜拵憮搾憫悜憫悢延闲延佑佑佑佑舷-+('+,++'(,+)****,/257:=FGNPUWZ]dfggffdb`_^][ZWUVVRQNPQPSNNOOPPQQQOQ憦拺拸彁悜憫憫悙有以有醒岩乙矣以)-)'&%&(%&&)&)))*,.247;=FFLNRUY^fhihfeda`_^]\ZWTVWRQQQQQQQQQQQQQQQPR悕剚亊~~}}~~憫悙有以友岩乙乙乙蚁&((+'))))))()((.'*ikhj>C?IPO]Y\^eghhgedca_]\[ZYWUTQQQQQQQQQQQQQQQQNR拺}}}}}~}}~~憫悙有矣友岩乙乙乙倚'((+()))))))))'$**lnjg@BELONSVZ_gijigecba^]\[ZYWUTQQQQQQQQQQQQQQQQPS摂}}~}~~}}~~憫悙友矣已乙乙乙乙已(())))))))))))***)klikmhjli[UW`afgkhigeca_]^[[YWUTQQQQQQQQQQQQQQQQPR憭��~~~}}~~憫悙友矣已乙乙乙乙乙)))))))))))))()+()ijjlldfigdVXadfgihgedc^`Z_XZYVUTQQQQQQQQQQQQQQQQOQ憪�}~~~~}}~~憫悙友乙乙乙乙乙乙右))))))))))))))())*ijkjkkhlikghiihhkjgfddc`^^ZZXVTTQQQQQQQQQQQQQQQQPR拺�}~~~~}}~~憫悘友乙乙乙乙乙乙佑*))))))))))))((**)ljkjkoiiedijkkhhkkhfedac]\ZYXVTTQQQQQQQQQQQQQQQQQR拺}~}~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))((**(mjljkmkjljljjkmj┃Θa^]]ZZYVTTQQQQQQQQQQQQQQQQQP彂}}~|~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))))+*(kjjjhikiighhjjkjЁb`]\ZZYVTTQQQQQQQQQQQQQQQQQP彂}}~|~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))))+*(kjjjiijihhhijjkjXVTTQQQQQQQQQQQQQQQQQP悞}}~}~~}}~~憫悘右乙乙乙乙乙乙佑*))))))))))))))+*(kjjjjjjkkjijikjjīXVTTQQQQQQQQQQQQQQQQQP悞~~~~~~}}~~憫悘右乙乙乙乙乙乙佑*)))))))))))))))))kjkjjjjkkjiiikjjíQQQQQQQQQQQQQQQQQQ悞~~~~~~}}~~憫悘右乙乙乙乙乙乙佑*)))))))))))))))))jjjjjjjjjjjiikjjQQQQQQQQQQQQQQQQPQ憮~~~~~~}}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjiikjjQQQQQQQQQQQQQQQQPQ憮~~~~~~}}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjiikjjQQQQQQQQQQQQQQQQPQ憮~~~~~~~}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ憮~~~~~~~}~~憫悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ悜~~~}~亅|}~彁悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ悘亐}~|~亶崘徲乙乙乙乙乙乙乙�)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ悢帍悘彁彂弿拹悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQQP悡憫拺憪悡憮拺悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPP彂憫拺憦悞悞憭悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ憫拸悘弿悜彃彁悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQQQ拻晵敁拹悜悞挀悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ憪搾拻憫憫拻憫悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ憪搾拻憫憫拻憪悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQQQ憫拻拻憫憫憫憫悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅葳圹[[ZZ\96775589眇耩铑痧钏松缮送嫂│ⅷЕ櫂檟wwwupnlnnmloafagecce洖灋灋灉瀾敃敁搾攳媼墢増夀棖梞jmtuqmoonopmegedcddc湚湝湝洑洆搼拻拸搤妶寙媻壽杸LE\Z@A[pono^EDVXCEVdec渹MO儍OR�憰挀wNR�LYGwR[MsZv5mn54je9gKKk6np53cg7eMM�2櫅66洔4唲剨9帟8噯ca妿^^Zu6TR65NP6gffi7OQ56LL8gde�4ji88ii5剛儌3cf4刞Ip僤Mu\v9ok42gd5fZZj6ml56eg4eYX�6殯66洕9倐倛0拸=亞a]唻^]ZubDE][ACYfZYi^BA]cEGfcXX殌QP儍PQq刔[刴GN}O_JxK_MtYurolljgdcegiiklnpsvy}�剓枩牋殱潏剟剟垘憡墕噳媿圼wvtkligfeeghiklnpsvy}亜亝垪湚洜洓憜倐倐拺妷噰墝媶[xxwuysggeeghiklnpsvy}亙剦媿摋殯洓憭剟剤帒妷媻垎噵Ywwwxvuwuohfiiklnpsvy}亙厛帊悢棖槞洈拻拻拻増寧俌`乑wwvwwwxvnopjkkkmosw{}�剣唹彂悢櫄櫄殭槚敁拤垗媣M`媅xwvwwwxvnopllllmnsw{}�儐妽寧摋棛殮殭槚枖拪垘厜[`媅xwvwwwxvnopnnnnlhksy|�剣墠彁挄枠殮殭槚枙拰妷噮a^塠xwvwwwxvnopooookfdceo~厗墠悞挀枠殮殭槚枙憪寢坱MJt\wyvvvvvwnpkooopmegbddddv悓實摌洓洓洓櫁敀搾弶噧儑奫wvywwwwxonpooopmecfeeeee洊搻摂暁湜殭槚晹攽寢垊�|zYtwwwwwwvlonnnnokbedeeeeg櫃湝殫枠殮殮櫁敁搻寠噧|{YY[\[[[[Z57666666痫篑耩痤眄赍哔昭兔酣潔乲kZZZZZZZZY7����66痱镳蝮蝠鹗书咿匾兔憨檼則fZZZZZZZZY7����66瘃痫祛麴鹗嗜孟仔似法殢噒fZZZZZZZZY7����66 痼盹蝣鲳鹗侍缮商糖腑乼fZZZZZZZZY7����66铖镲铕箴鹗适噬侍师�tfZZZZZZZZY6��66锺痧镲痧鹗侍适人骚ЕうhZZZZZZZZY6��66瘃镳痧痧鹗侍缮松骚ΖウΕZZZZZZZY6��66瘃镳痧痧鹗仕适适骚ΖΖΕZZZZZZZX6��56瘃镳痧痧鹗仕适适骚ΖΖΕZZZZZZZY5倎��56瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZ[58655766瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZX76887666瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZX56578666瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZY57666666瘃镳痧痧鹗仕适适骚ΖΖΖΔウ痨痼#%" $!#"敀晲挃攽okqnnnnpn苓咻茌哚 墜湠殰沰jihglig噮厔們唲{}}}{{}~z洏槞櫁棓ciadgeee▓墛拰寷沯gkkgjgi�剠們剠儃z|}~~}|}棖枙枟敄jfihefed柍窚柍磶khhh┉敀箔晞厔}嵁瘣惎瘝棛棗3稙獄﹠飾聮幜緢壘湙j縣i牧剣纼ⅲ{縷}妹}|聎ruz緭椉bb悞ie搹顤括饯×}~xt繐柫痢ち剝唞翞澚翝毰usst砍布c暕xe彧{驓緯懨缷喣�帊t耼m谰剟羶敂~纙|亮|z莙soq臇樇fb憢ch悙駲《窔棻磾�寛u叜�{�墥東彴皪嵃珡m潥n叢盯⿸﹝〝駳枔憥崍厒~vvsnkihkedjfw亅~vx倅x~rtsrt棙ddgegb]b駵洓彂妵剛�wvrnkhijeeiea_iwx~{{{時qoqv棙dd_gfabg駶潪湝檳剛|yvppngfgfhgdcahjotxz亅敂srsv棙dd_hbihb駵洓灊櫄檔�{zvoolghfefeeecgjltxxv|憵殫槣棙dda`bk饻湝湝湝歭ihntrkghigeccddfjkmrtp}y厏崚槙棙ddg`~e饻湝湝湝歬iiijihhjbdfbdbbehikqttwz}亝厧敃梔ebfh敀e饻湝湝湝渋ikiijir俷gjeh``cgkmprswxz剢墡挅cgfen憮g餃湝湝湝渉ileikfh�剝mkdfefikmsqyw亇墣審摂槜歡zエ{餃灇湝湝漟iiiiiij唵倓剟刼blikttuyz亐厛寧挆槚槞殯cc顫煘湝湝歨kjhhhhh儎儍儍儎亅ooorvy|倓噴崙枡槝櫄洑氻潩湝湝湝gigjjjjh唲儏厖厓~|w|{vpry�儎唺帓枡槞殯湞濓盹镲镳痫$#&####&憫悡摀摂oilpolilpx~挐试葩溴骈祉痧痧痧痧�!�~��"#憫拻拻拹klnpnmmln揶帳擦试葩滏玳祉痧痧痧痧�!�~��"#憫拻拻拻onnlknqoo揶哙俟嗽噌沐骊祉痧痧痧痧�!�~��"#憫拻拻拹ppnmmnooo揶阝廪苷哚沌珀眄痧痧痧痧�!�~��"#憫拻拻拸nonnppooo揶苓籴捺沌轫眇痧痧痧痧"亐亖##憫拻拻拹nonnoonnn葺圻葸噙眄痧痧痧痧�"亐亖##憫拻拻拺nonnnnnnn葺谵捺咿痧痧痧痧�"亐亖##憫拻拻拺nonnnnnnn葺谶捱咿痧痧痧痧�"亐亖##憫拻拻拺nonnnnnnn葺谶捱咿痧痧痧痧�!}倉##憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�"$!!""#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�"$##""%#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�#"$ $#"#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�#"""""!#憫拻拻拺nonnnnnnn葺谶捱咿LJJJLJINQOOPLMPMTN摃搹攼弿搹帒搾拻醒醒蜒乙乙颜砸延**((((((((()()(()*ikhijhikihijkijlěЕえⅸōKJKIKJMOPOTPIIIMQP摃憪拹悜拺憫悙悜兄友钟研有矣已已*'&(*'')(**()(())&hkhfgkkikillklklè哀えKG "44422/./1301/.-/@A?@>AA@@A?>@CB?&'%''&'%&(&'&&&$:5751137:8303559LK 03/12//2-12/0///@?@ABA?=??@>A>AA%&'%%(#'&&'&&(%&5869821;=956:MK   !0*"%!&#!0.3/..//01//1..0A@AA?AA@A>A@?@@?)$&%&%%#$(%&'''(77669>6+2CC64766HH  !$"0+&)"'$.+,/,01102023332?>@>?AAAB@?A@@C>'%%'&%&(*'#%&$%(566;BA86=B9.0;<4KM!!帓憫3456帇悡=:0..////-14悜悡BBA@弿彁B>??BB@?拻憦彂晳&'%$$&&'%&彂搾(&87拻8&S儠棝垖b/NN!悞 9晸64寠,?攷:4021240.1彄21憫@@搻=>憪>@>@@BA悞悞拹彂($*))'%&*悜()悡&5挄5?D+G墜O<5�廚PN #摀--//搾憯;<=?悞775帓6/.崙2000彅晵@=B?拹@>@敁@敀挀搾憮/51.--'(晹&%-%嫢墦@;+=7'==<+:搣.RN%#挀+,12憫摀;:>;憫:<8悞5/0彂1/10拺悡@?@D摀A@B憭?悤憮搼拹2/10/2))敂&%&搸亾15?;9>4;>9>垖DQP&&枒-悡-悞悜9敀A憪;<<86747悙3憪2挀憯?拹?拺=@C?AC悜憮拻拻搼彂0/2//2//悥)憶暉挅~攼�=:;-:6巣>0TQ&%悜+憦0挀摀9搾>憫;:;;9585拻4憪3憫彅@拺B悜CB@>>@彂悙憫憫悜枑01201202搾&彄*棄悕7PS悗B2;E寠K45SR(#挃.*0.搾憮89?@憰;>8::865搼462.摀憮@A@A搹A@A?BC摀憮搼拸/3111001憯$'%"創崢8$>�A;1寔@A6BRP$$拻--00拻悙:9?=憭<<:悘876拸2012拺悞???@攺?><:;:85756搾拻1.0.悞帗:7:9<988857553211000111222366855@ )+0./111//0+&$%'6676553543664696TS$$'*+.23:8>;<9;@=<;;98986755332211122233344444F>(+1331110/0-(&'(6654467875544647PP!$%+2697677:<=;<8;9:98565533221112223334443771% !"0//..///1-)&%&6788976686666856QP!")3;::<9589;:;6:;<:867564322111222333444365,&"$0/010..-+)('%&6667855868788876UT! !"%+1**98:;1@QQ  ! !10100000000011/-00--0012234555556612.-+)&&"! #$$$%&676313D/6N�嘍@9:QQ  ! !0000000000000/-0;=6/,,/2332223446611.-+)&&"!"##$%'5665.EA70倗C;8$-QQ  !!!0/01/000000010.0;=4//.13322233436611.-+)&&"! "###%(3558=@4<墝98@5AAQQ  !! //01/00000000/,-:>77;9;><85443346611.,,*&&#! "###%$('&'.9+8弿8CC晙FQQ  !! ///2.0000000/.+,9=88;;>@>;8677655500,++*%%#!!###%%'&&&*1F9啑崑摛孌QQ! !!0./3-10000000.-/>>:;=@AA@><=;:8513//,,,+%%$"!###%%&&'&'($,$#"(078;QQ# ! !!0./3,00000000//0B?=>?@@@@@@@@;86.0/--0/+'%$# !##$%&&&&&%%%$#""&,343RS"! !!../4+1000.00010->?@>>@@@@@@@@@:E%/3,+(&$('&#!##$%&&&&%%$###"#$%%$!OR!!" !!0//4*/000000/00.AA@@@@@@@@@@AA;E'691-'#!'%(&"!##$%%%%%%$$$##"!"""!QR! $$#""!! ! .-.4+2200000121.@@>@?BBBAAAA@@<>""!##$$$$$$$$$###""! PN!!!# ! /..5*/001100/0/-C?@C?@@@@@@@AAAA!"!#$%&&&&%%%$$$$$"!  PRNOOQNPPPPPPPPPPV彂晪摂拺憪憫悙斞酉醒佑佑佑佑油�574/-+*+'(,+)*)**,/257:=FGNPUW\aegggfeca`^]\ZXVVVVRQNPQPSNNOOPPQQQPU~帒棇悜悙憫憫悙愑幸杂行蜒乙乙友�)-)'%$&(&'')')&**..247;=FFLNRV[bgihgfdba_^^][XVUVWRQQQQQQQQQQQQQQQSS}~厏}�~~�~}亜悙有以友岩乙乙乙蚁&((+')))(('(($$(,0j\F<I6瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZSC97229>6瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZS<42-/686瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZV57666776瘃镳痧痧鹗仕适适骚ΖΖΖΔウ痨痼#%" $!#"敀晲挃攽okqnnnnpn苓咻茌茌 +  +墜湠殰沰jihglig噮厔們唲{}}}{{}~z洏槞櫁槜cdai_dca▓墛拰寷沯gkkgjgi�剠們剠儃z|}~~}|}棖枙枟棛ede^iefh柍窚柍磶khhh┉敀箔晞厔}嵁瘣惎瘝棛棗3尝zd礂飾聮幜緢壘湙j縣i牧剣纼ⅲ{縷}妹}|聎ruz緭櫬籯kufi垝顤括饯×}~xt繐柫痢ち剝唞翞澚翝毰usst砍艓or璵驓緯懨缷喣�帊t耼m谰剟羶敂~纙|亮|z莙soq臇捑跾櫁`総f駲《窔棻磾�寛u叜�{�剴東彴皪嵃珡m潥n叢瘻爳�X痷j駳枔憥崍厒~vvsrvtnnhjztx亅~vx|x~rtsrt棙dd`qWgbf駵洓彂妵剛�wvrpolkkfgmic_iwx~{{{時qoqv棙dd`h^dfe駶潪湝檴儌|yvpojdegfgdaaahjotxz亅敂srsv棙ddf_ibac駵洓灊櫄檔�{zvmkheijiga`bcgjltxww|憵殫槣棙ddhg灋﹟饻湝湝湝歭ihntriegmomgbacfjkmrttyy厏崚槙棙ddeiti湀饻湝湝湝歬iiijihhkeikeebbehikqttwz}亝厧敃梔efj^l饻湝湝湝渋ikiijiq�jadaf`_cgkmpstuxz剢墡挅cgjjn_餃湝湝湝渉ileikfe亀vvbeceefhkpstwy|}啇垙挃槜lg玻餃灇湝湝ibfdbrj剛亗剟�rblikqtsuz}y厛唽帇懅Д焛ka顫煘湝湝nike`oh儎儍儍剝亅ooortuz垍妰妽憲殯殰洑頋潨湝湝pkmgbrh唲儏厖厓~|w|{vu{}亃寢敀挀潩崘灍灊镯镲镲痧譑&.&憫悡摀摂oilpoli\�x憫寥僮玳忪骅眇痧痧痧瘥��噲妱u#憫拻拻拹klnpnmmot诟袜茑鲴尻眄痧痧痧痧�z|{�倆#憫拻拻拻onnlknqWz圳滢澜涛拶茜嚅眄痧痧痧痧鷢~�|�倈#憫拻拻拹ppnmmnort兆冂捃茔屋蜷殒轫痧痧痧痧魟亞厔剕#憫拻拻拸nonnopoul忤葸遴坂 绘眄痧痧痧痧韸厡剢�#憫拻拻拹nonnoonnl廨圻葸葸腠眇痧痧痧痃唝�唥儉#憫拻拻拺nonnnnnnn葺谵捺咿痧痧痧痧雬{儊z儌#憫拻拻拺nonnnnnnn葺谶捱咿痧痧痧痧魖寗�垊#憫拻拻拺nonnnnnnn葺谶捱咿痧痧痧痧鬴w寔��s#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�9%(&6#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�$* !!#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�/(,#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�#"""" #憫拻拻拺nonnnnnnn葺谶捱咿TQPNNJHNTTTUQRURTN摃搹攼弿搹帒搾拻醒醒蜒乙乙颜砸延**((((((((()()(()*ikhiijhikihfbe^m耿毊┅SQQMMJNPQQXTMMMQQP摃憪拹悜拺憫悙悜兄友钟研有矣已已*'&(*'')(**()(())&hkhffgkkikikmnee┅┅SN%$ %" 44422/./1301/.-/@A?@>AA@@A?>@CB?&'%'''&'%&(%%*3*4089757468976578TR" ! 03/12//2-12/0///@?@ABA?=??@>A>AA%&'%%%(#'&')**2,120G685767635978UR&""/)!$ $$!0.3/..//01//1..0A@AA?AA@A>A@?@@?)$&%%&%%#$(*-')3=0<;67774788676PO&" !-(#&$$.+,/,01102023332?>@>?AAAB@?A@@C>'%%''&%&(*'# ./5>-6976796755697ST'"!!崘崓/012妵悡=:0..////-14悜悡BBA@弿彁B>??BB@?拻憦彂晳&'%$$$&&'%&彆J憪>@>@@BA悞悞拹彂))+**)-&+*悜z!5&<湙77悞58崕78憦9VS$%拹)(//搾憯;<=?悞765帓6/.崙2000彅晵@=B?拹@>@敁@敀挀搾憮.0002-2*1彋槕8--妵'776憮搼6759悜WR($憪''12憫摀;:>;憫:<8悞5/0彂1/10拺悡@?@D摀A@B憭?悤憮搼拹2/169/,//1*償$&晵9278彄搹87:6憦VT)'晭)嫇-悞悜9敀A憪;<<86747悙3憪2挀憯?拹?拺=@C?AC悜憮拻拻搼彂0/2/%==.,) 寵/=棎I厭7憦彂7拺8摃YU)&弾'審0挀摀9搾>憫;:;;9585拻4憪3憫彅@拺B悜CB@>>@彂悙憫憫悜枑012)%5>/)20崢0./寲>剱7拻拻7悜8摀XV+$憫*%0.搾憮89?@憰;>8::865搼462.摀憮@A@A搹A@A?BC摀憮搼拸/31,(/80+68敧(. 晬8A64拺憭4656悞WT'%憦)(00拻悙:9?=憭<<:悘876拸2012拺悞???@攺?><:;:85756搾拻1.0.悞帗:7<;>DBA憫拻拻悜11--0拞5272啔寱}�.;M厵拻7447拻憫85WV(&),-14480634;BEB?><988857553211000234789;<<>=D@ )+0./4551/0+&$%+6676553543655696WV'&*-.00086=:<9;@=<;;989867553322111345789;;;;;G@(+0331130/0,)&'*6654467875544647SS""$'(,-0567;=?>=;<8;9:9856553322111345789:::9=<;!"0//..///1-)&%&6788876686666856TS"!"$%+29:;?=:<;;:;6:;<:8675643221112345678887;;4 "$0/010..-+)('%&6667755868788876XW$##$%*180/<::;)9帒544.櫃4QQ  !! //00000000000.-.:>77;9;><85443346631.,+*&&#! " ""%%$'%&8763.047亣-5:悤2QQ  !! ///2.0000000/-,-:=88;<=?=:7765445732-)))%%!! ""$$$'&'4433;+1:T}妸倖C0QQ! !!0//3-10000000.-.=>:;=>??=<::95101743-(&)'$!"#$$$*))*1)/6689759:7QQ# ! !!0//3,00000000///B?=>??>======6//-542/,(()%""!&+/25767<=?@>>?>=======1?$280.(&'-*#!##""!! !"##$%(+/241OR!!" !!0//4*/000000/00.AA@@??>>====>>5@%6;41-..2,)" !#%%$#""!!!"#$&''*+-./-QR! $$#""!! ! .-.4+2200000121.@@>@?A@?>>>>==8:!*)&"'" #"$$&(((''''''''&&&&&&'&%$PN!!!# ! /..5*/001100/0/-C?@C??>=====>>@> &&!#--# ""%'()**+,,,*&#  PRNOOQNPPPPPPPPPPV彂晪摂拺憪憫悙斞酉醒已行行行形�00/04540*1@EA9.*)**-06?DLKPQUWY\^`bcdedb`^\[YXVUTTRQNPQPSNNOOPPQQQPU~帒棇悜悙憫憫悙愑幸杂贤挝舷舷杏�#%#',,($#-9OOM')))2646;?FHOPWY[^bdgijkid`\XUUTUTVWRQQQQQQQQQQQQQQQSS}~厏}�~~�~}亜悙有以友岩乙乙乙蚁&((+')&%%)-((%$('"<44@BEFPTSZ\_dgihgedc`][YXWVVVUTQQQQQQQQQQQQQQQQST�們yz~~�~}亜悙友矣已乙乙乙乙已(())))))))))++-.0)c^\b=?EOTRSX]bfiihffec`^][[YXVUTQQQQQQQQQQQQQQQQSS亜||~~�~}亜悙友矣已乙乙乙乙乙))))))))))))**,,)%cdgnIGNUZYTX]bfhigfedba_^]\[YVTTQQQQQQQQQQQQQQQQSR~�儂z~~�~}亜悙友乙乙乙乙乙乙右)))))))))))))+-,&&inspgaaffidfhklkifca`_^]\[[[XUTTQQQQQQQQQQQQQQQQSR亜zz~~�~}亜悘友乙乙乙乙乙乙佑*)))))))))))),/-*,uyztmlghgghhilllifcaa`__^^]\XUTTQQQQQQQQQQQQQQQQSR�儂z~~�~}亜悘右乙乙乙乙乙乙佑*))))))))))))'#!mnldaebbaadcehjihecaa````_^\YVTTQQQQQQQQQQQQQQQQSR}倆z~~�~}亜悘右乙乙乙乙乙乙佑*))))))))))))(&$"&qpkcbfffhgjjjkkiea^\\\\\[[ZYWUTTQQQQQQQQQQQQQQQQSR}倆z~~�~}亜悘右乙乙乙乙乙乙佑*)))))))))))))()()nlieegiijikjjjlj┅[[XVUUVUTTQQQQQQQQQQQQQQQQSR~�儂z~~�~}亜悘右乙乙乙乙乙乙佑*))))))))))))))+*)kjiiiijjjiihijkjīΘ[\XVUUUTTTQQQQQQQQQQQQQQQQSR~�儂z~~�~}亜悘右乙乙乙乙乙乙佑*)))))))))))))))))kjjjjjjkkjiiikjjíXVTTQQQQQQQQQQQQQQQQTS~�儂z~~�~}亜悘右乙乙乙乙乙乙佑*)))))))))))))))))jjkjjjjjjjjiikjjXVTTQQQQQQQQQQQQQQQQSR亜zz~~�~}亜悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjiikjjQQQQQQQQQQQQQQQQSR�亜zz~~�~}亜悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiijjjjjjiikjjQQQQQQQQQQQQQQQQRQ亜剒z~~��~}儎悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ倕剏{~~~}}剣悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQQP剤儁~~}}唽悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPP厞剓�~}}~倗寪徲乙乙乙乙乙乙乙�)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPP啈帄憪悘悙悙憪悘右乙乙乙乙乙乙乙)((())))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQOO噾悓搾拹憭拻拹悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQON啇弻敀拹悜憫拹悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQOO垜悑拹悘悜悙憪悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPP嫆憦晹搼悜憫憪悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPP寪憦摀拺憫拻憪悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ崘拹搾憫憫拻憪悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅QQQQQQQQQQQQQQQQPQ帒拻拻憫憫憫憪悘右乙乙乙乙乙乙佑*)))))))))))))***)jjkiiijjjjjjjjjj┅[vZh\dQM\96775589眇耩铑痧钏怂缮侍千ДΖイ暃帉rfhupnlnnmolafagecce洖灋灋潩瀾敃晸搾憠妶噲墘圿剰獣xlruqmoonopmegedcddc湚湝湝洑洆搾憭憫悐噲墘垏塢憘XDV`LA[pono^EDVXCEVdec渹MO儍OR�憰摂塧LysLMttMMsa�3帉>:{e9gKKk6np53cg7eMM�2櫅66洔4唲q僺K[咢剦55墘6Rz/VQ32LP6gffi7OQ56LL8gde�4ji88ii5剛�拏Y]~6^`66`_7\i@vp.-nd5fZZj6ml56eg4eYX�6殯66洕9倐�拏Y\�9泩55垏8\gq8Bc[6CYfZYi^BA]cEGfhXX渶QP儍PQq刔x厃KQ俿HKrrKKt[urolljgdcegiikgdemsvwpu{敎牋湜潏剗亊嫃墛墘垏噰塠wvtkligfeeghikjjlqux{}~亝垪湚洖潧憜倐厛寧妷垑妸妶[xxwuysieeeghimopqtvy~剢唹媿摋殯洓憭剟剫彂妷増噰噴Ywwwxvuwuohfiimprssru}唸垐帊悢槜棙洈拻拻拻増妡`QMtZwwvwwwxvnopjkkmnooosy�唹唹彂悢櫄櫄殭槚敀拤垏垥昖m[xwvwwwxvnopllmmllprvz倖妽寧摌槝櫄殭槚敁拤垝s僤E�[xwvwwwxvnopnnnnmjoy�倕噳崗悞晼槡殮櫂枖搾増妰妭^d[xwvwwwxvnopoooonlortz剣噳崘拻摉槡殮櫂枖搾増厱RaLx\wyvvvvyzrnmmrvrmegbddddv悓實摌櫃櫂槝枔憪弻媺噯厙奫wvywwwyxqljjmqpmecfeeeee洊搻摂棝灋潨洐槞櫀拵妵儈zYtwwwwwwvqjfgimqmbedeeeeg櫃湝殫櫈¥!煖殭棏妭ztty{YY[\[[[\XL90339G6痫篑耧扉甾葆茇讶鹿槓宯jZZZZZZZZ^hv亞唥o6痱镳蝮蝤蓐忖巯萍攱卨aZZZZZZZZcr}儕垁z6瘃痧祛趔笸椭姓酝萍疇搱paZZZZZZZZbt}�垍~~6 痼眇蝣鲲锶壬剖趟萍阿晪唈aZZZZZZZY^s{|�y~6铖镳镳箴鹗仕墒怂乒檺媕aZZZZZZZY\s~~儅y�6锺痧铒痧鹚怂噬耸骗И拝wpgZZZZZZZY]t�亝�{�6瘃镳痧痧鹗侍噬噬骚Κ隘痸hZZZZZZZX_r亝噧~}6瘃镳痧痧鹗仕适适骚ΕěΖZZZZZZY_m噲�v6瘃镳痧痧鹗仕适适骚ΒⅱⅲZZZZZZY]e{垏剗l6瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZXNA:44>I6瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZTC97229>6瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZT<42-/686瘃镳痧痧鹗仕适适骚ΖΖΖZZZZZZZU57666776瘃镳痧痧鹗仕适适骚ΖΖΖ﹀茈蒿纟#%" $!#"敀晲挃攽okqnnnnpn苓圻苻茌蠘拹嫋沰jihglig噮厔們唲{}}}{{}~z洏枡櫂槜cdbdeddd锜崒彉灃沯gkkgjgi�剠們剠儃z|}~~}|}棖晼晽棛eddccddd袥牶础4磶khhh┉敀箔晞厔}嵁瘣惎瘝棛槚洭尝zИ{{}閹習娎艑壘湙j縣i牧剣纼ⅲ{縷}妹}|聎r俰椆礆糽d亮dd灵捔啪牎羮~xt繐柫痢ち剝唞翞澚翝毰usrqr敼厬览憮诀熈枒慷喣�帊t耼m谰剟羶敂~纙|亮|z莙s}un「浬Zf揪fd硫煪垢殰麓攢寛u叜�{�剴東彴皪嵃珡m潧t尃稖偁瑋||餁搻帇妴剛~vvsrqpkmim~y{�倎y{亐{乽wvuw棜dd`qWgbf顧槝寧噮儌�wvrokhhjgjqmgblz{亗~~~榰trty棙dd`h^dfe顨殯櫃枅倐|yvpmg`bfgjhfddkmrw{}�棗vuvy棙ddf_ibac顧槝洑枟檔�{zvmidafijjeeefjmow{yz敐潥洘棙ddhg灋﹟頇櫃櫃櫃歭ihntrgacjnnjfffimnpuxyz{垇悤洏棙ddgfZY檵頇櫃櫃櫃歬iiijifegbhlhiffhklntwwz}�剤垜棗榙d\{k姫w顧櫃櫃櫃渋ikiijhm~g`edjdcfjnpsvwy{}倗墝憲榙ddkdl憮頇櫃櫃櫃渉ileikf`�vuwepmhhgjlruvzz倠搵挆榙diZ湇�顪灇湝湝ibfdbrj亐亗剗yo]jgkqty{y�倛摃憯枔崈wljic頋煘湝湝nike`oh亜儍儊{xtjnrx|{x亄{�摃殲。殫ji頋潨湝湝pkmgbrh唲儏厖厔|uxvpr|噽弳剱憦憳煟あ煘涳盹镲镳鹱K&.&憫悡摀摓wmlke_Zhr姃師┖召掴溷噌牝痧痧痧痧麁�噲妱u#憫拻拻拵ijkmkjjoc悎嫧笨佘噔膺谳珥痧痧痧痧�z|{�倆#憫拻拻拺mlligjmdx呙煙吧苓溟腙珑腠痧痧痧痧鷢~�|�倈#憫拻拻拻qplihhhmj奏唛芡献葩邃忏珥痧痧痧痧魟亞厔剕#憫拻拻拠gikmpssog苕垆孥卩骈赙滗觏痧痧痧痧韸厡剢�#憫拻拻拫iklnqrrpj後圻噌哚腠眄眇痧痧痧痃唝�唥儉#憫拻拻拺nonnnnnnm咻谵捺咿眄痧痧痧痧雬{儊z儌#憫拻拻拺nonnnnnnn葺谶捱咿痧痧痧痧魖寗�垊#憫拻拻拺nonnnnnnn葺谶捱咿痧痧痧痧鬴w寔��s#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�9%(&6#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�$* !!#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�/(,#憫拻拻拺nnnnnnnnn葺谶捱咿痧痧痧痧�#"""" #憫拻拻拺nonnnnnnn葺谶捱咿QRNQTPQQQRRRSRQPPQ拺憭悞憪搼憭搻憫幸蜒乙已杂矣右延**((((((((()()(()*ikhhijjjlgkijlkkЛ┅SRRPSRQPOQORRQPQNQ寧憪悞拺拻帎憫悜言友匝蜒已矣乙已*'&(*'')(**()(())&hkhhhiikjjkkjhhj┇┇┇ī┆SP  !##/0/0///02122////?B???AA>@??=@AB?&'%''&)&'&'%%''&7486687965756777RQ  !# 130.1302-010/0.0B?AAA@@@??@@B>AA%&'&'(&)')%$&'"(5665669554566857[Y   ! /0101110120110/0A>@@?@AA@>AB@?@?)$&$#&&&&%$$%&&%6746877657555687ZX" !!$ !!!204.21020/001333@AA>???>A>?@A?C>'%%&%'('&'&&&%'$4441485566666488YZ!!彁帗34 !帓悡/1100/000..2悜彃A@AB憮憯DA@@BC@?拻憦彂晳&'%%%((%"%%憥()&8弿搾�87<憫拵�97\[帎 挃6#挀 !拺20.01220/3帓..弿A@搼=>彂?ABAABA悞悞拹彂%$'&%&%%$'悗�'')弿:77悡8帒758憥5\Z 搻挀拺?=;A悞301搼/0/悙002.憫挃A?CA拺A>A彄@敀挀搾拻00000000%彅憮'''89755摀779767搾4YX"憫" 悜憫>拻10/帒-00憫0.21挃搾C@AA搼?=?拻?悤憮搼悙0-.110/.$((搼$(#875:6敁4:9628憫6YZ&&晭+拺1搼摂?悙@拸;9;91212憫.彄1憪悡A拸@悞?BBAAC悜憮拻拻搼搻.-1//2.132%拻%%&97彄拺:857悙彂66ZZ%$悡.憪1搼拻<憪@敁=;99011.挅0悜1挃憫A憪C拻?>B>>@彂悙憫憫悜拺30000011.1%挀&&'65476彃775987搻6Z[)&憪.,1/敀摀=@>>搻89:::955憯1000拺敁?AAA憭@B>DBC摀憮搼憮.042//-2012拻')&47798挀756586搻7[Z'%憭/.03悜搻==>=憦799彁767悞3.0/憫拺@?@@搾C@A彄A憭拺憭拹1.011.0.201悜&'%57556敀858665攽6WY'&,拸-3彅99憯??拺<=;:悜7664拹21搼3?拹>A憮CBA?悞A憮搾挀憫72/.搻123/12悡(&&彃767拻7彁488拹5\Z'%*,彂搾76:9挀摀<=<:79974645晵拺31C@憭憰?A@@@AB@憫拻拻拺7201-憭0310悜拹憫&6悘憪�867憮憫�86[Z'&*)--027586<<<=<<;:78774644332001233223=?>>=ABB@122220.101//&&&)8777637857765575[Y&&++,*005467=????><;:8785534221//0122110544344A?'())-100.//0'&%(7644477576467775[Y'&**-/2257:;?????><;98885533221//0122111435565A>'(++/2000211('%'7755564655875678RQ "#*-2134::>==>>>=<;9896644332001233332425555533322$$'(,/-//100'&$&7767975657556785QR "!(,0232<:===>>>=;:999664533200123333221445433351/$$&&-0/0/111))%%5666665543668978QR "#$" !"78=>>>>=<:98776533221//0122210125456663523++('" %%&''&$('(&$#%$%466676458767弿97OP " " !!!88=>>>>=<;:977654434310123332233545567350/,*)($"&&&%&%$'%%$%!'&%56657595769嫊�84OP "!!!!!!!!!!! ";;;;777665543321/101322233545557450.,*)(%##&'&&'''&&&&!'&%5666767665拻搼34OQ "!!!!!!!!!!!"#;;;;787766543202120/332233455457450/,*)(%% #&'%%&&&&&'%$&&%576688457悜8挀77OQ !!!!!!!!!!!!!3222/2666532210102333223334554464500++''$$ &&&&%%%##&&&57655675搻97拻97PQ !!!! 200112345543310111112332334554464500++'&##&&&&&%%$$%&&67667667彂悙搻�5PQ !!!! ! 0/////000011111111012322334554464500++('#$ !"#$$%&&6865836:9766拻97PQ !! "!//0000000111222033122222334554464500++)($%! !"$$$%&&686566568856敁56PQ !! ! ./001/////000001<;1/2322334554465500,+)'#%"! !"#$$&&686555637483憪67PQ !//10111111111102@@312122334554455400,+('"%!! !"#$$&'68654697567憪拺5PQ! !!! !0/0/1112221111/2A@A@AAA=535655445420,+((!%!! !#$$'&%&&(%%4766865686OQ"!   40/03/./////00.0B>=?B>>;536765335432,-))#%  #$$(&&&%&$%1556869477QQ!" " !0.1/1////000001/@?@>ABCB>=@A@?534201-,*'## "#$$%##$$&$!%$#""!3776PP!  !! 010.122111000010BA@?@@@@??ABA@8646/0/,**%# !#$$'%%%%&&$#####$3945OQ !##"! ! 100000000011111.@@@?@AABBAABB@BB--)&$%! "$%%(&%%$$$$"!"###""!OM$"""!!!! 1/11/1111100000,A>BA>==>???@A?A?.*('&$#!##$$(&%%$$$%"#"#"#"!QUOPQROTTSRQQPPPOT帍弾悞拻拻拻拺悤弦盐幸右右幸已已*)'&*'+,&*PSDD:6++11::?BKLRSXY_bihhgdcbb__[[YYWXQUQRPPTRQPPPPQQQQQPQ搻晵搼憫憫憫憫憭蚁右右蜒右岩杂延*)+*)***)(RPDB86,+31<:@BKLSTYZ_ciihgedbb`a\\YXXVTWQQQQQQQQQQQQQQQQQN剘~~�亖�~~~~憭蚁佑右乙乙乙乙延*)+**********)*-)+21;=BCJJOSX]`djjihedbb`a\\YWVUTSQQQQQQQQQQQQQQQQOO亖�~~~}}}}}}憫倚佑右乙乙乙乙岩*)*************),)30::@BJJQPXYaekkjhecbb`a\\YWVUTSQQQQQQQQQQQQQQQQQQ�~�}}}}~~~~~憫蜒佑右乙乙乙乙岩*)**)))))))))(('*,ijjjCFKKSQ\\aejkjifdcb``[\YWVUTSQQQQQQQQQQQQQQQQQQ~~~�||}}}}}~~憫岩佑右乙乙乙乙岩*)*))))))))))**)+)hgjkDEIKSSZY`dijiifdcb``[\YWVUTSQQQQQQQQQQQQQQQQPO}|~~�}}}}}~~~~憫岩右已乙乙乙乙蜒*)*))))))))))))))*hkhjjhiiif^Zachiihfdcb``[\YWVUTSQQQQQQQQQQQQQQQQPO~|�}~~~~~~~~憪延右已乙乙乙乙蜒*))))))))))))**)))fijkkiijgg]Zceiihhedcb``[\YWVUTSQQQQQQQQQQQQQQQQPP�}~}~~~~~~~~憪延右已乙乙乙乙蜒*))))))))))))))))(jiiiiiijjljihhjihgedbb``[\YWVUTSQQQQQQQQQQQQQQQQPP}}}}~~~~~~~~憪延右已乙乙乙乙蜒)))))))))))))(('(*ghlkjjjjjgjiijkihgdccb``[\YWVUTTQQQQQQQQQQQQQQQQPP}}}~~~~~~~~~憪延右已乙乙乙乙蜒)))))))))))))(('(*ghlkjjjjjjjjjjkj┅a]]\ZXWUUTQQQQQQQQQQQQQQQQQP~~}~~~~~~~~~憪延右已乙乙乙乙蜒)))))))))))))((((*hilkjjjjjjjjjjjj┅┅a]\]X\VUUTQQQQQQQQQQQQQQQQQQ~~~~~~~~~~~~~~拹岩乙乙乙乙乙乙蜒))))))))))))))(((*iikkjjjjjjjjjjjj┅┅UUUTQQQQQQQQQQQQQQQQQQ~~~~~~~~~~~~~~拹岩乙乙乙乙乙乙蜒))))))))))))))(((*iikkjjjjjjjjjjjj┅UUUTQQQQQQQQQQQQQQQQQQ~~~~~~~~~~~~拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅ī┅QQQQQQQQQQQQQQQQQQ~~~~~~~~~~~~拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅┄QQQQQQQQQQQQQQQQQQ~~~~~~~~~~~~拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ~~~~~~~~~~~~拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅┆QQQQQQQQQQQQQQQQQP~~~拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅┆QQQQQQQQQQQQQQQQON�~}}}}}~~~~~~拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQQR帎拹弿彁悙悜憫拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQQQ彂拺悘弿彁悙悙拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQRQ悙憫挀摀搾拻拻拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQSQ拹憪憭拻拻拹悙拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQPN拹憪憭拻拺憫憫拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQSP攽悙悞拻拺憭拺拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQSP攽悙悞拻憫憫憫拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅QQQQQQQQQQQQQQQQSP搼悜憭拻憫憫憪拹岩乙乙乙乙乙乙蜒))))))))))))))()(*jjjjjjjjjjjjjjjj┅[\ZZYZYXX83875587眇耩铑痧钏松翘耸搔Ηイ晽枠xuzsmoknnmloaeagecce洖灋灋灉瀾攼憮拺攪墜妷媼圵檿櫀vvwwpooooopodedeedbc湚湝湝湙洆摀拹憫拪媺墜垎圫榿NK^eHD_oono^EEVWBFWddc渹MO儍OR�憰拹慟e揓^MrJ^LsV�8晼76db5oPSn6oo66gb5eLM�2櫅66洔5倕倗}Ng拤奯^妶``Wr6SM65LO8ghnm9RR86KL5gde�4ji88ih6唭儌別d憞`Is塨KtWt7ol75gc7bZ\i5ml36ca5eVX�6殯66洔4厔儎僛b悑奯\噰`^UrbED_ZC@WeZ[i^ECdW@DWcXX殌QP儍PPa卂]刾ILzL_KsI^KrVqpmniiddefghiklnquxxeece櫆櫃殯湚漸唲剟剴憡墔媹妸塜sroljifeefghiklnquxz|~僩湞潩湝洓湋垈倐倰憡墜妶妸塟vtrkjeddefgijklnquxx��厛墢潥殯湞潝拝厖厭憡増垔垑奫xvtushfdefhijklnqux{}亣噹帍挄櫅洔憦拻拻拺妷妸坸:塠xwvvvvvvhhjjjkknmtw{}亜垔崗憮棛殯晲敁拺拻妸妸sM6塠xwvvvvvxmlmjjkkmsux{}亜垔崗憮枟櫅洏晹搾拻妸媺9_4t[xwvvvvvxpommmmmnntw{}亜垔崗憮枟櫆潥棔敁拻妸垐墘7媅xwvvvvvvonknnnnpcru{}亜垔崗憮枟櫅殫枛晹拻妸増妔5v\wyvvvvvwnpkoooomefbf~唸帋寪敃槞洓槜棔敂拵媹垔媼媅wvywwwwxonpoooomdcecfde墜審挀槞櫆湙棗枙搼帉妵�増Ytwwwwwwvlonnnnnlbeddabbe洕寫敃棛洓櫄櫁晸拸巼厑{wYY[\[[[[Z57666665眇镱镘蓍祆獒葑有然矤晢{kcZZZZZZZZ[�亐���5耨镳痧耱镫玢葚瘴示埃晥zkaZZZZZZZZ[�亐���5耨镳痧痫钏受葳瘴示埃晥zkaZZZZZZZZ[�亐���5耨镳痧痱鹛噬人盐示埃晥zkaZZZZZZZZ[�亐���5耨镳痧痦鹗蜕怂侍示挨晥zkaZZZZZZZZZ亐���5瘃镳痧痧鹗适适仕骚Δ檲|k^ZZZZZZZZZ亐���5瘃镳痧痧鹗适适适骚ΔぅaZZZZZZZZZ亐���5瘃镳痧痧袷适适适骚ΗЕΖZZZZZZZY亐���5瘃镳痧痧袷适适适骚ΖЁЖ╖ZZZZZZZW������6瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZY65566666瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZY58866666瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZY69777776瘃镳痧痧鹗适适适骚ΖΖΖZZZZZZZY66666666瘃镳痧痧鹗适适适骚ΖΖΖ︼痱镲镳眍"!#!"#"$搻攽敂拺okqnnnnpn苓葆捃葺飰垔嫙潩漥hhhijji噧剠剝儏{}}}{{}~z洏槚棖晽cedeedee靿寜墰潩漢kgjihhj�儎儎剟儃z|}~~}|}棖棛棙殬eddbbcdd閴棾礄Х穪jiif仺瓟挷瓡剠剗嵁瘣惎瘝棛棛毞瓥☉瓛﹟陦聥壝羻喢j摃g纉i美�吚參纜}妹}z纑tru煾獡ce挃bf拻霔扩隶そ}{lg罁暳沥⒔厖唞翞澚翝熆rrqpr榞挮|e摢}順罀嵙缞劸~崐s緆k懒儑绹晹~纙|亮||纔utst櫕榙d摀gc憪陿3窓槼睈}崐q劎﹢懗皷啌杴彴皪嵃瓚r洑u啴叮⊕﹝﹞钖枖崑墖剚}zwtpljiiig倎儌~z}~}}~}|倂tttt棗cdicfdfd頇枔拫寘剚}zwtpljiiihheg剓}|z{|}�{棆tttt棗cdcdfbad饻檿悓妴剚}zwtpljiiihffchei|}}|{{}棗ssss棗cdffdffc餄湜灈垎剚}zwtpmjiihhfbeedhjosw{~~枠棗棗棗cddcfv纅饻湝洓洓潄}yusqmjhdhgffeefijmptx{}晿晼槞棗ccdc|e饻湝洓洓歨ijvspliiiigffeefijmptw{|們晻枛棗ccce聬縵饻湝洓洓漢khijkljhhggffeefijmptwy}剣姀摋梒cecee耭餃湝洓洓沢hkjjiii刪hfffeefikmqtwxz倓噳崘棗ccfed{聓餃灇湝湝漡iihhhhj唵們ffcdhijlqvuy|倖妽彄槡檾edddd顫煘湝湝歨kjhhhhg儎倕剠僣ekhiqrxx{亣妿悢棙枦櫃瀌d頋潨湝湝済igjjjjg厓儎厔唭y{korrwy|亜厜崘敇殭櫂殱潩镯镲镲痧�$#&####&憫悜摃憮oqlnpQZfq亴洣读在噔沌珥眄痧痧痧痧飦亐����$拻搾拻拺nnnnonnmp倠毃崩肄後滏殡眍痧痧痧痧飦亐����$拻搾拻拺nnnnnnnqo捱湩茨洼徉滏殡眍痧痧痧痧飦亐����$拻搾拻拺nnnnnnnno掭掭芰艳後滏殡眍痧痧痧痧飦亐����$拻搾拻拺nnnnnnnmp葳茌捱葸咪滏殡眍痧痧痧痧飦亖����$拻搾拻拺nonnnnnno葺揶揶揶溏觑镳痧痧痧痫亖亐���$拻搾拻拺nonnnnnnn葺揶揶掭镲痧痧痧痧飦亖����$拻搾拻拺nonnnnnnn葺揶揶掭痧痧痧痧飦亖����#拻拻拻拺nonnnnnnn葺揶揶掭 痧痧痧痧駘亇����#憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�#!!""""#憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�#""#####憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�$$ $$$$#憫拻拻拺nnnnnnnnn葺揶揶咿痧痧痧痧�#""""""#憫拻拻拺nonnnnnnn葺揶揶咿 \ No newline at end of file diff --git a/rs/moq-video/src/decode/test_data/vp9_64x64_pattern_5f.ivf b/rs/moq-video/src/decode/test_data/vp9_64x64_pattern_5f.ivf new file mode 100644 index 0000000000000000000000000000000000000000..3141cc694f3b6cc8d9d27e6419ed39d535b79585 GIT binary patch literal 5284 zcmV;V6kF>=OG!om03ZNXP&qI_06+j9000010000500000000122mk;8000000001j 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 literal 0 HcmV?d00001 diff --git a/rs/moq-video/src/decode/test_data/vp9_64x64_pattern_5f.yuv b/rs/moq-video/src/decode/test_data/vp9_64x64_pattern_5f.yuv new file mode 100644 index 0000000000..0b81fb7ede --- /dev/null +++ b/rs/moq-video/src/decode/test_data/vp9_64x64_pattern_5f.yuv @@ -0,0 +1 @@ +LJJJLJIKPPVP悤憭拹拸悘幸已右岩乙)()(()()(()*ikhhgghmkn┆┊īīKJKIKJMLNPPS崕悙憮憪挀弦岩孕研诱(*(**(*(())&hkhhjijjijíīǐKG !21/11//.1-?@>AAB>??A&'%($)%&%%7484574557LK! /-/11/-//2>@@@??AA@@%&'&%'(#&%7396566575MK  6: !/2./0201/.?B@@?@>?AB)$&$%&%'&'6656843779HH   76 20/.01.010CBBA@>C>=?'%%''(('&(784:686656KL!!帓拻?>>?彂搹1100A@@BA?BC帓憦彂晳&'%%&%"'%'拺搻9678拺LL悞 6拻>@悡02彂10/>?>@??B憯@悞拹彂%$''*%''(憮86悗78弿8SN$)悡2/98憭拻9;97悞0/?憫@>@搻AC挀搾12帎100憫&&&憭6776悡搻67QQ(&彃228;搾挃<:79搼11C拹@AC憥@@憭拺22憫/.0憫(%'憭9578彄搹87PP(&敂3憫6拹憮8搻6摀23A?@@>@彂>拻憫憫挀1弿1.101/$)拺8拻7憦彂7扥S&(悘1悞7悙憫8敁7憫43>A@A>>敀@憪憫憫悜/憫13/020(%悜6拹7拻拻7怱Q))晸1178拺憮:976憭361321?@悡AB憭拺2.悜/./22002敁8754拺憭45QR$&拺3299悜憪;:79拺5.2悡1>@悞?>憫憫/2悜101拺110悜8756憫憫65SP$&-悜47憭>>搾97悞521.搼1534晸B拻拻1憪2/1/憭00.3憮77搼77憮7QP%&./搼悙>>>?拻憪95201/22.332憯拻拻憮20.2///.0///摂拻7447拻QQ'&+,2288A===9::965331111223455541101/////0116555666666RS'&*)3457@;::96633222133456668.-++-0.//101116555666666QP!#/257@>?<:998441100001123444621++,././101116666677777RP! !!"!!:?<;:97744221111223455550/*,#$''.011///.4445667777RN !"#" "9><=99985522111122345565/1,+&% %&/01200007888888777RQ ! !#" " /09:8844110110122344750/*)%%&$%'%&')2334556666RS" #! !!02;9663311011122335495/-))#%%&'(&&'*3555566656RS" #! ! 00/0223311011032325495/-))#%%#%#7766765656RR " !! ! 00/00045221110424334860.*)#$&%'%7676976747QR ! !! ! 00/0//220/2111323324760/*)$$#"$$5656665477QR ! 00/001331.2012125444761/*)$$"!%&5677875488QQ ! ! !! 0000000012>@??5342446710+)$$""$"('#$556733QQ!! ! !! 00/0012121>@>?4344556710+)$#!"%%('$&566453PQ! ! !! 0000///.0/?A>A>?A?545720+)%#"$&&%%%%%$65PQ! ! !! 0//0/01010@@>???@A245720+)$# $%&&$$%$$#76QP!! !0/1//.01/0@@@@@@@@@?..)+"$" $%'&$%"$"#! RP# 213///.0/0BBBAAA@@@@/0**$$! #%'%&&#%#$"!TP""  2.///51/0/@AAAAAAAAA&# ! "$%%$$"#"#! RP #!  "!"3/.//3-100A@@@@AAAAA%'"$&%%$"#"" SQ" " "  !1000/10.01>AAAAA@@@@! "$%$$$!#!" QN#!!! !!40/1101/0.A@@@@@@@@@#!%&(''&#$"" QRNQOPNOQRPU崙彁憫彃悤醒岩乙佑佑('()'(&(()(,ji>?GJVVacihec_^[ZWVRRPPQQOPPOQR悙悞挀拹拻右乙乙乙佑))',**+)(((*ii@?HIWUabiifd__[ZWVRQQQQQQQQPPN儊亗崘佑乙乙乙乙))',**+)CK唙z媧妱墢墕梙卍e`a]ZWUQQQQQQQQQQQP~}|}}}}~彂右乙乙乙乙))(+***){PSs噯|siw渷hyjdg^aZZVVQQQQQQQRRRRR~~}�~拻右乙乙乙乙))(***))TU歲媣殗tp啎lqo乥e^^\YWVQQQQQQQQQQRR~�~~|憦蜒乙乙乙乙))(*+))(Me8<杹k噣俷剈杛俥e_`[]VWQQQQQQQQQQQQ}~~~}~}憪矣乙乙乙乙))(*+)((^KK卽v悥|{�櫅w湡_^\YVVQQQQQQQQRQRP~~~~~~憪佑乙乙乙乙))))+)((宎X\m宻坲峼檣姛Λ゛`[]UUQQQQQQQQRQSP~}~~}}悙已乙乙乙乙))))+)((g;mg亷坮憚潨l枬湯┅WQQQQQQQQPQSO}||~~|{悡杂乙乙乙乙))))+)((o:hg巚s姄q攟崲々┃WQQQQQQQQPQSO}||~~|{悡杂乙乙乙乙))))+)((Q>@D噰杝檢剛唟煣┆QQQQQQQQPQSP}}|~~}|悞佑乙乙乙乙))))+)((PXG亣亁厓晢帣mエQQQQQQQQPQRP}}}~~~~憫佑乙乙乙乙*))(*)()S[凪昽搗w枃倕劃И猀QQQQQQQPQRQ}~}~~}~憫乙乙乙乙乙*))(*)()}+{J洊檪崚寪唗ぇQQQQQQQQQQQQ|}}~~~~~憪乙乙乙乙乙*))(*)()洆]a坿i搮攕唘{QQQQQQQQQQQQ|}}~~~~~憪岩乙乙乙乙*))(*)()G僕evy啌}tz嫐叄煪猀QQQQQQQQQQQ|~~~~~憪岩乙乙乙乙*))(*)()I~qI潁k悧x塵乶#QQQQQQQQQQQR|~~~~~拹岩乙乙乙乙*))(*)()8]B憱kr摏o垏s湯QQQQQQQQQQRS姁悙悙帉攽乙乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQQQR憰挀拺搾拺栽乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQQQQ憫憫憫拻憫右乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQQTQ悘悜拹帎挀右乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQPTR憪摀拻悙摀矣乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQRQORQ悜拹憭憪拹延乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQRQOPQ悙悙悙悙憦矣乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQQQQ憭憮拸憪搼赵乙乙乙乙*))(*))))))*ijjjkjijik葳圹\X:64:4镯盹痤怂嗜搔ウΕ蹤槞vwnmkkoeeddf潩潩湠憯搼搳噰噰迼枟kyplnomedeec湜洔櫅摀晽搱墘墘蹡�LBWXFEbndccXGO儍OR�憰拺{LMttMZs5kf66fh6mNKf7d�55殑5刕d�5噳55塟s7RP66PO6mfcd6Ni88i\5剠亼:^`66`[t9mg66gj8kcgf6e�55殔8僸o�8妶55圸sbBBYYBD^l`cypBP儍PKq卭n刼MKrrKYsomfefhikmovz儓殭潩剟剠厖噲墘塜wtnifefikmovz儖彁湠泟剠倓妷墘塡utvtidjjlmovz儔崘暁湊剢厗垑墘塠xywwtnjklmovz儖寫晿洖拺晵墘墘塠ywvwwomlmnow{們媽憮槢洏様憠垑増[xwvwwoommnlvy}倞寫摌洓槜敁媺垐塠xwvwwoomomhfx~剨寫摌洓槜晻帇噰媅xwvwwoolpmefbe儕寫摌洓槜晼悓唴孿wyvwxnnqlnecccc湊憮槞殫晻敁墕儈[wvyyvpmlnmddddd洔湑棜潧槙拹寚亅Ytwwwwlkmmofdddd潫湠潥棛槜敀崍亅YY[\[Y:8768祚铒镲舌苷膛瓬俼ZZZZ[Z亐�6痧痧罏湧珖灢睔僷ZZZZ[Z亐�6痧痧匠湗瓱瓨卲ZZZZ[Z亐�6痧痧硸瑣殏唕ZZZZ[Z亐�6痧痧括棴噲瀩ェZZZZZZ���6痧痧柿殰彇湊ΖΖZZZZZZ���6痧痧姜嚁悢煂ΖΖZZZZZZ���6痧痧挼獧洡�ΖΖZZZZZZ���6痧痧怜櫏柀珎ΖΖZZZZ[Z87766痧痧瘃适适失ΖΖZZZZ[Z87766痧痧瘃适适失ΖΖZZZZ[Z87766痧痧瘃适适失ΖΖZZZZ[Z87766痧痧瘃适适失ΖΖぅΘ痦"!! $敀敂憂nnnpn苓谳�墜煗hhjig厓儎厎{{}~z洏棙梘bddb▓墛墲iiigi剟剟亊~~}|}棖棙梕dbbd柍硴挰珒j厖剷悙崡櫀槨{{柧弻柯}w羑ぅ吢唡妹|t胹毌櫩cd亮d饦困翢澙o唶兞览湜胻ss椑拺览戲暱強戮|v羖~~兙唡亮|s纔唶t腸f揪f駴澋磾惉皡h~�g~舶崓碍唖墔r埁瑋|棎帄噦}vrmihgfed{||zutqqstcdddd顭洂寘~|vrmihgfefjmz}}utrvrfdddd駶湚渿亄vrmihgfebglrw|攔tssddddd餂湝湚f{vrlihgfedjppw|枖槙fdddc餃湝湞iiiokiigifegmqvz儔敃gddac饻湝湞iiikkihehcdgmqvz儑挄hcded饻湝湞iijlh儍gfidgmqvz儕悢棛ddc餃湝湞iijii儌儍fdgmqvz儓帞槞棜e餃灇櫄hjlhh剟剟剒inpvy唺帞櫄櫃欘潫灊漥ikij唭儍儀z}qwz~唶崝櫃櫄氻潩湝漢jjig厖厖厈|}{{|儕彆櫂櫅濓眍铕�!#%$$彃拻抧onpop蹞Ψ芜怃玳痧痧痧亖$拻拻抩oooK9x崨=n滇珈牮痧痧饋�$拻拻抩oooLFvtⅶ噤骒痧痧痧亖$拻拻抩oooAC璬歚q栝牮痧痧饋�$拻拻抩oooM>mP{眇痧痧饋��$拻拻抧nnnTPw`q�痧痧痧亖�$拻拻抧nnnL@Rhaj�痧痧痧亖�$拻拻抧nnn.F檙倠v痧痧痧亖�$拻拻抧nnnPBs媠憻痧痧耩$#"##憭拻抩ooooo揶揶�痧痧耩$#"##憭拻抩ooooo揶揶�痧痧耩$#"##憭拻抩ooooo揶揶�痧痧耩$#"##憭拻抩ooooo揶揶�LJJJLJIKMOPL帗挀拹拸悘幸已右岩乙)()(()()(()*ikhhgghmkn┆┊īīKJKIKJMLKLPS寭帒挀憪挀弦岩孕研诱(*(**(*(())&hkhiiijjijíīǐKG !$!.0.11//.1-?@>AAB>??A&'%&&)%&%%7484574557LK!!-'110/-//2>@@@??AA@@%&'&%'(#&%7396566575MK  #'! 22200201/.?B@@?@>?AB)$&$%&%'&'6656843779HH  !%$1+3//1.010CBBA@>C>=?'%%''(('&(784:686656KL!!帓弿<>23憦搹1100A@@BA?BC帓憦彂晳&'%%&%"'%'拺搻9678拺NL 悞 8憮C/嫃02彂10/>?>A>@B憯@悞拹彂%$'()%''(憮86悗78弿8QN"%悡2/98憭拻9;64帎//?拺A>B晱EC挀搾12帎100憫&&&憭6776悡搻67QQ(&彃228;搾挃<:57憪00C拸?BE搼BA憭拺22憫/.0憫(%'憭9578彄搹87PP(&敂3憫6拹憮8搻6拻11?=?=AA憱=敀憫憫挀1弿1.101/$)拺8拻7憦彂7扥S&(悘1悞7悙憫8敂8憪21;?BC@=晹>搻憫憫悜/憫13/110(%悜6拹7拻拻7怱Q))晸1178拺憮:987憫14.16:?=彁@D憭拺2.悜/./22002敁8754拺憭45QR$&拺3299悜憪;:79憪4,0帢<==憥>@憫憫/2悜101拺110悜8756憫憫65SP$&-悜47憭>>搾95帎410.搹6519棏E拻拻1憪2/1/憭01.3憮77搼77憮7QP&&./搼悙>>>?拻帊73211.+103<:帢拻拻憮20.1///.1///摂拻7447拻QR(&()3664BA=?=;986421211003445622/1/--.21015655666666TU)(-,5799C?>;?97653211111234456++11..//21/04445566666SR!"&'1147@??>:7786432222234556766-)25.//022015655666666RQ $&0368@??;756642100000123345681*.1/00032026766777777QO!!"51@?;;98754321111123445301-.&'$""%-00010./3555677777PM !1/=>?@99875321111123445654/.&'$"$%/01121/27888888777PO! ! !89;98642121111123345540/)($"$!'%&&('(+2444566676RR"!!""89?7642112112212445654..(($")!$#'''%'+3555777666RS#! # ! 34/4331122112212455653-.(($! #'$'+5566786666RR " !! ! 0002122332112212356764..'(# #'%(,5565654679QR ! !! ! 0000000011113412232454/.'(# !$"&+4322456675QR ! 00/0123200111123432455//'(# #"',6677666775QQ ! 0000000028>=72246666650/((#!$"$#'#23424555QQ!! 00/0012217>=73245456650/((" #"&$'#45656974PQ! 000///1//5?A@@@?:403550/((#  $$&%&&%'.573PQ! ! !! 0////02104?@AA?;91066500()#!" %$&$" $*6:6QP!! 0/1///0102@@A@@@=@@:74/1()#" " $$'%$$##%"! RP# 213///.0/0BBBAAA@@@=64..((" ! #$'&%%$$$#"!TP""  2./.051/0/@AAAAAAAAA(%  ! "$%%$###""! RP #! "!"3/..03-100A@@@@AAAAA&( "$&%$##""! SQ" " !  !100//10.01>AAAAA@@@@! "$%$$#"""! RN#!!! !!40/1101/0.A@@@@@@@@@#!%&('&%$#"! RRNQOPNOQRPU崙彁憫彃悤醒岩乙佑佑)*()'))+-/*,16:9GJVVacigda_\ZXWVRRPPQQOPPOQR悙悞挀拹拻右乙乙乙佑).,,-+*'%((+3=B@HIWUabihfb_][XWVQQQQQQQQPN儊儊}~矣乙乙乙乙))',**+)FTgyoy攧O乭n姀r焍da^ZWUTQQQQQQQQQP~}|}}}}}}乙乙乙乙乙))(+***)嶳pgwon}V噡uu嫐q`d^^YXVUQQQQQQQRRR~~}�亇個乙乙乙乙乙))(***))R朩g啙攷殨uz峫~s`a`]ZXVUQQQQQQQQRR~�~~~�{亇醒乙乙乙乙))(*+))(i嘗.焪條~p~r寃r峚c_aYYWVQQQQQQQQQQ}~~~}}}�|亊延乙乙乙乙))(*+)((�13棑倎嫐崈俻煖aa`]YXVUQQQQQQQQRP~~~~~}}~亊亊矣乙乙乙乙))))+)((roj4~嚍z恥挏剝ぇcc_aXWUTQQQQQQQQSP~}~~}~~~~�~蜒乙乙乙乙))))+)((u{\b抴j亷pyzw懃煭玔YWVQQQQQQQQSO}||~~}~|}~�佊右乙乙乙�))))+)((m杅L洈媶峷檾lyⅹYYWVQQQQQQQQSO}||~~~~|}~�佊右乙乙乙�))))+)((i]\Vj憵搫寕彊{#QQQQQQQQSP}}|~~~~~~~��矣乙乙乙乙))))+)((j;0n搈o渧~}�巟ェQQQQQQQQRP}}}~~~~~�~�矣乙乙乙乙*))(*)()xwccym巗晢倎坰·QQQQQQQQRQ}~}~~~~}�岩乙乙乙乙*))(*)()Nm仜憏憇塶ry挙潽猀QQQQQQQQQ|}}~~~~~�}亊岩乙乙乙乙*))(*)()嘦哤媜寍唚lq抶ˉQQQQQQQQQQ|}}~~~~~�}亊幸乙乙乙乙*))(*)()Pg�3w悅~挋~媢垾湭猀QQQQQQQQQ|~~~~~�}亊幸乙乙乙乙*))(*)()QMI9vw洆y悏噡導ⅹ猀QQQQQQQQQ|�~~~~�}倊幸乙乙乙乙*))(*)()EXov|帇寭悵崚}エQQQQQQQQQQRS垚悙悙帉攽乙乙乙乙乙*))(*))))))*ijjjkjijikíQQQQQQQQQQQR憰挀拺搾拺栽乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQQQQ憫憫憫拻憫右乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQQTQ悘悜拹帎挀右乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQPTR憪摀拻悙摀矣乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQRQORQ悜拹憭憪拹延乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQRQOPQ悙悙悙悙憦矣乙乙乙乙*))(*))))))*ijjjkjijikQQQQQQQQQQQQ憭憮拸憪搼赵乙乙乙乙*))(*))))))*ijjjkjijik葳圹\X:6676  镯盹痤怂嗜搔ウΕ蹤槞vwnmklpbed]e潩潩湠憯搼搳噰噰迼枟kyplpmodaeaa湜洔櫅摀晽搱墘墘蹡�LBWXFH_pd_bVDO儍OR�憰拺{LMttMZs5kf66fh7nKKf1c�55殑5刕d�5噳55塟s7RP66PP5ndad1Li88i\5剠亼:^`66`[t9mg66gm4mdce4a�55殔8僸o�8妶55圸rbBBYYBE^m]byjAP儍PKq卭n刼MKrrKXsnledegjkmqv{厧棞湐垉剠厗噲墘塛vsmhedehjlpuz厠彆湞搰儍儐墘墘塠tsushciijloty~剦帓棝棊噭厙垑墘塟wxvvsmiijloty~剦帓枡湙敀搹妷墘塟xvuvvnlklmqv|亝妿憰櫅殭棑帄垑増Zwvuvvnnmmmpuz剨帒暀洑槚攼媺垐塟wvuvvoooomjoy倗嫀憰櫅殬棔拵妵垔[wvuvvooppnifgr剫帒暀洑槚枖強唵圼wyvwxnmlmof`dbe帍憰槢湚枙敁墔倐[wvyyvpmoqpdcfcf殮摃槢潧槙拹媴�|Ytwwwwlkmipbafdg潥湜湝殭槜敀寙�|YY[\[Y:858=  镬眇耠後苷膛獢rZZZZZ亐�亊| 痧痧窚綘杯憦瑬僷ZZZZZ亐�� 痧痧樔姇摫灔瑯�jZZZZZ亐�}}} 痧痧懻姌崋瘝⿻�mZZZZZ亐�倊�痧痧捄墽⿻珤┈qZZZZZ��亖}痧痧级湢槕ЕΖZZZZZ���}{ 痧痧á殱柋瀴ΖΖZZZZZ��亖厈痧痧煚柅爫ΖΖZZZZZ���y 痧痧瓶拤棎ΖΖZZZZ[Z876:< 痧痧瘃适适失ΖΖZZZZ[Z8744: 痧痧瘃适适失ΖΖZZZZ[Z876<;痧痧瘃适适失ΖΖZZZZ[Z878<5 痧痧瘃适适失ΖΖ%│镲# !!#敄枖梟nnnpn苓谳�噸灊ghgii厓噲剘{{}~z洏棙梘bddb〾厠帠lihbg厒儑亊~~}|}棖棙梕dbbd▌椀皹尟珇f剝仌悙崡櫀槨{{柪寧脚{n縣'嚵倈妹|t胹毌櫩cd亮d顩困⒙翞澛l~剛璃溊罍浢tss椑拺览戱樉弻韭zs緆儏劷噟亮|s纔唶t腸f揪f驐澏磿尞眳j~j叺皪嵃瓎s墔r埁瑋|槗強噦}wqkkfhdgnx�|xvopqutc`acf餃棏寙儂uqljhhffjgwx{~ptsopcgefe驏牅搨~wwqnjjhhfamgu}媥rorhaefg駴洟灉q}wrojkhigbnityz崚槜榟j_eb鬀灈殲efknljiihgeeoqw~�垥槙fegea霝洕潥lmhlhkehdceimrw{亝寭朾hgdd驑殭櫇fcfkm俿maeghprv|~厰姕杒hbf駳煛殱ojcii倆卶ggiprvz~�厤挏暃hc餃灇櫄hjjei厔儉噂lnru|倛帞櫄櫃欘潫灊漥ikih唩儌唜{ouu{~亞崝櫃櫄氻潩湝漢jlkg唫噯儅{ywvy倛嫃暀櫄洕镯铑瘃!#" $拺搾攎lnoln厳Ψ芜沐玳痧痧饋�倎{崜拺攐oomM=祲o�^n潆腠痧痧饋�}{z悤憪攐ooo4S_gq瑃栣屙镳痧痧亖}|悢拻攐ooo+aWr[D�彖腠痧痧饋�倎z悜摂搊ooo0MU枛p�铕痧痧饋��亄憫挃昻nnnKS嘪儏g痧痧饋�|}}憮憮梟nnn76tym瀬痧痧饋�~~|憯弾搉nnnD@剛p測痧痧饋��z崜搾梟nnnQO廝gMf痧痧耩$#"!#攽拹憃ooooo揶揶�痧痧耩$###!悙枙昽ooooo揶揶�痧痧耩$#&$ 憫攼憃ooooo揶揶�痧痧耩$#!!悢攺搊ooooo揶揶�LJJJLJIMQQWU帓攽悙拸悘幸已右岩乙)()(()()(()*ikhhgghmkn┆┊īīKJKIKJMNQOTW墥憪憮憪挀弦岩孕研诱(*(**(*(())&hkhiiijjijíīǐKG  "&)43-+.//.1-?@>AAB>??A&'%%&)%&%%7484574557LK ! "0*1../-//2>@@@??AA@@%&'&%'(#&%7396566575MK  "%562./201/.?B@@?@>?AB)$&$%&%'&'6656843779HH  !"!711,-1.010CBBA@>C>=?'%%''(('&(784:686656KL!!帓攺/./6摂搹1100A@@BA?BC帓憦彂晳&'%%&%"'%'拺搻9678拺OM !悞 :悈4.弿32彂100??>A=?B憯@悞拹彂(())(%&'(憮86悗78弿8TQ$&憮1.98憭拻9;53帒11B枔A=>悕EE挀搾12帎.,.憫&'&憭6776悡搻67UU+(悞118;搾挃<:46憫23G枒@@A弿CC憭拺22憫/.0憫(%'憭9578彄搹87TT+(晹2悜6拹憮8搹5挀34CAA>@?彆>枓憫憫挀1弿1.110/$)拺8拻7憦彂7扴W)*憦0彃7悙憫8敁7憫44?CDDA=晻?晲憫憫悜/憫13/110(%悜6拹7拻拻7怶U,+枔0078拺憮:976憭37247AB枓@A憫憫/2悜101拺110悜8756憫憫65WT'(.悙37憭>>搾94崘5332棎9:8@湐F拻拻1憪2/1/憭01.3憮77搼77憮7UT)'//拹悙>>>?拻崒743340.359D@憴拻拻憮20.1///.1///摂拻7447拻VV*'''147A>@=87664210000012334570!.1/00032026766777777XT#$,397EC<=<:75432111112344531/)-*("%-00010./3555677777WR! '+96FD=>>=:75321111123445664/1*($%/01121/27888888777QQ"$"!!$25>8=9764211111122334553..)($ $!'%%&('(+2444566676TT$" &3396<:763110//011354445500)("$ #$'('$%*4654678764ST#! ! ! 4346763210.-.013553344//((# "'))"$)4664478952RR " !! ! 0002343331//./13453454..((# &*+&'*3453336975QR ! !! ! 0000000012210212220144/.((#"&(%(+1132236884QR ! 000112220010//12320245//'(#!$#(.89:9656897QQ ! 0001443115:861024455650/((# "&0035746678QQ!! 00/15663039862001246650/(("#'1137<<;;86PQ! 00001230.3AAAAA@@@@ ! "$%%%%$$#!RN#!!! !!40/1101/0.A@@@@@@@@@#!%&('%%%%$!RRNQOPNOQRPU崙彁憫彃悤醒岩乙佑佑)*(**,././*,16:P儍PKq刼n卭MKrrKXsnledehlrnjp}|u帡湝攬剟厔唶垑墘Wvsmhedgkklqwz}剨彆湞搰儌儐墘墘塠tsushcililuyx墝帓棝棊噭厙垑墘塟wxvvsmigjpstw垕帓枡湙敀搹妷墘塟xvuvvnkjlorsv}厠帒暀洑櫁搸妶墘圸wvuvvnomijqtrx儕帒暀洑槚攼媺垐塟wvuvvoonkiiqz儓寧憰櫅殬棔拵妵垔[wvuvvomlpmdgu唻帒暀洑槚枖強唴嘯wyvwxnmlmof`dbe彂晽櫅湙棔敁墔倐[wvyyvpnnqpdcfcf殦晽櫅潧槙拹媴�|Ytwwwwlllipbafdg殰洔湝殭槜敀寙�|YY[\[Y:858=  祉痱痣後苷膛獢rZZZZZ亐�亊| 痧痧十湲豹珢~nZZZZZ亐�� 痧痧硾皝攧殝⿸yhZZZZZ亐�}}} 痧痧顶尅◢{kZZZZZ亐�亊�痧痧⑼暔殢檷獰umZZZZZ��亗}痧痧嚑煟槴殝ィZZZZZ���}{ 痧痧殉�懀殺¥焃ZZZZ��亖厈痧痧案晻灖ǎZZZZZ���y 痧痧瘔摎獝え│ZZZZ[Z876:< 痧痧瘃适适失ЁéZZZZ[Z8744: 痧痧瘃适适失ΖΖZZZZ[Z876<;痧痧瘃适适失ΖΖZZZZ[Z878<5 痧痧瘃适适失ΖΖΖǎ祛$# "彂晸抧nnnpn苓谳�唽潨higee厓儎�{{}~z洏棙梘bddb▓唽彈khh_d厒�剚~~~}|}棖棙梕dbbd樃硻嫭�g倎倴悙崡櫀槨{{暳彂灸xm羓ⅵ壝亅妹|t胹毌櫩cd亮d須哩C罎犅l亣偭獪览湜胻ss椑拺览戲櫧帇矫{w緆噳劷媩亮|s纔唶t腸f揪f髼湷睌嵄矈j�o姸皪嵃瓎s墔r埁瑋|槗悑垈}wmhrejj�qx�xwspsqp`mgdd驗槓妱倄tumndjceilxv��nx{pwb_dib髸潣悅倉wtjc`jhbcniw~�峺rkrhdmae洕槝pzqf`dikgflkxx{拻槙揮gjbf鯕殨暈konnjgkkgbdjpp{�~嫕挆g[\_f颌洑櫁kngmjccjicdknsy}倗妿梌f\bd駰槜槥hffhkukedijfrwt}儎寫歽eaqf駳牏洕nihejzn``flqsx|儑垚枠zme餃灇櫄hjmde儍噥刲orsw|~倛帞檿m顫煘潩jinhe剝唭倇outv{~亞崝檼槣氻潩湝漢jnke厓墕�|ywvvy倗嫃暀殲镯铑瘃!## #拺敀搇ppmln厳Ψ芜哝玟痧痧饋�亖|崜憫昽mnlRClay寗撥潢麴痧痧亖{{|憯彁杘oooI2]F~^蓦珉痧痧饋�|~拻彂梠oooB8f儐_�8桦腩痧痧饋�倉拹悡杘ooo=Zw妜Ve昼轲痧痧亖�亅憪憯昻nnn18t晎梺铕痧痧亖|}}憮憮梟nnnIL/b厀S痧痧饋�~~|憯弾搉nnn;Ow帞Xw痧痧饋��z崜搾梟nnn?2qy嚋�痧痧耩$#"!#攽拹憃ooooo揶揶�痧痧耩$###!悙枙昽ooooo揶揶�痧痧耩$#&$ 憫攼憃ooooo揶揶�痧痧耩$#!!悢攺搊ooooo揶揶�PNNNPNMPQQWU帓攽悙拸悘幸已右岩乙)()(()()(()*ikhhgghmkn┆┊īīONOMONQRQOTW墥憪憮憪挀弦岩孕研诱(*(**(*(())&hkhiiijjijíīǐNJ"# "!!!"&)43-,-//.1-?@>AAB>??A&'%%&)%&%%7484574557NM! "! "0*1../-//2>@@@??AA@@%&'&%'(#&%7396566575NL!!  "%562./201/.?B@@?@>?AB)$&$%&%'&'6656843779HH  !"!711,-1.010CBBA@>C>=?'%%''(('&(784:686656JK  崙攺/./6摂搹1100A@@BA?BC帓憦彂晳&'%%&%"'%'拺搻9678拺KJ!彂:悈4.弿32彂100??>A=>B憯@悞拹彂))))(%&'(憮86悗78弿8II!%憦' 98憭拻9;53帒11B枔A=?悕EE挀搾12帎-+-憫&'&憭6776悡搻67LN('弿*(8;搾挃<:46憫23G枒@@A弿CC憭拺22憫/.0憫(%'憭9578彄搹87QR)'敀0崙6拹憮8搹5挀34CAA>@?彆>枓憫憫挀1弿1.110/$)拺8拻7憦彂7扸Y((弾2拻7悙憫8敁7憫44?CDDA=晻?晲憫憫悜/憫13/110(%悜6拹7拻拻7怾X,(摀3678拺憮:976憭37247AB枓@A憫憫/2悜101拺110悜8756憫憫65XT&&,彁47憭>>搾94崘5332棎9:8@湐F拻拻1憪2/1/憭01.3憮77搼77憮7TS'%--憦悙>>>?拻崒74334//348D@憴拻拻憮20.1///.1///摂拻7447拻UV)&''1359B<:95:;86432311016445622/1/--.21015655666666ZZ+(,,779=D>@9876653211111234456++11..//21/04445566666RS&*/.559>=6:;89986432222234556760 25.//022015655666666OR&*/079<=@=?<76664210000012334570!.1/00032026766777777XT#$,498FD=>=:75432111112344531/)-*("%-00010./3555677777WR! '+;8HF?@@>;75321111123445664/1*($%/01121/27888888777QQ"$"!!&47@:?;764211111122334553..)($ $!'%%&('(+2444566776ST$" )66;8=;863110//011354445400)("# #$&('#%*4654578863ST#! !! 5467763210.-.013553344//((" #&))#$)4664478853RR " !! ! 0002343331//./13453454..((#!%*+&'*3453336875QR ! !! ! 0000000012210212220234/.((#"&(%(+1222236884QR ! 001112220010//12320245//'(#!$#(.89:9656897QQ ! 0002343115:861024455650/((# "&0025746678QQ!! 00/24663039862001246650/(("#'1137<<;;86PQ! 00001230.3AAAAA@@@@ !#"$&'''&#! !RN#!!! !!40/1101/0.A@@@@@@@@@ !%#'(*)(&$"! RRNQOPNOQRPU崙彁憫彃悤醒岩乙佑佑)*(**,.../*,16:?FLXXcekie_^[YXWVRRPPQQOPPOQR悙悞挀拹拻右乙乙乙佑--.,+(&''((+3=BBJKYWcdkje^]\[YXWQQQQQQQQPN儊儊}~矣乙乙乙乙))',**+)Bm墐|梲kV峠恵梹渁Zec]`\]QQQQQQQQQP~}|}}}}}}乙乙乙乙乙))(+***)@SEQ塻dojz實攼c俢___[[URQQQQQQQRRR~~}�亇個乙乙乙乙乙))(***))OF@ct彆t創kw巙z塪ga`a^WRQQQQQQQQRR~�~~~�{亇醒乙乙乙乙))(*+))(P儍PKq僶n卭MKrrKXsnledehlrmjp}|u帡湝攬剟厔唶垑墘Wvsmhedhjklqwz}剨彆湞搰儌儐墘墘塠tsushcililuyx垗帓棝棊噭厙垑墘塟wxvvsmigjpstw噷帓枡湙敀搹妷墘塟xvuvvnkjlorsv}厠帒暀洑櫁搸妶墘圸wvuvvnomijqtrx儕帒暀洑槚攼媺垐塟wvuvvoonkiiqz儓寧憰櫅殬棔拵妵垔[wvuvvollpmdgu唻帒暀洑槚枖強唴嘯wyvwxnmlmof`dbe彂晽櫅湗枙攽媴倐[wvyyvpnnqpdcfcf殦晽櫅潧槙拹媴�|Ytwwwwlllipbafdg殰洔湝殭槜攽寙�|YY[\[Y:858=  祉痱痣後苷膛獢sZZZZZ亐�亊| 痧痧醛毄瓖�嫬恾mZZZZZ亐�� 痧痧骗牃あ皹⿸yhZZZZZ亐�}}} 痧痧含瓖櫖◢{kZZZZZ亐�亊�痧痧捄珷潔umZZZZZ��亗}痧痧祝槚攼煚ΓZZZZZ���}{ 痧痧皩厸湁審ⅲZZZZZ��亖厈痧痧暀棐毀ǎZZZZZ���y 痧痧棪獘'éZZZZ[Z876:< 痧痧瘃适适失ЁЕZZZZ[Z8744: 痧痧瘃适适失ΖΖZZZZ[Z876<;痧痧瘃适适失ΖΖZZZZ[Z878<5 痧痧瘃适适失ΖΖ铌磉,% !!媿敂杒moqso圮谳�▼噳jdjfd個倕剘z|�亄殨棙梘bddb強湡nhj`c儉厑}}�~枔棙梕dbbd泩敶禑叚�g亐倴彂膊帠枛槨{{壢媯览fl羓'壝�y履w膔棷櫩cd亮d飼搂?臑灹m儔兝苛煘膕ps椑拺览戺暲強磁乼絣妼吋坹缆v羣儑t腸f揪f鍞毚瑯幆畨j剝p壊瓕幊皣r唴r埁瑋|槗弻垇}wmirejj�qx�xwspsqp`mgdd鬁槖垊剎sumndjceilxv��nx{pwb_dib駱湑搩wtjc`jhbcniw~�峺rkrhdmae鼭湢晽t}zqf`dikfflkxx{拻槙揮gjbf鬄檼槦gqnnjgkkgbdjpp{�~嫕挆g[\_f魺湞枛nlgmjccjicdknsy}倗妿梌f\bd饳槙殲fgfhkukedijfrwt}儎寫歽eaqf饳牐殱oihejzn`aelqsw|儑垚枠zme餃灇櫄hjmde儍噥刲orsx|~剫憲湑m顫煘潩jinhe剝唭倇outv{~倝悧槚槣氻潩湝漢jnke厓墕�|ywvvy倗崚槥牅殲镯铑瘃!## #拺敀搇ppmln厳┖砚哝玟痧痧饋�亖|崜憫昽mnlF>q_hHJu哏眵痧痧饋�{{|憯彁杘oooXA寏媊唥囝觐痧痧饋�|~拻彂梠oooK?mZ腩铖痧痧饋�倉拹悡杘ooo-H噠凪� 訇祓痧痧亖�亅憪憯昻nnn_@cog`t铕痧痧亖|}}憮憮梟nnnC+Ut圦R痧痧饋�~~|憯弾搉nnn@A@&'%($)%&%%7484574557RQ  .01100-//1<@A@=>A@>?%&'&%'(#&%7396566575[Y! /.1..2.010@@@B@B@@AC)$&$%&%'&'6656843779ZX" !#/04//..00.@A@@A?B@AB'%%''(('&(784:686656YZ!!彁憭"02憯搻30/1A@?A@悘A?A憭AC挀搾(&悜/11悢1''悞4776悡搻67WY 挀  搻悤0110搾//@搾?>?憮AA憭拺))憭101悜0'(悜7678彄搹87ZZ('憫4憭:敀拺;攽0憪10>@ABB@拹@彃憫憫挀'悙002013$'拻7拻7憦彂7扻X()摂5摃:拹憪8敀.憫1/DA>B>?拻C悙憫憫悜+憫11/101($悙5搻7拻拻7怹[)+憪4789拺挄::77枖.0ABD>B@拺AA憭拺&)憪0/210//0敀6754拺憭45ZZ))悜68;;挃拻:996憪1-?弿A@C挀@@憫憫()挀1/1敀///憮6556憫憫65YZ''1彃58拺@<憮79摀3100憪?ABC搼A拻拻-攽///1憭//02拸77搼77憮7[[()-/憥拻?B;>攽敀822201A@@@A?晳拻拻憪1100012./2/3悞拻7447拻[Z((,.33::??<<:9763312000/37=@AA--10010//10/7888777777ZX''-/44::??<<:9763301001158=?AA,-1.10/0/00/5555666666ZY((.044::??<<:97633000111124566-0110//1117777777777ZY((./33::??<<:97633011111424356/./..//2205444555555OO #+/45::??<<:9763301111142324554,.%&2210.0006777777777OP #*-22::??<<:97633011111423356451-'(1//0/00/6887776777SP "!#!::??<<:9763301111132335645-0'("!%#&&&&%&&(2556666777QP"!#!::??<<:9763301111032556645/0')""'&(%%'%%%'2666666777QP"!#"!! !;=;9773300111032556645/0')""#&&&'(''''4766666777QQ!!!!!!!!9:99571200001032556645//'("""%&%%%&&&%6666666777QQ!!"!"" 3100872300001232556544//'(""&&'&&$7666666777QQ !!!!!!! 1/00773310001132555544//'("!&%&%&$7566666777QR !! " 100000001/111142545544/.'("!!"%&6666666777QR !!!!! ///000000.211142545544/.'("!!#&'3266666777QR !!2241./0/22;>2142545544/.'("!"#$#'&66666777PQ !  001../1.//;@2142545534/.'(#!"#%$%#66666777PP!  ! 0/1../0//.@??BC>745644..'(#! ""&$$$$$$%3576QQ! !!" 0/0//0/100AA@@@<645584-.'(# !!#"&$$$$%%'3576QR# !  "2.../31101?A@AB@>>@A54.-'(#! !#&&&&&&$ %# OQ! !0//./2.1/0??>>??>?@@230,+'#"!!"%%$$$%$!#" OQ! !1//0131.10>?????@@??&'$  ""&%%$$%$!!" !QM$ ! "4//4/23/2.B?@A@ABB@@&'$! $"'%%$#%%$!$ !PTPRQQNPQOQU帗拹搾悞悢舷延蜒釉佑&))&)(()梥|榹殏摍壂牘┆┅è㏎QQQQQQQ~~~~~~~~~~~~~~~~乙佑岩乙()(*)))*Zrr~x剸檽挊対Μí┇琎QQQQQQQ~~~~~~~~~~~~~~~~乙佑岩乙()(*)))*�濪ok亰棞u摐n敗湱┅㏎QQQQQQQ~~~~~~~~~~~~~~~~乙佑岩乙()(*)))*nA厴湋nrx攳剅枺灙㏎QQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjij┆┆QQQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjijQQQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjijQQQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjijQQQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjijQQQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjijQQQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjijQQQQQQQQQQQQ悙憫憫憫憫乙乙乙乙乙()(*)))))***jjjjjjjjij[\Z[ZZ=64:4镯盹痤怂嗜搔ウΕ\晽枟unkkkoeeddf潩潩湠憯搼搳噰噰W檿檿ymmnomedeec湜洔櫅摀晽搱墘墘S榿NMe_BEbndccXGO儍OR�憰拺{LMttMV�5晽62on8nMLe5b�55殝5匼\�5妷55塙r6QN57NR7nedf5Li88ia4剝啋7^`66`Ut7me66lh5pTVe5a�55殗5俼o�5垐55圲p`EBY\C@^nbWcVDP儍PKm僴o僸IKssKVqolgddgikmoxyde潨洑渽厖厖厙垑墘Vqnkgddgikmou|亪湝潪棞剟厒剨墘墘]uoigddgikmovy亜嫄槤洔攩唴唸墘墘[wvtgddgiknov{亣嫀挄湡挀憰拤墘墘[xwvvuggiknrv|倗寧挄槢敀晵憡墘墘[xwvxxlljimtw{倗寧挄殲槜晸拪墘墘[xwvxynollmow{倗寧挄殲殮棓搶墘墘[xwvuwmoornfw{倗寧挄棞櫃槙攳墘墘\wyvxxnnqlnebf亞妿摋棟殬槙晬噮増[wvyyvpmlnmdedec媿悡槣櫄棔枏寘�xYtwwwwlkmmofdfef湙枖槥洐棖棎妱亄YY[\[Y:8768痧痧囗赆垡杉}iZZZZ��������痧痧楷等悐|hZZZZ��������痧痧ⅰ┏А|hZZZZ��������痧痧剺槝彨嚁|hZZZZ��������痧痧吉獚拞惃搢hZZZZ��������痧痧募簷Г}hZZZZ��������痧痧笗瓙攳硻エΖZZZZ��������痧痧煖儗倞ГΖZZZZ��������痧痧牆槫攩�ォЖZZZZZY76766痧痧痧适缮失ウΖZZZZZY76766痧痧痧适缮失ΖΖZZZZZY76766痧痧痧适缮失ΖΖZZZZZY76766痧痧痧适缮失ΖΖ镳蝻耦#"! $敀敂憂nnnpn苓谳�飰垔啘jgjig厓儎厎{{}~z洏棙梘bddb靿寜垱jmigi剟剟亊~~}|}棖棙梕dbbd陦棾菠}僯厖剷悙崡櫀槨{{娍崍昧jj緅ⅱ効剕妹|尷u櫄椓ed亮d陽搂紳暰h厖劶览湩縭wv櫫憫览戧柫帀苛|t續敂喞唡亮|娂r唸u糴f揪f钖灢矑嵀瓍j}搮柉皪嵃矅r墖q叒瑋|枒媺�|uoihfi倕{{}|{ruqqstcdddd霒拲墔|uoihfege{~z}|}rurvrfdddd驔晭墔|uoihjiedfjy~|z杣tssddddd馂潧墔|uoihhfgdgkns}{敂敇昮dddd饻洔湜||tnjjgfggfjosz{晿枙梒dddd饻洔潨ihwkkhggggfjosy{倓枠杅dddd饻洔湠hjjikihgggfjosx}亞姄榚dddd餃洔湝lkhhj俫gggfjnsx{剣崘敇dddd餃灇櫄hjlhh剠乬cfmntv{亝崘枦棙ce顫煘潩jikij唲剚乭kqtv|儓帓枠櫄櫄頋潨湞hjjig厒倕厇|pqw{亝墤槞湜湜镯铑瘃!#%$$彃搼抣nno^o啑奏滏腠痧痧��������拻拻oonnKCV|gkc]溏腩痧痧��������拻拻oooo;:あi悕犱珉铕痧饊�������拻拻oooo%3xs\楰|溏腩痧痧��������拻拻ooooO?9沘bN溏腩痧痧��������拻拻nnnnQL々墆�腩痧痧��������拻拻nnnnH3漛hZ�痧痧��������拻拻nnnn?9儃DRB痧痧��������拻拻nnnn57q弌F�痧痧痫#""##憭拻抩ooonn葺揶�痧痧痫#""##憭拻抩ooonn葺揶�痧痧痫#""##憭拻抩ooonn葺揶�痧痧痫#""##憭拻抩ooonn葺揶� \ No newline at end of file diff --git a/rs/moq-video/src/decode/test_data/vp9_profile1_16x16_1f.ivf b/rs/moq-video/src/decode/test_data/vp9_profile1_16x16_1f.ivf new file mode 100644 index 0000000000000000000000000000000000000000..a3180112e1ebd36ccae6848e4cc1bd2d14f33ab4 GIT binary patch literal 423 zcmV;Y0a*S-OG!om03ZNXP&qIV01yBk0000100001000000001c0RR91000000001@ zNrOTF03HAyzy}0_g9$(Y1Rwx>Xor9Q^ZX59IVC8-Zr}g0y3^Rd=;c9{AqJ0f=l}ol z`?Csx>28%c)Fu=T@24dvi9HUF|Nn0&MewMi2Uf>D4qE%_0DCpI`9lBbn6)Q={1LKa z{o-{5)xQX<`aLx=na0IT1`FyZE^)4=zb#YsaMYM#%J=rS|Nq04yISokiTz731l(EakM#Ua<43-KUJ`j=_W$^> zM=F{^4oW}XU|m%-CI9`9UFvIx;{8@IN+z62`X>HyLHMM8HfuivXZ0`s=)Qi*er7-@ zRUh^aCj~dI+Jh?{FYs3*0dI;a9?=?o|NY_pKX>En^BV2V-Hs`4)P`wG>)H0!N7_Fp RkBg3t@GP*0(J_fLcK{3(#;^bY literal 0 HcmV?d00001 diff --git a/rs/scripts/media-features.sh b/rs/scripts/media-features.sh index 5264da2655..8887fc691a 100755 --- a/rs/scripts/media-features.sh +++ b/rs/scripts/media-features.sh @@ -52,6 +52,17 @@ for crate in openh264 openh264-sys2 wgpu; do forbid_crate "$native" "$crate" "moq-video native-only" done +# libvpx comes from the build host (the Nix dev shell here), so the default +# check never compiles this backend. Its tests decode committed fixtures and +# need no hardware, so they run here rather than waiting for the nightly. +check -p moq-video --no-default-features --features vpx +vpx=$(tree -p moq-video --no-default-features --features vpx) +require_crate "$vpx" libvpx-native-sys "moq-video VP8/VP9" +for crate in openh264 openh264-sys2 wgpu; do + forbid_crate "$vpx" "$crate" "moq-video VP8/VP9" +done +cargo nextest run --locked -p moq-video --no-default-features --features vpx -E 'test(/::vpx::/)' + check -p moq-video --no-default-features --features render render=$(tree -p moq-video --no-default-features --features render) require_crate "$render" wgpu "moq-video rendering" From 3424ebad8d64f0dfc6f21548bee5f3c000abc5c6 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 24 Sep 2026 20:35:18 -0700 Subject: [PATCH 3/5] style: rustfmt the vpx backend Co-Authored-By: Claude Opus 5.5 --- rs/moq-video/src/decode/backend/vpx.rs | 37 ++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/rs/moq-video/src/decode/backend/vpx.rs b/rs/moq-video/src/decode/backend/vpx.rs index 5c93b2badf..1a016435b7 100644 --- a/rs/moq-video/src/decode/backend/vpx.rs +++ b/rs/moq-video/src/decode/backend/vpx.rs @@ -100,7 +100,12 @@ impl Vpx { self.broken = true; self.lost += 1; if self.lost == 1 { - tracing::warn!(decoder = NAME, codec = self.codec.label(), reason, "picture lost, waiting for the next keyframe"); + tracing::warn!( + decoder = NAME, + codec = self.codec.label(), + reason, + "picture lost, waiting for the next keyframe" + ); } else { tracing::trace!(decoder = NAME, reason, "picture lost"); } @@ -384,7 +389,13 @@ mod tests { .unwrap_or_else(|e| panic!("{} frame {index} ended the stream: {e}", vector.name)); out.extend(pictures.into_iter().map(|picture| (index, picture))); } - out.extend(decoder.flush().unwrap().into_iter().map(|picture| (usize::MAX, picture))); + out.extend( + decoder + .flush() + .unwrap() + .into_iter() + .map(|picture| (usize::MAX, picture)), + ); out } @@ -392,13 +403,23 @@ mod tests { let Surface::I420(i420) = &frame.surface else { panic!("{} produced a non-I420 surface", vector.name); }; - assert_eq!((i420.width, i420.height), (vector.width, vector.height), "{}", vector.name); + assert_eq!( + (i420.width, i420.height), + (vector.width, vector.height), + "{}", + vector.name + ); assert!( i420.data == reference(vector, index), "{} picture {index} differs from the reference decode", vector.name ); - assert_eq!(frame.timestamp, at(index), "{} picture {index} mis-stamped", vector.name); + assert_eq!( + frame.timestamp, + at(index), + "{} picture {index} mis-stamped", + vector.name + ); } #[test] @@ -539,7 +560,13 @@ mod tests { // Join after the first keyframe: frames 1..3 are deltas, 4 a keyframe. for (index, frame) in frames(VP9_64.ivf).into_iter().enumerate().skip(1) { let key = keyframe(Codec::Vp9, &frame); - decoded.extend(decoder.decode(&frame, at(index), key).unwrap().into_iter().map(|f| (index, f))); + decoded.extend( + decoder + .decode(&frame, at(index), key) + .unwrap() + .into_iter() + .map(|f| (index, f)), + ); } assert_eq!(decoded.len(), 1, "a delta frame was decoded before the keyframe"); let (index, frame) = &decoded[0]; From 77f4080ce1e397638e3f5c92dfea5f674cb6b329 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 24 Sep 2026 23:49:23 -0700 Subject: [PATCH 4/5] fix(cli): let `play` select VP8/VP9 when built with vpx Co-Authored-By: Claude Opus 5.5 --- rs/moq-cli/src/args.rs | 8 ++++++-- rs/moq-cli/src/play/args.rs | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/rs/moq-cli/src/args.rs b/rs/moq-cli/src/args.rs index 2e5cff514d..4d4cbcfd6c 100644 --- a/rs/moq-cli/src/args.rs +++ b/rs/moq-cli/src/args.rs @@ -1767,8 +1767,12 @@ mod tests { let Command::Play(play) = &cli.stages[0] else { panic!("expected play") }; - let err = play.validate().unwrap_err().to_string(); - assert!(err.contains(codec), "{err}"); + if cfg!(feature = "vpx") { + play.validate().unwrap(); + } else { + let err = play.validate().unwrap_err().to_string(); + assert!(err.contains(codec), "{err}"); + } } let cli = Invocation::try_parse_from([ diff --git a/rs/moq-cli/src/play/args.rs b/rs/moq-cli/src/play/args.rs index b4094a2246..39d43144ff 100644 --- a/rs/moq-cli/src/play/args.rs +++ b/rs/moq-cli/src/play/args.rs @@ -54,8 +54,8 @@ impl Args { use crate::subscribe::VideoCodecArg; anyhow::ensure!( - !matches!(self.select.video_codec, Some(VideoCodecArg::Vp8 | VideoCodecArg::Vp9)), - "`play` cannot decode vp8 or vp9; pass --video-codec h264, h265, or av1" + cfg!(feature = "vpx") || !matches!(self.select.video_codec, Some(VideoCodecArg::Vp8 | VideoCodecArg::Vp9)), + "`play` was built without the `vpx` feature, so it cannot decode vp8 or vp9; pass --video-codec h264, h265, or av1" ); // The delay is the speaker's ring depth, so a value it cannot hold is // refused here rather than after the pipeline has opened a device. @@ -90,9 +90,16 @@ mod tests { parse(&["--video-codec", "h264"]).validate().unwrap(); parse(&["--video-codec", "av1"]).validate().unwrap(); - let err = parse(&["--video-codec", "vp9"]).validate().unwrap_err().to_string(); - assert!(err.contains("vp8 or vp9"), "{err}"); - assert!(parse(&["--video-codec", "vp8"]).validate().is_err()); + // VP8 and VP9 decode only through the opt-in libvpx backend. + for codec in ["vp8", "vp9"] { + let result = parse(&["--video-codec", codec]).validate(); + if cfg!(feature = "vpx") { + result.unwrap(); + } else { + let err = result.unwrap_err().to_string(); + assert!(err.contains("vp8 or vp9"), "{err}"); + } + } } /// The delay is the playout offset and the staleness budget at once, so its From 8b049acfc9dfe840028786df55155f269ef6a0c0 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 25 Sep 2026 06:32:53 -0700 Subject: [PATCH 5/5] fix(video): treat an unparseable VP8/VP9 bitstream as fatal Co-Authored-By: Claude Opus 5.5 --- rs/moq-video/src/decode/backend/vpx.rs | 30 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/rs/moq-video/src/decode/backend/vpx.rs b/rs/moq-video/src/decode/backend/vpx.rs index 1a016435b7..03f683c945 100644 --- a/rs/moq-video/src/decode/backend/vpx.rs +++ b/rs/moq-video/src/decode/backend/vpx.rs @@ -125,13 +125,11 @@ fn describe(err: vpx_codec_err_t, detail: Option) -> String { /// Whether `err` describes the frame rather than the decoder. /// /// A truncated or damaged frame is ordinary on a lossy path, and libvpx stays -/// usable after it: the next keyframe restores the picture. Anything else (out -/// of memory, a bad argument) says the decoder itself is in trouble. +/// usable after it: the next keyframe restores the picture. Anything else says +/// the stream or the decoder is in trouble, including `UNSUP_BITSTREAM`, which +/// libvpx documents as a stream it cannot parse at all and so cannot proceed on. fn describes_frame(err: vpx_codec_err_t) -> bool { - matches!( - err, - vpx_codec_err_t::VPX_CODEC_CORRUPT_FRAME | vpx_codec_err_t::VPX_CODEC_UNSUP_BITSTREAM - ) + err == vpx_codec_err_t::VPX_CODEC_CORRUPT_FRAME } /// The color space libvpx reports for a picture, when [`Color`] can name it. @@ -485,6 +483,26 @@ mod tests { } } + /// A frame libvpx cannot parse at all ends the stream, rather than blanking + /// the picture while each later keyframe fails the same way. + #[test] + fn an_unparseable_frame_is_fatal() { + for vector in [&VP8_64, &VP9_64] { + let mut frame = frames(vector.ivf)[0].to_vec(); + match vector.codec { + // The keyframe start code (RFC 6386 section 9.1). + Codec::Vp8 => frame[3] = 0, + // The two-bit frame marker (VP9 section 6.2). + _ => frame[0] = 0, + } + match open(vector.codec).decode(Bytes::from(frame), at(0), true) { + Err(Error::Codec(_)) => {} + Err(other) => panic!("{}: expected Codec, got {other:?}", vector.name), + Ok(frames) => panic!("{}: decoded {} pictures", vector.name, frames.len()), + } + } + } + /// A decoder that has been flushed takes a new stream from its keyframe. #[test] fn a_flushed_decoder_takes_another_stream() {