| Index: remoting/protocol/webrtc_video_stream.cc
|
| diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc
|
| index b6f8b6add5e061d2aae948f9e8c5f67723c882c0..45fc2adb7a45749f522bb6ab0e6f2e8d65720c2a 100644
|
| --- a/remoting/protocol/webrtc_video_stream.cc
|
| +++ b/remoting/protocol/webrtc_video_stream.cc
|
| @@ -13,6 +13,7 @@
|
| #include "remoting/protocol/frame_stats.h"
|
| #include "remoting/protocol/host_video_stats_dispatcher.h"
|
| #include "remoting/protocol/webrtc_dummy_video_capturer.h"
|
| +#include "remoting/protocol/webrtc_frame_scheduler_simple.h"
|
| #include "remoting/protocol/webrtc_transport.h"
|
| #include "third_party/webrtc/api/mediastreaminterface.h"
|
| #include "third_party/webrtc/api/peerconnectioninterface.h"
|
| @@ -134,18 +135,15 @@ bool WebrtcVideoStream::Start(
|
| video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel(
|
| video_stats_dispatcher_.channel_name()),
|
| this);
|
| +
|
| + scheduler_.reset(new WebrtcFrameSchedulerSimple());
|
| +
|
| return true;
|
| }
|
|
|
| void WebrtcVideoStream::Pause(bool pause) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (pause) {
|
| - capture_timer_.Stop();
|
| - } else {
|
| - if (received_first_frame_request_) {
|
| - StartCaptureTimer();
|
| - }
|
| - }
|
| + scheduler_->Pause(pause);
|
| }
|
|
|
| void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) {
|
| @@ -173,50 +171,27 @@ void WebrtcVideoStream::SetObserver(Observer* observer) {
|
| void WebrtcVideoStream::SetKeyFrameRequest() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - key_frame_request_ = true;
|
| + scheduler_->SetKeyFrameRequest();
|
| +
|
| + // Create capture scheduler when the first key frame request is received.
|
| if (!received_first_frame_request_) {
|
| received_first_frame_request_ = true;
|
| - StartCaptureTimer();
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&WebrtcVideoStream::StartCaptureTimer,
|
| - weak_factory_.GetWeakPtr()));
|
| + scheduler_->Start(base::Bind(&WebrtcVideoStream::CaptureNextFrame,
|
| + base::Unretained(this)));
|
| }
|
| }
|
|
|
| -void WebrtcVideoStream::StartCaptureTimer() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - capture_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this,
|
| - &WebrtcVideoStream::CaptureNextFrame);
|
| -}
|
| -
|
| void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| VLOG(1) << "Set Target bitrate " << target_bitrate_kbps;
|
| - target_bitrate_kbps_ = target_bitrate_kbps;
|
| -}
|
| -
|
| -bool WebrtcVideoStream::ClearAndGetKeyFrameRequest() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - bool key_frame_request = key_frame_request_;
|
| - key_frame_request_ = false;
|
| - return key_frame_request;
|
| + scheduler_->SetTargetBitrate(target_bitrate_kbps);
|
| }
|
|
|
| void WebrtcVideoStream::OnCaptureResult(
|
| webrtc::DesktopCapturer::Result result,
|
| std::unique_ptr<webrtc::DesktopFrame> frame) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(capture_pending_);
|
| - capture_pending_ = false;
|
| -
|
| -
|
| - if (encode_pending_) {
|
| - // TODO(isheriff): consider queuing here
|
| - VLOG(1) << "Dropping captured frame since encoder is still busy";
|
| - return;
|
| - }
|
|
|
| // TODO(sergeyu): Handle ERROR_PERMANENT result here.
|
|
|
| @@ -235,14 +210,9 @@ void WebrtcVideoStream::OnCaptureResult(
|
| captured_frame_timestamps_->capture_delay =
|
| base::TimeDelta::FromMilliseconds(frame->capture_time_ms());
|
|
|
| - encode_pending_ = true;
|
| -
|
| - // TODO(sergeyu): Currently frame_duration is always set to 1/15 of a second.
|
| - // Experiment with different values, and try changing it dynamically.
|
| WebrtcVideoEncoder::FrameParams frame_params;
|
| - frame_params.bitrate_kbps = target_bitrate_kbps_;
|
| - frame_params.duration = base::TimeDelta::FromSeconds(1) / 15;
|
| - frame_params.key_frame = ClearAndGetKeyFrameRequest();
|
| + if (!scheduler_->GetEncoderFrameParams(*frame, &frame_params))
|
| + return;
|
|
|
| base::PostTaskAndReplyWithResult(
|
| encode_task_runner_.get(), FROM_HERE,
|
| @@ -266,20 +236,6 @@ void WebrtcVideoStream::OnChannelClosed(
|
| void WebrtcVideoStream::CaptureNextFrame() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - if (capture_pending_ || encode_pending_) {
|
| - VLOG(1) << "Capture/encode still pending..";
|
| - return;
|
| - }
|
| -
|
| - base::TimeTicks now = base::TimeTicks::Now();
|
| -
|
| - capture_pending_ = true;
|
| - VLOG(1) << "Capture next frame after "
|
| - << (base::TimeTicks::Now() - last_capture_started_ticks_)
|
| - .InMilliseconds();
|
| - last_capture_started_ticks_ = now;
|
| -
|
| -
|
| // |next_frame_timestamps_| is not set if no input events were received since
|
| // the previous frame. In that case create FrameTimestamps instance without
|
| // setting |input_event_client_timestamp| and |input_event_received_time|.
|
| @@ -287,7 +243,7 @@ void WebrtcVideoStream::CaptureNextFrame() {
|
| next_frame_timestamps_.reset(new FrameTimestamps());
|
|
|
| captured_frame_timestamps_ = std::move(next_frame_timestamps_);
|
| - captured_frame_timestamps_->capture_started_time = now;
|
| + captured_frame_timestamps_->capture_started_time = base::TimeTicks::Now();
|
|
|
| capturer_->Capture(webrtc::DesktopRegion());
|
| }
|
| @@ -309,64 +265,49 @@ WebrtcVideoStream::EncodedFrameWithTimestamps WebrtcVideoStream::EncodeFrame(
|
| void WebrtcVideoStream::OnFrameEncoded(EncodedFrameWithTimestamps frame) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - encode_pending_ = false;
|
| + // Send the frame itself.
|
| + webrtc::EncodedImageCallback::Result result =
|
| + webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
|
| + *frame.frame, frame.timestamps->capture_started_time);
|
| + if (result.error != webrtc::EncodedImageCallback::Result::OK) {
|
| + // TODO(sergeyu): Stop the stream.
|
| + LOG(ERROR) << "Failed to send video frame.";
|
| + return;
|
| + }
|
| +
|
| + scheduler_->OnFrameEncoded(*frame.frame, result);
|
|
|
| - size_t frame_size = frame.frame ? frame.frame->data.size() : 0;
|
| + // Send FrameStats message.
|
| + if (video_stats_dispatcher_.is_connected()) {
|
| + HostFrameStats stats;
|
| + stats.frame_size = frame.frame->data.size();
|
| +
|
| + if (!frame.timestamps->input_event_received_time.is_null()) {
|
| + stats.capture_pending_delay = frame.timestamps->capture_started_time -
|
| + frame.timestamps->input_event_received_time;
|
| + stats.latest_event_timestamp = base::TimeTicks::FromInternalValue(
|
| + frame.timestamps->input_event_client_timestamp);
|
| + }
|
|
|
| - // Generate HostFrameStats.
|
| - HostFrameStats stats;
|
| - stats.frame_size = frame_size;
|
| + stats.capture_delay = frame.timestamps->capture_delay;
|
|
|
| - if (!frame.timestamps->input_event_received_time.is_null()) {
|
| - stats.capture_pending_delay = frame.timestamps->capture_started_time -
|
| - frame.timestamps->input_event_received_time;
|
| - stats.latest_event_timestamp = base::TimeTicks::FromInternalValue(
|
| - frame.timestamps->input_event_client_timestamp);
|
| - }
|
| + // Total overhead time for IPC and threading when capturing frames.
|
| + stats.capture_overhead_delay = (frame.timestamps->capture_ended_time -
|
| + frame.timestamps->capture_started_time) -
|
| + stats.capture_delay;
|
|
|
| - stats.capture_delay = frame.timestamps->capture_delay;
|
| -
|
| - // Total overhead time for IPC and threading when capturing frames.
|
| - stats.capture_overhead_delay = (frame.timestamps->capture_ended_time -
|
| - frame.timestamps->capture_started_time) -
|
| - stats.capture_delay;
|
| -
|
| - stats.encode_pending_delay = frame.timestamps->encode_started_time -
|
| - frame.timestamps->capture_ended_time;
|
| -
|
| - stats.encode_delay = frame.timestamps->encode_ended_time -
|
| - frame.timestamps->encode_started_time;
|
| -
|
| - // TODO(sergeyu): Figure out how to measure send_pending time with WebRTC and
|
| - // set it here.
|
| - stats.send_pending_delay = base::TimeDelta();
|
| -
|
| - uint32_t frame_id = 0;
|
| - if (frame.frame) {
|
| - // Send the frame itself.
|
| - webrtc::EncodedImageCallback::Result result =
|
| - webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
|
| - std::move(frame.frame), frame.timestamps->capture_started_time);
|
| - if (result.error != webrtc::EncodedImageCallback::Result::OK) {
|
| - // TODO(sergeyu): Stop the stream.
|
| - LOG(ERROR) << "Failed to send video frame.";
|
| - return;
|
| - }
|
| - frame_id = result.frame_id;
|
| - }
|
| + stats.encode_pending_delay = frame.timestamps->encode_started_time -
|
| + frame.timestamps->capture_ended_time;
|
|
|
| - // Send FrameStats message.
|
| - if (video_stats_dispatcher_.is_connected())
|
| - video_stats_dispatcher_.OnVideoFrameStats(frame_id, stats);
|
| -
|
| - // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS.
|
| - // TODO(sergeyu): Move this logic to a separate class.
|
| - float encoded_bits = frame_size * 8.0;
|
| - uint32_t next_sched_ms = std::max(
|
| - 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200));
|
| - capture_timer_.Start(FROM_HERE,
|
| - base::TimeDelta::FromMilliseconds(next_sched_ms), this,
|
| - &WebrtcVideoStream::CaptureNextFrame);
|
| + stats.encode_delay = frame.timestamps->encode_ended_time -
|
| + frame.timestamps->encode_started_time;
|
| +
|
| + // TODO(sergeyu): Figure out how to measure send_pending time with WebRTC
|
| + // and set it here.
|
| + stats.send_pending_delay = base::TimeDelta();
|
| +
|
| + video_stats_dispatcher_.OnVideoFrameStats(result.frame_id, stats);
|
| + }
|
| }
|
|
|
| } // namespace protocol
|
|
|