1 /*
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 */
10 #include "video/video_loopback.h"
11
12 #include <stdio.h>
13
14 #include <memory>
15 #include <string>
16 #include <vector>
17
18 #include "absl/flags/flag.h"
19 #include "absl/flags/parse.h"
20 #include "absl/types/optional.h"
21 #include "api/test/simulated_network.h"
22 #include "api/test/video_quality_test_fixture.h"
23 #include "api/transport/bitrate_settings.h"
24 #include "api/video_codecs/video_codec.h"
25 #include "rtc_base/checks.h"
26 #include "rtc_base/logging.h"
27 #include "system_wrappers/include/field_trial.h"
28 #include "test/field_trial.h"
29 #include "test/gtest.h"
30 #include "test/run_test.h"
31 #include "video/video_quality_test.h"
32
33 // Flags common with screenshare loopback, with different default values.
34 ABSL_FLAG(int, width, 640, "Video width.");
35
36 ABSL_FLAG(int, height, 480, "Video height.");
37
38 ABSL_FLAG(int, fps, 30, "Frames per second.");
39
40 ABSL_FLAG(int, capture_device_index, 0, "Capture device to select");
41
42 ABSL_FLAG(int, min_bitrate, 50, "Call and stream min bitrate in kbps.");
43
44 ABSL_FLAG(int, start_bitrate, 300, "Call start bitrate in kbps.");
45
46 ABSL_FLAG(int, target_bitrate, 800, "Stream target bitrate in kbps.");
47
48 ABSL_FLAG(int, max_bitrate, 800, "Call and stream max bitrate in kbps.");
49
50 ABSL_FLAG(bool,
51 suspend_below_min_bitrate,
52 false,
53 "Suspends video below the configured min bitrate.");
54
55 ABSL_FLAG(int,
56 num_temporal_layers,
57 1,
58 "Number of temporal layers. Set to 1-4 to override.");
59
60 ABSL_FLAG(int,
61 inter_layer_pred,
62 2,
63 "Inter-layer prediction mode. "
64 "0 - enabled, 1 - disabled, 2 - enabled only for key pictures.");
65
66 // Flags common with screenshare loopback, with equal default values.
67 ABSL_FLAG(std::string, codec, "VP8", "Video codec to use.");
68
69 ABSL_FLAG(int,
70 selected_tl,
71 -1,
72 "Temporal layer to show or analyze. -1 to disable filtering.");
73
74 ABSL_FLAG(
75 int,
76 duration,
77 0,
78 "Duration of the test in seconds. If 0, rendered will be shown instead.");
79
80 ABSL_FLAG(std::string, output_filename, "", "Target graph data filename.");
81
82 ABSL_FLAG(std::string,
83 graph_title,
84 "",
85 "If empty, title will be generated automatically.");
86
87 ABSL_FLAG(int, loss_percent, 0, "Percentage of packets randomly lost.");
88
89 ABSL_FLAG(int,
90 avg_burst_loss_length,
91 -1,
92 "Average burst length of lost packets.");
93
94 ABSL_FLAG(int,
95 link_capacity,
96 0,
97 "Capacity (kbps) of the fake link. 0 means infinite.");
98
99 ABSL_FLAG(int, queue_size, 0, "Size of the bottleneck link queue in packets.");
100
101 ABSL_FLAG(int,
102 avg_propagation_delay_ms,
103 0,
104 "Average link propagation delay in ms.");
105
106 ABSL_FLAG(std::string,
107 rtc_event_log_name,
108 "",
109 "Filename for rtc event log. Two files "
110 "with \"_send\" and \"_recv\" suffixes will be created.");
111
112 ABSL_FLAG(std::string,
113 rtp_dump_name,
114 "",
115 "Filename for dumped received RTP stream.");
116
117 ABSL_FLAG(int,
118 std_propagation_delay_ms,
119 0,
120 "Link propagation delay standard deviation in ms.");
121
122 ABSL_FLAG(int, num_streams, 0, "Number of streams to show or analyze.");
123
124 ABSL_FLAG(int,
125 selected_stream,
126 0,
127 "ID of the stream to show or analyze. "
128 "Set to the number of streams to show them all.");
129
130 ABSL_FLAG(int, num_spatial_layers, 1, "Number of spatial layers to use.");
131
132 ABSL_FLAG(int,
133 selected_sl,
134 -1,
135 "Spatial layer to show or analyze. -1 to disable filtering.");
136
137 ABSL_FLAG(std::string,
138 stream0,
139 "",
140 "Comma separated values describing VideoStream for stream #0.");
141
142 ABSL_FLAG(std::string,
143 stream1,
144 "",
145 "Comma separated values describing VideoStream for stream #1.");
146
147 ABSL_FLAG(std::string,
148 sl0,
149 "",
150 "Comma separated values describing SpatialLayer for layer #0.");
151
152 ABSL_FLAG(std::string,
153 sl1,
154 "",
155 "Comma separated values describing SpatialLayer for layer #1.");
156
157 ABSL_FLAG(std::string,
158 sl2,
159 "",
160 "Comma separated values describing SpatialLayer for layer #2.");
161
162 ABSL_FLAG(std::string,
163 encoded_frame_path,
164 "",
165 "The base path for encoded frame logs. Created files will have "
166 "the form <encoded_frame_path>.<n>.(recv|send.<m>).ivf");
167
168 ABSL_FLAG(bool, logs, false, "print logs to stderr");
169
170 ABSL_FLAG(bool, send_side_bwe, true, "Use send-side bandwidth estimation");
171
172 ABSL_FLAG(bool, generic_descriptor, false, "Use the generic frame descriptor.");
173
174 ABSL_FLAG(bool, allow_reordering, false, "Allow packet reordering to occur");
175
176 ABSL_FLAG(bool, use_ulpfec, false, "Use RED+ULPFEC forward error correction.");
177
178 ABSL_FLAG(bool, use_flexfec, false, "Use FlexFEC forward error correction.");
179
180 ABSL_FLAG(bool, audio, false, "Add audio stream");
181
182 ABSL_FLAG(bool,
183 use_real_adm,
184 false,
185 "Use real ADM instead of fake (no effect if audio is false)");
186
187 ABSL_FLAG(bool,
188 audio_video_sync,
189 false,
190 "Sync audio and video stream (no effect if"
191 " audio is false)");
192
193 ABSL_FLAG(bool,
194 audio_dtx,
195 false,
196 "Enable audio DTX (no effect if audio is false)");
197
198 ABSL_FLAG(bool, video, true, "Add video stream");
199
200 ABSL_FLAG(
201 std::string,
202 force_fieldtrials,
203 "",
204 "Field trials control experimental feature code which can be forced. "
205 "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enabled/"
206 " will assign the group Enable to field trial WebRTC-FooFeature. Multiple "
207 "trials are separated by \"/\"");
208
209 // Video-specific flags.
210 ABSL_FLAG(std::string,
211 clip,
212 "",
213 "Name of the clip to show. If empty, using chroma generator.");
214
215 namespace webrtc {
216 namespace {
217
Width()218 size_t Width() {
219 return static_cast<size_t>(absl::GetFlag(FLAGS_width));
220 }
221
Height()222 size_t Height() {
223 return static_cast<size_t>(absl::GetFlag(FLAGS_height));
224 }
225
Fps()226 int Fps() {
227 return absl::GetFlag(FLAGS_fps);
228 }
229
GetCaptureDevice()230 size_t GetCaptureDevice() {
231 return static_cast<size_t>(absl::GetFlag(FLAGS_capture_device_index));
232 }
233
MinBitrateKbps()234 int MinBitrateKbps() {
235 return absl::GetFlag(FLAGS_min_bitrate);
236 }
237
StartBitrateKbps()238 int StartBitrateKbps() {
239 return absl::GetFlag(FLAGS_start_bitrate);
240 }
241
TargetBitrateKbps()242 int TargetBitrateKbps() {
243 return absl::GetFlag(FLAGS_target_bitrate);
244 }
245
MaxBitrateKbps()246 int MaxBitrateKbps() {
247 return absl::GetFlag(FLAGS_max_bitrate);
248 }
249
NumTemporalLayers()250 int NumTemporalLayers() {
251 return absl::GetFlag(FLAGS_num_temporal_layers);
252 }
253
InterLayerPred()254 InterLayerPredMode InterLayerPred() {
255 if (absl::GetFlag(FLAGS_inter_layer_pred) == 0) {
256 return InterLayerPredMode::kOn;
257 } else if (absl::GetFlag(FLAGS_inter_layer_pred) == 1) {
258 return InterLayerPredMode::kOff;
259 } else {
260 RTC_DCHECK_EQ(absl::GetFlag(FLAGS_inter_layer_pred), 2);
261 return InterLayerPredMode::kOnKeyPic;
262 }
263 }
264
Codec()265 std::string Codec() {
266 return absl::GetFlag(FLAGS_codec);
267 }
268
SelectedTL()269 int SelectedTL() {
270 return absl::GetFlag(FLAGS_selected_tl);
271 }
272
DurationSecs()273 int DurationSecs() {
274 return absl::GetFlag(FLAGS_duration);
275 }
276
OutputFilename()277 std::string OutputFilename() {
278 return absl::GetFlag(FLAGS_output_filename);
279 }
280
GraphTitle()281 std::string GraphTitle() {
282 return absl::GetFlag(FLAGS_graph_title);
283 }
284
LossPercent()285 int LossPercent() {
286 return static_cast<int>(absl::GetFlag(FLAGS_loss_percent));
287 }
288
AvgBurstLossLength()289 int AvgBurstLossLength() {
290 return static_cast<int>(absl::GetFlag(FLAGS_avg_burst_loss_length));
291 }
292
LinkCapacityKbps()293 int LinkCapacityKbps() {
294 return static_cast<int>(absl::GetFlag(FLAGS_link_capacity));
295 }
296
QueueSize()297 int QueueSize() {
298 return static_cast<int>(absl::GetFlag(FLAGS_queue_size));
299 }
300
AvgPropagationDelayMs()301 int AvgPropagationDelayMs() {
302 return static_cast<int>(absl::GetFlag(FLAGS_avg_propagation_delay_ms));
303 }
304
RtcEventLogName()305 std::string RtcEventLogName() {
306 return absl::GetFlag(FLAGS_rtc_event_log_name);
307 }
308
RtpDumpName()309 std::string RtpDumpName() {
310 return absl::GetFlag(FLAGS_rtp_dump_name);
311 }
312
StdPropagationDelayMs()313 int StdPropagationDelayMs() {
314 return absl::GetFlag(FLAGS_std_propagation_delay_ms);
315 }
316
NumStreams()317 int NumStreams() {
318 return absl::GetFlag(FLAGS_num_streams);
319 }
320
SelectedStream()321 int SelectedStream() {
322 return absl::GetFlag(FLAGS_selected_stream);
323 }
324
NumSpatialLayers()325 int NumSpatialLayers() {
326 return absl::GetFlag(FLAGS_num_spatial_layers);
327 }
328
SelectedSL()329 int SelectedSL() {
330 return absl::GetFlag(FLAGS_selected_sl);
331 }
332
Stream0()333 std::string Stream0() {
334 return absl::GetFlag(FLAGS_stream0);
335 }
336
Stream1()337 std::string Stream1() {
338 return absl::GetFlag(FLAGS_stream1);
339 }
340
SL0()341 std::string SL0() {
342 return absl::GetFlag(FLAGS_sl0);
343 }
344
SL1()345 std::string SL1() {
346 return absl::GetFlag(FLAGS_sl1);
347 }
348
SL2()349 std::string SL2() {
350 return absl::GetFlag(FLAGS_sl2);
351 }
352
EncodedFramePath()353 std::string EncodedFramePath() {
354 return absl::GetFlag(FLAGS_encoded_frame_path);
355 }
356
Clip()357 std::string Clip() {
358 return absl::GetFlag(FLAGS_clip);
359 }
360
361 } // namespace
362
Loopback()363 void Loopback() {
364 BuiltInNetworkBehaviorConfig pipe_config;
365 pipe_config.loss_percent = LossPercent();
366 pipe_config.avg_burst_loss_length = AvgBurstLossLength();
367 pipe_config.link_capacity_kbps = LinkCapacityKbps();
368 pipe_config.queue_length_packets = QueueSize();
369 pipe_config.queue_delay_ms = AvgPropagationDelayMs();
370 pipe_config.delay_standard_deviation_ms = StdPropagationDelayMs();
371 pipe_config.allow_reordering = absl::GetFlag(FLAGS_allow_reordering);
372
373 BitrateConstraints call_bitrate_config;
374 call_bitrate_config.min_bitrate_bps = MinBitrateKbps() * 1000;
375 call_bitrate_config.start_bitrate_bps = StartBitrateKbps() * 1000;
376 call_bitrate_config.max_bitrate_bps = -1; // Don't cap bandwidth estimate.
377
378 VideoQualityTest::Params params;
379 params.call.send_side_bwe = absl::GetFlag(FLAGS_send_side_bwe);
380 params.call.generic_descriptor = absl::GetFlag(FLAGS_generic_descriptor);
381 params.call.call_bitrate_config = call_bitrate_config;
382
383 params.video[0].enabled = absl::GetFlag(FLAGS_video);
384 params.video[0].width = Width();
385 params.video[0].height = Height();
386 params.video[0].fps = Fps();
387 params.video[0].min_bitrate_bps = MinBitrateKbps() * 1000;
388 params.video[0].target_bitrate_bps = TargetBitrateKbps() * 1000;
389 params.video[0].max_bitrate_bps = MaxBitrateKbps() * 1000;
390 params.video[0].suspend_below_min_bitrate =
391 absl::GetFlag(FLAGS_suspend_below_min_bitrate);
392 params.video[0].codec = Codec();
393 params.video[0].num_temporal_layers = NumTemporalLayers();
394 params.video[0].selected_tl = SelectedTL();
395 params.video[0].min_transmit_bps = 0;
396 params.video[0].ulpfec = absl::GetFlag(FLAGS_use_ulpfec);
397 params.video[0].flexfec = absl::GetFlag(FLAGS_use_flexfec);
398 params.video[0].automatic_scaling = NumStreams() < 2;
399 params.video[0].clip_path = Clip();
400 params.video[0].capture_device_index = GetCaptureDevice();
401 params.audio.enabled = absl::GetFlag(FLAGS_audio);
402 params.audio.sync_video = absl::GetFlag(FLAGS_audio_video_sync);
403 params.audio.dtx = absl::GetFlag(FLAGS_audio_dtx);
404 params.audio.use_real_adm = absl::GetFlag(FLAGS_use_real_adm);
405 params.logging.rtc_event_log_name = RtcEventLogName();
406 params.logging.rtp_dump_name = RtpDumpName();
407 params.logging.encoded_frame_base_path = EncodedFramePath();
408 params.screenshare[0].enabled = false;
409 params.analyzer.test_label = "video";
410 params.analyzer.test_durations_secs = DurationSecs();
411 params.analyzer.graph_data_output_filename = OutputFilename();
412 params.analyzer.graph_title = GraphTitle();
413 params.config = pipe_config;
414
415 if (NumStreams() > 1 && Stream0().empty() && Stream1().empty()) {
416 params.ss[0].infer_streams = true;
417 }
418
419 std::vector<std::string> stream_descriptors;
420 stream_descriptors.push_back(Stream0());
421 stream_descriptors.push_back(Stream1());
422 std::vector<std::string> SL_descriptors;
423 SL_descriptors.push_back(SL0());
424 SL_descriptors.push_back(SL1());
425 SL_descriptors.push_back(SL2());
426 VideoQualityTest::FillScalabilitySettings(
427 ¶ms, 0, stream_descriptors, NumStreams(), SelectedStream(),
428 NumSpatialLayers(), SelectedSL(), InterLayerPred(), SL_descriptors);
429
430 auto fixture = std::make_unique<VideoQualityTest>(nullptr);
431 if (DurationSecs()) {
432 fixture->RunWithAnalyzer(params);
433 } else {
434 fixture->RunWithRenderers(params);
435 }
436 }
437
RunLoopbackTest(int argc,char * argv[])438 int RunLoopbackTest(int argc, char* argv[]) {
439 ::testing::InitGoogleTest(&argc, argv);
440 absl::ParseCommandLine(argc, argv);
441
442 rtc::LogMessage::SetLogToStderr(absl::GetFlag(FLAGS_logs));
443
444 // InitFieldTrialsFromString stores the char*, so the char array must outlive
445 // the application.
446 const std::string field_trials = absl::GetFlag(FLAGS_force_fieldtrials);
447 webrtc::field_trial::InitFieldTrialsFromString(field_trials.c_str());
448
449 webrtc::test::RunTest(webrtc::Loopback);
450 return 0;
451 }
452 } // namespace webrtc
453