Skip to content

Commit ffdf13e

Browse files
committed
Update options in Worker.run() to make it more clear
1 parent f2e7a1c commit ffdf13e

File tree

12 files changed

+102
-68
lines changed

12 files changed

+102
-68
lines changed

docs/api.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [Worker.remove](#worker-remove)
99
- [Worker.transcode](#worker-transcode)
1010
- [Worker.trim](#worker-trim)
11+
- [Worker.concatDemuxer](#worker-concatDemuxer)
1112
- [Worker.run](#worker-run)
1213

1314
---
@@ -135,14 +136,14 @@ Worker.remove() removes files in file system, it will be better to delete unused
135136

136137
<a name="worker-transcode"></a>
137138

138-
### Worker.transcode(inputPath, outputPath, options, del, jobId): Promise
139+
### Worker.transcode(input, output, options, del, jobId): Promise
139140

140141
Worker.transcode() transcode a video file to another format.
141142

142143
**Arguments:**
143144

144-
- `inputPath` input file path, the input file should be written through Worker.write()
145-
- `outputPath` output file path, can be read with Worker.read() later
145+
- `input` input file path, the input file should be written through Worker.write()
146+
- `output` output file path, can be read with Worker.read() later
146147
- `options` a string to add extra arguments to ffmpeg
147148
- `del` a boolean to determine whether to delete input file after the task is done, default: true
148149
- `jobId` check Worker.load()
@@ -157,7 +158,7 @@ Worker.transcode() transcode a video file to another format.
157158

158159
<a name="worker-trim"></a>
159160

160-
### Worker.trim(inputPath, outputPath, from, to, options, del, jobId): Promise
161+
### Worker.trim(input, output, from, to, options, del, jobId): Promise
161162

162163
Worker.trim() trims video to specific interval.
163164

@@ -181,14 +182,14 @@ Worker.trim() trims video to specific interval.
181182

182183
<a name="worker-concatDemuxer"></a>
183184

184-
### Worker.concatDemuxer(inputPaths, outputPath, options, del, jobId): Promise
185+
### Worker.concatDemuxer(input, output, options, del, jobId): Promise
185186

186187
Worker.concatDemuxer() concatenates multiple videos using concatDemuxer. This method won't encode the videos again. But it has its limitations. See [Concat demuxer Wiki](https://trac.ffmpeg.org/wiki/Concatenate)
187188

188189
**Arguments:**
189190

190-
- `inputPaths` input file paths as an Array, the input files should be written through Worker.write()
191-
- `outputPath` output file path, can be read with Worker.read() later
191+
- `input` input file paths as an Array, the input files should be written through Worker.write()
192+
- `output` output file path, can be read with Worker.read() later
192193
- `options` a string to add extra arguments to ffmpeg
193194
- `del` a boolean to determine whether to delete input file after the task is done, default: true
194195
- `jobId` check Worker.load()
@@ -197,7 +198,7 @@ Worker.concatDemuxer() concatenates multiple videos using concatDemuxer. This me
197198

198199
```javascript
199200
(async () => {
200-
await worker.trim(["flame-1.avi", "flame-2.avi"], "output.mp4");
201+
await worker.concatDemuxer(["flame-1.avi", "flame-2.avi"], "output.mp4");
201202
})();
202203
```
203204

@@ -210,16 +211,19 @@ Worker.run() is similar to FFmpeg cli tool, aims to provide maximum flexiblity f
210211
**Arguments:**
211212

212213
- `args` a string to represent arguments, note: inputPath must start with `/data/` as worker.write write to this path by default.
213-
- `options` a object to define the value for inputPath, outputPath and del.
214+
- `options` a object to define the value for input, output and del.
215+
- `input` a string or an array of strings to indicate input files, ffmpeg.js deletes these files for you.
216+
- `output` a string or an array of strings to indicate output files, ffmpeg.js moves these files to `/data`, deletes them from MEMFS and you can read them with Worker.read()
217+
- `del` a boolean to determine whether to delete input file after the task is done, default: true
214218
- `jobId` check Worker.load()
215219

216220
**Examples:**
217221

218222
```javascript
219223
(async () => {
220224
await worker.run("-i /data/flame.avi -s 1920x1080 output.mp4", {
221-
inputPath: "flame.avi",
222-
outputPath: "output.mp4"
225+
input: "flame.avi",
226+
output: "output.mp4"
223227
});
224228
})();
225229
```

examples/browser/image2video.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ <h3>Click start to transcode images to mp4 (x264) and play!</h3>
3838
await worker.write(`tmp.${num}.png`, `../../tests/assets/triangle/tmp.${num}.png`);
3939
}
4040
message.innerHTML = 'Start transcoding';
41-
await worker.run('-framerate 30 -pattern_type glob -i /data/*.png -i /data/audio.ogg -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out.mp4', { outputPath: 'out.mp4' });
41+
await worker.run('-framerate 30 -pattern_type glob -i /data/*.png -i /data/audio.ogg -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out.mp4', { output: 'out.mp4' });
4242
const { data } = await worker.read('out.mp4');
4343
await worker.remove('audio.ogg');
4444
for (let i = 0; i < 60; i += 1) {

examples/browser/run.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ <h3>Upload a video to transcode to mp4 (x264) and play!</h3>
3333
await worker.load();
3434
message.innerHTML = 'Start transcoding';
3535
await worker.write(name, files[0]);
36-
await worker.run(`-i /data/${name} output.mp4`, { inputPath: name, outputPath: 'output.mp4' });
36+
await worker.run(`-i /data/${name} output.mp4`, { input: name, output: 'output.mp4' });
3737
message.innerHTML = 'Complete transcoding';
3838
const { data } = await worker.read('output.mp4');
3939

examples/browser/transcode.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ <h3>Upload a video to transcode to mp4 (x264) and play!</h3>
2323
const { createWorker } = FFmpeg;
2424
const worker = createWorker({
2525
corePath: '../../node_modules/@ffmpeg/core/ffmpeg-core.js',
26+
logger: ({ message }) => console.log(message),
2627
progress: p => console.log(p),
2728
});
2829

@@ -36,7 +37,6 @@ <h3>Upload a video to transcode to mp4 (x264) and play!</h3>
3637
await worker.transcode(name, 'output.mp4');
3738
message.innerHTML = 'Complete transcoding';
3839
const { data } = await worker.read('output.mp4');
39-
console.log(data);
4040

4141
const video = document.getElementById('output-video');
4242
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));

examples/browser/trim.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</style>
1616
</head>
1717
<body>
18-
<h3>Upload a mp4 (x264) video and trim its first 2 seconds and play!</h3>
18+
<h3>Upload a mp4 (x264) video and trim its first 10 seconds and play!</h3>
1919
<video id="output-video" controls></video><br/>
2020
<input type="file" id="uploader">
2121
<p id="message"></p>
@@ -33,7 +33,7 @@ <h3>Upload a mp4 (x264) video and trim its first 2 seconds and play!</h3>
3333
await worker.load();
3434
message.innerHTML = 'Start trimming';
3535
await worker.write(name, files[0]);
36-
await worker.trim(name, 'output.mp4', 0, 2);
36+
await worker.trim(name, 'output.mp4', 0, 10);
3737
message.innerHTML = 'Complete trimming';
3838
const { data } = await worker.read('output.mp4');
3939

examples/node/image2video.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const worker = createWorker({
1515
await worker.write(`tmp.${num}.png`, `../../tests/assets/triangle/tmp.${num}.png`);
1616
}
1717
console.log('Start transcoding');
18-
await worker.run('-framerate 30 -pattern_type glob -i /data/*.png -i /data/audio.ogg -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out.mp4', { outputPath: 'out.mp4' });
18+
await worker.run('-framerate 30 -pattern_type glob -i /data/*.png -i /data/audio.ogg -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out.mp4', { output: 'out.mp4' });
1919
const { data } = await worker.read('out.mp4');
2020
console.log('Complete transcoding');
2121
await worker.remove('audio.ogg');

examples/node/run.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const worker = createWorker({
99
await worker.load();
1010
console.log('Start transcoding');
1111
await worker.write('flame.avi', '../../tests/assets/flame.avi');
12-
await worker.run('-i /data/flame.avi flame.mp4', { inputPath: 'flame.avi', outputPath: 'flame.mp4' });
12+
await worker.run('-i /data/flame.avi flame.mp4', { input: 'flame.avi', output: 'flame.mp4' });
1313
const { data } = await worker.read('flame.mp4');
1414
console.log('Complete transcoding');
1515
fs.writeFileSync('flame.mp4', Buffer.from(data));

examples/node/trim.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const worker = createWorker({
99
await worker.load();
1010
console.log('Start trimming');
1111
await worker.write('flame.avi', '../../tests/assets/flame.avi');
12-
await worker.trim('flame.avi', 'flame_trim.avi', 1, 2);
12+
await worker.trim('flame.avi', 'flame_trim.avi', 0, 10);
1313
const { data } = await worker.read('flame_trim.avi');
1414
console.log('Complete trimming');
1515
fs.writeFileSync('flame_trim.avi', Buffer.from(data));

src/createWorker.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -106,33 +106,35 @@ module.exports = (_options = {}) => {
106106
}))
107107
);
108108

109-
const transcode = (inputPath, outputPath, opts = '', del = true, jobId) => (
109+
const transcode = (input, output, opts = '', del = true, jobId) => (
110110
run(
111-
`${opts} -i /data/${inputPath} ${outputPath}`,
112-
{ inputPath, outputPath, del },
111+
`${opts} -i /data/${input} ${output}`,
112+
{ input, output, del },
113113
jobId,
114114
)
115115
);
116116

117-
const trim = (inputPath, outputPath, from, to, opts = '', del = true, jobId) => (
117+
const trim = (input, output, from, to, opts = '', del = true, jobId) => (
118118
run(
119-
`${opts} -i /data/${inputPath} -ss ${from} -to ${to} -c copy ${outputPath}`,
120-
{ inputPath, outputPath, del },
119+
`${opts} -i /data/${input} -ss ${from} -to ${to} -c copy ${output}`,
120+
{ input, output, del },
121121
jobId,
122122
)
123123
);
124124

125-
const concatDemuxer = async (inputPaths, outputPath, opts = '', del = true, jobId) => {
126-
const text = inputPaths.reduce((acc, input) => `${acc}\nfile ${input}`, '');
125+
const concatDemuxer = async (input, output, opts = '', del = true, jobId) => {
126+
const text = input.reduce((acc, path) => `${acc}\nfile ${path}`, '');
127127
await writeText('concat_list.txt', text);
128-
return run(`${opts} -f concat -safe 0 -i /data/concat_list.txt -c copy ${outputPath}`,
129-
{ del, outputPath, inputPaths: [...inputPaths, 'concat_list.txt'] },
128+
return run(`${opts} -f concat -safe 0 -i /data/concat_list.txt -c copy ${output}`,
129+
{ del, output, input: [...input, 'concat_list.txt'] },
130130
jobId);
131131
};
132132

133133
const ls = (path, jobId) => (
134134
startJob(createJob({
135-
id: jobId, action: 'ls', payload: { path },
135+
id: jobId,
136+
action: 'FS',
137+
payload: { method: 'readdir', args: [path] },
136138
}))
137139
);
138140

@@ -154,10 +156,13 @@ module.exports = (_options = {}) => {
154156
if (status === 'resolve') {
155157
log(`[${workerId}]: Complete ${jobId}`);
156158
let d = data;
157-
if (action === 'read') {
158-
d = Uint8Array.from({ ...data, length: Object.keys(data).length });
159-
} else {
160-
logger(d);
159+
if (action === 'FS') {
160+
const { method, data: _data } = data;
161+
if (method === 'readFile') {
162+
d = Uint8Array.from({ ..._data, length: Object.keys(_data).length });
163+
} else {
164+
d = _data;
165+
}
161166
}
162167
resolves[action]({ jobId, data: d });
163168
} else if (status === 'reject') {

src/worker-script/index.js

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,12 @@
11
require('regenerator-runtime/runtime');
22
const defaultArgs = require('./constants/defaultArgs');
3+
const strList2ptr = require('./utils/strList2ptr');
34

45
let action = 'unknown';
56
let Module = null;
67
let adapter = null;
78
let ffmpeg = null;
89

9-
const str2ptr = (s) => {
10-
const ptr = Module._malloc((s.length + 1) * Uint8Array.BYTES_PER_ELEMENT);
11-
for (let i = 0; i < s.length; i += 1) {
12-
Module.setValue(ptr + i, s.charCodeAt(i), 'i8');
13-
}
14-
Module.setValue(ptr + s.length, 0, 'i8');
15-
return ptr;
16-
};
17-
18-
const strList2ptr = (strList) => {
19-
const listPtr = Module._malloc(strList.length * Uint32Array.BYTES_PER_ELEMENT);
20-
21-
strList.forEach((s, idx) => {
22-
const strPtr = str2ptr(s);
23-
Module.setValue(listPtr + (4 * idx), strPtr, 'i32');
24-
});
25-
26-
return listPtr;
27-
};
28-
2910
const load = ({ workerId, payload: { options: { corePath } } }, res) => {
3011
if (Module == null) {
3112
const Core = adapter.getCore(corePath);
@@ -54,33 +35,57 @@ const syncfs = async ({
5435
res.resolve({ message: `Sync file system with populate=${populate}` });
5536
};
5637

57-
const ls = ({
38+
const FS = ({
5839
payload: {
59-
path,
40+
method,
41+
args,
6042
},
6143
}, res) => {
62-
const dirs = Module.FS.readdir(path);
63-
res.resolve({ message: `List path ${path}`, dirs });
44+
const data = Module.FS[method](...args);
45+
res.resolve({
46+
message: `${method} ${args.join(',')}`,
47+
method,
48+
data,
49+
});
6450
};
6551

6652
const run = async ({
6753
payload: {
6854
args: _args,
6955
options: {
70-
inputPath, inputPaths, outputPath, del,
56+
input, output, del = true,
7157
},
7258
},
7359
}, res) => {
7460
const args = [...defaultArgs, ..._args.trim().split(' ')];
75-
ffmpeg(args.length, strList2ptr(args));
76-
await adapter.fs.writeFile(outputPath, Module.FS.readFile(outputPath));
77-
Module.FS.unlink(outputPath);
78-
if (del && typeof inputPath === 'string') {
79-
await adapter.fs.deleteFile(inputPath);
80-
} else if (del && Array.isArray(inputPaths)) {
81-
inputPaths.reduce((promise, input) => promise.then(() => adapter.fs.deleteFile(input)),
82-
Promise.resolve());
61+
ffmpeg(args.length, strList2ptr(Module, args));
62+
63+
/*
64+
* After executing the ffmpeg command, the data is saved in MEMFS,
65+
* if `output` is specified in the options, here ffmpeg.js will move
66+
* these files to IDBFS or NODEFS here.
67+
*/
68+
if (typeof output === 'string') {
69+
await adapter.fs.writeFile(output, Module.FS.readFile(output));
70+
Module.FS.unlink(output);
71+
} else if (Array.isArray(output)) {
72+
await Promise.all(output.map(async (p) => {
73+
await adapter.fs.writeFile(p, Module.FS.readFile(p));
74+
Module.FS.unlink(p);
75+
}));
8376
}
77+
78+
/*
79+
* To prevent input files occupy filesystem without notice,
80+
* if `input` is specified in the options, ffmpeg.js cleans these
81+
* files for you
82+
*/
83+
if (del && typeof input === 'string') {
84+
await adapter.fs.deleteFile(input);
85+
} else if (del && Array.isArray(input)) {
86+
await Promise.all(input.map((p) => adapter.fs.deleteFile(p)));
87+
}
88+
8489
res.resolve({ message: `Complete ${args.join(' ')}` });
8590
};
8691

@@ -100,8 +105,8 @@ exports.dispatchHandlers = (packet, send) => {
100105
try {
101106
({
102107
load,
103-
ls,
104108
syncfs,
109+
FS,
105110
run,
106111
})[packet.action](packet, res);
107112
} catch (err) {

0 commit comments

Comments
 (0)