Howto:anti-aliased menus and buttons with dvdauthor
From IVTV
started 26 July 2006
Most PC drawing packages work in square pixels. For example my display shows 1280x1024 pixels and measures 340x270mm so each of my pixels has a physical size of about 0.266x0.264mm. This gives a pixel aspect ratio ('PAR') of roughly 1:1 (340/1280 divided by 270/1024). Consequently if I use my drawing package to draw a square of 500x500 pixels it displays on my screen as very nearly undistorted square.
The same is not true for TV material, which uses non-square pixels. This means that DVD menus created on a PC can look distorted. Sometimes this doesn't matter but on other occasions you'll want things to be displayed exactly the way you drew them.
The effect isn't too noticeable for normal (4:3) TV. Such images have pixel dimensions of 720x576 (PAL) and display on TV screens that have a physical aspect ratio of 4:3. This gives a PAR of 1.067:1 (4/720 divided by 3/576). So a circle drawn on the PC will display as 6.7% wider than it is high, but most people won't notice such a relatively low level of distortion.
For widescreen (16:9) material the effect is much more pronounced. The images have the same pixel dimensions (720x576) but the TV stretches them out to fit the increased width. This gives a PAR of 1.422:1 (42% distortion) - which is definitely noticeable.
Therefore if you are producing widescreen DVD menus it is advisable to pre-distort them so that the text and graphics display as intended. Some drawing packages may be able to work directly in non-square pixels, but the simpler option is to work on a wider (or shorter) canvas and then re-scale the completed image to fit the required pixel dimensions.
The following tables give the correct canvas sizes for different aspect ratios. You can choose either option 'A' (an over-wide canvas which you shrink horizontally), or option 'B' (an under-height canvas that you stretch vertically). In general you may find that option 'B' is preferable for images that contain fine detail or text because stretching introduces less aliasing effects than shrinking, but try both ways and see which looks better to you.
PAL
| Aspect Ratio | PAR | Option A | Option B | Resize to |
|---|---|---|---|---|
| 4:3 | 1.067 | 768 x 576 | 720 x 540 | 720 x 576 |
| 16:9 | 1.422 | 1024 x 576 | 720 x 405 | 720 x 576 |
| 2.21:1 | 1.768 | 1273 x 576 | 720 x 326 | 720 x 576 |
NTSC
| Aspect Ratio | PAR | Option A | Option B | Resize to |
|---|---|---|---|---|
| 4:3 | 0.889 | 640 x 480 | 720 x 540 | 720 x 480 |
| 16:9 | 1.185 | 853 x 480 | 720 x 405 | 720 x 480 |
| 2.21:1 | 1.473 | 640 x 480 | 720 x 326 | 720 x 480 |
For example to create a menu for a PAL DVD that will be shown in widescreen (16:9) you might:
- use gimp to create a blank image of 720x405 pixels;
- draw your text and graphics;
- use image->scale image to resize it to 720x576 pixels; and then
- save it as a .PNG file ready to load into spumux.
1. capture mpeg clip to use as the intro - i.e. the short clip that plays before the menu comes up
Use v4l2-ctl to configure the driver to produce a dvdauthor compliant stream (e.g. see my howto), do cp /dev/video0 intro.mpg to capture the video, and then use gopchop to edit it.
2. capture mpeg clip which will form the menu background
same method as above
3. demux the menu clip into seperate audio and video files
tcextract -imenu_clip.mpg -tvob -a0 -xmp2 -d0 > menu_clip_audio.mp2 tcextract -imenu_clip.mpg -xmpeg2 -d0 > menu_clip_video.m2v [from ~/video_scripts/demux_ivtv.sh]
note: tcextract is part of the outstanding transcode package (available from [1]).
4. extract the menu video frames as a sequence of PPM images
mkdir menu_clip_frames transcode -imenu_video.m2v -o./menu_clip_frames/ -xmpeg2,null -yppm,null -Y0,10,6,12 -Z742x582
The -Y and -Z are to remove capture card border. Omit for clean material, e.g. that extracted from a DVD. Don't mess with --export_asr or --input_asr; transcode knows what it's doing.
[from ~/video_scripts/extract_ivtv_frames.sh]
5. make a template for the menu text
open any one of the menu clip frames using GIMP resize to either 720x480 or 1024x576 (see above) position guides as required to align text create layer 'background text' and add text that will be visible all the time create layer 'highlight text' and add text that will only be visible when a button is highlighted create layer 'highlight colour' and fill it completely with the highlight text colour position more guides at the corners of all buttons save as 'menu_stack.xcf' resize to 720x576 note the coordinates of all button corners save as 'menu_stack_resized.xcf' [to make text blurred, use 'create path from text' each time you use the text tool then stroke the path with brush circle fuzzy 09. When all text is done, merge visible layers then finish with 5 pixel gaussian blur]
6. overlay background text onto menu frames
open menu_stack_resized.xcf using GIMP
create a working copy [image->duplicate] and close original image
delete all layers except 'background text'
save as 'menu_overlay.xcf'
close image
open the first menu clip frame
use my 'animated gallery' plug-in to overlay menu_overlay.xcf to each frame [python-fu->alchemy->animated gallery]
set number of frames=0,
directory path=directory above 'menu_clip_frames',
Animation 1=menu_overlay.xcf (all others set to OFF)
output filename=menu_background_frames/000000.xcf
close and exit
[note: if there are a LOT of frames, do them in sections or GIMP will die]
7. assemble menu background frames into M2V video
cd menu_background_frames cat ./*.ppm | ppmtoy4m -v1 -F25:1 -A59:54 -Ip -S420mpeg2 | mpeg2enc -v1 -f8 -b9000 -V237 -F3 -a2 -q1 -g10 -G15 -Q0.0 -H -D10 -o ../menu_background_video.m2v [from ~/video_scripts/ppm-to-m2v.sh]
8. multiplex the audio back in
mplex -v1 -V -omenu_background.mpg -f8 menu_background.m2v menu_clip_audio.mp2
9. create custom GIMP palette (if not already present)
open GIMP open palette dialogue [file->dialogues->palettes] click 'new palette' button set name as '4 colour grey' set foreground colour to white click 'new colour from FG' button edit foreground colour to HTML AAAAAA click 'new colour from FG' button repeat for colours 555555 and finally 000000 click 'save palette' button
10. create anti-aliased 4 colour PNG images for buttons
open menu_stack_resized.xcf using GIMP create a working copy [image->duplicate] and close original image delete all layers except 'highlight text' decompose to RGBA [image->mode->decompose->rgba] delete the red, green and blue layers select the alpha layer open the 'convert to indexed' dialogue [image->mode->indexed] select 'use custom palette' click on the mini-palette icon and select '4 colour grey' palette select colour dithering 'none' click 'OK' convert back to greyscale [image->mode->greyscale] switch back to the un-decomposed image use 'undo' [ctrl-Z] to undelete the 'highlight colour' layer delete all other layers decompose to RGB [image->mode->decompose->RGB] close the un-decomposed image [no need to save] return to the image with the quantised alpha layer drag the 'alpha' layer from the layers dialogue and drop it onto the decomposed RGB image close the quantised alpha layer image [no need to save] re-compose the decomposed RGB image, with the new Alpha layer [image->mode->compose->RGBA] save as 'menu_highlight.png' [all 'save as PNG' options boxes should be unticked] close the composed image return to the 4-layer decomposed image fill the Red, Green and Blue layers with required colour for 'select' [normally all white] re-compose RGBA as above save as 'menu_select.png' close and exit
11. create XML file describing button positions
refer to the notes of the coordinates of the button corners on menu_stack_resized.xcf (720x576) create file buttons.xml, based on example below:
<subpictures>
<stream>
<spu
start="00:00:00.00"
transparent="000000"
highlight="menu_highlight.png"
select="menu_select.png"
force="yes"
>
<button name="1" x0="230" y0="400" x1="600" y1="452"/>
<button name="2" x0="230" y0="453" x1="600" y1="505"/>
<button name="3" x0="230" y0="506" x1="600" y1="557"/>
</spu>
</stream>
</subpictures>
12. multiplex buttons into background MPG
spumux -mdvd -v2 buttons.xml < menu_background.mpg > menu_with_buttons.mpg
13. create suitable dvd layout XML file
create file dvd_layout.xml, based on the following example:
<dvdauthor>
<vmgm>
<menus lang="EN">
<video format="pal" aspect="16:9"></video>
<audio format="mp2" lang="EN"></audio>
<pgc entry="title">
<vob file="intro.mpg" pause="1"></vob>
<post>jump titleset 1 menu;</post>
</pgc>
</menus>
</vmgm>
<titleset>
<menus>
<video format="pal" aspect="16:9"></video>
<audio format="mp2" lang="EN"></audio>
<pgc entry="root">
<vob file="menu_with_buttons.mpg"></vob>
<button name="1">jump title 1 chapter 1;</button>
<button name="2">jump title 2 chapter 1;</button>
<button name="3">jump title 3 chapter 1;</button>
<post>jump cell 1;</post>
</pgc>
</menus>
<titles>
<video format="pal" aspect="16:9"></video>
<audio format="mp2" lang="EN"></audio>
<pgc>
<vob file="clip1.mpg" chapters="0"></vob>
<post>call menu entry root;</post>
</pgc>
<pgc>
<vob file="clip2.mpg" chapters="0"></vob>
<post>call menu entry root;</post>
</pgc>
<pgc>
<vob file="clip1.mpg" chapters="0"></vob>
<post>call menu entry root;</post>
</pgc>
</titles>
</titleset>
</dvdauthor>
14. author the DVD
rm -r DVD dvdauthor -w -o DVD -x dvd_layout.xml
15. test the DVD image
xine dvd:/full/path/to/DVD
16. burn the DVD
sudo pkill hald [insert blank DVD-R] growisofs -Z /dev/dvd -dvd-video DVD [from ~/video_scripts/burn_dvd.sh]