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:
Artem Titov
2021-08-05 22:12:21 +02:00
committed by WebRTC LUCI CQ
parent 51e30837d5
commit a1aa9d732c
3 changed files with 122 additions and 15 deletions

View File

@ -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;
}

View File

@ -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.

View File

@ -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