blob: ea54e662938db73229e1d2347c210a1e67043e88 [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"
Magnus Jedvertdf4883d2017-11-17 14:44:55 +010017#include "api/video_codecs/video_encoder_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "media/engine/scopedvideoencoder.h"
19#include "modules/video_coding/codecs/vp8/screenshare_layers.h"
20#include "modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
21#include "rtc_base/checks.h"
22#include "system_wrappers/include/clock.h"
Mirko Bonadei65432062017-12-11 09:32:13 +010023#include "third_party/libyuv/include/libyuv/scale.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000024
25namespace {
26
27const unsigned int kDefaultMinQp = 2;
28const unsigned int kDefaultMaxQp = 56;
29// Max qp for lowest spatial resolution when doing simulcast.
30const unsigned int kLowestResMaxQp = 45;
31
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000032uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
33 uint32_t bitrate_sum = 0;
34 for (int i = 0; i < streams; ++i) {
35 bitrate_sum += codec.simulcastStream[i].maxBitrate;
36 }
37 return bitrate_sum;
38}
39
40int NumberOfStreams(const webrtc::VideoCodec& codec) {
41 int streams =
42 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
43 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
44 if (simulcast_max_bitrate == 0) {
45 streams = 1;
46 }
47 return streams;
48}
49
50bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec,
51 int num_streams) {
52 if (codec.width != codec.simulcastStream[num_streams - 1].width ||
53 codec.height != codec.simulcastStream[num_streams - 1].height) {
54 return false;
55 }
56 for (int i = 0; i < num_streams; ++i) {
57 if (codec.width * codec.simulcastStream[i].height !=
58 codec.height * codec.simulcastStream[i].width) {
59 return false;
60 }
61 }
62 return true;
63}
64
65int VerifyCodec(const webrtc::VideoCodec* inst) {
brandtr5e171752017-05-23 03:32:16 -070066 if (inst == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000067 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
68 }
69 if (inst->maxFramerate < 1) {
70 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
71 }
72 // allow zero to represent an unspecified maxBitRate
73 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
74 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
75 }
76 if (inst->width <= 1 || inst->height <= 1) {
77 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
78 }
hta257dc392016-10-25 09:05:06 -070079 if (inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000080 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
81 }
82 return WEBRTC_VIDEO_CODEC_OK;
83}
84
Noah Richards41ee1ea2015-04-15 09:24:26 -070085// An EncodedImageCallback implementation that forwards on calls to a
86// SimulcastEncoderAdapter, but with the stream index it's registered with as
87// the first parameter to Encoded.
88class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
89 public:
90 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
91 size_t stream_idx)
92 : adapter_(adapter), stream_idx_(stream_idx) {}
93
Sergey Ulanov525df3f2016-08-02 17:46:41 -070094 EncodedImageCallback::Result OnEncodedImage(
95 const webrtc::EncodedImage& encoded_image,
96 const webrtc::CodecSpecificInfo* codec_specific_info,
97 const webrtc::RTPFragmentationHeader* fragmentation) override {
98 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
99 codec_specific_info, fragmentation);
Noah Richards41ee1ea2015-04-15 09:24:26 -0700100 }
101
102 private:
103 webrtc::SimulcastEncoderAdapter* const adapter_;
104 const size_t stream_idx_;
105};
106
Erik Språng08127a92016-11-16 16:41:30 +0100107// Utility class used to adapt the simulcast id as reported by the temporal
108// layers factory, since each sub-encoder will report stream 0.
109class TemporalLayersFactoryAdapter : public webrtc::TemporalLayersFactory {
110 public:
111 TemporalLayersFactoryAdapter(int adapted_simulcast_id,
112 const TemporalLayersFactory& tl_factory)
113 : adapted_simulcast_id_(adapted_simulcast_id), tl_factory_(tl_factory) {}
114 ~TemporalLayersFactoryAdapter() override {}
115 webrtc::TemporalLayers* Create(int simulcast_id,
116 int temporal_layers,
117 uint8_t initial_tl0_pic_idx) const override {
118 return tl_factory_.Create(adapted_simulcast_id_, temporal_layers,
119 initial_tl0_pic_idx);
120 }
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +0200121 std::unique_ptr<webrtc::TemporalLayersChecker> CreateChecker(
122 int simulcast_id,
123 int temporal_layers,
124 uint8_t initial_tl0_pic_idx) const override {
125 return tl_factory_.CreateChecker(adapted_simulcast_id_, temporal_layers,
126 initial_tl0_pic_idx);
127 }
Erik Språng08127a92016-11-16 16:41:30 +0100128
129 const int adapted_simulcast_id_;
130 const TemporalLayersFactory& tl_factory_;
131};
132
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000133} // namespace
134
135namespace webrtc {
136
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100137SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory)
138 : inited_(0),
139 factory_(factory),
140 cricket_factory_(nullptr),
141 encoded_complete_callback_(nullptr),
142 implementation_name_("SimulcastEncoderAdapter") {
143 // The adapter is typically created on the worker thread, but operated on
144 // the encoder task queue.
145 encoder_queue_.Detach();
146
147 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
148}
149
Zhi Huangaea84f52017-11-16 18:46:27 +0000150SimulcastEncoderAdapter::SimulcastEncoderAdapter(
151 cricket::WebRtcVideoEncoderFactory* factory)
brandtr5e171752017-05-23 03:32:16 -0700152 : inited_(0),
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100153 factory_(nullptr),
154 cricket_factory_(factory),
Erik Språng78ce6192016-09-12 16:04:43 +0200155 encoded_complete_callback_(nullptr),
Peter Boströma5dec162016-01-20 15:53:55 +0100156 implementation_name_("SimulcastEncoderAdapter") {
brandtr5e171752017-05-23 03:32:16 -0700157 // The adapter is typically created on the worker thread, but operated on
158 // the encoder task queue.
159 encoder_queue_.Detach();
160
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000161 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
162}
163
164SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
brandtr5e171752017-05-23 03:32:16 -0700165 RTC_DCHECK(!Initialized());
166 DestroyStoredEncoders();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000167}
168
169int SimulcastEncoderAdapter::Release() {
brandtr5e171752017-05-23 03:32:16 -0700170 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
171
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000172 while (!streaminfos_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700173 std::unique_ptr<VideoEncoder> encoder =
174 std::move(streaminfos_.back().encoder);
brandtr5e171752017-05-23 03:32:16 -0700175 // Even though it seems very unlikely, there are no guarantees that the
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200176 // encoder will not call back after being Release()'d. Therefore, we first
177 // disable the callbacks here.
brandtr5e171752017-05-23 03:32:16 -0700178 encoder->RegisterEncodeCompleteCallback(nullptr);
Rasmus Brandt9cf9f752017-09-28 13:02:58 +0200179 encoder->Release();
brandtr5e171752017-05-23 03:32:16 -0700180 streaminfos_.pop_back(); // Deletes callback adapter.
magjed3f897582017-08-28 08:05:42 -0700181 stored_encoders_.push(std::move(encoder));
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000182 }
brandtr5e171752017-05-23 03:32:16 -0700183
184 // It's legal to move the encoder to another queue now.
185 encoder_queue_.Detach();
186
187 rtc::AtomicOps::ReleaseStore(&inited_, 0);
188
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000189 return WEBRTC_VIDEO_CODEC_OK;
190}
191
192int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
193 int number_of_cores,
194 size_t max_payload_size) {
brandtr5e171752017-05-23 03:32:16 -0700195 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
196
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000197 if (number_of_cores < 1) {
198 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
199 }
200
201 int ret = VerifyCodec(inst);
202 if (ret < 0) {
203 return ret;
204 }
205
206 ret = Release();
207 if (ret < 0) {
208 return ret;
209 }
210
211 int number_of_streams = NumberOfStreams(*inst);
brandtr5e171752017-05-23 03:32:16 -0700212 RTC_DCHECK_LE(number_of_streams, kMaxSimulcastStreams);
Peter Boströmd53c3892016-03-30 17:03:52 +0200213 const bool doing_simulcast = (number_of_streams > 1);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000214
215 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
216 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
217 }
218
219 codec_ = *inst;
Erik Språng08127a92016-11-16 16:41:30 +0100220 SimulcastRateAllocator rate_allocator(codec_, nullptr);
221 BitrateAllocation allocation = rate_allocator.GetAllocation(
222 codec_.startBitrate * 1000, codec_.maxFramerate);
223 std::vector<uint32_t> start_bitrates;
224 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
225 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
226 start_bitrates.push_back(stream_bitrate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000227 }
228
Peter Boströma5dec162016-01-20 15:53:55 +0100229 std::string implementation_name;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000230 // Create |number_of_streams| of encoder instances and init them.
231 for (int i = 0; i < number_of_streams; ++i) {
232 VideoCodec stream_codec;
Erik Språng78ce6192016-09-12 16:04:43 +0200233 uint32_t start_bitrate_kbps = start_bitrates[i];
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000234 if (!doing_simulcast) {
235 stream_codec = codec_;
236 stream_codec.numberOfSimulcastStreams = 1;
237 } else {
Erik Språng78ce6192016-09-12 16:04:43 +0200238 // Cap start bitrate to the min bitrate in order to avoid strange codec
239 // behavior. Since sending sending will be false, this should not matter.
240 start_bitrate_kbps =
241 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000242 bool highest_resolution_stream = (i == (number_of_streams - 1));
brandtr5e171752017-05-23 03:32:16 -0700243 PopulateStreamCodec(codec_, i, start_bitrate_kbps,
Erik Språng78ce6192016-09-12 16:04:43 +0200244 highest_resolution_stream, &stream_codec);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000245 }
Erik Språng08127a92016-11-16 16:41:30 +0100246 TemporalLayersFactoryAdapter tl_factory_adapter(i,
247 *codec_.VP8()->tl_factory);
248 stream_codec.VP8()->tl_factory = &tl_factory_adapter;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000249
250 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl.
251 if (stream_codec.qpMax < kDefaultMinQp) {
252 stream_codec.qpMax = kDefaultMaxQp;
253 }
254
brandtr5e171752017-05-23 03:32:16 -0700255 // If an existing encoder instance exists, reuse it.
256 // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
257 // when we start storing that state outside the encoder wrappers.
magjed3f897582017-08-28 08:05:42 -0700258 std::unique_ptr<VideoEncoder> encoder;
brandtr5e171752017-05-23 03:32:16 -0700259 if (!stored_encoders_.empty()) {
magjed3f897582017-08-28 08:05:42 -0700260 encoder = std::move(stored_encoders_.top());
brandtr5e171752017-05-23 03:32:16 -0700261 stored_encoders_.pop();
262 } else {
Magnus Jedvertdf4883d2017-11-17 14:44:55 +0100263 encoder = factory_ ? factory_->CreateVideoEncoder(SdpVideoFormat("VP8"))
264 : CreateScopedVideoEncoder(cricket_factory_,
265 cricket::VideoCodec("VP8"));
brandtr5e171752017-05-23 03:32:16 -0700266 }
267
philipelcce46fc2015-12-21 03:04:49 -0800268 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000269 if (ret < 0) {
noahrice5ba75a2016-12-12 13:08:27 -0800270 // Explicitly destroy the current encoder; because we haven't registered a
271 // StreamInfo for it yet, Release won't do anything about it.
magjed3f897582017-08-28 08:05:42 -0700272 encoder.reset();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000273 Release();
274 return ret;
275 }
brandtr5e171752017-05-23 03:32:16 -0700276 std::unique_ptr<EncodedImageCallback> callback(
277 new AdapterEncodedImageCallback(this, i));
278 encoder->RegisterEncodeCompleteCallback(callback.get());
magjed3f897582017-08-28 08:05:42 -0700279 streaminfos_.emplace_back(std::move(encoder), std::move(callback),
280 stream_codec.width, stream_codec.height,
281 start_bitrate_kbps > 0);
brandtr5e171752017-05-23 03:32:16 -0700282
283 if (i != 0) {
Peter Boströma5dec162016-01-20 15:53:55 +0100284 implementation_name += ", ";
brandtr5e171752017-05-23 03:32:16 -0700285 }
Peter Boströma5dec162016-01-20 15:53:55 +0100286 implementation_name += streaminfos_[i].encoder->ImplementationName();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000287 }
brandtr5e171752017-05-23 03:32:16 -0700288
Peter Boströmd53c3892016-03-30 17:03:52 +0200289 if (doing_simulcast) {
290 implementation_name_ =
291 "SimulcastEncoderAdapter (" + implementation_name + ")";
292 } else {
293 implementation_name_ = implementation_name;
294 }
brandtr5e171752017-05-23 03:32:16 -0700295
296 // To save memory, don't store encoders that we don't use.
297 DestroyStoredEncoders();
298
299 rtc::AtomicOps::ReleaseStore(&inited_, 1);
300
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000301 return WEBRTC_VIDEO_CODEC_OK;
302}
303
304int SimulcastEncoderAdapter::Encode(
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700305 const VideoFrame& input_image,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000306 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700307 const std::vector<FrameType>* frame_types) {
brandtr5e171752017-05-23 03:32:16 -0700308 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
309
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000310 if (!Initialized()) {
311 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
312 }
brandtr5e171752017-05-23 03:32:16 -0700313 if (encoded_complete_callback_ == nullptr) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000314 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
315 }
316
317 // All active streams should generate a key frame if
318 // a key frame is requested by any stream.
319 bool send_key_frame = false;
320 if (frame_types) {
321 for (size_t i = 0; i < frame_types->size(); ++i) {
Peter Boström49e196a2015-10-23 15:58:18 +0200322 if (frame_types->at(i) == kVideoFrameKey) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000323 send_key_frame = true;
324 break;
325 }
326 }
327 }
328 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
329 if (streaminfos_[stream_idx].key_frame_request &&
330 streaminfos_[stream_idx].send_stream) {
331 send_key_frame = true;
332 break;
333 }
334 }
335
336 int src_width = input_image.width();
337 int src_height = input_image.height();
338 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200339 // Don't encode frames in resolutions that we don't intend to send.
brandtr5e171752017-05-23 03:32:16 -0700340 if (!streaminfos_[stream_idx].send_stream) {
Peter Boström5d0379d2015-10-06 14:04:51 +0200341 continue;
brandtr5e171752017-05-23 03:32:16 -0700342 }
Peter Boström5d0379d2015-10-06 14:04:51 +0200343
pbos22993e12015-10-19 02:39:06 -0700344 std::vector<FrameType> stream_frame_types;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000345 if (send_key_frame) {
Peter Boström49e196a2015-10-23 15:58:18 +0200346 stream_frame_types.push_back(kVideoFrameKey);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000347 streaminfos_[stream_idx].key_frame_request = false;
348 } else {
Peter Boström49e196a2015-10-23 15:58:18 +0200349 stream_frame_types.push_back(kVideoFrameDelta);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000350 }
351
352 int dst_width = streaminfos_[stream_idx].width;
353 int dst_height = streaminfos_[stream_idx].height;
354 // If scaling isn't required, because the input resolution
355 // matches the destination or the input image is empty (e.g.
356 // a keyframe request for encoders with internal camera
noahricfe3654d2016-07-01 09:05:54 -0700357 // sources) or the source image has a native handle, pass the image on
358 // directly. Otherwise, we'll scale it to match what the encoder expects
359 // (below).
360 // For texture frames, the underlying encoder is expected to be able to
361 // correctly sample/scale the source texture.
362 // TODO(perkj): ensure that works going forward, and figure out how this
363 // affects webrtc:5683.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000364 if ((dst_width == src_width && dst_height == src_height) ||
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000365 input_image.video_frame_buffer()->type() ==
366 VideoFrameBuffer::Type::kNative) {
noahric57779102016-05-25 06:48:46 -0700367 int ret = streaminfos_[stream_idx].encoder->Encode(
368 input_image, codec_specific_info, &stream_frame_types);
369 if (ret != WEBRTC_VIDEO_CODEC_OK) {
370 return ret;
371 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000372 } else {
nisse64ec8f82016-09-27 00:17:25 -0700373 rtc::scoped_refptr<I420Buffer> dst_buffer =
Magnus Jedvert72dbe2a2017-06-10 17:03:37 +0000374 I420Buffer::Create(dst_width, dst_height);
375 rtc::scoped_refptr<I420BufferInterface> src_buffer =
376 input_image.video_frame_buffer()->ToI420();
377 libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
378 src_buffer->DataU(), src_buffer->StrideU(),
379 src_buffer->DataV(), src_buffer->StrideV(), src_width,
380 src_height, dst_buffer->MutableDataY(),
381 dst_buffer->StrideY(), dst_buffer->MutableDataU(),
382 dst_buffer->StrideU(), dst_buffer->MutableDataV(),
383 dst_buffer->StrideV(), dst_width, dst_height,
nissec9c142f2016-05-17 04:05:47 -0700384 libyuv::kFilterBilinear);
nisse64ec8f82016-09-27 00:17:25 -0700385
noahric57779102016-05-25 06:48:46 -0700386 int ret = streaminfos_[stream_idx].encoder->Encode(
nisse64ec8f82016-09-27 00:17:25 -0700387 VideoFrame(dst_buffer, input_image.timestamp(),
388 input_image.render_time_ms(), webrtc::kVideoRotation_0),
389 codec_specific_info, &stream_frame_types);
noahric57779102016-05-25 06:48:46 -0700390 if (ret != WEBRTC_VIDEO_CODEC_OK) {
391 return ret;
392 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000393 }
394 }
395
396 return WEBRTC_VIDEO_CODEC_OK;
397}
398
399int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
400 EncodedImageCallback* callback) {
brandtr5e171752017-05-23 03:32:16 -0700401 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000402 encoded_complete_callback_ = callback;
403 return WEBRTC_VIDEO_CODEC_OK;
404}
405
406int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000407 int64_t rtt) {
brandtr5e171752017-05-23 03:32:16 -0700408 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000409 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
410 streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt);
411 }
412 return WEBRTC_VIDEO_CODEC_OK;
413}
414
Erik Språng08127a92016-11-16 16:41:30 +0100415int SimulcastEncoderAdapter::SetRateAllocation(const BitrateAllocation& bitrate,
416 uint32_t new_framerate) {
brandtr5e171752017-05-23 03:32:16 -0700417 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
418
419 if (!Initialized()) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000420 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
brandtr5e171752017-05-23 03:32:16 -0700421 }
sprang647bf432016-11-10 06:46:20 -0800422
brandtr5e171752017-05-23 03:32:16 -0700423 if (new_framerate < 1) {
Erik Språng08127a92016-11-16 16:41:30 +0100424 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700425 }
Erik Språng08127a92016-11-16 16:41:30 +0100426
brandtr5e171752017-05-23 03:32:16 -0700427 if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100428 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700429 }
Erik Språng08127a92016-11-16 16:41:30 +0100430
431 if (bitrate.get_sum_bps() > 0) {
sprang1369c832016-11-10 08:30:33 -0800432 // Make sure the bitrate fits the configured min bitrates. 0 is a special
433 // value that means paused, though, so leave it alone.
brandtr5e171752017-05-23 03:32:16 -0700434 if (bitrate.get_sum_kbps() < codec_.minBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +0100435 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
brandtr5e171752017-05-23 03:32:16 -0700436 }
Erik Språng08127a92016-11-16 16:41:30 +0100437
sprang1369c832016-11-10 08:30:33 -0800438 if (codec_.numberOfSimulcastStreams > 0 &&
Erik Språng08127a92016-11-16 16:41:30 +0100439 bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
440 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
sprang1369c832016-11-10 08:30:33 -0800441 }
sprang1369c832016-11-10 08:30:33 -0800442 }
Erik Språng08127a92016-11-16 16:41:30 +0100443
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000444 codec_.maxFramerate = new_framerate;
445
sprang1369c832016-11-10 08:30:33 -0800446 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
Erik Språng08127a92016-11-16 16:41:30 +0100447 uint32_t stream_bitrate_kbps =
448 bitrate.GetSpatialLayerSum(stream_idx) / 1000;
449
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000450 // Need a key frame if we have not sent this stream before.
Erik Språng78ce6192016-09-12 16:04:43 +0200451 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000452 streaminfos_[stream_idx].key_frame_request = true;
453 }
Erik Språng78ce6192016-09-12 16:04:43 +0200454 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000455
Erik Språng08127a92016-11-16 16:41:30 +0100456 // Slice the temporal layers out of the full allocation and pass it on to
457 // the encoder handling the current simulcast stream.
458 BitrateAllocation stream_allocation;
brandtr5e171752017-05-23 03:32:16 -0700459 for (int i = 0; i < kMaxTemporalStreams; ++i) {
erikvarga@webrtc.org01f2ec32017-11-15 14:58:23 +0100460 if (bitrate.HasBitrate(stream_idx, i)) {
461 stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
462 }
brandtr5e171752017-05-23 03:32:16 -0700463 }
Erik Språng08127a92016-11-16 16:41:30 +0100464 streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
465 new_framerate);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000466 }
467
468 return WEBRTC_VIDEO_CODEC_OK;
469}
470
brandtr5e171752017-05-23 03:32:16 -0700471// TODO(brandtr): Add task checker to this member function, when all encoder
472// callbacks are coming in on the encoder queue.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700473EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
Noah Richards41ee1ea2015-04-15 09:24:26 -0700474 size_t stream_idx,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000475 const EncodedImage& encodedImage,
476 const CodecSpecificInfo* codecSpecificInfo,
477 const RTPFragmentationHeader* fragmentation) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000478 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
perkj275afc52016-09-01 00:21:16 -0700479 stream_codec_specific.codec_name = implementation_name_.c_str();
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000480 CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8);
481 vp8Info->simulcastIdx = stream_idx;
482
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700483 return encoded_complete_callback_->OnEncodedImage(
Peter Boström5d0379d2015-10-06 14:04:51 +0200484 encodedImage, &stream_codec_specific, fragmentation);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000485}
486
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000487void SimulcastEncoderAdapter::PopulateStreamCodec(
brandtr5e171752017-05-23 03:32:16 -0700488 const webrtc::VideoCodec& inst,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000489 int stream_index,
Erik Språng78ce6192016-09-12 16:04:43 +0200490 uint32_t start_bitrate_kbps,
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000491 bool highest_resolution_stream,
Erik Språng78ce6192016-09-12 16:04:43 +0200492 webrtc::VideoCodec* stream_codec) {
brandtr5e171752017-05-23 03:32:16 -0700493 *stream_codec = inst;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000494
495 // Stream specific settings.
hta257dc392016-10-25 09:05:06 -0700496 stream_codec->VP8()->numberOfTemporalLayers =
brandtr5e171752017-05-23 03:32:16 -0700497 inst.simulcastStream[stream_index].numberOfTemporalLayers;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000498 stream_codec->numberOfSimulcastStreams = 0;
brandtr5e171752017-05-23 03:32:16 -0700499 stream_codec->width = inst.simulcastStream[stream_index].width;
500 stream_codec->height = inst.simulcastStream[stream_index].height;
501 stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
502 stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
503 stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000504 // Settings that are based on stream/resolution.
brandtr5e171752017-05-23 03:32:16 -0700505 const bool lowest_resolution_stream = (stream_index == 0);
506 if (lowest_resolution_stream) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000507 // Settings for lowest spatial resolutions.
508 stream_codec->qpMax = kLowestResMaxQp;
509 }
510 if (!highest_resolution_stream) {
511 // For resolutions below CIF, set the codec |complexity| parameter to
512 // kComplexityHigher, which maps to cpu_used = -4.
513 int pixels_per_frame = stream_codec->width * stream_codec->height;
514 if (pixels_per_frame < 352 * 288) {
hta257dc392016-10-25 09:05:06 -0700515 stream_codec->VP8()->complexity = webrtc::kComplexityHigher;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000516 }
517 // Turn off denoising for all streams but the highest resolution.
hta257dc392016-10-25 09:05:06 -0700518 stream_codec->VP8()->denoisingOn = false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000519 }
520 // TODO(ronghuawu): what to do with targetBitrate.
521
Erik Språng78ce6192016-09-12 16:04:43 +0200522 stream_codec->startBitrate = start_bitrate_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000523}
524
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000525bool SimulcastEncoderAdapter::Initialized() const {
brandtr5e171752017-05-23 03:32:16 -0700526 return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
527}
528
529void SimulcastEncoderAdapter::DestroyStoredEncoders() {
530 while (!stored_encoders_.empty()) {
brandtr5e171752017-05-23 03:32:16 -0700531 stored_encoders_.pop();
532 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000533}
534
pbos65e15ba2015-10-15 10:52:15 -0700535bool SimulcastEncoderAdapter::SupportsNativeHandle() const {
brandtr5e171752017-05-23 03:32:16 -0700536 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
pbos65e15ba2015-10-15 10:52:15 -0700537 // We should not be calling this method before streaminfos_ are configured.
538 RTC_DCHECK(!streaminfos_.empty());
noahricfe3654d2016-07-01 09:05:54 -0700539 for (const auto& streaminfo : streaminfos_) {
brandtr5e171752017-05-23 03:32:16 -0700540 if (!streaminfo.encoder->SupportsNativeHandle()) {
noahricfe3654d2016-07-01 09:05:54 -0700541 return false;
brandtr5e171752017-05-23 03:32:16 -0700542 }
noahricfe3654d2016-07-01 09:05:54 -0700543 }
544 return true;
pbos65e15ba2015-10-15 10:52:15 -0700545}
546
kthelgason876222f2016-11-29 01:44:11 -0800547VideoEncoder::ScalingSettings SimulcastEncoderAdapter::GetScalingSettings()
548 const {
brandtr5e171752017-05-23 03:32:16 -0700549 // TODO(brandtr): Investigate why the sequence checker below fails on mac.
550 // RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -0800551 // Turn off quality scaling for simulcast.
brandtr5e171752017-05-23 03:32:16 -0700552 if (!Initialized() || NumberOfStreams(codec_) != 1) {
kthelgason876222f2016-11-29 01:44:11 -0800553 return VideoEncoder::ScalingSettings(false);
brandtr5e171752017-05-23 03:32:16 -0700554 }
kthelgason876222f2016-11-29 01:44:11 -0800555 return streaminfos_[0].encoder->GetScalingSettings();
556}
557
pbosecd21b42016-01-07 08:03:05 -0800558const char* SimulcastEncoderAdapter::ImplementationName() const {
brandtr5e171752017-05-23 03:32:16 -0700559 RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
Peter Boströma5dec162016-01-20 15:53:55 +0100560 return implementation_name_.c_str();
pbosecd21b42016-01-07 08:03:05 -0800561}
562
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000563} // namespace webrtc