webrtc/test/testsupport/y4m_frame_reader.cc
Sergey Silkin 1985b5a927 Refactor YUV frame reader
Purposes of this refactoring:
1. Add functionality for reading a specified frame.
2. Change resolution and frame rate on per-frame basis.

Both features are needed for https://webrtc-review.googlesource.com/c/src/+/283525

Bug: b/261160916
Change-Id: I6d60e62dbc3913c43b5c1b491690f5cb4a8632dd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/285483
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38829}
2022-12-06 16:23:48 +00:00

92 lines
3.2 KiB
C++

/*
* 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 <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 "rtc_base/strings/string_builder.h"
#include "test/testsupport/file_utils.h"
#include "test/testsupport/frame_reader.h"
namespace webrtc {
namespace test {
namespace {
constexpr int kFrameHeaderSize = 6; // "FRAME\n"
} // namespace
void ParseY4mHeader(std::string filepath,
Resolution* resolution,
int* header_size) {
FILE* file = fopen(filepath.c_str(), "r");
RTC_CHECK(file != NULL) << "Cannot open " << filepath;
// Length of Y4M header is technically unlimited due to the comment tag 'X'.
char h[1024];
RTC_CHECK(fgets(h, sizeof(h), file) != NULL)
<< "File " << filepath << " is too small";
fclose(file);
RTC_CHECK(sscanf(h, "YUV4MPEG2 W%d H%d", &resolution->width,
&resolution->height) == 2)
<< filepath << " is not a valid Y4M file";
RTC_CHECK_GT(resolution->width, 0) << "Width must be positive";
RTC_CHECK_GT(resolution->height, 0) << "Height must be positive";
*header_size = strcspn(h, "\n") + 1;
RTC_CHECK(static_cast<unsigned>(*header_size) < sizeof(h))
<< filepath << " has unexpectedly large header";
}
Y4mFrameReaderImpl::Y4mFrameReaderImpl(std::string filepath,
RepeatMode repeat_mode)
: YuvFrameReaderImpl(filepath, Resolution(), repeat_mode) {}
void Y4mFrameReaderImpl::Init() {
file_ = fopen(filepath_.c_str(), "rb");
RTC_CHECK(file_ != nullptr) << "Cannot open " << filepath_;
ParseY4mHeader(filepath_, &resolution_, &header_size_bytes_);
frame_size_bytes_ =
CalcBufferSize(VideoType::kI420, resolution_.width, resolution_.height);
frame_size_bytes_ += kFrameHeaderSize;
size_t file_size_bytes = GetFileSize(filepath_);
RTC_CHECK_GT(file_size_bytes, 0u) << "File " << filepath_ << " is empty";
RTC_CHECK_GT(file_size_bytes, header_size_bytes_)
<< "File " << filepath_ << " is too small";
num_frames_ = static_cast<int>((file_size_bytes - header_size_bytes_) /
frame_size_bytes_);
RTC_CHECK_GT(num_frames_, 0u) << "File " << filepath_ << " is too small";
header_size_bytes_ += kFrameHeaderSize;
}
std::unique_ptr<FrameReader> CreateY4mFrameReader(std::string filepath) {
return CreateY4mFrameReader(filepath,
YuvFrameReaderImpl::RepeatMode::kSingle);
}
std::unique_ptr<FrameReader> CreateY4mFrameReader(
std::string filepath,
YuvFrameReaderImpl::RepeatMode repeat_mode) {
Y4mFrameReaderImpl* frame_reader =
new Y4mFrameReaderImpl(filepath, repeat_mode);
frame_reader->Init();
return std::unique_ptr<FrameReader>(frame_reader);
}
} // namespace test
} // namespace webrtc