Allow to specify a 'fps_hint' when creating a IvfVideoFrameGenerator.

Change-Id: Id75694f9dccfa6523f383e03dd90067fb6894b37
Bug: b/378855419
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/368162
Commit-Queue: Jeremy Leconte <jleconte@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43395}
This commit is contained in:
Jeremy Leconte 2024-11-13 15:39:42 +01:00 committed by WebRTC LUCI CQ
parent 4c171e84c3
commit 90da0650b5
5 changed files with 27 additions and 13 deletions

View File

@ -75,8 +75,9 @@ std::unique_ptr<FrameGeneratorInterface> CreateFromNV12FileFrameGenerator(
absl::Nonnull<std::unique_ptr<FrameGeneratorInterface>> absl::Nonnull<std::unique_ptr<FrameGeneratorInterface>>
CreateFromIvfFileFrameGenerator(const Environment& env, CreateFromIvfFileFrameGenerator(const Environment& env,
absl::string_view filename) { absl::string_view filename,
return std::make_unique<IvfVideoFrameGenerator>(env, filename); std::optional<int> fps_hint) {
return std::make_unique<IvfVideoFrameGenerator>(env, filename, fps_hint);
} }
std::unique_ptr<FrameGeneratorInterface> std::unique_ptr<FrameGeneratorInterface>

View File

@ -57,7 +57,8 @@ std::unique_ptr<FrameGeneratorInterface> CreateFromNV12FileFrameGenerator(
absl::Nonnull<std::unique_ptr<FrameGeneratorInterface>> absl::Nonnull<std::unique_ptr<FrameGeneratorInterface>>
CreateFromIvfFileFrameGenerator(const Environment& env, CreateFromIvfFileFrameGenerator(const Environment& env,
absl::string_view filename); absl::string_view filename,
std::optional<int> fps_hint = std::nullopt);
// Creates a frame generator which takes a set of yuv files (wrapping a // Creates a frame generator which takes a set of yuv files (wrapping a
// frame generator created by CreateFromYuvFile() above), but outputs frames // frame generator created by CreateFromYuvFile() above), but outputs frames

View File

@ -53,12 +53,14 @@ std::unique_ptr<VideoDecoder> CreateDecoder(const Environment& env,
} // namespace } // namespace
IvfVideoFrameGenerator::IvfVideoFrameGenerator(const Environment& env, IvfVideoFrameGenerator::IvfVideoFrameGenerator(const Environment& env,
absl::string_view file_name) absl::string_view file_name,
std::optional<int> fps_hint)
: callback_(this), : callback_(this),
file_reader_(IvfFileReader::Create(FileWrapper::OpenReadOnly(file_name))), file_reader_(IvfFileReader::Create(FileWrapper::OpenReadOnly(file_name))),
video_decoder_(CreateDecoder(env, file_reader_->GetVideoCodecType())), video_decoder_(CreateDecoder(env, file_reader_->GetVideoCodecType())),
width_(file_reader_->GetFrameWidth()), width_(file_reader_->GetFrameWidth()),
height_(file_reader_->GetFrameHeight()) { height_(file_reader_->GetFrameHeight()),
fps_hint_(fps_hint) {
RTC_CHECK(video_decoder_) << "No decoder found for file's video codec type"; RTC_CHECK(video_decoder_) << "No decoder found for file's video codec type";
VideoDecoder::Settings decoder_settings; VideoDecoder::Settings decoder_settings;
decoder_settings.set_codec_type(file_reader_->GetVideoCodecType()); decoder_settings.set_codec_type(file_reader_->GetVideoCodecType());

View File

@ -32,7 +32,10 @@ namespace test {
// All methods except constructor must be used from the same thread. // All methods except constructor must be used from the same thread.
class IvfVideoFrameGenerator : public FrameGeneratorInterface { class IvfVideoFrameGenerator : public FrameGeneratorInterface {
public: public:
IvfVideoFrameGenerator(const Environment& env, absl::string_view file_name); // Allow to specify a `fps_hint` in case the fps of the video is known.
IvfVideoFrameGenerator(const Environment& env,
absl::string_view file_name,
std::optional<int> fps_hint);
~IvfVideoFrameGenerator() override; ~IvfVideoFrameGenerator() override;
VideoFrameData NextFrame() override; VideoFrameData NextFrame() override;
@ -40,7 +43,7 @@ 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;
std::optional<int> fps() const override { return std::nullopt; } std::optional<int> fps() const override { return fps_hint_; }
private: private:
class DecodedCallback : public DecodedImageCallback { class DecodedCallback : public DecodedImageCallback {
@ -66,6 +69,7 @@ class IvfVideoFrameGenerator : public FrameGeneratorInterface {
size_t width_; size_t width_;
size_t height_; size_t height_;
std::optional<int> fps_hint_;
// This lock is used to ensure that all API method will be called // This lock is used to ensure that all API method will be called
// sequentially. It is required because we need to ensure that generator // sequentially. It is required because we need to ensure that generator

View File

@ -167,15 +167,21 @@ class IvfVideoFrameGeneratorTest : public ::testing::Test {
} // namespace } // namespace
TEST_F(IvfVideoFrameGeneratorTest, DoesNotKnowFps) { TEST_F(IvfVideoFrameGeneratorTest, FpsWithoutHint) {
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, CreateVp8Encoder(env_)); CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, CreateVp8Encoder(env_));
IvfVideoFrameGenerator generator(env_, file_name_); IvfVideoFrameGenerator generator(env_, file_name_, /*fps_hint=*/std::nullopt);
EXPECT_EQ(generator.fps(), std::nullopt); EXPECT_EQ(generator.fps(), std::nullopt);
} }
TEST_F(IvfVideoFrameGeneratorTest, FpsWithHint) {
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, CreateVp8Encoder(env_));
IvfVideoFrameGenerator generator(env_, file_name_, /*fps_hint=*/123);
EXPECT_EQ(generator.fps(), 123);
}
TEST_F(IvfVideoFrameGeneratorTest, Vp8) { TEST_F(IvfVideoFrameGeneratorTest, Vp8) {
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, CreateVp8Encoder(env_)); CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, CreateVp8Encoder(env_));
IvfVideoFrameGenerator generator(env_, file_name_); IvfVideoFrameGenerator generator(env_, file_name_, /*fps_hint=*/std::nullopt);
for (size_t i = 0; i < video_frames_.size(); ++i) { for (size_t i = 0; i < video_frames_.size(); ++i) {
auto& expected_frame = video_frames_[i]; auto& expected_frame = video_frames_[i];
VideoFrame actual_frame = BuildFrame(generator.NextFrame()); VideoFrame actual_frame = BuildFrame(generator.NextFrame());
@ -185,7 +191,7 @@ TEST_F(IvfVideoFrameGeneratorTest, Vp8) {
TEST_F(IvfVideoFrameGeneratorTest, Vp8DoubleRead) { TEST_F(IvfVideoFrameGeneratorTest, Vp8DoubleRead) {
CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, CreateVp8Encoder(env_)); CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, CreateVp8Encoder(env_));
IvfVideoFrameGenerator generator(env_, file_name_); IvfVideoFrameGenerator generator(env_, file_name_, /*fps_hint=*/std::nullopt);
for (size_t i = 0; i < video_frames_.size() * 2; ++i) { for (size_t i = 0; i < video_frames_.size() * 2; ++i) {
auto& expected_frame = video_frames_[i % video_frames_.size()]; auto& expected_frame = video_frames_[i % video_frames_.size()];
VideoFrame actual_frame = BuildFrame(generator.NextFrame()); VideoFrame actual_frame = BuildFrame(generator.NextFrame());
@ -195,7 +201,7 @@ TEST_F(IvfVideoFrameGeneratorTest, Vp8DoubleRead) {
TEST_F(IvfVideoFrameGeneratorTest, Vp9) { TEST_F(IvfVideoFrameGeneratorTest, Vp9) {
CreateTestVideoFile(VideoCodecType::kVideoCodecVP9, CreateVp9Encoder(env_)); CreateTestVideoFile(VideoCodecType::kVideoCodecVP9, CreateVp9Encoder(env_));
IvfVideoFrameGenerator generator(env_, file_name_); IvfVideoFrameGenerator generator(env_, file_name_, /*fps_hint=*/std::nullopt);
for (size_t i = 0; i < video_frames_.size(); ++i) { for (size_t i = 0; i < video_frames_.size(); ++i) {
auto& expected_frame = video_frames_[i]; auto& expected_frame = video_frames_[i];
VideoFrame actual_frame = BuildFrame(generator.NextFrame()); VideoFrame actual_frame = BuildFrame(generator.NextFrame());
@ -206,7 +212,7 @@ TEST_F(IvfVideoFrameGeneratorTest, Vp9) {
#if defined(WEBRTC_USE_H264) #if defined(WEBRTC_USE_H264)
TEST_F(IvfVideoFrameGeneratorTest, H264) { TEST_F(IvfVideoFrameGeneratorTest, H264) {
CreateTestVideoFile(VideoCodecType::kVideoCodecH264, CreateH264Encoder(env_)); CreateTestVideoFile(VideoCodecType::kVideoCodecH264, CreateH264Encoder(env_));
IvfVideoFrameGenerator generator(env_, file_name_); IvfVideoFrameGenerator generator(env_, file_name_, /*fps_hint=*/std::nullopt);
for (size_t i = 0; i < video_frames_.size(); ++i) { for (size_t i = 0; i < video_frames_.size(); ++i) {
auto& expected_frame = video_frames_[i]; auto& expected_frame = video_frames_[i];
VideoFrame actual_frame = BuildFrame(generator.NextFrame()); VideoFrame actual_frame = BuildFrame(generator.NextFrame());