From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- .../libwebrtc/test/frame_generator_capturer.cc | 323 +++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 third_party/libwebrtc/test/frame_generator_capturer.cc (limited to 'third_party/libwebrtc/test/frame_generator_capturer.cc') diff --git a/third_party/libwebrtc/test/frame_generator_capturer.cc b/third_party/libwebrtc/test/frame_generator_capturer.cc new file mode 100644 index 0000000000..c69fca0965 --- /dev/null +++ b/third_party/libwebrtc/test/frame_generator_capturer.cc @@ -0,0 +1,323 @@ +/* + * 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. + */ + +#include "test/frame_generator_capturer.h" + +#include +#include +#include +#include +#include +#include + +#include "absl/strings/match.h" +#include "api/test/create_frame_generator.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/task_queue.h" +#include "rtc_base/time_utils.h" +#include "system_wrappers/include/clock.h" +#include "test/testsupport/file_utils.h" + +namespace webrtc { +namespace test { +namespace { +std::string TransformFilePath(std::string path) { + static const std::string resource_prefix = "res://"; + int ext_pos = path.rfind('.'); + if (ext_pos < 0) { + return test::ResourcePath(path, "yuv"); + } else if (absl::StartsWith(path, resource_prefix)) { + std::string name = path.substr(resource_prefix.length(), ext_pos); + std::string ext = path.substr(ext_pos, path.size()); + return test::ResourcePath(name, ext); + } + return path; +} +} // namespace + +FrameGeneratorCapturer::FrameGeneratorCapturer( + Clock* clock, + std::unique_ptr frame_generator, + int target_fps, + TaskQueueFactory& task_queue_factory) + : clock_(clock), + sending_(true), + sink_wants_observer_(nullptr), + frame_generator_(std::move(frame_generator)), + source_fps_(target_fps), + target_capture_fps_(target_fps), + first_frame_capture_time_(-1), + task_queue_(task_queue_factory.CreateTaskQueue( + "FrameGenCapQ", + TaskQueueFactory::Priority::HIGH)) { + RTC_DCHECK(frame_generator_); + RTC_DCHECK_GT(target_fps, 0); +} + +FrameGeneratorCapturer::~FrameGeneratorCapturer() { + Stop(); +} + +std::unique_ptr FrameGeneratorCapturer::Create( + Clock* clock, + TaskQueueFactory& task_queue_factory, + FrameGeneratorCapturerConfig::SquaresVideo config) { + return std::make_unique( + clock, + CreateSquareFrameGenerator(config.width, config.height, + config.pixel_format, config.num_squares), + config.framerate, task_queue_factory); +} +std::unique_ptr FrameGeneratorCapturer::Create( + Clock* clock, + TaskQueueFactory& task_queue_factory, + FrameGeneratorCapturerConfig::SquareSlides config) { + return std::make_unique( + clock, + CreateSlideFrameGenerator( + config.width, config.height, + /*frame_repeat_count*/ config.change_interval.seconds() * + config.framerate), + config.framerate, task_queue_factory); +} +std::unique_ptr FrameGeneratorCapturer::Create( + Clock* clock, + TaskQueueFactory& task_queue_factory, + FrameGeneratorCapturerConfig::VideoFile config) { + RTC_CHECK(config.width && config.height); + return std::make_unique( + clock, + CreateFromYuvFileFrameGenerator({TransformFilePath(config.name)}, + config.width, config.height, + /*frame_repeat_count*/ 1), + config.framerate, task_queue_factory); +} + +std::unique_ptr FrameGeneratorCapturer::Create( + Clock* clock, + TaskQueueFactory& task_queue_factory, + FrameGeneratorCapturerConfig::ImageSlides config) { + std::unique_ptr slides_generator; + std::vector paths = config.paths; + for (std::string& path : paths) + path = TransformFilePath(path); + + if (config.crop.width || config.crop.height) { + TimeDelta pause_duration = + config.change_interval - config.crop.scroll_duration; + RTC_CHECK_GE(pause_duration, TimeDelta::Zero()); + int crop_width = config.crop.width.value_or(config.width); + int crop_height = config.crop.height.value_or(config.height); + RTC_CHECK_LE(crop_width, config.width); + RTC_CHECK_LE(crop_height, config.height); + slides_generator = CreateScrollingInputFromYuvFilesFrameGenerator( + clock, paths, config.width, config.height, crop_width, crop_height, + config.crop.scroll_duration.ms(), pause_duration.ms()); + } else { + slides_generator = CreateFromYuvFileFrameGenerator( + paths, config.width, config.height, + /*frame_repeat_count*/ config.change_interval.seconds() * + config.framerate); + } + return std::make_unique( + clock, std::move(slides_generator), config.framerate, task_queue_factory); +} + +std::unique_ptr FrameGeneratorCapturer::Create( + Clock* clock, + TaskQueueFactory& task_queue_factory, + const FrameGeneratorCapturerConfig& config) { + if (config.video_file) { + return Create(clock, task_queue_factory, *config.video_file); + } else if (config.image_slides) { + return Create(clock, task_queue_factory, *config.image_slides); + } else if (config.squares_slides) { + return Create(clock, task_queue_factory, *config.squares_slides); + } else { + return Create(clock, task_queue_factory, + config.squares_video.value_or( + FrameGeneratorCapturerConfig::SquaresVideo())); + } +} + +void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) { + MutexLock lock(&lock_); + fake_rotation_ = rotation; +} + +void FrameGeneratorCapturer::SetFakeColorSpace( + absl::optional color_space) { + MutexLock lock(&lock_); + fake_color_space_ = color_space; +} + +bool FrameGeneratorCapturer::Init() { + // This check is added because frame_generator_ might be file based and should + // not crash because a file moved. + if (frame_generator_.get() == nullptr) + return false; + + frame_task_ = RepeatingTaskHandle::DelayedStart( + task_queue_.Get(), + TimeDelta::Seconds(1) / GetCurrentConfiguredFramerate(), + [this] { + InsertFrame(); + return TimeDelta::Seconds(1) / GetCurrentConfiguredFramerate(); + }, + TaskQueueBase::DelayPrecision::kHigh); + return true; +} + +void FrameGeneratorCapturer::InsertFrame() { + absl::optional resolution; + + { + MutexLock lock(&lock_); + if (sending_) { + FrameGeneratorInterface::VideoFrameData frame_data = + frame_generator_->NextFrame(); + // TODO(srte): Use more advanced frame rate control to allow arbritrary + // fractions. + int decimation = + std::round(static_cast(source_fps_) / target_capture_fps_); + for (int i = 1; i < decimation; ++i) + frame_data = frame_generator_->NextFrame(); + + VideoFrame frame = + VideoFrame::Builder() + .set_video_frame_buffer(frame_data.buffer) + .set_rotation(fake_rotation_) + .set_timestamp_us(clock_->TimeInMicroseconds()) + .set_ntp_time_ms(clock_->CurrentNtpInMilliseconds()) + .set_update_rect(frame_data.update_rect) + .set_color_space(fake_color_space_) + .build(); + if (first_frame_capture_time_ == -1) { + first_frame_capture_time_ = frame.ntp_time_ms(); + } + + resolution = Resolution{frame.width(), frame.height()}; + + TestVideoCapturer::OnFrame(frame); + } + } + + if (resolution) { + MutexLock lock(&stats_lock_); + source_resolution_ = resolution; + } +} + +absl::optional +FrameGeneratorCapturer::GetResolution() { + MutexLock lock(&stats_lock_); + return source_resolution_; +} + +void FrameGeneratorCapturer::Start() { + { + MutexLock lock(&lock_); + sending_ = true; + } + if (!frame_task_.Running()) { + frame_task_ = RepeatingTaskHandle::Start( + task_queue_.Get(), + [this] { + InsertFrame(); + return TimeDelta::Seconds(1) / GetCurrentConfiguredFramerate(); + }, + TaskQueueBase::DelayPrecision::kHigh); + } +} + +void FrameGeneratorCapturer::Stop() { + MutexLock lock(&lock_); + sending_ = false; +} + +void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) { + MutexLock lock(&lock_); + frame_generator_->ChangeResolution(width, height); +} + +void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) { + MutexLock lock(&lock_); + RTC_CHECK(target_capture_fps_ > 0); + if (target_framerate > source_fps_) + RTC_LOG(LS_WARNING) << "Target framerate clamped from " << target_framerate + << " to " << source_fps_; + if (source_fps_ % target_capture_fps_ != 0) { + int decimation = + std::round(static_cast(source_fps_) / target_capture_fps_); + int effective_rate = target_capture_fps_ / decimation; + RTC_LOG(LS_WARNING) << "Target framerate, " << target_framerate + << ", is an uneven fraction of the source rate, " + << source_fps_ + << ". The framerate will be :" << effective_rate; + } + target_capture_fps_ = std::min(source_fps_, target_framerate); +} + +void FrameGeneratorCapturer::OnOutputFormatRequest( + int width, + int height, + const absl::optional& max_fps) { + TestVideoCapturer::OnOutputFormatRequest(width, height, max_fps); +} + +void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) { + MutexLock lock(&lock_); + RTC_DCHECK(!sink_wants_observer_); + sink_wants_observer_ = observer; +} + +void FrameGeneratorCapturer::AddOrUpdateSink( + rtc::VideoSinkInterface* sink, + const rtc::VideoSinkWants& wants) { + TestVideoCapturer::AddOrUpdateSink(sink, wants); + MutexLock lock(&lock_); + if (sink_wants_observer_) { + // Tests need to observe unmodified sink wants. + sink_wants_observer_->OnSinkWantsChanged(sink, wants); + } + UpdateFps(GetSinkWants().max_framerate_fps); +} + +void FrameGeneratorCapturer::RemoveSink( + rtc::VideoSinkInterface* sink) { + TestVideoCapturer::RemoveSink(sink); + + MutexLock lock(&lock_); + UpdateFps(GetSinkWants().max_framerate_fps); +} + +void FrameGeneratorCapturer::UpdateFps(int max_fps) { + if (max_fps < target_capture_fps_) { + wanted_fps_.emplace(max_fps); + } else { + wanted_fps_.reset(); + } +} + +void FrameGeneratorCapturer::ForceFrame() { + // One-time non-repeating task, + task_queue_.PostTask([this] { InsertFrame(); }); +} + +int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() { + MutexLock lock(&lock_); + if (wanted_fps_ && *wanted_fps_ < target_capture_fps_) + return *wanted_fps_; + return target_capture_fps_; +} + +} // namespace test +} // namespace webrtc -- cgit v1.2.3