This document is a practical description of a working draft for the libogg 0.98 library interface. Comments to xiphmont@mit.edu (especially from application developers!) are welcome.
Most recent update: May 8 1996
This document is copyright (C) 1996 Xiphophorus. Xiphophorus and OggSquish are trademarks (tm) of the Xiphophorus company. All rights reserved.
This document, as well as the specification, preserved in its entirety without modification, may be freely distributed.
After the engine has been properly set up by loading one or more scripts and setting any additional adjustments, such as specifying restrictions on memory usage, the engine can be used. The encapsulated engine functions on blocks of data, and passes back new data blocks after processing the input. Libogg does not perform any stream or file handling internally, but can return information to the application in a form directly useful for file or stream I/O.
The second step of setting up the engine is to tweak any number of settings available to the application that influence the operation of the OggSquish engine. These settings are chosen by modifying the contents of an ogg_settings structure (defined in libogg.h) and submitting it to the engine with ogg_settings_submit(). The settings may be changed at any time, but most will take effect only when resetting the engine or loading a new program script.
Several readable variables are also available to the application that allow it to properly set up its own behavior. Most notable among these are ogg_errno which reports error numbers (and ogg_strerr which points to a string version of the error). In addition, the application may query the output buffers to determine specifics about the output data (eg, during decompression, the application might want to know the output audio's sampling rate or number of channels). Output buffer information is available after a script or header is loaded.
ogg_script_parse(char *program) is used to submit a compression or decompression script to the engine. An entire script need not be submitted at once, but my be submitted piecewise using multiple calls to ogg_script_parse. Once parsed, the script is then assembled by the Ogg engine, and the ogg_script_ready variable flag is set. ogg_script_use(int scriptnum) can then be called to 'burn' the program into the engine for immediate use (also setting ogg_run_ready), or calling ogg_script_makeheader(char **buffer,long *bytes) would return the script in header form for use as a complete bitstream header.
ogg_script_reset(void) will reset the parser at any time. An implicit reset is performed after ogg_script_use() and ogg_script_makeheader().
Submit headers to the engine by loading the beginning of a bitstream into a character array and passing it to the engine using ogg_script_loadheader(char *buffer,int bytes). The return value will be how many bytes of the input buffer was read; the next bitstream submission should begin at the first unread byte. Positioning and memory management of buffers submitted to and returned by the Ogg engine are up to the application. Submitted buffers should be allocated and freed by the application, and returned buffers should be freed by the application. The only exception to this rule are strings pointed to by global variables (such as ogg_strerr); these strings point to static strings in the Ogg engine. See Memory Management in the API spec for more details.
If the submitted buffer was long enough and the header was loaded successfully, ogg_errno will be cleared and ogg_script_ready will be set. The engine can the be burned in using ogg_script_use() or saved to a different bitstream using ogg_script_makeheader().
If the submitted buffer is not long enough, ogg_errno will be cleared and ogg_script_ready will also be cleared. In this case, ogg_script_loadheader() must be called again with another data block (the data already submitted is buffered; the next submission should be the next block of data, not a longer block starting at the original position).
The return value of ogg_script_loadheader() (the number of bytes read) will not necessarily be equal to the number of bytes even when the submitted block is not long enough; always check the return value to see where libogg expects the next block to begin!
If some error occurred during loading, ogg_errno and ogg_strerr will be set to appropriate values, and ogg_script_ready will be cleared. An error during the loading process implicitly resets the parser/loader. Any subsequent header (or script) submissions must start at the beginning.
ogg_settings_get(struct ogg_settings *s) is used to place a copy of the current engine settings into the passed structure. New settings are requested by submitting on ogg_settings structure to the engine using ogg_settings_submit(struct ogg_settings *s).
Settings are only guaranteed to take effect after a program change (ie, after a call to ogg_script_use()).
Currently, the only settings of interest are ogg_memory and ogg_precision. See a copy of the API specification for a description of the ogg_settings struct and these fields.
The OggSquish engine is designed to be able to use different input streams simultaneously (for example, an input stream for raw audio and another for raw video). For this reason, using the engine is not as straightforward as passing a buffer into a function call and using a buffer returned from that call.
OggSquish input buffers are named; that is, the OggScript program is written to expect specific data to be available from certain buffers. Audio applications will typically only make use of the primary input buffers ogg_dsp_in, ogg_dsp_out, ogg_bit_in and ogg_bit_out (defined in both libogg.h and , by default, in the OggScript assembler). Note: Although flexible, this setup could be abused by the OggScript programmer to send data or read data from nonstandard places that applications cannot possibly expect. Buffers have intended uses that must be adhered to; the standard buffers and their uses are described in the formal specification.
If only one script (eg, decompression) is being used, then the application need not concern itself with multiscripting. However, the OggSquish interpreter in libogg is also capable of using more than one script as if multiple independent copies of the interpreter were available. The different interpreter 'banks' are selectable using ogg_run_set; care must be taken however, to be certain the applications is using the interpreter bank it intends to.
In most other cases, however, the application cannot determine by itself how much data to submit to the engine, for example when submitting raw data or input bitstreams in an unbroken file form. The application should query the engine using ogg_input_query(int buffer) to determine the safe minimum amount of data to submit to the buffer.
This value should be queried for each submission; submitted data that is not used in one frame will be buffered for use in the next. Submitting less than the requested amount of data (except in the case of EOF; more later) can cause a later error. Submitting more than the requested amount of data is safe, but the engine will need to allocate memory to buffer the excess; consistently submitting too much data will cause the allocation of more and more buffer space each frame. If the engine currently has enough data buffered, it could answer the submission query with a request for 0 values.
Any buffered data can be cleared from any input buffer using ogg_input_reset(); this is recommended between dealing with frames of packetized data that each store a single whole frame to avoid inadvertently losing synchronization in the case that a packet is the wrong length.
(NOTE: The submission size hint is actually set by the OggScript program and must be carefully chosen by the OggScript programmer).
The dynamic range of an Ogg bitstream is set in the OggScript program, however; submitting a 32 bit wide data array to a program explicitly using an internal resolution of 16 bits will not result in 32 bits of headroom. The data will either be scaled to fit 16 bits if 'scale' is set or truncated to fit 16 bits if scale is not set.
When dealing with prepacketized input data or any case where the exact blocksize is known, the exact amount of data may be submitted; otherwise submit the minimum recommended amount. If less than the minimum recommended amount is available for submission (for example, the very end of a non-packetized bitstream), it may be submitted and used; if the engine tries to read past the end of a submission, the engine will return an out of data error.
After the call completes, the various output buffers will be ready for reading, and each input buffer's data request values will be updated. In addition, if the bitstream terminates with the processing of this frame, the ogg_run_ready flag will be cleared. (Note that when submitting the last available data to input buffers, the data may require more than one frame to completely consume; the ogg_run_ready flag should be checked to make certain that the bitstream successfully terminated).
If left unread, an output buffer will be cleared during the next call to ogg_run.
(NOTE: Most advanced modern operating systems, such as SUN Solaris and Linus Torvald's Linux, will allocate pages of memory for malloc() calls even if virtual memory is exhausted; this results from a 'lazy allocation' scheme which is arguably correct behavior for an OS. In this case, memory is allocated, but when accessed results in a SIGSEGV; Ogg traps this SIGSEGV and returns it as a 'Virtual memory error'. Less advanced systems, such as MS Windows, tend to return NULL from malloc requests that fail due to insufficient memory.)
Ogg behavior after an error differs depending on the function call in which the error occurred; specific descriptions given in the formal function call description documentation. As a rule, the function calls other than ogg_run() simply abort and leave engine state unchanged.
If an error occurs during ogg_run(), the engine simply aborts processing at the point the error occurred (clearing ogg_run_ready and setting the error flag). This leaves the engine in an indeterminate state that should be reset with ogg_run_reset() or ogg_run_clear().
At the moment, there is no way to continue from the exact point of an error that occurs during ogg_run() processing. Arguably, this behavior is sufficient; the only cases in which a runtime error can occur would either make continuing impossible or result in at least some data loss:
DeskFish WWW Server / Address comments to: xiphmont@cs.titech.ac.jp