xref: /aosp_15_r20/external/webrtc/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2012 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 "modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h"
12 
13 #include <string.h>
14 
15 #include <algorithm>
16 #include <cstdint>
17 #include <iterator>
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "absl/algorithm/container.h"
24 #include "api/scoped_refptr.h"
25 #include "api/video/video_content_type.h"
26 #include "api/video/video_frame_buffer.h"
27 #include "api/video/video_timing.h"
28 #include "api/video_codecs/vp8_temporal_layers.h"
29 #include "api/video_codecs/vp8_temporal_layers_factory.h"
30 #include "modules/video_coding/codecs/interface/common_constants.h"
31 #include "modules/video_coding/codecs/vp8/include/vp8.h"
32 #include "modules/video_coding/codecs/vp8/vp8_scalability.h"
33 #include "modules/video_coding/include/video_error_codes.h"
34 #include "modules/video_coding/svc/scalability_mode_util.h"
35 #include "modules/video_coding/utility/simulcast_rate_allocator.h"
36 #include "modules/video_coding/utility/simulcast_utility.h"
37 #include "rtc_base/checks.h"
38 #include "rtc_base/experiments/field_trial_parser.h"
39 #include "rtc_base/experiments/field_trial_units.h"
40 #include "rtc_base/logging.h"
41 #include "rtc_base/trace_event.h"
42 #include "system_wrappers/include/field_trial.h"
43 #include "third_party/libyuv/include/libyuv/scale.h"
44 #include "vpx/vp8cx.h"
45 
46 namespace webrtc {
47 namespace {
48 #if defined(WEBRTC_IOS)
49 constexpr char kVP8IosMaxNumberOfThreadFieldTrial[] =
50     "WebRTC-VP8IosMaxNumberOfThread";
51 constexpr char kVP8IosMaxNumberOfThreadFieldTrialParameter[] = "max_thread";
52 #endif
53 
54 constexpr char kVp8ForcePartitionResilience[] =
55     "WebRTC-VP8-ForcePartitionResilience";
56 
57 // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
58 // bitstream range of [0, 127] and not the user-level range of [0,63].
59 constexpr int kLowVp8QpThreshold = 29;
60 constexpr int kHighVp8QpThreshold = 95;
61 
62 constexpr int kTokenPartitions = VP8_ONE_TOKENPARTITION;
63 constexpr uint32_t kVp832ByteAlign = 32u;
64 
65 constexpr int kRtpTicksPerSecond = 90000;
66 constexpr int kRtpTicksPerMs = kRtpTicksPerSecond / 1000;
67 
68 // VP8 denoiser states.
69 enum denoiserState : uint32_t {
70   kDenoiserOff,
71   kDenoiserOnYOnly,
72   kDenoiserOnYUV,
73   kDenoiserOnYUVAggressive,
74   // Adaptive mode defaults to kDenoiserOnYUV on key frame, but may switch
75   // to kDenoiserOnYUVAggressive based on a computed noise metric.
76   kDenoiserOnAdaptive
77 };
78 
79 // Greatest common divisior
GCD(int a,int b)80 int GCD(int a, int b) {
81   int c = a % b;
82   while (c != 0) {
83     a = b;
84     b = c;
85     c = a % b;
86   }
87   return b;
88 }
89 
90 static_assert(Vp8EncoderConfig::TemporalLayerConfig::kMaxPeriodicity ==
91                   VPX_TS_MAX_PERIODICITY,
92               "Vp8EncoderConfig::kMaxPeriodicity must be kept in sync with the "
93               "constant in libvpx.");
94 static_assert(Vp8EncoderConfig::TemporalLayerConfig::kMaxLayers ==
95                   VPX_TS_MAX_LAYERS,
96               "Vp8EncoderConfig::kMaxLayers must be kept in sync with the "
97               "constant in libvpx.");
98 
99 // Allow a newer value to override a current value only if the new value
100 // is set.
101 template <typename T>
MaybeSetNewValue(const absl::optional<T> & new_value,absl::optional<T> * base_value)102 bool MaybeSetNewValue(const absl::optional<T>& new_value,
103                       absl::optional<T>* base_value) {
104   if (new_value.has_value() && new_value != *base_value) {
105     *base_value = new_value;
106     return true;
107   } else {
108     return false;
109   }
110 }
111 
112 // Adds configuration from `new_config` to `base_config`. Both configs consist
113 // of optionals, and only optionals which are set in `new_config` can have
114 // an effect. (That is, set values in `base_config` cannot be unset.)
115 // Returns `true` iff any changes were made to `base_config`.
MaybeExtendVp8EncoderConfig(const Vp8EncoderConfig & new_config,Vp8EncoderConfig * base_config)116 bool MaybeExtendVp8EncoderConfig(const Vp8EncoderConfig& new_config,
117                                  Vp8EncoderConfig* base_config) {
118   bool changes_made = false;
119   changes_made |= MaybeSetNewValue(new_config.temporal_layer_config,
120                                    &base_config->temporal_layer_config);
121   changes_made |= MaybeSetNewValue(new_config.rc_target_bitrate,
122                                    &base_config->rc_target_bitrate);
123   changes_made |= MaybeSetNewValue(new_config.rc_max_quantizer,
124                                    &base_config->rc_max_quantizer);
125   changes_made |= MaybeSetNewValue(new_config.g_error_resilient,
126                                    &base_config->g_error_resilient);
127   return changes_made;
128 }
129 
ApplyVp8EncoderConfigToVpxConfig(const Vp8EncoderConfig & encoder_config,vpx_codec_enc_cfg_t * vpx_config)130 void ApplyVp8EncoderConfigToVpxConfig(const Vp8EncoderConfig& encoder_config,
131                                       vpx_codec_enc_cfg_t* vpx_config) {
132   if (encoder_config.temporal_layer_config.has_value()) {
133     const Vp8EncoderConfig::TemporalLayerConfig& ts_config =
134         encoder_config.temporal_layer_config.value();
135     vpx_config->ts_number_layers = ts_config.ts_number_layers;
136     std::copy(ts_config.ts_target_bitrate.begin(),
137               ts_config.ts_target_bitrate.end(),
138               std::begin(vpx_config->ts_target_bitrate));
139     std::copy(ts_config.ts_rate_decimator.begin(),
140               ts_config.ts_rate_decimator.end(),
141               std::begin(vpx_config->ts_rate_decimator));
142     vpx_config->ts_periodicity = ts_config.ts_periodicity;
143     std::copy(ts_config.ts_layer_id.begin(), ts_config.ts_layer_id.end(),
144               std::begin(vpx_config->ts_layer_id));
145   } else {
146     vpx_config->ts_number_layers = 1;
147     vpx_config->ts_rate_decimator[0] = 1;
148     vpx_config->ts_periodicity = 1;
149     vpx_config->ts_layer_id[0] = 0;
150   }
151 
152   if (encoder_config.rc_target_bitrate.has_value()) {
153     vpx_config->rc_target_bitrate = encoder_config.rc_target_bitrate.value();
154   }
155 
156   if (encoder_config.rc_max_quantizer.has_value()) {
157     vpx_config->rc_max_quantizer = encoder_config.rc_max_quantizer.value();
158   }
159 
160   if (encoder_config.g_error_resilient.has_value()) {
161     vpx_config->g_error_resilient = encoder_config.g_error_resilient.value();
162   }
163 }
164 
IsCompatibleVideoFrameBufferType(VideoFrameBuffer::Type left,VideoFrameBuffer::Type right)165 bool IsCompatibleVideoFrameBufferType(VideoFrameBuffer::Type left,
166                                       VideoFrameBuffer::Type right) {
167   if (left == VideoFrameBuffer::Type::kI420 ||
168       left == VideoFrameBuffer::Type::kI420A) {
169     // LibvpxVp8Encoder does not care about the alpha channel, I420A and I420
170     // are considered compatible.
171     return right == VideoFrameBuffer::Type::kI420 ||
172            right == VideoFrameBuffer::Type::kI420A;
173   }
174   return left == right;
175 }
176 
SetRawImagePlanes(vpx_image_t * raw_image,VideoFrameBuffer * buffer)177 void SetRawImagePlanes(vpx_image_t* raw_image, VideoFrameBuffer* buffer) {
178   switch (buffer->type()) {
179     case VideoFrameBuffer::Type::kI420:
180     case VideoFrameBuffer::Type::kI420A: {
181       const I420BufferInterface* i420_buffer = buffer->GetI420();
182       RTC_DCHECK(i420_buffer);
183       raw_image->planes[VPX_PLANE_Y] =
184           const_cast<uint8_t*>(i420_buffer->DataY());
185       raw_image->planes[VPX_PLANE_U] =
186           const_cast<uint8_t*>(i420_buffer->DataU());
187       raw_image->planes[VPX_PLANE_V] =
188           const_cast<uint8_t*>(i420_buffer->DataV());
189       raw_image->stride[VPX_PLANE_Y] = i420_buffer->StrideY();
190       raw_image->stride[VPX_PLANE_U] = i420_buffer->StrideU();
191       raw_image->stride[VPX_PLANE_V] = i420_buffer->StrideV();
192       break;
193     }
194     case VideoFrameBuffer::Type::kNV12: {
195       const NV12BufferInterface* nv12_buffer = buffer->GetNV12();
196       RTC_DCHECK(nv12_buffer);
197       raw_image->planes[VPX_PLANE_Y] =
198           const_cast<uint8_t*>(nv12_buffer->DataY());
199       raw_image->planes[VPX_PLANE_U] =
200           const_cast<uint8_t*>(nv12_buffer->DataUV());
201       raw_image->planes[VPX_PLANE_V] = raw_image->planes[VPX_PLANE_U] + 1;
202       raw_image->stride[VPX_PLANE_Y] = nv12_buffer->StrideY();
203       raw_image->stride[VPX_PLANE_U] = nv12_buffer->StrideUV();
204       raw_image->stride[VPX_PLANE_V] = nv12_buffer->StrideUV();
205       break;
206     }
207     default:
208       RTC_DCHECK_NOTREACHED();
209   }
210 }
211 
212 }  // namespace
213 
Create()214 std::unique_ptr<VideoEncoder> VP8Encoder::Create() {
215   return std::make_unique<LibvpxVp8Encoder>(LibvpxInterface::Create(),
216                                             VP8Encoder::Settings());
217 }
218 
Create(VP8Encoder::Settings settings)219 std::unique_ptr<VideoEncoder> VP8Encoder::Create(
220     VP8Encoder::Settings settings) {
221   return std::make_unique<LibvpxVp8Encoder>(LibvpxInterface::Create(),
222                                             std::move(settings));
223 }
224 
EncodeFlags(const Vp8FrameConfig & references)225 vpx_enc_frame_flags_t LibvpxVp8Encoder::EncodeFlags(
226     const Vp8FrameConfig& references) {
227   RTC_DCHECK(!references.drop_frame);
228 
229   vpx_enc_frame_flags_t flags = 0;
230 
231   if ((references.last_buffer_flags &
232        Vp8FrameConfig::BufferFlags::kReference) == 0)
233     flags |= VP8_EFLAG_NO_REF_LAST;
234   if ((references.last_buffer_flags & Vp8FrameConfig::BufferFlags::kUpdate) ==
235       0)
236     flags |= VP8_EFLAG_NO_UPD_LAST;
237   if ((references.golden_buffer_flags &
238        Vp8FrameConfig::BufferFlags::kReference) == 0)
239     flags |= VP8_EFLAG_NO_REF_GF;
240   if ((references.golden_buffer_flags & Vp8FrameConfig::BufferFlags::kUpdate) ==
241       0)
242     flags |= VP8_EFLAG_NO_UPD_GF;
243   if ((references.arf_buffer_flags & Vp8FrameConfig::BufferFlags::kReference) ==
244       0)
245     flags |= VP8_EFLAG_NO_REF_ARF;
246   if ((references.arf_buffer_flags & Vp8FrameConfig::BufferFlags::kUpdate) == 0)
247     flags |= VP8_EFLAG_NO_UPD_ARF;
248   if (references.freeze_entropy)
249     flags |= VP8_EFLAG_NO_UPD_ENTROPY;
250 
251   return flags;
252 }
253 
LibvpxVp8Encoder(std::unique_ptr<LibvpxInterface> interface,VP8Encoder::Settings settings)254 LibvpxVp8Encoder::LibvpxVp8Encoder(std::unique_ptr<LibvpxInterface> interface,
255                                    VP8Encoder::Settings settings)
256     : libvpx_(std::move(interface)),
257       rate_control_settings_(RateControlSettings::ParseFromFieldTrials()),
258       frame_buffer_controller_factory_(
259           std::move(settings.frame_buffer_controller_factory)),
260       resolution_bitrate_limits_(std::move(settings.resolution_bitrate_limits)),
261       key_frame_request_(kMaxSimulcastStreams, false),
262       variable_framerate_experiment_(ParseVariableFramerateConfig(
263           "WebRTC-VP8VariableFramerateScreenshare")),
264       framerate_controller_(variable_framerate_experiment_.framerate_limit) {
265   // TODO(eladalon/ilnik): These reservations might be wasting memory.
266   // InitEncode() is resizing to the actual size, which might be smaller.
267   raw_images_.reserve(kMaxSimulcastStreams);
268   encoded_images_.reserve(kMaxSimulcastStreams);
269   send_stream_.reserve(kMaxSimulcastStreams);
270   cpu_speed_.assign(kMaxSimulcastStreams, cpu_speed_default_);
271   encoders_.reserve(kMaxSimulcastStreams);
272   vpx_configs_.reserve(kMaxSimulcastStreams);
273   config_overrides_.reserve(kMaxSimulcastStreams);
274   downsampling_factors_.reserve(kMaxSimulcastStreams);
275 }
276 
~LibvpxVp8Encoder()277 LibvpxVp8Encoder::~LibvpxVp8Encoder() {
278   Release();
279 }
280 
Release()281 int LibvpxVp8Encoder::Release() {
282   int ret_val = WEBRTC_VIDEO_CODEC_OK;
283 
284   encoded_images_.clear();
285 
286   if (inited_) {
287     for (auto it = encoders_.rbegin(); it != encoders_.rend(); ++it) {
288       if (libvpx_->codec_destroy(&*it)) {
289         ret_val = WEBRTC_VIDEO_CODEC_MEMORY;
290       }
291     }
292   }
293   encoders_.clear();
294 
295   vpx_configs_.clear();
296   config_overrides_.clear();
297   send_stream_.clear();
298   cpu_speed_.clear();
299 
300   for (auto it = raw_images_.rbegin(); it != raw_images_.rend(); ++it) {
301     libvpx_->img_free(&*it);
302   }
303   raw_images_.clear();
304 
305   frame_buffer_controller_.reset();
306   inited_ = false;
307   return ret_val;
308 }
309 
SetRates(const RateControlParameters & parameters)310 void LibvpxVp8Encoder::SetRates(const RateControlParameters& parameters) {
311   if (!inited_) {
312     RTC_LOG(LS_WARNING) << "SetRates() while not initialize";
313     return;
314   }
315 
316   if (encoders_[0].err) {
317     RTC_LOG(LS_WARNING) << "Encoder in error state.";
318     return;
319   }
320 
321   if (parameters.framerate_fps < 1.0) {
322     RTC_LOG(LS_WARNING) << "Unsupported framerate (must be >= 1.0): "
323                         << parameters.framerate_fps;
324     return;
325   }
326 
327   if (parameters.bitrate.get_sum_bps() == 0) {
328     // Encoder paused, turn off all encoding.
329     const int num_streams = static_cast<size_t>(encoders_.size());
330     for (int i = 0; i < num_streams; ++i)
331       SetStreamState(false, i);
332     return;
333   }
334 
335   codec_.maxFramerate = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
336 
337   if (encoders_.size() > 1) {
338     // If we have more than 1 stream, reduce the qp_max for the low resolution
339     // stream if frame rate is not too low. The trade-off with lower qp_max is
340     // possibly more dropped frames, so we only do this if the frame rate is
341     // above some threshold (base temporal layer is down to 1/4 for 3 layers).
342     // We may want to condition this on bitrate later.
343     if (rate_control_settings_.Vp8BoostBaseLayerQuality() &&
344         parameters.framerate_fps > 20.0) {
345       vpx_configs_[encoders_.size() - 1].rc_max_quantizer = 45;
346     } else {
347       // Go back to default value set in InitEncode.
348       vpx_configs_[encoders_.size() - 1].rc_max_quantizer = qp_max_;
349     }
350   }
351 
352   for (size_t i = 0; i < encoders_.size(); ++i) {
353     const size_t stream_idx = encoders_.size() - 1 - i;
354 
355     unsigned int target_bitrate_kbps =
356         parameters.bitrate.GetSpatialLayerSum(stream_idx) / 1000;
357 
358     bool send_stream = target_bitrate_kbps > 0;
359     if (send_stream || encoders_.size() > 1)
360       SetStreamState(send_stream, stream_idx);
361 
362     vpx_configs_[i].rc_target_bitrate = target_bitrate_kbps;
363     if (send_stream) {
364       frame_buffer_controller_->OnRatesUpdated(
365           stream_idx, parameters.bitrate.GetTemporalLayerAllocation(stream_idx),
366           static_cast<int>(parameters.framerate_fps + 0.5));
367     }
368 
369     UpdateVpxConfiguration(stream_idx);
370 
371     vpx_codec_err_t err =
372         libvpx_->codec_enc_config_set(&encoders_[i], &vpx_configs_[i]);
373     if (err != VPX_CODEC_OK) {
374       RTC_LOG(LS_WARNING) << "Error configuring codec, error code: " << err
375                           << ", details: "
376                           << libvpx_->codec_error_detail(&encoders_[i]);
377     }
378   }
379 }
380 
OnPacketLossRateUpdate(float packet_loss_rate)381 void LibvpxVp8Encoder::OnPacketLossRateUpdate(float packet_loss_rate) {
382   // TODO(bugs.webrtc.org/10431): Replace condition by DCHECK.
383   if (frame_buffer_controller_) {
384     frame_buffer_controller_->OnPacketLossRateUpdate(packet_loss_rate);
385   }
386 }
387 
OnRttUpdate(int64_t rtt_ms)388 void LibvpxVp8Encoder::OnRttUpdate(int64_t rtt_ms) {
389   // TODO(bugs.webrtc.org/10431): Replace condition by DCHECK.
390   if (frame_buffer_controller_) {
391     frame_buffer_controller_->OnRttUpdate(rtt_ms);
392   }
393 }
394 
OnLossNotification(const LossNotification & loss_notification)395 void LibvpxVp8Encoder::OnLossNotification(
396     const LossNotification& loss_notification) {
397   if (frame_buffer_controller_) {
398     frame_buffer_controller_->OnLossNotification(loss_notification);
399   }
400 }
401 
SetStreamState(bool send_stream,int stream_idx)402 void LibvpxVp8Encoder::SetStreamState(bool send_stream, int stream_idx) {
403   if (send_stream && !send_stream_[stream_idx]) {
404     // Need a key frame if we have not sent this stream before.
405     key_frame_request_[stream_idx] = true;
406   }
407   send_stream_[stream_idx] = send_stream;
408 }
409 
SetFecControllerOverride(FecControllerOverride * fec_controller_override)410 void LibvpxVp8Encoder::SetFecControllerOverride(
411     FecControllerOverride* fec_controller_override) {
412   // TODO(bugs.webrtc.org/10769): Update downstream and remove ability to
413   // pass nullptr.
414   // RTC_DCHECK(fec_controller_override);
415   RTC_DCHECK(!fec_controller_override_);
416   fec_controller_override_ = fec_controller_override;
417 }
418 
419 // TODO(eladalon): s/inst/codec_settings/g.
InitEncode(const VideoCodec * inst,const VideoEncoder::Settings & settings)420 int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst,
421                                  const VideoEncoder::Settings& settings) {
422   if (inst == NULL) {
423     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
424   }
425   if (inst->maxFramerate < 1) {
426     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
427   }
428   // allow zero to represent an unspecified maxBitRate
429   if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
430     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
431   }
432   if (inst->width < 1 || inst->height < 1) {
433     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
434   }
435   if (settings.number_of_cores < 1) {
436     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
437   }
438 
439   if (absl::optional<ScalabilityMode> scalability_mode =
440           inst->GetScalabilityMode();
441       scalability_mode.has_value() &&
442       !VP8SupportsScalabilityMode(*scalability_mode)) {
443     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
444   }
445 
446   num_active_streams_ = 0;
447   for (int i = 0; i < inst->numberOfSimulcastStreams; ++i) {
448     if (inst->simulcastStream[i].active) {
449       ++num_active_streams_;
450     }
451   }
452   if (inst->numberOfSimulcastStreams == 0 && inst->active) {
453     num_active_streams_ = 1;
454   }
455 
456   if (inst->VP8().automaticResizeOn && num_active_streams_ > 1) {
457     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
458   }
459 
460   // Use the previous pixel format to avoid extra image allocations.
461   vpx_img_fmt_t pixel_format =
462       raw_images_.empty() ? VPX_IMG_FMT_I420 : raw_images_[0].fmt;
463 
464   int retVal = Release();
465   if (retVal < 0) {
466     return retVal;
467   }
468 
469   int number_of_streams = SimulcastUtility::NumberOfSimulcastStreams(*inst);
470   if (number_of_streams > 1 &&
471       !SimulcastUtility::ValidSimulcastParameters(*inst, number_of_streams)) {
472     return WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED;
473   }
474 
475   RTC_DCHECK(!frame_buffer_controller_);
476   if (frame_buffer_controller_factory_) {
477     frame_buffer_controller_ = frame_buffer_controller_factory_->Create(
478         *inst, settings, fec_controller_override_);
479   } else {
480     Vp8TemporalLayersFactory factory;
481     frame_buffer_controller_ =
482         factory.Create(*inst, settings, fec_controller_override_);
483   }
484   RTC_DCHECK(frame_buffer_controller_);
485 
486   number_of_cores_ = settings.number_of_cores;
487   timestamp_ = 0;
488   codec_ = *inst;
489 
490   // Code expects simulcastStream resolutions to be correct, make sure they are
491   // filled even when there are no simulcast layers.
492   if (codec_.numberOfSimulcastStreams == 0) {
493     codec_.simulcastStream[0].width = codec_.width;
494     codec_.simulcastStream[0].height = codec_.height;
495   }
496 
497   encoded_images_.resize(number_of_streams);
498   encoders_.resize(number_of_streams);
499   vpx_configs_.resize(number_of_streams);
500   config_overrides_.resize(number_of_streams);
501   downsampling_factors_.resize(number_of_streams);
502   raw_images_.resize(number_of_streams);
503   send_stream_.resize(number_of_streams);
504   send_stream_[0] = true;  // For non-simulcast case.
505   cpu_speed_.resize(number_of_streams);
506   std::fill(key_frame_request_.begin(), key_frame_request_.end(), false);
507 
508   int idx = number_of_streams - 1;
509   for (int i = 0; i < (number_of_streams - 1); ++i, --idx) {
510     int gcd = GCD(inst->simulcastStream[idx].width,
511                   inst->simulcastStream[idx - 1].width);
512     downsampling_factors_[i].num = inst->simulcastStream[idx].width / gcd;
513     downsampling_factors_[i].den = inst->simulcastStream[idx - 1].width / gcd;
514     send_stream_[i] = false;
515   }
516   if (number_of_streams > 1) {
517     send_stream_[number_of_streams - 1] = false;
518     downsampling_factors_[number_of_streams - 1].num = 1;
519     downsampling_factors_[number_of_streams - 1].den = 1;
520   }
521 
522   // populate encoder configuration with default values
523   if (libvpx_->codec_enc_config_default(vpx_codec_vp8_cx(), &vpx_configs_[0],
524                                         0)) {
525     return WEBRTC_VIDEO_CODEC_ERROR;
526   }
527   // setting the time base of the codec
528   vpx_configs_[0].g_timebase.num = 1;
529   vpx_configs_[0].g_timebase.den = kRtpTicksPerSecond;
530   vpx_configs_[0].g_lag_in_frames = 0;  // 0- no frame lagging
531 
532   // Set the error resilience mode for temporal layers (but not simulcast).
533   vpx_configs_[0].g_error_resilient =
534       (SimulcastUtility::NumberOfTemporalLayers(*inst, 0) > 1)
535           ? VPX_ERROR_RESILIENT_DEFAULT
536           : 0;
537 
538   // Override the error resilience mode if this is not simulcast, but we are
539   // using temporal layers.
540   if (field_trial::IsEnabled(kVp8ForcePartitionResilience) &&
541       (number_of_streams == 1) &&
542       (SimulcastUtility::NumberOfTemporalLayers(*inst, 0) > 1)) {
543     RTC_LOG(LS_INFO) << "Overriding g_error_resilient from "
544                      << vpx_configs_[0].g_error_resilient << " to "
545                      << VPX_ERROR_RESILIENT_PARTITIONS;
546     vpx_configs_[0].g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS;
547   }
548 
549   // rate control settings
550   vpx_configs_[0].rc_dropframe_thresh = FrameDropThreshold(0);
551   vpx_configs_[0].rc_end_usage = VPX_CBR;
552   vpx_configs_[0].g_pass = VPX_RC_ONE_PASS;
553   // Handle resizing outside of libvpx.
554   vpx_configs_[0].rc_resize_allowed = 0;
555   vpx_configs_[0].rc_min_quantizer =
556       codec_.mode == VideoCodecMode::kScreensharing ? 12 : 2;
557   if (inst->qpMax >= vpx_configs_[0].rc_min_quantizer) {
558     qp_max_ = inst->qpMax;
559   }
560   if (rate_control_settings_.LibvpxVp8QpMax()) {
561     qp_max_ = std::max(rate_control_settings_.LibvpxVp8QpMax().value(),
562                        static_cast<int>(vpx_configs_[0].rc_min_quantizer));
563   }
564   vpx_configs_[0].rc_max_quantizer = qp_max_;
565   vpx_configs_[0].rc_undershoot_pct = 100;
566   vpx_configs_[0].rc_overshoot_pct = 15;
567   vpx_configs_[0].rc_buf_initial_sz = 500;
568   vpx_configs_[0].rc_buf_optimal_sz = 600;
569   vpx_configs_[0].rc_buf_sz = 1000;
570 
571   // Set the maximum target size of any key-frame.
572   rc_max_intra_target_ = MaxIntraTarget(vpx_configs_[0].rc_buf_optimal_sz);
573 
574   if (inst->VP8().keyFrameInterval > 0) {
575     vpx_configs_[0].kf_mode = VPX_KF_AUTO;
576     vpx_configs_[0].kf_max_dist = inst->VP8().keyFrameInterval;
577   } else {
578     vpx_configs_[0].kf_mode = VPX_KF_DISABLED;
579   }
580 
581   // Allow the user to set the complexity for the base stream.
582   switch (inst->GetVideoEncoderComplexity()) {
583     case VideoCodecComplexity::kComplexityHigh:
584       cpu_speed_[0] = -5;
585       break;
586     case VideoCodecComplexity::kComplexityHigher:
587       cpu_speed_[0] = -4;
588       break;
589     case VideoCodecComplexity::kComplexityMax:
590       cpu_speed_[0] = -3;
591       break;
592     default:
593       cpu_speed_[0] = -6;
594       break;
595   }
596   cpu_speed_default_ = cpu_speed_[0];
597   // Set encoding complexity (cpu_speed) based on resolution and/or platform.
598   cpu_speed_[0] = GetCpuSpeed(inst->width, inst->height);
599   for (int i = 1; i < number_of_streams; ++i) {
600     cpu_speed_[i] =
601         GetCpuSpeed(inst->simulcastStream[number_of_streams - 1 - i].width,
602                     inst->simulcastStream[number_of_streams - 1 - i].height);
603   }
604   vpx_configs_[0].g_w = inst->width;
605   vpx_configs_[0].g_h = inst->height;
606 
607   // Determine number of threads based on the image size and #cores.
608   // TODO(fbarchard): Consider number of Simulcast layers.
609   vpx_configs_[0].g_threads = NumberOfThreads(
610       vpx_configs_[0].g_w, vpx_configs_[0].g_h, settings.number_of_cores);
611 
612   // Creating a wrapper to the image - setting image data to NULL.
613   // Actual pointer will be set in encode. Setting align to 1, as it
614   // is meaningless (no memory allocation is done here).
615   libvpx_->img_wrap(&raw_images_[0], pixel_format, inst->width, inst->height, 1,
616                     NULL);
617 
618   // Note the order we use is different from webm, we have lowest resolution
619   // at position 0 and they have highest resolution at position 0.
620   const size_t stream_idx_cfg_0 = encoders_.size() - 1;
621   SimulcastRateAllocator init_allocator(codec_);
622   VideoBitrateAllocation allocation =
623       init_allocator.Allocate(VideoBitrateAllocationParameters(
624           inst->startBitrate * 1000, inst->maxFramerate));
625   std::vector<uint32_t> stream_bitrates;
626   for (int i = 0; i == 0 || i < inst->numberOfSimulcastStreams; ++i) {
627     uint32_t bitrate = allocation.GetSpatialLayerSum(i) / 1000;
628     stream_bitrates.push_back(bitrate);
629   }
630 
631   vpx_configs_[0].rc_target_bitrate = stream_bitrates[stream_idx_cfg_0];
632   if (stream_bitrates[stream_idx_cfg_0] > 0) {
633     uint32_t maxFramerate =
634         inst->simulcastStream[stream_idx_cfg_0].maxFramerate;
635     if (!maxFramerate) {
636       maxFramerate = inst->maxFramerate;
637     }
638 
639     frame_buffer_controller_->OnRatesUpdated(
640         stream_idx_cfg_0,
641         allocation.GetTemporalLayerAllocation(stream_idx_cfg_0), maxFramerate);
642   }
643   frame_buffer_controller_->SetQpLimits(stream_idx_cfg_0,
644                                         vpx_configs_[0].rc_min_quantizer,
645                                         vpx_configs_[0].rc_max_quantizer);
646   UpdateVpxConfiguration(stream_idx_cfg_0);
647   vpx_configs_[0].rc_dropframe_thresh = FrameDropThreshold(stream_idx_cfg_0);
648 
649   for (size_t i = 1; i < encoders_.size(); ++i) {
650     const size_t stream_idx = encoders_.size() - 1 - i;
651     memcpy(&vpx_configs_[i], &vpx_configs_[0], sizeof(vpx_configs_[0]));
652 
653     vpx_configs_[i].g_w = inst->simulcastStream[stream_idx].width;
654     vpx_configs_[i].g_h = inst->simulcastStream[stream_idx].height;
655 
656     // Use 1 thread for lower resolutions.
657     vpx_configs_[i].g_threads = 1;
658 
659     vpx_configs_[i].rc_dropframe_thresh = FrameDropThreshold(stream_idx);
660 
661     // Setting alignment to 32 - as that ensures at least 16 for all
662     // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for
663     // the y plane, but only half of it to the u and v planes.
664     libvpx_->img_alloc(
665         &raw_images_[i], pixel_format, inst->simulcastStream[stream_idx].width,
666         inst->simulcastStream[stream_idx].height, kVp832ByteAlign);
667     SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
668     vpx_configs_[i].rc_target_bitrate = stream_bitrates[stream_idx];
669     if (stream_bitrates[stream_idx] > 0) {
670       uint32_t maxFramerate = inst->simulcastStream[stream_idx].maxFramerate;
671       if (!maxFramerate) {
672         maxFramerate = inst->maxFramerate;
673       }
674       frame_buffer_controller_->OnRatesUpdated(
675           stream_idx, allocation.GetTemporalLayerAllocation(stream_idx),
676           maxFramerate);
677     }
678     frame_buffer_controller_->SetQpLimits(stream_idx,
679                                           vpx_configs_[i].rc_min_quantizer,
680                                           vpx_configs_[i].rc_max_quantizer);
681     UpdateVpxConfiguration(stream_idx);
682   }
683 
684   return InitAndSetControlSettings();
685 }
686 
GetCpuSpeed(int width,int height)687 int LibvpxVp8Encoder::GetCpuSpeed(int width, int height) {
688 #if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || \
689     defined(WEBRTC_ANDROID)
690   // On mobile platform, use a lower speed setting for lower resolutions for
691   // CPUs with 4 or more cores.
692   RTC_DCHECK_GT(number_of_cores_, 0);
693   if (experimental_cpu_speed_config_arm_
694           .GetValue(width * height, number_of_cores_)
695           .has_value()) {
696     return experimental_cpu_speed_config_arm_
697         .GetValue(width * height, number_of_cores_)
698         .value();
699   }
700 
701   if (number_of_cores_ <= 3)
702     return -12;
703 
704   if (width * height <= 352 * 288)
705     return -8;
706   else if (width * height <= 640 * 480)
707     return -10;
708   else
709     return -12;
710 #else
711   // For non-ARM, increase encoding complexity (i.e., use lower speed setting)
712   // if resolution is below CIF. Otherwise, keep the default/user setting
713   // (`cpu_speed_default_`) set on InitEncode via VP8().complexity.
714   if (width * height < 352 * 288)
715     return (cpu_speed_default_ < -4) ? -4 : cpu_speed_default_;
716   else
717     return cpu_speed_default_;
718 #endif
719 }
720 
NumberOfThreads(int width,int height,int cpus)721 int LibvpxVp8Encoder::NumberOfThreads(int width, int height, int cpus) {
722 #if defined(WEBRTC_ANDROID)
723   if (width * height >= 320 * 180) {
724     if (cpus >= 4) {
725       // 3 threads for CPUs with 4 and more cores since most of times only 4
726       // cores will be active.
727       return 3;
728     } else if (cpus == 3 || cpus == 2) {
729       return 2;
730     } else {
731       return 1;
732     }
733   }
734   return 1;
735 #else
736 #if defined(WEBRTC_IOS)
737   std::string trial_string =
738       field_trial::FindFullName(kVP8IosMaxNumberOfThreadFieldTrial);
739   FieldTrialParameter<int> max_thread_number(
740       kVP8IosMaxNumberOfThreadFieldTrialParameter, 0);
741   ParseFieldTrial({&max_thread_number}, trial_string);
742   if (max_thread_number.Get() > 0) {
743     if (width * height < 320 * 180) {
744       return 1;  // Use single thread for small screens
745     }
746     // thread number must be less than or equal to the number of CPUs.
747     return std::min(cpus, max_thread_number.Get());
748   }
749 #endif  // defined(WEBRTC_IOS)
750   if (width * height >= 1920 * 1080 && cpus > 8) {
751     return 8;  // 8 threads for 1080p on high perf machines.
752   } else if (width * height > 1280 * 960 && cpus >= 6) {
753     // 3 threads for 1080p.
754     return 3;
755   } else if (width * height > 640 * 480 && cpus >= 3) {
756     // Default 2 threads for qHD/HD, but allow 3 if core count is high enough,
757     // as this will allow more margin for high-core/low clock machines or if
758     // not built with highest optimization.
759     if (cpus >= 6) {
760       return 3;
761     }
762     return 2;
763   } else {
764     // 1 thread for VGA or less.
765     return 1;
766   }
767 #endif
768 }
769 
InitAndSetControlSettings()770 int LibvpxVp8Encoder::InitAndSetControlSettings() {
771   vpx_codec_flags_t flags = 0;
772   flags |= VPX_CODEC_USE_OUTPUT_PARTITION;
773 
774   if (encoders_.size() > 1) {
775     int error = libvpx_->codec_enc_init_multi(
776         &encoders_[0], vpx_codec_vp8_cx(), &vpx_configs_[0], encoders_.size(),
777         flags, &downsampling_factors_[0]);
778     if (error) {
779       return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
780     }
781   } else {
782     if (libvpx_->codec_enc_init(&encoders_[0], vpx_codec_vp8_cx(),
783                                 &vpx_configs_[0], flags)) {
784       return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
785     }
786   }
787   // Enable denoising for the highest resolution stream, and for
788   // the second highest resolution if we are doing more than 2
789   // spatial layers/streams.
790   // TODO(holmer): Investigate possibility of adding a libvpx API
791   // for getting the denoised frame from the encoder and using that
792   // when encoding lower resolution streams. Would it work with the
793   // multi-res encoding feature?
794   denoiserState denoiser_state = kDenoiserOnYOnly;
795 #if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || \
796     defined(WEBRTC_ANDROID)
797   denoiser_state = kDenoiserOnYOnly;
798 #else
799   denoiser_state = kDenoiserOnAdaptive;
800 #endif
801   libvpx_->codec_control(
802       &encoders_[0], VP8E_SET_NOISE_SENSITIVITY,
803       codec_.VP8()->denoisingOn ? denoiser_state : kDenoiserOff);
804   if (encoders_.size() > 2) {
805     libvpx_->codec_control(
806         &encoders_[1], VP8E_SET_NOISE_SENSITIVITY,
807         codec_.VP8()->denoisingOn ? denoiser_state : kDenoiserOff);
808   }
809   for (size_t i = 0; i < encoders_.size(); ++i) {
810     // Allow more screen content to be detected as static.
811     libvpx_->codec_control(
812         &(encoders_[i]), VP8E_SET_STATIC_THRESHOLD,
813         codec_.mode == VideoCodecMode::kScreensharing ? 100u : 1u);
814     libvpx_->codec_control(&(encoders_[i]), VP8E_SET_CPUUSED, cpu_speed_[i]);
815     libvpx_->codec_control(
816         &(encoders_[i]), VP8E_SET_TOKEN_PARTITIONS,
817         static_cast<vp8e_token_partitions>(kTokenPartitions));
818     libvpx_->codec_control(&(encoders_[i]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
819                            rc_max_intra_target_);
820     // VP8E_SET_SCREEN_CONTENT_MODE 2 = screen content with more aggressive
821     // rate control (drop frames on large target bitrate overshoot)
822     libvpx_->codec_control(
823         &(encoders_[i]), VP8E_SET_SCREEN_CONTENT_MODE,
824         codec_.mode == VideoCodecMode::kScreensharing ? 2u : 0u);
825   }
826   inited_ = true;
827   return WEBRTC_VIDEO_CODEC_OK;
828 }
829 
MaxIntraTarget(uint32_t optimalBuffersize)830 uint32_t LibvpxVp8Encoder::MaxIntraTarget(uint32_t optimalBuffersize) {
831   // Set max to the optimal buffer level (normalized by target BR),
832   // and scaled by a scalePar.
833   // Max target size = scalePar * optimalBufferSize * targetBR[Kbps].
834   // This values is presented in percentage of perFrameBw:
835   // perFrameBw = targetBR[Kbps] * 1000 / frameRate.
836   // The target in % is as follows:
837 
838   float scalePar = 0.5;
839   uint32_t targetPct = optimalBuffersize * scalePar * codec_.maxFramerate / 10;
840 
841   // Don't go below 3 times the per frame bandwidth.
842   const uint32_t minIntraTh = 300;
843   return (targetPct < minIntraTh) ? minIntraTh : targetPct;
844 }
845 
FrameDropThreshold(size_t spatial_idx) const846 uint32_t LibvpxVp8Encoder::FrameDropThreshold(size_t spatial_idx) const {
847   if (!codec_.GetFrameDropEnabled()) {
848     return 0;
849   }
850 
851   // If temporal layers are used, they get to override the frame dropping
852   // setting, as eg. ScreenshareLayers does not work as intended with frame
853   // dropping on and DefaultTemporalLayers will have performance issues with
854   // frame dropping off.
855   RTC_DCHECK(frame_buffer_controller_);
856   RTC_DCHECK_LT(spatial_idx, frame_buffer_controller_->StreamCount());
857   return frame_buffer_controller_->SupportsEncoderFrameDropping(spatial_idx)
858              ? 30
859              : 0;
860 }
861 
SteadyStateSize(int sid,int tid)862 size_t LibvpxVp8Encoder::SteadyStateSize(int sid, int tid) {
863   const int encoder_id = encoders_.size() - 1 - sid;
864   size_t bitrate_bps;
865   float fps;
866   if ((SimulcastUtility::IsConferenceModeScreenshare(codec_) && sid == 0) ||
867       vpx_configs_[encoder_id].ts_number_layers <= 1) {
868     // In conference screenshare there's no defined per temporal layer bitrate
869     // and framerate.
870     bitrate_bps = vpx_configs_[encoder_id].rc_target_bitrate * 1000;
871     fps = codec_.maxFramerate;
872   } else {
873     bitrate_bps = vpx_configs_[encoder_id].ts_target_bitrate[tid] * 1000;
874     fps = codec_.maxFramerate /
875           fmax(vpx_configs_[encoder_id].ts_rate_decimator[tid], 1.0);
876     if (tid > 0) {
877       // Layer bitrate and fps are counted as a partial sums.
878       bitrate_bps -= vpx_configs_[encoder_id].ts_target_bitrate[tid - 1] * 1000;
879       fps = codec_.maxFramerate /
880             fmax(vpx_configs_[encoder_id].ts_rate_decimator[tid - 1], 1.0);
881     }
882   }
883 
884   if (fps < 1e-9)
885     return 0;
886   return static_cast<size_t>(
887       bitrate_bps / (8 * fps) *
888           (100 -
889            variable_framerate_experiment_.steady_state_undershoot_percentage) /
890           100 +
891       0.5);
892 }
893 
UpdateVpxConfiguration(size_t stream_index)894 bool LibvpxVp8Encoder::UpdateVpxConfiguration(size_t stream_index) {
895   RTC_DCHECK(frame_buffer_controller_);
896 
897   const size_t config_index = vpx_configs_.size() - 1 - stream_index;
898 
899   RTC_DCHECK_LT(config_index, config_overrides_.size());
900   Vp8EncoderConfig* config = &config_overrides_[config_index];
901 
902   const Vp8EncoderConfig new_config =
903       frame_buffer_controller_->UpdateConfiguration(stream_index);
904 
905   if (new_config.reset_previous_configuration_overrides) {
906     *config = new_config;
907     return true;
908   }
909 
910   const bool changes_made = MaybeExtendVp8EncoderConfig(new_config, config);
911 
912   // Note that overrides must be applied even if they haven't changed.
913   RTC_DCHECK_LT(config_index, vpx_configs_.size());
914   vpx_codec_enc_cfg_t* vpx_config = &vpx_configs_[config_index];
915   ApplyVp8EncoderConfigToVpxConfig(*config, vpx_config);
916 
917   return changes_made;
918 }
919 
Encode(const VideoFrame & frame,const std::vector<VideoFrameType> * frame_types)920 int LibvpxVp8Encoder::Encode(const VideoFrame& frame,
921                              const std::vector<VideoFrameType>* frame_types) {
922   RTC_DCHECK_EQ(frame.width(), codec_.width);
923   RTC_DCHECK_EQ(frame.height(), codec_.height);
924 
925   if (!inited_)
926     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
927   if (encoded_complete_callback_ == NULL)
928     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
929 
930   bool key_frame_requested = false;
931   for (size_t i = 0; i < key_frame_request_.size() && i < send_stream_.size();
932        ++i) {
933     if (key_frame_request_[i] && send_stream_[i]) {
934       key_frame_requested = true;
935       break;
936     }
937   }
938   if (!key_frame_requested && frame_types) {
939     for (size_t i = 0; i < frame_types->size() && i < send_stream_.size();
940          ++i) {
941       if ((*frame_types)[i] == VideoFrameType::kVideoFrameKey &&
942           send_stream_[i]) {
943         key_frame_requested = true;
944         break;
945       }
946     }
947   }
948 
949   if (frame.update_rect().IsEmpty() && num_steady_state_frames_ >= 3 &&
950       !key_frame_requested) {
951     if (variable_framerate_experiment_.enabled &&
952         framerate_controller_.DropFrame(frame.timestamp() / kRtpTicksPerMs)) {
953       return WEBRTC_VIDEO_CODEC_OK;
954     }
955     framerate_controller_.AddFrame(frame.timestamp() / kRtpTicksPerMs);
956   }
957 
958   bool send_key_frame = key_frame_requested;
959   bool drop_frame = false;
960   bool retransmission_allowed = true;
961   Vp8FrameConfig tl_configs[kMaxSimulcastStreams];
962   for (size_t i = 0; i < encoders_.size(); ++i) {
963     tl_configs[i] =
964         frame_buffer_controller_->NextFrameConfig(i, frame.timestamp());
965     send_key_frame |= tl_configs[i].IntraFrame();
966     drop_frame |= tl_configs[i].drop_frame;
967     RTC_DCHECK(i == 0 ||
968                retransmission_allowed == tl_configs[i].retransmission_allowed);
969     retransmission_allowed = tl_configs[i].retransmission_allowed;
970   }
971 
972   if (drop_frame && !send_key_frame) {
973     return WEBRTC_VIDEO_CODEC_OK;
974   }
975 
976   vpx_enc_frame_flags_t flags[kMaxSimulcastStreams];
977   for (size_t i = 0; i < encoders_.size(); ++i) {
978     flags[i] = send_key_frame ? VPX_EFLAG_FORCE_KF : EncodeFlags(tl_configs[i]);
979   }
980 
981   // Scale and map buffers and set `raw_images_` to hold pointers to the result.
982   // Because `raw_images_` are set to hold pointers to the prepared buffers, we
983   // need to keep these buffers alive through reference counting until after
984   // encoding is complete.
985   std::vector<rtc::scoped_refptr<VideoFrameBuffer>> prepared_buffers =
986       PrepareBuffers(frame.video_frame_buffer());
987   if (prepared_buffers.empty()) {
988     return WEBRTC_VIDEO_CODEC_ERROR;
989   }
990   struct CleanUpOnExit {
991     explicit CleanUpOnExit(
992         vpx_image_t* raw_image,
993         std::vector<rtc::scoped_refptr<VideoFrameBuffer>> prepared_buffers)
994         : raw_image_(raw_image),
995           prepared_buffers_(std::move(prepared_buffers)) {}
996     ~CleanUpOnExit() {
997       raw_image_->planes[VPX_PLANE_Y] = nullptr;
998       raw_image_->planes[VPX_PLANE_U] = nullptr;
999       raw_image_->planes[VPX_PLANE_V] = nullptr;
1000     }
1001     vpx_image_t* raw_image_;
1002     std::vector<rtc::scoped_refptr<VideoFrameBuffer>> prepared_buffers_;
1003   } clean_up_on_exit(&raw_images_[0], std::move(prepared_buffers));
1004 
1005   if (send_key_frame) {
1006     // Adapt the size of the key frame when in screenshare with 1 temporal
1007     // layer.
1008     if (encoders_.size() == 1 &&
1009         codec_.mode == VideoCodecMode::kScreensharing &&
1010         codec_.VP8()->numberOfTemporalLayers <= 1) {
1011       const uint32_t forceKeyFrameIntraTh = 100;
1012       libvpx_->codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
1013                              forceKeyFrameIntraTh);
1014     }
1015 
1016     std::fill(key_frame_request_.begin(), key_frame_request_.end(), false);
1017   }
1018 
1019   // Set the encoder frame flags and temporal layer_id for each spatial stream.
1020   // Note that streams are defined starting from lowest resolution at
1021   // position 0 to highest resolution at position |encoders_.size() - 1|,
1022   // whereas `encoder_` is from highest to lowest resolution.
1023   for (size_t i = 0; i < encoders_.size(); ++i) {
1024     const size_t stream_idx = encoders_.size() - 1 - i;
1025 
1026     if (UpdateVpxConfiguration(stream_idx)) {
1027       if (libvpx_->codec_enc_config_set(&encoders_[i], &vpx_configs_[i]))
1028         return WEBRTC_VIDEO_CODEC_ERROR;
1029     }
1030 
1031     libvpx_->codec_control(&encoders_[i], VP8E_SET_FRAME_FLAGS,
1032                            static_cast<int>(flags[stream_idx]));
1033     libvpx_->codec_control(&encoders_[i], VP8E_SET_TEMPORAL_LAYER_ID,
1034                            tl_configs[i].encoder_layer_id);
1035   }
1036   // TODO(holmer): Ideally the duration should be the timestamp diff of this
1037   // frame and the next frame to be encoded, which we don't have. Instead we
1038   // would like to use the duration of the previous frame. Unfortunately the
1039   // rate control seems to be off with that setup. Using the average input
1040   // frame rate to calculate an average duration for now.
1041   RTC_DCHECK_GT(codec_.maxFramerate, 0);
1042   uint32_t duration = kRtpTicksPerSecond / codec_.maxFramerate;
1043 
1044   int error = WEBRTC_VIDEO_CODEC_OK;
1045   int num_tries = 0;
1046   // If the first try returns WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT
1047   // the frame must be reencoded with the same parameters again because
1048   // target bitrate is exceeded and encoder state has been reset.
1049   while (num_tries == 0 ||
1050          (num_tries == 1 &&
1051           error == WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT)) {
1052     ++num_tries;
1053     // Note we must pass 0 for `flags` field in encode call below since they are
1054     // set above in `libvpx_interface_->vpx_codec_control_` function for each
1055     // encoder/spatial layer.
1056     error = libvpx_->codec_encode(&encoders_[0], &raw_images_[0], timestamp_,
1057                                   duration, 0, VPX_DL_REALTIME);
1058     // Reset specific intra frame thresholds, following the key frame.
1059     if (send_key_frame) {
1060       libvpx_->codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
1061                              rc_max_intra_target_);
1062     }
1063     if (error)
1064       return WEBRTC_VIDEO_CODEC_ERROR;
1065     // Examines frame timestamps only.
1066     error = GetEncodedPartitions(frame, retransmission_allowed);
1067   }
1068   // TODO(sprang): Shouldn't we use the frame timestamp instead?
1069   timestamp_ += duration;
1070   return error;
1071 }
1072 
PopulateCodecSpecific(CodecSpecificInfo * codec_specific,const vpx_codec_cx_pkt_t & pkt,int stream_idx,int encoder_idx,uint32_t timestamp)1073 void LibvpxVp8Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
1074                                              const vpx_codec_cx_pkt_t& pkt,
1075                                              int stream_idx,
1076                                              int encoder_idx,
1077                                              uint32_t timestamp) {
1078   RTC_DCHECK(codec_specific);
1079   codec_specific->codecType = kVideoCodecVP8;
1080   codec_specific->codecSpecific.VP8.keyIdx =
1081       kNoKeyIdx;  // TODO(hlundin) populate this
1082   codec_specific->codecSpecific.VP8.nonReference =
1083       (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
1084 
1085   int qp = 0;
1086   vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER_64, &qp);
1087   bool is_keyframe = (pkt.data.frame.flags & VPX_FRAME_IS_KEY) != 0;
1088   frame_buffer_controller_->OnEncodeDone(stream_idx, timestamp,
1089                                          encoded_images_[encoder_idx].size(),
1090                                          is_keyframe, qp, codec_specific);
1091   if (is_keyframe && codec_specific->template_structure != absl::nullopt) {
1092     // Number of resolutions must match number of spatial layers, VP8 structures
1093     // expected to use single spatial layer. Templates must be ordered by
1094     // spatial_id, so assumption there is exactly one spatial layer is same as
1095     // assumption last template uses spatial_id = 0.
1096     // This check catches potential scenario where template_structure is shared
1097     // across multiple vp8 streams and they are distinguished using spatial_id.
1098     // Assigning single resolution doesn't support such scenario, i.e. assumes
1099     // vp8 simulcast is sent using multiple ssrcs.
1100     RTC_DCHECK(!codec_specific->template_structure->templates.empty());
1101     RTC_DCHECK_EQ(
1102         codec_specific->template_structure->templates.back().spatial_id, 0);
1103     codec_specific->template_structure->resolutions = {
1104         RenderResolution(pkt.data.frame.width[0], pkt.data.frame.height[0])};
1105   }
1106 }
1107 
GetEncodedPartitions(const VideoFrame & input_image,bool retransmission_allowed)1108 int LibvpxVp8Encoder::GetEncodedPartitions(const VideoFrame& input_image,
1109                                            bool retransmission_allowed) {
1110   int stream_idx = static_cast<int>(encoders_.size()) - 1;
1111   int result = WEBRTC_VIDEO_CODEC_OK;
1112   for (size_t encoder_idx = 0; encoder_idx < encoders_.size();
1113        ++encoder_idx, --stream_idx) {
1114     vpx_codec_iter_t iter = NULL;
1115     encoded_images_[encoder_idx].set_size(0);
1116     encoded_images_[encoder_idx]._frameType = VideoFrameType::kVideoFrameDelta;
1117     CodecSpecificInfo codec_specific;
1118     const vpx_codec_cx_pkt_t* pkt = NULL;
1119 
1120     size_t encoded_size = 0;
1121     while ((pkt = libvpx_->codec_get_cx_data(&encoders_[encoder_idx], &iter)) !=
1122            NULL) {
1123       if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
1124         encoded_size += pkt->data.frame.sz;
1125       }
1126     }
1127 
1128     auto buffer = EncodedImageBuffer::Create(encoded_size);
1129 
1130     iter = NULL;
1131     size_t encoded_pos = 0;
1132     while ((pkt = libvpx_->codec_get_cx_data(&encoders_[encoder_idx], &iter)) !=
1133            NULL) {
1134       switch (pkt->kind) {
1135         case VPX_CODEC_CX_FRAME_PKT: {
1136           RTC_CHECK_LE(encoded_pos + pkt->data.frame.sz, buffer->size());
1137           memcpy(&buffer->data()[encoded_pos], pkt->data.frame.buf,
1138                  pkt->data.frame.sz);
1139           encoded_pos += pkt->data.frame.sz;
1140           break;
1141         }
1142         default:
1143           break;
1144       }
1145       // End of frame
1146       if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
1147         // check if encoded frame is a key frame
1148         if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
1149           encoded_images_[encoder_idx]._frameType =
1150               VideoFrameType::kVideoFrameKey;
1151         }
1152         encoded_images_[encoder_idx].SetEncodedData(buffer);
1153         encoded_images_[encoder_idx].set_size(encoded_pos);
1154         encoded_images_[encoder_idx].SetSpatialIndex(stream_idx);
1155         PopulateCodecSpecific(&codec_specific, *pkt, stream_idx, encoder_idx,
1156                               input_image.timestamp());
1157         if (codec_specific.codecSpecific.VP8.temporalIdx != kNoTemporalIdx) {
1158           encoded_images_[encoder_idx].SetTemporalIndex(
1159               codec_specific.codecSpecific.VP8.temporalIdx);
1160         }
1161         break;
1162       }
1163     }
1164     encoded_images_[encoder_idx].SetTimestamp(input_image.timestamp());
1165     encoded_images_[encoder_idx].SetColorSpace(input_image.color_space());
1166     encoded_images_[encoder_idx].SetRetransmissionAllowed(
1167         retransmission_allowed);
1168 
1169     if (send_stream_[stream_idx]) {
1170       if (encoded_images_[encoder_idx].size() > 0) {
1171         TRACE_COUNTER_ID1("webrtc", "EncodedFrameSize", encoder_idx,
1172                           encoded_images_[encoder_idx].size());
1173         encoded_images_[encoder_idx]._encodedHeight =
1174             codec_.simulcastStream[stream_idx].height;
1175         encoded_images_[encoder_idx]._encodedWidth =
1176             codec_.simulcastStream[stream_idx].width;
1177         int qp_128 = -1;
1178         libvpx_->codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER,
1179                                &qp_128);
1180         encoded_images_[encoder_idx].qp_ = qp_128;
1181         encoded_complete_callback_->OnEncodedImage(encoded_images_[encoder_idx],
1182                                                    &codec_specific);
1183         const size_t steady_state_size = SteadyStateSize(
1184             stream_idx, codec_specific.codecSpecific.VP8.temporalIdx);
1185         if (qp_128 > variable_framerate_experiment_.steady_state_qp ||
1186             encoded_images_[encoder_idx].size() > steady_state_size) {
1187           num_steady_state_frames_ = 0;
1188         } else {
1189           ++num_steady_state_frames_;
1190         }
1191       } else if (!frame_buffer_controller_->SupportsEncoderFrameDropping(
1192                      stream_idx)) {
1193         result = WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT;
1194         if (encoded_images_[encoder_idx].size() == 0) {
1195           // Dropped frame that will be re-encoded.
1196           frame_buffer_controller_->OnFrameDropped(stream_idx,
1197                                                    input_image.timestamp());
1198         }
1199       }
1200     }
1201   }
1202   return result;
1203 }
1204 
GetEncoderInfo() const1205 VideoEncoder::EncoderInfo LibvpxVp8Encoder::GetEncoderInfo() const {
1206   EncoderInfo info;
1207   info.supports_native_handle = false;
1208   info.implementation_name = "libvpx";
1209   info.has_trusted_rate_controller =
1210       rate_control_settings_.LibvpxVp8TrustedRateController();
1211   info.is_hardware_accelerated = false;
1212   info.supports_simulcast = true;
1213   if (!resolution_bitrate_limits_.empty()) {
1214     info.resolution_bitrate_limits = resolution_bitrate_limits_;
1215   }
1216   if (encoder_info_override_.requested_resolution_alignment()) {
1217     info.requested_resolution_alignment =
1218         *encoder_info_override_.requested_resolution_alignment();
1219     info.apply_alignment_to_all_simulcast_layers =
1220         encoder_info_override_.apply_alignment_to_all_simulcast_layers();
1221   }
1222   if (!encoder_info_override_.resolution_bitrate_limits().empty()) {
1223     info.resolution_bitrate_limits =
1224         encoder_info_override_.resolution_bitrate_limits();
1225   }
1226 
1227   const bool enable_scaling =
1228       num_active_streams_ == 1 &&
1229       (vpx_configs_.empty() || vpx_configs_[0].rc_dropframe_thresh > 0) &&
1230       codec_.VP8().automaticResizeOn;
1231 
1232   info.scaling_settings = enable_scaling
1233                               ? VideoEncoder::ScalingSettings(
1234                                     kLowVp8QpThreshold, kHighVp8QpThreshold)
1235                               : VideoEncoder::ScalingSettings::kOff;
1236   if (rate_control_settings_.LibvpxVp8MinPixels()) {
1237     info.scaling_settings.min_pixels_per_frame =
1238         rate_control_settings_.LibvpxVp8MinPixels().value();
1239   }
1240   info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420,
1241                                   VideoFrameBuffer::Type::kNV12};
1242 
1243   if (inited_) {
1244     // `encoder_idx` is libvpx index where 0 is highest resolution.
1245     // `si` is simulcast index, where 0 is lowest resolution.
1246     for (size_t si = 0, encoder_idx = encoders_.size() - 1;
1247          si < encoders_.size(); ++si, --encoder_idx) {
1248       info.fps_allocation[si].clear();
1249       if ((codec_.numberOfSimulcastStreams > si &&
1250            !codec_.simulcastStream[si].active) ||
1251           (si == 0 && SimulcastUtility::IsConferenceModeScreenshare(codec_))) {
1252         // No defined frame rate fractions if not active or if using
1253         // ScreenshareLayers, leave vector empty and continue;
1254         continue;
1255       }
1256       if (vpx_configs_[encoder_idx].ts_number_layers <= 1) {
1257         info.fps_allocation[si].push_back(EncoderInfo::kMaxFramerateFraction);
1258       } else {
1259         for (size_t ti = 0; ti < vpx_configs_[encoder_idx].ts_number_layers;
1260              ++ti) {
1261           RTC_DCHECK_GT(vpx_configs_[encoder_idx].ts_rate_decimator[ti], 0);
1262           info.fps_allocation[si].push_back(rtc::saturated_cast<uint8_t>(
1263               EncoderInfo::kMaxFramerateFraction /
1264                   vpx_configs_[encoder_idx].ts_rate_decimator[ti] +
1265               0.5));
1266         }
1267       }
1268     }
1269   }
1270 
1271   return info;
1272 }
1273 
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)1274 int LibvpxVp8Encoder::RegisterEncodeCompleteCallback(
1275     EncodedImageCallback* callback) {
1276   encoded_complete_callback_ = callback;
1277   return WEBRTC_VIDEO_CODEC_OK;
1278 }
1279 
MaybeUpdatePixelFormat(vpx_img_fmt fmt)1280 void LibvpxVp8Encoder::MaybeUpdatePixelFormat(vpx_img_fmt fmt) {
1281   RTC_DCHECK(!raw_images_.empty());
1282   if (raw_images_[0].fmt == fmt) {
1283     RTC_DCHECK(std::all_of(
1284         std::next(raw_images_.begin()), raw_images_.end(),
1285         [fmt](const vpx_image_t& raw_img) { return raw_img.fmt == fmt; }))
1286         << "Not all raw images had the right format!";
1287     return;
1288   }
1289   RTC_LOG(LS_INFO) << "Updating vp8 encoder pixel format to "
1290                    << (fmt == VPX_IMG_FMT_NV12 ? "NV12" : "I420");
1291   for (size_t i = 0; i < raw_images_.size(); ++i) {
1292     vpx_image_t& img = raw_images_[i];
1293     auto d_w = img.d_w;
1294     auto d_h = img.d_h;
1295     libvpx_->img_free(&img);
1296     // First image is wrapping the input frame, the rest are allocated.
1297     if (i == 0) {
1298       libvpx_->img_wrap(&img, fmt, d_w, d_h, 1, NULL);
1299     } else {
1300       libvpx_->img_alloc(&img, fmt, d_w, d_h, kVp832ByteAlign);
1301     }
1302   }
1303 }
1304 
1305 std::vector<rtc::scoped_refptr<VideoFrameBuffer>>
PrepareBuffers(rtc::scoped_refptr<VideoFrameBuffer> buffer)1306 LibvpxVp8Encoder::PrepareBuffers(rtc::scoped_refptr<VideoFrameBuffer> buffer) {
1307   RTC_DCHECK_EQ(buffer->width(), raw_images_[0].d_w);
1308   RTC_DCHECK_EQ(buffer->height(), raw_images_[0].d_h);
1309   absl::InlinedVector<VideoFrameBuffer::Type, kMaxPreferredPixelFormats>
1310       supported_formats = {VideoFrameBuffer::Type::kI420,
1311                            VideoFrameBuffer::Type::kNV12};
1312 
1313   rtc::scoped_refptr<VideoFrameBuffer> mapped_buffer;
1314   if (buffer->type() != VideoFrameBuffer::Type::kNative) {
1315     // `buffer` is already mapped.
1316     mapped_buffer = buffer;
1317   } else {
1318     // Attempt to map to one of the supported formats.
1319     mapped_buffer = buffer->GetMappedFrameBuffer(supported_formats);
1320   }
1321   if (!mapped_buffer ||
1322       (absl::c_find(supported_formats, mapped_buffer->type()) ==
1323            supported_formats.end() &&
1324        mapped_buffer->type() != VideoFrameBuffer::Type::kI420A)) {
1325     // Unknown pixel format or unable to map, convert to I420 and prepare that
1326     // buffer instead to ensure Scale() is safe to use.
1327     auto converted_buffer = buffer->ToI420();
1328     if (!converted_buffer) {
1329       RTC_LOG(LS_ERROR) << "Failed to convert "
1330                         << VideoFrameBufferTypeToString(buffer->type())
1331                         << " image to I420. Can't encode frame.";
1332       return {};
1333     }
1334     RTC_CHECK(converted_buffer->type() == VideoFrameBuffer::Type::kI420 ||
1335               converted_buffer->type() == VideoFrameBuffer::Type::kI420A);
1336 
1337     // Because `buffer` had to be converted, use `converted_buffer` instead...
1338     buffer = mapped_buffer = converted_buffer;
1339   }
1340 
1341   // Maybe update pixel format.
1342   absl::InlinedVector<VideoFrameBuffer::Type, kMaxPreferredPixelFormats>
1343       mapped_type = {mapped_buffer->type()};
1344   switch (mapped_buffer->type()) {
1345     case VideoFrameBuffer::Type::kI420:
1346     case VideoFrameBuffer::Type::kI420A:
1347       MaybeUpdatePixelFormat(VPX_IMG_FMT_I420);
1348       break;
1349     case VideoFrameBuffer::Type::kNV12:
1350       MaybeUpdatePixelFormat(VPX_IMG_FMT_NV12);
1351       break;
1352     default:
1353       RTC_DCHECK_NOTREACHED();
1354   }
1355 
1356   // Prepare `raw_images_` from `mapped_buffer` and, if simulcast, scaled
1357   // versions of `buffer`.
1358   std::vector<rtc::scoped_refptr<VideoFrameBuffer>> prepared_buffers;
1359   SetRawImagePlanes(&raw_images_[0], mapped_buffer.get());
1360   prepared_buffers.push_back(mapped_buffer);
1361   for (size_t i = 1; i < encoders_.size(); ++i) {
1362     // Native buffers should implement optimized scaling and is the preferred
1363     // buffer to scale. But if the buffer isn't native, it should be cheaper to
1364     // scale from the previously prepared buffer which is smaller than `buffer`.
1365     VideoFrameBuffer* buffer_to_scale =
1366         buffer->type() == VideoFrameBuffer::Type::kNative
1367             ? buffer.get()
1368             : prepared_buffers.back().get();
1369 
1370     auto scaled_buffer =
1371         buffer_to_scale->Scale(raw_images_[i].d_w, raw_images_[i].d_h);
1372     if (scaled_buffer->type() == VideoFrameBuffer::Type::kNative) {
1373       auto mapped_scaled_buffer =
1374           scaled_buffer->GetMappedFrameBuffer(mapped_type);
1375       RTC_DCHECK(mapped_scaled_buffer) << "Unable to map the scaled buffer.";
1376       if (!mapped_scaled_buffer) {
1377         RTC_LOG(LS_ERROR) << "Failed to map scaled "
1378                           << VideoFrameBufferTypeToString(scaled_buffer->type())
1379                           << " image to "
1380                           << VideoFrameBufferTypeToString(mapped_buffer->type())
1381                           << ". Can't encode frame.";
1382         return {};
1383       }
1384       scaled_buffer = mapped_scaled_buffer;
1385     }
1386     if (!IsCompatibleVideoFrameBufferType(scaled_buffer->type(),
1387                                           mapped_buffer->type())) {
1388       RTC_LOG(LS_ERROR) << "When scaling "
1389                         << VideoFrameBufferTypeToString(buffer_to_scale->type())
1390                         << ", the image was unexpectedly converted to "
1391                         << VideoFrameBufferTypeToString(scaled_buffer->type())
1392                         << " instead of "
1393                         << VideoFrameBufferTypeToString(mapped_buffer->type())
1394                         << ". Can't encode frame.";
1395       RTC_DCHECK_NOTREACHED()
1396           << "Scaled buffer type "
1397           << VideoFrameBufferTypeToString(scaled_buffer->type())
1398           << " is not compatible with mapped buffer type "
1399           << VideoFrameBufferTypeToString(mapped_buffer->type());
1400       return {};
1401     }
1402     SetRawImagePlanes(&raw_images_[i], scaled_buffer.get());
1403     prepared_buffers.push_back(scaled_buffer);
1404   }
1405   return prepared_buffers;
1406 }
1407 
1408 // static
1409 LibvpxVp8Encoder::VariableFramerateExperiment
ParseVariableFramerateConfig(std::string group_name)1410 LibvpxVp8Encoder::ParseVariableFramerateConfig(std::string group_name) {
1411   FieldTrialFlag disabled = FieldTrialFlag("Disabled");
1412   FieldTrialParameter<double> framerate_limit("min_fps", 5.0);
1413   FieldTrialParameter<int> qp("min_qp", 15);
1414   FieldTrialParameter<int> undershoot_percentage("undershoot", 30);
1415   ParseFieldTrial({&disabled, &framerate_limit, &qp, &undershoot_percentage},
1416                   field_trial::FindFullName(group_name));
1417   VariableFramerateExperiment config;
1418   config.enabled = !disabled.Get();
1419   config.framerate_limit = framerate_limit.Get();
1420   config.steady_state_qp = qp.Get();
1421   config.steady_state_undershoot_percentage = undershoot_percentage.Get();
1422 
1423   return config;
1424 }
1425 
1426 }  // namespace webrtc
1427