1 /*
2 * Copyright (c) 2019 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 <memory>
12 #include <vector>
13
14 #include "absl/types/optional.h"
15 #include "api/test/create_frame_generator.h"
16 #include "api/video/encoded_image.h"
17 #include "api/video/video_codec_type.h"
18 #include "api/video_codecs/video_codec.h"
19 #include "api/video_codecs/video_encoder.h"
20 #include "common_video/libyuv/include/webrtc_libyuv.h"
21 #include "media/base/codec.h"
22 #include "media/base/media_constants.h"
23 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
24 #include "modules/video_coding/codecs/vp8/include/vp8.h"
25 #include "modules/video_coding/codecs/vp9/include/vp9.h"
26 #include "modules/video_coding/include/video_error_codes.h"
27 #include "modules/video_coding/utility/ivf_file_writer.h"
28 #include "rtc_base/event.h"
29 #include "test/gtest.h"
30 #include "test/testsupport/file_utils.h"
31 #include "test/testsupport/ivf_video_frame_generator.h"
32 #include "test/video_codec_settings.h"
33
34 #if defined(WEBRTC_USE_H264)
35 #include "modules/video_coding/codecs/h264/include/h264.h"
36 #include "rtc_base/synchronization/mutex.h"
37
38 #endif
39
40 namespace webrtc {
41 namespace test {
42 namespace {
43
44 constexpr int kWidth = 320;
45 constexpr int kHeight = 240;
46 constexpr int kVideoFramesCount = 30;
47 constexpr int kMaxFramerate = 30;
48 constexpr int kMaxFrameEncodeWaitTimeoutMs = 2000;
49 static const VideoEncoder::Capabilities kCapabilities(false);
50
51 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
52 constexpr double kExpectedMinPsnr = 35;
53 #else
54 constexpr double kExpectedMinPsnr = 39;
55 #endif
56
57 class IvfFileWriterEncodedCallback : public EncodedImageCallback {
58 public:
IvfFileWriterEncodedCallback(const std::string & file_name,VideoCodecType video_codec_type,int expected_frames_count)59 IvfFileWriterEncodedCallback(const std::string& file_name,
60 VideoCodecType video_codec_type,
61 int expected_frames_count)
62 : file_writer_(
63 IvfFileWriter::Wrap(FileWrapper::OpenWriteOnly(file_name), 0)),
64 video_codec_type_(video_codec_type),
65 expected_frames_count_(expected_frames_count) {
66 EXPECT_TRUE(file_writer_.get());
67 }
~IvfFileWriterEncodedCallback()68 ~IvfFileWriterEncodedCallback() { EXPECT_TRUE(file_writer_->Close()); }
69
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info,const RTPFragmentationHeader * fragmentation)70 Result OnEncodedImage(const EncodedImage& encoded_image,
71 const CodecSpecificInfo* codec_specific_info,
72 const RTPFragmentationHeader* fragmentation) override {
73 EXPECT_TRUE(file_writer_->WriteFrame(encoded_image, video_codec_type_));
74
75 MutexLock lock(&lock_);
76 received_frames_count_++;
77 RTC_CHECK_LE(received_frames_count_, expected_frames_count_);
78 if (received_frames_count_ == expected_frames_count_) {
79 expected_frames_count_received_.Set();
80 }
81 return Result(Result::Error::OK);
82 }
83
WaitForExpectedFramesReceived(int timeout_ms)84 bool WaitForExpectedFramesReceived(int timeout_ms) {
85 return expected_frames_count_received_.Wait(timeout_ms);
86 }
87
88 private:
89 std::unique_ptr<IvfFileWriter> file_writer_;
90 const VideoCodecType video_codec_type_;
91 const int expected_frames_count_;
92
93 Mutex lock_;
94 int received_frames_count_ RTC_GUARDED_BY(lock_) = 0;
95 rtc::Event expected_frames_count_received_;
96 };
97
98 class IvfVideoFrameGeneratorTest : public ::testing::Test {
99 protected:
SetUp()100 void SetUp() override {
101 file_name_ =
102 webrtc::test::TempFilename(webrtc::test::OutputPath(), "test_file.ivf");
103 }
TearDown()104 void TearDown() override { webrtc::test::RemoveFile(file_name_); }
105
BuildFrame(FrameGeneratorInterface::VideoFrameData frame_data)106 VideoFrame BuildFrame(FrameGeneratorInterface::VideoFrameData frame_data) {
107 return VideoFrame::Builder()
108 .set_video_frame_buffer(frame_data.buffer)
109 .set_update_rect(frame_data.update_rect)
110 .build();
111 }
112
CreateTestVideoFile(VideoCodecType video_codec_type,std::unique_ptr<VideoEncoder> video_encoder)113 void CreateTestVideoFile(VideoCodecType video_codec_type,
114 std::unique_ptr<VideoEncoder> video_encoder) {
115 std::unique_ptr<test::FrameGeneratorInterface> frame_generator =
116 test::CreateSquareFrameGenerator(
117 kWidth, kHeight, test::FrameGeneratorInterface::OutputType::kI420,
118 absl::nullopt);
119
120 VideoCodec codec_settings;
121 webrtc::test::CodecSettings(video_codec_type, &codec_settings);
122 codec_settings.width = kWidth;
123 codec_settings.height = kHeight;
124 codec_settings.maxFramerate = kMaxFramerate;
125 const uint32_t kBitrateBps = 500000;
126 VideoBitrateAllocation bitrate_allocation;
127 bitrate_allocation.SetBitrate(0, 0, kBitrateBps);
128
129 IvfFileWriterEncodedCallback ivf_writer_callback(
130 file_name_, video_codec_type, kVideoFramesCount);
131
132 video_encoder->RegisterEncodeCompleteCallback(&ivf_writer_callback);
133 video_encoder->SetRates(VideoEncoder::RateControlParameters(
134 bitrate_allocation, static_cast<double>(codec_settings.maxFramerate)));
135 ASSERT_EQ(WEBRTC_VIDEO_CODEC_OK,
136 video_encoder->InitEncode(
137 &codec_settings,
138 VideoEncoder::Settings(kCapabilities, /*number_of_cores=*/1,
139 /*max_payload_size=*/0)));
140
141 uint32_t last_frame_timestamp = 0;
142
143 for (int i = 0; i < kVideoFramesCount; ++i) {
144 VideoFrame frame = BuildFrame(frame_generator->NextFrame());
145 const uint32_t timestamp =
146 last_frame_timestamp +
147 kVideoPayloadTypeFrequency / codec_settings.maxFramerate;
148 frame.set_timestamp(timestamp);
149
150 last_frame_timestamp = timestamp;
151
152 ASSERT_EQ(WEBRTC_VIDEO_CODEC_OK, video_encoder->Encode(frame, nullptr));
153 video_frames_.push_back(frame);
154 }
155
156 ASSERT_TRUE(ivf_writer_callback.WaitForExpectedFramesReceived(
157 kMaxFrameEncodeWaitTimeoutMs));
158 }
159
160 std::string file_name_;
161 std::vector<VideoFrame> video_frames_;
162 };
163
164 } // namespace
165
TEST_F(IvfVideoFrameGeneratorTest,Vp8)166 TEST_F(IvfVideoFrameGeneratorTest, Vp8) {
167 CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create());
168 IvfVideoFrameGenerator generator(file_name_);
169 for (size_t i = 0; i < video_frames_.size(); ++i) {
170 auto& expected_frame = video_frames_[i];
171 VideoFrame actual_frame = BuildFrame(generator.NextFrame());
172 EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr);
173 }
174 }
175
TEST_F(IvfVideoFrameGeneratorTest,Vp8DoubleRead)176 TEST_F(IvfVideoFrameGeneratorTest, Vp8DoubleRead) {
177 CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create());
178 IvfVideoFrameGenerator generator(file_name_);
179 for (size_t i = 0; i < video_frames_.size() * 2; ++i) {
180 auto& expected_frame = video_frames_[i % video_frames_.size()];
181 VideoFrame actual_frame = BuildFrame(generator.NextFrame());
182 EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr);
183 }
184 }
185
TEST_F(IvfVideoFrameGeneratorTest,Vp9)186 TEST_F(IvfVideoFrameGeneratorTest, Vp9) {
187 CreateTestVideoFile(VideoCodecType::kVideoCodecVP9, VP9Encoder::Create());
188 IvfVideoFrameGenerator generator(file_name_);
189 for (size_t i = 0; i < video_frames_.size(); ++i) {
190 auto& expected_frame = video_frames_[i];
191 VideoFrame actual_frame = BuildFrame(generator.NextFrame());
192 EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr);
193 }
194 }
195
196 #if defined(WEBRTC_USE_H264)
TEST_F(IvfVideoFrameGeneratorTest,H264)197 TEST_F(IvfVideoFrameGeneratorTest, H264) {
198 CreateTestVideoFile(
199 VideoCodecType::kVideoCodecH264,
200 H264Encoder::Create(cricket::VideoCodec(cricket::kH264CodecName)));
201 IvfVideoFrameGenerator generator(file_name_);
202 for (size_t i = 0; i < video_frames_.size(); ++i) {
203 auto& expected_frame = video_frames_[i];
204 VideoFrame actual_frame = BuildFrame(generator.NextFrame());
205 EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr);
206 }
207 }
208 #endif
209
210 } // namespace test
211 } // namespace webrtc
212