Add histograms for receive statistics:
- decoded frames per second ("WebRTC.Video.DecodedFramesPerSecond")
- percentage of delayed frames to rendered ("WebRTC.Video.DelayedFramesToRenderer")
- average delay (of delayed frames) to renderer ("WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs")

BUG=crbug/419657
R=stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/26319004

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@7847 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/video_coding/main/source/generic_decoder.cc b/modules/video_coding/main/source/generic_decoder.cc
index cb0faf9..4f8a7ca 100644
--- a/modules/video_coding/main/source/generic_decoder.cc
+++ b/modules/video_coding/main/source/generic_decoder.cc
@@ -68,7 +68,8 @@
     _timing.StopDecodeTimer(
         decodedImage.timestamp(),
         frameInfo->decodeStartTimeMs,
-        _clock->TimeInMilliseconds());
+        _clock->TimeInMilliseconds(),
+        frameInfo->renderTimeMs);
 
     if (callback != NULL)
     {
diff --git a/modules/video_coding/main/source/timing.cc b/modules/video_coding/main/source/timing.cc
index 2ec149c..0e2fddf 100644
--- a/modules/video_coding/main/source/timing.cc
+++ b/modules/video_coding/main/source/timing.cc
@@ -13,6 +13,7 @@
 #include "webrtc/modules/video_coding/main/source/internal_defines.h"
 #include "webrtc/modules/video_coding/main/source/jitter_buffer_common.h"
 #include "webrtc/system_wrappers/interface/clock.h"
+#include "webrtc/system_wrappers/interface/metrics.h"
 #include "webrtc/system_wrappers/interface/timestamp_extrapolator.h"
 
 
@@ -30,7 +31,11 @@
       jitter_delay_ms_(0),
       current_delay_ms_(0),
       last_decode_ms_(0),
-      prev_frame_timestamp_(0) {
+      prev_frame_timestamp_(0),
+      num_decoded_frames_(0),
+      num_delayed_decoded_frames_(0),
+      first_decoded_frame_ms_(-1),
+      sum_missed_render_deadline_ms_(0) {
   if (master_timing == NULL) {
     master_ = true;
     ts_extrapolator_ = new TimestampExtrapolator(clock_->TimeInMilliseconds());
@@ -40,12 +45,34 @@
 }
 
 VCMTiming::~VCMTiming() {
+  UpdateHistograms();
   if (master_) {
     delete ts_extrapolator_;
   }
   delete crit_sect_;
 }
 
+void VCMTiming::UpdateHistograms() const {
+  CriticalSectionScoped cs(crit_sect_);
+  if (num_decoded_frames_ == 0) {
+    return;
+  }
+  int64_t elapsed_sec =
+      (clock_->TimeInMilliseconds() - first_decoded_frame_ms_) / 1000;
+  if (elapsed_sec < metrics::kMinRunTimeInSeconds) {
+    return;
+  }
+  RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.DecodedFramesPerSecond",
+      static_cast<int>((num_decoded_frames_ / elapsed_sec) + 0.5f));
+  RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.DelayedFramesToRenderer",
+      num_delayed_decoded_frames_ * 100 / num_decoded_frames_);
+  if (num_delayed_decoded_frames_ > 0) {
+    RTC_HISTOGRAM_COUNTS_1000(
+        "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
+            sum_missed_render_deadline_ms_ / num_delayed_decoded_frames_);
+  }
+}
+
 void VCMTiming::Reset() {
   CriticalSectionScoped cs(crit_sect_);
   ts_extrapolator_->Reset(clock_->TimeInMilliseconds());
@@ -139,11 +166,23 @@
 
 int32_t VCMTiming::StopDecodeTimer(uint32_t time_stamp,
                                    int64_t start_time_ms,
-                                   int64_t now_ms) {
+                                   int64_t now_ms,
+                                   int64_t render_time_ms) {
   CriticalSectionScoped cs(crit_sect_);
   int32_t time_diff_ms = codec_timer_.StopTimer(start_time_ms, now_ms);
   assert(time_diff_ms >= 0);
   last_decode_ms_ = time_diff_ms;
+
+  // Update stats.
+  ++num_decoded_frames_;
+  if (num_decoded_frames_ == 1) {
+    first_decoded_frame_ms_ = now_ms;
+  }
+  int time_until_rendering_ms = render_time_ms - render_delay_ms_ - now_ms;
+  if (time_until_rendering_ms < 0) {
+    sum_missed_render_deadline_ms_ += -time_until_rendering_ms;
+    ++num_delayed_decoded_frames_;
+  }
   return 0;
 }
 
diff --git a/modules/video_coding/main/source/timing.h b/modules/video_coding/main/source/timing.h
index bb44a93..61c0273 100644
--- a/modules/video_coding/main/source/timing.h
+++ b/modules/video_coding/main/source/timing.h
@@ -59,7 +59,8 @@
   // or when the decoded frame callback is called.
   int32_t StopDecodeTimer(uint32_t time_stamp,
                           int64_t start_time_ms,
-                          int64_t now_ms);
+                          int64_t now_ms,
+                          int64_t render_time_ms);
 
   // Used to report that a frame is passed to decoding. Updates the timestamp
   // filter which is used to map between timestamps and receiver system time.
@@ -101,6 +102,8 @@
   uint32_t TargetDelayInternal() const EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
 
  private:
+  void UpdateHistograms() const;
+
   CriticalSectionWrapper* crit_sect_;
   Clock* const clock_;
   bool master_ GUARDED_BY(crit_sect_);
@@ -112,6 +115,12 @@
   uint32_t current_delay_ms_ GUARDED_BY(crit_sect_);
   int last_decode_ms_ GUARDED_BY(crit_sect_);
   uint32_t prev_frame_timestamp_ GUARDED_BY(crit_sect_);
+
+  // Statistics.
+  size_t num_decoded_frames_ GUARDED_BY(crit_sect_);
+  size_t num_delayed_decoded_frames_ GUARDED_BY(crit_sect_);
+  int64_t first_decoded_frame_ms_ GUARDED_BY(crit_sect_);
+  uint64_t sum_missed_render_deadline_ms_ GUARDED_BY(crit_sect_);
 };
 }  // namespace webrtc
 
diff --git a/modules/video_coding/main/source/timing_unittest.cc b/modules/video_coding/main/source/timing_unittest.cc
index dde26a9..32df31c 100644
--- a/modules/video_coding/main/source/timing_unittest.cc
+++ b/modules/video_coding/main/source/timing_unittest.cc
@@ -86,7 +86,8 @@
     int64_t startTimeMs = clock.TimeInMilliseconds();
     clock.AdvanceTimeMilliseconds(10);
     timing.StopDecodeTimer(timeStamp, startTimeMs,
-                           clock.TimeInMilliseconds());
+                           clock.TimeInMilliseconds(), timing.RenderTimeMs(
+                               timeStamp, clock.TimeInMilliseconds()));
     timeStamp += 90000 / 25;
     clock.AdvanceTimeMilliseconds(1000 / 25 - 10);
     timing.IncomingTimestamp(timeStamp, clock.TimeInMilliseconds());