Commit 6b92858f authored by Jerome Wu's avatar Jerome Wu

Add x265 (WIP)

parent 5dc21ead
......@@ -7,3 +7,6 @@
[submodule "third_party/libvpx"]
path = third_party/libvpx
url = https://github.com/ffmpegwasm/libvpx
[submodule "third_party/x265"]
path = third_party/x265
url = https://github.com/ffmpegwasm/x265
......@@ -8,9 +8,11 @@ SCRIPT_ROOT=$(dirname $0)/wasm/build-scripts
emcc -v
# build x264
$SCRIPT_ROOT/build-x264.sh
# build x265 (WIP)
# $SCRIPT_ROOT/build-x265.sh
# build libvpx
$SCRIPT_ROOT/build-libvpx.sh
# configure FFmpeg with Emscripten
$SCRIPT_ROOT/configure-ffmpeg.sh
# build ffmpeg.wasm
# build ffmpeg.wasm core
$SCRIPT_ROOT/build-ffmpeg.sh
Subproject commit 2bb5520e9596f361bf0ed81b3b8da0d7fd999069
#!/bin/bash
set -euo pipefail
source $(dirname $0)/var.sh
LIB_PATH=third_party/x265/source
CONF_FLAGS=(
-DCMAKE_INSTALL_PREFIX=$BUILD_DIR
-DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE
-DENABLE_SHARED:bool=off
-DENABLE_CLI:bool=off
)
echo "CONF_FLAGS=${CONF_FLAGS[@]}"
rm -rf $LIB_PATH/build
mkdir -p $LIB_PATH/build
(cd $LIB_PATH/build && emmake cmake .. "${CONF_FLAGS[@]}")
emmake make -C $LIB_PATH/build clean
emmake make -C $LIB_PATH/build install -j
......@@ -4,6 +4,9 @@
set -euo pipefail
# Include llvm binaries
export PATH=$PATH:/emsdk/upstream/bin
# Flags for code optimization, focus on speed instead
# of size
OPTIM_FLAGS=(
......@@ -24,6 +27,9 @@ OPTIM_FLAGS="${OPTIM_FLAGS[@]}"
# Directory to install headers and libraries
BUILD_DIR=$PWD/build
# Toolchain file path for cmake
TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
CFLAGS="-s USE_PTHREADS=1 -I$BUILD_DIR/include $OPTIM_FLAGS"
LDFLAGS="$CFLAGS -L$BUILD_DIR/lib"
FFMPEG_CONFIG_FLAGS_BASE=(
......
<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 mp4 (x265) 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', '-i', 'video.avi', '-c:v', 'libx265', '-acodec', 'copy', 'video.mp4'];
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.mp4');
Core.FS.unlink('video.mp4');
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 { TIMEOUT } = require('./config');
const { runFFmpeg } = require('./utils');
const aviFilePath = path.join(__dirname, 'data', 'video-1s.avi');
const MP4_SIZE = 38372;
let aviData = null;
beforeAll(async () => {
aviData = Uint8Array.from(fs.readFileSync(aviFilePath));
});
test('transcode avi to x265 mp4', async () => {
const Core = await runFFmpeg('video.avi', aviData, ['-i', 'video.avi', '-c:v', 'libx265', 'video.mp4']);
const fileSize = Core.FS.readFile('video.mp4').length;
Core.FS.unlink('video.mp4');
expect(fileSize).toBe(MP4_SIZE);
}, TIMEOUT);
test('transcode avi to x265 mp4 twice', async () => {
for (let i = 0 ; i < 2; i++) {
const Core = await runFFmpeg('video.avi', aviData, ['-i', 'video.avi', '-c:v', 'libx265', 'video.mp4']);
const fileSize = Core.FS.readFile('video.mp4').length;
Core.FS.unlink('video.mp4');
expect(fileSize).toBe(MP4_SIZE);
}
}, TIMEOUT);
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