Merge remote tracking branch 'upstream-master'
Bug: 153469641 Test: run cuttlefish locally Change-Id: Ida3bfe62ef5c6549278f4c155a1f690b008e9b9d
This commit is contained in:
@ -25,6 +25,7 @@
|
||||
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h"
|
||||
#include "modules/video_coding/utility/vp9_uncompressed_header_parser.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/experiments/rate_control_settings.h"
|
||||
#include "rtc_base/keep_ref_until_done.h"
|
||||
@ -45,14 +46,21 @@ namespace {
|
||||
uint8_t kRefBufIdx[4] = {0, 0, 0, 1};
|
||||
uint8_t kUpdBufIdx[4] = {0, 0, 1, 0};
|
||||
|
||||
int kMaxNumTiles4kVideo = 8;
|
||||
|
||||
// Maximum allowed PID difference for differnet per-layer frame-rate case.
|
||||
const int kMaxAllowedPidDiff = 30;
|
||||
|
||||
constexpr double kLowRateFactor = 1.0;
|
||||
constexpr double kHighRateFactor = 2.0;
|
||||
|
||||
// TODO(ilink): Tune these thresholds further.
|
||||
// Selected using ConverenceMotion_1280_720_50.yuv clip.
|
||||
// No toggling observed on any link capacity from 100-2000kbps.
|
||||
// HD was reached consistently when link capacity was 1500kbps.
|
||||
// Set resolutions are a bit more conservative than svc_config.cc sets, e.g.
|
||||
// for 300kbps resolution converged to 270p instead of 360p.
|
||||
constexpr int kLowVp9QpThreshold = 149;
|
||||
constexpr int kHighVp9QpThreshold = 205;
|
||||
|
||||
// These settings correspond to the settings in vpx_codec_enc_cfg.
|
||||
struct Vp9RateSettings {
|
||||
uint32_t rc_undershoot_pct;
|
||||
@ -249,6 +257,8 @@ VP9EncoderImpl::VP9EncoderImpl(const cricket::VideoCodec& codec)
|
||||
"WebRTC-VP9VariableFramerateScreenshare")),
|
||||
variable_framerate_controller_(
|
||||
variable_framerate_experiment_.framerate_limit),
|
||||
quality_scaler_experiment_(
|
||||
ParseQualityScalerConfig("WebRTC-VP9QualityScaler")),
|
||||
num_steady_state_frames_(0),
|
||||
config_changed_(true) {
|
||||
codec_ = {};
|
||||
@ -399,7 +409,6 @@ bool VP9EncoderImpl::SetSvcRates(
|
||||
expect_no_more_active_layers = seen_active_layer;
|
||||
}
|
||||
}
|
||||
RTC_DCHECK_GT(num_active_spatial_layers_, 0);
|
||||
|
||||
if (higher_layers_enabled && !force_key_frame_) {
|
||||
// Prohibit drop of all layers for the next frame, so newly enabled
|
||||
@ -517,6 +526,11 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst,
|
||||
config_->g_profile = 0;
|
||||
config_->g_input_bit_depth = 8;
|
||||
break;
|
||||
case VP9Profile::kProfile1:
|
||||
// Encoding of profile 1 is not implemented. It would require extended
|
||||
// support for I444, I422, and I440 buffers.
|
||||
RTC_NOTREACHED();
|
||||
break;
|
||||
case VP9Profile::kProfile2:
|
||||
img_fmt = VPX_IMG_FMT_I42016;
|
||||
bits_for_storage = 16;
|
||||
@ -562,7 +576,13 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst,
|
||||
// put some key-frames at will even in VPX_KF_DISABLED kf_mode.
|
||||
config_->kf_max_dist = inst->VP9().keyFrameInterval;
|
||||
config_->kf_min_dist = config_->kf_max_dist;
|
||||
config_->rc_resize_allowed = inst->VP9().automaticResizeOn ? 1 : 0;
|
||||
if (quality_scaler_experiment_.enabled) {
|
||||
// In that experiment webrtc wide quality scaler is used instead of libvpx
|
||||
// internal scaler.
|
||||
config_->rc_resize_allowed = 0;
|
||||
} else {
|
||||
config_->rc_resize_allowed = inst->VP9().automaticResizeOn ? 1 : 0;
|
||||
}
|
||||
// Determine number of threads based on the image size and #cores.
|
||||
config_->g_threads =
|
||||
NumberOfThreads(config_->g_w, config_->g_h, settings.number_of_cores);
|
||||
@ -587,13 +607,6 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst,
|
||||
(num_spatial_layers_ > 1 &&
|
||||
codec_.mode == VideoCodecMode::kScreensharing) ||
|
||||
inter_layer_pred_ == InterLayerPredMode::kOn;
|
||||
// TODO(ilnik): Remove this workaround once external reference control works
|
||||
// nicely with simulcast SVC mode.
|
||||
// Simlucast SVC mode is currently only used in some tests and is impossible
|
||||
// to trigger for users without using some field trials.
|
||||
if (inter_layer_pred_ == InterLayerPredMode::kOff) {
|
||||
external_ref_control_ = false;
|
||||
}
|
||||
|
||||
if (num_temporal_layers_ == 1) {
|
||||
gof_.SetGofInfoVP9(kTemporalStructureMode1);
|
||||
@ -987,6 +1000,10 @@ int VP9EncoderImpl::Encode(const VideoFrame& input_image,
|
||||
raw_->stride[VPX_PLANE_V] = i420_buffer->StrideV();
|
||||
break;
|
||||
}
|
||||
case VP9Profile::kProfile1: {
|
||||
RTC_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
case VP9Profile::kProfile2: {
|
||||
// We can inject kI010 frames directly for encode. All other formats
|
||||
// should be converted to it.
|
||||
@ -1560,7 +1577,12 @@ VideoEncoder::EncoderInfo VP9EncoderImpl::GetEncoderInfo() const {
|
||||
EncoderInfo info;
|
||||
info.supports_native_handle = false;
|
||||
info.implementation_name = "libvpx";
|
||||
info.scaling_settings = VideoEncoder::ScalingSettings::kOff;
|
||||
if (quality_scaler_experiment_.enabled) {
|
||||
info.scaling_settings = VideoEncoder::ScalingSettings(
|
||||
quality_scaler_experiment_.low_qp, quality_scaler_experiment_.high_qp);
|
||||
} else {
|
||||
info.scaling_settings = VideoEncoder::ScalingSettings::kOff;
|
||||
}
|
||||
info.has_trusted_rate_controller = trusted_rate_controller_;
|
||||
info.is_hardware_accelerated = false;
|
||||
info.has_internal_source = false;
|
||||
@ -1633,6 +1655,24 @@ VP9EncoderImpl::ParseVariableFramerateConfig(std::string group_name) {
|
||||
return config;
|
||||
}
|
||||
|
||||
// static
|
||||
VP9EncoderImpl::QualityScalerExperiment
|
||||
VP9EncoderImpl::ParseQualityScalerConfig(std::string group_name) {
|
||||
FieldTrialFlag disabled = FieldTrialFlag("Disabled");
|
||||
FieldTrialParameter<int> low_qp("low_qp", kLowVp9QpThreshold);
|
||||
FieldTrialParameter<int> high_qp("hihg_qp", kHighVp9QpThreshold);
|
||||
ParseFieldTrial({&disabled, &low_qp, &high_qp},
|
||||
field_trial::FindFullName(group_name));
|
||||
QualityScalerExperiment config;
|
||||
config.enabled = !disabled.Get();
|
||||
RTC_LOG(LS_INFO) << "Webrtc quality scaler for vp9 is "
|
||||
<< (config.enabled ? "enabled." : "disabled");
|
||||
config.low_qp = low_qp.Get();
|
||||
config.high_qp = high_qp.Get();
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
VP9DecoderImpl::VP9DecoderImpl()
|
||||
: decode_complete_callback_(nullptr),
|
||||
inited_(false),
|
||||
@ -1672,14 +1712,32 @@ int VP9DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) {
|
||||
// errors earlier than the multi-threads version.
|
||||
// - Make peak CPU usage under control (not depending on input)
|
||||
cfg.threads = 1;
|
||||
(void)kMaxNumTiles4kVideo; // unused
|
||||
#else
|
||||
// We want to use multithreading when decoding high resolution videos. But,
|
||||
// since we don't know resolution of input stream at this stage, we always
|
||||
// enable it.
|
||||
cfg.threads = std::min(number_of_cores, kMaxNumTiles4kVideo);
|
||||
if (!inst) {
|
||||
// No config provided - don't know resolution to decode yet.
|
||||
// Set thread count to one in the meantime.
|
||||
cfg.threads = 1;
|
||||
} else {
|
||||
// We want to use multithreading when decoding high resolution videos. But
|
||||
// not too many in order to avoid overhead when many stream are decoded
|
||||
// concurrently.
|
||||
// Set 2 thread as target for 1280x720 pixel count, and then scale up
|
||||
// linearly from there - but cap at physical core count.
|
||||
// For common resolutions this results in:
|
||||
// 1 for 360p
|
||||
// 2 for 720p
|
||||
// 4 for 1080p
|
||||
// 8 for 1440p
|
||||
// 18 for 4K
|
||||
int num_threads =
|
||||
std::max(1, 2 * (inst->width * inst->height) / (1280 * 720));
|
||||
cfg.threads = std::min(number_of_cores, num_threads);
|
||||
current_codec_ = *inst;
|
||||
}
|
||||
#endif
|
||||
|
||||
num_cores_ = number_of_cores;
|
||||
|
||||
vpx_codec_flags_t flags = 0;
|
||||
if (vpx_codec_dec_init(decoder_, vpx_codec_vp9_dx(), &cfg, flags)) {
|
||||
return WEBRTC_VIDEO_CODEC_MEMORY;
|
||||
@ -1697,6 +1755,15 @@ int VP9DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) {
|
||||
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
vpx_codec_err_t status =
|
||||
vpx_codec_control(decoder_, VP9D_SET_LOOP_FILTER_OPT, 1);
|
||||
if (status != VPX_CODEC_OK) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to enable VP9D_SET_LOOP_FILTER_OPT. "
|
||||
<< vpx_codec_error(decoder_);
|
||||
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
||||
}
|
||||
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
@ -1709,6 +1776,29 @@ int VP9DecoderImpl::Decode(const EncodedImage& input_image,
|
||||
if (decode_complete_callback_ == nullptr) {
|
||||
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
||||
}
|
||||
|
||||
if (input_image._frameType == VideoFrameType::kVideoFrameKey) {
|
||||
absl::optional<vp9::FrameInfo> frame_info =
|
||||
vp9::ParseIntraFrameInfo(input_image.data(), input_image.size());
|
||||
if (frame_info) {
|
||||
if (frame_info->frame_width != current_codec_.width ||
|
||||
frame_info->frame_height != current_codec_.height) {
|
||||
// Resolution has changed, tear down and re-init a new decoder in
|
||||
// order to get correct sizing.
|
||||
Release();
|
||||
current_codec_.width = frame_info->frame_width;
|
||||
current_codec_.height = frame_info->frame_height;
|
||||
int reinit_status = InitDecode(¤t_codec_, num_cores_);
|
||||
if (reinit_status != WEBRTC_VIDEO_CODEC_OK) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to re-init decoder.";
|
||||
return reinit_status;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RTC_LOG(LS_WARNING) << "Failed to parse VP9 header from key-frame.";
|
||||
}
|
||||
}
|
||||
|
||||
// Always start with a complete key frame.
|
||||
if (key_frame_required_) {
|
||||
if (input_image._frameType != VideoFrameType::kVideoFrameKey)
|
||||
|
||||
Reference in New Issue
Block a user