OLD | NEW |
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/scoped_ptr.h" | 22 #include "base/memory/scoped_ptr.h" |
23 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 23 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
24 #include "build/build_config.h" | 24 #include "build/build_config.h" |
25 #include "media/base/simd/convert_rgb_to_yuv.h" | 25 #include "media/base/simd/convert_rgb_to_yuv.h" |
26 #include "media/base/simd/convert_yuv_to_rgb.h" | 26 #include "media/base/simd/convert_yuv_to_rgb.h" |
27 #include "media/base/simd/filter_yuv.h" | 27 #include "media/base/simd/filter_yuv.h" |
28 #include "media/base/simd/yuv_to_rgb_table.h" | |
29 | 28 |
30 #if defined(ARCH_CPU_X86_FAMILY) | 29 #if defined(ARCH_CPU_X86_FAMILY) |
31 #if defined(COMPILER_MSVC) | 30 #if defined(COMPILER_MSVC) |
32 #include <intrin.h> | 31 #include <intrin.h> |
33 #else | 32 #else |
34 #include <mmintrin.h> | 33 #include <mmintrin.h> |
35 #endif | 34 #endif |
36 #endif | 35 #endif |
37 | 36 |
38 // Assembly functions are declared without namespace. | 37 // Assembly functions are declared without namespace. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 int, | 72 int, |
74 int, | 73 int, |
75 int, | 74 int, |
76 int, | 75 int, |
77 YUVType); | 76 YUVType); |
78 | 77 |
79 typedef void (*ConvertYUVToRGB32RowProc)(const uint8*, | 78 typedef void (*ConvertYUVToRGB32RowProc)(const uint8*, |
80 const uint8*, | 79 const uint8*, |
81 const uint8*, | 80 const uint8*, |
82 uint8*, | 81 uint8*, |
83 ptrdiff_t, | 82 ptrdiff_t); |
84 const int16[1024][4]); | |
85 | 83 |
86 typedef void (*ConvertYUVAToARGBRowProc)(const uint8*, | 84 typedef void (*ConvertYUVAToARGBRowProc)(const uint8*, |
87 const uint8*, | 85 const uint8*, |
88 const uint8*, | 86 const uint8*, |
89 const uint8*, | 87 const uint8*, |
90 uint8*, | 88 uint8*, |
91 ptrdiff_t, | 89 ptrdiff_t); |
92 const int16[1024][4]); | |
93 | 90 |
94 typedef void (*ScaleYUVToRGB32RowProc)(const uint8*, | 91 typedef void (*ScaleYUVToRGB32RowProc)(const uint8*, |
95 const uint8*, | 92 const uint8*, |
96 const uint8*, | 93 const uint8*, |
97 uint8*, | 94 uint8*, |
98 ptrdiff_t, | 95 ptrdiff_t, |
99 ptrdiff_t, | 96 ptrdiff_t); |
100 const int16[1024][4]); | |
101 | 97 |
102 static FilterYUVRowsProc g_filter_yuv_rows_proc_ = NULL; | 98 static FilterYUVRowsProc g_filter_yuv_rows_proc_ = NULL; |
103 static ConvertYUVToRGB32RowProc g_convert_yuv_to_rgb32_row_proc_ = NULL; | 99 static ConvertYUVToRGB32RowProc g_convert_yuv_to_rgb32_row_proc_ = NULL; |
104 static ScaleYUVToRGB32RowProc g_scale_yuv_to_rgb32_row_proc_ = NULL; | 100 static ScaleYUVToRGB32RowProc g_scale_yuv_to_rgb32_row_proc_ = NULL; |
105 static ScaleYUVToRGB32RowProc g_linear_scale_yuv_to_rgb32_row_proc_ = NULL; | 101 static ScaleYUVToRGB32RowProc g_linear_scale_yuv_to_rgb32_row_proc_ = NULL; |
106 static ConvertRGBToYUVProc g_convert_rgb32_to_yuv_proc_ = NULL; | 102 static ConvertRGBToYUVProc g_convert_rgb32_to_yuv_proc_ = NULL; |
107 static ConvertRGBToYUVProc g_convert_rgb24_to_yuv_proc_ = NULL; | 103 static ConvertRGBToYUVProc g_convert_rgb24_to_yuv_proc_ = NULL; |
108 static ConvertYUVToRGB32Proc g_convert_yuv_to_rgb32_proc_ = NULL; | 104 static ConvertYUVToRGB32Proc g_convert_yuv_to_rgb32_proc_ = NULL; |
109 static ConvertYUVAToARGBProc g_convert_yuva_to_argb_proc_ = NULL; | 105 static ConvertYUVAToARGBProc g_convert_yuva_to_argb_proc_ = NULL; |
110 | 106 |
111 // Empty SIMD registers state after using them. | 107 // Empty SIMD registers state after using them. |
112 void EmptyRegisterStateStub() {} | 108 void EmptyRegisterStateStub() {} |
113 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) | 109 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) |
114 void EmptyRegisterStateIntrinsic() { _mm_empty(); } | 110 void EmptyRegisterStateIntrinsic() { _mm_empty(); } |
115 #endif | 111 #endif |
116 typedef void (*EmptyRegisterStateProc)(); | 112 typedef void (*EmptyRegisterStateProc)(); |
117 static EmptyRegisterStateProc g_empty_register_state_proc_ = NULL; | 113 static EmptyRegisterStateProc g_empty_register_state_proc_ = NULL; |
118 | 114 |
119 // Get the appropriate value to bitshift by for vertical indices. | |
120 int GetVerticalShift(YUVType type) { | |
121 switch (type) { | |
122 case YV16: | |
123 return 0; | |
124 case YV12: | |
125 case YV12J: | |
126 return 1; | |
127 } | |
128 NOTREACHED(); | |
129 return 0; | |
130 } | |
131 | |
132 const int16 (&GetLookupTable(YUVType type))[1024][4] { | |
133 switch (type) { | |
134 case YV12: | |
135 case YV16: | |
136 return kCoefficientsRgbY; | |
137 case YV12J: | |
138 return kCoefficientsRgbY_JPEG; | |
139 } | |
140 NOTREACHED(); | |
141 return kCoefficientsRgbY; | |
142 } | |
143 | |
144 void InitializeCPUSpecificYUVConversions() { | 115 void InitializeCPUSpecificYUVConversions() { |
145 CHECK(!g_filter_yuv_rows_proc_); | 116 CHECK(!g_filter_yuv_rows_proc_); |
146 CHECK(!g_convert_yuv_to_rgb32_row_proc_); | 117 CHECK(!g_convert_yuv_to_rgb32_row_proc_); |
147 CHECK(!g_scale_yuv_to_rgb32_row_proc_); | 118 CHECK(!g_scale_yuv_to_rgb32_row_proc_); |
148 CHECK(!g_linear_scale_yuv_to_rgb32_row_proc_); | 119 CHECK(!g_linear_scale_yuv_to_rgb32_row_proc_); |
149 CHECK(!g_convert_rgb32_to_yuv_proc_); | 120 CHECK(!g_convert_rgb32_to_yuv_proc_); |
150 CHECK(!g_convert_rgb24_to_yuv_proc_); | 121 CHECK(!g_convert_rgb24_to_yuv_proc_); |
151 CHECK(!g_convert_yuv_to_rgb32_proc_); | 122 CHECK(!g_convert_yuv_to_rgb32_proc_); |
152 CHECK(!g_convert_yuva_to_argb_proc_); | 123 CHECK(!g_convert_yuva_to_argb_proc_); |
153 CHECK(!g_empty_register_state_proc_); | 124 CHECK(!g_empty_register_state_proc_); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 // Helps performance on CPU with 16K L1 cache. | 215 // Helps performance on CPU with 16K L1 cache. |
245 // Large enough for 3830x2160 and 30" displays which are 2560x1600. | 216 // Large enough for 3830x2160 and 30" displays which are 2560x1600. |
246 const int kFilterBufferSize = 4096; | 217 const int kFilterBufferSize = 4096; |
247 // Disable filtering if the screen is too big (to avoid buffer overflows). | 218 // Disable filtering if the screen is too big (to avoid buffer overflows). |
248 // This should never happen to regular users: they don't have monitors | 219 // This should never happen to regular users: they don't have monitors |
249 // wider than 4096 pixels. | 220 // wider than 4096 pixels. |
250 // TODO(fbarchard): Allow rotated videos to filter. | 221 // TODO(fbarchard): Allow rotated videos to filter. |
251 if (source_width > kFilterBufferSize || view_rotate) | 222 if (source_width > kFilterBufferSize || view_rotate) |
252 filter = FILTER_NONE; | 223 filter = FILTER_NONE; |
253 | 224 |
254 unsigned int y_shift = GetVerticalShift(yuv_type); | 225 unsigned int y_shift = yuv_type; |
255 // Diagram showing origin and direction of source sampling. | 226 // Diagram showing origin and direction of source sampling. |
256 // ->0 4<- | 227 // ->0 4<- |
257 // 7 3 | 228 // 7 3 |
258 // | 229 // |
259 // 6 5 | 230 // 6 5 |
260 // ->1 2<- | 231 // ->1 2<- |
261 // Rotations that start at right side of image. | 232 // Rotations that start at right side of image. |
262 if ((view_rotate == ROTATE_180) || (view_rotate == ROTATE_270) || | 233 if ((view_rotate == ROTATE_180) || (view_rotate == ROTATE_270) || |
263 (view_rotate == MIRROR_ROTATE_0) || (view_rotate == MIRROR_ROTATE_90)) { | 234 (view_rotate == MIRROR_ROTATE_0) || (view_rotate == MIRROR_ROTATE_90)) { |
264 y_buf += source_width - 1; | 235 y_buf += source_width - 1; |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 ubuf[uv_source_width] = ubuf[uv_source_width - 1]; | 347 ubuf[uv_source_width] = ubuf[uv_source_width - 1]; |
377 vbuf[uv_source_width] = vbuf[uv_source_width - 1]; | 348 vbuf[uv_source_width] = vbuf[uv_source_width - 1]; |
378 } else { | 349 } else { |
379 // Offset by 1/2 pixel for center sampling. | 350 // Offset by 1/2 pixel for center sampling. |
380 int source_y = (source_y_subpixel + (kFractionMax / 2)) >> kFractionBits; | 351 int source_y = (source_y_subpixel + (kFractionMax / 2)) >> kFractionBits; |
381 y_ptr = y_buf + source_y * y_pitch; | 352 y_ptr = y_buf + source_y * y_pitch; |
382 u_ptr = u_buf + (source_y >> y_shift) * uv_pitch; | 353 u_ptr = u_buf + (source_y >> y_shift) * uv_pitch; |
383 v_ptr = v_buf + (source_y >> y_shift) * uv_pitch; | 354 v_ptr = v_buf + (source_y >> y_shift) * uv_pitch; |
384 } | 355 } |
385 if (source_dx == kFractionMax) { // Not scaled | 356 if (source_dx == kFractionMax) { // Not scaled |
386 g_convert_yuv_to_rgb32_row_proc_( | 357 g_convert_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, width); |
387 y_ptr, u_ptr, v_ptr, dest_pixel, width, kCoefficientsRgbY); | |
388 } else { | 358 } else { |
389 if (filter & FILTER_BILINEAR_H) { | 359 if (filter & FILTER_BILINEAR_H) { |
390 g_linear_scale_yuv_to_rgb32_row_proc_(y_ptr, | 360 g_linear_scale_yuv_to_rgb32_row_proc_( |
391 u_ptr, | 361 y_ptr, u_ptr, v_ptr, dest_pixel, width, source_dx); |
392 v_ptr, | |
393 dest_pixel, | |
394 width, | |
395 source_dx, | |
396 kCoefficientsRgbY); | |
397 } else { | 362 } else { |
398 g_scale_yuv_to_rgb32_row_proc_(y_ptr, | 363 g_scale_yuv_to_rgb32_row_proc_( |
399 u_ptr, | 364 y_ptr, u_ptr, v_ptr, dest_pixel, width, source_dx); |
400 v_ptr, | |
401 dest_pixel, | |
402 width, | |
403 source_dx, | |
404 kCoefficientsRgbY); | |
405 } | 365 } |
406 } | 366 } |
407 } | 367 } |
408 | 368 |
409 g_empty_register_state_proc_(); | 369 g_empty_register_state_proc_(); |
410 } | 370 } |
411 | 371 |
412 // Scale a frame of YV12 to 32 bit ARGB for a specific rectangle. | 372 // Scale a frame of YV12 to 32 bit ARGB for a specific rectangle. |
413 void ScaleYUVToRGB32WithRect(const uint8* y_buf, | 373 void ScaleYUVToRGB32WithRect(const uint8* y_buf, |
414 const uint8* u_buf, | 374 const uint8* u_buf, |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 v_temp + source_uv_left, v0_ptr, v1_ptr, source_uv_width, fraction); | 498 v_temp + source_uv_left, v0_ptr, v1_ptr, source_uv_width, fraction); |
539 | 499 |
540 // Perform horizontal interpolation and color space conversion. | 500 // Perform horizontal interpolation and color space conversion. |
541 // TODO(hclam): Use the MMX version after more testing. | 501 // TODO(hclam): Use the MMX version after more testing. |
542 LinearScaleYUVToRGB32RowWithRange_C(y_temp, | 502 LinearScaleYUVToRGB32RowWithRange_C(y_temp, |
543 u_temp, | 503 u_temp, |
544 v_temp, | 504 v_temp, |
545 rgb_buf, | 505 rgb_buf, |
546 dest_rect_width, | 506 dest_rect_width, |
547 source_left, | 507 source_left, |
548 x_step, | 508 x_step); |
549 kCoefficientsRgbY); | |
550 } else { | 509 } else { |
551 // If the frame is too large then we linear scale a single row. | 510 // If the frame is too large then we linear scale a single row. |
552 LinearScaleYUVToRGB32RowWithRange_C(y0_ptr, | 511 LinearScaleYUVToRGB32RowWithRange_C(y0_ptr, |
553 u0_ptr, | 512 u0_ptr, |
554 v0_ptr, | 513 v0_ptr, |
555 rgb_buf, | 514 rgb_buf, |
556 dest_rect_width, | 515 dest_rect_width, |
557 source_left, | 516 source_left, |
558 x_step, | 517 x_step); |
559 kCoefficientsRgbY); | |
560 } | 518 } |
561 | 519 |
562 // Advance vertically in the source and destination image. | 520 // Advance vertically in the source and destination image. |
563 source_top += y_step; | 521 source_top += y_step; |
564 rgb_buf += rgb_pitch; | 522 rgb_buf += rgb_pitch; |
565 } | 523 } |
566 | 524 |
567 g_empty_register_state_proc_(); | 525 g_empty_register_state_proc_(); |
568 } | 526 } |
569 | 527 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 width, | 650 width, |
693 height, | 651 height, |
694 ystride, | 652 ystride, |
695 uvstride, | 653 uvstride, |
696 astride, | 654 astride, |
697 rgbstride, | 655 rgbstride, |
698 yuv_type); | 656 yuv_type); |
699 } | 657 } |
700 | 658 |
701 } // namespace media | 659 } // namespace media |
OLD | NEW |