Merge branch 'develop'

This commit is contained in:
Jerome Wu 2019-10-30 19:28:33 +08:00
commit ddc713b132
44 changed files with 611 additions and 125 deletions

View File

@ -2,6 +2,11 @@
"extends": "airbnb-base",
"rules": {
"no-underscore-dangle": 0,
"linebreak-style": 0,
"linebreak-style": 0
"global-require": 0
},
"env": {
"browser": true,
"node": true
}
}

View File

@ -28,11 +28,13 @@ $ npm install @ffmpeg/ffmpeg
```javascript
const fs = require('fs');
const ffmpeg = require('@ffmpeg/ffmpeg');
const { createWorker } = require('@ffmpeg/ffmpeg');
const worker = createWorker();
(async () => {
await ffmpeg.load();
const data = ffmpeg.transcode('./test.avi', 'mp4');
await worker.load();
const { data } = await worker.transcode('./test.avi', 'mp4');
fs.wrieFileSync('./test.mp4', data);
})();
```

View File

@ -0,0 +1,44 @@
<html>
<head>
<script src="/dist/ffmpeg.dev.js"></script>
<style>
html, body {
margin: 0;
width: 100%;
height: 100%
}
body {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
</head>
<body>
<h3>Upload a video to transcode to mp4 (x264) and play!</h3>
<video id="output-video" controls></video><br/>
<input type="file" id="uploader">
<p id="message" />
<script>
const { createWorker } = FFmpeg;
const worker = createWorker({
corePath: '../../node_modules/@ffmpeg/core/ffmpeg-core.js',
logger: ({ message }) => console.log(message),
});
const transcode = async ({ target: { files } }) => {
const message = document.getElementById('message');
message.innerHTML = 'Loading ffmpeg-core.js';
await worker.load();
message.innerHTML = 'Start transcoding';
const { data } = await worker.transcode(files[0], 'mp4');
message.innerHTML = 'Complete transcoding';
const video = document.getElementById('output-video');
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
}
const elm = document.getElementById('uploader');
elm.addEventListener('change', transcode);
</script>
</body>
</html>

18
examples/node/transcode.js Executable file
View File

@ -0,0 +1,18 @@
const fs = require('fs');
const { createWorker } = require('../../src');
const { argv } = process;
const [,, inputPath, outputPath] = argv;
const worker = createWorker({
logger: ({ message }) => console.log(message),
});
(async () => {
await worker.load();
console.log('Start transcoding');
const { data } = await worker.transcode(inputPath, outputPath.split('.').pop());
console.log('Complete transcoding');
fs.writeFileSync(outputPath, Buffer.from(data));
process.exit(0);
})();

View File

@ -1,10 +0,0 @@
const fs = require('fs');
const ffmpeg = require('../src');
const { argv } = process;
const [,, inputPath, outputPath] = argv;
(async () => {
await ffmpeg.load();
const data = ffmpeg.transcode(inputPath, outputPath.split('.').pop());
fs.writeFileSync(outputPath, data);
})();

56
package-lock.json generated
View File

@ -811,9 +811,9 @@
}
},
"@ffmpeg/core": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.1.0.tgz",
"integrity": "sha512-a4/HokRytKFJDW+RVvuf22rUzjNgXZKhlF6FIVBcLACIDcCEQZ0uCUC+5DZb+xprCvdMyXm0wy90uoYLRTq+LA=="
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.3.0.tgz",
"integrity": "sha512-bm95T4C2/glYHuzTW7r49Ia+CCSYCbmOe0VOhvCorR3eBzPV/4ESuA4LxdouIraOHueDZf6rcPik94Jv1+t0iQ=="
},
"@webassemblyjs/ast": {
"version": "1.8.5",
@ -3056,8 +3056,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -3078,14 +3077,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -3100,20 +3097,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -3230,8 +3224,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -3243,7 +3236,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -3258,7 +3250,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -3266,14 +3257,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -3292,7 +3281,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -3373,8 +3361,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -3386,7 +3373,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -3508,7 +3494,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -3528,7 +3513,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -4207,6 +4191,11 @@
"has-symbols": "^1.0.0"
}
},
"is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
},
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@ -4856,6 +4845,11 @@
}
}
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
},
"node-libs-browser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
@ -5538,6 +5532,11 @@
"regenerate": "^1.4.0"
}
},
"regenerator-runtime": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
},
"regenerator-transform": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz",
@ -5688,8 +5687,7 @@
"resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
"dev": true
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
},
"restore-cursor": {
"version": "2.0.0",

View File

@ -32,7 +32,11 @@
},
"homepage": "https://github.com/ffmpegjs/ffmpeg.js#readme",
"dependencies": {
"@ffmpeg/core": "^0.1.0"
"@ffmpeg/core": "^0.3.0",
"is-url": "^1.2.4",
"node-fetch": "^2.6.0",
"regenerator-runtime": "^0.13.3",
"resolve-url": "^0.2.1"
},
"devDependencies": {
"@babel/core": "^7.6.4",

View File

@ -32,8 +32,8 @@ module.exports = [
library: 'FFmpeg',
libraryTarget: 'umd',
}),
//genConfig({
// entry: path.resolve(__dirname, '..', 'src', 'worker-script', 'browser', 'index.js'),
// filename: 'worker.dev.js',
//}),
genConfig({
entry: path.resolve(__dirname, '..', 'src', 'worker-script', 'browser', 'index.js'),
filename: 'worker.dev.js',
}),
];

View File

@ -23,8 +23,8 @@ module.exports = [
library: 'FFmpeg',
libraryTarget: 'umd',
}),
//genConfig({
// entry: path.resolve(__dirname, '..', 'src', 'worker-script', 'browser', 'index.js'),
// filename: 'worker.min.js',
//}),
genConfig({
entry: path.resolve(__dirname, '..', 'src', 'worker-script', 'browser', 'index.js'),
filename: 'worker.min.js',
}),
];

View File

@ -0,0 +1,3 @@
module.exports = {
logger: () => {},
};

21
src/createJob.js Normal file
View File

@ -0,0 +1,21 @@
const getId = require('./utils/getId');
let jobCounter = 0;
module.exports = ({
id: _id,
action,
payload = {},
}) => {
let id = _id;
if (typeof id === 'undefined') {
id = getId('Job', jobCounter);
jobCounter += 1;
}
return {
id,
action,
payload,
};
};

109
src/createWorker.js Normal file
View File

@ -0,0 +1,109 @@
const createJob = require('./createJob');
const { log } = require('./utils/log');
const getId = require('./utils/getId');
const {
defaultOptions,
spawnWorker,
terminateWorker,
onMessage,
loadMedia,
send,
} = require('./worker/node');
let workerCounter = 0;
module.exports = (_options = {}) => {
const id = getId('Worker', workerCounter);
const {
logger,
...options
} = {
...defaultOptions,
..._options,
};
const resolves = {};
const rejects = {};
let worker = spawnWorker(options);
workerCounter += 1;
const setResolve = (action, res) => {
resolves[action] = res;
};
const setReject = (action, rej) => {
rejects[action] = rej;
};
const startJob = ({ id: jobId, action, payload }) => (
new Promise((resolve, reject) => {
log(`[${id}]: Start ${jobId}, action=${action}`);
setResolve(action, resolve);
setReject(action, reject);
send(worker, {
workerId: id,
jobId,
action,
payload,
});
})
);
const load = (jobId) => (
startJob(createJob({
id: jobId, action: 'load', payload: { options },
}))
);
const transcode = async (media, outputExt, opts, jobId) => (
startJob(createJob({
id: jobId,
action: 'transcode',
payload: {
media: await loadMedia(media),
outputExt,
options: opts,
},
}))
);
const terminate = async (jobId) => {
if (worker !== null) {
await startJob(createJob({
id: jobId,
action: 'terminate',
}));
terminateWorker(worker);
worker = null;
}
return Promise.resolve();
};
onMessage(worker, ({
workerId, jobId, status, action, data,
}) => {
if (status === 'resolve') {
log(`[${workerId}]: Complete ${jobId}`);
let d = data;
if (action === 'transcode') {
d = Uint8Array.from({ ...data, length: Object.keys(data).length });
}
resolves[action]({ jobId, data: d });
} else if (status === 'reject') {
rejects[action](data);
throw Error(data);
} else if (status === 'progress') {
logger(data);
}
});
return {
id,
worker,
setResolve,
setReject,
load,
transcode,
terminate,
};
};

View File

@ -1,7 +1,9 @@
const load = require('./load');
const transcode = require('./transcode');
require('regenerator-runtime/runtime');
const { logging, setLogging } = require('./utils/log');
const createWorker = require('./createWorker');
module.exports = {
load,
transcode,
logging,
setLogging,
createWorker,
};

View File

@ -1,12 +0,0 @@
const FFmpegCore = require('@ffmpeg/core');
const { setModule } = require('./util/module');
module.exports = () => (
new Promise((resolve) => {
FFmpegCore()
.then((Module) => {
setModule(Module);
resolve();
});
})
);

View File

@ -1,17 +0,0 @@
const fs = require('fs');
const { getModule } = require('./util/module');
const getFFmpeg = require('./util/getFFmpeg');
const strList2ptr = require('./util/strList2ptr');
const defaultArgs = require('./constants/defaultArgs');
module.exports = (inputPath, outputExt, options = '') => {
const Module = getModule();
const data = new Uint8Array(fs.readFileSync(inputPath));
const iPath = `file.${inputPath.split('.').pop()}`;
const oPath = `file.${outputExt}`;
const ffmpeg = getFFmpeg();
const args = [...defaultArgs, ...`${options} -i ${iPath} ${oPath}`.trim().split(' ')];
Module.FS.writeFile(iPath, data);
ffmpeg(args.length, strList2ptr(args));
return Buffer.from(Module.FS.readFile(oPath));
};

View File

@ -1,6 +0,0 @@
const { getModule } = require('./module');
module.exports = () => {
const Module = getModule();
return Module.cwrap('ffmpeg', 'number', ['number', 'number']);
};

View File

@ -1,7 +0,0 @@
let Module = null;
exports.setModule = (m) => {
Module = m;
};
exports.getModule = () => Module;

View File

@ -1,11 +0,0 @@
const { getModule } = require('./module');
module.exports = (s) => {
const Module = getModule();
const ptr = Module._malloc((s.length + 1) * Uint8Array.BYTES_PER_ELEMENT);
for (let i = 0; i < s.length; i += 1) {
Module.setValue(ptr + i, s.charCodeAt(i), 'i8');
}
Module.setValue(ptr + s.length, 0, 'i8');
return ptr;
};

View File

@ -1,14 +0,0 @@
const { getModule } = require('./module');
const str2ptr = require('./str2ptr');
module.exports = (strList) => {
const Module = getModule();
const listPtr = Module._malloc(strList.length * Uint32Array.BYTES_PER_ELEMENT);
strList.forEach((s, idx) => {
const strPtr = str2ptr(s);
Module.setValue(listPtr + (4 * idx), strPtr, 'i32');
});
return listPtr;
};

3
src/utils/getId.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = (prefix, cnt) => (
`${prefix}-${cnt}-${Math.random().toString(16).slice(3, 8)}`
);

9
src/utils/log.js Normal file
View File

@ -0,0 +1,9 @@
let logging = false;
exports.logging = logging;
exports.setLogging = (_logging) => {
logging = _logging;
};
exports.log = (...args) => (logging ? console.log.apply(this, args) : null);

View File

@ -0,0 +1,5 @@
{
"env": {
"worker": true
}
}

View File

@ -0,0 +1,6 @@
module.exports = (corePath) => {
if (typeof global.Module === 'undefined') {
global.importScripts(corePath);
}
return global.Module;
};

View File

@ -0,0 +1,10 @@
const worker = require('../');
const getCore = require('./getCore');
global.addEventListener('message', ({ data }) => {
worker.dispatchHandlers(data, (obj) => postMessage(obj));
});
worker.setAdapter({
getCore,
});

View File

@ -1,6 +1,4 @@
module.exports = [
'./ffmpeg', // args[0] is always binary path
'-nostdin', // Disable interaction mode
'-loglevel',
'quiet',
];

View File

@ -0,0 +1,92 @@
require('regenerator-runtime/runtime');
const defaultArgs = require('./constants/defaultArgs');
let action = 'unknown';
let Module = null;
let adapter = null;
let ffmpeg = null;
const str2ptr = (s) => {
const ptr = Module._malloc((s.length + 1) * Uint8Array.BYTES_PER_ELEMENT);
for (let i = 0; i < s.length; i += 1) {
Module.setValue(ptr + i, s.charCodeAt(i), 'i8');
}
Module.setValue(ptr + s.length, 0, 'i8');
return ptr;
};
const strList2ptr = (strList) => {
const listPtr = Module._malloc(strList.length * Uint32Array.BYTES_PER_ELEMENT);
strList.forEach((s, idx) => {
const strPtr = str2ptr(s);
Module.setValue(listPtr + (4 * idx), strPtr, 'i32');
});
return listPtr;
};
const load = ({ workerId, payload: { options: { corePath } } }, res) => {
if (Module == null) {
const Core = adapter.getCore(corePath);
Core()
.then((_Module) => {
Module = _Module;
Module.setLogger((message, type) => {
res.progress({ workerId, action, type, message });
});
ffmpeg = Module.cwrap('ffmpeg', 'number', ['number', 'number']);
res.resolve(true);
});
} else {
res.resolve(true);
}
};
const transcode = ({
payload: {
media,
outputExt,
options = '',
},
}, res) => {
const data = Uint8Array.from({ ...media, length: Object.keys(media).length });
const iPath = 'media';
const oPath = `media.${outputExt}`;
const args = [...defaultArgs, ...`${options} -i file:${iPath} ${oPath}`.trim().split(' ')];
Module.FS.writeFile(iPath, data);
ffmpeg(args.length, strList2ptr(args));
const out = Module.FS.readFile(oPath);
Module.FS.unlink(iPath);
Module.FS.unlink(oPath);
res.resolve(out);
};
exports.dispatchHandlers = (packet, send) => {
const res = (status, data) => {
send({
...packet,
status,
data,
});
};
res.resolve = res.bind(this, 'resolve');
res.reject = res.bind(this, 'reject');
res.progress = res.bind(this, 'progress');
action = packet.action
try {
({
load,
transcode,
})[packet.action](packet, res);
} catch (err) {
/** Prepare exception to travel through postMessage */
res.reject(err.toString());
}
action = 'unknown';
};
exports.setAdapter = (_adapter) => {
adapter = _adapter;
};

View File

@ -0,0 +1,8 @@
let FFmpegCore = null;
module.exports = () => {
if (FFmpegCore === null) {
FFmpegCore = require('@ffmpeg/core');
}
return FFmpegCore;
};

View File

@ -0,0 +1,10 @@
const worker = require('../');
const getCore = require('./getCore');
process.on('message', (packet) => {
worker.dispatchHandlers(packet, (obj) => process.send(obj));
});
worker.setAdapter({
getCore,
});

View File

@ -0,0 +1,14 @@
const resolveURL = require('resolve-url');
const { version, dependencies } = require('../../../package.json');
const defaultOptions = require('../../constants/defaultOptions');
/*
* Default options for browser worker
*/
module.exports = {
...defaultOptions,
workerPath: (typeof process !== 'undefined' && process.env.FFMPEG_ENV === 'development')
? resolveURL(`/dist/worker.dev.js?nocache=${Math.random().toString(36).slice(3)}`)
: `https://unpkg.com/@ffmpeg/ffmpeg@v${version}/dist/worker.min.js`,
corePath: `https://unpkg.com/@ffmpeg/core@v${dependencies['@ffmpeg/core'].substring(1)}/ffmpeg-core.js`,
};

View File

@ -0,0 +1,24 @@
/**
*
* Tesseract Worker adapter for browser
*
* @fileoverview Tesseract Worker adapter for browser
* @author Kevin Kwok <antimatter15@gmail.com>
* @author Guillermo Webster <gui@mit.edu>
* @author Jerome Wu <jeromewus@gmail.com>
*/
const defaultOptions = require('./defaultOptions');
const spawnWorker = require('./spawnWorker');
const terminateWorker = require('./terminateWorker');
const onMessage = require('./onMessage');
const send = require('./send');
const loadMedia = require('./loadMedia');
module.exports = {
defaultOptions,
spawnWorker,
terminateWorker,
onMessage,
send,
loadMedia,
};

View File

@ -0,0 +1,46 @@
const resolveURL = require('resolve-url');
/**
* readFromBlobOrFile
*
* @name readFromBlobOrFile
* @function
* @access private
*/
const readFromBlobOrFile = (blob) => (
new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = () => {
resolve(fileReader.result);
};
fileReader.onerror = ({ target: { error: { code } } }) => {
reject(Error(`File could not be read! Code=${code}`));
};
fileReader.readAsArrayBuffer(blob);
})
);
const loadMedia = async (image) => {
let data = image;
if (typeof image === 'undefined') {
return 'undefined';
}
if (typeof image === 'string') {
// Base64 Media
if (/data:image\/([a-zA-Z]*);base64,([^"]*)/.test(image)) {
data = atob(image.split(',')[1])
.split('')
.map((c) => c.charCodeAt(0));
} else {
const res = await fetch(resolveURL(image));
data = res.arrayBuffer();
}
} else if (image instanceof File || image instanceof Blob) {
data = await readFromBlobOrFile(image);
}
return new Uint8Array(data);
};
module.exports = loadMedia;

View File

@ -0,0 +1,5 @@
module.exports = (worker, handler) => {
worker.onmessage = ({ data }) => { // eslint-disable-line
handler(data);
};
};

View File

@ -0,0 +1,10 @@
/**
* send
*
* @name send
* @function send packet to worker and create a job
* @access public
*/
module.exports = async (worker, packet) => {
worker.postMessage(packet);
};

View File

@ -0,0 +1,10 @@
/**
* spawnWorker
*
* @name spawnWorker
* @function create a new Worker in browser
* @access public
*/
module.exports = ({ workerPath }) => (
new Worker(workerPath)
);

View File

@ -0,0 +1,10 @@
/**
* terminateWorker
*
* @name terminateWorker
* @function terminate worker
* @access public
*/
module.exports = (worker) => {
worker.terminate();
};

View File

@ -0,0 +1,10 @@
const path = require('path');
const defaultOptions = require('../../constants/defaultOptions');
/*
* Default options for node worker
*/
module.exports = {
...defaultOptions,
workerPath: path.join(__dirname, '..', '..', 'worker-script', 'node', 'index.js'),
};

24
src/worker/node/index.js Normal file
View File

@ -0,0 +1,24 @@
/**
*
* Tesseract Worker impl. for node (using child_process)
*
* @fileoverview Tesseract Worker impl. for node
* @author Kevin Kwok <antimatter15@gmail.com>
* @author Guillermo Webster <gui@mit.edu>
* @author Jerome Wu <jeromewus@gmail.com>
*/
const defaultOptions = require('./defaultOptions');
const spawnWorker = require('./spawnWorker');
const terminateWorker = require('./terminateWorker');
const onMessage = require('./onMessage');
const send = require('./send');
const loadMedia = require('./loadMedia');
module.exports = {
defaultOptions,
spawnWorker,
terminateWorker,
onMessage,
send,
loadMedia,
};

View File

@ -0,0 +1,28 @@
const util = require('util');
const fs = require('fs');
const fetch = require('node-fetch');
const isURL = require('is-url');
const readFile = util.promisify(fs.readFile);
module.exports = async (media) => {
let data = media;
if (typeof media === 'undefined') {
return media;
}
if (typeof media === 'string') {
if (isURL(media) || media.startsWith('chrome-extension://') || media.startsWith('file://')) {
const res = await fetch(media);
data = res.arrayBuffer();
} else if (/data:media\/([a-zA-Z]*);base64,([^"]*)/.test(media)) {
data = Buffer.from(media.split(',')[1], 'base64');
} else {
data = await readFile(media);
}
} else if (Buffer.isBuffer(media)) {
data = media;
}
return new Uint8Array(data);
};

View File

@ -0,0 +1,3 @@
module.exports = (worker, handler) => {
worker.on('message', handler);
};

10
src/worker/node/send.js Normal file
View File

@ -0,0 +1,10 @@
/**
* send
*
* @name send
* @function send packet to worker and create a job
* @access public
*/
module.exports = (worker, packet) => {
worker.send(packet);
};

View File

@ -0,0 +1,12 @@
const { fork } = require('child_process');
/**
* spawnWorker
*
* @name spawnWorker
* @function fork a new process in node
* @access public
*/
module.exports = ({ workerPath }) => (
fork(workerPath)
);

View File

@ -0,0 +1,10 @@
/**
* terminateWorker
*
* @name terminateWorker
* @function kill worker
* @access public
*/
module.exports = (worker) => {
worker.kill();
};

BIN
tests/assets/flame.avi Normal file

Binary file not shown.

Binary file not shown.