Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1158)

Side by Side Diff: webrtc/media/base/videoframe_unittest.h

Issue 2315663002: Make cricket::VideoFrame inherit webrtc::VideoFrame. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698