If you make an "Outstanding" Tiny Desk AI clip and drop it into an editor, you may see three odd things. The project says 30 fps but the clip says 24. The clip runs longer than the "15-second" reference. And a copy you "only remuxed" plays the same but is missing something. I wanted numbers instead of guesses, so I ran a small stream audit on the eight public sample clips on the Tiny Desk Outstanding home page: one reference video and seven generated or alternate cuts. Everything below was run on November 13, 2026 with ffmpeg/ffprobe and Python 3.13. The output is pasted as it came out.
The audit script
stream_audit.py asks ffprobe for the real packet count (-count_packets) instead of trusting header metadata. It compares the video and audio stream durations, then walks the MP4's top-level boxes to see whether moov (the index) comes before mdat (the media). That second check is what "faststart" means: a browser can start playing before the whole file has arrived.
#!/usr/bin/env python3 """stream_audit.py - per-stream duration, frame rate, A/V gap and moov position for MP4 files.""" import json, struct, subprocess, sys from fractions import Fraction def probe(path): out = subprocess.run(["ffprobe", "-v", "error", "-count_packets", "-show_streams", "-show_format", "-of", "json", path], capture_output=True, text=True, check=True).stdout return json.loads(out) def top_atoms(path): """Return the order of top-level MP4 boxes (ftyp, moov, mdat ...).""" order = [] with open(path, "rb") as f: while True: head = f.read(8) if len(head) < 8: break size, kind = struct.unpack(">I4s", head) if size == 1: size = struct.unpack(">Q", f.read(8))[0] f.seek(size - 16, 1) elif size == 0: order.append(kind.decode("latin-1")); break else: f.seek(size - 8, 1) order.append(kind.decode("latin-1")) return order def audit(path): info = probe(path) v = next(s for s in info["streams"] if s["codec_type"] == "video") a = next((s for s in info["streams"] if s["codec_type"] == "audio"), None) vdur = float(v["duration"]) row = {"file": path.split("/")[-1][:18], "size": f'{v["width"]}x{v["height"]}', "fps": round(float(Fraction(v["avg_frame_rate"])), 3), "frames": int(v["nb_read_packets"]), "v_dur": round(vdur, 3), "a_dur": round(float(a["duration"]), 3) if a else None, "a_rate": int(a["sample_rate"]) if a else None, "a_ch": a["channels"] if a else None} row["av_gap_ms"] = round((row["a_dur"] - vdur) * 1000) if a else None atoms = top_atoms(path) row["faststart"] = atoms.index("moov") < atoms.index("mdat") return row (The table printer at the bottom is a few lines of f-strings. The full file is 58 lines.)
What the eight sample clips look like
The files are named by their SHA-256, so the first 18 characters are enough to tell them apart:
file size fps frames v_dur a_dur a_rate a_ch av_gap_ms faststart 0299078c3f432f8bb7 720x1280 24.0 422 17.583 17.583 44100 2 0 True 632c0129d45a4c0a42 720x1280 24.0 424 17.667 17.666 44100 2 -1 True 8256cd873b7ea128d5 480x854 24.0 417 17.375 17.376 32000 2 1 False 875d2458181e34670e 540x940 24.0 97 4.042 4.063 44100 2 21 True 947f5eb2a447eb6c65 720x1280 24.0 481 20.042 19.087 44100 2 -955 True db033545db008394dc 540x960 24.0 241 10.042 10.04 44100 2 -2 True db09b1c54359b0930c 720x1280 30.0 435 14.5 14.506 48000 2 6 True f7ff52686113081806 540x960 24.0 457 19.042 19.04 44100 2 -2 True db09b1c5… is the one the page labels "Whole Band reference video". Here is what stood out:
- Frame rate. The reference is 30 fps with 48 kHz audio. Every other clip is 24 fps, mostly with 44.1 kHz audio. If your editing timeline is set to the reference (30 fps), a 24 fps clip gets a repeated frame in every group of four. That's fine for a meme, but you should know it's happening.
- Length. The reference is 14.5 s; the site rounds that to "15 sec". The three full recasts run 17.4 to 17.7 s, and two alternate cuts run 19 to 20 s. Don't assume a clip will fit a 15-second slot. Measure it.
- A 955 ms audio gap.
947f5eb2…has 20.042 s of video but only 19.087 s of audio. Some players hold the last audio sample, some go silent, and some editors show an "offline" stripe. Of all the problems here, this is the one most likely to cause trouble when you post. - One file without faststart.
8256cd87…(480x854) has itsmoovbox at the end, after 9.77 MB of media data. A browser has to fetch the end of the file before it can show the first frame. - An odd size.
875d2458…is 540x940. That isn't 9:16 (which would be 540x960), so expect a sliver of letterbox if you put it in a 9:16 frame.
The fixes I ran
#!/usr/bin/env bash set -euo pipefail # 1) moov at the end -> remux with faststart (no re-encode) ffmpeg -v error -y -i hoodie_480p.mp4 -c copy -movflags +faststart hoodie_480p_fs.mp4 # 2) audio ends ~1 s before video -> pad audio with silence to the video length ffmpeg -v error -y -i redhair_720p.mp4 -c:v copy -af apad -shortest -c:a aac -b:a 128k -movflags +faststart redhair_720p_pad.mp4 # 3) need 30 fps for an editor timeline that matches the 30 fps reference ffmpeg -v error -y -i leather_720p.mp4 -vf fps=30 -c:v libx264 -crf 18 -preset veryfast -c:a copy -movflags +faststart leather_720p_30.mp4 I re-audited the results:
file size fps frames v_dur a_dur a_rate a_ch av_gap_ms faststart reference.mp4 720x1280 30.0 435 14.5 14.506 48000 2 6 True hoodie_480p.mp4 480x854 24.0 417 17.375 17.376 32000 2 1 False hoodie_480p_fs.mp4 480x854 24.0 417 17.375 17.376 32000 2 1 True redhair_720p.mp4 720x1280 24.0 481 20.042 19.087 44100 2 -955 True redhair_720p_pad.m 720x1280 24.0 481 20.042 20.039 44100 2 -3 True leather_720p.mp4 720x1280 24.0 422 17.583 17.583 44100 2 0 True leather_720p_30.mp 720x1280 30.0 528 17.6 17.583 44100 2 -17 True - The faststart remux took no re-encode and the file got 21 KB smaller (9,808,970 → 9,787,295 bytes). Keep reading for why that matters.
-
apad+-shortestclosed the gap from -955 ms to -3 ms. The video was stream-copied, so picture quality didn't change. -
fps=30turned 422 frames into 528. That's 106 duplicated frames, about one in four, and no new motion. The file grew from 6.97 MB to 7.93 MB. Only do this if your editor really needs 30 fps.
The 21 KB that disappeared was the Content Credentials
The non-faststart file had a box the others don't: a 21,674-byte uuid box right after ftyp. That box holds a C2PA manifest (Content Credentials). I read it with the official c2pa-python reader:
#!/usr/bin/env python3 """c2pa_check.py - does this MP4 still carry Content Credentials (C2PA)? Needs: pip install c2pa-python""" import json, sys import c2pa for path in sys.argv[1:]: try: store = json.loads(c2pa.Reader(path).json()) except Exception as e: # ManifestNotFound for files without credentials print(f"{path}: no C2PA manifest ({type(e).__name__})"); continue m = store["manifests"][store["active_manifest"]] acts = [a for a in m["assertions"] if a["label"].startswith("c2pa.actions")] first = acts[0]["data"]["actions"][0] if acts else {} print(f"{path}: manifest found, state={store.get('validation_state')}, " f"action={first.get('action')}, source={first.get('digitalSourceType', '').rsplit('/', 1)[-1]}") hoodie_480p.mp4: manifest found, state=Valid, action=c2pa.created, source=trainedAlgorithmicMedia hoodie_480p_fs.mp4: no C2PA manifest (_C2paManifestNotFound) leather_720p.mp4: no C2PA manifest (_C2paManifestNotFound) The original file says, in a signed and hash-bound way, "this was created by a trained algorithm". After ffmpeg -c copy -movflags +faststart, that statement is gone. A plain -c copy with no flags drops it too; I checked. ffmpeg doesn't carry unknown uuid boxes into a new file. Even if it did, moving moov changes the byte layout the manifest's hash covers, so the manifest wouldn't validate anymore. The other seven samples had already been through an ffmpeg pass (their encoder tag is Lavf), and none of them carries a manifest.
What this means if you're shipping an AI video pipeline:
- Keep the generator's original file as the master and treat it as read-only. Make your web or share copies from it, and expect them to lose the credentials.
- If provenance matters to you or your platform, put the label somewhere that survives re-encoding too: a visible "AI parody" note, or a line in the caption. Social apps re-encode uploads anyway.
- Add the C2PA check to CI next to the stream audit. It takes about a second per file.
Checklist before you post or edit a Tiny Desk AI clip
| Check | Command | Healthy |
|---|---|---|
| A/V gap | stream_audit.py clip.mp4 | within ±50 ms |
| Faststart | same | True for web embeds |
| Frame rate vs timeline | same | matches, or you accept duplicates |
| Content Credentials | c2pa_check.py clip.mp4 | present on the master |
The reference and the three scenes (Just Me, Back Row, Whole Band) are described on the Whole Band scene page. The page lists the five seats and which shot each one appears in, which helps when you scrub a clip to check a face.
