blob: 6a585c6c7aa313d3097b34c138a4678dca7e55c7 [file] [log] [blame]
pbos@webrtc.org9115cde2014-12-09 10:36:40 +00001/*
2 * Copyright (c) 2014 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "media/engine/simulcast_encoder_adapter.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <stdio.h>
14#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020015
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000016#include <algorithm>
Yves Gerey3e707812018-11-28 16:47:49 +010017#include <cstdint>
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020018#include <string>
19#include <utility>
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000020
Mirko Bonadeid9708072019-01-25 20:26:48 +010021#include "api/scoped_refptr.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010023#include "api/video/video_codec_constants.h"
Yves Gerey3e707812018-11-28 16:47:49 +010024#include "api/video/video_frame_buffer.h"
25#include "api/video/video_rotation.h"
Elad Alon370f93a2019-06-11 14:57:57 +020026#include "api/video_codecs/video_encoder.h"
Magnus Jedvertdf4883d2017-11-17 14:44:55 +010027#include "api/video_codecs/video_encoder_factory.h"
Erik Språngf4e0c292019-10-01 18:50:03 +020028#include "api/video_codecs/video_encoder_software_fallback_wrapper.h"
Yves Gerey3e707812018-11-28 16:47:49 +010029#include "modules/video_coding/include/video_error_codes.h"
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +020030#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "rtc_base/checks.h"
Erik Språng7f24fb92019-02-13 10:49:37 +010033#include "rtc_base/experiments/rate_control_settings.h"
Erik Språng16cb8f52019-04-12 13:59:09 +020034#include "rtc_base/logging.h"
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020035#include "system_wrappers/include/field_trial.h"
Mirko Bonadei65432062017-12-11 09:32:13 +010036#include "third_party/libyuv/include/libyuv/scale.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000037
38namespace {
39
40const unsigned int kDefaultMinQp = 2;
41const unsigned int kDefaultMaxQp = 56;
42// Max qp for lowest spatial resolution when doing simulcast.
43const unsigned int kLowestResMaxQp = 45;
44
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020045absl::optional<unsigned int> GetScreenshareBoostedQpValue() {
46 std::string experiment_group =
47 webrtc::field_trial::FindFullName("WebRTC-BoostedScreenshareQp");
48 unsigned int qp;
49 if (sscanf(experiment_group.c_str(), "%u", &qp) != 1)
50 return absl::nullopt;
51 qp = std::min(qp, 63u);
52 qp = std::max(qp, 1u);
53 return qp;
54}
55
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000056uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
57 uint32_t bitrate_sum = 0;
58 for (int i = 0; i < streams; ++i) {
59 bitrate_sum += codec.simulcastStream[i].maxBitrate;
60 }
61 return bitrate_sum;
62}
63
64int NumberOfStreams(const webrtc::VideoCodec& codec) {
65 int streams =
66 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
67 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
68 if (simulcast_max_bitrate == 0) {
69 streams = 1;
70 }
71 return streams;
72}
73
Erik Språngf4e0c292019-10-01 18:50:03 +020074int NumActiveStreams(const webrtc::VideoCodec& codec) {
75 int num_configured_streams = NumberOfStreams(codec);
76 int num_active_streams = 0;
77 for (int i = 0; i < num_configured_streams; ++i) {
78 if (codec.simulcastStream[i].active) {
79 ++num_active_streams;
80 }
81 }
82 return num_active_streams;
83}
84
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000085int VerifyCodec(const webrtc::VideoCodec* inst) {
brandtr5e171752017-05-23 03:32:16 -070086 if (inst == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000087 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
88 }
89 if (inst->maxFramerate < 1) {
90 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
91 }
92 // allow zero to represent an unspecified maxBitRate
93 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
94 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
95 }
96 if (inst->width <= 1 || inst->height <= 1) {
97 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
98 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +020099 if (inst->codecType == webrtc::kVideoCodecVP8 &&
100 inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000101 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
102 }
103 return WEBRTC_VIDEO_CODEC_OK;
104}
105
Florent Castelli1b761ca2019-01-21 14:33:02 +0100106bool StreamResolutionCompare(const webrtc::SimulcastStream& a,
107 const webrtc::SimulcastStream& b) {
108 return std::tie(a.height, a.width, a.maxBitrate, a.maxFramerate) <
109 std::tie(b.height, b.width, b.maxBitrate, b.maxFramerate);
110}
111
Noah Richards41ee1ea2015-04-15 09:24:26 -0700112// An EncodedImageCallback implementation that forwards on calls to a
113// SimulcastEncoderAdapter, but with the stream index it's registered with as
114// the first parameter to Encoded.
115class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
116 public:
117 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
118 size_t stream_idx)
119 : adapter_(adapter), stream_idx_(stream_idx) {}
120
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700121 EncodedImageCallback::Result OnEncodedImage(
122 const webrtc::EncodedImage& encoded_image,
123 const webrtc::CodecSpecificInfo* codec_specific_info,
124 const webrtc::RTPFragmentationHeader* fragmentation) override {
125 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
126 codec_specific_info, fragmentation);
Noah Richards41ee1ea2015-04-15 09:24:26 -0700127 }
128
129 private:
130 webrtc::SimulcastEncoderAdapter* const adapter_;
131 const size_t stream_idx_;
132};
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000133} // namespace
134
135namespace webrtc {
136
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200137SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory,
138 const SdpVideoFormat& format)
Erik Språngf4e0c292019-10-01 18:50:03 +0200139 : SimulcastEncoderAdapter(factory, nullptr, format) {}
140
141SimulcastEncoderAdapter::SimulcastEncoderAdapter(
142 VideoEncoderFactory* primary_factory,
143 VideoEncoderFactory* fallback_factory,
144 const SdpVideoFormat& format)
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100145 : inited_(0),
Erik Språngf4e0c292019-10-01 18:50:03 +0200146 primary_encoder_factory_(primary_factory),
147 fallback_encoder_factory_(fallback_factory),
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200148 video_format_(format),
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100149 encoded_complete_callback_(nullptr),
Erik Språng7f24fb92019-02-13 10:49:37 +0100150 experimental_boosted_screenshare_qp_(GetScreenshareBoostedQpValue()),
151 boost_base_layer_quality_(RateControlSettings::ParseFromFieldTrials()
152 .Vp8BoostBaseLayerQuality()) {
Erik Språngf4e0c292019-10-01 18:50:03 +0200153 RTC_DCHECK(primary_factory);
Erik Språng75de46a2018-11-07 14:53:32 +0100154 encoder_info_.implementation_name = "SimulcastEncoderAdapter";
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100155
brandtr5e171752017-05-23 03:32:16 -0700156 // The adapter is typically created on the worker thread, but operated on
157 // the encoder task queue.
158 encoder_queue_.Detach();
159
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000160 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
161}
162
163SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
brandtr5e171752017-05-23 03:32:16 -0700164 RTC_DCHECK(!Initialized());
165 DestroyStoredEncoders();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000166}
167
Elad Alon8f01c4e2019-06-28 15:19:43 +0200168void SimulcastEncoderAdapter::SetFecControllerOverride(
169 FecControllerOverride* fec_controller_override) {
170 // Ignored.
171}
172
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000173int SimulcastEncoderAdapter::Release() {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200174 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700175
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000176 while (!streaminfos_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700177 std::unique_ptr<VideoEncoder> encoder =
178 std::move(streaminfos_.back().encoder);
brandtr5e171752017-05-23 03:32:16 -0700179 // Even though it seems very unlikely, there are no guarantees that the
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200180 // encoder will not call back after being Release()'d. Therefore, we first
181 // disable the callbacks here.
brandtr5e171752017-05-23 03:32:16 -0700182 encoder->RegisterEncodeCompleteCallback(nullptr);
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200183 encoder->Release();
brandtr5e171752017-05-23 03:32:16 -0700184 streaminfos_.pop_back(); // Deletes callback adapter.
magjed3f897582017-08-28 08:05:42 -0700185 stored_encoders_.push(std::move(encoder));
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000186 }
brandtr5e171752017-05-23 03:32:16 -0700187
188 // It's legal to move the encoder to another queue now.
189 encoder_queue_.Detach();
190
191 rtc::AtomicOps::ReleaseStore(&inited_, 0);
192
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000193 return WEBRTC_VIDEO_CODEC_OK;
194}
195
Elad Alon370f93a2019-06-11 14:57:57 +0200196// TODO(eladalon): s/inst/codec_settings/g.
197int SimulcastEncoderAdapter::InitEncode(
198 const VideoCodec* inst,
199 const VideoEncoder::Settings& settings) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200200 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700201
Elad Alon370f93a2019-06-11 14:57:57 +0200202 if (settings.number_of_cores < 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000203 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
204 }
205
206 int ret = VerifyCodec(inst);
207 if (ret < 0) {
208 return ret;
209 }
210
211 ret = Release();
212 if (ret < 0) {
213 return ret;
214 }
215
216 int number_of_streams = NumberOfStreams(*inst);
brandtr5e171752017-05-23 03:32:16 -0700217 RTC_DCHECK_LE(number_of_streams, kMaxSimulcastStreams);
Erik Språngf4e0c292019-10-01 18:50:03 +0200218 bool doing_simulcast_using_adapter = (number_of_streams > 1);
219 int num_active_streams = NumActiveStreams(*inst);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000220
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000221 codec_ = *inst;
Erik Språng82fad3d2018-03-21 09:57:23 +0100222 SimulcastRateAllocator rate_allocator(codec_);
Florent Castelli8bbdb5b2019-08-02 15:16:28 +0200223 VideoBitrateAllocation allocation =
224 rate_allocator.Allocate(VideoBitrateAllocationParameters(
225 codec_.startBitrate * 1000, codec_.maxFramerate));
Erik Språng08127a92016-11-16 16:41:30 +0100226 std::vector<uint32_t> start_bitrates;
227 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
228 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
229 start_bitrates.push_back(stream_bitrate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000230 }
231
Erik Språng75de46a2018-11-07 14:53:32 +0100232 encoder_info_.supports_native_handle = true;
233 encoder_info_.scaling_settings.thresholds = absl::nullopt;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000234 // Create |number_of_streams| of encoder instances and init them.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100235
236 const auto minmax = std::minmax_element(
237 std::begin(codec_.simulcastStream),
238 std::begin(codec_.simulcastStream) + number_of_streams,
239 StreamResolutionCompare);
240 const auto lowest_resolution_stream_index =
241 std::distance(std::begin(codec_.simulcastStream), minmax.first);
242 const auto highest_resolution_stream_index =
243 std::distance(std::begin(codec_.simulcastStream), minmax.second);
244
245 RTC_DCHECK_LT(lowest_resolution_stream_index, number_of_streams);
246 RTC_DCHECK_LT(highest_resolution_stream_index, number_of_streams);
247
Erik Språngf4e0c292019-10-01 18:50:03 +0200248 const SdpVideoFormat format(
249 codec_.codecType == webrtc::kVideoCodecVP8 ? "VP8" : "H264");
250
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000251 for (int i = 0; i < number_of_streams; ++i) {
Erik Språngf4e0c292019-10-01 18:50:03 +0200252 // If an existing encoder instance exists, reuse it.
253 // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
254 // when we start storing that state outside the encoder wrappers.
255 std::unique_ptr<VideoEncoder> encoder;
256 if (!stored_encoders_.empty()) {
257 encoder = std::move(stored_encoders_.top());
258 stored_encoders_.pop();
259 } else {
260 encoder = primary_encoder_factory_->CreateVideoEncoder(format);
261 if (fallback_encoder_factory_ != nullptr) {
262 encoder = CreateVideoEncoderSoftwareFallbackWrapper(
263 fallback_encoder_factory_->CreateVideoEncoder(format),
264 std::move(encoder));
265 }
266 }
267
268 bool encoder_initialized = false;
269 if (doing_simulcast_using_adapter && i == 0 &&
270 encoder->GetEncoderInfo().supports_simulcast) {
271 ret = encoder->InitEncode(&codec_, settings);
272 if (ret < 0) {
273 encoder->Release();
274 } else {
275 doing_simulcast_using_adapter = false;
276 number_of_streams = 1;
277 encoder_initialized = true;
278 }
279 }
280
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000281 VideoCodec stream_codec;
Erik Språng78ce6192016-09-12 16:04:43 +0200282 uint32_t start_bitrate_kbps = start_bitrates[i];
Erik Språngf4e0c292019-10-01 18:50:03 +0200283 const bool send_stream = doing_simulcast_using_adapter
284 ? start_bitrate_kbps > 0
285 : num_active_streams > 0;
286 if (!doing_simulcast_using_adapter) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000287 stream_codec = codec_;
Erik Språngf4e0c292019-10-01 18:50:03 +0200288 stream_codec.numberOfSimulcastStreams =
289 std::max<uint8_t>(1, stream_codec.numberOfSimulcastStreams);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000290 } else {
Erik Språng78ce6192016-09-12 16:04:43 +0200291 // Cap start bitrate to the min bitrate in order to avoid strange codec
Erik Språng7d687b12018-09-12 17:04:10 +0200292 // behavior. Since sending will be false, this should not matter.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100293 StreamResolution stream_resolution =
294 i == highest_resolution_stream_index
295 ? StreamResolution::HIGHEST
296 : i == lowest_resolution_stream_index ? StreamResolution::LOWEST
297 : StreamResolution::OTHER;
298
Erik Språng78ce6192016-09-12 16:04:43 +0200299 start_bitrate_kbps =
300 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
Florent Castelli1b761ca2019-01-21 14:33:02 +0100301 PopulateStreamCodec(codec_, i, start_bitrate_kbps, stream_resolution,
302 &stream_codec);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000303 }
304
Erik Språngcc681cc2018-03-14 17:52:55 +0100305 // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000306 if (stream_codec.qpMax < kDefaultMinQp) {
307 stream_codec.qpMax = kDefaultMaxQp;
308 }
309
Erik Språngf4e0c292019-10-01 18:50:03 +0200310 if (!encoder_initialized) {
311 ret = encoder->InitEncode(&stream_codec, settings);
312 if (ret < 0) {
313 // Explicitly destroy the current encoder; because we haven't registered
314 // a StreamInfo for it yet, Release won't do anything about it.
315 encoder.reset();
316 Release();
317 return ret;
318 }
brandtr5e171752017-05-23 03:32:16 -0700319 }
320
Erik Språngf4e0c292019-10-01 18:50:03 +0200321 if (!doing_simulcast_using_adapter) {
Erik Språng75de46a2018-11-07 14:53:32 +0100322 // Without simulcast, just pass through the encoder info from the one
323 // active encoder.
Erik Språngf4e0c292019-10-01 18:50:03 +0200324 encoder_info_ = encoder->GetEncoderInfo();
325 encoder->RegisterEncodeCompleteCallback(encoded_complete_callback_);
326 streaminfos_.emplace_back(std::move(encoder), nullptr, stream_codec.width,
327 stream_codec.height, send_stream);
Erik Språng75de46a2018-11-07 14:53:32 +0100328 } else {
Erik Språngf4e0c292019-10-01 18:50:03 +0200329 std::unique_ptr<EncodedImageCallback> callback(
330 new AdapterEncodedImageCallback(this, i));
331 encoder->RegisterEncodeCompleteCallback(callback.get());
332 streaminfos_.emplace_back(std::move(encoder), std::move(callback),
333 stream_codec.width, stream_codec.height,
334 send_stream);
335
Erik Språng75de46a2018-11-07 14:53:32 +0100336 const EncoderInfo encoder_impl_info =
337 streaminfos_[i].encoder->GetEncoderInfo();
338
339 if (i == 0) {
340 // Quality scaling not enabled for simulcast.
341 encoder_info_.scaling_settings = VideoEncoder::ScalingSettings::kOff;
342
343 // Encoder name indicates names of all sub-encoders.
344 encoder_info_.implementation_name = "SimulcastEncoderAdapter (";
345 encoder_info_.implementation_name +=
346 encoder_impl_info.implementation_name;
347
348 encoder_info_.supports_native_handle =
349 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100350 encoder_info_.has_trusted_rate_controller =
351 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100352 encoder_info_.is_hardware_accelerated =
353 encoder_impl_info.is_hardware_accelerated;
354 encoder_info_.has_internal_source =
355 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100356 } else {
357 encoder_info_.implementation_name += ", ";
358 encoder_info_.implementation_name +=
359 encoder_impl_info.implementation_name;
360
361 // Native handle supported only if all encoders supports it.
362 encoder_info_.supports_native_handle &=
363 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100364
365 // Trusted rate controller only if all encoders have it.
366 encoder_info_.has_trusted_rate_controller &=
367 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100368
369 // Uses hardware support if any of the encoders uses it.
370 // For example, if we are having issues with down-scaling due to
371 // pipelining delay in HW encoders we need higher encoder usage
372 // thresholds in CPU adaptation.
373 encoder_info_.is_hardware_accelerated |=
374 encoder_impl_info.is_hardware_accelerated;
375
376 // Has internal source only if all encoders have it.
377 encoder_info_.has_internal_source &=
378 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100379 }
Erik Språngdbdd8392019-01-17 15:27:50 +0100380 encoder_info_.fps_allocation[i] = encoder_impl_info.fps_allocation[0];
brandtr5e171752017-05-23 03:32:16 -0700381 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000382 }
brandtr5e171752017-05-23 03:32:16 -0700383
Erik Språngf4e0c292019-10-01 18:50:03 +0200384 if (doing_simulcast_using_adapter) {
Erik Språng75de46a2018-11-07 14:53:32 +0100385 encoder_info_.implementation_name += ")";
Peter Boströmd53c3892016-03-30 17:03:52 +0200386 }
brandtr5e171752017-05-23 03:32:16 -0700387
388 // To save memory, don't store encoders that we don't use.
389 DestroyStoredEncoders();
390
391 rtc::AtomicOps::ReleaseStore(&inited_, 1);
392
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000393 return WEBRTC_VIDEO_CODEC_OK;
394}
395
396int SimulcastEncoderAdapter::Encode(
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700397 const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100398 const std::vector<VideoFrameType>* frame_types) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200399 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700400
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000401 if (!Initialized()) {
402 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
403 }
brandtr5e171752017-05-23 03:32:16 -0700404 if (encoded_complete_callback_ == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000405 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
406 }
407
408 // All active streams should generate a key frame if
409 // a key frame is requested by any stream.
410 bool send_key_frame = false;
411 if (frame_types) {
412 for (size_t i = 0; i < frame_types->size(); ++i) {
Niels Möller8f7ce222019-03-21 15:43:58 +0100413 if (frame_types->at(i) == VideoFrameType::kVideoFrameKey) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000414 send_key_frame = true;
415 break;
416 }
417 }
418 }
419 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
420 if (streaminfos_[stream_idx].key_frame_request &&
421 streaminfos_[stream_idx].send_stream) {
422 send_key_frame = true;
423 break;
424 }
425 }
426
427 int src_width = input_image.width();
428 int src_height = input_image.height();
429 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200430 // Don't encode frames in resolutions that we don't intend to send.
brandtr5e171752017-05-23 03:32:16 -0700431 if (!streaminfos_[stream_idx].send_stream) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200432 continue;
brandtr5e171752017-05-23 03:32:16 -0700433 }
Peter Boström5d0379d2015-10-06 14:04:51 +0200434
Niels Möller87e2d782019-03-07 10:18:23 +0100435 std::vector<VideoFrameType> stream_frame_types;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000436 if (send_key_frame) {
Niels Möller8f7ce222019-03-21 15:43:58 +0100437 stream_frame_types.push_back(VideoFrameType::kVideoFrameKey);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000438 streaminfos_[stream_idx].key_frame_request = false;
439 } else {
Niels Möller8f7ce222019-03-21 15:43:58 +0100440 stream_frame_types.push_back(VideoFrameType::kVideoFrameDelta);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000441 }
442
443 int dst_width = streaminfos_[stream_idx].width;
444 int dst_height = streaminfos_[stream_idx].height;
445 // If scaling isn't required, because the input resolution
446 // matches the destination or the input image is empty (e.g.
447 // a keyframe request for encoders with internal camera
noahricfe3654d2016-07-01 09:05:54 -0700448 // sources) or the source image has a native handle, pass the image on
449 // directly. Otherwise, we'll scale it to match what the encoder expects
450 // (below).
451 // For texture frames, the underlying encoder is expected to be able to
452 // correctly sample/scale the source texture.
453 // TODO(perkj): ensure that works going forward, and figure out how this
454 // affects webrtc:5683.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000455 if ((dst_width == src_width && dst_height == src_height) ||
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000456 input_image.video_frame_buffer()->type() ==
457 VideoFrameBuffer::Type::kNative) {
Niels Möllerc8d2e732019-03-06 12:00:33 +0100458 int ret = streaminfos_[stream_idx].encoder->Encode(input_image,
459 &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700460 if (ret != WEBRTC_VIDEO_CODEC_OK) {
461 return ret;
462 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000463 } else {
nisse64ec8f82016-09-27 00:17:25 -0700464 rtc::scoped_refptr<I420Buffer> dst_buffer =
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000465 I420Buffer::Create(dst_width, dst_height);
466 rtc::scoped_refptr<I420BufferInterface> src_buffer =
467 input_image.video_frame_buffer()->ToI420();
468 libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
469 src_buffer->DataU(), src_buffer->StrideU(),
470 src_buffer->DataV(), src_buffer->StrideV(), src_width,
471 src_height, dst_buffer->MutableDataY(),
472 dst_buffer->StrideY(), dst_buffer->MutableDataU(),
473 dst_buffer->StrideU(), dst_buffer->MutableDataV(),
474 dst_buffer->StrideV(), dst_width, dst_height,
nissec9c142f2016-05-17 04:05:47 -0700475 libyuv::kFilterBilinear);
nisse64ec8f82016-09-27 00:17:25 -0700476
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100477 // UpdateRect is not propagated to lower simulcast layers currently.
478 // TODO(ilnik): Consider scaling UpdateRect together with the buffer.
Ilya Nikolaevskiy4fc08552019-06-05 15:59:12 +0200479 VideoFrame frame(input_image);
480 frame.set_video_frame_buffer(dst_buffer);
481 frame.set_rotation(webrtc::kVideoRotation_0);
482 frame.set_update_rect(
483 VideoFrame::UpdateRect{0, 0, frame.width(), frame.height()});
Niels Möllerc8d2e732019-03-06 12:00:33 +0100484 int ret =
485 streaminfos_[stream_idx].encoder->Encode(frame, &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700486 if (ret != WEBRTC_VIDEO_CODEC_OK) {
487 return ret;
488 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000489 }
490 }
491
492 return WEBRTC_VIDEO_CODEC_OK;
493}
494
495int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
496 EncodedImageCallback* callback) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200497 RTC_DCHECK_RUN_ON(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000498 encoded_complete_callback_ = callback;
Erik Språngf4e0c292019-10-01 18:50:03 +0200499 if (streaminfos_.size() == 1) {
500 streaminfos_[0].encoder->RegisterEncodeCompleteCallback(callback);
501 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000502 return WEBRTC_VIDEO_CODEC_OK;
503}
504
Erik Språng16cb8f52019-04-12 13:59:09 +0200505void SimulcastEncoderAdapter::SetRates(
506 const RateControlParameters& parameters) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200507 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700508
509 if (!Initialized()) {
Erik Språng16cb8f52019-04-12 13:59:09 +0200510 RTC_LOG(LS_WARNING) << "SetRates while not initialized";
511 return;
brandtr5e171752017-05-23 03:32:16 -0700512 }
sprang647bf432016-11-10 06:46:20 -0800513
Erik Språng16cb8f52019-04-12 13:59:09 +0200514 if (parameters.framerate_fps < 1.0) {
515 RTC_LOG(LS_WARNING) << "Invalid framerate: " << parameters.framerate_fps;
516 return;
brandtr5e171752017-05-23 03:32:16 -0700517 }
Erik Språng08127a92016-11-16 16:41:30 +0100518
Erik Språng16cb8f52019-04-12 13:59:09 +0200519 codec_.maxFramerate = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000520
Erik Språngf4e0c292019-10-01 18:50:03 +0200521 if (streaminfos_.size() == 1) {
522 // Not doing simulcast.
523 streaminfos_[0].encoder->SetRates(parameters);
524 return;
525 }
526
sprang1369c832016-11-10 08:30:33 -0800527 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Erik Språng08127a92016-11-16 16:41:30 +0100528 uint32_t stream_bitrate_kbps =
Erik Språng16cb8f52019-04-12 13:59:09 +0200529 parameters.bitrate.GetSpatialLayerSum(stream_idx) / 1000;
Erik Språng08127a92016-11-16 16:41:30 +0100530
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000531 // Need a key frame if we have not sent this stream before.
Erik Språng78ce6192016-09-12 16:04:43 +0200532 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000533 streaminfos_[stream_idx].key_frame_request = true;
534 }
Erik Språng78ce6192016-09-12 16:04:43 +0200535 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000536
Erik Språng08127a92016-11-16 16:41:30 +0100537 // Slice the temporal layers out of the full allocation and pass it on to
538 // the encoder handling the current simulcast stream.
Erik Språng16cb8f52019-04-12 13:59:09 +0200539 RateControlParameters stream_parameters = parameters;
540 stream_parameters.bitrate = VideoBitrateAllocation();
brandtr5e171752017-05-23 03:32:16 -0700541 for (int i = 0; i < kMaxTemporalStreams; ++i) {
Erik Språng16cb8f52019-04-12 13:59:09 +0200542 if (parameters.bitrate.HasBitrate(stream_idx, i)) {
543 stream_parameters.bitrate.SetBitrate(
544 0, i, parameters.bitrate.GetBitrate(stream_idx, i));
erikvarga@webrtc.org01f2ec32017-11-15 14:58:23 +0100545 }
brandtr5e171752017-05-23 03:32:16 -0700546 }
Minyue Li7ddef1a2019-04-11 10:50:19 +0000547
Erik Språng16cb8f52019-04-12 13:59:09 +0200548 // Assign link allocation proportionally to spatial layer allocation.
549 if (parameters.bandwidth_allocation != DataRate::Zero()) {
550 stream_parameters.bandwidth_allocation =
551 DataRate::bps((parameters.bandwidth_allocation.bps() *
552 stream_parameters.bitrate.get_sum_bps()) /
553 parameters.bitrate.get_sum_bps());
554 // Make sure we don't allocate bandwidth lower than target bitrate.
555 if (stream_parameters.bandwidth_allocation.bps() <
556 stream_parameters.bitrate.get_sum_bps()) {
557 stream_parameters.bandwidth_allocation =
558 DataRate::bps(stream_parameters.bitrate.get_sum_bps());
559 }
560 }
561
562 streaminfos_[stream_idx].encoder->SetRates(stream_parameters);
563 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000564}
565
Elad Alon65764e42019-06-28 18:43:44 +0200566void SimulcastEncoderAdapter::OnPacketLossRateUpdate(float packet_loss_rate) {
567 for (StreamInfo& info : streaminfos_) {
568 info.encoder->OnPacketLossRateUpdate(packet_loss_rate);
569 }
570}
571
572void SimulcastEncoderAdapter::OnRttUpdate(int64_t rtt_ms) {
573 for (StreamInfo& info : streaminfos_) {
574 info.encoder->OnRttUpdate(rtt_ms);
575 }
576}
577
578void SimulcastEncoderAdapter::OnLossNotification(
579 const LossNotification& loss_notification) {
580 for (StreamInfo& info : streaminfos_) {
581 info.encoder->OnLossNotification(loss_notification);
582 }
583}
584
brandtr5e171752017-05-23 03:32:16 -0700585// TODO(brandtr): Add task checker to this member function, when all encoder
586// callbacks are coming in on the encoder queue.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700587EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
Noah Richards41ee1ea2015-04-15 09:24:26 -0700588 size_t stream_idx,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000589 const EncodedImage& encodedImage,
590 const CodecSpecificInfo* codecSpecificInfo,
591 const RTPFragmentationHeader* fragmentation) {
Niels Möllerd3b8c632018-08-27 15:33:42 +0200592 EncodedImage stream_image(encodedImage);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000593 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200594
595 stream_image.SetSpatialIndex(stream_idx);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000596
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700597 return encoded_complete_callback_->OnEncodedImage(
Niels Möllerd3b8c632018-08-27 15:33:42 +0200598 stream_image, &stream_codec_specific, fragmentation);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000599}
600
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000601void SimulcastEncoderAdapter::PopulateStreamCodec(
brandtr5e171752017-05-23 03:32:16 -0700602 const webrtc::VideoCodec& inst,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000603 int stream_index,
Erik Språng78ce6192016-09-12 16:04:43 +0200604 uint32_t start_bitrate_kbps,
Florent Castelli1b761ca2019-01-21 14:33:02 +0100605 StreamResolution stream_resolution,
Erik Språng78ce6192016-09-12 16:04:43 +0200606 webrtc::VideoCodec* stream_codec) {
brandtr5e171752017-05-23 03:32:16 -0700607 *stream_codec = inst;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000608
609 // Stream specific settings.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000610 stream_codec->numberOfSimulcastStreams = 0;
brandtr5e171752017-05-23 03:32:16 -0700611 stream_codec->width = inst.simulcastStream[stream_index].width;
612 stream_codec->height = inst.simulcastStream[stream_index].height;
613 stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
614 stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
615 stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000616 // Settings that are based on stream/resolution.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100617 if (stream_resolution == StreamResolution::LOWEST) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000618 // Settings for lowest spatial resolutions.
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +0200619 if (inst.mode == VideoCodecMode::kScreensharing) {
620 if (experimental_boosted_screenshare_qp_) {
621 stream_codec->qpMax = *experimental_boosted_screenshare_qp_;
622 }
Erik Språng7f24fb92019-02-13 10:49:37 +0100623 } else if (boost_base_layer_quality_) {
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +0200624 stream_codec->qpMax = kLowestResMaxQp;
625 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000626 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200627 if (inst.codecType == webrtc::kVideoCodecVP8) {
628 stream_codec->VP8()->numberOfTemporalLayers =
629 inst.simulcastStream[stream_index].numberOfTemporalLayers;
Florent Castelli1b761ca2019-01-21 14:33:02 +0100630 if (stream_resolution != StreamResolution::HIGHEST) {
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200631 // For resolutions below CIF, set the codec |complexity| parameter to
632 // kComplexityHigher, which maps to cpu_used = -4.
633 int pixels_per_frame = stream_codec->width * stream_codec->height;
634 if (pixels_per_frame < 352 * 288) {
635 stream_codec->VP8()->complexity =
636 webrtc::VideoCodecComplexity::kComplexityHigher;
637 }
638 // Turn off denoising for all streams but the highest resolution.
639 stream_codec->VP8()->denoisingOn = false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000640 }
Johnny Leec5385062019-06-19 14:13:32 -0400641 } else if (inst.codecType == webrtc::kVideoCodecH264) {
642 stream_codec->H264()->numberOfTemporalLayers =
643 inst.simulcastStream[stream_index].numberOfTemporalLayers;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000644 }
645 // TODO(ronghuawu): what to do with targetBitrate.
646
Erik Språng78ce6192016-09-12 16:04:43 +0200647 stream_codec->startBitrate = start_bitrate_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000648}
649
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000650bool SimulcastEncoderAdapter::Initialized() const {
brandtr5e171752017-05-23 03:32:16 -0700651 return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
652}
653
654void SimulcastEncoderAdapter::DestroyStoredEncoders() {
655 while (!stored_encoders_.empty()) {
brandtr5e171752017-05-23 03:32:16 -0700656 stored_encoders_.pop();
657 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000658}
659
Erik Språng9b5b0702018-11-01 14:52:30 +0100660VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
Erik Språng75de46a2018-11-07 14:53:32 +0100661 return encoder_info_;
pbosecd21b42016-01-07 08:03:05 -0800662}
663
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000664} // namespace webrtc