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 // Helper used to encode frames on the encode thread.
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.
30 scoped_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());
36 return encoder
->Encode(*frame
);
41 // 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.
45 static const int kKeepAlivePacketIntervalMs
= 200;
47 static bool g_enable_timestamps
= false;
50 void VideoFramePump::EnableTimestampsForTests() {
51 g_enable_timestamps
= true;
54 VideoFramePump::VideoFramePump(
55 scoped_refptr
<base::SingleThreadTaskRunner
> encode_task_runner
,
56 scoped_ptr
<webrtc::DesktopCapturer
> capturer
,
57 scoped_ptr
<VideoEncoder
> encoder
,
58 protocol::VideoStub
* video_stub
)
59 : encode_task_runner_(encode_task_runner
),
60 capturer_(capturer
.Pass()),
61 encoder_(encoder
.Pass()),
62 video_stub_(video_stub
),
65 base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs
),
66 base::Bind(&VideoFramePump::SendKeepAlivePacket
,
67 base::Unretained(this)),
69 capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame
,
70 base::Unretained(this))),
71 latest_event_timestamp_(0),
76 capturer_
->Start(this);
77 capture_scheduler_
.Start();
80 VideoFramePump::~VideoFramePump() {
81 encode_task_runner_
->DeleteSoon(FROM_HERE
, encoder_
.release());
84 void VideoFramePump::Pause(bool pause
) {
85 DCHECK(thread_checker_
.CalledOnValidThread());
87 capture_scheduler_
.Pause(pause
);
90 void VideoFramePump::SetLatestEventTimestamp(int64 latest_event_timestamp
) {
91 DCHECK(thread_checker_
.CalledOnValidThread());
93 latest_event_timestamp_
= latest_event_timestamp
;
96 void VideoFramePump::SetLosslessEncode(bool want_lossless
) {
97 DCHECK(thread_checker_
.CalledOnValidThread());
99 encode_task_runner_
->PostTask(
100 FROM_HERE
, base::Bind(&VideoEncoder::SetLosslessEncode
,
101 base::Unretained(encoder_
.get()), want_lossless
));
104 void VideoFramePump::SetLosslessColor(bool want_lossless
) {
105 DCHECK(thread_checker_
.CalledOnValidThread());
107 encode_task_runner_
->PostTask(
108 FROM_HERE
, base::Bind(&VideoEncoder::SetLosslessColor
,
109 base::Unretained(encoder_
.get()), want_lossless
));
112 webrtc::SharedMemory
* VideoFramePump::CreateSharedMemory(size_t size
) {
113 DCHECK(thread_checker_
.CalledOnValidThread());
117 void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame
* frame
) {
118 DCHECK(thread_checker_
.CalledOnValidThread());
120 capture_scheduler_
.OnCaptureCompleted();
122 // Even when |frame| is nullptr we still need to post it to the encode thread
123 // to make sure frames are freed in the same order they are received and
124 // that we don't start capturing frame n+2 before frame n is freed.
125 base::PostTaskAndReplyWithResult(
126 encode_task_runner_
.get(), FROM_HERE
,
127 base::Bind(&EncodeFrame
, encoder_
.get(),
128 base::Passed(make_scoped_ptr(frame
))),
129 base::Bind(&VideoFramePump::SendEncodedFrame
, weak_factory_
.GetWeakPtr(),
130 latest_event_timestamp_
, base::TimeTicks::Now()));
133 void VideoFramePump::CaptureNextFrame() {
134 DCHECK(thread_checker_
.CalledOnValidThread());
136 capturer_
->Capture(webrtc::DesktopRegion());
139 void VideoFramePump::SendEncodedFrame(int64 latest_event_timestamp
,
140 base::TimeTicks timestamp
,
141 scoped_ptr
<VideoPacket
> packet
) {
142 DCHECK(thread_checker_
.CalledOnValidThread());
144 if (g_enable_timestamps
)
145 packet
->set_timestamp(timestamp
.ToInternalValue());
147 packet
->set_latest_event_timestamp(latest_event_timestamp
);
149 capture_scheduler_
.OnFrameEncoded(packet
.get());
151 video_stub_
->ProcessVideoPacket(packet
.Pass(),
152 base::Bind(&VideoFramePump::OnVideoPacketSent
,
153 weak_factory_
.GetWeakPtr()));
156 void VideoFramePump::OnVideoPacketSent() {
157 DCHECK(thread_checker_
.CalledOnValidThread());
159 capture_scheduler_
.OnFrameSent();
160 keep_alive_timer_
.Reset();
163 void VideoFramePump::SendKeepAlivePacket() {
164 DCHECK(thread_checker_
.CalledOnValidThread());
166 video_stub_
->ProcessVideoPacket(
167 make_scoped_ptr(new VideoPacket()),
168 base::Bind(&VideoFramePump::OnKeepAlivePacketSent
,
169 weak_factory_
.GetWeakPtr()));
172 void VideoFramePump::OnKeepAlivePacketSent() {
173 DCHECK(thread_checker_
.CalledOnValidThread());
175 keep_alive_timer_
.Reset();
178 } // namespace remoting