blob: 885ff2c9d19231850870ad2bf9abf7dcf1dc3a5b [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"
Sebastian Janssonfb14c5d2019-02-28 13:30:04 +010020#include "api/task_queue/global_task_queue_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010021#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "rtc_base/critical_section.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/task_queue.h"
Sebastian Janssonecb68972019-01-18 10:30:54 +010025#include "rtc_base/task_utils/repeating_task.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "system_wrappers/include/clock.h"
pbos@webrtc.org26d12102013-05-29 13:41:03 +000028
29namespace webrtc {
30namespace test {
31
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080032FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
33 int width,
34 int height,
Danil Chapovalov431abd92018-06-18 12:54:17 +020035 absl::optional<FrameGenerator::OutputType> type,
36 absl::optional<int> num_squares,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080037 int target_fps,
38 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020039 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080040 clock,
41 FrameGenerator::CreateSquareGenerator(width, height, type, num_squares),
Danil Chapovalovabd42732018-09-10 14:07:45 +020042 target_fps);
Taylor Brandstetter081136f2018-03-08 01:54:10 +000043 if (!capturer->Init())
44 return nullptr;
45
46 return capturer.release();
47}
48
andresp@webrtc.orgab654952013-09-19 12:14:03 +000049FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile(
sprang@webrtc.org131bea82015-02-18 12:46:06 +000050 const std::string& file_name,
andresp@webrtc.orgab654952013-09-19 12:14:03 +000051 size_t width,
52 size_t height,
53 int target_fps,
54 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020055 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
sprangc5d62e22017-04-02 23:53:04 -070056 clock,
57 FrameGenerator::CreateFromYuvFile(std::vector<std::string>(1, file_name),
58 width, height, 1),
Danil Chapovalovabd42732018-09-10 14:07:45 +020059 target_fps);
sprangc5d62e22017-04-02 23:53:04 -070060 if (!capturer->Init())
61 return nullptr;
andresp@webrtc.orgab654952013-09-19 12:14:03 +000062
sprangc5d62e22017-04-02 23:53:04 -070063 return capturer.release();
andresp@webrtc.orgab654952013-09-19 12:14:03 +000064}
65
erikvarga579de6f2017-08-29 09:12:57 -070066FrameGeneratorCapturer* FrameGeneratorCapturer::CreateSlideGenerator(
67 int width,
68 int height,
69 int frame_repeat_count,
70 int target_fps,
71 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020072 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
Yves Gerey665174f2018-06-19 15:03:05 +020073 clock,
74 FrameGenerator::CreateSlideGenerator(width, height, frame_repeat_count),
Danil Chapovalovabd42732018-09-10 14:07:45 +020075 target_fps);
erikvarga579de6f2017-08-29 09:12:57 -070076 if (!capturer->Init())
77 return nullptr;
78
79 return capturer.release();
80}
81
Artem Titova3ed4512019-01-25 14:59:57 +010082FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
83 std::unique_ptr<FrameGenerator> frame_generator,
84 int target_fps,
85 Clock* clock) {
86 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
87 clock, std::move(frame_generator), target_fps);
88 if (!capturer->Init())
89 return nullptr;
90
91 return capturer.release();
92}
93
perkja8ba1952017-02-27 06:52:10 -080094FrameGeneratorCapturer::FrameGeneratorCapturer(
95 Clock* clock,
96 std::unique_ptr<FrameGenerator> frame_generator,
97 int target_fps)
Sebastian Janssonfb14c5d2019-02-28 13:30:04 +010098 : FrameGeneratorCapturer(clock,
99 std::move(frame_generator),
100 target_fps,
101 GlobalTaskQueueFactory()) {}
102
103FrameGeneratorCapturer::FrameGeneratorCapturer(
104 Clock* clock,
105 std::unique_ptr<FrameGenerator> frame_generator,
106 int target_fps,
107 TaskQueueFactory& task_queue_factory)
perkja49cbd32016-09-16 07:53:41 -0700108 : clock_(clock),
Niels Möller8eeccbe2018-12-14 13:35:32 +0100109 sending_(true),
perkj803d97f2016-11-01 11:45:46 -0700110 sink_wants_observer_(nullptr),
perkja8ba1952017-02-27 06:52:10 -0800111 frame_generator_(std::move(frame_generator)),
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200112 source_fps_(target_fps),
113 target_capture_fps_(target_fps),
ilnikbaded152017-03-17 05:55:25 -0700114 first_frame_capture_time_(-1),
Sebastian Janssonfb14c5d2019-02-28 13:30:04 +0100115 task_queue_(task_queue_factory.CreateTaskQueue(
116 "FrameGenCapQ",
117 TaskQueueFactory::Priority::HIGH)) {
perkja8ba1952017-02-27 06:52:10 -0800118 RTC_DCHECK(frame_generator_);
perkja49cbd32016-09-16 07:53:41 -0700119 RTC_DCHECK_GT(target_fps, 0);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000120}
121
122FrameGeneratorCapturer::~FrameGeneratorCapturer() {
123 Stop();
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000124}
125
Perba7dc722016-04-19 15:01:23 +0200126void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) {
127 rtc::CritScope cs(&lock_);
128 fake_rotation_ = rotation;
129}
130
Johannes Kronf7f13e02018-12-12 11:17:43 +0100131void FrameGeneratorCapturer::SetFakeColorSpace(
132 absl::optional<ColorSpace> color_space) {
133 rtc::CritScope cs(&lock_);
134 fake_color_space_ = color_space;
135}
136
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000137bool FrameGeneratorCapturer::Init() {
pbos@webrtc.org94015242013-10-16 11:05:37 +0000138 // This check is added because frame_generator_ might be file based and should
139 // not crash because a file moved.
sprangc5d62e22017-04-02 23:53:04 -0700140 if (frame_generator_.get() == nullptr)
pbos@webrtc.org94015242013-10-16 11:05:37 +0000141 return false;
142
Sebastian Janssonecb68972019-01-18 10:30:54 +0100143 RepeatingTaskHandle::DelayedStart(
144 &task_queue_, TimeDelta::seconds(1) / GetCurrentConfiguredFramerate(),
145 [this] {
146 InsertFrame();
147 return TimeDelta::seconds(1) / GetCurrentConfiguredFramerate();
148 });
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000149 return true;
150}
151
152void FrameGeneratorCapturer::InsertFrame() {
sprangc5d62e22017-04-02 23:53:04 -0700153 rtc::CritScope cs(&lock_);
154 if (sending_) {
155 VideoFrame* frame = frame_generator_->NextFrame();
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200156 // TODO(srte): Use more advanced frame rate control to allow arbritrary
157 // fractions.
158 int decimation =
159 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
160 for (int i = 1; i < decimation; ++i)
161 frame = frame_generator_->NextFrame();
ilnik04f4d122017-06-19 07:18:55 -0700162 frame->set_timestamp_us(clock_->TimeInMicroseconds());
sprangc5d62e22017-04-02 23:53:04 -0700163 frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
164 frame->set_rotation(fake_rotation_);
Johannes Kronf7f13e02018-12-12 11:17:43 +0100165 if (fake_color_space_) {
Danil Chapovalovb7698942019-02-05 11:32:19 +0100166 frame->set_color_space(fake_color_space_);
Johannes Kronf7f13e02018-12-12 11:17:43 +0100167 }
sprangc5d62e22017-04-02 23:53:04 -0700168 if (first_frame_capture_time_ == -1) {
169 first_frame_capture_time_ = frame->ntp_time_ms();
170 }
171
Niels Möller3793bb42018-12-20 13:46:06 +0100172 TestVideoCapturer::OnFrame(*frame);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000173 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000174}
175
176void FrameGeneratorCapturer::Start() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200177 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000178 sending_ = true;
179}
180
181void FrameGeneratorCapturer::Stop() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200182 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000183 sending_ = false;
184}
sprang867fb522015-08-03 04:38:41 -0700185
perkjfa10b552016-10-02 23:45:26 -0700186void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) {
187 rtc::CritScope cs(&lock_);
188 frame_generator_->ChangeResolution(width, height);
189}
190
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200191void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) {
192 rtc::CritScope cs(&lock_);
193 RTC_CHECK(target_capture_fps_ > 0);
194 if (target_framerate > source_fps_)
195 RTC_LOG(LS_WARNING) << "Target framerate clamped from " << target_framerate
196 << " to " << source_fps_;
197 if (source_fps_ % target_capture_fps_ != 0) {
198 int decimation =
199 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
200 int effective_rate = target_capture_fps_ / decimation;
201 RTC_LOG(LS_WARNING) << "Target framerate, " << target_framerate
202 << ", is an uneven fraction of the source rate, "
203 << source_fps_
204 << ". The framerate will be :" << effective_rate;
205 }
206 target_capture_fps_ = std::min(source_fps_, target_framerate);
207}
208
perkj803d97f2016-11-01 11:45:46 -0700209void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
210 rtc::CritScope cs(&lock_);
211 RTC_DCHECK(!sink_wants_observer_);
212 sink_wants_observer_ = observer;
213}
214
perkja49cbd32016-09-16 07:53:41 -0700215void FrameGeneratorCapturer::AddOrUpdateSink(
216 rtc::VideoSinkInterface<VideoFrame>* sink,
217 const rtc::VideoSinkWants& wants) {
Niels Möller3793bb42018-12-20 13:46:06 +0100218 TestVideoCapturer::AddOrUpdateSink(sink, wants);
perkja49cbd32016-09-16 07:53:41 -0700219 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100220 if (sink_wants_observer_) {
221 // Tests need to observe unmodified sink wants.
perkj803d97f2016-11-01 11:45:46 -0700222 sink_wants_observer_->OnSinkWantsChanged(sink, wants);
sprangc5d62e22017-04-02 23:53:04 -0700223 }
Niels Möller3793bb42018-12-20 13:46:06 +0100224 UpdateFps(GetSinkWants().max_framerate_fps);
perkja49cbd32016-09-16 07:53:41 -0700225}
226
227void FrameGeneratorCapturer::RemoveSink(
228 rtc::VideoSinkInterface<VideoFrame>* sink) {
Niels Möller3793bb42018-12-20 13:46:06 +0100229 TestVideoCapturer::RemoveSink(sink);
230
perkja49cbd32016-09-16 07:53:41 -0700231 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100232 UpdateFps(GetSinkWants().max_framerate_fps);
233}
234
235void FrameGeneratorCapturer::UpdateFps(int max_fps) {
236 if (max_fps < target_capture_fps_) {
237 wanted_fps_.emplace(max_fps);
238 } else {
239 wanted_fps_.reset();
240 }
perkja49cbd32016-09-16 07:53:41 -0700241}
242
sprang867fb522015-08-03 04:38:41 -0700243void FrameGeneratorCapturer::ForceFrame() {
ilnikbaded152017-03-17 05:55:25 -0700244 // One-time non-repeating task,
Danil Chapovalovabd42732018-09-10 14:07:45 +0200245 task_queue_.PostTask([this] { InsertFrame(); });
sprang867fb522015-08-03 04:38:41 -0700246}
ilnikbaded152017-03-17 05:55:25 -0700247
sprangc5d62e22017-04-02 23:53:04 -0700248int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() {
249 rtc::CritScope cs(&lock_);
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200250 if (wanted_fps_ && *wanted_fps_ < target_capture_fps_)
sprangc5d62e22017-04-02 23:53:04 -0700251 return *wanted_fps_;
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200252 return target_capture_fps_;
sprangc5d62e22017-04-02 23:53:04 -0700253}
254
ilnikbaded152017-03-17 05:55:25 -0700255} // namespace test
256} // namespace webrtc