
This turned out to be a bit complicated, mostly related to the tests, but here's what's changed: * No AsyncInvoker (and avoid ClearInternal) in WebRtcVideoSendStream (WVSS) * The reason it was there is due to a "design leak" from VideoSourceSinkController/VideoStreamEncoder where the former uses locks in all methods and is unaware of a threading model. That design affected downstream objects, pushed the need for an async hop into WVSS and added a lock. A suggestion was made to address this in a follow-up change, here: https://webrtc-review.googlesource.com/c/src/+/165684 * All methods in VideoSourceSinkController are now called on a known and checked sequence and this CL removes the lock. This also makes checking state consistent (i.e. calling a getter twice in a row on the same sequence, will always return the same value, avoiding race with other threads). * Handling of reporting state changes from the encoder queue to the VSSC, is done by VideoStreamEncoder. * VideoSendStreamImpl is still instantiated on the incorrect thread [1] but has two initialization steps [2]. The second one already runs on the right thread. Addressing that TODO [1] is something we should do but it has side effects to consider. For the purposes of this CL the steps relating to the encoder (setting the sink pointer) have been moved to [2]. [1] https://source.chromium.org/chromium/chromium/src/+/master:third_party/webrtc/video/video_send_stream.cc;l=94 [2] https://source.chromium.org/chromium/chromium/src/+/master:third_party/webrtc/video/video_send_stream.cc;drc=f4a9991cce74a37d006438ec0e366313ed33162e;l=115 Bug: webrtc:11222, webrtc:11908 Change-Id: Ie46d46e3a52bbe225951b4bd580ecb8cc9cad873 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/184508 Reviewed-by: Henrik Boström <hbos@webrtc.org> Commit-Queue: Tommi <tommi@webrtc.org> Cr-Commit-Position: refs/heads/master@{#32150}
168 lines
5.2 KiB
C++
168 lines
5.2 KiB
C++
/*
|
|
* Copyright 2020 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 "video/video_source_sink_controller.h"
|
|
|
|
#include <algorithm>
|
|
#include <limits>
|
|
#include <utility>
|
|
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/numerics/safe_conversions.h"
|
|
#include "rtc_base/strings/string_builder.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
std::string WantsToString(const rtc::VideoSinkWants& wants) {
|
|
rtc::StringBuilder ss;
|
|
|
|
ss << "max_fps=" << wants.max_framerate_fps
|
|
<< " max_pixel_count=" << wants.max_pixel_count << " target_pixel_count="
|
|
<< (wants.target_pixel_count.has_value()
|
|
? std::to_string(wants.target_pixel_count.value())
|
|
: "null");
|
|
|
|
return ss.Release();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
VideoSourceSinkController::VideoSourceSinkController(
|
|
rtc::VideoSinkInterface<VideoFrame>* sink,
|
|
rtc::VideoSourceInterface<VideoFrame>* source)
|
|
: sink_(sink), source_(source) {
|
|
RTC_DCHECK(sink_);
|
|
}
|
|
|
|
VideoSourceSinkController::~VideoSourceSinkController() {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
}
|
|
|
|
void VideoSourceSinkController::SetSource(
|
|
rtc::VideoSourceInterface<VideoFrame>* source) {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
rtc::VideoSourceInterface<VideoFrame>* old_source = source_;
|
|
source_ = source;
|
|
|
|
if (old_source != source && old_source)
|
|
old_source->RemoveSink(sink_);
|
|
|
|
if (!source)
|
|
return;
|
|
|
|
source->AddOrUpdateSink(sink_, CurrentSettingsToSinkWants());
|
|
}
|
|
|
|
bool VideoSourceSinkController::HasSource() const {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
return source_ != nullptr;
|
|
}
|
|
|
|
void VideoSourceSinkController::PushSourceSinkSettings() {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
if (!source_)
|
|
return;
|
|
rtc::VideoSinkWants wants = CurrentSettingsToSinkWants();
|
|
RTC_LOG(INFO) << "Pushing SourceSink restrictions: " << WantsToString(wants);
|
|
source_->AddOrUpdateSink(sink_, wants);
|
|
}
|
|
|
|
VideoSourceRestrictions VideoSourceSinkController::restrictions() const {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
return restrictions_;
|
|
}
|
|
|
|
absl::optional<size_t> VideoSourceSinkController::pixels_per_frame_upper_limit()
|
|
const {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
return pixels_per_frame_upper_limit_;
|
|
}
|
|
|
|
absl::optional<double> VideoSourceSinkController::frame_rate_upper_limit()
|
|
const {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
return frame_rate_upper_limit_;
|
|
}
|
|
|
|
bool VideoSourceSinkController::rotation_applied() const {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
return rotation_applied_;
|
|
}
|
|
|
|
int VideoSourceSinkController::resolution_alignment() const {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
return resolution_alignment_;
|
|
}
|
|
|
|
void VideoSourceSinkController::SetRestrictions(
|
|
VideoSourceRestrictions restrictions) {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
restrictions_ = std::move(restrictions);
|
|
}
|
|
|
|
void VideoSourceSinkController::SetPixelsPerFrameUpperLimit(
|
|
absl::optional<size_t> pixels_per_frame_upper_limit) {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
pixels_per_frame_upper_limit_ = std::move(pixels_per_frame_upper_limit);
|
|
}
|
|
|
|
void VideoSourceSinkController::SetFrameRateUpperLimit(
|
|
absl::optional<double> frame_rate_upper_limit) {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
frame_rate_upper_limit_ = std::move(frame_rate_upper_limit);
|
|
}
|
|
|
|
void VideoSourceSinkController::SetRotationApplied(bool rotation_applied) {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
rotation_applied_ = rotation_applied;
|
|
}
|
|
|
|
void VideoSourceSinkController::SetResolutionAlignment(
|
|
int resolution_alignment) {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
resolution_alignment_ = resolution_alignment;
|
|
}
|
|
|
|
// RTC_EXCLUSIVE_LOCKS_REQUIRED(sequence_checker_)
|
|
rtc::VideoSinkWants VideoSourceSinkController::CurrentSettingsToSinkWants()
|
|
const {
|
|
rtc::VideoSinkWants wants;
|
|
wants.rotation_applied = rotation_applied_;
|
|
// |wants.black_frames| is not used, it always has its default value false.
|
|
wants.max_pixel_count =
|
|
rtc::dchecked_cast<int>(restrictions_.max_pixels_per_frame().value_or(
|
|
std::numeric_limits<int>::max()));
|
|
wants.target_pixel_count =
|
|
restrictions_.target_pixels_per_frame().has_value()
|
|
? absl::optional<int>(rtc::dchecked_cast<int>(
|
|
restrictions_.target_pixels_per_frame().value()))
|
|
: absl::nullopt;
|
|
wants.max_framerate_fps =
|
|
restrictions_.max_frame_rate().has_value()
|
|
? static_cast<int>(restrictions_.max_frame_rate().value())
|
|
: std::numeric_limits<int>::max();
|
|
wants.resolution_alignment = resolution_alignment_;
|
|
wants.max_pixel_count =
|
|
std::min(wants.max_pixel_count,
|
|
rtc::dchecked_cast<int>(pixels_per_frame_upper_limit_.value_or(
|
|
std::numeric_limits<int>::max())));
|
|
wants.max_framerate_fps =
|
|
std::min(wants.max_framerate_fps,
|
|
frame_rate_upper_limit_.has_value()
|
|
? static_cast<int>(frame_rate_upper_limit_.value())
|
|
: std::numeric_limits<int>::max());
|
|
return wants;
|
|
}
|
|
|
|
} // namespace webrtc
|