Skip to content

Commit 744162e

Browse files
committed
Add support for AAC-LC codec
1 parent 73cfa29 commit 744162e

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

codecs/codecs.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ export function getShortMIMEString(info) {
5050
if (!info) throw `Invalid ProbeInfo`;
5151
if (!info.streams || info.streams.length === 0) throw `No streams in ProbeInfo`;
5252

53+
// mp3 files are always considered audio/.
54+
if (info.format.format_name === 'mp3') {
55+
return 'audio/mpeg';
56+
}
57+
58+
// Otherwise, any file with at least 1 video stream is considered video/.
59+
// Otherwise, any file with at least 1 audio stream is considered audio/.
5360
const type = info.streams.some(s => s.codec_type === 'video') ?
5461
'video' :
5562
info.streams.some(s => s.codec_type === 'audio') ? 'audio' : undefined;
@@ -98,16 +105,30 @@ export function getShortMIMEString(info) {
98105
export function getFullMIMEString(info) {
99106
/** A string like 'video/mp4' */
100107
let contentType = `${getShortMIMEString(info)}`;
108+
// If MP3, just send back the type.
109+
if (contentType === 'audio/mpeg') {
110+
return contentType;
111+
}
112+
101113
let codecFrags = new Set();
102114

103115
for (const stream of info.streams) {
104116
if (stream.codec_type === 'audio') {
105-
// TODO! At least mp4a!
117+
switch (stream.codec_tag_string) {
118+
case 'mp4a': codecFrags.add(getMP4ACodecString(stream)); break;
119+
// TODO: vorbis.
120+
// TODO: opus.
121+
default:
122+
}
106123
}
107124
else if (stream.codec_type === 'video') {
108125
switch (stream.codec_tag_string) {
109126
case 'avc1': codecFrags.add(getAVC1CodecString(stream)); break;
110127
case 'vp09': codecFrags.add(getVP09CodecString(stream)); break;
128+
// We don't handle these as video streams with codecs, so skip them.
129+
case 'png':
130+
case 'mjpeg':
131+
continue;
111132
default:
112133
throw `Could not handle codec_tag_string ${stream.codec_tag_string} yet. ` +
113134
`Please file a bug https://github.com/codedread/bitjs/issues/new`;
@@ -116,7 +137,6 @@ export function getFullMIMEString(info) {
116137
}
117138

118139
if (codecFrags.length === 0) return contentType;
119-
120140
return contentType + '; codecs="' + Array.from(codecFrags).join(',') + '"';
121141
}
122142

@@ -215,3 +235,22 @@ function getVP09CodecString(stream) {
215235

216236
return frag;
217237
}
238+
239+
/**
240+
* https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter#mp4a
241+
* @param {ProbeStream} stream
242+
* @returns {string}
243+
*/
244+
function getMP4ACodecString(stream) {
245+
let frag = 'mp4a.40';
246+
switch (stream.profile) {
247+
case 'LC':
248+
frag += '.2';
249+
break;
250+
// TODO: more!
251+
default:
252+
throw `Cannot handle AAC stream with profile ${stream.profile} yet. ` +
253+
`Please file a bug https://github.com/codedread/bitjs/issues/new`;
254+
}
255+
return frag;
256+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@codedread/bitjs",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"description": "Binary Tools for JavaScript",
55
"homepage": "https://github.com/codedread/bitjs",
66
"author": "Jeff Schiller",

tests/codecs.spec.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ describe('codecs test suite', () => {
4040
})).to.throw();
4141
});
4242

43+
it('detects MP3', () => {
44+
expect(getShortMIMEString({
45+
format: { format_name: 'mp3' },
46+
streams: [ { codec_type: 'audio'}, { codec_type: 'video' } ],
47+
})).equals('audio/mpeg');
48+
});
49+
4350
it('detects AVI video', () => {
4451
expect(getShortMIMEString({
4552
format: { format_name: 'avi' },
@@ -252,4 +259,32 @@ describe('codecs test suite', () => {
252259
});
253260
});
254261
});
262+
263+
describe('AAC', () => {
264+
/** @type {ProbeInfo} */
265+
let info;
266+
267+
beforeEach(() => {
268+
info = {
269+
format: { format_name: 'mov,mp4,m4a,3gp,3g2,mj2' },
270+
streams: [{
271+
codec_type: 'audio',
272+
codec_tag_string: 'mp4a',
273+
}],
274+
};
275+
});
276+
277+
it('throws when unknown', () => {
278+
expect(() => getFullMIMEString(info)).to.throw();
279+
});
280+
281+
describe('Profile tests', () => {
282+
it('recognizes AAC-LC', () => {
283+
info.streams[0].profile = 'LC';
284+
expect(getFullMIMEString(info))
285+
.to.be.a('string')
286+
.and.equals('audio/mp4; codecs="mp4a.40.2"');
287+
});
288+
});
289+
});
255290
});

0 commit comments

Comments
 (0)