The Codec Interface (CPI)

Note: Some information presented here may be slightly out of date, as the specifications and code underneath all this is still somewhat a moving target. If you find something here which doesn't look right, please do not be too alarmed, as it may just need updating.
Last Updated: Sept 24, 2002

UCI codecs are implemented as shared libraries conforming to the following specifications:

  1. The name of the shared library is "codec_type_name.extension", where type indicates the type of codec (currently defined types are "audio" and "video"), name is the name of the codec, and extension is the standard shared library extension for the platform on which it is intended to run ("so" for most unix platforms). extension can optionally also include other versioning information or extensions as per the convention for the platform (such as ".so.0", etc), with the stipulation that it must still be separated from the name using a period ("."). (for example, "codec_video_foo-12.so" is not a valid codec library name, but "codec_video_foo.-12.so" or "codec_video_foo.v-12.so" would be, if such a convention needed to be used). On platforms which use SONAMEs or similarly embed the library name within the library file, such names should be the same as the filename, to avoid confusion and linking errors.

    Note that it is illegal to have two codecs installed in a given system with the same type and name which implement the same version of the UCI interface (interface_version in the codec_info structure returned by the library's codec_get_info function). It is only allowed to have codecs with the same type and name if they are used to implement different interface versions (for backwards compatibility). In this case, extension should have appropriate versioning information to keep the filenames and SONAMEs different between the different versions of the codec library.

  2. The shared library is located in one of the defined directories for codec libraries. This can vary according to system configuration, but by default the UCI library will check all of the normal shared library directories (as defined by /etc/ld.so.conf or other appropriate configuration files) for subdirectories named "codecs", and look in any such subdirectories it finds. This behavior can be modified or completely changed in /etc/uci.conf, however.

  3. The shared library must export the following functions (as defined elsewhere in this document):

  4. If the codec supports encoding, the shared library must export the following functions (as defined elsewhere in this document):

  5. If the codec supports decoding, the shared library must export the following functions (as defined elsewhere in this document):

It is assumed that these shared libraries will normally be thin interfaces to the actual codec implementation, which is stored in a separate library. As there are some situations where numerous codec interface libraries will be loaded and unloaded without actually needing to use the codecs themselves (such as when scanning codec_info structures), it is reccomended if possible to use demand-loading or explicit dlopen calls (in codec_init), etc, to link to the actual codec code libraries, such that the entire codec implementation (and any supporting libraries, and so on) does not need to be loaded into memory unless an application actually indicates its intention to use the codec.

General Codec Functions

const codec_info *codec_get_info(void)

Return a codec_info structure describing this codec. codec_init is not required to be called before calling this function.

The codec_info structure:

  typedef struct {
    int interface_version;
    char *name;
    char *short_description;
    char *long_description;
    codec_type_t codec_type;
    int flags;

    int num_formats;
    codec_format_info formats[];
  } codec_info;

'interface_version' indicates the version of the codec interface implemented by this codec. This should be set to CODEC_INTERFACE_VERSION.

'name' is the brief, unique name identifying this codec. This should be the same as the codec name used in the shared library filename.

'short_description' is a brief (less than 60 chars, one line) description of the codec, such as "The Foo Group's MPEG4 codec". This should not have any line-terminators at the end of it.

'long_description' is a longer description of the codec. This can contain multiple lines and has no length limit (it is reccomended this be kept under a screen's worth of text, however). This can contain any number of newline ('\n') characters, and should be terminated with a single newline.

'codec_type' is an integer value indicating the type of codec implemented by this library. Currently supported values are CODEC_TYPE_VIDEO or CODEC_TYPE_AUDIO.

'flags' contains a set of bitmapped flags for the codec, which may be one or more of the following (bitwise ORed together):

CODEC_MULTICALLABLE
This indicates that multiple encoding or decoding sessions can be used by the same thread at the same time (by alternating calls to encode_data/decode_data/etc).
CODEC_MT_SAFE
This indicates that the codec can be called by multiple threads from the same process simultaneously. Note that this is not the same as CODEC_MULTICALLABLE, as this involves additional reentrancy requirements (the process may be inside encode_data/decode_data (or other functions) multiple times simultaneously). It is also theoretically possible for a codec to be CODEC_MT_SAFE while not being CODEC_MULTICALLABLE (if it can only have one active session per thread, but supports multiple threads), although this is a rather peculiar and non-reccomended configuration.

'num_formats' contains the number of entries in the following 'formats' array.

'formats' is an array of codec_format_info structures describing the encoded formats this codec supports:

  typedef struct {
    int id;
    char *name;
    char *short_description;
    int flags;

    codec_fmt_identifier *idents;

    codec_param_def *encode_init_paramdef;
    codec_param_def *encode_paramdef;
    codec_param_def *decode_init_paramdef;
    codec_param_def *decode_paramdef;
  } codec_format_info;
  typedef struct {
    int id_type;
    char *data;
  } codec_fmt_identifier;

id_type can be one of:

CODEC_FMTID_FOURCC
(video) data points to a (VfW-style) FourCC code (4 bytes)
CODEC_FMTID_DSHOW
(video/audio) data points to a DirectShow GUID (16 bytes)
CODEC_FMTID_MCF
(video[/audio?]) data points to a text string containing an MCF-style format identifier (length unknown, zero-terminated)
CODEC_FMTID_ACM
(audio) data points to an ACM-style format code (2 bytes)

int codec_init(codec_instance *cinst)

Will be called before any other functions (except for codec_get_info). This function should perform any setup required to actually use the codec (loading additional libraries, setting up global structures, etc).

This function will only be called once per process.

This function should return CODEC_STATUS_OK if initialization was successful, or an error code otherwise. If an error code is returned, no further calls to this codec will be made.

void codec_end(codec_instance *cinst)

This function will be called when all use of this codec has been finished. It should clean up any resources allocated in codec_init or in other calls to this codec.

Encoding Functions

codec_avail_format *encode_supported_formats(codec_instance *cinst, codec_params *iparam)

Return a structure indicating the list of raw data formats in which this codec can take data to be encoded. If "iparam" is provided, this function should return a list of formats which are compatible with the initialization parameters specified. "iparam" may be NULL, in which case this function should return a list which indicates all formats available for any combination of initialization parameters. Formats whose availability may vary depending on initialization parameters should be indicated as such by setting CODEC_RAWFMT_SELECTED_AVAIL in the flags associated with that entry. If valid data is provided for "iparam", it is illegal to return any entries with CODEC_RAWFMT_SELECTED_AVAIL set. In the case where the codec supports the same set of input formats regardless of any initialization parameters, this function should return the same data regardless of what is passed to it in "iparam".

All video codecs must support at least one of the following raw formats:

All audio codecs must support at least one of the following raw formats:

Codecs may support more than one of these formats (and in fact are encouraged to do so if it can be done easily), as well as any number of other standard or nonstandard formats for communicating with applications.

int encode_init(encode_session *sess, codec_params *iparam)

This function is called to begin an encoding session with the provided parameters. It should return CODEC_STATUS_OK on success or an error code otherwise. On successful completion, the codec should fill in appropriate values for the following members of the encode_session structure:

  typedef struct {
    codec_instance *cinst;
    int format;
    void *reserved;  // Used for storing UCI internal data (don't touch!)

    // Session information filled in by encode_init
    size_t min_raw_buffer_size;
    size_t max_raw_buffer_size;
    size_t encode_buffer_size;
    size_t stream_header_size;
    char *stream_header;
    void *codec_data;
  } encode_session;

min_raw_buffer_size/max_raw_buffer_size - This indicates the minimum and maximum amount of raw data that can be handled by one call to encode_data. For video codecs, these should both be set to the size of one frame.

encode_buffer_size - This should contain the minimum size of buffer which is guaranteed to hold max_raw_buffer_size's worth of encoded data.

stream_header and stream_header_size - If the encoding format needs a "header" to be stored in the file to contain format parameter information, stream_header should point to the data structure that should be stored for this purpose. stream_header_size contains the size of the structure to write. If this data is allocated from the heap, it should be freed later by encode_end.

codec_data - This pointer can be used to point to any codec-internal data associated with this session, or otherwise identify the session to the codec. Its contents are private to the codec.

int encode_data(encode_session *sess, codec_data *in, codec_data *out, codec_params *eparam, codec_params *eresults)

  typedef struct codec_data_st {
    int flags;
    int buffer_id;
    char *buffer;
    size_t data_begin;
    size_t data_end;
    void (*unlock_func)(void *);
    void *unlock_data;
  } codec_data;

flags can be one or more of the following:

CODEC_DATAFLAG_LOCKABLE
The codec is allowed to lock this buffer if it so desires, as per the Buffer Locking Protocol
CODEC_DATAFLAG_LOCKED
This buffer has been locked. If a codec ever receives a buffer with this flag set, it is not allowed to modify its contents. This flag may be set by the codec prior to return (if the LOCKABLE flag is set) if it wishes to lock the buffer for its own future use.
CODEC_DATAFLAG_DATA_VALID
This buffer contains data to be processed, or data resulting from processing. Should be set by the codec on output buffers prior to returning, unless the encode/decode call did not result in any output data. The codec should clear this bit on input buffers iff all of the provided data has been used by the encode/decode process.
CODEC_DATAFLAG_METADATA
This buffer contains stream metadata (data which does not itself represent audio/video data (and thus, for example, is not actually part of any video frame), but pertains to the other data in the stream (an example of this is information indicating a change in encoding tables/parameters/etc which a decoder would need to be aware of in order to properly decode future data). This flag should be considered advisory only. Some stream encapsulations may not be able to interpret or preserve this information, so the codec should not rely on this flag being correctly set on input, or preserved on output.
CODEC_DATAFLAG_MORE_DATA
More data is available to be returned. The application should call the encode/decode function again (without CODEC_DATAFLAG_DATA_VALID on input) to retrieve it.

int encode_end(encode_session *sess)

Decoding Functions

codec_avail_format *decode_supported_formats(codec_instance *cinst, codec_params *iparam)

int decode_init(decode_session *sess, codec_params *iparam)

int decode_data(decode_session *sess, codec_data *in, codec_data *out, codec_params *dparam, codec_params *dresults)

int decode_end(decode_session *sess)

Buffer Locking Protocol

[This needs to be documented]

Todo

The following issues may still need to be considered in greater detail: