diff --git a/webrtc/test/call_test.cc b/webrtc/test/call_test.cc index d49f6e3fe4..4e7fa9acaa 100644 --- a/webrtc/test/call_test.cc +++ b/webrtc/test/call_test.cc @@ -19,6 +19,7 @@ CallTest::CallTest() send_stream_(NULL), fake_encoder_(clock_) { } + CallTest::~CallTest() { } diff --git a/webrtc/video/call_perf_tests.cc b/webrtc/video/call_perf_tests.cc index f42e5dd0ba..1087239be4 100644 --- a/webrtc/video/call_perf_tests.cc +++ b/webrtc/video/call_perf_tests.cc @@ -570,4 +570,92 @@ TEST_F(CallPerfTest, NoPadWithoutMinTransmitBitrate) { TestMinTransmitBitrate(false); } +TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) { + static const uint32_t kInitialBitrateKbps = 400; + static const uint32_t kReconfigureThresholdKbps = 600; + static const uint32_t kPermittedReconfiguredBitrateDiffKbps = 100; + + class BitrateObserver : public test::EndToEndTest, public test::FakeEncoder { + public: + BitrateObserver() + : EndToEndTest(kDefaultTimeoutMs), + FakeEncoder(Clock::GetRealTimeClock()), + time_to_reconfigure_(webrtc::EventWrapper::Create()), + encoder_inits_(0) {} + + virtual int32_t InitEncode(const VideoCodec* config, + int32_t number_of_cores, + uint32_t max_payload_size) OVERRIDE { + if (encoder_inits_ == 0) { + EXPECT_EQ(kInitialBitrateKbps, config->startBitrate) + << "Encoder not initialized at expected bitrate."; + } + ++encoder_inits_; + if (encoder_inits_ == 2) { + EXPECT_GE(last_set_bitrate_, kReconfigureThresholdKbps); + EXPECT_NEAR(config->startBitrate, + last_set_bitrate_, + kPermittedReconfiguredBitrateDiffKbps) + << "Encoder reconfigured with bitrate too far away from last set."; + observation_complete_->Set(); + } + return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size); + } + + virtual int32_t SetRates(uint32_t new_target_bitrate_kbps, + uint32_t framerate) OVERRIDE { + last_set_bitrate_ = new_target_bitrate_kbps; + if (encoder_inits_ == 1 && + new_target_bitrate_kbps > kReconfigureThresholdKbps) { + time_to_reconfigure_->Set(); + } + return FakeEncoder::SetRates(new_target_bitrate_kbps, framerate); + } + + Call::Config GetSenderCallConfig() OVERRIDE { + Call::Config config = EndToEndTest::GetSenderCallConfig(); + config.stream_start_bitrate_bps = kInitialBitrateKbps * 1000; + return config; + } + + virtual void ModifyConfigs( + VideoSendStream::Config* send_config, + std::vector* receive_configs, + VideoEncoderConfig* encoder_config) OVERRIDE { + send_config->encoder_settings.encoder = this; + encoder_config->streams[0].min_bitrate_bps = 50000; + encoder_config->streams[0].target_bitrate_bps = + encoder_config->streams[0].max_bitrate_bps = 2000000; + + encoder_config_ = *encoder_config; + } + + virtual void OnStreamsCreated( + VideoSendStream* send_stream, + const std::vector& receive_streams) OVERRIDE { + send_stream_ = send_stream; + } + + virtual void PerformTest() OVERRIDE { + ASSERT_EQ(kEventSignaled, time_to_reconfigure_->Wait(kDefaultTimeoutMs)) + << "Timed out before receiving an initial high bitrate."; + encoder_config_.streams[0].width *= 2; + encoder_config_.streams[0].height *= 2; + EXPECT_TRUE(send_stream_->ReconfigureVideoEncoder(encoder_config_)); + EXPECT_EQ(kEventSignaled, Wait()) + << "Timed out while waiting for a couple of high bitrate estimates " + "after reconfiguring the send stream."; + } + + private: + scoped_ptr time_to_reconfigure_; + int encoder_inits_; + uint32_t last_set_bitrate_; + VideoSendStream* send_stream_; + VideoEncoderConfig encoder_config_; + } test; + + RunBaseTest(&test); +} + } // namespace webrtc diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index 0e87a03386..ee36dd5db9 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -1791,6 +1791,19 @@ void EndToEndTest::TestRtpStatePreservation(bool use_rtx) { encoder_config_.streams[i].max_bitrate_bps = 20000; } + // Use the same total bitrates when sending a single stream to avoid lowering + // the bitrate estimate and requiring a subsequent rampup. + VideoEncoderConfig one_stream = encoder_config_; + one_stream.streams.resize(1); + for (size_t i = 1; i < encoder_config_.streams.size(); ++i) { + one_stream.streams.front().min_bitrate_bps += + encoder_config_.streams[i].min_bitrate_bps; + one_stream.streams.front().target_bitrate_bps += + encoder_config_.streams[i].target_bitrate_bps; + one_stream.streams.front().max_bitrate_bps += + encoder_config_.streams[i].max_bitrate_bps; + } + CreateMatchingReceiveConfigs(); CreateStreams(); @@ -1807,8 +1820,6 @@ void EndToEndTest::TestRtpStatePreservation(bool use_rtx) { sender_call_->DestroyVideoSendStream(send_stream_); // Re-create VideoSendStream with only one stream. - VideoEncoderConfig one_stream = encoder_config_; - one_stream.streams.resize(1); send_stream_ = sender_call_->CreateVideoSendStream(send_config_, one_stream); send_stream_->Start(); diff --git a/webrtc/video/rampup_tests.cc b/webrtc/video/rampup_tests.cc index 96a22763d3..011ef6af57 100644 --- a/webrtc/video/rampup_tests.cc +++ b/webrtc/video/rampup_tests.cc @@ -154,7 +154,9 @@ bool StreamObserver::SendRtcp(const uint8_t* packet, size_t length) { return true; } -EventTypeWrapper StreamObserver::Wait() { return test_done_->Wait(120 * 1000); } +EventTypeWrapper StreamObserver::Wait() { + return test_done_->Wait(test::CallTest::kLongTimeoutMs); +} void StreamObserver::ReportResult(const std::string& measurement, size_t value, diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index 6e8f238165..635c37f72d 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -125,6 +125,7 @@ VideoSendStream::VideoSendStream( suspended_ssrcs_(suspended_ssrcs), external_codec_(NULL), channel_(-1), + use_default_bitrate_(true), stats_proxy_(config) { video_engine_base_ = ViEBase::GetInterface(video_engine); video_engine_base_->CreateChannel(channel_, base_channel); @@ -378,8 +379,13 @@ bool VideoSendStream::ReconfigureVideoEncoder( video_codec.qpMax = std::max(video_codec.qpMax, static_cast(streams[i].max_qp)); } + unsigned int start_bitrate_bps; + if (codec_->GetCodecTargetBitrate(channel_, &start_bitrate_bps) != 0 || + use_default_bitrate_) { + start_bitrate_bps = start_bitrate_bps_; + } video_codec.startBitrate = - static_cast(start_bitrate_bps_) / 1000; + static_cast(start_bitrate_bps) / 1000; if (video_codec.minBitrate < kViEMinCodecBitrate) video_codec.minBitrate = kViEMinCodecBitrate; @@ -398,7 +404,11 @@ bool VideoSendStream::ReconfigureVideoEncoder( assert(streams[0].max_framerate > 0); video_codec.maxFramerate = streams[0].max_framerate; - return codec_->SetSendCodec(channel_, video_codec) == 0; + if (codec_->SetSendCodec(channel_, video_codec) != 0) + return false; + + use_default_bitrate_ = false; + return true; } bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h index 8a77852e37..f7874308eb 100644 --- a/webrtc/video/video_send_stream.h +++ b/webrtc/video/video_send_stream.h @@ -94,6 +94,11 @@ class VideoSendStream : public webrtc::VideoSendStream, int channel_; int capture_id_; + // Used as a workaround to indicate that we should be using the configured + // start bitrate initially, instead of the one reported by VideoEngine (which + // defaults to too high). + bool use_default_bitrate_; + SendStatisticsProxy stats_proxy_; }; } // namespace internal