blob: 7b6aa2b7a4b47daf2d1b8022eba7539d01027bb0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/base/constants.h"
#include "remoting/codec/frame_processing_time_estimator.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
using base::TimeDelta;
using base::TimeTicks;
namespace {
WebrtcVideoEncoder::EncodedFrame CreateEncodedFrame(bool key_frame,
int size,
TimeTicks start,
TimeTicks end) {
WebrtcVideoEncoder::EncodedFrame result;
result.key_frame = key_frame;
result.data.assign(static_cast<size_t>(size), 'A');
result.stats = std::make_unique<WebrtcVideoEncoder::FrameStats>();
result.stats->capture_started_time = start;
result.stats->encode_ended_time = end;
return result;
}
} // namespace
TEST(FrameProcessingTimeEstimatorTest, EstimateDeltaAndKeyFrame) {
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start;
for (int i = 0; i < 10; i++) {
start = end;
if (i % 5 == 0) {
// Fake a key-frame.
end += TimeDelta::FromMilliseconds(10);
estimator.FinishFrame(CreateEncodedFrame(true, 100, start, end));
} else {
// Fake a delta-frame.
end += TimeDelta::FromMilliseconds(1);
estimator.FinishFrame(CreateEncodedFrame(false, 50, start, end));
}
}
estimator.SetBandwidthKbps(50);
estimator.SetBandwidthKbps(150);
EXPECT_EQ(100, estimator.AverageBandwidthKbps());
EXPECT_EQ(TimeDelta::FromMilliseconds(10),
estimator.EstimatedProcessingTime(true));
EXPECT_EQ(TimeDelta::FromMilliseconds(1),
estimator.EstimatedProcessingTime(false));
EXPECT_EQ(TimeDelta::FromMilliseconds(8),
estimator.EstimatedTransitTime(true));
EXPECT_EQ(TimeDelta::FromMilliseconds(4),
estimator.EstimatedTransitTime(false));
EXPECT_EQ(60, estimator.EstimatedFrameSize());
EXPECT_EQ(TimeDelta::FromMicroseconds(2800),
estimator.EstimatedProcessingTime());
EXPECT_EQ(TimeDelta::FromMicroseconds(4800),
estimator.EstimatedTransitTime());
EXPECT_EQ(kTargetFrameRate, estimator.RecentFrameRate());
EXPECT_EQ(kTargetFrameRate, estimator.PredictedFrameRate());
EXPECT_EQ(kTargetFrameRate, estimator.EstimatedFrameRate());
}
TEST(FrameProcessingTimeEstimatorTest, NegativeBandwidthShouldBeDropped) {
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start + TimeDelta::FromMilliseconds(10);
estimator.FinishFrame(CreateEncodedFrame(true, 100, start, end));
estimator.SetBandwidthKbps(100);
estimator.SetBandwidthKbps(-100);
EXPECT_EQ(TimeDelta::FromMilliseconds(8),
estimator.EstimatedTransitTime(true));
}
TEST(FrameProcessingTimeEstimatorTest, ShouldNotReturn0WithOnlyKeyFrames) {
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start + TimeDelta::FromMilliseconds(10);
estimator.FinishFrame(CreateEncodedFrame(true, 100, start, end));
estimator.SetBandwidthKbps(100);
EXPECT_EQ(TimeDelta::FromMilliseconds(10),
estimator.EstimatedProcessingTime(true));
EXPECT_EQ(TimeDelta::FromMilliseconds(8),
estimator.EstimatedTransitTime(true));
EXPECT_EQ(TimeDelta::FromMilliseconds(10),
estimator.EstimatedProcessingTime(false));
EXPECT_EQ(TimeDelta::FromMilliseconds(8),
estimator.EstimatedTransitTime(false));
EXPECT_EQ(TimeDelta::FromMilliseconds(10),
estimator.EstimatedProcessingTime());
EXPECT_EQ(TimeDelta::FromMilliseconds(8), estimator.EstimatedTransitTime());
EXPECT_EQ(100, estimator.EstimatedFrameSize());
EXPECT_EQ(kTargetFrameRate, estimator.RecentFrameRate());
EXPECT_EQ(kTargetFrameRate, estimator.PredictedFrameRate());
EXPECT_EQ(kTargetFrameRate, estimator.EstimatedFrameRate());
}
TEST(FrameProcessingTimeEstimatorTest, ShouldNotReturn0WithOnlyDeltaFrames) {
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start + TimeDelta::FromMilliseconds(1);
estimator.FinishFrame(CreateEncodedFrame(false, 50, start, end));
estimator.SetBandwidthKbps(100);
EXPECT_EQ(TimeDelta::FromMilliseconds(1),
estimator.EstimatedProcessingTime(false));
EXPECT_EQ(TimeDelta::FromMilliseconds(4),
estimator.EstimatedTransitTime(false));
EXPECT_EQ(TimeDelta::FromMilliseconds(1),
estimator.EstimatedProcessingTime(true));
EXPECT_EQ(TimeDelta::FromMilliseconds(4),
estimator.EstimatedTransitTime(true));
EXPECT_EQ(TimeDelta::FromMilliseconds(1),
estimator.EstimatedProcessingTime());
EXPECT_EQ(TimeDelta::FromMilliseconds(4), estimator.EstimatedTransitTime());
EXPECT_EQ(50, estimator.EstimatedFrameSize());
EXPECT_EQ(kTargetFrameRate, estimator.RecentFrameRate());
EXPECT_EQ(kTargetFrameRate, estimator.PredictedFrameRate());
EXPECT_EQ(kTargetFrameRate, estimator.EstimatedFrameRate());
}
TEST(FrameProcessingTimeEstimatorTest, ShouldReturnDefaultValueWithoutRecords) {
FrameProcessingTimeEstimator estimator;
EXPECT_EQ(base::TimeDelta(), estimator.EstimatedProcessingTime(true));
EXPECT_EQ(base::TimeDelta(), estimator.EstimatedProcessingTime(false));
EXPECT_EQ(base::TimeDelta(), estimator.EstimatedProcessingTime());
EXPECT_EQ(0, estimator.EstimatedFrameSize());
EXPECT_EQ(kTargetFrameRate, estimator.RecentFrameRate());
EXPECT_EQ(1, estimator.PredictedFrameRate());
EXPECT_EQ(1, estimator.EstimatedFrameRate());
TimeTicks start = TimeTicks::Now();
TimeTicks end = start;
for (int i = 0; i < 10; i++) {
start = end;
if (i % 5 == 0) {
// Fake a key-frame.
end += TimeDelta::FromMilliseconds(100);
estimator.FinishFrame(CreateEncodedFrame(true, 100, start, end));
} else {
// Fake a delta-frame.
end += TimeDelta::FromMilliseconds(50);
estimator.FinishFrame(CreateEncodedFrame(false, 50, start, end));
}
}
EXPECT_EQ(TimeDelta::FromMillisecondsD(static_cast<double>(500) / 9),
estimator.RecentAverageFrameInterval());
EXPECT_EQ(19, estimator.RecentFrameRate());
EXPECT_EQ(1, estimator.PredictedFrameRate());
EXPECT_EQ(1, estimator.EstimatedFrameRate());
}
TEST(FrameProcessingTimeEstimatorTest,
ShouldEstimateFrameRateFromProcessingTime) {
// Processing times are much longer than transit times, so the estimation of
// the frame rate should depend on the processing time.
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start;
for (int i = 0; i < 10; i++) {
start = end;
if (i % 5 == 0) {
// Fake a key-frame.
end += TimeDelta::FromMilliseconds(100);
estimator.FinishFrame(CreateEncodedFrame(true, 100, start, end));
} else {
// Fake a delta-frame.
end += TimeDelta::FromMilliseconds(50);
estimator.FinishFrame(CreateEncodedFrame(false, 50, start, end));
}
}
estimator.SetBandwidthKbps(100);
EXPECT_EQ(TimeDelta::FromMilliseconds(60),
estimator.EstimatedProcessingTime());
EXPECT_EQ(TimeDelta::FromMillisecondsD(static_cast<double>(500) / 9),
estimator.RecentAverageFrameInterval());
EXPECT_EQ(19, estimator.RecentFrameRate());
EXPECT_EQ(17, estimator.PredictedFrameRate());
EXPECT_EQ(17, estimator.EstimatedFrameRate());
}
TEST(FrameProcessingTimeEstimatorTest,
ShouldEstimateFrameRateFromTransitTime) {
// Transit times are much longer than processing times, so the estimation of
// the frame rate should depend on the transit time.
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start;
for (int i = 0; i < 10; i++) {
start = end;
if (i % 5 == 0) {
// Fake a key-frame.
end += TimeDelta::FromMilliseconds(10);
estimator.FinishFrame(CreateEncodedFrame(true, 100, start, end));
} else {
// Fake a delta-frame.
end += TimeDelta::FromMilliseconds(1);
estimator.FinishFrame(CreateEncodedFrame(false, 50, start, end));
}
}
estimator.SetBandwidthKbps(10);
EXPECT_EQ(TimeDelta::FromMilliseconds(48), estimator.EstimatedTransitTime());
EXPECT_EQ(kTargetFrameRate, estimator.RecentFrameRate());
EXPECT_EQ(21, estimator.PredictedFrameRate());
EXPECT_EQ(21, estimator.EstimatedFrameRate());
}
TEST(FrameProcessingTimeEstimatorTest,
ShouldNotReturnNegativeEstimatedFrameRate) {
// Both processing times and transit times are extremely long, estimator
// should return 1.
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start;
for (int i = 0; i < 10; i++) {
start = end;
if (i % 5 == 0) {
// Fake a key-frame.
end += TimeDelta::FromMilliseconds(10000);
estimator.FinishFrame(CreateEncodedFrame(true, 1000, start, end));
} else {
// Fake a delta-frame.
end += TimeDelta::FromMilliseconds(5000);
estimator.FinishFrame(CreateEncodedFrame(false, 500, start, end));
}
}
estimator.SetBandwidthKbps(1);
EXPECT_EQ(TimeDelta::FromMilliseconds(6000),
estimator.EstimatedProcessingTime());
EXPECT_EQ(TimeDelta::FromMilliseconds(4800),
estimator.EstimatedTransitTime());
EXPECT_EQ(1, estimator.RecentFrameRate());
EXPECT_EQ(1, estimator.PredictedFrameRate());
EXPECT_EQ(1, estimator.EstimatedFrameRate());
}
TEST(FrameProcessingTimeEstimatorTest,
RecentAverageFrameIntervalShouldConsiderDelay) {
FrameProcessingTimeEstimator estimator;
TimeTicks start = TimeTicks::Now();
TimeTicks end = start;
for (int i = 0; i < 10; i++) {
end += TimeDelta::FromMilliseconds(50);
start = end;
if (i % 5 == 0) {
// Fake a key-frame.
end += TimeDelta::FromMilliseconds(10);
estimator.FinishFrame(CreateEncodedFrame(true, 1000, start, end));
} else {
// Fake a delta-frame.
end += TimeDelta::FromMilliseconds(5);
estimator.FinishFrame(CreateEncodedFrame(false, 500, start, end));
}
}
estimator.SetBandwidthKbps(1000);
EXPECT_EQ(TimeDelta::FromMilliseconds(6),
estimator.EstimatedProcessingTime());
EXPECT_EQ(TimeDelta::FromMillisecondsD(
static_cast<double>(50 * 9 + 10 + 5 * 8) / 9),
estimator.RecentAverageFrameInterval());
EXPECT_EQ(19, estimator.RecentFrameRate());
// Processing time & transit time are both pretty low, we should be able to
// reach 30 FPS if capturing delay has been reduced.
EXPECT_EQ(kTargetFrameRate, estimator.PredictedFrameRate());
EXPECT_EQ(19, estimator.EstimatedFrameRate());
}
} // namespace remoting