Home | History | Annotate | Download | only in media
      1 // libjingle
      2 // Copyright 2014 Google Inc.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are met:
      6 //
      7 //  1. Redistributions of source code must retain the above copyright notice,
      8 //     this list of conditions and the following disclaimer.
      9 //  2. Redistributions in binary form must reproduce the above copyright notice,
     10 //     this list of conditions and the following disclaimer in the documentation
     11 //     and/or other materials provided with the distribution.
     12 //  3. The name of the author may not be used to endorse or promote products
     13 //     derived from this software without specific prior written permission.
     14 //
     15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25 
     26 #include <string>
     27 
     28 #include "libyuv/convert.h"
     29 #include "libyuv/convert_from.h"
     30 #include "libyuv/convert_from_argb.h"
     31 #include "libyuv/format_conversion.h"
     32 #include "libyuv/mjpeg_decoder.h"
     33 #include "libyuv/planar_functions.h"
     34 #include "talk/media/base/testutils.h"
     35 #include "talk/media/base/videocommon.h"
     36 #include "webrtc/base/flags.h"
     37 #include "webrtc/base/gunit.h"
     38 #include "webrtc/base/scoped_ptr.h"
     39 
     40 // Undefine macros for the windows build.
     41 #undef max
     42 #undef min
     43 
     44 using cricket::DumpPlanarYuvTestImage;
     45 
     46 DEFINE_bool(planarfunctions_dump, false,
     47     "whether to write out scaled images for inspection");
     48 DEFINE_int(planarfunctions_repeat, 1,
     49     "how many times to perform each scaling operation (for perf testing)");
     50 
     51 namespace cricket {
     52 
     53 // Number of testing colors in each color channel.
     54 static const int kTestingColorChannelResolution = 6;
     55 
     56 // The total number of testing colors
     57 // kTestingColorNum = kTestingColorChannelResolution^3;
     58 static const int kTestingColorNum = kTestingColorChannelResolution *
     59     kTestingColorChannelResolution * kTestingColorChannelResolution;
     60 
     61 static const int kWidth = 1280;
     62 static const int kHeight = 720;
     63 static const int kAlignment = 16;
     64 
     65 class PlanarFunctionsTest : public testing::TestWithParam<int> {
     66  protected:
     67   PlanarFunctionsTest() : dump_(false), repeat_(1) {
     68     InitializeColorBand();
     69   }
     70 
     71   virtual void SetUp() {
     72     dump_ = FLAG_planarfunctions_dump;
     73     repeat_ = FLAG_planarfunctions_repeat;
     74   }
     75 
     76   // Initialize the color band for testing.
     77   void InitializeColorBand() {
     78     testing_color_y_.reset(new uint8[kTestingColorNum]);
     79     testing_color_u_.reset(new uint8[kTestingColorNum]);
     80     testing_color_v_.reset(new uint8[kTestingColorNum]);
     81     testing_color_r_.reset(new uint8[kTestingColorNum]);
     82     testing_color_g_.reset(new uint8[kTestingColorNum]);
     83     testing_color_b_.reset(new uint8[kTestingColorNum]);
     84     int color_counter = 0;
     85     for (int i = 0; i < kTestingColorChannelResolution; ++i) {
     86       uint8 color_r = static_cast<uint8>(
     87           i * 255 / (kTestingColorChannelResolution - 1));
     88       for (int j = 0; j < kTestingColorChannelResolution; ++j) {
     89         uint8 color_g = static_cast<uint8>(
     90             j * 255 / (kTestingColorChannelResolution - 1));
     91         for (int k = 0; k < kTestingColorChannelResolution; ++k) {
     92           uint8 color_b = static_cast<uint8>(
     93               k * 255 / (kTestingColorChannelResolution - 1));
     94           testing_color_r_[color_counter] = color_r;
     95           testing_color_g_[color_counter] = color_g;
     96           testing_color_b_[color_counter] = color_b;
     97            // Converting the testing RGB colors to YUV colors.
     98           ConvertRgbPixel(color_r, color_g, color_b,
     99                           &(testing_color_y_[color_counter]),
    100                           &(testing_color_u_[color_counter]),
    101                           &(testing_color_v_[color_counter]));
    102           ++color_counter;
    103         }
    104       }
    105     }
    106   }
    107   // Simple and slow RGB->YUV conversion. From NTSC standard, c/o Wikipedia.
    108   // (from lmivideoframe_unittest.cc)
    109   void ConvertRgbPixel(uint8 r, uint8 g, uint8 b,
    110                        uint8* y, uint8* u, uint8* v) {
    111     *y = ClampUint8(.257 * r + .504 * g + .098 * b + 16);
    112     *u = ClampUint8(-.148 * r - .291 * g + .439 * b + 128);
    113     *v = ClampUint8(.439 * r - .368 * g - .071 * b + 128);
    114   }
    115 
    116   uint8 ClampUint8(double value) {
    117     value = std::max(0., std::min(255., value));
    118     uint8 uint8_value = static_cast<uint8>(value);
    119     return uint8_value;
    120   }
    121 
    122   // Generate a Red-Green-Blue inter-weaving chessboard-like
    123   // YUV testing image (I420/I422/I444).
    124   // The pattern looks like c0 c1 c2 c3 ...
    125   //                        c1 c2 c3 c4 ...
    126   //                        c2 c3 c4 c5 ...
    127   //                        ...............
    128   // The size of each chrome block is (block_size) x (block_size).
    129   uint8* CreateFakeYuvTestingImage(int height, int width, int block_size,
    130                                    libyuv::JpegSubsamplingType subsample_type,
    131                                    uint8* &y_pointer,
    132                                    uint8* &u_pointer,
    133                                    uint8* &v_pointer) {
    134     if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
    135     int y_size = height * width;
    136     int u_size, v_size;
    137     int vertical_sample_ratio = 1, horizontal_sample_ratio = 1;
    138     switch (subsample_type) {
    139       case libyuv::kJpegYuv420:
    140         u_size = ((height + 1) >> 1) * ((width + 1) >> 1);
    141         v_size = u_size;
    142         vertical_sample_ratio = 2, horizontal_sample_ratio = 2;
    143         break;
    144       case libyuv::kJpegYuv422:
    145         u_size = height * ((width + 1) >> 1);
    146         v_size = u_size;
    147         vertical_sample_ratio = 1, horizontal_sample_ratio = 2;
    148         break;
    149       case libyuv::kJpegYuv444:
    150         v_size = u_size = y_size;
    151         vertical_sample_ratio = 1, horizontal_sample_ratio = 1;
    152         break;
    153       case libyuv::kJpegUnknown:
    154       default:
    155         return NULL;
    156         break;
    157     }
    158     uint8* image_pointer = new uint8[y_size + u_size + v_size + kAlignment];
    159     y_pointer = ALIGNP(image_pointer, kAlignment);
    160     u_pointer = ALIGNP(&image_pointer[y_size], kAlignment);
    161     v_pointer = ALIGNP(&image_pointer[y_size + u_size], kAlignment);
    162     uint8* current_y_pointer = y_pointer;
    163     uint8* current_u_pointer = u_pointer;
    164     uint8* current_v_pointer = v_pointer;
    165     for (int j = 0; j < height; ++j) {
    166       for (int i = 0; i < width; ++i) {
    167         int color = ((i / block_size) + (j / block_size)) % kTestingColorNum;
    168         *(current_y_pointer++) = testing_color_y_[color];
    169         if (i % horizontal_sample_ratio == 0 &&
    170             j % vertical_sample_ratio == 0) {
    171           *(current_u_pointer++) = testing_color_u_[color];
    172           *(current_v_pointer++) = testing_color_v_[color];
    173         }
    174       }
    175     }
    176     return image_pointer;
    177   }
    178 
    179   // Generate a Red-Green-Blue inter-weaving chessboard-like
    180   // YUY2/UYVY testing image.
    181   // The pattern looks like c0 c1 c2 c3 ...
    182   //                        c1 c2 c3 c4 ...
    183   //                        c2 c3 c4 c5 ...
    184   //                        ...............
    185   // The size of each chrome block is (block_size) x (block_size).
    186   uint8* CreateFakeInterleaveYuvTestingImage(
    187       int height, int width, int block_size,
    188       uint8* &yuv_pointer, FourCC fourcc_type) {
    189     if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
    190     if (fourcc_type != FOURCC_YUY2 && fourcc_type != FOURCC_UYVY) {
    191       LOG(LS_ERROR) << "Format " << static_cast<int>(fourcc_type)
    192                     << " is not supported.";
    193       return NULL;
    194     }
    195     // Regularize the width of the output to be even.
    196     int awidth = (width + 1) & ~1;
    197 
    198     uint8* image_pointer = new uint8[2 * height * awidth + kAlignment];
    199     yuv_pointer = ALIGNP(image_pointer, kAlignment);
    200     uint8* current_yuv_pointer = yuv_pointer;
    201     switch (fourcc_type) {
    202       case FOURCC_YUY2: {
    203         for (int j = 0; j < height; ++j) {
    204           for (int i = 0; i < awidth; i += 2, current_yuv_pointer += 4) {
    205             int color1 = ((i / block_size) + (j / block_size)) %
    206                 kTestingColorNum;
    207             int color2 = (((i + 1) / block_size) + (j / block_size)) %
    208                 kTestingColorNum;
    209             current_yuv_pointer[0] = testing_color_y_[color1];
    210             if (i < width) {
    211               current_yuv_pointer[1] = static_cast<uint8>(
    212                   (static_cast<uint32>(testing_color_u_[color1]) +
    213                   static_cast<uint32>(testing_color_u_[color2])) / 2);
    214               current_yuv_pointer[2] = testing_color_y_[color2];
    215               current_yuv_pointer[3] = static_cast<uint8>(
    216                   (static_cast<uint32>(testing_color_v_[color1]) +
    217                   static_cast<uint32>(testing_color_v_[color2])) / 2);
    218             } else {
    219               current_yuv_pointer[1] = testing_color_u_[color1];
    220               current_yuv_pointer[2] = 0;
    221               current_yuv_pointer[3] = testing_color_v_[color1];
    222             }
    223           }
    224         }
    225         break;
    226       }
    227       case FOURCC_UYVY: {
    228         for (int j = 0; j < height; ++j) {
    229           for (int i = 0; i < awidth; i += 2, current_yuv_pointer += 4) {
    230             int color1 = ((i / block_size) + (j / block_size)) %
    231                 kTestingColorNum;
    232             int color2 = (((i + 1) / block_size) + (j / block_size)) %
    233                 kTestingColorNum;
    234             if (i < width) {
    235               current_yuv_pointer[0] = static_cast<uint8>(
    236                   (static_cast<uint32>(testing_color_u_[color1]) +
    237                   static_cast<uint32>(testing_color_u_[color2])) / 2);
    238               current_yuv_pointer[1] = testing_color_y_[color1];
    239               current_yuv_pointer[2] = static_cast<uint8>(
    240                   (static_cast<uint32>(testing_color_v_[color1]) +
    241                   static_cast<uint32>(testing_color_v_[color2])) / 2);
    242               current_yuv_pointer[3] = testing_color_y_[color2];
    243             } else {
    244               current_yuv_pointer[0] = testing_color_u_[color1];
    245               current_yuv_pointer[1] = testing_color_y_[color1];
    246               current_yuv_pointer[2] = testing_color_v_[color1];
    247               current_yuv_pointer[3] = 0;
    248             }
    249           }
    250         }
    251         break;
    252       }
    253     }
    254     return image_pointer;
    255   }
    256   // Generate a Red-Green-Blue inter-weaving chessboard-like
    257   // Q420 testing image.
    258   // The pattern looks like c0 c1 c2 c3 ...
    259   //                        c1 c2 c3 c4 ...
    260   //                        c2 c3 c4 c5 ...
    261   //                        ...............
    262   // The size of each chrome block is (block_size) x (block_size).
    263   uint8* CreateFakeQ420TestingImage(int height, int width, int block_size,
    264       uint8* &y_pointer, uint8* &yuy2_pointer) {
    265     if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
    266     // Regularize the width of the output to be even.
    267     int awidth = (width + 1) & ~1;
    268 
    269     uint8* image_pointer = new uint8[(height / 2) * awidth * 2 +
    270         ((height + 1) / 2) * width + kAlignment];
    271     y_pointer = ALIGNP(image_pointer, kAlignment);
    272     yuy2_pointer = y_pointer + ((height + 1) / 2) * width;
    273     uint8* current_yuy2_pointer = yuy2_pointer;
    274     uint8* current_y_pointer = y_pointer;
    275     for (int j = 0; j < height; ++j) {
    276       if (j % 2 == 0) {
    277         for (int i = 0; i < width; ++i) {
    278           int color = ((i / block_size) + (j / block_size)) %
    279               kTestingColorNum;
    280           *(current_y_pointer++) = testing_color_y_[color];
    281         }
    282       } else {
    283         for (int i = 0; i < awidth; i += 2, current_yuy2_pointer += 4) {
    284           int color1 = ((i / block_size) + (j / block_size)) %
    285               kTestingColorNum;
    286           int color2 = (((i + 1) / block_size) + (j / block_size)) %
    287               kTestingColorNum;
    288           current_yuy2_pointer[0] = testing_color_y_[color1];
    289           if (i < width) {
    290             current_yuy2_pointer[1] = static_cast<uint8>(
    291                 (static_cast<uint32>(testing_color_u_[color1]) +
    292                 static_cast<uint32>(testing_color_u_[color2])) / 2);
    293             current_yuy2_pointer[2] = testing_color_y_[color2];
    294             current_yuy2_pointer[3] = static_cast<uint8>(
    295                 (static_cast<uint32>(testing_color_v_[color1]) +
    296                 static_cast<uint32>(testing_color_v_[color2])) / 2);
    297           } else {
    298             current_yuy2_pointer[1] = testing_color_u_[color1];
    299             current_yuy2_pointer[2] = 0;
    300             current_yuy2_pointer[3] = testing_color_v_[color1];
    301           }
    302         }
    303       }
    304     }
    305     return image_pointer;
    306   }
    307 
    308   // Generate a Red-Green-Blue inter-weaving chessboard-like
    309   // NV12 testing image.
    310   // (Note: No interpolation is used.)
    311   // The pattern looks like c0 c1 c2 c3 ...
    312   //                        c1 c2 c3 c4 ...
    313   //                        c2 c3 c4 c5 ...
    314   //                        ...............
    315   // The size of each chrome block is (block_size) x (block_size).
    316   uint8* CreateFakeNV12TestingImage(int height, int width, int block_size,
    317       uint8* &y_pointer, uint8* &uv_pointer) {
    318     if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
    319 
    320     uint8* image_pointer = new uint8[height * width +
    321         ((height + 1) / 2) * ((width + 1) / 2) * 2 + kAlignment];
    322     y_pointer = ALIGNP(image_pointer, kAlignment);
    323     uv_pointer = y_pointer + height * width;
    324     uint8* current_uv_pointer = uv_pointer;
    325     uint8* current_y_pointer = y_pointer;
    326     for (int j = 0; j < height; ++j) {
    327       for (int i = 0; i < width; ++i) {
    328         int color = ((i / block_size) + (j / block_size)) %
    329             kTestingColorNum;
    330         *(current_y_pointer++) = testing_color_y_[color];
    331       }
    332       if (j % 2 == 0) {
    333         for (int i = 0; i < width; i += 2, current_uv_pointer += 2) {
    334           int color = ((i / block_size) + (j / block_size)) %
    335               kTestingColorNum;
    336           current_uv_pointer[0] = testing_color_u_[color];
    337           current_uv_pointer[1] = testing_color_v_[color];
    338         }
    339       }
    340     }
    341     return image_pointer;
    342   }
    343 
    344   // Generate a Red-Green-Blue inter-weaving chessboard-like
    345   // M420 testing image.
    346   // (Note: No interpolation is used.)
    347   // The pattern looks like c0 c1 c2 c3 ...
    348   //                        c1 c2 c3 c4 ...
    349   //                        c2 c3 c4 c5 ...
    350   //                        ...............
    351   // The size of each chrome block is (block_size) x (block_size).
    352   uint8* CreateFakeM420TestingImage(
    353       int height, int width, int block_size, uint8* &m420_pointer) {
    354     if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
    355 
    356     uint8* image_pointer = new uint8[height * width +
    357         ((height + 1) / 2) * ((width + 1) / 2) * 2 + kAlignment];
    358     m420_pointer = ALIGNP(image_pointer, kAlignment);
    359     uint8* current_m420_pointer = m420_pointer;
    360     for (int j = 0; j < height; ++j) {
    361       for (int i = 0; i < width; ++i) {
    362         int color = ((i / block_size) + (j / block_size)) %
    363             kTestingColorNum;
    364         *(current_m420_pointer++) = testing_color_y_[color];
    365       }
    366       if (j % 2 == 1) {
    367         for (int i = 0; i < width; i += 2, current_m420_pointer += 2) {
    368           int color = ((i / block_size) + ((j - 1) / block_size)) %
    369               kTestingColorNum;
    370           current_m420_pointer[0] = testing_color_u_[color];
    371           current_m420_pointer[1] = testing_color_v_[color];
    372         }
    373       }
    374     }
    375     return image_pointer;
    376   }
    377 
    378   // Generate a Red-Green-Blue inter-weaving chessboard-like
    379   // ARGB/ABGR/RAW/BG24 testing image.
    380   // The pattern looks like c0 c1 c2 c3 ...
    381   //                        c1 c2 c3 c4 ...
    382   //                        c2 c3 c4 c5 ...
    383   //                        ...............
    384   // The size of each chrome block is (block_size) x (block_size).
    385   uint8* CreateFakeArgbTestingImage(int height, int width, int block_size,
    386                                     uint8* &argb_pointer, FourCC fourcc_type) {
    387     if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
    388     uint8* image_pointer = NULL;
    389     if (fourcc_type == FOURCC_ABGR || fourcc_type == FOURCC_BGRA ||
    390         fourcc_type == FOURCC_ARGB) {
    391       image_pointer = new uint8[height * width * 4 + kAlignment];
    392     } else if (fourcc_type == FOURCC_RAW || fourcc_type == FOURCC_24BG) {
    393       image_pointer = new uint8[height * width * 3 + kAlignment];
    394     } else {
    395       LOG(LS_ERROR) << "Format " << static_cast<int>(fourcc_type)
    396                     << " is not supported.";
    397       return NULL;
    398     }
    399     argb_pointer = ALIGNP(image_pointer, kAlignment);
    400     uint8* current_pointer = argb_pointer;
    401     switch (fourcc_type) {
    402       case FOURCC_ARGB: {
    403         for (int j = 0; j < height; ++j) {
    404           for (int i = 0; i < width; ++i) {
    405             int color = ((i / block_size) + (j / block_size)) %
    406                 kTestingColorNum;
    407             *(current_pointer++) = testing_color_b_[color];
    408             *(current_pointer++) = testing_color_g_[color];
    409             *(current_pointer++) = testing_color_r_[color];
    410             *(current_pointer++) = 255;
    411           }
    412         }
    413         break;
    414       }
    415       case FOURCC_ABGR: {
    416         for (int j = 0; j < height; ++j) {
    417           for (int i = 0; i < width; ++i) {
    418             int color = ((i / block_size) + (j / block_size)) %
    419                 kTestingColorNum;
    420             *(current_pointer++) = testing_color_r_[color];
    421             *(current_pointer++) = testing_color_g_[color];
    422             *(current_pointer++) = testing_color_b_[color];
    423             *(current_pointer++) = 255;
    424           }
    425         }
    426         break;
    427       }
    428       case FOURCC_BGRA: {
    429         for (int j = 0; j < height; ++j) {
    430           for (int i = 0; i < width; ++i) {
    431             int color = ((i / block_size) + (j / block_size)) %
    432                 kTestingColorNum;
    433             *(current_pointer++) = 255;
    434             *(current_pointer++) = testing_color_r_[color];
    435             *(current_pointer++) = testing_color_g_[color];
    436             *(current_pointer++) = testing_color_b_[color];
    437            }
    438         }
    439         break;
    440       }
    441       case FOURCC_24BG: {
    442         for (int j = 0; j < height; ++j) {
    443           for (int i = 0; i < width; ++i) {
    444             int color = ((i / block_size) + (j / block_size)) %
    445                 kTestingColorNum;
    446             *(current_pointer++) = testing_color_b_[color];
    447             *(current_pointer++) = testing_color_g_[color];
    448             *(current_pointer++) = testing_color_r_[color];
    449           }
    450         }
    451         break;
    452       }
    453       case FOURCC_RAW: {
    454         for (int j = 0; j < height; ++j) {
    455           for (int i = 0; i < width; ++i) {
    456             int color = ((i / block_size) + (j / block_size)) %
    457                 kTestingColorNum;
    458             *(current_pointer++) = testing_color_r_[color];
    459             *(current_pointer++) = testing_color_g_[color];
    460             *(current_pointer++) = testing_color_b_[color];
    461           }
    462         }
    463         break;
    464       }
    465       default: {
    466         LOG(LS_ERROR) << "Format " << static_cast<int>(fourcc_type)
    467                       << " is not supported.";
    468       }
    469     }
    470     return image_pointer;
    471   }
    472 
    473   // Check if two memory chunks are equal.
    474   // (tolerate MSE errors within a threshold).
    475   static bool IsMemoryEqual(const uint8* ibuf, const uint8* obuf,
    476                             int osize, double average_error) {
    477     double sse = cricket::ComputeSumSquareError(ibuf, obuf, osize);
    478     double error = sse / osize;  // Mean Squared Error.
    479     double PSNR = cricket::ComputePSNR(sse, osize);
    480     LOG(LS_INFO) << "Image MSE: "  << error << " Image PSNR: " << PSNR
    481                  << " First Diff Byte: " << FindDiff(ibuf, obuf, osize);
    482     return (error < average_error);
    483   }
    484 
    485   // Returns the index of the first differing byte. Easier to debug than memcmp.
    486   static int FindDiff(const uint8* buf1, const uint8* buf2, int len) {
    487     int i = 0;
    488     while (i < len && buf1[i] == buf2[i]) {
    489       i++;
    490     }
    491     return (i < len) ? i : -1;
    492   }
    493 
    494   // Dump the result image (ARGB format).
    495   void DumpArgbImage(const uint8* obuf, int width, int height) {
    496     DumpPlanarArgbTestImage(GetTestName(), obuf, width, height);
    497   }
    498 
    499   // Dump the result image (YUV420 format).
    500   void DumpYuvImage(const uint8* obuf, int width, int height) {
    501     DumpPlanarYuvTestImage(GetTestName(), obuf, width, height);
    502   }
    503 
    504   std::string GetTestName() {
    505     const testing::TestInfo* const test_info =
    506         testing::UnitTest::GetInstance()->current_test_info();
    507     std::string test_name(test_info->name());
    508     return test_name;
    509   }
    510 
    511   bool dump_;
    512   int repeat_;
    513 
    514   // Y, U, V and R, G, B channels of testing colors.
    515   rtc::scoped_ptr<uint8[]> testing_color_y_;
    516   rtc::scoped_ptr<uint8[]> testing_color_u_;
    517   rtc::scoped_ptr<uint8[]> testing_color_v_;
    518   rtc::scoped_ptr<uint8[]> testing_color_r_;
    519   rtc::scoped_ptr<uint8[]> testing_color_g_;
    520   rtc::scoped_ptr<uint8[]> testing_color_b_;
    521 };
    522 
    523 TEST_F(PlanarFunctionsTest, I420Copy) {
    524   uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
    525   int y_pitch = kWidth;
    526   int u_pitch = (kWidth + 1) >> 1;
    527   int v_pitch = (kWidth + 1) >> 1;
    528   int y_size = kHeight * kWidth;
    529   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
    530   int block_size = 3;
    531   // Generate a fake input image.
    532   rtc::scoped_ptr<uint8[]> yuv_input(
    533       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    534                                 libyuv::kJpegYuv420,
    535                                 y_pointer, u_pointer, v_pointer));
    536   // Allocate space for the output image.
    537   rtc::scoped_ptr<uint8[]> yuv_output(
    538       new uint8[I420_SIZE(kHeight, kWidth) + kAlignment]);
    539   uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment);
    540   uint8 *u_output_pointer = y_output_pointer + y_size;
    541   uint8 *v_output_pointer = u_output_pointer + uv_size;
    542 
    543   for (int i = 0; i < repeat_; ++i) {
    544   libyuv::I420Copy(y_pointer, y_pitch,
    545                    u_pointer, u_pitch,
    546                    v_pointer, v_pitch,
    547                    y_output_pointer, y_pitch,
    548                    u_output_pointer, u_pitch,
    549                    v_output_pointer, v_pitch,
    550                    kWidth, kHeight);
    551   }
    552 
    553   // Expect the copied frame to be exactly the same.
    554   EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_pointer,
    555       I420_SIZE(kHeight, kWidth), 1.e-6));
    556 
    557   if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
    558 }
    559 
    560 TEST_F(PlanarFunctionsTest, I422ToI420) {
    561   uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
    562   int y_pitch = kWidth;
    563   int u_pitch = (kWidth + 1) >> 1;
    564   int v_pitch = (kWidth + 1) >> 1;
    565   int y_size = kHeight * kWidth;
    566   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
    567   int block_size = 2;
    568   // Generate a fake input image.
    569   rtc::scoped_ptr<uint8[]> yuv_input(
    570       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    571                                 libyuv::kJpegYuv422,
    572                                 y_pointer, u_pointer, v_pointer));
    573   // Allocate space for the output image.
    574   rtc::scoped_ptr<uint8[]> yuv_output(
    575       new uint8[I420_SIZE(kHeight, kWidth) + kAlignment]);
    576   uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment);
    577   uint8 *u_output_pointer = y_output_pointer + y_size;
    578   uint8 *v_output_pointer = u_output_pointer + uv_size;
    579   // Generate the expected output.
    580   uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
    581         *v_expected_pointer = NULL;
    582   rtc::scoped_ptr<uint8[]> yuv_output_expected(
    583       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    584           libyuv::kJpegYuv420,
    585           y_expected_pointer, u_expected_pointer, v_expected_pointer));
    586 
    587   for (int i = 0; i < repeat_; ++i) {
    588   libyuv::I422ToI420(y_pointer, y_pitch,
    589                      u_pointer, u_pitch,
    590                      v_pointer, v_pitch,
    591                      y_output_pointer, y_pitch,
    592                      u_output_pointer, u_pitch,
    593                      v_output_pointer, v_pitch,
    594                      kWidth, kHeight);
    595   }
    596 
    597   // Compare the output frame with what is expected; expect exactly the same.
    598   // Note: MSE should be set to a larger threshold if an odd block width
    599   // is used, since the conversion will be lossy.
    600   EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
    601       I420_SIZE(kHeight, kWidth), 1.e-6));
    602 
    603   if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
    604 }
    605 
    606 TEST_P(PlanarFunctionsTest, Q420ToI420) {
    607   // Get the unalignment offset
    608   int unalignment = GetParam();
    609   uint8 *y_pointer = NULL, *yuy2_pointer = NULL;
    610   int y_pitch = kWidth;
    611   int yuy2_pitch = 2 * ((kWidth + 1) & ~1);
    612   int u_pitch = (kWidth + 1) >> 1;
    613   int v_pitch = (kWidth + 1) >> 1;
    614   int y_size = kHeight * kWidth;
    615   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
    616   int block_size = 2;
    617   // Generate a fake input image.
    618   rtc::scoped_ptr<uint8[]> yuv_input(
    619       CreateFakeQ420TestingImage(kHeight, kWidth, block_size,
    620                                  y_pointer, yuy2_pointer));
    621   // Allocate space for the output image.
    622   rtc::scoped_ptr<uint8[]> yuv_output(
    623       new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]);
    624   uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) +
    625       unalignment;
    626   uint8 *u_output_pointer = y_output_pointer + y_size;
    627   uint8 *v_output_pointer = u_output_pointer + uv_size;
    628   // Generate the expected output.
    629   uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
    630         *v_expected_pointer = NULL;
    631   rtc::scoped_ptr<uint8[]> yuv_output_expected(
    632       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    633           libyuv::kJpegYuv420,
    634           y_expected_pointer, u_expected_pointer, v_expected_pointer));
    635 
    636   for (int i = 0; i < repeat_; ++i) {
    637   libyuv::Q420ToI420(y_pointer, y_pitch,
    638                      yuy2_pointer, yuy2_pitch,
    639                      y_output_pointer, y_pitch,
    640                      u_output_pointer, u_pitch,
    641                      v_output_pointer, v_pitch,
    642                      kWidth, kHeight);
    643   }
    644   // Compare the output frame with what is expected; expect exactly the same.
    645   // Note: MSE should be set to a larger threshold if an odd block width
    646   // is used, since the conversion will be lossy.
    647   EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
    648       I420_SIZE(kHeight, kWidth), 1.e-6));
    649 
    650   if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
    651 }
    652 
    653 TEST_P(PlanarFunctionsTest, M420ToI420) {
    654   // Get the unalignment offset
    655   int unalignment = GetParam();
    656   uint8 *m420_pointer = NULL;
    657   int y_pitch = kWidth;
    658   int m420_pitch = kWidth;
    659   int u_pitch = (kWidth + 1) >> 1;
    660   int v_pitch = (kWidth + 1) >> 1;
    661   int y_size = kHeight * kWidth;
    662   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
    663   int block_size = 2;
    664   // Generate a fake input image.
    665   rtc::scoped_ptr<uint8[]> yuv_input(
    666       CreateFakeM420TestingImage(kHeight, kWidth, block_size, m420_pointer));
    667   // Allocate space for the output image.
    668   rtc::scoped_ptr<uint8[]> yuv_output(
    669       new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]);
    670   uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) + unalignment;
    671   uint8 *u_output_pointer = y_output_pointer + y_size;
    672   uint8 *v_output_pointer = u_output_pointer + uv_size;
    673   // Generate the expected output.
    674   uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
    675         *v_expected_pointer = NULL;
    676   rtc::scoped_ptr<uint8[]> yuv_output_expected(
    677       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    678           libyuv::kJpegYuv420,
    679           y_expected_pointer, u_expected_pointer, v_expected_pointer));
    680 
    681   for (int i = 0; i < repeat_; ++i) {
    682   libyuv::M420ToI420(m420_pointer, m420_pitch,
    683                      y_output_pointer, y_pitch,
    684                      u_output_pointer, u_pitch,
    685                      v_output_pointer, v_pitch,
    686                      kWidth, kHeight);
    687   }
    688   // Compare the output frame with what is expected; expect exactly the same.
    689   // Note: MSE should be set to a larger threshold if an odd block width
    690   // is used, since the conversion will be lossy.
    691   EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
    692       I420_SIZE(kHeight, kWidth), 1.e-6));
    693 
    694   if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
    695 }
    696 
    697 TEST_P(PlanarFunctionsTest, NV12ToI420) {
    698   // Get the unalignment offset
    699   int unalignment = GetParam();
    700   uint8 *y_pointer = NULL, *uv_pointer = NULL;
    701   int y_pitch = kWidth;
    702   int uv_pitch = 2 * ((kWidth + 1) >> 1);
    703   int u_pitch = (kWidth + 1) >> 1;
    704   int v_pitch = (kWidth + 1) >> 1;
    705   int y_size = kHeight * kWidth;
    706   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
    707   int block_size = 2;
    708   // Generate a fake input image.
    709   rtc::scoped_ptr<uint8[]> yuv_input(
    710       CreateFakeNV12TestingImage(kHeight, kWidth, block_size,
    711                                  y_pointer, uv_pointer));
    712   // Allocate space for the output image.
    713   rtc::scoped_ptr<uint8[]> yuv_output(
    714       new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]);
    715   uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) + unalignment;
    716   uint8 *u_output_pointer = y_output_pointer + y_size;
    717   uint8 *v_output_pointer = u_output_pointer + uv_size;
    718   // Generate the expected output.
    719   uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
    720         *v_expected_pointer = NULL;
    721   rtc::scoped_ptr<uint8[]> yuv_output_expected(
    722       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    723           libyuv::kJpegYuv420,
    724           y_expected_pointer, u_expected_pointer, v_expected_pointer));
    725 
    726   for (int i = 0; i < repeat_; ++i) {
    727   libyuv::NV12ToI420(y_pointer, y_pitch,
    728                      uv_pointer, uv_pitch,
    729                      y_output_pointer, y_pitch,
    730                      u_output_pointer, u_pitch,
    731                      v_output_pointer, v_pitch,
    732                      kWidth, kHeight);
    733   }
    734   // Compare the output frame with what is expected; expect exactly the same.
    735   // Note: MSE should be set to a larger threshold if an odd block width
    736   // is used, since the conversion will be lossy.
    737   EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
    738       I420_SIZE(kHeight, kWidth), 1.e-6));
    739 
    740   if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
    741 }
    742 
    743 // A common macro for testing converting YUY2/UYVY to I420.
    744 #define TEST_YUVTOI420(SRC_NAME, MSE, BLOCK_SIZE) \
    745 TEST_P(PlanarFunctionsTest, SRC_NAME##ToI420) { \
    746   /* Get the unalignment offset.*/ \
    747   int unalignment = GetParam(); \
    748   uint8 *yuv_pointer = NULL; \
    749   int yuv_pitch = 2 * ((kWidth + 1) & ~1); \
    750   int y_pitch = kWidth; \
    751   int u_pitch = (kWidth + 1) >> 1; \
    752   int v_pitch = (kWidth + 1) >> 1; \
    753   int y_size = kHeight * kWidth; \
    754   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1); \
    755   int block_size = 2; \
    756   /* Generate a fake input image.*/ \
    757   rtc::scoped_ptr<uint8[]> yuv_input( \
    758       CreateFakeInterleaveYuvTestingImage(kHeight, kWidth, BLOCK_SIZE, \
    759           yuv_pointer, FOURCC_##SRC_NAME)); \
    760   /* Allocate space for the output image.*/ \
    761   rtc::scoped_ptr<uint8[]> yuv_output( \
    762       new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]); \
    763   uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) + \
    764       unalignment; \
    765   uint8 *u_output_pointer = y_output_pointer + y_size; \
    766   uint8 *v_output_pointer = u_output_pointer + uv_size; \
    767   /* Generate the expected output.*/ \
    768   uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL, \
    769         *v_expected_pointer = NULL; \
    770   rtc::scoped_ptr<uint8[]> yuv_output_expected( \
    771       CreateFakeYuvTestingImage(kHeight, kWidth, block_size, \
    772           libyuv::kJpegYuv420, \
    773           y_expected_pointer, u_expected_pointer, v_expected_pointer)); \
    774   for (int i = 0; i < repeat_; ++i) { \
    775     libyuv::SRC_NAME##ToI420(yuv_pointer, yuv_pitch, \
    776                              y_output_pointer, y_pitch, \
    777                              u_output_pointer, u_pitch, \
    778                              v_output_pointer, v_pitch, \
    779                              kWidth, kHeight); \
    780   } \
    781   /* Compare the output frame with what is expected.*/ \
    782   /* Note: MSE should be set to a larger threshold if an odd block width*/ \
    783   /* is used, since the conversion will be lossy.*/ \
    784   EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer, \
    785       I420_SIZE(kHeight, kWidth), MSE)); \
    786   if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); } \
    787 } \
    788 
    789 // TEST_P(PlanarFunctionsTest, YUV2ToI420)
    790 TEST_YUVTOI420(YUY2, 1.e-6, 2);
    791 // TEST_P(PlanarFunctionsTest, UYVYToI420)
    792 TEST_YUVTOI420(UYVY, 1.e-6, 2);
    793 
    794 // A common macro for testing converting I420 to ARGB, BGRA and ABGR.
    795 #define TEST_YUVTORGB(SRC_NAME, DST_NAME, JPG_TYPE, MSE, BLOCK_SIZE) \
    796 TEST_F(PlanarFunctionsTest, SRC_NAME##To##DST_NAME) { \
    797   uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL; \
    798   uint8 *argb_expected_pointer = NULL; \
    799   int y_pitch = kWidth; \
    800   int u_pitch = (kWidth + 1) >> 1; \
    801   int v_pitch = (kWidth + 1) >> 1; \
    802   /* Generate a fake input image.*/ \
    803   rtc::scoped_ptr<uint8[]> yuv_input( \
    804       CreateFakeYuvTestingImage(kHeight, kWidth, BLOCK_SIZE, JPG_TYPE, \
    805                                 y_pointer, u_pointer, v_pointer)); \
    806   /* Generate the expected output.*/ \
    807   rtc::scoped_ptr<uint8[]> argb_expected( \
    808       CreateFakeArgbTestingImage(kHeight, kWidth, BLOCK_SIZE, \
    809                                  argb_expected_pointer, FOURCC_##DST_NAME)); \
    810   /* Allocate space for the output.*/ \
    811   rtc::scoped_ptr<uint8[]> argb_output( \
    812     new uint8[kHeight * kWidth * 4 + kAlignment]); \
    813   uint8 *argb_pointer = ALIGNP(argb_expected.get(), kAlignment); \
    814   for (int i = 0; i < repeat_; ++i) { \
    815     libyuv::SRC_NAME##To##DST_NAME(y_pointer, y_pitch, \
    816                                    u_pointer, u_pitch, \
    817                                    v_pointer, v_pitch, \
    818                                    argb_pointer, \
    819                                    kWidth * 4, \
    820                                    kWidth, kHeight); \
    821   } \
    822   EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer, \
    823                             kHeight * kWidth * 4, MSE)); \
    824   if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); } \
    825 }
    826 
    827 // TEST_F(PlanarFunctionsTest, I420ToARGB)
    828 TEST_YUVTORGB(I420, ARGB, libyuv::kJpegYuv420, 3., 2);
    829 // TEST_F(PlanarFunctionsTest, I420ToABGR)
    830 TEST_YUVTORGB(I420, ABGR, libyuv::kJpegYuv420, 3., 2);
    831 // TEST_F(PlanarFunctionsTest, I420ToBGRA)
    832 TEST_YUVTORGB(I420, BGRA, libyuv::kJpegYuv420, 3., 2);
    833 // TEST_F(PlanarFunctionsTest, I422ToARGB)
    834 TEST_YUVTORGB(I422, ARGB, libyuv::kJpegYuv422, 3., 2);
    835 // TEST_F(PlanarFunctionsTest, I444ToARGB)
    836 TEST_YUVTORGB(I444, ARGB, libyuv::kJpegYuv444, 3., 3);
    837 // Note: an empirical MSE tolerance 3.0 is used here for the probable
    838 // error from float-to-uint8 type conversion.
    839 
    840 TEST_F(PlanarFunctionsTest, I400ToARGB_Reference) {
    841   uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
    842   int y_pitch = kWidth;
    843   int u_pitch = (kWidth + 1) >> 1;
    844   int v_pitch = (kWidth + 1) >> 1;
    845   int block_size = 3;
    846   // Generate a fake input image.
    847   rtc::scoped_ptr<uint8[]> yuv_input(
    848       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    849                                 libyuv::kJpegYuv420,
    850                                 y_pointer, u_pointer, v_pointer));
    851   // As the comparison standard, we convert a grayscale image (by setting both
    852   // U and V channels to be 128) using an I420 converter.
    853   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
    854 
    855   rtc::scoped_ptr<uint8[]> uv(new uint8[uv_size + kAlignment]);
    856   u_pointer = v_pointer = ALIGNP(uv.get(), kAlignment);
    857   memset(u_pointer, 128, uv_size);
    858 
    859   // Allocate space for the output image and generate the expected output.
    860   rtc::scoped_ptr<uint8[]> argb_expected(
    861       new uint8[kHeight * kWidth * 4 + kAlignment]);
    862   rtc::scoped_ptr<uint8[]> argb_output(
    863       new uint8[kHeight * kWidth * 4 + kAlignment]);
    864   uint8 *argb_expected_pointer = ALIGNP(argb_expected.get(), kAlignment);
    865   uint8 *argb_pointer = ALIGNP(argb_output.get(), kAlignment);
    866 
    867   libyuv::I420ToARGB(y_pointer, y_pitch,
    868                      u_pointer, u_pitch,
    869                      v_pointer, v_pitch,
    870                      argb_expected_pointer, kWidth * 4,
    871                      kWidth, kHeight);
    872   for (int i = 0; i < repeat_; ++i) {
    873     libyuv::I400ToARGB_Reference(y_pointer, y_pitch,
    874                                  argb_pointer, kWidth * 4,
    875                                  kWidth, kHeight);
    876   }
    877 
    878   // Note: I420ToARGB and I400ToARGB_Reference should produce identical results.
    879   EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer,
    880                             kHeight * kWidth * 4, 2.));
    881   if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); }
    882 }
    883 
    884 TEST_P(PlanarFunctionsTest, I400ToARGB) {
    885   // Get the unalignment offset
    886   int unalignment = GetParam();
    887   uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
    888   int y_pitch = kWidth;
    889   int u_pitch = (kWidth + 1) >> 1;
    890   int v_pitch = (kWidth + 1) >> 1;
    891   int block_size = 3;
    892   // Generate a fake input image.
    893   rtc::scoped_ptr<uint8[]> yuv_input(
    894       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    895                                 libyuv::kJpegYuv420,
    896                                 y_pointer, u_pointer, v_pointer));
    897   // As the comparison standard, we convert a grayscale image (by setting both
    898   // U and V channels to be 128) using an I420 converter.
    899   int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
    900 
    901   // 1 byte extra if in the unaligned mode.
    902   rtc::scoped_ptr<uint8[]> uv(new uint8[uv_size * 2 + kAlignment]);
    903   u_pointer = ALIGNP(uv.get(), kAlignment);
    904   v_pointer = u_pointer + uv_size;
    905   memset(u_pointer, 128, uv_size);
    906   memset(v_pointer, 128, uv_size);
    907 
    908   // Allocate space for the output image and generate the expected output.
    909   rtc::scoped_ptr<uint8[]> argb_expected(
    910       new uint8[kHeight * kWidth * 4 + kAlignment]);
    911   // 1 byte extra if in the misalinged mode.
    912   rtc::scoped_ptr<uint8[]> argb_output(
    913       new uint8[kHeight * kWidth * 4 + kAlignment + unalignment]);
    914   uint8 *argb_expected_pointer = ALIGNP(argb_expected.get(), kAlignment);
    915   uint8 *argb_pointer = ALIGNP(argb_output.get(), kAlignment) + unalignment;
    916 
    917   libyuv::I420ToARGB(y_pointer, y_pitch,
    918                      u_pointer, u_pitch,
    919                      v_pointer, v_pitch,
    920                      argb_expected_pointer, kWidth * 4,
    921                      kWidth, kHeight);
    922   for (int i = 0; i < repeat_; ++i) {
    923     libyuv::I400ToARGB(y_pointer, y_pitch,
    924                        argb_pointer, kWidth * 4,
    925                        kWidth, kHeight);
    926   }
    927 
    928   // Note: current I400ToARGB uses an approximate method,
    929   // so the error tolerance is larger here.
    930   EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer,
    931                             kHeight * kWidth * 4, 64.0));
    932   if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); }
    933 }
    934 
    935 TEST_P(PlanarFunctionsTest, ARGBToI400) {
    936   // Get the unalignment offset
    937   int unalignment = GetParam();
    938   // Create a fake ARGB input image.
    939   uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
    940   uint8 *argb_pointer = NULL;
    941   int block_size = 3;
    942   // Generate a fake input image.
    943   rtc::scoped_ptr<uint8[]> argb_input(
    944       CreateFakeArgbTestingImage(kHeight, kWidth, block_size,
    945                                  argb_pointer, FOURCC_ARGB));
    946   // Generate the expected output. Only Y channel is used
    947   rtc::scoped_ptr<uint8[]> yuv_expected(
    948       CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
    949                                 libyuv::kJpegYuv420,
    950                                 y_pointer, u_pointer, v_pointer));
    951   // Allocate space for the Y output.
    952   rtc::scoped_ptr<uint8[]> y_output(
    953     new uint8[kHeight * kWidth + kAlignment + unalignment]);
    954   uint8 *y_output_pointer = ALIGNP(y_output.get(), kAlignment) + unalignment;
    955 
    956   for (int i = 0; i < repeat_; ++i) {
    957     libyuv::ARGBToI400(argb_pointer, kWidth * 4, y_output_pointer, kWidth,
    958                        kWidth, kHeight);
    959   }
    960   // Check if the output matches the input Y channel.
    961   // Note: an empirical MSE tolerance 2.0 is used here for the probable
    962   // error from float-to-uint8 type conversion.
    963   EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_pointer,
    964                             kHeight * kWidth, 2.));
    965   if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); }
    966 }
    967 
    968 // A common macro for testing converting RAW, BG24, BGRA, and ABGR
    969 // to ARGB.
    970 #define TEST_ARGB(SRC_NAME, FC_ID, BPP, BLOCK_SIZE) \
    971 TEST_P(PlanarFunctionsTest, SRC_NAME##ToARGB) { \
    972   int unalignment = GetParam();  /* Get the unalignment offset.*/ \
    973   uint8 *argb_expected_pointer = NULL, *src_pointer = NULL; \
    974   /* Generate a fake input image.*/ \
    975   rtc::scoped_ptr<uint8[]> src_input(  \
    976       CreateFakeArgbTestingImage(kHeight, kWidth, BLOCK_SIZE, \
    977                                  src_pointer, FOURCC_##FC_ID)); \
    978   /* Generate the expected output.*/ \
    979   rtc::scoped_ptr<uint8[]> argb_expected( \
    980       CreateFakeArgbTestingImage(kHeight, kWidth, BLOCK_SIZE, \
    981                                  argb_expected_pointer, FOURCC_ARGB)); \
    982   /* Allocate space for the output; 1 byte extra if in the unaligned mode.*/ \
    983   rtc::scoped_ptr<uint8[]> argb_output( \
    984       new uint8[kHeight * kWidth * 4 + kAlignment + unalignment]); \
    985   uint8 *argb_pointer = ALIGNP(argb_output.get(), kAlignment) + unalignment; \
    986   for (int i = 0; i < repeat_; ++i) { \
    987     libyuv:: SRC_NAME##ToARGB(src_pointer, kWidth * (BPP), argb_pointer, \
    988                               kWidth * 4, kWidth, kHeight); \
    989   } \
    990   /* Compare the result; expect identical.*/ \
    991   EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer, \
    992                             kHeight * kWidth * 4, 1.e-6)); \
    993   if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); } \
    994 }
    995 
    996 TEST_ARGB(RAW, RAW, 3, 3);    // TEST_P(PlanarFunctionsTest, RAWToARGB)
    997 TEST_ARGB(BG24, 24BG, 3, 3);  // TEST_P(PlanarFunctionsTest, BG24ToARGB)
    998 TEST_ARGB(ABGR, ABGR, 4, 3);  // TEST_P(PlanarFunctionsTest, ABGRToARGB)
    999 TEST_ARGB(BGRA, BGRA, 4, 3);  // TEST_P(PlanarFunctionsTest, BGRAToARGB)
   1000 
   1001 // Parameter Test: The parameter is the unalignment offset.
   1002 // Aligned data for testing assembly versions.
   1003 INSTANTIATE_TEST_CASE_P(PlanarFunctionsAligned, PlanarFunctionsTest,
   1004     ::testing::Values(0));
   1005 
   1006 // Purposely unalign the output argb pointer to test slow path (C version).
   1007 INSTANTIATE_TEST_CASE_P(PlanarFunctionsMisaligned, PlanarFunctionsTest,
   1008     ::testing::Values(1));
   1009 
   1010 }  // namespace cricket
   1011