blob: fd7134f12cc5ce3e8ef15774085ae11f4161b663 [file] [log] [blame]
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/media/base/videobroadcaster.h"
#include <limits>
#include "webrtc/base/checks.h"
namespace rtc {
VideoBroadcaster::VideoBroadcaster() {
thread_checker_.DetachFromThread();
}
void VideoBroadcaster::AddOrUpdateSink(
VideoSinkInterface<cricket::VideoFrame>* sink,
const VideoSinkWants& wants) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
RTC_DCHECK(sink != nullptr);
rtc::CritScope cs(&sinks_and_wants_lock_);
VideoSourceBase::AddOrUpdateSink(sink, wants);
UpdateWants();
}
void VideoBroadcaster::RemoveSink(
VideoSinkInterface<cricket::VideoFrame>* sink) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
RTC_DCHECK(sink != nullptr);
rtc::CritScope cs(&sinks_and_wants_lock_);
VideoSourceBase::RemoveSink(sink);
UpdateWants();
}
bool VideoBroadcaster::frame_wanted() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
rtc::CritScope cs(&sinks_and_wants_lock_);
return !sink_pairs().empty();
}
VideoSinkWants VideoBroadcaster::wants() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
rtc::CritScope cs(&sinks_and_wants_lock_);
return current_wants_;
}
void VideoBroadcaster::OnFrame(const cricket::VideoFrame& frame) {
rtc::CritScope cs(&sinks_and_wants_lock_);
for (auto& sink_pair : sink_pairs()) {
if (sink_pair.wants.black_frames) {
sink_pair.sink->OnFrame(GetBlackFrame(frame));
} else {
sink_pair.sink->OnFrame(frame);
}
}
}
void VideoBroadcaster::UpdateWants() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
VideoSinkWants wants;
wants.rotation_applied = false;
for (auto& sink : sink_pairs()) {
// wants.rotation_applied == ANY(sink.wants.rotation_applied)
if (sink.wants.rotation_applied) {
wants.rotation_applied = true;
}
// wants.max_pixel_count == MIN(sink.wants.max_pixel_count)
if (sink.wants.max_pixel_count &&
(!wants.max_pixel_count ||
(*sink.wants.max_pixel_count < *wants.max_pixel_count))) {
wants.max_pixel_count = sink.wants.max_pixel_count;
}
// wants.max_pixel_count_step_up == MIN(sink.wants.max_pixel_count_step_up)
if (sink.wants.max_pixel_count_step_up &&
(!wants.max_pixel_count_step_up ||
(*sink.wants.max_pixel_count_step_up <
*wants.max_pixel_count_step_up))) {
wants.max_pixel_count_step_up = sink.wants.max_pixel_count_step_up;
}
}
if (wants.max_pixel_count && wants.max_pixel_count_step_up &&
*wants.max_pixel_count_step_up >= *wants.max_pixel_count) {
wants.max_pixel_count_step_up = Optional<int>();
}
current_wants_ = wants;
}
const cricket::VideoFrame& VideoBroadcaster::GetBlackFrame(
const cricket::VideoFrame& frame) {
if (black_frame_ && black_frame_->GetWidth() == frame.GetWidth() &&
black_frame_->GetHeight() == frame.GetHeight() &&
black_frame_->GetVideoRotation() == frame.GetVideoRotation()) {
black_frame_->SetTimeStamp(frame.GetTimeStamp());
return *black_frame_;
}
black_frame_.reset(new cricket::WebRtcVideoFrame(
new rtc::RefCountedObject<webrtc::I420Buffer>(
static_cast<int>(frame.GetWidth()),
static_cast<int>(frame.GetHeight())),
frame.GetTimeStamp(), frame.GetVideoRotation()));
black_frame_->SetToBlack();
return *black_frame_;
}
} // namespace rtc