blob: 74dc9a2f51bda87d058f71120c02147621263cd0 [file] [log] [blame]
Sebastian Jansson5fbebd52019-02-20 11:16:19 +01001/*
2 * Copyright 2019 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 <atomic>
11
12#include "test/gtest.h"
13#include "test/scenario/scenario.h"
14
15namespace webrtc {
16namespace test {
17namespace {
Sebastian Janssond37307c2019-02-22 17:07:49 +010018using Capture = VideoStreamConfig::Source::Capture;
19using ContentType = VideoStreamConfig::Encoder::ContentType;
Sebastian Jansson5fbebd52019-02-20 11:16:19 +010020using Codec = VideoStreamConfig::Encoder::Codec;
21using CodecImpl = VideoStreamConfig::Encoder::Implementation;
22} // namespace
23
Sebastian Jansson342f98b2019-06-18 16:08:23 +020024TEST(VideoStreamTest, ReceivesFramesFromFileBasedStreams) {
Sebastian Janssond37307c2019-02-22 17:07:49 +010025 TimeDelta kRunTime = TimeDelta::ms(500);
26 std::vector<int> kFrameRates = {15, 30};
27 std::deque<std::atomic<int>> frame_counts(2);
28 frame_counts[0] = 0;
29 frame_counts[1] = 0;
30 {
31 Scenario s;
Sebastian Janssonef86d142019-04-15 14:42:42 +020032 auto route =
33 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
34 {s.CreateSimulationNode(NetworkSimulationConfig())},
35 s.CreateClient("callee", CallClientConfig()),
36 {s.CreateSimulationNode(NetworkSimulationConfig())});
Sebastian Janssond37307c2019-02-22 17:07:49 +010037
38 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020039 c->hooks.frame_pair_handlers = {
40 [&](const VideoFramePair&) { frame_counts[0]++; }};
Sebastian Janssond37307c2019-02-22 17:07:49 +010041 c->source.capture = Capture::kVideoFile;
42 c->source.video_file.name = "foreman_cif";
43 c->source.video_file.width = 352;
44 c->source.video_file.height = 288;
45 c->source.framerate = kFrameRates[0];
46 c->encoder.implementation = CodecImpl::kSoftware;
47 c->encoder.codec = Codec::kVideoCodecVP8;
48 });
49 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020050 c->hooks.frame_pair_handlers = {
51 [&](const VideoFramePair&) { frame_counts[1]++; }};
Sebastian Janssond37307c2019-02-22 17:07:49 +010052 c->source.capture = Capture::kImageSlides;
53 c->source.slides.images.crop.width = 320;
54 c->source.slides.images.crop.height = 240;
55 c->source.framerate = kFrameRates[1];
56 c->encoder.implementation = CodecImpl::kSoftware;
57 c->encoder.codec = Codec::kVideoCodecVP9;
58 });
59 s.RunFor(kRunTime);
60 }
61 std::vector<int> expected_counts;
62 for (int fps : kFrameRates)
63 expected_counts.push_back(
64 static_cast<int>(kRunTime.seconds<double>() * fps * 0.8));
65
66 EXPECT_GE(frame_counts[0], expected_counts[0]);
67 EXPECT_GE(frame_counts[1], expected_counts[1]);
68}
69
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020070TEST(VideoStreamTest, RecievesVp8SimulcastFrames) {
Sebastian Jansson5fbebd52019-02-20 11:16:19 +010071 TimeDelta kRunTime = TimeDelta::ms(500);
72 int kFrameRate = 30;
73
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020074 std::deque<std::atomic<int>> frame_counts(3);
75 frame_counts[0] = 0;
76 frame_counts[1] = 0;
77 frame_counts[2] = 0;
Sebastian Jansson5fbebd52019-02-20 11:16:19 +010078 {
79 Scenario s;
Sebastian Janssonef86d142019-04-15 14:42:42 +020080 auto route =
81 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
82 {s.CreateSimulationNode(NetworkSimulationConfig())},
83 s.CreateClient("callee", CallClientConfig()),
84 {s.CreateSimulationNode(NetworkSimulationConfig())});
Sebastian Jansson5fbebd52019-02-20 11:16:19 +010085 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
86 // TODO(srte): Replace with code checking for all simulcast streams when
87 // there's a hook available for that.
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020088 c->hooks.frame_pair_handlers = {[&](const VideoFramePair& info) {
89 frame_counts[info.layer_id]++;
90 RTC_DCHECK(info.decoded);
91 printf("%i: [%3i->%3i, %i], %i->%i, \n", info.layer_id, info.capture_id,
92 info.decode_id, info.repeated, info.captured->width(),
93 info.decoded->width());
94 }};
Sebastian Jansson5fbebd52019-02-20 11:16:19 +010095 c->source.framerate = kFrameRate;
96 // The resolution must be high enough to allow smaller layers to be
97 // created.
98 c->source.generator.width = 1024;
99 c->source.generator.height = 768;
Sebastian Jansson5fbebd52019-02-20 11:16:19 +0100100 c->encoder.implementation = CodecImpl::kSoftware;
101 c->encoder.codec = Codec::kVideoCodecVP8;
102 // By enabling multiple spatial layers, simulcast will be enabled for VP8.
103 c->encoder.layers.spatial = 3;
104 });
105 s.RunFor(kRunTime);
106 }
107
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200108 // Using high error margin to avoid flakyness.
Sebastian Jansson5fbebd52019-02-20 11:16:19 +0100109 const int kExpectedCount =
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200110 static_cast<int>(kRunTime.seconds<double>() * kFrameRate * 0.5);
Sebastian Jansson5fbebd52019-02-20 11:16:19 +0100111
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200112 EXPECT_GE(frame_counts[0], kExpectedCount);
113 EXPECT_GE(frame_counts[1], kExpectedCount);
114 EXPECT_GE(frame_counts[2], kExpectedCount);
Sebastian Jansson5fbebd52019-02-20 11:16:19 +0100115}
Sebastian Jansson342f98b2019-06-18 16:08:23 +0200116
Sebastian Janssonc57b0ee2019-06-26 16:22:39 +0200117TEST(VideoStreamTest, SendsNacksOnLoss) {
118 Scenario s;
119 auto route =
120 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
121 {s.CreateSimulationNode([](NetworkSimulationConfig* c) {
122 c->loss_rate = 0.2;
123 })},
124 s.CreateClient("callee", CallClientConfig()),
125 {s.CreateSimulationNode(NetworkSimulationConfig())});
126 // NACK retransmissions are enabled by default.
127 auto video = s.CreateVideoStream(route->forward(), VideoStreamConfig());
128 s.RunFor(TimeDelta::seconds(1));
129 auto stream_stats = video->send()->GetStats().substreams.begin()->second;
130 EXPECT_GT(stream_stats.rtp_stats.retransmitted.packets, 0u);
131}
132
Sebastian Jansson342f98b2019-06-18 16:08:23 +0200133TEST(VideoStreamTest, SendsFecWithUlpFec) {
134 Scenario s;
135 auto route =
136 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
137 {s.CreateSimulationNode([](NetworkSimulationConfig* c) {
138 c->loss_rate = 0.1;
139 })},
140 s.CreateClient("callee", CallClientConfig()),
141 {s.CreateSimulationNode(NetworkSimulationConfig())});
142 auto video = s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
Sebastian Janssonc57b0ee2019-06-26 16:22:39 +0200143 // We do not allow NACK+ULPFEC for generic codec, using VP8.
144 c->encoder.codec = VideoStreamConfig::Encoder::Codec::kVideoCodecVP8;
Sebastian Jansson342f98b2019-06-18 16:08:23 +0200145 c->stream.use_ulpfec = true;
146 });
147 s.RunFor(TimeDelta::seconds(5));
148 VideoSendStream::Stats video_stats = video->send()->GetStats();
149 EXPECT_GT(video_stats.substreams.begin()->second.rtp_stats.fec.packets, 0u);
150}
151TEST(VideoStreamTest, SendsFecWithFlexFec) {
152 Scenario s;
153 auto route =
154 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
155 {s.CreateSimulationNode([](NetworkSimulationConfig* c) {
156 c->loss_rate = 0.1;
157 })},
158 s.CreateClient("callee", CallClientConfig()),
159 {s.CreateSimulationNode(NetworkSimulationConfig())});
160 auto video = s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
161 c->stream.use_flexfec = true;
162 });
163 s.RunFor(TimeDelta::seconds(5));
164 VideoSendStream::Stats video_stats = video->send()->GetStats();
165 EXPECT_GT(video_stats.substreams.begin()->second.rtp_stats.fec.packets, 0u);
166}
Sebastian Jansson5fbebd52019-02-20 11:16:19 +0100167} // namespace test
168} // namespace webrtc