xref: /aosp_15_r20/external/webrtc/test/frame_generator_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 <stdio.h>
14 #include <string.h>
15 
16 #include <cstdint>
17 #include <memory>
18 #include <string>
19 
20 #include "api/scoped_refptr.h"
21 #include "api/test/create_frame_generator.h"
22 #include "api/test/frame_generator_interface.h"
23 #include "api/video/video_frame_buffer.h"
24 #include "test/gtest.h"
25 #include "test/testsupport/file_utils.h"
26 
27 namespace webrtc {
28 namespace test {
29 
30 constexpr int kFrameWidth = 4;
31 constexpr int kFrameHeight = 4;
32 constexpr int y_size = kFrameWidth * kFrameHeight;
33 constexpr int uv_size = ((kFrameHeight + 1) / 2) * ((kFrameWidth + 1) / 2);
34 
35 class FrameGeneratorTest : public ::testing::Test {
36  public:
SetUp()37   void SetUp() override {
38     two_frame_yuv_filename_ =
39         test::TempFilename(test::OutputPath(), "2_frame_yuv_file");
40     one_frame_yuv_filename_ =
41         test::TempFilename(test::OutputPath(), "1_frame_yuv_file");
42     two_frame_nv12_filename_ =
43         test::TempFilename(test::OutputPath(), "2_frame_nv12_file");
44     one_frame_nv12_filename_ =
45         test::TempFilename(test::OutputPath(), "1_frame_nv12_file");
46 
47     FILE* file = fopen(two_frame_yuv_filename_.c_str(), "wb");
48     WriteYuvFile(file, 0, 0, 0);
49     WriteYuvFile(file, 127, 128, 129);
50     fclose(file);
51     file = fopen(one_frame_yuv_filename_.c_str(), "wb");
52     WriteYuvFile(file, 255, 255, 255);
53     fclose(file);
54     file = fopen(two_frame_nv12_filename_.c_str(), "wb");
55     WriteNV12File(file, 0, 0, 0);
56     WriteNV12File(file, 127, 128, 129);
57     fclose(file);
58     file = fopen(one_frame_nv12_filename_.c_str(), "wb");
59     WriteNV12File(file, 255, 255, 255);
60     fclose(file);
61   }
62 
TearDown()63   void TearDown() override {
64     remove(one_frame_yuv_filename_.c_str());
65     remove(two_frame_yuv_filename_.c_str());
66     remove(one_frame_nv12_filename_.c_str());
67     remove(two_frame_nv12_filename_.c_str());
68   }
69 
70  protected:
WriteYuvFile(FILE * file,uint8_t y,uint8_t u,uint8_t v)71   void WriteYuvFile(FILE* file, uint8_t y, uint8_t u, uint8_t v) {
72     RTC_DCHECK(file);
73     std::unique_ptr<uint8_t[]> plane_buffer(new uint8_t[y_size]);
74     memset(plane_buffer.get(), y, y_size);
75     fwrite(plane_buffer.get(), 1, y_size, file);
76     memset(plane_buffer.get(), u, uv_size);
77     fwrite(plane_buffer.get(), 1, uv_size, file);
78     memset(plane_buffer.get(), v, uv_size);
79     fwrite(plane_buffer.get(), 1, uv_size, file);
80   }
81 
WriteNV12File(FILE * file,uint8_t y,uint8_t u,uint8_t v)82   void WriteNV12File(FILE* file, uint8_t y, uint8_t u, uint8_t v) {
83     RTC_DCHECK(file);
84     uint8_t plane_buffer[y_size];
85 
86     memset(&plane_buffer, y, y_size);
87     fwrite(&plane_buffer, 1, y_size, file);
88     for (size_t i = 0; i < uv_size; ++i) {
89       plane_buffer[2 * i] = u;
90       plane_buffer[2 * i + 1] = v;
91     }
92     fwrite(&plane_buffer, 1, 2 * uv_size, file);
93   }
94 
CheckFrameAndMutate(const FrameGeneratorInterface::VideoFrameData & frame,uint8_t y,uint8_t u,uint8_t v)95   void CheckFrameAndMutate(const FrameGeneratorInterface::VideoFrameData& frame,
96                            uint8_t y,
97                            uint8_t u,
98                            uint8_t v) {
99     // Check that frame is valid, has the correct color and timestamp are clean.
100     rtc::scoped_refptr<I420BufferInterface> i420_buffer =
101         frame.buffer->ToI420();
102     const uint8_t* buffer;
103     buffer = i420_buffer->DataY();
104     for (int i = 0; i < y_size; ++i)
105       ASSERT_EQ(y, buffer[i]);
106     buffer = i420_buffer->DataU();
107     for (int i = 0; i < uv_size; ++i)
108       ASSERT_EQ(u, buffer[i]);
109     buffer = i420_buffer->DataV();
110     for (int i = 0; i < uv_size; ++i)
111       ASSERT_EQ(v, buffer[i]);
112   }
113 
Hash(const FrameGeneratorInterface::VideoFrameData & frame)114   uint64_t Hash(const FrameGeneratorInterface::VideoFrameData& frame) {
115     // Generate a 64-bit hash from the frame's buffer.
116     uint64_t hash = 19;
117     rtc::scoped_refptr<I420BufferInterface> i420_buffer =
118         frame.buffer->ToI420();
119     const uint8_t* buffer = i420_buffer->DataY();
120     for (int i = 0; i < y_size; ++i) {
121       hash = (37 * hash) + buffer[i];
122     }
123     buffer = i420_buffer->DataU();
124     for (int i = 0; i < uv_size; ++i) {
125       hash = (37 * hash) + buffer[i];
126     }
127     buffer = i420_buffer->DataV();
128     for (int i = 0; i < uv_size; ++i) {
129       hash = (37 * hash) + buffer[i];
130     }
131     return hash;
132   }
133 
134   std::string two_frame_yuv_filename_;
135   std::string one_frame_yuv_filename_;
136   std::string two_frame_nv12_filename_;
137   std::string one_frame_nv12_filename_;
138 };
139 
TEST_F(FrameGeneratorTest,SingleFrameYuvFile)140 TEST_F(FrameGeneratorTest, SingleFrameYuvFile) {
141   std::unique_ptr<FrameGeneratorInterface> generator(
142       CreateFromYuvFileFrameGenerator(
143           std::vector<std::string>(1, one_frame_yuv_filename_), kFrameWidth,
144           kFrameHeight, 1));
145   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
146   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
147 }
148 
TEST_F(FrameGeneratorTest,TwoFrameYuvFile)149 TEST_F(FrameGeneratorTest, TwoFrameYuvFile) {
150   std::unique_ptr<FrameGeneratorInterface> generator(
151       CreateFromYuvFileFrameGenerator(
152           std::vector<std::string>(1, two_frame_yuv_filename_), kFrameWidth,
153           kFrameHeight, 1));
154   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
155   CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
156   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
157 }
158 
TEST_F(FrameGeneratorTest,MultipleFrameYuvFiles)159 TEST_F(FrameGeneratorTest, MultipleFrameYuvFiles) {
160   std::vector<std::string> files;
161   files.push_back(two_frame_yuv_filename_);
162   files.push_back(one_frame_yuv_filename_);
163 
164   std::unique_ptr<FrameGeneratorInterface> generator(
165       CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight, 1));
166   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
167   CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
168   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
169   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
170 }
171 
TEST_F(FrameGeneratorTest,TwoFrameYuvFileWithRepeat)172 TEST_F(FrameGeneratorTest, TwoFrameYuvFileWithRepeat) {
173   const int kRepeatCount = 3;
174   std::unique_ptr<FrameGeneratorInterface> generator(
175       CreateFromYuvFileFrameGenerator(
176           std::vector<std::string>(1, two_frame_yuv_filename_), kFrameWidth,
177           kFrameHeight, kRepeatCount));
178   for (int i = 0; i < kRepeatCount; ++i)
179     CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
180   for (int i = 0; i < kRepeatCount; ++i)
181     CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
182   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
183 }
184 
TEST_F(FrameGeneratorTest,MultipleFrameYuvFilesWithRepeat)185 TEST_F(FrameGeneratorTest, MultipleFrameYuvFilesWithRepeat) {
186   const int kRepeatCount = 3;
187   std::vector<std::string> files;
188   files.push_back(two_frame_yuv_filename_);
189   files.push_back(one_frame_yuv_filename_);
190   std::unique_ptr<FrameGeneratorInterface> generator(
191       CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight,
192                                       kRepeatCount));
193   for (int i = 0; i < kRepeatCount; ++i)
194     CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
195   for (int i = 0; i < kRepeatCount; ++i)
196     CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
197   for (int i = 0; i < kRepeatCount; ++i)
198     CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
199   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
200 }
201 
TEST_F(FrameGeneratorTest,SingleFrameNV12File)202 TEST_F(FrameGeneratorTest, SingleFrameNV12File) {
203   std::unique_ptr<FrameGeneratorInterface> generator(
204       CreateFromNV12FileFrameGenerator(
205           std::vector<std::string>(1, one_frame_nv12_filename_), kFrameWidth,
206           kFrameHeight, 1));
207   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
208   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
209 }
210 
TEST_F(FrameGeneratorTest,TwoFrameNV12File)211 TEST_F(FrameGeneratorTest, TwoFrameNV12File) {
212   std::unique_ptr<FrameGeneratorInterface> generator(
213       CreateFromNV12FileFrameGenerator(
214           std::vector<std::string>(1, two_frame_nv12_filename_), kFrameWidth,
215           kFrameHeight, 1));
216   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
217   CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
218   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
219 }
220 
TEST_F(FrameGeneratorTest,MultipleFrameNV12Files)221 TEST_F(FrameGeneratorTest, MultipleFrameNV12Files) {
222   std::vector<std::string> files;
223   files.push_back(two_frame_nv12_filename_);
224   files.push_back(one_frame_nv12_filename_);
225 
226   std::unique_ptr<FrameGeneratorInterface> generator(
227       CreateFromNV12FileFrameGenerator(files, kFrameWidth, kFrameHeight, 1));
228   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
229   CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
230   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
231   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
232 }
233 
TEST_F(FrameGeneratorTest,TwoFrameNV12FileWithRepeat)234 TEST_F(FrameGeneratorTest, TwoFrameNV12FileWithRepeat) {
235   const int kRepeatCount = 3;
236   std::unique_ptr<FrameGeneratorInterface> generator(
237       CreateFromNV12FileFrameGenerator(
238           std::vector<std::string>(1, two_frame_nv12_filename_), kFrameWidth,
239           kFrameHeight, kRepeatCount));
240   for (int i = 0; i < kRepeatCount; ++i)
241     CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
242   for (int i = 0; i < kRepeatCount; ++i)
243     CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
244   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
245 }
246 
TEST_F(FrameGeneratorTest,MultipleFrameNV12FilesWithRepeat)247 TEST_F(FrameGeneratorTest, MultipleFrameNV12FilesWithRepeat) {
248   const int kRepeatCount = 3;
249   std::vector<std::string> files;
250   files.push_back(two_frame_nv12_filename_);
251   files.push_back(one_frame_nv12_filename_);
252   std::unique_ptr<FrameGeneratorInterface> generator(
253       CreateFromNV12FileFrameGenerator(files, kFrameWidth, kFrameHeight,
254                                        kRepeatCount));
255   for (int i = 0; i < kRepeatCount; ++i)
256     CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
257   for (int i = 0; i < kRepeatCount; ++i)
258     CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
259   for (int i = 0; i < kRepeatCount; ++i)
260     CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
261   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
262 }
263 
TEST_F(FrameGeneratorTest,SlideGenerator)264 TEST_F(FrameGeneratorTest, SlideGenerator) {
265   const int kGenCount = 9;
266   const int kRepeatCount = 3;
267   std::unique_ptr<FrameGeneratorInterface> generator(
268       CreateSlideFrameGenerator(kFrameWidth, kFrameHeight, kRepeatCount));
269   uint64_t hashes[kGenCount];
270   for (int i = 0; i < kGenCount; ++i) {
271     hashes[i] = Hash(generator->NextFrame());
272   }
273   // Check that the buffer changes only every `kRepeatCount` frames.
274   for (int i = 1; i < kGenCount; ++i) {
275     if (i % kRepeatCount == 0) {
276       EXPECT_NE(hashes[i - 1], hashes[i]);
277     } else {
278       EXPECT_EQ(hashes[i - 1], hashes[i]);
279     }
280   }
281 }
282 
283 }  // namespace test
284 }  // namespace webrtc
285