diff --git a/webrtc/api/statscollector.cc b/webrtc/api/statscollector.cc index d150045d06..fab33cd241 100644 --- a/webrtc/api/statscollector.cc +++ b/webrtc/api/statscollector.cc @@ -267,6 +267,7 @@ void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) { { StatsReport::kStatsValueNamePacketsLost, info.packets_lost }, { StatsReport::kStatsValueNamePacketsSent, info.packets_sent }, { StatsReport::kStatsValueNamePlisReceived, info.plis_rcvd }, + { StatsReport::kStatsValueNameFramesEncoded, info.frames_encoded }, }; for (const auto& i : ints) diff --git a/webrtc/api/statscollector_unittest.cc b/webrtc/api/statscollector_unittest.cc index 866e76fdaa..f92db73666 100644 --- a/webrtc/api/statscollector_unittest.cc +++ b/webrtc/api/statscollector_unittest.cc @@ -29,6 +29,7 @@ #include "webrtc/base/fakesslidentity.h" #include "webrtc/base/gunit.h" #include "webrtc/base/network.h" +#include "webrtc/base/stringencode.h" #include "webrtc/logging/rtc_event_log/rtc_event_log.h" #include "webrtc/media/base/fakemediaengine.h" #include "webrtc/media/base/test/mock_mediachannel.h" @@ -1896,4 +1897,46 @@ TEST_F(StatsCollectorTest, TwoLocalTracksWithSameSsrc) { media_channel, &new_voice_sender_info, NULL, &new_stats_read, &reports); } +// This test verifies that stats are correctly set in video send ssrc stats. +TEST_F(StatsCollectorTest, VerifyVideoSendSsrcStats) { + StatsCollectorForTest stats(&pc_); + + EXPECT_CALL(session_, GetLocalCertificate(_, _)) + .WillRepeatedly(Return(false)); + EXPECT_CALL(session_, GetRemoteSSLCertificate_ReturnsRawPointer(_)) + .WillRepeatedly(Return(nullptr)); + + const char kVideoChannelName[] = "video"; + + InitSessionStats(kVideoChannelName); + EXPECT_CALL(session_, GetTransportStats(_)) + .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_), Return(true))); + + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); + cricket::VideoChannel video_channel(worker_thread_, network_thread_, + media_channel, nullptr, kVideoChannelName, + false); + StatsReports reports; // returned values. + cricket::VideoSenderInfo video_sender_info; + cricket::VideoMediaInfo stats_read; + + AddOutgoingVideoTrackStats(); + stats.AddStream(stream_); + + // Construct a stats value to read. + video_sender_info.add_ssrc(1234); + video_sender_info.frames_encoded = 10; + stats_read.senders.push_back(video_sender_info); + + EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel)); + EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); + EXPECT_CALL(*media_channel, GetStats(_)) + .WillOnce(DoAll(SetArgPointee<0>(stats_read), Return(true))); + stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); + stats.GetStats(NULL, &reports); + EXPECT_EQ(rtc::ToString(video_sender_info.frames_encoded), + ExtractSsrcStatsValue(reports, + StatsReport::kStatsValueNameFramesEncoded)); +} + } // namespace webrtc diff --git a/webrtc/api/statstypes.cc b/webrtc/api/statstypes.cc index 391a938cc7..1a9752d0b1 100644 --- a/webrtc/api/statstypes.cc +++ b/webrtc/api/statstypes.cc @@ -393,6 +393,8 @@ const char* StatsReport::Value::display_name() const { return "state"; case kStatsValueNameDataChannelId: return "datachannelid"; + case kStatsValueNameFramesEncoded: + return "framesEncoded"; case kStatsValueNameCodecImplementationName: return "codecImplementationName"; case kStatsValueNameMediaType: diff --git a/webrtc/api/statstypes.h b/webrtc/api/statstypes.h index edcfcfd694..e88879f1fa 100644 --- a/webrtc/api/statstypes.h +++ b/webrtc/api/statstypes.h @@ -106,6 +106,7 @@ class StatsReport { kStatsValueNameBytesSent, kStatsValueNameCodecImplementationName, kStatsValueNameDataChannelId, + kStatsValueNameFramesEncoded, kStatsValueNameMediaType, kStatsValueNamePacketsLost, kStatsValueNamePacketsReceived, diff --git a/webrtc/media/base/mediachannel.h b/webrtc/media/base/mediachannel.h index f522a5f82b..1243ae776d 100644 --- a/webrtc/media/base/mediachannel.h +++ b/webrtc/media/base/mediachannel.h @@ -677,8 +677,8 @@ struct VideoSenderInfo : public MediaSenderInfo { adapt_reason(0), adapt_changes(0), avg_encode_ms(0), - encode_usage_percent(0) { - } + encode_usage_percent(0), + frames_encoded(0) {} std::vector ssrc_groups; std::string encoder_implementation_name; @@ -696,6 +696,7 @@ struct VideoSenderInfo : public MediaSenderInfo { int adapt_changes; int avg_encode_ms; int encode_usage_percent; + uint32_t frames_encoded; }; struct VideoReceiverInfo : public MediaReceiverInfo { diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc index e5ea9d2d1c..8b63d08627 100644 --- a/webrtc/media/engine/webrtcvideoengine2.cc +++ b/webrtc/media/engine/webrtcvideoengine2.cc @@ -2162,6 +2162,7 @@ VideoSenderInfo WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo( info.framerate_sent = stats.encode_frame_rate; info.avg_encode_ms = stats.avg_encode_time_ms; info.encode_usage_percent = stats.encode_usage_percent; + info.frames_encoded = stats.frames_encoded; 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 103562fcbd..829b351198 100644 --- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc +++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc @@ -2861,6 +2861,17 @@ TEST_F(WebRtcVideoChannel2Test, GetStatsReportsCpuOveruseMetrics) { EXPECT_EQ(stats.encode_usage_percent, info.senders[0].encode_usage_percent); } +TEST_F(WebRtcVideoChannel2Test, GetStatsReportsFramesEncoded) { + FakeVideoSendStream* stream = AddSendStream(); + webrtc::VideoSendStream::Stats stats; + stats.frames_encoded = 13; + stream->SetStats(stats); + + cricket::VideoMediaInfo info; + ASSERT_TRUE(channel_->GetStats(&info)); + EXPECT_EQ(stats.frames_encoded, info.senders[0].frames_encoded); +} + 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 be58e3ed3d..6bebd46212 100644 --- a/webrtc/video/send_statistics_proxy.cc +++ b/webrtc/video/send_statistics_proxy.cc @@ -443,6 +443,7 @@ void SendStatisticsProxy::OnSendEncodedImage( size_t simulcast_idx = 0; rtc::CritScope lock(&crit_); + ++stats_.frames_encoded; if (codec_info) { if (codec_info->codecType == kVideoCodecVP8) { simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx; diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc index 73e98cffb7..cb3bde4426 100644 --- a/webrtc/video/send_statistics_proxy_unittest.cc +++ b/webrtc/video/send_statistics_proxy_unittest.cc @@ -301,6 +301,16 @@ TEST_F(SendStatisticsProxyTest, OnEncoderReconfiguredChangePreferredBitrate) { EXPECT_EQ(kPreferredMediaBitrateBps, stats.preferred_media_bitrate_bps); } +TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesFramesEncoded) { + EncodedImage encoded_image; + CodecSpecificInfo codec_info; + EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_encoded); + for (uint32_t i = 1; i <= 3; ++i) { + statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info); + EXPECT_EQ(i, statistics_proxy_->GetStats().frames_encoded); + } +} + 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 43283a55da..c0bee4ed3c 100644 --- a/webrtc/video_send_stream.h +++ b/webrtc/video_send_stream.h @@ -56,6 +56,7 @@ class VideoSendStream { int encode_frame_rate = 0; int avg_encode_time_ms = 0; int encode_usage_percent = 0; + uint32_t frames_encoded = 0; // Bitrate the encoder is currently configured to use due to bandwidth // limitations. int target_media_bitrate_bps = 0;