blob: 768bab5cb12d1aa5857cd38de712d0013e5d83de [file] [log] [blame]
pbos@webrtc.org26d12102013-05-29 13:41:03 +00001/*
2 * Copyright (c) 2013 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "test/frame_generator_capturer.h"
pbos@webrtc.org26d12102013-05-29 13:41:03 +000012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <algorithm>
14#include <cmath>
15#include <limits>
ilnikbaded152017-03-17 05:55:25 -070016#include <utility>
17#include <vector>
18
Danil Chapovalovabd42732018-09-10 14:07:45 +020019#include "absl/memory/memory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010020#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/criticalsection.h"
22#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/task_queue.h"
24#include "rtc_base/timeutils.h"
25#include "system_wrappers/include/clock.h"
pbos@webrtc.org26d12102013-05-29 13:41:03 +000026
27namespace webrtc {
28namespace test {
29
ilnikbaded152017-03-17 05:55:25 -070030class FrameGeneratorCapturer::InsertFrameTask : public rtc::QueuedTask {
31 public:
Danil Chapovalovabd42732018-09-10 14:07:45 +020032 explicit InsertFrameTask(FrameGeneratorCapturer* frame_generator_capturer)
ilnikbaded152017-03-17 05:55:25 -070033 : frame_generator_capturer_(frame_generator_capturer),
Danil Chapovalovabd42732018-09-10 14:07:45 +020034 repeat_interval_ms_(-1),
35 next_run_time_ms_(-1) {}
ilnikbaded152017-03-17 05:55:25 -070036
37 private:
38 bool Run() override {
Danil Chapovalovabd42732018-09-10 14:07:45 +020039 // Check if the frame interval for this
40 // task queue is the same same as the current configured frame rate.
41 int interval_ms =
42 1000 / frame_generator_capturer_->GetCurrentConfiguredFramerate();
43 if (repeat_interval_ms_ != interval_ms) {
44 // Restart the timer if frame rate has changed since task was started.
45 next_run_time_ms_ = rtc::TimeMillis();
46 repeat_interval_ms_ = interval_ms;
ilnikbaded152017-03-17 05:55:25 -070047 }
Danil Chapovalovabd42732018-09-10 14:07:45 +020048 // Schedule the next frame capture event to happen at approximately the
49 // correct absolute time point.
50 next_run_time_ms_ += interval_ms;
51
ilnikbaded152017-03-17 05:55:25 -070052 frame_generator_capturer_->InsertFrame();
Danil Chapovalovabd42732018-09-10 14:07:45 +020053
54 int64_t now_ms = rtc::TimeMillis();
55 if (next_run_time_ms_ < now_ms) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020056 RTC_LOG(LS_ERROR) << "Frame Generator Capturer can't keep up with "
Danil Chapovalovafc3eb12018-09-12 12:53:10 +020057 "requested fps.";
58 rtc::TaskQueue::Current()->PostTask(absl::WrapUnique(this));
59 } else {
60 int64_t delay_ms = next_run_time_ms_ - now_ms;
61 RTC_DCHECK_GE(delay_ms, 0);
62 RTC_DCHECK_LE(delay_ms, interval_ms);
63 rtc::TaskQueue::Current()->PostDelayedTask(absl::WrapUnique(this),
64 delay_ms);
Danil Chapovalovabd42732018-09-10 14:07:45 +020065 }
Danil Chapovalovabd42732018-09-10 14:07:45 +020066 return false;
ilnikbaded152017-03-17 05:55:25 -070067 }
68
69 webrtc::test::FrameGeneratorCapturer* const frame_generator_capturer_;
Danil Chapovalovabd42732018-09-10 14:07:45 +020070 int repeat_interval_ms_;
71 int64_t next_run_time_ms_;
ilnikbaded152017-03-17 05:55:25 -070072};
73
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080074FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
75 int width,
76 int height,
Danil Chapovalov431abd92018-06-18 12:54:17 +020077 absl::optional<FrameGenerator::OutputType> type,
78 absl::optional<int> num_squares,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080079 int target_fps,
80 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020081 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080082 clock,
83 FrameGenerator::CreateSquareGenerator(width, height, type, num_squares),
Danil Chapovalovabd42732018-09-10 14:07:45 +020084 target_fps);
Taylor Brandstetter081136f2018-03-08 01:54:10 +000085 if (!capturer->Init())
86 return nullptr;
87
88 return capturer.release();
89}
90
andresp@webrtc.orgab654952013-09-19 12:14:03 +000091FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile(
sprang@webrtc.org131bea82015-02-18 12:46:06 +000092 const std::string& file_name,
andresp@webrtc.orgab654952013-09-19 12:14:03 +000093 size_t width,
94 size_t height,
95 int target_fps,
96 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020097 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
sprangc5d62e22017-04-02 23:53:04 -070098 clock,
99 FrameGenerator::CreateFromYuvFile(std::vector<std::string>(1, file_name),
100 width, height, 1),
Danil Chapovalovabd42732018-09-10 14:07:45 +0200101 target_fps);
sprangc5d62e22017-04-02 23:53:04 -0700102 if (!capturer->Init())
103 return nullptr;
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000104
sprangc5d62e22017-04-02 23:53:04 -0700105 return capturer.release();
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000106}
107
erikvarga579de6f2017-08-29 09:12:57 -0700108FrameGeneratorCapturer* FrameGeneratorCapturer::CreateSlideGenerator(
109 int width,
110 int height,
111 int frame_repeat_count,
112 int target_fps,
113 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +0200114 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
Yves Gerey665174f2018-06-19 15:03:05 +0200115 clock,
116 FrameGenerator::CreateSlideGenerator(width, height, frame_repeat_count),
Danil Chapovalovabd42732018-09-10 14:07:45 +0200117 target_fps);
erikvarga579de6f2017-08-29 09:12:57 -0700118 if (!capturer->Init())
119 return nullptr;
120
121 return capturer.release();
122}
123
perkja8ba1952017-02-27 06:52:10 -0800124FrameGeneratorCapturer::FrameGeneratorCapturer(
125 Clock* clock,
126 std::unique_ptr<FrameGenerator> frame_generator,
127 int target_fps)
perkja49cbd32016-09-16 07:53:41 -0700128 : clock_(clock),
Niels Möller8eeccbe2018-12-14 13:35:32 +0100129 sending_(true),
perkj803d97f2016-11-01 11:45:46 -0700130 sink_wants_observer_(nullptr),
perkja8ba1952017-02-27 06:52:10 -0800131 frame_generator_(std::move(frame_generator)),
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200132 source_fps_(target_fps),
133 target_capture_fps_(target_fps),
ilnikbaded152017-03-17 05:55:25 -0700134 first_frame_capture_time_(-1),
Yves Gerey665174f2018-06-19 15:03:05 +0200135 task_queue_("FrameGenCapQ", rtc::TaskQueue::Priority::HIGH) {
perkja8ba1952017-02-27 06:52:10 -0800136 RTC_DCHECK(frame_generator_);
perkja49cbd32016-09-16 07:53:41 -0700137 RTC_DCHECK_GT(target_fps, 0);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000138}
139
140FrameGeneratorCapturer::~FrameGeneratorCapturer() {
141 Stop();
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000142}
143
Perba7dc722016-04-19 15:01:23 +0200144void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) {
145 rtc::CritScope cs(&lock_);
146 fake_rotation_ = rotation;
147}
148
Johannes Kronf7f13e02018-12-12 11:17:43 +0100149void FrameGeneratorCapturer::SetFakeColorSpace(
150 absl::optional<ColorSpace> color_space) {
151 rtc::CritScope cs(&lock_);
152 fake_color_space_ = color_space;
153}
154
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000155bool FrameGeneratorCapturer::Init() {
pbos@webrtc.org94015242013-10-16 11:05:37 +0000156 // This check is added because frame_generator_ might be file based and should
157 // not crash because a file moved.
sprangc5d62e22017-04-02 23:53:04 -0700158 if (frame_generator_.get() == nullptr)
pbos@webrtc.org94015242013-10-16 11:05:37 +0000159 return false;
160
sprangc5d62e22017-04-02 23:53:04 -0700161 int framerate_fps = GetCurrentConfiguredFramerate();
Danil Chapovalovabd42732018-09-10 14:07:45 +0200162 task_queue_.PostDelayedTask(absl::make_unique<InsertFrameTask>(this),
163 1000 / framerate_fps);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000164
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000165 return true;
166}
167
168void FrameGeneratorCapturer::InsertFrame() {
sprangc5d62e22017-04-02 23:53:04 -0700169 rtc::CritScope cs(&lock_);
170 if (sending_) {
171 VideoFrame* frame = frame_generator_->NextFrame();
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200172 // TODO(srte): Use more advanced frame rate control to allow arbritrary
173 // fractions.
174 int decimation =
175 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
176 for (int i = 1; i < decimation; ++i)
177 frame = frame_generator_->NextFrame();
ilnik04f4d122017-06-19 07:18:55 -0700178 frame->set_timestamp_us(clock_->TimeInMicroseconds());
sprangc5d62e22017-04-02 23:53:04 -0700179 frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
180 frame->set_rotation(fake_rotation_);
Johannes Kronf7f13e02018-12-12 11:17:43 +0100181 if (fake_color_space_) {
182 frame->set_color_space(&fake_color_space_.value());
183 }
sprangc5d62e22017-04-02 23:53:04 -0700184 if (first_frame_capture_time_ == -1) {
185 first_frame_capture_time_ = frame->ntp_time_ms();
186 }
187
Niels Möller3793bb42018-12-20 13:46:06 +0100188 TestVideoCapturer::OnFrame(*frame);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000189 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000190}
191
192void FrameGeneratorCapturer::Start() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200193 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000194 sending_ = true;
195}
196
197void FrameGeneratorCapturer::Stop() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200198 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000199 sending_ = false;
200}
sprang867fb522015-08-03 04:38:41 -0700201
perkjfa10b552016-10-02 23:45:26 -0700202void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) {
203 rtc::CritScope cs(&lock_);
204 frame_generator_->ChangeResolution(width, height);
205}
206
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200207void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) {
208 rtc::CritScope cs(&lock_);
209 RTC_CHECK(target_capture_fps_ > 0);
210 if (target_framerate > source_fps_)
211 RTC_LOG(LS_WARNING) << "Target framerate clamped from " << target_framerate
212 << " to " << source_fps_;
213 if (source_fps_ % target_capture_fps_ != 0) {
214 int decimation =
215 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
216 int effective_rate = target_capture_fps_ / decimation;
217 RTC_LOG(LS_WARNING) << "Target framerate, " << target_framerate
218 << ", is an uneven fraction of the source rate, "
219 << source_fps_
220 << ". The framerate will be :" << effective_rate;
221 }
222 target_capture_fps_ = std::min(source_fps_, target_framerate);
223}
224
perkj803d97f2016-11-01 11:45:46 -0700225void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
226 rtc::CritScope cs(&lock_);
227 RTC_DCHECK(!sink_wants_observer_);
228 sink_wants_observer_ = observer;
229}
230
perkja49cbd32016-09-16 07:53:41 -0700231void FrameGeneratorCapturer::AddOrUpdateSink(
232 rtc::VideoSinkInterface<VideoFrame>* sink,
233 const rtc::VideoSinkWants& wants) {
Niels Möller3793bb42018-12-20 13:46:06 +0100234 TestVideoCapturer::AddOrUpdateSink(sink, wants);
perkja49cbd32016-09-16 07:53:41 -0700235 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100236 if (sink_wants_observer_) {
237 // Tests need to observe unmodified sink wants.
perkj803d97f2016-11-01 11:45:46 -0700238 sink_wants_observer_->OnSinkWantsChanged(sink, wants);
sprangc5d62e22017-04-02 23:53:04 -0700239 }
Niels Möller3793bb42018-12-20 13:46:06 +0100240 UpdateFps(GetSinkWants().max_framerate_fps);
perkja49cbd32016-09-16 07:53:41 -0700241}
242
243void FrameGeneratorCapturer::RemoveSink(
244 rtc::VideoSinkInterface<VideoFrame>* sink) {
Niels Möller3793bb42018-12-20 13:46:06 +0100245 TestVideoCapturer::RemoveSink(sink);
246
perkja49cbd32016-09-16 07:53:41 -0700247 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100248 UpdateFps(GetSinkWants().max_framerate_fps);
249}
250
251void FrameGeneratorCapturer::UpdateFps(int max_fps) {
252 if (max_fps < target_capture_fps_) {
253 wanted_fps_.emplace(max_fps);
254 } else {
255 wanted_fps_.reset();
256 }
perkja49cbd32016-09-16 07:53:41 -0700257}
258
sprang867fb522015-08-03 04:38:41 -0700259void FrameGeneratorCapturer::ForceFrame() {
ilnikbaded152017-03-17 05:55:25 -0700260 // One-time non-repeating task,
Danil Chapovalovabd42732018-09-10 14:07:45 +0200261 task_queue_.PostTask([this] { InsertFrame(); });
sprang867fb522015-08-03 04:38:41 -0700262}
ilnikbaded152017-03-17 05:55:25 -0700263
sprangc5d62e22017-04-02 23:53:04 -0700264int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() {
265 rtc::CritScope cs(&lock_);
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200266 if (wanted_fps_ && *wanted_fps_ < target_capture_fps_)
sprangc5d62e22017-04-02 23:53:04 -0700267 return *wanted_fps_;
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200268 return target_capture_fps_;
sprangc5d62e22017-04-02 23:53:04 -0700269}
270
ilnikbaded152017-03-17 05:55:25 -0700271} // namespace test
272} // namespace webrtc