blob: 071fe5f635ffb2a5e8f6ca5dc645d89cdb5ab3e1 [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
Sebastian Janssone6d7c3e2018-07-11 15:00:41 +020070std::unique_ptr<VideoEncoder> VideoQualityTest::CreateVideoEncoder(
Niels Möller4db138e2018-04-19 09:04:13 +020071 const SdpVideoFormat& format) {
72 if (format.name == "VP8") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020073 return absl::make_unique<VP8EncoderSimulcastProxy>(
74 &internal_encoder_factory_, format);
Niels Möller4db138e2018-04-19 09:04:13 +020075 } else if (format.name == "multiplex") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020076 return absl::make_unique<MultiplexEncoderAdapter>(
Niels Möller4db138e2018-04-19 09:04:13 +020077 &internal_encoder_factory_, SdpVideoFormat(cricket::kVp9CodecName));
Niels Möller4db138e2018-04-19 09:04:13 +020078 }
Emircan Uysaler0823eec2018-07-13 17:10:00 -070079 return internal_encoder_factory_.CreateVideoEncoder(format);
Niels Möller4db138e2018-04-19 09:04:13 +020080}
81
Patrik Höglundb6b29e02018-06-21 16:58:01 +020082VideoQualityTest::VideoQualityTest(
83 std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory)
Sebastian Janssone6d7c3e2018-07-11 15:00:41 +020084 : clock_(Clock::GetRealTimeClock()),
85 video_encoder_factory_([this](const SdpVideoFormat& format) {
86 return this->CreateVideoEncoder(format);
87 }),
88 receive_logs_(0),
89 send_logs_(0) {
minyue20c84cc2017-04-10 16:57:57 -070090 payload_type_map_ = test::CallTest::payload_type_map_;
91 RTC_DCHECK(payload_type_map_.find(kPayloadTypeH264) ==
92 payload_type_map_.end());
93 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP8) ==
94 payload_type_map_.end());
95 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP9) ==
96 payload_type_map_.end());
97 payload_type_map_[kPayloadTypeH264] = webrtc::MediaType::VIDEO;
98 payload_type_map_[kPayloadTypeVP8] = webrtc::MediaType::VIDEO;
99 payload_type_map_[kPayloadTypeVP9] = webrtc::MediaType::VIDEO;
ivica5d6a06c2015-09-17 05:30:24 -0700100
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100101 fec_controller_factory_ = std::move(fec_controller_factory);
Ying Wang3b790f32018-01-19 17:58:57 +0100102}
103
minyue626bc952016-10-31 05:47:02 -0700104VideoQualityTest::Params::Params()
Sebastian Janssonfc8d26b2018-02-21 09:52:06 +0100105 : call({false, BitrateConstraints(), 0}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100106 video{{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200107 false, false, ""},
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100108 {false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200109 false, false, ""}},
minyue4c8b9422017-03-21 04:11:43 -0700110 audio({false, false, false}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100111 screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
minyue626bc952016-10-31 05:47:02 -0700112 analyzer({"", 0.0, 0.0, 0, "", ""}),
113 pipe(),
Sergey Silkin57027362018-05-15 09:12:05 +0200114 ss{{std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
115 std::vector<SpatialLayer>()},
116 {std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
117 std::vector<SpatialLayer>()}},
Mirko Bonadei45a4c412018-07-31 15:07:28 +0200118 logging({"", "", ""}) {}
minyue626bc952016-10-31 05:47:02 -0700119
120VideoQualityTest::Params::~Params() = default;
121
ivica5d6a06c2015-09-17 05:30:24 -0700122void VideoQualityTest::TestBody() {}
123
sprangce4aef12015-11-02 07:23:20 -0800124std::string VideoQualityTest::GenerateGraphTitle() const {
125 std::stringstream ss;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100126 ss << params_.video[0].codec;
127 ss << " (" << params_.video[0].target_bitrate_bps / 1000 << "kbps";
128 ss << ", " << params_.video[0].fps << " FPS";
129 if (params_.screenshare[0].scroll_duration)
130 ss << ", " << params_.screenshare[0].scroll_duration << "s scroll";
131 if (params_.ss[0].streams.size() > 1)
132 ss << ", Stream #" << params_.ss[0].selected_stream;
133 if (params_.ss[0].num_spatial_layers > 1)
134 ss << ", Layer #" << params_.ss[0].selected_sl;
sprangce4aef12015-11-02 07:23:20 -0800135 ss << ")";
136 return ss.str();
137}
138
139void VideoQualityTest::CheckParams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100140 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
141 // Iterate over primary and secondary video streams.
142 if (!params_.video[video_idx].enabled)
143 return;
144 // Add a default stream in none specified.
145 if (params_.ss[video_idx].streams.empty())
146 params_.ss[video_idx].streams.push_back(
147 VideoQualityTest::DefaultVideoStream(params_, video_idx));
148 if (params_.ss[video_idx].num_spatial_layers == 0)
149 params_.ss[video_idx].num_spatial_layers = 1;
sprangce4aef12015-11-02 07:23:20 -0800150
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100151 if (params_.pipe.loss_percent != 0 ||
152 params_.pipe.queue_length_packets != 0) {
153 // Since LayerFilteringTransport changes the sequence numbers, we can't
154 // use that feature with pack loss, since the NACK request would end up
155 // retransmitting the wrong packets.
156 RTC_CHECK(params_.ss[video_idx].selected_sl == -1 ||
157 params_.ss[video_idx].selected_sl ==
158 params_.ss[video_idx].num_spatial_layers - 1);
159 RTC_CHECK(params_.video[video_idx].selected_tl == -1 ||
160 params_.video[video_idx].selected_tl ==
161 params_.video[video_idx].num_temporal_layers - 1);
162 }
sprangce4aef12015-11-02 07:23:20 -0800163
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100164 // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as
165 // it does in some parts of the code?
166 RTC_CHECK_GE(params_.video[video_idx].max_bitrate_bps,
167 params_.video[video_idx].target_bitrate_bps);
168 RTC_CHECK_GE(params_.video[video_idx].target_bitrate_bps,
169 params_.video[video_idx].min_bitrate_bps);
170 RTC_CHECK_LT(params_.video[video_idx].selected_tl,
171 params_.video[video_idx].num_temporal_layers);
172 RTC_CHECK_LE(params_.ss[video_idx].selected_stream,
173 params_.ss[video_idx].streams.size());
174 for (const VideoStream& stream : params_.ss[video_idx].streams) {
175 RTC_CHECK_GE(stream.min_bitrate_bps, 0);
176 RTC_CHECK_GE(stream.target_bitrate_bps, stream.min_bitrate_bps);
177 RTC_CHECK_GE(stream.max_bitrate_bps, stream.target_bitrate_bps);
178 }
179 // TODO(ivica): Should we check if the sum of all streams/layers is equal to
180 // the total bitrate? We anyway have to update them in the case bitrate
181 // estimator changes the total bitrates.
182 RTC_CHECK_GE(params_.ss[video_idx].num_spatial_layers, 1);
183 RTC_CHECK_LE(params_.ss[video_idx].selected_sl,
184 params_.ss[video_idx].num_spatial_layers);
185 RTC_CHECK(
186 params_.ss[video_idx].spatial_layers.empty() ||
187 params_.ss[video_idx].spatial_layers.size() ==
188 static_cast<size_t>(params_.ss[video_idx].num_spatial_layers));
189 if (params_.video[video_idx].codec == "VP8") {
190 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
191 } else if (params_.video[video_idx].codec == "VP9") {
192 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 1);
193 }
194 RTC_CHECK_GE(params_.call.num_thumbnails, 0);
195 if (params_.call.num_thumbnails > 0) {
196 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
197 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 3);
198 RTC_CHECK_EQ(params_.video[video_idx].num_temporal_layers, 3);
199 RTC_CHECK_EQ(params_.video[video_idx].codec, "VP8");
200 }
201 // Dual streams with FEC not supported in tests yet.
202 RTC_CHECK(!params_.video[video_idx].flexfec || num_video_streams_ == 1);
203 RTC_CHECK(!params_.video[video_idx].ulpfec || num_video_streams_ == 1);
ilnika014cc52017-03-07 04:21:04 -0800204 }
sprangce4aef12015-11-02 07:23:20 -0800205}
206
207// Static.
208std::vector<int> VideoQualityTest::ParseCSV(const std::string& str) {
209 // Parse comma separated nonnegative integers, where some elements may be
210 // empty. The empty values are replaced with -1.
211 // E.g. "10,-20,,30,40" --> {10, 20, -1, 30,40}
212 // E.g. ",,10,,20," --> {-1, -1, 10, -1, 20, -1}
213 std::vector<int> result;
214 if (str.empty())
215 return result;
216
217 const char* p = str.c_str();
218 int value = -1;
219 int pos;
220 while (*p) {
221 if (*p == ',') {
222 result.push_back(value);
223 value = -1;
224 ++p;
225 continue;
226 }
227 RTC_CHECK_EQ(sscanf(p, "%d%n", &value, &pos), 1)
228 << "Unexpected non-number value.";
229 p += pos;
230 }
231 result.push_back(value);
232 return result;
233}
234
235// Static.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100236VideoStream VideoQualityTest::DefaultVideoStream(const Params& params,
237 size_t video_idx) {
sprangce4aef12015-11-02 07:23:20 -0800238 VideoStream stream;
Danil Chapovalov350531e2018-06-08 11:04:04 +0000239 stream.width = params.video[video_idx].width;
240 stream.height = params.video[video_idx].height;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100241 stream.max_framerate = params.video[video_idx].fps;
242 stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps;
243 stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
244 stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
sprang1168fd42017-06-21 09:00:17 -0700245 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100246 stream.num_temporal_layers = params.video[video_idx].num_temporal_layers;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800247 stream.active = true;
ilnika014cc52017-03-07 04:21:04 -0800248 return stream;
249}
250
251// Static.
252VideoStream VideoQualityTest::DefaultThumbnailStream() {
253 VideoStream stream;
254 stream.width = 320;
255 stream.height = 180;
256 stream.max_framerate = 7;
257 stream.min_bitrate_bps = 7500;
258 stream.target_bitrate_bps = 37500;
259 stream.max_bitrate_bps = 50000;
sprang1168fd42017-06-21 09:00:17 -0700260 stream.max_qp = kDefaultMaxQp;
sprangce4aef12015-11-02 07:23:20 -0800261 return stream;
262}
263
264// Static.
265void VideoQualityTest::FillScalabilitySettings(
266 Params* params,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100267 size_t video_idx,
sprangce4aef12015-11-02 07:23:20 -0800268 const std::vector<std::string>& stream_descriptors,
sprang1168fd42017-06-21 09:00:17 -0700269 int num_streams,
sprangce4aef12015-11-02 07:23:20 -0800270 size_t selected_stream,
271 int num_spatial_layers,
272 int selected_sl,
Sergey Silkin57027362018-05-15 09:12:05 +0200273 InterLayerPredMode inter_layer_pred,
sprangce4aef12015-11-02 07:23:20 -0800274 const std::vector<std::string>& sl_descriptors) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100275 if (params->ss[video_idx].streams.empty() &&
276 params->ss[video_idx].infer_streams) {
sprang1168fd42017-06-21 09:00:17 -0700277 webrtc::VideoEncoderConfig encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200278 encoder_config.codec_type =
279 PayloadStringToCodecType(params->video[video_idx].codec);
sprang1168fd42017-06-21 09:00:17 -0700280 encoder_config.content_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100281 params->screenshare[video_idx].enabled
sprang1168fd42017-06-21 09:00:17 -0700282 ? webrtc::VideoEncoderConfig::ContentType::kScreen
283 : webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100284 encoder_config.max_bitrate_bps = params->video[video_idx].max_bitrate_bps;
285 encoder_config.min_transmit_bitrate_bps =
286 params->video[video_idx].min_transmit_bps;
sprang1168fd42017-06-21 09:00:17 -0700287 encoder_config.number_of_streams = num_streams;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100288 encoder_config.spatial_layers = params->ss[video_idx].spatial_layers;
Seth Hampson8234ead2018-02-02 15:16:24 -0800289 encoder_config.simulcast_layers = std::vector<VideoStream>(num_streams);
sprang1168fd42017-06-21 09:00:17 -0700290 encoder_config.video_stream_factory =
291 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100292 params->video[video_idx].codec, kDefaultMaxQp,
293 params->video[video_idx].fps,
294 params->screenshare[video_idx].enabled, true);
295 params->ss[video_idx].streams =
sprang1168fd42017-06-21 09:00:17 -0700296 encoder_config.video_stream_factory->CreateEncoderStreams(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100297 static_cast<int>(params->video[video_idx].width),
298 static_cast<int>(params->video[video_idx].height), encoder_config);
sprang1168fd42017-06-21 09:00:17 -0700299 } else {
300 // Read VideoStream and SpatialLayer elements from a list of comma separated
301 // lists. To use a default value for an element, use -1 or leave empty.
302 // Validity checks performed in CheckParams.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100303 RTC_CHECK(params->ss[video_idx].streams.empty());
sprang1168fd42017-06-21 09:00:17 -0700304 for (auto descriptor : stream_descriptors) {
305 if (descriptor.empty())
306 continue;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100307 VideoStream stream =
308 VideoQualityTest::DefaultVideoStream(*params, video_idx);
sprang1168fd42017-06-21 09:00:17 -0700309 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
310 if (v[0] != -1)
311 stream.width = static_cast<size_t>(v[0]);
312 if (v[1] != -1)
313 stream.height = static_cast<size_t>(v[1]);
314 if (v[2] != -1)
315 stream.max_framerate = v[2];
316 if (v[3] != -1)
317 stream.min_bitrate_bps = v[3];
318 if (v[4] != -1)
319 stream.target_bitrate_bps = v[4];
320 if (v[5] != -1)
321 stream.max_bitrate_bps = v[5];
322 if (v.size() > 6 && v[6] != -1)
323 stream.max_qp = v[6];
Sergey Silkina796a7e2018-03-01 15:11:29 +0100324 if (v.size() > 7 && v[7] != -1) {
325 stream.num_temporal_layers = v[7];
sprang1168fd42017-06-21 09:00:17 -0700326 } else {
327 // Automatic TL thresholds for more than two layers not supported.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100328 RTC_CHECK_LE(params->video[video_idx].num_temporal_layers, 2);
sprang1168fd42017-06-21 09:00:17 -0700329 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100330 params->ss[video_idx].streams.push_back(stream);
sprangce4aef12015-11-02 07:23:20 -0800331 }
sprangce4aef12015-11-02 07:23:20 -0800332 }
sprangce4aef12015-11-02 07:23:20 -0800333
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100334 params->ss[video_idx].num_spatial_layers = std::max(1, num_spatial_layers);
335 params->ss[video_idx].selected_stream = selected_stream;
sprang1168fd42017-06-21 09:00:17 -0700336
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100337 params->ss[video_idx].selected_sl = selected_sl;
Sergey Silkin57027362018-05-15 09:12:05 +0200338 params->ss[video_idx].inter_layer_pred = inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100339 RTC_CHECK(params->ss[video_idx].spatial_layers.empty());
sprangce4aef12015-11-02 07:23:20 -0800340 for (auto descriptor : sl_descriptors) {
341 if (descriptor.empty())
342 continue;
343 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
Sergey Silkin13e74342018-03-02 12:28:00 +0100344 RTC_CHECK_EQ(v.size(), 7);
sprangce4aef12015-11-02 07:23:20 -0800345
Sergey Silkin13e74342018-03-02 12:28:00 +0100346 SpatialLayer layer = {0};
347 layer.width = v[0];
348 layer.height = v[1];
349 layer.numberOfTemporalLayers = v[2];
350 layer.maxBitrate = v[3];
351 layer.minBitrate = v[4];
352 layer.targetBitrate = v[5];
353 layer.qpMax = v[6];
354 layer.active = true;
355
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100356 params->ss[video_idx].spatial_layers.push_back(layer);
sprangce4aef12015-11-02 07:23:20 -0800357 }
358}
359
minyuea27172d2016-11-01 05:59:29 -0700360void VideoQualityTest::SetupVideo(Transport* send_transport,
361 Transport* recv_transport) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100362 size_t total_streams_used = 0;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100363 video_receive_configs_.clear();
364 video_send_configs_.clear();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100365 video_encoder_configs_.clear();
366 allocated_decoders_.clear();
367 bool decode_all_receive_streams = true;
368 size_t num_video_substreams = params_.ss[0].streams.size();
369 RTC_CHECK(num_video_streams_ > 0);
370 video_encoder_configs_.resize(num_video_streams_);
371 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
372 video_send_configs_.push_back(VideoSendStream::Config(send_transport));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100373 video_encoder_configs_.push_back(VideoEncoderConfig());
374 num_video_substreams = params_.ss[video_idx].streams.size();
375 RTC_CHECK_GT(num_video_substreams, 0);
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200376 for (size_t i = 0; i < num_video_substreams; ++i)
377 video_send_configs_[video_idx].rtp.ssrcs.push_back(
378 kVideoSendSsrcs[total_streams_used + i]);
Qingsi Wang2d82ade2018-07-11 06:04:44 +0000379
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100380 int payload_type;
381 if (params_.video[video_idx].codec == "H264") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100382 payload_type = kPayloadTypeH264;
383 } else if (params_.video[video_idx].codec == "VP8") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100384 payload_type = kPayloadTypeVP8;
385 } else if (params_.video[video_idx].codec == "VP9") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100386 payload_type = kPayloadTypeVP9;
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800387 } else if (params_.video[video_idx].codec == "multiplex") {
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800388 payload_type = kPayloadTypeVP9;
ilnikcb8c1462017-03-09 09:23:30 -0800389 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100390 RTC_NOTREACHED() << "Codec not supported!";
391 return;
ilnikcb8c1462017-03-09 09:23:30 -0800392 }
Niels Möller4db138e2018-04-19 09:04:13 +0200393 video_send_configs_[video_idx].encoder_settings.encoder_factory =
394 &video_encoder_factory_;
395
Niels Möller259a4972018-04-05 15:36:51 +0200396 video_send_configs_[video_idx].rtp.payload_name =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100397 params_.video[video_idx].codec;
Niels Möller259a4972018-04-05 15:36:51 +0200398 video_send_configs_[video_idx].rtp.payload_type = payload_type;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100399 video_send_configs_[video_idx].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
400 video_send_configs_[video_idx].rtp.rtx.payload_type = kSendRtxPayloadType;
401 for (size_t i = 0; i < num_video_substreams; ++i) {
402 video_send_configs_[video_idx].rtp.rtx.ssrcs.push_back(
403 kSendRtxSsrcs[i + total_streams_used]);
ilnik9fd9f6c2017-03-02 08:10:10 -0800404 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100405 video_send_configs_[video_idx].rtp.extensions.clear();
406 if (params_.call.send_side_bwe) {
407 video_send_configs_[video_idx].rtp.extensions.push_back(
408 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
409 test::kTransportSequenceNumberExtensionId));
410 } else {
411 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
412 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
413 }
414 video_send_configs_[video_idx].rtp.extensions.push_back(
415 RtpExtension(RtpExtension::kVideoContentTypeUri,
416 test::kVideoContentTypeExtensionId));
417 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
418 RtpExtension::kVideoTimingUri, test::kVideoTimingExtensionId));
419
Niels Möller4db138e2018-04-19 09:04:13 +0200420 video_encoder_configs_[video_idx].video_format.name =
421 params_.video[video_idx].codec;
422
Emircan Uysaler0823eec2018-07-13 17:10:00 -0700423 video_encoder_configs_[video_idx].video_format.parameters =
424 params_.video[video_idx].sdp_params;
425
Niels Möller259a4972018-04-05 15:36:51 +0200426 video_encoder_configs_[video_idx].codec_type =
427 PayloadStringToCodecType(params_.video[video_idx].codec);
428
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100429 video_encoder_configs_[video_idx].min_transmit_bitrate_bps =
430 params_.video[video_idx].min_transmit_bps;
431
432 video_send_configs_[video_idx].suspend_below_min_bitrate =
433 params_.video[video_idx].suspend_below_min_bitrate;
434
435 video_encoder_configs_[video_idx].number_of_streams =
436 params_.ss[video_idx].streams.size();
437 video_encoder_configs_[video_idx].max_bitrate_bps = 0;
438 for (size_t i = 0; i < params_.ss[video_idx].streams.size(); ++i) {
439 video_encoder_configs_[video_idx].max_bitrate_bps +=
440 params_.ss[video_idx].streams[i].max_bitrate_bps;
441 }
442 if (params_.ss[video_idx].infer_streams) {
Seth Hampson8234ead2018-02-02 15:16:24 -0800443 video_encoder_configs_[video_idx].simulcast_layers =
444 std::vector<VideoStream>(params_.ss[video_idx].streams.size());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100445 video_encoder_configs_[video_idx].video_stream_factory =
446 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
447 params_.video[video_idx].codec,
448 params_.ss[video_idx].streams[0].max_qp,
449 params_.video[video_idx].fps,
450 params_.screenshare[video_idx].enabled, true);
451 } else {
452 video_encoder_configs_[video_idx].video_stream_factory =
453 new rtc::RefCountedObject<VideoStreamFactory>(
454 params_.ss[video_idx].streams);
455 }
456
457 video_encoder_configs_[video_idx].spatial_layers =
458 params_.ss[video_idx].spatial_layers;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100459 decode_all_receive_streams = params_.ss[video_idx].selected_stream ==
460 params_.ss[video_idx].streams.size();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200461 absl::optional<int> decode_sub_stream;
462 if (!decode_all_receive_streams)
463 decode_sub_stream = params_.ss[video_idx].selected_stream;
464 CreateMatchingVideoReceiveConfigs(
465 video_send_configs_[video_idx], recv_transport,
466 params_.call.send_side_bwe, decode_sub_stream, true, kNackRtpHistoryMs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100467
468 if (params_.screenshare[video_idx].enabled) {
469 // Fill out codec settings.
470 video_encoder_configs_[video_idx].content_type =
471 VideoEncoderConfig::ContentType::kScreen;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700472 degradation_preference_ = DegradationPreference::MAINTAIN_RESOLUTION;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100473 if (params_.video[video_idx].codec == "VP8") {
474 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
475 vp8_settings.denoisingOn = false;
476 vp8_settings.frameDroppingOn = false;
477 vp8_settings.numberOfTemporalLayers = static_cast<unsigned char>(
478 params_.video[video_idx].num_temporal_layers);
479 video_encoder_configs_[video_idx].encoder_specific_settings =
480 new rtc::RefCountedObject<
481 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
482 } else if (params_.video[video_idx].codec == "VP9") {
483 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
484 vp9_settings.denoisingOn = false;
485 vp9_settings.frameDroppingOn = false;
486 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
487 params_.video[video_idx].num_temporal_layers);
488 vp9_settings.numberOfSpatialLayers = static_cast<unsigned char>(
489 params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200490 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100491 video_encoder_configs_[video_idx].encoder_specific_settings =
492 new rtc::RefCountedObject<
493 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
494 }
495 } else if (params_.ss[video_idx].num_spatial_layers > 1) {
496 // If SVC mode without screenshare, still need to set codec specifics.
497 RTC_CHECK(params_.video[video_idx].codec == "VP9");
498 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
499 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
500 params_.video[video_idx].num_temporal_layers);
501 vp9_settings.numberOfSpatialLayers =
502 static_cast<unsigned char>(params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200503 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100504 video_encoder_configs_[video_idx].encoder_specific_settings =
505 new rtc::RefCountedObject<
506 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Niels Möller6aa415e2018-06-07 11:14:13 +0200507 } else if (params_.video[video_idx].automatic_scaling) {
508 if (params_.video[video_idx].codec == "VP8") {
509 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
510 vp8_settings.automaticResizeOn = true;
511 video_encoder_configs_[video_idx].encoder_specific_settings =
512 new rtc::RefCountedObject<
513 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
514 } else if (params_.video[video_idx].codec == "VP9") {
515 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
516 vp9_settings.automaticResizeOn = true;
517 video_encoder_configs_[video_idx].encoder_specific_settings =
518 new rtc::RefCountedObject<
519 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
520 } else {
521 RTC_NOTREACHED() << "Automatic scaling not supported for codec "
Yves Gerey665174f2018-06-19 15:03:05 +0200522 << params_.video[video_idx].codec << ", stream "
523 << video_idx;
Niels Möller6aa415e2018-06-07 11:14:13 +0200524 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100525 }
526 total_streams_used += num_video_substreams;
sprangce4aef12015-11-02 07:23:20 -0800527 }
brandtr1293aca2016-11-16 22:47:29 -0800528
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100529 // FEC supported only for single video stream mode yet.
530 if (params_.video[0].flexfec) {
sprang1168fd42017-06-21 09:00:17 -0700531 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200532 SetSendFecConfig(GetVideoSendConfig()->rtp.ssrcs);
sprang1168fd42017-06-21 09:00:17 -0700533 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200534 SetSendFecConfig({kVideoSendSsrcs[params_.ss[0].selected_stream]});
sprang1168fd42017-06-21 09:00:17 -0700535 }
brandtr1293aca2016-11-16 22:47:29 -0800536
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200537 CreateMatchingFecConfig(recv_transport, *GetVideoSendConfig());
538 GetFlexFecConfig()->transport_cc = params_.call.send_side_bwe;
brandtrb29e6522016-12-21 06:37:18 -0800539 if (params_.call.send_side_bwe) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200540 GetFlexFecConfig()->rtp_header_extensions.push_back(
brandtrb29e6522016-12-21 06:37:18 -0800541 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
542 test::kTransportSequenceNumberExtensionId));
543 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200544 GetFlexFecConfig()->rtp_header_extensions.push_back(RtpExtension(
brandtrb29e6522016-12-21 06:37:18 -0800545 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
546 }
brandtr1293aca2016-11-16 22:47:29 -0800547 }
548
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100549 if (params_.video[0].ulpfec) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200550 SetSendUlpFecConfig(GetVideoSendConfig());
sprang1168fd42017-06-21 09:00:17 -0700551 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200552 for (auto& receive_config : video_receive_configs_) {
553 SetReceiveUlpFecConfig(&receive_config);
sprang1168fd42017-06-21 09:00:17 -0700554 }
555 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200556 SetReceiveUlpFecConfig(
557 &video_receive_configs_[params_.ss[0].selected_stream]);
sprang1168fd42017-06-21 09:00:17 -0700558 }
brandtr1293aca2016-11-16 22:47:29 -0800559 }
ivica5d6a06c2015-09-17 05:30:24 -0700560}
561
ilnika014cc52017-03-07 04:21:04 -0800562void VideoQualityTest::SetupThumbnails(Transport* send_transport,
563 Transport* recv_transport) {
ilnik98436952017-07-13 00:47:03 -0700564 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 04:21:04 -0800565 // Thumbnails will be send in the other way: from receiver_call to
566 // sender_call.
567 VideoSendStream::Config thumbnail_send_config(recv_transport);
568 thumbnail_send_config.rtp.ssrcs.push_back(kThumbnailSendSsrcStart + i);
Niels Möller4db138e2018-04-19 09:04:13 +0200569 // TODO(nisse): Could use a simpler VP8-only encoder factory.
570 thumbnail_send_config.encoder_settings.encoder_factory =
571 &video_encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200572 thumbnail_send_config.rtp.payload_name = params_.video[0].codec;
573 thumbnail_send_config.rtp.payload_type = kPayloadTypeVP8;
ilnika014cc52017-03-07 04:21:04 -0800574 thumbnail_send_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
575 thumbnail_send_config.rtp.rtx.payload_type = kSendRtxPayloadType;
576 thumbnail_send_config.rtp.rtx.ssrcs.push_back(kThumbnailRtxSsrcStart + i);
577 thumbnail_send_config.rtp.extensions.clear();
578 if (params_.call.send_side_bwe) {
579 thumbnail_send_config.rtp.extensions.push_back(
580 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
581 test::kTransportSequenceNumberExtensionId));
582 } else {
583 thumbnail_send_config.rtp.extensions.push_back(RtpExtension(
584 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
585 }
586
587 VideoEncoderConfig thumbnail_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200588 thumbnail_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller4db138e2018-04-19 09:04:13 +0200589 thumbnail_encoder_config.video_format.name = "VP8";
ilnika014cc52017-03-07 04:21:04 -0800590 thumbnail_encoder_config.min_transmit_bitrate_bps = 7500;
591 thumbnail_send_config.suspend_below_min_bitrate =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100592 params_.video[0].suspend_below_min_bitrate;
ilnika014cc52017-03-07 04:21:04 -0800593 thumbnail_encoder_config.number_of_streams = 1;
594 thumbnail_encoder_config.max_bitrate_bps = 50000;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100595 if (params_.ss[0].infer_streams) {
ilnik6b826ef2017-06-16 06:53:48 -0700596 thumbnail_encoder_config.video_stream_factory =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100597 new rtc::RefCountedObject<VideoStreamFactory>(params_.ss[0].streams);
ilnik6b826ef2017-06-16 06:53:48 -0700598 } else {
Seth Hampson8234ead2018-02-02 15:16:24 -0800599 thumbnail_encoder_config.simulcast_layers = std::vector<VideoStream>(1);
ilnik6b826ef2017-06-16 06:53:48 -0700600 thumbnail_encoder_config.video_stream_factory =
601 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100602 params_.video[0].codec, params_.ss[0].streams[0].max_qp,
603 params_.video[0].fps, params_.screenshare[0].enabled, true);
ilnik6b826ef2017-06-16 06:53:48 -0700604 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100605 thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers;
ilnika014cc52017-03-07 04:21:04 -0800606
ilnika014cc52017-03-07 04:21:04 -0800607 thumbnail_encoder_configs_.push_back(thumbnail_encoder_config.Copy());
608 thumbnail_send_configs_.push_back(thumbnail_send_config.Copy());
ilnika014cc52017-03-07 04:21:04 -0800609
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200610 AddMatchingVideoReceiveConfigs(
611 &thumbnail_receive_configs_, thumbnail_send_config, send_transport,
612 params_.call.send_side_bwe, absl::nullopt, false, kNackRtpHistoryMs);
613 }
614 for (size_t i = 0; i < thumbnail_send_configs_.size(); ++i) {
ilnika014cc52017-03-07 04:21:04 -0800615 thumbnail_send_streams_.push_back(receiver_call_->CreateVideoSendStream(
616 thumbnail_send_configs_[i].Copy(),
617 thumbnail_encoder_configs_[i].Copy()));
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200618 }
619 for (size_t i = 0; i < thumbnail_receive_configs_.size(); ++i) {
ilnika014cc52017-03-07 04:21:04 -0800620 thumbnail_receive_streams_.push_back(sender_call_->CreateVideoReceiveStream(
621 thumbnail_receive_configs_[i].Copy()));
622 }
623}
624
625void VideoQualityTest::DestroyThumbnailStreams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100626 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800627 receiver_call_->DestroyVideoSendStream(thumbnail_send_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100628 }
ilnika014cc52017-03-07 04:21:04 -0800629 thumbnail_send_streams_.clear();
630 for (VideoReceiveStream* thumbnail_receive_stream :
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100631 thumbnail_receive_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800632 sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100633 }
ilnika014cc52017-03-07 04:21:04 -0800634 thumbnail_send_streams_.clear();
635 thumbnail_receive_streams_.clear();
eladalon413ee9a2017-08-22 04:02:52 -0700636 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
637 thumbnail_capturers_) {
638 video_caputurer.reset();
639 }
ilnika014cc52017-03-07 04:21:04 -0800640}
641
ilnika014cc52017-03-07 04:21:04 -0800642void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) {
643 VideoStream thumbnail = DefaultThumbnailStream();
644 for (size_t i = 0; i < num_thumbnail_streams; ++i) {
645 thumbnail_capturers_.emplace_back(test::FrameGeneratorCapturer::Create(
646 static_cast<int>(thumbnail.width), static_cast<int>(thumbnail.height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200647 absl::nullopt, absl::nullopt, thumbnail.max_framerate, clock_));
ilnikf89a7382017-03-07 06:15:27 -0800648 RTC_DCHECK(thumbnail_capturers_.back());
ilnika014cc52017-03-07 04:21:04 -0800649 }
650}
651
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100652std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator(
653 size_t video_idx) {
654 // Setup frame generator.
655 const size_t kWidth = 1850;
656 const size_t kHeight = 1110;
657 std::unique_ptr<test::FrameGenerator> frame_generator;
658 if (params_.screenshare[video_idx].generate_slides) {
659 frame_generator = test::FrameGenerator::CreateSlideGenerator(
660 kWidth, kHeight,
661 params_.screenshare[video_idx].slide_change_interval *
662 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700663 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100664 std::vector<std::string> slides = params_.screenshare[video_idx].slides;
665 if (slides.size() == 0) {
666 slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
667 slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
668 slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
669 slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
670 }
671 if (params_.screenshare[video_idx].scroll_duration == 0) {
672 // Cycle image every slide_change_interval seconds.
673 frame_generator = test::FrameGenerator::CreateFromYuvFile(
674 slides, kWidth, kHeight,
675 params_.screenshare[video_idx].slide_change_interval *
676 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700677 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100678 RTC_CHECK_LE(params_.video[video_idx].width, kWidth);
679 RTC_CHECK_LE(params_.video[video_idx].height, kHeight);
680 RTC_CHECK_GT(params_.screenshare[video_idx].slide_change_interval, 0);
681 const int kPauseDurationMs =
682 (params_.screenshare[video_idx].slide_change_interval -
683 params_.screenshare[video_idx].scroll_duration) *
684 1000;
685 RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration,
686 params_.screenshare[video_idx].slide_change_interval);
687
688 frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
689 clock_, slides, kWidth, kHeight, params_.video[video_idx].width,
690 params_.video[video_idx].height,
691 params_.screenshare[video_idx].scroll_duration * 1000,
692 kPauseDurationMs);
ivica5d6a06c2015-09-17 05:30:24 -0700693 }
694 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100695 return frame_generator;
696}
697
698void VideoQualityTest::CreateCapturers() {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200699 RTC_DCHECK(video_sources_.empty());
700 RTC_DCHECK(video_capturers_.empty());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100701 video_capturers_.resize(num_video_streams_);
702 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
703 if (params_.screenshare[video_idx].enabled) {
704 std::unique_ptr<test::FrameGenerator> frame_generator =
705 CreateFrameGenerator(video_idx);
706 test::FrameGeneratorCapturer* frame_generator_capturer =
707 new test::FrameGeneratorCapturer(clock_, std::move(frame_generator),
708 params_.video[video_idx].fps);
709 EXPECT_TRUE(frame_generator_capturer->Init());
710 video_capturers_[video_idx].reset(frame_generator_capturer);
711 } else {
712 if (params_.video[video_idx].clip_name == "Generator") {
713 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
714 static_cast<int>(params_.video[video_idx].width),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200715 static_cast<int>(params_.video[video_idx].height), absl::nullopt,
716 absl::nullopt, params_.video[video_idx].fps, clock_));
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800717 } else if (params_.video[video_idx].clip_name == "GeneratorI420A") {
718 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
719 static_cast<int>(params_.video[video_idx].width),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100720 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200721 test::FrameGenerator::OutputType::I420A, absl::nullopt,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100722 params_.video[video_idx].fps, clock_));
Emircan Uysaler0823eec2018-07-13 17:10:00 -0700723 } else if (params_.video[video_idx].clip_name == "GeneratorI010") {
724 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
725 static_cast<int>(params_.video[video_idx].width),
726 static_cast<int>(params_.video[video_idx].height),
727 test::FrameGenerator::OutputType::I010, absl::nullopt,
728 params_.video[video_idx].fps, clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100729 } else if (params_.video[video_idx].clip_name.empty()) {
730 video_capturers_[video_idx].reset(test::VcmCapturer::Create(
731 params_.video[video_idx].width, params_.video[video_idx].height,
732 params_.video[video_idx].fps,
733 params_.video[video_idx].capture_device_index));
734 if (!video_capturers_[video_idx]) {
735 // Failed to get actual camera, use chroma generator as backup.
736 video_capturers_[video_idx].reset(
737 test::FrameGeneratorCapturer::Create(
738 static_cast<int>(params_.video[video_idx].width),
739 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200740 absl::nullopt, absl::nullopt, params_.video[video_idx].fps,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800741 clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100742 }
743 } else {
744 video_capturers_[video_idx].reset(
745 test::FrameGeneratorCapturer::CreateFromYuvFile(
746 test::ResourcePath(params_.video[video_idx].clip_name, "yuv"),
747 params_.video[video_idx].width, params_.video[video_idx].height,
748 params_.video[video_idx].fps, clock_));
749 ASSERT_TRUE(video_capturers_[video_idx])
750 << "Could not create capturer for "
751 << params_.video[video_idx].clip_name
752 << ".yuv. Is this resource file present?";
753 }
754 }
755 RTC_DCHECK(video_capturers_[video_idx].get());
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200756 video_sources_.push_back(video_capturers_[video_idx].get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100757 }
ivica5d6a06c2015-09-17 05:30:24 -0700758}
759
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200760void VideoQualityTest::StartThumbnails() {
761 for (VideoSendStream* send_stream : thumbnail_send_streams_)
762 send_stream->Start();
763 for (VideoReceiveStream* receive_stream : thumbnail_receive_streams_)
764 receive_stream->Start();
765 for (std::unique_ptr<test::VideoCapturer>& capturer : thumbnail_capturers_)
766 capturer->Start();
767}
768
769void VideoQualityTest::StopThumbnails() {
770 for (std::unique_ptr<test::VideoCapturer>& capturer : thumbnail_capturers_)
771 capturer->Stop();
772 for (VideoReceiveStream* receive_stream : thumbnail_receive_streams_)
773 receive_stream->Stop();
774 for (VideoSendStream* send_stream : thumbnail_send_streams_)
775 send_stream->Stop();
776}
777
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100778std::unique_ptr<test::LayerFilteringTransport>
779VideoQualityTest::CreateSendTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200780 return absl::make_unique<test::LayerFilteringTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100781 &task_queue_, params_.pipe, sender_call_.get(), kPayloadTypeVP8,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100782 kPayloadTypeVP9, params_.video[0].selected_tl, params_.ss[0].selected_sl,
783 payload_type_map_, kVideoSendSsrcs[0],
784 static_cast<uint32_t>(kVideoSendSsrcs[0] + params_.ss[0].streams.size() -
785 1));
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100786}
787
788std::unique_ptr<test::DirectTransport>
789VideoQualityTest::CreateReceiveTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200790 return absl::make_unique<test::DirectTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100791 &task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_);
792}
793
sprang7a975f72015-10-12 06:33:21 -0700794void VideoQualityTest::RunWithAnalyzer(const Params& params) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100795 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -0700796 std::unique_ptr<test::LayerFilteringTransport> send_transport;
797 std::unique_ptr<test::DirectTransport> recv_transport;
798 FILE* graph_data_output_file = nullptr;
799 std::unique_ptr<VideoAnalyzer> analyzer;
800
sprangce4aef12015-11-02 07:23:20 -0800801 params_ = params;
ivica5d6a06c2015-09-17 05:30:24 -0700802 // TODO(ivica): Merge with RunWithRenderer and use a flag / argument to
803 // differentiate between the analyzer and the renderer case.
sprangce4aef12015-11-02 07:23:20 -0800804 CheckParams();
ivica5d6a06c2015-09-17 05:30:24 -0700805
sprangce4aef12015-11-02 07:23:20 -0800806 if (!params_.analyzer.graph_data_output_filename.empty()) {
ivica5d6a06c2015-09-17 05:30:24 -0700807 graph_data_output_file =
sprangce4aef12015-11-02 07:23:20 -0800808 fopen(params_.analyzer.graph_data_output_filename.c_str(), "w");
Peter Boström74f6e9e2016-04-04 17:56:10 +0200809 RTC_CHECK(graph_data_output_file)
sprangce4aef12015-11-02 07:23:20 -0800810 << "Can't open the file " << params_.analyzer.graph_data_output_filename
811 << "!";
ivica87f83a92015-10-08 05:13:32 -0700812 }
sprang7a975f72015-10-12 06:33:21 -0700813
ilnik98436952017-07-13 00:47:03 -0700814 if (!params.logging.rtc_event_log_name.empty()) {
Bjorn Terelius0a6a2b72018-01-19 17:52:38 +0100815 send_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
816 recv_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100817 std::unique_ptr<RtcEventLogOutputFile> send_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200818 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100819 params.logging.rtc_event_log_name + "_send",
820 RtcEventLog::kUnlimitedOutput));
821 std::unique_ptr<RtcEventLogOutputFile> recv_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200822 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100823 params.logging.rtc_event_log_name + "_recv",
824 RtcEventLog::kUnlimitedOutput));
825 bool event_log_started =
826 send_event_log_->StartLogging(std::move(send_output),
827 RtcEventLog::kImmediateOutput) &&
828 recv_event_log_->StartLogging(std::move(recv_output),
829 RtcEventLog::kImmediateOutput);
ilnik98436952017-07-13 00:47:03 -0700830 RTC_DCHECK(event_log_started);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100831 } else {
832 send_event_log_ = RtcEventLog::CreateNull();
833 recv_event_log_ = RtcEventLog::CreateNull();
ilnik98436952017-07-13 00:47:03 -0700834 }
835
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100836 Call::Config send_call_config(send_event_log_.get());
837 Call::Config recv_call_config(recv_event_log_.get());
838 send_call_config.bitrate_config = params.call.call_bitrate_config;
839 recv_call_config.bitrate_config = params.call.call_bitrate_config;
stefanf116bd02015-10-27 08:29:42 -0700840
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100841 task_queue_.SendTask([this, &send_call_config, &recv_call_config,
842 &send_transport, &recv_transport]() {
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200843 if (params_.audio.enabled) {
844 InitializeAudioDevice(&send_call_config, &recv_call_config);
845 }
846
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100847 CreateCalls(send_call_config, recv_call_config);
848 send_transport = CreateSendTransport();
849 recv_transport = CreateReceiveTransport();
850 });
stefanf116bd02015-10-27 08:29:42 -0700851
sprangce4aef12015-11-02 07:23:20 -0800852 std::string graph_title = params_.analyzer.graph_title;
853 if (graph_title.empty())
854 graph_title = VideoQualityTest::GenerateGraphTitle();
sprangc1b57a12017-02-28 08:50:47 -0800855 bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
Karl Wiberg918f50c2018-07-05 11:40:33 +0200856 analyzer = absl::make_unique<VideoAnalyzer>(
eladalon413ee9a2017-08-22 04:02:52 -0700857 send_transport.get(), params_.analyzer.test_label,
ilnik2a8c2f52017-02-15 02:23:28 -0800858 params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
ilnik9ae0d762017-02-15 00:53:12 -0800859 is_quick_test_enabled
860 ? kFramesSentInQuickTest
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100861 : params_.analyzer.test_durations_secs * params_.video[0].fps,
sprangce4aef12015-11-02 07:23:20 -0800862 graph_data_output_file, graph_title,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100863 kVideoSendSsrcs[params_.ss[0].selected_stream],
864 kSendRtxSsrcs[params_.ss[0].selected_stream],
865 static_cast<size_t>(params_.ss[0].selected_stream),
866 params.ss[0].selected_sl, params_.video[0].selected_tl,
867 is_quick_test_enabled, clock_, params_.logging.rtp_dump_name);
ivica5d6a06c2015-09-17 05:30:24 -0700868
eladalon413ee9a2017-08-22 04:02:52 -0700869 task_queue_.SendTask([&]() {
870 analyzer->SetCall(sender_call_.get());
871 analyzer->SetReceiver(receiver_call_->Receiver());
872 send_transport->SetReceiver(analyzer.get());
873 recv_transport->SetReceiver(sender_call_->Receiver());
ivica5d6a06c2015-09-17 05:30:24 -0700874
eladalon413ee9a2017-08-22 04:02:52 -0700875 SetupVideo(analyzer.get(), recv_transport.get());
876 SetupThumbnails(analyzer.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100877 video_receive_configs_[params_.ss[0].selected_stream].renderer =
eladalon413ee9a2017-08-22 04:02:52 -0700878 analyzer.get();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200879 GetVideoSendConfig()->pre_encode_callback = analyzer->pre_encode_proxy();
880 RTC_DCHECK(!GetVideoSendConfig()->post_encode_callback);
881 GetVideoSendConfig()->post_encode_callback = analyzer.get();
kthelgason2bc68642017-02-07 07:02:22 -0800882
eladalon413ee9a2017-08-22 04:02:52 -0700883 CreateFlexfecStreams();
884 CreateVideoStreams();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100885 analyzer->SetSendStream(video_send_streams_[0]);
eladalon413ee9a2017-08-22 04:02:52 -0700886 if (video_receive_streams_.size() == 1)
887 analyzer->SetReceiveStream(video_receive_streams_[0]);
ivica5d6a06c2015-09-17 05:30:24 -0700888
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200889 GetVideoSendStream()->SetSource(analyzer->OutputInterface(),
890 degradation_preference_);
eladalon413ee9a2017-08-22 04:02:52 -0700891 SetupThumbnailCapturers(params_.call.num_thumbnails);
892 for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
893 thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
894 degradation_preference_);
895 }
ilnika014cc52017-03-07 04:21:04 -0800896
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100897 CreateCapturers();
ivicac1cc8542015-10-08 03:44:06 -0700898
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100899 analyzer->SetSource(video_capturers_[0].get(), params_.ss[0].infer_streams);
ilnika014cc52017-03-07 04:21:04 -0800900
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100901 for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) {
902 video_send_streams_[video_idx]->SetSource(
903 video_capturers_[video_idx].get(), degradation_preference_);
904 }
905
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200906 StartEncodedFrameLogs(GetVideoSendStream());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100907 StartEncodedFrameLogs(
908 video_receive_streams_[params_.ss[0].selected_stream]);
ilnika014cc52017-03-07 04:21:04 -0800909
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200910 if (params_.audio.enabled) {
911 SetupAudio(send_transport.get());
eladalon413ee9a2017-08-22 04:02:52 -0700912 }
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200913 StartThumbnails();
914 Start();
915
916 if (params_.audio.enabled) {
917 analyzer->SetAudioReceiveStream(audio_receive_streams_[0]);
918 }
919 analyzer->StartMeasuringCpuProcessTime();
eladalon413ee9a2017-08-22 04:02:52 -0700920 });
ivica5d6a06c2015-09-17 05:30:24 -0700921
eladalon413ee9a2017-08-22 04:02:52 -0700922 analyzer->Wait();
ivica5d6a06c2015-09-17 05:30:24 -0700923
eladalon413ee9a2017-08-22 04:02:52 -0700924 task_queue_.SendTask([&]() {
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200925 StopThumbnails();
926 Stop();
ivica5d6a06c2015-09-17 05:30:24 -0700927
eladalon413ee9a2017-08-22 04:02:52 -0700928 DestroyStreams();
929 DestroyThumbnailStreams();
ivica5d6a06c2015-09-17 05:30:24 -0700930
eladalon413ee9a2017-08-22 04:02:52 -0700931 if (graph_data_output_file)
932 fclose(graph_data_output_file);
933
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100934 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -0700935 send_transport.reset();
936 recv_transport.reset();
937
938 DestroyCalls();
939 });
ivica5d6a06c2015-09-17 05:30:24 -0700940}
941
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200942void VideoQualityTest::InitializeAudioDevice(Call::Config* send_call_config,
943 Call::Config* recv_call_config) {
944 rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device =
945 TestAudioDeviceModule::CreateTestAudioDeviceModule(
946 TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
947 TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
948
949 AudioState::Config audio_state_config;
950 audio_state_config.audio_mixer = AudioMixerImpl::Create();
951 audio_state_config.audio_processing = AudioProcessingBuilder().Create();
952 audio_state_config.audio_device_module = fake_audio_device;
953 send_call_config->audio_state = AudioState::Create(audio_state_config);
954 RTC_CHECK(fake_audio_device->RegisterAudioCallback(
955 send_call_config->audio_state->audio_transport()) == 0);
956 recv_call_config->audio_state = AudioState::Create(audio_state_config);
957 fake_audio_device->Init();
958}
959
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200960void VideoQualityTest::SetupAudio(Transport* transport) {
961 AudioSendStream::Config audio_send_config(transport);
962 audio_send_config.rtp.ssrc = kAudioSendSsrc;
minyuea27172d2016-11-01 05:59:29 -0700963
964 // Add extension to enable audio send side BWE, and allow audio bit rate
965 // adaptation.
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200966 audio_send_config.rtp.extensions.clear();
967 audio_send_config.send_codec_spec = AudioSendStream::Config::SendCodecSpec(
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100968 kAudioSendPayloadType,
Yves Gerey665174f2018-06-19 15:03:05 +0200969 {"OPUS",
970 48000,
971 2,
972 {{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}});
minyuea27172d2016-11-01 05:59:29 -0700973
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200974 if (params_.call.send_side_bwe) {
975 audio_send_config.rtp.extensions.push_back(
976 webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri,
977 test::kTransportSequenceNumberExtensionId));
978 audio_send_config.min_bitrate_bps = kOpusMinBitrateBps;
979 audio_send_config.max_bitrate_bps = kOpusBitrateFbBps;
980 audio_send_config.send_codec_spec->transport_cc_enabled = true;
981 }
982 audio_send_config.encoder_factory = audio_encoder_factory_;
983 SetAudioConfig(audio_send_config);
984
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200985 std::string sync_group;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100986 if (params_.video[0].enabled && params_.audio.sync_video)
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200987 sync_group = kSyncGroup;
minyuea27172d2016-11-01 05:59:29 -0700988
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200989 CreateMatchingAudioConfigs(transport, sync_group);
990 CreateAudioStreams();
minyuea27172d2016-11-01 05:59:29 -0700991}
992
minyue73208662016-08-18 06:28:55 -0700993void VideoQualityTest::RunWithRenderers(const Params& params) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100994 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -0700995 std::unique_ptr<test::LayerFilteringTransport> send_transport;
996 std::unique_ptr<test::DirectTransport> recv_transport;
minyuea27172d2016-11-01 05:59:29 -0700997 std::unique_ptr<test::VideoRenderer> local_preview;
eladalon413ee9a2017-08-22 04:02:52 -0700998 std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
Sebastian Jansson8e6602f2018-07-13 10:43:20 +0200999 RtcEventLogNullImpl null_event_log;
minyue73208662016-08-18 06:28:55 -07001000
eladalon413ee9a2017-08-22 04:02:52 -07001001 task_queue_.SendTask([&]() {
1002 params_ = params;
1003 CheckParams();
palmkviste75f2042016-09-28 06:19:48 -07001004
eladalon413ee9a2017-08-22 04:02:52 -07001005 // TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
1006 // match the full stack tests.
Sebastian Jansson8e6602f2018-07-13 10:43:20 +02001007 Call::Config call_config(&null_event_log);
eladalon413ee9a2017-08-22 04:02:52 -07001008 call_config.bitrate_config = params_.call.call_bitrate_config;
Niels Möller2bf9e732017-08-14 11:26:16 +02001009
Christoffer Rodbroc2a02882018-08-07 14:10:56 +02001010 Call::Config recv_call_config(&null_event_log);
ivica5d6a06c2015-09-17 05:30:24 -07001011
eladalon413ee9a2017-08-22 04:02:52 -07001012 if (params_.audio.enabled) {
Christoffer Rodbroc2a02882018-08-07 14:10:56 +02001013 InitializeAudioDevice(&call_config, &recv_call_config);
eladalon413ee9a2017-08-22 04:02:52 -07001014 }
minyue73208662016-08-18 06:28:55 -07001015
Christoffer Rodbroc2a02882018-08-07 14:10:56 +02001016 CreateCalls(call_config, recv_call_config);
eladalon413ee9a2017-08-22 04:02:52 -07001017
1018 // TODO(minyue): consider if this is a good transport even for audio only
1019 // calls.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001020 send_transport = CreateSendTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001021
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001022 recv_transport = CreateReceiveTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001023
1024 // TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
1025 // least share as much code as possible. That way this test would also match
1026 // the full stack tests better.
1027 send_transport->SetReceiver(receiver_call_->Receiver());
1028 recv_transport->SetReceiver(sender_call_->Receiver());
1029
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001030 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001031 // Create video renderers.
1032 local_preview.reset(test::VideoRenderer::Create(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001033 "Local Preview", params_.video[0].width, params_.video[0].height));
eladalon413ee9a2017-08-22 04:02:52 -07001034
1035 SetupVideo(send_transport.get(), recv_transport.get());
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001036 GetVideoSendConfig()->pre_encode_callback = local_preview.get();
eladalon413ee9a2017-08-22 04:02:52 -07001037
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001038 size_t num_streams_processed = 0;
1039 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1040 const size_t selected_stream_id = params_.ss[video_idx].selected_stream;
1041 const size_t num_streams = params_.ss[video_idx].streams.size();
1042 if (selected_stream_id == num_streams) {
1043 for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
1044 std::ostringstream oss;
1045 oss << "Loopback Video #" << video_idx << " - Stream #"
1046 << static_cast<int>(stream_id);
1047 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1048 oss.str().c_str(),
1049 params_.ss[video_idx].streams[stream_id].width,
1050 params_.ss[video_idx].streams[stream_id].height));
1051 video_receive_configs_[stream_id + num_streams_processed].renderer =
1052 loopback_renderers.back().get();
1053 if (params_.audio.enabled && params_.audio.sync_video)
1054 video_receive_configs_[stream_id + num_streams_processed]
1055 .sync_group = kSyncGroup;
1056 }
1057 } else {
1058 std::ostringstream oss;
1059 oss << "Loopback Video #" << video_idx;
1060 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1061 oss.str().c_str(),
1062 params_.ss[video_idx].streams[selected_stream_id].width,
1063 params_.ss[video_idx].streams[selected_stream_id].height));
1064 video_receive_configs_[selected_stream_id + num_streams_processed]
1065 .renderer = loopback_renderers.back().get();
eladalon413ee9a2017-08-22 04:02:52 -07001066 if (params_.audio.enabled && params_.audio.sync_video)
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001067 video_receive_configs_[num_streams_processed + selected_stream_id]
1068 .sync_group = kSyncGroup;
eladalon413ee9a2017-08-22 04:02:52 -07001069 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001070 num_streams_processed += num_streams;
eladalon413ee9a2017-08-22 04:02:52 -07001071 }
eladalon413ee9a2017-08-22 04:02:52 -07001072 CreateFlexfecStreams();
1073 CreateVideoStreams();
1074
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001075 CreateCapturers();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001076 ConnectVideoSourcesToStreams();
eladalon413ee9a2017-08-22 04:02:52 -07001077 }
1078
1079 if (params_.audio.enabled) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001080 SetupAudio(send_transport.get());
eladalon413ee9a2017-08-22 04:02:52 -07001081 }
1082
1083 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1084 StartEncodedFrameLogs(receive_stream);
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001085 StartEncodedFrameLogs(GetVideoSendStream());
1086 Start();
eladalon413ee9a2017-08-22 04:02:52 -07001087 });
minyue73208662016-08-18 06:28:55 -07001088
ivica5d6a06c2015-09-17 05:30:24 -07001089 test::PressEnterToContinue();
1090
eladalon413ee9a2017-08-22 04:02:52 -07001091 task_queue_.SendTask([&]() {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001092 Stop();
1093 DestroyStreams();
minyue73208662016-08-18 06:28:55 -07001094
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001095 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -07001096 send_transport.reset();
1097 recv_transport.reset();
sprang1168fd42017-06-21 09:00:17 -07001098
eladalon413ee9a2017-08-22 04:02:52 -07001099 local_preview.reset();
1100 loopback_renderers.clear();
1101
1102 DestroyCalls();
1103 });
ivica5d6a06c2015-09-17 05:30:24 -07001104}
1105
palmkviste75f2042016-09-28 06:19:48 -07001106void VideoQualityTest::StartEncodedFrameLogs(VideoSendStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001107 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001108 std::ostringstream str;
1109 str << send_logs_++;
1110 std::string prefix =
ilnik98436952017-07-13 00:47:03 -07001111 params_.logging.encoded_frame_base_path + "." + str.str() + ".send.";
palmkviste75f2042016-09-28 06:19:48 -07001112 stream->EnableEncodedFrameRecording(
1113 std::vector<rtc::PlatformFile>(
1114 {rtc::CreatePlatformFile(prefix + "1.ivf"),
1115 rtc::CreatePlatformFile(prefix + "2.ivf"),
1116 rtc::CreatePlatformFile(prefix + "3.ivf")}),
ilnik98436952017-07-13 00:47:03 -07001117 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001118 }
1119}
ilnikcb8c1462017-03-09 09:23:30 -08001120
palmkviste75f2042016-09-28 06:19:48 -07001121void VideoQualityTest::StartEncodedFrameLogs(VideoReceiveStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001122 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001123 std::ostringstream str;
1124 str << receive_logs_++;
1125 std::string path =
ilnik98436952017-07-13 00:47:03 -07001126 params_.logging.encoded_frame_base_path + "." + str.str() + ".recv.ivf";
palmkviste75f2042016-09-28 06:19:48 -07001127 stream->EnableEncodedFrameRecording(rtc::CreatePlatformFile(path),
ilnik98436952017-07-13 00:47:03 -07001128 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001129 }
1130}
ivica5d6a06c2015-09-17 05:30:24 -07001131} // namespace webrtc