blob: 095a2043e5a8a9bb760b6b54cdf67f0858c58102 [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
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000011#include "webrtc/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
Edward Lemurc20978e2017-07-06 19:44:34 +020016#include "webrtc/rtc_base/criticalsection.h"
17#include "webrtc/rtc_base/logging.h"
18#include "webrtc/rtc_base/platform_thread.h"
19#include "webrtc/rtc_base/task_queue.h"
20#include "webrtc/rtc_base/timeutils.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/clock.h"
pbos12411ef2015-11-23 14:47:56 -080022#include "webrtc/test/frame_generator.h"
mbonadei52127002017-08-28 06:46:48 -070023#include "webrtc/call/video_send_stream.h"
pbos@webrtc.org26d12102013-05-29 13:41:03 +000024
25namespace webrtc {
26namespace test {
27
ilnikbaded152017-03-17 05:55:25 -070028class FrameGeneratorCapturer::InsertFrameTask : public rtc::QueuedTask {
29 public:
30 // Repeats in |repeat_interval_ms|. One-time if |repeat_interval_ms| == 0.
31 InsertFrameTask(
32 webrtc::test::FrameGeneratorCapturer* frame_generator_capturer,
33 uint32_t repeat_interval_ms)
34 : frame_generator_capturer_(frame_generator_capturer),
35 repeat_interval_ms_(repeat_interval_ms),
36 intended_run_time_ms_(-1) {}
37
38 private:
39 bool Run() override {
sprangc5d62e22017-04-02 23:53:04 -070040 bool task_completed = true;
ilnikbaded152017-03-17 05:55:25 -070041 if (repeat_interval_ms_ > 0) {
sprangc5d62e22017-04-02 23:53:04 -070042 // This is not a one-off frame. Check if the frame interval for this
43 // task queue is the same same as the current configured frame rate.
44 uint32_t current_interval_ms =
45 1000 / frame_generator_capturer_->GetCurrentConfiguredFramerate();
46 if (repeat_interval_ms_ != current_interval_ms) {
47 // Frame rate has changed since task was started, create a new instance.
lliuuf9ed2352017-03-30 10:44:38 -070048 rtc::TaskQueue::Current()->PostDelayedTask(
sprangc5d62e22017-04-02 23:53:04 -070049 std::unique_ptr<rtc::QueuedTask>(new InsertFrameTask(
50 frame_generator_capturer_, current_interval_ms)),
51 current_interval_ms);
lliuuf9ed2352017-03-30 10:44:38 -070052 } else {
sprangc5d62e22017-04-02 23:53:04 -070053 // Schedule the next frame capture event to happen at approximately the
54 // correct absolute time point.
55 int64_t delay_ms;
56 int64_t time_now_ms = rtc::TimeMillis();
57 if (intended_run_time_ms_ > 0) {
58 delay_ms = time_now_ms - intended_run_time_ms_;
59 } else {
60 delay_ms = 0;
61 intended_run_time_ms_ = time_now_ms;
62 }
63 intended_run_time_ms_ += repeat_interval_ms_;
64 if (delay_ms < repeat_interval_ms_) {
65 rtc::TaskQueue::Current()->PostDelayedTask(
66 std::unique_ptr<rtc::QueuedTask>(this),
67 repeat_interval_ms_ - delay_ms);
68 } else {
69 rtc::TaskQueue::Current()->PostDelayedTask(
70 std::unique_ptr<rtc::QueuedTask>(this), 0);
71 LOG(LS_ERROR)
72 << "Frame Generator Capturer can't keep up with requested fps";
73 }
74 // Repost of this instance, make sure it is not deleted.
75 task_completed = false;
ilnikbaded152017-03-17 05:55:25 -070076 }
77 }
78 frame_generator_capturer_->InsertFrame();
79 // Task should be deleted only if it's not repeating.
sprangc5d62e22017-04-02 23:53:04 -070080 return task_completed;
ilnikbaded152017-03-17 05:55:25 -070081 }
82
83 webrtc::test::FrameGeneratorCapturer* const frame_generator_capturer_;
84 const uint32_t repeat_interval_ms_;
85 int64_t intended_run_time_ms_;
86};
87
perkja8ba1952017-02-27 06:52:10 -080088FrameGeneratorCapturer* FrameGeneratorCapturer::Create(int width,
89 int height,
Peter Boström4b91bd02015-06-26 06:58:16 +020090 int target_fps,
91 Clock* clock) {
sprangc5d62e22017-04-02 23:53:04 -070092 std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer(
93 clock, FrameGenerator::CreateSquareGenerator(width, height), target_fps));
94 if (!capturer->Init())
95 return nullptr;
pbos@webrtc.org26d12102013-05-29 13:41:03 +000096
sprangc5d62e22017-04-02 23:53:04 -070097 return capturer.release();
pbos@webrtc.org26d12102013-05-29 13:41:03 +000098}
99
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000100FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile(
sprang@webrtc.org131bea82015-02-18 12:46:06 +0000101 const std::string& file_name,
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000102 size_t width,
103 size_t height,
104 int target_fps,
105 Clock* clock) {
sprangc5d62e22017-04-02 23:53:04 -0700106 std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer(
107 clock,
108 FrameGenerator::CreateFromYuvFile(std::vector<std::string>(1, file_name),
109 width, height, 1),
110 target_fps));
111 if (!capturer->Init())
112 return nullptr;
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000113
sprangc5d62e22017-04-02 23:53:04 -0700114 return capturer.release();
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000115}
116
erikvarga579de6f2017-08-29 09:12:57 -0700117FrameGeneratorCapturer* FrameGeneratorCapturer::CreateSlideGenerator(
118 int width,
119 int height,
120 int frame_repeat_count,
121 int target_fps,
122 Clock* clock) {
123 std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer(
124 clock, FrameGenerator::CreateSlideGenerator(width, height,
125 frame_repeat_count),
126 target_fps));
127 if (!capturer->Init())
128 return nullptr;
129
130 return capturer.release();
131}
132
perkja8ba1952017-02-27 06:52:10 -0800133FrameGeneratorCapturer::FrameGeneratorCapturer(
134 Clock* clock,
135 std::unique_ptr<FrameGenerator> frame_generator,
136 int target_fps)
perkja49cbd32016-09-16 07:53:41 -0700137 : clock_(clock),
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000138 sending_(false),
perkja49cbd32016-09-16 07:53:41 -0700139 sink_(nullptr),
perkj803d97f2016-11-01 11:45:46 -0700140 sink_wants_observer_(nullptr),
perkja8ba1952017-02-27 06:52:10 -0800141 frame_generator_(std::move(frame_generator)),
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000142 target_fps_(target_fps),
ilnikbaded152017-03-17 05:55:25 -0700143 first_frame_capture_time_(-1),
144 task_queue_("FrameGenCapQ",
145 rtc::TaskQueue::Priority::HIGH) {
perkja8ba1952017-02-27 06:52:10 -0800146 RTC_DCHECK(frame_generator_);
perkja49cbd32016-09-16 07:53:41 -0700147 RTC_DCHECK_GT(target_fps, 0);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000148}
149
150FrameGeneratorCapturer::~FrameGeneratorCapturer() {
151 Stop();
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000152}
153
Perba7dc722016-04-19 15:01:23 +0200154void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) {
155 rtc::CritScope cs(&lock_);
156 fake_rotation_ = rotation;
157}
158
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000159bool FrameGeneratorCapturer::Init() {
pbos@webrtc.org94015242013-10-16 11:05:37 +0000160 // This check is added because frame_generator_ might be file based and should
161 // not crash because a file moved.
sprangc5d62e22017-04-02 23:53:04 -0700162 if (frame_generator_.get() == nullptr)
pbos@webrtc.org94015242013-10-16 11:05:37 +0000163 return false;
164
sprangc5d62e22017-04-02 23:53:04 -0700165 int framerate_fps = GetCurrentConfiguredFramerate();
ilnikbaded152017-03-17 05:55:25 -0700166 task_queue_.PostDelayedTask(
167 std::unique_ptr<rtc::QueuedTask>(
sprangc5d62e22017-04-02 23:53:04 -0700168 new InsertFrameTask(this, 1000 / framerate_fps)),
169 1000 / framerate_fps);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000170
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000171 return true;
172}
173
174void FrameGeneratorCapturer::InsertFrame() {
sprangc5d62e22017-04-02 23:53:04 -0700175 rtc::CritScope cs(&lock_);
176 if (sending_) {
177 VideoFrame* 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_);
181 if (first_frame_capture_time_ == -1) {
182 first_frame_capture_time_ = frame->ntp_time_ms();
183 }
184
185 if (sink_) {
186 rtc::Optional<VideoFrame> out_frame = AdaptFrame(*frame);
187 if (out_frame)
188 sink_->OnFrame(*out_frame);
andresp@webrtc.orgab654952013-09-19 12:14:03 +0000189 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000190 }
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000191}
192
193void FrameGeneratorCapturer::Start() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200194 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000195 sending_ = true;
196}
197
198void FrameGeneratorCapturer::Stop() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200199 rtc::CritScope cs(&lock_);
pbos@webrtc.org26d12102013-05-29 13:41:03 +0000200 sending_ = false;
201}
sprang867fb522015-08-03 04:38:41 -0700202
perkjfa10b552016-10-02 23:45:26 -0700203void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) {
204 rtc::CritScope cs(&lock_);
205 frame_generator_->ChangeResolution(width, height);
206}
207
perkj803d97f2016-11-01 11:45:46 -0700208void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
209 rtc::CritScope cs(&lock_);
210 RTC_DCHECK(!sink_wants_observer_);
211 sink_wants_observer_ = observer;
212}
213
perkja49cbd32016-09-16 07:53:41 -0700214void FrameGeneratorCapturer::AddOrUpdateSink(
215 rtc::VideoSinkInterface<VideoFrame>* sink,
216 const rtc::VideoSinkWants& wants) {
217 rtc::CritScope cs(&lock_);
perkj803d97f2016-11-01 11:45:46 -0700218 RTC_CHECK(!sink_ || sink_ == sink);
perkja49cbd32016-09-16 07:53:41 -0700219 sink_ = sink;
perkj803d97f2016-11-01 11:45:46 -0700220 if (sink_wants_observer_)
221 sink_wants_observer_->OnSinkWantsChanged(sink, wants);
sprangc5d62e22017-04-02 23:53:04 -0700222
223 // Handle framerate within this class, just pass on resolution for possible
224 // adaptation.
225 rtc::VideoSinkWants resolution_wants = wants;
226 resolution_wants.max_framerate_fps = std::numeric_limits<int>::max();
227 VideoCapturer::AddOrUpdateSink(sink, resolution_wants);
228
229 // Ignore any requests for framerate higher than initially configured.
230 if (wants.max_framerate_fps < target_fps_) {
231 wanted_fps_.emplace(wants.max_framerate_fps);
232 } else {
233 wanted_fps_.reset();
234 }
perkja49cbd32016-09-16 07:53:41 -0700235}
236
237void FrameGeneratorCapturer::RemoveSink(
238 rtc::VideoSinkInterface<VideoFrame>* sink) {
239 rtc::CritScope cs(&lock_);
240 RTC_CHECK(sink_ == sink);
241 sink_ = nullptr;
242}
243
sprang867fb522015-08-03 04:38:41 -0700244void FrameGeneratorCapturer::ForceFrame() {
ilnikbaded152017-03-17 05:55:25 -0700245 // One-time non-repeating task,
246 // therefore repeat_interval_ms is 0 in InsertFrameTask()
247 task_queue_.PostTask(
248 std::unique_ptr<rtc::QueuedTask>(new InsertFrameTask(this, 0)));
sprang867fb522015-08-03 04:38:41 -0700249}
ilnikbaded152017-03-17 05:55:25 -0700250
sprangc5d62e22017-04-02 23:53:04 -0700251int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() {
252 rtc::CritScope cs(&lock_);
253 if (wanted_fps_ && *wanted_fps_ < target_fps_)
254 return *wanted_fps_;
255 return target_fps_;
256}
257
ilnikbaded152017-03-17 05:55:25 -0700258} // namespace test
259} // namespace webrtc