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.0

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.0
File Size Uploaded Provenance Actions
hdmv_menus-0.1.0.tar.gz 45.9 kB With provenance Details for hdmv_menus-0.1.0.tar.gz

Built distributions (wheels)

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

Total release size: 2.3 MB

Release files / hdmv_menus-0.1.0.tar.gz

Download URL hdmv_menus-0.1.0.tar.gz
Size 45.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9da2b0442e122c89e12fb7305c473f5ab67144ce82bcd51615a70fb5f173eab9
BLAKE2b-256 checksum
How to use checksums
b00d7e3e7863c0ceee93aebe17442590f4ae188a5c1150c3a6310b7ffc009568
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 9, 2026.

Transparency log

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

Download URL hdmv_menus-0.1.0-cp39-abi3-win_arm64.whl
Size 292.6 kB
Tags CPython 3.9 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
bb2fe36b94e923ec873b0f34ee73ee4d52ab2932f96a173e374b975dfca07eb3
BLAKE2b-256 checksum
How to use checksums
e8666099419ba9f3a51b961f25bd7d10972e8927c7bd28b00f485c647196158b
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 9, 2026.

Transparency log

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

Download URL hdmv_menus-0.1.0-cp39-abi3-win_amd64.whl
Size 309.2 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
31e0b8fb549fa7c0eb0437ab2afb0f5058f507838c68ff1a09445b8e5c4427c3
BLAKE2b-256 checksum
How to use checksums
ee79c3a1d58951a5399f3246b1b360458a2c971c4ff97b61e29969a4ce249197
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 9, 2026.

Transparency log

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

Download URL hdmv_menus-0.1.0-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
e23d609e6a9df2e907817bc33059b6c6a76b5859c35afc19bd631900623660b1
BLAKE2b-256 checksum
How to use checksums
2b890f3eefa4083f5aebc77271a07f640a85e5122fed6fb90cd54e0aaed07855
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 9, 2026.

Transparency log

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

Download URL hdmv_menus-0.1.0-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
35ea79222372d7c0b6bf760c4feda710dd98598767f5efea9c15949e8f58f1ac
BLAKE2b-256 checksum
How to use checksums
e2d368632e04c391f2d101fffa1151e8f68586eed91c11fe0868eaf0c19f1b11
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 9, 2026.

Transparency log

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

Download URL hdmv_menus-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
Size 394.8 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
ffa142acca797a6e9786b97d752923899bcad40d5ef5fa69b081c82c1a4aaf3c
BLAKE2b-256 checksum
How to use checksums
d1555afaa6f6a25e2db163cf0d03c76c4870c2cee796a7f3cfb7cde08f9f084e
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 9, 2026.

Transparency log

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

Download URL hdmv_menus-0.1.0-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
7ebbeca68e8d111d3a6f33afe446a7699a8819dd0dc1605dcce6f3e68f061c21
BLAKE2b-256 checksum
How to use checksums
3afe160c1ee26ee1e9b07f252f75c95388a58bfc62c3776c50ada254a4fc0270
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 9, 2026.

Transparency log

Security for hdmv-menus 0.1.0

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.0.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 9, 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.0 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