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