Home | History | Annotate | Download | only in base
      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_
   2117