-
-
Notifications
You must be signed in to change notification settings - Fork 298
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Emscripten update and standalone support #925
Changes from all commits
1ca4b0e
957f2eb
6520e46
f515151
62b07dc
73ee2ab
ca8693a
7d775a8
1733e7b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,52 +2,116 @@ | |
set -e | ||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
|
||
CORES=$(nproc --all) | ||
CORES="${CORES:-`nproc --all`}" | ||
ENABLE_LIBDE265="${ENABLE_LIBDE265:-1}" | ||
LIBDE265_VERSION="${LIBDE265_VERSION:-1.0.12}" | ||
ENABLE_AOM="${ENABLE_AOM:-0}" | ||
AOM_VERSION="${AOM_VERSION:-3.6.1}" | ||
STANDALONE="${STANDALONE:-0}" | ||
DEBUG="${DEBUG:-0}" | ||
USE_WASM="${USE_WASM:-1}" | ||
|
||
echo "Build using ${CORES} CPU cores" | ||
|
||
LIBDE265_VERSION=1.0.8 | ||
[ -s "libde265-${LIBDE265_VERSION}.tar.gz" ] || curl \ | ||
-L \ | ||
-o libde265-${LIBDE265_VERSION}.tar.gz \ | ||
https://github.com/strukturag/libde265/releases/download/v${LIBDE265_VERSION}/libde265-${LIBDE265_VERSION}.tar.gz | ||
if [ ! -s "libde265-${LIBDE265_VERSION}/libde265/.libs/libde265.so" ]; then | ||
tar xf libde265-${LIBDE265_VERSION}.tar.gz | ||
cd libde265-${LIBDE265_VERSION} | ||
[ -x configure ] || ./autogen.sh | ||
emconfigure ./configure --disable-sse --disable-dec265 --disable-sherlock265 | ||
emmake make -j${CORES} | ||
cd .. | ||
LIBRARY_LINKER_FLAGS="" | ||
LIBRARY_INCLUDE_FLAGS="" | ||
|
||
CONFIGURE_ARGS_LIBDE265="" | ||
if [ "$ENABLE_LIBDE265" = "1" ]; then | ||
[ -s "libde265-${LIBDE265_VERSION}.tar.gz" ] || curl \ | ||
-L \ | ||
-o libde265-${LIBDE265_VERSION}.tar.gz \ | ||
https://github.com/strukturag/libde265/releases/download/v${LIBDE265_VERSION}/libde265-${LIBDE265_VERSION}.tar.gz | ||
if [ ! -s "libde265-${LIBDE265_VERSION}/libde265/.libs/libde265.so" ]; then | ||
tar xf libde265-${LIBDE265_VERSION}.tar.gz | ||
cd libde265-${LIBDE265_VERSION} | ||
[ -x configure ] || ./autogen.sh | ||
emconfigure ./configure --disable-sse --disable-dec265 --disable-sherlock265 | ||
emmake make -j${CORES} | ||
cd .. | ||
fi | ||
CONFIGURE_ARGS_LIBDE265="-DLIBDE265_INCLUDE_DIR=${DIR}/libde265-${LIBDE265_VERSION} -DLIBDE265_LIBRARY=-L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs" | ||
LIBRARY_LINKER_FLAGS="$LIBRARY_LINKER_FLAGS -lde265" | ||
LIBRARY_INCLUDE_FLAGS="$LIBRARY_INCLUDE_FLAGS -L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs" | ||
fi | ||
|
||
CONFIGURE_ARGS_AOM="" | ||
if [ "$ENABLE_AOM" = "1" ]; then | ||
[ -s "aom-${AOM_VERSION}.tar.gz" ] || curl \ | ||
-L \ | ||
-o aom-${AOM_VERSION}.tar.gz \ | ||
"https://aomedia.googlesource.com/aom/+archive/v${AOM_VERSION}.tar.gz" | ||
if [ ! -s "aom-${AOM_VERSION}/libaom.a" ]; then | ||
mkdir -p aom-${AOM_VERSION}/aom-source | ||
tar xf aom-${AOM_VERSION}.tar.gz -C aom-${AOM_VERSION}/aom-source | ||
cd aom-${AOM_VERSION} | ||
|
||
emcmake cmake aom-source \ | ||
-DENABLE_CCACHE=1 \ | ||
-DAOM_TARGET_CPU=generic \ | ||
-DENABLE_DOCS=0 \ | ||
-DENABLE_TESTS=0 \ | ||
-DENABLE_EXAMPLES=0 \ | ||
-DENABLE_TESTDATA=0 \ | ||
-DENABLE_TOOLS=0 \ | ||
-DCONFIG_MULTITHREAD=0 \ | ||
-DCONFIG_RUNTIME_CPU_DETECT=0 \ | ||
-DBUILD_SHARED_LIBS=1 \ | ||
-DCMAKE_BUILD_TYPE=Release | ||
|
||
emmake make -j${CORES} | ||
|
||
cd .. | ||
fi | ||
|
||
CONFIGURE_ARGS_AOM="-DAOM_INCLUDE_DIR=${DIR}/aom-${AOM_VERSION}/aom-source -DAOM_LIBRARY=-L${DIR}/aom-${AOM_VERSION}" | ||
LIBRARY_LINKER_FLAGS="$LIBRARY_LINKER_FLAGS -laom" | ||
LIBRARY_INCLUDE_FLAGS="$LIBRARY_INCLUDE_FLAGS -L${DIR}/aom-${AOM_VERSION}" | ||
fi | ||
|
||
CONFIGURE_ARGS="-DENABLE_MULTITHREADING_SUPPORT=OFF -DWITH_GDK_PIXBUF=OFF -DWITH_EXAMPLES=OFF -DBUILD_SHARED_LIBS=ON" | ||
#export PKG_CONFIG_PATH="${DIR}/libde265-${LIBDE265_VERSION}" | ||
EXTRA_EXE_LINKER_FLAGS="-lembind" | ||
EXTRA_COMPILER_FLAGS="" | ||
if [ "$STANDALONE" = "1" ]; then | ||
EXTRA_EXE_LINKER_FLAGS="" | ||
EXTRA_COMPILER_FLAGS="-D__EMSCRIPTEN_STANDALONE_WASM__=1" | ||
fi | ||
|
||
CONFIGURE_ARGS="-DENABLE_MULTITHREADING_SUPPORT=OFF -DWITH_GDK_PIXBUF=OFF -DWITH_EXAMPLES=OFF -DBUILD_SHARED_LIBS=ON -DENABLE_PLUGIN_LOADING=OFF" | ||
emcmake cmake $CONFIGURE_ARGS \ | ||
-DLIBDE265_INCLUDE_DIR="${DIR}/libde265-${LIBDE265_VERSION}" \ | ||
-DLIBDE265_LIBRARY="-L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs" | ||
-DCMAKE_C_FLAGS="${EXTRA_COMPILER_FLAGS}" \ | ||
-DCMAKE_CXX_FLAGS="${EXTRA_COMPILER_FLAGS}" \ | ||
-DCMAKE_EXE_LINKER_FLAGS="${LIBRARY_LINKER_FLAGS} ${EXTRA_EXE_LINKER_FLAGS}" \ | ||
$CONFIGURE_ARGS_LIBDE265 \ | ||
$CONFIGURE_ARGS_AOM | ||
|
||
emmake make -j${CORES} | ||
|
||
export TOTAL_MEMORY=16777216 | ||
LIBHEIFA="libheif/libheif.a" | ||
EXPORTED_FUNCTIONS=$($EMSDK/upstream/bin/llvm-nm $LIBHEIFA --format=just-symbols | grep "^heif_\|^de265_\|^aom_" | grep "[^:]$" | sed 's/^/_/' | paste -sd "," -) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is necessary to make the C API's be exposed, otherwise they won't be available exported the WASM/JS code. |
||
|
||
echo "Running Emscripten..." | ||
emcc libheif/libheif.so \ | ||
--bind \ | ||
--closure 0 \ | ||
-s NO_EXIT_RUNTIME=1 \ | ||
-s TOTAL_MEMORY=${TOTAL_MEMORY} \ | ||
|
||
BUILD_FLAGS="-lembind -o libheif.js --pre-js pre.js --post-js post.js -sWASM=$USE_WASM" | ||
RELEASE_BUILD_FLAGS="-O3" | ||
|
||
if [ "$STANDALONE" = "1" ]; then | ||
echo "Building in standalone (non-web) build mode" | ||
BUILD_FLAGS="$BUILD_FLAGS -s STANDALONE_WASM=1 -s WASM=1 -o libheif.wasm --no-entry" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @farindk I specifically did not extend There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. I'll undo that. I must admit that I didn't really understand the 'standalone' option. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @farindk Standalone builds allow you to run the generated WASM outside the browser in WebAssembly runtimes such as Wasmer, WAVM, or wasmtime. Personally I'm using the standalone build in the Wazero runtime to be used in the go-libheif library, this allows for a go library that is fully contained (because the WASM is embedded in the library) and doesn't need external native libraries, it also allows the library to run fully sandboxed. The only downside is that it's slower than CGO, and multithreaded support is pretty bad right now, which causes the decoding to be around 3x as slow as CGO. |
||
fi | ||
|
||
if [ "$DEBUG" = "1" ]; then | ||
echo "Building in debug mode" | ||
RELEASE_BUILD_FLAGS="--profile -g" | ||
fi | ||
|
||
emcc "$LIBHEIFA" \ | ||
-s EXPORTED_FUNCTIONS="$EXPORTED_FUNCTIONS,_free,_malloc,_memcpy" \ | ||
-s ALLOW_MEMORY_GROWTH=1 \ | ||
-s ASSERTIONS=0 \ | ||
-s INVOKE_RUN=0 \ | ||
-s DOUBLE_MODE=0 \ | ||
-s PRECISE_F32=0 \ | ||
-s DISABLE_EXCEPTION_CATCHING=1 \ | ||
-s USE_CLOSURE_COMPILER=0 \ | ||
-s LEGACY_VM_SUPPORT=1 \ | ||
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have removed all the old flags here, I don't think they are neccesary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When not building to WASM, but plain JS, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @farindk Ah I did not even know it was possible to only emit JS, was that what the previous version had as output? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, previously, it was a single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @farindk Shouldn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. But I think in this case, I would take the risk to change the default because WASM is clearly the future and it doesn't change anything for the end-user. Just of the ones building new libheif.js files. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have notified the following repo of the change: catdad-experiments/libheif-emscripten#19 What kind of other changes do you want to make? I think it might be interesting to look at thread support (for the browser it's possible). |
||
-s LLD_REPORT_UNDEFINED \ | ||
--memory-init-file 0 \ | ||
-O3 \ | ||
-std=c++11 \ | ||
-L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs \ | ||
-lde265 \ | ||
--pre-js pre.js \ | ||
--post-js post.js \ | ||
-o libheif.js | ||
$LIBRARY_INCLUDE_FLAGS \ | ||
$LIBRARY_LINKER_FLAGS \ | ||
$BUILD_FLAGS \ | ||
$RELEASE_BUILD_FLAGS |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ | |
#include <set> | ||
#include <limits> | ||
|
||
#if defined(__EMSCRIPTEN__) | ||
#if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_STANDALONE_WASM__) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: |
||
#include "heif_emscripten.h" | ||
#endif | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,7 +112,7 @@ static emscripten::val heif_js_decode_image(struct heif_image_handle* handle, | |
result.set("width", width); | ||
int height = heif_image_get_height(image, heif_channel_Y); | ||
result.set("height", height); | ||
std::string data; | ||
std::basic_string<unsigned char> data; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was needed because Embind was messing up the data transfer when using a normal std::string, however, the data transfer between strings looks very odd to me right now because I think what currently happens is:
I believe we can remove the string conversion, probably also speeds things up a bit. I'm currently talking to Emscripten what the best way to do that is in Embind. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Converning passing the data around: do you think this (answer item 3) might work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! |
||
result.set("chroma", heif_image_get_chroma_format(image)); | ||
result.set("colorspace", heif_image_get_colorspace(image)); | ||
switch (heif_image_get_colorspace(image)) { | ||
|
@@ -127,7 +127,7 @@ static emscripten::val heif_js_decode_image(struct heif_image_handle* handle, | |
const uint8_t* plane_v = heif_image_get_plane_readonly(image, | ||
heif_channel_Cr, &stride_v); | ||
data.resize((width * height) + (2 * round_odd(width) * round_odd(height))); | ||
char* dest = const_cast<char*>(data.data()); | ||
unsigned char* dest = const_cast<unsigned char*>(data.data()); | ||
strided_copy(dest, plane_y, width, height, stride_y); | ||
strided_copy(dest + (width * height), plane_u, | ||
round_odd(width), round_odd(height), stride_u); | ||
|
@@ -142,7 +142,7 @@ static emscripten::val heif_js_decode_image(struct heif_image_handle* handle, | |
const uint8_t* plane_rgb = heif_image_get_plane_readonly(image, | ||
heif_channel_interleaved, &stride_rgb); | ||
data.resize(width * height * 3); | ||
char* dest = const_cast<char*>(data.data()); | ||
unsigned char* dest = const_cast<unsigned char*>(data.data()); | ||
strided_copy(dest, plane_rgb, width * 3, height, stride_rgb); | ||
} | ||
break; | ||
|
@@ -153,7 +153,7 @@ static emscripten::val heif_js_decode_image(struct heif_image_handle* handle, | |
const uint8_t* plane_grey = heif_image_get_plane_readonly(image, | ||
heif_channel_Y, &stride_grey); | ||
data.resize(width * height); | ||
char* dest = const_cast<char*>(data.data()); | ||
unsigned char* dest = const_cast<unsigned char*>(data.data()); | ||
strided_copy(dest, plane_grey, width, height, stride_grey); | ||
} | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -175,40 +175,6 @@ var libheif = { | |
} | ||
}; | ||
|
||
var key; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has all moved to pre.js |
||
|
||
// Expose enum values. | ||
var enums = { | ||
"heif_error_code": true, | ||
"heif_suberror_code": true, | ||
"heif_compression_format": true, | ||
"heif_chroma": true, | ||
"heif_colorspace": true, | ||
"heif_channel": true | ||
}; | ||
var e; | ||
for (e in enums) { | ||
if (!enums.hasOwnProperty(e)) { | ||
continue; | ||
} | ||
for (key in Module[e]) { | ||
if (!Module[e].hasOwnProperty(key) || | ||
key === "values") { | ||
continue; | ||
} | ||
|
||
libheif[key] = Module[e][key]; | ||
} | ||
} | ||
|
||
// Expose internal C API. | ||
for (key in Module) { | ||
if (enums.hasOwnProperty(key) || key.indexOf("heif_") !== 0) { | ||
continue; | ||
} | ||
libheif[key] = Module[key]; | ||
} | ||
|
||
// don't pollute the global namespace | ||
delete this['Module']; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,5 +29,47 @@ var Module = { | |
console.error(text); | ||
}, | ||
canvas: {}, | ||
noInitialRun: true | ||
noInitialRun: true, | ||
onRuntimeInitialized: function() { | ||
// Expose enum values. | ||
var enums = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had to move all this logic from |
||
"heif_error_code": true, | ||
"heif_suberror_code": true, | ||
"heif_compression_format": true, | ||
"heif_chroma": true, | ||
"heif_colorspace": true, | ||
"heif_channel": true | ||
}; | ||
var e; | ||
for (e in enums) { | ||
if (!enums.hasOwnProperty(e)) { | ||
continue; | ||
} | ||
|
||
for (key in this[e]) { | ||
if (!this[e].hasOwnProperty(key) || | ||
key === "values") { | ||
continue; | ||
} | ||
|
||
libheif[key] = this[e][key]; | ||
} | ||
} | ||
|
||
// Expose internal C API. | ||
for (key in this) { | ||
if (enums.hasOwnProperty(key.slice(1)) || key.indexOf("_heif_") !== 0) { | ||
continue; | ||
} | ||
libheif[key.slice(1)] = this[key]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the LLVM build, C functions start with |
||
} | ||
|
||
// Expose embind API. | ||
for (key in Module) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I alias the embind API after the C API because there are two functions that have the same name as in the C API ( |
||
if (enums.hasOwnProperty(key) || key.indexOf("heif_") !== 0) { | ||
continue; | ||
} | ||
libheif[key] = Module[key]; | ||
} | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,6 @@ fi | |
|
||
LIBSTDC_BASE=http://de.archive.ubuntu.com/ubuntu/pool/main/g/gcc-5 | ||
EMSDK_DOWNLOAD=https://github.com/emscripten-core/emsdk.git | ||
EMSDK_VERSION=3.1.29 | ||
|
||
CODENAME=$(/usr/bin/lsb_release --codename --short) | ||
if [ "$CODENAME" = "trusty" ] && [ ! -e "/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21" ]; then | ||
|
@@ -33,13 +32,13 @@ if [ ! -d emsdk ]; then | |
fi | ||
|
||
cd emsdk | ||
echo "Updating SDK base to ${EMSDK_VERSION} ..." | ||
echo "Updating SDK base to ${VERSION} ..." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have removed the |
||
git checkout main | ||
git pull --verbose | ||
git checkout ${EMSDK_VERSION} | ||
git checkout ${VERSION} | ||
|
||
echo "Installing SDK version ${VERSION} ..." | ||
./emsdk install sdk-fastcomp-${VERSION}-64bit | ||
echo "Installing SDK version latest ..." | ||
./emsdk install ${VERSION} | ||
|
||
echo "Activating SDK version ${VERSION} ..." | ||
./emsdk activate sdk-fastcomp-${VERSION}-64bit | ||
echo "Activating SDK version latest ..." | ||
./emsdk activate ${VERSION} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added
-DENABLE_PLUGIN_LOADING=OFF
, I thought it would make sense.