• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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