summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/test/scenario/video_frame_matcher.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/test/scenario/video_frame_matcher.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/test/scenario/video_frame_matcher.cc')
-rw-r--r--third_party/libwebrtc/test/scenario/video_frame_matcher.cc188
1 files changed, 188 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/scenario/video_frame_matcher.cc b/third_party/libwebrtc/test/scenario/video_frame_matcher.cc
new file mode 100644
index 0000000000..dc8cd59756
--- /dev/null
+++ b/third_party/libwebrtc/test/scenario/video_frame_matcher.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2018 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/scenario/video_frame_matcher.h"
+
+#include <utility>
+
+#include "common_video/libyuv/include/webrtc_libyuv.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/event.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+constexpr int kThumbWidth = 96;
+constexpr int kThumbHeight = 96;
+} // namespace
+
+VideoFrameMatcher::VideoFrameMatcher(
+ std::vector<std::function<void(const VideoFramePair&)> >
+ frame_pair_handlers)
+ : frame_pair_handlers_(std::move(frame_pair_handlers)),
+ task_queue_("VideoAnalyzer") {}
+
+VideoFrameMatcher::~VideoFrameMatcher() {
+ task_queue_.SendTask([this] { Finalize(); });
+}
+
+void VideoFrameMatcher::RegisterLayer(int layer_id) {
+ task_queue_.PostTask([this, layer_id] { layers_[layer_id] = VideoLayer(); });
+}
+
+void VideoFrameMatcher::OnCapturedFrame(const VideoFrame& frame,
+ Timestamp at_time) {
+ CapturedFrame captured;
+ captured.id = next_capture_id_++;
+ captured.capture_time = at_time;
+ captured.frame = frame.video_frame_buffer();
+ captured.thumb = ScaleVideoFrameBuffer(*frame.video_frame_buffer()->ToI420(),
+ kThumbWidth, kThumbHeight),
+ task_queue_.PostTask([this, captured]() {
+ for (auto& layer : layers_) {
+ CapturedFrame copy = captured;
+ if (layer.second.last_decode &&
+ layer.second.last_decode->frame->width() <= captured.frame->width()) {
+ copy.best_score = I420SSE(*captured.thumb->GetI420(),
+ *layer.second.last_decode->thumb->GetI420());
+ copy.best_decode = layer.second.last_decode;
+ }
+ layer.second.captured_frames.push_back(std::move(copy));
+ }
+ });
+}
+
+void VideoFrameMatcher::OnDecodedFrame(const VideoFrame& frame,
+ int layer_id,
+ Timestamp render_time,
+ Timestamp at_time) {
+ rtc::scoped_refptr<DecodedFrame> decoded(new DecodedFrame{});
+ decoded->decoded_time = at_time;
+ decoded->render_time = render_time;
+ decoded->frame = frame.video_frame_buffer();
+ decoded->thumb = ScaleVideoFrameBuffer(*frame.video_frame_buffer()->ToI420(),
+ kThumbWidth, kThumbHeight);
+
+ task_queue_.PostTask([this, decoded, layer_id] {
+ auto& layer = layers_[layer_id];
+ decoded->id = layer.next_decoded_id++;
+ layer.last_decode = decoded;
+ for (auto& captured : layer.captured_frames) {
+ // We can't match with a smaller capture.
+ if (captured.frame->width() < decoded->frame->width()) {
+ captured.matched = true;
+ continue;
+ }
+ double score =
+ I420SSE(*captured.thumb->GetI420(), *decoded->thumb->GetI420());
+ if (score < captured.best_score) {
+ captured.best_score = score;
+ captured.best_decode = decoded;
+ captured.matched = false;
+ } else {
+ captured.matched = true;
+ }
+ }
+ while (!layer.captured_frames.empty() &&
+ layer.captured_frames.front().matched) {
+ HandleMatch(std::move(layer.captured_frames.front()), layer_id);
+ layer.captured_frames.pop_front();
+ }
+ });
+}
+
+bool VideoFrameMatcher::Active() const {
+ return !frame_pair_handlers_.empty();
+}
+
+void VideoFrameMatcher::HandleMatch(VideoFrameMatcher::CapturedFrame captured,
+ int layer_id) {
+ VideoFramePair frame_pair;
+ frame_pair.layer_id = layer_id;
+ frame_pair.captured = captured.frame;
+ frame_pair.capture_id = captured.id;
+ frame_pair.capture_time = captured.capture_time;
+ if (captured.best_decode) {
+ frame_pair.decode_id = captured.best_decode->id;
+ frame_pair.decoded = captured.best_decode->frame;
+ frame_pair.decoded_time = captured.best_decode->decoded_time;
+ // We can't render frames before they have been decoded.
+ frame_pair.render_time = std::max(captured.best_decode->render_time,
+ captured.best_decode->decoded_time);
+ frame_pair.repeated = captured.best_decode->repeat_count++;
+ }
+ for (auto& handler : frame_pair_handlers_)
+ handler(frame_pair);
+}
+
+void VideoFrameMatcher::Finalize() {
+ for (auto& layer : layers_) {
+ while (!layer.second.captured_frames.empty()) {
+ HandleMatch(std::move(layer.second.captured_frames.front()), layer.first);
+ layer.second.captured_frames.pop_front();
+ }
+ }
+}
+
+CapturedFrameTap::CapturedFrameTap(Clock* clock, VideoFrameMatcher* matcher)
+ : clock_(clock), matcher_(matcher) {}
+
+void CapturedFrameTap::OnFrame(const VideoFrame& frame) {
+ matcher_->OnCapturedFrame(frame, clock_->CurrentTime());
+}
+void CapturedFrameTap::OnDiscardedFrame() {
+ discarded_count_++;
+}
+
+ForwardingCapturedFrameTap::ForwardingCapturedFrameTap(
+ Clock* clock,
+ VideoFrameMatcher* matcher,
+ rtc::VideoSourceInterface<VideoFrame>* source)
+ : clock_(clock), matcher_(matcher), source_(source) {}
+
+void ForwardingCapturedFrameTap::OnFrame(const VideoFrame& frame) {
+ RTC_CHECK(sink_);
+ matcher_->OnCapturedFrame(frame, clock_->CurrentTime());
+ sink_->OnFrame(frame);
+}
+void ForwardingCapturedFrameTap::OnDiscardedFrame() {
+ RTC_CHECK(sink_);
+ discarded_count_++;
+ sink_->OnDiscardedFrame();
+}
+
+void ForwardingCapturedFrameTap::AddOrUpdateSink(
+ VideoSinkInterface<VideoFrame>* sink,
+ const rtc::VideoSinkWants& wants) {
+ if (!sink_)
+ sink_ = sink;
+ RTC_DCHECK_EQ(sink_, sink);
+ source_->AddOrUpdateSink(this, wants);
+}
+void ForwardingCapturedFrameTap::RemoveSink(
+ VideoSinkInterface<VideoFrame>* sink) {
+ source_->RemoveSink(this);
+ sink_ = nullptr;
+}
+
+DecodedFrameTap::DecodedFrameTap(Clock* clock,
+ VideoFrameMatcher* matcher,
+ int layer_id)
+ : clock_(clock), matcher_(matcher), layer_id_(layer_id) {
+ matcher_->RegisterLayer(layer_id_);
+}
+
+void DecodedFrameTap::OnFrame(const VideoFrame& frame) {
+ matcher_->OnDecodedFrame(frame, layer_id_,
+ Timestamp::Millis(frame.render_time_ms()),
+ clock_->CurrentTime());
+}
+
+} // namespace test
+} // namespace webrtc