mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
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:
parent
2a256c82ec
commit
b5f2c7edda
8 changed files with 63 additions and 2 deletions
|
@ -49,6 +49,12 @@ class FrameGeneratorInterface {
|
||||||
virtual void ChangeResolution(size_t width, size_t height) = 0;
|
virtual void ChangeResolution(size_t width, size_t height) = 0;
|
||||||
|
|
||||||
virtual Resolution GetResolution() const = 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
|
} // namespace test
|
||||||
|
|
|
@ -92,7 +92,10 @@ rtc_library("y4m_frame_generator") {
|
||||||
"../api/video:video_frame",
|
"../api/video:video_frame",
|
||||||
"../rtc_base:checks",
|
"../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") {
|
rtc_library("frame_utils") {
|
||||||
|
|
|
@ -40,6 +40,8 @@ class SquareGenerator : public FrameGeneratorInterface {
|
||||||
VideoFrameData NextFrame() override;
|
VideoFrameData NextFrame() override;
|
||||||
Resolution GetResolution() const override;
|
Resolution GetResolution() const override;
|
||||||
|
|
||||||
|
absl::optional<int> fps() const override { return absl::nullopt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rtc::scoped_refptr<I420Buffer> CreateI420Buffer(int width, int height);
|
rtc::scoped_refptr<I420Buffer> CreateI420Buffer(int width, int height);
|
||||||
|
|
||||||
|
@ -82,6 +84,8 @@ class YuvFileGenerator : public FrameGeneratorInterface {
|
||||||
}
|
}
|
||||||
Resolution GetResolution() const override;
|
Resolution GetResolution() const override;
|
||||||
|
|
||||||
|
absl::optional<int> fps() const override { return absl::nullopt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Returns true if the new frame was loaded.
|
// Returns true if the new frame was loaded.
|
||||||
// False only in case of a single file with a single frame in it.
|
// 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;
|
Resolution GetResolution() const override;
|
||||||
|
|
||||||
|
absl::optional<int> fps() const override { return absl::nullopt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Returns true if the new frame was loaded.
|
// Returns true if the new frame was loaded.
|
||||||
// False only in case of a single file with a single frame in it.
|
// 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;
|
Resolution GetResolution() const override;
|
||||||
|
|
||||||
|
absl::optional<int> fps() const override { return absl::nullopt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Generates some randomly sized and colored squares scattered
|
// Generates some randomly sized and colored squares scattered
|
||||||
// over the frame.
|
// over the frame.
|
||||||
|
@ -177,6 +185,8 @@ class ScrollingImageFrameGenerator : public FrameGeneratorInterface {
|
||||||
}
|
}
|
||||||
Resolution GetResolution() const override;
|
Resolution GetResolution() const override;
|
||||||
|
|
||||||
|
absl::optional<int> fps() const override { return absl::nullopt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateSourceFrame(size_t frame_num);
|
void UpdateSourceFrame(size_t frame_num);
|
||||||
void CropSourceToScrolledImage(double scroll_factor);
|
void CropSourceToScrolledImage(double scroll_factor);
|
||||||
|
|
|
@ -37,6 +37,8 @@ class IvfVideoFrameGenerator : public FrameGeneratorInterface {
|
||||||
void ChangeResolution(size_t width, size_t height) override;
|
void ChangeResolution(size_t width, size_t height) override;
|
||||||
Resolution GetResolution() const override;
|
Resolution GetResolution() const override;
|
||||||
|
|
||||||
|
absl::optional<int> fps() const override { return absl::nullopt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class DecodedCallback : public DecodedImageCallback {
|
class DecodedCallback : public DecodedImageCallback {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -164,6 +164,12 @@ class IvfVideoFrameGeneratorTest : public ::testing::Test {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
TEST_F(IvfVideoFrameGeneratorTest, DoesNotKnowFps) {
|
||||||
|
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create());
|
||||||
|
IvfVideoFrameGenerator generator(file_name_);
|
||||||
|
EXPECT_EQ(generator.fps(), absl::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IvfVideoFrameGeneratorTest, Vp8) {
|
TEST_F(IvfVideoFrameGeneratorTest, Vp8) {
|
||||||
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create());
|
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create());
|
||||||
IvfVideoFrameGenerator generator(file_name_);
|
IvfVideoFrameGenerator generator(file_name_);
|
||||||
|
|
|
@ -41,7 +41,11 @@ Y4mFrameGenerator::Y4mFrameGenerator(absl::string_view filename,
|
||||||
RTC_CHECK(fgets(header, sizeof(header), file) != nullptr)
|
RTC_CHECK(fgets(header, sizeof(header), file) != nullptr)
|
||||||
<< "File " << filename_ << " is too small";
|
<< "File " << filename_ << " is too small";
|
||||||
fclose(file);
|
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(width_, 0);
|
||||||
RTC_CHECK_GT(height_, 0);
|
RTC_CHECK_GT(height_, 0);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
|
#include "absl/types/optional.h"
|
||||||
#include "api/test/frame_generator_interface.h"
|
#include "api/test/frame_generator_interface.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "test/testsupport/frame_reader.h"
|
#include "test/testsupport/frame_reader.h"
|
||||||
|
@ -50,6 +51,8 @@ class Y4mFrameGenerator : public FrameGeneratorInterface {
|
||||||
|
|
||||||
Resolution GetResolution() const override;
|
Resolution GetResolution() const override;
|
||||||
|
|
||||||
|
absl::optional<int> fps() const override { return fps_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
YuvFrameReaderImpl::RepeatMode ToYuvFrameReaderRepeatMode(
|
YuvFrameReaderImpl::RepeatMode ToYuvFrameReaderRepeatMode(
|
||||||
RepeatMode repeat_mode) const;
|
RepeatMode repeat_mode) const;
|
||||||
|
@ -57,6 +60,7 @@ class Y4mFrameGenerator : public FrameGeneratorInterface {
|
||||||
std::string filename_;
|
std::string filename_;
|
||||||
size_t width_;
|
size_t width_;
|
||||||
size_t height_;
|
size_t height_;
|
||||||
|
int fps_;
|
||||||
const RepeatMode repeat_mode_;
|
const RepeatMode repeat_mode_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,32 @@ TEST_F(Y4mFrameGeneratorTest, CanReadResolutionFromFile) {
|
||||||
EXPECT_EQ(res.height, 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, SingleRepeatMode) {
|
TEST_F(Y4mFrameGeneratorTest, SingleRepeatMode) {
|
||||||
Y4mFrameGenerator generator(input_filepath_,
|
Y4mFrameGenerator generator(input_filepath_,
|
||||||
Y4mFrameGenerator::RepeatMode::kSingle);
|
Y4mFrameGenerator::RepeatMode::kSingle);
|
||||||
|
|
Loading…
Reference in a new issue