blob: 66f4e138700244d9f02824a5c1c549ce653e5bf6 [file] [log] [blame]
/*
* Copyright 2020 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 "video/adaptation/quality_scaler_resource.h"
#include <memory>
#include "absl/types/optional.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "api/task_queue/task_queue_factory.h"
#include "api/video_codecs/video_encoder.h"
#include "rtc_base/event.h"
#include "rtc_base/task_queue.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
const int kDefaultTimeout = 5000;
class FakeQualityScalerQpUsageHandlerCallback
: public QualityScalerQpUsageHandlerCallbackInterface {
public:
explicit FakeQualityScalerQpUsageHandlerCallback(
rtc::TaskQueue* encoder_queue)
: QualityScalerQpUsageHandlerCallbackInterface(),
encoder_queue_(encoder_queue),
is_handled_(false),
qp_usage_handled_event_(true /* manual_reset */, false),
clear_qp_samples_result_(absl::nullopt) {}
~FakeQualityScalerQpUsageHandlerCallback() override {
RTC_DCHECK(is_handled_)
<< "The callback was destroyed without being invoked.";
}
void OnQpUsageHandled(bool clear_qp_samples) override {
ASSERT_TRUE(encoder_queue_->IsCurrent());
RTC_DCHECK(!is_handled_);
clear_qp_samples_result_ = clear_qp_samples;
is_handled_ = true;
qp_usage_handled_event_.Set();
}
bool is_handled() const { return is_handled_; }
rtc::Event* qp_usage_handled_event() { return &qp_usage_handled_event_; }
absl::optional<bool> clear_qp_samples_result() const {
return clear_qp_samples_result_;
}
private:
rtc::TaskQueue* const encoder_queue_;
bool is_handled_;
rtc::Event qp_usage_handled_event_;
absl::optional<bool> clear_qp_samples_result_;
};
} // namespace
class QualityScalerResourceTest : public ::testing::Test {
public:
QualityScalerResourceTest()
: task_queue_factory_(CreateDefaultTaskQueueFactory()),
resource_adaptation_queue_(task_queue_factory_->CreateTaskQueue(
"ResourceAdaptationQueue",
TaskQueueFactory::Priority::NORMAL)),
encoder_queue_(task_queue_factory_->CreateTaskQueue(
"EncoderQueue",
TaskQueueFactory::Priority::NORMAL)),
quality_scaler_resource_(new QualityScalerResource()) {
quality_scaler_resource_->Initialize(&encoder_queue_,
&resource_adaptation_queue_);
rtc::Event event;
encoder_queue_.PostTask([this, &event] {
quality_scaler_resource_->StartCheckForOveruse(
VideoEncoder::QpThresholds());
event.Set();
});
event.Wait(kDefaultTimeout);
}
~QualityScalerResourceTest() {
rtc::Event event;
encoder_queue_.PostTask([this, &event] {
quality_scaler_resource_->StopCheckForOveruse();
event.Set();
});
event.Wait(kDefaultTimeout);
}
protected:
const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
rtc::TaskQueue resource_adaptation_queue_;
rtc::TaskQueue encoder_queue_;
rtc::scoped_refptr<QualityScalerResource> quality_scaler_resource_;
};
TEST_F(QualityScalerResourceTest, ReportQpHigh) {
rtc::scoped_refptr<FakeQualityScalerQpUsageHandlerCallback> callback =
new FakeQualityScalerQpUsageHandlerCallback(&encoder_queue_);
encoder_queue_.PostTask([this, callback] {
quality_scaler_resource_->OnReportQpUsageHigh(callback);
});
callback->qp_usage_handled_event()->Wait(kDefaultTimeout);
}
TEST_F(QualityScalerResourceTest, ReportQpLow) {
rtc::scoped_refptr<FakeQualityScalerQpUsageHandlerCallback> callback =
new FakeQualityScalerQpUsageHandlerCallback(&encoder_queue_);
encoder_queue_.PostTask([this, callback] {
quality_scaler_resource_->OnReportQpUsageLow(callback);
});
callback->qp_usage_handled_event()->Wait(kDefaultTimeout);
}
TEST_F(QualityScalerResourceTest, MultipleCallbacksInFlight) {
rtc::scoped_refptr<FakeQualityScalerQpUsageHandlerCallback> callback1 =
new FakeQualityScalerQpUsageHandlerCallback(&encoder_queue_);
rtc::scoped_refptr<FakeQualityScalerQpUsageHandlerCallback> callback2 =
new FakeQualityScalerQpUsageHandlerCallback(&encoder_queue_);
rtc::scoped_refptr<FakeQualityScalerQpUsageHandlerCallback> callback3 =
new FakeQualityScalerQpUsageHandlerCallback(&encoder_queue_);
encoder_queue_.PostTask([this, callback1, callback2, callback3] {
quality_scaler_resource_->OnReportQpUsageHigh(callback1);
quality_scaler_resource_->OnReportQpUsageLow(callback2);
quality_scaler_resource_->OnReportQpUsageHigh(callback3);
});
callback1->qp_usage_handled_event()->Wait(kDefaultTimeout);
callback2->qp_usage_handled_event()->Wait(kDefaultTimeout);
callback3->qp_usage_handled_event()->Wait(kDefaultTimeout);
}
TEST_F(QualityScalerResourceTest, AbortPendingCallbacksAndStartAgain) {
rtc::scoped_refptr<FakeQualityScalerQpUsageHandlerCallback> callback1 =
new FakeQualityScalerQpUsageHandlerCallback(&encoder_queue_);
rtc::scoped_refptr<FakeQualityScalerQpUsageHandlerCallback> callback2 =
new FakeQualityScalerQpUsageHandlerCallback(&encoder_queue_);
encoder_queue_.PostTask([this, callback1, callback2] {
quality_scaler_resource_->OnReportQpUsageHigh(callback1);
quality_scaler_resource_->StopCheckForOveruse();
EXPECT_TRUE(callback1->qp_usage_handled_event()->Wait(0));
quality_scaler_resource_->StartCheckForOveruse(
VideoEncoder::QpThresholds());
quality_scaler_resource_->OnReportQpUsageHigh(callback2);
});
callback1->qp_usage_handled_event()->Wait(kDefaultTimeout);
callback2->qp_usage_handled_event()->Wait(kDefaultTimeout);
}
} // namespace webrtc