previous next

Chapter 5: File Format Plug-In

The first step in integrating your datatype into RealSystem is building a file format plug-in that converts your datatype into a stream of RealSystem packets. RealServer uses your plug-in to stream your datatype directly from its native file format. The RealSystem client then assembles the packets and displays the data through a rendering plug-in. Clients and tools can also use the file format plug-in to read files locally. RealPlayer, for example, uses the plug-in to read a file of your datatype saved to the client's local disk.

File Format Plug-in

A file format plug-in does not read files directly from disk or any other data source. It simply interacts with a file object given to it by RealSystem. The file object, which is created by a file system plug-in, provides a virtual file system with standard interfaces that the file format plug-in can use to perform read and seek operations without regard to the platform or storage device that holds the file.

Design Considerations

In addition to the general plug-in design considerations described in "Designing a Plug-In", keep the following points in mind as you develop your file format plug-in:

  1. Optimize the file format plug-in's CPU usage. RealServer creates a file format plug-in instance for each connected client. Plug-ins that use too much CPU can quickly degrade RealServer performance.

  2. Design your datatype to use Adaptive Stream Management (ASM) to adapt to changing network conditions dynamically. Your datatype should report as much information about itself as possible to ASM (for example, report the Average Bandwidth Standard Deviation). Also, you should use ASM to assign priorities to your packets so that RealServer can deliver them effectively and robustly over the Internet.

    Additional Information
    See "Chapter 11: Adaptive Stream Management".

  3. If serving a file request requires accessing multiple files, your file format plug-in can implement file cross-referencing in a catalog of its own design. It can then use the file object interfaces, particularly the relative file object methods, to load the necessary files for a requested URL.

    Additional Information
    See "Getting Relative File Objects".

    The alternative method is to make your file format a container datatype for the other datatypes. Content producers do not then need to keep track of multiple files for each presentation and the file format plug-in does not need to cross-reference URLs with file sets. Using a container file format eliminates the advantages of streaming from native file formats, however. RealSystem supports either implementation. This design choice is your decision.

Interfaces

A file format plug-in typically implements the following interfaces:

The file format plug-in may also implement the following interfaces, depending on which RealSystem features it needs to support or use:

Coding the Plug-In

The following sections explain how RealSystem (RealServer or client) and a file format plug-in use the RealSystem interfaces to stream data to a client. The sample files included with this SDK illustrate many of these features. You can use these sample files as a starting point for building your own plug-in. Refer to the RealSystem SDK header files for more information on function variables and return values.

Note
The order of function calls listed in the following sections provides a generalized explanation and is for illustrative purposes only. Because RealSystem is asynchronous, your plug-in must be able to handle any call made to it while it is processing data or waiting for a response from another object. Do not code your plug-in so that it expects a specific sequence of events to occur as it interacts with RealSystem.

Starting Up

When RealSystem starts up, it loads each file format plug-in:

  1. The system calls RMACreateInstance to create a new instance of the file format plug-in. The system calls this function at start-up and each time it receives a request for a file type handled by the plug-in.

    Additional Information
    See "Creating a Plug-In Instance" for more on this function.

  2. The system calls IRMAPlugin::GetPluginInfo, which returns descriptive information about the plug-in, including its copyright and "more information" URL. The bLoadMultiple attribute should be TRUE. This causes RealServer to launch multiple instances of the plug-in in separate processes. A RealSystem client using the file format plug-in ignores this attribute.

  3. The system calls IRMAFileFormatObject::GetFileFormatInfo, which returns functional information about the plug-in:

Initializing

When the system receives a request for a file, it identifies the appropriate file format plug-in based on the requested file's extension and the pFileExtensions values returned by the file format plug-ins during start-up. If two or more plug-ins handle the same file extension, the system uses the first plug-in for that file type that it loaded during start-up. The system then initializes the chosen plug-in:

  1. The system calls IRMAPlugin::InitPlugin, passing the file format plug-in a pointer to the system context. Within the IRMAPlugin::InitPlugin method, the plug-in should peform any necessary initialization. It should also use the system context pointer to store a reference to IRMACommonClassFactory so that it can later create RealSystem objects used to send data to the system.

  2. The system calls the file format plug-in's IRMAFileFormatObject::InitFileFormat method to pass it pointers to these interfaces:

  3. When the initialization finishes, the file object calls the file format plug-in's IRMAFileResponse::InitDone method to return a status code. Within this method, the plug-in notifies the system through IRMAFormatResponse::InitDone that its initialization has completed successfully or not.

    Additional Information
    See "Status Codes".

  4. Optionally, the file format plug-in can gather file information from the file object.

    Additional Information
    See "Retrieving File Information".

  5. The system calls IRMAFileFormatObject::GetFileHeader to get an object that contains the file header data. The plug-in must then use the file object interface to retrieve an IRMABuffer of this data. Because of its asynchronous nature, RealSystem uses several routines to complete this operation.

    Additional Information
    See "Interacting with a File Object" for more information.

  6. With the retrieved IRMABuffer data, the file format plug-in creates an IRMAValues interface that contains the file header data. This interface contains a value for the required property StreamCount, as well as any other opaque data the plug-in needs to send the renderer before sending the file streams.

  7. The plug-in calls the IRMAFormatResponse::FileHeaderReady method to pass the system a pointer to the file header object. It then uses IUnknown::Release to release the interface.

Creating Stream Headers

After sending the system the file header for the requested file, the file format plug-in sends it the stream headers for each stream in the file:

  1. The system calls the plug-in's IRMAFileFormatObject::GetStreamHeader method. The plug-in then uses the file object to get for each stream an IRMABuffer interface that contains the stream header data. Because of its asynchronous nature, RealSystem uses several routines to complete this operation.

    Additional Information
    See "Interacting with a File Object" for more information.

  2. With the IRMABuffer of the retrieved stream header data, the file format plug-in creates an IRMAValues interface that contains the stream header data. This interface contains any opaque data the plug-in needs to send to its renderer, as well as values for the properties listed in the following table

    Stream Header Properties
    Property Description Required?
    StreamNumber Number of this stream. Yes
    AvgBitRate Average number of bits streamed per second. Yes
    Duration Duration of this stream in milliseconds. Yes
    MimeType The stream MIME type, which the RealSystem client uses to associate the stream with the right renderer. Yes
    Preroll Number of milliseconds to buffer before starting the stream. No
    ASMRuleBook The rule book for Adaptive Stream Management (ASM). No
    MaxBitRate Maximum bit rate for the stream. No
    MaxPacketSize Maximum packet size for the stream. No
    AvgPacketSize Average packet size for the stream. No
    StreamName Name of the stream. No

    Note
    These stream header properties are used for both the RDT (RealSystem G2) and PNA (RealSystem 5.0 and below) packet formats. A plug-in that supports other packet formats such as RTP sets additional stream header properties. For more on this, see "Supporting Multiple Packet Formats".

  3. The plug-in calls IRMAFormatResponse::StreamHeaderReady to pass the system a pointer to the header object for each stream. It then uses IUnknown::Release to release each object.

  4. If ASM is used, the system calls the plug-in's IRMAASMSource::Subscribe method to indicate which rules for which streams the client has subscribed to.

    Additional Information
    See "Chapter 11: Adaptive Stream Management".

Creating Stream Packets

After receiving the stream header or headers, the system requests packets for each stream:

  1. The system calls the file format plug-in's IRMAFileFormatObject::GetPacket method to get the first packet for a stream. Because of the asynchronous nature of RealSystem, retrieving the packet data requires several routines.

    Additional Information
    See "Interacting with a File Object" for more information.

  2. With the retrieved packet data from each IRMAFileFormatObject::GetPacket call, the file format plug-in creates an IRMAPacket interface that contains the opaque data passed to the renderer, as well as values for the properties listed in the following table.

    Stream Packet Properties
    Property Description Required?
    deliveryTime Time stamp for the packet delivery. Yes
    streamNo Number of this stream. Yes
    ASMFlags When set to ASM_SWITCH_ON, indicates that an ASM rule change can occur on this packet. Only for packets where rule changes may occur.
    ASMRuleNo ASM rule number associated with this packet. Yes, when ASM is used.

    Additional Information
    See "Using IRMAPacket to Create Stream Packets" for the basics of packet creation. See also "Chapter 11: Adaptive Stream Management".

  3. The file format plug-in calls IRMAFormatResponse::PacketReady to pass the system a pointer to the packet interface. It then releases the packet interface with IUnknown::Release.

  4. When the system needs another packet, it calls IRMAFileFormatObject::GetPacket again and the above procedure repeats until the plug-in has delivered all packets. At that point the plug-in calls IRMAFormatResponse::StreamDone to notify the system that the stream has finished.

A file format plug-in should generally create packets of 430 to 500 bytes for the opaque data. Staying under 500 bytes decreases the likelihood of packet fragmentation. RealNetworks also recommends that you write code that lets the plug-in quickly change the size of the packets it sends.

For each stream, a file format plug-in should not accept requests for another packet or header until the previous request has been satisfied. The plug-in should return the status code PNR_UNEXPECTED if it receives an IRMAFileFormatObject::GetPacket or GetHeader() call before returning IRMAFormatResponse::PacketReady or HeaderReady() from the previous request. If the plug-in supports multiple streams, however, the plug-in must be able to support a IRMAFileFormatObject::GetPacket call for one stream while it is preparing a packet for another stream.

Additional Information
See "Status Codes".

Handling User Seeks

During a RealSystem presentation, the user may move the client slider to begin playing the presentation back from a different place in the timeline. When this happens, the system calls the file format plug-in's IRMAFileFormatObject::Seek method, passing the plug-in the requested time in milliseconds. The file format plug-in notifies the system of success or failure with IRMAFormatResponse::SeekDone.

In performing the seek, the file format plug-in needs to determine what packet to send and perform the necessary actions to prepare and send it. A plug-in for an audio datatype may need only to send the packet that corresponds to the current place in a new timeline. A plug-in for a video datatype, however, may have to locate the keyframe before the new timeline.

Additional Information
See "Interacting with a File Object" for more information on seeking and reading. "Creating Stream Packets" explains the packet creation procedures.

Closing

When the file playback has finished or is stopped, the system calls the plug-in's Close method. The plug-in must then release all references to objects and deallocate memory. This includes calling IRMAFileObject::Close for all file objects in use. When it releases the file resources, the file object returns a status code through IRMAFileResponse::CloseDone.

Additional Information
See "Status Codes".

Supporting Multiple Packet Formats

A file format plug-in can support packet formats in addition to the RealSystem default packet format of RDT. This lets the plug-in deliver its datatype to a client based on an standardized packet format. RealSystem currently supports the RTP (Real Time Protocol) packet standard. Supporting RTP also requires using the ASM Marker property.

Additional Information
See "RTP Marker Bit Property".

RealServer calls IRMAPacketFormat::GetSupportedPacketFormats to determine which formats the plug-in supports. The method returns a null-terminated list of supported formats ("rdt", "rtp", and so on). RealServer then calls IRMAPacketFormat::SetPacketFormat to inform the plug-in of the format to use. If the plug-in does not implement IRMAPacketFormat, RealServer assumes the plug-in supports only RDT.

RTP Stream Header Properties

In addition to the regular stream header properties, file format plug-ins supporting RTP need to set the header properties listed in the following table.

Stream Header Properties for RTP
Property Description Required?
RTPPayloadType Payload type number. See table below. Yes
SamplesPerSecond Number of samples per second. With dynamic RTP payload audio Codecs only.
Channels Number of channels. With dynamic RTP payload audio Codecs only.

The audio Codec properties allow the construction of an interoperable stream description called SDP, which allows RTP clients to play streams from dynamic payload types. The following table summarizes the supported RTP payload types.

RTP Payload Types
Property Description
0 RTP_PAYLOAD_PCMU
1 RTP_PAYLOAD_1016
2 RTP_PAYLOAD_G721
3 RTP_PAYLOAD_GSM
4 RTP_PAYLOAD_G723
5 RTP_PAYLOAD_DVI4_8
6 RTP_PAYLOAD_DVI4_16
7 RTP_PAYLOAD_LPC
8 RTP_PAYLOAD_PCMA
9 RTP_PAYLOAD_G722
10 RTP_PAYLOAD_L16_2CH
11 RTP_PAYLOAD_L16_1CH
14 RTP_PAYLOAD_MPA
15 RTP_PAYLOAD_G728
16 RTP_PAYLOAD_DVI4_11
17 RTP_PAYLOAD_DVI4_22
26 RTP_PAYLOAD_JPEG
31 RTP_PAYLOAD_H261
32 RTP_PAYLOAD_MPV
33 RTP_PAYLOAD_MP2T
34 RTP_PAYLOAD_H263

Additional Information
For more on payload types, refer to RFC 1890, which you can find on the IETF Web site at http://www.ietf.org/html.charters/avt-charter.html.

SDPData Header Property

The SDPData property in the file or stream header allows a file format or encoder to provide a direct input to the Session Description Protocol (SDP). This property also allows a renderer to receive the non-universal SDP attributes.

A file format plug-in can specify the SDPData String property as part of the stream and/or file header. The content of the SDPData must be a series of properly-formatted and properly-delimited SDP attribute records ("a=") — refer to RFC2327 for formatting requirements. The attribute records a=rtpmap and a=control are the exception and must not be specified as part of SDPData. The SDPData information is integrated in the SDP describe request response verbatim. If specified in the header file, it is appended to the session description; if specified in the stream header, it is appended to the media description.

On the client side, the reversal of this process occurs. RealPlayer or RealServer, when receiving packets from the encoder, places any non-universal (and thus not recognized by the transport layer) SDP attributes in the SDPData and passes it on in the file or stream header, depending on where the non-universal attributes are located — in the session or media description.

MIME Type

Even though a MIME type could conceivably assume any string, to enable interoperability it should follow the following format:


<media>/<encoding name>

Refer to RFC2327 for more information.

RTP Timing

The Real Media Architecture uses milliseconds as the integral unit of time. In RTP streaming, the time stamp might contain a non-integral number of milliseconds. This results in an aliasing effect when RTP time stamps are converted to milliseconds. The IRMARTPPacket interface can be used to avoid the aliasing effect and preserve the accuracy of RTP time stamps.

The IRMARTPPacket interface that is derived from IRMAPacket contains the IRMARTPPacket::GetRTP, IRMARTPPacket::GetRTPTime, and IRMARTPPacket::SetRTP methods. These methods are analogous to IRMAPacket::Get, IRMAPacket::GetTime, and IRMAPacket::Set, and provide for the addition of RTP time to the packet. The RTP time is scaled by Samples/Second, which a file format plug-in supporting RTP is required to specify using the SamplesPerSecond property:


<time in milliseconds> = 1000.0 * RTPTime / SamplesPerSecond

The RTP time stamps the RTP packet sent out by the server. The RealPlayer forms packets supporting the IRMARTPPacket interface whenever a packet is received through RTP. Thus the renderers can take advantage of the raw RTP time stamp if needed.

Note
The server is not using the RTP time for scheduling purposes. The standard packet time in milliseconds (RMA time) is the time the server uses as delivery time.

A packet supporting the IRMARTPPacket interface is required to implement IRMAPacket. Thus, the additional functionality of the IRMARTPPacket interface can be ignored if it is not needed. However, if a packet supporting IRMARTPPacket is set using the IRMARTPPacket::Set method, the RTP time of that packet is set to the same value as the standard RMA time (in milliseconds). This is significant since the server, when using RTP, uses packet RTP times stamps verbatim whenever the packet supports the IRMARTPPacket interface.

Note
If a stream contains a packet supporting the IRMARTPPacket interface, then all packets in the stream must support IRMARTPPacket.

Reporting Pending Status

Optionally, file format and file system plug-ins can implement IRMAPendingStatus to inform the RealSystem client of their pending operations. To learn the component's status, the client calls IRMAPendingStatus::GetStatus, which returns three parameters:

  1. uStatusCode

    This status code, which is not related to the system status codes, indicates the plug-in's current activity:

  2. pStatusDesc

    An optional pointer to an IRMABuffer interface that contains a text description of the current status. This buffer might contain, for example, the address of a host being contacted.

  3. ulPercentDone

    An integer value that represents the percentage of the task complete. This is used primarily for buffering. If the plug-in is contacting a host or initializing, the returned value is 0 when the operation is underway, 100 when complete. A percent done value for the RMA_STATUS_READY state is ignored.

Modifying the Response Headers

When a client requests a file, RealSystem generates a request object that contains the URL and the request headers. This object exists as long as the request is being served. A file format plug-in or a file object can send the client any information about the file by attaching response headers to the request object before RealServer begins to stream the file:

  1. During initialization, RealServer passes a file format plug-in a pointer to the request object. For a file object, RealServer calls IRMARequestHandler::SetRequest to pass the pointer to the file object.

  2. If necessary, the plug-in or file object can call IRMARequest::GetURL to get the fully qualified path for the requested file.

  3. The plug-in or file object creates an IRMAValues interface and adds the necessary response header values to the object.

  4. The plug-in or file object calls IRMARequest::SetResponseHeaders to give the request object a pointer to the values interface containing the response headers. (Multiple values interfaces can be associated with the request object.)

  5. If the connection is over HTTP, RealServer includes the response headers in the HTTP header section. Over RTSP, it gives the response headers to the client in an IRMAValues interface.

Interacting with a File Object

Instead of reading files directly, a file format plug-in accesses data through file objects created by a file system plug-in. RealSystem determines which file system plug-in to use and hands the file format plug-in a file object during initialization. The file format plug-in can then get file data through IRMAFileObject, receiving responses through IRMAFileResponse without needing to know the location or format of the file data.

Retrieving File Information

To retrieve the file object's name without any path information, the file format plug-in can call IRMAFileObject::GetFilename, which returns a pointer to the file name. The plug-in can use the request object to get the fully qualified path of the request URL.

Additional Information
See "Modifying the Response Headers".

If the file object implements IRMAFileStat, a file format plug-in can call the IRMAFileStat::Stat method, which passes the file object a pointer to the file statistics response object. The file object then gathers file statistics and returns them to the response object, which is typically the file format plug-in, through IRMAFileStatResponse::StatDone. Statistics include the following, which are defined in rmafiles.h:

Seeking File Data

When the file format plug-in receives an IRMAFileFormatObject::Seek, IRMAFileFormatObject::GetFileHeader, IRMAFileFormatObject::GetStreamHeader, or IRMAFileFormatObject::GetPacket call, it uses the IRMAFileObject interface to seek for and read the file through the file object. The following actions occur when a file format plug-in must perform a file seek:

  1. Before implementing the seek, the file format plug-in records its state so that it can respond to the proper context (IRMAFileFormatObject::GetFileHeader, IRMAFileFormatObject::GetStreamHeader, or IRMAFileFormatObject::GetPacket) when it receives notification that the seek has finished.

  2. The file format plug-in calls IRMAFileObject::Seek. This method takes a file offset value and a bRelative parameter that, when set to TRUE, specifies that the value is relative to the last seek. When set to FALSE, the bRelative parameter makes the seek an absolute offset.

  3. The file object responds to the file format plug-in with the status code PNR_OK or PNR_FAIL through IRMAFileResponse::SeekDone. Do not assume, however, that when a call to IRMAFileObject::Seek returns, IRMAFileResponse::SeekDone has been called.

    Additional Information
    See "Status Codes".

Reading File Data

The following actions occur after a seek has completed successfully:

  1. The file format plug-in records its state so that it can respond to the proper context (IRMAFileFormatObject::GetFileHeader, IRMAFileFormatObject::GetStreamHeader, or IRMAFileFormatObject::GetPacket) when the subsequent read action completes.

  2. The file format plug-in calls IRMAFileObject::Read, which takes a value for the length of the data buffer to read.

    Tip
    If the file header is extremely complex and requires several read calls to process, you may want to read the maximum size of the header in one read, and perform your parsing logic on the returned memory buffer. This allows you to use far fewer states in your state machine.

  3. The file object calls the file format plug-in's IRMAFileResponse::ReadDone method, returning a pointer to the IRMABuffer interface that contains the data. Do not assume, however, that when a call to IRMAFileObject::Read returns, IRMAFileResponse::ReadDone has been called.

  4. The file format plug-in calls its method that creates the file header, stream header, or packet object from the returned IRMABuffer interface.

Note the following about using IRMAFileObject::Read:

Closing a File Object

Before releasing a file object, the file format plug-in calls IRMAFileObject::Close to release resources associated with the object. The plug-in can then call IUnknown::Release.

Getting Relative File Objects

During initialization, the file format plug-in initializes a file object for the requested file. In addition, it can access another file or set of files in locations relative to that specified by the requested URL. It can even create additional file objects for the same file to, for example, access multiple streams in the file. Using the relative file object methods greatly reduces the amount of overhead the system performs when creating multiple file objects.

By implementing IRMAFileSystemManagerResponse, the file format plug-in can do the following to create relative file objects:

  1. The file format plug-in creates an IRMAFileSystemManager interface from the Common Class Factory. For example:
    
    m_pCommonClassFactory-CreateInstance(CLSID_IRMAFileSystemManager,
    (void**)&m_pFSManager);

  2. The file format plug-in calls IRMAFileSystemManager::Init, identifying itself as the response object.

  3. The file format plug-in calls IRMAFileSystemManager::GetRelativeFileObject, passing a pointer to the original file object and the relative path to the new file. For example, if the requested URL is for:
    
    /home/rmserver/rafiles/alanis.ra 
    

    and the new file is:

    
    /home/rmserver/rafiles/extra/alanis.rae 
    

    the relative path passed in IRMAFileSystemManager::GetRelativeFileObject is

    
    extra/alanis.rae 
    

    The relative path must contain a file name and, optionally, a subdirectory path. Hence the relative file must reside at or below the directory level of the original file. To create a new file object for the same file, the plug-in simply passes in the file name, which it can retrieve through IRMAFileObject::GetFilename, as the relative path.

  4. The file manager object calls the file format plug-in's IRMAFileSystemManagerResponse::FileObjectReady method, returning a pointer to the new file object.

    Note
    Do not try to create a second file object with the file manager object before the first file object is ready.

  5. The file format plug-in initializes the new file object by calling IRMAFileObject::Init as described above in "Initializing".

Using Multiple Relative Files

A file format plug-in can create a file object relative to another relative file object. With the simple file system (the basic file system used to locate files on RealServer or the client's local disks), all relative file objects are relative to the file object passed as a pointer in IRMAFileSystemManager::GetRelativeFileObject. The following example illustrates this:

  1. Suppose that the original file object points to this file:
    
    /home/rmserver/rafiles/alanis.ra 
    

  2. A relative object to the file extra/alanis.rae is then created to point to this path:
    
    /home/rmserver/rafiles/extra/alanis.rae 
    

  3. A third file object defined as alanis.bork is then created relative to the second file object. (That is, the IRMAFileSystemManager::GetRelativeFileObject method used to create the third object passes a pointer to the relative file object defined in the preceding step, as well as the path alanis.bork.) Because this file object is relative to the second file object, it points to this file:
    
    /home/rmserver/rafiles/extra/alanis.bork 
    

    Note, however, that this is not necessarily true for file systems other than the simple file system. Other file system plug-ins supported by RealSystem's virtual file system architecture may create the third file object relative to the first file object:

    
    /home/rmserver/rafiles/alanis.bork 
    

Modifying the File Format Plug-in Sample Code

The RealSystem SDK includes sample file format plug-ins that you can use as a starting point for building your own plug-in:

Carry out the following steps to modify either of the intermediate sample files. These steps assume your company name is "Foo Bar, Inc.", your file extension is ".foo", and the MIME type of your file format is "application/x-foobar".

  1. Copy the source code from the samples directory to a working directory.

  2. Change the file name and class names to match your file format name. For example, if you are implementing a Foo file format you might replace all occurrences of CExampleFileFormat with CFooFileFormat, and rename the files fooffpln.cpp and fooffpln.h.

  3. Change the plug-in description, copyright, and more information URL stored in zm_pDescription, zm_pCopyright, and zm_pMoreInfoURL. For the Foo example, you could change the values as follows:
    
    char* CFooFileFormat::zm_pDescription    = "Foo File Format Plug-in";
    char* CFooFileFormat::zm_pCopyright = "(c)1997 Foo Bar";
    char* CFooFileFormat::zm_pMoreInfoURL = "http://www.foobar.com";

  4. Change the file MIME type, extension, and Open File info stored in zm_pFileMimeTypes, zm_pFileExtensions, and zm_pFileOpenNames. For the Foo example, you could change the values as follows:
    
    char* CFooFileFormat::zm_pFileMimeTypes  = {"application/x-foobar", NULL};
    char* CFooFileFormat::zm_pFileExtensions = {"foo", NULL};
    char* CFooFileFormat::zm_pFileOpenNames = {"Foo File Format (*.foo)", NULL};

  5. Change the stream MIME type from application/x-pn-examplestream to the new value for your stream. The stream MIME type is usually the same as the file MIME type.

  6. If your file format is a container file format, such as QuickTime, it needs to create multiple streams of data packets. Change the StreamCount value in pHeader to the number of streams your plug-in creates. The sample ex2strms.cpp demonstrates this.

  7. Process your input data as needed to create RealSystem packets.

  8. Compile, debug, and test your plug-in.

    Additional Information
    "Compiling a Plug-In".


Copyright © 2000 RealNetworks
For technical support, please contact supportsdk@real.com.
This file last updated on 05/17/00 at 12:50:17.
previous next