summaryrefslogtreecommitdiffstats
path: root/media/base
diff options
context:
space:
mode:
authorvigneshv@chromium.org <vigneshv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-19 23:43:32 +0000
committervigneshv@chromium.org <vigneshv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-19 23:43:32 +0000
commit6ac955b41814da1eebf56244a147f3fad00f5aa7 (patch)
tree9671f7731055aa027d63e56290722d7ec012756f /media/base
parente69198bfdb89c4658a023c05c4929e9617ac2828 (diff)
downloadchromium_src-6ac955b41814da1eebf56244a147f3fad00f5aa7.zip
chromium_src-6ac955b41814da1eebf56244a147f3fad00f5aa7.tar.gz
chromium_src-6ac955b41814da1eebf56244a147f3fad00f5aa7.tar.bz2
media: Add support for playback of VP8 Alpha video streams
BUG=147355 TEST=VP8 Alpha video streams play TBR=sky Review URL: https://chromiumcodereview.appspot.com/13886011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195339 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/base')
-rw-r--r--media/base/decoder_buffer.cc48
-rw-r--r--media/base/decoder_buffer.h14
-rw-r--r--media/base/decoder_buffer_unittest.cc11
-rw-r--r--media/base/media_switches.cc3
-rw-r--r--media/base/media_switches.h2
-rw-r--r--media/base/simd/convert_yuv_to_rgb.h60
-rw-r--r--media/base/simd/convert_yuv_to_rgb_c.cc78
-rw-r--r--media/base/simd/convert_yuv_to_rgb_x86.cc31
-rw-r--r--media/base/simd/convert_yuva_to_argb_mmx.asm23
-rw-r--r--media/base/simd/convert_yuva_to_argb_mmx.inc174
-rw-r--r--media/base/simd/yuv_to_rgb_table.cc85
-rw-r--r--media/base/simd/yuv_to_rgb_table.h2
-rw-r--r--media/base/video_frame.cc27
-rw-r--r--media/base/video_frame.h4
-rw-r--r--media/base/video_util.cc10
-rw-r--r--media/base/video_util.h10
-rw-r--r--media/base/yuv_convert.cc30
-rw-r--r--media/base/yuv_convert.h15
18 files changed, 614 insertions, 13 deletions
diff --git a/media/base/decoder_buffer.cc b/media/base/decoder_buffer.cc
index 03f9bbb..aec4521 100644
--- a/media/base/decoder_buffer.cc
+++ b/media/base/decoder_buffer.cc
@@ -10,12 +10,14 @@
namespace media {
DecoderBuffer::DecoderBuffer(int size)
- : size_(size) {
+ : size_(size),
+ side_data_size_(0) {
Initialize();
}
DecoderBuffer::DecoderBuffer(const uint8* data, int size)
- : size_(size) {
+ : size_(size),
+ side_data_size_(0) {
if (!data) {
CHECK_EQ(size_, 0);
return;
@@ -25,6 +27,20 @@ DecoderBuffer::DecoderBuffer(const uint8* data, int size)
memcpy(data_.get(), data, size_);
}
+DecoderBuffer::DecoderBuffer(const uint8* data, int size,
+ const uint8* side_data, int side_data_size)
+ : size_(size),
+ side_data_size_(side_data_size) {
+ if (!data) {
+ CHECK_EQ(size_, 0);
+ return;
+ }
+
+ Initialize();
+ memcpy(data_.get(), data, size_);
+ memcpy(side_data_.get(), side_data, side_data_size_);
+}
+
DecoderBuffer::~DecoderBuffer() {}
void DecoderBuffer::Initialize() {
@@ -32,6 +48,11 @@ void DecoderBuffer::Initialize() {
data_.reset(reinterpret_cast<uint8*>(
base::AlignedAlloc(size_ + kPaddingSize, kAlignmentSize)));
memset(data_.get() + size_, 0, kPaddingSize);
+ if (side_data_size_ > 0) {
+ side_data_.reset(reinterpret_cast<uint8*>(
+ base::AlignedAlloc(side_data_size_ + kPaddingSize, kAlignmentSize)));
+ memset(side_data_.get() + side_data_size_, 0, kPaddingSize);
+ }
}
// static
@@ -43,6 +64,18 @@ scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(const uint8* data,
}
// static
+scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(const uint8* data,
+ int data_size,
+ const uint8* side_data,
+ int side_data_size) {
+ // If you hit this CHECK you likely have a bug in a demuxer. Go fix it.
+ CHECK(data);
+ CHECK(side_data);
+ return make_scoped_refptr(new DecoderBuffer(data, data_size,
+ side_data, side_data_size));
+}
+
+// static
scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer() {
return make_scoped_refptr(new DecoderBuffer(NULL, 0));
}
@@ -82,6 +115,16 @@ int DecoderBuffer::GetDataSize() const {
return size_;
}
+const uint8* DecoderBuffer::GetSideData() const {
+ DCHECK(!IsEndOfStream());
+ return side_data_.get();
+}
+
+int DecoderBuffer::GetSideDataSize() const {
+ DCHECK(!IsEndOfStream());
+ return side_data_size_;
+}
+
const DecryptConfig* DecoderBuffer::GetDecryptConfig() const {
DCHECK(!IsEndOfStream());
return decrypt_config_.get();
@@ -105,6 +148,7 @@ std::string DecoderBuffer::AsHumanReadableString() {
s << "timestamp: " << timestamp_.InMicroseconds()
<< " duration: " << duration_.InMicroseconds()
<< " size: " << size_
+ << " side_data_size: " << side_data_size_
<< " encrypted: " << (decrypt_config_ != NULL);
return s.str();
}
diff --git a/media/base/decoder_buffer.h b/media/base/decoder_buffer.h
index c23e88f..168ab2c 100644
--- a/media/base/decoder_buffer.h
+++ b/media/base/decoder_buffer.h
@@ -47,6 +47,13 @@ class MEDIA_EXPORT DecoderBuffer
// padded and aligned as necessary. |data| must not be NULL and |size| >= 0.
static scoped_refptr<DecoderBuffer> CopyFrom(const uint8* data, int size);
+ // Create a DecoderBuffer whose |data_| is copied from |data| and |side_data_|
+ // is copied from |side_data|. Buffers will be padded and aligned as necessary
+ // Data pointers must not be NULL and sizes must be >= 0.
+ static scoped_refptr<DecoderBuffer> CopyFrom(const uint8* data, int size,
+ const uint8* side_data,
+ int side_data_size);
+
// Create a DecoderBuffer indicating we've reached end of stream.
//
// Calling any method other than IsEndOfStream() on the resulting buffer
@@ -64,6 +71,9 @@ class MEDIA_EXPORT DecoderBuffer
int GetDataSize() const;
+ const uint8* GetSideData() const;
+ int GetSideDataSize() const;
+
const DecryptConfig* GetDecryptConfig() const;
void SetDecryptConfig(scoped_ptr<DecryptConfig> decrypt_config);
@@ -80,6 +90,8 @@ class MEDIA_EXPORT DecoderBuffer
// will be padded and aligned as necessary. If |data| is NULL then |data_| is
// set to NULL and |buffer_size_| to 0.
DecoderBuffer(const uint8* data, int size);
+ DecoderBuffer(const uint8* data, int size,
+ const uint8* side_data, int side_data_size);
virtual ~DecoderBuffer();
private:
@@ -88,6 +100,8 @@ class MEDIA_EXPORT DecoderBuffer
int size_;
scoped_ptr<uint8, base::ScopedPtrAlignedFree> data_;
+ int side_data_size_;
+ scoped_ptr<uint8, base::ScopedPtrAlignedFree> side_data_;
scoped_ptr<DecryptConfig> decrypt_config_;
// Constructor helper method for memory allocations.
diff --git a/media/base/decoder_buffer_unittest.cc b/media/base/decoder_buffer_unittest.cc
index 32c38d0..7880a80 100644
--- a/media/base/decoder_buffer_unittest.cc
+++ b/media/base/decoder_buffer_unittest.cc
@@ -35,6 +35,17 @@ TEST(DecoderBufferTest, CopyFrom) {
EXPECT_EQ(buffer2->GetDataSize(), kDataSize);
EXPECT_EQ(0, memcmp(buffer2->GetData(), kData, kDataSize));
EXPECT_FALSE(buffer2->IsEndOfStream());
+ scoped_refptr<DecoderBuffer> buffer3(DecoderBuffer::CopyFrom(
+ reinterpret_cast<const uint8*>(&kData), kDataSize,
+ reinterpret_cast<const uint8*>(&kData), kDataSize));
+ ASSERT_TRUE(buffer3);
+ EXPECT_NE(kData, buffer3->GetData());
+ EXPECT_EQ(buffer3->GetDataSize(), kDataSize);
+ EXPECT_EQ(0, memcmp(buffer3->GetData(), kData, kDataSize));
+ EXPECT_NE(kData, buffer3->GetSideData());
+ EXPECT_EQ(buffer3->GetSideDataSize(), kDataSize);
+ EXPECT_EQ(0, memcmp(buffer3->GetSideData(), kData, kDataSize));
+ EXPECT_FALSE(buffer3->IsEndOfStream());
}
#if !defined(OS_ANDROID)
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 04e711e..7c1ab90 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -57,6 +57,9 @@ const char kEnableOpusPlayback[] = "enable-opus-playback";
// Enables VP9 playback in media elements.
const char kEnableVp9Playback[] = "enable-vp9-playback";
+// Enables VP8 Alpha playback in media elements.
+const char kEnableVp8AlphaPlayback[] = "enable-vp8-alpha-playback";
+
#if defined(OS_WIN)
const char kWaveOutBuffers[] = "waveout-buffers";
#endif
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index ea32fae..e9b6ab9 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -44,6 +44,8 @@ MEDIA_EXPORT extern const char kEnableOpusPlayback[];
MEDIA_EXPORT extern const char kEnableVp9Playback[];
+MEDIA_EXPORT extern const char kEnableVp8AlphaPlayback[];
+
#if defined(OS_WIN)
MEDIA_EXPORT extern const char kWaveOutBuffers[];
#endif
diff --git a/media/base/simd/convert_yuv_to_rgb.h b/media/base/simd/convert_yuv_to_rgb.h
index d05f039..7db35b5 100644
--- a/media/base/simd/convert_yuv_to_rgb.h
+++ b/media/base/simd/convert_yuv_to_rgb.h
@@ -21,6 +21,19 @@ typedef void (*ConvertYUVToRGB32Proc)(const uint8*,
int,
YUVType);
+typedef void (*ConvertYUVAToARGBProc)(const uint8*,
+ const uint8*,
+ const uint8*,
+ const uint8*,
+ uint8*,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ YUVType);
+
void ConvertYUVToRGB32_C(const uint8* yplane,
const uint8* uplane,
const uint8* vplane,
@@ -32,6 +45,19 @@ void ConvertYUVToRGB32_C(const uint8* yplane,
int rgbstride,
YUVType yuv_type);
+void ConvertYUVAToARGB_C(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbframe,
+ int width,
+ int height,
+ int ystride,
+ int uvstride,
+ int avstride,
+ int rgbstride,
+ YUVType yuv_type);
+
void ConvertYUVToRGB32_SSE(const uint8* yplane,
const uint8* uplane,
const uint8* vplane,
@@ -54,6 +80,19 @@ void ConvertYUVToRGB32_MMX(const uint8* yplane,
int rgbstride,
YUVType yuv_type);
+void ConvertYUVAToARGB_MMX(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbframe,
+ int width,
+ int height,
+ int ystride,
+ int uvstride,
+ int avstride,
+ int rgbstride,
+ YUVType yuv_type);
+
} // namespace media
// Assembly functions are declared without namespace.
@@ -72,6 +111,13 @@ typedef void (*ConvertYUVToRGB32RowProc)(const uint8*,
uint8*,
ptrdiff_t);
+typedef void (*ConvertYUVAToARGBRowProc)(const uint8*,
+ const uint8*,
+ const uint8*,
+ const uint8*,
+ uint8*,
+ ptrdiff_t);
+
typedef void (*ScaleYUVToRGB32RowProc)(const uint8*,
const uint8*,
const uint8*,
@@ -85,12 +131,26 @@ void ConvertYUVToRGB32Row_C(const uint8* yplane,
uint8* rgbframe,
ptrdiff_t width);
+void ConvertYUVAToARGBRow_C(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbframe,
+ ptrdiff_t width);
+
void ConvertYUVToRGB32Row_MMX(const uint8* yplane,
const uint8* uplane,
const uint8* vplane,
uint8* rgbframe,
ptrdiff_t width);
+void ConvertYUVAToARGBRow_MMX(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbframe,
+ ptrdiff_t width);
+
void ConvertYUVToRGB32Row_SSE(const uint8* yplane,
const uint8* uplane,
const uint8* vplane,
diff --git a/media/base/simd/convert_yuv_to_rgb_c.cc b/media/base/simd/convert_yuv_to_rgb_c.cc
index 2849cac..e09ed13 100644
--- a/media/base/simd/convert_yuv_to_rgb_c.cc
+++ b/media/base/simd/convert_yuv_to_rgb_c.cc
@@ -39,6 +39,34 @@ static inline void ConvertYUVToRGB32_C(uint8 y,
(packuswb(a) << 24);
}
+static inline void ConvertYUVAToARGB_C(uint8 y,
+ uint8 u,
+ uint8 v,
+ uint8 a,
+ uint8* rgb_buf) {
+ int b = kCoefficientsRgbY[256+u][0];
+ int g = kCoefficientsRgbY[256+u][1];
+ int r = kCoefficientsRgbY[256+u][2];
+
+ b = paddsw(b, kCoefficientsRgbY[512+v][0]);
+ g = paddsw(g, kCoefficientsRgbY[512+v][1]);
+ r = paddsw(r, kCoefficientsRgbY[512+v][2]);
+
+ b = paddsw(b, kCoefficientsRgbY[y][0]);
+ g = paddsw(g, kCoefficientsRgbY[y][1]);
+ r = paddsw(r, kCoefficientsRgbY[y][2]);
+
+ b >>= 6;
+ g >>= 6;
+ r >>= 6;
+
+ b = packuswb(b) * a >> 8;
+ g = packuswb(g) * a >> 8;
+ r = packuswb(r) * a >> 8;
+
+ *reinterpret_cast<uint32*>(rgb_buf) = b | (g << 8) | (r << 16) | (a << 24);
+}
+
extern "C" {
void ConvertYUVToRGB32Row_C(const uint8* y_buf,
@@ -59,6 +87,27 @@ void ConvertYUVToRGB32Row_C(const uint8* y_buf,
}
}
+void ConvertYUVAToARGBRow_C(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ const uint8* a_buf,
+ uint8* rgba_buf,
+ ptrdiff_t width) {
+ for (int x = 0; x < width; x += 2) {
+ uint8 u = u_buf[x >> 1];
+ uint8 v = v_buf[x >> 1];
+ uint8 y0 = y_buf[x];
+ uint8 a0 = a_buf[x];
+ ConvertYUVAToARGB_C(y0, u, v, a0, rgba_buf);
+ if ((x + 1) < width) {
+ uint8 y1 = y_buf[x + 1];
+ uint8 a1 = a_buf[x + 1];
+ ConvertYUVAToARGB_C(y1, u, v, a1, rgba_buf + 4);
+ }
+ rgba_buf += 8; // Advance 2 pixels.
+ }
+}
+
// 16.16 fixed point is used. A shift by 16 isolates the integer.
// A shift by 17 is used to further subsample the chrominence channels.
// & 0xffff isolates the fixed point fraction. >> 2 to get the upper 2 bits,
@@ -161,4 +210,33 @@ void ConvertYUVToRGB32_C(const uint8* yplane,
}
}
+void ConvertYUVAToARGB_C(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbaframe,
+ int width,
+ int height,
+ int ystride,
+ int uvstride,
+ int astride,
+ int rgbastride,
+ YUVType yuv_type) {
+ unsigned int y_shift = yuv_type;
+ for (int y = 0; y < height; y++) {
+ uint8* rgba_row = rgbaframe + y * rgbastride;
+ const uint8* y_ptr = yplane + y * ystride;
+ const uint8* u_ptr = uplane + (y >> y_shift) * uvstride;
+ const uint8* v_ptr = vplane + (y >> y_shift) * uvstride;
+ const uint8* a_ptr = aplane + y * astride;
+
+ ConvertYUVAToARGBRow_C(y_ptr,
+ u_ptr,
+ v_ptr,
+ a_ptr,
+ rgba_row,
+ width);
+ }
+}
+
} // namespace media
diff --git a/media/base/simd/convert_yuv_to_rgb_x86.cc b/media/base/simd/convert_yuv_to_rgb_x86.cc
index 37b168d..d1d6e16 100644
--- a/media/base/simd/convert_yuv_to_rgb_x86.cc
+++ b/media/base/simd/convert_yuv_to_rgb_x86.cc
@@ -40,6 +40,37 @@ void ConvertYUVToRGB32_MMX(const uint8* yplane,
EmptyRegisterState();
}
+void ConvertYUVAToARGB_MMX(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbframe,
+ int width,
+ int height,
+ int ystride,
+ int uvstride,
+ int astride,
+ int rgbstride,
+ YUVType yuv_type) {
+ unsigned int y_shift = yuv_type;
+ for (int y = 0; y < height; ++y) {
+ uint8* rgb_row = rgbframe + y * rgbstride;
+ const uint8* y_ptr = yplane + y * ystride;
+ const uint8* u_ptr = uplane + (y >> y_shift) * uvstride;
+ const uint8* v_ptr = vplane + (y >> y_shift) * uvstride;
+ const uint8* a_ptr = aplane + y * astride;
+
+ ConvertYUVAToARGBRow_MMX(y_ptr,
+ u_ptr,
+ v_ptr,
+ a_ptr,
+ rgb_row,
+ width);
+ }
+
+ EmptyRegisterState();
+}
+
void ConvertYUVToRGB32_SSE(const uint8* yplane,
const uint8* uplane,
const uint8* vplane,
diff --git a/media/base/simd/convert_yuva_to_argb_mmx.asm b/media/base/simd/convert_yuva_to_argb_mmx.asm
new file mode 100644
index 0000000..b39315dc
--- /dev/null
+++ b/media/base/simd/convert_yuva_to_argb_mmx.asm
@@ -0,0 +1,23 @@
+; Copyright (c) 2011 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 "third_party/x86inc/x86inc.asm"
+
+;
+; This file uses MMX instructions.
+;
+ SECTION_TEXT
+ CPU MMX
+
+; Use movq to save the output.
+%define MOVQ movq
+
+; extern "C" void ConvertYUVAToARGBRow_MMX(const uint8* y_buf,
+; const uint8* u_buf,
+; const uint8* v_buf,
+; const uint8* a_buf,
+; uint8* rgb_buf,
+; ptrdiff_t width);
+%define SYMBOL ConvertYUVAToARGBRow_MMX
+%include "convert_yuva_to_argb_mmx.inc"
diff --git a/media/base/simd/convert_yuva_to_argb_mmx.inc b/media/base/simd/convert_yuva_to_argb_mmx.inc
new file mode 100644
index 0000000..621100e
--- /dev/null
+++ b/media/base/simd/convert_yuva_to_argb_mmx.inc
@@ -0,0 +1,174 @@
+; Copyright (c) 2011 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.
+
+ global mangle(SYMBOL) PRIVATE
+ align function_align
+
+; Non-PIC code is the fastest so use this if possible.
+%ifndef PIC
+mangle(SYMBOL):
+ %assign stack_offset 0
+ PROLOGUE 6, 7, 3, Y, U, V, A, ARGB, WIDTH, TEMP
+ extern mangle(kCoefficientsRgbY)
+ jmp .convertend
+
+.convertloop:
+ movzx TEMPd, BYTE [Uq]
+ movq mm0, [mangle(kCoefficientsRgbY) + 2048 + 8 * TEMPq]
+ add Uq, 1
+ movzx TEMPd, BYTE [Vq]
+ paddsw mm0, [mangle(kCoefficientsRgbY) + 4096 + 8 * TEMPq]
+ add Vq, 1
+ movzx TEMPd, BYTE [Yq]
+ movq mm1, [mangle(kCoefficientsRgbY) + 8 * TEMPq]
+ movzx TEMPd, BYTE [Yq + 1]
+ movq mm2, [mangle(kCoefficientsRgbY) + 8 * TEMPq]
+ add Yq, 2
+ paddsw mm1, mm0
+ paddsw mm2, mm0
+ psraw mm1, 6
+ psraw mm2, 6
+ packuswb mm1, mm2
+
+ ; Multiply ARGB by alpha value.
+ movq mm0, mm1
+ pxor mm2, mm2
+ punpcklbw mm0, mm2
+ punpckhbw mm1, mm2
+ movzx TEMPd, BYTE [Aq]
+ movq mm2, [mangle(kCoefficientsRgbY) + 6144 + 8 * TEMPq]
+ pmullw mm0, mm2
+ psrlw mm0, 8
+ movzx TEMPd, BYTE [Aq + 1]
+ movq mm2, [mangle(kCoefficientsRgbY) + 6144 + 8 * TEMPq]
+ add Aq, 2
+ pmullw mm1, mm2
+ psrlw mm1, 8
+ packuswb mm0, mm1
+
+ MOVQ [ARGBq], mm0
+ add ARGBq, 8
+
+.convertend:
+ sub WIDTHq, 2
+ jns .convertloop
+
+ ; If number of pixels is odd then compute it.
+ and WIDTHq, 1
+ jz .convertdone
+
+ movzx TEMPd, BYTE [Uq]
+ movq mm0, [mangle(kCoefficientsRgbY) + 2048 + 8 * TEMPq]
+ movzx TEMPd, BYTE [Vq]
+ paddsw mm0, [mangle(kCoefficientsRgbY) + 4096 + 8 * TEMPq]
+ movzx TEMPd, BYTE [Yq]
+ movq mm1, [mangle(kCoefficientsRgbY) + 8 * TEMPq]
+ paddsw mm1, mm0
+ psraw mm1, 6
+ packuswb mm1, mm1
+
+ ; Multiply ARGB by alpha value.
+ pxor mm0, mm0
+ punpcklbw mm1, mm0
+ movzx TEMPd, BYTE [Aq]
+ movq mm0, [mangle(kCoefficientsRgbY) + 6144 + 8 * TEMPq]
+ pmullw mm1, mm0
+ psrlw mm1, 8
+ packuswb mm1, mm1
+
+ movd [ARGBq], mm1
+
+.convertdone:
+ RET
+%endif
+
+; With PIC code we need to load the address of mangle(kCoefficientsRgbY).
+; This code is slower than the above version.
+%ifdef PIC
+mangle(SYMBOL):
+ %assign stack_offset 0
+ PROLOGUE 6, 7, 3, Y, U, V, A, ARGB, WIDTH, TEMP
+ extern mangle(kCoefficientsRgbY)
+ PUSH WIDTHq
+ DEFINE_ARGS Y, U, V, A, ARGB, TABLE, TEMP
+ LOAD_SYM TABLEq, mangle(kCoefficientsRgbY)
+ jmp .convertend
+
+.convertloop:
+ movzx TEMPd, BYTE [Uq]
+ movq mm0, [TABLEq + 2048 + 8 * TEMPq]
+ add Uq, 1
+
+ movzx TEMPd, BYTE [Vq]
+ paddsw mm0, [TABLEq + 4096 + 8 * TEMPq]
+ add Vq, 1
+
+ movzx TEMPd, BYTE [Yq]
+ movq mm1, [TABLEq + 8 * TEMPq]
+
+ movzx TEMPd, BYTE [Yq + 1]
+ movq mm2, [TABLEq + 8 * TEMPq]
+ add Yq, 2
+
+ ; Add UV components to Y component.
+ paddsw mm1, mm0
+ paddsw mm2, mm0
+
+ ; Down shift and then pack.
+ psraw mm1, 6
+ psraw mm2, 6
+ packuswb mm1, mm2
+
+ ; Unpack and multiply by alpha value, then repack high bytes of words.
+ movq mm0, mm1
+ pxor mm2, mm2
+ punpcklbw mm0, mm2
+ punpckhbw mm1, mm2
+ movzx TEMPd, BYTE [Aq]
+ movq mm2, [TABLEq + 6144 + 8 * TEMPq]
+ pmullw mm0, mm2
+ psrlw mm0, 8
+ movzx TEMPd, BYTE [Aq + 1]
+ movq mm2, [TABLEq + 6144 + 8 * TEMPq]
+ add Aq, 2
+ pmullw mm1, mm2
+ psrlw mm1, 8
+ packuswb mm0, mm1
+
+ MOVQ [ARGBq], mm0
+ add ARGBq, 8
+
+.convertend:
+ sub dword [rsp], 2
+ jns .convertloop
+
+ ; If number of pixels is odd then compute it.
+ and dword [rsp], 1
+ jz .convertdone
+
+ movzx TEMPd, BYTE [Uq]
+ movq mm0, [TABLEq + 2048 + 8 * TEMPq]
+ movzx TEMPd, BYTE [Vq]
+ paddsw mm0, [TABLEq + 4096 + 8 * TEMPq]
+ movzx TEMPd, BYTE [Yq]
+ movq mm1, [TABLEq + 8 * TEMPq]
+ paddsw mm1, mm0
+ psraw mm1, 6
+ packuswb mm1, mm1
+
+ ; Multiply ARGB by alpha value.
+ pxor mm0, mm0
+ punpcklbw mm1, mm0
+ movzx TEMPd, BYTE [Aq]
+ movq mm0, [TABLEq + 6144 + 8 * TEMPq]
+ pmullw mm1, mm0
+ psrlw mm1, 8
+ packuswb mm1, mm1
+
+ movd [ARGBq], mm1
+
+.convertdone:
+ POP TABLEq
+ RET
+%endif \ No newline at end of file
diff --git a/media/base/simd/yuv_to_rgb_table.cc b/media/base/simd/yuv_to_rgb_table.cc
index f998e85..3789969 100644
--- a/media/base/simd/yuv_to_rgb_table.cc
+++ b/media/base/simd/yuv_to_rgb_table.cc
@@ -6,6 +6,7 @@
extern "C" {
+// Defines the R,G,B,A contributions from Y.
#define RGBY(i) { \
static_cast<int16>(1.164 * 64 * (i - 16) + 0.5), \
static_cast<int16>(1.164 * 64 * (i - 16) + 0.5), \
@@ -13,6 +14,9 @@ extern "C" {
0 \
}
+// Defines the R,G,B,A contributions from U.
+// The contribution to A is the same for any value of U
+// causing the final A value to be 255 in every conversion.
#define RGBU(i) { \
static_cast<int16>(2.018 * 64 * (i - 128) + 0.5), \
static_cast<int16>(-0.391 * 64 * (i - 128) + 0.5), \
@@ -20,6 +24,7 @@ extern "C" {
static_cast<int16>(256 * 64 - 1) \
}
+// Defines the R,G,B,A contributions from V.
#define RGBV(i) { \
0, \
static_cast<int16>(-0.813 * 64 * (i - 128) + 0.5), \
@@ -27,7 +32,18 @@ extern "C" {
0 \
}
-SIMD_ALIGNED(int16 kCoefficientsRgbY[256 * 3][4]) = {
+// Used to define a set of multiplier words for each alpha level.
+#define ALPHA(i) { \
+ i, i, i, i \
+}
+
+// The following table defines the RGBA contributions
+// for each component of YUVA. The Y table is first followed
+// by the U, and V tables. The alpha multiplier table follows.
+// These tables are aligned and kept adjacent to optimize for
+// SIMD and cacheing.
+
+SIMD_ALIGNED(int16 kCoefficientsRgbY[256 * 4][4]) = {
RGBY(0x00), RGBY(0x01), RGBY(0x02), RGBY(0x03),
RGBY(0x04), RGBY(0x05), RGBY(0x06), RGBY(0x07),
RGBY(0x08), RGBY(0x09), RGBY(0x0A), RGBY(0x0B),
@@ -224,10 +240,77 @@ SIMD_ALIGNED(int16 kCoefficientsRgbY[256 * 3][4]) = {
RGBV(0xF4), RGBV(0xF5), RGBV(0xF6), RGBV(0xF7),
RGBV(0xF8), RGBV(0xF9), RGBV(0xFA), RGBV(0xFB),
RGBV(0xFC), RGBV(0xFD), RGBV(0xFE), RGBV(0xFF),
+
+ // Alpha multipliers for each alpha level.
+ ALPHA(0x00), ALPHA(0x01), ALPHA(0x02), ALPHA(0x03),
+ ALPHA(0x04), ALPHA(0x05), ALPHA(0x06), ALPHA(0x07),
+ ALPHA(0x08), ALPHA(0x09), ALPHA(0x0A), ALPHA(0x0B),
+ ALPHA(0x0C), ALPHA(0x0D), ALPHA(0x0E), ALPHA(0x0F),
+ ALPHA(0x10), ALPHA(0x11), ALPHA(0x12), ALPHA(0x13),
+ ALPHA(0x14), ALPHA(0x15), ALPHA(0x16), ALPHA(0x17),
+ ALPHA(0x18), ALPHA(0x19), ALPHA(0x1A), ALPHA(0x1B),
+ ALPHA(0x1C), ALPHA(0x1D), ALPHA(0x1E), ALPHA(0x1F),
+ ALPHA(0x20), ALPHA(0x21), ALPHA(0x22), ALPHA(0x23),
+ ALPHA(0x24), ALPHA(0x25), ALPHA(0x26), ALPHA(0x27),
+ ALPHA(0x28), ALPHA(0x29), ALPHA(0x2A), ALPHA(0x2B),
+ ALPHA(0x2C), ALPHA(0x2D), ALPHA(0x2E), ALPHA(0x2F),
+ ALPHA(0x30), ALPHA(0x31), ALPHA(0x32), ALPHA(0x33),
+ ALPHA(0x34), ALPHA(0x35), ALPHA(0x36), ALPHA(0x37),
+ ALPHA(0x38), ALPHA(0x39), ALPHA(0x3A), ALPHA(0x3B),
+ ALPHA(0x3C), ALPHA(0x3D), ALPHA(0x3E), ALPHA(0x3F),
+ ALPHA(0x40), ALPHA(0x41), ALPHA(0x42), ALPHA(0x43),
+ ALPHA(0x44), ALPHA(0x45), ALPHA(0x46), ALPHA(0x47),
+ ALPHA(0x48), ALPHA(0x49), ALPHA(0x4A), ALPHA(0x4B),
+ ALPHA(0x4C), ALPHA(0x4D), ALPHA(0x4E), ALPHA(0x4F),
+ ALPHA(0x50), ALPHA(0x51), ALPHA(0x52), ALPHA(0x53),
+ ALPHA(0x54), ALPHA(0x55), ALPHA(0x56), ALPHA(0x57),
+ ALPHA(0x58), ALPHA(0x59), ALPHA(0x5A), ALPHA(0x5B),
+ ALPHA(0x5C), ALPHA(0x5D), ALPHA(0x5E), ALPHA(0x5F),
+ ALPHA(0x60), ALPHA(0x61), ALPHA(0x62), ALPHA(0x63),
+ ALPHA(0x64), ALPHA(0x65), ALPHA(0x66), ALPHA(0x67),
+ ALPHA(0x68), ALPHA(0x69), ALPHA(0x6A), ALPHA(0x6B),
+ ALPHA(0x6C), ALPHA(0x6D), ALPHA(0x6E), ALPHA(0x6F),
+ ALPHA(0x70), ALPHA(0x71), ALPHA(0x72), ALPHA(0x73),
+ ALPHA(0x74), ALPHA(0x75), ALPHA(0x76), ALPHA(0x77),
+ ALPHA(0x78), ALPHA(0x79), ALPHA(0x7A), ALPHA(0x7B),
+ ALPHA(0x7C), ALPHA(0x7D), ALPHA(0x7E), ALPHA(0x7F),
+ ALPHA(0x80), ALPHA(0x81), ALPHA(0x82), ALPHA(0x83),
+ ALPHA(0x84), ALPHA(0x85), ALPHA(0x86), ALPHA(0x87),
+ ALPHA(0x88), ALPHA(0x89), ALPHA(0x8A), ALPHA(0x8B),
+ ALPHA(0x8C), ALPHA(0x8D), ALPHA(0x8E), ALPHA(0x8F),
+ ALPHA(0x90), ALPHA(0x91), ALPHA(0x92), ALPHA(0x93),
+ ALPHA(0x94), ALPHA(0x95), ALPHA(0x96), ALPHA(0x97),
+ ALPHA(0x98), ALPHA(0x99), ALPHA(0x9A), ALPHA(0x9B),
+ ALPHA(0x9C), ALPHA(0x9D), ALPHA(0x9E), ALPHA(0x9F),
+ ALPHA(0xA0), ALPHA(0xA1), ALPHA(0xA2), ALPHA(0xA3),
+ ALPHA(0xA4), ALPHA(0xA5), ALPHA(0xA6), ALPHA(0xA7),
+ ALPHA(0xA8), ALPHA(0xA9), ALPHA(0xAA), ALPHA(0xAB),
+ ALPHA(0xAC), ALPHA(0xAD), ALPHA(0xAE), ALPHA(0xAF),
+ ALPHA(0xB0), ALPHA(0xB1), ALPHA(0xB2), ALPHA(0xB3),
+ ALPHA(0xB4), ALPHA(0xB5), ALPHA(0xB6), ALPHA(0xB7),
+ ALPHA(0xB8), ALPHA(0xB9), ALPHA(0xBA), ALPHA(0xBB),
+ ALPHA(0xBC), ALPHA(0xBD), ALPHA(0xBE), ALPHA(0xBF),
+ ALPHA(0xC0), ALPHA(0xC1), ALPHA(0xC2), ALPHA(0xC3),
+ ALPHA(0xC4), ALPHA(0xC5), ALPHA(0xC6), ALPHA(0xC7),
+ ALPHA(0xC8), ALPHA(0xC9), ALPHA(0xCA), ALPHA(0xCB),
+ ALPHA(0xCC), ALPHA(0xCD), ALPHA(0xCE), ALPHA(0xCF),
+ ALPHA(0xD0), ALPHA(0xD1), ALPHA(0xD2), ALPHA(0xD3),
+ ALPHA(0xD4), ALPHA(0xD5), ALPHA(0xD6), ALPHA(0xD7),
+ ALPHA(0xD8), ALPHA(0xD9), ALPHA(0xDA), ALPHA(0xDB),
+ ALPHA(0xDC), ALPHA(0xDD), ALPHA(0xDE), ALPHA(0xDF),
+ ALPHA(0xE0), ALPHA(0xE1), ALPHA(0xE2), ALPHA(0xE3),
+ ALPHA(0xE4), ALPHA(0xE5), ALPHA(0xE6), ALPHA(0xE7),
+ ALPHA(0xE8), ALPHA(0xE9), ALPHA(0xEA), ALPHA(0xEB),
+ ALPHA(0xEC), ALPHA(0xED), ALPHA(0xEE), ALPHA(0xEF),
+ ALPHA(0xF0), ALPHA(0xF1), ALPHA(0xF2), ALPHA(0xF3),
+ ALPHA(0xF4), ALPHA(0xF5), ALPHA(0xF6), ALPHA(0xF7),
+ ALPHA(0xF8), ALPHA(0xF9), ALPHA(0xFA), ALPHA(0xFB),
+ ALPHA(0xFC), ALPHA(0xFD), ALPHA(0xFE), ALPHA(0xFF),
};
#undef RGBY
#undef RGBU
#undef RGBV
+#undef ALPHA
} // extern "C"
diff --git a/media/base/simd/yuv_to_rgb_table.h b/media/base/simd/yuv_to_rgb_table.h
index 0c43a7a..3ed7bd9 100644
--- a/media/base/simd/yuv_to_rgb_table.h
+++ b/media/base/simd/yuv_to_rgb_table.h
@@ -19,7 +19,7 @@ extern "C" {
#endif
// Align the table to 16-bytes to allow faster reading.
-extern SIMD_ALIGNED(int16 kCoefficientsRgbY[768][4]);
+extern SIMD_ALIGNED(int16 kCoefficientsRgbY[256 * 4][4]);
} // extern "C"
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 9c3b4b6..6d4997b 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -32,6 +32,7 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
frame->AllocateRGB(4u);
break;
case VideoFrame::YV12:
+ case VideoFrame::YV12A:
case VideoFrame::YV16:
frame->AllocateYUV();
break;
@@ -167,6 +168,8 @@ size_t VideoFrame::NumPlanes(Format format) {
case VideoFrame::YV12:
case VideoFrame::YV16:
return 3;
+ case VideoFrame::YV12A:
+ return 4;
case VideoFrame::EMPTY:
case VideoFrame::I420:
case VideoFrame::INVALID:
@@ -204,7 +207,8 @@ void VideoFrame::AllocateRGB(size_t bytes_per_pixel) {
}
void VideoFrame::AllocateYUV() {
- DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16);
+ DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
+ format_ == VideoFrame::YV12A);
// Align Y rows at least at 16 byte boundaries. The stride for both
// YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for
// U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
@@ -213,7 +217,9 @@ void VideoFrame::AllocateYUV() {
// YV16. We also round the height of the surface allocated to be an even
// number to avoid any potential of faulting by code that attempts to access
// the Y values of the final row, but assumes that the last row of U & V
- // applies to a full two rows of Y.
+ // applies to a full two rows of Y. YV12A is the same as YV12, but with an
+ // additional alpha plane that has the same size and alignment as the Y plane.
+
size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
kFrameSizeAlignment);
size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
@@ -222,9 +228,12 @@ void VideoFrame::AllocateYUV() {
// and then the size needs to be a multiple of two macroblocks (vertically).
// See libavcodec/utils.c:avcodec_align_dimensions2().
size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
- size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height;
+ size_t uv_height = (format_ == VideoFrame::YV12 ||
+ format_ == VideoFrame::YV12A) ?
+ y_height / 2 : y_height;
size_t y_bytes = y_height * y_stride;
size_t uv_bytes = uv_height * uv_stride;
+ size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
// The extra line of UV being allocated is because h264 chroma MC
// overreads by one line in some cases, see libavcodec/utils.c:
@@ -232,7 +241,7 @@ void VideoFrame::AllocateYUV() {
// put_h264_chroma_mc4_ssse3().
uint8* data = reinterpret_cast<uint8*>(
base::AlignedAlloc(
- y_bytes + (uv_bytes * 2 + uv_stride) + kFrameSizePadding,
+ y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding,
kFrameAddressAlignment));
no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
@@ -242,6 +251,10 @@ void VideoFrame::AllocateYUV() {
strides_[VideoFrame::kYPlane] = y_stride;
strides_[VideoFrame::kUPlane] = uv_stride;
strides_[VideoFrame::kVPlane] = uv_stride;
+ if (format_ == YV12A) {
+ data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
+ strides_[VideoFrame::kAPlane] = y_stride;
+ }
}
VideoFrame::VideoFrame(VideoFrame::Format format,
@@ -285,7 +298,8 @@ int VideoFrame::row_bytes(size_t plane) const {
// Planar, 8bpp.
case YV12:
case YV16:
- if (plane == kYPlane)
+ case YV12A:
+ if (plane == kYPlane || plane == kAPlane)
return width;
return RoundUp(width, 2) / 2;
@@ -307,7 +321,8 @@ int VideoFrame::rows(size_t plane) const {
return height;
case YV12:
- if (plane == kYPlane)
+ case YV12A:
+ if (plane == kYPlane || plane == kAPlane)
return height;
return RoundUp(height, 2) / 2;
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index 9a6f0a6..6cd5a0f 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -24,13 +24,14 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
};
enum {
- kMaxPlanes = 3,
+ kMaxPlanes = 4,
kRGBPlane = 0,
kYPlane = 0,
kUPlane = 1,
kVPlane = 2,
+ kAPlane = 3,
};
// Surface formats roughly based on FOURCC labels, see:
@@ -47,6 +48,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
#if defined(GOOGLE_TV)
HOLE = 13, // Hole frame.
#endif
+ YV12A = 14, // 20bpp YUVA planar 1x1 Y, 2x2 VU, 1x1 A samples.
};
// Creates a new frame in system memory with given parameters. Buffers for
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
index 972ac17..e1de7bd 100644
--- a/media/base/video_util.cc
+++ b/media/base/video_util.cc
@@ -62,6 +62,16 @@ void CopyVPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
CopyPlane(VideoFrame::kVPlane, source, stride, rows, frame);
}
+void CopyAPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
+ CopyPlane(VideoFrame::kAPlane, source, stride, rows, frame);
+}
+
+void MakeOpaqueAPlane(int stride, int rows, VideoFrame* frame) {
+ int rows_to_clear = std::min(frame->rows(VideoFrame::kAPlane), rows);
+ memset(frame->data(VideoFrame::kAPlane), 255,
+ frame->stride(VideoFrame::kAPlane) * rows_to_clear);
+}
+
void FillYUV(VideoFrame* frame, uint8 y, uint8 u, uint8 v) {
// Fill the Y plane.
uint8* y_plane = frame->data(VideoFrame::kYPlane);
diff --git a/media/base/video_util.h b/media/base/video_util.h
index 27156fa..05e5927 100644
--- a/media/base/video_util.h
+++ b/media/base/video_util.h
@@ -19,7 +19,7 @@ MEDIA_EXPORT gfx::Size GetNaturalSize(const gfx::Size& visible_size,
int aspect_ratio_numerator,
int aspect_ratio_denominator);
-// Copies a plane of YUV source into a VideoFrame object, taking into account
+// Copies a plane of YUV(A) source into a VideoFrame object, taking into account
// source and destinations dimensions.
//
// NOTE: rows is *not* the same as height!
@@ -29,8 +29,14 @@ MEDIA_EXPORT void CopyUPlane(const uint8* source, int stride, int rows,
VideoFrame* frame);
MEDIA_EXPORT void CopyVPlane(const uint8* source, int stride, int rows,
VideoFrame* frame);
+MEDIA_EXPORT void CopyAPlane(const uint8* source, int stride, int rows,
+ VideoFrame* frame);
+
+// Sets alpha plane values to be completely opaque (all 255's).
+MEDIA_EXPORT void MakeOpaqueAPlane(int stride, int rows, VideoFrame* frame);
+
// |plane| is one of VideoFrame::kYPlane, VideoFrame::kUPlane,
-// or VideoFrame::kVPlane.
+// VideoFrame::kVPlane or VideoFrame::kAPlane
MEDIA_EXPORT void CopyPlane(size_t plane, const uint8* source, int stride,
int rows, VideoFrame* frame);
diff --git a/media/base/yuv_convert.cc b/media/base/yuv_convert.cc
index 85b0699..1d09a24 100644
--- a/media/base/yuv_convert.cc
+++ b/media/base/yuv_convert.cc
@@ -603,4 +603,34 @@ void ConvertYUVToRGB32(const uint8* yplane,
#endif
}
+void ConvertYUVAToARGB(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbframe,
+ int width,
+ int height,
+ int ystride,
+ int uvstride,
+ int astride,
+ int rgbstride,
+ YUVType yuv_type) {
+#if defined(ARCH_CPU_ARM_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
+ ConvertYUVAToARGB_C(yplane, uplane, vplane, aplane, rgbframe,
+ width, height, ystride, uvstride, astride, rgbstride,
+ yuv_type);
+#else
+ static ConvertYUVAToARGBProc convert_proc = NULL;
+ if (!convert_proc) {
+ base::CPU cpu;
+ if (cpu.has_mmx())
+ convert_proc = &ConvertYUVAToARGB_MMX;
+ else
+ convert_proc = &ConvertYUVAToARGB_C;
+ }
+ convert_proc(yplane, uplane, vplane, aplane, rgbframe,
+ width, height, ystride, uvstride, astride, rgbstride, yuv_type);
+#endif
+}
+
} // namespace media
diff --git a/media/base/yuv_convert.h b/media/base/yuv_convert.h
index 30c07ab..0e53193 100644
--- a/media/base/yuv_convert.h
+++ b/media/base/yuv_convert.h
@@ -60,6 +60,21 @@ void ConvertYUVToRGB32(const uint8* yplane,
int rgbstride,
YUVType yuv_type);
+// Convert a frame of YUVA to 32 bit ARGB.
+// Pass in YV12A
+void ConvertYUVAToARGB(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ const uint8* aplane,
+ uint8* rgbframe,
+ int width,
+ int height,
+ int ystride,
+ int uvstride,
+ int astride,
+ int rgbstride,
+ YUVType yuv_type);
+
// Scale a frame of YUV to 32 bit ARGB.
// Supports rotation and mirroring.
void ScaleYUVToRGB32(const uint8* yplane,