All checks were successful
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 24s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 52s
wai-app and Create / wai-app · does this change touch it (push) Successful in 55s
wai-quantum for JavaScript / does this change touch it (push) Successful in 46s
wai-ledger service / does this change touch it (push) Successful in 50s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 1m10s
wai-quantum studio and desktop / does this change touch it (push) Successful in 39s
wai-audit collector and player integration / does this change touch it (push) Successful in 57s
wai-key-proxy / does this change touch it (push) Successful in 1m7s
wai-fleet service / does this change touch it (push) Successful in 1m8s
WAI operation catalogue / does this change touch it (push) Successful in 1m12s
wai-sink-android native sink library / does this change touch it (push) Successful in 53s
WAI Studio / does this change touch it (push) Successful in 36s
wai-sink-swift native sink package / does this change touch it (push) Successful in 41s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 1m51s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 5m36s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 4m36s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 7m38s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 12s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 12s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 42s
wai-key-proxy / proxy · linux (push) Successful in 1m35s
wai-quantum for JavaScript / javascript · linux (push) Successful in 3m45s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m4s
wai-ledger service / service · linux (push) Successful in 3m59s
wai-audit collector and player integration / collector · linux (push) Successful in 4m35s
wai-fleet service / service · linux (push) Successful in 4m8s
wai-quantum studio and desktop / studio · browser (push) Successful in 5m24s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 7m52s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 8m49s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 12m32s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 1m37s
WAI Studio / Studio in WebKit · linux (push) Successful in 25m52s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m18s
wai-ledger service / service · macos (push) Successful in 2m15s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 3m33s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 6m30s
wai-fleet service / service · macos (push) Successful in 53s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 12m55s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 6m23s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 9m55s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 10m3s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m32s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 5m23s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 13m6s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 8m17s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 22m28s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 19m30s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 6m17s
http-delivery §11.7 and Appendix B had sample entries and no implementation. Now: - wai-pack's modef writes a sequence of envelopes as one fragmented MP4 track in the structure of a CMAF track: a header whose wai1 or wai2 sample entry holds the track's waiC (the union and floor of §4.2, the highest MINOR), one media segment a piece, each sample one envelope byte for byte and a sync sample, a track file with its sidx, and an HLS media playlist naming the header by EXT-X-MAP, a piece with no object a gap. - wai-rs's http_binding::modef describes a track of given envelopes and reads a header and its segments, or a track file, back to each envelope with its cid, every rule of Appendix B checked in its order with the reasons §13 now lists (modef_*). - Appendix B gains the handler by media class, what waiC holds, the fragments, no encryption, the track file and the reader's order. A layer object is not a sample; a track carries the bases. The 4CCs stay unregistered and Mode F stays test material. - §11.8: the session-data line and Mode F checked clause by clause against CTA-5005-B (January 2025), and the result written down. - pack-conformance/modef/: five tracks, two track files, media playlists, a test multivariant playlist, and planted faults each refused with its reason; replayed by wai-pack modef check (every file again byte for byte), wai-rs tests/http_modef.rs, and modef_verify.py, a second implementation with its own box reader. modef_probe.py opens every track with a media prober. Every golden track and every object of the packaging and HTTP corpora round trip through Mode F to the same envelopes and cids. - CI: a verifier step for wai-conformance (the reader's test, modef_verify.py among the independent verifiers); in wai-pack.yml the corpus check, modef_verify.py --self-test, and the tracks through ffprobe in the media job. Co-Authored-By: Claude Opus 5.5 <[email protected]>
462 lines
24 KiB
YAML
462 lines
24 KiB
YAML
name: wai-pack
|
|
|
|
# The reference packager of WAI's packaging extension (wai/extensions/packaging.md) and
|
|
# its conformance corpus (wai/pack-conformance). Four jobs:
|
|
#
|
|
# - legs: on each architecture of the fleet, clippy with float arithmetic denied (no
|
|
# float decides anything in a package), the tests in release with a floor on how many
|
|
# each target lists, and the corpus recomputed by the crate: the golden packages
|
|
# packed again byte for byte and verified, every mutation's reason. On the macOS leg,
|
|
# whose host has a GPU, the steps a GPU runs (packaging §11.6): wai-pack-gpu's kernels
|
|
# held to integer types on naga's IR (no adapter needed; the crate is built there), its
|
|
# kernels against their references and every edited kernel caught, and wai-pack's fabric
|
|
# differential (every golden packed on the GPU byte for byte, every verdict the CPU's),
|
|
# an absent adapter a failure there (WAI_PACK_GPU_REQUIRE), never a skip.
|
|
# - independent: the corpus recomputed by its second implementation, written in Python
|
|
# from the extension text and sharing no code with wai-pack, the golden packages
|
|
# verified and re-derived from their sources among it (every refinement layer and
|
|
# still byte for byte, every delivery case through the staged-measurement simulator's
|
|
# Python twin); and the differentials: source readers, policies, scene cuts, the
|
|
# staged packer (layers, stills, piece plans, deliveries), and a still's reader.
|
|
# - media: the golden's floor, its CMAF initialization segment and fragments, read and
|
|
# decoded by a media prober (test 14); and Mode F's tracks (pack-conformance/modef/), each
|
|
# opened by the prober, every packet its sample's envelope byte for byte.
|
|
# - licences: every crate in wai-pack's dependency graph is under a licence deny.toml
|
|
# allows; a source-available licence fails it.
|
|
#
|
|
# Push filters match the push's delta, so every path a build or a verifier reads is
|
|
# listed: the crate, the wai crate it builds on, the corpus, the BLAKE3, integer payload,
|
|
# staged-delivery and staged-measurement verifiers, the claim verifier (a metered
|
|
# package's claim) and the OER verifier it imports, the registry export pack_verify.py
|
|
# reads, and this file.
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- 'wai/wai-pack/**'
|
|
- 'wai/wai-pack-gpu/**'
|
|
- 'wai/wai-rs/**'
|
|
- 'wai/pack-conformance/**'
|
|
# tests/encode_rung.rs checks the encoded renditions of the base golden.
|
|
- 'wai/encode-conformance/rendition/**'
|
|
- 'wai/claim-conformance/_blake3.py'
|
|
- 'wai/claim-conformance/_ed25519.py'
|
|
- 'wai/claim-conformance/claim_verify.py'
|
|
- 'wai/oer-conformance/oer2_verify.py'
|
|
- 'wai/int-payload-conformance/int_payload_verify.py'
|
|
- 'wai/staged-conformance/staged_verify.py'
|
|
- 'wai/staged-measure-conformance/sim_verify.py'
|
|
- 'wai/staged-measure-conformance/measure_verify.py'
|
|
- 'wai/http-conformance/http_verify.py'
|
|
# Mode F (src/modef.rs, tests/modef.rs): the corpus writes O9's sequence and O11bL1,
|
|
# and every object of the HTTP corpus round trips.
|
|
- 'wai/http-conformance/objects/**'
|
|
- 'wai/http-conformance/playlists/o9/**'
|
|
# The components beside the lead (src/multi.rs): the vector raster, and the
|
|
# independent renderer multi_verify.py reads.
|
|
- 'wai/wai-vector/**'
|
|
- 'wai/tools/wai_vector_check.py'
|
|
# The composing sink's reference package, packed again by the corpus check, and the
|
|
# inputs it reads from other corpora.
|
|
- 'wai/wai-web/compose/**'
|
|
- 'wai/vector-conformance/vectors/motion/stroke-titles.wvg1'
|
|
- 'wai/score-conformance/vectors/scale48.wscr'
|
|
- '.github/workflows/wai-pack.yml'
|
|
schedule:
|
|
- cron: '38 6 * * *'
|
|
jobs:
|
|
# Forgejo matches the `paths:` filters above against the **push delta**, not
|
|
# the pull request's diff. A rebase moves a branch across every commit main
|
|
# has gained, so its delta touches nearly every path and this workflow fires
|
|
# on changes that cannot affect it. Measured on this repo: a jcp-only change
|
|
# pushed to a fresh branch ran 2 workflows; the same change force-pushed after
|
|
# a rebase ran 15, this one among them, putting three platforms of wai-pack and
|
|
# the JPEG-AI whole decode in a queue they had no business being in.
|
|
#
|
|
# So the filters above still gate the *trigger*, and this job gates the
|
|
# *work*, from the pull request's own diff. It reads the path list out of this
|
|
# file, so there is one list and not a third copy to drift. On a push to main
|
|
# there is no pull-request context, the shas are empty, and the gate answers
|
|
# `true` — a push to main runs everything, as before.
|
|
relevant:
|
|
name: wai-pack · does this change touch it
|
|
runs-on: gate
|
|
outputs:
|
|
run: ${{ steps.gate.outputs.run }}
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
fetch-depth: 0
|
|
- id: gate
|
|
run: |
|
|
set -euo pipefail
|
|
r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-pack.yml \
|
|
"${{ github.event.pull_request.base.sha }}" \
|
|
"${{ github.event.pull_request.head.sha }}")
|
|
echo "this change touches wai-pack: $r"
|
|
echo "run=$r" >> "$GITHUB_OUTPUT"
|
|
|
|
legs:
|
|
name: wai-pack · ${{ matrix.os }}
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# Self-hosted fleet labels: x86_64 by linux, arm64 by linux-arm64 and macos.
|
|
# A Windows leg waits for its runner (see wai-byte-equality.yml).
|
|
os: [linux, linux-arm64, macos]
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
# The docker runners ship no Rust, so rustup is bootstrapped; the macOS host has
|
|
# it, but launchd's PATH omits ~/.cargo/bin.
|
|
- name: Install Rust 1.99.1
|
|
shell: bash
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
command -v rustup >/dev/null 2>&1 || \
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1
|
|
rustup toolchain install 1.99.1 --profile minimal
|
|
rustup default 1.99.1
|
|
rustup component add --toolchain 1.99.1 clippy
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
|
|
# clippy::float_arithmetic is denied for the library and the CLI (Cargo.toml and
|
|
# the crate attributes); -D warnings makes every other lint fail the step too.
|
|
- name: clippy, float arithmetic denied
|
|
working-directory: wai/wai-pack
|
|
run: cargo clippy --locked --all-targets -- -D warnings
|
|
|
|
- name: Tests (release)
|
|
working-directory: wai/wai-pack
|
|
run: cargo test --release --locked
|
|
|
|
# A target that lost its tests (a module dropped, a cfg that compiles them out)
|
|
# would still report ok. Each target must list at least as many tests as it had
|
|
# when the floor was set; raise a floor when tests are added.
|
|
- name: Test-count floor per target
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: |
|
|
set -euo pipefail
|
|
fail=0
|
|
while read -r target floor; do
|
|
n=$(cargo test --release --locked $target -- --list 2>/dev/null | grep -c ': test$' || true)
|
|
echo "$target: $n tests (floor $floor)"
|
|
[ "$n" -ge "$floor" ] || { echo "::error::$target lists $n tests, under its floor of $floor"; fail=1; }
|
|
done <<'EOF'
|
|
--lib 39
|
|
--test=cmaf 4
|
|
--test=conformance 1
|
|
--test=encode_rung 3
|
|
--test=fabric 3
|
|
--test=floor_only 2
|
|
--test=ladder 3
|
|
--test=modef 4
|
|
--test=multi 17
|
|
--test=pack_alloc 1
|
|
--test=packs 9
|
|
--test=review 9
|
|
--test=refusals 6
|
|
--test=repack 3
|
|
--test=scenecut 3
|
|
--test=source_alloc 1
|
|
--test=staged 10
|
|
EOF
|
|
exit $fail
|
|
|
|
- name: The corpus, recomputed by wai-pack
|
|
working-directory: wai/wai-pack
|
|
run: cargo run --release --locked --bin wai-pack -- conformance check ../pack-conformance
|
|
|
|
# Mode F's corpus (http-delivery §11.7, Appendix B): every file written again byte for
|
|
# byte, and every case through wai-rs's reader (tests/modef.rs runs the same check).
|
|
- name: Mode F's corpus, recomputed by wai-pack
|
|
working-directory: wai/wai-pack
|
|
run: cargo run --release --locked --bin wai-pack -- modef check ../pack-conformance/modef
|
|
|
|
# The catalogue's package.build and package.verify (wai-rs/src/bin/wai_cli/package.rs)
|
|
# run this packer as itself: a dry run of `wai package build` writes nothing; a real one
|
|
# writes the golden package of video-base-01 byte for byte; `wai package verify` accepts
|
|
# it and exits 1 on a copy whose receipt was edited.
|
|
- name: The catalogue's package doors run this packer
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
(cd wai/wai-pack && cargo build --release --locked --bin wai-pack)
|
|
(cd wai/wai-rs && cargo build --locked --no-default-features --bin wai)
|
|
P="$PWD/wai/wai-pack/target/release/wai-pack"; W="$PWD/wai/wai-rs/target/debug/wai"
|
|
G=wai/pack-conformance/packs/video-base-01; D=$(mktemp -d)
|
|
cp -r "$G/policy.toml" "$G/floor" "$G/key.hex" "$D/"
|
|
"$P" fixture gen video-base-01 -o "$D/video-base-01.y4m"
|
|
"$W" package build --dry-run --packer "$P" --policy "$D/policy.toml" --out "$D/out" --key "$D/key.hex"
|
|
test ! -e "$D/out"
|
|
"$W" package build --packer "$P" --policy "$D/policy.toml" --out "$D/out" --key "$D/key.hex"
|
|
diff -r "$D/out" "$G/package"
|
|
"$W" package verify --packer "$P" "$D/out"
|
|
cp -r "$D/out" "$D/edited"
|
|
sed -i.bak 's/"total_entries":[0-9]*/"total_entries":1/' "$D/edited/package.receipt.json" && rm "$D/edited/package.receipt.json.bak"
|
|
set +e; "$W" package verify --packer "$P" "$D/edited"; code=$?; set -e
|
|
[ "$code" = 1 ] || { echo "::error::an edited package's verify exited $code, not 1"; exit 1; }
|
|
|
|
# The steps a GPU runs (packaging §11.6), on the one leg whose host has a GPU. Each
|
|
# test prints the adapter it ran on; the step requires those lines, so a run that
|
|
# found no adapter, or filtered the tests away, fails. tests/integer_only.rs needs no
|
|
# adapter: it holds each kernel to integer types on naga's IR (packaging §11.6 item 1)
|
|
# and shows six planted violations refused, and the step requires its lines too.
|
|
- name: wai-pack-gpu, clippy, its kernels on naga's IR and against their references (Metal)
|
|
if: matrix.os == 'macos'
|
|
shell: bash
|
|
working-directory: wai/wai-pack-gpu
|
|
env:
|
|
WAI_PACK_GPU_REQUIRE: '1'
|
|
run: |
|
|
set -euo pipefail
|
|
cargo clippy --locked --all-targets -- -D warnings
|
|
cargo test --release --locked -- --nocapture 2>&1 | tee "$RUNNER_TEMP/gpu.txt"
|
|
grep -q 'motion search, 54 frames, every vector the text' "$RUNNER_TEMP/gpu.txt"
|
|
grep -q 'every hash the reference crate' "$RUNNER_TEMP/gpu.txt"
|
|
[ "$(grep -c '^caught: ' "$RUNNER_TEMP/gpu.txt")" -ge 12 ]
|
|
[ "$(grep -c '^pack-gpu integer rule: [a-z0-9]*: rules 1-2 hold$' "$RUNNER_TEMP/gpu.txt")" -eq 3 ]
|
|
[ "$(grep -c '^pack-gpu integer rule: planted .*: refused: ' "$RUNNER_TEMP/gpu.txt")" -eq 6 ]
|
|
- name: wai-pack's fabric differential on the GPU (Metal)
|
|
if: matrix.os == 'macos'
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
env:
|
|
WAI_PACK_GPU_REQUIRE: '1'
|
|
run: |
|
|
set -euo pipefail
|
|
cargo clippy --locked --all-targets --features gpu,fabric-meter -- -D warnings
|
|
cargo test --release --locked --features gpu --test fabric -- --nocapture 2>&1 | tee "$RUNNER_TEMP/fabric.txt"
|
|
grep -q 'the search on the GPU: ' "$RUNNER_TEMP/fabric.txt"
|
|
grep -q 'verdicts, each the CPU' "$RUNNER_TEMP/fabric.txt"
|
|
grep -q 'test result: ok. 7 passed' "$RUNNER_TEMP/fabric.txt"
|
|
|
|
independent:
|
|
name: wai-pack · independent verifier (Python)
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: linux-arm64
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
# The standard library (tomllib, hashlib); BLAKE3 from the shared pure-Python module
|
|
# beside the claim corpus; the package receipts' Ed25519 equation from the
|
|
# `cryptography` package, pinned with its dependencies by SHA-256 so pip installs only
|
|
# the files the requirements name.
|
|
- name: Install the Ed25519 library (hashes required)
|
|
shell: bash
|
|
working-directory: wai
|
|
run: python -m pip install --require-hashes -r pack-conformance/requirements-verify.txt
|
|
- name: pack_verify.py
|
|
working-directory: wai
|
|
shell: bash
|
|
run: python3 pack-conformance/pack_verify.py pack-conformance
|
|
# The same checks with the hashes and decodes run ahead in worker processes
|
|
# (--jobs): every check and its reason are the serial run's.
|
|
- name: pack_verify.py --jobs 2
|
|
working-directory: wai
|
|
shell: bash
|
|
run: python3 pack-conformance/pack_verify.py --jobs 2 pack-conformance
|
|
# The packages of several components: each component's pieces, digests and
|
|
# objects recomputed from its sources, and a planted fault in each found.
|
|
- name: multi_verify.py
|
|
working-directory: wai
|
|
shell: bash
|
|
run: python3 -I pack-conformance/multi_verify.py pack-conformance
|
|
# Mode F's tracks by their second implementation, with its own box reader: every case,
|
|
# every track as its writer must have made it, and each of its checks dropped in turn
|
|
# failing a case.
|
|
- name: modef_verify.py
|
|
working-directory: wai
|
|
shell: bash
|
|
run: python3 -I pack-conformance/modef_verify.py --self-test pack-conformance/modef
|
|
- name: Install Rust 1.99.1
|
|
shell: bash
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
command -v rustup >/dev/null 2>&1 || \
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1
|
|
rustup toolchain install 1.99.1 --profile minimal
|
|
rustup default 1.99.1
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
# The source readers differentially: seeded Y4M and WAV mutations, every verdict of
|
|
# wai-pack (debug and release, both with overflow checks) equal to pack_verify.py's,
|
|
# and no reader panicking.
|
|
- name: source_diff.py, wai-pack against pack_verify.py
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: |
|
|
set -euo pipefail
|
|
cargo build --locked --bin wai-pack
|
|
cargo build --release --locked --bin wai-pack
|
|
for profile in debug release; do
|
|
python3 ../pack-conformance/source_diff.py "target/$profile/wai-pack" 1 3000
|
|
done
|
|
# The policy reader differentially: byte-level cases and seeded random policies,
|
|
# every verdict and digest of wai-pack equal to pack_verify.py's.
|
|
- name: policy_diff.py, wai-pack against pack_verify.py
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: python3 ../pack-conformance/policy_diff.py target/release/wai-pack 1 3000
|
|
# wai.pack.scenecut/1 differentially: the streaming segmenter against
|
|
# pack_verify.py's on-demand form on seeded random clips.
|
|
- name: segment_diff.py, wai-pack against pack_verify.py
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: python3 ../pack-conformance/segment_diff.py target/release/wai-pack 1 2000
|
|
# The staged packer differentially: refinement layers, stills, piece plans and
|
|
# deliveries on seeded random inputs, every result of wai-pack equal to
|
|
# pack_verify.py's (debug and release, both with overflow checks).
|
|
- name: stage_diff.py, wai-pack against pack_verify.py
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: |
|
|
set -euo pipefail
|
|
python3 ../pack-conformance/stage_diff.py target/debug/wai-pack 1 1000
|
|
python3 ../pack-conformance/stage_diff.py target/release/wai-pack 2 3000
|
|
# The supplied CMAF reader differentially (packaging §7.7): seeded alterations of a
|
|
# media muxer's segments and of §7.6's writer's, every verdict and accepted segment's
|
|
# samples of wai-pack's reader equal to pack_verify.py's.
|
|
- name: cmaf_diff.py, wai-pack against pack_verify.py
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: python3 ../pack-conformance/cmaf_diff.py target/release/wai-pack 1 3000
|
|
# A still's reader differentially: the zlib library's own streams, dynamic blocks
|
|
# built on each of RFC 1951's and zlib's code-set rules, and their alterations, every
|
|
# verdict of wai-pack's reader equal to pack_verify.py's, which inflates with
|
|
# Python's zlib (debug and release).
|
|
- name: png_diff.py, wai-pack against pack_verify.py
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: |
|
|
set -euo pipefail
|
|
python3 ../pack-conformance/png_diff.py target/debug/wai-pack 1 2000
|
|
python3 ../pack-conformance/png_diff.py target/release/wai-pack 2 4000
|
|
|
|
media:
|
|
name: wai-pack · the floor through a media prober
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: linux-arm64
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
- name: Install a media prober
|
|
shell: bash
|
|
run: |
|
|
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
|
|
$SUDO apt-get update -qq
|
|
$SUDO apt-get install -y -qq ffmpeg python3
|
|
# Test 14: each golden floor's init.mp4 and its fragments, in its floor playlist's
|
|
# order, read as one AV1 track of every frame of the source, with a key frame at each
|
|
# piece start of the plan and nowhere else, and decode without an error; a ladder
|
|
# golden has one floor playlist per floor rung (packaging §7.1), each read so.
|
|
- name: The goldens' floors read and decode
|
|
shell: bash
|
|
working-directory: wai/pack-conformance/packs
|
|
run: |
|
|
set -euo pipefail
|
|
for g in video-base-01 video-staged-01 video-ladder-01 video-cmaf-01 video-floor-only-02; do
|
|
( cd "$g/package"
|
|
for pl in hls/classic/floor-*.m3u8; do
|
|
f=$(basename "$pl" .m3u8); f=${f#floor-}
|
|
tmp=$(mktemp -d)
|
|
cat "floor/$f/init.mp4" $(grep -v '^#' "$pl" | sed 's#^\.\./\.\./##') > "$tmp/floor.mp4"
|
|
ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=codec_name,width,height,nb_read_frames -of default=nw=1 "$tmp/floor.mp4" | tee "$tmp/probe.txt"
|
|
grep -qx 'codec_name=av1' "$tmp/probe.txt"
|
|
grep -qx 'nb_read_frames=200' "$tmp/probe.txt"
|
|
# A sample's pts is in the track's timescale, not in frames: the packager's
|
|
# own floors tick once per frame, a muxer's CMAF floor (video-cmaf-01) 48000
|
|
# times. The sample spacing is the second sample's pts less the first's (some
|
|
# ffprobe versions report no duration for the first fMP4 sample), every sample
|
|
# must sit on that grid, and a duration ffprobe does report must equal it: a gap,
|
|
# an uneven duration or a sample out of order is refused here rather than read
|
|
# as a moved key frame. A key frame's index is its place on the grid.
|
|
keys=$(ffprobe -v error -select_streams v:0 -show_entries packet=pts,duration,flags -of compact=p=0 "$tmp/floor.mp4" \
|
|
| awk -F'|' -v what="$g $f" '
|
|
{ delete v; for (i = 1; i <= NF; i++) { j = index($i, "="); v[substr($i, 1, j - 1)] = substr($i, j + 1) }
|
|
if (v["pts"] !~ /^-?[0-9]+$/) { printf "::error::%s: sample %d has no pts (%s)\n", what, NR - 1, v["pts"] > "/dev/stderr"; bad = 1; exit 1 }
|
|
pts[NR - 1] = v["pts"]; dur[NR - 1] = v["duration"]; key[NR - 1] = (v["flags"] ~ /K/) }
|
|
END { if (bad) exit 1
|
|
n = NR
|
|
if (n < 2) { printf "::error::%s: fewer than two samples\n", what > "/dev/stderr"; exit 1 }
|
|
p0 = pts[0]; d = pts[1] - p0
|
|
if (d <= 0) { printf "::error::%s: the second sample is not after the first (%s, %s)\n", what, p0, pts[1] > "/dev/stderr"; exit 1 }
|
|
for (i = 0; i < n; i++) {
|
|
if (pts[i] - p0 != i * d) { printf "::error::%s: sample %d is at pts %s, not %d samples of %d ticks after %s\n", what, i, pts[i], i, d, p0 > "/dev/stderr"; exit 1 }
|
|
if (dur[i] ~ /^[0-9]+$/ && dur[i] != d) { printf "::error::%s: sample %d lasts %s ticks, not %d\n", what, i, dur[i], d > "/dev/stderr"; exit 1 }
|
|
if (key[i]) printf "%d ", i
|
|
} }')
|
|
want=$(tr '\n' ' ' < plan-v.txt)
|
|
echo "$g $f key frames: $keys"
|
|
[ "$keys" = "$want" ] || { echo "::error::$g $f: key frames at $keys; the plan says $want"; exit 1; }
|
|
ffmpeg -v error -xerror -i "$tmp/floor.mp4" -f null -
|
|
echo "$g $f: the floor reads as one AV1 track of 200 frames, a key frame at each piece start"
|
|
done )
|
|
done
|
|
# Mode F (http-delivery §11.7, Appendix B): every track of pack-conformance/modef/ and
|
|
# its track files opened by ffprobe as one stream of the entry's codec tag (wai1, wai2)
|
|
# and the handler's type, one packet a sample at its decode time, a key frame, each
|
|
# packet's bytes the sample's envelope; and the test multivariant playlist opening as
|
|
# the classical AV1 variant beside the Mode F one.
|
|
- name: Mode F's tracks through ffprobe
|
|
shell: bash
|
|
run: python3 wai/pack-conformance/modef_probe.py "$(command -v ffprobe)" wai/pack-conformance/modef
|
|
|
|
licences:
|
|
name: wai-pack · dependency licences
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: linux-arm64
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
- name: Install Rust 1.99.1
|
|
shell: bash
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
command -v rustup >/dev/null 2>&1 || \
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1
|
|
rustup toolchain install 1.99.1 --profile minimal
|
|
rustup default 1.99.1
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
- name: Install cargo-deny
|
|
shell: bash
|
|
run: cargo install --locked cargo-deny --version 0.19.8
|
|
- name: cargo deny check licenses
|
|
working-directory: wai/wai-pack
|
|
run: cargo deny --locked check licenses
|
|
# deny.toml's MPL-2.0 exception covers cbindgen as wai's build-time tool: it must
|
|
# reach wai-pack through no normal (linked) edge. The second query sees the build
|
|
# edge, so an empty answer from the first is an answer.
|
|
- name: cbindgen is a build dependency only
|
|
shell: bash
|
|
working-directory: wai/wai-pack
|
|
run: |
|
|
set -euo pipefail
|
|
err=$(mktemp)
|
|
if ! linked=$(cargo tree --locked -e normal --target all -i cbindgen 2>"$err"); then
|
|
grep -q "did not match any packages" "$err" || { cat "$err"; exit 1; }
|
|
linked=""
|
|
fi
|
|
if [ -n "$linked" ]; then
|
|
echo "::error::cbindgen is a linked dependency of wai-pack; its MPL-2.0 exception covers a build tool only"
|
|
echo "$linked"
|
|
exit 1
|
|
fi
|
|
cargo tree --locked -e normal,build --target all -i cbindgen | grep -q '^cbindgen v' || { echo "::error::cbindgen not found as wai's build dependency"; exit 1; }
|
|
echo "cbindgen is a build dependency only"
|
|
# The `wai` binary's HTTP commands with their TLS client (the cli_tls feature:
|
|
# rustls and the operating system's trust store), under wai-rs's own deny.toml: the
|
|
# same allow-list, over the binary's features on the hosts it is built for.
|
|
- name: cargo deny check licenses (the wai binary's TLS client)
|
|
working-directory: wai/wai-rs
|
|
run: cargo deny --locked check licenses
|