@@ -18,7 +18,7 @@ class M4AAudioDemuxer {
18
18
*/
19
19
struct Frame {
20
20
Codec codec;
21
- const char * mime = nullptr ;;
21
+ const char * mime = nullptr ;
22
22
const uint8_t * data;
23
23
size_t size;
24
24
uint64_t timestamp;
@@ -45,16 +45,18 @@ class M4AAudioDemuxer {
45
45
46
46
void setCodec (M4AAudioDemuxer::Codec c) { codec = c; }
47
47
48
- void setCallback (FrameCallback cb) {
49
- callback = cb;
50
- }
48
+ void setCallback (FrameCallback cb) { callback = cb; }
51
49
52
50
void setReference (void * r) { ref = r; }
53
51
54
52
void write (const uint8_t * data, size_t len, bool is_final) {
55
53
// Resize buffer to the current sample size
56
54
size_t currentSize = currentSampleSize ();
57
55
resize (currentSize);
56
+ if (currentSize == 0 ) {
57
+ LOGE (" No sample size defined, cannot write data" );
58
+ return ;
59
+ }
58
60
59
61
// / fill buffer up to the current sample size
60
62
for (int j = 0 ; j < len; j++) {
@@ -97,16 +99,15 @@ class M4AAudioDemuxer {
97
99
frame.timestamp = 0 ; // TODO: timestamp
98
100
switch (codec) {
99
101
case Codec::AAC: {
100
- uint8_t adts[7 ];
101
- writeAdtsHeader (adts, aacProfile, sampleRateIdx, channelCfg,
102
- frameSize);
103
102
uint8_t out[frameSize + 7 ];
104
- memcpy (out, adts, 7 );
103
+ writeAdtsHeader (out, aacProfile, sampleRateIdx, channelCfg,
104
+ frameSize);
105
105
memcpy (out + 7 , buffer.data (), frameSize);
106
106
frame.data = out;
107
107
frame.size = sizeof (out);
108
108
frame.mime = " audio/aac" ;
109
- callback (frame, ref);
109
+ if (callback) callback (frame, ref);
110
+ else LOGE (" No callback defined for audio frame extraction" );
110
111
return ;
111
112
}
112
113
case Codec::ALAC:
@@ -120,6 +121,7 @@ class M4AAudioDemuxer {
120
121
break ;
121
122
}
122
123
if (callback) callback (frame, ref);
124
+ else LOGE (" No callback defined for audio frame extraction" );
123
125
}
124
126
125
127
void resize (size_t newSize) {
@@ -151,24 +153,24 @@ class M4AAudioDemuxer {
151
153
152
154
using FrameCallback = std::function<void (const Frame&, void * ref)>;
153
155
154
- M4AAudioDemuxer (FrameCallback cb) : callback(cb ) {
156
+ M4AAudioDemuxer () {
155
157
parser.setReference (this );
156
158
parser.setCallback (boxCallback);
157
159
158
- sampleExtractor.setReference (this );
159
- sampleExtractor.setCallback (callback);
160
-
161
160
// incremental data callback
162
161
parser.setDataCallback (boxDataCallback);
163
162
164
- // Add more as needed...
165
- // parser.begin();
163
+ }
164
+
165
+ void setCallback (FrameCallback cb) {
166
+ sampleExtractor.setReference (ref);
167
+ sampleExtractor.setCallback (cb);
166
168
}
167
169
168
170
void begin () {
169
171
codec = Codec::Unknown;
170
172
alacMagicCookie.clear ();
171
- resize (1024 );
173
+ resize (default_size );
172
174
173
175
// When codec/sampleSizes/callback/ref change, update the extractor:
174
176
parser.begin ();
@@ -181,24 +183,23 @@ class M4AAudioDemuxer {
181
183
182
184
Vector<uint8_t >& getAlacMagicCookie () { return alacMagicCookie; }
183
185
184
- void setReference (void * ref) {
185
- this ->ref = ref;
186
- }
186
+ void setReference (void * ref) { this ->ref = ref; }
187
187
188
188
void resize (int size) {
189
+ default_size = size;
189
190
if (buffer.size () < size) {
190
191
buffer.resize (size);
191
192
}
192
193
}
193
194
194
195
protected:
195
- FrameCallback callback;
196
196
MP4ParserIncremental parser;
197
197
Codec codec = Codec::Unknown;
198
198
Vector<uint8_t > alacMagicCookie;
199
199
SingleBuffer<uint8_t > buffer; // buffer to collect incremental data
200
200
SampleExtractor sampleExtractor;
201
201
void * ref = nullptr ;
202
+ size_t default_size = 1024 ;
202
203
203
204
bool isRelevantBox (const char * type) {
204
205
// Check if the box is relevant for audio demuxing
@@ -208,10 +209,17 @@ class M4AAudioDemuxer {
208
209
// / Just prints the box name and the number of bytes received
209
210
static void boxCallback (MP4Parser::Box& box, void * ref) {
210
211
M4AAudioDemuxer& self = *static_cast <M4AAudioDemuxer*>(ref);
211
- if (self.isRelevantBox (box.type )) {
212
- self.resize (box.size );
213
- self.buffer .clear ();
214
- if (box.data_size > 0 ) self.buffer .writeArray (box.data , box.data_size );
212
+ bool is_relevant = self.isRelevantBox (box.type );
213
+ if (is_relevant) {
214
+ LOGI (" Box: %s, size: %u bytes" , box.type , (unsigned ) box.size );
215
+ if (box.data_size == 0 ) {
216
+ // setup for increemental processing
217
+ self.resize (box.size );
218
+ self.buffer .clear ();
219
+ } else {
220
+ // we have the complete box data
221
+ self.processBox (box);
222
+ }
215
223
}
216
224
}
217
225
@@ -221,31 +229,44 @@ class M4AAudioDemuxer {
221
229
222
230
// mdat must not be buffered
223
231
if (StrView (box.type ) == " mdat" ) {
224
- self.sampleExtractor .setCodec (self.codec );
232
+ LOGI (" *Box: %s, size: %u bytes" , box.type , (unsigned ) len);
233
+ // self.sampleExtractor.setCodec(self.codec);
225
234
self.sampleExtractor .write (data, len, is_final);
226
235
return ;
227
236
}
228
237
229
238
// only process relevant boxes
230
- if (!self.isRelevantBox (box.type ) == false ) return ;
239
+ if (!self.isRelevantBox (box.type )) return ;
240
+
241
+ LOGI (" *Box: %s, size: %u bytes" , box.type , (unsigned ) len);
231
242
232
243
// others fill buffer incrementally
233
244
if (len > 0 ) {
234
- self.buffer .writeArray (data, len);
245
+ size_t written = self.buffer .writeArray (data, len);
246
+ if (written != len) {
247
+ LOGE (" Failed to write all data to buffer, written: %zu, expected: %zu" ,
248
+ written, len);
249
+ }
235
250
}
236
251
237
252
// on last chunk, call the specific box handler
238
253
if (is_final) {
239
254
MP4Parser::Box complete_box = box;
240
255
complete_box.data = self.buffer .data ();
241
256
complete_box.data_size = self.buffer .size ();
242
- if (StrView (box.type ) == " stsd" ) {
243
- self.onStsd (complete_box);
244
- } else if (StrView (box.type ) == " stsz" ) {
245
- self.onStsz (complete_box);
246
- } else if (StrView (box.type ) == " stco" ) {
247
- self.onStco (complete_box);
248
- }
257
+ self.processBox (complete_box);
258
+ // The buffer might be quite large, so we resize it to the default size
259
+ self.resize (self.default_size );
260
+ }
261
+ }
262
+
263
+ void processBox (MP4Parser::Box& box) {
264
+ if (StrView (box.type ) == " stsd" ) {
265
+ onStsd (box);
266
+ } else if (StrView (box.type ) == " stsz" ) {
267
+ onStsz (box);
268
+ } else if (StrView (box.type ) == " stco" ) {
269
+ onStco (box);
249
270
}
250
271
}
251
272
@@ -254,7 +275,8 @@ class M4AAudioDemuxer {
254
275
}
255
276
256
277
void onStsd (const MP4Parser::Box& box) {
257
- const uint8_t * data = box.data ;
278
+ LOGI (" onStsd: %s, size: %zu bytes" , box.type , box.data_size );
279
+ const uint8_t * data = box.data ; // skip version/flags ?
258
280
size_t size = box.data_size ;
259
281
if (size < 8 ) return ;
260
282
uint32_t entryCount = readU32 (data + 4 );
@@ -268,13 +290,22 @@ class M4AAudioDemuxer {
268
290
size_t childrenEnd = cursor + entrySize;
269
291
codec = Codec::Unknown;
270
292
if (StrView (entryType) == " mp4a" ) {
293
+ LOGI (" -> AAC" )
271
294
codec = Codec::AAC;
295
+ sampleExtractor.setCodec (codec);
272
296
onStsdHandleMp4a (data, size, childrenStart, childrenEnd);
297
+ break ;
273
298
} else if (StrView (entryType) == " .mp3" ) {
299
+ LOGI (" -> MP3" )
274
300
codec = Codec::MP3;
301
+ sampleExtractor.setCodec (codec);
302
+ break ;
275
303
} else if (StrView (entryType) == " alac" ) {
304
+ LOGI (" -> ALAC" )
276
305
codec = Codec::ALAC;
306
+ sampleExtractor.setCodec (codec);
277
307
onStsdHandleAlac (data, size, childrenStart, childrenEnd);
308
+ break ;
278
309
}
279
310
cursor += entrySize;
280
311
}
@@ -336,8 +367,9 @@ class M4AAudioDemuxer {
336
367
}
337
368
338
369
void onStsz (MP4Parser::Box& box) {
370
+ LOGI (" onStsz: %s, size: %zu bytes" , box.type , box.data_size );
339
371
// Parse stsz box and fill sampleSizes
340
- const uint8_t * data = box.data ;
372
+ const uint8_t * data = box.data + 4 ; // skip version/flags
341
373
size_t size = box.data_size ;
342
374
if (size < 12 ) return ;
343
375
uint32_t sampleSize = readU32 (data);
@@ -346,25 +378,29 @@ class M4AAudioDemuxer {
346
378
Vector<size_t >& sampleSizes = sampleExtractor.getSampleSizes ();
347
379
if (sampleSize == 0 ) {
348
380
if (size < 12 + 4 * sampleCount) return ;
381
+ LOGI (" -> Sample Sizes Count: %u" , sampleCount);
382
+ sampleSizes.resize (sampleCount);
349
383
for (uint32_t i = 0 ; i < sampleCount; ++i) {
350
- sampleSizes. push_back ( readU32 (data + 12 + i * 4 ) );
384
+ sampleSizes[i] = readU32 (data + 12 + i * 4 );
351
385
}
352
386
} else {
353
387
sampleSizes.assign (sampleCount, sampleSize);
354
388
}
355
389
}
356
390
357
391
void onStco (MP4Parser::Box& box) {
392
+ LOGI (" onStco: %s, size: %zu bytes" , box.type , box.data_size );
358
393
// Parse stco box and fill chunkOffsets
359
- const uint8_t * data = box.data ;
394
+ const uint8_t * data = box.data + 4 ; // skip version/flags
360
395
size_t size = box.data_size ;
361
396
if (size < 4 ) return ;
362
397
uint32_t entryCount = readU32 (data);
363
398
Vector<size_t >& chunkOffsets = sampleExtractor.getChunkOffsets ();
364
- chunkOffsets.clear ();
365
399
if (size < 4 + 4 * entryCount) return ;
400
+ chunkOffsets.resize (entryCount);
401
+ LOGI (" -> Chunk offsets count: %u" , entryCount);
366
402
for (uint32_t i = 0 ; i < entryCount; ++i) {
367
- chunkOffsets. push_back ( readU32 (data + 4 + i * 4 ) );
403
+ chunkOffsets[i] = readU32 (data + 4 + i * 4 );
368
404
}
369
405
}
370
406
};
0 commit comments