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 base::TimeTicks can_send_time; | |
Irfan
2016/08/09 17:00:37
what is this for ?
Sergey Ulanov
2016/08/10 18:07:44
It wasn't used, removed now.
| |
60 }; | |
61 | |
62 struct WebrtcVideoStream::PacketWithTimestamps { | |
63 std::unique_ptr<VideoPacket> packet; | |
64 std::unique_ptr<FrameTimestamps> timestamps; | |
Irfan
2016/08/09 17:00:37
It would be nice to have a consistency on the nami
Sergey Ulanov
2016/08/10 18:07:45
packet = encoded frame
Calling it VideoFrame would
| |
65 }; | |
66 | |
71 WebrtcVideoStream::WebrtcVideoStream() | 67 WebrtcVideoStream::WebrtcVideoStream() |
72 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 68 : video_stats_dispatcher_(kStreamLabel), weak_factory_(this) {} |
73 weak_factory_(this) {} | |
74 | 69 |
75 WebrtcVideoStream::~WebrtcVideoStream() { | 70 WebrtcVideoStream::~WebrtcVideoStream() { |
76 if (stream_) { | 71 if (stream_) { |
77 for (const auto& track : stream_->GetVideoTracks()) { | 72 for (const auto& track : stream_->GetVideoTracks()) { |
78 track->GetSource()->Stop(); | 73 track->GetSource()->Stop(); |
79 stream_->RemoveTrack(track.get()); | 74 stream_->RemoveTrack(track.get()); |
80 } | 75 } |
81 peer_connection_->RemoveStream(stream_.get()); | 76 peer_connection_->RemoveStream(stream_.get()); |
82 } | 77 } |
83 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release()); | 78 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release()); |
(...skipping 13 matching lines...) Expand all Loading... | |
97 scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory( | 92 scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory( |
98 webrtc_transport->peer_connection_factory()); | 93 webrtc_transport->peer_connection_factory()); |
99 peer_connection_ = webrtc_transport->peer_connection(); | 94 peer_connection_ = webrtc_transport->peer_connection(); |
100 DCHECK(peer_connection_factory); | 95 DCHECK(peer_connection_factory); |
101 DCHECK(peer_connection_); | 96 DCHECK(peer_connection_); |
102 | 97 |
103 encode_task_runner_ = encode_task_runner; | 98 encode_task_runner_ = encode_task_runner; |
104 capturer_ = std::move(desktop_capturer); | 99 capturer_ = std::move(desktop_capturer); |
105 webrtc_transport_ = webrtc_transport; | 100 webrtc_transport_ = webrtc_transport; |
106 encoder_ = std::move(video_encoder); | 101 encoder_ = std::move(video_encoder); |
107 capture_timer_.reset(new base::RepeatingTimer()); | |
108 | |
109 capturer_->Start(this); | 102 capturer_->Start(this); |
110 | 103 |
111 // Set video stream constraints. | 104 // Set video stream constraints. |
112 webrtc::FakeConstraints video_constraints; | 105 webrtc::FakeConstraints video_constraints; |
113 video_constraints.AddMandatory( | 106 video_constraints.AddMandatory( |
114 webrtc::MediaConstraintsInterface::kMinFrameRate, 5); | 107 webrtc::MediaConstraintsInterface::kMinFrameRate, 5); |
115 | 108 |
116 rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> src = | 109 rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> src = |
117 peer_connection_factory->CreateVideoSource(new WebrtcDummyVideoCapturer(), | 110 peer_connection_factory->CreateVideoSource(new WebrtcDummyVideoCapturer(), |
118 &video_constraints); | 111 &video_constraints); |
119 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track = | 112 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track = |
120 peer_connection_factory->CreateVideoTrack(kVideoLabel, src); | 113 peer_connection_factory->CreateVideoTrack(kVideoLabel, src); |
121 | 114 |
122 stream_ = peer_connection_factory->CreateLocalMediaStream(kStreamLabel); | 115 stream_ = peer_connection_factory->CreateLocalMediaStream(kStreamLabel); |
123 | 116 |
124 if (!stream_->AddTrack(video_track.get()) || | 117 if (!stream_->AddTrack(video_track.get()) || |
125 !peer_connection_->AddStream(stream_.get())) { | 118 !peer_connection_->AddStream(stream_.get())) { |
126 stream_ = nullptr; | 119 stream_ = nullptr; |
127 peer_connection_ = nullptr; | 120 peer_connection_ = nullptr; |
128 return false; | 121 return false; |
129 } | 122 } |
130 | 123 |
131 // Register for PLI requests. | 124 // Register for PLI requests. |
132 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback( | 125 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback( |
133 base::Bind(&PostTaskOnTaskRunner, main_task_runner_, | 126 base::Bind(&PostTaskOnTaskRunner, base::ThreadTaskRunnerHandle::Get(), |
134 base::Bind(&WebrtcVideoStream::SetKeyFrameRequest, | 127 base::Bind(&WebrtcVideoStream::SetKeyFrameRequest, |
135 weak_factory_.GetWeakPtr()))); | 128 weak_factory_.GetWeakPtr()))); |
136 | 129 |
137 // Register for target bitrate notifications. | 130 // Register for target bitrate notifications. |
138 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback( | 131 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback( |
139 base::Bind(&PostTaskOnTaskRunnerWithParam<int>, main_task_runner_, | 132 base::Bind(&PostTaskOnTaskRunnerWithParam<int>, |
133 base::ThreadTaskRunnerHandle::Get(), | |
140 base::Bind(&WebrtcVideoStream::SetTargetBitrate, | 134 base::Bind(&WebrtcVideoStream::SetTargetBitrate, |
141 weak_factory_.GetWeakPtr()))); | 135 weak_factory_.GetWeakPtr()))); |
142 | 136 |
137 video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel( | |
138 video_stats_dispatcher_.channel_name()), | |
139 this); | |
143 return true; | 140 return true; |
144 } | 141 } |
145 | 142 |
146 void WebrtcVideoStream::Pause(bool pause) { | 143 void WebrtcVideoStream::Pause(bool pause) { |
147 DCHECK(thread_checker_.CalledOnValidThread()); | 144 DCHECK(thread_checker_.CalledOnValidThread()); |
148 if (pause) { | 145 if (pause) { |
149 capture_timer_->Stop(); | 146 capture_timer_.Stop(); |
150 } else { | 147 } else { |
151 if (received_first_frame_request_) { | 148 if (received_first_frame_request_) { |
152 StartCaptureTimer(); | 149 StartCaptureTimer(); |
153 } | 150 } |
154 } | 151 } |
155 } | 152 } |
156 | 153 |
157 void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) { | 154 void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) { |
158 NOTIMPLEMENTED(); | 155 DCHECK(thread_checker_.CalledOnValidThread()); |
156 | |
157 if (!next_frame_timestamps_) | |
158 next_frame_timestamps_.reset(new FrameTimestamps()); | |
159 next_frame_timestamps_->input_event_client_timestamp = event_timestamp; | |
160 next_frame_timestamps_->input_event_received_time = base::TimeTicks::Now(); | |
159 } | 161 } |
160 | 162 |
161 void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) { | 163 void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) { |
162 NOTIMPLEMENTED(); | 164 NOTIMPLEMENTED(); |
163 } | 165 } |
164 | 166 |
165 void WebrtcVideoStream::SetLosslessColor(bool want_lossless) { | 167 void WebrtcVideoStream::SetLosslessColor(bool want_lossless) { |
166 NOTIMPLEMENTED(); | 168 NOTIMPLEMENTED(); |
167 } | 169 } |
168 | 170 |
169 void WebrtcVideoStream::SetObserver(Observer* observer) { | 171 void WebrtcVideoStream::SetObserver(Observer* observer) { |
170 DCHECK(thread_checker_.CalledOnValidThread()); | 172 DCHECK(thread_checker_.CalledOnValidThread()); |
171 observer_ = observer; | 173 observer_ = observer; |
172 } | 174 } |
173 | 175 |
174 void WebrtcVideoStream::SetKeyFrameRequest() { | 176 void WebrtcVideoStream::SetKeyFrameRequest() { |
175 DCHECK(thread_checker_.CalledOnValidThread()); | 177 DCHECK(thread_checker_.CalledOnValidThread()); |
176 | 178 |
177 key_frame_request_ = true; | 179 key_frame_request_ = true; |
178 if (!received_first_frame_request_) { | 180 if (!received_first_frame_request_) { |
179 received_first_frame_request_ = true; | 181 received_first_frame_request_ = true; |
180 StartCaptureTimer(); | 182 StartCaptureTimer(); |
181 main_task_runner_->PostTask( | 183 base::ThreadTaskRunnerHandle::Get()->PostTask( |
182 FROM_HERE, base::Bind(&WebrtcVideoStream::StartCaptureTimer, | 184 FROM_HERE, base::Bind(&WebrtcVideoStream::StartCaptureTimer, |
183 weak_factory_.GetWeakPtr())); | 185 weak_factory_.GetWeakPtr())); |
184 } | 186 } |
185 } | 187 } |
186 | 188 |
187 void WebrtcVideoStream::StartCaptureTimer() { | 189 void WebrtcVideoStream::StartCaptureTimer() { |
188 DCHECK(thread_checker_.CalledOnValidThread()); | 190 DCHECK(thread_checker_.CalledOnValidThread()); |
189 capture_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, | 191 capture_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, |
190 &WebrtcVideoStream::CaptureNextFrame); | 192 &WebrtcVideoStream::CaptureNextFrame); |
191 } | 193 } |
192 | 194 |
193 void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) { | 195 void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) { |
194 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
195 | 197 |
196 VLOG(1) << "Set Target bitrate " << target_bitrate_kbps; | 198 VLOG(1) << "Set Target bitrate " << target_bitrate_kbps; |
197 target_bitrate_kbps_ = target_bitrate_kbps; | 199 target_bitrate_kbps_ = target_bitrate_kbps; |
198 } | 200 } |
199 | 201 |
200 bool WebrtcVideoStream::ClearAndGetKeyFrameRequest() { | 202 bool WebrtcVideoStream::ClearAndGetKeyFrameRequest() { |
201 DCHECK(thread_checker_.CalledOnValidThread()); | 203 DCHECK(thread_checker_.CalledOnValidThread()); |
202 | 204 |
203 bool key_frame_request = key_frame_request_; | 205 bool key_frame_request = key_frame_request_; |
204 key_frame_request_ = false; | 206 key_frame_request_ = false; |
205 return key_frame_request; | 207 return key_frame_request; |
206 } | 208 } |
207 | 209 |
208 void WebrtcVideoStream::OnCaptureResult( | 210 void WebrtcVideoStream::OnCaptureResult( |
209 webrtc::DesktopCapturer::Result result, | 211 webrtc::DesktopCapturer::Result result, |
210 std::unique_ptr<webrtc::DesktopFrame> frame) { | 212 std::unique_ptr<webrtc::DesktopFrame> frame) { |
211 DCHECK(thread_checker_.CalledOnValidThread()); | 213 DCHECK(thread_checker_.CalledOnValidThread()); |
214 DCHECK(capture_pending_); | |
215 capture_pending_ = false; | |
212 | 216 |
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 | 217 |
218 if (encode_pending_) { | 218 if (encode_pending_) { |
219 // TODO(isheriff): consider queuing here | 219 // TODO(isheriff): consider queuing here |
220 VLOG(1) << "Dropping captured frame since encoder is still busy"; | 220 VLOG(1) << "Dropping captured frame since encoder is still busy"; |
221 return; | 221 return; |
222 } | 222 } |
223 | 223 |
224 // TODO(sergeyu): Handle ERROR_PERMANENT result here. | 224 // TODO(sergeyu): Handle ERROR_PERMANENT result here. |
225 | 225 |
226 webrtc::DesktopVector dpi = | 226 webrtc::DesktopVector dpi = |
227 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) | 227 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) |
228 : frame->dpi(); | 228 : frame->dpi(); |
229 | 229 |
230 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { | 230 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { |
231 frame_size_ = frame->size(); | 231 frame_size_ = frame->size(); |
232 frame_dpi_ = dpi; | 232 frame_dpi_ = dpi; |
233 if (observer_) | 233 if (observer_) |
234 observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_); | 234 observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_); |
235 } | 235 } |
236 | |
237 captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now(); | |
238 captured_frame_timestamps_->capture_delay = | |
239 base::TimeDelta::FromMilliseconds(frame->capture_time_ms()); | |
240 | |
236 encode_pending_ = true; | 241 encode_pending_ = true; |
237 base::PostTaskAndReplyWithResult( | 242 base::PostTaskAndReplyWithResult( |
238 encode_task_runner_.get(), FROM_HERE, | 243 encode_task_runner_.get(), FROM_HERE, |
239 base::Bind(&EncodeFrame, encoder_.get(), base::Passed(std::move(frame)), | 244 base::Bind(&WebrtcVideoStream::EncodeFrame, encoder_.get(), |
240 target_bitrate_kbps_, ClearAndGetKeyFrameRequest(), | 245 base::Passed(std::move(frame)), |
241 capture_timestamp_ms), | 246 base::Passed(std::move(captured_frame_timestamps_)), |
247 target_bitrate_kbps_, ClearAndGetKeyFrameRequest()), | |
242 base::Bind(&WebrtcVideoStream::OnFrameEncoded, | 248 base::Bind(&WebrtcVideoStream::OnFrameEncoded, |
243 weak_factory_.GetWeakPtr())); | 249 weak_factory_.GetWeakPtr())); |
244 } | 250 } |
245 | 251 |
252 void WebrtcVideoStream::OnChannelInitialized( | |
253 ChannelDispatcherBase* channel_dispatcher) { | |
254 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); | |
Irfan
2016/08/09 17:00:37
Are these callbacks helpful ? It sounds like we al
Sergey Ulanov
2016/08/10 18:07:45
OnChannelClosed() is useful if only to log the war
| |
255 } | |
256 void WebrtcVideoStream::OnChannelClosed( | |
257 ChannelDispatcherBase* channel_dispatcher) { | |
258 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); | |
259 LOG(WARNING) << "video_stats channel was closing"; | |
260 } | |
261 | |
246 void WebrtcVideoStream::CaptureNextFrame() { | 262 void WebrtcVideoStream::CaptureNextFrame() { |
247 DCHECK(thread_checker_.CalledOnValidThread()); | 263 DCHECK(thread_checker_.CalledOnValidThread()); |
248 | 264 |
249 if (capture_pending_ || encode_pending_) { | 265 if (capture_pending_ || encode_pending_) { |
250 VLOG(1) << "Capture/encode still pending.."; | 266 VLOG(1) << "Capture/encode still pending.."; |
251 return; | 267 return; |
252 } | 268 } |
253 | 269 |
270 base::TimeTicks now = base::TimeTicks::Now(); | |
271 | |
254 capture_pending_ = true; | 272 capture_pending_ = true; |
255 VLOG(1) << "Capture next frame after " | 273 VLOG(1) << "Capture next frame after " |
256 << (base::TimeTicks::Now() - last_capture_started_ticks_) | 274 << (base::TimeTicks::Now() - last_capture_started_ticks_) |
257 .InMilliseconds(); | 275 .InMilliseconds(); |
258 last_capture_started_ticks_ = base::TimeTicks::Now(); | 276 last_capture_started_ticks_ = now; |
277 | |
278 | |
279 // |next_frame_timestamps_| is not set if no input events were received since | |
280 // the previous frame. In that case create FrameTimestamps instance without | |
281 // setting |input_event_client_timestamp| and |input_event_received_time|. | |
282 if (!next_frame_timestamps_) | |
283 next_frame_timestamps_.reset(new FrameTimestamps()); | |
284 | |
285 captured_frame_timestamps_ = std::move(next_frame_timestamps_); | |
286 captured_frame_timestamps_->capture_started_time = now; | |
287 | |
259 capturer_->Capture(webrtc::DesktopRegion()); | 288 capturer_->Capture(webrtc::DesktopRegion()); |
260 } | 289 } |
261 | 290 |
262 void WebrtcVideoStream::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) { | 291 // static |
292 WebrtcVideoStream::PacketWithTimestamps WebrtcVideoStream::EncodeFrame( | |
293 VideoEncoder* encoder, | |
294 std::unique_ptr<webrtc::DesktopFrame> frame, | |
295 std::unique_ptr<WebrtcVideoStream::FrameTimestamps> timestamps, | |
296 uint32_t target_bitrate_kbps, | |
297 bool key_frame_request) { | |
298 PacketWithTimestamps result; | |
299 result.timestamps = std::move(timestamps); | |
300 result.timestamps->encode_started_time = base::TimeTicks::Now(); | |
301 | |
302 encoder->UpdateTargetBitrate(target_bitrate_kbps); | |
303 result.packet = encoder->Encode( | |
304 *frame, key_frame_request ? VideoEncoder::REQUEST_KEY_FRAME : 0); | |
305 | |
306 result.timestamps->encode_ended_time = base::TimeTicks::Now(); | |
307 | |
308 return result; | |
309 } | |
310 | |
311 void WebrtcVideoStream::OnFrameEncoded(PacketWithTimestamps packet) { | |
263 DCHECK(thread_checker_.CalledOnValidThread()); | 312 DCHECK(thread_checker_.CalledOnValidThread()); |
264 | 313 |
265 encode_pending_ = false; | 314 encode_pending_ = false; |
266 if (!packet) | 315 |
267 return; | 316 size_t packet_size = packet.packet ? packet.packet->data().size() : 0; |
268 base::TimeTicks current = base::TimeTicks::Now(); | 317 |
269 float encoded_bits = packet->data().size() * 8.0; | 318 // Generate HostFrameStats. |
319 HostFrameStats stats; | |
320 stats.frame_size = packet_size; | |
321 stats.latest_event_timestamp = base::TimeTicks::FromInternalValue( | |
322 packet.timestamps->input_event_client_timestamp); | |
323 | |
324 if (!packet.timestamps->input_event_received_time.is_null()) { | |
325 stats.capture_pending_delay = packet.timestamps->capture_started_time - | |
Irfan
2016/08/09 17:00:37
update capture_pending_delay when there is no inpu
Sergey Ulanov
2016/08/10 18:07:45
capture_pending_delay is defined as the delay betw
| |
326 packet.timestamps->input_event_received_time; | |
327 stats.latest_event_timestamp = base::TimeTicks::FromInternalValue( | |
Irfan
2016/08/09 17:00:37
This is duplicated above
Sergey Ulanov
2016/08/10 18:07:45
Removed it from above.
| |
328 packet.timestamps->input_event_client_timestamp); | |
329 } | |
330 | |
331 stats.capture_delay = packet.timestamps->capture_delay; | |
332 stats.capture_overhead_delay = (packet.timestamps->capture_ended_time - | |
Irfan
2016/08/09 17:00:37
Will be helpful to comment what capture_overhead_d
Sergey Ulanov
2016/08/10 18:07:45
Done.
| |
333 packet.timestamps->capture_started_time) - | |
334 stats.capture_delay; | |
335 | |
336 stats.encode_pending_delay = packet.timestamps->encode_started_time - | |
337 packet.timestamps->capture_ended_time; | |
338 | |
339 stats.encode_delay = packet.timestamps->encode_ended_time - | |
340 packet.timestamps->encode_started_time; | |
341 | |
342 // TODO(sergeyu): Figure out how to measure send_pending time with WebRTC and | |
343 // set it here. | |
344 stats.send_pending_delay = base::TimeDelta(); | |
Irfan
2016/08/09 17:00:37
what is send_pending_delay ? How long webrtc waits
Sergey Ulanov
2016/08/10 18:07:45
It may wait if the are other frames in the queue.
| |
345 | |
346 uint32_t frame_id = 0; | |
347 if (packet.packet) { | |
348 // Send the frame itself. | |
349 webrtc::EncodedImageCallback::Result result = | |
350 webrtc_transport_->video_encoder_factory()->SendEncodedFrame( | |
351 std::move(packet.packet), packet.timestamps->capture_started_time); | |
352 if (result.error != webrtc::EncodedImageCallback::Result::OK) { | |
353 // TODO(sergeyu): Stop the stream. | |
354 LOG(ERROR) << "Failed to send video frame."; | |
355 return; | |
356 } | |
357 frame_id = result.frame_id; | |
358 } | |
359 | |
360 // Send FrameStats message. | |
361 if (video_stats_dispatcher_.is_connected()) | |
362 video_stats_dispatcher_.OnVideoFrameStats(frame_id, stats); | |
270 | 363 |
271 // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS. | 364 // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS. |
365 // TODO(sergeyu): Move this logic to a separate class. | |
366 float encoded_bits = packet_size * 8.0; | |
272 uint32_t next_sched_ms = std::max( | 367 uint32_t next_sched_ms = std::max( |
273 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200)); | 368 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200)); |
274 if (webrtc_transport_->video_encoder_factory()->SendEncodedFrame( | 369 capture_timer_.Start(FROM_HERE, |
275 std::move(packet)) >= 0) { | 370 base::TimeDelta::FromMilliseconds(next_sched_ms), this, |
276 VLOG(1) << "Send duration " | 371 &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 } | 372 } |
286 | 373 |
287 } // namespace protocol | 374 } // namespace protocol |
288 } // namespace remoting | 375 } // namespace remoting |
OLD | NEW |