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