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