Multimedia I/O ProceduresWritten by Lachlan O'Dea
This is an article about I/O procedures, a small part of OS/2's large and complex multimedia system. I became interested in I/O procedures (hereafter known as IOProcs) as a means for reading, writing and displaying PNG images. PNG is a graphics file format similar to GIF and is pronounced 'ping'.
At first I planned on writing my own PM program for viewing PNG files, and actually developed a basic PNG viewer. I can't recall exactly how I got the idea of using an IOProc, but after reading the relevant information in the Toolkit docs I decided that writing an IOProc would be both an easier and superior approach.
I plan to write two articles about IOProcs. This article shall deal with IOProcs in general: what they are for, how they work and where they fit into the OS/2 multimedia system. The second article will be about the implementation of PNGIOProc, my own IOProc which reads and writes PNG images.
Please note that I am not an expert on this subject. What knowledge I have comes from reading the documentation in the Warp Toolkit and writing my own IOProc. I hope people find this article useful.
Before getting into the details of IOProcs, I'll briefly describe the multimedia subsystems and how they relate to each other and the OS/2 multimedia system in general.
The Multimedia Subsystem
The OS/2 multimedia system was designed with an extensible architecture, which allows developers to add support for new functions, multimedia devices and multimedia data formats. This extensible architecture is achieved through multimedia subsystems which can be installed to provide new functionality. There are three types of subsystems, each controlled by a manager.
Media Control Drivers
A Media Control Driver (MCD) provides access to the features of a multimedia device. Such devices include CD audio, digital video and the amplifier/mixer. To add support for a new media device, you must write an MCD to support that device. MCDs do not communicate directly with the hardware, instead they send commands to a physical device driver or use the other multimedia subsystems, such as the stream programming interface.
The various MCDs on the system are controlled by the Media Device Manager (MDM). Multimedia applications access the features of the MCDs through the MDM. When a process tries to access a device, the MDM makes sure that it does not interfere with other processes which might be using the device. The MDM also allows an application to synchronize the use of two or more devices.
Stream handlers are used for providing a continuous flow of multimedia data in a real-time manner. Typical use of stream handlers are digital audio, MIDI, and video. Stream handlers can run at ring 0 as a physical device driver or at ring 3 as a dynamic link library, depending on whether the stream handler needs to directly access the device. Stream handlers can make use of CODECs and I/O Procedures if desired.
The Synchronization and Streaming Manager (SSM) coordinates and synchronizes stream handlers. The SSM provides the stream programming interface (SPI) to higher- level multimedia components such as MCDs while providing helper services to both ring 0 and ring 3 stream handlers. The SSM also provides the synchronization features essential to multimedia applications.
IOProcs are used by the Multimedia I/O (MMIO) Manager to access multimedia data stored as a file. Although the term 'file' is used, IOProcs can be written to support storage mechanisms other than the standard file system, such as memory files.
The services of the MMIO manager can be used by applications or other parts of the multimedia system whenever they need to manipulate data as a file. Much of the MMIO API (mmioOpen, mmioRead, mmioClose) mimics the standard Dos API, but there are many extra features related to multimedia. An application uses the MMIO API by calling mmioOpen, which returns a handle to the 'file' (such handles are typically named with the prefix hmmio). This MMIO file handle is then used in all subsequent operations on the file, until the file is closed. While a MMIO handle is used in a similar way to a standard OS/2 file handle, they are not interchangeable.
The MMIO Manager also provides other services in the form of CODECs, or COmpressors/DECompressors. A CODEC is basically used to take a buffer full of data and either compress it or decompress it. If you want to support a new method of compression (perhaps a new type of AVI) then you can install a new CODEC which handles that compression method. CODECs can be used by IOProcs, applications or other parts of the multimedia system. Internally, CODECs have a similar architecture to that of IOProcs.
The remainder of this article will cover I/O Procedures in detail.
Inside I/O Procedures
Four character codes (FOURCCs)
IOProcs (and CODECs) are identified within the MMIO system by a 32 bit quantity usually represented as a sequence of four characters. These four character sequences are called four character codes and have a data type of FOURCC. This is a much more convenient method of identification of IOProcs than the string holding the NLS name of the procedure.
Functions exist for manipulating FOURCCs, such as mmioFOURCC which makes a FOURCC out of four separate characters. A FOURCC can contain less than four characters, in which case it is padded on the right by spaces. The first character is placed into lowest byte of the 32 bits and the last character is placed in the highest byte.
FOURCCs are also used in other parts of the multimedia system, such as chunk IDs in RIFF files.
Storage System IOProcs
These process data which has a particular method of storage. Storage system IOProcs have no knowledge of the format of the data they are reading; they operate only on the storage mechanism used, not the actual data which is stored.
There are three storage system IOProcs which are provided internally by MMIO:
Note that these IOProcs don't care what kind of data they are being used to store; it could be audio, video, image or any other kind of multimedia data. For example, the DOS IOProc can be used to read both WAV and AVI files from a hard disk, but it won't translate the data in any way.
So why use a storage system IOProc to read a file when you could just use the standard Dos filesystem services? Because the Dos functions only work for files stored via the filesystem, whereas the MMIO functions provide a consistent interface for all storage mechanisms (a feature taken advantage of in file format IOProcs). New storage mechanisms can be easily supported by installing a new storage system IOProc.
Storage system IOProcs can be used by applications, as well as file format IOProcs.
File Format IOProcs
A file format IOProc processes multimedia data which is in a specific format. OS/2 comes with several standard file format IOProcs including WAVE, MIDI and AVI. My PNGIOProc example is a file format IOProc, as is the MMIOPROC sample in the Warp Toolkit. PNGIOProc supports files which are in the PNG format, whereas MMIOPROC supports files which are in the M-Motion still video format.
File format IOProcs perform all I/O using storage system IOProcs. This is where we see the advantage of using storage system IOProcs instead of more direct methods. As a file format IOProc uses a storage system IOProc to perform I/O, the file format IOProc doesn't care where or how the data is stored, it only cares what format the data is in. A file format IOProc can therefore access data using any mechanism which is supported by a storage system IOProc.
The file format supported by an IOProc must be of a particular media type, such as audio, image or video.
Translated or untranslated?
File format IOProcs have two modes of operation: translated and untranslated. Translation can be applied to the header and/or the data of the file. An IOProc can support both translated and untranslated modes if desired.
The PNGIOProc example operates only in translated mode for both the header and the image data. Translation involves converting the native format of the data to and from one of OS/2*s standard formats. This allows multimedia applications to read and write data without knowing anything about the format it is stored in - they only need to know about the standard OS/2 formats.
This is how the image viewer that comes with the Bonus Pack works (IB.EXE - it is used by the light table to display images). When the user asks to view an image, MMIO determines which IOProc must be used. The file is then opened in translation mode and the IOProc converts the image to one OS/2's four standard bitmap formats, which the viewer application knows how to display.
Similarly, the Multimedia Data Converter (located in the Multimedia folder on the desktop) uses translation to convert images and digital audio to other formats. For example, a GIF image can be translated into a standard OS/2 bitmap by a GIF IOProc and then a PCX IOProc can be used to write the bitmap out as a PCX image. If you install PNGIOProc, the Multimedia Data Converter will be able to convert PNG to and from any other image format with an IOProc.
The main disadvantage of translation is that you are limited by OS/2's standard formats. If you convert a GIF to an OS/2 bitmap and then to a PNG, you lose any transparency information on the way, even though both GIF and PNG support transparency. Also, as PNGIOProc shows, the restrictions placed by the standard formats can make the translation process quite inefficient.
Each media type has a set of possible standard formats which an IOProc can translate to. For a media type of 'image', there are four OS/2 1.3 bitmap formats which can be used; for a media type of 'audio', three PCM formats can be used.
It also possible for an IOProc to operate in untranslated mode. Some of the multimedia documentation doesn't seem to make much sense when describing untranslated mode. For example, the Multimedia Subsystem Programming Guide has the following:
The default mode of access, untranslated, allows the caller to perform I/O of the file data in its native format. All header information and any data is written to a file and read from a file and presented at the caller level without modification.
To me, this seems to be saying that the IOProc simply passes data along without modifying it in any way. Why not just use the storage system IOProc directly? I'm still not sure what untranslated mode is useful for.
Untranslated mode has the disadvantage that applications have to be written for specific IOProcs - the application must understand the format-specific data that the IOProc returns. The advantage is that you are not limited by OS/2's standard formats and can use all the features available. For example, reading a PNG image in untranslated mode would allow for a progressive display using interlacing, but this is not possible using translated mode. Also, it is possible to do better and more efficient conversion to other (non-standard) formats.
IOProc Message Handling
An IOProc is basically a single procedure which processes MMIO messages. There are pre-defined messages, as well as user-defined messages which are specific to an application. Which pre-defined messages an IOProc must support depends on the type of the IOProc and what its capabilities are. Some messages must be supported by all IOProcs, however.
If an IOProc doesn't know how to handle a message, it must either pass the message to the child IOProc (if one exists) or return an error code. A child IOProc is the storage system IOProc which a file format IOProc is using to do I/O.
An IOProc is packaged in a DLL and accessed via a single function entry point:
LONG IOProc_Entry( PVOID pmmioStruct, USHORT usMsg, LONG lParam1, LONG lParam2 )Figure 1) IOProc entrypoint prototype
Refer to the Multimedia Programming Reference for the complete details of all the MMIO messages.
Implementing a new IOProc basically involves writing an IOProc entry function which correctly handles all the required MMIO messages. Next month I will discuss in detail each of the messages handled by PNGIOProc.
Installing I/O Procedures
An IOProc can be installed to process a particular file by calling mmioOpen with the address of the IOProc entry point. This has the effect of over-riding the default IOProc with the one the application wants. Once the file is closed, the IOProc will not be used again unless its address is passed in another call of mmioOpen.
To specify the IOProc to mmioOpen, store the address of the entry point in the pIOProc field of the MMIOINFO structure. Set the fccIOProc field to 0.
When using this method, the IOProc doesn't need to reside in a DLL. Naturally, a DLL must be used if the IOProc is to be used by multiple programs. Also, the entry point address can be resolved either at load-time or run-time.
This method of installation uses the mmioInstallIOProc function which basically installs the IOProc for use by the current process. A list of installed IOProcs is kept for each process which uses MMIO functions. mmioInstallIOProc can be used to add to and remove from this list, as well as find a particular IOProc in the list.
As this function only affects the process which calls it, different processes can install different IOProcs with the same FOURCC without interfering with each other. If an IOProc is in a DLL to be shared by multiple applications, then each application must call mmioInstallIOProc before it can use the IOProc.
Once an application has called mmioInstallIOProc, the IOProc is automatically available for use by all subsequent calls to mmioOpen within that application.
An IOProc can be installed so that it is permanently available to all applications as soon as the system is started. This is done by placing the required information about the IOProc in the MMIO initialization file (MMPMMMIO.INI). An IOProc installed in this way is automatically available to any application that wants to use it; calling mmioInstallIOProc is not required.
This method of installation is really the only way you can take advantage of translation in IOProcs. It is also useful for untranslated IOProcs, however. When using this installation method, the IOProc must be in a DLL. Multiple IOProcs can reside in the same DLL, provided they each have a different name for their entry point function.
The IOProc information can be added to the INI file by calling mmioIniFileHandler with the flag MMIO_INSTALLPROC specified. An MMINIFILEINFO structure must also be passed containing the following information.
mmioIniFileHandler may also be called to remove an IOProc, or to find an IOProc with particular characteristics.
The Multimedia Install Program
If you want to permanently install an IOProc on a user's system, it is probably more convenient to use the Multimedia Install Program (MINSTALL) rather than write your own program which calls mmioIniFileHandler. MINSTALL uses things called 'control files' which enable you to make appropriate changes to CONFIG.SYS and the INI files. You can also write an 'installation DLL' to further customize the installation process.
MINSTALL is very versatile, as it is designed to all install all kinds of multimedia software, not just IOProcs. I've never used it myself, but it doesn't look too tricky to install an IOProc with it. I won't go into details now, as MINSTALL is probably a big enough topic to deserve its own article.
I'll Be Back!
Hopefully I've managed to give you a decent introduction to what I/O Procedures do and how they work. Next month I'll present my home-made IOProc for reading and writing PNG images and give a detailed explanation of how it works. While PNGIOProc doesn't handle all of the MMIO messages, it will hopefully provide a good example of how to write an IOProc.
A significant portion of the code in PNGIOProc is based on a sample program in the Warp Toolkit called MMIOPROC. Other relevant sample programs are: CASECONV, a simple IOProc which performs case conversion on text; ULTIMOIO which implements a video IOProc using a CODEC; and MMBROWSE, an image browser application which uses IOProcs. Check out these sample programs if you are interested in IOProcs.
If you have any questions or comments about this article, please e-mail them to me at firstname.lastname@example.org. If you think this article is nothing but a rephrasing of the multimedia documentation, then let me know!