Case Study: Xan Video Codec

by Mike Melanson (mike at multimedia.cx)
Updated June 29, 2004

Xan is a reasonably simple video codec that can be decoded with a standalone Win32 DLL. It was used to compress video in AVI files in certain Origin computer games, most notably Wing Commander IV. It is used in this exercise because the output it generates will not be too large. The DLL, xanlib.dll, is available here. It weighs in at a mere 35 kilobytes. The sample AVI file used in this experiment is wc4trailer.avi, available from the sample URL as the DLL.

First, disassemble the DLL with scd:

scd xanlib.dll > xanlib.dll.txt
Next, run the scd-addresses.pl script on the output:
scd-addresses.pl < xanlib.dll.txt > xanlib-functions.txt
If you do not feel like performing the experiment, the xanlib-functions.txt file is here.

Next, it's time to gather execution data. Running Win32 code under Linux usually requires a complicated solution involving Wine. Fortunately, the specific decode functions needed to decode Xan data do not require any external Win32 functions. (Thanks to Mario Brito for determining how to use the DLL.) The DLL can be loaded directly into its linked address of 0x90001000. This simple program, loadxan.c, loads xanlib.dll and the first 2 frames of wc4trailer.avi. The first 2 frames are processed through the proper functions while address logging is enabled. Running this program results in ~27 megabytes of output data.

The key functions in xanlib.dll are DecompressXD() and DrawFrameXD(). It is interesting that DrawFrameXD() required the exact same number of instructions for both frames. The output from the sort-addresses.pl script is as follows:

*************************************************************************
Profile: xanlib.dll:DecompressXD(), frame #0
total addresses executed: 806833
*************************************************************************
(no name): 90003085 -> 900031D8, count = 409406 (50.7423469292902%)
(no name): 90004380 -> 900044A0, count = 326764 (40.4995829372373%)
(no name): 90002FB9 -> 90003084, count = 39744 (4.92592643087231%)
(no name): 900044A1 -> 9000459F, count = 30858 (3.82458327807613%)
DecompressXD: 90002DD0 -> 90002E5F, count = 38 (0.00470977265431632%)
(no name): 90001000 -> 9000102F, count = 24 (0.00297459325535768%)

*************************************************************************
Profile: xanlib.dll:DrawFrameXD(), frame #0
total addresses executed: 491383
*************************************************************************
(no name): 90002660 -> 9000288F, count = 491322 (99.9875860581257%)
DrawFrameXD: 90002E60 -> 90002FB8, count = 38 (0.00773327526593309%)
(no name): 90001000 -> 9000102F, count = 24 (0.00488417385216827%)

*************************************************************************
Profile: xanlib.dll:DecompressXD(), frame #1
total addresses executed: 907559
*************************************************************************
(no name): 90004380 -> 900044A0, count = 421543 (46.4479995239979%)
(no name): 90003085 -> 900031D8, count = 409406 (45.1106760001278%)
(no name): 90002FB9 -> 90003084, count = 39744 (4.37921942264911%)
(no name): 900044A1 -> 9000459F, count = 36805 (4.05538372711857%)
DecompressXD: 90002DD0 -> 90002E5F, count = 38 (0.00418705560740404%)
(no name): 90001000 -> 9000102F, count = 24 (0.00264445617309729%)

*************************************************************************
Profile: xanlib.dll:DrawFrameXD(), frame #1
total addresses executed: 491383
*************************************************************************
(no name): 90002660 -> 9000288F, count = 491322 (99.9875860581257%)
DrawFrameXD: 90002E60 -> 90002FB8, count = 38 (0.00773327526593309%)
(no name): 90001000 -> 9000102F, count = 24 (0.00488417385216827%)

Return to the main page