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