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