diff --git a/api/test/video_codec_tester.h b/api/test/video_codec_tester.h index ab5a91574c..1bd341c05b 100644 --- a/api/test/video_codec_tester.h +++ b/api/test/video_codec_tester.h @@ -91,6 +91,8 @@ class VideoCodecTester { virtual ~Encoder() = default; + virtual void Initialize() = 0; + virtual void Encode(const VideoFrame& frame, EncodeCallback callback) = 0; virtual void Flush() = 0; @@ -104,6 +106,8 @@ class VideoCodecTester { virtual ~Decoder() = default; + virtual void Initialize() = 0; + virtual void Decode(const EncodedImage& frame, DecodeCallback callback) = 0; virtual void Flush() = 0; diff --git a/modules/video_coding/codecs/test/video_codec_test.cc b/modules/video_coding/codecs/test/video_codec_test.cc index 79968f2017..e260cb77ee 100644 --- a/modules/video_coding/codecs/test/video_codec_test.cc +++ b/modules/video_coding/codecs/test/video_codec_test.cc @@ -80,6 +80,33 @@ struct EncodingSettings { DataRate bitrate; }; std::map layer_settings; + + bool IsSameSettings(const EncodingSettings& other) const { + if (scalability_mode != other.scalability_mode) { + return true; + } + + for (auto [layer_id, layer] : layer_settings) { + const auto& other_layer = other.layer_settings.at(layer_id); + if (layer.resolution != other_layer.resolution) { + return true; + } + } + + return false; + } + + bool IsSameRate(const EncodingSettings& other) const { + for (auto [layer_id, layer] : layer_settings) { + const auto& other_layer = other.layer_settings.at(layer_id); + if (layer.bitrate != other_layer.bitrate || + layer.framerate != other_layer.framerate) { + return true; + } + } + + return false; + } }; const VideoInfo kFourPeople_1280x720_30 = { @@ -188,17 +215,20 @@ class TestEncoder : public VideoCodecTester::Encoder, encoder_->RegisterEncodeCompleteCallback(this); } + void Initialize() override { + const EncodingSettings& first_frame_settings = frame_settings_.at(0); + Configure(first_frame_settings); + SetRates(first_frame_settings); + } + void Encode(const VideoFrame& frame, EncodeCallback callback) override { callbacks_[frame.timestamp()] = std::move(callback); if (auto fs = frame_settings_.find(frame_num_); - fs != frame_settings_.end()) { - if (fs == frame_settings_.begin() || - ConfigChanged(fs->second, std::prev(fs)->second)) { + fs != frame_settings_.begin() && fs != frame_settings_.end()) { + if (!fs->second.IsSameSettings(std::prev(fs)->second)) { Configure(fs->second); - } - if (fs == frame_settings_.begin() || - RateChanged(fs->second, std::prev(fs)->second)) { + } else if (!fs->second.IsSameRate(std::prev(fs)->second)) { SetRates(fs->second); } } @@ -261,6 +291,8 @@ class TestEncoder : public VideoCodecTester::Encoder, int result = encoder_->InitEncode(&vc, ves); ASSERT_EQ(result, WEBRTC_VIDEO_CODEC_OK); + + SetRates(es); } void SetRates(const EncodingSettings& es) { @@ -284,34 +316,6 @@ class TestEncoder : public VideoCodecTester::Encoder, encoder_->SetRates(rc); } - bool ConfigChanged(const EncodingSettings& es, - const EncodingSettings& prev_es) const { - if (es.scalability_mode != prev_es.scalability_mode) { - return true; - } - - for (auto [layer_id, layer_settings] : es.layer_settings) { - const auto& prev_layer_settings = prev_es.layer_settings.at(layer_id); - if (layer_settings.resolution != prev_layer_settings.resolution) { - return true; - } - } - - return false; - } - - bool RateChanged(const EncodingSettings& es, - const EncodingSettings& prev_es) const { - for (auto [layer_id, layer_settings] : es.layer_settings) { - const auto& prev_layer_settings = prev_es.layer_settings.at(layer_id); - if (layer_settings.bitrate != prev_layer_settings.bitrate || - layer_settings.framerate != prev_layer_settings.framerate) { - return true; - } - } - return false; - } - std::unique_ptr encoder_; const std::string codec_type_; const std::map& frame_settings_; @@ -324,20 +328,24 @@ class TestDecoder : public VideoCodecTester::Decoder, public: TestDecoder(std::unique_ptr decoder, const std::string codec_type) - : decoder_(std::move(decoder)), codec_type_(codec_type), frame_num_(0) { + : decoder_(std::move(decoder)), codec_type_(codec_type) { decoder_->RegisterDecodeCompleteCallback(this); } + void Initialize() override { + VideoDecoder::Settings ds; + ds.set_codec_type(PayloadStringToCodecType(codec_type_)); + ds.set_number_of_cores(1); + ds.set_max_render_resolution({1280, 720}); + + bool result = decoder_->Configure(ds); + ASSERT_TRUE(result); + } + void Decode(const EncodedImage& frame, DecodeCallback callback) override { callbacks_[frame.Timestamp()] = std::move(callback); - - if (frame_num_ == 0) { - Configure(); - } - decoder_->Decode(frame, /*missing_frames=*/false, /*render_time_ms=*/0); - ++frame_num_; } void Flush() override { @@ -350,16 +358,6 @@ class TestDecoder : public VideoCodecTester::Decoder, VideoDecoder* decoder() { return decoder_.get(); } protected: - void Configure() { - VideoDecoder::Settings ds; - ds.set_codec_type(PayloadStringToCodecType(codec_type_)); - ds.set_number_of_cores(1); - ds.set_max_render_resolution({1280, 720}); - - bool result = decoder_->Configure(ds); - ASSERT_TRUE(result); - } - int Decoded(VideoFrame& decoded_frame) override { auto cb = callbacks_.find(decoded_frame.timestamp()); RTC_CHECK(cb != callbacks_.end()); @@ -371,7 +369,6 @@ class TestDecoder : public VideoCodecTester::Decoder, std::unique_ptr decoder_; const std::string codec_type_; - int frame_num_; std::map callbacks_; }; diff --git a/modules/video_coding/codecs/test/video_codec_tester_impl.cc b/modules/video_coding/codecs/test/video_codec_tester_impl.cc index 1d79933954..cccecf14b4 100644 --- a/modules/video_coding/codecs/test/video_codec_tester_impl.cc +++ b/modules/video_coding/codecs/test/video_codec_tester_impl.cc @@ -187,58 +187,6 @@ class TesterY4mWriter { 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.decoded_y4m_base_path) { - y4m_writer_ = - std::make_unique(*settings.decoded_y4m_base_path); - } - } - - void Decode(const EncodedImage& frame) { - Timestamp timestamp = Timestamp::Micros((frame.Timestamp() / k90kHz).us()); - - task_queue_.PostScheduledTask( - [this, frame] { - analyzer_->StartDecode(frame); - - decoder_->Decode( - frame, [this, spatial_idx = frame.SpatialIndex().value_or(0)]( - const VideoFrame& decoded_frame) { - analyzer_->FinishDecode(decoded_frame, spatial_idx); - - if (y4m_writer_) { - y4m_writer_->Write(decoded_frame, spatial_idx); - } - }); - }, - pacer_.Schedule(timestamp)); - } - - void Flush() { - Timestamp now = Timestamp::Micros(rtc::TimeMicros()); - task_queue_.PostScheduledTask([this] { decoder_->Flush(); }, now); - task_queue_.WaitForPreviouslyPostedTasks(); - } - - protected: - Decoder* const decoder_; - VideoCodecAnalyzer* const analyzer_; - const DecoderSettings& settings_; - Pacer pacer_; - LimitedTaskQueue task_queue_; - std::unique_ptr y4m_writer_; -}; - class TesterIvfWriter { public: explicit TesterIvfWriter(absl::string_view base_path) @@ -277,6 +225,64 @@ class TesterIvfWriter { 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.decoded_y4m_base_path) { + y4m_writer_ = + std::make_unique(*settings.decoded_y4m_base_path); + } + } + + void Initialize() { + task_queue_.PostScheduledTask([this] { decoder_->Initialize(); }, + Timestamp::Zero()); + task_queue_.WaitForPreviouslyPostedTasks(); + } + + void Decode(const EncodedImage& frame) { + Timestamp timestamp = Timestamp::Micros((frame.Timestamp() / k90kHz).us()); + + task_queue_.PostScheduledTask( + [this, frame] { + analyzer_->StartDecode(frame); + + decoder_->Decode( + frame, [this, spatial_idx = frame.SpatialIndex().value_or(0)]( + const VideoFrame& decoded_frame) { + analyzer_->FinishDecode(decoded_frame, spatial_idx); + + if (y4m_writer_) { + y4m_writer_->Write(decoded_frame, spatial_idx); + } + }); + }, + 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 y4m_writer_; +}; + class TesterEncoder { public: TesterEncoder(Encoder* encoder, @@ -295,6 +301,12 @@ class TesterEncoder { } } + void Initialize() { + task_queue_.PostScheduledTask([this] { encoder_->Initialize(); }, + Timestamp::Zero()); + task_queue_.WaitForPreviouslyPostedTasks(); + } + void Encode(const VideoFrame& frame) { Timestamp timestamp = Timestamp::Micros((frame.timestamp() / k90kHz).us()); @@ -317,8 +329,8 @@ class TesterEncoder { } void Flush() { - Timestamp now = Timestamp::Micros(rtc::TimeMicros()); - task_queue_.PostScheduledTask([this] { encoder_->Flush(); }, now); + task_queue_.PostScheduledTask([this] { encoder_->Flush(); }, + Timestamp::Zero()); task_queue_.WaitForPreviouslyPostedTasks(); } @@ -341,6 +353,8 @@ std::unique_ptr VideoCodecTesterImpl::RunDecodeTest( VideoCodecAnalyzer perf_analyzer; TesterDecoder tester_decoder(decoder, &perf_analyzer, decoder_settings); + tester_decoder.Initialize(); + while (auto frame = video_source->PullFrame()) { tester_decoder.Decode(*frame); } @@ -359,6 +373,8 @@ std::unique_ptr VideoCodecTesterImpl::RunEncodeTest( TesterEncoder tester_encoder(encoder, /*decoder=*/nullptr, &perf_analyzer, encoder_settings); + tester_encoder.Initialize(); + while (auto frame = sync_source.PullFrame()) { tester_encoder.Encode(*frame); } @@ -380,6 +396,9 @@ std::unique_ptr VideoCodecTesterImpl::RunEncodeDecodeTest( 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); } diff --git a/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc b/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc index a54c5cbbaa..459ef4f0dd 100644 --- a/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc +++ b/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc @@ -117,6 +117,7 @@ class MockCodedVideoSource : public CodedVideoSource { class MockDecoder : public Decoder { public: + MOCK_METHOD(void, Initialize, (), (override)); MOCK_METHOD(void, Decode, (const EncodedImage& frame, DecodeCallback callback), @@ -126,6 +127,7 @@ class MockDecoder : public Decoder { class MockEncoder : public Encoder { public: + MOCK_METHOD(void, Initialize, (), (override)); MOCK_METHOD(void, Encode, (const VideoFrame& frame, EncodeCallback callback),