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