blob: cfd2fced3f1c49159225a161dff56aa7c4cf6b8e [file] [log] [blame]
/*
* 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.
*/
#ifndef MODULES_VIDEO_CODING_UTILITY_QUALITY_SCALER_H_
#define MODULES_VIDEO_CODING_UTILITY_QUALITY_SCALER_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include "absl/types/optional.h"
#include "api/scoped_refptr.h"
#include "api/video_codecs/video_encoder.h"
#include "rtc_base/experiments/quality_scaling_experiment.h"
#include "rtc_base/numerics/moving_average.h"
#include "rtc_base/ref_count.h"
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/synchronization/sequence_checker.h"
#include "rtc_base/task_queue.h"
namespace webrtc {
class QualityScalerQpUsageHandlerCallbackInterface;
class QualityScalerQpUsageHandlerInterface;
// QualityScaler runs asynchronously and monitors QP values of encoded frames.
// It holds a reference to a QualityScalerQpUsageHandlerInterface implementation
// to signal an overuse or underuse of QP (which indicate a desire to scale the
// video stream down or up).
class QualityScaler {
public:
// Construct a QualityScaler with given |thresholds| and |handler|.
// This starts the quality scaler periodically checking what the average QP
// has been recently.
QualityScaler(QualityScalerQpUsageHandlerInterface* handler,
VideoEncoder::QpThresholds thresholds);
virtual ~QualityScaler();
// Should be called each time a frame is dropped at encoding.
void ReportDroppedFrameByMediaOpt();
void ReportDroppedFrameByEncoder();
// Inform the QualityScaler of the last seen QP.
void ReportQp(int qp, int64_t time_sent_us);
void SetQpThresholds(VideoEncoder::QpThresholds thresholds);
bool QpFastFilterLow() const;
// The following members declared protected for testing purposes.
protected:
QualityScaler(QualityScalerQpUsageHandlerInterface* handler,
VideoEncoder::QpThresholds thresholds,
int64_t sampling_period_ms);
private:
class QpSmoother;
class CheckQpTask;
class CheckQpTaskHandlerCallback;
enum class CheckQpResult {
kInsufficientSamples,
kNormalQp,
kHighQp,
kLowQp,
};
// Starts checking for QP in a delayed task. When the resulting CheckQpTask
// completes, it will invoke this method again, ensuring that we always
// periodically check for QP. See CheckQpTask for more details. We never run
// more than one CheckQpTask at a time.
void StartNextCheckQpTask();
CheckQpResult CheckQp() const;
void ClearSamples();
std::unique_ptr<CheckQpTask> pending_qp_task_ RTC_GUARDED_BY(&task_checker_);
QualityScalerQpUsageHandlerInterface* const handler_
RTC_GUARDED_BY(&task_checker_);
SequenceChecker task_checker_;
VideoEncoder::QpThresholds thresholds_ RTC_GUARDED_BY(&task_checker_);
const int64_t sampling_period_ms_;
bool fast_rampup_ RTC_GUARDED_BY(&task_checker_);
rtc::MovingAverage average_qp_ RTC_GUARDED_BY(&task_checker_);
rtc::MovingAverage framedrop_percent_media_opt_
RTC_GUARDED_BY(&task_checker_);
rtc::MovingAverage framedrop_percent_all_ RTC_GUARDED_BY(&task_checker_);
// Used by QualityScalingExperiment.
const bool experiment_enabled_;
QualityScalingExperiment::Config config_ RTC_GUARDED_BY(&task_checker_);
std::unique_ptr<QpSmoother> qp_smoother_high_ RTC_GUARDED_BY(&task_checker_);
std::unique_ptr<QpSmoother> qp_smoother_low_ RTC_GUARDED_BY(&task_checker_);
const size_t min_frames_needed_;
const double initial_scale_factor_;
const absl::optional<double> scale_factor_;
};
// Reacts to QP being too high or too low. For best quality, when QP is high it
// is desired to decrease the resolution or frame rate of the stream and when QP
// is low it is desired to increase the resolution or frame rate of the stream.
// Whether to reconfigure the stream is ultimately up to the handler, which is
// able to respond asynchronously.
class QualityScalerQpUsageHandlerInterface {
public:
virtual ~QualityScalerQpUsageHandlerInterface();
// Reacts to QP usage being too high or too low. The |callback| MUST be
// invoked when the handler is done, allowing the QualityScaler to resume
// checking for QP.
virtual void OnReportQpUsageHigh(
rtc::scoped_refptr<QualityScalerQpUsageHandlerCallbackInterface>
callback) = 0;
virtual void OnReportQpUsageLow(
rtc::scoped_refptr<QualityScalerQpUsageHandlerCallbackInterface>
callback) = 0;
};
// When QP is reported as high or low by the QualityScaler, it pauses checking
// for QP until the QP usage has been handled. When OnQpUsageHandled() is
// invoked, the QualityScaler resumes checking for QP. This ensures that if the
// stream is reconfigured in response to QP usage we do not include QP samples
// from before the reconfiguration the next time we check for QP.
//
// OnQpUsageHandled() MUST be invoked exactly once before this object is
// destroyed.
class QualityScalerQpUsageHandlerCallbackInterface
: public rtc::RefCountedObject<rtc::RefCountInterface> {
public:
virtual ~QualityScalerQpUsageHandlerCallbackInterface();
// If |clear_qp_samples| is true, existing QP samples are cleared before the
// next time QualityScaler checks for QP. This is usually a good idea when the
// stream is reconfigured. If |clear_qp_samples| is false, samples are not
// cleared and QualityScaler increases its frequency of checking for QP.
virtual void OnQpUsageHandled(bool clear_qp_samples) = 0;
protected:
QualityScalerQpUsageHandlerCallbackInterface();
};
} // namespace webrtc
#endif // MODULES_VIDEO_CODING_UTILITY_QUALITY_SCALER_H_