From 42d09cb1ba54f7d5108c055f2323abeb2d9e2ce1 Mon Sep 17 00:00:00 2001 From: Artem Titov Date: Mon, 13 Jun 2022 10:21:58 +0200 Subject: [PATCH] [DVQA] Extract FrameInFlight into separate file Also add ability to remove expected receivers for the frame. Bug: b/231397778 Change-Id: Id1fb2df05a69e0dca4f05eaa995521b6be2ac52a Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/265396 Commit-Queue: Artem Titov Reviewed-by: Mirko Bonadei Cr-Commit-Position: refs/heads/main@{#37191} --- test/pc/e2e/BUILD.gn | 2 + .../video/default_video_quality_analyzer.cc | 180 +--------------- .../video/default_video_quality_analyzer.h | 113 +--------- ..._video_quality_analyzer_frame_in_flight.cc | 194 ++++++++++++++++++ ...t_video_quality_analyzer_frame_in_flight.h | 159 ++++++++++++++ .../pc/e2e/analyzer/video/names_collection.cc | 12 ++ test/pc/e2e/analyzer/video/names_collection.h | 5 + 7 files changed, 383 insertions(+), 282 deletions(-) create mode 100644 test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc create mode 100644 test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn index e88d53ddd8..43bd800316 100644 --- a/test/pc/e2e/BUILD.gn +++ b/test/pc/e2e/BUILD.gn @@ -734,6 +734,8 @@ if (!build_with_chromium) { sources = [ "analyzer/video/default_video_quality_analyzer_cpu_measurer.cc", "analyzer/video/default_video_quality_analyzer_cpu_measurer.h", + "analyzer/video/default_video_quality_analyzer_frame_in_flight.cc", + "analyzer/video/default_video_quality_analyzer_frame_in_flight.h", "analyzer/video/default_video_quality_analyzer_frames_comparator.cc", "analyzer/video/default_video_quality_analyzer_frames_comparator.h", "analyzer/video/default_video_quality_analyzer_internal_shared_objects.cc", diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc index ebebe9208d..5922c44e27 100644 --- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc +++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc @@ -12,7 +12,9 @@ #include #include +#include #include +#include #include "api/array_view.h" #include "api/numerics/samples_stats_counter.h" @@ -25,6 +27,7 @@ #include "rtc_base/strings/string_builder.h" #include "rtc_base/time_utils.h" #include "rtc_tools/frame_analyzer/video_geometry_aligner.h" +#include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_shared_objects.h" @@ -227,10 +230,13 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured( captured_frames_in_flight_.erase(it); } + std::set frame_receivers_indexes = peers_->GetPresentIndexes(); + if (!options_.enable_receive_own_stream) { + frame_receivers_indexes.erase(peer_index); + } captured_frames_in_flight_.emplace( - frame_id, - FrameInFlight(stream_index, frame, captured_time, peer_index, - peers_->size(), options_.enable_receive_own_stream)); + frame_id, FrameInFlight(stream_index, frame, captured_time, + std::move(frame_receivers_indexes))); // Set frame id on local copy of the frame captured_frames_in_flight_.at(frame_id).SetFrameId(frame_id); @@ -593,7 +599,7 @@ void DefaultVideoQualityAnalyzer::RegisterParticipantInCall( // frame, the frame will be removed by OnFrameRendered after next frame comes // for the new peer. It is important because FrameInFlight is a large object. for (auto& key_val : captured_frames_in_flight_) { - key_val.second.AddPeer(); + key_val.second.AddExpectedReceiver(new_peer_index); } } @@ -988,170 +994,4 @@ DefaultVideoQualityAnalyzer::GetStreamFrames() const { return out; } -bool DefaultVideoQualityAnalyzer::FrameInFlight::RemoveFrame() { - if (!frame_) { - return false; - } - frame_ = absl::nullopt; - return true; -} - -void DefaultVideoQualityAnalyzer::FrameInFlight::SetFrameId(uint16_t id) { - if (frame_) { - frame_->set_id(id); - } -} - -std::vector -DefaultVideoQualityAnalyzer::FrameInFlight::GetPeersWhichDidntReceive() const { - std::vector out; - for (size_t i = 0; i < peers_count_; ++i) { - auto it = receiver_stats_.find(i); - bool should_current_peer_receive = - i != owner_ || enable_receive_own_stream_; - if (should_current_peer_receive && - (it == receiver_stats_.end() || - it->second.rendered_time.IsInfinite())) { - out.push_back(i); - } - } - return out; -} - -bool DefaultVideoQualityAnalyzer::FrameInFlight::HaveAllPeersReceived() const { - for (size_t i = 0; i < peers_count_; ++i) { - // Skip `owner_` only if peer can't receive its own stream. - if (i == owner_ && !enable_receive_own_stream_) { - continue; - } - - auto it = receiver_stats_.find(i); - if (it == receiver_stats_.end()) { - return false; - } - - if (!it->second.dropped && it->second.rendered_time.IsInfinite()) { - return false; - } - } - return true; -} - -void DefaultVideoQualityAnalyzer::FrameInFlight::OnFrameEncoded( - webrtc::Timestamp time, - VideoFrameType frame_type, - DataSize encoded_image_size, - uint32_t target_encode_bitrate, - StreamCodecInfo used_encoder) { - encoded_time_ = time; - frame_type_ = frame_type; - encoded_image_size_ = encoded_image_size; - target_encode_bitrate_ += target_encode_bitrate; - // Update used encoder info. If simulcast/SVC is used, this method can - // be called multiple times, in such case we should preserve the value - // of `used_encoder_.switched_on_at` from the first invocation as the - // smallest one. - Timestamp encoder_switched_on_at = used_encoder_.has_value() - ? used_encoder_->switched_on_at - : Timestamp::PlusInfinity(); - RTC_DCHECK(used_encoder.switched_on_at.IsFinite()); - RTC_DCHECK(used_encoder.switched_from_at.IsFinite()); - used_encoder_ = used_encoder; - if (encoder_switched_on_at < used_encoder_->switched_on_at) { - used_encoder_->switched_on_at = encoder_switched_on_at; - } -} - -void DefaultVideoQualityAnalyzer::FrameInFlight::OnFramePreDecode( - size_t peer, - webrtc::Timestamp received_time, - webrtc::Timestamp decode_start_time, - VideoFrameType frame_type, - DataSize encoded_image_size) { - receiver_stats_[peer].received_time = received_time; - receiver_stats_[peer].decode_start_time = decode_start_time; - receiver_stats_[peer].frame_type = frame_type; - receiver_stats_[peer].encoded_image_size = encoded_image_size; -} - -bool DefaultVideoQualityAnalyzer::FrameInFlight::HasReceivedTime( - size_t peer) const { - auto it = receiver_stats_.find(peer); - if (it == receiver_stats_.end()) { - return false; - } - return it->second.received_time.IsFinite(); -} - -void DefaultVideoQualityAnalyzer::FrameInFlight::OnFrameDecoded( - size_t peer, - webrtc::Timestamp time, - StreamCodecInfo used_decoder) { - receiver_stats_[peer].decode_end_time = time; - receiver_stats_[peer].used_decoder = used_decoder; -} - -bool DefaultVideoQualityAnalyzer::FrameInFlight::HasDecodeEndTime( - size_t peer) const { - auto it = receiver_stats_.find(peer); - if (it == receiver_stats_.end()) { - return false; - } - return it->second.decode_end_time.IsFinite(); -} - -void DefaultVideoQualityAnalyzer::FrameInFlight::OnFrameRendered( - size_t peer, - webrtc::Timestamp time, - int width, - int height) { - receiver_stats_[peer].rendered_time = time; - receiver_stats_[peer].rendered_frame_width = width; - receiver_stats_[peer].rendered_frame_height = height; -} - -bool DefaultVideoQualityAnalyzer::FrameInFlight::HasRenderedTime( - size_t peer) const { - auto it = receiver_stats_.find(peer); - if (it == receiver_stats_.end()) { - return false; - } - return it->second.rendered_time.IsFinite(); -} - -bool DefaultVideoQualityAnalyzer::FrameInFlight::IsDropped(size_t peer) const { - auto it = receiver_stats_.find(peer); - if (it == receiver_stats_.end()) { - return false; - } - return it->second.dropped; -} - -FrameStats DefaultVideoQualityAnalyzer::FrameInFlight::GetStatsForPeer( - size_t peer) const { - FrameStats stats(captured_time_); - stats.pre_encode_time = pre_encode_time_; - stats.encoded_time = encoded_time_; - stats.target_encode_bitrate = target_encode_bitrate_; - stats.encoded_frame_type = frame_type_; - stats.encoded_image_size = encoded_image_size_; - stats.used_encoder = used_encoder_; - - absl::optional receiver_stats = - MaybeGetValue(receiver_stats_, peer); - if (receiver_stats.has_value()) { - stats.received_time = receiver_stats->received_time; - stats.decode_start_time = receiver_stats->decode_start_time; - stats.decode_end_time = receiver_stats->decode_end_time; - stats.rendered_time = receiver_stats->rendered_time; - stats.prev_frame_rendered_time = receiver_stats->prev_frame_rendered_time; - stats.rendered_frame_width = receiver_stats->rendered_frame_width; - stats.rendered_frame_height = receiver_stats->rendered_frame_height; - stats.used_decoder = receiver_stats->used_decoder; - stats.pre_decoded_frame_type = receiver_stats->frame_type; - stats.pre_decoded_image_size = receiver_stats->encoded_image_size; - } - return stats; -} - } // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h index b9d8e3eccd..6d4818f15d 100644 --- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h +++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h @@ -34,6 +34,7 @@ #include "rtc_base/thread_annotations.h" #include "system_wrappers/include/clock.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_cpu_measurer.h" +#include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_shared_objects.h" @@ -108,118 +109,6 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { private: enum State { kNew, kActive, kStopped }; - struct ReceiverFrameStats { - // Time when last packet of a frame was received. - Timestamp received_time = Timestamp::MinusInfinity(); - Timestamp decode_start_time = Timestamp::MinusInfinity(); - Timestamp decode_end_time = Timestamp::MinusInfinity(); - Timestamp rendered_time = Timestamp::MinusInfinity(); - Timestamp prev_frame_rendered_time = Timestamp::MinusInfinity(); - - // Type and encoded size of received frame. - VideoFrameType frame_type = VideoFrameType::kEmptyFrame; - DataSize encoded_image_size = DataSize::Bytes(0); - - absl::optional rendered_frame_width = absl::nullopt; - absl::optional rendered_frame_height = absl::nullopt; - - // Can be not set if frame was dropped in the network. - absl::optional used_decoder = absl::nullopt; - - bool dropped = false; - }; - - class FrameInFlight { - public: - FrameInFlight(size_t stream, - VideoFrame frame, - Timestamp captured_time, - size_t owner, - size_t peers_count, - bool enable_receive_own_stream) - : stream_(stream), - owner_(owner), - peers_count_(peers_count), - enable_receive_own_stream_(enable_receive_own_stream), - frame_(std::move(frame)), - captured_time_(captured_time) {} - - size_t stream() const { return stream_; } - const absl::optional& frame() const { return frame_; } - // Returns was frame removed or not. - bool RemoveFrame(); - void SetFrameId(uint16_t id); - - void AddPeer() { ++peers_count_; } - - std::vector GetPeersWhichDidntReceive() const; - bool HaveAllPeersReceived() const; - - void SetPreEncodeTime(webrtc::Timestamp time) { pre_encode_time_ = time; } - - void OnFrameEncoded(webrtc::Timestamp time, - VideoFrameType frame_type, - DataSize encoded_image_size, - uint32_t target_encode_bitrate, - StreamCodecInfo used_encoder); - - bool HasEncodedTime() const { return encoded_time_.IsFinite(); } - - void OnFramePreDecode(size_t peer, - webrtc::Timestamp received_time, - webrtc::Timestamp decode_start_time, - VideoFrameType frame_type, - DataSize encoded_image_size); - - bool HasReceivedTime(size_t peer) const; - - void OnFrameDecoded(size_t peer, - webrtc::Timestamp time, - StreamCodecInfo used_decoder); - - bool HasDecodeEndTime(size_t peer) const; - - void OnFrameRendered(size_t peer, - webrtc::Timestamp time, - int width, - int height); - - bool HasRenderedTime(size_t peer) const; - - // Crash if rendered time is not set for specified `peer`. - webrtc::Timestamp rendered_time(size_t peer) const { - return receiver_stats_.at(peer).rendered_time; - } - - void MarkDropped(size_t peer) { receiver_stats_[peer].dropped = true; } - bool IsDropped(size_t peer) const; - - void SetPrevFrameRenderedTime(size_t peer, webrtc::Timestamp time) { - receiver_stats_[peer].prev_frame_rendered_time = time; - } - - FrameStats GetStatsForPeer(size_t peer) const; - - private: - const size_t stream_; - const size_t owner_; - size_t peers_count_; - const bool enable_receive_own_stream_; - absl::optional frame_; - - // Frame events timestamp. - Timestamp captured_time_; - Timestamp pre_encode_time_ = Timestamp::MinusInfinity(); - Timestamp encoded_time_ = Timestamp::MinusInfinity(); - // Type and encoded size of sent frame. - VideoFrameType frame_type_ = VideoFrameType::kEmptyFrame; - DataSize encoded_image_size_ = DataSize::Bytes(0); - uint32_t target_encode_bitrate_ = 0; - // Can be not set if frame was dropped by encoder. - absl::optional used_encoder_ = absl::nullopt; - std::map receiver_stats_; - }; - // Returns next frame id to use. Frame ID can't be `VideoFrame::kNotSetId`, // because this value is reserved by `VideoFrame` as "ID not set". uint16_t GetNextFrameId() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc new file mode 100644 index 0000000000..13e77b4586 --- /dev/null +++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h" + +#include +#include + +#include "absl/types/optional.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" +#include "api/video/video_frame_type.h" +#include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h" + +namespace webrtc { +namespace { + +template +absl::optional MaybeGetValue(const std::map& map, size_t key) { + auto it = map.find(key); + if (it == map.end()) { + return absl::nullopt; + } + return it->second; +} + +} // namespace + +FrameInFlight::FrameInFlight(size_t stream, + VideoFrame frame, + Timestamp captured_time, + std::set expected_receivers) + : stream_(stream), + expected_receivers_(std::move(expected_receivers)), + frame_(std::move(frame)), + captured_time_(captured_time) {} + +bool FrameInFlight::RemoveFrame() { + if (!frame_) { + return false; + } + frame_ = absl::nullopt; + return true; +} + +void FrameInFlight::SetFrameId(uint16_t id) { + if (frame_) { + frame_->set_id(id); + } +} + +std::vector FrameInFlight::GetPeersWhichDidntReceive() const { + std::vector out; + for (size_t peer : expected_receivers_) { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end() || + (!it->second.dropped && it->second.rendered_time.IsInfinite())) { + out.push_back(peer); + } + } + return out; +} + +bool FrameInFlight::HaveAllPeersReceived() const { + for (size_t peer : expected_receivers_) { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + + if (!it->second.dropped && it->second.rendered_time.IsInfinite()) { + return false; + } + } + return true; +} + +void FrameInFlight::OnFrameEncoded(webrtc::Timestamp time, + VideoFrameType frame_type, + DataSize encoded_image_size, + uint32_t target_encode_bitrate, + StreamCodecInfo used_encoder) { + encoded_time_ = time; + frame_type_ = frame_type; + encoded_image_size_ = encoded_image_size; + target_encode_bitrate_ += target_encode_bitrate; + // Update used encoder info. If simulcast/SVC is used, this method can + // be called multiple times, in such case we should preserve the value + // of `used_encoder_.switched_on_at` from the first invocation as the + // smallest one. + Timestamp encoder_switched_on_at = used_encoder_.has_value() + ? used_encoder_->switched_on_at + : Timestamp::PlusInfinity(); + RTC_DCHECK(used_encoder.switched_on_at.IsFinite()); + RTC_DCHECK(used_encoder.switched_from_at.IsFinite()); + used_encoder_ = used_encoder; + if (encoder_switched_on_at < used_encoder_->switched_on_at) { + used_encoder_->switched_on_at = encoder_switched_on_at; + } +} + +void FrameInFlight::OnFramePreDecode(size_t peer, + webrtc::Timestamp received_time, + webrtc::Timestamp decode_start_time, + VideoFrameType frame_type, + DataSize encoded_image_size) { + receiver_stats_[peer].received_time = received_time; + receiver_stats_[peer].decode_start_time = decode_start_time; + receiver_stats_[peer].frame_type = frame_type; + receiver_stats_[peer].encoded_image_size = encoded_image_size; +} + +bool FrameInFlight::HasReceivedTime(size_t peer) const { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + return it->second.received_time.IsFinite(); +} + +void FrameInFlight::OnFrameDecoded(size_t peer, + webrtc::Timestamp time, + StreamCodecInfo used_decoder) { + receiver_stats_[peer].decode_end_time = time; + receiver_stats_[peer].used_decoder = used_decoder; +} + +bool FrameInFlight::HasDecodeEndTime(size_t peer) const { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + return it->second.decode_end_time.IsFinite(); +} + +void FrameInFlight::OnFrameRendered(size_t peer, + webrtc::Timestamp time, + int width, + int height) { + 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 { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + return it->second.rendered_time.IsFinite(); +} + +bool FrameInFlight::IsDropped(size_t peer) const { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + return it->second.dropped; +} + +FrameStats FrameInFlight::GetStatsForPeer(size_t peer) const { + FrameStats stats(captured_time_); + stats.pre_encode_time = pre_encode_time_; + stats.encoded_time = encoded_time_; + stats.target_encode_bitrate = target_encode_bitrate_; + stats.encoded_frame_type = frame_type_; + stats.encoded_image_size = encoded_image_size_; + stats.used_encoder = used_encoder_; + + absl::optional receiver_stats = + MaybeGetValue(receiver_stats_, peer); + if (receiver_stats.has_value()) { + stats.received_time = receiver_stats->received_time; + stats.decode_start_time = receiver_stats->decode_start_time; + stats.decode_end_time = receiver_stats->decode_end_time; + stats.rendered_time = receiver_stats->rendered_time; + stats.prev_frame_rendered_time = receiver_stats->prev_frame_rendered_time; + stats.rendered_frame_width = receiver_stats->rendered_frame_width; + stats.rendered_frame_height = receiver_stats->rendered_frame_height; + stats.used_decoder = receiver_stats->used_decoder; + stats.pre_decoded_frame_type = receiver_stats->frame_type; + stats.pre_decoded_image_size = receiver_stats->encoded_image_size; + } + return stats; +} + +} // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h new file mode 100644 index 0000000000..a1ce8faf5b --- /dev/null +++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_PC_E2E_ANALYZER_VIDEO_DEFAULT_VIDEO_QUALITY_ANALYZER_FRAME_IN_FLIGHT_H_ +#define TEST_PC_E2E_ANALYZER_VIDEO_DEFAULT_VIDEO_QUALITY_ANALYZER_FRAME_IN_FLIGHT_H_ + +#include +#include +#include +#include + +#include "absl/types/optional.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" +#include "api/video/video_frame.h" +#include "api/video/video_frame_type.h" +#include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h" + +namespace webrtc { + +struct ReceiverFrameStats { + // Time when last packet of a frame was received. + Timestamp received_time = Timestamp::MinusInfinity(); + Timestamp decode_start_time = Timestamp::MinusInfinity(); + Timestamp decode_end_time = Timestamp::MinusInfinity(); + Timestamp rendered_time = Timestamp::MinusInfinity(); + Timestamp prev_frame_rendered_time = Timestamp::MinusInfinity(); + + // Type and encoded size of received frame. + VideoFrameType frame_type = VideoFrameType::kEmptyFrame; + DataSize encoded_image_size = DataSize::Bytes(0); + + absl::optional rendered_frame_width = absl::nullopt; + absl::optional rendered_frame_height = absl::nullopt; + + // Can be not set if frame was dropped in the network. + absl::optional used_decoder = absl::nullopt; + + bool dropped = false; +}; + +// Represents a frame which was sent by sender and is currently on the way to +// multiple receivers. Some receivers may receive this frame and some don't. +// +// Contains all statistic associated with the frame and gathered in multiple +// points of the video pipeline. +// +// Internally may store the copy of the source frame which was sent. In such +// case this frame is "alive". +class FrameInFlight { + public: + FrameInFlight(size_t stream, + VideoFrame frame, + Timestamp captured_time, + std::set expected_receivers); + + size_t stream() const { return stream_; } + // Returns internal copy of source `VideoFrame` or `absl::nullopt` if it was + // removed before. + const absl::optional& frame() const { return frame_; } + // Removes internal copy of the source `VideoFrame` to free up extra memory. + // Returns was frame removed or not. + bool RemoveFrame(); + void SetFrameId(uint16_t id); + + void AddExpectedReceiver(size_t peer) { expected_receivers_.insert(peer); } + + void RemoveExpectedReceiver(size_t peer) { expected_receivers_.erase(peer); } + + std::vector GetPeersWhichDidntReceive() const; + + // Returns if all peers which were expected to receive this frame actually + // received it or not. + bool HaveAllPeersReceived() const; + + void SetPreEncodeTime(webrtc::Timestamp time) { pre_encode_time_ = time; } + + void OnFrameEncoded(webrtc::Timestamp time, + VideoFrameType frame_type, + DataSize encoded_image_size, + uint32_t target_encode_bitrate, + StreamCodecInfo used_encoder); + + bool HasEncodedTime() const { return encoded_time_.IsFinite(); } + + void OnFramePreDecode(size_t peer, + webrtc::Timestamp received_time, + webrtc::Timestamp decode_start_time, + VideoFrameType frame_type, + DataSize encoded_image_size); + + bool HasReceivedTime(size_t peer) const; + + void OnFrameDecoded(size_t peer, + webrtc::Timestamp time, + StreamCodecInfo used_decoder); + + bool HasDecodeEndTime(size_t peer) const; + + void OnFrameRendered(size_t peer, + webrtc::Timestamp time, + int width, + int height); + + bool HasRenderedTime(size_t peer) const; + + // Crash if rendered time is not set for specified `peer`. + webrtc::Timestamp rendered_time(size_t peer) const { + return receiver_stats_.at(peer).rendered_time; + } + + // Marks that frame was dropped and wasn't seen by particular `peer`. + void MarkDropped(size_t peer) { receiver_stats_[peer].dropped = true; } + bool IsDropped(size_t peer) const; + + void SetPrevFrameRenderedTime(size_t peer, webrtc::Timestamp time) { + receiver_stats_[peer].prev_frame_rendered_time = time; + } + + FrameStats GetStatsForPeer(size_t peer) const; + + private: + const size_t stream_; + // Set of peer's indexes who are expected to receive this frame. This is not + // the set of peer's indexes that received the frame. For example, if peer A + // was among expected receivers, it received frame and then left the call, A + // will be removed from this set, but the Stats for peer A still will be + // preserved in the FrameInFlight. + // + // This set is used to determine if this frame is expected to be received by + // any peer or can be safely deleted. It is responsibility of the user of this + // object to decide when it should be deleted. + std::set expected_receivers_; + absl::optional frame_; + + // Frame events timestamp. + Timestamp captured_time_; + Timestamp pre_encode_time_ = Timestamp::MinusInfinity(); + Timestamp encoded_time_ = Timestamp::MinusInfinity(); + // Type and encoded size of sent frame. + VideoFrameType frame_type_ = VideoFrameType::kEmptyFrame; + DataSize encoded_image_size_ = DataSize::Bytes(0); + uint32_t target_encode_bitrate_ = 0; + // Can be not set if frame was dropped by encoder. + absl::optional used_encoder_ = absl::nullopt; + // Map from the receiver peer's index to frame stats for that peer. + std::map receiver_stats_; +}; + +} // namespace webrtc + +#endif // TEST_PC_E2E_ANALYZER_VIDEO_DEFAULT_VIDEO_QUALITY_ANALYZER_FRAME_IN_FLIGHT_H_ diff --git a/test/pc/e2e/analyzer/video/names_collection.cc b/test/pc/e2e/analyzer/video/names_collection.cc index 845f73d398..6ee2ef06ec 100644 --- a/test/pc/e2e/analyzer/video/names_collection.cc +++ b/test/pc/e2e/analyzer/video/names_collection.cc @@ -10,6 +10,8 @@ #include "test/pc/e2e/analyzer/video/names_collection.h" +#include + #include "absl/strings/string_view.h" #include "absl/types/optional.h" @@ -78,4 +80,14 @@ absl::optional NamesCollection::RemoveIfPresent( return index; } +std::set NamesCollection::GetPresentIndexes() const { + std::set out; + for (size_t i = 0; i < removed_.size(); ++i) { + if (!removed_[i]) { + out.insert(i); + } + } + return out; +} + } // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/names_collection.h b/test/pc/e2e/analyzer/video/names_collection.h index 77c4939f85..4b4a439e35 100644 --- a/test/pc/e2e/analyzer/video/names_collection.h +++ b/test/pc/e2e/analyzer/video/names_collection.h @@ -12,6 +12,7 @@ #define TEST_PC_E2E_ANALYZER_VIDEO_NAMES_COLLECTION_H_ #include +#include #include #include @@ -70,6 +71,10 @@ class NamesCollection { // registered in the collection. absl::optional RemoveIfPresent(absl::string_view name); + // Returns a set of indexes for all currently present names in the + // collection. + std::set GetPresentIndexes() const; + private: std::vector names_; std::vector removed_;