blob: 49ce40a440a6e69d014d850f1af23e710e649f87 [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
Artem Titova3ed4512019-01-25 14:59:57 +010081FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
82 std::unique_ptr<FrameGenerator> frame_generator,
83 int target_fps,
84 Clock* clock) {
85 auto capturer = absl::make_unique<FrameGeneratorCapturer>(
86 clock, std::move(frame_generator), target_fps);
87 if (!capturer->Init())
88 return nullptr;
89
90 return capturer.release();
91}
92
perkja8ba1952017-02-27 06:52:10 -080093FrameGeneratorCapturer::FrameGeneratorCapturer(
94 Clock* clock,
95 std::unique_ptr<FrameGenerator> frame_generator,
96 int target_fps)
perkja49cbd32016-09-16 07:53:41 -070097 : clock_(clock),
Niels Möller8eeccbe2018-12-14 13:35:32 +010098 sending_(true),
perkj803d97f2016-11-01 11:45:46 -070099 sink_wants_observer_(nullptr),
perkja8ba1952017-02-27 06:52:10 -0800100 frame_generator_(std::move(frame_generator)),
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200101 source_fps_(target_fps),
102 target_capture_fps_(target_fps),
ilnikbaded152017-03-17 05:55:25 -0700103 first_frame_capture_time_(-1),
Yves Gerey665174f2018-06-19 15:03:05 +0200104 task_queue_("FrameGenCapQ", rtc::TaskQueue::Priority::HIGH) {
perkja8ba1952017-02-27 06:52:10 -0800105 RTC_DCHECK(frame_generator_);
perkja49cbd32016-09-16 07:53:41 -0700106 RTC_DCHECK_GT(target_fps, 0);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000107}
108
109FrameGeneratorCapturer::~FrameGeneratorCapturer() {
110 Stop();
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000111}
112
Perba7dc722016-04-19 15:01:23 +0200113void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) {
114 rtc::CritScope cs(&lock_);
115 fake_rotation_ = rotation;
116}
117
Johannes Kronf7f13e02018-12-12 11:17:43 +0100118void FrameGeneratorCapturer::SetFakeColorSpace(
119 absl::optional<ColorSpace> color_space) {
120 rtc::CritScope cs(&lock_);
121 fake_color_space_ = color_space;
122}
123
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000124bool FrameGeneratorCapturer::Init() {
pbos@webrtc.org94015242013-10-16 11:05:37 +0000125 // This check is added because frame_generator_ might be file based and should
126 // not crash because a file moved.
sprangc5d62e22017-04-02 23:53:04 -0700127 if (frame_generator_.get() == nullptr)
pbos@webrtc.org94015242013-10-16 11:05:37 +0000128 return false;
129
Sebastian Janssonecb68972019-01-18 10:30:54 +0100130 RepeatingTaskHandle::DelayedStart(
131 &task_queue_, TimeDelta::seconds(1) / GetCurrentConfiguredFramerate(),
132 [this] {
133 InsertFrame();
134 return TimeDelta::seconds(1) / GetCurrentConfiguredFramerate();
135 });
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000136 return true;
137}
138
139void FrameGeneratorCapturer::InsertFrame() {
sprangc5d62e22017-04-02 23:53:04 -0700140 rtc::CritScope cs(&lock_);
141 if (sending_) {
142 VideoFrame* frame = frame_generator_->NextFrame();
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200143 // TODO(srte): Use more advanced frame rate control to allow arbritrary
144 // fractions.
145 int decimation =
146 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
147 for (int i = 1; i < decimation; ++i)
148 frame = frame_generator_->NextFrame();
ilnik04f4d122017-06-19 07:18:55 -0700149 frame->set_timestamp_us(clock_->TimeInMicroseconds());
sprangc5d62e22017-04-02 23:53:04 -0700150 frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
151 frame->set_rotation(fake_rotation_);
Johannes Kronf7f13e02018-12-12 11:17:43 +0100152 if (fake_color_space_) {
Danil Chapovalovb7698942019-02-05 11:32:19 +0100153 frame->set_color_space(fake_color_space_);
Johannes Kronf7f13e02018-12-12 11:17:43 +0100154 }
sprangc5d62e22017-04-02 23:53:04 -0700155 if (first_frame_capture_time_ == -1) {
156 first_frame_capture_time_ = frame->ntp_time_ms();
157 }
158
Niels Möller3793bb42018-12-20 13:46:06 +0100159 TestVideoCapturer::OnFrame(*frame);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000160 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000161}
162
163void FrameGeneratorCapturer::Start() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200164 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000165 sending_ = true;
166}
167
168void FrameGeneratorCapturer::Stop() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200169 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000170 sending_ = false;
171}
sprang867fb522015-08-03 04:38:41 -0700172
perkjfa10b552016-10-02 23:45:26 -0700173void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) {
174 rtc::CritScope cs(&lock_);
175 frame_generator_->ChangeResolution(width, height);
176}
177
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200178void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) {
179 rtc::CritScope cs(&lock_);
180 RTC_CHECK(target_capture_fps_ > 0);
181 if (target_framerate > source_fps_)
182 RTC_LOG(LS_WARNING) << "Target framerate clamped from " << target_framerate
183 << " to " << source_fps_;
184 if (source_fps_ % target_capture_fps_ != 0) {
185 int decimation =
186 std::round(static_cast<double>(source_fps_) / target_capture_fps_);
187 int effective_rate = target_capture_fps_ / decimation;
188 RTC_LOG(LS_WARNING) << "Target framerate, " << target_framerate
189 << ", is an uneven fraction of the source rate, "
190 << source_fps_
191 << ". The framerate will be :" << effective_rate;
192 }
193 target_capture_fps_ = std::min(source_fps_, target_framerate);
194}
195
perkj803d97f2016-11-01 11:45:46 -0700196void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
197 rtc::CritScope cs(&lock_);
198 RTC_DCHECK(!sink_wants_observer_);
199 sink_wants_observer_ = observer;
200}
201
perkja49cbd32016-09-16 07:53:41 -0700202void FrameGeneratorCapturer::AddOrUpdateSink(
203 rtc::VideoSinkInterface<VideoFrame>* sink,
204 const rtc::VideoSinkWants& wants) {
Niels Möller3793bb42018-12-20 13:46:06 +0100205 TestVideoCapturer::AddOrUpdateSink(sink, wants);
perkja49cbd32016-09-16 07:53:41 -0700206 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100207 if (sink_wants_observer_) {
208 // Tests need to observe unmodified sink wants.
perkj803d97f2016-11-01 11:45:46 -0700209 sink_wants_observer_->OnSinkWantsChanged(sink, wants);
sprangc5d62e22017-04-02 23:53:04 -0700210 }
Niels Möller3793bb42018-12-20 13:46:06 +0100211 UpdateFps(GetSinkWants().max_framerate_fps);
perkja49cbd32016-09-16 07:53:41 -0700212}
213
214void FrameGeneratorCapturer::RemoveSink(
215 rtc::VideoSinkInterface<VideoFrame>* sink) {
Niels Möller3793bb42018-12-20 13:46:06 +0100216 TestVideoCapturer::RemoveSink(sink);
217
perkja49cbd32016-09-16 07:53:41 -0700218 rtc::CritScope cs(&lock_);
Niels Möller3793bb42018-12-20 13:46:06 +0100219 UpdateFps(GetSinkWants().max_framerate_fps);
220}
221
222void FrameGeneratorCapturer::UpdateFps(int max_fps) {
223 if (max_fps < target_capture_fps_) {
224 wanted_fps_.emplace(max_fps);
225 } else {
226 wanted_fps_.reset();
227 }
perkja49cbd32016-09-16 07:53:41 -0700228}
229
sprang867fb522015-08-03 04:38:41 -0700230void FrameGeneratorCapturer::ForceFrame() {
ilnikbaded152017-03-17 05:55:25 -0700231 // One-time non-repeating task,
Danil Chapovalovabd42732018-09-10 14:07:45 +0200232 task_queue_.PostTask([this] { InsertFrame(); });
sprang867fb522015-08-03 04:38:41 -0700233}
ilnikbaded152017-03-17 05:55:25 -0700234
sprangc5d62e22017-04-02 23:53:04 -0700235int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() {
236 rtc::CritScope cs(&lock_);
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200237 if (wanted_fps_ && *wanted_fps_ < target_capture_fps_)
sprangc5d62e22017-04-02 23:53:04 -0700238 return *wanted_fps_;
Sebastian Janssonba3decf2018-08-30 11:19:23 +0200239 return target_capture_fps_;
sprangc5d62e22017-04-02 23:53:04 -0700240}
241
ilnikbaded152017-03-17 05:55:25 -0700242} // namespace test
243} // namespace webrtc