mp4filechecker
Version:
Check details of an mp4 file, e.g. to determine if transcoding is required
146 lines (145 loc) • 4.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: Object.getOwnPropertyDescriptor(all, name).get
});
}
_export(exports, {
get DEFAULT_OPTIONS () {
return DEFAULT_OPTIONS;
},
get checkMp4File () {
return checkMp4File;
}
});
const _mp4box = /*#__PURE__*/ _interop_require_wildcard(require("mp4box"));
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
const DEFAULT_OPTIONS = {
maxWidth: 1280,
maxHeight: 720,
supportedMimeTypes: [
'video/mp4'
],
supportedVideoCodecs: [
/^avc1\.42e0/,
/^avc1\.4d40/,
/^avc1\.6400/
],
supportedAudioCodecs: [
'mp4a.40.2',
'mp4a.40.5'
]
};
const loadBuffer = (blob)=>new Promise(function(resolve, reject) {
const fileReader = new FileReader();
fileReader.onload = function(evt) {
if (!evt.target) {
reject(new Error('File could not be read'));
} else if (evt.target.error) {
reject(evt.target.error);
} else {
resolve(evt.target.result);
}
};
fileReader.readAsArrayBuffer(blob);
});
async function* loadChunks(file, chunkSize = 64 * 1024) {
const fileSize = file.size;
let offset = 0;
while(offset <= fileSize){
const chunkBlob = file.slice(offset, chunkSize + offset);
const chunkData = await loadBuffer(chunkBlob);
chunkData.fileStart = offset;
yield chunkData;
offset += chunkData.byteLength;
}
}
const matchesOne = (candidateValue, testValues)=>{
return testValues.some((testCase)=>{
if (testCase instanceof RegExp) {
return testCase.test(candidateValue);
} else {
return candidateValue === testCase;
}
});
};
const isMatch = (info, options)=>{
const tracks = info.tracks;
return tracks.every((track)=>{
if (track.type === 'video') {
const isSupportedCodec = matchesOne(track.codec, options.supportedVideoCodecs);
const isSupportedWidth = track.video.width <= options.maxWidth;
const isSupportedHeight = track.video.height <= options.maxHeight;
return isSupportedCodec && isSupportedWidth && isSupportedHeight;
} else if (track.type === 'audio') {
return matchesOne(track.codec, options.supportedAudioCodecs);
} else {
return true;
}
});
};
const checkMp4File = async (file, options = DEFAULT_OPTIONS)=>{
if (!file || !matchesOne(file.type, options.supportedMimeTypes)) {
return false;
}
const box = _mp4box.createFile();
let result = null;
box.onReady = (info)=>{
result = info;
};
for await (const chunk of loadChunks(file)){
box.appendBuffer(chunk);
if (result) {
break;
}
}
if (result === null) {
return false;
} else {
return isMatch(result, options);
}
};