@audio/decode-mp4 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/decode-mp4.js +15 -6
- package/package.json +22 -3
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @audio/decode-mp4
|
|
2
2
|
|
|
3
3
|
Decode the audio track of MP4, MOV, M4A, M4V and 3GP files to PCM float samples.<br>
|
|
4
|
-
A pure-JS ISO BMFF demuxer that skips the video track and routes the audio to the matching codec package, loaded on demand.
|
|
4
|
+
A pure-JS ISO BMFF demuxer that skips the video track and routes the audio (AAC, ALAC, MP3, FLAC, Opus, AC-3, DTS, AMR, PCM) to the matching codec package, loaded on demand.
|
|
5
5
|
|
|
6
6
|
[](https://npmjs.org/package/@audio/decode-mp4/)
|
|
7
7
|
|
|
@@ -29,8 +29,11 @@ dec.free()
|
|
|
29
29
|
| `samr`, `sawb` | AMR-NB, AMR-WB | [@audio/decode-amr](../decode-amr) |
|
|
30
30
|
| `sowt`, `twos`, `in24`, `in32`, `fl32`, `fl64`, `lpcm`, `ipcm`, `fpcm`, `raw `, `NONE` | PCM 8–32 bit int, 32/64 bit float, either endianness | built in |
|
|
31
31
|
| `ulaw`, `alaw` | G.711 | built in |
|
|
32
|
+
| `ac-3`, `mp4a` (0xA5) | AC-3 | [@audio/decode-ac3](../decode-ac3) |
|
|
33
|
+
| `dtsc`, `dtsh`, `dtsl`, `dtse`, `mp4a` (0xA9) | DTS (core) | [@audio/decode-dts](../decode-dts) |
|
|
34
|
+
| `ec-3`, `mp4a` (0xA6) | E-AC-3 (Dolby Digital Plus) | [@audio/decode-eac3](../decode-eac3) |
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
TrueHD tracks throw an error naming the codec. Fragmented MP4 (`moof`) is not supported. QuickTime sound descriptions v0, v1 and v2 are handled, including `wave`-wrapped configs and `enda` endianness flags. When `moov` follows `mdat` (typical of camera and QuickTime output) the file is buffered until the header arrives.
|
|
34
37
|
|
|
35
38
|
Codec packages are imported dynamically, which is unavailable inside an AudioWorklet — decode in the main thread or a Worker.
|
|
36
39
|
|
package/decode-mp4.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MP4 / MOV / M4A / M4V / 3GP audio decoder — ISO BMFF demuxer that routes the audio track to a codec:
|
|
3
3
|
* AAC, ALAC → @audio/decode-aac · MP3 → @audio/decode-mp3 · FLAC → @audio/decode-flac
|
|
4
|
-
* Opus → @audio/decode-opus/core · AMR → @audio/decode-amr ·
|
|
4
|
+
* Opus → @audio/decode-opus/core · AMR → @audio/decode-amr · AC-3 → @audio/decode-ac3 · E-AC-3 → @audio/decode-eac3
|
|
5
|
+
* DTS → @audio/decode-dts · PCM / µ-law / A-law inline.
|
|
5
6
|
*
|
|
6
7
|
* let { channelData, sampleRate } = await decode(mp4buf)
|
|
7
8
|
* let dec = await decoder(); let result = await dec.decode(chunk)
|
|
@@ -248,13 +249,17 @@ function advance(st) {
|
|
|
248
249
|
// ===== codec routing =====
|
|
249
250
|
|
|
250
251
|
const MP3_OTI = new Set([0x69, 0x6B]), AAC_OTI = new Set([0x40, 0x66, 0x67, 0x68])
|
|
251
|
-
const UNSUPPORTED = {
|
|
252
|
+
const UNSUPPORTED = { 0xE1: 'QCELP' }
|
|
253
|
+
const DTS_TYPES = new Set(['dtsc', 'dtsh', 'dtsl', 'dtse']) // DTS-HD variants carry a decodable core
|
|
252
254
|
|
|
253
255
|
async function createCodec({ entry, children }) {
|
|
254
256
|
let { type } = entry
|
|
255
257
|
if (type === 'mp4a') {
|
|
256
258
|
let { oti, dsi } = children.esds ? parseEsds(children.esds) : {}
|
|
257
|
-
if (MP3_OTI.has(oti)) return mp3
|
|
259
|
+
if (MP3_OTI.has(oti)) return frames(import('@audio/decode-mp3'))
|
|
260
|
+
if (oti === 0xA5) return frames(import('@audio/decode-ac3'))
|
|
261
|
+
if (oti === 0xA9) return frames(import('@audio/decode-dts'))
|
|
262
|
+
if (oti === 0xA6) return frames(import('@audio/decode-eac3'))
|
|
258
263
|
if (!oti || AAC_OTI.has(oti)) {
|
|
259
264
|
if (!dsi) throw Error('MP4 AAC track has no AudioSpecificConfig')
|
|
260
265
|
return aac({ asc: dsi })
|
|
@@ -265,7 +270,7 @@ async function createCodec({ entry, children }) {
|
|
|
265
270
|
if (!children.alac) throw Error('MP4 ALAC track has no magic cookie')
|
|
266
271
|
return aac({ alac: children.alac })
|
|
267
272
|
}
|
|
268
|
-
if (type === '.mp3') return mp3
|
|
273
|
+
if (type === '.mp3') return frames(import('@audio/decode-mp3'))
|
|
269
274
|
if (type === 'fLaC') {
|
|
270
275
|
if (!children.dfLa) throw Error('MP4 FLAC track has no dfLa box')
|
|
271
276
|
return flac(children.dfLa.subarray(4))
|
|
@@ -275,6 +280,9 @@ async function createCodec({ entry, children }) {
|
|
|
275
280
|
return opus(children.dOps)
|
|
276
281
|
}
|
|
277
282
|
if (type === 'samr' || type === 'sawb') return amr(type === 'sawb')
|
|
283
|
+
if (type === 'ac-3') return frames(import('@audio/decode-ac3'))
|
|
284
|
+
if (type === 'ec-3') return frames(import('@audio/decode-eac3'))
|
|
285
|
+
if (DTS_TYPES.has(type)) return frames(import('@audio/decode-dts'))
|
|
278
286
|
let fmt = pcmFormat(entry, children)
|
|
279
287
|
if (fmt) return pcm(fmt)
|
|
280
288
|
throw unsupported(UNSUPPORTED[type] || type)
|
|
@@ -316,8 +324,9 @@ async function aac(opts) {
|
|
|
316
324
|
return { feed: frames => dec.decode(frames), flush: () => dec.flush(), free: () => dec.free() }
|
|
317
325
|
}
|
|
318
326
|
|
|
319
|
-
|
|
320
|
-
|
|
327
|
+
// self-synchronizing frame streams (MP3, AC-3, DTS): the codec resyncs on concatenated samples
|
|
328
|
+
async function frames(load) {
|
|
329
|
+
let dec = await (await load).decoder()
|
|
321
330
|
return { feed: frames => dec.decode(concat(frames)), flush: () => dec.flush?.() ?? EMPTY, free: () => dec.free() }
|
|
322
331
|
}
|
|
323
332
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@audio/decode-mp4",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Decode the audio track of MP4, MOV, M4A, M4V and 3GP files (AAC, ALAC, MP3, FLAC, Opus, AMR, PCM) to PCM samples",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "decode-mp4.js",
|
|
@@ -28,10 +28,13 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@audio/decode-aac": "^1.5.0",
|
|
31
|
+
"@audio/decode-ac3": "^1.0.0",
|
|
31
32
|
"@audio/decode-amr": "^1.3.0",
|
|
33
|
+
"@audio/decode-dts": "^1.0.0",
|
|
32
34
|
"@audio/decode-flac": "^1.3.0",
|
|
33
35
|
"@audio/decode-mp3": "^1.3.0",
|
|
34
|
-
"@audio/decode-opus": "^1.3.0"
|
|
36
|
+
"@audio/decode-opus": "^1.3.0",
|
|
37
|
+
"@audio/decode-eac3": "^1.0.0"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
40
|
"tst": "^9.2.2"
|
|
@@ -39,7 +42,23 @@
|
|
|
39
42
|
"engines": {
|
|
40
43
|
"node": ">=18"
|
|
41
44
|
},
|
|
42
|
-
"keywords": [
|
|
45
|
+
"keywords": [
|
|
46
|
+
"mp4",
|
|
47
|
+
"mov",
|
|
48
|
+
"m4a",
|
|
49
|
+
"m4v",
|
|
50
|
+
"3gp",
|
|
51
|
+
"quicktime",
|
|
52
|
+
"isobmff",
|
|
53
|
+
"demux",
|
|
54
|
+
"video",
|
|
55
|
+
"audio",
|
|
56
|
+
"decode",
|
|
57
|
+
"decoder",
|
|
58
|
+
"aac",
|
|
59
|
+
"alac",
|
|
60
|
+
"pcm"
|
|
61
|
+
],
|
|
43
62
|
"license": "MIT",
|
|
44
63
|
"author": "audiojs",
|
|
45
64
|
"homepage": "https://github.com/audiojs/decode/tree/main/packages/decode-mp4",
|