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