Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit 54bd848

Browse files
Ilya NikolaevskiyCommit Bot
authored andcommitted
Merge to M88: Enable initial frame drop for single stream/layer
This is merge of 4 separate CLs: 1) Enable initial frame drop for SVC 'singlecast' Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/195542 (cherry picked from commit cde4a9f) 2) Reset initial frame dropper if the stream changes for external reasons External reasons here are simulcast configuration and source resolution change. Initial frame dropper should be enabled in these cases because the client can request way too big resolution for available bitrate and usual quality scaling would take too long. Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/195004 (cherry picked from commit 84bc348) 3) Adjust min bitrate for the first active stream Without this change, if the user disables QVGA and VGA streams via |active| flags in SetParamters, the resulting stream would have too high min bitrate. This would lead to bad performance and low quality adaptation rate. Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/195325 (cherry picked from commit d381194) 4) Enable initial frame drop for one active simulcast layer. Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/193840 (cherry picked from commit f46723c) No-Try: True Bug: chromium:1153693 Change-Id: I7f31f85b5da2afdfd79e9c6f92d9a5a629cf18f7 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/195940 Commit-Queue: Mirko Bonadei <[email protected]> Reviewed-by: Åsa Persson <[email protected]> Cr-Commit-Position: refs/branch-heads/4324@{#2} Cr-Branched-From: daab689-refs/heads/master@{#32599}
1 parent 93779d8 commit 54bd848

7 files changed

+492
-22
lines changed

media/engine/webrtc_video_engine.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3621,6 +3621,32 @@ EncoderStreamFactory::CreateSimulcastOrConferenceModeScreenshareStreams(
36213621
BoostMaxSimulcastLayer(
36223622
webrtc::DataRate::BitsPerSec(encoder_config.max_bitrate_bps), &layers);
36233623
}
3624+
3625+
// Sort the layers by max_bitrate_bps, they might not always be from
3626+
// smallest to biggest
3627+
std::vector<size_t> index(layers.size());
3628+
std::iota(index.begin(), index.end(), 0);
3629+
std::stable_sort(index.begin(), index.end(), [&layers](size_t a, size_t b) {
3630+
return layers[a].max_bitrate_bps < layers[b].max_bitrate_bps;
3631+
});
3632+
3633+
if (!layers[index[0]].active) {
3634+
// Adjust min bitrate of the first active layer to allow it to go as low as
3635+
// the lowest (now inactive) layer could.
3636+
// Otherwise, if e.g. a single HD stream is active, it would have 600kbps
3637+
// min bitrate, which would always be allocated to the stream.
3638+
// This would lead to congested network, dropped frames and overall bad
3639+
// experience.
3640+
3641+
const int min_configured_bitrate = layers[index[0]].min_bitrate_bps;
3642+
for (size_t i = 0; i < layers.size(); ++i) {
3643+
if (layers[index[i]].active) {
3644+
layers[index[i]].min_bitrate_bps = min_configured_bitrate;
3645+
break;
3646+
}
3647+
}
3648+
}
3649+
36243650
return layers;
36253651
}
36263652

media/engine/webrtc_video_engine_unittest.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7878,6 +7878,59 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersMultipleEncodingsActive) {
78787878
EXPECT_TRUE(channel_->SetVideoSend(primary_ssrc, nullptr, nullptr));
78797879
}
78807880

7881+
// Tests that when some streams are disactivated then the lowest
7882+
// stream min_bitrate would be reused for the first active stream.
7883+
TEST_F(WebRtcVideoChannelTest,
7884+
SetRtpSendParametersSetsMinBitrateForFirstActiveStream) {
7885+
// Create the stream params with multiple ssrcs for simulcast.
7886+
const size_t kNumSimulcastStreams = 3;
7887+
std::vector<uint32_t> ssrcs = MAKE_VECTOR(kSsrcs3);
7888+
StreamParams stream_params = CreateSimStreamParams("cname", ssrcs);
7889+
FakeVideoSendStream* fake_video_send_stream = AddSendStream(stream_params);
7890+
uint32_t primary_ssrc = stream_params.first_ssrc();
7891+
7892+
// Using the FrameForwarder, we manually send a full size
7893+
// frame. This allows us to test that ReconfigureEncoder is called
7894+
// appropriately.
7895+
webrtc::test::FrameForwarder frame_forwarder;
7896+
VideoOptions options;
7897+
EXPECT_TRUE(channel_->SetVideoSend(primary_ssrc, &options, &frame_forwarder));
7898+
channel_->SetSend(true);
7899+
frame_forwarder.IncomingCapturedFrame(frame_source_.GetFrame(
7900+
1920, 1080, webrtc::VideoRotation::kVideoRotation_0,
7901+
rtc::kNumMicrosecsPerSec / 30));
7902+
7903+
// Check that all encodings are initially active.
7904+
webrtc::RtpParameters parameters =
7905+
channel_->GetRtpSendParameters(primary_ssrc);
7906+
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
7907+
EXPECT_TRUE(parameters.encodings[0].active);
7908+
EXPECT_TRUE(parameters.encodings[1].active);
7909+
EXPECT_TRUE(parameters.encodings[2].active);
7910+
EXPECT_TRUE(fake_video_send_stream->IsSending());
7911+
7912+
// Only turn on the highest stream.
7913+
parameters.encodings[0].active = false;
7914+
parameters.encodings[1].active = false;
7915+
parameters.encodings[2].active = true;
7916+
EXPECT_TRUE(channel_->SetRtpSendParameters(primary_ssrc, parameters).ok());
7917+
7918+
// Check that the VideoSendStream is updated appropriately. This means its
7919+
// send state was updated and it was reconfigured.
7920+
EXPECT_TRUE(fake_video_send_stream->IsSending());
7921+
std::vector<webrtc::VideoStream> simulcast_streams =
7922+
fake_video_send_stream->GetVideoStreams();
7923+
EXPECT_EQ(kNumSimulcastStreams, simulcast_streams.size());
7924+
EXPECT_FALSE(simulcast_streams[0].active);
7925+
EXPECT_FALSE(simulcast_streams[1].active);
7926+
EXPECT_TRUE(simulcast_streams[2].active);
7927+
7928+
EXPECT_EQ(simulcast_streams[2].min_bitrate_bps,
7929+
simulcast_streams[0].min_bitrate_bps);
7930+
7931+
EXPECT_TRUE(channel_->SetVideoSend(primary_ssrc, nullptr, nullptr));
7932+
}
7933+
78817934
// Test that if a stream is reconfigured (due to a codec change or other
78827935
// change) while its encoding is still inactive, it doesn't start sending.
78837936
TEST_F(WebRtcVideoChannelTest,

video/adaptation/video_stream_encoder_resource_manager.cc

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "video/adaptation/video_stream_encoder_resource_manager.h"
1212

13+
#include <algorithm>
1314
#include <cmath>
1415
#include <limits>
1516
#include <memory>
@@ -58,6 +59,52 @@ std::string ToString(VideoAdaptationReason reason) {
5859
RTC_CHECK_NOTREACHED();
5960
}
6061

62+
absl::optional<uint32_t> GetSingleActiveStreamPixels(const VideoCodec& codec) {
63+
int num_active = 0;
64+
absl::optional<uint32_t> pixels;
65+
if (codec.codecType == VideoCodecType::kVideoCodecVP9) {
66+
for (int i = 0; i < codec.VP9().numberOfSpatialLayers; ++i) {
67+
if (codec.spatialLayers[i].active) {
68+
++num_active;
69+
pixels = codec.spatialLayers[i].width * codec.spatialLayers[i].height;
70+
}
71+
}
72+
} else {
73+
for (int i = 0; i < codec.numberOfSimulcastStreams; ++i) {
74+
if (codec.simulcastStream[i].active) {
75+
++num_active;
76+
pixels =
77+
codec.simulcastStream[i].width * codec.simulcastStream[i].height;
78+
}
79+
}
80+
}
81+
if (num_active > 1)
82+
return absl::nullopt;
83+
return pixels;
84+
}
85+
86+
std::vector<bool> GetActiveLayersFlags(const VideoCodec& codec) {
87+
std::vector<bool> flags;
88+
if (codec.codecType == VideoCodecType::kVideoCodecVP9) {
89+
flags.resize(codec.VP9().numberOfSpatialLayers);
90+
for (size_t i = 0; i < flags.size(); ++i) {
91+
flags[i] = codec.spatialLayers[i].active;
92+
}
93+
} else {
94+
flags.resize(codec.numberOfSimulcastStreams);
95+
for (size_t i = 0; i < flags.size(); ++i) {
96+
flags[i] = codec.simulcastStream[i].active;
97+
}
98+
}
99+
return flags;
100+
}
101+
102+
bool EqualFlags(const std::vector<bool>& a, const std::vector<bool>& b) {
103+
if (a.size() != b.size())
104+
return false;
105+
return std::equal(a.begin(), a.end(), b.begin());
106+
}
107+
61108
} // namespace
62109

63110
class VideoStreamEncoderResourceManager::InitialFrameDropper {
@@ -69,7 +116,9 @@ class VideoStreamEncoderResourceManager::InitialFrameDropper {
69116
has_seen_first_bwe_drop_(false),
70117
set_start_bitrate_(DataRate::Zero()),
71118
set_start_bitrate_time_ms_(0),
72-
initial_framedrop_(0) {
119+
initial_framedrop_(0),
120+
last_input_width_(0),
121+
last_input_height_(0) {
73122
RTC_DCHECK(quality_scaler_resource_);
74123
}
75124

@@ -78,6 +127,10 @@ class VideoStreamEncoderResourceManager::InitialFrameDropper {
78127
return initial_framedrop_ < kMaxInitialFramedrop;
79128
}
80129

130+
absl::optional<uint32_t> single_active_stream_pixels() const {
131+
return single_active_stream_pixels_;
132+
}
133+
81134
// Input signals.
82135
void SetStartBitrate(DataRate start_bitrate, int64_t now_ms) {
83136
set_start_bitrate_ = start_bitrate;
@@ -104,9 +157,38 @@ class VideoStreamEncoderResourceManager::InitialFrameDropper {
104157
}
105158
}
106159

160+
void OnEncoderSettingsUpdated(
161+
const VideoCodec& codec,
162+
const VideoAdaptationCounters& adaptation_counters) {
163+
std::vector<bool> active_flags = GetActiveLayersFlags(codec);
164+
// Check if the source resolution has changed for the external reasons,
165+
// i.e. without any adaptation from WebRTC.
166+
const bool source_resolution_changed =
167+
(last_input_width_ != codec.width ||
168+
last_input_height_ != codec.height) &&
169+
adaptation_counters.resolution_adaptations ==
170+
last_adaptation_counters_.resolution_adaptations;
171+
if (!EqualFlags(active_flags, last_active_flags_) ||
172+
source_resolution_changed) {
173+
// Streams configuration has changed.
174+
// Initial frame drop must be enabled because BWE might be way too low
175+
// for the selected resolution.
176+
if (quality_scaler_resource_->is_started()) {
177+
RTC_LOG(LS_INFO) << "Resetting initial_framedrop_ due to changed "
178+
"stream parameters";
179+
initial_framedrop_ = 0;
180+
}
181+
}
182+
last_adaptation_counters_ = adaptation_counters;
183+
last_active_flags_ = active_flags;
184+
last_input_width_ = codec.width;
185+
last_input_height_ = codec.height;
186+
single_active_stream_pixels_ = GetSingleActiveStreamPixels(codec);
187+
}
188+
107189
void OnFrameDroppedDueToSize() { ++initial_framedrop_; }
108190

109-
void OnMaybeEncodeFrame() { initial_framedrop_ = kMaxInitialFramedrop; }
191+
void Disable() { initial_framedrop_ = kMaxInitialFramedrop; }
110192

111193
void OnQualityScalerSettingsUpdated() {
112194
if (quality_scaler_resource_->is_started()) {
@@ -130,6 +212,12 @@ class VideoStreamEncoderResourceManager::InitialFrameDropper {
130212
int64_t set_start_bitrate_time_ms_;
131213
// Counts how many frames we've dropped in the initial framedrop phase.
132214
int initial_framedrop_;
215+
absl::optional<uint32_t> single_active_stream_pixels_;
216+
217+
std::vector<bool> last_active_flags_;
218+
VideoAdaptationCounters last_adaptation_counters_;
219+
int last_input_width_;
220+
int last_input_height_;
133221
};
134222

135223
VideoStreamEncoderResourceManager::VideoStreamEncoderResourceManager(
@@ -230,7 +318,7 @@ void VideoStreamEncoderResourceManager::AddResource(
230318
RTC_DCHECK(resource);
231319
bool inserted;
232320
std::tie(std::ignore, inserted) = resources_.emplace(resource, reason);
233-
RTC_DCHECK(inserted) << "Resurce " << resource->Name()
321+
RTC_DCHECK(inserted) << "Resource " << resource->Name()
234322
<< " already was inserted";
235323
adaptation_processor_->AddResource(resource);
236324
}
@@ -259,6 +347,8 @@ void VideoStreamEncoderResourceManager::SetEncoderSettings(
259347
RTC_DCHECK_RUN_ON(encoder_queue_);
260348
encoder_settings_ = std::move(encoder_settings);
261349
bitrate_constraint_->OnEncoderSettingsUpdated(encoder_settings_);
350+
initial_frame_dropper_->OnEncoderSettingsUpdated(
351+
encoder_settings_->video_codec(), current_adaptation_counters_);
262352
MaybeUpdateTargetFrameRate();
263353
}
264354

@@ -339,9 +429,15 @@ bool VideoStreamEncoderResourceManager::DropInitialFrames() const {
339429
return initial_frame_dropper_->DropInitialFrames();
340430
}
341431

432+
absl::optional<uint32_t>
433+
VideoStreamEncoderResourceManager::SingleActiveStreamPixels() const {
434+
RTC_DCHECK_RUN_ON(encoder_queue_);
435+
return initial_frame_dropper_->single_active_stream_pixels();
436+
}
437+
342438
void VideoStreamEncoderResourceManager::OnMaybeEncodeFrame() {
343439
RTC_DCHECK_RUN_ON(encoder_queue_);
344-
initial_frame_dropper_->OnMaybeEncodeFrame();
440+
initial_frame_dropper_->Disable();
345441
if (quality_rampup_experiment_ && quality_scaler_resource_->is_started()) {
346442
DataRate bandwidth = encoder_rates_.has_value()
347443
? encoder_rates_->bandwidth_allocation
@@ -457,6 +553,8 @@ void VideoStreamEncoderResourceManager::OnVideoSourceRestrictionsUpdated(
457553
rtc::scoped_refptr<Resource> reason,
458554
const VideoSourceRestrictions& unfiltered_restrictions) {
459555
RTC_DCHECK_RUN_ON(encoder_queue_);
556+
current_adaptation_counters_ = adaptation_counters;
557+
460558
// TODO(bugs.webrtc.org/11553) Remove reason parameter and add reset callback.
461559
if (!reason && adaptation_counters.Total() == 0) {
462560
// Adaptation was manually reset - clear the per-reason counters too.

video/adaptation/video_stream_encoder_resource_manager.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ class VideoStreamEncoderResourceManager
121121
VideoAdaptationReason reason);
122122
void RemoveResource(rtc::scoped_refptr<Resource> resource);
123123
std::vector<AdaptationConstraint*> AdaptationConstraints() const;
124-
// If true, the VideoStreamEncoder should eexecute its logic to maybe drop
125-
// frames baseed on size and bitrate.
124+
// If true, the VideoStreamEncoder should execute its logic to maybe drop
125+
// frames based on size and bitrate.
126126
bool DropInitialFrames() const;
127+
absl::optional<uint32_t> SingleActiveStreamPixels() const;
127128

128129
// VideoSourceRestrictionsListener implementation.
129130
// Updates |video_source_restrictions_|.
@@ -183,6 +184,9 @@ class VideoStreamEncoderResourceManager
183184
VideoSourceRestrictions video_source_restrictions_
184185
RTC_GUARDED_BY(encoder_queue_);
185186

187+
VideoAdaptationCounters current_adaptation_counters_
188+
RTC_GUARDED_BY(encoder_queue_);
189+
186190
const BalancedDegradationSettings balanced_settings_;
187191
Clock* clock_ RTC_GUARDED_BY(encoder_queue_);
188192
const bool experiment_cpu_load_estimator_ RTC_GUARDED_BY(encoder_queue_);

0 commit comments

Comments
 (0)