1 /*
2 * Copyright (c) 2022 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 */
10
11 #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h"
12
13 #include <utility>
14 #include <vector>
15
16 #include "absl/types/optional.h"
17 #include "api/units/data_size.h"
18 #include "api/units/timestamp.h"
19 #include "api/video/video_frame.h"
20 #include "api/video/video_frame_type.h"
21 #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h"
22
23 namespace webrtc {
24 namespace {
25
26 template <typename T>
MaybeGetValue(const std::map<size_t,T> & map,size_t key)27 absl::optional<T> MaybeGetValue(const std::map<size_t, T>& map, size_t key) {
28 auto it = map.find(key);
29 if (it == map.end()) {
30 return absl::nullopt;
31 }
32 return it->second;
33 }
34
35 } // namespace
36
FrameInFlight(size_t stream,VideoFrame frame,Timestamp captured_time,std::set<size_t> expected_receivers)37 FrameInFlight::FrameInFlight(size_t stream,
38 VideoFrame frame,
39 Timestamp captured_time,
40 std::set<size_t> expected_receivers)
41 : stream_(stream),
42 expected_receivers_(std::move(expected_receivers)),
43 frame_(std::move(frame)),
44 captured_time_(captured_time) {}
45
RemoveFrame()46 bool FrameInFlight::RemoveFrame() {
47 if (!frame_) {
48 return false;
49 }
50 frame_ = absl::nullopt;
51 return true;
52 }
53
SetFrameId(uint16_t id)54 void FrameInFlight::SetFrameId(uint16_t id) {
55 if (frame_) {
56 frame_->set_id(id);
57 }
58 frame_id_ = id;
59 }
60
GetPeersWhichDidntReceive() const61 std::vector<size_t> FrameInFlight::GetPeersWhichDidntReceive() const {
62 std::vector<size_t> out;
63 for (size_t peer : expected_receivers_) {
64 auto it = receiver_stats_.find(peer);
65 if (it == receiver_stats_.end() ||
66 (!it->second.dropped && it->second.rendered_time.IsInfinite())) {
67 out.push_back(peer);
68 }
69 }
70 return out;
71 }
72
HaveAllPeersReceived() const73 bool FrameInFlight::HaveAllPeersReceived() const {
74 for (size_t peer : expected_receivers_) {
75 auto it = receiver_stats_.find(peer);
76 if (it == receiver_stats_.end()) {
77 return false;
78 }
79
80 if (!it->second.dropped && it->second.rendered_time.IsInfinite()) {
81 return false;
82 }
83 }
84 return true;
85 }
86
OnFrameEncoded(webrtc::Timestamp time,VideoFrameType frame_type,DataSize encoded_image_size,uint32_t target_encode_bitrate,int qp,StreamCodecInfo used_encoder)87 void FrameInFlight::OnFrameEncoded(webrtc::Timestamp time,
88 VideoFrameType frame_type,
89 DataSize encoded_image_size,
90 uint32_t target_encode_bitrate,
91 int qp,
92 StreamCodecInfo used_encoder) {
93 encoded_time_ = time;
94 frame_type_ = frame_type;
95 encoded_image_size_ = encoded_image_size;
96 target_encode_bitrate_ += target_encode_bitrate;
97 qp_values_.AddSample(SamplesStatsCounter::StatsSample{
98 .value = static_cast<double>(qp), .time = time});
99 // Update used encoder info. If simulcast/SVC is used, this method can
100 // be called multiple times, in such case we should preserve the value
101 // of `used_encoder_.switched_on_at` from the first invocation as the
102 // smallest one.
103 Timestamp encoder_switched_on_at = used_encoder_.has_value()
104 ? used_encoder_->switched_on_at
105 : Timestamp::PlusInfinity();
106 RTC_DCHECK(used_encoder.switched_on_at.IsFinite());
107 RTC_DCHECK(used_encoder.switched_from_at.IsFinite());
108 used_encoder_ = used_encoder;
109 if (encoder_switched_on_at < used_encoder_->switched_on_at) {
110 used_encoder_->switched_on_at = encoder_switched_on_at;
111 }
112 }
113
OnFramePreDecode(size_t peer,webrtc::Timestamp received_time,webrtc::Timestamp decode_start_time,VideoFrameType frame_type,DataSize encoded_image_size)114 void FrameInFlight::OnFramePreDecode(size_t peer,
115 webrtc::Timestamp received_time,
116 webrtc::Timestamp decode_start_time,
117 VideoFrameType frame_type,
118 DataSize encoded_image_size) {
119 receiver_stats_[peer].received_time = received_time;
120 receiver_stats_[peer].decode_start_time = decode_start_time;
121 receiver_stats_[peer].frame_type = frame_type;
122 receiver_stats_[peer].encoded_image_size = encoded_image_size;
123 }
124
HasReceivedTime(size_t peer) const125 bool FrameInFlight::HasReceivedTime(size_t peer) const {
126 auto it = receiver_stats_.find(peer);
127 if (it == receiver_stats_.end()) {
128 return false;
129 }
130 return it->second.received_time.IsFinite();
131 }
132
OnFrameDecoded(size_t peer,webrtc::Timestamp time,int width,int height,const StreamCodecInfo & used_decoder)133 void FrameInFlight::OnFrameDecoded(size_t peer,
134 webrtc::Timestamp time,
135 int width,
136 int height,
137 const StreamCodecInfo& used_decoder) {
138 receiver_stats_[peer].decode_end_time = time;
139 receiver_stats_[peer].used_decoder = used_decoder;
140 receiver_stats_[peer].decoded_frame_width = width;
141 receiver_stats_[peer].decoded_frame_height = height;
142 }
143
OnDecoderError(size_t peer,const StreamCodecInfo & used_decoder)144 void FrameInFlight::OnDecoderError(size_t peer,
145 const StreamCodecInfo& used_decoder) {
146 receiver_stats_[peer].decoder_failed = true;
147 receiver_stats_[peer].used_decoder = used_decoder;
148 }
149
HasDecodeEndTime(size_t peer) const150 bool FrameInFlight::HasDecodeEndTime(size_t peer) const {
151 auto it = receiver_stats_.find(peer);
152 if (it == receiver_stats_.end()) {
153 return false;
154 }
155 return it->second.decode_end_time.IsFinite();
156 }
157
OnFrameRendered(size_t peer,webrtc::Timestamp time)158 void FrameInFlight::OnFrameRendered(size_t peer, webrtc::Timestamp time) {
159 receiver_stats_[peer].rendered_time = time;
160 }
161
HasRenderedTime(size_t peer) const162 bool FrameInFlight::HasRenderedTime(size_t peer) const {
163 auto it = receiver_stats_.find(peer);
164 if (it == receiver_stats_.end()) {
165 return false;
166 }
167 return it->second.rendered_time.IsFinite();
168 }
169
IsDropped(size_t peer) const170 bool FrameInFlight::IsDropped(size_t peer) const {
171 auto it = receiver_stats_.find(peer);
172 if (it == receiver_stats_.end()) {
173 return false;
174 }
175 return it->second.dropped;
176 }
177
GetStatsForPeer(size_t peer) const178 FrameStats FrameInFlight::GetStatsForPeer(size_t peer) const {
179 RTC_DCHECK_NE(frame_id_, VideoFrame::kNotSetId)
180 << "Frame id isn't initialized";
181 FrameStats stats(frame_id_, captured_time_);
182 stats.pre_encode_time = pre_encode_time_;
183 stats.encoded_time = encoded_time_;
184 stats.target_encode_bitrate = target_encode_bitrate_;
185 stats.encoded_frame_type = frame_type_;
186 stats.encoded_image_size = encoded_image_size_;
187 stats.used_encoder = used_encoder_;
188 stats.qp_values = qp_values_;
189
190 absl::optional<ReceiverFrameStats> receiver_stats =
191 MaybeGetValue<ReceiverFrameStats>(receiver_stats_, peer);
192 if (receiver_stats.has_value()) {
193 stats.received_time = receiver_stats->received_time;
194 stats.decode_start_time = receiver_stats->decode_start_time;
195 stats.decode_end_time = receiver_stats->decode_end_time;
196 stats.rendered_time = receiver_stats->rendered_time;
197 stats.prev_frame_rendered_time = receiver_stats->prev_frame_rendered_time;
198 stats.decoded_frame_width = receiver_stats->decoded_frame_width;
199 stats.decoded_frame_height = receiver_stats->decoded_frame_height;
200 stats.used_decoder = receiver_stats->used_decoder;
201 stats.pre_decoded_frame_type = receiver_stats->frame_type;
202 stats.pre_decoded_image_size = receiver_stats->encoded_image_size;
203 stats.decoder_failed = receiver_stats->decoder_failed;
204 }
205 return stats;
206 }
207
208 } // namespace webrtc
209