author | Chris Double <chris.double@double.co.nz> |
Tue, 06 Apr 2010 12:57:56 +1200 | |
changeset 40463 | 67f4c546d40329f52d64b4290779008c670fbdfa |
parent 40462 | f9a11b9b2b9fd4d081708217fac56e29ec23e8db |
child 40464 | 2b9a4c865737a743e89d81ccff6931abd5ea6137 |
child 40475 | 56850227b2946ec32197a7cca78d2ea54156ee0b |
push id | 12615 |
push user | cdouble@mozilla.com |
push date | Tue, 06 Apr 2010 02:46:13 +0000 |
treeherder | mozilla-central@67f4c546d403 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc |
bugs | 551378 |
milestone | 1.9.3a4pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
|
--- a/gfx/layers/ImageLayers.h +++ b/gfx/layers/ImageLayers.h @@ -214,19 +214,16 @@ protected: * 4:2:0 - CbCr width and height is half that of Y. * * The color format is detected based on the height/width ratios * defined above. * * The Image that is rendered is the picture region defined by * mPicX, mPicY and mPicSize. The size of the rendered image is * mPicSize, not mYSize or mCbCrSize. - * - * Note: The color-conversion code does not currently support 4:4:4 - * and an error is raised in this case. See bug 551378. */ class THEBES_API PlanarYCbCrImage : public Image { public: struct Data { // Luminance buffer PRUint8* mYChannel; PRInt32 mYStride; gfxIntSize mYSize;
--- a/gfx/layers/basic/BasicImages.cpp +++ b/gfx/layers/basic/BasicImages.cpp @@ -130,17 +130,17 @@ BasicPlanarYCbCrImage::SetData(const Dat if (!mBuffer) { // out of memory return; } gfx::YUVType type = gfx::YV12; if (aData.mYSize.width == aData.mCbCrSize.width && aData.mYSize.height == aData.mCbCrSize.height) { - NS_ERROR("YCbCr 4:4:4 format not supported"); + type = gfx::YV24; } else if (aData.mYSize.width / 2 == aData.mCbCrSize.width && aData.mYSize.height == aData.mCbCrSize.height) { type = gfx::YV16; } else if (aData.mYSize.width / 2 == aData.mCbCrSize.width && aData.mYSize.height / 2 == aData.mCbCrSize.height ) { type = gfx::YV12;
--- a/gfx/ycbcr/README +++ b/gfx/ycbcr/README @@ -10,8 +10,10 @@ convert.patch: Change Chromium code to b Add runtime CPU detection for MMX Move default C implementation to work on all platforms. picture_region.patch: Change Chromium code to allow a picture region. The YUV conversion will convert within this picture region only. remove_scale.patch: Removes Chromium scaling code. + +yv24.patch: Adds YCbCr 4:4:4 support
--- a/gfx/ycbcr/update.sh +++ b/gfx/ycbcr/update.sh @@ -4,8 +4,9 @@ cp $1/media/base/yuv_convert.cc yuv_conv cp $1/media/base/yuv_row.h . cp $1/media/base/yuv_row_linux.cc yuv_row_linux.cpp cp $1/media/base/yuv_row_mac.cc yuv_row_mac.cpp cp $1/media/base/yuv_row_win.cc yuv_row_win.cpp cp $1/media/base/yuv_row_linux.cc yuv_row_c.cpp patch -p3 <convert.patch patch -p3 <picture_region.patch patch -p3 <remove_scale.patch +patch -p3 <yv24.patch
--- a/gfx/ycbcr/yuv_convert.cpp +++ b/gfx/ycbcr/yuv_convert.cpp @@ -6,16 +6,17 @@ // http://www.fourcc.org/yuv.php // The actual conversion is best described here // http://en.wikipedia.org/wiki/YUV // An article on optimizing YUV conversion using tables instead of multiplies // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf // // YV12 is a full plane of Y and a half height, half width chroma planes // YV16 is a full plane of Y and a full height, half width chroma planes +// YV24 is a full plane of Y and a full height, full width chroma planes // // ARGB pixel format is output, which on little endian is stored as BGRA. // The alpha is set to 255, allowing the application to use RGBA or RGB32. #include "yuv_convert.h" // Header for low level row functions. #include "yuv_row.h" @@ -33,50 +34,55 @@ void ConvertYCbCrToRGB32(const uint8* y_ int pic_x, int pic_y, int pic_width, int pic_height, int y_pitch, int uv_pitch, int rgb_pitch, YUVType yuv_type) { - unsigned int y_shift = yuv_type; - bool has_mmx = supports_mmx(); - bool odd_pic_x = pic_x % 2 != 0; + unsigned int y_shift = yuv_type == YV12 ? 1 : 0; + unsigned int x_shift = yuv_type == YV24 ? 0 : 1; + // There is no optimized YV24 MMX routine so we check for this and + // fall back to the C code. + bool has_mmx = supports_mmx() && yuv_type != YV24; + bool odd_pic_x = yuv_type != YV24 && pic_x % 2 != 0; int x_width = odd_pic_x ? pic_width - 1 : pic_width; for (int y = pic_y; y < pic_height + pic_y; ++y) { uint8* rgb_row = rgb_buf + (y - pic_y) * rgb_pitch; const uint8* y_ptr = y_buf + y * y_pitch + pic_x; - const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch + (pic_x >> 1); - const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch + (pic_x >> 1); + const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch + (pic_x >> x_shift); + const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch + (pic_x >> x_shift); if (odd_pic_x) { // Handle the single odd pixel manually and use the // fast routines for the remaining. FastConvertYUVToRGB32Row_C(y_ptr++, u_ptr++, v_ptr++, rgb_row, - 1); + 1, + x_shift); rgb_row += 4; } if (has_mmx) FastConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr, rgb_row, x_width); else FastConvertYUVToRGB32Row_C(y_ptr, u_ptr, v_ptr, rgb_row, - x_width); + x_width, + x_shift); } // MMX used for FastConvertYUVToRGB32Row requires emms instruction. if (has_mmx) EMMS(); } } // namespace gfx
--- a/gfx/ycbcr/yuv_convert.h +++ b/gfx/ycbcr/yuv_convert.h @@ -9,18 +9,19 @@ namespace mozilla { namespace gfx { // Type of YUV surface. // The value of these enums matter as they are used to shift vertical indices. enum YUVType { - YV16 = 0, // YV16 is half width and full height chroma channels. - YV12 = 1 // YV12 is half width and half height chroma channels. + YV12 = 0, // YV12 is half width and half height chroma channels. + YV16 = 1, // YV16 is half width and full height chroma channels. + YV24 = 2 // YV24 is full width and full height chroma channels. }; // Convert a frame of YUV to 32 bit ARGB. // Pass in YV16/YV12 depending on source format void ConvertYCbCrToRGB32(const uint8* yplane, const uint8* uplane, const uint8* vplane, uint8* rgbframe,
--- a/gfx/ycbcr/yuv_row.h +++ b/gfx/ycbcr/yuv_row.h @@ -20,17 +20,18 @@ void FastConvertYUVToRGB32Row(const uint const uint8* v_buf, uint8* rgb_buf, int width); void FastConvertYUVToRGB32Row_C(const uint8* y_buf, const uint8* u_buf, const uint8* v_buf, uint8* rgb_buf, - int width); + int width, + unsigned int x_shift); } // extern "C" // x64 uses MMX2 (SSE) so emms is not required. #if !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_PPC) #if defined(_MSC_VER) #define EMMS() __asm emms
--- a/gfx/ycbcr/yuv_row_c.cpp +++ b/gfx/ycbcr/yuv_row_c.cpp @@ -153,24 +153,29 @@ static inline void YuvPixel(uint8 y, (clip(C298a + cr) << 16) | (0xff000000); } void FastConvertYUVToRGB32Row_C(const uint8* y_buf, const uint8* u_buf, const uint8* v_buf, uint8* rgb_buf, - int width) { + int width, + unsigned int x_shift) { for (int x = 0; x < width; x += 2) { - uint8 u = u_buf[x >> 1]; - uint8 v = v_buf[x >> 1]; + uint8 u = u_buf[x >> x_shift]; + uint8 v = v_buf[x >> x_shift]; uint8 y0 = y_buf[x]; YuvPixel(y0, u, v, rgb_buf); if ((x + 1) < width) { uint8 y1 = y_buf[x + 1]; + if (x_shift == 0) { + u = u_buf[x + 1]; + v = v_buf[x + 1]; + } YuvPixel(y1, u, v, rgb_buf + 4); } rgb_buf += 8; // Advance 2 pixels. } } } // extern "C"
new file mode 100644 --- /dev/null +++ b/gfx/ycbcr/yv24.patch @@ -0,0 +1,172 @@ +diff --git a/gfx/ycbcr/yuv_convert.cpp b/gfx/ycbcr/yuv_convert.cpp +index b22e778..cdbb040 100644 +--- a/gfx/ycbcr/yuv_convert.cpp ++++ b/gfx/ycbcr/yuv_convert.cpp +@@ -6,16 +6,17 @@ + // http://www.fourcc.org/yuv.php + // The actual conversion is best described here + // http://en.wikipedia.org/wiki/YUV + // An article on optimizing YUV conversion using tables instead of multiplies + // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf + // + // YV12 is a full plane of Y and a half height, half width chroma planes + // YV16 is a full plane of Y and a full height, half width chroma planes ++// YV24 is a full plane of Y and a full height, full width chroma planes + // + // ARGB pixel format is output, which on little endian is stored as BGRA. + // The alpha is set to 255, allowing the application to use RGBA or RGB32. + + #include "yuv_convert.h" + + // Header for low level row functions. + #include "yuv_row.h" +@@ -33,50 +34,55 @@ void ConvertYCbCrToRGB32(const uint8* y_buf, + int pic_x, + int pic_y, + int pic_width, + int pic_height, + int y_pitch, + int uv_pitch, + int rgb_pitch, + YUVType yuv_type) { +- unsigned int y_shift = yuv_type; +- bool has_mmx = supports_mmx(); +- bool odd_pic_x = pic_x % 2 != 0; ++ unsigned int y_shift = yuv_type == YV12 ? 1 : 0; ++ unsigned int x_shift = yuv_type == YV24 ? 0 : 1; ++ // There is no optimized YV24 MMX routine so we check for this and ++ // fall back to the C code. ++ bool has_mmx = supports_mmx() && yuv_type != YV24; ++ bool odd_pic_x = yuv_type != YV24 && pic_x % 2 != 0; + int x_width = odd_pic_x ? pic_width - 1 : pic_width; + + for (int y = pic_y; y < pic_height + pic_y; ++y) { + uint8* rgb_row = rgb_buf + (y - pic_y) * rgb_pitch; + const uint8* y_ptr = y_buf + y * y_pitch + pic_x; +- const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch + (pic_x >> 1); +- const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch + (pic_x >> 1); ++ const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch + (pic_x >> x_shift); ++ const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch + (pic_x >> x_shift); + + if (odd_pic_x) { + // Handle the single odd pixel manually and use the + // fast routines for the remaining. + FastConvertYUVToRGB32Row_C(y_ptr++, + u_ptr++, + v_ptr++, + rgb_row, +- 1); ++ 1, ++ x_shift); + rgb_row += 4; + } + + if (has_mmx) + FastConvertYUVToRGB32Row(y_ptr, + u_ptr, + v_ptr, + rgb_row, + x_width); + else + FastConvertYUVToRGB32Row_C(y_ptr, + u_ptr, + v_ptr, + rgb_row, +- x_width); ++ x_width, ++ x_shift); + } + + // MMX used for FastConvertYUVToRGB32Row requires emms instruction. + if (has_mmx) + EMMS(); + } + + } // namespace gfx +diff --git a/gfx/ycbcr/yuv_convert.h b/gfx/ycbcr/yuv_convert.h +index 6735b77..15fe381 100644 +--- a/gfx/ycbcr/yuv_convert.h ++++ b/gfx/ycbcr/yuv_convert.h +@@ -9,18 +9,19 @@ + + namespace mozilla { + + namespace gfx { + + // Type of YUV surface. + // The value of these enums matter as they are used to shift vertical indices. + enum YUVType { +- YV16 = 0, // YV16 is half width and full height chroma channels. +- YV12 = 1 // YV12 is half width and half height chroma channels. ++ YV12 = 0, // YV12 is half width and half height chroma channels. ++ YV16 = 1, // YV16 is half width and full height chroma channels. ++ YV24 = 2 // YV24 is full width and full height chroma channels. + }; + + // Convert a frame of YUV to 32 bit ARGB. + // Pass in YV16/YV12 depending on source format + void ConvertYCbCrToRGB32(const uint8* yplane, + const uint8* uplane, + const uint8* vplane, + uint8* rgbframe, +diff --git a/gfx/ycbcr/yuv_row.h b/gfx/ycbcr/yuv_row.h +index 2a82972..d776dac 100644 +--- a/gfx/ycbcr/yuv_row.h ++++ b/gfx/ycbcr/yuv_row.h +@@ -20,17 +20,18 @@ void FastConvertYUVToRGB32Row(const uint8* y_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + + void FastConvertYUVToRGB32Row_C(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, +- int width); ++ int width, ++ unsigned int x_shift); + + + } // extern "C" + + // x64 uses MMX2 (SSE) so emms is not required. + #if !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_PPC) + #if defined(_MSC_VER) + #define EMMS() __asm emms +diff --git a/gfx/ycbcr/yuv_row_c.cpp b/gfx/ycbcr/yuv_row_c.cpp +index d3bdab4..36d9bda 100644 +--- a/gfx/ycbcr/yuv_row_c.cpp ++++ b/gfx/ycbcr/yuv_row_c.cpp +@@ -153,24 +153,29 @@ static inline void YuvPixel(uint8 y, + (clip(C298a + cr) << 16) | + (0xff000000); + } + + void FastConvertYUVToRGB32Row_C(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, +- int width) { ++ int width, ++ unsigned int x_shift) { + for (int x = 0; x < width; x += 2) { +- uint8 u = u_buf[x >> 1]; +- uint8 v = v_buf[x >> 1]; ++ uint8 u = u_buf[x >> x_shift]; ++ uint8 v = v_buf[x >> x_shift]; + uint8 y0 = y_buf[x]; + YuvPixel(y0, u, v, rgb_buf); + if ((x + 1) < width) { + uint8 y1 = y_buf[x + 1]; ++ if (x_shift == 0) { ++ u = u_buf[x + 1]; ++ v = v_buf[x + 1]; ++ } + YuvPixel(y1, u, v, rgb_buf + 4); + } + rgb_buf += 8; // Advance 2 pixels. + } + } + + } // extern "C" +