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