blob: 999ca7481c290dad5d39a3e92b3b2bf0c842529c [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>
14
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020015#include "absl/memory/memory.h"
16#include "common_video/h264/sps_vui_rewriter.h"
Erik Språng6a7baa72019-02-26 18:31:00 +010017#include "modules/include/module_common_types_public.h"
18#include "modules/video_coding/include/video_coding_defines.h"
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020019#include "rtc_base/copy_on_write_buffer.h"
Erik Språng6a7baa72019-02-26 18:31:00 +010020#include "rtc_base/logging.h"
21#include "rtc_base/time_utils.h"
22
23namespace webrtc {
24namespace {
25const int kMessagesThrottlingThreshold = 2;
26const int kThrottleRatio = 100000;
27} // namespace
28
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020029FrameEncodeMetadataWriter::TimingFramesLayerInfo::TimingFramesLayerInfo() =
30 default;
31FrameEncodeMetadataWriter::TimingFramesLayerInfo::~TimingFramesLayerInfo() =
32 default;
Erik Språng6a7baa72019-02-26 18:31:00 +010033
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020034FrameEncodeMetadataWriter::FrameEncodeMetadataWriter(
35 EncodedImageCallback* frame_drop_callback)
Erik Språng6a7baa72019-02-26 18:31:00 +010036 : frame_drop_callback_(frame_drop_callback),
37 internal_source_(false),
38 framerate_fps_(0),
39 last_timing_frame_time_ms_(-1),
Erik Språng6a7baa72019-02-26 18:31:00 +010040 reordered_frames_logged_messages_(0),
41 stalled_encoder_logged_messages_(0) {
42 codec_settings_.timing_frame_thresholds = {-1, 0};
43}
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020044FrameEncodeMetadataWriter::~FrameEncodeMetadataWriter() {}
Erik Språng6a7baa72019-02-26 18:31:00 +010045
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020046void FrameEncodeMetadataWriter::OnEncoderInit(const VideoCodec& codec,
47 bool internal_source) {
Erik Språng6a7baa72019-02-26 18:31:00 +010048 rtc::CritScope cs(&lock_);
49 codec_settings_ = codec;
50 internal_source_ = internal_source;
51}
52
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020053void FrameEncodeMetadataWriter::OnSetRates(
Erik Språng6a7baa72019-02-26 18:31:00 +010054 const VideoBitrateAllocation& bitrate_allocation,
55 uint32_t framerate_fps) {
56 rtc::CritScope cs(&lock_);
57 framerate_fps_ = framerate_fps;
58 const size_t num_spatial_layers = NumSpatialLayers();
59 if (timing_frames_info_.size() < num_spatial_layers) {
60 timing_frames_info_.resize(num_spatial_layers);
61 }
62 for (size_t i = 0; i < num_spatial_layers; ++i) {
63 timing_frames_info_[i].target_bitrate_bytes_per_sec =
64 bitrate_allocation.GetSpatialLayerSum(i) / 8;
65 }
66}
67
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020068void FrameEncodeMetadataWriter::OnEncodeStarted(const VideoFrame& frame) {
Erik Språng6a7baa72019-02-26 18:31:00 +010069 rtc::CritScope cs(&lock_);
70 if (internal_source_) {
71 return;
72 }
73
74 const size_t num_spatial_layers = NumSpatialLayers();
75 timing_frames_info_.resize(num_spatial_layers);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020076 FrameMetadata metadata;
77 metadata.rtp_timestamp = frame.timestamp();
78 metadata.encode_start_time_ms = rtc::TimeMillis();
79 metadata.ntp_time_ms = frame.ntp_time_ms();
80 metadata.timestamp_us = frame.timestamp_us();
81 metadata.rotation = frame.rotation();
82 metadata.color_space = frame.color_space();
Erik Språng6a7baa72019-02-26 18:31:00 +010083 for (size_t si = 0; si < num_spatial_layers; ++si) {
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020084 RTC_DCHECK(timing_frames_info_[si].frames.empty() ||
85 rtc::TimeDiff(
86 frame.render_time_ms(),
87 timing_frames_info_[si].frames.back().timestamp_us / 1000) >=
88 0);
Erik Språng6a7baa72019-02-26 18:31:00 +010089 // If stream is disabled due to low bandwidth OnEncodeStarted still will be
90 // called and have to be ignored.
91 if (timing_frames_info_[si].target_bitrate_bytes_per_sec == 0)
92 return;
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +020093 if (timing_frames_info_[si].frames.size() == kMaxEncodeStartTimeListSize) {
Erik Språng6a7baa72019-02-26 18:31:00 +010094 ++stalled_encoder_logged_messages_;
95 if (stalled_encoder_logged_messages_ <= kMessagesThrottlingThreshold ||
96 stalled_encoder_logged_messages_ % kThrottleRatio == 0) {
97 RTC_LOG(LS_WARNING) << "Too many frames in the encode_start_list."
98 " Did encoder stall?";
99 if (stalled_encoder_logged_messages_ == kMessagesThrottlingThreshold) {
100 RTC_LOG(LS_WARNING)
101 << "Too many log messages. Further stalled encoder"
102 "warnings will be throttled.";
103 }
104 }
105 frame_drop_callback_->OnDroppedFrame(
106 EncodedImageCallback::DropReason::kDroppedByEncoder);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200107 timing_frames_info_[si].frames.pop_front();
Erik Språng6a7baa72019-02-26 18:31:00 +0100108 }
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200109 timing_frames_info_[si].frames.emplace_back(metadata);
Erik Språng6a7baa72019-02-26 18:31:00 +0100110 }
111}
112
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200113void FrameEncodeMetadataWriter::FillTimingInfo(size_t simulcast_svc_idx,
114 EncodedImage* encoded_image) {
Erik Språng6a7baa72019-02-26 18:31:00 +0100115 rtc::CritScope cs(&lock_);
116 absl::optional<size_t> outlier_frame_size;
117 absl::optional<int64_t> encode_start_ms;
118 uint8_t timing_flags = VideoSendTiming::kNotTriggered;
119
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200120 int64_t encode_done_ms = rtc::TimeMillis();
121
Erik Språng6a7baa72019-02-26 18:31:00 +0100122 // Encoders with internal sources do not call OnEncodeStarted
123 // |timing_frames_info_| may be not filled here.
124 if (!internal_source_) {
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200125 encode_start_ms =
126 ExtractEncodeStartTimeAndFillMetadata(simulcast_svc_idx, encoded_image);
Erik Språng6a7baa72019-02-26 18:31:00 +0100127 }
128
129 if (timing_frames_info_.size() > simulcast_svc_idx) {
130 size_t target_bitrate =
131 timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec;
132 if (framerate_fps_ > 0 && target_bitrate > 0) {
133 // framerate and target bitrate were reported by encoder.
134 size_t average_frame_size = target_bitrate / framerate_fps_;
135 outlier_frame_size.emplace(
136 average_frame_size *
137 codec_settings_.timing_frame_thresholds.outlier_ratio_percent / 100);
138 }
139 }
140
141 // Outliers trigger timing frames, but do not affect scheduled timing
142 // frames.
143 if (outlier_frame_size && encoded_image->size() >= *outlier_frame_size) {
144 timing_flags |= VideoSendTiming::kTriggeredBySize;
145 }
146
147 // Check if it's time to send a timing frame.
148 int64_t timing_frame_delay_ms =
149 encoded_image->capture_time_ms_ - last_timing_frame_time_ms_;
150 // Trigger threshold if it's a first frame, too long passed since the last
151 // timing frame, or we already sent timing frame on a different simulcast
152 // stream with the same capture time.
153 if (last_timing_frame_time_ms_ == -1 ||
154 timing_frame_delay_ms >=
155 codec_settings_.timing_frame_thresholds.delay_ms ||
156 timing_frame_delay_ms == 0) {
157 timing_flags |= VideoSendTiming::kTriggeredByTimer;
158 last_timing_frame_time_ms_ = encoded_image->capture_time_ms_;
159 }
160
161 // Workaround for chromoting encoder: it passes encode start and finished
162 // timestamps in |timing_| field, but they (together with capture timestamp)
163 // are not in the WebRTC clock.
164 if (internal_source_ && encoded_image->timing_.encode_finish_ms > 0 &&
165 encoded_image->timing_.encode_start_ms > 0) {
166 int64_t clock_offset_ms =
167 encode_done_ms - encoded_image->timing_.encode_finish_ms;
168 // Translate capture timestamp to local WebRTC clock.
169 encoded_image->capture_time_ms_ += clock_offset_ms;
170 encoded_image->SetTimestamp(
171 static_cast<uint32_t>(encoded_image->capture_time_ms_ * 90));
172 encode_start_ms.emplace(encoded_image->timing_.encode_start_ms +
173 clock_offset_ms);
174 }
175
176 // If encode start is not available that means that encoder uses internal
177 // source. In that case capture timestamp may be from a different clock with a
178 // drift relative to rtc::TimeMillis(). We can't use it for Timing frames,
179 // because to being sent in the network capture time required to be less than
180 // all the other timestamps.
181 if (encode_start_ms) {
182 encoded_image->SetEncodeTime(*encode_start_ms, encode_done_ms);
183 encoded_image->timing_.flags = timing_flags;
184 } else {
185 encoded_image->timing_.flags = VideoSendTiming::kInvalid;
186 }
187}
188
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200189std::unique_ptr<RTPFragmentationHeader>
190FrameEncodeMetadataWriter::UpdateBitstream(
191 const CodecSpecificInfo* codec_specific_info,
192 const RTPFragmentationHeader* fragmentation,
193 EncodedImage* encoded_image) {
194 if (!codec_specific_info ||
195 codec_specific_info->codecType != kVideoCodecH264 || !fragmentation ||
196 encoded_image->_frameType != VideoFrameType::kVideoFrameKey) {
197 return nullptr;
198 }
199
200 rtc::CopyOnWriteBuffer modified_buffer;
201 std::unique_ptr<RTPFragmentationHeader> modified_fragmentation =
202 absl::make_unique<RTPFragmentationHeader>();
203 modified_fragmentation->CopyFrom(*fragmentation);
204
205 // Make sure that the data is not copied if owned by EncodedImage.
206 const EncodedImage& buffer = *encoded_image;
207 SpsVuiRewriter::ParseOutgoingBitstreamAndRewriteSps(
208 buffer, fragmentation->fragmentationVectorSize,
209 fragmentation->fragmentationOffset, fragmentation->fragmentationLength,
210 &modified_buffer, modified_fragmentation->fragmentationOffset,
211 modified_fragmentation->fragmentationLength);
212
213 encoded_image->SetEncodedData(modified_buffer);
214
215 return modified_fragmentation;
216}
217
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200218void FrameEncodeMetadataWriter::Reset() {
Erik Språng6a7baa72019-02-26 18:31:00 +0100219 rtc::CritScope cs(&lock_);
220 timing_frames_info_.clear();
221 last_timing_frame_time_ms_ = -1;
222 reordered_frames_logged_messages_ = 0;
223 stalled_encoder_logged_messages_ = 0;
224}
225
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200226absl::optional<int64_t>
227FrameEncodeMetadataWriter::ExtractEncodeStartTimeAndFillMetadata(
Erik Språng6a7baa72019-02-26 18:31:00 +0100228 size_t simulcast_svc_idx,
229 EncodedImage* encoded_image) {
230 absl::optional<int64_t> result;
231 size_t num_simulcast_svc_streams = timing_frames_info_.size();
232 if (simulcast_svc_idx < num_simulcast_svc_streams) {
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200233 auto metadata_list = &timing_frames_info_[simulcast_svc_idx].frames;
Erik Språng6a7baa72019-02-26 18:31:00 +0100234 // Skip frames for which there was OnEncodeStarted but no OnEncodedImage
235 // call. These are dropped by encoder internally.
236 // Because some hardware encoders don't preserve capture timestamp we
237 // use RTP timestamps here.
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200238 while (!metadata_list->empty() &&
Erik Språng6a7baa72019-02-26 18:31:00 +0100239 IsNewerTimestamp(encoded_image->Timestamp(),
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200240 metadata_list->front().rtp_timestamp)) {
Erik Språng6a7baa72019-02-26 18:31:00 +0100241 frame_drop_callback_->OnDroppedFrame(
242 EncodedImageCallback::DropReason::kDroppedByEncoder);
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200243 metadata_list->pop_front();
Erik Språng6a7baa72019-02-26 18:31:00 +0100244 }
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200245 if (!metadata_list->empty() &&
246 metadata_list->front().rtp_timestamp == encoded_image->Timestamp()) {
247 result.emplace(metadata_list->front().encode_start_time_ms);
248
249 encoded_image->capture_time_ms_ =
250 metadata_list->front().timestamp_us / 1000;
251 encoded_image->ntp_time_ms_ = metadata_list->front().ntp_time_ms;
252 encoded_image->rotation_ = metadata_list->front().rotation;
253 encoded_image->SetColorSpace(metadata_list->front().color_space);
254 encoded_image->content_type_ =
255 (codec_settings_.mode == VideoCodecMode::kScreensharing)
256 ? VideoContentType::SCREENSHARE
257 : VideoContentType::UNSPECIFIED;
258
259 metadata_list->pop_front();
Erik Språng6a7baa72019-02-26 18:31:00 +0100260 } else {
261 ++reordered_frames_logged_messages_;
262 if (reordered_frames_logged_messages_ <= kMessagesThrottlingThreshold ||
263 reordered_frames_logged_messages_ % kThrottleRatio == 0) {
264 RTC_LOG(LS_WARNING) << "Frame with no encode started time recordings. "
265 "Encoder may be reordering frames "
266 "or not preserving RTP timestamps.";
267 if (reordered_frames_logged_messages_ == kMessagesThrottlingThreshold) {
268 RTC_LOG(LS_WARNING) << "Too many log messages. Further frames "
269 "reordering warnings will be throttled.";
270 }
271 }
272 }
273 }
274 return result;
275}
276
Ilya Nikolaevskiy2ebf5232019-05-13 16:13:36 +0200277size_t FrameEncodeMetadataWriter::NumSpatialLayers() const {
Erik Språng6a7baa72019-02-26 18:31:00 +0100278 size_t num_spatial_layers = codec_settings_.numberOfSimulcastStreams;
279 if (codec_settings_.codecType == kVideoCodecVP9) {
280 num_spatial_layers = std::max(
281 num_spatial_layers,
282 static_cast<size_t>(codec_settings_.VP9().numberOfSpatialLayers));
283 }
284 return std::max(num_spatial_layers, size_t{1});
285}
286
287} // namespace webrtc