Introduce Y4mFrameReader.
Bug: webrtc:10138 Change-Id: I213a4309a8a4b1a7afd296bf45566c9b3f9a215c Reviewed-on: https://webrtc-review.googlesource.com/c/117301 Commit-Queue: Artem Titov <titovartem@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26243}
This commit is contained in:
parent
a8c7326524
commit
645df9e3b5
@ -254,6 +254,7 @@ if (rtc_include_tests) {
|
||||
"testsupport/frame_reader.h",
|
||||
"testsupport/frame_writer.h",
|
||||
"testsupport/mock/mock_frame_reader.h",
|
||||
"testsupport/y4m_frame_reader.cc",
|
||||
"testsupport/y4m_frame_writer.cc",
|
||||
"testsupport/yuv_frame_reader.cc",
|
||||
"testsupport/yuv_frame_writer.cc",
|
||||
@ -352,6 +353,7 @@ if (rtc_include_tests) {
|
||||
"//testing/gmock",
|
||||
"//testing/gtest",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
]
|
||||
sources = [
|
||||
"direct_transport_unittest.cc",
|
||||
@ -363,6 +365,7 @@ if (rtc_include_tests) {
|
||||
"testsupport/always_passing_unittest.cc",
|
||||
"testsupport/perf_test_unittest.cc",
|
||||
"testsupport/test_artifacts_unittest.cc",
|
||||
"testsupport/y4m_frame_reader_unittest.cc",
|
||||
"testsupport/y4m_frame_writer_unittest.cc",
|
||||
"testsupport/yuv_frame_reader_unittest.cc",
|
||||
"testsupport/yuv_frame_writer_unittest.cc",
|
||||
|
||||
@ -59,8 +59,9 @@ class YuvFrameReaderImpl : public FrameReader {
|
||||
size_t FrameLength() override;
|
||||
int NumberOfFrames() override;
|
||||
|
||||
private:
|
||||
protected:
|
||||
const std::string input_filename_;
|
||||
// It is not const, so subclasses will be able to add frame header size.
|
||||
size_t frame_length_in_bytes_;
|
||||
const int width_;
|
||||
const int height_;
|
||||
@ -68,6 +69,22 @@ class YuvFrameReaderImpl : public FrameReader {
|
||||
FILE* input_file_;
|
||||
};
|
||||
|
||||
class Y4mFrameReaderImpl : public YuvFrameReaderImpl {
|
||||
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.
|
||||
Y4mFrameReaderImpl(std::string input_filename, int width, int height);
|
||||
~Y4mFrameReaderImpl() override;
|
||||
bool Init() override;
|
||||
rtc::scoped_refptr<I420Buffer> ReadFrame() override;
|
||||
|
||||
private:
|
||||
// Buffer that is used to read file and frame headers.
|
||||
uint8_t* buffer_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
85
test/testsupport/y4m_frame_reader.cc
Normal file
85
test/testsupport/y4m_frame_reader.cc
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "rtc_base/scoped_ref_ptr.h"
|
||||
#include "test/testsupport/file_utils.h"
|
||||
#include "test/testsupport/frame_reader.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
// Size of header: "YUV4MPEG2 W50 H20 F30:1 C420\n"
|
||||
const size_t kFileHeaderSize = 29;
|
||||
// Size of header: "FRAME\n"
|
||||
const size_t kFrameHeaderSize = 6;
|
||||
|
||||
} // namespace
|
||||
|
||||
Y4mFrameReaderImpl::Y4mFrameReaderImpl(std::string input_filename,
|
||||
int width,
|
||||
int height)
|
||||
: YuvFrameReaderImpl(input_filename, width, height) {
|
||||
frame_length_in_bytes_ += kFrameHeaderSize;
|
||||
buffer_ = new uint8_t[kFileHeaderSize];
|
||||
}
|
||||
Y4mFrameReaderImpl::~Y4mFrameReaderImpl() {
|
||||
delete[] buffer_;
|
||||
}
|
||||
|
||||
bool Y4mFrameReaderImpl::Init() {
|
||||
if (width_ <= 0 || height_ <= 0) {
|
||||
fprintf(stderr, "Frame width and height must be >0, was %d x %d\n", width_,
|
||||
height_);
|
||||
return false;
|
||||
}
|
||||
input_file_ = fopen(input_filename_.c_str(), "rb");
|
||||
if (input_file_ == nullptr) {
|
||||
fprintf(stderr, "Couldn't open input file for reading: %s\n",
|
||||
input_filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
size_t source_file_size = GetFileSize(input_filename_);
|
||||
if (source_file_size <= 0u) {
|
||||
fprintf(stderr, "Found empty file: %s\n", input_filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
if (fread(buffer_, 1, kFileHeaderSize, input_file_) < kFileHeaderSize) {
|
||||
fprintf(stderr, "Failed to read file header from input file: %s\n",
|
||||
input_filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
// Calculate total number of frames.
|
||||
number_of_frames_ = static_cast<int>((source_file_size - kFileHeaderSize) /
|
||||
frame_length_in_bytes_);
|
||||
return true;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<I420Buffer> Y4mFrameReaderImpl::ReadFrame() {
|
||||
if (input_file_ == nullptr) {
|
||||
fprintf(stderr,
|
||||
"Y4mFrameReaderImpl is not initialized (input file is NULL)\n");
|
||||
return nullptr;
|
||||
}
|
||||
if (fread(buffer_, 1, kFrameHeaderSize, input_file_) < kFrameHeaderSize &&
|
||||
ferror(input_file_)) {
|
||||
fprintf(stderr, "Failed to read frame header from input file: %s\n",
|
||||
input_filename_.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
return YuvFrameReaderImpl::ReadFrame();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
93
test/testsupport/y4m_frame_reader_unittest.cc
Normal file
93
test/testsupport/y4m_frame_reader_unittest.cc
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "api/video/video_frame_buffer.h"
|
||||
#include "rtc_base/scoped_ref_ptr.h"
|
||||
#include "test/gtest.h"
|
||||
#include "test/testsupport/file_utils.h"
|
||||
#include "test/testsupport/frame_reader.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
const absl::string_view kFileHeader = "YUV4MPEG2 W50 H20 F30:1 C420\n";
|
||||
const absl::string_view kFrameHeader = "FRAME\n";
|
||||
const absl::string_view kInputVideoContents = "abcdef";
|
||||
|
||||
const size_t kFrameWidth = 2;
|
||||
const size_t kFrameHeight = 2;
|
||||
const size_t kFrameLength = 3 * kFrameWidth * kFrameHeight / 2; // I420.
|
||||
|
||||
} // namespace
|
||||
|
||||
class Y4mFrameReaderTest : public testing::Test {
|
||||
protected:
|
||||
Y4mFrameReaderTest() = default;
|
||||
~Y4mFrameReaderTest() override = default;
|
||||
|
||||
void SetUp() override {
|
||||
temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(),
|
||||
"y4m_frame_reader_unittest");
|
||||
FILE* dummy = fopen(temp_filename_.c_str(), "wb");
|
||||
fprintf(dummy, "%s",
|
||||
(std::string(kFileHeader) + std::string(kFrameHeader) +
|
||||
std::string(kInputVideoContents))
|
||||
.c_str());
|
||||
fclose(dummy);
|
||||
|
||||
frame_reader_.reset(
|
||||
new Y4mFrameReaderImpl(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(Y4mFrameReaderTest, InitSuccess) {}
|
||||
|
||||
TEST_F(Y4mFrameReaderTest, FrameLength) {
|
||||
EXPECT_EQ(kFrameHeader.size() + kFrameLength, frame_reader_->FrameLength());
|
||||
}
|
||||
|
||||
TEST_F(Y4mFrameReaderTest, NumberOfFrames) {
|
||||
EXPECT_EQ(1, frame_reader_->NumberOfFrames());
|
||||
}
|
||||
|
||||
TEST_F(Y4mFrameReaderTest, ReadFrame) {
|
||||
rtc::scoped_refptr<I420BufferInterface> buffer = frame_reader_->ReadFrame();
|
||||
ASSERT_TRUE(buffer);
|
||||
// Expect I420 packed as YUV.
|
||||
EXPECT_EQ(kInputVideoContents[0], buffer->DataY()[0]);
|
||||
EXPECT_EQ(kInputVideoContents[1], buffer->DataY()[1]);
|
||||
EXPECT_EQ(kInputVideoContents[2], buffer->DataY()[2]);
|
||||
EXPECT_EQ(kInputVideoContents[3], buffer->DataY()[3]);
|
||||
EXPECT_EQ(kInputVideoContents[4], buffer->DataU()[0]);
|
||||
EXPECT_EQ(kInputVideoContents[5], buffer->DataV()[0]);
|
||||
EXPECT_FALSE(frame_reader_->ReadFrame()); // End of file.
|
||||
}
|
||||
|
||||
TEST_F(Y4mFrameReaderTest, ReadFrameUninitialized) {
|
||||
Y4mFrameReaderImpl file_reader(temp_filename_, kFrameWidth, kFrameHeight);
|
||||
EXPECT_FALSE(file_reader.ReadFrame());
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
@ -24,7 +24,8 @@ YuvFrameReaderImpl::YuvFrameReaderImpl(std::string input_filename,
|
||||
int width,
|
||||
int height)
|
||||
: input_filename_(input_filename),
|
||||
frame_length_in_bytes_(0),
|
||||
frame_length_in_bytes_(width * height +
|
||||
2 * ((width + 1) / 2) * ((height + 1) / 2)),
|
||||
width_(width),
|
||||
height_(height),
|
||||
number_of_frames_(-1),
|
||||
@ -40,9 +41,6 @@ bool YuvFrameReaderImpl::Init() {
|
||||
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_ == nullptr) {
|
||||
fprintf(stderr, "Couldn't open input file for reading: %s\n",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user