Reland "Enables/disables simulcast streams by allocating a bitrate of 0 to the spatial layer."
This is a reland of 18c4261339dc76b220e7c805e36b4ea6f3dd161d 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=sprang@webrtc.org,stefan@webrtc.org,deadbeef@webrtc.org Bug: webrtc:8630 Change-Id: Ib3df6f9b7158bff362a7ec66fc57e368682c5846 Reviewed-on: https://webrtc-review.googlesource.com/40980 Reviewed-by: Seth Hampson <shampson@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Seth Hampson <shampson@webrtc.org> Cr-Commit-Position: refs/heads/master@{#21688}
This commit is contained in:
@ -73,6 +73,10 @@ TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) {
|
|||||||
TestVp8Simulcast::TestDisablingStreams();
|
TestVp8Simulcast::TestDisablingStreams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TestSimulcastEncoderAdapter, TestActiveStreams) {
|
||||||
|
TestVp8Simulcast::TestActiveStreams();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
|
TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
|
||||||
TestVp8Simulcast::TestSwitchingToOneStream();
|
TestVp8Simulcast::TestSwitchingToOneStream();
|
||||||
}
|
}
|
||||||
|
@ -37,56 +37,92 @@ void SimulcastRateAllocator::OnTemporalLayersCreated(int simulcast_id,
|
|||||||
BitrateAllocation SimulcastRateAllocator::GetAllocation(
|
BitrateAllocation SimulcastRateAllocator::GetAllocation(
|
||||||
uint32_t total_bitrate_bps,
|
uint32_t total_bitrate_bps,
|
||||||
uint32_t framerate) {
|
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;
|
uint32_t left_to_allocate = total_bitrate_bps;
|
||||||
if (codec_.maxBitrate && codec_.maxBitrate * 1000 < left_to_allocate)
|
if (codec_.maxBitrate && codec_.maxBitrate * 1000 < left_to_allocate)
|
||||||
left_to_allocate = codec_.maxBitrate * 1000;
|
left_to_allocate = codec_.maxBitrate * 1000;
|
||||||
|
|
||||||
BitrateAllocation allocated_bitrates_bps;
|
|
||||||
if (codec_.numberOfSimulcastStreams == 0) {
|
if (codec_.numberOfSimulcastStreams == 0) {
|
||||||
// No simulcast, just set the target as this has been capped already.
|
// No simulcast, just set the target as this has been capped already.
|
||||||
allocated_bitrates_bps.SetBitrate(
|
if (codec_.active) {
|
||||||
|
allocated_bitrates_bps->SetBitrate(
|
||||||
0, 0, std::max(codec_.minBitrate * 1000, left_to_allocate));
|
0, 0, std::max(codec_.minBitrate * 1000, left_to_allocate));
|
||||||
} else {
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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
|
// Always allocate enough bitrate for the minimum bitrate of the first
|
||||||
// layer. Suspending below min bitrate is controlled outside the codec
|
// active layer. Suspending below min bitrate is controlled outside the
|
||||||
// implementation and is not overridden by this.
|
// codec implementation and is not overridden by this.
|
||||||
left_to_allocate =
|
left_to_allocate = std::max(
|
||||||
std::max(codec_.simulcastStream[0].minBitrate * 1000, left_to_allocate);
|
codec_.simulcastStream[active_layer].minBitrate * 1000, left_to_allocate);
|
||||||
|
|
||||||
// Begin by allocating bitrate to simulcast streams, putting all bitrate in
|
// Begin by allocating bitrate to simulcast streams, putting all bitrate in
|
||||||
// temporal layer 0. We'll then distribute this bitrate, across potential
|
// temporal layer 0. We'll then distribute this bitrate, across potential
|
||||||
// temporal layers, when stream allocation is done.
|
// temporal layers, when stream allocation is done.
|
||||||
|
|
||||||
// Allocate up to the target bitrate for each simulcast layer.
|
size_t top_active_layer = active_layer;
|
||||||
size_t layer = 0;
|
// Allocate up to the target bitrate for each active simulcast layer.
|
||||||
for (; layer < codec_.numberOfSimulcastStreams; ++layer) {
|
for (; active_layer < codec_.numberOfSimulcastStreams; ++active_layer) {
|
||||||
const SimulcastStream& stream = codec_.simulcastStream[layer];
|
const SimulcastStream& stream = codec_.simulcastStream[active_layer];
|
||||||
if (left_to_allocate < stream.minBitrate * 1000)
|
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;
|
break;
|
||||||
|
}
|
||||||
|
// We are allocating to this layer so it is the current active allocation.
|
||||||
|
top_active_layer = active_layer;
|
||||||
uint32_t allocation =
|
uint32_t allocation =
|
||||||
std::min(left_to_allocate, stream.targetBitrate * 1000);
|
std::min(left_to_allocate, stream.targetBitrate * 1000);
|
||||||
allocated_bitrates_bps.SetBitrate(layer, 0, allocation);
|
allocated_bitrates_bps->SetBitrate(active_layer, 0, allocation);
|
||||||
RTC_DCHECK_LE(allocation, left_to_allocate);
|
RTC_DCHECK_LE(allocation, left_to_allocate);
|
||||||
left_to_allocate -= allocation;
|
left_to_allocate -= allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, try allocate remaining bitrate, up to max bitrate, in top stream.
|
// 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
|
// TODO(sprang): Allocate up to max bitrate for all layers once we have a
|
||||||
// better idea of possible performance implications.
|
// better idea of possible performance implications.
|
||||||
if (left_to_allocate > 0) {
|
if (left_to_allocate > 0) {
|
||||||
size_t active_layer = layer - 1;
|
const SimulcastStream& stream = codec_.simulcastStream[top_active_layer];
|
||||||
const SimulcastStream& stream = codec_.simulcastStream[active_layer];
|
|
||||||
uint32_t bitrate_bps =
|
uint32_t bitrate_bps =
|
||||||
allocated_bitrates_bps.GetSpatialLayerSum(active_layer);
|
allocated_bitrates_bps->GetSpatialLayerSum(top_active_layer);
|
||||||
uint32_t allocation =
|
uint32_t allocation =
|
||||||
std::min(left_to_allocate, stream.maxBitrate * 1000 - bitrate_bps);
|
std::min(left_to_allocate, stream.maxBitrate * 1000 - bitrate_bps);
|
||||||
bitrate_bps += allocation;
|
bitrate_bps += allocation;
|
||||||
RTC_DCHECK_LE(allocation, left_to_allocate);
|
RTC_DCHECK_LE(allocation, left_to_allocate);
|
||||||
left_to_allocate -= allocation;
|
left_to_allocate -= allocation;
|
||||||
allocated_bitrates_bps.SetBitrate(active_layer, 0, bitrate_bps);
|
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 =
|
const int num_spatial_streams =
|
||||||
std::max(1, static_cast<int>(codec_.numberOfSimulcastStreams));
|
std::max(1, static_cast<int>(codec_.numberOfSimulcastStreams));
|
||||||
|
|
||||||
@ -94,16 +130,21 @@ BitrateAllocation SimulcastRateAllocator::GetAllocation(
|
|||||||
// available temporal layers.
|
// available temporal layers.
|
||||||
for (int simulcast_id = 0; simulcast_id < num_spatial_streams;
|
for (int simulcast_id = 0; simulcast_id < num_spatial_streams;
|
||||||
++simulcast_id) {
|
++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);
|
auto tl_it = temporal_layers_.find(simulcast_id);
|
||||||
if (tl_it == temporal_layers_.end())
|
if (tl_it == temporal_layers_.end())
|
||||||
continue; // TODO(sprang): If > 1 SS, assume default TL alloc?
|
continue; // TODO(sprang): If > 1 SS, assume default TL alloc?
|
||||||
|
|
||||||
uint32_t target_bitrate_kbps =
|
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;
|
const uint32_t expected_allocated_bitrate_kbps = target_bitrate_kbps;
|
||||||
RTC_DCHECK_EQ(
|
RTC_DCHECK_EQ(
|
||||||
target_bitrate_kbps,
|
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>(
|
const int num_temporal_streams = std::max<uint8_t>(
|
||||||
1, codec_.numberOfSimulcastStreams == 0
|
1, codec_.numberOfSimulcastStreams == 0
|
||||||
? codec_.VP8().numberOfTemporalLayers
|
? codec_.VP8().numberOfTemporalLayers
|
||||||
@ -137,14 +178,14 @@ BitrateAllocation SimulcastRateAllocator::GetAllocation(
|
|||||||
uint64_t tl_allocation_sum_kbps = 0;
|
uint64_t tl_allocation_sum_kbps = 0;
|
||||||
for (size_t tl_index = 0; tl_index < tl_allocation.size(); ++tl_index) {
|
for (size_t tl_index = 0; tl_index < tl_allocation.size(); ++tl_index) {
|
||||||
uint32_t layer_rate_kbps = tl_allocation[tl_index];
|
uint32_t layer_rate_kbps = tl_allocation[tl_index];
|
||||||
allocated_bitrates_bps.SetBitrate(simulcast_id, tl_index,
|
if (layer_rate_kbps > 0) {
|
||||||
|
allocated_bitrates_bps->SetBitrate(simulcast_id, tl_index,
|
||||||
layer_rate_kbps * 1000);
|
layer_rate_kbps * 1000);
|
||||||
|
}
|
||||||
tl_allocation_sum_kbps += layer_rate_kbps;
|
tl_allocation_sum_kbps += layer_rate_kbps;
|
||||||
}
|
}
|
||||||
RTC_DCHECK_LE(tl_allocation_sum_kbps, expected_allocated_bitrate_kbps);
|
RTC_DCHECK_LE(tl_allocation_sum_kbps, expected_allocated_bitrate_kbps);
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocated_bitrates_bps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SimulcastRateAllocator::GetPreferredBitrateBps(uint32_t framerate) {
|
uint32_t SimulcastRateAllocator::GetPreferredBitrateBps(uint32_t framerate) {
|
||||||
|
@ -39,6 +39,12 @@ class SimulcastRateAllocator : public VideoBitrateAllocator,
|
|||||||
const VideoCodec& GetCodec() const;
|
const VideoCodec& GetCodec() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void DistributeAllocationToSimulcastLayers(
|
||||||
|
uint32_t total_bitrate_bps,
|
||||||
|
BitrateAllocation* allocated_bitrates_bps);
|
||||||
|
void DistributeAllocationToTemporalLayers(
|
||||||
|
uint32_t framerate,
|
||||||
|
BitrateAllocation* allocated_bitrates_bps);
|
||||||
const VideoCodec codec_;
|
const VideoCodec codec_;
|
||||||
std::map<uint32_t, TemporalLayers*> temporal_layers_;
|
std::map<uint32_t, TemporalLayers*> temporal_layers_;
|
||||||
std::unique_ptr<TemporalLayersFactory> tl_factory_;
|
std::unique_ptr<TemporalLayersFactory> tl_factory_;
|
||||||
|
@ -203,6 +203,7 @@ class TestVp8Simulcast : public ::testing::Test {
|
|||||||
settings->width = kDefaultWidth;
|
settings->width = kDefaultWidth;
|
||||||
settings->height = kDefaultHeight;
|
settings->height = kDefaultHeight;
|
||||||
settings->numberOfSimulcastStreams = kNumberOfSimulcastStreams;
|
settings->numberOfSimulcastStreams = kNumberOfSimulcastStreams;
|
||||||
|
settings->active = true;
|
||||||
ASSERT_EQ(3, kNumberOfSimulcastStreams);
|
ASSERT_EQ(3, kNumberOfSimulcastStreams);
|
||||||
settings->timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
|
settings->timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
|
||||||
kDefaultOutlierFrameSizePercent};
|
kDefaultOutlierFrameSizePercent};
|
||||||
@ -238,6 +239,7 @@ class TestVp8Simulcast : public ::testing::Test {
|
|||||||
stream->targetBitrate = target_bitrate;
|
stream->targetBitrate = target_bitrate;
|
||||||
stream->numberOfTemporalLayers = num_temporal_layers;
|
stream->numberOfTemporalLayers = num_temporal_layers;
|
||||||
stream->qpMax = 45;
|
stream->qpMax = 45;
|
||||||
|
stream->active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -282,10 +284,22 @@ class TestVp8Simulcast : public ::testing::Test {
|
|||||||
rate_allocator_->GetAllocation(bitrate_kbps * 1000, fps), fps);
|
rate_allocator_->GetAllocation(bitrate_kbps * 1000, fps), fps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpectStreams(FrameType frame_type, int expected_video_streams) {
|
void UpdateActiveStreams(const std::vector<bool> active_streams) {
|
||||||
ASSERT_GE(expected_video_streams, 0);
|
ASSERT_EQ(static_cast<int>(active_streams.size()),
|
||||||
ASSERT_LE(expected_video_streams, kNumberOfSimulcastStreams);
|
kNumberOfSimulcastStreams);
|
||||||
if (expected_video_streams >= 1) {
|
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]) {
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
encoder_callback_,
|
encoder_callback_,
|
||||||
OnEncodedImage(
|
OnEncodedImage(
|
||||||
@ -297,7 +311,7 @@ class TestVp8Simulcast : public ::testing::Test {
|
|||||||
.WillRepeatedly(Return(EncodedImageCallback::Result(
|
.WillRepeatedly(Return(EncodedImageCallback::Result(
|
||||||
EncodedImageCallback::Result::OK, 0)));
|
EncodedImageCallback::Result::OK, 0)));
|
||||||
}
|
}
|
||||||
if (expected_video_streams >= 2) {
|
if (expected_streams_active[1]) {
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
encoder_callback_,
|
encoder_callback_,
|
||||||
OnEncodedImage(
|
OnEncodedImage(
|
||||||
@ -309,7 +323,7 @@ class TestVp8Simulcast : public ::testing::Test {
|
|||||||
.WillRepeatedly(Return(EncodedImageCallback::Result(
|
.WillRepeatedly(Return(EncodedImageCallback::Result(
|
||||||
EncodedImageCallback::Result::OK, 0)));
|
EncodedImageCallback::Result::OK, 0)));
|
||||||
}
|
}
|
||||||
if (expected_video_streams >= 3) {
|
if (expected_streams_active[2]) {
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
encoder_callback_,
|
encoder_callback_,
|
||||||
OnEncodedImage(
|
OnEncodedImage(
|
||||||
@ -323,6 +337,16 @@ 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(
|
void VerifyTemporalIdxAndSyncForAllSpatialLayers(
|
||||||
Vp8TestEncodedImageCallback* encoder_callback,
|
Vp8TestEncodedImageCallback* encoder_callback,
|
||||||
const int* expected_temporal_idx,
|
const int* expected_temporal_idx,
|
||||||
@ -501,6 +525,43 @@ class TestVp8Simulcast : public ::testing::Test {
|
|||||||
EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
|
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) {
|
void SwitchingToOneStream(int width, int height) {
|
||||||
// Disable all streams except the last and set the bitrate of the last to
|
// 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.
|
// 100 kbps. This verifies the way GTP switches to screenshare mode.
|
||||||
|
@ -55,6 +55,10 @@ TEST_F(TestVp8Impl, TestDisablingStreams) {
|
|||||||
TestVp8Simulcast::TestDisablingStreams();
|
TestVp8Simulcast::TestDisablingStreams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TestVp8Impl, TestActiveStreams) {
|
||||||
|
TestVp8Simulcast::TestActiveStreams();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TestVp8Impl, TestSwitchingToOneStream) {
|
TEST_F(TestVp8Impl, TestSwitchingToOneStream) {
|
||||||
TestVp8Simulcast::TestSwitchingToOneStream();
|
TestVp8Simulcast::TestSwitchingToOneStream();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ BitrateAllocation DefaultVideoBitrateAllocator::GetAllocation(
|
|||||||
uint32_t total_bitrate_bps,
|
uint32_t total_bitrate_bps,
|
||||||
uint32_t framerate) {
|
uint32_t framerate) {
|
||||||
BitrateAllocation allocation;
|
BitrateAllocation allocation;
|
||||||
if (total_bitrate_bps == 0)
|
if (total_bitrate_bps == 0 || !codec_.active)
|
||||||
return allocation;
|
return allocation;
|
||||||
|
|
||||||
if (total_bitrate_bps < codec_.minBitrate * 1000) {
|
if (total_bitrate_bps < codec_.minBitrate * 1000) {
|
||||||
|
@ -45,6 +45,13 @@ TEST_F(DefaultVideoBitrateAllocatorTest, ZeroIsOff) {
|
|||||||
EXPECT_EQ(0u, allocation.get_sum_bps());
|
EXPECT_EQ(0u, allocation.get_sum_bps());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DefaultVideoBitrateAllocatorTest, Inactive) {
|
||||||
|
codec_.active = false;
|
||||||
|
allocator_.reset(new DefaultVideoBitrateAllocator(codec_));
|
||||||
|
BitrateAllocation allocation = allocator_->GetAllocation(1, kMaxFramerate);
|
||||||
|
EXPECT_EQ(0u, allocation.get_sum_bps());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(DefaultVideoBitrateAllocatorTest, CapsToMin) {
|
TEST_F(DefaultVideoBitrateAllocatorTest, CapsToMin) {
|
||||||
BitrateAllocation allocation = allocator_->GetAllocation(1, kMaxFramerate);
|
BitrateAllocation allocation = allocator_->GetAllocation(1, kMaxFramerate);
|
||||||
EXPECT_EQ(kMinBitrateBps, allocation.get_sum_bps());
|
EXPECT_EQ(kMinBitrateBps, allocation.get_sum_bps());
|
||||||
|
@ -51,6 +51,7 @@ class SimulcastRateAllocatorTest : public ::testing::TestWithParam<bool> {
|
|||||||
codec_.minBitrate = kMinBitrateKbps;
|
codec_.minBitrate = kMinBitrateKbps;
|
||||||
codec_.targetBitrate = kTargetBitrateKbps;
|
codec_.targetBitrate = kTargetBitrateKbps;
|
||||||
codec_.maxBitrate = kMaxBitrateKbps;
|
codec_.maxBitrate = kMaxBitrateKbps;
|
||||||
|
codec_.active = true;
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
}
|
}
|
||||||
virtual ~SimulcastRateAllocatorTest() {}
|
virtual ~SimulcastRateAllocatorTest() {}
|
||||||
@ -69,6 +70,9 @@ class SimulcastRateAllocatorTest : public ::testing::TestWithParam<bool> {
|
|||||||
uint32_t sum = 0;
|
uint32_t sum = 0;
|
||||||
for (size_t i = 0; i < S; ++i) {
|
for (size_t i = 0; i < S; ++i) {
|
||||||
uint32_t layer_bitrate = actual.GetSpatialLayerSum(i);
|
uint32_t layer_bitrate = actual.GetSpatialLayerSum(i);
|
||||||
|
if (layer_bitrate == 0) {
|
||||||
|
EXPECT_FALSE(actual.IsSpatialLayerUsed(i));
|
||||||
|
}
|
||||||
EXPECT_EQ(expected[i] * 1000U, layer_bitrate) << "Mismatch at index "
|
EXPECT_EQ(expected[i] * 1000U, layer_bitrate) << "Mismatch at index "
|
||||||
<< i;
|
<< i;
|
||||||
sum += layer_bitrate;
|
sum += layer_bitrate;
|
||||||
@ -96,6 +100,34 @@ class SimulcastRateAllocatorTest : public ::testing::TestWithParam<bool> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupCodecThreeSimulcastStreams(
|
||||||
|
const std::vector<bool>& active_streams) {
|
||||||
|
size_t num_streams = 3;
|
||||||
|
RTC_DCHECK_GE(active_streams.size(), num_streams);
|
||||||
|
SetupCodecTwoSimulcastStreams(active_streams);
|
||||||
|
codec_.numberOfSimulcastStreams = num_streams;
|
||||||
|
codec_.simulcastStream[2].minBitrate = 2000;
|
||||||
|
codec_.simulcastStream[2].targetBitrate = 3000;
|
||||||
|
codec_.simulcastStream[2].maxBitrate = 4000;
|
||||||
|
codec_.simulcastStream[2].active = active_streams[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupCodecTwoSimulcastStreams(const std::vector<bool>& active_streams) {
|
||||||
|
size_t num_streams = 2;
|
||||||
|
RTC_DCHECK_GE(active_streams.size(), num_streams);
|
||||||
|
codec_.numberOfSimulcastStreams = num_streams;
|
||||||
|
codec_.maxBitrate = 0;
|
||||||
|
codec_.simulcastStream[0].minBitrate = 10;
|
||||||
|
codec_.simulcastStream[0].targetBitrate = 100;
|
||||||
|
codec_.simulcastStream[0].maxBitrate = 500;
|
||||||
|
codec_.simulcastStream[1].minBitrate = 50;
|
||||||
|
codec_.simulcastStream[1].targetBitrate = 500;
|
||||||
|
codec_.simulcastStream[1].maxBitrate = 1000;
|
||||||
|
for (size_t i = 0; i < num_streams; ++i) {
|
||||||
|
codec_.simulcastStream[i].active = active_streams[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<TemporalLayersFactory> GetTlFactory() {
|
virtual std::unique_ptr<TemporalLayersFactory> GetTlFactory() {
|
||||||
return std::unique_ptr<TemporalLayersFactory>(new TemporalLayersFactory());
|
return std::unique_ptr<TemporalLayersFactory>(new TemporalLayersFactory());
|
||||||
}
|
}
|
||||||
@ -113,6 +145,7 @@ class SimulcastRateAllocatorTest : public ::testing::TestWithParam<bool> {
|
|||||||
|
|
||||||
TEST_F(SimulcastRateAllocatorTest, NoSimulcastBelowMin) {
|
TEST_F(SimulcastRateAllocatorTest, NoSimulcastBelowMin) {
|
||||||
uint32_t expected[] = {codec_.minBitrate};
|
uint32_t expected[] = {codec_.minBitrate};
|
||||||
|
codec_.active = true;
|
||||||
ExpectEqual(expected, GetAllocation(codec_.minBitrate - 1));
|
ExpectEqual(expected, GetAllocation(codec_.minBitrate - 1));
|
||||||
ExpectEqual(expected, GetAllocation(1));
|
ExpectEqual(expected, GetAllocation(1));
|
||||||
ExpectEqual(expected, GetAllocation(0));
|
ExpectEqual(expected, GetAllocation(0));
|
||||||
@ -120,12 +153,14 @@ TEST_F(SimulcastRateAllocatorTest, NoSimulcastBelowMin) {
|
|||||||
|
|
||||||
TEST_F(SimulcastRateAllocatorTest, NoSimulcastAboveMax) {
|
TEST_F(SimulcastRateAllocatorTest, NoSimulcastAboveMax) {
|
||||||
uint32_t expected[] = {codec_.maxBitrate};
|
uint32_t expected[] = {codec_.maxBitrate};
|
||||||
|
codec_.active = true;
|
||||||
ExpectEqual(expected, GetAllocation(codec_.maxBitrate + 1));
|
ExpectEqual(expected, GetAllocation(codec_.maxBitrate + 1));
|
||||||
ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
|
ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SimulcastRateAllocatorTest, NoSimulcastNoMax) {
|
TEST_F(SimulcastRateAllocatorTest, NoSimulcastNoMax) {
|
||||||
const uint32_t kMax = BitrateAllocation::kMaxBitrateBps / 1000;
|
const uint32_t kMax = BitrateAllocation::kMaxBitrateBps / 1000;
|
||||||
|
codec_.active = true;
|
||||||
codec_.maxBitrate = 0;
|
codec_.maxBitrate = 0;
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
|
|
||||||
@ -134,6 +169,7 @@ TEST_F(SimulcastRateAllocatorTest, NoSimulcastNoMax) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SimulcastRateAllocatorTest, NoSimulcastWithinLimits) {
|
TEST_F(SimulcastRateAllocatorTest, NoSimulcastWithinLimits) {
|
||||||
|
codec_.active = true;
|
||||||
for (uint32_t bitrate = codec_.minBitrate; bitrate <= codec_.maxBitrate;
|
for (uint32_t bitrate = codec_.minBitrate; bitrate <= codec_.maxBitrate;
|
||||||
++bitrate) {
|
++bitrate) {
|
||||||
uint32_t expected[] = {bitrate};
|
uint32_t expected[] = {bitrate};
|
||||||
@ -141,12 +177,25 @@ TEST_F(SimulcastRateAllocatorTest, NoSimulcastWithinLimits) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that when we aren't using simulcast and the codec is marked inactive no
|
||||||
|
// bitrate will be allocated.
|
||||||
|
TEST_F(SimulcastRateAllocatorTest, NoSimulcastInactive) {
|
||||||
|
codec_.active = false;
|
||||||
|
uint32_t expected[] = {0};
|
||||||
|
CreateAllocator();
|
||||||
|
|
||||||
|
ExpectEqual(expected, GetAllocation(kMinBitrateKbps - 10));
|
||||||
|
ExpectEqual(expected, GetAllocation(kTargetBitrateKbps));
|
||||||
|
ExpectEqual(expected, GetAllocation(kMaxBitrateKbps + 10));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(SimulcastRateAllocatorTest, SingleSimulcastBelowMin) {
|
TEST_F(SimulcastRateAllocatorTest, SingleSimulcastBelowMin) {
|
||||||
// With simulcast, use the min bitrate from the ss spec instead of the global.
|
// With simulcast, use the min bitrate from the ss spec instead of the global.
|
||||||
codec_.numberOfSimulcastStreams = 1;
|
codec_.numberOfSimulcastStreams = 1;
|
||||||
const uint32_t kMin = codec_.minBitrate - 10;
|
const uint32_t kMin = codec_.minBitrate - 10;
|
||||||
codec_.simulcastStream[0].minBitrate = kMin;
|
codec_.simulcastStream[0].minBitrate = kMin;
|
||||||
codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
|
codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
|
||||||
|
codec_.simulcastStream[0].active = true;
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
|
|
||||||
uint32_t expected[] = {kMin};
|
uint32_t expected[] = {kMin};
|
||||||
@ -160,6 +209,7 @@ TEST_F(SimulcastRateAllocatorTest, SingleSimulcastAboveMax) {
|
|||||||
codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
|
codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
|
||||||
const uint32_t kMax = codec_.simulcastStream[0].maxBitrate + 1000;
|
const uint32_t kMax = codec_.simulcastStream[0].maxBitrate + 1000;
|
||||||
codec_.simulcastStream[0].maxBitrate = kMax;
|
codec_.simulcastStream[0].maxBitrate = kMax;
|
||||||
|
codec_.simulcastStream[0].active = true;
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
|
|
||||||
uint32_t expected[] = {kMax};
|
uint32_t expected[] = {kMax};
|
||||||
@ -173,6 +223,7 @@ TEST_F(SimulcastRateAllocatorTest, SingleSimulcastWithinLimits) {
|
|||||||
codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
|
codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
|
||||||
codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
|
codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
|
||||||
codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
|
codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
|
||||||
|
codec_.simulcastStream[0].active = true;
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
|
|
||||||
for (uint32_t bitrate = kMinBitrateKbps; bitrate <= kMaxBitrateKbps;
|
for (uint32_t bitrate = kMinBitrateKbps; bitrate <= kMaxBitrateKbps;
|
||||||
@ -182,18 +233,23 @@ TEST_F(SimulcastRateAllocatorTest, SingleSimulcastWithinLimits) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SimulcastRateAllocatorTest, SingleSimulcastInactive) {
|
||||||
|
codec_.numberOfSimulcastStreams = 1;
|
||||||
|
codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
|
||||||
|
codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
|
||||||
|
codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
|
||||||
|
codec_.simulcastStream[0].active = false;
|
||||||
|
CreateAllocator();
|
||||||
|
|
||||||
|
uint32_t expected[] = {0};
|
||||||
|
ExpectEqual(expected, GetAllocation(kMinBitrateKbps - 10));
|
||||||
|
ExpectEqual(expected, GetAllocation(kTargetBitrateKbps));
|
||||||
|
ExpectEqual(expected, GetAllocation(kMaxBitrateKbps + 10));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) {
|
TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) {
|
||||||
codec_.numberOfSimulcastStreams = 3;
|
const std::vector<bool> active_streams(3, true);
|
||||||
codec_.maxBitrate = 0;
|
SetupCodecThreeSimulcastStreams(active_streams);
|
||||||
codec_.simulcastStream[0].minBitrate = 10;
|
|
||||||
codec_.simulcastStream[0].targetBitrate = 100;
|
|
||||||
codec_.simulcastStream[0].maxBitrate = 500;
|
|
||||||
codec_.simulcastStream[1].minBitrate = 50;
|
|
||||||
codec_.simulcastStream[1].targetBitrate = 500;
|
|
||||||
codec_.simulcastStream[1].maxBitrate = 1000;
|
|
||||||
codec_.simulcastStream[2].minBitrate = 2000;
|
|
||||||
codec_.simulcastStream[2].targetBitrate = 3000;
|
|
||||||
codec_.simulcastStream[2].maxBitrate = 4000;
|
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -267,6 +323,164 @@ TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) {
|
|||||||
codec_.simulcastStream[2].maxBitrate};
|
codec_.simulcastStream[2].maxBitrate};
|
||||||
ExpectEqual(expected, GetAllocation(bitrate));
|
ExpectEqual(expected, GetAllocation(bitrate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Enough to max out all streams which will allocate the target amount to
|
||||||
|
// the lower streams.
|
||||||
|
const uint32_t bitrate = codec_.simulcastStream[0].maxBitrate +
|
||||||
|
codec_.simulcastStream[1].maxBitrate +
|
||||||
|
codec_.simulcastStream[2].maxBitrate;
|
||||||
|
uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate,
|
||||||
|
codec_.simulcastStream[1].targetBitrate,
|
||||||
|
codec_.simulcastStream[2].maxBitrate};
|
||||||
|
ExpectEqual(expected, GetAllocation(bitrate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If three simulcast streams that are all inactive, none of them should be
|
||||||
|
// allocated bitrate.
|
||||||
|
TEST_F(SimulcastRateAllocatorTest, ThreeStreamsInactive) {
|
||||||
|
const std::vector<bool> active_streams(3, false);
|
||||||
|
SetupCodecThreeSimulcastStreams(active_streams);
|
||||||
|
CreateAllocator();
|
||||||
|
|
||||||
|
// Just enough to allocate the min.
|
||||||
|
const uint32_t min_bitrate = codec_.simulcastStream[0].minBitrate +
|
||||||
|
codec_.simulcastStream[1].minBitrate +
|
||||||
|
codec_.simulcastStream[2].minBitrate;
|
||||||
|
// Enough bitrate to allocate target to all streams.
|
||||||
|
const uint32_t target_bitrate = codec_.simulcastStream[0].targetBitrate +
|
||||||
|
codec_.simulcastStream[1].targetBitrate +
|
||||||
|
codec_.simulcastStream[2].targetBitrate;
|
||||||
|
// Enough bitrate to allocate max to all streams.
|
||||||
|
const uint32_t max_bitrate = codec_.simulcastStream[0].maxBitrate +
|
||||||
|
codec_.simulcastStream[1].maxBitrate +
|
||||||
|
codec_.simulcastStream[2].maxBitrate;
|
||||||
|
uint32_t expected[] = {0, 0, 0};
|
||||||
|
ExpectEqual(expected, GetAllocation(0));
|
||||||
|
ExpectEqual(expected, GetAllocation(min_bitrate));
|
||||||
|
ExpectEqual(expected, GetAllocation(target_bitrate));
|
||||||
|
ExpectEqual(expected, GetAllocation(max_bitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are two simulcast streams, we expect the high active stream to be
|
||||||
|
// allocated as if it is a single active stream.
|
||||||
|
TEST_F(SimulcastRateAllocatorTest, TwoStreamsLowInactive) {
|
||||||
|
const std::vector<bool> active_streams({false, true});
|
||||||
|
SetupCodecTwoSimulcastStreams(active_streams);
|
||||||
|
CreateAllocator();
|
||||||
|
|
||||||
|
const uint32_t kActiveStreamMinBitrate = codec_.simulcastStream[1].minBitrate;
|
||||||
|
const uint32_t kActiveStreamTargetBitrate =
|
||||||
|
codec_.simulcastStream[1].targetBitrate;
|
||||||
|
const uint32_t kActiveStreamMaxBitrate = codec_.simulcastStream[1].maxBitrate;
|
||||||
|
{
|
||||||
|
// Expect that the stream is always allocated its min bitrate.
|
||||||
|
uint32_t expected[] = {0, kActiveStreamMinBitrate};
|
||||||
|
ExpectEqual(expected, GetAllocation(0));
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate - 10));
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// The stream should be allocated its target bitrate.
|
||||||
|
uint32_t expected[] = {0, kActiveStreamTargetBitrate};
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamTargetBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// The stream should be allocated its max if the target input is sufficient.
|
||||||
|
uint32_t expected[] = {0, kActiveStreamMaxBitrate};
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamMaxBitrate));
|
||||||
|
ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are two simulcast streams, we expect the low active stream to be
|
||||||
|
// allocated as if it is a single active stream.
|
||||||
|
TEST_F(SimulcastRateAllocatorTest, TwoStreamsHighInactive) {
|
||||||
|
const std::vector<bool> active_streams({true, false});
|
||||||
|
SetupCodecTwoSimulcastStreams(active_streams);
|
||||||
|
CreateAllocator();
|
||||||
|
|
||||||
|
const uint32_t kActiveStreamMinBitrate = codec_.simulcastStream[0].minBitrate;
|
||||||
|
const uint32_t kActiveStreamTargetBitrate =
|
||||||
|
codec_.simulcastStream[0].targetBitrate;
|
||||||
|
const uint32_t kActiveStreamMaxBitrate = codec_.simulcastStream[0].maxBitrate;
|
||||||
|
{
|
||||||
|
// Expect that the stream is always allocated its min bitrate.
|
||||||
|
uint32_t expected[] = {kActiveStreamMinBitrate, 0};
|
||||||
|
ExpectEqual(expected, GetAllocation(0));
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate - 10));
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// The stream should be allocated its target bitrate.
|
||||||
|
uint32_t expected[] = {kActiveStreamTargetBitrate, 0};
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamTargetBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// The stream should be allocated its max if the target input is sufficent.
|
||||||
|
uint32_t expected[] = {kActiveStreamMaxBitrate, 0};
|
||||||
|
ExpectEqual(expected, GetAllocation(kActiveStreamMaxBitrate));
|
||||||
|
ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are three simulcast streams and the middle stream is inactive, the
|
||||||
|
// other two streams should be allocated bitrate the same as if they are two
|
||||||
|
// active simulcast streams.
|
||||||
|
TEST_F(SimulcastRateAllocatorTest, ThreeStreamsMiddleInactive) {
|
||||||
|
const std::vector<bool> active_streams({true, false, true});
|
||||||
|
SetupCodecThreeSimulcastStreams(active_streams);
|
||||||
|
CreateAllocator();
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint32_t kLowStreamMinBitrate = codec_.simulcastStream[0].minBitrate;
|
||||||
|
// The lowest stream should always be allocated its minimum bitrate.
|
||||||
|
uint32_t expected[] = {kLowStreamMinBitrate, 0, 0};
|
||||||
|
ExpectEqual(expected, GetAllocation(0));
|
||||||
|
ExpectEqual(expected, GetAllocation(kLowStreamMinBitrate - 10));
|
||||||
|
ExpectEqual(expected, GetAllocation(kLowStreamMinBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// The lowest stream gets its target bitrate.
|
||||||
|
uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, 0, 0};
|
||||||
|
ExpectEqual(expected,
|
||||||
|
GetAllocation(codec_.simulcastStream[0].targetBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// The lowest stream gets its max bitrate, but not enough for the high
|
||||||
|
// stream.
|
||||||
|
const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
|
||||||
|
codec_.simulcastStream[2].minBitrate - 1;
|
||||||
|
uint32_t expected[] = {codec_.simulcastStream[0].maxBitrate, 0, 0};
|
||||||
|
ExpectEqual(expected, GetAllocation(bitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Both active streams get allocated target bitrate.
|
||||||
|
const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
|
||||||
|
codec_.simulcastStream[2].targetBitrate;
|
||||||
|
uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, 0,
|
||||||
|
codec_.simulcastStream[2].targetBitrate};
|
||||||
|
ExpectEqual(expected, GetAllocation(bitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Lowest stream gets its target bitrate, high stream gets its max bitrate.
|
||||||
|
uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
|
||||||
|
codec_.simulcastStream[2].maxBitrate;
|
||||||
|
uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, 0,
|
||||||
|
codec_.simulcastStream[2].maxBitrate};
|
||||||
|
ExpectEqual(expected, GetAllocation(bitrate));
|
||||||
|
ExpectEqual(expected, GetAllocation(bitrate + 10));
|
||||||
|
ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateBps) {
|
TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateBps) {
|
||||||
@ -283,15 +497,18 @@ TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateSimulcast) {
|
|||||||
codec_.maxBitrate = 999999;
|
codec_.maxBitrate = 999999;
|
||||||
codec_.simulcastStream[0].minBitrate = 10;
|
codec_.simulcastStream[0].minBitrate = 10;
|
||||||
codec_.simulcastStream[0].targetBitrate = 100;
|
codec_.simulcastStream[0].targetBitrate = 100;
|
||||||
|
codec_.simulcastStream[0].active = true;
|
||||||
|
|
||||||
codec_.simulcastStream[0].maxBitrate = 500;
|
codec_.simulcastStream[0].maxBitrate = 500;
|
||||||
codec_.simulcastStream[1].minBitrate = 50;
|
codec_.simulcastStream[1].minBitrate = 50;
|
||||||
codec_.simulcastStream[1].targetBitrate = 500;
|
codec_.simulcastStream[1].targetBitrate = 500;
|
||||||
codec_.simulcastStream[1].maxBitrate = 1000;
|
codec_.simulcastStream[1].maxBitrate = 1000;
|
||||||
|
codec_.simulcastStream[1].active = true;
|
||||||
|
|
||||||
codec_.simulcastStream[2].minBitrate = 2000;
|
codec_.simulcastStream[2].minBitrate = 2000;
|
||||||
codec_.simulcastStream[2].targetBitrate = 3000;
|
codec_.simulcastStream[2].targetBitrate = 3000;
|
||||||
codec_.simulcastStream[2].maxBitrate = 4000;
|
codec_.simulcastStream[2].maxBitrate = 4000;
|
||||||
|
codec_.simulcastStream[2].active = true;
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
|
|
||||||
uint32_t preferred_bitrate_kbps;
|
uint32_t preferred_bitrate_kbps;
|
||||||
@ -305,7 +522,7 @@ TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateSimulcast) {
|
|||||||
|
|
||||||
class ScreenshareRateAllocationTest : public SimulcastRateAllocatorTest {
|
class ScreenshareRateAllocationTest : public SimulcastRateAllocatorTest {
|
||||||
public:
|
public:
|
||||||
void SetupConferenceScreenshare(bool use_simulcast) {
|
void SetupConferenceScreenshare(bool use_simulcast, bool active = true) {
|
||||||
codec_.mode = VideoCodecMode::kScreensharing;
|
codec_.mode = VideoCodecMode::kScreensharing;
|
||||||
codec_.minBitrate = kMinBitrateKbps;
|
codec_.minBitrate = kMinBitrateKbps;
|
||||||
codec_.maxBitrate = kMaxBitrateKbps;
|
codec_.maxBitrate = kMaxBitrateKbps;
|
||||||
@ -315,10 +532,12 @@ class ScreenshareRateAllocationTest : public SimulcastRateAllocatorTest {
|
|||||||
codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
|
codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
|
||||||
codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
|
codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
|
||||||
codec_.simulcastStream[0].numberOfTemporalLayers = 2;
|
codec_.simulcastStream[0].numberOfTemporalLayers = 2;
|
||||||
|
codec_.simulcastStream[0].active = active;
|
||||||
} else {
|
} else {
|
||||||
codec_.numberOfSimulcastStreams = 0;
|
codec_.numberOfSimulcastStreams = 0;
|
||||||
codec_.targetBitrate = kTargetBitrateKbps;
|
codec_.targetBitrate = kTargetBitrateKbps;
|
||||||
codec_.VP8()->numberOfTemporalLayers = 2;
|
codec_.VP8()->numberOfTemporalLayers = 2;
|
||||||
|
codec_.active = active;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,4 +592,17 @@ TEST_P(ScreenshareRateAllocationTest, BitrateAboveTl1) {
|
|||||||
allocation.GetBitrate(0, 1) / 1000);
|
allocation.GetBitrate(0, 1) / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This tests when the screenshare is inactive it should be allocated 0 bitrate
|
||||||
|
// for all layers.
|
||||||
|
TEST_P(ScreenshareRateAllocationTest, InactiveScreenshare) {
|
||||||
|
SetupConferenceScreenshare(GetParam(), false);
|
||||||
|
CreateAllocator();
|
||||||
|
|
||||||
|
// Enough bitrate for TL0 and TL1.
|
||||||
|
uint32_t target_bitrate_kbps = (kTargetBitrateKbps + kMaxBitrateKbps) / 2;
|
||||||
|
BitrateAllocation allocation =
|
||||||
|
allocator_->GetAllocation(target_bitrate_kbps * 1000, kFramerateFps);
|
||||||
|
|
||||||
|
EXPECT_EQ(0U, allocation.get_sum_kbps());
|
||||||
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -192,6 +192,15 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
|
|||||||
video_codec.numberOfSimulcastStreams =
|
video_codec.numberOfSimulcastStreams =
|
||||||
static_cast<unsigned char>(streams.size());
|
static_cast<unsigned char>(streams.size());
|
||||||
video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
|
video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
|
||||||
|
bool codec_active = false;
|
||||||
|
for (const VideoStream& stream : streams) {
|
||||||
|
if (stream.active) {
|
||||||
|
codec_active = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set active for the entire video codec for the non simulcast case.
|
||||||
|
video_codec.active = codec_active;
|
||||||
if (video_codec.minBitrate < kEncoderMinBitrateKbps)
|
if (video_codec.minBitrate < kEncoderMinBitrateKbps)
|
||||||
video_codec.minBitrate = kEncoderMinBitrateKbps;
|
video_codec.minBitrate = kEncoderMinBitrateKbps;
|
||||||
video_codec.timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
|
video_codec.timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
|
||||||
@ -231,6 +240,7 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
|
|||||||
sim_stream->qpMax = streams[i].max_qp;
|
sim_stream->qpMax = streams[i].max_qp;
|
||||||
sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
|
sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
|
||||||
streams[i].temporal_layer_thresholds_bps.size() + 1);
|
streams[i].temporal_layer_thresholds_bps.size() + 1);
|
||||||
|
sim_stream->active = streams[i].active;
|
||||||
|
|
||||||
video_codec.width =
|
video_codec.width =
|
||||||
std::max(video_codec.width, static_cast<uint16_t>(streams[i].width));
|
std::max(video_codec.width, static_cast<uint16_t>(streams[i].width));
|
||||||
|
@ -118,6 +118,7 @@ class VideoCodecInitializerTest : public ::testing::Test {
|
|||||||
stream.target_bitrate_bps = kDefaultTargetBitrateBps;
|
stream.target_bitrate_bps = kDefaultTargetBitrateBps;
|
||||||
stream.max_bitrate_bps = kDefaultMaxBitrateBps;
|
stream.max_bitrate_bps = kDefaultMaxBitrateBps;
|
||||||
stream.max_qp = kDefaultMaxQp;
|
stream.max_qp = kDefaultMaxQp;
|
||||||
|
stream.active = true;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,6 +129,7 @@ class VideoCodecInitializerTest : public ::testing::Test {
|
|||||||
stream.max_bitrate_bps = 1000000;
|
stream.max_bitrate_bps = 1000000;
|
||||||
stream.max_framerate = kScreenshareDefaultFramerate;
|
stream.max_framerate = kScreenshareDefaultFramerate;
|
||||||
stream.temporal_layer_thresholds_bps.push_back(kScreenshareTl0BitrateBps);
|
stream.temporal_layer_thresholds_bps.push_back(kScreenshareTl0BitrateBps);
|
||||||
|
stream.active = true;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +157,20 @@ TEST_F(VideoCodecInitializerTest, SingleStreamVp8Screenshare) {
|
|||||||
EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
|
EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
|
||||||
|
SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
|
||||||
|
VideoStream inactive_stream = DefaultStream();
|
||||||
|
inactive_stream.active = false;
|
||||||
|
streams_.push_back(inactive_stream);
|
||||||
|
EXPECT_TRUE(InitializeCodec());
|
||||||
|
|
||||||
|
BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
|
||||||
|
kDefaultTargetBitrateBps, kDefaultFrameRate);
|
||||||
|
EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
|
||||||
|
EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
|
||||||
|
EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
|
TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
|
||||||
SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
|
SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
|
||||||
streams_.push_back(DefaultScreenshareStream());
|
streams_.push_back(DefaultScreenshareStream());
|
||||||
@ -169,7 +185,7 @@ TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
|
|||||||
EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
|
EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VideoCodecInitializerTest, SimlucastVp8Screenshare) {
|
TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
|
||||||
SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
|
SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
|
||||||
streams_.push_back(DefaultScreenshareStream());
|
streams_.push_back(DefaultScreenshareStream());
|
||||||
VideoStream video_stream = DefaultStream();
|
VideoStream video_stream = DefaultStream();
|
||||||
@ -190,7 +206,31 @@ TEST_F(VideoCodecInitializerTest, SimlucastVp8Screenshare) {
|
|||||||
bitrate_allocation.GetSpatialLayerSum(1));
|
bitrate_allocation.GetSpatialLayerSum(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VideoCodecInitializerTest, HighFpsSimlucastVp8Screenshare) {
|
// Tests that when a video stream is inactive, then the bitrate allocation will
|
||||||
|
// be 0 for that stream.
|
||||||
|
TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
|
||||||
|
SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
|
||||||
|
streams_.push_back(DefaultScreenshareStream());
|
||||||
|
VideoStream inactive_video_stream = DefaultStream();
|
||||||
|
inactive_video_stream.active = false;
|
||||||
|
inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
|
||||||
|
streams_.push_back(inactive_video_stream);
|
||||||
|
EXPECT_TRUE(InitializeCodec());
|
||||||
|
|
||||||
|
EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
|
||||||
|
EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
|
||||||
|
const uint32_t target_bitrate =
|
||||||
|
streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
|
||||||
|
BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
|
||||||
|
target_bitrate, kScreenshareDefaultFramerate);
|
||||||
|
EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
|
||||||
|
bitrate_allocation.get_sum_bps());
|
||||||
|
EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
|
||||||
|
bitrate_allocation.GetSpatialLayerSum(0));
|
||||||
|
EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
|
||||||
// Two simulcast streams, the lower one using legacy settings (two temporal
|
// Two simulcast streams, the lower one using legacy settings (two temporal
|
||||||
// streams, 5fps), the higher one using 3 temporal streams and 30fps.
|
// streams, 5fps), the higher one using 3 temporal streams and 30fps.
|
||||||
SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
|
SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
|
||||||
|
@ -50,6 +50,7 @@ std::vector<VideoStream> CreateVideoStreams(
|
|||||||
std::min(bitrate_left_bps,
|
std::min(bitrate_left_bps,
|
||||||
DefaultVideoStreamFactory::kMaxBitratePerStream[i]);
|
DefaultVideoStreamFactory::kMaxBitratePerStream[i]);
|
||||||
stream_settings[i].max_qp = 56;
|
stream_settings[i].max_qp = 56;
|
||||||
|
stream_settings[i].active = true;
|
||||||
bitrate_left_bps -= stream_settings[i].target_bitrate_bps;
|
bitrate_left_bps -= stream_settings[i].target_bitrate_bps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ static void CodecSettings(VideoCodecType codec_type, VideoCodec* settings) {
|
|||||||
settings->timing_frame_thresholds = {
|
settings->timing_frame_thresholds = {
|
||||||
kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
|
kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
|
||||||
};
|
};
|
||||||
|
settings->active = true;
|
||||||
*(settings->VP8()) = VideoEncoder::GetDefaultVp8Settings();
|
*(settings->VP8()) = VideoEncoder::GetDefaultVp8Settings();
|
||||||
return;
|
return;
|
||||||
case kVideoCodecVP9:
|
case kVideoCodecVP9:
|
||||||
@ -61,6 +62,7 @@ static void CodecSettings(VideoCodecType codec_type, VideoCodec* settings) {
|
|||||||
settings->timing_frame_thresholds = {
|
settings->timing_frame_thresholds = {
|
||||||
kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
|
kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
|
||||||
};
|
};
|
||||||
|
settings->active = true;
|
||||||
*(settings->VP9()) = VideoEncoder::GetDefaultVp9Settings();
|
*(settings->VP9()) = VideoEncoder::GetDefaultVp9Settings();
|
||||||
return;
|
return;
|
||||||
case kVideoCodecH264:
|
case kVideoCodecH264:
|
||||||
@ -79,6 +81,7 @@ static void CodecSettings(VideoCodecType codec_type, VideoCodec* settings) {
|
|||||||
settings->timing_frame_thresholds = {
|
settings->timing_frame_thresholds = {
|
||||||
kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
|
kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
|
||||||
};
|
};
|
||||||
|
settings->active = true;
|
||||||
*(settings->H264()) = VideoEncoder::GetDefaultH264Settings();
|
*(settings->H264()) = VideoEncoder::GetDefaultH264Settings();
|
||||||
return;
|
return;
|
||||||
case kVideoCodecI420:
|
case kVideoCodecI420:
|
||||||
@ -95,6 +98,7 @@ static void CodecSettings(VideoCodecType codec_type, VideoCodec* settings) {
|
|||||||
settings->height = kTestHeight;
|
settings->height = kTestHeight;
|
||||||
settings->minBitrate = kTestMinBitrateKbps;
|
settings->minBitrate = kTestMinBitrateKbps;
|
||||||
settings->numberOfSimulcastStreams = 0;
|
settings->numberOfSimulcastStreams = 0;
|
||||||
|
settings->active = true;
|
||||||
return;
|
return;
|
||||||
case kVideoCodecRED:
|
case kVideoCodecRED:
|
||||||
case kVideoCodecULPFEC:
|
case kVideoCodecULPFEC:
|
||||||
|
@ -258,8 +258,11 @@ void PayloadRouter::OnBitrateAllocationUpdated(
|
|||||||
// rtp stream, moving over the temporal layer allocation.
|
// rtp stream, moving over the temporal layer allocation.
|
||||||
for (size_t si = 0; si < rtp_modules_.size(); ++si) {
|
for (size_t si = 0; si < rtp_modules_.size(); ++si) {
|
||||||
// Don't send empty TargetBitrate messages on streams not being relayed.
|
// Don't send empty TargetBitrate messages on streams not being relayed.
|
||||||
if (!bitrate.IsSpatialLayerUsed(si))
|
if (!bitrate.IsSpatialLayerUsed(si)) {
|
||||||
break;
|
// The next spatial layer could be used if the current one is
|
||||||
|
// inactive.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
BitrateAllocation layer_bitrate;
|
BitrateAllocation layer_bitrate;
|
||||||
for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
|
for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
|
||||||
|
@ -32,6 +32,7 @@ namespace {
|
|||||||
const int8_t kPayloadType = 96;
|
const int8_t kPayloadType = 96;
|
||||||
const uint32_t kSsrc1 = 12345;
|
const uint32_t kSsrc1 = 12345;
|
||||||
const uint32_t kSsrc2 = 23456;
|
const uint32_t kSsrc2 = 23456;
|
||||||
|
const uint32_t kSsrc3 = 34567;
|
||||||
const int16_t kPictureId = 123;
|
const int16_t kPictureId = 123;
|
||||||
const int16_t kTl0PicIdx = 20;
|
const int16_t kTl0PicIdx = 20;
|
||||||
const uint8_t kTemporalIdx = 1;
|
const uint8_t kTemporalIdx = 1;
|
||||||
@ -186,23 +187,38 @@ TEST(PayloadRouterTest, SimulcastTargetBitrate) {
|
|||||||
payload_router.OnBitrateAllocationUpdated(bitrate);
|
payload_router.OnBitrateAllocationUpdated(bitrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the middle of three streams is inactive the first and last streams should
|
||||||
|
// be asked to send the TargetBitrate message.
|
||||||
TEST(PayloadRouterTest, SimulcastTargetBitrateWithInactiveStream) {
|
TEST(PayloadRouterTest, SimulcastTargetBitrateWithInactiveStream) {
|
||||||
// Set up two active rtp modules.
|
// Set up three active rtp modules.
|
||||||
NiceMock<MockRtpRtcp> rtp_1;
|
NiceMock<MockRtpRtcp> rtp_1;
|
||||||
NiceMock<MockRtpRtcp> rtp_2;
|
NiceMock<MockRtpRtcp> rtp_2;
|
||||||
std::vector<RtpRtcp*> modules = {&rtp_1, &rtp_2};
|
NiceMock<MockRtpRtcp> rtp_3;
|
||||||
PayloadRouter payload_router(modules, {kSsrc1, kSsrc2}, kPayloadType, {});
|
std::vector<RtpRtcp*> modules = {&rtp_1, &rtp_2, &rtp_3};
|
||||||
|
PayloadRouter payload_router(modules, {kSsrc1, kSsrc2, kSsrc3}, kPayloadType,
|
||||||
|
{});
|
||||||
payload_router.SetActive(true);
|
payload_router.SetActive(true);
|
||||||
|
|
||||||
// Create bitrate allocation with bitrate only for the first stream.
|
// Create bitrate allocation with bitrate only for the first and third stream.
|
||||||
BitrateAllocation bitrate;
|
BitrateAllocation bitrate;
|
||||||
bitrate.SetBitrate(0, 0, 10000);
|
bitrate.SetBitrate(0, 0, 10000);
|
||||||
bitrate.SetBitrate(0, 1, 20000);
|
bitrate.SetBitrate(0, 1, 20000);
|
||||||
|
bitrate.SetBitrate(2, 0, 40000);
|
||||||
|
bitrate.SetBitrate(2, 1, 80000);
|
||||||
|
|
||||||
// Expect only the first rtp module to be asked to send a TargetBitrate
|
BitrateAllocation layer0_bitrate;
|
||||||
|
layer0_bitrate.SetBitrate(0, 0, 10000);
|
||||||
|
layer0_bitrate.SetBitrate(0, 1, 20000);
|
||||||
|
|
||||||
|
BitrateAllocation layer2_bitrate;
|
||||||
|
layer2_bitrate.SetBitrate(0, 0, 40000);
|
||||||
|
layer2_bitrate.SetBitrate(0, 1, 80000);
|
||||||
|
|
||||||
|
// Expect the first and third rtp module to be asked to send a TargetBitrate
|
||||||
// message. (No target bitrate with 0bps sent from the second one.)
|
// message. (No target bitrate with 0bps sent from the second one.)
|
||||||
EXPECT_CALL(rtp_1, SetVideoBitrateAllocation(bitrate)).Times(1);
|
EXPECT_CALL(rtp_1, SetVideoBitrateAllocation(layer0_bitrate)).Times(1);
|
||||||
EXPECT_CALL(rtp_2, SetVideoBitrateAllocation(_)).Times(0);
|
EXPECT_CALL(rtp_2, SetVideoBitrateAllocation(_)).Times(0);
|
||||||
|
EXPECT_CALL(rtp_3, SetVideoBitrateAllocation(layer2_bitrate)).Times(1);
|
||||||
|
|
||||||
payload_router.OnBitrateAllocationUpdated(bitrate);
|
payload_router.OnBitrateAllocationUpdated(bitrate);
|
||||||
}
|
}
|
||||||
|
@ -1200,6 +1200,7 @@ VideoStream VideoQualityTest::DefaultVideoStream(const Params& params,
|
|||||||
stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
|
stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
|
||||||
stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
|
stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
|
||||||
stream.max_qp = kDefaultMaxQp;
|
stream.max_qp = kDefaultMaxQp;
|
||||||
|
stream.active = true;
|
||||||
// TODO(sprang): Can we make this less of a hack?
|
// TODO(sprang): Can we make this less of a hack?
|
||||||
if (params.video[video_idx].num_temporal_layers == 2) {
|
if (params.video[video_idx].num_temporal_layers == 2) {
|
||||||
stream.temporal_layer_thresholds_bps.push_back(stream.target_bitrate_bps);
|
stream.temporal_layer_thresholds_bps.push_back(stream.target_bitrate_bps);
|
||||||
|
@ -967,7 +967,8 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged(
|
|||||||
encoder_max_bitrate_bps_ = 0;
|
encoder_max_bitrate_bps_ = 0;
|
||||||
double stream_bitrate_priority_sum = 0;
|
double stream_bitrate_priority_sum = 0;
|
||||||
for (const auto& stream : streams) {
|
for (const auto& stream : streams) {
|
||||||
encoder_max_bitrate_bps_ += stream.max_bitrate_bps;
|
// We don't want to allocate more bitrate than needed to inactive streams.
|
||||||
|
encoder_max_bitrate_bps_ += stream.active ? stream.max_bitrate_bps : 0;
|
||||||
if (stream.bitrate_priority) {
|
if (stream.bitrate_priority) {
|
||||||
RTC_DCHECK_GT(*stream.bitrate_priority, 0);
|
RTC_DCHECK_GT(*stream.bitrate_priority, 0);
|
||||||
stream_bitrate_priority_sum += *stream.bitrate_priority;
|
stream_bitrate_priority_sum += *stream.bitrate_priority;
|
||||||
@ -975,6 +976,9 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged(
|
|||||||
}
|
}
|
||||||
RTC_DCHECK_GT(stream_bitrate_priority_sum, 0);
|
RTC_DCHECK_GT(stream_bitrate_priority_sum, 0);
|
||||||
encoder_bitrate_priority_ = stream_bitrate_priority_sum;
|
encoder_bitrate_priority_ = stream_bitrate_priority_sum;
|
||||||
|
encoder_max_bitrate_bps_ =
|
||||||
|
std::max(static_cast<uint32_t>(encoder_min_bitrate_bps_),
|
||||||
|
encoder_max_bitrate_bps_);
|
||||||
max_padding_bitrate_ = CalculateMaxPadBitrateBps(
|
max_padding_bitrate_ = CalculateMaxPadBitrateBps(
|
||||||
streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate);
|
streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user