| 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/codec/webrtc_video_encoder_vpx.h" | 12 #include "remoting/codec/webrtc_video_encoder_vpx.h" |
| 13 #include "remoting/protocol/frame_stats.h" | 13 #include "remoting/protocol/frame_stats.h" |
| 14 #include "remoting/protocol/host_video_stats_dispatcher.h" | 14 #include "remoting/protocol/host_video_stats_dispatcher.h" |
| 15 #include "remoting/protocol/webrtc_capture_scheduler_simple.h" |
| 15 #include "remoting/protocol/webrtc_dummy_video_capturer.h" | 16 #include "remoting/protocol/webrtc_dummy_video_capturer.h" |
| 16 #include "remoting/protocol/webrtc_transport.h" | 17 #include "remoting/protocol/webrtc_transport.h" |
| 17 #include "third_party/webrtc/api/mediastreaminterface.h" | 18 #include "third_party/webrtc/api/mediastreaminterface.h" |
| 18 #include "third_party/webrtc/api/peerconnectioninterface.h" | 19 #include "third_party/webrtc/api/peerconnectioninterface.h" |
| 19 #include "third_party/webrtc/api/test/fakeconstraints.h" | 20 #include "third_party/webrtc/api/test/fakeconstraints.h" |
| 20 #include "third_party/webrtc/media/base/videocapturer.h" | 21 #include "third_party/webrtc/media/base/videocapturer.h" |
| 21 | 22 |
| 22 namespace remoting { | 23 namespace remoting { |
| 23 namespace protocol { | 24 namespace protocol { |
| 24 | 25 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 // Register for target bitrate notifications. | 128 // Register for target bitrate notifications. |
| 128 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback( | 129 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback( |
| 129 base::Bind(&PostTaskOnTaskRunnerWithParam<int>, | 130 base::Bind(&PostTaskOnTaskRunnerWithParam<int>, |
| 130 base::ThreadTaskRunnerHandle::Get(), | 131 base::ThreadTaskRunnerHandle::Get(), |
| 131 base::Bind(&WebrtcVideoStream::SetTargetBitrate, | 132 base::Bind(&WebrtcVideoStream::SetTargetBitrate, |
| 132 weak_factory_.GetWeakPtr()))); | 133 weak_factory_.GetWeakPtr()))); |
| 133 | 134 |
| 134 video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel( | 135 video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel( |
| 135 video_stats_dispatcher_.channel_name()), | 136 video_stats_dispatcher_.channel_name()), |
| 136 this); | 137 this); |
| 138 |
| 139 scheduler_.reset(new WebrtcCaptureSchedulerSimple()); |
| 140 |
| 137 return true; | 141 return true; |
| 138 } | 142 } |
| 139 | 143 |
| 140 void WebrtcVideoStream::Pause(bool pause) { | 144 void WebrtcVideoStream::Pause(bool pause) { |
| 141 DCHECK(thread_checker_.CalledOnValidThread()); | 145 DCHECK(thread_checker_.CalledOnValidThread()); |
| 142 if (pause) { | 146 scheduler_->Pause(pause); |
| 143 capture_timer_.Stop(); | |
| 144 } else { | |
| 145 if (received_first_frame_request_) { | |
| 146 StartCaptureTimer(); | |
| 147 } | |
| 148 } | |
| 149 } | 147 } |
| 150 | 148 |
| 151 void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) { | 149 void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) { |
| 152 DCHECK(thread_checker_.CalledOnValidThread()); | 150 DCHECK(thread_checker_.CalledOnValidThread()); |
| 153 | 151 |
| 154 if (!next_frame_timestamps_) | 152 if (!next_frame_timestamps_) |
| 155 next_frame_timestamps_.reset(new FrameTimestamps()); | 153 next_frame_timestamps_.reset(new FrameTimestamps()); |
| 156 next_frame_timestamps_->input_event_client_timestamp = event_timestamp; | 154 next_frame_timestamps_->input_event_client_timestamp = event_timestamp; |
| 157 next_frame_timestamps_->input_event_received_time = base::TimeTicks::Now(); | 155 next_frame_timestamps_->input_event_received_time = base::TimeTicks::Now(); |
| 158 } | 156 } |
| 159 | 157 |
| 160 void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) { | 158 void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) { |
| 161 NOTIMPLEMENTED(); | 159 NOTIMPLEMENTED(); |
| 162 } | 160 } |
| 163 | 161 |
| 164 void WebrtcVideoStream::SetLosslessColor(bool want_lossless) { | 162 void WebrtcVideoStream::SetLosslessColor(bool want_lossless) { |
| 165 NOTIMPLEMENTED(); | 163 NOTIMPLEMENTED(); |
| 166 } | 164 } |
| 167 | 165 |
| 168 void WebrtcVideoStream::SetObserver(Observer* observer) { | 166 void WebrtcVideoStream::SetObserver(Observer* observer) { |
| 169 DCHECK(thread_checker_.CalledOnValidThread()); | 167 DCHECK(thread_checker_.CalledOnValidThread()); |
| 170 observer_ = observer; | 168 observer_ = observer; |
| 171 } | 169 } |
| 172 | 170 |
| 173 void WebrtcVideoStream::SetKeyFrameRequest() { | 171 void WebrtcVideoStream::SetKeyFrameRequest() { |
| 174 DCHECK(thread_checker_.CalledOnValidThread()); | 172 DCHECK(thread_checker_.CalledOnValidThread()); |
| 175 | 173 |
| 176 key_frame_request_ = true; | 174 scheduler_->SetKeyFrameRequest(); |
| 175 |
| 176 // Create capture scheduler when the first key frame request is received. |
| 177 if (!received_first_frame_request_) { | 177 if (!received_first_frame_request_) { |
| 178 received_first_frame_request_ = true; | 178 received_first_frame_request_ = true; |
| 179 StartCaptureTimer(); | 179 scheduler_->Start(base::Bind(&WebrtcVideoStream::CaptureNextFrame, |
| 180 base::ThreadTaskRunnerHandle::Get()->PostTask( | 180 base::Unretained(this))); |
| 181 FROM_HERE, base::Bind(&WebrtcVideoStream::StartCaptureTimer, | |
| 182 weak_factory_.GetWeakPtr())); | |
| 183 } | 181 } |
| 184 } | 182 } |
| 185 | 183 |
| 186 void WebrtcVideoStream::StartCaptureTimer() { | |
| 187 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 188 capture_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, | |
| 189 &WebrtcVideoStream::CaptureNextFrame); | |
| 190 } | |
| 191 | |
| 192 void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) { | 184 void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) { |
| 193 DCHECK(thread_checker_.CalledOnValidThread()); | 185 DCHECK(thread_checker_.CalledOnValidThread()); |
| 194 | 186 |
| 195 VLOG(1) << "Set Target bitrate " << target_bitrate_kbps; | 187 VLOG(1) << "Set Target bitrate " << target_bitrate_kbps; |
| 196 target_bitrate_kbps_ = target_bitrate_kbps; | 188 scheduler_->SetTargetBitrate(target_bitrate_kbps); |
| 197 } | |
| 198 | |
| 199 bool WebrtcVideoStream::ClearAndGetKeyFrameRequest() { | |
| 200 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 201 | |
| 202 bool key_frame_request = key_frame_request_; | |
| 203 key_frame_request_ = false; | |
| 204 return key_frame_request; | |
| 205 } | 189 } |
| 206 | 190 |
| 207 void WebrtcVideoStream::OnCaptureResult( | 191 void WebrtcVideoStream::OnCaptureResult( |
| 208 webrtc::DesktopCapturer::Result result, | 192 webrtc::DesktopCapturer::Result result, |
| 209 std::unique_ptr<webrtc::DesktopFrame> frame) { | 193 std::unique_ptr<webrtc::DesktopFrame> frame) { |
| 210 DCHECK(thread_checker_.CalledOnValidThread()); | 194 DCHECK(thread_checker_.CalledOnValidThread()); |
| 211 DCHECK(capture_pending_); | |
| 212 capture_pending_ = false; | |
| 213 | |
| 214 | |
| 215 if (encode_pending_) { | |
| 216 // TODO(isheriff): consider queuing here | |
| 217 VLOG(1) << "Dropping captured frame since encoder is still busy"; | |
| 218 return; | |
| 219 } | |
| 220 | 195 |
| 221 // TODO(sergeyu): Handle ERROR_PERMANENT result here. | 196 // TODO(sergeyu): Handle ERROR_PERMANENT result here. |
| 222 | 197 |
| 223 webrtc::DesktopVector dpi = | 198 webrtc::DesktopVector dpi = |
| 224 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) | 199 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) |
| 225 : frame->dpi(); | 200 : frame->dpi(); |
| 226 | 201 |
| 227 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { | 202 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { |
| 228 frame_size_ = frame->size(); | 203 frame_size_ = frame->size(); |
| 229 frame_dpi_ = dpi; | 204 frame_dpi_ = dpi; |
| 230 if (observer_) | 205 if (observer_) |
| 231 observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_); | 206 observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_); |
| 232 } | 207 } |
| 233 | 208 |
| 234 captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now(); | 209 captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now(); |
| 235 captured_frame_timestamps_->capture_delay = | 210 captured_frame_timestamps_->capture_delay = |
| 236 base::TimeDelta::FromMilliseconds(frame->capture_time_ms()); | 211 base::TimeDelta::FromMilliseconds(frame->capture_time_ms()); |
| 237 | 212 |
| 238 encode_pending_ = true; | 213 WebrtcVideoEncoder::FrameParams frame_params; |
| 214 if (!scheduler_->GetEncoderFrameParams(*frame, &frame_params)) |
| 215 return; |
| 239 | 216 |
| 240 // TODO(sergeyu): Currently frame_duration is always set to 1/15 of a second. | |
| 241 // Experiment with different values, and try changing it dynamically. | |
| 242 WebrtcVideoEncoder::FrameParams frame_params{ | |
| 243 .bitrate_kbps = target_bitrate_kbps_, | |
| 244 .duration = base::TimeDelta::FromSeconds(1) / 15, | |
| 245 .key_frame = ClearAndGetKeyFrameRequest()}; | |
| 246 base::PostTaskAndReplyWithResult( | 217 base::PostTaskAndReplyWithResult( |
| 247 encode_task_runner_.get(), FROM_HERE, | 218 encode_task_runner_.get(), FROM_HERE, |
| 248 base::Bind(&WebrtcVideoStream::EncodeFrame, encoder_.get(), | 219 base::Bind(&WebrtcVideoStream::EncodeFrame, encoder_.get(), |
| 249 base::Passed(std::move(frame)), frame_params, | 220 base::Passed(std::move(frame)), frame_params, |
| 250 base::Passed(std::move(captured_frame_timestamps_))), | 221 base::Passed(std::move(captured_frame_timestamps_))), |
| 251 base::Bind(&WebrtcVideoStream::OnFrameEncoded, | 222 base::Bind(&WebrtcVideoStream::OnFrameEncoded, |
| 252 weak_factory_.GetWeakPtr())); | 223 weak_factory_.GetWeakPtr())); |
| 253 } | 224 } |
| 254 | 225 |
| 255 void WebrtcVideoStream::OnChannelInitialized( | 226 void WebrtcVideoStream::OnChannelInitialized( |
| 256 ChannelDispatcherBase* channel_dispatcher) { | 227 ChannelDispatcherBase* channel_dispatcher) { |
| 257 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); | 228 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); |
| 258 } | 229 } |
| 259 void WebrtcVideoStream::OnChannelClosed( | 230 void WebrtcVideoStream::OnChannelClosed( |
| 260 ChannelDispatcherBase* channel_dispatcher) { | 231 ChannelDispatcherBase* channel_dispatcher) { |
| 261 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); | 232 DCHECK(&video_stats_dispatcher_ == channel_dispatcher); |
| 262 LOG(WARNING) << "video_stats channel was closed."; | 233 LOG(WARNING) << "video_stats channel was closed."; |
| 263 } | 234 } |
| 264 | 235 |
| 265 void WebrtcVideoStream::CaptureNextFrame() { | 236 void WebrtcVideoStream::CaptureNextFrame() { |
| 266 DCHECK(thread_checker_.CalledOnValidThread()); | 237 DCHECK(thread_checker_.CalledOnValidThread()); |
| 267 | 238 |
| 268 if (capture_pending_ || encode_pending_) { | |
| 269 VLOG(1) << "Capture/encode still pending.."; | |
| 270 return; | |
| 271 } | |
| 272 | |
| 273 base::TimeTicks now = base::TimeTicks::Now(); | |
| 274 | |
| 275 capture_pending_ = true; | |
| 276 VLOG(1) << "Capture next frame after " | |
| 277 << (base::TimeTicks::Now() - last_capture_started_ticks_) | |
| 278 .InMilliseconds(); | |
| 279 last_capture_started_ticks_ = now; | |
| 280 | |
| 281 | |
| 282 // |next_frame_timestamps_| is not set if no input events were received since | 239 // |next_frame_timestamps_| is not set if no input events were received since |
| 283 // the previous frame. In that case create FrameTimestamps instance without | 240 // the previous frame. In that case create FrameTimestamps instance without |
| 284 // setting |input_event_client_timestamp| and |input_event_received_time|. | 241 // setting |input_event_client_timestamp| and |input_event_received_time|. |
| 285 if (!next_frame_timestamps_) | 242 if (!next_frame_timestamps_) |
| 286 next_frame_timestamps_.reset(new FrameTimestamps()); | 243 next_frame_timestamps_.reset(new FrameTimestamps()); |
| 287 | 244 |
| 288 captured_frame_timestamps_ = std::move(next_frame_timestamps_); | 245 captured_frame_timestamps_ = std::move(next_frame_timestamps_); |
| 289 captured_frame_timestamps_->capture_started_time = now; | 246 captured_frame_timestamps_->capture_started_time = base::TimeTicks::Now(); |
| 290 | 247 |
| 291 capturer_->Capture(webrtc::DesktopRegion()); | 248 capturer_->Capture(webrtc::DesktopRegion()); |
| 292 } | 249 } |
| 293 | 250 |
| 294 // static | 251 // static |
| 295 WebrtcVideoStream::EncodedFrameWithTimestamps WebrtcVideoStream::EncodeFrame( | 252 WebrtcVideoStream::EncodedFrameWithTimestamps WebrtcVideoStream::EncodeFrame( |
| 296 WebrtcVideoEncoder* encoder, | 253 WebrtcVideoEncoder* encoder, |
| 297 std::unique_ptr<webrtc::DesktopFrame> frame, | 254 std::unique_ptr<webrtc::DesktopFrame> frame, |
| 298 WebrtcVideoEncoder::FrameParams params, | 255 WebrtcVideoEncoder::FrameParams params, |
| 299 std::unique_ptr<WebrtcVideoStream::FrameTimestamps> timestamps) { | 256 std::unique_ptr<WebrtcVideoStream::FrameTimestamps> timestamps) { |
| 300 EncodedFrameWithTimestamps result; | 257 EncodedFrameWithTimestamps result; |
| 301 result.timestamps = std::move(timestamps); | 258 result.timestamps = std::move(timestamps); |
| 302 result.timestamps->encode_started_time = base::TimeTicks::Now(); | 259 result.timestamps->encode_started_time = base::TimeTicks::Now(); |
| 303 result.frame = encoder->Encode(*frame, params); | 260 result.frame = encoder->Encode(*frame, params); |
| 304 result.timestamps->encode_ended_time = base::TimeTicks::Now(); | 261 result.timestamps->encode_ended_time = base::TimeTicks::Now(); |
| 305 return result; | 262 return result; |
| 306 } | 263 } |
| 307 | 264 |
| 308 void WebrtcVideoStream::OnFrameEncoded(EncodedFrameWithTimestamps frame) { | 265 void WebrtcVideoStream::OnFrameEncoded(EncodedFrameWithTimestamps frame) { |
| 309 DCHECK(thread_checker_.CalledOnValidThread()); | 266 DCHECK(thread_checker_.CalledOnValidThread()); |
| 310 | 267 |
| 311 encode_pending_ = false; | 268 // Send the frame itself. |
| 312 | 269 webrtc::EncodedImageCallback::Result result = |
| 313 size_t frame_size = frame.frame ? frame.frame->data.size() : 0; | 270 webrtc_transport_->video_encoder_factory()->SendEncodedFrame( |
| 314 | 271 *frame.frame, frame.timestamps->capture_started_time); |
| 315 // Generate HostFrameStats. | 272 if (result.error != webrtc::EncodedImageCallback::Result::OK) { |
| 316 HostFrameStats stats; | 273 // TODO(sergeyu): Stop the stream. |
| 317 stats.frame_size = frame_size; | 274 LOG(ERROR) << "Failed to send video frame."; |
| 318 | 275 return; |
| 319 if (!frame.timestamps->input_event_received_time.is_null()) { | |
| 320 stats.capture_pending_delay = frame.timestamps->capture_started_time - | |
| 321 frame.timestamps->input_event_received_time; | |
| 322 stats.latest_event_timestamp = base::TimeTicks::FromInternalValue( | |
| 323 frame.timestamps->input_event_client_timestamp); | |
| 324 } | 276 } |
| 325 | 277 |
| 326 stats.capture_delay = frame.timestamps->capture_delay; | 278 scheduler_->OnFrameEncoded(*frame.frame, result); |
| 327 | |
| 328 // Total overhead time for IPC and threading when capturing frames. | |
| 329 stats.capture_overhead_delay = (frame.timestamps->capture_ended_time - | |
| 330 frame.timestamps->capture_started_time) - | |
| 331 stats.capture_delay; | |
| 332 | |
| 333 stats.encode_pending_delay = frame.timestamps->encode_started_time - | |
| 334 frame.timestamps->capture_ended_time; | |
| 335 | |
| 336 stats.encode_delay = frame.timestamps->encode_ended_time - | |
| 337 frame.timestamps->encode_started_time; | |
| 338 | |
| 339 // TODO(sergeyu): Figure out how to measure send_pending time with WebRTC and | |
| 340 // set it here. | |
| 341 stats.send_pending_delay = base::TimeDelta(); | |
| 342 | |
| 343 uint32_t frame_id = 0; | |
| 344 if (frame.frame) { | |
| 345 // Send the frame itself. | |
| 346 webrtc::EncodedImageCallback::Result result = | |
| 347 webrtc_transport_->video_encoder_factory()->SendEncodedFrame( | |
| 348 std::move(frame.frame), frame.timestamps->capture_started_time); | |
| 349 if (result.error != webrtc::EncodedImageCallback::Result::OK) { | |
| 350 // TODO(sergeyu): Stop the stream. | |
| 351 LOG(ERROR) << "Failed to send video frame."; | |
| 352 return; | |
| 353 } | |
| 354 frame_id = result.frame_id; | |
| 355 } | |
| 356 | 279 |
| 357 // Send FrameStats message. | 280 // Send FrameStats message. |
| 358 if (video_stats_dispatcher_.is_connected()) | 281 if (video_stats_dispatcher_.is_connected()) { |
| 359 video_stats_dispatcher_.OnVideoFrameStats(frame_id, stats); | 282 HostFrameStats stats; |
| 283 stats.frame_size = frame.frame->data.size(); |
| 360 | 284 |
| 361 // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS. | 285 if (!frame.timestamps->input_event_received_time.is_null()) { |
| 362 // TODO(sergeyu): Move this logic to a separate class. | 286 stats.capture_pending_delay = |
| 363 float encoded_bits = frame_size * 8.0; | 287 frame.timestamps->capture_started_time - |
| 364 uint32_t next_sched_ms = std::max( | 288 frame.timestamps->input_event_received_time; |
| 365 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200)); | 289 stats.latest_event_timestamp = base::TimeTicks::FromInternalValue( |
| 366 capture_timer_.Start(FROM_HERE, | 290 frame.timestamps->input_event_client_timestamp); |
| 367 base::TimeDelta::FromMilliseconds(next_sched_ms), this, | 291 } |
| 368 &WebrtcVideoStream::CaptureNextFrame); | 292 |
| 293 stats.capture_delay = frame.timestamps->capture_delay; |
| 294 |
| 295 // Total overhead time for IPC and threading when capturing frames. |
| 296 stats.capture_overhead_delay = (frame.timestamps->capture_ended_time - |
| 297 frame.timestamps->capture_started_time) - |
| 298 stats.capture_delay; |
| 299 |
| 300 stats.encode_pending_delay = frame.timestamps->encode_started_time - |
| 301 frame.timestamps->capture_ended_time; |
| 302 |
| 303 stats.encode_delay = frame.timestamps->encode_ended_time - |
| 304 frame.timestamps->encode_started_time; |
| 305 |
| 306 // TODO(sergeyu): Figure out how to measure send_pending time with WebRTC |
| 307 // and set it here. |
| 308 stats.send_pending_delay = base::TimeDelta(); |
| 309 |
| 310 video_stats_dispatcher_.OnVideoFrameStats(result.frame_id, stats); |
| 311 } |
| 369 } | 312 } |
| 370 | 313 |
| 371 } // namespace protocol | 314 } // namespace protocol |
| 372 } // namespace remoting | 315 } // namespace remoting |
| OLD | NEW |