• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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