Add totalDecodeTime to RTCInboundRTPStreamStats
Pull request to WebRTC stats specification:
https://github.com/w3c/webrtc-stats/pull/450
Bug: webrtc:10775
Change-Id: Id032cb324724329fee284ebc84595b9c39208ab8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/144035
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28440}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index a178d54..1f8b973 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -443,6 +443,7 @@
RTCStatsMember<double> gap_discard_rate;
RTCStatsMember<uint32_t> frames_decoded;
RTCStatsMember<uint32_t> key_frames_decoded;
+ RTCStatsMember<double> total_decode_time;
// https://henbos.github.io/webrtc-provisional-stats/#dom-rtcinboundrtpstreamstats-contenttype
RTCStatsMember<std::string> content_type;
};
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index 8bd9982..4bc9b28 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -85,6 +85,8 @@
int render_delay_ms = 10;
int64_t interframe_delay_max_ms = -1;
uint32_t frames_decoded = 0;
+ // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totaldecodetime
+ uint64_t total_decode_time_ms = 0;
int64_t first_frame_received_to_decoded_ms = -1;
absl::optional<uint64_t> qp_sum;
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index 8a97022..80a7e11 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -601,6 +601,8 @@
uint32_t key_frames_decoded = 0;
uint32_t frames_rendered = 0;
absl::optional<uint64_t> qp_sum;
+ // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totaldecodetime
+ uint64_t total_decode_time_ms = 0;
int64_t interframe_delay_max_ms = -1;
uint32_t freeze_count = 0;
uint32_t pause_count = 0;
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 393fbc5..4400aef 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -2762,6 +2762,7 @@
info.key_frames_decoded = stats.frame_counts.key_frames;
info.frames_rendered = stats.frames_rendered;
info.qp_sum = stats.qp_sum;
+ info.total_decode_time_ms = stats.total_decode_time_ms;
info.last_packet_received_timestamp_ms =
stats.rtp_stats.last_packet_received_timestamp_ms;
info.first_frame_received_to_decoded_ms =
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index bedda07..3702064 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -5086,6 +5086,7 @@
stats.frames_rendered = 13;
stats.frames_decoded = 14;
stats.qp_sum = 15;
+ stats.total_decode_time_ms = 16;
stream->SetStats(stats);
cricket::VideoMediaInfo info;
@@ -5113,6 +5114,7 @@
EXPECT_EQ(rtc::checked_cast<unsigned int>(stats.frame_counts.key_frames),
info.receivers[0].key_frames_decoded);
EXPECT_EQ(stats.qp_sum, info.receivers[0].qp_sum);
+ EXPECT_EQ(stats.total_decode_time_ms, info.receivers[0].total_decode_time_ms);
}
TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesReceivePacketStatsCorrectly) {
diff --git a/modules/video_coding/frame_buffer2.cc b/modules/video_coding/frame_buffer2.cc
index d5df3ba..d969946 100644
--- a/modules/video_coding/frame_buffer2.cc
+++ b/modules/video_coding/frame_buffer2.cc
@@ -699,19 +699,18 @@
if (!stats_callback_)
return;
- int decode_ms;
int max_decode_ms;
int current_delay_ms;
int target_delay_ms;
int jitter_buffer_ms;
int min_playout_delay_ms;
int render_delay_ms;
- if (timing_->GetTimings(&decode_ms, &max_decode_ms, ¤t_delay_ms,
- &target_delay_ms, &jitter_buffer_ms,
- &min_playout_delay_ms, &render_delay_ms)) {
+ if (timing_->GetTimings(&max_decode_ms, ¤t_delay_ms, &target_delay_ms,
+ &jitter_buffer_ms, &min_playout_delay_ms,
+ &render_delay_ms)) {
stats_callback_->OnFrameBufferTimingsUpdated(
- decode_ms, max_decode_ms, current_delay_ms, target_delay_ms,
- jitter_buffer_ms, min_playout_delay_ms, render_delay_ms);
+ max_decode_ms, current_delay_ms, target_delay_ms, jitter_buffer_ms,
+ min_playout_delay_ms, render_delay_ms);
}
}
diff --git a/modules/video_coding/frame_buffer2_unittest.cc b/modules/video_coding/frame_buffer2_unittest.cc
index 083b89b..3182579 100644
--- a/modules/video_coding/frame_buffer2_unittest.cc
+++ b/modules/video_coding/frame_buffer2_unittest.cc
@@ -59,8 +59,7 @@
return render_time_ms - now_ms - kDecodeTime;
}
- bool GetTimings(int* decode_ms,
- int* max_decode_ms,
+ bool GetTimings(int* max_decode_ms,
int* current_delay_ms,
int* target_delay_ms,
int* jitter_buffer_ms,
@@ -70,16 +69,15 @@
}
int GetCurrentJitter() {
- int decode_ms;
int max_decode_ms;
int current_delay_ms;
int target_delay_ms;
int jitter_buffer_ms;
int min_playout_delay_ms;
int render_delay_ms;
- VCMTiming::GetTimings(&decode_ms, &max_decode_ms, ¤t_delay_ms,
- &target_delay_ms, &jitter_buffer_ms,
- &min_playout_delay_ms, &render_delay_ms);
+ VCMTiming::GetTimings(&max_decode_ms, ¤t_delay_ms, &target_delay_ms,
+ &jitter_buffer_ms, &min_playout_delay_ms,
+ &render_delay_ms);
return jitter_buffer_ms;
}
@@ -115,9 +113,8 @@
VideoContentType content_type));
MOCK_METHOD1(OnDiscardedPacketsUpdated, void(int discarded_packets));
MOCK_METHOD1(OnFrameCountsUpdated, void(const FrameCounts& frame_counts));
- MOCK_METHOD7(OnFrameBufferTimingsUpdated,
- void(int decode_ms,
- int max_decode_ms,
+ MOCK_METHOD6(OnFrameBufferTimingsUpdated,
+ void(int max_decode_ms,
int current_delay_ms,
int target_delay_ms,
int jitter_buffer_ms,
@@ -548,8 +545,7 @@
EXPECT_CALL(stats_callback_,
OnCompleteFrame(true, kFrameSize, VideoContentType::UNSPECIFIED));
- EXPECT_CALL(stats_callback_,
- OnFrameBufferTimingsUpdated(_, _, _, _, _, _, _));
+ EXPECT_CALL(stats_callback_, OnFrameBufferTimingsUpdated(_, _, _, _, _, _));
{
std::unique_ptr<FrameObjectFake> frame(new FrameObjectFake());
diff --git a/modules/video_coding/generic_decoder.cc b/modules/video_coding/generic_decoder.cc
index ab83119..0f928d2 100644
--- a/modules/video_coding/generic_decoder.cc
+++ b/modules/video_coding/generic_decoder.cc
@@ -91,8 +91,7 @@
if (!decode_time_ms) {
decode_time_ms = now_ms - frameInfo->decodeStartTimeMs;
}
- _timing->StopDecodeTimer(decodedImage.timestamp(), *decode_time_ms, now_ms,
- frameInfo->renderTimeMs);
+ _timing->StopDecodeTimer(*decode_time_ms, now_ms);
// Report timing information.
TimingFrameInfo timing_frame_info;
@@ -147,7 +146,8 @@
decodedImage.set_timestamp_us(frameInfo->renderTimeMs *
rtc::kNumMicrosecsPerMillisec);
- _receiveCallback->FrameToRender(decodedImage, qp, frameInfo->content_type);
+ _receiveCallback->FrameToRender(decodedImage, qp, *decode_time_ms,
+ frameInfo->content_type);
}
void VCMDecodedFrameCallback::OnDecoderImplementationName(
diff --git a/modules/video_coding/generic_decoder_unittest.cc b/modules/video_coding/generic_decoder_unittest.cc
index 691561d..93d55a6 100644
--- a/modules/video_coding/generic_decoder_unittest.cc
+++ b/modules/video_coding/generic_decoder_unittest.cc
@@ -30,6 +30,7 @@
public:
int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT
absl::optional<uint8_t> qp,
+ int32_t decode_time_ms,
VideoContentType content_type) override {
{
rtc::CritScope cs(&lock_);
diff --git a/modules/video_coding/include/mock/mock_vcm_callbacks.h b/modules/video_coding/include/mock/mock_vcm_callbacks.h
index d2d0378..76fc561 100644
--- a/modules/video_coding/include/mock/mock_vcm_callbacks.h
+++ b/modules/video_coding/include/mock/mock_vcm_callbacks.h
@@ -27,8 +27,9 @@
MockVCMReceiveCallback() {}
virtual ~MockVCMReceiveCallback() {}
- MOCK_METHOD3(FrameToRender,
- int32_t(VideoFrame&, absl::optional<uint8_t>, VideoContentType));
+ MOCK_METHOD4(
+ FrameToRender,
+ int32_t(VideoFrame&, absl::optional<uint8_t>, int32_t, VideoContentType));
MOCK_METHOD1(OnIncomingPayloadType, void(int));
MOCK_METHOD1(OnDecoderImplementationName, void(const char*));
};
diff --git a/modules/video_coding/include/video_coding_defines.h b/modules/video_coding/include/video_coding_defines.h
index b785734..043d8c6 100644
--- a/modules/video_coding/include/video_coding_defines.h
+++ b/modules/video_coding/include/video_coding_defines.h
@@ -51,9 +51,21 @@
// rendered.
class VCMReceiveCallback {
public:
+ // TODO(kron): Remove once downstream projects are updated.
virtual int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT
absl::optional<uint8_t> qp,
- VideoContentType content_type) = 0;
+ VideoContentType content_type) {
+ // Cannot be pure virtual since this should be removed from derived
+ // classes.
+ return FrameToRender(videoFrame, qp, 0, content_type);
+ }
+
+ virtual int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT
+ absl::optional<uint8_t> qp,
+ int32_t decode_time_ms,
+ VideoContentType content_type) {
+ return FrameToRender(videoFrame, qp, content_type);
+ }
// Called when the current receive codec changes.
virtual void OnIncomingPayloadType(int payload_type);
@@ -71,8 +83,7 @@
size_t size_bytes,
VideoContentType content_type) = 0;
- virtual void OnFrameBufferTimingsUpdated(int decode_ms,
- int max_decode_ms,
+ virtual void OnFrameBufferTimingsUpdated(int max_decode_ms,
int current_delay_ms,
int target_delay_ms,
int jitter_buffer_ms,
diff --git a/modules/video_coding/receiver_unittest.cc b/modules/video_coding/receiver_unittest.cc
index 5631166..ade26ca 100644
--- a/modules/video_coding/receiver_unittest.cc
+++ b/modules/video_coding/receiver_unittest.cc
@@ -454,7 +454,7 @@
int render_delay_ms;
int max_decode_ms;
int dummy;
- timing_.GetTimings(&dummy, &max_decode_ms, &dummy, &dummy, &dummy, &dummy,
+ timing_.GetTimings(&max_decode_ms, &dummy, &dummy, &dummy, &dummy,
&render_delay_ms);
// Construct test samples.
diff --git a/modules/video_coding/timing.cc b/modules/video_coding/timing.cc
index a2a4e47..8da2b85 100644
--- a/modules/video_coding/timing.cc
+++ b/modules/video_coding/timing.cc
@@ -28,7 +28,6 @@
max_playout_delay_ms_(10000),
jitter_delay_ms_(0),
current_delay_ms_(0),
- last_decode_ms_(0),
prev_frame_timestamp_(0),
timing_frame_info_(),
num_decoded_frames_(0) {
@@ -150,14 +149,17 @@
}
}
-void VCMTiming::StopDecodeTimer(uint32_t time_stamp,
+void VCMTiming::StopDecodeTimer(uint32_t /*time_stamp*/,
int32_t decode_time_ms,
int64_t now_ms,
- int64_t render_time_ms) {
+ int64_t /*render_time_ms*/) {
+ StopDecodeTimer(decode_time_ms, now_ms);
+}
+
+void VCMTiming::StopDecodeTimer(int32_t decode_time_ms, int64_t now_ms) {
rtc::CritScope cs(&crit_sect_);
codec_timer_->AddTiming(decode_time_ms, now_ms);
assert(decode_time_ms >= 0);
- last_decode_ms_ = decode_time_ms;
++num_decoded_frames_;
}
@@ -217,15 +219,13 @@
jitter_delay_ms_ + RequiredDecodeTimeMs() + render_delay_ms_);
}
-bool VCMTiming::GetTimings(int* decode_ms,
- int* max_decode_ms,
+bool VCMTiming::GetTimings(int* max_decode_ms,
int* current_delay_ms,
int* target_delay_ms,
int* jitter_buffer_ms,
int* min_playout_delay_ms,
int* render_delay_ms) const {
rtc::CritScope cs(&crit_sect_);
- *decode_ms = last_decode_ms_;
*max_decode_ms = RequiredDecodeTimeMs();
*current_delay_ms = current_delay_ms_;
*target_delay_ms = TargetDelayInternal();
diff --git a/modules/video_coding/timing.h b/modules/video_coding/timing.h
index c70410e..764f0be 100644
--- a/modules/video_coding/timing.h
+++ b/modules/video_coding/timing.h
@@ -61,6 +61,9 @@
// Stops the decoder timer, should be called when the decoder returns a frame
// or when the decoded frame callback is called.
+ void StopDecodeTimer(int32_t decode_time_ms, int64_t now_ms);
+ // TODO(kron): Remove once downstream projects has been changed to use the
+ // above function.
void StopDecodeTimer(uint32_t time_stamp,
int32_t decode_time_ms,
int64_t now_ms,
@@ -85,8 +88,7 @@
// Return current timing information. Returns true if the first frame has been
// decoded, false otherwise.
- virtual bool GetTimings(int* decode_ms,
- int* max_decode_ms,
+ virtual bool GetTimings(int* max_decode_ms,
int* current_delay_ms,
int* target_delay_ms,
int* jitter_buffer_ms,
@@ -121,7 +123,6 @@
int max_playout_delay_ms_ RTC_GUARDED_BY(crit_sect_);
int jitter_delay_ms_ RTC_GUARDED_BY(crit_sect_);
int current_delay_ms_ RTC_GUARDED_BY(crit_sect_);
- int last_decode_ms_ RTC_GUARDED_BY(crit_sect_);
uint32_t prev_frame_timestamp_ RTC_GUARDED_BY(crit_sect_);
absl::optional<TimingFrameInfo> timing_frame_info_ RTC_GUARDED_BY(crit_sect_);
size_t num_decoded_frames_ RTC_GUARDED_BY(crit_sect_);
diff --git a/modules/video_coding/timing_unittest.cc b/modules/video_coding/timing_unittest.cc
index b9397ea..40e8c97 100644
--- a/modules/video_coding/timing_unittest.cc
+++ b/modules/video_coding/timing_unittest.cc
@@ -75,9 +75,7 @@
const uint32_t kDecodeTimeMs = 10;
for (int i = 0; i < kFps; i++) {
clock.AdvanceTimeMilliseconds(kDecodeTimeMs);
- timing.StopDecodeTimer(
- timestamp, kDecodeTimeMs, clock.TimeInMilliseconds(),
- timing.RenderTimeMs(timestamp, clock.TimeInMilliseconds()));
+ timing.StopDecodeTimer(kDecodeTimeMs, clock.TimeInMilliseconds());
timestamp += 90000 / kFps;
clock.AdvanceTimeMilliseconds(1000 / kFps - kDecodeTimeMs);
timing.IncomingTimestamp(timestamp, clock.TimeInMilliseconds());
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index fb85092..ec917ae 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -312,6 +312,9 @@
inbound_video->key_frames_decoded = video_receiver_info.key_frames_decoded;
if (video_receiver_info.qp_sum)
inbound_video->qp_sum = *video_receiver_info.qp_sum;
+ inbound_video->total_decode_time =
+ static_cast<double>(video_receiver_info.total_decode_time_ms) /
+ rtc::kNumMillisecsPerSec;
if (video_receiver_info.last_packet_received_timestamp_ms) {
inbound_video->last_packet_received_timestamp =
static_cast<double>(
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 2f0e78b..963a3bc 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -1803,6 +1803,7 @@
video_media_info.receivers[0].frames_decoded = 8;
video_media_info.receivers[0].key_frames_decoded = 3;
video_media_info.receivers[0].qp_sum = absl::nullopt;
+ video_media_info.receivers[0].total_decode_time_ms = 9000;
video_media_info.receivers[0].last_packet_received_timestamp_ms =
absl::nullopt;
video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
@@ -1840,6 +1841,7 @@
expected_video.frames_decoded = 8;
expected_video.key_frames_decoded = 3;
// |expected_video.qp_sum| should be undefined.
+ expected_video.total_decode_time = 9.0;
// |expected_video.last_packet_received_timestamp| should be undefined.
// |expected_video.content_type| should be undefined.
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index 79d6faf..a05fa0e 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -805,12 +805,15 @@
*inbound_stream.media_type == "video") {
verifier.TestMemberIsDefined(inbound_stream.frames_decoded);
verifier.TestMemberIsDefined(inbound_stream.key_frames_decoded);
+ verifier.TestMemberIsNonNegative<double>(
+ inbound_stream.total_decode_time);
// The integration test is not set up to test screen share; don't require
// this to be present.
verifier.MarkMemberTested(inbound_stream.content_type, true);
} else {
verifier.TestMemberIsUndefined(inbound_stream.frames_decoded);
verifier.TestMemberIsUndefined(inbound_stream.key_frames_decoded);
+ verifier.TestMemberIsUndefined(inbound_stream.total_decode_time);
verifier.TestMemberIsUndefined(inbound_stream.content_type);
}
return verifier.ExpectAllMembersSuccessfullyTested();
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index 2b62990..949e74c 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -615,6 +615,7 @@
&gap_discard_rate,
&frames_decoded,
&key_frames_decoded,
+ &total_decode_time,
&content_type)
// clang-format on
@@ -645,6 +646,7 @@
gap_discard_rate("gapDiscardRate"),
frames_decoded("framesDecoded"),
key_frames_decoded("keyFramesDecoded"),
+ total_decode_time("totalDecodeTime"),
content_type("contentType") {}
RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(
@@ -670,6 +672,7 @@
gap_discard_rate(other.gap_discard_rate),
frames_decoded(other.frames_decoded),
key_frames_decoded(other.key_frames_decoded),
+ total_decode_time(other.total_decode_time),
content_type(other.content_type) {}
RTCInboundRTPStreamStats::~RTCInboundRTPStreamStats() {}
diff --git a/video/receive_statistics_proxy.cc b/video/receive_statistics_proxy.cc
index 49ae0d5..6c9d121 100644
--- a/video/receive_statistics_proxy.cc
+++ b/video/receive_statistics_proxy.cc
@@ -615,7 +615,6 @@
}
void ReceiveStatisticsProxy::OnFrameBufferTimingsUpdated(
- int decode_ms,
int max_decode_ms,
int current_delay_ms,
int target_delay_ms,
@@ -623,14 +622,12 @@
int min_playout_delay_ms,
int render_delay_ms) {
rtc::CritScope lock(&crit_);
- stats_.decode_ms = decode_ms;
stats_.max_decode_ms = max_decode_ms;
stats_.current_delay_ms = current_delay_ms;
stats_.target_delay_ms = target_delay_ms;
stats_.jitter_buffer_ms = jitter_buffer_ms;
stats_.min_playout_delay_ms = min_playout_delay_ms;
stats_.render_delay_ms = render_delay_ms;
- decode_time_counter_.Add(decode_ms);
jitter_buffer_delay_counter_.Add(jitter_buffer_ms);
target_delay_counter_.Add(target_delay_ms);
current_delay_counter_.Add(current_delay_ms);
@@ -723,6 +720,7 @@
void ReceiveStatisticsProxy::OnDecodedFrame(const VideoFrame& frame,
absl::optional<uint8_t> qp,
+ int32_t decode_time_ms,
VideoContentType content_type) {
rtc::CritScope lock(&crit_);
@@ -745,7 +743,6 @@
if (stats_.frames_decoded != 1) {
RTC_LOG(LS_WARNING)
<< "Frames decoded was not 1 when first qp value was received.";
- stats_.frames_decoded = 1;
}
stats_.qp_sum = 0;
}
@@ -754,8 +751,10 @@
} else if (stats_.qp_sum) {
RTC_LOG(LS_WARNING)
<< "QP sum was already set and no QP was given for a frame.";
- stats_.qp_sum = absl::nullopt;
}
+ decode_time_counter_.Add(decode_time_ms);
+ stats_.decode_ms = decode_time_ms;
+ stats_.total_decode_time_ms += decode_time_ms;
last_content_type_ = content_type;
decode_fps_estimator_.Update(1, now_ms);
if (last_decoded_frame_time_ms_) {
diff --git a/video/receive_statistics_proxy.h b/video/receive_statistics_proxy.h
index 6eb9d48..8aa8f5e 100644
--- a/video/receive_statistics_proxy.h
+++ b/video/receive_statistics_proxy.h
@@ -51,6 +51,7 @@
void OnDecodedFrame(const VideoFrame& frame,
absl::optional<uint8_t> qp,
+ int32_t decode_time_ms,
VideoContentType content_type);
void OnSyncOffsetUpdated(int64_t sync_offset_ms, double estimated_freq_khz);
void OnRenderedFrame(const VideoFrame& frame);
@@ -68,8 +69,7 @@
void OnCompleteFrame(bool is_keyframe,
size_t size_bytes,
VideoContentType content_type) override;
- void OnFrameBufferTimingsUpdated(int decode_ms,
- int max_decode_ms,
+ void OnFrameBufferTimingsUpdated(int max_decode_ms,
int current_delay_ms,
int target_delay_ms,
int jitter_buffer_ms,
diff --git a/video/receive_statistics_proxy_unittest.cc b/video/receive_statistics_proxy_unittest.cc
index b8293aa..dbd6ccf 100644
--- a/video/receive_statistics_proxy_unittest.cc
+++ b/video/receive_statistics_proxy_unittest.cc
@@ -88,7 +88,7 @@
EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (uint32_t i = 1; i <= 3; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
EXPECT_EQ(i, statistics_proxy_->GetStats().frames_decoded);
}
@@ -99,7 +99,7 @@
const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
}
@@ -113,7 +113,7 @@
const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kRequiredSamples - 1; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
}
@@ -121,58 +121,67 @@
EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
}
-TEST_F(ReceiveStatisticsProxyTest, DecodedFpsIsReportedWithQpReset) {
- const int kFps1 = 10;
- webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
- for (int i = 0; i < metrics::kMinRunTimeInSeconds * kFps1; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
- VideoContentType::UNSPECIFIED);
- fake_clock_.AdvanceTimeMilliseconds(1000 / kFps1);
- }
- // First QP value received, resets frames decoded.
- const int kFps2 = 20;
- for (int i = 0; i < metrics::kMinRunTimeInSeconds * kFps2; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, 1u, VideoContentType::UNSPECIFIED);
- fake_clock_.AdvanceTimeMilliseconds(1000 / kFps2);
- }
- statistics_proxy_.reset();
- EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
- EXPECT_EQ(1,
- metrics::NumEvents("WebRTC.Video.DecodedFramesPerSecond", kFps2));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameWithQpResetsFramesDecoded) {
+TEST_F(ReceiveStatisticsProxyTest,
+ OnDecodedFrameWithQpDoesNotResetFramesDecodedOrTotalDecodeTime) {
EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
+ unsigned int expected_total_decode_time_ms = 0;
+ unsigned int expected_frames_decoded = 0;
for (uint32_t i = 1; i <= 3; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 1,
VideoContentType::UNSPECIFIED);
- EXPECT_EQ(i, statistics_proxy_->GetStats().frames_decoded);
+ expected_total_decode_time_ms += 1;
+ ++expected_frames_decoded;
+ EXPECT_EQ(expected_frames_decoded,
+ statistics_proxy_->GetStats().frames_decoded);
+ EXPECT_EQ(expected_total_decode_time_ms,
+ statistics_proxy_->GetStats().total_decode_time_ms);
}
- statistics_proxy_->OnDecodedFrame(frame, 1u, VideoContentType::UNSPECIFIED);
- EXPECT_EQ(1u, statistics_proxy_->GetStats().frames_decoded);
+ statistics_proxy_->OnDecodedFrame(frame, 1u, 3,
+ VideoContentType::UNSPECIFIED);
+ ++expected_frames_decoded;
+ expected_total_decode_time_ms += 3;
+ EXPECT_EQ(expected_frames_decoded,
+ statistics_proxy_->GetStats().frames_decoded);
+ EXPECT_EQ(expected_total_decode_time_ms,
+ statistics_proxy_->GetStats().total_decode_time_ms);
}
TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameIncreasesQpSum) {
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
- statistics_proxy_->OnDecodedFrame(frame, 3u, VideoContentType::UNSPECIFIED);
+ statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
+ VideoContentType::UNSPECIFIED);
EXPECT_EQ(3u, statistics_proxy_->GetStats().qp_sum);
- statistics_proxy_->OnDecodedFrame(frame, 127u, VideoContentType::UNSPECIFIED);
+ statistics_proxy_->OnDecodedFrame(frame, 127u, 0,
+ VideoContentType::UNSPECIFIED);
EXPECT_EQ(130u, statistics_proxy_->GetStats().qp_sum);
}
+TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameIncreasesTotalDecodeTime) {
+ EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
+ webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
+ statistics_proxy_->OnDecodedFrame(frame, 3u, 4,
+ VideoContentType::UNSPECIFIED);
+ EXPECT_EQ(4u, statistics_proxy_->GetStats().total_decode_time_ms);
+ statistics_proxy_->OnDecodedFrame(frame, 127u, 7,
+ VideoContentType::UNSPECIFIED);
+ EXPECT_EQ(11u, statistics_proxy_->GetStats().total_decode_time_ms);
+}
+
TEST_F(ReceiveStatisticsProxyTest, ReportsContentType) {
const std::string kRealtimeString("realtime");
const std::string kScreenshareString("screen");
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString(
statistics_proxy_->GetStats().content_type));
- statistics_proxy_->OnDecodedFrame(frame, 3u, VideoContentType::SCREENSHARE);
+ statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
+ VideoContentType::SCREENSHARE);
EXPECT_EQ(kScreenshareString,
videocontenttypehelpers::ToString(
statistics_proxy_->GetStats().content_type));
- statistics_proxy_->OnDecodedFrame(frame, 3u, VideoContentType::UNSPECIFIED);
+ statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
+ VideoContentType::UNSPECIFIED);
EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString(
statistics_proxy_->GetStats().content_type));
}
@@ -183,24 +192,24 @@
const int64_t kInterframeDelayMs2 = 200;
const int64_t kInterframeDelayMs3 = 100;
EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
EXPECT_EQ(kInterframeDelayMs1,
statistics_proxy_->GetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
EXPECT_EQ(kInterframeDelayMs2,
statistics_proxy_->GetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// kInterframeDelayMs3 is smaller than kInterframeDelayMs2.
EXPECT_EQ(kInterframeDelayMs2,
@@ -213,25 +222,25 @@
const int64_t kInterframeDelayMs2 = 750;
const int64_t kInterframeDelayMs3 = 700;
EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
EXPECT_EQ(kInterframeDelayMs1,
statistics_proxy_->GetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// Still first delay is the maximum
EXPECT_EQ(kInterframeDelayMs1,
statistics_proxy_->GetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// Now the first sample is out of the window, so the second is the maximum.
EXPECT_EQ(kInterframeDelayMs2,
@@ -342,19 +351,20 @@
TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameWithoutQpQpSumWontExist) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
}
-TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameWithoutQpResetsQpSum) {
+TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameWithoutQpDoesNotResetQpSum) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
- statistics_proxy_->OnDecodedFrame(frame, 3u, VideoContentType::UNSPECIFIED);
- EXPECT_EQ(3u, statistics_proxy_->GetStats().qp_sum);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
VideoContentType::UNSPECIFIED);
- EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
+ EXPECT_EQ(3u, statistics_proxy_->GetStats().qp_sum);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
+ VideoContentType::UNSPECIFIED);
+ EXPECT_EQ(3u, statistics_proxy_->GetStats().qp_sum);
}
TEST_F(ReceiveStatisticsProxyTest, OnRenderedFrameIncreasesFramesRendered) {
@@ -394,7 +404,6 @@
}
TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsDecodeTimingStats) {
- const int kDecodeMs = 1;
const int kMaxDecodeMs = 2;
const int kCurrentDelayMs = 3;
const int kTargetDelayMs = 4;
@@ -404,10 +413,9 @@
const int64_t kRttMs = 8;
statistics_proxy_->OnRttUpdate(kRttMs, 0);
statistics_proxy_->OnFrameBufferTimingsUpdated(
- kDecodeMs, kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
+ kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
kMinPlayoutDelayMs, kRenderDelayMs);
VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
- EXPECT_EQ(kDecodeMs, stats.decode_ms);
EXPECT_EQ(kMaxDecodeMs, stats.max_decode_ms);
EXPECT_EQ(kCurrentDelayMs, stats.current_delay_ms);
EXPECT_EQ(kTargetDelayMs, stats.target_delay_ms);
@@ -774,7 +782,6 @@
}
TEST_F(ReceiveStatisticsProxyTest, TimingHistogramsNotUpdatedForTooFewSamples) {
- const int kDecodeMs = 1;
const int kMaxDecodeMs = 2;
const int kCurrentDelayMs = 3;
const int kTargetDelayMs = 4;
@@ -784,8 +791,8 @@
for (int i = 0; i < kMinRequiredSamples - 1; ++i) {
statistics_proxy_->OnFrameBufferTimingsUpdated(
- kDecodeMs, kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs,
- kJitterBufferMs, kMinPlayoutDelayMs, kRenderDelayMs);
+ kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
+ kMinPlayoutDelayMs, kRenderDelayMs);
}
statistics_proxy_.reset();
@@ -797,7 +804,6 @@
}
TEST_F(ReceiveStatisticsProxyTest, TimingHistogramsAreUpdated) {
- const int kDecodeMs = 1;
const int kMaxDecodeMs = 2;
const int kCurrentDelayMs = 3;
const int kTargetDelayMs = 4;
@@ -807,18 +813,16 @@
for (int i = 0; i < kMinRequiredSamples; ++i) {
statistics_proxy_->OnFrameBufferTimingsUpdated(
- kDecodeMs, kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs,
- kJitterBufferMs, kMinPlayoutDelayMs, kRenderDelayMs);
+ kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
+ kMinPlayoutDelayMs, kRenderDelayMs);
}
statistics_proxy_.reset();
- EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DecodeTimeInMs"));
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
- EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DecodeTimeInMs", kDecodeMs));
EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.JitterBufferDelayInMs",
kJitterBufferMs));
EXPECT_EQ(1,
@@ -837,7 +841,7 @@
// Since OnRenderedFrame is never called the fps in each sample will be 0,
// i.e. bad
frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
statistics_proxy_->OnRenderedFrame(frame);
fake_clock_.AdvanceTimeMilliseconds(1000 / kDefaultFps);
@@ -893,7 +897,7 @@
TEST_F(ReceiveStatisticsProxyTest, ZeroDelayReportedIfFrameNotDelayed) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// Frame not delayed, delayed frames to render: 0%.
@@ -912,7 +916,7 @@
TEST_F(ReceiveStatisticsProxyTest,
DelayedFrameHistogramsAreNotUpdatedIfMinRuntimeHasNotPassed) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// Frame not delayed, delayed frames to render: 0%.
@@ -931,7 +935,7 @@
TEST_F(ReceiveStatisticsProxyTest,
DelayedFramesHistogramsAreNotUpdatedIfNoRenderedFrames) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// Min run time has passed. No rendered frames.
@@ -944,7 +948,7 @@
TEST_F(ReceiveStatisticsProxyTest, DelayReportedIfFrameIsDelayed) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// Frame delayed 1 ms, delayed frames to render: 100%.
@@ -964,7 +968,7 @@
TEST_F(ReceiveStatisticsProxyTest, AverageDelayOfDelayedFramesIsReported) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
VideoContentType::UNSPECIFIED);
// Two frames delayed (6 ms, 10 ms), delayed frames to render: 50%.
@@ -1099,12 +1103,12 @@
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
// One extra with double the interval.
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_.reset();
const int kExpectedInterFrame =
@@ -1134,16 +1138,16 @@
for (int i = 0; i <= kMinRequiredSamples - kLastFivePercentsSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
}
// Last 5% of intervals are double in size.
for (int i = 0; i < kLastFivePercentsSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(2 * kInterFrameDelayMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
}
// Final sample is outlier and 10 times as big.
fake_clock_.AdvanceTimeMilliseconds(10 * kInterFrameDelayMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_.reset();
const int kExpectedInterFrame = kInterFrameDelayMs * 2;
@@ -1164,7 +1168,7 @@
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
@@ -1184,7 +1188,7 @@
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i <= kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
@@ -1195,9 +1199,9 @@
// Insert two more frames. The interval during the pause should be disregarded
// in the stats.
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_.reset();
if (videocontenttypehelpers::IsScreenshare(content_type_)) {
@@ -1229,13 +1233,13 @@
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
// Add extra freeze.
fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
statistics_proxy_.reset();
@@ -1272,20 +1276,20 @@
for (int i = 0; i < kMinRequiredSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
}
// Freezes and pauses should be included into harmonic frame rate.
// Add freeze.
fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
// Add pause.
fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
statistics_proxy_->OnStreamInactive();
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
statistics_proxy_.reset();
@@ -1313,7 +1317,7 @@
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i <= kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
@@ -1323,7 +1327,7 @@
// Second playback interval with triple the length.
for (int i = 0; i <= kMinRequiredSamples * 3; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
@@ -1351,13 +1355,13 @@
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i <= kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
statistics_proxy_->OnStreamInactive();
fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
@@ -1378,13 +1382,15 @@
// HD frames.
for (int i = 0; i < kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, 0,
+ content_type_);
statistics_proxy_->OnRenderedFrame(frame_hd);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
// SD frames.
for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame_sd, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame_sd, absl::nullopt, 0,
+ content_type_);
statistics_proxy_->OnRenderedFrame(frame_sd);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
@@ -1411,18 +1417,18 @@
// High quality frames.
for (int i = 0; i < kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, kLowQp, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, kLowQp, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
// Blocky frames.
for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
- statistics_proxy_->OnDecodedFrame(frame, kHighQp, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
}
// Extra last frame.
- statistics_proxy_->OnDecodedFrame(frame, kHighQp, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame);
statistics_proxy_.reset();
@@ -1445,7 +1451,7 @@
webrtc::VideoFrame frame_ld = CreateFrame(320, 180);
// Call once to pass content type.
- statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, content_type_);
+ statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, 0, content_type_);
statistics_proxy_->OnRenderedFrame(frame_hd);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
@@ -1472,6 +1478,21 @@
}
}
+TEST_P(ReceiveStatisticsProxyTestWithContent, DecodeTimeReported) {
+ const int kInterFrameDelayMs = 20;
+ const int kLowQp = 30;
+ const int kDecodeMs = 7;
+
+ webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
+
+ for (int i = 0; i < kMinRequiredSamples; ++i) {
+ statistics_proxy_->OnDecodedFrame(frame, kLowQp, kDecodeMs, content_type_);
+ fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
+ }
+ statistics_proxy_.reset();
+ EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DecodeTimeInMs", kDecodeMs));
+}
+
TEST_P(ReceiveStatisticsProxyTestWithContent,
StatsAreSlicedOnSimulcastAndExperiment) {
const uint8_t experiment_id = 1;
@@ -1484,13 +1505,13 @@
videocontenttypehelpers::SetSimulcastId(&content_type, 1);
for (int i = 0; i <= kMinRequiredSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs1);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
}
videocontenttypehelpers::SetSimulcastId(&content_type, 2);
for (int i = 0; i <= kMinRequiredSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs2);
- statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type);
+ statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
}
statistics_proxy_.reset();
diff --git a/video/video_stream_decoder.cc b/video/video_stream_decoder.cc
index 0c4eeeb..c523a47 100644
--- a/video/video_stream_decoder.cc
+++ b/video/video_stream_decoder.cc
@@ -44,8 +44,10 @@
// Release. Acquiring the same lock in the path of decode callback can deadlock.
int32_t VideoStreamDecoder::FrameToRender(VideoFrame& video_frame,
absl::optional<uint8_t> qp,
+ int32_t decode_time_ms,
VideoContentType content_type) {
- receive_stats_callback_->OnDecodedFrame(video_frame, qp, content_type);
+ receive_stats_callback_->OnDecodedFrame(video_frame, qp, decode_time_ms,
+ content_type);
incoming_video_stream_->OnFrame(video_frame);
return 0;
}
diff --git a/video/video_stream_decoder.h b/video/video_stream_decoder.h
index 50b0c8c..b8ad933d 100644
--- a/video/video_stream_decoder.h
+++ b/video/video_stream_decoder.h
@@ -42,6 +42,7 @@
// Implements VCMReceiveCallback.
int32_t FrameToRender(VideoFrame& video_frame,
absl::optional<uint8_t> qp,
+ int32_t decode_time_ms,
VideoContentType content_type) override;
void OnIncomingPayloadType(int payload_type) override;
void OnDecoderImplementationName(const char* implementation_name) override;
diff --git a/video/video_stream_decoder_impl.cc b/video/video_stream_decoder_impl.cc
index b4ae848..003f230 100644
--- a/video/video_stream_decoder_impl.cc
+++ b/video/video_stream_decoder_impl.cc
@@ -277,8 +277,7 @@
absl::optional<int> casted_decode_time_ms(decode_time_ms.value_or(
decode_stop_time_ms - frame_timestamps->decode_start_time_ms));
- timing_.StopDecodeTimer(0, *casted_decode_time_ms, decode_stop_time_ms,
- frame_timestamps->render_time_us / 1000);
+ timing_.StopDecodeTimer(*casted_decode_time_ms, decode_stop_time_ms);
VideoFrame copy = decoded_image;
copy.set_timestamp_us(frame_timestamps->render_time_us);