3 * Copyright 2004 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #ifndef TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_
29 #define TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_
33 #include "libyuv/convert.h"
34 #include "libyuv/convert_from.h"
35 #include "libyuv/format_conversion.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"
47 #define ALIGN16(var) __declspec(align(16)) var
49 #define ALIGN16(var) var __attribute__((aligned(16)))
52 #define kImageFilename "faces.1280x720_P420.yuv"
53 #define kJpeg420Filename "faces_I420.jpg"
54 #define kJpeg422Filename "faces_I422.jpg"
55 #define kJpeg444Filename "faces_I444.jpg"
56 #define kJpeg411Filename "faces_I411.jpg"
57 #define kJpeg400Filename "faces_I400.jpg"
59 // Generic test class for testing various video frame implementations.
61 class VideoFrameTest : public testing::Test {
63 VideoFrameTest() : repeat_(1) {}
66 static const int kWidth = 1280;
67 static const int kHeight = 720;
68 static const int kAlignment = 16;
69 static const int kMinWidthAll = 1; // Constants for ConstructYUY2AllSizes.
70 static const int kMinHeightAll = 1;
71 static const int kMaxWidthAll = 17;
72 static const int kMaxHeightAll = 23;
74 // Load a video frame from disk.
75 bool LoadFrameNoRepeat(T* frame) {
76 int save_repeat = repeat_; // This LoadFrame disables repeat.
78 bool success = LoadFrame(kImageFilename, cricket::FOURCC_I420,
79 kWidth, kHeight, frame);
80 repeat_ = save_repeat;
84 bool LoadFrame(const std::string& filename, uint32 format,
85 int32 width, int32 height, T* frame) {
86 return LoadFrame(filename, format, width, height,
87 width, abs(height), 0, frame);
89 bool LoadFrame(const std::string& filename, uint32 format,
90 int32 width, int32 height, int dw, int dh, int rotation,
92 rtc::scoped_ptr<rtc::MemoryStream> ms(LoadSample(filename));
93 return LoadFrame(ms.get(), format, width, height, dw, dh, rotation, frame);
95 // Load a video frame from a memory stream.
96 bool LoadFrame(rtc::MemoryStream* ms, uint32 format,
97 int32 width, int32 height, T* frame) {
98 return LoadFrame(ms, format, width, height,
99 width, abs(height), 0, frame);
101 bool LoadFrame(rtc::MemoryStream* ms, uint32 format,
102 int32 width, int32 height, int dw, int dh, int rotation,
108 bool ret = ms->GetSize(&data_size);
111 ret = LoadFrame(reinterpret_cast<uint8*>(ms->GetBuffer()), data_size,
112 format, width, height, dw, dh, rotation, frame);
116 // Load a frame from a raw buffer.
117 bool LoadFrame(uint8* sample, size_t sample_size, uint32 format,
118 int32 width, int32 height, T* frame) {
119 return LoadFrame(sample, sample_size, format, width, height,
120 width, abs(height), 0, frame);
122 bool LoadFrame(uint8* sample, size_t sample_size, uint32 format,
123 int32 width, int32 height, int dw, int dh, int rotation,
126 for (int i = 0; i < repeat_; ++i) {
127 ret = frame->Init(format, width, height, dw, dh,
128 sample, sample_size, 1, 1, 0, 0, rotation);
133 rtc::MemoryStream* LoadSample(const std::string& filename) {
134 rtc::Pathname path(cricket::GetTestFilePath(filename));
135 rtc::scoped_ptr<rtc::FileStream> fs(
136 rtc::Filesystem::OpenFile(path, "rb"));
138 LOG(LS_ERROR) << "Could not open test file path: " << path.pathname()
139 << " from current dir "
140 << rtc::Filesystem::GetCurrentDirectory().pathname();
145 rtc::scoped_ptr<rtc::MemoryStream> ms(
146 new rtc::MemoryStream());
147 rtc::StreamResult res = Flow(fs.get(), buf, sizeof(buf), ms.get());
148 if (res != rtc::SR_SUCCESS) {
149 LOG(LS_ERROR) << "Could not load test file path: " << path.pathname();
156 // Write an I420 frame out to disk.
157 bool DumpFrame(const std::string& prefix,
158 const cricket::VideoFrame& frame) {
160 rtc::sprintfn(filename, sizeof(filename), "%s.%dx%d_P420.yuv",
161 prefix.c_str(), frame.GetWidth(), frame.GetHeight());
162 size_t out_size = cricket::VideoFrame::SizeOf(frame.GetWidth(),
164 rtc::scoped_ptr<uint8[]> out(new uint8[out_size]);
165 frame.CopyToBuffer(out.get(), out_size);
166 return DumpSample(filename, out.get(), out_size);
169 bool DumpSample(const std::string& filename, const void* buffer, int size) {
170 rtc::Pathname path(filename);
171 rtc::scoped_ptr<rtc::FileStream> fs(
172 rtc::Filesystem::OpenFile(path, "wb"));
177 return (fs->Write(buffer, size, NULL, NULL) == rtc::SR_SUCCESS);
180 // Create a test image in the desired color space.
181 // The image is a checkerboard pattern with 63x63 squares, which allows
182 // I420 chroma artifacts to easily be seen on the square boundaries.
183 // The pattern is { { green, orange }, { blue, purple } }
184 // There is also a gradient within each square to ensure that the luma
185 // values are handled properly.
186 rtc::MemoryStream* CreateYuv422Sample(uint32 fourcc,
187 uint32 width, uint32 height) {
188 int y1_pos, y2_pos, u_pos, v_pos;
189 if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) {
193 rtc::scoped_ptr<rtc::MemoryStream> ms(
194 new rtc::MemoryStream);
195 int awidth = (width + 1) & ~1;
196 int size = awidth * 2 * height;
197 if (!ms->ReserveSize(size)) {
200 for (uint32 y = 0; y < height; ++y) {
201 for (int x = 0; x < awidth; x += 2) {
203 quad[y1_pos] = (x % 63 + y % 63) + 64;
204 quad[y2_pos] = ((x + 1) % 63 + y % 63) + 64;
205 quad[u_pos] = ((x / 63) & 1) ? 192 : 64;
206 quad[v_pos] = ((y / 63) & 1) ? 192 : 64;
207 ms->Write(quad, sizeof(quad), NULL, NULL);
213 // Create a test image for YUV 420 formats with 12 bits per pixel.
214 rtc::MemoryStream* CreateYuvSample(uint32 width, uint32 height,
216 rtc::scoped_ptr<rtc::MemoryStream> ms(
217 new rtc::MemoryStream);
218 if (!ms->ReserveSize(width * height * bpp / 8)) {
222 for (uint32 i = 0; i < width * height * bpp / 8; ++i) {
223 char value = ((i / 63) & 1) ? 192 : 64;
224 ms->Write(&value, sizeof(value), NULL, NULL);
229 rtc::MemoryStream* CreateRgbSample(uint32 fourcc,
230 uint32 width, uint32 height) {
231 int r_pos, g_pos, b_pos, bytes;
232 if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) {
236 rtc::scoped_ptr<rtc::MemoryStream> ms(
237 new rtc::MemoryStream);
238 if (!ms->ReserveSize(width * height * bytes)) {
242 for (uint32 y = 0; y < height; ++y) {
243 for (uint32 x = 0; x < width; ++x) {
244 uint8 rgb[4] = { 255, 255, 255, 255 };
245 rgb[r_pos] = ((x / 63) & 1) ? 224 : 32;
246 rgb[g_pos] = (x % 63 + y % 63) + 96;
247 rgb[b_pos] = ((y / 63) & 1) ? 224 : 32;
248 ms->Write(rgb, bytes, NULL, NULL);
254 // Simple conversion routines to verify the optimized VideoFrame routines.
255 // Converts from the specified colorspace to I420.
256 bool ConvertYuv422(const rtc::MemoryStream* ms,
257 uint32 fourcc, uint32 width, uint32 height,
259 int y1_pos, y2_pos, u_pos, v_pos;
260 if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) {
264 const uint8* start = reinterpret_cast<const uint8*>(ms->GetBuffer());
265 int awidth = (width + 1) & ~1;
266 frame->InitToBlack(width, height, 1, 1, 0, 0);
267 int stride_y = frame->GetYPitch();
268 int stride_u = frame->GetUPitch();
269 int stride_v = frame->GetVPitch();
270 for (uint32 y = 0; y < height; ++y) {
271 for (uint32 x = 0; x < width; x += 2) {
272 const uint8* quad1 = start + (y * awidth + x) * 2;
273 frame->GetYPlane()[stride_y * y + x] = quad1[y1_pos];
274 if ((x + 1) < width) {
275 frame->GetYPlane()[stride_y * y + x + 1] = quad1[y2_pos];
278 const uint8* quad2 = quad1 + awidth * 2;
279 if ((y + 1) >= height) {
282 frame->GetUPlane()[stride_u * (y / 2) + x / 2] =
283 (quad1[u_pos] + quad2[u_pos] + 1) / 2;
284 frame->GetVPlane()[stride_v * (y / 2) + x / 2] =
285 (quad1[v_pos] + quad2[v_pos] + 1) / 2;
292 // Convert RGB to 420.
293 // A negative height inverts the image.
294 bool ConvertRgb(const rtc::MemoryStream* ms,
295 uint32 fourcc, int32 width, int32 height,
297 int r_pos, g_pos, b_pos, bytes;
298 if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) {
301 int pitch = width * bytes;
302 const uint8* start = reinterpret_cast<const uint8*>(ms->GetBuffer());
305 start = start + pitch * (height - 1);
308 frame->InitToBlack(width, height, 1, 1, 0, 0);
309 int stride_y = frame->GetYPitch();
310 int stride_u = frame->GetUPitch();
311 int stride_v = frame->GetVPitch();
312 for (int32 y = 0; y < height; y += 2) {
313 for (int32 x = 0; x < width; x += 2) {
316 rgb[0] = start + y * pitch + x * bytes;
317 rgb[1] = rgb[0] + ((x + 1) < width ? bytes : 0);
318 rgb[2] = rgb[0] + ((y + 1) < height ? pitch : 0);
319 rgb[3] = rgb[2] + ((x + 1) < width ? bytes : 0);
320 for (size_t i = 0; i < 4; ++i) {
321 ConvertRgbPixel(rgb[i][r_pos], rgb[i][g_pos], rgb[i][b_pos],
322 &yuv[i][0], &yuv[i][1], &yuv[i][2]);
324 frame->GetYPlane()[stride_y * y + x] = yuv[0][0];
325 if ((x + 1) < width) {
326 frame->GetYPlane()[stride_y * y + x + 1] = yuv[1][0];
328 if ((y + 1) < height) {
329 frame->GetYPlane()[stride_y * (y + 1) + x] = yuv[2][0];
330 if ((x + 1) < width) {
331 frame->GetYPlane()[stride_y * (y + 1) + x + 1] = yuv[3][0];
334 frame->GetUPlane()[stride_u * (y / 2) + x / 2] =
335 (yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1] + 2) / 4;
336 frame->GetVPlane()[stride_v * (y / 2) + x / 2] =
337 (yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2] + 2) / 4;
343 // Simple and slow RGB->YUV conversion. From NTSC standard, c/o Wikipedia.
344 void ConvertRgbPixel(uint8 r, uint8 g, uint8 b,
345 uint8* y, uint8* u, uint8* v) {
346 *y = static_cast<int>(.257 * r + .504 * g + .098 * b) + 16;
347 *u = static_cast<int>(-.148 * r - .291 * g + .439 * b) + 128;
348 *v = static_cast<int>(.439 * r - .368 * g - .071 * b) + 128;
351 bool GetYuv422Packing(uint32 fourcc,
352 int* y1_pos, int* y2_pos, int* u_pos, int* v_pos) {
353 if (fourcc == cricket::FOURCC_YUY2) {
354 *y1_pos = 0; *u_pos = 1; *y2_pos = 2; *v_pos = 3;
355 } else if (fourcc == cricket::FOURCC_UYVY) {
356 *u_pos = 0; *y1_pos = 1; *v_pos = 2; *y2_pos = 3;
363 bool GetRgbPacking(uint32 fourcc,
364 int* r_pos, int* g_pos, int* b_pos, int* bytes) {
365 if (fourcc == cricket::FOURCC_RAW) {
366 *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 3; // RGB in memory.
367 } else if (fourcc == cricket::FOURCC_24BG) {
368 *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 3; // BGR in memory.
369 } else if (fourcc == cricket::FOURCC_ABGR) {
370 *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 4; // RGBA in memory.
371 } else if (fourcc == cricket::FOURCC_BGRA) {
372 *r_pos = 1; *g_pos = 2; *b_pos = 3; *bytes = 4; // ARGB in memory.
373 } else if (fourcc == cricket::FOURCC_ARGB) {
374 *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 4; // BGRA in memory.
381 // Comparison functions for testing.
382 static bool IsNull(const cricket::VideoFrame& frame) {
383 return !frame.GetYPlane();
386 static bool IsSize(const cricket::VideoFrame& frame,
387 uint32 width, uint32 height) {
388 return !IsNull(frame) &&
389 frame.GetYPitch() >= static_cast<int32>(width) &&
390 frame.GetUPitch() >= static_cast<int32>(width) / 2 &&
391 frame.GetVPitch() >= static_cast<int32>(width) / 2 &&
392 frame.GetWidth() == width && frame.GetHeight() == height;
395 static bool IsPlaneEqual(const std::string& name,
396 const uint8* plane1, uint32 pitch1,
397 const uint8* plane2, uint32 pitch2,
398 uint32 width, uint32 height,
400 const uint8* r1 = plane1;
401 const uint8* r2 = plane2;
402 for (uint32 y = 0; y < height; ++y) {
403 for (uint32 x = 0; x < width; ++x) {
404 if (abs(static_cast<int>(r1[x] - r2[x])) > max_error) {
405 LOG(LS_INFO) << "IsPlaneEqual(" << name << "): pixel["
406 << x << "," << y << "] differs: "
407 << static_cast<int>(r1[x]) << " vs "
408 << static_cast<int>(r2[x]);
418 static bool IsEqual(const cricket::VideoFrame& frame,
419 size_t width, size_t height,
420 size_t pixel_width, size_t pixel_height,
421 int64 elapsed_time, int64 time_stamp,
422 const uint8* y, uint32 ypitch,
423 const uint8* u, uint32 upitch,
424 const uint8* v, uint32 vpitch,
427 static_cast<uint32>(width),
428 static_cast<uint32>(height)) &&
429 frame.GetPixelWidth() == pixel_width &&
430 frame.GetPixelHeight() == pixel_height &&
431 frame.GetElapsedTime() == elapsed_time &&
432 frame.GetTimeStamp() == time_stamp &&
433 IsPlaneEqual("y", frame.GetYPlane(), frame.GetYPitch(), y, ypitch,
434 static_cast<uint32>(width),
435 static_cast<uint32>(height), max_error) &&
436 IsPlaneEqual("u", frame.GetUPlane(), frame.GetUPitch(), u, upitch,
437 static_cast<uint32>((width + 1) / 2),
438 static_cast<uint32>((height + 1) / 2), max_error) &&
439 IsPlaneEqual("v", frame.GetVPlane(), frame.GetVPitch(), v, vpitch,
440 static_cast<uint32>((width + 1) / 2),
441 static_cast<uint32>((height + 1) / 2), max_error);
444 static bool IsEqual(const cricket::VideoFrame& frame1,
445 const cricket::VideoFrame& frame2,
447 return IsEqual(frame1,
448 frame2.GetWidth(), frame2.GetHeight(),
449 frame2.GetPixelWidth(), frame2.GetPixelHeight(),
450 frame2.GetElapsedTime(), frame2.GetTimeStamp(),
451 frame2.GetYPlane(), frame2.GetYPitch(),
452 frame2.GetUPlane(), frame2.GetUPitch(),
453 frame2.GetVPlane(), frame2.GetVPitch(),
457 static bool IsEqualWithCrop(const cricket::VideoFrame& frame1,
458 const cricket::VideoFrame& frame2,
459 int hcrop, int vcrop, int max_error) {
460 return frame1.GetWidth() <= frame2.GetWidth() &&
461 frame1.GetHeight() <= frame2.GetHeight() &&
463 frame2.GetWidth() - hcrop * 2,
464 frame2.GetHeight() - vcrop * 2,
465 frame2.GetPixelWidth(), frame2.GetPixelHeight(),
466 frame2.GetElapsedTime(), frame2.GetTimeStamp(),
467 frame2.GetYPlane() + vcrop * frame2.GetYPitch()
470 frame2.GetUPlane() + vcrop * frame2.GetUPitch() / 2
473 frame2.GetVPlane() + vcrop * frame2.GetVPitch() / 2
479 static bool IsBlack(const cricket::VideoFrame& frame) {
480 return !IsNull(frame) &&
481 *frame.GetYPlane() == 16 &&
482 *frame.GetUPlane() == 128 &&
483 *frame.GetVPlane() == 128;
486 ////////////////////////
487 // Construction tests //
488 ////////////////////////
490 // Test constructing an image from a I420 buffer.
491 void ConstructI420() {
493 EXPECT_TRUE(IsNull(frame));
494 rtc::scoped_ptr<rtc::MemoryStream> ms(
495 CreateYuvSample(kWidth, kHeight, 12));
496 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420,
497 kWidth, kHeight, &frame));
499 const uint8* y = reinterpret_cast<uint8*>(ms.get()->GetBuffer());
500 const uint8* u = y + kWidth * kHeight;
501 const uint8* v = u + kWidth * kHeight / 4;
502 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 1, 1, 0, 0,
503 y, kWidth, u, kWidth / 2, v, kWidth / 2, 0));
506 // Test constructing an image from a YV12 buffer.
507 void ConstructYV12() {
509 rtc::scoped_ptr<rtc::MemoryStream> ms(
510 CreateYuvSample(kWidth, kHeight, 12));
511 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YV12,
512 kWidth, kHeight, &frame));
514 const uint8* y = reinterpret_cast<uint8*>(ms.get()->GetBuffer());
515 const uint8* v = y + kWidth * kHeight;
516 const uint8* u = v + kWidth * kHeight / 4;
517 EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 1, 1, 0, 0,
518 y, kWidth, u, kWidth / 2, v, kWidth / 2, 0));
521 // Test constructing an image from a I422 buffer.
522 void ConstructI422() {
524 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
525 size_t buf_size = kWidth * kHeight * 2;
526 rtc::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
527 uint8* y = ALIGNP(buf.get(), kAlignment);
528 uint8* u = y + kWidth * kHeight;
529 uint8* v = u + (kWidth / 2) * kHeight;
530 EXPECT_EQ(0, libyuv::I420ToI422(frame1.GetYPlane(), frame1.GetYPitch(),
531 frame1.GetUPlane(), frame1.GetUPitch(),
532 frame1.GetVPlane(), frame1.GetVPitch(),
537 EXPECT_TRUE(LoadFrame(y, buf_size, cricket::FOURCC_I422,
538 kWidth, kHeight, &frame2));
539 EXPECT_TRUE(IsEqual(frame1, frame2, 1));
542 // Test constructing an image from a YUY2 buffer.
543 void ConstructYuy2() {
545 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
546 size_t buf_size = kWidth * kHeight * 2;
547 rtc::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
548 uint8* yuy2 = ALIGNP(buf.get(), kAlignment);
549 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
550 frame1.GetUPlane(), frame1.GetUPitch(),
551 frame1.GetVPlane(), frame1.GetVPitch(),
554 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2,
555 kWidth, kHeight, &frame2));
556 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
559 // Test constructing an image from a YUY2 buffer with buffer unaligned.
560 void ConstructYuy2Unaligned() {
562 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
563 size_t buf_size = kWidth * kHeight * 2;
564 rtc::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment + 1]);
565 uint8* yuy2 = ALIGNP(buf.get(), kAlignment) + 1;
566 EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
567 frame1.GetUPlane(), frame1.GetUPitch(),
568 frame1.GetVPlane(), frame1.GetVPitch(),
571 EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2,
572 kWidth, kHeight, &frame2));
573 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
576 // Test constructing an image from a wide YUY2 buffer.
577 // Normal is 1280x720. Wide is 12800x72
578 void ConstructYuy2Wide() {
580 rtc::scoped_ptr<rtc::MemoryStream> ms(
581 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth * 10, kHeight / 10));
582 ASSERT_TRUE(ms.get() != NULL);
583 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2,
584 kWidth * 10, kHeight / 10,
586 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
587 kWidth * 10, kHeight / 10, &frame2));
588 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
591 // Test constructing an image from a UYVY buffer.
592 void ConstructUyvy() {
594 rtc::scoped_ptr<rtc::MemoryStream> ms(
595 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
596 ASSERT_TRUE(ms.get() != NULL);
597 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
599 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
600 kWidth, kHeight, &frame2));
601 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
604 // Test constructing an image from a random buffer.
605 // We are merely verifying that the code succeeds and is free of crashes.
606 void ConstructM420() {
608 rtc::scoped_ptr<rtc::MemoryStream> ms(
609 CreateYuvSample(kWidth, kHeight, 12));
610 ASSERT_TRUE(ms.get() != NULL);
611 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_M420,
612 kWidth, kHeight, &frame));
615 void ConstructQ420() {
617 rtc::scoped_ptr<rtc::MemoryStream> ms(
618 CreateYuvSample(kWidth, kHeight, 12));
619 ASSERT_TRUE(ms.get() != NULL);
620 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_Q420,
621 kWidth, kHeight, &frame));
624 void ConstructNV21() {
626 rtc::scoped_ptr<rtc::MemoryStream> ms(
627 CreateYuvSample(kWidth, kHeight, 12));
628 ASSERT_TRUE(ms.get() != NULL);
629 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV21,
630 kWidth, kHeight, &frame));
633 void ConstructNV12() {
635 rtc::scoped_ptr<rtc::MemoryStream> ms(
636 CreateYuvSample(kWidth, kHeight, 12));
637 ASSERT_TRUE(ms.get() != NULL);
638 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV12,
639 kWidth, kHeight, &frame));
642 // Test constructing an image from a ABGR buffer
643 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
644 void ConstructABGR() {
646 rtc::scoped_ptr<rtc::MemoryStream> ms(
647 CreateRgbSample(cricket::FOURCC_ABGR, kWidth, kHeight));
648 ASSERT_TRUE(ms.get() != NULL);
649 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ABGR, kWidth, kHeight,
651 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ABGR,
652 kWidth, kHeight, &frame2));
653 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
656 // Test constructing an image from a ARGB buffer
657 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
658 void ConstructARGB() {
660 rtc::scoped_ptr<rtc::MemoryStream> ms(
661 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));
662 ASSERT_TRUE(ms.get() != NULL);
663 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight,
665 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
666 kWidth, kHeight, &frame2));
667 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
670 // Test constructing an image from a wide ARGB buffer
671 // Normal is 1280x720. Wide is 12800x72
672 void ConstructARGBWide() {
674 rtc::scoped_ptr<rtc::MemoryStream> ms(
675 CreateRgbSample(cricket::FOURCC_ARGB, kWidth * 10, kHeight / 10));
676 ASSERT_TRUE(ms.get() != NULL);
677 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
678 kWidth * 10, kHeight / 10, &frame1));
679 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
680 kWidth * 10, kHeight / 10, &frame2));
681 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
684 // Test constructing an image from an BGRA buffer.
685 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
686 void ConstructBGRA() {
688 rtc::scoped_ptr<rtc::MemoryStream> ms(
689 CreateRgbSample(cricket::FOURCC_BGRA, kWidth, kHeight));
690 ASSERT_TRUE(ms.get() != NULL);
691 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_BGRA, kWidth, kHeight,
693 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_BGRA,
694 kWidth, kHeight, &frame2));
695 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
698 // Test constructing an image from a 24BG buffer.
699 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
700 void Construct24BG() {
702 rtc::scoped_ptr<rtc::MemoryStream> ms(
703 CreateRgbSample(cricket::FOURCC_24BG, kWidth, kHeight));
704 ASSERT_TRUE(ms.get() != NULL);
705 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_24BG, kWidth, kHeight,
707 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_24BG,
708 kWidth, kHeight, &frame2));
709 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
712 // Test constructing an image from a raw RGB buffer.
713 // Due to rounding, some pixels may differ slightly from the VideoFrame impl.
714 void ConstructRaw() {
716 rtc::scoped_ptr<rtc::MemoryStream> ms(
717 CreateRgbSample(cricket::FOURCC_RAW, kWidth, kHeight));
718 ASSERT_TRUE(ms.get() != NULL);
719 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_RAW, kWidth, kHeight,
721 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_RAW,
722 kWidth, kHeight, &frame2));
723 EXPECT_TRUE(IsEqual(frame1, frame2, 2));
726 // Test constructing an image from a RGB565 buffer
727 void ConstructRGB565() {
729 size_t out_size = kWidth * kHeight * 2;
730 rtc::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
731 uint8* out = ALIGNP(outbuf.get(), kAlignment);
733 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
734 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_RGBP,
736 out_size, kWidth * 2));
737 EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_RGBP,
738 kWidth, kHeight, &frame2));
739 EXPECT_TRUE(IsEqual(frame1, frame2, 20));
742 // Test constructing an image from a ARGB1555 buffer
743 void ConstructARGB1555() {
745 size_t out_size = kWidth * kHeight * 2;
746 rtc::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
747 uint8* out = ALIGNP(outbuf.get(), kAlignment);
749 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
750 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_RGBO,
752 out_size, kWidth * 2));
753 EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_RGBO,
754 kWidth, kHeight, &frame2));
755 EXPECT_TRUE(IsEqual(frame1, frame2, 20));
758 // Test constructing an image from a ARGB4444 buffer
759 void ConstructARGB4444() {
761 size_t out_size = kWidth * kHeight * 2;
762 rtc::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
763 uint8* out = ALIGNP(outbuf.get(), kAlignment);
765 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
766 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_R444,
768 out_size, kWidth * 2));
769 EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_R444,
770 kWidth, kHeight, &frame2));
771 EXPECT_TRUE(IsEqual(frame1, frame2, 20));
774 // Macro to help test different Bayer formats.
775 // Error threshold of 60 allows for Bayer format subsampling.
776 // TODO(fbarchard): Refactor this test to go from Bayer to I420 and
777 // back to bayer, which would be less lossy.
778 #define TEST_BYR(NAME, BAYER) \
780 size_t bayer_size = kWidth * kHeight; \
781 rtc::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
782 bayer_size + kAlignment]); \
783 uint8* bayer = ALIGNP(bayerbuf.get(), kAlignment); \
785 rtc::scoped_ptr<rtc::MemoryStream> ms( \
786 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
787 ASSERT_TRUE(ms.get() != NULL); \
788 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8* >(ms->GetBuffer()), \
792 EXPECT_TRUE(LoadFrame(bayer, bayer_size, cricket::FOURCC_##BAYER, \
793 kWidth, kHeight, &frame1)); \
794 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight, \
796 EXPECT_TRUE(IsEqual(frame1, frame2, 60)); \
799 // Test constructing an image from Bayer formats.
800 TEST_BYR(ConstructBayerGRBG, GRBG)
801 TEST_BYR(ConstructBayerGBRG, GBRG)
802 TEST_BYR(ConstructBayerBGGR, BGGR)
803 TEST_BYR(ConstructBayerRGGB, RGGB)
806 // Macro to help test different rotations
807 #define TEST_MIRROR(FOURCC, BPP) \
808 void Construct##FOURCC##Mirror() { \
809 T frame1, frame2, frame3; \
810 rtc::scoped_ptr<rtc::MemoryStream> ms( \
811 CreateYuvSample(kWidth, kHeight, BPP)); \
812 ASSERT_TRUE(ms.get() != NULL); \
813 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, \
814 kWidth, -kHeight, kWidth, kHeight, \
815 cricket::ROTATION_180, &frame1)); \
817 bool ret = ms->GetSize(&data_size); \
819 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, \
820 kWidth, kHeight, kWidth, kHeight, \
821 reinterpret_cast<uint8*>(ms->GetBuffer()), \
824 int width_rotate = static_cast<int>(frame1.GetWidth()); \
825 int height_rotate = static_cast<int>(frame1.GetHeight()); \
826 EXPECT_TRUE(frame3.InitToBlack(width_rotate, height_rotate, 1, 1, 0, 0)); \
827 libyuv::I420Mirror(frame2.GetYPlane(), frame2.GetYPitch(), \
828 frame2.GetUPlane(), frame2.GetUPitch(), \
829 frame2.GetVPlane(), frame2.GetVPitch(), \
830 frame3.GetYPlane(), frame3.GetYPitch(), \
831 frame3.GetUPlane(), frame3.GetUPitch(), \
832 frame3.GetVPlane(), frame3.GetVPitch(), \
834 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \
837 TEST_MIRROR(I420, 420)
839 // Macro to help test different rotations
840 #define TEST_ROTATE(FOURCC, BPP, ROTATE) \
841 void Construct##FOURCC##Rotate##ROTATE() { \
842 T frame1, frame2, frame3; \
843 rtc::scoped_ptr<rtc::MemoryStream> ms( \
844 CreateYuvSample(kWidth, kHeight, BPP)); \
845 ASSERT_TRUE(ms.get() != NULL); \
846 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, \
847 kWidth, kHeight, kWidth, kHeight, \
848 cricket::ROTATION_##ROTATE, &frame1)); \
850 bool ret = ms->GetSize(&data_size); \
852 EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, \
853 kWidth, kHeight, kWidth, kHeight, \
854 reinterpret_cast<uint8*>(ms->GetBuffer()), \
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, 1, 1, 0, 0)); \
860 libyuv::I420Rotate(frame2.GetYPlane(), frame2.GetYPitch(), \
861 frame2.GetUPlane(), frame2.GetUPitch(), \
862 frame2.GetVPlane(), frame2.GetVPitch(), \
863 frame3.GetYPlane(), frame3.GetYPitch(), \
864 frame3.GetUPlane(), frame3.GetUPitch(), \
865 frame3.GetVPlane(), frame3.GetVPitch(), \
866 kWidth, kHeight, libyuv::kRotate##ROTATE); \
867 EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \
870 // Test constructing an image with rotation.
871 TEST_ROTATE(I420, 12, 0)
872 TEST_ROTATE(I420, 12, 90)
873 TEST_ROTATE(I420, 12, 180)
874 TEST_ROTATE(I420, 12, 270)
875 TEST_ROTATE(YV12, 12, 0)
876 TEST_ROTATE(YV12, 12, 90)
877 TEST_ROTATE(YV12, 12, 180)
878 TEST_ROTATE(YV12, 12, 270)
879 TEST_ROTATE(NV12, 12, 0)
880 TEST_ROTATE(NV12, 12, 90)
881 TEST_ROTATE(NV12, 12, 180)
882 TEST_ROTATE(NV12, 12, 270)
883 TEST_ROTATE(NV21, 12, 0)
884 TEST_ROTATE(NV21, 12, 90)
885 TEST_ROTATE(NV21, 12, 180)
886 TEST_ROTATE(NV21, 12, 270)
887 TEST_ROTATE(UYVY, 16, 0)
888 TEST_ROTATE(UYVY, 16, 90)
889 TEST_ROTATE(UYVY, 16, 180)
890 TEST_ROTATE(UYVY, 16, 270)
891 TEST_ROTATE(YUY2, 16, 0)
892 TEST_ROTATE(YUY2, 16, 90)
893 TEST_ROTATE(YUY2, 16, 180)
894 TEST_ROTATE(YUY2, 16, 270)
896 // Test constructing an image from a UYVY buffer rotated 90 degrees.
897 void ConstructUyvyRotate90() {
899 rtc::scoped_ptr<rtc::MemoryStream> ms(
900 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
901 ASSERT_TRUE(ms.get() != NULL);
902 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
903 kWidth, kHeight, kWidth, kHeight,
904 cricket::ROTATION_90, &frame2));
907 // Test constructing an image from a UYVY buffer rotated 180 degrees.
908 void ConstructUyvyRotate180() {
910 rtc::scoped_ptr<rtc::MemoryStream> ms(
911 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
912 ASSERT_TRUE(ms.get() != NULL);
913 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
914 kWidth, kHeight, kWidth, kHeight,
915 cricket::ROTATION_180, &frame2));
918 // Test constructing an image from a UYVY buffer rotated 270 degrees.
919 void ConstructUyvyRotate270() {
921 rtc::scoped_ptr<rtc::MemoryStream> ms(
922 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
923 ASSERT_TRUE(ms.get() != NULL);
924 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
925 kWidth, kHeight, kWidth, kHeight,
926 cricket::ROTATION_270, &frame2));
929 // Test constructing an image from a YUY2 buffer rotated 90 degrees.
930 void ConstructYuy2Rotate90() {
932 rtc::scoped_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,
936 kWidth, kHeight, kWidth, kHeight,
937 cricket::ROTATION_90, &frame2));
940 // Test constructing an image from a YUY2 buffer rotated 180 degrees.
941 void ConstructYuy2Rotate180() {
943 rtc::scoped_ptr<rtc::MemoryStream> ms(
944 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
945 ASSERT_TRUE(ms.get() != NULL);
946 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
947 kWidth, kHeight, kWidth, kHeight,
948 cricket::ROTATION_180, &frame2));
951 // Test constructing an image from a YUY2 buffer rotated 270 degrees.
952 void ConstructYuy2Rotate270() {
954 rtc::scoped_ptr<rtc::MemoryStream> ms(
955 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
956 ASSERT_TRUE(ms.get() != NULL);
957 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
958 kWidth, kHeight, kWidth, kHeight,
959 cricket::ROTATION_270, &frame2));
962 // Test 1 pixel edge case image I420 buffer.
963 void ConstructI4201Pixel() {
965 uint8 pixel[3] = { 1, 2, 3 };
966 for (int i = 0; i < repeat_; ++i) {
967 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1,
968 pixel, sizeof(pixel),
971 const uint8* y = pixel;
972 const uint8* u = y + 1;
973 const uint8* v = u + 1;
974 EXPECT_TRUE(IsEqual(frame, 1, 1, 1, 1, 0, 0,
975 y, 1, u, 1, v, 1, 0));
978 // Test 5 pixel edge case image I420 buffer rounds down to 4.
979 void ConstructI4205Pixel() {
981 uint8 pixels5x5[5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2];
982 memset(pixels5x5, 1, 5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2);
983 for (int i = 0; i < repeat_; ++i) {
984 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 5, 5, 5, 5,
985 pixels5x5, sizeof(pixels5x5),
988 EXPECT_EQ(4u, frame.GetWidth());
989 EXPECT_EQ(4u, frame.GetHeight());
990 EXPECT_EQ(4, frame.GetYPitch());
991 EXPECT_EQ(2, frame.GetUPitch());
992 EXPECT_EQ(2, frame.GetVPitch());
995 // Test 1 pixel edge case image ARGB buffer.
996 void ConstructARGB1Pixel() {
998 uint8 pixel[4] = { 64, 128, 192, 255 };
999 for (int i = 0; i < repeat_; ++i) {
1000 EXPECT_TRUE(frame.Init(cricket::FOURCC_ARGB, 1, 1, 1, 1,
1001 pixel, sizeof(pixel),
1004 // Convert back to ARGB.
1005 size_t out_size = 4;
1006 rtc::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
1007 uint8* out = ALIGNP(outbuf.get(), kAlignment);
1009 EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
1011 out_size, // buffer size
1012 out_size)); // stride
1013 #ifdef USE_LMI_CONVERT
1014 // TODO(fbarchard): Expected to fail, but not crash.
1015 EXPECT_FALSE(IsPlaneEqual("argb", pixel, 4, out, 4, 3, 1, 2));
1017 // TODO(fbarchard): Check for overwrite.
1018 EXPECT_TRUE(IsPlaneEqual("argb", pixel, 4, out, 4, 3, 1, 2));
1022 // Test Black, White and Grey pixels.
1023 void ConstructARGBBlackWhitePixel() {
1025 uint8 pixel[10 * 4] = { 0, 0, 0, 255, // Black.
1027 64, 64, 64, 255, // Dark Grey.
1029 128, 128, 128, 255, // Grey.
1031 196, 196, 196, 255, // Light Grey.
1033 255, 255, 255, 255, // White.
1034 255, 255, 255, 255 };
1036 for (int i = 0; i < repeat_; ++i) {
1037 EXPECT_TRUE(frame.Init(cricket::FOURCC_ARGB, 10, 1, 10, 1,
1038 pixel, sizeof(pixel),
1041 // Convert back to ARGB
1042 size_t out_size = 10 * 4;
1043 rtc::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
1044 uint8* out = ALIGNP(outbuf.get(), kAlignment);
1046 EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
1048 out_size, // buffer size.
1049 out_size)); // stride.
1050 EXPECT_TRUE(IsPlaneEqual("argb", pixel, out_size,
1055 // Test constructing an image from an I420 buffer with horizontal cropping.
1056 void ConstructI420CropHorizontal() {
1058 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1059 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight,
1060 kWidth * 3 / 4, kHeight, 0, &frame2));
1061 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0));
1064 // Test constructing an image from a YUY2 buffer with horizontal cropping.
1065 void ConstructYuy2CropHorizontal() {
1067 rtc::scoped_ptr<rtc::MemoryStream> ms(
1068 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
1069 ASSERT_TRUE(ms.get() != NULL);
1070 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
1072 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
1073 kWidth * 3 / 4, kHeight, 0, &frame2));
1074 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0));
1077 // Test constructing an image from an ARGB buffer with horizontal cropping.
1078 void ConstructARGBCropHorizontal() {
1080 rtc::scoped_ptr<rtc::MemoryStream> ms(
1081 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight));
1082 ASSERT_TRUE(ms.get() != NULL);
1083 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight,
1085 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight,
1086 kWidth * 3 / 4, kHeight, 0, &frame2));
1087 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 2));
1090 // Test constructing an image from an I420 buffer, cropping top and bottom.
1091 void ConstructI420CropVertical() {
1093 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1094 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight,
1095 kWidth, kHeight * 3 / 4, 0, &frame2));
1096 EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, 0, kHeight / 8, 0));
1099 // Test constructing an image from I420 synonymous formats.
1100 void ConstructI420Aliases() {
1101 T frame1, frame2, frame3;
1102 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight,
1104 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_IYUV, kWidth, kHeight,
1106 ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_YU12, kWidth, kHeight,
1108 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1109 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1112 // Test constructing an image from an I420 MJPG buffer.
1113 void ConstructMjpgI420() {
1115 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1116 ASSERT_TRUE(LoadFrame(kJpeg420Filename,
1117 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1118 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1121 // Test constructing an image from an I422 MJPG buffer.
1122 void ConstructMjpgI422() {
1124 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1125 ASSERT_TRUE(LoadFrame(kJpeg422Filename,
1126 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1127 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1130 // Test constructing an image from an I444 MJPG buffer.
1131 void ConstructMjpgI444() {
1133 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1134 ASSERT_TRUE(LoadFrame(kJpeg444Filename,
1135 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1136 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1139 // Test constructing an image from an I444 MJPG buffer.
1140 void ConstructMjpgI411() {
1142 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1143 ASSERT_TRUE(LoadFrame(kJpeg411Filename,
1144 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1145 EXPECT_TRUE(IsEqual(frame1, frame2, 32));
1148 // Test constructing an image from an I400 MJPG buffer.
1149 // TODO(fbarchard): Stronger compare on chroma. Compare agaisnt a grey image.
1150 void ConstructMjpgI400() {
1152 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1153 ASSERT_TRUE(LoadFrame(kJpeg400Filename,
1154 cricket::FOURCC_MJPG, kWidth, kHeight, &frame2));
1155 EXPECT_TRUE(IsPlaneEqual("y", frame1.GetYPlane(), frame1.GetYPitch(),
1156 frame2.GetYPlane(), frame2.GetYPitch(),
1157 kWidth, kHeight, 32));
1158 EXPECT_TRUE(IsEqual(frame1, frame2, 128));
1161 // Test constructing an image from an I420 MJPG buffer.
1162 void ValidateFrame(const char* name, uint32 fourcc, int data_adjust,
1163 int size_adjust, bool expected_result) {
1165 rtc::scoped_ptr<rtc::MemoryStream> ms(LoadSample(name));
1166 ASSERT_TRUE(ms.get() != NULL);
1167 const uint8* sample = reinterpret_cast<const uint8*>(ms.get()->GetBuffer());
1169 ms->GetSize(&sample_size);
1170 // Optional adjust size to test invalid size.
1171 size_t data_size = sample_size + data_adjust;
1173 // Allocate a buffer with end page aligned.
1174 const int kPadToHeapSized = 16 * 1024 * 1024;
1175 rtc::scoped_ptr<uint8[]> page_buffer(
1176 new uint8[((data_size + kPadToHeapSized + 4095) & ~4095)]);
1177 uint8* data_ptr = page_buffer.get();
1179 LOG(LS_WARNING) << "Failed to allocate memory for ValidateFrame test.";
1180 EXPECT_FALSE(expected_result); // NULL is okay if failure was expected.
1183 data_ptr += kPadToHeapSized + (-(static_cast<int>(data_size)) & 4095);
1184 memcpy(data_ptr, sample, rtc::_min(data_size, sample_size));
1185 for (int i = 0; i < repeat_; ++i) {
1186 EXPECT_EQ(expected_result, frame.Validate(fourcc, kWidth, kHeight,
1188 sample_size + size_adjust));
1192 // Test validate for I420 MJPG buffer.
1193 void ValidateMjpgI420() {
1194 ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, 0, 0, true);
1197 // Test validate for I422 MJPG buffer.
1198 void ValidateMjpgI422() {
1199 ValidateFrame(kJpeg422Filename, cricket::FOURCC_MJPG, 0, 0, true);
1202 // Test validate for I444 MJPG buffer.
1203 void ValidateMjpgI444() {
1204 ValidateFrame(kJpeg444Filename, cricket::FOURCC_MJPG, 0, 0, true);
1207 // Test validate for I411 MJPG buffer.
1208 void ValidateMjpgI411() {
1209 ValidateFrame(kJpeg411Filename, cricket::FOURCC_MJPG, 0, 0, true);
1212 // Test validate for I400 MJPG buffer.
1213 void ValidateMjpgI400() {
1214 ValidateFrame(kJpeg400Filename, cricket::FOURCC_MJPG, 0, 0, true);
1217 // Test validate for I420 buffer.
1218 void ValidateI420() {
1219 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, 0, true);
1222 // Test validate for I420 buffer where size is too small
1223 void ValidateI420SmallSize() {
1224 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, -16384, false);
1227 // Test validate for I420 buffer where size is too large (16 MB)
1228 // Will produce warning but pass.
1229 void ValidateI420LargeSize() {
1230 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 16000000, 16000000,
1234 // Test validate for I420 buffer where size is 1 GB (not reasonable).
1235 void ValidateI420HugeSize() {
1236 #ifndef WIN32 // TODO(fbarchard): Reenable when fixing bug 9603762.
1237 ValidateFrame(kImageFilename, cricket::FOURCC_I420, 1000000000u,
1238 1000000000u, false);
1242 // The following test that Validate crashes if the size is greater than the
1243 // actual buffer size.
1244 // TODO(fbarchard): Consider moving a filter into the capturer/plugin.
1245 #if defined(_MSC_VER) && defined(_DEBUG)
1246 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
1247 if (code == EXCEPTION_ACCESS_VIOLATION) {
1248 LOG(LS_INFO) << "Caught EXCEPTION_ACCESS_VIOLATION as expected.";
1249 return EXCEPTION_EXECUTE_HANDLER;
1251 LOG(LS_INFO) << "Did not catch EXCEPTION_ACCESS_VIOLATION. Unexpected.";
1252 return EXCEPTION_CONTINUE_SEARCH;
1256 // Test validate fails for truncated MJPG data buffer. If ValidateFrame
1257 // crashes the exception handler will return and unittest passes with OK.
1258 void ValidateMjpgI420InvalidSize() {
1260 ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, -16384, 0, false);
1261 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
1262 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1263 return; // Successfully crashed in ValidateFrame.
1267 // Test validate fails for truncated I420 buffer.
1268 void ValidateI420InvalidSize() {
1270 ValidateFrame(kImageFilename, cricket::FOURCC_I420, -16384, 0, false);
1271 FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION.";
1272 } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1273 return; // Successfully crashed in ValidateFrame.
1278 // Test constructing an image from a YUY2 buffer (and synonymous formats).
1279 void ConstructYuy2Aliases() {
1280 T frame1, frame2, frame3, frame4;
1281 rtc::scoped_ptr<rtc::MemoryStream> ms(
1282 CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight));
1283 ASSERT_TRUE(ms.get() != NULL);
1284 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight,
1286 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
1287 kWidth, kHeight, &frame2));
1288 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUVS,
1289 kWidth, kHeight, &frame3));
1290 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUYV,
1291 kWidth, kHeight, &frame4));
1292 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1293 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1294 EXPECT_TRUE(IsEqual(frame1, frame4, 0));
1297 // Test constructing an image from a UYVY buffer (and synonymous formats).
1298 void ConstructUyvyAliases() {
1299 T frame1, frame2, frame3, frame4;
1300 rtc::scoped_ptr<rtc::MemoryStream> ms(
1301 CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight));
1302 ASSERT_TRUE(ms.get() != NULL);
1303 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight,
1305 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY,
1306 kWidth, kHeight, &frame2));
1307 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_2VUY,
1308 kWidth, kHeight, &frame3));
1309 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_HDYC,
1310 kWidth, kHeight, &frame4));
1311 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1312 EXPECT_TRUE(IsEqual(frame1, frame3, 0));
1313 EXPECT_TRUE(IsEqual(frame1, frame4, 0));
1316 // Test creating a copy.
1317 void ConstructCopy() {
1319 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1320 for (int i = 0; i < repeat_; ++i) {
1321 EXPECT_TRUE(frame2.Init(frame1));
1323 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1326 // Test creating a copy and check that it just increments the refcount.
1327 void ConstructCopyIsRef() {
1329 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1330 for (int i = 0; i < repeat_; ++i) {
1331 EXPECT_TRUE(frame2.Init(frame1));
1333 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1334 EXPECT_EQ(frame1.GetYPlane(), frame2.GetYPlane());
1335 EXPECT_EQ(frame1.GetUPlane(), frame2.GetUPlane());
1336 EXPECT_EQ(frame1.GetVPlane(), frame2.GetVPlane());
1339 // Test creating an empty image and initing it to black.
1340 void ConstructBlack() {
1342 for (int i = 0; i < repeat_; ++i) {
1343 EXPECT_TRUE(frame.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1345 EXPECT_TRUE(IsSize(frame, kWidth, kHeight));
1346 EXPECT_TRUE(IsBlack(frame));
1349 // Test constructing an image from a YUY2 buffer with a range of sizes.
1350 // Only tests that conversion does not crash or corrupt heap.
1351 void ConstructYuy2AllSizes() {
1353 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
1354 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
1355 rtc::scoped_ptr<rtc::MemoryStream> ms(
1356 CreateYuv422Sample(cricket::FOURCC_YUY2, width, height));
1357 ASSERT_TRUE(ms.get() != NULL);
1358 EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, width, height,
1360 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2,
1361 width, height, &frame2));
1362 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1367 // Test constructing an image from a ARGB buffer with a range of sizes.
1368 // Only tests that conversion does not crash or corrupt heap.
1369 void ConstructARGBAllSizes() {
1371 for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) {
1372 for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) {
1373 rtc::scoped_ptr<rtc::MemoryStream> ms(
1374 CreateRgbSample(cricket::FOURCC_ARGB, width, height));
1375 ASSERT_TRUE(ms.get() != NULL);
1376 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, width, height,
1378 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
1379 width, height, &frame2));
1380 EXPECT_TRUE(IsEqual(frame1, frame2, 64));
1383 // Test a practical window size for screencasting usecase.
1384 const int kOddWidth = 1228;
1385 const int kOddHeight = 260;
1386 for (int j = 0; j < 2; ++j) {
1387 for (int i = 0; i < 2; ++i) {
1388 rtc::scoped_ptr<rtc::MemoryStream> ms(
1389 CreateRgbSample(cricket::FOURCC_ARGB, kOddWidth + i, kOddHeight + j));
1390 ASSERT_TRUE(ms.get() != NULL);
1391 EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB,
1392 kOddWidth + i, kOddHeight + j,
1394 EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB,
1395 kOddWidth + i, kOddHeight + j, &frame2));
1396 EXPECT_TRUE(IsEqual(frame1, frame2, 64));
1401 // Tests re-initing an existing image.
1404 rtc::scoped_ptr<rtc::MemoryStream> ms(
1405 LoadSample(kImageFilename));
1406 ASSERT_TRUE(ms.get() != NULL);
1408 ms->GetSize(&data_size);
1409 EXPECT_TRUE(frame1.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1410 EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1411 EXPECT_TRUE(IsBlack(frame1));
1412 EXPECT_TRUE(IsEqual(frame1, frame2, 0));
1413 EXPECT_TRUE(frame1.Reset(cricket::FOURCC_I420,
1414 kWidth, kHeight, kWidth, kHeight,
1415 reinterpret_cast<uint8*>(ms->GetBuffer()),
1416 data_size, 1, 1, 0, 0, 0));
1417 EXPECT_FALSE(IsBlack(frame1));
1418 EXPECT_FALSE(IsEqual(frame1, frame2, 0));
1421 //////////////////////
1422 // Conversion tests //
1423 //////////////////////
1425 enum ToFrom { TO, FROM };
1427 // Helper function for test converting from I420 to packed formats.
1428 inline void ConvertToBuffer(int bpp, int rowpad, bool invert, ToFrom to_from,
1429 int error, uint32 fourcc,
1430 int (*RGBToI420)(const uint8* src_frame, int src_stride_frame,
1431 uint8* dst_y, int dst_stride_y,
1432 uint8* dst_u, int dst_stride_u,
1433 uint8* dst_v, int dst_stride_v,
1434 int width, int height)) {
1436 int repeat_to = (to_from == TO) ? repeat_ : 1;
1437 int repeat_from = (to_from == FROM) ? repeat_ : 1;
1439 int astride = kWidth * bpp + rowpad;
1440 size_t out_size = astride * kHeight;
1441 rtc::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment + 1]);
1442 memset(outbuf.get(), 0, out_size + kAlignment + 1);
1443 uint8* outtop = ALIGNP(outbuf.get(), kAlignment);
1444 uint8* out = outtop;
1445 int stride = astride;
1447 out += (kHeight - 1) * stride; // Point to last row.
1450 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1452 for (int i = 0; i < repeat_to; ++i) {
1453 EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(fourcc,
1457 EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0));
1458 for (int i = 0; i < repeat_from; ++i) {
1459 EXPECT_EQ(0, RGBToI420(out, stride,
1460 frame2.GetYPlane(), frame2.GetYPitch(),
1461 frame2.GetUPlane(), frame2.GetUPitch(),
1462 frame2.GetVPlane(), frame2.GetVPitch(),
1466 EXPECT_EQ(0, outtop[kWidth * bpp]); // Ensure stride skipped end of row.
1467 EXPECT_NE(0, outtop[astride]); // Ensure pixel at start of 2nd row.
1469 EXPECT_NE(0, outtop[kWidth * bpp]); // Expect something to be here.
1471 EXPECT_EQ(0, outtop[out_size]); // Ensure no overrun.
1472 EXPECT_TRUE(IsEqual(frame1, frame2, error));
1475 static const int kError = 20;
1476 static const int kErrorHigh = 40;
1477 static const int kOddStride = 23;
1479 // Tests ConvertToRGBBuffer formats.
1480 void ConvertToARGBBuffer() {
1481 ConvertToBuffer(4, 0, false, TO, kError,
1482 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1484 void ConvertToBGRABuffer() {
1485 ConvertToBuffer(4, 0, false, TO, kError,
1486 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1488 void ConvertToABGRBuffer() {
1489 ConvertToBuffer(4, 0, false, TO, kError,
1490 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1492 void ConvertToRGB24Buffer() {
1493 ConvertToBuffer(3, 0, false, TO, kError,
1494 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1496 void ConvertToRAWBuffer() {
1497 ConvertToBuffer(3, 0, false, TO, kError,
1498 cricket::FOURCC_RAW, libyuv::RAWToI420);
1500 void ConvertToRGB565Buffer() {
1501 ConvertToBuffer(2, 0, false, TO, kError,
1502 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1504 void ConvertToARGB1555Buffer() {
1505 ConvertToBuffer(2, 0, false, TO, kError,
1506 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1508 void ConvertToARGB4444Buffer() {
1509 ConvertToBuffer(2, 0, false, TO, kError,
1510 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1512 void ConvertToBayerBGGRBuffer() {
1513 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1514 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1516 void ConvertToBayerGBRGBuffer() {
1517 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1518 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1520 void ConvertToBayerGRBGBuffer() {
1521 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1522 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1524 void ConvertToBayerRGGBBuffer() {
1525 ConvertToBuffer(1, 0, false, TO, kErrorHigh,
1526 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1528 void ConvertToI400Buffer() {
1529 ConvertToBuffer(1, 0, false, TO, 128,
1530 cricket::FOURCC_I400, libyuv::I400ToI420);
1532 void ConvertToYUY2Buffer() {
1533 ConvertToBuffer(2, 0, false, TO, kError,
1534 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1536 void ConvertToUYVYBuffer() {
1537 ConvertToBuffer(2, 0, false, TO, kError,
1538 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1541 // Tests ConvertToRGBBuffer formats with odd stride.
1542 void ConvertToARGBBufferStride() {
1543 ConvertToBuffer(4, kOddStride, false, TO, kError,
1544 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1546 void ConvertToBGRABufferStride() {
1547 ConvertToBuffer(4, kOddStride, false, TO, kError,
1548 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1550 void ConvertToABGRBufferStride() {
1551 ConvertToBuffer(4, kOddStride, false, TO, kError,
1552 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1554 void ConvertToRGB24BufferStride() {
1555 ConvertToBuffer(3, kOddStride, false, TO, kError,
1556 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1558 void ConvertToRAWBufferStride() {
1559 ConvertToBuffer(3, kOddStride, false, TO, kError,
1560 cricket::FOURCC_RAW, libyuv::RAWToI420);
1562 void ConvertToRGB565BufferStride() {
1563 ConvertToBuffer(2, kOddStride, false, TO, kError,
1564 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1566 void ConvertToARGB1555BufferStride() {
1567 ConvertToBuffer(2, kOddStride, false, TO, kError,
1568 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1570 void ConvertToARGB4444BufferStride() {
1571 ConvertToBuffer(2, kOddStride, false, TO, kError,
1572 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1574 void ConvertToBayerBGGRBufferStride() {
1575 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1576 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1578 void ConvertToBayerGBRGBufferStride() {
1579 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1580 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1582 void ConvertToBayerGRBGBufferStride() {
1583 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1584 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1586 void ConvertToBayerRGGBBufferStride() {
1587 ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh,
1588 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1590 void ConvertToI400BufferStride() {
1591 ConvertToBuffer(1, kOddStride, false, TO, 128,
1592 cricket::FOURCC_I400, libyuv::I400ToI420);
1594 void ConvertToYUY2BufferStride() {
1595 ConvertToBuffer(2, kOddStride, false, TO, kError,
1596 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1598 void ConvertToUYVYBufferStride() {
1599 ConvertToBuffer(2, kOddStride, false, TO, kError,
1600 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1603 // Tests ConvertToRGBBuffer formats with negative stride to invert image.
1604 void ConvertToARGBBufferInverted() {
1605 ConvertToBuffer(4, 0, true, TO, kError,
1606 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1608 void ConvertToBGRABufferInverted() {
1609 ConvertToBuffer(4, 0, true, TO, kError,
1610 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1612 void ConvertToABGRBufferInverted() {
1613 ConvertToBuffer(4, 0, true, TO, kError,
1614 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1616 void ConvertToRGB24BufferInverted() {
1617 ConvertToBuffer(3, 0, true, TO, kError,
1618 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1620 void ConvertToRAWBufferInverted() {
1621 ConvertToBuffer(3, 0, true, TO, kError,
1622 cricket::FOURCC_RAW, libyuv::RAWToI420);
1624 void ConvertToRGB565BufferInverted() {
1625 ConvertToBuffer(2, 0, true, TO, kError,
1626 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1628 void ConvertToARGB1555BufferInverted() {
1629 ConvertToBuffer(2, 0, true, TO, kError,
1630 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1632 void ConvertToARGB4444BufferInverted() {
1633 ConvertToBuffer(2, 0, true, TO, kError,
1634 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1636 void ConvertToBayerBGGRBufferInverted() {
1637 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1638 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1640 void ConvertToBayerGBRGBufferInverted() {
1641 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1642 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1644 void ConvertToBayerGRBGBufferInverted() {
1645 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1646 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1648 void ConvertToBayerRGGBBufferInverted() {
1649 ConvertToBuffer(1, 0, true, TO, kErrorHigh,
1650 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1652 void ConvertToI400BufferInverted() {
1653 ConvertToBuffer(1, 0, true, TO, 128,
1654 cricket::FOURCC_I400, libyuv::I400ToI420);
1656 void ConvertToYUY2BufferInverted() {
1657 ConvertToBuffer(2, 0, true, TO, kError,
1658 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1660 void ConvertToUYVYBufferInverted() {
1661 ConvertToBuffer(2, 0, true, TO, kError,
1662 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1665 // Tests ConvertFrom formats.
1666 void ConvertFromARGBBuffer() {
1667 ConvertToBuffer(4, 0, false, FROM, kError,
1668 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1670 void ConvertFromBGRABuffer() {
1671 ConvertToBuffer(4, 0, false, FROM, kError,
1672 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1674 void ConvertFromABGRBuffer() {
1675 ConvertToBuffer(4, 0, false, FROM, kError,
1676 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1678 void ConvertFromRGB24Buffer() {
1679 ConvertToBuffer(3, 0, false, FROM, kError,
1680 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1682 void ConvertFromRAWBuffer() {
1683 ConvertToBuffer(3, 0, false, FROM, kError,
1684 cricket::FOURCC_RAW, libyuv::RAWToI420);
1686 void ConvertFromRGB565Buffer() {
1687 ConvertToBuffer(2, 0, false, FROM, kError,
1688 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1690 void ConvertFromARGB1555Buffer() {
1691 ConvertToBuffer(2, 0, false, FROM, kError,
1692 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1694 void ConvertFromARGB4444Buffer() {
1695 ConvertToBuffer(2, 0, false, FROM, kError,
1696 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1698 void ConvertFromBayerBGGRBuffer() {
1699 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1700 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1702 void ConvertFromBayerGBRGBuffer() {
1703 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1704 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1706 void ConvertFromBayerGRBGBuffer() {
1707 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1708 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1710 void ConvertFromBayerRGGBBuffer() {
1711 ConvertToBuffer(1, 0, false, FROM, kErrorHigh,
1712 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1714 void ConvertFromI400Buffer() {
1715 ConvertToBuffer(1, 0, false, FROM, 128,
1716 cricket::FOURCC_I400, libyuv::I400ToI420);
1718 void ConvertFromYUY2Buffer() {
1719 ConvertToBuffer(2, 0, false, FROM, kError,
1720 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1722 void ConvertFromUYVYBuffer() {
1723 ConvertToBuffer(2, 0, false, FROM, kError,
1724 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1727 // Tests ConvertFrom formats with odd stride.
1728 void ConvertFromARGBBufferStride() {
1729 ConvertToBuffer(4, kOddStride, false, FROM, kError,
1730 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1732 void ConvertFromBGRABufferStride() {
1733 ConvertToBuffer(4, kOddStride, false, FROM, kError,
1734 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1736 void ConvertFromABGRBufferStride() {
1737 ConvertToBuffer(4, kOddStride, false, FROM, kError,
1738 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1740 void ConvertFromRGB24BufferStride() {
1741 ConvertToBuffer(3, kOddStride, false, FROM, kError,
1742 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1744 void ConvertFromRAWBufferStride() {
1745 ConvertToBuffer(3, kOddStride, false, FROM, kError,
1746 cricket::FOURCC_RAW, libyuv::RAWToI420);
1748 void ConvertFromRGB565BufferStride() {
1749 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1750 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1752 void ConvertFromARGB1555BufferStride() {
1753 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1754 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1756 void ConvertFromARGB4444BufferStride() {
1757 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1758 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1760 void ConvertFromBayerBGGRBufferStride() {
1761 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1762 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1764 void ConvertFromBayerGBRGBufferStride() {
1765 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1766 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1768 void ConvertFromBayerGRBGBufferStride() {
1769 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1770 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1772 void ConvertFromBayerRGGBBufferStride() {
1773 ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh,
1774 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1776 void ConvertFromI400BufferStride() {
1777 ConvertToBuffer(1, kOddStride, false, FROM, 128,
1778 cricket::FOURCC_I400, libyuv::I400ToI420);
1780 void ConvertFromYUY2BufferStride() {
1781 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1782 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1784 void ConvertFromUYVYBufferStride() {
1785 ConvertToBuffer(2, kOddStride, false, FROM, kError,
1786 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1789 // Tests ConvertFrom formats with negative stride to invert image.
1790 void ConvertFromARGBBufferInverted() {
1791 ConvertToBuffer(4, 0, true, FROM, kError,
1792 cricket::FOURCC_ARGB, libyuv::ARGBToI420);
1794 void ConvertFromBGRABufferInverted() {
1795 ConvertToBuffer(4, 0, true, FROM, kError,
1796 cricket::FOURCC_BGRA, libyuv::BGRAToI420);
1798 void ConvertFromABGRBufferInverted() {
1799 ConvertToBuffer(4, 0, true, FROM, kError,
1800 cricket::FOURCC_ABGR, libyuv::ABGRToI420);
1802 void ConvertFromRGB24BufferInverted() {
1803 ConvertToBuffer(3, 0, true, FROM, kError,
1804 cricket::FOURCC_24BG, libyuv::RGB24ToI420);
1806 void ConvertFromRAWBufferInverted() {
1807 ConvertToBuffer(3, 0, true, FROM, kError,
1808 cricket::FOURCC_RAW, libyuv::RAWToI420);
1810 void ConvertFromRGB565BufferInverted() {
1811 ConvertToBuffer(2, 0, true, FROM, kError,
1812 cricket::FOURCC_RGBP, libyuv::RGB565ToI420);
1814 void ConvertFromARGB1555BufferInverted() {
1815 ConvertToBuffer(2, 0, true, FROM, kError,
1816 cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420);
1818 void ConvertFromARGB4444BufferInverted() {
1819 ConvertToBuffer(2, 0, true, FROM, kError,
1820 cricket::FOURCC_R444, libyuv::ARGB4444ToI420);
1822 void ConvertFromBayerBGGRBufferInverted() {
1823 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1824 cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420);
1826 void ConvertFromBayerGBRGBufferInverted() {
1827 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1828 cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420);
1830 void ConvertFromBayerGRBGBufferInverted() {
1831 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1832 cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420);
1834 void ConvertFromBayerRGGBBufferInverted() {
1835 ConvertToBuffer(1, 0, true, FROM, kErrorHigh,
1836 cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420);
1838 void ConvertFromI400BufferInverted() {
1839 ConvertToBuffer(1, 0, true, FROM, 128,
1840 cricket::FOURCC_I400, libyuv::I400ToI420);
1842 void ConvertFromYUY2BufferInverted() {
1843 ConvertToBuffer(2, 0, true, FROM, kError,
1844 cricket::FOURCC_YUY2, libyuv::YUY2ToI420);
1846 void ConvertFromUYVYBufferInverted() {
1847 ConvertToBuffer(2, 0, true, FROM, kError,
1848 cricket::FOURCC_UYVY, libyuv::UYVYToI420);
1851 // Test converting from I420 to I422.
1852 void ConvertToI422Buffer() {
1854 size_t out_size = kWidth * kHeight * 2;
1855 rtc::scoped_ptr<uint8[]> buf(new uint8[out_size + kAlignment]);
1856 uint8* y = ALIGNP(buf.get(), kAlignment);
1857 uint8* u = y + kWidth * kHeight;
1858 uint8* v = u + (kWidth / 2) * kHeight;
1859 ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
1860 for (int i = 0; i < repeat_; ++i) {
1861 EXPECT_EQ(0, libyuv::I420ToI422(frame1.GetYPlane(), frame1.GetYPitch(),
1862 frame1.GetUPlane(), frame1.GetUPitch(),
1863 frame1.GetVPlane(), frame1.GetVPitch(),
1869 EXPECT_TRUE(frame2.Init(cricket::FOURCC_I422,
1870 kWidth, kHeight, kWidth, kHeight,
1872 out_size, 1, 1, 0, 0, cricket::ROTATION_0));
1873 EXPECT_TRUE(IsEqual(frame1, frame2, 1));
1876 #define TEST_TOBYR(NAME, BAYER) \
1878 size_t bayer_size = kWidth * kHeight; \
1879 rtc::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
1880 bayer_size + kAlignment]); \
1881 uint8* bayer = ALIGNP(bayerbuf.get(), kAlignment); \
1883 rtc::scoped_ptr<rtc::MemoryStream> ms( \
1884 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1885 ASSERT_TRUE(ms.get() != NULL); \
1886 for (int i = 0; i < repeat_; ++i) { \
1887 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()), \
1892 rtc::scoped_ptr<rtc::MemoryStream> ms2( \
1893 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1895 bool ret = ms2->GetSize(&data_size); \
1897 libyuv::Bayer##BAYER##ToARGB(bayer, kWidth, \
1898 reinterpret_cast<uint8*>(ms2->GetBuffer()), \
1901 EXPECT_TRUE(IsPlaneEqual("argb", \
1902 reinterpret_cast<uint8*>(ms->GetBuffer()), kWidth * 4, \
1903 reinterpret_cast<uint8*>(ms2->GetBuffer()), kWidth * 4, \
1904 kWidth * 4, kHeight, 240)); \
1906 void NAME##Unaligned() { \
1907 size_t bayer_size = kWidth * kHeight; \
1908 rtc::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
1909 bayer_size + 1 + kAlignment]); \
1910 uint8* bayer = ALIGNP(bayerbuf.get(), kAlignment) + 1; \
1912 rtc::scoped_ptr<rtc::MemoryStream> ms( \
1913 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1914 ASSERT_TRUE(ms.get() != NULL); \
1915 for (int i = 0; i < repeat_; ++i) { \
1916 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()), \
1921 rtc::scoped_ptr<rtc::MemoryStream> ms2( \
1922 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1924 bool ret = ms2->GetSize(&data_size); \
1926 libyuv::Bayer##BAYER##ToARGB(bayer, kWidth, \
1927 reinterpret_cast<uint8*>(ms2->GetBuffer()), \
1930 EXPECT_TRUE(IsPlaneEqual("argb", \
1931 reinterpret_cast<uint8*>(ms->GetBuffer()), kWidth * 4, \
1932 reinterpret_cast<uint8*>(ms2->GetBuffer()), kWidth * 4, \
1933 kWidth * 4, kHeight, 240)); \
1936 // Tests ARGB to Bayer formats.
1937 TEST_TOBYR(ConvertARGBToBayerGRBG, GRBG)
1938 TEST_TOBYR(ConvertARGBToBayerGBRG, GBRG)
1939 TEST_TOBYR(ConvertARGBToBayerBGGR, BGGR)
1940 TEST_TOBYR(ConvertARGBToBayerRGGB, RGGB)
1942 #define TEST_BYRTORGB(NAME, BAYER) \
1944 size_t bayer_size = kWidth * kHeight; \
1945 rtc::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
1946 bayer_size + kAlignment]); \
1947 uint8* bayer1 = ALIGNP(bayerbuf.get(), kAlignment); \
1948 for (int i = 0; i < kWidth * kHeight; ++i) { \
1949 bayer1[i] = static_cast<uint8>(i * 33u + 183u); \
1952 rtc::scoped_ptr<rtc::MemoryStream> ms( \
1953 CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \
1954 ASSERT_TRUE(ms.get() != NULL); \
1955 for (int i = 0; i < repeat_; ++i) { \
1956 libyuv::Bayer##BAYER##ToARGB(bayer1, kWidth, \
1957 reinterpret_cast<uint8*>(ms->GetBuffer()), \
1961 rtc::scoped_ptr<uint8[]> bayer2buf(new uint8[ \
1962 bayer_size + kAlignment]); \
1963 uint8* bayer2 = ALIGNP(bayer2buf.get(), kAlignment); \
1964 libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()), \
1968 EXPECT_TRUE(IsPlaneEqual("bayer", \
1971 kWidth, kHeight, 0)); \
1974 // Tests Bayer formats to ARGB.
1975 TEST_BYRTORGB(ConvertBayerGRBGToARGB, GRBG)
1976 TEST_BYRTORGB(ConvertBayerGBRGToARGB, GBRG)
1977 TEST_BYRTORGB(ConvertBayerBGGRToARGB, BGGR)
1978 TEST_BYRTORGB(ConvertBayerRGGBToARGB, RGGB)
1985 rtc::scoped_ptr<T> source(new T);
1986 rtc::scoped_ptr<cricket::VideoFrame> target;
1987 ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
1988 target.reset(source->Copy());
1989 EXPECT_TRUE(IsEqual(*source, *target, 0));
1991 EXPECT_TRUE(target->GetYPlane() != NULL);
1995 rtc::scoped_ptr<T> source(new T);
1996 rtc::scoped_ptr<cricket::VideoFrame> target;
1997 ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
1998 target.reset(source->Copy());
1999 EXPECT_TRUE(IsEqual(*source, *target, 0));
2000 EXPECT_EQ(source->GetYPlane(), target->GetYPlane());
2001 EXPECT_EQ(source->GetUPlane(), target->GetUPlane());
2002 EXPECT_EQ(source->GetVPlane(), target->GetVPlane());
2005 void MakeExclusive() {
2006 rtc::scoped_ptr<T> source(new T);
2007 rtc::scoped_ptr<cricket::VideoFrame> target;
2008 ASSERT_TRUE(LoadFrameNoRepeat(source.get()));
2009 target.reset(source->Copy());
2010 EXPECT_TRUE(target->MakeExclusive());
2011 EXPECT_TRUE(IsEqual(*source, *target, 0));
2012 EXPECT_NE(target->GetYPlane(), source->GetYPlane());
2013 EXPECT_NE(target->GetUPlane(), source->GetUPlane());
2014 EXPECT_NE(target->GetVPlane(), source->GetVPlane());
2017 void CopyToBuffer() {
2019 rtc::scoped_ptr<rtc::MemoryStream> ms(
2020 LoadSample(kImageFilename));
2021 ASSERT_TRUE(ms.get() != NULL);
2022 ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
2024 size_t out_size = kWidth * kHeight * 3 / 2;
2025 rtc::scoped_ptr<uint8[]> out(new uint8[out_size]);
2026 for (int i = 0; i < repeat_; ++i) {
2027 EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
2029 EXPECT_EQ(0, memcmp(out.get(), ms->GetBuffer(), out_size));
2032 void CopyToFrame() {
2034 rtc::scoped_ptr<rtc::MemoryStream> ms(
2035 LoadSample(kImageFilename));
2036 ASSERT_TRUE(ms.get() != NULL);
2037 ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
2040 // Create the target frame by loading from a file.
2042 ASSERT_TRUE(LoadFrameNoRepeat(&target));
2043 EXPECT_FALSE(IsBlack(target));
2045 // Stretch and check if the stretched target is black.
2046 source.CopyToFrame(&target);
2048 EXPECT_TRUE(IsEqual(source, target, 0));
2053 rtc::scoped_ptr<rtc::MemoryStream> ms(
2054 LoadSample(kImageFilename));
2055 ASSERT_TRUE(ms.get() != NULL);
2056 rtc::MemoryStream ms2;
2058 ASSERT_TRUE(ms->GetSize(&size));
2059 ASSERT_TRUE(ms2.ReserveSize(size));
2060 ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
2062 for (int i = 0; i < repeat_; ++i) {
2063 ms2.SetPosition(0u); // Useful when repeat_ > 1.
2065 EXPECT_EQ(rtc::SR_SUCCESS, frame.Write(&ms2, &error));
2067 size_t out_size = cricket::VideoFrame::SizeOf(kWidth, kHeight);
2068 EXPECT_EQ(0, memcmp(ms2.GetBuffer(), ms->GetBuffer(), out_size));
2071 void CopyToBuffer1Pixel() {
2072 size_t out_size = 3;
2073 rtc::scoped_ptr<uint8[]> out(new uint8[out_size + 1]);
2074 memset(out.get(), 0xfb, out_size + 1); // Fill buffer
2075 uint8 pixel[3] = { 1, 2, 3 };
2077 EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1,
2078 pixel, sizeof(pixel),
2080 for (int i = 0; i < repeat_; ++i) {
2081 EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
2083 EXPECT_EQ(1, out.get()[0]); // Check Y. Should be 1.
2084 EXPECT_EQ(2, out.get()[1]); // Check U. Should be 2.
2085 EXPECT_EQ(3, out.get()[2]); // Check V. Should be 3.
2086 EXPECT_EQ(0xfb, out.get()[3]); // Check sentinel is still intact.
2089 void StretchToFrame() {
2090 // Create the source frame as a black frame.
2092 EXPECT_TRUE(source.InitToBlack(kWidth * 2, kHeight * 2, 1, 1, 0, 0));
2093 EXPECT_TRUE(IsSize(source, kWidth * 2, kHeight * 2));
2095 // Create the target frame by loading from a file.
2097 ASSERT_TRUE(LoadFrameNoRepeat(&target1));
2098 EXPECT_FALSE(IsBlack(target1));
2100 // Stretch and check if the stretched target is black.
2101 source.StretchToFrame(&target1, true, false);
2102 EXPECT_TRUE(IsBlack(target1));
2104 // Crop and stretch and check if the stretched target is black.
2106 ASSERT_TRUE(LoadFrameNoRepeat(&target2));
2107 source.StretchToFrame(&target2, true, true);
2108 EXPECT_TRUE(IsBlack(target2));
2109 EXPECT_EQ(source.GetElapsedTime(), target2.GetElapsedTime());
2110 EXPECT_EQ(source.GetTimeStamp(), target2.GetTimeStamp());
2116 #endif // TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_