blob: fbf8a07834ad0ea05bb9df9fb4d1ed8b51f42a01 [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));
Qingsi Wang2d82ade2018-07-11 06:04:44 +000078 } else {
79 return internal_encoder_factory_.CreateVideoEncoder(format);
Niels Möller4db138e2018-04-19 09:04:13 +020080 }
81}
82
Patrik Höglundb6b29e02018-06-21 16:58:01 +020083VideoQualityTest::VideoQualityTest(
84 std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory)
Sebastian Janssone6d7c3e2018-07-11 15:00:41 +020085 : clock_(Clock::GetRealTimeClock()),
86 video_encoder_factory_([this](const SdpVideoFormat& format) {
87 return this->CreateVideoEncoder(format);
88 }),
89 receive_logs_(0),
90 send_logs_(0) {
minyue20c84cc2017-04-10 16:57:57 -070091 payload_type_map_ = test::CallTest::payload_type_map_;
92 RTC_DCHECK(payload_type_map_.find(kPayloadTypeH264) ==
93 payload_type_map_.end());
94 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP8) ==
95 payload_type_map_.end());
96 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP9) ==
97 payload_type_map_.end());
98 payload_type_map_[kPayloadTypeH264] = webrtc::MediaType::VIDEO;
99 payload_type_map_[kPayloadTypeVP8] = webrtc::MediaType::VIDEO;
100 payload_type_map_[kPayloadTypeVP9] = webrtc::MediaType::VIDEO;
ivica5d6a06c2015-09-17 05:30:24 -0700101
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100102 fec_controller_factory_ = std::move(fec_controller_factory);
Ying Wang3b790f32018-01-19 17:58:57 +0100103}
104
minyue626bc952016-10-31 05:47:02 -0700105VideoQualityTest::Params::Params()
Sebastian Janssonfc8d26b2018-02-21 09:52:06 +0100106 : call({false, BitrateConstraints(), 0}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100107 video{{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200108 false, false, ""},
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100109 {false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200110 false, false, ""}},
minyue4c8b9422017-03-21 04:11:43 -0700111 audio({false, false, false}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100112 screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
minyue626bc952016-10-31 05:47:02 -0700113 analyzer({"", 0.0, 0.0, 0, "", ""}),
114 pipe(),
Sergey Silkin57027362018-05-15 09:12:05 +0200115 ss{{std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
116 std::vector<SpatialLayer>()},
117 {std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
118 std::vector<SpatialLayer>()}},
ilnik98436952017-07-13 00:47:03 -0700119 logging({false, "", "", ""}) {}
minyue626bc952016-10-31 05:47:02 -0700120
121VideoQualityTest::Params::~Params() = default;
122
ivica5d6a06c2015-09-17 05:30:24 -0700123void VideoQualityTest::TestBody() {}
124
sprangce4aef12015-11-02 07:23:20 -0800125std::string VideoQualityTest::GenerateGraphTitle() const {
126 std::stringstream ss;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100127 ss << params_.video[0].codec;
128 ss << " (" << params_.video[0].target_bitrate_bps / 1000 << "kbps";
129 ss << ", " << params_.video[0].fps << " FPS";
130 if (params_.screenshare[0].scroll_duration)
131 ss << ", " << params_.screenshare[0].scroll_duration << "s scroll";
132 if (params_.ss[0].streams.size() > 1)
133 ss << ", Stream #" << params_.ss[0].selected_stream;
134 if (params_.ss[0].num_spatial_layers > 1)
135 ss << ", Layer #" << params_.ss[0].selected_sl;
sprangce4aef12015-11-02 07:23:20 -0800136 ss << ")";
137 return ss.str();
138}
139
140void VideoQualityTest::CheckParams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100141 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
142 // Iterate over primary and secondary video streams.
143 if (!params_.video[video_idx].enabled)
144 return;
145 // Add a default stream in none specified.
146 if (params_.ss[video_idx].streams.empty())
147 params_.ss[video_idx].streams.push_back(
148 VideoQualityTest::DefaultVideoStream(params_, video_idx));
149 if (params_.ss[video_idx].num_spatial_layers == 0)
150 params_.ss[video_idx].num_spatial_layers = 1;
sprangce4aef12015-11-02 07:23:20 -0800151
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100152 if (params_.pipe.loss_percent != 0 ||
153 params_.pipe.queue_length_packets != 0) {
154 // Since LayerFilteringTransport changes the sequence numbers, we can't
155 // use that feature with pack loss, since the NACK request would end up
156 // retransmitting the wrong packets.
157 RTC_CHECK(params_.ss[video_idx].selected_sl == -1 ||
158 params_.ss[video_idx].selected_sl ==
159 params_.ss[video_idx].num_spatial_layers - 1);
160 RTC_CHECK(params_.video[video_idx].selected_tl == -1 ||
161 params_.video[video_idx].selected_tl ==
162 params_.video[video_idx].num_temporal_layers - 1);
163 }
sprangce4aef12015-11-02 07:23:20 -0800164
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100165 // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as
166 // it does in some parts of the code?
167 RTC_CHECK_GE(params_.video[video_idx].max_bitrate_bps,
168 params_.video[video_idx].target_bitrate_bps);
169 RTC_CHECK_GE(params_.video[video_idx].target_bitrate_bps,
170 params_.video[video_idx].min_bitrate_bps);
171 RTC_CHECK_LT(params_.video[video_idx].selected_tl,
172 params_.video[video_idx].num_temporal_layers);
173 RTC_CHECK_LE(params_.ss[video_idx].selected_stream,
174 params_.ss[video_idx].streams.size());
175 for (const VideoStream& stream : params_.ss[video_idx].streams) {
176 RTC_CHECK_GE(stream.min_bitrate_bps, 0);
177 RTC_CHECK_GE(stream.target_bitrate_bps, stream.min_bitrate_bps);
178 RTC_CHECK_GE(stream.max_bitrate_bps, stream.target_bitrate_bps);
179 }
180 // TODO(ivica): Should we check if the sum of all streams/layers is equal to
181 // the total bitrate? We anyway have to update them in the case bitrate
182 // estimator changes the total bitrates.
183 RTC_CHECK_GE(params_.ss[video_idx].num_spatial_layers, 1);
184 RTC_CHECK_LE(params_.ss[video_idx].selected_sl,
185 params_.ss[video_idx].num_spatial_layers);
186 RTC_CHECK(
187 params_.ss[video_idx].spatial_layers.empty() ||
188 params_.ss[video_idx].spatial_layers.size() ==
189 static_cast<size_t>(params_.ss[video_idx].num_spatial_layers));
190 if (params_.video[video_idx].codec == "VP8") {
191 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
192 } else if (params_.video[video_idx].codec == "VP9") {
193 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 1);
194 }
195 RTC_CHECK_GE(params_.call.num_thumbnails, 0);
196 if (params_.call.num_thumbnails > 0) {
197 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
198 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 3);
199 RTC_CHECK_EQ(params_.video[video_idx].num_temporal_layers, 3);
200 RTC_CHECK_EQ(params_.video[video_idx].codec, "VP8");
201 }
202 // Dual streams with FEC not supported in tests yet.
203 RTC_CHECK(!params_.video[video_idx].flexfec || num_video_streams_ == 1);
204 RTC_CHECK(!params_.video[video_idx].ulpfec || num_video_streams_ == 1);
ilnika014cc52017-03-07 04:21:04 -0800205 }
sprangce4aef12015-11-02 07:23:20 -0800206}
207
208// Static.
209std::vector<int> VideoQualityTest::ParseCSV(const std::string& str) {
210 // Parse comma separated nonnegative integers, where some elements may be
211 // empty. The empty values are replaced with -1.
212 // E.g. "10,-20,,30,40" --> {10, 20, -1, 30,40}
213 // E.g. ",,10,,20," --> {-1, -1, 10, -1, 20, -1}
214 std::vector<int> result;
215 if (str.empty())
216 return result;
217
218 const char* p = str.c_str();
219 int value = -1;
220 int pos;
221 while (*p) {
222 if (*p == ',') {
223 result.push_back(value);
224 value = -1;
225 ++p;
226 continue;
227 }
228 RTC_CHECK_EQ(sscanf(p, "%d%n", &value, &pos), 1)
229 << "Unexpected non-number value.";
230 p += pos;
231 }
232 result.push_back(value);
233 return result;
234}
235
236// Static.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100237VideoStream VideoQualityTest::DefaultVideoStream(const Params& params,
238 size_t video_idx) {
sprangce4aef12015-11-02 07:23:20 -0800239 VideoStream stream;
Danil Chapovalov350531e2018-06-08 11:04:04 +0000240 stream.width = params.video[video_idx].width;
241 stream.height = params.video[video_idx].height;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100242 stream.max_framerate = params.video[video_idx].fps;
243 stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps;
244 stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
245 stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
sprang1168fd42017-06-21 09:00:17 -0700246 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100247 stream.num_temporal_layers = params.video[video_idx].num_temporal_layers;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800248 stream.active = true;
ilnika014cc52017-03-07 04:21:04 -0800249 return stream;
250}
251
252// Static.
253VideoStream VideoQualityTest::DefaultThumbnailStream() {
254 VideoStream stream;
255 stream.width = 320;
256 stream.height = 180;
257 stream.max_framerate = 7;
258 stream.min_bitrate_bps = 7500;
259 stream.target_bitrate_bps = 37500;
260 stream.max_bitrate_bps = 50000;
sprang1168fd42017-06-21 09:00:17 -0700261 stream.max_qp = kDefaultMaxQp;
sprangce4aef12015-11-02 07:23:20 -0800262 return stream;
263}
264
265// Static.
266void VideoQualityTest::FillScalabilitySettings(
267 Params* params,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100268 size_t video_idx,
sprangce4aef12015-11-02 07:23:20 -0800269 const std::vector<std::string>& stream_descriptors,
sprang1168fd42017-06-21 09:00:17 -0700270 int num_streams,
sprangce4aef12015-11-02 07:23:20 -0800271 size_t selected_stream,
272 int num_spatial_layers,
273 int selected_sl,
Sergey Silkin57027362018-05-15 09:12:05 +0200274 InterLayerPredMode inter_layer_pred,
sprangce4aef12015-11-02 07:23:20 -0800275 const std::vector<std::string>& sl_descriptors) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100276 if (params->ss[video_idx].streams.empty() &&
277 params->ss[video_idx].infer_streams) {
sprang1168fd42017-06-21 09:00:17 -0700278 webrtc::VideoEncoderConfig encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200279 encoder_config.codec_type =
280 PayloadStringToCodecType(params->video[video_idx].codec);
sprang1168fd42017-06-21 09:00:17 -0700281 encoder_config.content_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100282 params->screenshare[video_idx].enabled
sprang1168fd42017-06-21 09:00:17 -0700283 ? webrtc::VideoEncoderConfig::ContentType::kScreen
284 : webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100285 encoder_config.max_bitrate_bps = params->video[video_idx].max_bitrate_bps;
286 encoder_config.min_transmit_bitrate_bps =
287 params->video[video_idx].min_transmit_bps;
sprang1168fd42017-06-21 09:00:17 -0700288 encoder_config.number_of_streams = num_streams;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100289 encoder_config.spatial_layers = params->ss[video_idx].spatial_layers;
Seth Hampson8234ead2018-02-02 15:16:24 -0800290 encoder_config.simulcast_layers = std::vector<VideoStream>(num_streams);
sprang1168fd42017-06-21 09:00:17 -0700291 encoder_config.video_stream_factory =
292 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100293 params->video[video_idx].codec, kDefaultMaxQp,
294 params->video[video_idx].fps,
295 params->screenshare[video_idx].enabled, true);
296 params->ss[video_idx].streams =
sprang1168fd42017-06-21 09:00:17 -0700297 encoder_config.video_stream_factory->CreateEncoderStreams(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100298 static_cast<int>(params->video[video_idx].width),
299 static_cast<int>(params->video[video_idx].height), encoder_config);
sprang1168fd42017-06-21 09:00:17 -0700300 } else {
301 // Read VideoStream and SpatialLayer elements from a list of comma separated
302 // lists. To use a default value for an element, use -1 or leave empty.
303 // Validity checks performed in CheckParams.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100304 RTC_CHECK(params->ss[video_idx].streams.empty());
sprang1168fd42017-06-21 09:00:17 -0700305 for (auto descriptor : stream_descriptors) {
306 if (descriptor.empty())
307 continue;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100308 VideoStream stream =
309 VideoQualityTest::DefaultVideoStream(*params, video_idx);
sprang1168fd42017-06-21 09:00:17 -0700310 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
311 if (v[0] != -1)
312 stream.width = static_cast<size_t>(v[0]);
313 if (v[1] != -1)
314 stream.height = static_cast<size_t>(v[1]);
315 if (v[2] != -1)
316 stream.max_framerate = v[2];
317 if (v[3] != -1)
318 stream.min_bitrate_bps = v[3];
319 if (v[4] != -1)
320 stream.target_bitrate_bps = v[4];
321 if (v[5] != -1)
322 stream.max_bitrate_bps = v[5];
323 if (v.size() > 6 && v[6] != -1)
324 stream.max_qp = v[6];
Sergey Silkina796a7e2018-03-01 15:11:29 +0100325 if (v.size() > 7 && v[7] != -1) {
326 stream.num_temporal_layers = v[7];
sprang1168fd42017-06-21 09:00:17 -0700327 } else {
328 // Automatic TL thresholds for more than two layers not supported.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100329 RTC_CHECK_LE(params->video[video_idx].num_temporal_layers, 2);
sprang1168fd42017-06-21 09:00:17 -0700330 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100331 params->ss[video_idx].streams.push_back(stream);
sprangce4aef12015-11-02 07:23:20 -0800332 }
sprangce4aef12015-11-02 07:23:20 -0800333 }
sprangce4aef12015-11-02 07:23:20 -0800334
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100335 params->ss[video_idx].num_spatial_layers = std::max(1, num_spatial_layers);
336 params->ss[video_idx].selected_stream = selected_stream;
sprang1168fd42017-06-21 09:00:17 -0700337
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100338 params->ss[video_idx].selected_sl = selected_sl;
Sergey Silkin57027362018-05-15 09:12:05 +0200339 params->ss[video_idx].inter_layer_pred = inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100340 RTC_CHECK(params->ss[video_idx].spatial_layers.empty());
sprangce4aef12015-11-02 07:23:20 -0800341 for (auto descriptor : sl_descriptors) {
342 if (descriptor.empty())
343 continue;
344 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
Sergey Silkin13e74342018-03-02 12:28:00 +0100345 RTC_CHECK_EQ(v.size(), 7);
sprangce4aef12015-11-02 07:23:20 -0800346
Sergey Silkin13e74342018-03-02 12:28:00 +0100347 SpatialLayer layer = {0};
348 layer.width = v[0];
349 layer.height = v[1];
350 layer.numberOfTemporalLayers = v[2];
351 layer.maxBitrate = v[3];
352 layer.minBitrate = v[4];
353 layer.targetBitrate = v[5];
354 layer.qpMax = v[6];
355 layer.active = true;
356
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100357 params->ss[video_idx].spatial_layers.push_back(layer);
sprangce4aef12015-11-02 07:23:20 -0800358 }
359}
360
minyuea27172d2016-11-01 05:59:29 -0700361void VideoQualityTest::SetupVideo(Transport* send_transport,
362 Transport* recv_transport) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100363 size_t total_streams_used = 0;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100364 video_receive_configs_.clear();
365 video_send_configs_.clear();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100366 video_encoder_configs_.clear();
367 allocated_decoders_.clear();
368 bool decode_all_receive_streams = true;
369 size_t num_video_substreams = params_.ss[0].streams.size();
370 RTC_CHECK(num_video_streams_ > 0);
371 video_encoder_configs_.resize(num_video_streams_);
372 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
373 video_send_configs_.push_back(VideoSendStream::Config(send_transport));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100374 video_encoder_configs_.push_back(VideoEncoderConfig());
375 num_video_substreams = params_.ss[video_idx].streams.size();
376 RTC_CHECK_GT(num_video_substreams, 0);
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200377 for (size_t i = 0; i < num_video_substreams; ++i)
378 video_send_configs_[video_idx].rtp.ssrcs.push_back(
379 kVideoSendSsrcs[total_streams_used + i]);
Qingsi Wang2d82ade2018-07-11 06:04:44 +0000380
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100381 int payload_type;
382 if (params_.video[video_idx].codec == "H264") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100383 payload_type = kPayloadTypeH264;
384 } else if (params_.video[video_idx].codec == "VP8") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100385 payload_type = kPayloadTypeVP8;
386 } else if (params_.video[video_idx].codec == "VP9") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100387 payload_type = kPayloadTypeVP9;
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800388 } else if (params_.video[video_idx].codec == "multiplex") {
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800389 payload_type = kPayloadTypeVP9;
ilnikcb8c1462017-03-09 09:23:30 -0800390 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100391 RTC_NOTREACHED() << "Codec not supported!";
392 return;
ilnikcb8c1462017-03-09 09:23:30 -0800393 }
Niels Möller4db138e2018-04-19 09:04:13 +0200394 video_send_configs_[video_idx].encoder_settings.encoder_factory =
395 &video_encoder_factory_;
396
Niels Möller259a4972018-04-05 15:36:51 +0200397 video_send_configs_[video_idx].rtp.payload_name =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100398 params_.video[video_idx].codec;
Niels Möller259a4972018-04-05 15:36:51 +0200399 video_send_configs_[video_idx].rtp.payload_type = payload_type;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100400 video_send_configs_[video_idx].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
401 video_send_configs_[video_idx].rtp.rtx.payload_type = kSendRtxPayloadType;
402 for (size_t i = 0; i < num_video_substreams; ++i) {
403 video_send_configs_[video_idx].rtp.rtx.ssrcs.push_back(
404 kSendRtxSsrcs[i + total_streams_used]);
ilnik9fd9f6c2017-03-02 08:10:10 -0800405 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100406 video_send_configs_[video_idx].rtp.extensions.clear();
407 if (params_.call.send_side_bwe) {
408 video_send_configs_[video_idx].rtp.extensions.push_back(
409 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
410 test::kTransportSequenceNumberExtensionId));
411 } else {
412 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
413 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
414 }
415 video_send_configs_[video_idx].rtp.extensions.push_back(
416 RtpExtension(RtpExtension::kVideoContentTypeUri,
417 test::kVideoContentTypeExtensionId));
418 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
419 RtpExtension::kVideoTimingUri, test::kVideoTimingExtensionId));
420
Niels Möller4db138e2018-04-19 09:04:13 +0200421 video_encoder_configs_[video_idx].video_format.name =
422 params_.video[video_idx].codec;
423
Niels Möller259a4972018-04-05 15:36:51 +0200424 video_encoder_configs_[video_idx].codec_type =
425 PayloadStringToCodecType(params_.video[video_idx].codec);
426
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100427 video_encoder_configs_[video_idx].min_transmit_bitrate_bps =
428 params_.video[video_idx].min_transmit_bps;
429
430 video_send_configs_[video_idx].suspend_below_min_bitrate =
431 params_.video[video_idx].suspend_below_min_bitrate;
432
433 video_encoder_configs_[video_idx].number_of_streams =
434 params_.ss[video_idx].streams.size();
435 video_encoder_configs_[video_idx].max_bitrate_bps = 0;
436 for (size_t i = 0; i < params_.ss[video_idx].streams.size(); ++i) {
437 video_encoder_configs_[video_idx].max_bitrate_bps +=
438 params_.ss[video_idx].streams[i].max_bitrate_bps;
439 }
440 if (params_.ss[video_idx].infer_streams) {
Seth Hampson8234ead2018-02-02 15:16:24 -0800441 video_encoder_configs_[video_idx].simulcast_layers =
442 std::vector<VideoStream>(params_.ss[video_idx].streams.size());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100443 video_encoder_configs_[video_idx].video_stream_factory =
444 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
445 params_.video[video_idx].codec,
446 params_.ss[video_idx].streams[0].max_qp,
447 params_.video[video_idx].fps,
448 params_.screenshare[video_idx].enabled, true);
449 } else {
450 video_encoder_configs_[video_idx].video_stream_factory =
451 new rtc::RefCountedObject<VideoStreamFactory>(
452 params_.ss[video_idx].streams);
453 }
454
455 video_encoder_configs_[video_idx].spatial_layers =
456 params_.ss[video_idx].spatial_layers;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100457 decode_all_receive_streams = params_.ss[video_idx].selected_stream ==
458 params_.ss[video_idx].streams.size();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200459 absl::optional<int> decode_sub_stream;
460 if (!decode_all_receive_streams)
461 decode_sub_stream = params_.ss[video_idx].selected_stream;
462 CreateMatchingVideoReceiveConfigs(
463 video_send_configs_[video_idx], recv_transport,
464 params_.call.send_side_bwe, decode_sub_stream, true, kNackRtpHistoryMs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100465
466 if (params_.screenshare[video_idx].enabled) {
467 // Fill out codec settings.
468 video_encoder_configs_[video_idx].content_type =
469 VideoEncoderConfig::ContentType::kScreen;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700470 degradation_preference_ = DegradationPreference::MAINTAIN_RESOLUTION;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100471 if (params_.video[video_idx].codec == "VP8") {
472 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
473 vp8_settings.denoisingOn = false;
474 vp8_settings.frameDroppingOn = false;
475 vp8_settings.numberOfTemporalLayers = static_cast<unsigned char>(
476 params_.video[video_idx].num_temporal_layers);
477 video_encoder_configs_[video_idx].encoder_specific_settings =
478 new rtc::RefCountedObject<
479 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
480 } else if (params_.video[video_idx].codec == "VP9") {
481 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
482 vp9_settings.denoisingOn = false;
483 vp9_settings.frameDroppingOn = false;
484 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
485 params_.video[video_idx].num_temporal_layers);
486 vp9_settings.numberOfSpatialLayers = static_cast<unsigned char>(
487 params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200488 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100489 video_encoder_configs_[video_idx].encoder_specific_settings =
490 new rtc::RefCountedObject<
491 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
492 }
493 } else if (params_.ss[video_idx].num_spatial_layers > 1) {
494 // If SVC mode without screenshare, still need to set codec specifics.
495 RTC_CHECK(params_.video[video_idx].codec == "VP9");
496 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
497 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
498 params_.video[video_idx].num_temporal_layers);
499 vp9_settings.numberOfSpatialLayers =
500 static_cast<unsigned char>(params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200501 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100502 video_encoder_configs_[video_idx].encoder_specific_settings =
503 new rtc::RefCountedObject<
504 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Niels Möller6aa415e2018-06-07 11:14:13 +0200505 } else if (params_.video[video_idx].automatic_scaling) {
506 if (params_.video[video_idx].codec == "VP8") {
507 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
508 vp8_settings.automaticResizeOn = true;
509 video_encoder_configs_[video_idx].encoder_specific_settings =
510 new rtc::RefCountedObject<
511 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
512 } else if (params_.video[video_idx].codec == "VP9") {
513 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
514 vp9_settings.automaticResizeOn = true;
515 video_encoder_configs_[video_idx].encoder_specific_settings =
516 new rtc::RefCountedObject<
517 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
518 } else {
519 RTC_NOTREACHED() << "Automatic scaling not supported for codec "
Yves Gerey665174f2018-06-19 15:03:05 +0200520 << params_.video[video_idx].codec << ", stream "
521 << video_idx;
Niels Möller6aa415e2018-06-07 11:14:13 +0200522 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100523 }
524 total_streams_used += num_video_substreams;
sprangce4aef12015-11-02 07:23:20 -0800525 }
brandtr1293aca2016-11-16 22:47:29 -0800526
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100527 // FEC supported only for single video stream mode yet.
528 if (params_.video[0].flexfec) {
sprang1168fd42017-06-21 09:00:17 -0700529 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200530 SetSendFecConfig(GetVideoSendConfig()->rtp.ssrcs);
sprang1168fd42017-06-21 09:00:17 -0700531 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200532 SetSendFecConfig({kVideoSendSsrcs[params_.ss[0].selected_stream]});
sprang1168fd42017-06-21 09:00:17 -0700533 }
brandtr1293aca2016-11-16 22:47:29 -0800534
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200535 CreateMatchingFecConfig(recv_transport, *GetVideoSendConfig());
536 GetFlexFecConfig()->transport_cc = params_.call.send_side_bwe;
brandtrb29e6522016-12-21 06:37:18 -0800537 if (params_.call.send_side_bwe) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200538 GetFlexFecConfig()->rtp_header_extensions.push_back(
brandtrb29e6522016-12-21 06:37:18 -0800539 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
540 test::kTransportSequenceNumberExtensionId));
541 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200542 GetFlexFecConfig()->rtp_header_extensions.push_back(RtpExtension(
brandtrb29e6522016-12-21 06:37:18 -0800543 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
544 }
brandtr1293aca2016-11-16 22:47:29 -0800545 }
546
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100547 if (params_.video[0].ulpfec) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200548 SetSendUlpFecConfig(GetVideoSendConfig());
sprang1168fd42017-06-21 09:00:17 -0700549 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200550 for (auto& receive_config : video_receive_configs_) {
551 SetReceiveUlpFecConfig(&receive_config);
sprang1168fd42017-06-21 09:00:17 -0700552 }
553 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200554 SetReceiveUlpFecConfig(
555 &video_receive_configs_[params_.ss[0].selected_stream]);
sprang1168fd42017-06-21 09:00:17 -0700556 }
brandtr1293aca2016-11-16 22:47:29 -0800557 }
ivica5d6a06c2015-09-17 05:30:24 -0700558}
559
ilnika014cc52017-03-07 04:21:04 -0800560void VideoQualityTest::SetupThumbnails(Transport* send_transport,
561 Transport* recv_transport) {
ilnik98436952017-07-13 00:47:03 -0700562 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 04:21:04 -0800563 // Thumbnails will be send in the other way: from receiver_call to
564 // sender_call.
565 VideoSendStream::Config thumbnail_send_config(recv_transport);
566 thumbnail_send_config.rtp.ssrcs.push_back(kThumbnailSendSsrcStart + i);
Niels Möller4db138e2018-04-19 09:04:13 +0200567 // TODO(nisse): Could use a simpler VP8-only encoder factory.
568 thumbnail_send_config.encoder_settings.encoder_factory =
569 &video_encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200570 thumbnail_send_config.rtp.payload_name = params_.video[0].codec;
571 thumbnail_send_config.rtp.payload_type = kPayloadTypeVP8;
ilnika014cc52017-03-07 04:21:04 -0800572 thumbnail_send_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
573 thumbnail_send_config.rtp.rtx.payload_type = kSendRtxPayloadType;
574 thumbnail_send_config.rtp.rtx.ssrcs.push_back(kThumbnailRtxSsrcStart + i);
575 thumbnail_send_config.rtp.extensions.clear();
576 if (params_.call.send_side_bwe) {
577 thumbnail_send_config.rtp.extensions.push_back(
578 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
579 test::kTransportSequenceNumberExtensionId));
580 } else {
581 thumbnail_send_config.rtp.extensions.push_back(RtpExtension(
582 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
583 }
584
585 VideoEncoderConfig thumbnail_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200586 thumbnail_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller4db138e2018-04-19 09:04:13 +0200587 thumbnail_encoder_config.video_format.name = "VP8";
ilnika014cc52017-03-07 04:21:04 -0800588 thumbnail_encoder_config.min_transmit_bitrate_bps = 7500;
589 thumbnail_send_config.suspend_below_min_bitrate =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100590 params_.video[0].suspend_below_min_bitrate;
ilnika014cc52017-03-07 04:21:04 -0800591 thumbnail_encoder_config.number_of_streams = 1;
592 thumbnail_encoder_config.max_bitrate_bps = 50000;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100593 if (params_.ss[0].infer_streams) {
ilnik6b826ef2017-06-16 06:53:48 -0700594 thumbnail_encoder_config.video_stream_factory =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100595 new rtc::RefCountedObject<VideoStreamFactory>(params_.ss[0].streams);
ilnik6b826ef2017-06-16 06:53:48 -0700596 } else {
Seth Hampson8234ead2018-02-02 15:16:24 -0800597 thumbnail_encoder_config.simulcast_layers = std::vector<VideoStream>(1);
ilnik6b826ef2017-06-16 06:53:48 -0700598 thumbnail_encoder_config.video_stream_factory =
599 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100600 params_.video[0].codec, params_.ss[0].streams[0].max_qp,
601 params_.video[0].fps, params_.screenshare[0].enabled, true);
ilnik6b826ef2017-06-16 06:53:48 -0700602 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100603 thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers;
ilnika014cc52017-03-07 04:21:04 -0800604
ilnika014cc52017-03-07 04:21:04 -0800605 thumbnail_encoder_configs_.push_back(thumbnail_encoder_config.Copy());
606 thumbnail_send_configs_.push_back(thumbnail_send_config.Copy());
ilnika014cc52017-03-07 04:21:04 -0800607
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200608 AddMatchingVideoReceiveConfigs(
609 &thumbnail_receive_configs_, thumbnail_send_config, send_transport,
610 params_.call.send_side_bwe, absl::nullopt, false, kNackRtpHistoryMs);
611 }
612 for (size_t i = 0; i < thumbnail_send_configs_.size(); ++i) {
ilnika014cc52017-03-07 04:21:04 -0800613 thumbnail_send_streams_.push_back(receiver_call_->CreateVideoSendStream(
614 thumbnail_send_configs_[i].Copy(),
615 thumbnail_encoder_configs_[i].Copy()));
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200616 }
617 for (size_t i = 0; i < thumbnail_receive_configs_.size(); ++i) {
ilnika014cc52017-03-07 04:21:04 -0800618 thumbnail_receive_streams_.push_back(sender_call_->CreateVideoReceiveStream(
619 thumbnail_receive_configs_[i].Copy()));
620 }
621}
622
623void VideoQualityTest::DestroyThumbnailStreams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100624 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800625 receiver_call_->DestroyVideoSendStream(thumbnail_send_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100626 }
ilnika014cc52017-03-07 04:21:04 -0800627 thumbnail_send_streams_.clear();
628 for (VideoReceiveStream* thumbnail_receive_stream :
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100629 thumbnail_receive_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800630 sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100631 }
ilnika014cc52017-03-07 04:21:04 -0800632 thumbnail_send_streams_.clear();
633 thumbnail_receive_streams_.clear();
eladalon413ee9a2017-08-22 04:02:52 -0700634 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
635 thumbnail_capturers_) {
636 video_caputurer.reset();
637 }
ilnika014cc52017-03-07 04:21:04 -0800638}
639
ilnika014cc52017-03-07 04:21:04 -0800640void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) {
641 VideoStream thumbnail = DefaultThumbnailStream();
642 for (size_t i = 0; i < num_thumbnail_streams; ++i) {
643 thumbnail_capturers_.emplace_back(test::FrameGeneratorCapturer::Create(
644 static_cast<int>(thumbnail.width), static_cast<int>(thumbnail.height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200645 absl::nullopt, absl::nullopt, thumbnail.max_framerate, clock_));
ilnikf89a7382017-03-07 06:15:27 -0800646 RTC_DCHECK(thumbnail_capturers_.back());
ilnika014cc52017-03-07 04:21:04 -0800647 }
648}
649
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100650std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator(
651 size_t video_idx) {
652 // Setup frame generator.
653 const size_t kWidth = 1850;
654 const size_t kHeight = 1110;
655 std::unique_ptr<test::FrameGenerator> frame_generator;
656 if (params_.screenshare[video_idx].generate_slides) {
657 frame_generator = test::FrameGenerator::CreateSlideGenerator(
658 kWidth, kHeight,
659 params_.screenshare[video_idx].slide_change_interval *
660 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700661 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100662 std::vector<std::string> slides = params_.screenshare[video_idx].slides;
663 if (slides.size() == 0) {
664 slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
665 slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
666 slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
667 slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
668 }
669 if (params_.screenshare[video_idx].scroll_duration == 0) {
670 // Cycle image every slide_change_interval seconds.
671 frame_generator = test::FrameGenerator::CreateFromYuvFile(
672 slides, kWidth, kHeight,
673 params_.screenshare[video_idx].slide_change_interval *
674 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700675 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100676 RTC_CHECK_LE(params_.video[video_idx].width, kWidth);
677 RTC_CHECK_LE(params_.video[video_idx].height, kHeight);
678 RTC_CHECK_GT(params_.screenshare[video_idx].slide_change_interval, 0);
679 const int kPauseDurationMs =
680 (params_.screenshare[video_idx].slide_change_interval -
681 params_.screenshare[video_idx].scroll_duration) *
682 1000;
683 RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration,
684 params_.screenshare[video_idx].slide_change_interval);
685
686 frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
687 clock_, slides, kWidth, kHeight, params_.video[video_idx].width,
688 params_.video[video_idx].height,
689 params_.screenshare[video_idx].scroll_duration * 1000,
690 kPauseDurationMs);
ivica5d6a06c2015-09-17 05:30:24 -0700691 }
692 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100693 return frame_generator;
694}
695
696void VideoQualityTest::CreateCapturers() {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200697 RTC_DCHECK(video_sources_.empty());
698 RTC_DCHECK(video_capturers_.empty());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100699 video_capturers_.resize(num_video_streams_);
700 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
701 if (params_.screenshare[video_idx].enabled) {
702 std::unique_ptr<test::FrameGenerator> frame_generator =
703 CreateFrameGenerator(video_idx);
704 test::FrameGeneratorCapturer* frame_generator_capturer =
705 new test::FrameGeneratorCapturer(clock_, std::move(frame_generator),
706 params_.video[video_idx].fps);
707 EXPECT_TRUE(frame_generator_capturer->Init());
708 video_capturers_[video_idx].reset(frame_generator_capturer);
709 } else {
710 if (params_.video[video_idx].clip_name == "Generator") {
711 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
712 static_cast<int>(params_.video[video_idx].width),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200713 static_cast<int>(params_.video[video_idx].height), absl::nullopt,
714 absl::nullopt, params_.video[video_idx].fps, clock_));
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800715 } else if (params_.video[video_idx].clip_name == "GeneratorI420A") {
716 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
717 static_cast<int>(params_.video[video_idx].width),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100718 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200719 test::FrameGenerator::OutputType::I420A, absl::nullopt,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100720 params_.video[video_idx].fps, clock_));
721 } else if (params_.video[video_idx].clip_name.empty()) {
722 video_capturers_[video_idx].reset(test::VcmCapturer::Create(
723 params_.video[video_idx].width, params_.video[video_idx].height,
724 params_.video[video_idx].fps,
725 params_.video[video_idx].capture_device_index));
726 if (!video_capturers_[video_idx]) {
727 // Failed to get actual camera, use chroma generator as backup.
728 video_capturers_[video_idx].reset(
729 test::FrameGeneratorCapturer::Create(
730 static_cast<int>(params_.video[video_idx].width),
731 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200732 absl::nullopt, absl::nullopt, params_.video[video_idx].fps,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800733 clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100734 }
735 } else {
736 video_capturers_[video_idx].reset(
737 test::FrameGeneratorCapturer::CreateFromYuvFile(
738 test::ResourcePath(params_.video[video_idx].clip_name, "yuv"),
739 params_.video[video_idx].width, params_.video[video_idx].height,
740 params_.video[video_idx].fps, clock_));
741 ASSERT_TRUE(video_capturers_[video_idx])
742 << "Could not create capturer for "
743 << params_.video[video_idx].clip_name
744 << ".yuv. Is this resource file present?";
745 }
746 }
747 RTC_DCHECK(video_capturers_[video_idx].get());
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200748 video_sources_.push_back(video_capturers_[video_idx].get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100749 }
ivica5d6a06c2015-09-17 05:30:24 -0700750}
751
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100752std::unique_ptr<test::LayerFilteringTransport>
753VideoQualityTest::CreateSendTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200754 return absl::make_unique<test::LayerFilteringTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100755 &task_queue_, params_.pipe, sender_call_.get(), kPayloadTypeVP8,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100756 kPayloadTypeVP9, params_.video[0].selected_tl, params_.ss[0].selected_sl,
757 payload_type_map_, kVideoSendSsrcs[0],
758 static_cast<uint32_t>(kVideoSendSsrcs[0] + params_.ss[0].streams.size() -
759 1));
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100760}
761
762std::unique_ptr<test::DirectTransport>
763VideoQualityTest::CreateReceiveTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200764 return absl::make_unique<test::DirectTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100765 &task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_);
766}
767
sprang7a975f72015-10-12 06:33:21 -0700768void VideoQualityTest::RunWithAnalyzer(const Params& params) {
Ilya Nikolaevskiyad556762018-01-17 11:48:59 +0100769 rtc::LogMessage::SetLogToStderr(params.logging.logs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100770 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -0700771 std::unique_ptr<test::LayerFilteringTransport> send_transport;
772 std::unique_ptr<test::DirectTransport> recv_transport;
773 FILE* graph_data_output_file = nullptr;
774 std::unique_ptr<VideoAnalyzer> analyzer;
775
sprangce4aef12015-11-02 07:23:20 -0800776 params_ = params;
777
minyue626bc952016-10-31 05:47:02 -0700778 RTC_CHECK(!params_.audio.enabled);
ivica5d6a06c2015-09-17 05:30:24 -0700779 // TODO(ivica): Merge with RunWithRenderer and use a flag / argument to
780 // differentiate between the analyzer and the renderer case.
sprangce4aef12015-11-02 07:23:20 -0800781 CheckParams();
ivica5d6a06c2015-09-17 05:30:24 -0700782
sprangce4aef12015-11-02 07:23:20 -0800783 if (!params_.analyzer.graph_data_output_filename.empty()) {
ivica5d6a06c2015-09-17 05:30:24 -0700784 graph_data_output_file =
sprangce4aef12015-11-02 07:23:20 -0800785 fopen(params_.analyzer.graph_data_output_filename.c_str(), "w");
Peter Boström74f6e9e2016-04-04 17:56:10 +0200786 RTC_CHECK(graph_data_output_file)
sprangce4aef12015-11-02 07:23:20 -0800787 << "Can't open the file " << params_.analyzer.graph_data_output_filename
788 << "!";
ivica87f83a92015-10-08 05:13:32 -0700789 }
sprang7a975f72015-10-12 06:33:21 -0700790
ilnik98436952017-07-13 00:47:03 -0700791 if (!params.logging.rtc_event_log_name.empty()) {
Bjorn Terelius0a6a2b72018-01-19 17:52:38 +0100792 send_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
793 recv_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100794 std::unique_ptr<RtcEventLogOutputFile> send_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200795 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100796 params.logging.rtc_event_log_name + "_send",
797 RtcEventLog::kUnlimitedOutput));
798 std::unique_ptr<RtcEventLogOutputFile> recv_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200799 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100800 params.logging.rtc_event_log_name + "_recv",
801 RtcEventLog::kUnlimitedOutput));
802 bool event_log_started =
803 send_event_log_->StartLogging(std::move(send_output),
804 RtcEventLog::kImmediateOutput) &&
805 recv_event_log_->StartLogging(std::move(recv_output),
806 RtcEventLog::kImmediateOutput);
ilnik98436952017-07-13 00:47:03 -0700807 RTC_DCHECK(event_log_started);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100808 } else {
809 send_event_log_ = RtcEventLog::CreateNull();
810 recv_event_log_ = RtcEventLog::CreateNull();
ilnik98436952017-07-13 00:47:03 -0700811 }
812
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100813 Call::Config send_call_config(send_event_log_.get());
814 Call::Config recv_call_config(recv_event_log_.get());
815 send_call_config.bitrate_config = params.call.call_bitrate_config;
816 recv_call_config.bitrate_config = params.call.call_bitrate_config;
stefanf116bd02015-10-27 08:29:42 -0700817
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100818 task_queue_.SendTask([this, &send_call_config, &recv_call_config,
819 &send_transport, &recv_transport]() {
820 CreateCalls(send_call_config, recv_call_config);
821 send_transport = CreateSendTransport();
822 recv_transport = CreateReceiveTransport();
823 });
stefanf116bd02015-10-27 08:29:42 -0700824
sprangce4aef12015-11-02 07:23:20 -0800825 std::string graph_title = params_.analyzer.graph_title;
826 if (graph_title.empty())
827 graph_title = VideoQualityTest::GenerateGraphTitle();
sprangc1b57a12017-02-28 08:50:47 -0800828 bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
Karl Wiberg918f50c2018-07-05 11:40:33 +0200829 analyzer = absl::make_unique<VideoAnalyzer>(
eladalon413ee9a2017-08-22 04:02:52 -0700830 send_transport.get(), params_.analyzer.test_label,
ilnik2a8c2f52017-02-15 02:23:28 -0800831 params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
ilnik9ae0d762017-02-15 00:53:12 -0800832 is_quick_test_enabled
833 ? kFramesSentInQuickTest
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100834 : params_.analyzer.test_durations_secs * params_.video[0].fps,
sprangce4aef12015-11-02 07:23:20 -0800835 graph_data_output_file, graph_title,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100836 kVideoSendSsrcs[params_.ss[0].selected_stream],
837 kSendRtxSsrcs[params_.ss[0].selected_stream],
838 static_cast<size_t>(params_.ss[0].selected_stream),
839 params.ss[0].selected_sl, params_.video[0].selected_tl,
840 is_quick_test_enabled, clock_, params_.logging.rtp_dump_name);
ivica5d6a06c2015-09-17 05:30:24 -0700841
eladalon413ee9a2017-08-22 04:02:52 -0700842 task_queue_.SendTask([&]() {
843 analyzer->SetCall(sender_call_.get());
844 analyzer->SetReceiver(receiver_call_->Receiver());
845 send_transport->SetReceiver(analyzer.get());
846 recv_transport->SetReceiver(sender_call_->Receiver());
ivica5d6a06c2015-09-17 05:30:24 -0700847
eladalon413ee9a2017-08-22 04:02:52 -0700848 SetupVideo(analyzer.get(), recv_transport.get());
849 SetupThumbnails(analyzer.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100850 video_receive_configs_[params_.ss[0].selected_stream].renderer =
eladalon413ee9a2017-08-22 04:02:52 -0700851 analyzer.get();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200852 GetVideoSendConfig()->pre_encode_callback = analyzer->pre_encode_proxy();
853 RTC_DCHECK(!GetVideoSendConfig()->post_encode_callback);
854 GetVideoSendConfig()->post_encode_callback = analyzer.get();
kthelgason2bc68642017-02-07 07:02:22 -0800855
eladalon413ee9a2017-08-22 04:02:52 -0700856 CreateFlexfecStreams();
857 CreateVideoStreams();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100858 analyzer->SetSendStream(video_send_streams_[0]);
eladalon413ee9a2017-08-22 04:02:52 -0700859 if (video_receive_streams_.size() == 1)
860 analyzer->SetReceiveStream(video_receive_streams_[0]);
ivica5d6a06c2015-09-17 05:30:24 -0700861
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200862 GetVideoSendStream()->SetSource(analyzer->OutputInterface(),
863 degradation_preference_);
eladalon413ee9a2017-08-22 04:02:52 -0700864 SetupThumbnailCapturers(params_.call.num_thumbnails);
865 for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
866 thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
867 degradation_preference_);
868 }
ilnika014cc52017-03-07 04:21:04 -0800869
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100870 CreateCapturers();
ivicac1cc8542015-10-08 03:44:06 -0700871
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100872 analyzer->SetSource(video_capturers_[0].get(), params_.ss[0].infer_streams);
ilnika014cc52017-03-07 04:21:04 -0800873
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100874 for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) {
875 video_send_streams_[video_idx]->SetSource(
876 video_capturers_[video_idx].get(), degradation_preference_);
877 }
878
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200879 StartEncodedFrameLogs(GetVideoSendStream());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100880 StartEncodedFrameLogs(
881 video_receive_streams_[params_.ss[0].selected_stream]);
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200882 StartVideoStreams();
eladalon413ee9a2017-08-22 04:02:52 -0700883 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
884 thumbnail_send_stream->Start();
eladalon413ee9a2017-08-22 04:02:52 -0700885 for (VideoReceiveStream* thumbnail_receive_stream :
886 thumbnail_receive_streams_)
887 thumbnail_receive_stream->Start();
ilnika014cc52017-03-07 04:21:04 -0800888
eladalon413ee9a2017-08-22 04:02:52 -0700889 analyzer->StartMeasuringCpuProcessTime();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200890 StartVideoCapture();
eladalon413ee9a2017-08-22 04:02:52 -0700891 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
892 thumbnail_capturers_) {
893 video_caputurer->Start();
894 }
895 });
ivica5d6a06c2015-09-17 05:30:24 -0700896
eladalon413ee9a2017-08-22 04:02:52 -0700897 analyzer->Wait();
ivica5d6a06c2015-09-17 05:30:24 -0700898
eladalon413ee9a2017-08-22 04:02:52 -0700899 task_queue_.SendTask([&]() {
900 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
901 thumbnail_capturers_)
902 video_caputurer->Stop();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100903 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
904 video_capturers_[video_idx]->Stop();
905 }
eladalon413ee9a2017-08-22 04:02:52 -0700906 for (VideoReceiveStream* thumbnail_receive_stream :
907 thumbnail_receive_streams_)
908 thumbnail_receive_stream->Stop();
909 for (VideoReceiveStream* receive_stream : video_receive_streams_)
910 receive_stream->Stop();
911 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
912 thumbnail_send_stream->Stop();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100913 for (VideoSendStream* video_send_stream : video_send_streams_)
914 video_send_stream->Stop();
ivica5d6a06c2015-09-17 05:30:24 -0700915
eladalon413ee9a2017-08-22 04:02:52 -0700916 DestroyStreams();
917 DestroyThumbnailStreams();
ivica5d6a06c2015-09-17 05:30:24 -0700918
eladalon413ee9a2017-08-22 04:02:52 -0700919 if (graph_data_output_file)
920 fclose(graph_data_output_file);
921
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100922 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -0700923 send_transport.reset();
924 recv_transport.reset();
925
926 DestroyCalls();
927 });
ivica5d6a06c2015-09-17 05:30:24 -0700928}
929
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200930void VideoQualityTest::SetupAudio(Transport* transport) {
931 AudioSendStream::Config audio_send_config(transport);
932 audio_send_config.rtp.ssrc = kAudioSendSsrc;
minyuea27172d2016-11-01 05:59:29 -0700933
934 // Add extension to enable audio send side BWE, and allow audio bit rate
935 // adaptation.
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200936 audio_send_config.rtp.extensions.clear();
937 audio_send_config.send_codec_spec = AudioSendStream::Config::SendCodecSpec(
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100938 kAudioSendPayloadType,
Yves Gerey665174f2018-06-19 15:03:05 +0200939 {"OPUS",
940 48000,
941 2,
942 {{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}});
minyuea27172d2016-11-01 05:59:29 -0700943
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200944 if (params_.call.send_side_bwe) {
945 audio_send_config.rtp.extensions.push_back(
946 webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri,
947 test::kTransportSequenceNumberExtensionId));
948 audio_send_config.min_bitrate_bps = kOpusMinBitrateBps;
949 audio_send_config.max_bitrate_bps = kOpusBitrateFbBps;
950 audio_send_config.send_codec_spec->transport_cc_enabled = true;
951 }
952 audio_send_config.encoder_factory = audio_encoder_factory_;
953 SetAudioConfig(audio_send_config);
954
955 const char* sync_group = nullptr;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100956 if (params_.video[0].enabled && params_.audio.sync_video)
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200957 sync_group = kSyncGroup;
minyuea27172d2016-11-01 05:59:29 -0700958
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200959 CreateMatchingAudioConfigs(transport, sync_group);
960 CreateAudioStreams();
minyuea27172d2016-11-01 05:59:29 -0700961}
962
minyue73208662016-08-18 06:28:55 -0700963void VideoQualityTest::RunWithRenderers(const Params& params) {
Ilya Nikolaevskiyad556762018-01-17 11:48:59 +0100964 rtc::LogMessage::SetLogToStderr(params.logging.logs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100965 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -0700966 std::unique_ptr<test::LayerFilteringTransport> send_transport;
967 std::unique_ptr<test::DirectTransport> recv_transport;
minyuea27172d2016-11-01 05:59:29 -0700968 std::unique_ptr<test::VideoRenderer> local_preview;
eladalon413ee9a2017-08-22 04:02:52 -0700969 std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
Sebastian Jansson8e6602f2018-07-13 10:43:20 +0200970 RtcEventLogNullImpl null_event_log;
minyue73208662016-08-18 06:28:55 -0700971
eladalon413ee9a2017-08-22 04:02:52 -0700972 task_queue_.SendTask([&]() {
973 params_ = params;
974 CheckParams();
palmkviste75f2042016-09-28 06:19:48 -0700975
eladalon413ee9a2017-08-22 04:02:52 -0700976 // TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
977 // match the full stack tests.
Sebastian Jansson8e6602f2018-07-13 10:43:20 +0200978 Call::Config call_config(&null_event_log);
eladalon413ee9a2017-08-22 04:02:52 -0700979 call_config.bitrate_config = params_.call.call_bitrate_config;
Niels Möller2bf9e732017-08-14 11:26:16 +0200980
Artem Titov3faa8322018-03-07 14:44:00 +0100981 rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device =
982 TestAudioDeviceModule::CreateTestAudioDeviceModule(
983 TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
984 TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
ivica5d6a06c2015-09-17 05:30:24 -0700985
eladalon413ee9a2017-08-22 04:02:52 -0700986 if (params_.audio.enabled) {
eladalon413ee9a2017-08-22 04:02:52 -0700987 AudioState::Config audio_state_config;
eladalon413ee9a2017-08-22 04:02:52 -0700988 audio_state_config.audio_mixer = AudioMixerImpl::Create();
Ivo Creusen62337e52018-01-09 14:17:33 +0100989 audio_state_config.audio_processing = AudioProcessingBuilder().Create();
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100990 audio_state_config.audio_device_module = fake_audio_device;
eladalon413ee9a2017-08-22 04:02:52 -0700991 call_config.audio_state = AudioState::Create(audio_state_config);
Fredrik Solenbergd3195342017-11-21 20:33:05 +0100992 fake_audio_device->RegisterAudioCallback(
993 call_config.audio_state->audio_transport());
eladalon413ee9a2017-08-22 04:02:52 -0700994 }
minyue73208662016-08-18 06:28:55 -0700995
eladalon413ee9a2017-08-22 04:02:52 -0700996 CreateCalls(call_config, call_config);
997
998 // TODO(minyue): consider if this is a good transport even for audio only
999 // calls.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001000 send_transport = CreateSendTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001001
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001002 recv_transport = CreateReceiveTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001003
1004 // TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
1005 // least share as much code as possible. That way this test would also match
1006 // the full stack tests better.
1007 send_transport->SetReceiver(receiver_call_->Receiver());
1008 recv_transport->SetReceiver(sender_call_->Receiver());
1009
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001010 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001011 // Create video renderers.
1012 local_preview.reset(test::VideoRenderer::Create(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001013 "Local Preview", params_.video[0].width, params_.video[0].height));
eladalon413ee9a2017-08-22 04:02:52 -07001014
1015 SetupVideo(send_transport.get(), recv_transport.get());
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001016 GetVideoSendConfig()->pre_encode_callback = local_preview.get();
eladalon413ee9a2017-08-22 04:02:52 -07001017
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001018 size_t num_streams_processed = 0;
1019 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1020 const size_t selected_stream_id = params_.ss[video_idx].selected_stream;
1021 const size_t num_streams = params_.ss[video_idx].streams.size();
1022 if (selected_stream_id == num_streams) {
1023 for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
1024 std::ostringstream oss;
1025 oss << "Loopback Video #" << video_idx << " - Stream #"
1026 << static_cast<int>(stream_id);
1027 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1028 oss.str().c_str(),
1029 params_.ss[video_idx].streams[stream_id].width,
1030 params_.ss[video_idx].streams[stream_id].height));
1031 video_receive_configs_[stream_id + num_streams_processed].renderer =
1032 loopback_renderers.back().get();
1033 if (params_.audio.enabled && params_.audio.sync_video)
1034 video_receive_configs_[stream_id + num_streams_processed]
1035 .sync_group = kSyncGroup;
1036 }
1037 } else {
1038 std::ostringstream oss;
1039 oss << "Loopback Video #" << video_idx;
1040 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1041 oss.str().c_str(),
1042 params_.ss[video_idx].streams[selected_stream_id].width,
1043 params_.ss[video_idx].streams[selected_stream_id].height));
1044 video_receive_configs_[selected_stream_id + num_streams_processed]
1045 .renderer = loopback_renderers.back().get();
eladalon413ee9a2017-08-22 04:02:52 -07001046 if (params_.audio.enabled && params_.audio.sync_video)
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001047 video_receive_configs_[num_streams_processed + selected_stream_id]
1048 .sync_group = kSyncGroup;
eladalon413ee9a2017-08-22 04:02:52 -07001049 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001050 num_streams_processed += num_streams;
eladalon413ee9a2017-08-22 04:02:52 -07001051 }
eladalon413ee9a2017-08-22 04:02:52 -07001052 CreateFlexfecStreams();
1053 CreateVideoStreams();
1054
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001055 CreateCapturers();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001056 ConnectVideoSourcesToStreams();
eladalon413ee9a2017-08-22 04:02:52 -07001057 }
1058
1059 if (params_.audio.enabled) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001060 SetupAudio(send_transport.get());
eladalon413ee9a2017-08-22 04:02:52 -07001061 }
1062
1063 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1064 StartEncodedFrameLogs(receive_stream);
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001065 StartEncodedFrameLogs(GetVideoSendStream());
1066 Start();
eladalon413ee9a2017-08-22 04:02:52 -07001067 });
minyue73208662016-08-18 06:28:55 -07001068
ivica5d6a06c2015-09-17 05:30:24 -07001069 test::PressEnterToContinue();
1070
eladalon413ee9a2017-08-22 04:02:52 -07001071 task_queue_.SendTask([&]() {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001072 Stop();
1073 DestroyStreams();
minyue73208662016-08-18 06:28:55 -07001074
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001075 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -07001076 send_transport.reset();
1077 recv_transport.reset();
sprang1168fd42017-06-21 09:00:17 -07001078
eladalon413ee9a2017-08-22 04:02:52 -07001079 local_preview.reset();
1080 loopback_renderers.clear();
1081
1082 DestroyCalls();
1083 });
ivica5d6a06c2015-09-17 05:30:24 -07001084}
1085
palmkviste75f2042016-09-28 06:19:48 -07001086void VideoQualityTest::StartEncodedFrameLogs(VideoSendStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001087 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001088 std::ostringstream str;
1089 str << send_logs_++;
1090 std::string prefix =
ilnik98436952017-07-13 00:47:03 -07001091 params_.logging.encoded_frame_base_path + "." + str.str() + ".send.";
palmkviste75f2042016-09-28 06:19:48 -07001092 stream->EnableEncodedFrameRecording(
1093 std::vector<rtc::PlatformFile>(
1094 {rtc::CreatePlatformFile(prefix + "1.ivf"),
1095 rtc::CreatePlatformFile(prefix + "2.ivf"),
1096 rtc::CreatePlatformFile(prefix + "3.ivf")}),
ilnik98436952017-07-13 00:47:03 -07001097 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001098 }
1099}
ilnikcb8c1462017-03-09 09:23:30 -08001100
palmkviste75f2042016-09-28 06:19:48 -07001101void VideoQualityTest::StartEncodedFrameLogs(VideoReceiveStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001102 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001103 std::ostringstream str;
1104 str << receive_logs_++;
1105 std::string path =
ilnik98436952017-07-13 00:47:03 -07001106 params_.logging.encoded_frame_base_path + "." + str.str() + ".recv.ivf";
palmkviste75f2042016-09-28 06:19:48 -07001107 stream->EnableEncodedFrameRecording(rtc::CreatePlatformFile(path),
ilnik98436952017-07-13 00:47:03 -07001108 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001109 }
1110}
ivica5d6a06c2015-09-17 05:30:24 -07001111} // namespace webrtc