From 1ca4b0e573f05e28d3ad37539cceee7ea62e7dbd Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 18 Jul 2023 12:12:10 +0200 Subject: [PATCH 1/9] Fixes to the build script --- build-emscripten.sh | 30 ++++++------ libheif/heif_emscripten.h | 4 +- post.js | 87 ++++++++--------------------------- scripts/install-emscripten.sh | 13 +++--- 4 files changed, 40 insertions(+), 94 deletions(-) diff --git a/build-emscripten.sh b/build-emscripten.sh index 0992c02046..00dc637944 100755 --- a/build-emscripten.sh +++ b/build-emscripten.sh @@ -5,7 +5,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" CORES=$(nproc --all) echo "Build using ${CORES} CPU cores" -LIBDE265_VERSION=1.0.8 +LIBDE265_VERSION=1.0.12 [ -s "libde265-${LIBDE265_VERSION}.tar.gz" ] || curl \ -L \ -o libde265-${LIBDE265_VERSION}.tar.gz \ @@ -19,35 +19,31 @@ if [ ! -s "libde265-${LIBDE265_VERSION}/libde265/.libs/libde265.so" ]; then cd .. fi -CONFIGURE_ARGS="-DENABLE_MULTITHREADING_SUPPORT=OFF -DWITH_GDK_PIXBUF=OFF -DWITH_EXAMPLES=OFF -DBUILD_SHARED_LIBS=ON" +CONFIGURE_ARGS="-DENABLE_MULTITHREADING_SUPPORT=OFF -DWITH_GDK_PIXBUF=OFF -DWITH_EXAMPLES=OFF -DBUILD_SHARED_LIBS=ON -DENABLE_PLUGIN_LOADING=OFF" #export PKG_CONFIG_PATH="${DIR}/libde265-${LIBDE265_VERSION}" emcmake cmake $CONFIGURE_ARGS \ + -DCMAKE_EXE_LINKER_FLAGS="-lembind -lde265" \ -DLIBDE265_INCLUDE_DIR="${DIR}/libde265-${LIBDE265_VERSION}" \ -DLIBDE265_LIBRARY="-L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs" 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_" | grep "[^:]$" | sed 's/^/_/' | paste -sd "," -) + echo "Running Emscripten..." -emcc libheif/libheif.so \ - --bind \ - --closure 0 \ - -s NO_EXIT_RUNTIME=1 \ - -s TOTAL_MEMORY=${TOTAL_MEMORY} \ +emcc "$LIBHEIFA" \ + -lembind \ -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 \ - --memory-init-file 0 \ - -O3 \ + -s LINKABLE=1 \ + -O0 \ -std=c++11 \ -L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs \ -lde265 \ --pre-js pre.js \ --post-js post.js \ - -o libheif.js + -s MODULARIZE \ + -s 'EXPORT_NAME="createLibheifModule"' \ + -o libheif.html diff --git a/libheif/heif_emscripten.h b/libheif/heif_emscripten.h index 23e4262153..c2af40ec9f 100644 --- a/libheif/heif_emscripten.h +++ b/libheif/heif_emscripten.h @@ -170,13 +170,13 @@ static emscripten::val heif_js_decode_image(struct heif_image_handle* handle, emscripten::function(#name, &name, emscripten::allow_raw_pointers()) EMSCRIPTEN_BINDINGS(libheif) { - emscripten::function("heif_get_version", &_heif_get_version, + emscripten::function("heif_js_get_version", &_heif_get_version, emscripten::allow_raw_pointers()); EXPORT_HEIF_FUNCTION(heif_get_version_number); EXPORT_HEIF_FUNCTION(heif_context_alloc); EXPORT_HEIF_FUNCTION(heif_context_free); - emscripten::function("heif_context_read_from_memory", + emscripten::function("heif_js_context_read_from_memory", &_heif_context_read_from_memory, emscripten::allow_raw_pointers()); EXPORT_HEIF_FUNCTION(heif_context_get_number_of_top_level_images); emscripten::function("heif_js_context_get_list_of_top_level_image_IDs", diff --git a/post.js b/post.js index 3c0e70fec8..0e11cb69f6 100644 --- a/post.js +++ b/post.js @@ -7,14 +7,15 @@ function StringToArrayBuffer(str) { return buf; } -var HeifImage = function(handle) { +var HeifImage = function(handle, Module) { this.handle = handle; + this.Module = Module; this.img = null; }; HeifImage.prototype.free = function() { if (this.handle) { - libheif.heif_image_handle_release(this.handle); + this.Module.heif_image_handle_release(this.handle); this.handle = null; } }; @@ -24,15 +25,17 @@ HeifImage.prototype._ensureImage = function() { return; } - var img = libheif.heif_js_decode_image(this.handle, - libheif.heif_colorspace_YCbCr, libheif.heif_chroma_420); + var img = this.Module.heif_js_decode_image(this.handle, + this.Module.heif_colorspace.heif_colorspace_YCbCr, this.Module.heif_chroma.heif_chroma_420); if (!img || img.code) { console.log("Decoding image failed", this.handle, img); return; } - this.data = new Uint8Array(StringToArrayBuffer(img.data)); - delete img.data; + //this.data = new Uint8Array(StringToArrayBuffer(img.data)); + //delete img.data; + console.log(typeof(img.data)); + this.data = img.data; this.img = img; }; @@ -118,26 +121,28 @@ HeifImage.prototype.display = function(image_data, callback) { }.bind(this), 0); }; -var HeifDecoder = function() { +var HeifDecoder = function(Module) { this.decoder = null; + this.Module = Module; }; HeifDecoder.prototype.decode = function(buffer) { if (this.decoder) { - libheif.heif_context_free(this.decoder); + this.Module.heif_context_free(this.decoder); } - this.decoder = libheif.heif_context_alloc(); + this.decoder = this.Module.heif_context_alloc(); if (!this.decoder) { console.log("Could not create HEIF context"); return []; } - var error = libheif.heif_context_read_from_memory(this.decoder, buffer); - if (error.code !== libheif.heif_error_Ok) { + + var error = this.Module.heif_js_context_read_from_memory(this.decoder, buffer); + if (error.code !== this.Module.heif_error_code.heif_error_Ok) { console.log("Could not parse HEIF file", error); return []; } - var ids = libheif.heif_js_context_get_list_of_top_level_image_IDs(this.decoder); + var ids = this.Module.heif_js_context_get_list_of_top_level_image_IDs(this.decoder); if (!ids || ids.code) { console.log("Error loading image ids", ids); return []; @@ -149,13 +154,13 @@ HeifDecoder.prototype.decode = function(buffer) { var result = []; for (var i = 0; i < ids.length; i++) { - var handle = libheif.heif_js_context_get_image_handle(this.decoder, ids[i]); + var handle = this.Module.heif_js_context_get_image_handle(this.decoder, ids[i]); if (!handle || handle.code) { console.log("Could not get image data for id", ids[i], handle); continue; } - result.push(new HeifImage(handle)); + result.push(new HeifImage(handle, Module)); } return result; }; @@ -175,60 +180,6 @@ var libheif = { } }; -var key; - -// 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']; - -// On IE this function is called with "undefined" as first parameter. Override -// with a version that supports this behaviour. -function createNamedFunction(name, body) { - if (!name) { - name = "function_" + (new Date()); - } - name = makeLegalFunctionName(name); - /*jshint evil:true*/ - return new Function( - "body", - "return function " + name + "() {\n" + - " \"use strict\";" + - " return body.apply(this, arguments);\n" + - "};\n" - )(body); -} - var root = this; if (typeof exports !== 'undefined') { diff --git a/scripts/install-emscripten.sh b/scripts/install-emscripten.sh index d3b638e624..7b5374731b 100755 --- a/scripts/install-emscripten.sh +++ b/scripts/install-emscripten.sh @@ -1,17 +1,16 @@ #!/bin/sh set -e -VERSION=$1 -TARGET=$2 +TARGET=$1 -if [ -z "$VERSION" ] || [ -z "$TARGET" ]; then - echo "USAGE: $0 " +if [ -z "$TARGET" ]; then + echo "USAGE: $0 " exit 1 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 +EMSDK_VERSION=3.1.43 CODENAME=$(/usr/bin/lsb_release --codename --short) if [ "$CODENAME" = "trusty" ] && [ ! -e "/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21" ]; then @@ -39,7 +38,7 @@ git pull --verbose git checkout ${EMSDK_VERSION} echo "Installing SDK version ${VERSION} ..." -./emsdk install sdk-fastcomp-${VERSION}-64bit +./emsdk install latest echo "Activating SDK version ${VERSION} ..." -./emsdk activate sdk-fastcomp-${VERSION}-64bit +./emsdk activate latest From 957f2eb11aa94948f9a58fd82749919490b4b31d Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 18 Jul 2023 17:58:02 +0200 Subject: [PATCH 2/9] Add AOM, standalone build --- build-emscripten.sh | 56 ++++++++++++++++++++++++++++++++++++--------- libheif/heif.cc | 5 ---- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/build-emscripten.sh b/build-emscripten.sh index 00dc637944..1ed21559cd 100755 --- a/build-emscripten.sh +++ b/build-emscripten.sh @@ -19,31 +19,65 @@ if [ ! -s "libde265-${LIBDE265_VERSION}/libde265/.libs/libde265.so" ]; then cd .. fi + +AOM_VERSION=3.6.1 +[ -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 \ + -DCONFIG_ACCOUNTING=1 \ + -DCONFIG_INSPECTION=0 \ + -DCONFIG_MULTITHREAD=0 \ + -DCONFIG_RUNTIME_CPU_DETECT=0 \ + -DCONFIG_WEBM_IO=0 \ + -DBUILD_SHARED_LIBS=1 \ + -DCMAKE_BUILD_TYPE=Release + + emmake make -j${CORES} + + cd .. +fi + CONFIGURE_ARGS="-DENABLE_MULTITHREADING_SUPPORT=OFF -DWITH_GDK_PIXBUF=OFF -DWITH_EXAMPLES=OFF -DBUILD_SHARED_LIBS=ON -DENABLE_PLUGIN_LOADING=OFF" #export PKG_CONFIG_PATH="${DIR}/libde265-${LIBDE265_VERSION}" emcmake cmake $CONFIGURE_ARGS \ - -DCMAKE_EXE_LINKER_FLAGS="-lembind -lde265" \ + -DCMAKE_EXE_LINKER_FLAGS="-lde265 -laom" \ -DLIBDE265_INCLUDE_DIR="${DIR}/libde265-${LIBDE265_VERSION}" \ - -DLIBDE265_LIBRARY="-L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs" + -DLIBDE265_LIBRARY="-L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs" \ + -DAOM_INCLUDE_DIR="${DIR}/aom-${AOM_VERSION}/aom-source" \ + -DAOM_LIBRARY="-L${DIR}/aom-${AOM_VERSION}" 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_" | grep "[^:]$" | sed 's/^/_/' | paste -sd "," -) +EXPORTED_FUNCTIONS=$($EMSDK/upstream/bin/llvm-nm $LIBHEIFA --format=just-symbols | grep "^heif_\|^de265_\|^aom_" | grep "[^:]$" | sed 's/^/_/' | paste -sd "," -) echo "Running Emscripten..." emcc "$LIBHEIFA" \ - -lembind \ + -s EXPORTED_FUNCTIONS="$EXPORTED_FUNCTIONS,_free,_malloc,_memcpy" \ -s ALLOW_MEMORY_GROWTH=1 \ - -s LINKABLE=1 \ - -O0 \ + -s WASM=1 \ + -s STANDALONE_WASM=1 \ + -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ + -s LLD_REPORT_UNDEFINED \ + -O3 \ -std=c++11 \ -L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs \ + -L${DIR}/aom-${AOM_VERSION} \ -lde265 \ - --pre-js pre.js \ - --post-js post.js \ - -s MODULARIZE \ - -s 'EXPORT_NAME="createLibheifModule"' \ - -o libheif.html + -laom \ + -o libheif.wasm \ + --no-entry diff --git a/libheif/heif.cc b/libheif/heif.cc index 954c6c9a15..2d23fbb72e 100644 --- a/libheif/heif.cc +++ b/libheif/heif.cc @@ -32,11 +32,6 @@ #include "bitstream.h" #include #include - -#if defined(__EMSCRIPTEN__) -#include "heif_emscripten.h" -#endif - #include #include #include From 6520e4640868237d248ba324c049b7938ad9988b Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 18 Jul 2023 20:33:05 +0200 Subject: [PATCH 3/9] Add loads of build options --- build-emscripten.sh | 139 ++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/build-emscripten.sh b/build-emscripten.sh index 1ed21559cd..04f6aac2f2 100755 --- a/build-emscripten.sh +++ b/build-emscripten.sh @@ -2,82 +2,105 @@ 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}" + echo "Build using ${CORES} CPU cores" -LIBDE265_VERSION=1.0.12 -[ -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} -AOM_VERSION=3.6.1 -[ -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 \ - -DCONFIG_ACCOUNTING=1 \ - -DCONFIG_INSPECTION=0 \ - -DCONFIG_MULTITHREAD=0 \ - -DCONFIG_RUNTIME_CPU_DETECT=0 \ - -DCONFIG_WEBM_IO=0 \ - -DBUILD_SHARED_LIBS=1 \ - -DCMAKE_BUILD_TYPE=Release - - emmake make -j${CORES} - - cd .. + 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 -DENABLE_PLUGIN_LOADING=OFF" -#export PKG_CONFIG_PATH="${DIR}/libde265-${LIBDE265_VERSION}" - emcmake cmake $CONFIGURE_ARGS \ - -DCMAKE_EXE_LINKER_FLAGS="-lde265 -laom" \ - -DLIBDE265_INCLUDE_DIR="${DIR}/libde265-${LIBDE265_VERSION}" \ - -DLIBDE265_LIBRARY="-L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs" \ - -DAOM_INCLUDE_DIR="${DIR}/aom-${AOM_VERSION}/aom-source" \ - -DAOM_LIBRARY="-L${DIR}/aom-${AOM_VERSION}" -emmake make -j${CORES} + -DCMAKE_EXE_LINKER_FLAGS="${LIBRARY_LINKER_FLAGS}" \ + $CONFIGURE_ARGS_LIBDE265 \ + $CONFIGURE_ARGS_AOM -export TOTAL_MEMORY=16777216 +emmake make -j${CORES} LIBHEIFA="libheif/libheif.a" EXPORTED_FUNCTIONS=$($EMSDK/upstream/bin/llvm-nm $LIBHEIFA --format=just-symbols | grep "^heif_\|^de265_\|^aom_" | grep "[^:]$" | sed 's/^/_/' | paste -sd "," -) echo "Running Emscripten..." + +BUILD_FLAGS="-o libheif.js --pre-js pre.js --post-js post.js" +RELEASE_BUILD_FLAGS="-O3" + +if [ "$STANDALONE" = "1" ]; then + echo "Building in standalone (non-web) build mode" + BUILD_FLAGS="-s STANDALONE_WASM=1 -s WASM=1 -o libheif.wasm --no-entry" +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 WASM=1 \ - -s STANDALONE_WASM=1 \ - -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' \ -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ -s LLD_REPORT_UNDEFINED \ - -O3 \ -std=c++11 \ - -L${DIR}/libde265-${LIBDE265_VERSION}/libde265/.libs \ - -L${DIR}/aom-${AOM_VERSION} \ - -lde265 \ - -laom \ - -o libheif.wasm \ - --no-entry + $LIBRARY_INCLUDE_FLAGS \ + $LIBRARY_LINKER_FLAGS \ + $BUILD_FLAGS \ + $RELEASE_BUILD_FLAGS From f515151497f988f4fe526d3982ac01226158d3d2 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 18 Jul 2023 22:22:47 +0200 Subject: [PATCH 4/9] Make embind optional in build script (for standalone), fix embind wrapping in JS, fix embind raw image transfer issues --- build-emscripten.sh | 13 ++++++++-- libheif/heif.cc | 5 ++++ libheif/heif_emscripten.h | 12 ++++----- post.js | 53 +++++++++++++++++++++++++-------------- pre.js | 46 ++++++++++++++++++++++++++++++++- 5 files changed, 101 insertions(+), 28 deletions(-) diff --git a/build-emscripten.sh b/build-emscripten.sh index 04f6aac2f2..a53090ce73 100755 --- a/build-emscripten.sh +++ b/build-emscripten.sh @@ -68,9 +68,18 @@ if [ "$ENABLE_AOM" = "1" ]; then LIBRARY_INCLUDE_FLAGS="$LIBRARY_INCLUDE_FLAGS -L${DIR}/aom-${AOM_VERSION}" fi +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 \ - -DCMAKE_EXE_LINKER_FLAGS="${LIBRARY_LINKER_FLAGS}" \ + -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 @@ -81,7 +90,7 @@ EXPORTED_FUNCTIONS=$($EMSDK/upstream/bin/llvm-nm $LIBHEIFA --format=just-symbols echo "Running Emscripten..." -BUILD_FLAGS="-o libheif.js --pre-js pre.js --post-js post.js" +BUILD_FLAGS="-lembind -o libheif.js --pre-js pre.js --post-js post.js" RELEASE_BUILD_FLAGS="-O3" if [ "$STANDALONE" = "1" ]; then diff --git a/libheif/heif.cc b/libheif/heif.cc index 2d23fbb72e..30f3b0401d 100644 --- a/libheif/heif.cc +++ b/libheif/heif.cc @@ -32,6 +32,11 @@ #include "bitstream.h" #include #include + +#if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_STANDALONE_WASM__) +#include "heif_emscripten.h" +#endif + #include #include #include diff --git a/libheif/heif_emscripten.h b/libheif/heif_emscripten.h index c2af40ec9f..42b7417205 100644 --- a/libheif/heif_emscripten.h +++ b/libheif/heif_emscripten.h @@ -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 data; 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(data.data()); + unsigned char* dest = const_cast(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(data.data()); + unsigned char* dest = const_cast(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(data.data()); + unsigned char* dest = const_cast(data.data()); strided_copy(dest, plane_grey, width, height, stride_grey); } break; @@ -170,13 +170,13 @@ static emscripten::val heif_js_decode_image(struct heif_image_handle* handle, emscripten::function(#name, &name, emscripten::allow_raw_pointers()) EMSCRIPTEN_BINDINGS(libheif) { - emscripten::function("heif_js_get_version", &_heif_get_version, + emscripten::function("heif_get_version", &_heif_get_version, emscripten::allow_raw_pointers()); EXPORT_HEIF_FUNCTION(heif_get_version_number); EXPORT_HEIF_FUNCTION(heif_context_alloc); EXPORT_HEIF_FUNCTION(heif_context_free); - emscripten::function("heif_js_context_read_from_memory", + emscripten::function("heif_context_read_from_memory", &_heif_context_read_from_memory, emscripten::allow_raw_pointers()); EXPORT_HEIF_FUNCTION(heif_context_get_number_of_top_level_images); emscripten::function("heif_js_context_get_list_of_top_level_image_IDs", diff --git a/post.js b/post.js index 0e11cb69f6..fd733a5841 100644 --- a/post.js +++ b/post.js @@ -7,15 +7,14 @@ function StringToArrayBuffer(str) { return buf; } -var HeifImage = function(handle, Module) { +var HeifImage = function(handle) { this.handle = handle; - this.Module = Module; this.img = null; }; HeifImage.prototype.free = function() { if (this.handle) { - this.Module.heif_image_handle_release(this.handle); + libheif.heif_image_handle_release(this.handle); this.handle = null; } }; @@ -25,17 +24,15 @@ HeifImage.prototype._ensureImage = function() { return; } - var img = this.Module.heif_js_decode_image(this.handle, - this.Module.heif_colorspace.heif_colorspace_YCbCr, this.Module.heif_chroma.heif_chroma_420); + var img = libheif.heif_js_decode_image(this.handle, + libheif.heif_colorspace_YCbCr, libheif.heif_chroma_420); if (!img || img.code) { console.log("Decoding image failed", this.handle, img); return; } - //this.data = new Uint8Array(StringToArrayBuffer(img.data)); - //delete img.data; - console.log(typeof(img.data)); - this.data = img.data; + this.data = new Uint8Array(StringToArrayBuffer(img.data)); + delete img.data; this.img = img; }; @@ -121,28 +118,26 @@ HeifImage.prototype.display = function(image_data, callback) { }.bind(this), 0); }; -var HeifDecoder = function(Module) { +var HeifDecoder = function() { this.decoder = null; - this.Module = Module; }; HeifDecoder.prototype.decode = function(buffer) { if (this.decoder) { - this.Module.heif_context_free(this.decoder); + libheif.heif_context_free(this.decoder); } - this.decoder = this.Module.heif_context_alloc(); + this.decoder = libheif.heif_context_alloc(); if (!this.decoder) { console.log("Could not create HEIF context"); return []; } - - var error = this.Module.heif_js_context_read_from_memory(this.decoder, buffer); - if (error.code !== this.Module.heif_error_code.heif_error_Ok) { + var error = libheif.heif_context_read_from_memory(this.decoder, buffer); + if (error.code !== libheif.heif_error_Ok) { console.log("Could not parse HEIF file", error); return []; } - var ids = this.Module.heif_js_context_get_list_of_top_level_image_IDs(this.decoder); + var ids = libheif.heif_js_context_get_list_of_top_level_image_IDs(this.decoder); if (!ids || ids.code) { console.log("Error loading image ids", ids); return []; @@ -154,13 +149,13 @@ HeifDecoder.prototype.decode = function(buffer) { var result = []; for (var i = 0; i < ids.length; i++) { - var handle = this.Module.heif_js_context_get_image_handle(this.decoder, ids[i]); + var handle = libheif.heif_js_context_get_image_handle(this.decoder, ids[i]); if (!handle || handle.code) { console.log("Could not get image data for id", ids[i], handle); continue; } - result.push(new HeifImage(handle, Module)); + result.push(new HeifImage(handle)); } return result; }; @@ -180,6 +175,26 @@ var libheif = { } }; +// don't pollute the global namespace +delete this['Module']; + +// On IE this function is called with "undefined" as first parameter. Override +// with a version that supports this behaviour. +function createNamedFunction(name, body) { + if (!name) { + name = "function_" + (new Date()); + } + name = makeLegalFunctionName(name); + /*jshint evil:true*/ + return new Function( + "body", + "return function " + name + "() {\n" + + " \"use strict\";" + + " return body.apply(this, arguments);\n" + + "};\n" + )(body); +} + var root = this; if (typeof exports !== 'undefined') { diff --git a/pre.js b/pre.js index 25e608e583..b8aea383ad 100644 --- a/pre.js +++ b/pre.js @@ -29,5 +29,49 @@ var Module = { console.error(text); }, canvas: {}, - noInitialRun: true + noInitialRun: true, + onRuntimeInitialized: function() { + // 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 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]; + } + + // Expose embind API. + for (key in Module) { + if (enums.hasOwnProperty(key) || key.indexOf("heif_") !== 0) { + continue; + } + libheif[key] = Module[key]; + } + + console.log(libheif); + } }; From 62b07dc8a7f2176aa71b074f8c56039b549e1f80 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 18 Jul 2023 22:29:44 +0200 Subject: [PATCH 5/9] Ability to install a specific version of the Emscripten SDK --- .github/workflows/emscripten.yml | 2 +- scripts/install-emscripten.sh | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 7c7d3fb536..07131585b6 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -9,7 +9,7 @@ on: jobs: emscripten: env: - EMSCRIPTEN_VERSION: 1.37.26 + EMSCRIPTEN_VERSION: 3.1.43 runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 diff --git a/scripts/install-emscripten.sh b/scripts/install-emscripten.sh index 7b5374731b..a7ad195606 100755 --- a/scripts/install-emscripten.sh +++ b/scripts/install-emscripten.sh @@ -2,15 +2,15 @@ set -e TARGET=$1 +TARGET=$2 -if [ -z "$TARGET" ]; then - echo "USAGE: $0 " +if [ -z "$VERSION" ] || [ -z "$TARGET" ]; then + echo "USAGE: $0 " exit 1 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.43 CODENAME=$(/usr/bin/lsb_release --codename --short) if [ "$CODENAME" = "trusty" ] && [ ! -e "/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21" ]; then @@ -32,13 +32,13 @@ if [ ! -d emsdk ]; then fi cd emsdk -echo "Updating SDK base to ${EMSDK_VERSION} ..." +echo "Updating SDK base to ${VERSION} ..." git checkout main git pull --verbose -git checkout ${EMSDK_VERSION} +git checkout ${VERSION} -echo "Installing SDK version ${VERSION} ..." +echo "Installing SDK version latest ..." ./emsdk install latest -echo "Activating SDK version ${VERSION} ..." +echo "Activating SDK version latest ..." ./emsdk activate latest From 73ee2aba13add9b2e47bd2dbf372c647556848a8 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 18 Jul 2023 22:34:58 +0200 Subject: [PATCH 6/9] Fix Emscripten install script, remove console log --- pre.js | 2 -- scripts/install-emscripten.sh | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pre.js b/pre.js index b8aea383ad..3978ad958f 100644 --- a/pre.js +++ b/pre.js @@ -71,7 +71,5 @@ var Module = { } libheif[key] = Module[key]; } - - console.log(libheif); } }; diff --git a/scripts/install-emscripten.sh b/scripts/install-emscripten.sh index a7ad195606..dd6c61fb18 100755 --- a/scripts/install-emscripten.sh +++ b/scripts/install-emscripten.sh @@ -1,7 +1,7 @@ #!/bin/sh set -e -TARGET=$1 +VERSION=$1 TARGET=$2 if [ -z "$VERSION" ] || [ -z "$TARGET" ]; then From ca8693a6012319f09969499bb0ad974ba38a567b Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 18 Jul 2023 22:55:18 +0200 Subject: [PATCH 7/9] Make sure the SDK installs the same version as the SDK --- scripts/install-emscripten.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/install-emscripten.sh b/scripts/install-emscripten.sh index dd6c61fb18..066c77f463 100755 --- a/scripts/install-emscripten.sh +++ b/scripts/install-emscripten.sh @@ -38,7 +38,7 @@ git pull --verbose git checkout ${VERSION} echo "Installing SDK version latest ..." -./emsdk install latest +./emsdk install ${VERSION} echo "Activating SDK version latest ..." -./emsdk activate latest +./emsdk activate ${VERSION} From 7d775a87a13a29a1e69b81a622ae72157f221fe7 Mon Sep 17 00:00:00 2001 From: Dirk Farin Date: Wed, 19 Jul 2023 18:09:21 +0200 Subject: [PATCH 8/9] add option to optionally turn off WASM --- build-emscripten.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build-emscripten.sh b/build-emscripten.sh index a53090ce73..f404ad481b 100755 --- a/build-emscripten.sh +++ b/build-emscripten.sh @@ -9,6 +9,7 @@ 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" @@ -90,12 +91,12 @@ EXPORTED_FUNCTIONS=$($EMSDK/upstream/bin/llvm-nm $LIBHEIFA --format=just-symbols echo "Running Emscripten..." -BUILD_FLAGS="-lembind -o libheif.js --pre-js pre.js --post-js post.js" +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="-s STANDALONE_WASM=1 -s WASM=1 -o libheif.wasm --no-entry" + BUILD_FLAGS="$BUILD_FLAGS -s STANDALONE_WASM=1 -s WASM=1 -o libheif.wasm --no-entry" fi if [ "$DEBUG" = "1" ]; then @@ -108,6 +109,7 @@ emcc "$LIBHEIFA" \ -s ALLOW_MEMORY_GROWTH=1 \ -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ -s LLD_REPORT_UNDEFINED \ + --memory-init-file 0 \ -std=c++11 \ $LIBRARY_INCLUDE_FLAGS \ $LIBRARY_LINKER_FLAGS \ From 1733e7bc86bc56691d00f07ca660b02dfcb7accd Mon Sep 17 00:00:00 2001 From: Dirk Farin Date: Wed, 19 Jul 2023 18:19:43 +0200 Subject: [PATCH 9/9] fix apparent typos in standard argument values --- build-emscripten.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-emscripten.sh b/build-emscripten.sh index f404ad481b..d94604b834 100755 --- a/build-emscripten.sh +++ b/build-emscripten.sh @@ -7,8 +7,8 @@ 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}" +STANDALONE="${STANDALONE:-0}" +DEBUG="${DEBUG:-0}" USE_WASM="${USE_WASM:-1}" echo "Build using ${CORES} CPU cores"