blob: aa3f944e13a612d7163cddf80e52f0a3e2c1ce77 [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"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "rtc_base/critical_section.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/task_queue.h"
Sebastian Janssonecb68972019-01-18 10:30:54 +010024#include "rtc_base/task_utils/repeating_task.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "system_wrappers/include/clock.h"
pbos@webrtc.org26d12102013-05-29 13:41:03 +000027
28namespace webrtc {
29namespace test {
30
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080031FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
32 int width,
33 int height,
Danil Chapovalov431abd92018-06-18 12:54:17 +020034 absl::optional<FrameGenerator::OutputType> type,
35 absl::optional<int> num_squares,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080036 int target_fps,
37 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020038 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080039 clock,
40 FrameGenerator::CreateSquareGenerator(width, height, type, num_squares),
Danil Chapovalovabd42732018-09-10 14:07:45 +020041 target_fps);
Taylor Brandstetter081136f2018-03-08 01:54:10 +000042 if (!capturer->Init())
43 return nullptr;
44
45 return capturer.release();
46}
47
andresp@webrtc.orgab654952013-09-19 12:14:03 +000048FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile(
sprang@webrtc.org131bea82015-02-18 12:46:06 +000049 const std::string& file_name,
andresp@webrtc.orgab654952013-09-19 12:14:03 +000050 size_t width,
51 size_t height,
52 int target_fps,
53 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020054 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
sprangc5d62e22017-04-02 23:53:04 -070055 clock,
56 FrameGenerator::CreateFromYuvFile(std::vector<std::string>(1, file_name),
57 width, height, 1),
Danil Chapovalovabd42732018-09-10 14:07:45 +020058 target_fps);
sprangc5d62e22017-04-02 23:53:04 -070059 if (!capturer->Init())
60 return nullptr;
andresp@webrtc.orgab654952013-09-19 12:14:03 +000061
sprangc5d62e22017-04-02 23:53:04 -070062 return capturer.release();
andresp@webrtc.orgab654952013-09-19 12:14:03 +000063}
64
erikvarga579de6f2017-08-29 09:12:57 -070065FrameGeneratorCapturer* FrameGeneratorCapturer::CreateSlideGenerator(
66 int width,
67 int height,
68 int frame_repeat_count,
69 int target_fps,
70 Clock* clock) {
Danil Chapovalovabd42732018-09-10 14:07:45 +020071 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
Yves Gerey665174f2018-06-19 15:03:05 +020072 clock,
73 FrameGenerator::CreateSlideGenerator(width, height, frame_repeat_count),
Danil Chapovalovabd42732018-09-10 14:07:45 +020074 target_fps);
erikvarga579de6f2017-08-29 09:12:57 -070075 if (!capturer->Init())
76 return nullptr;
77
78 return capturer.release();
79}
80
perkja8ba1952017-02-27 06:52:10 -080081FrameGeneratorCapturer::FrameGeneratorCapturer(
82 Clock* clock,
83 std::unique_ptr<FrameGenerator> frame_generator,
84 int target_fps)
perkja49cbd32016-09-16 07:53:41 -070085 : clock_(clock),
Niels Möller8eeccbe2018-12-14 13:35:32 +010086 sending_(true),
perkj803d97f2016-11-01 11:45:46 -070087 sink_wants_observer_(nullptr),
perkja8ba1952017-02-27 06:52:10 -080088 frame_generator_(std::move(frame_generator)),
Sebastian Janssonba3decf2018-08-30 11:19:23 +020089 source_fps_(target_fps),
90 target_capture_fps_(target_fps),
ilnikbaded152017-03-17 05:55:25 -070091 first_frame_capture_time_(-1),
Yves Gerey665174f2018-06-19 15:03:05 +020092 task_queue_("FrameGenCapQ", rtc::TaskQueue::Priority::HIGH) {
perkja8ba1952017-02-27 06:52:10 -080093 RTC_DCHECK(frame_generator_);
perkja49cbd32016-09-16 07:53:41 -070094 RTC_DCHECK_GT(target_fps, 0);
pbos@webrtc.org26d12102013-05-29 13:41:03 +000095}
96
97FrameGeneratorCapturer::~FrameGeneratorCapturer() {
98 Stop();
pbos@webrtc.org26d12102013-05-29 13:41:03 +000099}
100
Perba7dc722016-04-19 15:01:23 +0200101void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) {
102 rtc::CritScope cs(&lock_);
103 fake_rotation_ = rotation;
104}
105
Johannes Kronf7f13e02018-12-12 11:17:43 +0100106void FrameGeneratorCapturer::SetFakeColorSpace(
107 absl::optional<ColorSpace> color_space) {
108 rtc::CritScope cs(&lock_);
109 fake_color_space_ = color_space;
110}
111
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000112bool FrameGeneratorCapturer::Init() {
pbos@webrtc.org94015242013-10-16 11:05:37 +0000113 // This check is added because frame_generator_ might be file based and should
114 // not crash because a file moved.
sprangc5d62e22017-04-02 23:53:04 -0700115 if (frame_generator_.get() == nullptr)
pbos@webrtc.org94015242013-10-16 11:05:37 +0000116 return false;
117
Sebastian Janssonecb68972019-01-18 10:30:54 +0100118 RepeatingTaskHandle::DelayedStart(
119 &task_queue_, TimeDelta::seconds(1) / GetCurrentConfiguredFramerate(),
120 [this] {
121 InsertFrame();
122 return TimeDelta::seconds(1) / GetCurrentConfiguredFramerate();
123 });
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000124 return true;
125}
126
127void FrameGeneratorCapturer::InsertFrame() {
sprangc5d62e22017-04-02 23:53:04 -0700128 rtc::CritScope cs(&lock_);
129 if (sending_) {
130 VideoFrame* frame = frame_generator_->NextFrame();
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200131 // TODO(srte): Use more advanced frame rate control to allow arbritrary
132 // fractions.
133 int decimation =
134 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
135 for (int i = 1; i < decimation; ++i)
136 frame = frame_generator_->NextFrame();
ilnik04f4d122017-06-19 07:18:55 -0700137 frame->set_timestamp_us(clock_->TimeInMicroseconds());
sprangc5d62e22017-04-02 23:53:04 -0700138 frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
139 frame->set_rotation(fake_rotation_);
Johannes Kronf7f13e02018-12-12 11:17:43 +0100140 if (fake_color_space_) {
141 frame->set_color_space(&fake_color_space_.value());
142 }
sprangc5d62e22017-04-02 23:53:04 -0700143 if (first_frame_capture_time_ == -1) {
144 first_frame_capture_time_ = frame->ntp_time_ms();
145 }
146
Niels Möller3793bb42018-12-20 13:46:06 +0100147 TestVideoCapturer::OnFrame(*frame);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000148 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000149}
150
151void FrameGeneratorCapturer::Start() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200152 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000153 sending_ = true;
154}
155
156void FrameGeneratorCapturer::Stop() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200157 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000158 sending_ = false;
159}
sprang867fb522015-08-03 04:38:41 -0700160
perkjfa10b552016-10-02 23:45:26 -0700161void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) {
162 rtc::CritScope cs(&lock_);
163 frame_generator_->ChangeResolution(width, height);
164}
165
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200166void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) {
167 rtc::CritScope cs(&lock_);
168 RTC_CHECK(target_capture_fps_ > 0);
169 if (target_framerate > source_fps_)
170 RTC_LOG(LS_WARNING) << "Target framerate clamped from " << target_framerate
171 << " to " << source_fps_;
172 if (source_fps_ % target_capture_fps_ != 0) {
173 int decimation =
174 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
175 int effective_rate = target_capture_fps_ / decimation;
176 RTC_LOG(LS_WARNING) << "Target framerate, " << target_framerate
177 << ", is an uneven fraction of the source rate, "
178 << source_fps_
179 << ". The framerate will be :" << effective_rate;
180 }
181 target_capture_fps_ = std::min(source_fps_, target_framerate);
182}
183
perkj803d97f2016-11-01 11:45:46 -0700184void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
185 rtc::CritScope cs(&lock_);
186 RTC_DCHECK(!sink_wants_observer_);
187 sink_wants_observer_ = observer;
188}
189
perkja49cbd32016-09-16 07:53:41 -0700190void FrameGeneratorCapturer::AddOrUpdateSink(
191 rtc::VideoSinkInterface<VideoFrame>* sink,
192 const rtc::VideoSinkWants& wants) {
Niels Möller3793bb42018-12-20 13:46:06 +0100193 TestVideoCapturer::AddOrUpdateSink(sink, wants);
perkja49cbd32016-09-16 07:53:41 -0700194 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100195 if (sink_wants_observer_) {
196 // Tests need to observe unmodified sink wants.
perkj803d97f2016-11-01 11:45:46 -0700197 sink_wants_observer_->OnSinkWantsChanged(sink, wants);
sprangc5d62e22017-04-02 23:53:04 -0700198 }
Niels Möller3793bb42018-12-20 13:46:06 +0100199 UpdateFps(GetSinkWants().max_framerate_fps);
perkja49cbd32016-09-16 07:53:41 -0700200}
201
202void FrameGeneratorCapturer::RemoveSink(
203 rtc::VideoSinkInterface<VideoFrame>* sink) {
Niels Möller3793bb42018-12-20 13:46:06 +0100204 TestVideoCapturer::RemoveSink(sink);
205
perkja49cbd32016-09-16 07:53:41 -0700206 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100207 UpdateFps(GetSinkWants().max_framerate_fps);
208}
209
210void FrameGeneratorCapturer::UpdateFps(int max_fps) {
211 if (max_fps < target_capture_fps_) {
212 wanted_fps_.emplace(max_fps);
213 } else {
214 wanted_fps_.reset();
215 }
perkja49cbd32016-09-16 07:53:41 -0700216}
217
sprang867fb522015-08-03 04:38:41 -0700218void FrameGeneratorCapturer::ForceFrame() {
ilnikbaded152017-03-17 05:55:25 -0700219 // One-time non-repeating task,
Danil Chapovalovabd42732018-09-10 14:07:45 +0200220 task_queue_.PostTask([this] { InsertFrame(); });
sprang867fb522015-08-03 04:38:41 -0700221}
ilnikbaded152017-03-17 05:55:25 -0700222
sprangc5d62e22017-04-02 23:53:04 -0700223int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() {
224 rtc::CritScope cs(&lock_);
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200225 if (wanted_fps_ && *wanted_fps_ < target_capture_fps_)
sprangc5d62e22017-04-02 23:53:04 -0700226 return *wanted_fps_;
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200227 return target_capture_fps_;
sprangc5d62e22017-04-02 23:53:04 -0700228}
229
ilnikbaded152017-03-17 05:55:25 -0700230} // namespace test
231} // namespace webrtc