Revert "Enables/disables simulcast streams by allocating a bitrate of 0 to the spatial layer."
This reverts commit 18c4261339dc76b220e7c805e36b4ea6f3dd161d. Reason for revert: Broke internal tests Original change's description: > Enables/disables simulcast streams by allocating a bitrate of 0 to the spatial layer. > > Creates VideoStreams & VideoCodec.simulcastStreams with an active field, and then allocates 0 bitrate to simulcast streams that are inactive. This turns off the encoder for specific simulcast streams. > > Bug: webrtc:8653 > Change-Id: Id93b03dcd8d1191a7d3300bd77882c8af96ee469 > Reviewed-on: https://webrtc-review.googlesource.com/37740 > Reviewed-by: Stefan Holmer <stefan@webrtc.org> > Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org> > Reviewed-by: Erik Språng <sprang@webrtc.org> > Commit-Queue: Seth Hampson <shampson@webrtc.org> > Cr-Commit-Position: refs/heads/master@{#21646} TBR=deadbeef@webrtc.org,sprang@webrtc.org,stefan@webrtc.org,shampson@webrtc.org Change-Id: I0aeb743cbd2e8d564aa732c937587c25a4c49b09 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: webrtc:8653 Reviewed-on: https://webrtc-review.googlesource.com/39883 Reviewed-by: Lu Liu <lliuu@webrtc.org> Commit-Queue: Lu Liu <lliuu@webrtc.org> Cr-Commit-Position: refs/heads/master@{#21647}
This commit is contained in:
@ -37,92 +37,56 @@ void SimulcastRateAllocator::OnTemporalLayersCreated(int simulcast_id,
|
||||
BitrateAllocation SimulcastRateAllocator::GetAllocation(
|
||||
uint32_t total_bitrate_bps,
|
||||
uint32_t framerate) {
|
||||
BitrateAllocation allocated_bitrates_bps;
|
||||
DistributeAllocationToSimulcastLayers(total_bitrate_bps,
|
||||
&allocated_bitrates_bps);
|
||||
DistributeAllocationToTemporalLayers(framerate, &allocated_bitrates_bps);
|
||||
return allocated_bitrates_bps;
|
||||
}
|
||||
|
||||
void SimulcastRateAllocator::DistributeAllocationToSimulcastLayers(
|
||||
uint32_t total_bitrate_bps,
|
||||
BitrateAllocation* allocated_bitrates_bps) {
|
||||
uint32_t left_to_allocate = total_bitrate_bps;
|
||||
if (codec_.maxBitrate && codec_.maxBitrate * 1000 < left_to_allocate)
|
||||
left_to_allocate = codec_.maxBitrate * 1000;
|
||||
|
||||
BitrateAllocation allocated_bitrates_bps;
|
||||
if (codec_.numberOfSimulcastStreams == 0) {
|
||||
// No simulcast, just set the target as this has been capped already.
|
||||
if (codec_.active) {
|
||||
allocated_bitrates_bps->SetBitrate(
|
||||
0, 0, std::max(codec_.minBitrate * 1000, left_to_allocate));
|
||||
allocated_bitrates_bps.SetBitrate(
|
||||
0, 0, std::max(codec_.minBitrate * 1000, left_to_allocate));
|
||||
} else {
|
||||
// Always allocate enough bitrate for the minimum bitrate of the first
|
||||
// layer. Suspending below min bitrate is controlled outside the codec
|
||||
// implementation and is not overridden by this.
|
||||
left_to_allocate =
|
||||
std::max(codec_.simulcastStream[0].minBitrate * 1000, left_to_allocate);
|
||||
|
||||
// Begin by allocating bitrate to simulcast streams, putting all bitrate in
|
||||
// temporal layer 0. We'll then distribute this bitrate, across potential
|
||||
// temporal layers, when stream allocation is done.
|
||||
|
||||
// Allocate up to the target bitrate for each simulcast layer.
|
||||
size_t layer = 0;
|
||||
for (; layer < codec_.numberOfSimulcastStreams; ++layer) {
|
||||
const SimulcastStream& stream = codec_.simulcastStream[layer];
|
||||
if (left_to_allocate < stream.minBitrate * 1000)
|
||||
break;
|
||||
uint32_t allocation =
|
||||
std::min(left_to_allocate, stream.targetBitrate * 1000);
|
||||
allocated_bitrates_bps.SetBitrate(layer, 0, allocation);
|
||||
RTC_DCHECK_LE(allocation, left_to_allocate);
|
||||
left_to_allocate -= allocation;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Find the first active layer. We don't allocate to inactive layers.
|
||||
size_t active_layer = 0;
|
||||
for (; active_layer < codec_.numberOfSimulcastStreams; ++active_layer) {
|
||||
if (codec_.simulcastStream[active_layer].active) {
|
||||
// Found the first active layer.
|
||||
break;
|
||||
|
||||
// Next, try allocate remaining bitrate, up to max bitrate, in top stream.
|
||||
// TODO(sprang): Allocate up to max bitrate for all layers once we have a
|
||||
// better idea of possible performance implications.
|
||||
if (left_to_allocate > 0) {
|
||||
size_t active_layer = layer - 1;
|
||||
const SimulcastStream& stream = codec_.simulcastStream[active_layer];
|
||||
uint32_t bitrate_bps =
|
||||
allocated_bitrates_bps.GetSpatialLayerSum(active_layer);
|
||||
uint32_t allocation =
|
||||
std::min(left_to_allocate, stream.maxBitrate * 1000 - bitrate_bps);
|
||||
bitrate_bps += allocation;
|
||||
RTC_DCHECK_LE(allocation, left_to_allocate);
|
||||
left_to_allocate -= allocation;
|
||||
allocated_bitrates_bps.SetBitrate(active_layer, 0, bitrate_bps);
|
||||
}
|
||||
}
|
||||
// All streams could be inactive, and nothing more to do.
|
||||
if (active_layer == codec_.numberOfSimulcastStreams) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always allocate enough bitrate for the minimum bitrate of the first
|
||||
// active layer. Suspending below min bitrate is controlled outside the
|
||||
// codec implementation and is not overridden by this.
|
||||
left_to_allocate = std::max(
|
||||
codec_.simulcastStream[active_layer].minBitrate * 1000, left_to_allocate);
|
||||
|
||||
// Begin by allocating bitrate to simulcast streams, putting all bitrate in
|
||||
// temporal layer 0. We'll then distribute this bitrate, across potential
|
||||
// temporal layers, when stream allocation is done.
|
||||
|
||||
size_t top_active_layer = active_layer;
|
||||
// Allocate up to the target bitrate for each active simulcast layer.
|
||||
for (; active_layer < codec_.numberOfSimulcastStreams; ++active_layer) {
|
||||
const SimulcastStream& stream = codec_.simulcastStream[active_layer];
|
||||
if (!stream.active) {
|
||||
continue;
|
||||
}
|
||||
// If we can't allocate to the current layer we can't allocate to higher
|
||||
// layers because they require a higher minimum bitrate.
|
||||
if (left_to_allocate < stream.minBitrate * 1000) {
|
||||
break;
|
||||
}
|
||||
// We are allocating to this layer so it is the current active allocation.
|
||||
top_active_layer = active_layer;
|
||||
uint32_t allocation =
|
||||
std::min(left_to_allocate, stream.targetBitrate * 1000);
|
||||
allocated_bitrates_bps->SetBitrate(active_layer, 0, allocation);
|
||||
RTC_DCHECK_LE(allocation, left_to_allocate);
|
||||
left_to_allocate -= allocation;
|
||||
}
|
||||
|
||||
// Next, try allocate remaining bitrate, up to max bitrate, in top active
|
||||
// stream.
|
||||
// TODO(sprang): Allocate up to max bitrate for all layers once we have a
|
||||
// better idea of possible performance implications.
|
||||
if (left_to_allocate > 0) {
|
||||
const SimulcastStream& stream = codec_.simulcastStream[top_active_layer];
|
||||
uint32_t bitrate_bps =
|
||||
allocated_bitrates_bps->GetSpatialLayerSum(top_active_layer);
|
||||
uint32_t allocation =
|
||||
std::min(left_to_allocate, stream.maxBitrate * 1000 - bitrate_bps);
|
||||
bitrate_bps += allocation;
|
||||
RTC_DCHECK_LE(allocation, left_to_allocate);
|
||||
left_to_allocate -= allocation;
|
||||
allocated_bitrates_bps->SetBitrate(top_active_layer, 0, bitrate_bps);
|
||||
}
|
||||
}
|
||||
|
||||
void SimulcastRateAllocator::DistributeAllocationToTemporalLayers(
|
||||
uint32_t framerate,
|
||||
BitrateAllocation* allocated_bitrates_bps) {
|
||||
const int num_spatial_streams =
|
||||
std::max(1, static_cast<int>(codec_.numberOfSimulcastStreams));
|
||||
|
||||
@ -130,21 +94,16 @@ void SimulcastRateAllocator::DistributeAllocationToTemporalLayers(
|
||||
// available temporal layers.
|
||||
for (int simulcast_id = 0; simulcast_id < num_spatial_streams;
|
||||
++simulcast_id) {
|
||||
// TODO(shampson): Consider adding a continue here if the simulcast stream
|
||||
// is inactive. Currently this is not added because the call
|
||||
// below to OnRatesUpdated changes the TemporalLayer's
|
||||
// state.
|
||||
auto tl_it = temporal_layers_.find(simulcast_id);
|
||||
if (tl_it == temporal_layers_.end())
|
||||
continue; // TODO(sprang): If > 1 SS, assume default TL alloc?
|
||||
|
||||
uint32_t target_bitrate_kbps =
|
||||
allocated_bitrates_bps->GetBitrate(simulcast_id, 0) / 1000;
|
||||
|
||||
allocated_bitrates_bps.GetBitrate(simulcast_id, 0) / 1000;
|
||||
const uint32_t expected_allocated_bitrate_kbps = target_bitrate_kbps;
|
||||
RTC_DCHECK_EQ(
|
||||
target_bitrate_kbps,
|
||||
allocated_bitrates_bps->GetSpatialLayerSum(simulcast_id) / 1000);
|
||||
allocated_bitrates_bps.GetSpatialLayerSum(simulcast_id) / 1000);
|
||||
const int num_temporal_streams = std::max<uint8_t>(
|
||||
1, codec_.numberOfSimulcastStreams == 0
|
||||
? codec_.VP8().numberOfTemporalLayers
|
||||
@ -178,14 +137,14 @@ void SimulcastRateAllocator::DistributeAllocationToTemporalLayers(
|
||||
uint64_t tl_allocation_sum_kbps = 0;
|
||||
for (size_t tl_index = 0; tl_index < tl_allocation.size(); ++tl_index) {
|
||||
uint32_t layer_rate_kbps = tl_allocation[tl_index];
|
||||
if (layer_rate_kbps > 0) {
|
||||
allocated_bitrates_bps->SetBitrate(simulcast_id, tl_index,
|
||||
layer_rate_kbps * 1000);
|
||||
}
|
||||
allocated_bitrates_bps.SetBitrate(simulcast_id, tl_index,
|
||||
layer_rate_kbps * 1000);
|
||||
tl_allocation_sum_kbps += layer_rate_kbps;
|
||||
}
|
||||
RTC_DCHECK_LE(tl_allocation_sum_kbps, expected_allocated_bitrate_kbps);
|
||||
}
|
||||
|
||||
return allocated_bitrates_bps;
|
||||
}
|
||||
|
||||
uint32_t SimulcastRateAllocator::GetPreferredBitrateBps(uint32_t framerate) {
|
||||
|
@ -39,12 +39,6 @@ class SimulcastRateAllocator : public VideoBitrateAllocator,
|
||||
const VideoCodec& GetCodec() const;
|
||||
|
||||
private:
|
||||
void DistributeAllocationToSimulcastLayers(
|
||||
uint32_t total_bitrate_bps,
|
||||
BitrateAllocation* allocated_bitrates_bps);
|
||||
void DistributeAllocationToTemporalLayers(
|
||||
uint32_t framerate,
|
||||
BitrateAllocation* allocated_bitrates_bps);
|
||||
const VideoCodec codec_;
|
||||
std::map<uint32_t, TemporalLayers*> temporal_layers_;
|
||||
std::unique_ptr<TemporalLayersFactory> tl_factory_;
|
||||
|
@ -203,7 +203,6 @@ class TestVp8Simulcast : public ::testing::Test {
|
||||
settings->width = kDefaultWidth;
|
||||
settings->height = kDefaultHeight;
|
||||
settings->numberOfSimulcastStreams = kNumberOfSimulcastStreams;
|
||||
settings->active = true;
|
||||
ASSERT_EQ(3, kNumberOfSimulcastStreams);
|
||||
settings->timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
|
||||
kDefaultOutlierFrameSizePercent};
|
||||
@ -239,7 +238,6 @@ class TestVp8Simulcast : public ::testing::Test {
|
||||
stream->targetBitrate = target_bitrate;
|
||||
stream->numberOfTemporalLayers = num_temporal_layers;
|
||||
stream->qpMax = 45;
|
||||
stream->active = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -284,22 +282,10 @@ class TestVp8Simulcast : public ::testing::Test {
|
||||
rate_allocator_->GetAllocation(bitrate_kbps * 1000, fps), fps);
|
||||
}
|
||||
|
||||
void UpdateActiveStreams(const std::vector<bool> active_streams) {
|
||||
ASSERT_EQ(static_cast<int>(active_streams.size()),
|
||||
kNumberOfSimulcastStreams);
|
||||
for (size_t i = 0; i < active_streams.size(); ++i) {
|
||||
settings_.simulcastStream[i].active = active_streams[i];
|
||||
}
|
||||
// Re initialize the allocator and encoder with the new settings.
|
||||
SetUpRateAllocator();
|
||||
EXPECT_EQ(0, encoder_->InitEncode(&settings_, 1, 1200));
|
||||
}
|
||||
|
||||
void ExpectStreams(FrameType frame_type,
|
||||
const std::vector<bool> expected_streams_active) {
|
||||
ASSERT_EQ(static_cast<int>(expected_streams_active.size()),
|
||||
kNumberOfSimulcastStreams);
|
||||
if (expected_streams_active[0]) {
|
||||
void ExpectStreams(FrameType frame_type, int expected_video_streams) {
|
||||
ASSERT_GE(expected_video_streams, 0);
|
||||
ASSERT_LE(expected_video_streams, kNumberOfSimulcastStreams);
|
||||
if (expected_video_streams >= 1) {
|
||||
EXPECT_CALL(
|
||||
encoder_callback_,
|
||||
OnEncodedImage(
|
||||
@ -311,7 +297,7 @@ class TestVp8Simulcast : public ::testing::Test {
|
||||
.WillRepeatedly(Return(EncodedImageCallback::Result(
|
||||
EncodedImageCallback::Result::OK, 0)));
|
||||
}
|
||||
if (expected_streams_active[1]) {
|
||||
if (expected_video_streams >= 2) {
|
||||
EXPECT_CALL(
|
||||
encoder_callback_,
|
||||
OnEncodedImage(
|
||||
@ -323,7 +309,7 @@ class TestVp8Simulcast : public ::testing::Test {
|
||||
.WillRepeatedly(Return(EncodedImageCallback::Result(
|
||||
EncodedImageCallback::Result::OK, 0)));
|
||||
}
|
||||
if (expected_streams_active[2]) {
|
||||
if (expected_video_streams >= 3) {
|
||||
EXPECT_CALL(
|
||||
encoder_callback_,
|
||||
OnEncodedImage(
|
||||
@ -337,16 +323,6 @@ class TestVp8Simulcast : public ::testing::Test {
|
||||
}
|
||||
}
|
||||
|
||||
void ExpectStreams(FrameType frame_type, int expected_video_streams) {
|
||||
ASSERT_GE(expected_video_streams, 0);
|
||||
ASSERT_LE(expected_video_streams, kNumberOfSimulcastStreams);
|
||||
std::vector<bool> expected_streams_active(kNumberOfSimulcastStreams, false);
|
||||
for (int i = 0; i < expected_video_streams; ++i) {
|
||||
expected_streams_active[i] = true;
|
||||
}
|
||||
ExpectStreams(frame_type, expected_streams_active);
|
||||
}
|
||||
|
||||
void VerifyTemporalIdxAndSyncForAllSpatialLayers(
|
||||
Vp8TestEncodedImageCallback* encoder_callback,
|
||||
const int* expected_temporal_idx,
|
||||
@ -525,43 +501,6 @@ class TestVp8Simulcast : public ::testing::Test {
|
||||
EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
|
||||
}
|
||||
|
||||
void TestActiveStreams() {
|
||||
const int kEnoughBitrateAllStreams =
|
||||
kMaxBitrates[0] + kMaxBitrates[1] + kMaxBitrates[2];
|
||||
std::vector<FrameType> frame_types(kNumberOfSimulcastStreams,
|
||||
kVideoFrameDelta);
|
||||
// TODO(shampson): Currently turning off the base stream causes unexpected
|
||||
// behavior in the libvpx encoder. The libvpx encoder labels key frames
|
||||
// based upon the base stream. If the base stream is never enabled, it
|
||||
// will continue to spit out encoded images labeled as key frames for the
|
||||
// other streams that are enabled. Once this is fixed in libvpx, update this
|
||||
// test to reflect that change.
|
||||
|
||||
// Only turn on the the base stream.
|
||||
std::vector<bool> active_streams = {true, false, false};
|
||||
UpdateActiveStreams(active_streams);
|
||||
SetRates(kEnoughBitrateAllStreams, 30);
|
||||
ExpectStreams(kVideoFrameKey, active_streams);
|
||||
input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
|
||||
EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
|
||||
|
||||
ExpectStreams(kVideoFrameDelta, active_streams);
|
||||
input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
|
||||
EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
|
||||
|
||||
// Turn off only the middle stream.
|
||||
active_streams = {true, false, true};
|
||||
UpdateActiveStreams(active_streams);
|
||||
SetRates(kEnoughBitrateAllStreams, 30);
|
||||
ExpectStreams(kVideoFrameKey, active_streams);
|
||||
input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
|
||||
EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
|
||||
|
||||
ExpectStreams(kVideoFrameDelta, active_streams);
|
||||
input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
|
||||
EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
|
||||
}
|
||||
|
||||
void SwitchingToOneStream(int width, int height) {
|
||||
// Disable all streams except the last and set the bitrate of the last to
|
||||
// 100 kbps. This verifies the way GTP switches to screenshare mode.
|
||||
|
@ -55,10 +55,6 @@ TEST_F(TestVp8Impl, TestDisablingStreams) {
|
||||
TestVp8Simulcast::TestDisablingStreams();
|
||||
}
|
||||
|
||||
TEST_F(TestVp8Impl, TestActiveStreams) {
|
||||
TestVp8Simulcast::TestActiveStreams();
|
||||
}
|
||||
|
||||
TEST_F(TestVp8Impl, TestSwitchingToOneStream) {
|
||||
TestVp8Simulcast::TestSwitchingToOneStream();
|
||||
}
|
||||
|
Reference in New Issue
Block a user