@remotion/timeline-utils: Add film strip codec tests#7383
Conversation
Co-authored-by: Jonny Burger <hi@jonny.io>
There was a problem hiding this comment.
Adds a focused integration test for extractFrames that wires the Studio's slot-generation helpers (ensureSlots, WEBCODECS_TIMESCALE) to the server-side extraction path, and switches the waveform fixture to MP4 so the path exercises a real codec decode. Two minor observations inline — none block merge.
TL;DR — Adds the first extractFrames test against a real MP4 fixture, asserting that decoded sample timestamps line up with the timeline film strip's slot timestamps within 50 ms, and swaps the waveform integration fixture from WAV to MP4 to cover codec-backed audio decoding.
Key changes
- Server-side film strip coverage for
extractFrames— wiresensureSlots+WEBCODECS_TIMESCALEfromrender-frame-stripinto the test so the same slot math the Studio uses is exercised end-to-end againsthttps://remotion.media/video.mp4. - Switch waveform fixture from WAV to MP4 —
load-waveform-peaks-server.test.tsnow decodes an MP4 audio track instead of a WAV file, exercising the codec-backed audio path.
Summary | 2 files | 1 commit | base: main ← cursor/timeline-filmstrip-codec-tests-642e
Film strip slot/sample alignment
Before: No test exercised
extractFramesagainst a real MP4 with the Studio's film-strip slot math.
After: A single integration test populatesfilledSlotsviaensureSlots, returns those slot timestamps fromtimestampsInSeconds, and verifies every decodedVideoSamplematches its slot within 50 ms.
The pairing relies on map insertion order: filledSlots.keys() is read once inside timestampsInSeconds and once after the iterator completes, with the test asserting extractedSamples.length === filledSlots.size and then indexing both arrays in lockstep. That's correct given JS Map iteration order, but if extractFrames ever skips a null sample (it does via continue), the length assertion catches it before the pairing loop runs — good.
Waveform fixture moved to MP4
Before:
loadWaveformPeakstests decodeddialogue.wav.
After: Both tests decode the MP4 audio track fromvideo.mp4.
This is a fixture swap, not an addition — WAV-format decode is no longer exercised by any test in this package. Worth confirming WAV is covered elsewhere (or that dropping it here is intentional given MP4 better represents production usage).
load-waveform-peaks-server.test.ts
Claude Opus | 𝕏
| timestampsInSeconds: ({track, container, durationInSeconds}) => { | ||
| expect(track).toEqual({width: 1920, height: 1080}); | ||
| expect(container).toBe('MP4'); | ||
| expect(durationInSeconds).toBe(10); |
There was a problem hiding this comment.
toBe(10) is exact float equality on the fixture's duration. If https://remotion.media/video.mp4 is ever re-encoded and lands at 9.97 s or 10.04 s, this fails. toBeCloseTo(10, 1) would survive minor re-encodes while still catching real drift.
| import {loadWaveformPeaks} from '../audio-waveform/load-waveform-peaks'; | ||
|
|
||
| const SAMPLE_AUDIO_URL = 'https://remotion.media/dialogue.wav'; | ||
| const SAMPLE_MEDIA_URL = 'https://remotion.media/video.mp4'; |
There was a problem hiding this comment.
This drops the only WAV-format coverage for loadWaveformPeaks in this package — the test name now says "MP4 audio track" rather than a generic "remote audio". If WAV decode is still a supported input path, consider keeping the original test and adding the MP4 case alongside it rather than replacing it.

Summary
extractFramesusing the same slot generation helpers used by Studio.Validation
bun test srcinpackages/timeline-utilsbun run formattinginpackages/timeline-utilsbun run lintinpackages/timeline-utilsbun run buildat repo rootbun run stylecheckat repo root was attempted and reached the known@remotion/lambda-goGo 1.22.2 vs Go >= 1.23.0 environment failure after timeline-utils formatting/lint passed.