| Index: media/base/yuv_convert.cc
|
| diff --git a/media/base/yuv_convert.cc b/media/base/yuv_convert.cc
|
| index cbf7f57622fdeb909f1d801c9c15a1c12a6ba9b6..7b4586ac07cfa556e55474325faf6eae14aa652a 100644
|
| --- a/media/base/yuv_convert.cc
|
| +++ b/media/base/yuv_convert.cc
|
| @@ -17,151 +17,93 @@
|
|
|
| #include "media/base/yuv_convert.h"
|
|
|
| +#include "base/logging.h"
|
| #include "build/build_config.h"
|
| #include "media/base/cpu_features.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/yuv_convert_internal.h"
|
| #include "media/base/yuv_row.h"
|
|
|
| -#if USE_MMX
|
| -#if defined(_MSC_VER)
|
| +#if defined(ARCH_CPU_X86_FAMILY)
|
| +#if defined(COMPILER_MSVC)
|
| #include <intrin.h>
|
| #else
|
| #include <mmintrin.h>
|
| #endif
|
| #endif
|
|
|
| -#if USE_SSE2
|
| -#include <emmintrin.h>
|
| -#endif
|
| -
|
| namespace media {
|
|
|
| -// 16.16 fixed point arithmetic
|
| -const int kFractionBits = 16;
|
| -const int kFractionMax = 1 << kFractionBits;
|
| -const int kFractionMask = ((1 << kFractionBits) - 1);
|
| -
|
| -// Convert a frame of YUV to 32 bit ARGB.
|
| -void ConvertYUVToRGB32(const uint8* y_buf,
|
| - const uint8* u_buf,
|
| - const uint8* v_buf,
|
| - uint8* rgb_buf,
|
| - int width,
|
| - int height,
|
| - int y_pitch,
|
| - int uv_pitch,
|
| - int rgb_pitch,
|
| - YUVType yuv_type) {
|
| - unsigned int y_shift = yuv_type;
|
| - for (int y = 0; y < height; ++y) {
|
| - uint8* rgb_row = rgb_buf + y * rgb_pitch;
|
| - const uint8* y_ptr = y_buf + y * y_pitch;
|
| - const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch;
|
| - const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch;
|
| -
|
| - FastConvertYUVToRGB32Row(y_ptr,
|
| - u_ptr,
|
| - v_ptr,
|
| - rgb_row,
|
| - width);
|
| - }
|
| -
|
| - // MMX used for FastConvertYUVToRGB32Row requires emms instruction.
|
| - EMMS();
|
| +static FilterYUVRowsProc ChooseFilterYUVRowsProc() {
|
| +#if defined(ARCH_CPU_X86_FAMILY)
|
| + if (hasSSE2())
|
| + return &FilterYUVRows_SSE2;
|
| + if (hasMMX())
|
| + return &FilterYUVRows_MMX;
|
| +#endif
|
| + return &FilterYUVRows_C;
|
| }
|
|
|
| -#if USE_SSE2
|
| -// FilterRows combines two rows of the image using linear interpolation.
|
| -// SSE2 version does 16 pixels at a time
|
| -
|
| -static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
|
| - int source_width, int source_y_fraction) {
|
| - __m128i zero = _mm_setzero_si128();
|
| - __m128i y1_fraction = _mm_set1_epi16(source_y_fraction);
|
| - __m128i y0_fraction = _mm_set1_epi16(256 - source_y_fraction);
|
| -
|
| - const __m128i* y0_ptr128 = reinterpret_cast<const __m128i*>(y0_ptr);
|
| - const __m128i* y1_ptr128 = reinterpret_cast<const __m128i*>(y1_ptr);
|
| - __m128i* dest128 = reinterpret_cast<__m128i*>(ybuf);
|
| - __m128i* end128 = reinterpret_cast<__m128i*>(ybuf + source_width);
|
| -
|
| - do {
|
| - __m128i y0 = _mm_loadu_si128(y0_ptr128);
|
| - __m128i y1 = _mm_loadu_si128(y1_ptr128);
|
| - __m128i y2 = _mm_unpackhi_epi8(y0, zero);
|
| - __m128i y3 = _mm_unpackhi_epi8(y1, zero);
|
| - y0 = _mm_unpacklo_epi8(y0, zero);
|
| - y1 = _mm_unpacklo_epi8(y1, zero);
|
| - y0 = _mm_mullo_epi16(y0, y0_fraction);
|
| - y1 = _mm_mullo_epi16(y1, y1_fraction);
|
| - y2 = _mm_mullo_epi16(y2, y0_fraction);
|
| - y3 = _mm_mullo_epi16(y3, y1_fraction);
|
| - y0 = _mm_add_epi16(y0, y1);
|
| - y2 = _mm_add_epi16(y2, y3);
|
| - y0 = _mm_srli_epi16(y0, 8);
|
| - y2 = _mm_srli_epi16(y2, 8);
|
| - y0 = _mm_packus_epi16(y0, y2);
|
| - *dest128++ = y0;
|
| - ++y0_ptr128;
|
| - ++y1_ptr128;
|
| - } while (dest128 < end128);
|
| +static ConvertYUVToRGB32RowProc ChooseConvertYUVToRGB32RowProc() {
|
| +#if defined(ARCH_CPU_X86_FAMILY)
|
| + if (hasSSE())
|
| + return &ConvertYUVToRGB32Row_SSE;
|
| + if (hasMMX())
|
| + return &ConvertYUVToRGB32Row_MMX;
|
| +#endif
|
| + return &ConvertYUVToRGB32Row_C;
|
| }
|
| -#elif USE_MMX
|
| -// MMX version does 8 pixels at a time
|
| -static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
|
| - int source_width, int source_y_fraction) {
|
| - __m64 zero = _mm_setzero_si64();
|
| - __m64 y1_fraction = _mm_set1_pi16(source_y_fraction);
|
| - __m64 y0_fraction = _mm_set1_pi16(256 - source_y_fraction);
|
| -
|
| - const __m64* y0_ptr64 = reinterpret_cast<const __m64*>(y0_ptr);
|
| - const __m64* y1_ptr64 = reinterpret_cast<const __m64*>(y1_ptr);
|
| - __m64* dest64 = reinterpret_cast<__m64*>(ybuf);
|
| - __m64* end64 = reinterpret_cast<__m64*>(ybuf + source_width);
|
| -
|
| - do {
|
| - __m64 y0 = *y0_ptr64++;
|
| - __m64 y1 = *y1_ptr64++;
|
| - __m64 y2 = _mm_unpackhi_pi8(y0, zero);
|
| - __m64 y3 = _mm_unpackhi_pi8(y1, zero);
|
| - y0 = _mm_unpacklo_pi8(y0, zero);
|
| - y1 = _mm_unpacklo_pi8(y1, zero);
|
| - y0 = _mm_mullo_pi16(y0, y0_fraction);
|
| - y1 = _mm_mullo_pi16(y1, y1_fraction);
|
| - y2 = _mm_mullo_pi16(y2, y0_fraction);
|
| - y3 = _mm_mullo_pi16(y3, y1_fraction);
|
| - y0 = _mm_add_pi16(y0, y1);
|
| - y2 = _mm_add_pi16(y2, y3);
|
| - y0 = _mm_srli_pi16(y0, 8);
|
| - y2 = _mm_srli_pi16(y2, 8);
|
| - y0 = _mm_packs_pu16(y0, y2);
|
| - *dest64++ = y0;
|
| - } while (dest64 < end64);
|
| +
|
| +static ScaleYUVToRGB32RowProc ChooseScaleYUVToRGB32RowProc() {
|
| +#if defined(ARCH_CPU_X86_FAMILY)
|
| +#if defined(ARCH_CPU_X86_64)
|
| + // Use 64-bits version if possible.
|
| + return &ScaleYUVToRGB32Row_SSE2_X64;
|
| +#endif
|
| + // Choose the best one on 32-bits system.
|
| + if (hasSSE())
|
| + return &ScaleYUVToRGB32Row_SSE;
|
| + if (hasMMX())
|
| + return &ScaleYUVToRGB32Row_MMX;
|
| +#endif
|
| + return &ScaleYUVToRGB32Row_C;
|
| }
|
| -#else // no MMX or SSE2
|
| -// C version does 8 at a time to mimic MMX code
|
| -static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr,
|
| - int source_width, int source_y_fraction) {
|
| - int y1_fraction = source_y_fraction;
|
| - int y0_fraction = 256 - y1_fraction;
|
| - uint8* end = ybuf + source_width;
|
| - do {
|
| - ybuf[0] = (y0_ptr[0] * y0_fraction + y1_ptr[0] * y1_fraction) >> 8;
|
| - ybuf[1] = (y0_ptr[1] * y0_fraction + y1_ptr[1] * y1_fraction) >> 8;
|
| - ybuf[2] = (y0_ptr[2] * y0_fraction + y1_ptr[2] * y1_fraction) >> 8;
|
| - ybuf[3] = (y0_ptr[3] * y0_fraction + y1_ptr[3] * y1_fraction) >> 8;
|
| - ybuf[4] = (y0_ptr[4] * y0_fraction + y1_ptr[4] * y1_fraction) >> 8;
|
| - ybuf[5] = (y0_ptr[5] * y0_fraction + y1_ptr[5] * y1_fraction) >> 8;
|
| - ybuf[6] = (y0_ptr[6] * y0_fraction + y1_ptr[6] * y1_fraction) >> 8;
|
| - ybuf[7] = (y0_ptr[7] * y0_fraction + y1_ptr[7] * y1_fraction) >> 8;
|
| - y0_ptr += 8;
|
| - y1_ptr += 8;
|
| - ybuf += 8;
|
| - } while (ybuf < end);
|
| +
|
| +static ScaleYUVToRGB32RowProc ChooseLinearScaleYUVToRGB32RowProc() {
|
| +#if defined(ARCH_CPU_X86_FAMILY)
|
| +#if defined(ARCH_CPU_X86_64)
|
| + // Use 64-bits version if possible.
|
| + return &LinearScaleYUVToRGB32Row_MMX_X64;
|
| +#endif
|
| + // 32-bits system.
|
| + if (hasSSE())
|
| + return &LinearScaleYUVToRGB32Row_SSE;
|
| + if (hasMMX())
|
| + return &LinearScaleYUVToRGB32Row_MMX;
|
| +#endif
|
| + return &LinearScaleYUVToRGB32Row_C;
|
| }
|
| +
|
| +// Empty SIMD registers state after using them.
|
| +void EmptyRegisterState() {
|
| +#if defined(ARCH_CPU_X86_FAMILY)
|
| + static bool checked = false;
|
| + static bool has_mmx = false;
|
| + if (!checked) {
|
| + has_mmx = hasMMX();
|
| + checked = true;
|
| + }
|
| + if (has_mmx)
|
| + _mm_empty();
|
| #endif
|
| +}
|
|
|
| +// 16.16 fixed point arithmetic
|
| +const int kFractionBits = 16;
|
| +const int kFractionMax = 1 << kFractionBits;
|
| +const int kFractionMask = ((1 << kFractionBits) - 1);
|
|
|
| // Scale a frame of YUV to 32 bit ARGB.
|
| void ScaleYUVToRGB32(const uint8* y_buf,
|
| @@ -178,6 +120,20 @@ void ScaleYUVToRGB32(const uint8* y_buf,
|
| YUVType yuv_type,
|
| Rotate view_rotate,
|
| ScaleFilter filter) {
|
| + static FilterYUVRowsProc filter_proc = NULL;
|
| + static ConvertYUVToRGB32RowProc convert_proc = NULL;
|
| + static ScaleYUVToRGB32RowProc scale_proc = NULL;
|
| + static ScaleYUVToRGB32RowProc linear_scale_proc = NULL;
|
| +
|
| + if (!filter_proc)
|
| + filter_proc = ChooseFilterYUVRowsProc();
|
| + if (!convert_proc)
|
| + convert_proc = ChooseConvertYUVToRGB32RowProc();
|
| + if (!scale_proc)
|
| + scale_proc = ChooseScaleYUVToRGB32RowProc();
|
| + if (!linear_scale_proc)
|
| + linear_scale_proc = ChooseLinearScaleYUVToRGB32RowProc();
|
| +
|
| // Handle zero sized sources and destinations.
|
| if ((yuv_type == YV12 && (source_width < 2 || source_height < 2)) ||
|
| (yuv_type == YV16 && (source_width < 2 || source_height < 1)) ||
|
| @@ -225,9 +181,6 @@ void ScaleYUVToRGB32(const uint8* y_buf,
|
|
|
| int source_dx = source_width * kFractionMax / width;
|
| int source_dy = source_height * kFractionMax / height;
|
| -#if USE_MMX && defined(_MSC_VER)
|
| - int source_dx_uv = source_dx;
|
| -#endif
|
|
|
| if ((view_rotate == ROTATE_90) ||
|
| (view_rotate == ROTATE_270)) {
|
| @@ -240,9 +193,6 @@ void ScaleYUVToRGB32(const uint8* y_buf,
|
| int original_dx = source_dx;
|
| int original_dy = source_dy;
|
| source_dx = ((original_dy >> kFractionBits) * y_pitch) << kFractionBits;
|
| -#if USE_MMX && defined(_MSC_VER)
|
| - source_dx_uv = ((original_dy >> kFractionBits) * uv_pitch) << kFractionBits;
|
| -#endif
|
| source_dy = original_dx;
|
| if (view_rotate == ROTATE_90) {
|
| y_pitch = -1;
|
| @@ -294,7 +244,7 @@ void ScaleYUVToRGB32(const uint8* y_buf,
|
| if (filter & media::FILTER_BILINEAR_V) {
|
| if (yscale_fixed != kFractionMax &&
|
| source_y_fraction && ((source_y + 1) < source_height)) {
|
| - FilterRows(ybuf, y0_ptr, y1_ptr, source_width, source_y_fraction);
|
| + filter_proc(ybuf, y0_ptr, y1_ptr, source_width, source_y_fraction);
|
| } else {
|
| memcpy(ybuf, y0_ptr, source_width);
|
| }
|
| @@ -304,8 +254,8 @@ void ScaleYUVToRGB32(const uint8* y_buf,
|
| if (yscale_fixed != kFractionMax &&
|
| source_uv_fraction &&
|
| (((source_y >> y_shift) + 1) < (source_height >> y_shift))) {
|
| - FilterRows(ubuf, u0_ptr, u1_ptr, uv_source_width, source_uv_fraction);
|
| - FilterRows(vbuf, v0_ptr, v1_ptr, uv_source_width, source_uv_fraction);
|
| + filter_proc(ubuf, u0_ptr, u1_ptr, uv_source_width, source_uv_fraction);
|
| + filter_proc(vbuf, v0_ptr, v1_ptr, uv_source_width, source_uv_fraction);
|
| } else {
|
| memcpy(ubuf, u0_ptr, uv_source_width);
|
| memcpy(vbuf, v0_ptr, uv_source_width);
|
| @@ -316,41 +266,17 @@ void ScaleYUVToRGB32(const uint8* y_buf,
|
| vbuf[uv_source_width] = vbuf[uv_source_width - 1];
|
| }
|
| if (source_dx == kFractionMax) { // Not scaled
|
| - FastConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
| - dest_pixel, width);
|
| + convert_proc(y_ptr, u_ptr, v_ptr, dest_pixel, width);
|
| } else {
|
| if (filter & FILTER_BILINEAR_H) {
|
| - LinearScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
| - dest_pixel, width, source_dx);
|
| - } else {
|
| -// Specialized scalers and rotation.
|
| -#if USE_MMX && defined(_MSC_VER)
|
| - if (width == (source_width * 2)) {
|
| - DoubleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
| - dest_pixel, width);
|
| - } else if ((source_dx & kFractionMask) == 0) {
|
| - // Scaling by integer scale factor. ie half.
|
| - ConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
| - dest_pixel, width,
|
| - source_dx >> kFractionBits);
|
| - } else if (source_dx_uv == source_dx) { // Not rotated.
|
| - ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
| - dest_pixel, width, source_dx);
|
| - } else {
|
| - RotateConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
| - dest_pixel, width,
|
| - source_dx >> kFractionBits,
|
| - source_dx_uv >> kFractionBits);
|
| - }
|
| -#else
|
| - ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
| - dest_pixel, width, source_dx);
|
| -#endif
|
| + linear_scale_proc(y_ptr, u_ptr, v_ptr, dest_pixel, width, source_dx);
|
| + } else {
|
| + scale_proc(y_ptr, u_ptr, v_ptr, dest_pixel, width, source_dx);
|
| }
|
| }
|
| }
|
| - // MMX used for FastConvertYUVToRGB32Row and FilterRows requires emms.
|
| - EMMS();
|
| +
|
| + EmptyRegisterState();
|
| }
|
|
|
| void ConvertRGB32ToYUV(const uint8* rgbframe,
|
| @@ -370,7 +296,6 @@ void ConvertRGB32ToYUV(const uint8* rgbframe,
|
| // TODO(hclam): Implement a NEON version.
|
| convert_proc = &ConvertRGB32ToYUV_C;
|
| #else
|
| - // For x86 processors, check if SSSE3 (or SSE2) is supported.
|
| if (hasSSE2())
|
| convert_proc = &ConvertRGB32ToYUV_SSE2;
|
| else
|
| @@ -403,4 +328,34 @@ void ConvertYUY2ToYUV(const uint8* src,
|
| int height) {
|
| ConvertYUY2ToYUV_C(src, yplane, uplane, vplane, width, height);
|
| }
|
| +
|
| +void ConvertYUVToRGB32(const uint8* yplane,
|
| + const uint8* uplane,
|
| + const uint8* vplane,
|
| + uint8* rgbframe,
|
| + int width,
|
| + int height,
|
| + int ystride,
|
| + int uvstride,
|
| + int rgbstride,
|
| + YUVType yuv_type) {
|
| +#if defined(ARCH_CPU_ARM_FAMILY)
|
| + ConvertYUVToRGB32_C(yplane, uplane, vplane, rgbframe,
|
| + width, height, ystride, uvstride, rgbstride, yuv_type);
|
| +#else
|
| + static ConvertYUVToRGB32Proc convert_proc = NULL;
|
| + if (!convert_proc) {
|
| + if (hasSSE())
|
| + convert_proc = &ConvertYUVToRGB32_SSE;
|
| + else if (hasMMX())
|
| + convert_proc = &ConvertYUVToRGB32_MMX;
|
| + else
|
| + convert_proc = &ConvertYUVToRGB32_C;
|
| + }
|
| +
|
| + convert_proc(yplane, uplane, vplane, rgbframe,
|
| + width, height, ystride, uvstride, rgbstride, yuv_type);
|
| +#endif
|
| +}
|
| +
|
| } // namespace media
|
|
|