summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-21 09:19:15 +0000
committerfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-21 09:19:15 +0000
commit3a78a8e8278cf6ac28ecb0ed59afbf540c288e48 (patch)
tree35678e74df1f53b867b3d53bdd6e2cba19a814f8 /media
parent1912cfef3207b30c2691a3f71c524a69ac969b19 (diff)
downloadchromium_src-3a78a8e8278cf6ac28ecb0ed59afbf540c288e48.zip
chromium_src-3a78a8e8278cf6ac28ecb0ed59afbf540c288e48.tar.gz
chromium_src-3a78a8e8278cf6ac28ecb0ed59afbf540c288e48.tar.bz2
YUV to RGB with arbitrary scaling.
Semi-optimized C code achieving 33 ms for 1080 double sized or 9 ms with openmp enabled. Special case half size which is much faster. Future versions will support mirror and perhaps rotate. (mirror is free) Future versions will be MMX assembly for speed. Review URL: http://codereview.chromium.org/67278 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14092 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/yuv_convert.cc59
-rw-r--r--media/base/yuv_scale.cc260
-rw-r--r--media/base/yuv_scale.h41
-rw-r--r--media/base/yuv_scale_unittest.cc119
-rw-r--r--media/media.gyp4
5 files changed, 453 insertions, 30 deletions
diff --git a/media/base/yuv_convert.cc b/media/base/yuv_convert.cc
index 1c5ff785d..dd40c9f 100644
--- a/media/base/yuv_convert.cc
+++ b/media/base/yuv_convert.cc
@@ -14,15 +14,15 @@
// On older, non-SIMD architectures, floating point arithmetic is much
// slower than using fixed-point arithmetic, so an alternative formulation
// is:
-// C = Y' - 16
-// D = U - 128
-// E = V - 128
+// c = Y' - 16
+// d = U - 128
+// e = V - 128
// Using the previous coefficients and noting that clip() denotes clipping a
// value to the range of 0 to 255, the following formulae provide the
// conversion from Y'UV to RGB (NTSC version):
-// R = clip((298 x C + 409 x E + 128) >> 8)
-// G = clip((298 x C - 100 x D - 208 x E + 128) >> 8)
-// B = clip((298 x C + 516 x D + 128) >> 8)
+// R = clip((298 x c + 409 x e + 128) >> 8)
+// G = clip((298 x c - 100 x d - 208 x e + 128) >> 8)
+// B = clip((298 x c + 516 x d + 128) >> 8)
//
// An article on optimizing YUV conversion using tables instead of multiplies
// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
@@ -339,14 +339,14 @@ void ConvertYV12ToRGB32Row(const uint8* y_buf,
shr ecx, 1
wloop :
- movzx eax, byte ptr [edi]
+ movzx eax, byte ptr [edi] // NOLINT
add edi, 1
- movzx ebx, byte ptr [esi]
+ movzx ebx, byte ptr [esi] // NOLINT
add esi, 1
movq mm0, [coefficients_RGB_U + 8 * eax]
- movzx eax, byte ptr [edx]
+ movzx eax, byte ptr [edx] // NOLINT
paddsw mm0, [coefficients_RGB_V + 8 * ebx]
- movzx ebx, byte ptr [edx + 1]
+ movzx ebx, byte ptr [edx + 1] // NOLINT
movq mm1, [coefficients_RGB_Y + 8 * eax]
add edx, 2
movq mm2, [coefficients_RGB_Y + 8 * ebx]
@@ -556,7 +556,7 @@ static uint8 g_rgb_clip_table[kClipOverflow
+ kClipTableSize
+ kClipOverflow] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 128 underflow values
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // clamped to 0.
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cliped to 0.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -604,7 +604,7 @@ static uint8 g_rgb_clip_table[kClipOverflow
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 128 overflow values
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // clamped to 255.
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // cliped to 255.
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -625,14 +625,15 @@ static uint8 g_rgb_clip_table[kClipOverflow
// Source is signed fixed point 8.8.
// Table allows for values to underflow or overflow by 128.
// Therefore source range is -128 to 384.
-// Output clamps to unsigned 0 to 255.
+// Output clips to unsigned 0 to 255.
static inline uint32 clip(int32 value) {
- DCHECK((((value) >> 8) + kClipOverflow) >= 0);
- DCHECK((((value) >> 8) + kClipOverflow)
- < kClipOverflow + kClipTableSize + kClipOverflow);
+ DCHECK(((value >> 8) + kClipOverflow) >= 0);
+ DCHECK(((value >> 8) + kClipOverflow) <
+ (kClipOverflow + kClipTableSize + kClipOverflow));
return static_cast<uint32>(g_rgb_clip_table[((value) >> 8) + kClipOverflow]);
}
+
void ConvertYV12ToRGB32Row(const uint8* y_buf,
const uint8* u_buf,
const uint8* v_buf,
@@ -641,26 +642,26 @@ void ConvertYV12ToRGB32Row(const uint8* y_buf,
for (int32 x = 0; x < static_cast<int32>(width); x += 2) {
uint8 u = u_buf[x >> 1];
uint8 v = v_buf[x >> 1];
- int32 D = static_cast<int32>(u) - 128;
- int32 E = static_cast<int32>(v) - 128;
+ int32 d = static_cast<int32>(u) - 128;
+ int32 e = static_cast<int32>(v) - 128;
- int32 Cb = (516 * D + 128);
- int32 Cg = (- 100 * D - 208 * E + 128);
- int32 Cr = (409 * E + 128);
+ int32 cb = (516 * d + 128);
+ int32 cg = (- 100 * d - 208 * e + 128);
+ int32 cr = (409 * e + 128);
uint8 y0 = y_buf[x];
int32 C298a = ((static_cast<int32>(y0) - 16) * 298 + 128);
- *reinterpret_cast<uint32*>(rgb_buf) = clip(C298a + Cb)
- | (clip(C298a + Cg) << 8)
- | (clip(C298a + Cr) << 16)
- | 0xff000000;
+ *reinterpret_cast<uint32*>(rgb_buf) = clip(C298a + cb) |
+ (clip(C298a + cg) << 8) |
+ (clip(C298a + cr) << 16) |
+ 0xff000000;
uint8 y1 = y_buf[x + 1];
int32 C298b = ((static_cast<int32>(y1) - 16) * 298 + 128);
- *reinterpret_cast<uint32*>(rgb_buf + 4) = clip(C298b + Cb)
- | (clip(C298b + Cg) << 8)
- | (clip(C298b + Cr) << 16)
- | 0xff000000;
+ *reinterpret_cast<uint32*>(rgb_buf + 4) = clip(C298b + cb) |
+ (clip(C298b + cg) << 8) |
+ (clip(C298b + cr) << 16) |
+ 0xff000000;
rgb_buf += 8; // Advance 2 pixels.
}
diff --git a/media/base/yuv_scale.cc b/media/base/yuv_scale.cc
new file mode 100644
index 0000000..7f39861
--- /dev/null
+++ b/media/base/yuv_scale.cc
@@ -0,0 +1,260 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/yuv_scale.h"
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+#ifdef _DEBUG
+#include "base/logging.h"
+#else
+#define DCHECK(a)
+#endif
+
+namespace media {
+
+static void ScaleYV12ToRGB32Row(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ uint8* rgb_buf,
+ size_t width,
+ size_t scaled_width);
+static void HalfYV12ToRGB32Row(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ uint8* rgb_buf,
+ size_t width);
+
+// Scale a frame of YV12 (aka YUV420) to 32 bit ARGB.
+void ScaleYV12ToRGB32(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ uint8* rgb_buf,
+ size_t width,
+ size_t height,
+ size_t scaled_width,
+ size_t scaled_height,
+ int y_pitch,
+ int uv_pitch,
+ int rgb_pitch) {
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+ for (int y = 0; y < static_cast<int>(scaled_height); ++y) {
+ uint8* dest_pixel = rgb_buf + y * rgb_pitch;
+ int scaled_y = (y * height / scaled_height);
+ const uint8* y_ptr = y_buf + scaled_y * y_pitch;
+ const uint8* u_ptr = u_buf + scaled_y / 2 * uv_pitch;
+ const uint8* v_ptr = v_buf + scaled_y / 2 * uv_pitch;
+
+ if (scaled_width == (width / 2)) {
+ HalfYV12ToRGB32Row(y_ptr, u_ptr, v_ptr,
+ dest_pixel, scaled_width);
+ } else {
+ ScaleYV12ToRGB32Row(y_ptr, u_ptr, v_ptr,
+ dest_pixel, width, scaled_width);
+ }
+ }
+}
+
+// Scale a frame of YV16 (aka YUV422) to 32 bit ARGB.
+void ScaleYV16ToRGB32(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ uint8* rgb_buf,
+ size_t width,
+ size_t height,
+ size_t scaled_width,
+ size_t scaled_height,
+ int y_pitch,
+ int uv_pitch,
+ int rgb_pitch) {
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+ for (int y = 0; y < static_cast<int>(scaled_height); ++y) {
+ uint8* dest_pixel = rgb_buf + y * rgb_pitch;
+ int scaled_y = (y * height / scaled_height);
+ const uint8* y_ptr = y_buf + scaled_y * y_pitch;
+ const uint8* u_ptr = u_buf + scaled_y * uv_pitch;
+ const uint8* v_ptr = v_buf + scaled_y * uv_pitch;
+
+ if (scaled_width == (width / 2)) {
+ HalfYV12ToRGB32Row(y_ptr, u_ptr, v_ptr,
+ dest_pixel, scaled_width);
+ } else {
+ ScaleYV12ToRGB32Row(y_ptr, u_ptr, v_ptr,
+ dest_pixel, width, scaled_width);
+ }
+ }
+}
+
+// Reference version of YUV Scaler.
+static const int kClipTableSize = 256;
+static const int kClipOverflow = 128;
+
+static uint8 g_rgb_clip_table[kClipOverflow
+ + kClipTableSize
+ + kClipOverflow] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 128 underflow values
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cliped to 0.
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Unclipped values.
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 128 overflow values
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // cliped to 255.
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+// Clip an rgb channel value to 0..255 range.
+// Source is signed fixed point 8.8.
+// Table allows for values to underflow or overflow by 128.
+// Therefore source range is -128 to 384.
+// Output clips to unsigned 0 to 255.
+static inline uint32 clip(int32 value) {
+ DCHECK(((value >> 8) + kClipOverflow) >= 0);
+ DCHECK(((value >> 8) + kClipOverflow) <
+ (kClipOverflow + kClipTableSize + kClipOverflow));
+ return static_cast<uint32>(g_rgb_clip_table[((value) >> 8) + kClipOverflow]);
+}
+
+// 28.4 fixed point is used. A shift by 4 isolates the integer.
+// A shift by 5 is used to further subsample the chrominence channels.
+// & 15 isolates the fixed point fraction. >> 2 to get the upper 2 bits,
+// for 1/4 pixel accurate interpolation.
+
+static void ScaleYV12ToRGB32Row(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ uint8* rgb_buf,
+ size_t width,
+ size_t scaled_width) {
+ int scaled_dx = width * 16 / scaled_width;
+ int scaled_x = 0;
+ for (int32 x = 0; x < static_cast<int32>(scaled_width); ++x) {
+ uint8 u = u_buf[scaled_x >> 5];
+ uint8 v = v_buf[scaled_x >> 5];
+ int32 d = static_cast<int32>(u) - 128;
+ int32 e = static_cast<int32>(v) - 128;
+
+ int32 cb = (516 * d + 128);
+ int32 cg = (- 100 * d - 208 * e + 128);
+ int32 cr = (409 * e + 128);
+
+ uint8 y0 = y_buf[scaled_x >> 4];
+ uint8 y1 = y_buf[(scaled_x >> 4) + 1];
+ switch ((scaled_x & 15) >> 2) {
+ case 1: // 75% first pixel, 25% second pixel.
+ y0 = (y0 + y0 + y0 + y1) >> 2;
+ break;
+ case 2: // 50/50 blend
+ y0 = (y0 + y1) >> 1;
+ break;
+ case 3: // 25% first pixel, 75% second pixel.
+ y0 = (y0 + y1 + y1 + y1) >> 2;
+ break;
+ default:
+ case 0: // 100% first pixel.
+ break;
+ }
+
+ int32 C298a = ((static_cast<int32>(y0) - 16) * 298 + 128);
+ *reinterpret_cast<uint32*>(rgb_buf) = clip(C298a + cb) |
+ (clip(C298a + cg) << 8) |
+ (clip(C298a + cr) << 16) |
+ 0xff000000;
+
+ rgb_buf += 4;
+ scaled_x += scaled_dx;
+ }
+}
+
+
+static void HalfYV12ToRGB32Row(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ uint8* rgb_buf,
+ size_t width) {
+ for (int32 x = 0; x < static_cast<int32>(width); ++x) {
+ uint8 u = u_buf[x];
+ uint8 v = v_buf[x];
+ int32 d = static_cast<int32>(u) - 128;
+ int32 e = static_cast<int32>(v) - 128;
+
+ int32 cb = (516 * d + 128);
+ int32 cg = (- 100 * d - 208 * e + 128);
+ int32 cr = (409 * e + 128);
+
+ uint8 y0 = y_buf[x * 2 + 0];
+ uint8 y1 = y_buf[x * 2 + 1];
+ int32 C298a = ((static_cast<int32>((y0 + y1) >> 1) - 16) * 298 + 128);
+ *reinterpret_cast<uint32*>(rgb_buf) = clip(C298a + cb) |
+ (clip(C298a + cg) << 8) |
+ (clip(C298a + cr) << 16) |
+ 0xff000000;
+
+ rgb_buf += 4;
+ }
+}
+
+} // namespace media
+
diff --git a/media/base/yuv_scale.h b/media/base/yuv_scale.h
new file mode 100644
index 0000000..f354942
--- /dev/null
+++ b/media/base/yuv_scale.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_YUV_SCALE_H_
+#define MEDIA_BASE_YUV_SCALE_H_
+
+#include "base/basictypes.h"
+
+namespace media {
+
+// Scale a frame of YV12 (aka YUV420) to 32 bit ARGB.
+void ScaleYV12ToRGB32(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ uint8* rgbframe,
+ size_t frame_width,
+ size_t frame_height,
+ size_t scaled_width,
+ size_t scaled_height,
+ int ystride,
+ int uvstride,
+ int rgbstride);
+
+// Scale a frame of YV16 (aka YUV422) to 32 bit ARGB.
+void ScaleYV16ToRGB32(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ uint8* rgbframe,
+ size_t frame_width,
+ size_t frame_height,
+ size_t scaled_width,
+ size_t scaled_height,
+ int ystride,
+ int uvstride,
+ int rgbstride);
+
+#endif // MEDIA_BASE_YUV_SCALE_H_
+
+} // namespace media
+
diff --git a/media/base/yuv_scale_unittest.cc b/media/base/yuv_scale_unittest.cc
new file mode 100644
index 0000000..f5e2f0d
--- /dev/null
+++ b/media/base/yuv_scale_unittest.cc
@@ -0,0 +1,119 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "media/base/yuv_scale.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Reference images were created with the following steps
+// ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv420p -an
+// bali.yv12.1280_720.yuv
+// yuvhalf -yv12 -skip 24 bali.yv12.1280_720.yuv bali.yv12.640_360.yuv
+
+// ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv422p -an
+// bali.yv16.1280_720.yuv
+// yuvhalf -yv16 -skip 24 bali.yv16.1280_720.yuv bali.yv16.640_360.yuv
+
+// After running the scale functions in the unit test below, a hash
+// is taken and compared to a reference value.
+// If the image or code changes, the hash will require an update.
+// A process outside the unittest is needed to confirm the new code
+// and data are correctly working. At this time, the author used
+// the media_player with the same parameters and visually inspected the
+// quality. Once satisified that the quality is correct, the hash
+// can be updated and used to ensure quality remains the same on
+// all future builds and ports.
+
+// Size of raw image.
+static const int kWidth = 640;
+static const int kHeight = 360;
+static const int kScaledWidth = 1024;
+static const int kScaledHeight = 768;
+static const int kBpp = 4;
+
+// DJB2 hash
+unsigned int hash(unsigned char *s, size_t len) {
+ unsigned int hash = 5381;
+ while (len--)
+ hash = hash * 33 + *s++;
+ return hash;
+}
+
+TEST(YuvScaleTest, Basic) {
+ // Read YUV reference data from file.
+ FilePath yuv_url;
+ EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
+ yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .Append(FILE_PATH_LITERAL("bali.yv12.640_360.yuv"));
+ const size_t size_of_yuv = kWidth * kHeight * 12 / 8; // 12 bpp.
+ uint8* yuv_bytes = new uint8[size_of_yuv];
+ EXPECT_EQ(static_cast<int>(size_of_yuv),
+ file_util::ReadFile(yuv_url,
+ reinterpret_cast<char*>(yuv_bytes),
+ static_cast<int>(size_of_yuv)));
+
+ // Scale a frame of YUV to 32 bit ARGB.
+ const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp;
+ uint8* rgb_scaled_bytes = new uint8[size_of_rgb_scaled];
+
+ media::ScaleYV12ToRGB32(yuv_bytes, // Y plane
+ yuv_bytes + kWidth * kHeight, // U plane
+ yuv_bytes + kWidth * kHeight * 5 / 4, // V plane
+ rgb_scaled_bytes, // Rgb output
+ kWidth, kHeight, // Dimensions
+ kScaledWidth, kScaledHeight, // Dimensions
+ kWidth, // YStride
+ kWidth / 2, // UvStride
+ kScaledWidth * kBpp); // RgbStride
+
+ unsigned int rgb_hash = hash(rgb_scaled_bytes, size_of_rgb_scaled);
+
+ // To get this hash value, run once and examine the following EXPECT_EQ.
+ // Then plug new hash value into EXPECT_EQ statements.
+
+ EXPECT_EQ(rgb_hash, 1849654084u);
+ return; // This is here to allow you to put a break point on this line
+}
+
+TEST(YV16ScaleTest, Basic) {
+ // Read YV16 reference data from file.
+ FilePath yuv_url;
+ EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
+ yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .Append(FILE_PATH_LITERAL("bali.yv16.640_360.yuv"));
+ const size_t size_of_yuv = kWidth * kHeight * 16 / 8; // 16 bpp.
+ uint8* yuv_bytes = new uint8[size_of_yuv];
+ EXPECT_EQ(static_cast<int>(size_of_yuv),
+ file_util::ReadFile(yuv_url,
+ reinterpret_cast<char*>(yuv_bytes),
+ static_cast<int>(size_of_yuv)));
+
+ // Scale a frame of YUV to 32 bit ARGB.
+ const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp;
+ uint8* rgb_scaled_bytes = new uint8[size_of_rgb_scaled];
+
+ media::ScaleYV16ToRGB32(yuv_bytes, // Y plane
+ yuv_bytes + kWidth * kHeight, // U plane
+ yuv_bytes + kWidth * kHeight * 3 / 2, // V plane
+ rgb_scaled_bytes, // Rgb output
+ kWidth, kHeight, // Dimensions
+ kScaledWidth, kScaledHeight, // Dimensions
+ kWidth, // YStride
+ kWidth / 2, // UvStride
+ kScaledWidth * kBpp); // RgbStride
+
+ unsigned int rgb_hash = hash(rgb_scaled_bytes, size_of_rgb_scaled);
+
+ // To get this hash value, run once and examine the following EXPECT_EQ.
+ // Then plug new hash value into EXPECT_EQ statements.
+
+ EXPECT_EQ(rgb_hash, 1297606858u);
+ return;
+}
+
diff --git a/media/media.gyp b/media/media.gyp
index fec2b64..d5c2323 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -66,6 +66,8 @@
'base/video_frame_impl.h',
'base/yuv_convert.cc',
'base/yuv_convert.h',
+ 'base/yuv_scale.cc',
+ 'base/yuv_scale.h',
'filters/audio_renderer_base.cc',
'filters/audio_renderer_base.h',
'filters/audio_renderer_impl.cc',
@@ -145,6 +147,7 @@
'base/run_all_unittests.cc',
'base/video_frame_impl_unittest.cc',
'base/yuv_convert_unittest.cc',
+ 'base/yuv_scale_unittest.cc',
'filters/ffmpeg_demuxer_unittest.cc',
'filters/ffmpeg_glue_unittest.cc',
'filters/file_data_source_unittest.cc',
@@ -186,7 +189,6 @@
'../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
],
'sources': [
- 'player/player.cc',
],
},
{