193 lines
6.4 KiB
Plaintext
193 lines
6.4 KiB
Plaintext
|
Using AVIFile.
|
||
|
|
||
|
|
||
|
Initializing the AVIFile DLL:
|
||
|
Before using any of the APIs in AVIFILE.DLL, be sure to
|
||
|
call AVIStreamInit. After using them, call AVIStreamExit.
|
||
|
If you don't, bad things will happen.
|
||
|
|
||
|
|
||
|
Using AVIFile to read some kind of file:
|
||
|
|
||
|
First, call AVIFileOpen with the OF_READ flag to open the file.
|
||
|
Then, you can call AVIFileInfo to find out how many streams are in
|
||
|
the file, and AVIFileGetStream to retrieve the streams you want.
|
||
|
|
||
|
Once you have a stream, you can can AVIStreamReadFormat to get the
|
||
|
bitmap format or wave format, and then call AVIStreamRead to actually
|
||
|
read the data you want.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
AVIFile and the Component Object model:
|
||
|
|
||
|
The AVIFile APIs include two interfaces, IAVIFile and IAVIStream,
|
||
|
which work with the Component Object model which is part of OLE 2.0.
|
||
|
|
||
|
Class IDs
|
||
|
Each server or DLL that handles these interfaces needs to have a
|
||
|
Globally Unique ID (GUID), so that it can be distinguished from all
|
||
|
other handlers. OLE uses 16-byte identifiers for this purpose. If
|
||
|
you're making a new handler, you can run the UUIDGEN program to make
|
||
|
yourself a unique ID.
|
||
|
|
||
|
The Registration Database
|
||
|
The registration database is essentially just a replacement for .INI
|
||
|
files. To look at what's going on in it, run "regedit -v".
|
||
|
|
||
|
DLLs which implement the IAVIFile and IAVIStream interfaces all need
|
||
|
to be listed in the registration database so that they can be found
|
||
|
when necessary.
|
||
|
|
||
|
Each DLL must be listed in the registration database by class ID,
|
||
|
with entries of the form:
|
||
|
|
||
|
|
||
|
HKEY_CLASSES_ROOT\Clsid\{00020003-0000-0000-C000-000000000046} = Wave File reader/writer
|
||
|
HKEY_CLASSES_ROOT\Clsid\{00020003-0000-0000-C000-000000000046}\InprocServer = wavefile.dll
|
||
|
|
||
|
where HKEY_CLASSES_ROOT is the root of the entire registration
|
||
|
database. The InProcServer entry indicates that wavefile.dll can be
|
||
|
loaded within an application to implement the class in question.
|
||
|
|
||
|
The AVIFile library uses additional entries in the registration
|
||
|
database in order to know which handler to use by default to open a
|
||
|
given file. If the file is a RIFF file,
|
||
|
|
||
|
HKEY_CLASSES_ROOT\AVIFile\Extensions\WAV = {00020003-0000-0000-C000-000000000046}
|
||
|
HKEY_CLASSES_ROOT\AVIFile\RIFFHandlers\WAVE = {00020003-0000-0000-C000-000000000046}
|
||
|
|
||
|
You get a GUID by running the uuidgen.exe program that comes
|
||
|
with the SDK; it will spit out a 16-byte hex number for you. You then
|
||
|
make a file with a .REG extension that looks like:
|
||
|
REGEDIT
|
||
|
HKEY_CLASSES_ROOT\Clsid\{5C2B8200-E2C8-1068-B1CA-6066188C6002} = JFIF (JPEG) Files
|
||
|
HKEY_CLASSES_ROOT\Clsid\{5C2B8200-E2C8-1068-B1CA-6066188C6002}\InprocServer =jfiffile.dll
|
||
|
HKEY_CLASSES_ROOT\AVIFile\Extensions\JPG = {5C2B8200-E2C8-1068-B1CA-6066188C6002}
|
||
|
|
||
|
(Of course, use your GUID here.) Then, on a user's machine, they can run
|
||
|
regedit -s whatever.reg and these definitions will get added to the
|
||
|
registration database, allowing the system to find your DLL and know what
|
||
|
sorts of files it can load.
|
||
|
|
||
|
|
||
|
|
||
|
What are IAVIFile and IAVIStream?
|
||
|
(Note: you may just want to read the OLE 2 documentation here....)
|
||
|
|
||
|
These are examples of "interfaces". An interface is a collection of
|
||
|
"methods".
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Implementing a handler DLL
|
||
|
|
||
|
|
||
|
|
||
|
IClassFactory
|
||
|
Obviously, it isn't enough for OLE to know the name of your DLL; some
|
||
|
standard entry point is required to establish communications. The
|
||
|
method through which COMPOBJ.DLL does this isn't exactly
|
||
|
straightforward. A handler DLL must export a DllGetClassObject
|
||
|
function; COMPOBJ calls that function to ask the DLL to return an
|
||
|
instance of the IClassFactory interface, which it then uses to
|
||
|
actually acquire an instance of the IAVIFile interface that we
|
||
|
actually care about.
|
||
|
|
||
|
|
||
|
Single-stream vs. Multi-stream
|
||
|
AVI files obviously support more than one stream of data in each
|
||
|
file. Wave files, for example, are much simpler, in that they only
|
||
|
can have exactly one stream of audio. This means that we only need
|
||
|
one stream object around, and we can make things even simpler by
|
||
|
having the same object support both the stream and file interfaces.
|
||
|
|
||
|
If you know that your handler will support, say, exactly one audio
|
||
|
and one video stream, things are also simpler than the completely
|
||
|
general case, because when you create your file object, you know that
|
||
|
you will have to create exactly two stream objects.
|
||
|
|
||
|
|
||
|
Read-only vs. Read-write
|
||
|
|
||
|
A handler can be written which only supports reading or writing; you
|
||
|
can always return an error code from any method. (One suggestion:
|
||
|
don't return unsupported from the FindSample function, but rather
|
||
|
just return that every frame is a key frame, every frame is non-empty, and
|
||
|
that the only format change is frame 0)
|
||
|
|
||
|
|
||
|
Using C++
|
||
|
These handlers don't actually need to be implemented using C++; it
|
||
|
was just easier that way.
|
||
|
|
||
|
|
||
|
Installing your handler:
|
||
|
For your handler to be found, it needs to have the appropriate
|
||
|
entries in the registration database.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Compression DLLs
|
||
|
When you call AVIMakeCompressedStream, you pass in a PAVISTREAM and
|
||
|
are returned another PAVISTREAM. This new stream can be used in two
|
||
|
ways: either you can read from the stream, in which case you will
|
||
|
read data which is compressed from the original stream, or you can
|
||
|
write to the new stream, in which case the data you write will be
|
||
|
compressed and written to the original stream.
|
||
|
|
||
|
To use the "read" method, you would use the following sequence of
|
||
|
calls: (extra parameters left out because I can't remember them at
|
||
|
the moment)
|
||
|
AVIFileOpen(&pf, "foo.avi",...)
|
||
|
AVIFileGetStream(pf, &ps, ...)
|
||
|
AVIMakeCompressedStream(ps, &psC, &options, ...)
|
||
|
AVIStreamReadFormat(psC, lpFormatC, &cbFormatC) // get compressed format
|
||
|
for (loop through frames)
|
||
|
AVIStreamRead(psC, frame, ....) // read compressed frames
|
||
|
|
||
|
To use the "write" method:
|
||
|
AVIFileOpen(&pf, "foo.avi", OF_CREATE | OF_WRITE...)
|
||
|
AVIFileCreateStream(pf, &ps, &strhdr, ....)
|
||
|
AVIMakeCompressedStream(ps, &psU, &options, ...)
|
||
|
AVIStreamSetFormat(psU, lpFormatU, cbFormatU) // set format of data
|
||
|
// to compress
|
||
|
for (loop through frames)
|
||
|
AVIStreamWrite(psU, frame, ....) // write uncompressed frames,
|
||
|
// which will be compressed and
|
||
|
// written to the file
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Using the Clipboard functions
|
||
|
|
||
|
The clipboard functions are easy. To copy a bunch of streams to
|
||
|
the clipboard, call AVIMakeFileFromStreams to bundle them up into a
|
||
|
single PAVIFILE, then call AVIPutFileOnClipboard. To get data off of
|
||
|
the clipboard, call AVIGetFromClipboard. To see whether any data is
|
||
|
present on the clipboard, for enabling menus or such, you can just
|
||
|
call AVIGetFromClipboard to see if it returns anything, and release
|
||
|
any file it returns.
|
||
|
|
||
|
|
||
|
|