Adds unit tests for VideoSendStreamImpl.

Bug: None
Change-Id: Ifadad47af4769d8aca42c98832cea49a6c7977cd
Reviewed-on: https://webrtc-review.googlesource.com/71040
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22959}
This commit is contained in:
Sebastian Jansson 2018-04-19 17:09:15 +02:00 committed by Commit Bot
parent 33444dc835
commit 652dc915bc
9 changed files with 300 additions and 55 deletions

View File

@ -127,6 +127,16 @@ rtc_source_set("video_stream_decoder_impl") {
}
if (rtc_include_tests) {
rtc_source_set("video_mocks") {
testonly = true
sources = [
"test/mock_video_stream_encoder.h",
]
deps = [
":video",
"../test:test_support",
]
}
rtc_source_set("video_quality_test") {
testonly = true
visibility = [ ":*" ] # Only targets in this file can depend on this.
@ -336,16 +346,19 @@ if (rtc_include_tests) {
"stats_counter_unittest.cc",
"stream_synchronization_unittest.cc",
"video_receive_stream_unittest.cc",
"video_send_stream_impl_unittest.cc",
"video_send_stream_tests.cc",
"video_stream_encoder_unittest.cc",
]
deps = [
":video",
":video_mocks",
"../api:optional",
"../api:video_frame_api",
"../api:video_frame_api_i420",
"../api/video_codecs:video_codecs_api",
"../call:call_interfaces",
"../call:mock_bitrate_allocator",
"../call:mock_rtp_interfaces",
"../call:rtp_receiver",
"../call:rtp_sender",
@ -377,6 +390,7 @@ if (rtc_include_tests) {
"../rtc_base:rtc_base_tests_utils",
"../rtc_base:rtc_numerics",
"../rtc_base:rtc_task_queue",
"../rtc_base:rtc_task_queue_for_test",
"../rtc_base/experiments:alr_experiment",
"../system_wrappers",
"../system_wrappers:field_trial_default",

View File

@ -19,7 +19,7 @@ namespace webrtc {
EncoderRtcpFeedback::EncoderRtcpFeedback(Clock* clock,
const std::vector<uint32_t>& ssrcs,
VideoStreamEncoder* encoder)
VideoStreamEncoderInterface* encoder)
: clock_(clock),
ssrcs_(ssrcs),
video_stream_encoder_(encoder),

View File

@ -19,13 +19,13 @@
namespace webrtc {
class VideoStreamEncoder;
class VideoStreamEncoderInterface;
class EncoderRtcpFeedback : public RtcpIntraFrameObserver {
public:
EncoderRtcpFeedback(Clock* clock,
const std::vector<uint32_t>& ssrcs,
VideoStreamEncoder* encoder);
const std::vector<uint32_t>& ssrcs,
VideoStreamEncoderInterface* encoder);
void OnReceivedIntraFrameRequest(uint32_t ssrc) override;
private:
@ -34,7 +34,7 @@ class EncoderRtcpFeedback : public RtcpIntraFrameObserver {
Clock* const clock_;
const std::vector<uint32_t> ssrcs_;
VideoStreamEncoder* const video_stream_encoder_;
VideoStreamEncoderInterface* const video_stream_encoder_;
rtc::CriticalSection crit_;
std::vector<int64_t> time_last_intra_request_ms_ RTC_GUARDED_BY(crit_);

View File

@ -14,34 +14,17 @@
#include "test/gmock.h"
#include "test/gtest.h"
#include "video/send_statistics_proxy.h"
#include "video/video_stream_encoder.h"
#include "video/test/mock_video_stream_encoder.h"
using ::testing::NiceMock;
namespace webrtc {
class MockVideoStreamEncoder : public VideoStreamEncoder {
public:
explicit MockVideoStreamEncoder(SendStatisticsProxy* send_stats_proxy)
: VideoStreamEncoder(1,
send_stats_proxy,
VideoSendStream::Config::EncoderSettings(),
nullptr,
rtc::MakeUnique<OveruseFrameDetector>(nullptr)) {}
~MockVideoStreamEncoder() { Stop(); }
MOCK_METHOD0(SendKeyFrame, void());
};
class VieKeyRequestTest : public ::testing::Test {
public:
VieKeyRequestTest()
: simulated_clock_(123456789),
send_stats_proxy_(&simulated_clock_,
VideoSendStream::Config(nullptr),
VideoEncoderConfig::ContentType::kRealtimeVideo),
encoder_(&send_stats_proxy_),
encoder_(),
encoder_rtcp_feedback_(
&simulated_clock_,
std::vector<uint32_t>(1, VieKeyRequestTest::kSsrc),
@ -51,8 +34,7 @@ class VieKeyRequestTest : public ::testing::Test {
const uint32_t kSsrc = 1234;
SimulatedClock simulated_clock_;
SendStatisticsProxy send_stats_proxy_;
MockVideoStreamEncoder encoder_;
testing::StrictMock<MockVideoStreamEncoder> encoder_;
EncoderRtcpFeedback encoder_rtcp_feedback_;
};

View File

@ -0,0 +1,44 @@
/*
* Copyright 2018 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.
*/
#ifndef VIDEO_TEST_MOCK_VIDEO_STREAM_ENCODER_H_
#define VIDEO_TEST_MOCK_VIDEO_STREAM_ENCODER_H_
#include "test/gmock.h"
#include "video/video_stream_encoder.h"
namespace webrtc {
class MockVideoStreamEncoder : public VideoStreamEncoderInterface {
public:
MOCK_METHOD2(SetSource,
void(rtc::VideoSourceInterface<VideoFrame>*,
const VideoSendStream::DegradationPreference&));
MOCK_METHOD2(SetSink, void(EncoderSink*, bool));
MOCK_METHOD1(SetStartBitrate, void(int));
MOCK_METHOD0(SendKeyFrame, void());
MOCK_METHOD3(OnBitrateUpdated, void(uint32_t, uint8_t, int64_t));
MOCK_METHOD1(OnFrame, void(const VideoFrame&));
MOCK_METHOD1(SetBitrateObserver, void(VideoBitrateAllocationObserver*));
MOCK_METHOD0(Stop, void());
MOCK_METHOD3(MockedConfigureEncoder,
void(const VideoEncoderConfig&, size_t, bool));
// gtest generates implicit copy which is not allowed on VideoEncoderConfig,
// so we can't mock ConfigureEncoder directly.
void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length,
bool nack_enabled) {
MockedConfigureEncoder(config, max_data_payload_length, nack_enabled);
}
};
} // namespace webrtc
#endif // VIDEO_TEST_MOCK_VIDEO_STREAM_ENCODER_H_

View File

@ -283,9 +283,9 @@ VideoSendStreamImpl::VideoSendStreamImpl(
rtc::TaskQueue* worker_queue,
CallStats* call_stats,
RtpTransportControllerSendInterface* transport,
BitrateAllocator* bitrate_allocator,
BitrateAllocatorInterface* bitrate_allocator,
SendDelayStats* send_delay_stats,
VideoStreamEncoder* video_stream_encoder,
VideoStreamEncoderInterface* video_stream_encoder,
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,

View File

@ -52,9 +52,9 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
rtc::TaskQueue* worker_queue,
CallStats* call_stats,
RtpTransportControllerSendInterface* transport,
BitrateAllocator* bitrate_allocator,
BitrateAllocatorInterface* bitrate_allocator,
SendDelayStats* send_delay_stats,
VideoStreamEncoder* video_stream_encoder,
VideoStreamEncoderInterface* video_stream_encoder,
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,
@ -156,7 +156,7 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
CallStats* const call_stats_;
RtpTransportControllerSendInterface* const transport_;
BitrateAllocator* const bitrate_allocator_;
BitrateAllocatorInterface* const bitrate_allocator_;
// TODO(brandtr): Move ownership to PayloadRouter.
std::unique_ptr<FlexfecSender> flexfec_sender_;
@ -172,7 +172,7 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
double encoder_bitrate_priority_;
bool has_packet_feedback_;
VideoStreamEncoder* const video_stream_encoder_;
VideoStreamEncoderInterface* const video_stream_encoder_;
EncoderRtcpFeedback encoder_feedback_;
RtcpBandwidthObserver* const bandwidth_observer_;

View File

@ -0,0 +1,183 @@
/*
* Copyright 2018 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 <string>
#include "call/test/mock_bitrate_allocator.h"
#include "call/test/mock_rtp_transport_controller_send.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "modules/video_coding/fec_controller_default.h"
#include "rtc_base/experiments/alr_experiment.h"
#include "rtc_base/task_queue_for_test.h"
#include "test/field_trial.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_transport.h"
#include "video/test/mock_video_stream_encoder.h"
#include "video/video_send_stream_impl.h"
namespace webrtc {
namespace internal {
namespace {
using testing::NiceMock;
using testing::StrictMock;
using testing::ReturnRef;
using testing::Return;
using testing::Invoke;
using testing::_;
constexpr int64_t kDefaultInitialBitrateBps = 333000;
const double kDefaultBitratePriority = 0.5;
const float kAlrProbingExperimentPaceMultiplier = 1.0f;
std::string GetAlrProbingExperimentString() {
return std::string(
AlrExperimentSettings::kScreenshareProbingBweExperimentName) +
"/1.0,2875,80,40,-60,3/";
}
} // namespace
class VideoSendStreamImplTest : public ::testing::Test {
protected:
VideoSendStreamImplTest()
: clock_(1000 * 1000 * 1000),
config_(&transport_),
send_delay_stats_(&clock_),
retransmission_limiter_(&clock_, 1000),
test_queue_("test_queue"),
process_thread_(ProcessThread::Create("test_thread")),
call_stats_(&clock_, process_thread_.get()),
stats_proxy_(&clock_,
config_,
VideoEncoderConfig::ContentType::kRealtimeVideo) {
config_.rtp.ssrcs.push_back(8080);
config_.rtp.payload_type = 1;
EXPECT_CALL(transport_controller_, keepalive_config())
.WillRepeatedly(ReturnRef(keepalive_config_));
EXPECT_CALL(transport_controller_, packet_router())
.WillRepeatedly(Return(&packet_router_));
}
~VideoSendStreamImplTest() {}
std::unique_ptr<VideoSendStreamImpl> CreateVideoSendStreamImpl(
int initial_encoder_max_bitrate,
double initial_encoder_bitrate_priority,
VideoEncoderConfig::ContentType content_type) {
EXPECT_CALL(bitrate_allocator_, GetStartBitrate(_))
.WillOnce(Return(123000));
std::map<uint32_t, RtpState> suspended_ssrcs;
std::map<uint32_t, RtpPayloadState> suspended_payload_states;
return rtc::MakeUnique<VideoSendStreamImpl>(
&stats_proxy_, &test_queue_, &call_stats_, &transport_controller_,
&bitrate_allocator_, &send_delay_stats_, &video_stream_encoder_,
&event_log_, &config_, initial_encoder_max_bitrate,
initial_encoder_bitrate_priority, suspended_ssrcs,
suspended_payload_states, content_type,
rtc::MakeUnique<FecControllerDefault>(&clock_),
&retransmission_limiter_);
}
protected:
NiceMock<MockTransport> transport_;
NiceMock<MockRtpTransportControllerSend> transport_controller_;
NiceMock<MockBitrateAllocator> bitrate_allocator_;
NiceMock<MockVideoStreamEncoder> video_stream_encoder_;
SimulatedClock clock_;
RtcEventLogNullImpl event_log_;
VideoSendStream::Config config_;
SendDelayStats send_delay_stats_;
RateLimiter retransmission_limiter_;
rtc::test::TaskQueueForTest test_queue_;
std::unique_ptr<ProcessThread> process_thread_;
CallStats call_stats_;
SendStatisticsProxy stats_proxy_;
PacketRouter packet_router_;
RtpKeepAliveConfig keepalive_config_;
};
TEST_F(VideoSendStreamImplTest, RegistersAsBitrateObserverOnStart) {
test_queue_.SendTask([this] {
config_.track_id = "test";
const bool kSuspend = false;
config_.suspend_below_min_bitrate = kSuspend;
auto vss_impl = CreateVideoSendStreamImpl(
kDefaultInitialBitrateBps, kDefaultBitratePriority,
VideoEncoderConfig::ContentType::kRealtimeVideo);
EXPECT_CALL(bitrate_allocator_, AddObserver(vss_impl.get(), _))
.WillOnce(Invoke(
[&](BitrateAllocatorObserver*, MediaStreamAllocationConfig config) {
EXPECT_EQ(config.min_bitrate_bps, 0u);
EXPECT_EQ(config.max_bitrate_bps, kDefaultInitialBitrateBps);
EXPECT_EQ(config.pad_up_bitrate_bps, 0u);
EXPECT_EQ(config.enforce_min_bitrate, !kSuspend);
EXPECT_EQ(config.track_id, "test");
EXPECT_EQ(config.bitrate_priority, kDefaultBitratePriority);
EXPECT_EQ(config.has_packet_feedback, false);
}));
vss_impl->Start();
EXPECT_CALL(bitrate_allocator_, RemoveObserver(vss_impl.get())).Times(1);
vss_impl->Stop();
});
}
TEST_F(VideoSendStreamImplTest, ReportFeedbackAvailability) {
test_queue_.SendTask([this] {
config_.rtp.extensions.emplace_back(
RtpExtension::kTransportSequenceNumberUri,
RtpExtension::kTransportSequenceNumberDefaultId);
auto vss_impl = CreateVideoSendStreamImpl(
kDefaultInitialBitrateBps, kDefaultBitratePriority,
VideoEncoderConfig::ContentType::kRealtimeVideo);
EXPECT_CALL(bitrate_allocator_, AddObserver(vss_impl.get(), _))
.WillOnce(Invoke(
[&](BitrateAllocatorObserver*, MediaStreamAllocationConfig config) {
EXPECT_EQ(config.has_packet_feedback, true);
}));
vss_impl->Start();
EXPECT_CALL(bitrate_allocator_, RemoveObserver(vss_impl.get())).Times(1);
vss_impl->Stop();
});
}
TEST_F(VideoSendStreamImplTest, SetsScreensharePacingFactorWithFeedback) {
test::ScopedFieldTrials alr_experiment(GetAlrProbingExperimentString());
test_queue_.SendTask([this] {
config_.rtp.extensions.emplace_back(
RtpExtension::kTransportSequenceNumberUri,
RtpExtension::kTransportSequenceNumberDefaultId);
EXPECT_CALL(transport_controller_,
SetPacingFactor(kAlrProbingExperimentPaceMultiplier))
.Times(1);
auto vss_impl = CreateVideoSendStreamImpl(
kDefaultInitialBitrateBps, kDefaultBitratePriority,
VideoEncoderConfig::ContentType::kScreen);
vss_impl->Start();
vss_impl->Stop();
});
}
TEST_F(VideoSendStreamImplTest, DoesNotSetPacingFactorWithoutFeedback) {
test::ScopedFieldTrials alr_experiment(GetAlrProbingExperimentString());
test_queue_.SendTask([this] {
EXPECT_CALL(transport_controller_, SetPacingFactor(_)).Times(0);
auto vss_impl = CreateVideoSendStreamImpl(
kDefaultInitialBitrateBps, kDefaultBitratePriority,
VideoEncoderConfig::ContentType::kScreen);
vss_impl->Start();
vss_impl->Stop();
});
}
} // namespace internal
} // namespace webrtc

View File

@ -39,18 +39,7 @@ namespace webrtc {
class SendStatisticsProxy;
class VideoBitrateAllocationObserver;
// VideoStreamEncoder represent a video encoder that accepts raw video frames as
// input and produces an encoded bit stream.
// Usage:
// Instantiate.
// Call SetSink.
// Call SetSource.
// Call ConfigureEncoder with the codec settings.
// Call Stop() when done.
class VideoStreamEncoder : public rtc::VideoSinkInterface<VideoFrame>,
private EncodedImageCallback,
// Protected only to provide access to tests.
protected AdaptationObserverInterface {
class VideoStreamEncoderInterface : public rtc::VideoSinkInterface<VideoFrame> {
public:
// Interface for receiving encoded video frames and notifications about
// configuration changes.
@ -60,7 +49,40 @@ class VideoStreamEncoder : public rtc::VideoSinkInterface<VideoFrame>,
std::vector<VideoStream> streams,
int min_transmit_bitrate_bps) = 0;
};
virtual void SetSource(
rtc::VideoSourceInterface<VideoFrame>* source,
const VideoSendStream::DegradationPreference& degradation_preference) = 0;
virtual void SetSink(EncoderSink* sink, bool rotation_applied) = 0;
virtual void SetStartBitrate(int start_bitrate_bps) = 0;
virtual void SendKeyFrame() = 0;
virtual void OnBitrateUpdated(uint32_t bitrate_bps,
uint8_t fraction_lost,
int64_t round_trip_time_ms) = 0;
virtual void SetBitrateObserver(
VideoBitrateAllocationObserver* bitrate_observer) = 0;
virtual void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length,
bool nack_enabled) = 0;
virtual void Stop() = 0;
protected:
~VideoStreamEncoderInterface() = default;
};
// VideoStreamEncoder represent a video encoder that accepts raw video frames as
// input and produces an encoded bit stream.
// Usage:
// Instantiate.
// Call SetSink.
// Call SetSource.
// Call ConfigureEncoder with the codec settings.
// Call Stop() when done.
class VideoStreamEncoder : public VideoStreamEncoderInterface,
private EncodedImageCallback,
// Protected only to provide access to tests.
protected AdaptationObserverInterface {
public:
// Number of resolution and framerate reductions (-1: disabled).
struct AdaptCounts {
int resolution = 0;
@ -77,34 +99,34 @@ class VideoStreamEncoder : public rtc::VideoSinkInterface<VideoFrame>,
// Sets the source that will provide I420 video frames.
// |degradation_preference| control whether or not resolution or frame rate
// may be reduced.
void SetSource(
rtc::VideoSourceInterface<VideoFrame>* source,
const VideoSendStream::DegradationPreference& degradation_preference);
void SetSource(rtc::VideoSourceInterface<VideoFrame>* source,
const VideoSendStream::DegradationPreference&
degradation_preference) override;
// Sets the |sink| that gets the encoded frames. |rotation_applied| means
// that the source must support rotation. Only set |rotation_applied| if the
// remote side does not support the rotation extension.
void SetSink(EncoderSink* sink, bool rotation_applied);
void SetSink(EncoderSink* sink, bool rotation_applied) override;
// TODO(perkj): Can we remove VideoCodec.startBitrate ?
void SetStartBitrate(int start_bitrate_bps);
void SetStartBitrate(int start_bitrate_bps) override;
void SetBitrateObserver(VideoBitrateAllocationObserver* bitrate_observer);
void SetBitrateObserver(
VideoBitrateAllocationObserver* bitrate_observer) override;
void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length,
bool nack_enabled);
bool nack_enabled) override;
// Permanently stop encoding. After this method has returned, it is
// guaranteed that no encoded frames will be delivered to the sink.
void Stop();
void Stop() override;
// virtual to test EncoderRtcpFeedback with mocks.
virtual void SendKeyFrame();
void SendKeyFrame() override;
void OnBitrateUpdated(uint32_t bitrate_bps,
uint8_t fraction_lost,
int64_t round_trip_time_ms);
int64_t round_trip_time_ms) override;
protected:
// Used for testing. For example the |ScalingObserverInterface| methods must