[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 <titovartem@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37191}
diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn
index e88d53d..43bd800 100644
--- a/test/pc/e2e/BUILD.gn
+++ b/test/pc/e2e/BUILD.gn
@@ -734,6 +734,8 @@
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 ebebe92..5922c44 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 <algorithm>
#include <memory>
+#include <set>
#include <utility>
+#include <vector>
#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 @@
captured_frames_in_flight_.erase(it);
}
+ std::set<size_t> 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 @@
// 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 @@
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<size_t>
-DefaultVideoQualityAnalyzer::FrameInFlight::GetPeersWhichDidntReceive() const {
- std::vector<size_t> 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<ReceiverFrameStats> receiver_stats =
- MaybeGetValue<ReceiverFrameStats>(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 b9d8e3e..6d4818f 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 @@
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<int> rendered_frame_width = absl::nullopt;
- absl::optional<int> rendered_frame_height = absl::nullopt;
-
- // Can be not set if frame was dropped in the network.
- absl::optional<StreamCodecInfo> 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<VideoFrame>& frame() const { return frame_; }
- // Returns was frame removed or not.
- bool RemoveFrame();
- void SetFrameId(uint16_t id);
-
- void AddPeer() { ++peers_count_; }
-
- std::vector<size_t> 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<VideoFrame> 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<StreamCodecInfo> used_encoder_ = absl::nullopt;
- std::map<size_t, ReceiverFrameStats> 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 0000000..13e77b4
--- /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 <utility>
+#include <vector>
+
+#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 <typename T>
+absl::optional<T> MaybeGetValue(const std::map<size_t, T>& 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<size_t> 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<size_t> FrameInFlight::GetPeersWhichDidntReceive() const {
+ std::vector<size_t> 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<ReceiverFrameStats> receiver_stats =
+ MaybeGetValue<ReceiverFrameStats>(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 0000000..a1ce8fa
--- /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 <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#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<int> rendered_frame_width = absl::nullopt;
+ absl::optional<int> rendered_frame_height = absl::nullopt;
+
+ // Can be not set if frame was dropped in the network.
+ absl::optional<StreamCodecInfo> 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<size_t> 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<VideoFrame>& 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<size_t> 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<size_t> expected_receivers_;
+ absl::optional<VideoFrame> 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<StreamCodecInfo> used_encoder_ = absl::nullopt;
+ // Map from the receiver peer's index to frame stats for that peer.
+ std::map<size_t, ReceiverFrameStats> 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 845f73d..6ee2ef0 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 <set>
+
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@@ -78,4 +80,14 @@
return index;
}
+std::set<size_t> NamesCollection::GetPresentIndexes() const {
+ std::set<size_t> 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 77c4939..4b4a439 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 <map>
+#include <set>
#include <string>
#include <vector>
@@ -70,6 +71,10 @@
// registered in the collection.
absl::optional<size_t> RemoveIfPresent(absl::string_view name);
+ // Returns a set of indexes for all currently present names in the
+ // collection.
+ std::set<size_t> GetPresentIndexes() const;
+
private:
std::vector<std::string> names_;
std::vector<bool> removed_;