[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}
This commit is contained in:
parent
c62e1b8d10
commit
42d09cb1ba
@ -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",
|
||||
|
||||
@ -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 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured(
|
||||
|
||||
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 @@ 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<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
|
||||
|
||||
@ -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<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_);
|
||||
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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 @@ absl::optional<size_t> NamesCollection::RemoveIfPresent(
|
||||
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
|
||||
|
||||
@ -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 @@ class NamesCollection {
|
||||
// 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_;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user