bdmvkit
Blu-ray (BDMV) authoring in pure Python. bdmvkit writes the files a Blu-ray player navigates by:
- playlists with chapter marks (
.mpls); - clip information with the entry-point map players seek with (
.clpi); index.bdmvandMovieObject.bdmvwith HDMV navigation commands;- menus: Interactive Graphics streams with buttons, the arrow keys between them and the commands they run;
- PGS subtitle streams (
.sup).
It also encodes the clips with ffmpeg and x264, using the Blu-ray settings. There are no dependencies beyond the standard library, and ffmpeg is needed only to encode.
日本語の説明は README.ja.md にあります。
Status: 0.2. Titles with chapters, sound and subtitle tracks, and menus whose buttons start titles, chapters and other menus. Pop-up menus (over a playing title) and menus with motion or music come next; they already work in oncemore, where this code comes from.
Why
Open-source Blu-ray tools mux streams into a BDMV folder (tsMuxer, for one), but they stop short of the navigation layer: menus, movie objects, playlists and commands. bdmvkit writes that layer itself, and is tested by playing every disc back with libbluray.
Install
pip install bdmvkit
A release is made by the version: when the version in pyproject.toml
(and bdmvkit/__init__.py) reaches main without a tag of its own,
.github/workflows/release.yml runs the tests, builds the package, makes
the GitHub release with its tag and publishes to PyPI (trusted publishing,
environment pypi). Merging the version bump is all it takes.
Use
from bdmvkit import Disc
from bdmvkit.encode import encode_clip
encode_clip("feature.mov", "feature.m2ts", chapters=[0, 300, 600]) # key frames at the chapters
encode_clip("extras.mp4", "extras.m2ts", fps=(25, 1))
disc = Disc()
disc.add_title("feature.m2ts", chapters=[0, 300, 600], audio=[("ac3", 2, "en")])
disc.add_title("extras.m2ts", fps=(25, 1))
disc.write("out") # out/BDMV/...
A menu is a picture and its buttons. Each button is a picture of how it looks when selected (and, if given, when activated and before it is selected), placed on the 1920 x 1080 menu, and a link:
from bdmvkit import Disc, MenuButton
disc = Disc()
disc.add_title("feature.m2ts", chapters=[0, 300, 600], end="menu:main")
disc.add_menu("main", "menu.png", [
MenuButton("play", 160, 700, "play-lit.png", "play-on.png", action="title:1"),
MenuButton("scene2", 160, 800, "scene2-lit.png", action="chapter:1:2"),
])
disc.write("out")
Links are title:<n>, chapter:<n>:<c> and menu:<id>; a title's end
takes the same. The arrow keys go to the nearest button that way unless a
button's nav says ({"down": "scene2"}). bdmvkit.igs makes the button
stream on its own, for other tools.
bdmvkit encode feature.mov feature.m2ts --chapters 0,300,600
bdmvkit build disc.json out
disc.json looks like this:
{"titles": [{"clip": "feature.m2ts", "fps": "24000/1001", "chapters": [0, 300, 600],
"audio": [["ac3", 2, "en"]], "subtitles": ["ja"], "end": "menu:main"}],
"menus": [{"id": "main", "background": "menu.png",
"buttons": [{"id": "play", "x": 160, "y": 700, "selected": "play-lit.png",
"action": "title:1"}]}],
"play_all": true}
How the disc is laid out:
- Frame rates are 23.976 (1080p), 25 and 29.97. The last two are coded as progressive frames in a 1080i stream, as the format asks.
- Sound is AC-3, LPCM or DTS.
- Subtitles are PGS streams muxed into the clip.
pgs.write_supmakes them from pictures, andencode_clip(..., sups=[...])muxes them in. - First play and the Top Menu key open the first menu, or start title 1 when there is none.
- A menu is an interactive title after the titles: its picture held as a still, with its buttons as an Interactive Graphics stream in its clip. The menus are encoded when the disc is written (ffmpeg).
To make a disc image of the folder, use
udfkit (UDF 2.50):
udfkit bluray out disc.iso --label MY_DISC.
Tests
python -m unittest discover -s tests -t .
The tests encode real clips, write a disc, and read it back with libbluray, the library VLC, mpv and Kodi play Blu-ray with. They check:
- the titles and their lengths;
- the chapter positions;
- the video, audio and subtitle streams and their languages;
- that running the disc from first play reaches the titles and chapters in order;
- that a menu's buttons, chosen and pressed with the remote's keys, start the titles, chapters and menus they link to.
The files' fixed bytes are checked as well.
Support
bdmvkit is free and stays free. If it saves you time, you can support its development through GitHub Sponsors (the Sponsor button at the top of this repository). Bug reports help just as much: Issues.
The logo, colours and writing rules: docs/DESIGN.md.
License
GNU Lesser General Public License, version 3 or later. See COPYING.LESSER and COPYING. You may use bdmvkit in programs under any license. Changes to bdmvkit itself stay under the LGPL.
Metadata
Release files for bdmvkit 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bdmvkit-0.2.0.tar.gz | 47.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bdmvkit-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 91.2 kB
Release files / bdmvkit-0.2.0.tar.gz
| Download URL | bdmvkit-0.2.0.tar.gz |
|---|---|
| Size | 47.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a6f7e3329a3ad6908c646bdadfb77d2612064c792e5fbe257aa7a46b54297aa4
|
|
BLAKE2b-256 checksum How to use checksums |
a8342aace624dde77ad90d52a86fdacdce2f79d6e4a2a1d314cf094daa3394ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 12, 2026.
Transparency logRelease files / bdmvkit-0.2.0-py3-none-any.whl
| Download URL | bdmvkit-0.2.0-py3-none-any.whl |
|---|---|
| Size | 43.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d463e5528760235cbae0b3b8ed7d372e543f419ddb710184d7db2ba10cbe1434
|
|
BLAKE2b-256 checksum How to use checksums |
3c688b9bedd20a91a3f717c9e284277a94392745087ffe54de655cbc5d9ca0dc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 12, 2026.
Transparency log