@file-type/av
Version:
file-type plugin for improved audio / video type detection
93 lines (92 loc) • 3.06 kB
JavaScript
import { parseFromTokenizer } from 'music-metadata';
function matchesHeader(data, header) {
if (data.length < header.length)
return false;
for (let i = 0; i < header.length; i++) {
if (data[i] !== header[i])
return false;
}
return true;
}
function stringMatchesHeader(data, header) {
const expected = new TextEncoder().encode(header);
return matchesHeader(data, expected);
}
export const detectAv = {
id: 'av',
detect: async (tokenizer) => {
const buffer = new Uint8Array(10);
await tokenizer.peekBuffer(buffer);
if (matchesHeader(buffer, [0x1A, 0x45, 0xDF, 0xA3])) {
const { format } = await parseFromTokenizer(tokenizer);
switch (format.container) {
case 'EBML/matroska':
return format.hasVideo ? {
ext: 'mkv',
mime: 'video/matroska'
} : {
ext: 'mka',
mime: 'audio/matroska'
};
case 'EBML/webm':
return format.hasVideo ? {
ext: 'webm',
mime: 'video/webm'
} : {
ext: 'webm',
mime: 'audio/webm'
};
}
}
if (stringMatchesHeader(buffer.subarray(4), 'ftyp')) {
const { format } = await parseFromTokenizer(tokenizer);
return format.hasVideo ? {
ext: 'mp4',
mime: 'video/mp4'
} : {
ext: 'm4a',
mime: 'audio/mp4'
};
}
if (stringMatchesHeader(buffer, 'OggS')) {
const { format } = await parseFromTokenizer(tokenizer);
let codecValue;
if (format.hasVideo) {
return {
ext: 'ogv',
mime: 'video/ogg'
};
}
if (format.codec) {
if (format.codec.startsWith('Opus')) {
return {
ext: 'opus',
mime: 'audio/ogg; codecs=opus'
};
}
if (format.codec.startsWith('Vorbis')) {
return {
ext: 'ogg',
mime: 'audio/ogg; codecs=vorbis'
};
}
if (format.codec.startsWith('Speex')) {
return {
ext: 'spx',
mime: 'audio/ogg; codecs=speex'
};
}
if (format.codec.startsWith('FLAC')) {
return {
ext: 'flac',
mime: 'audio/ogg; codecs=flac'
};
}
}
return {
ext: 'ogg',
mime: 'audio/ogg'
};
}
}
};