1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/host/video_frame_pump.h"
10 #include "base/callback.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/task_runner_util.h"
15 #include "base/time/time.h"
16 #include "remoting/proto/control.pb.h"
17 #include "remoting/proto/video.pb.h"
18 #include "remoting/protocol/video_stub.h"
19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
25 scoped_ptr
<VideoPacket
> EncodeFrame(VideoEncoder
* encoder
,
26 scoped_ptr
<webrtc::DesktopFrame
> frame
) {
27 scoped_ptr
<VideoPacket
> packet
;
29 // If |frame| is non-NULL then let the encoder process it.
31 packet
= encoder
->Encode(*frame
);
34 // If |frame| is NULL, or the encoder returned nothing, return an empty
37 packet
.reset(new VideoPacket());
45 // Interval between empty keep-alive frames. These frames are sent only when the
46 // stream is paused or inactive for some other reason (e.g. when blocked on
47 // capturer). To prevent PseudoTCP from resetting congestion window this value
48 // must be smaller than the minimum RTO used in PseudoTCP, which is 250ms.
49 static const int kKeepAlivePacketIntervalMs
= 200;
51 static bool g_enable_timestamps
= false;
54 void VideoFramePump::EnableTimestampsForTests() {
55 g_enable_timestamps
= true;
58 VideoFramePump::VideoFramePump(
59 scoped_refptr
<base::SingleThreadTaskRunner
> encode_task_runner
,
60 scoped_ptr
<webrtc::DesktopCapturer
> capturer
,
61 scoped_ptr
<VideoEncoder
> encoder
,
62 protocol::VideoStub
* video_stub
)
63 : encode_task_runner_(encode_task_runner
),
64 capturer_(capturer
.Pass()),
65 encoder_(encoder
.Pass()),
66 video_stub_(video_stub
),
69 base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs
),
70 base::Bind(&VideoFramePump::SendKeepAlivePacket
,
71 base::Unretained(this)),
73 capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame
,
74 base::Unretained(this))),
75 latest_event_timestamp_(0),
80 capturer_
->Start(this);
81 capture_scheduler_
.Start();
84 VideoFramePump::~VideoFramePump() {
85 encode_task_runner_
->DeleteSoon(FROM_HERE
, encoder_
.release());
88 void VideoFramePump::Pause(bool pause
) {
89 DCHECK(thread_checker_
.CalledOnValidThread());
91 capture_scheduler_
.Pause(pause
);
94 void VideoFramePump::SetLatestEventTimestamp(int64 latest_event_timestamp
) {
95 DCHECK(thread_checker_
.CalledOnValidThread());
97 latest_event_timestamp_
= latest_event_timestamp
;
100 void VideoFramePump::SetLosslessEncode(bool want_lossless
) {
101 DCHECK(thread_checker_
.CalledOnValidThread());
103 encode_task_runner_
->PostTask(
104 FROM_HERE
, base::Bind(&VideoEncoder::SetLosslessEncode
,
105 base::Unretained(encoder_
.get()), want_lossless
));
108 void VideoFramePump::SetLosslessColor(bool want_lossless
) {
109 DCHECK(thread_checker_
.CalledOnValidThread());
111 encode_task_runner_
->PostTask(
112 FROM_HERE
, base::Bind(&VideoEncoder::SetLosslessColor
,
113 base::Unretained(encoder_
.get()), want_lossless
));
116 webrtc::SharedMemory
* VideoFramePump::CreateSharedMemory(size_t size
) {
117 DCHECK(thread_checker_
.CalledOnValidThread());
121 void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame
* frame
) {
122 DCHECK(thread_checker_
.CalledOnValidThread());
124 capture_scheduler_
.OnCaptureCompleted();
126 // Even when |frame| is nullptr we still need to post it to the encode thread
127 // to make sure frames are freed in the same order they are received and
128 // that we don't start capturing frame n+2 before frame n is freed.
129 base::PostTaskAndReplyWithResult(
130 encode_task_runner_
.get(), FROM_HERE
,
131 base::Bind(&EncodeFrame
, encoder_
.get(),
132 base::Passed(make_scoped_ptr(frame
))),
133 base::Bind(&VideoFramePump::SendEncodedFrame
, weak_factory_
.GetWeakPtr(),
134 latest_event_timestamp_
, base::TimeTicks::Now()));
137 void VideoFramePump::CaptureNextFrame() {
138 DCHECK(thread_checker_
.CalledOnValidThread());
140 capturer_
->Capture(webrtc::DesktopRegion());
143 void VideoFramePump::SendEncodedFrame(int64 latest_event_timestamp
,
144 base::TimeTicks timestamp
,
145 scoped_ptr
<VideoPacket
> packet
) {
146 DCHECK(thread_checker_
.CalledOnValidThread());
148 if (g_enable_timestamps
)
149 packet
->set_timestamp(timestamp
.ToInternalValue());
151 packet
->set_latest_event_timestamp(latest_event_timestamp
);
153 capture_scheduler_
.OnFrameEncoded(packet
.get());
155 video_stub_
->ProcessVideoPacket(packet
.Pass(),
156 base::Bind(&VideoFramePump::OnVideoPacketSent
,
157 weak_factory_
.GetWeakPtr()));
160 void VideoFramePump::OnVideoPacketSent() {
161 DCHECK(thread_checker_
.CalledOnValidThread());
163 capture_scheduler_
.OnFrameSent();
164 keep_alive_timer_
.Reset();
167 void VideoFramePump::SendKeepAlivePacket() {
168 DCHECK(thread_checker_
.CalledOnValidThread());
170 video_stub_
->ProcessVideoPacket(
171 make_scoped_ptr(new VideoPacket()),
172 base::Bind(&VideoFramePump::OnKeepAlivePacketSent
,
173 weak_factory_
.GetWeakPtr()));
176 void VideoFramePump::OnKeepAlivePacketSent() {
177 DCHECK(thread_checker_
.CalledOnValidThread());
179 keep_alive_timer_
.Reset();
182 } // namespace remoting