blob: d60d081c4cec2c0e9a4b86d2e554555c20c81601 [file] [log] [blame]
ivica5d6a06c2015-09-17 05:30:24 -07001/*
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 06:47:31 +020010#include "video/video_quality_test.h"
perkj9fdbda62016-09-15 09:19:20 -070011
perkja49cbd32016-09-16 07:53:41 -070012#include <stdio.h>
ivica5d6a06c2015-09-17 05:30:24 -070013#include <algorithm>
14#include <deque>
15#include <map>
sprangce4aef12015-11-02 07:23:20 -080016#include <sstream>
mflodmand1590b22015-12-09 07:07:59 -080017#include <string>
ivica5d6a06c2015-09-17 05:30:24 -070018#include <vector>
19
Elad Alon83ccca12017-10-04 13:18:26 +020020#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
Magnus Jedvert46a27652017-11-13 14:10:02 +010021#include "media/engine/internalencoderfactory.h"
Niels Möller19a68d42018-04-13 13:37:52 +020022#include "media/engine/vp8_encoder_simulcast_proxy.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "media/engine/webrtcvideoengine.h"
24#include "modules/audio_mixer/audio_mixer_impl.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/video_coding/codecs/h264/include/h264.h"
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080026#include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h"
Niels Möller4db138e2018-04-19 09:04:13 +020027#include "modules/video_coding/codecs/vp8/include/vp8.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "modules/video_coding/codecs/vp9/include/vp9.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "test/run_loop.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "test/testsupport/fileutils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "test/video_renderer.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020032#include "video/video_analyzer.h"
ilnikee42d192017-08-22 07:16:20 -070033
minyue73208662016-08-18 06:28:55 -070034namespace {
minyue73208662016-08-18 06:28:55 -070035constexpr char kSyncGroup[] = "av_sync";
minyue10cbb462016-11-07 09:29:22 -080036constexpr int kOpusMinBitrateBps = 6000;
37constexpr int kOpusBitrateFbBps = 32000;
ilnik9ae0d762017-02-15 00:53:12 -080038constexpr int kFramesSentInQuickTest = 1;
ilnika014cc52017-03-07 04:21:04 -080039constexpr uint32_t kThumbnailSendSsrcStart = 0xE0000;
40constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000;
minyue73208662016-08-18 06:28:55 -070041
sprang1168fd42017-06-21 09:00:17 -070042constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax;
43
perkjfa10b552016-10-02 23:45:26 -070044class VideoStreamFactory
45 : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface {
46 public:
47 explicit VideoStreamFactory(const std::vector<webrtc::VideoStream>& streams)
48 : streams_(streams) {}
49
50 private:
51 std::vector<webrtc::VideoStream> CreateEncoderStreams(
52 int width,
53 int height,
54 const webrtc::VideoEncoderConfig& encoder_config) override {
mflodmand79f97b2016-12-15 07:24:33 -080055 // The highest layer must match the incoming resolution.
56 std::vector<webrtc::VideoStream> streams = streams_;
57 streams[streams_.size() - 1].height = height;
58 streams[streams_.size() - 1].width = width;
Seth Hampson24722b32017-12-22 09:36:42 -080059
60 streams[0].bitrate_priority = encoder_config.bitrate_priority;
mflodmand79f97b2016-12-15 07:24:33 -080061 return streams;
perkjfa10b552016-10-02 23:45:26 -070062 }
63
64 std::vector<webrtc::VideoStream> streams_;
65};
minyue73208662016-08-18 06:28:55 -070066} // namespace
ivica5d6a06c2015-09-17 05:30:24 -070067
68namespace webrtc {
69
Niels Möller4db138e2018-04-19 09:04:13 +020070// Not used by these tests.
71std::vector<SdpVideoFormat>
72VideoQualityTest::TestVideoEncoderFactory::GetSupportedFormats() const {
73 RTC_NOTREACHED();
74 return {};
75}
76
77VideoEncoderFactory::CodecInfo
78VideoQualityTest::TestVideoEncoderFactory::QueryVideoEncoder(
79 const SdpVideoFormat& format) const {
80 CodecInfo codec_info;
81 codec_info.is_hardware_accelerated = false;
82 codec_info.has_internal_source = false;
83 return codec_info;
84}
85
86std::unique_ptr<VideoEncoder>
87VideoQualityTest::TestVideoEncoderFactory::CreateVideoEncoder(
88 const SdpVideoFormat& format) {
89 if (format.name == "VP8") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020090 return absl::make_unique<VP8EncoderSimulcastProxy>(
91 &internal_encoder_factory_, format);
Niels Möller4db138e2018-04-19 09:04:13 +020092 } else if (format.name == "multiplex") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020093 return absl::make_unique<MultiplexEncoderAdapter>(
Niels Möller4db138e2018-04-19 09:04:13 +020094 &internal_encoder_factory_, SdpVideoFormat(cricket::kVp9CodecName));
Niels Möller4db138e2018-04-19 09:04:13 +020095 }
Emircan Uysalerfc9c4e82018-07-10 15:14:04 -070096 return internal_encoder_factory_.CreateVideoEncoder(format);
Niels Möller4db138e2018-04-19 09:04:13 +020097}
98
Patrik Höglundb6b29e02018-06-21 16:58:01 +020099VideoQualityTest::VideoQualityTest(
100 std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory)
minyue20c84cc2017-04-10 16:57:57 -0700101 : clock_(Clock::GetRealTimeClock()), receive_logs_(0), send_logs_(0) {
102 payload_type_map_ = test::CallTest::payload_type_map_;
103 RTC_DCHECK(payload_type_map_.find(kPayloadTypeH264) ==
104 payload_type_map_.end());
105 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP8) ==
106 payload_type_map_.end());
107 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP9) ==
108 payload_type_map_.end());
109 payload_type_map_[kPayloadTypeH264] = webrtc::MediaType::VIDEO;
110 payload_type_map_[kPayloadTypeVP8] = webrtc::MediaType::VIDEO;
111 payload_type_map_[kPayloadTypeVP9] = webrtc::MediaType::VIDEO;
ivica5d6a06c2015-09-17 05:30:24 -0700112
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100113 fec_controller_factory_ = std::move(fec_controller_factory);
Ying Wang3b790f32018-01-19 17:58:57 +0100114}
115
minyue626bc952016-10-31 05:47:02 -0700116VideoQualityTest::Params::Params()
Sebastian Janssonfc8d26b2018-02-21 09:52:06 +0100117 : call({false, BitrateConstraints(), 0}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100118 video{{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200119 false, false, ""},
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100120 {false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200121 false, false, ""}},
minyue4c8b9422017-03-21 04:11:43 -0700122 audio({false, false, false}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100123 screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
minyue626bc952016-10-31 05:47:02 -0700124 analyzer({"", 0.0, 0.0, 0, "", ""}),
125 pipe(),
Sergey Silkin57027362018-05-15 09:12:05 +0200126 ss{{std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
127 std::vector<SpatialLayer>()},
128 {std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
129 std::vector<SpatialLayer>()}},
ilnik98436952017-07-13 00:47:03 -0700130 logging({false, "", "", ""}) {}
minyue626bc952016-10-31 05:47:02 -0700131
132VideoQualityTest::Params::~Params() = default;
133
ivica5d6a06c2015-09-17 05:30:24 -0700134void VideoQualityTest::TestBody() {}
135
sprangce4aef12015-11-02 07:23:20 -0800136std::string VideoQualityTest::GenerateGraphTitle() const {
137 std::stringstream ss;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100138 ss << params_.video[0].codec;
139 ss << " (" << params_.video[0].target_bitrate_bps / 1000 << "kbps";
140 ss << ", " << params_.video[0].fps << " FPS";
141 if (params_.screenshare[0].scroll_duration)
142 ss << ", " << params_.screenshare[0].scroll_duration << "s scroll";
143 if (params_.ss[0].streams.size() > 1)
144 ss << ", Stream #" << params_.ss[0].selected_stream;
145 if (params_.ss[0].num_spatial_layers > 1)
146 ss << ", Layer #" << params_.ss[0].selected_sl;
sprangce4aef12015-11-02 07:23:20 -0800147 ss << ")";
148 return ss.str();
149}
150
151void VideoQualityTest::CheckParams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100152 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
153 // Iterate over primary and secondary video streams.
154 if (!params_.video[video_idx].enabled)
155 return;
156 // Add a default stream in none specified.
157 if (params_.ss[video_idx].streams.empty())
158 params_.ss[video_idx].streams.push_back(
159 VideoQualityTest::DefaultVideoStream(params_, video_idx));
160 if (params_.ss[video_idx].num_spatial_layers == 0)
161 params_.ss[video_idx].num_spatial_layers = 1;
sprangce4aef12015-11-02 07:23:20 -0800162
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100163 if (params_.pipe.loss_percent != 0 ||
164 params_.pipe.queue_length_packets != 0) {
165 // Since LayerFilteringTransport changes the sequence numbers, we can't
166 // use that feature with pack loss, since the NACK request would end up
167 // retransmitting the wrong packets.
168 RTC_CHECK(params_.ss[video_idx].selected_sl == -1 ||
169 params_.ss[video_idx].selected_sl ==
170 params_.ss[video_idx].num_spatial_layers - 1);
171 RTC_CHECK(params_.video[video_idx].selected_tl == -1 ||
172 params_.video[video_idx].selected_tl ==
173 params_.video[video_idx].num_temporal_layers - 1);
174 }
sprangce4aef12015-11-02 07:23:20 -0800175
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100176 // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as
177 // it does in some parts of the code?
178 RTC_CHECK_GE(params_.video[video_idx].max_bitrate_bps,
179 params_.video[video_idx].target_bitrate_bps);
180 RTC_CHECK_GE(params_.video[video_idx].target_bitrate_bps,
181 params_.video[video_idx].min_bitrate_bps);
182 RTC_CHECK_LT(params_.video[video_idx].selected_tl,
183 params_.video[video_idx].num_temporal_layers);
184 RTC_CHECK_LE(params_.ss[video_idx].selected_stream,
185 params_.ss[video_idx].streams.size());
186 for (const VideoStream& stream : params_.ss[video_idx].streams) {
187 RTC_CHECK_GE(stream.min_bitrate_bps, 0);
188 RTC_CHECK_GE(stream.target_bitrate_bps, stream.min_bitrate_bps);
189 RTC_CHECK_GE(stream.max_bitrate_bps, stream.target_bitrate_bps);
190 }
191 // TODO(ivica): Should we check if the sum of all streams/layers is equal to
192 // the total bitrate? We anyway have to update them in the case bitrate
193 // estimator changes the total bitrates.
194 RTC_CHECK_GE(params_.ss[video_idx].num_spatial_layers, 1);
195 RTC_CHECK_LE(params_.ss[video_idx].selected_sl,
196 params_.ss[video_idx].num_spatial_layers);
197 RTC_CHECK(
198 params_.ss[video_idx].spatial_layers.empty() ||
199 params_.ss[video_idx].spatial_layers.size() ==
200 static_cast<size_t>(params_.ss[video_idx].num_spatial_layers));
201 if (params_.video[video_idx].codec == "VP8") {
202 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
203 } else if (params_.video[video_idx].codec == "VP9") {
204 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 1);
205 }
206 RTC_CHECK_GE(params_.call.num_thumbnails, 0);
207 if (params_.call.num_thumbnails > 0) {
208 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
209 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 3);
210 RTC_CHECK_EQ(params_.video[video_idx].num_temporal_layers, 3);
211 RTC_CHECK_EQ(params_.video[video_idx].codec, "VP8");
212 }
213 // Dual streams with FEC not supported in tests yet.
214 RTC_CHECK(!params_.video[video_idx].flexfec || num_video_streams_ == 1);
215 RTC_CHECK(!params_.video[video_idx].ulpfec || num_video_streams_ == 1);
ilnika014cc52017-03-07 04:21:04 -0800216 }
sprangce4aef12015-11-02 07:23:20 -0800217}
218
219// Static.
220std::vector<int> VideoQualityTest::ParseCSV(const std::string& str) {
221 // Parse comma separated nonnegative integers, where some elements may be
222 // empty. The empty values are replaced with -1.
223 // E.g. "10,-20,,30,40" --> {10, 20, -1, 30,40}
224 // E.g. ",,10,,20," --> {-1, -1, 10, -1, 20, -1}
225 std::vector<int> result;
226 if (str.empty())
227 return result;
228
229 const char* p = str.c_str();
230 int value = -1;
231 int pos;
232 while (*p) {
233 if (*p == ',') {
234 result.push_back(value);
235 value = -1;
236 ++p;
237 continue;
238 }
239 RTC_CHECK_EQ(sscanf(p, "%d%n", &value, &pos), 1)
240 << "Unexpected non-number value.";
241 p += pos;
242 }
243 result.push_back(value);
244 return result;
245}
246
247// Static.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100248VideoStream VideoQualityTest::DefaultVideoStream(const Params& params,
249 size_t video_idx) {
sprangce4aef12015-11-02 07:23:20 -0800250 VideoStream stream;
Danil Chapovalov350531e2018-06-08 11:04:04 +0000251 stream.width = params.video[video_idx].width;
252 stream.height = params.video[video_idx].height;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100253 stream.max_framerate = params.video[video_idx].fps;
254 stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps;
255 stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
256 stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
sprang1168fd42017-06-21 09:00:17 -0700257 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100258 stream.num_temporal_layers = params.video[video_idx].num_temporal_layers;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800259 stream.active = true;
ilnika014cc52017-03-07 04:21:04 -0800260 return stream;
261}
262
263// Static.
264VideoStream VideoQualityTest::DefaultThumbnailStream() {
265 VideoStream stream;
266 stream.width = 320;
267 stream.height = 180;
268 stream.max_framerate = 7;
269 stream.min_bitrate_bps = 7500;
270 stream.target_bitrate_bps = 37500;
271 stream.max_bitrate_bps = 50000;
sprang1168fd42017-06-21 09:00:17 -0700272 stream.max_qp = kDefaultMaxQp;
sprangce4aef12015-11-02 07:23:20 -0800273 return stream;
274}
275
276// Static.
277void VideoQualityTest::FillScalabilitySettings(
278 Params* params,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100279 size_t video_idx,
sprangce4aef12015-11-02 07:23:20 -0800280 const std::vector<std::string>& stream_descriptors,
sprang1168fd42017-06-21 09:00:17 -0700281 int num_streams,
sprangce4aef12015-11-02 07:23:20 -0800282 size_t selected_stream,
283 int num_spatial_layers,
284 int selected_sl,
Sergey Silkin57027362018-05-15 09:12:05 +0200285 InterLayerPredMode inter_layer_pred,
sprangce4aef12015-11-02 07:23:20 -0800286 const std::vector<std::string>& sl_descriptors) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100287 if (params->ss[video_idx].streams.empty() &&
288 params->ss[video_idx].infer_streams) {
sprang1168fd42017-06-21 09:00:17 -0700289 webrtc::VideoEncoderConfig encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200290 encoder_config.codec_type =
291 PayloadStringToCodecType(params->video[video_idx].codec);
sprang1168fd42017-06-21 09:00:17 -0700292 encoder_config.content_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100293 params->screenshare[video_idx].enabled
sprang1168fd42017-06-21 09:00:17 -0700294 ? webrtc::VideoEncoderConfig::ContentType::kScreen
295 : webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100296 encoder_config.max_bitrate_bps = params->video[video_idx].max_bitrate_bps;
297 encoder_config.min_transmit_bitrate_bps =
298 params->video[video_idx].min_transmit_bps;
sprang1168fd42017-06-21 09:00:17 -0700299 encoder_config.number_of_streams = num_streams;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100300 encoder_config.spatial_layers = params->ss[video_idx].spatial_layers;
Seth Hampson8234ead2018-02-02 15:16:24 -0800301 encoder_config.simulcast_layers = std::vector<VideoStream>(num_streams);
sprang1168fd42017-06-21 09:00:17 -0700302 encoder_config.video_stream_factory =
303 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100304 params->video[video_idx].codec, kDefaultMaxQp,
305 params->video[video_idx].fps,
306 params->screenshare[video_idx].enabled, true);
307 params->ss[video_idx].streams =
sprang1168fd42017-06-21 09:00:17 -0700308 encoder_config.video_stream_factory->CreateEncoderStreams(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100309 static_cast<int>(params->video[video_idx].width),
310 static_cast<int>(params->video[video_idx].height), encoder_config);
sprang1168fd42017-06-21 09:00:17 -0700311 } else {
312 // Read VideoStream and SpatialLayer elements from a list of comma separated
313 // lists. To use a default value for an element, use -1 or leave empty.
314 // Validity checks performed in CheckParams.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100315 RTC_CHECK(params->ss[video_idx].streams.empty());
sprang1168fd42017-06-21 09:00:17 -0700316 for (auto descriptor : stream_descriptors) {
317 if (descriptor.empty())
318 continue;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100319 VideoStream stream =
320 VideoQualityTest::DefaultVideoStream(*params, video_idx);
sprang1168fd42017-06-21 09:00:17 -0700321 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
322 if (v[0] != -1)
323 stream.width = static_cast<size_t>(v[0]);
324 if (v[1] != -1)
325 stream.height = static_cast<size_t>(v[1]);
326 if (v[2] != -1)
327 stream.max_framerate = v[2];
328 if (v[3] != -1)
329 stream.min_bitrate_bps = v[3];
330 if (v[4] != -1)
331 stream.target_bitrate_bps = v[4];
332 if (v[5] != -1)
333 stream.max_bitrate_bps = v[5];
334 if (v.size() > 6 && v[6] != -1)
335 stream.max_qp = v[6];
Sergey Silkina796a7e2018-03-01 15:11:29 +0100336 if (v.size() > 7 && v[7] != -1) {
337 stream.num_temporal_layers = v[7];
sprang1168fd42017-06-21 09:00:17 -0700338 } else {
339 // Automatic TL thresholds for more than two layers not supported.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100340 RTC_CHECK_LE(params->video[video_idx].num_temporal_layers, 2);
sprang1168fd42017-06-21 09:00:17 -0700341 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100342 params->ss[video_idx].streams.push_back(stream);
sprangce4aef12015-11-02 07:23:20 -0800343 }
sprangce4aef12015-11-02 07:23:20 -0800344 }
sprangce4aef12015-11-02 07:23:20 -0800345
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100346 params->ss[video_idx].num_spatial_layers = std::max(1, num_spatial_layers);
347 params->ss[video_idx].selected_stream = selected_stream;
sprang1168fd42017-06-21 09:00:17 -0700348
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100349 params->ss[video_idx].selected_sl = selected_sl;
Sergey Silkin57027362018-05-15 09:12:05 +0200350 params->ss[video_idx].inter_layer_pred = inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100351 RTC_CHECK(params->ss[video_idx].spatial_layers.empty());
sprangce4aef12015-11-02 07:23:20 -0800352 for (auto descriptor : sl_descriptors) {
353 if (descriptor.empty())
354 continue;
355 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
Sergey Silkin13e74342018-03-02 12:28:00 +0100356 RTC_CHECK_EQ(v.size(), 7);
sprangce4aef12015-11-02 07:23:20 -0800357
Sergey Silkin13e74342018-03-02 12:28:00 +0100358 SpatialLayer layer = {0};
359 layer.width = v[0];
360 layer.height = v[1];
361 layer.numberOfTemporalLayers = v[2];
362 layer.maxBitrate = v[3];
363 layer.minBitrate = v[4];
364 layer.targetBitrate = v[5];
365 layer.qpMax = v[6];
366 layer.active = true;
367
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100368 params->ss[video_idx].spatial_layers.push_back(layer);
sprangce4aef12015-11-02 07:23:20 -0800369 }
370}
371
minyuea27172d2016-11-01 05:59:29 -0700372void VideoQualityTest::SetupVideo(Transport* send_transport,
373 Transport* recv_transport) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100374 size_t total_streams_used = 0;
375 size_t num_flexfec_streams = params_.video[0].flexfec ? 1 : 0;
376 CreateAudioAndFecSendConfigs(0, num_flexfec_streams, send_transport);
377 CreateMatchingAudioAndFecConfigs(recv_transport);
378 video_receive_configs_.clear();
379 video_send_configs_.clear();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100380 video_encoder_configs_.clear();
381 allocated_decoders_.clear();
382 bool decode_all_receive_streams = true;
383 size_t num_video_substreams = params_.ss[0].streams.size();
384 RTC_CHECK(num_video_streams_ > 0);
385 video_encoder_configs_.resize(num_video_streams_);
386 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
387 video_send_configs_.push_back(VideoSendStream::Config(send_transport));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100388 video_encoder_configs_.push_back(VideoEncoderConfig());
389 num_video_substreams = params_.ss[video_idx].streams.size();
390 RTC_CHECK_GT(num_video_substreams, 0);
391 CreateVideoSendConfig(&video_send_configs_[video_idx], num_video_substreams,
392 total_streams_used, send_transport);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100393 int payload_type;
394 if (params_.video[video_idx].codec == "H264") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100395 payload_type = kPayloadTypeH264;
396 } else if (params_.video[video_idx].codec == "VP8") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100397 payload_type = kPayloadTypeVP8;
398 } else if (params_.video[video_idx].codec == "VP9") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100399 payload_type = kPayloadTypeVP9;
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800400 } else if (params_.video[video_idx].codec == "multiplex") {
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800401 payload_type = kPayloadTypeVP9;
ilnikcb8c1462017-03-09 09:23:30 -0800402 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100403 RTC_NOTREACHED() << "Codec not supported!";
404 return;
ilnikcb8c1462017-03-09 09:23:30 -0800405 }
Niels Möller4db138e2018-04-19 09:04:13 +0200406 video_send_configs_[video_idx].encoder_settings.encoder_factory =
407 &video_encoder_factory_;
408
Niels Möller259a4972018-04-05 15:36:51 +0200409 video_send_configs_[video_idx].rtp.payload_name =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100410 params_.video[video_idx].codec;
Niels Möller259a4972018-04-05 15:36:51 +0200411 video_send_configs_[video_idx].rtp.payload_type = payload_type;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100412 video_send_configs_[video_idx].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
413 video_send_configs_[video_idx].rtp.rtx.payload_type = kSendRtxPayloadType;
414 for (size_t i = 0; i < num_video_substreams; ++i) {
415 video_send_configs_[video_idx].rtp.rtx.ssrcs.push_back(
416 kSendRtxSsrcs[i + total_streams_used]);
ilnik9fd9f6c2017-03-02 08:10:10 -0800417 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100418 video_send_configs_[video_idx].rtp.extensions.clear();
419 if (params_.call.send_side_bwe) {
420 video_send_configs_[video_idx].rtp.extensions.push_back(
421 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
422 test::kTransportSequenceNumberExtensionId));
423 } else {
424 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
425 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
426 }
427 video_send_configs_[video_idx].rtp.extensions.push_back(
428 RtpExtension(RtpExtension::kVideoContentTypeUri,
429 test::kVideoContentTypeExtensionId));
430 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
431 RtpExtension::kVideoTimingUri, test::kVideoTimingExtensionId));
432
Niels Möller4db138e2018-04-19 09:04:13 +0200433 video_encoder_configs_[video_idx].video_format.name =
434 params_.video[video_idx].codec;
435
Emircan Uysalerfc9c4e82018-07-10 15:14:04 -0700436 video_encoder_configs_[video_idx].video_format.parameters =
437 params_.video[video_idx].sdp_params;
438
Niels Möller259a4972018-04-05 15:36:51 +0200439 video_encoder_configs_[video_idx].codec_type =
440 PayloadStringToCodecType(params_.video[video_idx].codec);
441
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100442 video_encoder_configs_[video_idx].min_transmit_bitrate_bps =
443 params_.video[video_idx].min_transmit_bps;
444
445 video_send_configs_[video_idx].suspend_below_min_bitrate =
446 params_.video[video_idx].suspend_below_min_bitrate;
447
448 video_encoder_configs_[video_idx].number_of_streams =
449 params_.ss[video_idx].streams.size();
450 video_encoder_configs_[video_idx].max_bitrate_bps = 0;
451 for (size_t i = 0; i < params_.ss[video_idx].streams.size(); ++i) {
452 video_encoder_configs_[video_idx].max_bitrate_bps +=
453 params_.ss[video_idx].streams[i].max_bitrate_bps;
454 }
455 if (params_.ss[video_idx].infer_streams) {
Seth Hampson8234ead2018-02-02 15:16:24 -0800456 video_encoder_configs_[video_idx].simulcast_layers =
457 std::vector<VideoStream>(params_.ss[video_idx].streams.size());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100458 video_encoder_configs_[video_idx].video_stream_factory =
459 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
460 params_.video[video_idx].codec,
461 params_.ss[video_idx].streams[0].max_qp,
462 params_.video[video_idx].fps,
463 params_.screenshare[video_idx].enabled, true);
464 } else {
465 video_encoder_configs_[video_idx].video_stream_factory =
466 new rtc::RefCountedObject<VideoStreamFactory>(
467 params_.ss[video_idx].streams);
468 }
469
470 video_encoder_configs_[video_idx].spatial_layers =
471 params_.ss[video_idx].spatial_layers;
472
473 std::vector<VideoReceiveStream::Config> new_receive_configs =
474 CreateMatchingVideoReceiveConfigs(video_send_configs_[video_idx],
475 recv_transport);
476
477 decode_all_receive_streams = params_.ss[video_idx].selected_stream ==
478 params_.ss[video_idx].streams.size();
479
480 for (size_t i = 0; i < num_video_substreams; ++i) {
481 new_receive_configs[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
482 new_receive_configs[i].rtp.rtx_ssrc =
483 kSendRtxSsrcs[i + total_streams_used];
484 new_receive_configs[i]
485 .rtp.rtx_associated_payload_types[kSendRtxPayloadType] = payload_type;
486 new_receive_configs[i].rtp.transport_cc = params_.call.send_side_bwe;
487 new_receive_configs[i].rtp.remb = !params_.call.send_side_bwe;
488 // Enable RTT calculation so NTP time estimator will work.
489 new_receive_configs[i].rtp.rtcp_xr.receiver_reference_time_report = true;
490 // Force fake decoders on non-selected simulcast streams.
491 if (!decode_all_receive_streams &&
492 i != params_.ss[video_idx].selected_stream) {
493 VideoReceiveStream::Decoder decoder;
494 decoder.decoder = new test::FakeDecoder();
Niels Möller259a4972018-04-05 15:36:51 +0200495 decoder.payload_type = video_send_configs_[video_idx].rtp.payload_type;
496 decoder.payload_name = video_send_configs_[video_idx].rtp.payload_name;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100497 new_receive_configs[i].decoders.clear();
498 allocated_decoders_.emplace_back(decoder.decoder);
499 new_receive_configs[i].decoders.push_back(decoder);
500 }
501 }
502
503 for (VideoReceiveStream::Config& config : new_receive_configs) {
504 video_receive_configs_.push_back(config.Copy());
505 }
506
507 if (params_.screenshare[video_idx].enabled) {
508 // Fill out codec settings.
509 video_encoder_configs_[video_idx].content_type =
510 VideoEncoderConfig::ContentType::kScreen;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700511 degradation_preference_ = DegradationPreference::MAINTAIN_RESOLUTION;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100512 if (params_.video[video_idx].codec == "VP8") {
513 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
514 vp8_settings.denoisingOn = false;
515 vp8_settings.frameDroppingOn = false;
516 vp8_settings.numberOfTemporalLayers = static_cast<unsigned char>(
517 params_.video[video_idx].num_temporal_layers);
518 video_encoder_configs_[video_idx].encoder_specific_settings =
519 new rtc::RefCountedObject<
520 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
521 } else if (params_.video[video_idx].codec == "VP9") {
522 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
523 vp9_settings.denoisingOn = false;
524 vp9_settings.frameDroppingOn = false;
525 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
526 params_.video[video_idx].num_temporal_layers);
527 vp9_settings.numberOfSpatialLayers = static_cast<unsigned char>(
528 params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200529 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100530 video_encoder_configs_[video_idx].encoder_specific_settings =
531 new rtc::RefCountedObject<
532 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
533 }
534 } else if (params_.ss[video_idx].num_spatial_layers > 1) {
535 // If SVC mode without screenshare, still need to set codec specifics.
536 RTC_CHECK(params_.video[video_idx].codec == "VP9");
537 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
538 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
539 params_.video[video_idx].num_temporal_layers);
540 vp9_settings.numberOfSpatialLayers =
541 static_cast<unsigned char>(params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200542 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100543 video_encoder_configs_[video_idx].encoder_specific_settings =
544 new rtc::RefCountedObject<
545 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Niels Möller6aa415e2018-06-07 11:14:13 +0200546 } else if (params_.video[video_idx].automatic_scaling) {
547 if (params_.video[video_idx].codec == "VP8") {
548 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
549 vp8_settings.automaticResizeOn = true;
550 video_encoder_configs_[video_idx].encoder_specific_settings =
551 new rtc::RefCountedObject<
552 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
553 } else if (params_.video[video_idx].codec == "VP9") {
554 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
555 vp9_settings.automaticResizeOn = true;
556 video_encoder_configs_[video_idx].encoder_specific_settings =
557 new rtc::RefCountedObject<
558 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
559 } else {
560 RTC_NOTREACHED() << "Automatic scaling not supported for codec "
Yves Gerey665174f2018-06-19 15:03:05 +0200561 << params_.video[video_idx].codec << ", stream "
562 << video_idx;
Niels Möller6aa415e2018-06-07 11:14:13 +0200563 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100564 }
565 total_streams_used += num_video_substreams;
sprangce4aef12015-11-02 07:23:20 -0800566 }
brandtr1293aca2016-11-16 22:47:29 -0800567
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100568 // FEC supported only for single video stream mode yet.
569 if (params_.video[0].flexfec) {
Ilya Nikolaevskiy38aaf692017-12-22 14:39:09 +0100570 video_send_configs_[0].rtp.flexfec.payload_type = kFlexfecPayloadType;
571 video_send_configs_[0].rtp.flexfec.ssrc = kFlexfecSendSsrc;
sprang1168fd42017-06-21 09:00:17 -0700572 if (decode_all_receive_streams) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100573 for (uint32_t media_ssrc : video_send_configs_[0].rtp.ssrcs) {
574 video_send_configs_[0].rtp.flexfec.protected_media_ssrcs.push_back(
sprang1168fd42017-06-21 09:00:17 -0700575 media_ssrc);
576 }
577 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100578 video_send_configs_[0].rtp.flexfec.protected_media_ssrcs = {
579 kVideoSendSsrcs[params_.ss[0].selected_stream]};
sprang1168fd42017-06-21 09:00:17 -0700580 }
brandtr1293aca2016-11-16 22:47:29 -0800581
brandtr8313a6f2017-01-13 07:41:19 -0800582 // The matching receive config is _not_ created by
583 // CreateMatchingReceiveConfigs, since VideoQualityTest is not a BaseTest.
584 // Set up the receive config manually instead.
585 FlexfecReceiveStream::Config flexfec_receive_config(recv_transport);
brandtr1cfbd602016-12-08 04:17:53 -0800586 flexfec_receive_config.payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100587 video_send_configs_[0].rtp.flexfec.payload_type;
588 flexfec_receive_config.remote_ssrc =
589 video_send_configs_[0].rtp.flexfec.ssrc;
brandtr1293aca2016-11-16 22:47:29 -0800590 flexfec_receive_config.protected_media_ssrcs =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100591 video_send_configs_[0].rtp.flexfec.protected_media_ssrcs;
brandtrfa5a3682017-01-17 01:33:54 -0800592 flexfec_receive_config.local_ssrc = kReceiverLocalVideoSsrc;
brandtrb29e6522016-12-21 06:37:18 -0800593 flexfec_receive_config.transport_cc = params_.call.send_side_bwe;
594 if (params_.call.send_side_bwe) {
595 flexfec_receive_config.rtp_header_extensions.push_back(
596 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
597 test::kTransportSequenceNumberExtensionId));
598 } else {
599 flexfec_receive_config.rtp_header_extensions.push_back(RtpExtension(
600 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
601 }
brandtr1293aca2016-11-16 22:47:29 -0800602 flexfec_receive_configs_.push_back(flexfec_receive_config);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100603 if (num_video_substreams > 0) {
brandtr7cd28b92017-09-22 00:26:25 -0700604 video_receive_configs_[0].rtp.protected_by_flexfec = true;
605 }
brandtr1293aca2016-11-16 22:47:29 -0800606 }
607
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100608 if (params_.video[0].ulpfec) {
609 video_send_configs_[0].rtp.ulpfec.red_payload_type = kRedPayloadType;
610 video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
611 video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType;
brandtr1293aca2016-11-16 22:47:29 -0800612
sprang1168fd42017-06-21 09:00:17 -0700613 if (decode_all_receive_streams) {
614 for (auto it = video_receive_configs_.begin();
615 it != video_receive_configs_.end(); ++it) {
nisse3b3622f2017-09-26 02:49:21 -0700616 it->rtp.red_payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100617 video_send_configs_[0].rtp.ulpfec.red_payload_type;
nisse3b3622f2017-09-26 02:49:21 -0700618 it->rtp.ulpfec_payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100619 video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type;
620 it->rtp.rtx_associated_payload_types
621 [video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type] =
622 video_send_configs_[0].rtp.ulpfec.red_payload_type;
sprang1168fd42017-06-21 09:00:17 -0700623 }
624 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100625 video_receive_configs_[params_.ss[0].selected_stream]
626 .rtp.red_payload_type =
627 video_send_configs_[0].rtp.ulpfec.red_payload_type;
628 video_receive_configs_[params_.ss[0].selected_stream]
nisse3b3622f2017-09-26 02:49:21 -0700629 .rtp.ulpfec_payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100630 video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type;
631 video_receive_configs_[params_.ss[0].selected_stream]
632 .rtp.rtx_associated_payload_types
633 [video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type] =
634 video_send_configs_[0].rtp.ulpfec.red_payload_type;
sprang1168fd42017-06-21 09:00:17 -0700635 }
brandtr1293aca2016-11-16 22:47:29 -0800636 }
ivica5d6a06c2015-09-17 05:30:24 -0700637}
638
ilnika014cc52017-03-07 04:21:04 -0800639void VideoQualityTest::SetupThumbnails(Transport* send_transport,
640 Transport* recv_transport) {
ilnik98436952017-07-13 00:47:03 -0700641 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 04:21:04 -0800642 // Thumbnails will be send in the other way: from receiver_call to
643 // sender_call.
644 VideoSendStream::Config thumbnail_send_config(recv_transport);
645 thumbnail_send_config.rtp.ssrcs.push_back(kThumbnailSendSsrcStart + i);
Niels Möller4db138e2018-04-19 09:04:13 +0200646 // TODO(nisse): Could use a simpler VP8-only encoder factory.
647 thumbnail_send_config.encoder_settings.encoder_factory =
648 &video_encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200649 thumbnail_send_config.rtp.payload_name = params_.video[0].codec;
650 thumbnail_send_config.rtp.payload_type = kPayloadTypeVP8;
ilnika014cc52017-03-07 04:21:04 -0800651 thumbnail_send_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
652 thumbnail_send_config.rtp.rtx.payload_type = kSendRtxPayloadType;
653 thumbnail_send_config.rtp.rtx.ssrcs.push_back(kThumbnailRtxSsrcStart + i);
654 thumbnail_send_config.rtp.extensions.clear();
655 if (params_.call.send_side_bwe) {
656 thumbnail_send_config.rtp.extensions.push_back(
657 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
658 test::kTransportSequenceNumberExtensionId));
659 } else {
660 thumbnail_send_config.rtp.extensions.push_back(RtpExtension(
661 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
662 }
663
664 VideoEncoderConfig thumbnail_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200665 thumbnail_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller4db138e2018-04-19 09:04:13 +0200666 thumbnail_encoder_config.video_format.name = "VP8";
ilnika014cc52017-03-07 04:21:04 -0800667 thumbnail_encoder_config.min_transmit_bitrate_bps = 7500;
668 thumbnail_send_config.suspend_below_min_bitrate =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100669 params_.video[0].suspend_below_min_bitrate;
ilnika014cc52017-03-07 04:21:04 -0800670 thumbnail_encoder_config.number_of_streams = 1;
671 thumbnail_encoder_config.max_bitrate_bps = 50000;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100672 if (params_.ss[0].infer_streams) {
ilnik6b826ef2017-06-16 06:53:48 -0700673 thumbnail_encoder_config.video_stream_factory =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100674 new rtc::RefCountedObject<VideoStreamFactory>(params_.ss[0].streams);
ilnik6b826ef2017-06-16 06:53:48 -0700675 } else {
Seth Hampson8234ead2018-02-02 15:16:24 -0800676 thumbnail_encoder_config.simulcast_layers = std::vector<VideoStream>(1);
ilnik6b826ef2017-06-16 06:53:48 -0700677 thumbnail_encoder_config.video_stream_factory =
678 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100679 params_.video[0].codec, params_.ss[0].streams[0].max_qp,
680 params_.video[0].fps, params_.screenshare[0].enabled, true);
ilnik6b826ef2017-06-16 06:53:48 -0700681 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100682 thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers;
ilnika014cc52017-03-07 04:21:04 -0800683
684 VideoReceiveStream::Config thumbnail_receive_config(send_transport);
685 thumbnail_receive_config.rtp.remb = false;
686 thumbnail_receive_config.rtp.transport_cc = true;
687 thumbnail_receive_config.rtp.local_ssrc = kReceiverLocalVideoSsrc;
688 for (const RtpExtension& extension : thumbnail_send_config.rtp.extensions)
689 thumbnail_receive_config.rtp.extensions.push_back(extension);
690 thumbnail_receive_config.renderer = &fake_renderer_;
691
692 VideoReceiveStream::Decoder decoder =
Niels Möller259a4972018-04-05 15:36:51 +0200693 test::CreateMatchingDecoder(thumbnail_send_config);
ilnika014cc52017-03-07 04:21:04 -0800694 allocated_decoders_.push_back(
695 std::unique_ptr<VideoDecoder>(decoder.decoder));
696 thumbnail_receive_config.decoders.clear();
697 thumbnail_receive_config.decoders.push_back(decoder);
698 thumbnail_receive_config.rtp.remote_ssrc =
699 thumbnail_send_config.rtp.ssrcs[0];
700
701 thumbnail_receive_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
702 thumbnail_receive_config.rtp.rtx_ssrc = kThumbnailRtxSsrcStart + i;
nisse26e3abb2017-08-25 04:44:25 -0700703 thumbnail_receive_config.rtp
704 .rtx_associated_payload_types[kSendRtxPayloadType] = kPayloadTypeVP8;
ilnika014cc52017-03-07 04:21:04 -0800705 thumbnail_receive_config.rtp.transport_cc = params_.call.send_side_bwe;
706 thumbnail_receive_config.rtp.remb = !params_.call.send_side_bwe;
707
708 thumbnail_encoder_configs_.push_back(thumbnail_encoder_config.Copy());
709 thumbnail_send_configs_.push_back(thumbnail_send_config.Copy());
710 thumbnail_receive_configs_.push_back(thumbnail_receive_config.Copy());
711 }
712
ilnik98436952017-07-13 00:47:03 -0700713 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 04:21:04 -0800714 thumbnail_send_streams_.push_back(receiver_call_->CreateVideoSendStream(
715 thumbnail_send_configs_[i].Copy(),
716 thumbnail_encoder_configs_[i].Copy()));
717 thumbnail_receive_streams_.push_back(sender_call_->CreateVideoReceiveStream(
718 thumbnail_receive_configs_[i].Copy()));
719 }
720}
721
722void VideoQualityTest::DestroyThumbnailStreams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100723 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800724 receiver_call_->DestroyVideoSendStream(thumbnail_send_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100725 }
ilnika014cc52017-03-07 04:21:04 -0800726 thumbnail_send_streams_.clear();
727 for (VideoReceiveStream* thumbnail_receive_stream :
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100728 thumbnail_receive_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800729 sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100730 }
ilnika014cc52017-03-07 04:21:04 -0800731 thumbnail_send_streams_.clear();
732 thumbnail_receive_streams_.clear();
eladalon413ee9a2017-08-22 04:02:52 -0700733 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
734 thumbnail_capturers_) {
735 video_caputurer.reset();
736 }
ilnika014cc52017-03-07 04:21:04 -0800737}
738
ilnika014cc52017-03-07 04:21:04 -0800739void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) {
740 VideoStream thumbnail = DefaultThumbnailStream();
741 for (size_t i = 0; i < num_thumbnail_streams; ++i) {
742 thumbnail_capturers_.emplace_back(test::FrameGeneratorCapturer::Create(
743 static_cast<int>(thumbnail.width), static_cast<int>(thumbnail.height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200744 absl::nullopt, absl::nullopt, thumbnail.max_framerate, clock_));
ilnikf89a7382017-03-07 06:15:27 -0800745 RTC_DCHECK(thumbnail_capturers_.back());
ilnika014cc52017-03-07 04:21:04 -0800746 }
747}
748
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100749std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator(
750 size_t video_idx) {
751 // Setup frame generator.
752 const size_t kWidth = 1850;
753 const size_t kHeight = 1110;
754 std::unique_ptr<test::FrameGenerator> frame_generator;
755 if (params_.screenshare[video_idx].generate_slides) {
756 frame_generator = test::FrameGenerator::CreateSlideGenerator(
757 kWidth, kHeight,
758 params_.screenshare[video_idx].slide_change_interval *
759 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700760 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100761 std::vector<std::string> slides = params_.screenshare[video_idx].slides;
762 if (slides.size() == 0) {
763 slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
764 slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
765 slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
766 slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
767 }
768 if (params_.screenshare[video_idx].scroll_duration == 0) {
769 // Cycle image every slide_change_interval seconds.
770 frame_generator = test::FrameGenerator::CreateFromYuvFile(
771 slides, kWidth, kHeight,
772 params_.screenshare[video_idx].slide_change_interval *
773 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700774 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100775 RTC_CHECK_LE(params_.video[video_idx].width, kWidth);
776 RTC_CHECK_LE(params_.video[video_idx].height, kHeight);
777 RTC_CHECK_GT(params_.screenshare[video_idx].slide_change_interval, 0);
778 const int kPauseDurationMs =
779 (params_.screenshare[video_idx].slide_change_interval -
780 params_.screenshare[video_idx].scroll_duration) *
781 1000;
782 RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration,
783 params_.screenshare[video_idx].slide_change_interval);
784
785 frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
786 clock_, slides, kWidth, kHeight, params_.video[video_idx].width,
787 params_.video[video_idx].height,
788 params_.screenshare[video_idx].scroll_duration * 1000,
789 kPauseDurationMs);
ivica5d6a06c2015-09-17 05:30:24 -0700790 }
791 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100792 return frame_generator;
793}
794
795void VideoQualityTest::CreateCapturers() {
796 video_capturers_.resize(num_video_streams_);
797 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
798 if (params_.screenshare[video_idx].enabled) {
799 std::unique_ptr<test::FrameGenerator> frame_generator =
800 CreateFrameGenerator(video_idx);
801 test::FrameGeneratorCapturer* frame_generator_capturer =
802 new test::FrameGeneratorCapturer(clock_, std::move(frame_generator),
803 params_.video[video_idx].fps);
804 EXPECT_TRUE(frame_generator_capturer->Init());
805 video_capturers_[video_idx].reset(frame_generator_capturer);
806 } else {
807 if (params_.video[video_idx].clip_name == "Generator") {
808 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
809 static_cast<int>(params_.video[video_idx].width),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200810 static_cast<int>(params_.video[video_idx].height), absl::nullopt,
811 absl::nullopt, params_.video[video_idx].fps, clock_));
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800812 } else if (params_.video[video_idx].clip_name == "GeneratorI420A") {
813 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
814 static_cast<int>(params_.video[video_idx].width),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100815 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200816 test::FrameGenerator::OutputType::I420A, absl::nullopt,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100817 params_.video[video_idx].fps, clock_));
Emircan Uysalerfc9c4e82018-07-10 15:14:04 -0700818 } else if (params_.video[video_idx].clip_name == "GeneratorI010") {
819 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
820 static_cast<int>(params_.video[video_idx].width),
821 static_cast<int>(params_.video[video_idx].height),
822 test::FrameGenerator::OutputType::I010, absl::nullopt,
823 params_.video[video_idx].fps, clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100824 } else if (params_.video[video_idx].clip_name.empty()) {
825 video_capturers_[video_idx].reset(test::VcmCapturer::Create(
826 params_.video[video_idx].width, params_.video[video_idx].height,
827 params_.video[video_idx].fps,
828 params_.video[video_idx].capture_device_index));
829 if (!video_capturers_[video_idx]) {
830 // Failed to get actual camera, use chroma generator as backup.
831 video_capturers_[video_idx].reset(
832 test::FrameGeneratorCapturer::Create(
833 static_cast<int>(params_.video[video_idx].width),
834 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200835 absl::nullopt, absl::nullopt, params_.video[video_idx].fps,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800836 clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100837 }
838 } else {
839 video_capturers_[video_idx].reset(
840 test::FrameGeneratorCapturer::CreateFromYuvFile(
841 test::ResourcePath(params_.video[video_idx].clip_name, "yuv"),
842 params_.video[video_idx].width, params_.video[video_idx].height,
843 params_.video[video_idx].fps, clock_));
844 ASSERT_TRUE(video_capturers_[video_idx])
845 << "Could not create capturer for "
846 << params_.video[video_idx].clip_name
847 << ".yuv. Is this resource file present?";
848 }
849 }
850 RTC_DCHECK(video_capturers_[video_idx].get());
851 }
ivica5d6a06c2015-09-17 05:30:24 -0700852}
853
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100854std::unique_ptr<test::LayerFilteringTransport>
855VideoQualityTest::CreateSendTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200856 return absl::make_unique<test::LayerFilteringTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100857 &task_queue_, params_.pipe, sender_call_.get(), kPayloadTypeVP8,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100858 kPayloadTypeVP9, params_.video[0].selected_tl, params_.ss[0].selected_sl,
859 payload_type_map_, kVideoSendSsrcs[0],
860 static_cast<uint32_t>(kVideoSendSsrcs[0] + params_.ss[0].streams.size() -
861 1));
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100862}
863
864std::unique_ptr<test::DirectTransport>
865VideoQualityTest::CreateReceiveTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200866 return absl::make_unique<test::DirectTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100867 &task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_);
868}
869
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100870void VideoQualityTest::CreateVideoStreams() {
871 RTC_DCHECK(video_send_streams_.empty());
872 RTC_DCHECK(video_receive_streams_.empty());
873 RTC_DCHECK_EQ(video_send_configs_.size(), num_video_streams_);
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100874
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100875 // We currently only support testing external fec controllers with a single
876 // VideoSendStream.
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100877 if (fec_controller_factory_.get()) {
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100878 RTC_DCHECK_LE(video_send_configs_.size(), 1);
879 }
Ilya Nikolaevskiy4c09d7a2018-03-02 13:37:00 +0100880
881 // TODO(http://crbug/818127):
882 // Remove this workaround when ALR is not screenshare-specific.
883 std::list<size_t> streams_creation_order;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100884 for (size_t i = 0; i < video_send_configs_.size(); ++i) {
Ilya Nikolaevskiy4c09d7a2018-03-02 13:37:00 +0100885 // If dual streams are created, add the screenshare stream last.
886 if (video_encoder_configs_[i].content_type ==
887 VideoEncoderConfig::ContentType::kScreen) {
888 streams_creation_order.push_back(i);
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100889 } else {
Ilya Nikolaevskiy4c09d7a2018-03-02 13:37:00 +0100890 streams_creation_order.push_front(i);
891 }
892 }
893
894 video_send_streams_.resize(video_send_configs_.size(), nullptr);
895
896 for (size_t i : streams_creation_order) {
897 if (fec_controller_factory_.get()) {
898 video_send_streams_[i] = sender_call_->CreateVideoSendStream(
899 video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy(),
900 fec_controller_factory_->CreateFecController());
901 } else {
902 video_send_streams_[i] = sender_call_->CreateVideoSendStream(
903 video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy());
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100904 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100905 }
906 for (size_t i = 0; i < video_receive_configs_.size(); ++i) {
907 video_receive_streams_.push_back(receiver_call_->CreateVideoReceiveStream(
908 video_receive_configs_[i].Copy()));
909 }
910
911 AssociateFlexfecStreamsWithVideoStreams();
912}
913
914void VideoQualityTest::DestroyStreams() {
915 CallTest::DestroyStreams();
916
917 for (VideoSendStream* video_send_stream : video_send_streams_)
918 sender_call_->DestroyVideoSendStream(video_send_stream);
919}
920
sprang7a975f72015-10-12 06:33:21 -0700921void VideoQualityTest::RunWithAnalyzer(const Params& params) {
Ilya Nikolaevskiyad556762018-01-17 11:48:59 +0100922 rtc::LogMessage::SetLogToStderr(params.logging.logs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100923 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -0700924 std::unique_ptr<test::LayerFilteringTransport> send_transport;
925 std::unique_ptr<test::DirectTransport> recv_transport;
926 FILE* graph_data_output_file = nullptr;
927 std::unique_ptr<VideoAnalyzer> analyzer;
928
sprangce4aef12015-11-02 07:23:20 -0800929 params_ = params;
930
minyue626bc952016-10-31 05:47:02 -0700931 RTC_CHECK(!params_.audio.enabled);
ivica5d6a06c2015-09-17 05:30:24 -0700932 // TODO(ivica): Merge with RunWithRenderer and use a flag / argument to
933 // differentiate between the analyzer and the renderer case.
sprangce4aef12015-11-02 07:23:20 -0800934 CheckParams();
ivica5d6a06c2015-09-17 05:30:24 -0700935
sprangce4aef12015-11-02 07:23:20 -0800936 if (!params_.analyzer.graph_data_output_filename.empty()) {
ivica5d6a06c2015-09-17 05:30:24 -0700937 graph_data_output_file =
sprangce4aef12015-11-02 07:23:20 -0800938 fopen(params_.analyzer.graph_data_output_filename.c_str(), "w");
Peter Boström74f6e9e2016-04-04 17:56:10 +0200939 RTC_CHECK(graph_data_output_file)
sprangce4aef12015-11-02 07:23:20 -0800940 << "Can't open the file " << params_.analyzer.graph_data_output_filename
941 << "!";
ivica87f83a92015-10-08 05:13:32 -0700942 }
sprang7a975f72015-10-12 06:33:21 -0700943
ilnik98436952017-07-13 00:47:03 -0700944 if (!params.logging.rtc_event_log_name.empty()) {
Bjorn Terelius0a6a2b72018-01-19 17:52:38 +0100945 send_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
946 recv_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100947 std::unique_ptr<RtcEventLogOutputFile> send_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200948 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100949 params.logging.rtc_event_log_name + "_send",
950 RtcEventLog::kUnlimitedOutput));
951 std::unique_ptr<RtcEventLogOutputFile> recv_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200952 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100953 params.logging.rtc_event_log_name + "_recv",
954 RtcEventLog::kUnlimitedOutput));
955 bool event_log_started =
956 send_event_log_->StartLogging(std::move(send_output),
957 RtcEventLog::kImmediateOutput) &&
958 recv_event_log_->StartLogging(std::move(recv_output),
959 RtcEventLog::kImmediateOutput);
ilnik98436952017-07-13 00:47:03 -0700960 RTC_DCHECK(event_log_started);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100961 } else {
962 send_event_log_ = RtcEventLog::CreateNull();
963 recv_event_log_ = RtcEventLog::CreateNull();
ilnik98436952017-07-13 00:47:03 -0700964 }
965
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100966 Call::Config send_call_config(send_event_log_.get());
967 Call::Config recv_call_config(recv_event_log_.get());
968 send_call_config.bitrate_config = params.call.call_bitrate_config;
969 recv_call_config.bitrate_config = params.call.call_bitrate_config;
stefanf116bd02015-10-27 08:29:42 -0700970
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100971 task_queue_.SendTask([this, &send_call_config, &recv_call_config,
972 &send_transport, &recv_transport]() {
973 CreateCalls(send_call_config, recv_call_config);
974 send_transport = CreateSendTransport();
975 recv_transport = CreateReceiveTransport();
976 });
stefanf116bd02015-10-27 08:29:42 -0700977
sprangce4aef12015-11-02 07:23:20 -0800978 std::string graph_title = params_.analyzer.graph_title;
979 if (graph_title.empty())
980 graph_title = VideoQualityTest::GenerateGraphTitle();
sprangc1b57a12017-02-28 08:50:47 -0800981 bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
Karl Wiberg918f50c2018-07-05 11:40:33 +0200982 analyzer = absl::make_unique<VideoAnalyzer>(
eladalon413ee9a2017-08-22 04:02:52 -0700983 send_transport.get(), params_.analyzer.test_label,
ilnik2a8c2f52017-02-15 02:23:28 -0800984 params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
ilnik9ae0d762017-02-15 00:53:12 -0800985 is_quick_test_enabled
986 ? kFramesSentInQuickTest
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100987 : params_.analyzer.test_durations_secs * params_.video[0].fps,
sprangce4aef12015-11-02 07:23:20 -0800988 graph_data_output_file, graph_title,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100989 kVideoSendSsrcs[params_.ss[0].selected_stream],
990 kSendRtxSsrcs[params_.ss[0].selected_stream],
991 static_cast<size_t>(params_.ss[0].selected_stream),
992 params.ss[0].selected_sl, params_.video[0].selected_tl,
993 is_quick_test_enabled, clock_, params_.logging.rtp_dump_name);
ivica5d6a06c2015-09-17 05:30:24 -0700994
eladalon413ee9a2017-08-22 04:02:52 -0700995 task_queue_.SendTask([&]() {
996 analyzer->SetCall(sender_call_.get());
997 analyzer->SetReceiver(receiver_call_->Receiver());
998 send_transport->SetReceiver(analyzer.get());
999 recv_transport->SetReceiver(sender_call_->Receiver());
ivica5d6a06c2015-09-17 05:30:24 -07001000
eladalon413ee9a2017-08-22 04:02:52 -07001001 SetupVideo(analyzer.get(), recv_transport.get());
1002 SetupThumbnails(analyzer.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001003 video_receive_configs_[params_.ss[0].selected_stream].renderer =
eladalon413ee9a2017-08-22 04:02:52 -07001004 analyzer.get();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001005 video_send_configs_[0].pre_encode_callback = analyzer->pre_encode_proxy();
1006 RTC_DCHECK(!video_send_configs_[0].post_encode_callback);
Niels Möllerf88a22c2018-06-19 17:05:03 +02001007 video_send_configs_[0].post_encode_callback = analyzer.get();
kthelgason2bc68642017-02-07 07:02:22 -08001008
eladalon413ee9a2017-08-22 04:02:52 -07001009 CreateFlexfecStreams();
1010 CreateVideoStreams();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001011 analyzer->SetSendStream(video_send_streams_[0]);
eladalon413ee9a2017-08-22 04:02:52 -07001012 if (video_receive_streams_.size() == 1)
1013 analyzer->SetReceiveStream(video_receive_streams_[0]);
ivica5d6a06c2015-09-17 05:30:24 -07001014
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001015 video_send_streams_[0]->SetSource(analyzer->OutputInterface(),
1016 degradation_preference_);
eladalon413ee9a2017-08-22 04:02:52 -07001017 SetupThumbnailCapturers(params_.call.num_thumbnails);
1018 for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
1019 thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
1020 degradation_preference_);
1021 }
ilnika014cc52017-03-07 04:21:04 -08001022
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001023 CreateCapturers();
ivicac1cc8542015-10-08 03:44:06 -07001024
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001025 analyzer->SetSource(video_capturers_[0].get(), params_.ss[0].infer_streams);
ilnika014cc52017-03-07 04:21:04 -08001026
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001027 for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) {
1028 video_send_streams_[video_idx]->SetSource(
1029 video_capturers_[video_idx].get(), degradation_preference_);
1030 }
1031
1032 StartEncodedFrameLogs(video_send_streams_[0]);
1033 StartEncodedFrameLogs(
1034 video_receive_streams_[params_.ss[0].selected_stream]);
1035 for (VideoSendStream* video_send_stream : video_send_streams_)
1036 video_send_stream->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001037 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
1038 thumbnail_send_stream->Start();
1039 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1040 receive_stream->Start();
1041 for (VideoReceiveStream* thumbnail_receive_stream :
1042 thumbnail_receive_streams_)
1043 thumbnail_receive_stream->Start();
ilnika014cc52017-03-07 04:21:04 -08001044
eladalon413ee9a2017-08-22 04:02:52 -07001045 analyzer->StartMeasuringCpuProcessTime();
ivica5d6a06c2015-09-17 05:30:24 -07001046
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001047 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1048 video_capturers_[video_idx]->Start();
1049 }
eladalon413ee9a2017-08-22 04:02:52 -07001050 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
1051 thumbnail_capturers_) {
1052 video_caputurer->Start();
1053 }
1054 });
ivica5d6a06c2015-09-17 05:30:24 -07001055
eladalon413ee9a2017-08-22 04:02:52 -07001056 analyzer->Wait();
ivica5d6a06c2015-09-17 05:30:24 -07001057
Ilya Nikolaevskiy2c72fe82017-10-02 13:01:04 +02001058 event_log_->StopLogging();
1059
eladalon413ee9a2017-08-22 04:02:52 -07001060 task_queue_.SendTask([&]() {
1061 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
1062 thumbnail_capturers_)
1063 video_caputurer->Stop();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001064 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1065 video_capturers_[video_idx]->Stop();
1066 }
eladalon413ee9a2017-08-22 04:02:52 -07001067 for (VideoReceiveStream* thumbnail_receive_stream :
1068 thumbnail_receive_streams_)
1069 thumbnail_receive_stream->Stop();
1070 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1071 receive_stream->Stop();
1072 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
1073 thumbnail_send_stream->Stop();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001074 for (VideoSendStream* video_send_stream : video_send_streams_)
1075 video_send_stream->Stop();
ivica5d6a06c2015-09-17 05:30:24 -07001076
eladalon413ee9a2017-08-22 04:02:52 -07001077 DestroyStreams();
1078 DestroyThumbnailStreams();
ivica5d6a06c2015-09-17 05:30:24 -07001079
eladalon413ee9a2017-08-22 04:02:52 -07001080 if (graph_data_output_file)
1081 fclose(graph_data_output_file);
1082
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001083 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -07001084 send_transport.reset();
1085 recv_transport.reset();
1086
1087 DestroyCalls();
1088 });
ivica5d6a06c2015-09-17 05:30:24 -07001089}
1090
Fredrik Solenberg8f5787a2018-01-11 13:52:30 +01001091void VideoQualityTest::SetupAudio(Transport* transport,
minyuea27172d2016-11-01 05:59:29 -07001092 AudioReceiveStream** audio_receive_stream) {
1093 audio_send_config_ = AudioSendStream::Config(transport);
minyuea27172d2016-11-01 05:59:29 -07001094 audio_send_config_.rtp.ssrc = kAudioSendSsrc;
1095
1096 // Add extension to enable audio send side BWE, and allow audio bit rate
1097 // adaptation.
1098 audio_send_config_.rtp.extensions.clear();
1099 if (params_.call.send_side_bwe) {
1100 audio_send_config_.rtp.extensions.push_back(
1101 webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri,
1102 test::kTransportSequenceNumberExtensionId));
minyue10cbb462016-11-07 09:29:22 -08001103 audio_send_config_.min_bitrate_bps = kOpusMinBitrateBps;
1104 audio_send_config_.max_bitrate_bps = kOpusBitrateFbBps;
minyuea27172d2016-11-01 05:59:29 -07001105 }
Oskar Sundbom8e07c132018-01-08 16:45:42 +01001106 audio_send_config_.send_codec_spec = AudioSendStream::Config::SendCodecSpec(
1107 kAudioSendPayloadType,
Yves Gerey665174f2018-06-19 15:03:05 +02001108 {"OPUS",
1109 48000,
1110 2,
1111 {{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}});
Niels Möller2784a032018-03-28 14:16:04 +02001112 audio_send_config_.encoder_factory = audio_encoder_factory_;
sprang1168fd42017-06-21 09:00:17 -07001113 audio_send_stream_ = sender_call_->CreateAudioSendStream(audio_send_config_);
minyuea27172d2016-11-01 05:59:29 -07001114
1115 AudioReceiveStream::Config audio_config;
1116 audio_config.rtp.local_ssrc = kReceiverLocalAudioSsrc;
1117 audio_config.rtcp_send_transport = transport;
minyuea27172d2016-11-01 05:59:29 -07001118 audio_config.rtp.remote_ssrc = audio_send_config_.rtp.ssrc;
1119 audio_config.rtp.transport_cc = params_.call.send_side_bwe;
1120 audio_config.rtp.extensions = audio_send_config_.rtp.extensions;
Niels Möller2784a032018-03-28 14:16:04 +02001121 audio_config.decoder_factory = audio_decoder_factory_;
minyue20c84cc2017-04-10 16:57:57 -07001122 audio_config.decoder_map = {{kAudioSendPayloadType, {"OPUS", 48000, 2}}};
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001123 if (params_.video[0].enabled && params_.audio.sync_video)
minyuea27172d2016-11-01 05:59:29 -07001124 audio_config.sync_group = kSyncGroup;
1125
sprang1168fd42017-06-21 09:00:17 -07001126 *audio_receive_stream =
1127 receiver_call_->CreateAudioReceiveStream(audio_config);
minyuea27172d2016-11-01 05:59:29 -07001128}
1129
minyue73208662016-08-18 06:28:55 -07001130void VideoQualityTest::RunWithRenderers(const Params& params) {
Ilya Nikolaevskiyad556762018-01-17 11:48:59 +01001131 rtc::LogMessage::SetLogToStderr(params.logging.logs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001132 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -07001133 std::unique_ptr<test::LayerFilteringTransport> send_transport;
1134 std::unique_ptr<test::DirectTransport> recv_transport;
minyuea27172d2016-11-01 05:59:29 -07001135 std::unique_ptr<test::VideoRenderer> local_preview;
eladalon413ee9a2017-08-22 04:02:52 -07001136 std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
minyue73208662016-08-18 06:28:55 -07001137 AudioReceiveStream* audio_receive_stream = nullptr;
minyue73208662016-08-18 06:28:55 -07001138
eladalon413ee9a2017-08-22 04:02:52 -07001139 task_queue_.SendTask([&]() {
1140 params_ = params;
1141 CheckParams();
palmkviste75f2042016-09-28 06:19:48 -07001142
eladalon413ee9a2017-08-22 04:02:52 -07001143 // TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
1144 // match the full stack tests.
1145 Call::Config call_config(event_log_.get());
1146 call_config.bitrate_config = params_.call.call_bitrate_config;
Niels Möller2bf9e732017-08-14 11:26:16 +02001147
Artem Titov3faa8322018-03-07 14:44:00 +01001148 rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device =
1149 TestAudioDeviceModule::CreateTestAudioDeviceModule(
1150 TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
1151 TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
ivica5d6a06c2015-09-17 05:30:24 -07001152
eladalon413ee9a2017-08-22 04:02:52 -07001153 if (params_.audio.enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001154 AudioState::Config audio_state_config;
eladalon413ee9a2017-08-22 04:02:52 -07001155 audio_state_config.audio_mixer = AudioMixerImpl::Create();
Ivo Creusen62337e52018-01-09 14:17:33 +01001156 audio_state_config.audio_processing = AudioProcessingBuilder().Create();
Fredrik Solenberg2a877972017-12-15 16:42:15 +01001157 audio_state_config.audio_device_module = fake_audio_device;
eladalon413ee9a2017-08-22 04:02:52 -07001158 call_config.audio_state = AudioState::Create(audio_state_config);
Fredrik Solenbergd3195342017-11-21 20:33:05 +01001159 fake_audio_device->RegisterAudioCallback(
1160 call_config.audio_state->audio_transport());
eladalon413ee9a2017-08-22 04:02:52 -07001161 }
minyue73208662016-08-18 06:28:55 -07001162
eladalon413ee9a2017-08-22 04:02:52 -07001163 CreateCalls(call_config, call_config);
1164
1165 // TODO(minyue): consider if this is a good transport even for audio only
1166 // calls.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001167 send_transport = CreateSendTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001168
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001169 recv_transport = CreateReceiveTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001170
1171 // TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
1172 // least share as much code as possible. That way this test would also match
1173 // the full stack tests better.
1174 send_transport->SetReceiver(receiver_call_->Receiver());
1175 recv_transport->SetReceiver(sender_call_->Receiver());
1176
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001177 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001178 // Create video renderers.
1179 local_preview.reset(test::VideoRenderer::Create(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001180 "Local Preview", params_.video[0].width, params_.video[0].height));
eladalon413ee9a2017-08-22 04:02:52 -07001181
1182 SetupVideo(send_transport.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001183 video_send_configs_[0].pre_encode_callback = local_preview.get();
eladalon413ee9a2017-08-22 04:02:52 -07001184
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001185 size_t num_streams_processed = 0;
1186 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1187 const size_t selected_stream_id = params_.ss[video_idx].selected_stream;
1188 const size_t num_streams = params_.ss[video_idx].streams.size();
1189 if (selected_stream_id == num_streams) {
1190 for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
1191 std::ostringstream oss;
1192 oss << "Loopback Video #" << video_idx << " - Stream #"
1193 << static_cast<int>(stream_id);
1194 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1195 oss.str().c_str(),
1196 params_.ss[video_idx].streams[stream_id].width,
1197 params_.ss[video_idx].streams[stream_id].height));
1198 video_receive_configs_[stream_id + num_streams_processed].renderer =
1199 loopback_renderers.back().get();
1200 if (params_.audio.enabled && params_.audio.sync_video)
1201 video_receive_configs_[stream_id + num_streams_processed]
1202 .sync_group = kSyncGroup;
1203 }
1204 } else {
1205 std::ostringstream oss;
1206 oss << "Loopback Video #" << video_idx;
1207 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1208 oss.str().c_str(),
1209 params_.ss[video_idx].streams[selected_stream_id].width,
1210 params_.ss[video_idx].streams[selected_stream_id].height));
1211 video_receive_configs_[selected_stream_id + num_streams_processed]
1212 .renderer = loopback_renderers.back().get();
eladalon413ee9a2017-08-22 04:02:52 -07001213 if (params_.audio.enabled && params_.audio.sync_video)
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001214 video_receive_configs_[num_streams_processed + selected_stream_id]
1215 .sync_group = kSyncGroup;
eladalon413ee9a2017-08-22 04:02:52 -07001216 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001217 num_streams_processed += num_streams;
eladalon413ee9a2017-08-22 04:02:52 -07001218 }
eladalon413ee9a2017-08-22 04:02:52 -07001219 CreateFlexfecStreams();
1220 CreateVideoStreams();
1221
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001222 CreateCapturers();
1223 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1224 video_send_streams_[video_idx]->SetSource(
1225 video_capturers_[video_idx].get(), degradation_preference_);
1226 }
eladalon413ee9a2017-08-22 04:02:52 -07001227 }
1228
1229 if (params_.audio.enabled) {
Fredrik Solenberg8f5787a2018-01-11 13:52:30 +01001230 SetupAudio(send_transport.get(), &audio_receive_stream);
eladalon413ee9a2017-08-22 04:02:52 -07001231 }
1232
1233 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1234 StartEncodedFrameLogs(receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001235 StartEncodedFrameLogs(video_send_streams_[0]);
eladalon413ee9a2017-08-22 04:02:52 -07001236
1237 // Start sending and receiving video.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001238 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001239 for (VideoReceiveStream* video_receive_stream : video_receive_streams_)
1240 video_receive_stream->Start();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001241 for (VideoSendStream* video_send_stream : video_send_streams_)
1242 video_send_stream->Start();
1243 for (auto& video_capturer : video_capturers_)
1244 video_capturer->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001245 }
1246
1247 if (params_.audio.enabled) {
1248 // Start receiving audio.
1249 audio_receive_stream->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001250
1251 // Start sending audio.
1252 audio_send_stream_->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001253 }
1254 });
minyue73208662016-08-18 06:28:55 -07001255
ivica5d6a06c2015-09-17 05:30:24 -07001256 test::PressEnterToContinue();
1257
eladalon413ee9a2017-08-22 04:02:52 -07001258 task_queue_.SendTask([&]() {
1259 if (params_.audio.enabled) {
1260 // Stop sending audio.
eladalon413ee9a2017-08-22 04:02:52 -07001261 audio_send_stream_->Stop();
minyue73208662016-08-18 06:28:55 -07001262
eladalon413ee9a2017-08-22 04:02:52 -07001263 // Stop receiving audio.
eladalon413ee9a2017-08-22 04:02:52 -07001264 audio_receive_stream->Stop();
eladalon413ee9a2017-08-22 04:02:52 -07001265 }
minyue73208662016-08-18 06:28:55 -07001266
eladalon413ee9a2017-08-22 04:02:52 -07001267 // Stop receiving and sending video.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001268 if (params_.video[0].enabled) {
1269 for (auto& video_capturer : video_capturers_)
1270 video_capturer->Stop();
1271 for (VideoSendStream* video_send_stream : video_send_streams_)
1272 video_send_stream->Stop();
1273 DestroyStreams();
brandtr1293aca2016-11-16 22:47:29 -08001274 }
minyue73208662016-08-18 06:28:55 -07001275
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001276 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -07001277 send_transport.reset();
1278 recv_transport.reset();
sprang1168fd42017-06-21 09:00:17 -07001279
eladalon413ee9a2017-08-22 04:02:52 -07001280 local_preview.reset();
1281 loopback_renderers.clear();
1282
1283 DestroyCalls();
1284 });
ivica5d6a06c2015-09-17 05:30:24 -07001285}
1286
palmkviste75f2042016-09-28 06:19:48 -07001287void VideoQualityTest::StartEncodedFrameLogs(VideoSendStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001288 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001289 std::ostringstream str;
1290 str << send_logs_++;
1291 std::string prefix =
ilnik98436952017-07-13 00:47:03 -07001292 params_.logging.encoded_frame_base_path + "." + str.str() + ".send.";
palmkviste75f2042016-09-28 06:19:48 -07001293 stream->EnableEncodedFrameRecording(
1294 std::vector<rtc::PlatformFile>(
1295 {rtc::CreatePlatformFile(prefix + "1.ivf"),
1296 rtc::CreatePlatformFile(prefix + "2.ivf"),
1297 rtc::CreatePlatformFile(prefix + "3.ivf")}),
ilnik98436952017-07-13 00:47:03 -07001298 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001299 }
1300}
ilnikcb8c1462017-03-09 09:23:30 -08001301
palmkviste75f2042016-09-28 06:19:48 -07001302void VideoQualityTest::StartEncodedFrameLogs(VideoReceiveStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001303 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001304 std::ostringstream str;
1305 str << receive_logs_++;
1306 std::string path =
ilnik98436952017-07-13 00:47:03 -07001307 params_.logging.encoded_frame_base_path + "." + str.str() + ".recv.ivf";
palmkviste75f2042016-09-28 06:19:48 -07001308 stream->EnableEncodedFrameRecording(rtc::CreatePlatformFile(path),
ilnik98436952017-07-13 00:47:03 -07001309 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001310 }
1311}
ivica5d6a06c2015-09-17 05:30:24 -07001312} // namespace webrtc