Reland of Add optional visualization file writers to VideoProcessor tests. (patchset #1 id:1 of https://codereview.webrtc.org/2708103002/ ) Reason for revert: Necessary calls were "protected" by RTC_DCHECKs, that were optimized away in some release builds. Replacing the RTC_DCHECKs with EXPECTs. Original issue's description: > Revert of Add optional visualization file writers to VideoProcessor tests. (patchset #4 id:220001 of https://codereview.webrtc.org/2700493006/ ) > > Reason for revert: > Breaks downstream project. > > Original issue's description: > > Add optional visualization file writers to VideoProcessor tests. > > > > The purpose of this visualization CL is to add the ability to record > > video at the source, after encode, and after decode, in the VideoProcessor > > tests. These output files can then be replayed and used as a subjective > > complement to the objective metric plots given by the existing Python > > plotting script. > > > > BUG=webrtc:6634 > > > > Review-Url: https://codereview.webrtc.org/2700493006 > > Cr-Commit-Position: refs/heads/master@{#16738} > > Committed: https://chromium.googlesource.com/external/webrtc/+/872104ac41d7764f8676c9ea55555210bea4605c > > TBR=asapersson@webrtc.org,sprang@webrtc.org,kjellander@webrtc.org > # Skipping CQ checks because original CL landed less than 1 days ago. > NOPRESUBMIT=true > NOTREECHECKS=true > NOTRY=true > BUG=webrtc:6634 > > Review-Url: https://codereview.webrtc.org/2708103002 > Cr-Commit-Position: refs/heads/master@{#16745} > Committed: https://chromium.googlesource.com/external/webrtc/+/2a8135a1741761bd6de52163c0dc35f6eff7c8eb TBR=asapersson@webrtc.org,sprang@webrtc.org,kjellander@webrtc.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true BUG=webrtc:6634 Review-Url: https://codereview.webrtc.org/2706123003 Cr-Commit-Position: refs/heads/master@{#16769}
diff --git a/webrtc/test/BUILD.gn b/webrtc/test/BUILD.gn index a4c0185..07ffbee 100644 --- a/webrtc/test/BUILD.gn +++ b/webrtc/test/BUILD.gn
@@ -129,14 +129,15 @@ testonly = true sources = [ - "testsupport/frame_reader.cc", "testsupport/frame_reader.h", - "testsupport/frame_writer.cc", "testsupport/frame_writer.h", "testsupport/metrics/video_metrics.cc", "testsupport/metrics/video_metrics.h", "testsupport/mock/mock_frame_reader.h", "testsupport/mock/mock_frame_writer.h", + "testsupport/y4m_frame_writer.cc", + "testsupport/yuv_frame_reader.cc", + "testsupport/yuv_frame_writer.cc", ] deps = [ @@ -259,12 +260,13 @@ "rtp_file_reader_unittest.cc", "rtp_file_writer_unittest.cc", "testsupport/always_passing_unittest.cc", - "testsupport/frame_reader_unittest.cc", - "testsupport/frame_writer_unittest.cc", "testsupport/isolated_output_unittest.cc", "testsupport/metrics/video_metrics_unittest.cc", "testsupport/packet_reader_unittest.cc", "testsupport/perf_test_unittest.cc", + "testsupport/y4m_frame_writer_unittest.cc", + "testsupport/yuv_frame_reader_unittest.cc", + "testsupport/yuv_frame_writer_unittest.cc", ] # TODO(jschuh): Bug 1348: fix this warning.
diff --git a/webrtc/test/testsupport/frame_reader.h b/webrtc/test/testsupport/frame_reader.h index 13800cd..94dd78b 100644 --- a/webrtc/test/testsupport/frame_reader.h +++ b/webrtc/test/testsupport/frame_reader.h
@@ -46,14 +46,14 @@ virtual int NumberOfFrames() = 0; }; -class FrameReaderImpl : public FrameReader { +class YuvFrameReaderImpl : public FrameReader { public: // Creates a file handler. The input file is assumed to exist and be readable. // Parameters: // input_filename The file to read from. // width, height Size of each frame to read. - FrameReaderImpl(std::string input_filename, int width, int height); - ~FrameReaderImpl() override; + YuvFrameReaderImpl(std::string input_filename, int width, int height); + ~YuvFrameReaderImpl() override; bool Init() override; rtc::scoped_refptr<I420Buffer> ReadFrame() override; void Close() override; @@ -61,10 +61,10 @@ int NumberOfFrames() override; private: - std::string input_filename_; + const std::string input_filename_; size_t frame_length_in_bytes_; - int width_; - int height_; + const int width_; + const int height_; int number_of_frames_; FILE* input_file_; };
diff --git a/webrtc/test/testsupport/frame_reader_unittest.cc b/webrtc/test/testsupport/frame_reader_unittest.cc deleted file mode 100644 index 58a3245..0000000 --- a/webrtc/test/testsupport/frame_reader_unittest.cc +++ /dev/null
@@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011 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 "webrtc/test/testsupport/frame_reader.h" - -#include "webrtc/api/video/i420_buffer.h" -#include "webrtc/test/gtest.h" -#include "webrtc/test/testsupport/fileutils.h" - -namespace webrtc { -namespace test { - -const std::string kInputFileContents = "baz"; -const size_t kFrameLength = 3; - -class FrameReaderTest: public testing::Test { - protected: - FrameReaderTest() {} - virtual ~FrameReaderTest() {} - void SetUp() { - // Create a dummy input file. - temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), - "frame_reader_unittest"); - FILE* dummy = fopen(temp_filename_.c_str(), "wb"); - fprintf(dummy, "%s", kInputFileContents.c_str()); - fclose(dummy); - - frame_reader_ = new FrameReaderImpl(temp_filename_, 1, 1); - ASSERT_TRUE(frame_reader_->Init()); - } - void TearDown() { - delete frame_reader_; - // Cleanup the dummy input file. - remove(temp_filename_.c_str()); - } - FrameReader* frame_reader_; - std::string temp_filename_; -}; - -TEST_F(FrameReaderTest, InitSuccess) { - FrameReaderImpl frame_reader(temp_filename_, 1, 1); - ASSERT_TRUE(frame_reader.Init()); - ASSERT_EQ(kFrameLength, frame_reader.FrameLength()); - ASSERT_EQ(1, frame_reader.NumberOfFrames()); -} - -TEST_F(FrameReaderTest, ReadFrame) { - rtc::scoped_refptr<VideoFrameBuffer> buffer; - buffer = frame_reader_->ReadFrame(); - ASSERT_TRUE(buffer); - ASSERT_EQ(kInputFileContents[0], buffer->DataY()[0]); - ASSERT_EQ(kInputFileContents[1], buffer->DataU()[0]); - ASSERT_EQ(kInputFileContents[2], buffer->DataV()[0]); - ASSERT_FALSE(frame_reader_->ReadFrame()); // End of file -} - -TEST_F(FrameReaderTest, ReadFrameUninitialized) { - FrameReaderImpl file_reader(temp_filename_, 1, 1); - ASSERT_FALSE(file_reader.ReadFrame()); -} - -} // namespace test -} // namespace webrtc
diff --git a/webrtc/test/testsupport/frame_writer.cc b/webrtc/test/testsupport/frame_writer.cc deleted file mode 100644 index 1b9e8a8..0000000 --- a/webrtc/test/testsupport/frame_writer.cc +++ /dev/null
@@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011 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 "webrtc/test/testsupport/frame_writer.h" - -#include <assert.h> - -namespace webrtc { -namespace test { - -FrameWriterImpl::FrameWriterImpl(std::string output_filename, - size_t frame_length_in_bytes) - : output_filename_(output_filename), - frame_length_in_bytes_(frame_length_in_bytes), - output_file_(NULL) { -} - -FrameWriterImpl::~FrameWriterImpl() { - Close(); -} - -bool FrameWriterImpl::Init() { - if (frame_length_in_bytes_ <= 0) { - fprintf(stderr, "Frame length must be >0, was %zu\n", - frame_length_in_bytes_); - return false; - } - output_file_ = fopen(output_filename_.c_str(), "wb"); - if (output_file_ == NULL) { - fprintf(stderr, "Couldn't open output file for writing: %s\n", - output_filename_.c_str()); - return false; - } - return true; -} - -void FrameWriterImpl::Close() { - if (output_file_ != NULL) { - fclose(output_file_); - output_file_ = NULL; - } -} - -size_t FrameWriterImpl::FrameLength() { return frame_length_in_bytes_; } - -bool FrameWriterImpl::WriteFrame(uint8_t* frame_buffer) { - assert(frame_buffer); - if (output_file_ == NULL) { - fprintf(stderr, "FrameWriter is not initialized (output file is NULL)\n"); - return false; - } - size_t bytes_written = fwrite(frame_buffer, 1, frame_length_in_bytes_, - output_file_); - if (bytes_written != frame_length_in_bytes_) { - fprintf(stderr, "Failed to write %zu bytes to file %s\n", - frame_length_in_bytes_, output_filename_.c_str()); - return false; - } - return true; -} - -} // namespace test -} // namespace webrtc
diff --git a/webrtc/test/testsupport/frame_writer.h b/webrtc/test/testsupport/frame_writer.h index 8a6b1c2..7629849 100644 --- a/webrtc/test/testsupport/frame_writer.h +++ b/webrtc/test/testsupport/frame_writer.h
@@ -42,28 +42,46 @@ virtual size_t FrameLength() = 0; }; -class FrameWriterImpl : public FrameWriter { +// Writes raw I420 frames in sequence. +class YuvFrameWriterImpl : public FrameWriter { public: // Creates a file handler. The input file is assumed to exist and be readable // and the output file must be writable. // Parameters: // output_filename The file to write. Will be overwritten if already // existing. - // frame_length_in_bytes The size of each frame. - // For YUV: 3*width*height/2 - FrameWriterImpl(std::string output_filename, size_t frame_length_in_bytes); - ~FrameWriterImpl() override; + // width, height Size of each frame to read. + YuvFrameWriterImpl(std::string output_filename, int width, int height); + ~YuvFrameWriterImpl() override; bool Init() override; bool WriteFrame(uint8_t* frame_buffer) override; void Close() override; size_t FrameLength() override; - private: - std::string output_filename_; + protected: + const std::string output_filename_; size_t frame_length_in_bytes_; + const int width_; + const int height_; FILE* output_file_; }; +// Writes raw I420 frames in sequence, but with Y4M file and frame headers for +// more convenient playback in external media players. +class Y4mFrameWriterImpl : public YuvFrameWriterImpl { + public: + Y4mFrameWriterImpl(std::string output_filename, + int width, + int height, + int frame_rate); + ~Y4mFrameWriterImpl() override; + bool Init() override; + bool WriteFrame(uint8_t* frame_buffer) override; + + private: + const int frame_rate_; +}; + } // namespace test } // namespace webrtc
diff --git a/webrtc/test/testsupport/frame_writer_unittest.cc b/webrtc/test/testsupport/frame_writer_unittest.cc deleted file mode 100644 index 59173bd..0000000 --- a/webrtc/test/testsupport/frame_writer_unittest.cc +++ /dev/null
@@ -1,63 +0,0 @@ -/* - * Copyright (c) 2011 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 "webrtc/test/testsupport/frame_writer.h" - -#include "webrtc/test/gtest.h" -#include "webrtc/test/testsupport/fileutils.h" - -namespace webrtc { -namespace test { - -const size_t kFrameLength = 1000; - -class FrameWriterTest: public testing::Test { - protected: - FrameWriterTest() {} - virtual ~FrameWriterTest() {} - void SetUp() { - temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), - "frame_writer_unittest"); - frame_writer_ = new FrameWriterImpl(temp_filename_, kFrameLength); - ASSERT_TRUE(frame_writer_->Init()); - } - void TearDown() { - delete frame_writer_; - // Cleanup the temporary file. - remove(temp_filename_.c_str()); - } - FrameWriter* frame_writer_; - std::string temp_filename_; -}; - -TEST_F(FrameWriterTest, InitSuccess) { - FrameWriterImpl frame_writer(temp_filename_, kFrameLength); - ASSERT_TRUE(frame_writer.Init()); - ASSERT_EQ(kFrameLength, frame_writer.FrameLength()); -} - -TEST_F(FrameWriterTest, WriteFrame) { - uint8_t buffer[kFrameLength]; - memset(buffer, 9, kFrameLength); // Write lots of 9s to the buffer - bool result = frame_writer_->WriteFrame(buffer); - ASSERT_TRUE(result); // success - // Close the file and verify the size. - frame_writer_->Close(); - ASSERT_EQ(kFrameLength, GetFileSize(temp_filename_)); -} - -TEST_F(FrameWriterTest, WriteFrameUninitialized) { - uint8_t buffer[3]; - FrameWriterImpl frame_writer(temp_filename_, kFrameLength); - ASSERT_FALSE(frame_writer.WriteFrame(buffer)); -} - -} // namespace test -} // namespace webrtc
diff --git a/webrtc/test/testsupport/y4m_frame_writer.cc b/webrtc/test/testsupport/y4m_frame_writer.cc new file mode 100644 index 0000000..28fb4b0 --- /dev/null +++ b/webrtc/test/testsupport/y4m_frame_writer.cc
@@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 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 "webrtc/base/checks.h" +#include "webrtc/test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +Y4mFrameWriterImpl::Y4mFrameWriterImpl(std::string output_filename, + int width, + int height, + int frame_rate) + : YuvFrameWriterImpl(output_filename, width, height), + frame_rate_(frame_rate) {} + +Y4mFrameWriterImpl::~Y4mFrameWriterImpl() = default; + +bool Y4mFrameWriterImpl::Init() { + if (!YuvFrameWriterImpl::Init()) { + return false; + } + int bytes_written = fprintf(output_file_, "YUV4MPEG2 W%d H%d F%d:1 C420\n", + width_, height_, frame_rate_); + if (bytes_written < 0) { + fprintf(stderr, "Failed to write Y4M file header to file %s\n", + output_filename_.c_str()); + return false; + } + return true; +} + +bool Y4mFrameWriterImpl::WriteFrame(uint8_t* frame_buffer) { + if (output_file_ == nullptr) { + fprintf(stderr, + "Y4mFrameWriterImpl is not initialized (output file is NULL)\n"); + return false; + } + int bytes_written = fprintf(output_file_, "FRAME\n"); + if (bytes_written < 0) { + fprintf(stderr, "Failed to write Y4M frame header to file %s\n", + output_filename_.c_str()); + return false; + } + return YuvFrameWriterImpl::WriteFrame(frame_buffer); +} + +} // namespace test +} // namespace webrtc
diff --git a/webrtc/test/testsupport/y4m_frame_writer_unittest.cc b/webrtc/test/testsupport/y4m_frame_writer_unittest.cc new file mode 100644 index 0000000..a4e4172 --- /dev/null +++ b/webrtc/test/testsupport/y4m_frame_writer_unittest.cc
@@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 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 <memory> +#include <string> + +#include "webrtc/test/gtest.h" +#include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +namespace { +const size_t kFrameWidth = 50; +const size_t kFrameHeight = 20; +const size_t kFrameLength = 3 * kFrameWidth * kFrameHeight / 2; // I420. +const size_t kFrameRate = 30; + +const std::string kFileHeader = "YUV4MPEG2 W50 H20 F30:1 C420\n"; +const std::string kFrameHeader = "FRAME\n"; +} // namespace + +class Y4mFrameWriterTest : public testing::Test { + protected: + Y4mFrameWriterTest() = default; + ~Y4mFrameWriterTest() override = default; + + void SetUp() override { + temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), + "y4m_frame_writer_unittest"); + frame_writer_.reset(new Y4mFrameWriterImpl(temp_filename_, kFrameWidth, + kFrameHeight, kFrameRate)); + ASSERT_TRUE(frame_writer_->Init()); + } + + void TearDown() override { remove(temp_filename_.c_str()); } + + std::unique_ptr<FrameWriter> frame_writer_; + std::string temp_filename_; +}; + +TEST_F(Y4mFrameWriterTest, InitSuccess) {} + +TEST_F(Y4mFrameWriterTest, FrameLength) { + EXPECT_EQ(kFrameLength, frame_writer_->FrameLength()); +} + +TEST_F(Y4mFrameWriterTest, WriteFrame) { + uint8_t buffer[kFrameLength]; + memset(buffer, 9, kFrameLength); // Write lots of 9s to the buffer. + bool result = frame_writer_->WriteFrame(buffer); + ASSERT_TRUE(result); + result = frame_writer_->WriteFrame(buffer); + ASSERT_TRUE(result); + + frame_writer_->Close(); + EXPECT_EQ(kFileHeader.size() + 2 * kFrameHeader.size() + 2 * kFrameLength, + GetFileSize(temp_filename_)); +} + +TEST_F(Y4mFrameWriterTest, WriteFrameUninitialized) { + uint8_t buffer[kFrameLength]; + Y4mFrameWriterImpl frame_writer(temp_filename_, kFrameWidth, kFrameHeight, + kFrameRate); + EXPECT_FALSE(frame_writer.WriteFrame(buffer)); +} + +} // namespace test +} // namespace webrtc
diff --git a/webrtc/test/testsupport/frame_reader.cc b/webrtc/test/testsupport/yuv_frame_reader.cc similarity index 61% rename from webrtc/test/testsupport/frame_reader.cc rename to webrtc/test/testsupport/yuv_frame_reader.cc index 2593afd..3fe481e 100644 --- a/webrtc/test/testsupport/frame_reader.cc +++ b/webrtc/test/testsupport/yuv_frame_reader.cc
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2017 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 @@ -10,8 +10,6 @@ #include "webrtc/test/testsupport/frame_reader.h" -#include <assert.h> - #include "webrtc/api/video/i420_buffer.h" #include "webrtc/test/frame_utils.h" #include "webrtc/test/testsupport/fileutils.h" @@ -19,28 +17,31 @@ namespace webrtc { namespace test { -FrameReaderImpl::FrameReaderImpl(std::string input_filename, - int width, int height) +YuvFrameReaderImpl::YuvFrameReaderImpl(std::string input_filename, + int width, + int height) : input_filename_(input_filename), - width_(width), height_(height), - input_file_(NULL) { -} + frame_length_in_bytes_(0), + width_(width), + height_(height), + number_of_frames_(-1), + input_file_(nullptr) {} -FrameReaderImpl::~FrameReaderImpl() { +YuvFrameReaderImpl::~YuvFrameReaderImpl() { Close(); } -bool FrameReaderImpl::Init() { +bool YuvFrameReaderImpl::Init() { if (width_ <= 0 || height_ <= 0) { - fprintf(stderr, "Frame width and height must be >0, was %d x %d\n", - width_, height_); + fprintf(stderr, "Frame width and height must be >0, was %d x %d\n", width_, + height_); return false; } frame_length_in_bytes_ = width_ * height_ + 2 * ((width_ + 1) / 2) * ((height_ + 1) / 2); input_file_ = fopen(input_filename_.c_str(), "rb"); - if (input_file_ == NULL) { + if (input_file_ == nullptr) { fprintf(stderr, "Couldn't open input file for reading: %s\n", input_filename_.c_str()); return false; @@ -51,21 +52,15 @@ fprintf(stderr, "Found empty file: %s\n", input_filename_.c_str()); return false; } - number_of_frames_ = static_cast<int>(source_file_size / - frame_length_in_bytes_); + number_of_frames_ = + static_cast<int>(source_file_size / frame_length_in_bytes_); return true; } -void FrameReaderImpl::Close() { - if (input_file_ != NULL) { - fclose(input_file_); - input_file_ = NULL; - } -} - -rtc::scoped_refptr<I420Buffer> FrameReaderImpl::ReadFrame() { - if (input_file_ == NULL) { - fprintf(stderr, "FrameReader is not initialized (input file is NULL)\n"); +rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::ReadFrame() { + if (input_file_ == nullptr) { + fprintf(stderr, + "YuvFrameReaderImpl is not initialized (input file is NULL)\n"); return nullptr; } rtc::scoped_refptr<I420Buffer> buffer( @@ -77,8 +72,20 @@ return buffer; } -size_t FrameReaderImpl::FrameLength() { return frame_length_in_bytes_; } -int FrameReaderImpl::NumberOfFrames() { return number_of_frames_; } +void YuvFrameReaderImpl::Close() { + if (input_file_ != nullptr) { + fclose(input_file_); + input_file_ = nullptr; + } +} + +size_t YuvFrameReaderImpl::FrameLength() { + return frame_length_in_bytes_; +} + +int YuvFrameReaderImpl::NumberOfFrames() { + return number_of_frames_; +} } // namespace test } // namespace webrtc
diff --git a/webrtc/test/testsupport/yuv_frame_reader_unittest.cc b/webrtc/test/testsupport/yuv_frame_reader_unittest.cc new file mode 100644 index 0000000..9590814 --- /dev/null +++ b/webrtc/test/testsupport/yuv_frame_reader_unittest.cc
@@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017 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 <memory> +#include <string> + +#include "webrtc/api/video/i420_buffer.h" +#include "webrtc/test/gtest.h" +#include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/test/testsupport/frame_reader.h" + +namespace webrtc { +namespace test { + +namespace { +const std::string kInputFileContents = "bazouk"; + +const size_t kFrameWidth = 2; +const size_t kFrameHeight = 2; +const size_t kFrameLength = 3 * kFrameWidth * kFrameHeight / 2; // I420. +} // namespace + +class YuvFrameReaderTest : public testing::Test { + protected: + YuvFrameReaderTest() = default; + ~YuvFrameReaderTest() override = default; + + void SetUp() override { + temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), + "yuv_frame_reader_unittest"); + FILE* dummy = fopen(temp_filename_.c_str(), "wb"); + fprintf(dummy, "%s", kInputFileContents.c_str()); + fclose(dummy); + + frame_reader_.reset( + new YuvFrameReaderImpl(temp_filename_, kFrameWidth, kFrameHeight)); + ASSERT_TRUE(frame_reader_->Init()); + } + + void TearDown() override { remove(temp_filename_.c_str()); } + + std::unique_ptr<FrameReader> frame_reader_; + std::string temp_filename_; +}; + +TEST_F(YuvFrameReaderTest, InitSuccess) {} + +TEST_F(YuvFrameReaderTest, FrameLength) { + EXPECT_EQ(kFrameLength, frame_reader_->FrameLength()); +} + +TEST_F(YuvFrameReaderTest, NumberOfFrames) { + EXPECT_EQ(1, frame_reader_->NumberOfFrames()); +} + +TEST_F(YuvFrameReaderTest, ReadFrame) { + rtc::scoped_refptr<VideoFrameBuffer> buffer; + buffer = frame_reader_->ReadFrame(); + ASSERT_TRUE(buffer); + // Expect I420 packed as YUV. + EXPECT_EQ(kInputFileContents[0], buffer->DataY()[0]); + EXPECT_EQ(kInputFileContents[1], buffer->DataY()[1]); + EXPECT_EQ(kInputFileContents[2], buffer->DataY()[2]); + EXPECT_EQ(kInputFileContents[3], buffer->DataY()[3]); + EXPECT_EQ(kInputFileContents[4], buffer->DataU()[0]); + EXPECT_EQ(kInputFileContents[5], buffer->DataV()[0]); + EXPECT_FALSE(frame_reader_->ReadFrame()); // End of file. +} + +TEST_F(YuvFrameReaderTest, ReadFrameUninitialized) { + YuvFrameReaderImpl file_reader(temp_filename_, kFrameWidth, kFrameHeight); + EXPECT_FALSE(file_reader.ReadFrame()); +} + +} // namespace test +} // namespace webrtc
diff --git a/webrtc/test/testsupport/yuv_frame_writer.cc b/webrtc/test/testsupport/yuv_frame_writer.cc new file mode 100644 index 0000000..3c00761 --- /dev/null +++ b/webrtc/test/testsupport/yuv_frame_writer.cc
@@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 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 "webrtc/base/checks.h" +#include "webrtc/test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +YuvFrameWriterImpl::YuvFrameWriterImpl(std::string output_filename, + int width, + int height) + : output_filename_(output_filename), + frame_length_in_bytes_(0), + width_(width), + height_(height), + output_file_(nullptr) {} + +YuvFrameWriterImpl::~YuvFrameWriterImpl() { + Close(); +} + +bool YuvFrameWriterImpl::Init() { + if (width_ <= 0 || height_ <= 0) { + fprintf(stderr, "Frame width and height must be >0, was %d x %d\n", width_, + height_); + return false; + } + frame_length_in_bytes_ = + width_ * height_ + 2 * ((width_ + 1) / 2) * ((height_ + 1) / 2); + + output_file_ = fopen(output_filename_.c_str(), "wb"); + if (output_file_ == nullptr) { + fprintf(stderr, "Couldn't open output file for writing: %s\n", + output_filename_.c_str()); + return false; + } + return true; +} + +bool YuvFrameWriterImpl::WriteFrame(uint8_t* frame_buffer) { + RTC_DCHECK(frame_buffer); + if (output_file_ == nullptr) { + fprintf(stderr, + "YuvFrameWriterImpl is not initialized (output file is NULL)\n"); + return false; + } + size_t bytes_written = + fwrite(frame_buffer, 1, frame_length_in_bytes_, output_file_); + if (bytes_written != frame_length_in_bytes_) { + fprintf(stderr, "Failed to write %zu bytes to file %s\n", + frame_length_in_bytes_, output_filename_.c_str()); + return false; + } + return true; +} + +void YuvFrameWriterImpl::Close() { + if (output_file_ != nullptr) { + fclose(output_file_); + output_file_ = nullptr; + } +} + +size_t YuvFrameWriterImpl::FrameLength() { + return frame_length_in_bytes_; +} + +} // namespace test +} // namespace webrtc
diff --git a/webrtc/test/testsupport/yuv_frame_writer_unittest.cc b/webrtc/test/testsupport/yuv_frame_writer_unittest.cc new file mode 100644 index 0000000..5e3cc5c --- /dev/null +++ b/webrtc/test/testsupport/yuv_frame_writer_unittest.cc
@@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 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 <memory> + +#include "webrtc/test/gtest.h" +#include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +namespace { +const size_t kFrameWidth = 50; +const size_t kFrameHeight = 20; +const size_t kFrameLength = 3 * kFrameWidth * kFrameHeight / 2; // I420. +} // namespace + +class YuvFrameWriterTest : public testing::Test { + protected: + YuvFrameWriterTest() = default; + ~YuvFrameWriterTest() override = default; + + void SetUp() override { + temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), + "yuv_frame_writer_unittest"); + frame_writer_.reset( + new YuvFrameWriterImpl(temp_filename_, kFrameWidth, kFrameHeight)); + ASSERT_TRUE(frame_writer_->Init()); + } + + void TearDown() override { remove(temp_filename_.c_str()); } + + std::unique_ptr<FrameWriter> frame_writer_; + std::string temp_filename_; +}; + +TEST_F(YuvFrameWriterTest, InitSuccess) {} + +TEST_F(YuvFrameWriterTest, FrameLength) { + EXPECT_EQ(kFrameLength, frame_writer_->FrameLength()); +} + +TEST_F(YuvFrameWriterTest, WriteFrame) { + uint8_t buffer[kFrameLength]; + memset(buffer, 9, kFrameLength); // Write lots of 9s to the buffer. + bool result = frame_writer_->WriteFrame(buffer); + ASSERT_TRUE(result); + + frame_writer_->Close(); + EXPECT_EQ(kFrameLength, GetFileSize(temp_filename_)); +} + +TEST_F(YuvFrameWriterTest, WriteFrameUninitialized) { + uint8_t buffer[kFrameLength]; + YuvFrameWriterImpl frame_writer(temp_filename_, kFrameWidth, kFrameHeight); + EXPECT_FALSE(frame_writer.WriteFrame(buffer)); +} + +} // namespace test +} // namespace webrtc