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

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

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

Powered by Google App Engine
This is Rietveld 408576698