diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc index fe7fcb6f6b..4b67525e6e 100644 --- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc +++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc @@ -648,18 +648,26 @@ void VideoCodecTestFixtureImpl::SetUpAndInitObjects( RTC_DCHECK(decoded_frame_writers_.empty()); const size_t num_simulcast_or_spatial_layers = std::max( config_.NumberOfSimulcastStreams(), config_.NumberOfSpatialLayers()); + const size_t num_temporal_layers = config_.NumberOfTemporalLayers(); for (size_t simulcast_svc_idx = 0; simulcast_svc_idx < num_simulcast_or_spatial_layers; ++simulcast_svc_idx) { - const std::string output_filename_base = OutputPath() + - FilenameWithParams(config_) + "_" + - std::to_string(simulcast_svc_idx); + const std::string output_filename_base = + OutputPath() + FilenameWithParams(config_) + "_sl" + + std::to_string(simulcast_svc_idx); if (config_.visualization_params.save_encoded_ivf) { - FileWrapper post_encode_file = - FileWrapper::OpenWriteOnly(output_filename_base + ".ivf"); - encoded_frame_writers_.push_back( - IvfFileWriter::Wrap(std::move(post_encode_file), 0)); + for (size_t temporal_idx = 0; temporal_idx < num_temporal_layers; + ++temporal_idx) { + const std::string output_file_path = + output_filename_base + "tl" + std::to_string(temporal_idx) + ".ivf"; + FileWrapper ivf_file = FileWrapper::OpenWriteOnly(output_file_path); + + const VideoProcessor::LayerKey layer_key(simulcast_svc_idx, + temporal_idx); + encoded_frame_writers_[layer_key] = + IvfFileWriter::Wrap(std::move(ivf_file), /*byte_limit=*/0); + } } if (config_.visualization_params.save_decoded_y4m) { @@ -680,8 +688,7 @@ void VideoCodecTestFixtureImpl::SetUpAndInitObjects( CreateEncoderAndDecoder(); processor_ = absl::make_unique( encoder_.get(), &decoders_, source_frame_reader_.get(), config_, - &stats_, - encoded_frame_writers_.empty() ? nullptr : &encoded_frame_writers_, + &stats_, &encoded_frame_writers_, decoded_frame_writers_.empty() ? nullptr : &decoded_frame_writers_); }); } @@ -698,7 +705,7 @@ void VideoCodecTestFixtureImpl::ReleaseAndCloseObjects( // Close visualization files. for (auto& encoded_frame_writer : encoded_frame_writers_) { - EXPECT_TRUE(encoded_frame_writer->Close()); + EXPECT_TRUE(encoded_frame_writer.second->Close()); } encoded_frame_writers_.clear(); for (auto& decoded_frame_writer : decoded_frame_writers_) { diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.h b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.h index 9f4dbc5f7a..04f778b7f1 100644 --- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.h +++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.h @@ -95,7 +95,7 @@ class VideoCodecTestFixtureImpl : public VideoCodecTestFixture { Config config_; VideoCodecTestStatsImpl stats_; std::unique_ptr source_frame_reader_; - VideoProcessor::IvfFileWriterList encoded_frame_writers_; + VideoProcessor::IvfFileWriterMap encoded_frame_writers_; VideoProcessor::FrameWriterList decoded_frame_writers_; std::unique_ptr processor_; std::unique_ptr cpu_process_time_; diff --git a/modules/video_coding/codecs/test/videoprocessor.cc b/modules/video_coding/codecs/test/videoprocessor.cc index f73e06fc26..3e10c5d027 100644 --- a/modules/video_coding/codecs/test/videoprocessor.cc +++ b/modules/video_coding/codecs/test/videoprocessor.cc @@ -165,7 +165,7 @@ VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder, FrameReader* input_frame_reader, const VideoCodecTestFixture::Config& config, VideoCodecTestStats* stats, - IvfFileWriterList* encoded_frame_writers, + IvfFileWriterMap* encoded_frame_writers, FrameWriterList* decoded_frame_writers) : config_(config), num_simulcast_or_spatial_layers_( @@ -194,13 +194,12 @@ VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder, // Sanity checks. RTC_CHECK(TaskQueueBase::Current()) << "VideoProcessor must be run on a task queue."; - RTC_CHECK(encoder); - RTC_CHECK(decoders); - RTC_CHECK_EQ(decoders->size(), num_simulcast_or_spatial_layers_); - RTC_CHECK(input_frame_reader); - RTC_CHECK(stats); - RTC_CHECK(!encoded_frame_writers || - encoded_frame_writers->size() == num_simulcast_or_spatial_layers_); + RTC_CHECK(stats_); + RTC_CHECK(encoder_); + RTC_CHECK(decoders_); + RTC_CHECK_EQ(decoders_->size(), num_simulcast_or_spatial_layers_); + RTC_CHECK(input_frame_reader_); + RTC_CHECK(encoded_frame_writers_); RTC_CHECK(!decoded_frame_writers || decoded_frame_writers->size() == num_simulcast_or_spatial_layers_); @@ -360,8 +359,8 @@ void VideoProcessor::FrameEncoded( last_encoded_frame_num_[spatial_idx] < frame_number); // Ensure SVC spatial layers are delivered in ascending order. - if (!first_encoded_frame_[spatial_idx] && - config_.NumberOfSpatialLayers() > 1) { + const size_t num_spatial_layers = config_.NumberOfSpatialLayers(); + if (!first_encoded_frame_[spatial_idx] && num_spatial_layers > 1) { for (size_t i = 0; i < spatial_idx; ++i) { RTC_CHECK_LE(last_encoded_frame_num_[i], frame_number); } @@ -385,7 +384,6 @@ void VideoProcessor::FrameEncoded( frame_stat->max_nalu_size_bytes = GetMaxNaluSizeBytes(encoded_image, config_); frame_stat->qp = encoded_image.qp_; - const size_t num_spatial_layers = config_.NumberOfSpatialLayers(); bool end_of_picture = false; if (codec_type == kVideoCodecVP9) { const CodecSpecificInfoVP9& vp9_info = codec_specific.codecSpecific.VP9; @@ -399,7 +397,7 @@ void VideoProcessor::FrameEncoded( } const webrtc::EncodedImage* encoded_image_for_decode = &encoded_image; - if (config_.decode || encoded_frame_writers_) { + if (config_.decode || !encoded_frame_writers_->empty()) { if (num_spatial_layers > 1) { encoded_image_for_decode = BuildAndStoreSuperframe( encoded_image, codec_type, frame_number, spatial_idx, @@ -436,10 +434,17 @@ void VideoProcessor::FrameEncoded( frame_stat->decode_return_code = WEBRTC_VIDEO_CODEC_NO_OUTPUT; } - if (encoded_frame_writers_) { - RTC_CHECK(encoded_frame_writers_->at(spatial_idx) - ->WriteFrame(*encoded_image_for_decode, - config_.codec_settings.codecType)); + // Since frames in higher TLs typically depend on frames in lower TLs, + // write out frames in lower TLs to bitstream dumps of higher TLs. + for (size_t write_temporal_idx = temporal_idx; + write_temporal_idx < config_.NumberOfTemporalLayers(); + ++write_temporal_idx) { + const VideoProcessor::LayerKey layer_key(spatial_idx, write_temporal_idx); + auto it = encoded_frame_writers_->find(layer_key); + if (it != encoded_frame_writers_->cend()) { + RTC_CHECK(it->second->WriteFrame(*encoded_image_for_decode, + config_.codec_settings.codecType)); + } } if (!config_.encode_in_real_time) { diff --git a/modules/video_coding/codecs/test/videoprocessor.h b/modules/video_coding/codecs/test/videoprocessor.h index 4d31f2fe4d..aab636f343 100644 --- a/modules/video_coding/codecs/test/videoprocessor.h +++ b/modules/video_coding/codecs/test/videoprocessor.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "absl/memory/memory.h" @@ -53,7 +54,10 @@ namespace test { class VideoProcessor { public: using VideoDecoderList = std::vector>; - using IvfFileWriterList = std::vector>; + using LayerKey = std::pair; + using IvfFileWriterMap = std::map>; + // TODO(brandtr): Consider changing FrameWriterList to be a FrameWriterMap, + // to be able to save different TLs separately. using FrameWriterList = std::vector>; VideoProcessor(webrtc::VideoEncoder* encoder, @@ -61,7 +65,7 @@ class VideoProcessor { FrameReader* input_frame_reader, const VideoCodecTestFixture::Config& config, VideoCodecTestStats* stats, - IvfFileWriterList* encoded_frame_writers, + IvfFileWriterMap* encoded_frame_writers, FrameWriterList* decoded_frame_writers); ~VideoProcessor(); @@ -220,7 +224,7 @@ class VideoProcessor { // These (optional) file writers are used to persistently store the encoded // and decoded bitstreams. Each frame writer is enabled by being non-null. - IvfFileWriterList* const encoded_frame_writers_; + IvfFileWriterMap* const encoded_frame_writers_; FrameWriterList* const decoded_frame_writers_; // Metadata for inputed/encoded/decoded frames. Used for frame identification, diff --git a/modules/video_coding/codecs/test/videoprocessor_unittest.cc b/modules/video_coding/codecs/test/videoprocessor_unittest.cc index 4a9c3aab49..394ff238e1 100644 --- a/modules/video_coding/codecs/test/videoprocessor_unittest.cc +++ b/modules/video_coding/codecs/test/videoprocessor_unittest.cc @@ -54,8 +54,7 @@ class VideoProcessorTest : public testing::Test { q_.SendTask([this] { video_processor_ = absl::make_unique( &encoder_mock_, &decoders_, &frame_reader_mock_, config_, &stats_, - nullptr /* encoded_frame_writer */, - nullptr /* decoded_frame_writer */); + &encoded_frame_writers_, /*decoded_frame_writers=*/nullptr); }); } @@ -86,6 +85,7 @@ class VideoProcessorTest : public testing::Test { std::vector> decoders_; MockFrameReader frame_reader_mock_; VideoCodecTestStatsImpl stats_; + VideoProcessor::IvfFileWriterMap encoded_frame_writers_; std::unique_ptr video_processor_; };