Skip to content

Commit

Permalink
Ability to detect MPEG when prefixed with some noise
Browse files Browse the repository at this point in the history
  • Loading branch information
Borewit committed Jul 16, 2024
1 parent 9d2ee02 commit a27985e
Showing 1 changed file with 60 additions and 39 deletions.
99 changes: 60 additions & 39 deletions core.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ export async function fileTypeFromTokenizer(tokenizer) {

export class FileTypeParser {
constructor(options) {
this.options = {
mpegOffsetTollerance: 4,
...options,
};

this.detectors = options?.customDetectors;

this.fromTokenizer = this.fromTokenizer.bind(this);
Expand Down Expand Up @@ -1547,46 +1552,12 @@ export class FileTypeParser {
}

// Check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE)
if (this.buffer.length >= 2 && this.check([0xFF, 0xE0], {offset: 0, mask: [0xFF, 0xE0]})) {
if (this.check([0x10], {offset: 1, mask: [0x16]})) {
// Check for (ADTS) MPEG-2
if (this.check([0x08], {offset: 1, mask: [0x08]})) {
return {
ext: 'aac',
mime: 'audio/aac',
};
if (this.buffer.length >= (2 + this.options.mpegOffsetTollerance)) {
for (let depth = 0; depth < this.options.mpegOffsetTollerance; ++depth) {
const type = this.scanMpeg(depth);
if (type) {
return type;
}

// Must be (ADTS) MPEG-4
return {
ext: 'aac',
mime: 'audio/aac',
};
}

// MPEG 1 or 2 Layer 3 header
// Check for MPEG layer 3
if (this.check([0x02], {offset: 1, mask: [0x06]})) {
return {
ext: 'mp3',
mime: 'audio/mpeg',
};
}

// Check for MPEG layer 2
if (this.check([0x04], {offset: 1, mask: [0x06]})) {
return {
ext: 'mp2',
mime: 'audio/mpeg',
};
}

// Check for MPEG layer 1
if (this.check([0x06], {offset: 1, mask: [0x06]})) {
return {
ext: 'mp1',
mime: 'audio/mpeg',
};
}
}
}
Expand Down Expand Up @@ -1656,6 +1627,56 @@ export class FileTypeParser {
};
}
}

/**
Scan Check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE)
@param offset to scan for sync-preamble
@returns {{ext: string, mime: string}}
*/
scanMpeg(offset) {
if (this.check([0xFF, 0xE0], {offset, mask: [0xFF, 0xE0]})) {
if (this.check([0x10], {offset: offset + 1, mask: [0x16]})) {
// Check for (ADTS) MPEG-2
if (this.check([0x08], {offset: offset + 1, mask: [0x08]})) {
return {
ext: 'aac',
mime: 'audio/aac',
};
}

// Must be (ADTS) MPEG-4
return {
ext: 'aac',
mime: 'audio/aac',
};
}

// MPEG 1 or 2 Layer 3 header
// Check for MPEG layer 3
if (this.check([0x02], {offset: offset + 1, mask: [0x06]})) {
return {
ext: 'mp3',
mime: 'audio/mpeg',
};
}

// Check for MPEG layer 2
if (this.check([0x04], {offset: offset + 1, mask: [0x06]})) {
return {
ext: 'mp2',
mime: 'audio/mpeg',
};
}

// Check for MPEG layer 1
if (this.check([0x06], {offset: offset + 1, mask: [0x06]})) {
return {
ext: 'mp1',
mime: 'audio/mpeg',
};
}
}
}
}

export const supportedExtensions = new Set(extensions);
Expand Down

0 comments on commit a27985e

Please sign in to comment.