blob: 58b72db1ab03bdaaf38dabb44c35217ef6f06027 [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
sergeyu10ce97b2015-02-05 23:53:145#include "remoting/host/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 {
22
[email protected]b2bdc102014-08-15 22:23:1623// Interval between empty keep-alive frames. These frames are sent only when the
24// stream is paused or inactive for some other reason (e.g. when blocked on
25// capturer). To prevent PseudoTCP from resetting congestion window this value
26// must be smaller than the minimum RTO used in PseudoTCP, which is 250ms.
[email protected]997a3222014-07-08 06:17:2427static const int kKeepAlivePacketIntervalMs = 200;
[email protected]3e555342014-05-26 04:30:3528
[email protected]3fdfd762014-07-25 00:17:4629static bool g_enable_timestamps = false;
30
sergeyu752c6e62015-09-30 06:40:2731VideoFramePump::FrameTimestamps::FrameTimestamps() {}
32VideoFramePump::FrameTimestamps::~FrameTimestamps() {}
33
34VideoFramePump::PacketWithTimestamps::PacketWithTimestamps(
35 scoped_ptr<VideoPacket> packet,
36 scoped_ptr<FrameTimestamps> timestamps)
37 : packet(packet.Pass()), timestamps(timestamps.Pass()) {}
38
39VideoFramePump::PacketWithTimestamps::~PacketWithTimestamps() {}
40
[email protected]3fdfd762014-07-25 00:17:4641// static
sergeyu10ce97b2015-02-05 23:53:1442void VideoFramePump::EnableTimestampsForTests() {
[email protected]3fdfd762014-07-25 00:17:4643 g_enable_timestamps = true;
44}
45
sergeyu10ce97b2015-02-05 23:53:1446VideoFramePump::VideoFramePump(
[email protected]3c8cfbe72012-07-03 00:24:1547 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner,
[email protected]4e719f42014-08-12 18:04:3748 scoped_ptr<webrtc::DesktopCapturer> capturer,
[email protected]cdd1c9e2012-10-26 21:14:0449 scoped_ptr<VideoEncoder> encoder,
[email protected]324b1962013-05-01 19:30:2250 protocol::VideoStub* video_stub)
sergeyu1afb35a12015-02-13 18:45:3051 : encode_task_runner_(encode_task_runner),
[email protected]324b1962013-05-01 19:30:2252 capturer_(capturer.Pass()),
53 encoder_(encoder.Pass()),
[email protected]324b1962013-05-01 19:30:2254 video_stub_(video_stub),
sergeyu9fa354c2015-02-19 00:39:2555 keep_alive_timer_(
56 FROM_HERE,
57 base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs),
58 base::Bind(&VideoFramePump::SendKeepAlivePacket,
59 base::Unretained(this)),
60 false),
sergeyu1afb35a12015-02-13 18:45:3061 capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame,
62 base::Unretained(this))),
sergeyu1afb35a12015-02-13 18:45:3063 weak_factory_(this) {
[email protected]324b1962013-05-01 19:30:2264 DCHECK(encoder_);
[email protected]324b1962013-05-01 19:30:2265 DCHECK(video_stub_);
[email protected]cb3b1f9312010-06-07 19:58:2366
sergeyu1afb35a12015-02-13 18:45:3067 capturer_->Start(this);
68 capture_scheduler_.Start();
sergeyu91f93b62015-02-05 20:14:3069}
70
sergeyu1afb35a12015-02-13 18:45:3071VideoFramePump::~VideoFramePump() {
72 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release());
sergeyu91f93b62015-02-05 20:14:3073}
74
sergeyu10ce97b2015-02-05 23:53:1475void VideoFramePump::Pause(bool pause) {
sergeyu1afb35a12015-02-13 18:45:3076 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3077
sergeyu1afb35a12015-02-13 18:45:3078 capture_scheduler_.Pause(pause);
sergeyu91f93b62015-02-05 20:14:3079}
80
sergeyu752c6e62015-09-30 06:40:2781void VideoFramePump::OnInputEventReceived(int64_t event_timestamp) {
sergeyu1afb35a12015-02-13 18:45:3082 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3083
sergeyu752c6e62015-09-30 06:40:2784 if (!next_frame_timestamps_)
85 next_frame_timestamps_.reset(new FrameTimestamps());
86 next_frame_timestamps_->input_event_client_timestamp = event_timestamp;
87 next_frame_timestamps_->input_event_received_time = base::TimeTicks::Now();
sergeyu91f93b62015-02-05 20:14:3088}
89
sergeyu10ce97b2015-02-05 23:53:1490void VideoFramePump::SetLosslessEncode(bool want_lossless) {
sergeyu1afb35a12015-02-13 18:45:3091 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3092
93 encode_task_runner_->PostTask(
94 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessEncode,
95 base::Unretained(encoder_.get()), want_lossless));
96}
97
sergeyu10ce97b2015-02-05 23:53:1498void VideoFramePump::SetLosslessColor(bool want_lossless) {
sergeyu1afb35a12015-02-13 18:45:3099 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:30100
101 encode_task_runner_->PostTask(
102 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessColor,
103 base::Unretained(encoder_.get()), want_lossless));
104}
105
sergeyu10ce97b2015-02-05 23:53:14106webrtc::SharedMemory* VideoFramePump::CreateSharedMemory(size_t size) {
sergeyu1afb35a12015-02-13 18:45:30107 DCHECK(thread_checker_.CalledOnValidThread());
sergeyuc5f104b2015-01-09 19:33:24108 return nullptr;
[email protected]b9ed58f2013-05-16 10:45:24109}
110
sergeyu10ce97b2015-02-05 23:53:14111void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
sergeyu1afb35a12015-02-13 18:45:30112 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]489682932012-11-08 19:36:14113
sergeyu1afb35a12015-02-13 18:45:30114 capture_scheduler_.OnCaptureCompleted();
sergeyu91f93b62015-02-05 20:14:30115
sergeyu752c6e62015-09-30 06:40:27116 captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now();
117
sergeyu91f93b62015-02-05 20:14:30118 // Even when |frame| is nullptr we still need to post it to the encode thread
119 // to make sure frames are freed in the same order they are received and
120 // that we don't start capturing frame n+2 before frame n is freed.
121 base::PostTaskAndReplyWithResult(
122 encode_task_runner_.get(), FROM_HERE,
sergeyu752c6e62015-09-30 06:40:27123 base::Bind(&VideoFramePump::EncodeFrame, encoder_.get(),
124 base::Passed(make_scoped_ptr(frame)),
125 base::Passed(&captured_frame_timestamps_)),
126 base::Bind(&VideoFramePump::OnFrameEncoded, weak_factory_.GetWeakPtr()));
sergeyu91f93b62015-02-05 20:14:30127}
128
sergeyu1afb35a12015-02-13 18:45:30129void VideoFramePump::CaptureNextFrame() {
130 DCHECK(thread_checker_.CalledOnValidThread());
131
sergeyu752c6e62015-09-30 06:40:27132 // |next_frame_timestamps_| is not set if no input events were received since
133 // the previous frame. In that case create FrameTimestamps instance without
134 // setting |input_event_client_timestamp| and |input_event_received_time|.
135 if (!next_frame_timestamps_)
136 next_frame_timestamps_.reset(new FrameTimestamps());
137
138 captured_frame_timestamps_ = next_frame_timestamps_.Pass();
139 captured_frame_timestamps_->capture_started_time = base::TimeTicks::Now();
140
sergeyu1afb35a12015-02-13 18:45:30141 capturer_->Capture(webrtc::DesktopRegion());
142}
143
sergeyu752c6e62015-09-30 06:40:27144// static
145scoped_ptr<VideoFramePump::PacketWithTimestamps> VideoFramePump::EncodeFrame(
146 VideoEncoder* encoder,
147 scoped_ptr<webrtc::DesktopFrame> frame,
148 scoped_ptr<FrameTimestamps> timestamps) {
149 timestamps->encode_started_time = base::TimeTicks::Now();
150
151 scoped_ptr<VideoPacket> packet;
152 // If |frame| is non-NULL then let the encoder process it.
153 if (frame)
154 packet = encoder->Encode(*frame);
155
156 // If |frame| is NULL, or the encoder returned nothing, return an empty
157 // packet.
158 if (!packet)
159 packet.reset(new VideoPacket());
160
161 if (frame)
162 packet->set_capture_time_ms(frame->capture_time_ms());
163
164 timestamps->encode_ended_time = base::TimeTicks::Now();
165
166 return make_scoped_ptr(
167 new PacketWithTimestamps(packet.Pass(), timestamps.Pass()));
168}
169
170void VideoFramePump::OnFrameEncoded(scoped_ptr<PacketWithTimestamps> packet) {
sergeyu1afb35a12015-02-13 18:45:30171 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:30172
sergeyu752c6e62015-09-30 06:40:27173 capture_scheduler_.OnFrameEncoded(packet->packet.get());
sergeyu91f93b62015-02-05 20:14:30174
sergeyu752c6e62015-09-30 06:40:27175 if (send_pending_) {
176 pending_packets_.push_back(packet.Pass());
177 } else {
178 SendPacket(packet.Pass());
179 }
180}
sergeyu91f93b62015-02-05 20:14:30181
sergeyu752c6e62015-09-30 06:40:27182void VideoFramePump::SendPacket(scoped_ptr<PacketWithTimestamps> packet) {
183 DCHECK(thread_checker_.CalledOnValidThread());
184 DCHECK(!send_pending_);
sergeyu91f93b62015-02-05 20:14:30185
sergeyu752c6e62015-09-30 06:40:27186 packet->timestamps->can_send_time = base::TimeTicks::Now();
187 UpdateFrameTimers(packet->packet.get(), packet->timestamps.get());
188
189 send_pending_ = true;
190 video_stub_->ProcessVideoPacket(packet->packet.Pass(),
sergeyu1afb35a12015-02-13 18:45:30191 base::Bind(&VideoFramePump::OnVideoPacketSent,
192 weak_factory_.GetWeakPtr()));
[email protected]cb3b1f9312010-06-07 19:58:23193}
194
sergeyu752c6e62015-09-30 06:40:27195void VideoFramePump::UpdateFrameTimers(VideoPacket* packet,
196 FrameTimestamps* timestamps) {
197 if (g_enable_timestamps)
198 packet->set_timestamp(timestamps->capture_ended_time.ToInternalValue());
199
200
201 if (!timestamps->input_event_received_time.is_null()) {
202 packet->set_capture_pending_time_ms((timestamps->capture_started_time -
203 timestamps->input_event_received_time)
204 .InMilliseconds());
205 packet->set_latest_event_timestamp(
206 timestamps->input_event_client_timestamp);
207 }
208
209 packet->set_capture_overhead_time_ms(
210 (timestamps->capture_ended_time - timestamps->capture_started_time)
211 .InMilliseconds() -
212 packet->capture_time_ms());
213
214 packet->set_encode_pending_time_ms(
215 (timestamps->encode_started_time - timestamps->capture_ended_time)
216 .InMilliseconds());
217
218 packet->set_send_pending_time_ms(
219 (timestamps->can_send_time - timestamps->encode_ended_time)
220 .InMilliseconds());
221}
222
sergeyu10ce97b2015-02-05 23:53:14223void VideoFramePump::OnVideoPacketSent() {
sergeyu1afb35a12015-02-13 18:45:30224 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]9302fce2012-03-28 03:57:57225
sergeyu752c6e62015-09-30 06:40:27226 send_pending_ = false;
sergeyu1afb35a12015-02-13 18:45:30227 capture_scheduler_.OnFrameSent();
228 keep_alive_timer_.Reset();
sergeyu752c6e62015-09-30 06:40:27229
230 // Send next packet if any.
231 if (!pending_packets_.empty()) {
232 scoped_ptr<PacketWithTimestamps> next(pending_packets_.front());
233 pending_packets_.weak_erase(pending_packets_.begin());
234 SendPacket(next.Pass());
235 }
[email protected]5bc71832010-12-09 01:34:08236}
237
sergeyu10ce97b2015-02-05 23:53:14238void VideoFramePump::SendKeepAlivePacket() {
sergeyu1afb35a12015-02-13 18:45:30239 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]3e555342014-05-26 04:30:35240
[email protected]3e555342014-05-26 04:30:35241 video_stub_->ProcessVideoPacket(
sergeyu2d690882014-10-01 02:36:43242 make_scoped_ptr(new VideoPacket()),
sergeyu1afb35a12015-02-13 18:45:30243 base::Bind(&VideoFramePump::OnKeepAlivePacketSent,
244 weak_factory_.GetWeakPtr()));
[email protected]3e555342014-05-26 04:30:35245}
246
sergeyu10ce97b2015-02-05 23:53:14247void VideoFramePump::OnKeepAlivePacketSent() {
sergeyu1afb35a12015-02-13 18:45:30248 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]3e555342014-05-26 04:30:35249
sergeyu1afb35a12015-02-13 18:45:30250 keep_alive_timer_.Reset();
[email protected]d65e15bd2012-06-02 22:16:41251}
252
[email protected]cb3b1f9312010-06-07 19:58:23253} // namespace remoting