Skip to content

Commit ea99cf3

Browse files
authored
Merge pull request #13 from santosh898/master
Implemented ConcatDemuxer.
2 parents 8956937 + a84e624 commit ea99cf3

File tree

4 files changed

+120
-13
lines changed

4 files changed

+120
-13
lines changed

docs/api.md

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
API
2-
===
1+
# API
32

43
- [createWorker()](#create-worker)
54
- [Worker.load](#worker-load)
@@ -14,6 +13,7 @@ API
1413
---
1514

1615
<a name="create-worker"></a>
16+
1717
## createWorker(options): Worker
1818

1919
createWorker is a factory function that creates a ffmpeg worker, a worker is basically a Web Worker in browser and Child Process in Node.
@@ -27,17 +27,18 @@ createWorker is a factory function that creates a ffmpeg worker, a worker is bas
2727
- `logger` a function to log the progress, a quick example is `m => console.log(m)`
2828
- `progress` a function to trace the progress, a quick example is `p => console.log(p)`
2929

30-
3130
**Examples:**
3231

3332
```javascript
3433
const { createWorker } = FFmpeg;
3534
const worker = createWorker({
36-
corePath: './node_modules/@ffmpeg/core/ffmpeg-core.js',
37-
logger: m => console.log(m),
35+
corePath: "./node_modules/@ffmpeg/core/ffmpeg-core.js",
36+
logger: m => console.log(m)
3837
});
3938
```
39+
4040
<a name="worker-load"></a>
41+
4142
### Worker.load(jobId): Promise
4243

4344
Worker.load() loads ffmpeg-core.js script (download from remote if not presented), it makes Web Worker/Child Process ready for next action.
@@ -55,6 +56,7 @@ Worker.load() loads ffmpeg-core.js script (download from remote if not presented
5556
```
5657

5758
<a name="worker-write"></a>
59+
5860
### Worker.write(path, data): Promise
5961

6062
Worker.write() writes data to specific path in Emscripten file system, it is an essential step before doing any other tasks.
@@ -68,11 +70,15 @@ Worker.write() writes data to specific path in Emscripten file system, it is an
6870

6971
```javascript
7072
(async () => {
71-
await worker.write('flame.avi', 'http://localhost:3000/tests/assets/flame.avi');
73+
await worker.write(
74+
"flame.avi",
75+
"http://localhost:3000/tests/assets/flame.avi"
76+
);
7277
})();
7378
```
7479

7580
<a name="worker-writeText"></a>
81+
7682
### Worker.writeText(path, text): Promise
7783

7884
Worker.write() writes text data to specific path in Emscripten file system.
@@ -86,11 +92,12 @@ Worker.write() writes text data to specific path in Emscripten file system.
8692

8793
```javascript
8894
(async () => {
89-
await worker.write('sub.srt', '...');
95+
await worker.write("sub.srt", "...");
9096
})();
9197
```
9298

9399
<a name="worker-read"></a>
100+
94101
### Worker.read(path, del): Promise
95102

96103
Worker.read() reads data from file system, often used to get output data after specific task.
@@ -104,11 +111,12 @@ Worker.read() reads data from file system, often used to get output data after s
104111

105112
```javascript
106113
(async () => {
107-
const { data } = await worker.read('output.mp4');
114+
const { data } = await worker.read("output.mp4");
108115
})();
109116
```
110117

111118
<a name="worker-remove"></a>
119+
112120
### Worker.remove(path): Promise
113121

114122
Worker.remove() removes files in file system, it will be better to delete unused files if you need to run ffmpeg.js multiple times.
@@ -121,11 +129,12 @@ Worker.remove() removes files in file system, it will be better to delete unused
121129

122130
```javascript
123131
(async () => {
124-
await worker.remove('output.mp4');
132+
await worker.remove("output.mp4");
125133
})();
126134
```
127135

128136
<a name="worker-transcode"></a>
137+
129138
### Worker.transcode(inputPath, outputPath, options, del, jobId): Promise
130139

131140
Worker.transcode() transcode a video file to another format.
@@ -142,11 +151,12 @@ Worker.transcode() transcode a video file to another format.
142151

143152
```javascript
144153
(async () => {
145-
await worker.transcode('flame.avi', 'output.mp4', '-s 1920x1080');
154+
await worker.transcode("flame.avi", "output.mp4", "-s 1920x1080");
146155
})();
147156
```
148157

149158
<a name="worker-trim"></a>
159+
150160
### Worker.trim(inputPath, outputPath, from, to, options, del, jobId): Promise
151161

152162
Worker.trim() trims video to specific interval.
@@ -165,11 +175,34 @@ Worker.trim() trims video to specific interval.
165175

166176
```javascript
167177
(async () => {
168-
await worker.trim('flame.avi', 'output.mp4', 1, 2);
178+
await worker.trim("flame.avi", "output.mp4", 1, 2);
179+
})();
180+
```
181+
182+
<a name="worker-concatDemuxer"></a>
183+
184+
### Worker.concatDemuxer(inputPaths, outputPath, options, del, jobId): Promise
185+
186+
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)
187+
188+
**Arguments:**
189+
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
192+
- `options` a string to add extra arguments to ffmpeg
193+
- `del` a boolean to determine whether to delete input file after the task is done, default: true
194+
- `jobId` check Worker.load()
195+
196+
**Examples:**
197+
198+
```javascript
199+
(async () => {
200+
await worker.trim(["flame-1.avi", "flame-2.avi"], "output.mp4");
169201
})();
170202
```
171203

172204
<a name="worker-run"></a>
205+
173206
### Worker.run(args, options, jobId): Promise
174207

175208
Worker.run() is similar to FFmpeg cli tool, aims to provide maximum flexiblity for users.
@@ -184,6 +217,9 @@ Worker.run() is similar to FFmpeg cli tool, aims to provide maximum flexiblity f
184217

185218
```javascript
186219
(async () => {
187-
await worker.run('-i /data/flame.avi -s 1920x1080 output.mp4', { inputPath: 'flame.avi', outputPath: 'output.mp4' });
220+
await worker.run("-i /data/flame.avi -s 1920x1080 output.mp4", {
221+
inputPath: "flame.avi",
222+
outputPath: "output.mp4"
223+
});
188224
})();
189225
```

examples/browser/concatDemuxer.html

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<html>
2+
<head>
3+
<script src="/dist/ffmpeg.dev.js"></script>
4+
<style>
5+
html,
6+
body {
7+
margin: 0;
8+
width: 100%;
9+
height: 100%;
10+
}
11+
12+
body {
13+
display: flex;
14+
flex-direction: column;
15+
align-items: center;
16+
}
17+
</style>
18+
</head>
19+
20+
<body>
21+
<h3>Select multiple video files to Concatenate</h3>
22+
<video id="output-video" controls></video><br />
23+
<input type="file" id="uploader" multiple />
24+
<p id="message"></p>
25+
<script>
26+
const { createWorker } = FFmpeg;
27+
const worker = createWorker({
28+
corePath: "../../node_modules/@ffmpeg/core/ffmpeg-core.js",
29+
logger: ({ message }) => console.log(message)
30+
});
31+
32+
const transcode = async ({ target: { files } }) => {
33+
const message = document.getElementById("message");
34+
message.innerHTML = "Loading ffmpeg-core.js";
35+
await worker.load();
36+
message.innerHTML = "Start Concating";
37+
const inputPaths = [];
38+
for (const file of files) {
39+
const { name } = file;
40+
await worker.write(name, file);
41+
inputPaths.push(name);
42+
}
43+
await worker.concatDemuxer(inputPaths, "output.mp4");
44+
message.innerHTML = "Complete Concating";
45+
const { data } = await worker.read("output.mp4");
46+
const video = document.getElementById("output-video");
47+
video.src = URL.createObjectURL(
48+
new Blob([data.buffer], {
49+
type: "video/mp4"
50+
})
51+
);
52+
};
53+
const elm = document.getElementById("uploader");
54+
elm.addEventListener("change", transcode);
55+
</script>
56+
</body>
57+
</html>

src/createWorker.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ module.exports = (_options = {}) => {
122122
)
123123
);
124124

125+
const concatDemuxer = async (inputPaths, outputPath, opts = '', del = true, jobId) => {
126+
const text = inputPaths.reduce((acc, input) => `${acc}\nfile ${input}`, '');
127+
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'] },
130+
jobId);
131+
};
132+
125133
const ls = (path, jobId) => (
126134
startJob(createJob({
127135
id: jobId, action: 'ls', payload: { path },
@@ -175,6 +183,7 @@ module.exports = (_options = {}) => {
175183
run,
176184
transcode,
177185
trim,
186+
concatDemuxer,
178187
ls,
179188
terminate,
180189
};

src/worker-script/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ const ls = ({
6666
const run = async ({
6767
payload: {
6868
args: _args,
69-
options: { inputPath, outputPath, del },
69+
options: {
70+
inputPath, inputPaths, outputPath, del,
71+
},
7072
},
7173
}, res) => {
7274
const args = [...defaultArgs, ..._args.trim().split(' ')];
@@ -75,6 +77,9 @@ const run = async ({
7577
Module.FS.unlink(outputPath);
7678
if (del && typeof inputPath === 'string') {
7779
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());
7883
}
7984
res.resolve({ message: `Complete ${args.join(' ')}` });
8085
};

0 commit comments

Comments
 (0)