1 /*
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>
16 #include <utility>
17 #include <vector>
18
19 #include "absl/algorithm/container.h"
20 #include "absl/base/macros.h"
21 #include "absl/types/optional.h"
22 #include "api/scoped_refptr.h"
23 #include "api/video/encoded_image.h"
24 #include "api/video/i420_buffer.h"
25 #include "api/video/video_frame.h"
26 #include "api/video_codecs/video_codec.h"
27 #include "api/video_codecs/video_encoder.h"
28 #include "modules/video_coding/codecs/av1/scalable_video_controller.h"
29 #include "modules/video_coding/codecs/av1/scalable_video_controller_no_layering.h"
30 #include "modules/video_coding/include/video_codec_interface.h"
31 #include "modules/video_coding/include/video_error_codes.h"
32 #include "rtc_base/checks.h"
33 #include "rtc_base/logging.h"
34 #include "third_party/libaom/source/libaom/aom/aom_codec.h"
35 #include "third_party/libaom/source/libaom/aom/aom_encoder.h"
36 #include "third_party/libaom/source/libaom/aom/aomcx.h"
37
38 namespace webrtc {
39 namespace {
40
41 // Encoder configuration parameters
42 constexpr int kQpMin = 10;
43 constexpr int kUsageProfile = 1; // 0 = good quality; 1 = real-time.
44 constexpr int kMinQindex = 58; // Min qindex threshold for QP scaling.
45 constexpr int kMaxQindex = 180; // Max qindex threshold for QP scaling.
46 constexpr int kBitDepth = 8;
47 constexpr int kLagInFrames = 0; // No look ahead.
48 constexpr int kRtpTicksPerSecond = 90000;
49 constexpr float kMinimumFrameRate = 1.0;
50
51 // Only positive speeds, range for real-time coding currently is: 6 - 8.
52 // Lower means slower/better quality, higher means fastest/lower quality.
GetCpuSpeed(int width,int height,int number_of_cores)53 int GetCpuSpeed(int width, int height, int number_of_cores) {
54 // For smaller resolutions, use lower speed setting (get some coding gain at
55 // the cost of increased encoding complexity).
56 if (number_of_cores > 2 && width * height <= 320 * 180)
57 return 6;
58 else if (width * height >= 1280 * 720)
59 return 8;
60 else
61 return 7;
62 }
63
64 class LibaomAv1Encoder final : public VideoEncoder {
65 public:
66 explicit LibaomAv1Encoder(
67 std::unique_ptr<ScalableVideoController> svc_controller);
68 ~LibaomAv1Encoder();
69
70 int InitEncode(const VideoCodec* codec_settings,
71 const Settings& settings) override;
72
73 int32_t RegisterEncodeCompleteCallback(
74 EncodedImageCallback* encoded_image_callback) override;
75
76 int32_t Release() override;
77
78 int32_t Encode(const VideoFrame& frame,
79 const std::vector<VideoFrameType>* frame_types) override;
80
81 void SetRates(const RateControlParameters& parameters) override;
82
83 EncoderInfo GetEncoderInfo() const override;
84
85 private:
SvcEnabled() const86 bool SvcEnabled() const { return svc_params_.has_value(); }
87 // Fills svc_params_ memeber value. Returns false on error.
88 bool SetSvcParams(ScalableVideoController::StreamLayersConfig svc_config);
89 // Configures the encoder with layer for the next frame.
90 void SetSvcLayerId(
91 const ScalableVideoController::LayerFrameConfig& layer_frame);
92 // Configures the encoder which buffers next frame updates and can reference.
93 void SetSvcRefFrameConfig(
94 const ScalableVideoController::LayerFrameConfig& layer_frame);
95
96 const std::unique_ptr<ScalableVideoController> svc_controller_;
97 bool inited_;
98 absl::optional<aom_svc_params_t> svc_params_;
99 VideoCodec encoder_settings_;
100 aom_image_t* frame_for_encode_;
101 aom_codec_ctx_t ctx_;
102 aom_codec_enc_cfg_t cfg_;
103 EncodedImageCallback* encoded_image_callback_;
104 };
105
VerifyCodecSettings(const VideoCodec & codec_settings)106 int32_t VerifyCodecSettings(const VideoCodec& codec_settings) {
107 if (codec_settings.width < 1) {
108 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
109 }
110 if (codec_settings.height < 1) {
111 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
112 }
113 // maxBitrate == 0 represents an unspecified maxBitRate.
114 if (codec_settings.maxBitrate > 0 &&
115 codec_settings.minBitrate > codec_settings.maxBitrate) {
116 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
117 }
118 if (codec_settings.maxBitrate > 0 &&
119 codec_settings.startBitrate > codec_settings.maxBitrate) {
120 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
121 }
122 if (codec_settings.startBitrate < codec_settings.minBitrate) {
123 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
124 }
125 if (codec_settings.maxFramerate < 1) {
126 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
127 }
128 return WEBRTC_VIDEO_CODEC_OK;
129 }
130
LibaomAv1Encoder(std::unique_ptr<ScalableVideoController> svc_controller)131 LibaomAv1Encoder::LibaomAv1Encoder(
132 std::unique_ptr<ScalableVideoController> svc_controller)
133 : svc_controller_(std::move(svc_controller)),
134 inited_(false),
135 frame_for_encode_(nullptr),
136 encoded_image_callback_(nullptr) {
137 RTC_DCHECK(svc_controller_);
138 }
139
~LibaomAv1Encoder()140 LibaomAv1Encoder::~LibaomAv1Encoder() {
141 Release();
142 }
143
InitEncode(const VideoCodec * codec_settings,const Settings & settings)144 int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings,
145 const Settings& settings) {
146 if (codec_settings == nullptr) {
147 RTC_LOG(LS_WARNING) << "No codec settings provided to "
148 "LibaomAv1Encoder.";
149 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
150 }
151 if (settings.number_of_cores < 1) {
152 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
153 }
154 if (inited_) {
155 RTC_LOG(LS_WARNING) << "Initing LibaomAv1Encoder without first releasing.";
156 Release();
157 }
158 encoder_settings_ = *codec_settings;
159
160 // Sanity checks for encoder configuration.
161 const int32_t result = VerifyCodecSettings(encoder_settings_);
162 if (result < 0) {
163 RTC_LOG(LS_WARNING) << "Incorrect codec settings provided to "
164 "LibaomAv1Encoder.";
165 return result;
166 }
167
168 if (!SetSvcParams(svc_controller_->StreamConfig())) {
169 return WEBRTC_VIDEO_CODEC_ERROR;
170 }
171
172 // Initialize encoder configuration structure with default values
173 aom_codec_err_t ret =
174 aom_codec_enc_config_default(aom_codec_av1_cx(), &cfg_, 0);
175 if (ret != AOM_CODEC_OK) {
176 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
177 << " on aom_codec_enc_config_default.";
178 return WEBRTC_VIDEO_CODEC_ERROR;
179 }
180
181 // Overwrite default config with input encoder settings & RTC-relevant values.
182 cfg_.g_w = encoder_settings_.width;
183 cfg_.g_h = encoder_settings_.height;
184 cfg_.g_threads = settings.number_of_cores;
185 cfg_.g_timebase.num = 1;
186 cfg_.g_timebase.den = kRtpTicksPerSecond;
187 cfg_.rc_target_bitrate = encoder_settings_.maxBitrate; // kilobits/sec.
188 cfg_.g_input_bit_depth = kBitDepth;
189 cfg_.kf_mode = AOM_KF_DISABLED;
190 cfg_.rc_min_quantizer = kQpMin;
191 cfg_.rc_max_quantizer = encoder_settings_.qpMax;
192 cfg_.g_usage = kUsageProfile;
193 cfg_.g_error_resilient = 0;
194 // Low-latency settings.
195 cfg_.rc_end_usage = AOM_CBR; // Constant Bit Rate (CBR) mode
196 cfg_.g_pass = AOM_RC_ONE_PASS; // One-pass rate control
197 cfg_.g_lag_in_frames = kLagInFrames; // No look ahead when lag equals 0.
198
199 // Creating a wrapper to the image - setting image data to nullptr. Actual
200 // pointer will be set in encode. Setting align to 1, as it is meaningless
201 // (actual memory is not allocated).
202 frame_for_encode_ =
203 aom_img_alloc(nullptr, AOM_IMG_FMT_I420, cfg_.g_w, cfg_.g_h, 1);
204
205 // Flag options: AOM_CODEC_USE_PSNR and AOM_CODEC_USE_HIGHBITDEPTH
206 aom_codec_flags_t flags = 0;
207
208 // Initialize an encoder instance.
209 ret = aom_codec_enc_init(&ctx_, aom_codec_av1_cx(), &cfg_, flags);
210 if (ret != AOM_CODEC_OK) {
211 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
212 << " on aom_codec_enc_init.";
213 return WEBRTC_VIDEO_CODEC_ERROR;
214 }
215 inited_ = true;
216
217 // Set control parameters
218 ret = aom_codec_control(
219 &ctx_, AOME_SET_CPUUSED,
220 GetCpuSpeed(cfg_.g_w, cfg_.g_h, settings.number_of_cores));
221 if (ret != AOM_CODEC_OK) {
222 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
223 << " on control AV1E_SET_CPUUSED.";
224 return WEBRTC_VIDEO_CODEC_ERROR;
225 }
226 ret = aom_codec_control(&ctx_, AV1E_SET_ENABLE_TPL_MODEL, 0);
227 if (ret != AOM_CODEC_OK) {
228 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
229 << " on control AV1E_SET_ENABLE_TPL_MODEL.";
230 return WEBRTC_VIDEO_CODEC_ERROR;
231 }
232 ret = aom_codec_control(&ctx_, AV1E_SET_DELTAQ_MODE, 0);
233 if (ret != AOM_CODEC_OK) {
234 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
235 << " on control AV1E_SET_DELTAQ_MODE.";
236 return WEBRTC_VIDEO_CODEC_ERROR;
237 }
238 ret = aom_codec_control(&ctx_, AV1E_SET_ENABLE_ORDER_HINT, 0);
239 if (ret != AOM_CODEC_OK) {
240 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
241 << " on control AV1E_SET_ENABLE_ORDER_HINT.";
242 return WEBRTC_VIDEO_CODEC_ERROR;
243 }
244 ret = aom_codec_control(&ctx_, AV1E_SET_AQ_MODE, 3);
245 if (ret != AOM_CODEC_OK) {
246 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
247 << " on control AV1E_SET_AQ_MODE.";
248 return WEBRTC_VIDEO_CODEC_ERROR;
249 }
250 if (SvcEnabled()) {
251 ret = aom_codec_control(&ctx_, AV1E_SET_SVC_PARAMS, &*svc_params_);
252 if (ret != AOM_CODEC_OK) {
253 RTC_LOG(LS_WARNING) << "LibaomAV1Encoder::EncodeInit returned " << ret
254 << " on control AV1E_SET_SVC_PARAMS.";
255 return false;
256 }
257 }
258
259 ret = aom_codec_control(&ctx_, AOME_SET_MAX_INTRA_BITRATE_PCT, 300);
260 if (ret != AOM_CODEC_OK) {
261 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
262 << " on control AV1E_SET_MAX_INTRA_BITRATE_PCT.";
263 return WEBRTC_VIDEO_CODEC_ERROR;
264 }
265 ret = aom_codec_control(&ctx_, AV1E_SET_COEFF_COST_UPD_FREQ, 2);
266 if (ret != AOM_CODEC_OK) {
267 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
268 << " on control AV1E_SET_COEFF_COST_UPD_FREQ.";
269 return WEBRTC_VIDEO_CODEC_ERROR;
270 }
271 ret = aom_codec_control(&ctx_, AV1E_SET_MODE_COST_UPD_FREQ, 2);
272 if (ret != AOM_CODEC_OK) {
273 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
274 << " on control AV1E_SET_MODE_COST_UPD_FREQ.";
275 return WEBRTC_VIDEO_CODEC_ERROR;
276 }
277 ret = aom_codec_control(&ctx_, AV1E_SET_MV_COST_UPD_FREQ, 3);
278 if (ret != AOM_CODEC_OK) {
279 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
280 << " on control AV1E_SET_MV_COST_UPD_FREQ.";
281 return WEBRTC_VIDEO_CODEC_ERROR;
282 }
283
284 return WEBRTC_VIDEO_CODEC_OK;
285 }
286
SetSvcParams(ScalableVideoController::StreamLayersConfig svc_config)287 bool LibaomAv1Encoder::SetSvcParams(
288 ScalableVideoController::StreamLayersConfig svc_config) {
289 bool svc_enabled =
290 svc_config.num_spatial_layers > 1 || svc_config.num_temporal_layers > 1;
291 if (!svc_enabled) {
292 svc_params_ = absl::nullopt;
293 return true;
294 }
295 if (svc_config.num_spatial_layers < 1 || svc_config.num_spatial_layers > 4) {
296 RTC_LOG(LS_WARNING) << "Av1 supports up to 4 spatial layers. "
297 << svc_config.num_spatial_layers << " configured.";
298 return false;
299 }
300 if (svc_config.num_temporal_layers < 1 ||
301 svc_config.num_temporal_layers > 8) {
302 RTC_LOG(LS_WARNING) << "Av1 supports up to 8 temporal layers. "
303 << svc_config.num_temporal_layers << " configured.";
304 return false;
305 }
306 aom_svc_params_t& svc_params = svc_params_.emplace();
307 svc_params.number_spatial_layers = svc_config.num_spatial_layers;
308 svc_params.number_temporal_layers = svc_config.num_temporal_layers;
309
310 int num_layers =
311 svc_config.num_spatial_layers * svc_config.num_temporal_layers;
312 for (int i = 0; i < num_layers; ++i) {
313 svc_params.min_quantizers[i] = kQpMin;
314 svc_params.max_quantizers[i] = encoder_settings_.qpMax;
315 }
316
317 // Assume each temporal layer doubles framerate.
318 for (int tid = 0; tid < svc_config.num_temporal_layers; ++tid) {
319 svc_params.framerate_factor[tid] =
320 1 << (svc_config.num_temporal_layers - tid - 1);
321 }
322
323 for (int sid = 0; sid < svc_config.num_spatial_layers; ++sid) {
324 svc_params.scaling_factor_num[sid] = svc_config.scaling_factor_num[sid];
325 svc_params.scaling_factor_den[sid] = svc_config.scaling_factor_den[sid];
326 }
327
328 return true;
329 }
330
SetSvcLayerId(const ScalableVideoController::LayerFrameConfig & layer_frame)331 void LibaomAv1Encoder::SetSvcLayerId(
332 const ScalableVideoController::LayerFrameConfig& layer_frame) {
333 aom_svc_layer_id_t layer_id = {};
334 layer_id.spatial_layer_id = layer_frame.SpatialId();
335 layer_id.temporal_layer_id = layer_frame.TemporalId();
336 aom_codec_err_t ret =
337 aom_codec_control(&ctx_, AV1E_SET_SVC_LAYER_ID, &layer_id);
338 if (ret != AOM_CODEC_OK) {
339 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << ret
340 << " on control AV1E_SET_SVC_LAYER_ID.";
341 }
342 }
343
SetSvcRefFrameConfig(const ScalableVideoController::LayerFrameConfig & layer_frame)344 void LibaomAv1Encoder::SetSvcRefFrameConfig(
345 const ScalableVideoController::LayerFrameConfig& layer_frame) {
346 // Buffer name to use for each layer_frame.buffers position. In particular
347 // when there are 2 buffers are referenced, prefer name them last and golden,
348 // because av1 bitstream format has dedicated fields for these two names.
349 // See last_frame_idx and golden_frame_idx in the av1 spec
350 // https://aomediacodec.github.io/av1-spec/av1-spec.pdf
351 static constexpr int kPreferedSlotName[] = {0, // Last
352 3, // Golden
353 1, 2, 4, 5, 6};
354 static constexpr int kAv1NumBuffers = 8;
355
356 aom_svc_ref_frame_config_t ref_frame_config = {};
357 RTC_CHECK_LE(layer_frame.Buffers().size(), ABSL_ARRAYSIZE(kPreferedSlotName));
358 for (size_t i = 0; i < layer_frame.Buffers().size(); ++i) {
359 const CodecBufferUsage& buffer = layer_frame.Buffers()[i];
360 int slot_name = kPreferedSlotName[i];
361 RTC_CHECK_GE(buffer.id, 0);
362 RTC_CHECK_LT(buffer.id, kAv1NumBuffers);
363 ref_frame_config.ref_idx[slot_name] = buffer.id;
364 if (buffer.referenced) {
365 ref_frame_config.reference[slot_name] = 1;
366 }
367 if (buffer.updated) {
368 ref_frame_config.refresh[buffer.id] = 1;
369 }
370 }
371 aom_codec_err_t ret = aom_codec_control(&ctx_, AV1E_SET_SVC_REF_FRAME_CONFIG,
372 &ref_frame_config);
373 if (ret != AOM_CODEC_OK) {
374 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << ret
375 << " on control AV1_SET_SVC_REF_FRAME_CONFIG.";
376 }
377 }
378
RegisterEncodeCompleteCallback(EncodedImageCallback * encoded_image_callback)379 int32_t LibaomAv1Encoder::RegisterEncodeCompleteCallback(
380 EncodedImageCallback* encoded_image_callback) {
381 encoded_image_callback_ = encoded_image_callback;
382 return WEBRTC_VIDEO_CODEC_OK;
383 }
384
Release()385 int32_t LibaomAv1Encoder::Release() {
386 if (frame_for_encode_ != nullptr) {
387 aom_img_free(frame_for_encode_);
388 frame_for_encode_ = nullptr;
389 }
390 if (inited_) {
391 if (aom_codec_destroy(&ctx_)) {
392 return WEBRTC_VIDEO_CODEC_MEMORY;
393 }
394 inited_ = false;
395 }
396 return WEBRTC_VIDEO_CODEC_OK;
397 }
398
Encode(const VideoFrame & frame,const std::vector<VideoFrameType> * frame_types)399 int32_t LibaomAv1Encoder::Encode(
400 const VideoFrame& frame,
401 const std::vector<VideoFrameType>* frame_types) {
402 if (!inited_ || encoded_image_callback_ == nullptr) {
403 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
404 }
405
406 bool keyframe_required =
407 frame_types != nullptr &&
408 absl::c_linear_search(*frame_types, VideoFrameType::kVideoFrameKey);
409
410 std::vector<ScalableVideoController::LayerFrameConfig> layer_frames =
411 svc_controller_->NextFrameConfig(keyframe_required);
412
413 if (layer_frames.empty()) {
414 RTC_LOG(LS_ERROR) << "SVCController returned no configuration for a frame.";
415 return WEBRTC_VIDEO_CODEC_ERROR;
416 }
417
418 // Convert input frame to I420, if needed.
419 VideoFrame prepped_input_frame = frame;
420 if (prepped_input_frame.video_frame_buffer()->type() !=
421 VideoFrameBuffer::Type::kI420) {
422 rtc::scoped_refptr<I420BufferInterface> converted_buffer(
423 prepped_input_frame.video_frame_buffer()->ToI420());
424 prepped_input_frame = VideoFrame(converted_buffer, frame.timestamp(),
425 frame.render_time_ms(), frame.rotation());
426 }
427
428 // Set frame_for_encode_ data pointers and strides.
429 auto i420_buffer = prepped_input_frame.video_frame_buffer()->GetI420();
430 frame_for_encode_->planes[AOM_PLANE_Y] =
431 const_cast<unsigned char*>(i420_buffer->DataY());
432 frame_for_encode_->planes[AOM_PLANE_U] =
433 const_cast<unsigned char*>(i420_buffer->DataU());
434 frame_for_encode_->planes[AOM_PLANE_V] =
435 const_cast<unsigned char*>(i420_buffer->DataV());
436 frame_for_encode_->stride[AOM_PLANE_Y] = i420_buffer->StrideY();
437 frame_for_encode_->stride[AOM_PLANE_U] = i420_buffer->StrideU();
438 frame_for_encode_->stride[AOM_PLANE_V] = i420_buffer->StrideV();
439
440 const uint32_t duration =
441 kRtpTicksPerSecond / static_cast<float>(encoder_settings_.maxFramerate);
442
443 for (ScalableVideoController::LayerFrameConfig& layer_frame : layer_frames) {
444 aom_enc_frame_flags_t flags =
445 layer_frame.IsKeyframe() ? AOM_EFLAG_FORCE_KF : 0;
446
447 if (SvcEnabled()) {
448 SetSvcLayerId(layer_frame);
449 SetSvcRefFrameConfig(layer_frame);
450 }
451
452 // Encode a frame.
453 aom_codec_err_t ret = aom_codec_encode(&ctx_, frame_for_encode_,
454 frame.timestamp(), duration, flags);
455 if (ret != AOM_CODEC_OK) {
456 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << ret
457 << " on aom_codec_encode.";
458 return WEBRTC_VIDEO_CODEC_ERROR;
459 }
460
461 // Get encoded image data.
462 EncodedImage encoded_image;
463 encoded_image._completeFrame = true;
464 aom_codec_iter_t iter = nullptr;
465 int data_pkt_count = 0;
466 while (const aom_codec_cx_pkt_t* pkt =
467 aom_codec_get_cx_data(&ctx_, &iter)) {
468 if (pkt->kind == AOM_CODEC_CX_FRAME_PKT && pkt->data.frame.sz > 0) {
469 if (data_pkt_count > 0) {
470 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encoder returned more than "
471 "one data packet for an input video frame.";
472 Release();
473 }
474 encoded_image.SetEncodedData(EncodedImageBuffer::Create(
475 /*data=*/static_cast<const uint8_t*>(pkt->data.frame.buf),
476 /*size=*/pkt->data.frame.sz));
477
478 if ((pkt->data.frame.flags & AOM_EFLAG_FORCE_KF) != 0) {
479 layer_frame.Keyframe();
480 }
481 encoded_image._frameType = layer_frame.IsKeyframe()
482 ? VideoFrameType::kVideoFrameKey
483 : VideoFrameType::kVideoFrameDelta;
484 encoded_image.SetTimestamp(frame.timestamp());
485 encoded_image.capture_time_ms_ = frame.render_time_ms();
486 encoded_image.rotation_ = frame.rotation();
487 encoded_image.content_type_ = VideoContentType::UNSPECIFIED;
488 // If encoded image width/height info are added to aom_codec_cx_pkt_t,
489 // use those values in lieu of the values in frame.
490 encoded_image._encodedHeight = frame.height();
491 encoded_image._encodedWidth = frame.width();
492 encoded_image.timing_.flags = VideoSendTiming::kInvalid;
493 int qp = -1;
494 ret = aom_codec_control(&ctx_, AOME_GET_LAST_QUANTIZER, &qp);
495 if (ret != AOM_CODEC_OK) {
496 RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << ret
497 << " on control AOME_GET_LAST_QUANTIZER.";
498 return WEBRTC_VIDEO_CODEC_ERROR;
499 }
500 encoded_image.qp_ = qp;
501 encoded_image.SetColorSpace(frame.color_space());
502 ++data_pkt_count;
503 }
504 }
505
506 // Deliver encoded image data.
507 if (encoded_image.size() > 0) {
508 CodecSpecificInfo codec_specific_info;
509 codec_specific_info.codecType = kVideoCodecAV1;
510 bool is_keyframe = layer_frame.IsKeyframe();
511 codec_specific_info.generic_frame_info =
512 svc_controller_->OnEncodeDone(std::move(layer_frame));
513 if (is_keyframe && codec_specific_info.generic_frame_info) {
514 codec_specific_info.template_structure =
515 svc_controller_->DependencyStructure();
516 auto& resolutions = codec_specific_info.template_structure->resolutions;
517 if (SvcEnabled()) {
518 resolutions.resize(svc_params_->number_spatial_layers);
519 for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
520 int n = svc_params_->scaling_factor_num[sid];
521 int d = svc_params_->scaling_factor_den[sid];
522 resolutions[sid] =
523 RenderResolution(cfg_.g_w * n / d, cfg_.g_h * n / d);
524 }
525 } else {
526 resolutions = {RenderResolution(cfg_.g_w, cfg_.g_h)};
527 }
528 }
529 encoded_image_callback_->OnEncodedImage(encoded_image,
530 &codec_specific_info, nullptr);
531 }
532 }
533
534 return WEBRTC_VIDEO_CODEC_OK;
535 }
536
SetRates(const RateControlParameters & parameters)537 void LibaomAv1Encoder::SetRates(const RateControlParameters& parameters) {
538 if (!inited_) {
539 RTC_LOG(LS_WARNING) << "SetRates() while encoder is not initialized";
540 return;
541 }
542 if (parameters.framerate_fps < kMinimumFrameRate) {
543 RTC_LOG(LS_WARNING) << "Unsupported framerate (must be >= "
544 << kMinimumFrameRate
545 << " ): " << parameters.framerate_fps;
546 return;
547 }
548 if (parameters.bitrate.get_sum_bps() == 0) {
549 RTC_LOG(LS_WARNING) << "Attempt to set target bit rate to zero";
550 return;
551 }
552
553 // Check input target bit rate value.
554 uint32_t rc_target_bitrate_kbps = parameters.bitrate.get_sum_kbps();
555 if (encoder_settings_.maxBitrate > 0)
556 RTC_DCHECK_LE(rc_target_bitrate_kbps, encoder_settings_.maxBitrate);
557 RTC_DCHECK_GE(rc_target_bitrate_kbps, encoder_settings_.minBitrate);
558
559 svc_controller_->OnRatesUpdated(parameters.bitrate);
560 // Set target bit rate.
561 cfg_.rc_target_bitrate = rc_target_bitrate_kbps;
562
563 if (SvcEnabled()) {
564 for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
565 // libaom bitrate for spatial id S and temporal id T means bitrate
566 // of frames with spatial_id=S and temporal_id<=T
567 // while `parameters.bitrate` provdies bitrate of frames with
568 // spatial_id=S and temporal_id=T
569 int accumulated_bitrate_bps = 0;
570 for (int tid = 0; tid < svc_params_->number_temporal_layers; ++tid) {
571 int layer_index = sid * svc_params_->number_temporal_layers + tid;
572 accumulated_bitrate_bps += parameters.bitrate.GetBitrate(sid, tid);
573 // `svc_params.layer_target_bitrate` expects bitrate in kbps.
574 svc_params_->layer_target_bitrate[layer_index] =
575 accumulated_bitrate_bps / 1000;
576 }
577 }
578 aom_codec_control(&ctx_, AV1E_SET_SVC_PARAMS, &*svc_params_);
579 }
580
581 // Set frame rate to closest integer value.
582 encoder_settings_.maxFramerate =
583 static_cast<uint32_t>(parameters.framerate_fps + 0.5);
584
585 // Update encoder context.
586 aom_codec_err_t error_code = aom_codec_enc_config_set(&ctx_, &cfg_);
587 if (error_code != AOM_CODEC_OK) {
588 RTC_LOG(LS_WARNING) << "Error configuring encoder, error code: "
589 << error_code;
590 }
591 }
592
GetEncoderInfo() const593 VideoEncoder::EncoderInfo LibaomAv1Encoder::GetEncoderInfo() const {
594 EncoderInfo info;
595 info.supports_native_handle = false;
596 info.implementation_name = "libaom";
597 info.has_trusted_rate_controller = true;
598 info.is_hardware_accelerated = false;
599 info.scaling_settings = VideoEncoder::ScalingSettings(kMinQindex, kMaxQindex);
600 return info;
601 }
602
603 } // namespace
604
605 const bool kIsLibaomAv1EncoderSupported = true;
606
CreateLibaomAv1Encoder()607 std::unique_ptr<VideoEncoder> CreateLibaomAv1Encoder() {
608 return std::make_unique<LibaomAv1Encoder>(
609 std::make_unique<ScalableVideoControllerNoLayering>());
610 }
611
CreateLibaomAv1Encoder(std::unique_ptr<ScalableVideoController> svc_controller)612 std::unique_ptr<VideoEncoder> CreateLibaomAv1Encoder(
613 std::unique_ptr<ScalableVideoController> svc_controller) {
614 return std::make_unique<LibaomAv1Encoder>(std::move(svc_controller));
615 }
616
617 } // namespace webrtc
618