Add resolution and fps stats to histograms:
- "WebRTC.Video.InputWidthInPixels"
- "WebRTC.Video.InputHeightInPixels"
- "WebRTC.Video.SentWidthInPixels"
- "WebRTC.Video.SentHeightInPixels"
- "WebRTC.Video.ReceivedWidthInPixels"
- "WebRTC.Video.ReceivedHeightInPixels"
- "WebRTC.Video.RenderFramesPerSecond"

BUG=chromium:512752

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

Cr-Commit-Position: refs/heads/master@{#9611}
diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc
index 3a80b98..a840ddb 100644
--- a/webrtc/test/fake_encoder.cc
+++ b/webrtc/test/fake_encoder.cc
@@ -97,6 +97,8 @@
     encoded._timeStamp = input_image.timestamp();
     encoded.capture_time_ms_ = input_image.render_time_ms();
     encoded._frameType = (*frame_types)[i];
+    encoded._encodedWidth = config_.simulcastStream[i].width;
+    encoded._encodedHeight = config_.simulcastStream[i].height;
     // Always encode something on the first frame.
     if (min_stream_bits > bits_available && i > 0) {
       encoded._length = 0;
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index ab4dfaf..33fc75e 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -1634,10 +1634,32 @@
   EXPECT_EQ(1, test::NumHistogramSamples(
       "WebRTC.Video.ReceivedPacketsLostInPercent"));
 
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.InputWidthInPixels"));
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.InputHeightInPixels"));
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.SentWidthInPixels"));
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.SentHeightInPixels"));
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.ReceivedWidthInPixels"));
+  EXPECT_EQ(1,
+            test::NumHistogramSamples("WebRTC.Video.ReceivedHeightInPixels"));
+
+  EXPECT_EQ(static_cast<int>(encoder_config_.streams[0].width),
+            test::LastHistogramSample("WebRTC.Video.InputWidthInPixels"));
+  EXPECT_EQ(static_cast<int>(encoder_config_.streams[0].height),
+            test::LastHistogramSample("WebRTC.Video.InputHeightInPixels"));
+  EXPECT_EQ(static_cast<int>(encoder_config_.streams[0].width),
+            test::LastHistogramSample("WebRTC.Video.SentWidthInPixels"));
+  EXPECT_EQ(static_cast<int>(encoder_config_.streams[0].height),
+            test::LastHistogramSample("WebRTC.Video.SentHeightInPixels"));
+  EXPECT_EQ(static_cast<int>(encoder_config_.streams[0].width),
+            test::LastHistogramSample("WebRTC.Video.ReceivedWidthInPixels"));
+  EXPECT_EQ(static_cast<int>(encoder_config_.streams[0].height),
+            test::LastHistogramSample("WebRTC.Video.ReceivedHeightInPixels"));
+
   EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.InputFramesPerSecond"));
   EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.SentFramesPerSecond"));
   EXPECT_EQ(1, test::NumHistogramSamples(
       "WebRTC.Video.DecodedFramesPerSecond"));
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.RenderFramesPerSecond"));
 
   EXPECT_EQ(1, test::NumHistogramSamples(
       "WebRTC.Video.BitrateSentInKbps"));
diff --git a/webrtc/video/receive_statistics_proxy.cc b/webrtc/video/receive_statistics_proxy.cc
index b5d8056..e028dab 100644
--- a/webrtc/video/receive_statistics_proxy.cc
+++ b/webrtc/video/receive_statistics_proxy.cc
@@ -28,16 +28,24 @@
   UpdateHistograms();
 }
 
-void ReceiveStatisticsProxy::UpdateHistograms() const {
-  int fraction_lost;
-  {
-    rtc::CritScope lock(&crit_);
-    fraction_lost = report_block_stats_.FractionLostInPercent();
-  }
+void ReceiveStatisticsProxy::UpdateHistograms() {
+  int fraction_lost = report_block_stats_.FractionLostInPercent();
   if (fraction_lost != -1) {
     RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedPacketsLostInPercent",
         fraction_lost);
   }
+
+  int render_fps = static_cast<int>(render_fps_tracker_total_.units_second());
+  if (render_fps > 0)
+    RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.RenderFramesPerSecond", render_fps);
+
+  const int kMinRequiredSamples = 100;
+  int width = render_width_counter_.Avg(kMinRequiredSamples);
+  int height = render_height_counter_.Avg(kMinRequiredSamples);
+  if (width != -1) {
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedWidthInPixels", width);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedHeightInPixels", height);
+  }
 }
 
 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
@@ -117,12 +125,15 @@
   stats_.decode_frame_rate = decode_fps_estimator_.Rate(now);
 }
 
-void ReceiveStatisticsProxy::OnRenderedFrame() {
+void ReceiveStatisticsProxy::OnRenderedFrame(int width, int height) {
   uint64_t now = clock_->TimeInMilliseconds();
 
   rtc::CritScope lock(&crit_);
   renders_fps_estimator_.Update(1, now);
   stats_.render_frame_rate = renders_fps_estimator_.Rate(now);
+  render_width_counter_.Add(width);
+  render_height_counter_.Add(height);
+  render_fps_tracker_total_.Update(1);
 }
 
 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate,
@@ -140,4 +151,15 @@
   stats_.discarded_packets = discarded_packets;
 }
 
+void ReceiveStatisticsProxy::SampleCounter::Add(int sample) {
+  sum += sample;
+  ++num_samples;
+}
+
+int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
+  if (num_samples < min_required_samples || num_samples == 0)
+    return -1;
+  return sum / num_samples;
+}
+
 }  // namespace webrtc
diff --git a/webrtc/video/receive_statistics_proxy.h b/webrtc/video/receive_statistics_proxy.h
index df763ad..0d22948 100644
--- a/webrtc/video/receive_statistics_proxy.h
+++ b/webrtc/video/receive_statistics_proxy.h
@@ -14,6 +14,7 @@
 #include <string>
 
 #include "webrtc/base/criticalsection.h"
+#include "webrtc/base/ratetracker.h"
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/common_types.h"
 #include "webrtc/frame_callback.h"
@@ -42,9 +43,9 @@
   VideoReceiveStream::Stats GetStats() const;
 
   void OnDecodedFrame();
-  void OnRenderedFrame();
+  void OnRenderedFrame(int width, int height);
 
-  // Overrides VCMReceiveStatisticsCallback
+  // Overrides VCMReceiveStatisticsCallback.
   void OnReceiveRatesUpdated(uint32_t bitRate, uint32_t frameRate) override;
   void OnFrameCountsUpdated(const FrameCounts& frame_counts) override;
   void OnDiscardedPacketsUpdated(int discarded_packets) override;
@@ -68,7 +69,7 @@
                          uint32_t ssrc) override;
   void CNameChanged(const char* cname, uint32_t ssrc) override;
 
-  // Overrides RtcpPacketTypeCounterObserver
+  // Overrides RtcpPacketTypeCounterObserver.
   void RtcpPacketTypesCounterUpdated(
       uint32_t ssrc,
       const RtcpPacketTypeCounter& packet_counter) override;
@@ -77,13 +78,27 @@
                            uint32_t ssrc) override;
 
  private:
-  void UpdateHistograms() const;
+  struct SampleCounter {
+    SampleCounter() : sum(0), num_samples(0) {}
+    void Add(int sample);
+    int Avg(int min_required_samples) const;
+
+   private:
+    int sum;
+    int num_samples;
+  };
+
+  void UpdateHistograms() EXCLUSIVE_LOCKS_REQUIRED(crit_);
+
   Clock* const clock_;
 
   mutable rtc::CriticalSection crit_;
   VideoReceiveStream::Stats stats_ GUARDED_BY(crit_);
   RateStatistics decode_fps_estimator_ GUARDED_BY(crit_);
   RateStatistics renders_fps_estimator_ GUARDED_BY(crit_);
+  rtc::RateTracker render_fps_tracker_total_ GUARDED_BY(crit_);
+  SampleCounter render_width_counter_ GUARDED_BY(crit_);
+  SampleCounter render_height_counter_ GUARDED_BY(crit_);
   ReportBlockStats report_block_stats_ GUARDED_BY(crit_);
 };
 
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc
index c6f48e2..fe60f1e 100644
--- a/webrtc/video/send_statistics_proxy.cc
+++ b/webrtc/video/send_statistics_proxy.cc
@@ -10,6 +10,7 @@
 
 #include "webrtc/video/send_statistics_proxy.h"
 
+#include <algorithm>
 #include <map>
 
 #include "webrtc/base/checks.h"
@@ -24,7 +25,11 @@
 
 SendStatisticsProxy::SendStatisticsProxy(Clock* clock,
                                          const VideoSendStream::Config& config)
-    : clock_(clock), config_(config), last_sent_frame_timestamp_(0) {
+    : clock_(clock),
+      config_(config),
+      last_sent_frame_timestamp_(0),
+      max_sent_width_per_timestamp_(0),
+      max_sent_height_per_timestamp_(0) {
 }
 
 SendStatisticsProxy::~SendStatisticsProxy() {
@@ -34,13 +39,26 @@
 void SendStatisticsProxy::UpdateHistograms() {
   int input_fps =
       static_cast<int>(input_frame_rate_tracker_total_.units_second());
-  int sent_fps =
-      static_cast<int>(sent_frame_rate_tracker_total_.units_second());
-
   if (input_fps > 0)
     RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.InputFramesPerSecond", input_fps);
+  int sent_fps =
+      static_cast<int>(sent_frame_rate_tracker_total_.units_second());
   if (sent_fps > 0)
     RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.SentFramesPerSecond", sent_fps);
+
+  const int kMinRequiredSamples = 100;
+  int in_width = input_width_counter_.Avg(kMinRequiredSamples);
+  int in_height = input_height_counter_.Avg(kMinRequiredSamples);
+  if (in_width != -1) {
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InputWidthInPixels", in_width);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InputHeightInPixels", in_height);
+  }
+  int sent_width = sent_width_counter_.Avg(kMinRequiredSamples);
+  int sent_height = sent_height_counter_.Avg(kMinRequiredSamples);
+  if (sent_width != -1) {
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.SentWidthInPixels", sent_width);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.SentHeightInPixels", sent_height);
+  }
 }
 
 void SendStatisticsProxy::OutgoingRate(const int video_channel,
@@ -139,16 +157,33 @@
   stats->width = encoded_image._encodedWidth;
   stats->height = encoded_image._encodedHeight;
   update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
-  if (encoded_image._timeStamp != last_sent_frame_timestamp_) {
-    last_sent_frame_timestamp_ = encoded_image._timeStamp;
+
+  // TODO(asapersson): This is incorrect if simulcast layers are encoded on
+  // different threads and there is no guarantee that one frame of all layers
+  // are encoded before the next start.
+  if (last_sent_frame_timestamp_ > 0 &&
+      encoded_image._timeStamp != last_sent_frame_timestamp_) {
     sent_frame_rate_tracker_total_.Update(1);
+    sent_width_counter_.Add(max_sent_width_per_timestamp_);
+    sent_height_counter_.Add(max_sent_height_per_timestamp_);
+    max_sent_width_per_timestamp_ = 0;
+    max_sent_height_per_timestamp_ = 0;
   }
+  last_sent_frame_timestamp_ = encoded_image._timeStamp;
+  max_sent_width_per_timestamp_ =
+      std::max(max_sent_width_per_timestamp_,
+               static_cast<int>(encoded_image._encodedWidth));
+  max_sent_height_per_timestamp_ =
+      std::max(max_sent_height_per_timestamp_,
+               static_cast<int>(encoded_image._encodedHeight));
 }
 
-void SendStatisticsProxy::OnIncomingFrame() {
+void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
   rtc::CritScope lock(&crit_);
   input_frame_rate_tracker_.Update(1);
   input_frame_rate_tracker_total_.Update(1);
+  input_width_counter_.Add(width);
+  input_height_counter_.Add(height);
 }
 
 void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
@@ -219,4 +254,15 @@
   stats->max_delay_ms = max_delay_ms;
 }
 
+void SendStatisticsProxy::SampleCounter::Add(int sample) {
+  sum += sample;
+  ++num_samples;
+}
+
+int SendStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
+  if (num_samples < min_required_samples || num_samples == 0)
+    return -1;
+  return sum / num_samples;
+}
+
 }  // namespace webrtc
diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h
index 956a8f6..1d37f18 100644
--- a/webrtc/video/send_statistics_proxy.h
+++ b/webrtc/video/send_statistics_proxy.h
@@ -47,7 +47,7 @@
   virtual void OnSendEncodedImage(const EncodedImage& encoded_image,
                                   const RTPVideoHeader* rtp_video_header);
   // Used to update incoming frame rate.
-  void OnIncomingFrame();
+  void OnIncomingFrame(int width, int height);
 
   // From VideoEncoderRateObserver.
   void OnSetRates(uint32_t bitrate_bps, int framerate) override;
@@ -61,7 +61,7 @@
   void StatisticsUpdated(const RtcpStatistics& statistics,
                          uint32_t ssrc) override;
   void CNameChanged(const char* cname, uint32_t ssrc) override;
-  // From RtcpPacketTypeCounterObserver
+  // From RtcpPacketTypeCounterObserver.
   void RtcpPacketTypesCounterUpdated(
       uint32_t ssrc,
       const RtcpPacketTypeCounter& packet_counter) override;
@@ -90,6 +90,15 @@
                             uint32_t ssrc) override;
 
  private:
+  struct SampleCounter {
+    SampleCounter() : sum(0), num_samples(0) {}
+    void Add(int sample);
+    int Avg(int min_required_samples) const;
+
+   private:
+    int sum;
+    int num_samples;
+  };
   struct StatsUpdateTimes {
     StatsUpdateTimes() : resolution_update_ms(0) {}
     int64_t resolution_update_ms;
@@ -109,6 +118,13 @@
   rtc::RateTracker sent_frame_rate_tracker_total_ GUARDED_BY(crit_);
   uint32_t last_sent_frame_timestamp_ GUARDED_BY(crit_);
   std::map<uint32_t, StatsUpdateTimes> update_times_ GUARDED_BY(crit_);
+
+  int max_sent_width_per_timestamp_ GUARDED_BY(crit_);
+  int max_sent_height_per_timestamp_ GUARDED_BY(crit_);
+  SampleCounter input_width_counter_ GUARDED_BY(crit_);
+  SampleCounter input_height_counter_ GUARDED_BY(crit_);
+  SampleCounter sent_width_counter_ GUARDED_BY(crit_);
+  SampleCounter sent_height_counter_ GUARDED_BY(crit_);
 };
 
 }  // namespace webrtc
diff --git a/webrtc/video/video_capture_input.cc b/webrtc/video/video_capture_input.cc
index ecd7a30..8aae44f 100644
--- a/webrtc/video/video_capture_input.cc
+++ b/webrtc/video/video_capture_input.cc
@@ -78,7 +78,7 @@
   if (local_renderer_)
     local_renderer_->RenderFrame(video_frame, 0);
 
-  stats_proxy_->OnIncomingFrame();
+  stats_proxy_->OnIncomingFrame(video_frame.width(), video_frame.height());
 
   VideoFrame incoming_frame = video_frame;
 
diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc
index 6d6619a..d770f58 100644
--- a/webrtc/video/video_receive_stream.cc
+++ b/webrtc/video/video_receive_stream.cc
@@ -318,7 +318,7 @@
         video_frame,
         video_frame.render_time_ms() - clock_->TimeInMilliseconds());
 
-  stats_proxy_->OnRenderedFrame();
+  stats_proxy_->OnRenderedFrame(video_frame.width(), video_frame.height());
 
   return 0;
 }