| Index: webrtc/modules/video_coding/utility/simulcast_state_unittest.cc
|
| diff --git a/webrtc/modules/video_coding/utility/simulcast_state_unittest.cc b/webrtc/modules/video_coding/utility/simulcast_state_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aecdd74341e3b58e42a6c06ccb47ba150c6e53e6
|
| --- /dev/null
|
| +++ b/webrtc/modules/video_coding/utility/simulcast_state_unittest.cc
|
| @@ -0,0 +1,304 @@
|
| +/*
|
| + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license
|
| + * that can be found in the LICENSE file in the root of the source
|
| + * tree. An additional intellectual property rights grant can be found
|
| + * in the file PATENTS. All contributing project authors may
|
| + * be found in the AUTHORS file in the root of the source tree.
|
| + */
|
| +
|
| +#include "webrtc/modules/video_coding/utility/simulcast_state.h"
|
| +
|
| +#include <algorithm>
|
| +#include <memory>
|
| +#include <vector>
|
| +
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace webrtc {
|
| +namespace {
|
| +const int kMaxStreams = kMaxSimulcastStreams;
|
| +} // namespace
|
| +
|
| +class SimulcastStateTest : public ::testing::Test {
|
| + public:
|
| + SimulcastStateTest() {}
|
| + virtual ~SimulcastStateTest() {}
|
| +
|
| + void SetUp() override {
|
| + memset(&codec_, 0, sizeof(VideoCodec));
|
| + codec_.codecType = kVideoCodecVP8;
|
| + codec_.numberOfSimulcastStreams = 0;
|
| + codec_.minBitrate = 60;
|
| + codec_.targetBitrate = 600;
|
| + codec_.maxBitrate = 2400;
|
| + codec_.startBitrate = 300;
|
| + }
|
| +
|
| + void ExpectState(
|
| + const std::vector<SimulcastState::Stream>& expected_streams) {
|
| + const std::vector<SimulcastState::Stream>& actual_streams =
|
| + simulcast_state_->Streams();
|
| + ASSERT_EQ(expected_streams.size(), actual_streams.size());
|
| + const int num_streams = expected_streams.size();
|
| + ASSERT_LE(num_streams, kMaxStreams);
|
| + for (int i = 0; i < num_streams; ++i) {
|
| + const SimulcastState::Stream& expected = expected_streams[i];
|
| + const SimulcastState::Stream& actual = actual_streams[i];
|
| + EXPECT_EQ(i, expected.idx);
|
| + EXPECT_EQ(i, actual.idx);
|
| + EXPECT_EQ(expected.allocated_rate_bps, actual.allocated_rate_bps);
|
| + EXPECT_EQ(expected.sending, actual.sending);
|
| + EXPECT_EQ(expected.keyframe_request, actual.keyframe_request);
|
| + }
|
| + }
|
| +
|
| + void TestRateAllocation() {
|
| + int spillover_bps = 0;
|
| + int margin_bps = 0;
|
| + std::vector<SimulcastState::Stream> expected_streams;
|
| + for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) {
|
| + SimulcastState::Stream stream(i, &codec_, 0);
|
| + stream.sending = i == 0;
|
| + stream.keyframe_request = stream.sending;
|
| + stream.allocated_rate_bps =
|
| + stream.sending ? stream.config.minBitrate * 1000 : 0;
|
| + expected_streams.push_back(stream);
|
| + }
|
| +
|
| + simulcast_state_.reset(new SimulcastState(codec_));
|
| + simulcast_state_->AllocateBitrate(0);
|
| + EXPECT_TRUE(simulcast_state_->GetAndResetKeyFrameRequest(0));
|
| + expected_streams[0].keyframe_request = false;
|
| +
|
| + int top_layer = 0;
|
| + for (uint32_t i = 1; i < codec_.maxBitrate; ++i) {
|
| + simulcast_state_->AllocateBitrate(i * 1000);
|
| + ExpectState(expected_streams);
|
| +
|
| + // Always allocate enough bitrate for the lowest stream.
|
| + if (top_layer == 0 && i < codec_.simulcastStream[0].minBitrate) {
|
| + expected_streams[0].allocated_rate_bps =
|
| + codec_.simulcastStream[0].minBitrate * 1000;
|
| + continue;
|
| + }
|
| +
|
| + const int min_bitrate =
|
| + expected_streams[top_layer].config.minBitrate * 1000;
|
| + const int target_bitrate =
|
| + expected_streams[top_layer].config.targetBitrate * 1000;
|
| + const int max_bitrate =
|
| + expected_streams[top_layer].config.maxBitrate * 1000;
|
| +
|
| + if (top_layer > 0 &&
|
| + expected_streams[top_layer].allocated_rate_bps == min_bitrate) {
|
| + // Update and reset key frame status on first updater after enabling
|
| + // layer.
|
| + EXPECT_TRUE(simulcast_state_->GetAndResetKeyFrameRequest(top_layer));
|
| + expected_streams[top_layer].keyframe_request = false;
|
| + }
|
| +
|
| + // First fill up the top layer until target_bitrate.
|
| + if (expected_streams[top_layer].allocated_rate_bps < target_bitrate) {
|
| + expected_streams[top_layer].allocated_rate_bps += 1000;
|
| + continue;
|
| + }
|
| +
|
| + // We have allocated up to the target bitrate. Anything above this may
|
| + // be reallocated to a higher layer once it has enough bitrate to reach
|
| + // its min_bitrate.
|
| + margin_bps += 1000;
|
| + if (expected_streams[top_layer].allocated_rate_bps < max_bitrate) {
|
| + expected_streams[top_layer].allocated_rate_bps += 1000;
|
| + } else {
|
| + // TODO(sprang): When we enable allocating extra bits to layers other
|
| + // than the top one, traverse down and do that here.
|
| + spillover_bps += 1000;
|
| + }
|
| +
|
| + // Check if there is enough bitrate to enable the next layer.
|
| + if (top_layer + 1 < codec_.numberOfSimulcastStreams &&
|
| + margin_bps >= static_cast<int>(
|
| + expected_streams[top_layer + 1].config.minBitrate) *
|
| + 1000) {
|
| + ++top_layer;
|
| + expected_streams[top_layer].sending = true;
|
| + expected_streams[top_layer].keyframe_request = true;
|
| +
|
| + // Steal margin bits from the lower layers.
|
| + // TODO(sprang): Loop over j when we enable allocating extra bits to
|
| + // layers other than the top one.
|
| + int j = top_layer - 1;
|
| + int available_margin =
|
| + expected_streams[j].allocated_rate_bps -
|
| + (expected_streams[j].config.targetBitrate * 1000);
|
| + int consumed_margin = std::min(available_margin, margin_bps);
|
| + expected_streams[j].allocated_rate_bps -= consumed_margin;
|
| + margin_bps -= consumed_margin;
|
| +
|
| + if (margin_bps > 0 && spillover_bps > 0) {
|
| + // The rest of the needed margin is in allocated spillover.
|
| + EXPECT_EQ(margin_bps, spillover_bps);
|
| + spillover_bps = 0;
|
| + margin_bps = 0;
|
| + } else {
|
| + EXPECT_EQ(0, margin_bps);
|
| + }
|
| +
|
| + expected_streams[top_layer].allocated_rate_bps =
|
| + expected_streams[top_layer].config.minBitrate * 1000;
|
| + }
|
| + }
|
| + }
|
| +
|
| + VideoCodec codec_;
|
| + std::unique_ptr<SimulcastState> simulcast_state_;
|
| +};
|
| +
|
| +TEST_F(SimulcastStateTest, NoSimulcast) {
|
| + simulcast_state_.reset(new SimulcastState(codec_));
|
| +
|
| + SimulcastState::Stream expected_stream(0, &codec_,
|
| + codec_.startBitrate * 1000);
|
| + std::vector<SimulcastState::Stream> expected_streams;
|
| + expected_streams.push_back(expected_stream);
|
| +
|
| + ExpectState(expected_streams);
|
| +
|
| + for (uint32_t i = 0; i < codec_.maxBitrate + 1; ++i) {
|
| + simulcast_state_->AllocateBitrate(i * 1000);
|
| + if (i < codec_.minBitrate) {
|
| + expected_streams[0].allocated_rate_bps = codec_.minBitrate * 1000;
|
| + } else if (i > codec_.maxBitrate) {
|
| + expected_streams[0].allocated_rate_bps = codec_.maxBitrate * 1000;
|
| + } else {
|
| + expected_streams[0].allocated_rate_bps = i * 1000;
|
| + }
|
| + ExpectState(expected_streams);
|
| + }
|
| +}
|
| +
|
| +TEST_F(SimulcastStateTest, MultipleStreamsRates) {
|
| + for (int num_streams = 1; num_streams < kMaxStreams; ++num_streams) {
|
| + codec_.numberOfSimulcastStreams = num_streams;
|
| + codec_.startBitrate = 0;
|
| +
|
| + for (int i = 0; i < num_streams; ++i) {
|
| + codec_.simulcastStream[i].minBitrate =
|
| + ((i + 1) * codec_.minBitrate) / kMaxStreams;
|
| + codec_.simulcastStream[i].targetBitrate =
|
| + ((i + 1) * codec_.targetBitrate) / kMaxStreams;
|
| + codec_.simulcastStream[i].maxBitrate =
|
| + ((i + 1) * codec_.maxBitrate) / kMaxStreams;
|
| + }
|
| +
|
| + TestRateAllocation();
|
| + }
|
| +}
|
| +
|
| +TEST_F(SimulcastStateTest, NextMinLargerThanMax) {
|
| + codec_.startBitrate = 0;
|
| + codec_.numberOfSimulcastStreams = 2;
|
| + codec_.simulcastStream[0].minBitrate = 10;
|
| + codec_.simulcastStream[0].targetBitrate = 100;
|
| + codec_.simulcastStream[0].maxBitrate = 200;
|
| + codec_.simulcastStream[1].minBitrate = 300;
|
| + codec_.simulcastStream[1].targetBitrate = 400;
|
| + codec_.simulcastStream[1].maxBitrate = 500;
|
| +
|
| + TestRateAllocation();
|
| +}
|
| +
|
| +TEST_F(SimulcastStateTest, LargerMinButLowerMax) {
|
| + codec_.startBitrate = 0;
|
| + codec_.numberOfSimulcastStreams = 3;
|
| + codec_.simulcastStream[0].minBitrate = 100;
|
| + codec_.simulcastStream[0].targetBitrate = 200;
|
| + codec_.simulcastStream[0].maxBitrate = 600;
|
| + codec_.simulcastStream[1].minBitrate = 200;
|
| + codec_.simulcastStream[1].targetBitrate = 300;
|
| + codec_.simulcastStream[1].maxBitrate = 400;
|
| + codec_.simulcastStream[2].minBitrate = 300;
|
| + codec_.simulcastStream[2].targetBitrate = 600;
|
| + codec_.simulcastStream[2].maxBitrate = 800;
|
| +
|
| + TestRateAllocation();
|
| +}
|
| +
|
| +TEST_F(SimulcastStateTest, SetsSendingAndKeyframeStates) {
|
| + codec_.startBitrate = 0;
|
| + codec_.numberOfSimulcastStreams = 3;
|
| +
|
| + codec_.simulcastStream[0].minBitrate = 100;
|
| + codec_.simulcastStream[0].targetBitrate = 200;
|
| + codec_.simulcastStream[0].maxBitrate = 600;
|
| + const int kFirstCutoff = codec_.simulcastStream[0].minBitrate * 1000;
|
| +
|
| + codec_.simulcastStream[1].minBitrate = 300;
|
| + codec_.simulcastStream[1].targetBitrate = 600;
|
| + codec_.simulcastStream[1].maxBitrate = 1200;
|
| + const int kSecondCutoff = (codec_.simulcastStream[0].targetBitrate +
|
| + codec_.simulcastStream[1].minBitrate) *
|
| + 1000;
|
| +
|
| + codec_.simulcastStream[2].minBitrate = 500;
|
| + codec_.simulcastStream[2].targetBitrate = 800;
|
| + codec_.simulcastStream[2].maxBitrate = 1500;
|
| + const int kThirdCutoff = (codec_.simulcastStream[0].targetBitrate +
|
| + codec_.simulcastStream[1].targetBitrate +
|
| + codec_.simulcastStream[2].minBitrate) *
|
| + 1000;
|
| +
|
| + simulcast_state_.reset(new SimulcastState(codec_));
|
| +
|
| + simulcast_state_->AllocateBitrate(kFirstCutoff);
|
| + EXPECT_TRUE(simulcast_state_->GetAndResetKeyFrameRequest(0));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(0));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(1));
|
| + EXPECT_FALSE(simulcast_state_->IsSending(1));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(2));
|
| + EXPECT_FALSE(simulcast_state_->IsSending(2));
|
| +
|
| + simulcast_state_->AllocateBitrate(kSecondCutoff);
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(0));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(0));
|
| + EXPECT_TRUE(simulcast_state_->GetAndResetKeyFrameRequest(1));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(1));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(2));
|
| + EXPECT_FALSE(simulcast_state_->IsSending(2));
|
| +
|
| + simulcast_state_->AllocateBitrate(kThirdCutoff);
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(0));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(0));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(1));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(1));
|
| + EXPECT_TRUE(simulcast_state_->GetAndResetKeyFrameRequest(2));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(2));
|
| +
|
| + simulcast_state_->AllocateBitrate(kSecondCutoff);
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(0));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(0));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(1));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(1));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(2));
|
| + EXPECT_FALSE(simulcast_state_->IsSending(2));
|
| +
|
| + simulcast_state_->AllocateBitrate(kFirstCutoff);
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(0));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(0));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(1));
|
| + EXPECT_FALSE(simulcast_state_->IsSending(1));
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(2));
|
| + EXPECT_FALSE(simulcast_state_->IsSending(2));
|
| +
|
| + simulcast_state_->AllocateBitrate(kThirdCutoff);
|
| + EXPECT_FALSE(simulcast_state_->GetAndResetKeyFrameRequest(0));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(0));
|
| + EXPECT_TRUE(simulcast_state_->GetAndResetKeyFrameRequest(1));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(1));
|
| + EXPECT_TRUE(simulcast_state_->GetAndResetKeyFrameRequest(2));
|
| + EXPECT_TRUE(simulcast_state_->IsSending(2));
|
| +}
|
| +
|
| +} // namespace webrtc
|
|
|