blob: db98dc04160198708212dcfadd8283459acfbfca [file] [log] [blame]
ivica5d6a06c2015-09-17 12:30:241/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
Mirko Bonadei92ea95e2017-09-15 04:47:3110#include "video/video_quality_test.h"
perkj9fdbda62016-09-15 16:19:2011
perkja49cbd32016-09-16 14:53:4112#include <stdio.h>
Jonas Olssona4d87372019-07-05 17:08:3313
ivica5d6a06c2015-09-17 12:30:2414#include <algorithm>
15#include <deque>
16#include <map>
Mirko Bonadei317a1f02019-09-17 15:06:1817#include <memory>
mflodmand1590b22015-12-09 15:07:5918#include <string>
ivica5d6a06c2015-09-17 12:30:2419#include <vector>
20
Elad Alon8f01c4e2019-06-28 13:19:4321#include "api/fec_controller_override.h"
Niels Möllerd8b9ed72019-05-08 11:53:5122#include "api/rtc_event_log_output_file.h"
Danil Chapovalov1c41be62019-04-01 07:16:1223#include "api/task_queue/default_task_queue_factory.h"
Danil Chapovalov44db4362019-09-30 02:16:2824#include "api/task_queue/task_queue_base.h"
Niels Möller65f17ca2019-09-12 11:59:3625#include "api/transport/media/media_transport_config.h"
Jiawei Ouc2ebe212018-11-08 18:02:5626#include "api/video/builtin_video_bitrate_allocator_factory.h"
Elad Alon370f93a2019-06-11 12:57:5727#include "api/video_codecs/video_encoder.h"
Artem Titovdd2eebe2018-08-20 11:27:4528#include "call/fake_network_pipe.h"
29#include "call/simulated_network.h"
henrika255750b2018-08-27 14:13:3730#include "media/engine/adm_helpers.h"
Florent Castellie7862cc2018-12-06 12:38:2431#include "media/engine/encoder_simulcast_proxy.h"
Emircan Uysaler7c03bdc2019-01-16 20:07:5632#include "media/engine/fake_video_codec_factory.h"
Steve Anton10542f22019-01-11 17:11:0033#include "media/engine/internal_encoder_factory.h"
34#include "media/engine/webrtc_video_engine.h"
henrika255750b2018-08-27 14:13:3735#include "modules/audio_device/include/audio_device.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3136#include "modules/audio_mixer/audio_mixer_impl.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3137#include "modules/video_coding/codecs/h264/include/h264.h"
Niels Möllercbcbc222018-09-28 07:07:2438#include "modules/video_coding/codecs/multiplex/include/multiplex_decoder_adapter.h"
Emircan Uysaler03e6ec92018-03-09 23:03:2639#include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h"
Niels Möller4db138e2018-04-19 07:04:1340#include "modules/video_coding/codecs/vp8/include/vp8.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3141#include "modules/video_coding/codecs/vp9/include/vp9.h"
Niels Möller1beef1a2018-09-03 12:21:4442#include "modules/video_coding/utility/ivf_file_writer.h"
43#include "rtc_base/strings/string_builder.h"
Kári Tristan Helgasonede7cb22019-03-06 09:34:0944#include "test/platform_video_capturer.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3145#include "test/run_loop.h"
Steve Anton10542f22019-01-11 17:11:0046#include "test/testsupport/file_utils.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3147#include "test/video_renderer.h"
Erik Språng96965ae2018-10-23 13:42:3748#include "video/frame_dumping_decoder.h"
henrika255750b2018-08-27 14:13:3749#ifdef WEBRTC_WIN
50#include "modules/audio_device/include/audio_device_factory.h"
51#endif
ilnikee42d192017-08-22 14:16:2052
Niels Möller1beef1a2018-09-03 12:21:4453namespace webrtc {
54
minyue73208662016-08-18 13:28:5555namespace {
Elad Alond8d32482019-02-18 22:45:5756enum : int { // The first valid value is 1.
57 kAbsSendTimeExtensionId = 1,
Elad Alonccb9b752019-02-19 12:01:3158 kGenericFrameDescriptorExtensionId00,
59 kGenericFrameDescriptorExtensionId01,
Elad Alond8d32482019-02-18 22:45:5760 kTransportSequenceNumberExtensionId,
61 kVideoContentTypeExtensionId,
62 kVideoTimingExtensionId,
63};
64
minyue73208662016-08-18 13:28:5565constexpr char kSyncGroup[] = "av_sync";
minyue10cbb462016-11-07 17:29:2266constexpr int kOpusMinBitrateBps = 6000;
67constexpr int kOpusBitrateFbBps = 32000;
ilnik9ae0d762017-02-15 08:53:1268constexpr int kFramesSentInQuickTest = 1;
ilnika014cc52017-03-07 12:21:0469constexpr uint32_t kThumbnailSendSsrcStart = 0xE0000;
70constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000;
minyue73208662016-08-18 13:28:5571
sprang1168fd42017-06-21 16:00:1772constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax;
73
Elad Alon370f93a2019-06-11 12:57:5774const VideoEncoder::Capabilities kCapabilities(false);
75
Erik Språng616b2332019-02-11 13:16:2876std::pair<uint32_t, uint32_t> GetMinMaxBitratesBps(const VideoCodec& codec,
77 size_t spatial_idx) {
78 uint32_t min_bitrate = codec.minBitrate;
79 uint32_t max_bitrate = codec.maxBitrate;
80 if (spatial_idx < codec.numberOfSimulcastStreams) {
81 min_bitrate =
82 std::max(min_bitrate, codec.simulcastStream[spatial_idx].minBitrate);
83 max_bitrate =
84 std::min(max_bitrate, codec.simulcastStream[spatial_idx].maxBitrate);
85 }
86 if (codec.codecType == VideoCodecType::kVideoCodecVP9 &&
87 spatial_idx < codec.VP9().numberOfSpatialLayers) {
88 min_bitrate =
89 std::max(min_bitrate, codec.spatialLayers[spatial_idx].minBitrate);
90 max_bitrate =
91 std::min(max_bitrate, codec.spatialLayers[spatial_idx].maxBitrate);
92 }
93 max_bitrate = std::max(max_bitrate, min_bitrate);
94 return {min_bitrate * 1000, max_bitrate * 1000};
95}
96
perkjfa10b552016-10-03 06:45:2697class VideoStreamFactory
Niels Möller1beef1a2018-09-03 12:21:4498 : public VideoEncoderConfig::VideoStreamFactoryInterface {
perkjfa10b552016-10-03 06:45:2699 public:
Niels Möller1beef1a2018-09-03 12:21:44100 explicit VideoStreamFactory(const std::vector<VideoStream>& streams)
perkjfa10b552016-10-03 06:45:26101 : streams_(streams) {}
102
103 private:
Niels Möller1beef1a2018-09-03 12:21:44104 std::vector<VideoStream> CreateEncoderStreams(
perkjfa10b552016-10-03 06:45:26105 int width,
106 int height,
Niels Möller1beef1a2018-09-03 12:21:44107 const VideoEncoderConfig& encoder_config) override {
mflodmand79f97b2016-12-15 15:24:33108 // The highest layer must match the incoming resolution.
Niels Möller1beef1a2018-09-03 12:21:44109 std::vector<VideoStream> streams = streams_;
mflodmand79f97b2016-12-15 15:24:33110 streams[streams_.size() - 1].height = height;
111 streams[streams_.size() - 1].width = width;
Seth Hampson24722b32017-12-22 17:36:42112
113 streams[0].bitrate_priority = encoder_config.bitrate_priority;
mflodmand79f97b2016-12-15 15:24:33114 return streams;
perkjfa10b552016-10-03 06:45:26115 }
116
Niels Möller1beef1a2018-09-03 12:21:44117 std::vector<VideoStream> streams_;
perkjfa10b552016-10-03 06:45:26118};
ivica5d6a06c2015-09-17 12:30:24119
Niels Möller88be9722018-10-10 08:58:52120// This wrapper provides two features needed by the video quality tests:
121// 1. Invoke VideoAnalyzer callbacks before and after encoding each frame.
122// 2. Write the encoded frames to file, one file per simulcast layer.
123class QualityTestVideoEncoder : public VideoEncoder,
124 private EncodedImageCallback {
Niels Möller1beef1a2018-09-03 12:21:44125 public:
Niels Möller88be9722018-10-10 08:58:52126 QualityTestVideoEncoder(std::unique_ptr<VideoEncoder> encoder,
127 VideoAnalyzer* analyzer,
Erik Språng616b2332019-02-11 13:16:28128 std::vector<FileWrapper> files,
129 double overshoot_factor)
130 : encoder_(std::move(encoder)),
131 overshoot_factor_(overshoot_factor),
132 analyzer_(analyzer) {
Niels Möllerb7edf692019-02-08 15:40:53133 for (FileWrapper& file : files) {
Niels Möller1beef1a2018-09-03 12:21:44134 writers_.push_back(
Niels Möllerb7edf692019-02-08 15:40:53135 IvfFileWriter::Wrap(std::move(file), /* byte_limit= */ 100000000));
Niels Möller1beef1a2018-09-03 12:21:44136 }
137 }
Elad Alonfe4f6942019-05-07 21:13:42138
Niels Möller1beef1a2018-09-03 12:21:44139 // Implement VideoEncoder
Elad Alon8f01c4e2019-06-28 13:19:43140 void SetFecControllerOverride(
141 FecControllerOverride* fec_controller_override) {
142 // Ignored.
143 }
144
Niels Möller1beef1a2018-09-03 12:21:44145 int32_t InitEncode(const VideoCodec* codec_settings,
Elad Alon370f93a2019-06-11 12:57:57146 const Settings& settings) override {
Erik Språng616b2332019-02-11 13:16:28147 codec_settings_ = *codec_settings;
Elad Alon370f93a2019-06-11 12:57:57148 return encoder_->InitEncode(codec_settings, settings);
Niels Möller1beef1a2018-09-03 12:21:44149 }
Elad Alonfe4f6942019-05-07 21:13:42150
Niels Möller1beef1a2018-09-03 12:21:44151 int32_t RegisterEncodeCompleteCallback(
152 EncodedImageCallback* callback) override {
153 callback_ = callback;
154 return encoder_->RegisterEncodeCompleteCallback(this);
155 }
Elad Alonfe4f6942019-05-07 21:13:42156
Niels Möller1beef1a2018-09-03 12:21:44157 int32_t Release() override { return encoder_->Release(); }
Elad Alonfe4f6942019-05-07 21:13:42158
Niels Möller1beef1a2018-09-03 12:21:44159 int32_t Encode(const VideoFrame& frame,
Niels Möller87e2d782019-03-07 09:18:23160 const std::vector<VideoFrameType>* frame_types) {
Niels Möller88be9722018-10-10 08:58:52161 if (analyzer_) {
162 analyzer_->PreEncodeOnFrame(frame);
163 }
Niels Möllerc8d2e732019-03-06 11:00:33164 return encoder_->Encode(frame, frame_types);
Niels Möller1beef1a2018-09-03 12:21:44165 }
Elad Alonfe4f6942019-05-07 21:13:42166
Erik Språng16cb8f52019-04-12 11:59:09167 void SetRates(const RateControlParameters& parameters) override {
Erik Språng616b2332019-02-11 13:16:28168 RTC_DCHECK_GT(overshoot_factor_, 0.0);
169 if (overshoot_factor_ == 1.0) {
Erik Språng16cb8f52019-04-12 11:59:09170 encoder_->SetRates(parameters);
171 return;
Erik Språng616b2332019-02-11 13:16:28172 }
173
174 // Simulating encoder overshooting target bitrate, by configuring actual
175 // encoder too high. Take care not to adjust past limits of config,
176 // otherwise encoders may crash on DCHECK.
177 VideoBitrateAllocation overshot_allocation;
178 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
179 const uint32_t spatial_layer_bitrate_bps =
Erik Språng16cb8f52019-04-12 11:59:09180 parameters.bitrate.GetSpatialLayerSum(si);
Erik Språng616b2332019-02-11 13:16:28181 if (spatial_layer_bitrate_bps == 0) {
182 continue;
183 }
184
185 uint32_t min_bitrate_bps;
186 uint32_t max_bitrate_bps;
187 std::tie(min_bitrate_bps, max_bitrate_bps) =
188 GetMinMaxBitratesBps(codec_settings_, si);
189 double overshoot_factor = overshoot_factor_;
190 const uint32_t corrected_bitrate = rtc::checked_cast<uint32_t>(
191 overshoot_factor * spatial_layer_bitrate_bps);
192 if (corrected_bitrate < min_bitrate_bps) {
193 overshoot_factor = min_bitrate_bps / spatial_layer_bitrate_bps;
194 } else if (corrected_bitrate > max_bitrate_bps) {
195 overshoot_factor = max_bitrate_bps / spatial_layer_bitrate_bps;
196 }
197
198 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
Erik Språng16cb8f52019-04-12 11:59:09199 if (parameters.bitrate.HasBitrate(si, ti)) {
Erik Språng616b2332019-02-11 13:16:28200 overshot_allocation.SetBitrate(
201 si, ti,
Erik Språng16cb8f52019-04-12 11:59:09202 rtc::checked_cast<uint32_t>(
203 overshoot_factor * parameters.bitrate.GetBitrate(si, ti)));
Erik Språng616b2332019-02-11 13:16:28204 }
205 }
206 }
207
Erik Språng16cb8f52019-04-12 11:59:09208 return encoder_->SetRates(
209 RateControlParameters(overshot_allocation, parameters.framerate_fps,
210 parameters.bandwidth_allocation));
Niels Möller1beef1a2018-09-03 12:21:44211 }
Elad Alonfe4f6942019-05-07 21:13:42212
213 void OnPacketLossRateUpdate(float packet_loss_rate) override {
214 encoder_->OnPacketLossRateUpdate(packet_loss_rate);
215 }
216
217 void OnRttUpdate(int64_t rtt_ms) override { encoder_->OnRttUpdate(rtt_ms); }
218
219 void OnLossNotification(const LossNotification& loss_notification) override {
220 encoder_->OnLossNotification(loss_notification);
221 }
222
Erik Språng189013b2018-11-01 14:03:57223 EncoderInfo GetEncoderInfo() const override {
Erik Språng616b2332019-02-11 13:16:28224 EncoderInfo info = encoder_->GetEncoderInfo();
225 if (overshoot_factor_ != 1.0) {
226 // We're simulating bad encoder, don't forward trusted setting
227 // from eg libvpx.
228 info.has_trusted_rate_controller = false;
229 }
230 return info;
Niels Möller1beef1a2018-09-03 12:21:44231 }
232
233 private:
234 // Implement EncodedImageCallback
235 Result OnEncodedImage(const EncodedImage& encoded_image,
236 const CodecSpecificInfo* codec_specific_info,
237 const RTPFragmentationHeader* fragmentation) override {
238 if (codec_specific_info) {
239 int simulcast_index;
240 if (codec_specific_info->codecType == kVideoCodecVP9) {
241 simulcast_index = 0;
242 } else {
243 simulcast_index = encoded_image.SpatialIndex().value_or(0);
244 }
245 RTC_DCHECK_GE(simulcast_index, 0);
Niels Möller88be9722018-10-10 08:58:52246 if (analyzer_) {
247 analyzer_->PostEncodeOnFrame(simulcast_index,
248 encoded_image.Timestamp());
249 }
Niels Möller1beef1a2018-09-03 12:21:44250 if (static_cast<size_t>(simulcast_index) < writers_.size()) {
251 writers_[simulcast_index]->WriteFrame(encoded_image,
252 codec_specific_info->codecType);
253 }
254 }
255
256 return callback_->OnEncodedImage(encoded_image, codec_specific_info,
257 fragmentation);
258 }
259
260 void OnDroppedFrame(DropReason reason) override {
261 callback_->OnDroppedFrame(reason);
262 }
263
Erik Språng616b2332019-02-11 13:16:28264 const std::unique_ptr<VideoEncoder> encoder_;
265 const double overshoot_factor_;
Niels Möller88be9722018-10-10 08:58:52266 VideoAnalyzer* const analyzer_;
Niels Möller1beef1a2018-09-03 12:21:44267 std::vector<std::unique_ptr<IvfFileWriter>> writers_;
Erik Språng616b2332019-02-11 13:16:28268 EncodedImageCallback* callback_ = nullptr;
269 VideoCodec codec_settings_;
Niels Möller1beef1a2018-09-03 12:21:44270};
271
272} // namespace
ivica5d6a06c2015-09-17 12:30:24273
Niels Möllercbcbc222018-09-28 07:07:24274std::unique_ptr<VideoDecoder> VideoQualityTest::CreateVideoDecoder(
275 const SdpVideoFormat& format) {
276 std::unique_ptr<VideoDecoder> decoder;
277 if (format.name == "multiplex") {
Mirko Bonadei317a1f02019-09-17 15:06:18278 decoder = std::make_unique<MultiplexDecoderAdapter>(
“Michael3c396e52019-06-12 14:47:14279 decoder_factory_.get(), SdpVideoFormat(cricket::kVp9CodecName));
Emircan Uysaler7c03bdc2019-01-16 20:07:56280 } else if (format.name == "FakeCodec") {
281 decoder = webrtc::FakeVideoDecoderFactory::CreateVideoDecoder();
Niels Möllercbcbc222018-09-28 07:07:24282 } else {
“Michael3c396e52019-06-12 14:47:14283 decoder = decoder_factory_->CreateVideoDecoder(format);
Niels Möllercbcbc222018-09-28 07:07:24284 }
Niels Möller5ca29122018-10-02 07:55:01285 if (!params_.logging.encoded_frame_base_path.empty()) {
286 rtc::StringBuilder str;
287 str << receive_logs_++;
288 std::string path =
289 params_.logging.encoded_frame_base_path + "." + str.str() + ".recv.ivf";
Markus Handell1c2f6372019-08-20 18:21:37290 decoder = CreateFrameDumpingDecoderWrapper(
Niels Möllerb7edf692019-02-08 15:40:53291 std::move(decoder), FileWrapper::OpenWriteOnly(path));
Niels Möller5ca29122018-10-02 07:55:01292 }
Niels Möllercbcbc222018-09-28 07:07:24293 return decoder;
294}
295
Sebastian Janssone6d7c3e2018-07-11 13:00:41296std::unique_ptr<VideoEncoder> VideoQualityTest::CreateVideoEncoder(
Niels Möller88be9722018-10-10 08:58:52297 const SdpVideoFormat& format,
298 VideoAnalyzer* analyzer) {
Niels Möller1beef1a2018-09-03 12:21:44299 std::unique_ptr<VideoEncoder> encoder;
Niels Möller4db138e2018-04-19 07:04:13300 if (format.name == "VP8") {
Mirko Bonadei317a1f02019-09-17 15:06:18301 encoder =
302 std::make_unique<EncoderSimulcastProxy>(encoder_factory_.get(), format);
Niels Möller4db138e2018-04-19 07:04:13303 } else if (format.name == "multiplex") {
Mirko Bonadei317a1f02019-09-17 15:06:18304 encoder = std::make_unique<MultiplexEncoderAdapter>(
“Michael3c396e52019-06-12 14:47:14305 encoder_factory_.get(), SdpVideoFormat(cricket::kVp9CodecName));
Emircan Uysaler7c03bdc2019-01-16 20:07:56306 } else if (format.name == "FakeCodec") {
307 encoder = webrtc::FakeVideoEncoderFactory::CreateVideoEncoder();
Niels Möller1beef1a2018-09-03 12:21:44308 } else {
“Michael3c396e52019-06-12 14:47:14309 encoder = encoder_factory_->CreateVideoEncoder(format);
Niels Möller4db138e2018-04-19 07:04:13310 }
Erik Språng616b2332019-02-11 13:16:28311
312 std::vector<FileWrapper> encoded_frame_dump_files;
Niels Möller1beef1a2018-09-03 12:21:44313 if (!params_.logging.encoded_frame_base_path.empty()) {
314 char ss_buf[100];
315 rtc::SimpleStringBuilder sb(ss_buf);
316 sb << send_logs_++;
317 std::string prefix =
318 params_.logging.encoded_frame_base_path + "." + sb.str() + ".send.";
Erik Språng616b2332019-02-11 13:16:28319 encoded_frame_dump_files.push_back(
320 FileWrapper::OpenWriteOnly(prefix + "1.ivf"));
321 encoded_frame_dump_files.push_back(
322 FileWrapper::OpenWriteOnly(prefix + "2.ivf"));
323 encoded_frame_dump_files.push_back(
324 FileWrapper::OpenWriteOnly(prefix + "3.ivf"));
325 }
Niels Möllerb7edf692019-02-08 15:40:53326
Erik Språng616b2332019-02-11 13:16:28327 double overshoot_factor = 1.0;
328 // Match format to either of the streams in dual-stream mode in order to get
329 // the overshoot factor. This is not very robust but we can't know for sure
330 // which stream this encoder is meant for, from within the factory.
331 if (format ==
332 SdpVideoFormat(params_.video[0].codec, params_.video[0].sdp_params)) {
333 overshoot_factor = params_.video[0].encoder_overshoot_factor;
334 } else if (format == SdpVideoFormat(params_.video[1].codec,
335 params_.video[1].sdp_params)) {
336 overshoot_factor = params_.video[1].encoder_overshoot_factor;
337 }
338 if (overshoot_factor == 0.0) {
339 // If params were zero-initialized, set to 1.0 instead.
340 overshoot_factor = 1.0;
341 }
342
343 if (analyzer || !encoded_frame_dump_files.empty() || overshoot_factor > 1.0) {
Mirko Bonadei317a1f02019-09-17 15:06:18344 encoder = std::make_unique<QualityTestVideoEncoder>(
Erik Språng616b2332019-02-11 13:16:28345 std::move(encoder), analyzer, std::move(encoded_frame_dump_files),
346 overshoot_factor);
Niels Möller1beef1a2018-09-03 12:21:44347 }
Niels Möller88be9722018-10-10 08:58:52348
Niels Möller1beef1a2018-09-03 12:21:44349 return encoder;
Niels Möller4db138e2018-04-19 07:04:13350}
351
Patrik Höglundb6b29e02018-06-21 14:58:01352VideoQualityTest::VideoQualityTest(
Artem Titove269cb42018-08-29 07:59:23353 std::unique_ptr<InjectionComponents> injection_components)
Sebastian Janssone6d7c3e2018-07-11 13:00:41354 : clock_(Clock::GetRealTimeClock()),
Danil Chapovalov1c41be62019-04-01 07:16:12355 task_queue_factory_(CreateDefaultTaskQueueFactory()),
Danil Chapovalov304ea5f2019-04-11 13:18:18356 rtc_event_log_factory_(task_queue_factory_.get()),
Niels Möllercbcbc222018-09-28 07:07:24357 video_decoder_factory_([this](const SdpVideoFormat& format) {
358 return this->CreateVideoDecoder(format);
359 }),
Sebastian Janssone6d7c3e2018-07-11 13:00:41360 video_encoder_factory_([this](const SdpVideoFormat& format) {
Niels Möller88be9722018-10-10 08:58:52361 return this->CreateVideoEncoder(format, nullptr);
Sebastian Janssone6d7c3e2018-07-11 13:00:41362 }),
Niels Möller88be9722018-10-10 08:58:52363 video_encoder_factory_with_analyzer_(
364 [this](const SdpVideoFormat& format) {
365 return this->CreateVideoEncoder(format, analyzer_.get());
366 }),
Jiawei Ouc2ebe212018-11-08 18:02:56367 video_bitrate_allocator_factory_(
368 CreateBuiltinVideoBitrateAllocatorFactory()),
Sebastian Janssone6d7c3e2018-07-11 13:00:41369 receive_logs_(0),
Artem Titove269cb42018-08-29 07:59:23370 send_logs_(0),
Erik Språng96965ae2018-10-23 13:42:37371 injection_components_(std::move(injection_components)),
372 num_video_streams_(0) {
Artem Titove269cb42018-08-29 07:59:23373 if (injection_components_ == nullptr) {
Mirko Bonadei317a1f02019-09-17 15:06:18374 injection_components_ = std::make_unique<InjectionComponents>();
Artem Titove269cb42018-08-29 07:59:23375 }
“Michael3c396e52019-06-12 14:47:14376 if (injection_components_->video_decoder_factory != nullptr) {
377 decoder_factory_ = std::move(injection_components_->video_decoder_factory);
378 } else {
Mirko Bonadei317a1f02019-09-17 15:06:18379 decoder_factory_ = std::make_unique<InternalDecoderFactory>();
“Michael3c396e52019-06-12 14:47:14380 }
381 if (injection_components_->video_encoder_factory != nullptr) {
382 encoder_factory_ = std::move(injection_components_->video_encoder_factory);
383 } else {
Mirko Bonadei317a1f02019-09-17 15:06:18384 encoder_factory_ = std::make_unique<InternalEncoderFactory>();
“Michael3c396e52019-06-12 14:47:14385 }
Artem Titove269cb42018-08-29 07:59:23386
minyue20c84cc2017-04-10 23:57:57387 payload_type_map_ = test::CallTest::payload_type_map_;
388 RTC_DCHECK(payload_type_map_.find(kPayloadTypeH264) ==
389 payload_type_map_.end());
390 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP8) ==
391 payload_type_map_.end());
392 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP9) ==
393 payload_type_map_.end());
Rasmus Brandt5894b6a2019-06-13 14:28:14394 RTC_DCHECK(payload_type_map_.find(kPayloadTypeGeneric) ==
395 payload_type_map_.end());
minyue20c84cc2017-04-10 23:57:57396 payload_type_map_[kPayloadTypeH264] = webrtc::MediaType::VIDEO;
397 payload_type_map_[kPayloadTypeVP8] = webrtc::MediaType::VIDEO;
398 payload_type_map_[kPayloadTypeVP9] = webrtc::MediaType::VIDEO;
Rasmus Brandt5894b6a2019-06-13 14:28:14399 payload_type_map_[kPayloadTypeGeneric] = webrtc::MediaType::VIDEO;
ivica5d6a06c2015-09-17 12:30:24400
Artem Titove269cb42018-08-29 07:59:23401 fec_controller_factory_ =
402 std::move(injection_components_->fec_controller_factory);
Ying Wangcab77fd2019-04-16 09:12:49403 network_state_predictor_factory_ =
404 std::move(injection_components_->network_state_predictor_factory);
Sebastian Jansson1391ed22019-04-30 12:23:51405 network_controller_factory_ =
406 std::move(injection_components_->network_controller_factory);
Ying Wang3b790f32018-01-19 16:58:57407}
408
minyue626bc952016-10-31 12:47:02409VideoQualityTest::Params::Params()
philipel569397f2018-09-26 10:25:31410 : call({false, false, BitrateConstraints(), 0}),
Erik Språng616b2332019-02-11 13:16:28411 video{{false,
412 640,
413 480,
414 30,
415 50,
416 800,
417 800,
418 false,
419 "VP8",
420 1,
421 -1,
422 0,
423 false,
424 false,
425 false,
426 "",
427 0,
428 {},
429 0.0},
430 {false,
431 640,
432 480,
433 30,
434 50,
435 800,
436 800,
437 false,
438 "VP8",
439 1,
440 -1,
441 0,
442 false,
443 false,
444 false,
445 "",
446 0,
447 {},
448 0.0}},
henrika255750b2018-08-27 14:13:37449 audio({false, false, false, false}),
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59450 screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
minyue626bc952016-10-31 12:47:02451 analyzer({"", 0.0, 0.0, 0, "", ""}),
Artem Titovf18b3522018-08-28 14:54:24452 config(absl::nullopt),
Sergey Silkin57027362018-05-15 07:12:05453 ss{{std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
454 std::vector<SpatialLayer>()},
455 {std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
456 std::vector<SpatialLayer>()}},
Mirko Bonadei45a4c412018-07-31 13:07:28457 logging({"", "", ""}) {}
minyue626bc952016-10-31 12:47:02458
459VideoQualityTest::Params::~Params() = default;
460
Artem Titove269cb42018-08-29 07:59:23461VideoQualityTest::InjectionComponents::InjectionComponents() = default;
462
463VideoQualityTest::InjectionComponents::~InjectionComponents() = default;
464
ivica5d6a06c2015-09-17 12:30:24465void VideoQualityTest::TestBody() {}
466
sprangce4aef12015-11-02 15:23:20467std::string VideoQualityTest::GenerateGraphTitle() const {
Jonas Olsson366a50c2018-09-06 11:41:30468 rtc::StringBuilder ss;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59469 ss << params_.video[0].codec;
470 ss << " (" << params_.video[0].target_bitrate_bps / 1000 << "kbps";
471 ss << ", " << params_.video[0].fps << " FPS";
472 if (params_.screenshare[0].scroll_duration)
473 ss << ", " << params_.screenshare[0].scroll_duration << "s scroll";
474 if (params_.ss[0].streams.size() > 1)
475 ss << ", Stream #" << params_.ss[0].selected_stream;
476 if (params_.ss[0].num_spatial_layers > 1)
477 ss << ", Layer #" << params_.ss[0].selected_sl;
sprangce4aef12015-11-02 15:23:20478 ss << ")";
Jonas Olsson84df1c72018-09-14 14:59:32479 return ss.Release();
sprangce4aef12015-11-02 15:23:20480}
481
Artem Titove269cb42018-08-29 07:59:23482void VideoQualityTest::CheckParamsAndInjectionComponents() {
483 if (injection_components_ == nullptr) {
Mirko Bonadei317a1f02019-09-17 15:06:18484 injection_components_ = std::make_unique<InjectionComponents>();
Artem Titove269cb42018-08-29 07:59:23485 }
486 if (!params_.config && injection_components_->sender_network == nullptr &&
487 injection_components_->receiver_network == nullptr) {
Artem Titov62ae1782018-10-24 12:14:49488 params_.config = BuiltInNetworkBehaviorConfig();
Artem Titovf18b3522018-08-28 14:54:24489 }
Artem Titove269cb42018-08-29 07:59:23490 RTC_CHECK(
491 (params_.config && injection_components_->sender_network == nullptr &&
492 injection_components_->receiver_network == nullptr) ||
493 (!params_.config && injection_components_->sender_network != nullptr &&
494 injection_components_->receiver_network != nullptr));
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59495 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
496 // Iterate over primary and secondary video streams.
497 if (!params_.video[video_idx].enabled)
498 return;
499 // Add a default stream in none specified.
500 if (params_.ss[video_idx].streams.empty())
501 params_.ss[video_idx].streams.push_back(
502 VideoQualityTest::DefaultVideoStream(params_, video_idx));
503 if (params_.ss[video_idx].num_spatial_layers == 0)
504 params_.ss[video_idx].num_spatial_layers = 1;
sprangce4aef12015-11-02 15:23:20505
Artem Titove269cb42018-08-29 07:59:23506 if (params_.config) {
507 if (params_.config->loss_percent != 0 ||
508 params_.config->queue_length_packets != 0) {
509 // Since LayerFilteringTransport changes the sequence numbers, we can't
510 // use that feature with pack loss, since the NACK request would end up
511 // retransmitting the wrong packets.
512 RTC_CHECK(params_.ss[video_idx].selected_sl == -1 ||
513 params_.ss[video_idx].selected_sl ==
514 params_.ss[video_idx].num_spatial_layers - 1);
515 RTC_CHECK(params_.video[video_idx].selected_tl == -1 ||
516 params_.video[video_idx].selected_tl ==
517 params_.video[video_idx].num_temporal_layers - 1);
518 }
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59519 }
sprangce4aef12015-11-02 15:23:20520
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59521 // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as
522 // it does in some parts of the code?
523 RTC_CHECK_GE(params_.video[video_idx].max_bitrate_bps,
524 params_.video[video_idx].target_bitrate_bps);
525 RTC_CHECK_GE(params_.video[video_idx].target_bitrate_bps,
526 params_.video[video_idx].min_bitrate_bps);
Ilya Nikolaevskiyaec663e2019-02-27 11:52:11527 int selected_stream = params_.ss[video_idx].selected_stream;
528 int stream_tl = params_.ss[video_idx]
529 .streams[selected_stream]
530 .num_temporal_layers.value_or(1);
531 RTC_CHECK_LT(params_.video[video_idx].selected_tl, stream_tl);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59532 RTC_CHECK_LE(params_.ss[video_idx].selected_stream,
533 params_.ss[video_idx].streams.size());
534 for (const VideoStream& stream : params_.ss[video_idx].streams) {
535 RTC_CHECK_GE(stream.min_bitrate_bps, 0);
536 RTC_CHECK_GE(stream.target_bitrate_bps, stream.min_bitrate_bps);
537 RTC_CHECK_GE(stream.max_bitrate_bps, stream.target_bitrate_bps);
538 }
539 // TODO(ivica): Should we check if the sum of all streams/layers is equal to
540 // the total bitrate? We anyway have to update them in the case bitrate
541 // estimator changes the total bitrates.
542 RTC_CHECK_GE(params_.ss[video_idx].num_spatial_layers, 1);
543 RTC_CHECK_LE(params_.ss[video_idx].selected_sl,
544 params_.ss[video_idx].num_spatial_layers);
545 RTC_CHECK(
546 params_.ss[video_idx].spatial_layers.empty() ||
547 params_.ss[video_idx].spatial_layers.size() ==
548 static_cast<size_t>(params_.ss[video_idx].num_spatial_layers));
549 if (params_.video[video_idx].codec == "VP8") {
550 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
551 } else if (params_.video[video_idx].codec == "VP9") {
552 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 1);
553 }
554 RTC_CHECK_GE(params_.call.num_thumbnails, 0);
555 if (params_.call.num_thumbnails > 0) {
556 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
557 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 3);
558 RTC_CHECK_EQ(params_.video[video_idx].num_temporal_layers, 3);
559 RTC_CHECK_EQ(params_.video[video_idx].codec, "VP8");
560 }
561 // Dual streams with FEC not supported in tests yet.
562 RTC_CHECK(!params_.video[video_idx].flexfec || num_video_streams_ == 1);
563 RTC_CHECK(!params_.video[video_idx].ulpfec || num_video_streams_ == 1);
ilnika014cc52017-03-07 12:21:04564 }
sprangce4aef12015-11-02 15:23:20565}
566
567// Static.
568std::vector<int> VideoQualityTest::ParseCSV(const std::string& str) {
569 // Parse comma separated nonnegative integers, where some elements may be
570 // empty. The empty values are replaced with -1.
571 // E.g. "10,-20,,30,40" --> {10, 20, -1, 30,40}
572 // E.g. ",,10,,20," --> {-1, -1, 10, -1, 20, -1}
573 std::vector<int> result;
574 if (str.empty())
575 return result;
576
577 const char* p = str.c_str();
578 int value = -1;
579 int pos;
580 while (*p) {
581 if (*p == ',') {
582 result.push_back(value);
583 value = -1;
584 ++p;
585 continue;
586 }
587 RTC_CHECK_EQ(sscanf(p, "%d%n", &value, &pos), 1)
588 << "Unexpected non-number value.";
589 p += pos;
590 }
591 result.push_back(value);
592 return result;
593}
594
595// Static.
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59596VideoStream VideoQualityTest::DefaultVideoStream(const Params& params,
597 size_t video_idx) {
sprangce4aef12015-11-02 15:23:20598 VideoStream stream;
Danil Chapovalov350531e2018-06-08 11:04:04599 stream.width = params.video[video_idx].width;
600 stream.height = params.video[video_idx].height;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59601 stream.max_framerate = params.video[video_idx].fps;
602 stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps;
603 stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
604 stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
sprang1168fd42017-06-21 16:00:17605 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 14:11:29606 stream.num_temporal_layers = params.video[video_idx].num_temporal_layers;
Seth Hampson46e31ba2018-01-18 18:39:54607 stream.active = true;
ilnika014cc52017-03-07 12:21:04608 return stream;
609}
610
611// Static.
612VideoStream VideoQualityTest::DefaultThumbnailStream() {
613 VideoStream stream;
614 stream.width = 320;
615 stream.height = 180;
616 stream.max_framerate = 7;
617 stream.min_bitrate_bps = 7500;
618 stream.target_bitrate_bps = 37500;
619 stream.max_bitrate_bps = 50000;
sprang1168fd42017-06-21 16:00:17620 stream.max_qp = kDefaultMaxQp;
sprangce4aef12015-11-02 15:23:20621 return stream;
622}
623
624// Static.
625void VideoQualityTest::FillScalabilitySettings(
626 Params* params,
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59627 size_t video_idx,
sprangce4aef12015-11-02 15:23:20628 const std::vector<std::string>& stream_descriptors,
sprang1168fd42017-06-21 16:00:17629 int num_streams,
sprangce4aef12015-11-02 15:23:20630 size_t selected_stream,
631 int num_spatial_layers,
632 int selected_sl,
Sergey Silkin57027362018-05-15 07:12:05633 InterLayerPredMode inter_layer_pred,
sprangce4aef12015-11-02 15:23:20634 const std::vector<std::string>& sl_descriptors) {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59635 if (params->ss[video_idx].streams.empty() &&
636 params->ss[video_idx].infer_streams) {
sprang1168fd42017-06-21 16:00:17637 webrtc::VideoEncoderConfig encoder_config;
Niels Möller259a4972018-04-05 13:36:51638 encoder_config.codec_type =
639 PayloadStringToCodecType(params->video[video_idx].codec);
sprang1168fd42017-06-21 16:00:17640 encoder_config.content_type =
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59641 params->screenshare[video_idx].enabled
sprang1168fd42017-06-21 16:00:17642 ? webrtc::VideoEncoderConfig::ContentType::kScreen
643 : webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59644 encoder_config.max_bitrate_bps = params->video[video_idx].max_bitrate_bps;
645 encoder_config.min_transmit_bitrate_bps =
646 params->video[video_idx].min_transmit_bps;
sprang1168fd42017-06-21 16:00:17647 encoder_config.number_of_streams = num_streams;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59648 encoder_config.spatial_layers = params->ss[video_idx].spatial_layers;
Seth Hampson8234ead2018-02-02 23:16:24649 encoder_config.simulcast_layers = std::vector<VideoStream>(num_streams);
sprang1168fd42017-06-21 16:00:17650 encoder_config.video_stream_factory =
651 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59652 params->video[video_idx].codec, kDefaultMaxQp,
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59653 params->screenshare[video_idx].enabled, true);
654 params->ss[video_idx].streams =
sprang1168fd42017-06-21 16:00:17655 encoder_config.video_stream_factory->CreateEncoderStreams(
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59656 static_cast<int>(params->video[video_idx].width),
657 static_cast<int>(params->video[video_idx].height), encoder_config);
sprang1168fd42017-06-21 16:00:17658 } else {
659 // Read VideoStream and SpatialLayer elements from a list of comma separated
660 // lists. To use a default value for an element, use -1 or leave empty.
Artem Titove269cb42018-08-29 07:59:23661 // Validity checks performed in CheckParamsAndInjectionComponents.
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59662 RTC_CHECK(params->ss[video_idx].streams.empty());
Mirko Bonadei739baf02019-01-27 16:29:42663 for (const auto& descriptor : stream_descriptors) {
sprang1168fd42017-06-21 16:00:17664 if (descriptor.empty())
665 continue;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59666 VideoStream stream =
667 VideoQualityTest::DefaultVideoStream(*params, video_idx);
sprang1168fd42017-06-21 16:00:17668 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
669 if (v[0] != -1)
670 stream.width = static_cast<size_t>(v[0]);
671 if (v[1] != -1)
672 stream.height = static_cast<size_t>(v[1]);
673 if (v[2] != -1)
674 stream.max_framerate = v[2];
675 if (v[3] != -1)
676 stream.min_bitrate_bps = v[3];
677 if (v[4] != -1)
678 stream.target_bitrate_bps = v[4];
679 if (v[5] != -1)
680 stream.max_bitrate_bps = v[5];
681 if (v.size() > 6 && v[6] != -1)
682 stream.max_qp = v[6];
Sergey Silkina796a7e2018-03-01 14:11:29683 if (v.size() > 7 && v[7] != -1) {
684 stream.num_temporal_layers = v[7];
sprang1168fd42017-06-21 16:00:17685 } else {
686 // Automatic TL thresholds for more than two layers not supported.
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59687 RTC_CHECK_LE(params->video[video_idx].num_temporal_layers, 2);
sprang1168fd42017-06-21 16:00:17688 }
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59689 params->ss[video_idx].streams.push_back(stream);
sprangce4aef12015-11-02 15:23:20690 }
sprangce4aef12015-11-02 15:23:20691 }
sprangce4aef12015-11-02 15:23:20692
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59693 params->ss[video_idx].num_spatial_layers = std::max(1, num_spatial_layers);
694 params->ss[video_idx].selected_stream = selected_stream;
sprang1168fd42017-06-21 16:00:17695
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59696 params->ss[video_idx].selected_sl = selected_sl;
Sergey Silkin57027362018-05-15 07:12:05697 params->ss[video_idx].inter_layer_pred = inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59698 RTC_CHECK(params->ss[video_idx].spatial_layers.empty());
Mirko Bonadei739baf02019-01-27 16:29:42699 for (const auto& descriptor : sl_descriptors) {
sprangce4aef12015-11-02 15:23:20700 if (descriptor.empty())
701 continue;
702 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
Sergey Silkina89800c2019-02-19 11:52:56703 RTC_CHECK_EQ(v.size(), 8);
sprangce4aef12015-11-02 15:23:20704
Sergey Silkin13e74342018-03-02 11:28:00705 SpatialLayer layer = {0};
706 layer.width = v[0];
707 layer.height = v[1];
Sergey Silkina89800c2019-02-19 11:52:56708 layer.maxFramerate = v[2];
709 layer.numberOfTemporalLayers = v[3];
710 layer.maxBitrate = v[4];
711 layer.minBitrate = v[5];
712 layer.targetBitrate = v[6];
713 layer.qpMax = v[7];
Sergey Silkin13e74342018-03-02 11:28:00714 layer.active = true;
715
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59716 params->ss[video_idx].spatial_layers.push_back(layer);
sprangce4aef12015-11-02 15:23:20717 }
718}
719
minyuea27172d2016-11-01 12:59:29720void VideoQualityTest::SetupVideo(Transport* send_transport,
721 Transport* recv_transport) {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59722 size_t total_streams_used = 0;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59723 video_receive_configs_.clear();
724 video_send_configs_.clear();
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59725 video_encoder_configs_.clear();
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59726 bool decode_all_receive_streams = true;
727 size_t num_video_substreams = params_.ss[0].streams.size();
728 RTC_CHECK(num_video_streams_ > 0);
729 video_encoder_configs_.resize(num_video_streams_);
Rasmus Brandt5894b6a2019-06-13 14:28:14730 std::string generic_codec_name;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59731 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
732 video_send_configs_.push_back(VideoSendStream::Config(send_transport));
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59733 video_encoder_configs_.push_back(VideoEncoderConfig());
734 num_video_substreams = params_.ss[video_idx].streams.size();
735 RTC_CHECK_GT(num_video_substreams, 0);
Sebastian Jansson3bd2c792018-07-13 11:29:03736 for (size_t i = 0; i < num_video_substreams; ++i)
737 video_send_configs_[video_idx].rtp.ssrcs.push_back(
738 kVideoSendSsrcs[total_streams_used + i]);
Qingsi Wang2d82ade2018-07-11 06:04:44739
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59740 int payload_type;
741 if (params_.video[video_idx].codec == "H264") {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59742 payload_type = kPayloadTypeH264;
743 } else if (params_.video[video_idx].codec == "VP8") {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59744 payload_type = kPayloadTypeVP8;
745 } else if (params_.video[video_idx].codec == "VP9") {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59746 payload_type = kPayloadTypeVP9;
Emircan Uysaler03e6ec92018-03-09 23:03:26747 } else if (params_.video[video_idx].codec == "multiplex") {
Emircan Uysaler03e6ec92018-03-09 23:03:26748 payload_type = kPayloadTypeVP9;
Emircan Uysaler7c03bdc2019-01-16 20:07:56749 } else if (params_.video[video_idx].codec == "FakeCodec") {
750 payload_type = kFakeVideoSendPayloadType;
ilnikcb8c1462017-03-09 17:23:30751 } else {
Rasmus Brandt5894b6a2019-06-13 14:28:14752 RTC_CHECK(generic_codec_name.empty() ||
753 generic_codec_name == params_.video[video_idx].codec)
754 << "Supplying multiple generic codecs is unsupported.";
755 RTC_LOG(LS_INFO) << "Treating codec " << params_.video[video_idx].codec
756 << " as generic.";
757 payload_type = kPayloadTypeGeneric;
758 generic_codec_name = params_.video[video_idx].codec;
ilnikcb8c1462017-03-09 17:23:30759 }
Niels Möller4db138e2018-04-19 07:04:13760 video_send_configs_[video_idx].encoder_settings.encoder_factory =
Niels Möller88be9722018-10-10 08:58:52761 (video_idx == 0) ? &video_encoder_factory_with_analyzer_
762 : &video_encoder_factory_;
Jiawei Ouc2ebe212018-11-08 18:02:56763 video_send_configs_[video_idx].encoder_settings.bitrate_allocator_factory =
764 video_bitrate_allocator_factory_.get();
Niels Möller4db138e2018-04-19 07:04:13765
Niels Möller259a4972018-04-05 13:36:51766 video_send_configs_[video_idx].rtp.payload_name =
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59767 params_.video[video_idx].codec;
Niels Möller259a4972018-04-05 13:36:51768 video_send_configs_[video_idx].rtp.payload_type = payload_type;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59769 video_send_configs_[video_idx].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
770 video_send_configs_[video_idx].rtp.rtx.payload_type = kSendRtxPayloadType;
771 for (size_t i = 0; i < num_video_substreams; ++i) {
772 video_send_configs_[video_idx].rtp.rtx.ssrcs.push_back(
773 kSendRtxSsrcs[i + total_streams_used]);
ilnik9fd9f6c2017-03-02 16:10:10774 }
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59775 video_send_configs_[video_idx].rtp.extensions.clear();
776 if (params_.call.send_side_bwe) {
philipel569397f2018-09-26 10:25:31777 video_send_configs_[video_idx].rtp.extensions.emplace_back(
778 RtpExtension::kTransportSequenceNumberUri,
Elad Alond8d32482019-02-18 22:45:57779 kTransportSequenceNumberExtensionId);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59780 } else {
philipel569397f2018-09-26 10:25:31781 video_send_configs_[video_idx].rtp.extensions.emplace_back(
Elad Alond8d32482019-02-18 22:45:57782 RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59783 }
philipel569397f2018-09-26 10:25:31784
785 if (params_.call.generic_descriptor) {
786 // The generic descriptor is currently behind a field trial, so it needs
787 // to be set for this flag to have any effect.
788 // TODO(philipel): Remove this check when the experiment is removed.
789 RTC_CHECK(field_trial::IsEnabled("WebRTC-GenericDescriptor"));
790
791 video_send_configs_[video_idx].rtp.extensions.emplace_back(
Elad Alonccb9b752019-02-19 12:01:31792 RtpExtension::kGenericFrameDescriptorUri00,
793 kGenericFrameDescriptorExtensionId00);
794 video_send_configs_[video_idx].rtp.extensions.emplace_back(
795 RtpExtension::kGenericFrameDescriptorUri01,
796 kGenericFrameDescriptorExtensionId01);
philipel569397f2018-09-26 10:25:31797 }
798
799 video_send_configs_[video_idx].rtp.extensions.emplace_back(
Elad Alond8d32482019-02-18 22:45:57800 RtpExtension::kVideoContentTypeUri, kVideoContentTypeExtensionId);
philipel569397f2018-09-26 10:25:31801 video_send_configs_[video_idx].rtp.extensions.emplace_back(
Elad Alond8d32482019-02-18 22:45:57802 RtpExtension::kVideoTimingUri, kVideoTimingExtensionId);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59803
Niels Möller4db138e2018-04-19 07:04:13804 video_encoder_configs_[video_idx].video_format.name =
805 params_.video[video_idx].codec;
806
Emircan Uysaler0823eec2018-07-14 00:10:00807 video_encoder_configs_[video_idx].video_format.parameters =
808 params_.video[video_idx].sdp_params;
809
Niels Möller259a4972018-04-05 13:36:51810 video_encoder_configs_[video_idx].codec_type =
811 PayloadStringToCodecType(params_.video[video_idx].codec);
812
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59813 video_encoder_configs_[video_idx].min_transmit_bitrate_bps =
814 params_.video[video_idx].min_transmit_bps;
815
816 video_send_configs_[video_idx].suspend_below_min_bitrate =
817 params_.video[video_idx].suspend_below_min_bitrate;
818
819 video_encoder_configs_[video_idx].number_of_streams =
820 params_.ss[video_idx].streams.size();
821 video_encoder_configs_[video_idx].max_bitrate_bps = 0;
822 for (size_t i = 0; i < params_.ss[video_idx].streams.size(); ++i) {
823 video_encoder_configs_[video_idx].max_bitrate_bps +=
824 params_.ss[video_idx].streams[i].max_bitrate_bps;
825 }
Ilya Nikolaevskiy6957abe2019-01-29 15:33:04826 video_encoder_configs_[video_idx].simulcast_layers =
827 std::vector<VideoStream>(params_.ss[video_idx].streams.size());
828 if (!params_.ss[video_idx].infer_streams) {
Seth Hampson8234ead2018-02-02 23:16:24829 video_encoder_configs_[video_idx].simulcast_layers =
Ilya Nikolaevskiy6957abe2019-01-29 15:33:04830 params_.ss[video_idx].streams;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59831 }
Ilya Nikolaevskiy6957abe2019-01-29 15:33:04832 video_encoder_configs_[video_idx].video_stream_factory =
833 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
834 params_.video[video_idx].codec,
835 params_.ss[video_idx].streams[0].max_qp,
836 params_.screenshare[video_idx].enabled, true);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59837
838 video_encoder_configs_[video_idx].spatial_layers =
839 params_.ss[video_idx].spatial_layers;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59840 decode_all_receive_streams = params_.ss[video_idx].selected_stream ==
841 params_.ss[video_idx].streams.size();
Sebastian Jansson3bd2c792018-07-13 11:29:03842 absl::optional<int> decode_sub_stream;
843 if (!decode_all_receive_streams)
844 decode_sub_stream = params_.ss[video_idx].selected_stream;
845 CreateMatchingVideoReceiveConfigs(
846 video_send_configs_[video_idx], recv_transport,
Niels Möllercbcbc222018-09-28 07:07:24847 params_.call.send_side_bwe, &video_decoder_factory_, decode_sub_stream,
848 true, kNackRtpHistoryMs);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59849
850 if (params_.screenshare[video_idx].enabled) {
851 // Fill out codec settings.
852 video_encoder_configs_[video_idx].content_type =
853 VideoEncoderConfig::ContentType::kScreen;
Taylor Brandstetter49fcc102018-05-16 21:20:41854 degradation_preference_ = DegradationPreference::MAINTAIN_RESOLUTION;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59855 if (params_.video[video_idx].codec == "VP8") {
856 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
857 vp8_settings.denoisingOn = false;
858 vp8_settings.frameDroppingOn = false;
859 vp8_settings.numberOfTemporalLayers = static_cast<unsigned char>(
860 params_.video[video_idx].num_temporal_layers);
861 video_encoder_configs_[video_idx].encoder_specific_settings =
862 new rtc::RefCountedObject<
863 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
864 } else if (params_.video[video_idx].codec == "VP9") {
865 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
866 vp9_settings.denoisingOn = false;
867 vp9_settings.frameDroppingOn = false;
868 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
869 params_.video[video_idx].num_temporal_layers);
870 vp9_settings.numberOfSpatialLayers = static_cast<unsigned char>(
871 params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 07:12:05872 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy5546aef2018-12-04 14:54:52873 // High FPS vp9 screenshare requires flexible mode.
Ilya Nikolaevskiy5c18a5f2019-05-24 09:51:31874 if (params_.ss[video_idx].num_spatial_layers > 1) {
Ilya Nikolaevskiy5546aef2018-12-04 14:54:52875 vp9_settings.flexibleMode = true;
876 }
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59877 video_encoder_configs_[video_idx].encoder_specific_settings =
878 new rtc::RefCountedObject<
879 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
880 }
881 } else if (params_.ss[video_idx].num_spatial_layers > 1) {
882 // If SVC mode without screenshare, still need to set codec specifics.
883 RTC_CHECK(params_.video[video_idx].codec == "VP9");
884 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
885 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
886 params_.video[video_idx].num_temporal_layers);
887 vp9_settings.numberOfSpatialLayers =
888 static_cast<unsigned char>(params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 07:12:05889 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59890 video_encoder_configs_[video_idx].encoder_specific_settings =
891 new rtc::RefCountedObject<
892 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Niels Möller6aa415e2018-06-07 09:14:13893 } else if (params_.video[video_idx].automatic_scaling) {
894 if (params_.video[video_idx].codec == "VP8") {
895 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
896 vp8_settings.automaticResizeOn = true;
897 video_encoder_configs_[video_idx].encoder_specific_settings =
898 new rtc::RefCountedObject<
899 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
900 } else if (params_.video[video_idx].codec == "VP9") {
901 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
902 vp9_settings.automaticResizeOn = true;
903 video_encoder_configs_[video_idx].encoder_specific_settings =
904 new rtc::RefCountedObject<
905 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Stefan Holmer1f7a0082019-01-11 14:39:08906 } else if (params_.video[video_idx].codec == "H264") {
907 // Quality scaling is always on for H.264.
Niels Möller6aa415e2018-06-07 09:14:13908 } else {
909 RTC_NOTREACHED() << "Automatic scaling not supported for codec "
Yves Gerey665174f2018-06-19 13:03:05910 << params_.video[video_idx].codec << ", stream "
911 << video_idx;
Niels Möller6aa415e2018-06-07 09:14:13912 }
Ilya Nikolaevskiy6957abe2019-01-29 15:33:04913 } else {
914 // Default mode. Single SL, no automatic_scaling,
915 if (params_.video[video_idx].codec == "VP8") {
916 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
917 vp8_settings.automaticResizeOn = false;
918 video_encoder_configs_[video_idx].encoder_specific_settings =
919 new rtc::RefCountedObject<
920 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
921 } else if (params_.video[video_idx].codec == "VP9") {
922 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
923 vp9_settings.automaticResizeOn = false;
924 video_encoder_configs_[video_idx].encoder_specific_settings =
925 new rtc::RefCountedObject<
926 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
927 } else if (params_.video[video_idx].codec == "H264") {
928 VideoCodecH264 h264_settings = VideoEncoder::GetDefaultH264Settings();
929 video_encoder_configs_[video_idx].encoder_specific_settings =
930 new rtc::RefCountedObject<
931 VideoEncoderConfig::H264EncoderSpecificSettings>(h264_settings);
932 }
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59933 }
934 total_streams_used += num_video_substreams;
sprangce4aef12015-11-02 15:23:20935 }
brandtr1293aca2016-11-17 06:47:29936
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59937 // FEC supported only for single video stream mode yet.
938 if (params_.video[0].flexfec) {
sprang1168fd42017-06-21 16:00:17939 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 11:29:03940 SetSendFecConfig(GetVideoSendConfig()->rtp.ssrcs);
sprang1168fd42017-06-21 16:00:17941 } else {
Sebastian Jansson3bd2c792018-07-13 11:29:03942 SetSendFecConfig({kVideoSendSsrcs[params_.ss[0].selected_stream]});
sprang1168fd42017-06-21 16:00:17943 }
brandtr1293aca2016-11-17 06:47:29944
Sebastian Jansson3bd2c792018-07-13 11:29:03945 CreateMatchingFecConfig(recv_transport, *GetVideoSendConfig());
946 GetFlexFecConfig()->transport_cc = params_.call.send_side_bwe;
brandtrb29e6522016-12-21 14:37:18947 if (params_.call.send_side_bwe) {
Sebastian Jansson3bd2c792018-07-13 11:29:03948 GetFlexFecConfig()->rtp_header_extensions.push_back(
brandtrb29e6522016-12-21 14:37:18949 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
Elad Alond8d32482019-02-18 22:45:57950 kTransportSequenceNumberExtensionId));
brandtrb29e6522016-12-21 14:37:18951 } else {
Elad Alond8d32482019-02-18 22:45:57952 GetFlexFecConfig()->rtp_header_extensions.push_back(
953 RtpExtension(RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId));
brandtrb29e6522016-12-21 14:37:18954 }
brandtr1293aca2016-11-17 06:47:29955 }
956
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:59957 if (params_.video[0].ulpfec) {
Sebastian Jansson3bd2c792018-07-13 11:29:03958 SetSendUlpFecConfig(GetVideoSendConfig());
sprang1168fd42017-06-21 16:00:17959 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 11:29:03960 for (auto& receive_config : video_receive_configs_) {
961 SetReceiveUlpFecConfig(&receive_config);
sprang1168fd42017-06-21 16:00:17962 }
963 } else {
Sebastian Jansson3bd2c792018-07-13 11:29:03964 SetReceiveUlpFecConfig(
965 &video_receive_configs_[params_.ss[0].selected_stream]);
sprang1168fd42017-06-21 16:00:17966 }
brandtr1293aca2016-11-17 06:47:29967 }
ivica5d6a06c2015-09-17 12:30:24968}
969
ilnika014cc52017-03-07 12:21:04970void VideoQualityTest::SetupThumbnails(Transport* send_transport,
971 Transport* recv_transport) {
ilnik98436952017-07-13 07:47:03972 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 12:21:04973 // Thumbnails will be send in the other way: from receiver_call to
974 // sender_call.
975 VideoSendStream::Config thumbnail_send_config(recv_transport);
976 thumbnail_send_config.rtp.ssrcs.push_back(kThumbnailSendSsrcStart + i);
Niels Möller4db138e2018-04-19 07:04:13977 // TODO(nisse): Could use a simpler VP8-only encoder factory.
978 thumbnail_send_config.encoder_settings.encoder_factory =
979 &video_encoder_factory_;
Jiawei Ouc2ebe212018-11-08 18:02:56980 thumbnail_send_config.encoder_settings.bitrate_allocator_factory =
981 video_bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 13:36:51982 thumbnail_send_config.rtp.payload_name = params_.video[0].codec;
983 thumbnail_send_config.rtp.payload_type = kPayloadTypeVP8;
ilnika014cc52017-03-07 12:21:04984 thumbnail_send_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
985 thumbnail_send_config.rtp.rtx.payload_type = kSendRtxPayloadType;
986 thumbnail_send_config.rtp.rtx.ssrcs.push_back(kThumbnailRtxSsrcStart + i);
987 thumbnail_send_config.rtp.extensions.clear();
988 if (params_.call.send_side_bwe) {
989 thumbnail_send_config.rtp.extensions.push_back(
990 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
Elad Alond8d32482019-02-18 22:45:57991 kTransportSequenceNumberExtensionId));
ilnika014cc52017-03-07 12:21:04992 } else {
Elad Alond8d32482019-02-18 22:45:57993 thumbnail_send_config.rtp.extensions.push_back(
994 RtpExtension(RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId));
ilnika014cc52017-03-07 12:21:04995 }
996
997 VideoEncoderConfig thumbnail_encoder_config;
Niels Möller259a4972018-04-05 13:36:51998 thumbnail_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller4db138e2018-04-19 07:04:13999 thumbnail_encoder_config.video_format.name = "VP8";
ilnika014cc52017-03-07 12:21:041000 thumbnail_encoder_config.min_transmit_bitrate_bps = 7500;
1001 thumbnail_send_config.suspend_below_min_bitrate =
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591002 params_.video[0].suspend_below_min_bitrate;
ilnika014cc52017-03-07 12:21:041003 thumbnail_encoder_config.number_of_streams = 1;
1004 thumbnail_encoder_config.max_bitrate_bps = 50000;
Ilya Nikolaevskiy6957abe2019-01-29 15:33:041005 std::vector<VideoStream> streams{params_.ss[0].streams[0]};
1006 thumbnail_encoder_config.video_stream_factory =
1007 new rtc::RefCountedObject<VideoStreamFactory>(streams);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591008 thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers;
ilnika014cc52017-03-07 12:21:041009
ilnika014cc52017-03-07 12:21:041010 thumbnail_encoder_configs_.push_back(thumbnail_encoder_config.Copy());
1011 thumbnail_send_configs_.push_back(thumbnail_send_config.Copy());
ilnika014cc52017-03-07 12:21:041012
Sebastian Jansson3bd2c792018-07-13 11:29:031013 AddMatchingVideoReceiveConfigs(
1014 &thumbnail_receive_configs_, thumbnail_send_config, send_transport,
Niels Möllercbcbc222018-09-28 07:07:241015 params_.call.send_side_bwe, &video_decoder_factory_, absl::nullopt,
1016 false, kNackRtpHistoryMs);
Sebastian Jansson3bd2c792018-07-13 11:29:031017 }
1018 for (size_t i = 0; i < thumbnail_send_configs_.size(); ++i) {
ilnika014cc52017-03-07 12:21:041019 thumbnail_send_streams_.push_back(receiver_call_->CreateVideoSendStream(
1020 thumbnail_send_configs_[i].Copy(),
1021 thumbnail_encoder_configs_[i].Copy()));
Sebastian Jansson3bd2c792018-07-13 11:29:031022 }
1023 for (size_t i = 0; i < thumbnail_receive_configs_.size(); ++i) {
ilnika014cc52017-03-07 12:21:041024 thumbnail_receive_streams_.push_back(sender_call_->CreateVideoReceiveStream(
1025 thumbnail_receive_configs_[i].Copy()));
1026 }
1027}
1028
1029void VideoQualityTest::DestroyThumbnailStreams() {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591030 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) {
ilnika014cc52017-03-07 12:21:041031 receiver_call_->DestroyVideoSendStream(thumbnail_send_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591032 }
ilnika014cc52017-03-07 12:21:041033 thumbnail_send_streams_.clear();
1034 for (VideoReceiveStream* thumbnail_receive_stream :
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591035 thumbnail_receive_streams_) {
ilnika014cc52017-03-07 12:21:041036 sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591037 }
ilnika014cc52017-03-07 12:21:041038 thumbnail_send_streams_.clear();
1039 thumbnail_receive_streams_.clear();
Niels Möller1c931c42018-12-18 15:08:111040 for (std::unique_ptr<rtc::VideoSourceInterface<VideoFrame>>& video_capturer :
eladalon413ee9a2017-08-22 11:02:521041 thumbnail_capturers_) {
Niels Möller1c931c42018-12-18 15:08:111042 video_capturer.reset();
eladalon413ee9a2017-08-22 11:02:521043 }
ilnika014cc52017-03-07 12:21:041044}
1045
ilnika014cc52017-03-07 12:21:041046void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) {
1047 VideoStream thumbnail = DefaultThumbnailStream();
1048 for (size_t i = 0; i < num_thumbnail_streams; ++i) {
Danil Chapovalov908e22e2019-04-18 12:34:161049 auto frame_generator_capturer =
Mirko Bonadei317a1f02019-09-17 15:06:181050 std::make_unique<test::FrameGeneratorCapturer>(
Danil Chapovalov908e22e2019-04-18 12:34:161051 clock_,
1052 test::FrameGenerator::CreateSquareGenerator(
1053 static_cast<int>(thumbnail.width),
1054 static_cast<int>(thumbnail.height), absl::nullopt,
1055 absl::nullopt),
1056 thumbnail.max_framerate, *task_queue_factory_);
1057 EXPECT_TRUE(frame_generator_capturer->Init());
1058 thumbnail_capturers_.push_back(std::move(frame_generator_capturer));
ilnika014cc52017-03-07 12:21:041059 }
1060}
1061
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591062std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator(
1063 size_t video_idx) {
1064 // Setup frame generator.
1065 const size_t kWidth = 1850;
1066 const size_t kHeight = 1110;
1067 std::unique_ptr<test::FrameGenerator> frame_generator;
1068 if (params_.screenshare[video_idx].generate_slides) {
1069 frame_generator = test::FrameGenerator::CreateSlideGenerator(
1070 kWidth, kHeight,
1071 params_.screenshare[video_idx].slide_change_interval *
1072 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 12:30:241073 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591074 std::vector<std::string> slides = params_.screenshare[video_idx].slides;
Benjamin Wright1f4173e2019-03-14 00:59:321075 if (slides.empty()) {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591076 slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
1077 slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
1078 slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
1079 slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
1080 }
1081 if (params_.screenshare[video_idx].scroll_duration == 0) {
1082 // Cycle image every slide_change_interval seconds.
1083 frame_generator = test::FrameGenerator::CreateFromYuvFile(
1084 slides, kWidth, kHeight,
1085 params_.screenshare[video_idx].slide_change_interval *
1086 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 12:30:241087 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591088 RTC_CHECK_LE(params_.video[video_idx].width, kWidth);
1089 RTC_CHECK_LE(params_.video[video_idx].height, kHeight);
1090 RTC_CHECK_GT(params_.screenshare[video_idx].slide_change_interval, 0);
1091 const int kPauseDurationMs =
1092 (params_.screenshare[video_idx].slide_change_interval -
1093 params_.screenshare[video_idx].scroll_duration) *
1094 1000;
1095 RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration,
1096 params_.screenshare[video_idx].slide_change_interval);
1097
1098 frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
1099 clock_, slides, kWidth, kHeight, params_.video[video_idx].width,
1100 params_.video[video_idx].height,
1101 params_.screenshare[video_idx].scroll_duration * 1000,
1102 kPauseDurationMs);
ivica5d6a06c2015-09-17 12:30:241103 }
1104 }
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591105 return frame_generator;
1106}
1107
1108void VideoQualityTest::CreateCapturers() {
Sebastian Jansson3bd2c792018-07-13 11:29:031109 RTC_DCHECK(video_sources_.empty());
Niels Möller1c931c42018-12-18 15:08:111110 video_sources_.resize(num_video_streams_);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591111 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
Danil Chapovalov908e22e2019-04-18 12:34:161112 std::unique_ptr<test::FrameGenerator> frame_generator;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591113 if (params_.screenshare[video_idx].enabled) {
Danil Chapovalov908e22e2019-04-18 12:34:161114 frame_generator = CreateFrameGenerator(video_idx);
1115 } else if (params_.video[video_idx].clip_path == "Generator") {
1116 frame_generator = test::FrameGenerator::CreateSquareGenerator(
1117 static_cast<int>(params_.video[video_idx].width),
1118 static_cast<int>(params_.video[video_idx].height), absl::nullopt,
1119 absl::nullopt);
1120 } else if (params_.video[video_idx].clip_path == "GeneratorI420A") {
1121 frame_generator = test::FrameGenerator::CreateSquareGenerator(
1122 static_cast<int>(params_.video[video_idx].width),
1123 static_cast<int>(params_.video[video_idx].height),
Sebastian Janssoned0febf2019-07-26 13:58:111124 test::FrameGenerator::OutputType::kI420A, absl::nullopt);
Danil Chapovalov908e22e2019-04-18 12:34:161125 } else if (params_.video[video_idx].clip_path == "GeneratorI010") {
1126 frame_generator = test::FrameGenerator::CreateSquareGenerator(
1127 static_cast<int>(params_.video[video_idx].width),
1128 static_cast<int>(params_.video[video_idx].height),
Sebastian Janssoned0febf2019-07-26 13:58:111129 test::FrameGenerator::OutputType::kI010, absl::nullopt);
Danil Chapovalov908e22e2019-04-18 12:34:161130 } else if (params_.video[video_idx].clip_path.empty()) {
1131 video_sources_[video_idx] = test::CreateVideoCapturer(
1132 params_.video[video_idx].width, params_.video[video_idx].height,
1133 params_.video[video_idx].fps,
1134 params_.video[video_idx].capture_device_index);
1135 if (video_sources_[video_idx]) {
1136 continue;
1137 } else {
1138 // Failed to get actual camera, use chroma generator as backup.
1139 frame_generator = test::FrameGenerator::CreateSquareGenerator(
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591140 static_cast<int>(params_.video[video_idx].width),
Danil Chapovalovb9b146c2018-06-15 10:28:071141 static_cast<int>(params_.video[video_idx].height), absl::nullopt,
Danil Chapovalov908e22e2019-04-18 12:34:161142 absl::nullopt);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591143 }
Danil Chapovalov908e22e2019-04-18 12:34:161144 } else {
1145 frame_generator = test::FrameGenerator::CreateFromYuvFile(
1146 {params_.video[video_idx].clip_path}, params_.video[video_idx].width,
1147 params_.video[video_idx].height, 1);
1148 ASSERT_TRUE(frame_generator) << "Could not create capturer for "
1149 << params_.video[video_idx].clip_path
1150 << ".yuv. Is this file present?";
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591151 }
Danil Chapovalov908e22e2019-04-18 12:34:161152 ASSERT_TRUE(frame_generator);
1153 auto frame_generator_capturer =
Mirko Bonadei317a1f02019-09-17 15:06:181154 std::make_unique<test::FrameGeneratorCapturer>(
Danil Chapovalov908e22e2019-04-18 12:34:161155 clock_, std::move(frame_generator), params_.video[video_idx].fps,
1156 *task_queue_factory_);
1157 EXPECT_TRUE(frame_generator_capturer->Init());
1158 video_sources_[video_idx] = std::move(frame_generator_capturer);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591159 }
ivica5d6a06c2015-09-17 12:30:241160}
1161
Christoffer Rodbro39a44b22018-08-07 15:07:241162void VideoQualityTest::StartAudioStreams() {
1163 audio_send_stream_->Start();
1164 for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_)
1165 audio_recv_stream->Start();
1166}
1167
Christoffer Rodbroc2a02882018-08-07 12:10:561168void VideoQualityTest::StartThumbnails() {
1169 for (VideoSendStream* send_stream : thumbnail_send_streams_)
1170 send_stream->Start();
1171 for (VideoReceiveStream* receive_stream : thumbnail_receive_streams_)
1172 receive_stream->Start();
Christoffer Rodbroc2a02882018-08-07 12:10:561173}
1174
1175void VideoQualityTest::StopThumbnails() {
Christoffer Rodbroc2a02882018-08-07 12:10:561176 for (VideoReceiveStream* receive_stream : thumbnail_receive_streams_)
1177 receive_stream->Stop();
1178 for (VideoSendStream* send_stream : thumbnail_send_streams_)
1179 send_stream->Stop();
1180}
1181
Christoffer Rodbrob4bb4eb2017-11-13 12:03:521182std::unique_ptr<test::LayerFilteringTransport>
1183VideoQualityTest::CreateSendTransport() {
Artem Titov8ea1e9d2018-10-04 12:46:311184 std::unique_ptr<NetworkBehaviorInterface> network_behavior = nullptr;
Artem Titove269cb42018-08-29 07:59:231185 if (injection_components_->sender_network == nullptr) {
Mirko Bonadei317a1f02019-09-17 15:06:181186 network_behavior = std::make_unique<SimulatedNetwork>(*params_.config);
Artem Titove269cb42018-08-29 07:59:231187 } else {
Artem Titov8ea1e9d2018-10-04 12:46:311188 network_behavior = std::move(injection_components_->sender_network);
Artem Titove269cb42018-08-29 07:59:231189 }
Mirko Bonadei317a1f02019-09-17 15:06:181190 return std::make_unique<test::LayerFilteringTransport>(
Artem Titov4e199e92018-08-20 11:30:391191 &task_queue_,
Mirko Bonadei317a1f02019-09-17 15:06:181192 std::make_unique<FakeNetworkPipe>(clock_, std::move(network_behavior)),
Artem Titov4e199e92018-08-20 11:30:391193 sender_call_.get(), kPayloadTypeVP8, kPayloadTypeVP9,
1194 params_.video[0].selected_tl, params_.ss[0].selected_sl,
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591195 payload_type_map_, kVideoSendSsrcs[0],
1196 static_cast<uint32_t>(kVideoSendSsrcs[0] + params_.ss[0].streams.size() -
1197 1));
Christoffer Rodbrob4bb4eb2017-11-13 12:03:521198}
1199
1200std::unique_ptr<test::DirectTransport>
1201VideoQualityTest::CreateReceiveTransport() {
Artem Titov8ea1e9d2018-10-04 12:46:311202 std::unique_ptr<NetworkBehaviorInterface> network_behavior = nullptr;
Artem Titove269cb42018-08-29 07:59:231203 if (injection_components_->receiver_network == nullptr) {
Mirko Bonadei317a1f02019-09-17 15:06:181204 network_behavior = std::make_unique<SimulatedNetwork>(*params_.config);
Artem Titove269cb42018-08-29 07:59:231205 } else {
Artem Titov8ea1e9d2018-10-04 12:46:311206 network_behavior = std::move(injection_components_->receiver_network);
Artem Titove269cb42018-08-29 07:59:231207 }
Mirko Bonadei317a1f02019-09-17 15:06:181208 return std::make_unique<test::DirectTransport>(
Artem Titovdd2eebe2018-08-20 11:27:451209 &task_queue_,
Mirko Bonadei317a1f02019-09-17 15:06:181210 std::make_unique<FakeNetworkPipe>(clock_, std::move(network_behavior)),
Artem Titovdd2eebe2018-08-20 11:27:451211 receiver_call_.get(), payload_type_map_);
Christoffer Rodbrob4bb4eb2017-11-13 12:03:521212}
1213
sprang7a975f72015-10-12 13:33:211214void VideoQualityTest::RunWithAnalyzer(const Params& params) {
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591215 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 11:02:521216 std::unique_ptr<test::LayerFilteringTransport> send_transport;
1217 std::unique_ptr<test::DirectTransport> recv_transport;
1218 FILE* graph_data_output_file = nullptr;
eladalon413ee9a2017-08-22 11:02:521219
sprangce4aef12015-11-02 15:23:201220 params_ = params;
ivica5d6a06c2015-09-17 12:30:241221 // TODO(ivica): Merge with RunWithRenderer and use a flag / argument to
1222 // differentiate between the analyzer and the renderer case.
Artem Titove269cb42018-08-29 07:59:231223 CheckParamsAndInjectionComponents();
ivica5d6a06c2015-09-17 12:30:241224
sprangce4aef12015-11-02 15:23:201225 if (!params_.analyzer.graph_data_output_filename.empty()) {
ivica5d6a06c2015-09-17 12:30:241226 graph_data_output_file =
sprangce4aef12015-11-02 15:23:201227 fopen(params_.analyzer.graph_data_output_filename.c_str(), "w");
Peter Boström74f6e9e2016-04-04 15:56:101228 RTC_CHECK(graph_data_output_file)
sprangce4aef12015-11-02 15:23:201229 << "Can't open the file " << params_.analyzer.graph_data_output_filename
1230 << "!";
ivica87f83a92015-10-08 12:13:321231 }
sprang7a975f72015-10-12 13:33:211232
ilnik98436952017-07-13 07:47:031233 if (!params.logging.rtc_event_log_name.empty()) {
Danil Chapovalov304ea5f2019-04-11 13:18:181234 send_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
1235 RtcEventLog::EncodingType::Legacy);
1236 recv_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
1237 RtcEventLog::EncodingType::Legacy);
Ilya Nikolaevskiya4259f62017-12-05 12:19:451238 std::unique_ptr<RtcEventLogOutputFile> send_output(
Mirko Bonadei317a1f02019-09-17 15:06:181239 std::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 12:19:451240 params.logging.rtc_event_log_name + "_send",
1241 RtcEventLog::kUnlimitedOutput));
1242 std::unique_ptr<RtcEventLogOutputFile> recv_output(
Mirko Bonadei317a1f02019-09-17 15:06:181243 std::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 12:19:451244 params.logging.rtc_event_log_name + "_recv",
1245 RtcEventLog::kUnlimitedOutput));
1246 bool event_log_started =
1247 send_event_log_->StartLogging(std::move(send_output),
1248 RtcEventLog::kImmediateOutput) &&
1249 recv_event_log_->StartLogging(std::move(recv_output),
1250 RtcEventLog::kImmediateOutput);
ilnik98436952017-07-13 07:47:031251 RTC_DCHECK(event_log_started);
Ilya Nikolaevskiya4259f62017-12-05 12:19:451252 } else {
Mirko Bonadei317a1f02019-09-17 15:06:181253 send_event_log_ = std::make_unique<RtcEventLogNull>();
1254 recv_event_log_ = std::make_unique<RtcEventLogNull>();
ilnik98436952017-07-13 07:47:031255 }
1256
Artem Titovff7730d2019-04-02 11:46:531257 task_queue_.SendTask([this, &params, &send_transport, &recv_transport]() {
1258 Call::Config send_call_config(send_event_log_.get());
1259 Call::Config recv_call_config(recv_event_log_.get());
1260 send_call_config.bitrate_config = params.call.call_bitrate_config;
1261 recv_call_config.bitrate_config = params.call.call_bitrate_config;
Christoffer Rodbro39a44b22018-08-07 15:07:241262 if (params_.audio.enabled)
Benjamin Wright1f4173e2019-03-14 00:59:321263 InitializeAudioDevice(&send_call_config, &recv_call_config,
1264 params_.audio.use_real_adm);
Christoffer Rodbroc2a02882018-08-07 12:10:561265
Ilya Nikolaevskiya4259f62017-12-05 12:19:451266 CreateCalls(send_call_config, recv_call_config);
1267 send_transport = CreateSendTransport();
1268 recv_transport = CreateReceiveTransport();
1269 });
stefanf116bd02015-10-27 15:29:421270
sprangce4aef12015-11-02 15:23:201271 std::string graph_title = params_.analyzer.graph_title;
1272 if (graph_title.empty())
1273 graph_title = VideoQualityTest::GenerateGraphTitle();
sprangc1b57a12017-02-28 16:50:471274 bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
Mirko Bonadei317a1f02019-09-17 15:06:181275 analyzer_ = std::make_unique<VideoAnalyzer>(
eladalon413ee9a2017-08-22 11:02:521276 send_transport.get(), params_.analyzer.test_label,
ilnik2a8c2f52017-02-15 10:23:281277 params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
ilnik9ae0d762017-02-15 08:53:121278 is_quick_test_enabled
1279 ? kFramesSentInQuickTest
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591280 : params_.analyzer.test_durations_secs * params_.video[0].fps,
sprangce4aef12015-11-02 15:23:201281 graph_data_output_file, graph_title,
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591282 kVideoSendSsrcs[params_.ss[0].selected_stream],
1283 kSendRtxSsrcs[params_.ss[0].selected_stream],
1284 static_cast<size_t>(params_.ss[0].selected_stream),
1285 params.ss[0].selected_sl, params_.video[0].selected_tl,
Artem Titovff7730d2019-04-02 11:46:531286 is_quick_test_enabled, clock_, params_.logging.rtp_dump_name,
1287 &task_queue_);
ivica5d6a06c2015-09-17 12:30:241288
eladalon413ee9a2017-08-22 11:02:521289 task_queue_.SendTask([&]() {
Niels Möller88be9722018-10-10 08:58:521290 analyzer_->SetCall(sender_call_.get());
1291 analyzer_->SetReceiver(receiver_call_->Receiver());
1292 send_transport->SetReceiver(analyzer_.get());
eladalon413ee9a2017-08-22 11:02:521293 recv_transport->SetReceiver(sender_call_->Receiver());
ivica5d6a06c2015-09-17 12:30:241294
Niels Möller88be9722018-10-10 08:58:521295 SetupVideo(analyzer_.get(), recv_transport.get());
1296 SetupThumbnails(analyzer_.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591297 video_receive_configs_[params_.ss[0].selected_stream].renderer =
Niels Möller88be9722018-10-10 08:58:521298 analyzer_.get();
kthelgason2bc68642017-02-07 15:02:221299
eladalon413ee9a2017-08-22 11:02:521300 CreateFlexfecStreams();
1301 CreateVideoStreams();
Niels Möller88be9722018-10-10 08:58:521302 analyzer_->SetSendStream(video_send_streams_[0]);
Ilya Nikolaevskiyd47d3eb2019-01-21 15:27:171303 analyzer_->SetReceiveStream(
1304 video_receive_streams_[params_.ss[0].selected_stream]);
ivica5d6a06c2015-09-17 12:30:241305
Niels Möller88be9722018-10-10 08:58:521306 GetVideoSendStream()->SetSource(analyzer_->OutputInterface(),
Sebastian Jansson3bd2c792018-07-13 11:29:031307 degradation_preference_);
eladalon413ee9a2017-08-22 11:02:521308 SetupThumbnailCapturers(params_.call.num_thumbnails);
1309 for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
1310 thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
1311 degradation_preference_);
1312 }
ilnika014cc52017-03-07 12:21:041313
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591314 CreateCapturers();
ivicac1cc8542015-10-08 10:44:061315
Stefan Holmer1f7a0082019-01-11 14:39:081316 analyzer_->SetSource(video_sources_[0].get(), true);
ilnika014cc52017-03-07 12:21:041317
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591318 for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) {
Niels Möller1c931c42018-12-18 15:08:111319 video_send_streams_[video_idx]->SetSource(video_sources_[video_idx].get(),
1320 degradation_preference_);
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591321 }
1322
Christoffer Rodbroc2a02882018-08-07 12:10:561323 if (params_.audio.enabled) {
1324 SetupAudio(send_transport.get());
Christoffer Rodbro39a44b22018-08-07 15:07:241325 StartAudioStreams();
Niels Möller88be9722018-10-10 08:58:521326 analyzer_->SetAudioReceiveStream(audio_receive_streams_[0]);
Christoffer Rodbroc2a02882018-08-07 12:10:561327 }
Christoffer Rodbro39a44b22018-08-07 15:07:241328 StartVideoStreams();
1329 StartThumbnails();
Niels Möller88be9722018-10-10 08:58:521330 analyzer_->StartMeasuringCpuProcessTime();
eladalon413ee9a2017-08-22 11:02:521331 });
ivica5d6a06c2015-09-17 12:30:241332
Niels Möller88be9722018-10-10 08:58:521333 analyzer_->Wait();
ivica5d6a06c2015-09-17 12:30:241334
eladalon413ee9a2017-08-22 11:02:521335 task_queue_.SendTask([&]() {
Christoffer Rodbroc2a02882018-08-07 12:10:561336 StopThumbnails();
1337 Stop();
ivica5d6a06c2015-09-17 12:30:241338
eladalon413ee9a2017-08-22 11:02:521339 DestroyStreams();
1340 DestroyThumbnailStreams();
ivica5d6a06c2015-09-17 12:30:241341
eladalon413ee9a2017-08-22 11:02:521342 if (graph_data_output_file)
1343 fclose(graph_data_output_file);
1344
Niels Möller1c931c42018-12-18 15:08:111345 video_sources_.clear();
eladalon413ee9a2017-08-22 11:02:521346 send_transport.reset();
1347 recv_transport.reset();
1348
1349 DestroyCalls();
1350 });
Niels Möller88be9722018-10-10 08:58:521351 analyzer_ = nullptr;
ivica5d6a06c2015-09-17 12:30:241352}
1353
henrika255750b2018-08-27 14:13:371354rtc::scoped_refptr<AudioDeviceModule> VideoQualityTest::CreateAudioDevice() {
1355#ifdef WEBRTC_WIN
Benjamin Wright1f4173e2019-03-14 00:59:321356 RTC_LOG(INFO) << "Using latest version of ADM on Windows";
1357 // We must initialize the COM library on a thread before we calling any of
1358 // the library functions. All COM functions in the ADM will return
1359 // CO_E_NOTINITIALIZED otherwise. The legacy ADM for Windows used internal
1360 // COM initialization but the new ADM requires COM to be initialized
1361 // externally.
Mirko Bonadei317a1f02019-09-17 15:06:181362 com_initializer_ = std::make_unique<webrtc_win::ScopedCOMInitializer>(
Benjamin Wright1f4173e2019-03-14 00:59:321363 webrtc_win::ScopedCOMInitializer::kMTA);
1364 RTC_CHECK(com_initializer_->Succeeded());
1365 RTC_CHECK(webrtc_win::core_audio_utility::IsSupported());
1366 RTC_CHECK(webrtc_win::core_audio_utility::IsMMCSSSupported());
Danil Chapovalov1c41be62019-04-01 07:16:121367 return CreateWindowsCoreAudioAudioDeviceModule(task_queue_factory_.get());
henrika255750b2018-08-27 14:13:371368#else
Benjamin Wright1f4173e2019-03-14 00:59:321369 // Use legacy factory method on all platforms except Windows.
Danil Chapovalov1c41be62019-04-01 07:16:121370 return AudioDeviceModule::Create(AudioDeviceModule::kPlatformDefaultAudio,
1371 task_queue_factory_.get());
henrika255750b2018-08-27 14:13:371372#endif
1373}
1374
Christoffer Rodbroc2a02882018-08-07 12:10:561375void VideoQualityTest::InitializeAudioDevice(Call::Config* send_call_config,
henrika255750b2018-08-27 14:13:371376 Call::Config* recv_call_config,
1377 bool use_real_adm) {
1378 rtc::scoped_refptr<AudioDeviceModule> audio_device;
1379 if (use_real_adm) {
1380 // Run test with real ADM (using default audio devices) if user has
1381 // explicitly set the --audio and --use_real_adm command-line flags.
1382 audio_device = CreateAudioDevice();
1383 } else {
1384 // By default, create a test ADM which fakes audio.
Danil Chapovalov08fa9532019-06-12 11:49:171385 audio_device = TestAudioDeviceModule::Create(
1386 task_queue_factory_.get(),
henrika255750b2018-08-27 14:13:371387 TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
1388 TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
1389 }
1390 RTC_CHECK(audio_device);
Christoffer Rodbroc2a02882018-08-07 12:10:561391
1392 AudioState::Config audio_state_config;
1393 audio_state_config.audio_mixer = AudioMixerImpl::Create();
1394 audio_state_config.audio_processing = AudioProcessingBuilder().Create();
henrika255750b2018-08-27 14:13:371395 audio_state_config.audio_device_module = audio_device;
Christoffer Rodbroc2a02882018-08-07 12:10:561396 send_call_config->audio_state = AudioState::Create(audio_state_config);
Christoffer Rodbroc2a02882018-08-07 12:10:561397 recv_call_config->audio_state = AudioState::Create(audio_state_config);
henrika255750b2018-08-27 14:13:371398 if (use_real_adm) {
1399 // The real ADM requires extra initialization: setting default devices,
1400 // setting up number of channels etc. Helper class also calls
1401 // AudioDeviceModule::Init().
1402 webrtc::adm_helpers::Init(audio_device.get());
1403 } else {
1404 audio_device->Init();
1405 }
1406 // Always initialize the ADM before injecting a valid audio transport.
1407 RTC_CHECK(audio_device->RegisterAudioCallback(
Benjamin Wright1f4173e2019-03-14 00:59:321408 send_call_config->audio_state->audio_transport()) == 0);
Christoffer Rodbroc2a02882018-08-07 12:10:561409}
1410
Sebastian Jansson3bd2c792018-07-13 11:29:031411void VideoQualityTest::SetupAudio(Transport* transport) {
Niels Möller7d76a312018-10-26 10:57:071412 AudioSendStream::Config audio_send_config(transport,
Anton Sukhanov4f08faa2019-05-21 18:12:571413 webrtc::MediaTransportConfig());
Sebastian Jansson3bd2c792018-07-13 11:29:031414 audio_send_config.rtp.ssrc = kAudioSendSsrc;
minyuea27172d2016-11-01 12:59:291415
1416 // Add extension to enable audio send side BWE, and allow audio bit rate
1417 // adaptation.
Sebastian Jansson3bd2c792018-07-13 11:29:031418 audio_send_config.rtp.extensions.clear();
1419 audio_send_config.send_codec_spec = AudioSendStream::Config::SendCodecSpec(
Oskar Sundbom8e07c132018-01-08 15:45:421420 kAudioSendPayloadType,
Yves Gerey665174f2018-06-19 13:03:051421 {"OPUS",
1422 48000,
1423 2,
1424 {{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}});
minyuea27172d2016-11-01 12:59:291425
Sebastian Jansson3bd2c792018-07-13 11:29:031426 if (params_.call.send_side_bwe) {
1427 audio_send_config.rtp.extensions.push_back(
1428 webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri,
Elad Alond8d32482019-02-18 22:45:571429 kTransportSequenceNumberExtensionId));
Sebastian Jansson3bd2c792018-07-13 11:29:031430 audio_send_config.min_bitrate_bps = kOpusMinBitrateBps;
1431 audio_send_config.max_bitrate_bps = kOpusBitrateFbBps;
1432 audio_send_config.send_codec_spec->transport_cc_enabled = true;
Minyue Li455d27c2019-01-07 12:14:301433 // Only allow ANA when send-side BWE is enabled.
1434 audio_send_config.audio_network_adaptor_config = params_.audio.ana_config;
Sebastian Jansson3bd2c792018-07-13 11:29:031435 }
1436 audio_send_config.encoder_factory = audio_encoder_factory_;
1437 SetAudioConfig(audio_send_config);
1438
Christoffer Rodbroc2a02882018-08-07 12:10:561439 std::string sync_group;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591440 if (params_.video[0].enabled && params_.audio.sync_video)
Sebastian Jansson3bd2c792018-07-13 11:29:031441 sync_group = kSyncGroup;
minyuea27172d2016-11-01 12:59:291442
Sebastian Jansson3bd2c792018-07-13 11:29:031443 CreateMatchingAudioConfigs(transport, sync_group);
1444 CreateAudioStreams();
minyuea27172d2016-11-01 12:59:291445}
1446
minyue73208662016-08-18 13:28:551447void VideoQualityTest::RunWithRenderers(const Params& params) {
henrika255750b2018-08-27 14:13:371448 RTC_LOG(INFO) << __FUNCTION__;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591449 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 11:02:521450 std::unique_ptr<test::LayerFilteringTransport> send_transport;
1451 std::unique_ptr<test::DirectTransport> recv_transport;
minyuea27172d2016-11-01 12:59:291452 std::unique_ptr<test::VideoRenderer> local_preview;
eladalon413ee9a2017-08-22 11:02:521453 std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
Ilya Nikolaevskiy42e7d9c2018-11-02 12:14:371454
1455 if (!params.logging.rtc_event_log_name.empty()) {
Danil Chapovalov304ea5f2019-04-11 13:18:181456 send_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
1457 RtcEventLog::EncodingType::Legacy);
1458 recv_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
1459 RtcEventLog::EncodingType::Legacy);
Ilya Nikolaevskiy42e7d9c2018-11-02 12:14:371460 std::unique_ptr<RtcEventLogOutputFile> send_output(
Mirko Bonadei317a1f02019-09-17 15:06:181461 std::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiy42e7d9c2018-11-02 12:14:371462 params.logging.rtc_event_log_name + "_send",
1463 RtcEventLog::kUnlimitedOutput));
1464 std::unique_ptr<RtcEventLogOutputFile> recv_output(
Mirko Bonadei317a1f02019-09-17 15:06:181465 std::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiy42e7d9c2018-11-02 12:14:371466 params.logging.rtc_event_log_name + "_recv",
1467 RtcEventLog::kUnlimitedOutput));
1468 bool event_log_started =
1469 send_event_log_->StartLogging(std::move(send_output),
1470 /*output_period_ms=*/5000) &&
1471 recv_event_log_->StartLogging(std::move(recv_output),
1472 /*output_period_ms=*/5000);
1473 RTC_DCHECK(event_log_started);
1474 } else {
Mirko Bonadei317a1f02019-09-17 15:06:181475 send_event_log_ = std::make_unique<RtcEventLogNull>();
1476 recv_event_log_ = std::make_unique<RtcEventLogNull>();
Ilya Nikolaevskiy42e7d9c2018-11-02 12:14:371477 }
minyue73208662016-08-18 13:28:551478
eladalon413ee9a2017-08-22 11:02:521479 task_queue_.SendTask([&]() {
1480 params_ = params;
Artem Titove269cb42018-08-29 07:59:231481 CheckParamsAndInjectionComponents();
palmkviste75f2042016-09-28 13:19:481482
eladalon413ee9a2017-08-22 11:02:521483 // TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
1484 // match the full stack tests.
Ilya Nikolaevskiy42e7d9c2018-11-02 12:14:371485 Call::Config send_call_config(send_event_log_.get());
Christoffer Rodbro39a44b22018-08-07 15:07:241486 send_call_config.bitrate_config = params_.call.call_bitrate_config;
Ilya Nikolaevskiy42e7d9c2018-11-02 12:14:371487 Call::Config recv_call_config(recv_event_log_.get());
ivica5d6a06c2015-09-17 12:30:241488
Christoffer Rodbro39a44b22018-08-07 15:07:241489 if (params_.audio.enabled)
Benjamin Wright1f4173e2019-03-14 00:59:321490 InitializeAudioDevice(&send_call_config, &recv_call_config,
1491 params_.audio.use_real_adm);
minyue73208662016-08-18 13:28:551492
Christoffer Rodbro39a44b22018-08-07 15:07:241493 CreateCalls(send_call_config, recv_call_config);
eladalon413ee9a2017-08-22 11:02:521494
1495 // TODO(minyue): consider if this is a good transport even for audio only
1496 // calls.
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591497 send_transport = CreateSendTransport();
eladalon413ee9a2017-08-22 11:02:521498
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591499 recv_transport = CreateReceiveTransport();
eladalon413ee9a2017-08-22 11:02:521500
1501 // TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
1502 // least share as much code as possible. That way this test would also match
1503 // the full stack tests better.
1504 send_transport->SetReceiver(receiver_call_->Receiver());
1505 recv_transport->SetReceiver(sender_call_->Receiver());
1506
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591507 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 11:02:521508 // Create video renderers.
eladalon413ee9a2017-08-22 11:02:521509 SetupVideo(send_transport.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591510 size_t num_streams_processed = 0;
1511 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1512 const size_t selected_stream_id = params_.ss[video_idx].selected_stream;
1513 const size_t num_streams = params_.ss[video_idx].streams.size();
1514 if (selected_stream_id == num_streams) {
1515 for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
Jonas Olsson366a50c2018-09-06 11:41:301516 rtc::StringBuilder oss;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591517 oss << "Loopback Video #" << video_idx << " - Stream #"
1518 << static_cast<int>(stream_id);
1519 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1520 oss.str().c_str(),
1521 params_.ss[video_idx].streams[stream_id].width,
1522 params_.ss[video_idx].streams[stream_id].height));
1523 video_receive_configs_[stream_id + num_streams_processed].renderer =
1524 loopback_renderers.back().get();
1525 if (params_.audio.enabled && params_.audio.sync_video)
1526 video_receive_configs_[stream_id + num_streams_processed]
1527 .sync_group = kSyncGroup;
1528 }
1529 } else {
Jonas Olsson366a50c2018-09-06 11:41:301530 rtc::StringBuilder oss;
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591531 oss << "Loopback Video #" << video_idx;
1532 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1533 oss.str().c_str(),
1534 params_.ss[video_idx].streams[selected_stream_id].width,
1535 params_.ss[video_idx].streams[selected_stream_id].height));
1536 video_receive_configs_[selected_stream_id + num_streams_processed]
1537 .renderer = loopback_renderers.back().get();
eladalon413ee9a2017-08-22 11:02:521538 if (params_.audio.enabled && params_.audio.sync_video)
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591539 video_receive_configs_[num_streams_processed + selected_stream_id]
1540 .sync_group = kSyncGroup;
eladalon413ee9a2017-08-22 11:02:521541 }
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591542 num_streams_processed += num_streams;
eladalon413ee9a2017-08-22 11:02:521543 }
eladalon413ee9a2017-08-22 11:02:521544 CreateFlexfecStreams();
1545 CreateVideoStreams();
1546
Ilya Nikolaevskiy255d1cd2017-12-21 17:02:591547 CreateCapturers();
Niels Möller412d1852019-01-02 08:42:541548 if (params_.video[0].enabled) {
1549 // Create local preview
1550 local_preview.reset(test::VideoRenderer::Create(
1551 "Local Preview", params_.video[0].width, params_.video[0].height));
1552
1553 video_sources_[0]->AddOrUpdateSink(local_preview.get(),
1554 rtc::VideoSinkWants());
1555 }
Sebastian Jansson3bd2c792018-07-13 11:29:031556 ConnectVideoSourcesToStreams();
eladalon413ee9a2017-08-22 11:02:521557 }
1558
1559 if (params_.audio.enabled) {
Sebastian Jansson3bd2c792018-07-13 11:29:031560 SetupAudio(send_transport.get());
eladalon413ee9a2017-08-22 11:02:521561 }
1562
Sebastian Jansson3bd2c792018-07-13 11:29:031563 Start();
eladalon413ee9a2017-08-22 11:02:521564 });
minyue73208662016-08-18 13:28:551565
Danail Kirov6fcf6ca2018-10-25 17:45:471566 test::PressEnterToContinue(task_queue_);
ivica5d6a06c2015-09-17 12:30:241567
eladalon413ee9a2017-08-22 11:02:521568 task_queue_.SendTask([&]() {
Sebastian Jansson3bd2c792018-07-13 11:29:031569 Stop();
1570 DestroyStreams();
minyue73208662016-08-18 13:28:551571
Niels Möller1c931c42018-12-18 15:08:111572 video_sources_.clear();
eladalon413ee9a2017-08-22 11:02:521573 send_transport.reset();
1574 recv_transport.reset();
sprang1168fd42017-06-21 16:00:171575
eladalon413ee9a2017-08-22 11:02:521576 local_preview.reset();
1577 loopback_renderers.clear();
1578
1579 DestroyCalls();
1580 });
ivica5d6a06c2015-09-17 12:30:241581}
1582
ivica5d6a06c2015-09-17 12:30:241583} // namespace webrtc