| 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/logging.h" | 21 #include "base/logging.h" |
| 21 #include "base/memory/scoped_ptr.h" | 22 #include "base/memory/scoped_ptr.h" |
| 22 #include "build/build_config.h" | 23 #include "build/build_config.h" |
| 23 #include "media/base/cpu_features.h" | |
| 24 #include "media/base/simd/convert_rgb_to_yuv.h" | 24 #include "media/base/simd/convert_rgb_to_yuv.h" |
| 25 #include "media/base/simd/convert_yuv_to_rgb.h" | 25 #include "media/base/simd/convert_yuv_to_rgb.h" |
| 26 #include "media/base/simd/filter_yuv.h" | 26 #include "media/base/simd/filter_yuv.h" |
| 27 | 27 |
| 28 #if defined(ARCH_CPU_X86_FAMILY) | 28 #if defined(ARCH_CPU_X86_FAMILY) |
| 29 #if defined(COMPILER_MSVC) | 29 #if defined(COMPILER_MSVC) |
| 30 #include <intrin.h> | 30 #include <intrin.h> |
| 31 #else | 31 #else |
| 32 #include <mmintrin.h> | 32 #include <mmintrin.h> |
| 33 #endif | 33 #endif |
| 34 #endif | 34 #endif |
| 35 | 35 |
| 36 namespace media { | 36 namespace media { |
| 37 | 37 |
| 38 static FilterYUVRowsProc ChooseFilterYUVRowsProc() { | 38 static FilterYUVRowsProc ChooseFilterYUVRowsProc() { |
| 39 #if defined(ARCH_CPU_X86_FAMILY) | 39 #if defined(ARCH_CPU_X86_FAMILY) |
| 40 if (hasSSE2()) | 40 base::CPU cpu; |
| 41 if (cpu.has_sse2()) |
| 41 return &FilterYUVRows_SSE2; | 42 return &FilterYUVRows_SSE2; |
| 42 if (hasMMX()) | 43 if (cpu.has_mmx()) |
| 43 return &FilterYUVRows_MMX; | 44 return &FilterYUVRows_MMX; |
| 44 #endif | 45 #endif |
| 45 return &FilterYUVRows_C; | 46 return &FilterYUVRows_C; |
| 46 } | 47 } |
| 47 | 48 |
| 48 static ConvertYUVToRGB32RowProc ChooseConvertYUVToRGB32RowProc() { | 49 static ConvertYUVToRGB32RowProc ChooseConvertYUVToRGB32RowProc() { |
| 49 #if defined(ARCH_CPU_X86_FAMILY) | 50 #if defined(ARCH_CPU_X86_FAMILY) |
| 50 if (hasSSE()) | 51 base::CPU cpu; |
| 52 if (cpu.has_sse()) |
| 51 return &ConvertYUVToRGB32Row_SSE; | 53 return &ConvertYUVToRGB32Row_SSE; |
| 52 if (hasMMX()) | 54 if (cpu.has_mmx()) |
| 53 return &ConvertYUVToRGB32Row_MMX; | 55 return &ConvertYUVToRGB32Row_MMX; |
| 54 #endif | 56 #endif |
| 55 return &ConvertYUVToRGB32Row_C; | 57 return &ConvertYUVToRGB32Row_C; |
| 56 } | 58 } |
| 57 | 59 |
| 58 static ScaleYUVToRGB32RowProc ChooseScaleYUVToRGB32RowProc() { | 60 static ScaleYUVToRGB32RowProc ChooseScaleYUVToRGB32RowProc() { |
| 59 #if defined(ARCH_CPU_X86_64) | 61 #if defined(ARCH_CPU_X86_64) |
| 60 // Use 64-bits version if possible. | 62 // Use 64-bits version if possible. |
| 61 return &ScaleYUVToRGB32Row_SSE2_X64; | 63 return &ScaleYUVToRGB32Row_SSE2_X64; |
| 62 #elif defined(ARCH_CPU_X86_FAMILY) | 64 #elif defined(ARCH_CPU_X86_FAMILY) |
| 65 base::CPU cpu; |
| 63 // Choose the best one on 32-bits system. | 66 // Choose the best one on 32-bits system. |
| 64 if (hasSSE()) | 67 if (cpu.has_sse()) |
| 65 return &ScaleYUVToRGB32Row_SSE; | 68 return &ScaleYUVToRGB32Row_SSE; |
| 66 if (hasMMX()) | 69 if (cpu.has_mmx()) |
| 67 return &ScaleYUVToRGB32Row_MMX; | 70 return &ScaleYUVToRGB32Row_MMX; |
| 68 #endif // defined(ARCH_CPU_X86_64) | 71 #endif // defined(ARCH_CPU_X86_64) |
| 69 return &ScaleYUVToRGB32Row_C; | 72 return &ScaleYUVToRGB32Row_C; |
| 70 } | 73 } |
| 71 | 74 |
| 72 static ScaleYUVToRGB32RowProc ChooseLinearScaleYUVToRGB32RowProc() { | 75 static ScaleYUVToRGB32RowProc ChooseLinearScaleYUVToRGB32RowProc() { |
| 73 #if defined(ARCH_CPU_X86_64) | 76 #if defined(ARCH_CPU_X86_64) |
| 74 // Use 64-bits version if possible. | 77 // Use 64-bits version if possible. |
| 75 return &LinearScaleYUVToRGB32Row_MMX_X64; | 78 return &LinearScaleYUVToRGB32Row_MMX_X64; |
| 76 #elif defined(ARCH_CPU_X86_FAMILY) | 79 #elif defined(ARCH_CPU_X86_FAMILY) |
| 80 base::CPU cpu; |
| 77 // 32-bits system. | 81 // 32-bits system. |
| 78 if (hasSSE()) | 82 if (cpu.has_sse()) |
| 79 return &LinearScaleYUVToRGB32Row_SSE; | 83 return &LinearScaleYUVToRGB32Row_SSE; |
| 80 if (hasMMX()) | 84 if (cpu.has_mmx()) |
| 81 return &LinearScaleYUVToRGB32Row_MMX; | 85 return &LinearScaleYUVToRGB32Row_MMX; |
| 82 #endif // defined(ARCH_CPU_X86_64) | 86 #endif // defined(ARCH_CPU_X86_64) |
| 83 return &LinearScaleYUVToRGB32Row_C; | 87 return &LinearScaleYUVToRGB32Row_C; |
| 84 } | 88 } |
| 85 | 89 |
| 86 // Empty SIMD registers state after using them. | 90 // Empty SIMD registers state after using them. |
| 87 void EmptyRegisterState() { | 91 void EmptyRegisterState() { |
| 88 #if defined(ARCH_CPU_X86_FAMILY) | 92 #if defined(ARCH_CPU_X86_FAMILY) |
| 89 static bool checked = false; | 93 static bool checked = false; |
| 90 static bool has_mmx = false; | 94 static bool has_mmx = false; |
| 91 if (!checked) { | 95 if (!checked) { |
| 92 has_mmx = hasMMX(); | 96 base::CPU cpu; |
| 97 has_mmx = cpu.has_mmx(); |
| 93 checked = true; | 98 checked = true; |
| 94 } | 99 } |
| 95 if (has_mmx) | 100 if (has_mmx) |
| 96 _mm_empty(); | 101 _mm_empty(); |
| 97 #endif | 102 #endif |
| 98 } | 103 } |
| 99 | 104 |
| 100 // 16.16 fixed point arithmetic | 105 // 16.16 fixed point arithmetic |
| 101 const int kFractionBits = 16; | 106 const int kFractionBits = 16; |
| 102 const int kFractionMax = 1 << kFractionBits; | 107 const int kFractionMax = 1 << kFractionBits; |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 static void (*convert_proc)(const uint8*, uint8*, uint8*, uint8*, | 443 static void (*convert_proc)(const uint8*, uint8*, uint8*, uint8*, |
| 439 int, int, int, int, int) = NULL; | 444 int, int, int, int, int) = NULL; |
| 440 if (!convert_proc) { | 445 if (!convert_proc) { |
| 441 #if defined(ARCH_CPU_ARM_FAMILY) | 446 #if defined(ARCH_CPU_ARM_FAMILY) |
| 442 // For ARM processors, always use C version. | 447 // For ARM processors, always use C version. |
| 443 // TODO(hclam): Implement a NEON version. | 448 // TODO(hclam): Implement a NEON version. |
| 444 convert_proc = &ConvertRGB32ToYUV_C; | 449 convert_proc = &ConvertRGB32ToYUV_C; |
| 445 #else | 450 #else |
| 446 // TODO(hclam): Switch to SSSE3 version when the cyan problem is solved. | 451 // TODO(hclam): Switch to SSSE3 version when the cyan problem is solved. |
| 447 // See: crbug.com/100462 | 452 // See: crbug.com/100462 |
| 448 if (hasSSE2()) | 453 base::CPU cpu; |
| 454 if (cpu.has_sse2()) |
| 449 convert_proc = &ConvertRGB32ToYUV_SSE2; | 455 convert_proc = &ConvertRGB32ToYUV_SSE2; |
| 450 else | 456 else |
| 451 convert_proc = &ConvertRGB32ToYUV_C; | 457 convert_proc = &ConvertRGB32ToYUV_C; |
| 452 #endif | 458 #endif |
| 453 } | 459 } |
| 454 | 460 |
| 455 convert_proc(rgbframe, yplane, uplane, vplane, width, height, | 461 convert_proc(rgbframe, yplane, uplane, vplane, width, height, |
| 456 rgbstride, ystride, uvstride); | 462 rgbstride, ystride, uvstride); |
| 457 } | 463 } |
| 458 | 464 |
| 459 void ConvertRGB24ToYUV(const uint8* rgbframe, | 465 void ConvertRGB24ToYUV(const uint8* rgbframe, |
| 460 uint8* yplane, | 466 uint8* yplane, |
| 461 uint8* uplane, | 467 uint8* uplane, |
| 462 uint8* vplane, | 468 uint8* vplane, |
| 463 int width, | 469 int width, |
| 464 int height, | 470 int height, |
| 465 int rgbstride, | 471 int rgbstride, |
| 466 int ystride, | 472 int ystride, |
| 467 int uvstride) { | 473 int uvstride) { |
| 468 #if defined(ARCH_CPU_ARM_FAMILY) | 474 #if defined(ARCH_CPU_ARM_FAMILY) |
| 469 ConvertRGB24ToYUV_C(rgbframe, yplane, uplane, vplane, width, height, | 475 ConvertRGB24ToYUV_C(rgbframe, yplane, uplane, vplane, width, height, |
| 470 rgbstride, ystride, uvstride); | 476 rgbstride, ystride, uvstride); |
| 471 #else | 477 #else |
| 472 static void (*convert_proc)(const uint8*, uint8*, uint8*, uint8*, | 478 static void (*convert_proc)(const uint8*, uint8*, uint8*, uint8*, |
| 473 int, int, int, int, int) = NULL; | 479 int, int, int, int, int) = NULL; |
| 474 if (!convert_proc) { | 480 if (!convert_proc) { |
| 475 if (hasSSSE3()) | 481 base::CPU cpu; |
| 482 if (cpu.has_ssse3()) |
| 476 convert_proc = &ConvertRGB24ToYUV_SSSE3; | 483 convert_proc = &ConvertRGB24ToYUV_SSSE3; |
| 477 else | 484 else |
| 478 convert_proc = &ConvertRGB24ToYUV_C; | 485 convert_proc = &ConvertRGB24ToYUV_C; |
| 479 } | 486 } |
| 480 convert_proc(rgbframe, yplane, uplane, vplane, width, height, | 487 convert_proc(rgbframe, yplane, uplane, vplane, width, height, |
| 481 rgbstride, ystride, uvstride); | 488 rgbstride, ystride, uvstride); |
| 482 #endif | 489 #endif |
| 483 } | 490 } |
| 484 | 491 |
| 485 void ConvertYUY2ToYUV(const uint8* src, | 492 void ConvertYUY2ToYUV(const uint8* src, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 int ystride, | 541 int ystride, |
| 535 int uvstride, | 542 int uvstride, |
| 536 int rgbstride, | 543 int rgbstride, |
| 537 YUVType yuv_type) { | 544 YUVType yuv_type) { |
| 538 #if defined(ARCH_CPU_ARM_FAMILY) | 545 #if defined(ARCH_CPU_ARM_FAMILY) |
| 539 ConvertYUVToRGB32_C(yplane, uplane, vplane, rgbframe, | 546 ConvertYUVToRGB32_C(yplane, uplane, vplane, rgbframe, |
| 540 width, height, ystride, uvstride, rgbstride, yuv_type); | 547 width, height, ystride, uvstride, rgbstride, yuv_type); |
| 541 #else | 548 #else |
| 542 static ConvertYUVToRGB32Proc convert_proc = NULL; | 549 static ConvertYUVToRGB32Proc convert_proc = NULL; |
| 543 if (!convert_proc) { | 550 if (!convert_proc) { |
| 544 if (hasSSE()) | 551 base::CPU cpu; |
| 552 if (cpu.has_sse()) |
| 545 convert_proc = &ConvertYUVToRGB32_SSE; | 553 convert_proc = &ConvertYUVToRGB32_SSE; |
| 546 else if (hasMMX()) | 554 else if (cpu.has_mmx()) |
| 547 convert_proc = &ConvertYUVToRGB32_MMX; | 555 convert_proc = &ConvertYUVToRGB32_MMX; |
| 548 else | 556 else |
| 549 convert_proc = &ConvertYUVToRGB32_C; | 557 convert_proc = &ConvertYUVToRGB32_C; |
| 550 } | 558 } |
| 551 | 559 |
| 552 convert_proc(yplane, uplane, vplane, rgbframe, | 560 convert_proc(yplane, uplane, vplane, rgbframe, |
| 553 width, height, ystride, uvstride, rgbstride, yuv_type); | 561 width, height, ystride, uvstride, rgbstride, yuv_type); |
| 554 #endif | 562 #endif |
| 555 } | 563 } |
| 556 | 564 |
| 557 } // namespace media | 565 } // namespace media |
| OLD | NEW |