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"
8 #include "base/callback_helpers.h"
9 #include "base/format_macros.h"
10 #include "base/memory/aligned_memory.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/stringprintf.h"
13 #include "gpu/command_buffer/common/mailbox_holder.h"
14 #include "media/base/buffers.h"
15 #include "media/base/yuv_convert.h"
16 #include "testing/gtest/include/gtest/gtest.h"
20 using base::MD5DigestToBase16
;
22 // Helper function that initializes a YV12 frame with white and black scan
23 // lines based on the |white_to_black| parameter. If 0, then the entire
24 // frame will be black, if 1 then the entire frame will be white.
25 void InitializeYV12Frame(VideoFrame
* frame
, double white_to_black
) {
26 EXPECT_EQ(VideoFrame::YV12
, frame
->format());
27 int first_black_row
= static_cast<int>(frame
->coded_size().height() *
29 uint8
* y_plane
= frame
->data(VideoFrame::kYPlane
);
30 for (int row
= 0; row
< frame
->coded_size().height(); ++row
) {
31 int color
= (row
< first_black_row
) ? 0xFF : 0x00;
32 memset(y_plane
, color
, frame
->stride(VideoFrame::kYPlane
));
33 y_plane
+= frame
->stride(VideoFrame::kYPlane
);
35 uint8
* u_plane
= frame
->data(VideoFrame::kUPlane
);
36 uint8
* v_plane
= frame
->data(VideoFrame::kVPlane
);
37 for (int row
= 0; row
< frame
->coded_size().height(); row
+= 2) {
38 memset(u_plane
, 0x80, frame
->stride(VideoFrame::kUPlane
));
39 memset(v_plane
, 0x80, frame
->stride(VideoFrame::kVPlane
));
40 u_plane
+= frame
->stride(VideoFrame::kUPlane
);
41 v_plane
+= frame
->stride(VideoFrame::kVPlane
);
45 // Given a |yv12_frame| this method converts the YV12 frame to RGBA and
46 // makes sure that all the pixels of the RBG frame equal |expect_rgb_color|.
47 void ExpectFrameColor(media::VideoFrame
* yv12_frame
, uint32 expect_rgb_color
) {
48 ASSERT_EQ(VideoFrame::YV12
, yv12_frame
->format());
49 ASSERT_EQ(yv12_frame
->stride(VideoFrame::kUPlane
),
50 yv12_frame
->stride(VideoFrame::kVPlane
));
52 yv12_frame
->coded_size().width() & (VideoFrame::kFrameSizeAlignment
- 1),
55 yv12_frame
->coded_size().height() & (VideoFrame::kFrameSizeAlignment
- 1),
58 size_t bytes_per_row
= yv12_frame
->coded_size().width() * 4u;
59 uint8
* rgb_data
= reinterpret_cast<uint8
*>(
60 base::AlignedAlloc(bytes_per_row
* yv12_frame
->coded_size().height() +
61 VideoFrame::kFrameSizePadding
,
62 VideoFrame::kFrameAddressAlignment
));
64 media::ConvertYUVToRGB32(yv12_frame
->data(VideoFrame::kYPlane
),
65 yv12_frame
->data(VideoFrame::kUPlane
),
66 yv12_frame
->data(VideoFrame::kVPlane
),
68 yv12_frame
->coded_size().width(),
69 yv12_frame
->coded_size().height(),
70 yv12_frame
->stride(VideoFrame::kYPlane
),
71 yv12_frame
->stride(VideoFrame::kUPlane
),
75 for (int row
= 0; row
< yv12_frame
->coded_size().height(); ++row
) {
76 uint32
* rgb_row_data
= reinterpret_cast<uint32
*>(
77 rgb_data
+ (bytes_per_row
* row
));
78 for (int col
= 0; col
< yv12_frame
->coded_size().width(); ++col
) {
80 base::StringPrintf("Checking (%d, %d)", row
, col
));
81 EXPECT_EQ(expect_rgb_color
, rgb_row_data
[col
]);
85 base::AlignedFree(rgb_data
);
88 // Fill each plane to its reported extents and verify accessors report non
89 // zero values. Additionally, for the first plane verify the rows and
90 // row_bytes values are correct.
91 void ExpectFrameExtents(VideoFrame::Format format
, const char* expected_hash
) {
92 const unsigned char kFillByte
= 0x80;
93 const int kWidth
= 61;
94 const int kHeight
= 31;
95 const base::TimeDelta kTimestamp
= base::TimeDelta::FromMicroseconds(1337);
97 gfx::Size
size(kWidth
, kHeight
);
98 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
99 format
, size
, gfx::Rect(size
), size
, kTimestamp
);
100 ASSERT_TRUE(frame
.get());
102 int planes
= VideoFrame::NumPlanes(format
);
103 for (int plane
= 0; plane
< planes
; plane
++) {
104 SCOPED_TRACE(base::StringPrintf("Checking plane %d", plane
));
105 EXPECT_TRUE(frame
->data(plane
));
106 EXPECT_TRUE(frame
->stride(plane
));
107 EXPECT_TRUE(frame
->rows(plane
));
108 EXPECT_TRUE(frame
->row_bytes(plane
));
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::CreateEOSFrame();
159 EXPECT_TRUE(frame
->end_of_stream());
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
->timestamp().InMicroseconds());
174 EXPECT_FALSE(frame
->end_of_stream());
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 static void FrameNoLongerNeededCallback(
199 const scoped_refptr
<media::VideoFrame
>& frame
,
204 TEST(VideoFrame
, WrapVideoFrame
) {
205 const int kWidth
= 4;
206 const int kHeight
= 4;
207 scoped_refptr
<media::VideoFrame
> frame
;
208 bool no_longer_needed_triggered
= false;
210 scoped_refptr
<media::VideoFrame
> wrapped_frame
=
211 VideoFrame::CreateBlackFrame(gfx::Size(kWidth
, kHeight
));
212 ASSERT_TRUE(wrapped_frame
.get());
214 gfx::Rect
visible_rect(1, 1, 1, 1);
215 gfx::Size natural_size
= visible_rect
.size();
216 frame
= media::VideoFrame::WrapVideoFrame(
217 wrapped_frame
, visible_rect
, natural_size
,
218 base::Bind(&FrameNoLongerNeededCallback
, wrapped_frame
,
219 &no_longer_needed_triggered
));
220 EXPECT_EQ(wrapped_frame
->coded_size(), frame
->coded_size());
221 EXPECT_EQ(wrapped_frame
->data(media::VideoFrame::kYPlane
),
222 frame
->data(media::VideoFrame::kYPlane
));
223 EXPECT_NE(wrapped_frame
->visible_rect(), frame
->visible_rect());
224 EXPECT_EQ(visible_rect
, frame
->visible_rect());
225 EXPECT_NE(wrapped_frame
->natural_size(), frame
->natural_size());
226 EXPECT_EQ(natural_size
, frame
->natural_size());
229 EXPECT_FALSE(no_longer_needed_triggered
);
231 EXPECT_TRUE(no_longer_needed_triggered
);
234 // Ensure each frame is properly sized and allocated. Will trigger OOB reads
235 // and writes as well as incorrect frame hashes otherwise.
236 TEST(VideoFrame
, CheckFrameExtents
) {
237 // Each call consists of a VideoFrame::Format and the expected hash of all
238 // planes if filled with kFillByte (defined in ExpectFrameExtents).
239 ExpectFrameExtents(VideoFrame::YV12
, "8e5d54cb23cd0edca111dd35ffb6ff05");
240 ExpectFrameExtents(VideoFrame::YV16
, "cce408a044b212db42a10dfec304b3ef");
243 static void TextureCallback(uint32
* called_sync_point
,
244 uint32 release_sync_point
) {
245 *called_sync_point
= release_sync_point
;
248 // Verify the gpu::MailboxHolder::ReleaseCallback is called when VideoFrame is
249 // destroyed with the default release sync point.
250 TEST(VideoFrame
, TextureNoLongerNeededCallbackIsCalled
) {
251 uint32 called_sync_point
= 1;
254 scoped_refptr
<VideoFrame
> frame
= VideoFrame::WrapNativeTexture(
256 new gpu::MailboxHolder(gpu::Mailbox(), 5, 0 /* sync_point */)),
257 base::Bind(&TextureCallback
, &called_sync_point
),
258 gfx::Size(10, 10), // coded_size
259 gfx::Rect(10, 10), // visible_rect
260 gfx::Size(10, 10), // natural_size
261 base::TimeDelta(), // timestamp
262 false); // allow_overlay
264 // Nobody set a sync point to |frame|, so |frame| set |called_sync_point| to 0
266 EXPECT_EQ(0u, called_sync_point
);
271 class SyncPointClientImpl
: public VideoFrame::SyncPointClient
{
273 explicit SyncPointClientImpl(uint32 sync_point
) : sync_point_(sync_point
) {}
274 ~SyncPointClientImpl() override
{}
275 uint32
InsertSyncPoint() override
{ return sync_point_
; }
276 void WaitSyncPoint(uint32 sync_point
) override
{}
284 // Verify the gpu::MailboxHolder::ReleaseCallback is called when VideoFrame is
285 // destroyed with the release sync point, which was updated by clients.
286 // (i.e. the compositor, webgl).
287 TEST(VideoFrame
, TextureNoLongerNeededCallbackAfterTakingAndReleasingMailbox
) {
288 gpu::Mailbox mailbox
;
289 mailbox
.name
[0] = 50;
290 uint32 sync_point
= 7;
292 uint32 release_sync_point
= 111;
293 uint32 called_sync_point
= 0;
296 scoped_refptr
<VideoFrame
> frame
= VideoFrame::WrapNativeTexture(
297 make_scoped_ptr(new gpu::MailboxHolder(mailbox
, target
, sync_point
)),
298 base::Bind(&TextureCallback
, &called_sync_point
),
299 gfx::Size(10, 10), // coded_size
300 gfx::Rect(10, 10), // visible_rect
301 gfx::Size(10, 10), // natural_size
302 base::TimeDelta(), // timestamp
303 false); // allow_overlay
305 const gpu::MailboxHolder
* mailbox_holder
= frame
->mailbox_holder();
307 EXPECT_EQ(mailbox
.name
[0], mailbox_holder
->mailbox
.name
[0]);
308 EXPECT_EQ(target
, mailbox_holder
->texture_target
);
309 EXPECT_EQ(sync_point
, mailbox_holder
->sync_point
);
311 SyncPointClientImpl
client(release_sync_point
);
312 frame
->UpdateReleaseSyncPoint(&client
);
313 EXPECT_EQ(sync_point
, mailbox_holder
->sync_point
);
315 EXPECT_EQ(release_sync_point
, called_sync_point
);
318 TEST(VideoFrame
, ZeroInitialized
) {
319 const int kWidth
= 64;
320 const int kHeight
= 48;
321 const base::TimeDelta kTimestamp
= base::TimeDelta::FromMicroseconds(1337);
323 gfx::Size
size(kWidth
, kHeight
);
324 scoped_refptr
<media::VideoFrame
> frame
= VideoFrame::CreateFrame(
325 media::VideoFrame::YV12
, size
, gfx::Rect(size
), size
, kTimestamp
);
327 for (size_t i
= 0; i
< VideoFrame::NumPlanes(frame
->format()); ++i
)
328 EXPECT_EQ(0, frame
->data(i
)[0]);
331 TEST(VideoFrameMetadata
, SetAndThenGetAllKeysForAllTypes
) {
332 VideoFrameMetadata metadata
;
334 for (int i
= 0; i
< VideoFrameMetadata::NUM_KEYS
; ++i
) {
335 const VideoFrameMetadata::Key key
= static_cast<VideoFrameMetadata::Key
>(i
);
337 EXPECT_FALSE(metadata
.HasKey(key
));
338 metadata
.SetBoolean(key
, true);
339 EXPECT_TRUE(metadata
.HasKey(key
));
340 bool bool_value
= false;
341 EXPECT_TRUE(metadata
.GetBoolean(key
, &bool_value
));
342 EXPECT_EQ(true, bool_value
);
345 EXPECT_FALSE(metadata
.HasKey(key
));
346 metadata
.SetInteger(key
, i
);
347 EXPECT_TRUE(metadata
.HasKey(key
));
348 int int_value
= -999;
349 EXPECT_TRUE(metadata
.GetInteger(key
, &int_value
));
350 EXPECT_EQ(i
, int_value
);
353 EXPECT_FALSE(metadata
.HasKey(key
));
354 metadata
.SetDouble(key
, 3.14 * i
);
355 EXPECT_TRUE(metadata
.HasKey(key
));
356 double double_value
= -999.99;
357 EXPECT_TRUE(metadata
.GetDouble(key
, &double_value
));
358 EXPECT_EQ(3.14 * i
, double_value
);
361 EXPECT_FALSE(metadata
.HasKey(key
));
362 metadata
.SetString(key
, base::StringPrintf("\xfe%d\xff", i
));
363 EXPECT_TRUE(metadata
.HasKey(key
));
364 std::string string_value
;
365 EXPECT_TRUE(metadata
.GetString(key
, &string_value
));
366 EXPECT_EQ(base::StringPrintf("\xfe%d\xff", i
), string_value
);
369 EXPECT_FALSE(metadata
.HasKey(key
));
370 metadata
.SetTimeTicks(key
, base::TimeTicks::FromInternalValue(~(0LL) + i
));
371 EXPECT_TRUE(metadata
.HasKey(key
));
372 base::TimeTicks ticks_value
;
373 EXPECT_TRUE(metadata
.GetTimeTicks(key
, &ticks_value
));
374 EXPECT_EQ(base::TimeTicks::FromInternalValue(~(0LL) + i
), ticks_value
);
377 EXPECT_FALSE(metadata
.HasKey(key
));
378 metadata
.SetValue(key
,
379 scoped_ptr
<base::Value
>(base::Value::CreateNullValue()));
380 EXPECT_TRUE(metadata
.HasKey(key
));
381 const base::Value
* const null_value
= metadata
.GetValue(key
);
382 EXPECT_TRUE(null_value
);
383 EXPECT_EQ(base::Value::TYPE_NULL
, null_value
->GetType());
388 TEST(VideoFrameMetadata
, PassMetadataViaIntermediary
) {
389 VideoFrameMetadata expected
;
390 for (int i
= 0; i
< VideoFrameMetadata::NUM_KEYS
; ++i
) {
391 const VideoFrameMetadata::Key key
= static_cast<VideoFrameMetadata::Key
>(i
);
392 expected
.SetInteger(key
, i
);
395 base::DictionaryValue tmp
;
396 expected
.MergeInternalValuesInto(&tmp
);
397 EXPECT_EQ(static_cast<size_t>(VideoFrameMetadata::NUM_KEYS
), tmp
.size());
399 VideoFrameMetadata result
;
400 result
.MergeInternalValuesFrom(tmp
);
402 for (int i
= 0; i
< VideoFrameMetadata::NUM_KEYS
; ++i
) {
403 const VideoFrameMetadata::Key key
= static_cast<VideoFrameMetadata::Key
>(i
);
405 EXPECT_TRUE(result
.GetInteger(key
, &value
));