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