Skip to main content

hdmv-menus

A Blu-ray's HDMV menus, read straight from its files with nothing played: where each menu lives, every page and button (its place, its neighbours for the arrow keys, its pictures for each state, its commands), any page or button drawn as a picture, and what every button does: the disc's own programs run, as a player runs them, to the playlist a button plays or the page it turns to.

Written in Rust, with Python and C interfaces.

Python

pip install hdmv-menus            # (once published; for now: maturin build in crates/hdmv-menus-py)
import hdmv_menus

disc = hdmv_menus.Disc("E:/", aacs="C:/path/to/libaacs.dll")
for m in disc.menus():                             # [{"clip", "pid", "lang", "playlists"}]
    menu = disc.menu(m["clip"], m["pid"])
    for page in menu.pages:                        # plain dicts and lists
        menu.draw(page).to_pil().save("%s_page%d.png" % (m["clip"], page["id"]))   # (to_pil: Pillow)
        for button in menu.buttons(page):
            picture = menu.button_image(page, button, "selected")
    for link in disc.links(menu):                  # what each button does
        print(link["page"], link["button"], link["outcome"])   # {"kind": "play", "playlist": 83, "title": 25, ...}
        print(link.get("then", []))     # a button that plays: the playlists played after it, in turn
data = disc.to_dict()                              # everything but the pictures, ready for JSON

What a button does

links runs the disc's HDMV programs (sets, compares, jumps, calls) as a player would, and says where each button press leads: play (a playlist, and the title it's played in), page (another page of the menu, or another button on it), pop_up_off, resume, or link (within the playing playlist). A menu is pressed in the state the disc is in while it shows: the first play is run, each playlist it plays let play out (its warnings, logos), until a playlist carrying the menu starts; for a pop-up, that's the film. The player's own settings (language, region) are a typical English-language, region A player's, and can be changed. A title that runs Java (BD-J) is reported as such, not followed.

Menus inside menus: explore (--explore on the command line) finds every menu the disc can get to, and the way there: "first play > plays 00060 > 00072 page 2 button 35 > plays 00032 > plays 00117". A menu's buttons are pressed in the state it first showed in. Not yet followed: a menu carried in a film's own video that changes as the film plays (only its first is read, to spare reading the whole film).

Crawl plans

crawl(scope) (--crawl SCOPE on the command line) says what to look at, worked out from the disc's programs alone (no picture read, nothing played): the menus, what each button does, and for every title (playlist) the buttons that play it, best first. Best is one that starts the title from its beginning, on a page of such buttons (a list of extras rather than a film's scenes), in a menu reached sooner.

scope menus
titles those reached in the player's language that play a title: read each title's first button, and the next only if that reading fails
language every menu reached in the player's language
all every menu, in every language, reached or not
plan = disc.crawl("titles")
for t in plan["titles"]:
    best = t["buttons"][0]          # {"clip", "pid", "page", "button", "item", "mark"}

A decoded menu is kept by the disc, so asking for it again (or crawling again) costs nothing.

One wheel per platform works on Python 3.9 and every later version.

C (and anything that can call C: C++, C#, Go, Swift...)

cargo build --release -p hdmv-menus-c makes a shared library (hdmvmenus.dll / libhdmvmenus.so / libhdmvmenus.dylib) and a static one, with the header crates/hdmv-menus-c/include/hdmv_menus.h (made from the code on every build).

HdmvDisc *disc = hdmv_disc_open("E:/", "C:/path/to/libaacs.dll");   /* NULL: no decryption */
char *menus = hdmv_disc_menus_json(disc);                           /* JSON, as the CLI writes */
HdmvMenu *menu = hdmv_disc_menu(disc, "00072", 0x1400);
HdmvPicture *page = hdmv_menu_draw(menu, 0, -1, 0x00000000u);       /* RGBA, page->width x page->height */
/* ... */
hdmv_picture_free(page); hdmv_menu_free(menu); hdmv_string_free(menus); hdmv_disc_free(disc);

A call that fails returns NULL and leaves its reason in hdmv_last_error(); nothing it returns needs more than its own free function. See examples/c/list_menus.c.

Rust

cargo run --release --features cli -- E:/ --aacs "C:/path/to/libaacs.dll" --out menus

writes, for each menu stream, its data as JSON (menu_<clip>.json), every page drawn (<clip>_page<n>.png) and every button's own pictures (<clip>_p<page>_b<button>_<state>.png).

use std::path::Path;
use hdmv_menus::{aacs::Decryptor, Disc};

let root = Path::new("E:/");
let disc = Disc::open(root, Some(Box::new(Decryptor::new(Path::new("C:/path/to/libaacs.dll"), root)?)))?;
for stream in disc.menus()? {
    let menu = disc.menu(&stream.clip, stream.pid)?;
    for page in &menu.composition.pages {
        let picture = menu.draw(page, None, [0, 0, 0, 0]);    // RGBA
        for button in page.buttons() {
            println!("page {} button {} at {},{}: {:?}", page.id, button.id, button.x, button.y,
                     button.commands.iter().map(|c| c.to_string()).collect::<Vec<_>>());
        }
    }
}

Everything it returns can be serialized (serde), so JSON is one call away.

What it reads

File What it gives
BDMV/index.bdmv What each title, the first play and the top menu run
BDMV/MovieObject.bdmv The HDMV programs, each command decoded
BDMV/PLAYLIST/*.mpls Which playlists carry an interactive-graphics menu, and in which clip
BDMV/STREAM/*.m2ts The menu stream: palettes, pictures (the same run-length format as image subtitles) and the composition of pages and buttons

Commands are decoded, and run by the interpreter (vm) to link buttons to what they do.

Decryption

A commercial disc's clips are encrypted. This library ships, downloads and looks for no decryption library and handles no keys. To read an encrypted disc, point aacs::Decryptor at a libaacs-compatible library you already have (the aacs feature, on by default); it does its own work, as it would for any player. Or implement stream::Decrypt yourself. A decrypted copy of a disc needs nothing.

Layout

Folder What's there
crates/hdmv-menus The library, and the hdmv-menus command-line tool (--features cli)
crates/hdmv-menus-py The Python package (PyO3; built with maturin) and its tests
crates/hdmv-menus-c The C library and its header (include/hdmv_menus.h, generated)
examples/c A C program using it

Licence

MIT. See LICENSE.

Metadata

Release files for hdmv-menus 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hdmv-menus 0.1.1
File Size Uploaded Provenance Actions
hdmv_menus-0.1.1.tar.gz 46.1 kB With provenance Details for hdmv_menus-0.1.1.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for hdmv-menus 0.1.1
File Actions
hdmv_menus-0.1.1-cp39-abi3-win_arm64.whl CPython 3.9 abi3 Windows ARM64 Details for hdmv_menus-0.1.1-cp39-abi3-win_arm64.whl
hdmv_menus-0.1.1-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details for hdmv_menus-0.1.1-cp39-abi3-win_amd64.whl
hdmv_menus-0.1.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details for hdmv_menus-0.1.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
hdmv_menus-0.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details for hdmv_menus-0.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
hdmv_menus-0.1.1-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details for hdmv_menus-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
hdmv_menus-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details for hdmv_menus-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl

Total release size: 2.3 MB

Release files / hdmv_menus-0.1.1.tar.gz

Download URL hdmv_menus-0.1.1.tar.gz
Size 46.1 kB
Tags Source
SHA-256 checksum
How to use checksums
f5d480916d18c8c149fafd914af6cbd1cb48afc4a96c778b1a7460672b71afb9
BLAKE2b-256 checksum
How to use checksums
d9ca2913b03c28f61bb9ca38ab7cead702445d81192792314d1ddd7f9f64a116
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Release files / hdmv_menus-0.1.1-cp39-abi3-win_arm64.whl

Download URL hdmv_menus-0.1.1-cp39-abi3-win_arm64.whl
Size 292.6 kB
Tags CPython 3.9 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
7e3eca494ebe44194c440171a687e56ff5cc60b49fada07ee76ae5372ac6898c
BLAKE2b-256 checksum
How to use checksums
e7dc29161a3d58b94dab13da90b110ab39f64008c8e380991c5ab59e631c01c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Release files / hdmv_menus-0.1.1-cp39-abi3-win_amd64.whl

Download URL hdmv_menus-0.1.1-cp39-abi3-win_amd64.whl
Size 309.2 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
bd61aa1424aaf2fdad8e6335e9bcfdde9a0d80b3d73e19603b0dc56cbe79d84e
BLAKE2b-256 checksum
How to use checksums
75c66475be7c74d0ec1490465c97f7aad976432d93802cbc4284bf51909d9624
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Release files / hdmv_menus-0.1.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Download URL hdmv_menus-0.1.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Size 452.0 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
d4a487f9c5e95458ca175a36d4a9cd56b5bae03d3bcdab6c0e966b225bc11683
BLAKE2b-256 checksum
How to use checksums
c9a12ca8e3f06c5a792ca23f31015b10ce8f87ab1891b7fd64bdd7badb2e1e47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Release files / hdmv_menus-0.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl

Download URL hdmv_menus-0.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Size 437.8 kB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
2bb55ba3e5259097bfccc36308a1f7fdde9724e4ca61f45ba3c590b3a1f9ff9a
BLAKE2b-256 checksum
How to use checksums
19d40d555f1054eb7b467968a1ee8eff2f580c615f092ca7688b85f6845e04ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Release files / hdmv_menus-0.1.1-cp39-abi3-macosx_11_0_arm64.whl

Download URL hdmv_menus-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Size 394.9 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
62b168eacb0bf1d0b650852e279d3234dbd30f716d1b541b52d2d23509ba3171
BLAKE2b-256 checksum
How to use checksums
8c8a487fcfa6929ef581495df90de5f7f411872562f732e1c432a5e38a046de2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Release files / hdmv_menus-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl

Download URL hdmv_menus-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
Size 399.3 kB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
a41fa25f65740e704e5bb669bc3d51ce63fff98e43d2b83c07bfed3c00a7d9f3
BLAKE2b-256 checksum
How to use checksums
ad8611d8d69b5b92d39e66ca081aa15fbdff03ff40f66f1b49901e9ce42d43c6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Security for hdmv-menus 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 7 files in this release have been uploaded with provenance metadata.

Select from 7 files

Attestation for hdmv_menus-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

7 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page