[PCLF] Rescale frame to the requested resolution before passing it to analyzer

Bug: b/240540204
Change-Id: Idafa74021dd136d8ec9fd54cabaa7f0d49d379d9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280944
Reviewed-by: Andrey Logvin <landrey@google.com>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38498}
This commit is contained in:
Artem Titov
2022-10-28 20:34:56 +02:00
committed by WebRTC LUCI CQ
parent e02fbb040e
commit 21b0572e3b
10 changed files with 141 additions and 84 deletions

View File

@ -30,6 +30,7 @@
namespace webrtc { namespace webrtc {
namespace webrtc_pc_e2e { namespace webrtc_pc_e2e {
namespace {
using VideoSubscription = ::webrtc::webrtc_pc_e2e:: using VideoSubscription = ::webrtc::webrtc_pc_e2e::
PeerConnectionE2EQualityTestFixture::VideoSubscription; PeerConnectionE2EQualityTestFixture::VideoSubscription;
@ -38,6 +39,35 @@ using VideoResolution = ::webrtc::webrtc_pc_e2e::
using VideoConfig = using VideoConfig =
::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::VideoConfig; ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::VideoConfig;
// Scales video frame to `required_resolution` if necessary. Crashes if video
// frame and `required_resolution` have different aspect ratio.
VideoFrame ScaleVideoFrame(const VideoFrame& frame,
VideoResolution required_resolution) {
if (required_resolution.width() == static_cast<size_t>(frame.width()) &&
required_resolution.height() == static_cast<size_t>(frame.height())) {
return frame;
}
RTC_CHECK_LE(std::abs(static_cast<double>(required_resolution.width()) /
required_resolution.height() -
static_cast<double>(frame.width()) / frame.height()),
2 * std::numeric_limits<double>::epsilon())
<< "Received frame has different aspect ratio compared to requested "
<< "video resolution: required resolution="
<< required_resolution.ToString()
<< "; actual resolution=" << frame.width() << "x" << frame.height();
rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
required_resolution.width(), required_resolution.height()));
scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420());
VideoFrame scaled_frame = frame;
scaled_frame.set_video_frame_buffer(scaled_buffer);
return scaled_frame;
}
} // namespace
AnalyzingVideoSink::AnalyzingVideoSink(absl::string_view peer_name, AnalyzingVideoSink::AnalyzingVideoSink(absl::string_view peer_name,
Clock* clock, Clock* clock,
VideoQualityAnalyzerInterface& analyzer, VideoQualityAnalyzerInterface& analyzer,
@ -78,23 +108,30 @@ void AnalyzingVideoSink::OnFrame(const VideoFrame& frame) {
// This is dummy frame, so we don't need to process it further. // This is dummy frame, so we don't need to process it further.
return; return;
} }
// Copy entire video frame including video buffer to ensure that analyzer
// won't hold any WebRTC internal buffers. if (frame.id() == VideoFrame::kNotSetId) {
// If frame ID is unknown we can't get required render resolution, so pass
// to the analyzer in the actual resolution of the frame.
AnalyzeFrame(frame);
} else {
std::string stream_label = analyzer_->GetStreamLabel(frame.id());
SinksDescriptor* sinks_descriptor = PopulateSinks(stream_label);
RTC_CHECK(sinks_descriptor != nullptr);
VideoFrame scaled_frame =
ScaleVideoFrame(frame, sinks_descriptor->resolution);
AnalyzeFrame(scaled_frame);
for (auto& sink : sinks_descriptor->sinks) {
sink->OnFrame(scaled_frame);
}
}
}
void AnalyzingVideoSink::AnalyzeFrame(const VideoFrame& frame) {
VideoFrame frame_copy = frame; VideoFrame frame_copy = frame;
frame_copy.set_video_frame_buffer( frame_copy.set_video_frame_buffer(
I420Buffer::Copy(*frame.video_frame_buffer()->ToI420())); I420Buffer::Copy(*frame.video_frame_buffer()->ToI420()));
analyzer_->OnFrameRendered(peer_name_, frame_copy); analyzer_->OnFrameRendered(peer_name_, frame_copy);
if (frame.id() != VideoFrame::kNotSetId) {
std::string stream_label = analyzer_->GetStreamLabel(frame.id());
SinksDescriptor* sinks_descriptor = PopulateSinks(stream_label);
if (sinks_descriptor == nullptr) {
return;
}
for (auto& sink : sinks_descriptor->sinks) {
sink->OnFrame(frame);
}
}
} }
AnalyzingVideoSink::SinksDescriptor* AnalyzingVideoSink::PopulateSinks( AnalyzingVideoSink::SinksDescriptor* AnalyzingVideoSink::PopulateSinks(

View File

@ -66,6 +66,10 @@ class AnalyzingVideoSink : public rtc::VideoSinkInterface<VideoFrame> {
std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks; std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
}; };
// Creates full copy of the frame to free any frame owned internal buffers and
// passes created copy to analyzer. Uses `I420Buffer` to represent frame
// content.
void AnalyzeFrame(const VideoFrame& frame);
// Populates sink for specified stream and caches them in `stream_sinks_`. // Populates sink for specified stream and caches them in `stream_sinks_`.
SinksDescriptor* PopulateSinks(absl::string_view stream_label); SinksDescriptor* PopulateSinks(absl::string_view stream_label);

View File

@ -434,7 +434,8 @@ void DefaultVideoQualityAnalyzer::OnFrameDecoded(
used_decoder.last_frame_id = frame.id(); used_decoder.last_frame_id = frame.id();
used_decoder.switched_on_at = now; used_decoder.switched_on_at = now;
used_decoder.switched_from_at = now; used_decoder.switched_from_at = now;
it->second.OnFrameDecoded(peer_index, now, used_decoder); it->second.OnFrameDecoded(peer_index, now, frame.width(), frame.height(),
used_decoder);
} }
void DefaultVideoQualityAnalyzer::OnFrameRendered( void DefaultVideoQualityAnalyzer::OnFrameRendered(
@ -490,8 +491,7 @@ void DefaultVideoQualityAnalyzer::OnFrameRendered(
stream_frame_counters_.at(stats_key).rendered++; stream_frame_counters_.at(stats_key).rendered++;
// Update current frame stats. // Update current frame stats.
frame_in_flight->OnFrameRendered(peer_index, Now(), frame.width(), frame_in_flight->OnFrameRendered(peer_index, Now());
frame.height());
// After we received frame here we need to check if there are any dropped // After we received frame here we need to check if there are any dropped
// frames between this one and last one, that was rendered for this video // frames between this one and last one, that was rendered for this video
@ -1010,7 +1010,7 @@ void DefaultVideoQualityAnalyzer::ReportResults(
ImprovementDirection::kSmallerIsBetter, ImprovementDirection::kSmallerIsBetter,
metric_metadata); metric_metadata);
metrics_logger_->LogMetric( metrics_logger_->LogMetric(
"pixels_per_frame", test_case_name, stats.resolution_of_rendered_frame, "pixels_per_frame", test_case_name, stats.resolution_of_decoded_frame,
Unit::kCount, ImprovementDirection::kBiggerIsBetter, metric_metadata); Unit::kCount, ImprovementDirection::kBiggerIsBetter, metric_metadata);
metrics_logger_->LogSingleValueMetric( metrics_logger_->LogSingleValueMetric(
"min_psnr_dB", test_case_name, "min_psnr_dB", test_case_name,

View File

@ -129,9 +129,13 @@ bool FrameInFlight::HasReceivedTime(size_t peer) const {
void FrameInFlight::OnFrameDecoded(size_t peer, void FrameInFlight::OnFrameDecoded(size_t peer,
webrtc::Timestamp time, webrtc::Timestamp time,
int width,
int height,
const StreamCodecInfo& used_decoder) { const StreamCodecInfo& used_decoder) {
receiver_stats_[peer].decode_end_time = time; receiver_stats_[peer].decode_end_time = time;
receiver_stats_[peer].used_decoder = used_decoder; receiver_stats_[peer].used_decoder = used_decoder;
receiver_stats_[peer].decoded_frame_width = width;
receiver_stats_[peer].decoded_frame_height = height;
} }
void FrameInFlight::OnDecoderError(size_t peer, void FrameInFlight::OnDecoderError(size_t peer,
@ -148,13 +152,8 @@ bool FrameInFlight::HasDecodeEndTime(size_t peer) const {
return it->second.decode_end_time.IsFinite(); return it->second.decode_end_time.IsFinite();
} }
void FrameInFlight::OnFrameRendered(size_t peer, void FrameInFlight::OnFrameRendered(size_t peer, webrtc::Timestamp time) {
webrtc::Timestamp time,
int width,
int height) {
receiver_stats_[peer].rendered_time = time; receiver_stats_[peer].rendered_time = time;
receiver_stats_[peer].rendered_frame_width = width;
receiver_stats_[peer].rendered_frame_height = height;
} }
bool FrameInFlight::HasRenderedTime(size_t peer) const { bool FrameInFlight::HasRenderedTime(size_t peer) const {
@ -192,8 +191,8 @@ FrameStats FrameInFlight::GetStatsForPeer(size_t peer) const {
stats.decode_end_time = receiver_stats->decode_end_time; stats.decode_end_time = receiver_stats->decode_end_time;
stats.rendered_time = receiver_stats->rendered_time; stats.rendered_time = receiver_stats->rendered_time;
stats.prev_frame_rendered_time = receiver_stats->prev_frame_rendered_time; stats.prev_frame_rendered_time = receiver_stats->prev_frame_rendered_time;
stats.rendered_frame_width = receiver_stats->rendered_frame_width; stats.decoded_frame_width = receiver_stats->decoded_frame_width;
stats.rendered_frame_height = receiver_stats->rendered_frame_height; stats.decoded_frame_height = receiver_stats->decoded_frame_height;
stats.used_decoder = receiver_stats->used_decoder; stats.used_decoder = receiver_stats->used_decoder;
stats.pre_decoded_frame_type = receiver_stats->frame_type; stats.pre_decoded_frame_type = receiver_stats->frame_type;
stats.pre_decoded_image_size = receiver_stats->encoded_image_size; stats.pre_decoded_image_size = receiver_stats->encoded_image_size;

View File

@ -37,8 +37,8 @@ struct ReceiverFrameStats {
VideoFrameType frame_type = VideoFrameType::kEmptyFrame; VideoFrameType frame_type = VideoFrameType::kEmptyFrame;
DataSize encoded_image_size = DataSize::Bytes(0); DataSize encoded_image_size = DataSize::Bytes(0);
absl::optional<int> rendered_frame_width = absl::nullopt; absl::optional<int> decoded_frame_width = absl::nullopt;
absl::optional<int> rendered_frame_height = absl::nullopt; absl::optional<int> decoded_frame_height = absl::nullopt;
// Can be not set if frame was dropped in the network. // Can be not set if frame was dropped in the network.
absl::optional<StreamCodecInfo> used_decoder = absl::nullopt; absl::optional<StreamCodecInfo> used_decoder = absl::nullopt;
@ -101,15 +101,14 @@ class FrameInFlight {
void OnFrameDecoded(size_t peer, void OnFrameDecoded(size_t peer,
webrtc::Timestamp time, webrtc::Timestamp time,
int width,
int height,
const StreamCodecInfo& used_decoder); const StreamCodecInfo& used_decoder);
void OnDecoderError(size_t peer, const StreamCodecInfo& used_decoder); void OnDecoderError(size_t peer, const StreamCodecInfo& used_decoder);
bool HasDecodeEndTime(size_t peer) const; bool HasDecodeEndTime(size_t peer) const;
void OnFrameRendered(size_t peer, void OnFrameRendered(size_t peer, webrtc::Timestamp time);
webrtc::Timestamp time,
int width,
int height);
bool HasRenderedTime(size_t peer) const; bool HasRenderedTime(size_t peer) const;

View File

@ -80,10 +80,10 @@ FrameComparison ValidateFrameComparison(FrameComparison comparison) {
<< "Regular comparison has to have finite decode_end_time"; << "Regular comparison has to have finite decode_end_time";
RTC_DCHECK(comparison.frame_stats.rendered_time.IsFinite()) RTC_DCHECK(comparison.frame_stats.rendered_time.IsFinite())
<< "Regular comparison has to have finite rendered_time"; << "Regular comparison has to have finite rendered_time";
RTC_DCHECK(comparison.frame_stats.rendered_frame_width.has_value()) RTC_DCHECK(comparison.frame_stats.decoded_frame_width.has_value())
<< "Regular comparison has to have rendered_frame_width"; << "Regular comparison has to have decoded_frame_width";
RTC_DCHECK(comparison.frame_stats.rendered_frame_height.has_value()) RTC_DCHECK(comparison.frame_stats.decoded_frame_height.has_value())
<< "Regular comparison has to have rendered_frame_height"; << "Regular comparison has to have decoded_frame_height";
RTC_DCHECK(comparison.frame_stats.used_encoder.has_value()) RTC_DCHECK(comparison.frame_stats.used_encoder.has_value())
<< "Regular comparison has to have used_encoder"; << "Regular comparison has to have used_encoder";
RTC_DCHECK(comparison.frame_stats.used_decoder.has_value()) RTC_DCHECK(comparison.frame_stats.used_decoder.has_value())
@ -119,6 +119,13 @@ FrameComparison ValidateFrameComparison(FrameComparison comparison) {
RTC_DCHECK(comparison.frame_stats.used_decoder.has_value()) RTC_DCHECK(comparison.frame_stats.used_decoder.has_value())
<< "Dropped frame comparison has to have used_decoder when " << "Dropped frame comparison has to have used_decoder when "
<< "decode_end_time is set or decoder_failed is true"; << "decode_end_time is set or decoder_failed is true";
} else if (comparison.frame_stats.decode_end_time.IsFinite()) {
RTC_DCHECK(comparison.frame_stats.decoded_frame_width.has_value())
<< "Dropped frame comparison has to have decoded_frame_width when "
<< "decode_end_time is set";
RTC_DCHECK(comparison.frame_stats.decoded_frame_height.has_value())
<< "Dropped frame comparison has to have decoded_frame_height when "
<< "decode_end_time is set";
} else { } else {
RTC_DCHECK(!comparison.frame_stats.received_time.IsFinite()) RTC_DCHECK(!comparison.frame_stats.received_time.IsFinite())
<< "Dropped frame comparison can't have received_time when " << "Dropped frame comparison can't have received_time when "
@ -132,10 +139,6 @@ FrameComparison ValidateFrameComparison(FrameComparison comparison) {
} }
RTC_DCHECK(!comparison.frame_stats.rendered_time.IsFinite()) RTC_DCHECK(!comparison.frame_stats.rendered_time.IsFinite())
<< "Dropped frame comparison can't have rendered_time"; << "Dropped frame comparison can't have rendered_time";
RTC_DCHECK(!comparison.frame_stats.rendered_frame_width.has_value())
<< "Dropped frame comparison can't have rendered_frame_width";
RTC_DCHECK(!comparison.frame_stats.rendered_frame_height.has_value())
<< "Dropped frame comparison can't have rendered_frame_height";
break; break;
case FrameComparisonType::kFrameInFlight: case FrameComparisonType::kFrameInFlight:
// Frame in flight comparison may miss almost any FrameStats, but if // Frame in flight comparison may miss almost any FrameStats, but if
@ -147,10 +150,6 @@ FrameComparison ValidateFrameComparison(FrameComparison comparison) {
<< "Frame in flight comparison can't have rendered frame"; << "Frame in flight comparison can't have rendered frame";
RTC_DCHECK(!comparison.frame_stats.rendered_time.IsFinite()) RTC_DCHECK(!comparison.frame_stats.rendered_time.IsFinite())
<< "Frame in flight comparison can't have rendered_time"; << "Frame in flight comparison can't have rendered_time";
RTC_DCHECK(!comparison.frame_stats.rendered_frame_width.has_value())
<< "Frame in flight comparison can't have rendered_frame_width";
RTC_DCHECK(!comparison.frame_stats.rendered_frame_height.has_value())
<< "Frame in flight comparison can't have rendered_frame_height";
if (comparison.frame_stats.decode_end_time.IsFinite() || if (comparison.frame_stats.decode_end_time.IsFinite() ||
comparison.frame_stats.decoder_failed) { comparison.frame_stats.decoder_failed) {
@ -162,6 +161,14 @@ FrameComparison ValidateFrameComparison(FrameComparison comparison) {
<< "decode_start_time when decode_end_time is finite or " << "decode_start_time when decode_end_time is finite or "
<< "decoder_failed is true."; << "decoder_failed is true.";
} }
if (comparison.frame_stats.decode_end_time.IsFinite()) {
RTC_DCHECK(comparison.frame_stats.decoded_frame_width.has_value())
<< "Frame in flight comparison has to have decoded_frame_width "
<< "when decode_end_time is set.";
RTC_DCHECK(comparison.frame_stats.decoded_frame_height.has_value())
<< "Frame in flight comparison has to have decoded_frame_height "
<< "when decode_end_time is set.";
}
if (comparison.frame_stats.decode_start_time.IsFinite()) { if (comparison.frame_stats.decode_start_time.IsFinite()) {
RTC_DCHECK(comparison.frame_stats.received_time.IsFinite()) RTC_DCHECK(comparison.frame_stats.received_time.IsFinite())
<< "Frame in flight comparison has to have finite received_time " << "Frame in flight comparison has to have finite received_time "
@ -473,10 +480,6 @@ void DefaultVideoQualityAnalyzerFramesComparator::ProcessComparison(
if (comparison.type != FrameComparisonType::kDroppedFrame || if (comparison.type != FrameComparisonType::kDroppedFrame ||
comparison.frame_stats.decoder_failed) { comparison.frame_stats.decoder_failed) {
if (frame_stats.rendered_time.IsFinite()) { if (frame_stats.rendered_time.IsFinite()) {
stats->resolution_of_rendered_frame.AddSample(
StatsSample(*comparison.frame_stats.rendered_frame_width *
*comparison.frame_stats.rendered_frame_height,
frame_stats.rendered_time, metadata));
stats->total_delay_incl_transport_ms.AddSample( stats->total_delay_incl_transport_ms.AddSample(
StatsSample(frame_stats.rendered_time - frame_stats.captured_time, StatsSample(frame_stats.rendered_time - frame_stats.captured_time,
frame_stats.received_time, metadata)); frame_stats.received_time, metadata));
@ -507,6 +510,14 @@ void DefaultVideoQualityAnalyzerFramesComparator::ProcessComparison(
stats->decode_time_ms.AddSample(StatsSample( stats->decode_time_ms.AddSample(StatsSample(
frame_stats.decode_end_time - frame_stats.decode_start_time, frame_stats.decode_end_time - frame_stats.decode_start_time,
frame_stats.decode_end_time, metadata)); frame_stats.decode_end_time, metadata));
stats->resolution_of_decoded_frame.AddSample(
StatsSample(*comparison.frame_stats.decoded_frame_width *
*comparison.frame_stats.decoded_frame_height,
frame_stats.decode_end_time, metadata));
stats->resolution_of_rendered_frame.AddSample(
StatsSample(*comparison.frame_stats.decoded_frame_width *
*comparison.frame_stats.decoded_frame_height,
frame_stats.decode_end_time, metadata));
} }
if (frame_stats.prev_frame_rendered_time.IsFinite() && if (frame_stats.prev_frame_rendered_time.IsFinite() &&

View File

@ -86,8 +86,8 @@ FrameStats FrameStatsWith10msDeltaBetweenPhasesAnd10x10Frame(
frame_stats.used_encoder = Vp8CodecForOneFrame(1, frame_stats.encoded_time); frame_stats.used_encoder = Vp8CodecForOneFrame(1, frame_stats.encoded_time);
frame_stats.used_decoder = frame_stats.used_decoder =
Vp8CodecForOneFrame(1, frame_stats.decode_end_time); Vp8CodecForOneFrame(1, frame_stats.decode_end_time);
frame_stats.rendered_frame_width = 10; frame_stats.decoded_frame_width = 10;
frame_stats.rendered_frame_height = 10; frame_stats.decoded_frame_height = 10;
return frame_stats; return frame_stats;
} }
@ -102,8 +102,8 @@ FrameStats ShiftStatsOn(const FrameStats& stats, TimeDelta delta) {
frame_stats.used_encoder = stats.used_encoder; frame_stats.used_encoder = stats.used_encoder;
frame_stats.used_decoder = stats.used_decoder; frame_stats.used_decoder = stats.used_decoder;
frame_stats.rendered_frame_width = stats.rendered_frame_width; frame_stats.decoded_frame_width = stats.decoded_frame_width;
frame_stats.rendered_frame_height = stats.rendered_frame_height; frame_stats.decoded_frame_height = stats.decoded_frame_height;
return frame_stats; return frame_stats;
} }
@ -174,7 +174,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.at(stats_key).receive_to_render_time_ms), EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.at(stats_key).receive_to_render_time_ms),
30.0); 30.0);
EXPECT_DOUBLE_EQ( EXPECT_DOUBLE_EQ(
GetFirstOrDie(stats.at(stats_key).resolution_of_rendered_frame), 100.0); GetFirstOrDie(stats.at(stats_key).resolution_of_decoded_frame), 100.0);
} }
TEST( TEST(
@ -274,13 +274,13 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
frame_stats.captured_time + TimeDelta::Millis(50); frame_stats.captured_time + TimeDelta::Millis(50);
frame_stats.used_decoder = frame_stats.used_decoder =
Vp8CodecForOneFrame(1, frame_stats.decode_end_time); Vp8CodecForOneFrame(1, frame_stats.decode_end_time);
frame_stats.decoded_frame_width = 10;
frame_stats.decoded_frame_height = 10;
stats.push_back(frame_stats); stats.push_back(frame_stats);
// 6th stat // 6th stat
frame_stats = ShiftStatsOn(frame_stats, TimeDelta::Millis(15)); frame_stats = ShiftStatsOn(frame_stats, TimeDelta::Millis(15));
frame_stats.frame_id = 6; frame_stats.frame_id = 6;
frame_stats.rendered_time = frame_stats.captured_time + TimeDelta::Millis(60); frame_stats.rendered_time = frame_stats.captured_time + TimeDelta::Millis(60);
frame_stats.rendered_frame_width = 10;
frame_stats.rendered_frame_height = 10;
stats.push_back(frame_stats); stats.push_back(frame_stats);
comparator.Start(/*max_threads_count=*/1); comparator.Start(/*max_threads_count=*/1);
@ -323,9 +323,9 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
<< ToString(result_stats.receive_to_render_time_ms); << ToString(result_stats.receive_to_render_time_ms);
EXPECT_EQ(result_stats.receive_to_render_time_ms.NumSamples(), 1); EXPECT_EQ(result_stats.receive_to_render_time_ms.NumSamples(), 1);
EXPECT_DOUBLE_EQ(result_stats.resolution_of_rendered_frame.GetAverage(), 100) EXPECT_DOUBLE_EQ(result_stats.resolution_of_decoded_frame.GetAverage(), 100)
<< ToString(result_stats.resolution_of_rendered_frame); << ToString(result_stats.resolution_of_decoded_frame);
EXPECT_EQ(result_stats.resolution_of_rendered_frame.NumSamples(), 1); EXPECT_EQ(result_stats.resolution_of_decoded_frame.NumSamples(), 2);
EXPECT_DOUBLE_EQ(result_stats.encode_frame_rate.GetEventsPerSecond(), EXPECT_DOUBLE_EQ(result_stats.encode_frame_rate.GetEventsPerSecond(),
4.0 / 45 * 1000) 4.0 / 45 * 1000)
@ -375,7 +375,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
expectEmpty(stats.target_encode_bitrate); expectEmpty(stats.target_encode_bitrate);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -434,7 +434,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
expectEmpty(stats.target_encode_bitrate); expectEmpty(stats.target_encode_bitrate);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -501,7 +501,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -569,7 +569,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -642,7 +642,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -692,6 +692,9 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
frame_stats.decode_start_time = captured_time + TimeDelta::Millis(40); frame_stats.decode_start_time = captured_time + TimeDelta::Millis(40);
// Frame decoded // Frame decoded
frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50); frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50);
frame_stats.decoded_frame_width = 200;
frame_stats.decoded_frame_height = 100;
frame_stats.used_decoder = frame_stats.used_decoder =
Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time); Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
@ -719,7 +722,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); EXPECT_GE(GetFirstOrDie(stats.resolution_of_decoded_frame), 200 * 100.0);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -797,7 +800,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -859,7 +862,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
expectEmpty(stats.target_encode_bitrate); expectEmpty(stats.target_encode_bitrate);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -918,7 +921,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
expectEmpty(stats.target_encode_bitrate); expectEmpty(stats.target_encode_bitrate);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -985,7 +988,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -1053,7 +1056,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -1111,6 +1114,8 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50); frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50);
frame_stats.used_decoder = frame_stats.used_decoder =
Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time); Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
frame_stats.decoded_frame_width = 200;
frame_stats.decoded_frame_height = 100;
comparator.Start(/*max_threads_count=*/1); comparator.Start(/*max_threads_count=*/1);
comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2, comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2,
@ -1136,7 +1141,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
expectEmpty(stats.recv_key_frame_size_bytes); expectEmpty(stats.recv_key_frame_size_bytes);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -1214,7 +1219,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
expectEmpty(stats.resolution_of_rendered_frame); expectEmpty(stats.resolution_of_decoded_frame);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -1271,10 +1276,10 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50); frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50);
frame_stats.used_decoder = frame_stats.used_decoder =
Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time); Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
frame_stats.decoded_frame_width = 200;
frame_stats.decoded_frame_height = 100;
// Frame rendered // Frame rendered
frame_stats.rendered_time = captured_time + TimeDelta::Millis(60); frame_stats.rendered_time = captured_time + TimeDelta::Millis(60);
frame_stats.rendered_frame_width = 200;
frame_stats.rendered_frame_height = 100;
comparator.Start(/*max_threads_count=*/1); comparator.Start(/*max_threads_count=*/1);
comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2, comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2,
@ -1300,7 +1305,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest,
expectEmpty(stats.skipped_between_rendered); expectEmpty(stats.skipped_between_rendered);
expectEmpty(stats.freeze_time_ms); expectEmpty(stats.freeze_time_ms);
expectEmpty(stats.time_between_freezes_ms); expectEmpty(stats.time_between_freezes_ms);
EXPECT_GE(GetFirstOrDie(stats.resolution_of_rendered_frame), 200 * 100.0); EXPECT_GE(GetFirstOrDie(stats.resolution_of_decoded_frame), 200 * 100.0);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0); EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
expectEmpty(stats.recv_delta_frame_size_bytes); expectEmpty(stats.recv_delta_frame_size_bytes);
@ -1356,8 +1361,8 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest, AllStatsHaveMetadataSet) {
Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time); Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
// Frame rendered // Frame rendered
frame_stats.rendered_time = captured_time + TimeDelta::Millis(60); frame_stats.rendered_time = captured_time + TimeDelta::Millis(60);
frame_stats.rendered_frame_width = 200; frame_stats.decoded_frame_width = 200;
frame_stats.rendered_frame_height = 100; frame_stats.decoded_frame_height = 100;
comparator.Start(/*max_threads_count=*/1); comparator.Start(/*max_threads_count=*/1);
comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2, comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2,
@ -1378,7 +1383,7 @@ TEST(DefaultVideoQualityAnalyzerFramesComparatorTest, AllStatsHaveMetadataSet) {
AssertFirstMetadataHasField(stats.encode_time_ms, "frame_id", "1"); AssertFirstMetadataHasField(stats.encode_time_ms, "frame_id", "1");
AssertFirstMetadataHasField(stats.decode_time_ms, "frame_id", "1"); AssertFirstMetadataHasField(stats.decode_time_ms, "frame_id", "1");
AssertFirstMetadataHasField(stats.receive_to_render_time_ms, "frame_id", "1"); AssertFirstMetadataHasField(stats.receive_to_render_time_ms, "frame_id", "1");
AssertFirstMetadataHasField(stats.resolution_of_rendered_frame, "frame_id", AssertFirstMetadataHasField(stats.resolution_of_decoded_frame, "frame_id",
"1"); "1");
AssertFirstMetadataHasField(stats.target_encode_bitrate, "frame_id", "1"); AssertFirstMetadataHasField(stats.target_encode_bitrate, "frame_id", "1");
AssertFirstMetadataHasField(stats.recv_key_frame_size_bytes, "frame_id", "1"); AssertFirstMetadataHasField(stats.recv_key_frame_size_bytes, "frame_id", "1");

View File

@ -63,8 +63,8 @@ struct FrameStats {
DataSize pre_decoded_image_size = DataSize::Bytes(0); DataSize pre_decoded_image_size = DataSize::Bytes(0);
uint32_t target_encode_bitrate = 0; uint32_t target_encode_bitrate = 0;
absl::optional<int> rendered_frame_width = absl::nullopt; absl::optional<int> decoded_frame_width = absl::nullopt;
absl::optional<int> rendered_frame_height = absl::nullopt; absl::optional<int> decoded_frame_height = absl::nullopt;
// Can be not set if frame was dropped by encoder. // Can be not set if frame was dropped by encoder.
absl::optional<StreamCodecInfo> used_encoder = absl::nullopt; absl::optional<StreamCodecInfo> used_encoder = absl::nullopt;

View File

@ -142,6 +142,8 @@ struct StreamStats {
SamplesStatsCounter freeze_time_ms; SamplesStatsCounter freeze_time_ms;
// Mean time between one freeze end and next freeze start. // Mean time between one freeze end and next freeze start.
SamplesStatsCounter time_between_freezes_ms; SamplesStatsCounter time_between_freezes_ms;
SamplesStatsCounter resolution_of_decoded_frame;
// Deprecated. Used `resolution_of_decoded_frame` instead.
SamplesStatsCounter resolution_of_rendered_frame; SamplesStatsCounter resolution_of_rendered_frame;
SamplesStatsCounter target_encode_bitrate; SamplesStatsCounter target_encode_bitrate;

View File

@ -553,10 +553,10 @@ TEST(DefaultVideoQualityAnalyzerTest, NormalScenario2Receivers) {
EXPECT_GE(it->second.encode_time_ms.GetMin(), 20); EXPECT_GE(it->second.encode_time_ms.GetMin(), 20);
ASSERT_FALSE(it->second.decode_time_ms.IsEmpty()); ASSERT_FALSE(it->second.decode_time_ms.IsEmpty());
EXPECT_GE(it->second.decode_time_ms.GetMin(), 30); EXPECT_GE(it->second.decode_time_ms.GetMin(), 30);
ASSERT_FALSE(it->second.resolution_of_rendered_frame.IsEmpty()); ASSERT_FALSE(it->second.resolution_of_decoded_frame.IsEmpty());
EXPECT_GE(it->second.resolution_of_rendered_frame.GetMin(), EXPECT_GE(it->second.resolution_of_decoded_frame.GetMin(),
kFrameWidth * kFrameHeight - 1); kFrameWidth * kFrameHeight - 1);
EXPECT_LE(it->second.resolution_of_rendered_frame.GetMax(), EXPECT_LE(it->second.resolution_of_decoded_frame.GetMax(),
kFrameWidth * kFrameHeight + 1); kFrameWidth * kFrameHeight + 1);
} }
{ {
@ -566,10 +566,10 @@ TEST(DefaultVideoQualityAnalyzerTest, NormalScenario2Receivers) {
EXPECT_GE(it->second.encode_time_ms.GetMin(), 20); EXPECT_GE(it->second.encode_time_ms.GetMin(), 20);
ASSERT_FALSE(it->second.decode_time_ms.IsEmpty()); ASSERT_FALSE(it->second.decode_time_ms.IsEmpty());
EXPECT_GE(it->second.decode_time_ms.GetMin(), 30); EXPECT_GE(it->second.decode_time_ms.GetMin(), 30);
ASSERT_FALSE(it->second.resolution_of_rendered_frame.IsEmpty()); ASSERT_FALSE(it->second.resolution_of_decoded_frame.IsEmpty());
EXPECT_GE(it->second.resolution_of_rendered_frame.GetMin(), EXPECT_GE(it->second.resolution_of_decoded_frame.GetMin(),
kFrameWidth * kFrameHeight - 1); kFrameWidth * kFrameHeight - 1);
EXPECT_LE(it->second.resolution_of_rendered_frame.GetMax(), EXPECT_LE(it->second.resolution_of_decoded_frame.GetMax(),
kFrameWidth * kFrameHeight + 1); kFrameWidth * kFrameHeight + 1);
} }
} }