aboutsummaryrefslogtreecommitdiff
path: root/modules/video_coding/codecs/test/video_codec_tester_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'modules/video_coding/codecs/test/video_codec_tester_impl.cc')
-rw-r--r--modules/video_coding/codecs/test/video_codec_tester_impl.cc437
1 files changed, 0 insertions, 437 deletions
diff --git a/modules/video_coding/codecs/test/video_codec_tester_impl.cc b/modules/video_coding/codecs/test/video_codec_tester_impl.cc
deleted file mode 100644
index f15b1b35f3..0000000000
--- a/modules/video_coding/codecs/test/video_codec_tester_impl.cc
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * 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.
- */
-
-#include "modules/video_coding/codecs/test/video_codec_tester_impl.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "api/task_queue/default_task_queue_factory.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/i420_buffer.h"
-#include "api/video/video_codec_type.h"
-#include "api/video/video_frame.h"
-#include "modules/video_coding/codecs/test/video_codec_analyzer.h"
-#include "modules/video_coding/utility/ivf_file_writer.h"
-#include "rtc_base/event.h"
-#include "rtc_base/time_utils.h"
-#include "system_wrappers/include/sleep.h"
-#include "test/testsupport/video_frame_writer.h"
-
-namespace webrtc {
-namespace test {
-
-namespace {
-using RawVideoSource = VideoCodecTester::RawVideoSource;
-using CodedVideoSource = VideoCodecTester::CodedVideoSource;
-using Decoder = VideoCodecTester::Decoder;
-using Encoder = VideoCodecTester::Encoder;
-using EncoderSettings = VideoCodecTester::EncoderSettings;
-using DecoderSettings = VideoCodecTester::DecoderSettings;
-using PacingSettings = VideoCodecTester::PacingSettings;
-using PacingMode = PacingSettings::PacingMode;
-
-constexpr Frequency k90kHz = Frequency::Hertz(90000);
-
-// A thread-safe wrapper for video source to be shared with the quality analyzer
-// that reads reference frames from a separate thread.
-class SyncRawVideoSource : public VideoCodecAnalyzer::ReferenceVideoSource {
- public:
- explicit SyncRawVideoSource(RawVideoSource* video_source)
- : video_source_(video_source) {}
-
- absl::optional<VideoFrame> PullFrame() {
- MutexLock lock(&mutex_);
- return video_source_->PullFrame();
- }
-
- VideoFrame GetFrame(uint32_t timestamp_rtp, Resolution resolution) override {
- MutexLock lock(&mutex_);
- return video_source_->GetFrame(timestamp_rtp, resolution);
- }
-
- protected:
- RawVideoSource* const video_source_ RTC_GUARDED_BY(mutex_);
- Mutex mutex_;
-};
-
-// Pacer calculates delay necessary to keep frame encode or decode call spaced
-// from the previous calls by the pacing time. `Delay` is expected to be called
-// as close as possible to posting frame encode or decode task. This class is
-// not thread safe.
-class Pacer {
- public:
- explicit Pacer(PacingSettings settings)
- : settings_(settings), delay_(TimeDelta::Zero()) {}
- Timestamp Schedule(Timestamp timestamp) {
- Timestamp now = Timestamp::Micros(rtc::TimeMicros());
- if (settings_.mode == PacingMode::kNoPacing) {
- return now;
- }
-
- Timestamp scheduled = now;
- if (prev_scheduled_) {
- scheduled = *prev_scheduled_ + PacingTime(timestamp);
- if (scheduled < now) {
- scheduled = now;
- }
- }
-
- prev_timestamp_ = timestamp;
- prev_scheduled_ = scheduled;
- return scheduled;
- }
-
- private:
- TimeDelta PacingTime(Timestamp timestamp) {
- if (settings_.mode == PacingMode::kRealTime) {
- return timestamp - *prev_timestamp_;
- }
- RTC_CHECK_EQ(PacingMode::kConstantRate, settings_.mode);
- return 1 / settings_.constant_rate;
- }
-
- PacingSettings settings_;
- absl::optional<Timestamp> prev_timestamp_;
- absl::optional<Timestamp> prev_scheduled_;
- TimeDelta delay_;
-};
-
-// Task queue that keeps the number of queued tasks below a certain limit. If
-// the limit is reached, posting of a next task is blocked until execution of a
-// previously posted task starts. This class is not thread-safe.
-class LimitedTaskQueue {
- public:
- // The codec tester reads frames from video source in the main thread.
- // Encoding and decoding are done in separate threads. If encoding or
- // decoding is slow, the reading may go far ahead and may buffer too many
- // frames in memory. To prevent this we limit the encoding/decoding queue
- // size. When the queue is full, the main thread and, hence, reading frames
- // from video source is blocked until a previously posted encoding/decoding
- // task starts.
- static constexpr int kMaxTaskQueueSize = 3;
-
- LimitedTaskQueue() : queue_size_(0) {}
-
- void PostScheduledTask(absl::AnyInvocable<void() &&> task, Timestamp start) {
- ++queue_size_;
- task_queue_.PostTask([this, task = std::move(task), start]() mutable {
- int wait_ms = static_cast<int>(start.ms() - rtc::TimeMillis());
- if (wait_ms > 0) {
- SleepMs(wait_ms);
- }
-
- std::move(task)();
- --queue_size_;
- task_executed_.Set();
- });
-
- task_executed_.Reset();
- if (queue_size_ > kMaxTaskQueueSize) {
- task_executed_.Wait(rtc::Event::kForever);
- }
- RTC_CHECK(queue_size_ <= kMaxTaskQueueSize);
- }
-
- void WaitForPreviouslyPostedTasks() {
- task_queue_.SendTask([] {});
- }
-
- TaskQueueForTest task_queue_;
- std::atomic_int queue_size_;
- rtc::Event task_executed_;
-};
-
-class TesterY4mWriter {
- public:
- explicit TesterY4mWriter(absl::string_view base_path)
- : base_path_(base_path) {}
-
- ~TesterY4mWriter() {
- task_queue_.SendTask([] {});
- }
-
- void Write(const VideoFrame& frame, int spatial_idx) {
- task_queue_.PostTask([this, frame, spatial_idx] {
- if (y4m_writers_.find(spatial_idx) == y4m_writers_.end()) {
- std::string file_path =
- base_path_ + "_s" + std::to_string(spatial_idx) + ".y4m";
-
- Y4mVideoFrameWriterImpl* y4m_writer = new Y4mVideoFrameWriterImpl(
- file_path, frame.width(), frame.height(), /*fps=*/30);
- RTC_CHECK(y4m_writer);
-
- y4m_writers_[spatial_idx] =
- std::unique_ptr<VideoFrameWriter>(y4m_writer);
- }
-
- y4m_writers_.at(spatial_idx)->WriteFrame(frame);
- });
- }
-
- protected:
- std::string base_path_;
- std::map<int, std::unique_ptr<VideoFrameWriter>> y4m_writers_;
- TaskQueueForTest task_queue_;
-};
-
-class TesterIvfWriter {
- public:
- explicit TesterIvfWriter(absl::string_view base_path)
- : base_path_(base_path) {}
-
- ~TesterIvfWriter() {
- task_queue_.SendTask([] {});
- }
-
- void Write(const EncodedImage& encoded_frame) {
- task_queue_.PostTask([this, encoded_frame] {
- int spatial_idx = encoded_frame.SpatialIndex().value_or(0);
- if (ivf_file_writers_.find(spatial_idx) == ivf_file_writers_.end()) {
- std::string ivf_path =
- base_path_ + "_s" + std::to_string(spatial_idx) + ".ivf";
-
- FileWrapper ivf_file = FileWrapper::OpenWriteOnly(ivf_path);
- RTC_CHECK(ivf_file.is_open());
-
- std::unique_ptr<IvfFileWriter> ivf_writer =
- IvfFileWriter::Wrap(std::move(ivf_file), /*byte_limit=*/0);
- RTC_CHECK(ivf_writer);
-
- ivf_file_writers_[spatial_idx] = std::move(ivf_writer);
- }
-
- // To play: ffplay -vcodec vp8|vp9|av1|hevc|h264 filename
- ivf_file_writers_.at(spatial_idx)
- ->WriteFrame(encoded_frame, VideoCodecType::kVideoCodecGeneric);
- });
- }
-
- protected:
- std::string base_path_;
- std::map<int, std::unique_ptr<IvfFileWriter>> ivf_file_writers_;
- TaskQueueForTest task_queue_;
-};
-
-class TesterDecoder {
- public:
- TesterDecoder(Decoder* decoder,
- VideoCodecAnalyzer* analyzer,
- const DecoderSettings& settings)
- : decoder_(decoder),
- analyzer_(analyzer),
- settings_(settings),
- pacer_(settings.pacing) {
- RTC_CHECK(analyzer_) << "Analyzer must be provided";
-
- if (settings.decoder_input_base_path) {
- input_writer_ =
- std::make_unique<TesterIvfWriter>(*settings.decoder_input_base_path);
- }
-
- if (settings.decoder_output_base_path) {
- output_writer_ =
- std::make_unique<TesterY4mWriter>(*settings.decoder_output_base_path);
- }
- }
-
- void Initialize() {
- task_queue_.PostScheduledTask([this] { decoder_->Initialize(); },
- Timestamp::Zero());
- task_queue_.WaitForPreviouslyPostedTasks();
- }
-
- void Decode(const EncodedImage& input_frame) {
- Timestamp timestamp =
- Timestamp::Micros((input_frame.RtpTimestamp() / k90kHz).us());
-
- task_queue_.PostScheduledTask(
- [this, input_frame] {
- analyzer_->StartDecode(input_frame);
-
- decoder_->Decode(
- input_frame,
- [this, spatial_idx = input_frame.SpatialIndex().value_or(0)](
- const VideoFrame& output_frame) {
- analyzer_->FinishDecode(output_frame, spatial_idx);
-
- if (output_writer_) {
- output_writer_->Write(output_frame, spatial_idx);
- }
- });
-
- if (input_writer_) {
- input_writer_->Write(input_frame);
- }
- },
- pacer_.Schedule(timestamp));
- }
-
- void Flush() {
- task_queue_.PostScheduledTask([this] { decoder_->Flush(); },
- Timestamp::Zero());
- task_queue_.WaitForPreviouslyPostedTasks();
- }
-
- protected:
- Decoder* const decoder_;
- VideoCodecAnalyzer* const analyzer_;
- const DecoderSettings& settings_;
- Pacer pacer_;
- LimitedTaskQueue task_queue_;
- std::unique_ptr<TesterIvfWriter> input_writer_;
- std::unique_ptr<TesterY4mWriter> output_writer_;
-};
-
-class TesterEncoder {
- public:
- TesterEncoder(Encoder* encoder,
- TesterDecoder* decoder,
- VideoCodecAnalyzer* analyzer,
- const EncoderSettings& settings)
- : encoder_(encoder),
- decoder_(decoder),
- analyzer_(analyzer),
- settings_(settings),
- pacer_(settings.pacing) {
- RTC_CHECK(analyzer_) << "Analyzer must be provided";
- if (settings.encoder_input_base_path) {
- input_writer_ =
- std::make_unique<TesterY4mWriter>(*settings.encoder_input_base_path);
- }
-
- if (settings.encoder_output_base_path) {
- output_writer_ =
- std::make_unique<TesterIvfWriter>(*settings.encoder_output_base_path);
- }
- }
-
- void Initialize() {
- task_queue_.PostScheduledTask([this] { encoder_->Initialize(); },
- Timestamp::Zero());
- task_queue_.WaitForPreviouslyPostedTasks();
- }
-
- void Encode(const VideoFrame& input_frame) {
- Timestamp timestamp =
- Timestamp::Micros((input_frame.timestamp() / k90kHz).us());
-
- task_queue_.PostScheduledTask(
- [this, input_frame] {
- analyzer_->StartEncode(input_frame);
- encoder_->Encode(input_frame,
- [this](const EncodedImage& encoded_frame) {
- analyzer_->FinishEncode(encoded_frame);
-
- if (decoder_ != nullptr) {
- decoder_->Decode(encoded_frame);
- }
-
- if (output_writer_ != nullptr) {
- output_writer_->Write(encoded_frame);
- }
- });
-
- if (input_writer_) {
- input_writer_->Write(input_frame, /*spatial_idx=*/0);
- }
- },
- pacer_.Schedule(timestamp));
- }
-
- void Flush() {
- task_queue_.PostScheduledTask([this] { encoder_->Flush(); },
- Timestamp::Zero());
- task_queue_.WaitForPreviouslyPostedTasks();
- }
-
- protected:
- Encoder* const encoder_;
- TesterDecoder* const decoder_;
- VideoCodecAnalyzer* const analyzer_;
- const EncoderSettings& settings_;
- std::unique_ptr<TesterY4mWriter> input_writer_;
- std::unique_ptr<TesterIvfWriter> output_writer_;
- Pacer pacer_;
- LimitedTaskQueue task_queue_;
-};
-
-} // namespace
-
-std::unique_ptr<VideoCodecStats> VideoCodecTesterImpl::RunDecodeTest(
- CodedVideoSource* video_source,
- Decoder* decoder,
- const DecoderSettings& decoder_settings) {
- VideoCodecAnalyzer perf_analyzer;
- TesterDecoder tester_decoder(decoder, &perf_analyzer, decoder_settings);
-
- tester_decoder.Initialize();
-
- while (auto frame = video_source->PullFrame()) {
- tester_decoder.Decode(*frame);
- }
-
- tester_decoder.Flush();
-
- return perf_analyzer.GetStats();
-}
-
-std::unique_ptr<VideoCodecStats> VideoCodecTesterImpl::RunEncodeTest(
- RawVideoSource* video_source,
- Encoder* encoder,
- const EncoderSettings& encoder_settings) {
- SyncRawVideoSource sync_source(video_source);
- VideoCodecAnalyzer perf_analyzer;
- TesterEncoder tester_encoder(encoder, /*decoder=*/nullptr, &perf_analyzer,
- encoder_settings);
-
- tester_encoder.Initialize();
-
- while (auto frame = sync_source.PullFrame()) {
- tester_encoder.Encode(*frame);
- }
-
- tester_encoder.Flush();
-
- return perf_analyzer.GetStats();
-}
-
-std::unique_ptr<VideoCodecStats> VideoCodecTesterImpl::RunEncodeDecodeTest(
- RawVideoSource* video_source,
- Encoder* encoder,
- Decoder* decoder,
- const EncoderSettings& encoder_settings,
- const DecoderSettings& decoder_settings) {
- SyncRawVideoSource sync_source(video_source);
- VideoCodecAnalyzer perf_analyzer(&sync_source);
- TesterDecoder tester_decoder(decoder, &perf_analyzer, decoder_settings);
- TesterEncoder tester_encoder(encoder, &tester_decoder, &perf_analyzer,
- encoder_settings);
-
- tester_encoder.Initialize();
- tester_decoder.Initialize();
-
- while (auto frame = sync_source.PullFrame()) {
- tester_encoder.Encode(*frame);
- }
-
- tester_encoder.Flush();
- tester_decoder.Flush();
-
- return perf_analyzer.GetStats();
-}
-
-} // namespace test
-} // namespace webrtc