blob: 467323a0d55a9e195b64f8671cf72584989730e2 [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
30static const int kFrameWidth = 4;
31static const int kFrameHeight = 4;
32
33class FrameGeneratorTest : public ::testing::Test {
34 public:
35 void SetUp() override {
36 two_frame_filename_ =
37 test::TempFilename(test::OutputPath(), "2_frame_yuv_file");
38 one_frame_filename_ =
39 test::TempFilename(test::OutputPath(), "1_frame_yuv_file");
40
41 FILE* file = fopen(two_frame_filename_.c_str(), "wb");
42 WriteYuvFile(file, 0, 0, 0);
43 WriteYuvFile(file, 127, 127, 127);
44 fclose(file);
45 file = fopen(one_frame_filename_.c_str(), "wb");
46 WriteYuvFile(file, 255, 255, 255);
47 fclose(file);
48 }
49 void TearDown() override {
50 remove(one_frame_filename_.c_str());
51 remove(two_frame_filename_.c_str());
52 }
53
54 protected:
55 void WriteYuvFile(FILE* file, uint8_t y, uint8_t u, uint8_t v) {
Mirko Bonadei25ab3222021-07-08 20:08:20 +020056 RTC_DCHECK(file);
kwibergbfefb032016-05-01 14:53:46 -070057 std::unique_ptr<uint8_t[]> plane_buffer(new uint8_t[y_size]);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000058 memset(plane_buffer.get(), y, y_size);
59 fwrite(plane_buffer.get(), 1, y_size, file);
60 memset(plane_buffer.get(), u, uv_size);
61 fwrite(plane_buffer.get(), 1, uv_size, file);
62 memset(plane_buffer.get(), v, uv_size);
63 fwrite(plane_buffer.get(), 1, uv_size, file);
64 }
65
Artem Titov33f9d2b2019-12-05 15:59:00 +010066 void CheckFrameAndMutate(const FrameGeneratorInterface::VideoFrameData& frame,
Artem Titov5256d8b2019-12-02 10:34:12 +010067 uint8_t y,
68 uint8_t u,
69 uint8_t v) {
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000070 // Check that frame is valid, has the correct color and timestamp are clean.
Magnus Jedvert90e31902017-06-07 11:32:50 +020071 rtc::scoped_refptr<I420BufferInterface> i420_buffer =
Artem Titov5256d8b2019-12-02 10:34:12 +010072 frame.buffer->ToI420();
nissec9c142f2016-05-17 04:05:47 -070073 const uint8_t* buffer;
Magnus Jedvert90e31902017-06-07 11:32:50 +020074 buffer = i420_buffer->DataY();
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000075 for (int i = 0; i < y_size; ++i)
76 ASSERT_EQ(y, buffer[i]);
Magnus Jedvert90e31902017-06-07 11:32:50 +020077 buffer = i420_buffer->DataU();
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000078 for (int i = 0; i < uv_size; ++i)
79 ASSERT_EQ(u, buffer[i]);
Magnus Jedvert90e31902017-06-07 11:32:50 +020080 buffer = i420_buffer->DataV();
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000081 for (int i = 0; i < uv_size; ++i)
82 ASSERT_EQ(v, buffer[i]);
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +000083 }
84
Artem Titov33f9d2b2019-12-05 15:59:00 +010085 uint64_t Hash(const FrameGeneratorInterface::VideoFrameData& frame) {
erikvarga579de6f2017-08-29 09:12:57 -070086 // Generate a 64-bit hash from the frame's buffer.
87 uint64_t hash = 19;
88 rtc::scoped_refptr<I420BufferInterface> i420_buffer =
Artem Titov5256d8b2019-12-02 10:34:12 +010089 frame.buffer->ToI420();
erikvarga579de6f2017-08-29 09:12:57 -070090 const uint8_t* buffer = i420_buffer->DataY();
91 for (int i = 0; i < y_size; ++i) {
92 hash = (37 * hash) + buffer[i];
93 }
94 buffer = i420_buffer->DataU();
95 for (int i = 0; i < uv_size; ++i) {
96 hash = (37 * hash) + buffer[i];
97 }
98 buffer = i420_buffer->DataV();
99 for (int i = 0; i < uv_size; ++i) {
100 hash = (37 * hash) + buffer[i];
101 }
102 return hash;
103 }
104
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000105 std::string two_frame_filename_;
106 std::string one_frame_filename_;
107 const int y_size = kFrameWidth * kFrameHeight;
108 const int uv_size = ((kFrameHeight + 1) / 2) * ((kFrameWidth + 1) / 2);
109};
110
111TEST_F(FrameGeneratorTest, SingleFrameFile) {
Artem Titov33f9d2b2019-12-05 15:59:00 +0100112 std::unique_ptr<FrameGeneratorInterface> generator(
113 CreateFromYuvFileFrameGenerator(
114 std::vector<std::string>(1, one_frame_filename_), kFrameWidth,
115 kFrameHeight, 1));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000116 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
117 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
118}
119
120TEST_F(FrameGeneratorTest, TwoFrameFile) {
Artem Titov33f9d2b2019-12-05 15:59:00 +0100121 std::unique_ptr<FrameGeneratorInterface> generator(
122 CreateFromYuvFileFrameGenerator(
123 std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
124 kFrameHeight, 1));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000125 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
126 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
127 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
128}
129
130TEST_F(FrameGeneratorTest, MultipleFrameFiles) {
131 std::vector<std::string> files;
132 files.push_back(two_frame_filename_);
133 files.push_back(one_frame_filename_);
134
Artem Titov33f9d2b2019-12-05 15:59:00 +0100135 std::unique_ptr<FrameGeneratorInterface> generator(
136 CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight, 1));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000137 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
138 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
139 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
140 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
141}
142
143TEST_F(FrameGeneratorTest, TwoFrameFileWithRepeat) {
144 const int kRepeatCount = 3;
Artem Titov33f9d2b2019-12-05 15:59:00 +0100145 std::unique_ptr<FrameGeneratorInterface> generator(
146 CreateFromYuvFileFrameGenerator(
147 std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
148 kFrameHeight, kRepeatCount));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000149 for (int i = 0; i < kRepeatCount; ++i)
150 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
151 for (int i = 0; i < kRepeatCount; ++i)
152 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
153 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
154}
155
156TEST_F(FrameGeneratorTest, MultipleFrameFilesWithRepeat) {
157 const int kRepeatCount = 3;
158 std::vector<std::string> files;
159 files.push_back(two_frame_filename_);
160 files.push_back(one_frame_filename_);
Artem Titov33f9d2b2019-12-05 15:59:00 +0100161 std::unique_ptr<FrameGeneratorInterface> generator(
162 CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight,
163 kRepeatCount));
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000164 for (int i = 0; i < kRepeatCount; ++i)
165 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
166 for (int i = 0; i < kRepeatCount; ++i)
167 CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
168 for (int i = 0; i < kRepeatCount; ++i)
169 CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
170 CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
171}
172
erikvarga579de6f2017-08-29 09:12:57 -0700173TEST_F(FrameGeneratorTest, SlideGenerator) {
174 const int kGenCount = 9;
175 const int kRepeatCount = 3;
Artem Titov33f9d2b2019-12-05 15:59:00 +0100176 std::unique_ptr<FrameGeneratorInterface> generator(
177 CreateSlideFrameGenerator(kFrameWidth, kFrameHeight, kRepeatCount));
erikvarga579de6f2017-08-29 09:12:57 -0700178 uint64_t hashes[kGenCount];
179 for (int i = 0; i < kGenCount; ++i) {
180 hashes[i] = Hash(generator->NextFrame());
181 }
Artem Titov1ee563d2021-07-27 12:46:29 +0200182 // Check that the buffer changes only every `kRepeatCount` frames.
erikvarga579de6f2017-08-29 09:12:57 -0700183 for (int i = 1; i < kGenCount; ++i) {
184 if (i % kRepeatCount == 0) {
Yves Gerey665174f2018-06-19 15:03:05 +0200185 EXPECT_NE(hashes[i - 1], hashes[i]);
erikvarga579de6f2017-08-29 09:12:57 -0700186 } else {
Yves Gerey665174f2018-06-19 15:03:05 +0200187 EXPECT_EQ(hashes[i - 1], hashes[i]);
erikvarga579de6f2017-08-29 09:12:57 -0700188 }
189 }
190}
191
sprang@webrtc.org25dd1db2015-03-02 11:55:45 +0000192} // namespace test
193} // namespace webrtc