Updates to resolution adpatation:
-moved calculation of selected frame size & frame rate to qm_select class. -various updates to qm_select class (switch to 1/2 from 2 stages of 3/4, include native frame rate for going up temporal, favor spatial action for temporal layers,..). -updates to unittest. Review URL: https://webrtc-codereview.appspot.com/450008 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1914 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
a496b03c78
commit
e22d81ce4d
@ -24,8 +24,6 @@ _maxBitRate(0),
|
|||||||
_sendCodecType(kVideoCodecUnknown),
|
_sendCodecType(kVideoCodecUnknown),
|
||||||
_codecWidth(0),
|
_codecWidth(0),
|
||||||
_codecHeight(0),
|
_codecHeight(0),
|
||||||
_initCodecWidth(0),
|
|
||||||
_initCodecHeight(0),
|
|
||||||
_userFrameRate(0),
|
_userFrameRate(0),
|
||||||
_packetLossEnc(0),
|
_packetLossEnc(0),
|
||||||
_fractionLost(0),
|
_fractionLost(0),
|
||||||
@ -286,8 +284,6 @@ VCMMediaOptimization::SetEncodingData(VideoCodecType sendCodecType,
|
|||||||
_userFrameRate = static_cast<float>(frameRate);
|
_userFrameRate = static_cast<float>(frameRate);
|
||||||
_codecWidth = width;
|
_codecWidth = width;
|
||||||
_codecHeight = height;
|
_codecHeight = height;
|
||||||
_initCodecWidth = width;
|
|
||||||
_initCodecHeight = height;
|
|
||||||
_numLayers = (numLayers <= 1) ? 1 : numLayers; // Can also be zero.
|
_numLayers = (numLayers <= 1) ? 1 : numLayers; // Can also be zero.
|
||||||
WebRtc_Word32 ret = VCM_OK;
|
WebRtc_Word32 ret = VCM_OK;
|
||||||
ret = _qmResolution->Initialize((float)_targetBitRate, _userFrameRate,
|
ret = _qmResolution->Initialize((float)_targetBitRate, _userFrameRate,
|
||||||
@ -577,41 +573,39 @@ VCMMediaOptimization::checkStatusForQMchange()
|
|||||||
|
|
||||||
bool VCMMediaOptimization::QMUpdate(VCMResolutionScale* qm) {
|
bool VCMMediaOptimization::QMUpdate(VCMResolutionScale* qm) {
|
||||||
// Check for no change
|
// Check for no change
|
||||||
if (!qm->change_resolution) {
|
if (!qm->change_resolution_spatial && !qm->change_resolution_temporal) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for change in frame rate.
|
// Check for change in frame rate.
|
||||||
if (qm->temporal_fact != 1.0f) {
|
if (qm->change_resolution_temporal) {
|
||||||
_incomingFrameRate = _incomingFrameRate / qm->temporal_fact + 0.5f;
|
_incomingFrameRate = qm->frame_rate;
|
||||||
|
// Reset frame rate estimate.
|
||||||
memset(_incomingFrameTimes, -1, sizeof(_incomingFrameTimes));
|
memset(_incomingFrameTimes, -1, sizeof(_incomingFrameTimes));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for change in frame size.
|
// Check for change in frame size.
|
||||||
if (qm->spatial_height_fact != 1.0 || qm->spatial_width_fact != 1.0) {
|
if (qm->change_resolution_spatial) {
|
||||||
_codecWidth = static_cast<uint16_t>(_codecWidth /
|
_codecWidth = qm->codec_width;
|
||||||
qm->spatial_width_fact);
|
_codecHeight = qm->codec_height;
|
||||||
_codecHeight = static_cast<uint16_t>(_codecHeight /
|
|
||||||
qm->spatial_height_fact);
|
|
||||||
// New frame sizes should not exceed original size from SetEncodingData().
|
|
||||||
assert(_codecWidth <= _initCodecWidth);
|
|
||||||
assert(_codecHeight <= _initCodecHeight);
|
|
||||||
// Check that new frame sizes are multiples of two.
|
|
||||||
assert(_codecWidth % 2 == 0);
|
|
||||||
assert(_codecHeight % 2 == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, _id,
|
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, _id,
|
||||||
"Quality Mode Update: W = %d, H = %d, FR = %f",
|
"Resolution change from QM select: W = %d, H = %d, FR = %f",
|
||||||
_codecWidth, _codecHeight, _incomingFrameRate);
|
qm->codec_width, qm->codec_height, qm->frame_rate);
|
||||||
|
|
||||||
// Update VPM with new target frame rate and size
|
// Update VPM with new target frame rate and frame size.
|
||||||
_videoQMSettingsCallback->SetVideoQMSettings(_incomingFrameRate,
|
// Note: use |qm->frame_rate| instead of |_incomingFrameRate| for updating
|
||||||
|
// target frame rate in VPM frame dropper. The quantity |_incomingFrameRate|
|
||||||
|
// will vary/fluctuate, and since we don't want to change the state of the
|
||||||
|
// VPM frame dropper, unless a temporal action was selected, we use the
|
||||||
|
// quantity |qm->frame_rate| for updating.
|
||||||
|
_videoQMSettingsCallback->SetVideoQMSettings(qm->frame_rate,
|
||||||
_codecWidth,
|
_codecWidth,
|
||||||
_codecHeight);
|
_codecHeight);
|
||||||
|
_content->UpdateFrameRate(qm->frame_rate);
|
||||||
_content->UpdateFrameRate(_incomingFrameRate);
|
_qmResolution->UpdateCodecParameters(qm->frame_rate, _codecWidth,
|
||||||
_qmResolution->UpdateCodecFrameSize(_codecWidth, _codecHeight);
|
_codecHeight);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,8 +168,6 @@ private:
|
|||||||
VideoCodecType _sendCodecType;
|
VideoCodecType _sendCodecType;
|
||||||
WebRtc_UWord16 _codecWidth;
|
WebRtc_UWord16 _codecWidth;
|
||||||
WebRtc_UWord16 _codecHeight;
|
WebRtc_UWord16 _codecHeight;
|
||||||
WebRtc_UWord16 _initCodecWidth;
|
|
||||||
WebRtc_UWord16 _initCodecHeight;
|
|
||||||
float _userFrameRate;
|
float _userFrameRate;
|
||||||
|
|
||||||
VCMFrameDropper* _frameDropper;
|
VCMFrameDropper* _frameDropper;
|
||||||
|
@ -26,9 +26,11 @@ VCMQmMethod::VCMQmMethod()
|
|||||||
: content_metrics_(NULL),
|
: content_metrics_(NULL),
|
||||||
width_(0),
|
width_(0),
|
||||||
height_(0),
|
height_(0),
|
||||||
|
user_frame_rate_(0.0f),
|
||||||
native_width_(0),
|
native_width_(0),
|
||||||
native_height_(0),
|
native_height_(0),
|
||||||
framerate_level_(kDefault),
|
native_frame_rate_(0.0f),
|
||||||
|
framerate_level_(kFrameRateHigh),
|
||||||
init_(false) {
|
init_(false) {
|
||||||
ResetQM();
|
ResetQM();
|
||||||
}
|
}
|
||||||
@ -134,13 +136,15 @@ ImageType VCMQmMethod::FindClosestImageType(uint16_t width, uint16_t height) {
|
|||||||
return static_cast<ImageType>(isel);
|
return static_cast<ImageType>(isel);
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelClass VCMQmMethod::FrameRateLevel(float avg_framerate) {
|
FrameRateLevelClass VCMQmMethod::FrameRateLevel(float avg_framerate) {
|
||||||
if (avg_framerate < kLowFrameRate) {
|
if (avg_framerate < kLowFrameRate) {
|
||||||
return kLow;
|
return kFrameRateLow;
|
||||||
} else if (avg_framerate > kHighFrameRate) {
|
} else if (avg_framerate < kMiddleFrameRate) {
|
||||||
return kHigh;
|
return kFrameRateMiddle1;
|
||||||
|
} else if (avg_framerate < kHighFrameRate) {
|
||||||
|
return kFrameRateMiddle2;
|
||||||
} else {
|
} else {
|
||||||
return kDefault;
|
return kFrameRateHigh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +183,6 @@ void VCMQmResolution::ResetDownSamplingState() {
|
|||||||
|
|
||||||
void VCMQmResolution::Reset() {
|
void VCMQmResolution::Reset() {
|
||||||
target_bitrate_ = 0.0f;
|
target_bitrate_ = 0.0f;
|
||||||
user_framerate_ = 0.0f;
|
|
||||||
incoming_framerate_ = 0.0f;
|
incoming_framerate_ = 0.0f;
|
||||||
buffer_level_ = 0.0f;
|
buffer_level_ = 0.0f;
|
||||||
per_frame_bandwidth_ =0.0f;
|
per_frame_bandwidth_ =0.0f;
|
||||||
@ -212,23 +215,26 @@ int VCMQmResolution::Initialize(float bitrate,
|
|||||||
}
|
}
|
||||||
Reset();
|
Reset();
|
||||||
target_bitrate_ = bitrate;
|
target_bitrate_ = bitrate;
|
||||||
user_framerate_ = user_framerate;
|
|
||||||
incoming_framerate_ = user_framerate;
|
incoming_framerate_ = user_framerate;
|
||||||
UpdateCodecFrameSize(width, height);
|
UpdateCodecParameters(user_framerate, width, height);
|
||||||
native_width_ = width;
|
native_width_ = width;
|
||||||
native_height_ = height;
|
native_height_ = height;
|
||||||
|
native_frame_rate_ = user_framerate;
|
||||||
num_layers_ = num_layers;
|
num_layers_ = num_layers;
|
||||||
// Initial buffer level.
|
// Initial buffer level.
|
||||||
buffer_level_ = kOptBufferLevel * target_bitrate_;
|
buffer_level_ = kOptBufferLevel * target_bitrate_;
|
||||||
// Per-frame bandwidth.
|
// Per-frame bandwidth.
|
||||||
per_frame_bandwidth_ = target_bitrate_ / user_framerate_;
|
per_frame_bandwidth_ = target_bitrate_ / user_framerate;
|
||||||
init_ = true;
|
init_ = true;
|
||||||
return VCM_OK;
|
return VCM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCMQmResolution::UpdateCodecFrameSize(uint16_t width, uint16_t height) {
|
void VCMQmResolution::UpdateCodecParameters(float frame_rate, uint16_t width,
|
||||||
|
uint16_t height) {
|
||||||
width_ = width;
|
width_ = width;
|
||||||
height_ = height;
|
height_ = height;
|
||||||
|
// |user_frame_rate| is the target frame rate for VPM frame dropper.
|
||||||
|
user_frame_rate_ = frame_rate;
|
||||||
image_type_ = GetImageType(width, height);
|
image_type_ = GetImageType(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,11 +262,9 @@ void VCMQmResolution::UpdateRates(float target_bitrate,
|
|||||||
float encoder_sent_rate,
|
float encoder_sent_rate,
|
||||||
float incoming_framerate,
|
float incoming_framerate,
|
||||||
uint8_t packet_loss) {
|
uint8_t packet_loss) {
|
||||||
// Sum the target bitrate and incoming frame rate:
|
// Sum the target bitrate: this is the encoder rate from previous update
|
||||||
// these values are the encoder rates (from previous update ~1sec),
|
// (~1sec), i.e, before the update for next ~1sec.
|
||||||
// i.e, before the update for next ~1sec.
|
|
||||||
sum_target_rate_ += target_bitrate_;
|
sum_target_rate_ += target_bitrate_;
|
||||||
sum_incoming_framerate_ += incoming_framerate_;
|
|
||||||
update_rate_cnt_++;
|
update_rate_cnt_++;
|
||||||
|
|
||||||
// Sum the received (from RTCP reports) packet loss rates.
|
// Sum the received (from RTCP reports) packet loss rates.
|
||||||
@ -281,6 +285,7 @@ void VCMQmResolution::UpdateRates(float target_bitrate,
|
|||||||
// these values are ones the encoder will use for the current/next ~1sec
|
// these values are ones the encoder will use for the current/next ~1sec
|
||||||
target_bitrate_ = target_bitrate;
|
target_bitrate_ = target_bitrate;
|
||||||
incoming_framerate_ = incoming_framerate;
|
incoming_framerate_ = incoming_framerate;
|
||||||
|
sum_incoming_framerate_ += incoming_framerate_;
|
||||||
|
|
||||||
// Update the per_frame_bandwidth:
|
// Update the per_frame_bandwidth:
|
||||||
// this is the per_frame_bw for the current/next ~1sec
|
// this is the per_frame_bw for the current/next ~1sec
|
||||||
@ -296,8 +301,8 @@ void VCMQmResolution::UpdateRates(float target_bitrate,
|
|||||||
|
|
||||||
// In the current version the following constraints are imposed:
|
// In the current version the following constraints are imposed:
|
||||||
// 1) We only allow for one action, either down or up, at a given time.
|
// 1) We only allow for one action, either down or up, at a given time.
|
||||||
// 2) The possible down-sampling actions are: spatial 1/2x1/2, 3/4x3/4;
|
// 2) The possible down-sampling actions are: spatial by 1/2x1/2, 3/4x3/4;
|
||||||
// temporal 1/2 and 2/3.
|
// temporal/frame rate reduction by 1/2 and 2/3.
|
||||||
// 3) The action for going back up is the reverse of last (spatial or temporal)
|
// 3) The action for going back up is the reverse of last (spatial or temporal)
|
||||||
// down-sampling action. The list of down-sampling actions from the
|
// down-sampling action. The list of down-sampling actions from the
|
||||||
// Initialize() state are kept in |down_action_history_|.
|
// Initialize() state are kept in |down_action_history_|.
|
||||||
@ -313,10 +318,6 @@ int VCMQmResolution::SelectResolution(VCMResolutionScale** qm) {
|
|||||||
return VCM_OK;
|
return VCM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default settings: no action.
|
|
||||||
SetDefaultAction();
|
|
||||||
*qm = qm_;
|
|
||||||
|
|
||||||
// Compute content class for selection.
|
// Compute content class for selection.
|
||||||
content_class_ = ComputeContentClass();
|
content_class_ = ComputeContentClass();
|
||||||
|
|
||||||
@ -326,6 +327,10 @@ int VCMQmResolution::SelectResolution(VCMResolutionScale** qm) {
|
|||||||
// Get the encoder state.
|
// Get the encoder state.
|
||||||
ComputeEncoderState();
|
ComputeEncoderState();
|
||||||
|
|
||||||
|
// Default settings: no action.
|
||||||
|
SetDefaultAction();
|
||||||
|
*qm = qm_;
|
||||||
|
|
||||||
// Check for going back up in resolution, if we have had some down-sampling
|
// Check for going back up in resolution, if we have had some down-sampling
|
||||||
// relative to native state in Initialize().
|
// relative to native state in Initialize().
|
||||||
if (down_action_history_[0].spatial != kNoChangeSpatial ||
|
if (down_action_history_[0].spatial != kNoChangeSpatial ||
|
||||||
@ -348,10 +353,14 @@ int VCMQmResolution::SelectResolution(VCMResolutionScale** qm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VCMQmResolution::SetDefaultAction() {
|
void VCMQmResolution::SetDefaultAction() {
|
||||||
|
qm_->codec_width = width_;
|
||||||
|
qm_->codec_height = height_;
|
||||||
|
qm_->frame_rate = user_frame_rate_;
|
||||||
|
qm_->change_resolution_spatial = false;
|
||||||
|
qm_->change_resolution_temporal = false;
|
||||||
qm_->spatial_width_fact = 1.0f;
|
qm_->spatial_width_fact = 1.0f;
|
||||||
qm_->spatial_height_fact = 1.0f;
|
qm_->spatial_height_fact = 1.0f;
|
||||||
qm_->temporal_fact = 1.0f;
|
qm_->temporal_fact = 1.0f;
|
||||||
qm_->change_resolution = false;
|
|
||||||
action_.spatial = kNoChangeSpatial;
|
action_.spatial = kNoChangeSpatial;
|
||||||
action_.temporal = kNoChangeTemporal;
|
action_.temporal = kNoChangeTemporal;
|
||||||
}
|
}
|
||||||
@ -385,7 +394,9 @@ void VCMQmResolution::ComputeRatesForSelection() {
|
|||||||
(1.0 - kWeightRate) * target_bitrate_;
|
(1.0 - kWeightRate) * target_bitrate_;
|
||||||
avg_incoming_framerate_ = kWeightRate * avg_incoming_framerate_ +
|
avg_incoming_framerate_ = kWeightRate * avg_incoming_framerate_ +
|
||||||
(1.0 - kWeightRate) * incoming_framerate_;
|
(1.0 - kWeightRate) * incoming_framerate_;
|
||||||
framerate_level_ = FrameRateLevel(avg_incoming_framerate_);
|
// Use base layer frame rate for temporal layers: this will favor spatial.
|
||||||
|
framerate_level_ = FrameRateLevel(avg_incoming_framerate_ /
|
||||||
|
pow(2, num_layers_ - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCMQmResolution::ComputeEncoderState() {
|
void VCMQmResolution::ComputeEncoderState() {
|
||||||
@ -461,6 +472,7 @@ bool VCMQmResolution::ConditionForGoingUp(float fac_width,
|
|||||||
float scale_fac) {
|
float scale_fac) {
|
||||||
float estimated_transition_rate_up = GetTransitionRate(fac_width, fac_height,
|
float estimated_transition_rate_up = GetTransitionRate(fac_width, fac_height,
|
||||||
fac_temp, scale_fac);
|
fac_temp, scale_fac);
|
||||||
|
|
||||||
// Go back up if:
|
// Go back up if:
|
||||||
// 1) target rate is above threshold and current encoder state is stable, or
|
// 1) target rate is above threshold and current encoder state is stable, or
|
||||||
// 2) encoder state is easy (encoder is significantly under-shooting target).
|
// 2) encoder state is easy (encoder is significantly under-shooting target).
|
||||||
@ -527,11 +539,15 @@ bool VCMQmResolution::GoingDownResolution() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(marpan): If num_layers_ > 1, adjust/favor spatial over temporal ?
|
// Only allow for one action (spatial or temporal) at a given time.
|
||||||
|
assert(action_.temporal == kNoChangeTemporal ||
|
||||||
|
action_.spatial == kNoChangeSpatial);
|
||||||
|
|
||||||
// Adjust cases not captured in tables, mainly based on frame rate.
|
// Adjust cases not captured in tables, mainly based on frame rate.
|
||||||
AdjustAction();
|
AdjustAction();
|
||||||
|
|
||||||
|
ConvertSpatialFractionalToWhole();
|
||||||
|
|
||||||
CheckForEvenFrameSize();
|
CheckForEvenFrameSize();
|
||||||
|
|
||||||
// Update down-sampling state.
|
// Update down-sampling state.
|
||||||
@ -552,8 +568,14 @@ float VCMQmResolution::GetTransitionRate(float fac_width,
|
|||||||
static_cast<uint16_t>(fac_width * width_),
|
static_cast<uint16_t>(fac_width * width_),
|
||||||
static_cast<uint16_t>(fac_height * height_));
|
static_cast<uint16_t>(fac_height * height_));
|
||||||
|
|
||||||
LevelClass framerate_level =
|
FrameRateLevelClass framerate_level =
|
||||||
FrameRateLevel(fac_temp * avg_incoming_framerate_);
|
FrameRateLevel(fac_temp * avg_incoming_framerate_);
|
||||||
|
// If we are checking for going up temporally, and this is the last
|
||||||
|
// temporal action, then use native frame rate.
|
||||||
|
if (down_action_history_[1].temporal == kNoChangeTemporal &&
|
||||||
|
fac_temp > 1.0f) {
|
||||||
|
framerate_level = FrameRateLevel(native_frame_rate_);
|
||||||
|
}
|
||||||
|
|
||||||
// The maximum allowed rate below which down-sampling is allowed:
|
// The maximum allowed rate below which down-sampling is allowed:
|
||||||
// Nominal values based on image format (frame size and frame rate).
|
// Nominal values based on image format (frame size and frame rate).
|
||||||
@ -570,7 +592,6 @@ float VCMQmResolution::GetTransitionRate(float fac_width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VCMQmResolution::UpdateDownsamplingState(UpDownAction up_down) {
|
void VCMQmResolution::UpdateDownsamplingState(UpDownAction up_down) {
|
||||||
qm_->change_resolution = true;
|
|
||||||
if (up_down == kUpResolution) {
|
if (up_down == kUpResolution) {
|
||||||
qm_->spatial_width_fact = 1.0f / kFactorWidthSpatial[action_.spatial];
|
qm_->spatial_width_fact = 1.0f / kFactorWidthSpatial[action_.spatial];
|
||||||
qm_->spatial_height_fact = 1.0f / kFactorHeightSpatial[action_.spatial];
|
qm_->spatial_height_fact = 1.0f / kFactorHeightSpatial[action_.spatial];
|
||||||
@ -587,9 +608,9 @@ void VCMQmResolution::UpdateDownsamplingState(UpDownAction up_down) {
|
|||||||
// has been selected.
|
// has been selected.
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
UpdateCodecResolution();
|
||||||
state_dec_factor_spatial_ = state_dec_factor_spatial_ *
|
state_dec_factor_spatial_ = state_dec_factor_spatial_ *
|
||||||
qm_->spatial_width_fact *
|
qm_->spatial_width_fact * qm_->spatial_height_fact;
|
||||||
qm_->spatial_height_fact;
|
|
||||||
state_dec_factor_temporal_ = state_dec_factor_temporal_ * qm_->temporal_fact;
|
state_dec_factor_temporal_ = state_dec_factor_temporal_ * qm_->temporal_fact;
|
||||||
assert(state_dec_factor_spatial_ >= 1.0f);
|
assert(state_dec_factor_spatial_ >= 1.0f);
|
||||||
assert(state_dec_factor_spatial_ <= kMaxSpatialDown);
|
assert(state_dec_factor_spatial_ <= kMaxSpatialDown);
|
||||||
@ -597,6 +618,33 @@ void VCMQmResolution::UpdateDownsamplingState(UpDownAction up_down) {
|
|||||||
assert(state_dec_factor_temporal_ <= kMaxTempDown);
|
assert(state_dec_factor_temporal_ <= kMaxTempDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VCMQmResolution::UpdateCodecResolution() {
|
||||||
|
if (action_.spatial != kNoChangeSpatial) {
|
||||||
|
qm_->change_resolution_spatial = true;
|
||||||
|
qm_->codec_width = static_cast<uint16_t>(width_ / qm_->spatial_width_fact);
|
||||||
|
qm_->codec_height = static_cast<uint16_t>
|
||||||
|
(height_ / qm_->spatial_height_fact);
|
||||||
|
// Size can never exceed native sizes.
|
||||||
|
assert(qm_->codec_width <= native_width_);
|
||||||
|
assert(qm_->codec_height <= native_height_);
|
||||||
|
// Size should be multiple of 2.
|
||||||
|
assert(qm_->codec_width % 2 == 0);
|
||||||
|
assert(qm_->codec_height % 2 == 0);
|
||||||
|
}
|
||||||
|
if (action_.temporal != kNoChangeTemporal) {
|
||||||
|
qm_->change_resolution_temporal = true;
|
||||||
|
// Update the frame rate based on the average incoming frame rate.
|
||||||
|
qm_->frame_rate = avg_incoming_framerate_ / qm_->temporal_fact + 0.5f;
|
||||||
|
if (down_action_history_[0].temporal == 0) {
|
||||||
|
// When we undo the last temporal-down action, make sure we go back up
|
||||||
|
// to the native frame rate. Since the incoming frame rate may
|
||||||
|
// fluctuate over time, |avg_incoming_framerate_| scaled back up may
|
||||||
|
// be smaller than |native_frame rate_|.
|
||||||
|
qm_->frame_rate = native_frame_rate_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t VCMQmResolution::RateClass(float transition_rate) {
|
uint8_t VCMQmResolution::RateClass(float transition_rate) {
|
||||||
return avg_target_rate_ < (kFacLowRate * transition_rate) ? 0:
|
return avg_target_rate_ < (kFacLowRate * transition_rate) ? 0:
|
||||||
(avg_target_rate_ >= transition_rate ? 2 : 1);
|
(avg_target_rate_ >= transition_rate ? 2 : 1);
|
||||||
@ -607,17 +655,67 @@ void VCMQmResolution::AdjustAction() {
|
|||||||
// is not high, then safer to take frame rate reduction if the
|
// is not high, then safer to take frame rate reduction if the
|
||||||
// average incoming frame rate is high.
|
// average incoming frame rate is high.
|
||||||
if (spatial_.level == kDefault && motion_.level != kHigh &&
|
if (spatial_.level == kDefault && motion_.level != kHigh &&
|
||||||
framerate_level_ == kHigh) {
|
framerate_level_ == kFrameRateHigh) {
|
||||||
action_.spatial = kNoChangeSpatial;
|
action_.spatial = kNoChangeSpatial;
|
||||||
action_.temporal = kOneHalfTemporal;
|
action_.temporal = kOneHalfTemporal;
|
||||||
}
|
}
|
||||||
// If both motion and spatial level are low, and temporal down-action
|
// If both motion and spatial level are low, and temporal down action
|
||||||
// was selected, switch to spatial 3/4x3/4 if the frame rate is low.
|
// was selected, switch to spatial 3/4x3/4 if the frame rate is low.
|
||||||
if (motion_.level == kLow && spatial_.level == kLow &&
|
if (motion_.level == kLow && spatial_.level == kLow &&
|
||||||
framerate_level_ == kLow && action_.temporal != kNoChangeTemporal) {
|
framerate_level_ == kFrameRateLow &&
|
||||||
|
action_.temporal != kNoChangeTemporal) {
|
||||||
action_.spatial = kOneHalfSpatialUniform;
|
action_.spatial = kOneHalfSpatialUniform;
|
||||||
action_.temporal = kNoChangeTemporal;
|
action_.temporal = kNoChangeTemporal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If too much spatial action, and temporal action has not yet been chosen,
|
||||||
|
// then change to temporal action if the average frame rate is not low.
|
||||||
|
if (action_.spatial == kOneQuarterSpatialUniform &&
|
||||||
|
down_action_history_[0].spatial == kOneQuarterSpatialUniform &&
|
||||||
|
down_action_history_[0].temporal == kNoChangeTemporal &&
|
||||||
|
framerate_level_ != kFrameRateLow) {
|
||||||
|
action_.spatial = kNoChangeSpatial;
|
||||||
|
action_.temporal = kOneHalfTemporal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never use temporal action if number of temporal layers is above 2.
|
||||||
|
if (num_layers_ > 2) {
|
||||||
|
if (action_.temporal != kNoChangeTemporal) {
|
||||||
|
action_.spatial = kOneHalfSpatialUniform;
|
||||||
|
}
|
||||||
|
action_.temporal = kNoChangeTemporal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VCMQmResolution::ConvertSpatialFractionalToWhole() {
|
||||||
|
// If 3/4 spatial is selected, check if there has been another 3/4,
|
||||||
|
// and if so, combine them into 1/2. 1/2 scaling is more efficient than 9/16.
|
||||||
|
// Note we define 3/4x3/4 spatial as kOneHalfSpatialUniform.
|
||||||
|
if (action_.spatial == kOneHalfSpatialUniform) {
|
||||||
|
bool found = false;
|
||||||
|
int isel = kDownActionHistorySize;
|
||||||
|
for (int i = 0; i < kDownActionHistorySize; ++i) {
|
||||||
|
if (down_action_history_[i].spatial == kOneHalfSpatialUniform) {
|
||||||
|
isel = i;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
// Update state for removing 3/4 spatial.
|
||||||
|
state_dec_factor_spatial_ = state_dec_factor_spatial_ /
|
||||||
|
(kFactorWidthSpatial[kOneHalfSpatialUniform] *
|
||||||
|
kFactorHeightSpatial[kOneHalfSpatialUniform]);
|
||||||
|
width_ = width_ * kFactorWidthSpatial[kOneHalfSpatialUniform];
|
||||||
|
height_ = height_ * kFactorHeightSpatial[kOneHalfSpatialUniform];
|
||||||
|
// Remove 3/4 from the history.
|
||||||
|
for (int i = isel; i < kDownActionHistorySize - 1; ++i) {
|
||||||
|
down_action_history_[i].spatial = down_action_history_[i + 1].spatial;
|
||||||
|
}
|
||||||
|
// Update current selection action to be 1/2x1/2 (=1/4) spatial.
|
||||||
|
action_.spatial = kOneQuarterSpatialUniform;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCMQmResolution::CheckForEvenFrameSize() {
|
void VCMQmResolution::CheckForEvenFrameSize() {
|
||||||
@ -669,11 +767,11 @@ void VCMQmResolution::ConstrainAmountOfDownSampling() {
|
|||||||
// No spatial sampling if current frame size is too small (QCIF),
|
// No spatial sampling if current frame size is too small (QCIF),
|
||||||
// or if the amount of spatial down-sampling will be too much.
|
// or if the amount of spatial down-sampling will be too much.
|
||||||
float new_dec_factor_spatial = state_dec_factor_spatial_ *
|
float new_dec_factor_spatial = state_dec_factor_spatial_ *
|
||||||
qm_->spatial_width_fact *
|
qm_->spatial_width_fact * qm_->spatial_height_fact;
|
||||||
qm_->spatial_height_fact;
|
|
||||||
if ((width_ * height_) <= kMinImageSize ||
|
if ((width_ * height_) <= kMinImageSize ||
|
||||||
new_dec_factor_spatial > kMaxSpatialDown) {
|
new_dec_factor_spatial > kMaxSpatialDown) {
|
||||||
action_.spatial = kNoChangeSpatial;
|
action_.spatial = kNoChangeSpatial;
|
||||||
|
qm_->change_resolution_spatial = false;
|
||||||
qm_->spatial_width_fact = 1.0f;
|
qm_->spatial_width_fact = 1.0f;
|
||||||
qm_->spatial_height_fact = 1.0f;
|
qm_->spatial_height_fact = 1.0f;
|
||||||
}
|
}
|
||||||
@ -683,6 +781,7 @@ void VCMQmResolution::ConstrainAmountOfDownSampling() {
|
|||||||
if (avg_incoming_framerate_ <= kMinFrameRate ||
|
if (avg_incoming_framerate_ <= kMinFrameRate ||
|
||||||
new_dec_factor_temp >= kMaxTempDown) {
|
new_dec_factor_temp >= kMaxTempDown) {
|
||||||
action_.temporal = kNoChangeTemporal;
|
action_.temporal = kNoChangeTemporal;
|
||||||
|
qm_->change_resolution_temporal = false;
|
||||||
qm_->temporal_fact = 1.0f;
|
qm_->temporal_fact = 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -698,7 +797,7 @@ void VCMQmResolution::PickSpatialOrTemporal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(marpan): Update this when we allow for 1/2 spatial down-sampling.
|
// TODO(marpan): Update when we allow for directional spatial down-sampling.
|
||||||
void VCMQmResolution::SelectSpatialDirectionMode(float transition_rate) {
|
void VCMQmResolution::SelectSpatialDirectionMode(float transition_rate) {
|
||||||
// Default is 4/3x4/3
|
// Default is 4/3x4/3
|
||||||
// For bit rates well below transitional rate, we select 2x2.
|
// For bit rates well below transitional rate, we select 2x2.
|
||||||
|
@ -23,15 +23,23 @@ struct VideoContentMetrics;
|
|||||||
|
|
||||||
struct VCMResolutionScale {
|
struct VCMResolutionScale {
|
||||||
VCMResolutionScale()
|
VCMResolutionScale()
|
||||||
: spatial_width_fact(1.0f),
|
: codec_width(640),
|
||||||
|
codec_height(480),
|
||||||
|
frame_rate(30.0f),
|
||||||
|
spatial_width_fact(1.0f),
|
||||||
spatial_height_fact(1.0f),
|
spatial_height_fact(1.0f),
|
||||||
temporal_fact(1.0f),
|
temporal_fact(1.0f),
|
||||||
change_resolution(false) {
|
change_resolution_spatial(false),
|
||||||
|
change_resolution_temporal(false) {
|
||||||
}
|
}
|
||||||
|
uint16_t codec_width;
|
||||||
|
uint16_t codec_height;
|
||||||
|
float frame_rate;
|
||||||
float spatial_width_fact;
|
float spatial_width_fact;
|
||||||
float spatial_height_fact;
|
float spatial_height_fact;
|
||||||
float temporal_fact;
|
float temporal_fact;
|
||||||
bool change_resolution;
|
bool change_resolution_spatial;
|
||||||
|
bool change_resolution_temporal;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ImageType {
|
enum ImageType {
|
||||||
@ -50,7 +58,14 @@ enum ImageType {
|
|||||||
const uint32_t kSizeOfImageType[kNumImageTypes] =
|
const uint32_t kSizeOfImageType[kNumImageTypes] =
|
||||||
{ 25344, 57024, 76800, 101376, 172800, 307200, 518400, 921600, 2073600 };
|
{ 25344, 57024, 76800, 101376, 172800, 307200, 518400, 921600, 2073600 };
|
||||||
|
|
||||||
enum LevelClass {
|
enum FrameRateLevelClass {
|
||||||
|
kFrameRateLow,
|
||||||
|
kFrameRateMiddle1,
|
||||||
|
kFrameRateMiddle2,
|
||||||
|
kFrameRateHigh
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ContentLevelClass {
|
||||||
kLow,
|
kLow,
|
||||||
kHigh,
|
kHigh,
|
||||||
kDefault
|
kDefault
|
||||||
@ -66,7 +81,7 @@ struct VCMContFeature {
|
|||||||
level = kDefault;
|
level = kDefault;
|
||||||
}
|
}
|
||||||
float value;
|
float value;
|
||||||
LevelClass level;
|
ContentLevelClass level;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum UpDownAction {
|
enum UpDownAction {
|
||||||
@ -146,7 +161,7 @@ class VCMQmMethod {
|
|||||||
ImageType FindClosestImageType(uint16_t width, uint16_t height);
|
ImageType FindClosestImageType(uint16_t width, uint16_t height);
|
||||||
|
|
||||||
// Get the frame rate level.
|
// Get the frame rate level.
|
||||||
LevelClass FrameRateLevel(float frame_rate);
|
FrameRateLevelClass FrameRateLevel(float frame_rate);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Content Data.
|
// Content Data.
|
||||||
@ -155,12 +170,14 @@ class VCMQmMethod {
|
|||||||
// Encoder frame sizes and native frame sizes.
|
// Encoder frame sizes and native frame sizes.
|
||||||
uint16_t width_;
|
uint16_t width_;
|
||||||
uint16_t height_;
|
uint16_t height_;
|
||||||
|
float user_frame_rate_;
|
||||||
uint16_t native_width_;
|
uint16_t native_width_;
|
||||||
uint16_t native_height_;
|
uint16_t native_height_;
|
||||||
|
float native_frame_rate_;
|
||||||
float aspect_ratio_;
|
float aspect_ratio_;
|
||||||
// Image type and frame rate leve, for the current encoder resolution.
|
// Image type and frame rate leve, for the current encoder resolution.
|
||||||
ImageType image_type_;
|
ImageType image_type_;
|
||||||
LevelClass framerate_level_;
|
FrameRateLevelClass framerate_level_;
|
||||||
// Content class data.
|
// Content class data.
|
||||||
VCMContFeature motion_;
|
VCMContFeature motion_;
|
||||||
VCMContFeature spatial_;
|
VCMContFeature spatial_;
|
||||||
@ -195,7 +212,7 @@ class VCMQmResolution : public VCMQmMethod {
|
|||||||
int num_layers);
|
int num_layers);
|
||||||
|
|
||||||
// Update the encoder frame size.
|
// Update the encoder frame size.
|
||||||
void UpdateCodecFrameSize(uint16_t width, uint16_t height);
|
void UpdateCodecParameters(float frame_rate, uint16_t width, uint16_t height);
|
||||||
|
|
||||||
// Update with actual bit rate (size of the latest encoded frame)
|
// Update with actual bit rate (size of the latest encoded frame)
|
||||||
// and frame type, after every encoded frame.
|
// and frame type, after every encoded frame.
|
||||||
@ -214,6 +231,7 @@ class VCMQmResolution : public VCMQmMethod {
|
|||||||
// Output: the spatial and/or temporal scale change.
|
// Output: the spatial and/or temporal scale change.
|
||||||
int SelectResolution(VCMResolutionScale** qm);
|
int SelectResolution(VCMResolutionScale** qm);
|
||||||
|
|
||||||
|
private:
|
||||||
// Set the default resolution action.
|
// Set the default resolution action.
|
||||||
void SetDefaultAction();
|
void SetDefaultAction();
|
||||||
|
|
||||||
@ -248,12 +266,18 @@ class VCMQmResolution : public VCMQmMethod {
|
|||||||
// Update the down-sampling state.
|
// Update the down-sampling state.
|
||||||
void UpdateDownsamplingState(UpDownAction up_down);
|
void UpdateDownsamplingState(UpDownAction up_down);
|
||||||
|
|
||||||
|
// Update the codec frame size and frame rate.
|
||||||
|
void UpdateCodecResolution();
|
||||||
|
|
||||||
// Return a state based on average target rate relative transition rate.
|
// Return a state based on average target rate relative transition rate.
|
||||||
uint8_t RateClass(float transition_rate);
|
uint8_t RateClass(float transition_rate);
|
||||||
|
|
||||||
// Adjust the action selected from the table.
|
// Adjust the action selected from the table.
|
||||||
void AdjustAction();
|
void AdjustAction();
|
||||||
|
|
||||||
|
// Covert 2 stages of 3/4 (=9/16) spatial decimation to 1/2.
|
||||||
|
void ConvertSpatialFractionalToWhole();
|
||||||
|
|
||||||
// Check if the new frame sizes are still divisible by 2.
|
// Check if the new frame sizes are still divisible by 2.
|
||||||
void CheckForEvenFrameSize();
|
void CheckForEvenFrameSize();
|
||||||
|
|
||||||
@ -273,13 +297,11 @@ class VCMQmResolution : public VCMQmMethod {
|
|||||||
// Select the directional (1x2 or 2x1) spatial down-sampling action.
|
// Select the directional (1x2 or 2x1) spatial down-sampling action.
|
||||||
void SelectSpatialDirectionMode(float transition_rate);
|
void SelectSpatialDirectionMode(float transition_rate);
|
||||||
|
|
||||||
private:
|
|
||||||
enum { kDownActionHistorySize = 10};
|
enum { kDownActionHistorySize = 10};
|
||||||
|
|
||||||
VCMResolutionScale* qm_;
|
VCMResolutionScale* qm_;
|
||||||
// Encoder rate control parameters.
|
// Encoder rate control parameters.
|
||||||
float target_bitrate_;
|
float target_bitrate_;
|
||||||
float user_framerate_;
|
|
||||||
float incoming_framerate_;
|
float incoming_framerate_;
|
||||||
float per_frame_bandwidth_;
|
float per_frame_bandwidth_;
|
||||||
float buffer_level_;
|
float buffer_level_;
|
||||||
|
@ -53,7 +53,6 @@ const float kPacketLossThr = 0.1f;
|
|||||||
// Factor for reducing transitonal bitrate under packet loss.
|
// Factor for reducing transitonal bitrate under packet loss.
|
||||||
const float kPacketLossRateFac = 1.0f;
|
const float kPacketLossRateFac = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
// Maximum possible transitional rate for down-sampling:
|
// Maximum possible transitional rate for down-sampling:
|
||||||
// (units in kbps), for 30fps.
|
// (units in kbps), for 30fps.
|
||||||
const uint16_t kMaxRateQm[9] = {
|
const uint16_t kMaxRateQm[9] = {
|
||||||
@ -69,10 +68,11 @@ const uint16_t kMaxRateQm[9] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Frame rate scale for maximum transition rate.
|
// Frame rate scale for maximum transition rate.
|
||||||
const float kFrameRateFac[3] = {
|
const float kFrameRateFac[4] = {
|
||||||
0.7f, // L
|
0.5f, // Low
|
||||||
1.0f, // H
|
0.7f, // Middle level 1
|
||||||
0.8f // D
|
0.85f, // Middle level 2
|
||||||
|
1.0f, // High
|
||||||
};
|
};
|
||||||
|
|
||||||
// Scale for transitional rate: based on content class
|
// Scale for transitional rate: based on content class
|
||||||
@ -180,7 +180,7 @@ const uint8_t kTemporalAction[27] = {
|
|||||||
// Control the total amount of down-sampling allowed.
|
// Control the total amount of down-sampling allowed.
|
||||||
const float kMaxSpatialDown = 8.0f;
|
const float kMaxSpatialDown = 8.0f;
|
||||||
const float kMaxTempDown = 4.0f;
|
const float kMaxTempDown = 4.0f;
|
||||||
const float kMaxDownSample = 16.0f;
|
const float kMaxDownSample = 12.0f;
|
||||||
|
|
||||||
// Minimum image size for a spatial down-sampling.
|
// Minimum image size for a spatial down-sampling.
|
||||||
const int kMinImageSize= 176 * 144;
|
const int kMinImageSize= 176 * 144;
|
||||||
@ -199,6 +199,7 @@ const int kMinFrameRate = 8;
|
|||||||
|
|
||||||
// Thresholds for frame rate:
|
// Thresholds for frame rate:
|
||||||
const int kLowFrameRate = 10;
|
const int kLowFrameRate = 10;
|
||||||
|
const int kMiddleFrameRate = 15;
|
||||||
const int kHighFrameRate = 25;
|
const int kHighFrameRate = 25;
|
||||||
|
|
||||||
// Thresholds for motion: motion level is from NFD
|
// Thresholds for motion: motion level is from NFD
|
||||||
|
@ -62,7 +62,10 @@ class QmSelectTest : public ::testing::Test {
|
|||||||
bool IsSelectedActionCorrect(VCMResolutionScale* qm_scale,
|
bool IsSelectedActionCorrect(VCMResolutionScale* qm_scale,
|
||||||
float fac_width,
|
float fac_width,
|
||||||
float fac_height,
|
float fac_height,
|
||||||
float fac_temp);
|
float fac_temp,
|
||||||
|
uint16_t new_width,
|
||||||
|
uint16_t new_height,
|
||||||
|
float new_frame_rate);
|
||||||
|
|
||||||
void TearDown() {
|
void TearDown() {
|
||||||
delete qm_resolution_;
|
delete qm_resolution_;
|
||||||
@ -84,7 +87,8 @@ TEST_F(QmSelectTest, HandleInputs) {
|
|||||||
qm_resolution_->UpdateContent(content_metrics);
|
qm_resolution_->UpdateContent(content_metrics);
|
||||||
// Content metrics are NULL: Expect success and no down-sampling action.
|
// Content metrics are NULL: Expect success and no down-sampling action.
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0, 1.0, 1.0));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0, 1.0, 1.0, 640, 480,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// No down-sampling action at high rates.
|
// No down-sampling action at high rates.
|
||||||
@ -95,7 +99,7 @@ TEST_F(QmSelectTest, NoActionHighRate) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -111,7 +115,8 @@ TEST_F(QmSelectTest, NoActionHighRate) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(0, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(0, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rate is well below transition, down-sampling action is taken,
|
// Rate is well below transition, down-sampling action is taken,
|
||||||
@ -123,7 +128,7 @@ TEST_F(QmSelectTest, DownActionLowRate) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -140,35 +145,40 @@ TEST_F(QmSelectTest, DownActionLowRate) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Low motion, low spatial: 2/3 temporal is expected.
|
// Low motion, low spatial: 2/3 temporal is expected.
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialLow, kSpatialLow, kSpatialLow);
|
UpdateQmContentData(kTemporalLow, kSpatialLow, kSpatialLow, kSpatialLow);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(0, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(0, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480,
|
||||||
|
20.5f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Medium motion, low spatial: 2x2 spatial expected.
|
// Medium motion, low spatial: 2x2 spatial expected.
|
||||||
UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
|
UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// High motion, high spatial: 1/2 temporal expected.
|
// High motion, high spatial: 2/3 temporal expected.
|
||||||
UpdateQmContentData(kTemporalHigh, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
UpdateQmContentData(kTemporalHigh, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(4, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(4, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480,
|
||||||
|
20.5f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Low motion, high spatial: 1/2 temporal expected.
|
// Low motion, high spatial: 1/2 temporal expected.
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Medium motion, high spatial: 1/2 temporal expected.
|
// Medium motion, high spatial: 1/2 temporal expected.
|
||||||
@ -176,7 +186,8 @@ TEST_F(QmSelectTest, DownActionLowRate) {
|
|||||||
kSpatialHigh);
|
kSpatialHigh);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// High motion, medium spatial: 2x2 spatial expected.
|
// High motion, medium spatial: 2x2 spatial expected.
|
||||||
@ -184,7 +195,9 @@ TEST_F(QmSelectTest, DownActionLowRate) {
|
|||||||
kSpatialMedium);
|
kSpatialMedium);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
// Target frame rate for frame dropper should be the same as previous == 15.
|
||||||
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Low motion, medium spatial: high frame rate, so 1/2 temporal expected.
|
// Low motion, medium spatial: high frame rate, so 1/2 temporal expected.
|
||||||
@ -192,7 +205,8 @@ TEST_F(QmSelectTest, DownActionLowRate) {
|
|||||||
kSpatialMedium);
|
kSpatialMedium);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(2, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(2, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Medium motion, medium spatial: high frame rate, so 1/2 temporal expected.
|
// Medium motion, medium spatial: high frame rate, so 1/2 temporal expected.
|
||||||
@ -200,7 +214,8 @@ TEST_F(QmSelectTest, DownActionLowRate) {
|
|||||||
kSpatialMedium);
|
kSpatialMedium);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(8, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(8, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480,
|
||||||
|
15.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rate mis-match is high, and we have over-shooting.
|
// Rate mis-match is high, and we have over-shooting.
|
||||||
@ -212,7 +227,7 @@ TEST_F(QmSelectTest, DownActionHighRateMMOvershoot) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -230,14 +245,15 @@ TEST_F(QmSelectTest, DownActionHighRateMMOvershoot) {
|
|||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
||||||
1.0f));
|
1.0f, 480, 360, 30.0f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Low motion, high spatial
|
// Low motion, high spatial
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480,
|
||||||
|
20.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rate mis-match is high, target rate is below max for down-sampling,
|
// Rate mis-match is high, target rate is below max for down-sampling,
|
||||||
@ -249,7 +265,7 @@ TEST_F(QmSelectTest, NoActionHighRateMMUndershoot) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -266,14 +282,16 @@ TEST_F(QmSelectTest, NoActionHighRateMMUndershoot) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Low motion, high spatial
|
// Low motion, high spatial
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer is underflowing, and target rate is below max for down-sampling,
|
// Buffer is underflowing, and target rate is below max for down-sampling,
|
||||||
@ -285,7 +303,7 @@ TEST_F(QmSelectTest, DownActionBufferUnderflow) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update with encoded size over a number of frames.
|
// Update with encoded size over a number of frames.
|
||||||
@ -308,14 +326,15 @@ TEST_F(QmSelectTest, DownActionBufferUnderflow) {
|
|||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
||||||
1.0f));
|
1.0f, 480, 360, 30.0f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Low motion, high spatial
|
// Low motion, high spatial
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480,
|
||||||
|
20.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target rate is below max for down-sampling, but buffer level is stable,
|
// Target rate is below max for down-sampling, but buffer level is stable,
|
||||||
@ -327,7 +346,7 @@ TEST_F(QmSelectTest, NoActionBufferStable) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update with encoded size over a number of frames.
|
// Update with encoded size over a number of frames.
|
||||||
@ -349,14 +368,16 @@ TEST_F(QmSelectTest, NoActionBufferStable) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
qm_resolution_->ResetDownSamplingState();
|
qm_resolution_->ResetDownSamplingState();
|
||||||
// Low motion, high spatial
|
// Low motion, high spatial
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Very low rate, but no spatial down-sampling below some size (QCIF).
|
// Very low rate, but no spatial down-sampling below some size (QCIF).
|
||||||
@ -367,7 +388,7 @@ TEST_F(QmSelectTest, LimitDownSpatialAction) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 176;
|
uint16_t codec_width = 176;
|
||||||
uint16_t codec_height = 144;
|
uint16_t codec_height = 144;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(0, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(0, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -384,7 +405,8 @@ TEST_F(QmSelectTest, LimitDownSpatialAction) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 176, 144,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Very low rate, but no frame reduction below some frame_rate (8fps).
|
// Very low rate, but no frame reduction below some frame_rate (8fps).
|
||||||
@ -395,7 +417,7 @@ TEST_F(QmSelectTest, LimitDownTemporalAction) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(8.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -413,7 +435,8 @@ TEST_F(QmSelectTest, LimitDownTemporalAction) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(2, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(2, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480,
|
||||||
|
8.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two stages: spatial down-sample and then back up spatially,
|
// Two stages: spatial down-sample and then back up spatially,
|
||||||
@ -425,7 +448,7 @@ TEST_F(QmSelectTest, 2StageDownSpatialUpSpatial) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -442,11 +465,12 @@ TEST_F(QmSelectTest, 2StageDownSpatialUpSpatial) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Reset and go up in rate: expected to go back up.
|
// Reset and go up in rate: expected to go back up.
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
qm_resolution_->UpdateCodecFrameSize(320, 240);
|
qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
|
||||||
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
int target_rate2[] = {400, 400, 400, 400, 400};
|
int target_rate2[] = {400, 400, 400, 400, 400};
|
||||||
@ -457,7 +481,8 @@ TEST_F(QmSelectTest, 2StageDownSpatialUpSpatial) {
|
|||||||
fraction_lost2, 5);
|
fraction_lost2, 5);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 1.0f, 640, 480,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two stages: spatial down-sample and then back up spatially, since encoder
|
// Two stages: spatial down-sample and then back up spatially, since encoder
|
||||||
@ -469,7 +494,7 @@ TEST_F(QmSelectTest, 2StageDownSpatialUpSpatialUndershoot) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -486,11 +511,12 @@ TEST_F(QmSelectTest, 2StageDownSpatialUpSpatialUndershoot) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Reset rates and simulate under-shooting scenario.: expect to go back up.
|
// Reset rates and simulate under-shooting scenario.: expect to go back up.
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
qm_resolution_->UpdateCodecFrameSize(320, 240);
|
qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
|
||||||
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
int target_rate2[] = {200, 200, 200, 200, 200};
|
int target_rate2[] = {200, 200, 200, 200, 200};
|
||||||
@ -501,7 +527,8 @@ TEST_F(QmSelectTest, 2StageDownSpatialUpSpatialUndershoot) {
|
|||||||
fraction_lost2, 5);
|
fraction_lost2, 5);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 1.0f, 640, 480,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two stages: spatial down-sample and then no action to go up,
|
// Two stages: spatial down-sample and then no action to go up,
|
||||||
@ -513,7 +540,7 @@ TEST_F(QmSelectTest, 2StageDownSpatialNoActionUp) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -530,11 +557,12 @@ TEST_F(QmSelectTest, 2StageDownSpatialNoActionUp) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Reset and simulate large rate mis-match: expect no action to go back up.
|
// Reset and simulate large rate mis-match: expect no action to go back up.
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
qm_resolution_->UpdateCodecFrameSize(320, 240);
|
qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
|
||||||
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
int target_rate2[] = {400, 400, 400, 400, 400};
|
int target_rate2[] = {400, 400, 400, 400, 400};
|
||||||
@ -545,8 +573,10 @@ TEST_F(QmSelectTest, 2StageDownSpatialNoActionUp) {
|
|||||||
fraction_lost2, 5);
|
fraction_lost2, 5);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two stages: temporally down-sample and then back up temporally,
|
// Two stages: temporally down-sample and then back up temporally,
|
||||||
// as rate as increased.
|
// as rate as increased.
|
||||||
TEST_F(QmSelectTest, 2StatgeDownTemporalUpTemporal) {
|
TEST_F(QmSelectTest, 2StatgeDownTemporalUpTemporal) {
|
||||||
@ -556,91 +586,7 @@ TEST_F(QmSelectTest, 2StatgeDownTemporalUpTemporal) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
|
||||||
int target_rate[] = {100, 100, 100};
|
|
||||||
int encoder_sent_rate[] = {100, 100, 100};
|
|
||||||
int incoming_frame_rate[] = {30, 30, 30};
|
|
||||||
uint8_t fraction_lost[] = {10, 10, 10};
|
|
||||||
UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
|
|
||||||
fraction_lost, 3);
|
|
||||||
|
|
||||||
// Update content: motion level, and 3 spatial prediction errors.
|
|
||||||
// Low motion, high spatial.
|
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
|
||||||
|
|
||||||
// Reset rates and go up in rate: expect to go back up.
|
|
||||||
qm_resolution_->ResetRates();
|
|
||||||
// Update rates for a sequence of intervals.
|
|
||||||
int target_rate2[] = {400, 400, 400, 400, 400};
|
|
||||||
int encoder_sent_rate2[] = {400, 400, 400, 400, 400};
|
|
||||||
int incoming_frame_rate2[] = {15, 15, 15, 15, 15};
|
|
||||||
uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
|
|
||||||
UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
|
|
||||||
fraction_lost2, 5);
|
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Two stages: temporal down-sample and then back up temporally, since encoder
|
|
||||||
// is under-shooting target even though rate has not increased much.
|
|
||||||
TEST_F(QmSelectTest, 2StatgeDownTemporalUpTemporalUndershoot) {
|
|
||||||
// Initialize with bitrate, frame rate, and native system width/height.
|
|
||||||
InitQmNativeData(100, 30, 640, 480, 1);
|
|
||||||
|
|
||||||
// Update with encoder frame size.
|
|
||||||
uint16_t codec_width = 640;
|
|
||||||
uint16_t codec_height = 480;
|
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
|
||||||
int target_rate[] = {100, 100, 100};
|
|
||||||
int encoder_sent_rate[] = {100, 100, 100};
|
|
||||||
int incoming_frame_rate[] = {30, 30, 30};
|
|
||||||
uint8_t fraction_lost[] = {10, 10, 10};
|
|
||||||
UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
|
|
||||||
fraction_lost, 3);
|
|
||||||
|
|
||||||
// Update content: motion level, and 3 spatial prediction errors.
|
|
||||||
// Low motion, high spatial.
|
|
||||||
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
|
||||||
|
|
||||||
// Reset rates and simulate under-shooting scenario.: expect to go back up.
|
|
||||||
qm_resolution_->ResetRates();
|
|
||||||
// Update rates for a sequence of intervals.
|
|
||||||
int target_rate2[] = {200, 200, 200, 200, 200};
|
|
||||||
int encoder_sent_rate2[] = {50, 50, 50, 50, 50};
|
|
||||||
int incoming_frame_rate2[] = {15, 15, 15, 15, 15};
|
|
||||||
uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
|
|
||||||
UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
|
|
||||||
fraction_lost2, 5);
|
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
|
||||||
EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
|
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Two stages: temporal down-sample and then no action to go up,
|
|
||||||
// as encoding rate mis-match is too high.
|
|
||||||
TEST_F(QmSelectTest, 2StageDownTemporalNoActionUp) {
|
|
||||||
// Initialize with bitrate, frame rate, and native system width/height.
|
|
||||||
InitQmNativeData(100, 30, 640, 480, 1);
|
|
||||||
|
|
||||||
// Update with encoder frame size.
|
|
||||||
uint16_t codec_width = 640;
|
|
||||||
uint16_t codec_height = 480;
|
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -657,9 +603,98 @@ TEST_F(QmSelectTest, 2StageDownTemporalNoActionUp) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1, 1, 2));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
|
// Reset rates and go up in rate: expect to go back up.
|
||||||
|
qm_resolution_->ResetRates();
|
||||||
|
// Update rates for a sequence of intervals.
|
||||||
|
int target_rate2[] = {400, 400, 400, 400, 400};
|
||||||
|
int encoder_sent_rate2[] = {400, 400, 400, 400, 400};
|
||||||
|
int incoming_frame_rate2[] = {15, 15, 15, 15, 15};
|
||||||
|
uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
|
||||||
|
UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
|
||||||
|
fraction_lost2, 5);
|
||||||
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f, 640, 480,
|
||||||
|
30.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two stages: temporal down-sample and then back up temporally, since encoder
|
||||||
|
// is under-shooting target even though rate has not increased much.
|
||||||
|
TEST_F(QmSelectTest, 2StatgeDownTemporalUpTemporalUndershoot) {
|
||||||
|
// Initialize with bitrate, frame rate, and native system width/height.
|
||||||
|
InitQmNativeData(100, 30, 640, 480, 1);
|
||||||
|
|
||||||
|
// Update with encoder frame size.
|
||||||
|
uint16_t codec_width = 640;
|
||||||
|
uint16_t codec_height = 480;
|
||||||
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
|
// Update rates for a sequence of intervals.
|
||||||
|
int target_rate[] = {100, 100, 100};
|
||||||
|
int encoder_sent_rate[] = {100, 100, 100};
|
||||||
|
int incoming_frame_rate[] = {30, 30, 30};
|
||||||
|
uint8_t fraction_lost[] = {10, 10, 10};
|
||||||
|
UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
|
||||||
|
fraction_lost, 3);
|
||||||
|
|
||||||
|
// Update content: motion level, and 3 spatial prediction errors.
|
||||||
|
// Low motion, high spatial.
|
||||||
|
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
|
// Reset rates and simulate under-shooting scenario.: expect to go back up.
|
||||||
|
qm_resolution_->ResetRates();
|
||||||
|
// Update rates for a sequence of intervals.
|
||||||
|
int target_rate2[] = {200, 200, 200, 200, 200};
|
||||||
|
int encoder_sent_rate2[] = {50, 50, 50, 50, 50};
|
||||||
|
int incoming_frame_rate2[] = {15, 15, 15, 15, 15};
|
||||||
|
uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
|
||||||
|
UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
|
||||||
|
fraction_lost2, 5);
|
||||||
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
|
EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
|
||||||
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f, 640, 480,
|
||||||
|
30.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two stages: temporal down-sample and then no action to go up,
|
||||||
|
// as encoding rate mis-match is too high.
|
||||||
|
TEST_F(QmSelectTest, 2StageDownTemporalNoActionUp) {
|
||||||
|
// Initialize with bitrate, frame rate, and native system width/height.
|
||||||
|
InitQmNativeData(100, 30, 640, 480, 1);
|
||||||
|
|
||||||
|
// Update with encoder frame size.
|
||||||
|
uint16_t codec_width = 640;
|
||||||
|
uint16_t codec_height = 480;
|
||||||
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
|
// Update rates for a sequence of intervals.
|
||||||
|
int target_rate[] = {100, 100, 100};
|
||||||
|
int encoder_sent_rate[] = {100, 100, 100};
|
||||||
|
int incoming_frame_rate[] = {30, 30, 30};
|
||||||
|
uint8_t fraction_lost[] = {10, 10, 10};
|
||||||
|
UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
|
||||||
|
fraction_lost, 3);
|
||||||
|
|
||||||
|
// Update content: motion level, and 3 spatial prediction errors.
|
||||||
|
// Low motion, high spatial.
|
||||||
|
UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
|
||||||
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1, 1, 2, 640, 480, 15.5f));
|
||||||
|
|
||||||
// Reset and simulate large rate mis-match: expect no action to go back up.
|
// Reset and simulate large rate mis-match: expect no action to go back up.
|
||||||
|
qm_resolution_->UpdateCodecParameters(15.0f, codec_width, codec_height);
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
int target_rate2[] = {600, 600, 600, 600, 600};
|
int target_rate2[] = {600, 600, 600, 600, 600};
|
||||||
@ -670,7 +705,8 @@ TEST_F(QmSelectTest, 2StageDownTemporalNoActionUp) {
|
|||||||
fraction_lost2, 5);
|
fraction_lost2, 5);
|
||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480,
|
||||||
|
15.0f));
|
||||||
}
|
}
|
||||||
// 3 stages: spatial down-sample, followed by temporal down-sample,
|
// 3 stages: spatial down-sample, followed by temporal down-sample,
|
||||||
// and then go up to full state, as encoding rate has increased.
|
// and then go up to full state, as encoding rate has increased.
|
||||||
@ -681,7 +717,7 @@ TEST_F(QmSelectTest, 3StageDownSpatialTemporlaUpSpatialTemporal) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -698,10 +734,11 @@ TEST_F(QmSelectTest, 3StageDownSpatialTemporlaUpSpatialTemporal) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Change content data: expect temporal down-sample.
|
// Change content data: expect temporal down-sample.
|
||||||
qm_resolution_->UpdateCodecFrameSize(320, 240);
|
qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
|
||||||
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
||||||
|
|
||||||
// Update content: motion level, and 3 spatial prediction errors.
|
// Update content: motion level, and 3 spatial prediction errors.
|
||||||
@ -710,7 +747,8 @@ TEST_F(QmSelectTest, 3StageDownSpatialTemporlaUpSpatialTemporal) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 320, 240,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
// Reset rates and go high up in rate: expect to go back up both spatial
|
// Reset rates and go high up in rate: expect to go back up both spatial
|
||||||
// and temporally.
|
// and temporally.
|
||||||
@ -726,7 +764,8 @@ TEST_F(QmSelectTest, 3StageDownSpatialTemporlaUpSpatialTemporal) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 0.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 0.5f, 640, 480,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// No down-sampling below some total amount.
|
// No down-sampling below some total amount.
|
||||||
@ -737,7 +776,7 @@ TEST_F(QmSelectTest, NoActionTooMuchDownSampling) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 1280;
|
uint16_t codec_width = 1280;
|
||||||
uint16_t codec_height = 720;
|
uint16_t codec_height = 720;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(7, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(7, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -754,11 +793,12 @@ TEST_F(QmSelectTest, NoActionTooMuchDownSampling) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 640, 360,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Reset and lower rates to get another spatial action (3/4x3/4)
|
// Reset and lower rates to get another spatial action (3/4x3/4)
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
qm_resolution_->UpdateCodecFrameSize(640, 360);
|
qm_resolution_->UpdateCodecParameters(30.0f, 640, 360);
|
||||||
EXPECT_EQ(4, qm_resolution_->GetImageType(640, 360));
|
EXPECT_EQ(4, qm_resolution_->GetImageType(640, 360));
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
int target_rate2[] = {80, 80, 80, 80, 80};
|
int target_rate2[] = {80, 80, 80, 80, 80};
|
||||||
@ -776,13 +816,13 @@ TEST_F(QmSelectTest, NoActionTooMuchDownSampling) {
|
|||||||
EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
||||||
1.0f));
|
1.0f, 480, 270, 30.0f));
|
||||||
|
|
||||||
// Reset and go to very low rate: no action should be taken,
|
// Reset and go to very low rate: no action should be taken,
|
||||||
// we went down too much already.
|
// we went down too much already.
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
qm_resolution_->UpdateCodecFrameSize(320, 180);
|
qm_resolution_->UpdateCodecParameters(30.0f, 480, 270);
|
||||||
EXPECT_EQ(1, qm_resolution_->GetImageType(320, 180));
|
EXPECT_EQ(3, qm_resolution_->GetImageType(480, 270));
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
int target_rate3[] = {10, 10, 10, 10, 10};
|
int target_rate3[] = {10, 10, 10, 10, 10};
|
||||||
int encoder_sent_rate3[] = {10, 10, 10, 10, 10};
|
int encoder_sent_rate3[] = {10, 10, 10, 10, 10};
|
||||||
@ -793,7 +833,8 @@ TEST_F(QmSelectTest, NoActionTooMuchDownSampling) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 480, 270,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiple down-sampling stages and then undo all of them.
|
// Multiple down-sampling stages and then undo all of them.
|
||||||
@ -807,7 +848,7 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory1) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Go down spatial 3/4x3/4.
|
// Go down spatial 3/4x3/4.
|
||||||
@ -826,9 +867,9 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory1) {
|
|||||||
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
||||||
1.0f));
|
1.0f, 480, 360, 30.0f));
|
||||||
// Go down 1/2 temporal.
|
// Go down 1/2 temporal.
|
||||||
qm_resolution_->UpdateCodecFrameSize(480, 360);
|
qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
|
||||||
EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
|
EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
int target_rate2[] = {100, 100, 100, 100, 100};
|
int target_rate2[] = {100, 100, 100, 100, 100};
|
||||||
@ -844,9 +885,11 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory1) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 480, 360,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
// Go down 1/2x1/2 spatial.
|
// Go down 1/2x1/2 spatial.
|
||||||
|
qm_resolution_->UpdateCodecParameters(15.0f, 480, 360);
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
int target_rate3[] = {50, 50, 50, 50, 50};
|
int target_rate3[] = {50, 50, 50, 50, 50};
|
||||||
int encoder_sent_rate3[] = {50, 50, 50, 50, 50};
|
int encoder_sent_rate3[] = {50, 50, 50, 50, 50};
|
||||||
@ -861,14 +904,15 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory1) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 240, 180,
|
||||||
|
15.0f));
|
||||||
|
|
||||||
// Reset rates and go high up in rate: expect to go up:
|
// Reset rates and go high up in rate: expect to go up:
|
||||||
// should go up first: 1/2x1x2 and 1/2 temporally,
|
// should go up first: 1/2x1x2 and 1/2 temporally,
|
||||||
// and second: 3/4x3/4 spatial.
|
// and second: 3/4x3/4 spatial.
|
||||||
|
|
||||||
// Go up 1/2x1/2 spatially and 1/2 temporally
|
// Go up 1/2x1/2 spatially and 1/2 temporally
|
||||||
qm_resolution_->UpdateCodecFrameSize(240, 180);
|
qm_resolution_->UpdateCodecParameters(15.0f, 240, 180);
|
||||||
EXPECT_EQ(1, qm_resolution_->GetImageType(240, 180));
|
EXPECT_EQ(1, qm_resolution_->GetImageType(240, 180));
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -882,10 +926,11 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory1) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 0.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 0.5f, 480, 360,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Go up 3/4x3/4 spatially.
|
// Go up 3/4x3/4 spatially.
|
||||||
qm_resolution_->UpdateCodecFrameSize(480, 360);
|
qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
|
||||||
EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
|
EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
@ -900,7 +945,7 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory1) {
|
|||||||
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f,
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f,
|
||||||
1.0f));
|
1.0f, 640, 480, 30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiple down-sampling and up-sample stages, with partial undoing.
|
// Multiple down-sampling and up-sample stages, with partial undoing.
|
||||||
@ -914,7 +959,7 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory2) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Go down 1/2x1/2 spatial.
|
// Go down 1/2x1/2 spatial.
|
||||||
@ -932,10 +977,11 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory2) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Go down 2/3 temporal.
|
// Go down 2/3 temporal.
|
||||||
qm_resolution_->UpdateCodecFrameSize(320, 240);
|
qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
|
||||||
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
int target_rate2[] = {80, 80, 80, 80, 80};
|
int target_rate2[] = {80, 80, 80, 80, 80};
|
||||||
@ -952,9 +998,11 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory2) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 320, 240,
|
||||||
|
20.5f));
|
||||||
|
|
||||||
// Go up 1/2x1/2 spatially.
|
// Go up 1/2x1/2 spatially.
|
||||||
|
qm_resolution_->UpdateCodecParameters(20.0f, 320, 240);
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
// Update rates for a sequence of intervals.
|
// Update rates for a sequence of intervals.
|
||||||
int target_rate3[] = {300, 300, 300, 300, 300};
|
int target_rate3[] = {300, 300, 300, 300, 300};
|
||||||
@ -967,10 +1015,11 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory2) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 1.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 0.5f, 0.5f, 1.0f, 640, 480,
|
||||||
|
20.0f));
|
||||||
|
|
||||||
// Go down 1/2 temporal.
|
// Go down 1/2 temporal.
|
||||||
qm_resolution_->UpdateCodecFrameSize(640, 480);
|
qm_resolution_->UpdateCodecParameters(20.0f, 640, 480);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(640, 480));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(640, 480));
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
int target_rate4[] = {100, 100, 100, 100, 100};
|
int target_rate4[] = {100, 100, 100, 100, 100};
|
||||||
@ -986,7 +1035,8 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory2) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480,
|
||||||
|
10.5f));
|
||||||
|
|
||||||
// Go up 1/2 temporal.
|
// Go up 1/2 temporal.
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
@ -1001,7 +1051,8 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory2) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f, 640, 480,
|
||||||
|
20.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiple down-sampling and up-sample stages, with partial undoing.
|
// Multiple down-sampling and up-sample stages, with partial undoing.
|
||||||
@ -1015,7 +1066,7 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory3) {
|
|||||||
// Update with encoder frame size.
|
// Update with encoder frame size.
|
||||||
uint16_t codec_width = 640;
|
uint16_t codec_width = 640;
|
||||||
uint16_t codec_height = 480;
|
uint16_t codec_height = 480;
|
||||||
qm_resolution_->UpdateCodecFrameSize(codec_width, codec_height);
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
// Go down 3/4x3/4 spatial.
|
// Go down 3/4x3/4 spatial.
|
||||||
@ -1034,10 +1085,10 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory3) {
|
|||||||
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
||||||
1.0f));
|
1.0f, 480, 360, 30.0f));
|
||||||
|
|
||||||
// Go down 1/2 temporal.
|
// Go down 1/2 temporal.
|
||||||
qm_resolution_->UpdateCodecFrameSize(480, 360);
|
qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
|
||||||
EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
|
EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
int target_rate2[] = {100, 100, 100, 100, 100};
|
int target_rate2[] = {100, 100, 100, 100, 100};
|
||||||
@ -1053,7 +1104,8 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory3) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 480, 360,
|
||||||
|
15.5f));
|
||||||
|
|
||||||
// Go up 1/2 temporal.
|
// Go up 1/2 temporal.
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
@ -1068,15 +1120,16 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory3) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f, 480, 360,
|
||||||
|
30.0f));
|
||||||
|
|
||||||
// Go down 2/3 temporal.
|
// Go down 2/3 temporal.
|
||||||
qm_resolution_->UpdateCodecFrameSize(640, 480);
|
qm_resolution_->UpdateCodecParameters(30.0f, 640, 480);
|
||||||
EXPECT_EQ(5, qm_resolution_->GetImageType(640, 480));
|
EXPECT_EQ(5, qm_resolution_->GetImageType(640, 480));
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
int target_rate4[] = {150, 150, 150, 150, 150};
|
int target_rate4[] = {200, 200, 200, 200, 200};
|
||||||
int encoder_sent_rate4[] = {150, 150, 150, 150, 150};
|
int encoder_sent_rate4[] = {200, 200, 200, 200, 200};
|
||||||
int incoming_frame_rate4[] = {20, 20, 20, 20, 20};
|
int incoming_frame_rate4[] = {30, 30, 30, 30, 30};
|
||||||
uint8_t fraction_lost4[] = {30, 30, 30, 30, 30};
|
uint8_t fraction_lost4[] = {30, 30, 30, 30, 30};
|
||||||
UpdateQmRateData(target_rate4, encoder_sent_rate4, incoming_frame_rate4,
|
UpdateQmRateData(target_rate4, encoder_sent_rate4, incoming_frame_rate4,
|
||||||
fraction_lost4, 5);
|
fraction_lost4, 5);
|
||||||
@ -1088,7 +1141,8 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory3) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480,
|
||||||
|
20.5f));
|
||||||
|
|
||||||
// Go up 2/3 temporal.
|
// Go up 2/3 temporal.
|
||||||
qm_resolution_->ResetRates();
|
qm_resolution_->ResetRates();
|
||||||
@ -1103,7 +1157,58 @@ TEST_F(QmSelectTest, MultipleStagesCheckActionHistory3) {
|
|||||||
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
|
||||||
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f / 3.0f));
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f / 3.0f, 640,
|
||||||
|
480, 30.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two stages of 3/4x3/4 converted to one stage of 1/2x1/2.
|
||||||
|
TEST_F(QmSelectTest, ConvertThreeQuartersToOneHalf) {
|
||||||
|
// Initialize with bitrate, frame rate, and native system width/height.
|
||||||
|
InitQmNativeData(200, 30, 640, 480, 1);
|
||||||
|
|
||||||
|
// Update with encoder frame size.
|
||||||
|
uint16_t codec_width = 640;
|
||||||
|
uint16_t codec_height = 480;
|
||||||
|
qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
|
||||||
|
EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
|
||||||
|
|
||||||
|
// Go down 3/4x3/4 spatial.
|
||||||
|
// Update rates for a sequence of intervals.
|
||||||
|
int target_rate[] = {200, 200, 200};
|
||||||
|
int encoder_sent_rate[] = {200, 200, 200};
|
||||||
|
int incoming_frame_rate[] = {30, 30, 30};
|
||||||
|
uint8_t fraction_lost[] = {10, 10, 10};
|
||||||
|
UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
|
||||||
|
fraction_lost, 3);
|
||||||
|
|
||||||
|
// Update content: motion level, and 3 spatial prediction errors.
|
||||||
|
// Medium motion, low spatial.
|
||||||
|
UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
|
||||||
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
|
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
||||||
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f,
|
||||||
|
1.0f, 480, 360, 30.0f));
|
||||||
|
|
||||||
|
// Set rates to go down another 3/4 spatial. Should be converted ton 1/2.
|
||||||
|
qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
|
||||||
|
EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
|
||||||
|
qm_resolution_->ResetRates();
|
||||||
|
int target_rate2[] = {150, 150, 150, 150, 150};
|
||||||
|
int encoder_sent_rate2[] = {150, 150, 150, 150, 150};
|
||||||
|
int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
|
||||||
|
uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
|
||||||
|
UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
|
||||||
|
fraction_lost2, 5);
|
||||||
|
|
||||||
|
// Update content: motion level, and 3 spatial prediction errors.
|
||||||
|
// Medium motion, low spatial.
|
||||||
|
UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
|
||||||
|
EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
|
||||||
|
EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
|
||||||
|
EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
|
||||||
|
EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240,
|
||||||
|
30.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmSelectTest::InitQmNativeData(float initial_bit_rate,
|
void QmSelectTest::InitQmNativeData(float initial_bit_rate,
|
||||||
@ -1160,10 +1265,16 @@ void QmSelectTest::UpdateQmRateData(int* target_rate,
|
|||||||
bool QmSelectTest::IsSelectedActionCorrect(VCMResolutionScale* qm_scale,
|
bool QmSelectTest::IsSelectedActionCorrect(VCMResolutionScale* qm_scale,
|
||||||
float fac_width,
|
float fac_width,
|
||||||
float fac_height,
|
float fac_height,
|
||||||
float fac_temp) {
|
float fac_temp,
|
||||||
|
uint16_t new_width,
|
||||||
|
uint16_t new_height,
|
||||||
|
float new_frame_rate) {
|
||||||
if (qm_scale->spatial_width_fact == fac_width &&
|
if (qm_scale->spatial_width_fact == fac_width &&
|
||||||
qm_scale->spatial_height_fact == fac_height &&
|
qm_scale->spatial_height_fact == fac_height &&
|
||||||
qm_scale->temporal_fact == fac_temp) {
|
qm_scale->temporal_fact == fac_temp &&
|
||||||
|
qm_scale->codec_width == new_width &&
|
||||||
|
qm_scale->codec_height == new_height &&
|
||||||
|
qm_scale->frame_rate == new_frame_rate) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user