blob: a88901fec89189b3160c3e89ca22a497db87e6e1 [file] [log] [blame]
ivica5d6a06c2015-09-17 05:30:24 -07001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020010#include "video/video_quality_test.h"
perkj9fdbda62016-09-15 09:19:20 -070011
perkja49cbd32016-09-16 07:53:41 -070012#include <stdio.h>
ivica5d6a06c2015-09-17 05:30:24 -070013#include <algorithm>
14#include <deque>
15#include <map>
sprangce4aef12015-11-02 07:23:20 -080016#include <sstream>
mflodmand1590b22015-12-09 07:07:59 -080017#include <string>
ivica5d6a06c2015-09-17 05:30:24 -070018#include <vector>
19
Elad Alon83ccca12017-10-04 13:18:26 +020020#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
Magnus Jedvert46a27652017-11-13 14:10:02 +010021#include "media/engine/internalencoderfactory.h"
Niels Möller19a68d42018-04-13 13:37:52 +020022#include "media/engine/vp8_encoder_simulcast_proxy.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "media/engine/webrtcvideoengine.h"
24#include "modules/audio_mixer/audio_mixer_impl.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/video_coding/codecs/h264/include/h264.h"
Emircan Uysaler03e6ec92018-03-09 15:03:26 -080026#include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h"
Niels Möller4db138e2018-04-19 09:04:13 +020027#include "modules/video_coding/codecs/vp8/include/vp8.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "modules/video_coding/codecs/vp9/include/vp9.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "test/run_loop.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "test/testsupport/fileutils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "test/video_renderer.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020032#include "video/video_analyzer.h"
ilnikee42d192017-08-22 07:16:20 -070033
minyue73208662016-08-18 06:28:55 -070034namespace {
minyue73208662016-08-18 06:28:55 -070035constexpr char kSyncGroup[] = "av_sync";
minyue10cbb462016-11-07 09:29:22 -080036constexpr int kOpusMinBitrateBps = 6000;
37constexpr int kOpusBitrateFbBps = 32000;
ilnik9ae0d762017-02-15 00:53:12 -080038constexpr int kFramesSentInQuickTest = 1;
ilnika014cc52017-03-07 04:21:04 -080039constexpr uint32_t kThumbnailSendSsrcStart = 0xE0000;
40constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000;
minyue73208662016-08-18 06:28:55 -070041
sprang1168fd42017-06-21 09:00:17 -070042constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax;
43
perkjfa10b552016-10-02 23:45:26 -070044class VideoStreamFactory
45 : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface {
46 public:
47 explicit VideoStreamFactory(const std::vector<webrtc::VideoStream>& streams)
48 : streams_(streams) {}
49
50 private:
51 std::vector<webrtc::VideoStream> CreateEncoderStreams(
52 int width,
53 int height,
54 const webrtc::VideoEncoderConfig& encoder_config) override {
mflodmand79f97b2016-12-15 07:24:33 -080055 // The highest layer must match the incoming resolution.
56 std::vector<webrtc::VideoStream> streams = streams_;
57 streams[streams_.size() - 1].height = height;
58 streams[streams_.size() - 1].width = width;
Seth Hampson24722b32017-12-22 09:36:42 -080059
60 streams[0].bitrate_priority = encoder_config.bitrate_priority;
mflodmand79f97b2016-12-15 07:24:33 -080061 return streams;
perkjfa10b552016-10-02 23:45:26 -070062 }
63
64 std::vector<webrtc::VideoStream> streams_;
65};
minyue73208662016-08-18 06:28:55 -070066} // namespace
ivica5d6a06c2015-09-17 05:30:24 -070067
68namespace webrtc {
69
Niels Möller4db138e2018-04-19 09:04:13 +020070// Not used by these tests.
71std::vector<SdpVideoFormat>
72VideoQualityTest::TestVideoEncoderFactory::GetSupportedFormats() const {
73 RTC_NOTREACHED();
74 return {};
75}
76
77VideoEncoderFactory::CodecInfo
78VideoQualityTest::TestVideoEncoderFactory::QueryVideoEncoder(
79 const SdpVideoFormat& format) const {
80 CodecInfo codec_info;
81 codec_info.is_hardware_accelerated = false;
82 codec_info.has_internal_source = false;
83 return codec_info;
84}
85
86std::unique_ptr<VideoEncoder>
87VideoQualityTest::TestVideoEncoderFactory::CreateVideoEncoder(
88 const SdpVideoFormat& format) {
89 if (format.name == "VP8") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020090 return absl::make_unique<VP8EncoderSimulcastProxy>(
91 &internal_encoder_factory_, format);
Niels Möller4db138e2018-04-19 09:04:13 +020092 } else if (format.name == "multiplex") {
Karl Wiberg918f50c2018-07-05 11:40:33 +020093 return absl::make_unique<MultiplexEncoderAdapter>(
Niels Möller4db138e2018-04-19 09:04:13 +020094 &internal_encoder_factory_, SdpVideoFormat(cricket::kVp9CodecName));
95 } else {
96 return internal_encoder_factory_.CreateVideoEncoder(format);
97 }
98}
99
Patrik Höglundb6b29e02018-06-21 16:58:01 +0200100VideoQualityTest::VideoQualityTest(
101 std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory)
minyue20c84cc2017-04-10 16:57:57 -0700102 : clock_(Clock::GetRealTimeClock()), receive_logs_(0), send_logs_(0) {
103 payload_type_map_ = test::CallTest::payload_type_map_;
104 RTC_DCHECK(payload_type_map_.find(kPayloadTypeH264) ==
105 payload_type_map_.end());
106 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP8) ==
107 payload_type_map_.end());
108 RTC_DCHECK(payload_type_map_.find(kPayloadTypeVP9) ==
109 payload_type_map_.end());
110 payload_type_map_[kPayloadTypeH264] = webrtc::MediaType::VIDEO;
111 payload_type_map_[kPayloadTypeVP8] = webrtc::MediaType::VIDEO;
112 payload_type_map_[kPayloadTypeVP9] = webrtc::MediaType::VIDEO;
ivica5d6a06c2015-09-17 05:30:24 -0700113
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100114 fec_controller_factory_ = std::move(fec_controller_factory);
Ying Wang3b790f32018-01-19 17:58:57 +0100115}
116
minyue626bc952016-10-31 05:47:02 -0700117VideoQualityTest::Params::Params()
Sebastian Janssonfc8d26b2018-02-21 09:52:06 +0100118 : call({false, BitrateConstraints(), 0}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100119 video{{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200120 false, false, ""},
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100121 {false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
Niels Möller6aa415e2018-06-07 11:14:13 +0200122 false, false, ""}},
minyue4c8b9422017-03-21 04:11:43 -0700123 audio({false, false, false}),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100124 screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
minyue626bc952016-10-31 05:47:02 -0700125 analyzer({"", 0.0, 0.0, 0, "", ""}),
126 pipe(),
Sergey Silkin57027362018-05-15 09:12:05 +0200127 ss{{std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
128 std::vector<SpatialLayer>()},
129 {std::vector<VideoStream>(), 0, 0, -1, InterLayerPredMode::kOn,
130 std::vector<SpatialLayer>()}},
ilnik98436952017-07-13 00:47:03 -0700131 logging({false, "", "", ""}) {}
minyue626bc952016-10-31 05:47:02 -0700132
133VideoQualityTest::Params::~Params() = default;
134
ivica5d6a06c2015-09-17 05:30:24 -0700135void VideoQualityTest::TestBody() {}
136
sprangce4aef12015-11-02 07:23:20 -0800137std::string VideoQualityTest::GenerateGraphTitle() const {
138 std::stringstream ss;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100139 ss << params_.video[0].codec;
140 ss << " (" << params_.video[0].target_bitrate_bps / 1000 << "kbps";
141 ss << ", " << params_.video[0].fps << " FPS";
142 if (params_.screenshare[0].scroll_duration)
143 ss << ", " << params_.screenshare[0].scroll_duration << "s scroll";
144 if (params_.ss[0].streams.size() > 1)
145 ss << ", Stream #" << params_.ss[0].selected_stream;
146 if (params_.ss[0].num_spatial_layers > 1)
147 ss << ", Layer #" << params_.ss[0].selected_sl;
sprangce4aef12015-11-02 07:23:20 -0800148 ss << ")";
149 return ss.str();
150}
151
152void VideoQualityTest::CheckParams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100153 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
154 // Iterate over primary and secondary video streams.
155 if (!params_.video[video_idx].enabled)
156 return;
157 // Add a default stream in none specified.
158 if (params_.ss[video_idx].streams.empty())
159 params_.ss[video_idx].streams.push_back(
160 VideoQualityTest::DefaultVideoStream(params_, video_idx));
161 if (params_.ss[video_idx].num_spatial_layers == 0)
162 params_.ss[video_idx].num_spatial_layers = 1;
sprangce4aef12015-11-02 07:23:20 -0800163
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100164 if (params_.pipe.loss_percent != 0 ||
165 params_.pipe.queue_length_packets != 0) {
166 // Since LayerFilteringTransport changes the sequence numbers, we can't
167 // use that feature with pack loss, since the NACK request would end up
168 // retransmitting the wrong packets.
169 RTC_CHECK(params_.ss[video_idx].selected_sl == -1 ||
170 params_.ss[video_idx].selected_sl ==
171 params_.ss[video_idx].num_spatial_layers - 1);
172 RTC_CHECK(params_.video[video_idx].selected_tl == -1 ||
173 params_.video[video_idx].selected_tl ==
174 params_.video[video_idx].num_temporal_layers - 1);
175 }
sprangce4aef12015-11-02 07:23:20 -0800176
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100177 // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as
178 // it does in some parts of the code?
179 RTC_CHECK_GE(params_.video[video_idx].max_bitrate_bps,
180 params_.video[video_idx].target_bitrate_bps);
181 RTC_CHECK_GE(params_.video[video_idx].target_bitrate_bps,
182 params_.video[video_idx].min_bitrate_bps);
183 RTC_CHECK_LT(params_.video[video_idx].selected_tl,
184 params_.video[video_idx].num_temporal_layers);
185 RTC_CHECK_LE(params_.ss[video_idx].selected_stream,
186 params_.ss[video_idx].streams.size());
187 for (const VideoStream& stream : params_.ss[video_idx].streams) {
188 RTC_CHECK_GE(stream.min_bitrate_bps, 0);
189 RTC_CHECK_GE(stream.target_bitrate_bps, stream.min_bitrate_bps);
190 RTC_CHECK_GE(stream.max_bitrate_bps, stream.target_bitrate_bps);
191 }
192 // TODO(ivica): Should we check if the sum of all streams/layers is equal to
193 // the total bitrate? We anyway have to update them in the case bitrate
194 // estimator changes the total bitrates.
195 RTC_CHECK_GE(params_.ss[video_idx].num_spatial_layers, 1);
196 RTC_CHECK_LE(params_.ss[video_idx].selected_sl,
197 params_.ss[video_idx].num_spatial_layers);
198 RTC_CHECK(
199 params_.ss[video_idx].spatial_layers.empty() ||
200 params_.ss[video_idx].spatial_layers.size() ==
201 static_cast<size_t>(params_.ss[video_idx].num_spatial_layers));
202 if (params_.video[video_idx].codec == "VP8") {
203 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
204 } else if (params_.video[video_idx].codec == "VP9") {
205 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 1);
206 }
207 RTC_CHECK_GE(params_.call.num_thumbnails, 0);
208 if (params_.call.num_thumbnails > 0) {
209 RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1);
210 RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 3);
211 RTC_CHECK_EQ(params_.video[video_idx].num_temporal_layers, 3);
212 RTC_CHECK_EQ(params_.video[video_idx].codec, "VP8");
213 }
214 // Dual streams with FEC not supported in tests yet.
215 RTC_CHECK(!params_.video[video_idx].flexfec || num_video_streams_ == 1);
216 RTC_CHECK(!params_.video[video_idx].ulpfec || num_video_streams_ == 1);
ilnika014cc52017-03-07 04:21:04 -0800217 }
sprangce4aef12015-11-02 07:23:20 -0800218}
219
220// Static.
221std::vector<int> VideoQualityTest::ParseCSV(const std::string& str) {
222 // Parse comma separated nonnegative integers, where some elements may be
223 // empty. The empty values are replaced with -1.
224 // E.g. "10,-20,,30,40" --> {10, 20, -1, 30,40}
225 // E.g. ",,10,,20," --> {-1, -1, 10, -1, 20, -1}
226 std::vector<int> result;
227 if (str.empty())
228 return result;
229
230 const char* p = str.c_str();
231 int value = -1;
232 int pos;
233 while (*p) {
234 if (*p == ',') {
235 result.push_back(value);
236 value = -1;
237 ++p;
238 continue;
239 }
240 RTC_CHECK_EQ(sscanf(p, "%d%n", &value, &pos), 1)
241 << "Unexpected non-number value.";
242 p += pos;
243 }
244 result.push_back(value);
245 return result;
246}
247
248// Static.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100249VideoStream VideoQualityTest::DefaultVideoStream(const Params& params,
250 size_t video_idx) {
sprangce4aef12015-11-02 07:23:20 -0800251 VideoStream stream;
Danil Chapovalov350531e2018-06-08 11:04:04 +0000252 stream.width = params.video[video_idx].width;
253 stream.height = params.video[video_idx].height;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100254 stream.max_framerate = params.video[video_idx].fps;
255 stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps;
256 stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
257 stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
sprang1168fd42017-06-21 09:00:17 -0700258 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100259 stream.num_temporal_layers = params.video[video_idx].num_temporal_layers;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800260 stream.active = true;
ilnika014cc52017-03-07 04:21:04 -0800261 return stream;
262}
263
264// Static.
265VideoStream VideoQualityTest::DefaultThumbnailStream() {
266 VideoStream stream;
267 stream.width = 320;
268 stream.height = 180;
269 stream.max_framerate = 7;
270 stream.min_bitrate_bps = 7500;
271 stream.target_bitrate_bps = 37500;
272 stream.max_bitrate_bps = 50000;
sprang1168fd42017-06-21 09:00:17 -0700273 stream.max_qp = kDefaultMaxQp;
sprangce4aef12015-11-02 07:23:20 -0800274 return stream;
275}
276
277// Static.
278void VideoQualityTest::FillScalabilitySettings(
279 Params* params,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100280 size_t video_idx,
sprangce4aef12015-11-02 07:23:20 -0800281 const std::vector<std::string>& stream_descriptors,
sprang1168fd42017-06-21 09:00:17 -0700282 int num_streams,
sprangce4aef12015-11-02 07:23:20 -0800283 size_t selected_stream,
284 int num_spatial_layers,
285 int selected_sl,
Sergey Silkin57027362018-05-15 09:12:05 +0200286 InterLayerPredMode inter_layer_pred,
sprangce4aef12015-11-02 07:23:20 -0800287 const std::vector<std::string>& sl_descriptors) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100288 if (params->ss[video_idx].streams.empty() &&
289 params->ss[video_idx].infer_streams) {
sprang1168fd42017-06-21 09:00:17 -0700290 webrtc::VideoEncoderConfig encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200291 encoder_config.codec_type =
292 PayloadStringToCodecType(params->video[video_idx].codec);
sprang1168fd42017-06-21 09:00:17 -0700293 encoder_config.content_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100294 params->screenshare[video_idx].enabled
sprang1168fd42017-06-21 09:00:17 -0700295 ? webrtc::VideoEncoderConfig::ContentType::kScreen
296 : webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100297 encoder_config.max_bitrate_bps = params->video[video_idx].max_bitrate_bps;
298 encoder_config.min_transmit_bitrate_bps =
299 params->video[video_idx].min_transmit_bps;
sprang1168fd42017-06-21 09:00:17 -0700300 encoder_config.number_of_streams = num_streams;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100301 encoder_config.spatial_layers = params->ss[video_idx].spatial_layers;
Seth Hampson8234ead2018-02-02 15:16:24 -0800302 encoder_config.simulcast_layers = std::vector<VideoStream>(num_streams);
sprang1168fd42017-06-21 09:00:17 -0700303 encoder_config.video_stream_factory =
304 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100305 params->video[video_idx].codec, kDefaultMaxQp,
306 params->video[video_idx].fps,
307 params->screenshare[video_idx].enabled, true);
308 params->ss[video_idx].streams =
sprang1168fd42017-06-21 09:00:17 -0700309 encoder_config.video_stream_factory->CreateEncoderStreams(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100310 static_cast<int>(params->video[video_idx].width),
311 static_cast<int>(params->video[video_idx].height), encoder_config);
sprang1168fd42017-06-21 09:00:17 -0700312 } else {
313 // Read VideoStream and SpatialLayer elements from a list of comma separated
314 // lists. To use a default value for an element, use -1 or leave empty.
315 // Validity checks performed in CheckParams.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100316 RTC_CHECK(params->ss[video_idx].streams.empty());
sprang1168fd42017-06-21 09:00:17 -0700317 for (auto descriptor : stream_descriptors) {
318 if (descriptor.empty())
319 continue;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100320 VideoStream stream =
321 VideoQualityTest::DefaultVideoStream(*params, video_idx);
sprang1168fd42017-06-21 09:00:17 -0700322 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
323 if (v[0] != -1)
324 stream.width = static_cast<size_t>(v[0]);
325 if (v[1] != -1)
326 stream.height = static_cast<size_t>(v[1]);
327 if (v[2] != -1)
328 stream.max_framerate = v[2];
329 if (v[3] != -1)
330 stream.min_bitrate_bps = v[3];
331 if (v[4] != -1)
332 stream.target_bitrate_bps = v[4];
333 if (v[5] != -1)
334 stream.max_bitrate_bps = v[5];
335 if (v.size() > 6 && v[6] != -1)
336 stream.max_qp = v[6];
Sergey Silkina796a7e2018-03-01 15:11:29 +0100337 if (v.size() > 7 && v[7] != -1) {
338 stream.num_temporal_layers = v[7];
sprang1168fd42017-06-21 09:00:17 -0700339 } else {
340 // Automatic TL thresholds for more than two layers not supported.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100341 RTC_CHECK_LE(params->video[video_idx].num_temporal_layers, 2);
sprang1168fd42017-06-21 09:00:17 -0700342 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100343 params->ss[video_idx].streams.push_back(stream);
sprangce4aef12015-11-02 07:23:20 -0800344 }
sprangce4aef12015-11-02 07:23:20 -0800345 }
sprangce4aef12015-11-02 07:23:20 -0800346
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100347 params->ss[video_idx].num_spatial_layers = std::max(1, num_spatial_layers);
348 params->ss[video_idx].selected_stream = selected_stream;
sprang1168fd42017-06-21 09:00:17 -0700349
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100350 params->ss[video_idx].selected_sl = selected_sl;
Sergey Silkin57027362018-05-15 09:12:05 +0200351 params->ss[video_idx].inter_layer_pred = inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100352 RTC_CHECK(params->ss[video_idx].spatial_layers.empty());
sprangce4aef12015-11-02 07:23:20 -0800353 for (auto descriptor : sl_descriptors) {
354 if (descriptor.empty())
355 continue;
356 std::vector<int> v = VideoQualityTest::ParseCSV(descriptor);
Sergey Silkin13e74342018-03-02 12:28:00 +0100357 RTC_CHECK_EQ(v.size(), 7);
sprangce4aef12015-11-02 07:23:20 -0800358
Sergey Silkin13e74342018-03-02 12:28:00 +0100359 SpatialLayer layer = {0};
360 layer.width = v[0];
361 layer.height = v[1];
362 layer.numberOfTemporalLayers = v[2];
363 layer.maxBitrate = v[3];
364 layer.minBitrate = v[4];
365 layer.targetBitrate = v[5];
366 layer.qpMax = v[6];
367 layer.active = true;
368
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100369 params->ss[video_idx].spatial_layers.push_back(layer);
sprangce4aef12015-11-02 07:23:20 -0800370 }
371}
372
minyuea27172d2016-11-01 05:59:29 -0700373void VideoQualityTest::SetupVideo(Transport* send_transport,
374 Transport* recv_transport) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100375 size_t total_streams_used = 0;
376 size_t num_flexfec_streams = params_.video[0].flexfec ? 1 : 0;
377 CreateAudioAndFecSendConfigs(0, num_flexfec_streams, send_transport);
378 CreateMatchingAudioAndFecConfigs(recv_transport);
379 video_receive_configs_.clear();
380 video_send_configs_.clear();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100381 video_encoder_configs_.clear();
382 allocated_decoders_.clear();
383 bool decode_all_receive_streams = true;
384 size_t num_video_substreams = params_.ss[0].streams.size();
385 RTC_CHECK(num_video_streams_ > 0);
386 video_encoder_configs_.resize(num_video_streams_);
387 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
388 video_send_configs_.push_back(VideoSendStream::Config(send_transport));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100389 video_encoder_configs_.push_back(VideoEncoderConfig());
390 num_video_substreams = params_.ss[video_idx].streams.size();
391 RTC_CHECK_GT(num_video_substreams, 0);
392 CreateVideoSendConfig(&video_send_configs_[video_idx], num_video_substreams,
393 total_streams_used, send_transport);
ivica5d6a06c2015-09-17 05:30:24 -0700394
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100395 int payload_type;
396 if (params_.video[video_idx].codec == "H264") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100397 payload_type = kPayloadTypeH264;
398 } else if (params_.video[video_idx].codec == "VP8") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100399 payload_type = kPayloadTypeVP8;
400 } else if (params_.video[video_idx].codec == "VP9") {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100401 payload_type = kPayloadTypeVP9;
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800402 } else if (params_.video[video_idx].codec == "multiplex") {
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800403 payload_type = kPayloadTypeVP9;
ilnikcb8c1462017-03-09 09:23:30 -0800404 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100405 RTC_NOTREACHED() << "Codec not supported!";
406 return;
ilnikcb8c1462017-03-09 09:23:30 -0800407 }
Niels Möller4db138e2018-04-19 09:04:13 +0200408 video_send_configs_[video_idx].encoder_settings.encoder_factory =
409 &video_encoder_factory_;
410
Niels Möller259a4972018-04-05 15:36:51 +0200411 video_send_configs_[video_idx].rtp.payload_name =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100412 params_.video[video_idx].codec;
Niels Möller259a4972018-04-05 15:36:51 +0200413 video_send_configs_[video_idx].rtp.payload_type = payload_type;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100414 video_send_configs_[video_idx].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
415 video_send_configs_[video_idx].rtp.rtx.payload_type = kSendRtxPayloadType;
416 for (size_t i = 0; i < num_video_substreams; ++i) {
417 video_send_configs_[video_idx].rtp.rtx.ssrcs.push_back(
418 kSendRtxSsrcs[i + total_streams_used]);
ilnik9fd9f6c2017-03-02 08:10:10 -0800419 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100420 video_send_configs_[video_idx].rtp.extensions.clear();
421 if (params_.call.send_side_bwe) {
422 video_send_configs_[video_idx].rtp.extensions.push_back(
423 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
424 test::kTransportSequenceNumberExtensionId));
425 } else {
426 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
427 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
428 }
429 video_send_configs_[video_idx].rtp.extensions.push_back(
430 RtpExtension(RtpExtension::kVideoContentTypeUri,
431 test::kVideoContentTypeExtensionId));
432 video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension(
433 RtpExtension::kVideoTimingUri, test::kVideoTimingExtensionId));
434
Niels Möller4db138e2018-04-19 09:04:13 +0200435 video_encoder_configs_[video_idx].video_format.name =
436 params_.video[video_idx].codec;
437
Niels Möller259a4972018-04-05 15:36:51 +0200438 video_encoder_configs_[video_idx].codec_type =
439 PayloadStringToCodecType(params_.video[video_idx].codec);
440
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100441 video_encoder_configs_[video_idx].min_transmit_bitrate_bps =
442 params_.video[video_idx].min_transmit_bps;
443
444 video_send_configs_[video_idx].suspend_below_min_bitrate =
445 params_.video[video_idx].suspend_below_min_bitrate;
446
447 video_encoder_configs_[video_idx].number_of_streams =
448 params_.ss[video_idx].streams.size();
449 video_encoder_configs_[video_idx].max_bitrate_bps = 0;
450 for (size_t i = 0; i < params_.ss[video_idx].streams.size(); ++i) {
451 video_encoder_configs_[video_idx].max_bitrate_bps +=
452 params_.ss[video_idx].streams[i].max_bitrate_bps;
453 }
454 if (params_.ss[video_idx].infer_streams) {
Seth Hampson8234ead2018-02-02 15:16:24 -0800455 video_encoder_configs_[video_idx].simulcast_layers =
456 std::vector<VideoStream>(params_.ss[video_idx].streams.size());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100457 video_encoder_configs_[video_idx].video_stream_factory =
458 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
459 params_.video[video_idx].codec,
460 params_.ss[video_idx].streams[0].max_qp,
461 params_.video[video_idx].fps,
462 params_.screenshare[video_idx].enabled, true);
463 } else {
464 video_encoder_configs_[video_idx].video_stream_factory =
465 new rtc::RefCountedObject<VideoStreamFactory>(
466 params_.ss[video_idx].streams);
467 }
468
469 video_encoder_configs_[video_idx].spatial_layers =
470 params_.ss[video_idx].spatial_layers;
471
472 std::vector<VideoReceiveStream::Config> new_receive_configs =
473 CreateMatchingVideoReceiveConfigs(video_send_configs_[video_idx],
474 recv_transport);
475
476 decode_all_receive_streams = params_.ss[video_idx].selected_stream ==
477 params_.ss[video_idx].streams.size();
478
479 for (size_t i = 0; i < num_video_substreams; ++i) {
480 new_receive_configs[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
481 new_receive_configs[i].rtp.rtx_ssrc =
482 kSendRtxSsrcs[i + total_streams_used];
483 new_receive_configs[i]
484 .rtp.rtx_associated_payload_types[kSendRtxPayloadType] = payload_type;
485 new_receive_configs[i].rtp.transport_cc = params_.call.send_side_bwe;
486 new_receive_configs[i].rtp.remb = !params_.call.send_side_bwe;
487 // Enable RTT calculation so NTP time estimator will work.
488 new_receive_configs[i].rtp.rtcp_xr.receiver_reference_time_report = true;
489 // Force fake decoders on non-selected simulcast streams.
490 if (!decode_all_receive_streams &&
491 i != params_.ss[video_idx].selected_stream) {
492 VideoReceiveStream::Decoder decoder;
493 decoder.decoder = new test::FakeDecoder();
Niels Möller259a4972018-04-05 15:36:51 +0200494 decoder.payload_type = video_send_configs_[video_idx].rtp.payload_type;
495 decoder.payload_name = video_send_configs_[video_idx].rtp.payload_name;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100496 new_receive_configs[i].decoders.clear();
497 allocated_decoders_.emplace_back(decoder.decoder);
498 new_receive_configs[i].decoders.push_back(decoder);
499 }
500 }
501
502 for (VideoReceiveStream::Config& config : new_receive_configs) {
503 video_receive_configs_.push_back(config.Copy());
504 }
505
506 if (params_.screenshare[video_idx].enabled) {
507 // Fill out codec settings.
508 video_encoder_configs_[video_idx].content_type =
509 VideoEncoderConfig::ContentType::kScreen;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700510 degradation_preference_ = DegradationPreference::MAINTAIN_RESOLUTION;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100511 if (params_.video[video_idx].codec == "VP8") {
512 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
513 vp8_settings.denoisingOn = false;
514 vp8_settings.frameDroppingOn = false;
515 vp8_settings.numberOfTemporalLayers = static_cast<unsigned char>(
516 params_.video[video_idx].num_temporal_layers);
517 video_encoder_configs_[video_idx].encoder_specific_settings =
518 new rtc::RefCountedObject<
519 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
520 } else if (params_.video[video_idx].codec == "VP9") {
521 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
522 vp9_settings.denoisingOn = false;
523 vp9_settings.frameDroppingOn = false;
524 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
525 params_.video[video_idx].num_temporal_layers);
526 vp9_settings.numberOfSpatialLayers = static_cast<unsigned char>(
527 params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200528 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100529 video_encoder_configs_[video_idx].encoder_specific_settings =
530 new rtc::RefCountedObject<
531 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
532 }
533 } else if (params_.ss[video_idx].num_spatial_layers > 1) {
534 // If SVC mode without screenshare, still need to set codec specifics.
535 RTC_CHECK(params_.video[video_idx].codec == "VP9");
536 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
537 vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>(
538 params_.video[video_idx].num_temporal_layers);
539 vp9_settings.numberOfSpatialLayers =
540 static_cast<unsigned char>(params_.ss[video_idx].num_spatial_layers);
Sergey Silkin57027362018-05-15 09:12:05 +0200541 vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100542 video_encoder_configs_[video_idx].encoder_specific_settings =
543 new rtc::RefCountedObject<
544 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Niels Möller6aa415e2018-06-07 11:14:13 +0200545 } else if (params_.video[video_idx].automatic_scaling) {
546 if (params_.video[video_idx].codec == "VP8") {
547 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
548 vp8_settings.automaticResizeOn = true;
549 video_encoder_configs_[video_idx].encoder_specific_settings =
550 new rtc::RefCountedObject<
551 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
552 } else if (params_.video[video_idx].codec == "VP9") {
553 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
554 vp9_settings.automaticResizeOn = true;
555 video_encoder_configs_[video_idx].encoder_specific_settings =
556 new rtc::RefCountedObject<
557 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
558 } else {
559 RTC_NOTREACHED() << "Automatic scaling not supported for codec "
Yves Gerey665174f2018-06-19 15:03:05 +0200560 << params_.video[video_idx].codec << ", stream "
561 << video_idx;
Niels Möller6aa415e2018-06-07 11:14:13 +0200562 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100563 }
564 total_streams_used += num_video_substreams;
sprangce4aef12015-11-02 07:23:20 -0800565 }
brandtr1293aca2016-11-16 22:47:29 -0800566
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100567 // FEC supported only for single video stream mode yet.
568 if (params_.video[0].flexfec) {
Ilya Nikolaevskiy38aaf692017-12-22 14:39:09 +0100569 video_send_configs_[0].rtp.flexfec.payload_type = kFlexfecPayloadType;
570 video_send_configs_[0].rtp.flexfec.ssrc = kFlexfecSendSsrc;
sprang1168fd42017-06-21 09:00:17 -0700571 if (decode_all_receive_streams) {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100572 for (uint32_t media_ssrc : video_send_configs_[0].rtp.ssrcs) {
573 video_send_configs_[0].rtp.flexfec.protected_media_ssrcs.push_back(
sprang1168fd42017-06-21 09:00:17 -0700574 media_ssrc);
575 }
576 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100577 video_send_configs_[0].rtp.flexfec.protected_media_ssrcs = {
578 kVideoSendSsrcs[params_.ss[0].selected_stream]};
sprang1168fd42017-06-21 09:00:17 -0700579 }
brandtr1293aca2016-11-16 22:47:29 -0800580
brandtr8313a6f2017-01-13 07:41:19 -0800581 // The matching receive config is _not_ created by
582 // CreateMatchingReceiveConfigs, since VideoQualityTest is not a BaseTest.
583 // Set up the receive config manually instead.
584 FlexfecReceiveStream::Config flexfec_receive_config(recv_transport);
brandtr1cfbd602016-12-08 04:17:53 -0800585 flexfec_receive_config.payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100586 video_send_configs_[0].rtp.flexfec.payload_type;
587 flexfec_receive_config.remote_ssrc =
588 video_send_configs_[0].rtp.flexfec.ssrc;
brandtr1293aca2016-11-16 22:47:29 -0800589 flexfec_receive_config.protected_media_ssrcs =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100590 video_send_configs_[0].rtp.flexfec.protected_media_ssrcs;
brandtrfa5a3682017-01-17 01:33:54 -0800591 flexfec_receive_config.local_ssrc = kReceiverLocalVideoSsrc;
brandtrb29e6522016-12-21 06:37:18 -0800592 flexfec_receive_config.transport_cc = params_.call.send_side_bwe;
593 if (params_.call.send_side_bwe) {
594 flexfec_receive_config.rtp_header_extensions.push_back(
595 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
596 test::kTransportSequenceNumberExtensionId));
597 } else {
598 flexfec_receive_config.rtp_header_extensions.push_back(RtpExtension(
599 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
600 }
brandtr1293aca2016-11-16 22:47:29 -0800601 flexfec_receive_configs_.push_back(flexfec_receive_config);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100602 if (num_video_substreams > 0) {
brandtr7cd28b92017-09-22 00:26:25 -0700603 video_receive_configs_[0].rtp.protected_by_flexfec = true;
604 }
brandtr1293aca2016-11-16 22:47:29 -0800605 }
606
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100607 if (params_.video[0].ulpfec) {
608 video_send_configs_[0].rtp.ulpfec.red_payload_type = kRedPayloadType;
609 video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
610 video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType;
brandtr1293aca2016-11-16 22:47:29 -0800611
sprang1168fd42017-06-21 09:00:17 -0700612 if (decode_all_receive_streams) {
613 for (auto it = video_receive_configs_.begin();
614 it != video_receive_configs_.end(); ++it) {
nisse3b3622f2017-09-26 02:49:21 -0700615 it->rtp.red_payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100616 video_send_configs_[0].rtp.ulpfec.red_payload_type;
nisse3b3622f2017-09-26 02:49:21 -0700617 it->rtp.ulpfec_payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100618 video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type;
619 it->rtp.rtx_associated_payload_types
620 [video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type] =
621 video_send_configs_[0].rtp.ulpfec.red_payload_type;
sprang1168fd42017-06-21 09:00:17 -0700622 }
623 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100624 video_receive_configs_[params_.ss[0].selected_stream]
625 .rtp.red_payload_type =
626 video_send_configs_[0].rtp.ulpfec.red_payload_type;
627 video_receive_configs_[params_.ss[0].selected_stream]
nisse3b3622f2017-09-26 02:49:21 -0700628 .rtp.ulpfec_payload_type =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100629 video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type;
630 video_receive_configs_[params_.ss[0].selected_stream]
631 .rtp.rtx_associated_payload_types
632 [video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type] =
633 video_send_configs_[0].rtp.ulpfec.red_payload_type;
sprang1168fd42017-06-21 09:00:17 -0700634 }
brandtr1293aca2016-11-16 22:47:29 -0800635 }
ivica5d6a06c2015-09-17 05:30:24 -0700636}
637
ilnika014cc52017-03-07 04:21:04 -0800638void VideoQualityTest::SetupThumbnails(Transport* send_transport,
639 Transport* recv_transport) {
ilnik98436952017-07-13 00:47:03 -0700640 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 04:21:04 -0800641 // Thumbnails will be send in the other way: from receiver_call to
642 // sender_call.
643 VideoSendStream::Config thumbnail_send_config(recv_transport);
644 thumbnail_send_config.rtp.ssrcs.push_back(kThumbnailSendSsrcStart + i);
Niels Möller4db138e2018-04-19 09:04:13 +0200645 // TODO(nisse): Could use a simpler VP8-only encoder factory.
646 thumbnail_send_config.encoder_settings.encoder_factory =
647 &video_encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200648 thumbnail_send_config.rtp.payload_name = params_.video[0].codec;
649 thumbnail_send_config.rtp.payload_type = kPayloadTypeVP8;
ilnika014cc52017-03-07 04:21:04 -0800650 thumbnail_send_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
651 thumbnail_send_config.rtp.rtx.payload_type = kSendRtxPayloadType;
652 thumbnail_send_config.rtp.rtx.ssrcs.push_back(kThumbnailRtxSsrcStart + i);
653 thumbnail_send_config.rtp.extensions.clear();
654 if (params_.call.send_side_bwe) {
655 thumbnail_send_config.rtp.extensions.push_back(
656 RtpExtension(RtpExtension::kTransportSequenceNumberUri,
657 test::kTransportSequenceNumberExtensionId));
658 } else {
659 thumbnail_send_config.rtp.extensions.push_back(RtpExtension(
660 RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
661 }
662
663 VideoEncoderConfig thumbnail_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200664 thumbnail_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller4db138e2018-04-19 09:04:13 +0200665 thumbnail_encoder_config.video_format.name = "VP8";
ilnika014cc52017-03-07 04:21:04 -0800666 thumbnail_encoder_config.min_transmit_bitrate_bps = 7500;
667 thumbnail_send_config.suspend_below_min_bitrate =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100668 params_.video[0].suspend_below_min_bitrate;
ilnika014cc52017-03-07 04:21:04 -0800669 thumbnail_encoder_config.number_of_streams = 1;
670 thumbnail_encoder_config.max_bitrate_bps = 50000;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100671 if (params_.ss[0].infer_streams) {
ilnik6b826ef2017-06-16 06:53:48 -0700672 thumbnail_encoder_config.video_stream_factory =
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100673 new rtc::RefCountedObject<VideoStreamFactory>(params_.ss[0].streams);
ilnik6b826ef2017-06-16 06:53:48 -0700674 } else {
Seth Hampson8234ead2018-02-02 15:16:24 -0800675 thumbnail_encoder_config.simulcast_layers = std::vector<VideoStream>(1);
ilnik6b826ef2017-06-16 06:53:48 -0700676 thumbnail_encoder_config.video_stream_factory =
677 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100678 params_.video[0].codec, params_.ss[0].streams[0].max_qp,
679 params_.video[0].fps, params_.screenshare[0].enabled, true);
ilnik6b826ef2017-06-16 06:53:48 -0700680 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100681 thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers;
ilnika014cc52017-03-07 04:21:04 -0800682
683 VideoReceiveStream::Config thumbnail_receive_config(send_transport);
684 thumbnail_receive_config.rtp.remb = false;
685 thumbnail_receive_config.rtp.transport_cc = true;
686 thumbnail_receive_config.rtp.local_ssrc = kReceiverLocalVideoSsrc;
687 for (const RtpExtension& extension : thumbnail_send_config.rtp.extensions)
688 thumbnail_receive_config.rtp.extensions.push_back(extension);
689 thumbnail_receive_config.renderer = &fake_renderer_;
690
691 VideoReceiveStream::Decoder decoder =
Niels Möller259a4972018-04-05 15:36:51 +0200692 test::CreateMatchingDecoder(thumbnail_send_config);
ilnika014cc52017-03-07 04:21:04 -0800693 allocated_decoders_.push_back(
694 std::unique_ptr<VideoDecoder>(decoder.decoder));
695 thumbnail_receive_config.decoders.clear();
696 thumbnail_receive_config.decoders.push_back(decoder);
697 thumbnail_receive_config.rtp.remote_ssrc =
698 thumbnail_send_config.rtp.ssrcs[0];
699
700 thumbnail_receive_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
701 thumbnail_receive_config.rtp.rtx_ssrc = kThumbnailRtxSsrcStart + i;
nisse26e3abb2017-08-25 04:44:25 -0700702 thumbnail_receive_config.rtp
703 .rtx_associated_payload_types[kSendRtxPayloadType] = kPayloadTypeVP8;
ilnika014cc52017-03-07 04:21:04 -0800704 thumbnail_receive_config.rtp.transport_cc = params_.call.send_side_bwe;
705 thumbnail_receive_config.rtp.remb = !params_.call.send_side_bwe;
706
707 thumbnail_encoder_configs_.push_back(thumbnail_encoder_config.Copy());
708 thumbnail_send_configs_.push_back(thumbnail_send_config.Copy());
709 thumbnail_receive_configs_.push_back(thumbnail_receive_config.Copy());
710 }
711
ilnik98436952017-07-13 00:47:03 -0700712 for (int i = 0; i < params_.call.num_thumbnails; ++i) {
ilnika014cc52017-03-07 04:21:04 -0800713 thumbnail_send_streams_.push_back(receiver_call_->CreateVideoSendStream(
714 thumbnail_send_configs_[i].Copy(),
715 thumbnail_encoder_configs_[i].Copy()));
716 thumbnail_receive_streams_.push_back(sender_call_->CreateVideoReceiveStream(
717 thumbnail_receive_configs_[i].Copy()));
718 }
719}
720
721void VideoQualityTest::DestroyThumbnailStreams() {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100722 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800723 receiver_call_->DestroyVideoSendStream(thumbnail_send_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100724 }
ilnika014cc52017-03-07 04:21:04 -0800725 thumbnail_send_streams_.clear();
726 for (VideoReceiveStream* thumbnail_receive_stream :
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100727 thumbnail_receive_streams_) {
ilnika014cc52017-03-07 04:21:04 -0800728 sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100729 }
ilnika014cc52017-03-07 04:21:04 -0800730 thumbnail_send_streams_.clear();
731 thumbnail_receive_streams_.clear();
eladalon413ee9a2017-08-22 04:02:52 -0700732 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
733 thumbnail_capturers_) {
734 video_caputurer.reset();
735 }
ilnika014cc52017-03-07 04:21:04 -0800736}
737
ilnika014cc52017-03-07 04:21:04 -0800738void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) {
739 VideoStream thumbnail = DefaultThumbnailStream();
740 for (size_t i = 0; i < num_thumbnail_streams; ++i) {
741 thumbnail_capturers_.emplace_back(test::FrameGeneratorCapturer::Create(
742 static_cast<int>(thumbnail.width), static_cast<int>(thumbnail.height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200743 absl::nullopt, absl::nullopt, thumbnail.max_framerate, clock_));
ilnikf89a7382017-03-07 06:15:27 -0800744 RTC_DCHECK(thumbnail_capturers_.back());
ilnika014cc52017-03-07 04:21:04 -0800745 }
746}
747
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100748std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator(
749 size_t video_idx) {
750 // Setup frame generator.
751 const size_t kWidth = 1850;
752 const size_t kHeight = 1110;
753 std::unique_ptr<test::FrameGenerator> frame_generator;
754 if (params_.screenshare[video_idx].generate_slides) {
755 frame_generator = test::FrameGenerator::CreateSlideGenerator(
756 kWidth, kHeight,
757 params_.screenshare[video_idx].slide_change_interval *
758 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700759 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100760 std::vector<std::string> slides = params_.screenshare[video_idx].slides;
761 if (slides.size() == 0) {
762 slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
763 slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
764 slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
765 slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
766 }
767 if (params_.screenshare[video_idx].scroll_duration == 0) {
768 // Cycle image every slide_change_interval seconds.
769 frame_generator = test::FrameGenerator::CreateFromYuvFile(
770 slides, kWidth, kHeight,
771 params_.screenshare[video_idx].slide_change_interval *
772 params_.video[video_idx].fps);
ivica5d6a06c2015-09-17 05:30:24 -0700773 } else {
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100774 RTC_CHECK_LE(params_.video[video_idx].width, kWidth);
775 RTC_CHECK_LE(params_.video[video_idx].height, kHeight);
776 RTC_CHECK_GT(params_.screenshare[video_idx].slide_change_interval, 0);
777 const int kPauseDurationMs =
778 (params_.screenshare[video_idx].slide_change_interval -
779 params_.screenshare[video_idx].scroll_duration) *
780 1000;
781 RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration,
782 params_.screenshare[video_idx].slide_change_interval);
783
784 frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
785 clock_, slides, kWidth, kHeight, params_.video[video_idx].width,
786 params_.video[video_idx].height,
787 params_.screenshare[video_idx].scroll_duration * 1000,
788 kPauseDurationMs);
ivica5d6a06c2015-09-17 05:30:24 -0700789 }
790 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100791 return frame_generator;
792}
793
794void VideoQualityTest::CreateCapturers() {
795 video_capturers_.resize(num_video_streams_);
796 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
797 if (params_.screenshare[video_idx].enabled) {
798 std::unique_ptr<test::FrameGenerator> frame_generator =
799 CreateFrameGenerator(video_idx);
800 test::FrameGeneratorCapturer* frame_generator_capturer =
801 new test::FrameGeneratorCapturer(clock_, std::move(frame_generator),
802 params_.video[video_idx].fps);
803 EXPECT_TRUE(frame_generator_capturer->Init());
804 video_capturers_[video_idx].reset(frame_generator_capturer);
805 } else {
806 if (params_.video[video_idx].clip_name == "Generator") {
807 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
808 static_cast<int>(params_.video[video_idx].width),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200809 static_cast<int>(params_.video[video_idx].height), absl::nullopt,
810 absl::nullopt, params_.video[video_idx].fps, clock_));
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800811 } else if (params_.video[video_idx].clip_name == "GeneratorI420A") {
812 video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create(
813 static_cast<int>(params_.video[video_idx].width),
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100814 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200815 test::FrameGenerator::OutputType::I420A, absl::nullopt,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100816 params_.video[video_idx].fps, clock_));
817 } else if (params_.video[video_idx].clip_name.empty()) {
818 video_capturers_[video_idx].reset(test::VcmCapturer::Create(
819 params_.video[video_idx].width, params_.video[video_idx].height,
820 params_.video[video_idx].fps,
821 params_.video[video_idx].capture_device_index));
822 if (!video_capturers_[video_idx]) {
823 // Failed to get actual camera, use chroma generator as backup.
824 video_capturers_[video_idx].reset(
825 test::FrameGeneratorCapturer::Create(
826 static_cast<int>(params_.video[video_idx].width),
827 static_cast<int>(params_.video[video_idx].height),
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200828 absl::nullopt, absl::nullopt, params_.video[video_idx].fps,
Emircan Uysaler03e6ec92018-03-09 15:03:26 -0800829 clock_));
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100830 }
831 } else {
832 video_capturers_[video_idx].reset(
833 test::FrameGeneratorCapturer::CreateFromYuvFile(
834 test::ResourcePath(params_.video[video_idx].clip_name, "yuv"),
835 params_.video[video_idx].width, params_.video[video_idx].height,
836 params_.video[video_idx].fps, clock_));
837 ASSERT_TRUE(video_capturers_[video_idx])
838 << "Could not create capturer for "
839 << params_.video[video_idx].clip_name
840 << ".yuv. Is this resource file present?";
841 }
842 }
843 RTC_DCHECK(video_capturers_[video_idx].get());
844 }
ivica5d6a06c2015-09-17 05:30:24 -0700845}
846
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100847std::unique_ptr<test::LayerFilteringTransport>
848VideoQualityTest::CreateSendTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200849 return absl::make_unique<test::LayerFilteringTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100850 &task_queue_, params_.pipe, sender_call_.get(), kPayloadTypeVP8,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100851 kPayloadTypeVP9, params_.video[0].selected_tl, params_.ss[0].selected_sl,
852 payload_type_map_, kVideoSendSsrcs[0],
853 static_cast<uint32_t>(kVideoSendSsrcs[0] + params_.ss[0].streams.size() -
854 1));
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100855}
856
857std::unique_ptr<test::DirectTransport>
858VideoQualityTest::CreateReceiveTransport() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200859 return absl::make_unique<test::DirectTransport>(
Christoffer Rodbrob4bb4eb2017-11-13 13:03:52 +0100860 &task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_);
861}
862
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100863void VideoQualityTest::CreateVideoStreams() {
864 RTC_DCHECK(video_send_streams_.empty());
865 RTC_DCHECK(video_receive_streams_.empty());
866 RTC_DCHECK_EQ(video_send_configs_.size(), num_video_streams_);
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100867
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100868 // We currently only support testing external fec controllers with a single
869 // VideoSendStream.
Ying Wang0dd1b0a2018-02-20 12:50:27 +0100870 if (fec_controller_factory_.get()) {
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100871 RTC_DCHECK_LE(video_send_configs_.size(), 1);
872 }
Ilya Nikolaevskiy4c09d7a2018-03-02 13:37:00 +0100873
874 // TODO(http://crbug/818127):
875 // Remove this workaround when ALR is not screenshare-specific.
876 std::list<size_t> streams_creation_order;
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100877 for (size_t i = 0; i < video_send_configs_.size(); ++i) {
Ilya Nikolaevskiy4c09d7a2018-03-02 13:37:00 +0100878 // If dual streams are created, add the screenshare stream last.
879 if (video_encoder_configs_[i].content_type ==
880 VideoEncoderConfig::ContentType::kScreen) {
881 streams_creation_order.push_back(i);
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100882 } else {
Ilya Nikolaevskiy4c09d7a2018-03-02 13:37:00 +0100883 streams_creation_order.push_front(i);
884 }
885 }
886
887 video_send_streams_.resize(video_send_configs_.size(), nullptr);
888
889 for (size_t i : streams_creation_order) {
890 if (fec_controller_factory_.get()) {
891 video_send_streams_[i] = sender_call_->CreateVideoSendStream(
892 video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy(),
893 fec_controller_factory_->CreateFecController());
894 } else {
895 video_send_streams_[i] = sender_call_->CreateVideoSendStream(
896 video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy());
Stefan Holmerc6b224a2018-02-06 13:52:44 +0100897 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100898 }
899 for (size_t i = 0; i < video_receive_configs_.size(); ++i) {
900 video_receive_streams_.push_back(receiver_call_->CreateVideoReceiveStream(
901 video_receive_configs_[i].Copy()));
902 }
903
904 AssociateFlexfecStreamsWithVideoStreams();
905}
906
907void VideoQualityTest::DestroyStreams() {
908 CallTest::DestroyStreams();
909
910 for (VideoSendStream* video_send_stream : video_send_streams_)
911 sender_call_->DestroyVideoSendStream(video_send_stream);
912}
913
sprang7a975f72015-10-12 06:33:21 -0700914void VideoQualityTest::RunWithAnalyzer(const Params& params) {
Ilya Nikolaevskiyad556762018-01-17 11:48:59 +0100915 rtc::LogMessage::SetLogToStderr(params.logging.logs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100916 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -0700917 std::unique_ptr<test::LayerFilteringTransport> send_transport;
918 std::unique_ptr<test::DirectTransport> recv_transport;
919 FILE* graph_data_output_file = nullptr;
920 std::unique_ptr<VideoAnalyzer> analyzer;
921
sprangce4aef12015-11-02 07:23:20 -0800922 params_ = params;
923
minyue626bc952016-10-31 05:47:02 -0700924 RTC_CHECK(!params_.audio.enabled);
ivica5d6a06c2015-09-17 05:30:24 -0700925 // TODO(ivica): Merge with RunWithRenderer and use a flag / argument to
926 // differentiate between the analyzer and the renderer case.
sprangce4aef12015-11-02 07:23:20 -0800927 CheckParams();
ivica5d6a06c2015-09-17 05:30:24 -0700928
sprangce4aef12015-11-02 07:23:20 -0800929 if (!params_.analyzer.graph_data_output_filename.empty()) {
ivica5d6a06c2015-09-17 05:30:24 -0700930 graph_data_output_file =
sprangce4aef12015-11-02 07:23:20 -0800931 fopen(params_.analyzer.graph_data_output_filename.c_str(), "w");
Peter Boström74f6e9e2016-04-04 17:56:10 +0200932 RTC_CHECK(graph_data_output_file)
sprangce4aef12015-11-02 07:23:20 -0800933 << "Can't open the file " << params_.analyzer.graph_data_output_filename
934 << "!";
ivica87f83a92015-10-08 05:13:32 -0700935 }
sprang7a975f72015-10-12 06:33:21 -0700936
ilnik98436952017-07-13 00:47:03 -0700937 if (!params.logging.rtc_event_log_name.empty()) {
Bjorn Terelius0a6a2b72018-01-19 17:52:38 +0100938 send_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
939 recv_event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100940 std::unique_ptr<RtcEventLogOutputFile> send_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200941 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100942 params.logging.rtc_event_log_name + "_send",
943 RtcEventLog::kUnlimitedOutput));
944 std::unique_ptr<RtcEventLogOutputFile> recv_output(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200945 absl::make_unique<RtcEventLogOutputFile>(
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100946 params.logging.rtc_event_log_name + "_recv",
947 RtcEventLog::kUnlimitedOutput));
948 bool event_log_started =
949 send_event_log_->StartLogging(std::move(send_output),
950 RtcEventLog::kImmediateOutput) &&
951 recv_event_log_->StartLogging(std::move(recv_output),
952 RtcEventLog::kImmediateOutput);
ilnik98436952017-07-13 00:47:03 -0700953 RTC_DCHECK(event_log_started);
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100954 } else {
955 send_event_log_ = RtcEventLog::CreateNull();
956 recv_event_log_ = RtcEventLog::CreateNull();
ilnik98436952017-07-13 00:47:03 -0700957 }
958
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100959 Call::Config send_call_config(send_event_log_.get());
960 Call::Config recv_call_config(recv_event_log_.get());
961 send_call_config.bitrate_config = params.call.call_bitrate_config;
962 recv_call_config.bitrate_config = params.call.call_bitrate_config;
stefanf116bd02015-10-27 08:29:42 -0700963
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100964 task_queue_.SendTask([this, &send_call_config, &recv_call_config,
965 &send_transport, &recv_transport]() {
966 CreateCalls(send_call_config, recv_call_config);
967 send_transport = CreateSendTransport();
968 recv_transport = CreateReceiveTransport();
969 });
stefanf116bd02015-10-27 08:29:42 -0700970
sprangce4aef12015-11-02 07:23:20 -0800971 std::string graph_title = params_.analyzer.graph_title;
972 if (graph_title.empty())
973 graph_title = VideoQualityTest::GenerateGraphTitle();
sprangc1b57a12017-02-28 08:50:47 -0800974 bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
Karl Wiberg918f50c2018-07-05 11:40:33 +0200975 analyzer = absl::make_unique<VideoAnalyzer>(
eladalon413ee9a2017-08-22 04:02:52 -0700976 send_transport.get(), params_.analyzer.test_label,
ilnik2a8c2f52017-02-15 02:23:28 -0800977 params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
ilnik9ae0d762017-02-15 00:53:12 -0800978 is_quick_test_enabled
979 ? kFramesSentInQuickTest
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100980 : params_.analyzer.test_durations_secs * params_.video[0].fps,
sprangce4aef12015-11-02 07:23:20 -0800981 graph_data_output_file, graph_title,
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100982 kVideoSendSsrcs[params_.ss[0].selected_stream],
983 kSendRtxSsrcs[params_.ss[0].selected_stream],
984 static_cast<size_t>(params_.ss[0].selected_stream),
985 params.ss[0].selected_sl, params_.video[0].selected_tl,
986 is_quick_test_enabled, clock_, params_.logging.rtp_dump_name);
ivica5d6a06c2015-09-17 05:30:24 -0700987
eladalon413ee9a2017-08-22 04:02:52 -0700988 task_queue_.SendTask([&]() {
989 analyzer->SetCall(sender_call_.get());
990 analyzer->SetReceiver(receiver_call_->Receiver());
991 send_transport->SetReceiver(analyzer.get());
992 recv_transport->SetReceiver(sender_call_->Receiver());
ivica5d6a06c2015-09-17 05:30:24 -0700993
eladalon413ee9a2017-08-22 04:02:52 -0700994 SetupVideo(analyzer.get(), recv_transport.get());
995 SetupThumbnails(analyzer.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100996 video_receive_configs_[params_.ss[0].selected_stream].renderer =
eladalon413ee9a2017-08-22 04:02:52 -0700997 analyzer.get();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +0100998 video_send_configs_[0].pre_encode_callback = analyzer->pre_encode_proxy();
999 RTC_DCHECK(!video_send_configs_[0].post_encode_callback);
Niels Möllerf88a22c2018-06-19 17:05:03 +02001000 video_send_configs_[0].post_encode_callback = analyzer.get();
kthelgason2bc68642017-02-07 07:02:22 -08001001
eladalon413ee9a2017-08-22 04:02:52 -07001002 CreateFlexfecStreams();
1003 CreateVideoStreams();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001004 analyzer->SetSendStream(video_send_streams_[0]);
eladalon413ee9a2017-08-22 04:02:52 -07001005 if (video_receive_streams_.size() == 1)
1006 analyzer->SetReceiveStream(video_receive_streams_[0]);
ivica5d6a06c2015-09-17 05:30:24 -07001007
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001008 video_send_streams_[0]->SetSource(analyzer->OutputInterface(),
1009 degradation_preference_);
eladalon413ee9a2017-08-22 04:02:52 -07001010 SetupThumbnailCapturers(params_.call.num_thumbnails);
1011 for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
1012 thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
1013 degradation_preference_);
1014 }
ilnika014cc52017-03-07 04:21:04 -08001015
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001016 CreateCapturers();
ivicac1cc8542015-10-08 03:44:06 -07001017
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001018 analyzer->SetSource(video_capturers_[0].get(), params_.ss[0].infer_streams);
ilnika014cc52017-03-07 04:21:04 -08001019
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001020 for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) {
1021 video_send_streams_[video_idx]->SetSource(
1022 video_capturers_[video_idx].get(), degradation_preference_);
1023 }
1024
1025 StartEncodedFrameLogs(video_send_streams_[0]);
1026 StartEncodedFrameLogs(
1027 video_receive_streams_[params_.ss[0].selected_stream]);
1028 for (VideoSendStream* video_send_stream : video_send_streams_)
1029 video_send_stream->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001030 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
1031 thumbnail_send_stream->Start();
1032 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1033 receive_stream->Start();
1034 for (VideoReceiveStream* thumbnail_receive_stream :
1035 thumbnail_receive_streams_)
1036 thumbnail_receive_stream->Start();
ilnika014cc52017-03-07 04:21:04 -08001037
eladalon413ee9a2017-08-22 04:02:52 -07001038 analyzer->StartMeasuringCpuProcessTime();
ivica5d6a06c2015-09-17 05:30:24 -07001039
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001040 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1041 video_capturers_[video_idx]->Start();
1042 }
eladalon413ee9a2017-08-22 04:02:52 -07001043 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
1044 thumbnail_capturers_) {
1045 video_caputurer->Start();
1046 }
1047 });
ivica5d6a06c2015-09-17 05:30:24 -07001048
eladalon413ee9a2017-08-22 04:02:52 -07001049 analyzer->Wait();
ivica5d6a06c2015-09-17 05:30:24 -07001050
Ilya Nikolaevskiy2c72fe82017-10-02 13:01:04 +02001051 event_log_->StopLogging();
1052
eladalon413ee9a2017-08-22 04:02:52 -07001053 task_queue_.SendTask([&]() {
1054 for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
1055 thumbnail_capturers_)
1056 video_caputurer->Stop();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001057 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1058 video_capturers_[video_idx]->Stop();
1059 }
eladalon413ee9a2017-08-22 04:02:52 -07001060 for (VideoReceiveStream* thumbnail_receive_stream :
1061 thumbnail_receive_streams_)
1062 thumbnail_receive_stream->Stop();
1063 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1064 receive_stream->Stop();
1065 for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
1066 thumbnail_send_stream->Stop();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001067 for (VideoSendStream* video_send_stream : video_send_streams_)
1068 video_send_stream->Stop();
ivica5d6a06c2015-09-17 05:30:24 -07001069
eladalon413ee9a2017-08-22 04:02:52 -07001070 DestroyStreams();
1071 DestroyThumbnailStreams();
ivica5d6a06c2015-09-17 05:30:24 -07001072
eladalon413ee9a2017-08-22 04:02:52 -07001073 if (graph_data_output_file)
1074 fclose(graph_data_output_file);
1075
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001076 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -07001077 send_transport.reset();
1078 recv_transport.reset();
1079
1080 DestroyCalls();
1081 });
ivica5d6a06c2015-09-17 05:30:24 -07001082}
1083
Fredrik Solenberg8f5787a2018-01-11 13:52:30 +01001084void VideoQualityTest::SetupAudio(Transport* transport,
minyuea27172d2016-11-01 05:59:29 -07001085 AudioReceiveStream** audio_receive_stream) {
1086 audio_send_config_ = AudioSendStream::Config(transport);
minyuea27172d2016-11-01 05:59:29 -07001087 audio_send_config_.rtp.ssrc = kAudioSendSsrc;
1088
1089 // Add extension to enable audio send side BWE, and allow audio bit rate
1090 // adaptation.
1091 audio_send_config_.rtp.extensions.clear();
1092 if (params_.call.send_side_bwe) {
1093 audio_send_config_.rtp.extensions.push_back(
1094 webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri,
1095 test::kTransportSequenceNumberExtensionId));
minyue10cbb462016-11-07 09:29:22 -08001096 audio_send_config_.min_bitrate_bps = kOpusMinBitrateBps;
1097 audio_send_config_.max_bitrate_bps = kOpusBitrateFbBps;
minyuea27172d2016-11-01 05:59:29 -07001098 }
Oskar Sundbom8e07c132018-01-08 16:45:42 +01001099 audio_send_config_.send_codec_spec = AudioSendStream::Config::SendCodecSpec(
1100 kAudioSendPayloadType,
Yves Gerey665174f2018-06-19 15:03:05 +02001101 {"OPUS",
1102 48000,
1103 2,
1104 {{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}});
Niels Möller2784a032018-03-28 14:16:04 +02001105 audio_send_config_.encoder_factory = audio_encoder_factory_;
sprang1168fd42017-06-21 09:00:17 -07001106 audio_send_stream_ = sender_call_->CreateAudioSendStream(audio_send_config_);
minyuea27172d2016-11-01 05:59:29 -07001107
1108 AudioReceiveStream::Config audio_config;
1109 audio_config.rtp.local_ssrc = kReceiverLocalAudioSsrc;
1110 audio_config.rtcp_send_transport = transport;
minyuea27172d2016-11-01 05:59:29 -07001111 audio_config.rtp.remote_ssrc = audio_send_config_.rtp.ssrc;
1112 audio_config.rtp.transport_cc = params_.call.send_side_bwe;
1113 audio_config.rtp.extensions = audio_send_config_.rtp.extensions;
Niels Möller2784a032018-03-28 14:16:04 +02001114 audio_config.decoder_factory = audio_decoder_factory_;
minyue20c84cc2017-04-10 16:57:57 -07001115 audio_config.decoder_map = {{kAudioSendPayloadType, {"OPUS", 48000, 2}}};
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001116 if (params_.video[0].enabled && params_.audio.sync_video)
minyuea27172d2016-11-01 05:59:29 -07001117 audio_config.sync_group = kSyncGroup;
1118
sprang1168fd42017-06-21 09:00:17 -07001119 *audio_receive_stream =
1120 receiver_call_->CreateAudioReceiveStream(audio_config);
minyuea27172d2016-11-01 05:59:29 -07001121}
1122
minyue73208662016-08-18 06:28:55 -07001123void VideoQualityTest::RunWithRenderers(const Params& params) {
Ilya Nikolaevskiyad556762018-01-17 11:48:59 +01001124 rtc::LogMessage::SetLogToStderr(params.logging.logs);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001125 num_video_streams_ = params.call.dual_video ? 2 : 1;
eladalon413ee9a2017-08-22 04:02:52 -07001126 std::unique_ptr<test::LayerFilteringTransport> send_transport;
1127 std::unique_ptr<test::DirectTransport> recv_transport;
minyuea27172d2016-11-01 05:59:29 -07001128 std::unique_ptr<test::VideoRenderer> local_preview;
eladalon413ee9a2017-08-22 04:02:52 -07001129 std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
minyue73208662016-08-18 06:28:55 -07001130 AudioReceiveStream* audio_receive_stream = nullptr;
minyue73208662016-08-18 06:28:55 -07001131
eladalon413ee9a2017-08-22 04:02:52 -07001132 task_queue_.SendTask([&]() {
1133 params_ = params;
1134 CheckParams();
palmkviste75f2042016-09-28 06:19:48 -07001135
eladalon413ee9a2017-08-22 04:02:52 -07001136 // TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
1137 // match the full stack tests.
1138 Call::Config call_config(event_log_.get());
1139 call_config.bitrate_config = params_.call.call_bitrate_config;
Niels Möller2bf9e732017-08-14 11:26:16 +02001140
Artem Titov3faa8322018-03-07 14:44:00 +01001141 rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device =
1142 TestAudioDeviceModule::CreateTestAudioDeviceModule(
1143 TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
1144 TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
ivica5d6a06c2015-09-17 05:30:24 -07001145
eladalon413ee9a2017-08-22 04:02:52 -07001146 if (params_.audio.enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001147 AudioState::Config audio_state_config;
eladalon413ee9a2017-08-22 04:02:52 -07001148 audio_state_config.audio_mixer = AudioMixerImpl::Create();
Ivo Creusen62337e52018-01-09 14:17:33 +01001149 audio_state_config.audio_processing = AudioProcessingBuilder().Create();
Fredrik Solenberg2a877972017-12-15 16:42:15 +01001150 audio_state_config.audio_device_module = fake_audio_device;
eladalon413ee9a2017-08-22 04:02:52 -07001151 call_config.audio_state = AudioState::Create(audio_state_config);
Fredrik Solenbergd3195342017-11-21 20:33:05 +01001152 fake_audio_device->RegisterAudioCallback(
1153 call_config.audio_state->audio_transport());
eladalon413ee9a2017-08-22 04:02:52 -07001154 }
minyue73208662016-08-18 06:28:55 -07001155
eladalon413ee9a2017-08-22 04:02:52 -07001156 CreateCalls(call_config, call_config);
1157
1158 // TODO(minyue): consider if this is a good transport even for audio only
1159 // calls.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001160 send_transport = CreateSendTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001161
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001162 recv_transport = CreateReceiveTransport();
eladalon413ee9a2017-08-22 04:02:52 -07001163
1164 // TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
1165 // least share as much code as possible. That way this test would also match
1166 // the full stack tests better.
1167 send_transport->SetReceiver(receiver_call_->Receiver());
1168 recv_transport->SetReceiver(sender_call_->Receiver());
1169
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001170 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001171 // Create video renderers.
1172 local_preview.reset(test::VideoRenderer::Create(
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001173 "Local Preview", params_.video[0].width, params_.video[0].height));
eladalon413ee9a2017-08-22 04:02:52 -07001174
1175 SetupVideo(send_transport.get(), recv_transport.get());
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001176 video_send_configs_[0].pre_encode_callback = local_preview.get();
eladalon413ee9a2017-08-22 04:02:52 -07001177
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001178 size_t num_streams_processed = 0;
1179 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1180 const size_t selected_stream_id = params_.ss[video_idx].selected_stream;
1181 const size_t num_streams = params_.ss[video_idx].streams.size();
1182 if (selected_stream_id == num_streams) {
1183 for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
1184 std::ostringstream oss;
1185 oss << "Loopback Video #" << video_idx << " - Stream #"
1186 << static_cast<int>(stream_id);
1187 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1188 oss.str().c_str(),
1189 params_.ss[video_idx].streams[stream_id].width,
1190 params_.ss[video_idx].streams[stream_id].height));
1191 video_receive_configs_[stream_id + num_streams_processed].renderer =
1192 loopback_renderers.back().get();
1193 if (params_.audio.enabled && params_.audio.sync_video)
1194 video_receive_configs_[stream_id + num_streams_processed]
1195 .sync_group = kSyncGroup;
1196 }
1197 } else {
1198 std::ostringstream oss;
1199 oss << "Loopback Video #" << video_idx;
1200 loopback_renderers.emplace_back(test::VideoRenderer::Create(
1201 oss.str().c_str(),
1202 params_.ss[video_idx].streams[selected_stream_id].width,
1203 params_.ss[video_idx].streams[selected_stream_id].height));
1204 video_receive_configs_[selected_stream_id + num_streams_processed]
1205 .renderer = loopback_renderers.back().get();
eladalon413ee9a2017-08-22 04:02:52 -07001206 if (params_.audio.enabled && params_.audio.sync_video)
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001207 video_receive_configs_[num_streams_processed + selected_stream_id]
1208 .sync_group = kSyncGroup;
eladalon413ee9a2017-08-22 04:02:52 -07001209 }
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001210 num_streams_processed += num_streams;
eladalon413ee9a2017-08-22 04:02:52 -07001211 }
eladalon413ee9a2017-08-22 04:02:52 -07001212 CreateFlexfecStreams();
1213 CreateVideoStreams();
1214
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001215 CreateCapturers();
1216 for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
1217 video_send_streams_[video_idx]->SetSource(
1218 video_capturers_[video_idx].get(), degradation_preference_);
1219 }
eladalon413ee9a2017-08-22 04:02:52 -07001220 }
1221
1222 if (params_.audio.enabled) {
Fredrik Solenberg8f5787a2018-01-11 13:52:30 +01001223 SetupAudio(send_transport.get(), &audio_receive_stream);
eladalon413ee9a2017-08-22 04:02:52 -07001224 }
1225
1226 for (VideoReceiveStream* receive_stream : video_receive_streams_)
1227 StartEncodedFrameLogs(receive_stream);
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001228 StartEncodedFrameLogs(video_send_streams_[0]);
eladalon413ee9a2017-08-22 04:02:52 -07001229
1230 // Start sending and receiving video.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001231 if (params_.video[0].enabled) {
eladalon413ee9a2017-08-22 04:02:52 -07001232 for (VideoReceiveStream* video_receive_stream : video_receive_streams_)
1233 video_receive_stream->Start();
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001234 for (VideoSendStream* video_send_stream : video_send_streams_)
1235 video_send_stream->Start();
1236 for (auto& video_capturer : video_capturers_)
1237 video_capturer->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001238 }
1239
1240 if (params_.audio.enabled) {
1241 // Start receiving audio.
1242 audio_receive_stream->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001243
1244 // Start sending audio.
1245 audio_send_stream_->Start();
eladalon413ee9a2017-08-22 04:02:52 -07001246 }
1247 });
minyue73208662016-08-18 06:28:55 -07001248
ivica5d6a06c2015-09-17 05:30:24 -07001249 test::PressEnterToContinue();
1250
eladalon413ee9a2017-08-22 04:02:52 -07001251 task_queue_.SendTask([&]() {
1252 if (params_.audio.enabled) {
1253 // Stop sending audio.
eladalon413ee9a2017-08-22 04:02:52 -07001254 audio_send_stream_->Stop();
minyue73208662016-08-18 06:28:55 -07001255
eladalon413ee9a2017-08-22 04:02:52 -07001256 // Stop receiving audio.
eladalon413ee9a2017-08-22 04:02:52 -07001257 audio_receive_stream->Stop();
eladalon413ee9a2017-08-22 04:02:52 -07001258 }
minyue73208662016-08-18 06:28:55 -07001259
eladalon413ee9a2017-08-22 04:02:52 -07001260 // Stop receiving and sending video.
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001261 if (params_.video[0].enabled) {
1262 for (auto& video_capturer : video_capturers_)
1263 video_capturer->Stop();
1264 for (VideoSendStream* video_send_stream : video_send_streams_)
1265 video_send_stream->Stop();
1266 DestroyStreams();
brandtr1293aca2016-11-16 22:47:29 -08001267 }
minyue73208662016-08-18 06:28:55 -07001268
Ilya Nikolaevskiy255d1cd2017-12-21 18:02:59 +01001269 video_capturers_.clear();
eladalon413ee9a2017-08-22 04:02:52 -07001270 send_transport.reset();
1271 recv_transport.reset();
sprang1168fd42017-06-21 09:00:17 -07001272
eladalon413ee9a2017-08-22 04:02:52 -07001273 local_preview.reset();
1274 loopback_renderers.clear();
1275
1276 DestroyCalls();
1277 });
ivica5d6a06c2015-09-17 05:30:24 -07001278}
1279
palmkviste75f2042016-09-28 06:19:48 -07001280void VideoQualityTest::StartEncodedFrameLogs(VideoSendStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001281 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001282 std::ostringstream str;
1283 str << send_logs_++;
1284 std::string prefix =
ilnik98436952017-07-13 00:47:03 -07001285 params_.logging.encoded_frame_base_path + "." + str.str() + ".send.";
palmkviste75f2042016-09-28 06:19:48 -07001286 stream->EnableEncodedFrameRecording(
1287 std::vector<rtc::PlatformFile>(
1288 {rtc::CreatePlatformFile(prefix + "1.ivf"),
1289 rtc::CreatePlatformFile(prefix + "2.ivf"),
1290 rtc::CreatePlatformFile(prefix + "3.ivf")}),
ilnik98436952017-07-13 00:47:03 -07001291 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001292 }
1293}
ilnikcb8c1462017-03-09 09:23:30 -08001294
palmkviste75f2042016-09-28 06:19:48 -07001295void VideoQualityTest::StartEncodedFrameLogs(VideoReceiveStream* stream) {
ilnik98436952017-07-13 00:47:03 -07001296 if (!params_.logging.encoded_frame_base_path.empty()) {
palmkviste75f2042016-09-28 06:19:48 -07001297 std::ostringstream str;
1298 str << receive_logs_++;
1299 std::string path =
ilnik98436952017-07-13 00:47:03 -07001300 params_.logging.encoded_frame_base_path + "." + str.str() + ".recv.ivf";
palmkviste75f2042016-09-28 06:19:48 -07001301 stream->EnableEncodedFrameRecording(rtc::CreatePlatformFile(path),
ilnik98436952017-07-13 00:47:03 -07001302 100000000);
palmkviste75f2042016-09-28 06:19:48 -07001303 }
1304}
ivica5d6a06c2015-09-17 05:30:24 -07001305} // namespace webrtc