- add sources.
[platform/framework/web/crosswalk.git] / src / media / base / video_frame_unittest.cc
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.
4
5 #include "media/base/video_frame.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/format_macros.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/stringprintf.h"
12 #include "media/base/buffers.h"
13 #include "media/base/yuv_convert.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace media {
17
18 using base::MD5DigestToBase16;
19
20 // Helper function that initializes a YV12 frame with white and black scan
21 // lines based on the |white_to_black| parameter.  If 0, then the entire
22 // frame will be black, if 1 then the entire frame will be white.
23 void InitializeYV12Frame(VideoFrame* frame, double white_to_black) {
24   EXPECT_EQ(VideoFrame::YV12, frame->format());
25   int first_black_row = static_cast<int>(frame->coded_size().height() *
26                                          white_to_black);
27   uint8* y_plane = frame->data(VideoFrame::kYPlane);
28   for (int row = 0; row < frame->coded_size().height(); ++row) {
29     int color = (row < first_black_row) ? 0xFF : 0x00;
30     memset(y_plane, color, frame->stride(VideoFrame::kYPlane));
31     y_plane += frame->stride(VideoFrame::kYPlane);
32   }
33   uint8* u_plane = frame->data(VideoFrame::kUPlane);
34   uint8* v_plane = frame->data(VideoFrame::kVPlane);
35   for (int row = 0; row < frame->coded_size().height(); row += 2) {
36     memset(u_plane, 0x80, frame->stride(VideoFrame::kUPlane));
37     memset(v_plane, 0x80, frame->stride(VideoFrame::kVPlane));
38     u_plane += frame->stride(VideoFrame::kUPlane);
39     v_plane += frame->stride(VideoFrame::kVPlane);
40   }
41 }
42
43 // Given a |yv12_frame| this method converts the YV12 frame to RGBA and
44 // makes sure that all the pixels of the RBG frame equal |expect_rgb_color|.
45 void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) {
46   ASSERT_EQ(VideoFrame::YV12, yv12_frame->format());
47   ASSERT_EQ(yv12_frame->stride(VideoFrame::kUPlane),
48             yv12_frame->stride(VideoFrame::kVPlane));
49
50   scoped_refptr<media::VideoFrame> rgb_frame;
51   rgb_frame = media::VideoFrame::CreateFrame(VideoFrame::RGB32,
52                                              yv12_frame->coded_size(),
53                                              yv12_frame->visible_rect(),
54                                              yv12_frame->natural_size(),
55                                              yv12_frame->GetTimestamp());
56
57   ASSERT_EQ(yv12_frame->coded_size().width(),
58       rgb_frame->coded_size().width());
59   ASSERT_EQ(yv12_frame->coded_size().height(),
60       rgb_frame->coded_size().height());
61
62   media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane),
63                            yv12_frame->data(VideoFrame::kUPlane),
64                            yv12_frame->data(VideoFrame::kVPlane),
65                            rgb_frame->data(VideoFrame::kRGBPlane),
66                            rgb_frame->coded_size().width(),
67                            rgb_frame->coded_size().height(),
68                            yv12_frame->stride(VideoFrame::kYPlane),
69                            yv12_frame->stride(VideoFrame::kUPlane),
70                            rgb_frame->stride(VideoFrame::kRGBPlane),
71                            media::YV12);
72
73   for (int row = 0; row < rgb_frame->coded_size().height(); ++row) {
74     uint32* rgb_row_data = reinterpret_cast<uint32*>(
75         rgb_frame->data(VideoFrame::kRGBPlane) +
76         (rgb_frame->stride(VideoFrame::kRGBPlane) * row));
77     for (int col = 0; col < rgb_frame->coded_size().width(); ++col) {
78       SCOPED_TRACE(
79           base::StringPrintf("Checking (%d, %d)", row, col));
80       EXPECT_EQ(expect_rgb_color, rgb_row_data[col]);
81     }
82   }
83 }
84
85 // Fill each plane to its reported extents and verify accessors report non
86 // zero values.  Additionally, for the first plane verify the rows and
87 // row_bytes values are correct.
88 void ExpectFrameExtents(VideoFrame::Format format, int planes,
89                         int bytes_per_pixel, const char* expected_hash) {
90   const unsigned char kFillByte = 0x80;
91   const int kWidth = 61;
92   const int kHeight = 31;
93   const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337);
94
95   gfx::Size size(kWidth, kHeight);
96   scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
97       format, size, gfx::Rect(size), size, kTimestamp);
98   ASSERT_TRUE(frame.get());
99
100   for(int plane = 0; plane < planes; plane++) {
101     SCOPED_TRACE(base::StringPrintf("Checking plane %d", plane));
102     EXPECT_TRUE(frame->data(plane));
103     EXPECT_TRUE(frame->stride(plane));
104     EXPECT_TRUE(frame->rows(plane));
105     EXPECT_TRUE(frame->row_bytes(plane));
106
107     if (plane == 0) {
108       EXPECT_EQ(frame->rows(plane), kHeight);
109       EXPECT_EQ(frame->row_bytes(plane), kWidth * bytes_per_pixel);
110     }
111
112     memset(frame->data(plane), kFillByte,
113            frame->stride(plane) * frame->rows(plane));
114   }
115
116   base::MD5Context context;
117   base::MD5Init(&context);
118   frame->HashFrameForTesting(&context);
119   base::MD5Digest digest;
120   base::MD5Final(&digest, &context);
121   EXPECT_EQ(MD5DigestToBase16(digest), expected_hash);
122 }
123
124 TEST(VideoFrame, CreateFrame) {
125   const int kWidth = 64;
126   const int kHeight = 48;
127   const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337);
128
129   // Create a YV12 Video Frame.
130   gfx::Size size(kWidth, kHeight);
131   scoped_refptr<media::VideoFrame> frame =
132       VideoFrame::CreateFrame(media::VideoFrame::YV12, size, gfx::Rect(size),
133                               size, kTimestamp);
134   ASSERT_TRUE(frame.get());
135
136   // Test VideoFrame implementation.
137   EXPECT_EQ(media::VideoFrame::YV12, frame->format());
138   {
139     SCOPED_TRACE("");
140     InitializeYV12Frame(frame.get(), 0.0f);
141     ExpectFrameColor(frame.get(), 0xFF000000);
142   }
143   base::MD5Digest digest;
144   base::MD5Context context;
145   base::MD5Init(&context);
146   frame->HashFrameForTesting(&context);
147   base::MD5Final(&digest, &context);
148   EXPECT_EQ(MD5DigestToBase16(digest), "9065c841d9fca49186ef8b4ef547e79b");
149   {
150     SCOPED_TRACE("");
151     InitializeYV12Frame(frame.get(), 1.0f);
152     ExpectFrameColor(frame.get(), 0xFFFFFFFF);
153   }
154   base::MD5Init(&context);
155   frame->HashFrameForTesting(&context);
156   base::MD5Final(&digest, &context);
157   EXPECT_EQ(MD5DigestToBase16(digest), "911991d51438ad2e1a40ed5f6fc7c796");
158
159   // Test an empty frame.
160   frame = VideoFrame::CreateEmptyFrame();
161   EXPECT_TRUE(frame->IsEndOfStream());
162 }
163
164 TEST(VideoFrame, CreateBlackFrame) {
165   const int kWidth = 2;
166   const int kHeight = 2;
167   const uint8 kExpectedYRow[] = { 0, 0 };
168   const uint8 kExpectedUVRow[] = { 128 };
169
170   scoped_refptr<media::VideoFrame> frame =
171       VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight));
172   ASSERT_TRUE(frame.get());
173
174   // Test basic properties.
175   EXPECT_EQ(0, frame->GetTimestamp().InMicroseconds());
176   EXPECT_FALSE(frame->IsEndOfStream());
177
178   // Test |frame| properties.
179   EXPECT_EQ(VideoFrame::YV12, frame->format());
180   EXPECT_EQ(kWidth, frame->coded_size().width());
181   EXPECT_EQ(kHeight, frame->coded_size().height());
182
183   // Test frames themselves.
184   uint8* y_plane = frame->data(VideoFrame::kYPlane);
185   for (int y = 0; y < frame->coded_size().height(); ++y) {
186     EXPECT_EQ(0, memcmp(kExpectedYRow, y_plane, arraysize(kExpectedYRow)));
187     y_plane += frame->stride(VideoFrame::kYPlane);
188   }
189
190   uint8* u_plane = frame->data(VideoFrame::kUPlane);
191   uint8* v_plane = frame->data(VideoFrame::kVPlane);
192   for (int y = 0; y < frame->coded_size().height() / 2; ++y) {
193     EXPECT_EQ(0, memcmp(kExpectedUVRow, u_plane, arraysize(kExpectedUVRow)));
194     EXPECT_EQ(0, memcmp(kExpectedUVRow, v_plane, arraysize(kExpectedUVRow)));
195     u_plane += frame->stride(VideoFrame::kUPlane);
196     v_plane += frame->stride(VideoFrame::kVPlane);
197   }
198 }
199
200 // Ensure each frame is properly sized and allocated.  Will trigger OOB reads
201 // and writes as well as incorrect frame hashes otherwise.
202 TEST(VideoFrame, CheckFrameExtents) {
203   // Each call consists of a VideoFrame::Format, # of planes, bytes per pixel,
204   // and the expected hash of all planes if filled with kFillByte (defined in
205   // ExpectFrameExtents).
206   ExpectFrameExtents(
207       VideoFrame::RGB32,  1, 4, "de6d3d567e282f6a38d478f04fc81fb0");
208   ExpectFrameExtents(
209       VideoFrame::YV12,   3, 1, "71113bdfd4c0de6cf62f48fb74f7a0b1");
210   ExpectFrameExtents(
211       VideoFrame::YV16,   3, 1, "9bb99ac3ff350644ebff4d28dc01b461");
212 }
213
214 static void TextureCallback(uint32* called_sync_point, uint32 sync_point) {
215   *called_sync_point = sync_point;
216 }
217
218 // Verify the TextureNoLongerNeededCallback is called when VideoFrame is
219 // destroyed with the original sync point.
220 TEST(VideoFrame, TextureNoLongerNeededCallbackIsCalled) {
221   uint32 sync_point = 7;
222   uint32 called_sync_point = 0;
223
224   {
225     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
226         new VideoFrame::MailboxHolder(
227             gpu::Mailbox(),
228             sync_point,
229             base::Bind(&TextureCallback, &called_sync_point)),
230         5,  // texture_target
231         gfx::Size(10, 10),  // coded_size
232         gfx::Rect(10, 10),  // visible_rect
233         gfx::Size(10, 10),  // natural_size
234         base::TimeDelta(),  // timestamp
235         base::Callback<void(const SkBitmap&)>(),  // read_pixels_cb
236         base::Closure());  // no_longer_needed_cb
237
238     EXPECT_EQ(0u, called_sync_point);
239   }
240   EXPECT_EQ(sync_point, called_sync_point);
241 }
242
243 // Verify the TextureNoLongerNeededCallback is called when VideoFrame is
244 // destroyed with the new sync point, when the mailbox is taken by a caller.
245 TEST(VideoFrame, TextureNoLongerNeededCallbackAfterTakingAndReleasingMailbox) {
246   uint32 called_sync_point = 0;
247
248   gpu::Mailbox mailbox;
249   mailbox.name[0] = 50;
250   uint32 sync_point = 7;
251   uint32 target = 9;
252
253   {
254     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
255         new VideoFrame::MailboxHolder(
256             mailbox,
257             sync_point,
258             base::Bind(&TextureCallback, &called_sync_point)),
259         target,
260         gfx::Size(10, 10),  // coded_size
261         gfx::Rect(10, 10),  // visible_rect
262         gfx::Size(10, 10),  // natural_size
263         base::TimeDelta(),  // timestamp
264         base::Callback<void(const SkBitmap&)>(),  // read_pixels_cb
265         base::Closure());  // no_longer_needed_cb
266
267     {
268       scoped_refptr<VideoFrame::MailboxHolder> mailbox_holder =
269           frame->texture_mailbox();
270
271       EXPECT_EQ(mailbox.name[0], mailbox_holder->mailbox().name[0]);
272       EXPECT_EQ(sync_point, mailbox_holder->sync_point());
273       EXPECT_EQ(target, frame->texture_target());
274
275       // Misuse the callback.
276       sync_point = 12;
277       mailbox_holder->Return(sync_point);
278       EXPECT_EQ(0u, called_sync_point);
279
280       // Finish using the mailbox_holder and drop our reference.
281       sync_point = 10;
282       mailbox_holder->Return(sync_point);
283     }
284     EXPECT_EQ(0u, called_sync_point);
285   }
286   EXPECT_EQ(sync_point, called_sync_point);
287 }
288
289 // If a caller has taken ownership of the texture mailbox, it should
290 // not be released when the VideoFrame is destroyed, but should when
291 // the TextureNoLongerNeededCallback is called.
292 TEST(VideoFrame,
293      TextureNoLongerNeededCallbackAfterTakingMailboxWithDestroyedFrame) {
294   uint32 called_sync_point = 0;
295
296   gpu::Mailbox mailbox;
297   mailbox.name[0] = 50;
298   uint32 sync_point = 7;
299   uint32 target = 9;
300
301   {
302     scoped_refptr<VideoFrame::MailboxHolder> mailbox_holder;
303
304     {
305       scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
306           new VideoFrame::MailboxHolder(
307               mailbox,
308               sync_point,
309               base::Bind(&TextureCallback, &called_sync_point)),
310           target,
311           gfx::Size(10, 10),  // coded_size
312           gfx::Rect(10, 10),  // visible_rect
313           gfx::Size(10, 10),  // natural_size
314           base::TimeDelta(),  // timestamp
315           base::Callback<void(const SkBitmap&)>(),  // read_pixels_cb
316           base::Closure());  // no_longer_needed_cb
317
318       mailbox_holder = frame->texture_mailbox();
319
320       EXPECT_EQ(mailbox.name[0], mailbox_holder->mailbox().name[0]);
321       EXPECT_EQ(sync_point, mailbox_holder->sync_point());
322       EXPECT_EQ(target, frame->texture_target());
323
324       // Keep a ref on the mailbox_holder after the VideoFrame is dropped.
325     }
326     EXPECT_EQ(0u, called_sync_point);
327
328     // Misuse the callback.
329     sync_point = 12;
330     mailbox_holder->Return(sync_point);
331     EXPECT_EQ(0u, called_sync_point);
332
333     // Finish using the mailbox_holder and drop our ref.
334     sync_point = 10;
335     mailbox_holder->Return(sync_point);
336   }
337   EXPECT_EQ(sync_point, called_sync_point);
338 }
339
340 // If a caller has taken ownership of the texture mailbox, but does
341 // not call the callback, it should still happen with the original
342 // sync point.
343 TEST(VideoFrame,
344      TextureNoLongerNeededCallbackWhenNotCallingAndFrameDestroyed) {
345   uint32 called_sync_point = 0;
346
347   gpu::Mailbox mailbox;
348   mailbox.name[0] = 50;
349   uint32 sync_point = 7;
350   uint32 target = 9;
351
352   {
353     scoped_refptr<VideoFrame::MailboxHolder> mailbox_holder;
354
355     {
356       scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
357           new VideoFrame::MailboxHolder(
358               mailbox,
359               sync_point,
360               base::Bind(&TextureCallback, &called_sync_point)),
361           target,
362           gfx::Size(10, 10),  // coded_size
363           gfx::Rect(10, 10),  // visible_rect
364           gfx::Size(10, 10),  // natural_size
365           base::TimeDelta(),  // timestamp
366           base::Callback<void(const SkBitmap&)>(),  // read_pixels_cb
367           base::Closure());  // no_longer_needed_cb
368
369       mailbox_holder = frame->texture_mailbox();
370
371       EXPECT_EQ(mailbox.name[0], mailbox_holder->mailbox().name[0]);
372       EXPECT_EQ(sync_point, mailbox_holder->sync_point());
373       EXPECT_EQ(target, frame->texture_target());
374
375       // Destroy the video frame.
376     }
377     EXPECT_EQ(0u, called_sync_point);
378
379     // Drop the reference on the mailbox without using it at all.
380   }
381   EXPECT_EQ(sync_point, called_sync_point);
382 }
383
384 // If a caller has taken ownership of the texture mailbox, but does
385 // not call the callback, it should still happen with the original
386 // sync point.
387 TEST(VideoFrame,
388      TextureNoLongerNeededCallbackAfterTakingMailboxAndNotCalling) {
389   uint32 called_sync_point = 0;
390
391   gpu::Mailbox mailbox;
392   mailbox.name[0] = 50;
393   uint32 sync_point = 7;
394   uint32 target = 9;
395
396   {
397     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
398         new VideoFrame::MailboxHolder(
399             mailbox,
400             sync_point,
401             base::Bind(&TextureCallback, &called_sync_point)),
402         target,
403         gfx::Size(10, 10),  // coded_size
404         gfx::Rect(10, 10),  // visible_rect
405         gfx::Size(10, 10),  // natural_size
406         base::TimeDelta(),  // timestamp
407         base::Callback<void(const SkBitmap&)>(),  // read_pixels_cb
408         base::Closure());  // no_longer_needed_cb
409
410     scoped_refptr<VideoFrame::MailboxHolder> mailbox_holder =
411         frame->texture_mailbox();
412
413     EXPECT_EQ(mailbox.name[0], mailbox_holder->mailbox().name[0]);
414     EXPECT_EQ(sync_point, mailbox_holder->sync_point());
415     EXPECT_EQ(target, frame->texture_target());
416
417     EXPECT_EQ(0u, called_sync_point);
418
419     // Don't use the mailbox at all and drop our ref on it.
420   }
421   // The VideoFrame is destroyed, it should call the callback.
422   EXPECT_EQ(sync_point, called_sync_point);
423 }
424
425 }  // namespace media