1 /*
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
11 #include "media/engine/simulcast_encoder_adapter.h"
12
13 #include <stdio.h>
14 #include <string.h>
15
16 #include <algorithm>
17 #include <cstdint>
18 #include <string>
19 #include <utility>
20
21 #include "absl/algorithm/container.h"
22 #include "api/scoped_refptr.h"
23 #include "api/video/i420_buffer.h"
24 #include "api/video/video_codec_constants.h"
25 #include "api/video/video_frame_buffer.h"
26 #include "api/video/video_rotation.h"
27 #include "api/video_codecs/video_encoder.h"
28 #include "api/video_codecs/video_encoder_factory.h"
29 #include "api/video_codecs/video_encoder_software_fallback_wrapper.h"
30 #include "media/base/video_common.h"
31 #include "modules/video_coding/include/video_error_codes.h"
32 #include "modules/video_coding/utility/simulcast_rate_allocator.h"
33 #include "rtc_base/checks.h"
34 #include "rtc_base/experiments/rate_control_settings.h"
35 #include "rtc_base/logging.h"
36 #include "system_wrappers/include/field_trial.h"
37
38 namespace {
39
40 const unsigned int kDefaultMinQp = 2;
41 const unsigned int kDefaultMaxQp = 56;
42 // Max qp for lowest spatial resolution when doing simulcast.
43 const unsigned int kLowestResMaxQp = 45;
44
GetScreenshareBoostedQpValue()45 absl::optional<unsigned int> GetScreenshareBoostedQpValue() {
46 std::string experiment_group =
47 webrtc::field_trial::FindFullName("WebRTC-BoostedScreenshareQp");
48 unsigned int qp;
49 if (sscanf(experiment_group.c_str(), "%u", &qp) != 1)
50 return absl::nullopt;
51 qp = std::min(qp, 63u);
52 qp = std::max(qp, 1u);
53 return qp;
54 }
55
SumStreamMaxBitrate(int streams,const webrtc::VideoCodec & codec)56 uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
57 uint32_t bitrate_sum = 0;
58 for (int i = 0; i < streams; ++i) {
59 bitrate_sum += codec.simulcastStream[i].maxBitrate;
60 }
61 return bitrate_sum;
62 }
63
CountAllStreams(const webrtc::VideoCodec & codec)64 int CountAllStreams(const webrtc::VideoCodec& codec) {
65 int total_streams_count =
66 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
67 uint32_t simulcast_max_bitrate =
68 SumStreamMaxBitrate(total_streams_count, codec);
69 if (simulcast_max_bitrate == 0) {
70 total_streams_count = 1;
71 }
72 return total_streams_count;
73 }
74
CountActiveStreams(const webrtc::VideoCodec & codec)75 int CountActiveStreams(const webrtc::VideoCodec& codec) {
76 if (codec.numberOfSimulcastStreams < 1) {
77 return 1;
78 }
79 int total_streams_count = CountAllStreams(codec);
80 int active_streams_count = 0;
81 for (int i = 0; i < total_streams_count; ++i) {
82 if (codec.simulcastStream[i].active) {
83 ++active_streams_count;
84 }
85 }
86 return active_streams_count;
87 }
88
VerifyCodec(const webrtc::VideoCodec * inst)89 int VerifyCodec(const webrtc::VideoCodec* inst) {
90 if (inst == nullptr) {
91 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
92 }
93 if (inst->maxFramerate < 1) {
94 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
95 }
96 // allow zero to represent an unspecified maxBitRate
97 if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
98 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
99 }
100 if (inst->width <= 1 || inst->height <= 1) {
101 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
102 }
103 if (inst->codecType == webrtc::kVideoCodecVP8 &&
104 inst->VP8().automaticResizeOn && CountActiveStreams(*inst) > 1) {
105 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
106 }
107 return WEBRTC_VIDEO_CODEC_OK;
108 }
109
StreamQualityCompare(const webrtc::SimulcastStream & a,const webrtc::SimulcastStream & b)110 bool StreamQualityCompare(const webrtc::SimulcastStream& a,
111 const webrtc::SimulcastStream& b) {
112 return std::tie(a.height, a.width, a.maxBitrate, a.maxFramerate) <
113 std::tie(b.height, b.width, b.maxBitrate, b.maxFramerate);
114 }
115
GetLowestAndHighestQualityStreamIndixes(rtc::ArrayView<webrtc::SimulcastStream> streams,int * lowest_quality_stream_idx,int * highest_quality_stream_idx)116 void GetLowestAndHighestQualityStreamIndixes(
117 rtc::ArrayView<webrtc::SimulcastStream> streams,
118 int* lowest_quality_stream_idx,
119 int* highest_quality_stream_idx) {
120 const auto lowest_highest_quality_streams =
121 absl::c_minmax_element(streams, StreamQualityCompare);
122 *lowest_quality_stream_idx =
123 std::distance(streams.begin(), lowest_highest_quality_streams.first);
124 *highest_quality_stream_idx =
125 std::distance(streams.begin(), lowest_highest_quality_streams.second);
126 }
127
GetStreamStartBitratesKbps(const webrtc::VideoCodec & codec)128 std::vector<uint32_t> GetStreamStartBitratesKbps(
129 const webrtc::VideoCodec& codec) {
130 std::vector<uint32_t> start_bitrates;
131 std::unique_ptr<webrtc::VideoBitrateAllocator> rate_allocator =
132 std::make_unique<webrtc::SimulcastRateAllocator>(codec);
133 webrtc::VideoBitrateAllocation allocation =
134 rate_allocator->Allocate(webrtc::VideoBitrateAllocationParameters(
135 codec.startBitrate * 1000, codec.maxFramerate));
136
137 int total_streams_count = CountAllStreams(codec);
138 for (int i = 0; i < total_streams_count; ++i) {
139 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
140 start_bitrates.push_back(stream_bitrate);
141 }
142 return start_bitrates;
143 }
144
145 } // namespace
146
147 namespace webrtc {
148
EncoderContext(std::unique_ptr<VideoEncoder> encoder,bool prefer_temporal_support,VideoEncoder::EncoderInfo primary_info,VideoEncoder::EncoderInfo fallback_info)149 SimulcastEncoderAdapter::EncoderContext::EncoderContext(
150 std::unique_ptr<VideoEncoder> encoder,
151 bool prefer_temporal_support,
152 VideoEncoder::EncoderInfo primary_info,
153 VideoEncoder::EncoderInfo fallback_info)
154 : encoder_(std::move(encoder)),
155 prefer_temporal_support_(prefer_temporal_support),
156 primary_info_(std::move(primary_info)),
157 fallback_info_(std::move(fallback_info)) {}
158
Release()159 void SimulcastEncoderAdapter::EncoderContext::Release() {
160 if (encoder_) {
161 encoder_->Release();
162 encoder_->RegisterEncodeCompleteCallback(nullptr);
163 }
164 }
165
StreamContext(SimulcastEncoderAdapter * parent,std::unique_ptr<EncoderContext> encoder_context,std::unique_ptr<FramerateController> framerate_controller,int stream_idx,uint16_t width,uint16_t height,bool is_paused)166 SimulcastEncoderAdapter::StreamContext::StreamContext(
167 SimulcastEncoderAdapter* parent,
168 std::unique_ptr<EncoderContext> encoder_context,
169 std::unique_ptr<FramerateController> framerate_controller,
170 int stream_idx,
171 uint16_t width,
172 uint16_t height,
173 bool is_paused)
174 : parent_(parent),
175 encoder_context_(std::move(encoder_context)),
176 framerate_controller_(std::move(framerate_controller)),
177 stream_idx_(stream_idx),
178 width_(width),
179 height_(height),
180 is_keyframe_needed_(false),
181 is_paused_(is_paused) {
182 if (parent_) {
183 encoder_context_->encoder().RegisterEncodeCompleteCallback(this);
184 }
185 }
186
StreamContext(StreamContext && rhs)187 SimulcastEncoderAdapter::StreamContext::StreamContext(StreamContext&& rhs)
188 : parent_(rhs.parent_),
189 encoder_context_(std::move(rhs.encoder_context_)),
190 framerate_controller_(std::move(rhs.framerate_controller_)),
191 stream_idx_(rhs.stream_idx_),
192 width_(rhs.width_),
193 height_(rhs.height_),
194 is_keyframe_needed_(rhs.is_keyframe_needed_),
195 is_paused_(rhs.is_paused_) {
196 if (parent_) {
197 encoder_context_->encoder().RegisterEncodeCompleteCallback(this);
198 }
199 }
200
~StreamContext()201 SimulcastEncoderAdapter::StreamContext::~StreamContext() {
202 if (encoder_context_) {
203 encoder_context_->Release();
204 }
205 }
206
207 std::unique_ptr<SimulcastEncoderAdapter::EncoderContext>
ReleaseEncoderContext()208 SimulcastEncoderAdapter::StreamContext::ReleaseEncoderContext() && {
209 encoder_context_->Release();
210 return std::move(encoder_context_);
211 }
212
OnKeyframe(Timestamp timestamp)213 void SimulcastEncoderAdapter::StreamContext::OnKeyframe(Timestamp timestamp) {
214 is_keyframe_needed_ = false;
215 if (framerate_controller_) {
216 framerate_controller_->KeepFrame(timestamp.us() * 1000);
217 }
218 }
219
ShouldDropFrame(Timestamp timestamp)220 bool SimulcastEncoderAdapter::StreamContext::ShouldDropFrame(
221 Timestamp timestamp) {
222 if (!framerate_controller_) {
223 return false;
224 }
225 return framerate_controller_->ShouldDropFrame(timestamp.us() * 1000);
226 }
227
228 EncodedImageCallback::Result
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)229 SimulcastEncoderAdapter::StreamContext::OnEncodedImage(
230 const EncodedImage& encoded_image,
231 const CodecSpecificInfo* codec_specific_info) {
232 RTC_CHECK(parent_); // If null, this method should never be called.
233 return parent_->OnEncodedImage(stream_idx_, encoded_image,
234 codec_specific_info);
235 }
236
OnDroppedFrame(DropReason)237 void SimulcastEncoderAdapter::StreamContext::OnDroppedFrame(
238 DropReason /*reason*/) {
239 RTC_CHECK(parent_); // If null, this method should never be called.
240 parent_->OnDroppedFrame(stream_idx_);
241 }
242
SimulcastEncoderAdapter(VideoEncoderFactory * factory,const SdpVideoFormat & format)243 SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory,
244 const SdpVideoFormat& format)
245 : SimulcastEncoderAdapter(factory, nullptr, format) {}
246
SimulcastEncoderAdapter(VideoEncoderFactory * primary_factory,VideoEncoderFactory * fallback_factory,const SdpVideoFormat & format)247 SimulcastEncoderAdapter::SimulcastEncoderAdapter(
248 VideoEncoderFactory* primary_factory,
249 VideoEncoderFactory* fallback_factory,
250 const SdpVideoFormat& format)
251 : inited_(0),
252 primary_encoder_factory_(primary_factory),
253 fallback_encoder_factory_(fallback_factory),
254 video_format_(format),
255 total_streams_count_(0),
256 bypass_mode_(false),
257 encoded_complete_callback_(nullptr),
258 experimental_boosted_screenshare_qp_(GetScreenshareBoostedQpValue()),
259 boost_base_layer_quality_(RateControlSettings::ParseFromFieldTrials()
260 .Vp8BoostBaseLayerQuality()),
261 prefer_temporal_support_on_base_layer_(field_trial::IsEnabled(
262 "WebRTC-Video-PreferTemporalSupportOnBaseLayer")) {
263 RTC_DCHECK(primary_factory);
264
265 // The adapter is typically created on the worker thread, but operated on
266 // the encoder task queue.
267 encoder_queue_.Detach();
268 }
269
~SimulcastEncoderAdapter()270 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
271 RTC_DCHECK(!Initialized());
272 DestroyStoredEncoders();
273 }
274
SetFecControllerOverride(FecControllerOverride *)275 void SimulcastEncoderAdapter::SetFecControllerOverride(
276 FecControllerOverride* /*fec_controller_override*/) {
277 // Ignored.
278 }
279
Release()280 int SimulcastEncoderAdapter::Release() {
281 RTC_DCHECK_RUN_ON(&encoder_queue_);
282
283 while (!stream_contexts_.empty()) {
284 // Move the encoder instances and put it on the `cached_encoder_contexts_`
285 // where it may possibly be reused from (ordering does not matter).
286 cached_encoder_contexts_.push_front(
287 std::move(stream_contexts_.back()).ReleaseEncoderContext());
288 stream_contexts_.pop_back();
289 }
290
291 bypass_mode_ = false;
292
293 // It's legal to move the encoder to another queue now.
294 encoder_queue_.Detach();
295
296 inited_.store(0);
297
298 return WEBRTC_VIDEO_CODEC_OK;
299 }
300
InitEncode(const VideoCodec * inst,const VideoEncoder::Settings & settings)301 int SimulcastEncoderAdapter::InitEncode(
302 const VideoCodec* inst,
303 const VideoEncoder::Settings& settings) {
304 RTC_DCHECK_RUN_ON(&encoder_queue_);
305
306 if (settings.number_of_cores < 1) {
307 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
308 }
309
310 int ret = VerifyCodec(inst);
311 if (ret < 0) {
312 return ret;
313 }
314
315 Release();
316
317 codec_ = *inst;
318 total_streams_count_ = CountAllStreams(*inst);
319
320 // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder.
321 if (codec_.qpMax < kDefaultMinQp) {
322 codec_.qpMax = kDefaultMaxQp;
323 }
324
325 bool is_legacy_singlecast = codec_.numberOfSimulcastStreams == 0;
326 int lowest_quality_stream_idx = 0;
327 int highest_quality_stream_idx = 0;
328 if (!is_legacy_singlecast) {
329 GetLowestAndHighestQualityStreamIndixes(
330 rtc::ArrayView<SimulcastStream>(codec_.simulcastStream,
331 total_streams_count_),
332 &lowest_quality_stream_idx, &highest_quality_stream_idx);
333 }
334
335 std::unique_ptr<EncoderContext> encoder_context = FetchOrCreateEncoderContext(
336 /*is_lowest_quality_stream=*/(
337 is_legacy_singlecast ||
338 codec_.simulcastStream[lowest_quality_stream_idx].active));
339 if (encoder_context == nullptr) {
340 return WEBRTC_VIDEO_CODEC_MEMORY;
341 }
342
343 // Two distinct scenarios:
344 // * Singlecast (total_streams_count == 1) or simulcast with simulcast-capable
345 // underlaying encoder implementation if active_streams_count > 1. SEA
346 // operates in bypass mode: original settings are passed to the underlaying
347 // encoder, frame encode complete callback is not intercepted.
348 // * Multi-encoder simulcast or singlecast if layers are deactivated
349 // (active_streams_count >= 1). SEA creates N=active_streams_count encoders
350 // and configures each to produce a single stream.
351
352 int active_streams_count = CountActiveStreams(*inst);
353 // If we only have a single active layer it is better to create an encoder
354 // with only one configured layer than creating it with all-but-one disabled
355 // layers because that way we control scaling.
356 bool separate_encoders_needed =
357 !encoder_context->encoder().GetEncoderInfo().supports_simulcast ||
358 active_streams_count == 1;
359 // Singlecast or simulcast with simulcast-capable underlaying encoder.
360 if (total_streams_count_ == 1 || !separate_encoders_needed) {
361 int ret = encoder_context->encoder().InitEncode(&codec_, settings);
362 if (ret >= 0) {
363 stream_contexts_.emplace_back(
364 /*parent=*/nullptr, std::move(encoder_context),
365 /*framerate_controller=*/nullptr, /*stream_idx=*/0, codec_.width,
366 codec_.height, /*is_paused=*/active_streams_count == 0);
367 bypass_mode_ = true;
368
369 DestroyStoredEncoders();
370 inited_.store(1);
371 return WEBRTC_VIDEO_CODEC_OK;
372 }
373
374 encoder_context->Release();
375 if (total_streams_count_ == 1) {
376 // Failed to initialize singlecast encoder.
377 return ret;
378 }
379 }
380
381 // Multi-encoder simulcast or singlecast (deactivated layers).
382 std::vector<uint32_t> stream_start_bitrate_kbps =
383 GetStreamStartBitratesKbps(codec_);
384
385 for (int stream_idx = 0; stream_idx < total_streams_count_; ++stream_idx) {
386 if (!is_legacy_singlecast && !codec_.simulcastStream[stream_idx].active) {
387 continue;
388 }
389
390 if (encoder_context == nullptr) {
391 encoder_context = FetchOrCreateEncoderContext(
392 /*is_lowest_quality_stream=*/stream_idx == lowest_quality_stream_idx);
393 }
394 if (encoder_context == nullptr) {
395 Release();
396 return WEBRTC_VIDEO_CODEC_MEMORY;
397 }
398
399 VideoCodec stream_codec = MakeStreamCodec(
400 codec_, stream_idx, stream_start_bitrate_kbps[stream_idx],
401 /*is_lowest_quality_stream=*/stream_idx == lowest_quality_stream_idx,
402 /*is_highest_quality_stream=*/stream_idx == highest_quality_stream_idx);
403
404 int ret = encoder_context->encoder().InitEncode(&stream_codec, settings);
405 if (ret < 0) {
406 encoder_context.reset();
407 Release();
408 return ret;
409 }
410
411 // Intercept frame encode complete callback only for upper streams, where
412 // we need to set a correct stream index. Set `parent` to nullptr for the
413 // lowest stream to bypass the callback.
414 SimulcastEncoderAdapter* parent = stream_idx > 0 ? this : nullptr;
415
416 bool is_paused = stream_start_bitrate_kbps[stream_idx] == 0;
417 stream_contexts_.emplace_back(
418 parent, std::move(encoder_context),
419 std::make_unique<FramerateController>(stream_codec.maxFramerate),
420 stream_idx, stream_codec.width, stream_codec.height, is_paused);
421 }
422
423 // To save memory, don't store encoders that we don't use.
424 DestroyStoredEncoders();
425
426 inited_.store(1);
427 return WEBRTC_VIDEO_CODEC_OK;
428 }
429
Encode(const VideoFrame & input_image,const std::vector<VideoFrameType> * frame_types)430 int SimulcastEncoderAdapter::Encode(
431 const VideoFrame& input_image,
432 const std::vector<VideoFrameType>* frame_types) {
433 RTC_DCHECK_RUN_ON(&encoder_queue_);
434
435 if (!Initialized()) {
436 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
437 }
438 if (encoded_complete_callback_ == nullptr) {
439 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
440 }
441
442 if (encoder_info_override_.requested_resolution_alignment()) {
443 const int alignment =
444 *encoder_info_override_.requested_resolution_alignment();
445 if (input_image.width() % alignment != 0 ||
446 input_image.height() % alignment != 0) {
447 RTC_LOG(LS_WARNING) << "Frame " << input_image.width() << "x"
448 << input_image.height() << " not divisible by "
449 << alignment;
450 return WEBRTC_VIDEO_CODEC_ERROR;
451 }
452 if (encoder_info_override_.apply_alignment_to_all_simulcast_layers()) {
453 for (const auto& layer : stream_contexts_) {
454 if (layer.width() % alignment != 0 || layer.height() % alignment != 0) {
455 RTC_LOG(LS_WARNING)
456 << "Codec " << layer.width() << "x" << layer.height()
457 << " not divisible by " << alignment;
458 return WEBRTC_VIDEO_CODEC_ERROR;
459 }
460 }
461 }
462 }
463
464 bool is_keyframe_needed = false;
465 for (const auto& layer : stream_contexts_) {
466 if (layer.is_keyframe_needed()) {
467 // This is legacy behavior, generating a keyframe on all layers
468 // when generating one for a layer that became active for the first time
469 // or after being disabled
470 is_keyframe_needed = true;
471 break;
472 }
473 }
474
475 // Temporary thay may hold the result of texture to i420 buffer conversion.
476 rtc::scoped_refptr<VideoFrameBuffer> src_buffer;
477 int src_width = input_image.width();
478 int src_height = input_image.height();
479
480 for (auto& layer : stream_contexts_) {
481 // Don't encode frames in resolutions that we don't intend to send.
482 if (layer.is_paused()) {
483 continue;
484 }
485
486 // Convert timestamp from RTP 90kHz clock.
487 const Timestamp frame_timestamp =
488 Timestamp::Micros((1000 * input_image.timestamp()) / 90);
489
490 // If adapter is passed through and only one sw encoder does simulcast,
491 // frame types for all streams should be passed to the encoder unchanged.
492 // Otherwise a single per-encoder frame type is passed.
493 std::vector<VideoFrameType> stream_frame_types(
494 bypass_mode_ ? total_streams_count_ : 1,
495 VideoFrameType::kVideoFrameDelta);
496 bool keyframe_requested = false;
497 if (is_keyframe_needed) {
498 std::fill(stream_frame_types.begin(), stream_frame_types.end(),
499 VideoFrameType::kVideoFrameKey);
500 keyframe_requested = true;
501 } else if (frame_types) {
502 if (bypass_mode_) {
503 // In bypass mode, requesting a key frame on any layer triggers a
504 // key frame request on all layers.
505 for (const auto& frame_type : *frame_types) {
506 if (frame_type == VideoFrameType::kVideoFrameKey) {
507 std::fill(stream_frame_types.begin(), stream_frame_types.end(),
508 VideoFrameType::kVideoFrameKey);
509 keyframe_requested = true;
510 break;
511 }
512 }
513 } else {
514 size_t stream_idx = static_cast<size_t>(layer.stream_idx());
515 if (frame_types->size() >= stream_idx &&
516 (*frame_types)[stream_idx] == VideoFrameType::kVideoFrameKey) {
517 stream_frame_types[0] = VideoFrameType::kVideoFrameKey;
518 keyframe_requested = true;
519 }
520 }
521 }
522 if (keyframe_requested) {
523 layer.OnKeyframe(frame_timestamp);
524 } else if (layer.ShouldDropFrame(frame_timestamp)) {
525 continue;
526 }
527
528 // If scaling isn't required, because the input resolution
529 // matches the destination or the input image is empty (e.g.
530 // a keyframe request for encoders with internal camera
531 // sources) or the source image has a native handle, pass the image on
532 // directly. Otherwise, we'll scale it to match what the encoder expects
533 // (below).
534 // For texture frames, the underlying encoder is expected to be able to
535 // correctly sample/scale the source texture.
536 // TODO(perkj): ensure that works going forward, and figure out how this
537 // affects webrtc:5683.
538 if ((layer.width() == src_width && layer.height() == src_height) ||
539 (input_image.video_frame_buffer()->type() ==
540 VideoFrameBuffer::Type::kNative &&
541 layer.encoder().GetEncoderInfo().supports_native_handle)) {
542 int ret = layer.encoder().Encode(input_image, &stream_frame_types);
543 if (ret != WEBRTC_VIDEO_CODEC_OK) {
544 return ret;
545 }
546 } else {
547 if (src_buffer == nullptr) {
548 src_buffer = input_image.video_frame_buffer();
549 }
550 rtc::scoped_refptr<VideoFrameBuffer> dst_buffer =
551 src_buffer->Scale(layer.width(), layer.height());
552 if (!dst_buffer) {
553 RTC_LOG(LS_ERROR) << "Failed to scale video frame";
554 return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
555 }
556
557 // UpdateRect is not propagated to lower simulcast layers currently.
558 // TODO(ilnik): Consider scaling UpdateRect together with the buffer.
559 VideoFrame frame(input_image);
560 frame.set_video_frame_buffer(dst_buffer);
561 frame.set_rotation(webrtc::kVideoRotation_0);
562 frame.set_update_rect(
563 VideoFrame::UpdateRect{0, 0, frame.width(), frame.height()});
564 int ret = layer.encoder().Encode(frame, &stream_frame_types);
565 if (ret != WEBRTC_VIDEO_CODEC_OK) {
566 return ret;
567 }
568 }
569 }
570
571 return WEBRTC_VIDEO_CODEC_OK;
572 }
573
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)574 int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
575 EncodedImageCallback* callback) {
576 RTC_DCHECK_RUN_ON(&encoder_queue_);
577 encoded_complete_callback_ = callback;
578 if (!stream_contexts_.empty() && stream_contexts_.front().stream_idx() == 0) {
579 // Bypass frame encode complete callback for the lowest layer since there is
580 // no need to override frame's spatial index.
581 stream_contexts_.front().encoder().RegisterEncodeCompleteCallback(callback);
582 }
583 return WEBRTC_VIDEO_CODEC_OK;
584 }
585
SetRates(const RateControlParameters & parameters)586 void SimulcastEncoderAdapter::SetRates(
587 const RateControlParameters& parameters) {
588 RTC_DCHECK_RUN_ON(&encoder_queue_);
589
590 if (!Initialized()) {
591 RTC_LOG(LS_WARNING) << "SetRates while not initialized";
592 return;
593 }
594
595 if (parameters.framerate_fps < 1.0) {
596 RTC_LOG(LS_WARNING) << "Invalid framerate: " << parameters.framerate_fps;
597 return;
598 }
599
600 codec_.maxFramerate = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
601
602 if (bypass_mode_) {
603 stream_contexts_.front().encoder().SetRates(parameters);
604 return;
605 }
606
607 for (StreamContext& layer_context : stream_contexts_) {
608 int stream_idx = layer_context.stream_idx();
609 uint32_t stream_bitrate_kbps =
610 parameters.bitrate.GetSpatialLayerSum(stream_idx) / 1000;
611
612 // Need a key frame if we have not sent this stream before.
613 if (stream_bitrate_kbps > 0 && layer_context.is_paused()) {
614 layer_context.set_is_keyframe_needed();
615 }
616 layer_context.set_is_paused(stream_bitrate_kbps == 0);
617
618 // Slice the temporal layers out of the full allocation and pass it on to
619 // the encoder handling the current simulcast stream.
620 RateControlParameters stream_parameters = parameters;
621 stream_parameters.bitrate = VideoBitrateAllocation();
622 for (int i = 0; i < kMaxTemporalStreams; ++i) {
623 if (parameters.bitrate.HasBitrate(stream_idx, i)) {
624 stream_parameters.bitrate.SetBitrate(
625 0, i, parameters.bitrate.GetBitrate(stream_idx, i));
626 }
627 }
628
629 // Assign link allocation proportionally to spatial layer allocation.
630 if (!parameters.bandwidth_allocation.IsZero() &&
631 parameters.bitrate.get_sum_bps() > 0) {
632 stream_parameters.bandwidth_allocation =
633 DataRate::BitsPerSec((parameters.bandwidth_allocation.bps() *
634 stream_parameters.bitrate.get_sum_bps()) /
635 parameters.bitrate.get_sum_bps());
636 // Make sure we don't allocate bandwidth lower than target bitrate.
637 if (stream_parameters.bandwidth_allocation.bps() <
638 stream_parameters.bitrate.get_sum_bps()) {
639 stream_parameters.bandwidth_allocation =
640 DataRate::BitsPerSec(stream_parameters.bitrate.get_sum_bps());
641 }
642 }
643
644 stream_parameters.framerate_fps = std::min<double>(
645 parameters.framerate_fps,
646 layer_context.target_fps().value_or(parameters.framerate_fps));
647
648 layer_context.encoder().SetRates(stream_parameters);
649 }
650 }
651
OnPacketLossRateUpdate(float packet_loss_rate)652 void SimulcastEncoderAdapter::OnPacketLossRateUpdate(float packet_loss_rate) {
653 for (auto& c : stream_contexts_) {
654 c.encoder().OnPacketLossRateUpdate(packet_loss_rate);
655 }
656 }
657
OnRttUpdate(int64_t rtt_ms)658 void SimulcastEncoderAdapter::OnRttUpdate(int64_t rtt_ms) {
659 for (auto& c : stream_contexts_) {
660 c.encoder().OnRttUpdate(rtt_ms);
661 }
662 }
663
OnLossNotification(const LossNotification & loss_notification)664 void SimulcastEncoderAdapter::OnLossNotification(
665 const LossNotification& loss_notification) {
666 for (auto& c : stream_contexts_) {
667 c.encoder().OnLossNotification(loss_notification);
668 }
669 }
670
671 // TODO(brandtr): Add task checker to this member function, when all encoder
672 // callbacks are coming in on the encoder queue.
OnEncodedImage(size_t stream_idx,const EncodedImage & encodedImage,const CodecSpecificInfo * codecSpecificInfo)673 EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
674 size_t stream_idx,
675 const EncodedImage& encodedImage,
676 const CodecSpecificInfo* codecSpecificInfo) {
677 EncodedImage stream_image(encodedImage);
678 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
679
680 stream_image.SetSpatialIndex(stream_idx);
681
682 return encoded_complete_callback_->OnEncodedImage(stream_image,
683 &stream_codec_specific);
684 }
685
OnDroppedFrame(size_t stream_idx)686 void SimulcastEncoderAdapter::OnDroppedFrame(size_t stream_idx) {
687 // Not yet implemented.
688 }
689
Initialized() const690 bool SimulcastEncoderAdapter::Initialized() const {
691 return inited_.load() == 1;
692 }
693
DestroyStoredEncoders()694 void SimulcastEncoderAdapter::DestroyStoredEncoders() {
695 while (!cached_encoder_contexts_.empty()) {
696 cached_encoder_contexts_.pop_back();
697 }
698 }
699
700 std::unique_ptr<SimulcastEncoderAdapter::EncoderContext>
FetchOrCreateEncoderContext(bool is_lowest_quality_stream) const701 SimulcastEncoderAdapter::FetchOrCreateEncoderContext(
702 bool is_lowest_quality_stream) const {
703 bool prefer_temporal_support = fallback_encoder_factory_ != nullptr &&
704 is_lowest_quality_stream &&
705 prefer_temporal_support_on_base_layer_;
706
707 // Toggling of `prefer_temporal_support` requires encoder recreation. Find
708 // and reuse encoder with desired `prefer_temporal_support`. Otherwise, if
709 // there is no such encoder in the cache, create a new instance.
710 auto encoder_context_iter =
711 std::find_if(cached_encoder_contexts_.begin(),
712 cached_encoder_contexts_.end(), [&](auto& encoder_context) {
713 return encoder_context->prefer_temporal_support() ==
714 prefer_temporal_support;
715 });
716
717 std::unique_ptr<SimulcastEncoderAdapter::EncoderContext> encoder_context;
718 if (encoder_context_iter != cached_encoder_contexts_.end()) {
719 encoder_context = std::move(*encoder_context_iter);
720 cached_encoder_contexts_.erase(encoder_context_iter);
721 } else {
722 std::unique_ptr<VideoEncoder> primary_encoder =
723 primary_encoder_factory_->CreateVideoEncoder(video_format_);
724
725 std::unique_ptr<VideoEncoder> fallback_encoder;
726 if (fallback_encoder_factory_ != nullptr) {
727 fallback_encoder =
728 fallback_encoder_factory_->CreateVideoEncoder(video_format_);
729 }
730
731 std::unique_ptr<VideoEncoder> encoder;
732 VideoEncoder::EncoderInfo primary_info;
733 VideoEncoder::EncoderInfo fallback_info;
734
735 if (primary_encoder != nullptr) {
736 primary_info = primary_encoder->GetEncoderInfo();
737 fallback_info = primary_info;
738
739 if (fallback_encoder == nullptr) {
740 encoder = std::move(primary_encoder);
741 } else {
742 encoder = CreateVideoEncoderSoftwareFallbackWrapper(
743 std::move(fallback_encoder), std::move(primary_encoder),
744 prefer_temporal_support);
745 }
746 } else if (fallback_encoder != nullptr) {
747 RTC_LOG(LS_WARNING) << "Failed to create primary " << video_format_.name
748 << " encoder. Use fallback encoder.";
749 fallback_info = fallback_encoder->GetEncoderInfo();
750 primary_info = fallback_info;
751 encoder = std::move(fallback_encoder);
752 } else {
753 RTC_LOG(LS_ERROR) << "Failed to create primary and fallback "
754 << video_format_.name << " encoders.";
755 return nullptr;
756 }
757
758 encoder_context = std::make_unique<SimulcastEncoderAdapter::EncoderContext>(
759 std::move(encoder), prefer_temporal_support, primary_info,
760 fallback_info);
761 }
762
763 encoder_context->encoder().RegisterEncodeCompleteCallback(
764 encoded_complete_callback_);
765 return encoder_context;
766 }
767
MakeStreamCodec(const webrtc::VideoCodec & codec,int stream_idx,uint32_t start_bitrate_kbps,bool is_lowest_quality_stream,bool is_highest_quality_stream)768 webrtc::VideoCodec SimulcastEncoderAdapter::MakeStreamCodec(
769 const webrtc::VideoCodec& codec,
770 int stream_idx,
771 uint32_t start_bitrate_kbps,
772 bool is_lowest_quality_stream,
773 bool is_highest_quality_stream) {
774 webrtc::VideoCodec codec_params = codec;
775 const SimulcastStream& stream_params = codec.simulcastStream[stream_idx];
776
777 codec_params.numberOfSimulcastStreams = 0;
778 codec_params.width = stream_params.width;
779 codec_params.height = stream_params.height;
780 codec_params.maxBitrate = stream_params.maxBitrate;
781 codec_params.minBitrate = stream_params.minBitrate;
782 codec_params.maxFramerate = stream_params.maxFramerate;
783 codec_params.qpMax = stream_params.qpMax;
784 codec_params.active = stream_params.active;
785 codec_params.SetScalabilityMode(stream_params.GetScalabilityMode());
786 // Settings that are based on stream/resolution.
787 if (is_lowest_quality_stream) {
788 // Settings for lowest spatial resolutions.
789 if (codec.mode == VideoCodecMode::kScreensharing) {
790 if (experimental_boosted_screenshare_qp_) {
791 codec_params.qpMax = *experimental_boosted_screenshare_qp_;
792 }
793 } else if (boost_base_layer_quality_) {
794 codec_params.qpMax = kLowestResMaxQp;
795 }
796 }
797 if (codec.codecType == webrtc::kVideoCodecVP8) {
798 codec_params.VP8()->numberOfTemporalLayers =
799 stream_params.numberOfTemporalLayers;
800 if (!is_highest_quality_stream) {
801 // For resolutions below CIF, set the codec `complexity` parameter to
802 // kComplexityHigher, which maps to cpu_used = -4.
803 int pixels_per_frame = codec_params.width * codec_params.height;
804 if (pixels_per_frame < 352 * 288) {
805 codec_params.SetVideoEncoderComplexity(
806 webrtc::VideoCodecComplexity::kComplexityHigher);
807 }
808 // Turn off denoising for all streams but the highest resolution.
809 codec_params.VP8()->denoisingOn = false;
810 }
811 } else if (codec.codecType == webrtc::kVideoCodecH264) {
812 codec_params.H264()->numberOfTemporalLayers =
813 stream_params.numberOfTemporalLayers;
814 }
815
816 // Cap start bitrate to the min bitrate in order to avoid strange codec
817 // behavior.
818 codec_params.startBitrate =
819 std::max(stream_params.minBitrate, start_bitrate_kbps);
820
821 // Legacy screenshare mode is only enabled for the first simulcast layer
822 codec_params.legacy_conference_mode =
823 codec.legacy_conference_mode && stream_idx == 0;
824
825 return codec_params;
826 }
827
OverrideFromFieldTrial(VideoEncoder::EncoderInfo * info) const828 void SimulcastEncoderAdapter::OverrideFromFieldTrial(
829 VideoEncoder::EncoderInfo* info) const {
830 if (encoder_info_override_.requested_resolution_alignment()) {
831 info->requested_resolution_alignment = cricket::LeastCommonMultiple(
832 info->requested_resolution_alignment,
833 *encoder_info_override_.requested_resolution_alignment());
834 info->apply_alignment_to_all_simulcast_layers =
835 info->apply_alignment_to_all_simulcast_layers ||
836 encoder_info_override_.apply_alignment_to_all_simulcast_layers();
837 }
838 // Override resolution bitrate limits unless they're set already.
839 if (info->resolution_bitrate_limits.empty() &&
840 !encoder_info_override_.resolution_bitrate_limits().empty()) {
841 info->resolution_bitrate_limits =
842 encoder_info_override_.resolution_bitrate_limits();
843 }
844 }
845
GetEncoderInfo() const846 VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
847 if (stream_contexts_.size() == 1) {
848 // Not using simulcast adapting functionality, just pass through.
849 VideoEncoder::EncoderInfo info =
850 stream_contexts_.front().encoder().GetEncoderInfo();
851 OverrideFromFieldTrial(&info);
852 return info;
853 }
854
855 VideoEncoder::EncoderInfo encoder_info;
856 encoder_info.implementation_name = "SimulcastEncoderAdapter";
857 encoder_info.requested_resolution_alignment = 1;
858 encoder_info.apply_alignment_to_all_simulcast_layers = false;
859 encoder_info.supports_native_handle = true;
860 encoder_info.scaling_settings.thresholds = absl::nullopt;
861
862 if (stream_contexts_.empty()) {
863 // GetEncoderInfo queried before InitEncode. Only alignment info is needed
864 // to be filled.
865 // Create one encoder and query it.
866
867 std::unique_ptr<SimulcastEncoderAdapter::EncoderContext> encoder_context =
868 FetchOrCreateEncoderContext(/*is_lowest_quality_stream=*/true);
869 if (encoder_context == nullptr) {
870 return encoder_info;
871 }
872
873 const VideoEncoder::EncoderInfo& primary_info =
874 encoder_context->PrimaryInfo();
875 const VideoEncoder::EncoderInfo& fallback_info =
876 encoder_context->FallbackInfo();
877
878 encoder_info.requested_resolution_alignment = cricket::LeastCommonMultiple(
879 primary_info.requested_resolution_alignment,
880 fallback_info.requested_resolution_alignment);
881
882 encoder_info.apply_alignment_to_all_simulcast_layers =
883 primary_info.apply_alignment_to_all_simulcast_layers ||
884 fallback_info.apply_alignment_to_all_simulcast_layers;
885
886 if (!primary_info.supports_simulcast || !fallback_info.supports_simulcast) {
887 encoder_info.apply_alignment_to_all_simulcast_layers = true;
888 }
889
890 cached_encoder_contexts_.emplace_back(std::move(encoder_context));
891
892 OverrideFromFieldTrial(&encoder_info);
893 return encoder_info;
894 }
895
896 encoder_info.scaling_settings = VideoEncoder::ScalingSettings::kOff;
897
898 for (size_t i = 0; i < stream_contexts_.size(); ++i) {
899 VideoEncoder::EncoderInfo encoder_impl_info =
900 stream_contexts_[i].encoder().GetEncoderInfo();
901 if (i == 0) {
902 // Encoder name indicates names of all sub-encoders.
903 encoder_info.implementation_name += " (";
904 encoder_info.implementation_name += encoder_impl_info.implementation_name;
905
906 encoder_info.supports_native_handle =
907 encoder_impl_info.supports_native_handle;
908 encoder_info.has_trusted_rate_controller =
909 encoder_impl_info.has_trusted_rate_controller;
910 encoder_info.is_hardware_accelerated =
911 encoder_impl_info.is_hardware_accelerated;
912 encoder_info.is_qp_trusted = encoder_impl_info.is_qp_trusted;
913 } else {
914 encoder_info.implementation_name += ", ";
915 encoder_info.implementation_name += encoder_impl_info.implementation_name;
916
917 // Native handle supported if any encoder supports it.
918 encoder_info.supports_native_handle |=
919 encoder_impl_info.supports_native_handle;
920
921 // Trusted rate controller only if all encoders have it.
922 encoder_info.has_trusted_rate_controller &=
923 encoder_impl_info.has_trusted_rate_controller;
924
925 // Uses hardware support if any of the encoders uses it.
926 // For example, if we are having issues with down-scaling due to
927 // pipelining delay in HW encoders we need higher encoder usage
928 // thresholds in CPU adaptation.
929 encoder_info.is_hardware_accelerated |=
930 encoder_impl_info.is_hardware_accelerated;
931
932 // Treat QP from frame/slice/tile header as average QP only if all
933 // encoders report it as average QP.
934 encoder_info.is_qp_trusted =
935 encoder_info.is_qp_trusted.value_or(true) &&
936 encoder_impl_info.is_qp_trusted.value_or(true);
937 }
938 encoder_info.fps_allocation[i] = encoder_impl_info.fps_allocation[0];
939 encoder_info.requested_resolution_alignment = cricket::LeastCommonMultiple(
940 encoder_info.requested_resolution_alignment,
941 encoder_impl_info.requested_resolution_alignment);
942 // request alignment on all layers if any of the encoders may need it, or
943 // if any non-top layer encoder requests a non-trivial alignment.
944 if (encoder_impl_info.apply_alignment_to_all_simulcast_layers ||
945 (encoder_impl_info.requested_resolution_alignment > 1 &&
946 (codec_.simulcastStream[i].height < codec_.height ||
947 codec_.simulcastStream[i].width < codec_.width))) {
948 encoder_info.apply_alignment_to_all_simulcast_layers = true;
949 }
950 }
951 encoder_info.implementation_name += ")";
952
953 OverrideFromFieldTrial(&encoder_info);
954
955 return encoder_info;
956 }
957
958 } // namespace webrtc
959