Chromium Code Reviews| 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 |