Cryptograss:Video encoding pipeline
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
- 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. - Analyse. delivery-kid probes the file for duration, resolution and codecs, and writes them onto the draft page.
- 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.
- 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
MemoryErrorbefore copying a single byte — 13 milliseconds after the upload began. BecauseMemoryErrorstringifies 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
mp4while the handler looks formp4_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
- Cryptograss:Delivery-kid — the server this all runs on
- Special:DeliverVideo — the upload form
- Special:Releases — everything published
- Cryptograss:Video quality and storage — what the quality setting costs in bytes, measured, and why it was left alone
- Cryptograss:On The Pipe — the failure pattern most of these bugs shared