|  | /* | 
|  | *  Copyright (c) 2022 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 TEST_VIDEO_CODEC_TESTER_H_ | 
|  | #define TEST_VIDEO_CODEC_TESTER_H_ | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <limits> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <optional> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "api/environment/environment.h" | 
|  | #include "api/numerics/samples_stats_counter.h" | 
|  | #include "api/test/metrics/metrics_logger.h" | 
|  | #include "api/units/data_rate.h" | 
|  | #include "api/units/data_size.h" | 
|  | #include "api/units/frequency.h" | 
|  | #include "api/units/time_delta.h" | 
|  | #include "api/units/timestamp.h" | 
|  | #include "api/video/encoded_image.h" | 
|  | #include "api/video/resolution.h" | 
|  | #include "api/video_codecs/scalability_mode.h" | 
|  | #include "api/video_codecs/sdp_video_format.h" | 
|  | #include "api/video_codecs/video_codec.h" | 
|  | #include "api/video_codecs/video_decoder_factory.h" | 
|  | #include "api/video_codecs/video_encoder_factory.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace test { | 
|  |  | 
|  | class VideoCodecTester { | 
|  | public: | 
|  | struct LayerId { | 
|  | int spatial_idx = 0; | 
|  | int temporal_idx = 0; | 
|  |  | 
|  | bool operator==(const LayerId& o) const { | 
|  | return spatial_idx == o.spatial_idx && temporal_idx == o.temporal_idx; | 
|  | } | 
|  | bool operator<(const LayerId& o) const { | 
|  | return spatial_idx < o.spatial_idx || | 
|  | (spatial_idx == o.spatial_idx && temporal_idx < o.temporal_idx); | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct EncodingSettings { | 
|  | SdpVideoFormat sdp_video_format = SdpVideoFormat::VP8(); | 
|  | ScalabilityMode scalability_mode = ScalabilityMode::kL1T1; | 
|  | VideoCodecMode content_type = VideoCodecMode::kRealtimeVideo; | 
|  | bool frame_drop = true; | 
|  | bool keyframe = false; | 
|  |  | 
|  | struct LayerSettings { | 
|  | Resolution resolution; | 
|  | Frequency framerate; | 
|  | DataRate bitrate; | 
|  | }; | 
|  | std::map<LayerId, LayerSettings> layers_settings; | 
|  | }; | 
|  |  | 
|  | class VideoCodecStats { | 
|  | public: | 
|  | struct Filter { | 
|  | uint32_t min_timestamp_rtp = std::numeric_limits<uint32_t>::min(); | 
|  | uint32_t max_timestamp_rtp = std::numeric_limits<uint32_t>::max(); | 
|  | std::optional<LayerId> layer_id; | 
|  | }; | 
|  |  | 
|  | struct Frame { | 
|  | uint32_t timestamp_rtp = 0; | 
|  | LayerId layer_id; | 
|  | bool encoded = false; | 
|  | bool decoded = false; | 
|  | int width = 0; | 
|  | int height = 0; | 
|  | DataSize frame_size = DataSize::Zero(); | 
|  | bool keyframe = false; | 
|  | std::optional<int> qp; | 
|  | Timestamp encode_start = Timestamp::Zero(); | 
|  | TimeDelta encode_time = TimeDelta::Zero(); | 
|  | Timestamp decode_start = Timestamp::Zero(); | 
|  | TimeDelta decode_time = TimeDelta::Zero(); | 
|  | std::optional<DataRate> target_bitrate; | 
|  | std::optional<Frequency> target_framerate; | 
|  |  | 
|  | struct Psnr { | 
|  | double y = 0.0; | 
|  | double u = 0.0; | 
|  | double v = 0.0; | 
|  | }; | 
|  | std::optional<Psnr> psnr; | 
|  | }; | 
|  |  | 
|  | struct Stream { | 
|  | SamplesStatsCounter width; | 
|  | SamplesStatsCounter height; | 
|  | SamplesStatsCounter frame_size_bytes; | 
|  | SamplesStatsCounter keyframe; | 
|  | SamplesStatsCounter qp; | 
|  | SamplesStatsCounter encode_time_ms; | 
|  | SamplesStatsCounter decode_time_ms; | 
|  | SamplesStatsCounter target_bitrate_kbps; | 
|  | SamplesStatsCounter target_framerate_fps; | 
|  | SamplesStatsCounter encoded_bitrate_kbps; | 
|  | SamplesStatsCounter encoded_framerate_fps; | 
|  | SamplesStatsCounter bitrate_mismatch_pct; | 
|  | SamplesStatsCounter framerate_mismatch_pct; | 
|  | SamplesStatsCounter transmission_time_ms; | 
|  |  | 
|  | struct Psnr { | 
|  | SamplesStatsCounter y; | 
|  | SamplesStatsCounter u; | 
|  | SamplesStatsCounter v; | 
|  | } psnr; | 
|  |  | 
|  | // Logs `Stream` metrics to provided `MetricsLogger`. | 
|  | void LogMetrics(MetricsLogger* logger, | 
|  | std::string test_case_name, | 
|  | std::string prefix, | 
|  | std::map<std::string, std::string> metadata = {}) const; | 
|  | }; | 
|  |  | 
|  | virtual ~VideoCodecStats() = default; | 
|  |  | 
|  | // Returns frames for the slice specified by `filter`. If `merge` is true, | 
|  | // also merges frames belonging to the same temporal unit into one | 
|  | // superframe. | 
|  | virtual std::vector<Frame> Slice(Filter filter, bool merge) const = 0; | 
|  |  | 
|  | // Returns video statistics aggregated for the slice specified by `filter`. | 
|  | virtual Stream Aggregate(Filter filter) const = 0; | 
|  |  | 
|  | // Write metrics to a CSV file. | 
|  | virtual void LogMetrics( | 
|  | absl::string_view csv_path, | 
|  | std::vector<Frame> frames, | 
|  | std::map<std::string, std::string> metadata) const = 0; | 
|  | }; | 
|  |  | 
|  | // Pacing settings for codec input. | 
|  | struct PacingSettings { | 
|  | enum PacingMode { | 
|  | // Pacing is not used. Frames are sent to codec back-to-back. | 
|  | kNoPacing, | 
|  | // Pace with the rate equal to the target video frame rate. Pacing time is | 
|  | // derived from RTP timestamp. | 
|  | kRealTime, | 
|  | // Pace with the explicitly provided rate. | 
|  | kConstantRate, | 
|  | }; | 
|  | PacingMode mode = PacingMode::kNoPacing; | 
|  | // Pacing rate for `kConstantRate` mode. | 
|  | Frequency constant_rate = Frequency::Zero(); | 
|  | }; | 
|  |  | 
|  | struct VideoSourceSettings { | 
|  | std::string file_path; | 
|  | Resolution resolution; | 
|  | Frequency framerate; | 
|  | }; | 
|  |  | 
|  | struct DecoderSettings { | 
|  | PacingSettings pacing_settings; | 
|  | std::optional<std::string> decoder_input_base_path; | 
|  | std::optional<std::string> decoder_output_base_path; | 
|  | }; | 
|  |  | 
|  | struct EncoderSettings { | 
|  | PacingSettings pacing_settings; | 
|  | std::optional<std::string> encoder_input_base_path; | 
|  | std::optional<std::string> encoder_output_base_path; | 
|  | }; | 
|  |  | 
|  | virtual ~VideoCodecTester() = default; | 
|  |  | 
|  | // Interface for a coded video frames source. | 
|  | class CodedVideoSource { | 
|  | public: | 
|  | virtual ~CodedVideoSource() = default; | 
|  |  | 
|  | // Returns next frame. Returns `std::nullopt` if the end-of-stream is | 
|  | // reached. Frames should have RTP timestamps representing desired frame | 
|  | // rate. | 
|  | virtual std::optional<EncodedImage> PullFrame() = 0; | 
|  | }; | 
|  |  | 
|  | // A helper function that creates `EncodingSettings` from the given | 
|  | // parameters. `bitrate` is either total, or per-spatial layer or per-spatial | 
|  | // and per-temporal layer. If layer bitrates are not explicitly specified, | 
|  | // then the codec-specific rate allocators used to distribute the total | 
|  | // bitrate across spatial or/and temporal layers. | 
|  | static EncodingSettings CreateEncodingSettings(const Environment& env, | 
|  | std::string codec_type, | 
|  | std::string scalability_name, | 
|  | int width, | 
|  | int height, | 
|  | std::vector<DataRate> bitrate, | 
|  | Frequency framerate, | 
|  | bool screencast = false, | 
|  | bool frame_drop = true); | 
|  |  | 
|  | // A helper function that creates a map of RTP timestamps to | 
|  | // `EncodingSettings` for the given number of frames. | 
|  | static std::map<uint32_t, EncodingSettings> CreateFrameSettings( | 
|  | const EncodingSettings& encoding_settings, | 
|  | int num_frames, | 
|  | uint32_t first_timestamp_rtp = 90000); | 
|  |  | 
|  | // Decodes video, collects and returns decode metrics. | 
|  | static std::unique_ptr<VideoCodecStats> RunDecodeTest( | 
|  | const Environment& env, | 
|  | CodedVideoSource* video_source, | 
|  | VideoDecoderFactory* decoder_factory, | 
|  | const DecoderSettings& decoder_settings, | 
|  | const SdpVideoFormat& sdp_video_format); | 
|  |  | 
|  | // Encodes video, collects and returns encode metrics. | 
|  | static std::unique_ptr<VideoCodecStats> RunEncodeTest( | 
|  | const Environment& env, | 
|  | const VideoSourceSettings& source_settings, | 
|  | VideoEncoderFactory* encoder_factory, | 
|  | const EncoderSettings& encoder_settings, | 
|  | const std::map<uint32_t, EncodingSettings>& encoding_settings); | 
|  |  | 
|  | // Encodes and decodes video, collects and returns encode and decode metrics. | 
|  | static std::unique_ptr<VideoCodecStats> RunEncodeDecodeTest( | 
|  | const Environment& env, | 
|  | const VideoSourceSettings& source_settings, | 
|  | VideoEncoderFactory* encoder_factory, | 
|  | VideoDecoderFactory* decoder_factory, | 
|  | const EncoderSettings& encoder_settings, | 
|  | const DecoderSettings& decoder_settings, | 
|  | const std::map<uint32_t, EncodingSettings>& encoding_settings); | 
|  | }; | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace webrtc | 
|  |  | 
|  | #endif  // TEST_VIDEO_CODEC_TESTER_H_ |