From d89920b74a173b7bf80c6760908a382c095a66cc Mon Sep 17 00:00:00 2001 From: asapersson Date: Wed, 22 Jul 2015 06:52:00 -0700 Subject: [PATCH] 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} --- webrtc/test/fake_encoder.cc | 2 + webrtc/video/end_to_end_tests.cc | 22 +++++++++ webrtc/video/receive_statistics_proxy.cc | 36 +++++++++++--- webrtc/video/receive_statistics_proxy.h | 23 +++++++-- webrtc/video/send_statistics_proxy.cc | 60 +++++++++++++++++++++--- webrtc/video/send_statistics_proxy.h | 20 +++++++- webrtc/video/video_capture_input.cc | 2 +- webrtc/video/video_receive_stream.cc | 2 +- 8 files changed, 145 insertions(+), 22 deletions(-) diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc index 3a80b9883e..a840ddb68a 100644 --- a/webrtc/test/fake_encoder.cc +++ b/webrtc/test/fake_encoder.cc @@ -97,6 +97,8 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, 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 ab4dfaf65a..33fc75e20d 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -1634,10 +1634,32 @@ void EndToEndTest::VerifyHistogramStats(bool use_rtx, bool use_red) { 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(encoder_config_.streams[0].width), + test::LastHistogramSample("WebRTC.Video.InputWidthInPixels")); + EXPECT_EQ(static_cast(encoder_config_.streams[0].height), + test::LastHistogramSample("WebRTC.Video.InputHeightInPixels")); + EXPECT_EQ(static_cast(encoder_config_.streams[0].width), + test::LastHistogramSample("WebRTC.Video.SentWidthInPixels")); + EXPECT_EQ(static_cast(encoder_config_.streams[0].height), + test::LastHistogramSample("WebRTC.Video.SentHeightInPixels")); + EXPECT_EQ(static_cast(encoder_config_.streams[0].width), + test::LastHistogramSample("WebRTC.Video.ReceivedWidthInPixels")); + EXPECT_EQ(static_cast(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 b5d80560f1..e028dab2e8 100644 --- a/webrtc/video/receive_statistics_proxy.cc +++ b/webrtc/video/receive_statistics_proxy.cc @@ -28,16 +28,24 @@ ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { 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(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 @@ void ReceiveStatisticsProxy::OnDecodedFrame() { 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 @@ void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) { 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 df763ad910..0d229487b9 100644 --- a/webrtc/video/receive_statistics_proxy.h +++ b/webrtc/video/receive_statistics_proxy.h @@ -14,6 +14,7 @@ #include #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 @@ class ReceiveStatisticsProxy : public ViEDecoderObserver, 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 @@ class ReceiveStatisticsProxy : public ViEDecoderObserver, 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 @@ class ReceiveStatisticsProxy : public ViEDecoderObserver, 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 c6f48e21a8..fe60f1eaa5 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 #include #include "webrtc/base/checks.h" @@ -24,7 +25,11 @@ const int SendStatisticsProxy::kStatsTimeoutMs = 5000; 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 @@ SendStatisticsProxy::~SendStatisticsProxy() { void SendStatisticsProxy::UpdateHistograms() { int input_fps = static_cast(input_frame_rate_tracker_total_.units_second()); - int sent_fps = - static_cast(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(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 @@ void SendStatisticsProxy::OnSendEncodedImage( 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(encoded_image._encodedWidth)); + max_sent_height_per_timestamp_ = + std::max(max_sent_height_per_timestamp_, + static_cast(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 @@ void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms, 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 956a8f6fe9..1d37f18b84 100644 --- a/webrtc/video/send_statistics_proxy.h +++ b/webrtc/video/send_statistics_proxy.h @@ -47,7 +47,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, 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 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, 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 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, 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 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, rtc::RateTracker sent_frame_rate_tracker_total_ GUARDED_BY(crit_); uint32_t last_sent_frame_timestamp_ GUARDED_BY(crit_); std::map 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 ecd7a30234..8aae44fa35 100644 --- a/webrtc/video/video_capture_input.cc +++ b/webrtc/video/video_capture_input.cc @@ -78,7 +78,7 @@ void VideoCaptureInput::IncomingCapturedFrame(const VideoFrame& video_frame) { 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 6d6619a38f..d770f58969 100644 --- a/webrtc/video/video_receive_stream.cc +++ b/webrtc/video/video_receive_stream.cc @@ -318,7 +318,7 @@ int VideoReceiveStream::RenderFrame(const uint32_t /*stream_id*/, video_frame, video_frame.render_time_ms() - clock_->TimeInMilliseconds()); - stats_proxy_->OnRenderedFrame(); + stats_proxy_->OnRenderedFrame(video_frame.width(), video_frame.height()); return 0; }