blob: 09b05456c3ded6746c86050ed345115cdf20e2ec [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>
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000015#include <algorithm>
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <cstdint>
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020017#include <string>
18#include <utility>
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000019
Mirko Bonadeid9708072019-01-25 20:26:48 +010020#include "api/scoped_refptr.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010022#include "api/video/video_codec_constants.h"
Yves Gerey3e707812018-11-28 16:47:49 +010023#include "api/video/video_frame_buffer.h"
24#include "api/video/video_rotation.h"
Magnus Jedvertdf4883d2017-11-17 14:44:55 +010025#include "api/video_codecs/video_encoder_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010026#include "modules/video_coding/include/video_error_codes.h"
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +020027#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/checks.h"
Erik Språng7f24fb92019-02-13 10:49:37 +010030#include "rtc_base/experiments/rate_control_settings.h"
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020031#include "system_wrappers/include/field_trial.h"
Mirko Bonadei65432062017-12-11 09:32:13 +010032#include "third_party/libyuv/include/libyuv/scale.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000033
34namespace {
35
36const unsigned int kDefaultMinQp = 2;
37const unsigned int kDefaultMaxQp = 56;
38// Max qp for lowest spatial resolution when doing simulcast.
39const unsigned int kLowestResMaxQp = 45;
40
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020041absl::optional<unsigned int> GetScreenshareBoostedQpValue() {
42 std::string experiment_group =
43 webrtc::field_trial::FindFullName("WebRTC-BoostedScreenshareQp");
44 unsigned int qp;
45 if (sscanf(experiment_group.c_str(), "%u", &qp) != 1)
46 return absl::nullopt;
47 qp = std::min(qp, 63u);
48 qp = std::max(qp, 1u);
49 return qp;
50}
51
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000052uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
53 uint32_t bitrate_sum = 0;
54 for (int i = 0; i < streams; ++i) {
55 bitrate_sum += codec.simulcastStream[i].maxBitrate;
56 }
57 return bitrate_sum;
58}
59
60int NumberOfStreams(const webrtc::VideoCodec& codec) {
61 int streams =
62 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
63 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
64 if (simulcast_max_bitrate == 0) {
65 streams = 1;
66 }
67 return streams;
68}
69
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000070int VerifyCodec(const webrtc::VideoCodec* inst) {
brandtr5e171752017-05-23 03:32:16 -070071 if (inst == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000072 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
73 }
74 if (inst->maxFramerate < 1) {
75 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
76 }
77 // allow zero to represent an unspecified maxBitRate
78 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
79 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
80 }
81 if (inst->width <= 1 || inst->height <= 1) {
82 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
83 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +020084 if (inst->codecType == webrtc::kVideoCodecVP8 &&
85 inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000086 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
87 }
88 return WEBRTC_VIDEO_CODEC_OK;
89}
90
Florent Castelli1b761ca2019-01-21 14:33:02 +010091bool StreamResolutionCompare(const webrtc::SimulcastStream& a,
92 const webrtc::SimulcastStream& b) {
93 return std::tie(a.height, a.width, a.maxBitrate, a.maxFramerate) <
94 std::tie(b.height, b.width, b.maxBitrate, b.maxFramerate);
95}
96
Noah Richards41ee1ea2015-04-15 09:24:26 -070097// An EncodedImageCallback implementation that forwards on calls to a
98// SimulcastEncoderAdapter, but with the stream index it's registered with as
99// the first parameter to Encoded.
100class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
101 public:
102 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
103 size_t stream_idx)
104 : adapter_(adapter), stream_idx_(stream_idx) {}
105
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700106 EncodedImageCallback::Result OnEncodedImage(
107 const webrtc::EncodedImage& encoded_image,
108 const webrtc::CodecSpecificInfo* codec_specific_info,
109 const webrtc::RTPFragmentationHeader* fragmentation) override {
110 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
111 codec_specific_info, fragmentation);
Noah Richards41ee1ea2015-04-15 09:24:26 -0700112 }
113
114 private:
115 webrtc::SimulcastEncoderAdapter* const adapter_;
116 const size_t stream_idx_;
117};
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000118} // namespace
119
120namespace webrtc {
121
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200122SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory,
123 const SdpVideoFormat& format)
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100124 : inited_(0),
125 factory_(factory),
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200126 video_format_(format),
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100127 encoded_complete_callback_(nullptr),
Erik Språng7f24fb92019-02-13 10:49:37 +0100128 experimental_boosted_screenshare_qp_(GetScreenshareBoostedQpValue()),
129 boost_base_layer_quality_(RateControlSettings::ParseFromFieldTrials()
130 .Vp8BoostBaseLayerQuality()) {
Rasmus Brandtc334ce92018-02-05 13:03:25 +0100131 RTC_DCHECK(factory_);
Erik Språng75de46a2018-11-07 14:53:32 +0100132 encoder_info_.implementation_name = "SimulcastEncoderAdapter";
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100133
brandtr5e171752017-05-23 03:32:16 -0700134 // The adapter is typically created on the worker thread, but operated on
135 // the encoder task queue.
136 encoder_queue_.Detach();
137
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000138 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
139}
140
141SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
brandtr5e171752017-05-23 03:32:16 -0700142 RTC_DCHECK(!Initialized());
143 DestroyStoredEncoders();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000144}
145
146int SimulcastEncoderAdapter::Release() {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200147 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700148
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000149 while (!streaminfos_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700150 std::unique_ptr<VideoEncoder> encoder =
151 std::move(streaminfos_.back().encoder);
brandtr5e171752017-05-23 03:32:16 -0700152 // Even though it seems very unlikely, there are no guarantees that the
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200153 // encoder will not call back after being Release()'d. Therefore, we first
154 // disable the callbacks here.
brandtr5e171752017-05-23 03:32:16 -0700155 encoder->RegisterEncodeCompleteCallback(nullptr);
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200156 encoder->Release();
brandtr5e171752017-05-23 03:32:16 -0700157 streaminfos_.pop_back(); // Deletes callback adapter.
magjed3f897582017-08-28 08:05:42 -0700158 stored_encoders_.push(std::move(encoder));
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000159 }
brandtr5e171752017-05-23 03:32:16 -0700160
161 // It's legal to move the encoder to another queue now.
162 encoder_queue_.Detach();
163
164 rtc::AtomicOps::ReleaseStore(&inited_, 0);
165
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000166 return WEBRTC_VIDEO_CODEC_OK;
167}
168
169int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
170 int number_of_cores,
171 size_t max_payload_size) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200172 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700173
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000174 if (number_of_cores < 1) {
175 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
176 }
177
178 int ret = VerifyCodec(inst);
179 if (ret < 0) {
180 return ret;
181 }
182
183 ret = Release();
184 if (ret < 0) {
185 return ret;
186 }
187
188 int number_of_streams = NumberOfStreams(*inst);
brandtr5e171752017-05-23 03:32:16 -0700189 RTC_DCHECK_LE(number_of_streams, kMaxSimulcastStreams);
Peter Boströmd53c3892016-03-30 17:03:52 +0200190 const bool doing_simulcast = (number_of_streams > 1);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000191
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000192 codec_ = *inst;
Erik Språng82fad3d2018-03-21 09:57:23 +0100193 SimulcastRateAllocator rate_allocator(codec_);
Erik Språng566124a2018-04-23 12:32:22 +0200194 VideoBitrateAllocation allocation = rate_allocator.GetAllocation(
Erik Språng08127a92016-11-16 16:41:30 +0100195 codec_.startBitrate * 1000, codec_.maxFramerate);
196 std::vector<uint32_t> start_bitrates;
197 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
198 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
199 start_bitrates.push_back(stream_bitrate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000200 }
201
Erik Språng75de46a2018-11-07 14:53:32 +0100202 encoder_info_.supports_native_handle = true;
203 encoder_info_.scaling_settings.thresholds = absl::nullopt;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000204 // Create |number_of_streams| of encoder instances and init them.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100205
206 const auto minmax = std::minmax_element(
207 std::begin(codec_.simulcastStream),
208 std::begin(codec_.simulcastStream) + number_of_streams,
209 StreamResolutionCompare);
210 const auto lowest_resolution_stream_index =
211 std::distance(std::begin(codec_.simulcastStream), minmax.first);
212 const auto highest_resolution_stream_index =
213 std::distance(std::begin(codec_.simulcastStream), minmax.second);
214
215 RTC_DCHECK_LT(lowest_resolution_stream_index, number_of_streams);
216 RTC_DCHECK_LT(highest_resolution_stream_index, number_of_streams);
217
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000218 for (int i = 0; i < number_of_streams; ++i) {
219 VideoCodec stream_codec;
Erik Språng78ce6192016-09-12 16:04:43 +0200220 uint32_t start_bitrate_kbps = start_bitrates[i];
Erik Språng7d687b12018-09-12 17:04:10 +0200221 const bool send_stream = start_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000222 if (!doing_simulcast) {
223 stream_codec = codec_;
224 stream_codec.numberOfSimulcastStreams = 1;
Erik Språng75de46a2018-11-07 14:53:32 +0100225
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000226 } else {
Erik Språng78ce6192016-09-12 16:04:43 +0200227 // Cap start bitrate to the min bitrate in order to avoid strange codec
Erik Språng7d687b12018-09-12 17:04:10 +0200228 // behavior. Since sending will be false, this should not matter.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100229 StreamResolution stream_resolution =
230 i == highest_resolution_stream_index
231 ? StreamResolution::HIGHEST
232 : i == lowest_resolution_stream_index ? StreamResolution::LOWEST
233 : StreamResolution::OTHER;
234
Erik Språng78ce6192016-09-12 16:04:43 +0200235 start_bitrate_kbps =
236 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
Florent Castelli1b761ca2019-01-21 14:33:02 +0100237 PopulateStreamCodec(codec_, i, start_bitrate_kbps, stream_resolution,
238 &stream_codec);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000239 }
240
Erik Språngcc681cc2018-03-14 17:52:55 +0100241 // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000242 if (stream_codec.qpMax < kDefaultMinQp) {
243 stream_codec.qpMax = kDefaultMaxQp;
244 }
245
brandtr5e171752017-05-23 03:32:16 -0700246 // If an existing encoder instance exists, reuse it.
247 // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
248 // when we start storing that state outside the encoder wrappers.
magjed3f897582017-08-28 08:05:42 -0700249 std::unique_ptr<VideoEncoder> encoder;
brandtr5e171752017-05-23 03:32:16 -0700250 if (!stored_encoders_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700251 encoder = std::move(stored_encoders_.top());
brandtr5e171752017-05-23 03:32:16 -0700252 stored_encoders_.pop();
253 } else {
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200254 encoder = factory_->CreateVideoEncoder(SdpVideoFormat(
255 codec_.codecType == webrtc::kVideoCodecVP8 ? "VP8" : "H264"));
brandtr5e171752017-05-23 03:32:16 -0700256 }
257
philipelcce46fc2015-12-21 03:04:49 -0800258 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000259 if (ret < 0) {
noahrice5ba75a2016-12-12 13:08:27 -0800260 // Explicitly destroy the current encoder; because we haven't registered a
261 // StreamInfo for it yet, Release won't do anything about it.
magjed3f897582017-08-28 08:05:42 -0700262 encoder.reset();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000263 Release();
264 return ret;
265 }
Erik Språngd3438aa2018-11-08 16:56:43 +0100266
brandtr5e171752017-05-23 03:32:16 -0700267 std::unique_ptr<EncodedImageCallback> callback(
268 new AdapterEncodedImageCallback(this, i));
269 encoder->RegisterEncodeCompleteCallback(callback.get());
magjed3f897582017-08-28 08:05:42 -0700270 streaminfos_.emplace_back(std::move(encoder), std::move(callback),
271 stream_codec.width, stream_codec.height,
Erik Språng7d687b12018-09-12 17:04:10 +0200272 send_stream);
brandtr5e171752017-05-23 03:32:16 -0700273
Erik Språng75de46a2018-11-07 14:53:32 +0100274 if (!doing_simulcast) {
275 // Without simulcast, just pass through the encoder info from the one
276 // active encoder.
277 encoder_info_ = streaminfos_[0].encoder->GetEncoderInfo();
278 } else {
279 const EncoderInfo encoder_impl_info =
280 streaminfos_[i].encoder->GetEncoderInfo();
281
282 if (i == 0) {
283 // Quality scaling not enabled for simulcast.
284 encoder_info_.scaling_settings = VideoEncoder::ScalingSettings::kOff;
285
286 // Encoder name indicates names of all sub-encoders.
287 encoder_info_.implementation_name = "SimulcastEncoderAdapter (";
288 encoder_info_.implementation_name +=
289 encoder_impl_info.implementation_name;
290
291 encoder_info_.supports_native_handle =
292 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100293 encoder_info_.has_trusted_rate_controller =
294 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100295 encoder_info_.is_hardware_accelerated =
296 encoder_impl_info.is_hardware_accelerated;
297 encoder_info_.has_internal_source =
298 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100299 } else {
300 encoder_info_.implementation_name += ", ";
301 encoder_info_.implementation_name +=
302 encoder_impl_info.implementation_name;
303
304 // Native handle supported only if all encoders supports it.
305 encoder_info_.supports_native_handle &=
306 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100307
308 // Trusted rate controller only if all encoders have it.
309 encoder_info_.has_trusted_rate_controller &=
310 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100311
312 // Uses hardware support if any of the encoders uses it.
313 // For example, if we are having issues with down-scaling due to
314 // pipelining delay in HW encoders we need higher encoder usage
315 // thresholds in CPU adaptation.
316 encoder_info_.is_hardware_accelerated |=
317 encoder_impl_info.is_hardware_accelerated;
318
319 // Has internal source only if all encoders have it.
320 encoder_info_.has_internal_source &=
321 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100322 }
Erik Språngdbdd8392019-01-17 15:27:50 +0100323 encoder_info_.fps_allocation[i] = encoder_impl_info.fps_allocation[0];
brandtr5e171752017-05-23 03:32:16 -0700324 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000325 }
brandtr5e171752017-05-23 03:32:16 -0700326
Peter Boströmd53c3892016-03-30 17:03:52 +0200327 if (doing_simulcast) {
Erik Språng75de46a2018-11-07 14:53:32 +0100328 encoder_info_.implementation_name += ")";
Peter Boströmd53c3892016-03-30 17:03:52 +0200329 }
brandtr5e171752017-05-23 03:32:16 -0700330
331 // To save memory, don't store encoders that we don't use.
332 DestroyStoredEncoders();
333
334 rtc::AtomicOps::ReleaseStore(&inited_, 1);
335
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000336 return WEBRTC_VIDEO_CODEC_OK;
337}
338
339int SimulcastEncoderAdapter::Encode(
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700340 const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100341 const std::vector<VideoFrameType>* frame_types) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200342 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700343
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000344 if (!Initialized()) {
345 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
346 }
brandtr5e171752017-05-23 03:32:16 -0700347 if (encoded_complete_callback_ == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000348 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
349 }
350
351 // All active streams should generate a key frame if
352 // a key frame is requested by any stream.
353 bool send_key_frame = false;
354 if (frame_types) {
355 for (size_t i = 0; i < frame_types->size(); ++i) {
Niels Möller8f7ce222019-03-21 15:43:58 +0100356 if (frame_types->at(i) == VideoFrameType::kVideoFrameKey) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000357 send_key_frame = true;
358 break;
359 }
360 }
361 }
362 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
363 if (streaminfos_[stream_idx].key_frame_request &&
364 streaminfos_[stream_idx].send_stream) {
365 send_key_frame = true;
366 break;
367 }
368 }
369
370 int src_width = input_image.width();
371 int src_height = input_image.height();
372 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200373 // Don't encode frames in resolutions that we don't intend to send.
brandtr5e171752017-05-23 03:32:16 -0700374 if (!streaminfos_[stream_idx].send_stream) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200375 continue;
brandtr5e171752017-05-23 03:32:16 -0700376 }
Peter Boström5d0379d2015-10-06 14:04:51 +0200377
Niels Möller87e2d782019-03-07 10:18:23 +0100378 std::vector<VideoFrameType> stream_frame_types;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000379 if (send_key_frame) {
Niels Möller8f7ce222019-03-21 15:43:58 +0100380 stream_frame_types.push_back(VideoFrameType::kVideoFrameKey);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000381 streaminfos_[stream_idx].key_frame_request = false;
382 } else {
Niels Möller8f7ce222019-03-21 15:43:58 +0100383 stream_frame_types.push_back(VideoFrameType::kVideoFrameDelta);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000384 }
385
386 int dst_width = streaminfos_[stream_idx].width;
387 int dst_height = streaminfos_[stream_idx].height;
388 // If scaling isn't required, because the input resolution
389 // matches the destination or the input image is empty (e.g.
390 // a keyframe request for encoders with internal camera
noahricfe3654d2016-07-01 09:05:54 -0700391 // sources) or the source image has a native handle, pass the image on
392 // directly. Otherwise, we'll scale it to match what the encoder expects
393 // (below).
394 // For texture frames, the underlying encoder is expected to be able to
395 // correctly sample/scale the source texture.
396 // TODO(perkj): ensure that works going forward, and figure out how this
397 // affects webrtc:5683.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000398 if ((dst_width == src_width && dst_height == src_height) ||
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000399 input_image.video_frame_buffer()->type() ==
400 VideoFrameBuffer::Type::kNative) {
Niels Möllerc8d2e732019-03-06 12:00:33 +0100401 int ret = streaminfos_[stream_idx].encoder->Encode(input_image,
402 &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700403 if (ret != WEBRTC_VIDEO_CODEC_OK) {
404 return ret;
405 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000406 } else {
nisse64ec8f82016-09-27 00:17:25 -0700407 rtc::scoped_refptr<I420Buffer> dst_buffer =
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000408 I420Buffer::Create(dst_width, dst_height);
409 rtc::scoped_refptr<I420BufferInterface> src_buffer =
410 input_image.video_frame_buffer()->ToI420();
411 libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
412 src_buffer->DataU(), src_buffer->StrideU(),
413 src_buffer->DataV(), src_buffer->StrideV(), src_width,
414 src_height, dst_buffer->MutableDataY(),
415 dst_buffer->StrideY(), dst_buffer->MutableDataU(),
416 dst_buffer->StrideU(), dst_buffer->MutableDataV(),
417 dst_buffer->StrideV(), dst_width, dst_height,
nissec9c142f2016-05-17 04:05:47 -0700418 libyuv::kFilterBilinear);
nisse64ec8f82016-09-27 00:17:25 -0700419
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100420 // UpdateRect is not propagated to lower simulcast layers currently.
421 // TODO(ilnik): Consider scaling UpdateRect together with the buffer.
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100422 VideoFrame frame = VideoFrame::Builder()
423 .set_video_frame_buffer(dst_buffer)
424 .set_timestamp_rtp(input_image.timestamp())
425 .set_rotation(webrtc::kVideoRotation_0)
426 .set_timestamp_ms(input_image.render_time_ms())
427 .build();
Niels Möllerc8d2e732019-03-06 12:00:33 +0100428 int ret =
429 streaminfos_[stream_idx].encoder->Encode(frame, &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700430 if (ret != WEBRTC_VIDEO_CODEC_OK) {
431 return ret;
432 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000433 }
434 }
435
436 return WEBRTC_VIDEO_CODEC_OK;
437}
438
439int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
440 EncodedImageCallback* callback) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200441 RTC_DCHECK_RUN_ON(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000442 encoded_complete_callback_ = callback;
443 return WEBRTC_VIDEO_CODEC_OK;
444}
445
Minyue Li7ddef1a2019-04-11 10:50:19 +0000446int SimulcastEncoderAdapter::SetRateAllocation(
447 const VideoBitrateAllocation& bitrate,
448 uint32_t new_framerate) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200449 RTC_DCHECK_RUN_ON(&encoder_queue_);
brandtr5e171752017-05-23 03:32:16 -0700450
451 if (!Initialized()) {
Minyue Li7ddef1a2019-04-11 10:50:19 +0000452 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
brandtr5e171752017-05-23 03:32:16 -0700453 }
sprang647bf432016-11-10 06:46:20 -0800454
Minyue Li7ddef1a2019-04-11 10:50:19 +0000455 if (new_framerate < 1) {
456 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700457 }
Erik Språng08127a92016-11-16 16:41:30 +0100458
Minyue Li7ddef1a2019-04-11 10:50:19 +0000459 if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) {
460 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700461 }
Erik Språng08127a92016-11-16 16:41:30 +0100462
Minyue Li7ddef1a2019-04-11 10:50:19 +0000463 if (bitrate.get_sum_bps() > 0) {
sprang1369c832016-11-10 08:30:33 -0800464 // Make sure the bitrate fits the configured min bitrates. 0 is a special
465 // value that means paused, though, so leave it alone.
Minyue Li7ddef1a2019-04-11 10:50:19 +0000466 if (bitrate.get_sum_kbps() < codec_.minBitrate) {
467 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700468 }
Erik Språng08127a92016-11-16 16:41:30 +0100469
sprang1369c832016-11-10 08:30:33 -0800470 if (codec_.numberOfSimulcastStreams > 0 &&
Minyue Li7ddef1a2019-04-11 10:50:19 +0000471 bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
472 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
sprang1369c832016-11-10 08:30:33 -0800473 }
sprang1369c832016-11-10 08:30:33 -0800474 }
Erik Språng08127a92016-11-16 16:41:30 +0100475
Minyue Li7ddef1a2019-04-11 10:50:19 +0000476 codec_.maxFramerate = new_framerate;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000477
sprang1369c832016-11-10 08:30:33 -0800478 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Erik Språng08127a92016-11-16 16:41:30 +0100479 uint32_t stream_bitrate_kbps =
Minyue Li7ddef1a2019-04-11 10:50:19 +0000480 bitrate.GetSpatialLayerSum(stream_idx) / 1000;
Erik Språng08127a92016-11-16 16:41:30 +0100481
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000482 // Need a key frame if we have not sent this stream before.
Erik Språng78ce6192016-09-12 16:04:43 +0200483 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000484 streaminfos_[stream_idx].key_frame_request = true;
485 }
Erik Språng78ce6192016-09-12 16:04:43 +0200486 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000487
Erik Språng08127a92016-11-16 16:41:30 +0100488 // Slice the temporal layers out of the full allocation and pass it on to
489 // the encoder handling the current simulcast stream.
Minyue Li7ddef1a2019-04-11 10:50:19 +0000490 VideoBitrateAllocation stream_allocation;
brandtr5e171752017-05-23 03:32:16 -0700491 for (int i = 0; i < kMaxTemporalStreams; ++i) {
Minyue Li7ddef1a2019-04-11 10:50:19 +0000492 if (bitrate.HasBitrate(stream_idx, i)) {
493 stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
erikvarga@webrtc.org01f2ec32017-11-15 14:58:23 +0100494 }
brandtr5e171752017-05-23 03:32:16 -0700495 }
Minyue Li7ddef1a2019-04-11 10:50:19 +0000496 streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
497 new_framerate);
Erik Språng7ac0d5f2019-04-11 09:06:13 +0200498 }
Minyue Li7ddef1a2019-04-11 10:50:19 +0000499
500 return WEBRTC_VIDEO_CODEC_OK;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000501}
502
brandtr5e171752017-05-23 03:32:16 -0700503// TODO(brandtr): Add task checker to this member function, when all encoder
504// callbacks are coming in on the encoder queue.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700505EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
Noah Richards41ee1ea2015-04-15 09:24:26 -0700506 size_t stream_idx,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000507 const EncodedImage& encodedImage,
508 const CodecSpecificInfo* codecSpecificInfo,
509 const RTPFragmentationHeader* fragmentation) {
Niels Möllerd3b8c632018-08-27 15:33:42 +0200510 EncodedImage stream_image(encodedImage);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000511 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200512
513 stream_image.SetSpatialIndex(stream_idx);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000514
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700515 return encoded_complete_callback_->OnEncodedImage(
Niels Möllerd3b8c632018-08-27 15:33:42 +0200516 stream_image, &stream_codec_specific, fragmentation);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000517}
518
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000519void SimulcastEncoderAdapter::PopulateStreamCodec(
brandtr5e171752017-05-23 03:32:16 -0700520 const webrtc::VideoCodec& inst,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000521 int stream_index,
Erik Språng78ce6192016-09-12 16:04:43 +0200522 uint32_t start_bitrate_kbps,
Florent Castelli1b761ca2019-01-21 14:33:02 +0100523 StreamResolution stream_resolution,
Erik Språng78ce6192016-09-12 16:04:43 +0200524 webrtc::VideoCodec* stream_codec) {
brandtr5e171752017-05-23 03:32:16 -0700525 *stream_codec = inst;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000526
527 // Stream specific settings.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000528 stream_codec->numberOfSimulcastStreams = 0;
brandtr5e171752017-05-23 03:32:16 -0700529 stream_codec->width = inst.simulcastStream[stream_index].width;
530 stream_codec->height = inst.simulcastStream[stream_index].height;
531 stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
532 stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
533 stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000534 // Settings that are based on stream/resolution.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100535 if (stream_resolution == StreamResolution::LOWEST) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000536 // Settings for lowest spatial resolutions.
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +0200537 if (inst.mode == VideoCodecMode::kScreensharing) {
538 if (experimental_boosted_screenshare_qp_) {
539 stream_codec->qpMax = *experimental_boosted_screenshare_qp_;
540 }
Erik Språng7f24fb92019-02-13 10:49:37 +0100541 } else if (boost_base_layer_quality_) {
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +0200542 stream_codec->qpMax = kLowestResMaxQp;
543 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000544 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200545 if (inst.codecType == webrtc::kVideoCodecVP8) {
546 stream_codec->VP8()->numberOfTemporalLayers =
547 inst.simulcastStream[stream_index].numberOfTemporalLayers;
Florent Castelli1b761ca2019-01-21 14:33:02 +0100548 if (stream_resolution != StreamResolution::HIGHEST) {
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200549 // For resolutions below CIF, set the codec |complexity| parameter to
550 // kComplexityHigher, which maps to cpu_used = -4.
551 int pixels_per_frame = stream_codec->width * stream_codec->height;
552 if (pixels_per_frame < 352 * 288) {
553 stream_codec->VP8()->complexity =
554 webrtc::VideoCodecComplexity::kComplexityHigher;
555 }
556 // Turn off denoising for all streams but the highest resolution.
557 stream_codec->VP8()->denoisingOn = false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000558 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000559 }
560 // TODO(ronghuawu): what to do with targetBitrate.
561
Erik Språng78ce6192016-09-12 16:04:43 +0200562 stream_codec->startBitrate = start_bitrate_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000563}
564
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000565bool SimulcastEncoderAdapter::Initialized() const {
brandtr5e171752017-05-23 03:32:16 -0700566 return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
567}
568
569void SimulcastEncoderAdapter::DestroyStoredEncoders() {
570 while (!stored_encoders_.empty()) {
brandtr5e171752017-05-23 03:32:16 -0700571 stored_encoders_.pop();
572 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000573}
574
Erik Språng9b5b0702018-11-01 14:52:30 +0100575VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
Erik Språng75de46a2018-11-07 14:53:32 +0100576 return encoder_info_;
pbosecd21b42016-01-07 08:03:05 -0800577}
578
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000579} // namespace webrtc