webrtc_m130/video/video_analyzer.h
Jeremy Leconte 6903f713d2 Revert "Report total and squared inter frame delays measured in OnRenderedFrame"
This reverts commit d49d49ad89e67d1a3c63fbc638af445af5648875.

Reason for revert:
# Check failed: total_freezes_duration_ms_double <= total_frames_duration_ms_double (196 vs. 0.044783)
https://ci.chromium.org/p/webrtc/builders/perf/Perf%20Mac%20M1%20Arm64%2012
it also breaks the metric 'freeze_duration_ratio':
https://chromeperf.appspot.com/report?sid=6e919d271ff5885c3fa6363dd255b9793d5e79332a9f202b725c33cc7d3da31a

Original change's description:
> Report total and squared inter frame delays measured in OnRenderedFrame
>
> After https://webrtc-review.googlesource.com/c/src/+/160042 we ended up with two sets of metrics representing total and total squared inter frame delays: old is measured in OnDecodedFrame and new in OnRenderedFrame. Reporting of old metrics was unshipped in https://webrtc-review.googlesource.com/c/src/+/278100. The metrics are used for calculation of harmonic frame rate and are desired to be measured as close as possible to rendering. This CL removes calculation of inter frame delay metrics from OnDecodedFrame and reports the metrics calculated in OnRenderedFrame to the stats.
>
> Bug: webrtc:11108, b/261512902
> Change-Id: Ia21b321aab3a1ac0b6136dc0df7d95f2f0fd24c6
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/286842
> Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
> Reviewed-by: Erik Språng <sprang@webrtc.org>
> Reviewed-by: Harald Alvestrand <hta@webrtc.org>
> Reviewed-by: Henrik Boström <hbos@webrtc.org>
> Cr-Commit-Position: refs/heads/main@{#38909}

Bug: webrtc:11108, b/261512902, webrtc:14789
Change-Id: Ie0da33c1071c48c50bff6608830c9e2a5a928fb4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/288402
Commit-Queue: Jeremy Leconte <jleconte@google.com>
Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38922}
2022-12-20 11:04:31 +00:00

321 lines
13 KiB
C++

/*
* Copyright 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 VIDEO_VIDEO_ANALYZER_H_
#define VIDEO_VIDEO_ANALYZER_H_
#include <deque>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "api/numerics/samples_stats_counter.h"
#include "api/task_queue/task_queue_base.h"
#include "api/test/metrics/metric.h"
#include "api/video/video_source_interface.h"
#include "modules/rtp_rtcp/source/rtp_packet.h"
#include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
#include "rtc_base/event.h"
#include "rtc_base/numerics/running_statistics.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/time_utils.h"
#include "test/layer_filtering_transport.h"
#include "test/rtp_file_writer.h"
namespace webrtc {
class VideoAnalyzer : public PacketReceiver,
public Transport,
public rtc::VideoSinkInterface<VideoFrame> {
public:
VideoAnalyzer(test::LayerFilteringTransport* transport,
const std::string& test_label,
double avg_psnr_threshold,
double avg_ssim_threshold,
int duration_frames,
TimeDelta test_duration,
FILE* graph_data_output_file,
const std::string& graph_title,
uint32_t ssrc_to_analyze,
uint32_t rtx_ssrc_to_analyze,
size_t selected_stream,
int selected_sl,
int selected_tl,
bool is_quick_test_enabled,
Clock* clock,
std::string rtp_dump_name,
TaskQueueBase* task_queue);
~VideoAnalyzer();
virtual void SetReceiver(PacketReceiver* receiver);
void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source,
bool respect_sink_wants);
void SetCall(Call* call);
void SetSendStream(VideoSendStream* stream);
void SetReceiveStream(VideoReceiveStreamInterface* stream);
void SetAudioReceiveStream(AudioReceiveStreamInterface* recv_stream);
rtc::VideoSinkInterface<VideoFrame>* InputInterface();
rtc::VideoSourceInterface<VideoFrame>* OutputInterface();
DeliveryStatus DeliverPacket(MediaType media_type,
rtc::CopyOnWriteBuffer packet,
int64_t packet_time_us) override;
void PreEncodeOnFrame(const VideoFrame& video_frame);
void PostEncodeOnFrame(size_t stream_id, uint32_t timestamp);
bool SendRtp(const uint8_t* packet,
size_t length,
const PacketOptions& options) override;
bool SendRtcp(const uint8_t* packet, size_t length) override;
void OnFrame(const VideoFrame& video_frame) override;
void Wait();
void StartMeasuringCpuProcessTime();
void StopMeasuringCpuProcessTime();
void StartExcludingCpuThreadTime() RTC_LOCKS_EXCLUDED(cpu_measurement_lock_);
void StopExcludingCpuThreadTime() RTC_LOCKS_EXCLUDED(cpu_measurement_lock_);
double GetCpuUsagePercent() RTC_LOCKS_EXCLUDED(cpu_measurement_lock_);
test::LayerFilteringTransport* const transport_;
PacketReceiver* receiver_;
private:
struct FrameComparison {
FrameComparison();
FrameComparison(const VideoFrame& reference,
const VideoFrame& render,
bool dropped,
int64_t input_time_ms,
int64_t send_time_ms,
int64_t recv_time_ms,
int64_t render_time_ms,
size_t encoded_frame_size);
FrameComparison(bool dropped,
int64_t input_time_ms,
int64_t send_time_ms,
int64_t recv_time_ms,
int64_t render_time_ms,
size_t encoded_frame_size);
absl::optional<VideoFrame> reference;
absl::optional<VideoFrame> render;
bool dropped;
int64_t input_time_ms;
int64_t send_time_ms;
int64_t recv_time_ms;
int64_t render_time_ms;
size_t encoded_frame_size;
};
struct Sample {
Sample(int dropped,
int64_t input_time_ms,
int64_t send_time_ms,
int64_t recv_time_ms,
int64_t render_time_ms,
size_t encoded_frame_size,
double psnr,
double ssim);
int dropped;
int64_t input_time_ms;
int64_t send_time_ms;
int64_t recv_time_ms;
int64_t render_time_ms;
size_t encoded_frame_size;
double psnr;
double ssim;
};
// Implements VideoSinkInterface to receive captured frames from a
// FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
// as a source to VideoSendStream.
// It forwards all input frames to the VideoAnalyzer for later comparison and
// forwards the captured frames to the VideoSendStream.
class CapturedFrameForwarder : public rtc::VideoSinkInterface<VideoFrame>,
public rtc::VideoSourceInterface<VideoFrame> {
public:
CapturedFrameForwarder(VideoAnalyzer* analyzer,
Clock* clock,
int frames_to_capture,
TimeDelta test_duration);
void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source);
private:
void OnFrame(const VideoFrame& video_frame)
RTC_LOCKS_EXCLUDED(lock_) override;
// Called when `send_stream_.SetSource()` is called.
void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
const rtc::VideoSinkWants& wants)
RTC_LOCKS_EXCLUDED(lock_) override;
// Called by `send_stream_` when `send_stream_.SetSource()` is called.
void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink)
RTC_LOCKS_EXCLUDED(lock_) override;
VideoAnalyzer* const analyzer_;
Mutex lock_;
rtc::VideoSinkInterface<VideoFrame>* send_stream_input_
RTC_GUARDED_BY(lock_);
VideoSourceInterface<VideoFrame>* video_source_;
Clock* clock_;
int captured_frames_ RTC_GUARDED_BY(lock_);
const int frames_to_capture_;
const Timestamp test_end_;
};
struct FrameWithPsnr {
double psnr;
VideoFrame frame;
};
bool IsInSelectedSpatialAndTemporalLayer(const RtpPacket& rtp_packet);
void AddFrameComparison(const VideoFrame& reference,
const VideoFrame& render,
bool dropped,
int64_t render_time_ms)
RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
void PollStats() RTC_LOCKS_EXCLUDED(comparison_lock_);
static void FrameComparisonThread(void* obj);
bool CompareFrames();
bool PopComparison(FrameComparison* comparison);
// Increment counter for number of frames received for comparison.
void FrameRecorded() RTC_EXCLUSIVE_LOCKS_REQUIRED(comparison_lock_);
// Returns true if all frames to be compared have been taken from the queue.
bool AllFramesRecorded() RTC_LOCKS_EXCLUDED(comparison_lock_);
bool AllFramesRecordedLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(comparison_lock_);
// Increase count of number of frames processed. Returns true if this was the
// last frame to be processed.
bool FrameProcessed() RTC_LOCKS_EXCLUDED(comparison_lock_);
void PrintResults() RTC_LOCKS_EXCLUDED(lock_, comparison_lock_);
void PerformFrameComparison(const FrameComparison& comparison)
RTC_LOCKS_EXCLUDED(comparison_lock_);
void PrintResult(absl::string_view result_type,
const SamplesStatsCounter& stats,
webrtc::test::Unit unit,
webrtc::test::ImprovementDirection improvement_direction);
void PrintResultWithExternalMean(
absl::string_view result_type,
double mean,
const SamplesStatsCounter& stats,
webrtc::test::Unit unit,
webrtc::test::ImprovementDirection improvement_direction);
void PrintSamplesToFile(void) RTC_LOCKS_EXCLUDED(comparison_lock_);
void AddCapturedFrameForComparison(const VideoFrame& video_frame)
RTC_LOCKS_EXCLUDED(lock_, comparison_lock_);
Call* call_;
VideoSendStream* send_stream_;
VideoReceiveStreamInterface* receive_stream_;
AudioReceiveStreamInterface* audio_receive_stream_;
CapturedFrameForwarder captured_frame_forwarder_;
const std::string test_label_;
FILE* const graph_data_output_file_;
const std::string graph_title_;
const uint32_t ssrc_to_analyze_;
const uint32_t rtx_ssrc_to_analyze_;
const size_t selected_stream_;
const int selected_sl_;
const int selected_tl_;
Mutex comparison_lock_;
std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter sender_time_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter receiver_time_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter network_time_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter psnr_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter ssim_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter end_to_end_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter rendered_delta_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter encoded_frame_size_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter encode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter encode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter encode_usage_percent_ RTC_GUARDED_BY(comparison_lock_);
double mean_decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter decode_time_max_ms_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter media_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter fec_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter send_bandwidth_bps_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter memory_usage_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter audio_expand_rate_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter audio_accelerate_rate_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter audio_jitter_buffer_ms_ RTC_GUARDED_BY(comparison_lock_);
SamplesStatsCounter pixels_ RTC_GUARDED_BY(comparison_lock_);
// Rendered frame with worst PSNR is saved for further analysis.
absl::optional<FrameWithPsnr> worst_frame_ RTC_GUARDED_BY(comparison_lock_);
// Freeze metrics.
SamplesStatsCounter time_between_freezes_ RTC_GUARDED_BY(comparison_lock_);
uint32_t freeze_count_ RTC_GUARDED_BY(comparison_lock_);
uint32_t total_freezes_duration_ms_ RTC_GUARDED_BY(comparison_lock_);
uint32_t total_frames_duration_ms_ RTC_GUARDED_BY(comparison_lock_);
double sum_squared_frame_durations_ RTC_GUARDED_BY(comparison_lock_);
double decode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
double render_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
size_t last_fec_bytes_;
Mutex lock_ RTC_ACQUIRED_BEFORE(comparison_lock_)
RTC_ACQUIRED_BEFORE(cpu_measurement_lock_);
const int frames_to_process_;
const Timestamp test_end_;
int frames_recorded_ RTC_GUARDED_BY(comparison_lock_);
int frames_processed_ RTC_GUARDED_BY(comparison_lock_);
int captured_frames_ RTC_GUARDED_BY(comparison_lock_);
int dropped_frames_ RTC_GUARDED_BY(comparison_lock_);
int dropped_frames_before_first_encode_ RTC_GUARDED_BY(lock_);
int dropped_frames_before_rendering_ RTC_GUARDED_BY(lock_);
int64_t last_render_time_ RTC_GUARDED_BY(comparison_lock_);
int64_t last_render_delta_ms_ RTC_GUARDED_BY(comparison_lock_);
int64_t last_unfreeze_time_ms_ RTC_GUARDED_BY(comparison_lock_);
uint32_t rtp_timestamp_delta_ RTC_GUARDED_BY(lock_);
Mutex cpu_measurement_lock_;
int64_t cpu_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
int64_t wallclock_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
std::deque<VideoFrame> frames_ RTC_GUARDED_BY(lock_);
absl::optional<VideoFrame> last_rendered_frame_ RTC_GUARDED_BY(lock_);
rtc::TimestampWrapAroundHandler wrap_handler_ RTC_GUARDED_BY(lock_);
std::map<int64_t, int64_t> send_times_ RTC_GUARDED_BY(lock_);
std::map<int64_t, int64_t> recv_times_ RTC_GUARDED_BY(lock_);
std::map<int64_t, size_t> encoded_frame_sizes_ RTC_GUARDED_BY(lock_);
absl::optional<uint32_t> first_encoded_timestamp_ RTC_GUARDED_BY(lock_);
absl::optional<uint32_t> first_sent_timestamp_ RTC_GUARDED_BY(lock_);
const double avg_psnr_threshold_;
const double avg_ssim_threshold_;
bool is_quick_test_enabled_;
std::vector<rtc::PlatformThread> comparison_thread_pool_;
rtc::Event comparison_available_event_;
std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_);
bool quit_ RTC_GUARDED_BY(comparison_lock_);
rtc::Event done_;
std::unique_ptr<VideoRtpDepacketizer> vp8_depacketizer_;
std::unique_ptr<VideoRtpDepacketizer> vp9_depacketizer_;
std::unique_ptr<test::RtpFileWriter> rtp_file_writer_;
Clock* const clock_;
const int64_t start_ms_;
TaskQueueBase* task_queue_;
};
} // namespace webrtc
#endif // VIDEO_VIDEO_ANALYZER_H_