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