From f50c6c2fb41410a49ba0173fa0754c8b90f74511 Mon Sep 17 00:00:00 2001 From: Artem Titov Date: Thu, 24 Jan 2019 16:54:03 +0100 Subject: [PATCH] Introduce VideoQualityAnalyzerInjectionHelper. VideoQualityAnalyzerInjectionHelper will be used to provide all required entities to inject video quality analyzer into peer connection pipeline. Bug: webrtc:10138 Change-Id: Iea7cf453311d809619839d5cf94b78a020ce9167 Reviewed-on: https://webrtc-review.googlesource.com/c/119642 Commit-Queue: Artem Titov Reviewed-by: Ilya Nikolaevskiy Reviewed-by: Peter Slatala Cr-Commit-Position: refs/heads/master@{#26395} --- test/frame_generator.cc | 4 + test/frame_generator.h | 6 +- test/pc/e2e/BUILD.gn | 24 +++ ...video_quality_analyzer_injection_helper.cc | 139 ++++++++++++++++++ .../video_quality_analyzer_injection_helper.h | 76 ++++++++++ 5 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc create mode 100644 test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h diff --git a/test/frame_generator.cc b/test/frame_generator.cc index 9acffb15cc..e37e823dd8 100644 --- a/test/frame_generator.cc +++ b/test/frame_generator.cc @@ -467,6 +467,10 @@ bool FrameForwarder::has_sinks() const { return sink_ != nullptr; } +void FrameGenerator::ChangeResolution(size_t width, size_t height) { + RTC_NOTREACHED(); +} + std::unique_ptr FrameGenerator::CreateSquareGenerator( int width, int height, diff --git a/test/frame_generator.h b/test/frame_generator.h index ba36d38713..358dc0fb65 100644 --- a/test/frame_generator.h +++ b/test/frame_generator.h @@ -29,7 +29,7 @@ namespace test { class FrameForwarder : public rtc::VideoSourceInterface { public: FrameForwarder(); - virtual ~FrameForwarder(); + ~FrameForwarder() override; // Forwards |video_frame| to the registered |sink_|. virtual void IncomingCapturedFrame(const VideoFrame& video_frame); rtc::VideoSinkWants sink_wants() const; @@ -56,9 +56,7 @@ class FrameGenerator { virtual VideoFrame* NextFrame() = 0; // Change the capture resolution. - virtual void ChangeResolution(size_t width, size_t height) { - RTC_NOTREACHED(); - } + virtual void ChangeResolution(size_t width, size_t height); enum class OutputType { I420, I420A, I010 }; diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn index 82c334f94c..6aa5412afb 100644 --- a/test/pc/e2e/BUILD.gn +++ b/test/pc/e2e/BUILD.gn @@ -20,6 +20,9 @@ group("e2e") { ":quality_analyzing_video_encoder", ":single_process_encoded_image_id_injector", ] + if (rtc_include_tests) { + deps += [ ":video_quality_analyzer_injection_helper" ] + } } if (rtc_include_tests) { @@ -127,6 +130,27 @@ rtc_source_set("quality_analyzing_video_encoder") { } if (rtc_include_tests) { + rtc_source_set("video_quality_analyzer_injection_helper") { + visibility = [ "*" ] + testonly = true + sources = [ + "analyzer/video/video_quality_analyzer_injection_helper.cc", + "analyzer/video/video_quality_analyzer_injection_helper.h", + ] + deps = [ + ":encoded_image_id_injector_api", + ":id_generator", + ":quality_analyzing_video_decoder", + ":quality_analyzing_video_encoder", + "../../../api/video:video_frame", + "../../../api/video_codecs:video_codecs_api", + "../../../test:video_test_common", + "../../../test:video_test_support", + "api:video_quality_analyzer_api", + "//third_party/abseil-cpp/absl/memory:memory", + ] + } + rtc_source_set("single_process_encoded_image_id_injector_unittest") { testonly = true sources = [ diff --git a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc new file mode 100644 index 0000000000..fab8849281 --- /dev/null +++ b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc @@ -0,0 +1,139 @@ +/* + * 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/video_quality_analyzer_injection_helper.h" + +#include + +#include "absl/memory/memory.h" +#include "test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h" +#include "test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h" + +namespace webrtc { +namespace test { + +namespace { + +// Intercepts generated frames and passes them also to video quality analyzer +// and into video frame writer, if the last one is provided. +class InterceptingFrameGenerator : public FrameGenerator { + public: + InterceptingFrameGenerator(std::string stream_label, + std::unique_ptr delegate, + VideoQualityAnalyzerInterface* analyzer, + VideoFrameWriter* video_writer) + : stream_label_(std::move(stream_label)), + delegate_(std::move(delegate)), + analyzer_(analyzer), + video_writer_(video_writer) { + RTC_DCHECK(analyzer_); + } + ~InterceptingFrameGenerator() override = default; + + VideoFrame* NextFrame() override { + VideoFrame* frame = delegate_->NextFrame(); + uint16_t frame_id = analyzer_->OnFrameCaptured(stream_label_, *frame); + frame->set_id(frame_id); + if (video_writer_) { + bool result = video_writer_->WriteFrame(*frame); + RTC_CHECK(result) << "Failed to write frame"; + } + return frame; + } + + void ChangeResolution(size_t width, size_t height) override { + delegate_->ChangeResolution(width, height); + } + + private: + std::string stream_label_; + std::unique_ptr delegate_; + VideoQualityAnalyzerInterface* analyzer_; + VideoFrameWriter* video_writer_; +}; + +// Implements the video sink, that forwards rendered frames to the video quality +// analyzer and to the video frame writer, if the last one is provided. +class AnalyzingVideoSink : public rtc::VideoSinkInterface { + public: + AnalyzingVideoSink(VideoQualityAnalyzerInterface* analyzer, + VideoFrameWriter* video_writer) + : analyzer_(analyzer), video_writer_(video_writer) { + RTC_DCHECK(analyzer_); + } + ~AnalyzingVideoSink() override = default; + + void OnFrame(const VideoFrame& frame) override { + analyzer_->OnFrameRendered(frame); + if (video_writer_) { + bool result = video_writer_->WriteFrame(frame); + RTC_CHECK(result) << "Failed to write frame"; + } + } + void OnDiscardedFrame() override {} + + private: + VideoQualityAnalyzerInterface* analyzer_; + VideoFrameWriter* video_writer_; +}; + +} // namespace + +VideoQualityAnalyzerInjectionHelper::VideoQualityAnalyzerInjectionHelper( + std::unique_ptr analyzer, + EncodedImageIdInjector* injector, + EncodedImageIdExtractor* extractor) + : analyzer_(std::move(analyzer)), + injector_(injector), + extractor_(extractor), + encoding_entities_id_generator_(absl::make_unique(1)) { + RTC_DCHECK(injector_); + RTC_DCHECK(extractor_); +} +VideoQualityAnalyzerInjectionHelper::~VideoQualityAnalyzerInjectionHelper() = + default; + +std::unique_ptr +VideoQualityAnalyzerInjectionHelper::WrapVideoEncoderFactory( + std::unique_ptr delegate) const { + return absl::make_unique( + std::move(delegate), encoding_entities_id_generator_.get(), injector_, + analyzer_.get()); +} + +std::unique_ptr +VideoQualityAnalyzerInjectionHelper::WrapVideoDecoderFactory( + std::unique_ptr delegate) const { + return absl::make_unique( + std::move(delegate), encoding_entities_id_generator_.get(), extractor_, + analyzer_.get()); +} + +std::unique_ptr +VideoQualityAnalyzerInjectionHelper::WrapFrameGenerator( + std::string stream_label, + std::unique_ptr delegate, + VideoFrameWriter* writer) const { + return absl::make_unique( + std::move(stream_label), std::move(delegate), analyzer_.get(), writer); +} + +std::unique_ptr> +VideoQualityAnalyzerInjectionHelper::CreateVideoSink( + VideoFrameWriter* writer) const { + return absl::make_unique(analyzer_.get(), writer); +} + +void VideoQualityAnalyzerInjectionHelper::Stop() { + analyzer_->Stop(); +} + +} // namespace test +} // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h new file mode 100644 index 0000000000..40a381d73a --- /dev/null +++ b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h @@ -0,0 +1,76 @@ +/* + * 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_VIDEO_QUALITY_ANALYZER_INJECTION_HELPER_H_ +#define TEST_PC_E2E_ANALYZER_VIDEO_VIDEO_QUALITY_ANALYZER_INJECTION_HELPER_H_ + +#include +#include + +#include "api/video/video_frame.h" +#include "api/video/video_sink_interface.h" +#include "api/video_codecs/video_decoder_factory.h" +#include "api/video_codecs/video_encoder_factory.h" +#include "test/frame_generator.h" +#include "test/pc/e2e/analyzer/video/encoded_image_id_injector.h" +#include "test/pc/e2e/analyzer/video/id_generator.h" +#include "test/pc/e2e/api/video_quality_analyzer_interface.h" +#include "test/testsupport/video_frame_writer.h" + +namespace webrtc { +namespace test { + +// Provides factory methods for components, that will be used to inject +// VideoQualityAnalyzerInterface into PeerConnection pipeline. +class VideoQualityAnalyzerInjectionHelper { + public: + VideoQualityAnalyzerInjectionHelper( + std::unique_ptr analyzer, + EncodedImageIdInjector* injector, + EncodedImageIdExtractor* extractor); + ~VideoQualityAnalyzerInjectionHelper(); + + // Wraps video encoder factory to give video quality analyzer access to frames + // before encoding and encoded images after. + std::unique_ptr WrapVideoEncoderFactory( + std::unique_ptr delegate) const; + // Wraps video decoder factory to give video quality analyzer access to + // received encoded images and frames, that were decoded from them. + std::unique_ptr WrapVideoDecoderFactory( + std::unique_ptr delegate) const; + + // Wraps frame generator, so video quality analyzer will gain access to the + // captured frames. If |writer| in not nullptr, will dump captured frames + // with provided writer. + std::unique_ptr WrapFrameGenerator( + std::string stream_label, + std::unique_ptr delegate, + VideoFrameWriter* writer) const; + // Creates sink, that will allow video quality analyzer to get access to the + // rendered frames. If |writer| in not nullptr, will dump rendered frames + // with provided writer. + std::unique_ptr> CreateVideoSink( + VideoFrameWriter* writer) const; + + // Stops VideoQualityAnalyzerInterface to populate final data and metrics. + void Stop(); + + private: + std::unique_ptr analyzer_; + EncodedImageIdInjector* injector_; + EncodedImageIdExtractor* extractor_; + + std::unique_ptr> encoding_entities_id_generator_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_PC_E2E_ANALYZER_VIDEO_VIDEO_QUALITY_ANALYZER_INJECTION_HELPER_H_