blob: db4ba232695500b512e63b6997983021efa07317 [file] [log] [blame]
kjellander@webrtc.org5b97b122011-12-08 07:42:181/*
brandtrb78bc752017-02-22 09:26:592 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
kjellander@webrtc.org5b97b122011-12-08 07:42:183 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Yves Gerey3e707812018-11-28 15:47:4911#include <stdio.h>
Jonas Olssona4d87372019-07-05 17:08:3312
Yves Gerey3e707812018-11-28 15:47:4913#include <string>
kjellander@webrtc.org5b97b122011-12-08 07:42:1814
Mirko Bonadeid9708072019-01-25 19:26:4815#include "api/scoped_refptr.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3116#include "api/video/i420_buffer.h"
Sergey Silkin1985b5a2022-12-06 14:36:2117#include "common_video/libyuv/include/webrtc_libyuv.h"
Sergey Silkin18454b72022-02-18 10:54:2818#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3119#include "test/frame_utils.h"
Steve Anton10542f22019-01-11 17:11:0020#include "test/testsupport/file_utils.h"
Yves Gerey3e707812018-11-28 15:47:4921#include "test/testsupport/frame_reader.h"
kjellander@webrtc.org5b97b122011-12-08 07:42:1822
23namespace webrtc {
24namespace test {
Sergey Silkin1985b5a2022-12-06 14:36:2125namespace {
26using RepeatMode = YuvFrameReaderImpl::RepeatMode;
27
28int WrapFrameNum(int frame_num, int num_frames, RepeatMode mode) {
29 RTC_CHECK_GE(frame_num, 0) << "frame_num cannot be negative";
30 RTC_CHECK_GT(num_frames, 0) << "num_frames must be greater than 0";
31 if (mode == RepeatMode::kSingle) {
32 return frame_num;
33 }
34 if (mode == RepeatMode::kRepeat) {
35 return frame_num % num_frames;
36 }
37
38 RTC_CHECK_EQ(RepeatMode::kPingPong, mode);
Sergey Silkin8c16f1f2023-10-21 13:32:4239 int cycle_len = std::max(1, 2 * (num_frames - 1));
Sergey Silkin1985b5a2022-12-06 14:36:2140 int wrapped_num = frame_num % cycle_len;
41 if (wrapped_num >= num_frames) {
42 return cycle_len - wrapped_num;
43 }
44 return wrapped_num;
Erik Språngebe5acb2020-12-03 15:18:4445}
46
Sergey Silkin1985b5a2022-12-06 14:36:2147rtc::scoped_refptr<I420Buffer> Scale(rtc::scoped_refptr<I420Buffer> buffer,
48 Resolution resolution) {
49 if (buffer->width() == resolution.width &&
50 buffer->height() == resolution.height) {
Erik Språngebe5acb2020-12-03 15:18:4451 return buffer;
kjellander@webrtc.org5b97b122011-12-08 07:42:1852 }
Sergey Silkin1985b5a2022-12-06 14:36:2153 rtc::scoped_refptr<I420Buffer> scaled(
54 I420Buffer::Create(resolution.width, resolution.height));
55 scaled->ScaleFrom(*buffer.get());
56 return scaled;
57}
58} // namespace
Erik Språngebe5acb2020-12-03 15:18:4459
Sergey Silkin1985b5a2022-12-06 14:36:2160int YuvFrameReaderImpl::RateScaler::Skip(Ratio framerate_scale) {
61 ticks_ = ticks_.value_or(framerate_scale.num);
62 int skip = 0;
63 while (ticks_ <= 0) {
64 *ticks_ += framerate_scale.num;
65 ++skip;
66 }
67 *ticks_ -= framerate_scale.den;
68 return skip;
kjellander@webrtc.org5b97b122011-12-08 07:42:1869}
70
Sergey Silkin1985b5a2022-12-06 14:36:2171YuvFrameReaderImpl::YuvFrameReaderImpl(std::string filepath,
72 Resolution resolution,
73 RepeatMode repeat_mode)
74 : filepath_(filepath),
75 resolution_(resolution),
76 repeat_mode_(repeat_mode),
77 num_frames_(0),
78 frame_num_(0),
79 frame_size_bytes_(0),
80 header_size_bytes_(0),
81 file_(nullptr) {}
82
83YuvFrameReaderImpl::~YuvFrameReaderImpl() {
84 if (file_ != nullptr) {
85 fclose(file_);
86 file_ = nullptr;
brandtrb78bc752017-02-22 09:26:5987 }
88}
89
Sergey Silkin1985b5a2022-12-06 14:36:2190void YuvFrameReaderImpl::Init() {
91 RTC_CHECK_GT(resolution_.width, 0) << "Width must be positive";
92 RTC_CHECK_GT(resolution_.height, 0) << "Height must be positive";
93 frame_size_bytes_ =
94 CalcBufferSize(VideoType::kI420, resolution_.width, resolution_.height);
95
96 file_ = fopen(filepath_.c_str(), "rb");
97 RTC_CHECK(file_ != NULL) << "Cannot open " << filepath_;
98
99 size_t file_size_bytes = GetFileSize(filepath_);
100 RTC_CHECK_GT(file_size_bytes, 0u) << "File " << filepath_ << " is empty";
101
102 num_frames_ = static_cast<int>(file_size_bytes / frame_size_bytes_);
103 RTC_CHECK_GT(num_frames_, 0u) << "File " << filepath_ << " is too small";
brandtrb78bc752017-02-22 09:26:59104}
105
Sergey Silkin1985b5a2022-12-06 14:36:21106rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame() {
107 return PullFrame(/*frame_num=*/nullptr);
108}
109
110rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame(int* frame_num) {
111 return PullFrame(frame_num, resolution_, /*framerate_scale=*/kNoScale);
112}
113
114rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame(
115 int* frame_num,
116 Resolution resolution,
117 Ratio framerate_scale) {
118 frame_num_ += framerate_scaler_.Skip(framerate_scale);
119 auto buffer = ReadFrame(frame_num_, resolution);
120 if (frame_num != nullptr) {
121 *frame_num = frame_num_;
122 }
123 return buffer;
124}
125
126rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::ReadFrame(int frame_num) {
127 return ReadFrame(frame_num, resolution_);
128}
129
130rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::ReadFrame(
131 int frame_num,
132 Resolution resolution) {
133 int wrapped_num = WrapFrameNum(frame_num, num_frames_, repeat_mode_);
134 if (wrapped_num >= num_frames_) {
135 RTC_CHECK_EQ(RepeatMode::kSingle, repeat_mode_);
136 return nullptr;
137 }
138 fseek(file_, header_size_bytes_ + wrapped_num * frame_size_bytes_, SEEK_SET);
139 auto buffer = ReadI420Buffer(resolution_.width, resolution_.height, file_);
140 RTC_CHECK(buffer != nullptr);
141
142 return Scale(buffer, resolution);
143}
144
145std::unique_ptr<FrameReader> CreateYuvFrameReader(std::string filepath,
146 Resolution resolution) {
147 return CreateYuvFrameReader(filepath, resolution,
148 YuvFrameReaderImpl::RepeatMode::kSingle);
149}
150
151std::unique_ptr<FrameReader> CreateYuvFrameReader(
152 std::string filepath,
153 Resolution resolution,
154 YuvFrameReaderImpl::RepeatMode repeat_mode) {
155 YuvFrameReaderImpl* frame_reader =
156 new YuvFrameReaderImpl(filepath, resolution, repeat_mode);
157 frame_reader->Init();
158 return std::unique_ptr<FrameReader>(frame_reader);
brandtrb78bc752017-02-22 09:26:59159}
pbos@webrtc.orge6c39662013-07-30 13:08:38160
kjellander@webrtc.org5b97b122011-12-08 07:42:18161} // namespace test
162} // namespace webrtc