1*09537850SAkhilesh Sanikop // Copyright 2019 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop // http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop
15*09537850SAkhilesh Sanikop #include "examples/file_reader.h"
16*09537850SAkhilesh Sanikop
17*09537850SAkhilesh Sanikop #include <algorithm>
18*09537850SAkhilesh Sanikop #include <cstdint>
19*09537850SAkhilesh Sanikop #include <cstdio>
20*09537850SAkhilesh Sanikop #include <new>
21*09537850SAkhilesh Sanikop #include <string>
22*09537850SAkhilesh Sanikop #include <vector>
23*09537850SAkhilesh Sanikop
24*09537850SAkhilesh Sanikop #if defined(_WIN32)
25*09537850SAkhilesh Sanikop #include <fcntl.h>
26*09537850SAkhilesh Sanikop #include <io.h>
27*09537850SAkhilesh Sanikop #endif
28*09537850SAkhilesh Sanikop
29*09537850SAkhilesh Sanikop #include "examples/file_reader_constants.h"
30*09537850SAkhilesh Sanikop #include "examples/file_reader_factory.h"
31*09537850SAkhilesh Sanikop #include "examples/file_reader_interface.h"
32*09537850SAkhilesh Sanikop #include "examples/ivf_parser.h"
33*09537850SAkhilesh Sanikop #include "examples/logging.h"
34*09537850SAkhilesh Sanikop
35*09537850SAkhilesh Sanikop namespace libgav1 {
36*09537850SAkhilesh Sanikop namespace {
37*09537850SAkhilesh Sanikop
SetBinaryMode(FILE * stream)38*09537850SAkhilesh Sanikop FILE* SetBinaryMode(FILE* stream) {
39*09537850SAkhilesh Sanikop #if defined(_WIN32)
40*09537850SAkhilesh Sanikop _setmode(_fileno(stream), _O_BINARY);
41*09537850SAkhilesh Sanikop #endif
42*09537850SAkhilesh Sanikop return stream;
43*09537850SAkhilesh Sanikop }
44*09537850SAkhilesh Sanikop
45*09537850SAkhilesh Sanikop } // namespace
46*09537850SAkhilesh Sanikop
47*09537850SAkhilesh Sanikop bool FileReader::registered_in_factory_ =
48*09537850SAkhilesh Sanikop FileReaderFactory::RegisterReader(FileReader::Open);
49*09537850SAkhilesh Sanikop
~FileReader()50*09537850SAkhilesh Sanikop FileReader::~FileReader() {
51*09537850SAkhilesh Sanikop if (owns_file_) fclose(file_);
52*09537850SAkhilesh Sanikop }
53*09537850SAkhilesh Sanikop
Open(const std::string & file_name,const bool error_tolerant)54*09537850SAkhilesh Sanikop std::unique_ptr<FileReaderInterface> FileReader::Open(
55*09537850SAkhilesh Sanikop const std::string& file_name, const bool error_tolerant) {
56*09537850SAkhilesh Sanikop if (file_name.empty()) return nullptr;
57*09537850SAkhilesh Sanikop
58*09537850SAkhilesh Sanikop FILE* raw_file_ptr;
59*09537850SAkhilesh Sanikop
60*09537850SAkhilesh Sanikop bool owns_file = true;
61*09537850SAkhilesh Sanikop if (file_name == "-") {
62*09537850SAkhilesh Sanikop raw_file_ptr = SetBinaryMode(stdin);
63*09537850SAkhilesh Sanikop owns_file = false; // stdin is owned by the Standard C Library.
64*09537850SAkhilesh Sanikop } else {
65*09537850SAkhilesh Sanikop raw_file_ptr = fopen(file_name.c_str(), "rb");
66*09537850SAkhilesh Sanikop }
67*09537850SAkhilesh Sanikop
68*09537850SAkhilesh Sanikop if (raw_file_ptr == nullptr) {
69*09537850SAkhilesh Sanikop return nullptr;
70*09537850SAkhilesh Sanikop }
71*09537850SAkhilesh Sanikop
72*09537850SAkhilesh Sanikop std::unique_ptr<FileReader> file(
73*09537850SAkhilesh Sanikop new (std::nothrow) FileReader(raw_file_ptr, owns_file, error_tolerant));
74*09537850SAkhilesh Sanikop if (file == nullptr) {
75*09537850SAkhilesh Sanikop LIBGAV1_EXAMPLES_LOG_ERROR("Out of memory");
76*09537850SAkhilesh Sanikop if (owns_file) fclose(raw_file_ptr);
77*09537850SAkhilesh Sanikop return nullptr;
78*09537850SAkhilesh Sanikop }
79*09537850SAkhilesh Sanikop
80*09537850SAkhilesh Sanikop if (!file->ReadIvfFileHeader()) {
81*09537850SAkhilesh Sanikop LIBGAV1_EXAMPLES_LOG_ERROR("Unsupported file type");
82*09537850SAkhilesh Sanikop return nullptr;
83*09537850SAkhilesh Sanikop }
84*09537850SAkhilesh Sanikop
85*09537850SAkhilesh Sanikop // With C++11, to return |file|, an explicit move is required as the return
86*09537850SAkhilesh Sanikop // type differs from the local variable. Overload resolution isn't guaranteed
87*09537850SAkhilesh Sanikop // in this case, though some compilers may adopt the C++14 behavior (C++
88*09537850SAkhilesh Sanikop // Standard Core Language Issue #1579, Return by converting move
89*09537850SAkhilesh Sanikop // constructor):
90*09537850SAkhilesh Sanikop // https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579
91*09537850SAkhilesh Sanikop // To keep things simple we opt for the following compatible form.
92*09537850SAkhilesh Sanikop return std::unique_ptr<FileReaderInterface>(file.release());
93*09537850SAkhilesh Sanikop }
94*09537850SAkhilesh Sanikop
95*09537850SAkhilesh Sanikop // IVF Frame Header format, from https://wiki.multimedia.cx/index.php/IVF
96*09537850SAkhilesh Sanikop // bytes 0-3 size of frame in bytes (not including the 12-byte header)
97*09537850SAkhilesh Sanikop // bytes 4-11 64-bit presentation timestamp
98*09537850SAkhilesh Sanikop // bytes 12.. frame data
ReadTemporalUnit(std::vector<uint8_t> * const tu_data,int64_t * const timestamp)99*09537850SAkhilesh Sanikop bool FileReader::ReadTemporalUnit(std::vector<uint8_t>* const tu_data,
100*09537850SAkhilesh Sanikop int64_t* const timestamp) {
101*09537850SAkhilesh Sanikop if (tu_data == nullptr) return false;
102*09537850SAkhilesh Sanikop tu_data->clear();
103*09537850SAkhilesh Sanikop
104*09537850SAkhilesh Sanikop uint8_t header_buffer[kIvfFrameHeaderSize];
105*09537850SAkhilesh Sanikop const size_t num_read = fread(header_buffer, 1, kIvfFrameHeaderSize, file_);
106*09537850SAkhilesh Sanikop
107*09537850SAkhilesh Sanikop if (IsEndOfFile()) {
108*09537850SAkhilesh Sanikop if (num_read != 0) {
109*09537850SAkhilesh Sanikop LIBGAV1_EXAMPLES_LOG_ERROR(
110*09537850SAkhilesh Sanikop "Cannot read IVF frame header: Not enough data available");
111*09537850SAkhilesh Sanikop return false;
112*09537850SAkhilesh Sanikop }
113*09537850SAkhilesh Sanikop
114*09537850SAkhilesh Sanikop return true;
115*09537850SAkhilesh Sanikop }
116*09537850SAkhilesh Sanikop
117*09537850SAkhilesh Sanikop IvfFrameHeader ivf_frame_header;
118*09537850SAkhilesh Sanikop if (!ParseIvfFrameHeader(header_buffer, &ivf_frame_header)) {
119*09537850SAkhilesh Sanikop LIBGAV1_EXAMPLES_LOG_ERROR("Could not parse IVF frame header");
120*09537850SAkhilesh Sanikop if (error_tolerant_) {
121*09537850SAkhilesh Sanikop ivf_frame_header.frame_size =
122*09537850SAkhilesh Sanikop std::min(ivf_frame_header.frame_size, size_t{kMaxTemporalUnitSize});
123*09537850SAkhilesh Sanikop } else {
124*09537850SAkhilesh Sanikop return false;
125*09537850SAkhilesh Sanikop }
126*09537850SAkhilesh Sanikop }
127*09537850SAkhilesh Sanikop
128*09537850SAkhilesh Sanikop if (timestamp != nullptr) *timestamp = ivf_frame_header.timestamp;
129*09537850SAkhilesh Sanikop
130*09537850SAkhilesh Sanikop tu_data->resize(ivf_frame_header.frame_size);
131*09537850SAkhilesh Sanikop const size_t size_read =
132*09537850SAkhilesh Sanikop fread(tu_data->data(), 1, ivf_frame_header.frame_size, file_);
133*09537850SAkhilesh Sanikop if (size_read != ivf_frame_header.frame_size) {
134*09537850SAkhilesh Sanikop LIBGAV1_EXAMPLES_LOG_ERROR(
135*09537850SAkhilesh Sanikop "Unexpected EOF or I/O error reading frame data");
136*09537850SAkhilesh Sanikop if (error_tolerant_) {
137*09537850SAkhilesh Sanikop tu_data->resize(size_read);
138*09537850SAkhilesh Sanikop } else {
139*09537850SAkhilesh Sanikop return false;
140*09537850SAkhilesh Sanikop }
141*09537850SAkhilesh Sanikop }
142*09537850SAkhilesh Sanikop return true;
143*09537850SAkhilesh Sanikop }
144*09537850SAkhilesh Sanikop
145*09537850SAkhilesh Sanikop // Attempt to read an IVF file header. Returns true for success, and false for
146*09537850SAkhilesh Sanikop // failure.
147*09537850SAkhilesh Sanikop //
148*09537850SAkhilesh Sanikop // IVF File Header format, from https://wiki.multimedia.cx/index.php/IVF
149*09537850SAkhilesh Sanikop // bytes 0-3 signature: 'DKIF'
150*09537850SAkhilesh Sanikop // bytes 4-5 version (should be 0)
151*09537850SAkhilesh Sanikop // bytes 6-7 length of header in bytes
152*09537850SAkhilesh Sanikop // bytes 8-11 codec FourCC (e.g., 'VP80')
153*09537850SAkhilesh Sanikop // bytes 12-13 width in pixels
154*09537850SAkhilesh Sanikop // bytes 14-15 height in pixels
155*09537850SAkhilesh Sanikop // bytes 16-19 frame rate
156*09537850SAkhilesh Sanikop // bytes 20-23 time scale
157*09537850SAkhilesh Sanikop // bytes 24-27 number of frames in file
158*09537850SAkhilesh Sanikop // bytes 28-31 unused
159*09537850SAkhilesh Sanikop //
160*09537850SAkhilesh Sanikop // Note: The rate and scale fields correspond to the numerator and denominator
161*09537850SAkhilesh Sanikop // of frame rate (fps) or time base (the reciprocal of frame rate) as follows:
162*09537850SAkhilesh Sanikop //
163*09537850SAkhilesh Sanikop // bytes 16-19 frame rate timebase.den framerate.numerator
164*09537850SAkhilesh Sanikop // bytes 20-23 time scale timebase.num framerate.denominator
ReadIvfFileHeader()165*09537850SAkhilesh Sanikop bool FileReader::ReadIvfFileHeader() {
166*09537850SAkhilesh Sanikop uint8_t header_buffer[kIvfFileHeaderSize];
167*09537850SAkhilesh Sanikop const size_t num_read = fread(header_buffer, 1, kIvfFileHeaderSize, file_);
168*09537850SAkhilesh Sanikop if (num_read != kIvfFileHeaderSize) {
169*09537850SAkhilesh Sanikop LIBGAV1_EXAMPLES_LOG_ERROR(
170*09537850SAkhilesh Sanikop "Cannot read IVF header: Not enough data available");
171*09537850SAkhilesh Sanikop return false;
172*09537850SAkhilesh Sanikop }
173*09537850SAkhilesh Sanikop
174*09537850SAkhilesh Sanikop IvfFileHeader ivf_file_header;
175*09537850SAkhilesh Sanikop if (!ParseIvfFileHeader(header_buffer, &ivf_file_header)) {
176*09537850SAkhilesh Sanikop LIBGAV1_EXAMPLES_LOG_ERROR("Could not parse IVF file header");
177*09537850SAkhilesh Sanikop if (error_tolerant_) {
178*09537850SAkhilesh Sanikop ivf_file_header = {};
179*09537850SAkhilesh Sanikop } else {
180*09537850SAkhilesh Sanikop return false;
181*09537850SAkhilesh Sanikop }
182*09537850SAkhilesh Sanikop }
183*09537850SAkhilesh Sanikop
184*09537850SAkhilesh Sanikop width_ = ivf_file_header.width;
185*09537850SAkhilesh Sanikop height_ = ivf_file_header.height;
186*09537850SAkhilesh Sanikop frame_rate_ = ivf_file_header.frame_rate_numerator;
187*09537850SAkhilesh Sanikop time_scale_ = ivf_file_header.frame_rate_denominator;
188*09537850SAkhilesh Sanikop type_ = kFileTypeIvf;
189*09537850SAkhilesh Sanikop
190*09537850SAkhilesh Sanikop return true;
191*09537850SAkhilesh Sanikop }
192*09537850SAkhilesh Sanikop
193*09537850SAkhilesh Sanikop } // namespace libgav1
194