Jump to content

MMAPG - Multimedia I/O File Services

From EDM2
Multimedia Application Programming Guide
  1. Introduction
  2. What's New...
  3. Multimedia Application Programming Environment
  4. Media Control Interface
  5. Multimedia Logical Devices
  6. Amplifier-Mixer Device
  7. Waveform Audio Device
  8. Sequencer Device
  9. CD Audio Device
  10. CD-XA Device
  11. Videodisc Device
  12. Digital Video Device
  13. Direct Interface Video Extensions (DIVE)
  14. Captioning
  15. OS/2 Multimedia Controls
  16. Multimedia I/O File Services
  17. Resource Interchange File Format (RIFF) Services
  18. Sample Application Programs
  19. Installing a Program Using MINSTALL
  20. Caption DLL
  21. High-Level Service API
  22. Notices
  23. Glossary

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

The multimedia input/output (MMIO) file services are an extension of the base OS/2 file services. Designed to be simple, fast, and flexible, MMIO functions enable an application to access and manipulate multimedia data files in a transparent manner.

Multimedia files contain a variety of media elements such as images, graphics, digital audio and video. These elements can be in different file formats: for example, RIFF, M-Motion, and AVI. Multimedia files can also be stored as memory files, elements of a compound file storage system, or as DOS files. MMIO provides a consistent programming interface so that an application can refer to these files, read and write data to the files, and query the contents of the files, while remaining independent of the underlying file formats or the storage systems that contain the files. In addition, MMIO now enables compressors and decompressors (CODEC procedures) to operate on data objects. See CODEC Procedures for more a more detailed description of CODEC procedures.

MMIO Architecture

Because files services have unique characteristics, the architecture of MMIO is stand-alone and separate from the notion of the media control interface, although some media drivers and file system stream handlers still require file services from MMIO.

When an application calls multimedia I/O functions, the MMIO Manager calls the appropriate I/O procedure (IOProc) if necessary, or processes the function within the MMIO Manager itself. The MMIO Manager uses IOProcs to direct the input and output associated with reading from and writing to different types of storage systems or file formats. IOProcs provide an abstract of the file format, allowing operations such as read, write, and seek to be independent of the specific format in use. The handler is responsible for translating a generic application request into the necessary format-specific operations.

The MMIO architecture provides for CODEC procedures to operate on data objects as required. A given file format I/O procedure might support none, one, or many CODEC procedures operating on a single format.

The following figure illustrates the architecture of the MMIO subsystem.

            ┌────────────┐  ┌────────────┐  ┌────────────┐
            │            │  │   MEDIA    │  │   STREAM   │
            │APPLICATIONS│  │  DRIVERS   │  │   HANDLER  │
            └─────┬──────┘  └─────┬──────┘  └─────┬──────┘
                  │               │               │
                  └───────────────┼───────────────┘
                                  ▼
                    ┌───────────────────────────┐
                    │        MMIO MANAGER       │
                    └─────────────┬─────────────┘
       ┌────────────────────┐     │    ┌────────────────────┐
       │File Format IOProcs │     │    │File Format IOProcs │
       │ ┌───────────────┐  │     │    │ ┌───────────────┐  │
       │ │      WAVE     │  │     │    │ │  AVC image    │  │
       │ ├───────────────┤  │     │    │ ├───────────────┤  │
       │ │    CLI VOC    │  │     │    │ │M-Motion image │  │
       │ ├───────────────┤  ├─────┼────┤ ├───────────────┤  │
       │ │   AVC audio   │  │     │    │ │1.3 & 2.0 BMP  │  │
       │ ├───────────────┤  │     │    │ ├───────────────┤  │
       │ │  RMID & MID   │  │     │    │ │ RDIB & DIB    │  │
       │ ├───────────────┤  │     │    │ └───────────────┘  │
       │ │     AVI       │  │     │    │         .          │
       │ └───────────────┘  │     │    │         .          │
       │                    │     │    │         .          │
       └────────────────────┘     │    └────────────────────┘
                                  │
       ┌───────────────────┐      │     ┌───────────────────┐
       │  Codec Procedures ├──────┼─────┤  Codec Procedures │
       │ ┌───────────────┐ │      │     │ ┌───────────────┐ │
       │ │  Ultimotion   │ │      │     │ │     Others    │ │
       │ └───────────────┘ │      │     │ └───────────────┘ │
       └───────────────────┘      │     └───────────────────┘
- - - - - - - - - - - - - - - - - │ - - - - - - - - - - - - - - -
               ┌────────────┬─────┴────┬───────────┐
               ▼            ▼          ▼           ▼
          ┌──────────┐┌──────────┐┌──────────┐┌──────────┐
System    │   DOS    ││  MEMORY  ││ COMPOUND ││  OTHERS  │
Storage   │   FILE   ││  FILE    ││ FILE     ││          │
IOProcs   └────┬─────┘└──────────┘└────┬─────┘└─────┬────┘
               │                       │            │      Ring 3
- - - - - - - -│- - - - - - - - - - - -│- - - - - - │- - - - - - -
               ▼                       ▼            ▼      Ring 0
   ┌───────────────────────────────────────────────────────────┐
   │                        File System                        │
   └───────────────────────────────────────────────────────────┘

Installable I/O Procedures

The MMIO Manager uses I/O procedures to direct the input and output associated with reading and writing to different types of storage systems or file formats. Applications and the MMIO subsystem communicate to IOProcs (DLL files) through the use of MMIO messages. When MMIO receives a request from an application through a function call, messages are created by the MMIO Manager. Next, MMIO sends a predefined message for that operation to the IOProc that supports that particular file format or storage system. These messages are designed for efficient communications to all IOProcs. The IOProcs, however, must be able to handle the messages sent by the MMIO Manager to be processed, or pass them on to a child I/O procedure.

Types of I/O Procedures

Two types of I/O procedures are as follows:

Storage System IOProcs unwrap data objects such as RIFF files, compound RIFF files, or AVC files. These IOProcs are ignorant to the content of the data they contain. A storage system IOProc goes directly to the OS/2 (or native) file system (memory in the case of a MEM file) and does not pass information to any other file format or storage system IOProc. The internal I/O procedures provided for DOS files, memory files, and RIFF compound files are examples of storage system IOProcs because they operate on the storage mechanism rather than the data content itself. See the table in the Internal Storage System Procedures section.

File Format IOProcs manipulate multimedia data at the element level (not to be confused with an element of a RIFF compound file). Each IOProc handles a different element type such as audio, image, or MIDI. A file format IOProc handles the element type it was written for and does not rely on any other file format IOProcs to do any processing. However, a file format IOProc might need to call a storage system IOProc to obtain data within a file containing multiple file elements. For example, the MIDI IOProc calls MMIO functions to access data from other storage system IOProcs supported by MMIO. See the table in the File Format I/O Procedures Provided With OS/2 Multimedia section.

Identifying an I/O Procedure

Each file format is represented by a unique identifier called a four-character code (FOURCC). A FOURCC is a 32-bit quantity representing a sequence of one to four ASCII alphanumeric characters (padded on the right with blank characters).

Each IOProc supports a specific file format. The file format and IOProc are represented by a specific FOURCC code. This permits the FOURCC to be used as an ID value, rather than the string-name of the file format or a file name extension. Their use is supported by a set of functions to pack or unpack FOURCC values from or to their component characters. Examples of FOURCC values are: WAVE for RIFF waveform audio files, RMID for RIFF MIDI files, and AVCA for AVC audio files.

Formats that support multiple media types require a different FOURCC for each variation. This appears as a different IOProc for each media type. For example, an Audio Visual Connection (AVC) program might have an IOProc to process image, an IOProc to process audio, and an IOProc to process MIDI. You can, however, include more than one IOProc in a dynamic-link library (DLL) file by providing different entry points in the DLL file.

The data type for a four-character code is FOURCC. The mmioFOURCC function converts four characters to a four-character code as shown:

FOURCC   fccIOProc;

fccIOProc = mmioFOURCC( 'A', 'V', 'C', 'A' ) ;

The mmioFOURCC function is called by the application and passed in subsequent MMIO calls to route the file to the correct IOProc.

Note: Another way to create a four-character code is to use the mmioStringToFOURCC function, which converts a null-terminated string to a four-character code. The second parameter in mmioStringToFOURCC specifies options for converting the string to a four-character code. If you specify the MMIO_TOUPPER flag, mmioStringToFOURCC converts all alphabetic characters in the string to uppercase.

Internal Storage System Procedures

The following table lists the MMIO services provided by internal I/O procedures:

IOProc Description
DOS Handles standard OS/2 disk files.
MEM (memory) Manages memory files without accessing the file system. A memory file is a block of memory that is perceived as a file to an application. This unifies the interface for applications that access both files and memory.
CF (compound file) Supports the RIFF compound file format. The CF IOProc operates on a compound file. The MMIO Manager provides services to find, query, and access file elements in a compound file. It also supports the function of file compaction.

File Format I/O Procedures Provided With OS/2 Multimedia

The MMIO Manager calls a file format I/O procedure to handle I/O to files of a certain media type and format: for example, AVC or M-Motion files. File format I/O procedures are available with the installation of OS/2 multimedia. These I/O procedures are enabled for data and file format translation. They provide conversion support for the Multimedia Data Converter program. By installing file format I/O procedures, existing applications no longer need to store multiple copies of the same media file for running on various platforms using different file formats.

The information in the following table serves as a guide to application developers who would like to access the functions that deal with particular file formats. OS/2 multimedia provides the following file format IOProcs, which can be used to access non-RIFF data and perform multimedia data conversions. Each I/O procedure can read or write format-specific data or standardized data.

IOProc FOURCC Description Common Extension
AIFF AIFF Supports AIFF waveform digital audio files. .AIF
AVC Audio AVCA Supports IBM Audio Visual Connection (AVC) digital audio files of type ADPCM and native ACPA formats. ._AU, ._AD
AVC Image AVCI Supports IBM Audio Visual Connection (AVC) digital image files. ._IM, .!IM, ._ID
AVI Movie AVI Supports audio/video interleaved (AVI) movie files. .AVI
CLI VOC VOC Supports Creative Technology Voice files. .VOC
DIB DI30 Supports device independent bitmap image files. .DIB
FLC/FLI Animation FLIC Supports multi-track read requests from AutoDesk animation files. .FLC, .FLI
GIF GIFC Supports compressed GIF image files. .GIF
JPEG Still Image JPEG Supports translated read and write access to JPEG still image files. .JPG
OS/2 1.3 Bitmap OS13 Supports OS/2 1.3 and Windows 3.0 uncompressed bitmap image files. .BMP
OS/2 2.0 Bitmap OS20 Supports OS/2 2.0 and Windows 3.0 1, 4, 8-bit palettized and 24-bit RGB bitmap image files. .BMP
MIDI MIDI, RMID Supports MIDI files (format 0 and format 1 data), in RIFF or non-RIFF format. .MID
M-Motion Still MOT Supports translated and untranslated access to IBM M-Motion/M-Control YUV video still image files of type packed 12-bit YUV data. .VID
MPEG-1 Movie MPEG Supports multi-track read requests from an MPEG-1 movie file. .MPG
PCX PCXC Supports compressed PCX image files. .PCX
PhotoCD PCD Supports translated read-only access to PhotoCD image files. .PCD
RIFF DIB RDIB Supports RIFF device independent bitmap image files. .RDI
RIFF Waveform WAVE Supports RIFF waveform digital audio files, including PCM, IBM ADPCM, IBM mu-Law, and A-Law. .WAV
TARGA TGAU, TGAC Supports uncompressed and compressed TARGA image files. .TGA
TIFF TIFU, TIFIC, TFMU, TFMC, TFFC Supports compressed and uncompressed Intel or Motorola TIFF image files and compressed TIFF FAX image files. .TIF
UNIX SND SND Supports UNIX (NeXT/Sun) SND digital audio files. .SND

Installing an I/O Procedure

Certain factors must be considered when installing an IOProc; for example, the number of processes that use the IOProc might help you decide which method you use to install an IOProc. Depending on the requirements of your application, you can choose to install an IOProc on a temporary, semipermanent, or permanent basis.

The following MMIO functions allow you to install an IOProc:

Function Description
mmioOpen Temporarily installs an I/O procedure.
mmioInstallIOProc Adds, replaces, finds, or removes an entry in the MMIO IOProc table.
mmioIniFileHandler Adds, replaces, finds, or removes an entry in the initialization file (MMPMMMIO.INI).

Temporary Installation Using mmioOpen

You can temporarily install an I/O procedure using mmioOpen. In this case, the IOProc is only used when a file opened by the MMIO Manager does not install the IOProc in the I/O procedure table.

To specify an I/O procedure when you open a file using mmioOpen, use the pmmioinfo parameter to reference an MMIOINFO structure as follows:

1. Load the DLL using the DosLoadModule and DosQueryProcAddr functions to install and obtain the procedure address of the IOProc as shown in the following code fragment.

strcpy( acMMIOProcName,
        acStringBuffer[ IDS_MMIO_INSTALLPROC_NAME - 1 ] );

ldosAPIRc =
  DosLoadModule(
   &acFailureNameBuffer[ 0 ],    /* Object name if failure occurs.  */
   FILE_NAME_SIZE,               /* Size of the name buffer.        */
   acStringBuffer[ IDS_MMIO_INSTALLPROC_DLL_NAME - 1 ], /* DLL Name.*/
   &hmModHandle );               /* Handle to the module.           */
     .
     .
     .

ldosAPIRc =
  DosQueryProcAddr(
   hmModHandle,                /* Handle to the DLL module.         */
   (ULONG) NULL,               /* NULL gives the entry point.       */
   acMMIOProcName,             /* Name of the Installable procedure.*/
   (PFN *) &pmmioprocIoProc ); /* Pointer to the Installable proc.  */

2. In the MMIOINFO structure passed to mmioOpen, store the procedure address of the IOProc type in the pIOProc field. Set the fccIOProc field to NULL.

3. Call mmioOpen to use the IOProc with a file, passing the MMIOINFO structure in as the second parameter. This sends a MMIOM_OPEN message to the temporary IOProc. (Note that this does not make the IOProc available for use with other files.)

4. Set all other fields to 0 (unless you are opening a memory file, or directly reading or writing to the file I/O buffer).

This strategy allows a file format IOProc to replace a default IOProc (such as the DOS IOProc), simply by using the address of a replacement custom routine.

Semipermanent Installation Using mmioInstallIOProc

You can install an IOProc during run-time from your application. This method is semipermanent because the IOProc can only be called while the process is active. When the process terminates, it is removed from the IOProc table. Once the DLL is removed from memory, the next loading of the MMIO DLL does not load this IOProc. Because this IOProc is installed by specifically calling mmioInstallIOProc, as shown in the following figure, the IOProc is available for any files opened within that process.

PMMIOPROC  pmmioprocSpecialIOProc; /* Pointer once IOProc
                                      is installed.        */


 pmmioprocSpecialIOProc =
   mmioInstallIOProc(
    fccIOProc,          /* The identifier (FOURCC) of the procedure.*/
    pmmioprocIoProc,    /* Pointer to the installable procedure.    */
    MMIO_INSTALLPROC ); /* Flag to install the procedure.            */

The mmioInstallIOProc function maintains a separate list of installed I/O procedures for each OS/2 application that uses MMIO. This allows different applications to use the same I/O procedure identifier for different I/O procedures without causing conflict. When you install an I/O procedure using mmioInstallIOProc, the procedure remains installed until you remove it. The mmioInstallIOProc function does not prevent an application from installing two different I/O procedures with the same identifier, or installing an I/O procedure with the same identifier as a internal I/O procedure (DOS, MEM, or CF). When mmioInstallIOProc is called with the MMIO_REMOVEPROC flag set, as shown in the following code fragment, the most recently installed procedure is the first one to be removed.

PMMIOPROC  pmmioprocSpecialIOProc; /* Pointer once IOProc
                                      is installed.                */

 pmmioprocSpecialIOProc =
   mmioInstallIOProc(
     fccIOProc,               /* The identifier of the procedure. */
     pmmioprocIoProc,         /* Pointer to the Installable proc. */
     MMIO_REMOVEPROC );       /* Flag to deinstall the proc.      */

Permanent Installation Using mmioIniFileHandler

You can permanently install an IOProc in your system by identifying the IOProc in the initialization file (MMPMMMIO.INI) when you start your system. This method allows the IOProc to be used by any process because it is installed in the IOProc table for every process (like the internal I/O procedures). Therefore, a call to mmioInstallIOProc is not necessary every time the IOProc is needed.

The advantage of installing I/O procedures in the MMPMMMIO.INI file is to achieve application transparency; I/O procedures become built-in as soon as you restart your system. Note that the IOProc must be contained in a DLL file, although more than one IOProc can be contained in the DLL if necessary.

To permanently install an IOProc, an IOProc entry is added to the MMPMMMIO.INI file. This is accomplished by either writing an INI change control file or writing an application using the mmioIniFileHandler function with the MMIO_INSTALLPROC specified. The IOProc is installed in the IOProc table ahead of the MMIO default IOProcs (DOS, MEM, and CF).

The following code fragment is an example of how an application uses the mmioIniFileHandler function to permanently install the OS/2 1.3 PM bitmap image IOProc.

#define FOURCC_OS13   mmioFOURCC( 'O', 'S', '1', '3' )

#pragma linkage( mmioIniFileHandler, system )

void main ()
{
 ULONG   ul;
 MMINIFILEINFO  mminifileinfo;
 mminifileinfo.fccIOProc = FOURCC_OS13;
 strcpy (mminifileinfo.szDLLName, "OS13PROC");
 strcpy (mminifileinfo.szProcName, "OS13BITMAPIOPROC");
 mminifileinfo.ulExtendLen = 16L;
 mminifileinfo.ulFlags = 0L;
 mminifileinfo.ulMediaType = MMIO_MEDIA_IMAGE;
 mminifileinfo.ulIOProcType = MMIO_IOPROC_FILEFORMAT;
 strcpy (mmioinifileinfo.szDefExt, "");

 printf ("Installing OS/2 PM Bitmap (V1.3) IOProc\n");

 rc = mmioIniFileHandler (&mminifileinfo, MMIO_INSTALLPROC);
 switch (rc)
 {
 case MMIO_SUCCESS:
  printf ("Installing Complete\n");
  break;
 case MMIOERR_INVALID_PARAMETER:
  printf ("Error in this install program\n");
  break;
 case MMIOERR_INTERNAL_SYSTEM:
  printf ("OS/2 MPM System Error\n");
  break;
 case MMIOERR_NO_CORE:
  printf ("Memory unavailable for this IOProc\n");
  break;
 case MMIOERR_INI_OPEN:
  printf ("Unable to access the OS/2 MMPMMMIO.INI file\n");
  break;
 case MMIOERR_INVALID_FILENAME:
  printf ("Cannot find the file : OS13PROC.DLL\n");
  break;
 default:
  printf ("Unknown error attempting to install OS/2 Bitmap V(1.3)\n");
  break;
 }
}

CODEC Procedures

CODEC procedures are similar to I/O procedures (IOProcs). They are dynamic-link library (DLL) routines that operate on data within a file or buffer. Based on the data content, a particular CODEC procedure is loaded typically by a file format IOProc to either compress or decompress the data.

OS/2 multimedia currently supports image and digital video CODECs. The following table describes the video CODEC procedures provided with OS/2 multimedia.

CODEC Format FOURCC Description
LDC Ultimotion ULTI Decompressor
INDEO Indeo 2.1 rt21/RT21 Compressor/Decompressor
INDDEC32 Indeo 3.1/3.2 iv31/IV31/iv32/IV32 Decompressor
ULCORT Ultimotion ULTI Real-time compressor
ULCOASYM Ultimotion ULTI Frame-step compressor
INDRTR31 Indeo 3.1 IV31 Real-time compressor
INDFSR31 Indeo 3.1 IV31 Frame-step compressor
CONDO Uncompressed RRIB Supports SW Monitor/RGB16-YUV411 Playback
AUTOPROC FLI/FLC flic Supports AutoDesk Animator Playback
JPGDC JPEG JPEG JPEG hardware interface CODEC

OS/2 multimedia also provides a set of audio CODECs; however, there is no public interface to install new audio CODECs or to interface to audio CODECs directly.

The following table describes the audio CODEC procedures used internally within OS/2 multimedia for playing files that contain compressed audio.

CODEC Format Format Tag Comp. Decomp. Description
IMAADPCM MS ADPCM Compression is not real-time
IMAADPCM IMA ADPCM 17 Real-time compression

CODEC Functions, Messages, and Data Structures

There are enough differences between CODEC procedures and I/O procedures that several additional functions and messages are needed for CODEC processing. Both applications and I/O procedures can call these CODEC functions and messages.

The MMIO subsystem supports the CODEC functions listed in the following table.

Function Description
mmioIniFileCODEC Adds, replaces, removes, or finds a CODEC entry in the MMPMMMIO.INI file.
mmioQueryCODECName Queries the ID string of a CODEC procedure.
mmioQueryCODECNameLength Queries the length of a CODEC procedure ID string.
mmioLoadCODECProc Loads the CODEC procedure and returns the entry point.
mmioSet Sets or queries extended file information.

The messages listed in the following table are supported by I/O procedures.

Message Description
MMIOM_COMPRESS Sent to an IOProc to compress data.
MMIOM_DECOMPRESS Sent to an IOProc to decompress data.
MMIOM_MULTITRACKREAD Sent to an IOProc to read multi-track data from a file.
MMIOM_MULTITRACKWRITE Sent to an IOProc to writes multi-track data to a file.
MMIOM_SET Sets and queries CODEC attributes of the CODEC procedure.

The messages listed in the following table are supported by CODEC procedures.

Message Description
MMIOM_CODEC_OPEN Opens a CODEC instance.
MMIOM_CODEC_CLOSE Closes a CODEC instance.
MMIOM_CODEC_QUERYNAME Queries the CODEC procedure ID string.
MMIOM_CODEC_QUERYNAMELENGTH Queries the length of the CODEC procedure ID string.
MMIOM_CODEC_COMPRESS Compresses data.
MMIOM_CODEC_DECOMPRESS Decompresses data.

The data structures listed in the following table are supported by I/O procedures and CODEC procedures. The CODEC.H and MMIOOS2.H header files define these data structures. Include the CODEC.H and MMIOOS2.H header files and define INCL_MMIO_CODEC in any source that uses CODEC functions.

Data Structure Description
MMEXTENDINFO Used by mmioSet and MMIOM_SET.
MMULTITRACKREAD Used by MMIOM_MULTITRACKREAD.
MMULTITRACKWRITE Used by MMIOM_MULTITRACKWRITE.
MMMOVIEHEADER Standard presentation movie header.
MMVIDEOHEADER Standard presentation video header.
MMVIDEOOPEN Used by MMIOM_OPEN.
MMCOMPRESS Used by MMIOM_CODEC_COMPRESS and MMIOM_COMPRESS.
MMDECOMPRESS Used by MMIOM_CODEC_DECOMPRESS and MMIOM_DECOMPRESS.
CODECVIDEOHEADER Used by MMIOM_CODEC_OPEN.
CODECOPEN Used by MMIOM_CODEC_OPEN.
CODECINIFILEINFO Used by mmioIniFileCODEC.

Installing a CODEC Procedure

Unlike I/O procedures that have several methods of installation, CODEC procedures are installed by registering them in the MMPMMMIO.INI file using the mmioIniFileCODEC function. Once registered in the MMPMMMIO.INI file, queries can be made on CODEC properties associated with the file format of the opened file. A particular CODEC procedure can be associated with different file formats. A separate entry is required for each different file format a CODEC procedure supports. Allowing CODEC procedures to be queried and dynamically loaded based on the data content alleviates the need to statically load CODEC procedures with the file format IOProc, or hard code DLL names with the IOProc. The following code fragment shows how to install a CODEC procedure using mmioIniFileCODEC.

 CODECINIFILEINFO codecIniFileInfo;
 ULONG ulFlags = 0L;
 ULONG rc;
        .
        .
        .
 memset( &codecIniFileInfo, '\0', sizeof(CODECINIFILEINFO) );
 codecIniFileInfo.ulStructLen = sizeof(CODECINIFILEINFO);
 codecIniFileInfo.fcc = FOURCC_MYPROC;
 codecIniFileInfo.ulCompressType = COMPRESSTYPE_MYPROC;
 codecIniFileInfo.ulCompressSubType = COMPRESSSUBTYPE_MYPROC;
 codecIniFileInfo.ulMediaType = MEDIATYPE_MYPROC;
 codecIniFileInfo.ulCapsFlags = CODEC_DECOMPRESS;
 codecIniFileInfo.ulFlags = 0;
 codecIniFileInfo.szHWID = HWID_MYPROC;
 codecIniFileInfo.ulMaxSrcBufLen = MAXBUFLEN_MYPROC;
 codecIniFileInfo.ulSyncMethod = 1;
 codecIniFileInfo.ulReserved1 = 0;
 codecIniFileInfo.ulXalignment = XALIGNMENT_MYPROC;
 codecIniFileInfo.ulYalignment = YALIGNMENT_MYPROC;
 strncpy( codecIniFileInfo.szDLLName, "MYPROC.DLL", DLLNAME_SIZE );
 strncpy( codecIniFileInfo.szProcName, "MyCODECProc", PROCNAME_SIZE );
 ulFlags = MMIO_INSTALLPROC | MMIO_MATCHCOMPRESSTYPE |
            MMIO_MATCHCOMPRESSSUBTYPE |
            MMIO_MATCHCAPSFLAGS | MMIO_MATCHHWID;

 rc = mmioIniFileCODEC( &codecIniFileInfo,
                          ulFlags);
 if (rc)
   /* error */
 else
        .
        .
        .

MMIO Data Structures

The MMIOOS2.H header file, supplied with the Toolkit, defines data structures used in passing information between an application and MMIO file services. Include the MMIOOS2.H file in any source that uses multimedia file I/O functions. Also include the main header file, OS2.H, which contains a declaration statement for the MMIOOS2.H file. The MMIOOS2.H file defines MMIO data structures listed in the following table.

Note: The MMMIDIHEADER data structure is defined in the MIDIOS2.H file.

Data Structure Description
MMAUDIOHEADER Contains descriptive information about a digital audio element (such as the sample rate, bits per sample, and so forth).
MMCFINFO Contains information about a RIFF compound file.
MMCKINFO Contains information about a chunk in a RIFF file.
MMCTOCENTRY Contains information about an entry in the compound file table of contents (CTOC) of a RIFF compound file.
MMFORMATINFO Contains information about the format of a file or file element.
MMIMAGEHEADER Contains descriptive information about an image (such as the size, color type and extent, palette information, and so forth).
MMINIFILEINFO Contains information about the MMPMMMIO.INI file.
MMIOINFO Describes the current state of an open file.
MMMIDIHEADER Contains descriptive information about a MIDI file.

Note: Initialize all fields in MMIO data structures that are not used in a given function to NULL. In addition, set unused flags and bits in flags that are not used to 0.

Basic I/O Functions

The following MMIO functions enable applications to manage basic multimedia file I/O operations. These functions, together with media independent operations, provide applications independence from a specific media type. Basic multimedia file I/O services are shown in the following table.

Function Description
mmioOpen Opens or creates a file for reading, writing, or both.
mmioRead Reads a specified number of bytes from an open file.
mmioWrite Writes a specified number of bytes to an open file.
mmioSeek Changes the current position for reading, writing, or both in an open file.
mmioClose Closes an open file.

Opening or Creating a File

To perform I/O operations on a new or existing file, an application must first establish a connection by calling the mmioOpen function. This returns a file handle, which identifies the open file when calling other file I/O functions. Specify the pmmioinfo parameter to identify a pointer to a caller-provided MMIOINFO block containing extra parameters used by mmioOpen. pmmioinfo may be NULL if the default values of the fields of pmmioinfo are sufficient. By specifying an MMIOINFO structure, you can open a memory file, specify a file format I/O procedure, supply a buffer, or specify data transfers in a standard presentation format. For basic file I/O services, set pmmioinfo to NULL. For example, the following code sample shows how to open a data file without a buffer.

hmmio = mmioOpen("filename.ext", NULL, 0);

Basic options for mmioOpen are shown in the following table.

Flag Description
MMIO_ALLOCBUF System allocates an internal I/O buffer.
MMIO_APPEND Allows appending to the end of a file.
MMIO_BUFSHARED Uses shared memory if MMIO allocates an I/O buffer.
MMIO_CREATE Creates a new file.
MMIO_DELETE Deletes the file if it already exists.
MMIO_NOIDENTIFY Does not attempt to identify the file type.
MMIO_READ Opens a file for reading only (default).
MMIO_READWRITE Opens a file for both reading and writing.
MMIO_VERTBAR ) as a file separator character rather than the plus sign (+).
MMIO_WRITE Opens a file for writing only.

The following example creates a new file named NEW.TXT and opens it for writing:

hmmio = mmioOpen("NEW.TXT", NULL, MMIO_CREATE | MMIO_WRITE);

You can also use mmioOpen to specify sharing options for data files. These options enable DOS files to be opened and accessed by more than one process, allowing an application to take advantage of the multi-processing feature of the OS/2 operating system.

Sharing options for data files are shown in the following table.

Flag Description
MMIO_DENYNONE Opens a file without denying other processes read or write access to the file.
MMIO_DENYREAD Opens a file and denies other processes read access to the file.
MMIO_DENYWRITE Opens a file and denies other processes write access to the file.
MMIO_EXCLUSIVE Opens a file with exclusive mode, denying other processes both read and write access to the file.

Reading from and Writing to a File

Use the mmioRead and mmioWrite functions to read and write to files opened by mmioOpen. Use the pch parameter to specify the buffer to read to (mmioRead) or the buffer to write from (mmioWrite). Use the cch parameter to specify the number of bytes to read to or write from pch to the file. (The read and write operations are not limited to 64KB.)

The following example shows how to read 20 bytes from a file:

mmioRead(hmmio, achBuffer, 20)

The following example shows how to write 20 bytes to a file:

mmioWrite(hmmio, achBuffer, 20)

Note: Where translation (MMIO_TRANSLATEDATA) is enabled, the translation takes place during the read and write operation.

Changing the Position in a File

Use the mmioSeek function to change the current position of the file pointer in an open file. This is the place where the next read or write operation is going to take place. The lOffset parameter specifies an offset to move the file position to. The lOrigin parameter specifies how the offset is interpreted.

The following example illustrates how to seek to the beginning of an open file:

mmioSeek(hFile, 0L, SEEK_SET);

To seek to the current file position:

mmioSeek(hFile, 0L, SEEK_CUR);

To seek to the end of a file:

mmioSeek(hFile, 0L, SEEK_END);

To seek to a position 20 bytes from the end of an open file:

mmioSeek(hFile, -20L, SEEK_END);

The return value is the new file position (specified in bytes) from the beginning of the file. If an error occurs, the return code is MMIO_ERROR. Use caution when seeking past the end of the file. Instead of returning MMIO_ERROR, mmioSeek returns the offset of the new file position.

Note: The mmioSeek function supports seeking in translation mode within the limits and capabilities of the specific file format IOProc that handles that format.

Retrieving an Error

Use the mmioGetLastError function to return the last error condition stored in the system for this process. This function assists you in obtaining additional information about the failing condition for error routine analysis.

Note: This function only works if you have an MMIO handle.

Buffered File I/O

Using buffers improves the performance of multimedia applications that perform numerous file I/O operations when accessing media devices. With buffered file I/O, the system maintains a block of memory that the operating system uses to store data as it is read from (or written to) the disk. If data is already in the buffer, the operating system can transfer the record to the application's area without reading the sector from the disk. This improves performance by reducing the number of times the application accesses the disk for read or write operations. The application only accesses the media device when the buffer must be filled from or written to the disk.

Many factors must be considered when deciding whether or not to use buffered file I/O; for example, the number and size of read and write operations. Although it is difficult to identify criteria for using buffered I/O, there are some general guidelines you can follow. It is a good idea to use buffered I/O for applications that perform many I/O operations, less than 4KB each. However, if you are performing I/O operations where buffer sizes may be larger than 4KB (as in the case of streaming), it might be best to use unbuffered I/O. If an application such as the Sync/Stream Manager (SSM) provides its own internal buffers, a secondary set of buffers during run-time may hinder, rather than improve, performance. Experiment to optimize file I/O for your application's requirements.

Opening a File Using Buffered File I/O

When a file is opened for buffered I/O, the buffer is essentially transparent to the application. You can read, write, and seek in the same way as unbuffered I/O. To open a file using buffered file I/O, you can either provide an I/O buffer in an application, or allow the system to allocate an internal buffer. To provide a user-supplied I/O buffer, you can either use mmioOpen and have the pmmioinfo field point to the buffer, or use mmioSetBuffer (see the table of buffered I/O functions in the next subsection.) To provide a system-supplied buffer, specify the MMIO_ALLOCBUF option of the mmioOpen function. Unless you have a performance-sensitive application that directly accesses an I/O buffer or opens a memory file, it is a good idea to use the MMIO Manager to allocate the buffer. For example, the following code sample opens a DOS file and directs mmioOpen to allocate a standard-sized buffer.

hmmio = mmioOpen("EXAMPLE.DIB", NULL, MMIO_ALLOCBUF);

Managing Buffered I/O

The MMIO functions shown in the following table allow you to manage an I/O buffer.

Function Description
mmioFlush Forces the contents of an I/O buffer to be written to disk.
mmioSetBuffer Enables or disables buffered I/O, and changes the buffer or buffer size for an open file.

Emptying the Contents of an I/O Buffer

Emptying the contents of an I/O buffer means that the contents of the buffer are written to disk. You can empty the contents of a buffer by calling mmioFlush or mmioClose. The buffer is automatically emptied when you close a file by calling mmioClose. If you do not close a file immediately after writing to it, empty the contents of the buffer to make sure the information is written to disk. You can also use the MMIO_EMPTYBUF flag of mmioFlush to clear the I/O buffer without deallocating the buffer.

Note: The mmioFlush function may fail if there is insufficient disk space to write the buffer, even if the preceding mmioWrite functions succeeded.

Setting or Changing an I/O Buffer

Use the mmioSetBuffer function to enable or disable I/O buffering for reading to or writing from files. You can also change the size of the internal I/O buffer (8KB default) or supply your own buffer for use as a memory file.

The mmioSetBuffer function requires a pchBuffer parameter, which identifies the pointer to a user-supplied buffer for buffered I/O. If you want mmioSetBuffer to allocate the buffer, or if you want to disable any predefined I/O buffers, set pchBuffer to NULL. A second parameter, cchBuffer, specifies the size of the caller-supplied buffer. If you set pchBuffer to NULL, cchBuffer is the size of the buffer that the you want mmioSetBuffer to allocate. To disable buffering, set pchBuffer and cchBuffer to NULL.

The following example illustrates how to open an unbuffered file named TESTING and then allocate an internal 16KB buffer.

HMMIO hFile;
.
.
.
if ((hFile = mmioOpen("TESTING", NULL, MMIO_READ)) !=NULL) {
   /* File opened successfully; request an I/O buffer */
   if (mmioSetBuffer(hFile, NULL, 16384L, 0))
       /* Buffer cannot be allocated */
   else
       /* Buffer allocated successfully */
}
else
     /* File cannot be opened */

The following example illustrates how to open a buffered file named TESTING and then disable buffered I/O.

HMMIO hmmio;
.
.
.
if ((hmmio = mmioOpen("TESTING", NULL, MMIO_ALLOCBUF)) !=NULL) {
   /* File opened successfully; disable buffered I/O */
   if (mmioSetBuffer(hFile, NULL, NULL, 0))
       /* Cannot disable buffered I/O  */
   else
       /* Buffered I/O disabled successfully */
}
else
       /* File cannot be opened */

Directly Accessing a File I/O Buffer

Applications that are performance-sensitive can optimize file I/O performance by directly accessing the file I/O buffer. Exercise care if you choose to do this—by accessing the file I/O buffer directly, you bypass some of the safeguards and error checking provided by the MMIO Manager.

The MMIO functions shown in the following table allow you to support direct I/O buffer access on a file opened for buffered I/O.

Function Description
mmioGetInfo Retrieves information on the file I/O buffer of a file opened for buffered I/O.
mmioAdvance Fills and empties the contents of an I/O buffer of a file set up for direct I/O buffer access.
mmioSetInfo Changes information on the file I/O buffer of a file opened for buffered I/O.

Note: After you call mmioGetInfo, do not call any MMIO functions other than mmioAdvance. You can begin calling MMIO functions again after you call the mmioSetInfo function.

The MMIO Manager uses the MMIOINFO data structure to maintain state information on an open file. The MMIOINFO data structure is defined in the MMIOOS2.H header file as as shown.

typedef struct _MMIOINFO {        /* mmioinfo                     */
   ULONG       ulFlags;          /* Open flags                  */
   FOURCC      fccIOProc;        /* FOURCC of the IOProc to use */
   PMMIOPROC   pIOProc;          /* Function Pointer to IOProc to use */
   ULONG       ulErrorRet;       /* Extended Error return code  */
   LONG        cchBuffer;        /* I/O buff size (if used), Fsize if MEM */
   PCHAR       pchBuffer;        /* Start of I/O buff            */
   PCHAR       pchNext;          /* Next char to read or write in buff */
   PCHAR       pchEndRead;       /* Last char in buff can be read + 1  */
   PCHAR       pchEndWrite;      /* Last char in buff can be written + 1 */
   LONG        lBufOffset;       /* Offset in buff to pchNext */
   LONG        lDiskOffset;      /* Disk offset in file       */
   ULONG       aulInfo[4];       /* IOProc specific fields    */
   LONG        lLogicalFilePos;  /* Actual file position, buffered or not */
   ULONG       ulTranslate;      /* Translation field         */
   FOURCC      fccChildIOProc;   /* FOURCC of Child IOProc     */
   PVOID       pExtraInfoStruct; /* Pointer to a structure of related data */
   HMMIO       hmmio;            /* Handle to media element   */
   } MMIOINFO;

Getting Buffer Information

Use mmioGetInfo to obtain information about a file I/O buffer, such as the buffer size and address. The mmioGetInfo function also sets up a file for direct I/O buffer manipulation.

The mmioGetInfo function identifies a pointer to an MMIOINFO structure that mmioGetInfo fills with information about the file I/O buffer. The return value is 0 if the operation is successful; otherwise, the return value specifies an error code.

Reading from and Writing to the Buffer

The following table shows three fields in the MMIOINFO structure used for reading from and writing to the file I/O buffer.

Field Description
pchNext Points to the next location in the buffer to read or write. You must increment pchNext as you read and write the buffer.
pchEndRead Identifies the location containing the last valid character you can read from the buffer. This is the memory location following the last valid data in the buffer.
pchEndWrite Identifies the last location in the buffer you can write to. This is the memory location following the end of buffer.

Advancing the File I/O Buffer

When you reach the end of the file I/O buffer, use mmioAdvance to advance the buffer. Advancing the buffer allows you to fill a file I/O buffer from disk (MMIO_READ). If there is not enough data remaining in the file to fill the buffer, the pchEndRead field in the MMIOINFO structure points to the location following the last valid byte in the buffer.

mmioAdvance also allows you to empty the contents of the current buffer to disk (MMIO_WRITE) by setting the MMIO_DIRTY flag in the ulFlags field of the MMIOINFO structure. mmioAdvance updates the fields in the MMIOINFO structure to reflect the new state of the I/O buffer (including pchNext, pchEndRead, and pchEndWrite).

Advancing a File I/O Buffer for Reading

The following figure shows how the file I/O buffer is advanced as a file is read from.

(1) The application opens the file for buffered I/O. The buffer is initially empty, so mmioOpen sets pchNext and pchEndRead to point to the beginning of the file I/O buffer.

(2) The application calls mmioAdvance to fill the I/O buffer. The mmioAdvance function fills the buffer and sets pchNext to point to the beginning of the buffer.

(3) The application reads from the I/O buffer and increments pchNext.

(4) The application continues to read the buffer and call mmioAdvance to refill the buffer when it is empty. When mmioAdvance reaches the end of the file, there is not enough information to fill the buffer. The mmioAdvance function sets pchEndRead to point to the end of the valid data in the buffer.

Advancing a File I/O Buffer for Writing

The following figure shows how the file I/O buffer is advanced as a file is written to.

(1) The application opens the file for buffered I/O by calling mmioOpen. The mmioOpen function sets pchNext to point to the beginning of the file I/O buffer and pchEndWrite to point to the end of the buffer.

(2) The application writes to the I/O buffer and increments pchNext.

(3) Once the application fills the buffer, it calls mmioAdvance to empty the contents of the buffer to disk. The mmioAdvance function resets pchNext to point to the beginning of the buffer.

(4) The application continues to write to the buffer and call mmioAdvance to empty the contents of the buffer when its full. At the end of the file, there is not enough information to fill the buffer. When the application calls mmioAdvance to empty the contents of the buffer, pchNext points to the end of the valid data in the buffer.

Ending Direct Access of a File I/O Buffer

When you finish accessing a file I/O buffer, pass the MMIOINFO structure filled by mmioGetInfo to mmioSetInfo to end direct access to the I/O buffer. Before calling mmioSetInfo, make sure that you set the MMIO_DIRTY flag of the ulFlags field of pmmioinfo if you have written to the buffer. Otherwise, the contents of the buffer will not get emptied to disk. When mmioSetInfo is called, then the caller should stop accessing the I/O buffer directly and revert to using mmioRead and mmioWrite to read from and write to the file.

The following code fragment illustrates how to directly read an I/O buffer.

mmioGetInfo(hmmio, &mmioinfo, 0)
mmioAdvance(hmmio, &mmioinfo, MMIO_READ)
for (i=0, iCount=0;  i<20; i++)
 iCount += *(mmioinfo.pchNext)++;
mmioSetInfo(hmmio, &mmioinfo, 0);

File I/O in Memory

A memory file is a block of memory that is perceived as a file by an application. This can be useful if you already have a file image in memory. Memory files let you reduce the number of special-case conditions in your code because, for I/O purposes, you can treat file memory images as if they were disk-based files.

Like I/O buffers, memory files can use memory allocated by the application or by the MMIO Manager. In addition, memory files can be expandable or non-expandable.

Memory is expandable when the system allocates an internal buffer using the MMIO_ALLOCBUF flag of the mmioOpen function. When the MMIO Manager reaches the end of an expandable memory file, it expands the memory file by a predefined increment.

Use the mmioOpen function to open a memory file. Specify NULL for the szFileName parameter and the MMIO_READWRITE flag, as shown:

hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READWRITE);

In addition, set the pmmioinfo parameter to point to an MMIOINFO structure set up as follows:

  • Set the pIOProc field to NULL.
  • Set the fccIOProc field to FOURCC_MEM.
  • Set the pchBuffer field to point to the memory block. To request that the MMIO Manager allocate the memory block, set pchBuffer to NULL.
  • Set the cchBuffer field to the initial size of the memory block.
  • Set the aulInfo[0] field to the minimum expansion size of the memory block. For a non-expandable memory file, set aulInfo[0] to NULL.
  • Set all other fields to 0.

The following code fragment shows how to open a memory file using a buffer named achMyBuffer.

        /* set mmioinfo structure to 0 */
        mmioinfo.fccIOProc= FOURCC_MEM
        mmioinfo.pchBuffer= achMyBuffer
        mmioinfo.cchBuffer= cchMyBuffer
hmmio = mmioOpen(NULL, &mmioinfo, 0);

The following code fragment shows how to open a memory file with 1 byte initially and expand up to 1KB as required.

        /* set mmioinfo structure to 0 */
        mmioinfo.fccIOProc= FOURCC_MEM
        mmioinfo.pchBuffer= NULL
        mmioinfo.cchBuffer= 1
        mmioinfo.aulInfo[0] = 1024;
hmmio = mmioOpen(NULL, &mmioinfo, MMIO_CREATE)

Allocating Memory for Memory Files

There are no restrictions on allocating memory for use as a non-expandable memory file. You can use static memory or stack memory, or you can use locally allocated or globally allocated memory.