Skip to content

Commit 5d8552d

Browse files
committed
Initial implementation of Spectral Band Replication for HE-AAC v1
1 parent 43e93d3 commit 5d8552d

15 files changed

+3395
-70
lines changed

src/adts_demuxer.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
var AV = require('av');
22
var tables = require('./tables');
33

4-
var ADTSDemuxer = AV.Demuxer.extend(function() {
5-
AV.Demuxer.register(this);
6-
7-
this.probe = function(stream) {
4+
class ADTSDemuxer extends AV.Demuxer {
5+
static probe(stream) {
86
var offset = stream.offset;
97

108
// attempt to find ADTS syncword
@@ -17,15 +15,15 @@ var ADTSDemuxer = AV.Demuxer.extend(function() {
1715

1816
stream.seek(offset);
1917
return false;
20-
};
18+
}
2119

22-
this.prototype.init = function() {
20+
init() {
2321
this.bitstream = new AV.Bitstream(this.stream);
24-
};
22+
}
2523

2624
// Reads an ADTS header
2725
// See http://wiki.multimedia.cx/index.php?title=ADTS
28-
this.readHeader = function(stream) {
26+
static readHeader(stream) {
2927
if (stream.read(12) !== 0xfff)
3028
throw new Error('Invalid ADTS header.');
3129

@@ -49,9 +47,9 @@ var ADTSDemuxer = AV.Demuxer.extend(function() {
4947
stream.advance(16);
5048

5149
return ret;
52-
};
50+
}
5351

54-
this.prototype.readChunk = function() {
52+
readChunk() {
5553
if (!this.sentHeader) {
5654
var offset = this.stream.offset;
5755
var header = ADTSDemuxer.readHeader(this.bitstream);
@@ -77,7 +75,9 @@ var ADTSDemuxer = AV.Demuxer.extend(function() {
7775
var buffer = this.stream.readSingleBuffer(this.stream.remainingBytes());
7876
this.emit('data', buffer);
7977
}
80-
};
81-
});
78+
}
79+
}
80+
81+
AV.Demuxer.register(ADTSDemuxer);
8282

8383
module.exports = ADTSDemuxer;

src/decoder.js

Lines changed: 105 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -25,37 +25,43 @@ var CPEElement = require('./cpe');
2525
var CCEElement = require('./cce');
2626
var FilterBank = require('./filter_bank');
2727
var tables = require('./tables');
28+
var FIL = require('./fil');
29+
var SBR = require('./sbr/sbr');
2830

29-
var AACDecoder = AV.Decoder.extend(function() {
30-
AV.Decoder.register('mp4a', this);
31-
AV.Decoder.register('aac ', this);
32-
33-
// AAC profiles
34-
const AOT_AAC_MAIN = 1, // no
35-
AOT_AAC_LC = 2, // yes
36-
AOT_AAC_LTP = 4, // no
37-
AOT_ESCAPE = 31;
38-
39-
// Channel configurations
40-
const CHANNEL_CONFIG_NONE = 0,
41-
CHANNEL_CONFIG_MONO = 1,
42-
CHANNEL_CONFIG_STEREO = 2,
43-
CHANNEL_CONFIG_STEREO_PLUS_CENTER = 3,
44-
CHANNEL_CONFIG_STEREO_PLUS_CENTER_PLUS_REAR_MONO = 4,
45-
CHANNEL_CONFIG_FIVE = 5,
46-
CHANNEL_CONFIG_FIVE_PLUS_ONE = 6,
47-
CHANNEL_CONFIG_SEVEN_PLUS_ONE = 8;
48-
49-
this.prototype.init = function() {
31+
// AAC profiles
32+
const AOT_AAC_MAIN = 1, // no
33+
AOT_AAC_LC = 2, // yes
34+
AOT_AAC_LTP = 4, // no
35+
AOT_ESCAPE = 31;
36+
37+
// Channel configurations
38+
const CHANNEL_CONFIG_NONE = 0,
39+
CHANNEL_CONFIG_MONO = 1,
40+
CHANNEL_CONFIG_STEREO = 2,
41+
CHANNEL_CONFIG_STEREO_PLUS_CENTER = 3,
42+
CHANNEL_CONFIG_STEREO_PLUS_CENTER_PLUS_REAR_MONO = 4,
43+
CHANNEL_CONFIG_FIVE = 5,
44+
CHANNEL_CONFIG_FIVE_PLUS_ONE = 6,
45+
CHANNEL_CONFIG_SEVEN_PLUS_ONE = 8;
46+
47+
const SCE_ELEMENT = 0,
48+
CPE_ELEMENT = 1,
49+
CCE_ELEMENT = 2,
50+
LFE_ELEMENT = 3,
51+
DSE_ELEMENT = 4,
52+
PCE_ELEMENT = 5,
53+
FIL_ELEMENT = 6,
54+
END_ELEMENT = 7;
55+
56+
class AACDecoder extends AV.Decoder {
57+
init() {
5058
this.format.floatingPoint = true;
5159
}
5260

53-
this.prototype.setCookie = function(buffer) {
54-
var data = AV.Stream.fromBuffer(buffer),
55-
stream = new AV.Bitstream(data);
61+
setCookie(buffer) {
62+
var stream = AV.Bitstream.fromBuffer(buffer);
5663

5764
this.config = {};
58-
5965
this.config.profile = stream.read(5);
6066
if (this.config.profile === AOT_ESCAPE)
6167
this.config.profile = 32 + stream.read(6);
@@ -75,6 +81,7 @@ var AACDecoder = AV.Decoder.extend(function() {
7581

7682
this.config.chanConfig = stream.read(4);
7783
this.format.channelsPerFrame = this.config.chanConfig; // sometimes m4a files encode this wrong
84+
this.format.sampleRate = this.config.sampleRate;
7885

7986
switch (this.config.profile) {
8087
case AOT_AAC_MAIN:
@@ -109,20 +116,31 @@ var AACDecoder = AV.Decoder.extend(function() {
109116
throw new Error('AAC profile ' + this.config.profile + ' not supported.');
110117
}
111118

119+
console.log(stream.available(10))
120+
if (stream.available(11)) {
121+
let type = stream.read(11);
122+
switch (type) {
123+
case 0x2B7:
124+
let profile = stream.read(5);
125+
if (profile === 5) {
126+
this.config.sbrPresent = stream.read(1);
127+
if (this.config.sbrPresent) {
128+
this.config.profile = profile;
129+
130+
let sampleIndex = stream.read(4);
131+
this.format.sampleRate = tables.SAMPLE_RATES[sampleIndex];
132+
console.log(this.config)
133+
}
134+
}
135+
break;
136+
}
137+
}
138+
112139
this.filter_bank = new FilterBank(false, this.config.chanConfig);
113-
};
114-
115-
const SCE_ELEMENT = 0,
116-
CPE_ELEMENT = 1,
117-
CCE_ELEMENT = 2,
118-
LFE_ELEMENT = 3,
119-
DSE_ELEMENT = 4,
120-
PCE_ELEMENT = 5,
121-
FIL_ELEMENT = 6,
122-
END_ELEMENT = 7;
123-
140+
}
141+
124142
// The main decoding function.
125-
this.prototype.readChunk = function() {
143+
readChunk() {
126144
var stream = this.bitstream;
127145

128146
// check if there is an ADTS header, and read it if so
@@ -132,7 +150,8 @@ var AACDecoder = AV.Decoder.extend(function() {
132150
this.cces = [];
133151
var elements = [],
134152
config = this.config,
135-
frameLength = config.frameLength,
153+
mult = config.sbrPresent ? 2 : 1,
154+
frameLength = mult * config.frameLength,
136155
elementType = null;
137156

138157
while ((elementType = stream.read(3)) !== END_ELEMENT) {
@@ -146,6 +165,7 @@ var AACDecoder = AV.Decoder.extend(function() {
146165
ics.id = id;
147166
elements.push(ics);
148167
ics.decode(stream, config, false);
168+
this.prev = ics;
149169
break;
150170

151171
// channel pair element
@@ -154,13 +174,15 @@ var AACDecoder = AV.Decoder.extend(function() {
154174
cpe.id = id;
155175
elements.push(cpe);
156176
cpe.decode(stream, config);
177+
this.prev = cpe;
157178
break;
158179

159180
// channel coupling element
160181
case CCE_ELEMENT:
161182
var cce = new CCEElement(this.config);
162183
this.cces.push(cce);
163184
cce.decode(stream, config);
185+
this.prev = null;
164186
break;
165187

166188
// data-stream element
@@ -176,20 +198,34 @@ var AACDecoder = AV.Decoder.extend(function() {
176198

177199
// skip for now...
178200
stream.advance(count * 8);
201+
this.prev = null;
179202
break;
180203

181204
// program configuration element
182205
case PCE_ELEMENT:
206+
this.prev = null;
183207
throw new Error("TODO: PCE_ELEMENT")
184208
break;
185209

186210
// filler element
187211
case FIL_ELEMENT:
188-
if (id === 15)
212+
if (id === 15) {
189213
id += stream.read(8) - 1;
190-
214+
}
215+
216+
id *= 8;
217+
var end = stream.offset() + id;
218+
219+
FIL.decode(stream, id, this.prev, this.config.sampleRate);
220+
221+
if (this.prev && this.prev.sbr) {
222+
this.sbrPresent = true;
223+
}
224+
225+
this.prev = null;
226+
191227
// skip for now...
192-
stream.advance(id * 8);
228+
stream.seek(end);
193229
break;
194230

195231
default:
@@ -200,6 +236,12 @@ var AACDecoder = AV.Decoder.extend(function() {
200236
stream.align();
201237
this.process(elements);
202238

239+
for (let element of elements) {
240+
if (element.sbr) {
241+
SBR.release(element.sbr);
242+
}
243+
}
244+
203245
// Interleave channels
204246
var data = this.data,
205247
channels = data.length,
@@ -213,14 +255,14 @@ var AACDecoder = AV.Decoder.extend(function() {
213255
}
214256

215257
return output;
216-
};
258+
}
217259

218-
this.prototype.process = function(elements) {
260+
process(elements) {
219261
var channels = this.config.chanConfig;
220262

221263
// if (channels === 1 && psPresent)
222264
// TODO: sbrPresent (2)
223-
var mult = 1;
265+
var mult = this.config.sbrPresent ? 2 : 1;
224266

225267
var len = mult * this.config.frameLength;
226268
var data = this.data = [];
@@ -245,9 +287,9 @@ var AACDecoder = AV.Decoder.extend(function() {
245287
throw new Error("Unknown element found.")
246288
}
247289
}
248-
};
290+
}
249291

250-
this.prototype.processSingle = function(element, channel) {
292+
processSingle(element, channel) {
251293
var profile = this.config.profile,
252294
info = element.info,
253295
data = element.data;
@@ -280,9 +322,9 @@ var AACDecoder = AV.Decoder.extend(function() {
280322
throw new Error("SBR not implemented");
281323

282324
return 1;
283-
};
325+
}
284326

285-
this.prototype.processPair = function(element, channel) {
327+
processPair(element, channel) {
286328
var profile = this.config.profile,
287329
left = element.left,
288330
right = element.right,
@@ -329,12 +371,14 @@ var AACDecoder = AV.Decoder.extend(function() {
329371
if (right.gainPresent)
330372
throw new Error("Gain control not implemented");
331373

332-
if (this.sbrPresent)
333-
throw new Error("SBR not implemented");
334-
};
374+
if (this.sbrPresent) {
375+
// throw new Error("SBR not implemented");
376+
element.sbr.process(this.data[channel], this.data[channel + 1], false);
377+
}
378+
}
335379

336380
// Intensity stereo
337-
this.prototype.processIS = function(element, left, right) {
381+
processIS(element, left, right) {
338382
var ics = element.right,
339383
info = ics.info,
340384
offsets = info.swbOffsets,
@@ -373,10 +417,10 @@ var AACDecoder = AV.Decoder.extend(function() {
373417

374418
groupOff += info.groupLength[g] * 128;
375419
}
376-
};
420+
}
377421

378422
// Mid-side stereo
379-
this.prototype.processMS = function(element, left, right) {
423+
processMS(element, left, right) {
380424
var ics = element.left,
381425
info = ics.info,
382426
offsets = info.swbOffsets,
@@ -401,9 +445,9 @@ var AACDecoder = AV.Decoder.extend(function() {
401445
}
402446
groupOff += info.groupLength[g] * 128;
403447
}
404-
};
448+
}
405449

406-
this.prototype.applyChannelCoupling = function(element, couplingPoint, data1, data2) {
450+
applyChannelCoupling(element, couplingPoint, data1, data2) {
407451
var cces = this.cces,
408452
isChannelPair = element instanceof CPEElement,
409453
applyCoupling = couplingPoint === CCEElement.AFTER_IMDCT ? 'applyIndependentCoupling' : 'applyDependentCoupling';
@@ -430,8 +474,11 @@ var AACDecoder = AV.Decoder.extend(function() {
430474
}
431475
}
432476
}
433-
};
477+
}
434478

435-
});
479+
}
480+
481+
AV.Decoder.register('mp4a', AACDecoder);
482+
AV.Decoder.register('aac ', AACDecoder);
436483

437484
module.exports = AACDecoder;

0 commit comments

Comments
 (0)