For compression purposes, I am re‐encoding a grayscale video to the H.265/HEVC codec. Although the input video is more or less perfectly grayscale in aspect, it is provided in the yuv420p pixel format. So I thought that mapping the video to the gray pixel format would reduce file size further. I was expecting this, not only because gray uses 8 bits per pixel while yuv420p uses 12 (according to ffmpeg -pix_fmts), but also because stripping noisy data (irrelevant color information) would help compression.

To my surprise, the opposite happened: the output video in gray is about 14 % larger than the output video in yuv420p!

As an example, I measured the byte size with a 60‐second footage, which I encoded as follows :

ffmpeg -i in.h264 \
    -filter:V 'crop=960:720:160:0, format=gray, format=yuv420p' \
    -c:V libx265 -crf 26 -preset medium \

I tried several filter chains (I was also cropping the video):

  • nothing (output file out.h265),
  • turning the video to gray (output file out-gray.h265)
  • turning the video to gray, then back to yuv420p (output file out-gray-yuv.h265) — as hinted at by that answer.

(I also tried the hue filter, like this: hue=s=0, but it is apparently subsumed by converting the video to gray. Also, using the -pix_fmt option appears to be equivalent to appending a format filter)

BYTES      NAME                FFPROBE
14972779   in.h264             h264 (Main), yuv420p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 1200k tbn, 50 tbc
 3043717   out-gray.h265       hevc (Rext), gray(tv),                 960x720 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1200k tbn, 25 tbc
 2670564   out.h265            hevc (Main), yuv420p(tv),              960x720 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1200k tbn, 25 tbc
 2662991   out-gray-yuv.h265   hevc (Main), yuv420p(tv),              960x720 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1200k tbn, 25 tbc

It appears that out-gray-yuv is very slightly smaller than out, which is not surprising (it could come from the input video not being perfectly grayscale yet). However, it is also about 14 % smaller than out-gray, which I cannot explain.

Why do I observe these results? What should I do to benefit from grayscale compression with H.265?

  • Imna hazard a guess and say out-gray.h265 doesn’t use chroma sub sampling, and isn’t just the y’ component, maybe? Maybe it’s 411? I don’t understand why out-gray-Yuv would be 420, either; it shouldn’t have a chrominance component — it should just be black and white. May 30, 2020 at 10:27
  • encoding videos can be quirky. A different combination of preset and crf values might give you totally different results! Also I imagine that the libx265 encoder was primarily optimized for yuv420/yuv420p10/color formats. You might just be running into some slightly substandard behavior. One thing you can try is keep the yuv420p format, but explicitly remove the chroma components with lutrgb="g=0:b=0" and see what happens.
    – Chris
    Feb 9, 2021 at 22:41
  • I consistently observe this. @JasonConrad the gray pixel format doesn’t even have a chroma to sub-sample. It’s really just the Y component (or Y', I don’t know exactly) at 8 bits per pixel. Whereas the yuv420p is 12 bits per pixel (Y at 8b/px, U at 8b/4px, V at 8b/4px). This is documented by ffmpeg -pix_fmts. As far as I understand, the encoding of out-gray-yuv is just the same as that of out-gray with four additional null bits per pixel. So I guess it’s just that H.265 compression algorithms/settings have not been optimized for 8bit-pixels. ¯\_(ツ)_/¯
    – Maëlan
    Jun 5, 2022 at 1:05
  • 1
    @Chris The video filter lutrgb=g=0:b=0 imposes RGB instead of YUV, and removes the green and blue components, leaving the picture in redscale. I guess you rather meant lutyuv=u=128:v=128 (hinted by man ffmpeg-filters), which cancels the chroma components (while keeping these null components in the output). I just tested it, it is exactly the same (bit-equal) as the filter chain format=gray, format=yuv420p which I was using in the question.
    – Maëlan
    Jun 5, 2022 at 1:08
  • Right you are! I've learned a bit more about color in the year since I replied. Sometimes I wonder if ffmpeg's automatic format conversion filter insertion does too much. It makes things much easier to get working most of the time, but in this case it automatically inserts a format conversion filter to rgb24 before lutrgb=g=0:b=0. If I was forced to be explicit about fmt conversions I probably would have re-thought what I was doing. Just some musings. Anyway, thanks for correcting me!
    – Chris
    Jun 6, 2022 at 0:28


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.