blob: 4ed90dbcb15e17f3c476ab97174e2217aa29cd40 [file] [log] [blame]
Erik Språng6a7baa72019-02-26 18:31:00 +01001/*
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
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020011#include "video/frame_encode_metadata_writer.h"
Erik Språng6a7baa72019-02-26 18:31:00 +010012
13#include <algorithm>
Niels Möller4d504c72019-06-18 15:56:56 +020014#include <utility>
Erik Språng6a7baa72019-02-26 18:31:00 +010015
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020016#include "absl/memory/memory.h"
17#include "common_video/h264/sps_vui_rewriter.h"
Erik Språng6a7baa72019-02-26 18:31:00 +010018#include "modules/include/module_common_types_public.h"
19#include "modules/video_coding/include/video_coding_defines.h"
20#include "rtc_base/logging.h"
Niels Möller4d504c72019-06-18 15:56:56 +020021#include "rtc_base/ref_counted_object.h"
Erik Språng6a7baa72019-02-26 18:31:00 +010022#include "rtc_base/time_utils.h"
23
24namespace webrtc {
25namespace {
26const int kMessagesThrottlingThreshold = 2;
27const int kThrottleRatio = 100000;
Niels Möller4d504c72019-06-18 15:56:56 +020028
29class EncodedImageBufferWrapper : public EncodedImageBufferInterface {
30 public:
31 explicit EncodedImageBufferWrapper(rtc::Buffer&& buffer)
32 : buffer_(std::move(buffer)) {}
33
34 const uint8_t* data() const override { return buffer_.data(); }
35 uint8_t* data() override { return buffer_.data(); }
36 size_t size() const override { return buffer_.size(); }
37
38 void Realloc(size_t t) override { RTC_NOTREACHED(); }
39
40 private:
41 rtc::Buffer buffer_;
42};
43
Erik Språng6a7baa72019-02-26 18:31:00 +010044} // namespace
45
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020046FrameEncodeMetadataWriter::TimingFramesLayerInfo::TimingFramesLayerInfo() =
47 default;
48FrameEncodeMetadataWriter::TimingFramesLayerInfo::~TimingFramesLayerInfo() =
49 default;
Erik Språng6a7baa72019-02-26 18:31:00 +010050
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020051FrameEncodeMetadataWriter::FrameEncodeMetadataWriter(
52 EncodedImageCallback* frame_drop_callback)
Erik Språng6a7baa72019-02-26 18:31:00 +010053 : frame_drop_callback_(frame_drop_callback),
54 internal_source_(false),
55 framerate_fps_(0),
56 last_timing_frame_time_ms_(-1),
Erik Språng6a7baa72019-02-26 18:31:00 +010057 reordered_frames_logged_messages_(0),
58 stalled_encoder_logged_messages_(0) {
59 codec_settings_.timing_frame_thresholds = {-1, 0};
60}
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020061FrameEncodeMetadataWriter::~FrameEncodeMetadataWriter() {}
Erik Språng6a7baa72019-02-26 18:31:00 +010062
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020063void FrameEncodeMetadataWriter::OnEncoderInit(const VideoCodec& codec,
64 bool internal_source) {
Erik Språng6a7baa72019-02-26 18:31:00 +010065 rtc::CritScope cs(&lock_);
66 codec_settings_ = codec;
67 internal_source_ = internal_source;
68}
69
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020070void FrameEncodeMetadataWriter::OnSetRates(
Erik Språng6a7baa72019-02-26 18:31:00 +010071 const VideoBitrateAllocation& bitrate_allocation,
72 uint32_t framerate_fps) {
73 rtc::CritScope cs(&lock_);
74 framerate_fps_ = framerate_fps;
75 const size_t num_spatial_layers = NumSpatialLayers();
76 if (timing_frames_info_.size() < num_spatial_layers) {
77 timing_frames_info_.resize(num_spatial_layers);
78 }
79 for (size_t i = 0; i < num_spatial_layers; ++i) {
80 timing_frames_info_[i].target_bitrate_bytes_per_sec =
81 bitrate_allocation.GetSpatialLayerSum(i) / 8;
82 }
83}
84
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020085void FrameEncodeMetadataWriter::OnEncodeStarted(const VideoFrame& frame) {
Erik Språng6a7baa72019-02-26 18:31:00 +010086 rtc::CritScope cs(&lock_);
87 if (internal_source_) {
88 return;
89 }
90
91 const size_t num_spatial_layers = NumSpatialLayers();
92 timing_frames_info_.resize(num_spatial_layers);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020093 FrameMetadata metadata;
94 metadata.rtp_timestamp = frame.timestamp();
95 metadata.encode_start_time_ms = rtc::TimeMillis();
96 metadata.ntp_time_ms = frame.ntp_time_ms();
97 metadata.timestamp_us = frame.timestamp_us();
98 metadata.rotation = frame.rotation();
99 metadata.color_space = frame.color_space();
Chen Xingf00bf422019-06-20 10:05:55 +0200100 metadata.packet_infos = frame.packet_infos();
Erik Språng6a7baa72019-02-26 18:31:00 +0100101 for (size_t si = 0; si < num_spatial_layers; ++si) {
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200102 RTC_DCHECK(timing_frames_info_[si].frames.empty() ||
103 rtc::TimeDiff(
104 frame.render_time_ms(),
105 timing_frames_info_[si].frames.back().timestamp_us / 1000) >=
106 0);
Erik Språng6a7baa72019-02-26 18:31:00 +0100107 // If stream is disabled due to low bandwidth OnEncodeStarted still will be
108 // called and have to be ignored.
109 if (timing_frames_info_[si].target_bitrate_bytes_per_sec == 0)
110 return;
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200111 if (timing_frames_info_[si].frames.size() == kMaxEncodeStartTimeListSize) {
Erik Språng6a7baa72019-02-26 18:31:00 +0100112 ++stalled_encoder_logged_messages_;
113 if (stalled_encoder_logged_messages_ <= kMessagesThrottlingThreshold ||
114 stalled_encoder_logged_messages_ % kThrottleRatio == 0) {
115 RTC_LOG(LS_WARNING) << "Too many frames in the encode_start_list."
116 " Did encoder stall?";
117 if (stalled_encoder_logged_messages_ == kMessagesThrottlingThreshold) {
118 RTC_LOG(LS_WARNING)
119 << "Too many log messages. Further stalled encoder"
120 "warnings will be throttled.";
121 }
122 }
123 frame_drop_callback_->OnDroppedFrame(
124 EncodedImageCallback::DropReason::kDroppedByEncoder);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200125 timing_frames_info_[si].frames.pop_front();
Erik Språng6a7baa72019-02-26 18:31:00 +0100126 }
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200127 timing_frames_info_[si].frames.emplace_back(metadata);
Erik Språng6a7baa72019-02-26 18:31:00 +0100128 }
129}
130
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200131void FrameEncodeMetadataWriter::FillTimingInfo(size_t simulcast_svc_idx,
132 EncodedImage* encoded_image) {
Erik Språng6a7baa72019-02-26 18:31:00 +0100133 rtc::CritScope cs(&lock_);
134 absl::optional<size_t> outlier_frame_size;
135 absl::optional<int64_t> encode_start_ms;
136 uint8_t timing_flags = VideoSendTiming::kNotTriggered;
137
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200138 int64_t encode_done_ms = rtc::TimeMillis();
139
Erik Språng6a7baa72019-02-26 18:31:00 +0100140 // Encoders with internal sources do not call OnEncodeStarted
141 // |timing_frames_info_| may be not filled here.
142 if (!internal_source_) {
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200143 encode_start_ms =
144 ExtractEncodeStartTimeAndFillMetadata(simulcast_svc_idx, encoded_image);
Erik Språng6a7baa72019-02-26 18:31:00 +0100145 }
146
147 if (timing_frames_info_.size() > simulcast_svc_idx) {
148 size_t target_bitrate =
149 timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec;
150 if (framerate_fps_ > 0 && target_bitrate > 0) {
151 // framerate and target bitrate were reported by encoder.
152 size_t average_frame_size = target_bitrate / framerate_fps_;
153 outlier_frame_size.emplace(
154 average_frame_size *
155 codec_settings_.timing_frame_thresholds.outlier_ratio_percent / 100);
156 }
157 }
158
159 // Outliers trigger timing frames, but do not affect scheduled timing
160 // frames.
161 if (outlier_frame_size && encoded_image->size() >= *outlier_frame_size) {
162 timing_flags |= VideoSendTiming::kTriggeredBySize;
163 }
164
165 // Check if it's time to send a timing frame.
166 int64_t timing_frame_delay_ms =
167 encoded_image->capture_time_ms_ - last_timing_frame_time_ms_;
168 // Trigger threshold if it's a first frame, too long passed since the last
169 // timing frame, or we already sent timing frame on a different simulcast
170 // stream with the same capture time.
171 if (last_timing_frame_time_ms_ == -1 ||
172 timing_frame_delay_ms >=
173 codec_settings_.timing_frame_thresholds.delay_ms ||
174 timing_frame_delay_ms == 0) {
175 timing_flags |= VideoSendTiming::kTriggeredByTimer;
176 last_timing_frame_time_ms_ = encoded_image->capture_time_ms_;
177 }
178
179 // Workaround for chromoting encoder: it passes encode start and finished
180 // timestamps in |timing_| field, but they (together with capture timestamp)
181 // are not in the WebRTC clock.
182 if (internal_source_ && encoded_image->timing_.encode_finish_ms > 0 &&
183 encoded_image->timing_.encode_start_ms > 0) {
184 int64_t clock_offset_ms =
185 encode_done_ms - encoded_image->timing_.encode_finish_ms;
186 // Translate capture timestamp to local WebRTC clock.
187 encoded_image->capture_time_ms_ += clock_offset_ms;
188 encoded_image->SetTimestamp(
189 static_cast<uint32_t>(encoded_image->capture_time_ms_ * 90));
190 encode_start_ms.emplace(encoded_image->timing_.encode_start_ms +
191 clock_offset_ms);
192 }
193
194 // If encode start is not available that means that encoder uses internal
195 // source. In that case capture timestamp may be from a different clock with a
196 // drift relative to rtc::TimeMillis(). We can't use it for Timing frames,
197 // because to being sent in the network capture time required to be less than
198 // all the other timestamps.
199 if (encode_start_ms) {
200 encoded_image->SetEncodeTime(*encode_start_ms, encode_done_ms);
201 encoded_image->timing_.flags = timing_flags;
202 } else {
203 encoded_image->timing_.flags = VideoSendTiming::kInvalid;
204 }
205}
206
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200207std::unique_ptr<RTPFragmentationHeader>
208FrameEncodeMetadataWriter::UpdateBitstream(
209 const CodecSpecificInfo* codec_specific_info,
210 const RTPFragmentationHeader* fragmentation,
211 EncodedImage* encoded_image) {
212 if (!codec_specific_info ||
213 codec_specific_info->codecType != kVideoCodecH264 || !fragmentation ||
214 encoded_image->_frameType != VideoFrameType::kVideoFrameKey) {
215 return nullptr;
216 }
217
Niels Möller4d504c72019-06-18 15:56:56 +0200218 rtc::Buffer modified_buffer;
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200219 std::unique_ptr<RTPFragmentationHeader> modified_fragmentation =
220 absl::make_unique<RTPFragmentationHeader>();
221 modified_fragmentation->CopyFrom(*fragmentation);
222
223 // Make sure that the data is not copied if owned by EncodedImage.
224 const EncodedImage& buffer = *encoded_image;
225 SpsVuiRewriter::ParseOutgoingBitstreamAndRewriteSps(
226 buffer, fragmentation->fragmentationVectorSize,
227 fragmentation->fragmentationOffset, fragmentation->fragmentationLength,
Sergey Silkin0c0c9692019-06-12 14:27:34 +0200228 encoded_image->ColorSpace(), &modified_buffer,
229 modified_fragmentation->fragmentationOffset,
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200230 modified_fragmentation->fragmentationLength);
231
Niels Möller4d504c72019-06-18 15:56:56 +0200232 encoded_image->SetEncodedData(
233 new rtc::RefCountedObject<EncodedImageBufferWrapper>(
234 std::move(modified_buffer)));
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200235
236 return modified_fragmentation;
237}
238
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200239void FrameEncodeMetadataWriter::Reset() {
Erik Språng6a7baa72019-02-26 18:31:00 +0100240 rtc::CritScope cs(&lock_);
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +0200241 for (auto& info : timing_frames_info_) {
242 info.frames.clear();
243 }
Erik Språng6a7baa72019-02-26 18:31:00 +0100244 last_timing_frame_time_ms_ = -1;
245 reordered_frames_logged_messages_ = 0;
246 stalled_encoder_logged_messages_ = 0;
247}
248
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200249absl::optional<int64_t>
250FrameEncodeMetadataWriter::ExtractEncodeStartTimeAndFillMetadata(
Erik Språng6a7baa72019-02-26 18:31:00 +0100251 size_t simulcast_svc_idx,
252 EncodedImage* encoded_image) {
253 absl::optional<int64_t> result;
254 size_t num_simulcast_svc_streams = timing_frames_info_.size();
255 if (simulcast_svc_idx < num_simulcast_svc_streams) {
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200256 auto metadata_list = &timing_frames_info_[simulcast_svc_idx].frames;
Erik Språng6a7baa72019-02-26 18:31:00 +0100257 // Skip frames for which there was OnEncodeStarted but no OnEncodedImage
258 // call. These are dropped by encoder internally.
259 // Because some hardware encoders don't preserve capture timestamp we
260 // use RTP timestamps here.
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200261 while (!metadata_list->empty() &&
Erik Språng6a7baa72019-02-26 18:31:00 +0100262 IsNewerTimestamp(encoded_image->Timestamp(),
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200263 metadata_list->front().rtp_timestamp)) {
Erik Språng6a7baa72019-02-26 18:31:00 +0100264 frame_drop_callback_->OnDroppedFrame(
265 EncodedImageCallback::DropReason::kDroppedByEncoder);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200266 metadata_list->pop_front();
Erik Språng6a7baa72019-02-26 18:31:00 +0100267 }
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +0200268
269 encoded_image->content_type_ =
270 (codec_settings_.mode == VideoCodecMode::kScreensharing)
271 ? VideoContentType::SCREENSHARE
272 : VideoContentType::UNSPECIFIED;
273
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200274 if (!metadata_list->empty() &&
275 metadata_list->front().rtp_timestamp == encoded_image->Timestamp()) {
276 result.emplace(metadata_list->front().encode_start_time_ms);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200277 encoded_image->capture_time_ms_ =
278 metadata_list->front().timestamp_us / 1000;
279 encoded_image->ntp_time_ms_ = metadata_list->front().ntp_time_ms;
280 encoded_image->rotation_ = metadata_list->front().rotation;
281 encoded_image->SetColorSpace(metadata_list->front().color_space);
Chen Xingf00bf422019-06-20 10:05:55 +0200282 encoded_image->SetPacketInfos(metadata_list->front().packet_infos);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200283 metadata_list->pop_front();
Erik Språng6a7baa72019-02-26 18:31:00 +0100284 } else {
285 ++reordered_frames_logged_messages_;
286 if (reordered_frames_logged_messages_ <= kMessagesThrottlingThreshold ||
287 reordered_frames_logged_messages_ % kThrottleRatio == 0) {
288 RTC_LOG(LS_WARNING) << "Frame with no encode started time recordings. "
289 "Encoder may be reordering frames "
290 "or not preserving RTP timestamps.";
291 if (reordered_frames_logged_messages_ == kMessagesThrottlingThreshold) {
292 RTC_LOG(LS_WARNING) << "Too many log messages. Further frames "
293 "reordering warnings will be throttled.";
294 }
295 }
296 }
297 }
298 return result;
299}
300
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200301size_t FrameEncodeMetadataWriter::NumSpatialLayers() const {
Erik Språng6a7baa72019-02-26 18:31:00 +0100302 size_t num_spatial_layers = codec_settings_.numberOfSimulcastStreams;
303 if (codec_settings_.codecType == kVideoCodecVP9) {
304 num_spatial_layers = std::max(
305 num_spatial_layers,
306 static_cast<size_t>(codec_settings_.VP9().numberOfSpatialLayers));
307 }
308 return std::max(num_spatial_layers, size_t{1});
309}
310
311} // namespace webrtc