kjellander@webrtc.org | 5b97b12 | 2011-12-08 07:42:18 | [diff] [blame] | 1 | /* |
brandtr | b78bc75 | 2017-02-22 09:26:59 | [diff] [blame] | 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
kjellander@webrtc.org | 5b97b12 | 2011-12-08 07:42:18 | [diff] [blame] | 3 | * |
| 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 Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 11 | #include <stdio.h> |
Jonas Olsson | a4d8737 | 2019-07-05 17:08:33 | [diff] [blame] | 12 | |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 13 | #include <string> |
kjellander@webrtc.org | 5b97b12 | 2011-12-08 07:42:18 | [diff] [blame] | 14 | |
Mirko Bonadei | d970807 | 2019-01-25 19:26:48 | [diff] [blame] | 15 | #include "api/scoped_refptr.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 16 | #include "api/video/i420_buffer.h" |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 17 | #include "common_video/libyuv/include/webrtc_libyuv.h" |
Sergey Silkin | 18454b7 | 2022-02-18 10:54:28 | [diff] [blame] | 18 | #include "rtc_base/logging.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 19 | #include "test/frame_utils.h" |
Steve Anton | 10542f2 | 2019-01-11 17:11:00 | [diff] [blame] | 20 | #include "test/testsupport/file_utils.h" |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 21 | #include "test/testsupport/frame_reader.h" |
kjellander@webrtc.org | 5b97b12 | 2011-12-08 07:42:18 | [diff] [blame] | 22 | |
| 23 | namespace webrtc { |
| 24 | namespace test { |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 25 | namespace { |
| 26 | using RepeatMode = YuvFrameReaderImpl::RepeatMode; |
| 27 | |
| 28 | int 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 Silkin | 8c16f1f | 2023-10-21 13:32:42 | [diff] [blame] | 39 | int cycle_len = std::max(1, 2 * (num_frames - 1)); |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 40 | 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ång | ebe5acb | 2020-12-03 15:18:44 | [diff] [blame] | 45 | } |
| 46 | |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 47 | rtc::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ång | ebe5acb | 2020-12-03 15:18:44 | [diff] [blame] | 51 | return buffer; |
kjellander@webrtc.org | 5b97b12 | 2011-12-08 07:42:18 | [diff] [blame] | 52 | } |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 53 | 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ång | ebe5acb | 2020-12-03 15:18:44 | [diff] [blame] | 59 | |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 60 | int 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.org | 5b97b12 | 2011-12-08 07:42:18 | [diff] [blame] | 69 | } |
| 70 | |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 71 | YuvFrameReaderImpl::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 | |
| 83 | YuvFrameReaderImpl::~YuvFrameReaderImpl() { |
| 84 | if (file_ != nullptr) { |
| 85 | fclose(file_); |
| 86 | file_ = nullptr; |
brandtr | b78bc75 | 2017-02-22 09:26:59 | [diff] [blame] | 87 | } |
| 88 | } |
| 89 | |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 90 | void 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"; |
brandtr | b78bc75 | 2017-02-22 09:26:59 | [diff] [blame] | 104 | } |
| 105 | |
Sergey Silkin | 1985b5a | 2022-12-06 14:36:21 | [diff] [blame] | 106 | rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame() { |
| 107 | return PullFrame(/*frame_num=*/nullptr); |
| 108 | } |
| 109 | |
| 110 | rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame(int* frame_num) { |
| 111 | return PullFrame(frame_num, resolution_, /*framerate_scale=*/kNoScale); |
| 112 | } |
| 113 | |
| 114 | rtc::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 | |
| 126 | rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::ReadFrame(int frame_num) { |
| 127 | return ReadFrame(frame_num, resolution_); |
| 128 | } |
| 129 | |
| 130 | rtc::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 | |
| 145 | std::unique_ptr<FrameReader> CreateYuvFrameReader(std::string filepath, |
| 146 | Resolution resolution) { |
| 147 | return CreateYuvFrameReader(filepath, resolution, |
| 148 | YuvFrameReaderImpl::RepeatMode::kSingle); |
| 149 | } |
| 150 | |
| 151 | std::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); |
brandtr | b78bc75 | 2017-02-22 09:26:59 | [diff] [blame] | 159 | } |
pbos@webrtc.org | e6c3966 | 2013-07-30 13:08:38 | [diff] [blame] | 160 | |
kjellander@webrtc.org | 5b97b12 | 2011-12-08 07:42:18 | [diff] [blame] | 161 | } // namespace test |
| 162 | } // namespace webrtc |