Move the QP scaling thresholds to the relevant encoders.

Also provide a new set of thresholds for the VideoToolbox encoder. The new thresholds were experimentally determined to work well on the iPhone 6S, and also adequately on the iPhone 5S.

BUG=webrtc:5678

Review-Url: https://codereview.webrtc.org/2309743002
Cr-Commit-Position: refs/heads/master@{#14420}
This commit is contained in:
kthelgason
2016-09-28 08:17:43 -07:00
committed by Commit bot
parent e75f204b06
commit 478681e1e6
6 changed files with 52 additions and 46 deletions

View File

@ -395,16 +395,9 @@ int32_t MediaCodecVideoEncoder::InitEncode(
ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled"); ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled");
if (scale_) { if (scale_) {
if (codecType_ == kVideoCodecVP8) { if (codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecH264) {
quality_scaler_.Init( quality_scaler_.Init(codecType_, codec_settings->startBitrate,
QualityScaler::kLowVp8QpThreshold, QualityScaler::kBadVp8QpThreshold, codec_settings->width, codec_settings->height,
codec_settings->startBitrate, codec_settings->width,
codec_settings->height, codec_settings->maxFramerate);
} else if (codecType_ == kVideoCodecH264) {
quality_scaler_.Init(QualityScaler::kLowH264QpThreshold,
QualityScaler::kBadH264QpThreshold,
codec_settings->startBitrate, codec_settings->width,
codec_settings->height,
codec_settings->maxFramerate); codec_settings->maxFramerate);
} else { } else {
// When adding codec support to additional hardware codecs, also configure // When adding codec support to additional hardware codecs, also configure

View File

@ -213,10 +213,9 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
return WEBRTC_VIDEO_CODEC_ERROR; return WEBRTC_VIDEO_CODEC_ERROR;
} }
// TODO(pbos): Base init params on these values before submitting. // TODO(pbos): Base init params on these values before submitting.
quality_scaler_.Init(QualityScaler::kLowH264QpThreshold, quality_scaler_.Init(codec_settings_.codecType, codec_settings_.startBitrate,
QualityScaler::kBadH264QpThreshold, codec_settings_.width, codec_settings_.height,
codec_settings_.startBitrate, codec_settings_.width, codec_settings_.maxFramerate);
codec_settings_.height, codec_settings_.maxFramerate);
int video_format = EVideoFormatType::videoFormatI420; int video_format = EVideoFormatType::videoFormatI420;
openh264_encoder_->SetOption(ENCODER_OPTION_DATAFORMAT, openh264_encoder_->SetOption(ENCODER_OPTION_DATAFORMAT,
&video_format); &video_format);

View File

@ -33,6 +33,10 @@ namespace internal {
// kVTCompressionPropertyKey_AverageBitRate. The data rate limit is set higher // kVTCompressionPropertyKey_AverageBitRate. The data rate limit is set higher
// than the average bit rate to avoid undershooting the target. // than the average bit rate to avoid undershooting the target.
const float kLimitToAverageBitRateFactor = 1.5f; const float kLimitToAverageBitRateFactor = 1.5f;
// These thresholds deviate from the default h264 QP thresholds, as they
// have been found to work better on devices that support VideoToolbox
const int kLowH264QpThreshold = 28;
const int kHighH264QpThreshold = 39;
// Convenience function for creating a dictionary. // Convenience function for creating a dictionary.
inline CFDictionaryRef CreateCFDictionary(CFTypeRef* keys, inline CFDictionaryRef CreateCFDictionary(CFTypeRef* keys,
@ -232,8 +236,8 @@ int H264VideoToolboxEncoder::InitEncode(const VideoCodec* codec_settings,
RTC_DCHECK_EQ(codec_settings->codecType, kVideoCodecH264); RTC_DCHECK_EQ(codec_settings->codecType, kVideoCodecH264);
{ {
rtc::CritScope lock(&quality_scaler_crit_); rtc::CritScope lock(&quality_scaler_crit_);
quality_scaler_.Init(QualityScaler::kLowH264QpThreshold, quality_scaler_.Init(internal::kLowH264QpThreshold,
QualityScaler::kBadH264QpThreshold, internal::kHighH264QpThreshold,
codec_settings->startBitrate, codec_settings->width, codec_settings->startBitrate, codec_settings->width,
codec_settings->height, codec_settings->maxFramerate); codec_settings->height, codec_settings->maxFramerate);
QualityScaler::Resolution res = quality_scaler_.GetScaledResolution(); QualityScaler::Resolution res = quality_scaler_.GetScaledResolution();

View File

@ -562,9 +562,8 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
} }
rps_.Init(); rps_.Init();
quality_scaler_.Init(QualityScaler::kLowVp8QpThreshold, quality_scaler_.Init(codec_.codecType, codec_.startBitrate, codec_.width,
QualityScaler::kBadVp8QpThreshold, codec_.startBitrate, codec_.height, codec_.maxFramerate);
codec_.width, codec_.height, codec_.maxFramerate);
// Only apply scaling to improve for single-layer streams. The scaling metrics // Only apply scaling to improve for single-layer streams. The scaling metrics
// use frame drops as a signal and is only applicable when we drop frames. // use frame drops as a signal and is only applicable when we drop frames.

View File

@ -14,6 +14,8 @@
#include <algorithm> #include <algorithm>
#include "webrtc/base/checks.h"
// TODO(kthelgason): Some versions of Android have issues with log2. // TODO(kthelgason): Some versions of Android have issues with log2.
// See https://code.google.com/p/android/issues/detail?id=212634 for details // See https://code.google.com/p/android/issues/detail?id=212634 for details
#if defined(WEBRTC_ANDROID) #if defined(WEBRTC_ANDROID)
@ -38,42 +40,54 @@ static const int kVgaBitrateThresholdKbps = 500;
static const int kVgaNumPixels = 700 * 500; // 640x480 static const int kVgaNumPixels = 700 * 500; // 640x480
static const int kQvgaBitrateThresholdKbps = 250; static const int kQvgaBitrateThresholdKbps = 250;
static const int kQvgaNumPixels = 400 * 300; // 320x240 static const int kQvgaNumPixels = 400 * 300; // 320x240
// QP scaling threshold defaults:
static const int kLowH264QpThreshold = 24;
static const int kHighH264QpThreshold = 37;
// QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 127] and not the user-level range of [0,63].
static const int kLowVp8QpThreshold = 29;
static const int kHighVp8QpThreshold = 95;
} // namespace } // namespace
// QP thresholds are chosen to be high enough to be hit in practice when quality
// is good, but also low enough to not cause a flip-flop behavior (e.g. going up
// in resolution shouldn't give so bad quality that we should go back down).
const int QualityScaler::kLowVp8QpThreshold = 29;
const int QualityScaler::kBadVp8QpThreshold = 95;
#if defined(WEBRTC_IOS)
const int QualityScaler::kLowH264QpThreshold = 32;
const int QualityScaler::kBadH264QpThreshold = 42;
#else
const int QualityScaler::kLowH264QpThreshold = 24;
const int QualityScaler::kBadH264QpThreshold = 37;
#endif
// Default values. Should immediately get set to something more sensible. // Default values. Should immediately get set to something more sensible.
QualityScaler::QualityScaler() QualityScaler::QualityScaler()
: average_qp_(kMeasureSecondsUpscale * 30), : average_qp_(kMeasureSecondsUpscale * 30),
framedrop_percent_(kMeasureSecondsUpscale * 30), framedrop_percent_(kMeasureSecondsUpscale * 30),
low_qp_threshold_(-1) {} low_qp_threshold_(-1) {}
void QualityScaler::Init(VideoCodecType codec_type,
int initial_bitrate_kbps,
int width,
int height,
int fps) {
int low = -1, high = -1;
switch (codec_type) {
case kVideoCodecH264:
low = kLowH264QpThreshold;
high = kHighH264QpThreshold;
break;
case kVideoCodecVP8:
low = kLowVp8QpThreshold;
high = kHighVp8QpThreshold;
break;
default:
RTC_NOTREACHED() << "Invalid codec type for QualityScaler.";
}
Init(low, high, initial_bitrate_kbps, width, height, fps);
}
void QualityScaler::Init(int low_qp_threshold, void QualityScaler::Init(int low_qp_threshold,
int high_qp_threshold, int high_qp_threshold,
int initial_bitrate_kbps, int initial_bitrate_kbps,
int width, int width,
int height, int height,
int fps) { int fps) {
ClearSamples();
low_qp_threshold_ = low_qp_threshold; low_qp_threshold_ = low_qp_threshold;
high_qp_threshold_ = high_qp_threshold; high_qp_threshold_ = high_qp_threshold;
downscale_shift_ = 0; downscale_shift_ = 0;
fast_rampup_ = true; fast_rampup_ = true;
ClearSamples();
ReportFramerate(fps); ReportFramerate(fps);
const int init_width = width; const int init_width = width;

View File

@ -11,6 +11,7 @@
#ifndef WEBRTC_MODULES_VIDEO_CODING_UTILITY_QUALITY_SCALER_H_ #ifndef WEBRTC_MODULES_VIDEO_CODING_UTILITY_QUALITY_SCALER_H_
#define WEBRTC_MODULES_VIDEO_CODING_UTILITY_QUALITY_SCALER_H_ #define WEBRTC_MODULES_VIDEO_CODING_UTILITY_QUALITY_SCALER_H_
#include "webrtc/common_types.h"
#include "webrtc/common_video/include/i420_buffer_pool.h" #include "webrtc/common_video/include/i420_buffer_pool.h"
#include "webrtc/modules/video_coding/utility/moving_average.h" #include "webrtc/modules/video_coding/utility/moving_average.h"
@ -23,6 +24,11 @@ class QualityScaler {
}; };
QualityScaler(); QualityScaler();
void Init(VideoCodecType codec_type,
int initial_bitrate_kbps,
int width,
int height,
int fps);
void Init(int low_qp_threshold, void Init(int low_qp_threshold,
int high_qp_threshold, int high_qp_threshold,
int initial_bitrate_kbps, int initial_bitrate_kbps,
@ -38,15 +44,6 @@ class QualityScaler {
const rtc::scoped_refptr<VideoFrameBuffer>& frame); const rtc::scoped_refptr<VideoFrameBuffer>& frame);
int downscale_shift() const { return downscale_shift_; } int downscale_shift() const { return downscale_shift_; }
// QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 127] and not the user-level range of [0,63].
static const int kLowVp8QpThreshold;
static const int kBadVp8QpThreshold;
// H264 QP is in the range [0, 51].
static const int kLowH264QpThreshold;
static const int kBadH264QpThreshold;
private: private:
void ClearSamples(); void ClearSamples();
void ScaleUp(); void ScaleUp();