Skip to content

Commit

Permalink
Align codebase with current emscripten, ffmpeg, etc; enable hevc deco…
Browse files Browse the repository at this point in the history
…ding.
  • Loading branch information
duanyao committed Dec 31, 2019
1 parent 8c64c60 commit c31de35
Show file tree
Hide file tree
Showing 6 changed files with 407 additions and 83 deletions.
100 changes: 56 additions & 44 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ module.exports = function (grunt) {
'h263i',
'h263p',
'h264',
'h264_crystalhd',
'h264_vda',
'h264_vdpau',
'hevc',
'libvpx_vp8',
'libvpx_vp9',
'mjpeg',
Expand All @@ -27,17 +25,10 @@ module.exports = function (grunt) {
'mp3float',
'mp3on4',
'mp3on4float',
'mpeg1_vdpau',
'mpeg1video',
'mpeg2_crystalhd',
'mpeg2video',
'mpeg4',
'mpeg4_crystalhd',
'mpeg4_vdpau',
'mpeg_vdpau',
'mpeg_xvmc',
'mpegvideo',
'msmpeg4_crystalhd',
'msmpeg4v1',
'msmpeg4v2',
'msmpeg4v3',
Expand Down Expand Up @@ -81,8 +72,6 @@ module.exports = function (grunt) {
'rv40',
'sipr',
'vc1',
'vc1_crystalhd',
'vc1_vdpau',
'vc1image',
'vorbis',
'vp6',
Expand All @@ -96,8 +85,6 @@ module.exports = function (grunt) {
'wmv1',
'wmv2',
'wmv3',
'wmv3_crystalhd',
'wmv3_vdpau',
'wmv3image',
'zlib',
];
Expand Down Expand Up @@ -147,7 +134,10 @@ module.exports = function (grunt) {

var ffParsers = [
'aac',
'aac_latm'
'aac_latm',
'h264',
'hevc',
'opus',
];

var ffEncoders = [
Expand Down Expand Up @@ -210,17 +200,17 @@ module.exports = function (grunt) {
// '-v' enables verbose output during 'make'. Note this may break grunt-exec
// (you can run 'emmake make' directly in console instead if you really need verbose).
//' -v' +
' --cc="emcc" --prefix=' + distPath +
' --cc="emcc" --ranlib="emranlib" --prefix=' + distPath +
' --pkg-config="' + pkgConfigScript + '" ' +
' --optflags="-O3" --extra-cflags="-I' + distPath + '/include -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600" ' +
' --optflags="-O3" --extra-cflags="-I' + distPath + '/include -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -fno-stack-protector " ' +
' --extra-ldflags="-L' + distPath + '/lib" ' +
' --enable-cross-compile --target-os=none --arch=x86_32 --cpu=generic --disable-debug --disable-runtime-cpudetect ' +
' --disable-stripping ' +
' --disable-programs ' +
' --disable-ffplay --disable-ffprobe --disable-ffserver --disable-asm --disable-doc --disable-pthreads --disable-w32threads ' +
' --disable-ffplay --disable-ffprobe --disable-asm --disable-doc --disable-pthreads --disable-w32threads ' +
' --disable-network --disable-iconv --disable-xlib ' +
' --enable-gpl --enable-libvpx --enable-libx264 ' +
' --enable-libmp3lame --enable-libopus --enable-libopenh264 ';
' --enable-libmp3lame --enable-libopus --enable-libopenh264';

var ffmpegFullConfig = ffmpegConfigShared + ' --enable-protocol=file ';

Expand All @@ -236,8 +226,8 @@ module.exports = function (grunt) {
opus: {
repo: 'https://github.com/xiph/opus.git',
pre: 'sh autogen.sh',
configure: 'emconfigure ./configure CFLAGS=-O3 --prefix=' + distPath + ' --enable-shared=no --disable-asm ' +
'--disable-rtcd', // --enable-intrinsics'
configure: 'emconfigure ./configure CFLAGS="-O3" --prefix=' + distPath + ' --enable-shared=no --disable-asm ' +
'--disable-rtcd --disable-stack-protector', // --enable-intrinsics'
},
lame: {
repo: 'https://github.com/rbrito/lame.git',
Expand All @@ -246,26 +236,27 @@ module.exports = function (grunt) {
},
libvpx: {
repo: 'https://github.com/webmproject/libvpx.git',
needPatch: true,
needPatch: false,
configure: 'emconfigure ./configure --prefix=' + distPath + ' --disable-examples --disable-docs ' +
' --disable-runtime-cpu-detect --disable-multithread --target=generic-gnu --extra-cflags=-O3',
make: 'emmake make SHELL="/bin/bash -x" -j' + paraMake
make: 'emmake make SHELL="/bin/bash -x" -j' + paraMake,
postMake: 'emranlib libvpx.a', // https://github.com/emscripten-core/emscripten/issues/9705
},
x264: {
repo: 'git://git.videolan.org/x264.git',
needPatch: true,
repo: 'https://code.videolan.org/videolan/x264.git',
needPatch: false,
configure: 'emconfigure ./configure --disable-thread --disable-asm --disable-opencl ' +
' --host=i686-pc-linux-gnu --disable-cli --enable-shared --disable-gpl --prefix=' + distPath,
make: 'emmake make SHELL="/bin/bash -x" -j' + paraMake
},
openh264: {
repo: 'https://github.com/cisco/openh264.git',
make: 'emmake make ARCH=mips CFLAGS_OPT=-O3 -j' + paraMake,
make: 'emmake make SHELL="/bin/bash -x" ARCH=mips CFLAGS="-O3 -fno-stack-protector" -j' + 1, //paraMake,
install: 'emmake make ARCH=mips PREFIX=' + distPath + ' install-headers install-shared',
},
zlib: {
repo: 'https://github.com/madler/zlib.git',
configure: 'emconfigure ./configure --prefix=' + distPath + ' --64 --static',
configure: 'emconfigure ./configure --prefix=' + distPath + ' --static',
make: 'emmake make CFLAGS="-O3" SHELL="/bin/bash -x" -j' + paraMake,
},
ffmpeg: {
Expand All @@ -281,6 +272,14 @@ module.exports = function (grunt) {

//==================== Add grunt tasks =========================

function makeCmd(taskName, cmdStr) {
function cmd() {
console.log('>>> exec: ' + taskName + ': ' + cmdStr);
return cmdStr;
}
return cmd;
}

var execConfigs = {};

var cloneSourceTasks = [];
Expand Down Expand Up @@ -309,20 +308,20 @@ module.exports = function (grunt) {
var repoInfo = nativeRepos[repoName];
var cloneTask = 'clone-' + repoName;
execConfigs[cloneTask] = {
command: 'git clone --depth ' + cloneDepth + ' ' + repoInfo.repo + ' "' + localPath + '"',
command: makeCmd(cloneTask, 'git clone --depth ' + cloneDepth + ' ' + repoInfo.repo + ' "' + localPath + '"'),
};
cloneSourceTasks.push('exec:' + cloneTask);

var resetTask = 'reset-' + repoName;
execConfigs[resetTask] = {
command: 'git reset --hard',
command: makeCmd(resetTask, 'git reset --hard'),
cwd: localPath,
};
resetTasks.push('exec:' + resetTask);

var pullTask = 'pull-' + repoName;
execConfigs[pullTask] = {
command: 'git pull',
command: makeCmd(pullTask, 'git pull'),
cwd: localPath,
};
pullTasks.push('exec:' + pullTask);
Expand All @@ -331,14 +330,14 @@ module.exports = function (grunt) {
var patchFile = path.join(rootPath, 'patch', repoName + '.patch');
var genPatchTask = 'gen-patch-' + repoName;
execConfigs[genPatchTask] = {
command: 'git diff > "' + patchFile + '"',
command: makeCmd(genPatchTask, 'git diff > "' + patchFile + '"'),
cwd: localPath,
};
genPatchTasks.push('exec:' + genPatchTask);

var applyPatchTask = 'apply-patch-' + repoName;
execConfigs[applyPatchTask] = {
command: 'patch -p1 -d . ' + '< "' + patchFile + '"',
command: makeCmd(applyPatchTask, 'patch -p1 -d . ' + '< "' + patchFile + '"'),
cwd: localPath,
};
patchTasks.push('exec:' + resetTask);
Expand All @@ -348,7 +347,7 @@ module.exports = function (grunt) {
if (repoInfo.pre) {
var preTask = 'pre-' + repoName;
execConfigs[preTask] = {
command: repoInfo.pre,
command: makeCmd(preTask, repoInfo.pre),
cwd: localPath,
};
if (repoName !== 'ffmpeg') configDepsTasks.push('exec:' + preTask);
Expand All @@ -357,65 +356,78 @@ module.exports = function (grunt) {
if (repoInfo.configure) {
var configTask = 'configure-' + repoName;
execConfigs[configTask] = {
command: repoInfo.configure,
command: makeCmd(configTask, repoInfo.configure),
cwd: localPath,
};
if (repoName !== 'ffmpeg') configDepsTasks.push('exec:' + configTask);
}

var makeTask = 'make-' + repoName;
execConfigs[makeTask] = {
command: repoInfo.make || 'emmake make -j' + paraMake,
command: makeCmd(makeTask, repoInfo.make || 'emmake make -j' + paraMake),
cwd: localPath,
};
if (repoName !== 'ffmpeg') makeDepsTasks.push('exec:' + makeTask);

if (repoInfo.postMake) {
var postMakeTask = 'postMake-' + repoName;
execConfigs[postMakeTask] = {
command: makeCmd(postMakeTask, repoInfo.postMake),
cwd: localPath,
};
if (repoName !== 'ffmpeg') makeDepsTasks.push('exec:' + postMakeTask);
}

var installTask = 'install-' + repoName;
execConfigs[installTask] = {
command: repoInfo.install || 'emmake make install',
command: makeCmd(installTask, repoInfo.install || 'emmake make install'),
cwd: localPath,
};
if (repoName !== 'ffmpeg') makeDepsTasks.push('exec:' + installTask);

var cleanTask = 'clean-' + repoName;
execConfigs[cleanTask] = {
command: repoInfo.clean || 'emmake make clean',
command: makeCmd(cleanTask, repoInfo.clean || 'emmake make clean'),
cwd: localPath,
};
cleanTasks.push('exec:' + cleanTask);
}

var EM_CPPFLAGS = ' --bind -O3 -c -v -std=c++11 -I' + distPath + '/include ';
var EM_LDFLAGS = ' -shared -L' + distPath + '/lib -lavutil -lavformat -lavcodec -lswscale -lswresample -lavutil ' +
' -lz -lmp3lame -lvpx -lx264 -lopus -lopenh264 -lm ';
var EM_JSFLAGS = ' --bind -O3 -v -s OUTLINING_LIMIT=100000 -s VERBOSE=1 -s TOTAL_MEMORY=67108864 ';
' -lz -lmp3lame -lvpx -lx264 -lopus -lopenh264 -lm ';
var EM_JSFLAGS = ' --bind -O3 -v -s VERBOSE=1 -s TOTAL_MEMORY=67108864 ' +
' -s ERROR_ON_UNDEFINED_SYMBOLS=0 ' + // fix "undefined symbol: pthread_attr_setschedpolicy"
' -lworkerfs.js ' // enable WORKERFS
;
var codeboxSrc = ['CodecBoxDecoder', 'embinder'];
var codeboxTasks = [];
var srcDir = path.join(rootPath, 'src');

codeboxSrc.forEach(function(src) {
var compileTask = 'emcc-' + src;
execConfigs[compileTask] = {
command: 'emcc -o ' + src + '.o ' + EM_CPPFLAGS + ' ' + src + '.cpp',
command: makeCmd(compileTask, 'emcc -o ' + src + '.o ' + EM_CPPFLAGS + ' ' + src + '.cpp'),
cwd: srcDir,
}
codeboxTasks.push('exec:' + compileTask);
});

execConfigs.emld = {
command: 'emcc -o codecbox.so ' + codeboxSrc.map(function(src) { return src + '.o' }).join(' ') + ' ' + EM_LDFLAGS,
command: makeCmd('emld', 'emcc -o codecbox.so ' + codeboxSrc.map(function(src) { return src + '.o' }).join(' ') + ' ' + EM_LDFLAGS),
cwd: srcDir,
};

execConfigs.emjs = {
command: 'emcc -o codecbox.js ' + EM_JSFLAGS + ' codecbox.so ' +
distPath + '/lib/libx264.so ' + distPath + '/lib/libopenh264.so',
command: makeCmd('emjs', 'emcc -o codecbox.js ' + EM_JSFLAGS + ' codecbox.so ' +
distPath + '/lib/libx264.so ' + distPath + '/lib/libopenh264.so '
),
cwd: srcDir,
};
codeboxTasks.push('exec:emld', 'exec:emjs');

execConfigs['clean-codecbox'] = {
command: 'rm codecbox.js *.so *.o *.mem',
command: makeCmd('clean-codecbox', 'rm -f codecbox.js *.so *.o *.mem *.wasm'),
cwd: srcDir,
}
cleanTasks.push('exec:clean-codecbox');
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# codecbox.js

Codecbox.js is a pure javascript library providing fine-grained APIs for video/audio processing (currently only decoding is supported). Codecbox.js is based on [FFmpeg](http://www.ffmpeg.org/) and related libraries, which are compiled by [emscripten](http://kripken.github.io/emscripten-site/) into [asm.js](http://asmjs.org). Codecbox.js should run reasonably well in browsers with web worker and asm.js support.
Codecbox.js is a pure javascript library providing fine-grained APIs for video/audio processing (currently only decoding is supported). Codecbox.js is based on [FFmpeg](http://www.ffmpeg.org/) and related libraries, which are compiled by [emscripten](https://emscripten.org/) into [wasm](https://webassembly.org/)([asm.js](http://asmjs.org) is also possible). Codecbox.js should run reasonably well in browsers with web worker and wasm support.

View the [demo page](http://duanyao.github.io/codecbox.js/).

Expand All @@ -9,18 +9,21 @@ Currently codecbox.js is only provided as source code, you have to build it your
## Build
You need a Linux or similar system to build codecbox.js.

1. Install [emscripten](http://kripken.github.io/emscripten-site/docs/getting_started/index.html), the C/C++ to asm.js comipler. Node.js should be installed as well.
1. Install [emscripten](https://emscripten.org/), the C/C++ to wasm/asm.js comipler. Node.js should be installed as well.

2. Install [grunt](http://gruntjs.com/), the build runner for JS.
2. Install [grunt](http://gruntjs.com/), the build runner for JS. For short, run `npm install -g grunt-cli`.

3. Clone codecbox.js repostory (suppose cloned to `codecbox.js` dir).

4. Go to `codecbox.js` dir in a terminal, execute command `npm install`. Do the following steps in this dir as well.

5. Execute command `grunt init`. This clones repos of ffmpeg and its external libraries (including [x264](git://git.videolan.org/x264.git), [openh264](https://github.com/cisco/openh264.git), [libvpx](https://github.com/webmproject/libvpx.git), [libopus](https://github.com/xiph/opus.git), [lame](https://github.com/rbrito/lame.git), and [zlib](https://github.com/madler/zlib.git)), so make sure you have good internet connection.
This project try to build the latest master branch of these libraries. If you want to stick to specific versions, go to `build/<lib_name>` and checkout manually. You may also want to adjust and apply patches in `patch` dir.
5. Execute command `grunt init`. This clones repos of [ffmpeg](https://github.com/FFmpeg/FFmpeg.git) and its external libraries (including [x264](git://git.videolan.org/x264.git), [openh264](https://github.com/cisco/openh264.git), [libvpx](https://github.com/webmproject/libvpx.git), [libopus](https://github.com/xiph/opus.git), [lame](https://github.com/rbrito/lame.git), and [zlib](https://github.com/madler/zlib.git)), so make sure you have good internet connection.

6. Execute command `grunt build`. This should compile ffmpeg etc. and produces `codecbox.js` and `codecbox.js.mem` in `src` dir.
git may fail to clone some repo due to temporal network issues, if so you may repeat `grunt init --force` multiple times until all repos above are cloned into `build/<lib_name>` dir.

This project try to build the latest master branch of these libraries. If you want to stick to specific versions, go to `build/<lib_name>` and checkout manually. You may also want to adjust and apply patches in `patch` dir -- currently (2019-12-31) no patch is required.

6. Execute command `grunt build`. This should compile ffmpeg etc. and produces `codecbox.js` and `codecbox.wasm` in `src` dir.

7. Load `src/demo-player.html` and try to play a media file (most common audio/video formats should be fine).
This demo uses ffmpeg to decode media files, and renders video frames via HTML Canvas, and plays sound via Web Audio API.
Expand Down
Loading

0 comments on commit c31de35

Please sign in to comment.