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