diff --git a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc index fcefdb89fa..4a22e3d31f 100644 --- a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc +++ b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc @@ -694,6 +694,9 @@ int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { encoded_image_.capture_time_ms_ = input_image_->render_time_ms(); encoded_image_._encodedHeight = raw_->d_h; encoded_image_._encodedWidth = raw_->d_w; + int qp = -1; + vpx_codec_control(encoder_, VP8E_GET_LAST_QUANTIZER, &qp); + encoded_image_.qp_ = qp; encoded_complete_callback_->Encoded(encoded_image_, &codec_specific, &frag_info); } diff --git a/webrtc/system_wrappers/include/metrics.h b/webrtc/system_wrappers/include/metrics.h index 1576f91910..d5e549285f 100644 --- a/webrtc/system_wrappers/include/metrics.h +++ b/webrtc/system_wrappers/include/metrics.h @@ -69,6 +69,9 @@ #define RTC_HISTOGRAM_COUNTS_200(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50) +#define RTC_HISTOGRAM_COUNTS_500(name, sample) \ + RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50) + #define RTC_HISTOGRAM_COUNTS_1000(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50) @@ -89,6 +92,9 @@ #define RTC_LOGGED_HISTOGRAM_COUNTS_200(name, sample) \ RTC_LOGGED_HISTOGRAM_COUNTS(name, sample, 1, 200, 50) +#define RTC_LOGGED_HISTOGRAM_COUNTS_500(name, sample) \ + RTC_LOGGED_HISTOGRAM_COUNTS(name, sample, 1, 500, 50) + #define RTC_LOGGED_HISTOGRAM_COUNTS_1000(name, sample) \ RTC_LOGGED_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50) @@ -175,6 +181,10 @@ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)) +#define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) \ + RTC_HISTOGRAMS_COMMON(index, name, sample, \ + RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50)) + #define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)) @@ -204,6 +214,10 @@ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_LOGGED_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)) +#define RTC_LOGGED_HISTOGRAMS_COUNTS_500(index, name, sample) \ + RTC_HISTOGRAMS_COMMON(index, name, sample, \ + RTC_LOGGED_HISTOGRAM_COUNTS(name, sample, 1, 500, 50)) + #define RTC_LOGGED_HISTOGRAMS_COUNTS_1000(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_LOGGED_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)) diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc index 86694c930e..6951fda01b 100644 --- a/webrtc/video/send_statistics_proxy.cc +++ b/webrtc/video/send_statistics_proxy.cc @@ -194,26 +194,46 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( } for (const auto& it : qp_counters_) { - int qp = it.second.vp8.Avg(kMinRequiredSamples); - if (qp != -1) { + int qp_vp8 = it.second.vp8.Avg(kMinRequiredSamples); + if (qp_vp8 != -1) { int spatial_idx = it.first; if (spatial_idx == -1) { RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8", - qp); + qp_vp8); } else if (spatial_idx == 0) { - RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex, - uma_prefix_ + "Encoded.Qp.Vp8.S0", qp); + RTC_LOGGED_HISTOGRAMS_COUNTS_200( + kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0", qp_vp8); } else if (spatial_idx == 1) { - RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex, - uma_prefix_ + "Encoded.Qp.Vp8.S1", qp); + RTC_LOGGED_HISTOGRAMS_COUNTS_200( + kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1", qp_vp8); } else if (spatial_idx == 2) { - RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex, - uma_prefix_ + "Encoded.Qp.Vp8.S2", qp); + RTC_LOGGED_HISTOGRAMS_COUNTS_200( + kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2", qp_vp8); } else { LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx " << spatial_idx; } } + int qp_vp9 = it.second.vp9.Avg(kMinRequiredSamples); + if (qp_vp9 != -1) { + int spatial_idx = it.first; + if (spatial_idx == -1) { + RTC_LOGGED_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9", + qp_vp9); + } else if (spatial_idx == 0) { + RTC_LOGGED_HISTOGRAMS_COUNTS_500( + kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0", qp_vp9); + } else if (spatial_idx == 1) { + RTC_LOGGED_HISTOGRAMS_COUNTS_500( + kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1", qp_vp9); + } else if (spatial_idx == 2) { + RTC_LOGGED_HISTOGRAMS_COUNTS_500( + kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2", qp_vp9); + } else { + LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer " + << spatial_idx; + } + } } if (first_rtcp_stats_time_ms_ != -1) { @@ -449,11 +469,19 @@ void SendStatisticsProxy::OnSendEncodedImage( } } - if (encoded_image.qp_ != -1 && rtp_video_header && - rtp_video_header->codec == kRtpVideoVp8) { - int spatial_idx = - (config_.rtp.ssrcs.size() == 1) ? -1 : static_cast(simulcast_idx); - uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_); + if (encoded_image.qp_ != -1 && rtp_video_header) { + if (rtp_video_header->codec == kRtpVideoVp8) { + int spatial_idx = (config_.rtp.ssrcs.size() == 1) + ? -1 + : static_cast(simulcast_idx); + uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_); + } else if (rtp_video_header->codec == kRtpVideoVp9) { + int spatial_idx = + (rtp_video_header->codecHeader.VP9.num_spatial_layers == 1) + ? -1 + : rtp_video_header->codecHeader.VP9.spatial_idx; + uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_); + } } // TODO(asapersson): This is incorrect if simulcast layers are encoded on diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h index 5a479a1e80..bb0372aec1 100644 --- a/webrtc/video/send_statistics_proxy.h +++ b/webrtc/video/send_statistics_proxy.h @@ -126,7 +126,8 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, int64_t bitrate_update_ms; }; struct QpCounters { - SampleCounter vp8; + SampleCounter vp8; // QP range: 0-127 + SampleCounter vp9; // QP range: 0-255 }; void PurgeOldStats() EXCLUSIVE_LOCKS_REQUIRED(crit_); VideoSendStream::StreamStats* GetStatsEntry(uint32_t ssrc) diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc index bb404fb8be..dae0b46a45 100644 --- a/webrtc/video/send_statistics_proxy_unittest.cc +++ b/webrtc/video/send_statistics_proxy_unittest.cc @@ -21,11 +21,16 @@ #include "webrtc/test/histogram.h" namespace webrtc { +namespace { +const uint32_t kFirstSsrc = 17; +const uint32_t kSecondSsrc = 42; +const uint32_t kFirstRtxSsrc = 18; +const uint32_t kSecondRtxSsrc = 43; -static const uint32_t kFirstSsrc = 17; -static const uint32_t kSecondSsrc = 42; -static const uint32_t kFirstRtxSsrc = 18; -static const uint32_t kSecondRtxSsrc = 43; +const int kMinRequiredSamples = 200; +const int kQpIdx0 = 21; +const int kQpIdx1 = 39; +} // namespace class SendStatisticsProxyTest : public ::testing::Test { public: @@ -310,7 +315,6 @@ TEST_F(SendStatisticsProxyTest, OnEncodedFrameTimeMeasured) { TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) { test::ClearHistograms(); - const int kMinRequiredSamples = 200; const int kWidth = 640; const int kHeight = 480; @@ -329,11 +333,7 @@ TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) { TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8) { test::ClearHistograms(); - const int kMinRequiredSamples = 200; - const int kQpIdx0 = 21; - const int kQpIdx1 = 39; EncodedImage encoded_image; - RTPVideoHeader rtp_video_header; rtp_video_header.codec = kRtpVideoVp8; @@ -361,10 +361,7 @@ TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8OneSsrc) { &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo)); test::ClearHistograms(); - const int kMinRequiredSamples = 200; - const int kQpIdx0 = 21; EncodedImage encoded_image; - RTPVideoHeader rtp_video_header; rtp_video_header.codec = kRtpVideoVp8; @@ -378,6 +375,54 @@ TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8OneSsrc) { EXPECT_EQ(kQpIdx0, test::LastHistogramSample("WebRTC.Video.Encoded.Qp.Vp8")); } +TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9) { + test::ClearHistograms(); + EncodedImage encoded_image; + RTPVideoHeader rtp_video_header; + rtp_video_header.simulcastIdx = 0; + rtp_video_header.codec = kRtpVideoVp9; + rtp_video_header.codecHeader.VP9.num_spatial_layers = 2; + + for (int i = 0; i < kMinRequiredSamples; ++i) { + encoded_image.qp_ = kQpIdx0; + rtp_video_header.codecHeader.VP9.spatial_idx = 0; + statistics_proxy_->OnSendEncodedImage(encoded_image, &rtp_video_header); + encoded_image.qp_ = kQpIdx1; + rtp_video_header.codecHeader.VP9.spatial_idx = 1; + statistics_proxy_->OnSendEncodedImage(encoded_image, &rtp_video_header); + } + statistics_proxy_.reset(); + EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.Encoded.Qp.Vp9.S0")); + EXPECT_EQ(kQpIdx0, + test::LastHistogramSample("WebRTC.Video.Encoded.Qp.Vp9.S0")); + EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.Encoded.Qp.Vp9.S1")); + EXPECT_EQ(kQpIdx1, + test::LastHistogramSample("WebRTC.Video.Encoded.Qp.Vp9.S1")); +} + +TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9OneSpatialLayer) { + VideoSendStream::Config config(nullptr); + config.rtp.ssrcs.push_back(kFirstSsrc); + statistics_proxy_.reset(new SendStatisticsProxy( + &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo)); + + test::ClearHistograms(); + EncodedImage encoded_image; + RTPVideoHeader rtp_video_header; + rtp_video_header.simulcastIdx = 0; + rtp_video_header.codec = kRtpVideoVp9; + rtp_video_header.codecHeader.VP9.num_spatial_layers = 1; + + for (int i = 0; i < kMinRequiredSamples; ++i) { + encoded_image.qp_ = kQpIdx0; + rtp_video_header.codecHeader.VP9.spatial_idx = 0; + statistics_proxy_->OnSendEncodedImage(encoded_image, &rtp_video_header); + } + statistics_proxy_.reset(); + EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.Encoded.Qp.Vp9")); + EXPECT_EQ(kQpIdx0, test::LastHistogramSample("WebRTC.Video.Encoded.Qp.Vp9")); +} + TEST_F(SendStatisticsProxyTest, NoSubstreams) { uint32_t excluded_ssrc = std::max(