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 \
out-gray-yuv.h265
I tried several filter chains (I was also cropping the video):
- nothing (output file
out.h265
), - turning the video to
gray
(output fileout-gray.h265
) - turning the video to
gray
, then back toyuv420p
(output fileout-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?
lutrgb="g=0:b=0"
and see what happens.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 theyuv420p
is 12 bits per pixel (Y at 8b/px, U at 8b/4px, V at 8b/4px). This is documented byffmpeg -pix_fmts
. As far as I understand, the encoding ofout-gray-yuv
is just the same as that ofout-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. ¯\_(ツ)_/¯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 meantlutyuv=u=128:v=128
(hinted byman 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 chainformat=gray, format=yuv420p
which I was using in the question.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!