Extend full stack tests with more stats

BUG=
R=pbos@webrtc.org

Review URL: https://codereview.webrtc.org/1216613002 .

Cr-Commit-Position: refs/heads/master@{#9612}
diff --git a/webrtc/video/full_stack.cc b/webrtc/video/full_stack.cc
index ad1b5c6..a03344e 100644
--- a/webrtc/video/full_stack.cc
+++ b/webrtc/video/full_stack.cc
@@ -18,6 +18,7 @@
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/call.h"
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/frame_callback.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
 #include "webrtc/system_wrappers/interface/clock.h"
 #include "webrtc/system_wrappers/interface/cpu_info.h"
@@ -37,6 +38,7 @@
 namespace webrtc {
 
 static const int kFullStackTestDurationSecs = 60;
+static const int kSendStatsPollingIntervalMs = 1000;
 
 struct FullStackTestParams {
   const char* test_label;
@@ -63,7 +65,8 @@
 class VideoAnalyzer : public PacketReceiver,
                       public newapi::Transport,
                       public VideoRenderer,
-                      public VideoCaptureInput {
+                      public VideoCaptureInput,
+                      public EncodedFrameObserver {
  public:
   VideoAnalyzer(VideoCaptureInput* input,
                 Transport* transport,
@@ -74,6 +77,7 @@
       : input_(input),
         transport_(transport),
         receiver_(nullptr),
+        send_stream_(nullptr),
         test_label_(test_label),
         frames_to_process_(duration_frames),
         frames_recorded_(0),
@@ -110,6 +114,10 @@
       EXPECT_TRUE(thread->Start());
       comparison_thread_pool_.push_back(thread.release());
     }
+
+    stats_polling_thread_ =
+        ThreadWrapper::CreateThread(&PollStatsThread, this, "StatsPoller");
+    EXPECT_TRUE(stats_polling_thread_->Start());
   }
 
   ~VideoAnalyzer() {
@@ -173,6 +181,12 @@
     return transport_->SendRtcp(packet, length);
   }
 
+  void EncodedFrameCallback(const EncodedFrame& frame) override {
+    rtc::CritScope lock(&comparison_lock_);
+    if (frames_recorded_ < frames_to_process_)
+      encoded_frame_size_.AddSample(frame.length_);
+  }
+
   void RenderFrame(const VideoFrame& video_frame,
                    int time_to_render_ms) override {
     int64_t render_time_ms =
@@ -222,11 +236,18 @@
           << "Analyzer stalled while waiting for test to finish.";
       last_frames_processed = frames_processed;
     }
+
+    // Signal stats polling thread if that is still waiting and stop it now,
+    // since it uses the send_stream_ reference that might be reclaimed after
+    // returning from this method.
+    done_->Set();
+    EXPECT_TRUE(stats_polling_thread_->Stop());
   }
 
   VideoCaptureInput* input_;
   Transport* transport_;
   PacketReceiver* receiver_;
+  VideoSendStream* send_stream_;
 
  private:
   struct FrameComparison {
@@ -265,15 +286,39 @@
     recv_times_.erase(reference.timestamp());
 
     rtc::CritScope crit(&comparison_lock_);
-    comparisons_.push_back(FrameComparison(reference,
-                                           render,
-                                           dropped,
-                                           send_time_ms,
-                                           recv_time_ms,
+    comparisons_.push_back(FrameComparison(reference, render, dropped,
+                                           send_time_ms, recv_time_ms,
                                            render_time_ms));
     comparison_available_event_->Set();
   }
 
+  static bool PollStatsThread(void* obj) {
+    return static_cast<VideoAnalyzer*>(obj)->PollStats();
+  }
+
+  bool PollStats() {
+    switch (done_->Wait(kSendStatsPollingIntervalMs)) {
+      case kEventSignaled:
+      case kEventError:
+        done_->Set();  // Make sure main thread is also signaled.
+        return false;
+      case kEventTimeout:
+        break;
+      default:
+        RTC_NOTREACHED();
+    }
+
+    VideoSendStream::Stats stats = send_stream_->GetStats();
+
+    rtc::CritScope crit(&comparison_lock_);
+    encode_frame_rate_.AddSample(stats.encode_frame_rate);
+    encode_time_ms.AddSample(stats.avg_encode_time_ms);
+    encode_usage_percent.AddSample(stats.encode_usage_percent);
+    media_bitrate_bps.AddSample(stats.media_bitrate_bps);
+
+    return true;
+  }
+
   static bool FrameComparisonThread(void* obj) {
     return static_cast<VideoAnalyzer*>(obj)->CompareFrames();
   }
@@ -358,6 +403,12 @@
     PrintResult("receiver_time", receiver_time_, " ms");
     PrintResult("total_delay_incl_network", end_to_end_, " ms");
     PrintResult("time_between_rendered_frames", rendered_delta_, " ms");
+    PrintResult("encoded_frame_size", encoded_frame_size_, " bytes");
+    PrintResult("encode_frame_rate", encode_frame_rate_, " fps");
+    PrintResult("encode_time", encode_time_ms, " ms");
+    PrintResult("encode_usage_percent", encode_usage_percent, " percent");
+    PrintResult("media_bitrate", media_bitrate_bps, " bps");
+
     EXPECT_GT(psnr_.Mean(), avg_psnr_threshold_);
     EXPECT_GT(ssim_.Mean(), avg_ssim_threshold_);
   }
@@ -397,12 +448,18 @@
   }
 
   const char* const test_label_;
-  test::Statistics sender_time_;
-  test::Statistics receiver_time_;
-  test::Statistics psnr_;
-  test::Statistics ssim_;
-  test::Statistics end_to_end_;
-  test::Statistics rendered_delta_;
+  test::Statistics sender_time_ GUARDED_BY(comparison_lock_);
+  test::Statistics receiver_time_ GUARDED_BY(comparison_lock_);
+  test::Statistics psnr_ GUARDED_BY(comparison_lock_);
+  test::Statistics ssim_ GUARDED_BY(comparison_lock_);
+  test::Statistics end_to_end_ GUARDED_BY(comparison_lock_);
+  test::Statistics rendered_delta_ GUARDED_BY(comparison_lock_);
+  test::Statistics encoded_frame_size_ GUARDED_BY(comparison_lock_);
+  test::Statistics encode_frame_rate_ GUARDED_BY(comparison_lock_);
+  test::Statistics encode_time_ms GUARDED_BY(comparison_lock_);
+  test::Statistics encode_usage_percent GUARDED_BY(comparison_lock_);
+  test::Statistics media_bitrate_bps GUARDED_BY(comparison_lock_);
+
   const int frames_to_process_;
   int frames_recorded_;
   int frames_processed_;
@@ -421,6 +478,7 @@
 
   rtc::CriticalSection comparison_lock_;
   std::vector<ThreadWrapper*> comparison_thread_pool_;
+  rtc::scoped_ptr<ThreadWrapper> stats_polling_thread_;
   const rtc::scoped_ptr<EventWrapper> comparison_available_event_;
   std::deque<FrameComparison> comparisons_ GUARDED_BY(comparison_lock_);
   const rtc::scoped_ptr<EventWrapper> done_;
@@ -478,8 +536,11 @@
   receive_configs_[0].rtp.rtx[kSendRtxPayloadType].payload_type =
       kSendRtxPayloadType;
 
+  for (auto& config : receive_configs_)
+    config.pre_decode_callback = &analyzer;
   CreateStreams();
   analyzer.input_ = send_stream_->Input();
+  analyzer.send_stream_ = send_stream_;
 
   if (params.screenshare) {
     std::vector<std::string> slides;