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