Update StreamStats.encode_frame_rate when GetStats is called.
Currently encode_frame_rate is updated (ComputeRate called) when a frame is encoded. If a stream is stopped, encode_frame_rate will have an old value (the framerate at the time of the last encoded frame) instead of zero. Bug: webrtc:13037 Change-Id: I1a2122df61e3e8187e57155dda71c0173cda4c5b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228220 Commit-Queue: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34695}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
ecc46eff5b
commit
603e6e3ffc
@ -748,6 +748,14 @@ VideoSendStream::Stats SendStatisticsProxy::GetStats() {
|
||||
stats_.media_bitrate_bps = media_byte_rate_tracker_.ComputeRate() * 8;
|
||||
stats_.quality_limitation_durations_ms =
|
||||
quality_limitation_reason_tracker_.DurationsMs();
|
||||
|
||||
for (auto& substream : stats_.substreams) {
|
||||
uint32_t ssrc = substream.first;
|
||||
if (encoded_frame_rate_trackers_.count(ssrc) > 0) {
|
||||
substream.second.encode_frame_rate =
|
||||
encoded_frame_rate_trackers_[ssrc]->ComputeRate();
|
||||
}
|
||||
}
|
||||
return stats_;
|
||||
}
|
||||
|
||||
@ -963,12 +971,12 @@ void SendStatisticsProxy::OnSendEncodedImage(
|
||||
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
||||
if (!stats)
|
||||
return;
|
||||
if (encoded_frame_rate_trackers_.count(simulcast_idx) == 0) {
|
||||
encoded_frame_rate_trackers_[simulcast_idx] =
|
||||
|
||||
if (encoded_frame_rate_trackers_.count(ssrc) == 0) {
|
||||
encoded_frame_rate_trackers_[ssrc] =
|
||||
std::make_unique<rtc::RateTracker>(kBucketSizeMs, kBucketCount);
|
||||
}
|
||||
stats->encode_frame_rate =
|
||||
encoded_frame_rate_trackers_[simulcast_idx]->ComputeRate();
|
||||
|
||||
stats->frames_encoded++;
|
||||
stats->total_encode_time_ms += encoded_image.timing_.encode_finish_ms -
|
||||
encoded_image.timing_.encode_start_ms;
|
||||
@ -1025,7 +1033,7 @@ void SendStatisticsProxy::OnSendEncodedImage(
|
||||
// is_top_spatial_layer pertains only to SVC, will always be true for
|
||||
// simulcast.
|
||||
if (is_top_spatial_layer)
|
||||
encoded_frame_rate_trackers_[simulcast_idx]->AddSamples(1);
|
||||
encoded_frame_rate_trackers_[ssrc]->AddSamples(1);
|
||||
|
||||
absl::optional<int> downscales =
|
||||
adaptation_limitations_.MaskedQualityCounts().resolution_adaptations;
|
||||
|
@ -284,6 +284,7 @@ class SendStatisticsProxy : public VideoStreamEncoderObserver,
|
||||
RTC_GUARDED_BY(mutex_);
|
||||
rtc::RateTracker media_byte_rate_tracker_ RTC_GUARDED_BY(mutex_);
|
||||
rtc::RateTracker encoded_frame_rate_tracker_ RTC_GUARDED_BY(mutex_);
|
||||
// Rate trackers mapped by ssrc.
|
||||
std::map<uint32_t, std::unique_ptr<rtc::RateTracker>>
|
||||
encoded_frame_rate_trackers_ RTC_GUARDED_BY(mutex_);
|
||||
|
||||
|
@ -456,22 +456,24 @@ TEST_F(SendStatisticsProxyTest,
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStream) {
|
||||
const int kInterframeDelayMs = 100;
|
||||
auto ssrc = config_.rtp.ssrcs[0];
|
||||
const auto ssrc = config_.rtp.ssrcs[0];
|
||||
rtc::ScopedFakeClock fake_global_clock;
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
|
||||
EncodedImage encoded_image;
|
||||
|
||||
// First frame
|
||||
EncodedImage encoded_image;
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
|
||||
// Second frame
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
// Second frame
|
||||
encoded_image.SetTimestamp(encoded_image.Timestamp() +
|
||||
90 * kInterframeDelayMs);
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
|
||||
auto stats = statistics_proxy_->GetStats();
|
||||
EXPECT_EQ(stats.substreams[ssrc].encode_frame_rate, 10);
|
||||
@ -480,39 +482,74 @@ TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStream) {
|
||||
TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp8Simulcast) {
|
||||
const int kInterframeDelayMs = 100;
|
||||
rtc::ScopedFakeClock fake_global_clock;
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
EncodedImage encoded_image;
|
||||
CodecSpecificInfo codec_info;
|
||||
codec_info.codecType = kVideoCodecVP8;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
encoded_image.SetTimestamp(encoded_image.Timestamp() +
|
||||
90 * kInterframeDelayMs);
|
||||
encoded_image.SetSpatialIndex(0);
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
|
||||
encoded_image.SetSpatialIndex(1);
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
}
|
||||
|
||||
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
|
||||
EXPECT_EQ(2u, stats.substreams.size());
|
||||
EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[0]].encode_frame_rate, 10);
|
||||
EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[1]].encode_frame_rate, 10);
|
||||
|
||||
// Stop encoding second stream, expect framerate to be zero.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
encoded_image.SetTimestamp(encoded_image.Timestamp() +
|
||||
90 * kInterframeDelayMs);
|
||||
encoded_image.SetSpatialIndex(0);
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
}
|
||||
|
||||
stats = statistics_proxy_->GetStats();
|
||||
EXPECT_EQ(2u, stats.substreams.size());
|
||||
EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[0]].encode_frame_rate, 10);
|
||||
EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[1]].encode_frame_rate, 0);
|
||||
|
||||
// Start encoding second stream.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
encoded_image.SetTimestamp(encoded_image.Timestamp() +
|
||||
90 * kInterframeDelayMs);
|
||||
encoded_image.SetSpatialIndex(0);
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
|
||||
encoded_image.SetSpatialIndex(1);
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
}
|
||||
|
||||
stats = statistics_proxy_->GetStats();
|
||||
EXPECT_EQ(2u, stats.substreams.size());
|
||||
EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[0]].encode_frame_rate, 10);
|
||||
EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[1]].encode_frame_rate, 10);
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp9Svc) {
|
||||
const int kInterframeDelayMs = 100;
|
||||
rtc::ScopedFakeClock fake_global_clock;
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
EncodedImage encoded_image;
|
||||
CodecSpecificInfo codec_info;
|
||||
codec_info.codecType = kVideoCodecVP9;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
encoded_image.SetTimestamp(encoded_image.Timestamp() +
|
||||
90 * kInterframeDelayMs);
|
||||
encoded_image.SetSpatialIndex(0);
|
||||
@ -521,6 +558,9 @@ TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp9Svc) {
|
||||
encoded_image.SetSpatialIndex(1);
|
||||
codec_info.end_of_picture = true;
|
||||
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
|
||||
fake_global_clock.SetTime(
|
||||
Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
|
||||
}
|
||||
|
||||
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
|
||||
|
Reference in New Issue
Block a user