Implement qpSum stat for video send ssrc stats.

Implemented as defined by this pull request: https://github.com/w3c/webrtc-stats/pull/70

BUG=webrtc:6541

Review-Url: https://codereview.webrtc.org/2430603003
Cr-Commit-Position: refs/heads/master@{#14851}
diff --git a/webrtc/api/statscollector.cc b/webrtc/api/statscollector.cc
index 819f31b..a40835c 100644
--- a/webrtc/api/statscollector.cc
+++ b/webrtc/api/statscollector.cc
@@ -253,6 +253,8 @@
                      (info.adapt_reason & 0x1) > 0);
   report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
                      (info.adapt_reason & 0x4) > 0);
+  if (info.qp_sum)
+    report->AddInt(StatsReport::kStatsValueNameQpSum, *info.qp_sum);
 
   const IntForAdd ints[] = {
     { StatsReport::kStatsValueNameAdaptationChanges, info.adapt_changes },
diff --git a/webrtc/api/statscollector_unittest.cc b/webrtc/api/statscollector_unittest.cc
index 8c82811..10fe1e3 100644
--- a/webrtc/api/statscollector_unittest.cc
+++ b/webrtc/api/statscollector_unittest.cc
@@ -1926,6 +1926,7 @@
   // Construct a stats value to read.
   video_sender_info.add_ssrc(1234);
   video_sender_info.frames_encoded = 10;
+  video_sender_info.qp_sum = rtc::Optional<uint64_t>(11);
   stats_read.senders.push_back(video_sender_info);
 
   EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
@@ -1937,6 +1938,8 @@
   EXPECT_EQ(rtc::ToString(video_sender_info.frames_encoded),
             ExtractSsrcStatsValue(reports,
                                   StatsReport::kStatsValueNameFramesEncoded));
+  EXPECT_EQ(rtc::ToString(*video_sender_info.qp_sum),
+            ExtractSsrcStatsValue(reports, StatsReport::kStatsValueNameQpSum));
 }
 
 // This test verifies that stats are correctly set in video receive ssrc stats.
diff --git a/webrtc/api/statstypes.cc b/webrtc/api/statstypes.cc
index 8f25d05..354f115 100644
--- a/webrtc/api/statstypes.cc
+++ b/webrtc/api/statstypes.cc
@@ -401,6 +401,8 @@
       return "codecImplementationName";
     case kStatsValueNameMediaType:
       return "mediaType";
+    case kStatsValueNameQpSum:
+      return "qpSum";
     // 'goog' prefixed constants.
     case kStatsValueNameAccelerateRate:
       return "googAccelerateRate";
diff --git a/webrtc/api/statstypes.h b/webrtc/api/statstypes.h
index 366b6ef..9501c29 100644
--- a/webrtc/api/statstypes.h
+++ b/webrtc/api/statstypes.h
@@ -113,6 +113,7 @@
     kStatsValueNamePacketsReceived,
     kStatsValueNamePacketsSent,
     kStatsValueNameProtocol,
+    kStatsValueNameQpSum,
     kStatsValueNameReceiving,
     kStatsValueNameSelectedCandidatePairId,
     kStatsValueNameSsrc,
diff --git a/webrtc/media/base/mediachannel.h b/webrtc/media/base/mediachannel.h
index dc29b9f..863b4dc 100644
--- a/webrtc/media/base/mediachannel.h
+++ b/webrtc/media/base/mediachannel.h
@@ -709,6 +709,7 @@
   int avg_encode_ms;
   int encode_usage_percent;
   uint32_t frames_encoded;
+  rtc::Optional<uint64_t> qp_sum;
 };
 
 struct VideoReceiverInfo : public MediaReceiverInfo {
diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc
index 98b3adf..fcc9254 100644
--- a/webrtc/media/engine/webrtcvideoengine2.cc
+++ b/webrtc/media/engine/webrtcvideoengine2.cc
@@ -2124,6 +2124,7 @@
   info.avg_encode_ms = stats.avg_encode_time_ms;
   info.encode_usage_percent = stats.encode_usage_percent;
   info.frames_encoded = stats.frames_encoded;
+  info.qp_sum = stats.qp_sum;
 
   info.nominal_bitrate = stats.media_bitrate_bps;
   info.preferred_bitrate = stats.preferred_media_bitrate_bps;
diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
index 5d7b2b3..d3a6047 100644
--- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc
+++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
@@ -2875,6 +2875,17 @@
   EXPECT_EQ(stats.frames_encoded, info.senders[0].frames_encoded);
 }
 
+TEST_F(WebRtcVideoChannel2Test, GetStatsReportsQpSum) {
+  FakeVideoSendStream* stream = AddSendStream();
+  webrtc::VideoSendStream::Stats stats;
+  stats.qp_sum = rtc::Optional<uint64_t>(13);
+  stream->SetStats(stats);
+
+  cricket::VideoMediaInfo info;
+  ASSERT_TRUE(channel_->GetStats(&info));
+  EXPECT_EQ(stats.qp_sum, info.senders[0].qp_sum);
+}
+
 TEST_F(WebRtcVideoChannel2Test, GetStatsReportsUpperResolution) {
   FakeVideoSendStream* stream = AddSendStream();
   webrtc::VideoSendStream::Stats stats;
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc
index 6bebd46..370f119 100644
--- a/webrtc/video/send_statistics_proxy.cc
+++ b/webrtc/video/send_statistics_proxy.cc
@@ -495,17 +495,24 @@
     }
   }
 
-  if (encoded_image.qp_ != -1 && codec_info) {
-    if (codec_info->codecType == kVideoCodecVP8) {
-      int spatial_idx = (rtp_config_.ssrcs.size() == 1)
-                            ? -1
-                            : static_cast<int>(simulcast_idx);
-      uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
-    } else if (codec_info->codecType == kVideoCodecVP9) {
-      int spatial_idx = (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
-                            ? -1
-                            : codec_info->codecSpecific.VP9.spatial_idx;
-      uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
+  if (encoded_image.qp_ != -1) {
+    if (!stats_.qp_sum)
+      stats_.qp_sum = rtc::Optional<uint64_t>(0);
+    *stats_.qp_sum += encoded_image.qp_;
+
+    if (codec_info) {
+      if (codec_info->codecType == kVideoCodecVP8) {
+        int spatial_idx = (rtp_config_.ssrcs.size() == 1)
+                              ? -1
+                              : static_cast<int>(simulcast_idx);
+        uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
+      } else if (codec_info->codecType == kVideoCodecVP9) {
+        int spatial_idx =
+            (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
+                ? -1
+                : codec_info->codecSpecific.VP9.spatial_idx;
+        uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
+      }
     }
   }
 
diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc
index 488d575..e661e0e 100644
--- a/webrtc/video/send_statistics_proxy_unittest.cc
+++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -311,6 +311,28 @@
   }
 }
 
+TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesQpSum) {
+  EncodedImage encoded_image;
+  CodecSpecificInfo codec_info;
+  EXPECT_EQ(rtc::Optional<uint64_t>(), statistics_proxy_->GetStats().qp_sum);
+  encoded_image.qp_ = 3;
+  statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
+  EXPECT_EQ(rtc::Optional<uint64_t>(3u), statistics_proxy_->GetStats().qp_sum);
+  encoded_image.qp_ = 127;
+  statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
+  EXPECT_EQ(rtc::Optional<uint64_t>(130u),
+            statistics_proxy_->GetStats().qp_sum);
+}
+
+TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) {
+  EncodedImage encoded_image;
+  CodecSpecificInfo codec_info;
+  encoded_image.qp_ = -1;
+  EXPECT_EQ(rtc::Optional<uint64_t>(), statistics_proxy_->GetStats().qp_sum);
+  statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
+  EXPECT_EQ(rtc::Optional<uint64_t>(), statistics_proxy_->GetStats().qp_sum);
+}
+
 TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) {
   const int kWidth = 640;
   const int kHeight = 480;
diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h
index c0bee4e..4ca9fa7 100644
--- a/webrtc/video_send_stream.h
+++ b/webrtc/video_send_stream.h
@@ -57,6 +57,7 @@
     int avg_encode_time_ms = 0;
     int encode_usage_percent = 0;
     uint32_t frames_encoded = 0;
+    rtc::Optional<uint64_t> qp_sum;
     // Bitrate the encoder is currently configured to use due to bandwidth
     // limitations.
     int target_media_bitrate_bps = 0;