This CL implements `ChangeResolution()` to let `Y4mFrameGenerator` generate I420 frame with resolution other than y4m input by scaling. The code is mostly copied from `IvfVideoFrameGenerator`. The test case is also added for this change. Bug: webrtc:15210 Change-Id: I690e427a545a72d93ed39b77fd0f602054a30508 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311521 Commit-Queue: Jianhui J Dai <jianhui.j.dai@intel.com> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40426}
150 lines
5.0 KiB
C++
150 lines
5.0 KiB
C++
/*
|
|
* 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, CanReadFPSFromFile) {
|
|
Y4mFrameGenerator generator(input_filepath_,
|
|
Y4mFrameGenerator::RepeatMode::kSingle);
|
|
EXPECT_EQ(*generator.fps(), 2);
|
|
}
|
|
|
|
TEST_F(Y4mFrameGeneratorTest, CanReadFPSFromFileWhenRoundingIsNeeded) {
|
|
std::string input_filepath = TempFilename(OutputPath(), "2x2_23_FPS.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 F24000:1001 C420\n"
|
|
"FRAME\n"
|
|
"123456FRAME\n"
|
|
"abcdefFRAME\n"
|
|
"987654";
|
|
std::fprintf(y4m_file, "%s", y4m_content.c_str());
|
|
fclose(y4m_file);
|
|
|
|
Y4mFrameGenerator generator(input_filepath,
|
|
Y4mFrameGenerator::RepeatMode::kSingle);
|
|
EXPECT_EQ(generator.fps(), 23);
|
|
remove(input_filepath.c_str());
|
|
}
|
|
|
|
TEST_F(Y4mFrameGeneratorTest, CanChangeResolution) {
|
|
constexpr int kNewWidth = 4;
|
|
constexpr int kNewHeight = 6;
|
|
constexpr int kFrameCount = 10;
|
|
|
|
Y4mFrameGenerator generator(input_filepath_,
|
|
Y4mFrameGenerator::RepeatMode::kLoop);
|
|
FrameGeneratorInterface::Resolution res = generator.GetResolution();
|
|
EXPECT_EQ(res.width, 2u);
|
|
EXPECT_EQ(res.height, 2u);
|
|
|
|
generator.ChangeResolution(kNewWidth, kNewHeight);
|
|
res = generator.GetResolution();
|
|
EXPECT_EQ(static_cast<int>(res.width), kNewWidth);
|
|
EXPECT_EQ(static_cast<int>(res.height), kNewHeight);
|
|
|
|
for (int i = 0; i < kFrameCount; ++i) {
|
|
FrameGeneratorInterface::VideoFrameData frame = generator.NextFrame();
|
|
EXPECT_EQ(frame.buffer->width(), kNewWidth);
|
|
EXPECT_EQ(frame.buffer->height(), kNewHeight);
|
|
}
|
|
}
|
|
|
|
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
|