xref: /aosp_15_r20/external/webrtc/modules/video_coding/utility/ivf_file_reader.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/video_coding/utility/ivf_file_reader.h"
12 
13 #include <string>
14 #include <vector>
15 
16 #include "api/video_codecs/video_codec.h"
17 #include "modules/rtp_rtcp/source/byte_io.h"
18 #include "modules/video_coding/utility/ivf_defines.h"
19 #include "rtc_base/logging.h"
20 
21 namespace webrtc {
22 namespace {
23 
24 constexpr size_t kIvfFrameHeaderSize = 12;
25 constexpr int kCodecTypeBytesCount = 4;
26 
27 constexpr uint8_t kFileHeaderStart[kCodecTypeBytesCount] = {'D', 'K', 'I', 'F'};
28 constexpr uint8_t kVp8Header[kCodecTypeBytesCount] = {'V', 'P', '8', '0'};
29 constexpr uint8_t kVp9Header[kCodecTypeBytesCount] = {'V', 'P', '9', '0'};
30 constexpr uint8_t kAv1Header[kCodecTypeBytesCount] = {'A', 'V', '0', '1'};
31 constexpr uint8_t kH264Header[kCodecTypeBytesCount] = {'H', '2', '6', '4'};
32 
33 // RTP standard required 90kHz clock rate.
34 constexpr int32_t kRtpClockRateHz = 90000;
35 
36 }  // namespace
37 
Create(FileWrapper file)38 std::unique_ptr<IvfFileReader> IvfFileReader::Create(FileWrapper file) {
39   auto reader =
40       std::unique_ptr<IvfFileReader>(new IvfFileReader(std::move(file)));
41   if (!reader->Reset()) {
42     return nullptr;
43   }
44   return reader;
45 }
~IvfFileReader()46 IvfFileReader::~IvfFileReader() {
47   Close();
48 }
49 
Reset()50 bool IvfFileReader::Reset() {
51   // Set error to true while initialization.
52   has_error_ = true;
53   if (!file_.Rewind()) {
54     RTC_LOG(LS_ERROR) << "Failed to rewind IVF file";
55     return false;
56   }
57 
58   uint8_t ivf_header[kIvfHeaderSize] = {0};
59   size_t read = file_.Read(&ivf_header, kIvfHeaderSize);
60   if (read != kIvfHeaderSize) {
61     RTC_LOG(LS_ERROR) << "Failed to read IVF header";
62     return false;
63   }
64 
65   if (memcmp(&ivf_header[0], kFileHeaderStart, 4) != 0) {
66     RTC_LOG(LS_ERROR) << "File is not in IVF format: DKIF header expected";
67     return false;
68   }
69 
70   absl::optional<VideoCodecType> codec_type = ParseCodecType(ivf_header, 8);
71   if (!codec_type) {
72     return false;
73   }
74   codec_type_ = *codec_type;
75 
76   width_ = ByteReader<uint16_t>::ReadLittleEndian(&ivf_header[12]);
77   height_ = ByteReader<uint16_t>::ReadLittleEndian(&ivf_header[14]);
78   if (width_ == 0 || height_ == 0) {
79     RTC_LOG(LS_ERROR) << "Invalid IVF header: width or height is 0";
80     return false;
81   }
82 
83   time_scale_ = ByteReader<uint32_t>::ReadLittleEndian(&ivf_header[16]);
84   if (time_scale_ == 0) {
85     RTC_LOG(LS_ERROR) << "Invalid IVF header: time scale can't be 0";
86     return false;
87   }
88 
89   num_frames_ = static_cast<size_t>(
90       ByteReader<uint32_t>::ReadLittleEndian(&ivf_header[24]));
91   if (num_frames_ <= 0) {
92     RTC_LOG(LS_ERROR) << "Invalid IVF header: number of frames 0 or negative";
93     return false;
94   }
95 
96   num_read_frames_ = 0;
97   next_frame_header_ = ReadNextFrameHeader();
98   if (!next_frame_header_) {
99     RTC_LOG(LS_ERROR) << "Failed to read 1st frame header";
100     return false;
101   }
102   // Initialization succeed: reset error.
103   has_error_ = false;
104 
105   const char* codec_name = CodecTypeToPayloadString(codec_type_);
106   RTC_LOG(LS_INFO) << "Opened IVF file with codec data of type " << codec_name
107                    << " at resolution " << width_ << " x " << height_
108                    << ", using " << time_scale_ << "Hz clock resolution.";
109 
110   return true;
111 }
112 
NextFrame()113 absl::optional<EncodedImage> IvfFileReader::NextFrame() {
114   if (has_error_ || !HasMoreFrames()) {
115     return absl::nullopt;
116   }
117 
118   rtc::scoped_refptr<EncodedImageBuffer> payload = EncodedImageBuffer::Create();
119   std::vector<size_t> layer_sizes;
120   // next_frame_header_ have to be presented by the way how it was loaded. If it
121   // is missing it means there is a bug in error handling.
122   RTC_DCHECK(next_frame_header_);
123   int64_t current_timestamp = next_frame_header_->timestamp;
124   // The first frame from the file should be marked as Key frame.
125   bool is_first_frame = num_read_frames_ == 0;
126   while (next_frame_header_ &&
127          current_timestamp == next_frame_header_->timestamp) {
128     // Resize payload to fit next spatial layer.
129     size_t current_layer_size = next_frame_header_->frame_size;
130     size_t current_layer_start_pos = payload->size();
131     payload->Realloc(payload->size() + current_layer_size);
132     layer_sizes.push_back(current_layer_size);
133 
134     // Read next layer into payload
135     size_t read = file_.Read(&payload->data()[current_layer_start_pos],
136                              current_layer_size);
137     if (read != current_layer_size) {
138       RTC_LOG(LS_ERROR) << "Frame #" << num_read_frames_
139                         << ": failed to read frame payload";
140       has_error_ = true;
141       return absl::nullopt;
142     }
143     num_read_frames_++;
144 
145     current_timestamp = next_frame_header_->timestamp;
146     next_frame_header_ = ReadNextFrameHeader();
147   }
148   if (!next_frame_header_) {
149     // If EOF was reached, we need to check that all frames were met.
150     if (!has_error_ && num_read_frames_ != num_frames_) {
151       RTC_LOG(LS_ERROR) << "Unexpected EOF";
152       has_error_ = true;
153       return absl::nullopt;
154     }
155   }
156 
157   EncodedImage image;
158   image.capture_time_ms_ = current_timestamp;
159   image.SetTimestamp(
160       static_cast<uint32_t>(current_timestamp * kRtpClockRateHz / time_scale_));
161   image.SetEncodedData(payload);
162   image.SetSpatialIndex(static_cast<int>(layer_sizes.size()) - 1);
163   for (size_t i = 0; i < layer_sizes.size(); ++i) {
164     image.SetSpatialLayerFrameSize(static_cast<int>(i), layer_sizes[i]);
165   }
166   if (is_first_frame) {
167     image._frameType = VideoFrameType::kVideoFrameKey;
168   }
169 
170   return image;
171 }
172 
Close()173 bool IvfFileReader::Close() {
174   if (!file_.is_open())
175     return false;
176 
177   file_.Close();
178   return true;
179 }
180 
ParseCodecType(uint8_t * buffer,size_t start_pos)181 absl::optional<VideoCodecType> IvfFileReader::ParseCodecType(uint8_t* buffer,
182                                                              size_t start_pos) {
183   if (memcmp(&buffer[start_pos], kVp8Header, kCodecTypeBytesCount) == 0) {
184     return VideoCodecType::kVideoCodecVP8;
185   }
186   if (memcmp(&buffer[start_pos], kVp9Header, kCodecTypeBytesCount) == 0) {
187     return VideoCodecType::kVideoCodecVP9;
188   }
189   if (memcmp(&buffer[start_pos], kAv1Header, kCodecTypeBytesCount) == 0) {
190     return VideoCodecType::kVideoCodecAV1;
191   }
192   if (memcmp(&buffer[start_pos], kH264Header, kCodecTypeBytesCount) == 0) {
193     return VideoCodecType::kVideoCodecH264;
194   }
195   has_error_ = true;
196   RTC_LOG(LS_ERROR) << "Unknown codec type: "
197                     << std::string(
198                            reinterpret_cast<char const*>(&buffer[start_pos]),
199                            kCodecTypeBytesCount);
200   return absl::nullopt;
201 }
202 
203 absl::optional<IvfFileReader::FrameHeader>
ReadNextFrameHeader()204 IvfFileReader::ReadNextFrameHeader() {
205   uint8_t ivf_frame_header[kIvfFrameHeaderSize] = {0};
206   size_t read = file_.Read(&ivf_frame_header, kIvfFrameHeaderSize);
207   if (read != kIvfFrameHeaderSize) {
208     if (read != 0 || !file_.ReadEof()) {
209       has_error_ = true;
210       RTC_LOG(LS_ERROR) << "Frame #" << num_read_frames_
211                         << ": failed to read IVF frame header";
212     }
213     return absl::nullopt;
214   }
215   FrameHeader header;
216   header.frame_size = static_cast<size_t>(
217       ByteReader<uint32_t>::ReadLittleEndian(&ivf_frame_header[0]));
218   header.timestamp =
219       ByteReader<uint64_t>::ReadLittleEndian(&ivf_frame_header[4]);
220 
221   if (header.frame_size == 0) {
222     has_error_ = true;
223     RTC_LOG(LS_ERROR) << "Frame #" << num_read_frames_
224                       << ": invalid frame size";
225     return absl::nullopt;
226   }
227 
228   if (header.timestamp < 0) {
229     has_error_ = true;
230     RTC_LOG(LS_ERROR) << "Frame #" << num_read_frames_
231                       << ": negative timestamp";
232     return absl::nullopt;
233   }
234 
235   return header;
236 }
237 
238 }  // namespace webrtc
239