• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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