Enable initial frame drop for one active simulcast layer.
Bug: webrtc:12216 Change-Id: Ib2ac2fab45e560ba3eae30a926ce72667a257b07 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/193840 Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Åsa Persson <asapersson@webrtc.org> Cr-Commit-Position: refs/heads/master@{#32652}
This commit is contained in:
parent
766a32c28d
commit
f46723c8aa
@ -58,6 +58,20 @@ std::string ToString(VideoAdaptationReason reason) {
|
||||
RTC_CHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
absl::optional<uint32_t> GetSingleActiveStreamPixels(const VideoCodec& codec) {
|
||||
int num_active = 0;
|
||||
absl::optional<uint32_t> pixels;
|
||||
for (int i = 0; i < codec.numberOfSimulcastStreams; ++i) {
|
||||
if (codec.simulcastStream[i].active) {
|
||||
++num_active;
|
||||
pixels = codec.simulcastStream[i].width * codec.simulcastStream[i].height;
|
||||
}
|
||||
if (num_active > 1)
|
||||
return absl::nullopt;
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class VideoStreamEncoderResourceManager::InitialFrameDropper {
|
||||
@ -78,6 +92,10 @@ class VideoStreamEncoderResourceManager::InitialFrameDropper {
|
||||
return initial_framedrop_ < kMaxInitialFramedrop;
|
||||
}
|
||||
|
||||
absl::optional<uint32_t> single_active_stream_pixels() const {
|
||||
return single_active_stream_pixels_;
|
||||
}
|
||||
|
||||
// Input signals.
|
||||
void SetStartBitrate(DataRate start_bitrate, int64_t now_ms) {
|
||||
set_start_bitrate_ = start_bitrate;
|
||||
@ -104,6 +122,10 @@ class VideoStreamEncoderResourceManager::InitialFrameDropper {
|
||||
}
|
||||
}
|
||||
|
||||
void OnEncoderSettingsUpdated(const VideoCodec& codec) {
|
||||
single_active_stream_pixels_ = GetSingleActiveStreamPixels(codec);
|
||||
}
|
||||
|
||||
void OnFrameDroppedDueToSize() { ++initial_framedrop_; }
|
||||
|
||||
void OnMaybeEncodeFrame() { initial_framedrop_ = kMaxInitialFramedrop; }
|
||||
@ -130,6 +152,7 @@ class VideoStreamEncoderResourceManager::InitialFrameDropper {
|
||||
int64_t set_start_bitrate_time_ms_;
|
||||
// Counts how many frames we've dropped in the initial framedrop phase.
|
||||
int initial_framedrop_;
|
||||
absl::optional<uint32_t> single_active_stream_pixels_;
|
||||
};
|
||||
|
||||
VideoStreamEncoderResourceManager::VideoStreamEncoderResourceManager(
|
||||
@ -230,7 +253,7 @@ void VideoStreamEncoderResourceManager::AddResource(
|
||||
RTC_DCHECK(resource);
|
||||
bool inserted;
|
||||
std::tie(std::ignore, inserted) = resources_.emplace(resource, reason);
|
||||
RTC_DCHECK(inserted) << "Resurce " << resource->Name()
|
||||
RTC_DCHECK(inserted) << "Resource " << resource->Name()
|
||||
<< " already was inserted";
|
||||
adaptation_processor_->AddResource(resource);
|
||||
}
|
||||
@ -259,6 +282,8 @@ void VideoStreamEncoderResourceManager::SetEncoderSettings(
|
||||
RTC_DCHECK_RUN_ON(encoder_queue_);
|
||||
encoder_settings_ = std::move(encoder_settings);
|
||||
bitrate_constraint_->OnEncoderSettingsUpdated(encoder_settings_);
|
||||
initial_frame_dropper_->OnEncoderSettingsUpdated(
|
||||
encoder_settings_->video_codec());
|
||||
MaybeUpdateTargetFrameRate();
|
||||
}
|
||||
|
||||
@ -339,6 +364,12 @@ bool VideoStreamEncoderResourceManager::DropInitialFrames() const {
|
||||
return initial_frame_dropper_->DropInitialFrames();
|
||||
}
|
||||
|
||||
absl::optional<uint32_t>
|
||||
VideoStreamEncoderResourceManager::SingleActiveStreamPixels() const {
|
||||
RTC_DCHECK_RUN_ON(encoder_queue_);
|
||||
return initial_frame_dropper_->single_active_stream_pixels();
|
||||
}
|
||||
|
||||
void VideoStreamEncoderResourceManager::OnMaybeEncodeFrame() {
|
||||
RTC_DCHECK_RUN_ON(encoder_queue_);
|
||||
initial_frame_dropper_->OnMaybeEncodeFrame();
|
||||
|
||||
@ -121,9 +121,10 @@ class VideoStreamEncoderResourceManager
|
||||
VideoAdaptationReason reason);
|
||||
void RemoveResource(rtc::scoped_refptr<Resource> resource);
|
||||
std::vector<AdaptationConstraint*> AdaptationConstraints() const;
|
||||
// If true, the VideoStreamEncoder should eexecute its logic to maybe drop
|
||||
// frames baseed on size and bitrate.
|
||||
// If true, the VideoStreamEncoder should execute its logic to maybe drop
|
||||
// frames based on size and bitrate.
|
||||
bool DropInitialFrames() const;
|
||||
absl::optional<uint32_t> SingleActiveStreamPixels() const;
|
||||
|
||||
// VideoSourceRestrictionsListener implementation.
|
||||
// Updates |video_source_restrictions_|.
|
||||
|
||||
@ -56,6 +56,7 @@ class QualityScalingTest : public test::CallTest {
|
||||
protected:
|
||||
void RunTest(VideoEncoderFactory* encoder_factory,
|
||||
const std::string& payload_name,
|
||||
const std::vector<bool>& streams_active,
|
||||
int start_bps,
|
||||
bool automatic_resize,
|
||||
bool frame_dropping,
|
||||
@ -67,6 +68,7 @@ class QualityScalingTest : public test::CallTest {
|
||||
|
||||
void QualityScalingTest::RunTest(VideoEncoderFactory* encoder_factory,
|
||||
const std::string& payload_name,
|
||||
const std::vector<bool>& streams_active,
|
||||
int start_bps,
|
||||
bool automatic_resize,
|
||||
bool frame_dropping,
|
||||
@ -77,6 +79,7 @@ void QualityScalingTest::RunTest(VideoEncoderFactory* encoder_factory,
|
||||
public:
|
||||
ScalingObserver(VideoEncoderFactory* encoder_factory,
|
||||
const std::string& payload_name,
|
||||
const std::vector<bool>& streams_active,
|
||||
int start_bps,
|
||||
bool automatic_resize,
|
||||
bool frame_dropping,
|
||||
@ -84,6 +87,7 @@ void QualityScalingTest::RunTest(VideoEncoderFactory* encoder_factory,
|
||||
: SendTest(expect_adaptation ? kDefaultTimeoutMs : kTimeoutMs),
|
||||
encoder_factory_(encoder_factory),
|
||||
payload_name_(payload_name),
|
||||
streams_active_(streams_active),
|
||||
start_bps_(start_bps),
|
||||
automatic_resize_(automatic_resize),
|
||||
frame_dropping_(frame_dropping),
|
||||
@ -108,6 +112,10 @@ void QualityScalingTest::RunTest(VideoEncoderFactory* encoder_factory,
|
||||
bitrate_config->start_bitrate_bps = start_bps_;
|
||||
}
|
||||
|
||||
size_t GetNumVideoStreams() const override {
|
||||
return streams_active_.size();
|
||||
}
|
||||
|
||||
void ModifyVideoConfigs(
|
||||
VideoSendStream::Config* send_config,
|
||||
std::vector<VideoReceiveStream::Config>* receive_configs,
|
||||
@ -117,7 +125,15 @@ void QualityScalingTest::RunTest(VideoEncoderFactory* encoder_factory,
|
||||
send_config->rtp.payload_type = kVideoSendPayloadType;
|
||||
const VideoCodecType codec_type = PayloadStringToCodecType(payload_name_);
|
||||
encoder_config->codec_type = codec_type;
|
||||
encoder_config->max_bitrate_bps = start_bps_;
|
||||
encoder_config->max_bitrate_bps =
|
||||
std::max(start_bps_, encoder_config->max_bitrate_bps);
|
||||
double scale_factor = 1.0;
|
||||
for (int i = streams_active_.size() - 1; i >= 0; --i) {
|
||||
VideoStream& stream = encoder_config->simulcast_layers[i];
|
||||
stream.active = streams_active_[i];
|
||||
stream.scale_resolution_down_by = scale_factor;
|
||||
scale_factor *= 2.0;
|
||||
}
|
||||
SetEncoderSpecific(encoder_config, codec_type, automatic_resize_,
|
||||
frame_dropping_);
|
||||
}
|
||||
@ -129,12 +145,13 @@ void QualityScalingTest::RunTest(VideoEncoderFactory* encoder_factory,
|
||||
|
||||
VideoEncoderFactory* const encoder_factory_;
|
||||
const std::string payload_name_;
|
||||
const std::vector<bool> streams_active_;
|
||||
const int start_bps_;
|
||||
const bool automatic_resize_;
|
||||
const bool frame_dropping_;
|
||||
const bool expect_adaptation_;
|
||||
} test(encoder_factory, payload_name, start_bps, automatic_resize,
|
||||
frame_dropping, expect_adaptation);
|
||||
} test(encoder_factory, payload_name, streams_active, start_bps,
|
||||
automatic_resize, frame_dropping, expect_adaptation);
|
||||
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
@ -150,7 +167,7 @@ TEST_F(QualityScalingTest, AdaptsDownForHighQp_Vp8) {
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "VP8", {true}, kHighStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
@ -165,7 +182,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForHighQpWithResizeOff_Vp8) {
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "VP8", {true}, kHighStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
@ -182,7 +199,7 @@ TEST_F(QualityScalingTest,
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "VP8", {true}, kHighStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
@ -197,7 +214,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForNormalQp_Vp8) {
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "VP8", {true}, kHighStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
@ -212,10 +229,57 @@ TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrate) {
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", kLowStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "VP8", {true}, kLowStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrate_Simulcast) {
|
||||
// VP8 QP thresholds, low:1, high:127 -> normal QP.
|
||||
test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
|
||||
|
||||
// QualityScaler disabled.
|
||||
const bool kAutomaticResize = false;
|
||||
const bool kFrameDropping = true;
|
||||
const bool kExpectAdapt = false;
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", {true, true}, kLowStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalingTest,
|
||||
AdaptsDownForLowStartBitrate_SimulcastOneActiveHighRes) {
|
||||
// VP8 QP thresholds, low:1, high:127 -> normal QP.
|
||||
test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
|
||||
|
||||
// QualityScaler enabled.
|
||||
const bool kAutomaticResize = true;
|
||||
const bool kFrameDropping = true;
|
||||
const bool kExpectAdapt = true;
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", {false, false, true}, kLowStartBps,
|
||||
kAutomaticResize, kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalingTest,
|
||||
NoAdaptDownForLowStartBitrate_SimulcastOneActiveLowRes) {
|
||||
// VP8 QP thresholds, low:1, high:127 -> normal QP.
|
||||
test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
|
||||
|
||||
// QualityScaler enabled.
|
||||
const bool kAutomaticResize = true;
|
||||
const bool kFrameDropping = true;
|
||||
const bool kExpectAdapt = false;
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", {true, false, false}, kLowStartBps,
|
||||
kAutomaticResize, kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateWithScalingOff) {
|
||||
// VP8 QP thresholds, low:1, high:127 -> normal QP.
|
||||
test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
|
||||
@ -227,7 +291,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateWithScalingOff) {
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP8", kLowStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "VP8", {true}, kLowStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
@ -243,7 +307,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForHighQp_Vp9) {
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP9Encoder::Create(); });
|
||||
RunTest(&encoder_factory, "VP9", kHighStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "VP9", {true}, kHighStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
|
||||
@ -259,7 +323,7 @@ TEST_F(QualityScalingTest, AdaptsDownForHighQp_H264) {
|
||||
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return H264Encoder::Create(cricket::VideoCodec("H264")); });
|
||||
RunTest(&encoder_factory, "H264", kHighStartBps, kAutomaticResize,
|
||||
RunTest(&encoder_factory, "H264", {true}, kHighStartBps, kAutomaticResize,
|
||||
kFrameDropping, kExpectAdapt);
|
||||
}
|
||||
#endif // defined(WEBRTC_USE_H264)
|
||||
|
||||
@ -565,6 +565,7 @@ void VideoStreamEncoder::SetSink(EncoderSink* sink, bool rotation_applied) {
|
||||
void VideoStreamEncoder::SetStartBitrate(int start_bitrate_bps) {
|
||||
encoder_queue_.PostTask([this, start_bitrate_bps] {
|
||||
RTC_DCHECK_RUN_ON(&encoder_queue_);
|
||||
RTC_LOG(LS_INFO) << "SetStartBitrate " << start_bitrate_bps;
|
||||
encoder_target_bitrate_bps_ =
|
||||
start_bitrate_bps != 0 ? absl::optional<uint32_t>(start_bitrate_bps)
|
||||
: absl::nullopt;
|
||||
@ -1848,14 +1849,20 @@ bool VideoStreamEncoder::DropDueToSize(uint32_t pixel_count) const {
|
||||
bool simulcast_or_svc =
|
||||
(send_codec_.codecType == VideoCodecType::kVideoCodecVP9 &&
|
||||
send_codec_.VP9().numberOfSpatialLayers > 1) ||
|
||||
send_codec_.numberOfSimulcastStreams > 1 ||
|
||||
encoder_config_.simulcast_layers.size() > 1;
|
||||
((send_codec_.numberOfSimulcastStreams > 1 ||
|
||||
encoder_config_.simulcast_layers.size() > 1) &&
|
||||
!stream_resource_manager_.SingleActiveStreamPixels());
|
||||
|
||||
if (simulcast_or_svc || !stream_resource_manager_.DropInitialFrames() ||
|
||||
!encoder_target_bitrate_bps_.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (send_codec_.numberOfSimulcastStreams > 1 &&
|
||||
stream_resource_manager_.SingleActiveStreamPixels()) {
|
||||
pixel_count = stream_resource_manager_.SingleActiveStreamPixels().value();
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::ResolutionBitrateLimits> encoder_bitrate_limits =
|
||||
encoder_->GetEncoderInfo().GetEncoderBitrateLimitsForResolution(
|
||||
pixel_count);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user