blob: ab06022f242383a7e584f67265674a44e411c05c [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
13#include <algorithm>
14
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "api/video/i420_buffer.h"
Erik Språng7fd0a282018-05-22 15:37:23 +020017#include "api/video/video_bitrate_allocation.h"
Magnus Jedvertdf4883d2017-11-17 14:44:55 +010018#include "api/video_codecs/video_encoder_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "media/engine/scopedvideoencoder.h"
20#include "modules/video_coding/codecs/vp8/screenshare_layers.h"
21#include "modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
22#include "rtc_base/checks.h"
23#include "system_wrappers/include/clock.h"
Mirko Bonadei65432062017-12-11 09:32:13 +010024#include "third_party/libyuv/include/libyuv/scale.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000025
26namespace {
27
28const unsigned int kDefaultMinQp = 2;
29const unsigned int kDefaultMaxQp = 56;
30// Max qp for lowest spatial resolution when doing simulcast.
31const unsigned int kLowestResMaxQp = 45;
32
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000033uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
34 uint32_t bitrate_sum = 0;
35 for (int i = 0; i < streams; ++i) {
36 bitrate_sum += codec.simulcastStream[i].maxBitrate;
37 }
38 return bitrate_sum;
39}
40
41int NumberOfStreams(const webrtc::VideoCodec& codec) {
42 int streams =
43 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
44 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
45 if (simulcast_max_bitrate == 0) {
46 streams = 1;
47 }
48 return streams;
49}
50
51bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec,
52 int num_streams) {
53 if (codec.width != codec.simulcastStream[num_streams - 1].width ||
54 codec.height != codec.simulcastStream[num_streams - 1].height) {
55 return false;
56 }
57 for (int i = 0; i < num_streams; ++i) {
58 if (codec.width * codec.simulcastStream[i].height !=
59 codec.height * codec.simulcastStream[i].width) {
60 return false;
61 }
62 }
63 return true;
64}
65
66int VerifyCodec(const webrtc::VideoCodec* inst) {
brandtr5e171752017-05-23 03:32:16 -070067 if (inst == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000068 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
69 }
70 if (inst->maxFramerate < 1) {
71 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
72 }
73 // allow zero to represent an unspecified maxBitRate
74 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
75 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
76 }
77 if (inst->width <= 1 || inst->height <= 1) {
78 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
79 }
hta257dc392016-10-25 09:05:06 -070080 if (inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000081 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
82 }
83 return WEBRTC_VIDEO_CODEC_OK;
84}
85
Noah Richards41ee1ea2015-04-15 09:24:26 -070086// An EncodedImageCallback implementation that forwards on calls to a
87// SimulcastEncoderAdapter, but with the stream index it's registered with as
88// the first parameter to Encoded.
89class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
90 public:
91 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
92 size_t stream_idx)
93 : adapter_(adapter), stream_idx_(stream_idx) {}
94
Sergey Ulanov525df3f2016-08-02 17:46:41 -070095 EncodedImageCallback::Result OnEncodedImage(
96 const webrtc::EncodedImage& encoded_image,
97 const webrtc::CodecSpecificInfo* codec_specific_info,
98 const webrtc::RTPFragmentationHeader* fragmentation) override {
99 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
100 codec_specific_info, fragmentation);
Noah Richards41ee1ea2015-04-15 09:24:26 -0700101 }
102
103 private:
104 webrtc::SimulcastEncoderAdapter* const adapter_;
105 const size_t stream_idx_;
106};
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000107} // namespace
108
109namespace webrtc {
110
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200111SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory,
112 const SdpVideoFormat& format)
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100113 : inited_(0),
114 factory_(factory),
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200115 video_format_(format),
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100116 encoded_complete_callback_(nullptr),
117 implementation_name_("SimulcastEncoderAdapter") {
Rasmus Brandtc334ce92018-02-05 13:03:25 +0100118 RTC_DCHECK(factory_);
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100119
brandtr5e171752017-05-23 03:32:16 -0700120 // The adapter is typically created on the worker thread, but operated on
121 // the encoder task queue.
122 encoder_queue_.Detach();
123
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000124 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
125}
126
127SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
brandtr5e171752017-05-23 03:32:16 -0700128 RTC_DCHECK(!Initialized());
129 DestroyStoredEncoders();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000130}
131
132int SimulcastEncoderAdapter::Release() {
brandtr5e171752017-05-23 03:32:16 -0700133 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
134
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000135 while (!streaminfos_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700136 std::unique_ptr<VideoEncoder> encoder =
137 std::move(streaminfos_.back().encoder);
brandtr5e171752017-05-23 03:32:16 -0700138 // Even though it seems very unlikely, there are no guarantees that the
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200139 // encoder will not call back after being Release()'d. Therefore, we first
140 // disable the callbacks here.
brandtr5e171752017-05-23 03:32:16 -0700141 encoder->RegisterEncodeCompleteCallback(nullptr);
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200142 encoder->Release();
brandtr5e171752017-05-23 03:32:16 -0700143 streaminfos_.pop_back(); // Deletes callback adapter.
magjed3f897582017-08-28 08:05:42 -0700144 stored_encoders_.push(std::move(encoder));
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000145 }
brandtr5e171752017-05-23 03:32:16 -0700146
147 // It's legal to move the encoder to another queue now.
148 encoder_queue_.Detach();
149
150 rtc::AtomicOps::ReleaseStore(&inited_, 0);
151
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000152 return WEBRTC_VIDEO_CODEC_OK;
153}
154
155int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
156 int number_of_cores,
157 size_t max_payload_size) {
brandtr5e171752017-05-23 03:32:16 -0700158 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
159
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000160 if (number_of_cores < 1) {
161 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
162 }
163
164 int ret = VerifyCodec(inst);
165 if (ret < 0) {
166 return ret;
167 }
168
169 ret = Release();
170 if (ret < 0) {
171 return ret;
172 }
173
174 int number_of_streams = NumberOfStreams(*inst);
brandtr5e171752017-05-23 03:32:16 -0700175 RTC_DCHECK_LE(number_of_streams, kMaxSimulcastStreams);
Peter Boströmd53c3892016-03-30 17:03:52 +0200176 const bool doing_simulcast = (number_of_streams > 1);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000177
178 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
179 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
180 }
181
182 codec_ = *inst;
Erik Språng82fad3d2018-03-21 09:57:23 +0100183 SimulcastRateAllocator rate_allocator(codec_);
Erik Språng566124a2018-04-23 12:32:22 +0200184 VideoBitrateAllocation allocation = rate_allocator.GetAllocation(
Erik Språng08127a92016-11-16 16:41:30 +0100185 codec_.startBitrate * 1000, codec_.maxFramerate);
186 std::vector<uint32_t> start_bitrates;
187 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
188 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
189 start_bitrates.push_back(stream_bitrate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000190 }
191
Peter Boströma5dec162016-01-20 15:53:55 +0100192 std::string implementation_name;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000193 // Create |number_of_streams| of encoder instances and init them.
194 for (int i = 0; i < number_of_streams; ++i) {
195 VideoCodec stream_codec;
Erik Språng78ce6192016-09-12 16:04:43 +0200196 uint32_t start_bitrate_kbps = start_bitrates[i];
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000197 if (!doing_simulcast) {
198 stream_codec = codec_;
199 stream_codec.numberOfSimulcastStreams = 1;
200 } else {
Erik Språng78ce6192016-09-12 16:04:43 +0200201 // Cap start bitrate to the min bitrate in order to avoid strange codec
202 // behavior. Since sending sending will be false, this should not matter.
203 start_bitrate_kbps =
204 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000205 bool highest_resolution_stream = (i == (number_of_streams - 1));
brandtr5e171752017-05-23 03:32:16 -0700206 PopulateStreamCodec(codec_, i, start_bitrate_kbps,
Erik Språng78ce6192016-09-12 16:04:43 +0200207 highest_resolution_stream, &stream_codec);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000208 }
209
Erik Språngcc681cc2018-03-14 17:52:55 +0100210 // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000211 if (stream_codec.qpMax < kDefaultMinQp) {
212 stream_codec.qpMax = kDefaultMaxQp;
213 }
214
brandtr5e171752017-05-23 03:32:16 -0700215 // If an existing encoder instance exists, reuse it.
216 // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
217 // when we start storing that state outside the encoder wrappers.
magjed3f897582017-08-28 08:05:42 -0700218 std::unique_ptr<VideoEncoder> encoder;
brandtr5e171752017-05-23 03:32:16 -0700219 if (!stored_encoders_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700220 encoder = std::move(stored_encoders_.top());
brandtr5e171752017-05-23 03:32:16 -0700221 stored_encoders_.pop();
222 } else {
Ilya Nikolaevskiy97b4ee52018-05-28 10:24:22 +0200223 encoder = factory_->CreateVideoEncoder(video_format_);
brandtr5e171752017-05-23 03:32:16 -0700224 }
225
philipelcce46fc2015-12-21 03:04:49 -0800226 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000227 if (ret < 0) {
noahrice5ba75a2016-12-12 13:08:27 -0800228 // Explicitly destroy the current encoder; because we haven't registered a
229 // StreamInfo for it yet, Release won't do anything about it.
magjed3f897582017-08-28 08:05:42 -0700230 encoder.reset();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000231 Release();
232 return ret;
233 }
brandtr5e171752017-05-23 03:32:16 -0700234 std::unique_ptr<EncodedImageCallback> callback(
235 new AdapterEncodedImageCallback(this, i));
236 encoder->RegisterEncodeCompleteCallback(callback.get());
magjed3f897582017-08-28 08:05:42 -0700237 streaminfos_.emplace_back(std::move(encoder), std::move(callback),
238 stream_codec.width, stream_codec.height,
239 start_bitrate_kbps > 0);
brandtr5e171752017-05-23 03:32:16 -0700240
241 if (i != 0) {
Peter Boströma5dec162016-01-20 15:53:55 +0100242 implementation_name += ", ";
brandtr5e171752017-05-23 03:32:16 -0700243 }
Peter Boströma5dec162016-01-20 15:53:55 +0100244 implementation_name += streaminfos_[i].encoder->ImplementationName();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000245 }
brandtr5e171752017-05-23 03:32:16 -0700246
Peter Boströmd53c3892016-03-30 17:03:52 +0200247 if (doing_simulcast) {
248 implementation_name_ =
249 "SimulcastEncoderAdapter (" + implementation_name + ")";
250 } else {
251 implementation_name_ = implementation_name;
252 }
brandtr5e171752017-05-23 03:32:16 -0700253
254 // To save memory, don't store encoders that we don't use.
255 DestroyStoredEncoders();
256
257 rtc::AtomicOps::ReleaseStore(&inited_, 1);
258
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000259 return WEBRTC_VIDEO_CODEC_OK;
260}
261
262int SimulcastEncoderAdapter::Encode(
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700263 const VideoFrame& input_image,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000264 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700265 const std::vector<FrameType>* frame_types) {
brandtr5e171752017-05-23 03:32:16 -0700266 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
267
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000268 if (!Initialized()) {
269 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
270 }
brandtr5e171752017-05-23 03:32:16 -0700271 if (encoded_complete_callback_ == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000272 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
273 }
274
275 // All active streams should generate a key frame if
276 // a key frame is requested by any stream.
277 bool send_key_frame = false;
278 if (frame_types) {
279 for (size_t i = 0; i < frame_types->size(); ++i) {
Peter Boström49e196a2015-10-23 15:58:18 +0200280 if (frame_types->at(i) == kVideoFrameKey) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000281 send_key_frame = true;
282 break;
283 }
284 }
285 }
286 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
287 if (streaminfos_[stream_idx].key_frame_request &&
288 streaminfos_[stream_idx].send_stream) {
289 send_key_frame = true;
290 break;
291 }
292 }
293
294 int src_width = input_image.width();
295 int src_height = input_image.height();
296 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200297 // Don't encode frames in resolutions that we don't intend to send.
brandtr5e171752017-05-23 03:32:16 -0700298 if (!streaminfos_[stream_idx].send_stream) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200299 continue;
brandtr5e171752017-05-23 03:32:16 -0700300 }
Peter Boström5d0379d2015-10-06 14:04:51 +0200301
pbos22993e12015-10-19 02:39:06 -0700302 std::vector<FrameType> stream_frame_types;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000303 if (send_key_frame) {
Peter Boström49e196a2015-10-23 15:58:18 +0200304 stream_frame_types.push_back(kVideoFrameKey);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000305 streaminfos_[stream_idx].key_frame_request = false;
306 } else {
Peter Boström49e196a2015-10-23 15:58:18 +0200307 stream_frame_types.push_back(kVideoFrameDelta);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000308 }
309
310 int dst_width = streaminfos_[stream_idx].width;
311 int dst_height = streaminfos_[stream_idx].height;
312 // If scaling isn't required, because the input resolution
313 // matches the destination or the input image is empty (e.g.
314 // a keyframe request for encoders with internal camera
noahricfe3654d2016-07-01 09:05:54 -0700315 // sources) or the source image has a native handle, pass the image on
316 // directly. Otherwise, we'll scale it to match what the encoder expects
317 // (below).
318 // For texture frames, the underlying encoder is expected to be able to
319 // correctly sample/scale the source texture.
320 // TODO(perkj): ensure that works going forward, and figure out how this
321 // affects webrtc:5683.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000322 if ((dst_width == src_width && dst_height == src_height) ||
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000323 input_image.video_frame_buffer()->type() ==
324 VideoFrameBuffer::Type::kNative) {
noahric57779102016-05-25 06:48:46 -0700325 int ret = streaminfos_[stream_idx].encoder->Encode(
326 input_image, codec_specific_info, &stream_frame_types);
327 if (ret != WEBRTC_VIDEO_CODEC_OK) {
328 return ret;
329 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000330 } else {
nisse64ec8f82016-09-27 00:17:25 -0700331 rtc::scoped_refptr<I420Buffer> dst_buffer =
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000332 I420Buffer::Create(dst_width, dst_height);
333 rtc::scoped_refptr<I420BufferInterface> src_buffer =
334 input_image.video_frame_buffer()->ToI420();
335 libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
336 src_buffer->DataU(), src_buffer->StrideU(),
337 src_buffer->DataV(), src_buffer->StrideV(), src_width,
338 src_height, dst_buffer->MutableDataY(),
339 dst_buffer->StrideY(), dst_buffer->MutableDataU(),
340 dst_buffer->StrideU(), dst_buffer->MutableDataV(),
341 dst_buffer->StrideV(), dst_width, dst_height,
nissec9c142f2016-05-17 04:05:47 -0700342 libyuv::kFilterBilinear);
nisse64ec8f82016-09-27 00:17:25 -0700343
noahric57779102016-05-25 06:48:46 -0700344 int ret = streaminfos_[stream_idx].encoder->Encode(
nisse64ec8f82016-09-27 00:17:25 -0700345 VideoFrame(dst_buffer, input_image.timestamp(),
346 input_image.render_time_ms(), webrtc::kVideoRotation_0),
347 codec_specific_info, &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700348 if (ret != WEBRTC_VIDEO_CODEC_OK) {
349 return ret;
350 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000351 }
352 }
353
354 return WEBRTC_VIDEO_CODEC_OK;
355}
356
357int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
358 EncodedImageCallback* callback) {
brandtr5e171752017-05-23 03:32:16 -0700359 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000360 encoded_complete_callback_ = callback;
361 return WEBRTC_VIDEO_CODEC_OK;
362}
363
364int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000365 int64_t rtt) {
brandtr5e171752017-05-23 03:32:16 -0700366 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000367 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
368 streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt);
369 }
370 return WEBRTC_VIDEO_CODEC_OK;
371}
372
Erik Språng566124a2018-04-23 12:32:22 +0200373int SimulcastEncoderAdapter::SetRateAllocation(
374 const VideoBitrateAllocation& bitrate,
375 uint32_t new_framerate) {
brandtr5e171752017-05-23 03:32:16 -0700376 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
377
378 if (!Initialized()) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000379 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
brandtr5e171752017-05-23 03:32:16 -0700380 }
sprang647bf432016-11-10 06:46:20 -0800381
brandtr5e171752017-05-23 03:32:16 -0700382 if (new_framerate < 1) {
Erik Språng08127a92016-11-16 16:41:30 +0100383 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700384 }
Erik Språng08127a92016-11-16 16:41:30 +0100385
brandtr5e171752017-05-23 03:32:16 -0700386 if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100387 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700388 }
Erik Språng08127a92016-11-16 16:41:30 +0100389
390 if (bitrate.get_sum_bps() > 0) {
sprang1369c832016-11-10 08:30:33 -0800391 // Make sure the bitrate fits the configured min bitrates. 0 is a special
392 // value that means paused, though, so leave it alone.
brandtr5e171752017-05-23 03:32:16 -0700393 if (bitrate.get_sum_kbps() < codec_.minBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100394 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700395 }
Erik Språng08127a92016-11-16 16:41:30 +0100396
sprang1369c832016-11-10 08:30:33 -0800397 if (codec_.numberOfSimulcastStreams > 0 &&
Erik Språng08127a92016-11-16 16:41:30 +0100398 bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
399 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
sprang1369c832016-11-10 08:30:33 -0800400 }
sprang1369c832016-11-10 08:30:33 -0800401 }
Erik Språng08127a92016-11-16 16:41:30 +0100402
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000403 codec_.maxFramerate = new_framerate;
404
sprang1369c832016-11-10 08:30:33 -0800405 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Erik Språng08127a92016-11-16 16:41:30 +0100406 uint32_t stream_bitrate_kbps =
407 bitrate.GetSpatialLayerSum(stream_idx) / 1000;
408
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000409 // Need a key frame if we have not sent this stream before.
Erik Språng78ce6192016-09-12 16:04:43 +0200410 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000411 streaminfos_[stream_idx].key_frame_request = true;
412 }
Erik Språng78ce6192016-09-12 16:04:43 +0200413 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000414
Erik Språng08127a92016-11-16 16:41:30 +0100415 // Slice the temporal layers out of the full allocation and pass it on to
416 // the encoder handling the current simulcast stream.
Erik Språng566124a2018-04-23 12:32:22 +0200417 VideoBitrateAllocation stream_allocation;
brandtr5e171752017-05-23 03:32:16 -0700418 for (int i = 0; i < kMaxTemporalStreams; ++i) {
erikvarga@webrtc.org01f2ec32017-11-15 14:58:23 +0100419 if (bitrate.HasBitrate(stream_idx, i)) {
420 stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
421 }
brandtr5e171752017-05-23 03:32:16 -0700422 }
Erik Språng08127a92016-11-16 16:41:30 +0100423 streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
424 new_framerate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000425 }
426
427 return WEBRTC_VIDEO_CODEC_OK;
428}
429
brandtr5e171752017-05-23 03:32:16 -0700430// TODO(brandtr): Add task checker to this member function, when all encoder
431// callbacks are coming in on the encoder queue.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700432EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
Noah Richards41ee1ea2015-04-15 09:24:26 -0700433 size_t stream_idx,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000434 const EncodedImage& encodedImage,
435 const CodecSpecificInfo* codecSpecificInfo,
436 const RTPFragmentationHeader* fragmentation) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000437 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
perkj275afc52016-09-01 00:21:16 -0700438 stream_codec_specific.codec_name = implementation_name_.c_str();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000439 CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8);
440 vp8Info->simulcastIdx = stream_idx;
441
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700442 return encoded_complete_callback_->OnEncodedImage(
Peter Boström5d0379d2015-10-06 14:04:51 +0200443 encodedImage, &stream_codec_specific, fragmentation);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000444}
445
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000446void SimulcastEncoderAdapter::PopulateStreamCodec(
brandtr5e171752017-05-23 03:32:16 -0700447 const webrtc::VideoCodec& inst,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000448 int stream_index,
Erik Språng78ce6192016-09-12 16:04:43 +0200449 uint32_t start_bitrate_kbps,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000450 bool highest_resolution_stream,
Erik Språng78ce6192016-09-12 16:04:43 +0200451 webrtc::VideoCodec* stream_codec) {
brandtr5e171752017-05-23 03:32:16 -0700452 *stream_codec = inst;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000453
454 // Stream specific settings.
hta257dc392016-10-25 09:05:06 -0700455 stream_codec->VP8()->numberOfTemporalLayers =
brandtr5e171752017-05-23 03:32:16 -0700456 inst.simulcastStream[stream_index].numberOfTemporalLayers;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000457 stream_codec->numberOfSimulcastStreams = 0;
brandtr5e171752017-05-23 03:32:16 -0700458 stream_codec->width = inst.simulcastStream[stream_index].width;
459 stream_codec->height = inst.simulcastStream[stream_index].height;
460 stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
461 stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
462 stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000463 // Settings that are based on stream/resolution.
brandtr5e171752017-05-23 03:32:16 -0700464 const bool lowest_resolution_stream = (stream_index == 0);
465 if (lowest_resolution_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000466 // Settings for lowest spatial resolutions.
467 stream_codec->qpMax = kLowestResMaxQp;
468 }
469 if (!highest_resolution_stream) {
470 // For resolutions below CIF, set the codec |complexity| parameter to
471 // kComplexityHigher, which maps to cpu_used = -4.
472 int pixels_per_frame = stream_codec->width * stream_codec->height;
473 if (pixels_per_frame < 352 * 288) {
Niels Möllere3cf3d02018-06-13 11:52:16 +0200474 stream_codec->VP8()->complexity =
475 webrtc::VideoCodecComplexity::kComplexityHigher;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000476 }
477 // Turn off denoising for all streams but the highest resolution.
hta257dc392016-10-25 09:05:06 -0700478 stream_codec->VP8()->denoisingOn = false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000479 }
480 // TODO(ronghuawu): what to do with targetBitrate.
481
Erik Språng78ce6192016-09-12 16:04:43 +0200482 stream_codec->startBitrate = start_bitrate_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000483}
484
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000485bool SimulcastEncoderAdapter::Initialized() const {
brandtr5e171752017-05-23 03:32:16 -0700486 return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
487}
488
489void SimulcastEncoderAdapter::DestroyStoredEncoders() {
490 while (!stored_encoders_.empty()) {
brandtr5e171752017-05-23 03:32:16 -0700491 stored_encoders_.pop();
492 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000493}
494
pbos65e15ba2015-10-15 10:52:15 -0700495bool SimulcastEncoderAdapter::SupportsNativeHandle() const {
brandtr5e171752017-05-23 03:32:16 -0700496 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos65e15ba2015-10-15 10:52:15 -0700497 // We should not be calling this method before streaminfos_ are configured.
498 RTC_DCHECK(!streaminfos_.empty());
noahricfe3654d2016-07-01 09:05:54 -0700499 for (const auto& streaminfo : streaminfos_) {
brandtr5e171752017-05-23 03:32:16 -0700500 if (!streaminfo.encoder->SupportsNativeHandle()) {
noahricfe3654d2016-07-01 09:05:54 -0700501 return false;
brandtr5e171752017-05-23 03:32:16 -0700502 }
noahricfe3654d2016-07-01 09:05:54 -0700503 }
504 return true;
pbos65e15ba2015-10-15 10:52:15 -0700505}
506
kthelgason876222f2016-11-29 01:44:11 -0800507VideoEncoder::ScalingSettings SimulcastEncoderAdapter::GetScalingSettings()
508 const {
brandtr5e171752017-05-23 03:32:16 -0700509 // TODO(brandtr): Investigate why the sequence checker below fails on mac.
510 // RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -0800511 // Turn off quality scaling for simulcast.
brandtr5e171752017-05-23 03:32:16 -0700512 if (!Initialized() || NumberOfStreams(codec_) != 1) {
Niels Möller225c7872018-02-22 15:03:53 +0100513 return VideoEncoder::ScalingSettings::kOff;
brandtr5e171752017-05-23 03:32:16 -0700514 }
kthelgason876222f2016-11-29 01:44:11 -0800515 return streaminfos_[0].encoder->GetScalingSettings();
516}
517
pbosecd21b42016-01-07 08:03:05 -0800518const char* SimulcastEncoderAdapter::ImplementationName() const {
brandtr5e171752017-05-23 03:32:16 -0700519 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
Peter Boströma5dec162016-01-20 15:53:55 +0100520 return implementation_name_.c_str();
pbosecd21b42016-01-07 08:03:05 -0800521}
522
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000523} // namespace webrtc