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