| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #ifndef WEBRTC_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_ | |
| 12 #define WEBRTC_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_ | |
| 13 | |
| 14 #include <algorithm> | |
| 15 #include <memory> | |
| 16 #include <string> | |
| 17 | |
| 18 #include "libyuv/convert.h" | |
| 19 #include "libyuv/convert_from.h" | |
| 20 #include "libyuv/planar_functions.h" | |
| 21 #include "libyuv/rotate.h" | |
| 22 #include "webrtc/base/gunit.h" | |
| 23 #include "webrtc/base/pathutils.h" | |
| 24 #include "webrtc/base/stream.h" | |
| 25 #include "webrtc/base/stringutils.h" | |
| 26 #include "webrtc/common_video/rotation.h" | |
| 27 #include "webrtc/media/base/testutils.h" | |
| 28 #include "webrtc/media/base/videocommon.h" | |
| 29 #include "webrtc/media/base/videoframe.h" | |
| 30 #include "webrtc/test/testsupport/fileutils.h" | |
| 31 | |
| 32 #if defined(_MSC_VER) | |
| 33 #define ALIGN16(var) __declspec(align(16)) var | |
| 34 #else | |
| 35 #define ALIGN16(var) var __attribute__((aligned(16))) | |
| 36 #endif | |
| 37 | |
| 38 #define kImageFilename "media/faces.1280x720_P420" | |
| 39 #define kYuvExtension "yuv" | |
| 40 #define kJpeg420Filename "media/faces_I420" | |
| 41 #define kJpeg422Filename "media/faces_I422" | |
| 42 #define kJpeg444Filename "media/faces_I444" | |
| 43 #define kJpeg411Filename "media/faces_I411" | |
| 44 #define kJpeg400Filename "media/faces_I400" | |
| 45 #define kJpegExtension "jpg" | |
| 46 | |
| 47 // Generic test class for testing various video frame implementations. | |
| 48 template <class T> | |
| 49 class VideoFrameTest : public testing::Test { | |
| 50 public: | |
| 51 VideoFrameTest() : repeat_(1) {} | |
| 52 | |
| 53 protected: | |
| 54 static const int kWidth = 1280; | |
| 55 static const int kHeight = 720; | |
| 56 static const int kAlignment = 16; | |
| 57 static const int kMinWidthAll = 1; // Constants for ConstructYUY2AllSizes. | |
| 58 static const int kMinHeightAll = 1; | |
| 59 static const int kMaxWidthAll = 17; | |
| 60 static const int kMaxHeightAll = 23; | |
| 61 | |
| 62 // Load a video frame from disk. | |
| 63 bool LoadFrameNoRepeat(T* frame) { | |
| 64 int save_repeat = repeat_; // This LoadFrame disables repeat. | |
| 65 repeat_ = 1; | |
| 66 bool success = LoadFrame(LoadSample(kImageFilename, kYuvExtension).get(), | |
| 67 cricket::FOURCC_I420, | |
| 68 kWidth, kHeight, frame); | |
| 69 repeat_ = save_repeat; | |
| 70 return success; | |
| 71 } | |
| 72 | |
| 73 bool LoadFrame(const std::string& filename, | |
| 74 uint32_t format, | |
| 75 int32_t width, | |
| 76 int32_t height, | |
| 77 T* frame) { | |
| 78 return LoadFrame(filename, format, width, height, width, abs(height), | |
| 79 webrtc::kVideoRotation_0, frame); | |
| 80 } | |
| 81 bool LoadFrame(const std::string& filename, | |
| 82 uint32_t format, | |
| 83 int32_t width, | |
| 84 int32_t height, | |
| 85 int dw, | |
| 86 int dh, | |
| 87 webrtc::VideoRotation rotation, | |
| 88 T* frame) { | |
| 89 std::unique_ptr<rtc::MemoryStream> ms(LoadSample(filename)); | |
| 90 return LoadFrame(ms.get(), format, width, height, dw, dh, rotation, frame); | |
| 91 } | |
| 92 // Load a video frame from a memory stream. | |
| 93 bool LoadFrame(rtc::MemoryStream* ms, | |
| 94 uint32_t format, | |
| 95 int32_t width, | |
| 96 int32_t height, | |
| 97 T* frame) { | |
| 98 return LoadFrame(ms, format, width, height, width, abs(height), | |
| 99 webrtc::kVideoRotation_0, frame); | |
| 100 } | |
| 101 bool LoadFrame(rtc::MemoryStream* ms, | |
| 102 uint32_t format, | |
| 103 int32_t width, | |
| 104 int32_t height, | |
| 105 int dw, | |
| 106 int dh, | |
| 107 webrtc::VideoRotation rotation, | |
| 108 T* frame) { | |
| 109 if (!ms) { | |
| 110 return false; | |
| 111 } | |
| 112 size_t data_size; | |
| 113 bool ret = ms->GetSize(&data_size); | |
| 114 EXPECT_TRUE(ret); | |
| 115 if (ret) { | |
| 116 ret = LoadFrame(reinterpret_cast<uint8_t*>(ms->GetBuffer()), data_size, | |
| 117 format, width, height, dw, dh, rotation, frame); | |
| 118 } | |
| 119 return ret; | |
| 120 } | |
| 121 // Load a frame from a raw buffer. | |
| 122 bool LoadFrame(uint8_t* sample, | |
| 123 size_t sample_size, | |
| 124 uint32_t format, | |
| 125 int32_t width, | |
| 126 int32_t height, | |
| 127 T* frame) { | |
| 128 return LoadFrame(sample, sample_size, format, width, height, width, | |
| 129 abs(height), webrtc::kVideoRotation_0, frame); | |
| 130 } | |
| 131 bool LoadFrame(uint8_t* sample, | |
| 132 size_t sample_size, | |
| 133 uint32_t format, | |
| 134 int32_t width, | |
| 135 int32_t height, | |
| 136 int dw, | |
| 137 int dh, | |
| 138 webrtc::VideoRotation rotation, | |
| 139 T* frame) { | |
| 140 bool ret = false; | |
| 141 for (int i = 0; i < repeat_; ++i) { | |
| 142 ret = frame->Init(format, width, height, dw, dh, | |
| 143 sample, sample_size, 0, rotation); | |
| 144 } | |
| 145 return ret; | |
| 146 } | |
| 147 | |
| 148 std::unique_ptr<rtc::MemoryStream> LoadSample(const std::string& filename, | |
| 149 const std::string& extension) { | |
| 150 rtc::Pathname path(webrtc::test::ResourcePath(filename, extension)); | |
| 151 std::unique_ptr<rtc::FileStream> fs( | |
| 152 rtc::Filesystem::OpenFile(path, "rb")); | |
| 153 if (!fs.get()) { | |
| 154 LOG(LS_ERROR) << "Could not open test file path: " << path.pathname() | |
| 155 << " from current dir " | |
| 156 << rtc::Filesystem::GetCurrentDirectory().pathname(); | |
| 157 return NULL; | |
| 158 } | |
| 159 | |
| 160 char buf[4096]; | |
| 161 std::unique_ptr<rtc::MemoryStream> ms( | |
| 162 new rtc::MemoryStream()); | |
| 163 rtc::StreamResult res = Flow(fs.get(), buf, sizeof(buf), ms.get()); | |
| 164 if (res != rtc::SR_SUCCESS) { | |
| 165 LOG(LS_ERROR) << "Could not load test file path: " << path.pathname(); | |
| 166 return NULL; | |
| 167 } | |
| 168 | |
| 169 return ms; | |
| 170 } | |
| 171 | |
| 172 bool DumpSample(const std::string& filename, const void* buffer, int size) { | |
| 173 rtc::Pathname path(filename); | |
| 174 std::unique_ptr<rtc::FileStream> fs( | |
| 175 rtc::Filesystem::OpenFile(path, "wb")); | |
| 176 if (!fs.get()) { | |
| 177 return false; | |
| 178 } | |
| 179 | |
| 180 return (fs->Write(buffer, size, NULL, NULL) == rtc::SR_SUCCESS); | |
| 181 } | |
| 182 | |
| 183 // Create a test image in the desired color space. | |
| 184 // The image is a checkerboard pattern with 63x63 squares, which allows | |
| 185 // I420 chroma artifacts to easily be seen on the square boundaries. | |
| 186 // The pattern is { { green, orange }, { blue, purple } } | |
| 187 // There is also a gradient within each square to ensure that the luma | |
| 188 // values are handled properly. | |
| 189 std::unique_ptr<rtc::MemoryStream> CreateYuv422Sample(uint32_t fourcc, | |
| 190 uint32_t width, | |
| 191 uint32_t height) { | |
| 192 int y1_pos, y2_pos, u_pos, v_pos; | |
| 193 if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) { | |
| 194 return NULL; | |
| 195 } | |
| 196 | |
| 197 std::unique_ptr<rtc::MemoryStream> ms( | |
| 198 new rtc::MemoryStream); | |
| 199 int awidth = (width + 1) & ~1; | |
| 200 int size = awidth * 2 * height; | |
| 201 if (!ms->ReserveSize(size)) { | |
| 202 return NULL; | |
| 203 } | |
| 204 for (uint32_t y = 0; y < height; ++y) { | |
| 205 for (int x = 0; x < awidth; x += 2) { | |
| 206 uint8_t quad[4]; | |
| 207 quad[y1_pos] = (x % 63 + y % 63) + 64; | |
| 208 quad[y2_pos] = ((x + 1) % 63 + y % 63) + 64; | |
| 209 quad[u_pos] = ((x / 63) & 1) ? 192 : 64; | |
| 210 quad[v_pos] = ((y / 63) & 1) ? 192 : 64; | |
| 211 ms->Write(quad, sizeof(quad), NULL, NULL); | |
| 212 } | |
| 213 } | |
| 214 return ms; | |
| 215 } | |
| 216 | |
| 217 // Create a test image for YUV 420 formats with 12 bits per pixel. | |
| 218 std::unique_ptr<rtc::MemoryStream> CreateYuvSample(uint32_t width, | |
| 219 uint32_t height, | |
| 220 uint32_t bpp) { | |
| 221 std::unique_ptr<rtc::MemoryStream> ms( | |
| 222 new rtc::MemoryStream); | |
| 223 if (!ms->ReserveSize(width * height * bpp / 8)) { | |
| 224 return NULL; | |
| 225 } | |
| 226 | |
| 227 for (uint32_t i = 0; i < width * height * bpp / 8; ++i) { | |
| 228 uint8_t value = ((i / 63) & 1) ? 192 : 64; | |
| 229 ms->Write(&value, sizeof(value), NULL, NULL); | |
| 230 } | |
| 231 return ms; | |
| 232 } | |
| 233 | |
| 234 std::unique_ptr<rtc::MemoryStream> CreateRgbSample(uint32_t fourcc, | |
| 235 uint32_t width, | |
| 236 uint32_t height) { | |
| 237 int r_pos, g_pos, b_pos, bytes; | |
| 238 if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) { | |
| 239 return NULL; | |
| 240 } | |
| 241 | |
| 242 std::unique_ptr<rtc::MemoryStream> ms( | |
| 243 new rtc::MemoryStream); | |
| 244 if (!ms->ReserveSize(width * height * bytes)) { | |
| 245 return NULL; | |
| 246 } | |
| 247 | |
| 248 for (uint32_t y = 0; y < height; ++y) { | |
| 249 for (uint32_t x = 0; x < width; ++x) { | |
| 250 uint8_t rgb[4] = {255, 255, 255, 255}; | |
| 251 rgb[r_pos] = ((x / 63) & 1) ? 224 : 32; | |
| 252 rgb[g_pos] = (x % 63 + y % 63) + 96; | |
| 253 rgb[b_pos] = ((y / 63) & 1) ? 224 : 32; | |
| 254 ms->Write(rgb, bytes, NULL, NULL); | |
| 255 } | |
| 256 } | |
| 257 return ms; | |
| 258 } | |
| 259 | |
| 260 // Simple conversion routines to verify the optimized VideoFrame routines. | |
| 261 // Converts from the specified colorspace to I420. | |
| 262 std::unique_ptr<T> ConvertYuv422(const rtc::MemoryStream* ms, | |
| 263 uint32_t fourcc, | |
| 264 uint32_t width, | |
| 265 uint32_t height) { | |
| 266 int y1_pos, y2_pos, u_pos, v_pos; | |
| 267 if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) { | |
| 268 return nullptr; | |
| 269 } | |
| 270 | |
| 271 rtc::scoped_refptr<webrtc::I420Buffer> buffer( | |
| 272 new rtc::RefCountedObject<webrtc::I420Buffer>(width, height)); | |
| 273 | |
| 274 buffer->SetToBlack(); | |
| 275 | |
| 276 const uint8_t* start = reinterpret_cast<const uint8_t*>(ms->GetBuffer()); | |
| 277 int awidth = (width + 1) & ~1; | |
| 278 int stride_y = buffer->StrideY(); | |
| 279 int stride_u = buffer->StrideU(); | |
| 280 int stride_v = buffer->StrideV(); | |
| 281 uint8_t* plane_y = buffer->MutableDataY(); | |
| 282 uint8_t* plane_u = buffer->MutableDataU(); | |
| 283 uint8_t* plane_v = buffer->MutableDataV(); | |
| 284 for (uint32_t y = 0; y < height; ++y) { | |
| 285 for (uint32_t x = 0; x < width; x += 2) { | |
| 286 const uint8_t* quad1 = start + (y * awidth + x) * 2; | |
| 287 plane_y[stride_y * y + x] = quad1[y1_pos]; | |
| 288 if ((x + 1) < width) { | |
| 289 plane_y[stride_y * y + x + 1] = quad1[y2_pos]; | |
| 290 } | |
| 291 if ((y & 1) == 0) { | |
| 292 const uint8_t* quad2 = quad1 + awidth * 2; | |
| 293 if ((y + 1) >= height) { | |
| 294 quad2 = quad1; | |
| 295 } | |
| 296 plane_u[stride_u * (y / 2) + x / 2] = | |
| 297 (quad1[u_pos] + quad2[u_pos] + 1) / 2; | |
| 298 plane_v[stride_v * (y / 2) + x / 2] = | |
| 299 (quad1[v_pos] + quad2[v_pos] + 1) / 2; | |
| 300 } | |
| 301 } | |
| 302 } | |
| 303 return std::unique_ptr<T>(new T(buffer, 0, webrtc::kVideoRotation_0)); | |
| 304 } | |
| 305 | |
| 306 // Convert RGB to 420. | |
| 307 // A negative height inverts the image. | |
| 308 std::unique_ptr<T> ConvertRgb(const rtc::MemoryStream* ms, | |
| 309 uint32_t fourcc, | |
| 310 int32_t width, | |
| 311 int32_t height) { | |
| 312 int r_pos, g_pos, b_pos, bytes; | |
| 313 if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) { | |
| 314 return nullptr; | |
| 315 } | |
| 316 int pitch = width * bytes; | |
| 317 const uint8_t* start = reinterpret_cast<const uint8_t*>(ms->GetBuffer()); | |
| 318 if (height < 0) { | |
| 319 height = -height; | |
| 320 start = start + pitch * (height - 1); | |
| 321 pitch = -pitch; | |
| 322 } | |
| 323 rtc::scoped_refptr<webrtc::I420Buffer> buffer( | |
| 324 new rtc::RefCountedObject<webrtc::I420Buffer>(width, height)); | |
| 325 | |
| 326 buffer->SetToBlack(); | |
| 327 | |
| 328 int stride_y = buffer->StrideY(); | |
| 329 int stride_u = buffer->StrideU(); | |
| 330 int stride_v = buffer->StrideV(); | |
| 331 uint8_t* plane_y = buffer->MutableDataY(); | |
| 332 uint8_t* plane_u = buffer->MutableDataU(); | |
| 333 uint8_t* plane_v = buffer->MutableDataV(); | |
| 334 for (int32_t y = 0; y < height; y += 2) { | |
| 335 for (int32_t x = 0; x < width; x += 2) { | |
| 336 const uint8_t* rgb[4]; | |
| 337 uint8_t yuv[4][3]; | |
| 338 rgb[0] = start + y * pitch + x * bytes; | |
| 339 rgb[1] = rgb[0] + ((x + 1) < width ? bytes : 0); | |
| 340 rgb[2] = rgb[0] + ((y + 1) < height ? pitch : 0); | |
| 341 rgb[3] = rgb[2] + ((x + 1) < width ? bytes : 0); | |
| 342 for (size_t i = 0; i < 4; ++i) { | |
| 343 ConvertRgbPixel(rgb[i][r_pos], rgb[i][g_pos], rgb[i][b_pos], | |
| 344 &yuv[i][0], &yuv[i][1], &yuv[i][2]); | |
| 345 } | |
| 346 plane_y[stride_y * y + x] = yuv[0][0]; | |
| 347 if ((x + 1) < width) { | |
| 348 plane_y[stride_y * y + x + 1] = yuv[1][0]; | |
| 349 } | |
| 350 if ((y + 1) < height) { | |
| 351 plane_y[stride_y * (y + 1) + x] = yuv[2][0]; | |
| 352 if ((x + 1) < width) { | |
| 353 plane_y[stride_y * (y + 1) + x + 1] = yuv[3][0]; | |
| 354 } | |
| 355 } | |
| 356 plane_u[stride_u * (y / 2) + x / 2] = | |
| 357 (yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1] + 2) / 4; | |
| 358 plane_v[stride_v * (y / 2) + x / 2] = | |
| 359 (yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2] + 2) / 4; | |
| 360 } | |
| 361 } | |
| 362 return std::unique_ptr<T>(new T(buffer, 0, webrtc::kVideoRotation_0)); | |
| 363 } | |
| 364 | |
| 365 // Simple and slow RGB->YUV conversion. From NTSC standard, c/o Wikipedia. | |
| 366 void ConvertRgbPixel(uint8_t r, | |
| 367 uint8_t g, | |
| 368 uint8_t b, | |
| 369 uint8_t* y, | |
| 370 uint8_t* u, | |
| 371 uint8_t* v) { | |
| 372 *y = static_cast<int>(.257 * r + .504 * g + .098 * b) + 16; | |
| 373 *u = static_cast<int>(-.148 * r - .291 * g + .439 * b) + 128; | |
| 374 *v = static_cast<int>(.439 * r - .368 * g - .071 * b) + 128; | |
| 375 } | |
| 376 | |
| 377 bool GetYuv422Packing(uint32_t fourcc, | |
| 378 int* y1_pos, | |
| 379 int* y2_pos, | |
| 380 int* u_pos, | |
| 381 int* v_pos) { | |
| 382 if (fourcc == cricket::FOURCC_YUY2) { | |
| 383 *y1_pos = 0; *u_pos = 1; *y2_pos = 2; *v_pos = 3; | |
| 384 } else if (fourcc == cricket::FOURCC_UYVY) { | |
| 385 *u_pos = 0; *y1_pos = 1; *v_pos = 2; *y2_pos = 3; | |
| 386 } else { | |
| 387 return false; | |
| 388 } | |
| 389 return true; | |
| 390 } | |
| 391 | |
| 392 bool GetRgbPacking(uint32_t fourcc, | |
| 393 int* r_pos, | |
| 394 int* g_pos, | |
| 395 int* b_pos, | |
| 396 int* bytes) { | |
| 397 if (fourcc == cricket::FOURCC_RAW) { | |
| 398 *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 3; // RGB in memory. | |
| 399 } else if (fourcc == cricket::FOURCC_24BG) { | |
| 400 *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 3; // BGR in memory. | |
| 401 } else if (fourcc == cricket::FOURCC_ABGR) { | |
| 402 *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 4; // RGBA in memory. | |
| 403 } else if (fourcc == cricket::FOURCC_BGRA) { | |
| 404 *r_pos = 1; *g_pos = 2; *b_pos = 3; *bytes = 4; // ARGB in memory. | |
| 405 } else if (fourcc == cricket::FOURCC_ARGB) { | |
| 406 *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 4; // BGRA in memory. | |
| 407 } else { | |
| 408 return false; | |
| 409 } | |
| 410 return true; | |
| 411 } | |
| 412 | |
| 413 // Comparison functions for testing. | |
| 414 static bool IsNull(const cricket::VideoFrame& frame) { | |
| 415 return !frame.video_frame_buffer(); | |
| 416 } | |
| 417 | |
| 418 static bool IsSize(const cricket::VideoFrame& frame, | |
| 419 int width, | |
| 420 int height) { | |
| 421 return !IsNull(frame) && frame.video_frame_buffer()->StrideY() >= width && | |
| 422 frame.video_frame_buffer()->StrideU() >= width / 2 && | |
| 423 frame.video_frame_buffer()->StrideV() >= width / 2 && | |
| 424 frame.width() == width && frame.height() == height; | |
| 425 } | |
| 426 | |
| 427 static bool IsPlaneEqual(const std::string& name, | |
| 428 const uint8_t* plane1, | |
| 429 uint32_t pitch1, | |
| 430 const uint8_t* plane2, | |
| 431 uint32_t pitch2, | |
| 432 uint32_t width, | |
| 433 uint32_t height, | |
| 434 int max_error) { | |
| 435 const uint8_t* r1 = plane1; | |
| 436 const uint8_t* r2 = plane2; | |
| 437 for (uint32_t y = 0; y < height; ++y) { | |
| 438 for (uint32_t x = 0; x < width; ++x) { | |
| 439 if (abs(static_cast<int>(r1[x] - r2[x])) > max_error) { | |
| 440 LOG(LS_INFO) << "IsPlaneEqual(" << name << "): pixel[" | |
| 441 << x << "," << y << "] differs: " | |
| 442 << static_cast<int>(r1[x]) << " vs " | |
| 443 << static_cast<int>(r2[x]); | |
| 444 return false; | |
| 445 } | |
| 446 } | |
| 447 r1 += pitch1; | |
| 448 r2 += pitch2; | |
| 449 } | |
| 450 return true; | |
| 451 } | |
| 452 | |
| 453 static bool IsEqual(const cricket::VideoFrame& frame, | |
| 454 int width, | |
| 455 int height, | |
| 456 int64_t time_stamp, | |
| 457 const uint8_t* y, | |
| 458 uint32_t ypitch, | |
| 459 const uint8_t* u, | |
| 460 uint32_t upitch, | |
| 461 const uint8_t* v, | |
| 462 uint32_t vpitch, | |
| 463 int max_error) { | |
| 464 return IsSize(frame, width, height) && frame.GetTimeStamp() == time_stamp && | |
| 465 IsPlaneEqual("y", frame.video_frame_buffer()->DataY(), | |
| 466 frame.video_frame_buffer()->StrideY(), y, ypitch, | |
| 467 static_cast<uint32_t>(width), | |
| 468 static_cast<uint32_t>(height), max_error) && | |
| 469 IsPlaneEqual("u", frame.video_frame_buffer()->DataU(), | |
| 470 frame.video_frame_buffer()->StrideU(), u, upitch, | |
| 471 static_cast<uint32_t>((width + 1) / 2), | |
| 472 static_cast<uint32_t>((height + 1) / 2), max_error) && | |
| 473 IsPlaneEqual("v", frame.video_frame_buffer()->DataV(), | |
| 474 frame.video_frame_buffer()->StrideV(), v, vpitch, | |
| 475 static_cast<uint32_t>((width + 1) / 2), | |
| 476 static_cast<uint32_t>((height + 1) / 2), max_error); | |
| 477 } | |
| 478 | |
| 479 static bool IsEqual(const cricket::VideoFrame& frame1, | |
| 480 const cricket::VideoFrame& frame2, | |
| 481 int max_error) { | |
| 482 return IsEqual(frame1, | |
| 483 frame2.width(), frame2.height(), | |
| 484 frame2.GetTimeStamp(), | |
| 485 frame2.video_frame_buffer()->DataY(), | |
| 486 frame2.video_frame_buffer()->StrideY(), | |
| 487 frame2.video_frame_buffer()->DataU(), | |
| 488 frame2.video_frame_buffer()->StrideU(), | |
| 489 frame2.video_frame_buffer()->DataV(), | |
| 490 frame2.video_frame_buffer()->StrideV(), | |
| 491 max_error); | |
| 492 } | |
| 493 | |
| 494 static bool IsEqualWithCrop(const cricket::VideoFrame& frame1, | |
| 495 const cricket::VideoFrame& frame2, | |
| 496 int hcrop, int vcrop, int max_error) { | |
| 497 return frame1.width() <= frame2.width() && | |
| 498 frame1.height() <= frame2.height() && | |
| 499 IsEqual(frame1, | |
| 500 frame2.width() - hcrop * 2, | |
| 501 frame2.height() - vcrop * 2, | |
| 502 frame2.GetTimeStamp(), | |
| 503 frame2.video_frame_buffer()->DataY() | |
| 504 + vcrop * frame2.video_frame_buffer()->StrideY() | |
| 505 + hcrop, | |
| 506 frame2.video_frame_buffer()->StrideY(), | |
| 507 frame2.video_frame_buffer()->DataU() | |
| 508 + vcrop * frame2.video_frame_buffer()->StrideU() / 2 | |
| 509 + hcrop / 2, | |
| 510 frame2.video_frame_buffer()->StrideU(), | |
| 511 frame2.video_frame_buffer()->DataV() | |
| 512 + vcrop * frame2.video_frame_buffer()->StrideV() / 2 | |
| 513 + hcrop / 2, | |
| 514 frame2.video_frame_buffer()->StrideV(), | |
| 515 max_error); | |
| 516 } | |
| 517 | |
| 518 static bool IsBlack(const cricket::VideoFrame& frame) { | |
| 519 return !IsNull(frame) && | |
| 520 *frame.video_frame_buffer()->DataY() <= 16 && | |
| 521 *frame.video_frame_buffer()->DataU() == 128 && | |
| 522 *frame.video_frame_buffer()->DataV() == 128; | |
| 523 } | |
| 524 | |
| 525 //////////////////////// | |
| 526 // Construction tests // | |
| 527 //////////////////////// | |
| 528 | |
| 529 // Test constructing an image from a I420 buffer. | |
| 530 void ConstructI420() { | |
| 531 T frame; | |
| 532 EXPECT_TRUE(IsNull(frame)); | |
| 533 std::unique_ptr<rtc::MemoryStream> ms( | |
| 534 CreateYuvSample(kWidth, kHeight, 12)); | |
| 535 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, | |
| 536 kWidth, kHeight, &frame)); | |
| 537 | |
| 538 const uint8_t* y = reinterpret_cast<uint8_t*>(ms.get()->GetBuffer()); | |
| 539 const uint8_t* u = y + kWidth * kHeight; | |
| 540 const uint8_t* v = u + kWidth * kHeight / 4; | |
| 541 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 0, y, kWidth, u, | |
| 542 kWidth / 2, v, kWidth / 2, 0)); | |
| 543 } | |
| 544 | |
| 545 // Test constructing an image from a YV12 buffer. | |
| 546 void ConstructYV12() { | |
| 547 T frame; | |
| 548 std::unique_ptr<rtc::MemoryStream> ms( | |
| 549 CreateYuvSample(kWidth, kHeight, 12)); | |
| 550 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YV12, | |
| 551 kWidth, kHeight, &frame)); | |
| 552 | |
| 553 const uint8_t* y = reinterpret_cast<uint8_t*>(ms.get()->GetBuffer()); | |
| 554 const uint8_t* v = y + kWidth * kHeight; | |
| 555 const uint8_t* u = v + kWidth * kHeight / 4; | |
| 556 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 0, y, kWidth, u, | |
| 557 kWidth / 2, v, kWidth / 2, 0)); | |
| 558 } | |
| 559 | |
| 560 // Test constructing an image from a I422 buffer. | |
| 561 void ConstructI422() { | |
| 562 T frame1, frame2; | |
| 563 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 564 size_t buf_size = kWidth * kHeight * 2; | |
| 565 std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size + kAlignment]); | |
| 566 uint8_t* y = ALIGNP(buf.get(), kAlignment); | |
| 567 uint8_t* u = y + kWidth * kHeight; | |
| 568 uint8_t* v = u + (kWidth / 2) * kHeight; | |
| 569 EXPECT_EQ(0, libyuv::I420ToI422(frame1.video_frame_buffer()->DataY(), | |
| 570 frame1.video_frame_buffer()->StrideY(), | |
| 571 frame1.video_frame_buffer()->DataU(), | |
| 572 frame1.video_frame_buffer()->StrideU(), | |
| 573 frame1.video_frame_buffer()->DataV(), | |
| 574 frame1.video_frame_buffer()->StrideV(), | |
| 575 y, kWidth, | |
| 576 u, kWidth / 2, | |
| 577 v, kWidth / 2, | |
| 578 kWidth, kHeight)); | |
| 579 EXPECT_TRUE(LoadFrame(y, buf_size, cricket::FOURCC_I422, | |
| 580 kWidth, kHeight, &frame2)); | |
| 581 EXPECT_TRUE(IsEqual(frame1, frame2, 1)); | |
| 582 } | |
| 583 | |
| 584 // Test constructing an image from a YUY2 buffer. | |
| 585 void ConstructYuy2() { | |
| 586 T frame1, frame2; | |
| 587 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 588 size_t buf_size = kWidth * kHeight * 2; | |
| 589 std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size + kAlignment]); | |
| 590 uint8_t* yuy2 = ALIGNP(buf.get(), kAlignment); | |
| 591 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.video_frame_buffer()->DataY(), | |
| 592 frame1.video_frame_buffer()->StrideY(), | |
| 593 frame1.video_frame_buffer()->DataU(), | |
| 594 frame1.video_frame_buffer()->StrideU(), | |
| 595 frame1.video_frame_buffer()->DataV(), | |
| 596 frame1.video_frame_buffer()->StrideV(), | |
| 597 yuy2, kWidth * 2, | |
| 598 kWidth, kHeight)); | |
| 599 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2, | |
| 600 kWidth, kHeight, &frame2)); | |
| 601 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 602 } | |
| 603 | |
| 604 // Test constructing an image from a YUY2 buffer with buffer unaligned. | |
| 605 void ConstructYuy2Unaligned() { | |
| 606 T frame1, frame2; | |
| 607 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 608 size_t buf_size = kWidth * kHeight * 2; | |
| 609 std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size + kAlignment + 1]); | |
| 610 uint8_t* yuy2 = ALIGNP(buf.get(), kAlignment) + 1; | |
| 611 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.video_frame_buffer()->DataY(), | |
| 612 frame1.video_frame_buffer()->StrideY(), | |
| 613 frame1.video_frame_buffer()->DataU(), | |
| 614 frame1.video_frame_buffer()->StrideU(), | |
| 615 frame1.video_frame_buffer()->DataV(), | |
| 616 frame1.video_frame_buffer()->StrideV(), | |
| 617 yuy2, kWidth * 2, | |
| 618 kWidth, kHeight)); | |
| 619 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2, | |
| 620 kWidth, kHeight, &frame2)); | |
| 621 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 622 } | |
| 623 | |
| 624 // Test constructing an image from a wide YUY2 buffer. | |
| 625 // Normal is 1280x720. Wide is 12800x72 | |
| 626 void ConstructYuy2Wide() { | |
| 627 std::unique_ptr<rtc::MemoryStream> ms( | |
| 628 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth * 10, kHeight / 10)); | |
| 629 ASSERT_TRUE(ms.get() != NULL); | |
| 630 std::unique_ptr<T> frame1 = ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, | |
| 631 kWidth * 10, kHeight / 10); | |
| 632 ASSERT_TRUE(frame1); | |
| 633 T frame2; | |
| 634 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, | |
| 635 kWidth * 10, kHeight / 10, &frame2)); | |
| 636 EXPECT_TRUE(IsEqual(*frame1, frame2, 0)); | |
| 637 } | |
| 638 | |
| 639 // Test constructing an image from a UYVY buffer. | |
| 640 void ConstructUyvy() { | |
| 641 std::unique_ptr<rtc::MemoryStream> ms( | |
| 642 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); | |
| 643 ASSERT_TRUE(ms.get() != NULL); | |
| 644 std::unique_ptr<T> frame1 = ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, | |
| 645 kWidth, kHeight); | |
| 646 T frame2; | |
| 647 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, | |
| 648 kWidth, kHeight, &frame2)); | |
| 649 EXPECT_TRUE(IsEqual(*frame1, frame2, 0)); | |
| 650 } | |
| 651 | |
| 652 // Test constructing an image from a random buffer. | |
| 653 // We are merely verifying that the code succeeds and is free of crashes. | |
| 654 void ConstructM420() { | |
| 655 T frame; | |
| 656 std::unique_ptr<rtc::MemoryStream> ms( | |
| 657 CreateYuvSample(kWidth, kHeight, 12)); | |
| 658 ASSERT_TRUE(ms.get() != NULL); | |
| 659 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_M420, | |
| 660 kWidth, kHeight, &frame)); | |
| 661 } | |
| 662 | |
| 663 void ConstructNV21() { | |
| 664 T frame; | |
| 665 std::unique_ptr<rtc::MemoryStream> ms( | |
| 666 CreateYuvSample(kWidth, kHeight, 12)); | |
| 667 ASSERT_TRUE(ms.get() != NULL); | |
| 668 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV21, | |
| 669 kWidth, kHeight, &frame)); | |
| 670 } | |
| 671 | |
| 672 void ConstructNV12() { | |
| 673 T frame; | |
| 674 std::unique_ptr<rtc::MemoryStream> ms( | |
| 675 CreateYuvSample(kWidth, kHeight, 12)); | |
| 676 ASSERT_TRUE(ms.get() != NULL); | |
| 677 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV12, | |
| 678 kWidth, kHeight, &frame)); | |
| 679 } | |
| 680 | |
| 681 // Test constructing an image from a ABGR buffer | |
| 682 // Due to rounding, some pixels may differ slightly from the VideoFrame impl. | |
| 683 void ConstructABGR() { | |
| 684 std::unique_ptr<rtc::MemoryStream> ms( | |
| 685 CreateRgbSample(cricket::FOURCC_ABGR, kWidth, kHeight)); | |
| 686 ASSERT_TRUE(ms.get() != NULL); | |
| 687 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ABGR, | |
| 688 kWidth, kHeight); | |
| 689 ASSERT_TRUE(frame1); | |
| 690 T frame2; | |
| 691 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ABGR, | |
| 692 kWidth, kHeight, &frame2)); | |
| 693 EXPECT_TRUE(IsEqual(*frame1, frame2, 2)); | |
| 694 } | |
| 695 | |
| 696 // Test constructing an image from a ARGB buffer | |
| 697 // Due to rounding, some pixels may differ slightly from the VideoFrame impl. | |
| 698 void ConstructARGB() { | |
| 699 std::unique_ptr<rtc::MemoryStream> ms( | |
| 700 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); | |
| 701 ASSERT_TRUE(ms.get() != NULL); | |
| 702 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB, | |
| 703 kWidth, kHeight); | |
| 704 ASSERT_TRUE(frame1); | |
| 705 T frame2; | |
| 706 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, | |
| 707 kWidth, kHeight, &frame2)); | |
| 708 EXPECT_TRUE(IsEqual(*frame1, frame2, 2)); | |
| 709 } | |
| 710 | |
| 711 // Test constructing an image from a wide ARGB buffer | |
| 712 // Normal is 1280x720. Wide is 12800x72 | |
| 713 void ConstructARGBWide() { | |
| 714 std::unique_ptr<rtc::MemoryStream> ms( | |
| 715 CreateRgbSample(cricket::FOURCC_ARGB, kWidth * 10, kHeight / 10)); | |
| 716 ASSERT_TRUE(ms.get() != NULL); | |
| 717 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB, | |
| 718 kWidth * 10, kHeight / 10); | |
| 719 ASSERT_TRUE(frame1); | |
| 720 T frame2; | |
| 721 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, | |
| 722 kWidth * 10, kHeight / 10, &frame2)); | |
| 723 EXPECT_TRUE(IsEqual(*frame1, frame2, 2)); | |
| 724 } | |
| 725 | |
| 726 // Test constructing an image from an BGRA buffer. | |
| 727 // Due to rounding, some pixels may differ slightly from the VideoFrame impl. | |
| 728 void ConstructBGRA() { | |
| 729 std::unique_ptr<rtc::MemoryStream> ms( | |
| 730 CreateRgbSample(cricket::FOURCC_BGRA, kWidth, kHeight)); | |
| 731 ASSERT_TRUE(ms.get() != NULL); | |
| 732 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_BGRA, | |
| 733 kWidth, kHeight); | |
| 734 ASSERT_TRUE(frame1); | |
| 735 T frame2; | |
| 736 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_BGRA, | |
| 737 kWidth, kHeight, &frame2)); | |
| 738 EXPECT_TRUE(IsEqual(*frame1, frame2, 2)); | |
| 739 } | |
| 740 | |
| 741 // Test constructing an image from a 24BG buffer. | |
| 742 // Due to rounding, some pixels may differ slightly from the VideoFrame impl. | |
| 743 void Construct24BG() { | |
| 744 std::unique_ptr<rtc::MemoryStream> ms( | |
| 745 CreateRgbSample(cricket::FOURCC_24BG, kWidth, kHeight)); | |
| 746 ASSERT_TRUE(ms.get() != NULL); | |
| 747 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_24BG, | |
| 748 kWidth, kHeight); | |
| 749 ASSERT_TRUE(frame1); | |
| 750 T frame2; | |
| 751 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_24BG, | |
| 752 kWidth, kHeight, &frame2)); | |
| 753 EXPECT_TRUE(IsEqual(*frame1, frame2, 2)); | |
| 754 } | |
| 755 | |
| 756 // Test constructing an image from a raw RGB buffer. | |
| 757 // Due to rounding, some pixels may differ slightly from the VideoFrame impl. | |
| 758 void ConstructRaw() { | |
| 759 std::unique_ptr<rtc::MemoryStream> ms( | |
| 760 CreateRgbSample(cricket::FOURCC_RAW, kWidth, kHeight)); | |
| 761 ASSERT_TRUE(ms.get() != NULL); | |
| 762 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_RAW, | |
| 763 kWidth, kHeight); | |
| 764 ASSERT_TRUE(frame1); | |
| 765 T frame2; | |
| 766 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_RAW, | |
| 767 kWidth, kHeight, &frame2)); | |
| 768 EXPECT_TRUE(IsEqual(*frame1, frame2, 2)); | |
| 769 } | |
| 770 | |
| 771 // Macro to help test different rotations | |
| 772 #define TEST_MIRROR(FOURCC, BPP) \ | |
| 773 void Construct##FOURCC##Mirror() { \ | |
| 774 T frame1, frame2, frame3; \ | |
| 775 std::unique_ptr<rtc::MemoryStream> ms( \ | |
| 776 CreateYuvSample(kWidth, kHeight, BPP)); \ | |
| 777 ASSERT_TRUE(ms.get() != NULL); \ | |
| 778 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, kWidth, \ | |
| 779 -kHeight, kWidth, kHeight, \ | |
| 780 webrtc::kVideoRotation_180, &frame1)); \ | |
| 781 size_t data_size; \ | |
| 782 bool ret = ms->GetSize(&data_size); \ | |
| 783 EXPECT_TRUE(ret); \ | |
| 784 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, kWidth, kHeight, kWidth, \ | |
| 785 kHeight, \ | |
| 786 reinterpret_cast<uint8_t*>(ms->GetBuffer()), \ | |
| 787 data_size, 0, webrtc::kVideoRotation_0)); \ | |
| 788 int width_rotate = frame1.width(); \ | |
| 789 int height_rotate = frame1.height(); \ | |
| 790 frame3.InitToEmptyBuffer(width_rotate, height_rotate); \ | |
| 791 libyuv::I420Mirror(frame2.video_frame_buffer()->DataY(), \ | |
| 792 frame2.video_frame_buffer()->StrideY(), \ | |
| 793 frame2.video_frame_buffer()->DataU(), \ | |
| 794 frame2.video_frame_buffer()->StrideU(), \ | |
| 795 frame2.video_frame_buffer()->DataV(), \ | |
| 796 frame2.video_frame_buffer()->StrideV(), \ | |
| 797 frame3.video_frame_buffer()->MutableDataY(), \ | |
| 798 frame3.video_frame_buffer()->StrideY(), \ | |
| 799 frame3.video_frame_buffer()->MutableDataU(), \ | |
| 800 frame3.video_frame_buffer()->StrideU(), \ | |
| 801 frame3.video_frame_buffer()->MutableDataV(), \ | |
| 802 frame3.video_frame_buffer()->StrideV(), kWidth, \ | |
| 803 kHeight); \ | |
| 804 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \ | |
| 805 } | |
| 806 | |
| 807 TEST_MIRROR(I420, 420) | |
| 808 | |
| 809 // Macro to help test different rotations | |
| 810 #define TEST_ROTATE(FOURCC, BPP, ROTATE) \ | |
| 811 void Construct##FOURCC##Rotate##ROTATE() { \ | |
| 812 T frame1, frame2, frame3; \ | |
| 813 std::unique_ptr<rtc::MemoryStream> ms( \ | |
| 814 CreateYuvSample(kWidth, kHeight, BPP)); \ | |
| 815 ASSERT_TRUE(ms.get() != NULL); \ | |
| 816 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, kWidth, kHeight, \ | |
| 817 kWidth, kHeight, webrtc::kVideoRotation_##ROTATE, \ | |
| 818 &frame1)); \ | |
| 819 size_t data_size; \ | |
| 820 bool ret = ms->GetSize(&data_size); \ | |
| 821 EXPECT_TRUE(ret); \ | |
| 822 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, kWidth, kHeight, kWidth, \ | |
| 823 kHeight, \ | |
| 824 reinterpret_cast<uint8_t*>(ms->GetBuffer()), \ | |
| 825 data_size, 0, webrtc::kVideoRotation_0)); \ | |
| 826 int width_rotate = frame1.width(); \ | |
| 827 int height_rotate = frame1.height(); \ | |
| 828 frame3.InitToEmptyBuffer(width_rotate, height_rotate); \ | |
| 829 libyuv::I420Rotate(frame2.video_frame_buffer()->DataY(), \ | |
| 830 frame2.video_frame_buffer()->StrideY(), \ | |
| 831 frame2.video_frame_buffer()->DataU(), \ | |
| 832 frame2.video_frame_buffer()->StrideU(), \ | |
| 833 frame2.video_frame_buffer()->DataV(), \ | |
| 834 frame2.video_frame_buffer()->StrideV(), \ | |
| 835 frame3.video_frame_buffer()->MutableDataY(), \ | |
| 836 frame3.video_frame_buffer()->StrideY(), \ | |
| 837 frame3.video_frame_buffer()->MutableDataU(), \ | |
| 838 frame3.video_frame_buffer()->StrideU(), \ | |
| 839 frame3.video_frame_buffer()->MutableDataV(), \ | |
| 840 frame3.video_frame_buffer()->StrideV(), kWidth, \ | |
| 841 kHeight, libyuv::kRotate##ROTATE); \ | |
| 842 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \ | |
| 843 } | |
| 844 | |
| 845 // Test constructing an image with rotation. | |
| 846 TEST_ROTATE(I420, 12, 0) | |
| 847 TEST_ROTATE(I420, 12, 90) | |
| 848 TEST_ROTATE(I420, 12, 180) | |
| 849 TEST_ROTATE(I420, 12, 270) | |
| 850 TEST_ROTATE(YV12, 12, 0) | |
| 851 TEST_ROTATE(YV12, 12, 90) | |
| 852 TEST_ROTATE(YV12, 12, 180) | |
| 853 TEST_ROTATE(YV12, 12, 270) | |
| 854 TEST_ROTATE(NV12, 12, 0) | |
| 855 TEST_ROTATE(NV12, 12, 90) | |
| 856 TEST_ROTATE(NV12, 12, 180) | |
| 857 TEST_ROTATE(NV12, 12, 270) | |
| 858 TEST_ROTATE(NV21, 12, 0) | |
| 859 TEST_ROTATE(NV21, 12, 90) | |
| 860 TEST_ROTATE(NV21, 12, 180) | |
| 861 TEST_ROTATE(NV21, 12, 270) | |
| 862 TEST_ROTATE(UYVY, 16, 0) | |
| 863 TEST_ROTATE(UYVY, 16, 90) | |
| 864 TEST_ROTATE(UYVY, 16, 180) | |
| 865 TEST_ROTATE(UYVY, 16, 270) | |
| 866 TEST_ROTATE(YUY2, 16, 0) | |
| 867 TEST_ROTATE(YUY2, 16, 90) | |
| 868 TEST_ROTATE(YUY2, 16, 180) | |
| 869 TEST_ROTATE(YUY2, 16, 270) | |
| 870 | |
| 871 // Test constructing an image from a UYVY buffer rotated 90 degrees. | |
| 872 void ConstructUyvyRotate90() { | |
| 873 T frame2; | |
| 874 std::unique_ptr<rtc::MemoryStream> ms( | |
| 875 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); | |
| 876 ASSERT_TRUE(ms.get() != NULL); | |
| 877 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight, | |
| 878 kWidth, kHeight, webrtc::kVideoRotation_90, &frame2)); | |
| 879 } | |
| 880 | |
| 881 // Test constructing an image from a UYVY buffer rotated 180 degrees. | |
| 882 void ConstructUyvyRotate180() { | |
| 883 T frame2; | |
| 884 std::unique_ptr<rtc::MemoryStream> ms( | |
| 885 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); | |
| 886 ASSERT_TRUE(ms.get() != NULL); | |
| 887 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight, | |
| 888 kWidth, kHeight, webrtc::kVideoRotation_180, | |
| 889 &frame2)); | |
| 890 } | |
| 891 | |
| 892 // Test constructing an image from a UYVY buffer rotated 270 degrees. | |
| 893 void ConstructUyvyRotate270() { | |
| 894 T frame2; | |
| 895 std::unique_ptr<rtc::MemoryStream> ms( | |
| 896 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); | |
| 897 ASSERT_TRUE(ms.get() != NULL); | |
| 898 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight, | |
| 899 kWidth, kHeight, webrtc::kVideoRotation_270, | |
| 900 &frame2)); | |
| 901 } | |
| 902 | |
| 903 // Test constructing an image from a YUY2 buffer rotated 90 degrees. | |
| 904 void ConstructYuy2Rotate90() { | |
| 905 T frame2; | |
| 906 std::unique_ptr<rtc::MemoryStream> ms( | |
| 907 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); | |
| 908 ASSERT_TRUE(ms.get() != NULL); | |
| 909 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, | |
| 910 kWidth, kHeight, webrtc::kVideoRotation_90, &frame2)); | |
| 911 } | |
| 912 | |
| 913 // Test constructing an image from a YUY2 buffer rotated 180 degrees. | |
| 914 void ConstructYuy2Rotate180() { | |
| 915 T frame2; | |
| 916 std::unique_ptr<rtc::MemoryStream> ms( | |
| 917 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); | |
| 918 ASSERT_TRUE(ms.get() != NULL); | |
| 919 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, | |
| 920 kWidth, kHeight, webrtc::kVideoRotation_180, | |
| 921 &frame2)); | |
| 922 } | |
| 923 | |
| 924 // Test constructing an image from a YUY2 buffer rotated 270 degrees. | |
| 925 void ConstructYuy2Rotate270() { | |
| 926 T frame2; | |
| 927 std::unique_ptr<rtc::MemoryStream> ms( | |
| 928 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); | |
| 929 ASSERT_TRUE(ms.get() != NULL); | |
| 930 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, | |
| 931 kWidth, kHeight, webrtc::kVideoRotation_270, | |
| 932 &frame2)); | |
| 933 } | |
| 934 | |
| 935 // Test 1 pixel edge case image I420 buffer. | |
| 936 void ConstructI4201Pixel() { | |
| 937 T frame; | |
| 938 uint8_t pixel[3] = {1, 2, 3}; | |
| 939 for (int i = 0; i < repeat_; ++i) { | |
| 940 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1, pixel, | |
| 941 sizeof(pixel), 0, webrtc::kVideoRotation_0)); | |
| 942 } | |
| 943 const uint8_t* y = pixel; | |
| 944 const uint8_t* u = y + 1; | |
| 945 const uint8_t* v = u + 1; | |
| 946 EXPECT_TRUE(IsEqual(frame, 1, 1, 0, y, 1, u, 1, v, 1, 0)); | |
| 947 } | |
| 948 | |
| 949 // Test 5 pixel edge case image. | |
| 950 void ConstructI4205Pixel() { | |
| 951 T frame; | |
| 952 uint8_t pixels5x5[5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2]; | |
| 953 memset(pixels5x5, 1, 5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2); | |
| 954 for (int i = 0; i < repeat_; ++i) { | |
| 955 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 5, 5, 5, 5, pixels5x5, | |
| 956 sizeof(pixels5x5), 0, | |
| 957 webrtc::kVideoRotation_0)); | |
| 958 } | |
| 959 EXPECT_EQ(5, frame.width()); | |
| 960 EXPECT_EQ(5, frame.height()); | |
| 961 EXPECT_EQ(5, frame.video_frame_buffer()->StrideY()); | |
| 962 EXPECT_EQ(3, frame.video_frame_buffer()->StrideU()); | |
| 963 EXPECT_EQ(3, frame.video_frame_buffer()->StrideV()); | |
| 964 } | |
| 965 | |
| 966 // Test constructing an image from an I420 buffer with horizontal cropping. | |
| 967 void ConstructI420CropHorizontal() { | |
| 968 T frame1, frame2; | |
| 969 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 970 ASSERT_TRUE(LoadFrame(kImageFilename, kYuvExtension, | |
| 971 cricket::FOURCC_I420, kWidth, kHeight, | |
| 972 kWidth * 3 / 4, kHeight, webrtc::kVideoRotation_0, | |
| 973 &frame2)); | |
| 974 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0)); | |
| 975 } | |
| 976 | |
| 977 // Test constructing an image from a YUY2 buffer with horizontal cropping. | |
| 978 void ConstructYuy2CropHorizontal() { | |
| 979 T frame1, frame2; | |
| 980 std::unique_ptr<rtc::MemoryStream> ms( | |
| 981 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); | |
| 982 ASSERT_TRUE(ms.get() != NULL); | |
| 983 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, | |
| 984 &frame1)); | |
| 985 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, | |
| 986 kWidth * 3 / 4, kHeight, webrtc::kVideoRotation_0, | |
| 987 &frame2)); | |
| 988 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0)); | |
| 989 } | |
| 990 | |
| 991 // Test constructing an image from an ARGB buffer with horizontal cropping. | |
| 992 void ConstructARGBCropHorizontal() { | |
| 993 std::unique_ptr<rtc::MemoryStream> ms( | |
| 994 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); | |
| 995 ASSERT_TRUE(ms.get() != NULL); | |
| 996 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB, | |
| 997 kWidth, kHeight); | |
| 998 ASSERT_TRUE(frame1); | |
| 999 T frame2; | |
| 1000 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight, | |
| 1001 kWidth * 3 / 4, kHeight, webrtc::kVideoRotation_0, | |
| 1002 &frame2)); | |
| 1003 EXPECT_TRUE(IsEqualWithCrop(frame2, *frame1, kWidth / 8, 0, 2)); | |
| 1004 } | |
| 1005 | |
| 1006 // Test constructing an image from an I420 buffer, cropping top and bottom. | |
| 1007 void ConstructI420CropVertical() { | |
| 1008 T frame1, frame2; | |
| 1009 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1010 ASSERT_TRUE(LoadFrame(LoadSample(kImageFilename, kYuvExtension).get(), | |
| 1011 cricket::FOURCC_I420, kWidth, kHeight, | |
| 1012 kWidth, kHeight * 3 / 4, webrtc::kVideoRotation_0, | |
| 1013 &frame2)); | |
| 1014 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, 0, kHeight / 8, 0)); | |
| 1015 } | |
| 1016 | |
| 1017 // Test constructing an image from I420 synonymous formats. | |
| 1018 void ConstructI420Aliases() { | |
| 1019 T frame1, frame2, frame3; | |
| 1020 ASSERT_TRUE(LoadFrame(LoadSample(kImageFilename, kYuvExtension), | |
| 1021 cricket::FOURCC_I420, kWidth, kHeight, | |
| 1022 &frame1)); | |
| 1023 ASSERT_TRUE(LoadFrame(kImageFilename, kYuvExtension, | |
| 1024 cricket::FOURCC_IYUV, kWidth, kHeight, | |
| 1025 &frame2)); | |
| 1026 ASSERT_TRUE(LoadFrame(kImageFilename, kYuvExtension, | |
| 1027 cricket::FOURCC_YU12, kWidth, kHeight, | |
| 1028 &frame3)); | |
| 1029 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 1030 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); | |
| 1031 } | |
| 1032 | |
| 1033 // Test constructing an image from an I420 MJPG buffer. | |
| 1034 void ConstructMjpgI420() { | |
| 1035 T frame1, frame2; | |
| 1036 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1037 ASSERT_TRUE(LoadFrame(kJpeg420Filename, kJpegExtension, | |
| 1038 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); | |
| 1039 EXPECT_TRUE(IsEqual(frame1, frame2, 32)); | |
| 1040 } | |
| 1041 | |
| 1042 // Test constructing an image from an I422 MJPG buffer. | |
| 1043 void ConstructMjpgI422() { | |
| 1044 T frame1, frame2; | |
| 1045 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1046 ASSERT_TRUE(LoadFrame(LoadSample(kJpeg422Filename, kJpegExtension).get(), | |
| 1047 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); | |
| 1048 EXPECT_TRUE(IsEqual(frame1, frame2, 32)); | |
| 1049 } | |
| 1050 | |
| 1051 // Test constructing an image from an I444 MJPG buffer. | |
| 1052 void ConstructMjpgI444() { | |
| 1053 T frame1, frame2; | |
| 1054 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1055 ASSERT_TRUE(LoadFrame(LoadSample(kJpeg444Filename, kJpegExtension), | |
| 1056 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); | |
| 1057 EXPECT_TRUE(IsEqual(frame1, frame2, 32)); | |
| 1058 } | |
| 1059 | |
| 1060 // Test constructing an image from an I444 MJPG buffer. | |
| 1061 void ConstructMjpgI411() { | |
| 1062 T frame1, frame2; | |
| 1063 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1064 ASSERT_TRUE(LoadFrame(kJpeg411Filename, kJpegExtension, | |
| 1065 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); | |
| 1066 EXPECT_TRUE(IsEqual(frame1, frame2, 32)); | |
| 1067 } | |
| 1068 | |
| 1069 // Test constructing an image from an I400 MJPG buffer. | |
| 1070 // TODO(fbarchard): Stronger compare on chroma. Compare agaisnt a grey image. | |
| 1071 void ConstructMjpgI400() { | |
| 1072 T frame1, frame2; | |
| 1073 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1074 ASSERT_TRUE(LoadFrame(kJpeg400Filename, kJpegExtension, | |
| 1075 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); | |
| 1076 EXPECT_TRUE(IsPlaneEqual("y", frame1.video_frame_buffer()->DataY(), | |
| 1077 frame1.video_frame_buffer()->StrideY(), | |
| 1078 frame2.video_frame_buffer()->DataY(), | |
| 1079 frame2.video_frame_buffer()->StrideY(), | |
| 1080 kWidth, kHeight, 32)); | |
| 1081 EXPECT_TRUE(IsEqual(frame1, frame2, 128)); | |
| 1082 } | |
| 1083 | |
| 1084 // Test constructing an image from an I420 MJPG buffer. | |
| 1085 void ValidateFrame(const char* name, | |
| 1086 const char* extension, | |
| 1087 uint32_t fourcc, | |
| 1088 int data_adjust, | |
| 1089 int size_adjust, | |
| 1090 bool expected_result) { | |
| 1091 T frame; | |
| 1092 std::unique_ptr<rtc::MemoryStream> ms(LoadSample(name, extension)); | |
| 1093 ASSERT_TRUE(ms.get() != NULL); | |
| 1094 const uint8_t* sample = | |
| 1095 reinterpret_cast<const uint8_t*>(ms.get()->GetBuffer()); | |
| 1096 size_t sample_size; | |
| 1097 ms->GetSize(&sample_size); | |
| 1098 // Optional adjust size to test invalid size. | |
| 1099 size_t data_size = sample_size + data_adjust; | |
| 1100 | |
| 1101 // Allocate a buffer with end page aligned. | |
| 1102 const int kPadToHeapSized = 16 * 1024 * 1024; | |
| 1103 std::unique_ptr<uint8_t[]> page_buffer( | |
| 1104 new uint8_t[((data_size + kPadToHeapSized + 4095) & ~4095)]); | |
| 1105 uint8_t* data_ptr = page_buffer.get(); | |
| 1106 if (!data_ptr) { | |
| 1107 LOG(LS_WARNING) << "Failed to allocate memory for ValidateFrame test."; | |
| 1108 EXPECT_FALSE(expected_result); // NULL is okay if failure was expected. | |
| 1109 return; | |
| 1110 } | |
| 1111 data_ptr += kPadToHeapSized + (-(static_cast<int>(data_size)) & 4095); | |
| 1112 memcpy(data_ptr, sample, std::min(data_size, sample_size)); | |
| 1113 for (int i = 0; i < repeat_; ++i) { | |
| 1114 EXPECT_EQ(expected_result, frame.Validate(fourcc, kWidth, kHeight, | |
| 1115 data_ptr, | |
| 1116 sample_size + size_adjust)); | |
| 1117 } | |
| 1118 } | |
| 1119 | |
| 1120 // Test validate for I420 MJPG buffer. | |
| 1121 void ValidateMjpgI420() { | |
| 1122 ValidateFrame(kJpeg420Filename, kJpegExtension, | |
| 1123 cricket::FOURCC_MJPG, 0, 0, true); | |
| 1124 } | |
| 1125 | |
| 1126 // Test validate for I422 MJPG buffer. | |
| 1127 void ValidateMjpgI422() { | |
| 1128 ValidateFrame(kJpeg422Filename, kJpegExtension, | |
| 1129 cricket::FOURCC_MJPG, 0, 0, true); | |
| 1130 } | |
| 1131 | |
| 1132 // Test validate for I444 MJPG buffer. | |
| 1133 void ValidateMjpgI444() { | |
| 1134 ValidateFrame(kJpeg444Filename, kJpegExtension, | |
| 1135 cricket::FOURCC_MJPG, 0, 0, true); | |
| 1136 } | |
| 1137 | |
| 1138 // Test validate for I411 MJPG buffer. | |
| 1139 void ValidateMjpgI411() { | |
| 1140 ValidateFrame(kJpeg411Filename, kJpegExtension, | |
| 1141 cricket::FOURCC_MJPG, 0, 0, true); | |
| 1142 } | |
| 1143 | |
| 1144 // Test validate for I400 MJPG buffer. | |
| 1145 void ValidateMjpgI400() { | |
| 1146 ValidateFrame(kJpeg400Filename, kJpegExtension, | |
| 1147 cricket::FOURCC_MJPG, 0, 0, true); | |
| 1148 } | |
| 1149 | |
| 1150 // Test validate for I420 buffer. | |
| 1151 void ValidateI420() { | |
| 1152 ValidateFrame(kImageFilename, kYuvExtension, | |
| 1153 cricket::FOURCC_I420, 0, 0, true); | |
| 1154 } | |
| 1155 | |
| 1156 // Test validate for I420 buffer where size is too small | |
| 1157 void ValidateI420SmallSize() { | |
| 1158 ValidateFrame(kImageFilename, kYuvExtension, | |
| 1159 cricket::FOURCC_I420, 0, -16384, false); | |
| 1160 } | |
| 1161 | |
| 1162 // Test validate for I420 buffer where size is too large (16 MB) | |
| 1163 // Will produce warning but pass. | |
| 1164 void ValidateI420LargeSize() { | |
| 1165 ValidateFrame(kImageFilename, kYuvExtension, | |
| 1166 cricket::FOURCC_I420, 16000000, 16000000, | |
| 1167 true); | |
| 1168 } | |
| 1169 | |
| 1170 // Test validate for I420 buffer where size is 1 GB (not reasonable). | |
| 1171 void ValidateI420HugeSize() { | |
| 1172 #ifndef WIN32 // TODO(fbarchard): Reenable when fixing bug 9603762. | |
| 1173 ValidateFrame(kImageFilename, kYuvExtension, | |
| 1174 cricket::FOURCC_I420, 1000000000u, | |
| 1175 1000000000u, false); | |
| 1176 #endif | |
| 1177 } | |
| 1178 | |
| 1179 // The following test that Validate crashes if the size is greater than the | |
| 1180 // actual buffer size. | |
| 1181 // TODO(fbarchard): Consider moving a filter into the capturer/plugin. | |
| 1182 #if defined(_MSC_VER) && !defined(NDEBUG) | |
| 1183 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) { | |
| 1184 if (code == EXCEPTION_ACCESS_VIOLATION) { | |
| 1185 LOG(LS_INFO) << "Caught EXCEPTION_ACCESS_VIOLATION as expected."; | |
| 1186 return EXCEPTION_EXECUTE_HANDLER; | |
| 1187 } else { | |
| 1188 LOG(LS_INFO) << "Did not catch EXCEPTION_ACCESS_VIOLATION. Unexpected."; | |
| 1189 return EXCEPTION_CONTINUE_SEARCH; | |
| 1190 } | |
| 1191 } | |
| 1192 | |
| 1193 // Test validate fails for truncated MJPG data buffer. If ValidateFrame | |
| 1194 // crashes the exception handler will return and unittest passes with OK. | |
| 1195 void ValidateMjpgI420InvalidSize() { | |
| 1196 __try { | |
| 1197 ValidateFrame(kJpeg420Filename, kJpegExtension, | |
| 1198 cricket::FOURCC_MJPG, -16384, 0, false); | |
| 1199 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION."; | |
| 1200 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) { | |
| 1201 return; // Successfully crashed in ValidateFrame. | |
| 1202 } | |
| 1203 } | |
| 1204 | |
| 1205 // Test validate fails for truncated I420 buffer. | |
| 1206 void ValidateI420InvalidSize() { | |
| 1207 __try { | |
| 1208 ValidateFrame(kImageFilename, kYuvExtension, | |
| 1209 cricket::FOURCC_I420, -16384, 0, false); | |
| 1210 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION."; | |
| 1211 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) { | |
| 1212 return; // Successfully crashed in ValidateFrame. | |
| 1213 } | |
| 1214 } | |
| 1215 #endif | |
| 1216 | |
| 1217 // Test constructing an image from a YUY2 buffer (and synonymous formats). | |
| 1218 void ConstructYuy2Aliases() { | |
| 1219 T frame1, frame2, frame3, frame4; | |
| 1220 std::unique_ptr<rtc::MemoryStream> ms( | |
| 1221 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); | |
| 1222 ASSERT_TRUE(ms.get() != NULL); | |
| 1223 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, | |
| 1224 &frame1)); | |
| 1225 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, | |
| 1226 kWidth, kHeight, &frame2)); | |
| 1227 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUVS, | |
| 1228 kWidth, kHeight, &frame3)); | |
| 1229 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUYV, | |
| 1230 kWidth, kHeight, &frame4)); | |
| 1231 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 1232 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); | |
| 1233 EXPECT_TRUE(IsEqual(frame1, frame4, 0)); | |
| 1234 } | |
| 1235 | |
| 1236 // Test constructing an image from a UYVY buffer (and synonymous formats). | |
| 1237 void ConstructUyvyAliases() { | |
| 1238 T frame1, frame2, frame3, frame4; | |
| 1239 std::unique_ptr<rtc::MemoryStream> ms( | |
| 1240 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); | |
| 1241 ASSERT_TRUE(ms.get() != NULL); | |
| 1242 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight, | |
| 1243 &frame1)); | |
| 1244 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, | |
| 1245 kWidth, kHeight, &frame2)); | |
| 1246 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_2VUY, | |
| 1247 kWidth, kHeight, &frame3)); | |
| 1248 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_HDYC, | |
| 1249 kWidth, kHeight, &frame4)); | |
| 1250 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 1251 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); | |
| 1252 EXPECT_TRUE(IsEqual(frame1, frame4, 0)); | |
| 1253 } | |
| 1254 | |
| 1255 // Test creating a copy. | |
| 1256 void ConstructCopy() { | |
| 1257 T frame1, frame2; | |
| 1258 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1259 for (int i = 0; i < repeat_; ++i) { | |
| 1260 EXPECT_TRUE(frame2.Init(frame1)); | |
| 1261 } | |
| 1262 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 1263 } | |
| 1264 | |
| 1265 // Test creating a copy and check that it just increments the refcount. | |
| 1266 void ConstructCopyIsRef() { | |
| 1267 T frame1, frame2; | |
| 1268 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1269 for (int i = 0; i < repeat_; ++i) { | |
| 1270 EXPECT_TRUE(frame2.Init(frame1)); | |
| 1271 } | |
| 1272 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 1273 EXPECT_EQ(frame1.video_frame_buffer(), frame2.video_frame_buffer()); | |
| 1274 } | |
| 1275 | |
| 1276 // Test constructing an image from a YUY2 buffer with a range of sizes. | |
| 1277 // Only tests that conversion does not crash or corrupt heap. | |
| 1278 void ConstructYuy2AllSizes() { | |
| 1279 T frame1, frame2; | |
| 1280 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) { | |
| 1281 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) { | |
| 1282 std::unique_ptr<rtc::MemoryStream> ms( | |
| 1283 CreateYuv422Sample(cricket::FOURCC_YUY2, width, height)); | |
| 1284 ASSERT_TRUE(ms.get() != NULL); | |
| 1285 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, width, height, | |
| 1286 &frame1)); | |
| 1287 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, | |
| 1288 width, height, &frame2)); | |
| 1289 EXPECT_TRUE(IsEqual(frame1, frame2, 0)); | |
| 1290 } | |
| 1291 } | |
| 1292 } | |
| 1293 | |
| 1294 // Test constructing an image from a ARGB buffer with a range of sizes. | |
| 1295 // Only tests that conversion does not crash or corrupt heap. | |
| 1296 void ConstructARGBAllSizes() { | |
| 1297 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) { | |
| 1298 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) { | |
| 1299 std::unique_ptr<rtc::MemoryStream> ms( | |
| 1300 CreateRgbSample(cricket::FOURCC_ARGB, width, height)); | |
| 1301 ASSERT_TRUE(ms.get() != NULL); | |
| 1302 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB, | |
| 1303 width, height); | |
| 1304 ASSERT_TRUE(frame1); | |
| 1305 T frame2; | |
| 1306 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, | |
| 1307 width, height, &frame2)); | |
| 1308 EXPECT_TRUE(IsEqual(*frame1, frame2, 64)); | |
| 1309 } | |
| 1310 } | |
| 1311 // Test a practical window size for screencasting usecase. | |
| 1312 const int kOddWidth = 1228; | |
| 1313 const int kOddHeight = 260; | |
| 1314 for (int j = 0; j < 2; ++j) { | |
| 1315 for (int i = 0; i < 2; ++i) { | |
| 1316 std::unique_ptr<rtc::MemoryStream> ms( | |
| 1317 CreateRgbSample(cricket::FOURCC_ARGB, kOddWidth + i, kOddHeight + j)); | |
| 1318 ASSERT_TRUE(ms.get() != NULL); | |
| 1319 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB, | |
| 1320 kOddWidth + i, kOddHeight + j); | |
| 1321 ASSERT_TRUE(frame1); | |
| 1322 T frame2; | |
| 1323 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, | |
| 1324 kOddWidth + i, kOddHeight + j, &frame2)); | |
| 1325 EXPECT_TRUE(IsEqual(*frame1, frame2, 64)); | |
| 1326 } | |
| 1327 } | |
| 1328 } | |
| 1329 | |
| 1330 ////////////////////// | |
| 1331 // Conversion tests // | |
| 1332 ////////////////////// | |
| 1333 | |
| 1334 // Test converting from I420 to I422. | |
| 1335 void ConvertToI422Buffer() { | |
| 1336 T frame1, frame2; | |
| 1337 size_t out_size = kWidth * kHeight * 2; | |
| 1338 std::unique_ptr<uint8_t[]> buf(new uint8_t[out_size + kAlignment]); | |
| 1339 uint8_t* y = ALIGNP(buf.get(), kAlignment); | |
| 1340 uint8_t* u = y + kWidth * kHeight; | |
| 1341 uint8_t* v = u + (kWidth / 2) * kHeight; | |
| 1342 ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); | |
| 1343 for (int i = 0; i < repeat_; ++i) { | |
| 1344 EXPECT_EQ(0, libyuv::I420ToI422(frame1.video_frame_buffer()->DataY(), | |
| 1345 frame1.video_frame_buffer()->StrideY(), | |
| 1346 frame1.video_frame_buffer()->DataU(), | |
| 1347 frame1.video_frame_buffer()->StrideU(), | |
| 1348 frame1.video_frame_buffer()->DataV(), | |
| 1349 frame1.video_frame_buffer()->StrideV(), | |
| 1350 y, kWidth, | |
| 1351 u, kWidth / 2, | |
| 1352 v, kWidth / 2, | |
| 1353 kWidth, kHeight)); | |
| 1354 } | |
| 1355 EXPECT_TRUE(frame2.Init(cricket::FOURCC_I422, kWidth, kHeight, kWidth, | |
| 1356 kHeight, y, out_size, 1, 1, 0, | |
| 1357 webrtc::kVideoRotation_0)); | |
| 1358 EXPECT_TRUE(IsEqual(frame1, frame2, 1)); | |
| 1359 } | |
| 1360 | |
| 1361 int repeat_; | |
| 1362 }; | |
| 1363 | |
| 1364 #endif // WEBRTC_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_ | |
| OLD | NEW |