OLD | NEW |
---|---|
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/protocol/webrtc_video_stream.h" | 5 #include "remoting/protocol/webrtc_video_stream.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/single_thread_task_runner.h" | 8 #include "base/single_thread_task_runner.h" |
9 #include "base/task_runner_util.h" | 9 #include "base/task_runner_util.h" |
10 #include "base/threading/thread_task_runner_handle.h" | 10 #include "base/threading/thread_task_runner_handle.h" |
11 #include "remoting/base/constants.h" | 11 #include "remoting/base/constants.h" |
12 #include "remoting/proto/video.pb.h" | 12 #include "remoting/proto/video.pb.h" |
13 #include "remoting/protocol/frame_stats.h" | |
14 #include "remoting/protocol/host_video_stats_dispatcher.h" | |
13 #include "remoting/protocol/webrtc_dummy_video_capturer.h" | 15 #include "remoting/protocol/webrtc_dummy_video_capturer.h" |
14 #include "remoting/protocol/webrtc_transport.h" | 16 #include "remoting/protocol/webrtc_transport.h" |
15 #include "third_party/webrtc/api/mediastreaminterface.h" | 17 #include "third_party/webrtc/api/mediastreaminterface.h" |
16 #include "third_party/webrtc/api/peerconnectioninterface.h" | 18 #include "third_party/webrtc/api/peerconnectioninterface.h" |
17 #include "third_party/webrtc/api/test/fakeconstraints.h" | 19 #include "third_party/webrtc/api/test/fakeconstraints.h" |
18 #include "third_party/webrtc/media/base/videocapturer.h" | 20 #include "third_party/webrtc/media/base/videocapturer.h" |
19 | 21 |
20 namespace remoting { | 22 namespace remoting { |
21 namespace protocol { | 23 namespace protocol { |
22 | 24 |
23 namespace { | 25 namespace { |
24 | 26 |
25 // Task running on the encoder thread to encode the |frame|. | |
26 std::unique_ptr<VideoPacket> EncodeFrame( | |
27 VideoEncoder* encoder, | |
28 std::unique_ptr<webrtc::DesktopFrame> frame, | |
29 uint32_t target_bitrate_kbps, | |
30 bool key_frame_request, | |
31 int64_t capture_time_ms) { | |
32 uint32_t flags = 0; | |
33 if (key_frame_request) | |
34 flags |= VideoEncoder::REQUEST_KEY_FRAME; | |
35 | |
36 base::TimeTicks current = base::TimeTicks::Now(); | |
37 encoder->UpdateTargetBitrate(target_bitrate_kbps); | |
38 std::unique_ptr<VideoPacket> packet = encoder->Encode(*frame, flags); | |
39 if (!packet) | |
40 return nullptr; | |
41 // TODO(isheriff): Note that while VideoPacket capture time is supposed | |
42 // to be capture duration, we (ab)use it for capture timestamp here. This | |
43 // will go away when we move away from VideoPacket. | |
44 packet->set_capture_time_ms(capture_time_ms); | |
45 | |
46 VLOG(1) << "Encode duration " | |
47 << (base::TimeTicks::Now() - current).InMilliseconds() | |
48 << " payload size " << packet->data().size(); | |
49 return packet; | |
50 } | |
51 | |
52 void PostTaskOnTaskRunner( | 27 void PostTaskOnTaskRunner( |
53 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 28 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
54 const base::Closure& task) { | 29 const base::Closure& task) { |
55 task_runner->PostTask(FROM_HERE, task); | 30 task_runner->PostTask(FROM_HERE, task); |
56 } | 31 } |
57 | 32 |
58 template <typename ParamType> | 33 template <typename ParamType> |
59 void PostTaskOnTaskRunnerWithParam( | 34 void PostTaskOnTaskRunnerWithParam( |
60 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 35 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
61 const base::Callback<void(ParamType param)>& task, | 36 const base::Callback<void(ParamType param)>& task, |
62 ParamType param) { | 37 ParamType param) { |
63 task_runner->PostTask(FROM_HERE, base::Bind(task, param)); | 38 task_runner->PostTask(FROM_HERE, base::Bind(task, param)); |
64 } | 39 } |
65 | 40 |
66 } // namespace | 41 } // namespace |
67 | 42 |
68 const char kStreamLabel[] = "screen_stream"; | 43 const char kStreamLabel[] = "screen_stream"; |
69 const char kVideoLabel[] = "screen_video"; | 44 const char kVideoLabel[] = "screen_video"; |
70 | 45 |
46 struct WebrtcVideoStream::FrameTimestamps { | |
47 // The following two fields are set only for one frame after each incoming | |
48 // input event. |input_event_client_timestamp| is event timestamp | |
49 // received from the client. |input_event_received_time| is local time when | |
50 // the event was received. | |
51 int64_t input_event_client_timestamp = -1; | |
52 base::TimeTicks input_event_received_time; | |
53 | |
54 base::TimeTicks capture_started_time; | |
55 base::TimeTicks capture_ended_time; | |
56 base::TimeDelta capture_delay; | |
57 base::TimeTicks encode_started_time; | |
58 base::TimeTicks encode_ended_time; | |
59 }; | |
60 | |
61 struct WebrtcVideoStream::PacketWithTimestamps { | |
62 std::unique_ptr<VideoPacket> packet; | |
Irfan
2016/08/10 20:58:49
+1 for EncodedVideoFrame
Sergey Ulanov
2016/08/10 22:29:56
Renamed PacketWithTimestamps->EncodedFrameWithTime
| |
63 std::unique_ptr<FrameTimestamps> timestamps; | |
64 }; | |
65 | |
71 WebrtcVideoStream::WebrtcVideoStream() | 66 WebrtcVideoStream::WebrtcVideoStream() |
72 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 67 : video_stats_dispatcher_(kStreamLabel), weak_factory_(this) {} |
73 weak_factory_(this) {} | |
74 | 68 |
75 WebrtcVideoStream::~WebrtcVideoStream() { | 69 WebrtcVideoStream::~WebrtcVideoStream() { |
76 if (stream_) { | 70 if (stream_) { |
77 for (const auto& track : stream_->GetVideoTracks()) { | 71 for (const auto& track : stream_->GetVideoTracks()) { |
78 track->GetSource()->Stop(); | 72 track->GetSource()->Stop(); |
79 stream_->RemoveTrack(track.get()); | 73 stream_->RemoveTrack(track.get()); |
80 } | 74 } |
81 peer_connection_->RemoveStream(stream_.get()); | 75 peer_connection_->RemoveStream(stream_.get()); |
82 } | 76 } |
83 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release()); | 77 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release()); |
(...skipping 13 matching lines...) Expand all Loading... | |
97 scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory( | 91 scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory( |
98 webrtc_transport->peer_connection_factory()); | 92 webrtc_transport->peer_connection_factory()); |
99 peer_connection_ = webrtc_transport->peer_connection(); | 93 peer_connection_ = webrtc_transport->peer_connection(); |
100 DCHECK(peer_connection_factory); | 94 DCHECK(peer_connection_factory); |
101 DCHECK(peer_connection_); | 95 DCHECK(peer_connection_); |
102 | 96 |
103 encode_task_runner_ = encode_task_runner; | 97 encode_task_runner_ = encode_task_runner; |
104 capturer_ = std::move(desktop_capturer); | 98 capturer_ = std::move(desktop_capturer); |
105 webrtc_transport_ = webrtc_transport; | 99 webrtc_transport_ = webrtc_transport; |
106 encoder_ = std::move(video_encoder); | 100 encoder_ = std::move(video_encoder); |
107 capture_timer_.reset(new base::RepeatingTimer()); | |
108 | |
109 capturer_->Start(this); | 101 capturer_->Start(this); |
110 | 102 |
111 // Set video stream constraints. | 103 // Set video stream constraints. |
112 webrtc::FakeConstraints video_constraints; | 104 webrtc::FakeConstraints video_constraints; |
113 video_constraints.AddMandatory( | 105 video_constraints.AddMandatory( |
114 webrtc::MediaConstraintsInterface::kMinFrameRate, 5); | 106 webrtc::MediaConstraintsInterface::kMinFrameRate, 5); |
115 | 107 |
116 rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> src = | 108 rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> src = |
117 peer_connection_factory->CreateVideoSource(new WebrtcDummyVideoCapturer(), | 109 peer_connection_factory->CreateVideoSource(new WebrtcDummyVideoCapturer(), |
118 &video_constraints); | 110 &video_constraints); |
119 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track = | 111 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track = |
120 peer_connection_factory->CreateVideoTrack(kVideoLabel, src); | 112 peer_connection_factory->CreateVideoTrack(kVideoLabel, src); |
121 | 113 |
122 stream_ = peer_connection_factory->CreateLocalMediaStream(kStreamLabel); | 114 stream_ = peer_connection_factory->CreateLocalMediaStream(kStreamLabel); |
123 | 115 |
124 if (!stream_->AddTrack(video_track.get()) || | 116 if (!stream_->AddTrack(video_track.get()) || |
125 !peer_connection_->AddStream(stream_.get())) { | 117 !peer_connection_->AddStream(stream_.get())) { |
126 stream_ = nullptr; | 118 stream_ = nullptr; |
127 peer_connection_ = nullptr; | 119 peer_connection_ = nullptr; |
128 return false; | 120 return false; |
129 } | 121 } |
130 | 122 |
131 // Register for PLI requests. | 123 // Register for PLI requests. |
132 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback( | 124 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback( |
133 base::Bind(&PostTaskOnTaskRunner, main_task_runner_, | 125 base::Bind(&PostTaskOnTaskRunner, base::ThreadTaskRunnerHandle::Get(), |
134 base::Bind(&WebrtcVideoStream::SetKeyFrameRequest, | 126 base::Bind(&WebrtcVideoStream::SetKeyFrameRequest, |
135 weak_factory_.GetWeakPtr()))); | 127 weak_factory_.GetWeakPtr()))); |
136 | 128 |
137 // Register for target bitrate notifications. | 129 // Register for target bitrate notifications. |
138 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback( | 130 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback( |
139 base::Bind(&PostTaskOnTaskRunnerWithParam<int>, main_task_runner_, | 131 base::Bind(&PostTaskOnTaskRunnerWithParam<int>, |
132 base::ThreadTaskRunnerHandle::Get(), | |
140 base::Bind(&WebrtcVideoStream::SetTargetBitrate, | 133 base::Bind(&WebrtcVideoStream::SetTargetBitrate, |
141 weak_factory_.GetWeakPtr()))); | 134 weak_factory_.GetWeakPtr()))); |
142 | 135 |
136 video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel( | |
137 video_stats_dispatcher_.channel_name()), | |
138 this); | |
143 return true; | 139 return true; |
144 } | 140 } |
145 | 141 |
146 void WebrtcVideoStream::Pause(bool pause) { | 142 void WebrtcVideoStream::Pause(bool pause) { |
147 DCHECK(thread_checker_.CalledOnValidThread()); | 143 DCHECK(thread_checker_.CalledOnValidThread()); |
148 if (pause) { | 144 if (pause) { |
149 capture_timer_->Stop(); | 145 capture_timer_.Stop(); |
150 } else { | 146 } else { |
151 if (received_first_frame_request_) { | 147 if (received_first_frame_request_) { |
152 StartCaptureTimer(); | 148 StartCaptureTimer(); |
153 } | 149 } |
154 } | 150 } |
155 } | 151 } |
156 | 152 |
157 void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) { | 153 void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) { |
158 NOTIMPLEMENTED(); | 154 DCHECK(thread_checker_.CalledOnValidThread()); |
155 | |
156 if (!next_frame_timestamps_) | |
157 next_frame_timestamps_.reset(new FrameTimestamps()); | |
158 next_frame_timestamps_->input_event_client_timestamp = event_timestamp; | |
159 next_frame_timestamps_->input_event_received_time = base::TimeTicks::Now(); | |
159 } | 160 } |
160 | 161 |
161 void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) { | 162 void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) { |
162 NOTIMPLEMENTED(); | 163 NOTIMPLEMENTED(); |
163 } | 164 } |
164 | 165 |
165 void WebrtcVideoStream::SetLosslessColor(bool want_lossless) { | 166 void WebrtcVideoStream::SetLosslessColor(bool want_lossless) { |
166 NOTIMPLEMENTED(); | 167 NOTIMPLEMENTED(); |
167 } | 168 } |
168 | 169 |
169 void WebrtcVideoStream::SetObserver(Observer* observer) { | 170 void WebrtcVideoStream::SetObserver(Observer* observer) { |
170 DCHECK(thread_checker_.CalledOnValidThread()); | 171 DCHECK(thread_checker_.CalledOnValidThread()); |
171 observer_ = observer; | 172 observer_ = observer; |
172 } | 173 } |
173 | 174 |
174 void WebrtcVideoStream::SetKeyFrameRequest() { | 175 void WebrtcVideoStream::SetKeyFrameRequest() { |
175 DCHECK(thread_checker_.CalledOnValidThread()); | 176 DCHECK(thread_checker_.CalledOnValidThread()); |
176 | 177 |
177 key_frame_request_ = true; | 178 key_frame_request_ = true; |
178 if (!received_first_frame_request_) { | 179 if (!received_first_frame_request_) { |
179 received_first_frame_request_ = true; | 180 received_first_frame_request_ = true; |
180 StartCaptureTimer(); | 181 StartCaptureTimer(); |
181 main_task_runner_->PostTask( | 182 base::ThreadTaskRunnerHandle::Get()->PostTask( |
182 FROM_HERE, base::Bind(&WebrtcVideoStream::StartCaptureTimer, | 183 FROM_HERE, base::Bind(&WebrtcVideoStream::StartCaptureTimer, |
183 weak_factory_.GetWeakPtr())); | 184 weak_factory_.GetWeakPtr())); |
184 } | 185 } |
185 } | 186 } |
186 | 187 |
187 void WebrtcVideoStream::StartCaptureTimer() { | 188 void WebrtcVideoStream::StartCaptureTimer() { |
188 DCHECK(thread_checker_.CalledOnValidThread()); | 189 DCHECK(thread_checker_.CalledOnValidThread()); |
189 capture_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, | 190 capture_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, |
190 &WebrtcVideoStream::CaptureNextFrame); | 191 &WebrtcVideoStream::CaptureNextFrame); |
191 } | 192 } |
192 | 193 |
193 void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) { | 194 void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) { |
194 DCHECK(thread_checker_.CalledOnValidThread()); | 195 DCHECK(thread_checker_.CalledOnValidThread()); |
195 | 196 |
196 VLOG(1) << "Set Target bitrate " << target_bitrate_kbps; | 197 VLOG(1) << "Set Target bitrate " << target_bitrate_kbps; |
197 target_bitrate_kbps_ = target_bitrate_kbps; | 198 target_bitrate_kbps_ = target_bitrate_kbps; |
198 } | 199 } |
199 | 200 |
200 bool WebrtcVideoStream::ClearAndGetKeyFrameRequest() { | 201 bool WebrtcVideoStream::ClearAndGetKeyFrameRequest() { |
201 DCHECK(thread_checker_.CalledOnValidThread()); | 202 DCHECK(thread_checker_.CalledOnValidThread()); |
202 | 203 |
203 bool key_frame_request = key_frame_request_; | 204 bool key_frame_request = key_frame_request_; |
204 key_frame_request_ = false; | 205 key_frame_request_ = false; |
205 return key_frame_request; | 206 return key_frame_request; |
206 } | 207 } |
207 | 208 |
208 void WebrtcVideoStream::OnCaptureResult( | 209 void WebrtcVideoStream::OnCaptureResult( |
209 webrtc::DesktopCapturer::Result result, | 210 webrtc::DesktopCapturer::Result result, |
210 std::unique_ptr<webrtc::DesktopFrame> frame) { | 211 std::unique_ptr<webrtc::DesktopFrame> frame) { |
211 DCHECK(thread_checker_.CalledOnValidThread()); | 212 DCHECK(thread_checker_.CalledOnValidThread()); |
213 DCHECK(capture_pending_); | |
214 capture_pending_ = false; | |
212 | 215 |
213 base::TimeTicks captured_ticks = base::TimeTicks::Now(); | |
214 int64_t capture_timestamp_ms = | |
215 (captured_ticks - base::TimeTicks()).InMilliseconds(); | |
216 capture_pending_ = false; | |
217 | 216 |
218 if (encode_pending_) { | 217 if (encode_pending_) { |
219 // TODO(isheriff): consider queuing here | 218 // TODO(isheriff): consider queuing here |
220 VLOG(1) << "Dropping captured frame since encoder is still busy"; | 219 VLOG(1) << "Dropping captured frame since encoder is still busy"; |
221 return; | 220 return; |
222 } | 221 } |
223 | 222 |
224 // TODO(sergeyu): Handle ERROR_PERMANENT result here. | 223 // TODO(sergeyu): Handle ERROR_PERMANENT result here. |
225 | 224 |
226 webrtc::DesktopVector dpi = | 225 webrtc::DesktopVector dpi = |
227 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) | 226 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) |
228 : frame->dpi(); | 227 : frame->dpi(); |
229 | 228 |
230 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { | 229 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { |
231 frame_size_ = frame->size(); | 230 frame_size_ = frame->size(); |
232 frame_dpi_ = dpi; | 231 frame_dpi_ = dpi; |
233 if (observer_) | 232 if (observer_) |
234 observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_); | 233 observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_); |
235 } | 234 } |
235 | |
236 captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now(); | |
237 captured_frame_timestamps_->capture_delay = | |
238 base::TimeDelta::FromMilliseconds(frame->capture_time_ms()); | |
239 | |
236 encode_pending_ = true; | 240 encode_pending_ = true; |
237 base::PostTaskAndReplyWithResult( | 241 base::PostTaskAndReplyWithResult( |
238 encode_task_runner_.get(), FROM_HERE, | 242 encode_task_runner_.get(), FROM_HERE, |
239 base::Bind(&EncodeFrame, encoder_.get(), base::Passed(std::move(frame)), | 243 base::Bind(&WebrtcVideoStream::EncodeFrame, encoder_.get(), |
240 target_bitrate_kbps_, ClearAndGetKeyFrameRequest(), | 244 base::Passed(std::move(frame)), |
241 capture_timestamp_ms), | 245 base::Passed(std::move(captured_frame_timestamps_)), |
246 target_bitrate_kbps_, ClearAndGetKeyFrameRequest()), | |
242 base::Bind(&WebrtcVideoStream::OnFrameEncoded, | 247 base::Bind(&WebrtcVideoStream::OnFrameEncoded, |
243 weak_factory_.GetWeakPtr())); | 248 weak_factory_.GetWeakPtr())); |
244 } | 249 } |
245 | 250 |
251 void WebrtcVideoStream::OnChannelInitialized( | |
252 ChannelDispatcherBase* channel_dispatcher) { | |
253 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); | |
254 } | |
255 void WebrtcVideoStream::OnChannelClosed( | |
256 ChannelDispatcherBase* channel_dispatcher) { | |
257 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); | |
258 LOG(WARNING) << "video_stats channel was closed."; | |
259 } | |
260 | |
246 void WebrtcVideoStream::CaptureNextFrame() { | 261 void WebrtcVideoStream::CaptureNextFrame() { |
247 DCHECK(thread_checker_.CalledOnValidThread()); | 262 DCHECK(thread_checker_.CalledOnValidThread()); |
248 | 263 |
249 if (capture_pending_ || encode_pending_) { | 264 if (capture_pending_ || encode_pending_) { |
250 VLOG(1) << "Capture/encode still pending.."; | 265 VLOG(1) << "Capture/encode still pending.."; |
251 return; | 266 return; |
252 } | 267 } |
253 | 268 |
269 base::TimeTicks now = base::TimeTicks::Now(); | |
270 | |
254 capture_pending_ = true; | 271 capture_pending_ = true; |
255 VLOG(1) << "Capture next frame after " | 272 VLOG(1) << "Capture next frame after " |
256 << (base::TimeTicks::Now() - last_capture_started_ticks_) | 273 << (base::TimeTicks::Now() - last_capture_started_ticks_) |
257 .InMilliseconds(); | 274 .InMilliseconds(); |
258 last_capture_started_ticks_ = base::TimeTicks::Now(); | 275 last_capture_started_ticks_ = now; |
276 | |
277 | |
278 // |next_frame_timestamps_| is not set if no input events were received since | |
279 // the previous frame. In that case create FrameTimestamps instance without | |
280 // setting |input_event_client_timestamp| and |input_event_received_time|. | |
281 if (!next_frame_timestamps_) | |
282 next_frame_timestamps_.reset(new FrameTimestamps()); | |
283 | |
284 captured_frame_timestamps_ = std::move(next_frame_timestamps_); | |
285 captured_frame_timestamps_->capture_started_time = now; | |
286 | |
259 capturer_->Capture(webrtc::DesktopRegion()); | 287 capturer_->Capture(webrtc::DesktopRegion()); |
260 } | 288 } |
261 | 289 |
262 void WebrtcVideoStream::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) { | 290 // static |
291 WebrtcVideoStream::PacketWithTimestamps WebrtcVideoStream::EncodeFrame( | |
292 VideoEncoder* encoder, | |
293 std::unique_ptr<webrtc::DesktopFrame> frame, | |
294 std::unique_ptr<WebrtcVideoStream::FrameTimestamps> timestamps, | |
295 uint32_t target_bitrate_kbps, | |
296 bool key_frame_request) { | |
297 PacketWithTimestamps result; | |
298 result.timestamps = std::move(timestamps); | |
299 result.timestamps->encode_started_time = base::TimeTicks::Now(); | |
300 | |
301 encoder->UpdateTargetBitrate(target_bitrate_kbps); | |
302 result.packet = encoder->Encode( | |
303 *frame, key_frame_request ? VideoEncoder::REQUEST_KEY_FRAME : 0); | |
304 | |
305 result.timestamps->encode_ended_time = base::TimeTicks::Now(); | |
306 | |
307 return result; | |
308 } | |
309 | |
310 void WebrtcVideoStream::OnFrameEncoded(PacketWithTimestamps packet) { | |
263 DCHECK(thread_checker_.CalledOnValidThread()); | 311 DCHECK(thread_checker_.CalledOnValidThread()); |
264 | 312 |
265 encode_pending_ = false; | 313 encode_pending_ = false; |
266 if (!packet) | 314 |
267 return; | 315 size_t packet_size = packet.packet ? packet.packet->data().size() : 0; |
268 base::TimeTicks current = base::TimeTicks::Now(); | 316 |
269 float encoded_bits = packet->data().size() * 8.0; | 317 // Generate HostFrameStats. |
318 HostFrameStats stats; | |
319 stats.frame_size = packet_size; | |
320 | |
321 if (!packet.timestamps->input_event_received_time.is_null()) { | |
322 stats.capture_pending_delay = packet.timestamps->capture_started_time - | |
323 packet.timestamps->input_event_received_time; | |
324 stats.latest_event_timestamp = base::TimeTicks::FromInternalValue( | |
325 packet.timestamps->input_event_client_timestamp); | |
326 } | |
327 | |
328 stats.capture_delay = packet.timestamps->capture_delay; | |
329 | |
330 // Total overhead time for IPC and threading when capturing frames. | |
331 stats.capture_overhead_delay = (packet.timestamps->capture_ended_time - | |
332 packet.timestamps->capture_started_time) - | |
333 stats.capture_delay; | |
334 | |
335 stats.encode_pending_delay = packet.timestamps->encode_started_time - | |
336 packet.timestamps->capture_ended_time; | |
337 | |
338 stats.encode_delay = packet.timestamps->encode_ended_time - | |
339 packet.timestamps->encode_started_time; | |
340 | |
341 // TODO(sergeyu): Figure out how to measure send_pending time with WebRTC and | |
342 // set it here. | |
343 stats.send_pending_delay = base::TimeDelta(); | |
344 | |
345 uint32_t frame_id = 0; | |
346 if (packet.packet) { | |
347 // Send the frame itself. | |
348 webrtc::EncodedImageCallback::Result result = | |
349 webrtc_transport_->video_encoder_factory()->SendEncodedFrame( | |
350 std::move(packet.packet), packet.timestamps->capture_started_time); | |
351 if (result.error != webrtc::EncodedImageCallback::Result::OK) { | |
352 // TODO(sergeyu): Stop the stream. | |
353 LOG(ERROR) << "Failed to send video frame."; | |
354 return; | |
355 } | |
356 frame_id = result.frame_id; | |
357 } | |
358 | |
359 // Send FrameStats message. | |
360 if (video_stats_dispatcher_.is_connected()) | |
361 video_stats_dispatcher_.OnVideoFrameStats(frame_id, stats); | |
270 | 362 |
271 // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS. | 363 // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS. |
364 // TODO(sergeyu): Move this logic to a separate class. | |
365 float encoded_bits = packet_size * 8.0; | |
272 uint32_t next_sched_ms = std::max( | 366 uint32_t next_sched_ms = std::max( |
273 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200)); | 367 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200)); |
274 if (webrtc_transport_->video_encoder_factory()->SendEncodedFrame( | 368 capture_timer_.Start(FROM_HERE, |
275 std::move(packet)) >= 0) { | 369 base::TimeDelta::FromMilliseconds(next_sched_ms), this, |
276 VLOG(1) << "Send duration " | 370 &WebrtcVideoStream::CaptureNextFrame); |
277 << (base::TimeTicks::Now() - current).InMilliseconds() | |
278 << ", next sched " << next_sched_ms; | |
279 } else { | |
280 LOG(ERROR) << "SendEncodedFrame() failed"; | |
281 } | |
282 capture_timer_->Start(FROM_HERE, | |
283 base::TimeDelta::FromMilliseconds(next_sched_ms), this, | |
284 &WebrtcVideoStream::CaptureNextFrame); | |
285 } | 371 } |
286 | 372 |
287 } // namespace protocol | 373 } // namespace protocol |
288 } // namespace remoting | 374 } // namespace remoting |
OLD | NEW |