| /* |
| * Copyright (c) 2013 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 VIDEO_SEND_STATISTICS_PROXY_H_ |
| #define VIDEO_SEND_STATISTICS_PROXY_H_ |
| |
| #include <array> |
| #include <deque> |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "api/field_trials_view.h" |
| #include "api/video/video_codec_constants.h" |
| #include "call/video_send_stream.h" |
| #include "modules/include/module_common_types_public.h" |
| #include "modules/rtp_rtcp/include/report_block_data.h" |
| #include "modules/video_coding/include/video_codec_interface.h" |
| #include "modules/video_coding/include/video_coding_defines.h" |
| #include "rtc_base/numerics/exp_filter.h" |
| #include "rtc_base/rate_tracker.h" |
| #include "rtc_base/synchronization/mutex.h" |
| #include "rtc_base/thread_annotations.h" |
| #include "system_wrappers/include/clock.h" |
| #include "video/config/video_encoder_config.h" |
| #include "video/quality_limitation_reason_tracker.h" |
| #include "video/report_block_stats.h" |
| #include "video/stats_counter.h" |
| #include "video/video_stream_encoder_observer.h" |
| |
| namespace webrtc { |
| |
| class SendStatisticsProxy : public VideoStreamEncoderObserver, |
| public ReportBlockDataObserver, |
| public RtcpPacketTypeCounterObserver, |
| public StreamDataCountersCallback, |
| public BitrateStatisticsObserver, |
| public FrameCountObserver { |
| public: |
| static constexpr TimeDelta kStatsTimeout = TimeDelta::Seconds(5); |
| // Number of required samples to be collected before a metric is added |
| // to a rtc histogram. |
| static const int kMinRequiredMetricsSamples = 200; |
| |
| SendStatisticsProxy(Clock* clock, |
| const VideoSendStream::Config& config, |
| VideoEncoderConfig::ContentType content_type, |
| const FieldTrialsView& field_trials); |
| ~SendStatisticsProxy() override; |
| |
| virtual VideoSendStream::Stats GetStats(); |
| |
| void OnSendEncodedImage(const EncodedImage& encoded_image, |
| const CodecSpecificInfo* codec_info) override; |
| |
| void OnEncoderImplementationChanged( |
| EncoderImplementation implementation) override; |
| |
| // Used to update incoming frame rate. |
| void OnIncomingFrame(int width, int height) override; |
| |
| // Dropped frame stats. |
| void OnFrameDropped(DropReason) override; |
| |
| // Adaptation stats. |
| void OnAdaptationChanged( |
| VideoAdaptationReason reason, |
| const VideoAdaptationCounters& cpu_counters, |
| const VideoAdaptationCounters& quality_counters) override; |
| void ClearAdaptationStats() override; |
| void UpdateAdaptationSettings(AdaptationSettings cpu_settings, |
| AdaptationSettings quality_settings) override; |
| |
| void OnBitrateAllocationUpdated( |
| const VideoCodec& codec, |
| const VideoBitrateAllocation& allocation) override; |
| |
| void OnEncoderInternalScalerUpdate(bool is_scaled) override; |
| |
| 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) override; |
| |
| // Used to update the encoder target rate. |
| void OnSetEncoderTargetRate(uint32_t bitrate_bps); |
| |
| // Implements CpuOveruseMetricsObserver. |
| void OnEncodedFrameTimeMeasured(int encode_time_ms, |
| int encode_usage_percent) override; |
| |
| void OnSendPacket(uint32_t ssrc, Timestamp capture_time); |
| |
| int GetInputFrameRate() const override; |
| int GetSendFrameRate() const; |
| |
| protected: |
| // From ReportBlockDataObserver. |
| void OnReportBlockDataUpdated(ReportBlockData report_block_data) override; |
| // From RtcpPacketTypeCounterObserver. |
| void RtcpPacketTypesCounterUpdated( |
| uint32_t ssrc, |
| const RtcpPacketTypeCounter& packet_counter) override; |
| // From StreamDataCountersCallback. |
| void DataCountersUpdated(const StreamDataCounters& counters, |
| uint32_t ssrc) override; |
| |
| // From BitrateStatisticsObserver. |
| void Notify(uint32_t total_bitrate_bps, |
| uint32_t retransmit_bitrate_bps, |
| uint32_t ssrc) override; |
| |
| // From FrameCountObserver. |
| void FrameCountUpdated(const FrameCounts& frame_counts, |
| uint32_t ssrc) override; |
| |
| private: |
| class SampleCounter { |
| public: |
| SampleCounter() : sum(0), num_samples(0) {} |
| ~SampleCounter() {} |
| void Add(int sample); |
| int Avg(int64_t min_required_samples) const; |
| |
| private: |
| int64_t sum; |
| int64_t num_samples; |
| }; |
| class BoolSampleCounter { |
| public: |
| BoolSampleCounter() : sum(0), num_samples(0) {} |
| ~BoolSampleCounter() {} |
| void Add(bool sample); |
| void Add(bool sample, int64_t count); |
| int Percent(int64_t min_required_samples) const; |
| int Permille(int64_t min_required_samples) const; |
| |
| private: |
| int Fraction(int64_t min_required_samples, float multiplier) const; |
| int64_t sum; |
| int64_t num_samples; |
| }; |
| struct TargetRateUpdates { |
| TargetRateUpdates() |
| : pause_resume_events(0), last_paused_or_resumed(false), last_ms(-1) {} |
| int pause_resume_events; |
| bool last_paused_or_resumed; |
| int64_t last_ms; |
| }; |
| struct FallbackEncoderInfo { |
| FallbackEncoderInfo(); |
| bool is_possible = true; |
| bool is_active = false; |
| int on_off_events = 0; |
| int64_t elapsed_ms = 0; |
| std::optional<int64_t> last_update_ms; |
| const int max_frame_diff_ms = 2000; |
| }; |
| struct FallbackEncoderInfoDisabled { |
| bool is_possible = true; |
| bool min_pixel_limit_reached = false; |
| }; |
| struct StatsTimer { |
| void Start(int64_t now_ms); |
| void Stop(int64_t now_ms); |
| void Restart(int64_t now_ms); |
| int64_t start_ms = -1; |
| int64_t total_ms = 0; |
| }; |
| struct QpCounters { |
| SampleCounter vp8; // QP range: 0-127. |
| SampleCounter vp9; // QP range: 0-255. |
| SampleCounter h264; // QP range: 0-51. |
| }; |
| struct AdaptChanges { |
| int down = 0; |
| int up = 0; |
| }; |
| |
| // Map holding encoded frames (mapped by timestamp). |
| // If simulcast layers are encoded on different threads, there is no guarantee |
| // that one frame of all layers are encoded before the next start. |
| struct TimestampOlderThan { |
| bool operator()(uint32_t ts1, uint32_t ts2) const { |
| return IsNewerTimestamp(ts2, ts1); |
| } |
| }; |
| struct Frame { |
| Frame(int64_t send_ms, uint32_t width, uint32_t height, int simulcast_idx) |
| : send_ms(send_ms), |
| max_width(width), |
| max_height(height), |
| max_simulcast_idx(simulcast_idx) {} |
| const int64_t |
| send_ms; // Time when first frame with this timestamp is sent. |
| uint32_t max_width; // Max width with this timestamp. |
| uint32_t max_height; // Max height with this timestamp. |
| int max_simulcast_idx; // Max simulcast index with this timestamp. |
| }; |
| typedef std::map<uint32_t, Frame, TimestampOlderThan> EncodedFrameMap; |
| |
| void PurgeOldStats() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); |
| VideoSendStream::StreamStats* GetStatsEntry(uint32_t ssrc) |
| RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); |
| |
| struct MaskedAdaptationCounts { |
| std::optional<int> resolution_adaptations = std::nullopt; |
| std::optional<int> num_framerate_reductions = std::nullopt; |
| }; |
| |
| struct Adaptations { |
| public: |
| MaskedAdaptationCounts MaskedCpuCounts() const; |
| MaskedAdaptationCounts MaskedQualityCounts() const; |
| |
| void set_cpu_counts(const VideoAdaptationCounters& cpu_counts); |
| void set_quality_counts(const VideoAdaptationCounters& quality_counts); |
| |
| VideoAdaptationCounters cpu_counts() const; |
| VideoAdaptationCounters quality_counts() const; |
| |
| void UpdateMaskingSettings(AdaptationSettings cpu_settings, |
| AdaptationSettings quality_settings); |
| |
| private: |
| VideoAdaptationCounters cpu_counts_; |
| AdaptationSettings cpu_settings_; |
| VideoAdaptationCounters quality_counts_; |
| AdaptationSettings quality_settings_; |
| |
| MaskedAdaptationCounts Mask(const VideoAdaptationCounters& counters, |
| const AdaptationSettings& settings) const; |
| }; |
| // Collection of various stats that are tracked per ssrc. |
| struct Trackers { |
| struct SendDelayEntry { |
| Timestamp when; |
| TimeDelta send_delay; |
| }; |
| |
| Trackers(); |
| Trackers(const Trackers&) = delete; |
| Trackers& operator=(const Trackers&) = delete; |
| |
| void AddSendDelay(Timestamp now, TimeDelta send_delay); |
| |
| Timestamp resolution_update = Timestamp::MinusInfinity(); |
| rtc::RateTracker encoded_frame_rate; |
| |
| std::deque<SendDelayEntry> send_delays; |
| |
| // The sum of `send_delay` in `send_delays`. |
| TimeDelta send_delay_sum = TimeDelta::Zero(); |
| |
| // Pointer to the maximum `send_delay` in `send_delays` or nullptr if |
| // `send_delays.empty()` |
| const TimeDelta* send_delay_max = nullptr; |
| }; |
| |
| void SetAdaptTimer(const MaskedAdaptationCounts& counts, StatsTimer* timer) |
| RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); |
| void UpdateAdaptationStats() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); |
| void TryUpdateInitialQualityResolutionAdaptUp( |
| std::optional<int> old_quality_downscales, |
| std::optional<int> updated_quality_downscales) |
| RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); |
| |
| void UpdateEncoderFallbackStats(const CodecSpecificInfo* codec_info, |
| int pixels, |
| int simulcast_index) |
| RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); |
| void UpdateFallbackDisabledStats(const CodecSpecificInfo* codec_info, |
| int pixels, |
| int simulcast_index) |
| RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); |
| |
| Clock* const clock_; |
| const std::string payload_name_; |
| const RtpConfig rtp_config_; |
| const std::optional<int> fallback_max_pixels_; |
| const std::optional<int> fallback_max_pixels_disabled_; |
| mutable Mutex mutex_; |
| VideoEncoderConfig::ContentType content_type_ RTC_GUARDED_BY(mutex_); |
| const int64_t start_ms_; |
| VideoSendStream::Stats stats_ RTC_GUARDED_BY(mutex_); |
| rtc::ExpFilter encode_time_ RTC_GUARDED_BY(mutex_); |
| QualityLimitationReasonTracker quality_limitation_reason_tracker_ |
| RTC_GUARDED_BY(mutex_); |
| rtc::RateTracker media_byte_rate_tracker_ RTC_GUARDED_BY(mutex_); |
| rtc::RateTracker encoded_frame_rate_tracker_ RTC_GUARDED_BY(mutex_); |
| // Trackers mapped by ssrc. |
| std::map<uint32_t, Trackers> trackers_ RTC_GUARDED_BY(mutex_); |
| |
| std::optional<int64_t> last_outlier_timestamp_ RTC_GUARDED_BY(mutex_); |
| |
| int last_num_spatial_layers_ RTC_GUARDED_BY(mutex_); |
| int last_num_simulcast_streams_ RTC_GUARDED_BY(mutex_); |
| std::array<bool, kMaxSpatialLayers> last_spatial_layer_use_ |
| RTC_GUARDED_BY(mutex_); |
| // Indicates if the latest bitrate allocation had layers disabled by low |
| // available bandwidth. |
| bool bw_limited_layers_ RTC_GUARDED_BY(mutex_); |
| // Indicastes if the encoder internally downscales input image. |
| bool internal_encoder_scaler_ RTC_GUARDED_BY(mutex_); |
| Adaptations adaptation_limitations_ RTC_GUARDED_BY(mutex_); |
| |
| struct EncoderChangeEvent { |
| std::string previous_encoder_implementation; |
| std::string new_encoder_implementation; |
| }; |
| // Stores the last change in encoder implementation in an optional, so that |
| // the event can be consumed. |
| std::optional<EncoderChangeEvent> encoder_changed_; |
| |
| // Contains stats used for UMA histograms. These stats will be reset if |
| // content type changes between real-time video and screenshare, since these |
| // will be reported separately. |
| struct UmaSamplesContainer { |
| UmaSamplesContainer(const char* prefix, |
| const VideoSendStream::Stats& start_stats, |
| Clock* clock); |
| ~UmaSamplesContainer(); |
| |
| void UpdateHistograms(const RtpConfig& rtp_config, |
| const VideoSendStream::Stats& current_stats); |
| |
| void InitializeBitrateCounters(const VideoSendStream::Stats& stats); |
| |
| bool InsertEncodedFrame(const EncodedImage& encoded_frame, |
| int simulcast_idx); |
| void RemoveOld(int64_t now_ms); |
| |
| const std::string uma_prefix_; |
| Clock* const clock_; |
| SampleCounter input_width_counter_; |
| SampleCounter input_height_counter_; |
| SampleCounter sent_width_counter_; |
| SampleCounter sent_height_counter_; |
| SampleCounter encode_time_counter_; |
| BoolSampleCounter key_frame_counter_; |
| BoolSampleCounter quality_limited_frame_counter_; |
| SampleCounter quality_downscales_counter_; |
| BoolSampleCounter cpu_limited_frame_counter_; |
| BoolSampleCounter bw_limited_frame_counter_; |
| SampleCounter bw_resolutions_disabled_counter_; |
| SampleCounter delay_counter_; |
| SampleCounter max_delay_counter_; |
| rtc::RateTracker input_frame_rate_tracker_; |
| RateCounter input_fps_counter_; |
| RateCounter sent_fps_counter_; |
| RateAccCounter total_byte_counter_; |
| RateAccCounter media_byte_counter_; |
| RateAccCounter rtx_byte_counter_; |
| RateAccCounter padding_byte_counter_; |
| RateAccCounter retransmit_byte_counter_; |
| RateAccCounter fec_byte_counter_; |
| int64_t first_rtcp_stats_time_ms_; |
| int64_t first_rtp_stats_time_ms_; |
| StatsTimer cpu_adapt_timer_; |
| StatsTimer quality_adapt_timer_; |
| BoolSampleCounter paused_time_counter_; |
| TargetRateUpdates target_rate_updates_; |
| BoolSampleCounter fallback_active_counter_; |
| FallbackEncoderInfo fallback_info_; |
| FallbackEncoderInfoDisabled fallback_info_disabled_; |
| ReportBlockStats report_block_stats_; |
| const VideoSendStream::Stats start_stats_; |
| size_t num_streams_; // Number of configured streams to encoder. |
| size_t num_pixels_highest_stream_; |
| EncodedFrameMap encoded_frames_; |
| AdaptChanges initial_quality_changes_; |
| |
| std::map<int, QpCounters> |
| qp_counters_; // QP counters mapped by spatial idx. |
| }; |
| |
| std::unique_ptr<UmaSamplesContainer> uma_container_ RTC_GUARDED_BY(mutex_); |
| }; |
| |
| } // namespace webrtc |
| #endif // VIDEO_SEND_STATISTICS_PROXY_H_ |