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:
parent
6c02541abe
commit
616b233688
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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, "", ""}),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user