Added VP8 simulcast tests. Fixed analyzer to correctly infer timestamps.

BUG=webrtc:7095

Review-Url: https://codereview.webrtc.org/2668763004
Cr-Commit-Position: refs/heads/master@{#16428}
diff --git a/webrtc/common_video/include/frame_callback.h b/webrtc/common_video/include/frame_callback.h
index 81737c6..0fa4458 100644
--- a/webrtc/common_video/include/frame_callback.h
+++ b/webrtc/common_video/include/frame_callback.h
@@ -22,13 +22,32 @@
 
 struct EncodedFrame {
  public:
-  EncodedFrame() : data_(NULL), length_(0), frame_type_(kEmptyFrame) {}
-  EncodedFrame(const uint8_t* data, size_t length, FrameType frame_type)
-    : data_(data), length_(length), frame_type_(frame_type) {}
+  EncodedFrame()
+      : data_(nullptr),
+        length_(0),
+        frame_type_(kEmptyFrame),
+        encoded_width_(0),
+        encoded_height_(0),
+        timestamp_(0) {}
+  EncodedFrame(const uint8_t* data,
+               size_t length,
+               FrameType frame_type,
+               uint32_t encoded_width,
+               uint32_t encoded_height,
+               uint32_t timestamp)
+      : data_(data),
+        length_(length),
+        frame_type_(frame_type),
+        encoded_width_(encoded_width),
+        encoded_height_(encoded_height),
+        timestamp_(timestamp) {}
 
   const uint8_t* data_;
   const size_t length_;
   const FrameType frame_type_;
+  const uint32_t encoded_width_;
+  const uint32_t encoded_height_;
+  const uint32_t timestamp_;
 };
 
 class I420FrameCallback {
diff --git a/webrtc/video/full_stack_tests.cc b/webrtc/video/full_stack_tests.cc
index f1d1150..fba5550 100644
--- a/webrtc/video/full_stack_tests.cc
+++ b/webrtc/video/full_stack_tests.cc
@@ -345,4 +345,115 @@
 }
 #endif  // !defined(RTC_DISABLE_VP9)
 
+TEST_F(FullStackTest, SimulcastVP8_3SL_High) {
+  VideoQualityTest::Params simulcast;
+  simulcast.call.send_side_bwe = true;
+  simulcast.video = {true,   1280,    720,     50,
+                     800000, 2500000, 2500000, false,
+                     "VP8",  1,       0,       400000,
+                     false,  false,   "",      "ConferenceMotion_1280_720_50"};
+  simulcast.analyzer = {"simulcast_vp8_3sl_demo", 0.0, 0.0,
+                        kFullStackTestDurationSecs};
+  simulcast.pipe.loss_percent = 0;
+  simulcast.pipe.queue_delay_ms = 100;
+  VideoQualityTest::Params video_params_high;
+  video_params_high.video = {
+      true,   1280,    720,     50,
+      800000, 2500000, 2500000, false,
+      "VP8",  1,       0,       400000,
+      false,  false,   "",      "ConferenceMotion_1280_720_50"};
+  VideoQualityTest::Params video_params_medium;
+  video_params_medium.video = {
+      true,   640,    360,    50,
+      150000, 500000, 700000, false,
+      "VP8",  1,      0,      400000,
+      false,  false,  "",     "ConferenceMotion_1280_720_50"};
+  VideoQualityTest::Params video_params_low;
+  video_params_low.video = {
+      true,  320,    180,    50,
+      30000, 150000, 200000, false,
+      "VP8", 1,      0,      400000,
+      false, false,  "",     "ConferenceMotion_1280_720_50"};
+
+  std::vector<VideoStream> streams = {DefaultVideoStream(video_params_low),
+                                      DefaultVideoStream(video_params_medium),
+                                      DefaultVideoStream(video_params_high)};
+  simulcast.ss = {streams, 2, 1, 0};
+  RunTest(simulcast);
+}
+
+TEST_F(FullStackTest, SimulcastVP8_3SL_Medium) {
+  VideoQualityTest::Params simulcast;
+  simulcast.call.send_side_bwe = true;
+  simulcast.video = {true,   1280,    720,     50,
+                     800000, 2500000, 2500000, false,
+                     "VP8",  1,       0,       400000,
+                     false,  false,   "",      "ConferenceMotion_1280_720_50"};
+  simulcast.analyzer = {"simulcast_vp8_3sl_demo", 0.0, 0.0,
+                        kFullStackTestDurationSecs};
+  simulcast.pipe.loss_percent = 0;
+  simulcast.pipe.queue_delay_ms = 100;
+  VideoQualityTest::Params video_params_high;
+  video_params_high.video = {
+      true,   1280,    720,     50,
+      800000, 2500000, 2500000, false,
+      "VP8",  1,       0,       400000,
+      false,  false,   "",      "ConferenceMotion_1280_720_50"};
+  VideoQualityTest::Params video_params_medium;
+  video_params_medium.video = {
+      true,   640,    360,    50,
+      150000, 500000, 700000, false,
+      "VP8",  1,      0,      400000,
+      false,  false,  "",     "ConferenceMotion_1280_720_50"};
+  VideoQualityTest::Params video_params_low;
+  video_params_low.video = {
+      true,  320,    180,    50,
+      30000, 150000, 200000, false,
+      "VP8", 1,      0,      400000,
+      false, false,  "",     "ConferenceMotion_1280_720_50"};
+
+  std::vector<VideoStream> streams = {DefaultVideoStream(video_params_low),
+                                      DefaultVideoStream(video_params_medium),
+                                      DefaultVideoStream(video_params_high)};
+  simulcast.ss = {streams, 1, 1, 0};
+  RunTest(simulcast);
+}
+
+TEST_F(FullStackTest, SimulcastVP8_3SL_Low) {
+  VideoQualityTest::Params simulcast;
+  simulcast.call.send_side_bwe = true;
+  simulcast.video = {true,   1280,    720,     50,
+                     800000, 2500000, 2500000, false,
+                     "VP8",  1,       0,       400000,
+                     false,  false,   "",      "ConferenceMotion_1280_720_50"};
+  simulcast.analyzer = {"simulcast_vp8_3sl_demo", 0.0, 0.0,
+                        kFullStackTestDurationSecs};
+  simulcast.pipe.loss_percent = 0;
+  simulcast.pipe.queue_delay_ms = 100;
+  VideoQualityTest::Params video_params_high;
+  video_params_high.video = {
+      true,   1280,    720,     50,
+      800000, 2500000, 2500000, false,
+      "VP8",  1,       0,       400000,
+      false,  false,   "",      "ConferenceMotion_1280_720_50"};
+  VideoQualityTest::Params video_params_medium;
+  video_params_medium.video = {
+      true,   640,    360,    50,
+      150000, 500000, 700000, false,
+      "VP8",  1,      0,      400000,
+      false,  false,  "",     "ConferenceMotion_1280_720_50"};
+  VideoQualityTest::Params video_params_low;
+  video_params_low.video = {
+      true,  320,    180,    50,
+      30000, 150000, 200000, false,
+      "VP8", 1,      0,      400000,
+      false, false,  "",     "ConferenceMotion_1280_720_50"};
+
+  std::vector<VideoStream> streams = {DefaultVideoStream(video_params_low),
+                                      DefaultVideoStream(video_params_medium),
+                                      DefaultVideoStream(video_params_high)};
+  simulcast.ss = {streams, 0, 1, 0};
+  RunTest(simulcast);
+}
+
 }  // namespace webrtc
diff --git a/webrtc/video/video_quality_test.cc b/webrtc/video/video_quality_test.cc
index c1e0786..a419195 100644
--- a/webrtc/video/video_quality_test.cc
+++ b/webrtc/video/video_quality_test.cc
@@ -133,7 +133,9 @@
                 int duration_frames,
                 FILE* graph_data_output_file,
                 const std::string& graph_title,
-                uint32_t ssrc_to_analyze)
+                uint32_t ssrc_to_analyze,
+                uint32_t selected_width,
+                uint32_t selected_height)
       : transport_(transport),
         receiver_(nullptr),
         send_stream_(nullptr),
@@ -143,6 +145,8 @@
         graph_data_output_file_(graph_data_output_file),
         graph_title_(graph_title),
         ssrc_to_analyze_(ssrc_to_analyze),
+        selected_width_(selected_width),
+        selected_height_(selected_height),
         pre_encode_proxy_(this),
         encode_timing_proxy_(this),
         frames_to_process_(duration_frames),
@@ -226,10 +230,11 @@
     RtpUtility::RtpHeaderParser parser(packet, length);
     RTPHeader header;
     parser.Parse(&header);
-    if (!IsFlexfec(header.payloadType)) {
+    if (!IsFlexfec(header.payloadType) && header.ssrc != ssrc_to_analyze_) {
       // Ignore FlexFEC timestamps, to avoid collisions with media timestamps.
       // (FlexFEC and media are sent on different SSRCs, which have different
       // timestamps spaces.)
+      // Also ignore packets from wrong SSRC.
       rtc::CritScope lock(&crit_);
       int64_t timestamp =
           wrap_handler_.Unwrap(header.timestamp - rtp_timestamp_delta_);
@@ -247,13 +252,23 @@
 
   void PreEncodeOnFrame(const VideoFrame& video_frame) {
     rtc::CritScope lock(&crit_);
-    if (!first_send_timestamp_ && rtp_timestamp_delta_ == 0) {
+    if (!first_encoded_timestamp_) {
       while (frames_.front().timestamp() != video_frame.timestamp()) {
         ++dropped_frames_before_first_encode_;
         frames_.pop_front();
         RTC_CHECK(!frames_.empty());
       }
-      first_send_timestamp_ = rtc::Optional<uint32_t>(video_frame.timestamp());
+      first_encoded_timestamp_ =
+          rtc::Optional<uint32_t>(video_frame.timestamp());
+    }
+  }
+
+  void PostEncodeFrameCallback(const EncodedFrame& encoded_frame) {
+    rtc::CritScope lock(&crit_);
+    if (!first_sent_timestamp_ &&
+        encoded_frame.encoded_width_ == selected_width_ &&
+        encoded_frame.encoded_height_ == selected_height_) {
+      first_sent_timestamp_ = rtc::Optional<uint32_t>(encoded_frame.timestamp_);
     }
   }
 
@@ -269,15 +284,15 @@
     bool result = transport_->SendRtp(packet, length, options);
     {
       rtc::CritScope lock(&crit_);
-
-      if (rtp_timestamp_delta_ == 0) {
-        rtp_timestamp_delta_ = header.timestamp - *first_send_timestamp_;
-        first_send_timestamp_ = rtc::Optional<uint32_t>();
+      if (rtp_timestamp_delta_ == 0 && header.ssrc == ssrc_to_analyze_) {
+        rtp_timestamp_delta_ = header.timestamp - *first_sent_timestamp_;
       }
-      if (!IsFlexfec(header.payloadType)) {
+
+      if (!IsFlexfec(header.payloadType) && header.ssrc == ssrc_to_analyze_) {
         // Ignore FlexFEC timestamps, to avoid collisions with media timestamps.
         // (FlexFEC and media are sent on different SSRCs, which have different
         // timestamps spaces.)
+        // Also ignore packets from wrong SSRC.
         int64_t timestamp =
             wrap_handler_.Unwrap(header.timestamp - rtp_timestamp_delta_);
         send_times_[timestamp] = current_time;
@@ -477,7 +492,9 @@
     void OnEncodeTiming(int64_t ntp_time_ms, int encode_time_ms) override {
       parent_->MeasuredEncodeTiming(ntp_time_ms, encode_time_ms);
     }
-    void EncodedFrameCallback(const EncodedFrame& frame) override {}
+    void EncodedFrameCallback(const EncodedFrame& frame) override {
+      parent_->PostEncodeFrameCallback(frame);
+    }
 
    private:
     VideoAnalyzer* const parent_;
@@ -787,9 +804,11 @@
    private:
     void OnFrame(const VideoFrame& video_frame) override {
       VideoFrame copy = video_frame;
+      // Frames from the capturer does not have a rtp timestamp.
+      // Create one so it can be used for comparison.
+      RTC_DCHECK_EQ(0, video_frame.timestamp());
       copy.set_timestamp(copy.ntp_time_ms() * 90);
-
-      analyzer_->AddCapturedFrameForComparison(video_frame);
+      analyzer_->AddCapturedFrameForComparison(copy);
       rtc::CritScope lock(&crit_);
       if (send_stream_input_)
         send_stream_input_->OnFrame(video_frame);
@@ -817,12 +836,7 @@
 
   void AddCapturedFrameForComparison(const VideoFrame& video_frame) {
     rtc::CritScope lock(&crit_);
-    RTC_DCHECK_EQ(0, video_frame.timestamp());
-    // Frames from the capturer does not have a rtp timestamp. Create one so it
-    // can be used for comparison.
-    VideoFrame copy = video_frame;
-    copy.set_timestamp(copy.ntp_time_ms() * 90);
-    frames_.push_back(copy);
+    frames_.push_back(video_frame);
   }
 
   VideoSendStream* send_stream_;
@@ -832,6 +846,8 @@
   FILE* const graph_data_output_file_;
   const std::string graph_title_;
   const uint32_t ssrc_to_analyze_;
+  const uint32_t selected_width_;
+  const uint32_t selected_height_;
   PreEncodeProxy pre_encode_proxy_;
   OnEncodeTimingProxy encode_timing_proxy_;
   std::vector<Sample> samples_ GUARDED_BY(comparison_lock_);
@@ -866,7 +882,8 @@
   std::map<int64_t, int64_t> send_times_ GUARDED_BY(crit_);
   std::map<int64_t, int64_t> recv_times_ GUARDED_BY(crit_);
   std::map<int64_t, size_t> encoded_frame_sizes_ GUARDED_BY(crit_);
-  rtc::Optional<uint32_t> first_send_timestamp_ GUARDED_BY(crit_);
+  rtc::Optional<uint32_t> first_encoded_timestamp_ GUARDED_BY(crit_);
+  rtc::Optional<uint32_t> first_sent_timestamp_ GUARDED_BY(crit_);
   const double avg_psnr_threshold_;
   const double avg_ssim_threshold_;
 
@@ -1310,7 +1327,7 @@
   if (disable_quality_check) {
     fprintf(stderr,
             "Warning: Calculating PSNR and SSIM for downsized resolution "
-            "not implemented yet! Skipping PSNR and SSIM calculations!");
+            "not implemented yet! Skipping PSNR and SSIM calculations!\n");
   }
 
   VideoAnalyzer analyzer(
@@ -1319,7 +1336,9 @@
       disable_quality_check ? -1.1 : params_.analyzer.avg_ssim_threshold,
       params_.analyzer.test_durations_secs * params_.video.fps,
       graph_data_output_file, graph_title,
-      kVideoSendSsrcs[params_.ss.selected_stream]);
+      kVideoSendSsrcs[params_.ss.selected_stream],
+      static_cast<uint32_t>(selected_stream.width),
+      static_cast<uint32_t>(selected_stream.height));
 
   analyzer.SetReceiver(receiver_call_->Receiver());
   send_transport.SetReceiver(&analyzer);
diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc
index f9a1d74..9fe84a9 100644
--- a/webrtc/video/video_receive_stream.cc
+++ b/webrtc/video/video_receive_stream.cc
@@ -405,7 +405,6 @@
     // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
     stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz);
   }
-
   // config_.renderer must never be null if we're getting this callback.
   config_.renderer->OnFrame(video_frame);
 
@@ -423,7 +422,8 @@
   if (config_.pre_decode_callback) {
     config_.pre_decode_callback->EncodedFrameCallback(
         EncodedFrame(encoded_image._buffer, encoded_image._length,
-                     encoded_image._frameType));
+                     encoded_image._frameType, encoded_image._encodedWidth,
+                     encoded_image._encodedHeight, encoded_image._timeStamp));
   }
   {
     rtc::CritScope lock(&ivf_writer_lock_);
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index bb67114..08ffa3f 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -1032,7 +1032,8 @@
   if (config_->post_encode_callback) {
     config_->post_encode_callback->EncodedFrameCallback(
         EncodedFrame(encoded_image._buffer, encoded_image._length,
-                     encoded_image._frameType));
+                     encoded_image._frameType, encoded_image._encodedWidth,
+                     encoded_image._encodedHeight, encoded_image._timeStamp));
   }
   {
     rtc::CritScope lock(&encoder_activity_crit_sect_);