Make Y4mFrameGenerator read FPS from file format.

Bug: b/269577953
Change-Id: Ied0072e1fdfbfb4d2b11e74a814c0718cad01d66
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/294862
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39401}
This commit is contained in:
Mirko Bonadei 2023-02-27 11:13:13 +01:00 committed by WebRTC LUCI CQ
parent 2a256c82ec
commit b5f2c7edda
8 changed files with 63 additions and 2 deletions

View file

@ -49,6 +49,12 @@ class FrameGeneratorInterface {
virtual void ChangeResolution(size_t width, size_t height) = 0;
virtual Resolution GetResolution() const = 0;
// Returns the frames per second this generator is supposed to provide
// according to its data source. Not all frame generators know the frames per
// second of the data source, in such case this method returns absl::nullopt.
// TODO(mbonadei): Make this pure virtual.
virtual absl::optional<int> fps() const { return absl::nullopt; }
};
} // namespace test

View file

@ -92,7 +92,10 @@ rtc_library("y4m_frame_generator") {
"../api/video:video_frame",
"../rtc_base:checks",
]
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
absl_deps = [
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
}
rtc_library("frame_utils") {

View file

@ -40,6 +40,8 @@ class SquareGenerator : public FrameGeneratorInterface {
VideoFrameData NextFrame() override;
Resolution GetResolution() const override;
absl::optional<int> fps() const override { return absl::nullopt; }
private:
rtc::scoped_refptr<I420Buffer> CreateI420Buffer(int width, int height);
@ -82,6 +84,8 @@ class YuvFileGenerator : public FrameGeneratorInterface {
}
Resolution GetResolution() const override;
absl::optional<int> fps() const override { return absl::nullopt; }
private:
// Returns true if the new frame was loaded.
// False only in case of a single file with a single frame in it.
@ -115,6 +119,8 @@ class NV12FileGenerator : public FrameGeneratorInterface {
}
Resolution GetResolution() const override;
absl::optional<int> fps() const override { return absl::nullopt; }
private:
// Returns true if the new frame was loaded.
// False only in case of a single file with a single frame in it.
@ -145,6 +151,8 @@ class SlideGenerator : public FrameGeneratorInterface {
}
Resolution GetResolution() const override;
absl::optional<int> fps() const override { return absl::nullopt; }
private:
// Generates some randomly sized and colored squares scattered
// over the frame.
@ -177,6 +185,8 @@ class ScrollingImageFrameGenerator : public FrameGeneratorInterface {
}
Resolution GetResolution() const override;
absl::optional<int> fps() const override { return absl::nullopt; }
private:
void UpdateSourceFrame(size_t frame_num);
void CropSourceToScrolledImage(double scroll_factor);

View file

@ -37,6 +37,8 @@ class IvfVideoFrameGenerator : public FrameGeneratorInterface {
void ChangeResolution(size_t width, size_t height) override;
Resolution GetResolution() const override;
absl::optional<int> fps() const override { return absl::nullopt; }
private:
class DecodedCallback : public DecodedImageCallback {
public:

View file

@ -164,6 +164,12 @@ class IvfVideoFrameGeneratorTest : public ::testing::Test {
} // namespace
TEST_F(IvfVideoFrameGeneratorTest, DoesNotKnowFps) {
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create());
IvfVideoFrameGenerator generator(file_name_);
EXPECT_EQ(generator.fps(), absl::nullopt);
}
TEST_F(IvfVideoFrameGeneratorTest, Vp8) {
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create());
IvfVideoFrameGenerator generator(file_name_);

View file

@ -41,7 +41,11 @@ Y4mFrameGenerator::Y4mFrameGenerator(absl::string_view filename,
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);
int fps_denominator;
RTC_CHECK_EQ(sscanf(header, "YUV4MPEG2 W%zu H%zu F%i:%i", &width_, &height_,
&fps_, &fps_denominator),
4);
fps_ /= fps_denominator;
RTC_CHECK_GT(width_, 0);
RTC_CHECK_GT(height_, 0);

View file

@ -16,6 +16,7 @@
#include <string>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/test/frame_generator_interface.h"
#include "rtc_base/checks.h"
#include "test/testsupport/frame_reader.h"
@ -50,6 +51,8 @@ class Y4mFrameGenerator : public FrameGeneratorInterface {
Resolution GetResolution() const override;
absl::optional<int> fps() const override { return fps_; }
private:
YuvFrameReaderImpl::RepeatMode ToYuvFrameReaderRepeatMode(
RepeatMode repeat_mode) const;
@ -57,6 +60,7 @@ class Y4mFrameGenerator : public FrameGeneratorInterface {
std::string filename_;
size_t width_;
size_t height_;
int fps_;
const RepeatMode repeat_mode_;
};

View file

@ -56,6 +56,32 @@ TEST_F(Y4mFrameGeneratorTest, CanReadResolutionFromFile) {
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, SingleRepeatMode) {
Y4mFrameGenerator generator(input_filepath_,
Y4mFrameGenerator::RepeatMode::kSingle);