blob: 1a5d4b415ed17ac2b450e8bd98a4a656c4ae0a08 [file] [log] [blame]
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +01001/*
2 * Copyright 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
Sebastian Jansson7150d8c2019-04-09 14:18:09 +020010#include "test/scenario/video_frame_matcher.h"
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010011
12#include <utility>
13
14#include "common_video/libyuv/include/webrtc_libyuv.h"
15#include "rtc_base/checks.h"
16#include "rtc_base/event.h"
17
18namespace webrtc {
19namespace test {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020020namespace {
21constexpr int kThumbWidth = 96;
22constexpr int kThumbHeight = 96;
23} // namespace
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010024
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020025VideoFrameMatcher::VideoFrameMatcher(
26 std::vector<std::function<void(const VideoFramePair&)> >
27 frame_pair_handlers)
28 : frame_pair_handlers_(frame_pair_handlers), task_queue_("VideoAnalyzer") {}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010029
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020030VideoFrameMatcher::~VideoFrameMatcher() {
Sebastian Jansson7237c152019-04-08 16:47:49 +020031 task_queue_.SendTask([this] { Finalize(); });
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010032}
33
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020034void VideoFrameMatcher::RegisterLayer(int layer_id) {
35 task_queue_.PostTask([this, layer_id] { layers_[layer_id] = VideoLayer(); });
36}
37
38void VideoFrameMatcher::OnCapturedFrame(const VideoFrame& frame,
39 Timestamp at_time) {
40 CapturedFrame captured;
41 captured.id = next_capture_id_++;
42 captured.capture_time = at_time;
43 captured.frame = frame.video_frame_buffer();
44 captured.thumb = ScaleVideoFrameBuffer(*frame.video_frame_buffer()->ToI420(),
45 kThumbWidth, kThumbHeight),
46 task_queue_.PostTask([this, captured]() {
47 for (auto& layer : layers_) {
48 CapturedFrame copy = captured;
Sebastian Janssond0aec912019-04-17 13:22:27 +020049 if (layer.second.last_decode &&
50 layer.second.last_decode->frame->width() <= captured.frame->width()) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020051 copy.best_score = I420SSE(*captured.thumb->GetI420(),
52 *layer.second.last_decode->thumb->GetI420());
53 copy.best_decode = layer.second.last_decode;
54 }
55 layer.second.captured_frames.push_back(std::move(copy));
56 }
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010057 });
58}
59
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020060void VideoFrameMatcher::OnDecodedFrame(const VideoFrame& frame,
61 Timestamp render_time,
62 int layer_id) {
63 rtc::scoped_refptr<DecodedFrame> decoded(new DecodedFrame{});
64 decoded->render_time = render_time;
65 decoded->frame = frame.video_frame_buffer();
66 decoded->thumb = ScaleVideoFrameBuffer(*frame.video_frame_buffer()->ToI420(),
67 kThumbWidth, kThumbHeight);
68 decoded->render_time = render_time;
69
70 task_queue_.PostTask([this, decoded, layer_id] {
71 auto& layer = layers_[layer_id];
72 decoded->id = layer.next_decoded_id++;
73 layer.last_decode = decoded;
74 for (auto& captured : layer.captured_frames) {
Sebastian Janssond0aec912019-04-17 13:22:27 +020075 // We can't match with a smaller capture.
76 if (captured.frame->width() < decoded->frame->width()) {
77 captured.matched = true;
78 continue;
79 }
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020080 double score =
81 I420SSE(*captured.thumb->GetI420(), *decoded->thumb->GetI420());
82 if (score < captured.best_score) {
83 captured.best_score = score;
84 captured.best_decode = decoded;
85 captured.matched = false;
86 } else {
87 captured.matched = true;
88 }
89 }
90 while (!layer.captured_frames.empty() &&
91 layer.captured_frames.front().matched) {
Sebastian Jansson7150d8c2019-04-09 14:18:09 +020092 HandleMatch(std::move(layer.captured_frames.front()), layer_id);
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020093 layer.captured_frames.pop_front();
94 }
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010095 });
96}
97
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020098bool VideoFrameMatcher::Active() const {
99 return !frame_pair_handlers_.empty();
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100100}
101
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200102void VideoFrameMatcher::HandleMatch(VideoFrameMatcher::CapturedFrame captured,
103 int layer_id) {
104 VideoFramePair frame_pair;
105 frame_pair.layer_id = layer_id;
106 frame_pair.captured = captured.frame;
107 frame_pair.capture_id = captured.id;
Sebastian Janssondab21c62019-05-13 11:48:40 +0200108 frame_pair.capture_time = captured.capture_time;
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200109 if (captured.best_decode) {
110 frame_pair.decode_id = captured.best_decode->id;
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200111 frame_pair.decoded = captured.best_decode->frame;
112 frame_pair.render_time = captured.best_decode->render_time;
113 frame_pair.repeated = captured.best_decode->repeat_count++;
114 }
115 for (auto& handler : frame_pair_handlers_)
116 handler(frame_pair);
117}
118
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200119void VideoFrameMatcher::Finalize() {
120 for (auto& layer : layers_) {
121 while (!layer.second.captured_frames.empty()) {
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200122 HandleMatch(std::move(layer.second.captured_frames.front()), layer.first);
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200123 layer.second.captured_frames.pop_front();
124 }
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100125 }
126}
127
128ForwardingCapturedFrameTap::ForwardingCapturedFrameTap(
Sebastian Janssonaa01f272019-01-30 11:28:59 +0100129 Clock* clock,
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200130 VideoFrameMatcher* matcher,
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100131 rtc::VideoSourceInterface<VideoFrame>* source)
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200132 : clock_(clock), matcher_(matcher), source_(source) {}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100133
134ForwardingCapturedFrameTap::~ForwardingCapturedFrameTap() {}
135
136void ForwardingCapturedFrameTap::OnFrame(const VideoFrame& frame) {
137 RTC_CHECK(sink_);
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200138 matcher_->OnCapturedFrame(frame, Timestamp::ms(clock_->TimeInMilliseconds()));
139 sink_->OnFrame(frame);
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100140}
141void ForwardingCapturedFrameTap::OnDiscardedFrame() {
142 RTC_CHECK(sink_);
143 discarded_count_++;
144 sink_->OnDiscardedFrame();
145}
146
147void ForwardingCapturedFrameTap::AddOrUpdateSink(
148 VideoSinkInterface<VideoFrame>* sink,
149 const rtc::VideoSinkWants& wants) {
150 sink_ = sink;
151 source_->AddOrUpdateSink(this, wants);
152}
153void ForwardingCapturedFrameTap::RemoveSink(
154 VideoSinkInterface<VideoFrame>* sink) {
155 source_->RemoveSink(this);
156 sink_ = nullptr;
157}
158
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200159DecodedFrameTap::DecodedFrameTap(VideoFrameMatcher* matcher, int layer_id)
160 : matcher_(matcher), layer_id_(layer_id) {
161 matcher_->RegisterLayer(layer_id_);
162}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100163
164void DecodedFrameTap::OnFrame(const VideoFrame& frame) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200165 matcher_->OnDecodedFrame(frame, Timestamp::ms(frame.render_time_ms()),
166 layer_id_);
167}
168
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100169} // namespace test
170} // namespace webrtc