blob: a130a5151b8646487c01a2a347f6bd635cffb535 [file] [log] [blame]
sergeyu10ce97b2015-02-05 23:53:141// Copyright 2015 The Chromium Authors. All rights reserved.
[email protected]cb3b1f9312010-06-07 19:58:232// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
sergeyu4d208002015-11-23 22:27:435#include "remoting/protocol/video_frame_pump.h"
[email protected]cb3b1f9312010-06-07 19:58:236
7#include <algorithm>
8
[email protected]8db2aaae2011-08-12 22:46:119#include "base/bind.h"
[email protected]8ef69222011-12-20 03:12:5410#include "base/callback.h"
[email protected]cb3b1f9312010-06-07 19:58:2311#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1512#include "base/memory/scoped_ptr.h"
sergeyu1afb35a12015-02-13 18:45:3013#include "base/single_thread_task_runner.h"
sergeyu91f93b62015-02-05 20:14:3014#include "base/task_runner_util.h"
[email protected]5d7eb862013-06-28 15:21:2415#include "base/time/time.h"
[email protected]35b9c562010-11-09 02:22:4316#include "remoting/proto/control.pb.h"
[email protected]3adf1b22010-11-09 23:22:2017#include "remoting/proto/video.pb.h"
[email protected]3aef7222013-06-07 22:39:5018#include "remoting/protocol/video_stub.h"
[email protected]b9ed58f2013-05-16 10:45:2419#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
[email protected]cb3b1f9312010-06-07 19:58:2320
21namespace remoting {
sergeyu4d208002015-11-23 22:27:4322namespace protocol {
[email protected]cb3b1f9312010-06-07 19:58:2323
[email protected]b2bdc102014-08-15 22:23:1624// Interval between empty keep-alive frames. These frames are sent only when the
25// stream is paused or inactive for some other reason (e.g. when blocked on
26// capturer). To prevent PseudoTCP from resetting congestion window this value
27// must be smaller than the minimum RTO used in PseudoTCP, which is 250ms.
[email protected]997a3222014-07-08 06:17:2428static const int kKeepAlivePacketIntervalMs = 200;
[email protected]3e555342014-05-26 04:30:3529
[email protected]3fdfd762014-07-25 00:17:4630static bool g_enable_timestamps = false;
31
sergeyu752c6e62015-09-30 06:40:2732VideoFramePump::FrameTimestamps::FrameTimestamps() {}
33VideoFramePump::FrameTimestamps::~FrameTimestamps() {}
34
35VideoFramePump::PacketWithTimestamps::PacketWithTimestamps(
36 scoped_ptr<VideoPacket> packet,
37 scoped_ptr<FrameTimestamps> timestamps)
sergeyuaa6fa2342015-12-22 23:26:4838 : packet(std::move(packet)), timestamps(std::move(timestamps)) {}
sergeyu752c6e62015-09-30 06:40:2739
40VideoFramePump::PacketWithTimestamps::~PacketWithTimestamps() {}
41
[email protected]3fdfd762014-07-25 00:17:4642// static
sergeyu10ce97b2015-02-05 23:53:1443void VideoFramePump::EnableTimestampsForTests() {
[email protected]3fdfd762014-07-25 00:17:4644 g_enable_timestamps = true;
45}
46
sergeyu10ce97b2015-02-05 23:53:1447VideoFramePump::VideoFramePump(
[email protected]3c8cfbe72012-07-03 00:24:1548 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner,
[email protected]4e719f42014-08-12 18:04:3749 scoped_ptr<webrtc::DesktopCapturer> capturer,
[email protected]cdd1c9e2012-10-26 21:14:0450 scoped_ptr<VideoEncoder> encoder,
[email protected]324b1962013-05-01 19:30:2251 protocol::VideoStub* video_stub)
sergeyu1afb35a12015-02-13 18:45:3052 : encode_task_runner_(encode_task_runner),
sergeyuaa6fa2342015-12-22 23:26:4853 capturer_(std::move(capturer)),
54 encoder_(std::move(encoder)),
[email protected]324b1962013-05-01 19:30:2255 video_stub_(video_stub),
sergeyu9fa354c2015-02-19 00:39:2556 keep_alive_timer_(
57 FROM_HERE,
58 base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs),
59 base::Bind(&VideoFramePump::SendKeepAlivePacket,
60 base::Unretained(this)),
61 false),
sergeyu1afb35a12015-02-13 18:45:3062 capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame,
63 base::Unretained(this))),
sergeyu1afb35a12015-02-13 18:45:3064 weak_factory_(this) {
[email protected]324b1962013-05-01 19:30:2265 DCHECK(encoder_);
[email protected]324b1962013-05-01 19:30:2266 DCHECK(video_stub_);
[email protected]cb3b1f9312010-06-07 19:58:2367
sergeyu1afb35a12015-02-13 18:45:3068 capturer_->Start(this);
69 capture_scheduler_.Start();
sergeyu91f93b62015-02-05 20:14:3070}
71
sergeyu1afb35a12015-02-13 18:45:3072VideoFramePump::~VideoFramePump() {
73 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release());
sergeyu91f93b62015-02-05 20:14:3074}
75
sergeyu10ce97b2015-02-05 23:53:1476void VideoFramePump::Pause(bool pause) {
sergeyu1afb35a12015-02-13 18:45:3077 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3078
sergeyu1afb35a12015-02-13 18:45:3079 capture_scheduler_.Pause(pause);
sergeyu91f93b62015-02-05 20:14:3080}
81
sergeyu752c6e62015-09-30 06:40:2782void VideoFramePump::OnInputEventReceived(int64_t event_timestamp) {
sergeyu1afb35a12015-02-13 18:45:3083 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3084
sergeyu752c6e62015-09-30 06:40:2785 if (!next_frame_timestamps_)
86 next_frame_timestamps_.reset(new FrameTimestamps());
87 next_frame_timestamps_->input_event_client_timestamp = event_timestamp;
88 next_frame_timestamps_->input_event_received_time = base::TimeTicks::Now();
sergeyu91f93b62015-02-05 20:14:3089}
90
sergeyu10ce97b2015-02-05 23:53:1491void VideoFramePump::SetLosslessEncode(bool want_lossless) {
sergeyu1afb35a12015-02-13 18:45:3092 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3093
94 encode_task_runner_->PostTask(
95 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessEncode,
96 base::Unretained(encoder_.get()), want_lossless));
97}
98
sergeyu10ce97b2015-02-05 23:53:1499void VideoFramePump::SetLosslessColor(bool want_lossless) {
sergeyu1afb35a12015-02-13 18:45:30100 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:30101
102 encode_task_runner_->PostTask(
103 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessColor,
104 base::Unretained(encoder_.get()), want_lossless));
105}
106
sergeyua609b7a2015-11-30 06:25:39107void VideoFramePump::SetSizeCallback(const SizeCallback& size_callback) {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 size_callback_ = size_callback;
110}
111
sergeyu10ce97b2015-02-05 23:53:14112webrtc::SharedMemory* VideoFramePump::CreateSharedMemory(size_t size) {
sergeyu1afb35a12015-02-13 18:45:30113 DCHECK(thread_checker_.CalledOnValidThread());
sergeyuc5f104b2015-01-09 19:33:24114 return nullptr;
[email protected]b9ed58f2013-05-16 10:45:24115}
116
sergeyu10ce97b2015-02-05 23:53:14117void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
sergeyu1afb35a12015-02-13 18:45:30118 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]489682932012-11-08 19:36:14119
sergeyu1afb35a12015-02-13 18:45:30120 capture_scheduler_.OnCaptureCompleted();
sergeyu91f93b62015-02-05 20:14:30121
sergeyu752c6e62015-09-30 06:40:27122 captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now();
123
sergeyua609b7a2015-11-30 06:25:39124 if (frame && !frame_size_.equals(frame->size())) {
125 frame_size_ = frame->size();
126 if (!size_callback_.is_null())
127 size_callback_.Run(frame_size_);
128 }
129
sergeyu91f93b62015-02-05 20:14:30130 // Even when |frame| is nullptr we still need to post it to the encode thread
131 // to make sure frames are freed in the same order they are received and
132 // that we don't start capturing frame n+2 before frame n is freed.
133 base::PostTaskAndReplyWithResult(
134 encode_task_runner_.get(), FROM_HERE,
sergeyu752c6e62015-09-30 06:40:27135 base::Bind(&VideoFramePump::EncodeFrame, encoder_.get(),
136 base::Passed(make_scoped_ptr(frame)),
137 base::Passed(&captured_frame_timestamps_)),
138 base::Bind(&VideoFramePump::OnFrameEncoded, weak_factory_.GetWeakPtr()));
sergeyu91f93b62015-02-05 20:14:30139}
140
sergeyu1afb35a12015-02-13 18:45:30141void VideoFramePump::CaptureNextFrame() {
142 DCHECK(thread_checker_.CalledOnValidThread());
143
sergeyu752c6e62015-09-30 06:40:27144 // |next_frame_timestamps_| is not set if no input events were received since
145 // the previous frame. In that case create FrameTimestamps instance without
146 // setting |input_event_client_timestamp| and |input_event_received_time|.
147 if (!next_frame_timestamps_)
148 next_frame_timestamps_.reset(new FrameTimestamps());
149
sergeyuaa6fa2342015-12-22 23:26:48150 captured_frame_timestamps_ = std::move(next_frame_timestamps_);
sergeyu752c6e62015-09-30 06:40:27151 captured_frame_timestamps_->capture_started_time = base::TimeTicks::Now();
152
sergeyu1afb35a12015-02-13 18:45:30153 capturer_->Capture(webrtc::DesktopRegion());
154}
155
sergeyu752c6e62015-09-30 06:40:27156// static
157scoped_ptr<VideoFramePump::PacketWithTimestamps> VideoFramePump::EncodeFrame(
158 VideoEncoder* encoder,
159 scoped_ptr<webrtc::DesktopFrame> frame,
160 scoped_ptr<FrameTimestamps> timestamps) {
161 timestamps->encode_started_time = base::TimeTicks::Now();
162
163 scoped_ptr<VideoPacket> packet;
164 // If |frame| is non-NULL then let the encoder process it.
165 if (frame)
166 packet = encoder->Encode(*frame);
167
168 // If |frame| is NULL, or the encoder returned nothing, return an empty
169 // packet.
170 if (!packet)
171 packet.reset(new VideoPacket());
172
173 if (frame)
174 packet->set_capture_time_ms(frame->capture_time_ms());
175
176 timestamps->encode_ended_time = base::TimeTicks::Now();
anandc6928da072015-10-31 01:33:49177 packet->set_encode_time_ms(
178 (timestamps->encode_ended_time - timestamps->encode_started_time)
179 .InMilliseconds());
sergeyu752c6e62015-09-30 06:40:27180
181 return make_scoped_ptr(
sergeyuaa6fa2342015-12-22 23:26:48182 new PacketWithTimestamps(std::move(packet), std::move(timestamps)));
sergeyu752c6e62015-09-30 06:40:27183}
184
185void VideoFramePump::OnFrameEncoded(scoped_ptr<PacketWithTimestamps> packet) {
sergeyu1afb35a12015-02-13 18:45:30186 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:30187
sergeyu752c6e62015-09-30 06:40:27188 capture_scheduler_.OnFrameEncoded(packet->packet.get());
sergeyu91f93b62015-02-05 20:14:30189
sergeyu752c6e62015-09-30 06:40:27190 if (send_pending_) {
sergeyuaa6fa2342015-12-22 23:26:48191 pending_packets_.push_back(std::move(packet));
sergeyu752c6e62015-09-30 06:40:27192 } else {
sergeyuaa6fa2342015-12-22 23:26:48193 SendPacket(std::move(packet));
sergeyu752c6e62015-09-30 06:40:27194 }
195}
sergeyu91f93b62015-02-05 20:14:30196
sergeyu752c6e62015-09-30 06:40:27197void VideoFramePump::SendPacket(scoped_ptr<PacketWithTimestamps> packet) {
198 DCHECK(thread_checker_.CalledOnValidThread());
199 DCHECK(!send_pending_);
sergeyu91f93b62015-02-05 20:14:30200
sergeyu752c6e62015-09-30 06:40:27201 packet->timestamps->can_send_time = base::TimeTicks::Now();
202 UpdateFrameTimers(packet->packet.get(), packet->timestamps.get());
203
204 send_pending_ = true;
sergeyuaa6fa2342015-12-22 23:26:48205 video_stub_->ProcessVideoPacket(std::move(packet->packet),
sergeyu1afb35a12015-02-13 18:45:30206 base::Bind(&VideoFramePump::OnVideoPacketSent,
207 weak_factory_.GetWeakPtr()));
[email protected]cb3b1f9312010-06-07 19:58:23208}
209
sergeyu752c6e62015-09-30 06:40:27210void VideoFramePump::UpdateFrameTimers(VideoPacket* packet,
211 FrameTimestamps* timestamps) {
212 if (g_enable_timestamps)
213 packet->set_timestamp(timestamps->capture_ended_time.ToInternalValue());
214
215
216 if (!timestamps->input_event_received_time.is_null()) {
217 packet->set_capture_pending_time_ms((timestamps->capture_started_time -
218 timestamps->input_event_received_time)
219 .InMilliseconds());
220 packet->set_latest_event_timestamp(
221 timestamps->input_event_client_timestamp);
222 }
223
224 packet->set_capture_overhead_time_ms(
225 (timestamps->capture_ended_time - timestamps->capture_started_time)
226 .InMilliseconds() -
227 packet->capture_time_ms());
228
229 packet->set_encode_pending_time_ms(
230 (timestamps->encode_started_time - timestamps->capture_ended_time)
231 .InMilliseconds());
232
233 packet->set_send_pending_time_ms(
234 (timestamps->can_send_time - timestamps->encode_ended_time)
235 .InMilliseconds());
236}
237
sergeyu10ce97b2015-02-05 23:53:14238void VideoFramePump::OnVideoPacketSent() {
sergeyu1afb35a12015-02-13 18:45:30239 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]9302fce2012-03-28 03:57:57240
sergeyu752c6e62015-09-30 06:40:27241 send_pending_ = false;
sergeyu1afb35a12015-02-13 18:45:30242 capture_scheduler_.OnFrameSent();
243 keep_alive_timer_.Reset();
sergeyu752c6e62015-09-30 06:40:27244
245 // Send next packet if any.
246 if (!pending_packets_.empty()) {
247 scoped_ptr<PacketWithTimestamps> next(pending_packets_.front());
248 pending_packets_.weak_erase(pending_packets_.begin());
sergeyuaa6fa2342015-12-22 23:26:48249 SendPacket(std::move(next));
sergeyu752c6e62015-09-30 06:40:27250 }
[email protected]5bc71832010-12-09 01:34:08251}
252
sergeyu10ce97b2015-02-05 23:53:14253void VideoFramePump::SendKeepAlivePacket() {
sergeyu1afb35a12015-02-13 18:45:30254 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]3e555342014-05-26 04:30:35255
[email protected]3e555342014-05-26 04:30:35256 video_stub_->ProcessVideoPacket(
sergeyu2d690882014-10-01 02:36:43257 make_scoped_ptr(new VideoPacket()),
sergeyu1afb35a12015-02-13 18:45:30258 base::Bind(&VideoFramePump::OnKeepAlivePacketSent,
259 weak_factory_.GetWeakPtr()));
[email protected]3e555342014-05-26 04:30:35260}
261
sergeyu10ce97b2015-02-05 23:53:14262void VideoFramePump::OnKeepAlivePacketSent() {
sergeyu1afb35a12015-02-13 18:45:30263 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]3e555342014-05-26 04:30:35264
sergeyu1afb35a12015-02-13 18:45:30265 keep_alive_timer_.Reset();
[email protected]d65e15bd2012-06-02 22:16:41266}
267
sergeyu4d208002015-11-23 22:27:43268} // namespace protocol
[email protected]cb3b1f9312010-06-07 19:58:23269} // namespace remoting