• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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