Friday, August 04, 2006

Creating New Buttons for DVDStyler

In my never-ending quest to find cheap (read: free) software to use for desktop video, I stumbled across DVDStyler; a freeware DVD authoring package that runs on Windows, Mac, and Linux. It’s pretty full featured and allows you to do some things that the lower-end commercial packages won’t do, like have video clips for your menus instead of just still images.

DVDStyler is actually a graphical front-end for the dvdauthor package, which is itself a collection of command-line tools. DVDStyler won’t let you do anything those tools can’t do, but by providing an easy-to-use and flexible interface, it makes the DVD authoring process much more accessible.

Plus, DVDStyler comes with its own collection of background images and buttons, ready to drag-n-drop into your projects. If you want a different background image, it’s pretty easy: just make a 720x480 (for NTSC) or 720x576 (for PAL) jpeg image and import it. You can also easily use your own smaller images in conjunction with the “Frame” button for a custom look.

For more traditional functions, like navigation, DVDStyler has a set of pre-made arrows, and text boxes that you use. You can change their colors, set how they react to the remote, and so on.

But, if you want a real custom interface, you may want to make your own buttons, with your own design that will still have the capability of having unselected, highlighted, and selected states.

The DVDStyler manual doesn’t provide any guidance on making new buttons, but I’ve been able to puzzle out a few things and develop buttons that work just like the original set. Keep in mind, however, that I’ve worked this out myself and it isn’t in any way sanctioned by the developer. I may have missed some things and it may not work in future releases. But right now, at least, it does work.

The process is actually pretty simple, because the DVDStyler author had the intelligence and foresight to use industry standards like xml (eXtensible Mark-up Language) and svg (Scalable Vector Graphics) for external files rather than some proprietary format. That makes it easy to look at things, try out options and develop new material.

Each button is actually an xml file stored in the “buttons” directory of the main application. All you have to do to add a new button that will show up automatically in the DVDStyler button dock is drop a properly formatted file into this directory.

So, what’s properly formatted?

A button xml file consists of two main parts: the graphical definition of the button itself, defined by svg, and a set of parameters that are unique to DVDStyler and parsed by the application when the button is loaded. Of course, these parameters are defined in xml.

To make a new button, you first have to “draw” what it looks like. I’ve put “draw” in quotes because svg is a text-based language, meaning you could type out a definition in say, Notepad, and use that, without drawing any kind of graphic at all.

That works, (It’s how I did my first, simple button.) but it’s kind of a pain if you don’t know svg (or even if you do).

It’s much nicer to use a dedicated svg drawing package. There are a number of alternatives, but the one I like best is InkScape. It has more features that you’ll ever need, runs on lots of platforms, and, like all my tools, is freeware.

Since this isn’t an InkScape tutorial, I won’t go into the steps of creating the initial graphic. Instead, you can get a very simple .svg file from here. Right-click and "Save Target as..." to download it into the “buttons” directory of DVDStyler. (It may want to come down as an .xml file, which is OK, since that's what it needs to be anyway.) We’ll take this file and turn it into a DVDStyler button step by step. But, feel free to create and use your own graphic instead.

However, here are a few tips that will make the process a bit easier. They apply specifically to InkScape, but are useful no matter what package you use:

1) Set the document size to something reasonable for a button. I often use 160x120 pixels.
2) Name any element that you want to control in DVDStyler. It’s easier to work with “Box” than it is “rect1872”.
3) When you are ready to make the button, save a copy of your file as plain .svg and use that. You don’t need all the extra information that InkScape normally saves.

Once you have the .svg file in place, select it in the file list and hit F2 to rename. Change the extension from .svg to .xml. Windows will warn you about changing extensions, but just ignore it and hit the “Yes” button.

Now, right-click the file and open it with WordPad so you can do a little editing. You only need to add a single xml tag pair to the file to make it a valid button.

Before the opening <svg> tag, you need to add <button> and at the very end of the file you need to add </button>.
Also, although it isn't apparently required, but you might also want to add the sequence:
&#60Title>PutYourButtonNameHere<Title>
right after the <button> tag.

That’s it! Save the file and start up DVDStyler.

Double-click a Background image to add it to the screen and then click the Button tab. Scroll down, and you should see your new button. Drag it on to the screen. If you wanted to, you could link a video file to it, burn a disk, and your button would work.

There are a couple of limitations at this point, however.

For one thing, you can’t change the size of the button. You can drag the bounding box and it will resize, but the graphic won’t. Likewise, changing the size on the properties sheet doesn’t change the graphic size.

Secondly, you can’t change any visual properties. You’re stuck with whatever you had originally. Colors, opacity, stroke widths, are all fixed.

Finally, the button won’t visually react when it is selected or clicked. It works, but you can’t see it doing anything.

We’ll fix these problems one at a time. You’ll need to close and restart DVDStyler each time so that it can recognize the changes we’re making.

Making it resizable is easy. Open the button file in Wordpad again. Toward the top of the file you’ll see the main <svg> tag. It has a number of attributes embedded in it and we just need to add one.

If you’re using my file, the opening tag looks like this:

<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="160"
height="120"
id="svg2">

We’re going to add a “viewBox” attribute right after the “height” setting. Like this:

<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="160"
height="120"
viewBox=”0 0 160 120”
id="svg2">

I’m not going to go into detail about what the attribute does, but for us it provides scaling in DVDStyler. Make sure that the “B” is capitalized and set the last two numbers in the list to the width and height of the document.

Save the file and open DVDStyler. Now when you put your button on the screen you can change the size either by dragging the bounding box or by entering numbers into the properties sheet.

Now it’s time to give ourselves some control over other aspects of the button. This is the second part of the file that I mentioned earlier: the parameters.

Fortunately, this is pretty easy as well, thanks to DVDStyler’s use of xml. Simply add the right code to the button file and the proper controls will show up when you open the button’s properties sheet. Let’s start with some generalities, and then set up a few controls.

All the parameters for the button are defined in a block that resides between the closing </svg> tag and the closing </button> tag at the end of the file. This block starts with the <parameters> tag and ends with </parameters>. Within that block are the individual controls, delineated by <parameter> and </parameter>. These are what show up on the properties sheet. Virtually any element of a button can be controlled.

Each control has it’s own set of tag pairs:

<title> which is the name of the control on the properties sheet
<name> an internal control name which can be anything but must be unique in the button
<type> what kind of control it is: text, integer, string, image, or colour (note spelling)
<element> which part of the button the control affects
<attribute> the part of the element being controlled

The proper controls are created automatically based on the <type> tag. That is, a colour control has a color selection box, an integer control has a spinner, and so on.

There are some other tags, but we’ll discuss those later. For now, let’s just add a control allowing us to change the color of our circle button.

Open “Circle.xml” in WordPad and add the following block of code between the </svg> and </button> tags:

<parameters>
<parameter>
<title>Circle Color</title>
<name>c_color</name>
<type>colour</type>
<element>Circle</element>
<attribute>fill</attribute>
</parameter>
</parameters>

Restart DVDStyler and drag your button onto the screen. Double-click it open the properties sheet. If you’ve entered everything correctly you should have a new control that allows you to change the color of the circle to anything you want. If not, you made a typing error somewhere and need to go back and double-check everything.

All controls are created this same way: as a <parameter> block. Let’s add another control; this one will control the width of the outline around the circle.

Add the following code right before the closing </parameters> tag. Note that I said </parameters> and not </parameter>. There can be only one pair of <parameters> tags in a button, but there may be many <parameter> pairs.

<parameter>
<title>Outline Width</title>
<name>o_width</name>
<type>integer</type>
<element>Circle</element>
<attribute>stroke-width</attribute>
</parameter>

A couple of things to note here:

Firstly, DVDStyler created a new type of control; an integer box with a spinner attached, because you told it that you wanted an integer-type control. It stretches all the way across the sheet, but that’s normal and can’t be changed.

Secondly, we are controlling an aspect of the “Circle” element that isn’t explicitly named in the file. That is, there is no attribute for “stroke-width” shown in the svg definition (at least if you’re using my file). But a default is still created and can be manipulated. Consult a good svg reference to find out what all the attributes are.

Let’s do one more simple control. Add this code right before the closing </parameters> tag:

<parameter>
<title>Outline Opacity</title>
<name>o_opacity</name>
<type>string</type>
<element>Circle</element>
<attribute>stroke-opacity</attribute>
</parameter>

This one controls the transparency of the outline. You’ll need to increase the stroke width a bit to really see it. Note that this is string variable rather than an integer because opacity in svg ranges from 0 to 1.

You can continue in this manner, adding controls for stroke color and fill opacity if you want to. A more complex graphic might have more than one element in it and you could create a set of controls for that as well. We haven’t covered the text or image types, but they’re pretty self-explanatory, so play around with them a bit and look at the buttons that came with DVDStyler.

But even with all the controls we’ve added, our button still won’t react when it’s highlighted or selected with the remote. Let’s change that now.

Add the following block of code: (You should know by now where it goes.)

<parameter>
<title>Circle Color Change</title>
<name>c_changes</name>
<type>colour</type>
<element>Circle</element>
<attribute>fill</attribute>
<changeable />
</parameter>

It’s virtually the same as our first color change control with a different title and name and the addition of the <changeable/> singleton tag.

That one tag calls up a new set of three color controls, one each for Normal, Highlighted, and Selected. You can set these as you wish and now your button will react by changing color as it is accessed. As far as I know, only colors can be manipulated in this way; you can’t (for example) change stroke-width.

That’s just about it. There are some other parameter tags that you can experiment with like default-value, default-size, min-size, and init-parameter, but you don’t really need them to make fully functional buttons.

Take some time to look at the buttons that come with DVDStyler and you’ll see how they work. There are also some interesting things in some of the files about how to link two elements so that they can be managed with one control (text-shadow.xml) and how to use the image type (frame.xml).

Have fun, and let me know if you find out anything interesting.

Friday, July 28, 2006

Extended Video Playlists

I was going to start this blog off with a short, simple piece about something or other, but then I decided that since entries are likely to be few and far between (How do people do this every day?), I might as well put in something with some heft to it. With millions of people on the net each day there's surely somebody out there that doesn't think this is a waste of time.

-----

Over the years I’ve built up a large library of video programs that I’ve taped off the air. Recently, I’ve been engaged in moving some of them from VHS tape to the computer to save them before the originals deteriorate.

The problem is that I have a LOT of tapes. Several hundred, in fact; most taped in SLP. I don’t want to save all of them, but there are still dozens of programs that I do want to keep. And I’d like to be able to watch just portions of some of them. Maybe taking the commercials out. Or in some cases, being able to play just the commercials.

Ideally, I’d capture at a very high data rate, edit out what I want, and burn a bunch of DVD’s. Not gonna happen. For one thing, I don’t have enough storage space. I COULD capture at a rate of about 200 MB per minute which translates to about 6 gigs per half-hour program. Wouldn’t take long to fill my 250GB drive at that rate. Plus, that’s really overkill for SLP VHS originals. MPEG-1 is more than enough to capture the quality of the recordings.

But, MPEG-1 isn’t good for editing. You’ve already thrown away enough information that going through a decompression-edit-recompression cycle introduces significant quality loss, and takes a lot of time to boot.

Plus, you’re stuck with whatever you edit. Say I have a tape containing six hours of Halloween specials (and I do). I might like to capture all of them at once as a single file and re-sequence them in a particular order. Or I might like to just take a few favorite scenes and be able to watch those. I can do that by editing, but if I change my mind, I have to do it all again. The editing isn’t hard, but the time spent in doing it is significant.

One solution is on-the-fly editing, AKA playlists. That is, capture the original as MPEG-1, create a playlist that identifies the portions you’re interested in and just automatically step down through the list, loading and playing each scene in turn. Windows Media Player (WMP) can handle the playback, but its playlist function is pretty limited. It will let you create lists, but they only deal with complete files. There’s no way to tell it to play just part of a program.

Fortunately, there’s another way. We’ll add our own list capability to WMP. It takes a bit of work to set up initially, but it does give you complete freedom to choose what segments to watch, rearrange their order, mix scenes from different files, and create new lists simply by editing text files. And since it works directly from the original capture, there’s no need to edit, recompress, or save multiple copies of a single program. There’s only the MPEG-1 capture file and a few text files, which saves space as well.

Functionally, I’m going to provide you with a script that acts as a “wrapper” for WMP. It adds a new floating palette that allows you load a list of scenes and allows you to choose one to play from a dropdown menu. Since each scene can actually be a list of scenes, you can sequence things any way you want. The script is written using Auto-It, which is a terrific program control language, but you don’t need to know how to use it for this situation: I’ve provided an executable file that you just have to run like any other program.

You do need a few things to make this work, however.

First, you need a Windows machine. I’m not a platform zealot and I’m not saying you can’t do something similar on a Mac or Linux box. It’s just that I use (and like) Windows, so that’s what this technique works on.

You also need Windows Media Player installed in its default location. Since I’m providing the source code for the wrapper you could alter it to use something else without too much trouble, but that’s up to you.

You also need one other program. Fortunately, it’s so incredibly useful that you’ll want it anyway if you are doing any computer-based video work at all. It’s called “AviSynth”. It’s a freeware video scripting package that you can download from www.avisynth.org. I’m not going to go into detail about what it is or how it works here, but I’ll tell you enough so that you can use it for this application. For now, just install it.

You’ll also need my compiled script. You can download it here. Grab the source code, too, if you’re interested. It’s not well documented, but it’s so simple that you can probably figure it out. If not, just ask me.

There are a couple of other pieces of freeware that you might also want to get (I recommend it), but that aren’t absolutely necessary:

1) VirtualDub (www.virtualdub.org) – A great video manipulator with a wide range of uses.
2) AVSEdit (www.avisynth.org) - A nice editor for AviSynth scripts. You can get it on the same download page where you get the main AviSynth package.
3) Auto-It (www.autoitscript.com/autoit3/) – This is the scripting program I used to create the wrapper. You don’t need it to run my script, but if you want to make any changes to the source code, you’ll have to have it. It’s good to have anyway because it allows you to take control of just about any program. Very useful.

Ok. You have at least AviSynth installed and you have a video file that you want to use as a base for creating a scene list. Although I’m using MPEG-1 files, this technique works with any video that WMP can handle. There’s also no need to think “one video = one scene list”. One video can be used to create as many lists as you want and lists can hold scenes from multiple videos.

The first thing you need to do is to identify the scenes that you want to index. To do that, we’re going to write a very simple AviSynth script. It’s just three lines:

Clip1=DirectShowSource("YourFile.mpg”)
Clip1=Clip1.showframenumber(x=10,y=height(Clip1))
return Clip1

The first line is the only one you need to change. Just replace “YourFile.mpg” with the name of the video file you want to work with. You DO need to include the quotation marks. You can do this in Notepad or any other plain text editor. Just save it off in the same directory as your video clip using an appropriate name and make sure that it has an “.avs” extension. For example “Opener.avs”.

To test it, just drag the .avs file over the WMP icon in your taskbar and release it. It should just start playing. If you don’t have an icon, just launch WMP, chose “Open” from the file menu and select your .avs file. You’ll have to change the “Media Files” box to “Any File (*.*)” before the .avs will be visible.

When the file begins to play, you’ll see a set of numbers in the lower left corner of the video. These are the frame numbers for your video (put in by line 2 in the script). Move through the clip with the drawbar, noting the numbers that appear at the start and end of each segment you’re interested in. You’ll need these numbers later when we create our scene list. Write down the start/end pairs along with a short description of what they represent. e.g. “1374/2274 – Halloween Toy spot”.

An aside here: If you’ve also installed VirtualDub, you can reduce the script above to simply:

DirectShowSource("YourFile.mpg”)

Just save and open that in VirtualDub. VirtualDub already has a framecounter built in above the drawbar, so you don’t need to super the frame numbers with AviSynth. It’s also better at single-stepping through frames. If you’re going to be doing a lot of this, do it with VirtualDub; it’s just easier. In fact, if you are actually using MPEG-1 files, you can eliminate the script completely for this step. VirtualDub can directly open MPEG-1 video files.

At any rate, once you have the frame numbers for each segment, it’s time to write an AviSynth Script for each one. Don’t worry, though. They’re all virtually identical and very short. Here’s one:

DirectShowSource("YourFile.mpg”).Trim(1374,2274)

That’s it. Save it with a name like “Scene1.avs” in the same directory as the video file and open it in WMP. It should play just the portion between the start and end frame numbers. By the way, don’t worry about the filename at this point. You’ll add a descriptive name to the scene list, so the filename doesn’t need to be descriptive, as long as you know what file represents what scene.

Make a new .avs file for each scene, substituting the start and end frame numbers for each segment. Save them all with unique names in the directory with the video file. To make a script that plays the whole file, just leave off the “Trim()” portion of the command. e.g. DirectShowSource("YourFile.mpg”)

Once you’ve made all the files you want (at least for now) we can create the actual scene list that will appear in WMP. This, too, is very easy.

Fire up Notepad (or another text editor) and type:

[SCENES]
Play All= All.avs
Funny Scene=Scene1.avs
A Scary Surprise=Scene2.avs

Substituting, of course, your own descriptions and filenames.

When you’re done, save it in the directory with all the other files making sure it has a “.ini” extension. e.g; HalloweenVideo.ini

We’re done. All that remains is to fire up the wrapper script and try it out.

Double-click the “WMP_Scenes.exe” file that you downloaded from here. It should open a copy of Windows Media Player that looks entirely normal except for a new floating palette titled “Scenes” that has a “Load Scenes” button on it. The palette can’t be closed or minimized (unless you minimize WMP itself), but it can be moved freely anywhere on the screen. If you choose to view your video full-screen, the palette behaves nicely and disappears and will come back when you exit the full-screen mode.

Click the “Load Scenes” button and use the dialog box that pops up to navigate to your scene file. The box is set so that it only shows the appropriate filetype (*.ini). Double-click or choose “Open” to select the scene file. You’ll be returned to the main WMP screen with a new dropdown menu in the “Scenes” palette. Click to choose a scene. You’ll see WMP’s standard file open dialog box appear and the name of your chosen scene opening file will be automatically typed in for you. The box closes, and the scene starts to play. To play another one, just select it from the dropdown menu.

There is one small caveat, though. Sometimes, after a certain series of events, WMP won’t exit cleanly if a clip is playing or paused when you click the close button. The WMP window will go away, but the Scenes palette will remain. In addition, the WMP task is actually still running. The end result is that you will need to call up the Task Manger with CTRL+ALT+DELETE and kill the wmplayer.exe task. Until you do that, you won’t be able to play any more videos because the system thinks WMP is still running properly even though it has no visible elements. In short, stop any playing video before you exit WMP and you shouldn’t have any problems.

Before we wrap up I wanted to go back to a point I touched on earlier: a single scene entry can play more than one scene. For instance, you might want to simply remove all the commercials from a video. Or you might want to reorder sections. To do that, you simply add the scenes together in your AviSynth script.

Say, for example, that you have a compilation cartoon show that consists of three
shorts that you want to run back-to-back without the commercials. Your notes show the following times in the file “Toons.mpg”:

500/12200 – Bugs
15600/27300 – Daffy
30900/42600 – Porky

You could write a single scene entry that plays them all with an AviSynth script like this:

AllToons=DirectShowSource("Toons.mpg”)
Toon1=AllToons.Trim(500,12200)
Toon2=AllToons.Trim(15600,27300)
Toon3=AllToons.Trim(30900,42600)
Final=Toon1+Toon2+Toon3
Return Final

This is pretty straight-forward. We load the main clip, trim individual pieces out of it, and string them together. The names of the trims can be anything and they needn’t be defined in any order. I could just as easily written: Final=Toon3+Toon1+Toon2 and the clips would have played back in the new order. AviSynth is a very simple, yet very powerful language and a few minutes spent with the manual and some experimentation will really pay off. For example, I could have put dissolves between each cartoon, but I’ll let you figure out how to do that.

So, you can now add an entry to the “.ini” file that calls this script and it will play all the cartoons in order, with no commercials. Of course, that same file could have other scenes in it as well, like this:

[SCENES]
Bugs and the Vampire=Scene1.avs
Daffy and the Monster=Scene2.avs
Porky and the Leprechauns=Scene3.avs
Play All=Opener.avs
Play All (no Ads)=JustToons.avs

I think you get the idea by now.

To finish this up, you may have noticed that I kept harping on saving all the files in the same directory, but that isn’t absolutely necessary; it’s just easier. You can use fully-qualified paths in the individual scene files if you know the file locations won’t change. I’m never that certain, so I use relative paths.

My preferred way of structuring my collection is to create a new directory for each video and save everything there; the MPEG-1, all the scene (.avs) files, and the scene list (.ini). The .ini and .avs files do have to stay together, but they can reference video files in other directories. If I want to pull together a couple of clips from different directories I use standard dot notation to move up and down the file chain in the .avs files. In the examples below, “current directory” means the directory holding the .ini file.

Examples:

AllToons=DirectShowSource("Toons.mpg”) references a file in the current directory.

AllToons=DirectShowSource("..\Toons.mpg”) references a file in the directory above the current one

AllToons=DirectShowSource("\OtherToons\Toons.mpg”) references a file that is in a directory called “OtherToons” that is a sub-directory of the current directory

AllToons=DirectShowSource("..\MoreToons\Toons.mpg”) moves up one step on the file chain and then back down into a directory that exists at the same level as the current directory.

By using these rules you can mix and match scenes from any video on your system.

I’m no expert with Auto-It, so I’m sure there are faster, shorter, easier, and better ways to accomplish the same thing. That’s fine, but this does work and can be a starting point for more complex applications. Give it a try (it’s easier than it first appears) and let me know what you think.

Tuesday, June 27, 2006

Introduction

For quite some time now I have been toying with the idea of creating a blog as a place to share information about some my interests, but I had held off because of the amount of work required and the fact that I'm pretty sure that no one else is really interested in reading any of my ramblings.

However, since I work in instructional technology in higher education, I thought I had really better have some experience in using the technology. It's a chance to experiment a bit and see how I might be able to use this.

As such, this will be a pretty eclectic mix. I'll post some stuff about my work with small format video on a Windows machine, some discussions about my boardgame collection, and maybe a few things about animation, 3D, amusement parks, and a few of my other interests.