mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 14:15:30 +00:00
Bug 551378 - Implement 4:4:4 colorspace conversion in YCbCr layers code - r=roc
--HG-- extra : rebase_source : 05f17f0a4c855a12c89ad925ede78166655456e7
This commit is contained in:
parent
987e0e6294
commit
c8b2c0065e
@ -219,9 +219,6 @@ protected:
|
||||
* 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:
|
||||
|
@ -135,7 +135,7 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
|
||||
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) {
|
||||
|
@ -15,3 +15,5 @@ picture_region.patch: Change Chromium code to allow a picture region.
|
||||
picture region only.
|
||||
|
||||
remove_scale.patch: Removes Chromium scaling code.
|
||||
|
||||
yv24.patch: Adds YCbCr 4:4:4 support
|
||||
|
@ -9,3 +9,4 @@ 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
|
||||
|
@ -11,6 +11,7 @@
|
||||
//
|
||||
// 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.
|
||||
@ -38,16 +39,19 @@ void ConvertYCbCrToRGB32(const uint8* y_buf,
|
||||
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
|
||||
@ -56,7 +60,8 @@ void ConvertYCbCrToRGB32(const uint8* y_buf,
|
||||
u_ptr++,
|
||||
v_ptr++,
|
||||
rgb_row,
|
||||
1);
|
||||
1,
|
||||
x_shift);
|
||||
rgb_row += 4;
|
||||
}
|
||||
|
||||
@ -71,7 +76,8 @@ void ConvertYCbCrToRGB32(const uint8* y_buf,
|
||||
u_ptr,
|
||||
v_ptr,
|
||||
rgb_row,
|
||||
x_width);
|
||||
x_width,
|
||||
x_shift);
|
||||
}
|
||||
|
||||
// MMX used for FastConvertYUVToRGB32Row requires emms instruction.
|
||||
|
@ -14,8 +14,9 @@ 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.
|
||||
|
@ -25,7 +25,8 @@ 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"
|
||||
|
@ -158,14 +158,19 @@ 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.
|
||||
|
172
gfx/ycbcr/yv24.patch
Normal file
172
gfx/ycbcr/yv24.patch
Normal file
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user