OpenMPEG for OS/2 Offers New Support Software Audio, Buffered Play and Video CD

By Lauren Post

Volume 12 of the IBM Developer Connection delivers an updated release of the OpenMPEG for OS/2 Beta package that provides complete software playback of Motion Picture Expert Group (MPEG) multimedia files through an OS/2 subsystem for the first time. If you are running OS/2 Warp Version 4, you have everything you need to run the OpenMPEG for OS/2 Beta. If you are running OS/2 Warp Version 3, you need to install FixPak 26 before using OpenMPEG for OS/2.

This third release of the package includes the following new functions: This article addresses asynchronous buffer management and Video CD and CD-i support. Look for descriptions of other new OpenMPEG functions in future volumes of the IBM Developer Connection.
 * Software MPEG Audio support
 * Asynchronous buffer management
 * MPEG-2 Program streams support for MPEG hardware
 * MPEG-2 Transport streams support for MPEG hardware
 * Video CD support for playing multiple tracks
 * Video CD-i support using filename _VIDCDI.MPEG
 * Karaoke CD support
 * OpenMPEG Multiplatform specification changes
 * Software video enhancements
 * Multiple Instance support for simultaneous hardware and software playback
 * Single-stream support for single-stream hardware devices

Software Audio Support
The latest OpenMPEG Beta on Volume 12 contains complete software support for MPEG-1 movies which means anyone can now play MPEG as long as you have a sound card. In the past, special sound cards like MWAVE which could decompress MPEG audio in hardware were required to have audio support, but our latest version supports a software decoder to do this function. A limitation for software MPEG audio is that it will require a Pentium 90 MHz for reasonable frame rates. Anything lower (down to a 486 66MHz machine) will probably still play, but will have low frame rates and possible audio breakup. An interface is provided for changing the quality of the audio to three settings: low, medium and high, through environment variables. The current decoder defaults to a lower quality.

Buffered Play
Asynchronous buffer management makes OpenMPEG unique because, instead of just processing a file, the OpenMPEG engine can accept buffers and process them asynchronously. This capability is especially important for networking because, instead of downloading a movie, the movie can be streamed over a network and passed directly into OpenMPEG and to the hardware. Buffered play also is a helpful feature for anyone using interactive programming, such as game developers. Instead of passing seek commands throughout a game in progress (which can create much overhead), they can perform the I/O operations on an MPEG file internally and pass the buffers directly to OpenMPEG.

Buffered play was partially implemented in the OpenMPEG Beta version delivered in Volume 11 of the IBM Developer Connection, but on a synchronous level in which OpenMPEG accepted buffers but immediately returned them as consumed. In Volume 12, the engine has been updated to accept several buffers and use the buffer memory throughout until the buffer data has been entirely consumed.

The examples in this article show how to set up for buffered play, pass buffers to OpenMPEG, and process consumed buffers. These examples can be examined further in the SHOWOM1 sample program provided with OpenMPEG in the "Multimedia Category" of the DevCon for OS/2 (disc 2).

Setup for Buffered Play
Buffered play requires the OM1_BUFFERS flag in OM1OpenStream. When the OM1OpenStream is complete, the OpenMPEG engine is ready to start calling for buffers. However, no buffers are available until the OM1_BUF_READY state is set or until an OM1Play is issued. This means that no calls to query the size or information about the content can occur until a callback OM1_BUF_STREAM_OPEN is received. Below is sample code showing how to open a buffered stream and set the OM1_BUF_READY state.

Callback Procedure
The callback procedure is the most important feature of buffered play. The application uses this mechanism to provide the buffers to the OpenMPEG engine. The flow starts with the application telling OpenMPEG it is ready to send buffers with the OM1I_BUF_STATE index on OM1Set. On this thread, the OpenMPEG engine will call the callback procedure and request buffers until it has filled up its queue. For the application, it is important that the buffers are a minimum size or else OpenMPEG will not be able to process the MPEG content correctly.

Here is a list of the buffered play messages: The important messages to process in the callback are the OM1M_BUF_READY message, where the data is returned in a pointer to the OM1_BUF_DATA structure, and the OM1M_BUF_STREAM_OPEN message, where OpenMPEG notifies the application that it has received enough buffers and has enough data to start playback. At this time, the application can query OpenMPEG to get the height and width of the movie to set its own window size. When the stream has been entirely processed after playback, OpenMPEG will send an OM1M_BUF_STREAM_CLOSE message to notify the application that the stream is closed. When the stream is empty, OpenMPEG will send an OM1M_BUF_EMPTY message to notify the application that playback quality is jeopardized because the stream does not have enough data to process. This state happens primarily when the application does not return data on the OM1M_BUF_READY message.
 * OM1M_BUF_READY
 * OM1M_BUF_STREAM_OPEN
 * OM1M_BUF_STREAM_CLOSE
 * OM1M_BUF_EMPTY

The following callback procedure demonstrates buffered play notifications and completion notifications: ULONG APIENTRY Callback( BYTE msg, BYTE hStream, ULONG MessageValue ) { OM1_GET_INPUTGetInput; OM1_GET_OUTPUTGetOutput; ULONGulPosition; switch (msg) { case OM1M_COMPLETED: if (MessageValue == OM1_PLAY) { /* Play is done so close the stream instance */ /* and destroy the window */ OM1Close (hStream); }  break;

case OM1M_BUF_READY: /* The OpenMPEG engine is requesting a buffer to  /* If an empty buffer exists, then read from the file into if (!(om1BufData[usBufIndex].pBuffer)) { ulBytesRead = fread(FileBuffer[usBufIndex],                     1,                      BUFFER_SIZE,                      hFile); /* No data can be read so return NULL */ if (ulBytesRead == 0) return ((ULONG)NULL); /* Prep the om1BufData structure that will be returned om1BufData[usBufIndex].BufferSize = ulBytesRead; om1BufData[usBufIndex].pBuffer = (PBYTE) FileBuffer[usBufIndex]; om1BufData[usBufIndex].BytesToCallback = ulBytesRead; om1BufData[usBufIndex].BufferID = usBufIndex; om1BufData[usBufIndex].Flags = 0; pom1_buf = &om1BufData[usBufIndex];

/* The application uses the usBufIndex to manage its /* a circular fashion. It must check when it has reached /* end of the array and loop back to the beginning */ usBufIndex++; if (usBufIndex >= NUM_BUFFERS) usBufIndex = 0; /* The buffer is passed to OpenMPEG in the return field*/ return((ULONG) pom1_buf); } else { /* No data is available to pass so a NULL is returned */ return((ULONG)NULL); }/* endif */ break;

case OM1M_BUF_CONSUMED: /* A buffer has been consumed so it can now be  /* Later this buffer can be reused on the pom1_buf = (POM1_BUF_DATA) MessageValue; om1BufData[pom1_buf.BufferID].pBuffer = NULL; break;

case OM1M_BUF_STREAM_OPEN: if (!MessageValue) { /* The stream was opened successfully and the now /* can query OpenMPEG for the size */ GetInput.Index = OM1I_VID_SIZE; ulReturn = OM1Get ( hStream, &GetInput, &GetOutput); ulWidth = GetOutput.Output & 0xffff; ulHeight = GetOutput.Output 16; WinPostMsg ( hwndFrame, WM_COMMAND, (PVOID)ID_SNAP, 0L ); fOpen = TRUE; } else { /* An error occurred and the stream could not be  return ( FALSE ); } /* endif */ break;

case OM1M_BUF_STREAM_CLOSE: /* The stream has closed, so the application should fclose(hFile); break; } return 0; }

Video CD and CD-i Support
Another new function available in the this release of OpenMPEG is the Video CD and CD-i support. CD-i type CDs are actually unreadable since they are similar to music CDs. However, we have provided the support to play a Video CD by passing the dummy file name _VIDCDI.MPG. OpenMPEG uses the dummy file name as a key to query the CD drive for a CD-i CD.

The documentation contains a new mode, OM1F_VIDEOCD. When this mode is specified in OM1OpenStream, it notifies OpenMPEG that a Video CD is to be played. As a result, OpenMPEG will play all the tracks on a Video CD without requiring the user to change to the CD drive, go to the MPEGAV directory, and select the last file. If you use the time format OM1F_TRACKS, you can seek to different tracks. This also applies to music video CDs like karaoke.

What We Are Working on Next
Our objective in the next release of OpenMPEG is to have better performance so that higher frame rates can be obtained with a complete software solution. Our goal is to give everyone the opportunity to use OpenMPEG in our final delivery. The buffered play support in OpenMPEG provides important functionality for networking and interactivity.

We value any feedback you can give us about this beta release of the OpenMPEG subsystem. If you have any comments about the beta, please let us know through the IBM forums or in the OS2DF1 Multimedia section on CompuServe.