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_ptr<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_ptr<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, 1));
    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_ptr<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_ptr<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_ptr<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_ptr<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_ptr<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_ptr<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_ptr<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_ptr<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     ASSERT_TRUE(ms.get() != NULL);
   1158     const uint8* sample = reinterpret_cast<const uint8*>(ms.get()->GetBuffer());
   1159     size_t sample_size;
   1160     ms->GetSize(&sample_size);
   1161     // Optional adjust size to test invalid size.
   1162     size_t data_size = sample_size + data_adjust;
   1163 
   1164     // Allocate a buffer with end page aligned.
   1165     const int kPadToHeapSized = 16 * 1024 * 1024;
   1166     talk_base::scoped_ptr<uint8[]> page_buffer(
   1167         new uint8[((data_size + kPadToHeapSized + 4095) & ~4095)]);
   1168     uint8* data_ptr = page_buffer.get();
   1169     if (!data_ptr) {
   1170       LOG(LS_WARNING) << "Failed to allocate memory for ValidateFrame test.";
   1171       EXPECT_FALSE(expected_result);  // NULL is okay if failure was expected.
   1172       return;
   1173     }
   1174     data_ptr += kPadToHeapSized + (-(static_cast<int>(data_size)) & 4095);
   1175     memcpy(data_ptr, sample, talk_base::_min(data_size, sample_size));
   1176     for (int i = 0; i < repeat_; ++i) {
   1177       EXPECT_EQ(expected_result, frame.Validate(fourcc, kWidth, kHeight,
   1178                                                 data_ptr,
   1179                                                 sample_size + size_adjust));
   1180     }
   1181   }
   1182 
   1183   // Test validate for I420 MJPG buffer.
   1184   void ValidateMjpgI420() {
   1185     ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, 0, 0, true);
   1186   }
   1187 
   1188   // Test validate for I422 MJPG buffer.
   1189   void ValidateMjpgI422() {
   1190     ValidateFrame(kJpeg422Filename, cricket::FOURCC_MJPG, 0, 0, true);
   1191   }
   1192 
   1193   // Test validate for I444 MJPG buffer.
   1194   void ValidateMjpgI444() {
   1195     ValidateFrame(kJpeg444Filename, cricket::FOURCC_MJPG, 0, 0, true);
   1196   }
   1197 
   1198   // Test validate for I411 MJPG buffer.
   1199   void ValidateMjpgI411() {
   1200     ValidateFrame(kJpeg411Filename, cricket::FOURCC_MJPG, 0, 0, true);
   1201   }
   1202 
   1203   // Test validate for I400 MJPG buffer.
   1204   void ValidateMjpgI400() {
   1205     ValidateFrame(kJpeg400Filename, cricket::FOURCC_MJPG, 0, 0, true);
   1206   }
   1207 
   1208   // Test validate for I420 buffer.
   1209   void ValidateI420() {
   1210     ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, 0, true);
   1211   }
   1212 
   1213   // Test validate for I420 buffer where size is too small
   1214   void ValidateI420SmallSize() {
   1215     ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, -16384, false);
   1216   }
   1217 
   1218   // Test validate for I420 buffer where size is too large (16 MB)
   1219   // Will produce warning but pass.
   1220   void ValidateI420LargeSize() {
   1221     ValidateFrame(kImageFilename, cricket::FOURCC_I420, 16000000, 16000000,
   1222                   true);
   1223   }
   1224 
   1225   // Test validate for I420 buffer where size is 1 GB (not reasonable).
   1226   void ValidateI420HugeSize() {
   1227 #ifndef WIN32  // TODO(fbarchard): Reenable when fixing bug 9603762.
   1228     ValidateFrame(kImageFilename, cricket::FOURCC_I420, 1000000000u,
   1229                   1000000000u, false);
   1230 #endif
   1231   }
   1232 
   1233   // The following test that Validate crashes if the size is greater than the
   1234   // actual buffer size.
   1235   // TODO(fbarchard): Consider moving a filter into the capturer/plugin.
   1236 #if defined(_MSC_VER) && defined(_DEBUG)
   1237   int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
   1238     if (code == EXCEPTION_ACCESS_VIOLATION) {
   1239       LOG(LS_INFO) << "Caught EXCEPTION_ACCESS_VIOLATION as expected.";
   1240       return EXCEPTION_EXECUTE_HANDLER;
   1241     } else {
   1242       LOG(LS_INFO) << "Did not catch EXCEPTION_ACCESS_VIOLATION.  Unexpected.";
   1243       return EXCEPTION_CONTINUE_SEARCH;
   1244     }
   1245   }
   1246 
   1247   // Test validate fails for truncated MJPG data buffer.  If ValidateFrame
   1248   // crashes the exception handler will return and unittest passes with OK.
   1249   void ValidateMjpgI420InvalidSize() {
   1250     __try {
   1251       ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, -16384, 0, false);
   1252       FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
   1253     } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
   1254       return;  // Successfully crashed in ValidateFrame.
   1255     }
   1256   }
   1257 
   1258   // Test validate fails for truncated I420 buffer.
   1259   void ValidateI420InvalidSize() {
   1260     __try {
   1261       ValidateFrame(kImageFilename, cricket::FOURCC_I420, -16384, 0, false);
   1262       FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
   1263     } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
   1264       return;  // Successfully crashed in ValidateFrame.
   1265     }
   1266   }
   1267 #endif
   1268 
   1269   // Test constructing an image from a YUY2 buffer (and synonymous formats).
   1270   void ConstructYuy2Aliases() {
   1271     T frame1, frame2, frame3, frame4;
   1272     talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   1273         CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
   1274     ASSERT_TRUE(ms.get() != NULL);
   1275     EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
   1276                               &frame1));
   1277     EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
   1278                           kWidth, kHeight, &frame2));
   1279     EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUVS,
   1280                           kWidth, kHeight, &frame3));
   1281     EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUYV,
   1282                           kWidth, kHeight, &frame4));
   1283     EXPECT_TRUE(IsEqual(frame1, frame2, 0));
   1284     EXPECT_TRUE(IsEqual(frame1, frame3, 0));
   1285     EXPECT_TRUE(IsEqual(frame1, frame4, 0));
   1286   }
   1287 
   1288   // Test constructing an image from a UYVY buffer (and synonymous formats).
   1289   void ConstructUyvyAliases() {
   1290     T frame1, frame2, frame3, frame4;
   1291     talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   1292         CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
   1293     ASSERT_TRUE(ms.get() != NULL);
   1294     EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
   1295                               &frame1));
   1296     EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
   1297                           kWidth, kHeight, &frame2));
   1298     EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_2VUY,
   1299                           kWidth, kHeight, &frame3));
   1300     EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_HDYC,
   1301                           kWidth, kHeight, &frame4));
   1302     EXPECT_TRUE(IsEqual(frame1, frame2, 0));
   1303     EXPECT_TRUE(IsEqual(frame1, frame3, 0));
   1304     EXPECT_TRUE(IsEqual(frame1, frame4, 0));
   1305   }
   1306 
   1307   // Test creating a copy.
   1308   void ConstructCopy() {
   1309     T frame1, frame2;
   1310     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
   1311     for (int i = 0; i < repeat_; ++i) {
   1312       EXPECT_TRUE(frame2.Init(frame1));
   1313     }
   1314     EXPECT_TRUE(IsEqual(frame1, frame2, 0));
   1315   }
   1316 
   1317   // Test creating a copy and check that it just increments the refcount.
   1318   void ConstructCopyIsRef() {
   1319     T frame1, frame2;
   1320     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
   1321     for (int i = 0; i < repeat_; ++i) {
   1322       EXPECT_TRUE(frame2.Init(frame1));
   1323     }
   1324     EXPECT_TRUE(IsEqual(frame1, frame2, 0));
   1325     EXPECT_EQ(frame1.GetYPlane(), frame2.GetYPlane());
   1326     EXPECT_EQ(frame1.GetUPlane(), frame2.GetUPlane());
   1327     EXPECT_EQ(frame1.GetVPlane(), frame2.GetVPlane());
   1328   }
   1329 
   1330   // Test creating an empty image and initing it to black.
   1331   void ConstructBlack() {
   1332     T frame;
   1333     for (int i = 0; i < repeat_; ++i) {
   1334       EXPECT_TRUE(frame.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
   1335     }
   1336     EXPECT_TRUE(IsSize(frame, kWidth, kHeight));
   1337     EXPECT_TRUE(IsBlack(frame));
   1338   }
   1339 
   1340   // Test constructing an image from a YUY2 buffer with a range of sizes.
   1341   // Only tests that conversion does not crash or corrupt heap.
   1342   void ConstructYuy2AllSizes() {
   1343     T frame1, frame2;
   1344     for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
   1345       for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
   1346         talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   1347             CreateYuv422Sample(cricket::FOURCC_YUY2, width, height));
   1348         ASSERT_TRUE(ms.get() != NULL);
   1349         EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, width, height,
   1350                                   &frame1));
   1351         EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
   1352                               width, height, &frame2));
   1353         EXPECT_TRUE(IsEqual(frame1, frame2, 0));
   1354       }
   1355     }
   1356   }
   1357 
   1358   // Test constructing an image from a ARGB buffer with a range of sizes.
   1359   // Only tests that conversion does not crash or corrupt heap.
   1360   void ConstructARGBAllSizes() {
   1361     T frame1, frame2;
   1362     for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
   1363       for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
   1364         talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   1365             CreateRgbSample(cricket::FOURCC_ARGB, width, height));
   1366         ASSERT_TRUE(ms.get() != NULL);
   1367         EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, width, height,
   1368                                &frame1));
   1369         EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
   1370                               width, height, &frame2));
   1371         EXPECT_TRUE(IsEqual(frame1, frame2, 64));
   1372       }
   1373     }
   1374     // Test a practical window size for screencasting usecase.
   1375     const int kOddWidth = 1228;
   1376     const int kOddHeight = 260;
   1377     for (int j = 0; j < 2; ++j) {
   1378       for (int i = 0; i < 2; ++i) {
   1379         talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   1380         CreateRgbSample(cricket::FOURCC_ARGB, kOddWidth + i, kOddHeight + j));
   1381         ASSERT_TRUE(ms.get() != NULL);
   1382         EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
   1383                                kOddWidth + i, kOddHeight + j,
   1384                                &frame1));
   1385         EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
   1386                               kOddWidth + i, kOddHeight + j, &frame2));
   1387         EXPECT_TRUE(IsEqual(frame1, frame2, 64));
   1388       }
   1389     }
   1390   }
   1391 
   1392   // Tests re-initing an existing image.
   1393   void Reset() {
   1394     T frame1, frame2;
   1395     talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   1396         LoadSample(kImageFilename));
   1397     ASSERT_TRUE(ms.get() != NULL);
   1398     size_t data_size;
   1399     ms->GetSize(&data_size);
   1400     EXPECT_TRUE(frame1.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
   1401     EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
   1402     EXPECT_TRUE(IsBlack(frame1));
   1403     EXPECT_TRUE(IsEqual(frame1, frame2, 0));
   1404     EXPECT_TRUE(frame1.Reset(cricket::FOURCC_I420,
   1405                              kWidth, kHeight, kWidth, kHeight,
   1406                              reinterpret_cast<uint8*>(ms->GetBuffer()),
   1407                              data_size, 1, 1, 0, 0, 0));
   1408     EXPECT_FALSE(IsBlack(frame1));
   1409     EXPECT_FALSE(IsEqual(frame1, frame2, 0));
   1410   }
   1411 
   1412   //////////////////////
   1413   // Conversion tests //
   1414   //////////////////////
   1415 
   1416   enum ToFrom { TO, FROM };
   1417 
   1418   // Helper function for test converting from I420 to packed formats.
   1419   inline void ConvertToBuffer(int bpp, int rowpad, bool invert, ToFrom to_from,
   1420       int error, uint32 fourcc,
   1421       int (*RGBToI420)(const uint8* src_frame, int src_stride_frame,
   1422                        uint8* dst_y, int dst_stride_y,
   1423                        uint8* dst_u, int dst_stride_u,
   1424                        uint8* dst_v, int dst_stride_v,
   1425                        int width, int height)) {
   1426     T frame1, frame2;
   1427     int repeat_to = (to_from == TO) ? repeat_ : 1;
   1428     int repeat_from  = (to_from == FROM) ? repeat_ : 1;
   1429 
   1430     int astride = kWidth * bpp + rowpad;
   1431     size_t out_size = astride * kHeight;
   1432     talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment + 1]);
   1433     memset(outbuf.get(), 0, out_size + kAlignment + 1);
   1434     uint8 *outtop = ALIGNP(outbuf.get(), kAlignment);
   1435     uint8 *out = outtop;
   1436     int stride = astride;
   1437     if (invert) {
   1438       out += (kHeight - 1) * stride;  // Point to last row.
   1439       stride = -stride;
   1440     }
   1441     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
   1442 
   1443     for (int i = 0; i < repeat_to; ++i) {
   1444       EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(fourcc,
   1445                                                     out,
   1446                                                     out_size, stride));
   1447     }
   1448     EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
   1449     for (int i = 0; i < repeat_from; ++i) {
   1450       EXPECT_EQ(0, RGBToI420(out, stride,
   1451                              frame2.GetYPlane(), frame2.GetYPitch(),
   1452                              frame2.GetUPlane(), frame2.GetUPitch(),
   1453                              frame2.GetVPlane(), frame2.GetVPitch(),
   1454                              kWidth, kHeight));
   1455     }
   1456     if (rowpad) {
   1457       EXPECT_EQ(0, outtop[kWidth * bpp]);  // Ensure stride skipped end of row.
   1458       EXPECT_NE(0, outtop[astride]);       // Ensure pixel at start of 2nd row.
   1459     } else {
   1460       EXPECT_NE(0, outtop[kWidth * bpp]);  // Expect something to be here.
   1461     }
   1462     EXPECT_EQ(0, outtop[out_size]);      // Ensure no overrun.
   1463     EXPECT_TRUE(IsEqual(frame1, frame2, error));
   1464   }
   1465 
   1466   static const int kError = 20;
   1467   static const int kErrorHigh = 40;
   1468   static const int kOddStride = 23;
   1469 
   1470   // Tests ConvertToRGBBuffer formats.
   1471   void ConvertToARGBBuffer() {
   1472     ConvertToBuffer(4, 0, false, TO, kError,
   1473                     cricket::FOURCC_ARGB, libyuv::ARGBToI420);
   1474   }
   1475   void ConvertToBGRABuffer() {
   1476     ConvertToBuffer(4, 0, false, TO, kError,
   1477                     cricket::FOURCC_BGRA, libyuv::BGRAToI420);
   1478   }
   1479   void ConvertToABGRBuffer() {
   1480     ConvertToBuffer(4, 0, false, TO, kError,
   1481                     cricket::FOURCC_ABGR, libyuv::ABGRToI420);
   1482   }
   1483   void ConvertToRGB24Buffer() {
   1484     ConvertToBuffer(3, 0, false, TO, kError,
   1485                     cricket::FOURCC_24BG, libyuv::RGB24ToI420);
   1486   }
   1487   void ConvertToRAWBuffer() {
   1488     ConvertToBuffer(3, 0, false, TO, kError,
   1489                     cricket::FOURCC_RAW, libyuv::RAWToI420);
   1490   }
   1491   void ConvertToRGB565Buffer() {
   1492     ConvertToBuffer(2, 0, false, TO, kError,
   1493                     cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
   1494   }
   1495   void ConvertToARGB1555Buffer() {
   1496     ConvertToBuffer(2, 0, false, TO, kError,
   1497                     cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
   1498   }
   1499   void ConvertToARGB4444Buffer() {
   1500     ConvertToBuffer(2, 0, false, TO, kError,
   1501                     cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
   1502   }
   1503   void ConvertToBayerBGGRBuffer() {
   1504     ConvertToBuffer(1, 0, false, TO, kErrorHigh,
   1505                     cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
   1506   }
   1507   void ConvertToBayerGBRGBuffer() {
   1508     ConvertToBuffer(1, 0, false, TO, kErrorHigh,
   1509                     cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
   1510   }
   1511   void ConvertToBayerGRBGBuffer() {
   1512     ConvertToBuffer(1, 0, false, TO, kErrorHigh,
   1513                     cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
   1514   }
   1515   void ConvertToBayerRGGBBuffer() {
   1516     ConvertToBuffer(1, 0, false, TO, kErrorHigh,
   1517                     cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
   1518   }
   1519   void ConvertToI400Buffer() {
   1520     ConvertToBuffer(1, 0, false, TO, 128,
   1521                     cricket::FOURCC_I400, libyuv::I400ToI420);
   1522   }
   1523   void ConvertToYUY2Buffer() {
   1524     ConvertToBuffer(2, 0, false, TO, kError,
   1525                     cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
   1526   }
   1527   void ConvertToUYVYBuffer() {
   1528     ConvertToBuffer(2, 0, false, TO, kError,
   1529                     cricket::FOURCC_UYVY, libyuv::UYVYToI420);
   1530   }
   1531 
   1532   // Tests ConvertToRGBBuffer formats with odd stride.
   1533   void ConvertToARGBBufferStride() {
   1534     ConvertToBuffer(4, kOddStride, false, TO, kError,
   1535                     cricket::FOURCC_ARGB, libyuv::ARGBToI420);
   1536   }
   1537   void ConvertToBGRABufferStride() {
   1538     ConvertToBuffer(4, kOddStride, false, TO, kError,
   1539                     cricket::FOURCC_BGRA, libyuv::BGRAToI420);
   1540   }
   1541   void ConvertToABGRBufferStride() {
   1542     ConvertToBuffer(4, kOddStride, false, TO, kError,
   1543                     cricket::FOURCC_ABGR, libyuv::ABGRToI420);
   1544   }
   1545   void ConvertToRGB24BufferStride() {
   1546     ConvertToBuffer(3, kOddStride, false, TO, kError,
   1547                     cricket::FOURCC_24BG, libyuv::RGB24ToI420);
   1548   }
   1549   void ConvertToRAWBufferStride() {
   1550     ConvertToBuffer(3, kOddStride, false, TO, kError,
   1551                     cricket::FOURCC_RAW, libyuv::RAWToI420);
   1552   }
   1553   void ConvertToRGB565BufferStride() {
   1554     ConvertToBuffer(2, kOddStride, false, TO, kError,
   1555                     cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
   1556   }
   1557   void ConvertToARGB1555BufferStride() {
   1558     ConvertToBuffer(2, kOddStride, false, TO, kError,
   1559                     cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
   1560   }
   1561   void ConvertToARGB4444BufferStride() {
   1562     ConvertToBuffer(2, kOddStride, false, TO, kError,
   1563                     cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
   1564   }
   1565   void ConvertToBayerBGGRBufferStride() {
   1566     ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
   1567                     cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
   1568   }
   1569   void ConvertToBayerGBRGBufferStride() {
   1570     ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
   1571                     cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
   1572   }
   1573   void ConvertToBayerGRBGBufferStride() {
   1574     ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
   1575                     cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
   1576   }
   1577   void ConvertToBayerRGGBBufferStride() {
   1578     ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
   1579                     cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
   1580   }
   1581   void ConvertToI400BufferStride() {
   1582     ConvertToBuffer(1, kOddStride, false, TO, 128,
   1583                     cricket::FOURCC_I400, libyuv::I400ToI420);
   1584   }
   1585   void ConvertToYUY2BufferStride() {
   1586     ConvertToBuffer(2, kOddStride, false, TO, kError,
   1587                     cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
   1588   }
   1589   void ConvertToUYVYBufferStride() {
   1590     ConvertToBuffer(2, kOddStride, false, TO, kError,
   1591                     cricket::FOURCC_UYVY, libyuv::UYVYToI420);
   1592   }
   1593 
   1594   // Tests ConvertToRGBBuffer formats with negative stride to invert image.
   1595   void ConvertToARGBBufferInverted() {
   1596     ConvertToBuffer(4, 0, true, TO, kError,
   1597                     cricket::FOURCC_ARGB, libyuv::ARGBToI420);
   1598   }
   1599   void ConvertToBGRABufferInverted() {
   1600     ConvertToBuffer(4, 0, true, TO, kError,
   1601                     cricket::FOURCC_BGRA, libyuv::BGRAToI420);
   1602   }
   1603   void ConvertToABGRBufferInverted() {
   1604     ConvertToBuffer(4, 0, true, TO, kError,
   1605                     cricket::FOURCC_ABGR, libyuv::ABGRToI420);
   1606   }
   1607   void ConvertToRGB24BufferInverted() {
   1608     ConvertToBuffer(3, 0, true, TO, kError,
   1609                     cricket::FOURCC_24BG, libyuv::RGB24ToI420);
   1610   }
   1611   void ConvertToRAWBufferInverted() {
   1612     ConvertToBuffer(3, 0, true, TO, kError,
   1613                     cricket::FOURCC_RAW, libyuv::RAWToI420);
   1614   }
   1615   void ConvertToRGB565BufferInverted() {
   1616     ConvertToBuffer(2, 0, true, TO, kError,
   1617                     cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
   1618   }
   1619   void ConvertToARGB1555BufferInverted() {
   1620     ConvertToBuffer(2, 0, true, TO, kError,
   1621                     cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
   1622   }
   1623   void ConvertToARGB4444BufferInverted() {
   1624     ConvertToBuffer(2, 0, true, TO, kError,
   1625                     cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
   1626   }
   1627   void ConvertToBayerBGGRBufferInverted() {
   1628     ConvertToBuffer(1, 0, true, TO, kErrorHigh,
   1629                     cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
   1630   }
   1631   void ConvertToBayerGBRGBufferInverted() {
   1632     ConvertToBuffer(1, 0, true, TO, kErrorHigh,
   1633                     cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
   1634   }
   1635   void ConvertToBayerGRBGBufferInverted() {
   1636     ConvertToBuffer(1, 0, true, TO, kErrorHigh,
   1637                     cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
   1638   }
   1639   void ConvertToBayerRGGBBufferInverted() {
   1640     ConvertToBuffer(1, 0, true, TO, kErrorHigh,
   1641                     cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
   1642   }
   1643   void ConvertToI400BufferInverted() {
   1644     ConvertToBuffer(1, 0, true, TO, 128,
   1645                     cricket::FOURCC_I400, libyuv::I400ToI420);
   1646   }
   1647   void ConvertToYUY2BufferInverted() {
   1648     ConvertToBuffer(2, 0, true, TO, kError,
   1649                     cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
   1650   }
   1651   void ConvertToUYVYBufferInverted() {
   1652     ConvertToBuffer(2, 0, true, TO, kError,
   1653                     cricket::FOURCC_UYVY, libyuv::UYVYToI420);
   1654   }
   1655 
   1656   // Tests ConvertFrom formats.
   1657   void ConvertFromARGBBuffer() {
   1658     ConvertToBuffer(4, 0, false, FROM, kError,
   1659                     cricket::FOURCC_ARGB, libyuv::ARGBToI420);
   1660   }
   1661   void ConvertFromBGRABuffer() {
   1662     ConvertToBuffer(4, 0, false, FROM, kError,
   1663                     cricket::FOURCC_BGRA, libyuv::BGRAToI420);
   1664   }
   1665   void ConvertFromABGRBuffer() {
   1666     ConvertToBuffer(4, 0, false, FROM, kError,
   1667                     cricket::FOURCC_ABGR, libyuv::ABGRToI420);
   1668   }
   1669   void ConvertFromRGB24Buffer() {
   1670     ConvertToBuffer(3, 0, false, FROM, kError,
   1671                     cricket::FOURCC_24BG, libyuv::RGB24ToI420);
   1672   }
   1673   void ConvertFromRAWBuffer() {
   1674     ConvertToBuffer(3, 0, false, FROM, kError,
   1675                     cricket::FOURCC_RAW, libyuv::RAWToI420);
   1676   }
   1677   void ConvertFromRGB565Buffer() {
   1678     ConvertToBuffer(2, 0, false, FROM, kError,
   1679                     cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
   1680   }
   1681   void ConvertFromARGB1555Buffer() {
   1682     ConvertToBuffer(2, 0, false, FROM, kError,
   1683                     cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
   1684   }
   1685   void ConvertFromARGB4444Buffer() {
   1686     ConvertToBuffer(2, 0, false, FROM, kError,
   1687                     cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
   1688   }
   1689   void ConvertFromBayerBGGRBuffer() {
   1690     ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
   1691                     cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
   1692   }
   1693   void ConvertFromBayerGBRGBuffer() {
   1694     ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
   1695                     cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
   1696   }
   1697   void ConvertFromBayerGRBGBuffer() {
   1698     ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
   1699                     cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
   1700   }
   1701   void ConvertFromBayerRGGBBuffer() {
   1702     ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
   1703                     cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
   1704   }
   1705   void ConvertFromI400Buffer() {
   1706     ConvertToBuffer(1, 0, false, FROM, 128,
   1707                     cricket::FOURCC_I400, libyuv::I400ToI420);
   1708   }
   1709   void ConvertFromYUY2Buffer() {
   1710     ConvertToBuffer(2, 0, false, FROM, kError,
   1711                     cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
   1712   }
   1713   void ConvertFromUYVYBuffer() {
   1714     ConvertToBuffer(2, 0, false, FROM, kError,
   1715                     cricket::FOURCC_UYVY, libyuv::UYVYToI420);
   1716   }
   1717 
   1718   // Tests ConvertFrom formats with odd stride.
   1719   void ConvertFromARGBBufferStride() {
   1720     ConvertToBuffer(4, kOddStride, false, FROM, kError,
   1721                     cricket::FOURCC_ARGB, libyuv::ARGBToI420);
   1722   }
   1723   void ConvertFromBGRABufferStride() {
   1724     ConvertToBuffer(4, kOddStride, false, FROM, kError,
   1725                     cricket::FOURCC_BGRA, libyuv::BGRAToI420);
   1726   }
   1727   void ConvertFromABGRBufferStride() {
   1728     ConvertToBuffer(4, kOddStride, false, FROM, kError,
   1729                     cricket::FOURCC_ABGR, libyuv::ABGRToI420);
   1730   }
   1731   void ConvertFromRGB24BufferStride() {
   1732     ConvertToBuffer(3, kOddStride, false, FROM, kError,
   1733                     cricket::FOURCC_24BG, libyuv::RGB24ToI420);
   1734   }
   1735   void ConvertFromRAWBufferStride() {
   1736     ConvertToBuffer(3, kOddStride, false, FROM, kError,
   1737                     cricket::FOURCC_RAW, libyuv::RAWToI420);
   1738   }
   1739   void ConvertFromRGB565BufferStride() {
   1740     ConvertToBuffer(2, kOddStride, false, FROM, kError,
   1741                     cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
   1742   }
   1743   void ConvertFromARGB1555BufferStride() {
   1744     ConvertToBuffer(2, kOddStride, false, FROM, kError,
   1745                     cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
   1746   }
   1747   void ConvertFromARGB4444BufferStride() {
   1748     ConvertToBuffer(2, kOddStride, false, FROM, kError,
   1749                     cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
   1750   }
   1751   void ConvertFromBayerBGGRBufferStride() {
   1752     ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
   1753                     cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
   1754   }
   1755   void ConvertFromBayerGBRGBufferStride() {
   1756     ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
   1757                     cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
   1758   }
   1759   void ConvertFromBayerGRBGBufferStride() {
   1760     ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
   1761                     cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
   1762   }
   1763   void ConvertFromBayerRGGBBufferStride() {
   1764     ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
   1765                     cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
   1766   }
   1767   void ConvertFromI400BufferStride() {
   1768     ConvertToBuffer(1, kOddStride, false, FROM, 128,
   1769                     cricket::FOURCC_I400, libyuv::I400ToI420);
   1770   }
   1771   void ConvertFromYUY2BufferStride() {
   1772     ConvertToBuffer(2, kOddStride, false, FROM, kError,
   1773                     cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
   1774   }
   1775   void ConvertFromUYVYBufferStride() {
   1776     ConvertToBuffer(2, kOddStride, false, FROM, kError,
   1777                     cricket::FOURCC_UYVY, libyuv::UYVYToI420);
   1778   }
   1779 
   1780   // Tests ConvertFrom formats with negative stride to invert image.
   1781   void ConvertFromARGBBufferInverted() {
   1782     ConvertToBuffer(4, 0, true, FROM, kError,
   1783                     cricket::FOURCC_ARGB, libyuv::ARGBToI420);
   1784   }
   1785   void ConvertFromBGRABufferInverted() {
   1786     ConvertToBuffer(4, 0, true, FROM, kError,
   1787                     cricket::FOURCC_BGRA, libyuv::BGRAToI420);
   1788   }
   1789   void ConvertFromABGRBufferInverted() {
   1790     ConvertToBuffer(4, 0, true, FROM, kError,
   1791                     cricket::FOURCC_ABGR, libyuv::ABGRToI420);
   1792   }
   1793   void ConvertFromRGB24BufferInverted() {
   1794     ConvertToBuffer(3, 0, true, FROM, kError,
   1795                     cricket::FOURCC_24BG, libyuv::RGB24ToI420);
   1796   }
   1797   void ConvertFromRAWBufferInverted() {
   1798     ConvertToBuffer(3, 0, true, FROM, kError,
   1799                     cricket::FOURCC_RAW, libyuv::RAWToI420);
   1800   }
   1801   void ConvertFromRGB565BufferInverted() {
   1802     ConvertToBuffer(2, 0, true, FROM, kError,
   1803                     cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
   1804   }
   1805   void ConvertFromARGB1555BufferInverted() {
   1806     ConvertToBuffer(2, 0, true, FROM, kError,
   1807                     cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
   1808   }
   1809   void ConvertFromARGB4444BufferInverted() {
   1810     ConvertToBuffer(2, 0, true, FROM, kError,
   1811                     cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
   1812   }
   1813   void ConvertFromBayerBGGRBufferInverted() {
   1814     ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
   1815                     cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
   1816   }
   1817   void ConvertFromBayerGBRGBufferInverted() {
   1818     ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
   1819                     cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
   1820   }
   1821   void ConvertFromBayerGRBGBufferInverted() {
   1822     ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
   1823                     cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
   1824   }
   1825   void ConvertFromBayerRGGBBufferInverted() {
   1826     ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
   1827                     cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
   1828   }
   1829   void ConvertFromI400BufferInverted() {
   1830     ConvertToBuffer(1, 0, true, FROM, 128,
   1831                     cricket::FOURCC_I400, libyuv::I400ToI420);
   1832   }
   1833   void ConvertFromYUY2BufferInverted() {
   1834     ConvertToBuffer(2, 0, true, FROM, kError,
   1835                     cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
   1836   }
   1837   void ConvertFromUYVYBufferInverted() {
   1838     ConvertToBuffer(2, 0, true, FROM, kError,
   1839                     cricket::FOURCC_UYVY, libyuv::UYVYToI420);
   1840   }
   1841 
   1842   // Test converting from I420 to I422.
   1843   void ConvertToI422Buffer() {
   1844     T frame1, frame2;
   1845     size_t out_size = kWidth * kHeight * 2;
   1846     talk_base::scoped_ptr<uint8[]> buf(new uint8[out_size + kAlignment]);
   1847     uint8* y = ALIGNP(buf.get(), kAlignment);
   1848     uint8* u = y + kWidth * kHeight;
   1849     uint8* v = u + (kWidth / 2) * kHeight;
   1850     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
   1851     for (int i = 0; i < repeat_; ++i) {
   1852       EXPECT_EQ(0, libyuv::I420ToI422(frame1.GetYPlane(), frame1.GetYPitch(),
   1853                                       frame1.GetUPlane(), frame1.GetUPitch(),
   1854                                       frame1.GetVPlane(), frame1.GetVPitch(),
   1855                                       y, kWidth,
   1856                                       u, kWidth / 2,
   1857                                       v, kWidth / 2,
   1858                                       kWidth, kHeight));
   1859     }
   1860     EXPECT_TRUE(frame2.Init(cricket::FOURCC_I422,
   1861                             kWidth, kHeight, kWidth, kHeight,
   1862                             y,
   1863                             out_size,  1, 1, 0, 0, cricket::ROTATION_0));
   1864     EXPECT_TRUE(IsEqual(frame1, frame2, 1));
   1865   }
   1866 
   1867   #define TEST_TOBYR(NAME, BAYER)                                              \
   1868   void NAME() {                                                                \
   1869     size_t bayer_size = kWidth * kHeight;                                      \
   1870     talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[                         \
   1871         bayer_size + kAlignment]);                                             \
   1872     uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment);                         \
   1873     T frame;                                                                   \
   1874     talk_base::scoped_ptr<talk_base::MemoryStream> ms(                         \
   1875         CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));               \
   1876     ASSERT_TRUE(ms.get() != NULL);                                             \
   1877     for (int i = 0; i < repeat_; ++i) {                                        \
   1878       libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()),    \
   1879                                  kWidth * 4,                                   \
   1880                                  bayer, kWidth,                                \
   1881                                  kWidth, kHeight);                             \
   1882     }                                                                          \
   1883     talk_base::scoped_ptr<talk_base::MemoryStream> ms2(                        \
   1884         CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));               \
   1885     size_t data_size;                                                          \
   1886     bool ret = ms2->GetSize(&data_size);                                       \
   1887     EXPECT_TRUE(ret);                                                          \
   1888     libyuv::Bayer##BAYER##ToARGB(bayer, kWidth,                                \
   1889                                  reinterpret_cast<uint8*>(ms2->GetBuffer()),   \
   1890                                  kWidth * 4,                                   \
   1891                                  kWidth, kHeight);                             \
   1892     EXPECT_TRUE(IsPlaneEqual("argb",                                           \
   1893         reinterpret_cast<uint8*>(ms->GetBuffer()), kWidth * 4,                 \
   1894         reinterpret_cast<uint8*>(ms2->GetBuffer()), kWidth * 4,                \
   1895         kWidth * 4, kHeight, 240));                                            \
   1896   }                                                                            \
   1897   void NAME##Unaligned() {                                                     \
   1898     size_t bayer_size = kWidth * kHeight;                                      \
   1899     talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[                         \
   1900         bayer_size + 1 + kAlignment]);                                         \
   1901     uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment) + 1;                     \
   1902     T frame;                                                                   \
   1903     talk_base::scoped_ptr<talk_base::MemoryStream> ms(                         \
   1904         CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));               \
   1905     ASSERT_TRUE(ms.get() != NULL);                                             \
   1906     for (int i = 0; i < repeat_; ++i) {                                        \
   1907       libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()),    \
   1908                                  kWidth * 4,                                   \
   1909                                  bayer, kWidth,                                \
   1910                                  kWidth, kHeight);                             \
   1911     }                                                                          \
   1912     talk_base::scoped_ptr<talk_base::MemoryStream> ms2(                        \
   1913         CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));               \
   1914     size_t data_size;                                                          \
   1915     bool ret = ms2->GetSize(&data_size);                                       \
   1916     EXPECT_TRUE(ret);                                                          \
   1917     libyuv::Bayer##BAYER##ToARGB(bayer, kWidth,                                \
   1918                            reinterpret_cast<uint8*>(ms2->GetBuffer()),         \
   1919                            kWidth * 4,                                         \
   1920                            kWidth, kHeight);                                   \
   1921     EXPECT_TRUE(IsPlaneEqual("argb",                                           \
   1922         reinterpret_cast<uint8*>(ms->GetBuffer()), kWidth * 4,                 \
   1923         reinterpret_cast<uint8*>(ms2->GetBuffer()), kWidth * 4,                \
   1924         kWidth * 4, kHeight, 240));                                            \
   1925   }
   1926 
   1927   // Tests ARGB to Bayer formats.
   1928   TEST_TOBYR(ConvertARGBToBayerGRBG, GRBG)
   1929   TEST_TOBYR(ConvertARGBToBayerGBRG, GBRG)
   1930   TEST_TOBYR(ConvertARGBToBayerBGGR, BGGR)
   1931   TEST_TOBYR(ConvertARGBToBayerRGGB, RGGB)
   1932 
   1933   #define TEST_BYRTORGB(NAME, BAYER)                                           \
   1934   void NAME() {                                                                \
   1935     size_t bayer_size = kWidth * kHeight;                                      \
   1936     talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[                         \
   1937         bayer_size + kAlignment]);                                             \
   1938     uint8 *bayer1 = ALIGNP(bayerbuf.get(), kAlignment);                        \
   1939     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
   1940       bayer1[i] = static_cast<uint8>(i * 33u + 183u);                          \
   1941     }                                                                          \
   1942     T frame;                                                                   \
   1943     talk_base::scoped_ptr<talk_base::MemoryStream> ms(                         \
   1944         CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));               \
   1945     ASSERT_TRUE(ms.get() != NULL);                                             \
   1946     for (int i = 0; i < repeat_; ++i) {                                        \
   1947       libyuv::Bayer##BAYER##ToARGB(bayer1, kWidth,                             \
   1948                              reinterpret_cast<uint8*>(ms->GetBuffer()),        \
   1949                              kWidth * 4,                                       \
   1950                              kWidth, kHeight);                                 \
   1951     }                                                                          \
   1952     talk_base::scoped_ptr<uint8[]> bayer2buf(new uint8[                        \
   1953         bayer_size + kAlignment]);                                             \
   1954     uint8 *bayer2 = ALIGNP(bayer2buf.get(), kAlignment);                       \
   1955     libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()),      \
   1956                            kWidth * 4,                                         \
   1957                            bayer2, kWidth,                                     \
   1958                            kWidth, kHeight);                                   \
   1959     EXPECT_TRUE(IsPlaneEqual("bayer",                                          \
   1960         bayer1, kWidth,                                                        \
   1961         bayer2, kWidth,                                                        \
   1962         kWidth, kHeight, 0));                                                  \
   1963   }
   1964 
   1965   // Tests Bayer formats to ARGB.
   1966   TEST_BYRTORGB(ConvertBayerGRBGToARGB, GRBG)
   1967   TEST_BYRTORGB(ConvertBayerGBRGToARGB, GBRG)
   1968   TEST_BYRTORGB(ConvertBayerBGGRToARGB, BGGR)
   1969   TEST_BYRTORGB(ConvertBayerRGGBToARGB, RGGB)
   1970 
   1971   ///////////////////
   1972   // General tests //
   1973   ///////////////////
   1974 
   1975   void Copy() {
   1976     talk_base::scoped_ptr<T> source(new T);
   1977     talk_base::scoped_ptr<cricket::VideoFrame> target;
   1978     ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
   1979     target.reset(source->Copy());
   1980     EXPECT_TRUE(IsEqual(*source, *target, 0));
   1981     source.reset();
   1982     EXPECT_TRUE(target->GetYPlane() != NULL);
   1983   }
   1984 
   1985   void CopyIsRef() {
   1986     talk_base::scoped_ptr<T> source(new T);
   1987     talk_base::scoped_ptr<cricket::VideoFrame> target;
   1988     ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
   1989     target.reset(source->Copy());
   1990     EXPECT_TRUE(IsEqual(*source, *target, 0));
   1991     EXPECT_EQ(source->GetYPlane(), target->GetYPlane());
   1992     EXPECT_EQ(source->GetUPlane(), target->GetUPlane());
   1993     EXPECT_EQ(source->GetVPlane(), target->GetVPlane());
   1994   }
   1995 
   1996   void MakeExclusive() {
   1997     talk_base::scoped_ptr<T> source(new T);
   1998     talk_base::scoped_ptr<cricket::VideoFrame> target;
   1999     ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
   2000     target.reset(source->Copy());
   2001     EXPECT_TRUE(target->MakeExclusive());
   2002     EXPECT_TRUE(IsEqual(*source, *target, 0));
   2003     EXPECT_NE(target->GetYPlane(), source->GetYPlane());
   2004     EXPECT_NE(target->GetUPlane(), source->GetUPlane());
   2005     EXPECT_NE(target->GetVPlane(), source->GetVPlane());
   2006   }
   2007 
   2008   void CopyToBuffer() {
   2009     T frame;
   2010     talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   2011         LoadSample(kImageFilename));
   2012     ASSERT_TRUE(ms.get() != NULL);
   2013     ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
   2014                           &frame));
   2015     size_t out_size = kWidth * kHeight * 3 / 2;
   2016     talk_base::scoped_ptr<uint8[]> out(new uint8[out_size]);
   2017     for (int i = 0; i < repeat_; ++i) {
   2018       EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
   2019     }
   2020     EXPECT_EQ(0, memcmp(out.get(), ms->GetBuffer(), out_size));
   2021   }
   2022 
   2023   void CopyToFrame() {
   2024     T source;
   2025     talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   2026         LoadSample(kImageFilename));
   2027     ASSERT_TRUE(ms.get() != NULL);
   2028     ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
   2029                           &source));
   2030 
   2031     // Create the target frame by loading from a file.
   2032     T target;
   2033     ASSERT_TRUE(LoadFrameNoRepeat(&target));
   2034     EXPECT_FALSE(IsBlack(target));
   2035 
   2036     // Stretch and check if the stretched target is black.
   2037     source.CopyToFrame(&target);
   2038 
   2039     EXPECT_TRUE(IsEqual(source, target, 0));
   2040   }
   2041 
   2042   void Write() {
   2043     T frame;
   2044     talk_base::scoped_ptr<talk_base::MemoryStream> ms(
   2045         LoadSample(kImageFilename));
   2046     ASSERT_TRUE(ms.get() != NULL);
   2047     talk_base::MemoryStream ms2;
   2048     size_t size;
   2049     ASSERT_TRUE(ms->GetSize(&size));
   2050     ASSERT_TRUE(ms2.ReserveSize(size));
   2051     ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
   2052                           &frame));
   2053     for (int i = 0; i < repeat_; ++i) {
   2054       ms2.SetPosition(0u);  // Useful when repeat_ > 1.
   2055       int error;
   2056       EXPECT_EQ(talk_base::SR_SUCCESS, frame.Write(&ms2, &error));
   2057     }
   2058     size_t out_size = cricket::VideoFrame::SizeOf(kWidth, kHeight);
   2059     EXPECT_EQ(0, memcmp(ms2.GetBuffer(), ms->GetBuffer(), out_size));
   2060   }
   2061 
   2062   void CopyToBuffer1Pixel() {
   2063     size_t out_size = 3;
   2064     talk_base::scoped_ptr<uint8[]> out(new uint8[out_size + 1]);
   2065     memset(out.get(), 0xfb, out_size + 1);  // Fill buffer
   2066     uint8 pixel[3] = { 1, 2, 3 };
   2067     T frame;
   2068     EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1,
   2069                            pixel, sizeof(pixel),
   2070                            1, 1, 0, 0, 0));
   2071     for (int i = 0; i < repeat_; ++i) {
   2072       EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
   2073     }
   2074     EXPECT_EQ(1, out.get()[0]);  // Check Y.  Should be 1.
   2075     EXPECT_EQ(2, out.get()[1]);  // Check U.  Should be 2.
   2076     EXPECT_EQ(3, out.get()[2]);  // Check V.  Should be 3.
   2077     EXPECT_EQ(0xfb, out.get()[3]);  // Check sentinel is still intact.
   2078   }
   2079 
   2080   void StretchToFrame() {
   2081     // Create the source frame as a black frame.
   2082     T source;
   2083     EXPECT_TRUE(source.InitToBlack(kWidth * 2, kHeight * 2, 1, 1, 0, 0));
   2084     EXPECT_TRUE(IsSize(source, kWidth * 2, kHeight * 2));
   2085 
   2086     // Create the target frame by loading from a file.
   2087     T target1;
   2088     ASSERT_TRUE(LoadFrameNoRepeat(&target1));
   2089     EXPECT_FALSE(IsBlack(target1));
   2090 
   2091     // Stretch and check if the stretched target is black.
   2092     source.StretchToFrame(&target1, true, false);
   2093     EXPECT_TRUE(IsBlack(target1));
   2094 
   2095     // Crop and stretch and check if the stretched target is black.
   2096     T target2;
   2097     ASSERT_TRUE(LoadFrameNoRepeat(&target2));
   2098     source.StretchToFrame(&target2, true, true);
   2099     EXPECT_TRUE(IsBlack(target2));
   2100     EXPECT_EQ(source.GetElapsedTime(), target2.GetElapsedTime());
   2101     EXPECT_EQ(source.GetTimeStamp(), target2.GetTimeStamp());
   2102   }
   2103 
   2104   int repeat_;
   2105 };
   2106 
   2107 #endif  // TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_
   2108