New api function CreateVideoStreamEncoder.

Bug: webrtc:8830
Change-Id: I01de86f601e48f76e6b41b4182ce006d397a190c
Reviewed-on: https://webrtc-review.googlesource.com/78260
Commit-Queue: Niels Moller <nisse@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24079}
This commit is contained in:
Niels Möller 2018-07-24 09:29:58 +02:00 committed by Commit Bot
parent e507b0ce8e
commit 213618e37e
25 changed files with 770 additions and 399 deletions

View File

@ -135,6 +135,8 @@ rtc_source_set("video_stream_encoder") {
visibility = [ "*" ]
sources = [
"video_stream_encoder_interface.h",
"video_stream_encoder_observer.h",
"video_stream_encoder_settings.h",
]
deps = [
@ -143,5 +145,27 @@ rtc_source_set("video_stream_encoder") {
# For rtpparameters.h
"..:libjingle_peerconnection_api",
"../video_codecs:video_codecs_api",
"//third_party/abseil-cpp/absl/types:optional",
]
}
rtc_source_set("video_stream_encoder_create") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ] # TODO(bugs.webrtc.org/7925): Remove.
sources = [
"video_stream_encoder_create.cc",
"video_stream_encoder_create.h",
]
if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
deps = [
":video_stream_encoder",
"../../rtc_base:ptr_util",
"../../video:video_stream_encoder_impl",
"../video_codecs:video_codecs_api",
]
}

View File

@ -8,4 +8,7 @@ specific_include_rules = {
"video_stream_decoder_create.cc": [
"+video/video_stream_decoder_impl.h",
],
"video_stream_encoder_create.cc": [
"+video/video_stream_encoder.h",
],
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018 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 "api/video/video_stream_encoder_create.h"
#include "rtc_base/ptr_util.h"
#include "video/video_stream_encoder.h"
namespace webrtc {
std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
uint32_t number_of_cores,
VideoStreamEncoderObserver* encoder_stats_observer,
const VideoStreamEncoderSettings& settings,
// Deprecated, used for tests only.
rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback) {
return rtc::MakeUnique<VideoStreamEncoder>(
number_of_cores, encoder_stats_observer, settings, pre_encode_callback,
rtc::MakeUnique<OveruseFrameDetector>(encoder_stats_observer));
}
} // namespace webrtc

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2018 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 API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_
#define API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_
#include <map>
#include <memory>
#include <utility>
#include "api/video/video_stream_encoder_interface.h"
#include "api/video/video_stream_encoder_observer.h"
#include "api/video/video_stream_encoder_settings.h"
namespace webrtc {
std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
uint32_t number_of_cores,
VideoStreamEncoderObserver* encoder_stats_observer,
const VideoStreamEncoderSettings& settings,
// Deprecated, used for tests only.
rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback);
inline std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
uint32_t number_of_cores,
VideoStreamEncoderObserver* encoder_stats_observer,
const VideoStreamEncoderSettings& settings) {
return CreateVideoStreamEncoder(number_of_cores, encoder_stats_observer,
settings, nullptr);
}
} // namespace webrtc
#endif // API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_

View File

@ -47,8 +47,6 @@ class VideoStreamEncoderInterface : public rtc::VideoSinkInterface<VideoFrame> {
int min_transmit_bitrate_bps) = 0;
};
~VideoStreamEncoderInterface() override = default;
// Sets the source that will provide video frames to the VideoStreamEncoder's
// OnFrame method. |degradation_preference| control whether or not resolution
// or frame rate may be reduced. The VideoStreamEncoder registers itself with

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2018 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 API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_
#define API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_
#include <vector>
#include "absl/types/optional.h"
#include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/video_encoder_config.h"
namespace webrtc {
// TODO(nisse): Used for the OnSendEncodedImage callback below. The callback
// wants metadata such as size, encode timing, qp, but doesn't need actual
// encoded data. So use some other type to represent that.
class EncodedImage;
// Broken out into a base class, with public inheritance below, only to ease
// unit testing of the internal class OveruseFrameDetector.
class CpuOveruseMetricsObserver {
public:
virtual ~CpuOveruseMetricsObserver() = default;
virtual void OnEncodedFrameTimeMeasured(int encode_duration_ms,
int encode_usage_percent) = 0;
};
class VideoStreamEncoderObserver : public CpuOveruseMetricsObserver {
public:
// Number of resolution and framerate reductions (unset if disabled).
struct AdaptationSteps {
absl::optional<int> num_resolution_reductions = 0;
absl::optional<int> num_framerate_reductions = 0;
};
// TODO(nisse): There are too many enums to represent this. Besides
// this one, see AdaptationObserverInterface::AdaptReason and
// WebRtcVideoChannel::AdaptReason.
enum class AdaptationReason {
kNone, // Used for reset of counters.
kCpu,
kQuality,
};
// TODO(nisse): Duplicates enum EncodedImageCallback::DropReason.
enum class DropReason {
kSource,
kEncoderQueue,
kEncoder,
kMediaOptimization
};
virtual ~VideoStreamEncoderObserver() = default;
virtual void OnIncomingFrame(int width, int height) = 0;
// TODO(nisse): Merge into one callback per encoded frame.
using CpuOveruseMetricsObserver::OnEncodedFrameTimeMeasured;
virtual void OnSendEncodedImage(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_info) = 0;
virtual void OnFrameDropped(DropReason reason) = 0;
// Used to indicate change in content type, which may require a change in
// how stats are collected and set the configured preferred media bitrate.
virtual void OnEncoderReconfigured(
const VideoEncoderConfig& encoder_config,
const std::vector<VideoStream>& streams) = 0;
virtual void OnAdaptationChanged(AdaptationReason reason,
const AdaptationSteps& cpu_steps,
const AdaptationSteps& quality_steps) = 0;
virtual void OnMinPixelLimitReached() = 0;
virtual void OnInitialQualityResolutionAdaptDown() = 0;
virtual void OnSuspendChange(bool is_suspended) = 0;
// TODO(nisse): VideoStreamEncoder wants to query the stats, which makes this
// not a pure observer. GetInputFrameRate is needed for the cpu adaptation, so
// can be deleted if that responsibility is moved out to a VideoStreamAdaptor
// class.
virtual int GetInputFrameRate() const = 0;
};
} // namespace webrtc
#endif // API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2018 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 API_VIDEO_VIDEO_STREAM_ENCODER_SETTINGS_H_
#define API_VIDEO_VIDEO_STREAM_ENCODER_SETTINGS_H_
#include "api/video_codecs/video_encoder_factory.h"
namespace webrtc {
struct VideoStreamEncoderSettings {
VideoStreamEncoderSettings() = default;
// Enables the new method to estimate the cpu load from encoding, used for
// cpu adaptation.
bool experiment_cpu_load_estimator = false;
// Ownership stays with WebrtcVideoEngine (delegated from PeerConnection).
VideoEncoderFactory* encoder_factory = nullptr;
};
} // namespace webrtc
#endif // API_VIDEO_VIDEO_STREAM_ENCODER_SETTINGS_H_

View File

@ -242,6 +242,7 @@ rtc_source_set("video_stream_api") {
"../api:libjingle_peerconnection_api",
"../api:transport_api",
"../api/video:video_frame",
"../api/video:video_stream_encoder",
"../api/video_codecs:video_codecs_api",
"../common_video:common_video",
"../modules/rtp_rtcp:rtp_rtcp_format",

View File

@ -72,7 +72,8 @@ VideoSendStream::Config::Config::~Config() = default;
std::string VideoSendStream::Config::ToString() const {
char buf[2 * 1024];
rtc::SimpleStringBuilder ss(buf);
ss << "{encoder_settings: " << encoder_settings.ToString();
ss << "{encoder_settings: { experiment_cpu_load_estimator: "
<< (encoder_settings.experiment_cpu_load_estimator ? "on" : "off") << "}}";
ss << ", rtp: " << rtp.ToString();
ss << ", rtcp: " << rtcp.ToString();
ss << ", pre_encode_callback: "
@ -87,12 +88,4 @@ std::string VideoSendStream::Config::ToString() const {
return ss.str();
}
std::string VideoSendStream::Config::EncoderSettings::ToString() const {
char buf[1024];
rtc::SimpleStringBuilder ss(buf);
ss << "{encoder_factory: "
<< (encoder_factory ? "(VideoEncoderFactory)" : "(nullptr)");
ss << '}';
return ss.str();
}
} // namespace webrtc

View File

@ -19,6 +19,7 @@
#include "api/call/transport.h"
#include "api/video/video_sink_interface.h"
#include "api/video/video_source_interface.h"
#include "api/video/video_stream_encoder_settings.h"
#include "api/video_codecs/video_encoder_config.h"
#include "api/video_codecs/video_encoder_factory.h"
#include "call/rtp_config.h"
@ -104,17 +105,7 @@ class VideoSendStream {
std::string ToString() const;
struct EncoderSettings {
EncoderSettings() = default;
std::string ToString() const;
// Enables the new method to estimate the cpu load from encoding, used for
// cpu adaptation.
bool experiment_cpu_load_estimator = false;
// Ownership stays with WebrtcVideoEngine (delegated from PeerConnection).
VideoEncoderFactory* encoder_factory = nullptr;
} encoder_settings;
VideoStreamEncoderSettings encoder_settings;
RtpConfig rtp;

View File

@ -14,8 +14,6 @@ rtc_static_library("video") {
"call_stats.h",
"encoder_rtcp_feedback.cc",
"encoder_rtcp_feedback.h",
"overuse_frame_detector.cc",
"overuse_frame_detector.h",
"quality_threshold.cc",
"quality_threshold.h",
"receive_statistics_proxy.cc",
@ -46,8 +44,6 @@ rtc_static_library("video") {
"video_send_stream_impl.h",
"video_stream_decoder.cc",
"video_stream_decoder.h",
"video_stream_encoder.cc",
"video_stream_encoder.h",
]
if (!build_with_chromium && is_clang) {
@ -65,6 +61,7 @@ rtc_static_library("video") {
"../api/video:video_frame",
"../api/video:video_frame_i420",
"../api/video:video_stream_encoder",
"../api/video:video_stream_encoder_create",
"../api/video_codecs:video_codecs_api",
"../call:bitrate_allocator",
"../call:call_interfaces",
@ -137,6 +134,50 @@ rtc_source_set("video_stream_decoder_impl") {
]
}
rtc_source_set("video_stream_encoder_impl") {
visibility = [ "*" ]
# visibility = [ "../api/video:video_stream_encoder_create" ]
# In modules/video_coding, there's a dependency video_coding --> webrtc_vp8
allow_poison = [ "software_video_codecs" ] # TODO(bugs.webrtc.org/7925): Remove.
sources = [
"overuse_frame_detector.cc",
"overuse_frame_detector.h",
"video_stream_encoder.cc",
"video_stream_encoder.h",
]
if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
deps = [
"../api/video:video_bitrate_allocator",
"../api/video:video_frame",
"../api/video:video_frame_i420",
"../api/video:video_stream_encoder",
"../api/video_codecs:video_codecs_api",
"../common_video:common_video",
"../modules/video_coding",
"../modules/video_coding:video_coding_utility",
"../rtc_base:checks",
"../rtc_base:criticalsection",
"../rtc_base:logging",
"../rtc_base:macromagic",
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_event",
"../rtc_base:rtc_numerics",
"../rtc_base:rtc_task_queue",
"../rtc_base:sequenced_task_checker",
"../rtc_base:timeutils",
"../rtc_base/experiments:quality_scaling_experiment",
"../rtc_base/system:fallthrough",
"../system_wrappers:field_trial_api",
"//third_party/abseil-cpp/absl/types:optional",
]
}
if (rtc_include_tests) {
rtc_source_set("video_mocks") {
testonly = true
@ -144,7 +185,7 @@ if (rtc_include_tests) {
"test/mock_video_stream_encoder.h",
]
deps = [
":video",
"../api/video:video_stream_encoder",
"../test:test_support",
]
}
@ -380,6 +421,7 @@ if (rtc_include_tests) {
deps = [
":video",
":video_mocks",
":video_stream_encoder_impl",
"../api/video:video_frame",
"../api/video:video_frame_i420",
"../api/video_codecs:video_codecs_api",

View File

@ -10,8 +10,8 @@
#include "video/encoder_rtcp_feedback.h"
#include "api/video/video_stream_encoder_interface.h"
#include "rtc_base/checks.h"
#include "video/video_stream_encoder.h"
static const int kMinKeyFrameRequestIntervalMs = 300;

View File

@ -552,11 +552,10 @@ void OveruseFrameDetector::StopCheckForOveruse() {
void OveruseFrameDetector::EncodedFrameTimeMeasured(int encode_duration_ms) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
if (!metrics_)
metrics_ = CpuOveruseMetrics();
metrics_->encode_usage_percent = usage_->Value();
encode_usage_percent_ = usage_->Value();
metrics_observer_->OnEncodedFrameTimeMeasured(encode_duration_ms, *metrics_);
metrics_observer_->OnEncodedFrameTimeMeasured(encode_duration_ms,
*encode_usage_percent_);
}
bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const {
@ -583,7 +582,7 @@ void OveruseFrameDetector::ResetAll(int num_pixels) {
usage_->Reset();
last_capture_time_us_ = -1;
num_process_times_ = 0;
metrics_ = absl::nullopt;
encode_usage_percent_ = absl::nullopt;
OnTargetFramerateUpdated(max_framerate_);
}
@ -627,12 +626,13 @@ void OveruseFrameDetector::CheckForOveruse(
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
RTC_DCHECK(observer);
++num_process_times_;
if (num_process_times_ <= options_.min_process_count || !metrics_)
if (num_process_times_ <= options_.min_process_count ||
!encode_usage_percent_)
return;
int64_t now_ms = rtc::TimeMillis();
if (IsOverusing(*metrics_)) {
if (IsOverusing(*encode_usage_percent_)) {
// If the last thing we did was going up, and now have to back down, we need
// to check if this peak was short. If so we should back off to avoid going
// back and forth between this load, the system doesn't seem to handle it.
@ -656,7 +656,7 @@ void OveruseFrameDetector::CheckForOveruse(
++num_overuse_detections_;
observer->AdaptDown(kScaleReasonCpu);
} else if (IsUnderusing(*metrics_, now_ms)) {
} else if (IsUnderusing(*encode_usage_percent_, now_ms)) {
last_rampup_time_ms_ = now_ms;
in_quick_rampup_ = true;
@ -667,7 +667,7 @@ void OveruseFrameDetector::CheckForOveruse(
in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
RTC_LOG(LS_VERBOSE) << " Frame stats: "
<< " encode usage " << metrics_->encode_usage_percent
<< " encode usage " << *encode_usage_percent_
<< " overuse detections " << num_overuse_detections_
<< " rampup delay " << rampup_delay;
}
@ -680,11 +680,10 @@ void OveruseFrameDetector::SetOptions(const CpuOveruseOptions& options) {
usage_ = CreateProcessingUsage(options);
}
bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) {
bool OveruseFrameDetector::IsOverusing(int usage_percent) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
if (metrics.encode_usage_percent >=
options_.high_encode_usage_threshold_percent) {
if (usage_percent >= options_.high_encode_usage_threshold_percent) {
++checks_above_threshold_;
} else {
checks_above_threshold_ = 0;
@ -692,14 +691,12 @@ bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) {
return checks_above_threshold_ >= options_.high_threshold_consecutive_count;
}
bool OveruseFrameDetector::IsUnderusing(const CpuOveruseMetrics& metrics,
int64_t time_now) {
bool OveruseFrameDetector::IsUnderusing(int usage_percent, int64_t time_now) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
if (time_now < last_rampup_time_ms_ + delay)
return false;
return metrics.encode_usage_percent <
options_.low_encode_usage_threshold_percent;
return usage_percent < options_.low_encode_usage_threshold_percent;
}
} // namespace webrtc

View File

@ -15,6 +15,7 @@
#include <memory>
#include "absl/types/optional.h"
#include "api/video/video_stream_encoder_observer.h"
#include "modules/video_coding/utility/quality_scaler.h"
#include "rtc_base/constructormagic.h"
#include "rtc_base/numerics/exp_filter.h"
@ -44,20 +45,6 @@ struct CpuOveruseOptions {
int filter_time_ms; // Time constant for averaging
};
struct CpuOveruseMetrics {
CpuOveruseMetrics() : encode_usage_percent(-1) {}
int encode_usage_percent; // Average encode time divided by the average time
// difference between incoming captured frames.
};
class CpuOveruseMetricsObserver {
public:
virtual ~CpuOveruseMetricsObserver() {}
virtual void OnEncodedFrameTimeMeasured(int encode_duration_ms,
const CpuOveruseMetrics& metrics) = 0;
};
// Use to detect system overuse based on the send-side processing time of
// incoming frames. All methods must be called on a single task queue but it can
// be created and destroyed on an arbitrary thread.
@ -124,8 +111,8 @@ class OveruseFrameDetector {
class CheckOveruseTask;
void EncodedFrameTimeMeasured(int encode_duration_ms);
bool IsOverusing(const CpuOveruseMetrics& metrics);
bool IsUnderusing(const CpuOveruseMetrics& metrics, int64_t time_now);
bool IsOverusing(int encode_usage_percent);
bool IsUnderusing(int encode_usage_percent, int64_t time_now);
bool FrameTimeoutDetected(int64_t now) const;
bool FrameSizeChanged(int num_pixels) const;
@ -141,7 +128,7 @@ class OveruseFrameDetector {
// Stats metrics.
CpuOveruseMetricsObserver* const metrics_observer_;
absl::optional<CpuOveruseMetrics> metrics_ RTC_GUARDED_BY(task_checker_);
absl::optional<int> encode_usage_percent_ RTC_GUARDED_BY(task_checker_);
int64_t num_process_times_ RTC_GUARDED_BY(task_checker_);

View File

@ -77,8 +77,8 @@ class OveruseFrameDetectorTest : public ::testing::Test,
}
void OnEncodedFrameTimeMeasured(int encode_time_ms,
const CpuOveruseMetrics& metrics) override {
metrics_ = metrics;
int encode_usage_percent) override {
encode_usage_percent_ = encode_usage_percent;
}
int InitialUsage() {
@ -165,7 +165,7 @@ class OveruseFrameDetectorTest : public ::testing::Test,
overuse_detector_->CheckForOveruse(observer_);
}
int UsagePercent() { return metrics_.encode_usage_percent; }
int UsagePercent() { return encode_usage_percent_; }
int64_t OveruseProcessingTimeLimitForFramerate(int fps) const {
int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
@ -186,7 +186,7 @@ class OveruseFrameDetectorTest : public ::testing::Test,
MockCpuOveruseObserver mock_observer_;
AdaptationObserverInterface* observer_;
std::unique_ptr<OveruseFrameDetectorUnderTest> overuse_detector_;
CpuOveruseMetrics metrics_;
int encode_usage_percent_ = -1;
static const auto reason_ = AdaptationObserverInterface::AdaptReason::kCpu;
};

View File

@ -653,14 +653,13 @@ void SendStatisticsProxy::OnEncoderReconfigured(
streams.empty() ? 0 : (streams.back().width * streams.back().height);
}
void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
int encode_time_ms,
const CpuOveruseMetrics& metrics) {
void SendStatisticsProxy::OnEncodedFrameTimeMeasured(int encode_time_ms,
int encode_usage_percent) {
rtc::CritScope lock(&crit_);
uma_container_->encode_time_counter_.Add(encode_time_ms);
encode_time_.Apply(1.0f, encode_time_ms);
stats_.avg_encode_time_ms = round(encode_time_.filtered());
stats_.encode_usage_percent = metrics.encode_usage_percent;
stats_.encode_usage_percent = encode_usage_percent;
}
void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
@ -960,6 +959,11 @@ void SendStatisticsProxy::OnSendEncodedImage(
}
}
int SendStatisticsProxy::GetInputFrameRate() const {
rtc::CritScope lock(&crit_);
return round(uma_container_->input_frame_rate_tracker_.ComputeRate());
}
int SendStatisticsProxy::GetSendFrameRate() const {
rtc::CritScope lock(&crit_);
return round(encoded_frame_rate_tracker_.ComputeRate());
@ -982,62 +986,55 @@ void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
}
}
void SendStatisticsProxy::OnFrameDroppedBySource() {
void SendStatisticsProxy::OnFrameDropped(DropReason reason) {
rtc::CritScope lock(&crit_);
++stats_.frames_dropped_by_capturer;
switch (reason) {
case DropReason::kSource:
++stats_.frames_dropped_by_capturer;
break;
case DropReason::kEncoderQueue:
++stats_.frames_dropped_by_encoder_queue;
break;
case DropReason::kEncoder:
++stats_.frames_dropped_by_encoder;
break;
case DropReason::kMediaOptimization:
++stats_.frames_dropped_by_rate_limiter;
break;
}
}
void SendStatisticsProxy::OnFrameDroppedInEncoderQueue() {
void SendStatisticsProxy::OnAdaptationChanged(
AdaptationReason reason,
const AdaptationSteps& cpu_counts,
const AdaptationSteps& quality_counts) {
rtc::CritScope lock(&crit_);
++stats_.frames_dropped_by_encoder_queue;
}
void SendStatisticsProxy::OnFrameDroppedByEncoder() {
rtc::CritScope lock(&crit_);
++stats_.frames_dropped_by_encoder;
}
void SendStatisticsProxy::OnFrameDroppedByMediaOptimizations() {
rtc::CritScope lock(&crit_);
++stats_.frames_dropped_by_rate_limiter;
}
void SendStatisticsProxy::SetAdaptationStats(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts) {
rtc::CritScope lock(&crit_);
SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
UpdateAdaptationStats(cpu_counts, quality_counts);
}
void SendStatisticsProxy::OnCpuAdaptationChanged(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts) {
rtc::CritScope lock(&crit_);
++stats_.number_of_cpu_adapt_changes;
UpdateAdaptationStats(cpu_counts, quality_counts);
}
void SendStatisticsProxy::OnQualityAdaptationChanged(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts) {
rtc::CritScope lock(&crit_);
TryUpdateInitialQualityResolutionAdaptUp(quality_counts);
++stats_.number_of_quality_adapt_changes;
switch (reason) {
case AdaptationReason::kNone:
SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
break;
case AdaptationReason::kCpu:
++stats_.number_of_cpu_adapt_changes;
break;
case AdaptationReason::kQuality:
TryUpdateInitialQualityResolutionAdaptUp(quality_counts);
++stats_.number_of_quality_adapt_changes;
break;
}
UpdateAdaptationStats(cpu_counts, quality_counts);
}
void SendStatisticsProxy::UpdateAdaptationStats(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts) {
cpu_downscales_ = cpu_counts.resolution;
quality_downscales_ = quality_counts.resolution;
const AdaptationSteps& cpu_counts,
const AdaptationSteps& quality_counts) {
cpu_downscales_ = cpu_counts.num_resolution_reductions.value_or(-1);
quality_downscales_ = quality_counts.num_resolution_reductions.value_or(-1);
stats_.cpu_limited_resolution = cpu_counts.resolution > 0;
stats_.cpu_limited_framerate = cpu_counts.fps > 0;
stats_.bw_limited_resolution = quality_counts.resolution > 0;
stats_.bw_limited_framerate = quality_counts.fps > 0;
stats_.cpu_limited_resolution = cpu_counts.num_resolution_reductions > 0;
stats_.cpu_limited_framerate = cpu_counts.num_framerate_reductions > 0;
stats_.bw_limited_resolution = quality_counts.num_resolution_reductions > 0;
stats_.bw_limited_framerate = quality_counts.num_framerate_reductions > 0;
}
// TODO(asapersson): Include fps changes.
@ -1047,12 +1044,13 @@ void SendStatisticsProxy::OnInitialQualityResolutionAdaptDown() {
}
void SendStatisticsProxy::TryUpdateInitialQualityResolutionAdaptUp(
const VideoStreamEncoder::AdaptCounts& quality_counts) {
const AdaptationSteps& quality_counts) {
if (uma_container_->initial_quality_changes_.down == 0)
return;
if (quality_downscales_ > 0 &&
quality_counts.resolution < quality_downscales_) {
quality_counts.num_resolution_reductions.value_or(-1) <
quality_downscales_) {
// Adapting up in quality.
if (uma_container_->initial_quality_changes_.down >
uma_container_->initial_quality_changes_.up) {
@ -1061,10 +1059,9 @@ void SendStatisticsProxy::TryUpdateInitialQualityResolutionAdaptUp(
}
}
void SendStatisticsProxy::SetAdaptTimer(
const VideoStreamEncoder::AdaptCounts& counts,
StatsTimer* timer) {
if (counts.resolution >= 0 || counts.fps >= 0) {
void SendStatisticsProxy::SetAdaptTimer(const AdaptationSteps& counts,
StatsTimer* timer) {
if (counts.num_resolution_reductions || counts.num_framerate_reductions) {
// Adaptation enabled.
if (!stats_.suspended)
timer->Start(clock_->TimeInMilliseconds());

View File

@ -16,6 +16,7 @@
#include <string>
#include <vector>
#include "api/video/video_stream_encoder_observer.h"
#include "call/video_send_stream.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/video_coding/include/video_codec_interface.h"
@ -25,14 +26,12 @@
#include "rtc_base/ratetracker.h"
#include "rtc_base/thread_annotations.h"
#include "system_wrappers/include/clock.h"
#include "video/overuse_frame_detector.h"
#include "video/report_block_stats.h"
#include "video/stats_counter.h"
#include "video/video_stream_encoder.h"
namespace webrtc {
class SendStatisticsProxy : public CpuOveruseMetricsObserver,
class SendStatisticsProxy : public VideoStreamEncoderObserver,
public RtcpStatisticsCallback,
public RtcpPacketTypeCounterObserver,
public StreamDataCountersCallback,
@ -53,44 +52,37 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
virtual VideoSendStream::Stats GetStats();
void OnSendEncodedImage(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_info);
const CodecSpecificInfo* codec_info) override;
// Used to update incoming frame rate.
void OnIncomingFrame(int width, int height);
void OnIncomingFrame(int width, int height) override;
// Dropped frame stats.
void OnFrameDroppedBySource();
void OnFrameDroppedInEncoderQueue();
void OnFrameDroppedByEncoder();
void OnFrameDroppedByMediaOptimizations();
void OnFrameDropped(DropReason) override;
// Adaptation stats.
void SetAdaptationStats(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts);
void OnCpuAdaptationChanged(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts);
void OnQualityAdaptationChanged(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts);
void OnMinPixelLimitReached();
void OnInitialQualityResolutionAdaptDown();
void OnAdaptationChanged(AdaptationReason reason,
const AdaptationSteps& cpu_counts,
const AdaptationSteps& quality_counts) override;
void OnSuspendChange(bool is_suspended);
void OnMinPixelLimitReached() override;
void OnInitialQualityResolutionAdaptDown() override;
void OnSuspendChange(bool is_suspended) override;
void OnInactiveSsrc(uint32_t ssrc);
// Used to indicate change in content type, which may require a change in
// how stats are collected.
void OnEncoderReconfigured(const VideoEncoderConfig& encoder_config,
const std::vector<VideoStream>& streams);
const std::vector<VideoStream>& streams) override;
// Used to update the encoder target rate.
void OnSetEncoderTargetRate(uint32_t bitrate_bps);
// Implements CpuOveruseMetricsObserver.
void OnEncodedFrameTimeMeasured(int encode_time_ms,
const CpuOveruseMetrics& metrics) override;
int encode_usage_percent) override;
int GetInputFrameRate() const override;
int GetSendFrameRate() const;
protected:
@ -216,14 +208,13 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
VideoSendStream::StreamStats* GetStatsEntry(uint32_t ssrc)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void SetAdaptTimer(const VideoStreamEncoder::AdaptCounts& counts,
StatsTimer* timer) RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void UpdateAdaptationStats(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts)
void SetAdaptTimer(const AdaptationSteps& counts, StatsTimer* timer)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void UpdateAdaptationStats(const AdaptationSteps& cpu_counts,
const AdaptationSteps& quality_counts)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void TryUpdateInitialQualityResolutionAdaptUp(
const VideoStreamEncoder::AdaptCounts& quality_counts)
const AdaptationSteps& quality_counts)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void UpdateEncoderFallbackStats(const CodecSpecificInfo* codec_info,

View File

@ -309,13 +309,13 @@ TEST_F(SendStatisticsProxyTest, SendSideDelay) {
TEST_F(SendStatisticsProxyTest, OnEncodedFrameTimeMeasured) {
const int kEncodeTimeMs = 11;
CpuOveruseMetrics metrics;
metrics.encode_usage_percent = 80;
statistics_proxy_->OnEncodedFrameTimeMeasured(kEncodeTimeMs, metrics);
int encode_usage_percent = 80;
statistics_proxy_->OnEncodedFrameTimeMeasured(kEncodeTimeMs,
encode_usage_percent);
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
EXPECT_EQ(kEncodeTimeMs, stats.avg_encode_time_ms);
EXPECT_EQ(metrics.encode_usage_percent, stats.encode_usage_percent);
EXPECT_EQ(encode_usage_percent, stats.encode_usage_percent);
}
TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesFramesEncoded) {
@ -350,72 +350,92 @@ TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) {
}
TEST_F(SendStatisticsProxyTest, GetCpuAdaptationStats) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
cpu_counts.fps = 1;
cpu_counts.resolution = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_framerate_reductions = 1;
cpu_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
cpu_counts.fps = 0;
cpu_counts.resolution = 1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_framerate_reductions = 0;
cpu_counts.num_resolution_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
cpu_counts.fps = 1;
cpu_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_framerate_reductions = 1;
cpu_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
cpu_counts.fps = -1;
cpu_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_framerate_reductions = absl::nullopt;
cpu_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
}
TEST_F(SendStatisticsProxyTest, GetQualityAdaptationStats) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
quality_counts.fps = 1;
quality_counts.resolution = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = 1;
quality_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
quality_counts.fps = 0;
quality_counts.resolution = 1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = 0;
quality_counts.num_resolution_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
quality_counts.fps = 1;
quality_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = 1;
quality_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
quality_counts.fps = -1;
quality_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = absl::nullopt;
quality_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
}
TEST_F(SendStatisticsProxyTest, GetStatsReportsCpuAdaptChanges) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
cpu_counts.resolution = 1;
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
cpu_counts.num_resolution_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
cpu_counts.resolution = 2;
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
cpu_counts.num_resolution_reductions = 2;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
@ -423,18 +443,22 @@ TEST_F(SendStatisticsProxyTest, GetStatsReportsCpuAdaptChanges) {
}
TEST_F(SendStatisticsProxyTest, GetStatsReportsQualityAdaptChanges) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
quality_counts.fps = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
quality_counts.fps = 0;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
@ -456,9 +480,11 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_MinRuntimeNotPassed) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Min runtime has not passed.
fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
statistics_proxy_.reset();
@ -471,9 +497,11 @@ TEST_F(SendStatisticsProxyTest, ZeroAdaptChangesReported) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Min runtime has passed.
fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
statistics_proxy_.reset();
@ -489,11 +517,15 @@ TEST_F(SendStatisticsProxyTest, CpuAdaptChangesReported) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
@ -504,11 +536,15 @@ TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChange) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Adapt changes: 1 (1 initial) = 0, elapsed time: 10 sec => 0 per minute.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
@ -522,18 +558,26 @@ TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChanges) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Adapt changes: 3 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
quality_counts.resolution = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 2;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = 2;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 3;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = 3;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
EXPECT_EQ(1,
@ -546,11 +590,15 @@ TEST_F(SendStatisticsProxyTest, InitialQualityAdaptChangesNotExcludedOnError) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Adapt changes: 1 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
fake_clock_.AdvanceTimeMilliseconds(10000);
@ -565,28 +613,46 @@ TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownAndUpChanges) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Adapt changes: 8 (4 initial) = 4, elapsed time: 10 sec => 24 per minute.
quality_counts.resolution = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 2;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = 2;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 3;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.fps = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.fps = 0;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.resolution = 2; // Initial resolution up.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.resolution = 1; // Initial resolution up.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.resolution = 0;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = 3;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
quality_counts.num_framerate_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
quality_counts.num_framerate_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
quality_counts.num_resolution_reductions = 2; // Initial resolution up.
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
quality_counts.num_resolution_reductions = 1; // Initial resolution up.
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
quality_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
@ -601,41 +667,61 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsExcludesDisabledTime) {
UpdateDataCounters(kFirstSsrc);
// Disable quality adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
quality_counts.fps = -1;
quality_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
quality_counts.num_framerate_reductions = absl::nullopt;
quality_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
// Enable quality adaptation.
// Adapt changes: 2, elapsed time: 20 sec.
quality_counts.fps = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(5000);
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(9000);
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(6000);
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
// Disable quality adaptation.
quality_counts.fps = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
quality_counts.num_framerate_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(30000);
// Enable quality adaptation.
// Adapt changes: 1, elapsed time: 10 sec.
quality_counts.resolution = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
// Disable quality adaptation.
quality_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
quality_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(5000);
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(20000);
// Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
@ -669,13 +755,19 @@ TEST_F(SendStatisticsProxyTest, QualityAdaptChangesStatsExcludesSuspendedTime) {
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
// Adapt changes: 2, elapsed time: 20 sec.
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(20000);
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
// Suspend and resume video.
statistics_proxy_->OnSuspendChange(true);
@ -683,7 +775,9 @@ TEST_F(SendStatisticsProxyTest, QualityAdaptChangesStatsExcludesSuspendedTime) {
statistics_proxy_->OnSuspendChange(false);
// Adapt changes: 1, elapsed time: 10 sec.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
// Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
@ -703,21 +797,27 @@ TEST_F(SendStatisticsProxyTest, CpuAdaptChangesStatsExcludesSuspendedTime) {
fake_clock_.AdvanceTimeMilliseconds(30000);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
// Adapt changes: 1, elapsed time: 20 sec.
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
// Video not suspended, stats time already started.
statistics_proxy_->OnSuspendChange(false);
fake_clock_.AdvanceTimeMilliseconds(10000);
// Disable adaptation.
cpu_counts.fps = -1;
cpu_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_framerate_reductions = absl::nullopt;
cpu_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(30000);
// Suspend and resume video, stats time not started when scaling not enabled.
@ -728,11 +828,15 @@ TEST_F(SendStatisticsProxyTest, CpuAdaptChangesStatsExcludesSuspendedTime) {
// Enable adaptation.
// Adapt changes: 1, elapsed time: 10 sec.
cpu_counts.fps = 0;
cpu_counts.resolution = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_framerate_reductions = 0;
cpu_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
// Adapt changes: 2, elapsed time: 30 sec => 4 per minute.
statistics_proxy_.reset();
@ -748,16 +852,20 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsNotStartedIfVideoSuspended) {
statistics_proxy_->OnSuspendChange(true);
// Enable adaptation, stats time not started when suspended.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
// Resume video, stats time started.
// Adapt changes: 1, elapsed time: 10 sec.
statistics_proxy_->OnSuspendChange(false);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
// Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
statistics_proxy_.reset();
@ -768,15 +876,19 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsNotStartedIfVideoSuspended) {
TEST_F(SendStatisticsProxyTest, AdaptChangesStatsRestartsOnFirstSentPacket) {
// Send first packet, adaptation enabled.
// Elapsed time before first packet is sent should be excluded.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
UpdateDataCounters(kFirstSsrc);
// Adapt changes: 1, elapsed time: 10 sec.
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
UpdateDataCounters(kFirstSsrc);
// Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
@ -789,13 +901,17 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsRestartsOnFirstSentPacket) {
TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) {
// Enable and disable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(60000);
cpu_counts.fps = -1;
cpu_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_framerate_reductions = absl::nullopt;
cpu_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Send first packet, scaling disabled.
// Elapsed time before first packet is sent should be excluded.
@ -803,14 +919,18 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) {
fake_clock_.AdvanceTimeMilliseconds(60000);
// Enable adaptation.
cpu_counts.resolution = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
cpu_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
UpdateDataCounters(kFirstSsrc);
// Adapt changes: 1, elapsed time: 20 sec.
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
// Adapt changes: 1, elapsed time: 20 sec => 3 per minute.
statistics_proxy_.reset();
@ -821,16 +941,22 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) {
TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) {
// First RTP packet sent, cpu adaptation enabled.
UpdateDataCounters(kFirstSsrc);
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
quality_counts.fps = -1;
quality_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
quality_counts.num_framerate_reductions = absl::nullopt;
quality_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Adapt changes: 2, elapsed time: 15 sec => 8 per minute.
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(6000);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(9000);
// Switch content type, real-time stats should be updated.
@ -844,13 +970,23 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) {
// First RTP packet sent, scaling enabled.
UpdateDataCounters(kFirstSsrc);
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
// Adapt changes: 4, elapsed time: 120 sec => 2 per minute.
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
fake_clock_.AdvanceTimeMilliseconds(120000);
statistics_proxy_.reset();
@ -1007,10 +1143,12 @@ TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) {
}
TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramNotUpdatedWhenDisabled) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
cpu_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
cpu_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
@ -1021,16 +1159,20 @@ TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramNotUpdatedWhenDisabled) {
}
TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramUpdated) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
cpu_counts.resolution = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
cpu_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
cpu_counts.resolution = 1;
statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts);
cpu_counts.num_resolution_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
quality_counts);
for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
@ -1388,10 +1530,12 @@ TEST_F(SendStatisticsProxyTest,
TEST_F(SendStatisticsProxyTest,
QualityLimitedHistogramsNotUpdatedWhenDisabled) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
quality_counts.resolution = -1;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
quality_counts.num_resolution_reductions = absl::nullopt;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EncodedImage encoded_image;
for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
@ -1406,10 +1550,12 @@ TEST_F(SendStatisticsProxyTest,
TEST_F(SendStatisticsProxyTest,
QualityLimitedHistogramsUpdatedWhenEnabled_NoResolutionDownscale) {
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
quality_counts.resolution = 0;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
quality_counts.num_resolution_reductions = 0;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EncodedImage encoded_image;
for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
@ -1428,10 +1574,12 @@ TEST_F(SendStatisticsProxyTest,
TEST_F(SendStatisticsProxyTest,
QualityLimitedHistogramsUpdatedWhenEnabled_TwoResolutionDownscales) {
const int kDownscales = 2;
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
quality_counts.resolution = kDownscales;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
quality_counts.num_resolution_reductions = kDownscales;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
quality_counts);
EncodedImage encoded_image;
for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
@ -1507,10 +1655,12 @@ TEST_F(SendStatisticsProxyTest, GetStatsReportsBandwidthLimitedResolution) {
EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
// Resolution scaled due to quality.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
quality_counts.resolution = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
SendStatisticsProxy::AdaptationSteps cpu_counts;
SendStatisticsProxy::AdaptationSteps quality_counts;
quality_counts.num_resolution_reductions = 1;
statistics_proxy_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
quality_counts);
statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
}

View File

@ -10,8 +10,8 @@
#ifndef VIDEO_TEST_MOCK_VIDEO_STREAM_ENCODER_H_
#define VIDEO_TEST_MOCK_VIDEO_STREAM_ENCODER_H_
#include "api/video/video_stream_encoder_interface.h"
#include "test/gmock.h"
#include "video/video_stream_encoder.h"
namespace webrtc {

View File

@ -11,6 +11,7 @@
#include <utility>
#include "api/video/video_stream_encoder_create.h"
#include "modules/rtp_rtcp/source/rtp_sender.h"
#include "rtc_base/logging.h"
#include "video/video_send_stream_impl.h"
@ -77,10 +78,9 @@ VideoSendStream::VideoSendStream(
content_type_(encoder_config.content_type) {
RTC_DCHECK(config_.encoder_settings.encoder_factory);
video_stream_encoder_ = absl::make_unique<VideoStreamEncoder>(
num_cpu_cores, &stats_proxy_, config_.encoder_settings,
config_.pre_encode_callback,
absl::make_unique<OveruseFrameDetector>(&stats_proxy_));
video_stream_encoder_ = CreateVideoStreamEncoder(num_cpu_cores, &stats_proxy_,
config_.encoder_settings,
config_.pre_encode_callback);
// TODO(srte): Initialization should not be done posted on a task queue.
// Note that the posted task must not outlive this scope since the closure
// references local variables.

View File

@ -16,6 +16,7 @@
#include <vector>
#include "api/fec_controller.h"
#include "api/video/video_stream_encoder_interface.h"
#include "call/bitrate_allocator.h"
#include "call/video_receive_stream.h"
#include "call/video_send_stream.h"
@ -25,7 +26,6 @@
#include "rtc_base/task_queue.h"
#include "video/send_delay_stats.h"
#include "video/send_statistics_proxy.h"
#include "video/video_stream_encoder.h"
namespace webrtc {
namespace test {
@ -36,6 +36,7 @@ class CallStats;
class SendSideCongestionController;
class IvfFileWriter;
class ProcessThread;
class RateLimiter;
class RtpRtcp;
class RtpTransportControllerSendInterface;
class RtcEventLog;
@ -113,7 +114,7 @@ class VideoSendStream : public webrtc::VideoSendStream {
const VideoSendStream::Config config_;
const VideoEncoderConfig::ContentType content_type_;
std::unique_ptr<VideoSendStreamImpl> send_stream_;
std::unique_ptr<VideoStreamEncoder> video_stream_encoder_;
std::unique_ptr<VideoStreamEncoderInterface> video_stream_encoder_;
};
} // namespace internal

View File

@ -16,6 +16,7 @@
#include <vector>
#include "api/video/video_bitrate_allocator.h"
#include "api/video/video_stream_encoder_interface.h"
#include "call/bitrate_allocator.h"
#include "call/rtp_video_sender_interface.h"
#include "common_types.h" // NOLINT(build/include)
@ -27,7 +28,6 @@
#include "video/send_delay_stats.h"
#include "video/send_statistics_proxy.h"
#include "video/video_send_stream.h"
#include "video/video_stream_encoder.h"
namespace webrtc {
namespace internal {
@ -42,7 +42,7 @@ namespace internal {
class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
public webrtc::OverheadObserver,
public webrtc::VCMProtectionCallback,
public VideoStreamEncoder::EncoderSink,
public VideoStreamEncoderInterface::EncoderSink,
public VideoBitrateAllocationObserver,
public webrtc::PacketFeedbackObserver {
public:

View File

@ -16,11 +16,9 @@
#include <utility>
#include "api/video/i420_buffer.h"
#include "api/video/video_bitrate_allocator.h"
#include "common_video/include/video_frame.h"
#include "modules/video_coding/include/video_codec_initializer.h"
#include "modules/video_coding/include/video_coding.h"
#include "modules/video_coding/include/video_coding_defines.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/experiments/quality_scaling_experiment.h"
@ -30,7 +28,6 @@
#include "rtc_base/timeutils.h"
#include "rtc_base/trace_event.h"
#include "video/overuse_frame_detector.h"
#include "video/send_statistics_proxy.h"
namespace webrtc {
@ -86,7 +83,7 @@ bool IsFramerateScalingEnabled(DegradationPreference degradation_preference) {
// out). This should effectively turn off CPU adaptations for systems that
// remotely cope with the load right now.
CpuOveruseOptions GetCpuOveruseOptions(
const VideoSendStream::Config::EncoderSettings& settings,
const VideoStreamEncoderSettings& settings,
bool full_overuse_time) {
CpuOveruseOptions options;
@ -315,8 +312,8 @@ class VideoStreamEncoder::VideoSourceProxy {
VideoStreamEncoder::VideoStreamEncoder(
uint32_t number_of_cores,
SendStatisticsProxy* stats_proxy,
const VideoSendStream::Config::EncoderSettings& settings,
VideoStreamEncoderObserver* encoder_stats_observer,
const VideoStreamEncoderSettings& settings,
rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback,
std::unique_ptr<OveruseFrameDetector> overuse_detector)
: shutdown_event_(true /* manual_reset */, false),
@ -328,7 +325,7 @@ VideoStreamEncoder::VideoStreamEncoder(
settings_(settings),
video_sender_(Clock::GetRealTimeClock(), this),
overuse_detector_(std::move(overuse_detector)),
stats_proxy_(stats_proxy),
encoder_stats_observer_(encoder_stats_observer),
pre_encode_callback_(pre_encode_callback),
max_framerate_(-1),
pending_encoder_reconfiguration_(false),
@ -348,7 +345,7 @@ VideoStreamEncoder::VideoStreamEncoder(
dropped_frame_count_(0),
bitrate_observer_(nullptr),
encoder_queue_("EncoderQueue") {
RTC_DCHECK(stats_proxy);
RTC_DCHECK(encoder_stats_observer);
RTC_DCHECK(overuse_detector_);
}
@ -574,7 +571,7 @@ void VideoStreamEncoder::ReconfigureEncoder() {
video_sender_.UpdateChannelParameters(rate_allocator_.get(),
bitrate_observer_);
stats_proxy_->OnEncoderReconfigured(encoder_config_, streams);
encoder_stats_observer_->OnEncoderReconfigured(encoder_config_, streams);
pending_encoder_reconfiguration_ = false;
@ -623,8 +620,9 @@ void VideoStreamEncoder::ConfigureQualityScaler() {
initial_rampup_ = kMaxInitialFramedrop;
}
stats_proxy_->SetAdaptationStats(GetActiveCounts(kCpu),
GetActiveCounts(kQuality));
encoder_stats_observer_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kNone,
GetActiveCounts(kCpu), GetActiveCounts(kQuality));
}
void VideoStreamEncoder::OnFrame(const VideoFrame& video_frame) {
@ -680,8 +678,8 @@ void VideoStreamEncoder::OnFrame(const VideoFrame& video_frame) {
encoder_queue_.PostTask(
[this, incoming_frame, post_time_us, log_stats]() {
RTC_DCHECK_RUN_ON(&encoder_queue_);
stats_proxy_->OnIncomingFrame(incoming_frame.width(),
incoming_frame.height());
encoder_stats_observer_->OnIncomingFrame(incoming_frame.width(),
incoming_frame.height());
++captured_frame_count_;
const int posted_frames_waiting_for_encode =
posted_frames_waiting_for_encode_.fetch_sub(1);
@ -693,7 +691,8 @@ void VideoStreamEncoder::OnFrame(const VideoFrame& video_frame) {
RTC_LOG(LS_VERBOSE)
<< "Incoming frame dropped due to that the encoder is blocked.";
++dropped_frame_count_;
stats_proxy_->OnFrameDroppedInEncoderQueue();
encoder_stats_observer_->OnFrameDropped(
VideoStreamEncoderObserver::DropReason::kEncoderQueue);
}
if (log_stats) {
RTC_LOG(LS_INFO) << "Number of frames: captured "
@ -708,7 +707,8 @@ void VideoStreamEncoder::OnFrame(const VideoFrame& video_frame) {
}
void VideoStreamEncoder::OnDiscardedFrame() {
stats_proxy_->OnFrameDroppedBySource();
encoder_stats_observer_->OnFrameDropped(
VideoStreamEncoderObserver::DropReason::kSource);
}
bool VideoStreamEncoder::EncoderPaused() const {
@ -780,7 +780,7 @@ void VideoStreamEncoder::MaybeEncodeVideoFrame(const VideoFrame& video_frame,
int count = GetConstAdaptCounter().ResolutionCount(kQuality);
AdaptDown(kQuality);
if (GetConstAdaptCounter().ResolutionCount(kQuality) > count) {
stats_proxy_->OnInitialQualityResolutionAdaptDown();
encoder_stats_observer_->OnInitialQualityResolutionAdaptDown();
}
++initial_rampup_;
// Storing references to a native buffer risks blocking frame capture.
@ -869,7 +869,8 @@ EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage(
// Encoded is called on whatever thread the real encoder implementation run
// on. In the case of hardware encoders, there might be several encoders
// running in parallel on different threads.
stats_proxy_->OnSendEncodedImage(encoded_image, codec_specific_info);
encoder_stats_observer_->OnSendEncodedImage(encoded_image,
codec_specific_info);
EncodedImageCallback::Result result =
sink_->OnEncodedImage(encoded_image, codec_specific_info, fragmentation);
@ -904,7 +905,8 @@ EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage(
void VideoStreamEncoder::OnDroppedFrame(DropReason reason) {
switch (reason) {
case DropReason::kDroppedByMediaOptimizations:
stats_proxy_->OnFrameDroppedByMediaOptimizations();
encoder_stats_observer_->OnFrameDropped(
VideoStreamEncoderObserver::DropReason::kMediaOptimization);
encoder_queue_.PostTask([this] {
RTC_DCHECK_RUN_ON(&encoder_queue_);
if (quality_scaler_)
@ -912,7 +914,8 @@ void VideoStreamEncoder::OnDroppedFrame(DropReason reason) {
});
break;
case DropReason::kDroppedByEncoder:
stats_proxy_->OnFrameDroppedByEncoder();
encoder_stats_observer_->OnFrameDropped(
VideoStreamEncoderObserver::DropReason::kEncoder);
encoder_queue_.PostTask([this] {
RTC_DCHECK_RUN_ON(&encoder_queue_);
if (quality_scaler_)
@ -952,7 +955,7 @@ void VideoStreamEncoder::OnBitrateUpdated(uint32_t bitrate_bps,
if (video_suspension_changed) {
RTC_LOG(LS_INFO) << "Video suspend state changed to: "
<< (video_is_suspended ? "suspended" : "not suspended");
stats_proxy_->OnSuspendChange(video_is_suspended);
encoder_stats_observer_->OnSuspendChange(video_is_suspended);
}
if (video_suspension_changed && !video_is_suspended && pending_frame_ &&
!DropDueToSize(pending_frame_->size())) {
@ -979,7 +982,7 @@ void VideoStreamEncoder::AdaptDown(AdaptReason reason) {
RTC_DCHECK_RUN_ON(&encoder_queue_);
AdaptationRequest adaptation_request = {
last_frame_info_->pixel_count(),
stats_proxy_->GetStats().input_frame_rate,
encoder_stats_observer_->GetInputFrameRate(),
AdaptationRequest::Mode::kAdaptDown};
bool downgrade_requested =
@ -1034,7 +1037,7 @@ void VideoStreamEncoder::AdaptDown(AdaptReason reason) {
encoder_->GetScalingSettings().min_pixels_per_frame,
&min_pixels_reached)) {
if (min_pixels_reached)
stats_proxy_->OnMinPixelLimitReached();
encoder_stats_observer_->OnMinPixelLimitReached();
return;
}
GetAdaptCounter().IncrementResolution(reason);
@ -1074,7 +1077,7 @@ void VideoStreamEncoder::AdaptUp(AdaptReason reason) {
AdaptationRequest adaptation_request = {
last_frame_info_->pixel_count(),
stats_proxy_->GetStats().input_frame_rate,
encoder_stats_observer_->GetInputFrameRate(),
AdaptationRequest::Mode::kAdaptUp};
bool adapt_up_requested =
@ -1150,38 +1153,41 @@ void VideoStreamEncoder::AdaptUp(AdaptReason reason) {
RTC_LOG(LS_INFO) << adapt_counter.ToString();
}
// TODO(nisse): Delete, once AdaptReason and AdaptationReason are merged.
void VideoStreamEncoder::UpdateAdaptationStats(AdaptReason reason) {
switch (reason) {
case kCpu:
stats_proxy_->OnCpuAdaptationChanged(GetActiveCounts(kCpu),
GetActiveCounts(kQuality));
encoder_stats_observer_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kCpu,
GetActiveCounts(kCpu), GetActiveCounts(kQuality));
break;
case kQuality:
stats_proxy_->OnQualityAdaptationChanged(GetActiveCounts(kCpu),
GetActiveCounts(kQuality));
encoder_stats_observer_->OnAdaptationChanged(
VideoStreamEncoderObserver::AdaptationReason::kQuality,
GetActiveCounts(kCpu), GetActiveCounts(kQuality));
break;
}
}
VideoStreamEncoder::AdaptCounts VideoStreamEncoder::GetActiveCounts(
VideoStreamEncoderObserver::AdaptationSteps VideoStreamEncoder::GetActiveCounts(
AdaptReason reason) {
VideoStreamEncoder::AdaptCounts counts =
VideoStreamEncoderObserver::AdaptationSteps counts =
GetConstAdaptCounter().Counts(reason);
switch (reason) {
case kCpu:
if (!IsFramerateScalingEnabled(degradation_preference_))
counts.fps = -1;
counts.num_framerate_reductions = absl::nullopt;
if (!IsResolutionScalingEnabled(degradation_preference_))
counts.resolution = -1;
counts.num_resolution_reductions = absl::nullopt;
break;
case kQuality:
if (!IsFramerateScalingEnabled(degradation_preference_) ||
!quality_scaler_) {
counts.fps = -1;
counts.num_framerate_reductions = absl::nullopt;
}
if (!IsResolutionScalingEnabled(degradation_preference_) ||
!quality_scaler_) {
counts.resolution = -1;
counts.num_resolution_reductions = absl::nullopt;
}
break;
}
@ -1213,11 +1219,11 @@ std::string VideoStreamEncoder::AdaptCounter::ToString() const {
return ss.str();
}
VideoStreamEncoder::AdaptCounts VideoStreamEncoder::AdaptCounter::Counts(
int reason) const {
AdaptCounts counts;
counts.fps = fps_counters_[reason];
counts.resolution = resolution_counters_[reason];
VideoStreamEncoderObserver::AdaptationSteps
VideoStreamEncoder::AdaptCounter::Counts(int reason) const {
VideoStreamEncoderObserver::AdaptationSteps counts;
counts.num_framerate_reductions = fps_counters_[reason];
counts.num_resolution_reductions = resolution_counters_[reason];
return counts;
}

View File

@ -21,23 +21,19 @@
#include "api/video/video_rotation.h"
#include "api/video/video_sink_interface.h"
#include "api/video/video_stream_encoder_interface.h"
#include "api/video/video_stream_encoder_observer.h"
#include "api/video/video_stream_encoder_settings.h"
#include "api/video_codecs/video_encoder.h"
#include "call/video_send_stream.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/video_coding/include/video_coding_defines.h"
#include "modules/video_coding/utility/quality_scaler.h"
#include "modules/video_coding/video_coding_impl.h"
#include "rtc_base/criticalsection.h"
#include "rtc_base/event.h"
#include "rtc_base/sequenced_task_checker.h"
#include "rtc_base/task_queue.h"
#include "typedefs.h" // NOLINT(build/include)
#include "video/overuse_frame_detector.h"
namespace webrtc {
class SendStatisticsProxy;
// VideoStreamEncoder represent a video encoder that accepts raw video frames as
// input and produces an encoded bit stream.
// Usage:
@ -51,15 +47,9 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
// Protected only to provide access to tests.
protected AdaptationObserverInterface {
public:
// Number of resolution and framerate reductions (-1: disabled).
struct AdaptCounts {
int resolution = 0;
int fps = 0;
};
VideoStreamEncoder(uint32_t number_of_cores,
SendStatisticsProxy* stats_proxy,
const VideoSendStream::Config::EncoderSettings& settings,
VideoStreamEncoderObserver* encoder_stats_observer,
const VideoStreamEncoderSettings& settings,
rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback,
std::unique_ptr<OveruseFrameDetector> overuse_detector);
~VideoStreamEncoder() override;
@ -149,7 +139,7 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
~AdaptCounter();
// Get number of adaptation downscales for |reason|.
AdaptCounts Counts(int reason) const;
VideoStreamEncoderObserver::AdaptationSteps Counts(int reason) const;
std::string ToString() const;
@ -182,7 +172,8 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
AdaptCounter& GetAdaptCounter() RTC_RUN_ON(&encoder_queue_);
const AdaptCounter& GetConstAdaptCounter() RTC_RUN_ON(&encoder_queue_);
void UpdateAdaptationStats(AdaptReason reason) RTC_RUN_ON(&encoder_queue_);
AdaptCounts GetActiveCounts(AdaptReason reason) RTC_RUN_ON(&encoder_queue_);
VideoStreamEncoderObserver::AdaptationSteps GetActiveCounts(
AdaptReason reason) RTC_RUN_ON(&encoder_queue_);
rtc::Event shutdown_event_;
@ -194,7 +185,7 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
const std::unique_ptr<VideoSourceProxy> source_proxy_;
EncoderSink* sink_;
const VideoSendStream::Config::EncoderSettings settings_;
const VideoStreamEncoderSettings settings_;
vcm::VideoSender video_sender_ RTC_GUARDED_BY(&encoder_queue_);
const std::unique_ptr<OveruseFrameDetector> overuse_detector_
@ -202,7 +193,7 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
std::unique_ptr<QualityScaler> quality_scaler_ RTC_GUARDED_BY(&encoder_queue_)
RTC_PT_GUARDED_BY(&encoder_queue_);
SendStatisticsProxy* const stats_proxy_;
VideoStreamEncoderObserver* const encoder_stats_observer_;
rtc::VideoSinkInterface<VideoFrame>* const pre_encode_callback_;
// |thread_checker_| checks that public methods that are related to lifetime
// of VideoStreamEncoder are called on the same thread.

View File

@ -92,9 +92,8 @@ class CpuOveruseDetectorProxy : public OveruseFrameDetector {
class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
public:
VideoStreamEncoderUnderTest(
SendStatisticsProxy* stats_proxy,
const VideoSendStream::Config::EncoderSettings& settings)
VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
const VideoStreamEncoderSettings& settings)
: VideoStreamEncoder(1 /* number_of_cores */,
stats_proxy,
settings,
@ -225,6 +224,7 @@ class AdaptingFrameForwarder : public test::FrameForwarder {
absl::optional<int> last_height_;
};
// TODO(nisse): Mock only VideoStreamEncoderObserver.
class MockableSendStatisticsProxy : public SendStatisticsProxy {
public:
MockableSendStatisticsProxy(Clock* clock,
@ -239,6 +239,12 @@ class MockableSendStatisticsProxy : public SendStatisticsProxy {
return SendStatisticsProxy::GetStats();
}
int GetInputFrameRate() const override {
rtc::CritScope cs(&lock_);
if (mock_stats_)
return mock_stats_->input_frame_rate;
return SendStatisticsProxy::GetInputFrameRate();
}
void SetMockStats(const VideoSendStream::Stats& stats) {
rtc::CritScope cs(&lock_);
mock_stats_.emplace(stats);