108 lines
2.3 KiB
Bash
Executable file
108 lines
2.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "${root}"
|
|
|
|
input=""
|
|
seconds="6"
|
|
chunk_ms="2000"
|
|
|
|
usage() {
|
|
cat >&2 <<'EOF'
|
|
usage:
|
|
scripts/determinism-cmaf.sh --input <TS_FILE_OR_URL> [--seconds N] [--chunk-ms MS]
|
|
|
|
what it does:
|
|
- runs the CMAF (HLS fMP4) encoder/segmenter twice with the deterministic x264 profile
|
|
- compares sha256 of init + segments to check byte-for-byte determinism
|
|
|
|
notes:
|
|
- requires `ffmpeg` on PATH
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--input)
|
|
input="${2:-}"
|
|
shift 2
|
|
;;
|
|
--seconds)
|
|
seconds="${2:-}"
|
|
shift 2
|
|
;;
|
|
--chunk-ms)
|
|
chunk_ms="${2:-}"
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "error: unknown arg: $1" >&2
|
|
usage
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "${input}" ]]; then
|
|
echo "error: --input is required" >&2
|
|
usage
|
|
exit 2
|
|
fi
|
|
|
|
tmp="$(mktemp -d)"
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
|
|
ts="$input"
|
|
if [[ "${input}" == http://* || "${input}" == https://* ]]; then
|
|
ts="$tmp/in.ts"
|
|
ffmpeg -hide_banner -loglevel error -nostdin -y \
|
|
-t "${seconds}" -i "${input}" -c copy -f mpegts "${ts}"
|
|
fi
|
|
|
|
seg_secs="$(python3 - <<PY
|
|
ms=int("${chunk_ms}")
|
|
print(f"{ms/1000:.3f}")
|
|
PY
|
|
)"
|
|
|
|
run_one() {
|
|
out="$1"
|
|
rm -rf "$out"
|
|
mkdir -p "$out"
|
|
(cd "$out" && ffmpeg -hide_banner -loglevel error -nostdin -y \
|
|
-i "pipe:0" \
|
|
-map 0:v:0 -map 0:a:0? -sn -dn -map_metadata -1 \
|
|
-c:v libx264 \
|
|
-c:a aac -b:a 128k -ac 2 -ar 48000 \
|
|
-pix_fmt yuv420p -g 60 -keyint_min 60 -sc_threshold 0 -bf 0 \
|
|
-threads 1 \
|
|
-fflags +bitexact -flags:v +bitexact -flags:a +bitexact \
|
|
-f hls \
|
|
-hls_time "${seg_secs}" \
|
|
-hls_list_size 0 \
|
|
-hls_segment_type fmp4 \
|
|
-hls_flags independent_segments \
|
|
-hls_fmp4_init_filename init.mp4 \
|
|
-hls_segment_filename segment_%06d.m4s \
|
|
index.m3u8 < "$ts")
|
|
}
|
|
|
|
run_one "$tmp/a"
|
|
run_one "$tmp/b"
|
|
|
|
(cd "$tmp/a" && shasum -a 256 init.mp4 segment_*.m4s | sort) > "$tmp/a.sha"
|
|
(cd "$tmp/b" && shasum -a 256 init.mp4 segment_*.m4s | sort) > "$tmp/b.sha"
|
|
|
|
if diff -u "$tmp/a.sha" "$tmp/b.sha" >/dev/null; then
|
|
echo "OK: deterministic (init + segments match)"
|
|
else
|
|
echo "DIFF: non-deterministic output"
|
|
diff -u "$tmp/a.sha" "$tmp/b.sha" || true
|
|
exit 1
|
|
fi
|
|
|