/* * 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 "rtc_tools/video_file_reader.h" #include #include #include #include "absl/strings/match.h" #include "absl/types/optional.h" #include "api/make_ref_counted.h" #include "api/video/i420_buffer.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/string_encode.h" #include "rtc_base/string_to_number.h" namespace webrtc { namespace test { namespace { bool ReadBytes(uint8_t* dst, size_t n, FILE* file) { return fread(reinterpret_cast(dst), /* size= */ 1, n, file) == n; } // Common base class for .yuv and .y4m files. class VideoFile : public Video { public: VideoFile(int width, int height, const std::vector& frame_positions, FILE* file) : width_(width), height_(height), frame_positions_(frame_positions), file_(file) {} ~VideoFile() override { fclose(file_); } size_t number_of_frames() const override { return frame_positions_.size(); } int width() const override { return width_; } int height() const override { return height_; } rtc::scoped_refptr GetFrame( size_t frame_index) const override { RTC_CHECK_LT(frame_index, frame_positions_.size()); fsetpos(file_, &frame_positions_[frame_index]); rtc::scoped_refptr buffer = I420Buffer::Create(width_, height_); if (!ReadBytes(buffer->MutableDataY(), width_ * height_, file_) || !ReadBytes(buffer->MutableDataU(), buffer->ChromaWidth() * buffer->ChromaHeight(), file_) || !ReadBytes(buffer->MutableDataV(), buffer->ChromaWidth() * buffer->ChromaHeight(), file_)) { RTC_LOG(LS_ERROR) << "Could not read YUV data for frame " << frame_index; return nullptr; } return buffer; } private: const int width_; const int height_; const std::vector frame_positions_; FILE* const file_; }; } // namespace Video::Iterator::Iterator(const rtc::scoped_refptr& video, size_t index) : video_(video), index_(index) {} Video::Iterator::Iterator(const Video::Iterator& other) = default; Video::Iterator::Iterator(Video::Iterator&& other) = default; Video::Iterator& Video::Iterator::operator=(Video::Iterator&&) = default; Video::Iterator& Video::Iterator::operator=(const Video::Iterator&) = default; Video::Iterator::~Iterator() = default; rtc::scoped_refptr Video::Iterator::operator*() const { return video_->GetFrame(index_); } bool Video::Iterator::operator==(const Video::Iterator& other) const { return index_ == other.index_; } bool Video::Iterator::operator!=(const Video::Iterator& other) const { return !(*this == other); } Video::Iterator Video::Iterator::operator++(int) { const Iterator copy = *this; ++*this; return copy; } Video::Iterator& Video::Iterator::operator++() { ++index_; return *this; } Video::Iterator Video::begin() const { return Iterator(rtc::scoped_refptr(this), 0); } Video::Iterator Video::end() const { return Iterator(rtc::scoped_refptr(this), number_of_frames()); } rtc::scoped_refptr