Update options in Worker.run() to make it more clear
This commit is contained in:
parent
4ee05bbb9b
commit
5305ea6c7e
26
docs/api.md
26
docs/api.md
@ -8,6 +8,7 @@
|
|||||||
- [Worker.remove](#worker-remove)
|
- [Worker.remove](#worker-remove)
|
||||||
- [Worker.transcode](#worker-transcode)
|
- [Worker.transcode](#worker-transcode)
|
||||||
- [Worker.trim](#worker-trim)
|
- [Worker.trim](#worker-trim)
|
||||||
|
- [Worker.concatDemuxer](#worker-concatDemuxer)
|
||||||
- [Worker.run](#worker-run)
|
- [Worker.run](#worker-run)
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -135,14 +136,14 @@ Worker.remove() removes files in file system, it will be better to delete unused
|
|||||||
|
|
||||||
<a name="worker-transcode"></a>
|
<a name="worker-transcode"></a>
|
||||||
|
|
||||||
### Worker.transcode(inputPath, outputPath, options, del, jobId): Promise
|
### Worker.transcode(input, output, options, del, jobId): Promise
|
||||||
|
|
||||||
Worker.transcode() transcode a video file to another format.
|
Worker.transcode() transcode a video file to another format.
|
||||||
|
|
||||||
**Arguments:**
|
**Arguments:**
|
||||||
|
|
||||||
- `inputPath` input file path, the input file should be written through Worker.write()
|
- `input` input file path, the input file should be written through Worker.write()
|
||||||
- `outputPath` output file path, can be read with Worker.read() later
|
- `output` output file path, can be read with Worker.read() later
|
||||||
- `options` a string to add extra arguments to ffmpeg
|
- `options` a string to add extra arguments to ffmpeg
|
||||||
- `del` a boolean to determine whether to delete input file after the task is done, default: true
|
- `del` a boolean to determine whether to delete input file after the task is done, default: true
|
||||||
- `jobId` check Worker.load()
|
- `jobId` check Worker.load()
|
||||||
@ -157,7 +158,7 @@ Worker.transcode() transcode a video file to another format.
|
|||||||
|
|
||||||
<a name="worker-trim"></a>
|
<a name="worker-trim"></a>
|
||||||
|
|
||||||
### Worker.trim(inputPath, outputPath, from, to, options, del, jobId): Promise
|
### Worker.trim(input, output, from, to, options, del, jobId): Promise
|
||||||
|
|
||||||
Worker.trim() trims video to specific interval.
|
Worker.trim() trims video to specific interval.
|
||||||
|
|
||||||
@ -181,14 +182,14 @@ Worker.trim() trims video to specific interval.
|
|||||||
|
|
||||||
<a name="worker-concatDemuxer"></a>
|
<a name="worker-concatDemuxer"></a>
|
||||||
|
|
||||||
### Worker.concatDemuxer(inputPaths, outputPath, options, del, jobId): Promise
|
### Worker.concatDemuxer(input, output, options, del, jobId): Promise
|
||||||
|
|
||||||
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)
|
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)
|
||||||
|
|
||||||
**Arguments:**
|
**Arguments:**
|
||||||
|
|
||||||
- `inputPaths` input file paths as an Array, the input files should be written through Worker.write()
|
- `input` input file paths as an Array, the input files should be written through Worker.write()
|
||||||
- `outputPath` output file path, can be read with Worker.read() later
|
- `output` output file path, can be read with Worker.read() later
|
||||||
- `options` a string to add extra arguments to ffmpeg
|
- `options` a string to add extra arguments to ffmpeg
|
||||||
- `del` a boolean to determine whether to delete input file after the task is done, default: true
|
- `del` a boolean to determine whether to delete input file after the task is done, default: true
|
||||||
- `jobId` check Worker.load()
|
- `jobId` check Worker.load()
|
||||||
@ -197,7 +198,7 @@ Worker.concatDemuxer() concatenates multiple videos using concatDemuxer. This me
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
(async () => {
|
(async () => {
|
||||||
await worker.trim(["flame-1.avi", "flame-2.avi"], "output.mp4");
|
await worker.concatDemuxer(["flame-1.avi", "flame-2.avi"], "output.mp4");
|
||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -210,7 +211,10 @@ Worker.run() is similar to FFmpeg cli tool, aims to provide maximum flexiblity f
|
|||||||
**Arguments:**
|
**Arguments:**
|
||||||
|
|
||||||
- `args` a string to represent arguments, note: inputPath must start with `/data/` as worker.write write to this path by default.
|
- `args` a string to represent arguments, note: inputPath must start with `/data/` as worker.write write to this path by default.
|
||||||
- `options` a object to define the value for inputPath, outputPath and del.
|
- `options` a object to define the value for input, output and del.
|
||||||
|
- `input` a string or an array of strings to indicate input files, ffmpeg.js deletes these files for you.
|
||||||
|
- `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()
|
||||||
|
- `del` a boolean to determine whether to delete input file after the task is done, default: true
|
||||||
- `jobId` check Worker.load()
|
- `jobId` check Worker.load()
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
@ -218,8 +222,8 @@ Worker.run() is similar to FFmpeg cli tool, aims to provide maximum flexiblity f
|
|||||||
```javascript
|
```javascript
|
||||||
(async () => {
|
(async () => {
|
||||||
await worker.run("-i /data/flame.avi -s 1920x1080 output.mp4", {
|
await worker.run("-i /data/flame.avi -s 1920x1080 output.mp4", {
|
||||||
inputPath: "flame.avi",
|
input: "flame.avi",
|
||||||
outputPath: "output.mp4"
|
output: "output.mp4"
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
await worker.write(`tmp.${num}.png`, `../../tests/assets/triangle/tmp.${num}.png`);
|
await worker.write(`tmp.${num}.png`, `../../tests/assets/triangle/tmp.${num}.png`);
|
||||||
}
|
}
|
||||||
message.innerHTML = 'Start transcoding';
|
message.innerHTML = 'Start transcoding';
|
||||||
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' });
|
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' });
|
||||||
const { data } = await worker.read('out.mp4');
|
const { data } = await worker.read('out.mp4');
|
||||||
await worker.remove('audio.ogg');
|
await worker.remove('audio.ogg');
|
||||||
for (let i = 0; i < 60; i += 1) {
|
for (let i = 0; i < 60; i += 1) {
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
await worker.load();
|
await worker.load();
|
||||||
message.innerHTML = 'Start transcoding';
|
message.innerHTML = 'Start transcoding';
|
||||||
await worker.write(name, files[0]);
|
await worker.write(name, files[0]);
|
||||||
await worker.run(`-i /data/${name} output.mp4`, { inputPath: name, outputPath: 'output.mp4' });
|
await worker.run(`-i /data/${name} output.mp4`, { input: name, output: 'output.mp4' });
|
||||||
message.innerHTML = 'Complete transcoding';
|
message.innerHTML = 'Complete transcoding';
|
||||||
const { data } = await worker.read('output.mp4');
|
const { data } = await worker.read('output.mp4');
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
const { createWorker } = FFmpeg;
|
const { createWorker } = FFmpeg;
|
||||||
const worker = createWorker({
|
const worker = createWorker({
|
||||||
corePath: '../../node_modules/@ffmpeg/core/ffmpeg-core.js',
|
corePath: '../../node_modules/@ffmpeg/core/ffmpeg-core.js',
|
||||||
|
logger: ({ message }) => console.log(message),
|
||||||
progress: p => console.log(p),
|
progress: p => console.log(p),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -36,7 +37,6 @@
|
|||||||
await worker.transcode(name, 'output.mp4');
|
await worker.transcode(name, 'output.mp4');
|
||||||
message.innerHTML = 'Complete transcoding';
|
message.innerHTML = 'Complete transcoding';
|
||||||
const { data } = await worker.read('output.mp4');
|
const { data } = await worker.read('output.mp4');
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
const video = document.getElementById('output-video');
|
const video = document.getElementById('output-video');
|
||||||
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
|
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h3>Upload a mp4 (x264) video and trim its first 2 seconds and play!</h3>
|
<h3>Upload a mp4 (x264) video and trim its first 10 seconds and play!</h3>
|
||||||
<video id="output-video" controls></video><br/>
|
<video id="output-video" controls></video><br/>
|
||||||
<input type="file" id="uploader">
|
<input type="file" id="uploader">
|
||||||
<p id="message"></p>
|
<p id="message"></p>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
await worker.load();
|
await worker.load();
|
||||||
message.innerHTML = 'Start trimming';
|
message.innerHTML = 'Start trimming';
|
||||||
await worker.write(name, files[0]);
|
await worker.write(name, files[0]);
|
||||||
await worker.trim(name, 'output.mp4', 0, 2);
|
await worker.trim(name, 'output.mp4', 0, 10);
|
||||||
message.innerHTML = 'Complete trimming';
|
message.innerHTML = 'Complete trimming';
|
||||||
const { data } = await worker.read('output.mp4');
|
const { data } = await worker.read('output.mp4');
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ const worker = createWorker({
|
|||||||
await worker.write(`tmp.${num}.png`, `../../tests/assets/triangle/tmp.${num}.png`);
|
await worker.write(`tmp.${num}.png`, `../../tests/assets/triangle/tmp.${num}.png`);
|
||||||
}
|
}
|
||||||
console.log('Start transcoding');
|
console.log('Start transcoding');
|
||||||
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' });
|
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' });
|
||||||
const { data } = await worker.read('out.mp4');
|
const { data } = await worker.read('out.mp4');
|
||||||
console.log('Complete transcoding');
|
console.log('Complete transcoding');
|
||||||
await worker.remove('audio.ogg');
|
await worker.remove('audio.ogg');
|
||||||
|
@ -9,7 +9,7 @@ const worker = createWorker({
|
|||||||
await worker.load();
|
await worker.load();
|
||||||
console.log('Start transcoding');
|
console.log('Start transcoding');
|
||||||
await worker.write('flame.avi', '../../tests/assets/flame.avi');
|
await worker.write('flame.avi', '../../tests/assets/flame.avi');
|
||||||
await worker.run('-i /data/flame.avi flame.mp4', { inputPath: 'flame.avi', outputPath: 'flame.mp4' });
|
await worker.run('-i /data/flame.avi flame.mp4', { input: 'flame.avi', output: 'flame.mp4' });
|
||||||
const { data } = await worker.read('flame.mp4');
|
const { data } = await worker.read('flame.mp4');
|
||||||
console.log('Complete transcoding');
|
console.log('Complete transcoding');
|
||||||
fs.writeFileSync('flame.mp4', Buffer.from(data));
|
fs.writeFileSync('flame.mp4', Buffer.from(data));
|
||||||
|
@ -9,7 +9,7 @@ const worker = createWorker({
|
|||||||
await worker.load();
|
await worker.load();
|
||||||
console.log('Start trimming');
|
console.log('Start trimming');
|
||||||
await worker.write('flame.avi', '../../tests/assets/flame.avi');
|
await worker.write('flame.avi', '../../tests/assets/flame.avi');
|
||||||
await worker.trim('flame.avi', 'flame_trim.avi', 1, 2);
|
await worker.trim('flame.avi', 'flame_trim.avi', 0, 10);
|
||||||
const { data } = await worker.read('flame_trim.avi');
|
const { data } = await worker.read('flame_trim.avi');
|
||||||
console.log('Complete trimming');
|
console.log('Complete trimming');
|
||||||
fs.writeFileSync('flame_trim.avi', Buffer.from(data));
|
fs.writeFileSync('flame_trim.avi', Buffer.from(data));
|
||||||
|
@ -106,33 +106,35 @@ module.exports = (_options = {}) => {
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
const transcode = (inputPath, outputPath, opts = '', del = true, jobId) => (
|
const transcode = (input, output, opts = '', del = true, jobId) => (
|
||||||
run(
|
run(
|
||||||
`${opts} -i /data/${inputPath} ${outputPath}`,
|
`${opts} -i /data/${input} ${output}`,
|
||||||
{ inputPath, outputPath, del },
|
{ input, output, del },
|
||||||
jobId,
|
jobId,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const trim = (inputPath, outputPath, from, to, opts = '', del = true, jobId) => (
|
const trim = (input, output, from, to, opts = '', del = true, jobId) => (
|
||||||
run(
|
run(
|
||||||
`${opts} -i /data/${inputPath} -ss ${from} -to ${to} -c copy ${outputPath}`,
|
`${opts} -i /data/${input} -ss ${from} -to ${to} -c copy ${output}`,
|
||||||
{ inputPath, outputPath, del },
|
{ input, output, del },
|
||||||
jobId,
|
jobId,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const concatDemuxer = async (inputPaths, outputPath, opts = '', del = true, jobId) => {
|
const concatDemuxer = async (input, output, opts = '', del = true, jobId) => {
|
||||||
const text = inputPaths.reduce((acc, input) => `${acc}\nfile ${input}`, '');
|
const text = input.reduce((acc, path) => `${acc}\nfile ${path}`, '');
|
||||||
await writeText('concat_list.txt', text);
|
await writeText('concat_list.txt', text);
|
||||||
return run(`${opts} -f concat -safe 0 -i /data/concat_list.txt -c copy ${outputPath}`,
|
return run(`${opts} -f concat -safe 0 -i /data/concat_list.txt -c copy ${output}`,
|
||||||
{ del, outputPath, inputPaths: [...inputPaths, 'concat_list.txt'] },
|
{ del, output, input: [...input, 'concat_list.txt'] },
|
||||||
jobId);
|
jobId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ls = (path, jobId) => (
|
const ls = (path, jobId) => (
|
||||||
startJob(createJob({
|
startJob(createJob({
|
||||||
id: jobId, action: 'ls', payload: { path },
|
id: jobId,
|
||||||
|
action: 'FS',
|
||||||
|
payload: { method: 'readdir', args: [path] },
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -154,10 +156,13 @@ module.exports = (_options = {}) => {
|
|||||||
if (status === 'resolve') {
|
if (status === 'resolve') {
|
||||||
log(`[${workerId}]: Complete ${jobId}`);
|
log(`[${workerId}]: Complete ${jobId}`);
|
||||||
let d = data;
|
let d = data;
|
||||||
if (action === 'read') {
|
if (action === 'FS') {
|
||||||
d = Uint8Array.from({ ...data, length: Object.keys(data).length });
|
const { method, data: _data } = data;
|
||||||
|
if (method === 'readFile') {
|
||||||
|
d = Uint8Array.from({ ..._data, length: Object.keys(_data).length });
|
||||||
} else {
|
} else {
|
||||||
logger(d);
|
d = _data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resolves[action]({ jobId, data: d });
|
resolves[action]({ jobId, data: d });
|
||||||
} else if (status === 'reject') {
|
} else if (status === 'reject') {
|
||||||
|
@ -1,31 +1,12 @@
|
|||||||
require('regenerator-runtime/runtime');
|
require('regenerator-runtime/runtime');
|
||||||
const defaultArgs = require('./constants/defaultArgs');
|
const defaultArgs = require('./constants/defaultArgs');
|
||||||
|
const strList2ptr = require('./utils/strList2ptr');
|
||||||
|
|
||||||
let action = 'unknown';
|
let action = 'unknown';
|
||||||
let Module = null;
|
let Module = null;
|
||||||
let adapter = null;
|
let adapter = null;
|
||||||
let ffmpeg = 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) => {
|
const load = ({ workerId, payload: { options: { corePath } } }, res) => {
|
||||||
if (Module == null) {
|
if (Module == null) {
|
||||||
const Core = adapter.getCore(corePath);
|
const Core = adapter.getCore(corePath);
|
||||||
@ -54,33 +35,57 @@ const syncfs = async ({
|
|||||||
res.resolve({ message: `Sync file system with populate=${populate}` });
|
res.resolve({ message: `Sync file system with populate=${populate}` });
|
||||||
};
|
};
|
||||||
|
|
||||||
const ls = ({
|
const FS = ({
|
||||||
payload: {
|
payload: {
|
||||||
path,
|
method,
|
||||||
|
args,
|
||||||
},
|
},
|
||||||
}, res) => {
|
}, res) => {
|
||||||
const dirs = Module.FS.readdir(path);
|
const data = Module.FS[method](...args);
|
||||||
res.resolve({ message: `List path ${path}`, dirs });
|
res.resolve({
|
||||||
|
message: `${method} ${args.join(',')}`,
|
||||||
|
method,
|
||||||
|
data,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const run = async ({
|
const run = async ({
|
||||||
payload: {
|
payload: {
|
||||||
args: _args,
|
args: _args,
|
||||||
options: {
|
options: {
|
||||||
inputPath, inputPaths, outputPath, del,
|
input, output, del = true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, res) => {
|
}, res) => {
|
||||||
const args = [...defaultArgs, ..._args.trim().split(' ')];
|
const args = [...defaultArgs, ..._args.trim().split(' ')];
|
||||||
ffmpeg(args.length, strList2ptr(args));
|
ffmpeg(args.length, strList2ptr(Module, args));
|
||||||
await adapter.fs.writeFile(outputPath, Module.FS.readFile(outputPath));
|
|
||||||
Module.FS.unlink(outputPath);
|
/*
|
||||||
if (del && typeof inputPath === 'string') {
|
* After executing the ffmpeg command, the data is saved in MEMFS,
|
||||||
await adapter.fs.deleteFile(inputPath);
|
* if `output` is specified in the options, here ffmpeg.js will move
|
||||||
} else if (del && Array.isArray(inputPaths)) {
|
* these files to IDBFS or NODEFS here.
|
||||||
inputPaths.reduce((promise, input) => promise.then(() => adapter.fs.deleteFile(input)),
|
*/
|
||||||
Promise.resolve());
|
if (typeof output === 'string') {
|
||||||
|
await adapter.fs.writeFile(output, Module.FS.readFile(output));
|
||||||
|
Module.FS.unlink(output);
|
||||||
|
} else if (Array.isArray(output)) {
|
||||||
|
await Promise.all(output.map(async (p) => {
|
||||||
|
await adapter.fs.writeFile(p, Module.FS.readFile(p));
|
||||||
|
Module.FS.unlink(p);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To prevent input files occupy filesystem without notice,
|
||||||
|
* if `input` is specified in the options, ffmpeg.js cleans these
|
||||||
|
* files for you
|
||||||
|
*/
|
||||||
|
if (del && typeof input === 'string') {
|
||||||
|
await adapter.fs.deleteFile(input);
|
||||||
|
} else if (del && Array.isArray(input)) {
|
||||||
|
await Promise.all(input.map((p) => adapter.fs.deleteFile(p)));
|
||||||
|
}
|
||||||
|
|
||||||
res.resolve({ message: `Complete ${args.join(' ')}` });
|
res.resolve({ message: `Complete ${args.join(' ')}` });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,8 +105,8 @@ exports.dispatchHandlers = (packet, send) => {
|
|||||||
try {
|
try {
|
||||||
({
|
({
|
||||||
load,
|
load,
|
||||||
ls,
|
|
||||||
syncfs,
|
syncfs,
|
||||||
|
FS,
|
||||||
run,
|
run,
|
||||||
})[packet.action](packet, res);
|
})[packet.action](packet, res);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
8
src/worker-script/utils/str2ptr.js
Normal file
8
src/worker-script/utils/str2ptr.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = (Module, 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;
|
||||||
|
};
|
12
src/worker-script/utils/strList2ptr.js
Normal file
12
src/worker-script/utils/strList2ptr.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const str2ptr = require('./str2ptr');
|
||||||
|
|
||||||
|
module.exports = (Module, strList) => {
|
||||||
|
const listPtr = Module._malloc(strList.length * Uint32Array.BYTES_PER_ELEMENT);
|
||||||
|
|
||||||
|
strList.forEach((s, idx) => {
|
||||||
|
const strPtr = str2ptr(Module, s);
|
||||||
|
Module.setValue(listPtr + (4 * idx), strPtr, 'i32');
|
||||||
|
});
|
||||||
|
|
||||||
|
return listPtr;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user