Test picture sequence id when VideoSendStream is recreated.

Bug: webrtc:7475
Change-Id: I613b20b9da2c264b05c6a604d3f9754878857a0f
Reviewed-on: https://chromium-review.googlesource.com/527076
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#18722}
diff --git a/webrtc/video/BUILD.gn b/webrtc/video/BUILD.gn
index b5e8579..2204c74 100644
--- a/webrtc/video/BUILD.gn
+++ b/webrtc/video/BUILD.gn
@@ -241,6 +241,7 @@
       "end_to_end_tests.cc",
       "overuse_frame_detector_unittest.cc",
       "payload_router_unittest.cc",
+      "picture_id_tests.cc",
       "quality_threshold_unittest.cc",
       "receive_statistics_proxy_unittest.cc",
       "report_block_stats_unittest.cc",
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 68931ac..0d7662d 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -139,7 +139,6 @@
   void RespectsRtcpMode(RtcpMode rtcp_mode);
   void TestSendsSetSsrcs(size_t num_ssrcs, bool send_single_ssrc_first);
   void TestRtpStatePreservation(bool use_rtx, bool provoke_rtcpsr_before_rtp);
-  void TestPictureIdStatePreservation(VideoEncoder* encoder);
   void VerifyHistogramStats(bool use_rtx, bool use_red, bool screenshare);
   void VerifyNewVideoSendStreamsRespectNetworkState(
       MediaType network_to_bring_up,
@@ -3940,236 +3939,6 @@
   TestRtpStatePreservation(true, true);
 }
 
-void EndToEndTest::TestPictureIdStatePreservation(VideoEncoder* encoder) {
-  const size_t kFrameMaxWidth = 1280;
-  const size_t kFrameMaxHeight = 720;
-  const size_t kFrameRate = 30;
-
-  // Use a special stream factory in this test to ensure that all simulcast
-  // streams are being sent.
-  class VideoStreamFactory
-      : public VideoEncoderConfig::VideoStreamFactoryInterface {
-   public:
-    VideoStreamFactory() = default;
-
-   private:
-    std::vector<VideoStream> CreateEncoderStreams(
-        int width,
-        int height,
-        const VideoEncoderConfig& encoder_config) override {
-      std::vector<VideoStream> streams =
-          test::CreateVideoStreams(width, height, encoder_config);
-
-      const size_t kBitrate = 100000;
-
-      if (encoder_config.number_of_streams > 1) {
-        RTC_DCHECK_EQ(3, encoder_config.number_of_streams);
-
-        for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
-          streams[i].min_bitrate_bps = kBitrate;
-          streams[i].target_bitrate_bps = kBitrate;
-          streams[i].max_bitrate_bps = kBitrate;
-        }
-
-        // test::CreateVideoStreams does not return frame sizes for the lower
-        // streams that are accepted by VP8Impl::InitEncode.
-        // TODO(brandtr): Fix the problem in test::CreateVideoStreams, rather
-        // than overriding the values here.
-        streams[1].width = streams[2].width / 2;
-        streams[1].height = streams[2].height / 2;
-        streams[0].width = streams[1].width / 2;
-        streams[0].height = streams[1].height / 2;
-      } else {
-        // Use the same total bitrates when sending a single stream to avoid
-        // lowering the bitrate estimate and requiring a subsequent rampup.
-        streams[0].min_bitrate_bps = 3 * kBitrate;
-        streams[0].target_bitrate_bps = 3 * kBitrate;
-        streams[0].max_bitrate_bps = 3 * kBitrate;
-      }
-
-      return streams;
-    }
-  };
-
-  class PictureIdObserver : public test::RtpRtcpObserver {
-   public:
-    PictureIdObserver()
-        : test::RtpRtcpObserver(kDefaultTimeoutMs), num_ssrcs_to_observe_(1) {}
-
-    void ResetExpectations(size_t num_expected_ssrcs) {
-      rtc::CritScope lock(&crit_);
-      // Do not clear the timestamp and picture_id, to ensure that we check
-      // consistency between reinits and recreations.
-      num_packets_sent_.clear();
-      num_ssrcs_to_observe_ = num_expected_ssrcs;
-      ssrc_observed_.clear();
-    }
-
-   private:
-    Action OnSendRtp(const uint8_t* packet, size_t length) override {
-      rtc::CritScope lock(&crit_);
-
-      // RTP header.
-      RTPHeader header;
-      EXPECT_TRUE(parser_->Parse(packet, length, &header));
-      const uint32_t timestamp = header.timestamp;
-      const uint32_t ssrc = header.ssrc;
-
-      const bool known_ssrc =
-          (ssrc == kVideoSendSsrcs[0] || ssrc == kVideoSendSsrcs[1] ||
-           ssrc == kVideoSendSsrcs[2]);
-      EXPECT_TRUE(known_ssrc) << "Unknown SSRC sent.";
-
-      const bool is_padding =
-          (length == header.headerLength + header.paddingLength);
-      if (is_padding) {
-        return SEND_PACKET;
-      }
-
-      // VP8 header.
-      std::unique_ptr<RtpDepacketizer> depacketizer(
-          RtpDepacketizer::Create(kRtpVideoVp8));
-      RtpDepacketizer::ParsedPayload parsed_payload;
-      EXPECT_TRUE(depacketizer->Parse(
-          &parsed_payload, &packet[header.headerLength],
-          length - header.headerLength - header.paddingLength));
-      const uint16_t picture_id =
-          parsed_payload.type.Video.codecHeader.VP8.pictureId;
-
-      // If this is the first packet, we have nothing to compare to.
-      if (last_observed_timestamp_.find(ssrc) ==
-          last_observed_timestamp_.end()) {
-        last_observed_timestamp_[ssrc] = timestamp;
-        last_observed_picture_id_[ssrc] = picture_id;
-        ++num_packets_sent_[ssrc];
-
-        return SEND_PACKET;
-      }
-
-      // Verify continuity and monotonicity of picture_id sequence.
-      if (last_observed_timestamp_[ssrc] == timestamp) {
-        // Packet belongs to same frame as before.
-        EXPECT_EQ(last_observed_picture_id_[ssrc], picture_id);
-      } else {
-        // Packet is a new frame.
-        EXPECT_EQ((last_observed_picture_id_[ssrc] + 1) % (1 << 15),
-                  picture_id);
-      }
-      last_observed_timestamp_[ssrc] = timestamp;
-      last_observed_picture_id_[ssrc] = picture_id;
-
-      // Pass the test when enough media packets have been received
-      // on all streams.
-      if (++num_packets_sent_[ssrc] >= 10 && !ssrc_observed_[ssrc]) {
-        ssrc_observed_[ssrc] = true;
-        if (--num_ssrcs_to_observe_ == 0) {
-          observation_complete_.Set();
-        }
-      }
-
-      return SEND_PACKET;
-    }
-
-    rtc::CriticalSection crit_;
-    std::map<uint32_t, uint32_t> last_observed_timestamp_ GUARDED_BY(crit_);
-    std::map<uint32_t, uint16_t> last_observed_picture_id_ GUARDED_BY(crit_);
-    std::map<uint32_t, size_t> num_packets_sent_ GUARDED_BY(crit_);
-    size_t num_ssrcs_to_observe_ GUARDED_BY(crit_);
-    std::map<uint32_t, bool> ssrc_observed_ GUARDED_BY(crit_);
-  } observer;
-
-  Call::Config config(event_log_.get());
-  CreateCalls(config, config);
-
-  test::PacketTransport send_transport(
-      sender_call_.get(), &observer, test::PacketTransport::kSender,
-      payload_type_map_, FakeNetworkPipe::Config());
-  test::PacketTransport receive_transport(
-      nullptr, &observer, test::PacketTransport::kReceiver, payload_type_map_,
-      FakeNetworkPipe::Config());
-  send_transport.SetReceiver(receiver_call_->Receiver());
-  receive_transport.SetReceiver(sender_call_->Receiver());
-
-  CreateSendConfig(kNumSsrcs, 0, 0, &send_transport);
-  video_send_config_.encoder_settings.encoder = encoder;
-  video_send_config_.encoder_settings.payload_name = "VP8";
-  video_encoder_config_.video_stream_factory =
-      new rtc::RefCountedObject<VideoStreamFactory>();
-  video_encoder_config_.number_of_streams = 1;
-  CreateMatchingReceiveConfigs(&receive_transport);
-
-  CreateVideoStreams();
-  CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
-
-  auto reinit_encoder_and_test = [this, &observer](int num_expected_ssrcs) {
-    video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());
-    observer.ResetExpectations(num_expected_ssrcs);
-    EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
-  };
-
-  // TODO(brandtr): Add tests where we recreate the whole VideoSendStream. This
-  // requires synchronizing the frame generator output with the packetization
-  // output, to not have any timing-dependent gaps in the picture_id sequence.
-
-  // Initial test with a single stream.
-  Start();
-  EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
-
-  // Reinit the encoder and make sure the picture_id sequence is continuous.
-  reinit_encoder_and_test(1);
-
-  // Go up to three streams.
-  video_encoder_config_.number_of_streams = 3;
-  reinit_encoder_and_test(3);
-  reinit_encoder_and_test(3);
-
-  // Go back to one stream.
-  video_encoder_config_.number_of_streams = 1;
-  reinit_encoder_and_test(1);
-  reinit_encoder_and_test(1);
-
-  send_transport.StopSending();
-  receive_transport.StopSending();
-
-  Stop();
-  DestroyStreams();
-}
-
-TEST_F(EndToEndTest, PictureIdStateRetainedAfterReinitingVp8) {
-  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
-  TestPictureIdStatePreservation(encoder.get());
-}
-
-TEST_F(EndToEndTest,
-       PictureIdStateRetainedAfterReinitingSimulcastEncoderAdapter) {
-  class VideoEncoderFactoryAdapter : public webrtc::VideoEncoderFactory {
-   public:
-    explicit VideoEncoderFactoryAdapter(
-        cricket::WebRtcVideoEncoderFactory* factory)
-        : factory_(factory) {}
-    virtual ~VideoEncoderFactoryAdapter() {}
-
-    // Implements webrtc::VideoEncoderFactory.
-    webrtc::VideoEncoder* Create() override {
-      return factory_->CreateVideoEncoder(
-          cricket::VideoCodec(cricket::kVp8CodecName));
-    }
-
-    void Destroy(webrtc::VideoEncoder* encoder) override {
-      return factory_->DestroyVideoEncoder(encoder);
-    }
-
-   private:
-    cricket::WebRtcVideoEncoderFactory* const factory_;
-  };
-
-  cricket::InternalEncoderFactory internal_encoder_factory;
-  SimulcastEncoderAdapter simulcast_encoder_adapter(
-      new VideoEncoderFactoryAdapter(&internal_encoder_factory));
-
-  TestPictureIdStatePreservation(&simulcast_encoder_adapter);
-}
-
 // This test is flaky on linux_memcheck. Disable on all linux bots until
 // flakyness has been fixed.
 // https://bugs.chromium.org/p/webrtc/issues/detail?id=7737
diff --git a/webrtc/video/picture_id_tests.cc b/webrtc/video/picture_id_tests.cc
new file mode 100644
index 0000000..fe39a94
--- /dev/null
+++ b/webrtc/video/picture_id_tests.cc
@@ -0,0 +1,349 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "webrtc/media/engine/internalencoderfactory.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
+#include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
+#include "webrtc/modules/video_coding/sequence_number_util.h"
+#include "webrtc/test/call_test.h"
+
+namespace webrtc {
+
+const int kFrameMaxWidth = 1280;
+const int kFrameMaxHeight = 720;
+const int kFrameRate = 30;
+const int kMaxSecondsLost = 5;
+const int kMaxFramesLost = kFrameRate * kMaxSecondsLost;
+const int kMinPacketsToObserve = 10;
+const int kEncoderBitrateBps = 100000;
+const uint32_t kPictureIdWraparound = (1 << 15);
+
+class PictureIdObserver : public test::RtpRtcpObserver {
+ public:
+  PictureIdObserver()
+      : test::RtpRtcpObserver(test::CallTest::kDefaultTimeoutMs),
+        max_expected_picture_id_gap_(0),
+        num_ssrcs_to_observe_(1) {}
+
+  void SetExpectedSsrcs(size_t num_expected_ssrcs) {
+    rtc::CritScope lock(&crit_);
+    num_ssrcs_to_observe_ = num_expected_ssrcs;
+  }
+
+  void ResetObservedSsrcs() {
+    rtc::CritScope lock(&crit_);
+    // Do not clear the timestamp and picture_id, to ensure that we check
+    // consistency between reinits and recreations.
+    num_packets_sent_.clear();
+    observed_ssrcs_.clear();
+  }
+
+  void SetMaxExpectedPictureIdGap(int max_expected_picture_id_gap) {
+    rtc::CritScope lock(&crit_);
+    max_expected_picture_id_gap_ = max_expected_picture_id_gap;
+  }
+
+ private:
+  Action OnSendRtp(const uint8_t* packet, size_t length) override {
+    rtc::CritScope lock(&crit_);
+
+    // RTP header.
+    RTPHeader header;
+    EXPECT_TRUE(parser_->Parse(packet, length, &header));
+    const uint32_t timestamp = header.timestamp;
+    const uint32_t ssrc = header.ssrc;
+
+    const bool known_ssrc = (ssrc == test::CallTest::kVideoSendSsrcs[0] ||
+                             ssrc == test::CallTest::kVideoSendSsrcs[1] ||
+                             ssrc == test::CallTest::kVideoSendSsrcs[2]);
+    EXPECT_TRUE(known_ssrc) << "Unknown SSRC sent.";
+
+    const bool is_padding =
+        (length == header.headerLength + header.paddingLength);
+    if (is_padding) {
+      return SEND_PACKET;
+    }
+
+    // VP8 header.
+    std::unique_ptr<RtpDepacketizer> depacketizer(
+        RtpDepacketizer::Create(kRtpVideoVp8));
+    RtpDepacketizer::ParsedPayload parsed_payload;
+    EXPECT_TRUE(depacketizer->Parse(
+        &parsed_payload, &packet[header.headerLength],
+        length - header.headerLength - header.paddingLength));
+    const uint16_t picture_id =
+        parsed_payload.type.Video.codecHeader.VP8.pictureId;
+
+    // If this is the first packet, we have nothing to compare to.
+    if (last_observed_timestamp_.find(ssrc) == last_observed_timestamp_.end()) {
+      last_observed_timestamp_[ssrc] = timestamp;
+      last_observed_picture_id_[ssrc] = picture_id;
+      ++num_packets_sent_[ssrc];
+
+      return SEND_PACKET;
+    }
+
+    // Verify continuity and monotonicity of picture_id sequence.
+    if (last_observed_timestamp_[ssrc] == timestamp) {
+      // Packet belongs to same frame as before.
+      EXPECT_EQ(last_observed_picture_id_[ssrc], picture_id);
+    } else {
+      // Packet is a new frame.
+
+      // Picture id should be increasing.
+      const bool picture_id_is_increasing =
+          AheadOf<uint16_t, kPictureIdWraparound>(
+              picture_id, last_observed_picture_id_[ssrc]);
+      EXPECT_TRUE(picture_id_is_increasing);
+
+      // Picture id should not increase more than expected.
+      const int picture_id_diff = ForwardDiff<uint16_t, kPictureIdWraparound>(
+          last_observed_picture_id_[ssrc], picture_id);
+      EXPECT_LE(picture_id_diff - 1, max_expected_picture_id_gap_);
+    }
+    last_observed_timestamp_[ssrc] = timestamp;
+    last_observed_picture_id_[ssrc] = picture_id;
+
+    // Pass the test when enough media packets have been received
+    // on all streams.
+    if (++num_packets_sent_[ssrc] >= kMinPacketsToObserve &&
+        observed_ssrcs_.find(ssrc) == observed_ssrcs_.end()) {
+      observed_ssrcs_.insert(ssrc);
+      if (observed_ssrcs_.size() == num_ssrcs_to_observe_) {
+        observation_complete_.Set();
+      }
+    }
+
+    return SEND_PACKET;
+  }
+
+  rtc::CriticalSection crit_;
+  std::map<uint32_t, uint32_t> last_observed_timestamp_ GUARDED_BY(crit_);
+  std::map<uint32_t, uint16_t> last_observed_picture_id_ GUARDED_BY(crit_);
+  std::map<uint32_t, size_t> num_packets_sent_ GUARDED_BY(crit_);
+  int max_expected_picture_id_gap_ GUARDED_BY(crit_);
+  size_t num_ssrcs_to_observe_ GUARDED_BY(crit_);
+  std::set<uint32_t> observed_ssrcs_ GUARDED_BY(crit_);
+};
+
+class PictureIdTest : public test::CallTest {
+ public:
+  PictureIdTest() {}
+
+  virtual ~PictureIdTest() {
+    EXPECT_EQ(nullptr, video_send_stream_);
+    EXPECT_TRUE(video_receive_streams_.empty());
+  }
+
+  void SetupEncoder(VideoEncoder* encoder);
+  void TestPictureIdContinuousAfterReconfigure(
+      const std::vector<int>& ssrc_counts);
+  void TestPictureIdIncreaseAfterRecreateStreams(
+      const std::vector<int>& ssrc_counts);
+
+ private:
+  PictureIdObserver observer;
+};
+
+// Use a special stream factory to ensure that all simulcast streams are being
+// sent.
+class VideoStreamFactory
+    : public VideoEncoderConfig::VideoStreamFactoryInterface {
+ public:
+  VideoStreamFactory() = default;
+
+ private:
+  std::vector<VideoStream> CreateEncoderStreams(
+      int width,
+      int height,
+      const VideoEncoderConfig& encoder_config) override {
+    std::vector<VideoStream> streams =
+        test::CreateVideoStreams(width, height, encoder_config);
+
+    if (encoder_config.number_of_streams > 1) {
+      RTC_DCHECK_EQ(3, encoder_config.number_of_streams);
+
+      for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
+        streams[i].min_bitrate_bps = kEncoderBitrateBps;
+        streams[i].target_bitrate_bps = kEncoderBitrateBps;
+        streams[i].max_bitrate_bps = kEncoderBitrateBps;
+      }
+
+      // test::CreateVideoStreams does not return frame sizes for the lower
+      // streams that are accepted by VP8Impl::InitEncode.
+      // TODO(brandtr): Fix the problem in test::CreateVideoStreams, rather
+      // than overriding the values here.
+      streams[1].width = streams[2].width / 2;
+      streams[1].height = streams[2].height / 2;
+      streams[0].width = streams[1].width / 2;
+      streams[0].height = streams[1].height / 2;
+    } else {
+      // Use the same total bitrates when sending a single stream to avoid
+      // lowering the bitrate estimate and requiring a subsequent rampup.
+      streams[0].min_bitrate_bps = 3 * kEncoderBitrateBps;
+      streams[0].target_bitrate_bps = 3 * kEncoderBitrateBps;
+      streams[0].max_bitrate_bps = 3 * kEncoderBitrateBps;
+    }
+
+    return streams;
+  }
+};
+
+void PictureIdTest::SetupEncoder(VideoEncoder* encoder) {
+  Call::Config config(event_log_.get());
+  CreateCalls(config, config);
+
+  send_transport_.reset(new test::PacketTransport(
+      sender_call_.get(), &observer, test::PacketTransport::kSender,
+      payload_type_map_, FakeNetworkPipe::Config()));
+
+  CreateSendConfig(kNumSsrcs, 0, 0, send_transport_.get());
+  video_send_config_.encoder_settings.encoder = encoder;
+  video_send_config_.encoder_settings.payload_name = "VP8";
+  video_encoder_config_.video_stream_factory =
+      new rtc::RefCountedObject<VideoStreamFactory>();
+  video_encoder_config_.number_of_streams = 1;
+}
+
+void PictureIdTest::TestPictureIdContinuousAfterReconfigure(
+    const std::vector<int>& ssrc_counts) {
+  CreateVideoStreams();
+  CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
+
+  // Initial test with a single stream.
+  Start();
+  EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+
+  // Reconfigure VideoEncoder and test picture id increase.
+  // Expect continously increasing picture id, equivalent to no gaps.
+  observer.SetMaxExpectedPictureIdGap(0);
+  for (int ssrc_count : ssrc_counts) {
+    video_encoder_config_.number_of_streams = ssrc_count;
+    observer.SetExpectedSsrcs(ssrc_count);
+    observer.ResetObservedSsrcs();
+    // Make sure the picture_id sequence is continuous on reinit and recreate.
+    video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());
+    EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+  }
+
+  Stop();
+  DestroyStreams();
+}
+
+void PictureIdTest::TestPictureIdIncreaseAfterRecreateStreams(
+    const std::vector<int>& ssrc_counts) {
+  CreateVideoStreams();
+  CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
+
+  // Initial test with a single stream.
+  Start();
+  EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+
+  // Recreate VideoSendStream and test picture id increase.
+  // When the VideoSendStream is destroyed, any frames still in queue is lost
+  // with it, therefore it is expected that some frames might be lost.
+  observer.SetMaxExpectedPictureIdGap(kMaxFramesLost);
+  for (int ssrc_count : ssrc_counts) {
+    video_encoder_config_.number_of_streams = ssrc_count;
+
+    frame_generator_capturer_->Stop();
+    sender_call_->DestroyVideoSendStream(video_send_stream_);
+
+    observer.SetExpectedSsrcs(ssrc_count);
+    observer.ResetObservedSsrcs();
+
+    video_send_stream_ = sender_call_->CreateVideoSendStream(
+        video_send_config_.Copy(), video_encoder_config_.Copy());
+    video_send_stream_->Start();
+    CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
+    frame_generator_capturer_->Start();
+    EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+  }
+
+  Stop();
+  DestroyStreams();
+}
+
+TEST_F(PictureIdTest, PictureIdContinuousAfterReconfigureVp8) {
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  SetupEncoder(encoder.get());
+  TestPictureIdContinuousAfterReconfigure({1, 3, 3, 1, 1});
+}
+
+TEST_F(PictureIdTest, PictureIdIncreasingAfterRecreateStreamVp8) {
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  SetupEncoder(encoder.get());
+  TestPictureIdIncreaseAfterRecreateStreams({1, 3, 3, 1, 1});
+}
+
+TEST_F(PictureIdTest, PictureIdIncreasingAfterStreamCountChangeVp8) {
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  // Make sure that that the picture id is not reset if the stream count goes
+  // down and then up.
+  std::vector<int> ssrc_counts = {3, 1, 3};
+  SetupEncoder(encoder.get());
+  TestPictureIdContinuousAfterReconfigure(ssrc_counts);
+}
+
+class VideoEncoderFactoryAdapter : public webrtc::VideoEncoderFactory {
+ public:
+  explicit VideoEncoderFactoryAdapter(
+      cricket::WebRtcVideoEncoderFactory* factory)
+      : factory_(factory) {}
+  virtual ~VideoEncoderFactoryAdapter() {}
+
+  // Implements webrtc::VideoEncoderFactory.
+  webrtc::VideoEncoder* Create() override {
+    return factory_->CreateVideoEncoder(
+        cricket::VideoCodec(cricket::kVp8CodecName));
+  }
+
+  void Destroy(webrtc::VideoEncoder* encoder) override {
+    return factory_->DestroyVideoEncoder(encoder);
+  }
+
+ private:
+  cricket::WebRtcVideoEncoderFactory* const factory_;
+};
+
+TEST_F(PictureIdTest,
+       PictureIdContinuousAfterReconfigureSimulcastEncoderAdapter) {
+  cricket::InternalEncoderFactory internal_encoder_factory;
+  SimulcastEncoderAdapter simulcast_encoder_adapter(
+      new VideoEncoderFactoryAdapter(&internal_encoder_factory));
+  SetupEncoder(&simulcast_encoder_adapter);
+  TestPictureIdContinuousAfterReconfigure({1, 3, 3, 1, 1});
+}
+
+TEST_F(PictureIdTest,
+       PictureIdIncreasingAfterRecreateStreamSimulcastEncoderAdapter) {
+  cricket::InternalEncoderFactory internal_encoder_factory;
+  SimulcastEncoderAdapter simulcast_encoder_adapter(
+      new VideoEncoderFactoryAdapter(&internal_encoder_factory));
+  SetupEncoder(&simulcast_encoder_adapter);
+  TestPictureIdIncreaseAfterRecreateStreams({1, 3, 3, 1, 1});
+}
+
+// When using the simulcast encoder adapter, the picture id is randomly set
+// when the ssrc count is reduced and then increased. This means that we are
+// not spec compliant in that particular case.
+TEST_F(
+    PictureIdTest,
+    DISABLED_PictureIdIncreasingAfterStreamCountChangeSimulcastEncoderAdapter) {
+  cricket::InternalEncoderFactory internal_encoder_factory;
+  SimulcastEncoderAdapter simulcast_encoder_adapter(
+      new VideoEncoderFactoryAdapter(&internal_encoder_factory));
+  // Make sure that that the picture id is not reset if the stream count goes
+  // down and then up.
+  std::vector<int> ssrc_counts = {3, 1, 3};
+  SetupEncoder(&simulcast_encoder_adapter);
+  TestPictureIdContinuousAfterReconfigure(ssrc_counts);
+}
+
+}  // namespace webrtc