Moving src/webrtc into src/.
In order to eliminate the WebRTC Subtree mirror in Chromium, WebRTC is moving the content of the src/webrtc directory up to the src/ directory. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true TBR=tommi@webrtc.org Bug: chromium:611808 Change-Id: Iac59c5b51b950f174119565bac87955a7994bc38 Reviewed-on: https://webrtc-review.googlesource.com/1560 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Kjellander <kjellander@webrtc.org> Cr-Commit-Position: refs/heads/master@{#19845}
This commit is contained in:
committed by
Commit Bot
parent
6674846b4a
commit
bb547203bf
205
modules/video_coding/utility/quality_scaler.cc
Normal file
205
modules/video_coding/utility/quality_scaler.cc
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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 "webrtc/modules/video_coding/utility/quality_scaler.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/rtc_base/checks.h"
|
||||
#include "webrtc/rtc_base/logging.h"
|
||||
#include "webrtc/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 {
|
||||
// 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) {
|
||||
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_);
|
||||
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);
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
} // namespace webrtc
|
||||
Reference in New Issue
Block a user