blob: 912459183f557361d87aef7d4960d39f9d0a65c1 [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 Jansson7150d8c2019-04-09 14:18:09 +0200115 frame_pair.render_time = captured.best_decode->render_time;
116 frame_pair.repeated = captured.best_decode->repeat_count++;
117 }
118 for (auto& handler : frame_pair_handlers_)
119 handler(frame_pair);
120}
121
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200122void VideoFrameMatcher::Finalize() {
123 for (auto& layer : layers_) {
124 while (!layer.second.captured_frames.empty()) {
Sebastian Jansson7150d8c2019-04-09 14:18:09 +0200125 HandleMatch(std::move(layer.second.captured_frames.front()), layer.first);
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200126 layer.second.captured_frames.pop_front();
127 }
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100128 }
129}
130
Sebastian Janssone05ae5b2019-07-30 18:12:54 +0200131CapturedFrameTap::CapturedFrameTap(Clock* clock, VideoFrameMatcher* matcher)
132 : clock_(clock), matcher_(matcher) {}
133
134void CapturedFrameTap::OnFrame(const VideoFrame& frame) {
135 matcher_->OnCapturedFrame(frame, clock_->CurrentTime());
136}
137void CapturedFrameTap::OnDiscardedFrame() {
138 discarded_count_++;
139}
140
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100141ForwardingCapturedFrameTap::ForwardingCapturedFrameTap(
Sebastian Janssonaa01f272019-01-30 11:28:59 +0100142 Clock* clock,
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200143 VideoFrameMatcher* matcher,
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100144 rtc::VideoSourceInterface<VideoFrame>* source)
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200145 : clock_(clock), matcher_(matcher), source_(source) {}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100146
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100147void ForwardingCapturedFrameTap::OnFrame(const VideoFrame& frame) {
148 RTC_CHECK(sink_);
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200149 matcher_->OnCapturedFrame(frame, clock_->CurrentTime());
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200150 sink_->OnFrame(frame);
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100151}
152void ForwardingCapturedFrameTap::OnDiscardedFrame() {
153 RTC_CHECK(sink_);
154 discarded_count_++;
155 sink_->OnDiscardedFrame();
156}
157
158void ForwardingCapturedFrameTap::AddOrUpdateSink(
159 VideoSinkInterface<VideoFrame>* sink,
160 const rtc::VideoSinkWants& wants) {
161 sink_ = sink;
162 source_->AddOrUpdateSink(this, wants);
163}
164void ForwardingCapturedFrameTap::RemoveSink(
165 VideoSinkInterface<VideoFrame>* sink) {
166 source_->RemoveSink(this);
167 sink_ = nullptr;
168}
169
Sebastian Janssone9cac4f2019-06-24 17:10:55 +0200170DecodedFrameTap::DecodedFrameTap(Clock* clock,
171 VideoFrameMatcher* matcher,
172 int layer_id)
173 : clock_(clock), matcher_(matcher), layer_id_(layer_id) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200174 matcher_->RegisterLayer(layer_id_);
175}
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100176
177void DecodedFrameTap::OnFrame(const VideoFrame& frame) {
Sebastian Janssone9cac4f2019-06-24 17:10:55 +0200178 matcher_->OnDecodedFrame(frame, layer_id_,
179 Timestamp::ms(frame.render_time_ms()),
180 clock_->CurrentTime());
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200181}
182
Sebastian Jansson9a4f38e2018-12-19 13:14:41 +0100183} // namespace test
184} // namespace webrtc