MPEG,
Windows and Director
|
|||||||||
by Al Hospers (1999/2000) MPEG playback in Director should be a piece-of-cake. Instead, it can be like wrestling a bear. The following article attempts to make it a little less painful. The OptionsCurrently the only MPEG solution for the Mac is Quicktime 4 . It supports MPEG with,from what I hear, good quality and a choice between half raster and full raster allowing for playback on slower machines. There is talk about an update for Quicktime 3 on Windows that promises MPEG playback, but as of this writing it does not seem to be available. So this is not a fully cross-platform solution. Keep your eyes open and ears to the Apple QT developer site for late breaking news. In Windows you have 2 options for playing native MPEG files: 1) purchase a MPEG dedicated 3rd party Xtra or 2) use a combination of MCI, ActiveMovie and the BudAPI Xtra (or possibly the old dllGlue Xobject) to get you the interactivity during playback that you need. Which of these solutions you choose depends on how much money you have available and how much you want to write code. I've always been a bit of a code-horse myself. Clearly the simplest solution is to purchase one of the available Xtras. The two I am aware of currently are:
Both work well and the support is good. Mauricio Piacentini, from Tabuleiro da Baiana, is often on Direct-L and has been very free with his advice, even to those using MCI. I have used OnStage for a project and their support was also good. They each have somewhat similar feature sets and licensing agreements and each also has upgrade paths to more powerful versions. You should check out their web sites for more information. A real plus for the MpegXtra is the fact that it uses Microsoft's new technology, DirectShow, to play. This is the technology of the future. MCI and DirectorYou should be aware that Microsoft is phasing out MCI. DirectShow is the technology that is taking its place. But if you still want to roll-your-own using MCI, for whatever reasons maybe you're a masochist, you will certainly learn a lot. First you will want to read Technote ID # 3521 at Macromedia Support. It gives you a lot of information about the various MCI related commands that are available to you. Right now it is the only documentation available on the web since Microsoft removed its references. Through MCI Director gives you quite a lot of control over the various media types that Windows deals with. You can use MCI to control MPEG video and audio, Wave audio and AVI files using Lingo. Second, you will need to make sure that your system is configured to use MCI. You will need to install the ActiveMovie drivers on your machine, and/or your target machine, if it is not already installed. The latest version of DirectShow (the new name for ActiveMovie) can be downloaded from Microsoft. There is a direct link to Microsoft's download page on the Tabulario site. If you are running Windows 98 and IE4 you might find yourself someplace else, but the end result should be the same. Most machines
shipped after November 1996 already contain these drivers. However some
older machines running Windows 95A, version number 4.00.950, may need
to be upgraded. You can actually use MCI itself to check and see if ActiveMovie
is installed. You can use the following Lingo to check: If this comes
up with something other than ActiveMovie, or if the test movie does not
play, you'll need to make sure that your WIN.INI file is configured properly.
Look for a line in the [mci extensions] section that looks like: If it says something like mpg=MpegVideo, then it is probably configured for a RealMagic driver. You might also see mpg=SoftPeg. This is for the SoftPeg software MPEG driver. In any event, you want to change it to ActiveMovie. You also want to look in the [mci] section and make sure you have a line: ActiveMovie=mciqtz.drv This is the driver that ActiveMovie uses to play your files. As Mauricio from Tabulario says, "This is the stuff that will give you headache and a lot of tech support calls, and one of the reasons Microsoft is now promoting the use of the ActiveMovie/DirectShow interface instead of MCI." Is it interactive yet Daddy?There is one last piece of this puzzle that you will need to deal with and that is interactivity. Director is a real HOG for CPU clock cycles. There is no way internally to tell it to back off, and this has a real effect on video playback. The 3rd party media playback Xtras like OnStage and DirectMedia both have some code inside that gives some extra priority to the media playback process, and takes a little away from Director itself. That way each gets what they need to perform properly. Without this you get either stuttering media playback, or you cannot do anything in Director until the media is finished. Both are pretty
unacceptable for most multimedia applications. Currently the only way
around this unless you have Director 7 is with the "baSleep"
command in the BuddyAPI Xtra. You can download
an evaluation copy that will allow you to use any 3 commands for FREE.
FWIW - I can almost guarantee you that there are over 3 commands in this
Swiss Army Knife of Xtras that you will find a use for. That's fair warning!
You can play with the values, but for this use a setting of 50 seems to
work well. And now, for some real CODEWhile it is easy to use MCI just by writing a few lines of code and attaching them to a button or a mouseUp event, that's really inefficient. The best way to work with something like MCI for ActiveMovie, or even Quicktime for that matter, is to wrap it up in an OOP layer. You know, an Object. That way, if you keep the same methods in a series of objects you use to play different media types you can play one of those other media types simply by replacing the object. If your Quicktime object has playMedia, stopMedia, pauseMedia and rewindMedia methods, and your ActiveMovie MCI object has the same AND you pass info into then in the same manner and you give them the same global variable reference they will be basically interchangeable. It's very cool, and very flexible. Try it, you'll love it! So, we're going to create an object that performs the following functions: on New me on PlayMedia
me on StopMedia
me on SearchToLocation
me It uses the actorList to activate the baSleep function when the media is playing and also to check to see if the movie is finished and rewind to the start if it does. We'll pass the full path and filename of our movie into the object as we instantiate it. We are going to use the BudApi Xtra to create a short file name from this path. The reason for this is that some machines, NT for one, choke on long filenames or ones containing spaces and will give you an MCI Error message. So why take a chance? (See, I told you we couldn't use just one function!) We're also going to pass in the location on the stage that we want to place the MPEG and its size using a list consisting of the MovieTop, MovieLeft, MovieWidth and MovieHeight parameters in pixels. All this makes the object a lot more flexible. Here is the code we'll put in the startMovie handler to set things up: set
mediaPath = the moviePath & "test.mpg" This code assumes a movie stage size of 320 x 240, requires an MPEG video in the same path as the movie and named "test.mpg", and creates a list that gets passed into the object to position the video on the screen. Now let's look at the "on new me" handler. I've commented almost every line: on new me, mediaPath, ScreenLocList
-- make the short file name
set mediaPath = baShortFileName(mediaPath )
-- setup the video position values
setMovieWindowLoc me, ScreenLocList
-- the video window is going to be
-- a child of the stage
set MovieStyle = "child"
-- get the window handle of the stage
set hWinStage = baStageHandle()
-- open the file
mci "open " & mediaPath && "alias" && "myMovie" ¬
&& "style" && MovieStyle && "parent" ¬
&& string(hWinStage)
-- position the video window mci "put" && "myMovie" ¬
&& "window at" && MovieLeft ¬
&& MovieTop && MovieWidth && MovieHeight
-- a little error checking is a good thing
mci "status myMovie mode"
set mciStatus = the Result
if mciStatus contains "MCI Error: " then
set errorMessage = "Movie not loaded due to - ¬ "
& the result alert errorMessage HALT
end if
-- set the correct time format for the video
mci "set myMovie time format milliseconds"
-- we need the length so we can rewind at the end
set MediaLength = getMediaLength()
-- put the object into the actorList, check
-- out the "on stepFrame" handler
add the actorList me
-- pass a global reference to the object
-- back to the movie
return me
end
Have a good look at the way the MCI commands are built to open the video and then position it on the screen. Notice that all MCI commands are strings. Later you may want to step through this using the Debugger. Next here's the stepFrame handler that gets executed on every exitFrame, but is completely contained in the object.
on stepFrame me
if playStatus = TRUE then baSleep (50)
endOfMediaCallback
end
The playStatus property is set when we press the Play or Stop buttons. Notice that the baSleep command is only executed if the playStatus is TRUE. After all, it is unnecessary if the video is not playing! Here is the handler that checks to see if the movie has gotten to the end. We check the position by using the MCI "status" command. If we are at the end, we make sure that we pause the video and then use the searchToMediaPosition handler to go back to the start.
on endOfMediaCallback me
mci "status myMovie position"
if the result > (MediaLength - 1) then
-- pause the video
pauseMedia me
-- rewind to the beginning
SearchToMediaPosition me, 0
end if
end
We've created play and pause handlers that we drop onto a button in the score. Each contains an MCI command and sets the current playStatus flag appropriately. When you create these handlers make sure that they are Score Scripts. Here is the pauseMedia handler:
on pauseMedia me
set playStatus = FALSE
mci "pause myMovie"
end
The playMedia handler looks almost identical. Last here is the code in the killObject handler which is executed by the stopMovie handler.
on killObject me
deleteOne (the actorList, me )
mci "close myMovie"
set me = VOID
end
It is important when working with the actorList to make sure that you remove objects from it when you are done. You'll notice that we explicitly close the video and VOID out the object reference. This is all good programming practice. Also, if you try to open a new movie without explicitly closing the movie alias you already have open, you will get an MCI Error. So get it, and get with it!So there you have it. There are a few other handlers, but you can look through the code in the example movie for yourself. The example movie (PC format only), contains all you will need to get started. You might think about adding other MCI commands that you find in the Macromedia Technote quoted above to the object. All of this could be rolled into a behavior that could be attached to a button on the stage. There are a lot of possibilities, even make your own Media Player! Give them a try and have fun. MCI is a powerful tool that will open up your programming capabilities. Also, remember, this is just a demo. You may find various anomalies on different machines that I have not personally tested it on. This code is provided to you as-is, with absolutely no warrenties of any kind and WE ARE UNABLE TO PROVIDE FREE SUPPORT. Additional on-line resourcesHere are some resources on the web that you should definitely check out: MPEG.ORG You might also want to visit our Links page for possible additional pointers. Credits
Peter Small
Gary Smith Thanks guys. <grin> |