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
3 // found in the LICENSE file.
5 #include "media/base/video_frame.h"
7 #include "base/format_macros.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/stringprintf.h"
10 #include "media/base/buffers.h"
11 #include "media/base/yuv_convert.h"
12 #include "testing/gtest/include/gtest/gtest.h"
16 using base::MD5DigestToBase16
;
18 // Helper function that initializes a YV12 frame with white and black scan
19 // lines based on the |white_to_black| parameter. If 0, then the entire
20 // frame will be black, if 1 then the entire frame will be white.
21 void InitializeYV12Frame(VideoFrame
* frame
, double white_to_black
) {
22 EXPECT_EQ(VideoFrame::YV12
, frame
->format());
23 int first_black_row
= static_cast<int>(frame
->coded_size().height() *
25 uint8
* y_plane
= frame
->data(VideoFrame::kYPlane
);
26 for (int row
= 0; row
< frame
->coded_size().height(); ++row
) {
27 int color
= (row
< first_black_row
) ? 0xFF : 0x00;
28 memset(y_plane
, color
, frame
->stride(VideoFrame::kYPlane
));
29 y_plane
+= frame
->stride(VideoFrame::kYPlane
);
31 uint8
* u_plane
= frame
->data(VideoFrame::kUPlane
);
32 uint8
* v_plane
= frame
->data(VideoFrame::kVPlane
);
33 for (int row
= 0; row
< frame
->coded_size().height(); row
+= 2) {
34 memset(u_plane
, 0x80, frame
->stride(VideoFrame::kUPlane
));
35 memset(v_plane
, 0x80, frame
->stride(VideoFrame::kVPlane
));
36 u_plane
+= frame
->stride(VideoFrame::kUPlane
);
37 v_plane
+= frame
->stride(VideoFrame::kVPlane
);
41 // Given a |yv12_frame| this method converts the YV12 frame to RGBA and
42 // makes sure that all the pixels of the RBG frame equal |expect_rgb_color|.
43 void ExpectFrameColor(media::VideoFrame
* yv12_frame
, uint32 expect_rgb_color
) {
44 ASSERT_EQ(VideoFrame::YV12
, yv12_frame
->format());
45 ASSERT_EQ(yv12_frame
->stride(VideoFrame::kUPlane
),
46 yv12_frame
->stride(VideoFrame::kVPlane
));
48 scoped_refptr
<media::VideoFrame
> rgb_frame
;
49 rgb_frame
= media::VideoFrame::CreateFrame(VideoFrame::RGB32
,
50 yv12_frame
->coded_size(),
51 yv12_frame
->visible_rect(),
52 yv12_frame
->natural_size(),
53 yv12_frame
->GetTimestamp());
55 ASSERT_EQ(yv12_frame
->coded_size().width(),
56 rgb_frame
->coded_size().width());
57 ASSERT_EQ(yv12_frame
->coded_size().height(),
58 rgb_frame
->coded_size().height());
60 media::ConvertYUVToRGB32(yv12_frame
->data(VideoFrame::kYPlane
),
61 yv12_frame
->data(VideoFrame::kUPlane
),
62 yv12_frame
->data(VideoFrame::kVPlane
),
63 rgb_frame
->data(VideoFrame::kRGBPlane
),
64 rgb_frame
->coded_size().width(),
65 rgb_frame
->coded_size().height(),
66 yv12_frame
->stride(VideoFrame::kYPlane
),
67 yv12_frame
->stride(VideoFrame::kUPlane
),
68 rgb_frame
->stride(VideoFrame::kRGBPlane
),
71 for (int row
= 0; row
< rgb_frame
->coded_size().height(); ++row
) {
72 uint32
* rgb_row_data
= reinterpret_cast<uint32
*>(
73 rgb_frame
->data(VideoFrame::kRGBPlane
) +
74 (rgb_frame
->stride(VideoFrame::kRGBPlane
) * row
));
75 for (int col
= 0; col
< rgb_frame
->coded_size().width(); ++col
) {
77 base::StringPrintf("Checking (%d, %d)", row
, col
));
78 EXPECT_EQ(expect_rgb_color
, rgb_row_data
[col
]);
83 // Fill each plane to its reported extents and verify accessors report non
84 // zero values. Additionally, for the first plane verify the rows and
85 // row_bytes values are correct.
86 void ExpectFrameExtents(VideoFrame::Format format
, int planes
,
87 int bytes_per_pixel
, const char* expected_hash
) {
88 const unsigned char kFillByte
= 0x80;
89 const int kWidth
= 61;
90 const int kHeight
= 31;
91 const base::TimeDelta kTimestamp
= base::TimeDelta::FromMicroseconds(1337);
93 gfx::Size
size(kWidth
, kHeight
);
94 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
95 format
, size
, gfx::Rect(size
), size
, kTimestamp
);
96 ASSERT_TRUE(frame
.get());
98 for(int plane
= 0; plane
< planes
; plane
++) {
99 SCOPED_TRACE(base::StringPrintf("Checking plane %d", plane
));
100 EXPECT_TRUE(frame
->data(plane
));
101 EXPECT_TRUE(frame
->stride(plane
));
102 EXPECT_TRUE(frame
->rows(plane
));
103 EXPECT_TRUE(frame
->row_bytes(plane
));
106 EXPECT_EQ(frame
->rows(plane
), kHeight
);
107 EXPECT_EQ(frame
->row_bytes(plane
), kWidth
* bytes_per_pixel
);
110 memset(frame
->data(plane
), kFillByte
,
111 frame
->stride(plane
) * frame
->rows(plane
));
114 base::MD5Context context
;
115 base::MD5Init(&context
);
116 frame
->HashFrameForTesting(&context
);
117 base::MD5Digest digest
;
118 base::MD5Final(&digest
, &context
);
119 EXPECT_EQ(MD5DigestToBase16(digest
), expected_hash
);
122 TEST(VideoFrame
, CreateFrame
) {
123 const int kWidth
= 64;
124 const int kHeight
= 48;
125 const base::TimeDelta kTimestamp
= base::TimeDelta::FromMicroseconds(1337);
127 // Create a YV12 Video Frame.
128 gfx::Size
size(kWidth
, kHeight
);
129 scoped_refptr
<media::VideoFrame
> frame
=
130 VideoFrame::CreateFrame(media::VideoFrame::YV12
, size
, gfx::Rect(size
),
132 ASSERT_TRUE(frame
.get());
134 // Test VideoFrame implementation.
135 EXPECT_EQ(media::VideoFrame::YV12
, frame
->format());
138 InitializeYV12Frame(frame
.get(), 0.0f
);
139 ExpectFrameColor(frame
.get(), 0xFF000000);
141 base::MD5Digest digest
;
142 base::MD5Context context
;
143 base::MD5Init(&context
);
144 frame
->HashFrameForTesting(&context
);
145 base::MD5Final(&digest
, &context
);
146 EXPECT_EQ(MD5DigestToBase16(digest
), "9065c841d9fca49186ef8b4ef547e79b");
149 InitializeYV12Frame(frame
.get(), 1.0f
);
150 ExpectFrameColor(frame
.get(), 0xFFFFFFFF);
152 base::MD5Init(&context
);
153 frame
->HashFrameForTesting(&context
);
154 base::MD5Final(&digest
, &context
);
155 EXPECT_EQ(MD5DigestToBase16(digest
), "911991d51438ad2e1a40ed5f6fc7c796");
157 // Test an empty frame.
158 frame
= VideoFrame::CreateEmptyFrame();
159 EXPECT_TRUE(frame
->IsEndOfStream());
162 TEST(VideoFrame
, CreateBlackFrame
) {
163 const int kWidth
= 2;
164 const int kHeight
= 2;
165 const uint8 kExpectedYRow
[] = { 0, 0 };
166 const uint8 kExpectedUVRow
[] = { 128 };
168 scoped_refptr
<media::VideoFrame
> frame
=
169 VideoFrame::CreateBlackFrame(gfx::Size(kWidth
, kHeight
));
170 ASSERT_TRUE(frame
.get());
172 // Test basic properties.
173 EXPECT_EQ(0, frame
->GetTimestamp().InMicroseconds());
174 EXPECT_FALSE(frame
->IsEndOfStream());
176 // Test |frame| properties.
177 EXPECT_EQ(VideoFrame::YV12
, frame
->format());
178 EXPECT_EQ(kWidth
, frame
->coded_size().width());
179 EXPECT_EQ(kHeight
, frame
->coded_size().height());
181 // Test frames themselves.
182 uint8
* y_plane
= frame
->data(VideoFrame::kYPlane
);
183 for (int y
= 0; y
< frame
->coded_size().height(); ++y
) {
184 EXPECT_EQ(0, memcmp(kExpectedYRow
, y_plane
, arraysize(kExpectedYRow
)));
185 y_plane
+= frame
->stride(VideoFrame::kYPlane
);
188 uint8
* u_plane
= frame
->data(VideoFrame::kUPlane
);
189 uint8
* v_plane
= frame
->data(VideoFrame::kVPlane
);
190 for (int y
= 0; y
< frame
->coded_size().height() / 2; ++y
) {
191 EXPECT_EQ(0, memcmp(kExpectedUVRow
, u_plane
, arraysize(kExpectedUVRow
)));
192 EXPECT_EQ(0, memcmp(kExpectedUVRow
, v_plane
, arraysize(kExpectedUVRow
)));
193 u_plane
+= frame
->stride(VideoFrame::kUPlane
);
194 v_plane
+= frame
->stride(VideoFrame::kVPlane
);
198 // Ensure each frame is properly sized and allocated. Will trigger OOB reads
199 // and writes as well as incorrect frame hashes otherwise.
200 TEST(VideoFrame
, CheckFrameExtents
) {
201 // Each call consists of a VideoFrame::Format, # of planes, bytes per pixel,
202 // and the expected hash of all planes if filled with kFillByte (defined in
203 // ExpectFrameExtents).
205 VideoFrame::RGB32
, 1, 4, "de6d3d567e282f6a38d478f04fc81fb0");
207 VideoFrame::YV12
, 3, 1, "71113bdfd4c0de6cf62f48fb74f7a0b1");
209 VideoFrame::YV16
, 3, 1, "9bb99ac3ff350644ebff4d28dc01b461");