10 Tips to Effective Multimedia Programs

From EDM2
Jump to: navigation, search

by Linden deCarmo

The award winning functions in Multimedia Presentation Manager/2 (MMPM/2), coupled with the tremendous explosions in the sound, video capture, and CD-ROM markets has caused many programmers to experiment with multimedia. The downside to this incredible explosion is that the amount of documentation on how to write good multimedia programs and the amount of sample source code available simply cannot keep up with the demand. This article hopes to fill in that gap by providing you with my top ten tips on writing effective OS/2-based multimedia programs.

Note: Although some of the tips in this article apply specifically to digital audio, you can use many of these techniques with other multimedia devices. In addition, this article assumes that you are familiar with the media control interface of MMPM/2 (additional information on the media control interface is available in the MMPM/2 Toolkit on The Developer Connection for OS/2 CD-ROM).

Tip 1. Never use a DOS API to access a multimedia file.

The Multimedia Input/Output (MMIO) interface initially might seem like an excess layer that will slow your application. However, if used correctly, the MMIO interface can isolate your program from the many audio, video, and bitmap formats in the industry. MMIO accomplishes this file-format independence with a series of DLLs called I/O Procedures (I/O Procs). When a file is initially opened, MMIO searches through its list of I/O Procs and determines the one that understands the format of the file. As new I/O Procs are added to the system, all MMPM/2 programs that use MMIO automatically understand the file format of the new I/O Proc.

For example, because IBM's Ultimedia Builder Program uses the MMIO interface to read files, it instantly can recognize Photo CD, .MOD, and compressed audio files (if the appropriate I/O Proc is installed). Contrast this to applications that use DOS APIs to read multimedia data and; therefore, are limited to the data types they specifically support.

Tip 2. Use the MCI_OPEN_MMIO flag on MCI_OPEN or MCI_LOAD.

Use the MCI_OPEN_MMIO flag to pass a MMIO file handle to a media control interface driver. This flag is particularly effective if your program must open a multimedia file with the MMIO subsystem and also use media control interface functions, or if your application has several MMIO files open (for example, a jukebox application) and needs to open each one alternatively with media control interface functions. The media control interface driver, then, will reuse the file handle. This reuse is advantageous because a majority of the time spent in the MCI_OPEN or MCI_LOAD calls actually are MMIO routines. Using MCI_OPEN_MMIO can improve performance. Bottom line is that if for any reason you have a file open with MMIO, use MCI_OPEN_MMIO when making media control interface calls.

Tip 3. Support multimedia clipboard operations.

One big advantage that IBM's MMPM/2 and the Ultimedia Video IN products provide is the ability to easily process multimedia data in the clipboard. The Digital Audio media control interface driver (and the Digital Video media control interface driver if you have Ultimedia Video IN) supports clipboard operations through MCI_CUT, MCI_COPY, and MCI_PASTE. And, the audio clipboard operations let you pass information to and from your own buffers, rather than just a file.

Another clipboard-related feature that you can use is the unlimited undo/redo support provided by the Digital Audio media control interface driver. You can undo or redo an infinite number of record, cut, copy, and paste operations on an audio file. This unlimited undo/redo support is one of the unique capabilities provided by MMPM/2.

Tip 4. Use threads intelligently.

The MMPM/2 Programming Reference definitively states that if you use the MCI_NOTIFY flag "control is returned immediately to the application. When the requested action is complete, the MM_MCINOTIFY message is sent to the application window procedure." Despite this, it is dangerous to assume that because you sent a command with the MCI_NOTIFY flag, the media control interface driver did, in fact, perform the action on a thread.

To explain: For some commands, more overhead exists in setting up a thread rather than just processing the command. As a result, most media control interface drivers will only spin threads on commands that can take a considerable quantity of time.

Unfortunately, situations can exist where an application must start its own threads, despite the fact that it uses a MCI_NOTIFY flag. For instance, some media control interface drivers don't start threads when it is appropriate (such as MCI_LOAD processing in the Digital Video media control interface driver). In addition, MCI_OPEN performs the same whether you use MCI_WAIT or MCI_NOTIFY. This happens because a thread cannot be started until after the application executes several DosLoadModule calls and DosLoadModule consumes most of the MCI_OPEN. As a result, never execute an MCI_OPEN command on a PM message queue thread . And, when executing another media control interface command on the PM thread, ensure that either the command completes quickly or that you use MCI_NOTIFY and the driver is really starting a thread. Figure 1 shows the list of media control interface drivers that use threads.

10Tips-MM-Fig-1.gif

Figure 1. List of commands that use threads with the media control interface driver.

Tip 5. Share your multimedia devices.

Unlike the simpler multimedia interfaces in Windows and Windows NT, MMPM/2 lets an unlimited number of programs open and use the multimedia devices that it controls. Rather than opening and closing devices each time your program gains or loses focus, you need only process the MM_MCIPASSDEVICE to determine the device's state (see Maximizing the Audio Support in OS/2 2.1 in Volume 2 of The Developer Connection News for information on MM_MCIPASSDEVICE).

Tip 6. Don't assume anything, use device capabilities.

Use the MCI_GETDEVCAPS message to isolate your program from device specific features or limitations. For example, if you are writing an audio application that can output either 8-bit pulse code modulation (PCM) data or 16-bit PCM data, use MCI_GETDEVCAPS to determine which the hardware device can play. (Figure 2 shows how to determine audio device capabilities).

/* Set up the fields of the mciAudioCaps structure to see if the
 * device supports the different options on the Type menu of this
 * sample program. These items include&colon.
 * Mono or Stereo, 11 kHz or 22 kHz or 44 kHz, and 8 bit or 16 bit.
 * 12 different combinations are possible, so we will
 * issue the query 12 times. If any of the options are not supported
 * in ONE combination, we will disable that option on the Type menu.
 * Play and Record will also be tested with this api, so we can disable
 * the Play and Record pushbuttons if the device does not support the
 * function.
 */
 
 /* Test to see if the device can play 11 kHz, 8 bit, mono files. */
 
 mciAudioCaps.ulBitsPerSample = 8;
 mciAudioCaps.ulFormatTag = DATATYPE_WAVEFORM;
 mciAudioCaps.ulSamplesPerSec = 11025;
 mciAudioCaps.ulChannels = 1;
 mciAudioCaps.ulFormatMode = MCI_PLAY;
 mciAudioCaps.ulItem = MCI_GETDEVCAPS_WAVE_FORMAT;
 
 ulRC = mciSendCommand (mciOpenParms.usDeviceID, /* Device ID */
                        MCI_GETDEVCAPS,
                        MCI_WAIT | MCI_GETDEVCAPS_EXTENDED
                      | MCI_GETDEVCAPS_ITEM,
                        (PVOID) &mciAudioCaps,
                        0);
 ulRC &= 0x0000FFFF;
 if (ulRC != MCIERR_SUCCESS)
 {
   EvaluateReturnCode (8, 11025, 1, ulRC);
 }

Figure 2. Using MCI_GETDEVCAPS to determine the capabilities of the audio device.

Tip 7. Use shortcuts whenever possible.

Use MCI_SET with caution because each set has the potential to take a considerable amount of time. For example, changing an audio attribute (such as bits per sample or samples per second), an force the device to load a digital signal processing (DSP) module, or change hardware registers. Therefore, when possible, combine several MCI_SET flags on the MCI_SET call. For instance, if you are changing audio attributes, change them all at once rather than with separate calls. Not only will this reduce the size of your code, but it will noticeably improve its speed.

Tip 8. Use the amp-mixer.

Every media control interface driver with audio support (such as the Digital Video) actually is connected to a mixer device. As a result, your program can perform sophisticated effects (such as balance control and volume fades) with each file that it loads. However, these commands cannot be sent directly to the original media control interface device. Your program must get the device ID of the amp-mixer that's connected to the original media control interface driver to execute the mixer functions (see Figure 3 and Figure 4). After you obtain the device ID of the amp, you can use these sophisticated effects.

open \mmos2\sounds\laser.wav alias a wait
connection a query type wave stream alias b wait
set b audio balance 0 wait
set b audio volume 100 wait

Figure 3. String interface commands to get Amp/mixer alias. Once the mixer's alias is obtained, the file's balance and volume attributes are changed.

Note: You also can send these strings from REXX (see Volume 2 of The Developer Connection News for more information on MMPM/2 and REXX).

USHORT usWaveID;
USHORT usAmpID;

MCI_CONNECTION_PARMS connparms;
MCI_AMP_SET_PARMS ampset;

connparms.ulConnectorType = MCI_WAVE_STREAM_CONNECTOR;

mciSendCommand( usWaveID,
                MCI_CONNECTION,
                MCI_QUERY_CONNECTION | MCI_WAIT,
                (PVOID) &connparms,
                0 );

usAmpID = connparms.usToDeviceID;

/* Set the audio balance to 0--all left */

ampset.ulValue = 0;

mciSendCommand( usAmpID,
                MCI_SET,
                MCI_SET_AUDIO | MCI_AMP_SET_BALANCE | MCI_WAIT,
                ( PVOID ) &ampset,
                0 );

/* Set the audio volume to 100 */

ampset.ulValue = 100;

mciSendCommand( usAmpID,
                MCI_SET,
                MCI_SET_AUDIO | MCI_SET_VOLUME | MCI_WAIT,
                ( PVOID ) &ampset,
                0 );

Figure 4. Command interface version of getting the device ID of the amp-mixer connected to a wave device.

Tip 9. Use playlist for performance and advanced functions.

If your program will only be playing an audio file and will not modify the file's data through record or clipboard operations, open or load the file with the MCI_READONLY flag. If MCI_READONLY is not specified, the media control interface driver initializes temporary files that your program does not use.

The digital-audio media control interface driver can not only play standard .wav, it also can play waveform data from memory buffers. Because less overhead exists in playing audio data from memory, playlist programs have higher performance. Therefore, if your application demands speed (for example, it must play a sound immediately after a control is processed), or if it needs to modify the audio data before it is sent to the audio device, use playlists.

Tip 10. Don't poll media control interface devices.

If you want to determine the current position of the device, don't poll it with a series of MCI_STATUS_POSITION messages. Instead, use MCI_SET_POSITIONADVISE or MCI_SET_CUEPOINT (see Maximizing the Audio Support in OS/2 2.1 in Volume 2 of The Developer Connection News for more information.) These commands will not only ease the burden on the CPU, but will result in more accurate positioning information for your application.

Summary

OS/2 has the ability to be the ultimate multimedia environment; but, for users to appreciate OS/2's power, each application must take advantage of the unique features in MMPM/2. If you follow the suggestions listed in this article, your program will not only maximize the 32-bit OS/2 environment but also gain the competitive advantage of successful applications!

About the Author

Linden deCarmo is a Senior Associate Programmer in Workplace OS multimedia development and has been with IBM since 1991. He is an active supporter of multimedia developers on Internet, CompuServe, and the IBM BBS. He can be reached at lad@vnet.ibm.com.

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