FastLED 3.9.15
Loading...
Searching...
No Matches

◆ parseMp4()

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

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

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

References fl::Mp4TrackInfo::height, fl::Mp4TrackInfo::isValid, fl::span< T, Extent >::size(), and fl::Mp4TrackInfo::width.

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

+ Here is the call graph for this function:
+ Here is the caller graph for this function: