blob: 4b83060a0ceab983fbb15d7b6a3d05a20adc8c19 [file] [log] [blame]
sergeyu0fc40f92015-12-10 18:42:431// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/protocol/webrtc_video_stream.h"
6
yuweih1481d8d2017-04-04 01:43:517#include <utility>
8
Zijie He3d3751dc2017-10-26 19:29:549#include "base/bind.h"
sergeyu0fc40f92015-12-10 18:42:4310#include "base/logging.h"
Sergey Ulanove50708f2017-06-20 21:29:1111#include "base/memory/ptr_util.h"
Zijie Hecaea1e42017-10-11 23:20:3512#include "build/build_config.h"
sergeyu4e10ab12016-06-22 00:56:2213#include "remoting/base/constants.h"
Sergey Ulanove50708f2017-06-20 21:29:1114#include "remoting/codec/webrtc_video_encoder_proxy.h"
sergeyu2becb6012016-09-13 18:41:3215#include "remoting/codec/webrtc_video_encoder_vpx.h"
sergeyu09364632016-08-11 00:08:1016#include "remoting/protocol/frame_stats.h"
17#include "remoting/protocol/host_video_stats_dispatcher.h"
isheriff87c2fbd2016-04-13 21:21:4418#include "remoting/protocol/webrtc_dummy_video_capturer.h"
sergeyu0eaa5132016-09-20 01:39:3419#include "remoting/protocol/webrtc_frame_scheduler_simple.h"
sergeyu4e10ab12016-06-22 00:56:2220#include "remoting/protocol/webrtc_transport.h"
kjellander97705452016-02-10 14:51:2421#include "third_party/webrtc/api/mediastreaminterface.h"
22#include "third_party/webrtc/api/peerconnectioninterface.h"
23#include "third_party/webrtc/api/test/fakeconstraints.h"
isheriff87c2fbd2016-04-13 21:21:4424#include "third_party/webrtc/media/base/videocapturer.h"
sergeyu0fc40f92015-12-10 18:42:4325
Zijie Hecaea1e42017-10-11 23:20:3526#if defined(USE_H264_ENCODER)
27#include "remoting/codec/webrtc_video_encoder_gpu.h"
28#endif
29
sergeyu0fc40f92015-12-10 18:42:4330namespace remoting {
31namespace protocol {
32
Zijie Hecc8a0772017-10-17 03:19:3233namespace {
34
sergeyubf81cd62016-01-10 08:00:4235const char kStreamLabel[] = "screen_stream";
36const char kVideoLabel[] = "screen_video";
37
Zijie Hecc8a0772017-10-17 03:19:3238std::string EncodeResultToString(WebrtcVideoEncoder::EncodeResult result) {
39 using EncodeResult = WebrtcVideoEncoder::EncodeResult;
40
41 switch (result) {
42 case EncodeResult::SUCCEEDED:
43 return "Succeeded";
44 case EncodeResult::FRAME_SIZE_EXCEEDS_CAPABILITY:
45 return "Frame size exceeds capability";
46 case EncodeResult::UNKNOWN_ERROR:
47 return "Unknown error";
48 }
49 NOTREACHED();
50 return "";
51}
52
53} // namespace
54
zijiehe805f2ca2017-03-27 00:56:0055struct WebrtcVideoStream::FrameStats {
sergeyue84cc622016-10-15 06:54:0356 // The following fields is not null only for one frame after each incoming
57 // input event.
58 InputEventTimestamps input_event_timestamps;
sergeyu09364632016-08-11 00:08:1059
60 base::TimeTicks capture_started_time;
61 base::TimeTicks capture_ended_time;
62 base::TimeDelta capture_delay;
63 base::TimeTicks encode_started_time;
64 base::TimeTicks encode_ended_time;
zijiehe805f2ca2017-03-27 00:56:0065
66 uint32_t capturer_id = 0;
sergeyu09364632016-08-11 00:08:1067};
68
Zijie Heba571512017-11-20 20:22:2369WebrtcVideoStream::WebrtcVideoStream(const SessionOptions& session_options)
70 : video_stats_dispatcher_(kStreamLabel),
71 session_options_(session_options),
72 weak_factory_(this) {
Zijie He3d3751dc2017-10-26 19:29:5473 encoder_selector_.RegisterEncoder(
74 base::Bind(&WebrtcVideoEncoderVpx::IsSupportedByVP8),
75 base::Bind(&WebrtcVideoEncoderVpx::CreateForVP8));
76 encoder_selector_.RegisterEncoder(
77 base::Bind(&WebrtcVideoEncoderVpx::IsSupportedByVP9),
78 base::Bind(&WebrtcVideoEncoderVpx::CreateForVP9));
79#if defined(USE_H264_ENCODER)
80 encoder_selector_.RegisterEncoder(
81 base::Bind(&WebrtcVideoEncoderGpu::IsSupportedByH264),
82 base::Bind(&WebrtcVideoEncoderGpu::CreateForH264));
83#endif
84}
sergeyu0fc40f92015-12-10 18:42:4385
86WebrtcVideoStream::~WebrtcVideoStream() {
joedow18837eb2017-05-17 18:28:2487 DCHECK(thread_checker_.CalledOnValidThread());
sergeyubf81cd62016-01-10 08:00:4288 if (stream_) {
89 for (const auto& track : stream_->GetVideoTracks()) {
sergeyubf81cd62016-01-10 08:00:4290 stream_->RemoveTrack(track.get());
91 }
sergeyu4e10ab12016-06-22 00:56:2292 peer_connection_->RemoveStream(stream_.get());
sergeyu0fc40f92015-12-10 18:42:4393 }
sergeyubf81cd62016-01-10 08:00:4294}
95
sergeyu24b257a12016-10-09 02:46:2896void WebrtcVideoStream::Start(
dcheng0765c492016-04-06 22:41:5397 std::unique_ptr<webrtc::DesktopCapturer> desktop_capturer,
isheriff87c2fbd2016-04-13 21:21:4498 WebrtcTransport* webrtc_transport,
Sergey Ulanove50708f2017-06-20 21:29:1199 scoped_refptr<base::SequencedTaskRunner> encode_task_runner) {
sergeyu4e10ab12016-06-22 00:56:22100 DCHECK(thread_checker_.CalledOnValidThread());
isheriff87c2fbd2016-04-13 21:21:44101 DCHECK(webrtc_transport);
102 DCHECK(desktop_capturer);
sergeyu4e10ab12016-06-22 00:56:22103 DCHECK(encode_task_runner);
sergeyubf81cd62016-01-10 08:00:42104
isheriff87c2fbd2016-04-13 21:21:44105 scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory(
106 webrtc_transport->peer_connection_factory());
sergeyu4e10ab12016-06-22 00:56:22107 peer_connection_ = webrtc_transport->peer_connection();
isheriff87c2fbd2016-04-13 21:21:44108 DCHECK(peer_connection_factory);
sergeyu4e10ab12016-06-22 00:56:22109 DCHECK(peer_connection_);
isheriff87c2fbd2016-04-13 21:21:44110
gab10ae4362016-11-02 23:34:53111 encode_task_runner_ = std::move(encode_task_runner);
sergeyu4e10ab12016-06-22 00:56:22112 capturer_ = std::move(desktop_capturer);
113 webrtc_transport_ = webrtc_transport;
yuweih1481d8d2017-04-04 01:43:51114
115 webrtc_transport_->video_encoder_factory()->RegisterEncoderSelectedCallback(
116 base::Bind(&WebrtcVideoStream::OnEncoderCreated,
117 weak_factory_.GetWeakPtr()));
118
sergeyu4e10ab12016-06-22 00:56:22119 capturer_->Start(this);
sergeyubf81cd62016-01-10 08:00:42120
121 // Set video stream constraints.
122 webrtc::FakeConstraints video_constraints;
123 video_constraints.AddMandatory(
124 webrtc::MediaConstraintsInterface::kMinFrameRate, 5);
125
isheriff87c2fbd2016-04-13 21:21:44126 rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> src =
sergeyu4e10ab12016-06-22 00:56:22127 peer_connection_factory->CreateVideoSource(new WebrtcDummyVideoCapturer(),
128 &video_constraints);
sergeyubf81cd62016-01-10 08:00:42129 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track =
isheriff87c2fbd2016-04-13 21:21:44130 peer_connection_factory->CreateVideoTrack(kVideoLabel, src);
sergeyubf81cd62016-01-10 08:00:42131
132 stream_ = peer_connection_factory->CreateLocalMediaStream(kStreamLabel);
133
sergeyu24b257a12016-10-09 02:46:28134 // AddTrack() may fail only if there is another track with the same name,
135 // which is impossible because it's a brand new stream.
136 bool result = stream_->AddTrack(video_track.get());
137 DCHECK(result);
138
139 // AddStream() may fail if there is another stream with the same name or when
140 // the PeerConnection is closed, neither is expected.
141 result = peer_connection_->AddStream(stream_.get());
142 DCHECK(result);
sergeyu4e10ab12016-06-22 00:56:22143
Zijie Heba571512017-11-20 20:22:23144 scheduler_.reset(new WebrtcFrameSchedulerSimple(session_options_));
sergeyu78f725b2016-10-11 23:34:48145 scheduler_->Start(
146 webrtc_transport_->video_encoder_factory(),
147 base::Bind(&WebrtcVideoStream::CaptureNextFrame, base::Unretained(this)));
sergeyu4e10ab12016-06-22 00:56:22148
sergeyu09364632016-08-11 00:08:10149 video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel(
150 video_stats_dispatcher_.channel_name()),
151 this);
sergeyu0fc40f92015-12-10 18:42:43152}
153
sergeyue84cc622016-10-15 06:54:03154void WebrtcVideoStream::SetEventTimestampsSource(
155 scoped_refptr<InputEventTimestampsSource> event_timestamps_source) {
156 event_timestamps_source_ = event_timestamps_source;
157}
158
sergeyu0fc40f92015-12-10 18:42:43159void WebrtcVideoStream::Pause(bool pause) {
sergeyu4e10ab12016-06-22 00:56:22160 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu0eaa5132016-09-20 01:39:34161 scheduler_->Pause(pause);
sergeyu0fc40f92015-12-10 18:42:43162}
163
sergeyu0fc40f92015-12-10 18:42:43164void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) {
165 NOTIMPLEMENTED();
166}
167
168void WebrtcVideoStream::SetLosslessColor(bool want_lossless) {
169 NOTIMPLEMENTED();
170}
171
sergeyuad51be82016-06-22 06:04:39172void WebrtcVideoStream::SetObserver(Observer* observer) {
sergeyu4e10ab12016-06-22 00:56:22173 DCHECK(thread_checker_.CalledOnValidThread());
sergeyuad51be82016-06-22 06:04:39174 observer_ = observer;
sergeyu4e10ab12016-06-22 00:56:22175}
176
sergeyu4e10ab12016-06-22 00:56:22177void WebrtcVideoStream::OnCaptureResult(
178 webrtc::DesktopCapturer::Result result,
179 std::unique_ptr<webrtc::DesktopFrame> frame) {
180 DCHECK(thread_checker_.CalledOnValidThread());
sergeyu4e10ab12016-06-22 00:56:22181
Sergey Ulanove50708f2017-06-20 21:29:11182 current_frame_stats_->capture_ended_time = base::TimeTicks::Now();
183 current_frame_stats_->capture_delay =
sergeyu14b918b2017-01-09 23:10:24184 base::TimeDelta::FromMilliseconds(frame ? frame->capture_time_ms() : 0);
sergeyu09364632016-08-11 00:08:10185
sergeyu2becb6012016-09-13 18:41:32186 WebrtcVideoEncoder::FrameParams frame_params;
sergeyu14b918b2017-01-09 23:10:24187 if (!scheduler_->OnFrameCaptured(frame.get(), &frame_params)) {
sergeyu0eaa5132016-09-20 01:39:34188 return;
sergeyu14b918b2017-01-09 23:10:24189 }
190
191 // TODO(sergeyu): Handle ERROR_PERMANENT result here.
192 if (frame) {
193 webrtc::DesktopVector dpi =
194 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi)
195 : frame->dpi();
196
197 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) {
198 frame_size_ = frame->size();
199 frame_dpi_ = dpi;
200 if (observer_)
201 observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_);
202 }
Sergey Ulanove50708f2017-06-20 21:29:11203
204 current_frame_stats_->capturer_id = frame->capturer_id();
Zijie He3d3751dc2017-10-26 19:29:54205
206 if (!encoder_) {
207 encoder_selector_.SetDesktopFrame(*frame);
208 encoder_ = encoder_selector_.CreateEncoder();
209
210 // TODO(zijiehe): Permanently stop the video stream if we cannot create an
211 // encoder for the |frame|.
212 }
sergeyu14b918b2017-01-09 23:10:24213 }
sergeyu2becb6012016-09-13 18:41:32214
Zijie He3d3751dc2017-10-26 19:29:54215 if (encoder_) {
216 current_frame_stats_->encode_started_time = base::TimeTicks::Now();
217 encoder_->Encode(
218 std::move(frame), frame_params,
219 base::Bind(&WebrtcVideoStream::OnFrameEncoded, base::Unretained(this)));
220 }
sergeyu4e10ab12016-06-22 00:56:22221}
222
sergeyu09364632016-08-11 00:08:10223void WebrtcVideoStream::OnChannelInitialized(
224 ChannelDispatcherBase* channel_dispatcher) {
225 DCHECK(&video_stats_dispatcher_ == channel_dispatcher);
226}
227void WebrtcVideoStream::OnChannelClosed(
228 ChannelDispatcherBase* channel_dispatcher) {
229 DCHECK(&video_stats_dispatcher_ == channel_dispatcher);
230 LOG(WARNING) << "video_stats channel was closed.";
231}
232
sergeyu4e10ab12016-06-22 00:56:22233void WebrtcVideoStream::CaptureNextFrame() {
234 DCHECK(thread_checker_.CalledOnValidThread());
235
Sergey Ulanove50708f2017-06-20 21:29:11236 current_frame_stats_.reset(new FrameStats());
237 current_frame_stats_->capture_started_time = base::TimeTicks::Now();
238 current_frame_stats_->input_event_timestamps =
sergeyu5e372bf2017-03-21 21:56:23239 event_timestamps_source_->TakeLastEventTimestamps();
sergeyue84cc622016-10-15 06:54:03240
zijiehe27bcc912016-10-18 05:57:56241 capturer_->CaptureFrame();
sergeyu4e10ab12016-06-22 00:56:22242}
243
Sergey Ulanove50708f2017-06-20 21:29:11244void WebrtcVideoStream::OnFrameEncoded(
Zijie Hecc8a0772017-10-17 03:19:32245 WebrtcVideoEncoder::EncodeResult encode_result,
Sergey Ulanove50708f2017-06-20 21:29:11246 std::unique_ptr<WebrtcVideoEncoder::EncodedFrame> frame) {
sergeyu4e10ab12016-06-22 00:56:22247 DCHECK(thread_checker_.CalledOnValidThread());
248
Sergey Ulanove50708f2017-06-20 21:29:11249 current_frame_stats_->encode_ended_time = base::TimeTicks::Now();
sergeyu14b918b2017-01-09 23:10:24250
Sergey Ulanove50708f2017-06-20 21:29:11251 HostFrameStats stats;
252 scheduler_->OnFrameEncoded(frame.get(), &stats);
253
Zijie Hecc8a0772017-10-17 03:19:32254 if (encode_result != WebrtcVideoEncoder::EncodeResult::SUCCEEDED) {
Zijie Hecc8a0772017-10-17 03:19:32255 LOG(ERROR) << "Video encoder returns error "
256 << EncodeResultToString(encode_result);
Zijie He3d3751dc2017-10-26 19:29:54257 // TODO(zijiehe): Restart the video stream.
258 encoder_.reset();
Zijie Hecc8a0772017-10-17 03:19:32259 return;
260 }
261
Sergey Ulanove50708f2017-06-20 21:29:11262 if (!frame) {
sergeyu14b918b2017-01-09 23:10:24263 return;
264 }
265
sergeyu0eaa5132016-09-20 01:39:34266 webrtc::EncodedImageCallback::Result result =
267 webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
Sergey Ulanove50708f2017-06-20 21:29:11268 *frame, current_frame_stats_->capture_started_time);
sergeyu0eaa5132016-09-20 01:39:34269 if (result.error != webrtc::EncodedImageCallback::Result::OK) {
270 // TODO(sergeyu): Stop the stream.
271 LOG(ERROR) << "Failed to send video frame.";
272 return;
sergeyu09364632016-08-11 00:08:10273 }
274
sergeyu09364632016-08-11 00:08:10275 // Send FrameStats message.
sergeyu0eaa5132016-09-20 01:39:34276 if (video_stats_dispatcher_.is_connected()) {
Sergey Ulanove50708f2017-06-20 21:29:11277 stats.frame_size = frame ? frame->data.size() : 0;
sergeyu4e10ab12016-06-22 00:56:22278
Sergey Ulanove50708f2017-06-20 21:29:11279 if (!current_frame_stats_->input_event_timestamps.is_null()) {
sergeyue84cc622016-10-15 06:54:03280 stats.capture_pending_delay =
Sergey Ulanove50708f2017-06-20 21:29:11281 current_frame_stats_->capture_started_time -
282 current_frame_stats_->input_event_timestamps.host_timestamp;
sergeyue84cc622016-10-15 06:54:03283 stats.latest_event_timestamp =
Sergey Ulanove50708f2017-06-20 21:29:11284 current_frame_stats_->input_event_timestamps.client_timestamp;
sergeyu0eaa5132016-09-20 01:39:34285 }
286
Sergey Ulanove50708f2017-06-20 21:29:11287 stats.capture_delay = current_frame_stats_->capture_delay;
sergeyu0eaa5132016-09-20 01:39:34288
289 // Total overhead time for IPC and threading when capturing frames.
zijiehe805f2ca2017-03-27 00:56:00290 stats.capture_overhead_delay =
Sergey Ulanove50708f2017-06-20 21:29:11291 (current_frame_stats_->capture_ended_time -
292 current_frame_stats_->capture_started_time) -
zijiehe805f2ca2017-03-27 00:56:00293 stats.capture_delay;
sergeyu0eaa5132016-09-20 01:39:34294
Sergey Ulanove50708f2017-06-20 21:29:11295 stats.encode_pending_delay = current_frame_stats_->encode_started_time -
296 current_frame_stats_->capture_ended_time;
sergeyu0eaa5132016-09-20 01:39:34297
Sergey Ulanove50708f2017-06-20 21:29:11298 stats.encode_delay = current_frame_stats_->encode_ended_time -
299 current_frame_stats_->encode_started_time;
zijiehe805f2ca2017-03-27 00:56:00300
Sergey Ulanove50708f2017-06-20 21:29:11301 stats.capturer_id = current_frame_stats_->capturer_id;
sergeyu0eaa5132016-09-20 01:39:34302
sergeyu0eaa5132016-09-20 01:39:34303 video_stats_dispatcher_.OnVideoFrameStats(result.frame_id, stats);
304 }
sergeyu0fc40f92015-12-10 18:42:43305}
306
yuweih1481d8d2017-04-04 01:43:51307void WebrtcVideoStream::OnEncoderCreated(webrtc::VideoCodecType codec_type) {
308 DCHECK(thread_checker_.CalledOnValidThread());
Zijie He3d3751dc2017-10-26 19:29:54309 // The preferred codec id depends on the order of
310 // |encoder_selector_|.RegisterEncoder().
yuweih1481d8d2017-04-04 01:43:51311 if (codec_type == webrtc::kVideoCodecVP8) {
Zijie He3d3751dc2017-10-26 19:29:54312 LOG(WARNING) << "VP8 video codec is preferred.";
313 encoder_selector_.SetPreferredCodec(0);
yuweih1481d8d2017-04-04 01:43:51314 } else if (codec_type == webrtc::kVideoCodecVP9) {
Zijie He3d3751dc2017-10-26 19:29:54315 LOG(WARNING) << "VP9 video codec is preferred.";
316 encoder_selector_.SetPreferredCodec(1);
Gus Smithb654f6fc2017-07-24 18:51:44317 } else if (codec_type == webrtc::kVideoCodecH264) {
Zijie Hecaea1e42017-10-11 23:20:35318#if defined(USE_H264_ENCODER)
Zijie He3d3751dc2017-10-26 19:29:54319 LOG(WARNING) << "H264 video codec is preferred.";
320 encoder_selector_.SetPreferredCodec(2);
Zijie Hecaea1e42017-10-11 23:20:35321#else
Gus Smithb654f6fc2017-07-24 18:51:44322 NOTIMPLEMENTED();
Zijie Hecaea1e42017-10-11 23:20:35323#endif
yuweih1481d8d2017-04-04 01:43:51324 } else {
325 LOG(FATAL) << "Unknown codec type: " << codec_type;
326 }
327}
328
sergeyu0fc40f92015-12-10 18:42:43329} // namespace protocol
330} // namespace remoting