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