diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn index c9d1f48984..af1204f2cb 100644 --- a/test/pc/e2e/BUILD.gn +++ b/test/pc/e2e/BUILD.gn @@ -14,6 +14,7 @@ group("e2e") { deps = [ ":default_encoded_image_id_injector", ":encoded_image_id_injector_api", + ":example_video_quality_analyzer", ":single_process_encoded_image_id_injector", ] } @@ -99,3 +100,20 @@ if (rtc_include_tests) { ] } } + +rtc_source_set("example_video_quality_analyzer") { + visibility = [ "*" ] + testonly = true + sources = [ + "analyzer/video/example_video_quality_analyzer.cc", + "analyzer/video/example_video_quality_analyzer.h", + ] + + deps = [ + "../../../api/video:encoded_image", + "../../../api/video:video_frame", + "../../../rtc_base:criticalsection", + "../../../rtc_base:logging", + "api:video_quality_analyzer_api", + ] +} diff --git a/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc new file mode 100644 index 0000000000..07b31752ad --- /dev/null +++ b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019 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 "test/pc/e2e/analyzer/video/example_video_quality_analyzer.h" + +#include "rtc_base/logging.h" + +namespace webrtc { +namespace test { + +ExampleVideoQualityAnalyzer::ExampleVideoQualityAnalyzer() = default; +ExampleVideoQualityAnalyzer::~ExampleVideoQualityAnalyzer() = default; + +void ExampleVideoQualityAnalyzer::Start(int max_threads_count) {} + +uint16_t ExampleVideoQualityAnalyzer::OnFrameCaptured( + const std::string& stream_label, + const webrtc::VideoFrame& frame) { + rtc::CritScope crit(&lock_); + uint16_t frame_id = next_frame_id_++; + auto it = frames_in_flight_.find(frame_id); + if (it == frames_in_flight_.end()) { + frames_in_flight_.insert(frame_id); + } else { + RTC_LOG(WARNING) << "Meet new frame with the same id: " << frame_id + << ". Assumes old one as dropped"; + // We needn't insert frame to frames_in_flight_, because it is already + // there. + ++frames_dropped_; + } + ++frames_captured_; + return frame_id; +} + +void ExampleVideoQualityAnalyzer::OnFramePreEncode( + const webrtc::VideoFrame& frame) {} + +void ExampleVideoQualityAnalyzer::OnFrameEncoded( + uint16_t frame_id, + const webrtc::EncodedImage& encoded_image) { + rtc::CritScope crit(&lock_); + ++frames_sent_; +} + +void ExampleVideoQualityAnalyzer::OnFrameDropped( + webrtc::EncodedImageCallback::DropReason reason) { + RTC_LOG(INFO) << "Frame dropped by encoder"; + rtc::CritScope crit(&lock_); + ++frames_dropped_; +} + +void ExampleVideoQualityAnalyzer::OnFrameReceived( + uint16_t frame_id, + const webrtc::EncodedImage& encoded_image) { + rtc::CritScope crit(&lock_); + ++frames_received_; +} + +void ExampleVideoQualityAnalyzer::OnFrameDecoded( + const webrtc::VideoFrame& frame, + absl::optional decode_time_ms, + absl::optional qp) {} + +void ExampleVideoQualityAnalyzer::OnFrameRendered( + const webrtc::VideoFrame& frame) { + rtc::CritScope crit(&lock_); + frames_in_flight_.erase(frame.id()); + ++frames_rendered_; +} + +void ExampleVideoQualityAnalyzer::OnEncoderError( + const webrtc::VideoFrame& frame, + int32_t error_code) { + RTC_LOG(LS_ERROR) << "Failed to encode frame " << frame.id() + << ". Code: " << error_code; +} + +void ExampleVideoQualityAnalyzer::OnDecoderError(uint16_t frame_id, + int32_t error_code) { + RTC_LOG(LS_ERROR) << "Failed to decode frame " << frame_id + << ". Code: " << error_code; +} + +void ExampleVideoQualityAnalyzer::Stop() { + rtc::CritScope crit(&lock_); + RTC_LOG(INFO) << "There are " << frames_in_flight_.size() + << " frames in flight, assuming all of them are dropped"; + frames_dropped_ += frames_in_flight_.size(); +} + +uint64_t ExampleVideoQualityAnalyzer::frames_captured() const { + rtc::CritScope crit(&lock_); + return frames_captured_; +} + +uint64_t ExampleVideoQualityAnalyzer::frames_sent() const { + rtc::CritScope crit(&lock_); + return frames_sent_; +} + +uint64_t ExampleVideoQualityAnalyzer::frames_received() const { + rtc::CritScope crit(&lock_); + return frames_received_; +} + +uint64_t ExampleVideoQualityAnalyzer::frames_dropped() const { + rtc::CritScope crit(&lock_); + return frames_dropped_; +} + +uint64_t ExampleVideoQualityAnalyzer::frames_rendered() const { + rtc::CritScope crit(&lock_); + return frames_rendered_; +} + +} // namespace test +} // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h new file mode 100644 index 0000000000..4070b4d63b --- /dev/null +++ b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019 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_PC_E2E_ANALYZER_VIDEO_EXAMPLE_VIDEO_QUALITY_ANALYZER_H_ +#define TEST_PC_E2E_ANALYZER_VIDEO_EXAMPLE_VIDEO_QUALITY_ANALYZER_H_ + +#include +#include +#include + +#include "api/video/encoded_image.h" +#include "api/video/video_frame.h" +#include "rtc_base/critical_section.h" +#include "test/pc/e2e/api/video_quality_analyzer_interface.h" + +namespace webrtc { +namespace test { + +// This class is an example implementation of +// webrtc::VideoQualityAnalyzerInterface and calculates simple metrics +// just to demonstration purposes. Assumed to be used in the single process +// test cases, where both peers are in the same process. +class ExampleVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { + public: + ExampleVideoQualityAnalyzer(); + ~ExampleVideoQualityAnalyzer() override; + + void Start(int max_threads_count) override; + uint16_t OnFrameCaptured(const std::string& stream_label, + const VideoFrame& frame) override; + void OnFramePreEncode(const VideoFrame& frame) override; + void OnFrameEncoded(uint16_t frame_id, + const EncodedImage& encoded_image) override; + void OnFrameDropped(EncodedImageCallback::DropReason reason) override; + void OnFrameReceived(uint16_t frame_id, + const EncodedImage& encoded_image) override; + void OnFrameDecoded(const VideoFrame& frame, + absl::optional decode_time_ms, + absl::optional qp) override; + void OnFrameRendered(const VideoFrame& frame) override; + void OnEncoderError(const VideoFrame& frame, int32_t error_code) override; + void OnDecoderError(uint16_t frame_id, int32_t error_code) override; + void Stop() override; + + uint64_t frames_captured() const; + uint64_t frames_sent() const; + uint64_t frames_received() const; + uint64_t frames_dropped() const; + uint64_t frames_rendered() const; + + private: + // When peer A captured the frame it will come into analyzer's OnFrameCaptured + // and will be stored in frames_in_flight_. It will be removed from there + // when it will be received in peer B, so we need to guard it with lock. + // Also because analyzer will serve for all video streams it can be called + // from different threads inside one peer. + rtc::CriticalSection lock_; + // Stores frame ids, that are currently going from one peer to another. We + // need to keep them to correctly determine dropped frames and also correctly + // process frame id overlap. + std::set frames_in_flight_ RTC_GUARDED_BY(lock_); + uint16_t next_frame_id_ RTC_GUARDED_BY(lock_) = 0; + uint64_t frames_captured_ RTC_GUARDED_BY(lock_) = 0; + uint64_t frames_sent_ RTC_GUARDED_BY(lock_) = 0; + uint64_t frames_received_ RTC_GUARDED_BY(lock_) = 0; + uint64_t frames_dropped_ RTC_GUARDED_BY(lock_) = 0; + uint64_t frames_rendered_ RTC_GUARDED_BY(lock_) = 0; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_PC_E2E_ANALYZER_VIDEO_EXAMPLE_VIDEO_QUALITY_ANALYZER_H_