1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include <memory>
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include "api/test/simulated_network.h"
14*d9f75844SAndroid Build Coastguard Worker #include "api/test/video/function_video_encoder_factory.h"
15*d9f75844SAndroid Build Coastguard Worker #include "call/fake_network_pipe.h"
16*d9f75844SAndroid Build Coastguard Worker #include "call/simulated_network.h"
17*d9f75844SAndroid Build Coastguard Worker #include "media/engine/internal_encoder_factory.h"
18*d9f75844SAndroid Build Coastguard Worker #include "media/engine/simulcast_encoder_adapter.h"
19*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/create_video_rtp_depacketizer.h"
20*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_packet.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/codecs/vp8/include/vp8.h"
22*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/codecs/vp9/include/vp9.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/sequence_number_util.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/synchronization/mutex.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/task_queue_for_test.h"
27*d9f75844SAndroid Build Coastguard Worker #include "test/call_test.h"
28*d9f75844SAndroid Build Coastguard Worker
29*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
30*d9f75844SAndroid Build Coastguard Worker namespace {
31*d9f75844SAndroid Build Coastguard Worker const int kFrameMaxWidth = 1280;
32*d9f75844SAndroid Build Coastguard Worker const int kFrameMaxHeight = 720;
33*d9f75844SAndroid Build Coastguard Worker const int kFrameRate = 30;
34*d9f75844SAndroid Build Coastguard Worker const int kMaxSecondsLost = 5;
35*d9f75844SAndroid Build Coastguard Worker const int kMaxFramesLost = kFrameRate * kMaxSecondsLost;
36*d9f75844SAndroid Build Coastguard Worker const int kMinPacketsToObserve = 10;
37*d9f75844SAndroid Build Coastguard Worker const int kEncoderBitrateBps = 300000;
38*d9f75844SAndroid Build Coastguard Worker const uint32_t kPictureIdWraparound = (1 << 15);
39*d9f75844SAndroid Build Coastguard Worker const size_t kNumTemporalLayers[] = {1, 2, 3};
40*d9f75844SAndroid Build Coastguard Worker
41*d9f75844SAndroid Build Coastguard Worker } // namespace
42*d9f75844SAndroid Build Coastguard Worker
43*d9f75844SAndroid Build Coastguard Worker class PictureIdObserver : public test::RtpRtcpObserver {
44*d9f75844SAndroid Build Coastguard Worker public:
PictureIdObserver(VideoCodecType codec_type)45*d9f75844SAndroid Build Coastguard Worker explicit PictureIdObserver(VideoCodecType codec_type)
46*d9f75844SAndroid Build Coastguard Worker : test::RtpRtcpObserver(test::CallTest::kDefaultTimeout),
47*d9f75844SAndroid Build Coastguard Worker depacketizer_(CreateVideoRtpDepacketizer(codec_type)),
48*d9f75844SAndroid Build Coastguard Worker max_expected_picture_id_gap_(0),
49*d9f75844SAndroid Build Coastguard Worker max_expected_tl0_idx_gap_(0),
50*d9f75844SAndroid Build Coastguard Worker num_ssrcs_to_observe_(1) {}
51*d9f75844SAndroid Build Coastguard Worker
SetExpectedSsrcs(size_t num_expected_ssrcs)52*d9f75844SAndroid Build Coastguard Worker void SetExpectedSsrcs(size_t num_expected_ssrcs) {
53*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
54*d9f75844SAndroid Build Coastguard Worker num_ssrcs_to_observe_ = num_expected_ssrcs;
55*d9f75844SAndroid Build Coastguard Worker }
56*d9f75844SAndroid Build Coastguard Worker
ResetObservedSsrcs()57*d9f75844SAndroid Build Coastguard Worker void ResetObservedSsrcs() {
58*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
59*d9f75844SAndroid Build Coastguard Worker // Do not clear the timestamp and picture_id, to ensure that we check
60*d9f75844SAndroid Build Coastguard Worker // consistency between reinits and recreations.
61*d9f75844SAndroid Build Coastguard Worker num_packets_sent_.clear();
62*d9f75844SAndroid Build Coastguard Worker observed_ssrcs_.clear();
63*d9f75844SAndroid Build Coastguard Worker }
64*d9f75844SAndroid Build Coastguard Worker
SetMaxExpectedPictureIdGap(int max_expected_picture_id_gap)65*d9f75844SAndroid Build Coastguard Worker void SetMaxExpectedPictureIdGap(int max_expected_picture_id_gap) {
66*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
67*d9f75844SAndroid Build Coastguard Worker max_expected_picture_id_gap_ = max_expected_picture_id_gap;
68*d9f75844SAndroid Build Coastguard Worker // Expect smaller gap for `tl0_pic_idx` (running index for temporal_idx 0).
69*d9f75844SAndroid Build Coastguard Worker max_expected_tl0_idx_gap_ = max_expected_picture_id_gap_ / 2;
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker
72*d9f75844SAndroid Build Coastguard Worker private:
73*d9f75844SAndroid Build Coastguard Worker struct ParsedPacket {
74*d9f75844SAndroid Build Coastguard Worker uint32_t timestamp;
75*d9f75844SAndroid Build Coastguard Worker uint32_t ssrc;
76*d9f75844SAndroid Build Coastguard Worker int16_t picture_id;
77*d9f75844SAndroid Build Coastguard Worker int16_t tl0_pic_idx;
78*d9f75844SAndroid Build Coastguard Worker uint8_t temporal_idx;
79*d9f75844SAndroid Build Coastguard Worker VideoFrameType frame_type;
80*d9f75844SAndroid Build Coastguard Worker };
81*d9f75844SAndroid Build Coastguard Worker
ParsePayload(const uint8_t * packet,size_t length,ParsedPacket * parsed) const82*d9f75844SAndroid Build Coastguard Worker bool ParsePayload(const uint8_t* packet,
83*d9f75844SAndroid Build Coastguard Worker size_t length,
84*d9f75844SAndroid Build Coastguard Worker ParsedPacket* parsed) const {
85*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp_packet;
86*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Parse(packet, length));
87*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Ssrc() == test::CallTest::kVideoSendSsrcs[0] ||
88*d9f75844SAndroid Build Coastguard Worker rtp_packet.Ssrc() == test::CallTest::kVideoSendSsrcs[1] ||
89*d9f75844SAndroid Build Coastguard Worker rtp_packet.Ssrc() == test::CallTest::kVideoSendSsrcs[2])
90*d9f75844SAndroid Build Coastguard Worker << "Unknown SSRC sent.";
91*d9f75844SAndroid Build Coastguard Worker
92*d9f75844SAndroid Build Coastguard Worker if (rtp_packet.payload_size() == 0) {
93*d9f75844SAndroid Build Coastguard Worker return false; // Padding packet.
94*d9f75844SAndroid Build Coastguard Worker }
95*d9f75844SAndroid Build Coastguard Worker
96*d9f75844SAndroid Build Coastguard Worker parsed->timestamp = rtp_packet.Timestamp();
97*d9f75844SAndroid Build Coastguard Worker parsed->ssrc = rtp_packet.Ssrc();
98*d9f75844SAndroid Build Coastguard Worker
99*d9f75844SAndroid Build Coastguard Worker absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> parsed_payload =
100*d9f75844SAndroid Build Coastguard Worker depacketizer_->Parse(rtp_packet.PayloadBuffer());
101*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(parsed_payload);
102*d9f75844SAndroid Build Coastguard Worker
103*d9f75844SAndroid Build Coastguard Worker if (const auto* vp8_header = absl::get_if<RTPVideoHeaderVP8>(
104*d9f75844SAndroid Build Coastguard Worker &parsed_payload->video_header.video_type_header)) {
105*d9f75844SAndroid Build Coastguard Worker parsed->picture_id = vp8_header->pictureId;
106*d9f75844SAndroid Build Coastguard Worker parsed->tl0_pic_idx = vp8_header->tl0PicIdx;
107*d9f75844SAndroid Build Coastguard Worker parsed->temporal_idx = vp8_header->temporalIdx;
108*d9f75844SAndroid Build Coastguard Worker } else if (const auto* vp9_header = absl::get_if<RTPVideoHeaderVP9>(
109*d9f75844SAndroid Build Coastguard Worker &parsed_payload->video_header.video_type_header)) {
110*d9f75844SAndroid Build Coastguard Worker parsed->picture_id = vp9_header->picture_id;
111*d9f75844SAndroid Build Coastguard Worker parsed->tl0_pic_idx = vp9_header->tl0_pic_idx;
112*d9f75844SAndroid Build Coastguard Worker parsed->temporal_idx = vp9_header->temporal_idx;
113*d9f75844SAndroid Build Coastguard Worker } else {
114*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_NOTREACHED();
115*d9f75844SAndroid Build Coastguard Worker }
116*d9f75844SAndroid Build Coastguard Worker
117*d9f75844SAndroid Build Coastguard Worker parsed->frame_type = parsed_payload->video_header.frame_type;
118*d9f75844SAndroid Build Coastguard Worker return true;
119*d9f75844SAndroid Build Coastguard Worker }
120*d9f75844SAndroid Build Coastguard Worker
121*d9f75844SAndroid Build Coastguard Worker // Verify continuity and monotonicity of picture_id sequence.
VerifyPictureId(const ParsedPacket & current,const ParsedPacket & last) const122*d9f75844SAndroid Build Coastguard Worker void VerifyPictureId(const ParsedPacket& current,
123*d9f75844SAndroid Build Coastguard Worker const ParsedPacket& last) const
124*d9f75844SAndroid Build Coastguard Worker RTC_EXCLUSIVE_LOCKS_REQUIRED(&mutex_) {
125*d9f75844SAndroid Build Coastguard Worker if (current.timestamp == last.timestamp) {
126*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(last.picture_id, current.picture_id);
127*d9f75844SAndroid Build Coastguard Worker return; // Same frame.
128*d9f75844SAndroid Build Coastguard Worker }
129*d9f75844SAndroid Build Coastguard Worker
130*d9f75844SAndroid Build Coastguard Worker // Packet belongs to a new frame.
131*d9f75844SAndroid Build Coastguard Worker // Picture id should be increasing.
132*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE((AheadOf<uint16_t, kPictureIdWraparound>(current.picture_id,
133*d9f75844SAndroid Build Coastguard Worker last.picture_id)));
134*d9f75844SAndroid Build Coastguard Worker
135*d9f75844SAndroid Build Coastguard Worker // Expect continuously increasing picture id.
136*d9f75844SAndroid Build Coastguard Worker int diff = ForwardDiff<uint16_t, kPictureIdWraparound>(last.picture_id,
137*d9f75844SAndroid Build Coastguard Worker current.picture_id);
138*d9f75844SAndroid Build Coastguard Worker EXPECT_LE(diff - 1, max_expected_picture_id_gap_);
139*d9f75844SAndroid Build Coastguard Worker if (diff > 2) {
140*d9f75844SAndroid Build Coastguard Worker // If the VideoSendStream is destroyed, any frames still in queue is lost.
141*d9f75844SAndroid Build Coastguard Worker // This can result in a two-frame gap, which will result in logs like
142*d9f75844SAndroid Build Coastguard Worker // "packet transmission failed, no matching RTP module found, or
143*d9f75844SAndroid Build Coastguard Worker // transmission error".
144*d9f75844SAndroid Build Coastguard Worker // A larger gap is only possible for first frame after a recreation, i.e.
145*d9f75844SAndroid Build Coastguard Worker // key frames.
146*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(VideoFrameType::kVideoFrameKey, current.frame_type);
147*d9f75844SAndroid Build Coastguard Worker }
148*d9f75844SAndroid Build Coastguard Worker }
149*d9f75844SAndroid Build Coastguard Worker
VerifyTl0Idx(const ParsedPacket & current,const ParsedPacket & last) const150*d9f75844SAndroid Build Coastguard Worker void VerifyTl0Idx(const ParsedPacket& current, const ParsedPacket& last) const
151*d9f75844SAndroid Build Coastguard Worker RTC_EXCLUSIVE_LOCKS_REQUIRED(&mutex_) {
152*d9f75844SAndroid Build Coastguard Worker if (current.tl0_pic_idx == kNoTl0PicIdx ||
153*d9f75844SAndroid Build Coastguard Worker current.temporal_idx == kNoTemporalIdx) {
154*d9f75844SAndroid Build Coastguard Worker return; // No temporal layers.
155*d9f75844SAndroid Build Coastguard Worker }
156*d9f75844SAndroid Build Coastguard Worker
157*d9f75844SAndroid Build Coastguard Worker if (current.timestamp == last.timestamp || current.temporal_idx != 0) {
158*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(last.tl0_pic_idx, current.tl0_pic_idx);
159*d9f75844SAndroid Build Coastguard Worker return;
160*d9f75844SAndroid Build Coastguard Worker }
161*d9f75844SAndroid Build Coastguard Worker
162*d9f75844SAndroid Build Coastguard Worker // New frame with `temporal_idx` 0.
163*d9f75844SAndroid Build Coastguard Worker // `tl0_pic_idx` should be increasing.
164*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(AheadOf<uint8_t>(current.tl0_pic_idx, last.tl0_pic_idx));
165*d9f75844SAndroid Build Coastguard Worker
166*d9f75844SAndroid Build Coastguard Worker // Expect continuously increasing idx.
167*d9f75844SAndroid Build Coastguard Worker int diff = ForwardDiff<uint8_t>(last.tl0_pic_idx, current.tl0_pic_idx);
168*d9f75844SAndroid Build Coastguard Worker if (diff > 1) {
169*d9f75844SAndroid Build Coastguard Worker // If the VideoSendStream is destroyed, any frames still in queue is lost.
170*d9f75844SAndroid Build Coastguard Worker // Gaps only possible for first frame after a recreation, i.e. key frames.
171*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(VideoFrameType::kVideoFrameKey, current.frame_type);
172*d9f75844SAndroid Build Coastguard Worker EXPECT_LE(diff - 1, max_expected_tl0_idx_gap_);
173*d9f75844SAndroid Build Coastguard Worker }
174*d9f75844SAndroid Build Coastguard Worker }
175*d9f75844SAndroid Build Coastguard Worker
OnSendRtp(const uint8_t * packet,size_t length)176*d9f75844SAndroid Build Coastguard Worker Action OnSendRtp(const uint8_t* packet, size_t length) override {
177*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
178*d9f75844SAndroid Build Coastguard Worker
179*d9f75844SAndroid Build Coastguard Worker ParsedPacket parsed;
180*d9f75844SAndroid Build Coastguard Worker if (!ParsePayload(packet, length, &parsed))
181*d9f75844SAndroid Build Coastguard Worker return SEND_PACKET;
182*d9f75844SAndroid Build Coastguard Worker
183*d9f75844SAndroid Build Coastguard Worker uint32_t ssrc = parsed.ssrc;
184*d9f75844SAndroid Build Coastguard Worker if (last_observed_packet_.find(ssrc) != last_observed_packet_.end()) {
185*d9f75844SAndroid Build Coastguard Worker // Compare to last packet.
186*d9f75844SAndroid Build Coastguard Worker VerifyPictureId(parsed, last_observed_packet_[ssrc]);
187*d9f75844SAndroid Build Coastguard Worker VerifyTl0Idx(parsed, last_observed_packet_[ssrc]);
188*d9f75844SAndroid Build Coastguard Worker }
189*d9f75844SAndroid Build Coastguard Worker
190*d9f75844SAndroid Build Coastguard Worker last_observed_packet_[ssrc] = parsed;
191*d9f75844SAndroid Build Coastguard Worker
192*d9f75844SAndroid Build Coastguard Worker // Pass the test when enough media packets have been received on all
193*d9f75844SAndroid Build Coastguard Worker // streams.
194*d9f75844SAndroid Build Coastguard Worker if (++num_packets_sent_[ssrc] >= kMinPacketsToObserve &&
195*d9f75844SAndroid Build Coastguard Worker observed_ssrcs_.find(ssrc) == observed_ssrcs_.end()) {
196*d9f75844SAndroid Build Coastguard Worker observed_ssrcs_.insert(ssrc);
197*d9f75844SAndroid Build Coastguard Worker if (observed_ssrcs_.size() == num_ssrcs_to_observe_) {
198*d9f75844SAndroid Build Coastguard Worker observation_complete_.Set();
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker }
201*d9f75844SAndroid Build Coastguard Worker return SEND_PACKET;
202*d9f75844SAndroid Build Coastguard Worker }
203*d9f75844SAndroid Build Coastguard Worker
204*d9f75844SAndroid Build Coastguard Worker Mutex mutex_;
205*d9f75844SAndroid Build Coastguard Worker const std::unique_ptr<VideoRtpDepacketizer> depacketizer_;
206*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, ParsedPacket> last_observed_packet_ RTC_GUARDED_BY(mutex_);
207*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, size_t> num_packets_sent_ RTC_GUARDED_BY(mutex_);
208*d9f75844SAndroid Build Coastguard Worker int max_expected_picture_id_gap_ RTC_GUARDED_BY(mutex_);
209*d9f75844SAndroid Build Coastguard Worker int max_expected_tl0_idx_gap_ RTC_GUARDED_BY(mutex_);
210*d9f75844SAndroid Build Coastguard Worker size_t num_ssrcs_to_observe_ RTC_GUARDED_BY(mutex_);
211*d9f75844SAndroid Build Coastguard Worker std::set<uint32_t> observed_ssrcs_ RTC_GUARDED_BY(mutex_);
212*d9f75844SAndroid Build Coastguard Worker };
213*d9f75844SAndroid Build Coastguard Worker
214*d9f75844SAndroid Build Coastguard Worker class PictureIdTest : public test::CallTest,
215*d9f75844SAndroid Build Coastguard Worker public ::testing::WithParamInterface<size_t> {
216*d9f75844SAndroid Build Coastguard Worker public:
PictureIdTest()217*d9f75844SAndroid Build Coastguard Worker PictureIdTest() : num_temporal_layers_(GetParam()) {}
218*d9f75844SAndroid Build Coastguard Worker
~PictureIdTest()219*d9f75844SAndroid Build Coastguard Worker virtual ~PictureIdTest() {
220*d9f75844SAndroid Build Coastguard Worker SendTask(task_queue(), [this]() {
221*d9f75844SAndroid Build Coastguard Worker send_transport_.reset();
222*d9f75844SAndroid Build Coastguard Worker receive_transport_.reset();
223*d9f75844SAndroid Build Coastguard Worker DestroyCalls();
224*d9f75844SAndroid Build Coastguard Worker });
225*d9f75844SAndroid Build Coastguard Worker }
226*d9f75844SAndroid Build Coastguard Worker
227*d9f75844SAndroid Build Coastguard Worker void SetupEncoder(VideoEncoderFactory* encoder_factory,
228*d9f75844SAndroid Build Coastguard Worker const std::string& payload_name);
229*d9f75844SAndroid Build Coastguard Worker void SetVideoEncoderConfig(int num_streams);
230*d9f75844SAndroid Build Coastguard Worker void TestPictureIdContinuousAfterReconfigure(
231*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& ssrc_counts);
232*d9f75844SAndroid Build Coastguard Worker void TestPictureIdIncreaseAfterRecreateStreams(
233*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& ssrc_counts);
234*d9f75844SAndroid Build Coastguard Worker
235*d9f75844SAndroid Build Coastguard Worker private:
236*d9f75844SAndroid Build Coastguard Worker const size_t num_temporal_layers_;
237*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<PictureIdObserver> observer_;
238*d9f75844SAndroid Build Coastguard Worker };
239*d9f75844SAndroid Build Coastguard Worker
240*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/13725): Enable on android when flakiness fixed.
241*d9f75844SAndroid Build Coastguard Worker #if defined(WEBRTC_ANDROID)
242*d9f75844SAndroid Build Coastguard Worker #define MAYBE_TemporalLayers DISABLED_TemporalLayers
243*d9f75844SAndroid Build Coastguard Worker #else
244*d9f75844SAndroid Build Coastguard Worker #define MAYBE_TemporalLayers TemporalLayers
245*d9f75844SAndroid Build Coastguard Worker #endif
246*d9f75844SAndroid Build Coastguard Worker
247*d9f75844SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(MAYBE_TemporalLayers,
248*d9f75844SAndroid Build Coastguard Worker PictureIdTest,
249*d9f75844SAndroid Build Coastguard Worker ::testing::ValuesIn(kNumTemporalLayers));
250*d9f75844SAndroid Build Coastguard Worker
SetupEncoder(VideoEncoderFactory * encoder_factory,const std::string & payload_name)251*d9f75844SAndroid Build Coastguard Worker void PictureIdTest::SetupEncoder(VideoEncoderFactory* encoder_factory,
252*d9f75844SAndroid Build Coastguard Worker const std::string& payload_name) {
253*d9f75844SAndroid Build Coastguard Worker observer_.reset(
254*d9f75844SAndroid Build Coastguard Worker new PictureIdObserver(PayloadStringToCodecType(payload_name)));
255*d9f75844SAndroid Build Coastguard Worker
256*d9f75844SAndroid Build Coastguard Worker SendTask(
257*d9f75844SAndroid Build Coastguard Worker task_queue(), [this, encoder_factory, payload_name]() {
258*d9f75844SAndroid Build Coastguard Worker CreateCalls();
259*d9f75844SAndroid Build Coastguard Worker
260*d9f75844SAndroid Build Coastguard Worker send_transport_.reset(new test::PacketTransport(
261*d9f75844SAndroid Build Coastguard Worker task_queue(), sender_call_.get(), observer_.get(),
262*d9f75844SAndroid Build Coastguard Worker test::PacketTransport::kSender, payload_type_map_,
263*d9f75844SAndroid Build Coastguard Worker std::make_unique<FakeNetworkPipe>(
264*d9f75844SAndroid Build Coastguard Worker Clock::GetRealTimeClock(),
265*d9f75844SAndroid Build Coastguard Worker std::make_unique<SimulatedNetwork>(
266*d9f75844SAndroid Build Coastguard Worker BuiltInNetworkBehaviorConfig()))));
267*d9f75844SAndroid Build Coastguard Worker
268*d9f75844SAndroid Build Coastguard Worker CreateSendConfig(kNumSimulcastStreams, 0, 0, send_transport_.get());
269*d9f75844SAndroid Build Coastguard Worker GetVideoSendConfig()->encoder_settings.encoder_factory =
270*d9f75844SAndroid Build Coastguard Worker encoder_factory;
271*d9f75844SAndroid Build Coastguard Worker GetVideoSendConfig()->rtp.payload_name = payload_name;
272*d9f75844SAndroid Build Coastguard Worker GetVideoEncoderConfig()->codec_type =
273*d9f75844SAndroid Build Coastguard Worker PayloadStringToCodecType(payload_name);
274*d9f75844SAndroid Build Coastguard Worker SetVideoEncoderConfig(/* number_of_streams */ 1);
275*d9f75844SAndroid Build Coastguard Worker });
276*d9f75844SAndroid Build Coastguard Worker }
277*d9f75844SAndroid Build Coastguard Worker
SetVideoEncoderConfig(int num_streams)278*d9f75844SAndroid Build Coastguard Worker void PictureIdTest::SetVideoEncoderConfig(int num_streams) {
279*d9f75844SAndroid Build Coastguard Worker GetVideoEncoderConfig()->number_of_streams = num_streams;
280*d9f75844SAndroid Build Coastguard Worker GetVideoEncoderConfig()->max_bitrate_bps = kEncoderBitrateBps;
281*d9f75844SAndroid Build Coastguard Worker
282*d9f75844SAndroid Build Coastguard Worker // Always divide the same total bitrate across all streams so that sending a
283*d9f75844SAndroid Build Coastguard Worker // single stream avoids lowering the bitrate estimate and requiring a
284*d9f75844SAndroid Build Coastguard Worker // subsequent rampup.
285*d9f75844SAndroid Build Coastguard Worker const int encoder_stream_bps = kEncoderBitrateBps / num_streams;
286*d9f75844SAndroid Build Coastguard Worker double scale_factor = 1.0;
287*d9f75844SAndroid Build Coastguard Worker for (int i = num_streams - 1; i >= 0; --i) {
288*d9f75844SAndroid Build Coastguard Worker VideoStream& stream = GetVideoEncoderConfig()->simulcast_layers[i];
289*d9f75844SAndroid Build Coastguard Worker // Reduce the min bitrate by 10% to account for overhead that might
290*d9f75844SAndroid Build Coastguard Worker // otherwise cause streams to not be enabled.
291*d9f75844SAndroid Build Coastguard Worker stream.min_bitrate_bps = static_cast<int>(encoder_stream_bps * 0.9);
292*d9f75844SAndroid Build Coastguard Worker stream.target_bitrate_bps = encoder_stream_bps;
293*d9f75844SAndroid Build Coastguard Worker stream.max_bitrate_bps = encoder_stream_bps;
294*d9f75844SAndroid Build Coastguard Worker stream.num_temporal_layers = num_temporal_layers_;
295*d9f75844SAndroid Build Coastguard Worker stream.scale_resolution_down_by = scale_factor;
296*d9f75844SAndroid Build Coastguard Worker scale_factor *= 2.0;
297*d9f75844SAndroid Build Coastguard Worker }
298*d9f75844SAndroid Build Coastguard Worker }
299*d9f75844SAndroid Build Coastguard Worker
TestPictureIdContinuousAfterReconfigure(const std::vector<int> & ssrc_counts)300*d9f75844SAndroid Build Coastguard Worker void PictureIdTest::TestPictureIdContinuousAfterReconfigure(
301*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& ssrc_counts) {
302*d9f75844SAndroid Build Coastguard Worker SendTask(task_queue(), [this]() {
303*d9f75844SAndroid Build Coastguard Worker CreateVideoStreams();
304*d9f75844SAndroid Build Coastguard Worker CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
305*d9f75844SAndroid Build Coastguard Worker
306*d9f75844SAndroid Build Coastguard Worker // Initial test with a single stream.
307*d9f75844SAndroid Build Coastguard Worker Start();
308*d9f75844SAndroid Build Coastguard Worker });
309*d9f75844SAndroid Build Coastguard Worker
310*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
311*d9f75844SAndroid Build Coastguard Worker
312*d9f75844SAndroid Build Coastguard Worker // Reconfigure VideoEncoder and test picture id increase.
313*d9f75844SAndroid Build Coastguard Worker // Expect continuously increasing picture id, equivalent to no gaps.
314*d9f75844SAndroid Build Coastguard Worker observer_->SetMaxExpectedPictureIdGap(0);
315*d9f75844SAndroid Build Coastguard Worker for (int ssrc_count : ssrc_counts) {
316*d9f75844SAndroid Build Coastguard Worker SetVideoEncoderConfig(ssrc_count);
317*d9f75844SAndroid Build Coastguard Worker observer_->SetExpectedSsrcs(ssrc_count);
318*d9f75844SAndroid Build Coastguard Worker observer_->ResetObservedSsrcs();
319*d9f75844SAndroid Build Coastguard Worker // Make sure the picture_id sequence is continuous on reinit and recreate.
320*d9f75844SAndroid Build Coastguard Worker SendTask(task_queue(), [this]() {
321*d9f75844SAndroid Build Coastguard Worker GetVideoSendStream()->ReconfigureVideoEncoder(
322*d9f75844SAndroid Build Coastguard Worker GetVideoEncoderConfig()->Copy());
323*d9f75844SAndroid Build Coastguard Worker });
324*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
325*d9f75844SAndroid Build Coastguard Worker }
326*d9f75844SAndroid Build Coastguard Worker
327*d9f75844SAndroid Build Coastguard Worker SendTask(task_queue(), [this]() {
328*d9f75844SAndroid Build Coastguard Worker Stop();
329*d9f75844SAndroid Build Coastguard Worker DestroyStreams();
330*d9f75844SAndroid Build Coastguard Worker });
331*d9f75844SAndroid Build Coastguard Worker }
332*d9f75844SAndroid Build Coastguard Worker
TestPictureIdIncreaseAfterRecreateStreams(const std::vector<int> & ssrc_counts)333*d9f75844SAndroid Build Coastguard Worker void PictureIdTest::TestPictureIdIncreaseAfterRecreateStreams(
334*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& ssrc_counts) {
335*d9f75844SAndroid Build Coastguard Worker SendTask(task_queue(), [this]() {
336*d9f75844SAndroid Build Coastguard Worker CreateVideoStreams();
337*d9f75844SAndroid Build Coastguard Worker CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
338*d9f75844SAndroid Build Coastguard Worker
339*d9f75844SAndroid Build Coastguard Worker // Initial test with a single stream.
340*d9f75844SAndroid Build Coastguard Worker Start();
341*d9f75844SAndroid Build Coastguard Worker });
342*d9f75844SAndroid Build Coastguard Worker
343*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
344*d9f75844SAndroid Build Coastguard Worker
345*d9f75844SAndroid Build Coastguard Worker // Recreate VideoSendStream and test picture id increase.
346*d9f75844SAndroid Build Coastguard Worker // When the VideoSendStream is destroyed, any frames still in queue is lost
347*d9f75844SAndroid Build Coastguard Worker // with it, therefore it is expected that some frames might be lost.
348*d9f75844SAndroid Build Coastguard Worker observer_->SetMaxExpectedPictureIdGap(kMaxFramesLost);
349*d9f75844SAndroid Build Coastguard Worker for (int ssrc_count : ssrc_counts) {
350*d9f75844SAndroid Build Coastguard Worker SendTask(task_queue(), [this, &ssrc_count]() {
351*d9f75844SAndroid Build Coastguard Worker DestroyVideoSendStreams();
352*d9f75844SAndroid Build Coastguard Worker
353*d9f75844SAndroid Build Coastguard Worker SetVideoEncoderConfig(ssrc_count);
354*d9f75844SAndroid Build Coastguard Worker observer_->SetExpectedSsrcs(ssrc_count);
355*d9f75844SAndroid Build Coastguard Worker observer_->ResetObservedSsrcs();
356*d9f75844SAndroid Build Coastguard Worker
357*d9f75844SAndroid Build Coastguard Worker CreateVideoSendStreams();
358*d9f75844SAndroid Build Coastguard Worker GetVideoSendStream()->Start();
359*d9f75844SAndroid Build Coastguard Worker CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
360*d9f75844SAndroid Build Coastguard Worker });
361*d9f75844SAndroid Build Coastguard Worker
362*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
363*d9f75844SAndroid Build Coastguard Worker }
364*d9f75844SAndroid Build Coastguard Worker
365*d9f75844SAndroid Build Coastguard Worker SendTask(task_queue(), [this]() {
366*d9f75844SAndroid Build Coastguard Worker Stop();
367*d9f75844SAndroid Build Coastguard Worker DestroyStreams();
368*d9f75844SAndroid Build Coastguard Worker });
369*d9f75844SAndroid Build Coastguard Worker }
370*d9f75844SAndroid Build Coastguard Worker
TEST_P(PictureIdTest,ContinuousAfterReconfigureVp8)371*d9f75844SAndroid Build Coastguard Worker TEST_P(PictureIdTest, ContinuousAfterReconfigureVp8) {
372*d9f75844SAndroid Build Coastguard Worker test::FunctionVideoEncoderFactory encoder_factory(
373*d9f75844SAndroid Build Coastguard Worker []() { return VP8Encoder::Create(); });
374*d9f75844SAndroid Build Coastguard Worker SetupEncoder(&encoder_factory, "VP8");
375*d9f75844SAndroid Build Coastguard Worker TestPictureIdContinuousAfterReconfigure({1, 3, 3, 1, 1});
376*d9f75844SAndroid Build Coastguard Worker }
377*d9f75844SAndroid Build Coastguard Worker
TEST_P(PictureIdTest,IncreasingAfterRecreateStreamVp8)378*d9f75844SAndroid Build Coastguard Worker TEST_P(PictureIdTest, IncreasingAfterRecreateStreamVp8) {
379*d9f75844SAndroid Build Coastguard Worker test::FunctionVideoEncoderFactory encoder_factory(
380*d9f75844SAndroid Build Coastguard Worker []() { return VP8Encoder::Create(); });
381*d9f75844SAndroid Build Coastguard Worker SetupEncoder(&encoder_factory, "VP8");
382*d9f75844SAndroid Build Coastguard Worker TestPictureIdIncreaseAfterRecreateStreams({1, 3, 3, 1, 1});
383*d9f75844SAndroid Build Coastguard Worker }
384*d9f75844SAndroid Build Coastguard Worker
TEST_P(PictureIdTest,ContinuousAfterStreamCountChangeVp8)385*d9f75844SAndroid Build Coastguard Worker TEST_P(PictureIdTest, ContinuousAfterStreamCountChangeVp8) {
386*d9f75844SAndroid Build Coastguard Worker test::FunctionVideoEncoderFactory encoder_factory(
387*d9f75844SAndroid Build Coastguard Worker []() { return VP8Encoder::Create(); });
388*d9f75844SAndroid Build Coastguard Worker // Make sure that the picture id is not reset if the stream count goes
389*d9f75844SAndroid Build Coastguard Worker // down and then up.
390*d9f75844SAndroid Build Coastguard Worker SetupEncoder(&encoder_factory, "VP8");
391*d9f75844SAndroid Build Coastguard Worker TestPictureIdContinuousAfterReconfigure({3, 1, 3});
392*d9f75844SAndroid Build Coastguard Worker }
393*d9f75844SAndroid Build Coastguard Worker
TEST_P(PictureIdTest,ContinuousAfterReconfigureSimulcastEncoderAdapter)394*d9f75844SAndroid Build Coastguard Worker TEST_P(PictureIdTest, ContinuousAfterReconfigureSimulcastEncoderAdapter) {
395*d9f75844SAndroid Build Coastguard Worker InternalEncoderFactory internal_encoder_factory;
396*d9f75844SAndroid Build Coastguard Worker test::FunctionVideoEncoderFactory encoder_factory(
397*d9f75844SAndroid Build Coastguard Worker [&internal_encoder_factory]() {
398*d9f75844SAndroid Build Coastguard Worker return std::make_unique<SimulcastEncoderAdapter>(
399*d9f75844SAndroid Build Coastguard Worker &internal_encoder_factory, SdpVideoFormat("VP8"));
400*d9f75844SAndroid Build Coastguard Worker });
401*d9f75844SAndroid Build Coastguard Worker SetupEncoder(&encoder_factory, "VP8");
402*d9f75844SAndroid Build Coastguard Worker TestPictureIdContinuousAfterReconfigure({1, 3, 3, 1, 1});
403*d9f75844SAndroid Build Coastguard Worker }
404*d9f75844SAndroid Build Coastguard Worker
TEST_P(PictureIdTest,IncreasingAfterRecreateStreamSimulcastEncoderAdapter)405*d9f75844SAndroid Build Coastguard Worker TEST_P(PictureIdTest, IncreasingAfterRecreateStreamSimulcastEncoderAdapter) {
406*d9f75844SAndroid Build Coastguard Worker InternalEncoderFactory internal_encoder_factory;
407*d9f75844SAndroid Build Coastguard Worker test::FunctionVideoEncoderFactory encoder_factory(
408*d9f75844SAndroid Build Coastguard Worker [&internal_encoder_factory]() {
409*d9f75844SAndroid Build Coastguard Worker return std::make_unique<SimulcastEncoderAdapter>(
410*d9f75844SAndroid Build Coastguard Worker &internal_encoder_factory, SdpVideoFormat("VP8"));
411*d9f75844SAndroid Build Coastguard Worker });
412*d9f75844SAndroid Build Coastguard Worker SetupEncoder(&encoder_factory, "VP8");
413*d9f75844SAndroid Build Coastguard Worker TestPictureIdIncreaseAfterRecreateStreams({1, 3, 3, 1, 1});
414*d9f75844SAndroid Build Coastguard Worker }
415*d9f75844SAndroid Build Coastguard Worker
TEST_P(PictureIdTest,ContinuousAfterStreamCountChangeSimulcastEncoderAdapter)416*d9f75844SAndroid Build Coastguard Worker TEST_P(PictureIdTest, ContinuousAfterStreamCountChangeSimulcastEncoderAdapter) {
417*d9f75844SAndroid Build Coastguard Worker InternalEncoderFactory internal_encoder_factory;
418*d9f75844SAndroid Build Coastguard Worker test::FunctionVideoEncoderFactory encoder_factory(
419*d9f75844SAndroid Build Coastguard Worker [&internal_encoder_factory]() {
420*d9f75844SAndroid Build Coastguard Worker return std::make_unique<SimulcastEncoderAdapter>(
421*d9f75844SAndroid Build Coastguard Worker &internal_encoder_factory, SdpVideoFormat("VP8"));
422*d9f75844SAndroid Build Coastguard Worker });
423*d9f75844SAndroid Build Coastguard Worker // Make sure that the picture id is not reset if the stream count goes
424*d9f75844SAndroid Build Coastguard Worker // down and then up.
425*d9f75844SAndroid Build Coastguard Worker SetupEncoder(&encoder_factory, "VP8");
426*d9f75844SAndroid Build Coastguard Worker TestPictureIdContinuousAfterReconfigure({3, 1, 3});
427*d9f75844SAndroid Build Coastguard Worker }
428*d9f75844SAndroid Build Coastguard Worker
TEST_P(PictureIdTest,IncreasingAfterRecreateStreamVp9)429*d9f75844SAndroid Build Coastguard Worker TEST_P(PictureIdTest, IncreasingAfterRecreateStreamVp9) {
430*d9f75844SAndroid Build Coastguard Worker test::FunctionVideoEncoderFactory encoder_factory(
431*d9f75844SAndroid Build Coastguard Worker []() { return VP9Encoder::Create(); });
432*d9f75844SAndroid Build Coastguard Worker SetupEncoder(&encoder_factory, "VP9");
433*d9f75844SAndroid Build Coastguard Worker TestPictureIdIncreaseAfterRecreateStreams({1, 1});
434*d9f75844SAndroid Build Coastguard Worker }
435*d9f75844SAndroid Build Coastguard Worker
436*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
437