blob: 87e9bb3bcfd9e967cd4781f8ed4b3e23aee148ed [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
ilnikbaded152017-03-17 05:55:25 -070013#include <utility>
14#include <vector>
15
Yves Gerey665174f2018-06-19 15:03:05 +020016#include "call/video_send_stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/criticalsection.h"
18#include "rtc_base/logging.h"
19#include "rtc_base/platform_thread.h"
20#include "rtc_base/task_queue.h"
21#include "rtc_base/timeutils.h"
22#include "system_wrappers/include/clock.h"
pbos@webrtc.org26d12102013-05-29 13:41:03 +000023
24namespace webrtc {
25namespace test {
26
ilnikbaded152017-03-17 05:55:25 -070027class FrameGeneratorCapturer::InsertFrameTask : public rtc::QueuedTask {
28 public:
29 // Repeats in |repeat_interval_ms|. One-time if |repeat_interval_ms| == 0.
30 InsertFrameTask(
31 webrtc::test::FrameGeneratorCapturer* frame_generator_capturer,
32 uint32_t repeat_interval_ms)
33 : frame_generator_capturer_(frame_generator_capturer),
34 repeat_interval_ms_(repeat_interval_ms),
35 intended_run_time_ms_(-1) {}
36
37 private:
38 bool Run() override {
sprangc5d62e22017-04-02 23:53:04 -070039 bool task_completed = true;
ilnikbaded152017-03-17 05:55:25 -070040 if (repeat_interval_ms_ > 0) {
sprangc5d62e22017-04-02 23:53:04 -070041 // This is not a one-off frame. Check if the frame interval for this
42 // task queue is the same same as the current configured frame rate.
43 uint32_t current_interval_ms =
44 1000 / frame_generator_capturer_->GetCurrentConfiguredFramerate();
45 if (repeat_interval_ms_ != current_interval_ms) {
46 // Frame rate has changed since task was started, create a new instance.
lliuuf9ed2352017-03-30 10:44:38 -070047 rtc::TaskQueue::Current()->PostDelayedTask(
sprangc5d62e22017-04-02 23:53:04 -070048 std::unique_ptr<rtc::QueuedTask>(new InsertFrameTask(
49 frame_generator_capturer_, current_interval_ms)),
50 current_interval_ms);
lliuuf9ed2352017-03-30 10:44:38 -070051 } else {
sprangc5d62e22017-04-02 23:53:04 -070052 // Schedule the next frame capture event to happen at approximately the
53 // correct absolute time point.
54 int64_t delay_ms;
55 int64_t time_now_ms = rtc::TimeMillis();
56 if (intended_run_time_ms_ > 0) {
57 delay_ms = time_now_ms - intended_run_time_ms_;
58 } else {
59 delay_ms = 0;
60 intended_run_time_ms_ = time_now_ms;
61 }
62 intended_run_time_ms_ += repeat_interval_ms_;
63 if (delay_ms < repeat_interval_ms_) {
64 rtc::TaskQueue::Current()->PostDelayedTask(
65 std::unique_ptr<rtc::QueuedTask>(this),
66 repeat_interval_ms_ - delay_ms);
67 } else {
68 rtc::TaskQueue::Current()->PostDelayedTask(
69 std::unique_ptr<rtc::QueuedTask>(this), 0);
Mirko Bonadei675513b2017-11-09 11:09:25 +010070 RTC_LOG(LS_ERROR)
sprangc5d62e22017-04-02 23:53:04 -070071 << "Frame Generator Capturer can't keep up with requested fps";
72 }
73 // Repost of this instance, make sure it is not deleted.
74 task_completed = false;
ilnikbaded152017-03-17 05:55:25 -070075 }
76 }
77 frame_generator_capturer_->InsertFrame();
78 // Task should be deleted only if it's not repeating.
sprangc5d62e22017-04-02 23:53:04 -070079 return task_completed;
ilnikbaded152017-03-17 05:55:25 -070080 }
81
82 webrtc::test::FrameGeneratorCapturer* const frame_generator_capturer_;
83 const uint32_t repeat_interval_ms_;
84 int64_t intended_run_time_ms_;
85};
86
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080087FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
88 int width,
89 int height,
Danil Chapovalov431abd92018-06-18 12:54:17 +020090 absl::optional<FrameGenerator::OutputType> type,
91 absl::optional<int> num_squares,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080092 int target_fps,
93 Clock* clock) {
sprangc5d62e22017-04-02 23:53:04 -070094 std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer(
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080095 clock,
96 FrameGenerator::CreateSquareGenerator(width, height, type, num_squares),
97 target_fps));
Taylor Brandstetter081136f2018-03-08 01:54:10 +000098 if (!capturer->Init())
99 return nullptr;
100
101 return capturer.release();
102}
103
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000104FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile(
sprang@webrtc.org131bea82015-02-18 12:46:06 +0000105 const std::string& file_name,
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000106 size_t width,
107 size_t height,
108 int target_fps,
109 Clock* clock) {
sprangc5d62e22017-04-02 23:53:04 -0700110 std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer(
111 clock,
112 FrameGenerator::CreateFromYuvFile(std::vector<std::string>(1, file_name),
113 width, height, 1),
114 target_fps));
115 if (!capturer->Init())
116 return nullptr;
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000117
sprangc5d62e22017-04-02 23:53:04 -0700118 return capturer.release();
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000119}
120
erikvarga579de6f2017-08-29 09:12:57 -0700121FrameGeneratorCapturer* FrameGeneratorCapturer::CreateSlideGenerator(
122 int width,
123 int height,
124 int frame_repeat_count,
125 int target_fps,
126 Clock* clock) {
127 std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer(
Yves Gerey665174f2018-06-19 15:03:05 +0200128 clock,
129 FrameGenerator::CreateSlideGenerator(width, height, frame_repeat_count),
erikvarga579de6f2017-08-29 09:12:57 -0700130 target_fps));
131 if (!capturer->Init())
132 return nullptr;
133
134 return capturer.release();
135}
136
perkja8ba1952017-02-27 06:52:10 -0800137FrameGeneratorCapturer::FrameGeneratorCapturer(
138 Clock* clock,
139 std::unique_ptr<FrameGenerator> frame_generator,
140 int target_fps)
perkja49cbd32016-09-16 07:53:41 -0700141 : clock_(clock),
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000142 sending_(false),
perkja49cbd32016-09-16 07:53:41 -0700143 sink_(nullptr),
perkj803d97f2016-11-01 11:45:46 -0700144 sink_wants_observer_(nullptr),
perkja8ba1952017-02-27 06:52:10 -0800145 frame_generator_(std::move(frame_generator)),
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200146 source_fps_(target_fps),
147 target_capture_fps_(target_fps),
ilnikbaded152017-03-17 05:55:25 -0700148 first_frame_capture_time_(-1),
Yves Gerey665174f2018-06-19 15:03:05 +0200149 task_queue_("FrameGenCapQ", rtc::TaskQueue::Priority::HIGH) {
perkja8ba1952017-02-27 06:52:10 -0800150 RTC_DCHECK(frame_generator_);
perkja49cbd32016-09-16 07:53:41 -0700151 RTC_DCHECK_GT(target_fps, 0);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000152}
153
154FrameGeneratorCapturer::~FrameGeneratorCapturer() {
155 Stop();
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000156}
157
Perba7dc722016-04-19 15:01:23 +0200158void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) {
159 rtc::CritScope cs(&lock_);
160 fake_rotation_ = rotation;
161}
162
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000163bool FrameGeneratorCapturer::Init() {
pbos@webrtc.org94015242013-10-16 11:05:37 +0000164 // This check is added because frame_generator_ might be file based and should
165 // not crash because a file moved.
sprangc5d62e22017-04-02 23:53:04 -0700166 if (frame_generator_.get() == nullptr)
pbos@webrtc.org94015242013-10-16 11:05:37 +0000167 return false;
168
sprangc5d62e22017-04-02 23:53:04 -0700169 int framerate_fps = GetCurrentConfiguredFramerate();
ilnikbaded152017-03-17 05:55:25 -0700170 task_queue_.PostDelayedTask(
171 std::unique_ptr<rtc::QueuedTask>(
sprangc5d62e22017-04-02 23:53:04 -0700172 new InsertFrameTask(this, 1000 / framerate_fps)),
173 1000 / framerate_fps);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000174
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000175 return true;
176}
177
178void FrameGeneratorCapturer::InsertFrame() {
sprangc5d62e22017-04-02 23:53:04 -0700179 rtc::CritScope cs(&lock_);
180 if (sending_) {
181 VideoFrame* frame = frame_generator_->NextFrame();
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200182 // TODO(srte): Use more advanced frame rate control to allow arbritrary
183 // fractions.
184 int decimation =
185 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
186 for (int i = 1; i < decimation; ++i)
187 frame = frame_generator_->NextFrame();
ilnik04f4d122017-06-19 07:18:55 -0700188 frame->set_timestamp_us(clock_->TimeInMicroseconds());
sprangc5d62e22017-04-02 23:53:04 -0700189 frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
190 frame->set_rotation(fake_rotation_);
191 if (first_frame_capture_time_ == -1) {
192 first_frame_capture_time_ = frame->ntp_time_ms();
193 }
194
195 if (sink_) {
Danil Chapovalov431abd92018-06-18 12:54:17 +0200196 absl::optional<VideoFrame> out_frame = AdaptFrame(*frame);
sprangc5d62e22017-04-02 23:53:04 -0700197 if (out_frame)
198 sink_->OnFrame(*out_frame);
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000199 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000200 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000201}
202
203void FrameGeneratorCapturer::Start() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200204 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000205 sending_ = true;
206}
207
208void FrameGeneratorCapturer::Stop() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200209 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000210 sending_ = false;
211}
sprang867fb522015-08-03 04:38:41 -0700212
perkjfa10b552016-10-02 23:45:26 -0700213void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) {
214 rtc::CritScope cs(&lock_);
215 frame_generator_->ChangeResolution(width, height);
216}
217
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200218void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) {
219 rtc::CritScope cs(&lock_);
220 RTC_CHECK(target_capture_fps_ > 0);
221 if (target_framerate > source_fps_)
222 RTC_LOG(LS_WARNING) << "Target framerate clamped from " << target_framerate
223 << " to " << source_fps_;
224 if (source_fps_ % target_capture_fps_ != 0) {
225 int decimation =
226 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
227 int effective_rate = target_capture_fps_ / decimation;
228 RTC_LOG(LS_WARNING) << "Target framerate, " << target_framerate
229 << ", is an uneven fraction of the source rate, "
230 << source_fps_
231 << ". The framerate will be :" << effective_rate;
232 }
233 target_capture_fps_ = std::min(source_fps_, target_framerate);
234}
235
perkj803d97f2016-11-01 11:45:46 -0700236void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
237 rtc::CritScope cs(&lock_);
238 RTC_DCHECK(!sink_wants_observer_);
239 sink_wants_observer_ = observer;
240}
241
perkja49cbd32016-09-16 07:53:41 -0700242void FrameGeneratorCapturer::AddOrUpdateSink(
243 rtc::VideoSinkInterface<VideoFrame>* sink,
244 const rtc::VideoSinkWants& wants) {
245 rtc::CritScope cs(&lock_);
perkj803d97f2016-11-01 11:45:46 -0700246 RTC_CHECK(!sink_ || sink_ == sink);
perkja49cbd32016-09-16 07:53:41 -0700247 sink_ = sink;
perkj803d97f2016-11-01 11:45:46 -0700248 if (sink_wants_observer_)
249 sink_wants_observer_->OnSinkWantsChanged(sink, wants);
sprangc5d62e22017-04-02 23:53:04 -0700250
251 // Handle framerate within this class, just pass on resolution for possible
252 // adaptation.
253 rtc::VideoSinkWants resolution_wants = wants;
254 resolution_wants.max_framerate_fps = std::numeric_limits<int>::max();
Sebastian Janssonf1f363f2018-08-13 14:24:58 +0200255 TestVideoCapturer::AddOrUpdateSink(sink, resolution_wants);
sprangc5d62e22017-04-02 23:53:04 -0700256
257 // Ignore any requests for framerate higher than initially configured.
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200258 if (wants.max_framerate_fps < target_capture_fps_) {
sprangc5d62e22017-04-02 23:53:04 -0700259 wanted_fps_.emplace(wants.max_framerate_fps);
260 } else {
261 wanted_fps_.reset();
262 }
perkja49cbd32016-09-16 07:53:41 -0700263}
264
265void FrameGeneratorCapturer::RemoveSink(
266 rtc::VideoSinkInterface<VideoFrame>* sink) {
267 rtc::CritScope cs(&lock_);
268 RTC_CHECK(sink_ == sink);
269 sink_ = nullptr;
270}
271
sprang867fb522015-08-03 04:38:41 -0700272void FrameGeneratorCapturer::ForceFrame() {
ilnikbaded152017-03-17 05:55:25 -0700273 // One-time non-repeating task,
274 // therefore repeat_interval_ms is 0 in InsertFrameTask()
275 task_queue_.PostTask(
276 std::unique_ptr<rtc::QueuedTask>(new InsertFrameTask(this, 0)));
sprang867fb522015-08-03 04:38:41 -0700277}
ilnikbaded152017-03-17 05:55:25 -0700278
sprangc5d62e22017-04-02 23:53:04 -0700279int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() {
280 rtc::CritScope cs(&lock_);
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200281 if (wanted_fps_ && *wanted_fps_ < target_capture_fps_)
sprangc5d62e22017-04-02 23:53:04 -0700282 return *wanted_fps_;
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200283 return target_capture_fps_;
sprangc5d62e22017-04-02 23:53:04 -0700284}
285
ilnikbaded152017-03-17 05:55:25 -0700286} // namespace test
287} // namespace webrtc