The Rec.601 YCbCr to RGB equation is defined as such:
Given Y color range of [16, 235] and Cb,Cr color range of [16, 240].[ 1.164 0 1.59 ] [ Y - 16 ] [ r ]
[ 1.164 -0.391 -0.813 ] * [ Cb - 128 ] = [ g ]
[ 1.164 2.018 0 ] [ Cr - 128 ] [ b ]
You can generate a table of the YCbCr to RGB conversion using this bit of code. Values outside valid YCbCr ranges are simply mapped to white.
public class YCbCrAndRgb {
public static void main(String[] args) {
for (int y = 0; y < 256; y++) {
for (int cb = 0; cb < 256; cb++) {
for (int cr = 0; cr < 256; cr++) {
if (y >= 16 && cb >= 16 && cr >= 16 &&
y <= 235 && cb <= 240 && cr <= 240)
{
int r = (int)Math.round( (y - 16) * 1.164 + (cr - 128) * 1.596 );
int g = (int)Math.round( (y - 16) * 1.164 + (cb - 128) * -0.391 + (cr - 128) * -0.813 );
int b = (int)Math.round( (y - 16) * 1.164 + (cb - 128) * 2.018 );
if (r < 0) r = 0; else if (r > 255) r = 255;
if (g < 0) g = 0; else if (g > 255) g = 255;
if (b < 0) b = 0; else if (b > 255) b = 255;
System.out.format("%02x%02x%02x\t%02x%02x%02x", y, cb, cr, r, g, b);
System.out.println();
} else {
System.out.format("%02x%02x%02x\tffffff", y, cb, cr);
System.out.println();
}
}
}
}
}
}
Using a pixel format without subsampling should let me convert pixels without blending interfering, however ffmpeg still adds blending even to 4:4:4, which would distort the results. So instead I generated several AVIs with small dimensions (8x8) with fourcc YV12 pixel format (4:2:0), each frame containing one solid color. That came out to 256 AVI files, each with 256*256 frames.
Those AVIs were fed through ffmpeg and VirtualDub and converted to uncompressed RGB AVIs. This ffmepg command converts YCbCr to RGB AVI.
ffmpeg -i inYCbCr.avi -vcodec rawvideo -pix_fmt bgr24 outRgb.aviUnder VirtualDub's Video->Color Depth menu you can set the output pixel format.
A little script walked through every AVI and pulled out the first RGB pixel of each frame and associated it with the original YCbCr color.
At that point I had a table with 256^3 rows and 4 columns:
- Original YCbCr color
- RGB generated with the standard equation and floating-point math
- RGB generated with VirtualDub
- RGB generated with ffmpeg
Floating-point![]() | |
VirtualDub![]() | ffmpeg![]() |
Floating-point vs. VirtualDub![]() | Floating-point vs. ffmpeg![]() |
Now some numbers.
- VirtualDub has 1795792 pixels (11%) different from the floating-point conversion.
- ffmpeg has 10827725 pixels (65%) different from the floating-point conversion.

In the rare case someone has over an hour and 10GB to spare, along with various strange prerequisites, you can download the scripts used to generate these details.
*
FFmpeg version SVN-r22107, Copyright (c) 2000-2010 the FFmpeg developers
built on Feb 28 2010 06:11:15 with gcc 4.4.2
configuration: --enable-memalign-hack --cross-prefix=i686-mingw32- --cc=ccache-i686-mingw32-gcc --
arch=i686 --target-os=mingw32 --enable-runtime-cpudetect --enable-avisynth --enable-gpl --enable-ver
sion3 --enable-bzlib --enable-libgsm --enable-libfaad --enable-pthreads --enable-libvorbis --enable-
libtheora --enable-libspeex --enable-libmp3lame --enable-libopenjpeg --enable-libxvid --enable-libsc
hroedinger --enable-libx264 --enable-libopencore_amrwb --enable-libopencore_amrnb
libavutil 50. 9. 0 / 50. 9. 0
libavcodec 52.55. 0 / 52.55. 0
libavformat 52.54. 0 / 52.54. 0
libavdevice 52. 2. 0 / 52. 2. 0
libswscale 0.10. 0 / 0.10. 0
No comments:
Post a Comment