movies-resizer: The Rust CLI That Turns MP4s Into Raw Pixels

It uses ffprobe and ffmpeg to resize video to 540px wide, sample it at 1 FPS, and emit raw RGB24 buffers or JSON, so downstream code gets data instead of a decoder problem.

6 min read • View on GitHub • More from dashn9

A film reel enters a precision machine and comes out as orderly stacks of tiny pixel tiles and clean data sheets. The image explains that this tool is not about editing video for humans, but translating video into a format that other software can inspect.
The repo's core move is translation, not playback. It turns video into a predictable data contract.
Key Takeaways

Video, but for machines

Most video tools are built to preserve motion. movies-resizer does the opposite. It turns an .mp4 into a stream of raw pixels, then can serialize those pixels into JSON so another program can read a frame without first solving video decoding.

That sounds small until you need to feed video into a script, a model, or a visualization pipeline. At that point, a decoder is friction. A predictable byte contract is leverage.

The pipeline hidden inside one binary

The repo's real trick is not resizing. It is making every output frame computable ahead of time. ffprobe discovers the source dimensions, ffmpeg scales to 540px wide and samples at 1 FPS, and Rust reconstructs the exact byte count from width × height × 3.

The whole tool fits on one line: probe, transform, buffer, serialize. The interaction should make the byte contract visible at each step.

The tool also caps processing at 180 seconds. That keeps the data shape bounded, which matters because the JSON path turns each pixel into an explicit tuple and the memory bill rises fast.

ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0:s=x input.mp4
ffmpeg -i input.mp4 -vf scale=540:-1,fps=1 -t 180 -f rawvideo -pix_fmt rgb24 output.raw

Why Rust fits this job

Rust is doing glue work here, but good glue work. clap gives the CLI a clean surface, std::process::Command keeps the ffprobe and ffmpeg calls explicit, and serde_json handles metadata plus optional pixel serialization.

That choice matters because the repo is less about algorithmic novelty than contract discipline. The code says what it expects, what it emits, and when it stops. Even the sequential file loop feels intentional, because the first job is correctness, not throughput.

A close-up of a filmstrip passing through a measuring gauge, then breaking into evenly spaced segments before becoming tidy stacks of small pixel blocks. The image explains why fixed-width resizing and 1 FPS sampling make the output easy to predict and consume.
This is the repo's practical center of gravity: sample less, resize once, and make the output countable.

What it replaces, and what it does not

Tool / approachPrimary outputKnowledge neededStrengthWeaknessBest fit
FFmpeg shell scriptFrames or re-encoded videoHighFast and flexibleEasy to lose track of dimensions and byte countsOne-off local automation
Python with OpenCV or MoviePyFrames, arrays, or clipsMediumQuick to prototypeMore moving parts, especially across large batchesExploratory data prep
movies-resizerRaw RGB24, JSON, and .meta.jsonLow to mediumA single opinionated contractNarrow scope and memory-heavy JSONRepeatable preprocessing for downstream code

Compared with a shell script, the repo gives you a typed CLI and a repeatable metadata file. Compared with Python video pipelines, it gives you a narrower surface and fewer moving parts. It is not trying to be a media suite, only a preprocessing adapter with a very specific output shape.

A messy desk on the left is covered in tangled shell fragments, loose notes, and codec jargon, while the right side holds a single tidy Rust crate feeding a straight pipe of raw pixels and metadata. The image shows the difference between ad hoc video handling and a narrow preprocessing adapter.
The repo wins by refusing to be general-purpose. It narrows the problem until the output is easy to trust.

Origin, constraints, and the next obvious upgrade

The project reads like a single-maintainer utility, not a platform. That is a strength here. The smaller the tool, the easier it is to trust the contract: input video in, bounded raw frames out, metadata alongside the bytes.

There are no public interviews or quotes to lean on, so the README and the code carry the argument. The obvious next step is parallel file processing, which the dependency list already hints at, but the real trade-off remains memory. The JSON path is expensive because every pixel triplet gets expanded before it is serialized.