Plot bitrate allocation per layer based on RTCP XR target bitrate.
Bug: webrtc:10312
Change-Id: Ic0221e71d27d1fdc35c50a93e7e2303953c4fbf5
Reviewed-on: https://webrtc-review.googlesource.com/c/123222
Reviewed-by: Mirta Dvornicic <mirtad@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26717}
diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc
index 1b52c30..a4126bc 100644
--- a/rtc_tools/event_log_visualizer/analyzer.cc
+++ b/rtc_tools/event_log_visualizer/analyzer.cc
@@ -1115,6 +1115,46 @@
plot->SetTitle(GetDirectionAsString(direction) + " bitrate per stream");
}
+// Plot the bitrate allocation for each temporal and spatial layer.
+// Computed from RTCP XR target bitrate block, so the graph is only populated if
+// those are sent.
+void EventLogAnalyzer::CreateBitrateAllocationGraph(PacketDirection direction,
+ Plot* plot) {
+ std::map<LayerDescription, TimeSeries> time_series;
+ const auto& xr_list = parsed_log_.extended_reports(direction);
+ for (const auto& rtcp : xr_list) {
+ const absl::optional<rtcp::TargetBitrate>& target_bitrate =
+ rtcp.xr.target_bitrate();
+ if (!target_bitrate.has_value())
+ continue;
+ for (const auto& bitrate_item : target_bitrate->GetTargetBitrates()) {
+ LayerDescription layer(rtcp.xr.sender_ssrc(), bitrate_item.spatial_layer,
+ bitrate_item.temporal_layer);
+ auto time_series_it = time_series.find(layer);
+ if (time_series_it == time_series.end()) {
+ std::string layer_name = GetLayerName(layer);
+ bool inserted;
+ std::tie(time_series_it, inserted) = time_series.insert(
+ std::make_pair(layer, TimeSeries(layer_name, LineStyle::kStep)));
+ RTC_DCHECK(inserted);
+ }
+ float x = config_.GetCallTimeSec(rtcp.log_time_us());
+ float y = bitrate_item.target_bitrate_kbps;
+ time_series_it->second.points.emplace_back(x, y);
+ }
+ }
+ for (auto& layer : time_series) {
+ plot->AppendTimeSeries(std::move(layer.second));
+ }
+ plot->SetXAxis(config_.CallBeginTimeSec(), config_.CallEndTimeSec(),
+ "Time (s)", kLeftMargin, kRightMargin);
+ plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
+ if (direction == kIncomingPacket)
+ plot->SetTitle("Target bitrate per incoming layer");
+ else
+ plot->SetTitle("Target bitrate per outgoing layer");
+}
+
void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
using RtpPacketType = LoggedRtpPacketOutgoing;
using TransportFeedbackType = LoggedRtcpPacketTransportFeedback;
diff --git a/rtc_tools/event_log_visualizer/analyzer.h b/rtc_tools/event_log_visualizer/analyzer.h
index f8dd3de..e0ef0c3 100644
--- a/rtc_tools/event_log_visualizer/analyzer.h
+++ b/rtc_tools/event_log_visualizer/analyzer.h
@@ -81,6 +81,7 @@
bool show_alr_state = false);
void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot);
+ void CreateBitrateAllocationGraph(PacketDirection direction, Plot* plot);
void CreateSendSideBweSimulationGraph(Plot* plot);
void CreateReceiveSideBweSimulationGraph(Plot* plot);
@@ -132,6 +133,25 @@
void PrintNotifications(FILE* file);
private:
+ struct LayerDescription {
+ LayerDescription(uint32_t ssrc,
+ uint8_t spatial_layer,
+ uint8_t temporal_layer)
+ : ssrc(ssrc),
+ spatial_layer(spatial_layer),
+ temporal_layer(temporal_layer) {}
+ bool operator<(const LayerDescription& other) const {
+ if (ssrc != other.ssrc)
+ return ssrc < other.ssrc;
+ if (spatial_layer != other.spatial_layer)
+ return spatial_layer < other.spatial_layer;
+ return temporal_layer < other.temporal_layer;
+ }
+ uint32_t ssrc;
+ uint8_t spatial_layer;
+ uint8_t temporal_layer;
+ };
+
bool IsRtxSsrc(PacketDirection direction, uint32_t ssrc) const {
if (direction == kIncomingPacket) {
return parsed_log_.incoming_rtx_ssrcs().find(ssrc) !=
@@ -200,6 +220,14 @@
return name.str();
}
+ std::string GetLayerName(LayerDescription layer) const {
+ char buffer[100];
+ rtc::SimpleStringBuilder name(buffer);
+ name << "SSRC " << layer.ssrc << " sl " << layer.spatial_layer << ", tl "
+ << layer.temporal_layer;
+ return name.str();
+ }
+
void Alert_RtpLogTimeGap(PacketDirection direction,
float time_seconds,
int64_t duration) {
diff --git a/rtc_tools/event_log_visualizer/main.cc b/rtc_tools/event_log_visualizer/main.cc
index c08b71b..11824da 100644
--- a/rtc_tools/event_log_visualizer/main.cc
+++ b/rtc_tools/event_log_visualizer/main.cc
@@ -94,6 +94,14 @@
WEBRTC_DEFINE_bool(plot_outgoing_stream_bitrate,
true,
"Plot the bitrate used by each outgoing stream.");
+WEBRTC_DEFINE_bool(plot_incoming_layer_bitrate_allocation,
+ false,
+ "Plot the target bitrate for each incoming layer. Requires "
+ "incoming RTCP XR with target bitrate to be populated.");
+WEBRTC_DEFINE_bool(plot_outgoing_layer_bitrate_allocation,
+ false,
+ "Plot the target bitrate for each outgoing layer. Requires "
+ "outgoing RTCP XR with target bitrate to be populated.");
WEBRTC_DEFINE_bool(
plot_simulated_receiveside_bwe,
false,
@@ -343,6 +351,14 @@
analyzer.CreateStreamBitrateGraph(webrtc::kOutgoingPacket,
collection->AppendNewPlot());
}
+ if (FLAG_plot_incoming_layer_bitrate_allocation) {
+ analyzer.CreateBitrateAllocationGraph(webrtc::kIncomingPacket,
+ collection->AppendNewPlot());
+ }
+ if (FLAG_plot_outgoing_layer_bitrate_allocation) {
+ analyzer.CreateBitrateAllocationGraph(webrtc::kOutgoingPacket,
+ collection->AppendNewPlot());
+ }
if (FLAG_plot_simulated_receiveside_bwe) {
analyzer.CreateReceiveSideBweSimulationGraph(collection->AppendNewPlot());
}
@@ -522,6 +538,8 @@
FLAG_plot_outgoing_bitrate = setting;
FLAG_plot_incoming_stream_bitrate = setting;
FLAG_plot_outgoing_stream_bitrate = setting;
+ FLAG_plot_incoming_layer_bitrate_allocation = setting;
+ FLAG_plot_outgoing_layer_bitrate_allocation = setting;
FLAG_plot_simulated_receiveside_bwe = setting;
FLAG_plot_simulated_sendside_bwe = setting;
FLAG_plot_network_delay_feedback = setting;