blob: c33dfdd7703a373e1ac48f4a08cdcac38e2d51be [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
magjed6cc25612017-07-10 03:26:36 -070011#include "webrtc/media/engine/simulcast_encoder_adapter.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000012
13#include <algorithm>
14
15// NOTE(ajm): Path provided by gyp.
16#include "libyuv/scale.h" // NOLINT
17
nisseaf916892017-01-10 07:44:26 -080018#include "webrtc/api/video/i420_buffer.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000019#include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
kjellandera8d8aad2017-03-08 05:42:26 -080020#include "webrtc/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020021#include "webrtc/rtc_base/checks.h"
sprangb0fdfea2016-03-01 05:51:16 -080022#include "webrtc/system_wrappers/include/clock.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000023
24namespace {
25
26const unsigned int kDefaultMinQp = 2;
27const unsigned int kDefaultMaxQp = 56;
28// Max qp for lowest spatial resolution when doing simulcast.
29const unsigned int kLowestResMaxQp = 45;
30
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000031uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
32 uint32_t bitrate_sum = 0;
33 for (int i = 0; i < streams; ++i) {
34 bitrate_sum += codec.simulcastStream[i].maxBitrate;
35 }
36 return bitrate_sum;
37}
38
39int NumberOfStreams(const webrtc::VideoCodec& codec) {
40 int streams =
41 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
42 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
43 if (simulcast_max_bitrate == 0) {
44 streams = 1;
45 }
46 return streams;
47}
48
49bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec,
50 int num_streams) {
51 if (codec.width != codec.simulcastStream[num_streams - 1].width ||
52 codec.height != codec.simulcastStream[num_streams - 1].height) {
53 return false;
54 }
55 for (int i = 0; i < num_streams; ++i) {
56 if (codec.width * codec.simulcastStream[i].height !=
57 codec.height * codec.simulcastStream[i].width) {
58 return false;
59 }
60 }
61 return true;
62}
63
64int VerifyCodec(const webrtc::VideoCodec* inst) {
brandtr5e171752017-05-23 03:32:16 -070065 if (inst == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000066 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
67 }
68 if (inst->maxFramerate < 1) {
69 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
70 }
71 // allow zero to represent an unspecified maxBitRate
72 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
73 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
74 }
75 if (inst->width <= 1 || inst->height <= 1) {
76 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
77 }
hta257dc392016-10-25 09:05:06 -070078 if (inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000079 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
80 }
81 return WEBRTC_VIDEO_CODEC_OK;
82}
83
Noah Richards41ee1ea2015-04-15 09:24:26 -070084// An EncodedImageCallback implementation that forwards on calls to a
85// SimulcastEncoderAdapter, but with the stream index it's registered with as
86// the first parameter to Encoded.
87class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
88 public:
89 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
90 size_t stream_idx)
91 : adapter_(adapter), stream_idx_(stream_idx) {}
92
Sergey Ulanov525df3f2016-08-02 17:46:41 -070093 EncodedImageCallback::Result OnEncodedImage(
94 const webrtc::EncodedImage& encoded_image,
95 const webrtc::CodecSpecificInfo* codec_specific_info,
96 const webrtc::RTPFragmentationHeader* fragmentation) override {
97 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
98 codec_specific_info, fragmentation);
Noah Richards41ee1ea2015-04-15 09:24:26 -070099 }
100
101 private:
102 webrtc::SimulcastEncoderAdapter* const adapter_;
103 const size_t stream_idx_;
104};
105
Erik Språng08127a92016-11-16 16:41:30 +0100106// Utility class used to adapt the simulcast id as reported by the temporal
107// layers factory, since each sub-encoder will report stream 0.
108class TemporalLayersFactoryAdapter : public webrtc::TemporalLayersFactory {
109 public:
110 TemporalLayersFactoryAdapter(int adapted_simulcast_id,
111 const TemporalLayersFactory& tl_factory)
112 : adapted_simulcast_id_(adapted_simulcast_id), tl_factory_(tl_factory) {}
113 ~TemporalLayersFactoryAdapter() override {}
114 webrtc::TemporalLayers* Create(int simulcast_id,
115 int temporal_layers,
116 uint8_t initial_tl0_pic_idx) const override {
117 return tl_factory_.Create(adapted_simulcast_id_, temporal_layers,
118 initial_tl0_pic_idx);
119 }
120
121 const int adapted_simulcast_id_;
122 const TemporalLayersFactory& tl_factory_;
123};
124
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000125} // namespace
126
127namespace webrtc {
128
magjed6cc25612017-07-10 03:26:36 -0700129SimulcastEncoderAdapter::SimulcastEncoderAdapter(
130 cricket::WebRtcVideoEncoderFactory* factory)
brandtr5e171752017-05-23 03:32:16 -0700131 : inited_(0),
132 factory_(factory),
Erik Språng78ce6192016-09-12 16:04:43 +0200133 encoded_complete_callback_(nullptr),
Peter Boströma5dec162016-01-20 15:53:55 +0100134 implementation_name_("SimulcastEncoderAdapter") {
brandtr5e171752017-05-23 03:32:16 -0700135 // The adapter is typically created on the worker thread, but operated on
136 // the encoder task queue.
137 encoder_queue_.Detach();
138
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000139 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
140}
141
142SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
brandtr5e171752017-05-23 03:32:16 -0700143 RTC_DCHECK(!Initialized());
144 DestroyStoredEncoders();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000145}
146
147int SimulcastEncoderAdapter::Release() {
brandtr5e171752017-05-23 03:32:16 -0700148 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
149
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000150 while (!streaminfos_.empty()) {
151 VideoEncoder* encoder = streaminfos_.back().encoder;
sakal02f994b2017-02-23 02:25:20 -0800152 encoder->Release();
brandtr5e171752017-05-23 03:32:16 -0700153 // Even though it seems very unlikely, there are no guarantees that the
154 // encoder will not call back after being Release()'d. Therefore, we disable
155 // the callbacks here.
156 encoder->RegisterEncodeCompleteCallback(nullptr);
157 streaminfos_.pop_back(); // Deletes callback adapter.
158 stored_encoders_.push(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) {
brandtr5e171752017-05-23 03:32:16 -0700172 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
173
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
192 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
193 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
194 }
195
196 codec_ = *inst;
Erik Språng08127a92016-11-16 16:41:30 +0100197 SimulcastRateAllocator rate_allocator(codec_, nullptr);
198 BitrateAllocation allocation = rate_allocator.GetAllocation(
199 codec_.startBitrate * 1000, codec_.maxFramerate);
200 std::vector<uint32_t> start_bitrates;
201 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
202 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
203 start_bitrates.push_back(stream_bitrate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000204 }
205
Peter Boströma5dec162016-01-20 15:53:55 +0100206 std::string implementation_name;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000207 // Create |number_of_streams| of encoder instances and init them.
208 for (int i = 0; i < number_of_streams; ++i) {
209 VideoCodec stream_codec;
Erik Språng78ce6192016-09-12 16:04:43 +0200210 uint32_t start_bitrate_kbps = start_bitrates[i];
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000211 if (!doing_simulcast) {
212 stream_codec = codec_;
213 stream_codec.numberOfSimulcastStreams = 1;
214 } else {
Erik Språng78ce6192016-09-12 16:04:43 +0200215 // Cap start bitrate to the min bitrate in order to avoid strange codec
216 // behavior. Since sending sending will be false, this should not matter.
217 start_bitrate_kbps =
218 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000219 bool highest_resolution_stream = (i == (number_of_streams - 1));
brandtr5e171752017-05-23 03:32:16 -0700220 PopulateStreamCodec(codec_, i, start_bitrate_kbps,
Erik Språng78ce6192016-09-12 16:04:43 +0200221 highest_resolution_stream, &stream_codec);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000222 }
Erik Språng08127a92016-11-16 16:41:30 +0100223 TemporalLayersFactoryAdapter tl_factory_adapter(i,
224 *codec_.VP8()->tl_factory);
225 stream_codec.VP8()->tl_factory = &tl_factory_adapter;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000226
227 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl.
228 if (stream_codec.qpMax < kDefaultMinQp) {
229 stream_codec.qpMax = kDefaultMaxQp;
230 }
231
brandtr5e171752017-05-23 03:32:16 -0700232 // If an existing encoder instance exists, reuse it.
233 // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
234 // when we start storing that state outside the encoder wrappers.
235 VideoEncoder* encoder;
236 if (!stored_encoders_.empty()) {
237 encoder = stored_encoders_.top();
238 stored_encoders_.pop();
239 } else {
magjed6cc25612017-07-10 03:26:36 -0700240 encoder = factory_->CreateVideoEncoder(cricket::VideoCodec("VP8"));
brandtr5e171752017-05-23 03:32:16 -0700241 }
242
philipelcce46fc2015-12-21 03:04:49 -0800243 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000244 if (ret < 0) {
noahrice5ba75a2016-12-12 13:08:27 -0800245 // Explicitly destroy the current encoder; because we haven't registered a
246 // StreamInfo for it yet, Release won't do anything about it.
magjed6cc25612017-07-10 03:26:36 -0700247 factory_->DestroyVideoEncoder(encoder);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000248 Release();
249 return ret;
250 }
brandtr5e171752017-05-23 03:32:16 -0700251 std::unique_ptr<EncodedImageCallback> callback(
252 new AdapterEncodedImageCallback(this, i));
253 encoder->RegisterEncodeCompleteCallback(callback.get());
254 streaminfos_.emplace_back(encoder, std::move(callback), stream_codec.width,
255 stream_codec.height, start_bitrate_kbps > 0);
256
257 if (i != 0) {
Peter Boströma5dec162016-01-20 15:53:55 +0100258 implementation_name += ", ";
brandtr5e171752017-05-23 03:32:16 -0700259 }
Peter Boströma5dec162016-01-20 15:53:55 +0100260 implementation_name += streaminfos_[i].encoder->ImplementationName();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000261 }
brandtr5e171752017-05-23 03:32:16 -0700262
Peter Boströmd53c3892016-03-30 17:03:52 +0200263 if (doing_simulcast) {
264 implementation_name_ =
265 "SimulcastEncoderAdapter (" + implementation_name + ")";
266 } else {
267 implementation_name_ = implementation_name;
268 }
brandtr5e171752017-05-23 03:32:16 -0700269
270 // To save memory, don't store encoders that we don't use.
271 DestroyStoredEncoders();
272
273 rtc::AtomicOps::ReleaseStore(&inited_, 1);
274
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000275 return WEBRTC_VIDEO_CODEC_OK;
276}
277
278int SimulcastEncoderAdapter::Encode(
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700279 const VideoFrame& input_image,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000280 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700281 const std::vector<FrameType>* frame_types) {
brandtr5e171752017-05-23 03:32:16 -0700282 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
283
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000284 if (!Initialized()) {
285 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
286 }
brandtr5e171752017-05-23 03:32:16 -0700287 if (encoded_complete_callback_ == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000288 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
289 }
290
291 // All active streams should generate a key frame if
292 // a key frame is requested by any stream.
293 bool send_key_frame = false;
294 if (frame_types) {
295 for (size_t i = 0; i < frame_types->size(); ++i) {
Peter Boström49e196a2015-10-23 15:58:18 +0200296 if (frame_types->at(i) == kVideoFrameKey) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000297 send_key_frame = true;
298 break;
299 }
300 }
301 }
302 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
303 if (streaminfos_[stream_idx].key_frame_request &&
304 streaminfos_[stream_idx].send_stream) {
305 send_key_frame = true;
306 break;
307 }
308 }
309
310 int src_width = input_image.width();
311 int src_height = input_image.height();
312 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200313 // Don't encode frames in resolutions that we don't intend to send.
brandtr5e171752017-05-23 03:32:16 -0700314 if (!streaminfos_[stream_idx].send_stream) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200315 continue;
brandtr5e171752017-05-23 03:32:16 -0700316 }
Peter Boström5d0379d2015-10-06 14:04:51 +0200317
pbos22993e12015-10-19 02:39:06 -0700318 std::vector<FrameType> stream_frame_types;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000319 if (send_key_frame) {
Peter Boström49e196a2015-10-23 15:58:18 +0200320 stream_frame_types.push_back(kVideoFrameKey);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000321 streaminfos_[stream_idx].key_frame_request = false;
322 } else {
Peter Boström49e196a2015-10-23 15:58:18 +0200323 stream_frame_types.push_back(kVideoFrameDelta);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000324 }
325
326 int dst_width = streaminfos_[stream_idx].width;
327 int dst_height = streaminfos_[stream_idx].height;
328 // If scaling isn't required, because the input resolution
329 // matches the destination or the input image is empty (e.g.
330 // a keyframe request for encoders with internal camera
noahricfe3654d2016-07-01 09:05:54 -0700331 // sources) or the source image has a native handle, pass the image on
332 // directly. Otherwise, we'll scale it to match what the encoder expects
333 // (below).
334 // For texture frames, the underlying encoder is expected to be able to
335 // correctly sample/scale the source texture.
336 // TODO(perkj): ensure that works going forward, and figure out how this
337 // affects webrtc:5683.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000338 if ((dst_width == src_width && dst_height == src_height) ||
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000339 input_image.video_frame_buffer()->type() ==
340 VideoFrameBuffer::Type::kNative) {
noahric57779102016-05-25 06:48:46 -0700341 int ret = streaminfos_[stream_idx].encoder->Encode(
342 input_image, codec_specific_info, &stream_frame_types);
343 if (ret != WEBRTC_VIDEO_CODEC_OK) {
344 return ret;
345 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000346 } else {
nisse64ec8f82016-09-27 00:17:25 -0700347 rtc::scoped_refptr<I420Buffer> dst_buffer =
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000348 I420Buffer::Create(dst_width, dst_height);
349 rtc::scoped_refptr<I420BufferInterface> src_buffer =
350 input_image.video_frame_buffer()->ToI420();
351 libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
352 src_buffer->DataU(), src_buffer->StrideU(),
353 src_buffer->DataV(), src_buffer->StrideV(), src_width,
354 src_height, dst_buffer->MutableDataY(),
355 dst_buffer->StrideY(), dst_buffer->MutableDataU(),
356 dst_buffer->StrideU(), dst_buffer->MutableDataV(),
357 dst_buffer->StrideV(), dst_width, dst_height,
nissec9c142f2016-05-17 04:05:47 -0700358 libyuv::kFilterBilinear);
nisse64ec8f82016-09-27 00:17:25 -0700359
noahric57779102016-05-25 06:48:46 -0700360 int ret = streaminfos_[stream_idx].encoder->Encode(
nisse64ec8f82016-09-27 00:17:25 -0700361 VideoFrame(dst_buffer, input_image.timestamp(),
362 input_image.render_time_ms(), webrtc::kVideoRotation_0),
363 codec_specific_info, &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700364 if (ret != WEBRTC_VIDEO_CODEC_OK) {
365 return ret;
366 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000367 }
368 }
369
370 return WEBRTC_VIDEO_CODEC_OK;
371}
372
373int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
374 EncodedImageCallback* callback) {
brandtr5e171752017-05-23 03:32:16 -0700375 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000376 encoded_complete_callback_ = callback;
377 return WEBRTC_VIDEO_CODEC_OK;
378}
379
380int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000381 int64_t rtt) {
brandtr5e171752017-05-23 03:32:16 -0700382 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000383 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
384 streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt);
385 }
386 return WEBRTC_VIDEO_CODEC_OK;
387}
388
Erik Språng08127a92016-11-16 16:41:30 +0100389int SimulcastEncoderAdapter::SetRateAllocation(const BitrateAllocation& bitrate,
390 uint32_t new_framerate) {
brandtr5e171752017-05-23 03:32:16 -0700391 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
392
393 if (!Initialized()) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000394 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
brandtr5e171752017-05-23 03:32:16 -0700395 }
sprang647bf432016-11-10 06:46:20 -0800396
brandtr5e171752017-05-23 03:32:16 -0700397 if (new_framerate < 1) {
Erik Språng08127a92016-11-16 16:41:30 +0100398 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700399 }
Erik Språng08127a92016-11-16 16:41:30 +0100400
brandtr5e171752017-05-23 03:32:16 -0700401 if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100402 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700403 }
Erik Språng08127a92016-11-16 16:41:30 +0100404
405 if (bitrate.get_sum_bps() > 0) {
sprang1369c832016-11-10 08:30:33 -0800406 // Make sure the bitrate fits the configured min bitrates. 0 is a special
407 // value that means paused, though, so leave it alone.
brandtr5e171752017-05-23 03:32:16 -0700408 if (bitrate.get_sum_kbps() < codec_.minBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100409 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700410 }
Erik Språng08127a92016-11-16 16:41:30 +0100411
sprang1369c832016-11-10 08:30:33 -0800412 if (codec_.numberOfSimulcastStreams > 0 &&
Erik Språng08127a92016-11-16 16:41:30 +0100413 bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
414 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
sprang1369c832016-11-10 08:30:33 -0800415 }
sprang1369c832016-11-10 08:30:33 -0800416 }
Erik Språng08127a92016-11-16 16:41:30 +0100417
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000418 codec_.maxFramerate = new_framerate;
419
sprang1369c832016-11-10 08:30:33 -0800420 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Erik Språng08127a92016-11-16 16:41:30 +0100421 uint32_t stream_bitrate_kbps =
422 bitrate.GetSpatialLayerSum(stream_idx) / 1000;
423
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000424 // Need a key frame if we have not sent this stream before.
Erik Språng78ce6192016-09-12 16:04:43 +0200425 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000426 streaminfos_[stream_idx].key_frame_request = true;
427 }
Erik Språng78ce6192016-09-12 16:04:43 +0200428 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000429
Erik Språng08127a92016-11-16 16:41:30 +0100430 // Slice the temporal layers out of the full allocation and pass it on to
431 // the encoder handling the current simulcast stream.
432 BitrateAllocation stream_allocation;
brandtr5e171752017-05-23 03:32:16 -0700433 for (int i = 0; i < kMaxTemporalStreams; ++i) {
Erik Språng08127a92016-11-16 16:41:30 +0100434 stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
brandtr5e171752017-05-23 03:32:16 -0700435 }
Erik Språng08127a92016-11-16 16:41:30 +0100436 streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
437 new_framerate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000438 }
439
440 return WEBRTC_VIDEO_CODEC_OK;
441}
442
brandtr5e171752017-05-23 03:32:16 -0700443// TODO(brandtr): Add task checker to this member function, when all encoder
444// callbacks are coming in on the encoder queue.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700445EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
Noah Richards41ee1ea2015-04-15 09:24:26 -0700446 size_t stream_idx,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000447 const EncodedImage& encodedImage,
448 const CodecSpecificInfo* codecSpecificInfo,
449 const RTPFragmentationHeader* fragmentation) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000450 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
perkj275afc52016-09-01 00:21:16 -0700451 stream_codec_specific.codec_name = implementation_name_.c_str();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000452 CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8);
453 vp8Info->simulcastIdx = stream_idx;
454
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700455 return encoded_complete_callback_->OnEncodedImage(
Peter Boström5d0379d2015-10-06 14:04:51 +0200456 encodedImage, &stream_codec_specific, fragmentation);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000457}
458
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000459void SimulcastEncoderAdapter::PopulateStreamCodec(
brandtr5e171752017-05-23 03:32:16 -0700460 const webrtc::VideoCodec& inst,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000461 int stream_index,
Erik Språng78ce6192016-09-12 16:04:43 +0200462 uint32_t start_bitrate_kbps,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000463 bool highest_resolution_stream,
Erik Språng78ce6192016-09-12 16:04:43 +0200464 webrtc::VideoCodec* stream_codec) {
brandtr5e171752017-05-23 03:32:16 -0700465 *stream_codec = inst;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000466
467 // Stream specific settings.
hta257dc392016-10-25 09:05:06 -0700468 stream_codec->VP8()->numberOfTemporalLayers =
brandtr5e171752017-05-23 03:32:16 -0700469 inst.simulcastStream[stream_index].numberOfTemporalLayers;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000470 stream_codec->numberOfSimulcastStreams = 0;
brandtr5e171752017-05-23 03:32:16 -0700471 stream_codec->width = inst.simulcastStream[stream_index].width;
472 stream_codec->height = inst.simulcastStream[stream_index].height;
473 stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
474 stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
475 stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000476 // Settings that are based on stream/resolution.
brandtr5e171752017-05-23 03:32:16 -0700477 const bool lowest_resolution_stream = (stream_index == 0);
478 if (lowest_resolution_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000479 // Settings for lowest spatial resolutions.
480 stream_codec->qpMax = kLowestResMaxQp;
481 }
482 if (!highest_resolution_stream) {
483 // For resolutions below CIF, set the codec |complexity| parameter to
484 // kComplexityHigher, which maps to cpu_used = -4.
485 int pixels_per_frame = stream_codec->width * stream_codec->height;
486 if (pixels_per_frame < 352 * 288) {
hta257dc392016-10-25 09:05:06 -0700487 stream_codec->VP8()->complexity = webrtc::kComplexityHigher;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000488 }
489 // Turn off denoising for all streams but the highest resolution.
hta257dc392016-10-25 09:05:06 -0700490 stream_codec->VP8()->denoisingOn = false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000491 }
492 // TODO(ronghuawu): what to do with targetBitrate.
493
Erik Språng78ce6192016-09-12 16:04:43 +0200494 stream_codec->startBitrate = start_bitrate_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000495}
496
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000497bool SimulcastEncoderAdapter::Initialized() const {
brandtr5e171752017-05-23 03:32:16 -0700498 return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
499}
500
501void SimulcastEncoderAdapter::DestroyStoredEncoders() {
502 while (!stored_encoders_.empty()) {
503 VideoEncoder* encoder = stored_encoders_.top();
magjed6cc25612017-07-10 03:26:36 -0700504 factory_->DestroyVideoEncoder(encoder);
brandtr5e171752017-05-23 03:32:16 -0700505 stored_encoders_.pop();
506 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000507}
508
pbos65e15ba2015-10-15 10:52:15 -0700509bool SimulcastEncoderAdapter::SupportsNativeHandle() const {
brandtr5e171752017-05-23 03:32:16 -0700510 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos65e15ba2015-10-15 10:52:15 -0700511 // We should not be calling this method before streaminfos_ are configured.
512 RTC_DCHECK(!streaminfos_.empty());
noahricfe3654d2016-07-01 09:05:54 -0700513 for (const auto& streaminfo : streaminfos_) {
brandtr5e171752017-05-23 03:32:16 -0700514 if (!streaminfo.encoder->SupportsNativeHandle()) {
noahricfe3654d2016-07-01 09:05:54 -0700515 return false;
brandtr5e171752017-05-23 03:32:16 -0700516 }
noahricfe3654d2016-07-01 09:05:54 -0700517 }
518 return true;
pbos65e15ba2015-10-15 10:52:15 -0700519}
520
kthelgason876222f2016-11-29 01:44:11 -0800521VideoEncoder::ScalingSettings SimulcastEncoderAdapter::GetScalingSettings()
522 const {
brandtr5e171752017-05-23 03:32:16 -0700523 // TODO(brandtr): Investigate why the sequence checker below fails on mac.
524 // RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -0800525 // Turn off quality scaling for simulcast.
brandtr5e171752017-05-23 03:32:16 -0700526 if (!Initialized() || NumberOfStreams(codec_) != 1) {
kthelgason876222f2016-11-29 01:44:11 -0800527 return VideoEncoder::ScalingSettings(false);
brandtr5e171752017-05-23 03:32:16 -0700528 }
kthelgason876222f2016-11-29 01:44:11 -0800529 return streaminfos_[0].encoder->GetScalingSettings();
530}
531
pbosecd21b42016-01-07 08:03:05 -0800532const char* SimulcastEncoderAdapter::ImplementationName() const {
brandtr5e171752017-05-23 03:32:16 -0700533 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
Peter Boströma5dec162016-01-20 15:53:55 +0100534 return implementation_name_.c_str();
pbosecd21b42016-01-07 08:03:05 -0800535}
536
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000537} // namespace webrtc