diff --git a/.gitignore b/.gitignore index 18f45fa4e04d1926aafd52048a865484b7baa505..92c9b7ea52f541b70e6f6a989c7fdbed83ab681a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Ignore build dirs +samples/ vlc/ emsdk/ # and files @@ -6,5 +7,5 @@ experimental.data experimental.html experimental.js experimental.wasm +experimental.wasm.map experimental.worker.js - diff --git a/compile.sh b/compile.sh index 04bac1b1d6ab9330e93b47ffe0951bf0ba1730e3..ec18c0409e205e2640bf598c46add205817d0362 100755 --- a/compile.sh +++ b/compile.sh @@ -1,4 +1,4 @@ -#! /bin/sh +#!/bin/sh set -e ## FUNCTIONS @@ -15,175 +15,57 @@ checkfail() exit 1 fi } + +SLOW_MODE=${SLOW_MODE:=1} WORK_DIR=$PWD +EMSDK_VERSION="2.0.25" # Download the portable SDK and uncompress it if [ ! -d emsdk ]; then diagnostic "emsdk not found. Fetching it" git clone http://github.com/emscripten-core/emsdk.git emsdk - cd emsdk && ./emsdk update-tags && ./emsdk install tot-upstream && ./emsdk activate tot-upstream + cd emsdk && ./emsdk update-tags && ./emsdk install ${EMSDK_VERSION} && ./emsdk activate ${EMSDK_VERSION} checkfail "emsdk: fetch failed" fi cd $WORK_DIR -TESTED_HASH="7bad2a86" +TESTED_HASH="3379c7bdba42984d56d311fcdc9810308b3a08b7" # Go go go vlc if [ ! -d vlc ]; then diagnostic "VLC source not found, cloning" - git clone http://git.videolan.org/git/vlc.git vlc || checkfail "VLC source: git clone failed" + git clone https://code.videolan.org/videolan/vlc.git vlc || checkfail "VLC source: git clone failed" cd vlc diagnostic "VLC source: resetting to the TESTED_HASH commit (${TESTED_HASH})" git reset --hard ${TESTED_HASH} || checkfail "VLC source: TESTED_HASH ${TESTED_HASH} not found" - cd .. - checkfail "vlc source: git clone failed" -fi - -cd vlc - -# Make in // -if [ -z "$MAKEFLAGS" ]; then - UNAMES=$(uname -s) - MAKEFLAGS= - if which nproc >/dev/null; then - MAKEFLAGS=-j`nproc` - elif [ "$UNAMES" == "Darwin" ] && which sysctl >/dev/null; then - MAKEFLAGS=-j`sysctl -n machdep.cpu.thread_count` + # patching vlc + if [ -d ../vlc_patches ] && [ "$(ls -A ../vlc_patches)" ]; then + # core patches + git am -3 ../vlc_patches/0001-configure-improve-testing-unsupported-GL-functions-f.patch + git am -3 ../vlc_patches/0001-modules-disable-libvlc_json-and-ytbdl-vlc.js-17.patch + git am -3 ../vlc_patches/nacl-wasm/00*.patch + git am -3 ../vlc_patches/audio_output/00*.patch + git am -3 ../vlc_patches/video_output/00*.patch + git am -3 ../vlc_patches/logger/00*.patch + # git am -3 ../vlc_patches/filesystem/*.patch fi + checkfail "vlc source: git clone failed" fi -# VLC tools -export PATH=`pwd`/extras/tools/build/bin:$PATH -echo "Building tools" -cd extras/tools -./bootstrap -checkfail "buildsystem tools: bootstrap failed" -make $MAKEFLAGS -checkfail "buildsystem tools: make" - cd $WORK_DIR - diagnostic "Setting the environment" -source emsdk/emsdk_env.sh -export PKG_CONFIG_PATH=$EMSDK/emscripten/incoming/system/lib/pkgconfig -export PKG_CONFIG_LIBDIR=$PWD/vlc/contrib/wasm32_unknowm_emscripten/lib/pkgconfig -export PKG_CONFIG_PATH_CUSTOM=$PKG_CONFIG_LIBDIR +. emsdk/emsdk_env.sh -# Check that clang is working -clang --version - -diagnostic "Patching" - -cd vlc - -# patching vlc -if [ -d ../vlc_patches ] && [ "$(ls -A ../vlc_patches)" ]; then - # core patches - git am -3 ../vlc_patches/0001-contrib-add-emscripten-target.patch - git am -3 ../vlc_patches/0002-contrib-add-ffmpeg-configuration-options-for-wasm-em.patch - git am -3 ../vlc_patches/0003-contrib-delete-empty-variable.patch - git am -3 ../vlc_patches/0006-configure-Create-a-target-for-emscripten-in-the-conf.patch - git am -3 ../vlc_patches/0007-core-initial-core-build-for-emscripten-based-on-POSI.patch - git am -3 ../vlc_patches/0008-compat-add-sigwait-support-for-emscripten.patch - git am -3 ../vlc_patches/0009-compat-add-clock_nanosleep-support.patch - git am -3 ../vlc_patches/0010-emscripten-add-vlc_getProxyUrl-stub.patch - git am -3 ../vlc_patches/0011-configure-disable-deprecated-GL-functions-for-emscri.patch - git am -3 ../vlc_patches/0012-logger-add-emscripten-module.patch - git am -3 ../vlc_patches/0013-window-add-emscripten-type.patch - git am -3 ../vlc_patches/0014-vout-add-emscripten-gl-es2-and-window-modules.patch - git am -3 ../vlc_patches/0015-vlc_common-add-weak-attribute-support-for-wasm.patch - git am -3 ../vlc_patches/0016-Add-meson_system_name-for-emscripten.patch - - # Add OPENAL support - git am -3 ../vlc_patches/openal/* -fi - -# BOOTSTRAP - -if [ ! -f configure ]; then - echo "Bootstraping" - ./bootstrap - checkfail "vlc: bootstrap failed" -fi - -############ -# Contribs # -############ - -echo "Building the contribs" -mkdir -p contrib/contrib-emscripten -cd contrib/contrib-emscripten - - ../bootstrap --disable-disc --disable-gpl --disable-sout \ - --disable-network \ - --host=wasm32-unknown-emscripten --build=x86_64-linux -checkfail "contribs: bootstrap failed" - -emmake make list -emmake make $MAKEFLAGS fetch -checkfail "contribs: make fetch failed" -emmake make $MAKEFLAGS .ffmpeg - -checkfail "contribs: make failed" - -cd ../../ - -# Build -mkdir -p build-emscripten && cd build-emscripten - -OPTIONS=" - --host=wasm32-unknown-emscripten - --enable-debug - --enable-gles2 - --disable-lua - --disable-ssp - --disable-nls - --disable-sout - --disable-vlm - --disable-addonmanagermodules - --enable-avcodec - --enable-merge-ffmpeg - --disable-swscale - --disable-a52 - --disable-x264 - --disable-xcb - --disable-alsa - --disable-macosx - --disable-sparkle - --disable-qt - --disable-screen - --disable-xcb - --disable-pulse - --disable-alsa - --disable-oss - --disable-vlc" -# --disable-xvideo Unknown option -# Note : -# search.h is a blacklisted module -# time.h is a blacklisted module -# shm.h is a blacklisted module -# ssp is not supported on the wasm backend - -emconfigure ../configure ${OPTIONS} \ - ac_cv_func_sendmsg=yes ac_cv_func_recvmsg=yes ac_cv_func_if_nameindex=yes ac_cv_header_search_h=no ac_cv_header_time_h=no ac_cv_header_sys_shm_h=no - -emmake make ${MAKEFLAGS} - -diagnostic "Generating module list" -cd ../.. -./generate_modules_list.sh -cd vlc/build-emscripten -emcc vlc-modules.c -o vlc-modules.bc -pthread -cd ../.. +diagnostic "build libvlc" +cd ./vlc/extras/package/wasm-emscripten/ +./build.sh --mode=${SLOW_MODE} url="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" -# copy Dolby_Canyon.vob diagnostic "getting video" -cd vlc/build-emscripten/ -curl ${url} -o BigBuckBunny.mp4 - cd $WORK_DIR - +mkdir -p samples/ +if [ ! -f "./samples/BigBuckBunny.mp4" ]; then + curl ${url} -o samples/BigBuckBunny.mp4 +fi diagnostic "Generating executable" -cp main.c vlc/build-emscripten/ ./create_main.sh diff --git a/create_main.sh b/create_main.sh index ed333faebd4a7455cd43128d0523f067a6ba9ef1..32b8cb41b6f04f5297bf6cfb25306a64f8968dc3 100755 --- a/create_main.sh +++ b/create_main.sh @@ -23,16 +23,23 @@ if [ ! -d vlc ]; then exit 1 fi -PROJECT_DIR=$(pwd)/vlc +PATH_VLC=${PATH_VLC:=./vlc} +SAMPLE_DIR=${SAMPLE_DIR:=./samples} -cd vlc/build-emscripten -# for release, remove profiling-funcs and add -Os -emcc -s USE_PTHREADS=1 -s TOTAL_MEMORY=1GB \ - -s OFFSCREEN_FRAMEBUFFER=1 --profiling-funcs \ - -I $PROJECT_DIR/include/ -I $PROJECT_DIR/contrib/wasm32-unknown-emscripten/include/ main.c \ - $PROJECT_DIR/build-emscripten/lib/.libs/libvlc.a \ - vlc-modules.bc $PROJECT_DIR/build-emscripten/modules/.libs/*.a \ - $PROJECT_DIR/contrib/wasm32-unknown-emscripten/lib/*.a \ - $PROJECT_DIR/build-emscripten/src/.libs/libvlccore.a \ - $PROJECT_DIR/build-emscripten/compat/.libs/libcompat.a \ - -o ../../experimental.html --emrun --preload-file BigBuckBunny.mp4 +# For release builds, remove '--profiling-funcs' and add '-Os' +# Note that we use '-s MODULARIZE', but no '-s EXPORT_ES6', which would +# conflict with pthreads on Firefox. +emcc --bind -s USE_PTHREADS=1 -s TOTAL_MEMORY=1GB -s PTHREAD_POOL_SIZE=15 \ + -s OFFSCREEN_FRAMEBUFFER=1 -s USE_WEBGL2=1 --profiling-funcs \ + -s MODULARIZE=1 -s EXPORT_NAME="VlcModule" \ + -s EXTRA_EXPORTED_RUNTIME_METHODS="allocateUTF8" \ + -I $PATH_VLC/include/ -I $PATH_VLC/wasm32-unknown-emscripten/include/ \ + main.c exports_media_player.c exports_media.c \ + $PATH_VLC/build-emscripten/lib/.libs/libvlc.a \ + $PATH_VLC/build-emscripten/vlc-modules.bc \ + $PATH_VLC/build-emscripten/modules/.libs/*.a \ + $PATH_VLC/contrib/wasm32-unknown-emscripten/lib/*.a \ + $PATH_VLC/build-emscripten/src/.libs/libvlccore.a \ + $PATH_VLC/build-emscripten/compat/.libs/libcompat.a \ + --js-library lib/wasm-imports.js \ + -o experimental.js --preload-file ${SAMPLE_DIR} diff --git a/exports_media.c b/exports_media.c new file mode 100644 index 0000000000000000000000000000000000000000..55d35e13faaf4050bd3b82f9b187c9336b6bf010 --- /dev/null +++ b/exports_media.c @@ -0,0 +1,23 @@ +// Re-exports of functions defined in "include/vlc/libvlc/media/player.h" +// See exports_media_player.c for why this is necessary. + +#include <vlc/vlc.h> +#include <vlc_common.h> + +#include <emscripten.h> +#include <emscripten/html5.h> + +// Singleton, defined in main.c +extern libvlc_instance_t *libvlc; + +libvlc_media_t* EMSCRIPTEN_KEEPALIVE wasm_media_new_path(const char *path) { + return libvlc_media_new_path(libvlc, path); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_retain( libvlc_media_t *media) { + libvlc_media_retain(media); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_release( libvlc_media_t *media) { + libvlc_media_release(media); +} diff --git a/exports_media_player.c b/exports_media_player.c new file mode 100644 index 0000000000000000000000000000000000000000..af61c3777543f27ea51f4259ba763529e5ac4396 --- /dev/null +++ b/exports_media_player.c @@ -0,0 +1,236 @@ +// Re-exports of functions defined in "include/vlc/libvlc/media/player.h" +// We need to re-export these functions to make sure they're included as +// symbols in the wasm binary. +// Emscripten provides two ways to do that: EMSCRIPTEN_KEEPALIVE, and the +// EXPORTED_FUNCTIONS argument. EXPORTED_FUNCTIONS is not reliable, because +// symbols might be inlined in intermediary passes. +// Also, some functions need some marshalling of arguments to be callabled +// from JS. + +#include <vlc/vlc.h> +#include <vlc_common.h> + +#include <emscripten.h> +#include <emscripten/html5.h> + +// Singleton, defined in main.c +extern libvlc_instance_t *libvlc; + +libvlc_media_player_t* EMSCRIPTEN_KEEPALIVE wasm_media_player_new() { + return libvlc_media_player_new(libvlc); +} + +libvlc_media_player_t* EMSCRIPTEN_KEEPALIVE wasm_media_player_new_from_media(libvlc_media_t* media) { + return libvlc_media_player_new_from_media(media); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_release(libvlc_media_player_t *media_player) { + libvlc_media_player_release(media_player); +} + +void EMSCRIPTEN_KEEPALIVE wasmc_media_player_retain(libvlc_media_player_t *media_player) { + libvlc_media_player_retain(media_player); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_set_media(libvlc_media_player_t *media_player, libvlc_media_t *media) { + libvlc_media_player_set_media(media_player, media); +} + +libvlc_media_t* EMSCRIPTEN_KEEPALIVE wasm_media_player_get_media(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_media(media_player); +} + +// TODO +// LIBVLC_API libvlc_event_manager_t * libvlc_media_player_event_manager (libvlc_media_player_t *p_mi ); + +EM_BOOL EMSCRIPTEN_KEEPALIVE wasm_media_player_is_playing(libvlc_media_player_t *media_player) { + return libvlc_media_player_is_playing(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_play(libvlc_media_player_t *media_player) { + return libvlc_media_player_play(media_player); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_set_pause(libvlc_media_player_t *media_player, int do_pause) { + libvlc_media_player_set_pause(media_player, do_pause); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_pause(libvlc_media_player_t *media_player) { + libvlc_media_player_pause(media_player); +} + +// TODO +// LIBVLC_API int libvlc_media_player_stop_async ( libvlc_media_player_t *p_mi ); + + +libvlc_time_t EMSCRIPTEN_KEEPALIVE wasm_media_player_get_length(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_length(media_player); +} + +libvlc_time_t EMSCRIPTEN_KEEPALIVE wasm_media_player_get_time(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_time(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_set_time(libvlc_media_player_t *media_player, libvlc_time_t time, bool fast) { + return libvlc_media_player_set_time(media_player, time, fast); +} + +float EMSCRIPTEN_KEEPALIVE wasm_media_player_get_position(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_position(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_set_position(libvlc_media_player_t *media_player, float position, EM_BOOL fast) { + return libvlc_media_player_set_position(media_player, position, fast); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_set_chapter(libvlc_media_player_t *media_player, int chapter) { + libvlc_media_player_set_chapter(media_player, chapter); +} + +float EMSCRIPTEN_KEEPALIVE wasm_media_player_get_chapter(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_chapter(media_player); +} + +float EMSCRIPTEN_KEEPALIVE wasm_media_player_get_chapter_count(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_chapter_count(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_get_chapter_count_for_title(libvlc_media_player_t *media_player, int title) { + return libvlc_media_player_get_chapter_count_for_title(media_player, title); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_set_title(libvlc_media_player_t *media_player, int title) { + libvlc_media_player_set_title(media_player, title); +} + +float EMSCRIPTEN_KEEPALIVE wasm_media_player_get_title(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_title(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_get_title_count( libvlc_media_player_t *media_player ) { + return libvlc_media_player_get_title_count(media_player); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_previous_chapter( libvlc_media_player_t *media_player ) { + libvlc_media_player_previous_chapter(media_player); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_next_chapter( libvlc_media_player_t *media_player ) { + libvlc_media_player_next_chapter(media_player); +} + +float EMSCRIPTEN_KEEPALIVE wasm_media_player_get_rate( libvlc_media_player_t *media_player ) { + return libvlc_media_player_get_rate(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_set_rate( libvlc_media_player_t *media_player, float rate ) { + return libvlc_media_player_set_rate(media_player, rate); +} + + +unsigned EMSCRIPTEN_KEEPALIVE wasm_media_player_has_vout( libvlc_media_player_t *media_player ) { + return libvlc_media_player_has_vout(media_player); +} + +EM_BOOL EMSCRIPTEN_KEEPALIVE wasm_media_player_is_seekable( libvlc_media_player_t *media_player ) { + return libvlc_media_player_is_seekable(media_player); +} + +EM_BOOL EMSCRIPTEN_KEEPALIVE wasm_media_player_can_pause( libvlc_media_player_t *media_player ) { + return libvlc_media_player_can_pause(media_player); +} + +EM_BOOL EMSCRIPTEN_KEEPALIVE wasm_media_player_program_scrambled( libvlc_media_player_t *media_player ) { + return libvlc_media_player_program_scrambled(media_player); +} + +void EMSCRIPTEN_KEEPALIVE wasm_media_player_next_frame( libvlc_media_player_t *media_player ) { + libvlc_media_player_next_frame(media_player); +} + + +int EMSCRIPTEN_KEEPALIVE wasm_video_get_size_x(libvlc_media_player_t *media_player, unsigned num) { + unsigned x = 0; + unsigned y = 0; + int res = libvlc_video_get_size(media_player, num, &x, &y); + if (res == -1) + return -1; + else + return x; +} + +int EMSCRIPTEN_KEEPALIVE wasm_video_get_size_y(libvlc_media_player_t *media_player, unsigned num) { + unsigned x = 0; + unsigned y = 0; + int res = libvlc_video_get_size(media_player, num, &x, &y); + if (res == -1) + return -1; + else + return y; +} + +int EMSCRIPTEN_KEEPALIVE wasm_video_get_cursor_x(libvlc_media_player_t *media_player, unsigned num) { + int x = 0; + int y = 0; + int res = libvlc_video_get_cursor(media_player, num, &x, &y); + if (res == -1) + return -1; + else + return x; +} + +int EMSCRIPTEN_KEEPALIVE wasm_video_get_cursor_y(libvlc_media_player_t *media_player, unsigned num) { + int x = 0; + int y = 0; + int res = libvlc_video_get_cursor(media_player, num, &x, &y); + if (res == -1) + return -1; + else + return y; +} + +void EMSCRIPTEN_KEEPALIVE wasm_audio_toggle_mute(libvlc_media_player_t *media_player) { + libvlc_audio_toggle_mute(media_player); +} + +EM_BOOL EMSCRIPTEN_KEEPALIVE wasm_audio_get_mute(libvlc_media_player_t *media_player) { + return libvlc_audio_get_mute(media_player); +} + +void EMSCRIPTEN_KEEPALIVE wasm_audio_set_mute(libvlc_media_player_t *media_player, int status) { + libvlc_audio_set_mute(media_player, status); +} + +int EMSCRIPTEN_KEEPALIVE wasm_audio_get_volume(libvlc_media_player_t *media_player) { + return libvlc_audio_get_volume(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_audio_set_volume(libvlc_media_player_t *media_player, int volume) { + return libvlc_audio_set_volume(media_player, volume); +} + +int EMSCRIPTEN_KEEPALIVE wasm_audio_get_channel(libvlc_media_player_t *media_player) { + return libvlc_audio_get_channel(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_audio_set_channel(libvlc_media_player_t *media_player, int channel) { + return libvlc_audio_set_channel(media_player, channel); +} + +int EMSCRIPTEN_KEEPALIVE wasm_audio_get_delay(libvlc_media_player_t *media_player) { + return libvlc_audio_get_delay(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_audio_set_delay(libvlc_media_player_t *media_player, int delay) { + return libvlc_audio_set_delay(media_player, delay); +} + +// TODO - Export libvlc_media_player_role constants + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_get_role(libvlc_media_player_t *media_player) { + return libvlc_media_player_get_role(media_player); +} + +int EMSCRIPTEN_KEEPALIVE wasm_media_player_set_role(libvlc_media_player_t *media_player, unsigned role) { + return libvlc_media_player_set_role(media_player, role); +} diff --git a/generate_modules_list.sh b/generate_modules_list.sh deleted file mode 100755 index 9c3e3ebf775c9005d69e79c037d417dfc0b0fbf9..0000000000000000000000000000000000000000 --- a/generate_modules_list.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -e - -## FUNCTIONS - -diagnostic() -{ - echo "$@" 1>&2; -} - -checkfail() -{ - if [ ! $? -eq 0 ];then - diagnostic "$1" - exit 1 - fi -} - -get_symbol() -{ - echo "$1" | grep vlc_entry_$2 | cut -d " " -f 3 -} - -source emsdk/emsdk_env.sh - -if [ ! -d vlc ]; then - diagnostic "vlc must exists. Execute compile.sh" - exit 1 -fi - -cd vlc - -PROJECT_DIR=$(pwd) -NM="$EMSDK/upstream/bin/llvm-nm" - -cd build-emscripten/modules/.libs - -# create module list -echo "creating module list" -touch $PROJECT_DIR/build-emscripten/vlc-modules.c -echo -e "// This file is autogenerated" > $PROJECT_DIR/build-emscripten/vlc-modules.c -echo -e "#include <unistd.h>\n\n" >> $PROJECT_DIR/build-emscripten/vlc-modules.c - - -BUILTINS="const void *vlc_static_modules[] = {\n" -LDFLAGS="" -DEFINITIONS="" -VLCMODULES="" -i="" - -for i in `ls *plugin.a` -do - VLCMODULES="$i $VLCMODULES" -done - -for file in $VLCMODULES - do - symbols=$($NM -g $file) - entryname=$(get_symbol "$symbols" _) - DEFINITIONS+="int $entryname (int (*)(void *, void *, int, ...), void *);\n"; - BUILTINS+=" $entryname,\n" - LDFLAGS+="\$PROJECT_DIR/build-emscripten/modules/.libs/$file " - done; - -cd ../.. - -BUILTINS="$BUILTINS NULL\n};\n" - -echo -e "$DEFINITIONS\n$BUILTINS" >> $PROJECT_DIR/build-emscripten/vlc-modules.c diff --git a/lib/libvlc.js b/lib/libvlc.js new file mode 100644 index 0000000000000000000000000000000000000000..51a8e4d2bbd5a2d4813d400b3c765896a8505717 --- /dev/null +++ b/lib/libvlc.js @@ -0,0 +1,244 @@ +// Encapsulate functions exported from exports_*.c + +// Encapsulates libvlc_media_player_t +export class MediaPlayer { + constructor(module, path) { + this.module = module; + this.media_player_ptr = module._wasm_media_player_new(); + module._attach_update_events(this.media_player_ptr); + + if (path != null) { + let media = new Media(module, path); + this.set_media(media); + media.release(); + } + } + + release() { + this.module._wasm_media_player_release(this.media_player_ptr); + this.media_player_ptr = 0; + } + + set_media(media) { + // TODO - assert typeof + this.module._wasm_media_player_set_media(this.media_player_ptr, media.media_ptr); + } + + get_media() { + let media_ptr = this.module._wasm_media_player_get_media(this.media_player_ptr); + this.module._wasm_media_retain(media_ptr); + // Build from raw ptr + return new Media(this.module, null, media_ptr); + } + + toggle_play() { + if (!this.is_playing()) { + this.play(); + } + else { + this.pause(); + } + } + + is_playing() { + return this.module._wasm_media_player_is_playing(this.media_player_ptr); + } + + play() { + return this.module._wasm_media_player_play(this.media_player_ptr); + } + + set_pause(do_pause) { + return this.module._wasm_media_player_set_pause(this.media_player_ptr, do_pause); + } + + pause() { + return this.module._wasm_media_player_pause(this.media_player_ptr); + } + + get_length() { + return this.module._wasm_media_player_get_length(this.media_player_ptr); + } + + get_time() { + return this.module._wasm_media_player_get_time(this.media_player_ptr); + } + + set_time(time, fast = false) { + // TODO - what does "fast" argument do? + return this.module._wasm_media_player_set_time(this.media_player_ptr, time, fast); + } + + get_position() { + return this.module._wasm_media_player_get_position(this.media_player_ptr); + } + + set_position(position, fast = false) { + // TODO - what does "fast" argument do? + return this.module._wasm_media_player_set_position(this.media_player_ptr, position, fast); + } + + set_chapter(chapter) { + this.module._wasm_media_player_set_chapter(this.media_player_ptr, chapter); + } + + get_chapter() { + return this.module._wasm_media_player_get_chapter(this.media_player_ptr); + } + + get_chapter_count() { + return this.module._wasm_media_player_get_chapter_count(this.media_player_ptr); + } + + get_chapter_count_for_title(title) { + return this.module._wasm_media_player_get_chapter_count_for_title(this.media_player_ptr, title); + } + + set_title(title) { + this.module._wasm_media_player_set_title(this.media_player_ptr, title); + } + + get_title() { + return this.module._wasm_media_player_get_title(this.media_player_ptr); + } + + get_title_count() { + return this.module._wasm_media_player_get_title_count(this.media_player_ptr); + } + + previous_chapter() { + return this.module._wasm_media_player_previous_chapter(this.media_player_ptr); + } + + next_chapter() { + return this.module._wasm_media_player_next_chapter(this.media_player_ptr); + } + + get_rate() { + return this.module._wasm_media_player_get_rate(this.media_player_ptr); + } + + set_rate(rate) { + return this.module._wasm_media_player_set_rate(this.media_player_ptr, rate); + } + + has_vout() { + return this.module._wasm_media_player_has_vout(this.media_player_ptr); + } + + is_seekable() { + return this.module._wasm_media_player_is_seekable(this.media_player_ptr); + } + + can_pause() { + return this.module._wasm_media_player_can_pause(this.media_player_ptr); + } + + program_scrambled() { + return this.module._wasm_media_player_program_scrambled(this.media_player_ptr); + } + + next_frame() { + return this.module._wasm_media_player_next_frame(this.media_player_ptr); + } + + get_size() { + let x = this.module._wasm_video_get_size_x(this.media_player_ptr); + let y = this.module._wasm_video_get_size_y(this.media_player_ptr); + + if (x == -1 || y == -1) { + // TODO - give more context + throw new Error("Cannot get video size"); + } + + return { x, y }; + } + + get_cursor() { + let x = this.module._wasm_video_get_cursor_x(this.media_player_ptr); + let y = this.module._wasm_video_get_cursor_y(this.media_player_ptr); + + if (x == -1 || y == -1) { + // TODO - give more context + throw new Error("Cannot get video cursor"); + } + + return { x, y }; + } + + toggle_mute() { + this.module._wasm_audio_toggle_mute(this.media_player_ptr); + } + + get_mute() { + return this.module._wasm_audio_get_mute(this.media_player_ptr); + } + + set_mute(mute) { + this.module._wasm_audio_set_mute(this.media_player_ptr, mute); + } + + get_volume() { + return this.module._wasm_audio_get_volume(this.media_player_ptr); + } + + set_volume(volume) { + return this.module._wasm_audio_set_volume(this.media_player_ptr, volume); + } + + get_channel() { + return this.module._wasm_audio_get_channel(this.media_player_ptr); + } + + set_channel(rate) { + return this.module._wasm_audio_set_channel(this.media_player_ptr, rate); + } + + get_delay() { + return this.module._wasm_audio_get_delay(this.media_player_ptr); + } + + set_delay(rate) { + return this.module._wasm_audio_set_delay(this.media_player_ptr, rate); + } + + get_role() { + return this.module._wasm_media_player_get_role(this.media_player_ptr); + } + + set_role(role) { + return this.module._wasm_media_player_set_role(this.media_player_ptr, role); + } +} + + +// Encapsulates libvlc_media_t +export class Media { + constructor(module, path, raw_ptr) { + if (raw_ptr != null) { + this.module = module; + this.media_ptr = raw_ptr; + return; + } + + if (typeof path != 'string') { + throw new Error("Tried to create Media with invalid value"); + } + + this.module = module; + + let path_ptr = module.allocateUTF8(path) + this.media_ptr = module._wasm_media_new_path(path_ptr); + module._free(path_ptr); + + if (this.media_ptr == 0) { + // TODO - give more context + throw new Error(`Could not create media from path {path}`); + } + } + + release() { + this.module._wasm_media_release(this.media_ptr); + this.media_ptr = 0; + } +} diff --git a/assets/module-loader.js b/lib/module-loader.js similarity index 59% rename from assets/module-loader.js rename to lib/module-loader.js index f536ca5b08c07b8cbc87face67879f8d254d2309..1e89cc4e066b681e8e7e6354643e95d3ec92c07e 100644 --- a/assets/module-loader.js +++ b/lib/module-loader.js @@ -2,9 +2,20 @@ var statusElement = document.getElementById('status'); var progressElement = document.getElementById('progress'); var spinnerElement = document.getElementById('spinner'); -var Module = { +var VlcModuleExt = { preRun: [], - postRun: [], + postRun: [ function() { + // This should run after the wasm module is instantiated + // before, the Pthread object won't be available + VlcModuleExt.PThread.receiveObjectTransfer = function (data) { + // Transfer messages from worker threads to the main window. + let event = new CustomEvent('worker_message', { + detail: data.msg + }); + window.dispatchEvent(event); + }; + }], + print: (function() { var element = document.getElementById('output'); if (element) element.value = ''; // clear browser cache @@ -26,22 +37,39 @@ var Module = { if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); console.error(text); }, + canvas: (function() { var canvas = document.getElementById('canvas') + var overlay = document.getElementById('overlay') // As a default initial behavior, pop up an alert when webgl context is lost. To make your // application robust, you may want to override this behavior before shipping! // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 - canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false) + canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); + + overlay.addEventListener('click', (event) => { + window.on_overlay_click(overlay, event); + }); + + // Create a global window.display_overlay variable to track whether + // the UI should be visible - see update_overlay function + window.display_overlay = true, + overlay.addEventListener('mouseenter', e => { + window.display_overlay = true; + }); + overlay.addEventListener('mouseleave', e => { + window.display_overlay = false; + }); + return canvas; })(), setStatus: function(text) { - if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; - if (text === Module.setStatus.last.text) return; + if (!VlcModuleExt.setStatus.last) VlcModuleExt.setStatus.last = { time: Date.now(), text: '' }; + if (text === VlcModuleExt.setStatus.last.text) return; var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); var now = Date.now(); - if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon - Module.setStatus.last.time = now; - Module.setStatus.last.text = text; + if (m && now - VlcModuleExt.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon + VlcModuleExt.setStatus.last.time = now; + VlcModuleExt.setStatus.last.text = text; if (m) { text = m[1]; progressElement.value = parseInt(m[2])*100; @@ -59,15 +87,6 @@ var Module = { totalDependencies: 0, monitorRunDependencies: function(left) { this.totalDependencies = Math.max(this.totalDependencies, left); - Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); + VlcModuleExt.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); } }; -Module.setStatus('Downloading...'); -window.onerror = function(event) { - // TODO: do not warn on ok events like simulating an infinite loop or exitStatus - Module.setStatus('Exception thrown, see JavaScript console'); - spinnerElement.style.display = 'none'; - Module.setStatus = function(text) { - if (text) Module.printErr('[post-exception status] ' + text); - }; -}; \ No newline at end of file diff --git a/lib/overlay.js b/lib/overlay.js new file mode 100644 index 0000000000000000000000000000000000000000..7e0d627386bc27abef1d9df4c113ddcfa533d13b --- /dev/null +++ b/lib/overlay.js @@ -0,0 +1,230 @@ +// Functions to manage both the layout and user inputs of the video overlay +// It's very artisanal and would usually be done with a framework like +// React, but it's enough for the needs of the project. + +const PROGRESS_BAR_COLOR = "#2a81d4"; +const PROGRESS_BAR_BG_COLOR = "#2d2d2d"; +const VOLUME_BAR_COLOR = "#4ad24a"; +const VOLUME_BAR_MUTE_COLOR = "#4d704e"; +const VOLUME_BAR_BG_COLOR = "#2d2d2d"; + +const BUTTON_BG_COLOR = "#464646"; +const GENERAL_BG_COLOR = "#353535"; +const TEXT_COLOR = "#8d8d8c"; + +const MENU_BAR_HEIGHT = 30; +const BUTTON_SIZE = 20; +const GAP_SIZE = 5; + +function get_layout(canvas) { + const VOLUME_BAR_WIDTH = 100; + const VOLUME_BAR_HEIGHT = 20; + + const PROGRESS_TEXT_WIDTH = 80; + + const PROGRESS_BAR_WIDTH = canvas.width - + (GAP_SIZE + BUTTON_SIZE + GAP_SIZE + GAP_SIZE + BUTTON_SIZE + GAP_SIZE + PROGRESS_TEXT_WIDTH + GAP_SIZE + VOLUME_BAR_WIDTH + GAP_SIZE); + const PROGRESS_BAR_HEIGHT = 10; + + const PLAY_BUTTON_X = GAP_SIZE; + const PROGRESS_BAR_X = PLAY_BUTTON_X + BUTTON_SIZE + GAP_SIZE; + const PROGRESS_TEXT_X = PROGRESS_BAR_X + PROGRESS_BAR_WIDTH + GAP_SIZE; + const VOLUME_BUTTON_X = PROGRESS_TEXT_X + PROGRESS_TEXT_WIDTH + GAP_SIZE; + const VOLUME_BAR_X = VOLUME_BUTTON_X + BUTTON_SIZE + GAP_SIZE; + + return { + VOLUME_BAR_WIDTH, + VOLUME_BAR_HEIGHT, + PROGRESS_TEXT_WIDTH, + PROGRESS_BAR_WIDTH, + PROGRESS_BAR_HEIGHT, + PLAY_BUTTON_X, + PROGRESS_BAR_X, + PROGRESS_TEXT_X, + VOLUME_BUTTON_X, + VOLUME_BAR_X, + }; +} + +const central_play_icon = new Image(50, 50); +central_play_icon.src = "vlc/modules/gui/qt/pixmaps/play_button.svg"; + +const play_button = new Image(BUTTON_SIZE, BUTTON_SIZE); +play_button.src = "vlc/modules/gui/qt/pixmaps/play.png"; +const pause_button = new Image(BUTTON_SIZE, BUTTON_SIZE); +pause_button.src = "vlc/modules/gui/qt/pixmaps/pause.png"; + +const volume_button = new Image(BUTTON_SIZE, BUTTON_SIZE); +volume_button.src = "vlc/modules/gui/qt/pixmaps/toolbar/volume-medium.png"; +const muted_button = new Image(BUTTON_SIZE, BUTTON_SIZE); +muted_button.src = "vlc/modules/gui/qt/pixmaps/toolbar/volume-muted.png"; + +// Apply underlying changes (eg video is paused) to the displayed UI +export function update_overlay(overlay) { + const ctx = overlay.getContext("2d"); + const media_player = window.media_player; + if (media_player == null) { + return; + } + + const { + VOLUME_BAR_WIDTH, + VOLUME_BAR_HEIGHT, + PROGRESS_TEXT_WIDTH, + PROGRESS_BAR_WIDTH, + PROGRESS_BAR_HEIGHT, + PLAY_BUTTON_X, + PROGRESS_BAR_X, + PROGRESS_TEXT_X, + VOLUME_BUTTON_X, + VOLUME_BAR_X, + } = get_layout(overlay); + + ctx.save(); + ctx.clearRect(0, 0, overlay.width, overlay.height); + + let is_paused = !media_player.is_playing(); + + if (is_paused) { + ctx.drawImage( + central_play_icon, + overlay.width / 2 - central_play_icon.width / 2, + overlay.height / 2 - central_play_icon.height / 2, + central_play_icon.width, + central_play_icon.height, + ); + } + + if (window.display_overlay) { + // -- PAINT BACKGROUND -- + ctx.fillStyle = GENERAL_BG_COLOR; + ctx.fillRect( + 0, overlay.height - MENU_BAR_HEIGHT, + overlay.width, MENU_BAR_HEIGHT + ); + + let y = overlay.height - MENU_BAR_HEIGHT; + + // -- DRAW PLAY/PAUSE BUTTON -- + ctx.drawImage(is_paused ? play_button : pause_button, + GAP_SIZE, y + (MENU_BAR_HEIGHT - BUTTON_SIZE) / 2, + BUTTON_SIZE, BUTTON_SIZE + ); + + // -- DRAW PROGRESS BAR -- + let position = media_player.get_position(); + + ctx.fillStyle = PROGRESS_BAR_BG_COLOR; + ctx.fillRect( + PROGRESS_BAR_X, y + (MENU_BAR_HEIGHT - PROGRESS_BAR_HEIGHT) / 2, + PROGRESS_BAR_WIDTH, PROGRESS_BAR_HEIGHT + ); + ctx.fillStyle = PROGRESS_BAR_COLOR; + ctx.fillRect( + PROGRESS_BAR_X, y + (MENU_BAR_HEIGHT - PROGRESS_BAR_HEIGHT) / 2, + PROGRESS_BAR_WIDTH * position, PROGRESS_BAR_HEIGHT + ); + + // DRAW PROGRESS TEXT (eg: 12:31 / 15:00) -- + let time = media_player.get_time(); + let seconds = Math.trunc(time / 1000); + let minutes = Math.trunc(seconds / 60); + seconds = seconds % 60; + let max_time = media_player.get_length(); + let max_seconds = Math.trunc(max_time / 1000); + let max_minutes = Math.trunc(max_seconds / 60); + max_seconds = max_seconds % 60; + + ctx.textAlign = "right"; + ctx.textBaseline = "middle"; + ctx.fillStyle = TEXT_COLOR; + ctx.fillText( + `${minutes}:${seconds} / ${max_minutes}:${max_seconds}`, + PROGRESS_TEXT_X + PROGRESS_TEXT_WIDTH, y + MENU_BAR_HEIGHT / 2, + ); + + // -- DRAW VOLUME/MUTE BUTTON -- + let is_muted = media_player.get_mute(); + ctx.drawImage(is_muted ? muted_button : volume_button, + VOLUME_BUTTON_X, y + (MENU_BAR_HEIGHT - BUTTON_SIZE) / 2, + BUTTON_SIZE, BUTTON_SIZE + ); + + // -- DRAW VOLUME BAR -- + let volume = media_player.get_volume() / 100; + + ctx.fillStyle = VOLUME_BAR_BG_COLOR; + ctx.fillRect( + VOLUME_BAR_X, y + (MENU_BAR_HEIGHT - VOLUME_BAR_HEIGHT) / 2, + VOLUME_BAR_WIDTH, VOLUME_BAR_HEIGHT + ); + ctx.fillStyle = is_muted ? VOLUME_BAR_MUTE_COLOR : VOLUME_BAR_COLOR; + ctx.fillRect( + VOLUME_BAR_X, y + (MENU_BAR_HEIGHT - VOLUME_BAR_HEIGHT) / 2, + VOLUME_BAR_WIDTH * volume, VOLUME_BAR_HEIGHT + ); + } + + ctx.restore(); +} + +export function on_overlay_click(overlay, mouse_event) { + const ctx = overlay.getContext("2d"); + const media_player = window.media_player; + + if (media_player == null) { + // Video isn't loaded yet + return; + } + + const { + VOLUME_BAR_WIDTH, + VOLUME_BAR_HEIGHT, + PROGRESS_BAR_WIDTH, + PROGRESS_BAR_HEIGHT, + PLAY_BUTTON_X, + PROGRESS_BAR_X, + VOLUME_BUTTON_X, + VOLUME_BAR_X, + } = get_layout(overlay); + + let canvas_rect = mouse_event.target.getBoundingClientRect(); + let x = mouse_event.clientX - canvas_rect.left; + let y = mouse_event.clientY - canvas_rect.top; + + // User clicked in menu bar + if (y > overlay.height - MENU_BAR_HEIGHT) { + // User clicked on play/pause button + if (x > PLAY_BUTTON_X && x < PLAY_BUTTON_X + BUTTON_SIZE) { + media_player.toggle_play(); + update_overlay(overlay); + } + + // User clicked on progress bar + if (x > PROGRESS_BAR_X && x < PROGRESS_BAR_X + PROGRESS_BAR_WIDTH) { + let progress = (x - PROGRESS_BAR_X) / PROGRESS_BAR_WIDTH; + media_player.set_position(progress); + update_overlay(overlay); + } + + // User clicked on volume/mute button + if (x > VOLUME_BUTTON_X && x < VOLUME_BUTTON_X + BUTTON_SIZE) { + media_player.toggle_mute(); + update_overlay(overlay); + } + + // User clicked on volume bar + if (x > VOLUME_BAR_X && x < VOLUME_BAR_X + VOLUME_BAR_WIDTH) { + let new_volume = (x - VOLUME_BAR_X) / VOLUME_BAR_WIDTH; + media_player.set_volume(new_volume * 100); + // Unmute + media_player.set_mute(0); + update_overlay(overlay); + } + } + + // User clicked outside the menu bar + else { + media_player.toggle_play(); + } +} diff --git a/lib/wasm-imports.js b/lib/wasm-imports.js new file mode 100644 index 0000000000000000000000000000000000000000..a3c7df201e76a5c32356f06030db598f63daedfe --- /dev/null +++ b/lib/wasm-imports.js @@ -0,0 +1,21 @@ +// Functions injected into the wasm binary, can be +// called from C/C++ code. +// The top level of this JS file is executed at compile time. +// Functions bodies are copy-pasted into 'experimental.js' +// (unless they're culled from dead code elimination) + +mergeInto(LibraryManager.library, { + // Apply underlying changes (eg video is paused) to the displayed UI + update_overlay: function() { + const overlay = document.getElementById("overlay"); + update_overlay(overlay); + }, + + // Worker functions - These are intended to be called from threads + // They can't access the browser APIs directly, so they send messages + + // TODO - This essentially sends one message per frame; might be bad for perf + on_position_changed: function() { + postMessage({ cmd: "objectTransfer", msg: "on_position_changed" }); + } +}); diff --git a/main.c b/main.c index c39c1b1116f1f39a551acbdef5e635e9d77f2fd3..6c04056a2ec85a9774f48f848be273a5dce108bf 100644 --- a/main.c +++ b/main.c @@ -1,18 +1,20 @@ #include <stdio.h> #include <vlc/vlc.h> #include <vlc_common.h> +#include <assert.h> #include <errno.h> #include <emscripten.h> #include <emscripten/html5.h> libvlc_media_player_t *mp; -libvlc_instance_t *libvlc; +libvlc_instance_t *libvlc; libvlc_time_t t = -1; -char flag = 1; static void iter() { + if (!mp) + return; if (libvlc_media_player_get_time(mp) == t) { // when enable, the js does not respond. //libvlc_media_player_release( mp ); @@ -22,72 +24,57 @@ static void iter() t = libvlc_media_player_get_time(mp); } -static EM_BOOL play_pause_handler(int eventType, const EmscriptenMouseEvent *e, void *userData) -{ - (void) e; - (void) userData; // To use when mp won't be a global. - if (eventType == EMSCRIPTEN_EVENT_CLICK) - { - if (flag == 1) - { - libvlc_media_player_play(mp); - flag = 0; - } - // Don't do that until you implement a/v synchro. - // libvlc_media_player_pause(mp); - // flag = 1; - } - return 0; +void EMSCRIPTEN_KEEPALIVE set_global_media_player(libvlc_media_player_t *media_player) { + mp = media_player; } +extern void update_overlay(); +extern void on_position_changed(const libvlc_event_t *p_event, void *p_data); + int main() { /* We don't want to the main thread stop even if the main function exit. * If this thread stop, all proxyfied functions wont be called. */ EM_ASM(Module['noExitRuntime']=true); - emscripten_set_element_css_size("#canvas", 720, 540); - libvlc_media_t *m; char const *vlc_argv[] = { "-vvv", "--no-spu", "--no-osd", + "--aout=emworklet_audio", "-Idummy", "--ignore-config", }; - + libvlc = libvlc_new( ARRAY_SIZE( vlc_argv ), vlc_argv ); - if (libvlc == NULL) { fprintf( stderr, "unable to create libvlc instance" ); return -1; } - m = libvlc_media_new_path( libvlc, "./BigBuckBunny.mp4" ); - - if (m == NULL) - { - fprintf(stderr, "unable to create media"); - return -1; - } - mp = libvlc_media_player_new_from_media( m ); - if (mp == NULL) - { - fprintf(stderr, "unable to create media player"); - return -1; - } - - libvlc_media_release( m ); - m = libvlc_media_player_get_media(mp); - // libvlc_audio_set_volume (mp, 100); - // int res = libvlc_media_player_play (mp); - /* if (res != 0) { - fprintf( stderr, "unable to play media" ); - return -1; - } - */ - emscripten_set_click_callback("#canvas", 0, 1, play_pause_handler); + emscripten_set_main_loop(iter, 1, 1); - + return 0; } + +// Used to make sure the UI (progress bar, play/pause button, etc) is +// updated as the video is read. +void EMSCRIPTEN_KEEPALIVE attach_update_events(libvlc_media_player_t *media_player) { + libvlc_event_manager_t* event_manager = libvlc_media_player_event_manager(media_player); + int res; + res = libvlc_event_attach( + event_manager, + libvlc_MediaPlayerPositionChanged, + on_position_changed, + NULL + ); + assert(res == 0); + res = libvlc_event_attach( + event_manager, + libvlc_MediaPlayerPaused, + on_position_changed, + NULL + ); + assert(res == 0); +} diff --git a/vlc.html b/vlc.html index 5042212616bdaf22f91d67419f1f4b21d91caee1..29e1ebe482a00a825142955dd29edf0ddc456fd5 100644 --- a/vlc.html +++ b/vlc.html @@ -11,12 +11,24 @@ body { background-color: #343a40; } - canvas.emscripten { + #canvas { border:0 !important; display: flex; margin: 0 auto; background-color: #000; } + #overlay { + border:0 !important; + display: flex; + margin: 0 auto; + } + #stack { + display: grid; + } + #stack > canvas { + grid-column: 1; + grid-row: 1; + } #spinner { display: none; } @@ -57,22 +69,76 @@ </head> <body> <div class="emscripten_border"> - <div class="emscripten"> + <div class="emscripten"> <div class="banner"> <img src="./assets/emscripten.svg" id ="em_logo"> <div class="vlc_head"> <img src="./assets/VLC_Icon.svg" id="logo"> <span id="point">.</span> - <span id="js">JS</span> + <span id="js">JS</span> </div> </div> <progress id="progress" value="0" max="100"></progress> <div class="spinner" id='spinner'></div> <div class="emscripten" id="status">Downloading...</div> </div> - <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> </div> - <script type="text/javascript" src="./assets/module-loader.js"></script> - <script async type="text/javascript" src="./experimental.js"></script> + + <div id="stack"> + <canvas + class="emscripten" id="canvas" + oncontextmenu="event.preventDefault()" tabindex=-1 + width=1280 height=720 + ></canvas> + <canvas + class="emscripten hidden" id="overlay" + oncontextmenu="event.preventDefault()" tabindex=-2 + width=1280 height=720 + ></canvas> + </div> + + <script src="./lib/module-loader.js"></script> + <script src="./experimental.js"></script> + + <script type="module"> + import { update_overlay, on_overlay_click } from "./lib/overlay.js"; + import { MediaPlayer } from "./lib/libvlc.js"; + + // VlcModule is a function generated by emscripten in experimental.js, + // that loads the wasm file and generates a module object from it. + // VlcModuleExt is an object defined in 'lib/module-loader.js' with a + // bunch of options; also, all the fields of VlcModuleExt are added to + // the returned Module. + const Module = await VlcModule(VlcModuleExt); + + window.onerror = function(event) { + // TODO: do not warn on ok events like simulating an infinite loop or exitStatus + Module.setStatus('Exception thrown, see JavaScript console'); + spinnerElement.style.display = 'none'; + Module.setStatus = function(text) { + if (text) Module.printErr('[post-exception status] ' + text); + }; + }; + + const overlay = document.getElementById("overlay"); + const media_player = new MediaPlayer(Module, "./samples/BigBuckBunny.mp4"); + + // FIXME + Module._set_global_media_player(media_player.media_player_ptr); + + window.media_player = media_player; + window.on_overlay_click = on_overlay_click; + window.update_overlay = update_overlay; + + update_overlay(overlay); + + addEventListener('worker_message', function(msg) { + if (msg.detail === "on_position_changed") { + update_overlay(overlay); + } + }); + </script> + + </body> </html> diff --git a/vlc_patches/0001-configure-improve-testing-unsupported-GL-functions-f.patch b/vlc_patches/0001-configure-improve-testing-unsupported-GL-functions-f.patch new file mode 100644 index 0000000000000000000000000000000000000000..d5e39a521f17e0ff956a60f1f4e2df45e53ce0a7 --- /dev/null +++ b/vlc_patches/0001-configure-improve-testing-unsupported-GL-functions-f.patch @@ -0,0 +1,42 @@ +From b848ce9dd721810e11a1566d9dfdea3c34c13ace Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Tue, 27 Apr 2021 15:34:23 +0200 +Subject: [PATCH 1/1] configure: improve testing unsupported GL functions for + emscripten + +The build system assumes OpenGL functions are implemented if the headers are defined. +Which is wrong, so we need to disable the HAVE_GL marker, if linking fails. + +we use AM_LINK_IFELSE() because AC_COMPILE will add the "-c" option, and thus +in wasm-emscripten this function will appear supported even if it is not. +--- + configure.ac | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 374ce00cc7..81abc3fcf0 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3311,13 +3311,16 @@ PKG_CHECK_MODULES([GL], [gl], [ + have_gl="yes" + ], [ + AC_MSG_CHECKING([for OpenGL]) +- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ++ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #ifdef _WIN32 + # include <GL/glew.h> + #endif + #include <GL/gl.h> +-]], [ +- [int t0 = GL_TEXTURE0;]]) ++]], [[ ++ int t0 = GL_TEXTURE0; ++ // glColorMaterial is unavailable in webgl, and emscripten ++ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); ++ ]]) + ], [ + GL_CFLAGS="" + have_gl="yes" +-- +2.32.0 + diff --git a/vlc_patches/0001-contrib-add-emscripten-target.patch b/vlc_patches/0001-contrib-add-emscripten-target.patch deleted file mode 100644 index f42ffd4276ff8a189c8122f063dad14784a3effe..0000000000000000000000000000000000000000 --- a/vlc_patches/0001-contrib-add-emscripten-target.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 89483da629c05701ac2ff8a157a67e031e5e471f Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Mon, 30 Dec 2019 13:55:23 +0100 -Subject: [PATCH 1/1] contrib: add emscripten target - -set toolchain variables in bootstrap and main.mak - -Co-Author: Etienne Brateau <etienne.brateau@gmail.com> ---- - contrib/bootstrap | 3 +++ - contrib/src/main.mak | 9 +++++++++ - 2 files changed, 12 insertions(+) - -diff --git a/contrib/bootstrap b/contrib/bootstrap -index 01a234e55c..b6224bae9d 100755 ---- a/contrib/bootstrap -+++ b/contrib/bootstrap -@@ -348,6 +348,9 @@ case "${OS}" in - *nacl*) - add_make_enabled "HAVE_NACL" - ;; -+ *emscripten*) -+ add_make_enabled "HAVE_EMSCRIPTEN" -+ ;; - esac - - # -diff --git a/contrib/src/main.mak b/contrib/src/main.mak -index 5e5846de97..897020517e 100644 ---- a/contrib/src/main.mak -+++ b/contrib/src/main.mak -@@ -133,6 +133,15 @@ EXTRA_CFLAGS += -fno-stack-check - XCODE_FLAGS += OTHER_CFLAGS=-fno-stack-check - endif - -+ifdef HAVE_EMSCRIPTEN -+CC := emcc -+CXX := em++ -+LD := emcc -+AR := emar -+RANLIB := emranlib -+CFLAGS="-pthread" -+endif -+ - ifdef HAVE_MACOSX - EXTRA_CXXFLAGS += -stdlib=libc++ - ifeq ($(ARCH),x86_64) --- -2.24.1 - diff --git a/vlc_patches/0001-modules-disable-libvlc_json-and-ytbdl-vlc.js-17.patch b/vlc_patches/0001-modules-disable-libvlc_json-and-ytbdl-vlc.js-17.patch new file mode 100644 index 0000000000000000000000000000000000000000..6a81d35083ff2d06df598173bd600e0c21b410e3 --- /dev/null +++ b/vlc_patches/0001-modules-disable-libvlc_json-and-ytbdl-vlc.js-17.patch @@ -0,0 +1,37 @@ +From b67a4befac19e46f48e7955b5475dca89e8c9d52 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Fri, 16 Apr 2021 11:32:33 +0200 +Subject: [PATCH 1/1] modules: disable libvlc_json and ytbdl vlc.js#17 + +The libjson library is not linkable with emsdk v2.0.17, +this commit should be reverted when the ticket is resolved. +--- + modules/demux/Makefile.am | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/modules/demux/Makefile.am b/modules/demux/Makefile.am +index 48f5d7a97d..dbfe923650 100644 +--- a/modules/demux/Makefile.am ++++ b/modules/demux/Makefile.am +@@ -529,9 +529,11 @@ libytdl_plugin_la_SOURCES = demux/ytdl.c + libytdl_plugin_la_LIBADD = libvlc_json.la + if !HAVE_WIN32 + if !HAVE_ANDROID ++if !HAVE_EMSCRIPTEN + demux_LTLIBRARIES += libytdl_plugin.la + endif + endif ++endif + + libnoseek_plugin_la_SOURCES = demux/filter/noseek.c + demux_LTLIBRARIES += libnoseek_plugin.la +@@ -549,4 +551,6 @@ libvlc_json_la_SOURCES = \ + libvlc_json_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/demux/json + libvlc_json_la_LIBADD = $(LTLIBVLCCORE) ../compat/libcompat.la $(LIBM) + libvlc_json_la_LDFLAGS = -static ++if !HAVE_EMSCRIPTEN + noinst_LTLIBRARIES += libvlc_json.la ++endif +-- +2.32.0 + diff --git a/vlc_patches/0002-contrib-add-ffmpeg-configuration-options-for-wasm-em.patch b/vlc_patches/0002-contrib-add-ffmpeg-configuration-options-for-wasm-em.patch deleted file mode 100644 index cbcbf5ddfcd1fab13a8391de8a9b7d444447ad05..0000000000000000000000000000000000000000 --- a/vlc_patches/0002-contrib-add-ffmpeg-configuration-options-for-wasm-em.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 4a82c06361880c86123934b6dfb54263e0154051 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Wed, 4 Sep 2019 19:35:17 +0200 -Subject: [PATCH 01/15] contrib: add ffmpeg configuration options for - wasm-emscripten - -We need to specify the pthread flag for compilation and linking, otherwise tests will fail. ---- - ...001-configure-add-emscripten-support.patch | 33 +++++++++++++++++++ - contrib/src/ffmpeg/rules.mak | 6 ++++ - 2 files changed, 39 insertions(+) - create mode 100644 contrib/src/ffmpeg/0001-configure-add-emscripten-support.patch - -diff --git a/contrib/src/ffmpeg/0001-configure-add-emscripten-support.patch b/contrib/src/ffmpeg/0001-configure-add-emscripten-support.patch -new file mode 100644 -index 0000000000..cb8471c90e ---- /dev/null -+++ b/contrib/src/ffmpeg/0001-configure-add-emscripten-support.patch -@@ -0,0 +1,33 @@ -+From da7782c47f1f3d84eefb4ccce1c95e40d3b65fde Mon Sep 17 00:00:00 2001 -+From: Mehdi Sabwat <mehdisabwat@gmail.com> -+Date: Tue, 13 Aug 2019 21:14:56 +0200 -+Subject: [PATCH 1/1] configure: add emscripten support -+ -+--- -+ configure | 3 +++ -+ 1 file changed, 3 insertions(+) -+ -+diff --git a/configure b/configure -+index 7cea9d4d73..bafcbc87fc 100755 -+--- a/configure -++++ b/configure -+@@ -4239,6 +4239,7 @@ fi -+ exesuf() { -+ case $1 in -+ mingw32*|mingw64*|win32|win64|cygwin*|*-dos|freedos|opendos|os/2*|symbian) echo .exe ;; -++ emscripten) echo .js ;; -+ esac -+ } -+ -+@@ -5428,6 +5429,8 @@ case $target_os in -+ ;; -+ minix) -+ ;; -++ emscripten) -++ ;; -+ none) -+ ;; -+ *) -+-- -+2.23.0 -+ -diff --git a/contrib/src/ffmpeg/rules.mak b/contrib/src/ffmpeg/rules.mak -index 1ba04616e5..e2ec5f3cd3 100644 ---- a/contrib/src/ffmpeg/rules.mak -+++ b/contrib/src/ffmpeg/rules.mak -@@ -221,6 +221,11 @@ ifdef HAVE_NACL - FFMPEGCONF+=--disable-inline-asm --disable-asm --target-os=linux - endif - -+ifdef HAVE_EMSCRIPTEN -+FFMPEGCONF+=--target-os=emscripten --arch=wasm32 --ranlib=emranlib \ -+ --extra-ldflags="-pthread" --extra-ldexeflags="-pthread" -+endif -+ - # Build - PKGS += ffmpeg - ifeq ($(call need_pkg,"libavcodec >= $(FFMPEG_LAVC_MIN) libavformat >= 53.21.0 libswscale"),) -@@ -248,6 +253,7 @@ endif - ifdef USE_LIBAV - $(APPLY) $(SRC)/ffmpeg/libav_gsm.patch - endif -+ $(APPLY) $(SRC)/ffmpeg/0001-configure-add-emscripten-support.patch - $(MOVE) - - .ffmpeg: ffmpeg --- -2.23.0 - diff --git a/vlc_patches/0003-contrib-delete-empty-variable.patch b/vlc_patches/0003-contrib-delete-empty-variable.patch deleted file mode 100644 index 05c73b66a356f446dc4107db040ee480ed8352e8..0000000000000000000000000000000000000000 --- a/vlc_patches/0003-contrib-delete-empty-variable.patch +++ /dev/null @@ -1,26 +0,0 @@ -From ba9735f71e72cd3c7b57b1558a69c9f111316f65 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Tue, 31 Dec 2019 12:02:20 +0100 -Subject: [PATCH 1/1] contrib: delete empty variable - -As a fwp on c29409d1a742e65b6b2f3c95702196ff9ab1570c this commit fixes an issue -on platforms that are not listed. ---- - contrib/src/main.mak | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/contrib/src/main.mak b/contrib/src/main.mak -index 897020517e..a0469fb3e0 100644 ---- a/contrib/src/main.mak -+++ b/contrib/src/main.mak -@@ -646,7 +646,6 @@ ifdef HAVE_CROSS_COMPILE - echo "set(PKG_CONFIG_EXECUTABLE $(PKG_CONFIG))" >> $@ - endif - --MESON_SYSTEM_NAME = - ifdef HAVE_WIN32 - MESON_SYSTEM_NAME = windows - else --- -2.24.1 - diff --git a/vlc_patches/0006-configure-Create-a-target-for-emscripten-in-the-conf.patch b/vlc_patches/0006-configure-Create-a-target-for-emscripten-in-the-conf.patch deleted file mode 100644 index 3d09a3afc2f87d5470b18aceace95bcd55c80673..0000000000000000000000000000000000000000 --- a/vlc_patches/0006-configure-Create-a-target-for-emscripten-in-the-conf.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 3468bd741f19ff68d1017c374fdec6955bb5454e Mon Sep 17 00:00:00 2001 -From: Etienne Brateau <etienne.brateau@gmail.com> -Date: Thu, 6 Jul 2017 14:50:28 +0200 -Subject: [PATCH 06/15] configure: Create a target for emscripten in the - configure.ac - ---- - configure.ac | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/configure.ac b/configure.ac -index 210b4ca537..c9d04253cd 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -322,6 +322,19 @@ case "${host_os}" in - AC_LIBOBJ([recvmsg]) - AC_LIBOBJ([sendmsg]) - ;; -+ *emscripten*) -+ SYS=emscripten -+ CC=emcc -+ LD=emcc -+ LDSHARED=emcc -+ NM=llvm-nm -+ CPP=emcc -+ CXX=em++ -+ AR=emar -+ RANLIB=emranlib -+ CFLAGS="${CFLAGS} -D__NEED_ssize_t -pthread" -+ CXXFLAGS="${CXXFLAGS}" -+ ;; - *) - SYS="${host_os}" - ;; -@@ -388,6 +401,8 @@ AM_COND_IF([HAVE_X86ASM], [ - AC_SUBST([X86ASMFLAGS]) - AC_SUBST([X86ASMDEFS]) - -+AM_CONDITIONAL([HAVE_EMSCRIPTEN], [test "${SYS}" = "emscripten"]) -+ - dnl - dnl Sadly autoconf does not think about testing foo.exe when ask to test - dnl for program foo on win32 --- -2.23.0 - diff --git a/vlc_patches/0007-core-initial-core-build-for-emscripten-based-on-POSI.patch b/vlc_patches/0007-core-initial-core-build-for-emscripten-based-on-POSI.patch deleted file mode 100644 index 8496156418914a7c854bd158ccf68415452ab23f..0000000000000000000000000000000000000000 --- a/vlc_patches/0007-core-initial-core-build-for-emscripten-based-on-POSI.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 747c6207acf654665d23625537b962152922c8c5 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Mon, 24 Feb 2020 14:08:02 +0100 -Subject: [PATCH 1/1] core: initial core build for emscripten, based on POSIX - -posix/sort.c won't be added because qsort_r is not supported. ---- - src/Makefile.am | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/src/Makefile.am b/src/Makefile.am -index bf91159fcc..474ddcdd63 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -437,6 +437,17 @@ libvlccore_la_SOURCES += \ - posix/timer.c - endif - -+if HAVE_EMSCRIPTEN -+libvlccore_la_SOURCES += \ -+ posix/thread.c \ -+ posix/getaddrinfo.c \ -+ posix/error.c \ -+ posix/dirs.c \ -+ posix/filesystem.c \ -+ posix/specific.c \ -+ posix/timer.c -+endif -+ - if HAVE_DARWIN - libvlccore_la_SOURCES += \ - darwin/error.c \ -@@ -481,6 +492,7 @@ if !HAVE_LINUX - libvlccore_la_SOURCES += posix/wait.c - endif - if !HAVE_ANDROID -+if !HAVE_EMSCRIPTEN - libvlccore_la_SOURCES += posix/sort.c - if !HAVE_DARWIN - libvlccore_la_SOURCES += \ -@@ -503,6 +515,7 @@ endif - endif - endif - endif -+endif - - if ENABLE_SOUT - libvlccore_la_SOURCES += \ --- -2.25.0 - diff --git a/vlc_patches/0008-compat-add-sigwait-support-for-emscripten.patch b/vlc_patches/0008-compat-add-sigwait-support-for-emscripten.patch deleted file mode 100644 index 180433c4e5c1d1e61d314c85617419b82ff4f510..0000000000000000000000000000000000000000 --- a/vlc_patches/0008-compat-add-sigwait-support-for-emscripten.patch +++ /dev/null @@ -1,40 +0,0 @@ -From e06b3ac370e84480e7d3c6d9e8184c27fc2d0bf5 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Tue, 17 Sep 2019 18:59:43 +0200 -Subject: [PATCH 08/15] compat: add sigwait support for emscripten - ---- - compat/sigwait.c | 4 ++-- - configure.ac | 1 + - 2 files changed, 3 insertions(+), 2 deletions(-) - -diff --git a/compat/sigwait.c b/compat/sigwait.c -index e5a082d2d6..950579cc8b 100644 ---- a/compat/sigwait.c -+++ b/compat/sigwait.c -@@ -24,8 +24,8 @@ - # include <config.h> - #endif - --#ifdef __native_client__ --/* NaCl has no working sigwait, but SIGPIPE, for which vlc uses sigwait -+#if defined(__native_client__) || defined(__EMSCRIPTEN__) -+/* NaCl and Emscripten have no working sigwait, but SIGPIPE, for which vlc uses sigwait - * currently, is never generated in NaCl. So for SIGPIPE it's safe to instantly - * return, for all others run into an assertion. */ - -diff --git a/configure.ac b/configure.ac -index c9d04253cd..e5298e6f7a 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -324,6 +324,7 @@ case "${host_os}" in - ;; - *emscripten*) - SYS=emscripten -+ AC_LIBOBJ([sigwait]) - CC=emcc - LD=emcc - LDSHARED=emcc --- -2.23.0 - diff --git a/vlc_patches/0009-compat-add-clock_nanosleep-support.patch b/vlc_patches/0009-compat-add-clock_nanosleep-support.patch deleted file mode 100644 index f6327a921beedda67979ee4775eab506464a81a7..0000000000000000000000000000000000000000 --- a/vlc_patches/0009-compat-add-clock_nanosleep-support.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 39c77bd0970d509bd47df2d0c1e58b09281067e2 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Thu, 5 Sep 2019 23:54:30 +0200 -Subject: [PATCH 09/15] compat: add clock_nanosleep support - -clock_nanosleep() is not supported in emscripten - -Implementation from : https://code.woboq.org/userspace/glibc/sysdeps/unix/clock_nanosleep.c.html ---- - compat/clock_nanosleep.c | 91 ++++++++++++++++++++++++++++++++++++++++ - configure.ac | 1 + - 2 files changed, 92 insertions(+) - create mode 100644 compat/clock_nanosleep.c - -diff --git a/compat/clock_nanosleep.c b/compat/clock_nanosleep.c -new file mode 100644 -index 0000000000..d4cfee70e6 ---- /dev/null -+++ b/compat/clock_nanosleep.c -@@ -0,0 +1,91 @@ -+/***************************************************************************** -+ * clock_nanosleep.c: -+ High-resolution sleep with the specified clock for emscripten. -+ ***************************************************************************** -+ * Copyright © 2019 VLC authors, VideoLAN -+ * and Free Software Foundation, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU Lesser General Public License as published by -+ * the Free Software Foundation; either version 2.1 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -+ *****************************************************************************/ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <assert.h> -+#include <errno.h> -+#include <time.h> -+// #include <sysdep-cancel.h> -+ -+/* This implementation assumes that these is only a `nanosleep' system -+ call. So we have to remap all other activities. */ -+int -+//__clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, -+// struct timespec *rem) -+clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, -+ struct timespec *rem) -+{ -+ struct timespec now; -+ -+ if (__builtin_expect (req->tv_nsec, 0) < 0 -+ || __builtin_expect (req->tv_nsec, 0) >= 1000000000) -+ return EINVAL; -+ -+ if (clock_id == CLOCK_THREAD_CPUTIME_ID) -+ return EINVAL; /* POSIX specifies EINVAL for this case. */ -+ -+ if (clock_id < CLOCK_REALTIME || clock_id > CLOCK_THREAD_CPUTIME_ID) -+ return EINVAL; -+ -+ /* If we got an absolute time, remap it. */ -+ if (flags == TIMER_ABSTIME) -+ { -+ long int nsec; -+ long int sec; -+ -+ /* Make sure we use safe data types. */ -+ assert (sizeof (sec) >= sizeof (now.tv_sec)); -+ -+ /* Get the current time for this clock. */ -+ //if (__clock_gettime (clock_id, &now) != 0) -+ if (clock_gettime (clock_id, &now) != 0) -+ return errno; -+ -+ /* Compute the difference. */ -+ nsec = req->tv_nsec - now.tv_nsec; -+ sec = req->tv_sec - now.tv_sec - (nsec < 0); -+ if (sec < 0) -+ /* The time has already elapsed. */ -+ return 0; -+ -+ now.tv_sec = sec; -+ now.tv_nsec = nsec + (nsec < 0 ? 1000000000 : 0); -+ -+ /* From now on this is our time. */ -+ req = &now; -+ -+ /* Make sure we are not modifying the struct pointed to by REM. */ -+ rem = NULL; -+ } -+ else if (flags != 0) -+ return EINVAL; -+ -+ else if (clock_id != CLOCK_REALTIME) -+ /* Not supported. */ -+ return ENOTSUP; -+ // return __nanosleep (req, rem), 0 ? errno : 0; -+ return nanosleep (req, rem), 0 ? errno : 0; -+} -+//weak_alias (__clock_nanosleep, clock_nanosleep) -diff --git a/configure.ac b/configure.ac -index e5298e6f7a..5f24ab5945 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -325,6 +325,7 @@ case "${host_os}" in - *emscripten*) - SYS=emscripten - AC_LIBOBJ([sigwait]) -+ AC_LIBOBJ([clock_nanosleep]) - CC=emcc - LD=emcc - LDSHARED=emcc --- -2.23.0 - diff --git a/vlc_patches/0010-emscripten-add-vlc_getProxyUrl-stub.patch b/vlc_patches/0010-emscripten-add-vlc_getProxyUrl-stub.patch deleted file mode 100644 index 7cab9d4982caea46a7e3086b9cf03e3e57ff5512..0000000000000000000000000000000000000000 --- a/vlc_patches/0010-emscripten-add-vlc_getProxyUrl-stub.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 1f14176411e65c0d12fe167e62a8f7f10f233216 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Mon, 24 Feb 2020 14:15:56 +0100 -Subject: [PATCH 1/1] emscripten: add vlc_getProxyUrl stub. - ---- - src/Makefile.am | 3 ++- - src/emscripten/netconf.c | 39 +++++++++++++++++++++++++++++++++++++++ - 2 files changed, 41 insertions(+), 1 deletion(-) - create mode 100644 src/emscripten/netconf.c - -diff --git a/src/Makefile.am b/src/Makefile.am -index 474ddcdd63..64d28e12c4 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -445,7 +445,8 @@ libvlccore_la_SOURCES += \ - posix/dirs.c \ - posix/filesystem.c \ - posix/specific.c \ -- posix/timer.c -+ posix/timer.c \ -+ emscripten/netconf.c - endif - - if HAVE_DARWIN -diff --git a/src/emscripten/netconf.c b/src/emscripten/netconf.c -new file mode 100644 -index 0000000000..b972bf4976 ---- /dev/null -+++ b/src/emscripten/netconf.c -@@ -0,0 +1,39 @@ -+/***************************************************************************** -+ * netconf.c : Network configuration -+ ***************************************************************************** -+ * Copyright (C) 2019 -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU Lesser General Public License as published by -+ * the Free Software Foundation; either version 2.1 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -+ *****************************************************************************/ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <string.h> -+ -+char *vlc_getProxyUrl(const char *url); -+ -+/** -+ * Determines the network proxy server to use (if any). -+ * @param url absolute URL for which to get the proxy server -+ * @return proxy URL, NULL if no proxy or error -+ */ -+char *vlc_getProxyUrl(const char *url) -+{ -+ char *proxy = strdup(url); -+ -+ return proxy; -+} --- -2.25.0 - diff --git a/vlc_patches/0011-configure-disable-deprecated-GL-functions-for-emscri.patch b/vlc_patches/0011-configure-disable-deprecated-GL-functions-for-emscri.patch deleted file mode 100644 index c96f64eb142098f9cc8d6d642984c1d483eaf20f..0000000000000000000000000000000000000000 --- a/vlc_patches/0011-configure-disable-deprecated-GL-functions-for-emscri.patch +++ /dev/null @@ -1,27 +0,0 @@ -From a2a2372eb588474073873cd745164e22ef076328 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Mon, 9 Sep 2019 19:07:49 +0200 -Subject: [PATCH 11/15] configure: disable deprecated GL functions for - emscripten - -The build system assumes OpenGL functions are implemented if the headers are defined. -Which is wrong, so we need to disable the HAVE_GL marker. ---- - configure.ac | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/configure.ac b/configure.ac -index 5f24ab5945..66a69a91d7 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3231,6 +3231,7 @@ PKG_CHECK_MODULES([GL], [gl], [ - ]) - AC_MSG_RESULT([${have_gl}]) - ]) -+AS_IF([test "${SYS}" = "emscripten"], [have_gl="no"], [have_gl="yes"]) - AM_CONDITIONAL([HAVE_GL], [test "${have_gl}" = "yes"]) - AS_IF([test "${have_gl}" = "yes"], [ - AC_DEFINE([HAVE_GL], 1, [Defined if having OpenGL]) --- -2.23.0 - diff --git a/vlc_patches/0014-vout-add-emscripten-gl-es2-and-window-modules.patch b/vlc_patches/0014-vout-add-emscripten-gl-es2-and-window-modules.patch deleted file mode 100644 index fff95767123bcadc4273d196c64e767d0832acc6..0000000000000000000000000000000000000000 --- a/vlc_patches/0014-vout-add-emscripten-gl-es2-and-window-modules.patch +++ /dev/null @@ -1,222 +0,0 @@ -From 94cae7fd97cbdfe003d73aab433a031032556a50 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Thu, 12 Sep 2019 15:03:28 +0200 -Subject: [PATCH 14/15] vout: add emscripten gl es2 and window modules - -The module contains a window module that sets -the window type and a gl es2 submodule implementing -webgl function calls. - -Co-authored-by: Etienne Brateau <etienne@videolabs.io> ---- - modules/video_output/Makefile.am | 9 ++ - modules/video_output/emscripten.c | 177 ++++++++++++++++++++++++++++++ - 2 files changed, 186 insertions(+) - create mode 100644 modules/video_output/emscripten.c - -diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am -index a5b59f911a..f737781633 100644 ---- a/modules/video_output/Makefile.am -+++ b/modules/video_output/Makefile.am -@@ -469,6 +469,15 @@ libcaca_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' - EXTRA_LTLIBRARIES += libcaca_plugin.la - vout_LTLIBRARIES += $(LTLIBcaca) - -+### Emscripten ### -+libemscripten_window_plugin_la_SOURCES = video_output/emscripten.c -+libemscripten_window_plugin_la_CFLAGS = $(AM_CFLAGS) -+libemscripten_window_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' -+ -+if HAVE_EMSCRIPTEN -+vout_LTLIBRARIES += libemscripten_window_plugin.la -+endif -+ - ### Common ### - - libflaschen_plugin_la_SOURCES = video_output/flaschen.c -diff --git a/modules/video_output/emscripten.c b/modules/video_output/emscripten.c -new file mode 100644 -index 0000000000..1e582980e0 ---- /dev/null -+++ b/modules/video_output/emscripten.c -@@ -0,0 +1,177 @@ -+/** -+ * @file emscripten.c -+ * @brief Emscripten webgl video output for VLC media player -+ */ -+/***************************************************************************** -+ * Copyright © 2019 VLC authors and VideoLAN -+ * -+ * Authors: Etienne Brateau <etienne@videolabs.io> -+ * Mehdi Sabwat <mehdisabwat@gmail.com> -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU Lesser General Public License as published by -+ * the Free Software Foundation; either version 2.1 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -+ *****************************************************************************/ -+ -+#ifdef HAVE_CONFIG_H -+# include <config.h> -+#endif -+ -+#include <stdarg.h> -+ -+#include <vlc_common.h> -+#include <vlc_plugin.h> -+#include <vlc_vout_window.h> -+#include <vlc_vout_display.h> -+#include <vlc_opengl.h> -+ -+#include "./opengl/vout_helper.h" -+ -+#include <emscripten.h> -+#include <emscripten/html5.h> -+ -+static const struct vout_window_operations ops = { -+ //TODO: Implement canvas operations -+ //vout_window_ReportSize() should be called from here -+}; -+ -+typedef struct gl_sys_t -+{ -+ unsigned width; -+ unsigned height; -+ -+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context; -+} gl_sys_t; -+ -+static int OpenWindow(vout_window_t *wnd) -+{ -+ wnd->type = VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL; -+ wnd->ops = &ops; -+ -+ return VLC_SUCCESS; -+} -+ -+static void *GetProcAddress(vlc_gl_t *gl, const char *name) -+{ -+ // Not needed for OpenGL ES2 -+ VLC_UNUSED(gl); -+ VLC_UNUSED(name); -+ return NULL; -+} -+static int MakeCurrent(vlc_gl_t *gl) -+{ -+ gl_sys_t *sys = gl->sys; -+ -+ if (emscripten_webgl_make_context_current(sys->context) != EMSCRIPTEN_RESULT_SUCCESS) -+ return VLC_EGENERIC; -+ return VLC_SUCCESS; -+} -+ -+static void ReleaseCurrent(vlc_gl_t *gl) -+{ -+ VLC_UNUSED(gl); -+ emscripten_webgl_make_context_current(0); -+} -+ -+static void Swap(vlc_gl_t *gl) -+{ -+ VLC_UNUSED(gl); -+ emscripten_webgl_commit_frame(); -+} -+ -+static void Resize(vlc_gl_t *gl, unsigned w, unsigned h) -+{ -+ // to implement -+ VLC_UNUSED(gl); -+ VLC_UNUSED(w); -+ VLC_UNUSED(h); -+} -+ -+static void Close (vlc_gl_t *gl) -+{ -+ free(gl->sys); -+} -+ -+static int Open (vlc_gl_t *gl, unsigned width, unsigned height) -+{ -+ VLC_UNUSED(width), VLC_UNUSED(height); // to implement -+ -+ EmscriptenWebGLContextAttributes attr; -+ -+ emscripten_webgl_init_context_attributes(&attr); -+ attr.explicitSwapControl = 1; -+ -+ vout_window_t *wnd = gl->surface; -+ -+ if (wnd->type != VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL) -+ goto error; -+ -+ gl_sys_t *sys; -+ -+ gl->sys = sys = calloc(1, sizeof(*sys)); -+ if (!sys) -+ return VLC_EGENERIC; -+ -+ sys->context = emscripten_webgl_create_context("#canvas", &attr); -+ if (!sys->context) -+ { -+ msg_Err(gl, "Failed to make context current"); -+ goto error; -+ } -+ -+ // Check that the WebGL context is valid -+ if (emscripten_webgl_make_context_current(sys->context) != EMSCRIPTEN_RESULT_SUCCESS) -+ { -+ emscripten_log(EM_LOG_CONSOLE, "failed to make context current"); -+ goto error; -+ } -+ -+ // Release the context -+ emscripten_webgl_make_context_current(0); -+ wnd->handle.em_context = sys->context; -+ -+ // Implement egl routines: -+ gl->makeCurrent = MakeCurrent; -+ gl->releaseCurrent = ReleaseCurrent; -+ gl->resize = Resize; -+ gl->swap = Swap; -+ gl->getProcAddress = GetProcAddress; -+ gl->destroy = Close; -+ -+ return VLC_SUCCESS; -+error: -+ Close(gl); -+ return VLC_EGENERIC; -+} -+ -+/* -+ * Module descriptor -+ */ -+vlc_module_begin() -+ set_shortname(N_("Emscripten Window")) -+ set_description(N_("Emscripten drawing area")) -+ set_category(CAT_VIDEO) -+ set_subcategory(SUBCAT_VIDEO_VOUT) -+ set_capability("vout window", 10) -+ set_callbacks(OpenWindow, NULL) -+ -+ add_submodule () -+ set_shortname("Emscripten GL") -+ set_description(N_("Emscripten extension for OpenGL")) -+ set_category(CAT_VIDEO) -+ set_subcategory(SUBCAT_VIDEO_VOUT) -+ set_capability("opengl es2", 50) -+ set_callback(Open) -+ add_shortcut("emscripten-gl", "gles2") -+vlc_module_end() -+ --- -2.23.0 - diff --git a/vlc_patches/0015-vlc_common-add-weak-attribute-support-for-wasm.patch b/vlc_patches/0015-vlc_common-add-weak-attribute-support-for-wasm.patch deleted file mode 100644 index 319a2a565a100feb391f1adab0dfa5c7d25cc02d..0000000000000000000000000000000000000000 --- a/vlc_patches/0015-vlc_common-add-weak-attribute-support-for-wasm.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 7b4679fbdf714f8b6c3ea79a650d1bcdb1acd240 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Wed, 25 Sep 2019 20:20:59 +0200 -Subject: [PATCH 15/15] vlc_common: add weak attribute support for wasm - ---- - include/vlc_common.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/vlc_common.h b/include/vlc_common.h -index e4c5cd85c9..359c53dac8 100644 ---- a/include/vlc_common.h -+++ b/include/vlc_common.h -@@ -185,7 +185,7 @@ - # define VLC_USED - #endif - --#if defined (__ELF__) || defined (__MACH__) -+#if defined (__ELF__) || defined (__MACH__) || defined (__wasm__) - # define VLC_WEAK __attribute__((weak)) - #else - /** --- -2.23.0 - diff --git a/vlc_patches/0016-Add-meson_system_name-for-emscripten.patch b/vlc_patches/0016-Add-meson_system_name-for-emscripten.patch deleted file mode 100644 index 43cb8c1a353673761ff0e18a938613fca1d10e77..0000000000000000000000000000000000000000 --- a/vlc_patches/0016-Add-meson_system_name-for-emscripten.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 013429a1e49a2a11a9875400ca99ca8163eb219c Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Tue, 7 Jan 2020 11:57:22 +0100 -Subject: [PATCH 1/2] Add meson_system_name for emscripten - ---- - contrib/src/main.mak | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/contrib/src/main.mak b/contrib/src/main.mak -index a0469fb3e0..15be3d5638 100644 ---- a/contrib/src/main.mak -+++ b/contrib/src/main.mak -@@ -658,12 +658,16 @@ else - ifdef HAVE_LINUX - # android has also system = linux and defines HAVE_LINUX - MESON_SYSTEM_NAME = linux -+else -+ifdef HAVE_EMSCRIPTEN -+ MESON_SYSTEM_NAME = emscripten - else - $(error "No meson system name known for this target") - endif - endif - endif - endif -+endif - - crossfile.meson: $(SRC)/gen-meson-crossfile.py - $(HOSTVARS_MESON) \ --- -2.24.1 - diff --git a/vlc_patches/audio_output/0000-aout-add-emscripten-audio-worklet-module.patch b/vlc_patches/audio_output/0000-aout-add-emscripten-audio-worklet-module.patch new file mode 100644 index 0000000000000000000000000000000000000000..47292530b43c0a216c133e53a9c018192279f003 --- /dev/null +++ b/vlc_patches/audio_output/0000-aout-add-emscripten-audio-worklet-module.patch @@ -0,0 +1,438 @@ +From cb674e3724db5e204a60277e69c85765f8ad2141 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Fri, 30 Apr 2021 01:15:17 +0200 +Subject: [PATCH] aout: add emscripten audio worklet module + +--- + modules/audio_output/Makefile.am | 5 + + modules/audio_output/emscripten.cpp | 405 ++++++++++++++++++++++++++++ + 2 files changed, 410 insertions(+) + create mode 100644 modules/audio_output/emscripten.cpp + +diff --git a/modules/audio_output/Makefile.am b/modules/audio_output/Makefile.am +index 194c421e54..7c87faaea8 100644 +--- a/modules/audio_output/Makefile.am ++++ b/modules/audio_output/Makefile.am +@@ -117,3 +117,8 @@ endif + if HAVE_TVOS + aout_LTLIBRARIES += libaudiounit_ios_plugin.la + endif ++ ++libemworklet_audio_plugin_la_SOURCES = audio_output/emscripten.cpp ++if HAVE_EMSCRIPTEN ++aout_LTLIBRARIES += libemworklet_audio_plugin.la ++endif +diff --git a/modules/audio_output/emscripten.cpp b/modules/audio_output/emscripten.cpp +new file mode 100644 +index 0000000000..1c890b3f6d +--- /dev/null ++++ b/modules/audio_output/emscripten.cpp +@@ -0,0 +1,405 @@ ++/***************************************************************************** ++ * emscripten.c: audio output module using audio worklets ++ ***************************************************************************** ++ * Copyright © 2020 VLC authors and VideoLAN ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. ++ *****************************************************************************/ ++ ++#ifdef HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include <assert.h> ++#include <vlc_common.h> ++#include <vlc_plugin.h> ++#include <vlc_aout.h> ++ ++#include <emscripten.h> ++#include <emscripten/val.h> ++#include <emscripten/bind.h> ++#include <emscripten/html5.h> ++ ++#include <cstdint> ++#include <stdlib.h> ++ ++#define STORAGE_SIZE 1024 * 1024 ++// Sample rate might change, and it would be good to be able to change it during playback. ++#define AUDIO_WORKLET_SAMPLE_RATE 44100 ++// Don't know any way to get the browser's supported number of channels. ++#define AUDIO_WORKLET_NB_CHANNELS 2 ++ ++using namespace emscripten; ++namespace { ++ EM_BOOL requestAnimationFrame_cb( double time, void *userData ); ++ ++ class AWNodeWrapper { ++ public: ++ val context = val::undefined(); ++ val getCtx() const { return context; }; ++ void setCtx(val v_context) { context = v_context; }; ++ ++ uintptr_t sab_ptr; ++ uintptr_t getSabPtr() const { return sab_ptr; }; ++ void setSabPtr(uintptr_t p_sab) { sab_ptr = p_sab; }; ++ ++ size_t sab_size; ++ size_t getSabSize() const { return sab_size; }; ++ void setSabSize(size_t s_size) { sab_size = s_size; }; ++ ++ int8_t channels; ++ int8_t getChannels() const { return channels; }; ++ void setChannels(int8_t chan) { channels = chan; }; ++ ++ AWNodeWrapper(int sample_rate) { ++ // Prepare audio context options ++ val audio_ctx_options = val::object(); ++ audio_ctx_options.set("sampleRate", sample_rate); ++ ++ context = val::global("AudioContext").new_(audio_ctx_options); ++ context.call<void>("suspend"); ++ } ++ ++ val operator()( val undefined_promise_argument ) { ++ (val)undefined_promise_argument; ++ ++ // Prepare AWN Options ++ val awn_options = val::object(); ++ val awn_opt_outputChannelCount = val::array(); ++ awn_opt_outputChannelCount.call<val>("push", channels); ++ awn_options.set("outputChannelCount", awn_opt_outputChannelCount); ++ awn_options.set("numberOfInputs", 0); ++ awn_options.set("numberOfOutputs", 1); ++ ++ val AudioNode = val::global("AudioWorkletNode").new_(context, std::string("worklet-processor"), awn_options); ++ AudioNode.set("channelCount", channels); ++ ++ //Prepare postMessage message ++ val msg = val::object(); ++ msg.set("type", std::string("recv-audio-queue")); ++ msg.set("data", val::module_property("wasmMemory")["buffer"]); ++ msg.set("sab_ptr", sab_ptr); ++ msg.set("sab_size", sab_size); ++ ++ AudioNode["port"].call<val>("postMessage", msg); ++ AudioNode.call<val>("connect", context["destination"]); ++ ++ emscripten_request_animation_frame_loop(requestAnimationFrame_cb, this); ++ ++ return val::undefined(); ++ } ++ }; ++ ++ EMSCRIPTEN_BINDINGS(AWWSCOPE) { ++ class_<AWNodeWrapper>("awn_cb_wrapper") ++ .constructor<int>() ++ .property("context", &AWNodeWrapper::getCtx, &AWNodeWrapper::setCtx) ++ .property("sab_ptr", &AWNodeWrapper::getSabPtr, &AWNodeWrapper::setSabPtr) ++ .property("sab_size", &AWNodeWrapper::getSabSize, &AWNodeWrapper::setSabSize) ++ .property("channels", &AWNodeWrapper::getChannels, &AWNodeWrapper::setChannels) ++ .function("awn_call", &AWNodeWrapper::operator()); ++ }; ++ ++ typedef struct aout_sys_t ++ { ++ int8_t *sab; ++ size_t sab_size; ++ AWNodeWrapper *awn_inst; ++ float volume; ++ ++ } aout_sys_t; ++ ++ EM_BOOL requestAnimationFrame_cb( double time, void *userData ) { ++ (double) time; ++ AWNodeWrapper *inst = reinterpret_cast<AWNodeWrapper *>(userData); ++ uint32_t *sab = reinterpret_cast<uint32_t *>(inst->getSabPtr()); ++ val view = val(typed_memory_view(inst->getSabSize(), sab)); ++ val context = inst->getCtx(); ++ if ( view[0].as<int>() == 1 ) { ++ context.call<val>("resume"); ++ sab[0] = 0; ++ return EM_FALSE; ++ } ++ return EM_TRUE; ++ } ++ ++ // For Atomics.store() and .load() only integer types are supported ++ unsigned int js_index_load(int8_t *sab_ptr, int8_t index, size_t sab_size){ ++ uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); ++ val buffer = val(typed_memory_view(sab_size, buffer_view)); ++ ++ return val::global("Atomics").call<unsigned int>("load", buffer, index); ++ } ++ ++ void js_index_store(int8_t *sab_ptr, int8_t index, unsigned int value, size_t sab_size) { ++ uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); ++ val buffer = val(typed_memory_view(sab_size, buffer_view)); ++ ++ return val::global("Atomics").call<void>("store", buffer, index, value); ++ } ++ ++ // careful when calling this, you cannot wait on any index ++ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait ++ unsigned int js_index_wait(int8_t *sab_ptr, int8_t index, size_t sab_size) { ++ int32_t *buffer_view = reinterpret_cast<int32_t *>(sab_ptr); ++ val buffer = val(typed_memory_view(sab_size, buffer_view)); ++ ++ return val::global("Atomics").call<unsigned int>("wait", buffer, index); ++ } ++ ++ void Flush( audio_output_t *aout ) ++ { ++ aout_sys_t * sys = reinterpret_cast<aout_sys_t *>(aout->sys); ++ bzero(sys->sab, sys->sab_size); ++ } ++ ++ int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt ) ++ { ++ aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(aout->sys); ++ unsigned nbChannels = aout_FormatNbChannels(fmt); ++ ++ if (( nbChannels == 0 ) || !AOUT_FMT_LINEAR(fmt)) ++ return VLC_EGENERIC; ++ fmt->i_format = VLC_CODEC_FL32; ++ fmt->i_channels = AUDIO_WORKLET_NB_CHANNELS; ++ fmt->i_rate = AUDIO_WORKLET_SAMPLE_RATE; ++ ++ // resume audio context (first start, it is paused when initialized) ++ js_index_store(sys->sab, 4, (int)sys->volume * 100, sys->sab_size); ++ js_index_store(sys->sab, 0, 1, sys->sab_size); ++ ++ return VLC_SUCCESS; ++ } ++ ++ void Stop (audio_output_t *aout) ++ { ++ Flush(aout); ++ } ++ ++ int audio_worklet_push (audio_output_t *aout, const int8_t *data, unsigned data_size) { ++ aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(aout->sys); ++ int8_t *sab_view = sys->sab + 5 * sizeof(int32_t); ++ unsigned head = js_index_load(sys->sab, 1, sys->sab_size); ++ ++ // TODO: check that we do not write on unconsumed data. ++ if (head + data_size > STORAGE_SIZE) { ++ // Copy the part of the data at the buffer end ++ unsigned data_size_copy_end = STORAGE_SIZE - head; ++ memcpy(sab_view + head, data, data_size_copy_end); ++ head = 0; ++ ++ // Copy the part of the data at the buffer start ++ unsigned data_size_copy_start = data_size - data_size_copy_end; ++ memcpy(sab_view + head, data, data_size_copy_start); ++ head = data_size_copy_start; ++ } ++ else { ++ memcpy(sab_view + head, data, data_size); ++ head += data_size; ++ } ++ js_index_store(sys->sab, 1, head, sys->sab_size); ++ return 0; // return success to indicate successful push. ++ } ++ ++ void Play( audio_output_t *aout, block_t *block, vlc_tick_t date) ++ { ++ VLC_UNUSED(date); ++ aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(aout->sys); ++ const int8_t* data = (int8_t *)block->p_buffer; ++ size_t data_size = block->i_buffer; ++ ++ unsigned head = js_index_load(sys->sab, 1, sys->sab_size); ++ unsigned tail = js_index_load(sys->sab, 2, sys->sab_size); ++ unsigned new_head = (head + data_size) % STORAGE_SIZE; ++ if (new_head > tail) ++ { ++ // the worklet processor keeps rendering until tail matches head ++ // it will be notified by an Atomics.notify() from the process() callback ++ js_index_wait(sys->sab, 3, sys->sab_size); ++ } ++ audio_worklet_push(aout, data, data_size); ++ block_Release(block); ++ } ++ ++ void Pause( audio_output_t *aout, bool paused, vlc_tick_t date ) ++ { ++ aout_sys_t * sys = reinterpret_cast<aout_sys_t *>(aout->sys); ++ if (paused == false) { ++ js_index_store(sys->sab, 0, 0, sys->sab_size); ++ } ++ else { ++ js_index_store(sys->sab, 0, 1, sys->sab_size); ++ } ++ VLC_UNUSED(date); ++ Flush(aout); ++ } ++ ++ int Time_Get( audio_output_t *aout, vlc_tick_t *delay) ++ { ++ return aout_TimeGetDefault(aout, delay); ++ } ++ ++ void Close( vlc_object_t *obj ) ++ { ++ audio_output_t *aout = (audio_output_t *)obj; ++ struct aout_sys_t *sys = reinterpret_cast<struct aout_sys_t *>(aout->sys); ++ ++ delete sys->awn_inst; ++ free(sys->sab); ++ free(sys); ++ } ++ ++ int Volume_Set( audio_output_t *aout, float volume) ++ { ++ struct aout_sys_t *sys = reinterpret_cast<struct aout_sys_t *>(aout->sys); ++ ++ if (volume > 1.0f) ++ volume = 1.0f; ++ else if (volume < 0.0f) ++ volume = 0.0f; ++ // TODO: implement gain ++ sys->volume = volume; ++ js_index_store(sys->sab, 4, (int)volume * 100, sys->sab_size); ++ aout_VolumeReport(aout, volume); ++ ++ return 0; ++ } ++ ++ int Mute_Set( audio_output_t *aout, bool mute) ++ { ++ struct aout_sys_t *sys = reinterpret_cast<struct aout_sys_t *>(aout->sys); ++ ++ if (mute == 0) ++ js_index_store(sys->sab, 4, 0, sys->sab_size); ++ else ++ js_index_store(sys->sab, 4, (int)sys->volume * 100, sys->sab_size); ++ aout_MuteReport(aout, mute); ++ return 0; ++ } ++ ++ ++ int Open( vlc_object_t *obj ) ++ { ++ audio_output_t * aout = (audio_output_t *) obj; ++ ++ /* Allocate structures */ ++ aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(malloc( sizeof( *sys ) )); ++ if( unlikely(sys == NULL) ) ++ return VLC_ENOMEM; ++ ++ aout->sys = sys; ++ aout->start = Start; ++ aout->stop = Stop; ++ aout->play = Play; ++ aout->pause = Pause; ++ aout->flush = Flush; ++ aout->time_get = Time_Get; ++ aout->volume_set = Volume_Set; ++ aout->mute_set = Mute_Set; ++ ++ sys->awn_inst = new AWNodeWrapper(AUDIO_WORKLET_SAMPLE_RATE); ++ sys->sab_size = 5 * sizeof(int32_t) + STORAGE_SIZE; ++ sys->sab = reinterpret_cast<int8_t *>(malloc( sys->sab_size )); ++ sys->volume = 1.0f; ++ ++ if ( unlikely(sys->sab == NULL) ) ++ return VLC_ENOMEM; ++ bzero(sys->sab, sys->sab_size); ++ ++ val webaudio_context = sys->awn_inst->getCtx(); ++ ++ // Prepare audioWorkletProcessor blob ++ val document = val::global("document"); ++ val script = document.call<val>("createElement", std::string("SCRIPT")); ++ script.set("type", std::string("worklet")); ++ std::string processorStr = "class Processor extends AudioWorkletProcessor { \ ++ constructor() { \ ++ super(); \ ++ this.port.onmessage = e => { \ ++ if (e.data.type === 'recv-audio-queue') { \ ++ this.buf = e.data.data; \ ++ this.capacity = e.data.sab_size / 4; \ ++ this.flag = new Uint32Array(this.buf, e.data.sab_ptr, 1); \ ++ this.head = new Uint32Array(this.buf, e.data.sab_ptr + 4, 1); \ ++ this.tail = new Uint32Array(this.buf, e.data.sab_ptr + 8, 1); \ ++ this.can_write = new Int32Array(this.buf, e.data.sab_ptr + 12, 1); \ ++ this.volume = new Int32Array(this.buf, e.data.sab_ptr + 16, 1); \ ++ this.storage = new Float32Array(this.buf, e.data.sab_ptr + 20, this.capacity); \ ++ } else { \ ++ throw 'unexpected.'; \ ++ } \ ++ }; \ ++ } \ ++ process(inputs, outputs, parameters) { \ ++ const output = outputs[0]; \ ++ const nbChannels = output.length; \ ++ const nbSamples = output[0].length; \ ++ if (this.head.buffer.byteLength == 0) { \ ++ throw new Error('wasmMemory grew'); \ ++ } \ ++ var head = Atomics.load(this.head, 0) / 4; \ ++ var tail = Atomics.load(this.tail, 0) / 4; \ ++ var i = 0; \ ++ var volume = (Atomics.load(this.volume, 0) / 4) / 100; \ ++ while (tail != head && i < nbSamples) \ ++ { \ ++ for (let c = 0; c < nbChannels; ++c) { \ ++ output[c][i] = this.storage[tail] * volume; \ ++ tail++; \ ++ if (tail == this.capacity) { \ ++ tail = 0; \ ++ } \ ++ } \ ++ i++; \ ++ } \ ++ Atomics.store(this.tail, 0, tail * 4); \ ++ Atomics.notify(this.can_write, 0); \ ++ return true; \ ++ } \ ++} \ ++registerProcessor('worklet-processor', Processor);"; ++ script.set("innerText", processorStr); ++ val ProcessorTextArray = val::array(); ++ ProcessorTextArray.call<val>("push", script["innerText"]); ++ val BlobObject = val::object(); ++ BlobObject.set("type", std::string("application/javascript")); ++ val WorkletModuleUrl = val::global("URL").call<val>("createObjectURL", val::global("Blob").new_(ProcessorTextArray, BlobObject)); ++ ++ // Prepare audioWorkletProcessor callback ++ val cb_caller = val::module_property("awn_cb_wrapper").new_(AUDIO_WORKLET_SAMPLE_RATE); ++ cb_caller.set("context", val(webaudio_context)); ++ cb_caller.set("sab_ptr", val(reinterpret_cast<uintptr_t>(sys->sab))); ++ cb_caller.set("sab_size", val(sys->sab_size)); ++ cb_caller.set("channels", val(AUDIO_WORKLET_NB_CHANNELS)); ++ val awn_caller = cb_caller["awn_call"]; ++ val awn_cb = awn_caller.call<val>("bind", cb_caller); ++ ++ // start audio worklet (since the context is suspended, sound won't start now ++ // Since the WebAudio Context cannot be created in a worker, we create ++ // it in the main_thread and use the SAB to signal it when we want it to start ++ webaudio_context["audioWorklet"].call<val>("addModule", WorkletModuleUrl).call<val>("then", awn_cb); ++ ++ return VLC_SUCCESS; ++ } ++} ++ ++vlc_module_begin () ++ set_description( N_("Emscripten Worklet audio output") ) ++ set_shortname( "emworklet" ) ++ set_capability( "audio output", 100 ) ++ set_category( CAT_AUDIO ) ++ set_subcategory( SUBCAT_AUDIO_AOUT ) ++ set_callbacks( Open, Close ) ++vlc_module_end () +-- +2.32.0 + diff --git a/vlc_patches/audio_output/0001-Normalize-formatting-in-audio_output-emscripten.cpp.patch b/vlc_patches/audio_output/0001-Normalize-formatting-in-audio_output-emscripten.cpp.patch new file mode 100644 index 0000000000000000000000000000000000000000..06b5a820595a07e554b07413ec1c54827dc1c947 --- /dev/null +++ b/vlc_patches/audio_output/0001-Normalize-formatting-in-audio_output-emscripten.cpp.patch @@ -0,0 +1,261 @@ +From 03699f0b49461b93b588cbb01b42ff1ded93c5ed Mon Sep 17 00:00:00 2001 +From: Olivier FAURE <couteaubleu@gmail.com> +Date: Sun, 30 May 2021 12:01:49 +0200 +Subject: [PATCH 1/5] Normalize formatting in audio_output/emscripten.cpp + +--- + modules/audio_output/emscripten.cpp | 74 ++++++++++++++--------------- + 1 file changed, 37 insertions(+), 37 deletions(-) + +diff --git a/modules/audio_output/emscripten.cpp b/modules/audio_output/emscripten.cpp +index 1c890b3f6d..b704b90699 100644 +--- a/modules/audio_output/emscripten.cpp ++++ b/modules/audio_output/emscripten.cpp +@@ -42,7 +42,7 @@ + #define AUDIO_WORKLET_NB_CHANNELS 2 + + using namespace emscripten; +-namespace { ++namespace { + EM_BOOL requestAnimationFrame_cb( double time, void *userData ); + + class AWNodeWrapper { +@@ -50,31 +50,31 @@ namespace { + val context = val::undefined(); + val getCtx() const { return context; }; + void setCtx(val v_context) { context = v_context; }; +- ++ + uintptr_t sab_ptr; + uintptr_t getSabPtr() const { return sab_ptr; }; + void setSabPtr(uintptr_t p_sab) { sab_ptr = p_sab; }; +- ++ + size_t sab_size; + size_t getSabSize() const { return sab_size; }; + void setSabSize(size_t s_size) { sab_size = s_size; }; +- ++ + int8_t channels; + int8_t getChannels() const { return channels; }; + void setChannels(int8_t chan) { channels = chan; }; +- ++ + AWNodeWrapper(int sample_rate) { + // Prepare audio context options + val audio_ctx_options = val::object(); + audio_ctx_options.set("sampleRate", sample_rate); +- ++ + context = val::global("AudioContext").new_(audio_ctx_options); + context.call<void>("suspend"); + } +- ++ + val operator()( val undefined_promise_argument ) { + (val)undefined_promise_argument; +- ++ + // Prepare AWN Options + val awn_options = val::object(); + val awn_opt_outputChannelCount = val::array(); +@@ -82,26 +82,26 @@ namespace { + awn_options.set("outputChannelCount", awn_opt_outputChannelCount); + awn_options.set("numberOfInputs", 0); + awn_options.set("numberOfOutputs", 1); +- ++ + val AudioNode = val::global("AudioWorkletNode").new_(context, std::string("worklet-processor"), awn_options); + AudioNode.set("channelCount", channels); +- ++ + //Prepare postMessage message + val msg = val::object(); + msg.set("type", std::string("recv-audio-queue")); + msg.set("data", val::module_property("wasmMemory")["buffer"]); + msg.set("sab_ptr", sab_ptr); + msg.set("sab_size", sab_size); +- ++ + AudioNode["port"].call<val>("postMessage", msg); + AudioNode.call<val>("connect", context["destination"]); +- ++ + emscripten_request_animation_frame_loop(requestAnimationFrame_cb, this); +- ++ + return val::undefined(); + } + }; +- ++ + EMSCRIPTEN_BINDINGS(AWWSCOPE) { + class_<AWNodeWrapper>("awn_cb_wrapper") + .constructor<int>() +@@ -111,14 +111,14 @@ namespace { + .property("channels", &AWNodeWrapper::getChannels, &AWNodeWrapper::setChannels) + .function("awn_call", &AWNodeWrapper::operator()); + }; +- ++ + typedef struct aout_sys_t + { + int8_t *sab; + size_t sab_size; + AWNodeWrapper *awn_inst; + float volume; +- ++ + } aout_sys_t; + + EM_BOOL requestAnimationFrame_cb( double time, void *userData ) { +@@ -134,26 +134,26 @@ namespace { + } + return EM_TRUE; + } +- ++ + // For Atomics.store() and .load() only integer types are supported + unsigned int js_index_load(int8_t *sab_ptr, int8_t index, size_t sab_size){ +- uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); ++ uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); + val buffer = val(typed_memory_view(sab_size, buffer_view)); +- ++ + return val::global("Atomics").call<unsigned int>("load", buffer, index); + } +- ++ + void js_index_store(int8_t *sab_ptr, int8_t index, unsigned int value, size_t sab_size) { +- uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); ++ uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); + val buffer = val(typed_memory_view(sab_size, buffer_view)); +- ++ + return val::global("Atomics").call<void>("store", buffer, index, value); + } + + // careful when calling this, you cannot wait on any index + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait + unsigned int js_index_wait(int8_t *sab_ptr, int8_t index, size_t sab_size) { +- int32_t *buffer_view = reinterpret_cast<int32_t *>(sab_ptr); ++ int32_t *buffer_view = reinterpret_cast<int32_t *>(sab_ptr); + val buffer = val(typed_memory_view(sab_size, buffer_view)); + + return val::global("Atomics").call<unsigned int>("wait", buffer, index); +@@ -164,7 +164,7 @@ namespace { + aout_sys_t * sys = reinterpret_cast<aout_sys_t *>(aout->sys); + bzero(sys->sab, sys->sab_size); + } +- ++ + int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt ) + { + aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(aout->sys); +@@ -187,7 +187,7 @@ namespace { + { + Flush(aout); + } +- ++ + int audio_worklet_push (audio_output_t *aout, const int8_t *data, unsigned data_size) { + aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(aout->sys); + int8_t *sab_view = sys->sab + 5 * sizeof(int32_t); +@@ -199,7 +199,7 @@ namespace { + unsigned data_size_copy_end = STORAGE_SIZE - head; + memcpy(sab_view + head, data, data_size_copy_end); + head = 0; +- ++ + // Copy the part of the data at the buffer start + unsigned data_size_copy_start = data_size - data_size_copy_end; + memcpy(sab_view + head, data, data_size_copy_start); +@@ -219,7 +219,7 @@ namespace { + aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(aout->sys); + const int8_t* data = (int8_t *)block->p_buffer; + size_t data_size = block->i_buffer; +- ++ + unsigned head = js_index_load(sys->sab, 1, sys->sab_size); + unsigned tail = js_index_load(sys->sab, 2, sys->sab_size); + unsigned new_head = (head + data_size) % STORAGE_SIZE; +@@ -232,7 +232,7 @@ namespace { + audio_worklet_push(aout, data, data_size); + block_Release(block); + } +- ++ + void Pause( audio_output_t *aout, bool paused, vlc_tick_t date ) + { + aout_sys_t * sys = reinterpret_cast<aout_sys_t *>(aout->sys); +@@ -245,7 +245,7 @@ namespace { + VLC_UNUSED(date); + Flush(aout); + } +- ++ + int Time_Get( audio_output_t *aout, vlc_tick_t *delay) + { + return aout_TimeGetDefault(aout, delay); +@@ -289,16 +289,16 @@ namespace { + return 0; + } + +- ++ + int Open( vlc_object_t *obj ) + { + audio_output_t * aout = (audio_output_t *) obj; +- ++ + /* Allocate structures */ + aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(malloc( sizeof( *sys ) )); + if( unlikely(sys == NULL) ) + return VLC_ENOMEM; +- ++ + aout->sys = sys; + aout->start = Start; + aout->stop = Stop; +@@ -308,7 +308,7 @@ namespace { + aout->time_get = Time_Get; + aout->volume_set = Volume_Set; + aout->mute_set = Mute_Set; +- ++ + sys->awn_inst = new AWNodeWrapper(AUDIO_WORKLET_SAMPLE_RATE); + sys->sab_size = 5 * sizeof(int32_t) + STORAGE_SIZE; + sys->sab = reinterpret_cast<int8_t *>(malloc( sys->sab_size )); +@@ -317,9 +317,9 @@ namespace { + if ( unlikely(sys->sab == NULL) ) + return VLC_ENOMEM; + bzero(sys->sab, sys->sab_size); +- ++ + val webaudio_context = sys->awn_inst->getCtx(); +- ++ + // Prepare audioWorkletProcessor blob + val document = val::global("document"); + val script = document.call<val>("createElement", std::string("SCRIPT")); +@@ -376,7 +376,7 @@ registerProcessor('worklet-processor', Processor);"; + val BlobObject = val::object(); + BlobObject.set("type", std::string("application/javascript")); + val WorkletModuleUrl = val::global("URL").call<val>("createObjectURL", val::global("Blob").new_(ProcessorTextArray, BlobObject)); +- ++ + // Prepare audioWorkletProcessor callback + val cb_caller = val::module_property("awn_cb_wrapper").new_(AUDIO_WORKLET_SAMPLE_RATE); + cb_caller.set("context", val(webaudio_context)); +@@ -385,7 +385,7 @@ registerProcessor('worklet-processor', Processor);"; + cb_caller.set("channels", val(AUDIO_WORKLET_NB_CHANNELS)); + val awn_caller = cb_caller["awn_call"]; + val awn_cb = awn_caller.call<val>("bind", cb_caller); +- ++ + // start audio worklet (since the context is suspended, sound won't start now + // Since the WebAudio Context cannot be created in a worker, we create + // it in the main_thread and use the SAB to signal it when we want it to start +-- +2.32.0 + diff --git a/vlc_patches/audio_output/0002-Fix-emscripten-API-to-get-set-volume-levels-in-audio.patch b/vlc_patches/audio_output/0002-Fix-emscripten-API-to-get-set-volume-levels-in-audio.patch new file mode 100644 index 0000000000000000000000000000000000000000..84713d3ebb316ffb901a02254d1d6434d25276c1 --- /dev/null +++ b/vlc_patches/audio_output/0002-Fix-emscripten-API-to-get-set-volume-levels-in-audio.patch @@ -0,0 +1,54 @@ +From 7438b4206722654dc3704d68393268b797a190a1 Mon Sep 17 00:00:00 2001 +From: Olivier FAURE <couteaubleu@gmail.com> +Date: Sun, 30 May 2021 12:14:26 +0200 +Subject: [PATCH 2/5] Fix emscripten API to get/set volume levels in + audio_output module + +--- + modules/audio_output/emscripten.cpp | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/modules/audio_output/emscripten.cpp b/modules/audio_output/emscripten.cpp +index b704b90699..3fefa60065 100644 +--- a/modules/audio_output/emscripten.cpp ++++ b/modules/audio_output/emscripten.cpp +@@ -162,7 +162,7 @@ namespace { + void Flush( audio_output_t *aout ) + { + aout_sys_t * sys = reinterpret_cast<aout_sys_t *>(aout->sys); +- bzero(sys->sab, sys->sab_size); ++ bzero(sys->sab + (5 * sizeof(int32_t)), STORAGE_SIZE); + } + + int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt ) +@@ -177,7 +177,7 @@ namespace { + fmt->i_rate = AUDIO_WORKLET_SAMPLE_RATE; + + // resume audio context (first start, it is paused when initialized) +- js_index_store(sys->sab, 4, (int)sys->volume * 100, sys->sab_size); ++ js_index_store(sys->sab, 4, (int)(sys->volume * 100), sys->sab_size); + js_index_store(sys->sab, 0, 1, sys->sab_size); + + return VLC_SUCCESS; +@@ -229,6 +229,10 @@ namespace { + // it will be notified by an Atomics.notify() from the process() callback + js_index_wait(sys->sab, 3, sys->sab_size); + } ++ ++ // set volume ++ js_index_store(sys->sab, 4, (int)(sys->volume * 100), sys->sab_size); ++ + audio_worklet_push(aout, data, data_size); + block_Release(block); + } +@@ -271,7 +275,6 @@ namespace { + volume = 0.0f; + // TODO: implement gain + sys->volume = volume; +- js_index_store(sys->sab, 4, (int)volume * 100, sys->sab_size); + aout_VolumeReport(aout, volume); + + return 0; +-- +2.32.0 + diff --git a/vlc_patches/audio_output/0003-Move-some-audio-worklet-logic-out-of-JS-code.patch b/vlc_patches/audio_output/0003-Move-some-audio-worklet-logic-out-of-JS-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..8b8e8c14230ffa0f356871679afc8f9ec2115710 --- /dev/null +++ b/vlc_patches/audio_output/0003-Move-some-audio-worklet-logic-out-of-JS-code.patch @@ -0,0 +1,84 @@ +From 997717c4cd8f341704061561188cddbc55e52ef3 Mon Sep 17 00:00:00 2001 +From: Olivier FAURE <couteaubleu@gmail.com> +Date: Sun, 30 May 2021 14:18:32 +0200 +Subject: [PATCH 3/5] Move some audio worklet logic out of JS code. + +This isn't terribly useful on its own, but serves to prepare the next +commit. +--- + modules/audio_output/emscripten.cpp | 35 ++++++++++++++++++----------- + 1 file changed, 22 insertions(+), 13 deletions(-) + +diff --git a/modules/audio_output/emscripten.cpp b/modules/audio_output/emscripten.cpp +index 3fefa60065..625dda30c0 100644 +--- a/modules/audio_output/emscripten.cpp ++++ b/modules/audio_output/emscripten.cpp +@@ -86,12 +86,23 @@ namespace { + val AudioNode = val::global("AudioWorkletNode").new_(context, std::string("worklet-processor"), awn_options); + AudioNode.set("channelCount", channels); + ++ val Uint32Array = val::global("Uint32Array"); ++ val Int32Array = val::global("Int32Array"); ++ val Float32Array = val::global("Float32Array"); ++ ++ auto wasm_memory_buffer = val::module_property("wasmMemory")["buffer"]; ++ uint32_t storage_capacity = sab_size / 4; ++ + //Prepare postMessage message + val msg = val::object(); + msg.set("type", std::string("recv-audio-queue")); +- msg.set("data", val::module_property("wasmMemory")["buffer"]); +- msg.set("sab_ptr", sab_ptr); +- msg.set("sab_size", sab_size); ++ ++ msg.set("flag", Uint32Array.new_(wasm_memory_buffer, sab_ptr + 0, 1)); ++ msg.set("head", Uint32Array.new_(wasm_memory_buffer, sab_ptr + 4, 1)); ++ msg.set("tail", Uint32Array.new_(wasm_memory_buffer, sab_ptr + 8, 1)); ++ msg.set("can_write", Int32Array.new_(wasm_memory_buffer, sab_ptr + 12, 1)); ++ msg.set("volume", Int32Array.new_(wasm_memory_buffer, sab_ptr + 16, 1)); ++ msg.set("storage", Float32Array.new_(wasm_memory_buffer, sab_ptr + 20, storage_capacity)); + + AudioNode["port"].call<val>("postMessage", msg); + AudioNode.call<val>("connect", context["destination"]); +@@ -122,7 +133,7 @@ namespace { + } aout_sys_t; + + EM_BOOL requestAnimationFrame_cb( double time, void *userData ) { +- (double) time; ++ (void) time; + AWNodeWrapper *inst = reinterpret_cast<AWNodeWrapper *>(userData); + uint32_t *sab = reinterpret_cast<uint32_t *>(inst->getSabPtr()); + val view = val(typed_memory_view(inst->getSabSize(), sab)); +@@ -332,14 +343,12 @@ namespace { + super(); \ + this.port.onmessage = e => { \ + if (e.data.type === 'recv-audio-queue') { \ +- this.buf = e.data.data; \ +- this.capacity = e.data.sab_size / 4; \ +- this.flag = new Uint32Array(this.buf, e.data.sab_ptr, 1); \ +- this.head = new Uint32Array(this.buf, e.data.sab_ptr + 4, 1); \ +- this.tail = new Uint32Array(this.buf, e.data.sab_ptr + 8, 1); \ +- this.can_write = new Int32Array(this.buf, e.data.sab_ptr + 12, 1); \ +- this.volume = new Int32Array(this.buf, e.data.sab_ptr + 16, 1); \ +- this.storage = new Float32Array(this.buf, e.data.sab_ptr + 20, this.capacity); \ ++ this.flag = e.data.flag; \ ++ this.head = e.data.head; \ ++ this.tail = e.data.tail; \ ++ this.can_write = e.data.can_write; \ ++ this.volume = e.data.volume; \ ++ this.storage = e.data.storage; \ + } else { \ + throw 'unexpected.'; \ + } \ +@@ -361,7 +370,7 @@ namespace { + for (let c = 0; c < nbChannels; ++c) { \ + output[c][i] = this.storage[tail] * volume; \ + tail++; \ +- if (tail == this.capacity) { \ ++ if (tail == this.storage.length) { \ + tail = 0; \ + } \ + } \ +-- +2.32.0 + diff --git a/vlc_patches/audio_output/0004-Replace-untyped-js_index_load-store-functions-with-C.patch b/vlc_patches/audio_output/0004-Replace-untyped-js_index_load-store-functions-with-C.patch new file mode 100644 index 0000000000000000000000000000000000000000..cab4a240a4a846caa45f0c30845ca7618fb4feb2 --- /dev/null +++ b/vlc_patches/audio_output/0004-Replace-untyped-js_index_load-store-functions-with-C.patch @@ -0,0 +1,291 @@ +From 9526900f5d809cb24f6d21b7a79cd3496ae0e999 Mon Sep 17 00:00:00 2001 +From: Olivier FAURE <couteaubleu@gmail.com> +Date: Sun, 30 May 2021 15:15:22 +0200 +Subject: [PATCH 4/5] Replace untyped js_index_load/store functions with C++ + atomics + +--- + modules/audio_output/emscripten.cpp | 116 ++++++++++++++-------------- + 1 file changed, 59 insertions(+), 57 deletions(-) + +diff --git a/modules/audio_output/emscripten.cpp b/modules/audio_output/emscripten.cpp +index 625dda30c0..fa0f5bd3e4 100644 +--- a/modules/audio_output/emscripten.cpp ++++ b/modules/audio_output/emscripten.cpp +@@ -22,6 +22,8 @@ + # include "config.h" + #endif + ++#include <atomic> ++ + #include <assert.h> + #include <vlc_common.h> + #include <vlc_plugin.h> +@@ -45,6 +47,18 @@ using namespace emscripten; + namespace { + EM_BOOL requestAnimationFrame_cb( double time, void *userData ); + ++ typedef struct sound_buffer_t ++ { ++ // TODO - should be bool? ++ std::atomic<uint32_t> is_paused; ++ std::atomic<uint32_t> head; ++ std::atomic<uint32_t> tail; ++ std::atomic<uint32_t> can_write; ++ std::atomic<uint32_t> volume; ++ int8_t storage[STORAGE_SIZE]; ++ ++ } sound_buffer_t; ++ + class AWNodeWrapper { + public: + val context = val::undefined(); +@@ -55,10 +69,6 @@ namespace { + uintptr_t getSabPtr() const { return sab_ptr; }; + void setSabPtr(uintptr_t p_sab) { sab_ptr = p_sab; }; + +- size_t sab_size; +- size_t getSabSize() const { return sab_size; }; +- void setSabSize(size_t s_size) { sab_size = s_size; }; +- + int8_t channels; + int8_t getChannels() const { return channels; }; + void setChannels(int8_t chan) { channels = chan; }; +@@ -90,19 +100,26 @@ namespace { + val Int32Array = val::global("Int32Array"); + val Float32Array = val::global("Float32Array"); + +- auto wasm_memory_buffer = val::module_property("wasmMemory")["buffer"]; +- uint32_t storage_capacity = sab_size / 4; ++ auto wasm_mem = val::module_property("wasmMemory")["buffer"]; + + //Prepare postMessage message + val msg = val::object(); + msg.set("type", std::string("recv-audio-queue")); + +- msg.set("flag", Uint32Array.new_(wasm_memory_buffer, sab_ptr + 0, 1)); +- msg.set("head", Uint32Array.new_(wasm_memory_buffer, sab_ptr + 4, 1)); +- msg.set("tail", Uint32Array.new_(wasm_memory_buffer, sab_ptr + 8, 1)); +- msg.set("can_write", Int32Array.new_(wasm_memory_buffer, sab_ptr + 12, 1)); +- msg.set("volume", Int32Array.new_(wasm_memory_buffer, sab_ptr + 16, 1)); +- msg.set("storage", Float32Array.new_(wasm_memory_buffer, sab_ptr + 20, storage_capacity)); ++ msg.set("is_paused", ++ Uint32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, is_paused), 1)); ++ msg.set("head", ++ Uint32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, head), 1)); ++ msg.set("tail", ++ Uint32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, tail), 1)); ++ msg.set("can_write", ++ Int32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, can_write), 1)); ++ msg.set("volume", ++ Int32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, volume), 1)); ++ ++ uint32_t storage_capacity = STORAGE_SIZE / 4; ++ msg.set("storage", ++ Float32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, storage), storage_capacity)); + + AudioNode["port"].call<val>("postMessage", msg); + AudioNode.call<val>("connect", context["destination"]); +@@ -118,25 +135,25 @@ namespace { + .constructor<int>() + .property("context", &AWNodeWrapper::getCtx, &AWNodeWrapper::setCtx) + .property("sab_ptr", &AWNodeWrapper::getSabPtr, &AWNodeWrapper::setSabPtr) +- .property("sab_size", &AWNodeWrapper::getSabSize, &AWNodeWrapper::setSabSize) + .property("channels", &AWNodeWrapper::getChannels, &AWNodeWrapper::setChannels) + .function("awn_call", &AWNodeWrapper::operator()); + }; + + typedef struct aout_sys_t + { +- int8_t *sab; +- size_t sab_size; ++ sound_buffer_t *sab; // TODO - rename to sound_buff + AWNodeWrapper *awn_inst; + float volume; + + } aout_sys_t; + + EM_BOOL requestAnimationFrame_cb( double time, void *userData ) { +- (void) time; ++ VLC_UNUSED(time); ++ // FIXME - this function seems to mix two different views on the ++ // same memory, not sure why + AWNodeWrapper *inst = reinterpret_cast<AWNodeWrapper *>(userData); + uint32_t *sab = reinterpret_cast<uint32_t *>(inst->getSabPtr()); +- val view = val(typed_memory_view(inst->getSabSize(), sab)); ++ val view = val(typed_memory_view(sizeof(sound_buffer_t), sab)); + val context = inst->getCtx(); + if ( view[0].as<int>() == 1 ) { + context.call<val>("resume"); +@@ -146,34 +163,19 @@ namespace { + return EM_TRUE; + } + +- // For Atomics.store() and .load() only integer types are supported +- unsigned int js_index_load(int8_t *sab_ptr, int8_t index, size_t sab_size){ +- uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); +- val buffer = val(typed_memory_view(sab_size, buffer_view)); +- +- return val::global("Atomics").call<unsigned int>("load", buffer, index); +- } +- +- void js_index_store(int8_t *sab_ptr, int8_t index, unsigned int value, size_t sab_size) { +- uint32_t *buffer_view = reinterpret_cast<uint32_t *>(sab_ptr); +- val buffer = val(typed_memory_view(sab_size, buffer_view)); +- +- return val::global("Atomics").call<void>("store", buffer, index, value); +- } +- + // careful when calling this, you cannot wait on any index + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait +- unsigned int js_index_wait(int8_t *sab_ptr, int8_t index, size_t sab_size) { ++ uint32_t js_index_wait(sound_buffer_t *sab_ptr, int8_t index) { + int32_t *buffer_view = reinterpret_cast<int32_t *>(sab_ptr); +- val buffer = val(typed_memory_view(sab_size, buffer_view)); ++ val buffer = val(typed_memory_view(STORAGE_SIZE, buffer_view)); + +- return val::global("Atomics").call<unsigned int>("wait", buffer, index); ++ return val::global("Atomics").call<uint32_t>("wait", buffer, index); + } + + void Flush( audio_output_t *aout ) + { + aout_sys_t * sys = reinterpret_cast<aout_sys_t *>(aout->sys); +- bzero(sys->sab + (5 * sizeof(int32_t)), STORAGE_SIZE); ++ bzero(&sys->sab->storage, sizeof(sys->sab->storage)); + } + + int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt ) +@@ -188,8 +190,8 @@ namespace { + fmt->i_rate = AUDIO_WORKLET_SAMPLE_RATE; + + // resume audio context (first start, it is paused when initialized) +- js_index_store(sys->sab, 4, (int)(sys->volume * 100), sys->sab_size); +- js_index_store(sys->sab, 0, 1, sys->sab_size); ++ sys->sab->volume.store((int)(sys->volume * 100)); ++ sys->sab->is_paused.store(1); + + return VLC_SUCCESS; + } +@@ -199,10 +201,10 @@ namespace { + Flush(aout); + } + +- int audio_worklet_push (audio_output_t *aout, const int8_t *data, unsigned data_size) { ++ int audio_worklet_push (audio_output_t *aout, const int8_t *data, uint32_t data_size) { + aout_sys_t *sys = reinterpret_cast<aout_sys_t *>(aout->sys); +- int8_t *sab_view = sys->sab + 5 * sizeof(int32_t); +- unsigned head = js_index_load(sys->sab, 1, sys->sab_size); ++ int8_t *sab_view = sys->sab->storage; ++ uint32_t head = sys->sab->head.load(); + + // TODO: check that we do not write on unconsumed data. + if (head + data_size > STORAGE_SIZE) { +@@ -220,7 +222,7 @@ namespace { + memcpy(sab_view + head, data, data_size); + head += data_size; + } +- js_index_store(sys->sab, 1, head, sys->sab_size); ++ sys->sab->head.store(head); + return 0; // return success to indicate successful push. + } + +@@ -231,18 +233,18 @@ namespace { + const int8_t* data = (int8_t *)block->p_buffer; + size_t data_size = block->i_buffer; + +- unsigned head = js_index_load(sys->sab, 1, sys->sab_size); +- unsigned tail = js_index_load(sys->sab, 2, sys->sab_size); +- unsigned new_head = (head + data_size) % STORAGE_SIZE; ++ uint32_t head = sys->sab->head.load(); ++ uint32_t tail = sys->sab->tail.load(); ++ uint32_t new_head = (head + data_size) % STORAGE_SIZE; + if (new_head > tail) + { + // the worklet processor keeps rendering until tail matches head + // it will be notified by an Atomics.notify() from the process() callback +- js_index_wait(sys->sab, 3, sys->sab_size); ++ js_index_wait(sys->sab, 3); + } + + // set volume +- js_index_store(sys->sab, 4, (int)(sys->volume * 100), sys->sab_size); ++ sys->sab->volume.store((int)(sys->volume * 100)); + + audio_worklet_push(aout, data, data_size); + block_Release(block); +@@ -250,14 +252,14 @@ namespace { + + void Pause( audio_output_t *aout, bool paused, vlc_tick_t date ) + { ++ VLC_UNUSED(date); + aout_sys_t * sys = reinterpret_cast<aout_sys_t *>(aout->sys); + if (paused == false) { +- js_index_store(sys->sab, 0, 0, sys->sab_size); ++ sys->sab->is_paused.store(0); + } + else { +- js_index_store(sys->sab, 0, 1, sys->sab_size); ++ sys->sab->is_paused.store(1); + } +- VLC_UNUSED(date); + Flush(aout); + } + +@@ -271,6 +273,7 @@ namespace { + audio_output_t *aout = (audio_output_t *)obj; + struct aout_sys_t *sys = reinterpret_cast<struct aout_sys_t *>(aout->sys); + ++ // FIXME + delete sys->awn_inst; + free(sys->sab); + free(sys); +@@ -296,9 +299,10 @@ namespace { + struct aout_sys_t *sys = reinterpret_cast<struct aout_sys_t *>(aout->sys); + + if (mute == 0) +- js_index_store(sys->sab, 4, 0, sys->sab_size); ++ sys->sab->volume.store(0); + else +- js_index_store(sys->sab, 4, (int)sys->volume * 100, sys->sab_size); ++ sys->sab->volume.store((int)(sys->volume * 100)); ++ + aout_MuteReport(aout, mute); + return 0; + } +@@ -324,13 +328,12 @@ namespace { + aout->mute_set = Mute_Set; + + sys->awn_inst = new AWNodeWrapper(AUDIO_WORKLET_SAMPLE_RATE); +- sys->sab_size = 5 * sizeof(int32_t) + STORAGE_SIZE; +- sys->sab = reinterpret_cast<int8_t *>(malloc( sys->sab_size )); ++ sys->sab = (sound_buffer_t*)malloc(sizeof(sound_buffer_t)); + sys->volume = 1.0f; + + if ( unlikely(sys->sab == NULL) ) + return VLC_ENOMEM; +- bzero(sys->sab, sys->sab_size); ++ bzero(sys->sab, sizeof(sound_buffer_t)); + + val webaudio_context = sys->awn_inst->getCtx(); + +@@ -343,7 +346,7 @@ namespace { + super(); \ + this.port.onmessage = e => { \ + if (e.data.type === 'recv-audio-queue') { \ +- this.flag = e.data.flag; \ ++ this.is_paused = e.data.is_paused; \ + this.head = e.data.head; \ + this.tail = e.data.tail; \ + this.can_write = e.data.can_write; \ +@@ -393,7 +396,6 @@ registerProcessor('worklet-processor', Processor);"; + val cb_caller = val::module_property("awn_cb_wrapper").new_(AUDIO_WORKLET_SAMPLE_RATE); + cb_caller.set("context", val(webaudio_context)); + cb_caller.set("sab_ptr", val(reinterpret_cast<uintptr_t>(sys->sab))); +- cb_caller.set("sab_size", val(sys->sab_size)); + cb_caller.set("channels", val(AUDIO_WORKLET_NB_CHANNELS)); + val awn_caller = cb_caller["awn_call"]; + val awn_cb = awn_caller.call<val>("bind", cb_caller); +-- +2.32.0 + diff --git a/vlc_patches/audio_output/0005-Fix-volume-handling-in-emscripten-audio_output-modul.patch b/vlc_patches/audio_output/0005-Fix-volume-handling-in-emscripten-audio_output-modul.patch new file mode 100644 index 0000000000000000000000000000000000000000..79f1db48647d7a466f32cd3ad2639a8c64389ef8 --- /dev/null +++ b/vlc_patches/audio_output/0005-Fix-volume-handling-in-emscripten-audio_output-modul.patch @@ -0,0 +1,124 @@ +From 39c492904740f6bdcf794e0359930f01c49ee725 Mon Sep 17 00:00:00 2001 +From: Olivier FAURE <couteaubleu@gmail.com> +Date: Sun, 30 May 2021 17:18:23 +0200 +Subject: [PATCH 5/5] Fix volume handling in emscripten audio_output module + +Fix bug that had volume divided by 4 +Store mute state separately +--- + modules/audio_output/emscripten.cpp | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/modules/audio_output/emscripten.cpp b/modules/audio_output/emscripten.cpp +index fa0f5bd3e4..c39ca884b6 100644 +--- a/modules/audio_output/emscripten.cpp ++++ b/modules/audio_output/emscripten.cpp +@@ -55,6 +55,7 @@ namespace { + std::atomic<uint32_t> tail; + std::atomic<uint32_t> can_write; + std::atomic<uint32_t> volume; ++ std::atomic<uint32_t> is_muted; + int8_t storage[STORAGE_SIZE]; + + } sound_buffer_t; +@@ -116,6 +117,8 @@ namespace { + Int32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, can_write), 1)); + msg.set("volume", + Int32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, volume), 1)); ++ msg.set("is_muted", ++ Uint32Array.new_(wasm_mem, sab_ptr + offsetof(sound_buffer_t, is_muted), 1)); + + uint32_t storage_capacity = STORAGE_SIZE / 4; + msg.set("storage", +@@ -143,7 +146,6 @@ namespace { + { + sound_buffer_t *sab; // TODO - rename to sound_buff + AWNodeWrapper *awn_inst; +- float volume; + + } aout_sys_t; + +@@ -190,7 +192,6 @@ namespace { + fmt->i_rate = AUDIO_WORKLET_SAMPLE_RATE; + + // resume audio context (first start, it is paused when initialized) +- sys->sab->volume.store((int)(sys->volume * 100)); + sys->sab->is_paused.store(1); + + return VLC_SUCCESS; +@@ -240,12 +241,10 @@ namespace { + { + // the worklet processor keeps rendering until tail matches head + // it will be notified by an Atomics.notify() from the process() callback ++ // FIXME - This is layout-dependent, which isn't ideal + js_index_wait(sys->sab, 3); + } + +- // set volume +- sys->sab->volume.store((int)(sys->volume * 100)); +- + audio_worklet_push(aout, data, data_size); + block_Release(block); + } +@@ -288,7 +287,9 @@ namespace { + else if (volume < 0.0f) + volume = 0.0f; + // TODO: implement gain +- sys->volume = volume; ++ // Note: We store volume as an integer between 0..100 because ++ // for some reason Float32Array doesn't allow atomic operations ++ sys->sab->volume.store((int)(volume * 100)); + aout_VolumeReport(aout, volume); + + return 0; +@@ -298,12 +299,9 @@ namespace { + { + struct aout_sys_t *sys = reinterpret_cast<struct aout_sys_t *>(aout->sys); + +- if (mute == 0) +- sys->sab->volume.store(0); +- else +- sys->sab->volume.store((int)(sys->volume * 100)); +- ++ sys->sab->is_muted.store(mute); + aout_MuteReport(aout, mute); ++ + return 0; + } + +@@ -329,11 +327,11 @@ namespace { + + sys->awn_inst = new AWNodeWrapper(AUDIO_WORKLET_SAMPLE_RATE); + sys->sab = (sound_buffer_t*)malloc(sizeof(sound_buffer_t)); +- sys->volume = 1.0f; + + if ( unlikely(sys->sab == NULL) ) + return VLC_ENOMEM; + bzero(sys->sab, sizeof(sound_buffer_t)); ++ sys->sab->volume = 100; + + val webaudio_context = sys->awn_inst->getCtx(); + +@@ -351,6 +349,7 @@ namespace { + this.tail = e.data.tail; \ + this.can_write = e.data.can_write; \ + this.volume = e.data.volume; \ ++ this.is_muted = e.data.is_muted; \ + this.storage = e.data.storage; \ + } else { \ + throw 'unexpected.'; \ +@@ -367,7 +366,10 @@ namespace { + var head = Atomics.load(this.head, 0) / 4; \ + var tail = Atomics.load(this.tail, 0) / 4; \ + var i = 0; \ +- var volume = (Atomics.load(this.volume, 0) / 4) / 100; \ ++ var volume = Atomics.load(this.volume, 0) / 100; \ ++ if (Atomics.load(this.is_paused, 0) != 0 || Atomics.load(this.is_muted, 0) != 0) { \ ++ volume = 0; \ ++ } \ + while (tail != head && i < nbSamples) \ + { \ + for (let c = 0; c < nbChannels; ++c) { \ +-- +2.32.0 + diff --git a/vlc_patches/audio_output/0006-aout-fix-js_index_wait.patch b/vlc_patches/audio_output/0006-aout-fix-js_index_wait.patch new file mode 100644 index 0000000000000000000000000000000000000000..93a5ee04ec22016ab4f768ee1e66173b2d1b19c0 --- /dev/null +++ b/vlc_patches/audio_output/0006-aout-fix-js_index_wait.patch @@ -0,0 +1,51 @@ +From 825cfa2a712df088213bb806ba8868623020aa64 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Thu, 1 Jul 2021 11:28:53 +0200 +Subject: [PATCH 1/1] aout: fix js_index_wait + +- fix return type +- notifying without changing the value won't update the value +--- + modules/audio_output/emscripten.cpp | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/modules/audio_output/emscripten.cpp b/modules/audio_output/emscripten.cpp +index c39ca884b6..6acea387e3 100644 +--- a/modules/audio_output/emscripten.cpp ++++ b/modules/audio_output/emscripten.cpp +@@ -167,11 +167,11 @@ namespace { + + // careful when calling this, you cannot wait on any index + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait +- uint32_t js_index_wait(sound_buffer_t *sab_ptr, int8_t index) { ++ void js_index_wait(sound_buffer_t *sab_ptr, int8_t index) { + int32_t *buffer_view = reinterpret_cast<int32_t *>(sab_ptr); + val buffer = val(typed_memory_view(STORAGE_SIZE, buffer_view)); + +- return val::global("Atomics").call<uint32_t>("wait", buffer, index); ++ val::global("Atomics").call<val>("wait", buffer, index, 0); + } + + void Flush( audio_output_t *aout ) +@@ -241,7 +241,7 @@ namespace { + { + // the worklet processor keeps rendering until tail matches head + // it will be notified by an Atomics.notify() from the process() callback +- // FIXME - This is layout-dependent, which isn't ideal ++ // FIXME - This is layout-dependent, which isn't ideal + js_index_wait(sys->sab, 3); + } + +@@ -382,7 +382,8 @@ namespace { + i++; \ + } \ + Atomics.store(this.tail, 0, tail * 4); \ +- Atomics.notify(this.can_write, 0); \ ++ Atomics.store(this.can_write, 0, 1); \ ++ Atomics.notify(this.can_write, 0); \ + return true; \ + } \ + } \ +-- +2.32.0 + diff --git a/vlc_patches/dav1d/0001-contrib-bump-dav1d-to-0.5.0.patch b/vlc_patches/dav1d/0001-contrib-bump-dav1d-to-0.5.0.patch deleted file mode 100644 index d81906bf7bd0d92cb46b07cff697da4b92e227af..0000000000000000000000000000000000000000 --- a/vlc_patches/dav1d/0001-contrib-bump-dav1d-to-0.5.0.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9bed6fe6444a86a6660d275e237bb9126942c471 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Thu, 24 Oct 2019 18:05:16 +0200 -Subject: [PATCH 1/2] contrib: bump dav1d to 0.5.0 - ---- - contrib/src/dav1d/SHA512SUMS | 2 +- - contrib/src/dav1d/rules.mak | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/contrib/src/dav1d/SHA512SUMS b/contrib/src/dav1d/SHA512SUMS -index b3b14ff506..90996861fc 100644 ---- a/contrib/src/dav1d/SHA512SUMS -+++ b/contrib/src/dav1d/SHA512SUMS -@@ -1 +1 @@ --8ed44b3d747f01b87b34f86fada824dfb7f86c16168af641fe754c767af5714e9fe212b6eea2bc11b5b041460184c78f755e10d4947e46bc70d95e1bd750f79d dav1d-0.4.0.tar.xz -+10d3b174fa7ade0fb56f354dec8218761291c69d1ce1825d04bb6c7f6b28581f8811fd6e65c0f2a7a609b9694c11138ef469a2447814e020c038dba8d04de4df dav1d-0.5.0.tar.xz -diff --git a/contrib/src/dav1d/rules.mak b/contrib/src/dav1d/rules.mak -index 74a44dbb60..dbae572a02 100644 ---- a/contrib/src/dav1d/rules.mak -+++ b/contrib/src/dav1d/rules.mak -@@ -1,6 +1,6 @@ - # libdav1d - --DAV1D_VERSION := 0.4.0 -+DAV1D_VERSION := 0.5.0 - DAV1D_URL := $(VIDEOLAN)/dav1d/$(DAV1D_VERSION)/dav1d-$(DAV1D_VERSION).tar.xz - #~ DAV1D_HASH := de2059a1167ed560269c3253768929ef19cae989 - #~ DAV1D_VERSION := git-$(DAV1D_HASH) --- -2.23.0 - diff --git a/vlc_patches/dav1d/0002-contrib-add-dav1d-emscripten-support.patch b/vlc_patches/dav1d/0002-contrib-add-dav1d-emscripten-support.patch deleted file mode 100644 index 29ad1f34a16b14b211a02e91dad0109c97d00a8f..0000000000000000000000000000000000000000 --- a/vlc_patches/dav1d/0002-contrib-add-dav1d-emscripten-support.patch +++ /dev/null @@ -1,58 +0,0 @@ -From f027bb628d1542be954b9aa580dad6e14810f03d Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Thu, 24 Oct 2019 18:06:52 +0200 -Subject: [PATCH 2/2] contrib: add dav1d emscripten support - ---- - .../dav1d/0001-add-emscripten-support.patch | 26 +++++++++++++++++++ - contrib/src/dav1d/rules.mak | 1 + - 2 files changed, 27 insertions(+) - create mode 100644 contrib/src/dav1d/0001-add-emscripten-support.patch - -diff --git a/contrib/src/dav1d/0001-add-emscripten-support.patch b/contrib/src/dav1d/0001-add-emscripten-support.patch -new file mode 100644 -index 0000000000..9e63e5219a ---- /dev/null -+++ b/contrib/src/dav1d/0001-add-emscripten-support.patch -@@ -0,0 +1,26 @@ -+From fd9f38380eaf20b812091fbf6c2cea477c38d8e6 Mon Sep 17 00:00:00 2001 -+From: Mehdi Sabwat <mehdisabwat@gmail.com> -+Date: Thu, 24 Oct 2019 14:05:31 +0200 -+Subject: [PATCH 1/1] add emscripten support -+ -+--- -+ meson.build | 3 +++ -+ 1 file changed, 3 insertions(+) -+ -+diff --git a/meson.build b/meson.build -+index 90899a7..cc95315 100644 -+--- a/meson.build -++++ b/meson.build -+@@ -112,6 +112,9 @@ if host_machine.system() == 'windows' -+ # On Windows, we use a compatibility layer to emulate pthread -+ thread_dependency = [] -+ thread_compat_dep = declare_dependency(sources : files('src/win32/thread.c')) -++elif host_machine.system() == 'emscripten' -++ thread_dependency = [] -++ thread_compat_dep = [] -+ else -+ thread_dependency = dependency('threads') -+ thread_compat_dep = [] -+-- -+2.23.0 -+ -diff --git a/contrib/src/dav1d/rules.mak b/contrib/src/dav1d/rules.mak -index dbae572a02..e3cf065b0b 100644 ---- a/contrib/src/dav1d/rules.mak -+++ b/contrib/src/dav1d/rules.mak -@@ -24,6 +24,7 @@ $(TARBALLS)/dav1d-$(DAV1D_VERSION).tar.xz: - - dav1d: dav1d-$(DAV1D_VERSION).tar.xz .sum-dav1d - $(UNPACK) -+ $(APPLY) $(SRC)/dav1d/0001-add-emscripten-support.patch - $(MOVE) - - .dav1d: dav1d crossfile.meson --- -2.23.0 - diff --git a/vlc_patches/filesystem/0001-access-initial-emscripten-file-api-support.patch b/vlc_patches/filesystem/0001-access-initial-emscripten-file-api-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..231c512226e0cbb707789d8f520a9cb9a535e5b0 --- /dev/null +++ b/vlc_patches/filesystem/0001-access-initial-emscripten-file-api-support.patch @@ -0,0 +1,205 @@ +From ffa3b9e16691a72b744715564f63b34ea57ab414 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Wed, 18 Nov 2020 17:50:39 +0100 +Subject: [PATCH 1/1] access: initial emscripten file api support + +--- + modules/access/Makefile.am | 8 ++ + modules/access/emscripten.cpp | 169 ++++++++++++++++++++++++++++++++++ + 2 files changed, 177 insertions(+) + create mode 100644 modules/access/emscripten.cpp + +diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am +index 9cd3098fc2..331de24f82 100644 +--- a/modules/access/Makefile.am ++++ b/modules/access/Makefile.am +@@ -454,3 +454,11 @@ librist_plugin_la_LIBADD = $(SOCKET_LIBS) + if HAVE_BITSTREAM + access_LTLIBRARIES += librist_plugin.la + endif ++ ++### EMSCRIPTEN ### ++ ++libemscriptenfs_plugin_la_SOURCES = access/emscripten.cpp ++libemscriptenfs_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) ++if HAVE_EMSCRIPTEN ++access_LTLIBRARIES += libemscriptenfs_plugin.la ++endif +diff --git a/modules/access/emscripten.cpp b/modules/access/emscripten.cpp +new file mode 100644 +index 0000000000..f3162574f9 +--- /dev/null ++++ b/modules/access/emscripten.cpp +@@ -0,0 +1,169 @@ ++/***************************************************************************** ++ * emscripten.cpp: emscripten file system access plugin ++ ***************************************************************************** ++ * Copyright (C) 2001-2020 VLC authors and VideoLAN ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. ++ *****************************************************************************/ ++ ++#ifdef HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include <vlc_common.h> ++#include <vlc_plugin.h> ++#include<vlc_stream.h> ++#include <emscripten.h> ++ ++static ssize_t Read (stream_t *, void *, size_t); ++static int FileSeek (stream_t *, uint64_t); ++static int FileControl (stream_t *, int, va_list); ++ ++typedef struct ++{ ++ int fd; ++ int offset; ++ ++ bool b_pace_control; ++} access_sys_t; ++ ++/***************************************************************************** ++ * FileOpen: open the file ++ *****************************************************************************/ ++int FileOpen( vlc_object_t *p_this ) ++{ ++ stream_t *p_access = reinterpret_cast<stream_t *>(p_this); ++ ++ /* Open file */ ++ int fd = 42; // not implemented for now ++ access_sys_t *p_sys = reinterpret_cast<access_sys_t *>(vlc_obj_malloc(p_this, sizeof (*p_sys))); ++ if (unlikely(p_sys == NULL)) ++ goto error; ++ p_access->pf_read = Read; ++ p_access->pf_block = NULL; ++ p_access->pf_control = FileControl; ++ p_access->p_sys = p_sys; ++ p_sys->fd = fd; ++ p_sys->offset = 0; ++ p_access->pf_seek = FileSeek; ++ p_sys->b_pace_control = strcasecmp (p_access->psz_name, "stream"); ++ ++ return VLC_SUCCESS; ++error: ++ p_sys->offset=0; ++ return VLC_EGENERIC; ++} ++ ++/***************************************************************************** ++ * FileClose: reset the offset to 0 ++ *****************************************************************************/ ++void FileClose (vlc_object_t * p_this) ++{ ++ stream_t *p_access = reinterpret_cast<stream_t *>(p_this); ++ ++ access_sys_t *sys = reinterpret_cast<access_sys_t *>(p_access->p_sys); ++ sys->offset = 0; ++} ++ ++static ssize_t Read (stream_t *p_access, void *p_buffer, size_t i_len) ++{ ++ access_sys_t *sys = reinterpret_cast<access_sys_t *>(p_access->p_sys); ++ ++ EM_ASM ({ ++ let p_buffer = $0; ++ let start = $1; ++ let end = $2; ++ ++ let reader = new FileReaderSync(); ++ // TODO: get MimeType from the file handler ++ let data = reader.readAsArrayBuffer( new Blob([Module.fileHandle.slice(start, start+end)], {type: 'video/mp4'}) ); ++ let dataView = new Uint8Array( data ); ++ let wasmMemoryView = new Uint8Array( Module.wasmMemory.buffer, p_buffer, end); // ajouter + i_len ++ let wasmMemoryItems = wasmMemoryView.entries(); ++ ++ for ( let item of dataView.entries() ) { ++ let index = wasmMemoryItems.next().value[0]; ++ wasmMemoryView[index] = item[1];// an item is: [index, value] ++ } ++ }, p_buffer, sys->offset, i_len ); ++ sys->offset += i_len; ++ return i_len; ++} ++ ++/***************************************************************************** ++ * Seek: seek to a specific location in a file ++ *****************************************************************************/ ++static int FileSeek (stream_t *p_access, uint64_t i_pos) ++{ ++ access_sys_t *sys = reinterpret_cast<access_sys_t *>(p_access->p_sys); ++ ++ // SEEK_SET: i_pos is an absolute position ++ sys->offset = i_pos; ++ ++ return VLC_SUCCESS; ++} ++ ++/***************************************************************************** ++ * Control: ++ *****************************************************************************/ ++static int FileControl( stream_t *p_access, int i_query, va_list args ) ++{ ++ access_sys_t *sys = reinterpret_cast<access_sys_t *>(p_access->p_sys); ++ bool *pb_bool; ++ vlc_tick_t *pi_64; ++ ++ switch( i_query ) ++ { ++ case STREAM_CAN_SEEK: ++ case STREAM_CAN_FASTSEEK: ++ pb_bool = va_arg( args, bool * ); ++ *pb_bool = false; ++ break; ++ case STREAM_CAN_PAUSE: ++ case STREAM_CAN_CONTROL_PACE: ++ pb_bool = va_arg( args, bool * ); ++ *pb_bool = sys->b_pace_control; ++ break; ++ case STREAM_GET_SIZE: ++ { ++ size_t size = EM_ASM_INT({ return Module.fileHandle.size}); ++ //printf("taille: %zu\n", size); ++ // abort(); ++ *va_arg( args, uint64_t * ) = size; ++ break; ++ } ++ case STREAM_GET_PTS_DELAY: ++ pi_64 = va_arg( args, vlc_tick_t * ); ++ // network caching for later ++ *pi_64 = VLC_TICK_FROM_MS( ++ var_InheritInteger (p_access, "file-caching") ); ++ break; ++ default: ++ return VLC_EGENERIC; ++ ++ } ++ return VLC_SUCCESS; ++} ++ ++vlc_module_begin () ++ set_description( N_("File input") ) ++ set_shortname( N_("emscriptenfs") ) ++ set_category( CAT_INPUT ) ++ set_subcategory( SUBCAT_INPUT_ACCESS ) ++ set_capability( "access", 50 ) ++ add_shortcut( "emscriptenfs" ) ++ set_callbacks( FileOpen, FileClose ) ++vlc_module_end () +-- +2.32.0 + diff --git a/vlc_patches/0012-logger-add-emscripten-module.patch b/vlc_patches/logger/0001-logger-add-emscripten-module.patch similarity index 53% rename from vlc_patches/0012-logger-add-emscripten-module.patch rename to vlc_patches/logger/0001-logger-add-emscripten-module.patch index 43e5e0b7e6af6eaa74079668fd72954aca65c991..02f0b1f2aca6864b8333083848e95480168c1b37 100644 --- a/vlc_patches/0012-logger-add-emscripten-module.patch +++ b/vlc_patches/logger/0001-logger-add-emscripten-module.patch @@ -1,37 +1,36 @@ -From bde1b91e748fa7b2a97041605628ab7c96bd6a61 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Mon, 9 Sep 2019 19:18:36 +0200 -Subject: [PATCH 12/15] logger: add emscripten module +From 58c9af72a3cc04f39700369fbeb5579c0c384221 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Mon, 9 Nov 2020 22:35:32 +0100 +Subject: [PATCH] logger: add emscripten module --- - modules/logger/Makefile.am | 7 ++++ - modules/logger/emscripten.c | 82 +++++++++++++++++++++++++++++++++++++ - 2 files changed, 89 insertions(+) + modules/logger/Makefile.am | 6 +++ + modules/logger/emscripten.c | 92 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 98 insertions(+) create mode 100644 modules/logger/emscripten.c diff --git a/modules/logger/Makefile.am b/modules/logger/Makefile.am -index 4addf6dcfd..9b26a68afd 100644 +index 8ab485c8fe..1d10a6e3a4 100644 --- a/modules/logger/Makefile.am +++ b/modules/logger/Makefile.am -@@ -22,3 +22,10 @@ libandroid_logger_plugin_la_LIBADD = -llog - if HAVE_ANDROID - logger_LTLIBRARIES += libandroid_logger_plugin.la - endif +@@ -25,3 +25,9 @@ endif + + libjson_tracer_plugin_la_SOURCES = logger/json.c + logger_LTLIBRARIES += libjson_tracer_plugin.la + +libemscripten_logger_plugin_la_SOURCES = logger/emscripten.c -+libemscripten_logger_plugin_la_CFLAGS = $(AM_CFLAGS) + +if HAVE_EMSCRIPTEN +logger_LTLIBRARIES += libemscripten_logger_plugin.la +endif diff --git a/modules/logger/emscripten.c b/modules/logger/emscripten.c new file mode 100644 -index 0000000000..bb7ef220de +index 0000000000..85fdedb0d6 --- /dev/null +++ b/modules/logger/emscripten.c -@@ -0,0 +1,82 @@ +@@ -0,0 +1,92 @@ +/***************************************************************************** -+ * emscripten.c: Android logger using logcat ++ * emscripten.c: Emscripten logger + ***************************************************************************** + * Copyright © 2019 VLC authors and VideoLAN + * @@ -63,55 +62,65 @@ index 0000000000..bb7ef220de +#include <vlc_plugin.h> + +static void EmscriptenPrintMsg(void *opaque, int type, const vlc_log_t *p_item, -+ const char *format, va_list ap) ++ const char *format, va_list ap) +{ -+ int prio; -+ char *format2; -+ int verbose = (intptr_t)opaque; ++ int prio; ++ char *new_format; ++ char *message; ++ int verbose = (intptr_t)opaque; + -+ if (verbose < type) -+ return; ++ if (verbose < type) ++ return; ++ if (asprintf(&new_format, "[vlc.js: 0x%"PRIxPTR"/0x%"PRIxPTR"] %s %s: %s", ++ p_item->i_object_id, p_item->tid, p_item->psz_module, ++ p_item->psz_object_type, format) < 0) ++ return; ++ ++ switch (type) { ++ case VLC_MSG_ERR: ++ prio = EM_LOG_ERROR; ++ break; ++ case VLC_MSG_WARN: ++ prio = EM_LOG_WARN; ++ break; ++ default: ++ case VLC_MSG_DBG: ++ prio = EM_LOG_CONSOLE; ++ } + -+ if (asprintf(&format2, "[LIBVLC DEBUG] %s %s: %s", p_item->psz_module, p_item->psz_object_type, format) < 0) -+ return; -+ switch (type) { -+ case VLC_MSG_ERR: -+ prio = EM_LOG_ERROR; -+ break; -+ case VLC_MSG_WARN: -+ prio = EM_LOG_WARN; -+ break; -+ default: -+ case VLC_MSG_DBG: -+ prio = EM_LOG_CONSOLE; -+ } -+ emscripten_log(prio, format2, ap); -+ free(format2); ++ if (vasprintf(&message, new_format, ap) < 0) ++ { ++ free(new_format); ++ return ; ++ } ++ free(new_format); ++ emscripten_log(prio, "%s", message); ++ free(message); +} + +static const struct vlc_logger_operations ops = { EmscriptenPrintMsg, NULL }; + +static const struct vlc_logger_operations *Open(vlc_object_t *obj, void **sysp) +{ -+ int verbosity = var_InheritInteger(obj, "verbose"); ++ int verbosity = var_InheritInteger(obj, "verbose"); + -+ if (verbosity < 0) -+ return NULL; ++ if (verbosity < 0) ++ return NULL; + -+ verbosity += VLC_MSG_ERR; -+ *sysp = (void *)(uintptr_t)verbosity; ++ verbosity += VLC_MSG_ERR; ++ *sysp = (void *)(uintptr_t)verbosity; + -+ return &ops; ++ return &ops; +} + +vlc_module_begin() -+ set_shortname(N_("Emscripten log")) -+ set_description(N_("Emscripten log using logcat")) -+ set_category(CAT_ADVANCED) -+ set_subcategory(SUBCAT_ADVANCED_MISC) -+ set_capability("logger", 30) -+ set_callbacks(Open, NULL) ++ set_shortname(N_("emlog")) ++ set_description(N_("Emscripten loggger")) ++ set_category(CAT_ADVANCED) ++ set_subcategory(SUBCAT_ADVANCED_MISC) ++ set_capability("logger", 30) ++ set_callbacks(Open, NULL) +vlc_module_end () -- -2.23.0 +2.30.2 diff --git a/vlc_patches/nacl-wasm/0001-contrib-ass-add-support-for-wasm-emscripten.patch b/vlc_patches/nacl-wasm/0001-contrib-ass-add-support-for-wasm-emscripten.patch new file mode 100644 index 0000000000000000000000000000000000000000..f7c023b3eaff909e570a3484d4d7cbdf7b101cf6 --- /dev/null +++ b/vlc_patches/nacl-wasm/0001-contrib-ass-add-support-for-wasm-emscripten.patch @@ -0,0 +1,172 @@ +From fd1e539e2a585fb69ede782bd0180579e853597f Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Sun, 30 May 2021 19:22:31 +0200 +Subject: [PATCH 1/5] contrib: ass: add support for wasm-emscripten + +--- + contrib/src/ass/rules.mak | 5 + + ...nitial-support-for-wasm32-emscripten.patch | 105 ++++++++++++++++++ + contrib/src/fontconfig/rules.mak | 4 + + contrib/src/harfbuzz/rules.mak | 3 +- + 4 files changed, 116 insertions(+), 1 deletion(-) + create mode 100644 contrib/src/fontconfig/add-initial-support-for-wasm32-emscripten.patch + +diff --git a/contrib/src/ass/rules.mak b/contrib/src/ass/rules.mak +index fc6a90bb03..d84b209e77 100644 +--- a/contrib/src/ass/rules.mak ++++ b/contrib/src/ass/rules.mak +@@ -25,6 +25,11 @@ WITH_DWRITE = 1 + else + WITH_FONTCONFIG = 1 + WITH_HARFBUZZ = 1 ++ifdef HAVE_EMSCRIPTEN ++WITH_FONTCONFIG = 1 ++WITH_HARFBUZZ = 1 ++WITH_ASS_ASM = 0 ++endif + endif + endif + endif +diff --git a/contrib/src/fontconfig/add-initial-support-for-wasm32-emscripten.patch b/contrib/src/fontconfig/add-initial-support-for-wasm32-emscripten.patch +new file mode 100644 +index 0000000000..b1308fb19e +--- /dev/null ++++ b/contrib/src/fontconfig/add-initial-support-for-wasm32-emscripten.patch +@@ -0,0 +1,105 @@ ++From b7f21ca85efd78c8034223c63786a0c01b8378fe Mon Sep 17 00:00:00 2001 ++From: Mehdi Sabwat <mehdi@videolabs.io> ++Date: Wed, 9 Jun 2021 03:42:51 +0200 ++Subject: [PATCH 1/1] add initial support for wasm32-emscripten ++ ++This commit adds a check for uuid_generate_random which is not supported for now, and fixes a failing test. ++It also handles a case where F_FSTYPENAME field is not present in statfs struct. ++--- ++ configure.ac | 1 + ++ src/Makefile.am | 1 + ++ src/fcint.h | 5 +++++ ++ src/fcstat.c | 2 +- ++ src/uuid_generate_random.c | 9 +++++++++ ++ test/test-hash.c | 5 ++++- ++ 6 files changed, 21 insertions(+), 2 deletions(-) ++ create mode 100644 src/uuid_generate_random.c ++ ++diff --git a/configure.ac b/configure.ac ++index fb8af46..018cfc1 100644 ++--- a/configure.ac +++++ b/configure.ac ++@@ -171,2 +171,3 @@ AC_FUNC_VPRINTF ++ AC_FUNC_MMAP ++ AC_CHECK_FUNCS([link mkstemp mkostemp _mktemp_s mkdtemp getopt getopt_long getprogname getexecname rand random lrand48 random_r rand_r readlink fstatvfs fstatfs lstat strerror strerror_r]) +++AC_REPLACE_FUNCS([uuid_generate_random]) ++ ++ dnl AC_CHECK_FUNCS doesn't check for header files. ++ dnl posix_fadvise() may be not available in older libc. ++ AC_CHECK_SYMBOL([posix_fadvise], [fcntl.h], [fc_func_posix_fadvise=1], [fc_func_posix_fadvise=0]) ++diff --git a/src/Makefile.am b/src/Makefile.am ++index 7b414df..de1d785 100644 ++--- a/src/Makefile.am +++++ b/src/Makefile.am ++@@ -127,6 +127,7 @@ EXTRA_DIST += \ ++ fcobjshash.gperf.h ++ ++ libfontconfig_la_SOURCES = \ +++ uuid_generate_random.c \ ++ fcarch.h \ ++ fcatomic.c \ ++ fcatomic.h \ ++diff --git a/src/fcint.h b/src/fcint.h ++index a9d075a..d8fdbfd 100644 ++--- a/src/fcint.h +++++ b/src/fcint.h ++@@ -598,6 +598,11 @@ struct _FcValuePromotionBuffer { ++ FcPrivate FcCache * ++ FcDirCacheScan (const FcChar8 *dir, FcConfig *config); ++ +++#ifndef HAVE_UUID_GENERATE_RANDOM +++#include <uuid/uuid.h> +++void uuid_generate_random(uuid_t out); +++#endif +++ ++ FcPrivate FcCache * ++ FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs); ++ ++diff --git a/src/fcstat.c b/src/fcstat.c ++index 5aa1643..d1240c5 100644 ++--- a/src/fcstat.c +++++ b/src/fcstat.c ++@@ -384,7 +384,7 @@ FcFStatFs (int fd, FcStatFS *statb) ++ # endif ++ # if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) ++ p = buf.f_fstypename; ++-# elif defined(__linux__) +++# elif defined(__linux__) || defined(__EMSCRIPTEN__) ++ switch (buf.f_type) ++ { ++ case 0x6969: /* nfs */ ++diff --git a/src/uuid_generate_random.c b/src/uuid_generate_random.c ++new file mode 100644 ++index 0000000..c17a58d ++--- /dev/null +++++ b/src/uuid_generate_random.c ++@@ -0,0 +1,9 @@ +++// compat function for uuid_generate_random +++#include "fcint.h" +++ +++#ifndef HAVE_UUID_GENERATE_RANDOM +++void uuid_generate_random(uuid_t out) +++{ +++ uuid_generate(out); +++} +++#endif ++diff --git a/test/test-hash.c b/test/test-hash.c ++index 7530e82..221029d 100644 ++--- a/test/test-hash.c +++++ b/test/test-hash.c ++@@ -51,8 +51,11 @@ test_add (Test *test, FcChar8 *key, FcBool replace) ++ void *u; ++ FcBool (*hash_add) (FcHashTable *, void *, void *); ++ FcBool ret = FcFalse; ++- +++#ifdef HAVE_UUID_GENERATE_RANDOM ++ uuid_generate_random (uuid); +++#else +++ uuid_generate(uuid); +++#endif ++ if (replace) ++ hash_add = FcHashTableReplace; ++ else ++-- ++2.32.0 ++ +diff --git a/contrib/src/fontconfig/rules.mak b/contrib/src/fontconfig/rules.mak +index b761d44bd5..d187d211ae 100644 +--- a/contrib/src/fontconfig/rules.mak ++++ b/contrib/src/fontconfig/rules.mak +@@ -23,6 +23,10 @@ ifdef HAVE_WIN32 + endif + $(APPLY) $(SRC)/fontconfig/8208f99-fix-static-linking.patch + $(call pkg_static, "fontconfig.pc.in") ++ifdef HAVE_EMSCRIPTEN ++ $(APPLY) $(SRC)/fontconfig/add-initial-support-for-wasm32-emscripten.patch ++ $(UPDATE_AUTOCONFIG) ++endif + $(MOVE) + + FONTCONFIG_CONF := $(HOSTCONF) \ +diff --git a/contrib/src/harfbuzz/rules.mak b/contrib/src/harfbuzz/rules.mak +index 1ea81242e3..c1bc7fa5c3 100644 +--- a/contrib/src/harfbuzz/rules.mak ++++ b/contrib/src/harfbuzz/rules.mak +@@ -29,7 +29,8 @@ HARFBUZZ_CONF += --with-coretext + endif + + .harfbuzz: harfbuzz +- $(RECONF) ++ # https://savannah.gnu.org/support/index.php?110503 ++ export GTKDOCIZE=true && $(RECONF) + cd $< && $(HOSTVARS_PIC) ./configure $(HOSTCONF) $(HARFBUZZ_CONF) ICU_CONFIG=false + cd $< && $(MAKE) install + touch $@ +-- +2.30.2 + diff --git a/vlc_patches/nacl-wasm/0002-contrib-gcrypt-add-support-for-wasm-emscripten.patch b/vlc_patches/nacl-wasm/0002-contrib-gcrypt-add-support-for-wasm-emscripten.patch new file mode 100644 index 0000000000000000000000000000000000000000..84ab61769bc5292fb1de35ef2e84840385bbcd28 --- /dev/null +++ b/vlc_patches/nacl-wasm/0002-contrib-gcrypt-add-support-for-wasm-emscripten.patch @@ -0,0 +1,93 @@ +From ca88c8936b94312f6bfe844c9dacb310d7fee957 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Sun, 30 May 2021 20:38:46 +0200 +Subject: [PATCH 2/5] contrib: gcrypt: add support for wasm-emscripten + +--- + contrib/src/gcrypt/rules.mak | 6 ++++ + contrib/src/gpg-error/emscripten.patch | 43 ++++++++++++++++++++++++++ + contrib/src/gpg-error/rules.mak | 1 + + 3 files changed, 50 insertions(+) + create mode 100644 contrib/src/gpg-error/emscripten.patch + +diff --git a/contrib/src/gcrypt/rules.mak b/contrib/src/gcrypt/rules.mak +index c9c9be3efa..0275e21fe8 100644 +--- a/contrib/src/gcrypt/rules.mak ++++ b/contrib/src/gcrypt/rules.mak +@@ -72,6 +72,12 @@ ifeq ($(ARCH),aarch64) + GCRYPT_CONF += --disable-arm-crypto-support + endif + endif ++ifdef HAVE_EMSCRIPTEN ++GCRYPT_CONF += --disable-asm --disable-aesni-support ac_cv_func_syslog=no --disable-sse41-support ++GCRYPT_CONF += --disable-avx-support --disable-avx2-support --disable-padlock-support ++GCRYPT_CONF += --disable-amd64-as-feature-detection --disable-drng-support ++GCRYPT_CONF += --disable-pclmul-support ++endif + + .gcrypt: gcrypt + # Reconfiguring this requires a git repo to be available, to +diff --git a/contrib/src/gpg-error/emscripten.patch b/contrib/src/gpg-error/emscripten.patch +new file mode 100644 +index 0000000000..f60695c513 +--- /dev/null ++++ b/contrib/src/gpg-error/emscripten.patch +@@ -0,0 +1,43 @@ ++From 63aa1523659914acd6c84229fb31ff9b712fbf8b Mon Sep 17 00:00:00 2001 ++From: Mehdi Sabwat <mehdi@videolabs.io> ++Date: Wed, 2 Jun 2021 11:42:46 +0200 ++Subject: [PATCH 1/1] emscripten ++ ++--- ++ .../lock-obj-pub.wasm32-unknown-emscripten.h | 24 +++++++++++++++++++ ++ 1 file changed, 24 insertions(+) ++ create mode 100644 src/syscfg/lock-obj-pub.wasm32-unknown-emscripten.h ++ ++diff --git a/src/syscfg/lock-obj-pub.wasm32-unknown-emscripten.h b/src/syscfg/lock-obj-pub.wasm32-unknown-emscripten.h ++new file mode 100644 ++index 0000000..1651518 ++--- /dev/null +++++ b/src/syscfg/lock-obj-pub.wasm32-unknown-emscripten.h ++@@ -0,0 +1,24 @@ +++## lock-obj-pub.wasm32-unknown-emscripten.h +++## File created by gen-posix-lock-obj - DO NOT EDIT +++## To be included by mkheader into gpg-error.h +++ +++typedef struct +++{ +++ long _vers; +++ union { +++ volatile char _priv[28]; +++ long _x_align; +++ long *_xp_align; +++ } u; +++} gpgrt_lock_t; +++ +++#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ +++ 0,0,0,0,0,0,0,0, \ +++ 0,0,0,0,0,0,0,0, \ +++ 0,0,0,0}}} +++## +++## Local Variables: +++## mode: c +++## buffer-read-only: t +++## End: +++## ++-- ++2.31.1 ++ +diff --git a/contrib/src/gpg-error/rules.mak b/contrib/src/gpg-error/rules.mak +index 4e283c77cb..0f1053587d 100644 +--- a/contrib/src/gpg-error/rules.mak ++++ b/contrib/src/gpg-error/rules.mak +@@ -25,6 +25,7 @@ endif + $(APPLY) $(SRC)/gpg-error/version-bump-gawk-5.patch + $(APPLY) $(SRC)/gpg-error/win32-extern-struct.patch + $(APPLY) $(SRC)/gpg-error/darwin-triplet.patch ++ $(APPLY) $(SRC)/gpg-error/emscripten.patch + $(MOVE) + ifdef HAVE_ANDROID + ifeq ($(ARCH),aarch64) +-- +2.30.2 + diff --git a/vlc_patches/nacl-wasm/0003-contrib-gmp-add-support-for-wasm-emscripten.patch b/vlc_patches/nacl-wasm/0003-contrib-gmp-add-support-for-wasm-emscripten.patch new file mode 100644 index 0000000000000000000000000000000000000000..3fce285641d905911fee629611b29ff495386757 --- /dev/null +++ b/vlc_patches/nacl-wasm/0003-contrib-gmp-add-support-for-wasm-emscripten.patch @@ -0,0 +1,26 @@ +From cc28db23a9fc0fc2b116c33a26d72abf2dad7a4f Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Sun, 30 May 2021 21:22:40 +0200 +Subject: [PATCH 3/5] contrib: gmp: add support for wasm-emscripten + +--- + contrib/src/gmp/rules.mak | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/contrib/src/gmp/rules.mak b/contrib/src/gmp/rules.mak +index 11fe8acdfa..d6cd702ce0 100644 +--- a/contrib/src/gmp/rules.mak ++++ b/contrib/src/gmp/rules.mak +@@ -13,6 +13,9 @@ ifeq ($(ARCH),mips64el) + GMP_CONF += --disable-assembly + endif + endif ++ifdef HAVE_EMSCRIPTEN ++GMP_CONF += --disable-assembly ++endif + + ifdef HAVE_WIN32 + ifeq ($(ARCH),arm) +-- +2.30.2 + diff --git a/vlc_patches/nacl-wasm/0004-contrib-postproc-add-support-for-wasm-emscripten.patch b/vlc_patches/nacl-wasm/0004-contrib-postproc-add-support-for-wasm-emscripten.patch new file mode 100644 index 0000000000000000000000000000000000000000..9d7e904a29fce36aba2e625662c2c83941d4963b --- /dev/null +++ b/vlc_patches/nacl-wasm/0004-contrib-postproc-add-support-for-wasm-emscripten.patch @@ -0,0 +1,27 @@ +From 1e1459946fce7442ec6ca942d27227c8b19ff9ef Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Sun, 30 May 2021 22:00:12 +0200 +Subject: [PATCH 4/5] contrib: postproc: add support for wasm-emscripten + +--- + contrib/src/postproc/rules.mak | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/contrib/src/postproc/rules.mak b/contrib/src/postproc/rules.mak +index 252d6b384d..8a008f6ad2 100644 +--- a/contrib/src/postproc/rules.mak ++++ b/contrib/src/postproc/rules.mak +@@ -103,6 +103,10 @@ ifdef HAVE_SOLARIS + POSTPROCCONF += --enable-pic + endif + ++ifdef HAVE_EMSCRIPTEN ++POSTPROCCONF += --arch=wasm32 --target-os=linux ++endif ++ + # Build + + ifdef GPL +-- +2.30.2 + diff --git a/vlc_patches/nacl-wasm/0005-contrib-gnutls-add-support-for-wasm-emscripten.patch b/vlc_patches/nacl-wasm/0005-contrib-gnutls-add-support-for-wasm-emscripten.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc353a855cd7e064b311fb92a0ec4ff4a1fba247 --- /dev/null +++ b/vlc_patches/nacl-wasm/0005-contrib-gnutls-add-support-for-wasm-emscripten.patch @@ -0,0 +1,29 @@ +From 1627322eb7b9a485ce5380978e4db1fd5b331ee5 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Mon, 31 May 2021 00:18:18 +0200 +Subject: [PATCH 5/5] contrib: gnutls: add support for wasm-emscripten + +the contrib is temporarily disabled until this pr is merged: +https://github.com/emscripten-core/emscripten/pull/14352 +--- + contrib/src/gnutls/rules.mak | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/contrib/src/gnutls/rules.mak b/contrib/src/gnutls/rules.mak +index a5431693c1..012384d65b 100644 +--- a/contrib/src/gnutls/rules.mak ++++ b/contrib/src/gnutls/rules.mak +@@ -78,6 +78,10 @@ ifeq ($(ARCH),aarch64) + endif + endif + ++ifdef HAVE_EMSCRIPTEN ++ GNUTLS_CONF += --disable-hardware-acceleration ++endif ++ + .gnutls: gnutls + cd $< && $(GNUTLS_ENV) ./configure $(GNUTLS_CONF) + cd $< && $(MAKE) -C gl install +-- +2.30.2 + diff --git a/vlc_patches/openal/0001-Add-an-openal-audio-module.patch b/vlc_patches/openal/0001-Add-an-openal-audio-module.patch deleted file mode 100644 index ceeb4837de856fc03d372bb13d837abfcd03045f..0000000000000000000000000000000000000000 --- a/vlc_patches/openal/0001-Add-an-openal-audio-module.patch +++ /dev/null @@ -1,344 +0,0 @@ -From b1cefb4947b07ce2e4064c03d6cc20c3e6013af5 Mon Sep 17 00:00:00 2001 -From: Etienne Brateau <etienne.brateau@gmail.com> -Date: Tue, 29 Aug 2017 13:30:51 +0200 -Subject: [PATCH 1/6] Add an openal audio module. - ---- - modules/audio_output/Makefile.am | 11 ++ - modules/audio_output/openal.c | 305 +++++++++++++++++++++++++++++++ - 2 files changed, 316 insertions(+) - create mode 100644 modules/audio_output/openal.c - -diff --git a/modules/audio_output/Makefile.am b/modules/audio_output/Makefile.am -index 4af4d78c5f..120673ca6a 100644 ---- a/modules/audio_output/Makefile.am -+++ b/modules/audio_output/Makefile.am -@@ -117,3 +117,14 @@ endif - if HAVE_TVOS - aout_LTLIBRARIES += libaudiounit_ios_plugin.la - endif -+ -+libtizen_audio_plugin_la_SOURCES = audio_output/tizen_audio.c -+libtizen_audio_plugin_la_CFLAGS = $(AM_CFLAGS) -+EXTRA_LTLIBRARIES += libtizen_audio_plugin.la -+aout_LTLIBRARIES += $(LTLIBtizen_audio) -+ -+libopenal_audio_plugin_la_SOURCES = audio_output/openal.c -+libopenal_audio_plugin_la_CFLAGS = $(AM_CFLAGS) -+libopenal_audio_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(aoutdir)' -+libopenal_audio_plugin_la_LIBADD = -lopenal -+aout_LTLIBRARIES += libopenal_audio_plugin.la -diff --git a/modules/audio_output/openal.c b/modules/audio_output/openal.c -new file mode 100644 -index 0000000000..1c0b97a358 ---- /dev/null -+++ b/modules/audio_output/openal.c -@@ -0,0 +1,305 @@ -+/***************************************************************************** -+ * openal.c: output module to allow OpenAL integration -+ ***************************************************************************** -+ * -+ * Authors: Shaurav Garg <shauravg@gmail.com> -+ * Etienne Brateau <etienne.brateau@gmail.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -+ *****************************************************************************/ -+ -+/***************************************************************************** -+ * Preamble -+ *****************************************************************************/ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <assert.h> -+#include <vlc_common.h> -+#include <vlc_plugin.h> -+#include <vlc_aout.h> -+ -+#include <AL/al.h> -+#include <AL/alc.h> -+#ifndef __EMSCRIPTEN__ -+#include <AL/alext.h> -+#endif -+ -+#if defined __EMSCRIPTEN__ -+#include <emscripten.h> -+/* This format are supported in openAL by emscripten but the define are not done */ -+#define AL_FORMAT_MONO_FLOAT32 0x10010 -+#define AL_FORMAT_STEREO_FLOAT32 0x10011 -+#endif -+ -+/***************************************************************************** -+ * Local prototypes. -+ *****************************************************************************/ -+static int Open ( vlc_object_t * ); -+static void Close ( vlc_object_t * ); -+static void Stop ( audio_output_t *); -+static void Play ( audio_output_t *, block_t * ); -+static void Flush ( audio_output_t *, bool ); -+static void Pause ( audio_output_t *, bool , mtime_t ); -+static int Time_Get ( audio_output_t *, mtime_t * ); -+static int Start ( audio_output_t *, audio_sample_format_t *restrict ); -+static int DeviceSelect ( audio_output_t *, const char *); -+//static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, -+// vlc_value_t newval, vlc_value_t oldval, void *p_unused ); -+//static void GetDevices( vlc_object_t *, module_config_t * ); -+ -+/***************************************************************************** -+ * Used to configure OpenAL -+ ****************************************************************************/ -+#define NUM_BUF 255 -+#define CHUNK_SIZE 512 -+#define BUFFER_SIZE 4096 -+#define ALC_ALL_DEVICES_SPECIFIER 0x1013 -+ -+/*static const char *const ppsz_devices[] = { -+ "default", "default",}; -+ -+static const char *const ppsz_devices_text[] = { -+ N_("Default"), N_("Default"),}; -+*/ -+static ALenum openalFormat = AL_FORMAT_STEREO_FLOAT32; -+ -+/***************************************************************************** -+ * aout_sys_t: openal audio output method descriptor -+ ***************************************************************************** -+ * This structure is part of the audio output thread descriptor. -+ * It describes the direct sound specific properties of an audio device. -+ *****************************************************************************/ -+struct aout_sys_t -+{ -+ ALCdevice *dev; -+ ALCcontext *ctx; -+ ALsizei freq; -+ mtime_t start_date; -+ ALuint buffers[NUM_BUF]; -+ ALuint source; -+ ALuint is_playing; -+ ALuint next_buffer; -+}; -+ -+/***************************************************************************** -+ * Module descriptor -+ *****************************************************************************/ -+#define DEVICE_TEXT N_("Output device") -+#define DEVICE_LONGTEXT N_("Select your audio output device") -+ -+vlc_module_begin () -+ set_description( N_("OpenAL audio output") ) -+ set_shortname( "OpenAL" ) -+ set_capability( "audio output", 100 ) -+ set_category( CAT_AUDIO ) -+ set_subcategory( SUBCAT_AUDIO_AOUT ) -+// change_string_list( ppsz_devices, ppsz_devices_text ) -+// change_string_cb( FindDevicesCallback ) -+// change_action_add( FindDevicesCallback, N_("Refresh list") ) -+ -+ add_shortcut( "openal", "openal" ) -+ -+ add_string( "openal-audio-device-name", "default", -+ DEVICE_TEXT, DEVICE_LONGTEXT, false ) -+ -+ set_callbacks( Open, Close ) -+vlc_module_end () -+ -+/***************************************************************************** -+ * Open: open the audio device -+ ***************************************************************************** -+ * This function opens and setups Direct Sound. -+ *****************************************************************************/ -+static int Open( vlc_object_t *obj ) -+{ -+ audio_output_t * aout = (audio_output_t *) obj; -+ -+ /* Allocate structures */ -+ aout_sys_t *sys = malloc( sizeof( *sys ) ); -+ if( unlikely(sys == NULL) ) -+ return VLC_ENOMEM; -+ -+ -+ aout->sys = sys; -+ aout->start = Start; -+ aout->stop = Stop; -+ //aout_SoftVolumeInit(aout); -+ aout->play = Play; -+ aout->pause = Pause; -+ aout->flush = Flush; -+ //aout->time_get = Time_Get; -+ aout->pause = Pause; -+ aout->volume_set = NULL; -+ aout->mute_set = NULL; -+// aout->device_select = DeviceSelect; -+ -+ return VLC_SUCCESS; -+} -+ -+static int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt ) -+{ -+ aout_sys_t *sys = aout->sys; -+ -+ if ( aout_FormatNbChannels(fmt) == 0 ) -+ return VLC_EGENERIC; -+ -+ fmt->i_format = VLC_CODEC_FL32; -+ -+ float pos[3] = {0,0,0}; -+ float vel[3] = {0,0,0}; -+ float dir[6] = {0,0,-1,0,1,0}; -+ float speakerPos[3] = {0,0,1}; -+ //ALCint attrs[] = {ALC_FREQUENCY, fmt->i_rate, 0, 0}; -+ -+ const ALCchar* devInputName = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); -+ sys->dev = alcOpenDevice(devInputName); -+ if(!sys->dev) -+ { -+ msg_Err( aout, "cannot open OpenAL Device : %s", devInputName ); -+ return VLC_ENOMEM; -+ } -+ sys->ctx = alcCreateContext(sys->dev, NULL); -+ if(!sys->dev) -+ { -+ msg_Err( aout, "cannot create OpenAL Context" ); -+ return VLC_ENOMEM; -+ } -+ alcMakeContextCurrent(sys->ctx); -+ -+ alListenerfv(AL_POSITION, pos); -+ alListenerfv(AL_VELOCITY, vel); -+ alListenerfv(AL_ORIENTATION, dir); -+ alGenSources(1, &sys->source); -+ -+ alGenBuffers(NUM_BUF, &sys->buffers); -+ alSourcefv(sys->source, AL_POSITION, speakerPos); -+ alSource3f(sys->source, AL_VELOCITY, 0, 0, 0); -+ -+ alcGetIntegerv(sys->dev, ALC_FREQUENCY, 1, &sys->freq); -+ msg_Dbg(aout, "Openal Dev freq: %d", sys->freq); -+ -+ sys->start_date = 0; -+ sys->next_buffer = 0; -+ -+ return VLC_SUCCESS; -+} -+ -+static void Stop (audio_output_t *aout) -+{ -+ aout_sys_t *sys = aout->sys; -+ -+ alSourcei(sys->source, AL_BUFFER, 0); -+ alDeleteBuffers(NUM_BUF, &sys->buffers); -+ alDeleteSources(1, &sys->source); -+ -+ alcDestroyContext(sys->ctx); -+ alcCloseDevice(sys->dev); -+} -+ -+/***************************************************************************** -+ * Play: method description here -+ *****************************************************************************/ -+static void Play( audio_output_t *aout, block_t *block ) -+{ -+ aout_sys_t *sys = aout->sys; -+ const void* data = block->p_buffer; -+ size_t datalen = block->i_buffer; -+ -+ -+ ALenum err; -+ ALint buffersProcessed = 0; -+ -+ alGetSourcei(sys->source, AL_BUFFERS_PROCESSED, &buffersProcessed); -+ //msg_Dbg(aout, "buffered processed / next buffer : %i / %i", buffersProcessed, sys->next_buffer); -+ ALint tmpBuffers[buffersProcessed]; -+ -+ alSourceUnqueueBuffers(sys->source, buffersProcessed, &tmpBuffers); -+ -+ //fill with silence originally -+ if(buffersProcessed > 0) -+ alBufferData(tmpBuffers[0], openalFormat, data, datalen, sys->freq); -+ else -+ { -+ alBufferData(sys->buffers[sys->next_buffer], openalFormat, data, datalen, sys->freq); -+ } -+ -+ if(buffersProcessed > 0) -+ { -+ alSourceQueueBuffers(sys->source, 1, &tmpBuffers[0]); -+ } -+ else -+ { -+ alSourceQueueBuffers(sys->source, 1, &sys->buffers[sys->next_buffer]); -+ sys->next_buffer = (sys->next_buffer + 1) % NUM_BUF; -+ } -+ -+ alGetSourcei(sys->source, AL_SOURCE_STATE, &sys->is_playing); -+ if(sys->is_playing != AL_PLAYING) -+ alSourcePlay(sys->source); -+ -+ block_Release(block); -+} -+ -+static void Pause( audio_output_t *aout, bool paused, mtime_t date ) -+{ -+ aout_sys_t *sys = aout->sys; -+ // TODO -+} -+ -+static void Flush( audio_output_t *aout, bool wait ) -+{ -+ aout_sys_t * sys = aout->sys; -+ // TODO -+} -+ -+static int DeviceSelect( audio_output_t *aout, const char *psz_device) -+{ -+ /*if ( psz_device == NULL ) -+ return VLC_EGENERIC; -+ char* psz_end; -+ intptr_t ptr = strtoll( psz_device, &psz_end, 16 ); -+ if( *psz_end != 0 ) -+ return VLC_EGENERIC; -+ if (aout->sys->dev == (ALCdevice*)ptr) -+ return VLC_SUCCESS;*/ -+ const ALCchar* devInputName = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); -+ aout->sys->dev = alcOpenDevice(devInputName); -+ var_SetAddress (aout->obj.parent, "emscripten-openal-device", aout->sys->dev ); -+ aout_RestartRequest( aout, AOUT_RESTART_OUTPUT ); -+ return VLC_SUCCESS; -+} -+ -+/*static void Time_Get( audio_output_t *aout, mtime_t *delay) -+{ -+ aout_sys_t *sys = aout->sys; -+ -+ return 0; -+}*/ -+ -+/***************************************************************************** -+ * CloseAudio: close the audio device -+ *****************************************************************************/ -+static void Close( vlc_object_t *obj ) -+{ -+ msg_Dbg(obj, "Openal Close"); -+ audio_output_t *aout = (audio_output_t *)obj; -+ struct aout_sys_t *sys = aout->sys; -+ -+ free(sys); -+} -+ --- -2.23.0 - diff --git a/vlc_patches/openal/0002-wip-adapt-code-to-4.0-api.patch b/vlc_patches/openal/0002-wip-adapt-code-to-4.0-api.patch deleted file mode 100644 index cf98e1c45466d95b8c59cc71cfc1557c26c3cc7e..0000000000000000000000000000000000000000 --- a/vlc_patches/openal/0002-wip-adapt-code-to-4.0-api.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 9b46de215341f5ad54f2215c4bc41fa8e40cc1e9 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Tue, 1 Oct 2019 19:34:46 +0200 -Subject: [PATCH 2/6] wip: adapt code to 4.0 api - ---- - modules/audio_output/openal.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/modules/audio_output/openal.c b/modules/audio_output/openal.c -index 1c0b97a358..6d4a707642 100644 ---- a/modules/audio_output/openal.c -+++ b/modules/audio_output/openal.c -@@ -84,7 +84,7 @@ static ALenum openalFormat = AL_FORMAT_STEREO_FLOAT32; - * This structure is part of the audio output thread descriptor. - * It describes the direct sound specific properties of an audio device. - *****************************************************************************/ --struct aout_sys_t -+typedef struct aout_sys_t - { - ALCdevice *dev; - ALCcontext *ctx; -@@ -94,7 +94,7 @@ struct aout_sys_t - ALuint source; - ALuint is_playing; - ALuint next_buffer; --}; -+} aout_sys_t; - - /***************************************************************************** - * Module descriptor -@@ -269,6 +269,7 @@ static void Flush( audio_output_t *aout, bool wait ) - - static int DeviceSelect( audio_output_t *aout, const char *psz_device) - { -+ aout_sys_t *sys = aout->sys; - /*if ( psz_device == NULL ) - return VLC_EGENERIC; - char* psz_end; -@@ -278,8 +279,9 @@ static int DeviceSelect( audio_output_t *aout, const char *psz_device) - if (aout->sys->dev == (ALCdevice*)ptr) - return VLC_SUCCESS;*/ - const ALCchar* devInputName = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); -- aout->sys->dev = alcOpenDevice(devInputName); -- var_SetAddress (aout->obj.parent, "emscripten-openal-device", aout->sys->dev ); -+ -+ sys->dev = alcOpenDevice(devInputName); -+ var_SetAddress (vlc_object_parent(aout), "emscripten-openal-device", sys->dev ); - aout_RestartRequest( aout, AOUT_RESTART_OUTPUT ); - return VLC_SUCCESS; - } --- -2.23.0 - diff --git a/vlc_patches/openal/0003-aout-add-Timeg_Get-stub-for-OpenAl.patch b/vlc_patches/openal/0003-aout-add-Timeg_Get-stub-for-OpenAl.patch deleted file mode 100644 index 34c622da7b4af37733a95cda355a0b6c9f098f84..0000000000000000000000000000000000000000 --- a/vlc_patches/openal/0003-aout-add-Timeg_Get-stub-for-OpenAl.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 7504f01518164b091e5b0cf8c5e0dc9679cb1138 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Wed, 2 Oct 2019 22:05:01 +0200 -Subject: [PATCH 3/6] aout: add Timeg_Get stub for OpenAl - -to avoid aborting in src/audio_output/output.c ---- - modules/audio_output/openal.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/modules/audio_output/openal.c b/modules/audio_output/openal.c -index 6d4a707642..c48c5a0f5e 100644 ---- a/modules/audio_output/openal.c -+++ b/modules/audio_output/openal.c -@@ -142,7 +142,7 @@ static int Open( vlc_object_t *obj ) - aout->play = Play; - aout->pause = Pause; - aout->flush = Flush; -- //aout->time_get = Time_Get; -+ aout->time_get = Time_Get; - aout->pause = Pause; - aout->volume_set = NULL; - aout->mute_set = NULL; -@@ -286,12 +286,12 @@ static int DeviceSelect( audio_output_t *aout, const char *psz_device) - return VLC_SUCCESS; - } - --/*static void Time_Get( audio_output_t *aout, mtime_t *delay) -+static int Time_Get( audio_output_t *aout, mtime_t *delay) - { - aout_sys_t *sys = aout->sys; -- -+ *delay = aout_TimeGetDefault(aout, delay); - return 0; --}*/ -+} - - /***************************************************************************** - * CloseAudio: close the audio device --- -2.23.0 - diff --git a/vlc_patches/openal/0004-wip-delete-call-to-msg_Dbg.patch b/vlc_patches/openal/0004-wip-delete-call-to-msg_Dbg.patch deleted file mode 100644 index 9c4a476c68dccf6ab9e14fa3884330687909b6f7..0000000000000000000000000000000000000000 --- a/vlc_patches/openal/0004-wip-delete-call-to-msg_Dbg.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0aa4efe1deb2fe6bfcb51be19e876f85738078e2 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Thu, 3 Oct 2019 22:32:12 +0200 -Subject: [PATCH 4/6] wip: delete call to msg_Dbg - -The logger module needs to be fixed, there is something wrong with it. -some calls to msg_Dbg on various places -(audio output/audio filters/MP4 demux/access, keystore, and maybe more...) -triggers Runtime Errors (out of bounds). -Also, we see garbage values in the console instead of actual output. ---- - modules/audio_output/openal.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/modules/audio_output/openal.c b/modules/audio_output/openal.c -index c48c5a0f5e..2a5f6f946d 100644 ---- a/modules/audio_output/openal.c -+++ b/modules/audio_output/openal.c -@@ -191,7 +191,8 @@ static int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt ) - alSource3f(sys->source, AL_VELOCITY, 0, 0, 0); - - alcGetIntegerv(sys->dev, ALC_FREQUENCY, 1, &sys->freq); -- msg_Dbg(aout, "Openal Dev freq: %d", sys->freq); -+ -+ //msg_Dbg(aout, "Openal Dev freq: %d", sys->freq); - - sys->start_date = 0; - sys->next_buffer = 0; -@@ -298,7 +299,7 @@ static int Time_Get( audio_output_t *aout, mtime_t *delay) - *****************************************************************************/ - static void Close( vlc_object_t *obj ) - { -- msg_Dbg(obj, "Openal Close"); -+ //msg_Dbg(obj, "Openal Close"); - audio_output_t *aout = (audio_output_t *)obj; - struct aout_sys_t *sys = aout->sys; - --- -2.23.0 - diff --git a/vlc_patches/openal/0005-aout-Change-function-prototypes-and-add-volume_set-s.patch b/vlc_patches/openal/0005-aout-Change-function-prototypes-and-add-volume_set-s.patch deleted file mode 100644 index a9c16270e2adbf273a1b52f5ab318d4f2f14572d..0000000000000000000000000000000000000000 --- a/vlc_patches/openal/0005-aout-Change-function-prototypes-and-add-volume_set-s.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 5085d642685c1e47c78efeb9046373ca78f7b412 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Fri, 4 Oct 2019 19:37:18 +0200 -Subject: [PATCH 5/6] aout: Change function prototypes and add volume_set stub - -This commit enables a bug that is caused by an invalid pointer, -that I couldn't find yet. This is not a good implementation, as -audio will work, but will prevent frames from being displayed. -Probably because of the Audio processing taking too much processing -power out of the browser main thread. ---- - modules/audio_output/openal.c | 19 +++++++++++++------ - 1 file changed, 13 insertions(+), 6 deletions(-) - -diff --git a/modules/audio_output/openal.c b/modules/audio_output/openal.c -index 2a5f6f946d..374f2fd0a9 100644 ---- a/modules/audio_output/openal.c -+++ b/modules/audio_output/openal.c -@@ -52,12 +52,13 @@ - static int Open ( vlc_object_t * ); - static void Close ( vlc_object_t * ); - static void Stop ( audio_output_t *); --static void Play ( audio_output_t *, block_t * ); -+static void Play ( audio_output_t *, block_t * , vlc_tick_t); - static void Flush ( audio_output_t *, bool ); --static void Pause ( audio_output_t *, bool , mtime_t ); -+static void Pause ( audio_output_t *, bool , vlc_tick_t); - static int Time_Get ( audio_output_t *, mtime_t * ); - static int Start ( audio_output_t *, audio_sample_format_t *restrict ); - static int DeviceSelect ( audio_output_t *, const char *); -+static int Volume_Set ( audio_output_t *, float); - //static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, - // vlc_value_t newval, vlc_value_t oldval, void *p_unused ); - //static void GetDevices( vlc_object_t *, module_config_t * ); -@@ -143,8 +144,7 @@ static int Open( vlc_object_t *obj ) - aout->pause = Pause; - aout->flush = Flush; - aout->time_get = Time_Get; -- aout->pause = Pause; -- aout->volume_set = NULL; -+ aout->volume_set = Volume_Set; - aout->mute_set = NULL; - // aout->device_select = DeviceSelect; - -@@ -215,8 +215,9 @@ static void Stop (audio_output_t *aout) - /***************************************************************************** - * Play: method description here - *****************************************************************************/ --static void Play( audio_output_t *aout, block_t *block ) -+static void Play( audio_output_t *aout, block_t *block , vlc_tick_t date) - { -+ VLC_UNUSED(date); - aout_sys_t *sys = aout->sys; - const void* data = block->p_buffer; - size_t datalen = block->i_buffer; -@@ -256,7 +257,7 @@ static void Play( audio_output_t *aout, block_t *block ) - block_Release(block); - } - --static void Pause( audio_output_t *aout, bool paused, mtime_t date ) -+static void Pause( audio_output_t *aout, bool paused, vlc_tick_t date ) - { - aout_sys_t *sys = aout->sys; - // TODO -@@ -306,3 +307,9 @@ static void Close( vlc_object_t *obj ) - free(sys); - } - -+static int Volume_Set ( audio_output_t *aout, float volume) -+{ -+ VLC_UNUSED(aout); -+ VLC_UNUSED(volume); -+ return 0; -+} --- -2.23.0 - diff --git a/vlc_patches/openal/0006-fixup-implement-timeget-stub-correctly.patch b/vlc_patches/openal/0006-fixup-implement-timeget-stub-correctly.patch deleted file mode 100644 index 34de78ca34a61728ae52e853e266b28d48c32f53..0000000000000000000000000000000000000000 --- a/vlc_patches/openal/0006-fixup-implement-timeget-stub-correctly.patch +++ /dev/null @@ -1,39 +0,0 @@ -From b904cb2019ff494a49d249b52f50e71fd4d1e83b Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Fri, 11 Oct 2019 11:47:48 +0200 -Subject: [PATCH 6/6] fixup: implement timeget stub correctly - ---- - modules/audio_output/openal.c | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/modules/audio_output/openal.c b/modules/audio_output/openal.c -index 374f2fd0a9..48fdadb9dd 100644 ---- a/modules/audio_output/openal.c -+++ b/modules/audio_output/openal.c -@@ -55,7 +55,7 @@ static void Stop ( audio_output_t *); - static void Play ( audio_output_t *, block_t * , vlc_tick_t); - static void Flush ( audio_output_t *, bool ); - static void Pause ( audio_output_t *, bool , vlc_tick_t); --static int Time_Get ( audio_output_t *, mtime_t * ); -+static int Time_Get ( audio_output_t *, vlc_tick_t * ); - static int Start ( audio_output_t *, audio_sample_format_t *restrict ); - static int DeviceSelect ( audio_output_t *, const char *); - static int Volume_Set ( audio_output_t *, float); -@@ -288,11 +288,9 @@ static int DeviceSelect( audio_output_t *aout, const char *psz_device) - return VLC_SUCCESS; - } - --static int Time_Get( audio_output_t *aout, mtime_t *delay) -+static int Time_Get( audio_output_t *aout, vlc_tick_t *delay) - { -- aout_sys_t *sys = aout->sys; -- *delay = aout_TimeGetDefault(aout, delay); -- return 0; -+ return aout_TimeGetDefault(aout, delay); - } - - /***************************************************************************** --- -2.23.0 - diff --git a/vlc_patches/video_output/0001-opengl-set-egl-display.patch b/vlc_patches/video_output/0001-opengl-set-egl-display.patch new file mode 100644 index 0000000000000000000000000000000000000000..68c013c6ab9f64c5bf88493d5808d7043a1668f9 --- /dev/null +++ b/vlc_patches/video_output/0001-opengl-set-egl-display.patch @@ -0,0 +1,29 @@ +From 05d8b9c89724bb8cb1f268b8e9704d9673ec988c Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Tue, 27 Apr 2021 16:27:19 +0200 +Subject: [PATCH] opengl: set egl display + +Emscripten does not implement EGL extensions. +https://emscripten.org/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.html#egl-extensions +--- + modules/video_output/opengl/egl_display_generic.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/modules/video_output/opengl/egl_display_generic.c b/modules/video_output/opengl/egl_display_generic.c +index dfb841feef..730fb381d2 100644 +--- a/modules/video_output/opengl/egl_display_generic.c ++++ b/modules/video_output/opengl/egl_display_generic.c +@@ -52,8 +52,8 @@ static vlc_egl_display_open_fn Open; + static int + Open(struct vlc_egl_display *display) + { +-#ifdef __ANDROID__ +- /* The default display is refcounted on Android */ ++#if defined(__ANDROID__) || defined(__EMSCRIPTEN__) ++ /* The default display is refcounted on Android and Emscripten */ + display->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + #elif defined(EGL_KHR_display_reference) + const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); +-- +2.32.0 + diff --git a/vlc_patches/video_output/0001-vout-add-emscripten-webgl-module.patch b/vlc_patches/video_output/0001-vout-add-emscripten-webgl-module.patch new file mode 100644 index 0000000000000000000000000000000000000000..0134518a56e3708d6f20734cf031b9c4bb424615 --- /dev/null +++ b/vlc_patches/video_output/0001-vout-add-emscripten-webgl-module.patch @@ -0,0 +1,223 @@ +From 9fbc02711de3798c7bd7beda0db515fae91088d5 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Tue, 27 Apr 2021 16:45:02 +0200 +Subject: [PATCH] vout: add emscripten webgl module + +this module uses the OFFSCREEN_FRAMEBUFFER option which +adds a backbuffer to the webgl context, that will be used +for rendering. + +it works as a polyfill for offscreen canvas. + +Co-Authored-By: Etienne Brateau <etienne.brateau@gmail.com> +--- + modules/video_output/Makefile.am | 7 ++ + modules/video_output/emscripten.c | 178 ++++++++++++++++++++++++++++++ + 2 files changed, 185 insertions(+) + create mode 100644 modules/video_output/emscripten.c + +diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am +index 72f870b41c..7f629a8990 100644 +--- a/modules/video_output/Makefile.am ++++ b/modules/video_output/Makefile.am +@@ -301,6 +301,13 @@ libcaca_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' + EXTRA_LTLIBRARIES += libcaca_plugin.la + vout_LTLIBRARIES += $(LTLIBcaca) + ++### Emscripten ### ++libemscripten_window_plugin_la_SOURCES = video_output/emscripten.c ++ ++if HAVE_EMSCRIPTEN ++vout_LTLIBRARIES += libemscripten_window_plugin.la ++endif ++ + ### Common ### + + libflaschen_plugin_la_SOURCES = video_output/flaschen.c +diff --git a/modules/video_output/emscripten.c b/modules/video_output/emscripten.c +new file mode 100644 +index 0000000000..f940738a03 +--- /dev/null ++++ b/modules/video_output/emscripten.c +@@ -0,0 +1,178 @@ ++/** ++ * @file emscripten.c ++ * @brief Emscripten webgl video output for VLC media player ++ */ ++/***************************************************************************** ++ * Copyright © 2020 VLC authors and VideoLAN ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. ++ *****************************************************************************/ ++ ++#ifdef HAVE_CONFIG_H ++# include <config.h> ++#endif ++ ++#include <stdarg.h> ++ ++#include <vlc_common.h> ++#include <vlc_plugin.h> ++#include <vlc_vout_window.h> ++#include <vlc_vout_display.h> ++#include <vlc_opengl.h> ++ ++#include "./opengl/vout_helper.h" ++ ++#include <emscripten.h> ++#include <emscripten/html5.h> ++#include <webgl/webgl2.h> ++// eglGetProcAddress ++#include <EGL/egl.h> ++ ++extern emscripten_GetProcAddress(char *name); ++ ++static const struct vout_window_operations ops = { ++ //TODO: Implement canvas operations ++ //vout_window_ReportSize() should be called from here ++}; ++ ++typedef struct gl_sys_t ++{ ++ unsigned width; ++ unsigned height; ++ ++ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context; ++} gl_sys_t; ++ ++static int OpenWindow(vout_window_t *wnd) ++{ ++ wnd->type = VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL; ++ wnd->ops = &ops; ++ ++ return VLC_SUCCESS; ++} ++ ++static void *GetProcAddress(vlc_gl_t *gl, const char *name) ++{ ++ VLC_UNUSED(gl); ++ ++ return eglGetProcAddress(name); ++} ++static int MakeCurrent(vlc_gl_t *gl) ++{ ++ gl_sys_t *sys = gl->sys; ++ ++ if (emscripten_webgl_make_context_current(sys->context) != EMSCRIPTEN_RESULT_SUCCESS) ++ return VLC_EGENERIC; ++ return VLC_SUCCESS; ++} ++ ++static void ReleaseCurrent(vlc_gl_t *gl) ++{ ++ VLC_UNUSED(gl); ++ emscripten_webgl_make_context_current(0); ++} ++ ++static void Swap(vlc_gl_t *gl) ++{ ++ VLC_UNUSED(gl); ++ emscripten_webgl_commit_frame(); ++} ++ ++static void Resize(vlc_gl_t *gl, unsigned w, unsigned h) ++{ ++ VLC_UNUSED(gl); ++ VLC_UNUSED(w); ++ VLC_UNUSED(h); ++} ++ ++static void Close (vlc_gl_t *gl) ++{ ++ free(gl->sys); ++} ++ ++static int Open (vlc_gl_t *gl, unsigned width, unsigned height) ++{ ++ VLC_UNUSED(width), VLC_UNUSED(height); ++ ++ EmscriptenWebGLContextAttributes attr; ++ ++ emscripten_webgl_init_context_attributes(&attr); ++ attr.majorVersion=2; ++ attr.minorVersion=0; ++ attr.explicitSwapControl = 1; ++ ++ vout_window_t *wnd = gl->surface; ++ ++ if (wnd->type != VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL) ++ goto error; ++ ++ gl_sys_t *sys; ++ ++ gl->sys = sys = calloc(1, sizeof(*sys)); ++ if (!sys) ++ return VLC_ENOMEM; ++ ++ sys->context = emscripten_webgl_create_context("#canvas", &attr); ++ if (!sys->context) { ++ msg_Err(gl, "Failed to make context current"); ++ goto error; ++ } ++ ++ // Check that the WebGL context is valid ++ if (emscripten_webgl_make_context_current(sys->context) != EMSCRIPTEN_RESULT_SUCCESS) { ++ emscripten_log(EM_LOG_CONSOLE, "failed to make context current"); ++ goto error; ++ } ++ ++ // Release the context ++ emscripten_webgl_make_context_current(0); ++ wnd->handle.em_context = sys->context; ++ ++ // Implement egl routines: ++ gl->make_current = MakeCurrent; ++ gl->release_current = ReleaseCurrent; ++ gl->resize = Resize; ++ gl->swap = Swap; ++ gl->get_proc_address = GetProcAddress; ++ gl->destroy = Close; ++ ++ return VLC_SUCCESS; ++error: ++ Close(gl); ++ return VLC_EGENERIC; ++} ++ ++/* ++ * Module descriptor ++ */ ++vlc_module_begin() ++ set_shortname(N_("Emscripten Window")) ++ set_description(N_("Emscripten drawing area")) ++ set_category(CAT_VIDEO) ++ set_subcategory(SUBCAT_VIDEO_VOUT) ++ set_capability("vout window", 10) ++ set_callbacks(OpenWindow, NULL) ++ ++ add_submodule () ++ set_shortname("Emscripten GL") ++ set_description(N_("Emscripten extension for OpenGL")) ++ set_category(CAT_VIDEO) ++ set_subcategory(SUBCAT_VIDEO_VOUT) ++ set_capability("opengl es2", 50) ++ set_callback(Open) ++ add_shortcut("em_webgl") ++vlc_module_end() ++ +-- +2.32.0 + diff --git a/vlc_patches/0013-window-add-emscripten-type.patch b/vlc_patches/video_output/0001-vout-add-emscripten-window-and-webgl-context.patch similarity index 58% rename from vlc_patches/0013-window-add-emscripten-type.patch rename to vlc_patches/video_output/0001-vout-add-emscripten-window-and-webgl-context.patch index 623adfe5b0e2a16b779bb298f9b4a8bfc8c75d24..3fa87b2d749ebc97a84a628bf0e1b001366a73a4 100644 --- a/vlc_patches/0013-window-add-emscripten-type.patch +++ b/vlc_patches/video_output/0001-vout-add-emscripten-window-and-webgl-context.patch @@ -1,32 +1,32 @@ -From 09a5bb40c8e09967a07fdc9127337a9992e4afc9 Mon Sep 17 00:00:00 2001 -From: Mehdi Sabwat <mehdisabwat@gmail.com> -Date: Thu, 12 Sep 2019 15:02:47 +0200 -Subject: [PATCH 13/15] window: add emscripten type +From 463e0decd11348debe16ec70c46173231929f188 Mon Sep 17 00:00:00 2001 +From: Etienne Brateau <etienne.brateau@gmail.com> +Date: Tue, 27 Apr 2021 16:19:40 +0200 +Subject: [PATCH] vout: add emscripten window and webgl context --- include/vlc_vout_window.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/vlc_vout_window.h b/include/vlc_vout_window.h -index 9116fa6561..8533a963f3 100644 +index dd4e67a86e..769c3170d1 100644 --- a/include/vlc_vout_window.h +++ b/include/vlc_vout_window.h -@@ -63,6 +63,7 @@ enum vout_window_type { - VOUT_WINDOW_TYPE_NSOBJECT /**< MacOS X view */, +@@ -64,6 +64,7 @@ enum vout_window_type { VOUT_WINDOW_TYPE_ANDROID_NATIVE /**< Android native window */, VOUT_WINDOW_TYPE_WAYLAND /**< Wayland surface */, + VOUT_WINDOW_TYPE_DCOMP /**< Win32 DirectComposition */, + VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL /**< Emscripten surface */, }; /** -@@ -360,6 +361,7 @@ typedef struct vout_window_t { - void *nsobject; /**< Mac OSX view object */ +@@ -378,6 +379,7 @@ typedef struct vout_window_t { void *anativewindow; /**< Android native window */ struct wl_surface *wl; /**< Wayland surface (client pointer) */ + void *dcomp_visual; /**< Win32 direct composition visual */ + uint32_t em_context; /* Emscripten webgl context */ } handle; /** Display server (mandatory) -- -2.23.0 +2.32.0 diff --git a/vlc_patches/video_output/offscreen-canvas.patch b/vlc_patches/video_output/offscreen-canvas.patch new file mode 100644 index 0000000000000000000000000000000000000000..4e9f4df6e959938443984aca2b7f9a914dba4549 --- /dev/null +++ b/vlc_patches/video_output/offscreen-canvas.patch @@ -0,0 +1,357 @@ +From f77f89feafc1c88aee29671964344a84ded89238 Mon Sep 17 00:00:00 2001 +From: Mehdi Sabwat <mehdi@videolabs.io> +Date: Wed, 18 Nov 2020 20:34:30 +0100 +Subject: [PATCH 1/1] vout: add offscreen canvas initial support + +The Webgl context cannot be shared between workers, we need to be able to have : +- shader and program creation and linking +- gl operations +in the same worker. +--- + modules/video_output/emscripten.c | 185 ++++++++++++++++-------------- + src/video_output/video_output.c | 20 ++++ + src/video_output/vout_private.h | 1 + + src/video_output/vout_wrapper.c | 3 + + 4 files changed, 125 insertions(+), 84 deletions(-) + +diff --git a/modules/video_output/emscripten.c b/modules/video_output/emscripten.c +index f940738a03..988c8a7818 100644 +--- a/modules/video_output/emscripten.c ++++ b/modules/video_output/emscripten.c +@@ -44,135 +44,152 @@ + extern emscripten_GetProcAddress(char *name); + + static const struct vout_window_operations ops = { +- //TODO: Implement canvas operations +- //vout_window_ReportSize() should be called from here ++ //TODO: Implement canvas operations ++ //vout_window_ReportSize() should be called from here + }; + + typedef struct gl_sys_t + { +- unsigned width; +- unsigned height; ++ unsigned width; ++ unsigned height; + +- EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context; ++ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context; + } gl_sys_t; + + static int OpenWindow(vout_window_t *wnd) + { +- wnd->type = VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL; +- wnd->ops = &ops; ++ wnd->type = VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL; ++ wnd->ops = &ops; + +- return VLC_SUCCESS; ++ return VLC_SUCCESS; + } + + static void *GetProcAddress(vlc_gl_t *gl, const char *name) + { +- VLC_UNUSED(gl); ++ VLC_UNUSED(gl); + +- return eglGetProcAddress(name); ++ return (void *)emscripten_GetProcAddress(name); + } + static int MakeCurrent(vlc_gl_t *gl) + { +- gl_sys_t *sys = gl->sys; +- +- if (emscripten_webgl_make_context_current(sys->context) != EMSCRIPTEN_RESULT_SUCCESS) +- return VLC_EGENERIC; +- return VLC_SUCCESS; ++ VLC_UNUSED(gl); ++ /* ++ We don't need to MakeCurrent or ReleaseCurrent in a single threaded setting ++ cf : https://chromium.googlesource.com/chromium/src/+/9478e129bf1ab74b7629d2837b88189d234587b7/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp#416 ++ https://emscripten.org/docs/api_reference/html5.h.html#c.EmscriptenWebGLContextAttributes.proxyContextToMainThread ++ offscreen canvas means for now that all Webgl operations will happen in one thread ++ */ ++ ++ return VLC_SUCCESS; + } + + static void ReleaseCurrent(vlc_gl_t *gl) + { +- VLC_UNUSED(gl); +- emscripten_webgl_make_context_current(0); ++ VLC_UNUSED(gl); + } + + static void Swap(vlc_gl_t *gl) + { +- VLC_UNUSED(gl); +- emscripten_webgl_commit_frame(); ++ VLC_UNUSED(gl); ++ EM_ASM({ ++ // cf : vlc/extras/package/wasm-emscripten/assets/module-loader.js:postRun() ++ postMessage({ cmd: "objectTransfer", msg: { bitmap: self.Module.ctx.canvas.transferToImageBitmap()} }); ++ }, 0); + } + + static void Resize(vlc_gl_t *gl, unsigned w, unsigned h) + { +- VLC_UNUSED(gl); +- VLC_UNUSED(w); +- VLC_UNUSED(h); ++ // to implement ++ VLC_UNUSED(gl); ++ VLC_UNUSED(w); ++ VLC_UNUSED(h); + } + + static void Close (vlc_gl_t *gl) + { +- free(gl->sys); ++ free(gl->sys); + } + + static int Open (vlc_gl_t *gl, unsigned width, unsigned height) + { +- VLC_UNUSED(width), VLC_UNUSED(height); +- +- EmscriptenWebGLContextAttributes attr; +- +- emscripten_webgl_init_context_attributes(&attr); +- attr.majorVersion=2; +- attr.minorVersion=0; +- attr.explicitSwapControl = 1; +- +- vout_window_t *wnd = gl->surface; ++ VLC_UNUSED(width), VLC_UNUSED(height); // to implement ++ ++ vout_window_t *wnd = gl->surface; + +- if (wnd->type != VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL) +- goto error; +- +- gl_sys_t *sys; +- +- gl->sys = sys = calloc(1, sizeof(*sys)); +- if (!sys) +- return VLC_ENOMEM; ++ if (wnd->type != VOUT_WINDOW_TYPE_EMSCRIPTEN_WEBGL) ++ goto error; ++ ++ gl_sys_t *sys; + +- sys->context = emscripten_webgl_create_context("#canvas", &attr); +- if (!sys->context) { +- msg_Err(gl, "Failed to make context current"); +- goto error; +- } +- +- // Check that the WebGL context is valid +- if (emscripten_webgl_make_context_current(sys->context) != EMSCRIPTEN_RESULT_SUCCESS) { +- emscripten_log(EM_LOG_CONSOLE, "failed to make context current"); +- goto error; +- } +- +- // Release the context +- emscripten_webgl_make_context_current(0); +- wnd->handle.em_context = sys->context; +- +- // Implement egl routines: +- gl->make_current = MakeCurrent; +- gl->release_current = ReleaseCurrent; +- gl->resize = Resize; +- gl->swap = Swap; +- gl->get_proc_address = GetProcAddress; +- gl->destroy = Close; +- +- return VLC_SUCCESS; ++ gl->sys = sys = (gl_sys_t *)(calloc(1, sizeof(*sys))); ++ ++ if (!sys) ++ return VLC_EGENERIC; ++ ++ EM_ASM({ ++ const wdt = $0; ++ const hgt = $1; ++ ++ var canvas = new OffscreenCanvas(wdt, hgt); ++ // EM_ASM are constants, we need this to reuse the variable in another scope ++ // as long as we stay in the worker ++ Module.canvas = canvas; ++ ++ // set attributes with overloads for the emscripten GL object ++ var attributes = {}; ++ attributes.alpha = true; ++ attributes.depth = true; ++ attributes.stencil = false; ++ attributes.antialias = true; ++ attributes.premultipliedAlpha = true; ++ attributes.preserveDrawingBuffer = true; ++ attributes.powerPreference = "default";// default ++ attributes.failIfMajorPerformanceCaveat=false; ++ attributes.majorVersion=2; ++ attributes.minorVersion=0; ++ attributes.enableExtenisonsByDefault=true; ++ attributes.explicitSwapControl=true; ++ attributes.renderViaOffscreenBackBuffer=false; ++ attributes.proxyContextToMainThread = 0; ++ ++ // Create the context and set it as current ++ self.GLctx = GL.createContext(canvas, attributes); ++ GL.currentContext = self.GLctx; ++ GL.makeContextCurrent(self.GLctx); ++ }, width, height); ++ wnd->handle.em_context = sys->context; ++ ++ // Implement egl routines: ++ gl->make_current = MakeCurrent; ++ gl->release_current = ReleaseCurrent; ++ gl->resize = Resize; ++ gl->swap = Swap; ++ gl->get_proc_address = GetProcAddress; ++ gl->destroy = Close; ++ ++ return VLC_SUCCESS; + error: +- Close(gl); +- return VLC_EGENERIC; ++ Close(gl); ++ return VLC_EGENERIC; + } + + /* + * Module descriptor + */ + vlc_module_begin() +- set_shortname(N_("Emscripten Window")) +- set_description(N_("Emscripten drawing area")) +- set_category(CAT_VIDEO) +- set_subcategory(SUBCAT_VIDEO_VOUT) +- set_capability("vout window", 10) +- set_callbacks(OpenWindow, NULL) +- +- add_submodule () +- set_shortname("Emscripten GL") +- set_description(N_("Emscripten extension for OpenGL")) +- set_category(CAT_VIDEO) +- set_subcategory(SUBCAT_VIDEO_VOUT) +- set_capability("opengl es2", 50) +- set_callback(Open) +- add_shortcut("em_webgl") ++ set_shortname(N_("Emscripten Window")) ++ set_description(N_("Emscripten drawing area")) ++ set_category(CAT_VIDEO) ++ set_subcategory(SUBCAT_VIDEO_VOUT) ++ set_capability("vout window", 10) ++ set_callbacks(OpenWindow, NULL) ++ ++ add_submodule () ++ set_shortname("Emscripten GL") ++ set_description(N_("Emscripten extension for OpenGL")) ++ set_category(CAT_VIDEO) ++ set_subcategory(SUBCAT_VIDEO_VOUT) ++ set_capability("opengl es2", 50) ++ set_callback(Open) ++ add_shortcut("em_webgl") + vlc_module_end() +- +diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c +index 9a7f8f786d..28cbd30620 100644 +--- a/src/video_output/video_output.c ++++ b/src/video_output/video_output.c +@@ -70,6 +70,9 @@ typedef struct vout_thread_sys_t + + bool dummy; + ++ vlc_video_context *my_ctx; ++ const vout_configuration_t *my_cfg; ++ + /* Splitter module if used */ + char *splitter_name; + +@@ -166,6 +169,8 @@ typedef struct vout_thread_sys_t + + } vout_thread_sys_t; + ++static void vout_DisableWindow(vout_thread_sys_t *sys); ++ + #define VOUT_THREAD_TO_SYS(vout) \ + container_of(vout, vout_thread_sys_t, obj.obj) + +@@ -1777,6 +1782,14 @@ static void *Thread(void *object) + vout_thread_sys_t *vout = object; + vout_thread_sys_t *sys = vout; + ++ if (vout_Start(vout, sys->my_ctx, sys->my_cfg)) ++ { ++ msg_Err(sys->my_cfg->vout, "video output display creation failed"); ++ video_format_Clean(&sys->original); ++ vout_DisableWindow(vout); ++ goto leave; ++ } ++ + vlc_tick_t deadline = VLC_TICK_INVALID; + bool wait = false; + +@@ -1808,6 +1821,7 @@ static void *Thread(void *object) + + vout_SetInterlacingState(&vout->obj, &sys->private, picture_interlaced); + } ++leave: (void *)0; // no-op + return NULL; + } + +@@ -1981,6 +1995,8 @@ vout_thread_t *vout_Create(vlc_object_t *object) + vout_thread_sys_t *sys = p_vout; + sys->dummy = false; + ++ vlc_sem_init(&sys->private.my_sem, 0); ++ + /* Register the VLC variable and callbacks. On the one hand, the variables + * must be ready early on because further initializations below depend on + * some of them. On the other hand, the callbacks depend on said +@@ -2180,11 +2196,15 @@ int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input + return -1; + } + atomic_store(&sys->control_is_terminated, false); ++ sys->my_ctx = vctx; ++ sys->my_cfg = cfg; ++ + if (vlc_clone(&sys->thread, Thread, vout, VLC_THREAD_PRIORITY_OUTPUT)) { + vout_ReleaseDisplay(vout); + vout_DisableWindow(vout); + return -1; + } ++ vlc_sem_wait(&sys->private.my_sem); + + if (input != NULL && sys->spu) + spu_Attach(sys->spu, input); +diff --git a/src/video_output/vout_private.h b/src/video_output/vout_private.h +index 5e8c58dabe..24965748ed 100644 +--- a/src/video_output/vout_private.h ++++ b/src/video_output/vout_private.h +@@ -41,6 +41,7 @@ struct vout_thread_private_t + + picture_pool_t *private_pool; + picture_pool_t *display_pool; ++ vlc_sem_t my_sem; + }; + + /* */ +diff --git a/src/video_output/vout_wrapper.c b/src/video_output/vout_wrapper.c +index 9d819f8a2d..9994aefc80 100644 +--- a/src/video_output/vout_wrapper.c ++++ b/src/video_output/vout_wrapper.c +@@ -74,6 +74,9 @@ vout_display_t *vout_OpenWrapper(vout_thread_t *vout, vout_thread_private_t *sys + modlist = "splitter,none"; + + vd = vout_display_New(VLC_OBJECT(vout), fmt, vctx, cfg, modlist, &owner); ++ ++ vlc_sem_post(&sys->my_sem); ++ + free(modlistbuf); + + if (vd == NULL) +-- +2.32.0 +