summaryrefslogtreecommitdiff
path: root/media/base/video_frame_unittest.cc
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2012-11-14 11:43:16 +0000
committerTorne (Richard Coles) <torne@google.com>2012-11-14 11:43:16 +0000
commit5821806d5e7f356e8fa4b058a389a808ea183019 (patch)
treee19f4793aac92e2c0d9a01087019a60d6657d838 /media/base/video_frame_unittest.cc
parent8e79a8efe247f109aafd917a69e8a392961b3687 (diff)
downloadchromium_org-5821806d5e7f356e8fa4b058a389a808ea183019.tar.gz
Merge from Chromium at DEPS revision r167172
This commit was generated by merge_to_master.py. Change-Id: Ib8d56fd5ae39a2d7e8c91dcd76cc6d13f25f2aab
Diffstat (limited to 'media/base/video_frame_unittest.cc')
-rw-r--r--media/base/video_frame_unittest.cc212
1 files changed, 212 insertions, 0 deletions
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
new file mode 100644
index 0000000000..18cc1d3dd3
--- /dev/null
+++ b/media/base/video_frame_unittest.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2012 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/video_frame.h"
+
+#include "base/format_macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stringprintf.h"
+#include "media/base/buffers.h"
+#include "media/base/yuv_convert.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+using base::MD5DigestToBase16;
+
+// Helper function that initializes a YV12 frame with white and black scan
+// lines based on the |white_to_black| parameter. If 0, then the entire
+// frame will be black, if 1 then the entire frame will be white.
+void InitializeYV12Frame(VideoFrame* frame, double white_to_black) {
+ EXPECT_EQ(VideoFrame::YV12, frame->format());
+ int first_black_row = static_cast<int>(frame->coded_size().height() *
+ white_to_black);
+ uint8* y_plane = frame->data(VideoFrame::kYPlane);
+ for (int row = 0; row < frame->coded_size().height(); ++row) {
+ int color = (row < first_black_row) ? 0xFF : 0x00;
+ memset(y_plane, color, frame->stride(VideoFrame::kYPlane));
+ y_plane += frame->stride(VideoFrame::kYPlane);
+ }
+ uint8* u_plane = frame->data(VideoFrame::kUPlane);
+ uint8* v_plane = frame->data(VideoFrame::kVPlane);
+ for (int row = 0; row < frame->coded_size().height(); row += 2) {
+ memset(u_plane, 0x80, frame->stride(VideoFrame::kUPlane));
+ memset(v_plane, 0x80, frame->stride(VideoFrame::kVPlane));
+ u_plane += frame->stride(VideoFrame::kUPlane);
+ v_plane += frame->stride(VideoFrame::kVPlane);
+ }
+}
+
+// Given a |yv12_frame| this method converts the YV12 frame to RGBA and
+// makes sure that all the pixels of the RBG frame equal |expect_rgb_color|.
+void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) {
+ ASSERT_EQ(VideoFrame::YV12, yv12_frame->format());
+ ASSERT_EQ(yv12_frame->stride(VideoFrame::kUPlane),
+ yv12_frame->stride(VideoFrame::kVPlane));
+
+ scoped_refptr<media::VideoFrame> rgb_frame;
+ rgb_frame = media::VideoFrame::CreateFrame(VideoFrame::RGB32,
+ yv12_frame->coded_size(),
+ yv12_frame->visible_rect(),
+ yv12_frame->natural_size(),
+ yv12_frame->GetTimestamp());
+
+ ASSERT_EQ(yv12_frame->coded_size().width(),
+ rgb_frame->coded_size().width());
+ ASSERT_EQ(yv12_frame->coded_size().height(),
+ rgb_frame->coded_size().height());
+
+ media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane),
+ yv12_frame->data(VideoFrame::kUPlane),
+ yv12_frame->data(VideoFrame::kVPlane),
+ rgb_frame->data(VideoFrame::kRGBPlane),
+ rgb_frame->coded_size().width(),
+ rgb_frame->coded_size().height(),
+ yv12_frame->stride(VideoFrame::kYPlane),
+ yv12_frame->stride(VideoFrame::kUPlane),
+ rgb_frame->stride(VideoFrame::kRGBPlane),
+ media::YV12);
+
+ for (int row = 0; row < rgb_frame->coded_size().height(); ++row) {
+ uint32* rgb_row_data = reinterpret_cast<uint32*>(
+ rgb_frame->data(VideoFrame::kRGBPlane) +
+ (rgb_frame->stride(VideoFrame::kRGBPlane) * row));
+ for (int col = 0; col < rgb_frame->coded_size().width(); ++col) {
+ SCOPED_TRACE(
+ base::StringPrintf("Checking (%d, %d)", row, col));
+ EXPECT_EQ(expect_rgb_color, rgb_row_data[col]);
+ }
+ }
+}
+
+// Fill each plane to its reported extents and verify accessors report non
+// zero values. Additionally, for the first plane verify the rows and
+// row_bytes values are correct.
+void ExpectFrameExtents(VideoFrame::Format format, int planes,
+ int bytes_per_pixel, const char* expected_hash) {
+ const unsigned char kFillByte = 0x80;
+ const int kWidth = 61;
+ const int kHeight = 31;
+ const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337);
+
+ gfx::Size size(kWidth, kHeight);
+ scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
+ format, size, gfx::Rect(size), size, kTimestamp);
+ ASSERT_TRUE(frame);
+
+ for(int plane = 0; plane < planes; plane++) {
+ SCOPED_TRACE(base::StringPrintf("Checking plane %d", plane));
+ EXPECT_TRUE(frame->data(plane));
+ EXPECT_TRUE(frame->stride(plane));
+ EXPECT_TRUE(frame->rows(plane));
+ EXPECT_TRUE(frame->row_bytes(plane));
+
+ if (plane == 0) {
+ EXPECT_EQ(frame->rows(plane), kHeight);
+ EXPECT_EQ(frame->row_bytes(plane), kWidth * bytes_per_pixel);
+ }
+
+ memset(frame->data(plane), kFillByte,
+ frame->stride(plane) * frame->rows(plane));
+ }
+
+ base::MD5Context context;
+ base::MD5Init(&context);
+ frame->HashFrameForTesting(&context);
+ base::MD5Digest digest;
+ base::MD5Final(&digest, &context);
+ EXPECT_EQ(MD5DigestToBase16(digest), expected_hash);
+}
+
+TEST(VideoFrame, CreateFrame) {
+ const int kWidth = 64;
+ const int kHeight = 48;
+ const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337);
+
+ // Create a YV12 Video Frame.
+ gfx::Size size(kWidth, kHeight);
+ scoped_refptr<media::VideoFrame> frame =
+ VideoFrame::CreateFrame(media::VideoFrame::YV12, size, gfx::Rect(size),
+ size, kTimestamp);
+ ASSERT_TRUE(frame);
+
+ // Test VideoFrame implementation.
+ EXPECT_EQ(media::VideoFrame::YV12, frame->format());
+ {
+ SCOPED_TRACE("");
+ InitializeYV12Frame(frame, 0.0f);
+ ExpectFrameColor(frame, 0xFF000000);
+ }
+ base::MD5Digest digest;
+ base::MD5Context context;
+ base::MD5Init(&context);
+ frame->HashFrameForTesting(&context);
+ base::MD5Final(&digest, &context);
+ EXPECT_EQ(MD5DigestToBase16(digest), "9065c841d9fca49186ef8b4ef547e79b");
+ {
+ SCOPED_TRACE("");
+ InitializeYV12Frame(frame, 1.0f);
+ ExpectFrameColor(frame, 0xFFFFFFFF);
+ }
+ base::MD5Init(&context);
+ frame->HashFrameForTesting(&context);
+ base::MD5Final(&digest, &context);
+ EXPECT_EQ(MD5DigestToBase16(digest), "911991d51438ad2e1a40ed5f6fc7c796");
+
+ // Test an empty frame.
+ frame = VideoFrame::CreateEmptyFrame();
+ EXPECT_TRUE(frame->IsEndOfStream());
+}
+
+TEST(VideoFrame, CreateBlackFrame) {
+ const int kWidth = 2;
+ const int kHeight = 2;
+ const uint8 kExpectedYRow[] = { 0, 0 };
+ const uint8 kExpectedUVRow[] = { 128 };
+
+ scoped_refptr<media::VideoFrame> frame =
+ VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight));
+ ASSERT_TRUE(frame);
+
+ // Test basic properties.
+ EXPECT_EQ(0, frame->GetTimestamp().InMicroseconds());
+ EXPECT_FALSE(frame->IsEndOfStream());
+
+ // Test |frame| properties.
+ EXPECT_EQ(VideoFrame::YV12, frame->format());
+ EXPECT_EQ(kWidth, frame->coded_size().width());
+ EXPECT_EQ(kHeight, frame->coded_size().height());
+
+ // Test frames themselves.
+ uint8* y_plane = frame->data(VideoFrame::kYPlane);
+ for (int y = 0; y < frame->coded_size().height(); ++y) {
+ EXPECT_EQ(0, memcmp(kExpectedYRow, y_plane, arraysize(kExpectedYRow)));
+ y_plane += frame->stride(VideoFrame::kYPlane);
+ }
+
+ uint8* u_plane = frame->data(VideoFrame::kUPlane);
+ uint8* v_plane = frame->data(VideoFrame::kVPlane);
+ for (int y = 0; y < frame->coded_size().height() / 2; ++y) {
+ EXPECT_EQ(0, memcmp(kExpectedUVRow, u_plane, arraysize(kExpectedUVRow)));
+ EXPECT_EQ(0, memcmp(kExpectedUVRow, v_plane, arraysize(kExpectedUVRow)));
+ u_plane += frame->stride(VideoFrame::kUPlane);
+ v_plane += frame->stride(VideoFrame::kVPlane);
+ }
+}
+
+// Ensure each frame is properly sized and allocated. Will trigger OOB reads
+// and writes as well as incorrect frame hashes otherwise.
+TEST(VideoFrame, CheckFrameExtents) {
+ // Each call consists of a VideoFrame::Format, # of planes, bytes per pixel,
+ // and the expected hash of all planes if filled with kFillByte (defined in
+ // ExpectFrameExtents).
+ ExpectFrameExtents(
+ VideoFrame::RGB32, 1, 4, "de6d3d567e282f6a38d478f04fc81fb0");
+ ExpectFrameExtents(
+ VideoFrame::YV12, 3, 1, "71113bdfd4c0de6cf62f48fb74f7a0b1");
+ ExpectFrameExtents(
+ VideoFrame::YV16, 3, 1, "9bb99ac3ff350644ebff4d28dc01b461");
+}
+
+} // namespace media