mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00
Configure libaom encoder with scalability parameters
Bug: webrtc:11404 Change-Id: I9535d9dec2e0e0d85bf3435f921d6e78034c7bf8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/175653 Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Philip Eliasson <philipel@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31373}
This commit is contained in:
parent
c23d749c42
commit
a4d70a802c
1 changed files with 121 additions and 13 deletions
|
@ -17,6 +17,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/video/encoded_image.h"
|
||||
#include "api/video/i420_buffer.h"
|
||||
|
@ -82,9 +83,18 @@ class LibaomAv1Encoder final : public VideoEncoder {
|
|||
EncoderInfo GetEncoderInfo() const override;
|
||||
|
||||
private:
|
||||
// Configures the encoder with scalability for the next coded video sequence.
|
||||
bool SetSvcParams(ScalableVideoController::StreamLayersConfig svc_config);
|
||||
// Configures the encoder with layer for the next frame.
|
||||
void SetSvcLayerId(
|
||||
const ScalableVideoController::LayerFrameConfig& layer_frame);
|
||||
// Configures the encoder which buffers next frame updates and can reference.
|
||||
void SetSvcRefFrameConfig(
|
||||
const ScalableVideoController::LayerFrameConfig& layer_frame);
|
||||
|
||||
const std::unique_ptr<ScalableVideoController> svc_controller_;
|
||||
bool inited_;
|
||||
bool keyframe_required_;
|
||||
bool svc_enabled_;
|
||||
VideoCodec encoder_settings_;
|
||||
aom_image_t* frame_for_encode_;
|
||||
aom_codec_ctx_t ctx_;
|
||||
|
@ -121,7 +131,7 @@ LibaomAv1Encoder::LibaomAv1Encoder(
|
|||
std::unique_ptr<ScalableVideoController> svc_controller)
|
||||
: svc_controller_(std::move(svc_controller)),
|
||||
inited_(false),
|
||||
keyframe_required_(true),
|
||||
svc_enabled_(false),
|
||||
frame_for_encode_(nullptr),
|
||||
encoded_image_callback_(nullptr) {
|
||||
RTC_DCHECK(svc_controller_);
|
||||
|
@ -226,15 +236,113 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings,
|
|||
<< " on control AV1E_SET_AQ_MODE.";
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
ScalableVideoController::StreamLayersConfig svc_config =
|
||||
svc_controller_->StreamConfig();
|
||||
// TODO(danilchap): Configure SVC.
|
||||
(void)svc_config;
|
||||
if (!SetSvcParams(svc_controller_->StreamConfig())) {
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
bool LibaomAv1Encoder::SetSvcParams(
|
||||
ScalableVideoController::StreamLayersConfig svc_config) {
|
||||
svc_enabled_ =
|
||||
svc_config.num_spatial_layers > 1 || svc_config.num_temporal_layers > 1;
|
||||
if (!svc_enabled_) {
|
||||
return true;
|
||||
}
|
||||
aom_svc_params_t svc_params = {};
|
||||
if (svc_config.num_spatial_layers < 1 || svc_config.num_spatial_layers > 4) {
|
||||
RTC_LOG(LS_WARNING) << "Av1 supports up to 4 spatial layers. "
|
||||
<< svc_config.num_spatial_layers << " configured.";
|
||||
return false;
|
||||
}
|
||||
if (svc_config.num_temporal_layers < 1 ||
|
||||
svc_config.num_temporal_layers > 8) {
|
||||
RTC_LOG(LS_WARNING) << "Av1 supports up to 8 temporal layers. "
|
||||
<< svc_config.num_temporal_layers << " configured.";
|
||||
return false;
|
||||
}
|
||||
svc_params.number_spatial_layers = svc_config.num_spatial_layers;
|
||||
svc_params.number_temporal_layers = svc_config.num_temporal_layers;
|
||||
|
||||
int num_layers =
|
||||
svc_config.num_spatial_layers * svc_config.num_temporal_layers;
|
||||
for (int i = 0; i < num_layers; ++i) {
|
||||
svc_params.min_quantizers[i] = kQpMin;
|
||||
svc_params.max_quantizers[i] = kQpMax;
|
||||
}
|
||||
|
||||
// Assume each temporal layer doubles framerate.
|
||||
for (int tid = 0; tid < svc_config.num_temporal_layers; ++tid) {
|
||||
svc_params.framerate_factor[tid] =
|
||||
1 << (svc_config.num_temporal_layers - tid - 1);
|
||||
}
|
||||
|
||||
// TODO(danilchap): Add support for custom resolution factor.
|
||||
for (int sid = 0; sid < svc_config.num_spatial_layers; ++sid) {
|
||||
svc_params.scaling_factor_num[sid] = 1;
|
||||
svc_params.scaling_factor_den[sid] =
|
||||
1 << (svc_config.num_spatial_layers - sid - 1);
|
||||
}
|
||||
|
||||
aom_codec_err_t ret =
|
||||
aom_codec_control(&ctx_, AV1E_SET_SVC_PARAMS, &svc_params);
|
||||
if (ret != AOM_CODEC_OK) {
|
||||
RTC_LOG(LS_WARNING) << "LibaomAV1Encoder::EncodeInit returned " << ret
|
||||
<< " on control AV1E_SET_SVC_PARAMS.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LibaomAv1Encoder::SetSvcLayerId(
|
||||
const ScalableVideoController::LayerFrameConfig& layer_frame) {
|
||||
aom_svc_layer_id_t layer_id = {};
|
||||
layer_id.spatial_layer_id = layer_frame.spatial_id;
|
||||
layer_id.temporal_layer_id = layer_frame.temporal_id;
|
||||
aom_codec_err_t ret =
|
||||
aom_codec_control(&ctx_, AV1E_SET_SVC_LAYER_ID, &layer_id);
|
||||
if (ret != AOM_CODEC_OK) {
|
||||
RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << ret
|
||||
<< " on control AV1E_SET_SVC_LAYER_ID.";
|
||||
}
|
||||
}
|
||||
|
||||
void LibaomAv1Encoder::SetSvcRefFrameConfig(
|
||||
const ScalableVideoController::LayerFrameConfig& layer_frame) {
|
||||
// Buffer name to use for each layer_frame.buffers position. In particular
|
||||
// when there are 2 buffers are referenced, prefer name them last and golden,
|
||||
// because av1 bitstream format has dedicated fields for these two names.
|
||||
// See last_frame_idx and golden_frame_idx in the av1 spec
|
||||
// https://aomediacodec.github.io/av1-spec/av1-spec.pdf
|
||||
static constexpr int kPreferedSlotName[] = {0, // Last
|
||||
3, // Golden
|
||||
1, 2, 4, 5, 6};
|
||||
static constexpr int kAv1NumBuffers = 8;
|
||||
|
||||
aom_svc_ref_frame_config_t ref_frame_config = {};
|
||||
RTC_CHECK_LE(layer_frame.buffers.size(), ABSL_ARRAYSIZE(kPreferedSlotName));
|
||||
for (size_t i = 0; i < layer_frame.buffers.size(); ++i) {
|
||||
const CodecBufferUsage& buffer = layer_frame.buffers[i];
|
||||
int slot_name = kPreferedSlotName[i];
|
||||
RTC_CHECK_GE(buffer.id, 0);
|
||||
RTC_CHECK_LT(buffer.id, kAv1NumBuffers);
|
||||
ref_frame_config.ref_idx[slot_name] = buffer.id;
|
||||
if (buffer.referenced) {
|
||||
ref_frame_config.reference[slot_name] = 1;
|
||||
}
|
||||
if (buffer.updated) {
|
||||
ref_frame_config.refresh[buffer.id] = 1;
|
||||
}
|
||||
}
|
||||
aom_codec_err_t ret = aom_codec_control(&ctx_, AV1E_SET_SVC_REF_FRAME_CONFIG,
|
||||
&ref_frame_config);
|
||||
if (ret != AOM_CODEC_OK) {
|
||||
RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << ret
|
||||
<< " on control AV1_SET_SVC_REF_FRAME_CONFIG.";
|
||||
}
|
||||
}
|
||||
|
||||
int32_t LibaomAv1Encoder::RegisterEncodeCompleteCallback(
|
||||
EncodedImageCallback* encoded_image_callback) {
|
||||
encoded_image_callback_ = encoded_image_callback;
|
||||
|
@ -262,12 +370,12 @@ int32_t LibaomAv1Encoder::Encode(
|
|||
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
||||
}
|
||||
|
||||
keyframe_required_ =
|
||||
bool keyframe_required =
|
||||
frame_types != nullptr &&
|
||||
absl::c_linear_search(*frame_types, VideoFrameType::kVideoFrameKey);
|
||||
|
||||
std::vector<ScalableVideoController::LayerFrameConfig> layer_frames =
|
||||
svc_controller_->NextFrameConfig(keyframe_required_);
|
||||
svc_controller_->NextFrameConfig(keyframe_required);
|
||||
|
||||
if (layer_frames.empty()) {
|
||||
RTC_LOG(LS_ERROR) << "SVCController returned no configuration for a frame.";
|
||||
|
@ -299,14 +407,14 @@ int32_t LibaomAv1Encoder::Encode(
|
|||
const uint32_t duration =
|
||||
kRtpTicksPerSecond / static_cast<float>(encoder_settings_.maxFramerate);
|
||||
|
||||
// TODO(danilchap): Remove this checks when layering is implemented.
|
||||
RTC_DCHECK_EQ(layer_frames.size(), 1);
|
||||
for (ScalableVideoController::LayerFrameConfig& layer_frame : layer_frames) {
|
||||
aom_enc_frame_flags_t flags =
|
||||
layer_frame.is_keyframe ? AOM_EFLAG_FORCE_KF : 0;
|
||||
|
||||
// TODO(danilchap): configure buffers and layers based on
|
||||
// `layer_frame.buffers` when layering is enabled.
|
||||
if (svc_enabled_) {
|
||||
SetSvcLayerId(layer_frame);
|
||||
SetSvcRefFrameConfig(layer_frame);
|
||||
}
|
||||
|
||||
// Encode a frame.
|
||||
aom_codec_err_t ret = aom_codec_encode(&ctx_, frame_for_encode_,
|
||||
|
|
Loading…
Reference in a new issue