blob: 563ca4553292317848107eb9b6b4fc98453b734d [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 Bonadei92ea95e2017-09-15 06:47:31 +020020#include "api/video/i420_buffer.h"
Erik Språng7fd0a282018-05-22 15:37:23 +020021#include "api/video/video_bitrate_allocation.h"
Yves Gerey3e707812018-11-28 16:47:49 +010022#include "api/video/video_frame_buffer.h"
23#include "api/video/video_rotation.h"
Magnus Jedvertdf4883d2017-11-17 14:44:55 +010024#include "api/video_codecs/video_encoder_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010025#include "modules/video_coding/include/video_error_codes.h"
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +020026#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Yves Gerey3e707812018-11-28 16:47:49 +010027#include "rtc_base/atomicops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/checks.h"
Yves Gerey3e707812018-11-28 16:47:49 +010029#include "rtc_base/scoped_ref_ptr.h"
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020030#include "system_wrappers/include/field_trial.h"
Mirko Bonadei65432062017-12-11 09:32:13 +010031#include "third_party/libyuv/include/libyuv/scale.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000032
33namespace {
34
35const unsigned int kDefaultMinQp = 2;
36const unsigned int kDefaultMaxQp = 56;
37// Max qp for lowest spatial resolution when doing simulcast.
38const unsigned int kLowestResMaxQp = 45;
39
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +020040absl::optional<unsigned int> GetScreenshareBoostedQpValue() {
41 std::string experiment_group =
42 webrtc::field_trial::FindFullName("WebRTC-BoostedScreenshareQp");
43 unsigned int qp;
44 if (sscanf(experiment_group.c_str(), "%u", &qp) != 1)
45 return absl::nullopt;
46 qp = std::min(qp, 63u);
47 qp = std::max(qp, 1u);
48 return qp;
49}
50
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000051uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
52 uint32_t bitrate_sum = 0;
53 for (int i = 0; i < streams; ++i) {
54 bitrate_sum += codec.simulcastStream[i].maxBitrate;
55 }
56 return bitrate_sum;
57}
58
59int NumberOfStreams(const webrtc::VideoCodec& codec) {
60 int streams =
61 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
62 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
63 if (simulcast_max_bitrate == 0) {
64 streams = 1;
65 }
66 return streams;
67}
68
69bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec,
70 int num_streams) {
71 if (codec.width != codec.simulcastStream[num_streams - 1].width ||
72 codec.height != codec.simulcastStream[num_streams - 1].height) {
73 return false;
74 }
75 for (int i = 0; i < num_streams; ++i) {
76 if (codec.width * codec.simulcastStream[i].height !=
77 codec.height * codec.simulcastStream[i].width) {
78 return false;
79 }
80 }
81 return true;
82}
83
84int VerifyCodec(const webrtc::VideoCodec* inst) {
brandtr5e171752017-05-23 03:32:16 -070085 if (inst == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000086 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
87 }
88 if (inst->maxFramerate < 1) {
89 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
90 }
91 // allow zero to represent an unspecified maxBitRate
92 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
93 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
94 }
95 if (inst->width <= 1 || inst->height <= 1) {
96 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
97 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +020098 if (inst->codecType == webrtc::kVideoCodecVP8 &&
99 inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000100 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
101 }
102 return WEBRTC_VIDEO_CODEC_OK;
103}
104
Noah Richards41ee1ea2015-04-15 09:24:26 -0700105// An EncodedImageCallback implementation that forwards on calls to a
106// SimulcastEncoderAdapter, but with the stream index it's registered with as
107// the first parameter to Encoded.
108class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
109 public:
110 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
111 size_t stream_idx)
112 : adapter_(adapter), stream_idx_(stream_idx) {}
113
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700114 EncodedImageCallback::Result OnEncodedImage(
115 const webrtc::EncodedImage& encoded_image,
116 const webrtc::CodecSpecificInfo* codec_specific_info,
117 const webrtc::RTPFragmentationHeader* fragmentation) override {
118 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
119 codec_specific_info, fragmentation);
Noah Richards41ee1ea2015-04-15 09:24:26 -0700120 }
121
122 private:
123 webrtc::SimulcastEncoderAdapter* const adapter_;
124 const size_t stream_idx_;
125};
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000126} // namespace
127
128namespace webrtc {
129
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200130SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory,
131 const SdpVideoFormat& format)
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100132 : inited_(0),
133 factory_(factory),
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200134 video_format_(format),
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100135 encoded_complete_callback_(nullptr),
Oleh Prypina1d9ca42018-10-11 14:33:39 +0000136 experimental_boosted_screenshare_qp_(GetScreenshareBoostedQpValue()) {
Rasmus Brandtc334ce92018-02-05 13:03:25 +0100137 RTC_DCHECK(factory_);
Erik Språng75de46a2018-11-07 14:53:32 +0100138 encoder_info_.implementation_name = "SimulcastEncoderAdapter";
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100139
brandtr5e171752017-05-23 03:32:16 -0700140 // The adapter is typically created on the worker thread, but operated on
141 // the encoder task queue.
142 encoder_queue_.Detach();
143
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000144 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
145}
146
147SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
brandtr5e171752017-05-23 03:32:16 -0700148 RTC_DCHECK(!Initialized());
149 DestroyStoredEncoders();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000150}
151
152int SimulcastEncoderAdapter::Release() {
brandtr5e171752017-05-23 03:32:16 -0700153 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
154
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000155 while (!streaminfos_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700156 std::unique_ptr<VideoEncoder> encoder =
157 std::move(streaminfos_.back().encoder);
brandtr5e171752017-05-23 03:32:16 -0700158 // Even though it seems very unlikely, there are no guarantees that the
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200159 // encoder will not call back after being Release()'d. Therefore, we first
160 // disable the callbacks here.
brandtr5e171752017-05-23 03:32:16 -0700161 encoder->RegisterEncodeCompleteCallback(nullptr);
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200162 encoder->Release();
brandtr5e171752017-05-23 03:32:16 -0700163 streaminfos_.pop_back(); // Deletes callback adapter.
magjed3f897582017-08-28 08:05:42 -0700164 stored_encoders_.push(std::move(encoder));
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000165 }
brandtr5e171752017-05-23 03:32:16 -0700166
167 // It's legal to move the encoder to another queue now.
168 encoder_queue_.Detach();
169
170 rtc::AtomicOps::ReleaseStore(&inited_, 0);
171
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000172 return WEBRTC_VIDEO_CODEC_OK;
173}
174
175int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
176 int number_of_cores,
177 size_t max_payload_size) {
brandtr5e171752017-05-23 03:32:16 -0700178 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
179
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000180 if (number_of_cores < 1) {
181 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
182 }
183
184 int ret = VerifyCodec(inst);
185 if (ret < 0) {
186 return ret;
187 }
188
189 ret = Release();
190 if (ret < 0) {
191 return ret;
192 }
193
194 int number_of_streams = NumberOfStreams(*inst);
brandtr5e171752017-05-23 03:32:16 -0700195 RTC_DCHECK_LE(number_of_streams, kMaxSimulcastStreams);
Peter Boströmd53c3892016-03-30 17:03:52 +0200196 const bool doing_simulcast = (number_of_streams > 1);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000197
198 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
199 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
200 }
201
202 codec_ = *inst;
Erik Språng82fad3d2018-03-21 09:57:23 +0100203 SimulcastRateAllocator rate_allocator(codec_);
Erik Språng566124a2018-04-23 12:32:22 +0200204 VideoBitrateAllocation allocation = rate_allocator.GetAllocation(
Erik Språng08127a92016-11-16 16:41:30 +0100205 codec_.startBitrate * 1000, codec_.maxFramerate);
206 std::vector<uint32_t> start_bitrates;
207 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
208 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
209 start_bitrates.push_back(stream_bitrate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000210 }
211
Erik Språng75de46a2018-11-07 14:53:32 +0100212 encoder_info_.supports_native_handle = true;
213 encoder_info_.scaling_settings.thresholds = absl::nullopt;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000214 // Create |number_of_streams| of encoder instances and init them.
215 for (int i = 0; i < number_of_streams; ++i) {
216 VideoCodec stream_codec;
Erik Språng78ce6192016-09-12 16:04:43 +0200217 uint32_t start_bitrate_kbps = start_bitrates[i];
Erik Språng7d687b12018-09-12 17:04:10 +0200218 const bool send_stream = start_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000219 if (!doing_simulcast) {
220 stream_codec = codec_;
221 stream_codec.numberOfSimulcastStreams = 1;
Erik Språng75de46a2018-11-07 14:53:32 +0100222
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000223 } else {
Erik Språng78ce6192016-09-12 16:04:43 +0200224 // Cap start bitrate to the min bitrate in order to avoid strange codec
Erik Språng7d687b12018-09-12 17:04:10 +0200225 // behavior. Since sending will be false, this should not matter.
Erik Språng78ce6192016-09-12 16:04:43 +0200226 start_bitrate_kbps =
227 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000228 bool highest_resolution_stream = (i == (number_of_streams - 1));
brandtr5e171752017-05-23 03:32:16 -0700229 PopulateStreamCodec(codec_, i, start_bitrate_kbps,
Erik Språng78ce6192016-09-12 16:04:43 +0200230 highest_resolution_stream, &stream_codec);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000231 }
232
Erik Språngcc681cc2018-03-14 17:52:55 +0100233 // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000234 if (stream_codec.qpMax < kDefaultMinQp) {
235 stream_codec.qpMax = kDefaultMaxQp;
236 }
237
brandtr5e171752017-05-23 03:32:16 -0700238 // If an existing encoder instance exists, reuse it.
239 // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
240 // when we start storing that state outside the encoder wrappers.
magjed3f897582017-08-28 08:05:42 -0700241 std::unique_ptr<VideoEncoder> encoder;
brandtr5e171752017-05-23 03:32:16 -0700242 if (!stored_encoders_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700243 encoder = std::move(stored_encoders_.top());
brandtr5e171752017-05-23 03:32:16 -0700244 stored_encoders_.pop();
245 } else {
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200246 encoder = factory_->CreateVideoEncoder(SdpVideoFormat(
247 codec_.codecType == webrtc::kVideoCodecVP8 ? "VP8" : "H264"));
brandtr5e171752017-05-23 03:32:16 -0700248 }
249
philipelcce46fc2015-12-21 03:04:49 -0800250 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000251 if (ret < 0) {
noahrice5ba75a2016-12-12 13:08:27 -0800252 // Explicitly destroy the current encoder; because we haven't registered a
253 // StreamInfo for it yet, Release won't do anything about it.
magjed3f897582017-08-28 08:05:42 -0700254 encoder.reset();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000255 Release();
256 return ret;
257 }
Erik Språngd3438aa2018-11-08 16:56:43 +0100258
brandtr5e171752017-05-23 03:32:16 -0700259 std::unique_ptr<EncodedImageCallback> callback(
260 new AdapterEncodedImageCallback(this, i));
261 encoder->RegisterEncodeCompleteCallback(callback.get());
magjed3f897582017-08-28 08:05:42 -0700262 streaminfos_.emplace_back(std::move(encoder), std::move(callback),
263 stream_codec.width, stream_codec.height,
Erik Språng7d687b12018-09-12 17:04:10 +0200264 send_stream);
brandtr5e171752017-05-23 03:32:16 -0700265
Erik Språng75de46a2018-11-07 14:53:32 +0100266 if (!doing_simulcast) {
267 // Without simulcast, just pass through the encoder info from the one
268 // active encoder.
269 encoder_info_ = streaminfos_[0].encoder->GetEncoderInfo();
270 } else {
271 const EncoderInfo encoder_impl_info =
272 streaminfos_[i].encoder->GetEncoderInfo();
273
274 if (i == 0) {
275 // Quality scaling not enabled for simulcast.
276 encoder_info_.scaling_settings = VideoEncoder::ScalingSettings::kOff;
277
278 // Encoder name indicates names of all sub-encoders.
279 encoder_info_.implementation_name = "SimulcastEncoderAdapter (";
280 encoder_info_.implementation_name +=
281 encoder_impl_info.implementation_name;
282
283 encoder_info_.supports_native_handle =
284 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100285 encoder_info_.has_trusted_rate_controller =
286 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100287 encoder_info_.is_hardware_accelerated =
288 encoder_impl_info.is_hardware_accelerated;
289 encoder_info_.has_internal_source =
290 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100291 } else {
292 encoder_info_.implementation_name += ", ";
293 encoder_info_.implementation_name +=
294 encoder_impl_info.implementation_name;
295
296 // Native handle supported only if all encoders supports it.
297 encoder_info_.supports_native_handle &=
298 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100299
300 // Trusted rate controller only if all encoders have it.
301 encoder_info_.has_trusted_rate_controller &=
302 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100303
304 // Uses hardware support if any of the encoders uses it.
305 // For example, if we are having issues with down-scaling due to
306 // pipelining delay in HW encoders we need higher encoder usage
307 // thresholds in CPU adaptation.
308 encoder_info_.is_hardware_accelerated |=
309 encoder_impl_info.is_hardware_accelerated;
310
311 // Has internal source only if all encoders have it.
312 encoder_info_.has_internal_source &=
313 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100314 }
brandtr5e171752017-05-23 03:32:16 -0700315 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000316 }
brandtr5e171752017-05-23 03:32:16 -0700317
Peter Boströmd53c3892016-03-30 17:03:52 +0200318 if (doing_simulcast) {
Erik Språng75de46a2018-11-07 14:53:32 +0100319 encoder_info_.implementation_name += ")";
Peter Boströmd53c3892016-03-30 17:03:52 +0200320 }
brandtr5e171752017-05-23 03:32:16 -0700321
322 // To save memory, don't store encoders that we don't use.
323 DestroyStoredEncoders();
324
325 rtc::AtomicOps::ReleaseStore(&inited_, 1);
326
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000327 return WEBRTC_VIDEO_CODEC_OK;
328}
329
330int SimulcastEncoderAdapter::Encode(
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700331 const VideoFrame& input_image,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000332 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700333 const std::vector<FrameType>* frame_types) {
brandtr5e171752017-05-23 03:32:16 -0700334 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
335
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000336 if (!Initialized()) {
337 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
338 }
brandtr5e171752017-05-23 03:32:16 -0700339 if (encoded_complete_callback_ == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000340 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
341 }
342
343 // All active streams should generate a key frame if
344 // a key frame is requested by any stream.
345 bool send_key_frame = false;
346 if (frame_types) {
347 for (size_t i = 0; i < frame_types->size(); ++i) {
Peter Boström49e196a2015-10-23 15:58:18 +0200348 if (frame_types->at(i) == kVideoFrameKey) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000349 send_key_frame = true;
350 break;
351 }
352 }
353 }
354 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
355 if (streaminfos_[stream_idx].key_frame_request &&
356 streaminfos_[stream_idx].send_stream) {
357 send_key_frame = true;
358 break;
359 }
360 }
361
362 int src_width = input_image.width();
363 int src_height = input_image.height();
364 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200365 // Don't encode frames in resolutions that we don't intend to send.
brandtr5e171752017-05-23 03:32:16 -0700366 if (!streaminfos_[stream_idx].send_stream) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200367 continue;
brandtr5e171752017-05-23 03:32:16 -0700368 }
Peter Boström5d0379d2015-10-06 14:04:51 +0200369
pbos22993e12015-10-19 02:39:06 -0700370 std::vector<FrameType> stream_frame_types;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000371 if (send_key_frame) {
Peter Boström49e196a2015-10-23 15:58:18 +0200372 stream_frame_types.push_back(kVideoFrameKey);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000373 streaminfos_[stream_idx].key_frame_request = false;
374 } else {
Peter Boström49e196a2015-10-23 15:58:18 +0200375 stream_frame_types.push_back(kVideoFrameDelta);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000376 }
377
378 int dst_width = streaminfos_[stream_idx].width;
379 int dst_height = streaminfos_[stream_idx].height;
380 // If scaling isn't required, because the input resolution
381 // matches the destination or the input image is empty (e.g.
382 // a keyframe request for encoders with internal camera
noahricfe3654d2016-07-01 09:05:54 -0700383 // sources) or the source image has a native handle, pass the image on
384 // directly. Otherwise, we'll scale it to match what the encoder expects
385 // (below).
386 // For texture frames, the underlying encoder is expected to be able to
387 // correctly sample/scale the source texture.
388 // TODO(perkj): ensure that works going forward, and figure out how this
389 // affects webrtc:5683.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000390 if ((dst_width == src_width && dst_height == src_height) ||
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000391 input_image.video_frame_buffer()->type() ==
392 VideoFrameBuffer::Type::kNative) {
noahric57779102016-05-25 06:48:46 -0700393 int ret = streaminfos_[stream_idx].encoder->Encode(
394 input_image, codec_specific_info, &stream_frame_types);
395 if (ret != WEBRTC_VIDEO_CODEC_OK) {
396 return ret;
397 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000398 } else {
nisse64ec8f82016-09-27 00:17:25 -0700399 rtc::scoped_refptr<I420Buffer> dst_buffer =
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000400 I420Buffer::Create(dst_width, dst_height);
401 rtc::scoped_refptr<I420BufferInterface> src_buffer =
402 input_image.video_frame_buffer()->ToI420();
403 libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
404 src_buffer->DataU(), src_buffer->StrideU(),
405 src_buffer->DataV(), src_buffer->StrideV(), src_width,
406 src_height, dst_buffer->MutableDataY(),
407 dst_buffer->StrideY(), dst_buffer->MutableDataU(),
408 dst_buffer->StrideU(), dst_buffer->MutableDataV(),
409 dst_buffer->StrideV(), dst_width, dst_height,
nissec9c142f2016-05-17 04:05:47 -0700410 libyuv::kFilterBilinear);
nisse64ec8f82016-09-27 00:17:25 -0700411
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100412 VideoFrame frame = VideoFrame::Builder()
413 .set_video_frame_buffer(dst_buffer)
414 .set_timestamp_rtp(input_image.timestamp())
415 .set_rotation(webrtc::kVideoRotation_0)
416 .set_timestamp_ms(input_image.render_time_ms())
417 .build();
noahric57779102016-05-25 06:48:46 -0700418 int ret = streaminfos_[stream_idx].encoder->Encode(
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100419 frame, codec_specific_info, &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700420 if (ret != WEBRTC_VIDEO_CODEC_OK) {
421 return ret;
422 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000423 }
424 }
425
426 return WEBRTC_VIDEO_CODEC_OK;
427}
428
429int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
430 EncodedImageCallback* callback) {
brandtr5e171752017-05-23 03:32:16 -0700431 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000432 encoded_complete_callback_ = callback;
433 return WEBRTC_VIDEO_CODEC_OK;
434}
435
Erik Språng566124a2018-04-23 12:32:22 +0200436int SimulcastEncoderAdapter::SetRateAllocation(
437 const VideoBitrateAllocation& bitrate,
438 uint32_t new_framerate) {
brandtr5e171752017-05-23 03:32:16 -0700439 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
440
441 if (!Initialized()) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000442 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
brandtr5e171752017-05-23 03:32:16 -0700443 }
sprang647bf432016-11-10 06:46:20 -0800444
brandtr5e171752017-05-23 03:32:16 -0700445 if (new_framerate < 1) {
Erik Språng08127a92016-11-16 16:41:30 +0100446 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700447 }
Erik Språng08127a92016-11-16 16:41:30 +0100448
brandtr5e171752017-05-23 03:32:16 -0700449 if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100450 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700451 }
Erik Språng08127a92016-11-16 16:41:30 +0100452
453 if (bitrate.get_sum_bps() > 0) {
sprang1369c832016-11-10 08:30:33 -0800454 // Make sure the bitrate fits the configured min bitrates. 0 is a special
455 // value that means paused, though, so leave it alone.
brandtr5e171752017-05-23 03:32:16 -0700456 if (bitrate.get_sum_kbps() < codec_.minBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100457 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700458 }
Erik Språng08127a92016-11-16 16:41:30 +0100459
sprang1369c832016-11-10 08:30:33 -0800460 if (codec_.numberOfSimulcastStreams > 0 &&
Erik Språng08127a92016-11-16 16:41:30 +0100461 bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
462 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
sprang1369c832016-11-10 08:30:33 -0800463 }
sprang1369c832016-11-10 08:30:33 -0800464 }
Erik Språng08127a92016-11-16 16:41:30 +0100465
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000466 codec_.maxFramerate = new_framerate;
467
sprang1369c832016-11-10 08:30:33 -0800468 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Erik Språng08127a92016-11-16 16:41:30 +0100469 uint32_t stream_bitrate_kbps =
470 bitrate.GetSpatialLayerSum(stream_idx) / 1000;
471
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000472 // Need a key frame if we have not sent this stream before.
Erik Språng78ce6192016-09-12 16:04:43 +0200473 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000474 streaminfos_[stream_idx].key_frame_request = true;
475 }
Erik Språng78ce6192016-09-12 16:04:43 +0200476 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000477
Erik Språng08127a92016-11-16 16:41:30 +0100478 // Slice the temporal layers out of the full allocation and pass it on to
479 // the encoder handling the current simulcast stream.
Erik Språng566124a2018-04-23 12:32:22 +0200480 VideoBitrateAllocation stream_allocation;
brandtr5e171752017-05-23 03:32:16 -0700481 for (int i = 0; i < kMaxTemporalStreams; ++i) {
erikvarga@webrtc.org01f2ec32017-11-15 14:58:23 +0100482 if (bitrate.HasBitrate(stream_idx, i)) {
483 stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
484 }
brandtr5e171752017-05-23 03:32:16 -0700485 }
Erik Språng08127a92016-11-16 16:41:30 +0100486 streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
487 new_framerate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000488 }
489
490 return WEBRTC_VIDEO_CODEC_OK;
491}
492
brandtr5e171752017-05-23 03:32:16 -0700493// TODO(brandtr): Add task checker to this member function, when all encoder
494// callbacks are coming in on the encoder queue.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700495EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
Noah Richards41ee1ea2015-04-15 09:24:26 -0700496 size_t stream_idx,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000497 const EncodedImage& encodedImage,
498 const CodecSpecificInfo* codecSpecificInfo,
499 const RTPFragmentationHeader* fragmentation) {
Niels Möllerd3b8c632018-08-27 15:33:42 +0200500 EncodedImage stream_image(encodedImage);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000501 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200502
503 stream_image.SetSpatialIndex(stream_idx);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000504
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700505 return encoded_complete_callback_->OnEncodedImage(
Niels Möllerd3b8c632018-08-27 15:33:42 +0200506 stream_image, &stream_codec_specific, fragmentation);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000507}
508
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000509void SimulcastEncoderAdapter::PopulateStreamCodec(
brandtr5e171752017-05-23 03:32:16 -0700510 const webrtc::VideoCodec& inst,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000511 int stream_index,
Erik Språng78ce6192016-09-12 16:04:43 +0200512 uint32_t start_bitrate_kbps,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000513 bool highest_resolution_stream,
Erik Språng78ce6192016-09-12 16:04:43 +0200514 webrtc::VideoCodec* stream_codec) {
brandtr5e171752017-05-23 03:32:16 -0700515 *stream_codec = inst;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000516
517 // Stream specific settings.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000518 stream_codec->numberOfSimulcastStreams = 0;
brandtr5e171752017-05-23 03:32:16 -0700519 stream_codec->width = inst.simulcastStream[stream_index].width;
520 stream_codec->height = inst.simulcastStream[stream_index].height;
521 stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
522 stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
523 stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000524 // Settings that are based on stream/resolution.
brandtr5e171752017-05-23 03:32:16 -0700525 const bool lowest_resolution_stream = (stream_index == 0);
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +0200526 if (lowest_resolution_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000527 // Settings for lowest spatial resolutions.
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +0200528 if (inst.mode == VideoCodecMode::kScreensharing) {
529 if (experimental_boosted_screenshare_qp_) {
530 stream_codec->qpMax = *experimental_boosted_screenshare_qp_;
531 }
532 } else {
533 stream_codec->qpMax = kLowestResMaxQp;
534 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000535 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200536 if (inst.codecType == webrtc::kVideoCodecVP8) {
537 stream_codec->VP8()->numberOfTemporalLayers =
538 inst.simulcastStream[stream_index].numberOfTemporalLayers;
539 if (!highest_resolution_stream) {
540 // For resolutions below CIF, set the codec |complexity| parameter to
541 // kComplexityHigher, which maps to cpu_used = -4.
542 int pixels_per_frame = stream_codec->width * stream_codec->height;
543 if (pixels_per_frame < 352 * 288) {
544 stream_codec->VP8()->complexity =
545 webrtc::VideoCodecComplexity::kComplexityHigher;
546 }
547 // Turn off denoising for all streams but the highest resolution.
548 stream_codec->VP8()->denoisingOn = false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000549 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000550 }
551 // TODO(ronghuawu): what to do with targetBitrate.
552
Erik Språng78ce6192016-09-12 16:04:43 +0200553 stream_codec->startBitrate = start_bitrate_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000554}
555
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000556bool SimulcastEncoderAdapter::Initialized() const {
brandtr5e171752017-05-23 03:32:16 -0700557 return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
558}
559
560void SimulcastEncoderAdapter::DestroyStoredEncoders() {
561 while (!stored_encoders_.empty()) {
brandtr5e171752017-05-23 03:32:16 -0700562 stored_encoders_.pop();
563 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000564}
565
Erik Språng9b5b0702018-11-01 14:52:30 +0100566VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
Erik Språng75de46a2018-11-07 14:53:32 +0100567 return encoder_info_;
pbosecd21b42016-01-07 08:03:05 -0800568}
569
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000570} // namespace webrtc