Chromium Code Reviews| Index: media/base/yuv_convert.cc |
| diff --git a/media/base/yuv_convert.cc b/media/base/yuv_convert.cc |
| index 431183abb398c71db8e8fae9e605bf69e2597b8a..b035a85edc7d3b53c6fc4e97066c3d5b87fbeb5a 100644 |
| --- a/media/base/yuv_convert.cc |
| +++ b/media/base/yuv_convert.cc |
| @@ -19,13 +19,13 @@ |
| #include "base/cpu.h" |
| #include "base/logging.h" |
| +#include "base/memory/aligned_memory.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| #include "build/build_config.h" |
| #include "media/base/simd/convert_rgb_to_yuv.h" |
| #include "media/base/simd/convert_yuv_to_rgb.h" |
| #include "media/base/simd/filter_yuv.h" |
| -#include "media/base/simd/yuv_to_rgb_table.h" |
| #if defined(ARCH_CPU_X86_FAMILY) |
| #if defined(COMPILER_MSVC) |
| @@ -85,7 +85,7 @@ typedef void (*ConvertYUVToRGB32RowProc)(const uint8*, |
| const uint8*, |
| uint8*, |
| ptrdiff_t, |
| - const int16[1024][4]); |
| + const int16*); |
| typedef void (*ConvertYUVAToARGBRowProc)(const uint8*, |
| const uint8*, |
| @@ -93,7 +93,7 @@ typedef void (*ConvertYUVAToARGBRowProc)(const uint8*, |
| const uint8*, |
| uint8*, |
| ptrdiff_t, |
| - const int16[1024][4]); |
| + const int16*); |
| typedef void (*ScaleYUVToRGB32RowProc)(const uint8*, |
| const uint8*, |
| @@ -101,7 +101,7 @@ typedef void (*ScaleYUVToRGB32RowProc)(const uint8*, |
| uint8*, |
| ptrdiff_t, |
| ptrdiff_t, |
| - const int16[1024][4]); |
| + const int16*); |
| static FilterYUVRowsProc g_filter_yuv_rows_proc_ = NULL; |
| static ConvertYUVToRGB32RowProc g_convert_yuv_to_rgb32_row_proc_ = NULL; |
| @@ -112,6 +112,10 @@ static ConvertRGBToYUVProc g_convert_rgb24_to_yuv_proc_ = NULL; |
| static ConvertYUVToRGB32Proc g_convert_yuv_to_rgb32_proc_ = NULL; |
| static ConvertYUVAToARGBProc g_convert_yuva_to_argb_proc_ = NULL; |
| +static const int16* g_table_rec601 = 0; |
|
DaleCurtis
2015/01/08 01:36:57
NULL here and below.
rileya (GONE FROM CHROMIUM)
2015/01/12 21:46:20
I made each table a lazy instance, so no longer re
|
| +static const int16* g_table_jpeg = 0; |
| +static const int16* g_table_rec709 = 0; |
| + |
| // Empty SIMD registers state after using them. |
| void EmptyRegisterStateStub() {} |
| #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) |
| @@ -127,22 +131,78 @@ int GetVerticalShift(YUVType type) { |
| return 0; |
| case YV12: |
| case YV12J: |
| + case YV12HD: |
| return 1; |
| } |
| NOTREACHED(); |
| return 0; |
| } |
| -const int16 (&GetLookupTable(YUVType type))[1024][4] { |
| +const int16* GetLookupTable(YUVType type) { |
| switch (type) { |
| case YV12: |
| case YV16: |
| - return kCoefficientsRgbY; |
| + return g_table_rec601; |
| case YV12J: |
| - return kCoefficientsRgbY_JPEG; |
| + return g_table_jpeg; |
| + case YV12HD: |
| + return g_table_rec709; |
| } |
| NOTREACHED(); |
| - return kCoefficientsRgbY; |
| + return g_table_rec601; |
| +} |
| + |
| +const int16* CreateYUVToRGBTable(const double matrix[3][3], bool full_range) { |
| + // We'll have 4 sub-tables that lie contiguous in memory, one for each of Y, |
| + // U, V and A. |
| + int kNumTables = 4; |
| + // Each table has 256 rows (for all possible 8-bit values). |
| + int kNumRows = 256; |
| + // Each row has 4 columns, for contributions to each of R, G, B and A. |
| + int kNumColumns = 4; |
| + // Each element is a fixed-point (10.6) 16-bit signed value. |
| + int kElementSize = sizeof(int16); |
| + |
| + // An RGB value can be computed by looking up the Y, U, V and A values in each |
| + // table, adding them up, dropping the lower 6 bits and clamping into [0,255]. |
| + // We align to 16 bytes to make it more SIMD-friendly. |
| + int16* table = static_cast<int16*>(base::AlignedAlloc( |
|
DaleCurtis
2015/01/08 01:36:57
You'll either need to use a LazyInstance::Leaky wh
rileya (GONE FROM CHROMIUM)
2015/01/12 21:46:20
I made each table a LazyInstance::Leaky of a struc
|
| + kNumTables * kNumRows * kNumColumns * kElementSize, 16)); |
| + |
| + // Y needs an offset of -16 for color ranges that ignore the lower 16 values, |
| + // U and V get -128 to put them in [-128, 127] from [0, 255]. |
| + int offsets[3] = {(full_range ? 0 : -16), -128, -128}; |
| + |
| + for (int i = 0; i < kNumRows; ++i) { |
| + // Y, U, and V contributions to each of R, G, B and A. |
| + for (int j = 0; j < 3; ++j) { |
| +#if defined(OS_ANDROID) |
| + // Android is RGBA. |
| + table[(j * kNumRows + i) * kNumColumns + 0] = |
| + matrix[j][0] * 64 * (i + offsets[j]) + 0.5; |
| + table[(j * kNumRows + i) * kNumColumns + 1] = |
| + matrix[j][1] * 64 * (i + offsets[j]) + 0.5; |
| + table[(j * kNumRows + i) * kNumColumns + 2] = |
| + matrix[j][2] * 64 * (i + offsets[j]) + 0.5; |
| +#else |
| + // Other platforms are BGRA. |
| + table[(j * kNumRows + i) * kNumColumns + 0] = |
| + matrix[j][2] * 64 * (i + offsets[j]) + 0.5; |
| + table[(j * kNumRows + i) * kNumColumns + 1] = |
| + matrix[j][1] * 64 * (i + offsets[j]) + 0.5; |
| + table[(j * kNumRows + i) * kNumColumns + 2] = |
| + matrix[j][0] * 64 * (i + offsets[j]) + 0.5; |
| +#endif |
| + // Alpha contributions from Y and V are always 0. U is set such that |
| + // all values result in a full '255' alpha value. |
| + table[(j * kNumRows + i) * kNumColumns + 3] = (j == 1) ? 256 * 64 - 1 : 0; |
| + } |
| + // And YUVA alpha is passed through as-is. |
| + for (int k = 0; k < kNumTables; ++k) |
| + table[((kNumTables - 1) * kNumRows + i) * kNumColumns + k] = i; |
| + } |
| + |
| + return table; |
| } |
| void InitializeCPUSpecificYUVConversions() { |
| @@ -203,6 +263,28 @@ void InitializeCPUSpecificYUVConversions() { |
| // See: crbug.com/100462 |
| } |
| #endif |
| + |
| + // Initialize YUV conversion lookup tables. |
| + |
| + // SD Rec601 YUV->RGB matrix, see http://www.fourcc.org/fccyvrgb.php |
| + static const double kRec601ConvertMatrix[3][3] = { |
|
DaleCurtis
2015/01/08 01:36:57
const is fine for all of these. Typically we want
rileya (GONE FROM CHROMIUM)
2015/01/12 21:46:20
Done.
|
| + {1.164, 1.164, 1.164}, {0.0, -0.391, 2.018}, {1.596, -0.813, 0.0}, |
| + }; |
| + |
| + // JPEG table, values from above link. |
| + static const double kJPEGConvertMatrix[3][3] = { |
| + {1.0, 1.0, 1.0}, {0.0, -0.34414, 1.772}, {1.402, -0.71414, 0.0}, |
| + }; |
| + |
| + // Rec709 "HD" color space, values from: |
| + // http://www.equasys.de/colorconversion.html |
| + static const double kRec709ConvertMatrix[3][3] = { |
| + {1.164, 1.164, 1.164}, {0.0, -0.213, 2.112}, {1.793, -0.533, 0.0}, |
| + }; |
| + |
| + g_table_rec601 = CreateYUVToRGBTable(kRec601ConvertMatrix, false); |
| + g_table_jpeg = CreateYUVToRGBTable(kJPEGConvertMatrix, true); |
| + g_table_rec709 = CreateYUVToRGBTable(kRec709ConvertMatrix, false); |
| } |
| // Empty SIMD registers state after using them. |
| @@ -377,25 +459,16 @@ void ScaleYUVToRGB32(const uint8* y_buf, |
| v_ptr = v_buf + (source_y >> y_shift) * uv_pitch; |
| } |
| if (source_dx == kFractionMax) { // Not scaled |
| - g_convert_yuv_to_rgb32_row_proc_( |
| - y_ptr, u_ptr, v_ptr, dest_pixel, width, kCoefficientsRgbY); |
| + g_convert_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, width, |
| + GetLookupTable(yuv_type)); |
|
DaleCurtis
2015/01/08 01:36:57
Call this one outside of the loops? Ditto for all
rileya (GONE FROM CHROMIUM)
2015/01/12 21:46:21
Done.
|
| } else { |
| if (filter & FILTER_BILINEAR_H) { |
| - g_linear_scale_yuv_to_rgb32_row_proc_(y_ptr, |
| - u_ptr, |
| - v_ptr, |
| - dest_pixel, |
| - width, |
| - source_dx, |
| - kCoefficientsRgbY); |
| + g_linear_scale_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, |
| + width, source_dx, |
| + GetLookupTable(yuv_type)); |
| } else { |
| - g_scale_yuv_to_rgb32_row_proc_(y_ptr, |
| - u_ptr, |
| - v_ptr, |
| - dest_pixel, |
| - width, |
| - source_dx, |
| - kCoefficientsRgbY); |
| + g_scale_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, width, |
| + source_dx, GetLookupTable(yuv_type)); |
| } |
| } |
| } |
| @@ -533,24 +606,14 @@ void ScaleYUVToRGB32WithRect(const uint8* y_buf, |
| // Perform horizontal interpolation and color space conversion. |
| // TODO(hclam): Use the MMX version after more testing. |
| - LinearScaleYUVToRGB32RowWithRange_C(y_temp, |
| - u_temp, |
| - v_temp, |
| - rgb_buf, |
| - dest_rect_width, |
| - source_left, |
| - x_step, |
| - kCoefficientsRgbY); |
| + LinearScaleYUVToRGB32RowWithRange_C(y_temp, u_temp, v_temp, rgb_buf, |
| + dest_rect_width, source_left, x_step, |
| + GetLookupTable(YV12)); |
| } else { |
| // If the frame is too large then we linear scale a single row. |
| - LinearScaleYUVToRGB32RowWithRange_C(y0_ptr, |
| - u0_ptr, |
| - v0_ptr, |
| - rgb_buf, |
| - dest_rect_width, |
| - source_left, |
| - x_step, |
| - kCoefficientsRgbY); |
| + LinearScaleYUVToRGB32RowWithRange_C(y0_ptr, u0_ptr, v0_ptr, rgb_buf, |
| + dest_rect_width, source_left, x_step, |
| + GetLookupTable(YV12)); |
| } |
| // Advance vertically in the source and destination image. |