Validate MP4 Streams on Cloudflare Workers

Краткое содержание

Pixel’s announcement covers streaming MP4 validation in Cloudflare Workers as video files are saved to R2. The parser checks for video and audio tracks, verifies their durations are about 15 seconds, and detects incomplete files while avoiding the memory cost of downloading the full video into an ArrayBuffer.

DEV Community

Streaming MP4 Validation on Cloudflare Workers

The render API returns a .mp4 URL, and the download comes back with HTTP 200. Can you mark the job done? In Deck the Halls Dance AI, two photos become a 15-second Christmas dance clip like this sample MP4. Before the Worker hands out a download link, it checks that the file has both video and audio, that each track runs for about 15 seconds, and that the full file made it into storage. A valid-looking response can still carry a silent clip or end halfway through a box. Downloading the whole thing into an ArrayBuffer would make those checks straightforward, but memory would grow with every download. The Worker already has to read the response to save the video in Cloudflare R2, so it inspects the MP4 during that same pass. Read the MP4 boxes as the bytes arrive An MP4 is organized into boxes. Each box has a type and a size. For this check the Worker cares about three top-level types: ftyp for file type information, moov for the movie metadata, and mdat for the actual media bytes. The parser buffers the moov payload, with an 8 MiB cap. It counts the mdat bytes and passes them through to storage. Within moov, it walks the track metadata down to trak → mdia. The hdlr box identifies a video track (vide) or an audio track (soun). The mdhd box provides the track’s duration and timescale. A track with a timescale of 48,000 and a duration of 720,000 units runs for 15 seconds. The app accepts a half-second of drift in either direction for each video and audio track. Checking each track catches cases like 15 seconds of video paired with one second of audio. Network chunks can end anywhere, including in the middle of the size field. They can also carry the end of one box and the start of another. The parser holds up to 16 header bytes, including room for an extended size, and remembers how much payload of the active box remains. It can keep reading the other boxes when moov arrives after mdat. At end of stream, it checks that the stream ended on a valid boundary and that the required boxes and tracks were present. Complete the multipart upload after validation The R2 multipart upload API lets the Worker upload parts before it calls complete. The Worker fills 5 MiB parts sequentially and counts incoming bytes against a 100 MiB file limit. It enforces that limit even if the response has no Content-Length. This TypeScript sketch shows the ordering. writeParts handles buffering and part numbering, and flushParts uploads any bytes left in the buffer. let bytesRead = 0

try {
while (true) {
const { done, value } = await reader.read()
if (done) break

bytesRead += value.byteLength
checkByteLimit(bytesRead)
inspector.push(value)
await writeParts(value)

}

checkExpectedLength(bytesRead)
inspector.finish()
await flushParts()
await upload.complete(parts)
} catch (error) {
await reader.cancel().catch(() => undefined)
await upload.abort().catch(() => undefined)
throw error
} finally {
reader.releaseLock()
}
Suppose the last few bytes disappear after several parts have already made it to R2. The final length or box-boundary check fails and the Worker aborts the upload. The download stays unavailable because the job row only gets an output key after the upload completes. That job update also checks which attempt still owns the lease. Each attempt writes to a different object key, so a slow attempt that finishes after its lease expires can’t overwrite the newer attempt’s file. If R2 is temporarily unavailable, the job can retry the download from its stored source URL and reuse the existing render. Test the failures that would look like success The test fixtures build tiny MP4-shaped byte arrays so they can change one field at a time. Useful cases include a missing audio track, a one-second audio track under a full-length video track, an oversized moov header, and a response shorter than its declared size. One fixture uses a payload over 5 MiB to check that the upload splits into two parts. For a rejected f...
Validate MP4 Streams on Cloudflare Workers
Powered by Readybot.io

Последнее от Pixel

Fix GitHub Pages: Missing Artifact Error

Pixel's announcement explains why the GitHub Pages deploy action reports that no github-pages artifact was found. It covers skipped or failed build jobs, missing uploads, …

Rotate DB and Redis Passwords Without Downtime

Pixel shares a practical guide to rotating exposed database and Redis passwords without interrupting application connections. The approach updates Secrets, changes service credentials, and gradually …

AI Agent Earns Crypto from $0: Day 3 Update

Pixel shares Day 3 of a 21-day experiment testing whether an autonomous AI agent can earn real crypto from zero. The agent launched a pay-per-call …

AI Agent Receipts Prove What Actually Executed

Pixel’s announcement examines how public Zambo receipts verify what an AI agent actually did. A BTC price fetch succeeded with a recomputable output hash, while …