|  | /* | 
|  | *  Copyright (c) 2018 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 <stdio.h> | 
|  |  | 
|  | #include <cstdio> | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <tuple> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "api/scoped_refptr.h" | 
|  | #include "api/video/resolution.h" | 
|  | #include "api/video/video_frame_buffer.h" | 
|  | #include "test/gtest.h" | 
|  | #include "test/testsupport/file_utils.h" | 
|  | #include "test/testsupport/frame_reader.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace test { | 
|  | namespace { | 
|  | using Ratio = FrameReader::Ratio; | 
|  | using RepeatMode = YuvFrameReaderImpl::RepeatMode; | 
|  |  | 
|  | constexpr Resolution kResolution({.width = 1, .height = 1}); | 
|  | constexpr char kFileHeader[] = "YUV4MPEG2 W1 H1 F30:1 C420\n"; | 
|  | constexpr char kFrameHeader[] = "FRAME\n"; | 
|  | constexpr char kFrameContent[3][3] = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; | 
|  | constexpr int kNumFrames = sizeof(kFrameContent) / sizeof(kFrameContent[0]); | 
|  | }  // namespace | 
|  |  | 
|  | class Y4mFrameReaderTest : public ::testing::Test { | 
|  | protected: | 
|  | Y4mFrameReaderTest() = default; | 
|  | ~Y4mFrameReaderTest() override = default; | 
|  |  | 
|  | void SetUp() override { | 
|  | filepath_ = | 
|  | test::TempFilename(test::OutputPath(), "y4m_frame_reader_unittest"); | 
|  | FILE* file = fopen(filepath_.c_str(), "wb"); | 
|  | fwrite(kFileHeader, 1, sizeof(kFileHeader) - 1, file); | 
|  | for (int n = 0; n < kNumFrames; ++n) { | 
|  | fwrite(kFrameHeader, 1, sizeof(kFrameHeader) - 1, file); | 
|  | fwrite(kFrameContent[n], 1, sizeof(kFrameContent[n]), file); | 
|  | } | 
|  | fclose(file); | 
|  |  | 
|  | reader_ = CreateY4mFrameReader(filepath_); | 
|  | } | 
|  |  | 
|  | void TearDown() override { remove(filepath_.c_str()); } | 
|  |  | 
|  | std::string filepath_; | 
|  | std::unique_ptr<FrameReader> reader_; | 
|  | }; | 
|  |  | 
|  | TEST_F(Y4mFrameReaderTest, num_frames) { | 
|  | EXPECT_EQ(kNumFrames, reader_->num_frames()); | 
|  | } | 
|  |  | 
|  | TEST_F(Y4mFrameReaderTest, PullFrame_frameResolution) { | 
|  | scoped_refptr<I420BufferInterface> buffer = reader_->PullFrame(); | 
|  | EXPECT_EQ(kResolution.width, buffer->width()); | 
|  | EXPECT_EQ(kResolution.height, buffer->height()); | 
|  | } | 
|  |  | 
|  | TEST_F(Y4mFrameReaderTest, PullFrame_frameContent) { | 
|  | scoped_refptr<I420BufferInterface> buffer = reader_->PullFrame(); | 
|  | EXPECT_EQ(kFrameContent[0][0], *buffer->DataY()); | 
|  | EXPECT_EQ(kFrameContent[0][1], *buffer->DataU()); | 
|  | EXPECT_EQ(kFrameContent[0][2], *buffer->DataV()); | 
|  | } | 
|  |  | 
|  | TEST_F(Y4mFrameReaderTest, ReadFrame_randomOrder) { | 
|  | std::vector<int> expected_frames = {2, 0, 1}; | 
|  | std::vector<int> actual_frames; | 
|  | for (int frame_num : expected_frames) { | 
|  | scoped_refptr<I420BufferInterface> buffer = reader_->ReadFrame(frame_num); | 
|  | actual_frames.push_back(*buffer->DataY()); | 
|  | } | 
|  | EXPECT_EQ(expected_frames, actual_frames); | 
|  | } | 
|  |  | 
|  | TEST_F(Y4mFrameReaderTest, PullFrame_scale) { | 
|  | scoped_refptr<I420BufferInterface> buffer = reader_->PullFrame( | 
|  | /*pulled_frame_num=*/nullptr, Resolution({.width = 2, .height = 2}), | 
|  | FrameReader::kNoScale); | 
|  | EXPECT_EQ(2, buffer->width()); | 
|  | EXPECT_EQ(2, buffer->height()); | 
|  | } | 
|  |  | 
|  | class Y4mFrameReaderRepeatModeTest | 
|  | : public Y4mFrameReaderTest, | 
|  | public ::testing::WithParamInterface< | 
|  | std::tuple<RepeatMode, std::vector<int>>> {}; | 
|  |  | 
|  | TEST_P(Y4mFrameReaderRepeatModeTest, PullFrame) { | 
|  | RepeatMode mode = std::get<0>(GetParam()); | 
|  | std::vector<int> expected_frames = std::get<1>(GetParam()); | 
|  |  | 
|  | reader_ = CreateY4mFrameReader(filepath_, mode); | 
|  | std::vector<int> read_frames; | 
|  | for (size_t i = 0; i < expected_frames.size(); ++i) { | 
|  | scoped_refptr<I420BufferInterface> buffer = reader_->PullFrame(); | 
|  | read_frames.push_back(*buffer->DataY()); | 
|  | } | 
|  | EXPECT_EQ(expected_frames, read_frames); | 
|  | } | 
|  |  | 
|  | INSTANTIATE_TEST_SUITE_P( | 
|  | Y4mFrameReaderTest, | 
|  | Y4mFrameReaderRepeatModeTest, | 
|  | ::testing::ValuesIn( | 
|  | {std::make_tuple(RepeatMode::kSingle, std::vector<int>{0, 1, 2}), | 
|  | std::make_tuple(RepeatMode::kRepeat, | 
|  | std::vector<int>{0, 1, 2, 0, 1, 2}), | 
|  | std::make_tuple(RepeatMode::kPingPong, | 
|  | std::vector<int>{0, 1, 2, 1, 0, 1, 2})})); | 
|  |  | 
|  | class Y4mFrameReaderFramerateScaleTest | 
|  | : public Y4mFrameReaderTest, | 
|  | public ::testing::WithParamInterface< | 
|  | std::tuple<Ratio, std::vector<int>>> {}; | 
|  |  | 
|  | TEST_P(Y4mFrameReaderFramerateScaleTest, PullFrame) { | 
|  | Ratio framerate_scale = std::get<0>(GetParam()); | 
|  | std::vector<int> expected_frames = std::get<1>(GetParam()); | 
|  |  | 
|  | std::vector<int> actual_frames; | 
|  | for (size_t i = 0; i < expected_frames.size(); ++i) { | 
|  | int pulled_frame; | 
|  | scoped_refptr<I420BufferInterface> buffer = | 
|  | reader_->PullFrame(&pulled_frame, kResolution, framerate_scale); | 
|  | actual_frames.push_back(pulled_frame); | 
|  | } | 
|  | EXPECT_EQ(expected_frames, actual_frames); | 
|  | } | 
|  |  | 
|  | INSTANTIATE_TEST_SUITE_P(Y4mFrameReaderTest, | 
|  | Y4mFrameReaderFramerateScaleTest, | 
|  | ::testing::ValuesIn({ | 
|  | std::make_tuple(Ratio({.num = 1, .den = 2}), | 
|  | std::vector<int>{0, 2, 4}), | 
|  | std::make_tuple(Ratio({.num = 2, .den = 3}), | 
|  | std::vector<int>{0, 1, 3, 4, 6}), | 
|  | std::make_tuple(Ratio({.num = 2, .den = 1}), | 
|  | std::vector<int>{0, 0, 1, 1}), | 
|  | })); | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace webrtc |