blob: c61d772408cc41c1ee2261272059ac8f9be0bc92 [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
Artem Titovdd2eebe2018-08-20 13:27:45 +020020#include "call/fake_network_pipe.h"
21#include "call/simulated_network.h"
Elad Alon83ccca12017-10-04 13:18:26 +020022#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
Magnus Jedvert46a27652017-11-13 14:10:02 +010023#include "media/engine/internalencoderfactory.h"
Niels Möller19a68d42018-04-13 13:37:52 +020024#include "media/engine/vp8_encoder_simulcast_proxy.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "media/engine/webrtcvideoengine.h"
26#include "modules/audio_mixer/audio_mixer_impl.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "modules/video_coding/codecs/h264/include/h264.h"
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080028#include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h"
Niels Möller4db138e2018-04-19 09:04:13 +020029#include "modules/video_coding/codecs/vp8/include/vp8.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "modules/video_coding/codecs/vp9/include/vp9.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "test/run_loop.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "test/testsupport/fileutils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "test/video_renderer.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020034#include "video/video_analyzer.h"
ilnikee42d192017-08-22 07:16:20 -070035
minyue73208662016-08-18 06:28:55 -070036namespace {
minyue73208662016-08-18 06:28:55 -070037constexpr char kSyncGroup[] = "av_sync";
minyue10cbb462016-11-07 09:29:22 -080038constexpr int kOpusMinBitrateBps = 6000;
39constexpr int kOpusBitrateFbBps = 32000;
ilnik9ae0d762017-02-15 00:53:12 -080040constexpr int kFramesSentInQuickTest = 1;
ilnika014cc52017-03-07 04:21:04 -080041constexpr uint32_t kThumbnailSendSsrcStart = 0xE0000;
42constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000;
minyue73208662016-08-18 06:28:55 -070043
sprang1168fd42017-06-21 09:00:17 -070044constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax;
45
perkjfa10b552016-10-02 23:45:26 -070046class VideoStreamFactory
47 : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface {
48 public:
49 explicit VideoStreamFactory(const std::vector<webrtc::VideoStream>& streams)
50 : streams_(streams) {}
51
52 private:
53 std::vector<webrtc::VideoStream> CreateEncoderStreams(
54 int width,
55 int height,
56 const webrtc::VideoEncoderConfig& encoder_config) override {
mflodmand79f97b2016-12-15 07:24:33 -080057 // The highest layer must match the incoming resolution.
58 std::vector<webrtc::VideoStream> streams = streams_;
59 streams[streams_.size() - 1].height = height;
60 streams[streams_.size() - 1].width = width;
Seth Hampson24722b32017-12-22 09:36:42 -080061
62 streams[0].bitrate_priority = encoder_config.bitrate_priority;
mflodmand79f97b2016-12-15 07:24:33 -080063 return streams;
perkjfa10b552016-10-02 23:45:26 -070064 }
65
66 std::vector<webrtc::VideoStream> streams_;
67};
minyue73208662016-08-18 06:28:55 -070068} // namespace
ivica5d6a06c2015-09-17 05:30:24 -070069
70namespace webrtc {
71
Sebastian Janssone6d7c3e2018-07-11 15:00:41 +020072std::unique_ptr<VideoEncoder> VideoQualityTest::CreateVideoEncoder(
Niels Möller4db138e2018-04-19 09:04:13 +020073 const SdpVideoFormat& format) {
74 if (format.name == "VP8") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020075 return absl::make_unique<VP8EncoderSimulcastProxy>(
76 &internal_encoder_factory_, format);
Niels Möller4db138e2018-04-19 09:04:13 +020077 } else if (format.name == "multiplex") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020078 return absl::make_unique<MultiplexEncoderAdapter>(
Niels Möller4db138e2018-04-19 09:04:13 +020079 &internal_encoder_factory_, SdpVideoFormat(cricket::kVp9CodecName));
Niels Möller4db138e2018-04-19 09:04:13 +020080 }
Emircan Uysaler0823eec2018-07-13 17:10:00 -070081 return internal_encoder_factory_.CreateVideoEncoder(format);
Niels Möller4db138e2018-04-19 09:04:13 +020082}
83
Patrik Höglundb6b29e02018-06-21 16:58:01 +020084VideoQualityTest::VideoQualityTest(
85 std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory)
Sebastian Janssone6d7c3e2018-07-11 15:00:41 +020086 : clock_(Clock::GetRealTimeClock()),
87 video_encoder_factory_([this](const SdpVideoFormat& format) {
88 return this->CreateVideoEncoder(format);
89 }),
90 receive_logs_(0),
91 send_logs_(0) {
minyue20c84cc2017-04-10 16:57:57 -070092 payload_type_map_ = test::CallTest::payload_type_map_;
93 RTC_DCHECK(payload_type_map_.find(kPayloadTypeH264) ==
94 payload_type_map_.end());
95 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP8) ==
96 payload_type_map_.end());
97 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP9) ==
98 payload_type_map_.end());
99 payload_type_map_[kPayloadTypeH264] = webrtc::MediaType::VIDEO;
100 payload_type_map_[kPayloadTypeVP8] = webrtc::MediaType::VIDEO;
101 payload_type_map_[kPayloadTypeVP9] = webrtc::MediaType::VIDEO;
ivica5d6a06c2015-09-17 05:30:24 -0700102
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100103 fec_controller_factory_ = std::move(fec_controller_factory);
Ying Wang3b790f32018-01-19 17:58:57 +0100104}
105
minyue626bc952016-10-31 05:47:02 -0700106VideoQualityTest::Params::Params()
Sebastian Janssonfc8d26b2018-02-21 09:52:06 +0100107 : call({false, BitrateConstraints(), 0}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100108 video{{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200109 false, false, ""},
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100110 {false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200111 false, false, ""}},
minyue4c8b9422017-03-21 04:11:43 -0700112 audio({false, false, false}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100113 screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
minyue626bc952016-10-31 05:47:02 -0700114 analyzer({"", 0.0, 0.0, 0, "", ""}),
115 pipe(),
Sergey Silkin57027362018-05-15 09:12:05 +0200116 ss{{std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
117 std::vector<SpatialLayer>()},
118 {std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
119 std::vector<SpatialLayer>()}},
Mirko Bonadei45a4c412018-07-31 15:07:28 +0200120 logging({"", "", ""}) {}
minyue626bc952016-10-31 05:47:02 -0700121
122VideoQualityTest::Params::~Params() = default;
123
ivica5d6a06c2015-09-17 05:30:24 -0700124void VideoQualityTest::TestBody() {}
125
sprangce4aef12015-11-02 07:23:20 -0800126std::string VideoQualityTest::GenerateGraphTitle() const {
127 std::stringstream ss;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100128 ss << params_.video[0].codec;
129 ss << " (" << params_.video[0].target_bitrate_bps / 1000 << "kbps";
130 ss << ", " << params_.video[0].fps << " FPS";
131 if (params_.screenshare[0].scroll_duration)
132 ss << ", " << params_.screenshare[0].scroll_duration << "s scroll";
133 if (params_.ss[0].streams.size() > 1)
134 ss << ", Stream #" << params_.ss[0].selected_stream;
135 if (params_.ss[0].num_spatial_layers > 1)
136 ss << ", Layer #" << params_.ss[0].selected_sl;
sprangce4aef12015-11-02 07:23:20 -0800137 ss << ")";
138 return ss.str();
139}
140
141void VideoQualityTest::CheckParams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100142 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
143 // Iterate over primary and secondary video streams.
144 if (!params_.video[video_idx].enabled)
145 return;
146 // Add a default stream in none specified.
147 if (params_.ss[video_idx].streams.empty())
148 params_.ss[video_idx].streams.push_back(
149 VideoQualityTest::DefaultVideoStream(params_, video_idx));
150 if (params_.ss[video_idx].num_spatial_layers == 0)
151 params_.ss[video_idx].num_spatial_layers = 1;
sprangce4aef12015-11-02 07:23:20 -0800152
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100153 if (params_.pipe.loss_percent != 0 ||
154 params_.pipe.queue_length_packets != 0) {
155 // Since LayerFilteringTransport changes the sequence numbers, we can't
156 // use that feature with pack loss, since the NACK request would end up
157 // retransmitting the wrong packets.
158 RTC_CHECK(params_.ss[video_idx].selected_sl == -1 ||
159 params_.ss[video_idx].selected_sl ==
160 params_.ss[video_idx].num_spatial_layers - 1);
161 RTC_CHECK(params_.video[video_idx].selected_tl == -1 ||
162 params_.video[video_idx].selected_tl ==
163 params_.video[video_idx].num_temporal_layers - 1);
164 }
sprangce4aef12015-11-02 07:23:20 -0800165
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100166 // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as
167 // it does in some parts of the code?
168 RTC_CHECK_GE(params_.video[video_idx].max_bitrate_bps,
169 params_.video[video_idx].target_bitrate_bps);
170 RTC_CHECK_GE(params_.video[video_idx].target_bitrate_bps,
171 params_.video[video_idx].min_bitrate_bps);
172 RTC_CHECK_LT(params_.video[video_idx].selected_tl,
173 params_.video[video_idx].num_temporal_layers);
174 RTC_CHECK_LE(params_.ss[video_idx].selected_stream,
175 params_.ss[video_idx].streams.size());
176 for (const VideoStream& stream : params_.ss[video_idx].streams) {
177 RTC_CHECK_GE(stream.min_bitrate_bps, 0);
178 RTC_CHECK_GE(stream.target_bitrate_bps, stream.min_bitrate_bps);
179 RTC_CHECK_GE(stream.max_bitrate_bps, stream.target_bitrate_bps);
180 }
181 // TODO(ivica): Should we check if the sum of all streams/layers is equal to
182 // the total bitrate? We anyway have to update them in the case bitrate
183 // estimator changes the total bitrates.
184 RTC_CHECK_GE(params_.ss[video_idx].num_spatial_layers, 1);
185 RTC_CHECK_LE(params_.ss[video_idx].selected_sl,
186 params_.ss[video_idx].num_spatial_layers);
187 RTC_CHECK(
188 params_.ss[video_idx].spatial_layers.empty() ||
189 params_.ss[video_idx].spatial_layers.size() ==
190 static_cast<size_t>(params_.ss[video_idx].num_spatial_layers));
191 if (params_.video[video_idx].codec == "VP8") {
192 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
193 } else if (params_.video[video_idx].codec == "VP9") {
194 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 1);
195 }
196 RTC_CHECK_GE(params_.call.num_thumbnails, 0);
197 if (params_.call.num_thumbnails > 0) {
198 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
199 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 3);
200 RTC_CHECK_EQ(params_.video[video_idx].num_temporal_layers, 3);
201 RTC_CHECK_EQ(params_.video[video_idx].codec, "VP8");
202 }
203 // Dual streams with FEC not supported in tests yet.
204 RTC_CHECK(!params_.video[video_idx].flexfec || num_video_streams_ == 1);
205 RTC_CHECK(!params_.video[video_idx].ulpfec || num_video_streams_ == 1);
ilnika014cc52017-03-07 04:21:04 -0800206 }
sprangce4aef12015-11-02 07:23:20 -0800207}
208
209// Static.
210std::vector<int> VideoQualityTest::ParseCSV(const std::string& str) {
211 // Parse comma separated nonnegative integers, where some elements may be
212 // empty. The empty values are replaced with -1.
213 // E.g. "10,-20,,30,40" --> {10, 20, -1, 30,40}
214 // E.g. ",,10,,20," --> {-1, -1, 10, -1, 20, -1}
215 std::vector<int> result;
216 if (str.empty())
217 return result;
218
219 const char* p = str.c_str();
220 int value = -1;
221 int pos;
222 while (*p) {
223 if (*p == ',') {
224 result.push_back(value);
225 value = -1;
226 ++p;
227 continue;
228 }
229 RTC_CHECK_EQ(sscanf(p, "%d%n", &value, &pos), 1)
230 << "Unexpected non-number value.";
231 p += pos;
232 }
233 result.push_back(value);
234 return result;
235}
236
237// Static.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100238VideoStream VideoQualityTest::DefaultVideoStream(const Params& params,
239 size_t video_idx) {
sprangce4aef12015-11-02 07:23:20 -0800240 VideoStream stream;
Danil Chapovalov350531e2018-06-08 11:04:04 +0000241 stream.width = params.video[video_idx].width;
242 stream.height = params.video[video_idx].height;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100243 stream.max_framerate = params.video[video_idx].fps;
244 stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps;
245 stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
246 stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
sprang1168fd42017-06-21 09:00:17 -0700247 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100248 stream.num_temporal_layers = params.video[video_idx].num_temporal_layers;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800249 stream.active = true;
ilnika014cc52017-03-07 04:21:04 -0800250 return stream;
251}
252
253// Static.
254VideoStream VideoQualityTest::DefaultThumbnailStream() {
255 VideoStream stream;
256 stream.width = 320;
257 stream.height = 180;
258 stream.max_framerate = 7;
259 stream.min_bitrate_bps = 7500;
260 stream.target_bitrate_bps = 37500;
261 stream.max_bitrate_bps = 50000;
sprang1168fd42017-06-21 09:00:17 -0700262 stream.max_qp = kDefaultMaxQp;
sprangce4aef12015-11-02 07:23:20 -0800263 return stream;
264}
265
266// Static.
267void VideoQualityTest::FillScalabilitySettings(
268 Params* params,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100269 size_t video_idx,
sprangce4aef12015-11-02 07:23:20 -0800270 const std::vector<std::string>& stream_descriptors,
sprang1168fd42017-06-21 09:00:17 -0700271 int num_streams,
sprangce4aef12015-11-02 07:23:20 -0800272 size_t selected_stream,
273 int num_spatial_layers,
274 int selected_sl,
Sergey Silkin57027362018-05-15 09:12:05 +0200275 InterLayerPredMode inter_layer_pred,
sprangce4aef12015-11-02 07:23:20 -0800276 const std::vector<std::string>& sl_descriptors) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100277 if (params->ss[video_idx].streams.empty() &&
278 params->ss[video_idx].infer_streams) {
sprang1168fd42017-06-21 09:00:17 -0700279 webrtc::VideoEncoderConfig encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200280 encoder_config.codec_type =
281 PayloadStringToCodecType(params->video[video_idx].codec);
sprang1168fd42017-06-21 09:00:17 -0700282 encoder_config.content_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100283 params->screenshare[video_idx].enabled
sprang1168fd42017-06-21 09:00:17 -0700284 ? webrtc::VideoEncoderConfig::ContentType::kScreen
285 : webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100286 encoder_config.max_bitrate_bps = params->video[video_idx].max_bitrate_bps;
287 encoder_config.min_transmit_bitrate_bps =
288 params->video[video_idx].min_transmit_bps;
sprang1168fd42017-06-21 09:00:17 -0700289 encoder_config.number_of_streams = num_streams;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100290 encoder_config.spatial_layers = params->ss[video_idx].spatial_layers;
Seth Hampson8234ead2018-02-02 15:16:24 -0800291 encoder_config.simulcast_layers = std::vector<VideoStream>(num_streams);
sprang1168fd42017-06-21 09:00:17 -0700292 encoder_config.video_stream_factory =
293 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100294 params->video[video_idx].codec, kDefaultMaxQp,
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000295 params->video[video_idx].fps,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100296 params->screenshare[video_idx].enabled, true);
297 params->ss[video_idx].streams =
sprang1168fd42017-06-21 09:00:17 -0700298 encoder_config.video_stream_factory->CreateEncoderStreams(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100299 static_cast<int>(params->video[video_idx].width),
300 static_cast<int>(params->video[video_idx].height), encoder_config);
sprang1168fd42017-06-21 09:00:17 -0700301 } else {
302 // Read VideoStream and SpatialLayer elements from a list of comma separated
303 // lists. To use a default value for an element, use -1 or leave empty.
304 // Validity checks performed in CheckParams.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100305 RTC_CHECK(params->ss[video_idx].streams.empty());
sprang1168fd42017-06-21 09:00:17 -0700306 for (auto descriptor : stream_descriptors) {
307 if (descriptor.empty())
308 continue;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100309 VideoStream stream =
310 VideoQualityTest::DefaultVideoStream(*params, video_idx);
sprang1168fd42017-06-21 09:00:17 -0700311 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
312 if (v[0] != -1)
313 stream.width = static_cast<size_t>(v[0]);
314 if (v[1] != -1)
315 stream.height = static_cast<size_t>(v[1]);
316 if (v[2] != -1)
317 stream.max_framerate = v[2];
318 if (v[3] != -1)
319 stream.min_bitrate_bps = v[3];
320 if (v[4] != -1)
321 stream.target_bitrate_bps = v[4];
322 if (v[5] != -1)
323 stream.max_bitrate_bps = v[5];
324 if (v.size() > 6 && v[6] != -1)
325 stream.max_qp = v[6];
Sergey Silkina796a7e2018-03-01 15:11:29 +0100326 if (v.size() > 7 && v[7] != -1) {
327 stream.num_temporal_layers = v[7];
sprang1168fd42017-06-21 09:00:17 -0700328 } else {
329 // Automatic TL thresholds for more than two layers not supported.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100330 RTC_CHECK_LE(params->video[video_idx].num_temporal_layers, 2);
sprang1168fd42017-06-21 09:00:17 -0700331 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100332 params->ss[video_idx].streams.push_back(stream);
sprangce4aef12015-11-02 07:23:20 -0800333 }
sprangce4aef12015-11-02 07:23:20 -0800334 }
sprangce4aef12015-11-02 07:23:20 -0800335
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100336 params->ss[video_idx].num_spatial_layers = std::max(1, num_spatial_layers);
337 params->ss[video_idx].selected_stream = selected_stream;
sprang1168fd42017-06-21 09:00:17 -0700338
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100339 params->ss[video_idx].selected_sl = selected_sl;
Sergey Silkin57027362018-05-15 09:12:05 +0200340 params->ss[video_idx].inter_layer_pred = inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100341 RTC_CHECK(params->ss[video_idx].spatial_layers.empty());
sprangce4aef12015-11-02 07:23:20 -0800342 for (auto descriptor : sl_descriptors) {
343 if (descriptor.empty())
344 continue;
345 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
Sergey Silkin13e74342018-03-02 12:28:00 +0100346 RTC_CHECK_EQ(v.size(), 7);
sprangce4aef12015-11-02 07:23:20 -0800347
Sergey Silkin13e74342018-03-02 12:28:00 +0100348 SpatialLayer layer = {0};
349 layer.width = v[0];
350 layer.height = v[1];
351 layer.numberOfTemporalLayers = v[2];
352 layer.maxBitrate = v[3];
353 layer.minBitrate = v[4];
354 layer.targetBitrate = v[5];
355 layer.qpMax = v[6];
356 layer.active = true;
357
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100358 params->ss[video_idx].spatial_layers.push_back(layer);
sprangce4aef12015-11-02 07:23:20 -0800359 }
360}
361
minyuea27172d2016-11-01 05:59:29 -0700362void VideoQualityTest::SetupVideo(Transport* send_transport,
363 Transport* recv_transport) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100364 size_t total_streams_used = 0;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100365 video_receive_configs_.clear();
366 video_send_configs_.clear();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100367 video_encoder_configs_.clear();
368 allocated_decoders_.clear();
369 bool decode_all_receive_streams = true;
370 size_t num_video_substreams = params_.ss[0].streams.size();
371 RTC_CHECK(num_video_streams_ > 0);
372 video_encoder_configs_.resize(num_video_streams_);
373 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
374 video_send_configs_.push_back(VideoSendStream::Config(send_transport));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100375 video_encoder_configs_.push_back(VideoEncoderConfig());
376 num_video_substreams = params_.ss[video_idx].streams.size();
377 RTC_CHECK_GT(num_video_substreams, 0);
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200378 for (size_t i = 0; i < num_video_substreams; ++i)
379 video_send_configs_[video_idx].rtp.ssrcs.push_back(
380 kVideoSendSsrcs[total_streams_used + i]);
Qingsi Wang2d82ade2018-07-11 06:04:44 +0000381
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100382 int payload_type;
383 if (params_.video[video_idx].codec == "H264") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100384 payload_type = kPayloadTypeH264;
385 } else if (params_.video[video_idx].codec == "VP8") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100386 payload_type = kPayloadTypeVP8;
387 } else if (params_.video[video_idx].codec == "VP9") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100388 payload_type = kPayloadTypeVP9;
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800389 } else if (params_.video[video_idx].codec == "multiplex") {
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800390 payload_type = kPayloadTypeVP9;
ilnikcb8c1462017-03-09 09:23:30 -0800391 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100392 RTC_NOTREACHED() << "Codec not supported!";
393 return;
ilnikcb8c1462017-03-09 09:23:30 -0800394 }
Niels Möller4db138e2018-04-19 09:04:13 +0200395 video_send_configs_[video_idx].encoder_settings.encoder_factory =
396 &video_encoder_factory_;
397
Niels Möller259a4972018-04-05 15:36:51 +0200398 video_send_configs_[video_idx].rtp.payload_name =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100399 params_.video[video_idx].codec;
Niels Möller259a4972018-04-05 15:36:51 +0200400 video_send_configs_[video_idx].rtp.payload_type = payload_type;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100401 video_send_configs_[video_idx].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
402 video_send_configs_[video_idx].rtp.rtx.payload_type = kSendRtxPayloadType;
403 for (size_t i = 0; i < num_video_substreams; ++i) {
404 video_send_configs_[video_idx].rtp.rtx.ssrcs.push_back(
405 kSendRtxSsrcs[i + total_streams_used]);
ilnik9fd9f6c2017-03-02 08:10:10 -0800406 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100407 video_send_configs_[video_idx].rtp.extensions.clear();
408 if (params_.call.send_side_bwe) {
409 video_send_configs_[video_idx].rtp.extensions.push_back(
410 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
411 test::kTransportSequenceNumberExtensionId));
412 } else {
413 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
414 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
415 }
416 video_send_configs_[video_idx].rtp.extensions.push_back(
417 RtpExtension(RtpExtension::kVideoContentTypeUri,
418 test::kVideoContentTypeExtensionId));
419 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
420 RtpExtension::kVideoTimingUri, test::kVideoTimingExtensionId));
421
Niels Möller4db138e2018-04-19 09:04:13 +0200422 video_encoder_configs_[video_idx].video_format.name =
423 params_.video[video_idx].codec;
424
Emircan Uysaler0823eec2018-07-13 17:10:00 -0700425 video_encoder_configs_[video_idx].video_format.parameters =
426 params_.video[video_idx].sdp_params;
427
Niels Möller259a4972018-04-05 15:36:51 +0200428 video_encoder_configs_[video_idx].codec_type =
429 PayloadStringToCodecType(params_.video[video_idx].codec);
430
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100431 video_encoder_configs_[video_idx].min_transmit_bitrate_bps =
432 params_.video[video_idx].min_transmit_bps;
433
434 video_send_configs_[video_idx].suspend_below_min_bitrate =
435 params_.video[video_idx].suspend_below_min_bitrate;
436
437 video_encoder_configs_[video_idx].number_of_streams =
438 params_.ss[video_idx].streams.size();
439 video_encoder_configs_[video_idx].max_bitrate_bps = 0;
440 for (size_t i = 0; i < params_.ss[video_idx].streams.size(); ++i) {
441 video_encoder_configs_[video_idx].max_bitrate_bps +=
442 params_.ss[video_idx].streams[i].max_bitrate_bps;
443 }
444 if (params_.ss[video_idx].infer_streams) {
Seth Hampson8234ead2018-02-02 15:16:24 -0800445 video_encoder_configs_[video_idx].simulcast_layers =
446 std::vector<VideoStream>(params_.ss[video_idx].streams.size());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100447 video_encoder_configs_[video_idx].video_stream_factory =
448 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
449 params_.video[video_idx].codec,
450 params_.ss[video_idx].streams[0].max_qp,
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000451 params_.video[video_idx].fps,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100452 params_.screenshare[video_idx].enabled, true);
453 } else {
454 video_encoder_configs_[video_idx].video_stream_factory =
455 new rtc::RefCountedObject<VideoStreamFactory>(
456 params_.ss[video_idx].streams);
457 }
458
459 video_encoder_configs_[video_idx].spatial_layers =
460 params_.ss[video_idx].spatial_layers;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100461 decode_all_receive_streams = params_.ss[video_idx].selected_stream ==
462 params_.ss[video_idx].streams.size();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200463 absl::optional<int> decode_sub_stream;
464 if (!decode_all_receive_streams)
465 decode_sub_stream = params_.ss[video_idx].selected_stream;
466 CreateMatchingVideoReceiveConfigs(
467 video_send_configs_[video_idx], recv_transport,
468 params_.call.send_side_bwe, decode_sub_stream, true, kNackRtpHistoryMs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100469
470 if (params_.screenshare[video_idx].enabled) {
471 // Fill out codec settings.
472 video_encoder_configs_[video_idx].content_type =
473 VideoEncoderConfig::ContentType::kScreen;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700474 degradation_preference_ = DegradationPreference::MAINTAIN_RESOLUTION;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100475 if (params_.video[video_idx].codec == "VP8") {
476 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
477 vp8_settings.denoisingOn = false;
478 vp8_settings.frameDroppingOn = false;
479 vp8_settings.numberOfTemporalLayers = static_cast<unsigned char>(
480 params_.video[video_idx].num_temporal_layers);
481 video_encoder_configs_[video_idx].encoder_specific_settings =
482 new rtc::RefCountedObject<
483 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
484 } else if (params_.video[video_idx].codec == "VP9") {
485 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
486 vp9_settings.denoisingOn = false;
487 vp9_settings.frameDroppingOn = false;
488 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
489 params_.video[video_idx].num_temporal_layers);
490 vp9_settings.numberOfSpatialLayers = static_cast<unsigned char>(
491 params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200492 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100493 video_encoder_configs_[video_idx].encoder_specific_settings =
494 new rtc::RefCountedObject<
495 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
496 }
497 } else if (params_.ss[video_idx].num_spatial_layers > 1) {
498 // If SVC mode without screenshare, still need to set codec specifics.
499 RTC_CHECK(params_.video[video_idx].codec == "VP9");
500 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
501 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
502 params_.video[video_idx].num_temporal_layers);
503 vp9_settings.numberOfSpatialLayers =
504 static_cast<unsigned char>(params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200505 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100506 video_encoder_configs_[video_idx].encoder_specific_settings =
507 new rtc::RefCountedObject<
508 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Niels Möller6aa415e2018-06-07 11:14:13 +0200509 } else if (params_.video[video_idx].automatic_scaling) {
510 if (params_.video[video_idx].codec == "VP8") {
511 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
512 vp8_settings.automaticResizeOn = true;
513 video_encoder_configs_[video_idx].encoder_specific_settings =
514 new rtc::RefCountedObject<
515 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
516 } else if (params_.video[video_idx].codec == "VP9") {
517 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
518 vp9_settings.automaticResizeOn = true;
519 video_encoder_configs_[video_idx].encoder_specific_settings =
520 new rtc::RefCountedObject<
521 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
522 } else {
523 RTC_NOTREACHED() << "Automatic scaling not supported for codec "
Yves Gerey665174f2018-06-19 15:03:05 +0200524 << params_.video[video_idx].codec << ", stream "
525 << video_idx;
Niels Möller6aa415e2018-06-07 11:14:13 +0200526 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100527 }
528 total_streams_used += num_video_substreams;
sprangce4aef12015-11-02 07:23:20 -0800529 }
brandtr1293aca2016-11-16 22:47:29 -0800530
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100531 // FEC supported only for single video stream mode yet.
532 if (params_.video[0].flexfec) {
sprang1168fd42017-06-21 09:00:17 -0700533 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200534 SetSendFecConfig(GetVideoSendConfig()->rtp.ssrcs);
sprang1168fd42017-06-21 09:00:17 -0700535 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200536 SetSendFecConfig({kVideoSendSsrcs[params_.ss[0].selected_stream]});
sprang1168fd42017-06-21 09:00:17 -0700537 }
brandtr1293aca2016-11-16 22:47:29 -0800538
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200539 CreateMatchingFecConfig(recv_transport, *GetVideoSendConfig());
540 GetFlexFecConfig()->transport_cc = params_.call.send_side_bwe;
brandtrb29e6522016-12-21 06:37:18 -0800541 if (params_.call.send_side_bwe) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200542 GetFlexFecConfig()->rtp_header_extensions.push_back(
brandtrb29e6522016-12-21 06:37:18 -0800543 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
544 test::kTransportSequenceNumberExtensionId));
545 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200546 GetFlexFecConfig()->rtp_header_extensions.push_back(RtpExtension(
brandtrb29e6522016-12-21 06:37:18 -0800547 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
548 }
brandtr1293aca2016-11-16 22:47:29 -0800549 }
550
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100551 if (params_.video[0].ulpfec) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200552 SetSendUlpFecConfig(GetVideoSendConfig());
sprang1168fd42017-06-21 09:00:17 -0700553 if (decode_all_receive_streams) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200554 for (auto& receive_config : video_receive_configs_) {
555 SetReceiveUlpFecConfig(&receive_config);
sprang1168fd42017-06-21 09:00:17 -0700556 }
557 } else {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200558 SetReceiveUlpFecConfig(
559 &video_receive_configs_[params_.ss[0].selected_stream]);
sprang1168fd42017-06-21 09:00:17 -0700560 }
brandtr1293aca2016-11-16 22:47:29 -0800561 }
ivica5d6a06c2015-09-17 05:30:24 -0700562}
563
ilnika014cc52017-03-07 04:21:04 -0800564void VideoQualityTest::SetupThumbnails(Transport* send_transport,
565 Transport* recv_transport) {
ilnik98436952017-07-13 00:47:03 -0700566 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 04:21:04 -0800567 // Thumbnails will be send in the other way: from receiver_call to
568 // sender_call.
569 VideoSendStream::Config thumbnail_send_config(recv_transport);
570 thumbnail_send_config.rtp.ssrcs.push_back(kThumbnailSendSsrcStart + i);
Niels Möller4db138e2018-04-19 09:04:13 +0200571 // TODO(nisse): Could use a simpler VP8-only encoder factory.
572 thumbnail_send_config.encoder_settings.encoder_factory =
573 &video_encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200574 thumbnail_send_config.rtp.payload_name = params_.video[0].codec;
575 thumbnail_send_config.rtp.payload_type = kPayloadTypeVP8;
ilnika014cc52017-03-07 04:21:04 -0800576 thumbnail_send_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
577 thumbnail_send_config.rtp.rtx.payload_type = kSendRtxPayloadType;
578 thumbnail_send_config.rtp.rtx.ssrcs.push_back(kThumbnailRtxSsrcStart + i);
579 thumbnail_send_config.rtp.extensions.clear();
580 if (params_.call.send_side_bwe) {
581 thumbnail_send_config.rtp.extensions.push_back(
582 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
583 test::kTransportSequenceNumberExtensionId));
584 } else {
585 thumbnail_send_config.rtp.extensions.push_back(RtpExtension(
586 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
587 }
588
589 VideoEncoderConfig thumbnail_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200590 thumbnail_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller4db138e2018-04-19 09:04:13 +0200591 thumbnail_encoder_config.video_format.name = "VP8";
ilnika014cc52017-03-07 04:21:04 -0800592 thumbnail_encoder_config.min_transmit_bitrate_bps = 7500;
593 thumbnail_send_config.suspend_below_min_bitrate =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100594 params_.video[0].suspend_below_min_bitrate;
ilnika014cc52017-03-07 04:21:04 -0800595 thumbnail_encoder_config.number_of_streams = 1;
596 thumbnail_encoder_config.max_bitrate_bps = 50000;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100597 if (params_.ss[0].infer_streams) {
ilnik6b826ef2017-06-16 06:53:48 -0700598 thumbnail_encoder_config.video_stream_factory =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100599 new rtc::RefCountedObject<VideoStreamFactory>(params_.ss[0].streams);
ilnik6b826ef2017-06-16 06:53:48 -0700600 } else {
Seth Hampson8234ead2018-02-02 15:16:24 -0800601 thumbnail_encoder_config.simulcast_layers = std::vector<VideoStream>(1);
ilnik6b826ef2017-06-16 06:53:48 -0700602 thumbnail_encoder_config.video_stream_factory =
603 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100604 params_.video[0].codec, params_.ss[0].streams[0].max_qp,
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000605 params_.video[0].fps, params_.screenshare[0].enabled, true);
ilnik6b826ef2017-06-16 06:53:48 -0700606 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100607 thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers;
ilnika014cc52017-03-07 04:21:04 -0800608
ilnika014cc52017-03-07 04:21:04 -0800609 thumbnail_encoder_configs_.push_back(thumbnail_encoder_config.Copy());
610 thumbnail_send_configs_.push_back(thumbnail_send_config.Copy());
ilnika014cc52017-03-07 04:21:04 -0800611
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200612 AddMatchingVideoReceiveConfigs(
613 &thumbnail_receive_configs_, thumbnail_send_config, send_transport,
614 params_.call.send_side_bwe, absl::nullopt, false, kNackRtpHistoryMs);
615 }
616 for (size_t i = 0; i < thumbnail_send_configs_.size(); ++i) {
ilnika014cc52017-03-07 04:21:04 -0800617 thumbnail_send_streams_.push_back(receiver_call_->CreateVideoSendStream(
618 thumbnail_send_configs_[i].Copy(),
619 thumbnail_encoder_configs_[i].Copy()));
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200620 }
621 for (size_t i = 0; i < thumbnail_receive_configs_.size(); ++i) {
ilnika014cc52017-03-07 04:21:04 -0800622 thumbnail_receive_streams_.push_back(sender_call_->CreateVideoReceiveStream(
623 thumbnail_receive_configs_[i].Copy()));
624 }
625}
626
627void VideoQualityTest::DestroyThumbnailStreams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100628 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800629 receiver_call_->DestroyVideoSendStream(thumbnail_send_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100630 }
ilnika014cc52017-03-07 04:21:04 -0800631 thumbnail_send_streams_.clear();
632 for (VideoReceiveStream* thumbnail_receive_stream :
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100633 thumbnail_receive_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800634 sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100635 }
ilnika014cc52017-03-07 04:21:04 -0800636 thumbnail_send_streams_.clear();
637 thumbnail_receive_streams_.clear();
Sebastian Janssonf1f363f2018-08-13 14:24:58 +0200638 for (std::unique_ptr<test::TestVideoCapturer>& video_caputurer :
eladalon413ee9a2017-08-22 04:02:52 -0700639 thumbnail_capturers_) {
640 video_caputurer.reset();
641 }
ilnika014cc52017-03-07 04:21:04 -0800642}
643
ilnika014cc52017-03-07 04:21:04 -0800644void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) {
645 VideoStream thumbnail = DefaultThumbnailStream();
646 for (size_t i = 0; i < num_thumbnail_streams; ++i) {
647 thumbnail_capturers_.emplace_back(test::FrameGeneratorCapturer::Create(
648 static_cast<int>(thumbnail.width), static_cast<int>(thumbnail.height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200649 absl::nullopt, absl::nullopt, thumbnail.max_framerate, clock_));
ilnikf89a7382017-03-07 06:15:27 -0800650 RTC_DCHECK(thumbnail_capturers_.back());
ilnika014cc52017-03-07 04:21:04 -0800651 }
652}
653
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100654std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator(
655 size_t video_idx) {
656 // Setup frame generator.
657 const size_t kWidth = 1850;
658 const size_t kHeight = 1110;
659 std::unique_ptr<test::FrameGenerator> frame_generator;
660 if (params_.screenshare[video_idx].generate_slides) {
661 frame_generator = test::FrameGenerator::CreateSlideGenerator(
662 kWidth, kHeight,
663 params_.screenshare[video_idx].slide_change_interval *
664 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700665 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100666 std::vector<std::string> slides = params_.screenshare[video_idx].slides;
667 if (slides.size() == 0) {
668 slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
669 slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
670 slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
671 slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
672 }
673 if (params_.screenshare[video_idx].scroll_duration == 0) {
674 // Cycle image every slide_change_interval seconds.
675 frame_generator = test::FrameGenerator::CreateFromYuvFile(
676 slides, kWidth, kHeight,
677 params_.screenshare[video_idx].slide_change_interval *
678 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700679 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100680 RTC_CHECK_LE(params_.video[video_idx].width, kWidth);
681 RTC_CHECK_LE(params_.video[video_idx].height, kHeight);
682 RTC_CHECK_GT(params_.screenshare[video_idx].slide_change_interval, 0);
683 const int kPauseDurationMs =
684 (params_.screenshare[video_idx].slide_change_interval -
685 params_.screenshare[video_idx].scroll_duration) *
686 1000;
687 RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration,
688 params_.screenshare[video_idx].slide_change_interval);
689
690 frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
691 clock_, slides, kWidth, kHeight, params_.video[video_idx].width,
692 params_.video[video_idx].height,
693 params_.screenshare[video_idx].scroll_duration * 1000,
694 kPauseDurationMs);
ivica5d6a06c2015-09-17 05:30:24 -0700695 }
696 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100697 return frame_generator;
698}
699
700void VideoQualityTest::CreateCapturers() {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200701 RTC_DCHECK(video_sources_.empty());
702 RTC_DCHECK(video_capturers_.empty());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100703 video_capturers_.resize(num_video_streams_);
704 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
705 if (params_.screenshare[video_idx].enabled) {
706 std::unique_ptr<test::FrameGenerator> frame_generator =
707 CreateFrameGenerator(video_idx);
708 test::FrameGeneratorCapturer* frame_generator_capturer =
709 new test::FrameGeneratorCapturer(clock_, std::move(frame_generator),
710 params_.video[video_idx].fps);
711 EXPECT_TRUE(frame_generator_capturer->Init());
712 video_capturers_[video_idx].reset(frame_generator_capturer);
713 } else {
714 if (params_.video[video_idx].clip_name == "Generator") {
715 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
716 static_cast<int>(params_.video[video_idx].width),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200717 static_cast<int>(params_.video[video_idx].height), absl::nullopt,
718 absl::nullopt, params_.video[video_idx].fps, clock_));
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800719 } else if (params_.video[video_idx].clip_name == "GeneratorI420A") {
720 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
721 static_cast<int>(params_.video[video_idx].width),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100722 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200723 test::FrameGenerator::OutputType::I420A, absl::nullopt,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100724 params_.video[video_idx].fps, clock_));
Emircan Uysaler0823eec2018-07-13 17:10:00 -0700725 } else if (params_.video[video_idx].clip_name == "GeneratorI010") {
726 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
727 static_cast<int>(params_.video[video_idx].width),
728 static_cast<int>(params_.video[video_idx].height),
729 test::FrameGenerator::OutputType::I010, absl::nullopt,
730 params_.video[video_idx].fps, clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100731 } else if (params_.video[video_idx].clip_name.empty()) {
732 video_capturers_[video_idx].reset(test::VcmCapturer::Create(
733 params_.video[video_idx].width, params_.video[video_idx].height,
734 params_.video[video_idx].fps,
735 params_.video[video_idx].capture_device_index));
736 if (!video_capturers_[video_idx]) {
737 // Failed to get actual camera, use chroma generator as backup.
738 video_capturers_[video_idx].reset(
739 test::FrameGeneratorCapturer::Create(
740 static_cast<int>(params_.video[video_idx].width),
741 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200742 absl::nullopt, absl::nullopt, params_.video[video_idx].fps,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800743 clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100744 }
745 } else {
746 video_capturers_[video_idx].reset(
747 test::FrameGeneratorCapturer::CreateFromYuvFile(
748 test::ResourcePath(params_.video[video_idx].clip_name, "yuv"),
749 params_.video[video_idx].width, params_.video[video_idx].height,
750 params_.video[video_idx].fps, clock_));
751 ASSERT_TRUE(video_capturers_[video_idx])
752 << "Could not create capturer for "
753 << params_.video[video_idx].clip_name
754 << ".yuv. Is this resource file present?";
755 }
756 }
757 RTC_DCHECK(video_capturers_[video_idx].get());
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200758 video_sources_.push_back(video_capturers_[video_idx].get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100759 }
ivica5d6a06c2015-09-17 05:30:24 -0700760}
761
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200762void VideoQualityTest::StartAudioStreams() {
763 audio_send_stream_->Start();
764 for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_)
765 audio_recv_stream->Start();
766}
767
768void VideoQualityTest::StartThumbnailCapture() {
Sebastian Janssonf1f363f2018-08-13 14:24:58 +0200769 for (std::unique_ptr<test::TestVideoCapturer>& capturer :
770 thumbnail_capturers_)
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200771 capturer->Start();
772}
773
774void VideoQualityTest::StopThumbnailCapture() {
Sebastian Janssonf1f363f2018-08-13 14:24:58 +0200775 for (std::unique_ptr<test::TestVideoCapturer>& capturer :
776 thumbnail_capturers_)
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200777 capturer->Stop();
778}
779
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200780void VideoQualityTest::StartThumbnails() {
781 for (VideoSendStream* send_stream : thumbnail_send_streams_)
782 send_stream->Start();
783 for (VideoReceiveStream* receive_stream : thumbnail_receive_streams_)
784 receive_stream->Start();
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200785}
786
787void VideoQualityTest::StopThumbnails() {
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200788 for (VideoReceiveStream* receive_stream : thumbnail_receive_streams_)
789 receive_stream->Stop();
790 for (VideoSendStream* send_stream : thumbnail_send_streams_)
791 send_stream->Stop();
792}
793
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100794std::unique_ptr<test::LayerFilteringTransport>
795VideoQualityTest::CreateSendTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200796 return absl::make_unique<test::LayerFilteringTransport>(
Artem Titov4e199e92018-08-20 13:30:39 +0200797 &task_queue_,
798 absl::make_unique<FakeNetworkPipe>(
799 Clock::GetRealTimeClock(),
800 absl::make_unique<SimulatedNetwork>(params_.pipe)),
801 sender_call_.get(), kPayloadTypeVP8, kPayloadTypeVP9,
802 params_.video[0].selected_tl, params_.ss[0].selected_sl,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100803 payload_type_map_, kVideoSendSsrcs[0],
804 static_cast<uint32_t>(kVideoSendSsrcs[0] + params_.ss[0].streams.size() -
805 1));
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100806}
807
808std::unique_ptr<test::DirectTransport>
809VideoQualityTest::CreateReceiveTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200810 return absl::make_unique<test::DirectTransport>(
Artem Titovdd2eebe2018-08-20 13:27:45 +0200811 &task_queue_,
812 absl::make_unique<FakeNetworkPipe>(
813 Clock::GetRealTimeClock(),
814 absl::make_unique<SimulatedNetwork>(params_.pipe)),
815 receiver_call_.get(), payload_type_map_);
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100816}
817
sprang7a975f72015-10-12 06:33:21 -0700818void VideoQualityTest::RunWithAnalyzer(const Params& params) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100819 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -0700820 std::unique_ptr<test::LayerFilteringTransport> send_transport;
821 std::unique_ptr<test::DirectTransport> recv_transport;
822 FILE* graph_data_output_file = nullptr;
823 std::unique_ptr<VideoAnalyzer> analyzer;
824
sprangce4aef12015-11-02 07:23:20 -0800825 params_ = params;
ivica5d6a06c2015-09-17 05:30:24 -0700826 // TODO(ivica): Merge with RunWithRenderer and use a flag / argument to
827 // differentiate between the analyzer and the renderer case.
sprangce4aef12015-11-02 07:23:20 -0800828 CheckParams();
ivica5d6a06c2015-09-17 05:30:24 -0700829
sprangce4aef12015-11-02 07:23:20 -0800830 if (!params_.analyzer.graph_data_output_filename.empty()) {
ivica5d6a06c2015-09-17 05:30:24 -0700831 graph_data_output_file =
sprangce4aef12015-11-02 07:23:20 -0800832 fopen(params_.analyzer.graph_data_output_filename.c_str(), "w");
Peter Boström74f6e9e2016-04-04 17:56:10 +0200833 RTC_CHECK(graph_data_output_file)
sprangce4aef12015-11-02 07:23:20 -0800834 << "Can't open the file " << params_.analyzer.graph_data_output_filename
835 << "!";
ivica87f83a92015-10-08 05:13:32 -0700836 }
sprang7a975f72015-10-12 06:33:21 -0700837
ilnik98436952017-07-13 00:47:03 -0700838 if (!params.logging.rtc_event_log_name.empty()) {
Bjorn Terelius0a6a2b72018-01-19 17:52:38 +0100839 send_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
840 recv_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100841 std::unique_ptr<RtcEventLogOutputFile> send_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200842 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100843 params.logging.rtc_event_log_name + "_send",
844 RtcEventLog::kUnlimitedOutput));
845 std::unique_ptr<RtcEventLogOutputFile> recv_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200846 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100847 params.logging.rtc_event_log_name + "_recv",
848 RtcEventLog::kUnlimitedOutput));
849 bool event_log_started =
850 send_event_log_->StartLogging(std::move(send_output),
851 RtcEventLog::kImmediateOutput) &&
852 recv_event_log_->StartLogging(std::move(recv_output),
853 RtcEventLog::kImmediateOutput);
ilnik98436952017-07-13 00:47:03 -0700854 RTC_DCHECK(event_log_started);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100855 } else {
856 send_event_log_ = RtcEventLog::CreateNull();
857 recv_event_log_ = RtcEventLog::CreateNull();
ilnik98436952017-07-13 00:47:03 -0700858 }
859
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100860 Call::Config send_call_config(send_event_log_.get());
861 Call::Config recv_call_config(recv_event_log_.get());
862 send_call_config.bitrate_config = params.call.call_bitrate_config;
863 recv_call_config.bitrate_config = params.call.call_bitrate_config;
stefanf116bd02015-10-27 08:29:42 -0700864
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100865 task_queue_.SendTask([this, &send_call_config, &recv_call_config,
866 &send_transport, &recv_transport]() {
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200867 if (params_.audio.enabled)
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200868 InitializeAudioDevice(&send_call_config, &recv_call_config);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200869
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100870 CreateCalls(send_call_config, recv_call_config);
871 send_transport = CreateSendTransport();
872 recv_transport = CreateReceiveTransport();
873 });
stefanf116bd02015-10-27 08:29:42 -0700874
sprangce4aef12015-11-02 07:23:20 -0800875 std::string graph_title = params_.analyzer.graph_title;
876 if (graph_title.empty())
877 graph_title = VideoQualityTest::GenerateGraphTitle();
sprangc1b57a12017-02-28 08:50:47 -0800878 bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
Karl Wiberg918f50c2018-07-05 11:40:33 +0200879 analyzer = absl::make_unique<VideoAnalyzer>(
eladalon413ee9a2017-08-22 04:02:52 -0700880 send_transport.get(), params_.analyzer.test_label,
ilnik2a8c2f52017-02-15 02:23:28 -0800881 params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
ilnik9ae0d762017-02-15 00:53:12 -0800882 is_quick_test_enabled
883 ? kFramesSentInQuickTest
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100884 : params_.analyzer.test_durations_secs * params_.video[0].fps,
sprangce4aef12015-11-02 07:23:20 -0800885 graph_data_output_file, graph_title,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100886 kVideoSendSsrcs[params_.ss[0].selected_stream],
887 kSendRtxSsrcs[params_.ss[0].selected_stream],
888 static_cast<size_t>(params_.ss[0].selected_stream),
889 params.ss[0].selected_sl, params_.video[0].selected_tl,
890 is_quick_test_enabled, clock_, params_.logging.rtp_dump_name);
ivica5d6a06c2015-09-17 05:30:24 -0700891
eladalon413ee9a2017-08-22 04:02:52 -0700892 task_queue_.SendTask([&]() {
893 analyzer->SetCall(sender_call_.get());
894 analyzer->SetReceiver(receiver_call_->Receiver());
895 send_transport->SetReceiver(analyzer.get());
896 recv_transport->SetReceiver(sender_call_->Receiver());
ivica5d6a06c2015-09-17 05:30:24 -0700897
eladalon413ee9a2017-08-22 04:02:52 -0700898 SetupVideo(analyzer.get(), recv_transport.get());
899 SetupThumbnails(analyzer.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100900 video_receive_configs_[params_.ss[0].selected_stream].renderer =
eladalon413ee9a2017-08-22 04:02:52 -0700901 analyzer.get();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200902 GetVideoSendConfig()->pre_encode_callback = analyzer->pre_encode_proxy();
903 RTC_DCHECK(!GetVideoSendConfig()->post_encode_callback);
904 GetVideoSendConfig()->post_encode_callback = analyzer.get();
kthelgason2bc68642017-02-07 07:02:22 -0800905
eladalon413ee9a2017-08-22 04:02:52 -0700906 CreateFlexfecStreams();
907 CreateVideoStreams();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100908 analyzer->SetSendStream(video_send_streams_[0]);
eladalon413ee9a2017-08-22 04:02:52 -0700909 if (video_receive_streams_.size() == 1)
910 analyzer->SetReceiveStream(video_receive_streams_[0]);
ivica5d6a06c2015-09-17 05:30:24 -0700911
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200912 GetVideoSendStream()->SetSource(analyzer->OutputInterface(),
913 degradation_preference_);
eladalon413ee9a2017-08-22 04:02:52 -0700914 SetupThumbnailCapturers(params_.call.num_thumbnails);
915 for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
916 thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
917 degradation_preference_);
918 }
ilnika014cc52017-03-07 04:21:04 -0800919
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100920 CreateCapturers();
ivicac1cc8542015-10-08 03:44:06 -0700921
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100922 analyzer->SetSource(video_capturers_[0].get(), params_.ss[0].infer_streams);
ilnika014cc52017-03-07 04:21:04 -0800923
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100924 for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) {
925 video_send_streams_[video_idx]->SetSource(
926 video_capturers_[video_idx].get(), degradation_preference_);
927 }
928
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200929 StartEncodedFrameLogs(GetVideoSendStream());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100930 StartEncodedFrameLogs(
931 video_receive_streams_[params_.ss[0].selected_stream]);
ilnika014cc52017-03-07 04:21:04 -0800932
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200933 if (params_.audio.enabled) {
934 SetupAudio(send_transport.get());
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200935 StartAudioStreams();
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200936 analyzer->SetAudioReceiveStream(audio_receive_streams_[0]);
937 }
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200938 StartVideoStreams();
939 StartThumbnails();
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200940 analyzer->StartMeasuringCpuProcessTime();
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200941 StartVideoCapture();
942 StartThumbnailCapture();
eladalon413ee9a2017-08-22 04:02:52 -0700943 });
ivica5d6a06c2015-09-17 05:30:24 -0700944
eladalon413ee9a2017-08-22 04:02:52 -0700945 analyzer->Wait();
ivica5d6a06c2015-09-17 05:30:24 -0700946
eladalon413ee9a2017-08-22 04:02:52 -0700947 task_queue_.SendTask([&]() {
Christoffer Rodbro39a44b22018-08-07 17:07:24 +0200948 StopThumbnailCapture();
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200949 StopThumbnails();
950 Stop();
ivica5d6a06c2015-09-17 05:30:24 -0700951
eladalon413ee9a2017-08-22 04:02:52 -0700952 DestroyStreams();
953 DestroyThumbnailStreams();
ivica5d6a06c2015-09-17 05:30:24 -0700954
eladalon413ee9a2017-08-22 04:02:52 -0700955 if (graph_data_output_file)
956 fclose(graph_data_output_file);
957
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100958 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -0700959 send_transport.reset();
960 recv_transport.reset();
961
962 DestroyCalls();
963 });
ivica5d6a06c2015-09-17 05:30:24 -0700964}
965
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200966void VideoQualityTest::InitializeAudioDevice(Call::Config* send_call_config,
967 Call::Config* recv_call_config) {
968 rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device =
969 TestAudioDeviceModule::CreateTestAudioDeviceModule(
970 TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
971 TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
972
973 AudioState::Config audio_state_config;
974 audio_state_config.audio_mixer = AudioMixerImpl::Create();
975 audio_state_config.audio_processing = AudioProcessingBuilder().Create();
976 audio_state_config.audio_device_module = fake_audio_device;
977 send_call_config->audio_state = AudioState::Create(audio_state_config);
978 RTC_CHECK(fake_audio_device->RegisterAudioCallback(
979 send_call_config->audio_state->audio_transport()) == 0);
980 recv_call_config->audio_state = AudioState::Create(audio_state_config);
981 fake_audio_device->Init();
982}
983
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200984void VideoQualityTest::SetupAudio(Transport* transport) {
985 AudioSendStream::Config audio_send_config(transport);
986 audio_send_config.rtp.ssrc = kAudioSendSsrc;
minyuea27172d2016-11-01 05:59:29 -0700987
988 // Add extension to enable audio send side BWE, and allow audio bit rate
989 // adaptation.
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200990 audio_send_config.rtp.extensions.clear();
991 audio_send_config.send_codec_spec = AudioSendStream::Config::SendCodecSpec(
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100992 kAudioSendPayloadType,
Yves Gerey665174f2018-06-19 15:03:05 +0200993 {"OPUS",
994 48000,
995 2,
996 {{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}});
minyuea27172d2016-11-01 05:59:29 -0700997
Sebastian Jansson3bd2c792018-07-13 13:29:03 +0200998 if (params_.call.send_side_bwe) {
999 audio_send_config.rtp.extensions.push_back(
1000 webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri,
1001 test::kTransportSequenceNumberExtensionId));
1002 audio_send_config.min_bitrate_bps = kOpusMinBitrateBps;
1003 audio_send_config.max_bitrate_bps = kOpusBitrateFbBps;
1004 audio_send_config.send_codec_spec->transport_cc_enabled = true;
1005 }
1006 audio_send_config.encoder_factory = audio_encoder_factory_;
1007 SetAudioConfig(audio_send_config);
1008
Christoffer Rodbroc2a02882018-08-07 14:10:56 +02001009 std::string sync_group;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001010 if (params_.video[0].enabled && params_.audio.sync_video)
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001011 sync_group = kSyncGroup;
minyuea27172d2016-11-01 05:59:29 -07001012
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001013 CreateMatchingAudioConfigs(transport, sync_group);
1014 CreateAudioStreams();
minyuea27172d2016-11-01 05:59:29 -07001015}
1016
minyue73208662016-08-18 06:28:55 -07001017void VideoQualityTest::RunWithRenderers(const Params& params) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001018 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -07001019 std::unique_ptr<test::LayerFilteringTransport> send_transport;
1020 std::unique_ptr<test::DirectTransport> recv_transport;
minyuea27172d2016-11-01 05:59:29 -07001021 std::unique_ptr<test::VideoRenderer> local_preview;
eladalon413ee9a2017-08-22 04:02:52 -07001022 std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
Sebastian Jansson8e6602f2018-07-13 10:43:20 +02001023 RtcEventLogNullImpl null_event_log;
minyue73208662016-08-18 06:28:55 -07001024
eladalon413ee9a2017-08-22 04:02:52 -07001025 task_queue_.SendTask([&]() {
1026 params_ = params;
1027 CheckParams();
palmkviste75f2042016-09-28 06:19:48 -07001028
eladalon413ee9a2017-08-22 04:02:52 -07001029 // TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
1030 // match the full stack tests.
Christoffer Rodbro39a44b22018-08-07 17:07:24 +02001031 Call::Config send_call_config(&null_event_log);
1032 send_call_config.bitrate_config = params_.call.call_bitrate_config;
Christoffer Rodbroc2a02882018-08-07 14:10:56 +02001033 Call::Config recv_call_config(&null_event_log);
ivica5d6a06c2015-09-17 05:30:24 -07001034
Christoffer Rodbro39a44b22018-08-07 17:07:24 +02001035 if (params_.audio.enabled)
1036 InitializeAudioDevice(&send_call_config, &recv_call_config);
minyue73208662016-08-18 06:28:55 -07001037
Christoffer Rodbro39a44b22018-08-07 17:07:24 +02001038 CreateCalls(send_call_config, recv_call_config);
eladalon413ee9a2017-08-22 04:02:52 -07001039
1040 // TODO(minyue): consider if this is a good transport even for audio only
1041 // calls.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001042 send_transport = CreateSendTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001043
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001044 recv_transport = CreateReceiveTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001045
1046 // TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
1047 // least share as much code as possible. That way this test would also match
1048 // the full stack tests better.
1049 send_transport->SetReceiver(receiver_call_->Receiver());
1050 recv_transport->SetReceiver(sender_call_->Receiver());
1051
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001052 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001053 // Create video renderers.
1054 local_preview.reset(test::VideoRenderer::Create(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001055 "Local Preview", params_.video[0].width, params_.video[0].height));
eladalon413ee9a2017-08-22 04:02:52 -07001056
1057 SetupVideo(send_transport.get(), recv_transport.get());
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001058 GetVideoSendConfig()->pre_encode_callback = local_preview.get();
eladalon413ee9a2017-08-22 04:02:52 -07001059
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001060 size_t num_streams_processed = 0;
1061 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1062 const size_t selected_stream_id = params_.ss[video_idx].selected_stream;
1063 const size_t num_streams = params_.ss[video_idx].streams.size();
1064 if (selected_stream_id == num_streams) {
1065 for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
1066 std::ostringstream oss;
1067 oss << "Loopback Video #" << video_idx << " - Stream #"
1068 << static_cast<int>(stream_id);
1069 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1070 oss.str().c_str(),
1071 params_.ss[video_idx].streams[stream_id].width,
1072 params_.ss[video_idx].streams[stream_id].height));
1073 video_receive_configs_[stream_id + num_streams_processed].renderer =
1074 loopback_renderers.back().get();
1075 if (params_.audio.enabled && params_.audio.sync_video)
1076 video_receive_configs_[stream_id + num_streams_processed]
1077 .sync_group = kSyncGroup;
1078 }
1079 } else {
1080 std::ostringstream oss;
1081 oss << "Loopback Video #" << video_idx;
1082 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1083 oss.str().c_str(),
1084 params_.ss[video_idx].streams[selected_stream_id].width,
1085 params_.ss[video_idx].streams[selected_stream_id].height));
1086 video_receive_configs_[selected_stream_id + num_streams_processed]
1087 .renderer = loopback_renderers.back().get();
eladalon413ee9a2017-08-22 04:02:52 -07001088 if (params_.audio.enabled && params_.audio.sync_video)
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001089 video_receive_configs_[num_streams_processed + selected_stream_id]
1090 .sync_group = kSyncGroup;
eladalon413ee9a2017-08-22 04:02:52 -07001091 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001092 num_streams_processed += num_streams;
eladalon413ee9a2017-08-22 04:02:52 -07001093 }
eladalon413ee9a2017-08-22 04:02:52 -07001094 CreateFlexfecStreams();
1095 CreateVideoStreams();
1096
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001097 CreateCapturers();
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001098 ConnectVideoSourcesToStreams();
eladalon413ee9a2017-08-22 04:02:52 -07001099 }
1100
1101 if (params_.audio.enabled) {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001102 SetupAudio(send_transport.get());
eladalon413ee9a2017-08-22 04:02:52 -07001103 }
1104
1105 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1106 StartEncodedFrameLogs(receive_stream);
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001107 StartEncodedFrameLogs(GetVideoSendStream());
1108 Start();
eladalon413ee9a2017-08-22 04:02:52 -07001109 });
minyue73208662016-08-18 06:28:55 -07001110
ivica5d6a06c2015-09-17 05:30:24 -07001111 test::PressEnterToContinue();
1112
eladalon413ee9a2017-08-22 04:02:52 -07001113 task_queue_.SendTask([&]() {
Sebastian Jansson3bd2c792018-07-13 13:29:03 +02001114 Stop();
1115 DestroyStreams();
minyue73208662016-08-18 06:28:55 -07001116
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001117 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -07001118 send_transport.reset();
1119 recv_transport.reset();
sprang1168fd42017-06-21 09:00:17 -07001120
eladalon413ee9a2017-08-22 04:02:52 -07001121 local_preview.reset();
1122 loopback_renderers.clear();
1123
1124 DestroyCalls();
1125 });
ivica5d6a06c2015-09-17 05:30:24 -07001126}
1127
palmkviste75f2042016-09-28 06:19:48 -07001128void VideoQualityTest::StartEncodedFrameLogs(VideoSendStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001129 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001130 std::ostringstream str;
1131 str << send_logs_++;
1132 std::string prefix =
ilnik98436952017-07-13 00:47:03 -07001133 params_.logging.encoded_frame_base_path + "." + str.str() + ".send.";
palmkviste75f2042016-09-28 06:19:48 -07001134 stream->EnableEncodedFrameRecording(
1135 std::vector<rtc::PlatformFile>(
1136 {rtc::CreatePlatformFile(prefix + "1.ivf"),
1137 rtc::CreatePlatformFile(prefix + "2.ivf"),
1138 rtc::CreatePlatformFile(prefix + "3.ivf")}),
ilnik98436952017-07-13 00:47:03 -07001139 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001140 }
1141}
ilnikcb8c1462017-03-09 09:23:30 -08001142
palmkviste75f2042016-09-28 06:19:48 -07001143void VideoQualityTest::StartEncodedFrameLogs(VideoReceiveStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001144 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001145 std::ostringstream str;
1146 str << receive_logs_++;
1147 std::string path =
ilnik98436952017-07-13 00:47:03 -07001148 params_.logging.encoded_frame_base_path + "." + str.str() + ".recv.ivf";
palmkviste75f2042016-09-28 06:19:48 -07001149 stream->EnableEncodedFrameRecording(rtc::CreatePlatformFile(path),
ilnik98436952017-07-13 00:47:03 -07001150 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001151 }
1152}
ivica5d6a06c2015-09-17 05:30:24 -07001153} // namespace webrtc