Add FullStackTest with simulated encoder overshooting

Bug: webrtc:10302
Change-Id: I1d4b9ef22ba1ca9a221cc01e2c44775014c90d4f
Reviewed-on: https://webrtc-review.googlesource.com/c/122082
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26673}
This commit is contained in:
Erik Språng 2019-02-11 14:16:28 +01:00 committed by Commit Bot
parent 6c02541abe
commit 616b233688
3 changed files with 162 additions and 21 deletions

View File

@ -60,6 +60,7 @@ class VideoQualityTestFixtureInterface {
std::string clip_name; // "Generator" to generate frames instead.
size_t capture_device_index;
SdpVideoFormat::Parameters sdp_params;
double encoder_overshoot_factor;
} video[2];
struct Audio {
bool enabled;

View File

@ -279,6 +279,23 @@ TEST(FullStackTest, ForemanCifLink150kbpsWithoutPacketLoss) {
fixture->RunWithAnalyzer(foreman_cif);
}
// Restricted network and encoder overproducing by 30%.
TEST(FullStackTest, ForemanCifLink150kbpsBadRateController) {
auto fixture = CreateVideoQualityTestFixture();
ParamsWithLogging foreman_cif;
foreman_cif.call.send_side_bwe = true;
foreman_cif.video[0] = {true, 352, 288, 30, 30000, 500000, 2000000,
false, "VP8", 1, 0, 0, false, false,
true, "foreman_cif", 0, {}, 1.30};
foreman_cif.analyzer = {
"foreman_cif_link_150kbps_delay100ms_30pkts_queue_overshoot30", 0.0, 0.0,
kFullStackTestDurationSecs};
foreman_cif.config->link_capacity_kbps = 150;
foreman_cif.config->queue_length_packets = 30;
foreman_cif.config->queue_delay_ms = 100;
fixture->RunWithAnalyzer(foreman_cif);
}
TEST_P(GenericDescriptorTest, ForemanCifPlr5) {
auto fixture = CreateVideoQualityTestFixture();
ParamsWithLogging foreman_cif;

View File

@ -56,6 +56,27 @@ constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000;
constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax;
std::pair<uint32_t, uint32_t> GetMinMaxBitratesBps(const VideoCodec& codec,
size_t spatial_idx) {
uint32_t min_bitrate = codec.minBitrate;
uint32_t max_bitrate = codec.maxBitrate;
if (spatial_idx < codec.numberOfSimulcastStreams) {
min_bitrate =
std::max(min_bitrate, codec.simulcastStream[spatial_idx].minBitrate);
max_bitrate =
std::min(max_bitrate, codec.simulcastStream[spatial_idx].maxBitrate);
}
if (codec.codecType == VideoCodecType::kVideoCodecVP9 &&
spatial_idx < codec.VP9().numberOfSpatialLayers) {
min_bitrate =
std::max(min_bitrate, codec.spatialLayers[spatial_idx].minBitrate);
max_bitrate =
std::min(max_bitrate, codec.spatialLayers[spatial_idx].maxBitrate);
}
max_bitrate = std::max(max_bitrate, min_bitrate);
return {min_bitrate * 1000, max_bitrate * 1000};
}
class VideoStreamFactory
: public VideoEncoderConfig::VideoStreamFactoryInterface {
public:
@ -87,8 +108,11 @@ class QualityTestVideoEncoder : public VideoEncoder,
public:
QualityTestVideoEncoder(std::unique_ptr<VideoEncoder> encoder,
VideoAnalyzer* analyzer,
std::vector<FileWrapper> files)
: encoder_(std::move(encoder)), analyzer_(analyzer) {
std::vector<FileWrapper> files,
double overshoot_factor)
: encoder_(std::move(encoder)),
overshoot_factor_(overshoot_factor),
analyzer_(analyzer) {
for (FileWrapper& file : files) {
writers_.push_back(
IvfFileWriter::Wrap(std::move(file), /* byte_limit= */ 100000000));
@ -98,6 +122,7 @@ class QualityTestVideoEncoder : public VideoEncoder,
int32_t InitEncode(const VideoCodec* codec_settings,
int32_t number_of_cores,
size_t max_payload_size) override {
codec_settings_ = *codec_settings;
return encoder_->InitEncode(codec_settings, number_of_cores,
max_payload_size);
}
@ -115,15 +140,57 @@ class QualityTestVideoEncoder : public VideoEncoder,
}
return encoder_->Encode(frame, codec_specific_info, frame_types);
}
int32_t SetRates(uint32_t bitrate, uint32_t framerate) override {
return encoder_->SetRates(bitrate, framerate);
}
int32_t SetRateAllocation(const VideoBitrateAllocation& allocation,
uint32_t framerate) override {
return encoder_->SetRateAllocation(allocation, framerate);
RTC_DCHECK_GT(overshoot_factor_, 0.0);
if (overshoot_factor_ == 1.0) {
return encoder_->SetRateAllocation(allocation, framerate);
}
// Simulating encoder overshooting target bitrate, by configuring actual
// encoder too high. Take care not to adjust past limits of config,
// otherwise encoders may crash on DCHECK.
VideoBitrateAllocation overshot_allocation;
for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
const uint32_t spatial_layer_bitrate_bps =
allocation.GetSpatialLayerSum(si);
if (spatial_layer_bitrate_bps == 0) {
continue;
}
uint32_t min_bitrate_bps;
uint32_t max_bitrate_bps;
std::tie(min_bitrate_bps, max_bitrate_bps) =
GetMinMaxBitratesBps(codec_settings_, si);
double overshoot_factor = overshoot_factor_;
const uint32_t corrected_bitrate = rtc::checked_cast<uint32_t>(
overshoot_factor * spatial_layer_bitrate_bps);
if (corrected_bitrate < min_bitrate_bps) {
overshoot_factor = min_bitrate_bps / spatial_layer_bitrate_bps;
} else if (corrected_bitrate > max_bitrate_bps) {
overshoot_factor = max_bitrate_bps / spatial_layer_bitrate_bps;
}
for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
if (allocation.HasBitrate(si, ti)) {
overshot_allocation.SetBitrate(
si, ti,
rtc::checked_cast<uint32_t>(overshoot_factor *
allocation.GetBitrate(si, ti)));
}
}
}
return encoder_->SetRateAllocation(overshot_allocation, framerate);
}
EncoderInfo GetEncoderInfo() const override {
return encoder_->GetEncoderInfo();
EncoderInfo info = encoder_->GetEncoderInfo();
if (overshoot_factor_ != 1.0) {
// We're simulating bad encoder, don't forward trusted setting
// from eg libvpx.
info.has_trusted_rate_controller = false;
}
return info;
}
private:
@ -157,10 +224,12 @@ class QualityTestVideoEncoder : public VideoEncoder,
callback_->OnDroppedFrame(reason);
}
std::unique_ptr<VideoEncoder> encoder_;
EncodedImageCallback* callback_ = nullptr;
const std::unique_ptr<VideoEncoder> encoder_;
const double overshoot_factor_;
VideoAnalyzer* const analyzer_;
std::vector<std::unique_ptr<IvfFileWriter>> writers_;
EncodedImageCallback* callback_ = nullptr;
VideoCodec codec_settings_;
};
} // namespace
@ -202,22 +271,42 @@ std::unique_ptr<VideoEncoder> VideoQualityTest::CreateVideoEncoder(
} else {
encoder = internal_encoder_factory_.CreateVideoEncoder(format);
}
std::vector<FileWrapper> encoded_frame_dump_files;
if (!params_.logging.encoded_frame_base_path.empty()) {
char ss_buf[100];
rtc::SimpleStringBuilder sb(ss_buf);
sb << send_logs_++;
std::string prefix =
params_.logging.encoded_frame_base_path + "." + sb.str() + ".send.";
std::vector<FileWrapper> files;
files.push_back(FileWrapper::OpenWriteOnly(prefix + "1.ivf"));
files.push_back(FileWrapper::OpenWriteOnly(prefix + "2.ivf"));
files.push_back(FileWrapper::OpenWriteOnly(prefix + "3.ivf"));
encoded_frame_dump_files.push_back(
FileWrapper::OpenWriteOnly(prefix + "1.ivf"));
encoded_frame_dump_files.push_back(
FileWrapper::OpenWriteOnly(prefix + "2.ivf"));
encoded_frame_dump_files.push_back(
FileWrapper::OpenWriteOnly(prefix + "3.ivf"));
}
double overshoot_factor = 1.0;
// Match format to either of the streams in dual-stream mode in order to get
// the overshoot factor. This is not very robust but we can't know for sure
// which stream this encoder is meant for, from within the factory.
if (format ==
SdpVideoFormat(params_.video[0].codec, params_.video[0].sdp_params)) {
overshoot_factor = params_.video[0].encoder_overshoot_factor;
} else if (format == SdpVideoFormat(params_.video[1].codec,
params_.video[1].sdp_params)) {
overshoot_factor = params_.video[1].encoder_overshoot_factor;
}
if (overshoot_factor == 0.0) {
// If params were zero-initialized, set to 1.0 instead.
overshoot_factor = 1.0;
}
if (analyzer || !encoded_frame_dump_files.empty() || overshoot_factor > 1.0) {
encoder = absl::make_unique<QualityTestVideoEncoder>(
std::move(encoder), analyzer, std::move(files));
} else if (analyzer) {
encoder = absl::make_unique<QualityTestVideoEncoder>(
std::move(encoder), analyzer, std::vector<FileWrapper>());
std::move(encoder), analyzer, std::move(encoded_frame_dump_files),
overshoot_factor);
}
return encoder;
@ -263,10 +352,44 @@ VideoQualityTest::VideoQualityTest(
VideoQualityTest::Params::Params()
: call({false, false, BitrateConstraints(), 0}),
video{{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
false, false, ""},
{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
false, false, ""}},
video{{false,
640,
480,
30,
50,
800,
800,
false,
"VP8",
1,
-1,
0,
false,
false,
false,
"",
0,
{},
0.0},
{false,
640,
480,
30,
50,
800,
800,
false,
"VP8",
1,
-1,
0,
false,
false,
false,
"",
0,
{},
0.0}},
audio({false, false, false, false}),
screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
analyzer({"", 0.0, 0.0, 0, "", ""}),