konowebcodecs/src/createFFmpeg.js
2020-05-05 18:16:52 +08:00

132 lines
3.1 KiB
JavaScript

const defaultArgs = require('./constants/defaultArgs');
const { setLogging, log } = require('./utils/log');
const resolvePaths = require('./utils/resolvePaths');
const parseProgress = require('./utils/parseProgress');
const stringList2pointer = require('./utils/stringList2pointer');
const parseArgs = require('./utils/parseArgs');
const {
defaultOptions,
getModule,
fetchFile,
} = require('./node');
const NO_LOAD = Error('FFmpeg.js is not ready, make sure you have completed load().');
const NO_MULTIPLE_RUN = Error('FFmpeg.js can only run one command at a time');
let Module = null;
let ffmpeg = null;
module.exports = (_options = {}) => {
let runResolve = null;
let running = false;
const {
log: logging,
logger,
progress,
...options
} = resolvePaths({
...defaultOptions,
..._options,
});
const detectCompletion = ({ message, type }) => {
if (type === 'ffmpeg-stdout'
&& message === 'FFMPEG_END'
&& runResolve !== null) {
runResolve();
runResolve = null;
running = false;
}
};
setLogging(logging);
const load = async () => {
if (Module === null) {
log('info', 'load ffmpeg-core');
Module = await getModule(options);
Module.setLogger((_log) => {
detectCompletion(_log);
parseProgress(_log, progress);
logger(_log);
log(_log.type, _log.message);
});
if (ffmpeg === null) {
ffmpeg = Module.cwrap('proxy_main', 'number', ['number', 'number']);
}
log('info', 'ffmpeg-core loaded');
}
};
const FS = (method, args) => {
if (Module === null) {
throw NO_LOAD;
} else {
log('info', `FS.${method} ${args[0]}`);
return Module.FS[method](...args);
}
};
const write = async (path, data) => (
FS('writeFile', [path, await fetchFile(data)])
);
const writeText = (path, text) => (
FS('writeFile', [path, text])
);
const read = (path) => (
FS('readFile', [path])
);
const remove = (path) => (
FS('unlink', [path])
);
const ls = (path) => (
FS('readdir', [path])
);
const run = (_args) => {
if (ffmpeg === null) {
throw NO_LOAD;
} else if (running) {
throw NO_MULTIPLE_RUN;
} else {
running = true;
return new Promise((resolve) => {
const args = [...defaultArgs, ...parseArgs(_args)].filter((s) => s.length !== 0);
log('info', `ffmpeg command: ${args.join(' ')}`);
runResolve = resolve;
ffmpeg(args.length, stringList2pointer(Module, args));
});
}
};
const transcode = (input, output, opts = '') => (
run(`-i ${input} ${opts} ${output}`)
);
const trim = (input, output, from, to, opts = '') => (
run(`-i ${input} -ss ${from} -to ${to} ${opts} ${output}`)
);
const concatDemuxer = (input, output, opts = '') => {
const text = input.reduce((acc, path) => `${acc}\nfile ${path}`, '');
writeText('concat_list.txt', text);
return run(`-f concat -safe 0 -i concat_list.txt ${opts} ${output}`);
};
return {
load,
FS,
write,
writeText,
read,
remove,
ls,
run,
transcode,
trim,
concatDemuxer,
};
};