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