diff --git a/create_main.sh b/create_main.sh index 181d200408f71c4ce4c033357093a41d68c69bb8..5b41dafe46aae631a908b82e60b2e8a1f05ef409 100755 --- a/create_main.sh +++ b/create_main.sh @@ -40,7 +40,7 @@ emcc --bind -s USE_PTHREADS=1 -s TOTAL_MEMORY=2GB -s PTHREAD_POOL_SIZE=25 \ -s USE_WEBGL2=1 \ --profiling-funcs \ -s OFFSCREENCANVAS_SUPPORT=1 \ - -s MODULARIZE=1 -s EXPORT_NAME="initModule" \ + -s MODULARIZE=1 -s EXPORT_ES6=1 \ -s EXPORTED_RUNTIME_METHODS="[allocateUTF8, writeAsciiToMemory]" \ -s ASYNCIFY=1 -O3 \ -s EXIT_RUNTIME=1 -s ASSERTIONS=1 \ diff --git a/lib/libvlc.js b/lib/libvlc.js index 8aa8bff73f0d93e3411acc9b7e42e5214bef3159..ac98a858b48db145dd2c8cba035d9c3470204293 100644 --- a/lib/libvlc.js +++ b/lib/libvlc.js @@ -1,8 +1,19 @@ -// Encapsulate functions exported from exports_*.c +// Copyright 2021 - 2025, Videolabs and the Videolan contributors +// SPDX-License-Identifier: LGPL-2.0-or-later + +class InvalidRuntime extends Error { + constructor() { + super("LibVLC runtime is invalid"); + this.name = this.constructor.name; + } +} // Encapsulates libvlc_media_player_t export class MediaPlayer { constructor(module, path) { + if (module === undefined) + throw new InvalidRuntime; + this.module = module; this.media_player_ptr = module._wasm_media_player_new(); module._attach_update_events(this.media_player_ptr); @@ -214,10 +225,12 @@ export class MediaPlayer { } } - // Encapsulates libvlc_media_t export class Media { constructor(module, path, raw_ptr) { + if (module === undefined) + throw new InvalidRuntime; + if (raw_ptr != null) { this.module = module; this.media_ptr = raw_ptr; diff --git a/libvlc-loader.js b/libvlc-loader.js new file mode 100644 index 0000000000000000000000000000000000000000..52c80b8220e737704a5d2dc0236e9ef80ecd2e10 --- /dev/null +++ b/libvlc-loader.js @@ -0,0 +1,14 @@ +// Copyright 2025 - 2025, Videolabs and the Videolan contributors +// SPDX-License-Identifier: MIT + +export { MediaPlayer, Media } from "./lib/libvlc.js"; + +export async function initRuntime(ModuleExt) { + try { + const EmscriptenModule = await import('./experimental.js'); + return await EmscriptenModule.default(ModuleExt); + } catch (e) { + console.error(`Couldn't load libvlc runtime: ${e}`); + return undefined; + } +} diff --git a/vlc.html b/vlc.html index 0484682f4c82d86572b87b4d574d9a08cd10b34b..04f95a8c42555444bfc4dfdc9a1da9202dbc4c40 100644 --- a/vlc.html +++ b/vlc.html @@ -107,10 +107,9 @@ </div> </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"; + import { initRuntime, MediaPlayer } from "./libvlc-loader.js"; var vlc_options = ""; @@ -204,30 +203,24 @@ } }); - try { - // 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. - globalThis.Module = await initModule(VlcModuleExt); - createHandlers(); - localStorage.setItem('valid-options', options.value); - } catch (e) { - const validOptions = localStorage.getItem('valid-options'); - localStorage.setItem('options', validOptions); - window.location.reload(); + const Emscripten = await initRuntime(VlcModuleExt); + if (Emscripten !== undefined) { + createHandlers(Emscripten); + globalThis.Module = Emscripten; + } + else { + body.dispatchEvent(new CustomEvent('isLoading', { detail: { loading: false } })); } } - function createHandlers() { + function createHandlers(Emscripten) { 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'); + Emscripten.setStatus('Exception thrown, see JavaScript console'); // spinnerElement.style.display = 'none'; body.dispatchEvent(isNotLoading); - Module.setStatus = function(text) { - if (text) Module.printErr('[post-exception status] ' + text); + Emscripten.setStatus = function(text) { + if (text) Emscripten.printErr('[post-exception status] ' + text); }; }; @@ -236,7 +229,7 @@ for (var i=0; i < this.files.length; i++) { var name = this.files.item(i).name; console.log("opened file: ", name); - Module['vlc_access_file'][1] = this.files.item(i); + Emscripten['vlc_access_file'][1] = this.files.item(i); } globalThis.files = this.files; @@ -262,16 +255,16 @@ vlc_opts_size += vlc_opts_array[i].length + 1; } - var buffer = Module._malloc(vlc_opts_size); + var buffer = Emscripten._malloc(vlc_opts_size); var wrote_size = 0; for (let i in vlc_opts_array) { - Module.writeAsciiToMemory(vlc_opts_array[i], buffer + wrote_size, true); + Emscripten.writeAsciiToMemory(vlc_opts_array[i], buffer + wrote_size, true); wrote_size += vlc_opts_array[i].length + 1; } - var vlc_argv = Module._malloc(vlc_opts_array.length * 4 + 4); + var vlc_argv = Emscripten._malloc(vlc_opts_array.length * 4 + 4); var view_vlc_argv = new Uint32Array( - Module.wasmMemory.buffer, + Emscripten.wasmMemory.buffer, vlc_argv, vlc_opts_array.length ); @@ -282,13 +275,13 @@ wrote_size += vlc_opts_array[i].length + 1; } - Module._wasm_libvlc_init(vlc_opts_array.length, vlc_argv); - Module._free(vlc_argv); - Module._free(buffer); - media_player = new MediaPlayer(Module, "emjsfile://1"); + Emscripten._wasm_libvlc_init(vlc_opts_array.length, vlc_argv); + Emscripten._free(vlc_argv); + Emscripten._free(buffer); + media_player = new MediaPlayer(Emscripten, "emjsfile://1"); media_player.set_volume(80); - Module._set_global_media_player(media_player.media_player_ptr); + Emscripten._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;