measure decode time in TimeDelta instead of ms

increasing precision since summing up rounded values leads to
a rounding error, in particular for small frames which take very
little time to decode.

BUG=webrtc:12526,webrtc:13756

Change-Id: I647c702808856a002c746ed9f115aa9bcaddc1f3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/262810
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Philipp Hancke <philipp.hancke@googlemail.com>
Cr-Commit-Position: refs/heads/main@{#37249}
This commit is contained in:
Philipp Hancke 2022-06-17 07:34:23 +02:00 committed by WebRTC LUCI CQ
parent c374d11fac
commit d970b0901b
16 changed files with 131 additions and 105 deletions

View File

@ -105,7 +105,7 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface {
uint32_t frames_dropped = 0; uint32_t frames_dropped = 0;
uint32_t frames_decoded = 0; uint32_t frames_decoded = 0;
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totaldecodetime // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totaldecodetime
uint64_t total_decode_time_ms = 0; webrtc::TimeDelta total_decode_time = webrtc::TimeDelta::Millis(0);
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay
webrtc::TimeDelta total_processing_delay = webrtc::TimeDelta::Millis(0); webrtc::TimeDelta total_processing_delay = webrtc::TimeDelta::Millis(0);
// TODO(bugs.webrtc.org/13986): standardize // TODO(bugs.webrtc.org/13986): standardize

View File

@ -620,7 +620,7 @@ struct VideoReceiverInfo : public MediaReceiverInfo {
uint32_t frames_rendered = 0; uint32_t frames_rendered = 0;
absl::optional<uint64_t> qp_sum; absl::optional<uint64_t> qp_sum;
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totaldecodetime // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totaldecodetime
uint64_t total_decode_time_ms = 0; webrtc::TimeDelta total_decode_time = webrtc::TimeDelta::Millis(0);
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay
webrtc::TimeDelta total_processing_delay = webrtc::TimeDelta::Millis(0); webrtc::TimeDelta total_processing_delay = webrtc::TimeDelta::Millis(0);
webrtc::TimeDelta total_assembly_time = webrtc::TimeDelta::Millis(0); webrtc::TimeDelta total_assembly_time = webrtc::TimeDelta::Millis(0);

View File

@ -3208,7 +3208,7 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::GetVideoReceiverInfo(
info.key_frames_decoded = stats.frame_counts.key_frames; info.key_frames_decoded = stats.frame_counts.key_frames;
info.frames_rendered = stats.frames_rendered; info.frames_rendered = stats.frames_rendered;
info.qp_sum = stats.qp_sum; info.qp_sum = stats.qp_sum;
info.total_decode_time_ms = stats.total_decode_time_ms; info.total_decode_time = stats.total_decode_time;
info.total_processing_delay = stats.total_processing_delay; info.total_processing_delay = stats.total_processing_delay;
info.total_assembly_time = stats.total_assembly_time; info.total_assembly_time = stats.total_assembly_time;
info.frames_assembled_from_multiple_packets = info.frames_assembled_from_multiple_packets =

View File

@ -6152,7 +6152,7 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesDecodeStatsCorrectly) {
stats.frames_rendered = 13; stats.frames_rendered = 13;
stats.frames_decoded = 14; stats.frames_decoded = 14;
stats.qp_sum = 15; stats.qp_sum = 15;
stats.total_decode_time_ms = 16; stats.total_decode_time = webrtc::TimeDelta::Millis(16);
stats.total_assembly_time = webrtc::TimeDelta::Millis(4); stats.total_assembly_time = webrtc::TimeDelta::Millis(4);
stats.frames_assembled_from_multiple_packets = 2; stats.frames_assembled_from_multiple_packets = 2;
stream->SetStats(stats); stream->SetStats(stats);
@ -6182,7 +6182,7 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesDecodeStatsCorrectly) {
EXPECT_EQ(rtc::checked_cast<unsigned int>(stats.frame_counts.key_frames), EXPECT_EQ(rtc::checked_cast<unsigned int>(stats.frame_counts.key_frames),
info.receivers[0].key_frames_decoded); info.receivers[0].key_frames_decoded);
EXPECT_EQ(stats.qp_sum, info.receivers[0].qp_sum); EXPECT_EQ(stats.qp_sum, info.receivers[0].qp_sum);
EXPECT_EQ(stats.total_decode_time_ms, info.receivers[0].total_decode_time_ms); EXPECT_EQ(stats.total_decode_time, info.receivers[0].total_decode_time);
EXPECT_EQ(stats.total_assembly_time, info.receivers[0].total_assembly_time); EXPECT_EQ(stats.total_assembly_time, info.receivers[0].total_assembly_time);
EXPECT_EQ(stats.frames_assembled_from_multiple_packets, EXPECT_EQ(stats.frames_assembled_from_multiple_packets,
info.receivers[0].frames_assembled_from_multiple_packets); info.receivers[0].frames_assembled_from_multiple_packets);

View File

@ -174,7 +174,7 @@ void VCMDecodedFrameCallback::Decoded(VideoFrame& decodedImage,
decodedImage.set_timestamp_us(frameInfo->renderTimeMs * decodedImage.set_timestamp_us(frameInfo->renderTimeMs *
rtc::kNumMicrosecsPerMillisec); rtc::kNumMicrosecsPerMillisec);
_receiveCallback->FrameToRender(decodedImage, qp, decode_time.ms(), _receiveCallback->FrameToRender(decodedImage, qp, decode_time,
frameInfo->content_type); frameInfo->content_type);
} }

View File

@ -33,7 +33,7 @@ class ReceiveCallback : public VCMReceiveCallback {
public: public:
int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, TimeDelta decode_time,
VideoContentType content_type) override { VideoContentType content_type) override {
{ {
MutexLock lock(&lock_); MutexLock lock(&lock_);

View File

@ -51,7 +51,7 @@ class VCMReceiveCallback {
public: public:
virtual int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT virtual int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, TimeDelta decode_time,
VideoContentType content_type) = 0; VideoContentType content_type) = 0;
virtual void OnDroppedFrames(uint32_t frames_dropped); virtual void OnDroppedFrames(uint32_t frames_dropped);

View File

@ -38,9 +38,10 @@ class MockVCMReceiveCallback : public VCMReceiveCallback {
MockVCMReceiveCallback() {} MockVCMReceiveCallback() {}
virtual ~MockVCMReceiveCallback() {} virtual ~MockVCMReceiveCallback() {}
MOCK_METHOD(int32_t, MOCK_METHOD(
int32_t,
FrameToRender, FrameToRender,
(VideoFrame&, absl::optional<uint8_t>, int32_t, VideoContentType), (VideoFrame&, absl::optional<uint8_t>, TimeDelta, VideoContentType),
(override)); (override));
MOCK_METHOD(void, OnIncomingPayloadType, (int), (override)); MOCK_METHOD(void, OnIncomingPayloadType, (int), (override));
MOCK_METHOD(void, OnDecoderImplementationName, (const char*), (override)); MOCK_METHOD(void, OnDecoderImplementationName, (const char*), (override));

View File

@ -556,7 +556,7 @@ void SetInboundRTPStreamStatsFromVideoReceiverInfo(
if (video_receiver_info.qp_sum) if (video_receiver_info.qp_sum)
inbound_video->qp_sum = *video_receiver_info.qp_sum; inbound_video->qp_sum = *video_receiver_info.qp_sum;
inbound_video->total_decode_time = inbound_video->total_decode_time =
static_cast<double>(video_receiver_info.total_decode_time_ms) / static_cast<double>(video_receiver_info.total_decode_time.ms()) /
rtc::kNumMillisecsPerSec; rtc::kNumMillisecsPerSec;
inbound_video->total_processing_delay = inbound_video->total_processing_delay =
static_cast<double>(video_receiver_info.total_processing_delay.ms()) / static_cast<double>(video_receiver_info.total_processing_delay.ms()) /

View File

@ -2168,7 +2168,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
video_media_info.receivers[0].key_frames_decoded = 3; video_media_info.receivers[0].key_frames_decoded = 3;
video_media_info.receivers[0].frames_dropped = 13; video_media_info.receivers[0].frames_dropped = 13;
video_media_info.receivers[0].qp_sum = absl::nullopt; video_media_info.receivers[0].qp_sum = absl::nullopt;
video_media_info.receivers[0].total_decode_time_ms = 9000; video_media_info.receivers[0].total_decode_time =
webrtc::TimeDelta::Seconds(9);
video_media_info.receivers[0].total_processing_delay = video_media_info.receivers[0].total_processing_delay =
webrtc::TimeDelta::Millis(600); webrtc::TimeDelta::Millis(600);
video_media_info.receivers[0].total_assembly_time = video_media_info.receivers[0].total_assembly_time =

View File

@ -828,7 +828,7 @@ void ReceiveStatisticsProxy::OnCname(uint32_t ssrc, absl::string_view cname) {
void ReceiveStatisticsProxy::OnDecodedFrame(const VideoFrame& frame, void ReceiveStatisticsProxy::OnDecodedFrame(const VideoFrame& frame,
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, TimeDelta decode_time,
VideoContentType content_type) { VideoContentType content_type) {
webrtc::TimeDelta processing_delay = webrtc::TimeDelta::Millis(0); webrtc::TimeDelta processing_delay = webrtc::TimeDelta::Millis(0);
webrtc::Timestamp current_time = clock_->CurrentTime(); webrtc::Timestamp current_time = clock_->CurrentTime();
@ -853,17 +853,17 @@ void ReceiveStatisticsProxy::OnDecodedFrame(const VideoFrame& frame,
// "com.apple.coremedia.decompressionsession.clientcallback" // "com.apple.coremedia.decompressionsession.clientcallback"
VideoFrameMetaData meta(frame, current_time); VideoFrameMetaData meta(frame, current_time);
worker_thread_->PostTask( worker_thread_->PostTask(
ToQueuedTask(task_safety_, [meta, qp, decode_time_ms, processing_delay, ToQueuedTask(task_safety_, [meta, qp, decode_time, processing_delay,
assembly_time, content_type, this]() { assembly_time, content_type, this]() {
OnDecodedFrame(meta, qp, decode_time_ms, processing_delay, OnDecodedFrame(meta, qp, decode_time, processing_delay, assembly_time,
assembly_time, content_type); content_type);
})); }));
} }
void ReceiveStatisticsProxy::OnDecodedFrame( void ReceiveStatisticsProxy::OnDecodedFrame(
const VideoFrameMetaData& frame_meta, const VideoFrameMetaData& frame_meta,
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, TimeDelta decode_time,
webrtc::TimeDelta processing_delay, webrtc::TimeDelta processing_delay,
webrtc::TimeDelta assembly_time, webrtc::TimeDelta assembly_time,
VideoContentType content_type) { VideoContentType content_type) {
@ -903,9 +903,9 @@ void ReceiveStatisticsProxy::OnDecodedFrame(
<< "QP sum was already set and no QP was given for a frame."; << "QP sum was already set and no QP was given for a frame.";
stats_.qp_sum.reset(); stats_.qp_sum.reset();
} }
decode_time_counter_.Add(decode_time_ms); decode_time_counter_.Add(decode_time.ms());
stats_.decode_ms = decode_time_ms; stats_.decode_ms = decode_time.ms();
stats_.total_decode_time_ms += decode_time_ms; stats_.total_decode_time += decode_time;
stats_.total_processing_delay += processing_delay; stats_.total_processing_delay += processing_delay;
stats_.total_assembly_time += assembly_time; stats_.total_assembly_time += assembly_time;
if (!assembly_time.IsZero()) { if (!assembly_time.IsZero()) {
@ -913,7 +913,7 @@ void ReceiveStatisticsProxy::OnDecodedFrame(
} }
if (enable_decode_time_histograms_) { if (enable_decode_time_histograms_) {
UpdateDecodeTimeHistograms(frame_meta.width, frame_meta.height, UpdateDecodeTimeHistograms(frame_meta.width, frame_meta.height,
decode_time_ms); decode_time.ms());
} }
last_content_type_ = content_type; last_content_type_ = content_type;

View File

@ -59,7 +59,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
void OnDecodedFrame(const VideoFrame& frame, void OnDecodedFrame(const VideoFrame& frame,
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, webrtc::TimeDelta decode_time,
VideoContentType content_type); VideoContentType content_type);
// Called asyncronously on the worker thread as a result of a call to the // Called asyncronously on the worker thread as a result of a call to the
@ -67,7 +67,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
// the actual decoding happens. // the actual decoding happens.
void OnDecodedFrame(const VideoFrameMetaData& frame_meta, void OnDecodedFrame(const VideoFrameMetaData& frame_meta,
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, webrtc::TimeDelta decode_time,
webrtc::TimeDelta processing_delay, webrtc::TimeDelta processing_delay,
webrtc::TimeDelta assembly_time, webrtc::TimeDelta assembly_time,
VideoContentType content_type); VideoContentType content_type);

View File

@ -113,7 +113,8 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesFramesDecoded) {
EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded); EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (uint32_t i = 1; i <= 3; ++i) { for (uint32_t i = 1; i <= 3; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(i, FlushAndGetStats().frames_decoded); EXPECT_EQ(i, FlushAndGetStats().frames_decoded);
} }
@ -124,7 +125,8 @@ TEST_F(ReceiveStatisticsProxy2Test, DecodedFpsIsReported) {
const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps; const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kRequiredSamples; ++i) { for (int i = 0; i < kRequiredSamples; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
} }
@ -140,7 +142,8 @@ TEST_F(ReceiveStatisticsProxy2Test, DecodedFpsIsNotReportedForTooFewSamples) {
const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps; const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kRequiredSamples - 1; ++i) { for (int i = 0; i < kRequiredSamples - 1; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
} }
@ -153,28 +156,29 @@ TEST_F(ReceiveStatisticsProxy2Test,
OnDecodedFrameWithQpDoesNotResetFramesDecodedOrTotalDecodeTime) { OnDecodedFrameWithQpDoesNotResetFramesDecodedOrTotalDecodeTime) {
EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded); EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
unsigned int expected_total_decode_time_ms = 0; TimeDelta expected_total_decode_time = TimeDelta::Millis(0);
unsigned int expected_frames_decoded = 0; unsigned int expected_frames_decoded = 0;
for (uint32_t i = 1; i <= 3; ++i) { for (uint32_t i = 1; i <= 3; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 1, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(1),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
expected_total_decode_time_ms += 1; expected_total_decode_time += TimeDelta::Millis(1);
++expected_frames_decoded; ++expected_frames_decoded;
loop_.Flush(); loop_.Flush();
EXPECT_EQ(expected_frames_decoded, EXPECT_EQ(expected_frames_decoded,
statistics_proxy_->GetStats().frames_decoded); statistics_proxy_->GetStats().frames_decoded);
EXPECT_EQ(expected_total_decode_time_ms, EXPECT_EQ(expected_total_decode_time,
statistics_proxy_->GetStats().total_decode_time_ms); statistics_proxy_->GetStats().total_decode_time);
} }
statistics_proxy_->OnDecodedFrame(frame, 1u, 3, statistics_proxy_->OnDecodedFrame(frame, 1u, TimeDelta::Millis(3),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
++expected_frames_decoded; ++expected_frames_decoded;
expected_total_decode_time_ms += 3; expected_total_decode_time += TimeDelta::Millis(3);
loop_.Flush(); loop_.Flush();
EXPECT_EQ(expected_frames_decoded, EXPECT_EQ(expected_frames_decoded,
statistics_proxy_->GetStats().frames_decoded); statistics_proxy_->GetStats().frames_decoded);
EXPECT_EQ(expected_total_decode_time_ms, EXPECT_EQ(expected_total_decode_time,
statistics_proxy_->GetStats().total_decode_time_ms); statistics_proxy_->GetStats().total_decode_time);
} }
TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesProcessingDelay) { TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesProcessingDelay) {
@ -191,7 +195,8 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesProcessingDelay) {
frame.set_packet_infos(RtpPacketInfos(packet_infos)); frame.set_packet_infos(RtpPacketInfos(packet_infos));
for (int i = 1; i <= 3; ++i) { for (int i = 1; i <= 3; ++i) {
fake_clock_.AdvanceTime(kProcessingDelay); fake_clock_.AdvanceTime(kProcessingDelay);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 1, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(1),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
expected_total_processing_delay += i * kProcessingDelay; expected_total_processing_delay += i * kProcessingDelay;
++expected_frames_decoded; ++expected_frames_decoded;
@ -202,7 +207,7 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesProcessingDelay) {
statistics_proxy_->GetStats().total_processing_delay); statistics_proxy_->GetStats().total_processing_delay);
} }
fake_clock_.AdvanceTime(kProcessingDelay); fake_clock_.AdvanceTime(kProcessingDelay);
statistics_proxy_->OnDecodedFrame(frame, 1u, 3, statistics_proxy_->OnDecodedFrame(frame, 1u, TimeDelta::Millis(3),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
++expected_frames_decoded; ++expected_frames_decoded;
expected_total_processing_delay += 4 * kProcessingDelay; expected_total_processing_delay += 4 * kProcessingDelay;
@ -226,7 +231,7 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesAssemblyTime) {
RtpPacketInfos::vector_type single_packet_frame = { RtpPacketInfos::vector_type single_packet_frame = {
RtpPacketInfo({}, {}, {}, {}, {}, Now())}; RtpPacketInfo({}, {}, {}, {}, {}, Now())};
frame.set_packet_infos(RtpPacketInfos(single_packet_frame)); frame.set_packet_infos(RtpPacketInfos(single_packet_frame));
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 1, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(1),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
++expected_frames_decoded; ++expected_frames_decoded;
loop_.Flush(); loop_.Flush();
@ -243,7 +248,7 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesAssemblyTime) {
RtpPacketInfo({}, {}, {}, {}, {}, Now() + 2 * kAssemblyTime), RtpPacketInfo({}, {}, {}, {}, {}, Now() + 2 * kAssemblyTime),
}; };
frame.set_packet_infos(RtpPacketInfos(ordered_frame)); frame.set_packet_infos(RtpPacketInfos(ordered_frame));
statistics_proxy_->OnDecodedFrame(frame, 1u, 3, statistics_proxy_->OnDecodedFrame(frame, 1u, TimeDelta::Millis(3),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
++expected_frames_decoded; ++expected_frames_decoded;
++expected_frames_assembled_from_multiple_packets; ++expected_frames_assembled_from_multiple_packets;
@ -264,7 +269,7 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesAssemblyTime) {
RtpPacketInfo({}, {}, {}, {}, {}, Now() + kAssemblyTime), RtpPacketInfo({}, {}, {}, {}, {}, Now() + kAssemblyTime),
}; };
frame.set_packet_infos(RtpPacketInfos(unordered_frame)); frame.set_packet_infos(RtpPacketInfos(unordered_frame));
statistics_proxy_->OnDecodedFrame(frame, 1u, 3, statistics_proxy_->OnDecodedFrame(frame, 1u, TimeDelta::Millis(3),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
++expected_frames_decoded; ++expected_frames_decoded;
++expected_frames_assembled_from_multiple_packets; ++expected_frames_assembled_from_multiple_packets;
@ -282,10 +287,10 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesAssemblyTime) {
TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesQpSum) { TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesQpSum) {
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum); EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
statistics_proxy_->OnDecodedFrame(frame, 3u, 0, statistics_proxy_->OnDecodedFrame(frame, 3u, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(3u, FlushAndGetStats().qp_sum); EXPECT_EQ(3u, FlushAndGetStats().qp_sum);
statistics_proxy_->OnDecodedFrame(frame, 127u, 0, statistics_proxy_->OnDecodedFrame(frame, 127u, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(130u, FlushAndGetStats().qp_sum); EXPECT_EQ(130u, FlushAndGetStats().qp_sum);
} }
@ -293,12 +298,12 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesQpSum) {
TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesTotalDecodeTime) { TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesTotalDecodeTime) {
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum); EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
statistics_proxy_->OnDecodedFrame(frame, 3u, 4, statistics_proxy_->OnDecodedFrame(frame, 3u, TimeDelta::Millis(4),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(4u, FlushAndGetStats().total_decode_time_ms); EXPECT_EQ(4u, FlushAndGetStats().total_decode_time.ms());
statistics_proxy_->OnDecodedFrame(frame, 127u, 7, statistics_proxy_->OnDecodedFrame(frame, 127u, TimeDelta::Millis(7),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(11u, FlushAndGetStats().total_decode_time_ms); EXPECT_EQ(11u, FlushAndGetStats().total_decode_time.ms());
} }
TEST_F(ReceiveStatisticsProxy2Test, ReportsContentType) { TEST_F(ReceiveStatisticsProxy2Test, ReportsContentType) {
@ -307,11 +312,11 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportsContentType) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString( EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString(
statistics_proxy_->GetStats().content_type)); statistics_proxy_->GetStats().content_type));
statistics_proxy_->OnDecodedFrame(frame, 3u, 0, statistics_proxy_->OnDecodedFrame(frame, 3u, TimeDelta::Millis(0),
VideoContentType::SCREENSHARE); VideoContentType::SCREENSHARE);
EXPECT_EQ(kScreenshareString, EXPECT_EQ(kScreenshareString,
videocontenttypehelpers::ToString(FlushAndGetStats().content_type)); videocontenttypehelpers::ToString(FlushAndGetStats().content_type));
statistics_proxy_->OnDecodedFrame(frame, 3u, 0, statistics_proxy_->OnDecodedFrame(frame, 3u, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(kRealtimeString, EXPECT_EQ(kRealtimeString,
videocontenttypehelpers::ToString(FlushAndGetStats().content_type)); videocontenttypehelpers::ToString(FlushAndGetStats().content_type));
@ -329,7 +334,7 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxTotalInterFrameDelay) {
EXPECT_EQ(expected_total_squared_inter_frame_delay, EXPECT_EQ(expected_total_squared_inter_frame_delay,
statistics_proxy_->GetStats().total_squared_inter_frame_delay); statistics_proxy_->GetStats().total_squared_inter_frame_delay);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay, EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
FlushAndGetStats().total_inter_frame_delay); FlushAndGetStats().total_inter_frame_delay);
@ -337,7 +342,7 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxTotalInterFrameDelay) {
FlushAndGetStats().total_squared_inter_frame_delay); FlushAndGetStats().total_squared_inter_frame_delay);
fake_clock_.AdvanceTime(kInterFrameDelay1); fake_clock_.AdvanceTime(kInterFrameDelay1);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
expected_total_inter_frame_delay += kInterFrameDelay1.seconds<double>(); expected_total_inter_frame_delay += kInterFrameDelay1.seconds<double>();
expected_total_squared_inter_frame_delay += expected_total_squared_inter_frame_delay +=
@ -349,7 +354,7 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxTotalInterFrameDelay) {
statistics_proxy_->GetStats().total_squared_inter_frame_delay); statistics_proxy_->GetStats().total_squared_inter_frame_delay);
fake_clock_.AdvanceTime(kInterFrameDelay2); fake_clock_.AdvanceTime(kInterFrameDelay2);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
expected_total_inter_frame_delay += kInterFrameDelay2.seconds<double>(); expected_total_inter_frame_delay += kInterFrameDelay2.seconds<double>();
expected_total_squared_inter_frame_delay += expected_total_squared_inter_frame_delay +=
@ -361,7 +366,7 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxTotalInterFrameDelay) {
statistics_proxy_->GetStats().total_squared_inter_frame_delay); statistics_proxy_->GetStats().total_squared_inter_frame_delay);
fake_clock_.AdvanceTime(kInterFrameDelay3); fake_clock_.AdvanceTime(kInterFrameDelay3);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
expected_total_inter_frame_delay += kInterFrameDelay3.seconds<double>(); expected_total_inter_frame_delay += kInterFrameDelay3.seconds<double>();
expected_total_squared_inter_frame_delay += expected_total_squared_inter_frame_delay +=
@ -379,22 +384,22 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxInterframeDelay) {
const int64_t kInterframeDelayMs2 = 200; const int64_t kInterframeDelayMs2 = 200;
const int64_t kInterframeDelayMs3 = 100; const int64_t kInterframeDelayMs3 = 100;
EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms); EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// kInterframeDelayMs3 is smaller than kInterframeDelayMs2. // kInterframeDelayMs3 is smaller than kInterframeDelayMs2.
EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
@ -406,23 +411,23 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportInterframeDelayInWindow) {
const int64_t kInterframeDelayMs2 = 750; const int64_t kInterframeDelayMs2 = 750;
const int64_t kInterframeDelayMs3 = 700; const int64_t kInterframeDelayMs3 = 700;
EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms); EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// Still first delay is the maximum // Still first delay is the maximum
EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// Now the first sample is out of the window, so the second is the maximum. // Now the first sample is out of the window, so the second is the maximum.
EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms); EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
@ -532,7 +537,7 @@ TEST_F(ReceiveStatisticsProxy2Test, ReportsSumSquaredFrameDurations) {
TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpQpSumWontExist) { TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpQpSumWontExist) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum); EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum); EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum);
} }
@ -540,10 +545,10 @@ TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpQpSumWontExist) {
TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpResetsQpSum) { TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpResetsQpSum) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum); EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
statistics_proxy_->OnDecodedFrame(frame, 3u, 0, statistics_proxy_->OnDecodedFrame(frame, 3u, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(3u, FlushAndGetStats().qp_sum); EXPECT_EQ(3u, FlushAndGetStats().qp_sum);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum); EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum);
} }
@ -1014,7 +1019,8 @@ TEST_F(ReceiveStatisticsProxy2Test, DoesNotReportStaleFramerates) {
// Since OnRenderedFrame is never called the fps in each sample will be 0, // Since OnRenderedFrame is never called the fps in each sample will be 0,
// i.e. bad // i.e. bad
frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds()); frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
statistics_proxy_->OnRenderedFrame(MetaData(frame)); statistics_proxy_->OnRenderedFrame(MetaData(frame));
fake_clock_.AdvanceTimeMilliseconds(1000 / kDefaultFps); fake_clock_.AdvanceTimeMilliseconds(1000 / kDefaultFps);
@ -1083,7 +1089,7 @@ TEST_F(ReceiveStatisticsProxy2Test, ReceivedFrameHistogramsAreUpdated) {
TEST_F(ReceiveStatisticsProxy2Test, ZeroDelayReportedIfFrameNotDelayed) { TEST_F(ReceiveStatisticsProxy2Test, ZeroDelayReportedIfFrameNotDelayed) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// Frame not delayed, delayed frames to render: 0%. // Frame not delayed, delayed frames to render: 0%.
@ -1104,7 +1110,7 @@ TEST_F(ReceiveStatisticsProxy2Test, ZeroDelayReportedIfFrameNotDelayed) {
TEST_F(ReceiveStatisticsProxy2Test, TEST_F(ReceiveStatisticsProxy2Test,
DelayedFrameHistogramsAreNotUpdatedIfMinRuntimeHasNotPassed) { DelayedFrameHistogramsAreNotUpdatedIfMinRuntimeHasNotPassed) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// Frame not delayed, delayed frames to render: 0%. // Frame not delayed, delayed frames to render: 0%.
@ -1125,7 +1131,7 @@ TEST_F(ReceiveStatisticsProxy2Test,
TEST_F(ReceiveStatisticsProxy2Test, TEST_F(ReceiveStatisticsProxy2Test,
DelayedFramesHistogramsAreNotUpdatedIfNoRenderedFrames) { DelayedFramesHistogramsAreNotUpdatedIfNoRenderedFrames) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// Min run time has passed. No rendered frames. // Min run time has passed. No rendered frames.
@ -1140,7 +1146,7 @@ TEST_F(ReceiveStatisticsProxy2Test,
TEST_F(ReceiveStatisticsProxy2Test, DelayReportedIfFrameIsDelayed) { TEST_F(ReceiveStatisticsProxy2Test, DelayReportedIfFrameIsDelayed) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// Frame delayed 1 ms, delayed frames to render: 100%. // Frame delayed 1 ms, delayed frames to render: 100%.
@ -1163,7 +1169,7 @@ TEST_F(ReceiveStatisticsProxy2Test, DelayReportedIfFrameIsDelayed) {
TEST_F(ReceiveStatisticsProxy2Test, AverageDelayOfDelayedFramesIsReported) { TEST_F(ReceiveStatisticsProxy2Test, AverageDelayOfDelayedFramesIsReported) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
// Two frames delayed (6 ms, 10 ms), delayed frames to render: 50%. // Two frames delayed (6 ms, 10 ms), delayed frames to render: 50%.
@ -1315,12 +1321,14 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, InterFrameDelaysAreReported) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kMinRequiredSamples; ++i) { for (int i = 0; i < kMinRequiredSamples; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
} }
// One extra with double the interval. // One extra with double the interval.
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
content_type_);
FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr); FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
const int kExpectedInterFrame = const int kExpectedInterFrame =
@ -1350,16 +1358,19 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent,
for (int i = 0; i <= kMinRequiredSamples - kLastFivePercentsSamples; ++i) { for (int i = 0; i <= kMinRequiredSamples - kLastFivePercentsSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
} }
// Last 5% of intervals are double in size. // Last 5% of intervals are double in size.
for (int i = 0; i < kLastFivePercentsSamples; ++i) { for (int i = 0; i < kLastFivePercentsSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(2 * kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(2 * kInterFrameDelayMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
} }
// Final sample is outlier and 10 times as big. // Final sample is outlier and 10 times as big.
fake_clock_.AdvanceTimeMilliseconds(10 * kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(10 * kInterFrameDelayMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
content_type_);
FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr); FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
const int kExpectedInterFrame = kInterFrameDelayMs * 2; const int kExpectedInterFrame = kInterFrameDelayMs * 2;
@ -1381,7 +1392,8 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent,
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kMinRequiredSamples; ++i) { for (int i = 0; i < kMinRequiredSamples; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
} }
@ -1404,7 +1416,8 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent,
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i <= kMinRequiredSamples; ++i) { for (int i = 0; i <= kMinRequiredSamples; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
} }
@ -1416,9 +1429,11 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent,
// Insert two more frames. The interval during the pause should be // Insert two more frames. The interval during the pause should be
// disregarded in the stats. // disregarded in the stats.
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
content_type_);
FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr); FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
if (videocontenttypehelpers::IsScreenshare(content_type_)) { if (videocontenttypehelpers::IsScreenshare(content_type_)) {
@ -1454,7 +1469,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, FreezesAreReported) {
for (int i = 0; i < kMinRequiredSamples; ++i) { for (int i = 0; i < kMinRequiredSamples; ++i) {
VideoFrameMetaData meta = MetaData(frame); VideoFrameMetaData meta = MetaData(frame);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, absl::nullopt, 0, webrtc::TimeDelta::Millis(0), meta, absl::nullopt, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
@ -1463,7 +1478,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, FreezesAreReported) {
fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs); fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs);
VideoFrameMetaData meta = MetaData(frame); VideoFrameMetaData meta = MetaData(frame);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, absl::nullopt, 0, webrtc::TimeDelta::Millis(0), meta, absl::nullopt, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
@ -1502,7 +1517,8 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, HarmonicFrameRateIsReported) {
for (int i = 0; i < kMinRequiredSamples; ++i) { for (int i = 0; i < kMinRequiredSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs); fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(MetaData(frame)); statistics_proxy_->OnRenderedFrame(MetaData(frame));
} }
@ -1510,14 +1526,16 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, HarmonicFrameRateIsReported) {
// Add freeze. // Add freeze.
loop_.Flush(); loop_.Flush();
fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs); fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
content_type_);
statistics_proxy_->OnRenderedFrame(MetaData(frame)); statistics_proxy_->OnRenderedFrame(MetaData(frame));
// Add pause. // Add pause.
loop_.Flush(); loop_.Flush();
fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs); fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
statistics_proxy_->OnStreamInactive(); statistics_proxy_->OnStreamInactive();
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, TimeDelta::Millis(0),
content_type_);
statistics_proxy_->OnRenderedFrame(MetaData(frame)); statistics_proxy_->OnRenderedFrame(MetaData(frame));
FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr); FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
@ -1548,7 +1566,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, PausesAreIgnored) {
for (int i = 0; i <= kMinRequiredSamples; ++i) { for (int i = 0; i <= kMinRequiredSamples; ++i) {
VideoFrameMetaData meta = MetaData(frame); VideoFrameMetaData meta = MetaData(frame);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, absl::nullopt, 0, webrtc::TimeDelta::Millis(0), meta, absl::nullopt, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
@ -1560,7 +1578,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, PausesAreIgnored) {
for (int i = 0; i <= kMinRequiredSamples * 3; ++i) { for (int i = 0; i <= kMinRequiredSamples * 3; ++i) {
VideoFrameMetaData meta = MetaData(frame); VideoFrameMetaData meta = MetaData(frame);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, absl::nullopt, 0, webrtc::TimeDelta::Millis(0), meta, absl::nullopt, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
@ -1591,13 +1609,15 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, ManyPausesAtTheBeginning) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i <= kMinRequiredSamples; ++i) { for (int i = 0; i <= kMinRequiredSamples; ++i) {
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
statistics_proxy_->OnStreamInactive(); statistics_proxy_->OnStreamInactive();
fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs); fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
} }
@ -1623,7 +1643,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInHdReported) {
for (int i = 0; i < kMinRequiredSamples; ++i) { for (int i = 0; i < kMinRequiredSamples; ++i) {
VideoFrameMetaData meta = MetaData(frame_hd); VideoFrameMetaData meta = MetaData(frame_hd);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, absl::nullopt, 0, webrtc::TimeDelta::Millis(0), meta, absl::nullopt, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
@ -1632,7 +1652,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInHdReported) {
for (int i = 0; i < 2 * kMinRequiredSamples; ++i) { for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
VideoFrameMetaData meta = MetaData(frame_sd); VideoFrameMetaData meta = MetaData(frame_sd);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, absl::nullopt, 0, webrtc::TimeDelta::Millis(0), meta, absl::nullopt, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
@ -1663,7 +1683,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInBlockyVideoReported) {
for (int i = 0; i < kMinRequiredSamples; ++i) { for (int i = 0; i < kMinRequiredSamples; ++i) {
VideoFrameMetaData meta = MetaData(frame); VideoFrameMetaData meta = MetaData(frame);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, kLowQp, 0, webrtc::TimeDelta::Millis(0), meta, kLowQp, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
@ -1672,13 +1692,14 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInBlockyVideoReported) {
for (int i = 0; i < 2 * kMinRequiredSamples; ++i) { for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
VideoFrameMetaData meta = MetaData(frame); VideoFrameMetaData meta = MetaData(frame);
statistics_proxy_->OnDecodedFrame( statistics_proxy_->OnDecodedFrame(
meta, kHighQp, 0, webrtc::TimeDelta::Millis(0), meta, kHighQp, TimeDelta::Millis(0), webrtc::TimeDelta::Millis(0),
webrtc::TimeDelta::Millis(0), content_type_); webrtc::TimeDelta::Millis(0), content_type_);
statistics_proxy_->OnRenderedFrame(meta); statistics_proxy_->OnRenderedFrame(meta);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
} }
// Extra last frame. // Extra last frame.
statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame, kHighQp, TimeDelta::Millis(0),
content_type_);
statistics_proxy_->OnRenderedFrame(MetaData(frame)); statistics_proxy_->OnRenderedFrame(MetaData(frame));
FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr); FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
@ -1703,7 +1724,8 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, DownscalesReported) {
webrtc::VideoFrame frame_ld = CreateFrame(320, 180); webrtc::VideoFrame frame_ld = CreateFrame(320, 180);
// Call once to pass content type. // Call once to pass content type.
statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, 0, content_type_); statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt,
TimeDelta::Millis(0), content_type_);
loop_.Flush(); loop_.Flush();
statistics_proxy_->OnRenderedFrame(MetaData(frame_hd)); statistics_proxy_->OnRenderedFrame(MetaData(frame_hd));
@ -1740,7 +1762,8 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent, DecodeTimeReported) {
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
for (int i = 0; i < kMinRequiredSamples; ++i) { for (int i = 0; i < kMinRequiredSamples; ++i) {
statistics_proxy_->OnDecodedFrame(frame, kLowQp, kDecodeMs, content_type_); statistics_proxy_->OnDecodedFrame(
frame, kLowQp, TimeDelta::Millis(kDecodeMs), content_type_);
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
} }
FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr); FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
@ -1760,13 +1783,15 @@ TEST_P(ReceiveStatisticsProxy2TestWithContent,
videocontenttypehelpers::SetSimulcastId(&content_type, 1); videocontenttypehelpers::SetSimulcastId(&content_type, 1);
for (int i = 0; i <= kMinRequiredSamples; ++i) { for (int i = 0; i <= kMinRequiredSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs1); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs1);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type);
} }
videocontenttypehelpers::SetSimulcastId(&content_type, 2); videocontenttypehelpers::SetSimulcastId(&content_type, 2);
for (int i = 0; i <= kMinRequiredSamples; ++i) { for (int i = 0; i <= kMinRequiredSamples; ++i) {
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs2); fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs2);
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt,
TimeDelta::Millis(0), content_type);
} }
FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr); FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
@ -1876,7 +1901,7 @@ TEST_P(ReceiveStatisticsProxy2TestWithDecodeTimeHistograms,
for (int i = 0; i < kNumberOfFrames; ++i) { for (int i = 0; i < kNumberOfFrames; ++i) {
statistics_proxy_->OnDecodedFrame(frame, /*qp=*/absl::nullopt, statistics_proxy_->OnDecodedFrame(frame, /*qp=*/absl::nullopt,
kDecodeTimeMs, TimeDelta::Millis(kDecodeTimeMs),
VideoContentType::UNSPECIFIED); VideoContentType::UNSPECIFIED);
fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs); fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
} }

View File

@ -496,8 +496,7 @@ void VideoAnalyzer::PollStats() {
// `total_decode_time_ms` gives a good estimate of the mean decode time, // `total_decode_time_ms` gives a good estimate of the mean decode time,
// `decode_ms` is used to keep track of the standard deviation. // `decode_ms` is used to keep track of the standard deviation.
if (receive_stats.frames_decoded > 0) if (receive_stats.frames_decoded > 0)
mean_decode_time_ms_ = mean_decode_time_ms_ = receive_stats.total_decode_time.ms<double>() /
static_cast<double>(receive_stats.total_decode_time_ms) /
receive_stats.frames_decoded; receive_stats.frames_decoded;
if (receive_stats.decode_ms > 0) if (receive_stats.decode_ms > 0)
decode_time_ms_.AddSample(receive_stats.decode_ms); decode_time_ms_.AddSample(receive_stats.decode_ms);

View File

@ -44,9 +44,9 @@ VideoStreamDecoder::~VideoStreamDecoder() {
// Release. Acquiring the same lock in the path of decode callback can deadlock. // Release. Acquiring the same lock in the path of decode callback can deadlock.
int32_t VideoStreamDecoder::FrameToRender(VideoFrame& video_frame, int32_t VideoStreamDecoder::FrameToRender(VideoFrame& video_frame,
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, TimeDelta decode_time,
VideoContentType content_type) { VideoContentType content_type) {
receive_stats_callback_->OnDecodedFrame(video_frame, qp, decode_time_ms, receive_stats_callback_->OnDecodedFrame(video_frame, qp, decode_time,
content_type); content_type);
incoming_video_stream_->OnFrame(video_frame); incoming_video_stream_->OnFrame(video_frame);
return 0; return 0;

View File

@ -41,7 +41,7 @@ class VideoStreamDecoder : public VCMReceiveCallback {
// Implements VCMReceiveCallback. // Implements VCMReceiveCallback.
int32_t FrameToRender(VideoFrame& video_frame, int32_t FrameToRender(VideoFrame& video_frame,
absl::optional<uint8_t> qp, absl::optional<uint8_t> qp,
int32_t decode_time_ms, TimeDelta decode_time,
VideoContentType content_type) override; VideoContentType content_type) override;
void OnDroppedFrames(uint32_t frames_dropped) override; void OnDroppedFrames(uint32_t frames_dropped) override;
void OnIncomingPayloadType(int payload_type) override; void OnIncomingPayloadType(int payload_type) override;