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