1 /*
2 * Copyright (c) 2018 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
11 #include <memory>
12
13 #include "api/test/simulated_network.h"
14 #include "api/test/video/function_video_encoder_factory.h"
15 #include "call/fake_network_pipe.h"
16 #include "call/simulated_network.h"
17 #include "modules/include/module_common_types_public.h"
18 #include "modules/rtp_rtcp/source/rtp_packet.h"
19 #include "modules/video_coding/codecs/h264/include/h264.h"
20 #include "modules/video_coding/codecs/vp8/include/vp8.h"
21 #include "modules/video_coding/codecs/vp9/include/vp9.h"
22 #include "rtc_base/synchronization/mutex.h"
23 #include "rtc_base/task_queue_for_test.h"
24 #include "test/call_test.h"
25 #include "test/gmock.h"
26 #include "test/gtest.h"
27
28 using ::testing::Contains;
29
30 namespace webrtc {
31 namespace {
32 constexpr int kWidth = 1280;
33 constexpr int kHeight = 720;
34 constexpr int kFps = 30;
35 constexpr int kFramesToObserve = 10;
36
PayloadNameToPayloadType(const std::string & payload_name)37 uint8_t PayloadNameToPayloadType(const std::string& payload_name) {
38 if (payload_name == "VP8") {
39 return test::CallTest::kPayloadTypeVP8;
40 } else if (payload_name == "VP9") {
41 return test::CallTest::kPayloadTypeVP9;
42 } else if (payload_name == "H264") {
43 return test::CallTest::kPayloadTypeH264;
44 } else {
45 RTC_DCHECK_NOTREACHED();
46 return 0;
47 }
48 }
49
RemoveOlderOrEqual(uint32_t timestamp,std::vector<uint32_t> * timestamps)50 int RemoveOlderOrEqual(uint32_t timestamp, std::vector<uint32_t>* timestamps) {
51 int num_removed = 0;
52 while (!timestamps->empty()) {
53 auto it = timestamps->begin();
54 if (IsNewerTimestamp(*it, timestamp))
55 break;
56
57 timestamps->erase(it);
58 ++num_removed;
59 }
60 return num_removed;
61 }
62
63 class FrameObserver : public test::RtpRtcpObserver,
64 public rtc::VideoSinkInterface<VideoFrame> {
65 public:
FrameObserver()66 FrameObserver() : test::RtpRtcpObserver(test::CallTest::kDefaultTimeout) {}
67
Reset(uint8_t expected_payload_type)68 void Reset(uint8_t expected_payload_type) {
69 MutexLock lock(&mutex_);
70 num_sent_frames_ = 0;
71 num_rendered_frames_ = 0;
72 expected_payload_type_ = expected_payload_type;
73 }
74
75 private:
76 // Sends kFramesToObserve.
OnSendRtp(const uint8_t * packet,size_t length)77 Action OnSendRtp(const uint8_t* packet, size_t length) override {
78 MutexLock lock(&mutex_);
79
80 RtpPacket rtp_packet;
81 EXPECT_TRUE(rtp_packet.Parse(packet, length));
82 EXPECT_EQ(rtp_packet.Ssrc(), test::CallTest::kVideoSendSsrcs[0]);
83 if (rtp_packet.payload_size() == 0)
84 return SEND_PACKET; // Skip padding, may be sent after OnFrame is called.
85
86 if (expected_payload_type_ &&
87 rtp_packet.PayloadType() != expected_payload_type_.value()) {
88 return DROP_PACKET; // All frames sent.
89 }
90
91 if (!last_timestamp_ || rtp_packet.Timestamp() != *last_timestamp_) {
92 // New frame.
93 // Sent enough frames?
94 if (num_sent_frames_ >= kFramesToObserve)
95 return DROP_PACKET;
96
97 ++num_sent_frames_;
98 sent_timestamps_.push_back(rtp_packet.Timestamp());
99 }
100
101 last_timestamp_ = rtp_packet.Timestamp();
102 return SEND_PACKET;
103 }
104
105 // Verifies that all sent frames are decoded and rendered.
OnFrame(const VideoFrame & rendered_frame)106 void OnFrame(const VideoFrame& rendered_frame) override {
107 MutexLock lock(&mutex_);
108 EXPECT_THAT(sent_timestamps_, Contains(rendered_frame.timestamp()));
109
110 // Remove old timestamps too, only the newest decoded frame is rendered.
111 num_rendered_frames_ +=
112 RemoveOlderOrEqual(rendered_frame.timestamp(), &sent_timestamps_);
113
114 if (num_rendered_frames_ >= kFramesToObserve) {
115 EXPECT_TRUE(sent_timestamps_.empty()) << "All sent frames not decoded.";
116 observation_complete_.Set();
117 }
118 }
119
120 Mutex mutex_;
121 absl::optional<uint32_t> last_timestamp_; // Only accessed from pacer thread.
122 absl::optional<uint8_t> expected_payload_type_ RTC_GUARDED_BY(mutex_);
123 int num_sent_frames_ RTC_GUARDED_BY(mutex_) = 0;
124 int num_rendered_frames_ RTC_GUARDED_BY(mutex_) = 0;
125 std::vector<uint32_t> sent_timestamps_ RTC_GUARDED_BY(mutex_);
126 };
127 } // namespace
128
129 class MultiCodecReceiveTest : public test::CallTest {
130 public:
MultiCodecReceiveTest()131 MultiCodecReceiveTest() {
132 SendTask(task_queue(), [this]() {
133 CreateCalls();
134
135 send_transport_.reset(new test::PacketTransport(
136 task_queue(), sender_call_.get(), &observer_,
137 test::PacketTransport::kSender, kPayloadTypeMap,
138 std::make_unique<FakeNetworkPipe>(
139 Clock::GetRealTimeClock(), std::make_unique<SimulatedNetwork>(
140 BuiltInNetworkBehaviorConfig()))));
141 send_transport_->SetReceiver(receiver_call_->Receiver());
142
143 receive_transport_.reset(new test::PacketTransport(
144 task_queue(), receiver_call_.get(), &observer_,
145 test::PacketTransport::kReceiver, kPayloadTypeMap,
146 std::make_unique<FakeNetworkPipe>(
147 Clock::GetRealTimeClock(), std::make_unique<SimulatedNetwork>(
148 BuiltInNetworkBehaviorConfig()))));
149 receive_transport_->SetReceiver(sender_call_->Receiver());
150 });
151 }
152
~MultiCodecReceiveTest()153 virtual ~MultiCodecReceiveTest() {
154 SendTask(task_queue(), [this]() {
155 send_transport_.reset();
156 receive_transport_.reset();
157 DestroyCalls();
158 });
159 }
160
161 struct CodecConfig {
162 std::string payload_name;
163 size_t num_temporal_layers;
164 };
165
166 void ConfigureEncoder(const CodecConfig& config,
167 VideoEncoderFactory* encoder_factory);
168 void ConfigureDecoders(const std::vector<CodecConfig>& configs,
169 VideoDecoderFactory* decoder_factory);
170 void RunTestWithCodecs(const std::vector<CodecConfig>& configs);
171
172 private:
173 const std::map<uint8_t, MediaType> kPayloadTypeMap = {
174 {CallTest::kPayloadTypeVP8, MediaType::VIDEO},
175 {CallTest::kPayloadTypeVP9, MediaType::VIDEO},
176 {CallTest::kPayloadTypeH264, MediaType::VIDEO}};
177 FrameObserver observer_;
178 };
179
ConfigureDecoders(const std::vector<CodecConfig> & configs,VideoDecoderFactory * decoder_factory)180 void MultiCodecReceiveTest::ConfigureDecoders(
181 const std::vector<CodecConfig>& configs,
182 VideoDecoderFactory* decoder_factory) {
183 video_receive_configs_[0].decoders.clear();
184 // Placing the payload names in a std::set retains the unique names only.
185 video_receive_configs_[0].decoder_factory = decoder_factory;
186 std::set<std::string> unique_payload_names;
187 for (const auto& config : configs)
188 if (unique_payload_names.insert(config.payload_name).second) {
189 VideoReceiveStreamInterface::Decoder decoder =
190 test::CreateMatchingDecoder(
191 PayloadNameToPayloadType(config.payload_name),
192 config.payload_name);
193
194 video_receive_configs_[0].decoders.push_back(decoder);
195 }
196 }
197
ConfigureEncoder(const CodecConfig & config,VideoEncoderFactory * encoder_factory)198 void MultiCodecReceiveTest::ConfigureEncoder(
199 const CodecConfig& config,
200 VideoEncoderFactory* encoder_factory) {
201 GetVideoSendConfig()->encoder_settings.encoder_factory = encoder_factory;
202 GetVideoSendConfig()->rtp.payload_name = config.payload_name;
203 GetVideoSendConfig()->rtp.payload_type =
204 PayloadNameToPayloadType(config.payload_name);
205 GetVideoEncoderConfig()->codec_type =
206 PayloadStringToCodecType(config.payload_name);
207 EXPECT_EQ(1u, GetVideoEncoderConfig()->simulcast_layers.size());
208 GetVideoEncoderConfig()->simulcast_layers[0].num_temporal_layers =
209 config.num_temporal_layers;
210 GetVideoEncoderConfig()->video_format.name = config.payload_name;
211 }
212
RunTestWithCodecs(const std::vector<CodecConfig> & configs)213 void MultiCodecReceiveTest::RunTestWithCodecs(
214 const std::vector<CodecConfig>& configs) {
215 EXPECT_TRUE(!configs.empty());
216
217 test::FunctionVideoEncoderFactory encoder_factory(
218 [](const SdpVideoFormat& format) -> std::unique_ptr<VideoEncoder> {
219 if (format.name == "VP8") {
220 return VP8Encoder::Create();
221 }
222 if (format.name == "VP9") {
223 return VP9Encoder::Create();
224 }
225 if (format.name == "H264") {
226 return H264Encoder::Create(cricket::VideoCodec("H264"));
227 }
228 RTC_DCHECK_NOTREACHED() << format.name;
229 return nullptr;
230 });
231 test::FunctionVideoDecoderFactory decoder_factory(
232 [](const SdpVideoFormat& format) -> std::unique_ptr<VideoDecoder> {
233 if (format.name == "VP8") {
234 return VP8Decoder::Create();
235 }
236 if (format.name == "VP9") {
237 return VP9Decoder::Create();
238 }
239 if (format.name == "H264") {
240 return H264Decoder::Create();
241 }
242 RTC_DCHECK_NOTREACHED() << format.name;
243 return nullptr;
244 });
245 // Create and start call.
246 SendTask(task_queue(),
247 [this, &configs, &encoder_factory, &decoder_factory]() {
248 CreateSendConfig(1, 0, 0, send_transport_.get());
249 ConfigureEncoder(configs[0], &encoder_factory);
250 CreateMatchingReceiveConfigs(receive_transport_.get());
251 video_receive_configs_[0].renderer = &observer_;
252 // Disable to avoid post-decode frame dropping in
253 // VideoRenderFrames.
254 video_receive_configs_[0].enable_prerenderer_smoothing = false;
255 ConfigureDecoders(configs, &decoder_factory);
256 CreateVideoStreams();
257 CreateFrameGeneratorCapturer(kFps, kWidth, kHeight);
258 Start();
259 });
260 EXPECT_TRUE(observer_.Wait()) << "Timed out waiting for frames.";
261
262 for (size_t i = 1; i < configs.size(); ++i) {
263 // Recreate VideoSendStream with new config (codec, temporal layers).
264 SendTask(task_queue(), [this, i, &configs, &encoder_factory]() {
265 DestroyVideoSendStreams();
266 observer_.Reset(PayloadNameToPayloadType(configs[i].payload_name));
267
268 ConfigureEncoder(configs[i], &encoder_factory);
269 CreateVideoSendStreams();
270 GetVideoSendStream()->Start();
271 CreateFrameGeneratorCapturer(kFps, kWidth / 2, kHeight / 2);
272 ConnectVideoSourcesToStreams();
273 });
274 EXPECT_TRUE(observer_.Wait()) << "Timed out waiting for frames.";
275 }
276
277 SendTask(task_queue(), [this]() {
278 Stop();
279 DestroyStreams();
280 });
281 }
282
TEST_F(MultiCodecReceiveTest,SingleStreamReceivesVp8Vp9)283 TEST_F(MultiCodecReceiveTest, SingleStreamReceivesVp8Vp9) {
284 RunTestWithCodecs({{"VP8", 1}, {"VP9", 1}, {"VP8", 1}});
285 }
286
TEST_F(MultiCodecReceiveTest,SingleStreamReceivesVp8Vp9WithTl)287 TEST_F(MultiCodecReceiveTest, SingleStreamReceivesVp8Vp9WithTl) {
288 RunTestWithCodecs({{"VP8", 2}, {"VP9", 2}, {"VP8", 2}});
289 }
290
291 #if defined(WEBRTC_USE_H264)
TEST_F(MultiCodecReceiveTest,SingleStreamReceivesVp8H264)292 TEST_F(MultiCodecReceiveTest, SingleStreamReceivesVp8H264) {
293 RunTestWithCodecs({{"VP8", 1}, {"H264", 1}, {"VP8", 1}});
294 }
295
TEST_F(MultiCodecReceiveTest,SingleStreamReceivesVp8H264WithTl)296 TEST_F(MultiCodecReceiveTest, SingleStreamReceivesVp8H264WithTl) {
297 RunTestWithCodecs({{"VP8", 3}, {"H264", 1}, {"VP8", 3}});
298 }
299
TEST_F(MultiCodecReceiveTest,SingleStreamReceivesVp8Vp9H264)300 TEST_F(MultiCodecReceiveTest, SingleStreamReceivesVp8Vp9H264) {
301 RunTestWithCodecs({{"VP8", 1}, {"VP9", 1}, {"H264", 1}, {"VP9", 1}});
302 }
303
TEST_F(MultiCodecReceiveTest,SingleStreamReceivesVp8Vp9H264WithTl)304 TEST_F(MultiCodecReceiveTest, SingleStreamReceivesVp8Vp9H264WithTl) {
305 RunTestWithCodecs({{"VP8", 3}, {"VP9", 2}, {"H264", 1}, {"VP9", 3}});
306 }
307 #endif // defined(WEBRTC_USE_H264)
308
309 } // namespace webrtc
310