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

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

Issue 2411953002: Reland of Make cricket::VideoFrame inherit webrtc::VideoFrame. (Closed)
Patch Set: Fix for windows build. Created 4 years, 2 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
« no previous file with comments | « webrtc/media/base/videoframe.cc ('k') | webrtc/media/devices/gdivideorenderer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 const uint8_t* y,
457 uint32_t ypitch,
458 const uint8_t* u,
459 uint32_t upitch,
460 const uint8_t* v,
461 uint32_t vpitch,
462 int max_error) {
463 return IsSize(frame, width, height) &&
464 IsPlaneEqual("y", frame.video_frame_buffer()->DataY(),
465 frame.video_frame_buffer()->StrideY(), y, ypitch,
466 static_cast<uint32_t>(width),
467 static_cast<uint32_t>(height), max_error) &&
468 IsPlaneEqual("u", frame.video_frame_buffer()->DataU(),
469 frame.video_frame_buffer()->StrideU(), u, upitch,
470 static_cast<uint32_t>((width + 1) / 2),
471 static_cast<uint32_t>((height + 1) / 2), max_error) &&
472 IsPlaneEqual("v", frame.video_frame_buffer()->DataV(),
473 frame.video_frame_buffer()->StrideV(), v, vpitch,
474 static_cast<uint32_t>((width + 1) / 2),
475 static_cast<uint32_t>((height + 1) / 2), max_error);
476 }
477
478 static bool IsEqual(const cricket::VideoFrame& frame1,
479 const cricket::VideoFrame& frame2,
480 int max_error) {
481 return frame1.timestamp_us() == frame2.timestamp_us() &&
482 IsEqual(frame1,
483 frame2.width(), frame2.height(),
484 frame2.video_frame_buffer()->DataY(),
485 frame2.video_frame_buffer()->StrideY(),
486 frame2.video_frame_buffer()->DataU(),
487 frame2.video_frame_buffer()->StrideU(),
488 frame2.video_frame_buffer()->DataV(),
489 frame2.video_frame_buffer()->StrideV(), max_error);
490 }
491
492 static bool IsEqual(
493 const cricket::VideoFrame& frame1,
494 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer,
495 int max_error) {
496 return IsEqual(frame1, buffer->width(), buffer->height(),
497 buffer->DataY(), buffer->StrideY(),
498 buffer->DataU(), buffer->StrideU(),
499 buffer->DataV(), buffer->StrideV(),
500 max_error);
501 }
502
503 static bool IsEqualWithCrop(const cricket::VideoFrame& frame1,
504 const cricket::VideoFrame& frame2,
505 int hcrop, int vcrop, int max_error) {
506 return frame1.width() <= frame2.width() &&
507 frame1.height() <= frame2.height() &&
508 frame1.timestamp_us() == frame2.timestamp_us() &&
509 IsEqual(frame1,
510 frame2.width() - hcrop * 2,
511 frame2.height() - vcrop * 2,
512 frame2.video_frame_buffer()->DataY()
513 + vcrop * frame2.video_frame_buffer()->StrideY()
514 + hcrop,
515 frame2.video_frame_buffer()->StrideY(),
516 frame2.video_frame_buffer()->DataU()
517 + vcrop * frame2.video_frame_buffer()->StrideU() / 2
518 + hcrop / 2,
519 frame2.video_frame_buffer()->StrideU(),
520 frame2.video_frame_buffer()->DataV()
521 + vcrop * frame2.video_frame_buffer()->StrideV() / 2
522 + hcrop / 2,
523 frame2.video_frame_buffer()->StrideV(),
524 max_error);
525 }
526
527 static bool IsBlack(const cricket::VideoFrame& frame) {
528 return !IsNull(frame) &&
529 *frame.video_frame_buffer()->DataY() <= 16 &&
530 *frame.video_frame_buffer()->DataU() == 128 &&
531 *frame.video_frame_buffer()->DataV() == 128;
532 }
533
534 ////////////////////////
535 // Construction tests //
536 ////////////////////////
537
538 // Test constructing an image from a I420 buffer.
539 void ConstructI420() {
540 T frame;
541 EXPECT_TRUE(IsNull(frame));
542 std::unique_ptr<rtc::MemoryStream> ms(
543 CreateYuvSample(kWidth, kHeight, 12));
544 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420,
545 kWidth, kHeight, &frame));
546
547 const uint8_t* y = reinterpret_cast<uint8_t*>(ms.get()->GetBuffer());
548 const uint8_t* u = y + kWidth * kHeight;
549 const uint8_t* v = u + kWidth * kHeight / 4;
550 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, y, kWidth, u, kWidth / 2, v,
551 kWidth / 2, 0));
552 }
553
554 // Test constructing an image from a YV12 buffer.
555 void ConstructYV12() {
556 T frame;
557 std::unique_ptr<rtc::MemoryStream> ms(
558 CreateYuvSample(kWidth, kHeight, 12));
559 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YV12,
560 kWidth, kHeight, &frame));
561
562 const uint8_t* y = reinterpret_cast<uint8_t*>(ms.get()->GetBuffer());
563 const uint8_t* v = y + kWidth * kHeight;
564 const uint8_t* u = v + kWidth * kHeight / 4;
565 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, y, kWidth, u, kWidth / 2, v,
566 kWidth / 2, 0));
567 }
568
569 // Test constructing an image from a I422 buffer.
570 void ConstructI422() {
571 T frame1, frame2;
572 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
573 size_t buf_size = kWidth * kHeight * 2;
574 std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size + kAlignment]);
575 uint8_t* y = ALIGNP(buf.get(), kAlignment);
576 uint8_t* u = y + kWidth * kHeight;
577 uint8_t* v = u + (kWidth / 2) * kHeight;
578 EXPECT_EQ(0, libyuv::I420ToI422(frame1.video_frame_buffer()->DataY(),
579 frame1.video_frame_buffer()->StrideY(),
580 frame1.video_frame_buffer()->DataU(),
581 frame1.video_frame_buffer()->StrideU(),
582 frame1.video_frame_buffer()->DataV(),
583 frame1.video_frame_buffer()->StrideV(),
584 y, kWidth,
585 u, kWidth / 2,
586 v, kWidth / 2,
587 kWidth, kHeight));
588 EXPECT_TRUE(LoadFrame(y, buf_size, cricket::FOURCC_I422,
589 kWidth, kHeight, &frame2));
590 EXPECT_TRUE(IsEqual(frame1, frame2, 1));
591 }
592
593 // Test constructing an image from a YUY2 buffer.
594 void ConstructYuy2() {
595 T frame1, frame2;
596 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
597 size_t buf_size = kWidth * kHeight * 2;
598 std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size + kAlignment]);
599 uint8_t* yuy2 = ALIGNP(buf.get(), kAlignment);
600 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.video_frame_buffer()->DataY(),
601 frame1.video_frame_buffer()->StrideY(),
602 frame1.video_frame_buffer()->DataU(),
603 frame1.video_frame_buffer()->StrideU(),
604 frame1.video_frame_buffer()->DataV(),
605 frame1.video_frame_buffer()->StrideV(),
606 yuy2, kWidth * 2,
607 kWidth, kHeight));
608 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2,
609 kWidth, kHeight, &frame2));
610 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
611 }
612
613 // Test constructing an image from a YUY2 buffer with buffer unaligned.
614 void ConstructYuy2Unaligned() {
615 T frame1, frame2;
616 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
617 size_t buf_size = kWidth * kHeight * 2;
618 std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size + kAlignment + 1]);
619 uint8_t* yuy2 = ALIGNP(buf.get(), kAlignment) + 1;
620 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.video_frame_buffer()->DataY(),
621 frame1.video_frame_buffer()->StrideY(),
622 frame1.video_frame_buffer()->DataU(),
623 frame1.video_frame_buffer()->StrideU(),
624 frame1.video_frame_buffer()->DataV(),
625 frame1.video_frame_buffer()->StrideV(),
626 yuy2, kWidth * 2,
627 kWidth, kHeight));
628 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2,
629 kWidth, kHeight, &frame2));
630 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
631 }
632
633 // Test constructing an image from a wide YUY2 buffer.
634 // Normal is 1280x720. Wide is 12800x72
635 void ConstructYuy2Wide() {
636 std::unique_ptr<rtc::MemoryStream> ms(
637 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth * 10, kHeight / 10));
638 ASSERT_TRUE(ms.get() != NULL);
639 std::unique_ptr<T> frame1 = ConvertYuv422(ms.get(), cricket::FOURCC_YUY2,
640 kWidth * 10, kHeight / 10);
641 ASSERT_TRUE(frame1);
642 T frame2;
643 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
644 kWidth * 10, kHeight / 10, &frame2));
645 EXPECT_TRUE(IsEqual(*frame1, frame2, 0));
646 }
647
648 // Test constructing an image from a UYVY buffer.
649 void ConstructUyvy() {
650 std::unique_ptr<rtc::MemoryStream> ms(
651 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
652 ASSERT_TRUE(ms.get() != NULL);
653 std::unique_ptr<T> frame1 = ConvertYuv422(ms.get(), cricket::FOURCC_UYVY,
654 kWidth, kHeight);
655 T frame2;
656 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
657 kWidth, kHeight, &frame2));
658 EXPECT_TRUE(IsEqual(*frame1, frame2, 0));
659 }
660
661 // Test constructing an image from a random buffer.
662 // We are merely verifying that the code succeeds and is free of crashes.
663 void ConstructM420() {
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_M420,
669 kWidth, kHeight, &frame));
670 }
671
672 void ConstructNV21() {
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_NV21,
678 kWidth, kHeight, &frame));
679 }
680
681 void ConstructNV12() {
682 T frame;
683 std::unique_ptr<rtc::MemoryStream> ms(
684 CreateYuvSample(kWidth, kHeight, 12));
685 ASSERT_TRUE(ms.get() != NULL);
686 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV12,
687 kWidth, kHeight, &frame));
688 }
689
690 // Test constructing an image from a ABGR buffer
691 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
692 void ConstructABGR() {
693 std::unique_ptr<rtc::MemoryStream> ms(
694 CreateRgbSample(cricket::FOURCC_ABGR, kWidth, kHeight));
695 ASSERT_TRUE(ms.get() != NULL);
696 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ABGR,
697 kWidth, kHeight);
698 ASSERT_TRUE(frame1);
699 T frame2;
700 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ABGR,
701 kWidth, kHeight, &frame2));
702 EXPECT_TRUE(IsEqual(*frame1, frame2, 2));
703 }
704
705 // Test constructing an image from a ARGB buffer
706 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
707 void ConstructARGB() {
708 std::unique_ptr<rtc::MemoryStream> ms(
709 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));
710 ASSERT_TRUE(ms.get() != NULL);
711 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
712 kWidth, kHeight);
713 ASSERT_TRUE(frame1);
714 T frame2;
715 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
716 kWidth, kHeight, &frame2));
717 EXPECT_TRUE(IsEqual(*frame1, frame2, 2));
718 }
719
720 // Test constructing an image from a wide ARGB buffer
721 // Normal is 1280x720. Wide is 12800x72
722 void ConstructARGBWide() {
723 std::unique_ptr<rtc::MemoryStream> ms(
724 CreateRgbSample(cricket::FOURCC_ARGB, kWidth * 10, kHeight / 10));
725 ASSERT_TRUE(ms.get() != NULL);
726 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
727 kWidth * 10, kHeight / 10);
728 ASSERT_TRUE(frame1);
729 T frame2;
730 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
731 kWidth * 10, kHeight / 10, &frame2));
732 EXPECT_TRUE(IsEqual(*frame1, frame2, 2));
733 }
734
735 // Test constructing an image from an BGRA buffer.
736 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
737 void ConstructBGRA() {
738 std::unique_ptr<rtc::MemoryStream> ms(
739 CreateRgbSample(cricket::FOURCC_BGRA, kWidth, kHeight));
740 ASSERT_TRUE(ms.get() != NULL);
741 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_BGRA,
742 kWidth, kHeight);
743 ASSERT_TRUE(frame1);
744 T frame2;
745 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_BGRA,
746 kWidth, kHeight, &frame2));
747 EXPECT_TRUE(IsEqual(*frame1, frame2, 2));
748 }
749
750 // Test constructing an image from a 24BG buffer.
751 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
752 void Construct24BG() {
753 std::unique_ptr<rtc::MemoryStream> ms(
754 CreateRgbSample(cricket::FOURCC_24BG, kWidth, kHeight));
755 ASSERT_TRUE(ms.get() != NULL);
756 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_24BG,
757 kWidth, kHeight);
758 ASSERT_TRUE(frame1);
759 T frame2;
760 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_24BG,
761 kWidth, kHeight, &frame2));
762 EXPECT_TRUE(IsEqual(*frame1, frame2, 2));
763 }
764
765 // Test constructing an image from a raw RGB buffer.
766 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
767 void ConstructRaw() {
768 std::unique_ptr<rtc::MemoryStream> ms(
769 CreateRgbSample(cricket::FOURCC_RAW, kWidth, kHeight));
770 ASSERT_TRUE(ms.get() != NULL);
771 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_RAW,
772 kWidth, kHeight);
773 ASSERT_TRUE(frame1);
774 T frame2;
775 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_RAW,
776 kWidth, kHeight, &frame2));
777 EXPECT_TRUE(IsEqual(*frame1, frame2, 2));
778 }
779
780 // Macro to help test different rotations
781 #define TEST_MIRROR(FOURCC, BPP) \
782 void Construct##FOURCC##Mirror() { \
783 T frame1, frame2; \
784 rtc::scoped_refptr<webrtc::I420Buffer> res_buffer; \
785 std::unique_ptr<rtc::MemoryStream> ms( \
786 CreateYuvSample(kWidth, kHeight, BPP)); \
787 ASSERT_TRUE(ms.get() != NULL); \
788 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, kWidth, \
789 -kHeight, kWidth, kHeight, \
790 webrtc::kVideoRotation_180, &frame1)); \
791 size_t data_size; \
792 bool ret = ms->GetSize(&data_size); \
793 EXPECT_TRUE(ret); \
794 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, kWidth, kHeight, kWidth, \
795 kHeight, \
796 reinterpret_cast<uint8_t*>(ms->GetBuffer()), \
797 data_size, 0, webrtc::kVideoRotation_0)); \
798 int width_rotate = frame1.width(); \
799 int height_rotate = frame1.height(); \
800 res_buffer = webrtc::I420Buffer::Create(width_rotate, height_rotate); \
801 libyuv::I420Mirror(frame2.video_frame_buffer()->DataY(), \
802 frame2.video_frame_buffer()->StrideY(), \
803 frame2.video_frame_buffer()->DataU(), \
804 frame2.video_frame_buffer()->StrideU(), \
805 frame2.video_frame_buffer()->DataV(), \
806 frame2.video_frame_buffer()->StrideV(), \
807 res_buffer->MutableDataY(), res_buffer->StrideY(), \
808 res_buffer->MutableDataU(), res_buffer->StrideU(), \
809 res_buffer->MutableDataV(), res_buffer->StrideV(), \
810 kWidth, kHeight); \
811 EXPECT_TRUE(IsEqual(frame1, res_buffer, 0)); \
812 }
813
814 TEST_MIRROR(I420, 420)
815
816 // Macro to help test different rotations
817 #define TEST_ROTATE(FOURCC, BPP, ROTATE) \
818 void Construct##FOURCC##Rotate##ROTATE() { \
819 T frame1, frame2; \
820 rtc::scoped_refptr<webrtc::I420Buffer> res_buffer; \
821 std::unique_ptr<rtc::MemoryStream> ms( \
822 CreateYuvSample(kWidth, kHeight, BPP)); \
823 ASSERT_TRUE(ms.get() != NULL); \
824 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, kWidth, kHeight, \
825 kWidth, kHeight, webrtc::kVideoRotation_##ROTATE, \
826 &frame1)); \
827 size_t data_size; \
828 bool ret = ms->GetSize(&data_size); \
829 EXPECT_TRUE(ret); \
830 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, kWidth, kHeight, kWidth, \
831 kHeight, \
832 reinterpret_cast<uint8_t*>(ms->GetBuffer()), \
833 data_size, 0, webrtc::kVideoRotation_0)); \
834 int width_rotate = frame1.width(); \
835 int height_rotate = frame1.height(); \
836 res_buffer = webrtc::I420Buffer::Create(width_rotate, height_rotate); \
837 libyuv::I420Rotate(frame2.video_frame_buffer()->DataY(), \
838 frame2.video_frame_buffer()->StrideY(), \
839 frame2.video_frame_buffer()->DataU(), \
840 frame2.video_frame_buffer()->StrideU(), \
841 frame2.video_frame_buffer()->DataV(), \
842 frame2.video_frame_buffer()->StrideV(), \
843 res_buffer->MutableDataY(), res_buffer->StrideY(), \
844 res_buffer->MutableDataU(), res_buffer->StrideU(), \
845 res_buffer->MutableDataV(), res_buffer->StrideV(), \
846 kWidth, kHeight, libyuv::kRotate##ROTATE); \
847 EXPECT_TRUE(IsEqual(frame1, res_buffer, 0)); \
848 }
849
850 // Test constructing an image with rotation.
851 TEST_ROTATE(I420, 12, 0)
852 TEST_ROTATE(I420, 12, 90)
853 TEST_ROTATE(I420, 12, 180)
854 TEST_ROTATE(I420, 12, 270)
855 TEST_ROTATE(YV12, 12, 0)
856 TEST_ROTATE(YV12, 12, 90)
857 TEST_ROTATE(YV12, 12, 180)
858 TEST_ROTATE(YV12, 12, 270)
859 TEST_ROTATE(NV12, 12, 0)
860 TEST_ROTATE(NV12, 12, 90)
861 TEST_ROTATE(NV12, 12, 180)
862 TEST_ROTATE(NV12, 12, 270)
863 TEST_ROTATE(NV21, 12, 0)
864 TEST_ROTATE(NV21, 12, 90)
865 TEST_ROTATE(NV21, 12, 180)
866 TEST_ROTATE(NV21, 12, 270)
867 TEST_ROTATE(UYVY, 16, 0)
868 TEST_ROTATE(UYVY, 16, 90)
869 TEST_ROTATE(UYVY, 16, 180)
870 TEST_ROTATE(UYVY, 16, 270)
871 TEST_ROTATE(YUY2, 16, 0)
872 TEST_ROTATE(YUY2, 16, 90)
873 TEST_ROTATE(YUY2, 16, 180)
874 TEST_ROTATE(YUY2, 16, 270)
875
876 // Test constructing an image from a UYVY buffer rotated 90 degrees.
877 void ConstructUyvyRotate90() {
878 T frame2;
879 std::unique_ptr<rtc::MemoryStream> ms(
880 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
881 ASSERT_TRUE(ms.get() != NULL);
882 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
883 kWidth, kHeight, webrtc::kVideoRotation_90, &frame2));
884 }
885
886 // Test constructing an image from a UYVY buffer rotated 180 degrees.
887 void ConstructUyvyRotate180() {
888 T frame2;
889 std::unique_ptr<rtc::MemoryStream> ms(
890 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
891 ASSERT_TRUE(ms.get() != NULL);
892 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
893 kWidth, kHeight, webrtc::kVideoRotation_180,
894 &frame2));
895 }
896
897 // Test constructing an image from a UYVY buffer rotated 270 degrees.
898 void ConstructUyvyRotate270() {
899 T frame2;
900 std::unique_ptr<rtc::MemoryStream> ms(
901 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
902 ASSERT_TRUE(ms.get() != NULL);
903 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
904 kWidth, kHeight, webrtc::kVideoRotation_270,
905 &frame2));
906 }
907
908 // Test constructing an image from a YUY2 buffer rotated 90 degrees.
909 void ConstructYuy2Rotate90() {
910 T frame2;
911 std::unique_ptr<rtc::MemoryStream> ms(
912 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
913 ASSERT_TRUE(ms.get() != NULL);
914 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
915 kWidth, kHeight, webrtc::kVideoRotation_90, &frame2));
916 }
917
918 // Test constructing an image from a YUY2 buffer rotated 180 degrees.
919 void ConstructYuy2Rotate180() {
920 T frame2;
921 std::unique_ptr<rtc::MemoryStream> ms(
922 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
923 ASSERT_TRUE(ms.get() != NULL);
924 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
925 kWidth, kHeight, webrtc::kVideoRotation_180,
926 &frame2));
927 }
928
929 // Test constructing an image from a YUY2 buffer rotated 270 degrees.
930 void ConstructYuy2Rotate270() {
931 T frame2;
932 std::unique_ptr<rtc::MemoryStream> ms(
933 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
934 ASSERT_TRUE(ms.get() != NULL);
935 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
936 kWidth, kHeight, webrtc::kVideoRotation_270,
937 &frame2));
938 }
939
940 // Test 1 pixel edge case image I420 buffer.
941 void ConstructI4201Pixel() {
942 T frame;
943 uint8_t pixel[3] = {1, 2, 3};
944 for (int i = 0; i < repeat_; ++i) {
945 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1, pixel,
946 sizeof(pixel), 0, webrtc::kVideoRotation_0));
947 }
948 const uint8_t* y = pixel;
949 const uint8_t* u = y + 1;
950 const uint8_t* v = u + 1;
951 EXPECT_TRUE(IsEqual(frame, 1, 1, y, 1, u, 1, v, 1, 0));
952 }
953
954 // Test 5 pixel edge case image.
955 void ConstructI4205Pixel() {
956 T frame;
957 uint8_t pixels5x5[5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2];
958 memset(pixels5x5, 1, 5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2);
959 for (int i = 0; i < repeat_; ++i) {
960 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 5, 5, 5, 5, pixels5x5,
961 sizeof(pixels5x5), 0,
962 webrtc::kVideoRotation_0));
963 }
964 EXPECT_EQ(5, frame.width());
965 EXPECT_EQ(5, frame.height());
966 EXPECT_EQ(5, frame.video_frame_buffer()->StrideY());
967 EXPECT_EQ(3, frame.video_frame_buffer()->StrideU());
968 EXPECT_EQ(3, frame.video_frame_buffer()->StrideV());
969 }
970
971 // Test constructing an image from an I420 buffer with horizontal cropping.
972 void ConstructI420CropHorizontal() {
973 T frame1, frame2;
974 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
975 ASSERT_TRUE(LoadFrame(kImageFilename, kYuvExtension,
976 cricket::FOURCC_I420, kWidth, kHeight,
977 kWidth * 3 / 4, kHeight, webrtc::kVideoRotation_0,
978 &frame2));
979 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0));
980 }
981
982 // Test constructing an image from a YUY2 buffer with horizontal cropping.
983 void ConstructYuy2CropHorizontal() {
984 T frame1, frame2;
985 std::unique_ptr<rtc::MemoryStream> ms(
986 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
987 ASSERT_TRUE(ms.get() != NULL);
988 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
989 &frame1));
990 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
991 kWidth * 3 / 4, kHeight, webrtc::kVideoRotation_0,
992 &frame2));
993 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0));
994 }
995
996 // Test constructing an image from an ARGB buffer with horizontal cropping.
997 void ConstructARGBCropHorizontal() {
998 std::unique_ptr<rtc::MemoryStream> ms(
999 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));
1000 ASSERT_TRUE(ms.get() != NULL);
1001 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
1002 kWidth, kHeight);
1003 ASSERT_TRUE(frame1);
1004 T frame2;
1005 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight,
1006 kWidth * 3 / 4, kHeight, webrtc::kVideoRotation_0,
1007 &frame2));
1008 EXPECT_TRUE(IsEqualWithCrop(frame2, *frame1, kWidth / 8, 0, 2));
1009 }
1010
1011 // Test constructing an image from an I420 buffer, cropping top and bottom.
1012 void ConstructI420CropVertical() {
1013 T frame1, frame2;
1014 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1015 ASSERT_TRUE(LoadFrame(LoadSample(kImageFilename, kYuvExtension).get(),
1016 cricket::FOURCC_I420, kWidth, kHeight,
1017 kWidth, kHeight * 3 / 4, webrtc::kVideoRotation_0,
1018 &frame2));
1019 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, 0, kHeight / 8, 0));
1020 }
1021
1022 // Test constructing an image from I420 synonymous formats.
1023 void ConstructI420Aliases() {
1024 T frame1, frame2, frame3;
1025 ASSERT_TRUE(LoadFrame(LoadSample(kImageFilename, kYuvExtension),
1026 cricket::FOURCC_I420, kWidth, kHeight,
1027 &frame1));
1028 ASSERT_TRUE(LoadFrame(kImageFilename, kYuvExtension,
1029 cricket::FOURCC_IYUV, kWidth, kHeight,
1030 &frame2));
1031 ASSERT_TRUE(LoadFrame(kImageFilename, kYuvExtension,
1032 cricket::FOURCC_YU12, kWidth, kHeight,
1033 &frame3));
1034 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1035 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1036 }
1037
1038 // Test constructing an image from an I420 MJPG buffer.
1039 void ConstructMjpgI420() {
1040 T frame1, frame2;
1041 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1042 ASSERT_TRUE(LoadFrame(kJpeg420Filename, kJpegExtension,
1043 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1044 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1045 }
1046
1047 // Test constructing an image from an I422 MJPG buffer.
1048 void ConstructMjpgI422() {
1049 T frame1, frame2;
1050 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1051 ASSERT_TRUE(LoadFrame(LoadSample(kJpeg422Filename, kJpegExtension).get(),
1052 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1053 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1054 }
1055
1056 // Test constructing an image from an I444 MJPG buffer.
1057 void ConstructMjpgI444() {
1058 T frame1, frame2;
1059 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1060 ASSERT_TRUE(LoadFrame(LoadSample(kJpeg444Filename, kJpegExtension),
1061 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1062 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1063 }
1064
1065 // Test constructing an image from an I444 MJPG buffer.
1066 void ConstructMjpgI411() {
1067 T frame1, frame2;
1068 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1069 ASSERT_TRUE(LoadFrame(kJpeg411Filename, kJpegExtension,
1070 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1071 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1072 }
1073
1074 // Test constructing an image from an I400 MJPG buffer.
1075 // TODO(fbarchard): Stronger compare on chroma. Compare agaisnt a grey image.
1076 void ConstructMjpgI400() {
1077 T frame1, frame2;
1078 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1079 ASSERT_TRUE(LoadFrame(kJpeg400Filename, kJpegExtension,
1080 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1081 EXPECT_TRUE(IsPlaneEqual("y", frame1.video_frame_buffer()->DataY(),
1082 frame1.video_frame_buffer()->StrideY(),
1083 frame2.video_frame_buffer()->DataY(),
1084 frame2.video_frame_buffer()->StrideY(),
1085 kWidth, kHeight, 32));
1086 EXPECT_TRUE(IsEqual(frame1, frame2, 128));
1087 }
1088
1089 // Test constructing an image from an I420 MJPG buffer.
1090 void ValidateFrame(const char* name,
1091 const char* extension,
1092 uint32_t fourcc,
1093 int data_adjust,
1094 int size_adjust,
1095 bool expected_result) {
1096 T frame;
1097 std::unique_ptr<rtc::MemoryStream> ms(LoadSample(name, extension));
1098 ASSERT_TRUE(ms.get() != NULL);
1099 const uint8_t* sample =
1100 reinterpret_cast<const uint8_t*>(ms.get()->GetBuffer());
1101 size_t sample_size;
1102 ms->GetSize(&sample_size);
1103 // Optional adjust size to test invalid size.
1104 size_t data_size = sample_size + data_adjust;
1105
1106 // Allocate a buffer with end page aligned.
1107 const int kPadToHeapSized = 16 * 1024 * 1024;
1108 std::unique_ptr<uint8_t[]> page_buffer(
1109 new uint8_t[((data_size + kPadToHeapSized + 4095) & ~4095)]);
1110 uint8_t* data_ptr = page_buffer.get();
1111 if (!data_ptr) {
1112 LOG(LS_WARNING) << "Failed to allocate memory for ValidateFrame test.";
1113 EXPECT_FALSE(expected_result); // NULL is okay if failure was expected.
1114 return;
1115 }
1116 data_ptr += kPadToHeapSized + (-(static_cast<int>(data_size)) & 4095);
1117 memcpy(data_ptr, sample, std::min(data_size, sample_size));
1118 for (int i = 0; i < repeat_; ++i) {
1119 EXPECT_EQ(expected_result, frame.Validate(fourcc, kWidth, kHeight,
1120 data_ptr,
1121 sample_size + size_adjust));
1122 }
1123 }
1124
1125 // Test validate for I420 MJPG buffer.
1126 void ValidateMjpgI420() {
1127 ValidateFrame(kJpeg420Filename, kJpegExtension,
1128 cricket::FOURCC_MJPG, 0, 0, true);
1129 }
1130
1131 // Test validate for I422 MJPG buffer.
1132 void ValidateMjpgI422() {
1133 ValidateFrame(kJpeg422Filename, kJpegExtension,
1134 cricket::FOURCC_MJPG, 0, 0, true);
1135 }
1136
1137 // Test validate for I444 MJPG buffer.
1138 void ValidateMjpgI444() {
1139 ValidateFrame(kJpeg444Filename, kJpegExtension,
1140 cricket::FOURCC_MJPG, 0, 0, true);
1141 }
1142
1143 // Test validate for I411 MJPG buffer.
1144 void ValidateMjpgI411() {
1145 ValidateFrame(kJpeg411Filename, kJpegExtension,
1146 cricket::FOURCC_MJPG, 0, 0, true);
1147 }
1148
1149 // Test validate for I400 MJPG buffer.
1150 void ValidateMjpgI400() {
1151 ValidateFrame(kJpeg400Filename, kJpegExtension,
1152 cricket::FOURCC_MJPG, 0, 0, true);
1153 }
1154
1155 // Test validate for I420 buffer.
1156 void ValidateI420() {
1157 ValidateFrame(kImageFilename, kYuvExtension,
1158 cricket::FOURCC_I420, 0, 0, true);
1159 }
1160
1161 // Test validate for I420 buffer where size is too small
1162 void ValidateI420SmallSize() {
1163 ValidateFrame(kImageFilename, kYuvExtension,
1164 cricket::FOURCC_I420, 0, -16384, false);
1165 }
1166
1167 // Test validate for I420 buffer where size is too large (16 MB)
1168 // Will produce warning but pass.
1169 void ValidateI420LargeSize() {
1170 ValidateFrame(kImageFilename, kYuvExtension,
1171 cricket::FOURCC_I420, 16000000, 16000000,
1172 true);
1173 }
1174
1175 // Test validate for I420 buffer where size is 1 GB (not reasonable).
1176 void ValidateI420HugeSize() {
1177 #ifndef WIN32 // TODO(fbarchard): Reenable when fixing bug 9603762.
1178 ValidateFrame(kImageFilename, kYuvExtension,
1179 cricket::FOURCC_I420, 1000000000u,
1180 1000000000u, false);
1181 #endif
1182 }
1183
1184 // The following test that Validate crashes if the size is greater than the
1185 // actual buffer size.
1186 // TODO(fbarchard): Consider moving a filter into the capturer/plugin.
1187 #if defined(_MSC_VER) && !defined(NDEBUG)
1188 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
1189 if (code == EXCEPTION_ACCESS_VIOLATION) {
1190 LOG(LS_INFO) << "Caught EXCEPTION_ACCESS_VIOLATION as expected.";
1191 return EXCEPTION_EXECUTE_HANDLER;
1192 } else {
1193 LOG(LS_INFO) << "Did not catch EXCEPTION_ACCESS_VIOLATION. Unexpected.";
1194 return EXCEPTION_CONTINUE_SEARCH;
1195 }
1196 }
1197
1198 // Test validate fails for truncated MJPG data buffer. If ValidateFrame
1199 // crashes the exception handler will return and unittest passes with OK.
1200 void ValidateMjpgI420InvalidSize() {
1201 __try {
1202 ValidateFrame(kJpeg420Filename, kJpegExtension,
1203 cricket::FOURCC_MJPG, -16384, 0, false);
1204 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
1205 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1206 return; // Successfully crashed in ValidateFrame.
1207 }
1208 }
1209
1210 // Test validate fails for truncated I420 buffer.
1211 void ValidateI420InvalidSize() {
1212 __try {
1213 ValidateFrame(kImageFilename, kYuvExtension,
1214 cricket::FOURCC_I420, -16384, 0, false);
1215 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
1216 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1217 return; // Successfully crashed in ValidateFrame.
1218 }
1219 }
1220 #endif
1221
1222 // Test constructing an image from a YUY2 buffer (and synonymous formats).
1223 void ConstructYuy2Aliases() {
1224 T frame1, frame2, frame3, frame4;
1225 std::unique_ptr<rtc::MemoryStream> ms(
1226 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
1227 ASSERT_TRUE(ms.get() != NULL);
1228 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
1229 &frame1));
1230 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
1231 kWidth, kHeight, &frame2));
1232 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUVS,
1233 kWidth, kHeight, &frame3));
1234 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUYV,
1235 kWidth, kHeight, &frame4));
1236 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1237 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1238 EXPECT_TRUE(IsEqual(frame1, frame4, 0));
1239 }
1240
1241 // Test constructing an image from a UYVY buffer (and synonymous formats).
1242 void ConstructUyvyAliases() {
1243 T frame1, frame2, frame3, frame4;
1244 std::unique_ptr<rtc::MemoryStream> ms(
1245 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
1246 ASSERT_TRUE(ms.get() != NULL);
1247 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
1248 &frame1));
1249 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
1250 kWidth, kHeight, &frame2));
1251 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_2VUY,
1252 kWidth, kHeight, &frame3));
1253 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_HDYC,
1254 kWidth, kHeight, &frame4));
1255 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1256 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1257 EXPECT_TRUE(IsEqual(frame1, frame4, 0));
1258 }
1259
1260 // Test creating a copy.
1261 void ConstructCopy() {
1262 T frame1, frame2;
1263 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1264 for (int i = 0; i < repeat_; ++i) {
1265 EXPECT_TRUE(frame2.Init(frame1));
1266 }
1267 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1268 }
1269
1270 // Test creating a copy and check that it just increments the refcount.
1271 void ConstructCopyIsRef() {
1272 T frame1, frame2;
1273 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1274 for (int i = 0; i < repeat_; ++i) {
1275 EXPECT_TRUE(frame2.Init(frame1));
1276 }
1277 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1278 EXPECT_EQ(frame1.video_frame_buffer(), frame2.video_frame_buffer());
1279 }
1280
1281 // Test constructing an image from a YUY2 buffer with a range of sizes.
1282 // Only tests that conversion does not crash or corrupt heap.
1283 void ConstructYuy2AllSizes() {
1284 T frame1, frame2;
1285 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
1286 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
1287 std::unique_ptr<rtc::MemoryStream> ms(
1288 CreateYuv422Sample(cricket::FOURCC_YUY2, width, height));
1289 ASSERT_TRUE(ms.get() != NULL);
1290 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, width, height,
1291 &frame1));
1292 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
1293 width, height, &frame2));
1294 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1295 }
1296 }
1297 }
1298
1299 // Test constructing an image from a ARGB buffer with a range of sizes.
1300 // Only tests that conversion does not crash or corrupt heap.
1301 void ConstructARGBAllSizes() {
1302 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
1303 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
1304 std::unique_ptr<rtc::MemoryStream> ms(
1305 CreateRgbSample(cricket::FOURCC_ARGB, width, height));
1306 ASSERT_TRUE(ms.get() != NULL);
1307 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
1308 width, height);
1309 ASSERT_TRUE(frame1);
1310 T frame2;
1311 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
1312 width, height, &frame2));
1313 EXPECT_TRUE(IsEqual(*frame1, frame2, 64));
1314 }
1315 }
1316 // Test a practical window size for screencasting usecase.
1317 const int kOddWidth = 1228;
1318 const int kOddHeight = 260;
1319 for (int j = 0; j < 2; ++j) {
1320 for (int i = 0; i < 2; ++i) {
1321 std::unique_ptr<rtc::MemoryStream> ms(
1322 CreateRgbSample(cricket::FOURCC_ARGB, kOddWidth + i, kOddHeight + j));
1323 ASSERT_TRUE(ms.get() != NULL);
1324 std::unique_ptr<T> frame1 = ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
1325 kOddWidth + i, kOddHeight + j);
1326 ASSERT_TRUE(frame1);
1327 T frame2;
1328 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
1329 kOddWidth + i, kOddHeight + j, &frame2));
1330 EXPECT_TRUE(IsEqual(*frame1, frame2, 64));
1331 }
1332 }
1333 }
1334
1335 //////////////////////
1336 // Conversion tests //
1337 //////////////////////
1338
1339 // Test converting from I420 to I422.
1340 void ConvertToI422Buffer() {
1341 T frame1, frame2;
1342 size_t out_size = kWidth * kHeight * 2;
1343 std::unique_ptr<uint8_t[]> buf(new uint8_t[out_size + kAlignment]);
1344 uint8_t* y = ALIGNP(buf.get(), kAlignment);
1345 uint8_t* u = y + kWidth * kHeight;
1346 uint8_t* v = u + (kWidth / 2) * kHeight;
1347 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1348 for (int i = 0; i < repeat_; ++i) {
1349 EXPECT_EQ(0, libyuv::I420ToI422(frame1.video_frame_buffer()->DataY(),
1350 frame1.video_frame_buffer()->StrideY(),
1351 frame1.video_frame_buffer()->DataU(),
1352 frame1.video_frame_buffer()->StrideU(),
1353 frame1.video_frame_buffer()->DataV(),
1354 frame1.video_frame_buffer()->StrideV(),
1355 y, kWidth,
1356 u, kWidth / 2,
1357 v, kWidth / 2,
1358 kWidth, kHeight));
1359 }
1360 EXPECT_TRUE(frame2.Init(cricket::FOURCC_I422, kWidth, kHeight, kWidth,
1361 kHeight, y, out_size, 1, 1, 0,
1362 webrtc::kVideoRotation_0));
1363 EXPECT_TRUE(IsEqual(frame1, frame2, 1));
1364 }
1365
1366 int repeat_;
1367 };
1368
1369 #endif // WEBRTC_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_
OLDNEW
« no previous file with comments | « webrtc/media/base/videoframe.cc ('k') | webrtc/media/devices/gdivideorenderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698