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.

No comments: