Navigate this BlogHome
Idealog AlliesWork In Progress (Chris)
Thursday, December 18, 2003
This week's program of the week is dvd.py, my dvd authoring program. It takes as input a python program written using special DVD authoring functions, and uses dvdauthor to produce a filesystem that can be burned to a DVD. This program takes care of producing the configuration files and movies that dvdauthor needs to have to produce the menus that go on a DVD.
This program is divided into two source files, which must both be placed in the same directory for it to work.
This week's program depends on the same tools as last week's, as well as a new program and a new library. The program we need is dvdauthor, which takes in an xml file and a series of movies and produces a DVD filesystem. It also depends on the Python Imaging Library (PIL), which lets python programs easily draw images.
The program takes as an argument a menu file, which is a python program that may call certain commands to build menus and add titles to a disk. It also takes two options: --fast produces only menus, and leaves the content in the current disk image alone, while --noencode does not encode any movies, but only adds new subtitles to existing ones.
Right now, dvd.py assumes that a file named background.mp2 exists in the current directory. It's used as the background music for menus. It must be in the right format for a DVD audio track (mp2-compressed, 48000 samples per second). I normally use silence, which you can get above.
The filesystem is left in the dvd/ subdirectory of the current directory. It needs to be burned to disk using a tool like growisofs, which is part of the dvd+rw-tools package. I use a command like:
growisofs -Z /dev/sr0 -dvd-video -m dvd/
The information needed to create a DVD is given to dvd.py through the use of a menu file, which is a python program. This program calls appropriate functions, which are then used to build up the menus and content on the DVD. Documentation for all the commands that can be used in the menu file is given at the link above. Please read that, as it has quite a bit of information that isn't duplicated here.
To illustrate it, let me walk through part of a menu file I wrote. The full file is given at the link above. It creates a DVD of fansubs of the anime series "Full Metal Panic? Fumoffu", one of the funniest series I've seen. (Read more about it here.) The menu looks like:
Going through the menu file line by line, we have:
This loads in a truetype font, and scales it to a height of 20 pixels. It is then set as the default font for the rest of the file.
This places a picture on the background of the current menu. The picture is automatically scaled to the correct size of 704x480.
This moves the drawing cursor to the location 75, 100. That's in the upper-left corner of the screen, which is also the upper-left corner of the first button in the menu picture given above.
This sets the default chapters for titles that do not define their own.
title('../DVD-Fummofu/001.mpg', chapters='0,11:40') label('Ep 1 - Ghillie, Kidnapping') title('../DVD-Fummofu/001b.mpg', chapters='0:00,1:30,11:12') label("Ep 1' - Bread, Lunch Break") title('../DVD-Fummofu/002.mpg') label('Ep 2 - Beach')
The bulk of a file is a series of title and label commands. The title command takes in a mpeg movie that goes on the DVD. It also has an optional chapter argument, that can be used to specify the chapter breaks on a per-title basis. (The third title command uses the default chapter breaks given above.)
The label command defines a button on the screen, and advances the cursor. When not used with an action, it takes the default action from the last command. When the last command was a title statement, the result is to play the new title.
Later on in the file, we have:
moveto(450, 100) label('Ch. 01 ', action='jump title 1 chapter 1;', cr=False) label("02' ", action='jump title 1 chapter 2;') label("Ch. 03' ", action='jump title 2 chapter 2;', cr=False) label("02 ", action='jump title 2 chapter 3;') label('Ch. 03 ', action='jump title 3 chapter 2;')
The moveto command here moves back up to the top, but this time on the right to start the second column. It then adds new labels to jump directly to the chapters. This example shows how action clauses can be used to jump to individual chapters on the DVD.
The second config file is one that uses python heavily to script the creation of the menu. While the Fumoffu file expressed 27 buttons in 101 lines of code, this file (for a DVD I made for Chris of the Star Wars Holiday Special) expresses a whopping 64 buttons in only 145 lines of code. It's also more complex, with many of the buttons in a grid pattern, which is used to create a keypad to protect the DVD from inadvertent viewing. (The holiday special _is_ that bad.)
The keypad is created using a state machine, where the current menu is used to express the given state.
I've already written alot about this program, so I won't talk much about the implementation. Basically, the way it works is that each of the commands produces an object which is placed on a list. Callbacks are then called on each of the objects to produce the menus and xml config files.
The callbacks are in dvdlib.py, while the driver code is in dvd.py. One thing that dvd.py does is to export only specified symbols into the environment that menu.py is called in. The use of a scripting language for a config file makes this version of the software much more powerful than the previous one, which used text files.
I'm not sure what I'll post next week. But I do have a couple of candidates, so I'll flip a coin to pick one.
Thanks to Tony for beta testing this script.
Commenting has been suspended due to spam.