blob: 2f95b29c0c20e869115b387a89e5ade3c8876b54 [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)
Sebastian Janssone9cac4f2019-06-24 17:10:55 +020028 : frame_pair_handlers_(std::move(frame_pair_handlers)),
29 task_queue_("VideoAnalyzer") {}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010030
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020031VideoFrameMatcher::~VideoFrameMatcher() {
Sebastian Jansson7237c152019-04-08 16:47:49 +020032 task_queue_.SendTask([this] { Finalize(); });
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010033}
34
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020035void VideoFrameMatcher::RegisterLayer(int layer_id) {
36 task_queue_.PostTask([this, layer_id] { layers_[layer_id] = VideoLayer(); });
37}
38
39void VideoFrameMatcher::OnCapturedFrame(const VideoFrame& frame,
40 Timestamp at_time) {
41 CapturedFrame captured;
42 captured.id = next_capture_id_++;
43 captured.capture_time = at_time;
44 captured.frame = frame.video_frame_buffer();
45 captured.thumb = ScaleVideoFrameBuffer(*frame.video_frame_buffer()->ToI420(),
46 kThumbWidth, kThumbHeight),
47 task_queue_.PostTask([this, captured]() {
48 for (auto& layer : layers_) {
49 CapturedFrame copy = captured;
Sebastian Janssond0aec912019-04-17 13:22:27 +020050 if (layer.second.last_decode &&
51 layer.second.last_decode->frame->width() <= captured.frame->width()) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020052 copy.best_score = I420SSE(*captured.thumb->GetI420(),
53 *layer.second.last_decode->thumb->GetI420());
54 copy.best_decode = layer.second.last_decode;
55 }
56 layer.second.captured_frames.push_back(std::move(copy));
57 }
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010058 });
59}
60
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020061void VideoFrameMatcher::OnDecodedFrame(const VideoFrame& frame,
Sebastian Janssone9cac4f2019-06-24 17:10:55 +020062 int layer_id,
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020063 Timestamp render_time,
Sebastian Janssone9cac4f2019-06-24 17:10:55 +020064 Timestamp at_time) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020065 rtc::scoped_refptr<DecodedFrame> decoded(new DecodedFrame{});
Sebastian Janssone9cac4f2019-06-24 17:10:55 +020066 decoded->decoded_time = at_time;
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020067 decoded->render_time = render_time;
68 decoded->frame = frame.video_frame_buffer();
69 decoded->thumb = ScaleVideoFrameBuffer(*frame.video_frame_buffer()->ToI420(),
70 kThumbWidth, kThumbHeight);
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020071
72 task_queue_.PostTask([this, decoded, layer_id] {
73 auto& layer = layers_[layer_id];
74 decoded->id = layer.next_decoded_id++;
75 layer.last_decode = decoded;
76 for (auto& captured : layer.captured_frames) {
Sebastian Janssond0aec912019-04-17 13:22:27 +020077 // We can't match with a smaller capture.
78 if (captured.frame->width() < decoded->frame->width()) {
79 captured.matched = true;
80 continue;
81 }
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020082 double score =
83 I420SSE(*captured.thumb->GetI420(), *decoded->thumb->GetI420());
84 if (score < captured.best_score) {
85 captured.best_score = score;
86 captured.best_decode = decoded;
87 captured.matched = false;
88 } else {
89 captured.matched = true;
90 }
91 }
92 while (!layer.captured_frames.empty() &&
93 layer.captured_frames.front().matched) {
Sebastian Jansson7150d8c2019-04-09 14:18:09 +020094 HandleMatch(std::move(layer.captured_frames.front()), layer_id);
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +020095 layer.captured_frames.pop_front();
96 }
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +010097 });
98}
99
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200100bool VideoFrameMatcher::Active() const {
101 return !frame_pair_handlers_.empty();
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100102}
103
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200104void VideoFrameMatcher::HandleMatch(VideoFrameMatcher::CapturedFrame captured,
105 int layer_id) {
106 VideoFramePair frame_pair;
107 frame_pair.layer_id = layer_id;
108 frame_pair.captured = captured.frame;
109 frame_pair.capture_id = captured.id;
Sebastian Janssondab21c62019-05-13 11:48:40 +0200110 frame_pair.capture_time = captured.capture_time;
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200111 if (captured.best_decode) {
112 frame_pair.decode_id = captured.best_decode->id;
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200113 frame_pair.decoded = captured.best_decode->frame;
Sebastian Janssone9cac4f2019-06-24 17:10:55 +0200114 frame_pair.decoded_time = captured.best_decode->decoded_time;
Sebastian Janssonf77b9392019-10-08 12:09:57 +0200115 // We can't render frames before they have been decoded.
116 frame_pair.render_time = std::max(captured.best_decode->render_time,
117 captured.best_decode->decoded_time);
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200118 frame_pair.repeated = captured.best_decode->repeat_count++;
119 }
120 for (auto& handler : frame_pair_handlers_)
121 handler(frame_pair);
122}
123
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200124void VideoFrameMatcher::Finalize() {
125 for (auto& layer : layers_) {
126 while (!layer.second.captured_frames.empty()) {
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200127 HandleMatch(std::move(layer.second.captured_frames.front()), layer.first);
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200128 layer.second.captured_frames.pop_front();
129 }
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100130 }
131}
132
Sebastian Janssone05ae5b2019-07-30 18:12:54 +0200133CapturedFrameTap::CapturedFrameTap(Clock* clock, VideoFrameMatcher* matcher)
134 : clock_(clock), matcher_(matcher) {}
135
136void CapturedFrameTap::OnFrame(const VideoFrame& frame) {
137 matcher_->OnCapturedFrame(frame, clock_->CurrentTime());
138}
139void CapturedFrameTap::OnDiscardedFrame() {
140 discarded_count_++;
141}
142
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100143ForwardingCapturedFrameTap::ForwardingCapturedFrameTap(
Sebastian Janssonaa01f272019-01-30 11:28:59 +0100144 Clock* clock,
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200145 VideoFrameMatcher* matcher,
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100146 rtc::VideoSourceInterface<VideoFrame>* source)
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200147 : clock_(clock), matcher_(matcher), source_(source) {}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100148
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100149void ForwardingCapturedFrameTap::OnFrame(const VideoFrame& frame) {
150 RTC_CHECK(sink_);
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200151 matcher_->OnCapturedFrame(frame, clock_->CurrentTime());
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200152 sink_->OnFrame(frame);
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100153}
154void ForwardingCapturedFrameTap::OnDiscardedFrame() {
155 RTC_CHECK(sink_);
156 discarded_count_++;
157 sink_->OnDiscardedFrame();
158}
159
160void ForwardingCapturedFrameTap::AddOrUpdateSink(
161 VideoSinkInterface<VideoFrame>* sink,
162 const rtc::VideoSinkWants& wants) {
Sebastian Jansson7fa42772019-08-28 20:49:55 +0200163 if (!sink_)
164 sink_ = sink;
165 RTC_DCHECK_EQ(sink_, sink);
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100166 source_->AddOrUpdateSink(this, wants);
167}
168void ForwardingCapturedFrameTap::RemoveSink(
169 VideoSinkInterface<VideoFrame>* sink) {
170 source_->RemoveSink(this);
171 sink_ = nullptr;
172}
173
Sebastian Janssone9cac4f2019-06-24 17:10:55 +0200174DecodedFrameTap::DecodedFrameTap(Clock* clock,
175 VideoFrameMatcher* matcher,
176 int layer_id)
177 : clock_(clock), matcher_(matcher), layer_id_(layer_id) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200178 matcher_->RegisterLayer(layer_id_);
179}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100180
181void DecodedFrameTap::OnFrame(const VideoFrame& frame) {
Sebastian Janssone9cac4f2019-06-24 17:10:55 +0200182 matcher_->OnDecodedFrame(frame, layer_id_,
183 Timestamp::ms(frame.render_time_ms()),
184 clock_->CurrentTime());
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200185}
186
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100187} // namespace test
188} // namespace webrtc