psnr: tweak sampling rate to make a new measurement every second more likely
When getStats is polled at exactly 1hz the current frame sampling may
occasionally yield no increase in measurements. Avoid this by doing a
simple linear extrapolation using the previous and current frame and
comparing that extrapolation to the 90k frequency.
Bug: webrtc:375021
Change-Id: I252a2b3fef87cbd728e40f83e7efe18f05aafc37
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/406143
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@meta.com>
Cr-Commit-Position: refs/heads/main@{#45458}
diff --git a/modules/video_coding/utility/frame_sampler.cc b/modules/video_coding/utility/frame_sampler.cc
index b08f891..e50c184 100644
--- a/modules/video_coding/utility/frame_sampler.cc
+++ b/modules/video_coding/utility/frame_sampler.cc
@@ -10,18 +10,35 @@
#include "modules/video_coding/utility/frame_sampler.h"
+#include <cstdint>
+
#include "api/video/video_frame.h"
#include "modules/include/module_common_types_public.h"
namespace webrtc {
constexpr int kTimestampDifference =
- 90'000 - 1; // Sample every 90khz or once per second.
+ 90'000; // Sample every 90khz or once per second.
bool FrameSampler::ShouldBeSampled(const VideoFrame& frame) {
- if (!last_rtp_timestamp_sampled_.has_value() ||
- (IsNewerTimestamp(frame.rtp_timestamp(),
- *last_rtp_timestamp_sampled_ + kTimestampDifference))) {
+ if (!last_rtp_timestamp_sampled_) {
+ // Since we can not know the frame rate from the first frame,
+ // assume 30fps for the extrapolation.
+ last_rtp_timestamp_ =
+ frame.rtp_timestamp() + kTimestampDifference / /*fps=*/30;
+ last_rtp_timestamp_sampled_ = frame.rtp_timestamp();
+ return true;
+ }
+ // Since getStats is commonly called once per second, sample if the
+ // extrapolated RTP timestamp of the next frame would be be too late for this.
+ // This is not strictly necessary but makes plotting the values once per
+ // second much easier.
+ uint32_t extrapolated_rtp_timestamp =
+ frame.rtp_timestamp() + (frame.rtp_timestamp() - *last_rtp_timestamp_);
+ last_rtp_timestamp_ = frame.rtp_timestamp();
+
+ if (IsNewerTimestamp(extrapolated_rtp_timestamp,
+ *last_rtp_timestamp_sampled_ + kTimestampDifference)) {
last_rtp_timestamp_sampled_ = frame.rtp_timestamp();
return true;
}
diff --git a/modules/video_coding/utility/frame_sampler.h b/modules/video_coding/utility/frame_sampler.h
index 403c1e7..0cbcc0a 100644
--- a/modules/video_coding/utility/frame_sampler.h
+++ b/modules/video_coding/utility/frame_sampler.h
@@ -32,6 +32,7 @@
private:
std::optional<uint32_t> last_rtp_timestamp_sampled_;
+ std::optional<uint32_t> last_rtp_timestamp_;
};
} // namespace webrtc
diff --git a/modules/video_coding/utility/frame_sampler_unittest.cc b/modules/video_coding/utility/frame_sampler_unittest.cc
index 0587338..c3e9b5d 100644
--- a/modules/video_coding/utility/frame_sampler_unittest.cc
+++ b/modules/video_coding/utility/frame_sampler_unittest.cc
@@ -28,7 +28,22 @@
EXPECT_TRUE(sampler.ShouldBeSampled(frame));
frame.set_rtp_timestamp(45'000);
EXPECT_FALSE(sampler.ShouldBeSampled(frame));
- frame.set_rtp_timestamp(90'000);
+ frame.set_rtp_timestamp(90'000 - 3'000);
+ EXPECT_TRUE(sampler.ShouldBeSampled(frame));
+}
+
+TEST(FrameSampler, SamplesBasedOnRtpTimestampDeltaLessThanOneSecond) {
+ FrameSampler sampler;
+
+ auto buffer = make_ref_counted<I420Buffer>(320, 240);
+ VideoFrame frame =
+ VideoFrame::Builder().set_video_frame_buffer(buffer).build();
+
+ frame.set_rtp_timestamp(0);
+ EXPECT_TRUE(sampler.ShouldBeSampled(frame));
+ frame.set_rtp_timestamp(3'000);
+ EXPECT_FALSE(sampler.ShouldBeSampled(frame));
+ frame.set_rtp_timestamp(90'000 - 3'000);
EXPECT_TRUE(sampler.ShouldBeSampled(frame));
}
@@ -40,7 +55,7 @@
VideoFrame::Builder().set_video_frame_buffer(buffer).build();
// RTP timestamp wraps at 2**32.
- frame.set_rtp_timestamp(0xffff'ffff - 4000);
+ frame.set_rtp_timestamp(0xffff'ffff - 3'000);
EXPECT_TRUE(sampler.ShouldBeSampled(frame));
frame.set_rtp_timestamp(41'000);
EXPECT_FALSE(sampler.ShouldBeSampled(frame));