Commit 66aa1dd2 authored by Jerome Wu's avatar Jerome Wu

Add libvpx in build scripts

parent e7deac90
......@@ -8,6 +8,8 @@ SCRIPT_ROOT=$(dirname $0)/wasm/build-scripts
emcc -v
# build x264
$SCRIPT_ROOT/build-x264.sh
# build libvpx
$SCRIPT_ROOT/build-libvpx.sh
# configure FFmpeg with Emscripten
$SCRIPT_ROOT/configure-ffmpeg.sh
# build ffmpeg.wasm
......
......@@ -9,7 +9,7 @@ FLAGS=(
-I. -I./fftools -I$BUILD_DIR/include
-Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -L$BUILD_DIR/lib
-Wno-deprecated-declarations -Wno-pointer-sign -Wno-implicit-int-float-conversion -Wno-switch -Wno-parentheses -Qunused-arguments
-lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -lpostproc -lm -lx264 -pthread
-lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -lpostproc -lm -lx264 -lvpx -pthread
fftools/ffmpeg_opt.c fftools/ffmpeg_filter.c fftools/ffmpeg_hw.c fftools/cmdutils.c fftools/ffmpeg.c
-o wasm/dist/ffmpeg-core.js
-s USE_SDL=2 # use SDL2
......
#!/bin/bash
set -euo pipefail
source $(dirname $0)/var.sh
LIB_PATH=third_party/libvpx
FLAGS="-c -s USE_PTHREADS=1 $OPTIM_FLAGS"
CONF_FLAGS=(
--prefix=$BUILD_DIR # install library in a build directory for FFmpeg to include
--target=generic-gnu # target with miminal features
--disable-install-bins # not to install bins
--disable-examples # not to build examples
--disable-tools # not to build tools
--disable-docs # not to build docs
--disable-unit-tests # not to do unit tests
--extra-cflags="$FLAGS" # flags to use pthread and code optimization
--extra-cxxflags="$FLAGS" # flags to use pthread and code optimization
)
echo "CONF_FLAGS=${CONF_FLAGS[@]}"
(cd $LIB_PATH && LDFLAGS="$FLAGS" STRIP="llvm-strip" emconfigure ./configure "${CONF_FLAGS[@]}")
emmake make -C $LIB_PATH clean
emmake make -C $LIB_PATH install -j
......@@ -3,8 +3,8 @@
set -euo pipefail
source $(dirname $0)/var.sh
X264_PATH=third_party/x264
FLAGS=(
LIB_PATH=third_party/x264
CONF_FLAGS=(
--prefix=$BUILD_DIR # install library in a build directory for FFmpeg to include
--host=i686-gnu # use i686 linux
--enable-static # enable building static library
......@@ -12,6 +12,7 @@ FLAGS=(
--disable-asm # disable asm optimization
--extra-cflags="-c -s USE_PTHREADS=1 $OPTIM_FLAGS" # flags to use pthread and code optimization
)
echo "FLAGS=${FLAGS[@]}"
(cd $X264_PATH && emconfigure ./configure "${FLAGS[@]}")
emmake make -C $X264_PATH install-lib-static -j
echo "CONF_FLAGS=${CONF_FLAGS[@]}"
(cd $LIB_PATH && emconfigure ./configure "${CONF_FLAGS[@]}")
emmake make -C $LIB_PATH clean
emmake make -C $LIB_PATH install-lib-static -j
......@@ -37,6 +37,7 @@ FFMPEG_CONFIG_FLAGS_BASE=(
--disable-doc # disable doc
--enable-gpl # required by x264
--enable-libx264 # enable x264
--enable-libvpx # enable libvpx / webm
--disable-debug # disable debug info, required by closure
--disable-runtime-cpudetect # disable runtime cpu detect
--disable-autodetect # disable external libraries auto detect
......
<html>
<head>
<style>
html, body {
margin: 0;
width: 100%;
height: 100%
}
body {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
</head>
<body>
<h3>Upload a video to transcode to webm and play!</h3>
<video id="output-video" controls></video><br/>
<input type="file" id="uploader">
<p id="message">Update a video</p>
<script type="text/javascript">
const readFromBlobOrFile = (blob) => (
new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = () => {
resolve(fileReader.result);
};
fileReader.onerror = ({ target: { error: { code } } }) => {
reject(Error(`File could not be read! Code=${code}`));
};
fileReader.readAsArrayBuffer(blob);
})
);
const message = document.getElementById('message');
const transcode = async ({ target: { files } }) => {
let resolve = null;
const Core = await createFFmpegCore({
printErr: (m) => console.log(m),
print: (m) => {
console.log(m);
if (m.startsWith('FFMPEG_END')) {
resolve();
}
}
});
message.innerHTML = 'Writing file to MEMFS';
const data = await readFromBlobOrFile(files[0]);
Core.FS.writeFile('video.avi', new Uint8Array(data));
const ffmpeg = Core.cwrap('proxy_main', 'number', ['number', 'number']);
// const args = ['ffmpeg', '-hide_banner', '-nostdin', '-i', 'video.mp4', '-vf', 'scale=512:-1', '-vcodec', 'h264', '-acodec', 'copy', 'scaled.mp4'];
const args = ['ffmpeg', '-hide_banner', '-nostdin', '-threads', '0', '-i', 'video.avi', '-acodec', 'copy', '-row-mt', '1', 'video.webm'];
const argsPtr = Core._malloc(args.length * Uint32Array.BYTES_PER_ELEMENT);
args.forEach((s, idx) => {
const buf = Core._malloc(s.length + 1);
Core.writeAsciiToMemory(s, buf);
Core.setValue(argsPtr + (Uint32Array.BYTES_PER_ELEMENT * idx), buf, 'i32');
});
const d = Date.now();
console.time(`[${d}] ${files[0].name} execution time`);
message.innerHTML = 'Start to transcode';
ffmpeg(args.length, argsPtr);
await new Promise((_resolve) => { resolve = _resolve });
const output = Core.FS.readFile('video.webm');
Core.FS.unlink('video.webm');
const video = document.getElementById('output-video');
video.src = URL.createObjectURL(new Blob([output.buffer], { type: 'video/mp4' }));
console.timeEnd(`[${d}] ${files[0].name} execution time`);
};
document.getElementById('uploader').addEventListener('change', transcode);
</script>
<script type="text/javascript" src="../dist/ffmpeg-core.js"></script>
</body>
</html>
const fs = require('fs');
const path = require('path');
const createFFmpegCore = require('../dist/ffmpeg-core');
const { parseArgs, ffmpeg } = require('./utils');
const filePath = path.join(__dirname, 'data', 'video-3s.avi');
let data = null;
const { runFFmpeg } = require('./utils');
const aviFilePath = path.join(__dirname, 'data', 'video-3s.avi');
const TIMEOUT = 120000;
const MP4_SIZE = 98326;
const WEBM_SIZE = 114591;
let aviData = null;
beforeAll(async () => {
data = Uint8Array.from(fs.readFileSync(filePath));
aviData = Uint8Array.from(fs.readFileSync(aviFilePath));
});
test('transcode avi to x264 mp4', async () => {
let resolve = null;
const Core = await createFFmpegCore({
printErr: () => {},
print: (m) => {
if (m.startsWith('FFMPEG_END')) {
resolve();
}
},
});
Core.FS.writeFile('video.avi', data);
ffmpeg(Core, ['-i', 'video.avi', 'video.mp4']);
await new Promise((_resolve) => { resolve = _resolve });
const Core = await runFFmpeg('video.avi', aviData, ['-i', 'video.avi', 'video.mp4']);
const fileSize = Core.FS.readFile('video.mp4').length;
Core.FS.unlink('video.mp4');
expect(fileSize).toBe(98326);
}, 30000);
expect(fileSize).toBe(MP4_SIZE);
}, TIMEOUT);
test('transcode avi to x264 mp4 twice', async () => {
for (let i = 0 ; i < 2; i++) {
let resolve = null;
const Core = await createFFmpegCore({
printErr: () => {},
print: (m) => {
if (m.startsWith('FFMPEG_END')) {
resolve();
}
},
});
Core.FS.writeFile('video.avi', data);
ffmpeg(Core, ['-i', 'video.avi', 'video.mp4']);
await new Promise((_resolve) => { resolve = _resolve });
const Core = await runFFmpeg('video.avi', aviData, ['-i', 'video.avi', 'video.mp4']);
const fileSize = Core.FS.readFile('video.mp4').length;
Core.FS.unlink('video.mp4');
expect(fileSize).toBe(98326);
expect(fileSize).toBe(MP4_SIZE);
}
}, 30000);
}, TIMEOUT);
test('transcode avi to webm', async () => {
const Core = await runFFmpeg('video.avi', aviData, ['-i', 'video.avi', '-row-mt', '1', 'video.webm']);
const fileSize = Core.FS.readFile('video.webm').length;
Core.FS.unlink('video.webm');
expect(fileSize).toBe(WEBM_SIZE);
}, TIMEOUT);
test('transcode avi to webm twice', async () => {
for (let i = 0 ; i < 2; i++) {
const Core = await runFFmpeg('video.avi', aviData, ['-i', 'video.avi', '-row-mt', '1', 'video.webm']);
const fileSize = Core.FS.readFile('video.webm').length;
Core.FS.unlink('video.webm');
expect(fileSize).toBe(WEBM_SIZE);
}
}, TIMEOUT);
const createFFmpegCore = require('../dist/ffmpeg-core');
const parseArgs = (Core, args) => {
const argsPtr = Core._malloc(args.length * Uint32Array.BYTES_PER_ELEMENT);
args.forEach((s, idx) => {
......@@ -15,9 +17,24 @@ const ffmpeg = (Core, args) => {
['number', 'number'],
parseArgs(Core, ['ffmpeg', '-nostdin', ...args]),
);
}
};
const runFFmpeg = async (filename, data, args) => {
let resolve = null;
const Core = await createFFmpegCore({
printErr: () => {},
print: (m) => {
if (m.startsWith('FFMPEG_END')) {
resolve();
}
},
});
Core.FS.writeFile(filename, data);
ffmpeg(Core, args);
await new Promise((_resolve) => { resolve = _resolve });
return Core;
};
module.exports = {
ffmpeg,
parseArgs,
}
runFFmpeg,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment