blob: d7be7e38875b586052af63dbdafe3211eec81c05 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_
29#define TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_
30
31#include <string>
32
33#include "libyuv/convert.h"
34#include "libyuv/convert_from.h"
35#include "libyuv/format_conversion.h"
36#include "libyuv/planar_functions.h"
37#include "libyuv/rotate.h"
38#include "talk/base/gunit.h"
39#include "talk/base/pathutils.h"
40#include "talk/base/stream.h"
41#include "talk/base/stringutils.h"
42#include "talk/media/base/testutils.h"
43#include "talk/media/base/videocommon.h"
44#include "talk/media/base/videoframe.h"
45
46#if defined(_MSC_VER)
47#define ALIGN16(var) __declspec(align(16)) var
48#else
49#define ALIGN16(var) var __attribute__((aligned(16)))
50#endif
51
52#define kImageFilename "faces.1280x720_P420.yuv"
53#define kJpeg420Filename "faces_I420.jpg"
54#define kJpeg422Filename "faces_I422.jpg"
55#define kJpeg444Filename "faces_I444.jpg"
56#define kJpeg411Filename "faces_I411.jpg"
57#define kJpeg400Filename "faces_I400.jpg"
58
59// Generic test class for testing various video frame implementations.
60template <class T>
61class VideoFrameTest : public testing::Test {
62 public:
63 VideoFrameTest() : repeat_(1) {}
64
65 protected:
66 static const int kWidth = 1280;
67 static const int kHeight = 720;
68 static const int kAlignment = 16;
69 static const int kMinWidthAll = 1; // Constants for ConstructYUY2AllSizes.
70 static const int kMinHeightAll = 1;
71 static const int kMaxWidthAll = 17;
72 static const int kMaxHeightAll = 23;
73
74 // Load a video frame from disk.
75 bool LoadFrameNoRepeat(T* frame) {
76 int save_repeat = repeat_; // This LoadFrame disables repeat.
77 repeat_ = 1;
78 bool success = LoadFrame(kImageFilename, cricket::FOURCC_I420,
79 kWidth, kHeight, frame);
80 repeat_ = save_repeat;
81 return success;
82 }
83
84 bool LoadFrame(const std::string& filename, uint32 format,
85 int32 width, int32 height, T* frame) {
86 return LoadFrame(filename, format, width, height,
87 width, abs(height), 0, frame);
88 }
89 bool LoadFrame(const std::string& filename, uint32 format,
90 int32 width, int32 height, int dw, int dh, int rotation,
91 T* frame) {
92 talk_base::scoped_ptr<talk_base::MemoryStream> ms(LoadSample(filename));
93 return LoadFrame(ms.get(), format, width, height, dw, dh, rotation, frame);
94 }
95 // Load a video frame from a memory stream.
96 bool LoadFrame(talk_base::MemoryStream* ms, uint32 format,
97 int32 width, int32 height, T* frame) {
98 return LoadFrame(ms, format, width, height,
99 width, abs(height), 0, frame);
100 }
101 bool LoadFrame(talk_base::MemoryStream* ms, uint32 format,
102 int32 width, int32 height, int dw, int dh, int rotation,
103 T* frame) {
104 if (!ms) {
105 return false;
106 }
107 size_t data_size;
108 bool ret = ms->GetSize(&data_size);
109 EXPECT_TRUE(ret);
110 if (ret) {
111 ret = LoadFrame(reinterpret_cast<uint8*>(ms->GetBuffer()), data_size,
112 format, width, height, dw, dh, rotation, frame);
113 }
114 return ret;
115 }
116 // Load a frame from a raw buffer.
117 bool LoadFrame(uint8* sample, size_t sample_size, uint32 format,
118 int32 width, int32 height, T* frame) {
119 return LoadFrame(sample, sample_size, format, width, height,
120 width, abs(height), 0, frame);
121 }
122 bool LoadFrame(uint8* sample, size_t sample_size, uint32 format,
123 int32 width, int32 height, int dw, int dh, int rotation,
124 T* frame) {
125 bool ret = false;
126 for (int i = 0; i < repeat_; ++i) {
127 ret = frame->Init(format, width, height, dw, dh,
128 sample, sample_size, 1, 1, 0, 0, rotation);
129 }
130 return ret;
131 }
132
133 talk_base::MemoryStream* LoadSample(const std::string& filename) {
134 talk_base::Pathname path(cricket::GetTestFilePath(filename));
135 talk_base::scoped_ptr<talk_base::FileStream> fs(
136 talk_base::Filesystem::OpenFile(path, "rb"));
137 if (!fs.get()) {
138 return NULL;
139 }
140
141 char buf[4096];
142 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
143 new talk_base::MemoryStream());
144 talk_base::StreamResult res = Flow(fs.get(), buf, sizeof(buf), ms.get());
145 if (res != talk_base::SR_SUCCESS) {
146 return NULL;
147 }
148
149 return ms.release();
150 }
151
152 // Write an I420 frame out to disk.
153 bool DumpFrame(const std::string& prefix,
154 const cricket::VideoFrame& frame) {
155 char filename[256];
156 talk_base::sprintfn(filename, sizeof(filename), "%s.%dx%d_P420.yuv",
157 prefix.c_str(), frame.GetWidth(), frame.GetHeight());
158 size_t out_size = cricket::VideoFrame::SizeOf(frame.GetWidth(),
159 frame.GetHeight());
wu@webrtc.org97077a32013-10-25 21:18:33 +0000160 talk_base::scoped_ptr<uint8[]> out(new uint8[out_size]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161 frame.CopyToBuffer(out.get(), out_size);
162 return DumpSample(filename, out.get(), out_size);
163 }
164
165 bool DumpSample(const std::string& filename, const void* buffer, int size) {
166 talk_base::Pathname path(filename);
167 talk_base::scoped_ptr<talk_base::FileStream> fs(
168 talk_base::Filesystem::OpenFile(path, "wb"));
169 if (!fs.get()) {
170 return false;
171 }
172
173 return (fs->Write(buffer, size, NULL, NULL) == talk_base::SR_SUCCESS);
174 }
175
176 // Create a test image in the desired color space.
177 // The image is a checkerboard pattern with 63x63 squares, which allows
178 // I420 chroma artifacts to easily be seen on the square boundaries.
179 // The pattern is { { green, orange }, { blue, purple } }
180 // There is also a gradient within each square to ensure that the luma
181 // values are handled properly.
182 talk_base::MemoryStream* CreateYuv422Sample(uint32 fourcc,
183 uint32 width, uint32 height) {
184 int y1_pos, y2_pos, u_pos, v_pos;
185 if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) {
186 return NULL;
187 }
188
189 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
190 new talk_base::MemoryStream);
191 int awidth = (width + 1) & ~1;
192 int size = awidth * 2 * height;
193 if (!ms->ReserveSize(size)) {
194 return NULL;
195 }
196 for (uint32 y = 0; y < height; ++y) {
197 for (int x = 0; x < awidth; x += 2) {
198 uint8 quad[4];
199 quad[y1_pos] = (x % 63 + y % 63) + 64;
200 quad[y2_pos] = ((x + 1) % 63 + y % 63) + 64;
201 quad[u_pos] = ((x / 63) & 1) ? 192 : 64;
202 quad[v_pos] = ((y / 63) & 1) ? 192 : 64;
203 ms->Write(quad, sizeof(quad), NULL, NULL);
204 }
205 }
206 return ms.release();
207 }
208
209 // Create a test image for YUV 420 formats with 12 bits per pixel.
210 talk_base::MemoryStream* CreateYuvSample(uint32 width, uint32 height,
211 uint32 bpp) {
212 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
213 new talk_base::MemoryStream);
214 if (!ms->ReserveSize(width * height * bpp / 8)) {
215 return NULL;
216 }
217
218 for (uint32 i = 0; i < width * height * bpp / 8; ++i) {
219 char value = ((i / 63) & 1) ? 192 : 64;
220 ms->Write(&value, sizeof(value), NULL, NULL);
221 }
222 return ms.release();
223 }
224
225 talk_base::MemoryStream* CreateRgbSample(uint32 fourcc,
226 uint32 width, uint32 height) {
227 int r_pos, g_pos, b_pos, bytes;
228 if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) {
229 return NULL;
230 }
231
232 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
233 new talk_base::MemoryStream);
234 if (!ms->ReserveSize(width * height * bytes)) {
235 return NULL;
236 }
237
238 for (uint32 y = 0; y < height; ++y) {
239 for (uint32 x = 0; x < width; ++x) {
240 uint8 rgb[4] = { 255, 255, 255, 255 };
241 rgb[r_pos] = ((x / 63) & 1) ? 224 : 32;
242 rgb[g_pos] = (x % 63 + y % 63) + 96;
243 rgb[b_pos] = ((y / 63) & 1) ? 224 : 32;
244 ms->Write(rgb, bytes, NULL, NULL);
245 }
246 }
247 return ms.release();
248 }
249
250 // Simple conversion routines to verify the optimized VideoFrame routines.
251 // Converts from the specified colorspace to I420.
252 bool ConvertYuv422(const talk_base::MemoryStream* ms,
253 uint32 fourcc, uint32 width, uint32 height,
254 T* frame) {
255 int y1_pos, y2_pos, u_pos, v_pos;
256 if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) {
257 return false;
258 }
259
260 const uint8* start = reinterpret_cast<const uint8*>(ms->GetBuffer());
261 int awidth = (width + 1) & ~1;
262 frame->InitToBlack(width, height, 1, 1, 0, 0);
263 int stride_y = frame->GetYPitch();
264 int stride_u = frame->GetUPitch();
265 int stride_v = frame->GetVPitch();
266 for (uint32 y = 0; y < height; ++y) {
267 for (uint32 x = 0; x < width; x += 2) {
268 const uint8* quad1 = start + (y * awidth + x) * 2;
269 frame->GetYPlane()[stride_y * y + x] = quad1[y1_pos];
270 if ((x + 1) < width) {
271 frame->GetYPlane()[stride_y * y + x + 1] = quad1[y2_pos];
272 }
273 if ((y & 1) == 0) {
274 const uint8* quad2 = quad1 + awidth * 2;
275 if ((y + 1) >= height) {
276 quad2 = quad1;
277 }
278 frame->GetUPlane()[stride_u * (y / 2) + x / 2] =
279 (quad1[u_pos] + quad2[u_pos] + 1) / 2;
280 frame->GetVPlane()[stride_v * (y / 2) + x / 2] =
281 (quad1[v_pos] + quad2[v_pos] + 1) / 2;
282 }
283 }
284 }
285 return true;
286 }
287
288 // Convert RGB to 420.
289 // A negative height inverts the image.
290 bool ConvertRgb(const talk_base::MemoryStream* ms,
291 uint32 fourcc, int32 width, int32 height,
292 T* frame) {
293 int r_pos, g_pos, b_pos, bytes;
294 if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) {
295 return false;
296 }
297 int pitch = width * bytes;
298 const uint8* start = reinterpret_cast<const uint8*>(ms->GetBuffer());
299 if (height < 0) {
300 height = -height;
301 start = start + pitch * (height - 1);
302 pitch = -pitch;
303 }
304 frame->InitToBlack(width, height, 1, 1, 0, 0);
305 int stride_y = frame->GetYPitch();
306 int stride_u = frame->GetUPitch();
307 int stride_v = frame->GetVPitch();
308 for (int32 y = 0; y < height; y += 2) {
309 for (int32 x = 0; x < width; x += 2) {
310 const uint8* rgb[4];
311 uint8 yuv[4][3];
312 rgb[0] = start + y * pitch + x * bytes;
313 rgb[1] = rgb[0] + ((x + 1) < width ? bytes : 0);
314 rgb[2] = rgb[0] + ((y + 1) < height ? pitch : 0);
315 rgb[3] = rgb[2] + ((x + 1) < width ? bytes : 0);
316 for (size_t i = 0; i < 4; ++i) {
317 ConvertRgbPixel(rgb[i][r_pos], rgb[i][g_pos], rgb[i][b_pos],
318 &yuv[i][0], &yuv[i][1], &yuv[i][2]);
319 }
320 frame->GetYPlane()[stride_y * y + x] = yuv[0][0];
321 if ((x + 1) < width) {
322 frame->GetYPlane()[stride_y * y + x + 1] = yuv[1][0];
323 }
324 if ((y + 1) < height) {
325 frame->GetYPlane()[stride_y * (y + 1) + x] = yuv[2][0];
326 if ((x + 1) < width) {
327 frame->GetYPlane()[stride_y * (y + 1) + x + 1] = yuv[3][0];
328 }
329 }
330 frame->GetUPlane()[stride_u * (y / 2) + x / 2] =
331 (yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1] + 2) / 4;
332 frame->GetVPlane()[stride_v * (y / 2) + x / 2] =
333 (yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2] + 2) / 4;
334 }
335 }
336 return true;
337 }
338
339 // Simple and slow RGB->YUV conversion. From NTSC standard, c/o Wikipedia.
340 void ConvertRgbPixel(uint8 r, uint8 g, uint8 b,
341 uint8* y, uint8* u, uint8* v) {
342 *y = static_cast<int>(.257 * r + .504 * g + .098 * b) + 16;
343 *u = static_cast<int>(-.148 * r - .291 * g + .439 * b) + 128;
344 *v = static_cast<int>(.439 * r - .368 * g - .071 * b) + 128;
345 }
346
347 bool GetYuv422Packing(uint32 fourcc,
348 int* y1_pos, int* y2_pos, int* u_pos, int* v_pos) {
349 if (fourcc == cricket::FOURCC_YUY2) {
350 *y1_pos = 0; *u_pos = 1; *y2_pos = 2; *v_pos = 3;
351 } else if (fourcc == cricket::FOURCC_UYVY) {
352 *u_pos = 0; *y1_pos = 1; *v_pos = 2; *y2_pos = 3;
353 } else {
354 return false;
355 }
356 return true;
357 }
358
359 bool GetRgbPacking(uint32 fourcc,
360 int* r_pos, int* g_pos, int* b_pos, int* bytes) {
361 if (fourcc == cricket::FOURCC_RAW) {
362 *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 3; // RGB in memory.
363 } else if (fourcc == cricket::FOURCC_24BG) {
364 *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 3; // BGR in memory.
365 } else if (fourcc == cricket::FOURCC_ABGR) {
366 *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 4; // RGBA in memory.
367 } else if (fourcc == cricket::FOURCC_BGRA) {
368 *r_pos = 1; *g_pos = 2; *b_pos = 3; *bytes = 4; // ARGB in memory.
369 } else if (fourcc == cricket::FOURCC_ARGB) {
370 *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 4; // BGRA in memory.
371 } else {
372 return false;
373 }
374 return true;
375 }
376
377 // Comparison functions for testing.
378 static bool IsNull(const cricket::VideoFrame& frame) {
379 return !frame.GetYPlane();
380 }
381
382 static bool IsSize(const cricket::VideoFrame& frame,
383 uint32 width, uint32 height) {
384 return !IsNull(frame) &&
385 frame.GetYPitch() >= static_cast<int32>(width) &&
386 frame.GetUPitch() >= static_cast<int32>(width) / 2 &&
387 frame.GetVPitch() >= static_cast<int32>(width) / 2 &&
388 frame.GetWidth() == width && frame.GetHeight() == height;
389 }
390
391 static bool IsPlaneEqual(const std::string& name,
392 const uint8* plane1, uint32 pitch1,
393 const uint8* plane2, uint32 pitch2,
394 uint32 width, uint32 height,
395 int max_error) {
396 const uint8* r1 = plane1;
397 const uint8* r2 = plane2;
398 for (uint32 y = 0; y < height; ++y) {
399 for (uint32 x = 0; x < width; ++x) {
400 if (abs(static_cast<int>(r1[x] - r2[x])) > max_error) {
401 LOG(LS_INFO) << "IsPlaneEqual(" << name << "): pixel["
402 << x << "," << y << "] differs: "
403 << static_cast<int>(r1[x]) << " vs "
404 << static_cast<int>(r2[x]);
405 return false;
406 }
407 }
408 r1 += pitch1;
409 r2 += pitch2;
410 }
411 return true;
412 }
413
414 static bool IsEqual(const cricket::VideoFrame& frame,
415 size_t width, size_t height,
416 size_t pixel_width, size_t pixel_height,
417 int64 elapsed_time, int64 time_stamp,
418 const uint8* y, uint32 ypitch,
419 const uint8* u, uint32 upitch,
420 const uint8* v, uint32 vpitch,
421 int max_error) {
422 return IsSize(frame, width, height) &&
423 frame.GetPixelWidth() == pixel_width &&
424 frame.GetPixelHeight() == pixel_height &&
425 frame.GetElapsedTime() == elapsed_time &&
426 frame.GetTimeStamp() == time_stamp &&
427 IsPlaneEqual("y", frame.GetYPlane(), frame.GetYPitch(), y, ypitch,
428 width, height, max_error) &&
429 IsPlaneEqual("u", frame.GetUPlane(), frame.GetUPitch(), u, upitch,
430 (width + 1) / 2, (height + 1) / 2, max_error) &&
431 IsPlaneEqual("v", frame.GetVPlane(), frame.GetVPitch(), v, vpitch,
432 (width + 1) / 2, (height + 1) / 2, max_error);
433 }
434
435 static bool IsEqual(const cricket::VideoFrame& frame1,
436 const cricket::VideoFrame& frame2,
437 int max_error) {
438 return IsEqual(frame1,
439 frame2.GetWidth(), frame2.GetHeight(),
440 frame2.GetPixelWidth(), frame2.GetPixelHeight(),
441 frame2.GetElapsedTime(), frame2.GetTimeStamp(),
442 frame2.GetYPlane(), frame2.GetYPitch(),
443 frame2.GetUPlane(), frame2.GetUPitch(),
444 frame2.GetVPlane(), frame2.GetVPitch(),
445 max_error);
446 }
447
448 static bool IsEqualWithCrop(const cricket::VideoFrame& frame1,
449 const cricket::VideoFrame& frame2,
450 int hcrop, int vcrop, int max_error) {
451 return frame1.GetWidth() <= frame2.GetWidth() &&
452 frame1.GetHeight() <= frame2.GetHeight() &&
453 IsEqual(frame1,
454 frame2.GetWidth() - hcrop * 2,
455 frame2.GetHeight() - vcrop * 2,
456 frame2.GetPixelWidth(), frame2.GetPixelHeight(),
457 frame2.GetElapsedTime(), frame2.GetTimeStamp(),
458 frame2.GetYPlane() + vcrop * frame2.GetYPitch()
459 + hcrop,
460 frame2.GetYPitch(),
461 frame2.GetUPlane() + vcrop * frame2.GetUPitch() / 2
462 + hcrop / 2,
463 frame2.GetUPitch(),
464 frame2.GetVPlane() + vcrop * frame2.GetVPitch() / 2
465 + hcrop / 2,
466 frame2.GetVPitch(),
467 max_error);
468 }
469
470 static bool IsBlack(const cricket::VideoFrame& frame) {
471 return !IsNull(frame) &&
472 *frame.GetYPlane() == 16 &&
473 *frame.GetUPlane() == 128 &&
474 *frame.GetVPlane() == 128;
475 }
476
477 ////////////////////////
478 // Construction tests //
479 ////////////////////////
480
481 // Test constructing an image from a I420 buffer.
482 void ConstructI420() {
483 T frame;
484 EXPECT_TRUE(IsNull(frame));
485 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
486 CreateYuvSample(kWidth, kHeight, 12));
487 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420,
488 kWidth, kHeight, &frame));
489
490 const uint8* y = reinterpret_cast<uint8*>(ms.get()->GetBuffer());
491 const uint8* u = y + kWidth * kHeight;
492 const uint8* v = u + kWidth * kHeight / 4;
493 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 1, 1, 0, 0,
494 y, kWidth, u, kWidth / 2, v, kWidth / 2, 0));
495 }
496
497 // Test constructing an image from a YV12 buffer.
498 void ConstructYV12() {
499 T frame;
500 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
501 CreateYuvSample(kWidth, kHeight, 12));
502 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YV12,
503 kWidth, kHeight, &frame));
504
505 const uint8* y = reinterpret_cast<uint8*>(ms.get()->GetBuffer());
506 const uint8* v = y + kWidth * kHeight;
507 const uint8* u = v + kWidth * kHeight / 4;
508 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 1, 1, 0, 0,
509 y, kWidth, u, kWidth / 2, v, kWidth / 2, 0));
510 }
511
512 // Test constructing an image from a I422 buffer.
513 void ConstructI422() {
514 T frame1, frame2;
515 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
516 size_t buf_size = kWidth * kHeight * 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000517 talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 uint8* y = ALIGNP(buf.get(), kAlignment);
519 uint8* u = y + kWidth * kHeight;
520 uint8* v = u + (kWidth / 2) * kHeight;
521 EXPECT_EQ(0, libyuv::I420ToI422(frame1.GetYPlane(), frame1.GetYPitch(),
522 frame1.GetUPlane(), frame1.GetUPitch(),
523 frame1.GetVPlane(), frame1.GetVPitch(),
524 y, kWidth,
525 u, kWidth / 2,
526 v, kWidth / 2,
527 kWidth, kHeight));
528 EXPECT_TRUE(LoadFrame(y, buf_size, cricket::FOURCC_I422,
529 kWidth, kHeight, &frame2));
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000530 EXPECT_TRUE(IsEqual(frame1, frame2, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 }
532
533 // Test constructing an image from a YUY2 buffer.
534 void ConstructYuy2() {
535 T frame1, frame2;
536 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
537 size_t buf_size = kWidth * kHeight * 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000538 talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 uint8* yuy2 = ALIGNP(buf.get(), kAlignment);
540 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
541 frame1.GetUPlane(), frame1.GetUPitch(),
542 frame1.GetVPlane(), frame1.GetVPitch(),
543 yuy2, kWidth * 2,
544 kWidth, kHeight));
545 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2,
546 kWidth, kHeight, &frame2));
547 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
548 }
549
550 // Test constructing an image from a YUY2 buffer with buffer unaligned.
551 void ConstructYuy2Unaligned() {
552 T frame1, frame2;
553 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
554 size_t buf_size = kWidth * kHeight * 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000555 talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment + 1]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 uint8* yuy2 = ALIGNP(buf.get(), kAlignment) + 1;
557 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
558 frame1.GetUPlane(), frame1.GetUPitch(),
559 frame1.GetVPlane(), frame1.GetVPitch(),
560 yuy2, kWidth * 2,
561 kWidth, kHeight));
562 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2,
563 kWidth, kHeight, &frame2));
564 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
565 }
566
567 // Test constructing an image from a wide YUY2 buffer.
568 // Normal is 1280x720. Wide is 12800x72
569 void ConstructYuy2Wide() {
570 T frame1, frame2;
571 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
572 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth * 10, kHeight / 10));
573 ASSERT_TRUE(ms.get() != NULL);
574 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2,
575 kWidth * 10, kHeight / 10,
576 &frame1));
577 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
578 kWidth * 10, kHeight / 10, &frame2));
579 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
580 }
581
582 // Test constructing an image from a UYVY buffer.
583 void ConstructUyvy() {
584 T frame1, frame2;
585 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
586 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
587 ASSERT_TRUE(ms.get() != NULL);
588 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
589 &frame1));
590 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
591 kWidth, kHeight, &frame2));
592 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
593 }
594
595 // Test constructing an image from a random buffer.
596 // We are merely verifying that the code succeeds and is free of crashes.
597 void ConstructM420() {
598 T frame;
599 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
600 CreateYuvSample(kWidth, kHeight, 12));
601 ASSERT_TRUE(ms.get() != NULL);
602 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_M420,
603 kWidth, kHeight, &frame));
604 }
605
606 void ConstructQ420() {
607 T frame;
608 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
609 CreateYuvSample(kWidth, kHeight, 12));
610 ASSERT_TRUE(ms.get() != NULL);
611 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_Q420,
612 kWidth, kHeight, &frame));
613 }
614
615 void ConstructNV21() {
616 T frame;
617 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
618 CreateYuvSample(kWidth, kHeight, 12));
619 ASSERT_TRUE(ms.get() != NULL);
620 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV21,
621 kWidth, kHeight, &frame));
622 }
623
624 void ConstructNV12() {
625 T frame;
626 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
627 CreateYuvSample(kWidth, kHeight, 12));
628 ASSERT_TRUE(ms.get() != NULL);
629 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV12,
630 kWidth, kHeight, &frame));
631 }
632
633 // Test constructing an image from a ABGR buffer
634 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
635 void ConstructABGR() {
636 T frame1, frame2;
637 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
638 CreateRgbSample(cricket::FOURCC_ABGR, kWidth, kHeight));
639 ASSERT_TRUE(ms.get() != NULL);
640 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ABGR, kWidth, kHeight,
641 &frame1));
642 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ABGR,
643 kWidth, kHeight, &frame2));
644 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
645 }
646
647 // Test constructing an image from a ARGB buffer
648 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
649 void ConstructARGB() {
650 T frame1, frame2;
651 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
652 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));
653 ASSERT_TRUE(ms.get() != NULL);
654 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight,
655 &frame1));
656 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
657 kWidth, kHeight, &frame2));
658 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
659 }
660
661 // Test constructing an image from a wide ARGB buffer
662 // Normal is 1280x720. Wide is 12800x72
663 void ConstructARGBWide() {
664 T frame1, frame2;
665 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
666 CreateRgbSample(cricket::FOURCC_ARGB, kWidth * 10, kHeight / 10));
667 ASSERT_TRUE(ms.get() != NULL);
668 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
669 kWidth * 10, kHeight / 10, &frame1));
670 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
671 kWidth * 10, kHeight / 10, &frame2));
672 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
673 }
674
675 // Test constructing an image from an BGRA buffer.
676 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
677 void ConstructBGRA() {
678 T frame1, frame2;
679 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
680 CreateRgbSample(cricket::FOURCC_BGRA, kWidth, kHeight));
681 ASSERT_TRUE(ms.get() != NULL);
682 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_BGRA, kWidth, kHeight,
683 &frame1));
684 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_BGRA,
685 kWidth, kHeight, &frame2));
686 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
687 }
688
689 // Test constructing an image from a 24BG buffer.
690 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
691 void Construct24BG() {
692 T frame1, frame2;
693 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
694 CreateRgbSample(cricket::FOURCC_24BG, kWidth, kHeight));
695 ASSERT_TRUE(ms.get() != NULL);
696 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_24BG, kWidth, kHeight,
697 &frame1));
698 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_24BG,
699 kWidth, kHeight, &frame2));
700 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
701 }
702
703 // Test constructing an image from a raw RGB buffer.
704 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
705 void ConstructRaw() {
706 T frame1, frame2;
707 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
708 CreateRgbSample(cricket::FOURCC_RAW, kWidth, kHeight));
709 ASSERT_TRUE(ms.get() != NULL);
710 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_RAW, kWidth, kHeight,
711 &frame1));
712 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_RAW,
713 kWidth, kHeight, &frame2));
714 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
715 }
716
717 // Test constructing an image from a RGB565 buffer
718 void ConstructRGB565() {
719 T frame1, frame2;
720 size_t out_size = kWidth * kHeight * 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000721 talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 uint8 *out = ALIGNP(outbuf.get(), kAlignment);
723 T frame;
724 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
725 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_RGBP,
726 out,
727 out_size, kWidth * 2));
728 EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_RGBP,
729 kWidth, kHeight, &frame2));
730 EXPECT_TRUE(IsEqual(frame1, frame2, 20));
731 }
732
733 // Test constructing an image from a ARGB1555 buffer
734 void ConstructARGB1555() {
735 T frame1, frame2;
736 size_t out_size = kWidth * kHeight * 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000737 talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 uint8 *out = ALIGNP(outbuf.get(), kAlignment);
739 T frame;
740 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
741 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_RGBO,
742 out,
743 out_size, kWidth * 2));
744 EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_RGBO,
745 kWidth, kHeight, &frame2));
746 EXPECT_TRUE(IsEqual(frame1, frame2, 20));
747 }
748
749 // Test constructing an image from a ARGB4444 buffer
750 void ConstructARGB4444() {
751 T frame1, frame2;
752 size_t out_size = kWidth * kHeight * 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000753 talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754 uint8 *out = ALIGNP(outbuf.get(), kAlignment);
755 T frame;
756 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
757 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_R444,
758 out,
759 out_size, kWidth * 2));
760 EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_R444,
761 kWidth, kHeight, &frame2));
762 EXPECT_TRUE(IsEqual(frame1, frame2, 20));
763 }
764
765 // Macro to help test different Bayer formats.
766 // Error threshold of 60 allows for Bayer format subsampling.
767 // TODO(fbarchard): Refactor this test to go from Bayer to I420 and
768 // back to bayer, which would be less lossy.
769 #define TEST_BYR(NAME, BAYER) \
770 void NAME() { \
771 size_t bayer_size = kWidth * kHeight; \
wu@webrtc.org97077a32013-10-25 21:18:33 +0000772 talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 bayer_size + kAlignment]); \
774 uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment); \
775 T frame1, frame2; \
776 talk_base::scoped_ptr<talk_base::MemoryStream> ms( \
777 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
778 ASSERT_TRUE(ms.get() != NULL); \
779 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8 *>(ms->GetBuffer()), \
780 kWidth * 4, \
781 bayer, kWidth, \
782 kWidth, kHeight); \
783 EXPECT_TRUE(LoadFrame(bayer, bayer_size, cricket::FOURCC_##BAYER, \
784 kWidth, kHeight, &frame1)); \
785 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight, \
786 &frame2)); \
787 EXPECT_TRUE(IsEqual(frame1, frame2, 60)); \
788 }
789
790 // Test constructing an image from Bayer formats.
791 TEST_BYR(ConstructBayerGRBG, GRBG)
792 TEST_BYR(ConstructBayerGBRG, GBRG)
793 TEST_BYR(ConstructBayerBGGR, BGGR)
794 TEST_BYR(ConstructBayerRGGB, RGGB)
795
796
797// Macro to help test different rotations
798#define TEST_MIRROR(FOURCC, BPP) \
799void Construct##FOURCC##Mirror() { \
800 T frame1, frame2, frame3; \
801 talk_base::scoped_ptr<talk_base::MemoryStream> ms( \
802 CreateYuvSample(kWidth, kHeight, BPP)); \
803 ASSERT_TRUE(ms.get() != NULL); \
804 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, \
805 kWidth, -kHeight, kWidth, kHeight, \
806 cricket::ROTATION_180, &frame1)); \
807 size_t data_size; \
808 bool ret = ms->GetSize(&data_size); \
809 EXPECT_TRUE(ret); \
810 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, \
811 kWidth, kHeight, kWidth, kHeight, \
812 reinterpret_cast<uint8*>(ms->GetBuffer()), \
813 data_size, \
814 1, 1, 0, 0, 0)); \
815 int width_rotate = frame1.GetWidth(); \
816 int height_rotate = frame1.GetHeight(); \
817 EXPECT_TRUE(frame3.InitToBlack(width_rotate, height_rotate, 1, 1, 0, 0)); \
818 libyuv::I420Mirror(frame2.GetYPlane(), frame2.GetYPitch(), \
819 frame2.GetUPlane(), frame2.GetUPitch(), \
820 frame2.GetVPlane(), frame2.GetVPitch(), \
821 frame3.GetYPlane(), frame3.GetYPitch(), \
822 frame3.GetUPlane(), frame3.GetUPitch(), \
823 frame3.GetVPlane(), frame3.GetVPitch(), \
824 kWidth, kHeight); \
825 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \
826 }
827
828 TEST_MIRROR(I420, 420)
829
830// Macro to help test different rotations
831#define TEST_ROTATE(FOURCC, BPP, ROTATE) \
832void Construct##FOURCC##Rotate##ROTATE() { \
833 T frame1, frame2, frame3; \
834 talk_base::scoped_ptr<talk_base::MemoryStream> ms( \
835 CreateYuvSample(kWidth, kHeight, BPP)); \
836 ASSERT_TRUE(ms.get() != NULL); \
837 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, \
838 kWidth, kHeight, kWidth, kHeight, \
839 cricket::ROTATION_##ROTATE, &frame1)); \
840 size_t data_size; \
841 bool ret = ms->GetSize(&data_size); \
842 EXPECT_TRUE(ret); \
843 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, \
844 kWidth, kHeight, kWidth, kHeight, \
845 reinterpret_cast<uint8*>(ms->GetBuffer()), \
846 data_size, \
847 1, 1, 0, 0, 0)); \
848 int width_rotate = frame1.GetWidth(); \
849 int height_rotate = frame1.GetHeight(); \
850 EXPECT_TRUE(frame3.InitToBlack(width_rotate, height_rotate, 1, 1, 0, 0)); \
851 libyuv::I420Rotate(frame2.GetYPlane(), frame2.GetYPitch(), \
852 frame2.GetUPlane(), frame2.GetUPitch(), \
853 frame2.GetVPlane(), frame2.GetVPitch(), \
854 frame3.GetYPlane(), frame3.GetYPitch(), \
855 frame3.GetUPlane(), frame3.GetUPitch(), \
856 frame3.GetVPlane(), frame3.GetVPitch(), \
857 kWidth, kHeight, libyuv::kRotate##ROTATE); \
858 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \
859 }
860
861 // Test constructing an image with rotation.
862 TEST_ROTATE(I420, 12, 0)
863 TEST_ROTATE(I420, 12, 90)
864 TEST_ROTATE(I420, 12, 180)
865 TEST_ROTATE(I420, 12, 270)
866 TEST_ROTATE(YV12, 12, 0)
867 TEST_ROTATE(YV12, 12, 90)
868 TEST_ROTATE(YV12, 12, 180)
869 TEST_ROTATE(YV12, 12, 270)
870 TEST_ROTATE(NV12, 12, 0)
871 TEST_ROTATE(NV12, 12, 90)
872 TEST_ROTATE(NV12, 12, 180)
873 TEST_ROTATE(NV12, 12, 270)
874 TEST_ROTATE(NV21, 12, 0)
875 TEST_ROTATE(NV21, 12, 90)
876 TEST_ROTATE(NV21, 12, 180)
877 TEST_ROTATE(NV21, 12, 270)
878 TEST_ROTATE(UYVY, 16, 0)
879 TEST_ROTATE(UYVY, 16, 90)
880 TEST_ROTATE(UYVY, 16, 180)
881 TEST_ROTATE(UYVY, 16, 270)
882 TEST_ROTATE(YUY2, 16, 0)
883 TEST_ROTATE(YUY2, 16, 90)
884 TEST_ROTATE(YUY2, 16, 180)
885 TEST_ROTATE(YUY2, 16, 270)
886
887 // Test constructing an image from a UYVY buffer rotated 90 degrees.
888 void ConstructUyvyRotate90() {
889 T frame2;
890 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
891 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
892 ASSERT_TRUE(ms.get() != NULL);
893 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
894 kWidth, kHeight, kWidth, kHeight,
895 cricket::ROTATION_90, &frame2));
896 }
897
898 // Test constructing an image from a UYVY buffer rotated 180 degrees.
899 void ConstructUyvyRotate180() {
900 T frame2;
901 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
902 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
903 ASSERT_TRUE(ms.get() != NULL);
904 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
905 kWidth, kHeight, kWidth, kHeight,
906 cricket::ROTATION_180, &frame2));
907 }
908
909 // Test constructing an image from a UYVY buffer rotated 270 degrees.
910 void ConstructUyvyRotate270() {
911 T frame2;
912 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
913 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
914 ASSERT_TRUE(ms.get() != NULL);
915 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
916 kWidth, kHeight, kWidth, kHeight,
917 cricket::ROTATION_270, &frame2));
918 }
919
920 // Test constructing an image from a YUY2 buffer rotated 90 degrees.
921 void ConstructYuy2Rotate90() {
922 T frame2;
923 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
924 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
925 ASSERT_TRUE(ms.get() != NULL);
926 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
927 kWidth, kHeight, kWidth, kHeight,
928 cricket::ROTATION_90, &frame2));
929 }
930
931 // Test constructing an image from a YUY2 buffer rotated 180 degrees.
932 void ConstructYuy2Rotate180() {
933 T frame2;
934 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
935 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
936 ASSERT_TRUE(ms.get() != NULL);
937 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
938 kWidth, kHeight, kWidth, kHeight,
939 cricket::ROTATION_180, &frame2));
940 }
941
942 // Test constructing an image from a YUY2 buffer rotated 270 degrees.
943 void ConstructYuy2Rotate270() {
944 T frame2;
945 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
946 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
947 ASSERT_TRUE(ms.get() != NULL);
948 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
949 kWidth, kHeight, kWidth, kHeight,
950 cricket::ROTATION_270, &frame2));
951 }
952
953 // Test 1 pixel edge case image I420 buffer.
954 void ConstructI4201Pixel() {
955 T frame;
956 uint8 pixel[3] = { 1, 2, 3 };
957 for (int i = 0; i < repeat_; ++i) {
958 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1,
959 pixel, sizeof(pixel),
960 1, 1, 0, 0, 0));
961 }
962 const uint8* y = pixel;
963 const uint8* u = y + 1;
964 const uint8* v = u + 1;
965 EXPECT_TRUE(IsEqual(frame, 1, 1, 1, 1, 0, 0,
966 y, 1, u, 1, v, 1, 0));
967 }
968
969 // Test 5 pixel edge case image I420 buffer rounds down to 4.
970 void ConstructI4205Pixel() {
971 T frame;
972 uint8 pixels5x5[5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2];
973 memset(pixels5x5, 1, 5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2);
974 for (int i = 0; i < repeat_; ++i) {
975 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 5, 5, 5, 5,
976 pixels5x5, sizeof(pixels5x5),
977 1, 1, 0, 0, 0));
978 }
979 EXPECT_EQ(4u, frame.GetWidth());
980 EXPECT_EQ(4u, frame.GetHeight());
981 EXPECT_EQ(4, frame.GetYPitch());
982 EXPECT_EQ(2, frame.GetUPitch());
983 EXPECT_EQ(2, frame.GetVPitch());
984 }
985
986 // Test 1 pixel edge case image ARGB buffer.
987 void ConstructARGB1Pixel() {
988 T frame;
989 uint8 pixel[4] = { 64, 128, 192, 255 };
990 for (int i = 0; i < repeat_; ++i) {
991 EXPECT_TRUE(frame.Init(cricket::FOURCC_ARGB, 1, 1, 1, 1,
992 pixel, sizeof(pixel),
993 1, 1, 0, 0, 0));
994 }
995 // Convert back to ARGB.
996 size_t out_size = 4;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000997 talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 uint8 *out = ALIGNP(outbuf.get(), kAlignment);
999
1000 EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
1001 out,
1002 out_size, // buffer size
1003 out_size)); // stride
1004 #ifdef USE_LMI_CONVERT
1005 // TODO(fbarchard): Expected to fail, but not crash.
1006 EXPECT_FALSE(IsPlaneEqual("argb", pixel, 4, out, 4, 3, 1, 2));
1007 #else
1008 // TODO(fbarchard): Check for overwrite.
1009 EXPECT_TRUE(IsPlaneEqual("argb", pixel, 4, out, 4, 3, 1, 2));
1010 #endif
1011 }
1012
1013 // Test Black, White and Grey pixels.
1014 void ConstructARGBBlackWhitePixel() {
1015 T frame;
1016 uint8 pixel[10 * 4] = { 0, 0, 0, 255, // Black.
1017 0, 0, 0, 255,
1018 64, 64, 64, 255, // Dark Grey.
1019 64, 64, 64, 255,
1020 128, 128, 128, 255, // Grey.
1021 128, 128, 128, 255,
1022 196, 196, 196, 255, // Light Grey.
1023 196, 196, 196, 255,
1024 255, 255, 255, 255, // White.
1025 255, 255, 255, 255 };
1026
1027 for (int i = 0; i < repeat_; ++i) {
1028 EXPECT_TRUE(frame.Init(cricket::FOURCC_ARGB, 10, 1, 10, 1,
1029 pixel, sizeof(pixel),
1030 1, 1, 0, 0, 0));
1031 }
1032 // Convert back to ARGB
1033 size_t out_size = 10 * 4;
wu@webrtc.org97077a32013-10-25 21:18:33 +00001034 talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035 uint8 *out = ALIGNP(outbuf.get(), kAlignment);
1036
1037 EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
1038 out,
1039 out_size, // buffer size.
1040 out_size)); // stride.
1041 EXPECT_TRUE(IsPlaneEqual("argb", pixel, out_size,
1042 out, out_size,
1043 out_size, 1, 2));
1044 }
1045
1046 // Test constructing an image from an I420 buffer with horizontal cropping.
1047 void ConstructI420CropHorizontal() {
1048 T frame1, frame2;
1049 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1050 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight,
1051 kWidth * 3 / 4, kHeight, 0, &frame2));
1052 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0));
1053 }
1054
1055 // Test constructing an image from a YUY2 buffer with horizontal cropping.
1056 void ConstructYuy2CropHorizontal() {
1057 T frame1, frame2;
1058 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1059 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
1060 ASSERT_TRUE(ms.get() != NULL);
1061 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
1062 &frame1));
1063 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
1064 kWidth * 3 / 4, kHeight, 0, &frame2));
1065 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0));
1066 }
1067
1068 // Test constructing an image from an ARGB buffer with horizontal cropping.
1069 void ConstructARGBCropHorizontal() {
1070 T frame1, frame2;
1071 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1072 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));
1073 ASSERT_TRUE(ms.get() != NULL);
1074 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight,
1075 &frame1));
1076 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight,
1077 kWidth * 3 / 4, kHeight, 0, &frame2));
1078 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 2));
1079 }
1080
1081 // Test constructing an image from an I420 buffer, cropping top and bottom.
1082 void ConstructI420CropVertical() {
1083 T frame1, frame2;
1084 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1085 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight,
1086 kWidth, kHeight * 3 / 4, 0, &frame2));
1087 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, 0, kHeight / 8, 0));
1088 }
1089
1090 // Test constructing an image from I420 synonymous formats.
1091 void ConstructI420Aliases() {
1092 T frame1, frame2, frame3;
1093 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight,
1094 &frame1));
1095 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_IYUV, kWidth, kHeight,
1096 &frame2));
1097 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_YU12, kWidth, kHeight,
1098 &frame3));
1099 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1100 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1101 }
1102
1103 // Test constructing an image from an I420 MJPG buffer.
1104 void ConstructMjpgI420() {
1105 T frame1, frame2;
1106 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1107 ASSERT_TRUE(LoadFrame(kJpeg420Filename,
1108 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1109 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1110 }
1111
1112 // Test constructing an image from an I422 MJPG buffer.
1113 void ConstructMjpgI422() {
1114 T frame1, frame2;
1115 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1116 ASSERT_TRUE(LoadFrame(kJpeg422Filename,
1117 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1118 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1119 }
1120
1121 // Test constructing an image from an I444 MJPG buffer.
1122 void ConstructMjpgI444() {
1123 T frame1, frame2;
1124 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1125 ASSERT_TRUE(LoadFrame(kJpeg444Filename,
1126 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1127 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1128 }
1129
1130 // Test constructing an image from an I444 MJPG buffer.
1131 void ConstructMjpgI411() {
1132 T frame1, frame2;
1133 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1134 ASSERT_TRUE(LoadFrame(kJpeg411Filename,
1135 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1136 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1137 }
1138
1139 // Test constructing an image from an I400 MJPG buffer.
1140 // TODO(fbarchard): Stronger compare on chroma. Compare agaisnt a grey image.
1141 void ConstructMjpgI400() {
1142 T frame1, frame2;
1143 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1144 ASSERT_TRUE(LoadFrame(kJpeg400Filename,
1145 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1146 EXPECT_TRUE(IsPlaneEqual("y", frame1.GetYPlane(), frame1.GetYPitch(),
1147 frame2.GetYPlane(), frame2.GetYPitch(),
1148 kWidth, kHeight, 32));
1149 EXPECT_TRUE(IsEqual(frame1, frame2, 128));
1150 }
1151
1152 // Test constructing an image from an I420 MJPG buffer.
1153 void ValidateFrame(const char* name, uint32 fourcc, int data_adjust,
1154 int size_adjust, bool expected_result) {
1155 T frame;
1156 talk_base::scoped_ptr<talk_base::MemoryStream> ms(LoadSample(name));
wu@webrtc.org16d62542013-11-05 23:45:14 +00001157 ASSERT_TRUE(ms.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001158 const uint8* sample = reinterpret_cast<const uint8*>(ms.get()->GetBuffer());
1159 size_t sample_size;
1160 ms->GetSize(&sample_size);
1161 // Optional adjust size to test invalid size.
1162 size_t data_size = sample_size + data_adjust;
1163
1164 // Allocate a buffer with end page aligned.
1165 const int kPadToHeapSized = 16 * 1024 * 1024;
wu@webrtc.org97077a32013-10-25 21:18:33 +00001166 talk_base::scoped_ptr<uint8[]> page_buffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001167 new uint8[((data_size + kPadToHeapSized + 4095) & ~4095)]);
1168 uint8* data_ptr = page_buffer.get();
1169 if (!data_ptr) {
1170 LOG(LS_WARNING) << "Failed to allocate memory for ValidateFrame test.";
1171 EXPECT_FALSE(expected_result); // NULL is okay if failure was expected.
1172 return;
1173 }
1174 data_ptr += kPadToHeapSized + (-(static_cast<int>(data_size)) & 4095);
1175 memcpy(data_ptr, sample, talk_base::_min(data_size, sample_size));
1176 for (int i = 0; i < repeat_; ++i) {
1177 EXPECT_EQ(expected_result, frame.Validate(fourcc, kWidth, kHeight,
1178 data_ptr,
1179 sample_size + size_adjust));
1180 }
1181 }
1182
1183 // Test validate for I420 MJPG buffer.
1184 void ValidateMjpgI420() {
1185 ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, 0, 0, true);
1186 }
1187
1188 // Test validate for I422 MJPG buffer.
1189 void ValidateMjpgI422() {
1190 ValidateFrame(kJpeg422Filename, cricket::FOURCC_MJPG, 0, 0, true);
1191 }
1192
1193 // Test validate for I444 MJPG buffer.
1194 void ValidateMjpgI444() {
1195 ValidateFrame(kJpeg444Filename, cricket::FOURCC_MJPG, 0, 0, true);
1196 }
1197
1198 // Test validate for I411 MJPG buffer.
1199 void ValidateMjpgI411() {
1200 ValidateFrame(kJpeg411Filename, cricket::FOURCC_MJPG, 0, 0, true);
1201 }
1202
1203 // Test validate for I400 MJPG buffer.
1204 void ValidateMjpgI400() {
1205 ValidateFrame(kJpeg400Filename, cricket::FOURCC_MJPG, 0, 0, true);
1206 }
1207
1208 // Test validate for I420 buffer.
1209 void ValidateI420() {
1210 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, 0, true);
1211 }
1212
1213 // Test validate for I420 buffer where size is too small
1214 void ValidateI420SmallSize() {
1215 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, -16384, false);
1216 }
1217
1218 // Test validate for I420 buffer where size is too large (16 MB)
1219 // Will produce warning but pass.
1220 void ValidateI420LargeSize() {
1221 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 16000000, 16000000,
1222 true);
1223 }
1224
1225 // Test validate for I420 buffer where size is 1 GB (not reasonable).
1226 void ValidateI420HugeSize() {
1227#ifndef WIN32 // TODO(fbarchard): Reenable when fixing bug 9603762.
1228 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 1000000000u,
1229 1000000000u, false);
1230#endif
1231 }
1232
1233 // The following test that Validate crashes if the size is greater than the
1234 // actual buffer size.
1235 // TODO(fbarchard): Consider moving a filter into the capturer/plugin.
1236#if defined(_MSC_VER) && defined(_DEBUG)
1237 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
1238 if (code == EXCEPTION_ACCESS_VIOLATION) {
1239 LOG(LS_INFO) << "Caught EXCEPTION_ACCESS_VIOLATION as expected.";
1240 return EXCEPTION_EXECUTE_HANDLER;
1241 } else {
1242 LOG(LS_INFO) << "Did not catch EXCEPTION_ACCESS_VIOLATION. Unexpected.";
1243 return EXCEPTION_CONTINUE_SEARCH;
1244 }
1245 }
1246
1247 // Test validate fails for truncated MJPG data buffer. If ValidateFrame
1248 // crashes the exception handler will return and unittest passes with OK.
1249 void ValidateMjpgI420InvalidSize() {
1250 __try {
1251 ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, -16384, 0, false);
1252 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
1253 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1254 return; // Successfully crashed in ValidateFrame.
1255 }
1256 }
1257
1258 // Test validate fails for truncated I420 buffer.
1259 void ValidateI420InvalidSize() {
1260 __try {
1261 ValidateFrame(kImageFilename, cricket::FOURCC_I420, -16384, 0, false);
1262 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
1263 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1264 return; // Successfully crashed in ValidateFrame.
1265 }
1266 }
1267#endif
1268
1269 // Test constructing an image from a YUY2 buffer (and synonymous formats).
1270 void ConstructYuy2Aliases() {
1271 T frame1, frame2, frame3, frame4;
1272 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1273 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
1274 ASSERT_TRUE(ms.get() != NULL);
1275 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
1276 &frame1));
1277 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
1278 kWidth, kHeight, &frame2));
1279 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUVS,
1280 kWidth, kHeight, &frame3));
1281 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUYV,
1282 kWidth, kHeight, &frame4));
1283 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1284 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1285 EXPECT_TRUE(IsEqual(frame1, frame4, 0));
1286 }
1287
1288 // Test constructing an image from a UYVY buffer (and synonymous formats).
1289 void ConstructUyvyAliases() {
1290 T frame1, frame2, frame3, frame4;
1291 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1292 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
1293 ASSERT_TRUE(ms.get() != NULL);
1294 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
1295 &frame1));
1296 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
1297 kWidth, kHeight, &frame2));
1298 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_2VUY,
1299 kWidth, kHeight, &frame3));
1300 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_HDYC,
1301 kWidth, kHeight, &frame4));
1302 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1303 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1304 EXPECT_TRUE(IsEqual(frame1, frame4, 0));
1305 }
1306
1307 // Test creating a copy.
1308 void ConstructCopy() {
1309 T frame1, frame2;
1310 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1311 for (int i = 0; i < repeat_; ++i) {
1312 EXPECT_TRUE(frame2.Init(frame1));
1313 }
1314 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1315 }
1316
1317 // Test creating a copy and check that it just increments the refcount.
1318 void ConstructCopyIsRef() {
1319 T frame1, frame2;
1320 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1321 for (int i = 0; i < repeat_; ++i) {
1322 EXPECT_TRUE(frame2.Init(frame1));
1323 }
1324 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1325 EXPECT_EQ(frame1.GetYPlane(), frame2.GetYPlane());
1326 EXPECT_EQ(frame1.GetUPlane(), frame2.GetUPlane());
1327 EXPECT_EQ(frame1.GetVPlane(), frame2.GetVPlane());
1328 }
1329
1330 // Test creating an empty image and initing it to black.
1331 void ConstructBlack() {
1332 T frame;
1333 for (int i = 0; i < repeat_; ++i) {
1334 EXPECT_TRUE(frame.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1335 }
1336 EXPECT_TRUE(IsSize(frame, kWidth, kHeight));
1337 EXPECT_TRUE(IsBlack(frame));
1338 }
1339
1340 // Test constructing an image from a YUY2 buffer with a range of sizes.
1341 // Only tests that conversion does not crash or corrupt heap.
1342 void ConstructYuy2AllSizes() {
1343 T frame1, frame2;
1344 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
1345 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
1346 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1347 CreateYuv422Sample(cricket::FOURCC_YUY2, width, height));
1348 ASSERT_TRUE(ms.get() != NULL);
1349 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, width, height,
1350 &frame1));
1351 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
1352 width, height, &frame2));
1353 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1354 }
1355 }
1356 }
1357
1358 // Test constructing an image from a ARGB buffer with a range of sizes.
1359 // Only tests that conversion does not crash or corrupt heap.
1360 void ConstructARGBAllSizes() {
1361 T frame1, frame2;
1362 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
1363 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
1364 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1365 CreateRgbSample(cricket::FOURCC_ARGB, width, height));
1366 ASSERT_TRUE(ms.get() != NULL);
1367 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, width, height,
1368 &frame1));
1369 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
1370 width, height, &frame2));
1371 EXPECT_TRUE(IsEqual(frame1, frame2, 64));
1372 }
1373 }
1374 // Test a practical window size for screencasting usecase.
1375 const int kOddWidth = 1228;
1376 const int kOddHeight = 260;
1377 for (int j = 0; j < 2; ++j) {
1378 for (int i = 0; i < 2; ++i) {
1379 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1380 CreateRgbSample(cricket::FOURCC_ARGB, kOddWidth + i, kOddHeight + j));
1381 ASSERT_TRUE(ms.get() != NULL);
1382 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
1383 kOddWidth + i, kOddHeight + j,
1384 &frame1));
1385 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
1386 kOddWidth + i, kOddHeight + j, &frame2));
1387 EXPECT_TRUE(IsEqual(frame1, frame2, 64));
1388 }
1389 }
1390 }
1391
1392 // Tests re-initing an existing image.
1393 void Reset() {
1394 T frame1, frame2;
1395 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
1396 LoadSample(kImageFilename));
wu@webrtc.org16d62542013-11-05 23:45:14 +00001397 ASSERT_TRUE(ms.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001398 size_t data_size;
1399 ms->GetSize(&data_size);
1400 EXPECT_TRUE(frame1.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1401 EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1402 EXPECT_TRUE(IsBlack(frame1));
1403 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1404 EXPECT_TRUE(frame1.Reset(cricket::FOURCC_I420,
1405 kWidth, kHeight, kWidth, kHeight,
1406 reinterpret_cast<uint8*>(ms->GetBuffer()),
1407 data_size, 1, 1, 0, 0, 0));
1408 EXPECT_FALSE(IsBlack(frame1));
1409 EXPECT_FALSE(IsEqual(frame1, frame2, 0));
1410 }
1411
1412 //////////////////////
1413 // Conversion tests //
1414 //////////////////////
1415
1416 enum ToFrom { TO, FROM };
1417
1418 // Helper function for test converting from I420 to packed formats.
1419 inline void ConvertToBuffer(int bpp, int rowpad, bool invert, ToFrom to_from,
1420 int error, uint32 fourcc,
1421 int (*RGBToI420)(const uint8* src_frame, int src_stride_frame,
1422 uint8* dst_y, int dst_stride_y,
1423 uint8* dst_u, int dst_stride_u,
1424 uint8* dst_v, int dst_stride_v,
1425 int width, int height)) {
1426 T frame1, frame2;
1427 int repeat_to = (to_from == TO) ? repeat_ : 1;
1428 int repeat_from = (to_from == FROM) ? repeat_ : 1;
1429
1430 int astride = kWidth * bpp + rowpad;
1431 size_t out_size = astride * kHeight;
wu@webrtc.org97077a32013-10-25 21:18:33 +00001432 talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment + 1]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001433 memset(outbuf.get(), 0, out_size + kAlignment + 1);
1434 uint8 *outtop = ALIGNP(outbuf.get(), kAlignment);
1435 uint8 *out = outtop;
1436 int stride = astride;
1437 if (invert) {
1438 out += (kHeight - 1) * stride; // Point to last row.
1439 stride = -stride;
1440 }
1441 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1442
1443 for (int i = 0; i < repeat_to; ++i) {
1444 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(fourcc,
1445 out,
1446 out_size, stride));
1447 }
1448 EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1449 for (int i = 0; i < repeat_from; ++i) {
1450 EXPECT_EQ(0, RGBToI420(out, stride,
1451 frame2.GetYPlane(), frame2.GetYPitch(),
1452 frame2.GetUPlane(), frame2.GetUPitch(),
1453 frame2.GetVPlane(), frame2.GetVPitch(),
1454 kWidth, kHeight));
1455 }
1456 if (rowpad) {
1457 EXPECT_EQ(0, outtop[kWidth * bpp]); // Ensure stride skipped end of row.
1458 EXPECT_NE(0, outtop[astride]); // Ensure pixel at start of 2nd row.
1459 } else {
1460 EXPECT_NE(0, outtop[kWidth * bpp]); // Expect something to be here.
1461 }
1462 EXPECT_EQ(0, outtop[out_size]); // Ensure no overrun.
1463 EXPECT_TRUE(IsEqual(frame1, frame2, error));
1464 }
1465
1466 static const int kError = 20;
1467 static const int kErrorHigh = 40;
1468 static const int kOddStride = 23;
1469
1470 // Tests ConvertToRGBBuffer formats.
1471 void ConvertToARGBBuffer() {
1472 ConvertToBuffer(4, 0, false, TO, kError,
1473 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1474 }
1475 void ConvertToBGRABuffer() {
1476 ConvertToBuffer(4, 0, false, TO, kError,
1477 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1478 }
1479 void ConvertToABGRBuffer() {
1480 ConvertToBuffer(4, 0, false, TO, kError,
1481 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1482 }
1483 void ConvertToRGB24Buffer() {
1484 ConvertToBuffer(3, 0, false, TO, kError,
1485 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1486 }
1487 void ConvertToRAWBuffer() {
1488 ConvertToBuffer(3, 0, false, TO, kError,
1489 cricket::FOURCC_RAW, libyuv::RAWToI420);
1490 }
1491 void ConvertToRGB565Buffer() {
1492 ConvertToBuffer(2, 0, false, TO, kError,
1493 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1494 }
1495 void ConvertToARGB1555Buffer() {
1496 ConvertToBuffer(2, 0, false, TO, kError,
1497 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1498 }
1499 void ConvertToARGB4444Buffer() {
1500 ConvertToBuffer(2, 0, false, TO, kError,
1501 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1502 }
1503 void ConvertToBayerBGGRBuffer() {
1504 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1505 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1506 }
1507 void ConvertToBayerGBRGBuffer() {
1508 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1509 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1510 }
1511 void ConvertToBayerGRBGBuffer() {
1512 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1513 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1514 }
1515 void ConvertToBayerRGGBBuffer() {
1516 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1517 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1518 }
1519 void ConvertToI400Buffer() {
1520 ConvertToBuffer(1, 0, false, TO, 128,
1521 cricket::FOURCC_I400, libyuv::I400ToI420);
1522 }
1523 void ConvertToYUY2Buffer() {
1524 ConvertToBuffer(2, 0, false, TO, kError,
1525 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1526 }
1527 void ConvertToUYVYBuffer() {
1528 ConvertToBuffer(2, 0, false, TO, kError,
1529 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1530 }
1531
1532 // Tests ConvertToRGBBuffer formats with odd stride.
1533 void ConvertToARGBBufferStride() {
1534 ConvertToBuffer(4, kOddStride, false, TO, kError,
1535 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1536 }
1537 void ConvertToBGRABufferStride() {
1538 ConvertToBuffer(4, kOddStride, false, TO, kError,
1539 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1540 }
1541 void ConvertToABGRBufferStride() {
1542 ConvertToBuffer(4, kOddStride, false, TO, kError,
1543 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1544 }
1545 void ConvertToRGB24BufferStride() {
1546 ConvertToBuffer(3, kOddStride, false, TO, kError,
1547 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1548 }
1549 void ConvertToRAWBufferStride() {
1550 ConvertToBuffer(3, kOddStride, false, TO, kError,
1551 cricket::FOURCC_RAW, libyuv::RAWToI420);
1552 }
1553 void ConvertToRGB565BufferStride() {
1554 ConvertToBuffer(2, kOddStride, false, TO, kError,
1555 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1556 }
1557 void ConvertToARGB1555BufferStride() {
1558 ConvertToBuffer(2, kOddStride, false, TO, kError,
1559 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1560 }
1561 void ConvertToARGB4444BufferStride() {
1562 ConvertToBuffer(2, kOddStride, false, TO, kError,
1563 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1564 }
1565 void ConvertToBayerBGGRBufferStride() {
1566 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1567 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1568 }
1569 void ConvertToBayerGBRGBufferStride() {
1570 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1571 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1572 }
1573 void ConvertToBayerGRBGBufferStride() {
1574 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1575 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1576 }
1577 void ConvertToBayerRGGBBufferStride() {
1578 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1579 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1580 }
1581 void ConvertToI400BufferStride() {
1582 ConvertToBuffer(1, kOddStride, false, TO, 128,
1583 cricket::FOURCC_I400, libyuv::I400ToI420);
1584 }
1585 void ConvertToYUY2BufferStride() {
1586 ConvertToBuffer(2, kOddStride, false, TO, kError,
1587 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1588 }
1589 void ConvertToUYVYBufferStride() {
1590 ConvertToBuffer(2, kOddStride, false, TO, kError,
1591 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1592 }
1593
1594 // Tests ConvertToRGBBuffer formats with negative stride to invert image.
1595 void ConvertToARGBBufferInverted() {
1596 ConvertToBuffer(4, 0, true, TO, kError,
1597 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1598 }
1599 void ConvertToBGRABufferInverted() {
1600 ConvertToBuffer(4, 0, true, TO, kError,
1601 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1602 }
1603 void ConvertToABGRBufferInverted() {
1604 ConvertToBuffer(4, 0, true, TO, kError,
1605 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1606 }
1607 void ConvertToRGB24BufferInverted() {
1608 ConvertToBuffer(3, 0, true, TO, kError,
1609 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1610 }
1611 void ConvertToRAWBufferInverted() {
1612 ConvertToBuffer(3, 0, true, TO, kError,
1613 cricket::FOURCC_RAW, libyuv::RAWToI420);
1614 }
1615 void ConvertToRGB565BufferInverted() {
1616 ConvertToBuffer(2, 0, true, TO, kError,
1617 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1618 }
1619 void ConvertToARGB1555BufferInverted() {
1620 ConvertToBuffer(2, 0, true, TO, kError,
1621 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1622 }
1623 void ConvertToARGB4444BufferInverted() {
1624 ConvertToBuffer(2, 0, true, TO, kError,
1625 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1626 }
1627 void ConvertToBayerBGGRBufferInverted() {
1628 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1629 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1630 }
1631 void ConvertToBayerGBRGBufferInverted() {
1632 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1633 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1634 }
1635 void ConvertToBayerGRBGBufferInverted() {
1636 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1637 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1638 }
1639 void ConvertToBayerRGGBBufferInverted() {
1640 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1641 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1642 }
1643 void ConvertToI400BufferInverted() {
1644 ConvertToBuffer(1, 0, true, TO, 128,
1645 cricket::FOURCC_I400, libyuv::I400ToI420);
1646 }
1647 void ConvertToYUY2BufferInverted() {
1648 ConvertToBuffer(2, 0, true, TO, kError,
1649 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1650 }
1651 void ConvertToUYVYBufferInverted() {
1652 ConvertToBuffer(2, 0, true, TO, kError,
1653 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1654 }
1655
1656 // Tests ConvertFrom formats.
1657 void ConvertFromARGBBuffer() {
1658 ConvertToBuffer(4, 0, false, FROM, kError,
1659 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1660 }
1661 void ConvertFromBGRABuffer() {
1662 ConvertToBuffer(4, 0, false, FROM, kError,
1663 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1664 }
1665 void ConvertFromABGRBuffer() {
1666 ConvertToBuffer(4, 0, false, FROM, kError,
1667 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1668 }
1669 void ConvertFromRGB24Buffer() {
1670 ConvertToBuffer(3, 0, false, FROM, kError,
1671 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1672 }
1673 void ConvertFromRAWBuffer() {
1674 ConvertToBuffer(3, 0, false, FROM, kError,
1675 cricket::FOURCC_RAW, libyuv::RAWToI420);
1676 }
1677 void ConvertFromRGB565Buffer() {
1678 ConvertToBuffer(2, 0, false, FROM, kError,
1679 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1680 }
1681 void ConvertFromARGB1555Buffer() {
1682 ConvertToBuffer(2, 0, false, FROM, kError,
1683 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1684 }
1685 void ConvertFromARGB4444Buffer() {
1686 ConvertToBuffer(2, 0, false, FROM, kError,
1687 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1688 }
1689 void ConvertFromBayerBGGRBuffer() {
1690 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1691 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1692 }
1693 void ConvertFromBayerGBRGBuffer() {
1694 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1695 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1696 }
1697 void ConvertFromBayerGRBGBuffer() {
1698 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1699 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1700 }
1701 void ConvertFromBayerRGGBBuffer() {
1702 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1703 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1704 }
1705 void ConvertFromI400Buffer() {
1706 ConvertToBuffer(1, 0, false, FROM, 128,
1707 cricket::FOURCC_I400, libyuv::I400ToI420);
1708 }
1709 void ConvertFromYUY2Buffer() {
1710 ConvertToBuffer(2, 0, false, FROM, kError,
1711 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1712 }
1713 void ConvertFromUYVYBuffer() {
1714 ConvertToBuffer(2, 0, false, FROM, kError,
1715 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1716 }
1717
1718 // Tests ConvertFrom formats with odd stride.
1719 void ConvertFromARGBBufferStride() {
1720 ConvertToBuffer(4, kOddStride, false, FROM, kError,
1721 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1722 }
1723 void ConvertFromBGRABufferStride() {
1724 ConvertToBuffer(4, kOddStride, false, FROM, kError,
1725 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1726 }
1727 void ConvertFromABGRBufferStride() {
1728 ConvertToBuffer(4, kOddStride, false, FROM, kError,
1729 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1730 }
1731 void ConvertFromRGB24BufferStride() {
1732 ConvertToBuffer(3, kOddStride, false, FROM, kError,
1733 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1734 }
1735 void ConvertFromRAWBufferStride() {
1736 ConvertToBuffer(3, kOddStride, false, FROM, kError,
1737 cricket::FOURCC_RAW, libyuv::RAWToI420);
1738 }
1739 void ConvertFromRGB565BufferStride() {
1740 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1741 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1742 }
1743 void ConvertFromARGB1555BufferStride() {
1744 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1745 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1746 }
1747 void ConvertFromARGB4444BufferStride() {
1748 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1749 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1750 }
1751 void ConvertFromBayerBGGRBufferStride() {
1752 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1753 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1754 }
1755 void ConvertFromBayerGBRGBufferStride() {
1756 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1757 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1758 }
1759 void ConvertFromBayerGRBGBufferStride() {
1760 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1761 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1762 }
1763 void ConvertFromBayerRGGBBufferStride() {
1764 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1765 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1766 }
1767 void ConvertFromI400BufferStride() {
1768 ConvertToBuffer(1, kOddStride, false, FROM, 128,
1769 cricket::FOURCC_I400, libyuv::I400ToI420);
1770 }
1771 void ConvertFromYUY2BufferStride() {
1772 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1773 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1774 }
1775 void ConvertFromUYVYBufferStride() {
1776 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1777 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1778 }
1779
1780 // Tests ConvertFrom formats with negative stride to invert image.
1781 void ConvertFromARGBBufferInverted() {
1782 ConvertToBuffer(4, 0, true, FROM, kError,
1783 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1784 }
1785 void ConvertFromBGRABufferInverted() {
1786 ConvertToBuffer(4, 0, true, FROM, kError,
1787 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1788 }
1789 void ConvertFromABGRBufferInverted() {
1790 ConvertToBuffer(4, 0, true, FROM, kError,
1791 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1792 }
1793 void ConvertFromRGB24BufferInverted() {
1794 ConvertToBuffer(3, 0, true, FROM, kError,
1795 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1796 }
1797 void ConvertFromRAWBufferInverted() {
1798 ConvertToBuffer(3, 0, true, FROM, kError,
1799 cricket::FOURCC_RAW, libyuv::RAWToI420);
1800 }
1801 void ConvertFromRGB565BufferInverted() {
1802 ConvertToBuffer(2, 0, true, FROM, kError,
1803 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1804 }
1805 void ConvertFromARGB1555BufferInverted() {
1806 ConvertToBuffer(2, 0, true, FROM, kError,
1807 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1808 }
1809 void ConvertFromARGB4444BufferInverted() {
1810 ConvertToBuffer(2, 0, true, FROM, kError,
1811 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1812 }
1813 void ConvertFromBayerBGGRBufferInverted() {
1814 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1815 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1816 }
1817 void ConvertFromBayerGBRGBufferInverted() {
1818 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1819 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1820 }
1821 void ConvertFromBayerGRBGBufferInverted() {
1822 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1823 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1824 }
1825 void ConvertFromBayerRGGBBufferInverted() {
1826 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1827 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1828 }
1829 void ConvertFromI400BufferInverted() {
1830 ConvertToBuffer(1, 0, true, FROM, 128,
1831 cricket::FOURCC_I400, libyuv::I400ToI420);
1832 }
1833 void ConvertFromYUY2BufferInverted() {
1834 ConvertToBuffer(2, 0, true, FROM, kError,
1835 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1836 }
1837 void ConvertFromUYVYBufferInverted() {
1838 ConvertToBuffer(2, 0, true, FROM, kError,
1839 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1840 }
1841
1842 // Test converting from I420 to I422.
1843 void ConvertToI422Buffer() {
1844 T frame1, frame2;
1845 size_t out_size = kWidth * kHeight * 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +00001846 talk_base::scoped_ptr<uint8[]> buf(new uint8[out_size + kAlignment]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 uint8* y = ALIGNP(buf.get(), kAlignment);
1848 uint8* u = y + kWidth * kHeight;
1849 uint8* v = u + (kWidth / 2) * kHeight;
1850 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1851 for (int i = 0; i < repeat_; ++i) {
1852 EXPECT_EQ(0, libyuv::I420ToI422(frame1.GetYPlane(), frame1.GetYPitch(),
1853 frame1.GetUPlane(), frame1.GetUPitch(),
1854 frame1.GetVPlane(), frame1.GetVPitch(),
1855 y, kWidth,
1856 u, kWidth / 2,
1857 v, kWidth / 2,
1858 kWidth, kHeight));
1859 }
1860 EXPECT_TRUE(frame2.Init(cricket::FOURCC_I422,
1861 kWidth, kHeight, kWidth, kHeight,
1862 y,
1863 out_size, 1, 1, 0, 0, cricket::ROTATION_0));
wu@webrtc.org9caf2762013-12-11 18:25:07 +00001864 EXPECT_TRUE(IsEqual(frame1, frame2, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865 }
1866
1867 #define TEST_TOBYR(NAME, BAYER) \
1868 void NAME() { \
1869 size_t bayer_size = kWidth * kHeight; \
wu@webrtc.org97077a32013-10-25 21:18:33 +00001870 talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871 bayer_size + kAlignment]); \
1872 uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment); \
1873 T frame; \
1874 talk_base::scoped_ptr<talk_base::MemoryStream> ms( \
1875 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1876 ASSERT_TRUE(ms.get() != NULL); \
1877 for (int i = 0; i < repeat_; ++i) { \
1878 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()), \
1879 kWidth * 4, \
1880 bayer, kWidth, \
1881 kWidth, kHeight); \
1882 } \
1883 talk_base::scoped_ptr<talk_base::MemoryStream> ms2( \
1884 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1885 size_t data_size; \
1886 bool ret = ms2->GetSize(&data_size); \
1887 EXPECT_TRUE(ret); \
1888 libyuv::Bayer##BAYER##ToARGB(bayer, kWidth, \
1889 reinterpret_cast<uint8*>(ms2->GetBuffer()), \
1890 kWidth * 4, \
1891 kWidth, kHeight); \
1892 EXPECT_TRUE(IsPlaneEqual("argb", \
1893 reinterpret_cast<uint8*>(ms->GetBuffer()), kWidth * 4, \
1894 reinterpret_cast<uint8*>(ms2->GetBuffer()), kWidth * 4, \
1895 kWidth * 4, kHeight, 240)); \
1896 } \
1897 void NAME##Unaligned() { \
1898 size_t bayer_size = kWidth * kHeight; \
wu@webrtc.org97077a32013-10-25 21:18:33 +00001899 talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001900 bayer_size + 1 + kAlignment]); \
1901 uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment) + 1; \
1902 T frame; \
1903 talk_base::scoped_ptr<talk_base::MemoryStream> ms( \
1904 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1905 ASSERT_TRUE(ms.get() != NULL); \
1906 for (int i = 0; i < repeat_; ++i) { \
1907 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()), \
1908 kWidth * 4, \
1909 bayer, kWidth, \
1910 kWidth, kHeight); \
1911 } \
1912 talk_base::scoped_ptr<talk_base::MemoryStream> ms2( \
1913 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1914 size_t data_size; \
1915 bool ret = ms2->GetSize(&data_size); \
1916 EXPECT_TRUE(ret); \
1917 libyuv::Bayer##BAYER##ToARGB(bayer, kWidth, \
1918 reinterpret_cast<uint8*>(ms2->GetBuffer()), \
1919 kWidth * 4, \
1920 kWidth, kHeight); \
1921 EXPECT_TRUE(IsPlaneEqual("argb", \
1922 reinterpret_cast<uint8*>(ms->GetBuffer()), kWidth * 4, \
1923 reinterpret_cast<uint8*>(ms2->GetBuffer()), kWidth * 4, \
1924 kWidth * 4, kHeight, 240)); \
1925 }
1926
1927 // Tests ARGB to Bayer formats.
1928 TEST_TOBYR(ConvertARGBToBayerGRBG, GRBG)
1929 TEST_TOBYR(ConvertARGBToBayerGBRG, GBRG)
1930 TEST_TOBYR(ConvertARGBToBayerBGGR, BGGR)
1931 TEST_TOBYR(ConvertARGBToBayerRGGB, RGGB)
1932
1933 #define TEST_BYRTORGB(NAME, BAYER) \
1934 void NAME() { \
1935 size_t bayer_size = kWidth * kHeight; \
wu@webrtc.org97077a32013-10-25 21:18:33 +00001936 talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001937 bayer_size + kAlignment]); \
1938 uint8 *bayer1 = ALIGNP(bayerbuf.get(), kAlignment); \
1939 for (int i = 0; i < kWidth * kHeight; ++i) { \
1940 bayer1[i] = static_cast<uint8>(i * 33u + 183u); \
1941 } \
1942 T frame; \
1943 talk_base::scoped_ptr<talk_base::MemoryStream> ms( \
1944 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1945 ASSERT_TRUE(ms.get() != NULL); \
1946 for (int i = 0; i < repeat_; ++i) { \
1947 libyuv::Bayer##BAYER##ToARGB(bayer1, kWidth, \
1948 reinterpret_cast<uint8*>(ms->GetBuffer()), \
1949 kWidth * 4, \
1950 kWidth, kHeight); \
1951 } \
wu@webrtc.org97077a32013-10-25 21:18:33 +00001952 talk_base::scoped_ptr<uint8[]> bayer2buf(new uint8[ \
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953 bayer_size + kAlignment]); \
1954 uint8 *bayer2 = ALIGNP(bayer2buf.get(), kAlignment); \
1955 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()), \
1956 kWidth * 4, \
1957 bayer2, kWidth, \
1958 kWidth, kHeight); \
1959 EXPECT_TRUE(IsPlaneEqual("bayer", \
1960 bayer1, kWidth, \
1961 bayer2, kWidth, \
1962 kWidth, kHeight, 0)); \
1963 }
1964
1965 // Tests Bayer formats to ARGB.
1966 TEST_BYRTORGB(ConvertBayerGRBGToARGB, GRBG)
1967 TEST_BYRTORGB(ConvertBayerGBRGToARGB, GBRG)
1968 TEST_BYRTORGB(ConvertBayerBGGRToARGB, BGGR)
1969 TEST_BYRTORGB(ConvertBayerRGGBToARGB, RGGB)
1970
1971 ///////////////////
1972 // General tests //
1973 ///////////////////
1974
1975 void Copy() {
1976 talk_base::scoped_ptr<T> source(new T);
1977 talk_base::scoped_ptr<cricket::VideoFrame> target;
1978 ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
1979 target.reset(source->Copy());
1980 EXPECT_TRUE(IsEqual(*source, *target, 0));
1981 source.reset();
1982 EXPECT_TRUE(target->GetYPlane() != NULL);
1983 }
1984
1985 void CopyIsRef() {
1986 talk_base::scoped_ptr<T> source(new T);
1987 talk_base::scoped_ptr<cricket::VideoFrame> target;
1988 ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
1989 target.reset(source->Copy());
1990 EXPECT_TRUE(IsEqual(*source, *target, 0));
1991 EXPECT_EQ(source->GetYPlane(), target->GetYPlane());
1992 EXPECT_EQ(source->GetUPlane(), target->GetUPlane());
1993 EXPECT_EQ(source->GetVPlane(), target->GetVPlane());
1994 }
1995
1996 void MakeExclusive() {
1997 talk_base::scoped_ptr<T> source(new T);
1998 talk_base::scoped_ptr<cricket::VideoFrame> target;
1999 ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
2000 target.reset(source->Copy());
2001 EXPECT_TRUE(target->MakeExclusive());
2002 EXPECT_TRUE(IsEqual(*source, *target, 0));
2003 EXPECT_NE(target->GetYPlane(), source->GetYPlane());
2004 EXPECT_NE(target->GetUPlane(), source->GetUPlane());
2005 EXPECT_NE(target->GetVPlane(), source->GetVPlane());
2006 }
2007
2008 void CopyToBuffer() {
2009 T frame;
2010 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
2011 LoadSample(kImageFilename));
wu@webrtc.org16d62542013-11-05 23:45:14 +00002012 ASSERT_TRUE(ms.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002013 ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
2014 &frame));
2015 size_t out_size = kWidth * kHeight * 3 / 2;
wu@webrtc.org97077a32013-10-25 21:18:33 +00002016 talk_base::scoped_ptr<uint8[]> out(new uint8[out_size]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002017 for (int i = 0; i < repeat_; ++i) {
2018 EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
2019 }
2020 EXPECT_EQ(0, memcmp(out.get(), ms->GetBuffer(), out_size));
2021 }
2022
2023 void CopyToFrame() {
2024 T source;
2025 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
2026 LoadSample(kImageFilename));
wu@webrtc.org16d62542013-11-05 23:45:14 +00002027 ASSERT_TRUE(ms.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028 ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
2029 &source));
2030
2031 // Create the target frame by loading from a file.
2032 T target;
2033 ASSERT_TRUE(LoadFrameNoRepeat(&target));
2034 EXPECT_FALSE(IsBlack(target));
2035
2036 // Stretch and check if the stretched target is black.
2037 source.CopyToFrame(&target);
2038
2039 EXPECT_TRUE(IsEqual(source, target, 0));
2040 }
2041
2042 void Write() {
2043 T frame;
2044 talk_base::scoped_ptr<talk_base::MemoryStream> ms(
2045 LoadSample(kImageFilename));
wu@webrtc.org16d62542013-11-05 23:45:14 +00002046 ASSERT_TRUE(ms.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047 talk_base::MemoryStream ms2;
2048 size_t size;
2049 ASSERT_TRUE(ms->GetSize(&size));
2050 ASSERT_TRUE(ms2.ReserveSize(size));
2051 ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
2052 &frame));
2053 for (int i = 0; i < repeat_; ++i) {
2054 ms2.SetPosition(0u); // Useful when repeat_ > 1.
2055 int error;
2056 EXPECT_EQ(talk_base::SR_SUCCESS, frame.Write(&ms2, &error));
2057 }
2058 size_t out_size = cricket::VideoFrame::SizeOf(kWidth, kHeight);
2059 EXPECT_EQ(0, memcmp(ms2.GetBuffer(), ms->GetBuffer(), out_size));
2060 }
2061
2062 void CopyToBuffer1Pixel() {
2063 size_t out_size = 3;
wu@webrtc.org97077a32013-10-25 21:18:33 +00002064 talk_base::scoped_ptr<uint8[]> out(new uint8[out_size + 1]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 memset(out.get(), 0xfb, out_size + 1); // Fill buffer
2066 uint8 pixel[3] = { 1, 2, 3 };
2067 T frame;
2068 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1,
2069 pixel, sizeof(pixel),
2070 1, 1, 0, 0, 0));
2071 for (int i = 0; i < repeat_; ++i) {
2072 EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
2073 }
2074 EXPECT_EQ(1, out.get()[0]); // Check Y. Should be 1.
2075 EXPECT_EQ(2, out.get()[1]); // Check U. Should be 2.
2076 EXPECT_EQ(3, out.get()[2]); // Check V. Should be 3.
2077 EXPECT_EQ(0xfb, out.get()[3]); // Check sentinel is still intact.
2078 }
2079
2080 void StretchToFrame() {
2081 // Create the source frame as a black frame.
2082 T source;
2083 EXPECT_TRUE(source.InitToBlack(kWidth * 2, kHeight * 2, 1, 1, 0, 0));
2084 EXPECT_TRUE(IsSize(source, kWidth * 2, kHeight * 2));
2085
2086 // Create the target frame by loading from a file.
2087 T target1;
2088 ASSERT_TRUE(LoadFrameNoRepeat(&target1));
2089 EXPECT_FALSE(IsBlack(target1));
2090
2091 // Stretch and check if the stretched target is black.
2092 source.StretchToFrame(&target1, true, false);
2093 EXPECT_TRUE(IsBlack(target1));
2094
2095 // Crop and stretch and check if the stretched target is black.
2096 T target2;
2097 ASSERT_TRUE(LoadFrameNoRepeat(&target2));
2098 source.StretchToFrame(&target2, true, true);
2099 EXPECT_TRUE(IsBlack(target2));
2100 EXPECT_EQ(source.GetElapsedTime(), target2.GetElapsedTime());
2101 EXPECT_EQ(source.GetTimeStamp(), target2.GetTimeStamp());
2102 }
2103
2104 int repeat_;
2105};
2106
2107#endif // TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_