Allow DVQA analyse selft stream for peer
Bug: b/195652126 Change-Id: Ie65e238028b932866a39aeec3797ac576c5f6c1c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/227769 Commit-Queue: Artem Titov <titovartem@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34656}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
51e30837d5
commit
a1aa9d732c
@ -180,7 +180,7 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured(
|
||||
// Ensure stats for this stream exists.
|
||||
MutexLock lock(&comparison_lock_);
|
||||
for (size_t i = 0; i < peers_count; ++i) {
|
||||
if (i == peer_index) {
|
||||
if (i == peer_index && !options_.enable_receive_own_stream) {
|
||||
continue;
|
||||
}
|
||||
InternalStatsKey stats_key(stream_index, peer_index, i);
|
||||
@ -205,7 +205,7 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured(
|
||||
stream_to_sender_[stream_index] = peer_index;
|
||||
frame_counters_.captured++;
|
||||
for (size_t i = 0; i < peers_->size(); ++i) {
|
||||
if (i != peer_index) {
|
||||
if (i != peer_index || options_.enable_receive_own_stream) {
|
||||
InternalStatsKey key(stream_index, peer_index, i);
|
||||
stream_frame_counters_[key].captured++;
|
||||
}
|
||||
@ -214,7 +214,8 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured(
|
||||
auto state_it = stream_states_.find(stream_index);
|
||||
if (state_it == stream_states_.end()) {
|
||||
stream_states_.emplace(stream_index,
|
||||
StreamState(peer_index, peers_->size()));
|
||||
StreamState(peer_index, peers_->size(),
|
||||
options_.enable_receive_own_stream));
|
||||
}
|
||||
StreamState* state = &stream_states_.at(stream_index);
|
||||
state->PushBack(frame_id);
|
||||
@ -225,7 +226,7 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured(
|
||||
// still in flight, it means that this stream wasn't rendered for long
|
||||
// time and we need to process existing frame as dropped.
|
||||
for (size_t i = 0; i < peers_->size(); ++i) {
|
||||
if (i == peer_index) {
|
||||
if (i == peer_index && !options_.enable_receive_own_stream) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -248,7 +249,8 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured(
|
||||
captured_frames_in_flight_.emplace(
|
||||
frame_id,
|
||||
FrameInFlight(stream_index, frame,
|
||||
/*captured_time=*/Now(), peer_index, peers_->size()));
|
||||
/*captured_time=*/Now(), peer_index, peers_->size(),
|
||||
options_.enable_receive_own_stream));
|
||||
// Set frame id on local copy of the frame
|
||||
captured_frames_in_flight_.at(frame_id).SetFrameId(frame_id);
|
||||
|
||||
@ -287,7 +289,7 @@ void DefaultVideoQualityAnalyzer::OnFramePreEncode(
|
||||
frame_counters_.pre_encoded++;
|
||||
size_t peer_index = peers_->index(peer_name);
|
||||
for (size_t i = 0; i < peers_->size(); ++i) {
|
||||
if (i != peer_index) {
|
||||
if (i != peer_index || options_.enable_receive_own_stream) {
|
||||
InternalStatsKey key(it->second.stream(), peer_index, i);
|
||||
stream_frame_counters_.at(key).pre_encoded++;
|
||||
}
|
||||
@ -318,7 +320,7 @@ void DefaultVideoQualityAnalyzer::OnFrameEncoded(
|
||||
frame_counters_.encoded++;
|
||||
size_t peer_index = peers_->index(peer_name);
|
||||
for (size_t i = 0; i < peers_->size(); ++i) {
|
||||
if (i != peer_index) {
|
||||
if (i != peer_index || options_.enable_receive_own_stream) {
|
||||
InternalStatsKey key(it->second.stream(), peer_index, i);
|
||||
stream_frame_counters_.at(key).encoded++;
|
||||
}
|
||||
@ -965,7 +967,7 @@ StatsKey DefaultVideoQualityAnalyzer::ToStatsKey(
|
||||
|
||||
std::string DefaultVideoQualityAnalyzer::StatsKeyToMetricName(
|
||||
const StatsKey& key) const {
|
||||
if (peers_->size() <= 2) {
|
||||
if (peers_->size() <= 2 && key.sender != key.receiver) {
|
||||
return key.stream_label;
|
||||
}
|
||||
return key.ToString();
|
||||
@ -1026,7 +1028,12 @@ uint16_t DefaultVideoQualityAnalyzer::StreamState::PopFront(size_t peer) {
|
||||
other_size = cur_size;
|
||||
}
|
||||
}
|
||||
if (owner_size > other_size) {
|
||||
// Pops frame from owner queue if owner's queue is the longest and one of
|
||||
// next conditions is true:
|
||||
// 1. If `enable_receive_own_stream_` and `peer` == `owner_`
|
||||
// 2. If !`enable_receive_own_stream_`
|
||||
if (owner_size > other_size &&
|
||||
(!enable_receive_own_stream_ || peer == owner_)) {
|
||||
absl::optional<uint16_t> alive_frame_id = frame_ids_.PopFront(owner_);
|
||||
RTC_DCHECK(alive_frame_id.has_value());
|
||||
RTC_DCHECK_EQ(frame_id.value(), alive_frame_id.value());
|
||||
@ -1077,8 +1084,11 @@ DefaultVideoQualityAnalyzer::FrameInFlight::GetPeersWhichDidntReceive() const {
|
||||
std::vector<size_t> out;
|
||||
for (size_t i = 0; i < peers_count_; ++i) {
|
||||
auto it = receiver_stats_.find(i);
|
||||
if (i != owner_ && it != receiver_stats_.end() &&
|
||||
it->second.rendered_time.IsInfinite()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1087,7 +1097,8 @@ DefaultVideoQualityAnalyzer::FrameInFlight::GetPeersWhichDidntReceive() const {
|
||||
|
||||
bool DefaultVideoQualityAnalyzer::FrameInFlight::HaveAllPeersReceived() const {
|
||||
for (size_t i = 0; i < peers_count_; ++i) {
|
||||
if (i == owner_) {
|
||||
// Skip `owner_` only if peer can't receive its own stream.
|
||||
if (i == owner_ && !enable_receive_own_stream_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -183,6 +183,8 @@ struct DefaultVideoQualityAnalyzerOptions {
|
||||
// receivers per stream.
|
||||
size_t max_frames_in_flight_per_stream_count =
|
||||
kDefaultMaxFramesInFlightPerStream;
|
||||
// If true, the analyzer will expect peers to receive their own video streams.
|
||||
bool enable_receive_own_stream = false;
|
||||
};
|
||||
|
||||
class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface {
|
||||
@ -304,8 +306,12 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface {
|
||||
// Represents a current state of video stream.
|
||||
class StreamState {
|
||||
public:
|
||||
StreamState(size_t owner, size_t peers_count)
|
||||
: owner_(owner), frame_ids_(peers_count) {}
|
||||
StreamState(size_t owner,
|
||||
size_t peers_count,
|
||||
bool enable_receive_own_stream)
|
||||
: owner_(owner),
|
||||
enable_receive_own_stream_(enable_receive_own_stream),
|
||||
frame_ids_(peers_count) {}
|
||||
|
||||
size_t owner() const { return owner_; }
|
||||
|
||||
@ -331,6 +337,7 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface {
|
||||
private:
|
||||
// Index of the owner. Owner's queue in `frame_ids_` will keep alive frames.
|
||||
const size_t owner_;
|
||||
const bool enable_receive_own_stream_;
|
||||
// To correctly determine dropped frames we have to know sequence of frames
|
||||
// in each stream so we will keep a list of frame ids inside the stream.
|
||||
// This list is represented by multi head queue of frame ids with separate
|
||||
@ -373,10 +380,12 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface {
|
||||
VideoFrame frame,
|
||||
Timestamp captured_time,
|
||||
size_t owner,
|
||||
size_t peers_count)
|
||||
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) {}
|
||||
|
||||
@ -435,6 +444,7 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface {
|
||||
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.
|
||||
|
@ -963,6 +963,92 @@ TEST(DefaultVideoQualityAnalyzerTest,
|
||||
EXPECT_EQ(frame_counters.rendered, 2);
|
||||
}
|
||||
|
||||
TEST(DefaultVideoQualityAnalyzerTest, FrameCanBeReceivedBySender) {
|
||||
std::unique_ptr<test::FrameGeneratorInterface> frame_generator =
|
||||
test::CreateSquareFrameGenerator(kFrameWidth, kFrameHeight,
|
||||
/*type=*/absl::nullopt,
|
||||
/*num_squares=*/absl::nullopt);
|
||||
|
||||
DefaultVideoQualityAnalyzerOptions options = AnalyzerOptionsForTest();
|
||||
options.enable_receive_own_stream = true;
|
||||
DefaultVideoQualityAnalyzer analyzer(Clock::GetRealTimeClock(), options);
|
||||
analyzer.Start("test_case",
|
||||
std::vector<std::string>{kSenderPeerName, kReceiverPeerName},
|
||||
kAnalyzerMaxThreadsCount);
|
||||
|
||||
VideoFrame frame = NextFrame(frame_generator.get(), 1);
|
||||
|
||||
frame.set_id(analyzer.OnFrameCaptured(kSenderPeerName, kStreamLabel, frame));
|
||||
analyzer.OnFramePreEncode(kSenderPeerName, frame);
|
||||
analyzer.OnFrameEncoded(kSenderPeerName, frame.id(), FakeEncode(frame),
|
||||
VideoQualityAnalyzerInterface::EncoderStats());
|
||||
|
||||
// Receive by 2nd peer.
|
||||
VideoFrame received_frame = DeepCopy(frame);
|
||||
analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(),
|
||||
FakeEncode(received_frame));
|
||||
analyzer.OnFrameDecoded(kReceiverPeerName, received_frame,
|
||||
VideoQualityAnalyzerInterface::DecoderStats());
|
||||
analyzer.OnFrameRendered(kReceiverPeerName, received_frame);
|
||||
|
||||
// Check that we still have that frame in flight.
|
||||
AnalyzerStats analyzer_stats = analyzer.GetAnalyzerStats();
|
||||
std::vector<StatsSample> frames_in_flight_sizes =
|
||||
GetSortedSamples(analyzer_stats.frames_in_flight_left_count);
|
||||
EXPECT_EQ(frames_in_flight_sizes.back().value, 1)
|
||||
<< "Expected that frame is still in flight, "
|
||||
<< "because it wasn't received by sender"
|
||||
<< ToString(frames_in_flight_sizes);
|
||||
|
||||
// Receive by sender
|
||||
received_frame = DeepCopy(frame);
|
||||
analyzer.OnFramePreDecode(kSenderPeerName, received_frame.id(),
|
||||
FakeEncode(received_frame));
|
||||
analyzer.OnFrameDecoded(kSenderPeerName, received_frame,
|
||||
VideoQualityAnalyzerInterface::DecoderStats());
|
||||
analyzer.OnFrameRendered(kSenderPeerName, received_frame);
|
||||
|
||||
// Give analyzer some time to process frames on async thread. The computations
|
||||
// have to be fast (heavy metrics are disabled!), so if doesn't fit 100ms it
|
||||
// means we have an issue!
|
||||
SleepMs(100);
|
||||
analyzer.Stop();
|
||||
|
||||
analyzer_stats = analyzer.GetAnalyzerStats();
|
||||
EXPECT_EQ(analyzer_stats.comparisons_done, 2);
|
||||
|
||||
frames_in_flight_sizes =
|
||||
GetSortedSamples(analyzer_stats.frames_in_flight_left_count);
|
||||
EXPECT_EQ(frames_in_flight_sizes.back().value, 0)
|
||||
<< ToString(frames_in_flight_sizes);
|
||||
|
||||
FrameCounters frame_counters = analyzer.GetGlobalCounters();
|
||||
EXPECT_EQ(frame_counters.captured, 1);
|
||||
EXPECT_EQ(frame_counters.rendered, 2);
|
||||
|
||||
EXPECT_EQ(analyzer.GetStats().size(), 2lu);
|
||||
{
|
||||
FrameCounters stream_conters = analyzer.GetPerStreamCounters().at(
|
||||
StatsKey(kStreamLabel, kSenderPeerName, kReceiverPeerName));
|
||||
EXPECT_EQ(stream_conters.captured, 1);
|
||||
EXPECT_EQ(stream_conters.pre_encoded, 1);
|
||||
EXPECT_EQ(stream_conters.encoded, 1);
|
||||
EXPECT_EQ(stream_conters.received, 1);
|
||||
EXPECT_EQ(stream_conters.decoded, 1);
|
||||
EXPECT_EQ(stream_conters.rendered, 1);
|
||||
}
|
||||
{
|
||||
FrameCounters stream_conters = analyzer.GetPerStreamCounters().at(
|
||||
StatsKey(kStreamLabel, kSenderPeerName, kSenderPeerName));
|
||||
EXPECT_EQ(stream_conters.captured, 1);
|
||||
EXPECT_EQ(stream_conters.pre_encoded, 1);
|
||||
EXPECT_EQ(stream_conters.encoded, 1);
|
||||
EXPECT_EQ(stream_conters.received, 1);
|
||||
EXPECT_EQ(stream_conters.decoded, 1);
|
||||
EXPECT_EQ(stream_conters.rendered, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace webrtc_pc_e2e
|
||||
} // namespace webrtc
|
||||
|
Reference in New Issue
Block a user