xref: /aosp_15_r20/external/webrtc/video/picture_id_tests.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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