1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "test/frame_generator.h"
12
13 #include <assert.h>
14 #include <stdio.h>
15 #include <string.h>
16
17 #include <cstdint>
18 #include <memory>
19 #include <string>
20
21 #include "api/scoped_refptr.h"
22 #include "api/test/create_frame_generator.h"
23 #include "api/test/frame_generator_interface.h"
24 #include "api/video/video_frame_buffer.h"
25 #include "test/gtest.h"
26 #include "test/testsupport/file_utils.h"
27
28 namespace webrtc {
29 namespace test {
30
31 static const int kFrameWidth = 4;
32 static const int kFrameHeight = 4;
33
34 class FrameGeneratorTest : public ::testing::Test {
35 public:
SetUp()36 void SetUp() override {
37 two_frame_filename_ =
38 test::TempFilename(test::OutputPath(), "2_frame_yuv_file");
39 one_frame_filename_ =
40 test::TempFilename(test::OutputPath(), "1_frame_yuv_file");
41
42 FILE* file = fopen(two_frame_filename_.c_str(), "wb");
43 WriteYuvFile(file, 0, 0, 0);
44 WriteYuvFile(file, 127, 127, 127);
45 fclose(file);
46 file = fopen(one_frame_filename_.c_str(), "wb");
47 WriteYuvFile(file, 255, 255, 255);
48 fclose(file);
49 }
TearDown()50 void TearDown() override {
51 remove(one_frame_filename_.c_str());
52 remove(two_frame_filename_.c_str());
53 }
54
55 protected:
WriteYuvFile(FILE * file,uint8_t y,uint8_t u,uint8_t v)56 void WriteYuvFile(FILE* file, uint8_t y, uint8_t u, uint8_t v) {
57 assert(file);
58 std::unique_ptr<uint8_t[]> plane_buffer(new uint8_t[y_size]);
59 memset(plane_buffer.get(), y, y_size);
60 fwrite(plane_buffer.get(), 1, y_size, file);
61 memset(plane_buffer.get(), u, uv_size);
62 fwrite(plane_buffer.get(), 1, uv_size, file);
63 memset(plane_buffer.get(), v, uv_size);
64 fwrite(plane_buffer.get(), 1, uv_size, file);
65 }
66
CheckFrameAndMutate(const FrameGeneratorInterface::VideoFrameData & frame,uint8_t y,uint8_t u,uint8_t v)67 void CheckFrameAndMutate(const FrameGeneratorInterface::VideoFrameData& frame,
68 uint8_t y,
69 uint8_t u,
70 uint8_t v) {
71 // Check that frame is valid, has the correct color and timestamp are clean.
72 rtc::scoped_refptr<I420BufferInterface> i420_buffer =
73 frame.buffer->ToI420();
74 const uint8_t* buffer;
75 buffer = i420_buffer->DataY();
76 for (int i = 0; i < y_size; ++i)
77 ASSERT_EQ(y, buffer[i]);
78 buffer = i420_buffer->DataU();
79 for (int i = 0; i < uv_size; ++i)
80 ASSERT_EQ(u, buffer[i]);
81 buffer = i420_buffer->DataV();
82 for (int i = 0; i < uv_size; ++i)
83 ASSERT_EQ(v, buffer[i]);
84 }
85
Hash(const FrameGeneratorInterface::VideoFrameData & frame)86 uint64_t Hash(const FrameGeneratorInterface::VideoFrameData& frame) {
87 // Generate a 64-bit hash from the frame's buffer.
88 uint64_t hash = 19;
89 rtc::scoped_refptr<I420BufferInterface> i420_buffer =
90 frame.buffer->ToI420();
91 const uint8_t* buffer = i420_buffer->DataY();
92 for (int i = 0; i < y_size; ++i) {
93 hash = (37 * hash) + buffer[i];
94 }
95 buffer = i420_buffer->DataU();
96 for (int i = 0; i < uv_size; ++i) {
97 hash = (37 * hash) + buffer[i];
98 }
99 buffer = i420_buffer->DataV();
100 for (int i = 0; i < uv_size; ++i) {
101 hash = (37 * hash) + buffer[i];
102 }
103 return hash;
104 }
105
106 std::string two_frame_filename_;
107 std::string one_frame_filename_;
108 const int y_size = kFrameWidth * kFrameHeight;
109 const int uv_size = ((kFrameHeight + 1) / 2) * ((kFrameWidth + 1) / 2);
110 };
111
TEST_F(FrameGeneratorTest,SingleFrameFile)112 TEST_F(FrameGeneratorTest, SingleFrameFile) {
113 std::unique_ptr<FrameGeneratorInterface> generator(
114 CreateFromYuvFileFrameGenerator(
115 std::vector<std::string>(1, one_frame_filename_), kFrameWidth,
116 kFrameHeight, 1));
117 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
118 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
119 }
120
TEST_F(FrameGeneratorTest,TwoFrameFile)121 TEST_F(FrameGeneratorTest, TwoFrameFile) {
122 std::unique_ptr<FrameGeneratorInterface> generator(
123 CreateFromYuvFileFrameGenerator(
124 std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
125 kFrameHeight, 1));
126 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
127 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
128 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
129 }
130
TEST_F(FrameGeneratorTest,MultipleFrameFiles)131 TEST_F(FrameGeneratorTest, MultipleFrameFiles) {
132 std::vector<std::string> files;
133 files.push_back(two_frame_filename_);
134 files.push_back(one_frame_filename_);
135
136 std::unique_ptr<FrameGeneratorInterface> generator(
137 CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight, 1));
138 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
139 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
140 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
141 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
142 }
143
TEST_F(FrameGeneratorTest,TwoFrameFileWithRepeat)144 TEST_F(FrameGeneratorTest, TwoFrameFileWithRepeat) {
145 const int kRepeatCount = 3;
146 std::unique_ptr<FrameGeneratorInterface> generator(
147 CreateFromYuvFileFrameGenerator(
148 std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
149 kFrameHeight, kRepeatCount));
150 for (int i = 0; i < kRepeatCount; ++i)
151 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
152 for (int i = 0; i < kRepeatCount; ++i)
153 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
154 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
155 }
156
TEST_F(FrameGeneratorTest,MultipleFrameFilesWithRepeat)157 TEST_F(FrameGeneratorTest, MultipleFrameFilesWithRepeat) {
158 const int kRepeatCount = 3;
159 std::vector<std::string> files;
160 files.push_back(two_frame_filename_);
161 files.push_back(one_frame_filename_);
162 std::unique_ptr<FrameGeneratorInterface> generator(
163 CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight,
164 kRepeatCount));
165 for (int i = 0; i < kRepeatCount; ++i)
166 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
167 for (int i = 0; i < kRepeatCount; ++i)
168 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
169 for (int i = 0; i < kRepeatCount; ++i)
170 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
171 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
172 }
173
TEST_F(FrameGeneratorTest,SlideGenerator)174 TEST_F(FrameGeneratorTest, SlideGenerator) {
175 const int kGenCount = 9;
176 const int kRepeatCount = 3;
177 std::unique_ptr<FrameGeneratorInterface> generator(
178 CreateSlideFrameGenerator(kFrameWidth, kFrameHeight, kRepeatCount));
179 uint64_t hashes[kGenCount];
180 for (int i = 0; i < kGenCount; ++i) {
181 hashes[i] = Hash(generator->NextFrame());
182 }
183 // Check that the buffer changes only every |kRepeatCount| frames.
184 for (int i = 1; i < kGenCount; ++i) {
185 if (i % kRepeatCount == 0) {
186 EXPECT_NE(hashes[i - 1], hashes[i]);
187 } else {
188 EXPECT_EQ(hashes[i - 1], hashes[i]);
189 }
190 }
191 }
192
193 } // namespace test
194 } // namespace webrtc
195