Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: media/base/yuv_convert.cc

Issue 591313008: Add support for Rec709 color space videos in software YUV convert path. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix matrix error Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This webpage shows layout of YV12 and other YUV formats 5 // This webpage shows layout of YV12 and other YUV formats
6 // http://www.fourcc.org/yuv.php 6 // http://www.fourcc.org/yuv.php
7 // The actual conversion is best described here 7 // The actual conversion is best described here
8 // http://en.wikipedia.org/wiki/YUV 8 // http://en.wikipedia.org/wiki/YUV
9 // An article on optimizing YUV conversion using tables instead of multiplies 9 // An article on optimizing YUV conversion using tables instead of multiplies
10 // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf 10 // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
11 // 11 //
12 // YV12 is a full plane of Y and a half height, half width chroma planes 12 // YV12 is a full plane of Y and a half height, half width chroma planes
13 // YV16 is a full plane of Y and a full height, half width chroma planes 13 // YV16 is a full plane of Y and a full height, half width chroma planes
14 // 14 //
15 // ARGB pixel format is output, which on little endian is stored as BGRA. 15 // ARGB pixel format is output, which on little endian is stored as BGRA.
16 // The alpha is set to 255, allowing the application to use RGBA or RGB32. 16 // The alpha is set to 255, allowing the application to use RGBA or RGB32.
17 17
18 #include "media/base/yuv_convert.h" 18 #include "media/base/yuv_convert.h"
19 19
20 #include "base/cpu.h" 20 #include "base/cpu.h"
21 #include "base/logging.h" 21 #include "base/logging.h"
22 #include "base/memory/aligned_memory.h"
22 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/scoped_ptr.h"
23 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 24 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
24 #include "build/build_config.h" 25 #include "build/build_config.h"
25 #include "media/base/simd/convert_rgb_to_yuv.h" 26 #include "media/base/simd/convert_rgb_to_yuv.h"
26 #include "media/base/simd/convert_yuv_to_rgb.h" 27 #include "media/base/simd/convert_yuv_to_rgb.h"
27 #include "media/base/simd/filter_yuv.h" 28 #include "media/base/simd/filter_yuv.h"
28 #include "media/base/simd/yuv_to_rgb_table.h"
29 29
30 #if defined(ARCH_CPU_X86_FAMILY) 30 #if defined(ARCH_CPU_X86_FAMILY)
31 #if defined(COMPILER_MSVC) 31 #if defined(COMPILER_MSVC)
32 #include <intrin.h> 32 #include <intrin.h>
33 #else 33 #else
34 #include <mmintrin.h> 34 #include <mmintrin.h>
35 #endif 35 #endif
36 #endif 36 #endif
37 37
38 // Assembly functions are declared without namespace. 38 // Assembly functions are declared without namespace.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 int, 78 int,
79 int, 79 int,
80 int, 80 int,
81 YUVType); 81 YUVType);
82 82
83 typedef void (*ConvertYUVToRGB32RowProc)(const uint8*, 83 typedef void (*ConvertYUVToRGB32RowProc)(const uint8*,
84 const uint8*, 84 const uint8*,
85 const uint8*, 85 const uint8*,
86 uint8*, 86 uint8*,
87 ptrdiff_t, 87 ptrdiff_t,
88 const int16[1024][4]); 88 const int16*);
89 89
90 typedef void (*ConvertYUVAToARGBRowProc)(const uint8*, 90 typedef void (*ConvertYUVAToARGBRowProc)(const uint8*,
91 const uint8*, 91 const uint8*,
92 const uint8*, 92 const uint8*,
93 const uint8*, 93 const uint8*,
94 uint8*, 94 uint8*,
95 ptrdiff_t, 95 ptrdiff_t,
96 const int16[1024][4]); 96 const int16*);
97 97
98 typedef void (*ScaleYUVToRGB32RowProc)(const uint8*, 98 typedef void (*ScaleYUVToRGB32RowProc)(const uint8*,
99 const uint8*, 99 const uint8*,
100 const uint8*, 100 const uint8*,
101 uint8*, 101 uint8*,
102 ptrdiff_t, 102 ptrdiff_t,
103 ptrdiff_t, 103 ptrdiff_t,
104 const int16[1024][4]); 104 const int16*);
105 105
106 static FilterYUVRowsProc g_filter_yuv_rows_proc_ = NULL; 106 static FilterYUVRowsProc g_filter_yuv_rows_proc_ = NULL;
107 static ConvertYUVToRGB32RowProc g_convert_yuv_to_rgb32_row_proc_ = NULL; 107 static ConvertYUVToRGB32RowProc g_convert_yuv_to_rgb32_row_proc_ = NULL;
108 static ScaleYUVToRGB32RowProc g_scale_yuv_to_rgb32_row_proc_ = NULL; 108 static ScaleYUVToRGB32RowProc g_scale_yuv_to_rgb32_row_proc_ = NULL;
109 static ScaleYUVToRGB32RowProc g_linear_scale_yuv_to_rgb32_row_proc_ = NULL; 109 static ScaleYUVToRGB32RowProc g_linear_scale_yuv_to_rgb32_row_proc_ = NULL;
110 static ConvertRGBToYUVProc g_convert_rgb32_to_yuv_proc_ = NULL; 110 static ConvertRGBToYUVProc g_convert_rgb32_to_yuv_proc_ = NULL;
111 static ConvertRGBToYUVProc g_convert_rgb24_to_yuv_proc_ = NULL; 111 static ConvertRGBToYUVProc g_convert_rgb24_to_yuv_proc_ = NULL;
112 static ConvertYUVToRGB32Proc g_convert_yuv_to_rgb32_proc_ = NULL; 112 static ConvertYUVToRGB32Proc g_convert_yuv_to_rgb32_proc_ = NULL;
113 static ConvertYUVAToARGBProc g_convert_yuva_to_argb_proc_ = NULL; 113 static ConvertYUVAToARGBProc g_convert_yuva_to_argb_proc_ = NULL;
114 114
115 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
116 static const int16* g_table_jpeg = 0;
117 static const int16* g_table_rec709 = 0;
118
115 // Empty SIMD registers state after using them. 119 // Empty SIMD registers state after using them.
116 void EmptyRegisterStateStub() {} 120 void EmptyRegisterStateStub() {}
117 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) 121 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
118 void EmptyRegisterStateIntrinsic() { _mm_empty(); } 122 void EmptyRegisterStateIntrinsic() { _mm_empty(); }
119 #endif 123 #endif
120 typedef void (*EmptyRegisterStateProc)(); 124 typedef void (*EmptyRegisterStateProc)();
121 static EmptyRegisterStateProc g_empty_register_state_proc_ = NULL; 125 static EmptyRegisterStateProc g_empty_register_state_proc_ = NULL;
122 126
123 // Get the appropriate value to bitshift by for vertical indices. 127 // Get the appropriate value to bitshift by for vertical indices.
124 int GetVerticalShift(YUVType type) { 128 int GetVerticalShift(YUVType type) {
125 switch (type) { 129 switch (type) {
126 case YV16: 130 case YV16:
127 return 0; 131 return 0;
128 case YV12: 132 case YV12:
129 case YV12J: 133 case YV12J:
134 case YV12HD:
130 return 1; 135 return 1;
131 } 136 }
132 NOTREACHED(); 137 NOTREACHED();
133 return 0; 138 return 0;
134 } 139 }
135 140
136 const int16 (&GetLookupTable(YUVType type))[1024][4] { 141 const int16* GetLookupTable(YUVType type) {
137 switch (type) { 142 switch (type) {
138 case YV12: 143 case YV12:
139 case YV16: 144 case YV16:
140 return kCoefficientsRgbY; 145 return g_table_rec601;
141 case YV12J: 146 case YV12J:
142 return kCoefficientsRgbY_JPEG; 147 return g_table_jpeg;
148 case YV12HD:
149 return g_table_rec709;
143 } 150 }
144 NOTREACHED(); 151 NOTREACHED();
145 return kCoefficientsRgbY; 152 return g_table_rec601;
153 }
154
155 const int16* CreateYUVToRGBTable(const double matrix[3][3], bool full_range) {
156 // We'll have 4 sub-tables that lie contiguous in memory, one for each of Y,
157 // U, V and A.
158 int kNumTables = 4;
159 // Each table has 256 rows (for all possible 8-bit values).
160 int kNumRows = 256;
161 // Each row has 4 columns, for contributions to each of R, G, B and A.
162 int kNumColumns = 4;
163 // Each element is a fixed-point (10.6) 16-bit signed value.
164 int kElementSize = sizeof(int16);
165
166 // An RGB value can be computed by looking up the Y, U, V and A values in each
167 // table, adding them up, dropping the lower 6 bits and clamping into [0,255].
168 // We align to 16 bytes to make it more SIMD-friendly.
169 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
170 kNumTables * kNumRows * kNumColumns * kElementSize, 16));
171
172 // Y needs an offset of -16 for color ranges that ignore the lower 16 values,
173 // U and V get -128 to put them in [-128, 127] from [0, 255].
174 int offsets[3] = {(full_range ? 0 : -16), -128, -128};
175
176 for (int i = 0; i < kNumRows; ++i) {
177 // Y, U, and V contributions to each of R, G, B and A.
178 for (int j = 0; j < 3; ++j) {
179 #if defined(OS_ANDROID)
180 // Android is RGBA.
181 table[(j * kNumRows + i) * kNumColumns + 0] =
182 matrix[j][0] * 64 * (i + offsets[j]) + 0.5;
183 table[(j * kNumRows + i) * kNumColumns + 1] =
184 matrix[j][1] * 64 * (i + offsets[j]) + 0.5;
185 table[(j * kNumRows + i) * kNumColumns + 2] =
186 matrix[j][2] * 64 * (i + offsets[j]) + 0.5;
187 #else
188 // Other platforms are BGRA.
189 table[(j * kNumRows + i) * kNumColumns + 0] =
190 matrix[j][2] * 64 * (i + offsets[j]) + 0.5;
191 table[(j * kNumRows + i) * kNumColumns + 1] =
192 matrix[j][1] * 64 * (i + offsets[j]) + 0.5;
193 table[(j * kNumRows + i) * kNumColumns + 2] =
194 matrix[j][0] * 64 * (i + offsets[j]) + 0.5;
195 #endif
196 // Alpha contributions from Y and V are always 0. U is set such that
197 // all values result in a full '255' alpha value.
198 table[(j * kNumRows + i) * kNumColumns + 3] = (j == 1) ? 256 * 64 - 1 : 0;
199 }
200 // And YUVA alpha is passed through as-is.
201 for (int k = 0; k < kNumTables; ++k)
202 table[((kNumTables - 1) * kNumRows + i) * kNumColumns + k] = i;
203 }
204
205 return table;
146 } 206 }
147 207
148 void InitializeCPUSpecificYUVConversions() { 208 void InitializeCPUSpecificYUVConversions() {
149 CHECK(!g_filter_yuv_rows_proc_); 209 CHECK(!g_filter_yuv_rows_proc_);
150 CHECK(!g_convert_yuv_to_rgb32_row_proc_); 210 CHECK(!g_convert_yuv_to_rgb32_row_proc_);
151 CHECK(!g_scale_yuv_to_rgb32_row_proc_); 211 CHECK(!g_scale_yuv_to_rgb32_row_proc_);
152 CHECK(!g_linear_scale_yuv_to_rgb32_row_proc_); 212 CHECK(!g_linear_scale_yuv_to_rgb32_row_proc_);
153 CHECK(!g_convert_rgb32_to_yuv_proc_); 213 CHECK(!g_convert_rgb32_to_yuv_proc_);
154 CHECK(!g_convert_rgb24_to_yuv_proc_); 214 CHECK(!g_convert_rgb24_to_yuv_proc_);
155 CHECK(!g_convert_yuv_to_rgb32_proc_); 215 CHECK(!g_convert_yuv_to_rgb32_proc_);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 #endif 256 #endif
197 257
198 base::CPU cpu; 258 base::CPU cpu;
199 if (cpu.has_ssse3()) { 259 if (cpu.has_ssse3()) {
200 g_convert_rgb24_to_yuv_proc_ = &ConvertRGB24ToYUV_SSSE3; 260 g_convert_rgb24_to_yuv_proc_ = &ConvertRGB24ToYUV_SSSE3;
201 261
202 // TODO(hclam): Add ConvertRGB32ToYUV_SSSE3 when the cyan problem is solved. 262 // TODO(hclam): Add ConvertRGB32ToYUV_SSSE3 when the cyan problem is solved.
203 // See: crbug.com/100462 263 // See: crbug.com/100462
204 } 264 }
205 #endif 265 #endif
266
267 // Initialize YUV conversion lookup tables.
268
269 // SD Rec601 YUV->RGB matrix, see http://www.fourcc.org/fccyvrgb.php
270 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.
271 {1.164, 1.164, 1.164}, {0.0, -0.391, 2.018}, {1.596, -0.813, 0.0},
272 };
273
274 // JPEG table, values from above link.
275 static const double kJPEGConvertMatrix[3][3] = {
276 {1.0, 1.0, 1.0}, {0.0, -0.34414, 1.772}, {1.402, -0.71414, 0.0},
277 };
278
279 // Rec709 "HD" color space, values from:
280 // http://www.equasys.de/colorconversion.html
281 static const double kRec709ConvertMatrix[3][3] = {
282 {1.164, 1.164, 1.164}, {0.0, -0.213, 2.112}, {1.793, -0.533, 0.0},
283 };
284
285 g_table_rec601 = CreateYUVToRGBTable(kRec601ConvertMatrix, false);
286 g_table_jpeg = CreateYUVToRGBTable(kJPEGConvertMatrix, true);
287 g_table_rec709 = CreateYUVToRGBTable(kRec709ConvertMatrix, false);
206 } 288 }
207 289
208 // Empty SIMD registers state after using them. 290 // Empty SIMD registers state after using them.
209 void EmptyRegisterState() { g_empty_register_state_proc_(); } 291 void EmptyRegisterState() { g_empty_register_state_proc_(); }
210 292
211 // 16.16 fixed point arithmetic 293 // 16.16 fixed point arithmetic
212 const int kFractionBits = 16; 294 const int kFractionBits = 16;
213 const int kFractionMax = 1 << kFractionBits; 295 const int kFractionMax = 1 << kFractionBits;
214 const int kFractionMask = ((1 << kFractionBits) - 1); 296 const int kFractionMask = ((1 << kFractionBits) - 1);
215 297
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 ubuf[uv_source_width] = ubuf[uv_source_width - 1]; 452 ubuf[uv_source_width] = ubuf[uv_source_width - 1];
371 vbuf[uv_source_width] = vbuf[uv_source_width - 1]; 453 vbuf[uv_source_width] = vbuf[uv_source_width - 1];
372 } else { 454 } else {
373 // Offset by 1/2 pixel for center sampling. 455 // Offset by 1/2 pixel for center sampling.
374 int source_y = (source_y_subpixel + (kFractionMax / 2)) >> kFractionBits; 456 int source_y = (source_y_subpixel + (kFractionMax / 2)) >> kFractionBits;
375 y_ptr = y_buf + source_y * y_pitch; 457 y_ptr = y_buf + source_y * y_pitch;
376 u_ptr = u_buf + (source_y >> y_shift) * uv_pitch; 458 u_ptr = u_buf + (source_y >> y_shift) * uv_pitch;
377 v_ptr = v_buf + (source_y >> y_shift) * uv_pitch; 459 v_ptr = v_buf + (source_y >> y_shift) * uv_pitch;
378 } 460 }
379 if (source_dx == kFractionMax) { // Not scaled 461 if (source_dx == kFractionMax) { // Not scaled
380 g_convert_yuv_to_rgb32_row_proc_( 462 g_convert_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, width,
381 y_ptr, u_ptr, v_ptr, dest_pixel, width, kCoefficientsRgbY); 463 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.
382 } else { 464 } else {
383 if (filter & FILTER_BILINEAR_H) { 465 if (filter & FILTER_BILINEAR_H) {
384 g_linear_scale_yuv_to_rgb32_row_proc_(y_ptr, 466 g_linear_scale_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel,
385 u_ptr, 467 width, source_dx,
386 v_ptr, 468 GetLookupTable(yuv_type));
387 dest_pixel,
388 width,
389 source_dx,
390 kCoefficientsRgbY);
391 } else { 469 } else {
392 g_scale_yuv_to_rgb32_row_proc_(y_ptr, 470 g_scale_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, width,
393 u_ptr, 471 source_dx, GetLookupTable(yuv_type));
394 v_ptr,
395 dest_pixel,
396 width,
397 source_dx,
398 kCoefficientsRgbY);
399 } 472 }
400 } 473 }
401 } 474 }
402 475
403 g_empty_register_state_proc_(); 476 g_empty_register_state_proc_();
404 } 477 }
405 478
406 // Scale a frame of YV12 to 32 bit ARGB for a specific rectangle. 479 // Scale a frame of YV12 to 32 bit ARGB for a specific rectangle.
407 void ScaleYUVToRGB32WithRect(const uint8* y_buf, 480 void ScaleYUVToRGB32WithRect(const uint8* y_buf,
408 const uint8* u_buf, 481 const uint8* u_buf,
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
526 uint8 fraction = (source_top & kFractionMask) >> 8; 599 uint8 fraction = (source_top & kFractionMask) >> 8;
527 g_filter_yuv_rows_proc_( 600 g_filter_yuv_rows_proc_(
528 y_temp + source_y_left, y0_ptr, y1_ptr, source_y_width, fraction); 601 y_temp + source_y_left, y0_ptr, y1_ptr, source_y_width, fraction);
529 g_filter_yuv_rows_proc_( 602 g_filter_yuv_rows_proc_(
530 u_temp + source_uv_left, u0_ptr, u1_ptr, source_uv_width, fraction); 603 u_temp + source_uv_left, u0_ptr, u1_ptr, source_uv_width, fraction);
531 g_filter_yuv_rows_proc_( 604 g_filter_yuv_rows_proc_(
532 v_temp + source_uv_left, v0_ptr, v1_ptr, source_uv_width, fraction); 605 v_temp + source_uv_left, v0_ptr, v1_ptr, source_uv_width, fraction);
533 606
534 // Perform horizontal interpolation and color space conversion. 607 // Perform horizontal interpolation and color space conversion.
535 // TODO(hclam): Use the MMX version after more testing. 608 // TODO(hclam): Use the MMX version after more testing.
536 LinearScaleYUVToRGB32RowWithRange_C(y_temp, 609 LinearScaleYUVToRGB32RowWithRange_C(y_temp, u_temp, v_temp, rgb_buf,
537 u_temp, 610 dest_rect_width, source_left, x_step,
538 v_temp, 611 GetLookupTable(YV12));
539 rgb_buf,
540 dest_rect_width,
541 source_left,
542 x_step,
543 kCoefficientsRgbY);
544 } else { 612 } else {
545 // If the frame is too large then we linear scale a single row. 613 // If the frame is too large then we linear scale a single row.
546 LinearScaleYUVToRGB32RowWithRange_C(y0_ptr, 614 LinearScaleYUVToRGB32RowWithRange_C(y0_ptr, u0_ptr, v0_ptr, rgb_buf,
547 u0_ptr, 615 dest_rect_width, source_left, x_step,
548 v0_ptr, 616 GetLookupTable(YV12));
549 rgb_buf,
550 dest_rect_width,
551 source_left,
552 x_step,
553 kCoefficientsRgbY);
554 } 617 }
555 618
556 // Advance vertically in the source and destination image. 619 // Advance vertically in the source and destination image.
557 source_top += y_step; 620 source_top += y_step;
558 rgb_buf += rgb_pitch; 621 rgb_buf += rgb_pitch;
559 } 622 }
560 623
561 g_empty_register_state_proc_(); 624 g_empty_register_state_proc_();
562 } 625 }
563 626
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 width, 749 width,
687 height, 750 height,
688 ystride, 751 ystride,
689 uvstride, 752 uvstride,
690 astride, 753 astride,
691 rgbstride, 754 rgbstride,
692 yuv_type); 755 yuv_type);
693 } 756 }
694 757
695 } // namespace media 758 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698