xref: /aosp_15_r20/external/webrtc/video/frame_encode_metadata_writer.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "video/frame_encode_metadata_writer.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <utility>
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker #include "common_video/h264/sps_vui_rewriter.h"
18*d9f75844SAndroid Build Coastguard Worker #include "modules/include/module_common_types_public.h"
19*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/include/video_coding_defines.h"
20*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/svc/create_scalability_structure.h"
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"
23*d9f75844SAndroid Build Coastguard Worker 
24*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
25*d9f75844SAndroid Build Coastguard Worker namespace {
26*d9f75844SAndroid Build Coastguard Worker const int kMessagesThrottlingThreshold = 2;
27*d9f75844SAndroid Build Coastguard Worker const int kThrottleRatio = 100000;
28*d9f75844SAndroid Build Coastguard Worker 
29*d9f75844SAndroid Build Coastguard Worker class EncodedImageBufferWrapper : public EncodedImageBufferInterface {
30*d9f75844SAndroid Build Coastguard Worker  public:
EncodedImageBufferWrapper(rtc::Buffer && buffer)31*d9f75844SAndroid Build Coastguard Worker   explicit EncodedImageBufferWrapper(rtc::Buffer&& buffer)
32*d9f75844SAndroid Build Coastguard Worker       : buffer_(std::move(buffer)) {}
33*d9f75844SAndroid Build Coastguard Worker 
data() const34*d9f75844SAndroid Build Coastguard Worker   const uint8_t* data() const override { return buffer_.data(); }
data()35*d9f75844SAndroid Build Coastguard Worker   uint8_t* data() override { return buffer_.data(); }
size() const36*d9f75844SAndroid Build Coastguard Worker   size_t size() const override { return buffer_.size(); }
37*d9f75844SAndroid Build Coastguard Worker 
38*d9f75844SAndroid Build Coastguard Worker  private:
39*d9f75844SAndroid Build Coastguard Worker   rtc::Buffer buffer_;
40*d9f75844SAndroid Build Coastguard Worker };
41*d9f75844SAndroid Build Coastguard Worker 
42*d9f75844SAndroid Build Coastguard Worker }  // namespace
43*d9f75844SAndroid Build Coastguard Worker 
44*d9f75844SAndroid Build Coastguard Worker FrameEncodeMetadataWriter::TimingFramesLayerInfo::TimingFramesLayerInfo() =
45*d9f75844SAndroid Build Coastguard Worker     default;
46*d9f75844SAndroid Build Coastguard Worker FrameEncodeMetadataWriter::TimingFramesLayerInfo::~TimingFramesLayerInfo() =
47*d9f75844SAndroid Build Coastguard Worker     default;
48*d9f75844SAndroid Build Coastguard Worker 
FrameEncodeMetadataWriter(EncodedImageCallback * frame_drop_callback)49*d9f75844SAndroid Build Coastguard Worker FrameEncodeMetadataWriter::FrameEncodeMetadataWriter(
50*d9f75844SAndroid Build Coastguard Worker     EncodedImageCallback* frame_drop_callback)
51*d9f75844SAndroid Build Coastguard Worker     : frame_drop_callback_(frame_drop_callback),
52*d9f75844SAndroid Build Coastguard Worker       framerate_fps_(0),
53*d9f75844SAndroid Build Coastguard Worker       last_timing_frame_time_ms_(-1),
54*d9f75844SAndroid Build Coastguard Worker       reordered_frames_logged_messages_(0),
55*d9f75844SAndroid Build Coastguard Worker       stalled_encoder_logged_messages_(0) {
56*d9f75844SAndroid Build Coastguard Worker   codec_settings_.timing_frame_thresholds = {-1, 0};
57*d9f75844SAndroid Build Coastguard Worker }
~FrameEncodeMetadataWriter()58*d9f75844SAndroid Build Coastguard Worker FrameEncodeMetadataWriter::~FrameEncodeMetadataWriter() {}
59*d9f75844SAndroid Build Coastguard Worker 
OnEncoderInit(const VideoCodec & codec)60*d9f75844SAndroid Build Coastguard Worker void FrameEncodeMetadataWriter::OnEncoderInit(const VideoCodec& codec) {
61*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&lock_);
62*d9f75844SAndroid Build Coastguard Worker   codec_settings_ = codec;
63*d9f75844SAndroid Build Coastguard Worker   size_t num_spatial_layers = codec_settings_.numberOfSimulcastStreams;
64*d9f75844SAndroid Build Coastguard Worker   if (codec_settings_.codecType == kVideoCodecVP9) {
65*d9f75844SAndroid Build Coastguard Worker     num_spatial_layers = std::max(
66*d9f75844SAndroid Build Coastguard Worker         num_spatial_layers,
67*d9f75844SAndroid Build Coastguard Worker         static_cast<size_t>(codec_settings_.VP9()->numberOfSpatialLayers));
68*d9f75844SAndroid Build Coastguard Worker   } else if (codec_settings_.codecType == kVideoCodecAV1 &&
69*d9f75844SAndroid Build Coastguard Worker              codec_settings_.GetScalabilityMode().has_value()) {
70*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<ScalableVideoController> structure =
71*d9f75844SAndroid Build Coastguard Worker         CreateScalabilityStructure(*codec_settings_.GetScalabilityMode());
72*d9f75844SAndroid Build Coastguard Worker     if (structure) {
73*d9f75844SAndroid Build Coastguard Worker       num_spatial_layers = structure->StreamConfig().num_spatial_layers;
74*d9f75844SAndroid Build Coastguard Worker     } else {
75*d9f75844SAndroid Build Coastguard Worker       // |structure| maybe nullptr if the scalability mode is invalid.
76*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING) << "Cannot create ScalabilityStructure, since the "
77*d9f75844SAndroid Build Coastguard Worker                              "scalability mode is invalid";
78*d9f75844SAndroid Build Coastguard Worker     }
79*d9f75844SAndroid Build Coastguard Worker   }
80*d9f75844SAndroid Build Coastguard Worker   num_spatial_layers_ = std::max(num_spatial_layers, size_t{1});
81*d9f75844SAndroid Build Coastguard Worker }
82*d9f75844SAndroid Build Coastguard Worker 
OnSetRates(const VideoBitrateAllocation & bitrate_allocation,uint32_t framerate_fps)83*d9f75844SAndroid Build Coastguard Worker void FrameEncodeMetadataWriter::OnSetRates(
84*d9f75844SAndroid Build Coastguard Worker     const VideoBitrateAllocation& bitrate_allocation,
85*d9f75844SAndroid Build Coastguard Worker     uint32_t framerate_fps) {
86*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&lock_);
87*d9f75844SAndroid Build Coastguard Worker   framerate_fps_ = framerate_fps;
88*d9f75844SAndroid Build Coastguard Worker   if (timing_frames_info_.size() < num_spatial_layers_) {
89*d9f75844SAndroid Build Coastguard Worker     timing_frames_info_.resize(num_spatial_layers_);
90*d9f75844SAndroid Build Coastguard Worker   }
91*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < num_spatial_layers_; ++i) {
92*d9f75844SAndroid Build Coastguard Worker     timing_frames_info_[i].target_bitrate_bytes_per_sec =
93*d9f75844SAndroid Build Coastguard Worker         bitrate_allocation.GetSpatialLayerSum(i) / 8;
94*d9f75844SAndroid Build Coastguard Worker   }
95*d9f75844SAndroid Build Coastguard Worker }
96*d9f75844SAndroid Build Coastguard Worker 
OnEncodeStarted(const VideoFrame & frame)97*d9f75844SAndroid Build Coastguard Worker void FrameEncodeMetadataWriter::OnEncodeStarted(const VideoFrame& frame) {
98*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&lock_);
99*d9f75844SAndroid Build Coastguard Worker 
100*d9f75844SAndroid Build Coastguard Worker   timing_frames_info_.resize(num_spatial_layers_);
101*d9f75844SAndroid Build Coastguard Worker   FrameMetadata metadata;
102*d9f75844SAndroid Build Coastguard Worker   metadata.rtp_timestamp = frame.timestamp();
103*d9f75844SAndroid Build Coastguard Worker   metadata.encode_start_time_ms = rtc::TimeMillis();
104*d9f75844SAndroid Build Coastguard Worker   metadata.ntp_time_ms = frame.ntp_time_ms();
105*d9f75844SAndroid Build Coastguard Worker   metadata.timestamp_us = frame.timestamp_us();
106*d9f75844SAndroid Build Coastguard Worker   metadata.rotation = frame.rotation();
107*d9f75844SAndroid Build Coastguard Worker   metadata.color_space = frame.color_space();
108*d9f75844SAndroid Build Coastguard Worker   metadata.packet_infos = frame.packet_infos();
109*d9f75844SAndroid Build Coastguard Worker   for (size_t si = 0; si < num_spatial_layers_; ++si) {
110*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(timing_frames_info_[si].frames.empty() ||
111*d9f75844SAndroid Build Coastguard Worker                rtc::TimeDiff(
112*d9f75844SAndroid Build Coastguard Worker                    frame.render_time_ms(),
113*d9f75844SAndroid Build Coastguard Worker                    timing_frames_info_[si].frames.back().timestamp_us / 1000) >=
114*d9f75844SAndroid Build Coastguard Worker                    0);
115*d9f75844SAndroid Build Coastguard Worker     // If stream is disabled due to low bandwidth OnEncodeStarted still will be
116*d9f75844SAndroid Build Coastguard Worker     // called and have to be ignored.
117*d9f75844SAndroid Build Coastguard Worker     if (timing_frames_info_[si].target_bitrate_bytes_per_sec == 0)
118*d9f75844SAndroid Build Coastguard Worker       continue;
119*d9f75844SAndroid Build Coastguard Worker     if (timing_frames_info_[si].frames.size() == kMaxEncodeStartTimeListSize) {
120*d9f75844SAndroid Build Coastguard Worker       ++stalled_encoder_logged_messages_;
121*d9f75844SAndroid Build Coastguard Worker       if (stalled_encoder_logged_messages_ <= kMessagesThrottlingThreshold ||
122*d9f75844SAndroid Build Coastguard Worker           stalled_encoder_logged_messages_ % kThrottleRatio == 0) {
123*d9f75844SAndroid Build Coastguard Worker         RTC_LOG(LS_WARNING) << "Too many frames in the encode_start_list."
124*d9f75844SAndroid Build Coastguard Worker                                " Did encoder stall?";
125*d9f75844SAndroid Build Coastguard Worker         if (stalled_encoder_logged_messages_ == kMessagesThrottlingThreshold) {
126*d9f75844SAndroid Build Coastguard Worker           RTC_LOG(LS_WARNING)
127*d9f75844SAndroid Build Coastguard Worker               << "Too many log messages. Further stalled encoder"
128*d9f75844SAndroid Build Coastguard Worker                  "warnings will be throttled.";
129*d9f75844SAndroid Build Coastguard Worker         }
130*d9f75844SAndroid Build Coastguard Worker       }
131*d9f75844SAndroid Build Coastguard Worker       frame_drop_callback_->OnDroppedFrame(
132*d9f75844SAndroid Build Coastguard Worker           EncodedImageCallback::DropReason::kDroppedByEncoder);
133*d9f75844SAndroid Build Coastguard Worker       timing_frames_info_[si].frames.pop_front();
134*d9f75844SAndroid Build Coastguard Worker     }
135*d9f75844SAndroid Build Coastguard Worker     timing_frames_info_[si].frames.emplace_back(metadata);
136*d9f75844SAndroid Build Coastguard Worker   }
137*d9f75844SAndroid Build Coastguard Worker }
138*d9f75844SAndroid Build Coastguard Worker 
FillTimingInfo(size_t simulcast_svc_idx,EncodedImage * encoded_image)139*d9f75844SAndroid Build Coastguard Worker void FrameEncodeMetadataWriter::FillTimingInfo(size_t simulcast_svc_idx,
140*d9f75844SAndroid Build Coastguard Worker                                                EncodedImage* encoded_image) {
141*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&lock_);
142*d9f75844SAndroid Build Coastguard Worker   absl::optional<size_t> outlier_frame_size;
143*d9f75844SAndroid Build Coastguard Worker   absl::optional<int64_t> encode_start_ms;
144*d9f75844SAndroid Build Coastguard Worker   uint8_t timing_flags = VideoSendTiming::kNotTriggered;
145*d9f75844SAndroid Build Coastguard Worker 
146*d9f75844SAndroid Build Coastguard Worker   int64_t encode_done_ms = rtc::TimeMillis();
147*d9f75844SAndroid Build Coastguard Worker 
148*d9f75844SAndroid Build Coastguard Worker   encode_start_ms =
149*d9f75844SAndroid Build Coastguard Worker       ExtractEncodeStartTimeAndFillMetadata(simulcast_svc_idx, encoded_image);
150*d9f75844SAndroid Build Coastguard Worker 
151*d9f75844SAndroid Build Coastguard Worker   if (timing_frames_info_.size() > simulcast_svc_idx) {
152*d9f75844SAndroid Build Coastguard Worker     size_t target_bitrate =
153*d9f75844SAndroid Build Coastguard Worker         timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec;
154*d9f75844SAndroid Build Coastguard Worker     if (framerate_fps_ > 0 && target_bitrate > 0) {
155*d9f75844SAndroid Build Coastguard Worker       // framerate and target bitrate were reported by encoder.
156*d9f75844SAndroid Build Coastguard Worker       size_t average_frame_size = target_bitrate / framerate_fps_;
157*d9f75844SAndroid Build Coastguard Worker       outlier_frame_size.emplace(
158*d9f75844SAndroid Build Coastguard Worker           average_frame_size *
159*d9f75844SAndroid Build Coastguard Worker           codec_settings_.timing_frame_thresholds.outlier_ratio_percent / 100);
160*d9f75844SAndroid Build Coastguard Worker     }
161*d9f75844SAndroid Build Coastguard Worker   }
162*d9f75844SAndroid Build Coastguard Worker 
163*d9f75844SAndroid Build Coastguard Worker   // Outliers trigger timing frames, but do not affect scheduled timing
164*d9f75844SAndroid Build Coastguard Worker   // frames.
165*d9f75844SAndroid Build Coastguard Worker   if (outlier_frame_size && encoded_image->size() >= *outlier_frame_size) {
166*d9f75844SAndroid Build Coastguard Worker     timing_flags |= VideoSendTiming::kTriggeredBySize;
167*d9f75844SAndroid Build Coastguard Worker   }
168*d9f75844SAndroid Build Coastguard Worker 
169*d9f75844SAndroid Build Coastguard Worker   // Check if it's time to send a timing frame.
170*d9f75844SAndroid Build Coastguard Worker   int64_t timing_frame_delay_ms =
171*d9f75844SAndroid Build Coastguard Worker       encoded_image->capture_time_ms_ - last_timing_frame_time_ms_;
172*d9f75844SAndroid Build Coastguard Worker   // Trigger threshold if it's a first frame, too long passed since the last
173*d9f75844SAndroid Build Coastguard Worker   // timing frame, or we already sent timing frame on a different simulcast
174*d9f75844SAndroid Build Coastguard Worker   // stream with the same capture time.
175*d9f75844SAndroid Build Coastguard Worker   if (last_timing_frame_time_ms_ == -1 ||
176*d9f75844SAndroid Build Coastguard Worker       timing_frame_delay_ms >=
177*d9f75844SAndroid Build Coastguard Worker           codec_settings_.timing_frame_thresholds.delay_ms ||
178*d9f75844SAndroid Build Coastguard Worker       timing_frame_delay_ms == 0) {
179*d9f75844SAndroid Build Coastguard Worker     timing_flags |= VideoSendTiming::kTriggeredByTimer;
180*d9f75844SAndroid Build Coastguard Worker     last_timing_frame_time_ms_ = encoded_image->capture_time_ms_;
181*d9f75844SAndroid Build Coastguard Worker   }
182*d9f75844SAndroid Build Coastguard Worker 
183*d9f75844SAndroid Build Coastguard Worker   // If encode start is not available that means that encoder uses internal
184*d9f75844SAndroid Build Coastguard Worker   // source. In that case capture timestamp may be from a different clock with a
185*d9f75844SAndroid Build Coastguard Worker   // drift relative to rtc::TimeMillis(). We can't use it for Timing frames,
186*d9f75844SAndroid Build Coastguard Worker   // because to being sent in the network capture time required to be less than
187*d9f75844SAndroid Build Coastguard Worker   // all the other timestamps.
188*d9f75844SAndroid Build Coastguard Worker   if (encode_start_ms) {
189*d9f75844SAndroid Build Coastguard Worker     encoded_image->SetEncodeTime(*encode_start_ms, encode_done_ms);
190*d9f75844SAndroid Build Coastguard Worker     encoded_image->timing_.flags = timing_flags;
191*d9f75844SAndroid Build Coastguard Worker   } else {
192*d9f75844SAndroid Build Coastguard Worker     encoded_image->timing_.flags = VideoSendTiming::kInvalid;
193*d9f75844SAndroid Build Coastguard Worker   }
194*d9f75844SAndroid Build Coastguard Worker }
195*d9f75844SAndroid Build Coastguard Worker 
UpdateBitstream(const CodecSpecificInfo * codec_specific_info,EncodedImage * encoded_image)196*d9f75844SAndroid Build Coastguard Worker void FrameEncodeMetadataWriter::UpdateBitstream(
197*d9f75844SAndroid Build Coastguard Worker     const CodecSpecificInfo* codec_specific_info,
198*d9f75844SAndroid Build Coastguard Worker     EncodedImage* encoded_image) {
199*d9f75844SAndroid Build Coastguard Worker   if (!codec_specific_info ||
200*d9f75844SAndroid Build Coastguard Worker       codec_specific_info->codecType != kVideoCodecH264 ||
201*d9f75844SAndroid Build Coastguard Worker       encoded_image->_frameType != VideoFrameType::kVideoFrameKey) {
202*d9f75844SAndroid Build Coastguard Worker     return;
203*d9f75844SAndroid Build Coastguard Worker   }
204*d9f75844SAndroid Build Coastguard Worker 
205*d9f75844SAndroid Build Coastguard Worker   // Make sure that the data is not copied if owned by EncodedImage.
206*d9f75844SAndroid Build Coastguard Worker   const EncodedImage& buffer = *encoded_image;
207*d9f75844SAndroid Build Coastguard Worker   rtc::Buffer modified_buffer =
208*d9f75844SAndroid Build Coastguard Worker       SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite(
209*d9f75844SAndroid Build Coastguard Worker           buffer, encoded_image->ColorSpace());
210*d9f75844SAndroid Build Coastguard Worker 
211*d9f75844SAndroid Build Coastguard Worker   encoded_image->SetEncodedData(
212*d9f75844SAndroid Build Coastguard Worker       rtc::make_ref_counted<EncodedImageBufferWrapper>(
213*d9f75844SAndroid Build Coastguard Worker           std::move(modified_buffer)));
214*d9f75844SAndroid Build Coastguard Worker }
215*d9f75844SAndroid Build Coastguard Worker 
Reset()216*d9f75844SAndroid Build Coastguard Worker void FrameEncodeMetadataWriter::Reset() {
217*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&lock_);
218*d9f75844SAndroid Build Coastguard Worker   for (auto& info : timing_frames_info_) {
219*d9f75844SAndroid Build Coastguard Worker     info.frames.clear();
220*d9f75844SAndroid Build Coastguard Worker   }
221*d9f75844SAndroid Build Coastguard Worker   last_timing_frame_time_ms_ = -1;
222*d9f75844SAndroid Build Coastguard Worker   reordered_frames_logged_messages_ = 0;
223*d9f75844SAndroid Build Coastguard Worker   stalled_encoder_logged_messages_ = 0;
224*d9f75844SAndroid Build Coastguard Worker }
225*d9f75844SAndroid Build Coastguard Worker 
226*d9f75844SAndroid Build Coastguard Worker absl::optional<int64_t>
ExtractEncodeStartTimeAndFillMetadata(size_t simulcast_svc_idx,EncodedImage * encoded_image)227*d9f75844SAndroid Build Coastguard Worker FrameEncodeMetadataWriter::ExtractEncodeStartTimeAndFillMetadata(
228*d9f75844SAndroid Build Coastguard Worker     size_t simulcast_svc_idx,
229*d9f75844SAndroid Build Coastguard Worker     EncodedImage* encoded_image) {
230*d9f75844SAndroid Build Coastguard Worker   absl::optional<int64_t> result;
231*d9f75844SAndroid Build Coastguard Worker   size_t num_simulcast_svc_streams = timing_frames_info_.size();
232*d9f75844SAndroid Build Coastguard Worker   if (simulcast_svc_idx < num_simulcast_svc_streams) {
233*d9f75844SAndroid Build Coastguard Worker     auto metadata_list = &timing_frames_info_[simulcast_svc_idx].frames;
234*d9f75844SAndroid Build Coastguard Worker     // Skip frames for which there was OnEncodeStarted but no OnEncodedImage
235*d9f75844SAndroid Build Coastguard Worker     // call. These are dropped by encoder internally.
236*d9f75844SAndroid Build Coastguard Worker     // Because some hardware encoders don't preserve capture timestamp we
237*d9f75844SAndroid Build Coastguard Worker     // use RTP timestamps here.
238*d9f75844SAndroid Build Coastguard Worker     while (!metadata_list->empty() &&
239*d9f75844SAndroid Build Coastguard Worker            IsNewerTimestamp(encoded_image->Timestamp(),
240*d9f75844SAndroid Build Coastguard Worker                             metadata_list->front().rtp_timestamp)) {
241*d9f75844SAndroid Build Coastguard Worker       frame_drop_callback_->OnDroppedFrame(
242*d9f75844SAndroid Build Coastguard Worker           EncodedImageCallback::DropReason::kDroppedByEncoder);
243*d9f75844SAndroid Build Coastguard Worker       metadata_list->pop_front();
244*d9f75844SAndroid Build Coastguard Worker     }
245*d9f75844SAndroid Build Coastguard Worker 
246*d9f75844SAndroid Build Coastguard Worker     encoded_image->content_type_ =
247*d9f75844SAndroid Build Coastguard Worker         (codec_settings_.mode == VideoCodecMode::kScreensharing)
248*d9f75844SAndroid Build Coastguard Worker             ? VideoContentType::SCREENSHARE
249*d9f75844SAndroid Build Coastguard Worker             : VideoContentType::UNSPECIFIED;
250*d9f75844SAndroid Build Coastguard Worker 
251*d9f75844SAndroid Build Coastguard Worker     if (!metadata_list->empty() &&
252*d9f75844SAndroid Build Coastguard Worker         metadata_list->front().rtp_timestamp == encoded_image->Timestamp()) {
253*d9f75844SAndroid Build Coastguard Worker       result.emplace(metadata_list->front().encode_start_time_ms);
254*d9f75844SAndroid Build Coastguard Worker       encoded_image->capture_time_ms_ =
255*d9f75844SAndroid Build Coastguard Worker           metadata_list->front().timestamp_us / 1000;
256*d9f75844SAndroid Build Coastguard Worker       encoded_image->ntp_time_ms_ = metadata_list->front().ntp_time_ms;
257*d9f75844SAndroid Build Coastguard Worker       encoded_image->rotation_ = metadata_list->front().rotation;
258*d9f75844SAndroid Build Coastguard Worker       encoded_image->SetColorSpace(metadata_list->front().color_space);
259*d9f75844SAndroid Build Coastguard Worker       encoded_image->SetPacketInfos(metadata_list->front().packet_infos);
260*d9f75844SAndroid Build Coastguard Worker       metadata_list->pop_front();
261*d9f75844SAndroid Build Coastguard Worker     } else {
262*d9f75844SAndroid Build Coastguard Worker       ++reordered_frames_logged_messages_;
263*d9f75844SAndroid Build Coastguard Worker       if (reordered_frames_logged_messages_ <= kMessagesThrottlingThreshold ||
264*d9f75844SAndroid Build Coastguard Worker           reordered_frames_logged_messages_ % kThrottleRatio == 0) {
265*d9f75844SAndroid Build Coastguard Worker         RTC_LOG(LS_WARNING) << "Frame with no encode started time recordings. "
266*d9f75844SAndroid Build Coastguard Worker                                "Encoder may be reordering frames "
267*d9f75844SAndroid Build Coastguard Worker                                "or not preserving RTP timestamps.";
268*d9f75844SAndroid Build Coastguard Worker         if (reordered_frames_logged_messages_ == kMessagesThrottlingThreshold) {
269*d9f75844SAndroid Build Coastguard Worker           RTC_LOG(LS_WARNING) << "Too many log messages. Further frames "
270*d9f75844SAndroid Build Coastguard Worker                                  "reordering warnings will be throttled.";
271*d9f75844SAndroid Build Coastguard Worker         }
272*d9f75844SAndroid Build Coastguard Worker       }
273*d9f75844SAndroid Build Coastguard Worker     }
274*d9f75844SAndroid Build Coastguard Worker   }
275*d9f75844SAndroid Build Coastguard Worker   return result;
276*d9f75844SAndroid Build Coastguard Worker }
277*d9f75844SAndroid Build Coastguard Worker 
278*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
279