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