Get VideoCapturer stats via VideoTrackSourceInterface in StatsCollector,
without involving the VideoMediaChannel.

BUG=webrtc:5426

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

Cr-Commit-Position: refs/heads/master@{#12193}
diff --git a/webrtc/api/mediastreaminterface.h b/webrtc/api/mediastreaminterface.h
index 349fcc0..f1730c5 100644
--- a/webrtc/api/mediastreaminterface.h
+++ b/webrtc/api/mediastreaminterface.h
@@ -88,6 +88,10 @@
   static const char kAudioKind[];
   static const char kVideoKind[];
 
+  // The kind() method must return kAudioKind only if the object is a
+  // subclass of AudioTrackInterface, and kVideoKind only if the
+  // object is a subclass of VideoTrackInterface. It is typically used
+  // to protect a static_cast<> to the corresponding subclass.
   virtual std::string kind() const = 0;
   virtual std::string id() const = 0;
   virtual bool enabled() const = 0;
@@ -106,6 +110,11 @@
     : public MediaSourceInterface,
       public rtc::VideoSourceInterface<cricket::VideoFrame> {
  public:
+  struct Stats {
+    // Original size of captured frame, before video adaptation.
+    int input_width;
+    int input_height;
+  };
   // Get access to the source implementation of cricket::VideoCapturer.
   // This can be used for receiving frames and state notifications.
   // But it should not be used for starting or stopping capturing.
@@ -132,6 +141,11 @@
   // the encoder.
   virtual rtc::Optional<bool> needs_denoising() const = 0;
 
+  // Returns false if no stats are available, e.g, for a remote
+  // source, or a source which has not seen its first frame yet.
+  // Should avoid blocking.
+  virtual bool GetStats(Stats* stats) = 0;
+
  protected:
   virtual ~VideoTrackSourceInterface() {}
 };
diff --git a/webrtc/api/rtpsender.h b/webrtc/api/rtpsender.h
index 879a332..3919e07 100644
--- a/webrtc/api/rtpsender.h
+++ b/webrtc/api/rtpsender.h
@@ -101,6 +101,8 @@
   bool SetParameters(const RtpParameters& parameters);
 
  private:
+  // TODO(nisse): Since SSRC == 0 is technically valid, figure out
+  // some other way to test if we have a valid SSRC.
   bool can_send_track() const { return track_ && ssrc_; }
   // Helper function to construct options for
   // AudioProviderInterface::SetAudioSend.
diff --git a/webrtc/api/statscollector.cc b/webrtc/api/statscollector.cc
index d77953b..0182a37 100644
--- a/webrtc/api/statscollector.cc
+++ b/webrtc/api/statscollector.cc
@@ -236,11 +236,9 @@
     { StatsReport::kStatsValueNameEncodeUsagePercent,
       info.encode_usage_percent },
     { StatsReport::kStatsValueNameFirsReceived, info.firs_rcvd },
-    { StatsReport::kStatsValueNameFrameHeightInput, info.input_frame_height },
     { StatsReport::kStatsValueNameFrameHeightSent, info.send_frame_height },
     { StatsReport::kStatsValueNameFrameRateInput, info.framerate_input },
     { StatsReport::kStatsValueNameFrameRateSent, info.framerate_sent },
-    { StatsReport::kStatsValueNameFrameWidthInput, info.input_frame_width },
     { StatsReport::kStatsValueNameFrameWidthSent, info.send_frame_width },
     { StatsReport::kStatsValueNameNacksReceived, info.nacks_rcvd },
     { StatsReport::kStatsValueNamePacketsLost, info.packets_lost },
@@ -474,6 +472,7 @@
     ExtractSessionInfo();
     ExtractVoiceInfo();
     ExtractVideoInfo(level);
+    ExtractSenderInfo();
     ExtractDataInfo();
     UpdateTrackReports();
   }
@@ -828,6 +827,39 @@
   }
 }
 
+void StatsCollector::ExtractSenderInfo() {
+  RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+
+  for (const auto& sender : pc_->GetSenders()) {
+    // TODO(nisse): SSRC == 0 currently means none. Delete check when
+    // that is fixed.
+    if (!sender->ssrc()) {
+      continue;
+    }
+    const rtc::scoped_refptr<MediaStreamTrackInterface> track(sender->track());
+    if (!track || track->kind() != MediaStreamTrackInterface::kVideoKind) {
+      continue;
+    }
+    // Safe, because kind() == kVideoKind implies a subclass of
+    // VideoTrackInterface; see mediastreaminterface.h.
+    VideoTrackSourceInterface* source =
+        static_cast<VideoTrackInterface*>(track.get())->GetSource();
+
+    VideoTrackSourceInterface::Stats stats;
+    if (!source->GetStats(&stats)) {
+      continue;
+    }
+    const StatsReport::Id stats_id = StatsReport::NewIdWithDirection(
+        StatsReport::kStatsReportTypeSsrc,
+        rtc::ToString<uint32_t>(sender->ssrc()), StatsReport::kSend);
+    StatsReport* report = reports_.FindOrAddNew(stats_id);
+    report->AddInt(StatsReport::kStatsValueNameFrameWidthInput,
+                   stats.input_width);
+    report->AddInt(StatsReport::kStatsValueNameFrameHeightInput,
+                   stats.input_height);
+  }
+}
+
 void StatsCollector::ExtractDataInfo() {
   RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
 
diff --git a/webrtc/api/statscollector.h b/webrtc/api/statscollector.h
index 3757279..8c359e4 100644
--- a/webrtc/api/statscollector.h
+++ b/webrtc/api/statscollector.h
@@ -113,6 +113,7 @@
   void ExtractSessionInfo();
   void ExtractVoiceInfo();
   void ExtractVideoInfo(PeerConnectionInterface::StatsOutputLevel level);
+  void ExtractSenderInfo();
   void BuildSsrcToTransportId();
   webrtc::StatsReport* GetReport(const StatsReport::StatsType& type,
                                  const std::string& id,
diff --git a/webrtc/api/videocapturertracksource.cc b/webrtc/api/videocapturertracksource.cc
index 0543dff..cb53961 100644
--- a/webrtc/api/videocapturertracksource.cc
+++ b/webrtc/api/videocapturertracksource.cc
@@ -360,6 +360,11 @@
   // Initialize hasn't succeeded until a successful state change has occurred.
 }
 
+bool VideoCapturerTrackSource::GetStats(Stats* stats) {
+  return video_capturer_->GetInputSize(&stats->input_width,
+                                       &stats->input_height);
+}
+
 void VideoCapturerTrackSource::Stop() {
   if (!started_) {
     return;
diff --git a/webrtc/api/videocapturertracksource.h b/webrtc/api/videocapturertracksource.h
index 3673bf7..0d1142d 100644
--- a/webrtc/api/videocapturertracksource.h
+++ b/webrtc/api/videocapturertracksource.h
@@ -58,6 +58,8 @@
     return needs_denoising_;
   }
 
+  bool GetStats(Stats* stats) override;
+
   void Stop() override;
   void Restart() override;
 
diff --git a/webrtc/api/videosourceproxy.h b/webrtc/api/videosourceproxy.h
index fa6c428..f43c0db 100644
--- a/webrtc/api/videosourceproxy.h
+++ b/webrtc/api/videosourceproxy.h
@@ -28,6 +28,7 @@
 PROXY_METHOD0(void, Restart)
 PROXY_CONSTMETHOD0(bool, is_screencast)
 PROXY_CONSTMETHOD0(rtc::Optional<bool>, needs_denoising)
+PROXY_METHOD1(bool, GetStats, Stats*)
 PROXY_METHOD2(void,
               AddOrUpdateSink,
               rtc::VideoSinkInterface<cricket::VideoFrame>*,
diff --git a/webrtc/api/videotracksource.h b/webrtc/api/videotracksource.h
index 6d23d2e..108209d 100644
--- a/webrtc/api/videotracksource.h
+++ b/webrtc/api/videotracksource.h
@@ -40,6 +40,8 @@
   virtual rtc::Optional<bool> needs_denoising() const {
     return rtc::Optional<bool>(); }
 
+  bool GetStats(Stats* stats) override { return false; }
+
   void AddOrUpdateSink(rtc::VideoSinkInterface<cricket::VideoFrame>* sink,
                        const rtc::VideoSinkWants& wants) override;
   void RemoveSink(rtc::VideoSinkInterface<cricket::VideoFrame>* sink) override;
diff --git a/webrtc/media/base/mediachannel.h b/webrtc/media/base/mediachannel.h
index 5e0f2d8..6a56bcd 100644
--- a/webrtc/media/base/mediachannel.h
+++ b/webrtc/media/base/mediachannel.h
@@ -660,8 +660,6 @@
         firs_rcvd(0),
         plis_rcvd(0),
         nacks_rcvd(0),
-        input_frame_width(0),
-        input_frame_height(0),
         send_frame_width(0),
         send_frame_height(0),
         framerate_input(0),
@@ -680,8 +678,6 @@
   int firs_rcvd;
   int plis_rcvd;
   int nacks_rcvd;
-  int input_frame_width;
-  int input_frame_height;
   int send_frame_width;
   int send_frame_height;
   int framerate_input;
diff --git a/webrtc/media/base/videocapturer.cc b/webrtc/media/base/videocapturer.cc
index 6b182b3..57dc79f 100644
--- a/webrtc/media/base/videocapturer.cc
+++ b/webrtc/media/base/videocapturer.cc
@@ -179,9 +179,15 @@
   }
 }
 
-void VideoCapturer::GetStats(VideoFormat* last_captured_frame_format) {
+bool VideoCapturer::GetInputSize(int* width, int* height) {
   rtc::CritScope cs(&frame_stats_crit_);
-  *last_captured_frame_format = last_captured_frame_format_;
+  if (!input_size_valid_) {
+    return false;
+  }
+  *width = input_width_;
+  *height = input_height_;
+
+  return true;
 }
 
 void VideoCapturer::RemoveSink(
@@ -391,7 +397,7 @@
   }
 
   OnFrame(this, adapted_frame.get());
-  UpdateStats(captured_frame);
+  UpdateInputSize(captured_frame);
 }
 
 void VideoCapturer::OnFrame(VideoCapturer* capturer, const VideoFrame* frame) {
@@ -536,15 +542,13 @@
          format.height > max_format_->height;
 }
 
-void VideoCapturer::UpdateStats(const CapturedFrame* captured_frame) {
+void VideoCapturer::UpdateInputSize(const CapturedFrame* captured_frame) {
   // Update stats protected from fetches from different thread.
   rtc::CritScope cs(&frame_stats_crit_);
 
-  last_captured_frame_format_.width = captured_frame->width;
-  last_captured_frame_format_.height = captured_frame->height;
-  // TODO(ronghuawu): Useful to report interval as well?
-  last_captured_frame_format_.interval = 0;
-  last_captured_frame_format_.fourcc = captured_frame->fourcc;
+  input_size_valid_ = true;
+  input_width_ = captured_frame->width;
+  input_height_ = captured_frame->height;
 }
 
 }  // namespace cricket
diff --git a/webrtc/media/base/videocapturer.h b/webrtc/media/base/videocapturer.h
index 4ad102b..5ec743a 100644
--- a/webrtc/media/base/videocapturer.h
+++ b/webrtc/media/base/videocapturer.h
@@ -209,9 +209,7 @@
   // Takes ownership.
   void set_frame_factory(VideoFrameFactory* frame_factory);
 
-  // TODO(nisse): Rename function? Or pass the frame format before
-  // adaptation in some other way.
-  void GetStats(VideoFormat* last_captured_frame_format);
+  bool GetInputSize(int* width, int* height);
 
   // Implements VideoSourceInterface
   void AddOrUpdateSink(rtc::VideoSinkInterface<cricket::VideoFrame>* sink,
@@ -275,7 +273,7 @@
   // Returns true if format doesn't fulfill all applied restrictions.
   bool ShouldFilterFormat(const VideoFormat& format) const;
 
-  void UpdateStats(const CapturedFrame* captured_frame);
+  void UpdateInputSize(const CapturedFrame* captured_frame);
 
   rtc::ThreadChecker thread_checker_;
   std::string id_;
@@ -298,9 +296,10 @@
   CoordinatedVideoAdapter video_adapter_;
 
   rtc::CriticalSection frame_stats_crit_;
-
-  // The captured frame format before potential adapation.
-  VideoFormat last_captured_frame_format_;
+  // The captured frame size before potential adapation.
+  bool input_size_valid_ GUARDED_BY(frame_stats_crit_) = false;
+  int input_width_ GUARDED_BY(frame_stats_crit_);
+  int input_height_ GUARDED_BY(frame_stats_crit_);
 
   // Whether capturer should apply rotation to the frame before signaling it.
   bool apply_rotation_;
diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc
index b977521..41faf70 100644
--- a/webrtc/media/engine/webrtcvideoengine2.cc
+++ b/webrtc/media/engine/webrtcvideoengine2.cc
@@ -2089,13 +2089,6 @@
                           ? CoordinatedVideoAdapter::ADAPTREASON_NONE
                           : CoordinatedVideoAdapter::ADAPTREASON_CPU;
 
-  if (capturer_) {
-      VideoFormat last_captured_frame_format;
-      capturer_->GetStats(&last_captured_frame_format);
-      info.input_frame_width = last_captured_frame_format.width;
-      info.input_frame_height = last_captured_frame_format.height;
-  }
-
   // Get bandwidth limitation info from stream_->GetStats().
   // Input resolution (output from video_adapter) can be further scaled down or
   // higher video layer(s) can be dropped due to bitrate constraints.