blob: ece37a547f62b9e26e51d028b34e3fd5e50591d0 [file] [log] [blame]
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +00001/*
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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "test/frame_generator.h"
12
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000013#include <stdio.h>
Yves Gerey3e707812018-11-28 16:47:49 +010014#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020015
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <cstdint>
kwibergbfefb032016-05-01 14:53:46 -070017#include <memory>
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000018#include <string>
19
Mirko Bonadeid9708072019-01-25 20:26:48 +010020#include "api/scoped_refptr.h"
Artem Titov33f9d2b2019-12-05 15:59:00 +010021#include "api/test/create_frame_generator.h"
22#include "api/test/frame_generator_interface.h"
Yves Gerey3e707812018-11-28 16:47:49 +010023#include "api/video/video_frame_buffer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "test/testsupport/file_utils.h"
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000026
27namespace webrtc {
28namespace test {
29
Artem Titov9b731592022-10-07 15:01:32 +020030constexpr int kFrameWidth = 4;
31constexpr int kFrameHeight = 4;
32constexpr int y_size = kFrameWidth * kFrameHeight;
33constexpr int uv_size = ((kFrameHeight + 1) / 2) * ((kFrameWidth + 1) / 2);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000034
35class FrameGeneratorTest : public ::testing::Test {
36 public:
37 void SetUp() override {
Artem Titov9b731592022-10-07 15:01:32 +020038 two_frame_yuv_filename_ =
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000039 test::TempFilename(test::OutputPath(), "2_frame_yuv_file");
Artem Titov9b731592022-10-07 15:01:32 +020040 one_frame_yuv_filename_ =
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000041 test::TempFilename(test::OutputPath(), "1_frame_yuv_file");
Artem Titov9b731592022-10-07 15:01:32 +020042 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");
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000046
Artem Titov9b731592022-10-07 15:01:32 +020047 FILE* file = fopen(two_frame_yuv_filename_.c_str(), "wb");
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000048 WriteYuvFile(file, 0, 0, 0);
Artem Titov9b731592022-10-07 15:01:32 +020049 WriteYuvFile(file, 127, 128, 129);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000050 fclose(file);
Artem Titov9b731592022-10-07 15:01:32 +020051 file = fopen(one_frame_yuv_filename_.c_str(), "wb");
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000052 WriteYuvFile(file, 255, 255, 255);
53 fclose(file);
Artem Titov9b731592022-10-07 15:01:32 +020054 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);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000061 }
Artem Titov9b731592022-10-07 15:01:32 +020062
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000063 void TearDown() override {
Artem Titov9b731592022-10-07 15:01:32 +020064 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());
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000068 }
69
70 protected:
71 void WriteYuvFile(FILE* file, uint8_t y, uint8_t u, uint8_t v) {
Mirko Bonadei25ab3222021-07-08 20:08:20 +020072 RTC_DCHECK(file);
kwibergbfefb032016-05-01 14:53:46 -070073 std::unique_ptr<uint8_t[]> plane_buffer(new uint8_t[y_size]);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000074 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
Artem Titov9b731592022-10-07 15:01:32 +020082 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
Artem Titov33f9d2b2019-12-05 15:59:00 +010095 void CheckFrameAndMutate(const FrameGeneratorInterface::VideoFrameData& frame,
Artem Titov5256d8b2019-12-02 10:34:12 +010096 uint8_t y,
97 uint8_t u,
98 uint8_t v) {
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000099 // Check that frame is valid, has the correct color and timestamp are clean.
Magnus Jedvert90e31902017-06-07 11:32:50 +0200100 rtc::scoped_refptr<I420BufferInterface> i420_buffer =
Artem Titov5256d8b2019-12-02 10:34:12 +0100101 frame.buffer->ToI420();
nissec9c142f2016-05-17 04:05:47 -0700102 const uint8_t* buffer;
Magnus Jedvert90e31902017-06-07 11:32:50 +0200103 buffer = i420_buffer->DataY();
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000104 for (int i = 0; i < y_size; ++i)
105 ASSERT_EQ(y, buffer[i]);
Magnus Jedvert90e31902017-06-07 11:32:50 +0200106 buffer = i420_buffer->DataU();
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000107 for (int i = 0; i < uv_size; ++i)
108 ASSERT_EQ(u, buffer[i]);
Magnus Jedvert90e31902017-06-07 11:32:50 +0200109 buffer = i420_buffer->DataV();
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000110 for (int i = 0; i < uv_size; ++i)
111 ASSERT_EQ(v, buffer[i]);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000112 }
113
Artem Titov33f9d2b2019-12-05 15:59:00 +0100114 uint64_t Hash(const FrameGeneratorInterface::VideoFrameData& frame) {
erikvarga579de6f2017-08-29 09:12:57 -0700115 // Generate a 64-bit hash from the frame's buffer.
116 uint64_t hash = 19;
117 rtc::scoped_refptr<I420BufferInterface> i420_buffer =
Artem Titov5256d8b2019-12-02 10:34:12 +0100118 frame.buffer->ToI420();
erikvarga579de6f2017-08-29 09:12:57 -0700119 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
Artem Titov9b731592022-10-07 15:01:32 +0200134 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_;
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000138};
139
Artem Titov9b731592022-10-07 15:01:32 +0200140TEST_F(FrameGeneratorTest, SingleFrameYuvFile) {
Artem Titov33f9d2b2019-12-05 15:59:00 +0100141 std::unique_ptr<FrameGeneratorInterface> generator(
142 CreateFromYuvFileFrameGenerator(
Artem Titov9b731592022-10-07 15:01:32 +0200143 std::vector<std::string>(1, one_frame_yuv_filename_), kFrameWidth,
Artem Titov33f9d2b2019-12-05 15:59:00 +0100144 kFrameHeight, 1));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000145 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
146 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
147}
148
Artem Titov9b731592022-10-07 15:01:32 +0200149TEST_F(FrameGeneratorTest, TwoFrameYuvFile) {
Artem Titov33f9d2b2019-12-05 15:59:00 +0100150 std::unique_ptr<FrameGeneratorInterface> generator(
151 CreateFromYuvFileFrameGenerator(
Artem Titov9b731592022-10-07 15:01:32 +0200152 std::vector<std::string>(1, two_frame_yuv_filename_), kFrameWidth,
Artem Titov33f9d2b2019-12-05 15:59:00 +0100153 kFrameHeight, 1));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000154 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
Artem Titov9b731592022-10-07 15:01:32 +0200155 CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000156 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
157}
158
Artem Titov9b731592022-10-07 15:01:32 +0200159TEST_F(FrameGeneratorTest, MultipleFrameYuvFiles) {
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000160 std::vector<std::string> files;
Artem Titov9b731592022-10-07 15:01:32 +0200161 files.push_back(two_frame_yuv_filename_);
162 files.push_back(one_frame_yuv_filename_);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000163
Artem Titov33f9d2b2019-12-05 15:59:00 +0100164 std::unique_ptr<FrameGeneratorInterface> generator(
165 CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight, 1));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000166 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
Artem Titov9b731592022-10-07 15:01:32 +0200167 CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000168 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
169 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
170}
171
Artem Titov9b731592022-10-07 15:01:32 +0200172TEST_F(FrameGeneratorTest, TwoFrameYuvFileWithRepeat) {
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000173 const int kRepeatCount = 3;
Artem Titov33f9d2b2019-12-05 15:59:00 +0100174 std::unique_ptr<FrameGeneratorInterface> generator(
175 CreateFromYuvFileFrameGenerator(
Artem Titov9b731592022-10-07 15:01:32 +0200176 std::vector<std::string>(1, two_frame_yuv_filename_), kFrameWidth,
Artem Titov33f9d2b2019-12-05 15:59:00 +0100177 kFrameHeight, kRepeatCount));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000178 for (int i = 0; i < kRepeatCount; ++i)
179 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
180 for (int i = 0; i < kRepeatCount; ++i)
Artem Titov9b731592022-10-07 15:01:32 +0200181 CheckFrameAndMutate(generator->NextFrame(), 127, 128, 129);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000182 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
183}
184
Artem Titov9b731592022-10-07 15:01:32 +0200185TEST_F(FrameGeneratorTest, MultipleFrameYuvFilesWithRepeat) {
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000186 const int kRepeatCount = 3;
187 std::vector<std::string> files;
Artem Titov9b731592022-10-07 15:01:32 +0200188 files.push_back(two_frame_yuv_filename_);
189 files.push_back(one_frame_yuv_filename_);
Artem Titov33f9d2b2019-12-05 15:59:00 +0100190 std::unique_ptr<FrameGeneratorInterface> generator(
191 CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight,
192 kRepeatCount));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000193 for (int i = 0; i < kRepeatCount; ++i)
194 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
195 for (int i = 0; i < kRepeatCount; ++i)
Artem Titov9b731592022-10-07 15:01:32 +0200196 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
202TEST_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
211TEST_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
221TEST_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
234TEST_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
247TEST_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);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000259 for (int i = 0; i < kRepeatCount; ++i)
260 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
261 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
262}
263
erikvarga579de6f2017-08-29 09:12:57 -0700264TEST_F(FrameGeneratorTest, SlideGenerator) {
265 const int kGenCount = 9;
266 const int kRepeatCount = 3;
Artem Titov33f9d2b2019-12-05 15:59:00 +0100267 std::unique_ptr<FrameGeneratorInterface> generator(
268 CreateSlideFrameGenerator(kFrameWidth, kFrameHeight, kRepeatCount));
erikvarga579de6f2017-08-29 09:12:57 -0700269 uint64_t hashes[kGenCount];
270 for (int i = 0; i < kGenCount; ++i) {
271 hashes[i] = Hash(generator->NextFrame());
272 }
Artem Titov1ee563d2021-07-27 12:46:29 +0200273 // Check that the buffer changes only every `kRepeatCount` frames.
erikvarga579de6f2017-08-29 09:12:57 -0700274 for (int i = 1; i < kGenCount; ++i) {
275 if (i % kRepeatCount == 0) {
Yves Gerey665174f2018-06-19 15:03:05 +0200276 EXPECT_NE(hashes[i - 1], hashes[i]);
erikvarga579de6f2017-08-29 09:12:57 -0700277 } else {
Yves Gerey665174f2018-06-19 15:03:05 +0200278 EXPECT_EQ(hashes[i - 1], hashes[i]);
erikvarga579de6f2017-08-29 09:12:57 -0700279 }
280 }
281}
282
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000283} // namespace test
284} // namespace webrtc