0

media/gpu/VP9VaapiVideoEncoderDelegate: Support spatial SVC encoding

This CL adds the spatial SVC encoding support for
VP9VaapiVideoEncoderDelegate.

Bug: 1186051
Change-Id: I5129246f41420d86b9ecd9f0d488d9d25721e43b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2897010
Commit-Queue: Zhaoliang Ma <zhaoliang.ma@intel.com>
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#896018}
This commit is contained in:
Zhaoliang Ma
2021-06-25 12:28:56 +00:00
committed by Chromium LUCI CQ
parent 3ccd773c99
commit 6f92ac0be6
6 changed files with 571 additions and 165 deletions

@ -168,6 +168,8 @@ VP9SVCLayers::VP9SVCLayers(const std::vector<SpatialLayer>& spatial_layers)
gfx::Size(spatial_layer.width, spatial_layer.height));
}
active_spatial_layer_resolutions_ = spatial_layer_resolutions_;
begin_active_layer_ = 0;
end_active_layer_ = active_spatial_layer_resolutions_.size();
DCHECK_LE(num_temporal_layers_, kMaxSupportedTemporalLayers);
DCHECK(!spatial_layer_resolutions_.empty());
DCHECK_LE(spatial_layer_resolutions_.size(), kMaxSpatialLayers);
@ -177,9 +179,10 @@ VP9SVCLayers::~VP9SVCLayers() = default;
bool VP9SVCLayers::UpdateEncodeJob(bool is_key_frame_requested,
size_t kf_period_frames) {
if (is_key_frame_requested) {
if (force_key_frame_ || is_key_frame_requested) {
frame_num_ = 0;
spatial_idx_ = 0;
force_key_frame_ = false;
}
if (spatial_idx_ == active_spatial_layer_resolutions_.size()) {
@ -191,10 +194,111 @@ bool VP9SVCLayers::UpdateEncodeJob(bool is_key_frame_requested,
return frame_num_ == 0 && spatial_idx_ == 0;
}
bool VP9SVCLayers::MaybeUpdateActiveLayer(
VideoBitrateAllocation* bitrate_allocation) {
// Don't update active layer if current picture haven't completed SVC
// encoding. Since the |spatial_idx_| is updated in the beginning of next
// encoding, so the |spatial_idx_| equals 0 (only for the first frame) or the
// number of active spatial layers indicates the complement of SVC picture
// encoding.
if (spatial_idx_ != 0 &&
spatial_idx_ != active_spatial_layer_resolutions_.size()) {
return false;
}
size_t begin_active_layer = kMaxSpatialLayers;
size_t end_active_layer = spatial_layer_resolutions_.size();
for (size_t sid = 0; sid < spatial_layer_resolutions_.size(); ++sid) {
size_t sum = 0;
for (size_t tid = 0; tid < num_temporal_layers_; ++tid) {
const int tl_bitrate = bitrate_allocation->GetBitrateBps(sid, tid);
// A bitrate of a temporal layer must be zero if the bitrates of lower
// temporal layers are zero, e.g. {0, 0, 100}.
if (tid > 0 && tl_bitrate > 0 && sum == 0)
return false;
// A bitrate of a temporal layer must not be zero if the bitrates of lower
// temporal layers are not zero, e.g. {100, 0, 0}.
if (tid > 0 && tl_bitrate == 0 && sum != 0)
return false;
sum += static_cast<size_t>(tl_bitrate);
}
// Check if the temporal layers larger than |num_temporal_layers_| are zero.
for (size_t tid = num_temporal_layers_;
tid < VideoBitrateAllocation::kMaxTemporalLayers; ++tid) {
if (bitrate_allocation->GetBitrateBps(sid, tid) != 0)
return false;
}
if (sum == 0) {
// This is the first non-active spatial layer in the end side.
if (begin_active_layer != kMaxSpatialLayers) {
end_active_layer = sid;
break;
}
// No active spatial layer is found yet. Try the upper spatial layer.
continue;
}
// This is the lowest active layer.
if (begin_active_layer == kMaxSpatialLayers)
begin_active_layer = sid;
}
// Check if all the bitrates of unsupported temporal and spatial layers are
// zero.
for (size_t sid = end_active_layer;
sid < VideoBitrateAllocation::kMaxSpatialLayers; ++sid) {
for (size_t tid = 0; tid < VideoBitrateAllocation::kMaxTemporalLayers;
++tid) {
if (bitrate_allocation->GetBitrateBps(sid, tid) != 0)
return false;
}
}
// No active layer is found.
if (begin_active_layer == kMaxSpatialLayers)
return false;
DCHECK_LT(begin_active_layer_, end_active_layer_);
DCHECK_LE(end_active_layer_ - begin_active_layer_,
spatial_layer_resolutions_.size());
// Remove non active spatial layer bitrate if |begin_active_layer| > 0.
if (begin_active_layer > 0) {
for (size_t sid = begin_active_layer; sid < end_active_layer; ++sid) {
for (size_t tid = 0; tid < num_temporal_layers_; ++tid) {
int bitrate = bitrate_allocation->GetBitrateBps(sid, tid);
bitrate_allocation->SetBitrate(sid - begin_active_layer, tid, bitrate);
bitrate_allocation->SetBitrate(sid, tid, 0);
}
}
}
// Reset SVC parameters and force to produce key frame if active layer
// changed.
if (begin_active_layer != begin_active_layer_ ||
end_active_layer != end_active_layer_) {
// Update the stored active layer range.
begin_active_layer_ = begin_active_layer;
end_active_layer_ = end_active_layer;
active_spatial_layer_resolutions_ = {
spatial_layer_resolutions_.begin() + begin_active_layer,
spatial_layer_resolutions_.begin() + end_active_layer};
force_key_frame_ = true;
}
return true;
}
void VP9SVCLayers::FillUsedRefFramesAndMetadata(
VP9Picture* picture,
std::array<bool, kVp9NumRefsPerFrame>* ref_frames_used) {
DCHECK(picture->frame_hdr);
// Update the spatial layer size for VP9FrameHeader.
gfx::Size updated_size = active_spatial_layer_resolutions_[spatial_idx_];
picture->frame_hdr->render_width = updated_size.width();
picture->frame_hdr->render_height = updated_size.height();
picture->frame_hdr->frame_width = updated_size.width();
picture->frame_hdr->frame_height = updated_size.height();
// Initialize |metadata_for_encoding| with default values.
picture->metadata_for_encoding.emplace();

@ -13,6 +13,7 @@
#include "media/video/video_encode_accelerator.h"
namespace media {
class VideoBitrateAllocation;
class VP9Picture;
struct Vp9Metadata;
@ -46,6 +47,10 @@ class VP9SVCLayers {
// Returns true if EncodeJob needs to produce key frame.
bool UpdateEncodeJob(bool is_key_frame_requested, size_t kf_period_frames);
// Activate/Deactivate spatial layers via |bitrate_allocation|.
// Returns whether (de)updating is successful.
bool MaybeUpdateActiveLayer(VideoBitrateAllocation* bitrate_allocation);
// Sets |picture|'s used reference frames and |ref_frames_used| so that they
// structure valid temporal layers. This also fills |picture|'s
// |metadata_for_encoding|.
@ -54,6 +59,9 @@ class VP9SVCLayers {
std::array<bool, kVp9NumRefsPerFrame>* ref_frames_used);
size_t num_temporal_layers() const { return num_temporal_layers_; }
const std::vector<gfx::Size>& active_spatial_layer_resolutions() const {
return active_spatial_layer_resolutions_;
}
private:
// Useful functions to construct refresh flag and detect reference frames
@ -76,11 +84,18 @@ class VP9SVCLayers {
const size_t temporal_pattern_size_;
size_t spatial_idx_ = 0;
size_t frame_num_ = 0;
bool force_key_frame_ = false;
// Resolutions for all spatial layers and active spatial layers.
std::vector<gfx::Size> spatial_layer_resolutions_;
std::vector<gfx::Size> active_spatial_layer_resolutions_;
// Stores the active layer range, only used to judge whether active range has
// changed in |MaybeUpdateActiveLayer|, then
// |active_spatial_layer_resolutions_| needs update.
size_t begin_active_layer_;
size_t end_active_layer_;
// The pattern index used for reference frames slots.
uint8_t pattern_index_of_ref_frames_slots_[kMaxNumUsedReferenceFrames] = {};
};

@ -178,6 +178,93 @@ void VP9SVCLayersTest::VerifyRefFrames(
}
}
// This test verifies the bitrate check in MaybeUpdateActiveLayer().
TEST_F(VP9SVCLayersTest, MaybeUpdateActiveLayer) {
constexpr size_t kNumSpatialLayers = 3;
constexpr size_t kNumTemporalLayers = 3;
const std::vector<VP9SVCLayers::SpatialLayer> spatial_layers =
GetDefaultSVCLayers(kNumSpatialLayers, kNumTemporalLayers);
VP9SVCLayers svc_layers(spatial_layers);
// Set Default bitrate allocation.
int layer_rate = 1;
VideoBitrateAllocation allocation;
for (size_t sid = 0; sid < VideoBitrateAllocation::kMaxSpatialLayers; ++sid) {
for (size_t tid = 0; tid < VideoBitrateAllocation::kMaxTemporalLayers;
++tid) {
allocation.SetBitrate(sid, tid, layer_rate++);
}
}
DCHECK_LT(kNumSpatialLayers, VideoBitrateAllocation::kMaxSpatialLayers);
DCHECK_LT(kNumTemporalLayers, VideoBitrateAllocation::kMaxTemporalLayers);
EXPECT_FALSE(svc_layers.MaybeUpdateActiveLayer(&allocation));
// Set unsupported temporal layer bitrate to 0.
for (size_t sid = 0; sid < VideoBitrateAllocation::kMaxSpatialLayers; ++sid) {
for (size_t tid = kNumTemporalLayers;
tid < VideoBitrateAllocation::kMaxTemporalLayers; ++tid) {
allocation.SetBitrate(sid, tid, 0);
}
}
EXPECT_FALSE(svc_layers.MaybeUpdateActiveLayer(&allocation));
// Set unsupported spatial layer bitrate to 0.
for (size_t sid = kNumSpatialLayers;
sid < VideoBitrateAllocation::kMaxSpatialLayers; ++sid) {
for (size_t tid = 0; tid < VideoBitrateAllocation::kMaxTemporalLayers;
++tid) {
allocation.SetBitrate(sid, tid, 0);
}
}
EXPECT_TRUE(svc_layers.MaybeUpdateActiveLayer(&allocation));
// Set lower temporal layer bitrate to zero, e.g. {0, 2, 3}.
allocation.SetBitrate(/*spatial_index=*/0, /*temporal_index=*/0, 0);
EXPECT_FALSE(svc_layers.MaybeUpdateActiveLayer(&allocation));
allocation.SetBitrate(/*spatial_index=*/0, /*temporal_index=*/0, 1);
// Set upper temporal layer bitrate to 0, e.g. {1, 2, 0}.
allocation.SetBitrate(/*spatial_index=*/0, /*temporal_index=*/2, 0);
EXPECT_FALSE(svc_layers.MaybeUpdateActiveLayer(&allocation));
allocation.SetBitrate(/*spatial_index=*/0, /*temporal_index=*/2, 3);
// Deactivate SL0 and SL1 and verify the new bitrate allocation.
constexpr int kNumDeactivatedLowerSpatialLayer = 2;
VideoBitrateAllocation new_allocation = allocation;
for (size_t sid = 0; sid < kNumDeactivatedLowerSpatialLayer; ++sid) {
for (size_t tid = 0; tid < kNumTemporalLayers; ++tid)
new_allocation.SetBitrate(sid, tid, 0);
}
EXPECT_TRUE(svc_layers.MaybeUpdateActiveLayer(&new_allocation));
for (size_t sid = 0; sid < kNumSpatialLayers; ++sid) {
for (size_t tid = 0; tid < kNumTemporalLayers; ++tid) {
if (sid + kNumDeactivatedLowerSpatialLayer <
VideoBitrateAllocation::kMaxSpatialLayers)
EXPECT_EQ(new_allocation.GetBitrateBps(sid, tid),
allocation.GetBitrateBps(
sid + kNumDeactivatedLowerSpatialLayer, tid));
else
EXPECT_EQ(new_allocation.GetBitrateBps(sid, tid), 0);
}
}
// Deactivate SL2 and verify the new bitrate allocation.
new_allocation = allocation;
constexpr int kNumActiveSpatialLayer = 2;
for (size_t tid = 0; tid < kNumTemporalLayers; ++tid)
new_allocation.SetBitrate(/*spatial_index=*/2, tid, 0);
EXPECT_TRUE(svc_layers.MaybeUpdateActiveLayer(&new_allocation));
for (size_t sid = 0; sid < kNumSpatialLayers; ++sid) {
for (size_t tid = 0; tid < kNumTemporalLayers; ++tid) {
if (sid < kNumActiveSpatialLayer)
EXPECT_EQ(new_allocation.GetBitrateBps(sid, tid),
allocation.GetBitrateBps(sid, tid));
else
EXPECT_EQ(new_allocation.GetBitrateBps(sid, tid), 0);
}
}
}
TEST_P(VP9SVCLayersTest, ) {
const size_t num_spatial_layers = ::testing::get<0>(GetParam());
const size_t num_temporal_layers = ::testing::get<1>(GetParam());

@ -12,6 +12,7 @@
#include "base/bits.h"
#include "base/memory/ref_counted_memory.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "media/gpu/macros.h"
#include "media/gpu/vaapi/vaapi_common.h"
#include "media/gpu/vaapi/vaapi_wrapper.h"
@ -25,9 +26,6 @@ namespace {
// Keyframe period.
constexpr size_t kKFPeriod = 3000;
// Arbitrarily chosen bitrate window size for rate control, in ms.
constexpr int kCPBWindowSizeMs = 500;
// Quantization parameter. They are vp9 ac/dc indices and their ranges are
// 0-255. Based on WebRTC's defaults.
constexpr uint8_t kMinQP = 4;
@ -68,6 +66,12 @@ uint8_t QindexToQuantizer(uint8_t q_index) {
return base::size(kQuantizerToQindex) - 1;
}
// TODO(crbug.com/752720): remove this in favor of std::gcd if c++17 is enabled
// to use.
int GCD(int a, int b) {
return a == 0 ? b : GCD(b % a, a);
}
// The return value is expressed as a percentage of the average. For example,
// to allocate no more than 4.5 frames worth of bitrate to a keyframe, the
// return value is 450.
@ -91,39 +95,43 @@ uint32_t MaxSizeOfKeyframeAsPercentage(uint32_t optimal_buffer_size,
VideoBitrateAllocation GetDefaultVideoBitrateAllocation(
const VideoEncodeAccelerator::Config& config) {
DCHECK(!config.HasSpatialLayer()) << "Spatial layers are not supported.";
VideoBitrateAllocation bitrate_allocation;
if (!config.HasTemporalLayer()) {
if (!config.HasTemporalLayer() && !config.HasSpatialLayer()) {
bitrate_allocation.SetBitrate(0, 0, config.initial_bitrate);
return bitrate_allocation;
}
const auto& spatial_layer = config.spatial_layers[0];
const size_t num_temporal_layers = spatial_layer.num_of_temporal_layers;
DCHECK_GT(num_temporal_layers, 1u);
DCHECK_LE(num_temporal_layers, 3u);
constexpr double kTemporalLayersBitrateScaleFactors
[][VP9SVCLayers::kMaxSupportedTemporalLayers] = {
{0.50, 0.50, 0.00}, // For two temporal layers.
{0.25, 0.25, 0.50}, // For three temporal layers.
};
DCHECK_LE(config.spatial_layers.size(), VP9SVCLayers::kMaxSpatialLayers);
for (size_t sid = 0; sid < config.spatial_layers.size(); ++sid) {
const auto& spatial_layer = config.spatial_layers[sid];
const size_t num_temporal_layers = spatial_layer.num_of_temporal_layers;
DCHECK_LE(num_temporal_layers, VP9SVCLayers::kMaxSupportedTemporalLayers);
constexpr double kTemporalLayersBitrateScaleFactors
[][VP9SVCLayers::kMaxSupportedTemporalLayers] = {
{1.00, 0.00, 0.00}, // For one temporal layer.
{0.50, 0.50, 0.00}, // For two temporal layers.
{0.25, 0.25, 0.50}, // For three temporal layers.
};
const uint32_t bitrate_bps = spatial_layer.bitrate_bps;
for (size_t i = 0; i < num_temporal_layers; ++i) {
const double factor =
kTemporalLayersBitrateScaleFactors[num_temporal_layers - 2][i];
bitrate_allocation.SetBitrate(
0 /* spatial_index */, i,
base::checked_cast<int>(bitrate_bps * factor));
const uint32_t bitrate_bps = spatial_layer.bitrate_bps;
for (size_t tid = 0; tid < num_temporal_layers; ++tid) {
const double factor =
kTemporalLayersBitrateScaleFactors[num_temporal_layers - 1][tid];
bitrate_allocation.SetBitrate(
sid, tid, base::checked_cast<int>(bitrate_bps * factor));
}
}
return bitrate_allocation;
}
libvpx::VP9RateControlRtcConfig CreateRateControlConfig(
const gfx::Size encode_size,
const VP9VaapiVideoEncoderDelegate::EncodeParams& encode_params,
const VideoBitrateAllocation& bitrate_allocation,
const size_t num_temporal_layers) {
const size_t num_temporal_layers,
const std::vector<gfx::Size>& spatial_layer_resolutions) {
DCHECK(!spatial_layer_resolutions.empty());
const gfx::Size& encode_size = spatial_layer_resolutions.back();
const size_t num_spatial_layers = spatial_layer_resolutions.size();
libvpx::VP9RateControlRtcConfig rc_cfg{};
rc_cfg.rc_mode = VPX_CBR;
rc_cfg.width = encode_size.width();
@ -143,19 +151,24 @@ libvpx::VP9RateControlRtcConfig CreateRateControlConfig(
rc_cfg.buf_optimal_sz, encode_params.framerate);
rc_cfg.framerate = encode_params.framerate;
// Spatial layers variables.
rc_cfg.ss_number_layers = 1;
rc_cfg.scaling_factor_num[0] = 1;
rc_cfg.scaling_factor_den[0] = 1;
// Fill temporal layers variables.
// Fill spatial/temporal layers variables.
rc_cfg.ss_number_layers = num_spatial_layers;
rc_cfg.ts_number_layers = num_temporal_layers;
int bitrate_sum = 0;
for (size_t ti = 0; ti < num_temporal_layers; ti++) {
rc_cfg.max_quantizers[ti] = rc_cfg.max_quantizer;
rc_cfg.min_quantizers[ti] = rc_cfg.min_quantizer;
bitrate_sum += bitrate_allocation.GetBitrateBps(0, ti);
rc_cfg.layer_target_bitrate[ti] = bitrate_sum / 1000;
rc_cfg.ts_rate_decimator[ti] = 1u << (num_temporal_layers - ti - 1);
for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
int gcd =
GCD(encode_size.height(), spatial_layer_resolutions[sid].height());
rc_cfg.scaling_factor_num[sid] =
spatial_layer_resolutions[sid].height() / gcd;
rc_cfg.scaling_factor_den[sid] = encode_size.height() / gcd;
int bitrate_sum = 0;
for (size_t tid = 0; tid < num_temporal_layers; ++tid) {
size_t idx = sid * num_temporal_layers + tid;
rc_cfg.max_quantizers[idx] = rc_cfg.max_quantizer;
rc_cfg.min_quantizers[idx] = rc_cfg.min_quantizer;
bitrate_sum += bitrate_allocation.GetBitrateBps(sid, tid);
rc_cfg.layer_target_bitrate[idx] = bitrate_sum / 1000;
rc_cfg.ts_rate_decimator[tid] = 1u << (num_temporal_layers - tid - 1);
}
}
return rc_cfg;
}
@ -171,8 +184,6 @@ static scoped_refptr<base::RefCountedBytes> MakeRefCountedBytes(void* ptr,
VP9VaapiVideoEncoderDelegate::EncodeParams::EncodeParams()
: kf_period_frames(kKFPeriod),
framerate(0),
cpb_window_size_ms(kCPBWindowSizeMs),
cpb_size_bits(0),
initial_qp(kDefaultQP),
min_qp(kMinQP),
max_qp(kMaxQP),
@ -200,10 +211,6 @@ bool VP9VaapiVideoEncoderDelegate::Initialize(
DVLOGF(1) << "Invalid profile: " << GetProfileName(config.output_profile);
return false;
}
if (config.HasSpatialLayer()) {
DVLOGF(1) << "Spatial layer encoding is not supported";
return false;
}
if (config.input_visible_size.IsEmpty()) {
DVLOGF(1) << "Input visible size could not be empty";
@ -228,34 +235,68 @@ bool VP9VaapiVideoEncoderDelegate::Initialize(
auto initial_bitrate_allocation = GetDefaultVideoBitrateAllocation(config);
size_t num_temporal_layers = 1;
if (config.HasTemporalLayer()) {
size_t num_spatial_layers = 1;
std::vector<gfx::Size> spatial_layer_resolutions;
if (config.HasTemporalLayer() || config.HasSpatialLayer()) {
num_spatial_layers = config.spatial_layers.size();
num_temporal_layers = config.spatial_layers[0].num_of_temporal_layers;
if (num_temporal_layers == 1 && !config.HasSpatialLayer()) {
VLOGF(1) << "VP9SVCLayers only supports single temporal layer with more "
"than one spatial layer encoding";
DCHECK(num_spatial_layers != 1 || num_temporal_layers != 1);
for (size_t sid = 1; sid < num_spatial_layers; ++sid) {
if (num_temporal_layers !=
config.spatial_layers[sid].num_of_temporal_layers) {
VLOGF(1) << "The temporal layer sizes among spatial layers must be "
"identical";
return false;
}
}
if (num_spatial_layers > VP9SVCLayers::kMaxSpatialLayers ||
num_temporal_layers > VP9SVCLayers::kMaxSupportedTemporalLayers) {
VLOGF(1) << "Unsupported amount of spatial/temporal layers: "
<< ", Spatial layer number: " << num_spatial_layers
<< ", Temporal layer number: " << num_temporal_layers;
return false;
}
if (num_temporal_layers > VP9SVCLayers::kMaxSupportedTemporalLayers) {
VLOGF(1) << "Unsupported amount of temporal layers: "
<< num_temporal_layers;
if (num_spatial_layers > 1 &&
config.inter_layer_pred !=
VideoEncodeAccelerator::Config::InterLayerPredMode::kOnKeyPic) {
std::string inter_layer_pred;
if (config.inter_layer_pred ==
VideoEncodeAccelerator::Config::InterLayerPredMode::kOn)
inter_layer_pred = base::StringPrintf("InterLayerPredMode::kOn");
else
inter_layer_pred = base::StringPrintf("InterLayerPredMode::kOff");
VLOGF(1) << "Support only k-SVC encoding. inter_layer_pred="
<< inter_layer_pred;
return false;
}
for (const auto& spatial_layer : config.spatial_layers) {
spatial_layer_resolutions.emplace_back(
gfx::Size(spatial_layer.width, spatial_layer.height));
}
svc_layers_ = std::make_unique<VP9SVCLayers>(config.spatial_layers);
}
current_params_.max_qp = kMaxQPForSoftwareRateCtrl;
// Store layer size for vp9 simple stream.
if (spatial_layer_resolutions.empty())
spatial_layer_resolutions.push_back(visible_size_);
// |rate_ctrl_| might be injected for tests.
if (!rate_ctrl_) {
rate_ctrl_ = VP9RateControl::Create(CreateRateControlConfig(
visible_size_, current_params_, initial_bitrate_allocation,
num_temporal_layers));
current_params_, initial_bitrate_allocation, num_temporal_layers,
spatial_layer_resolutions));
}
if (!rate_ctrl_)
return false;
return UpdateRates(initial_bitrate_allocation,
DCHECK(!pending_update_rates_);
pending_update_rates_ =
std::make_pair(initial_bitrate_allocation,
config.initial_framerate.value_or(
VideoEncodeAccelerator::kDefaultFramerate));
return ApplyPendingUpdateRates();
}
gfx::Size VP9VaapiVideoEncoderDelegate::GetCodedSize() const {
@ -274,6 +315,9 @@ size_t VP9VaapiVideoEncoderDelegate::GetMaxNumOfRefFrames() const {
bool VP9VaapiVideoEncoderDelegate::PrepareEncodeJob(EncodeJob* encode_job) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!ApplyPendingUpdateRates())
return false;
if (svc_layers_) {
if (svc_layers_->UpdateEncodeJob(encode_job->IsKeyframeRequested(),
current_params_.kf_period_frames)) {
@ -332,6 +376,38 @@ void VP9VaapiVideoEncoderDelegate::BitrateControlUpdate(
rate_ctrl_->PostEncodeUpdate(encoded_chunk_size_bytes);
}
bool VP9VaapiVideoEncoderDelegate::ApplyPendingUpdateRates() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!pending_update_rates_)
return true;
VLOGF(2) << "New bitrate: " << pending_update_rates_->first.GetSumBps()
<< ", New framerate: " << pending_update_rates_->second;
current_params_.bitrate_allocation = pending_update_rates_->first;
current_params_.framerate = pending_update_rates_->second;
pending_update_rates_.reset();
// Update active layer status in |svc_layers_|, and key frame is produced when
// active layer changed.
if (svc_layers_ &&
!svc_layers_->MaybeUpdateActiveLayer(&current_params_.bitrate_allocation))
return false;
if (!rate_ctrl_)
return true;
const size_t num_temporal_layers =
svc_layers_ ? svc_layers_->num_temporal_layers() : 1u;
std::vector<gfx::Size> spatial_layer_resolutions = {visible_size_};
if (svc_layers_)
spatial_layer_resolutions = svc_layers_->active_spatial_layer_resolutions();
rate_ctrl_->UpdateRateControl(CreateRateControlConfig(
current_params_, current_params_.bitrate_allocation, num_temporal_layers,
spatial_layer_resolutions));
return true;
}
bool VP9VaapiVideoEncoderDelegate::UpdateRates(
const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate) {
@ -340,27 +416,11 @@ bool VP9VaapiVideoEncoderDelegate::UpdateRates(
if (bitrate_allocation.GetSumBps() == 0 || framerate == 0)
return false;
if (current_params_.bitrate_allocation == bitrate_allocation &&
current_params_.framerate == framerate) {
return true;
pending_update_rates_ = std::make_pair(bitrate_allocation, framerate);
if (current_params_.bitrate_allocation == pending_update_rates_->first &&
current_params_.framerate == pending_update_rates_->second) {
pending_update_rates_.reset();
}
VLOGF(2) << "New bitrate: " << bitrate_allocation.GetSumBps()
<< ", New framerate: " << framerate;
current_params_.bitrate_allocation = bitrate_allocation;
current_params_.framerate = framerate;
current_params_.cpb_size_bits =
current_params_.bitrate_allocation.GetSumBps() *
current_params_.cpb_window_size_ms / 1000;
if (!rate_ctrl_)
return true;
const size_t num_temporal_layers =
svc_layers_ ? svc_layers_->num_temporal_layers() : 1u;
rate_ctrl_->UpdateRateControl(CreateRateControlConfig(
visible_size_, current_params_, bitrate_allocation, num_temporal_layers));
return true;
}
@ -392,7 +452,7 @@ void VP9VaapiVideoEncoderDelegate::SetFrameHeader(
*picture->frame_hdr = GetDefaultFrameHeader(keyframe);
if (svc_layers_) {
// Reference frame settings for temporal layer stream.
// Reference frame settings for k-SVC stream.
svc_layers_->FillUsedRefFramesAndMetadata(picture, ref_frames_used);
// Enable error resilient mode so that the syntax of a frame can be decoded
// independently of previous frames.
@ -424,12 +484,19 @@ void VP9VaapiVideoEncoderDelegate::SetFrameHeader(
if (picture->metadata_for_encoding) {
frame_params.temporal_layer_id =
picture->metadata_for_encoding->temporal_idx;
frame_params.spatial_layer_id = picture->metadata_for_encoding->spatial_idx;
}
rate_ctrl_->ComputeQP(frame_params);
picture->frame_hdr->quant_params.base_q_idx = rate_ctrl_->GetQP();
picture->frame_hdr->loop_filter.level = rate_ctrl_->GetLoopfilterLevel();
DVLOGF(4) << "qp=" << rate_ctrl_->GetQP()
<< ", filter_level=" << rate_ctrl_->GetLoopfilterLevel();
DVLOGF(4) << "qp="
<< static_cast<int>(picture->frame_hdr->quant_params.base_q_idx)
<< ", filter_level="
<< static_cast<int>(picture->frame_hdr->loop_filter.level)
<< ", frame_params.temporal_layer_id:"
<< frame_params.temporal_layer_id
<< ", frame_params.spatial_layer_id:"
<< frame_params.spatial_layer_id;
}
void VP9VaapiVideoEncoderDelegate::UpdateReferenceFrames(

@ -36,12 +36,6 @@ class VP9VaapiVideoEncoderDelegate : public VaapiVideoEncoderDelegate {
// Framerate in FPS.
uint32_t framerate;
// Bitrate window size in ms.
unsigned int cpb_window_size_ms;
// Coded picture buffer size in bits.
unsigned int cpb_size_bits;
// Quantization parameter. They are vp9 ac/dc indices and their ranges are
// 0-255.
uint8_t initial_qp;
@ -73,6 +67,8 @@ class VP9VaapiVideoEncoderDelegate : public VaapiVideoEncoderDelegate {
void set_rate_ctrl_for_testing(std::unique_ptr<VP9RateControl> rate_ctrl);
bool ApplyPendingUpdateRates();
Vp9FrameHeader GetDefaultFrameHeader(const bool keyframe) const;
void SetFrameHeader(bool keyframe,
VP9Picture* picture,
@ -105,6 +101,9 @@ class VP9VaapiVideoEncoderDelegate : public VaapiVideoEncoderDelegate {
Vp9ReferenceFrameVector reference_frames_;
std::unique_ptr<VP9SVCLayers> svc_layers_;
absl::optional<std::pair<VideoBitrateAllocation, uint32_t>>
pending_update_rates_;
std::unique_ptr<VP9RateControl> rate_ctrl_;
DISALLOW_COPY_AND_ASSIGN(VP9VaapiVideoEncoderDelegate);

@ -34,6 +34,22 @@ namespace {
constexpr size_t kDefaultMaxNumRefFrames = kVp9NumRefsPerFrame;
constexpr double kSpatialLayersBitrateScaleFactors[][3] = {
{1.00, 0.00, 0.00}, // For one spatial layer.
{0.30, 0.70, 0.00}, // For two spatial layers.
{0.07, 0.23, 0.70}, // For three spatial layers.
};
constexpr int kSpatialLayersResolutionScaleDenom[][3] = {
{1, 0, 0}, // For one spatial layer.
{2, 1, 0}, // For two spatial layers.
{4, 2, 1}, // For three spatial layers.
};
constexpr double kTemporalLayersBitrateScaleFactors[][3] = {
{1.00, 0.00, 0.00}, // For one temporal layer.
{0.50, 0.50, 0.00}, // For two temporal layers.
{0.25, 0.25, 0.50}, // For three temporal layers.
};
VaapiVideoEncoderDelegate::Config kDefaultVaapiVideoEncoderDelegateConfig{
kDefaultMaxNumRefFrames,
VaapiVideoEncoderDelegate::BitrateControl::kConstantQuantizationParameter};
@ -55,14 +71,34 @@ constexpr std::array<bool, kVp9NumRefsPerFrame> kRefFramesUsedForInterFrame = {
true, true, true};
void GetTemporalLayer(bool keyframe,
int index,
int frame_num,
size_t num_spatial_layers,
size_t num_temporal_layers,
std::array<bool, kVp9NumRefsPerFrame>* ref_frames_used,
absl::optional<uint8_t>* temporal_layer_id) {
switch (num_temporal_layers) {
case 1:
*ref_frames_used =
keyframe ? kRefFramesUsedForKeyFrame : kRefFramesUsedForInterFrame;
if (num_spatial_layers > 1) {
// K-SVC stream.
if (keyframe) {
*ref_frames_used = keyframe ? kRefFramesUsedForKeyFrame
: kRefFramesUsedForInterFrame;
return;
}
*temporal_layer_id = 0;
{
constexpr std::tuple<uint8_t, std::array<bool, kVp9NumRefsPerFrame>>
kOneTemporalLayersDescription[] = {{0, {true, false, false}}};
const auto& layer_info = kOneTemporalLayersDescription
[frame_num % base::size(kOneTemporalLayersDescription)];
std::tie(*temporal_layer_id, *ref_frames_used) = layer_info;
}
} else {
// Simple stream.
*ref_frames_used =
keyframe ? kRefFramesUsedForKeyFrame : kRefFramesUsedForInterFrame;
}
break;
case 2:
if (keyframe) {
@ -81,7 +117,7 @@ void GetTemporalLayer(bool keyframe,
{0, {true, false, false}}, {1, {true, true, false}},
};
const auto& layer_info = kTwoTemporalLayersDescription
[index % base::size(kTwoTemporalLayersDescription)];
[frame_num % base::size(kTwoTemporalLayersDescription)];
std::tie(*temporal_layer_id, *ref_frames_used) = layer_info;
}
break;
@ -102,7 +138,7 @@ void GetTemporalLayer(bool keyframe,
{1, {true, true, false}}, {2, {true, true, false}},
};
const auto& layer_info = kThreeTemporalLayersDescription
[index % base::size(kThreeTemporalLayersDescription)];
[frame_num % base::size(kThreeTemporalLayersDescription)];
std::tie(*temporal_layer_id, *ref_frames_used) = layer_info;
}
break;
@ -110,34 +146,37 @@ void GetTemporalLayer(bool keyframe,
}
VideoBitrateAllocation GetDefaultVideoBitrateAllocation(
size_t num_spatial_layers,
size_t num_temporal_layers,
uint32_t bitrate) {
VideoBitrateAllocation bitrate_allocation;
if (num_temporal_layers == 1u) {
DCHECK_LE(num_spatial_layers, 3u);
DCHECK_LE(num_temporal_layers, 3u);
if (num_spatial_layers == 1u && num_temporal_layers == 1u) {
bitrate_allocation.SetBitrate(0, 0, bitrate);
return bitrate_allocation;
}
LOG_ASSERT(num_temporal_layers <= VP9SVCLayers::kMaxSupportedTemporalLayers);
constexpr double kTemporalLayersBitrateScaleFactors
[][VP9SVCLayers::kMaxSupportedTemporalLayers] = {
{0.50, 0.50, 0.00}, // For two temporal layers.
{0.25, 0.25, 0.50}, // For three temporal layers.
};
for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
const double bitrate_factor =
kSpatialLayersBitrateScaleFactors[num_spatial_layers - 1][sid];
uint32_t sl_bitrate = bitrate * bitrate_factor;
for (size_t i = 0; i < num_temporal_layers; i++) {
const double factor =
kTemporalLayersBitrateScaleFactors[num_temporal_layers - 2][i];
bitrate_allocation.SetBitrate(0 /* spatial_index */, i,
base::checked_cast<int>(bitrate * factor));
for (size_t tl_idx = 0; tl_idx < num_temporal_layers; ++tl_idx) {
const double tl_factor =
kTemporalLayersBitrateScaleFactors[num_temporal_layers - 1][tl_idx];
bitrate_allocation.SetBitrate(
sid, tl_idx, base::checked_cast<int>(sl_bitrate * tl_factor));
}
}
return bitrate_allocation;
}
MATCHER_P4(MatchRtcConfigWithRates,
MATCHER_P5(MatchRtcConfigWithRates,
size,
bitrate_allocation,
framerate,
num_spatial_layers,
num_temporal_layers,
"") {
if (arg.target_bandwidth != bitrate_allocation.GetSumBps() / 1000)
@ -146,25 +185,39 @@ MATCHER_P4(MatchRtcConfigWithRates,
if (arg.framerate != static_cast<double>(framerate))
return false;
int bitrate_sum = 0;
for (size_t i = 0; i < num_temporal_layers; i++) {
bitrate_sum += bitrate_allocation.GetBitrateBps(0, i);
if (arg.layer_target_bitrate[i] != bitrate_sum / 1000)
return false;
if (arg.ts_rate_decimator[i] != (1 << (num_temporal_layers - i - 1)))
for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
int bitrate_sum = 0;
for (size_t tid = 0; tid < num_temporal_layers; tid++) {
size_t idx = sid * num_temporal_layers + tid;
bitrate_sum += bitrate_allocation.GetBitrateBps(sid, tid);
if (arg.layer_target_bitrate[idx] != bitrate_sum / 1000)
return false;
if (arg.ts_rate_decimator[tid] != (1 << (num_temporal_layers - tid - 1)))
return false;
}
if (arg.scaling_factor_num[sid] != 1 ||
arg.scaling_factor_den[sid] !=
kSpatialLayersResolutionScaleDenom[num_spatial_layers - 1][sid]) {
return false;
}
}
return arg.width == size.width() && arg.height == size.height() &&
base::checked_cast<size_t>(arg.ss_number_layers) ==
num_spatial_layers &&
base::checked_cast<size_t>(arg.ts_number_layers) ==
num_temporal_layers &&
arg.ss_number_layers == 1 && arg.scaling_factor_num[0] == 1 &&
arg.scaling_factor_den[0] == 1;
num_temporal_layers;
}
MATCHER_P2(MatchFrameParam, frame_type, temporal_layer_id, "") {
MATCHER_P3(MatchFrameParam,
frame_type,
temporal_layer_id,
spatial_layer_id,
"") {
return arg.frame_type == frame_type &&
(!temporal_layer_id || arg.temporal_layer_id == *temporal_layer_id);
(!temporal_layer_id || arg.temporal_layer_id == *temporal_layer_id) &&
(!spatial_layer_id || arg.spatial_layer_id == *spatial_layer_id);
}
class MockVaapiWrapper : public VaapiWrapper {
@ -204,13 +257,17 @@ class VP9VaapiVideoEncoderDelegateTest
protected:
void InitializeVP9VaapiVideoEncoderDelegate(BitrateControl bitrate_control,
size_t num_spatial_layers,
size_t num_temporal_layers);
void EncodeConstantQuantizationParameterSequence(
bool is_keyframe,
size_t num_spatial_layers,
absl::optional<std::array<bool, kVp9NumRefsPerFrame>>
expected_ref_frames_used,
absl::optional<uint8_t> expected_temporal_layer_id = absl::nullopt);
absl::optional<uint8_t> expected_temporal_layer_id = absl::nullopt,
absl::optional<uint8_t> expected_spatial_layer_id = absl::nullopt);
void UpdateRatesTest(BitrateControl bitrate_control,
size_t num_spatial_layers,
size_t num_temporal_layers);
private:
@ -221,6 +278,7 @@ class VP9VaapiVideoEncoderDelegateTest
void UpdateRatesSequence(const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate,
BitrateControl bitrate_control,
size_t num_spatial_layers,
size_t num_temporal_layers);
std::unique_ptr<VP9VaapiVideoEncoderDelegate> encoder_;
@ -264,6 +322,7 @@ VP9VaapiVideoEncoderDelegateTest::CreateEncodeJob(
void VP9VaapiVideoEncoderDelegateTest::InitializeVP9VaapiVideoEncoderDelegate(
BitrateControl bitrate_control,
size_t num_spatial_layers,
size_t num_temporal_layers) {
auto config = kDefaultVideoEncodeAcceleratorConfig;
auto ave_config = kDefaultVaapiVideoEncoderDelegateConfig;
@ -277,44 +336,63 @@ void VP9VaapiVideoEncoderDelegateTest::InitializeVP9VaapiVideoEncoderDelegate(
VideoBitrateAllocation initial_bitrate_allocation;
initial_bitrate_allocation.SetBitrate(
0, 0, kDefaultVideoEncodeAcceleratorConfig.initial_bitrate);
if (num_temporal_layers > 1u) {
VideoEncodeAccelerator::Config::SpatialLayer spatial_layer;
spatial_layer.width = config.input_visible_size.width();
spatial_layer.height = config.input_visible_size.height();
spatial_layer.bitrate_bps = config.initial_bitrate;
spatial_layer.framerate = *config.initial_framerate;
spatial_layer.max_qp = 30;
spatial_layer.num_of_temporal_layers = num_temporal_layers;
config.spatial_layers.push_back(spatial_layer);
if (num_spatial_layers > 1u || num_temporal_layers > 1u) {
DCHECK_GT(num_spatial_layers, 0u);
for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
const double bitrate_factor =
kSpatialLayersBitrateScaleFactors[num_spatial_layers - 1][sid];
const double resolution_denom =
kSpatialLayersResolutionScaleDenom[num_spatial_layers - 1][sid];
VideoEncodeAccelerator::Config::SpatialLayer spatial_layer;
spatial_layer.width =
config.input_visible_size.width() / resolution_denom;
spatial_layer.height =
config.input_visible_size.height() / resolution_denom;
spatial_layer.bitrate_bps = config.initial_bitrate * bitrate_factor;
spatial_layer.framerate = *config.initial_framerate;
spatial_layer.num_of_temporal_layers = num_temporal_layers;
spatial_layer.max_qp = 30u;
config.spatial_layers.push_back(spatial_layer);
}
}
EXPECT_CALL(
*mock_rate_ctrl_,
UpdateRateControl(MatchRtcConfigWithRates(
kDefaultVideoEncodeAcceleratorConfig.input_visible_size,
GetDefaultVideoBitrateAllocation(num_temporal_layers,
config.initial_bitrate),
VideoEncodeAccelerator::kDefaultFramerate, num_temporal_layers)))
GetDefaultVideoBitrateAllocation(
num_spatial_layers, num_temporal_layers, config.initial_bitrate),
VideoEncodeAccelerator::kDefaultFramerate, num_spatial_layers,
num_temporal_layers)))
.Times(1)
.WillOnce(Return());
EXPECT_TRUE(encoder_->Initialize(config, ave_config));
EXPECT_EQ(num_temporal_layers > 1u, !!encoder_->svc_layers_);
EXPECT_EQ(num_temporal_layers > 1u || num_spatial_layers > 1u,
!!encoder_->svc_layers_);
}
void VP9VaapiVideoEncoderDelegateTest::
EncodeConstantQuantizationParameterSequence(
bool is_keyframe,
size_t num_spatial_layers,
absl::optional<std::array<bool, kVp9NumRefsPerFrame>>
expected_ref_frames_used,
absl::optional<uint8_t> expected_temporal_layer_id) {
absl::optional<uint8_t> expected_temporal_layer_id,
absl::optional<uint8_t> expected_spatial_layer_id) {
InSequence seq;
constexpr VASurfaceID kDummyVASurfaceID = 123;
const double resolution_denom =
kSpatialLayersResolutionScaleDenom[num_spatial_layers - 1]
[expected_spatial_layer_id.value_or(0)];
gfx::Size layer_size = gfx::Size(
kDefaultVideoEncodeAcceleratorConfig.input_visible_size.width() /
resolution_denom,
kDefaultVideoEncodeAcceleratorConfig.input_visible_size.height() /
resolution_denom);
auto va_surface = base::MakeRefCounted<VASurface>(
kDummyVASurfaceID,
kDefaultVideoEncodeAcceleratorConfig.input_visible_size,
VA_RT_FORMAT_YUV420, base::DoNothing());
kDummyVASurfaceID, layer_size, VA_RT_FORMAT_YUV420, base::DoNothing());
scoped_refptr<VP9Picture> picture = new VaapiVP9Picture(va_surface);
auto encode_job = CreateEncodeJob(is_keyframe, va_surface, picture);
@ -323,7 +401,8 @@ void VP9VaapiVideoEncoderDelegateTest::
is_keyframe ? FRAME_TYPE::KEY_FRAME : FRAME_TYPE::INTER_FRAME;
EXPECT_CALL(
*mock_rate_ctrl_,
ComputeQP(MatchFrameParam(libvpx_frame_type, expected_temporal_layer_id)))
ComputeQP(MatchFrameParam(libvpx_frame_type, expected_temporal_layer_id,
expected_spatial_layer_id)))
.WillOnce(Return());
constexpr int kDefaultQP = 34;
constexpr int kDefaultLoopFilterLevel = 8;
@ -348,38 +427,48 @@ void VP9VaapiVideoEncoderDelegateTest::UpdateRatesSequence(
const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate,
BitrateControl bitrate_control,
size_t num_spatial_layers,
size_t num_temporal_layers) {
ASSERT_TRUE(encoder_->current_params_.bitrate_allocation !=
bitrate_allocation ||
encoder_->current_params_.framerate != framerate);
ASSERT_EQ(bitrate_control, BitrateControl::kConstantQuantizationParameter);
EXPECT_CALL(*mock_rate_ctrl_, UpdateRateControl(MatchRtcConfigWithRates(
encoder_->visible_size_, bitrate_allocation,
framerate, num_temporal_layers)))
EXPECT_CALL(*mock_rate_ctrl_,
UpdateRateControl(MatchRtcConfigWithRates(
encoder_->visible_size_, bitrate_allocation, framerate,
num_spatial_layers, num_temporal_layers)))
.Times(1)
.WillOnce(Return());
EXPECT_TRUE(encoder_->UpdateRates(bitrate_allocation, framerate));
EXPECT_EQ(encoder_->current_params_.bitrate_allocation, bitrate_allocation);
EXPECT_EQ(encoder_->current_params_.framerate, framerate);
}
void VP9VaapiVideoEncoderDelegateTest::UpdateRatesTest(
BitrateControl bitrate_control,
size_t num_spatial_layers,
size_t num_temporal_layers) {
ASSERT_TRUE(num_temporal_layers <= VP9SVCLayers::kMaxSupportedTemporalLayers);
const auto update_rates_and_encode =
[this, bitrate_control, num_temporal_layers](
bool is_keyframe, const VideoBitrateAllocation& bitrate_allocation,
[this, bitrate_control, num_spatial_layers, num_temporal_layers](
bool is_key_pic, const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate) {
UpdateRatesSequence(bitrate_allocation, framerate, bitrate_control,
num_temporal_layers);
num_spatial_layers, num_temporal_layers);
ASSERT_EQ(bitrate_control,
BitrateControl::kConstantQuantizationParameter);
EncodeConstantQuantizationParameterSequence(is_keyframe, {},
absl::nullopt);
for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
const bool is_keyframe = is_key_pic && sid == 0;
EncodeConstantQuantizationParameterSequence(
is_keyframe, num_spatial_layers, {}, absl::nullopt,
absl::nullopt);
// Check if a rate change request is applied because the request is
// applied during PrepareEncodeJob().
EXPECT_EQ(encoder_->current_params_.bitrate_allocation,
bitrate_allocation);
EXPECT_EQ(encoder_->current_params_.framerate, framerate);
}
};
const uint32_t kBitrate =
@ -388,40 +477,69 @@ void VP9VaapiVideoEncoderDelegateTest::UpdateRatesTest(
*kDefaultVideoEncodeAcceleratorConfig.initial_framerate;
// Call UpdateRates before Encode.
update_rates_and_encode(
true, GetDefaultVideoBitrateAllocation(num_temporal_layers, kBitrate / 2),
true,
GetDefaultVideoBitrateAllocation(num_spatial_layers, num_temporal_layers,
kBitrate / 2),
kFramerate);
// Bitrate change only.
update_rates_and_encode(
false, GetDefaultVideoBitrateAllocation(num_temporal_layers, kBitrate),
false,
GetDefaultVideoBitrateAllocation(num_spatial_layers, num_temporal_layers,
kBitrate),
kFramerate);
// Framerate change only.
update_rates_and_encode(
false, GetDefaultVideoBitrateAllocation(num_temporal_layers, kBitrate),
false,
GetDefaultVideoBitrateAllocation(num_spatial_layers, num_temporal_layers,
kBitrate),
kFramerate + 2);
// Bitrate + Frame changes.
update_rates_and_encode(
false,
GetDefaultVideoBitrateAllocation(num_temporal_layers, kBitrate * 3 / 4),
GetDefaultVideoBitrateAllocation(num_spatial_layers, num_temporal_layers,
kBitrate * 3 / 4),
kFramerate - 5);
}
struct VP9VaapiVideoEncoderDelegateTestParam {
VP9VaapiVideoEncoderDelegateTest::BitrateControl bitrate_control;
size_t num_spatial_layers;
size_t num_temporal_layers;
} kTestCasesForVP9VaapiVideoEncoderDelegateTest[] = {
// {VP9VaapiVideoEncoderDelegateTest::BitrateControl, num_spatial_layers,
// num_temporal_layers}
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
1u},
1u, 1u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
2u},
1u, 2u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
3u},
1u, 3u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
2u, 1u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
2u, 2u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
2u, 3u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
3u, 1u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
3u, 2u},
{VP9VaapiVideoEncoderDelegateTest::BitrateControl::
kConstantQuantizationParameter,
3u, 3u},
};
TEST_P(VP9VaapiVideoEncoderDelegateTest, Initialize) {
InitializeVP9VaapiVideoEncoderDelegate(GetParam().bitrate_control,
GetParam().num_spatial_layers,
GetParam().num_temporal_layers);
}
@ -430,18 +548,24 @@ TEST_P(VP9VaapiVideoEncoderDelegateTest, EncodeWithSoftwareBitrateControl) {
if (bitrate_control != BitrateControl::kConstantQuantizationParameter)
GTEST_SKIP() << "Test only for with software bitrate control";
const size_t num_spatial_layers = GetParam().num_spatial_layers;
const size_t num_temporal_layers = GetParam().num_temporal_layers;
InitializeVP9VaapiVideoEncoderDelegate(bitrate_control, num_temporal_layers);
InitializeVP9VaapiVideoEncoderDelegate(bitrate_control, num_spatial_layers,
num_temporal_layers);
constexpr size_t kEncodeFrames = 20;
for (size_t i = 0; i < kEncodeFrames; i++) {
const bool is_keyframe = i == 0;
std::array<bool, kVp9NumRefsPerFrame> ref_frames_used;
absl::optional<uint8_t> temporal_layer_id;
GetTemporalLayer(is_keyframe, i, num_temporal_layers, &ref_frames_used,
&temporal_layer_id);
EncodeConstantQuantizationParameterSequence(is_keyframe, ref_frames_used,
temporal_layer_id);
for (size_t frame_num = 0; frame_num < kEncodeFrames; ++frame_num) {
for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
const bool is_keyframe = (frame_num == 0 && sid == 0);
std::array<bool, kVp9NumRefsPerFrame> ref_frames_used;
absl::optional<uint8_t> temporal_layer_id;
GetTemporalLayer(is_keyframe, frame_num, num_spatial_layers,
num_temporal_layers, &ref_frames_used,
&temporal_layer_id);
EncodeConstantQuantizationParameterSequence(
is_keyframe, num_spatial_layers, ref_frames_used, temporal_layer_id,
sid);
}
}
}
@ -451,30 +575,40 @@ TEST_P(VP9VaapiVideoEncoderDelegateTest,
if (bitrate_control != BitrateControl::kConstantQuantizationParameter)
GTEST_SKIP() << "Test only for with software bitrate control";
const size_t num_spatial_layers = GetParam().num_spatial_layers;
const size_t num_temporal_layers = GetParam().num_temporal_layers;
InitializeVP9VaapiVideoEncoderDelegate(bitrate_control, num_temporal_layers);
InitializeVP9VaapiVideoEncoderDelegate(bitrate_control, num_spatial_layers,
num_temporal_layers);
constexpr size_t kNumKeyFrames = 3;
constexpr size_t kKeyFrameInterval = 20;
for (size_t j = 0; j < kNumKeyFrames; j++) {
for (size_t i = 0; i < kKeyFrameInterval; i++) {
const bool is_keyframe = i == 0;
std::array<bool, kVp9NumRefsPerFrame> ref_frames_used;
absl::optional<uint8_t> temporal_layer_id;
GetTemporalLayer(is_keyframe, i, num_temporal_layers, &ref_frames_used,
&temporal_layer_id);
EncodeConstantQuantizationParameterSequence(is_keyframe, ref_frames_used,
temporal_layer_id);
for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
const bool keyframe = (i == 0 && sid == 0);
std::array<bool, kVp9NumRefsPerFrame> ref_frames_used;
absl::optional<uint8_t> temporal_layer_id;
GetTemporalLayer(keyframe, i, num_spatial_layers, num_temporal_layers,
&ref_frames_used, &temporal_layer_id);
EncodeConstantQuantizationParameterSequence(
keyframe, num_spatial_layers, ref_frames_used, temporal_layer_id,
sid);
}
}
}
}
TEST_P(VP9VaapiVideoEncoderDelegateTest, UpdateRates) {
const auto& bitrate_control = GetParam().bitrate_control;
const size_t num_spatial_layers = GetParam().num_spatial_layers;
const size_t num_temporal_layers = GetParam().num_temporal_layers;
InitializeVP9VaapiVideoEncoderDelegate(bitrate_control, num_temporal_layers);
UpdateRatesTest(bitrate_control, num_temporal_layers);
InitializeVP9VaapiVideoEncoderDelegate(bitrate_control, num_spatial_layers,
num_temporal_layers);
UpdateRatesTest(bitrate_control, num_spatial_layers, num_temporal_layers);
}
// TODO(crbug.com/1186051): Add the test case to activate and deactivate spatial
// layers.
INSTANTIATE_TEST_SUITE_P(
,
VP9VaapiVideoEncoderDelegateTest,