Introduce Y4mFrameGenerator.
Bug: b/269577953 Change-Id: Id28a395235cc88cb5422dd9754483fbac3e50807 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/294100 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Artem Titov <titovartem@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39344}
This commit is contained in:
parent
8ad4924936
commit
b337c40e58
@ -78,6 +78,23 @@ rtc_library("frame_generator_impl") {
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
||||
rtc_library("y4m_frame_generator") {
|
||||
visibility = [ "*" ]
|
||||
testonly = true
|
||||
sources = [
|
||||
"testsupport/y4m_frame_generator.cc",
|
||||
"testsupport/y4m_frame_generator.h",
|
||||
]
|
||||
deps = [
|
||||
":video_test_support",
|
||||
"../api:frame_generator_api",
|
||||
"../api:scoped_refptr",
|
||||
"../api/video:video_frame",
|
||||
"../rtc_base:checks",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
|
||||
}
|
||||
|
||||
rtc_library("frame_utils") {
|
||||
visibility = [ "*" ]
|
||||
testonly = true
|
||||
@ -632,6 +649,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
||||
":test_support_test_artifacts",
|
||||
":video_test_common",
|
||||
":video_test_support",
|
||||
":y4m_frame_generator",
|
||||
"../api:array_view",
|
||||
"../api:create_frame_generator",
|
||||
"../api:create_simulcast_test_fixture_api",
|
||||
@ -687,6 +705,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
||||
"testsupport/perf_test_unittest.cc",
|
||||
"testsupport/test_artifacts_unittest.cc",
|
||||
"testsupport/video_frame_writer_unittest.cc",
|
||||
"testsupport/y4m_frame_generator_test.cc",
|
||||
"testsupport/y4m_frame_reader_unittest.cc",
|
||||
"testsupport/y4m_frame_writer_unittest.cc",
|
||||
"testsupport/yuv_frame_reader_unittest.cc",
|
||||
|
||||
78
test/testsupport/y4m_frame_generator.cc
Normal file
78
test/testsupport/y4m_frame_generator.cc
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "test/testsupport/y4m_frame_generator.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "test/testsupport/frame_reader.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
// Reading 30 bytes from the Y4M header should be enough to get width
|
||||
// and heigth.
|
||||
// The header starts with: `YUV4MPEG2 W<WIDTH> H<HEIGTH>`.
|
||||
constexpr int kHeaderBytesToRead = 30;
|
||||
} // namespace
|
||||
|
||||
Y4mFrameGenerator::Y4mFrameGenerator(absl::string_view filename,
|
||||
RepeatMode repeat_mode)
|
||||
: filename_(filename), repeat_mode_(repeat_mode) {
|
||||
// Read resolution from the Y4M header.
|
||||
FILE* file = fopen(filename_.c_str(), "r");
|
||||
RTC_CHECK(file != NULL) << "Cannot open " << filename_;
|
||||
char header[kHeaderBytesToRead];
|
||||
RTC_CHECK(fgets(header, sizeof(header), file) != nullptr)
|
||||
<< "File " << filename_ << " is too small";
|
||||
fclose(file);
|
||||
RTC_CHECK_EQ(sscanf(header, "YUV4MPEG2 W%zu H%zu", &width_, &height_), 2);
|
||||
RTC_CHECK_GT(width_, 0);
|
||||
RTC_CHECK_GT(height_, 0);
|
||||
|
||||
// Delegate the actual reads (from NextFrame) to a Y4mReader.
|
||||
frame_reader_ = webrtc::test::CreateY4mFrameReader(
|
||||
filename_, ToYuvFrameReaderRepeatMode(repeat_mode_));
|
||||
}
|
||||
|
||||
Y4mFrameGenerator::VideoFrameData Y4mFrameGenerator::NextFrame() {
|
||||
webrtc::VideoFrame::UpdateRect update_rect{0, 0, static_cast<int>(width_),
|
||||
static_cast<int>(height_)};
|
||||
rtc::scoped_refptr<webrtc::I420Buffer> next_frame_buffer =
|
||||
frame_reader_->PullFrame();
|
||||
return VideoFrameData(next_frame_buffer, update_rect);
|
||||
}
|
||||
|
||||
FrameGeneratorInterface::Resolution Y4mFrameGenerator::GetResolution() const {
|
||||
return {.width = width_, .height = height_};
|
||||
}
|
||||
|
||||
YuvFrameReaderImpl::RepeatMode Y4mFrameGenerator::ToYuvFrameReaderRepeatMode(
|
||||
RepeatMode repeat_mode) const {
|
||||
switch (repeat_mode) {
|
||||
case RepeatMode::kSingle:
|
||||
return YuvFrameReaderImpl::RepeatMode::kSingle;
|
||||
case RepeatMode::kLoop:
|
||||
return YuvFrameReaderImpl::RepeatMode::kRepeat;
|
||||
case RepeatMode::kPingPong:
|
||||
return YuvFrameReaderImpl::RepeatMode::kPingPong;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
66
test/testsupport/y4m_frame_generator.h
Normal file
66
test/testsupport/y4m_frame_generator.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef TEST_TESTSUPPORT_Y4M_FRAME_GENERATOR_H_
|
||||
#define TEST_TESTSUPPORT_Y4M_FRAME_GENERATOR_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/test/frame_generator_interface.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "test/testsupport/frame_reader.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
// Generates frames from a Y4M file. The behaviour when reaching EOF is
|
||||
// configurable via RepeatMode.
|
||||
class Y4mFrameGenerator : public FrameGeneratorInterface {
|
||||
public:
|
||||
enum class RepeatMode {
|
||||
// Generate frames from the input file, but it stops generating new frames
|
||||
// once EOF is reached.
|
||||
kSingle,
|
||||
// Generate frames from the input file, when EOF is reached it starts from
|
||||
// the beginning.
|
||||
kLoop,
|
||||
// Generate frames from the input file, when EOF is reached it plays frames
|
||||
// backwards from the end to the beginning of the file (and vice versa,
|
||||
// literally doing Ping/Pong between the beginning and the end of the file).
|
||||
kPingPong,
|
||||
};
|
||||
Y4mFrameGenerator(absl::string_view filename, RepeatMode repeat_mode);
|
||||
~Y4mFrameGenerator() override = default;
|
||||
|
||||
VideoFrameData NextFrame() override;
|
||||
|
||||
void ChangeResolution(size_t width, size_t height) override {
|
||||
RTC_CHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
Resolution GetResolution() const override;
|
||||
|
||||
private:
|
||||
YuvFrameReaderImpl::RepeatMode ToYuvFrameReaderRepeatMode(
|
||||
RepeatMode repeat_mode) const;
|
||||
std::unique_ptr<webrtc::test::FrameReader> frame_reader_ = nullptr;
|
||||
std::string filename_;
|
||||
size_t width_;
|
||||
size_t height_;
|
||||
const RepeatMode repeat_mode_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_TESTSUPPORT_Y4M_FRAME_GENERATOR_H_
|
||||
100
test/testsupport/y4m_frame_generator_test.cc
Normal file
100
test/testsupport/y4m_frame_generator_test.cc
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "test/testsupport/y4m_frame_generator.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "test/gtest.h"
|
||||
#include "test/testsupport/file_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
class Y4mFrameGeneratorTest : public testing::Test {
|
||||
protected:
|
||||
Y4mFrameGeneratorTest() = default;
|
||||
~Y4mFrameGeneratorTest() = default;
|
||||
|
||||
void SetUp() {
|
||||
input_filepath_ = TempFilename(OutputPath(), "2x2.y4m");
|
||||
FILE* y4m_file = fopen(input_filepath_.c_str(), "wb");
|
||||
|
||||
// Input Y4M file: 3 YUV frames of 2x2 resolution.
|
||||
std::string y4m_content =
|
||||
"YUV4MPEG2 W2 H2 F2:1 C420\n"
|
||||
"FRAME\n"
|
||||
"123456FRAME\n"
|
||||
"abcdefFRAME\n"
|
||||
"987654";
|
||||
std::fprintf(y4m_file, "%s", y4m_content.c_str());
|
||||
fclose(y4m_file);
|
||||
}
|
||||
|
||||
void TearDown() { remove(input_filepath_.c_str()); }
|
||||
|
||||
std::string input_filepath_;
|
||||
};
|
||||
|
||||
TEST_F(Y4mFrameGeneratorTest, CanReadResolutionFromFile) {
|
||||
Y4mFrameGenerator generator(input_filepath_,
|
||||
Y4mFrameGenerator::RepeatMode::kSingle);
|
||||
FrameGeneratorInterface::Resolution res = generator.GetResolution();
|
||||
EXPECT_EQ(res.width, 2u);
|
||||
EXPECT_EQ(res.height, 2u);
|
||||
}
|
||||
|
||||
TEST_F(Y4mFrameGeneratorTest, SingleRepeatMode) {
|
||||
Y4mFrameGenerator generator(input_filepath_,
|
||||
Y4mFrameGenerator::RepeatMode::kSingle);
|
||||
|
||||
std::vector<std::string> expected_frame_ys = {"123456", "abcdef", "987654"};
|
||||
for (absl::string_view frame_y : expected_frame_ys) {
|
||||
EXPECT_EQ(frame_y.size(), 6u);
|
||||
FrameGeneratorInterface::VideoFrameData frame = generator.NextFrame();
|
||||
EXPECT_EQ(memcmp(frame_y.data(), frame.buffer->GetI420()->DataY(), 6), 0);
|
||||
}
|
||||
FrameGeneratorInterface::VideoFrameData frame = generator.NextFrame();
|
||||
EXPECT_EQ(frame.buffer, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(Y4mFrameGeneratorTest, LoopRepeatMode) {
|
||||
Y4mFrameGenerator generator(input_filepath_,
|
||||
Y4mFrameGenerator::RepeatMode::kLoop);
|
||||
|
||||
std::vector<std::string> expected_frame_ys = {"123456", "abcdef", "987654",
|
||||
"123456", "abcdef", "987654"};
|
||||
for (absl::string_view frame_y : expected_frame_ys) {
|
||||
EXPECT_EQ(frame_y.size(), 6u);
|
||||
FrameGeneratorInterface::VideoFrameData frame = generator.NextFrame();
|
||||
EXPECT_EQ(memcmp(frame_y.data(), frame.buffer->GetI420()->DataY(), 6), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Y4mFrameGeneratorTest, PingPongRepeatMode) {
|
||||
Y4mFrameGenerator generator(input_filepath_,
|
||||
Y4mFrameGenerator::RepeatMode::kPingPong);
|
||||
|
||||
std::vector<std::string> expected_frame_ys = {
|
||||
"123456", "abcdef", "987654", "abcdef", "123456", "abcdef", "987654"};
|
||||
for (absl::string_view frame_y : expected_frame_ys) {
|
||||
EXPECT_EQ(frame_y.size(), 6u);
|
||||
FrameGeneratorInterface::VideoFrameData frame = generator.NextFrame();
|
||||
EXPECT_EQ(memcmp(frame_y.data(), frame.buffer->GetI420()->DataY(), 6), 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
Loading…
x
Reference in New Issue
Block a user