blob: 1f11264b786e180eb4e2154a96629600d72a3068 [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
sergeyu91f93b62015-02-05 20:14:3023namespace {
24
25// Helper used to encode frames on the encode thread.
26//
27// TODO(sergeyu): This functions doesn't do much beside calling
28// VideoEncoder::Encode(). It's only needed to handle empty frames properly and
29// that logic can be moved to VideoEncoder implementations.
30scoped_ptr<VideoPacket> EncodeFrame(VideoEncoder* encoder,
31 scoped_ptr<webrtc::DesktopFrame> frame) {
32 // If there is nothing to encode then send an empty packet.
33 if (!frame || frame->updated_region().is_empty())
34 return make_scoped_ptr(new VideoPacket());
35
36 return encoder->Encode(*frame);
37}
38
39} // namespace
[email protected]cb3b1f9312010-06-07 19:58:2340
[email protected]b2bdc102014-08-15 22:23:1641// Interval between empty keep-alive frames. These frames are sent only when the
42// stream is paused or inactive for some other reason (e.g. when blocked on
43// capturer). To prevent PseudoTCP from resetting congestion window this value
44// must be smaller than the minimum RTO used in PseudoTCP, which is 250ms.
[email protected]997a3222014-07-08 06:17:2445static const int kKeepAlivePacketIntervalMs = 200;
[email protected]3e555342014-05-26 04:30:3546
[email protected]3fdfd762014-07-25 00:17:4647static bool g_enable_timestamps = false;
48
49// static
sergeyu10ce97b2015-02-05 23:53:1450void VideoFramePump::EnableTimestampsForTests() {
[email protected]3fdfd762014-07-25 00:17:4651 g_enable_timestamps = true;
52}
53
sergeyu10ce97b2015-02-05 23:53:1454VideoFramePump::VideoFramePump(
[email protected]3c8cfbe72012-07-03 00:24:1555 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner,
[email protected]4e719f42014-08-12 18:04:3756 scoped_ptr<webrtc::DesktopCapturer> capturer,
[email protected]cdd1c9e2012-10-26 21:14:0457 scoped_ptr<VideoEncoder> encoder,
[email protected]324b1962013-05-01 19:30:2258 protocol::VideoStub* video_stub)
sergeyu1afb35a12015-02-13 18:45:3059 : encode_task_runner_(encode_task_runner),
[email protected]324b1962013-05-01 19:30:2260 capturer_(capturer.Pass()),
61 encoder_(encoder.Pass()),
[email protected]324b1962013-05-01 19:30:2262 video_stub_(video_stub),
sergeyu1afb35a12015-02-13 18:45:3063 keep_alive_timer_(true, true),
64 capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame,
65 base::Unretained(this))),
66 latest_event_timestamp_(0),
67 weak_factory_(this) {
[email protected]324b1962013-05-01 19:30:2268 DCHECK(encoder_);
[email protected]324b1962013-05-01 19:30:2269 DCHECK(video_stub_);
[email protected]cb3b1f9312010-06-07 19:58:2370
sergeyu1afb35a12015-02-13 18:45:3071 capturer_->Start(this);
72 capture_scheduler_.Start();
[email protected]3b3d3af2010-07-02 22:23:1773
sergeyu1afb35a12015-02-13 18:45:3074 keep_alive_timer_.Start(
sergeyu91f93b62015-02-05 20:14:3075 FROM_HERE, base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs),
sergeyu1afb35a12015-02-13 18:45:3076 base::Bind(&VideoFramePump::SendKeepAlivePacket, base::Unretained(this)));
sergeyu91f93b62015-02-05 20:14:3077}
78
sergeyu1afb35a12015-02-13 18:45:3079VideoFramePump::~VideoFramePump() {
80 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release());
sergeyu91f93b62015-02-05 20:14:3081}
82
sergeyu10ce97b2015-02-05 23:53:1483void VideoFramePump::Pause(bool pause) {
sergeyu1afb35a12015-02-13 18:45:3084 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3085
sergeyu1afb35a12015-02-13 18:45:3086 capture_scheduler_.Pause(pause);
sergeyu91f93b62015-02-05 20:14:3087}
88
sergeyu10ce97b2015-02-05 23:53:1489void VideoFramePump::SetLatestEventTimestamp(int64 latest_event_timestamp) {
sergeyu1afb35a12015-02-13 18:45:3090 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3091
92 latest_event_timestamp_ = latest_event_timestamp;
93}
94
sergeyu10ce97b2015-02-05 23:53:1495void VideoFramePump::SetLosslessEncode(bool want_lossless) {
sergeyu1afb35a12015-02-13 18:45:3096 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:3097
98 encode_task_runner_->PostTask(
99 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessEncode,
100 base::Unretained(encoder_.get()), want_lossless));
101}
102
sergeyu10ce97b2015-02-05 23:53:14103void VideoFramePump::SetLosslessColor(bool want_lossless) {
sergeyu1afb35a12015-02-13 18:45:30104 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:30105
106 encode_task_runner_->PostTask(
107 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessColor,
108 base::Unretained(encoder_.get()), want_lossless));
109}
110
sergeyu10ce97b2015-02-05 23:53:14111webrtc::SharedMemory* VideoFramePump::CreateSharedMemory(size_t size) {
sergeyu1afb35a12015-02-13 18:45:30112 DCHECK(thread_checker_.CalledOnValidThread());
sergeyuc5f104b2015-01-09 19:33:24113 return nullptr;
[email protected]b9ed58f2013-05-16 10:45:24114}
115
sergeyu10ce97b2015-02-05 23:53:14116void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
sergeyu1afb35a12015-02-13 18:45:30117 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]489682932012-11-08 19:36:14118
sergeyu1afb35a12015-02-13 18:45:30119 capture_scheduler_.OnCaptureCompleted();
sergeyu91f93b62015-02-05 20:14:30120
121 // Even when |frame| is nullptr we still need to post it to the encode thread
122 // to make sure frames are freed in the same order they are received and
123 // that we don't start capturing frame n+2 before frame n is freed.
124 base::PostTaskAndReplyWithResult(
125 encode_task_runner_.get(), FROM_HERE,
sergeyu1afb35a12015-02-13 18:45:30126 base::Bind(&EncodeFrame, encoder_.get(),
127 base::Passed(make_scoped_ptr(frame))),
128 base::Bind(&VideoFramePump::SendEncodedFrame, weak_factory_.GetWeakPtr(),
sergeyu91f93b62015-02-05 20:14:30129 latest_event_timestamp_, base::TimeTicks::Now()));
130}
131
sergeyu1afb35a12015-02-13 18:45:30132void VideoFramePump::CaptureNextFrame() {
133 DCHECK(thread_checker_.CalledOnValidThread());
134
135 capturer_->Capture(webrtc::DesktopRegion());
136}
137
sergeyu10ce97b2015-02-05 23:53:14138void VideoFramePump::SendEncodedFrame(int64 latest_event_timestamp,
sergeyu91f93b62015-02-05 20:14:30139 base::TimeTicks timestamp,
140 scoped_ptr<VideoPacket> packet) {
sergeyu1afb35a12015-02-13 18:45:30141 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu91f93b62015-02-05 20:14:30142
143 if (g_enable_timestamps)
144 packet->set_timestamp(timestamp.ToInternalValue());
145
146 packet->set_latest_event_timestamp(latest_event_timestamp);
147
sergeyu1afb35a12015-02-13 18:45:30148 capture_scheduler_.OnFrameEncoded(
sergeyu91f93b62015-02-05 20:14:30149 base::TimeDelta::FromMilliseconds(packet->encode_time_ms()));
150
sergeyu1afb35a12015-02-13 18:45:30151 video_stub_->ProcessVideoPacket(packet.Pass(),
152 base::Bind(&VideoFramePump::OnVideoPacketSent,
153 weak_factory_.GetWeakPtr()));
[email protected]cb3b1f9312010-06-07 19:58:23154}
155
sergeyu10ce97b2015-02-05 23:53:14156void VideoFramePump::OnVideoPacketSent() {
sergeyu1afb35a12015-02-13 18:45:30157 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]9302fce2012-03-28 03:57:57158
sergeyu1afb35a12015-02-13 18:45:30159 capture_scheduler_.OnFrameSent();
160 keep_alive_timer_.Reset();
[email protected]5bc71832010-12-09 01:34:08161}
162
sergeyu10ce97b2015-02-05 23:53:14163void VideoFramePump::SendKeepAlivePacket() {
sergeyu1afb35a12015-02-13 18:45:30164 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]3e555342014-05-26 04:30:35165
[email protected]3e555342014-05-26 04:30:35166 video_stub_->ProcessVideoPacket(
sergeyu2d690882014-10-01 02:36:43167 make_scoped_ptr(new VideoPacket()),
sergeyu1afb35a12015-02-13 18:45:30168 base::Bind(&VideoFramePump::OnKeepAlivePacketSent,
169 weak_factory_.GetWeakPtr()));
[email protected]3e555342014-05-26 04:30:35170}
171
sergeyu10ce97b2015-02-05 23:53:14172void VideoFramePump::OnKeepAlivePacketSent() {
sergeyu1afb35a12015-02-13 18:45:30173 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]3e555342014-05-26 04:30:35174
sergeyu1afb35a12015-02-13 18:45:30175 keep_alive_timer_.Reset();
[email protected]d65e15bd2012-06-02 22:16:41176}
177
[email protected]cb3b1f9312010-06-07 19:58:23178} // namespace remoting