Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

206 lines
6.6 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/video_coding/utility/quality_scaler.h"
#include <math.h>
#include <algorithm>
#include <memory>
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/task_queue.h"
// TODO(kthelgason): Some versions of Android have issues with log2.
// See https://code.google.com/p/android/issues/detail?id=212634 for details
#if defined(WEBRTC_ANDROID)
#define log2(x) (log(x) / log(2))
#endif
namespace webrtc {
namespace {
Reland of Make QualityScaler more responsive to downgrades. (patchset #1 id:1 of https://codereview.webrtc.org/1880103002/ ) Reason for revert: Regressed behavior is actually desirable (go down to 360p instead of producing super-bad 720p). Original issue's description: > Revert of Make QualityScaler more responsive to downgrades. (patchset #3 id:40001 of https://codereview.webrtc.org/1830593003/ ) > > Reason for revert: > Speculative revert: want to see if this causes the regression in https://crbug.com/602621 > > Original issue's description: > > Make QualityScaler more responsive to downgrades. > > > > Permits going from HD to QVGA in 6 seconds instead of 10. Also adds > > windows for going up quickly in the beginning of a call (before any > > downscaling happens due to bad quality). > > > > BUG=webrtc:5678 > > R=glaznev@webrtc.org, stefan@webrtc.org > > > > Committed: https://crrev.com/85829fd90cc4e7a91c9857921b19e8fc126aeb60 > > Cr-Commit-Position: refs/heads/master@{#12219} > > TBR=glaznev@webrtc.org,stefan@webrtc.org,pbos@webrtc.org > # Not skipping CQ checks because original CL landed more than 1 days ago. > BUG=webrtc:5678 > NOTRY=true > > Committed: https://crrev.com/19b4fecf08e3fe215e431a260fb673553c15e569 > Cr-Commit-Position: refs/heads/master@{#12331} TBR=glaznev@webrtc.org,stefan@webrtc.org,phoglund@webrtc.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=chromium:602621, webrtc:5678 Review URL: https://codereview.webrtc.org/1887493003 Cr-Commit-Position: refs/heads/master@{#12341}
2016-04-13 02:51:02 -07:00
// Threshold constant used until first downscale (to permit fast rampup).
static const int kMeasureMs = 2000;
static const float kSamplePeriodScaleFactor = 2.5;
static const int kFramedropPercentThreshold = 60;
// QP scaling threshold defaults:
static const int kLowH264QpThreshold = 24;
static const int kHighH264QpThreshold = 37;
// QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 127] and not the user-level range of [0,63].
static const int kLowVp8QpThreshold = 29;
static const int kHighVp8QpThreshold = 95;
// QP is obtained from VP9-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 255] and not the user-level range of [0,63].
// Current VP9 settings are mapped from VP8 thresholds above.
static const int kLowVp9QpThreshold = 96;
static const int kHighVp9QpThreshold = 185;
static const int kMinFramesNeededToScale = 2 * 30;
static VideoEncoder::QpThresholds CodecTypeToDefaultThresholds(
VideoCodecType codec_type) {
int low = -1;
int high = -1;
switch (codec_type) {
case kVideoCodecH264:
low = kLowH264QpThreshold;
high = kHighH264QpThreshold;
break;
case kVideoCodecVP8:
low = kLowVp8QpThreshold;
high = kHighVp8QpThreshold;
break;
case kVideoCodecVP9:
low = kLowVp9QpThreshold;
high = kHighVp9QpThreshold;
break;
default:
RTC_NOTREACHED() << "Invalid codec type for QualityScaler.";
}
return VideoEncoder::QpThresholds(low, high);
}
} // namespace
class QualityScaler::CheckQPTask : public rtc::QueuedTask {
public:
explicit CheckQPTask(QualityScaler* scaler) : scaler_(scaler) {
RTC_LOG(LS_INFO) << "Created CheckQPTask. Scheduling on queue...";
rtc::TaskQueue::Current()->PostDelayedTask(
std::unique_ptr<rtc::QueuedTask>(this), scaler_->GetSamplingPeriodMs());
}
void Stop() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
RTC_LOG(LS_INFO) << "Stopping QP Check task.";
stop_ = true;
}
private:
bool Run() override {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
if (stop_)
return true; // TaskQueue will free this task.
scaler_->CheckQP();
rtc::TaskQueue::Current()->PostDelayedTask(
std::unique_ptr<rtc::QueuedTask>(this), scaler_->GetSamplingPeriodMs());
return false; // Retain the task in order to reuse it.
}
QualityScaler* const scaler_;
bool stop_ = false;
rtc::SequencedTaskChecker task_checker_;
};
QualityScaler::QualityScaler(AdaptationObserverInterface* observer,
VideoCodecType codec_type)
: QualityScaler(observer, CodecTypeToDefaultThresholds(codec_type)) {}
QualityScaler::QualityScaler(AdaptationObserverInterface* observer,
VideoEncoder::QpThresholds thresholds)
: QualityScaler(observer, thresholds, kMeasureMs) {}
// Protected ctor, should not be called directly.
QualityScaler::QualityScaler(AdaptationObserverInterface* observer,
VideoEncoder::QpThresholds thresholds,
int64_t sampling_period)
: check_qp_task_(nullptr),
observer_(observer),
sampling_period_ms_(sampling_period),
fast_rampup_(true),
// Arbitrarily choose size based on 30 fps for 5 seconds.
average_qp_(5 * 30),
framedrop_percent_(5 * 30),
thresholds_(thresholds) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
RTC_DCHECK(observer_ != nullptr);
check_qp_task_ = new CheckQPTask(this);
RTC_LOG(LS_INFO) << "QP thresholds: low: " << thresholds_.low
<< ", high: " << thresholds_.high;
}
QualityScaler::~QualityScaler() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
check_qp_task_->Stop();
}
int64_t QualityScaler::GetSamplingPeriodMs() const {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
return fast_rampup_ ? sampling_period_ms_
: (sampling_period_ms_ * kSamplePeriodScaleFactor);
}
void QualityScaler::ReportDroppedFrame() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
framedrop_percent_.AddSample(100);
}
void QualityScaler::ReportQP(int qp) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
framedrop_percent_.AddSample(0);
average_qp_.AddSample(qp);
}
void QualityScaler::CheckQP() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
// Should be set through InitEncode -> Should be set by now.
RTC_DCHECK_GE(thresholds_.low, 0);
// If we have not observed at least this many frames we can't
// make a good scaling decision.
if (framedrop_percent_.size() < kMinFramesNeededToScale)
return;
// Check if we should scale down due to high frame drop.
const rtc::Optional<int> drop_rate = framedrop_percent_.GetAverage();
if (drop_rate && *drop_rate >= kFramedropPercentThreshold) {
ReportQPHigh();
return;
}
// Check if we should scale up or down based on QP.
const rtc::Optional<int> avg_qp = average_qp_.GetAverage();
if (avg_qp) {
RTC_LOG(LS_INFO) << "Checking average QP " << *avg_qp;
if (*avg_qp > thresholds_.high) {
ReportQPHigh();
return;
}
if (*avg_qp <= thresholds_.low) {
// QP has been low. We want to try a higher resolution.
ReportQPLow();
return;
}
}
}
void QualityScaler::ReportQPLow() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
ClearSamples();
observer_->AdaptUp(AdaptationObserverInterface::AdaptReason::kQuality);
}
void QualityScaler::ReportQPHigh() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
ClearSamples();
observer_->AdaptDown(AdaptationObserverInterface::AdaptReason::kQuality);
// If we've scaled down, wait longer before scaling up again.
if (fast_rampup_) {
fast_rampup_ = false;
}
}
void QualityScaler::ClearSamples() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
framedrop_percent_.Reset();
average_qp_.Reset();
Reland of Make QualityScaler more responsive to downgrades. (patchset #1 id:1 of https://codereview.webrtc.org/1880103002/ ) Reason for revert: Regressed behavior is actually desirable (go down to 360p instead of producing super-bad 720p). Original issue's description: > Revert of Make QualityScaler more responsive to downgrades. (patchset #3 id:40001 of https://codereview.webrtc.org/1830593003/ ) > > Reason for revert: > Speculative revert: want to see if this causes the regression in https://crbug.com/602621 > > Original issue's description: > > Make QualityScaler more responsive to downgrades. > > > > Permits going from HD to QVGA in 6 seconds instead of 10. Also adds > > windows for going up quickly in the beginning of a call (before any > > downscaling happens due to bad quality). > > > > BUG=webrtc:5678 > > R=glaznev@webrtc.org, stefan@webrtc.org > > > > Committed: https://crrev.com/85829fd90cc4e7a91c9857921b19e8fc126aeb60 > > Cr-Commit-Position: refs/heads/master@{#12219} > > TBR=glaznev@webrtc.org,stefan@webrtc.org,pbos@webrtc.org > # Not skipping CQ checks because original CL landed more than 1 days ago. > BUG=webrtc:5678 > NOTRY=true > > Committed: https://crrev.com/19b4fecf08e3fe215e431a260fb673553c15e569 > Cr-Commit-Position: refs/heads/master@{#12331} TBR=glaznev@webrtc.org,stefan@webrtc.org,phoglund@webrtc.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=chromium:602621, webrtc:5678 Review URL: https://codereview.webrtc.org/1887493003 Cr-Commit-Position: refs/heads/master@{#12341}
2016-04-13 02:51:02 -07:00
}
} // namespace webrtc