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