From 8dcaed97a94a28247d66e5a06cd82b95b6782b8a Mon Sep 17 00:00:00 2001 From: Artem Titov Date: Wed, 31 Jul 2019 14:19:00 +0200 Subject: [PATCH] Split VideoFrameWriter into yuv and y4m writers Bug: webrtc:10138 Change-Id: I5eae094a1a4b426281d291273f7feb9555497139 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147645 Reviewed-by: Karl Wiberg Commit-Queue: Artem Titov Cr-Commit-Position: refs/heads/master@{#28781} --- test/pc/e2e/peer_connection_quality_test.cc | 2 +- test/testsupport/video_frame_writer.cc | 93 ++++++++++++------- test/testsupport/video_frame_writer.h | 47 +++++++--- .../video_frame_writer_unittest.cc | 50 +++++++++- 4 files changed, 140 insertions(+), 52 deletions(-) diff --git a/test/pc/e2e/peer_connection_quality_test.cc b/test/pc/e2e/peer_connection_quality_test.cc index 20ad73b9db..f43ef3a9ae 100644 --- a/test/pc/e2e/peer_connection_quality_test.cc +++ b/test/pc/e2e/peer_connection_quality_test.cc @@ -956,7 +956,7 @@ test::VideoFrameWriter* PeerConnectionE2EQualityTest::MaybeCreateVideoWriter( return nullptr; } // TODO(titovartem) create only one file writer for simulcast video track. - auto video_writer = absl::make_unique( + auto video_writer = absl::make_unique( file_name.value(), config.width, config.height, config.fps); test::VideoFrameWriter* out = video_writer.get(); video_writers_.push_back(std::move(video_writer)); diff --git a/test/testsupport/video_frame_writer.cc b/test/testsupport/video_frame_writer.cc index 2e2964f078..311f74ad40 100644 --- a/test/testsupport/video_frame_writer.cc +++ b/test/testsupport/video_frame_writer.cc @@ -23,40 +23,11 @@ namespace webrtc { namespace test { +namespace { -VideoFrameWriter::VideoFrameWriter(std::string output_file_name, - int width, - int height, - int fps) - // We will move string here to prevent extra copy. We won't use const ref - // to not corrupt caller variable with move and don't assume that caller's - // variable won't be destructed before writer. - : output_file_name_(std::move(output_file_name)), - width_(width), - height_(height), - fps_(fps), - frame_writer_(absl::make_unique(output_file_name_, - width_, - height_, - fps_)) { - // Init underlying frame writer and ensure that it is operational. - RTC_CHECK(frame_writer_->Init()); -} -VideoFrameWriter::~VideoFrameWriter() = default; - -bool VideoFrameWriter::WriteFrame(const webrtc::VideoFrame& frame) { - rtc::Buffer frame_buffer = ExtractI420BufferWithSize(frame, width_, height_); - RTC_CHECK_EQ(frame_buffer.size(), frame_writer_->FrameLength()); - return frame_writer_->WriteFrame(frame_buffer.data()); -} - -void VideoFrameWriter::Close() { - frame_writer_->Close(); -} - -rtc::Buffer VideoFrameWriter::ExtractI420BufferWithSize(const VideoFrame& frame, - int width, - int height) { +rtc::Buffer ExtractI420BufferWithSize(const VideoFrame& frame, + int width, + int height) { if (frame.width() != width || frame.height() != height) { RTC_CHECK_LE(std::abs(static_cast(width) / height - static_cast(frame.width()) / frame.height()), @@ -80,5 +51,61 @@ rtc::Buffer VideoFrameWriter::ExtractI420BufferWithSize(const VideoFrame& frame, return buffer; } +} // namespace + +Y4mVideoFrameWriterImpl::Y4mVideoFrameWriterImpl(std::string output_file_name, + int width, + int height, + int fps) + // We will move string here to prevent extra copy. We won't use const ref + // to not corrupt caller variable with move and don't assume that caller's + // variable won't be destructed before writer. + : width_(width), + height_(height), + frame_writer_( + absl::make_unique(std::move(output_file_name), + width_, + height_, + fps)) { + // Init underlying frame writer and ensure that it is operational. + RTC_CHECK(frame_writer_->Init()); +} + +bool Y4mVideoFrameWriterImpl::WriteFrame(const webrtc::VideoFrame& frame) { + rtc::Buffer frame_buffer = ExtractI420BufferWithSize(frame, width_, height_); + RTC_CHECK_EQ(frame_buffer.size(), frame_writer_->FrameLength()); + return frame_writer_->WriteFrame(frame_buffer.data()); +} + +void Y4mVideoFrameWriterImpl::Close() { + frame_writer_->Close(); +} + +YuvVideoFrameWriterImpl::YuvVideoFrameWriterImpl(std::string output_file_name, + int width, + int height) + // We will move string here to prevent extra copy. We won't use const ref + // to not corrupt caller variable with move and don't assume that caller's + // variable won't be destructed before writer. + : width_(width), + height_(height), + frame_writer_( + absl::make_unique(std::move(output_file_name), + width_, + height_)) { + // Init underlying frame writer and ensure that it is operational. + RTC_CHECK(frame_writer_->Init()); +} + +bool YuvVideoFrameWriterImpl::WriteFrame(const webrtc::VideoFrame& frame) { + rtc::Buffer frame_buffer = ExtractI420BufferWithSize(frame, width_, height_); + RTC_CHECK_EQ(frame_buffer.size(), frame_writer_->FrameLength()); + return frame_writer_->WriteFrame(frame_buffer.data()); +} + +void YuvVideoFrameWriterImpl::Close() { + frame_writer_->Close(); +} + } // namespace test } // namespace webrtc diff --git a/test/testsupport/video_frame_writer.h b/test/testsupport/video_frame_writer.h index c96faf6d27..db1d453775 100644 --- a/test/testsupport/video_frame_writer.h +++ b/test/testsupport/video_frame_writer.h @@ -22,27 +22,46 @@ namespace webrtc { namespace test { -// Writes webrtc::VideoFrame to specified file with y4m frame writer class VideoFrameWriter { public: - VideoFrameWriter(std::string output_file_name, - int width, - int height, - int fps); - virtual ~VideoFrameWriter(); + virtual ~VideoFrameWriter() = default; - bool WriteFrame(const webrtc::VideoFrame& frame); - void Close(); + virtual bool WriteFrame(const webrtc::VideoFrame& frame) = 0; + + virtual void Close() = 0; +}; + +// Writes webrtc::VideoFrame to specified file with y4m frame writer +class Y4mVideoFrameWriterImpl : public VideoFrameWriter { + public: + Y4mVideoFrameWriterImpl(std::string output_file_name, + int width, + int height, + int fps); + ~Y4mVideoFrameWriterImpl() override = default; + + bool WriteFrame(const webrtc::VideoFrame& frame) override; + void Close() override; + + private: + const int width_; + const int height_; + + std::unique_ptr frame_writer_; +}; + +// Writes webrtc::VideoFrame to specified file with yuv frame writer +class YuvVideoFrameWriterImpl : public VideoFrameWriter { + public: + YuvVideoFrameWriterImpl(std::string output_file_name, int width, int height); + ~YuvVideoFrameWriterImpl() override = default; + + bool WriteFrame(const webrtc::VideoFrame& frame) override; + void Close() override; private: - rtc::Buffer ExtractI420BufferWithSize(const VideoFrame& frame, - int width, - int height); - - const std::string output_file_name_; const int width_; const int height_; - const int fps_; std::unique_ptr frame_writer_; }; diff --git a/test/testsupport/video_frame_writer_unittest.cc b/test/testsupport/video_frame_writer_unittest.cc index 67fe90393a..c712a6e108 100644 --- a/test/testsupport/video_frame_writer_unittest.cc +++ b/test/testsupport/video_frame_writer_unittest.cc @@ -96,19 +96,36 @@ class VideoFrameWriterTest : public ::testing::Test { void SetUp() override { temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), "video_frame_writer_unittest"); - frame_writer_ = absl::make_unique( - temp_filename_, kFrameWidth, kFrameHeight, kFrameRate); + frame_writer_ = CreateFrameWriter(); } + virtual std::unique_ptr CreateFrameWriter() = 0; + void TearDown() override { remove(temp_filename_.c_str()); } std::unique_ptr frame_writer_; std::string temp_filename_; }; -TEST_F(VideoFrameWriterTest, InitSuccess) {} +class Y4mVideoFrameWriterTest : public VideoFrameWriterTest { + protected: + std::unique_ptr CreateFrameWriter() override { + return absl::make_unique( + temp_filename_, kFrameWidth, kFrameHeight, kFrameRate); + } +}; -TEST_F(VideoFrameWriterTest, WriteFrame) { +class YuvVideoFrameWriterTest : public VideoFrameWriterTest { + protected: + std::unique_ptr CreateFrameWriter() override { + return absl::make_unique( + temp_filename_, kFrameWidth, kFrameHeight); + } +}; + +TEST_F(Y4mVideoFrameWriterTest, InitSuccess) {} + +TEST_F(Y4mVideoFrameWriterTest, WriteFrame) { rtc::scoped_refptr expected_buffer = CreateI420Buffer(kFrameWidth, kFrameHeight); @@ -132,5 +149,30 @@ TEST_F(VideoFrameWriterTest, WriteFrame) { frame_reader->Close(); } +TEST_F(YuvVideoFrameWriterTest, InitSuccess) {} + +TEST_F(YuvVideoFrameWriterTest, WriteFrame) { + rtc::scoped_refptr expected_buffer = + CreateI420Buffer(kFrameWidth, kFrameHeight); + + VideoFrame frame = + VideoFrame::Builder().set_video_frame_buffer(expected_buffer).build(); + + ASSERT_TRUE(frame_writer_->WriteFrame(frame)); + ASSERT_TRUE(frame_writer_->WriteFrame(frame)); + + frame_writer_->Close(); + EXPECT_EQ(2 * kFrameLength, GetFileSize(temp_filename_)); + + std::unique_ptr frame_reader = + absl::make_unique(temp_filename_, kFrameWidth, + kFrameHeight); + ASSERT_TRUE(frame_reader->Init()); + AssertI420BuffersEq(frame_reader->ReadFrame(), expected_buffer); + AssertI420BuffersEq(frame_reader->ReadFrame(), expected_buffer); + EXPECT_FALSE(frame_reader->ReadFrame()); // End of file. + frame_reader->Close(); +} + } // namespace test } // namespace webrtc