PictureIdTest: Add test for VP9.
Bug: none
Change-Id: Ib75dc488fd2f79a06ecf15f7794a2a20cf2d1324
Reviewed-on: https://webrtc-review.googlesource.com/26500
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20935}diff --git a/video/picture_id_tests.cc b/video/picture_id_tests.cc
index f1545d8..1aced65 100644
--- a/video/picture_id_tests.cc
+++ b/video/picture_id_tests.cc
@@ -10,6 +10,7 @@
#include "media/engine/internalencoderfactory.h"
#include "media/engine/simulcast_encoder_adapter.h"
#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "modules/video_coding/codecs/vp9/include/vp9.h"
#include "rtc_base/numerics/sequence_number_util.h"
#include "test/call_test.h"
#include "test/field_trial.h"
@@ -27,12 +28,25 @@
const char kVp8ForcedFallbackEncoderEnabled[] =
"WebRTC-VP8-Forced-Fallback-Encoder-v2/Enabled/";
+
+RtpVideoCodecTypes PayloadNameToRtpVideoCodecType(
+ const std::string& payload_name) {
+ if (payload_name == "VP8") {
+ return kRtpVideoVp8;
+ } else if (payload_name == "VP9") {
+ return kRtpVideoVp9;
+ } else {
+ RTC_NOTREACHED();
+ return kRtpVideoNone;
+ }
+}
} // namespace
class PictureIdObserver : public test::RtpRtcpObserver {
public:
- PictureIdObserver()
+ explicit PictureIdObserver(RtpVideoCodecTypes codec_type)
: test::RtpRtcpObserver(test::CallTest::kDefaultTimeoutMs),
+ codec_type_(codec_type),
max_expected_picture_id_gap_(0),
num_ssrcs_to_observe_(1) {}
@@ -55,78 +69,100 @@
}
private:
+ // TODO(asapersson): Add test for tl0_pic_idx.
+ struct ParsedPacket {
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint16_t picture_id;
+ FrameType frame_type;
+ };
+
+ bool ParsePayload(const uint8_t* packet,
+ size_t length,
+ ParsedPacket* parsed) {
+ RTPHeader header;
+ EXPECT_TRUE(parser_->Parse(packet, length, &header));
+ EXPECT_TRUE(header.ssrc == test::CallTest::kVideoSendSsrcs[0] ||
+ header.ssrc == test::CallTest::kVideoSendSsrcs[1] ||
+ header.ssrc == test::CallTest::kVideoSendSsrcs[2])
+ << "Unknown SSRC sent.";
+
+ EXPECT_GE(length, header.headerLength + header.paddingLength);
+ size_t payload_length = length - header.headerLength - header.paddingLength;
+ if (payload_length == 0) {
+ return false; // Padding packet.
+ }
+
+ parsed->ssrc = header.ssrc;
+ parsed->timestamp = header.timestamp;
+
+ std::unique_ptr<RtpDepacketizer> depacketizer(
+ RtpDepacketizer::Create(codec_type_));
+ RtpDepacketizer::ParsedPayload parsed_payload;
+ EXPECT_TRUE(depacketizer->Parse(
+ &parsed_payload, &packet[header.headerLength], payload_length));
+
+ switch (codec_type_) {
+ case kRtpVideoVp8:
+ parsed->picture_id =
+ parsed_payload.type.Video.codecHeader.VP8.pictureId;
+ break;
+ case kRtpVideoVp9:
+ parsed->picture_id =
+ parsed_payload.type.Video.codecHeader.VP9.picture_id;
+ break;
+ default:
+ RTC_NOTREACHED();
+ break;
+ }
+
+ parsed->frame_type = parsed_payload.frame_type;
+ return true;
+ }
+
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) {
+ ParsedPacket parsed;
+ if (!ParsePayload(packet, length, &parsed)) {
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;
+ uint32_t ssrc = parsed.ssrc;
+ if (last_observed_packet_.find(ssrc) != last_observed_packet_.end()) {
+ // Verify continuity and monotonicity of picture_id sequence.
+ // Compare to last packet.
+ if (last_observed_packet_[ssrc].timestamp == parsed.timestamp) {
+ // Packet belongs to same frame as before.
+ EXPECT_EQ(last_observed_packet_[ssrc].picture_id, parsed.picture_id);
+ } else {
+ // Packet belongs to a new frame.
- // 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];
+ // Picture id should be increasing.
+ EXPECT_TRUE((AheadOf<uint16_t, kPictureIdWraparound>(
+ parsed.picture_id, last_observed_packet_[ssrc].picture_id)));
- return SEND_PACKET;
- }
+ // Picture id should not increase more than expected.
+ const int picture_id_diff = ForwardDiff<uint16_t, kPictureIdWraparound>(
+ last_observed_packet_[ssrc].picture_id, parsed.picture_id);
- // 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);
-
- // For delta frames, expect continuously increasing picture id.
- if (parsed_payload.frame_type != kVideoFrameKey) {
- EXPECT_EQ(picture_id_diff, 1);
- }
- // Any frames still in queue is lost when a VideoSendStream is destroyed.
- // The first frame after recreation should be a key frame.
- if (picture_id_diff > 1) {
- EXPECT_EQ(kVideoFrameKey, parsed_payload.frame_type);
- EXPECT_LE(picture_id_diff - 1, max_expected_picture_id_gap_);
+ // For delta frames, expect continuously increasing picture id.
+ if (parsed.frame_type != kVideoFrameKey) {
+ EXPECT_EQ(picture_id_diff, 1);
+ }
+ // Any frames still in queue is lost when a VideoSendStream is
+ // destroyed. The first frame after recreation should be a key frame.
+ if (picture_id_diff > 1) {
+ EXPECT_EQ(kVideoFrameKey, parsed.frame_type);
+ 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.
+ last_observed_packet_[ssrc] = parsed;
+
+ // 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);
@@ -134,13 +170,12 @@
observation_complete_.Set();
}
}
-
return SEND_PACKET;
}
rtc::CriticalSection crit_;
- std::map<uint32_t, uint32_t> last_observed_timestamp_ RTC_GUARDED_BY(crit_);
- std::map<uint32_t, uint16_t> last_observed_picture_id_ RTC_GUARDED_BY(crit_);
+ const RtpVideoCodecTypes codec_type_;
+ std::map<uint32_t, ParsedPacket> last_observed_packet_ RTC_GUARDED_BY(crit_);
std::map<uint32_t, size_t> num_packets_sent_ RTC_GUARDED_BY(crit_);
int max_expected_picture_id_gap_ RTC_GUARDED_BY(crit_);
size_t num_ssrcs_to_observe_ RTC_GUARDED_BY(crit_);
@@ -165,7 +200,7 @@
});
}
- void SetupEncoder(VideoEncoder* encoder);
+ void SetupEncoder(VideoEncoder* encoder, const std::string& payload_name);
void TestPictureIdContinuousAfterReconfigure(
const std::vector<int>& ssrc_counts);
void TestPictureIdIncreaseAfterRecreateStreams(
@@ -173,7 +208,7 @@
private:
test::ScopedFieldTrials scoped_field_trial_;
- PictureIdObserver observer;
+ std::unique_ptr<PictureIdObserver> observer_;
};
INSTANTIATE_TEST_CASE_P(TestWithForcedFallbackEncoderEnabled,
@@ -225,19 +260,23 @@
}
};
-void PictureIdTest::SetupEncoder(VideoEncoder* encoder) {
- task_queue_.SendTask([this, &encoder]() {
+void PictureIdTest::SetupEncoder(VideoEncoder* encoder,
+ const std::string& payload_name) {
+ observer_.reset(
+ new PictureIdObserver(PayloadNameToRtpVideoCodecType(payload_name)));
+
+ task_queue_.SendTask([this, &encoder, payload_name]() {
Call::Config config(event_log_.get());
CreateCalls(config, config);
send_transport_.reset(new test::PacketTransport(
- &task_queue_, sender_call_.get(), &observer,
+ &task_queue_, sender_call_.get(), observer_.get(),
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_send_config_.encoder_settings.payload_name = payload_name;
video_encoder_config_.video_stream_factory =
new rtc::RefCountedObject<VideoStreamFactory>();
video_encoder_config_.number_of_streams = 1;
@@ -254,20 +293,20 @@
Start();
});
- EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+ EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
// Reconfigure VideoEncoder and test picture id increase.
// Expect continuously increasing picture id, equivalent to no gaps.
- observer.SetMaxExpectedPictureIdGap(0);
+ observer_->SetMaxExpectedPictureIdGap(0);
for (int ssrc_count : ssrc_counts) {
video_encoder_config_.number_of_streams = ssrc_count;
- observer.SetExpectedSsrcs(ssrc_count);
- observer.ResetObservedSsrcs();
+ observer_->SetExpectedSsrcs(ssrc_count);
+ observer_->ResetObservedSsrcs();
// Make sure the picture_id sequence is continuous on reinit and recreate.
task_queue_.SendTask([this]() {
video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());
});
- EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+ EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
}
task_queue_.SendTask([this]() {
@@ -289,21 +328,20 @@
Start();
});
- EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+ 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);
+ observer_->SetMaxExpectedPictureIdGap(kMaxFramesLost);
for (int ssrc_count : ssrc_counts) {
task_queue_.SendTask([this, &ssrc_count]() {
- 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_encoder_config_.number_of_streams = ssrc_count;
+ observer_->SetExpectedSsrcs(ssrc_count);
+ observer_->ResetObservedSsrcs();
video_send_stream_ = sender_call_->CreateVideoSendStream(
video_send_config_.Copy(), video_encoder_config_.Copy());
@@ -312,7 +350,7 @@
frame_generator_capturer_->Start();
});
- EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
+ EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
}
task_queue_.SendTask([this]() {
@@ -323,48 +361,44 @@
});
}
-TEST_P(PictureIdTest, PictureIdContinuousAfterReconfigureVp8) {
+TEST_P(PictureIdTest, ContinuousAfterReconfigureVp8) {
std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
- SetupEncoder(encoder.get());
+ SetupEncoder(encoder.get(), "VP8");
TestPictureIdContinuousAfterReconfigure({1, 3, 3, 1, 1});
}
-TEST_P(PictureIdTest, PictureIdIncreasingAfterRecreateStreamVp8) {
+TEST_P(PictureIdTest, IncreasingAfterRecreateStreamVp8) {
std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
- SetupEncoder(encoder.get());
+ SetupEncoder(encoder.get(), "VP8");
TestPictureIdIncreaseAfterRecreateStreams({1, 3, 3, 1, 1});
}
-TEST_P(PictureIdTest, PictureIdIncreasingAfterStreamCountChangeVp8) {
+TEST_P(PictureIdTest, ContinuousAfterStreamCountChangeVp8) {
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);
+ SetupEncoder(encoder.get(), "VP8");
+ TestPictureIdContinuousAfterReconfigure({3, 1, 3});
}
-TEST_P(PictureIdTest,
- PictureIdContinuousAfterReconfigureSimulcastEncoderAdapter) {
+TEST_P(PictureIdTest, ContinuousAfterReconfigureSimulcastEncoderAdapter) {
InternalEncoderFactory internal_encoder_factory;
SimulcastEncoderAdapter simulcast_encoder_adapter(&internal_encoder_factory);
- SetupEncoder(&simulcast_encoder_adapter);
+ SetupEncoder(&simulcast_encoder_adapter, "VP8");
TestPictureIdContinuousAfterReconfigure({1, 3, 3, 1, 1});
}
-TEST_P(PictureIdTest,
- PictureIdIncreasingAfterRecreateStreamSimulcastEncoderAdapter) {
+TEST_P(PictureIdTest, IncreasingAfterRecreateStreamSimulcastEncoderAdapter) {
InternalEncoderFactory internal_encoder_factory;
SimulcastEncoderAdapter simulcast_encoder_adapter(&internal_encoder_factory);
- SetupEncoder(&simulcast_encoder_adapter);
+ SetupEncoder(&simulcast_encoder_adapter, "VP8");
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_P(PictureIdTest,
- PictureIdIncreasingAfterStreamCountChangeSimulcastEncoderAdapter) {
+TEST_P(PictureIdTest, ContinuousAfterStreamCountChangeSimulcastEncoderAdapter) {
// If forced fallback is enabled, the picture id is set in the PayloadRouter
// and the sequence should be continuous.
if (GetParam() == kVp8ForcedFallbackEncoderEnabled) {
@@ -373,10 +407,15 @@
&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);
+ SetupEncoder(&simulcast_encoder_adapter, "VP8");
+ TestPictureIdContinuousAfterReconfigure({3, 1, 3});
}
}
+TEST_P(PictureIdTest, IncreasingAfterRecreateStreamVp9) {
+ std::unique_ptr<VideoEncoder> encoder(VP9Encoder::Create());
+ SetupEncoder(encoder.get(), "VP9");
+ TestPictureIdIncreaseAfterRecreateStreams({1, 1});
+}
+
} // namespace webrtc