Secret Ops FMV Patch and Tool Documentation





How to convert a movie for use within Secret Ops as FMV or comms


In this document, i'll explain step-by-step how to convert a movie for use in Secret Ops. Even if you never used any of the tools mentioned below, you should have no problem getting things to work.

Here is a list of tools you'll need:

- Secret Ops FMV Patch (unzip it to your Secret Ops directory)
- Secret Ops FMV Tool (to convert the movie to a format Secret Ops can read)
- Prophecy Audio Tool (audio compression)
- Virtual Dub (movie compression, audio extraction)

In order to be possible to play a movie within Secret Ops, your movie must be coded at 15 frames per second. The most usual movie size for FMV is 320x160, although for the resolution of 640x480 you can have movies up to 320x240, due to the movie interlace scheme Secret Ops uses. For best results, the movie dimensions must be multiple of 16. For in-flight comms, movie size must be 96x96.

If your movie has sound (helmet comms, for example, have sound coded separately, so you'll want to code movies with no sound) it must be PCM coded at 22050hz, 16-bit (stereo). No matter what you want to do, you'll need audio and video information as separate files (AVI and WAV), so if the movie you want to convert has audio, the first thing you'll need to do is separate the two: open the movie with Virtual Dub and in the File menu choose Save Wav.



Of course, if the resulting WAV isn't PCM coded at 22050hz, 16-bit stereo, you'll need to convert it to this format before proceeding. The easiest way to check is opening the WAV on the Windows Sound Recorder:



Now that you have the audio on a WAV file, open the Prophecy Audio Tool and compress it into a *.XA file. This phase may take some time (depending on the WAV size), so please be patient.



Now that you have a XA file, rename it to "in.xa". This file will be needed later. The next step is to save the movie data to an OpenDivX/DivX4 format. I believe that using any DivX4 DLL will do, however if you have problems i recommend that you replace DivX.dll (on your \windows\system directory) with the DLL that i'm supplying with the FMV patch.

Open Virtual Dub: under Audio select "No Audio" (the AVI you're about to save must not have any sound, even if the movie you want to play on WCSO has) and under video select "Full Processing Mode". Then go to Compression and select a DivX4 codec (preferably the one on the image below else choose another DivX4 codec, Divx3/Divx;-) won't work). Save an AVI named "in.avi"



Ok, now it's simple: you have a DivX4 movie file with no sound (in.avi) and possibly a sound file (in.xa, depending on wether the movie has sound or not). Unzip the Secret Ops FMV Tool and place the file(s) in.avi (and in.xa, if you have it) on the directory where the FMV Tool was unzipped. Then open a DOS window and run divx2wve:

divx2wve filename


where filename is the name of the two output files. One file will have the extension .divx, while the other will have the extension .wve: the WVE file will hold the audio data and "frame library" information, while the DIVX file holds the image frames. The filename above must be a 4-number name if you're coding FMV. This is necessary so you can call the movie from mission code with the function SYS_PlayMovie. For example:

SYS_PlayMovie(7000);


on ProphecyC or WCPPas script. If you're coding an in-game comm, you can name it whatever you like (8 characters is the maximum).

And that's it:) Now you have a movie you can play inside Secret Ops. You have to create a directory called divx\ on the Secret Ops directory, which will hold the *.divx files, and a directory called movie\ which will hold the *.WVE files. If you're making a in-game comm, you'll want to place the WVE file on ifcomms\ instead, and if it doesn't have sound (helmet comm) rename it to UV2 extension.

Have fun!:)




A short explaination of the patch


Basically, this patch is a DLL (divx_loader.dll) which intercepts a CALL instruction inside the Secret Ops EXE. The called instruction usually decompresses a movie frame, but by redirecting it to a function inside my DLL, i can do whatever i want. There, i load divx.dll through a LoadLibrary call, and get the procedure address of decore(), which is used to decode DivX frames whenever needed. My function within divx_loader is responsible for determining which function to call, either the DivX decore or the usual WCSO decoder.

To load divx_loader.dll, a bit of modding had to be made to the secret ops EXE: i had to add, with a hex editor, a simple call to LoadLibrary, where divx_loader.dll is loaded into memory. The divx_loader DLL itself is responsible for intercepting the decoder function, which means that the EXE patch is just a generic DLL loader and that the EXE can be re-used for a similar patch in the future.

Only one problem remained: the Prophecy/Secret Ops movie player (which also plays comms) wasn't guaranteed to decompress every frame: if you had frames 1-2-3-4-5-6, it was very possible that the player had to skip one or more frames (due to delays), which would cause, for example, that the frames 1-4-5-6 were played while 2 and 3 were skipped. This (obviously) works for Prophecy movies, since the algorithm doesn't keep state variables between frames (each frame has everything it needs). However, that's not the case for DivX, where if a single frame is skipped, you could get serious image distortion at best and crashes at worse. Also, the decoder is just fed the compressed data, which means it doesn't have frame count information that would allow to recover from skipped frames. So much for stuffing the pIQT chunks with DivX compressed data...

To solve this, i had to make sure pIQT frames had frame count information somewhere. Therefore, i simply made the pIQT chunks into what i called a "frame library": it holds a tag which distiguishes my pIQTs from usual pIQT chunks, and has a frame counter, along with the *.divx file name. This way, my routine can determine, for example, that if frame 49 was just played and WCSO is sending frame 52 for decoding, it'll need to decompress frames 50 and 51 before proceeding to 52.

Luckily, there are no slowdowns due to loading from 2 different files, which is very good, since i would have to dig deeper into the EXE otherwise;)


Mario "HCl" Brito
mbrito@student.dei.uc.pt