110 if (data.size() < 8) {
111 if (error) *error =
"Data too small for MP4";
116 fl::size moovPos = findBox(data, 0, data.size(),
"moov");
117 if (moovPos == fl::size(-1)) {
118 if (error) *error =
"No moov box found";
123 fl::u32 moovSize = readU32BE(data, moovPos, ok);
125 if (error) *error =
"Invalid moov box size";
128 fl::size moovEnd = moovPos + moovSize;
129 if (moovEnd > data.size()) moovEnd = data.size();
130 fl::size moovBody = moovPos + 8;
133 fl::size trakPos = findBox(data, moovBody, moovEnd,
"trak");
134 if (trakPos == fl::size(-1)) {
135 if (error) *error =
"No trak box found";
139 fl::u32 trakSize = readU32BE(data, trakPos, ok);
141 if (error) *error =
"Invalid trak box size";
144 fl::size trakEnd = trakPos + trakSize;
145 if (trakEnd > moovEnd) trakEnd = moovEnd;
146 fl::size trakBody = trakPos + 8;
149 fl::size mdiaPos = findBox(data, trakBody, trakEnd,
"mdia");
150 if (mdiaPos == fl::size(-1)) {
151 if (error) *error =
"No mdia box found";
155 fl::u32 mdiaSize = readU32BE(data, mdiaPos, ok);
157 if (error) *error =
"Invalid mdia box size";
160 fl::size mdiaEnd = mdiaPos + mdiaSize;
161 if (mdiaEnd > trakEnd) mdiaEnd = trakEnd;
162 fl::size mdiaBody = mdiaPos + 8;
165 fl::size minfPos = findBox(data, mdiaBody, mdiaEnd,
"minf");
166 if (minfPos == fl::size(-1)) {
167 if (error) *error =
"No minf box found";
171 fl::u32 minfSize = readU32BE(data, minfPos, ok);
173 if (error) *error =
"Invalid minf box size";
176 fl::size minfEnd = minfPos + minfSize;
177 if (minfEnd > mdiaEnd) minfEnd = mdiaEnd;
178 fl::size minfBody = minfPos + 8;
181 fl::size stblPos = findBox(data, minfBody, minfEnd,
"stbl");
182 if (stblPos == fl::size(-1)) {
183 if (error) *error =
"No stbl box found";
187 fl::u32 stblSize = readU32BE(data, stblPos, ok);
189 if (error) *error =
"Invalid stbl box size";
192 fl::size stblEnd = stblPos + stblSize;
193 if (stblEnd > minfEnd) stblEnd = minfEnd;
194 fl::size stblBody = stblPos + 8;
197 fl::size stsdPos = findBox(data, stblBody, stblEnd,
"stsd");
198 if (stsdPos == fl::size(-1)) {
199 if (error) *error =
"No stsd box found";
203 fl::u32 stsdSize = readU32BE(data, stsdPos, ok);
205 if (error) *error =
"Invalid stsd box size";
208 fl::size stsdEnd = stsdPos + stsdSize;
209 if (stsdEnd > stblEnd) stsdEnd = stblEnd;
212 fl::size stsdBody = stsdPos + 8 + 4 + 4;
213 if (stsdBody > stsdEnd) {
214 if (error) *error =
"stsd box too small";
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)";
225 fl::u32 avc1Size = readU32BE(data, avc1Pos, ok);
227 if (error) *error =
"Invalid avc1 box size";
230 fl::size avc1End = avc1Pos + avc1Size;
231 if (avc1End > stsdEnd) avc1End = stsdEnd;
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";
249 info.
width = readU16BE(data, avc1Body, ok);
250 info.
height = readU16BE(data, avc1Body + 2, ok);
252 if (error) *error =
"Failed to read dimensions from avc1";
258 fl::size subBoxStart = avc1Body + 4 + 4 + 4 + 4 + 2 + 32 + 2 + 2;
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";
267 fl::u32 avcCSize = readU32BE(data, avcCPos, ok);
269 if (error) *error =
"Invalid avcC box size";
272 fl::size avcCEnd = avcCPos + avcCSize;
273 if (avcCEnd > avc1End) avcCEnd = avc1End;
275 if (!parseAvcC(data, avcCPos, avcCEnd, info)) {
276 if (error) *error =
"Failed to parse avcC configuration record";
289 if (!track.isValid) {
290 if (error) *error =
"Invalid track info";
294 fl::u8 nalLenSize = track.lengthSizeMinusOne + 1;
297 for (
const auto& sps : track.sps) {
302 for (fl::size j = 0; j < sps.size(); j++) {
308 for (
const auto& pps : track.pps) {
313 for (fl::size j = 0; j < pps.size(); j++) {
319 fl::size mdatPos = fl::size(-1);
322 while (
pos + 8 <= data.size()) {
324 fl::u32 boxSize = readU32BE(data,
pos, ok);
325 if (!ok || boxSize < 8)
break;
326 if (boxIs(data,
pos + 4,
"mdat")) {
334 if (mdatPos == fl::size(-1)) {
335 if (error) *error =
"No mdat box found";
340 fl::u32 mdatSize = readU32BE(data, mdatPos, ok);
342 if (error) *error =
"Invalid mdat box size";
346 fl::size mdatBody = mdatPos + 8;
347 fl::size mdatEnd = mdatPos + mdatSize;
348 if (mdatEnd > data.size()) mdatEnd = data.size();
350 fl::size
pos = mdatBody;
351 while (
pos + nalLenSize <= mdatEnd) {
353 for (
fl::u8 k = 0; k < nalLenSize; k++) {
354 nalLen = (nalLen << 8) | data[
pos + k];
358 if (
pos + nalLen > mdatEnd)
break;
365 for (fl::u32 j = 0; j < nalLen; j++) {