@audio/decode-aac 1.0.2 → 1.1.0
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/decode-aac.js +109 -4
- package/package.json +2 -1
- package/src/aac.wasm.cjs +0 -0
package/decode-aac.js
CHANGED
|
@@ -61,6 +61,9 @@ class AACDecoder {
|
|
|
61
61
|
this._ptr = 0
|
|
62
62
|
this._cap = 0
|
|
63
63
|
this._left = null
|
|
64
|
+
this._m4a = null // { sizes: number[], idx: number } — M4A streaming state
|
|
65
|
+
this._accum = null // Uint8Array[] — M4A header accumulator
|
|
66
|
+
this._accumLen = 0
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
decode(data) {
|
|
@@ -69,15 +72,37 @@ class AACDecoder {
|
|
|
69
72
|
|
|
70
73
|
let buf = data instanceof Uint8Array ? data : new Uint8Array(data)
|
|
71
74
|
|
|
72
|
-
//
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
+
// M4A streming phase 2: extract frames by known sizes
|
|
76
|
+
if (this._m4a) return this._feedM4AData(buf)
|
|
77
|
+
|
|
78
|
+
// M4A accumulating: waiting for moov + mdat header
|
|
79
|
+
if (this._accum) {
|
|
80
|
+
this._accum.push(buf)
|
|
81
|
+
this._accumLen += buf.length
|
|
82
|
+
return this._tryM4AInit()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ADTS mode (already initialized)
|
|
86
|
+
if (this.h) return this._decodeADTS(buf)
|
|
87
|
+
|
|
88
|
+
// First call: detect format
|
|
89
|
+
if (buf.length > 8 && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) {
|
|
90
|
+
this._accum = [buf]
|
|
91
|
+
this._accumLen = buf.length
|
|
92
|
+
return this._tryM4AInit()
|
|
93
|
+
}
|
|
75
94
|
|
|
76
95
|
return this._decodeADTS(buf)
|
|
77
96
|
}
|
|
78
97
|
|
|
79
98
|
flush() {
|
|
80
|
-
if (this.
|
|
99
|
+
if (this._accum?.length) {
|
|
100
|
+
// M4A moov-last: one-shot decode on accumulated data
|
|
101
|
+
let buf = this._catAccum()
|
|
102
|
+
this._accum = null; this._accumLen = 0
|
|
103
|
+
return this._decodeM4A(buf)
|
|
104
|
+
}
|
|
105
|
+
this._left = null
|
|
81
106
|
return EMPTY
|
|
82
107
|
}
|
|
83
108
|
|
|
@@ -94,6 +119,86 @@ class AACDecoder {
|
|
|
94
119
|
this._ptr = 0
|
|
95
120
|
this._cap = 0
|
|
96
121
|
}
|
|
122
|
+
this._accum = null; this._accumLen = 0
|
|
123
|
+
this._m4a = null; this._left = null
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
_catAccum() {
|
|
127
|
+
if (this._accum.length === 1) return this._accum[0]
|
|
128
|
+
let buf = new Uint8Array(this._accumLen), off = 0
|
|
129
|
+
for (let c of this._accum) { buf.set(c, off); off += c.length }
|
|
130
|
+
return buf
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
_tryM4AInit() {
|
|
134
|
+
let buf = this._catAccum()
|
|
135
|
+
let asc = null, stsz = null, stco = null, stsc = null
|
|
136
|
+
let mdatOff = 0, mdatLen = 0
|
|
137
|
+
|
|
138
|
+
parseBoxes(buf, 0, buf.length, (type, data, off) => {
|
|
139
|
+
if (type === 'esds') asc = parseEsds(data)
|
|
140
|
+
else if (type === 'stsz') stsz = parseStsz(data)
|
|
141
|
+
else if (type === 'stco') stco = parseStco(data)
|
|
142
|
+
else if (type === 'co64') stco = parseCo64(data)
|
|
143
|
+
else if (type === 'stsc') stsc = parseStsc(data)
|
|
144
|
+
else if (type === 'mdat') { mdatOff = off; mdatLen = data.length }
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
if (!asc) return EMPTY // moov not found yet
|
|
148
|
+
|
|
149
|
+
// Init WASM decoder with ASC
|
|
150
|
+
let m = this.m, h = m._aac_create()
|
|
151
|
+
let srP = m._aac_sr_ptr(), chP = m._aac_ch_ptr()
|
|
152
|
+
let ptr = this._alloc(asc.length)
|
|
153
|
+
m.HEAPU8.set(asc, ptr)
|
|
154
|
+
let err = m._aac_init2(h, ptr, asc.length, srP, chP)
|
|
155
|
+
if (err < 0) { m._aac_close(h); throw Error('M4A init failed (code ' + err + ')') }
|
|
156
|
+
this.sr = m.getValue(srP, 'i32')
|
|
157
|
+
this.ch = m.getValue(chP, 'i8')
|
|
158
|
+
if (!this.ch) { m._aac_close(h); throw Error('M4A init: no channels in ASC') }
|
|
159
|
+
this.h = h
|
|
160
|
+
|
|
161
|
+
// Extract available frames using stco (correct absolute offsets)
|
|
162
|
+
let frames = (stsz && stco)
|
|
163
|
+
? extractFrames(buf, stsz, stco, stsc)
|
|
164
|
+
: mdatLen ? scanMdat(buf, mdatOff, mdatLen) : []
|
|
165
|
+
|
|
166
|
+
let decodedIdx = frames.length
|
|
167
|
+
this._m4a = { sizes: stsz || [], idx: decodedIdx }
|
|
168
|
+
this._accum = null; this._accumLen = 0
|
|
169
|
+
|
|
170
|
+
// For streaming: compute leftover mdat data after extracted frames
|
|
171
|
+
if (stsz && decodedIdx < stsz.length && decodedIdx > 0 && stco?.length) {
|
|
172
|
+
let consumed = 0
|
|
173
|
+
for (let i = 0; i < decodedIdx; i++) consumed += stsz[i]
|
|
174
|
+
let dataStart = stco[0] + consumed
|
|
175
|
+
if (dataStart < buf.length) this._left = buf.subarray(dataStart).slice()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!frames.length) return EMPTY
|
|
179
|
+
return this._feedFrames(frames)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
_feedM4AData(buf) {
|
|
183
|
+
let st = this._m4a
|
|
184
|
+
if (this._left) {
|
|
185
|
+
let merged = new Uint8Array(this._left.length + buf.length)
|
|
186
|
+
merged.set(this._left); merged.set(buf, this._left.length)
|
|
187
|
+
buf = merged; this._left = null
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let frames = [], pos = 0
|
|
191
|
+
while (st.idx < st.sizes.length) {
|
|
192
|
+
let sz = st.sizes[st.idx]
|
|
193
|
+
if (pos + sz > buf.length) break
|
|
194
|
+
frames.push(buf.subarray(pos, pos + sz))
|
|
195
|
+
pos += sz
|
|
196
|
+
st.idx++
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (pos < buf.length) this._left = buf.subarray(pos).slice()
|
|
200
|
+
if (!frames.length) return EMPTY
|
|
201
|
+
return this._feedFrames(frames)
|
|
97
202
|
}
|
|
98
203
|
|
|
99
204
|
_alloc(len) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@audio/decode-aac",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Decode AAC/M4A audio via FAAD2 WASM",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "decode-aac.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "bash build.sh",
|
|
17
|
+
"prepack": "npm run build",
|
|
17
18
|
"test": "node test.js"
|
|
18
19
|
},
|
|
19
20
|
"files": [
|
package/src/aac.wasm.cjs
CHANGED
|
Binary file
|