Most mobile video editors are thin clients. The timeline is a remote data structure, the render happens on a GPU somewhere, and the finished file comes back through a download link that expires. That architecture gives you fast exports on cheap hardware and a copy of every clip you have ever edited on somebody else’s disk.
ReelRoll takes the other route: a full timeline editor that renders with FFmpeg on the device. The interesting problems are not in the effects. They are in undo, in storage and in making a long export survivable on a phone.
The timeline is a list of operations, not a video
The single most important design decision is that editing never rewrites the source files. A project is an ordered list of operations against references to original media: trim, split, merge, speed, reverse, crop, rotate, text with keyframes, overlay, mask, transition, subtitle, voice-over, added audio.
That buys three things at once:
- Undo and redo are free. They move an index in the operation list. No re-encoding, no copies, no “undo failed because the file was already replaced”.
- The originals are safe. A user who exports badly has lost nothing; the source clip is untouched.
- The export step is the only place that reads pixels. Everything before it is metadata.
The cost is that the preview must approximate the render. Preview and export run through different code paths — a fast approximate path for scrubbing, an exact one for the final encode — and any divergence shows up as “it looked different when I exported it”. Keeping the two paths describing the same operation list, rather than duplicating effect logic, is what keeps them in sync.
Storage is the real constraint
A three-minute 4K export is a few hundred megabytes. Doing that with a naive pipeline that demuxes to intermediate files will fill a phone before the export finishes.
The mitigations that mattered:
- Render to app-private cache, then move. Writing directly to shared storage means a half-written file can be picked up by the media scanner and appear in the gallery as corrupt. Export to cache, verify, then publish.
- Stream, do not stack. Concatenating media by building a full superset of decoded frames is the fastest way to an out-of-memory crash. Prefer filter graphs that process one input at a time.
- Cap intermediate bitrate, not final bitrate. Intermediate files only need to survive one more pass; encoding them at delivery quality doubles the work and the disk usage for no visible gain.
- Delete intermediates aggressively. On failure, on success, on app start. A cache that leaks is a support ticket about “ReelRoll is using 40 GB”.
A foreground service for the long tail
Exports take minutes, and users leave the app. Since Android 8 any work that must survive backgrounding needs a foreground service with a visible notification, and since Android 14 the service type has to be declared and justified.
The export service is deliberately boring: one job at a time, a determinate progress notification, a cancel action, and a clear failure state. The alternative — an in-process coroutine that dies when the activity is destroyed — produces exports that silently stop halfway, which users interpret as data loss.
For the same reason, exports go through Android’s media store APIs rather than raw file paths. Scoped storage means you do not get to write wherever you like, and the media store is also what makes the file visible in the gallery and in other apps’ pickers.
Metadata is a feature, not an afterthought
Photos and videos carry EXIF: GPS coordinates, device model, timestamps, sometimes a serial number. A private gallery should show that information, and a good editor should let you remove it.
ReelRoll reads EXIF for the location and device badges, and offers a share-without-metadata path that strips it from the exported copy. The original keeps its metadata, because silently rewriting the user’s source file is not a privacy feature, it is data loss.
What “local” actually costs
Honest accounting of the trade-offs:
- Exports are slower than a server farm. A phone is one device with a thermal budget. Long 4K timelines take minutes, and the phone gets warm.
- Binary size grows. FFmpeg is large, and the codec set you ship is a direct trade against install size.
- You own the crashes. There is no server-side retry. A malformed input crashes on the user’s phone, in the user’s hands, and the fix ships in the next release.
In exchange you get an editor that works on a plane, has no upload limit, has no per-minute pricing, and cannot leak footage it never had. For a personal media tool, that is the right side of the trade.