diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/test/testsupport/yuv_frame_reader.cc | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/testsupport/yuv_frame_reader.cc b/third_party/libwebrtc/test/testsupport/yuv_frame_reader.cc new file mode 100644 index 0000000000..02c1a68008 --- /dev/null +++ b/third_party/libwebrtc/test/testsupport/yuv_frame_reader.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017 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 <string> + +#include "api/scoped_refptr.h" +#include "api/video/i420_buffer.h" +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "rtc_base/logging.h" +#include "test/frame_utils.h" +#include "test/testsupport/file_utils.h" +#include "test/testsupport/frame_reader.h" + +namespace webrtc { +namespace test { +namespace { +using RepeatMode = YuvFrameReaderImpl::RepeatMode; + +int WrapFrameNum(int frame_num, int num_frames, RepeatMode mode) { + RTC_CHECK_GE(frame_num, 0) << "frame_num cannot be negative"; + RTC_CHECK_GT(num_frames, 0) << "num_frames must be greater than 0"; + if (mode == RepeatMode::kSingle) { + return frame_num; + } + if (mode == RepeatMode::kRepeat) { + return frame_num % num_frames; + } + + RTC_CHECK_EQ(RepeatMode::kPingPong, mode); + int cycle_len = 2 * (num_frames - 1); + int wrapped_num = frame_num % cycle_len; + if (wrapped_num >= num_frames) { + return cycle_len - wrapped_num; + } + return wrapped_num; +} + +rtc::scoped_refptr<I420Buffer> Scale(rtc::scoped_refptr<I420Buffer> buffer, + Resolution resolution) { + if (buffer->width() == resolution.width && + buffer->height() == resolution.height) { + return buffer; + } + rtc::scoped_refptr<I420Buffer> scaled( + I420Buffer::Create(resolution.width, resolution.height)); + scaled->ScaleFrom(*buffer.get()); + return scaled; +} +} // namespace + +int YuvFrameReaderImpl::RateScaler::Skip(Ratio framerate_scale) { + ticks_ = ticks_.value_or(framerate_scale.num); + int skip = 0; + while (ticks_ <= 0) { + *ticks_ += framerate_scale.num; + ++skip; + } + *ticks_ -= framerate_scale.den; + return skip; +} + +YuvFrameReaderImpl::YuvFrameReaderImpl(std::string filepath, + Resolution resolution, + RepeatMode repeat_mode) + : filepath_(filepath), + resolution_(resolution), + repeat_mode_(repeat_mode), + num_frames_(0), + frame_num_(0), + frame_size_bytes_(0), + header_size_bytes_(0), + file_(nullptr) {} + +YuvFrameReaderImpl::~YuvFrameReaderImpl() { + if (file_ != nullptr) { + fclose(file_); + file_ = nullptr; + } +} + +void YuvFrameReaderImpl::Init() { + RTC_CHECK_GT(resolution_.width, 0) << "Width must be positive"; + RTC_CHECK_GT(resolution_.height, 0) << "Height must be positive"; + frame_size_bytes_ = + CalcBufferSize(VideoType::kI420, resolution_.width, resolution_.height); + + file_ = fopen(filepath_.c_str(), "rb"); + RTC_CHECK(file_ != NULL) << "Cannot open " << filepath_; + + size_t file_size_bytes = GetFileSize(filepath_); + RTC_CHECK_GT(file_size_bytes, 0u) << "File " << filepath_ << " is empty"; + + num_frames_ = static_cast<int>(file_size_bytes / frame_size_bytes_); + RTC_CHECK_GT(num_frames_, 0u) << "File " << filepath_ << " is too small"; +} + +rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame() { + return PullFrame(/*frame_num=*/nullptr); +} + +rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame(int* frame_num) { + return PullFrame(frame_num, resolution_, /*framerate_scale=*/kNoScale); +} + +rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::PullFrame( + int* frame_num, + Resolution resolution, + Ratio framerate_scale) { + frame_num_ += framerate_scaler_.Skip(framerate_scale); + auto buffer = ReadFrame(frame_num_, resolution); + if (frame_num != nullptr) { + *frame_num = frame_num_; + } + return buffer; +} + +rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::ReadFrame(int frame_num) { + return ReadFrame(frame_num, resolution_); +} + +rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::ReadFrame( + int frame_num, + Resolution resolution) { + int wrapped_num = WrapFrameNum(frame_num, num_frames_, repeat_mode_); + if (wrapped_num >= num_frames_) { + RTC_CHECK_EQ(RepeatMode::kSingle, repeat_mode_); + return nullptr; + } + fseek(file_, header_size_bytes_ + wrapped_num * frame_size_bytes_, SEEK_SET); + auto buffer = ReadI420Buffer(resolution_.width, resolution_.height, file_); + RTC_CHECK(buffer != nullptr); + + return Scale(buffer, resolution); +} + +std::unique_ptr<FrameReader> CreateYuvFrameReader(std::string filepath, + Resolution resolution) { + return CreateYuvFrameReader(filepath, resolution, + YuvFrameReaderImpl::RepeatMode::kSingle); +} + +std::unique_ptr<FrameReader> CreateYuvFrameReader( + std::string filepath, + Resolution resolution, + YuvFrameReaderImpl::RepeatMode repeat_mode) { + YuvFrameReaderImpl* frame_reader = + new YuvFrameReaderImpl(filepath, resolution, repeat_mode); + frame_reader->Init(); + return std::unique_ptr<FrameReader>(frame_reader); +} + +} // namespace test +} // namespace webrtc |