commit a1334c60f3d3e8091c968063881c818e18943406 Author: Jerome Wu Date: Sun Oct 20 22:37:37 2019 +0800 Init commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1e7d4f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +. !text !filter !merge !diff diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae027b2 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +FFmpeg.js +========= + +A FFmpeg WebAssembly version built from scratch, you can learn how to do it from this series of stories: [Build FFmpeg WebAssembly version (=ffmpeg.js)](https://medium.com/@jeromewus/build-ffmpeg-webassembly-version-ffmpeg-js-part-1-preparation-ed12bf4c8fac). + +--- + +## Installation + +``` +$ npm install @ffmpeg/ffmpeg +``` + +## Example + +```javascript +const fs = require('fs'); +const ffmpeg = require('@ffmpeg/ffmpeg'); + +(async () => { + await ffmpeg.load(); + const data = ffmpeg.transcode('./test.avi', 'mp4'); + fs.wrieFileSync('./test.mp4', data); +})(); +``` diff --git a/examples/transcode.js b/examples/transcode.js new file mode 100755 index 0000000..724a182 --- /dev/null +++ b/examples/transcode.js @@ -0,0 +1,10 @@ +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); +})(); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8557910 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "@ffmpeg/ffmpeg", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@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==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c67bb22 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "@ffmpeg/ffmpeg", + "version": "0.1.0", + "description": "FFmpeg WebAssembly version", + "main": "src/index.js", + "directories": { + "example": "examples" + }, + "scripts": { + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/jeromewu/ffmpeg.js.git" + }, + "keywords": [ + "ffmpeg", + "WebAssembly", + "video" + ], + "author": "Jerome Wu ", + "license": "MIT", + "bugs": { + "url": "https://github.com/jeromewu/ffmpeg.js/issues" + }, + "homepage": "https://github.com/jeromewu/ffmpeg.js#readme", + "dependencies": { + "@ffmpeg/core": "^0.1.0" + } +} diff --git a/src/constants/defaultArgs.js b/src/constants/defaultArgs.js new file mode 100755 index 0000000..cf5c078 --- /dev/null +++ b/src/constants/defaultArgs.js @@ -0,0 +1,6 @@ +module.exports = [ + './ffmpeg', // args[0] is always binary path + '-nostdin', // Disable interaction mode + '-loglevel', + 'quiet', +]; diff --git a/src/index.js b/src/index.js new file mode 100755 index 0000000..d1c275c --- /dev/null +++ b/src/index.js @@ -0,0 +1,7 @@ +const load = require('./load'); +const transcode = require('./transcode'); + +module.exports = { + load, + transcode, +}; diff --git a/src/load.js b/src/load.js new file mode 100755 index 0000000..f7fc748 --- /dev/null +++ b/src/load.js @@ -0,0 +1,12 @@ +const { setModule } = require('./util/module'); +const FFmpegCore = require('@ffmpeg/core'); + +module.exports = () => ( + new Promise((resolve, reject) => { + FFmpegCore() + .then((Module) => { + setModule(Module); + resolve(); + }); + }) +); diff --git a/src/transcode.js b/src/transcode.js new file mode 100755 index 0000000..ce76d43 --- /dev/null +++ b/src/transcode.js @@ -0,0 +1,17 @@ +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)); +}; diff --git a/src/util/getFFmpeg.js b/src/util/getFFmpeg.js new file mode 100755 index 0000000..18c6692 --- /dev/null +++ b/src/util/getFFmpeg.js @@ -0,0 +1,6 @@ +const { getModule } = require('./module'); + +module.exports = () => { + const Module = getModule(); + return Module.cwrap('ffmpeg', 'number', ['number', 'number']); +}; diff --git a/src/util/module.js b/src/util/module.js new file mode 100755 index 0000000..be1a631 --- /dev/null +++ b/src/util/module.js @@ -0,0 +1,7 @@ +let Module = null; + +exports.setModule = m => { + Module = m; +}; + +exports.getModule = () => Module; diff --git a/src/util/str2ptr.js b/src/util/str2ptr.js new file mode 100755 index 0000000..9021854 --- /dev/null +++ b/src/util/str2ptr.js @@ -0,0 +1,11 @@ +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++) { + Module.setValue(ptr+i, s.charCodeAt(i), 'i8'); + } + Module.setValue(ptr+s.length, 0, 'i8'); + return ptr; +}; diff --git a/src/util/strList2ptr.js b/src/util/strList2ptr.js new file mode 100755 index 0000000..1eeb5b9 --- /dev/null +++ b/src/util/strList2ptr.js @@ -0,0 +1,14 @@ +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; +}; diff --git a/tests/assets/test.avi b/tests/assets/test.avi new file mode 100755 index 0000000..cc5ef6a Binary files /dev/null and b/tests/assets/test.avi differ