FastLED 3.10.8
Loading...
Searching...
No Matches

◆ parseMp4()

Mp4TrackInfo fl::parseMp4 ( fl::span< const fl::u8 > data,
fl::string * error )

Definition at line 107 of file mp4_parser.cpp.hpp.

107 {
108 Mp4TrackInfo info;
109
110 if (data.size() < 8) {
111 if (error) *error = "Data too small for MP4";
112 return info;
113 }
114
115 // Find moov box at top level
116 fl::size moovPos = findBox(data, 0, data.size(), "moov");
117 if (moovPos == fl::size(-1)) {
118 if (error) *error = "No moov box found";
119 return info;
120 }
121
122 bool ok = true;
123 fl::u32 moovSize = readU32BE(data, moovPos, ok);
124 if (!ok) {
125 if (error) *error = "Invalid moov box size";
126 return info;
127 }
128 fl::size moovEnd = moovPos + moovSize;
129 if (moovEnd > data.size()) moovEnd = data.size();
130 fl::size moovBody = moovPos + 8;
131
132 // Find trak box inside moov
133 fl::size trakPos = findBox(data, moovBody, moovEnd, "trak");
134 if (trakPos == fl::size(-1)) {
135 if (error) *error = "No trak box found";
136 return info;
137 }
138
139 fl::u32 trakSize = readU32BE(data, trakPos, ok);
140 if (!ok) {
141 if (error) *error = "Invalid trak box size";
142 return info;
143 }
144 fl::size trakEnd = trakPos + trakSize;
145 if (trakEnd > moovEnd) trakEnd = moovEnd;
146 fl::size trakBody = trakPos + 8;
147
148 // Find mdia box inside trak
149 fl::size mdiaPos = findBox(data, trakBody, trakEnd, "mdia");
150 if (mdiaPos == fl::size(-1)) {
151 if (error) *error = "No mdia box found";
152 return info;
153 }
154
155 fl::u32 mdiaSize = readU32BE(data, mdiaPos, ok);
156 if (!ok) {
157 if (error) *error = "Invalid mdia box size";
158 return info;
159 }
160 fl::size mdiaEnd = mdiaPos + mdiaSize;
161 if (mdiaEnd > trakEnd) mdiaEnd = trakEnd;
162 fl::size mdiaBody = mdiaPos + 8;
163
164 // Find minf box inside mdia
165 fl::size minfPos = findBox(data, mdiaBody, mdiaEnd, "minf");
166 if (minfPos == fl::size(-1)) {
167 if (error) *error = "No minf box found";
168 return info;
169 }
170
171 fl::u32 minfSize = readU32BE(data, minfPos, ok);
172 if (!ok) {
173 if (error) *error = "Invalid minf box size";
174 return info;
175 }
176 fl::size minfEnd = minfPos + minfSize;
177 if (minfEnd > mdiaEnd) minfEnd = mdiaEnd;
178 fl::size minfBody = minfPos + 8;
179
180 // Find stbl box inside minf
181 fl::size stblPos = findBox(data, minfBody, minfEnd, "stbl");
182 if (stblPos == fl::size(-1)) {
183 if (error) *error = "No stbl box found";
184 return info;
185 }
186
187 fl::u32 stblSize = readU32BE(data, stblPos, ok);
188 if (!ok) {
189 if (error) *error = "Invalid stbl box size";
190 return info;
191 }
192 fl::size stblEnd = stblPos + stblSize;
193 if (stblEnd > minfEnd) stblEnd = minfEnd;
194 fl::size stblBody = stblPos + 8;
195
196 // Find stsd box inside stbl
197 fl::size stsdPos = findBox(data, stblBody, stblEnd, "stsd");
198 if (stsdPos == fl::size(-1)) {
199 if (error) *error = "No stsd box found";
200 return info;
201 }
202
203 fl::u32 stsdSize = readU32BE(data, stsdPos, ok);
204 if (!ok) {
205 if (error) *error = "Invalid stsd box size";
206 return info;
207 }
208 fl::size stsdEnd = stsdPos + stsdSize;
209 if (stsdEnd > stblEnd) stsdEnd = stblEnd;
210
211 // stsd is a full box: 8 byte header + 4 byte version/flags + 4 byte entry_count
212 fl::size stsdBody = stsdPos + 8 + 4 + 4;
213 if (stsdBody > stsdEnd) {
214 if (error) *error = "stsd box too small";
215 return info;
216 }
217
218 // Look for avc1 sample entry inside stsd
219 fl::size avc1Pos = findBox(data, stsdBody, stsdEnd, "avc1");
220 if (avc1Pos == fl::size(-1)) {
221 if (error) *error = "No avc1 sample entry found (not H.264)";
222 return info;
223 }
224
225 fl::u32 avc1Size = readU32BE(data, avc1Pos, ok);
226 if (!ok) {
227 if (error) *error = "Invalid avc1 box size";
228 return info;
229 }
230 fl::size avc1End = avc1Pos + avc1Size;
231 if (avc1End > stsdEnd) avc1End = stsdEnd;
232
233 // avc1 sample entry layout:
234 // 8 bytes: box header (size + "avc1")
235 // 6 bytes: reserved
236 // 2 bytes: data_reference_index
237 // 2 bytes: pre_defined
238 // 2 bytes: reserved
239 // 12 bytes: pre_defined[3]
240 // 2 bytes: width
241 // 2 bytes: height
242 // ... then sub-boxes including avcC
243 fl::size avc1Body = avc1Pos + 8 + 6 + 2 + 2 + 2 + 12;
244 if (avc1Body + 4 > avc1End) {
245 if (error) *error = "avc1 box too small for dimensions";
246 return info;
247 }
248
249 info.width = readU16BE(data, avc1Body, ok);
250 info.height = readU16BE(data, avc1Body + 2, ok);
251 if (!ok) {
252 if (error) *error = "Failed to read dimensions from avc1";
253 return info;
254 }
255
256 // Skip to sub-boxes: avc1Body + 4 (width/height) + 4 (horiz res) + 4 (vert res) +
257 // 4 (reserved) + 2 (frame_count) + 32 (compressor_name) + 2 (depth) + 2 (pre_defined)
258 fl::size subBoxStart = avc1Body + 4 + 4 + 4 + 4 + 2 + 32 + 2 + 2;
259
260 // Find avcC box inside avc1
261 fl::size avcCPos = findBox(data, subBoxStart, avc1End, "avcC");
262 if (avcCPos == fl::size(-1)) {
263 if (error) *error = "No avcC box found inside avc1";
264 return info;
265 }
266
267 fl::u32 avcCSize = readU32BE(data, avcCPos, ok);
268 if (!ok) {
269 if (error) *error = "Invalid avcC box size";
270 return info;
271 }
272 fl::size avcCEnd = avcCPos + avcCSize;
273 if (avcCEnd > avc1End) avcCEnd = avc1End;
274
275 if (!parseAvcC(data, avcCPos, avcCEnd, info)) {
276 if (error) *error = "Failed to parse avcC configuration record";
277 return info;
278 }
279
280 info.isValid = true;
281 return info;
282}
constexpr fl::size size() const FL_NO_EXCEPT
Definition span.h:483
fl::u32 readU32BE(fl::span< const fl::u8 > data, fl::size offset, bool &ok) FL_NO_EXCEPT
fl::size findBox(fl::span< const fl::u8 > data, fl::size start, fl::size end, const char *type) FL_NO_EXCEPT
fl::u16 readU16BE(fl::span< const fl::u8 > data, fl::size offset, bool &ok) FL_NO_EXCEPT
bool parseAvcC(fl::span< const fl::u8 > data, fl::size offset, fl::size boxEnd, Mp4TrackInfo &info) FL_NO_EXCEPT

References FL_NO_EXCEPT, fl::Mp4TrackInfo::height, fl::Mp4TrackInfo::isValid, and fl::Mp4TrackInfo::width.

Referenced by fl::H264::parseH264Info().

+ Here is the caller graph for this function: