blob: 730c256dad3855fa1bbaa8eac210f7ad53f79471 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/protocol/webrtc_video_track_source.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/task/sequenced_task_runner.h"
#include "remoting/base/logging.h"
#include "remoting/protocol/webrtc_video_frame_adapter.h"
#include "third_party/webrtc/api/video/video_frame.h"
namespace remoting::protocol {
WebrtcVideoTrackSource::WebrtcVideoTrackSource(
AddSinkCallback add_sink_callback)
: add_sink_callback_(add_sink_callback),
main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}
WebrtcVideoTrackSource::~WebrtcVideoTrackSource() = default;
webrtc::MediaSourceInterface::SourceState WebrtcVideoTrackSource::state()
const {
return kLive;
}
bool WebrtcVideoTrackSource::remote() const {
return false;
}
bool WebrtcVideoTrackSource::is_screencast() const {
return true;
}
std::optional<bool> WebrtcVideoTrackSource::needs_denoising() const {
return std::nullopt;
}
bool WebrtcVideoTrackSource::GetStats(
webrtc::VideoTrackSourceInterface::Stats* stats) {
return false;
}
void WebrtcVideoTrackSource::AddOrUpdateSink(
webrtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
const webrtc::VideoSinkWants& wants) {
DCHECK(sink);
if (sink_ && (sink != sink_)) {
// The same sink can be added more than once, but there should only be 1
// in total.
LOG(WARNING) << "More than one sink added, only the latest will be used.";
}
sink_ = sink;
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(add_sink_callback_, wants)
.Then(base::BindOnce(&WebrtcVideoTrackSource::SendPendingFrame,
weak_ptr_factory_.GetWeakPtr())));
}
void WebrtcVideoTrackSource::RemoveSink(
webrtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
DCHECK(sink);
if (sink != sink_) {
// This might happen if more than one sink was added.
LOG(WARNING) << "RemoveSink() called with unexpected sink.";
return;
}
sink_ = nullptr;
}
bool WebrtcVideoTrackSource::SupportsEncodedOutput() const {
return false;
}
void WebrtcVideoTrackSource::GenerateKeyFrame() {}
void WebrtcVideoTrackSource::AddEncodedSink(
webrtc::VideoSinkInterface<webrtc::RecordableEncodedFrame>* sink) {}
void WebrtcVideoTrackSource::RemoveEncodedSink(
webrtc::VideoSinkInterface<webrtc::RecordableEncodedFrame>* sink) {}
void WebrtcVideoTrackSource::SendCapturedFrame(
std::unique_ptr<webrtc::DesktopFrame> desktop_frame,
std::unique_ptr<WebrtcVideoEncoder::FrameStats> frame_stats) {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
webrtc::VideoFrame video_frame = WebrtcVideoFrameAdapter::CreateVideoFrame(
std::move(desktop_frame), std::move(frame_stats));
// Wrap-around behavior of '++' is defined for unsigned types.
// VideoFrame::id() is a 16-bit number which could wrap back to 0 many times
// during a connection.
video_frame.set_id(frame_id_++);
if (sink_) {
sink_->OnFrame(video_frame);
return;
}
HOST_LOG << "Frame will be sent to the sink after the sink is registered.";
pending_frame_ = std::make_unique<webrtc::VideoFrame>(std::move(video_frame));
// Make the entire frame dirty.
pending_frame_->set_update_rect(webrtc::VideoFrame::UpdateRect{
.offset_x = 0,
.offset_y = 0,
.width = video_frame.width(),
.height = video_frame.height(),
});
}
void WebrtcVideoTrackSource::SendPendingFrame() {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
if (!pending_frame_) {
return;
}
HOST_LOG << "Sending pending frame to the sink.";
sink_->OnFrame(std::move(*pending_frame_));
pending_frame_.reset();
}
} // namespace remoting::protocol