blob: 895489ca36ceaf45ca9de59684a90bf3965e4883 [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ångf93eda12019-01-16 17:10:57 +010021#include "api/video/video_codec_constants.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"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/atomic_ops.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
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000069int VerifyCodec(const webrtc::VideoCodec* inst) {
brandtr5e171752017-05-23 03:32:16 -070070 if (inst == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000071 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
72 }
73 if (inst->maxFramerate < 1) {
74 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
75 }
76 // allow zero to represent an unspecified maxBitRate
77 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
78 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
79 }
80 if (inst->width <= 1 || inst->height <= 1) {
81 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
82 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +020083 if (inst->codecType == webrtc::kVideoCodecVP8 &&
84 inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000085 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
86 }
87 return WEBRTC_VIDEO_CODEC_OK;
88}
89
Florent Castelli1b761ca2019-01-21 14:33:02 +010090bool StreamResolutionCompare(const webrtc::SimulcastStream& a,
91 const webrtc::SimulcastStream& b) {
92 return std::tie(a.height, a.width, a.maxBitrate, a.maxFramerate) <
93 std::tie(b.height, b.width, b.maxBitrate, b.maxFramerate);
94}
95
Noah Richards41ee1ea2015-04-15 09:24:26 -070096// An EncodedImageCallback implementation that forwards on calls to a
97// SimulcastEncoderAdapter, but with the stream index it's registered with as
98// the first parameter to Encoded.
99class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
100 public:
101 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
102 size_t stream_idx)
103 : adapter_(adapter), stream_idx_(stream_idx) {}
104
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700105 EncodedImageCallback::Result OnEncodedImage(
106 const webrtc::EncodedImage& encoded_image,
107 const webrtc::CodecSpecificInfo* codec_specific_info,
108 const webrtc::RTPFragmentationHeader* fragmentation) override {
109 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
110 codec_specific_info, fragmentation);
Noah Richards41ee1ea2015-04-15 09:24:26 -0700111 }
112
113 private:
114 webrtc::SimulcastEncoderAdapter* const adapter_;
115 const size_t stream_idx_;
116};
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000117} // namespace
118
119namespace webrtc {
120
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200121SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory,
122 const SdpVideoFormat& format)
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100123 : inited_(0),
124 factory_(factory),
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200125 video_format_(format),
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100126 encoded_complete_callback_(nullptr),
Oleh Prypina1d9ca42018-10-11 14:33:39 +0000127 experimental_boosted_screenshare_qp_(GetScreenshareBoostedQpValue()) {
Rasmus Brandtc334ce92018-02-05 13:03:25 +0100128 RTC_DCHECK(factory_);
Erik Språng75de46a2018-11-07 14:53:32 +0100129 encoder_info_.implementation_name = "SimulcastEncoderAdapter";
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100130
brandtr5e171752017-05-23 03:32:16 -0700131 // The adapter is typically created on the worker thread, but operated on
132 // the encoder task queue.
133 encoder_queue_.Detach();
134
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000135 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
136}
137
138SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
brandtr5e171752017-05-23 03:32:16 -0700139 RTC_DCHECK(!Initialized());
140 DestroyStoredEncoders();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000141}
142
143int SimulcastEncoderAdapter::Release() {
brandtr5e171752017-05-23 03:32:16 -0700144 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
145
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000146 while (!streaminfos_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700147 std::unique_ptr<VideoEncoder> encoder =
148 std::move(streaminfos_.back().encoder);
brandtr5e171752017-05-23 03:32:16 -0700149 // Even though it seems very unlikely, there are no guarantees that the
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200150 // encoder will not call back after being Release()'d. Therefore, we first
151 // disable the callbacks here.
brandtr5e171752017-05-23 03:32:16 -0700152 encoder->RegisterEncodeCompleteCallback(nullptr);
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200153 encoder->Release();
brandtr5e171752017-05-23 03:32:16 -0700154 streaminfos_.pop_back(); // Deletes callback adapter.
magjed3f897582017-08-28 08:05:42 -0700155 stored_encoders_.push(std::move(encoder));
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000156 }
brandtr5e171752017-05-23 03:32:16 -0700157
158 // It's legal to move the encoder to another queue now.
159 encoder_queue_.Detach();
160
161 rtc::AtomicOps::ReleaseStore(&inited_, 0);
162
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000163 return WEBRTC_VIDEO_CODEC_OK;
164}
165
166int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
167 int number_of_cores,
168 size_t max_payload_size) {
brandtr5e171752017-05-23 03:32:16 -0700169 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
170
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000171 if (number_of_cores < 1) {
172 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
173 }
174
175 int ret = VerifyCodec(inst);
176 if (ret < 0) {
177 return ret;
178 }
179
180 ret = Release();
181 if (ret < 0) {
182 return ret;
183 }
184
185 int number_of_streams = NumberOfStreams(*inst);
brandtr5e171752017-05-23 03:32:16 -0700186 RTC_DCHECK_LE(number_of_streams, kMaxSimulcastStreams);
Peter Boströmd53c3892016-03-30 17:03:52 +0200187 const bool doing_simulcast = (number_of_streams > 1);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000188
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000189 codec_ = *inst;
Erik Språng82fad3d2018-03-21 09:57:23 +0100190 SimulcastRateAllocator rate_allocator(codec_);
Erik Språng566124a2018-04-23 12:32:22 +0200191 VideoBitrateAllocation allocation = rate_allocator.GetAllocation(
Erik Språng08127a92016-11-16 16:41:30 +0100192 codec_.startBitrate * 1000, codec_.maxFramerate);
193 std::vector<uint32_t> start_bitrates;
194 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
195 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
196 start_bitrates.push_back(stream_bitrate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000197 }
198
Erik Språng75de46a2018-11-07 14:53:32 +0100199 encoder_info_.supports_native_handle = true;
200 encoder_info_.scaling_settings.thresholds = absl::nullopt;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000201 // Create |number_of_streams| of encoder instances and init them.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100202
203 const auto minmax = std::minmax_element(
204 std::begin(codec_.simulcastStream),
205 std::begin(codec_.simulcastStream) + number_of_streams,
206 StreamResolutionCompare);
207 const auto lowest_resolution_stream_index =
208 std::distance(std::begin(codec_.simulcastStream), minmax.first);
209 const auto highest_resolution_stream_index =
210 std::distance(std::begin(codec_.simulcastStream), minmax.second);
211
212 RTC_DCHECK_LT(lowest_resolution_stream_index, number_of_streams);
213 RTC_DCHECK_LT(highest_resolution_stream_index, number_of_streams);
214
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000215 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.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100226 StreamResolution stream_resolution =
227 i == highest_resolution_stream_index
228 ? StreamResolution::HIGHEST
229 : i == lowest_resolution_stream_index ? StreamResolution::LOWEST
230 : StreamResolution::OTHER;
231
Erik Språng78ce6192016-09-12 16:04:43 +0200232 start_bitrate_kbps =
233 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
Florent Castelli1b761ca2019-01-21 14:33:02 +0100234 PopulateStreamCodec(codec_, i, start_bitrate_kbps, stream_resolution,
235 &stream_codec);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000236 }
237
Erik Språngcc681cc2018-03-14 17:52:55 +0100238 // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000239 if (stream_codec.qpMax < kDefaultMinQp) {
240 stream_codec.qpMax = kDefaultMaxQp;
241 }
242
brandtr5e171752017-05-23 03:32:16 -0700243 // If an existing encoder instance exists, reuse it.
244 // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
245 // when we start storing that state outside the encoder wrappers.
magjed3f897582017-08-28 08:05:42 -0700246 std::unique_ptr<VideoEncoder> encoder;
brandtr5e171752017-05-23 03:32:16 -0700247 if (!stored_encoders_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700248 encoder = std::move(stored_encoders_.top());
brandtr5e171752017-05-23 03:32:16 -0700249 stored_encoders_.pop();
250 } else {
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200251 encoder = factory_->CreateVideoEncoder(SdpVideoFormat(
252 codec_.codecType == webrtc::kVideoCodecVP8 ? "VP8" : "H264"));
brandtr5e171752017-05-23 03:32:16 -0700253 }
254
philipelcce46fc2015-12-21 03:04:49 -0800255 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000256 if (ret < 0) {
noahrice5ba75a2016-12-12 13:08:27 -0800257 // Explicitly destroy the current encoder; because we haven't registered a
258 // StreamInfo for it yet, Release won't do anything about it.
magjed3f897582017-08-28 08:05:42 -0700259 encoder.reset();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000260 Release();
261 return ret;
262 }
Erik Språngd3438aa2018-11-08 16:56:43 +0100263
brandtr5e171752017-05-23 03:32:16 -0700264 std::unique_ptr<EncodedImageCallback> callback(
265 new AdapterEncodedImageCallback(this, i));
266 encoder->RegisterEncodeCompleteCallback(callback.get());
magjed3f897582017-08-28 08:05:42 -0700267 streaminfos_.emplace_back(std::move(encoder), std::move(callback),
268 stream_codec.width, stream_codec.height,
Erik Språng7d687b12018-09-12 17:04:10 +0200269 send_stream);
brandtr5e171752017-05-23 03:32:16 -0700270
Erik Språng75de46a2018-11-07 14:53:32 +0100271 if (!doing_simulcast) {
272 // Without simulcast, just pass through the encoder info from the one
273 // active encoder.
274 encoder_info_ = streaminfos_[0].encoder->GetEncoderInfo();
275 } else {
276 const EncoderInfo encoder_impl_info =
277 streaminfos_[i].encoder->GetEncoderInfo();
278
279 if (i == 0) {
280 // Quality scaling not enabled for simulcast.
281 encoder_info_.scaling_settings = VideoEncoder::ScalingSettings::kOff;
282
283 // Encoder name indicates names of all sub-encoders.
284 encoder_info_.implementation_name = "SimulcastEncoderAdapter (";
285 encoder_info_.implementation_name +=
286 encoder_impl_info.implementation_name;
287
288 encoder_info_.supports_native_handle =
289 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100290 encoder_info_.has_trusted_rate_controller =
291 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100292 encoder_info_.is_hardware_accelerated =
293 encoder_impl_info.is_hardware_accelerated;
294 encoder_info_.has_internal_source =
295 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100296 } else {
297 encoder_info_.implementation_name += ", ";
298 encoder_info_.implementation_name +=
299 encoder_impl_info.implementation_name;
300
301 // Native handle supported only if all encoders supports it.
302 encoder_info_.supports_native_handle &=
303 encoder_impl_info.supports_native_handle;
Erik Språngd3438aa2018-11-08 16:56:43 +0100304
305 // Trusted rate controller only if all encoders have it.
306 encoder_info_.has_trusted_rate_controller &=
307 encoder_impl_info.has_trusted_rate_controller;
Mirta Dvornicic897a9912018-11-30 13:12:21 +0100308
309 // Uses hardware support if any of the encoders uses it.
310 // For example, if we are having issues with down-scaling due to
311 // pipelining delay in HW encoders we need higher encoder usage
312 // thresholds in CPU adaptation.
313 encoder_info_.is_hardware_accelerated |=
314 encoder_impl_info.is_hardware_accelerated;
315
316 // Has internal source only if all encoders have it.
317 encoder_info_.has_internal_source &=
318 encoder_impl_info.has_internal_source;
Erik Språng75de46a2018-11-07 14:53:32 +0100319 }
Erik Språngdbdd8392019-01-17 15:27:50 +0100320 encoder_info_.fps_allocation[i] = encoder_impl_info.fps_allocation[0];
brandtr5e171752017-05-23 03:32:16 -0700321 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000322 }
brandtr5e171752017-05-23 03:32:16 -0700323
Peter Boströmd53c3892016-03-30 17:03:52 +0200324 if (doing_simulcast) {
Erik Språng75de46a2018-11-07 14:53:32 +0100325 encoder_info_.implementation_name += ")";
Peter Boströmd53c3892016-03-30 17:03:52 +0200326 }
brandtr5e171752017-05-23 03:32:16 -0700327
328 // To save memory, don't store encoders that we don't use.
329 DestroyStoredEncoders();
330
331 rtc::AtomicOps::ReleaseStore(&inited_, 1);
332
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000333 return WEBRTC_VIDEO_CODEC_OK;
334}
335
336int SimulcastEncoderAdapter::Encode(
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700337 const VideoFrame& input_image,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000338 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700339 const std::vector<FrameType>* frame_types) {
brandtr5e171752017-05-23 03:32:16 -0700340 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
341
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000342 if (!Initialized()) {
343 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
344 }
brandtr5e171752017-05-23 03:32:16 -0700345 if (encoded_complete_callback_ == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000346 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
347 }
348
349 // All active streams should generate a key frame if
350 // a key frame is requested by any stream.
351 bool send_key_frame = false;
352 if (frame_types) {
353 for (size_t i = 0; i < frame_types->size(); ++i) {
Peter Boström49e196a2015-10-23 15:58:18 +0200354 if (frame_types->at(i) == kVideoFrameKey) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000355 send_key_frame = true;
356 break;
357 }
358 }
359 }
360 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
361 if (streaminfos_[stream_idx].key_frame_request &&
362 streaminfos_[stream_idx].send_stream) {
363 send_key_frame = true;
364 break;
365 }
366 }
367
368 int src_width = input_image.width();
369 int src_height = input_image.height();
370 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200371 // Don't encode frames in resolutions that we don't intend to send.
brandtr5e171752017-05-23 03:32:16 -0700372 if (!streaminfos_[stream_idx].send_stream) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200373 continue;
brandtr5e171752017-05-23 03:32:16 -0700374 }
Peter Boström5d0379d2015-10-06 14:04:51 +0200375
pbos22993e12015-10-19 02:39:06 -0700376 std::vector<FrameType> stream_frame_types;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000377 if (send_key_frame) {
Peter Boström49e196a2015-10-23 15:58:18 +0200378 stream_frame_types.push_back(kVideoFrameKey);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000379 streaminfos_[stream_idx].key_frame_request = false;
380 } else {
Peter Boström49e196a2015-10-23 15:58:18 +0200381 stream_frame_types.push_back(kVideoFrameDelta);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000382 }
383
384 int dst_width = streaminfos_[stream_idx].width;
385 int dst_height = streaminfos_[stream_idx].height;
386 // If scaling isn't required, because the input resolution
387 // matches the destination or the input image is empty (e.g.
388 // a keyframe request for encoders with internal camera
noahricfe3654d2016-07-01 09:05:54 -0700389 // sources) or the source image has a native handle, pass the image on
390 // directly. Otherwise, we'll scale it to match what the encoder expects
391 // (below).
392 // For texture frames, the underlying encoder is expected to be able to
393 // correctly sample/scale the source texture.
394 // TODO(perkj): ensure that works going forward, and figure out how this
395 // affects webrtc:5683.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000396 if ((dst_width == src_width && dst_height == src_height) ||
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000397 input_image.video_frame_buffer()->type() ==
398 VideoFrameBuffer::Type::kNative) {
noahric57779102016-05-25 06:48:46 -0700399 int ret = streaminfos_[stream_idx].encoder->Encode(
400 input_image, codec_specific_info, &stream_frame_types);
401 if (ret != WEBRTC_VIDEO_CODEC_OK) {
402 return ret;
403 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000404 } else {
nisse64ec8f82016-09-27 00:17:25 -0700405 rtc::scoped_refptr<I420Buffer> dst_buffer =
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000406 I420Buffer::Create(dst_width, dst_height);
407 rtc::scoped_refptr<I420BufferInterface> src_buffer =
408 input_image.video_frame_buffer()->ToI420();
409 libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
410 src_buffer->DataU(), src_buffer->StrideU(),
411 src_buffer->DataV(), src_buffer->StrideV(), src_width,
412 src_height, dst_buffer->MutableDataY(),
413 dst_buffer->StrideY(), dst_buffer->MutableDataU(),
414 dst_buffer->StrideU(), dst_buffer->MutableDataV(),
415 dst_buffer->StrideV(), dst_width, dst_height,
nissec9c142f2016-05-17 04:05:47 -0700416 libyuv::kFilterBilinear);
nisse64ec8f82016-09-27 00:17:25 -0700417
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100418 VideoFrame frame = VideoFrame::Builder()
419 .set_video_frame_buffer(dst_buffer)
420 .set_timestamp_rtp(input_image.timestamp())
421 .set_rotation(webrtc::kVideoRotation_0)
422 .set_timestamp_ms(input_image.render_time_ms())
423 .build();
noahric57779102016-05-25 06:48:46 -0700424 int ret = streaminfos_[stream_idx].encoder->Encode(
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100425 frame, codec_specific_info, &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700426 if (ret != WEBRTC_VIDEO_CODEC_OK) {
427 return ret;
428 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000429 }
430 }
431
432 return WEBRTC_VIDEO_CODEC_OK;
433}
434
435int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
436 EncodedImageCallback* callback) {
brandtr5e171752017-05-23 03:32:16 -0700437 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000438 encoded_complete_callback_ = callback;
439 return WEBRTC_VIDEO_CODEC_OK;
440}
441
Erik Språng566124a2018-04-23 12:32:22 +0200442int SimulcastEncoderAdapter::SetRateAllocation(
443 const VideoBitrateAllocation& bitrate,
444 uint32_t new_framerate) {
brandtr5e171752017-05-23 03:32:16 -0700445 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
446
447 if (!Initialized()) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000448 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
brandtr5e171752017-05-23 03:32:16 -0700449 }
sprang647bf432016-11-10 06:46:20 -0800450
brandtr5e171752017-05-23 03:32:16 -0700451 if (new_framerate < 1) {
Erik Språng08127a92016-11-16 16:41:30 +0100452 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700453 }
Erik Språng08127a92016-11-16 16:41:30 +0100454
brandtr5e171752017-05-23 03:32:16 -0700455 if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100456 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700457 }
Erik Språng08127a92016-11-16 16:41:30 +0100458
459 if (bitrate.get_sum_bps() > 0) {
sprang1369c832016-11-10 08:30:33 -0800460 // Make sure the bitrate fits the configured min bitrates. 0 is a special
461 // value that means paused, though, so leave it alone.
brandtr5e171752017-05-23 03:32:16 -0700462 if (bitrate.get_sum_kbps() < codec_.minBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100463 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700464 }
Erik Språng08127a92016-11-16 16:41:30 +0100465
sprang1369c832016-11-10 08:30:33 -0800466 if (codec_.numberOfSimulcastStreams > 0 &&
Erik Språng08127a92016-11-16 16:41:30 +0100467 bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
468 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
sprang1369c832016-11-10 08:30:33 -0800469 }
sprang1369c832016-11-10 08:30:33 -0800470 }
Erik Språng08127a92016-11-16 16:41:30 +0100471
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000472 codec_.maxFramerate = new_framerate;
473
sprang1369c832016-11-10 08:30:33 -0800474 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Erik Språng08127a92016-11-16 16:41:30 +0100475 uint32_t stream_bitrate_kbps =
476 bitrate.GetSpatialLayerSum(stream_idx) / 1000;
477
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000478 // Need a key frame if we have not sent this stream before.
Erik Språng78ce6192016-09-12 16:04:43 +0200479 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000480 streaminfos_[stream_idx].key_frame_request = true;
481 }
Erik Språng78ce6192016-09-12 16:04:43 +0200482 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000483
Erik Språng08127a92016-11-16 16:41:30 +0100484 // Slice the temporal layers out of the full allocation and pass it on to
485 // the encoder handling the current simulcast stream.
Erik Språng566124a2018-04-23 12:32:22 +0200486 VideoBitrateAllocation stream_allocation;
brandtr5e171752017-05-23 03:32:16 -0700487 for (int i = 0; i < kMaxTemporalStreams; ++i) {
erikvarga@webrtc.org01f2ec32017-11-15 14:58:23 +0100488 if (bitrate.HasBitrate(stream_idx, i)) {
489 stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
490 }
brandtr5e171752017-05-23 03:32:16 -0700491 }
Erik Språng08127a92016-11-16 16:41:30 +0100492 streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
493 new_framerate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000494 }
495
496 return WEBRTC_VIDEO_CODEC_OK;
497}
498
brandtr5e171752017-05-23 03:32:16 -0700499// TODO(brandtr): Add task checker to this member function, when all encoder
500// callbacks are coming in on the encoder queue.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700501EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
Noah Richards41ee1ea2015-04-15 09:24:26 -0700502 size_t stream_idx,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000503 const EncodedImage& encodedImage,
504 const CodecSpecificInfo* codecSpecificInfo,
505 const RTPFragmentationHeader* fragmentation) {
Niels Möllerd3b8c632018-08-27 15:33:42 +0200506 EncodedImage stream_image(encodedImage);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000507 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200508
509 stream_image.SetSpatialIndex(stream_idx);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000510
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700511 return encoded_complete_callback_->OnEncodedImage(
Niels Möllerd3b8c632018-08-27 15:33:42 +0200512 stream_image, &stream_codec_specific, fragmentation);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000513}
514
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000515void SimulcastEncoderAdapter::PopulateStreamCodec(
brandtr5e171752017-05-23 03:32:16 -0700516 const webrtc::VideoCodec& inst,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000517 int stream_index,
Erik Språng78ce6192016-09-12 16:04:43 +0200518 uint32_t start_bitrate_kbps,
Florent Castelli1b761ca2019-01-21 14:33:02 +0100519 StreamResolution stream_resolution,
Erik Språng78ce6192016-09-12 16:04:43 +0200520 webrtc::VideoCodec* stream_codec) {
brandtr5e171752017-05-23 03:32:16 -0700521 *stream_codec = inst;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000522
523 // Stream specific settings.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000524 stream_codec->numberOfSimulcastStreams = 0;
brandtr5e171752017-05-23 03:32:16 -0700525 stream_codec->width = inst.simulcastStream[stream_index].width;
526 stream_codec->height = inst.simulcastStream[stream_index].height;
527 stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
528 stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
529 stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000530 // Settings that are based on stream/resolution.
Florent Castelli1b761ca2019-01-21 14:33:02 +0100531 if (stream_resolution == StreamResolution::LOWEST) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000532 // Settings for lowest spatial resolutions.
Ilya Nikolaevskiyc30a1312018-08-27 11:07:48 +0200533 if (inst.mode == VideoCodecMode::kScreensharing) {
534 if (experimental_boosted_screenshare_qp_) {
535 stream_codec->qpMax = *experimental_boosted_screenshare_qp_;
536 }
537 } else {
538 stream_codec->qpMax = kLowestResMaxQp;
539 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000540 }
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200541 if (inst.codecType == webrtc::kVideoCodecVP8) {
542 stream_codec->VP8()->numberOfTemporalLayers =
543 inst.simulcastStream[stream_index].numberOfTemporalLayers;
Florent Castelli1b761ca2019-01-21 14:33:02 +0100544 if (stream_resolution != StreamResolution::HIGHEST) {
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +0200545 // For resolutions below CIF, set the codec |complexity| parameter to
546 // kComplexityHigher, which maps to cpu_used = -4.
547 int pixels_per_frame = stream_codec->width * stream_codec->height;
548 if (pixels_per_frame < 352 * 288) {
549 stream_codec->VP8()->complexity =
550 webrtc::VideoCodecComplexity::kComplexityHigher;
551 }
552 // Turn off denoising for all streams but the highest resolution.
553 stream_codec->VP8()->denoisingOn = false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000554 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000555 }
556 // TODO(ronghuawu): what to do with targetBitrate.
557
Erik Språng78ce6192016-09-12 16:04:43 +0200558 stream_codec->startBitrate = start_bitrate_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000559}
560
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000561bool SimulcastEncoderAdapter::Initialized() const {
brandtr5e171752017-05-23 03:32:16 -0700562 return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
563}
564
565void SimulcastEncoderAdapter::DestroyStoredEncoders() {
566 while (!stored_encoders_.empty()) {
brandtr5e171752017-05-23 03:32:16 -0700567 stored_encoders_.pop();
568 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000569}
570
Erik Språng9b5b0702018-11-01 14:52:30 +0100571VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
Erik Språng75de46a2018-11-07 14:53:32 +0100572 return encoder_info_;
pbosecd21b42016-01-07 08:03:05 -0800573}
574
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000575} // namespace webrtc