Cryptograss:Video encoding pipeline

From PickiPedia: A knowledge base of bluegrass, old time psychedelic jams, and other public domain music
Jump to navigationJump to search

Video encoding pipeline describes how a video travels from a musician's laptop to a published Release on PickiPedia — and, as of September 2026, why none of that work leaves delivery-kid any more.

How it works

  1. Upload. Special:DeliverVideo mints a draft, then the browser posts the video bytes directly to delivery-kid — they never pass through the wiki server. A ReleaseDraft: page is created first, so an upload that fails leaves an inspectable record instead of vanishing.
  2. Analyse. delivery-kid probes the file for duration, resolution and codecs, and writes them onto the draft page.
  3. Finalize. The video is transcoded to AV1 video and Opus audio in four renditions (see the quality ladder), a poster frame is extracted, and the whole directory is pinned to IPFS under one CID.
  4. Publish. A bot notices the finalized draft, creates the Release: page, and adds BitTorrent metadata so the release seeds as well as pins.

Encoding is the slow step — budget about two and a half times the video's length — and everything after it takes seconds. Progress is reported live on the draft page throughout, and a snapshot of the whole log is written to ReleaseDraft:<uuid>/diagnostics at every terminal state, so the record survives even if delivery-kid's storage is rebuilt.

Why AV1 and Opus

Both are royalty-free. H.264 and AAC — what cameras and phones actually record — are covered by patent pools. Since cryptograss exists to distribute music freely and durably, the published artefact should not depend on a licensing regime that can change. Encoding is also DRM-free: nothing here is encrypted or access-controlled, and the file is downloadable from IPFS by anyone.

The practical cost is that Apple ships no software AV1 decoder. Safari plays AV1 only on M3-and-later Macs and A17 Pro-and-later iPhones. Chrome and Firefox both bundle the royalty-free dav1d decoder and play AV1 on any desktop, including older Intel Macs. So on Apple hardware without AV1 support, use Firefox or Chrome, or download the file and play it in VLC. The player says as much when it cannot decode, rather than blaming IPFS.

The quality ladder

Every video is published as four streams under a single CID, listed in master.m3u8. The player picks one by bandwidth and switches as conditions change; a listener can also choose the audio-only stream deliberately.

Stream Short side CRF Audio Typical bitrate
stream_1080p 1080 px 32 128 kbps 2.6–5 Mbps
stream_720p 720 px 34 128 kbps 1.6–2.4 Mbps
stream_360p 360 px 36 96 kbps 0.65–1.0 Mbps
stream_audio — — 160 kbps ~0.15 Mbps

The audio-only stream is roughly fifty times smaller than 1080p, which makes it the one certain to work from a campground, and for an archive of music it is often the one people actually want. It gets the better audio bitrate for that reason.

Rungs larger than the source are skipped rather than upscaled. A rung is named for the short side of the picture, so an upright phone video is "1080p" at 1080×1920 exactly as a landscape one is at 1920×1080. Sizing by the tall side instead produced a 608×1080 "1080p" from a 1080×1920 phone clip, discarding well over half the picture. (maybelle-config#124, #128)

A poster frame (poster.jpg) is written alongside, taken about ten percent in so it does not land on a lens cap or an empty stage. It is a JPEG, so it renders even where the AV1 behind it will not — a Safari viewer at least sees what is on offer. (maybelle-config#120)

scripts/reladder.py rebuilds an already-published release as a ladder. It copies the existing top rendition and the audio bit-for-bit and only encodes the smaller rungs, so the original quality is never re-compressed. It cannot recover detail that was never published: a release whose best stream is 608×1080 stays that size, and only a re-upload of the original file restores it.

The September 2026 rework

Until early September 2026, transcoding was sent to Coconut, a paid cloud service. Long videos failed there consistently, and a chain of separate bugs made those failures nearly impossible to read. All of it surfaced from a single complaint: longer videos would not upload.

What was wrong

Uploads died instantly on large files
The upload handler read each file into memory in one allocation. On delivery-kid's 4 GB box a multi-gigabyte video exceeded available memory and raised MemoryError before copying a single byte — 13 milliseconds after the upload began. Because MemoryError stringifies to the empty string, the error surfaced as a bare "Upload error:" with nothing after it. Fixed by streaming to disk in 8 MB chunks: peak memory for a 200 MB file fell from 210 MB to 17 MB. (maybelle-config#108)
Coconut could not handle long videos
Two independent attempts on a 10.5 GB source failed 12m11s and 11m54s after submission — a fixed timeout, not a transient fault. Coconut's failure webhook carried no error field at all, so both the draft page and the container log reported only "Unknown error". (maybelle-config#110)
The local fallback used patented codecs
The "fallback" path was libx264 + aac — quietly undermining the royalty-free goal that sent the work to Coconut in the first place. It also could not be reached: once Coconut accepted a job, the finalize handler returned, and the job's later failure arrived by webhook with nothing left to fall back to.
delivery-kid could never write to the wiki
The wiki client was built with mwclient's default path of /w/, but PickiPedia serves its API at /api.php. Every write 404'd, so every diagnostics snapshot silently no-opped, and draft pages froze at whatever the browser last wrote.
A successful publish could still report total failure
The CID was held only in the browser's event stream. If anything after the pin failed, the source was deleted as "safely published" while nothing recorded where it went. The publish is now written down three ways — the draft file, a finalized/ ledger, and the wiki snapshot — before the uploader is told anything. (maybelle-config#117)

What changed

Encoding moved onto delivery-kid using SVT-AV1, which has become fast enough to make the cloud service unnecessary. Measured on two threads at 1080p, extrapolated to a 66-minute source:

Encoder Royalty-free Speed 66-minute source
SVT-AV1 preset 12 yes 0.51× realtime ~34 min
SVT-AV1 preset 10 yes 0.81× realtime ~53 min
libx264 medium no 1.32× realtime ~1.5 h
libvpx-VP9 speed 4 yes 2.69× realtime ~3.0 h

SVT-AV1 at preset 10 is faster than the patented libx264 profile it replaced. Coconut is now opt-in only; auto means local.

Encoding four renditions instead of one costs roughly 2.5× the video's length, measured end to end on real uploads:

Upload Output Speed
27 s landscape, single 1080p rendition 1920×1080 1.13× realtime
24 s upright, full ladder 1080×1920 top rung 0.43× realtime

So a 66-minute set is around two and a half hours of encoding. The page reports position, speed and a running estimate throughout, so a long encode looks busy rather than hung:

Encoding 34% · 11m40s of 34m00s · 1.36x · ~16m left

(maybelle-config#114 and pickipedia#108)

A detail worth recording, because it fails silently: AV1 and Opus cannot be carried in MPEG-TS segments. ffmpeg accepts such a command, exits zero, and writes a playlist whose streams probe back as bin_data — unplayable. HLS output here therefore uses fMP4/CMAF segments, with the GOP derived from source frame rate so keyframes land on segment boundaries. (maybelle-config#113)

Known issues

  • maybelle-config#126 — the preview shown on the draft page before publishing is still sent to Coconut, and its result has never been used: the job asks for an output named mp4 while the handler looks for mp4_preview, so the page falls back to playing the original upload. Each one spends a Coconut credit, waits about 30 seconds, and pins a one-file directory that nothing references. Awaiting a decision on removal.
  • maybelle-config#121 — four tests in the Coconut suite assert an output schema the code no longer emits. They are excluded from CI, loudly, until Coconut's fate is settled.
  • maybelle-config#110 — the original Coconut failure on very large uploads. Now confined to the preview path, and resolved by #126 either way.

Fixed since this page was first written: the lost-publish bug (#115), the diagnostics pages that had never been written, and every block height on the wiki being about ten days in the future.

Releases through the local pipeline

Release Length Finalized Note
Pickipedia Dispatch — Sombrero Edition 34 min 2 September 2026 first local encode
44th Bday Cicada Jam-Bash 66 min 3 September 2026 recovered after the lost-publish bug
Cicada 44th Bday Jam Set 1 13 min 4 September 2026 first with no manual intervention
Skyler Serenading Strangers on the Shore 27 s 14 September 2026 first diagnostics page ever written
Iceland Hot Springs Flute with Justin Holmes 24 s 15 September 2026 first quality ladder; upright, so published at 608×1080
Some band practice... in a field somewhere 38 s 17 September 2026 first upright video at full 1080×1920

The first three are single-rendition 1080p and predate the ladder.

Advice for uploaders

  • Export around 8–12 Mbps for 1080p. Camera and editor defaults are often 21 Mbps or higher, which is far more than jam footage needs — that is the difference between a 5 GB upload and a 10.5 GB one, with no visible gain.
  • Do not economise on audio. 256–320 kbps. It is a rounding error in file size and it is the part anyone actually listens to.
  • Upright phone video is fine. It is published at its full resolution. Send the file straight off the phone; re-exporting can bake in the rotation.
  • Expect the encode to take about 2.5× the video's length, and leave the page open — or don't, since the publish is recorded server-side either way.
  • Fill in venue and performers before finalizing. Those fields become the Release page, and the performer names are what connect a video to everyone's pages later.
  • Storage is roughly the size of the source now that four renditions are kept. A 38 s phone clip of 38 MB published as 39.8 MB across all four streams.

See also