Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(371)

Side by Side Diff: remoting/host/video_frame_pump.cc

Issue 1365663003: Add UMA histograms for more detailed latency tracking on the CRD host. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed tests Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/host/video_frame_pump.h ('k') | remoting/proto/video.proto » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/video_frame_pump.h" 5 #include "remoting/host/video_frame_pump.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
13 #include "base/single_thread_task_runner.h" 13 #include "base/single_thread_task_runner.h"
14 #include "base/task_runner_util.h" 14 #include "base/task_runner_util.h"
15 #include "base/time/time.h" 15 #include "base/time/time.h"
16 #include "remoting/proto/control.pb.h" 16 #include "remoting/proto/control.pb.h"
17 #include "remoting/proto/video.pb.h" 17 #include "remoting/proto/video.pb.h"
18 #include "remoting/protocol/video_stub.h" 18 #include "remoting/protocol/video_stub.h"
19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
20 20
21 namespace remoting { 21 namespace remoting {
22 22
23 namespace {
24
25 scoped_ptr<VideoPacket> EncodeFrame(VideoEncoder* encoder,
26 scoped_ptr<webrtc::DesktopFrame> frame) {
27 scoped_ptr<VideoPacket> packet;
28
29 // If |frame| is non-NULL then let the encoder process it.
30 if (frame) {
31 packet = encoder->Encode(*frame);
32 }
33
34 // If |frame| is NULL, or the encoder returned nothing, return an empty
35 // packet.
36 if (!packet) {
37 packet.reset(new VideoPacket());
38 }
39
40 return packet.Pass();
41 }
42
43 } // namespace
44
45 // Interval between empty keep-alive frames. These frames are sent only when the 23 // 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 24 // 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 25 // capturer). To prevent PseudoTCP from resetting congestion window this value
48 // must be smaller than the minimum RTO used in PseudoTCP, which is 250ms. 26 // must be smaller than the minimum RTO used in PseudoTCP, which is 250ms.
49 static const int kKeepAlivePacketIntervalMs = 200; 27 static const int kKeepAlivePacketIntervalMs = 200;
50 28
51 static bool g_enable_timestamps = false; 29 static bool g_enable_timestamps = false;
52 30
31 VideoFramePump::FrameTimestamps::FrameTimestamps() {}
32 VideoFramePump::FrameTimestamps::~FrameTimestamps() {}
33
34 VideoFramePump::PacketWithTimestamps::PacketWithTimestamps(
35 scoped_ptr<VideoPacket> packet,
36 scoped_ptr<FrameTimestamps> timestamps)
37 : packet(packet.Pass()), timestamps(timestamps.Pass()) {}
38
39 VideoFramePump::PacketWithTimestamps::~PacketWithTimestamps() {}
40
53 // static 41 // static
54 void VideoFramePump::EnableTimestampsForTests() { 42 void VideoFramePump::EnableTimestampsForTests() {
55 g_enable_timestamps = true; 43 g_enable_timestamps = true;
56 } 44 }
57 45
58 VideoFramePump::VideoFramePump( 46 VideoFramePump::VideoFramePump(
59 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, 47 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner,
60 scoped_ptr<webrtc::DesktopCapturer> capturer, 48 scoped_ptr<webrtc::DesktopCapturer> capturer,
61 scoped_ptr<VideoEncoder> encoder, 49 scoped_ptr<VideoEncoder> encoder,
62 protocol::VideoStub* video_stub) 50 protocol::VideoStub* video_stub)
63 : encode_task_runner_(encode_task_runner), 51 : encode_task_runner_(encode_task_runner),
64 capturer_(capturer.Pass()), 52 capturer_(capturer.Pass()),
65 encoder_(encoder.Pass()), 53 encoder_(encoder.Pass()),
66 video_stub_(video_stub), 54 video_stub_(video_stub),
67 keep_alive_timer_( 55 keep_alive_timer_(
68 FROM_HERE, 56 FROM_HERE,
69 base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs), 57 base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs),
70 base::Bind(&VideoFramePump::SendKeepAlivePacket, 58 base::Bind(&VideoFramePump::SendKeepAlivePacket,
71 base::Unretained(this)), 59 base::Unretained(this)),
72 false), 60 false),
73 capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame, 61 capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame,
74 base::Unretained(this))), 62 base::Unretained(this))),
75 latest_event_timestamp_(0),
76 weak_factory_(this) { 63 weak_factory_(this) {
77 DCHECK(encoder_); 64 DCHECK(encoder_);
78 DCHECK(video_stub_); 65 DCHECK(video_stub_);
79 66
80 capturer_->Start(this); 67 capturer_->Start(this);
81 capture_scheduler_.Start(); 68 capture_scheduler_.Start();
82 } 69 }
83 70
84 VideoFramePump::~VideoFramePump() { 71 VideoFramePump::~VideoFramePump() {
85 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release()); 72 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release());
86 } 73 }
87 74
88 void VideoFramePump::Pause(bool pause) { 75 void VideoFramePump::Pause(bool pause) {
89 DCHECK(thread_checker_.CalledOnValidThread()); 76 DCHECK(thread_checker_.CalledOnValidThread());
90 77
91 capture_scheduler_.Pause(pause); 78 capture_scheduler_.Pause(pause);
92 } 79 }
93 80
94 void VideoFramePump::SetLatestEventTimestamp(int64 latest_event_timestamp) { 81 void VideoFramePump::OnInputEventReceived(int64_t event_timestamp) {
95 DCHECK(thread_checker_.CalledOnValidThread()); 82 DCHECK(thread_checker_.CalledOnValidThread());
96 83
97 latest_event_timestamp_ = latest_event_timestamp; 84 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();
98 } 88 }
99 89
100 void VideoFramePump::SetLosslessEncode(bool want_lossless) { 90 void VideoFramePump::SetLosslessEncode(bool want_lossless) {
101 DCHECK(thread_checker_.CalledOnValidThread()); 91 DCHECK(thread_checker_.CalledOnValidThread());
102 92
103 encode_task_runner_->PostTask( 93 encode_task_runner_->PostTask(
104 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessEncode, 94 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessEncode,
105 base::Unretained(encoder_.get()), want_lossless)); 95 base::Unretained(encoder_.get()), want_lossless));
106 } 96 }
107 97
108 void VideoFramePump::SetLosslessColor(bool want_lossless) { 98 void VideoFramePump::SetLosslessColor(bool want_lossless) {
109 DCHECK(thread_checker_.CalledOnValidThread()); 99 DCHECK(thread_checker_.CalledOnValidThread());
110 100
111 encode_task_runner_->PostTask( 101 encode_task_runner_->PostTask(
112 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessColor, 102 FROM_HERE, base::Bind(&VideoEncoder::SetLosslessColor,
113 base::Unretained(encoder_.get()), want_lossless)); 103 base::Unretained(encoder_.get()), want_lossless));
114 } 104 }
115 105
116 webrtc::SharedMemory* VideoFramePump::CreateSharedMemory(size_t size) { 106 webrtc::SharedMemory* VideoFramePump::CreateSharedMemory(size_t size) {
117 DCHECK(thread_checker_.CalledOnValidThread()); 107 DCHECK(thread_checker_.CalledOnValidThread());
118 return nullptr; 108 return nullptr;
119 } 109 }
120 110
121 void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame* frame) { 111 void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
122 DCHECK(thread_checker_.CalledOnValidThread()); 112 DCHECK(thread_checker_.CalledOnValidThread());
123 113
124 capture_scheduler_.OnCaptureCompleted(); 114 capture_scheduler_.OnCaptureCompleted();
125 115
116 captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now();
117
126 // Even when |frame| is nullptr we still need to post it to the encode thread 118 // 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 119 // 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. 120 // that we don't start capturing frame n+2 before frame n is freed.
129 base::PostTaskAndReplyWithResult( 121 base::PostTaskAndReplyWithResult(
130 encode_task_runner_.get(), FROM_HERE, 122 encode_task_runner_.get(), FROM_HERE,
131 base::Bind(&EncodeFrame, encoder_.get(), 123 base::Bind(&VideoFramePump::EncodeFrame, encoder_.get(),
132 base::Passed(make_scoped_ptr(frame))), 124 base::Passed(make_scoped_ptr(frame)),
133 base::Bind(&VideoFramePump::SendEncodedFrame, weak_factory_.GetWeakPtr(), 125 base::Passed(&captured_frame_timestamps_)),
134 latest_event_timestamp_, base::TimeTicks::Now())); 126 base::Bind(&VideoFramePump::OnFrameEncoded, weak_factory_.GetWeakPtr()));
135 } 127 }
136 128
137 void VideoFramePump::CaptureNextFrame() { 129 void VideoFramePump::CaptureNextFrame() {
138 DCHECK(thread_checker_.CalledOnValidThread()); 130 DCHECK(thread_checker_.CalledOnValidThread());
139 131
132 // |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
140 capturer_->Capture(webrtc::DesktopRegion()); 141 capturer_->Capture(webrtc::DesktopRegion());
141 } 142 }
142 143
143 void VideoFramePump::SendEncodedFrame(int64 latest_event_timestamp, 144 // static
144 base::TimeTicks timestamp, 145 scoped_ptr<VideoFramePump::PacketWithTimestamps> VideoFramePump::EncodeFrame(
145 scoped_ptr<VideoPacket> packet) { 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
170 void VideoFramePump::OnFrameEncoded(scoped_ptr<PacketWithTimestamps> packet) {
146 DCHECK(thread_checker_.CalledOnValidThread()); 171 DCHECK(thread_checker_.CalledOnValidThread());
147 172
148 if (g_enable_timestamps) 173 capture_scheduler_.OnFrameEncoded(packet->packet.get());
149 packet->set_timestamp(timestamp.ToInternalValue());
150 174
151 packet->set_latest_event_timestamp(latest_event_timestamp); 175 if (send_pending_) {
176 pending_packets_.push_back(packet.Pass());
177 } else {
178 SendPacket(packet.Pass());
179 }
180 }
152 181
153 capture_scheduler_.OnFrameEncoded(packet.get()); 182 void VideoFramePump::SendPacket(scoped_ptr<PacketWithTimestamps> packet) {
183 DCHECK(thread_checker_.CalledOnValidThread());
184 DCHECK(!send_pending_);
154 185
155 video_stub_->ProcessVideoPacket(packet.Pass(), 186 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(),
156 base::Bind(&VideoFramePump::OnVideoPacketSent, 191 base::Bind(&VideoFramePump::OnVideoPacketSent,
157 weak_factory_.GetWeakPtr())); 192 weak_factory_.GetWeakPtr()));
158 } 193 }
159 194
195 void 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
160 void VideoFramePump::OnVideoPacketSent() { 223 void VideoFramePump::OnVideoPacketSent() {
161 DCHECK(thread_checker_.CalledOnValidThread()); 224 DCHECK(thread_checker_.CalledOnValidThread());
162 225
226 send_pending_ = false;
163 capture_scheduler_.OnFrameSent(); 227 capture_scheduler_.OnFrameSent();
164 keep_alive_timer_.Reset(); 228 keep_alive_timer_.Reset();
229
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 }
165 } 236 }
166 237
167 void VideoFramePump::SendKeepAlivePacket() { 238 void VideoFramePump::SendKeepAlivePacket() {
168 DCHECK(thread_checker_.CalledOnValidThread()); 239 DCHECK(thread_checker_.CalledOnValidThread());
169 240
170 video_stub_->ProcessVideoPacket( 241 video_stub_->ProcessVideoPacket(
171 make_scoped_ptr(new VideoPacket()), 242 make_scoped_ptr(new VideoPacket()),
172 base::Bind(&VideoFramePump::OnKeepAlivePacketSent, 243 base::Bind(&VideoFramePump::OnKeepAlivePacketSent,
173 weak_factory_.GetWeakPtr())); 244 weak_factory_.GetWeakPtr()));
174 } 245 }
175 246
176 void VideoFramePump::OnKeepAlivePacketSent() { 247 void VideoFramePump::OnKeepAlivePacketSent() {
177 DCHECK(thread_checker_.CalledOnValidThread()); 248 DCHECK(thread_checker_.CalledOnValidThread());
178 249
179 keep_alive_timer_.Reset(); 250 keep_alive_timer_.Reset();
180 } 251 }
181 252
182 } // namespace remoting 253 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/video_frame_pump.h ('k') | remoting/proto/video.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698