Preview from BDMV folder so the BD-J menu Xlet actually loads

The disc structure, signed JAR, and video are all valid. The menu never
appeared because 'make run' opened the UDF .iso: libbluray's BD-J stack must
copy BDMV/JAR/00000.jar out of the image into /tmp/libbluray-bdj-cache before
the JVM can load it, and that write is refused by libbluray's BD-J
SecurityManager (usingUdf=true / no disc root). With no JAR mounted the Xlet
class isn't found (ClassNotFoundException: org.homebrew.MyXlet) and VLC falls
back to the raw playlist -> video, no menu.

Opening the build/disc BDMV folder instead lets libbluray read the JAR
directly, so the Xlet loads and the menu overlay runs. The ISO is still built
for burning; real players read the JAR from the disc filesystem directly.

- run-vlc.sh: default to build/disc, accept folder or .iso, add --bluray-menu
- Makefile: 'run' depends on the disc folder, not the ISO
- README: document the folder-vs-ISO libbluray caveat

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
happy 2026-08-25 14:57:31 -04:00
parent 9c88b8f7f6
commit 48c172cb80
3 changed files with 42 additions and 10 deletions

View file

@ -102,8 +102,11 @@ inspect: $(ISO_FILE)
bd_info $(ISO_FILE) bd_info $(ISO_FILE)
bd_list_titles $(ISO_FILE) -a bd_list_titles $(ISO_FILE) -a
run: bootstrap $(ISO_FILE) # Preview the menu straight from the BDMV folder. libbluray loads the BD-J Xlet
scripts/run-vlc.sh $(ISO_FILE) # from a folder but not from a UDF .iso on this setup (see scripts/run-vlc.sh),
# so `run` intentionally does not depend on the ISO.
run: bootstrap $(JAR_FILE)
scripts/run-vlc.sh $(DISC_DIR)
open: run open: run

View file

@ -29,13 +29,22 @@ The ISO is written to:
build/adjustments.iso build/adjustments.iso
``` ```
`make run` launches VLC through the Blu-ray access module, not as a generic `make run` previews the disc by pointing VLC's Blu-ray access module at the
media file: `build/disc` BDMV **folder**, not the ISO:
```sh ```sh
vlc bluray:///absolute/path/to/build/adjustments.iso vlc --bluray-menu bluray:///absolute/path/to/build/disc
``` ```
Why the folder and not the ISO: when libbluray opens a UDF `.iso`, its BD-J
runtime must copy `BDMV/JAR/00000.jar` out of the image into a temp cache dir
before the JVM can load it. On this setup that write is refused by libbluray's
BD-J `SecurityManager`, so the Xlet class is never found and VLC silently falls
back to playing the raw playlist with no menu. Reading the folder lets
libbluray load the JAR directly, so the menu Xlet runs. The ISO is still the
artifact you burn/distribute; real players read the JAR from the disc
filesystem directly and are unaffected.
The initial menu is a Java Xlet overlay with a few bonus-feature placeholders The initial menu is a Java Xlet overlay with a few bonus-feature placeholders
and a hidden menu stub. The actual generated video is a short ffmpeg SMPTE bars and a hidden menu stub. The actual generated video is a short ffmpeg SMPTE bars
pattern with AC-3 audio, authored as playlist `00000`. pattern with AC-3 audio, authored as playlist `00000`.

View file

@ -1,12 +1,28 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
ISO_PATH="${1:-build/adjustments.iso}"
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MISE_BIN="${MISE_BIN:-$HOME/.local/bin/mise}" MISE_BIN="${MISE_BIN:-$HOME/.local/bin/mise}"
if [[ ! -f "$ISO_PATH" ]]; then # Default to the on-disk BDMV folder, not the ISO.
echo "Missing ISO: $ISO_PATH" >&2 #
# When libbluray opens a UDF *image* (.iso), its BD-J stack must first copy
# BDMV/JAR/00000.jar out of the image into a temp cache dir. On this setup that
# write is refused by libbluray's BD-J SecurityManager (usingUdf=true, no disc
# root), so the JAR never mounts, the Xlet class is never found, and VLC falls
# back to playing the raw playlist with no menu. Opening the *folder* lets
# libbluray read the JAR directly, so the Xlet (menu) loads. Pass an explicit
# path to override (folder or .iso).
TARGET="${1:-$ROOT_DIR/build/disc}"
if [[ -d "$TARGET" && ! -d "$TARGET/BDMV" ]]; then
echo "Not a BDMV folder (no BDMV/ inside): $TARGET" >&2
echo "Run: make" >&2
exit 1
fi
if [[ ! -e "$TARGET" ]]; then
echo "Missing disc target: $TARGET" >&2
echo "Run: make" >&2 echo "Run: make" >&2
exit 1 exit 1
fi fi
@ -32,5 +48,9 @@ if [[ -d "$LOCAL_VLC_PLUGINS" ]]; then
export VLC_PLUGIN_PATH="$LOCAL_VLC_PLUGINS:/usr/lib/vlc/plugins${VLC_PLUGIN_PATH:+:$VLC_PLUGIN_PATH}" export VLC_PLUGIN_PATH="$LOCAL_VLC_PLUGINS:/usr/lib/vlc/plugins${VLC_PLUGIN_PATH:+:$VLC_PLUGIN_PATH}"
fi fi
ABS_ISO="$(cd "$(dirname "$ISO_PATH")" && pwd)/$(basename "$ISO_PATH")" if [[ -d "$TARGET" ]]; then
exec vlc --reset-plugins-cache "bluray://$ABS_ISO" ABS_TARGET="$(cd "$TARGET" && pwd)"
else
ABS_TARGET="$(cd "$(dirname "$TARGET")" && pwd)/$(basename "$TARGET")"
fi
exec vlc --reset-plugins-cache --bluray-menu "bluray://$ABS_TARGET"