Skip to content

Commit

Permalink
Implement DelayVariationCalculator for events analysis.
Browse files Browse the repository at this point in the history
This CL implements {,Logging}DelayVariationCalculator, whose purpose is to calculate simple inter-arrival metrics for a sequence of RTP frames. Uses could include RtcEventLog analysis and ad hoc testing.

Want lgtm: asapersson

Bug: webrtc:15213
Change-Id: I3f9d13a2c4fa66b6f1229c1b6fcd66a6911070de
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/306741
Commit-Queue: Rasmus Brandt <[email protected]>
Reviewed-by: Åsa Persson <[email protected]>
Reviewed-by: Jeremy Leconte <[email protected]>
Cr-Commit-Position: refs/heads/main@{#40247}
  • Loading branch information
rasmusbrandt authored and WebRTC LUCI CQ committed Jun 8, 2023
1 parent f99e0f4 commit cde5354
Show file tree
Hide file tree
Showing 11 changed files with 594 additions and 0 deletions.
1 change: 1 addition & 0 deletions api/video/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ rtc_source_set("recordable_encoded_frame") {
rtc_source_set("video_frame_type") {
visibility = [ "*" ]
sources = [ "video_frame_type.h" ]
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
}

rtc_source_set("render_resolution") {
Expand Down
16 changes: 16 additions & 0 deletions api/video/video_frame_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#ifndef API_VIDEO_VIDEO_FRAME_TYPE_H_
#define API_VIDEO_VIDEO_FRAME_TYPE_H_

#include "absl/strings/string_view.h"

namespace webrtc {

enum class VideoFrameType {
Expand All @@ -21,6 +23,20 @@ enum class VideoFrameType {
kVideoFrameDelta = 4,
};

inline constexpr absl::string_view VideoFrameTypeToString(
VideoFrameType frame_type) {
if (frame_type == VideoFrameType::kEmptyFrame) {
return "empty";
}
if (frame_type == VideoFrameType::kVideoFrameKey) {
return "key";
}
if (frame_type == VideoFrameType::kVideoFrameDelta) {
return "delta";
}
return "";
}

} // namespace webrtc

#endif // API_VIDEO_VIDEO_FRAME_TYPE_H_
1 change: 1 addition & 0 deletions test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ if (rtc_include_tests) {
"../rtc_base:rtc_task_queue",
"../rtc_base/synchronization:mutex",
"../rtc_base/system:file_wrapper",
"jitter:jitter_unittests",
"pc/e2e:e2e_unittests",
"pc/e2e/analyzer/video:video_analyzer_unittests",
"pc/e2e/analyzer/video/dvqa:dvqa_unittests",
Expand Down
64 changes: 64 additions & 0 deletions test/jitter/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright (c) 2023 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.

import("../../webrtc.gni")

rtc_library("delay_variation_calculator") {
visibility = [ "*" ]
sources = [
"delay_variation_calculator.cc",
"delay_variation_calculator.h",
]
deps = [
"../../api/numerics",
"../../api/test/metrics:metrics_logger",
"../../api/units:data_size",
"../../api/units:frequency",
"../../api/units:time_delta",
"../../api/units:timestamp",
"../../api/video:video_frame_type",
"../../rtc_base:logging",
"../../rtc_base:rtc_numerics",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}

rtc_library("logging_delay_variation_calculator") {
visibility = [ "*" ]
sources = [
"logging_delay_variation_calculator.cc",
"logging_delay_variation_calculator.h",
]
deps = [
":delay_variation_calculator",
"../../api/test/metrics:global_metrics_logger_and_exporter",
"../../api/units:data_size",
"../../api/video:video_frame_type",
"../../rtc_base:logging",
]
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
}

if (rtc_include_tests) {
rtc_library("jitter_unittests") {
testonly = true
sources = [
"delay_variation_calculator_unittest.cc",
"logging_delay_variation_calculator_unittest.cc",
]
deps = [
":delay_variation_calculator",
":logging_delay_variation_calculator",
"../../api/numerics",
"../../api/test/metrics:metrics_logger",
"../../api/units:timestamp",
"../../system_wrappers",
"../../test:test_support",
]
}
}
1 change: 1 addition & 0 deletions test/jitter/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[email protected]
130 changes: 130 additions & 0 deletions test/jitter/delay_variation_calculator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2023 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/jitter/delay_variation_calculator.h"

#include <string>

#include "absl/types/optional.h"
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/logging.h"

namespace webrtc {
namespace test {

namespace {
constexpr Frequency k90000Hz = Frequency::Hertz(90000);
} // namespace

void DelayVariationCalculator::Insert(
uint32_t rtp_timestamp,
Timestamp arrival_time,
DataSize size,
absl::optional<int> spatial_layer,
absl::optional<int> temporal_layer,
absl::optional<VideoFrameType> frame_type) {
Frame frame{.rtp_timestamp = rtp_timestamp,
.unwrapped_rtp_timestamp = unwrapper_.Unwrap(rtp_timestamp),
.arrival_time = arrival_time,
.size = size,
.spatial_layer = spatial_layer,
.temporal_layer = temporal_layer,
.frame_type = frame_type};
// Using RTP timestamp as the time series sample identifier allows for
// cross-correlating time series logged by different objects at different
// arrival timestamps.
Timestamp sample_time =
Timestamp::Millis((frame.unwrapped_rtp_timestamp / k90000Hz).ms());
MetadataT sample_metadata = BuildMetadata(frame);
if (!prev_frame_) {
InsertFirstFrame(frame, sample_time, sample_metadata);
} else {
InsertFrame(frame, sample_time, sample_metadata);
}
prev_frame_ = frame;
}

void DelayVariationCalculator::InsertFirstFrame(const Frame& frame,
Timestamp sample_time,
MetadataT sample_metadata) {
const auto s = [=](double sample_value) {
return SamplesStatsCounter::StatsSample{.value = sample_value,
.time = sample_time,
.metadata = sample_metadata};
};
time_series_.rtp_timestamps.AddSample(
s(static_cast<double>(frame.rtp_timestamp)));
time_series_.arrival_times_ms.AddSample(s(frame.arrival_time.ms<double>()));
time_series_.sizes_bytes.AddSample(s(frame.size.bytes<double>()));
time_series_.inter_departure_times_ms.AddSample(s(0.0));
time_series_.inter_arrival_times_ms.AddSample(s(0.0));
time_series_.inter_delay_variations_ms.AddSample(s(0.0));
time_series_.inter_size_variations_bytes.AddSample(s(0.0));
}

void DelayVariationCalculator::InsertFrame(const Frame& frame,
Timestamp sample_time,
MetadataT sample_metadata) {
int64_t inter_rtp_time =
frame.unwrapped_rtp_timestamp - prev_frame_->unwrapped_rtp_timestamp;
TimeDelta inter_departure_time = inter_rtp_time / k90000Hz;
TimeDelta inter_arrival_time = frame.arrival_time - prev_frame_->arrival_time;
TimeDelta inter_delay_variation = inter_arrival_time - inter_departure_time;
double inter_size_variation_bytes =
frame.size.bytes<double>() - prev_frame_->size.bytes<double>();
const auto s = [=](double sample_value) {
return SamplesStatsCounter::StatsSample{.value = sample_value,
.time = sample_time,
.metadata = sample_metadata};
};
const auto ms = [](const TimeDelta& td) { return td.ms<double>(); };
time_series_.rtp_timestamps.AddSample(
s(static_cast<double>(frame.rtp_timestamp)));
time_series_.arrival_times_ms.AddSample(s(frame.arrival_time.ms<double>()));
time_series_.sizes_bytes.AddSample(s(frame.size.bytes<double>()));
time_series_.inter_departure_times_ms.AddSample(s(ms(inter_departure_time)));
time_series_.inter_arrival_times_ms.AddSample(s(ms(inter_arrival_time)));
time_series_.inter_delay_variations_ms.AddSample(
s(ms(inter_delay_variation)));
time_series_.inter_size_variations_bytes.AddSample(
s(inter_size_variation_bytes));
}

DelayVariationCalculator::MetadataT DelayVariationCalculator::BuildMetadata(
const Frame& frame) {
MetadataT metadata;
if (prev_frame_) {
if (prev_frame_->spatial_layer) {
metadata["sl_prev"] = std::to_string(*prev_frame_->spatial_layer);
}
if (prev_frame_->temporal_layer) {
metadata["tl_prev"] = std::to_string(*prev_frame_->temporal_layer);
}
if (prev_frame_->frame_type) {
metadata["frame_type_prev"] =
VideoFrameTypeToString(*prev_frame_->frame_type);
}
}
if (frame.spatial_layer) {
metadata["sl"] = std::to_string(*frame.spatial_layer);
}
if (frame.temporal_layer) {
metadata["tl"] = std::to_string(*frame.temporal_layer);
}
if (frame.frame_type) {
metadata["frame_type"] = VideoFrameTypeToString(*frame.frame_type);
}
return metadata;
}

} // namespace test
} // namespace webrtc
94 changes: 94 additions & 0 deletions test/jitter/delay_variation_calculator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2023 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_JITTER_DELAY_VARIATION_CALCULATOR_H_
#define TEST_JITTER_DELAY_VARIATION_CALCULATOR_H_

#include <stdint.h>

#include <map>
#include <string>

#include "absl/types/optional.h"
#include "api/numerics/samples_stats_counter.h"
#include "api/test/metrics/metrics_logger.h"
#include "api/units/data_size.h"
#include "api/units/timestamp.h"
#include "api/video/video_frame_type.h"
#include "rtc_base/numerics/sequence_number_unwrapper.h"

namespace webrtc {
namespace test {

// Helper class for calculating different delay variation statistics for "RTP
// frame arrival events". One use case is gathering statistics from
// RtcEventLogs. Another use case is online logging of data in test calls.
class DelayVariationCalculator {
public:
struct TimeSeries {
// Time series of RTP timestamps `t(n)` for each frame `n`.
SamplesStatsCounter rtp_timestamps;
// Time series of local arrival timestamps `r(n)` for each frame.
SamplesStatsCounter arrival_times_ms;
// Time series of sizes `s(n)` for each frame.
SamplesStatsCounter sizes_bytes;
// Time series of `d_t(n) = t(n) - t(n-1)` for each frame.
SamplesStatsCounter inter_departure_times_ms;
// Time series of `d_r(n) = r(n) - r(n-1)` for each frame.
SamplesStatsCounter inter_arrival_times_ms;
// Time series of `d_r(n) - d_t(n) = (r(n) - r(n-1)) - (t(n) - t(n-1))`
// for each frame.
SamplesStatsCounter inter_delay_variations_ms;
// Time series of `s(n) - s(n-1)`, for each frame.
SamplesStatsCounter inter_size_variations_bytes;
};

DelayVariationCalculator() = default;
~DelayVariationCalculator() = default;

void Insert(uint32_t rtp_timestamp,
Timestamp arrival_time,
DataSize size,
absl::optional<int> spatial_layer = absl::nullopt,
absl::optional<int> temporal_layer = absl::nullopt,
absl::optional<VideoFrameType> frame_type = absl::nullopt);

const TimeSeries& time_series() const { return time_series_; }

private:
struct Frame {
uint32_t rtp_timestamp;
int64_t unwrapped_rtp_timestamp;
Timestamp arrival_time;
DataSize size;
absl::optional<int> spatial_layer;
absl::optional<int> temporal_layer;
absl::optional<VideoFrameType> frame_type;
};
using MetadataT = std::map<std::string, std::string>;

void InsertFirstFrame(const Frame& frame,
Timestamp sample_time,
MetadataT sample_metadata);
void InsertFrame(const Frame& frame,
Timestamp sample_time,
MetadataT sample_metadata);

MetadataT BuildMetadata(const Frame& frame);

RtpTimestampUnwrapper unwrapper_;
absl::optional<Frame> prev_frame_ = absl::nullopt;
TimeSeries time_series_;
};

} // namespace test
} // namespace webrtc

#endif // TEST_JITTER_DELAY_VARIATION_CALCULATOR_H_
Loading

0 comments on commit cde5354

Please sign in to comment.