blob: 4e2d9bd5449bceea6063c70b02b72c30268c1aa4 [file] [log] [blame]
Danil Chapovalov976cc1a2020-03-20 09:36:131/*
2 * Copyright (c) 2020 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#include "modules/video_coding/codecs/av1/libaom_av1_encoder.h"
11
12#include <stddef.h>
13#include <stdint.h>
14
15#include <memory>
Danil Chapovalovb471ac792020-05-15 12:21:0316#include <utility>
Danil Chapovalov976cc1a2020-03-20 09:36:1317#include <vector>
18
19#include "absl/algorithm/container.h"
Danil Chapovalova4d70a82020-05-28 06:47:3720#include "absl/base/macros.h"
Danil Chapovalovb4913a52024-03-11 12:17:4521#include "absl/base/nullability.h"
Sergey Silkind6157042023-06-07 11:45:1422#include "absl/strings/match.h"
Danil Chapovalov54544ec2020-06-25 19:44:3123#include "absl/types/optional.h"
Danil Chapovalovb4913a52024-03-11 12:17:4524#include "api/environment/environment.h"
Sergey Silkind6157042023-06-07 11:45:1425#include "api/field_trials_view.h"
Danil Chapovalov976cc1a2020-03-20 09:36:1326#include "api/scoped_refptr.h"
Sergey Silkind6157042023-06-07 11:45:1427#include "api/transport/field_trial_based_config.h"
Danil Chapovalov976cc1a2020-03-20 09:36:1328#include "api/video/encoded_image.h"
29#include "api/video/i420_buffer.h"
30#include "api/video/video_frame.h"
Evan Shrubsole9b235cd2022-12-06 10:09:1031#include "api/video_codecs/scalability_mode.h"
Danil Chapovalov976cc1a2020-03-20 09:36:1332#include "api/video_codecs/video_codec.h"
33#include "api/video_codecs/video_encoder.h"
34#include "modules/video_coding/include/video_codec_interface.h"
35#include "modules/video_coding/include/video_error_codes.h"
Danil Chapovalov9f4859e2020-10-16 15:45:4136#include "modules/video_coding/svc/create_scalability_structure.h"
Danil Chapovalovda7fe392020-10-15 13:57:1737#include "modules/video_coding/svc/scalable_video_controller.h"
38#include "modules/video_coding/svc/scalable_video_controller_no_layering.h"
Danil Chapovalov976cc1a2020-03-20 09:36:1339#include "rtc_base/checks.h"
Michael Horowitzb27efd42023-02-28 15:59:5040#include "rtc_base/experiments/encoder_info_settings.h"
Danil Chapovalov976cc1a2020-03-20 09:36:1341#include "rtc_base/logging.h"
42#include "third_party/libaom/source/libaom/aom/aom_codec.h"
43#include "third_party/libaom/source/libaom/aom/aom_encoder.h"
44#include "third_party/libaom/source/libaom/aom/aomcx.h"
45
Sergey Silkina4b2b952023-10-06 11:18:4146#if (defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64)) && \
47 (defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS))
48#define MOBILE_ARM
49#endif
50
philipel8c354882022-05-02 08:27:2951#define SET_ENCODER_PARAM_OR_RETURN_ERROR(param_id, param_value) \
52 do { \
53 if (!SetEncoderControlParameters(param_id, param_value)) { \
54 return WEBRTC_VIDEO_CODEC_ERROR; \
55 } \
56 } while (0)
57
Danil Chapovalov976cc1a2020-03-20 09:36:1358namespace webrtc {
59namespace {
60
61// Encoder configuration parameters
Danil Chapovalov976cc1a2020-03-20 09:36:1362constexpr int kQpMin = 10;
Fyodor Kyslovb4547672021-04-05 21:37:3263constexpr int kUsageProfile = AOM_USAGE_REALTIME;
Florent Castelli90b74382022-04-25 15:28:0064constexpr int kMinQindex = 145; // Min qindex threshold for QP scaling.
65constexpr int kMaxQindex = 205; // Max qindex threshold for QP scaling.
Danil Chapovalov976cc1a2020-03-20 09:36:1366constexpr int kBitDepth = 8;
67constexpr int kLagInFrames = 0; // No look ahead.
68constexpr int kRtpTicksPerSecond = 90000;
Wan-Teh Changf6eb9d62023-02-14 22:28:4769constexpr double kMinimumFrameRate = 1.0;
Danil Chapovalov976cc1a2020-03-20 09:36:1370
Jerome Jiang04a65292021-02-18 23:21:3971aom_superblock_size_t GetSuperblockSize(int width, int height, int threads) {
72 int resolution = width * height;
73 if (threads >= 4 && resolution >= 960 * 540 && resolution < 1920 * 1080)
74 return AOM_SUPERBLOCK_SIZE_64X64;
75 else
76 return AOM_SUPERBLOCK_SIZE_DYNAMIC;
77}
78
Danil Chapovalov976cc1a2020-03-20 09:36:1379class LibaomAv1Encoder final : public VideoEncoder {
80 public:
Sergey Silkind6157042023-06-07 11:45:1481 LibaomAv1Encoder(const absl::optional<LibaomAv1EncoderAuxConfig>& aux_config,
82 const FieldTrialsView& trials);
Danil Chapovalov976cc1a2020-03-20 09:36:1383 ~LibaomAv1Encoder();
84
85 int InitEncode(const VideoCodec* codec_settings,
86 const Settings& settings) override;
87
88 int32_t RegisterEncodeCompleteCallback(
89 EncodedImageCallback* encoded_image_callback) override;
90
91 int32_t Release() override;
92
93 int32_t Encode(const VideoFrame& frame,
94 const std::vector<VideoFrameType>* frame_types) override;
95
96 void SetRates(const RateControlParameters& parameters) override;
97
98 EncoderInfo GetEncoderInfo() const override;
99
100 private:
philipel8c354882022-05-02 08:27:29101 template <typename P>
102 bool SetEncoderControlParameters(int param_id, P param_value);
103
“Michael15ee87f2022-03-03 18:09:02104 // Get value to be used for encoder cpu_speed setting
105 int GetCpuSpeed(int width, int height);
106
Jerome Jiang39d1f742020-12-17 01:54:33107 // Determine number of encoder threads to use.
108 int NumberOfThreads(int width, int height, int number_of_cores);
109
Danil Chapovalov54544ec2020-06-25 19:44:31110 bool SvcEnabled() const { return svc_params_.has_value(); }
111 // Fills svc_params_ memeber value. Returns false on error.
Danil Chapovalova4d70a82020-05-28 06:47:37112 bool SetSvcParams(ScalableVideoController::StreamLayersConfig svc_config);
113 // Configures the encoder with layer for the next frame.
114 void SetSvcLayerId(
115 const ScalableVideoController::LayerFrameConfig& layer_frame);
116 // Configures the encoder which buffers next frame updates and can reference.
117 void SetSvcRefFrameConfig(
118 const ScalableVideoController::LayerFrameConfig& layer_frame);
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07119 // If pixel format doesn't match, then reallocate.
120 void MaybeRewrapImgWithFormat(const aom_img_fmt_t fmt);
Danil Chapovalova4d70a82020-05-28 06:47:37121
Danil Chapovalov9f4859e2020-10-16 15:45:41122 std::unique_ptr<ScalableVideoController> svc_controller_;
Evan Shrubsole9b235cd2022-12-06 10:09:10123 absl::optional<ScalabilityMode> scalability_mode_;
Danil Chapovalov976cc1a2020-03-20 09:36:13124 bool inited_;
philipel0763ccc2021-12-01 14:12:54125 bool rates_configured_;
Danil Chapovalov54544ec2020-06-25 19:44:31126 absl::optional<aom_svc_params_t> svc_params_;
Danil Chapovalov976cc1a2020-03-20 09:36:13127 VideoCodec encoder_settings_;
philipel30ec7252022-05-04 09:20:04128 absl::optional<LibaomAv1EncoderAuxConfig> aux_config_;
Danil Chapovalov976cc1a2020-03-20 09:36:13129 aom_image_t* frame_for_encode_;
130 aom_codec_ctx_t ctx_;
131 aom_codec_enc_cfg_t cfg_;
132 EncodedImageCallback* encoded_image_callback_;
Erik SprĂĄngff1cf612023-02-23 17:41:13133 int64_t timestamp_;
Michael Horowitzb27efd42023-02-28 15:59:50134 const LibaomAv1EncoderInfoSettings encoder_info_override_;
Sergey Silkind6157042023-06-07 11:45:14135 // TODO(webrtc:15225): Kill switch for disabling frame dropping. Remove it
136 // after frame dropping is fully rolled out.
137 bool disable_frame_dropping_;
Dan Tan48601482024-01-31 17:11:18138 int max_consec_frame_drop_;
Danil Chapovalov976cc1a2020-03-20 09:36:13139};
140
141int32_t VerifyCodecSettings(const VideoCodec& codec_settings) {
142 if (codec_settings.width < 1) {
143 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
144 }
145 if (codec_settings.height < 1) {
146 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
147 }
148 // maxBitrate == 0 represents an unspecified maxBitRate.
149 if (codec_settings.maxBitrate > 0 &&
150 codec_settings.minBitrate > codec_settings.maxBitrate) {
151 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
152 }
153 if (codec_settings.maxBitrate > 0 &&
154 codec_settings.startBitrate > codec_settings.maxBitrate) {
155 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
156 }
157 if (codec_settings.startBitrate < codec_settings.minBitrate) {
158 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
159 }
160 if (codec_settings.maxFramerate < 1) {
161 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
162 }
Wan-Teh Chang8f29b422023-03-16 01:39:57163 if (codec_settings.qpMax < kQpMin || codec_settings.qpMax > 63) {
164 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
165 }
Danil Chapovalov976cc1a2020-03-20 09:36:13166 return WEBRTC_VIDEO_CODEC_OK;
167}
168
Dan Tan48601482024-01-31 17:11:18169int GetMaxConsecutiveFrameDrop(const FieldTrialsView& field_trials) {
170 webrtc::FieldTrialParameter<int> maxdrop("maxdrop", 0);
171 webrtc::ParseFieldTrial(
172 {&maxdrop},
173 field_trials.Lookup("WebRTC-LibaomAv1Encoder-MaxConsecFrameDrop"));
174 return maxdrop;
175}
176
philipel30ec7252022-05-04 09:20:04177LibaomAv1Encoder::LibaomAv1Encoder(
Sergey Silkind6157042023-06-07 11:45:14178 const absl::optional<LibaomAv1EncoderAuxConfig>& aux_config,
179 const FieldTrialsView& trials)
Danil Chapovalov11215fe2021-01-21 14:56:05180 : inited_(false),
philipel0763ccc2021-12-01 14:12:54181 rates_configured_(false),
philipel30ec7252022-05-04 09:20:04182 aux_config_(aux_config),
Danil Chapovalov976cc1a2020-03-20 09:36:13183 frame_for_encode_(nullptr),
Erik SprĂĄngff1cf612023-02-23 17:41:13184 encoded_image_callback_(nullptr),
Sergey Silkind6157042023-06-07 11:45:14185 timestamp_(0),
186 disable_frame_dropping_(absl::StartsWith(
187 trials.Lookup("WebRTC-LibaomAv1Encoder-DisableFrameDropping"),
Dan Tan48601482024-01-31 17:11:18188 "Enabled")),
189 max_consec_frame_drop_(GetMaxConsecutiveFrameDrop(trials)) {}
Danil Chapovalov976cc1a2020-03-20 09:36:13190
191LibaomAv1Encoder::~LibaomAv1Encoder() {
192 Release();
193}
194
195int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings,
196 const Settings& settings) {
197 if (codec_settings == nullptr) {
198 RTC_LOG(LS_WARNING) << "No codec settings provided to "
199 "LibaomAv1Encoder.";
200 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
201 }
202 if (settings.number_of_cores < 1) {
203 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
204 }
205 if (inited_) {
206 RTC_LOG(LS_WARNING) << "Initing LibaomAv1Encoder without first releasing.";
207 Release();
208 }
209 encoder_settings_ = *codec_settings;
210
211 // Sanity checks for encoder configuration.
212 const int32_t result = VerifyCodecSettings(encoder_settings_);
213 if (result < 0) {
214 RTC_LOG(LS_WARNING) << "Incorrect codec settings provided to "
215 "LibaomAv1Encoder.";
216 return result;
217 }
Danil Chapovalov9f4859e2020-10-16 15:45:41218 if (encoder_settings_.numberOfSimulcastStreams > 1) {
219 RTC_LOG(LS_WARNING) << "Simulcast is not implemented by LibaomAv1Encoder.";
220 return result;
221 }
Evan Shrubsole9b235cd2022-12-06 10:09:10222 scalability_mode_ = encoder_settings_.GetScalabilityMode();
223 if (!scalability_mode_.has_value()) {
Niels Möllercc171952022-04-06 11:37:40224 RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'.";
Evan Shrubsole9b235cd2022-12-06 10:09:10225 scalability_mode_ = ScalabilityMode::kL1T1;
Danil Chapovalov9f4859e2020-10-16 15:45:41226 }
Evan Shrubsole9b235cd2022-12-06 10:09:10227 svc_controller_ = CreateScalabilityStructure(*scalability_mode_);
Danil Chapovalov9f4859e2020-10-16 15:45:41228 if (svc_controller_ == nullptr) {
229 RTC_LOG(LS_WARNING) << "Failed to set scalability mode "
Evan Shrubsole9b235cd2022-12-06 10:09:10230 << static_cast<int>(*scalability_mode_);
Danil Chapovalov9f4859e2020-10-16 15:45:41231 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
232 }
Danil Chapovalov976cc1a2020-03-20 09:36:13233
Danil Chapovalov54544ec2020-06-25 19:44:31234 if (!SetSvcParams(svc_controller_->StreamConfig())) {
235 return WEBRTC_VIDEO_CODEC_ERROR;
236 }
237
Danil Chapovalov976cc1a2020-03-20 09:36:13238 // Initialize encoder configuration structure with default values
239 aom_codec_err_t ret =
Fyodor Kyslovb4547672021-04-05 21:37:32240 aom_codec_enc_config_default(aom_codec_av1_cx(), &cfg_, kUsageProfile);
Danil Chapovalov976cc1a2020-03-20 09:36:13241 if (ret != AOM_CODEC_OK) {
242 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
243 << " on aom_codec_enc_config_default.";
244 return WEBRTC_VIDEO_CODEC_ERROR;
245 }
246
247 // Overwrite default config with input encoder settings & RTC-relevant values.
248 cfg_.g_w = encoder_settings_.width;
249 cfg_.g_h = encoder_settings_.height;
Jerome Jiang39d1f742020-12-17 01:54:33250 cfg_.g_threads =
251 NumberOfThreads(cfg_.g_w, cfg_.g_h, settings.number_of_cores);
Danil Chapovalov976cc1a2020-03-20 09:36:13252 cfg_.g_timebase.num = 1;
253 cfg_.g_timebase.den = kRtpTicksPerSecond;
Yu-Chen (Eric) Sun35f2b892023-04-05 20:29:21254 cfg_.rc_target_bitrate = encoder_settings_.startBitrate; // kilobits/sec.
Sergey Silkind6157042023-06-07 11:45:14255 cfg_.rc_dropframe_thresh =
256 (!disable_frame_dropping_ && encoder_settings_.GetFrameDropEnabled()) ? 30
257 : 0;
Danil Chapovalov976cc1a2020-03-20 09:36:13258 cfg_.g_input_bit_depth = kBitDepth;
259 cfg_.kf_mode = AOM_KF_DISABLED;
260 cfg_.rc_min_quantizer = kQpMin;
Jerome Jiang7f7fb832020-06-04 03:44:50261 cfg_.rc_max_quantizer = encoder_settings_.qpMax;
Jerome Jiangd45f9302021-07-01 04:10:10262 cfg_.rc_undershoot_pct = 50;
263 cfg_.rc_overshoot_pct = 50;
264 cfg_.rc_buf_initial_sz = 600;
265 cfg_.rc_buf_optimal_sz = 600;
266 cfg_.rc_buf_sz = 1000;
Danil Chapovalov976cc1a2020-03-20 09:36:13267 cfg_.g_usage = kUsageProfile;
Jerome Jiang7a9b96f2020-07-20 21:31:34268 cfg_.g_error_resilient = 0;
Danil Chapovalov976cc1a2020-03-20 09:36:13269 // Low-latency settings.
270 cfg_.rc_end_usage = AOM_CBR; // Constant Bit Rate (CBR) mode
271 cfg_.g_pass = AOM_RC_ONE_PASS; // One-pass rate control
272 cfg_.g_lag_in_frames = kLagInFrames; // No look ahead when lag equals 0.
273
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07274 if (frame_for_encode_ != nullptr) {
275 aom_img_free(frame_for_encode_);
276 frame_for_encode_ = nullptr;
277 }
Danil Chapovalov976cc1a2020-03-20 09:36:13278
279 // Flag options: AOM_CODEC_USE_PSNR and AOM_CODEC_USE_HIGHBITDEPTH
280 aom_codec_flags_t flags = 0;
281
282 // Initialize an encoder instance.
283 ret = aom_codec_enc_init(&ctx_, aom_codec_av1_cx(), &cfg_, flags);
284 if (ret != AOM_CODEC_OK) {
285 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
286 << " on aom_codec_enc_init.";
287 return WEBRTC_VIDEO_CODEC_ERROR;
288 }
289 inited_ = true;
290
291 // Set control parameters
philipel8c354882022-05-02 08:27:29292 SET_ENCODER_PARAM_OR_RETURN_ERROR(AOME_SET_CPUUSED,
293 GetCpuSpeed(cfg_.g_w, cfg_.g_h));
294 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_CDEF, 1);
295 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_TPL_MODEL, 0);
296 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_DELTAQ_MODE, 0);
297 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_ORDER_HINT, 0);
298 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_AQ_MODE, 3);
299 SET_ENCODER_PARAM_OR_RETURN_ERROR(AOME_SET_MAX_INTRA_BITRATE_PCT, 300);
300 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_COEFF_COST_UPD_FREQ, 3);
301 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MODE_COST_UPD_FREQ, 3);
302 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MV_COST_UPD_FREQ, 3);
Danil Chapovalovb471ac792020-05-15 12:21:03303
Jerome Jianga78c9492022-04-04 18:24:53304 if (codec_settings->mode == VideoCodecMode::kScreensharing) {
philipel8c354882022-05-02 08:27:29305 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_TUNE_CONTENT,
306 AOM_CONTENT_SCREEN);
307 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_PALETTE, 1);
308 } else {
309 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_PALETTE, 0);
Jerome Jianga78c9492022-04-04 18:24:53310 }
311
Dan Tan48601482024-01-31 17:11:18312 if (codec_settings->mode == VideoCodecMode::kRealtimeVideo &&
313 encoder_settings_.GetFrameDropEnabled() && max_consec_frame_drop_ > 0) {
314 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MAX_CONSEC_FRAME_DROP_CBR,
315 max_consec_frame_drop_);
316 }
317
Jerome Jiang3403acb2023-06-07 14:17:41318 if (cfg_.g_threads == 8) {
319 // Values passed to AV1E_SET_TILE_ROWS and AV1E_SET_TILE_COLUMNS are log2()
320 // based.
321 // Use 4 tile columns x 2 tile rows for 8 threads.
322 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_TILE_ROWS, 1);
323 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_TILE_COLUMNS, 2);
324 } else if (cfg_.g_threads == 4) {
325 // Use 2 tile columns x 2 tile rows for 4 threads.
326 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_TILE_ROWS, 1);
327 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_TILE_COLUMNS, 1);
Jerome Jiang90ea0a62021-02-22 17:37:37328 } else {
philipel8c354882022-05-02 08:27:29329 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_TILE_COLUMNS,
330 static_cast<int>(log2(cfg_.g_threads)));
Jerome Jiang39d1f742020-12-17 01:54:33331 }
332
philipel8c354882022-05-02 08:27:29333 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ROW_MT, 1);
334 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_OBMC, 0);
335 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_NOISE_SENSITIVITY, 0);
336 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_WARPED_MOTION, 0);
337 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_GLOBAL_MOTION, 0);
338 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_REF_FRAME_MVS, 0);
339 SET_ENCODER_PARAM_OR_RETURN_ERROR(
340 AV1E_SET_SUPERBLOCK_SIZE,
341 GetSuperblockSize(cfg_.g_w, cfg_.g_h, cfg_.g_threads));
342 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_CFL_INTRA, 0);
343 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_SMOOTH_INTRA, 0);
344 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_ANGLE_DELTA, 0);
345 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_FILTER_INTRA, 0);
346 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_INTRA_DEFAULT_TX_ONLY, 1);
347 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_DISABLE_TRELLIS_QUANT, 1);
348 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_DIST_WTD_COMP, 0);
349 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_DIFF_WTD_COMP, 0);
350 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_DUAL_FILTER, 0);
351 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTERINTRA_COMP, 0);
352 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTERINTRA_WEDGE, 0);
353 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTRA_EDGE_FILTER, 0);
354 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTRABC, 0);
355 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_MASKED_COMP, 0);
356 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_PAETH_INTRA, 0);
357 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_QM, 0);
358 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_RECT_PARTITIONS, 0);
359 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_RESTORATION, 0);
360 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_SMOOTH_INTERINTRA, 0);
361 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_TX64, 0);
362 SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MAX_REFERENCE_FRAMES, 3);
Fyodor Kyslov26abdaf2021-03-22 20:53:57363
Danil Chapovalov976cc1a2020-03-20 09:36:13364 return WEBRTC_VIDEO_CODEC_OK;
365}
366
philipel8c354882022-05-02 08:27:29367template <typename P>
368bool LibaomAv1Encoder::SetEncoderControlParameters(int param_id,
369 P param_value) {
370 aom_codec_err_t error_code = aom_codec_control(&ctx_, param_id, param_value);
371 if (error_code != AOM_CODEC_OK) {
372 RTC_LOG(LS_WARNING)
373 << "LibaomAv1Encoder::SetEncoderControlParameters returned "
374 << error_code << " on id: " << param_id << ".";
375 }
376 return error_code == AOM_CODEC_OK;
377}
378
Johannes Kron17e35802024-03-07 15:41:34379// Only positive speeds, range for real-time coding currently is: 6 - 10.
380// Speed 11 is used for screen sharing.
“Michael15ee87f2022-03-03 18:09:02381// Lower means slower/better quality, higher means fastest/lower quality.
382int LibaomAv1Encoder::GetCpuSpeed(int width, int height) {
philipel30ec7252022-05-04 09:20:04383 if (aux_config_) {
384 if (auto it = aux_config_->max_pixel_count_to_cpu_speed.lower_bound(width *
385 height);
386 it != aux_config_->max_pixel_count_to_cpu_speed.end()) {
387 return it->second;
388 }
389
390 return 10;
391 } else {
Johannes Kron17e35802024-03-07 15:41:34392 if (encoder_settings_.mode == VideoCodecMode::kScreensharing) {
393 return 11;
394 }
philipel30ec7252022-05-04 09:20:04395 // For smaller resolutions, use lower speed setting (get some coding gain at
396 // the cost of increased encoding complexity).
397 switch (encoder_settings_.GetVideoEncoderComplexity()) {
398 case VideoCodecComplexity::kComplexityHigh:
399 if (width * height <= 320 * 180)
400 return 8;
401 else if (width * height <= 640 * 360)
402 return 9;
403 else
404 return 10;
405 case VideoCodecComplexity::kComplexityHigher:
406 if (width * height <= 320 * 180)
407 return 7;
408 else if (width * height <= 640 * 360)
409 return 8;
410 else if (width * height <= 1280 * 720)
411 return 9;
412 else
413 return 10;
414 case VideoCodecComplexity::kComplexityMax:
415 if (width * height <= 320 * 180)
416 return 6;
417 else if (width * height <= 640 * 360)
418 return 7;
419 else if (width * height <= 1280 * 720)
420 return 8;
421 else
422 return 9;
423 default:
“Michael15ee87f2022-03-03 18:09:02424 return 10;
philipel30ec7252022-05-04 09:20:04425 }
“Michael15ee87f2022-03-03 18:09:02426 }
427}
428
Jerome Jiang39d1f742020-12-17 01:54:33429int LibaomAv1Encoder::NumberOfThreads(int width,
430 int height,
431 int number_of_cores) {
Jerome Jiang90ea0a62021-02-22 17:37:37432 // Keep the number of encoder threads equal to the possible number of
433 // column/row tiles, which is (1, 2, 4, 8). See comments below for
434 // AV1E_SET_TILE_COLUMNS/ROWS.
Jerome Jiang3403acb2023-06-07 14:17:41435 if (width * height > 1280 * 720 && number_of_cores > 8) {
436 return 8;
437 } else if (width * height >= 640 * 360 && number_of_cores > 4) {
Jerome Jiang39d1f742020-12-17 01:54:33438 return 4;
Jerome Jiang90ea0a62021-02-22 17:37:37439 } else if (width * height >= 320 * 180 && number_of_cores > 2) {
Jerome Jiang39d1f742020-12-17 01:54:33440 return 2;
441 } else {
442// Use 2 threads for low res on ARM.
Sergey Silkina4b2b952023-10-06 11:18:41443#ifdef MOBILE_ARM
Jerome Jiang39d1f742020-12-17 01:54:33444 if (width * height >= 320 * 180 && number_of_cores > 2) {
445 return 2;
446 }
447#endif
448 // 1 thread less than VGA.
449 return 1;
450 }
451}
452
Danil Chapovalova4d70a82020-05-28 06:47:37453bool LibaomAv1Encoder::SetSvcParams(
454 ScalableVideoController::StreamLayersConfig svc_config) {
Danil Chapovalov54544ec2020-06-25 19:44:31455 bool svc_enabled =
Danil Chapovalova4d70a82020-05-28 06:47:37456 svc_config.num_spatial_layers > 1 || svc_config.num_temporal_layers > 1;
Danil Chapovalov54544ec2020-06-25 19:44:31457 if (!svc_enabled) {
458 svc_params_ = absl::nullopt;
Danil Chapovalova4d70a82020-05-28 06:47:37459 return true;
460 }
Danil Chapovalova4d70a82020-05-28 06:47:37461 if (svc_config.num_spatial_layers < 1 || svc_config.num_spatial_layers > 4) {
462 RTC_LOG(LS_WARNING) << "Av1 supports up to 4 spatial layers. "
463 << svc_config.num_spatial_layers << " configured.";
464 return false;
465 }
466 if (svc_config.num_temporal_layers < 1 ||
467 svc_config.num_temporal_layers > 8) {
468 RTC_LOG(LS_WARNING) << "Av1 supports up to 8 temporal layers. "
469 << svc_config.num_temporal_layers << " configured.";
470 return false;
471 }
Danil Chapovalov54544ec2020-06-25 19:44:31472 aom_svc_params_t& svc_params = svc_params_.emplace();
Danil Chapovalova4d70a82020-05-28 06:47:37473 svc_params.number_spatial_layers = svc_config.num_spatial_layers;
474 svc_params.number_temporal_layers = svc_config.num_temporal_layers;
475
476 int num_layers =
477 svc_config.num_spatial_layers * svc_config.num_temporal_layers;
478 for (int i = 0; i < num_layers; ++i) {
479 svc_params.min_quantizers[i] = kQpMin;
Jerome Jiang7f7fb832020-06-04 03:44:50480 svc_params.max_quantizers[i] = encoder_settings_.qpMax;
Danil Chapovalova4d70a82020-05-28 06:47:37481 }
482
483 // Assume each temporal layer doubles framerate.
484 for (int tid = 0; tid < svc_config.num_temporal_layers; ++tid) {
485 svc_params.framerate_factor[tid] =
486 1 << (svc_config.num_temporal_layers - tid - 1);
487 }
488
Danil Chapovalova4d70a82020-05-28 06:47:37489 for (int sid = 0; sid < svc_config.num_spatial_layers; ++sid) {
Danil Chapovalov1e10a612020-07-02 13:27:03490 svc_params.scaling_factor_num[sid] = svc_config.scaling_factor_num[sid];
491 svc_params.scaling_factor_den[sid] = svc_config.scaling_factor_den[sid];
Danil Chapovalova4d70a82020-05-28 06:47:37492 }
493
Wan-Teh Chang8f29b422023-03-16 01:39:57494 // svc_params.layer_target_bitrate is set in SetRates() before svc_params is
Wan-Teh Changad192a82023-03-16 23:15:17495 // passed to SetEncoderControlParameters(AV1E_SET_SVC_PARAMS).
Wan-Teh Chang8f29b422023-03-16 01:39:57496
Danil Chapovalova4d70a82020-05-28 06:47:37497 return true;
498}
499
500void LibaomAv1Encoder::SetSvcLayerId(
501 const ScalableVideoController::LayerFrameConfig& layer_frame) {
502 aom_svc_layer_id_t layer_id = {};
Danil Chapovalova48dd432020-06-08 17:47:08503 layer_id.spatial_layer_id = layer_frame.SpatialId();
504 layer_id.temporal_layer_id = layer_frame.TemporalId();
philipel8c354882022-05-02 08:27:29505 SetEncoderControlParameters(AV1E_SET_SVC_LAYER_ID, &layer_id);
Danil Chapovalova4d70a82020-05-28 06:47:37506}
507
508void LibaomAv1Encoder::SetSvcRefFrameConfig(
509 const ScalableVideoController::LayerFrameConfig& layer_frame) {
510 // Buffer name to use for each layer_frame.buffers position. In particular
511 // when there are 2 buffers are referenced, prefer name them last and golden,
512 // because av1 bitstream format has dedicated fields for these two names.
513 // See last_frame_idx and golden_frame_idx in the av1 spec
514 // https://aomediacodec.github.io/av1-spec/av1-spec.pdf
515 static constexpr int kPreferedSlotName[] = {0, // Last
516 3, // Golden
517 1, 2, 4, 5, 6};
518 static constexpr int kAv1NumBuffers = 8;
519
520 aom_svc_ref_frame_config_t ref_frame_config = {};
Danil Chapovalova48dd432020-06-08 17:47:08521 RTC_CHECK_LE(layer_frame.Buffers().size(), ABSL_ARRAYSIZE(kPreferedSlotName));
522 for (size_t i = 0; i < layer_frame.Buffers().size(); ++i) {
523 const CodecBufferUsage& buffer = layer_frame.Buffers()[i];
Danil Chapovalova4d70a82020-05-28 06:47:37524 int slot_name = kPreferedSlotName[i];
525 RTC_CHECK_GE(buffer.id, 0);
526 RTC_CHECK_LT(buffer.id, kAv1NumBuffers);
527 ref_frame_config.ref_idx[slot_name] = buffer.id;
528 if (buffer.referenced) {
529 ref_frame_config.reference[slot_name] = 1;
530 }
531 if (buffer.updated) {
532 ref_frame_config.refresh[buffer.id] = 1;
533 }
534 }
philipel8c354882022-05-02 08:27:29535
536 SetEncoderControlParameters(AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config);
Danil Chapovalova4d70a82020-05-28 06:47:37537}
538
Danil Chapovalov976cc1a2020-03-20 09:36:13539int32_t LibaomAv1Encoder::RegisterEncodeCompleteCallback(
540 EncodedImageCallback* encoded_image_callback) {
541 encoded_image_callback_ = encoded_image_callback;
542 return WEBRTC_VIDEO_CODEC_OK;
543}
544
545int32_t LibaomAv1Encoder::Release() {
546 if (frame_for_encode_ != nullptr) {
547 aom_img_free(frame_for_encode_);
548 frame_for_encode_ = nullptr;
549 }
550 if (inited_) {
551 if (aom_codec_destroy(&ctx_)) {
552 return WEBRTC_VIDEO_CODEC_MEMORY;
553 }
554 inited_ = false;
555 }
philipel0763ccc2021-12-01 14:12:54556 rates_configured_ = false;
Danil Chapovalov976cc1a2020-03-20 09:36:13557 return WEBRTC_VIDEO_CODEC_OK;
558}
559
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07560void LibaomAv1Encoder::MaybeRewrapImgWithFormat(const aom_img_fmt_t fmt) {
561 if (!frame_for_encode_) {
562 frame_for_encode_ =
563 aom_img_wrap(nullptr, fmt, cfg_.g_w, cfg_.g_h, 1, nullptr);
564
565 } else if (frame_for_encode_->fmt != fmt) {
566 RTC_LOG(LS_INFO) << "Switching AV1 encoder pixel format to "
567 << (fmt == AOM_IMG_FMT_NV12 ? "NV12" : "I420");
568 aom_img_free(frame_for_encode_);
569 frame_for_encode_ =
570 aom_img_wrap(nullptr, fmt, cfg_.g_w, cfg_.g_h, 1, nullptr);
571 }
572 // else no-op since the image is already in the right format.
573}
574
Danil Chapovalov976cc1a2020-03-20 09:36:13575int32_t LibaomAv1Encoder::Encode(
576 const VideoFrame& frame,
577 const std::vector<VideoFrameType>* frame_types) {
philipel0763ccc2021-12-01 14:12:54578 if (!inited_ || encoded_image_callback_ == nullptr || !rates_configured_) {
Danil Chapovalov976cc1a2020-03-20 09:36:13579 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
580 }
581
Danil Chapovalova4d70a82020-05-28 06:47:37582 bool keyframe_required =
Danil Chapovalov976cc1a2020-03-20 09:36:13583 frame_types != nullptr &&
584 absl::c_linear_search(*frame_types, VideoFrameType::kVideoFrameKey);
585
Danil Chapovalovb471ac792020-05-15 12:21:03586 std::vector<ScalableVideoController::LayerFrameConfig> layer_frames =
Danil Chapovalova4d70a82020-05-28 06:47:37587 svc_controller_->NextFrameConfig(keyframe_required);
Danil Chapovalovb471ac792020-05-15 12:21:03588
589 if (layer_frames.empty()) {
590 RTC_LOG(LS_ERROR) << "SVCController returned no configuration for a frame.";
591 return WEBRTC_VIDEO_CODEC_ERROR;
592 }
593
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07594 rtc::scoped_refptr<VideoFrameBuffer> buffer = frame.video_frame_buffer();
595 absl::InlinedVector<VideoFrameBuffer::Type, kMaxPreferredPixelFormats>
596 supported_formats = {VideoFrameBuffer::Type::kI420,
597 VideoFrameBuffer::Type::kNV12};
598 rtc::scoped_refptr<VideoFrameBuffer> mapped_buffer;
599 if (buffer->type() != VideoFrameBuffer::Type::kNative) {
600 // `buffer` is already mapped.
601 mapped_buffer = buffer;
602 } else {
603 // Attempt to map to one of the supported formats.
604 mapped_buffer = buffer->GetMappedFrameBuffer(supported_formats);
605 }
606
Danil Chapovalov976cc1a2020-03-20 09:36:13607 // Convert input frame to I420, if needed.
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07608 if (!mapped_buffer ||
609 (absl::c_find(supported_formats, mapped_buffer->type()) ==
610 supported_formats.end() &&
611 mapped_buffer->type() != VideoFrameBuffer::Type::kI420A)) {
philipelab68a912022-03-30 11:55:49612 rtc::scoped_refptr<I420BufferInterface> converted_buffer(buffer->ToI420());
Evan Shrubsolef906ec42021-06-21 11:47:44613 if (!converted_buffer) {
614 RTC_LOG(LS_ERROR) << "Failed to convert "
615 << VideoFrameBufferTypeToString(
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07616 frame.video_frame_buffer()->type())
Evan Shrubsolef906ec42021-06-21 11:47:44617 << " image to I420. Can't encode frame.";
618 return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
619 }
Byoungchan Lee75ac5ab2021-07-27 12:27:46620 RTC_CHECK(converted_buffer->type() == VideoFrameBuffer::Type::kI420 ||
621 converted_buffer->type() == VideoFrameBuffer::Type::kI420A);
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07622
623 mapped_buffer = converted_buffer;
Danil Chapovalov976cc1a2020-03-20 09:36:13624 }
625
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07626 switch (mapped_buffer->type()) {
627 case VideoFrameBuffer::Type::kI420:
628 case VideoFrameBuffer::Type::kI420A: {
629 // Set frame_for_encode_ data pointers and strides.
630 MaybeRewrapImgWithFormat(AOM_IMG_FMT_I420);
631 auto i420_buffer = mapped_buffer->GetI420();
632 RTC_DCHECK(i420_buffer);
633 frame_for_encode_->planes[AOM_PLANE_Y] =
634 const_cast<unsigned char*>(i420_buffer->DataY());
635 frame_for_encode_->planes[AOM_PLANE_U] =
636 const_cast<unsigned char*>(i420_buffer->DataU());
637 frame_for_encode_->planes[AOM_PLANE_V] =
638 const_cast<unsigned char*>(i420_buffer->DataV());
639 frame_for_encode_->stride[AOM_PLANE_Y] = i420_buffer->StrideY();
640 frame_for_encode_->stride[AOM_PLANE_U] = i420_buffer->StrideU();
641 frame_for_encode_->stride[AOM_PLANE_V] = i420_buffer->StrideV();
642 break;
643 }
644 case VideoFrameBuffer::Type::kNV12: {
645 MaybeRewrapImgWithFormat(AOM_IMG_FMT_NV12);
646 const NV12BufferInterface* nv12_buffer = mapped_buffer->GetNV12();
647 RTC_DCHECK(nv12_buffer);
648 frame_for_encode_->planes[AOM_PLANE_Y] =
649 const_cast<unsigned char*>(nv12_buffer->DataY());
650 frame_for_encode_->planes[AOM_PLANE_U] =
651 const_cast<unsigned char*>(nv12_buffer->DataUV());
652 frame_for_encode_->planes[AOM_PLANE_V] = nullptr;
653 frame_for_encode_->stride[AOM_PLANE_Y] = nv12_buffer->StrideY();
654 frame_for_encode_->stride[AOM_PLANE_U] = nv12_buffer->StrideUV();
655 frame_for_encode_->stride[AOM_PLANE_V] = 0;
656 break;
657 }
658 default:
659 return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
660 }
Danil Chapovalov976cc1a2020-03-20 09:36:13661
662 const uint32_t duration =
663 kRtpTicksPerSecond / static_cast<float>(encoder_settings_.maxFramerate);
Erik SprĂĄngff1cf612023-02-23 17:41:13664 timestamp_ += duration;
Danil Chapovalov976cc1a2020-03-20 09:36:13665
philipel448231d2021-10-27 09:29:45666 const size_t num_spatial_layers =
667 svc_params_ ? svc_params_->number_spatial_layers : 1;
philipeld3eb8f12021-11-01 10:58:50668 auto next_layer_frame = layer_frames.begin();
philipel448231d2021-10-27 09:29:45669 for (size_t i = 0; i < num_spatial_layers; ++i) {
670 // The libaom AV1 encoder requires that `aom_codec_encode` is called for
671 // every spatial layer, even if the configured bitrate for that layer is
672 // zero. For zero bitrate spatial layers no frames will be produced.
673 absl::optional<ScalableVideoController::LayerFrameConfig>
674 non_encoded_layer_frame;
675 ScalableVideoController::LayerFrameConfig* layer_frame;
philipeld3eb8f12021-11-01 10:58:50676 if (next_layer_frame != layer_frames.end() &&
677 next_layer_frame->SpatialId() == static_cast<int>(i)) {
678 layer_frame = &*next_layer_frame;
679 ++next_layer_frame;
philipel448231d2021-10-27 09:29:45680 } else {
681 // For layers that are not encoded only the spatial id matters.
682 non_encoded_layer_frame.emplace().S(i);
683 layer_frame = &*non_encoded_layer_frame;
684 }
philipeld3eb8f12021-11-01 10:58:50685 const bool end_of_picture = (next_layer_frame == layer_frames.end());
Danil Chapovalov06bbeb32020-11-11 11:42:56686
Danil Chapovalovb471ac792020-05-15 12:21:03687 aom_enc_frame_flags_t flags =
philipel448231d2021-10-27 09:29:45688 layer_frame->IsKeyframe() ? AOM_EFLAG_FORCE_KF : 0;
Danil Chapovalov976cc1a2020-03-20 09:36:13689
Danil Chapovalov54544ec2020-06-25 19:44:31690 if (SvcEnabled()) {
philipel448231d2021-10-27 09:29:45691 SetSvcLayerId(*layer_frame);
692 SetSvcRefFrameConfig(*layer_frame);
Danil Chapovalova4d70a82020-05-28 06:47:37693 }
Danil Chapovalov976cc1a2020-03-20 09:36:13694
Erik SprĂĄngff1cf612023-02-23 17:41:13695 // Encode a frame. The presentation timestamp `pts` should not use real
696 // timestamps from frames or the wall clock, as that can cause the rate
697 // controller to misbehave.
698 aom_codec_err_t ret =
699 aom_codec_encode(&ctx_, frame_for_encode_, timestamp_, duration, flags);
Danil Chapovalovb471ac792020-05-15 12:21:03700 if (ret != AOM_CODEC_OK) {
701 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << ret
702 << " on aom_codec_encode.";
703 return WEBRTC_VIDEO_CODEC_ERROR;
Danil Chapovalov976cc1a2020-03-20 09:36:13704 }
Danil Chapovalov976cc1a2020-03-20 09:36:13705
philipel448231d2021-10-27 09:29:45706 if (non_encoded_layer_frame) {
707 continue;
708 }
709
Danil Chapovalovb471ac792020-05-15 12:21:03710 // Get encoded image data.
711 EncodedImage encoded_image;
Danil Chapovalovb471ac792020-05-15 12:21:03712 aom_codec_iter_t iter = nullptr;
713 int data_pkt_count = 0;
714 while (const aom_codec_cx_pkt_t* pkt =
715 aom_codec_get_cx_data(&ctx_, &iter)) {
716 if (pkt->kind == AOM_CODEC_CX_FRAME_PKT && pkt->data.frame.sz > 0) {
717 if (data_pkt_count > 0) {
718 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encoder returned more than "
719 "one data packet for an input video frame.";
720 Release();
721 }
Danil Chapovalov222fdfd2020-06-11 17:44:24722 encoded_image.SetEncodedData(EncodedImageBuffer::Create(
723 /*data=*/static_cast<const uint8_t*>(pkt->data.frame.buf),
724 /*size=*/pkt->data.frame.sz));
Danil Chapovalovb471ac792020-05-15 12:21:03725
Danil Chapovalova48dd432020-06-08 17:47:08726 if ((pkt->data.frame.flags & AOM_EFLAG_FORCE_KF) != 0) {
philipel448231d2021-10-27 09:29:45727 layer_frame->Keyframe();
Danil Chapovalova48dd432020-06-08 17:47:08728 }
philipel448231d2021-10-27 09:29:45729
730 encoded_image._frameType = layer_frame->IsKeyframe()
Danil Chapovalovb471ac792020-05-15 12:21:03731 ? VideoFrameType::kVideoFrameKey
732 : VideoFrameType::kVideoFrameDelta;
Danil Chapovalov9c584832023-09-18 13:48:49733 encoded_image.SetRtpTimestamp(frame.timestamp());
Palak Agarwala09f21b2023-02-22 13:46:23734 encoded_image.SetCaptureTimeIdentifier(frame.capture_time_identifier());
Danil Chapovalovb471ac792020-05-15 12:21:03735 encoded_image.capture_time_ms_ = frame.render_time_ms();
736 encoded_image.rotation_ = frame.rotation();
737 encoded_image.content_type_ = VideoContentType::UNSPECIFIED;
738 // If encoded image width/height info are added to aom_codec_cx_pkt_t,
739 // use those values in lieu of the values in frame.
Erik SprĂĄngf86544482021-06-01 14:52:24740 if (svc_params_) {
philipel448231d2021-10-27 09:29:45741 int n = svc_params_->scaling_factor_num[layer_frame->SpatialId()];
742 int d = svc_params_->scaling_factor_den[layer_frame->SpatialId()];
Erik SprĂĄngf86544482021-06-01 14:52:24743 encoded_image._encodedWidth = cfg_.g_w * n / d;
744 encoded_image._encodedHeight = cfg_.g_h * n / d;
Zhaoliang Ma528e4892021-11-12 05:05:07745 encoded_image.SetSpatialIndex(layer_frame->SpatialId());
Florent Castelli90b74382022-04-25 15:28:00746 encoded_image.SetTemporalIndex(layer_frame->TemporalId());
Erik SprĂĄngf86544482021-06-01 14:52:24747 } else {
748 encoded_image._encodedWidth = cfg_.g_w;
749 encoded_image._encodedHeight = cfg_.g_h;
750 }
Danil Chapovalovb471ac792020-05-15 12:21:03751 encoded_image.timing_.flags = VideoSendTiming::kInvalid;
philipel8c354882022-05-02 08:27:29752
Danil Chapovalovb471ac792020-05-15 12:21:03753 int qp = -1;
philipel8c354882022-05-02 08:27:29754 SET_ENCODER_PARAM_OR_RETURN_ERROR(AOME_GET_LAST_QUANTIZER, &qp);
Danil Chapovalovb471ac792020-05-15 12:21:03755 encoded_image.qp_ = qp;
philipel8c354882022-05-02 08:27:29756
Danil Chapovalovb471ac792020-05-15 12:21:03757 encoded_image.SetColorSpace(frame.color_space());
758 ++data_pkt_count;
759 }
760 }
761
762 // Deliver encoded image data.
763 if (encoded_image.size() > 0) {
764 CodecSpecificInfo codec_specific_info;
765 codec_specific_info.codecType = kVideoCodecAV1;
Danil Chapovalov06bbeb32020-11-11 11:42:56766 codec_specific_info.end_of_picture = end_of_picture;
Evan Shrubsole9b235cd2022-12-06 10:09:10767 codec_specific_info.scalability_mode = scalability_mode_;
philipel448231d2021-10-27 09:29:45768 bool is_keyframe = layer_frame->IsKeyframe();
Danil Chapovalovb471ac792020-05-15 12:21:03769 codec_specific_info.generic_frame_info =
philipeld3eb8f12021-11-01 10:58:50770 svc_controller_->OnEncodeDone(*layer_frame);
Danil Chapovalovb471ac792020-05-15 12:21:03771 if (is_keyframe && codec_specific_info.generic_frame_info) {
772 codec_specific_info.template_structure =
773 svc_controller_->DependencyStructure();
Danil Chapovalov1e10a612020-07-02 13:27:03774 auto& resolutions = codec_specific_info.template_structure->resolutions;
775 if (SvcEnabled()) {
776 resolutions.resize(svc_params_->number_spatial_layers);
777 for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
778 int n = svc_params_->scaling_factor_num[sid];
779 int d = svc_params_->scaling_factor_den[sid];
780 resolutions[sid] =
781 RenderResolution(cfg_.g_w * n / d, cfg_.g_h * n / d);
782 }
783 } else {
784 resolutions = {RenderResolution(cfg_.g_w, cfg_.g_h)};
785 }
Danil Chapovalovb471ac792020-05-15 12:21:03786 }
787 encoded_image_callback_->OnEncodedImage(encoded_image,
Danil Chapovalov2549f172020-08-12 15:30:36788 &codec_specific_info);
Danil Chapovalovb471ac792020-05-15 12:21:03789 }
Danil Chapovalov976cc1a2020-03-20 09:36:13790 }
791
792 return WEBRTC_VIDEO_CODEC_OK;
793}
794
795void LibaomAv1Encoder::SetRates(const RateControlParameters& parameters) {
796 if (!inited_) {
797 RTC_LOG(LS_WARNING) << "SetRates() while encoder is not initialized";
798 return;
799 }
800 if (parameters.framerate_fps < kMinimumFrameRate) {
801 RTC_LOG(LS_WARNING) << "Unsupported framerate (must be >= "
802 << kMinimumFrameRate
803 << " ): " << parameters.framerate_fps;
804 return;
805 }
806 if (parameters.bitrate.get_sum_bps() == 0) {
807 RTC_LOG(LS_WARNING) << "Attempt to set target bit rate to zero";
808 return;
809 }
810
philipeld3eb8f12021-11-01 10:58:50811 // The bitrates caluclated internally in libaom when `AV1E_SET_SVC_PARAMS` is
812 // called depends on the currently configured `rc_target_bitrate`. If the
813 // total target bitrate is not updated first a division by zero could happen.
Danil Chapovalovbf181612020-06-25 13:47:57814 svc_controller_->OnRatesUpdated(parameters.bitrate);
philipelb3159512021-03-15 13:42:40815 cfg_.rc_target_bitrate = parameters.bitrate.get_sum_kbps();
philipel448231d2021-10-27 09:29:45816 aom_codec_err_t error_code = aom_codec_enc_config_set(&ctx_, &cfg_);
philipeld3eb8f12021-11-01 10:58:50817 if (error_code != AOM_CODEC_OK) {
818 RTC_LOG(LS_WARNING) << "Error configuring encoder, error code: "
819 << error_code;
820 }
Danil Chapovalov976cc1a2020-03-20 09:36:13821
Danil Chapovalov54544ec2020-06-25 19:44:31822 if (SvcEnabled()) {
823 for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
824 // libaom bitrate for spatial id S and temporal id T means bitrate
825 // of frames with spatial_id=S and temporal_id<=T
826 // while `parameters.bitrate` provdies bitrate of frames with
827 // spatial_id=S and temporal_id=T
828 int accumulated_bitrate_bps = 0;
829 for (int tid = 0; tid < svc_params_->number_temporal_layers; ++tid) {
830 int layer_index = sid * svc_params_->number_temporal_layers + tid;
831 accumulated_bitrate_bps += parameters.bitrate.GetBitrate(sid, tid);
Wan-Teh Chang8f29b422023-03-16 01:39:57832 // `svc_params_->layer_target_bitrate` expects bitrate in kbps.
Danil Chapovalov54544ec2020-06-25 19:44:31833 svc_params_->layer_target_bitrate[layer_index] =
834 accumulated_bitrate_bps / 1000;
835 }
836 }
philipel8c354882022-05-02 08:27:29837 SetEncoderControlParameters(AV1E_SET_SVC_PARAMS, &*svc_params_);
Danil Chapovalov54544ec2020-06-25 19:44:31838 }
839
philipel0763ccc2021-12-01 14:12:54840 rates_configured_ = true;
841
Danil Chapovalov976cc1a2020-03-20 09:36:13842 // Set frame rate to closest integer value.
843 encoder_settings_.maxFramerate =
844 static_cast<uint32_t>(parameters.framerate_fps + 0.5);
Danil Chapovalov976cc1a2020-03-20 09:36:13845}
846
847VideoEncoder::EncoderInfo LibaomAv1Encoder::GetEncoderInfo() const {
848 EncoderInfo info;
849 info.supports_native_handle = false;
850 info.implementation_name = "libaom";
851 info.has_trusted_rate_controller = true;
852 info.is_hardware_accelerated = false;
philipel31718d72023-09-13 12:44:23853 info.scaling_settings =
854 (inited_ && !encoder_settings_.AV1().automatic_resize_on)
855 ? VideoEncoder::ScalingSettings::kOff
856 : VideoEncoder::ScalingSettings(kMinQindex, kMaxQindex);
Ilya Nikolaevskiy1bcdafc2022-03-09 15:01:07857 info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420,
858 VideoFrameBuffer::Type::kNV12};
Danil Chapovalovb942d452021-01-12 13:45:07859 if (SvcEnabled()) {
860 for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
861 info.fps_allocation[sid].resize(svc_params_->number_temporal_layers);
862 for (int tid = 0; tid < svc_params_->number_temporal_layers; ++tid) {
Wan-Teh Chang1f391622023-02-09 11:41:48863 info.fps_allocation[sid][tid] = EncoderInfo::kMaxFramerateFraction /
864 svc_params_->framerate_factor[tid];
Danil Chapovalovb942d452021-01-12 13:45:07865 }
866 }
867 }
Michael Horowitzb27efd42023-02-28 15:59:50868 if (!encoder_info_override_.resolution_bitrate_limits().empty()) {
869 info.resolution_bitrate_limits =
870 encoder_info_override_.resolution_bitrate_limits();
871 }
Danil Chapovalov976cc1a2020-03-20 09:36:13872 return info;
873}
874
875} // namespace
876
Danil Chapovalovb4913a52024-03-11 12:17:45877absl::Nonnull<std::unique_ptr<VideoEncoder>> CreateLibaomAv1Encoder(
878 const Environment& env,
879 LibaomAv1EncoderSettings settings) {
880 if (settings.max_pixel_count_to_cpu_speed.empty()) {
881 return std::make_unique<LibaomAv1Encoder>(absl::nullopt,
882 env.field_trials());
883 } else {
884 return std::make_unique<LibaomAv1Encoder>(settings, env.field_trials());
885 }
886}
887
Danil Chapovalov976cc1a2020-03-20 09:36:13888std::unique_ptr<VideoEncoder> CreateLibaomAv1Encoder() {
Sergey Silkind6157042023-06-07 11:45:14889 return std::make_unique<LibaomAv1Encoder>(absl::nullopt,
890 FieldTrialBasedConfig());
philipel30ec7252022-05-04 09:20:04891}
892
893std::unique_ptr<VideoEncoder> CreateLibaomAv1Encoder(
894 const LibaomAv1EncoderAuxConfig& aux_config) {
Sergey Silkind6157042023-06-07 11:45:14895 return std::make_unique<LibaomAv1Encoder>(aux_config,
896 FieldTrialBasedConfig());
Danil Chapovalov976cc1a2020-03-20 09:36:13897}
898
Danil Chapovalov976cc1a2020-03-20 09:36:13899} // namespace webrtc