summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/test/testsupport/yuv_frame_reader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/test/testsupport/yuv_frame_reader.cc')
-rw-r--r--third_party/libwebrtc/test/testsupport/yuv_frame_reader.cc162
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