media: H.264 fallback beside every AV1, and the post links the H.264
All checks were successful
Deploy / build-deploy (push) Successful in 7m30s
All checks were successful
Deploy / build-deploy (push) Successful in 7m30s
The AV1-only publish lasted four hours in the wild: the first viewer on
mobile Safari got "bad media error" from the raw file, because a post's
link is fetched raw — Lemmy apps and browsers play that exact URL, with
no <source> negotiation in front of it. The previous commit's note
("--raw ... if that audience matters") had it backwards: the audience
that cannot play AV1 is not a per-post judgement call, it is whoever
happens to open the thread on an iPhone.
So publish-media.sh now emits two encodings and points the post at the
compatible one:
* Every video transcode also produces <hash>.h264.mp4 (x264 crf 23,
same denoise, same frames), uploaded beside the AV1 under the AV1's
hash — the poster's sibling-naming trick, reused, so fetch-media.sh
finds it by name with nothing to look up.
* The printed URL to paste into the post is the H.264 one. pict-rs
can thumbnail it too, so instance thumbnails come back as a bonus.
fetch-media.sh adopting an own-origin .h264.mp4 URL swaps the AV1 back
in as the page's primary when it is on the mount, and records the H.264
as `fallback` in posts.json. The renderer turns a non-empty fallback
into a <source> pair: the AV1 first with an explicit codecs parameter —
both files are video/mp4, so the parameter is the only thing that lets
a non-AV1 browser skip to the file it can play — and the H.264 second.
Browsers with AV1 keep downloading the small file; Safari before 17
gets one that plays instead of an element that will not.
e2e gains the matching conditional gate: a page offering an av01
<source> must offer an .h264.mp4 one, so an AV1 video can never again
ship without its fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
c21aa636aa
commit
a625176c7d
6 changed files with 142 additions and 25 deletions
|
|
@ -30,11 +30,16 @@
|
|||
# downstream consumer measures is what the viewer actually sees — see the
|
||||
# rotation note in fetch-media.sh for what goes wrong when it does not.
|
||||
#
|
||||
# NOTE ON AV1: nothing here emits a fallback encoding, and the <video> tag the
|
||||
# site renders carries a single src. Browsers without AV1 (Safari before 17, and
|
||||
# Apple hardware older than A17/M3) get an element that will not play rather than
|
||||
# a degraded one. Pass --raw, or re-encode to H.264, if that audience matters for
|
||||
# a particular post.
|
||||
# FALLBACK: AV1 alone locks out Safari before 17 and Apple hardware older than
|
||||
# A17/M3 — which surfaced the first time an AV1 link was posted and an iPhone
|
||||
# viewer got "bad media error" from the raw file. So every transcode also emits
|
||||
# an H.264 sibling, uploaded as <hash>.h264.mp4 next to the AV1 (same trick as
|
||||
# the poster: named after the AV1's hash so fetch-media.sh finds it with nothing
|
||||
# to look up). The URL this script prints for the post is the H.264 one, because
|
||||
# a post's link is fetched raw — Lemmy apps and browsers play that exact file,
|
||||
# with no <source> negotiation in front of it — and it must be the encoding
|
||||
# everything can play. Our own pages recognise the .h264.mp4 name, serve the AV1
|
||||
# to browsers that can take it, and keep the H.264 as the <source> fallback.
|
||||
|
||||
set -eu
|
||||
|
||||
|
|
@ -95,6 +100,7 @@ for src in $FILES; do
|
|||
esac
|
||||
|
||||
poster=""
|
||||
fallback=""
|
||||
if [ "$RAW" = 1 ] || [ "$kind" = other ]; then
|
||||
payload="$src"
|
||||
out_ext="$ext"
|
||||
|
|
@ -111,6 +117,18 @@ for src in $FILES; do
|
|||
# AAC rather than Opus on purpose: Opus-in-MP4 is still uneven in exactly
|
||||
# the players most likely to be shaky about AV1 anyway, and the audio is
|
||||
# a rounding error next to the video either way.
|
||||
fallback="$WORK/h264.mp4"
|
||||
echo " transcoding H.264 fallback (crf 23)…"
|
||||
# Same source and same denoise as the AV1, so the two encodings show the
|
||||
# same frames. CRF is x264's own scale (not comparable to SVT-AV1's);
|
||||
# 23 is its "looks the same" default, and this file is the compatibility
|
||||
# rail, not the one most visitors download — bigger is acceptable here.
|
||||
ffmpeg -nostdin -v error -i "$src" \
|
||||
-vf "hqdn3d=4:3:6:4.5" \
|
||||
-c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p \
|
||||
-movflags +faststart \
|
||||
-c:a aac -b:a 96k -ac 1 \
|
||||
"$fallback" -y
|
||||
poster="$WORK/poster.webp"
|
||||
# A frame a third of the way in, which beats frame 0 — recordings tend to
|
||||
# open on a lock screen, a hand moving into place, or a fade.
|
||||
|
|
@ -130,23 +148,32 @@ for src in $FILES; do
|
|||
name="$hash.$out_ext"
|
||||
publish_file "$payload" "$name"
|
||||
|
||||
# The poster is named after the VIDEO's hash, not its own. That is the whole
|
||||
# point: fetch-media.sh finds it by name, with nothing to look up, when the
|
||||
# instance did not manage to make a thumbnail — pict-rs will not read AV1, so
|
||||
# for these uploads that is the normal case rather than the exception.
|
||||
# The poster and the H.264 fallback are named after the AV1's hash, not
|
||||
# their own. That is the whole point: fetch-media.sh finds both by name,
|
||||
# with nothing to look up — the poster when the instance made no thumbnail
|
||||
# (pict-rs will not read AV1, so for these uploads that is the normal
|
||||
# case), the fallback for every browser that cannot decode AV1.
|
||||
if [ -n "$poster" ] && [ -f "$poster" ]; then
|
||||
publish_file "$poster" "$hash.poster.webp"
|
||||
fi
|
||||
post_name="$name"
|
||||
if [ -n "$fallback" ] && [ -f "$fallback" ]; then
|
||||
post_name="$hash.h264.mp4"
|
||||
publish_file "$fallback" "$post_name"
|
||||
fi
|
||||
|
||||
url="$SITE_ORIGIN/media/$name"
|
||||
# The postable URL is the H.264 one when it exists — see FALLBACK above.
|
||||
url="$SITE_ORIGIN/media/$post_name"
|
||||
# Confirm it is actually being served before handing over a URL that is about
|
||||
# to be pasted into a post, where a 404 is public and permanent.
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 30 "$url" || echo 000)
|
||||
if [ "$code" = 200 ]; then
|
||||
printf ' %s\n' "$url"
|
||||
printf ' post this: %s\n' "$url"
|
||||
else
|
||||
echo " WARNING: $url answered HTTP $code — do not post this link yet" >&2
|
||||
fi
|
||||
printf ' %s -> %s (%s)\n' \
|
||||
"$(du -h "$src" | cut -f1)" "$(du -h "$payload" | cut -f1)" "$name"
|
||||
[ -z "$fallback" ] || printf ' fallback: %s (%s)\n' \
|
||||
"$(du -h "$fallback" | cut -f1)" "$post_name"
|
||||
done
|
||||
|
|
|
|||
Loading…
Reference in a new issue