diff --git a/webrtc/api/statscollector.cc b/webrtc/api/statscollector.cc index fab33cd241..819f31b048 100644 --- a/webrtc/api/statscollector.cc +++ b/webrtc/api/statscollector.cc @@ -234,6 +234,7 @@ void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) { { StatsReport::kStatsValueNamePlisSent, info.plis_sent }, { StatsReport::kStatsValueNameRenderDelayMs, info.render_delay_ms }, { StatsReport::kStatsValueNameTargetDelayMs, info.target_delay_ms }, + { StatsReport::kStatsValueNameFramesDecoded, info.frames_decoded }, }; for (const auto& i : ints) diff --git a/webrtc/api/statscollector_unittest.cc b/webrtc/api/statscollector_unittest.cc index f92db73666..8c82811d76 100644 --- a/webrtc/api/statscollector_unittest.cc +++ b/webrtc/api/statscollector_unittest.cc @@ -1939,4 +1939,46 @@ TEST_F(StatsCollectorTest, VerifyVideoSendSsrcStats) { StatsReport::kStatsValueNameFramesEncoded)); } +// This test verifies that stats are correctly set in video receive ssrc stats. +TEST_F(StatsCollectorTest, VerifyVideoReceiveSsrcStats) { + 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::VideoReceiverInfo video_receiver_info; + cricket::VideoMediaInfo stats_read; + + AddIncomingVideoTrackStats(); + stats.AddStream(stream_); + + // Construct a stats value to read. + video_receiver_info.add_ssrc(1234); + video_receiver_info.frames_decoded = 10; + stats_read.receivers.push_back(video_receiver_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_receiver_info.frames_decoded), + ExtractSsrcStatsValue(reports, + StatsReport::kStatsValueNameFramesDecoded)); +} + } // namespace webrtc diff --git a/webrtc/api/statstypes.cc b/webrtc/api/statstypes.cc index 1a9752d0b1..8f25d0543b 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 kStatsValueNameFramesDecoded: + return "framesDecoded"; case kStatsValueNameFramesEncoded: return "framesEncoded"; case kStatsValueNameCodecImplementationName: diff --git a/webrtc/api/statstypes.h b/webrtc/api/statstypes.h index e88879f1fa..366b6efa0f 100644 --- a/webrtc/api/statstypes.h +++ b/webrtc/api/statstypes.h @@ -106,6 +106,7 @@ class StatsReport { kStatsValueNameBytesSent, kStatsValueNameCodecImplementationName, kStatsValueNameDataChannelId, + kStatsValueNameFramesDecoded, kStatsValueNameFramesEncoded, kStatsValueNameMediaType, kStatsValueNamePacketsLost, diff --git a/webrtc/media/base/mediachannel.h b/webrtc/media/base/mediachannel.h index f3cebee160..afad14cd9d 100644 --- a/webrtc/media/base/mediachannel.h +++ b/webrtc/media/base/mediachannel.h @@ -711,6 +711,7 @@ struct VideoReceiverInfo : public MediaReceiverInfo { framerate_output(0), framerate_render_input(0), framerate_render_output(0), + frames_decoded(0), decode_ms(0), max_decode_ms(0), jitter_buffer_ms(0), @@ -736,6 +737,7 @@ struct VideoReceiverInfo : public MediaReceiverInfo { int framerate_render_input; // Framerate that the renderer reports. int framerate_render_output; + uint32_t frames_decoded; // All stats below are gathered per-VideoReceiver, but some will be correlated // across MediaStreamTracks. NOTE(hta): when sinking stats into per-SSRC diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc index 8b63d08627..490bbf4504 100644 --- a/webrtc/media/engine/webrtcvideoengine2.cc +++ b/webrtc/media/engine/webrtcvideoengine2.cc @@ -2562,6 +2562,7 @@ WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetVideoReceiverInfo( info.jitter_buffer_ms = stats.jitter_buffer_ms; info.min_playout_delay_ms = stats.min_playout_delay_ms; info.render_delay_ms = stats.render_delay_ms; + info.frames_decoded = stats.frames_decoded; info.codec_name = GetCodecNameFromPayloadType(stats.current_payload_type); diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc index 829b351198..868ff42b7c 100644 --- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc +++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc @@ -3109,6 +3109,7 @@ TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesDecodeStatsCorrectly) { stats.render_delay_ms = 8; stats.width = 9; stats.height = 10; + stats.frames_decoded = 11; stream->SetStats(stats); cricket::VideoMediaInfo info; @@ -3124,6 +3125,7 @@ TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesDecodeStatsCorrectly) { EXPECT_EQ(stats.render_delay_ms, info.receivers[0].render_delay_ms); EXPECT_EQ(stats.width, info.receivers[0].frame_width); EXPECT_EQ(stats.height, info.receivers[0].frame_height); + EXPECT_EQ(stats.frames_decoded, info.receivers[0].frames_decoded); } TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesReceivePacketStatsCorrectly) { diff --git a/webrtc/video/BUILD.gn b/webrtc/video/BUILD.gn index c8d32b0dda..aa42dc0626 100644 --- a/webrtc/video/BUILD.gn +++ b/webrtc/video/BUILD.gn @@ -147,6 +147,7 @@ if (rtc_include_tests) { "end_to_end_tests.cc", "overuse_frame_detector_unittest.cc", "payload_router_unittest.cc", + "receive_statistics_proxy_unittest.cc", "report_block_stats_unittest.cc", "send_delay_stats_unittest.cc", "send_statistics_proxy_unittest.cc", diff --git a/webrtc/video/receive_statistics_proxy.cc b/webrtc/video/receive_statistics_proxy.cc index d4a0df371d..e7310e8b19 100644 --- a/webrtc/video/receive_statistics_proxy.cc +++ b/webrtc/video/receive_statistics_proxy.cc @@ -247,6 +247,7 @@ void ReceiveStatisticsProxy::OnDecodedFrame() { uint64_t now = clock_->TimeInMilliseconds(); rtc::CritScope lock(&crit_); + ++stats_.frames_decoded; decode_fps_estimator_.Update(1, now); stats_.decode_frame_rate = decode_fps_estimator_.Rate(now).value_or(0); } diff --git a/webrtc/video/receive_statistics_proxy_unittest.cc b/webrtc/video/receive_statistics_proxy_unittest.cc new file mode 100644 index 0000000000..894ee8fe73 --- /dev/null +++ b/webrtc/video/receive_statistics_proxy_unittest.cc @@ -0,0 +1,48 @@ +/* + * Copyright 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/video/receive_statistics_proxy.h" + +#include + +#include "webrtc/test/gtest.h" + +namespace webrtc { + +// TODO(sakal): ReceiveStatisticsProxy is lacking unittesting. +class ReceiveStatisticsProxyTest : public ::testing::Test { + public: + ReceiveStatisticsProxyTest() : fake_clock_(1234), config_(GetTestConfig()) {} + virtual ~ReceiveStatisticsProxyTest() {} + + protected: + virtual void SetUp() { + statistics_proxy_.reset(new ReceiveStatisticsProxy(&config_, &fake_clock_)); + } + + VideoReceiveStream::Config GetTestConfig() { + VideoReceiveStream::Config config(nullptr); + return config; + } + + SimulatedClock fake_clock_; + std::unique_ptr statistics_proxy_; + VideoReceiveStream::Config config_; +}; + +TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameIncreasesFramesDecoded) { + EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded); + for (uint32_t i = 1; i <= 3; ++i) { + statistics_proxy_->OnDecodedFrame(); + EXPECT_EQ(i, statistics_proxy_->GetStats().frames_decoded); + } +} + +} // namespace webrtc diff --git a/webrtc/video_receive_stream.h b/webrtc/video_receive_stream.h index 307b0a14e3..7049afc48f 100644 --- a/webrtc/video_receive_stream.h +++ b/webrtc/video_receive_stream.h @@ -65,6 +65,7 @@ class VideoReceiveStream { int jitter_buffer_ms = 0; int min_playout_delay_ms = 0; int render_delay_ms = 10; + uint32_t frames_decoded = 0; int current_payload_type = -1;