Upstream version 7.36.149.0
[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/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"
17
18 namespace media {
19
20 using base::MD5DigestToBase16;
21
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() *
28                                          white_to_black);
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);
34   }
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);
42   }
43 }
44
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));
51   ASSERT_EQ(
52       yv12_frame->coded_size().width() & (VideoFrame::kFrameSizeAlignment - 1),
53       0);
54   ASSERT_EQ(
55       yv12_frame->coded_size().height() & (VideoFrame::kFrameSizeAlignment - 1),
56       0);
57
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));
63
64   media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane),
65                            yv12_frame->data(VideoFrame::kUPlane),
66                            yv12_frame->data(VideoFrame::kVPlane),
67                            rgb_data,
68                            yv12_frame->coded_size().width(),
69                            yv12_frame->coded_size().height(),
70                            yv12_frame->stride(VideoFrame::kYPlane),
71                            yv12_frame->stride(VideoFrame::kUPlane),
72                            bytes_per_row,
73                            media::YV12);
74
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) {
79       SCOPED_TRACE(
80           base::StringPrintf("Checking (%d, %d)", row, col));
81       EXPECT_EQ(expect_rgb_color, rgb_row_data[col]);
82     }
83   }
84
85   base::AlignedFree(rgb_data);
86 }
87
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);
96
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());
101
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));
109
110     memset(frame->data(plane), kFillByte,
111            frame->stride(plane) * frame->rows(plane));
112   }
113
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);
120 }
121
122 TEST(VideoFrame, CreateFrame) {
123   const int kWidth = 64;
124   const int kHeight = 48;
125   const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337);
126
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),
131                               size, kTimestamp);
132   ASSERT_TRUE(frame.get());
133
134   // Test VideoFrame implementation.
135   EXPECT_EQ(media::VideoFrame::YV12, frame->format());
136   {
137     SCOPED_TRACE("");
138     InitializeYV12Frame(frame.get(), 0.0f);
139     ExpectFrameColor(frame.get(), 0xFF000000);
140   }
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");
147   {
148     SCOPED_TRACE("");
149     InitializeYV12Frame(frame.get(), 1.0f);
150     ExpectFrameColor(frame.get(), 0xFFFFFFFF);
151   }
152   base::MD5Init(&context);
153   frame->HashFrameForTesting(&context);
154   base::MD5Final(&digest, &context);
155   EXPECT_EQ(MD5DigestToBase16(digest), "911991d51438ad2e1a40ed5f6fc7c796");
156
157   // Test an empty frame.
158   frame = VideoFrame::CreateEOSFrame();
159   EXPECT_TRUE(frame->end_of_stream());
160 }
161
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 };
167
168   scoped_refptr<media::VideoFrame> frame =
169       VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight));
170   ASSERT_TRUE(frame.get());
171
172   // Test basic properties.
173   EXPECT_EQ(0, frame->timestamp().InMicroseconds());
174   EXPECT_FALSE(frame->end_of_stream());
175
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());
180
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);
186   }
187
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);
195   }
196 }
197
198 static void FrameNoLongerNeededCallback(
199     const scoped_refptr<media::VideoFrame>& frame,
200     bool* triggered) {
201   *triggered = true;
202 }
203
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;
209   {
210     scoped_refptr<media::VideoFrame> wrapped_frame =
211         VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight));
212     ASSERT_TRUE(wrapped_frame.get());
213
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());
227   }
228
229   EXPECT_FALSE(no_longer_needed_triggered);
230   frame = NULL;
231   EXPECT_TRUE(no_longer_needed_triggered);
232 }
233
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");
241 }
242
243 static void TextureCallback(std::vector<uint32>* called_sync_point,
244                             const std::vector<uint32>& release_sync_points) {
245   called_sync_point->assign(release_sync_points.begin(),
246                             release_sync_points.end());
247 }
248
249 // Verify the gpu::MailboxHolder::ReleaseCallback is called when VideoFrame is
250 // destroyed with the default release sync points.
251 TEST(VideoFrame, TextureNoLongerNeededCallbackIsCalled) {
252   std::vector<uint32> called_sync_points;
253   called_sync_points.push_back(1);
254
255   {
256     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
257         make_scoped_ptr(
258             new gpu::MailboxHolder(gpu::Mailbox(), 5, 0 /* sync_point */)),
259         base::Bind(&TextureCallback, &called_sync_points),
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         VideoFrame::ReadPixelsCB());  // read_pixels_cb
265
266     EXPECT_EQ(1u, called_sync_points.size());
267   }
268   EXPECT_TRUE(called_sync_points.empty());
269 }
270
271 // Verify the gpu::MailboxHolder::ReleaseCallback is called when VideoFrame is
272 // destroyed with the release sync points, which was updated by clients.
273 // (i.e. the compositor, webgl).
274 TEST(VideoFrame, TextureNoLongerNeededCallbackAfterTakingAndReleasingMailbox) {
275   std::vector<uint32> called_sync_points;
276
277   gpu::Mailbox mailbox;
278   mailbox.name[0] = 50;
279   uint32 sync_point = 7;
280   uint32 target = 9;
281   std::vector<uint32> release_sync_points;
282   release_sync_points.push_back(1);
283   release_sync_points.push_back(2);
284   release_sync_points.push_back(3);
285
286   {
287     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
288         make_scoped_ptr(new gpu::MailboxHolder(mailbox, target, sync_point)),
289         base::Bind(&TextureCallback, &called_sync_points),
290         gfx::Size(10, 10),            // coded_size
291         gfx::Rect(10, 10),            // visible_rect
292         gfx::Size(10, 10),            // natural_size
293         base::TimeDelta(),            // timestamp
294         VideoFrame::ReadPixelsCB());  // read_pixels_cb
295     EXPECT_TRUE(called_sync_points.empty());
296
297     const gpu::MailboxHolder* mailbox_holder = frame->mailbox_holder();
298
299     EXPECT_EQ(mailbox.name[0], mailbox_holder->mailbox.name[0]);
300     EXPECT_EQ(target, mailbox_holder->texture_target);
301     EXPECT_EQ(sync_point, mailbox_holder->sync_point);
302
303     frame->AppendReleaseSyncPoint(release_sync_points[0]);
304     frame->AppendReleaseSyncPoint(release_sync_points[1]);
305     frame->AppendReleaseSyncPoint(release_sync_points[2]);
306     EXPECT_EQ(sync_point, mailbox_holder->sync_point);
307   }
308   EXPECT_EQ(release_sync_points, called_sync_points);
309 }
310
311 }  // namespace media