TechEarl

How to Convert a Video to Black and White (Grayscale) with ffmpeg

Convert a video to grayscale with ffmpeg two ways: hue=s=0 to desaturate, or format=gray for a true single-channel gray file. Plus a custom black-and-white mix and a sepia tone with colorchannelmixer, and why this re-encodes.

Ishan Karunaratne⏱️ 7 min readUpdated
Share thisCopied
Convert a video to black and white with ffmpeg using hue=s=0 to desaturate or format=gray for true single-channel grayscale, plus a custom mix and sepia.

The fastest way to convert a video to grayscale with ffmpeg is to zero out the saturation with the hue filter:

bash
ffmpeg -i in.mp4 -vf hue=s=0 -c:a copy out.mp4

That gives you a black-and-white picture while leaving the audio untouched. But there are actually two different "grayscale" you can mean here, and they produce files that look the same on screen but are not the same on disk. This page covers both, plus a custom mix and a sepia tone, and the one thing every approach has in common: it re-encodes.

hue=s=0: desaturate, keep the color pipeline

hue=s=0 sets the saturation to zero. The colors collapse to gray, but the file stays in its original color pixel format (a YUV format with full chroma planes, those planes just carry no color information anymore).

bash
ffmpeg -i in.mp4 -vf hue=s=0 -c:a copy out.mp4

This is the right pick when you want a black-and-white look but the rest of your pipeline still expects a normal color video: a later filter, an editor, or a player that does not handle a gray pixel format gracefully. The output is a standard color-format MP4 that happens to be gray.

format=gray: a true single-channel gray file

If you want actual grayscale, convert the pixel format itself:

bash
ffmpeg -i in.mp4 -vf format=gray -c:a copy out.mp4

format=gray re-encodes into a single-channel gray pixel format. There are no chroma planes at all, just luma. This is the more literally-correct "grayscale," and because it drops the (now-useless) color planes, the encoded file is often a little smaller than the hue=s=0 version of the same clip.

That is the answer to the question people always ask: hue=s=0 desaturates within a color format; format=gray is single-channel gray. On screen they look identical. The difference is what the container holds and, sometimes, the file size.

One caveat: not every encoder and container combination accepts a gray pixel format. H.264 in an MP4 generally does, but if your target does not, ffmpeg will error on the pixel format. When that happens, fall back to hue=s=0 (which keeps a widely-supported color format), or add an explicit format back to something standard like format=yuv420p after the gray conversion.

A custom black-and-white mix (and sepia) with colorchannelmixer

Both filters above give you a fixed, neutral conversion. If you want control over how each color channel contributes to the gray, or a toned look like sepia, use colorchannelmixer. It is a matrix of how much red, green, and blue feed each output channel.

A neutral grayscale, straight from the official ffmpeg docs:

bash
ffmpeg -i in.mp4 -vf colorchannelmixer=.3:.4:.3:0:.3:.4:.3:0:.3:.4:.3 -c:a copy out.mp4

Every output channel gets the same blend of the inputs, so the result is gray. Bias those weights and you decide how bright reds or greens land in the conversion (a darker-red, brighter-green mix reads very differently for skin tones and foliage than a flat average).

For a sepia tone, the documented matrix is:

bash
ffmpeg -i in.mp4 -vf colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131 -c:a copy out.mp4

Here the three output rows differ, so the image is warmed toward brown instead of staying neutral. colorchannelmixer is the filter to reach for when "just gray" is not the look you want.

This re-encodes. You cannot -c copy it.

Grayscale conversion is a video filter, and a filter has to decode, transform, and re-encode every frame. So you cannot stream-copy the video with -c:v copy: the moment you apply -vf, the video is being re-encoded no matter what. (If you try to combine a filter with -c:v copy, ffmpeg rejects it: "Filtergraph ... was specified, but codec copy was selected.")

The audio is different. Nothing in these commands touches sound, so copy it through untouched with -c:a copy rather than needlessly re-encoding it:

bash
# Re-encode the (now-gray) video, but mux the original audio through as-is
ffmpeg -i in.mp4 -vf format=gray -c:a copy out.mp4

Leaving off -c:a copy makes ffmpeg pick a default audio encoder and re-encode the soundtrack for no reason, which is slower and slightly lossy. If you want to control the video encode while you are at it, add the usual knobs:

bash
ffmpeg -i in.mp4 -vf hue=s=0 -c:v libx264 -crf 20 -preset medium -c:a copy out.mp4

-crf sets the quality (lower is better, around 18 to 23 is the sane range for libx264), and -preset trades encode speed for file size.

A display-only alternative

If the video is for the web and you only need it to look gray in one place, you do not have to re-encode anything: the CSS filter: grayscale(1) desaturates a <video> element in the browser at display time, leaving the source file in full color. That is the right tool when the same asset needs to be color elsewhere. For converting the actual file, the ffmpeg filters above are what you want.

FAQ

See also

Sources

Authoritative references this article was fact-checked against.

Tagsffmpeggrayscaleblack and white videohueformat graycolorchannelmixerCLI

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

How to Convert WebM to MP4 (and Back) with ffmpeg

Convert WebM to MP4 with ffmpeg: why it has to re-encode (VP9/Opus into H.264/AAC, not a stream copy), the yuv420p flag that fixes the QuickTime black screen, and the reverse MP4 to WebM with VP9 and Opus.