Libquicktime dynamic codec interface

Programmed in 2002 by Burkhard Plaum (gmerlin_at_users.sourceforge.net)

1 Notes for application users
2 API extensions for application programmers
3. API for Codec developers
    3.1 Introduction
    3.2 Creating and deleting codecs
    3.3 Presenting ourselves to the outer world
    3.4 Passing codecs to libquicktime
    3.5 Encoding video
    3.6 Decoding video
    3.7 Encoding audio
    3.8 Decoding audio

1. Notes for application users

Libquicktime has dynamic codecs, which are installed in <prefix>/lib/libquicktime. Here, prefix is the same prefix, you used, when you compiled libquicktime (/usr/local by default). If you installed a binary package, you will find the plugins in /usr/lib/libquicktime. The plugin directory is currently hardcoded in the library and can only be changed by recompiling.

When your application tries to open a quicktime file with libquicktime, it will first search for the file .libquicktime_codecs in your home directory. Then it scans the plugin directory for files lqt_*.so. (The prefix lqt_ was choosen, to prevent confusion with regular shared libraries).

For all dynamic plugins, it checks, if they are in the database (.libquicktime_codecs). If they are not there, or if the dynamic plugin is younger, than the database entry, libquicktime opens the plugin and reads the information (name, capabilities of each codec etc) from the plugin. If the database entry however is still valid, the information is taken from the database to avoid the time consuming loading of the plugin. After the whole directory is scanned, the .libquicktime_plugins file is written with the updated codec data.

With this mechanism, you will always have the new codecs enabled automatically when you start a new libquicktime application. If your application supports it, you can even register new codecs without restarting the program (See below, how application programmers can implement this feature).

2. API extensions for application programmers

Libquicktime has a codec registry (see above) defined in a private linked list. It allows applications to build configuration dialogs for codecs dynamically at runtime depending on the codecs, the user has installed. This is necessary for the separate distribution of libquicktime codecs.

The registry  is initialized (using the method described above) by the first call of one of

  quicktime_supported_audio(),

  quicktime_supported_video(),

  quicktime_set_audio(),

  quicktime_set_video(),

when you write a file or

  quicktime_open()

when reading. If you want to access the codec database before calling one of these functions, call:

  lqt_init_codec_info();

to trigger the codec registration at a time of your choice. Your application can even rebuild the codec database at runtime. For this, call

  lqt_destroy_codec_info();

to destroy the registry and

  lqt_init_codec_info();

to rebuild it again. Calling only lqt_init_codec_info() after the registry is already initialized will do nothing. You always need to destroy the registry before bebuilding it. If your application is multithreaded, you should have a mutex in your application, which protects your codec database (Fixme: do this in libquicktime?).

Once the codec registry is initialized, get the number of available audio and video codecs by using:

  int lqt_get_num_audio_codecs();

  int lqt_get_num_video_codecs();

For each codec index (starting with zero), you can obtain an info structure with:

  const lqt_codec_info_t * lqt_get_audio_codec_info(int index);

  const lqt_codec_info_t * lqt_get_video_codec_info(int index);

These are the only functions, you should use to access the database. The returned structure is defined in lqt_codecinfo.h. The fields,
you might use in your program are:

  char * name;                   /* Name of the codec              */
  char * long_name;              /* Long name of the codec         */
  char * description;            /* Description                    */
  lqt_codec_type type;           /* LQT_CODEC_AUDIO or LQT_CODEC_VIDEO */
  lqt_codec_direction direction; /* LQT_DIRECTION_ENCODE,
                                    LQT_DIRECTION_DECODE or
                                    LQT_DIRECTION_BOTH */
  int num_fourccs;               /* Number of fourccs, this codec can handle */
  char ** fourccs;               /* Array of fourccs.                        */

  int num_encoding_parameters;   /* Number of encoding parameters            */

  /* encoding_parameters */

  lqt_codec_parameter_info_t * encoding_parameters;

  int num_decoding_parameters;   /* Number of decoding parameters */

  /* decoding_parameters */

  lqt_codec_parameter_info_t * decoding_parameters;

The other structure members are for internal use by libquicktime. You have 2 arrays for the encoding and decoding parameters. The parameter info structure is also defined in lqt_codecinfo.h:

typedef struct
  {
  char * name;      /* Parameter name (compatible with quicktime_set_parameter() )      */
  char * real_name; /* Parameter name for the world outside libquicktime                */
  lqt_parameter_type_t type; /* LQT_PARAMETER_INT or LQT_PARAMETER_STRING (maybe more?) */
  lqt_parameter_value_t val_default; /* default value (used when parameter is not set   */
  lqt_parameter_value_t val_min;
  lqt_parameter_value_t val_max;
  } lqt_codec_parameter_info_t;

The minimum and maximum values are only valid for numeric types and if val_min < val_max. If integer parameters have a minimum of 0 and a maximum of 1, they should be considered as boolean (applications will make a check button instead of a slider for this).

lqt_parameter_value_t is a union, which can carry values of different datatypes:

typedef union
  {
  int val_int;
  char * val_string;
  } lqt_parameter_value_t;

Currently, there is no codec with support for decoding parameters, but this might change in future versions.

3. API for Codec developers

3.1 Introduction

The codecs itself work the same way as quicktime4linux codecs. Several codecs (any combination of audio/video en- and decoders) can be in one shared module. How to define the codecs and how to write the interface functions for access by libquicktime is described here. For the codec interface specific parts of your module, you always need to include the file lqt_codecapi.h.

A quicktime codec is defined in qtprivate.h as:

typedef struct
  {
  int (*delete_vcodec)(quicktime_video_map_t *vtrack);
  int (*delete_acodec)(quicktime_audio_map_t *atrack);
  int (*decode_video)(quicktime_t *file, unsigned char **row_pointers, int track);

  int (*encode_video)(quicktime_t *file, unsigned char **row_pointers, int track);
  int (*decode_audio)(quicktime_t *file, int16_t *output_i, float *output_f, 
                      long samples, int track, int channel);
  int (*encode_audio)(quicktime_t *file, int16_t **input_i, float **input_f, 
                      int track, long samples);
  int (*reads_colormodel)(quicktime_t *file, int colormodel, int track);
  int (*writes_colormodel)(quicktime_t *file, int colormodel, int track);
  int (*set_parameter)(quicktime_t *file, int track, char *key, void *value);

  void (*flush)(quicktime_t *file, int track);

  void *priv;
  void *module; /* Needed by libquicktime for dynamic loading */
  } quicktime_codec_t;
The module pointer is used by libquicktime to dlclose() us, if we are not longer needed. It should not be touched. The functions pointers are your actual en- and decoding functions (how they are written and what they do is described below).

3.2 Creating and deleting codecs

The interface function, which creates one codec sets the members of the quicktime_codec_t structure to the functions defined in our module. It must be defined in the sourcecode for each codec separately.

Example: You have written a video codec blup, which keeps additional data in a structure blup_t. The structure is created by blup_create_codec() and destroyed by blup_delete_codec(). Your initialization function will look like this (if blup is a video codec):

void quicktime_init_codec_blup(quicktime_video_map_t *vtrack)
  {
  blup_t *codec = blup_create_codec();
  /* Init public items */
  ((quicktime_codec_t*)vtrack->codec)->priv = codec;
  ((quicktime_codec_t*)vtrack->codec)->delete_vcodec = delete_codec;
  ((quicktime_codec_t*)vtrack->codec)->decode_video = decode;
  ((quicktime_codec_t*)vtrack->codec)->encode_video = encode;
  ((quicktime_codec_t*)vtrack->codec)->reads_colormodel = reads_colormodel;
  ((quicktime_codec_t*)vtrack->codec)->writes_colormodel = writes_colormodel;
  ((quicktime_codec_t*)vtrack->codec)->set_parameter = set_parameter;
  }

The functions delete_codec(), encode(), decode(), reads_colormodel(), writes_colormodel() and set_parameter() should be defined in your source (ideally as static functions in the same sourcefile). If your codec has no parameters, you don't need to define set_parameter(). The function pointer is NULL by default and libquicktime won't try to set parameters then. For an audio codec, you set just set delete_acodec(), encode_audio(), decode_audio(), set_parameter() and flush(). Note that track->codec is defined as a void pointer in qtprivate.h (for whatever reason), so you always need to cast it to quicktime_codec_t. The priv member of the codec is for storing private data of the codec (like our blup_t).

Note:

The quicktime4linux codecs don't do any internal initialization in this function. Instead, the private codec structures have a flag, which is set to zero at at the beginning. Depending on this flag, the real initialization is then done at the beginning of the first call of one of the encoding or decoding functions. The reason for this could be, that it should be possible to call quicktime_set_parameter() after quicktime_set_audio() or quicktime_set_video() when writing or after quicktime_open() when reading.

When playback or encoding is finished a call to quicktime_close() will release all memory associated with the audio and video tracks of the file. For your codec, this will mean, that our delete_vcodec() or delete_acodec() are called. Since we have some private data allocated, we should free it then. The delete function will look like this for our blup video codec:

static int delete_codec(quicktime_video_map_t *vtrack)
  {
  blup_t *codec;

  codec = (blup_t*)(((quicktime_codec_t*)vtrack->codec)->priv);
  blup_delete_codec(codec);
  }

3.3 Presenting ourselves to the outer world

Libquicktime users now want to know something about the codecs contained in the module, e.g. their descriptions, parameters, your developer website etc. This is done by functions, which pass information structures to libquicktime. Imagine, you have written blup and blop (which share many routines, so they are in one module). You need to define some static data structures. These are the fourccs of each codec, the encoding parameters, the decoding parameters and structures for the other informations. These are defined as follows:

static char * fourccs_blup[]  = { "BLUP", "BLU1" };

static lqt_codec_info_static_t codec_info_blup =
  {
    "Blup",
    "Blup Video codec",                                       /* Long name of the codec */
    "Video codec based on the bluplet transform algorithm",   /* Description            */
    LQT_CODEC_VIDEO,
    LQT_DIRECTION_BOTH
  };

static lqt_codec_parameter_info_t encode_parameters_blup[] =
  {
     {
       "blup_bitrate",    /* Name for quicktime_set_parameter */
       "Bitrate",         /* Name for dialog boxes            */
       LQT_PARAMETER_INT, /* Type                             */
       {1000000 },        /* Default value                    */
       {0},               /* Minimum value                    */
       {0}                /* Maximum value                    */
     },
  };

static lqt_codec_parameter_info_t decode_parameters_blup[] =
  {
     {
       "blup_postprocess",     /* Name for quicktime_set_parameter */
       "Postpcocessing Level", /* Name for dialog boxes            */
       LQT_PARAMETER_INT,      /* Type                             */
       { 3 },                  /* Default value                    */
       {0},                    /* Minimum value                    */
       {5}                     /* Maximum value                    */
     },
  };

The lqt_codec_parameter_info_t structure (defined in lqt_codecinfo.h) is the same structure, which is exported into the library (see above). The lqt_codec_info_static_t structure (defined in lqt_codecapi.h) contains the members of lqt_codec_info_t, which can be initialized statically:

typedef struct
  {
  char * name;                   /* Name of the codec              */
  char * long_name;          /* Long name of the codec         */
  char * description;         /* Description                    */
  lqt_codec_type type;
  lqt_codec_direction direction;
  } lqt_codec_info_static_t;

Imagine you have similar structures defined for the blop codec also. You now need to program 2 functions, which pass this information to libquicktime. These look as follows:

extern int get_num_codecs() { return 2; }

extern lqt_codec_info_t * get_codec_info(int index)
  {
  switch(index)
    {
    case 0:
      return lqt_create_codec_info(&codec_info_blup,
                                   fourccs_blup,
                                   sizeof(fourccs_blup)/sizeof(char*),
                                   encode_parameters_blup,
                                   sizeof(encode_parameters_blup)/sizeof(lqt_codec_parameter_info_t),
                                   decode_parameters_blup,
                                   sizeof(decode_parameters_blup)/sizeof(lqt_codec_parameter_info_t),
                                   (const lqt_codec_parameter_info_t*)0,
                                   0);
    case 1:
      return lqt_create_codec_info(&codec_info_blop,
                                   fourccs_blop,
                                   sizeof(fourccs_blop)/sizeof(char*),
                                   encode_parameters_blop,
                                   sizeof(encode_parameters_blop)/sizeof(lqt_codec_parameter_info_t),
                                   (const lqt_codec_parameter_info_t*)0,
                                   0);
     }
  return (lqt_codec_info_t*)0; /* Keep gcc happy */
  }

The function get_num_codecs() is self explaining. The function get_codec_info() returns an lqt_codec_info_t structure as defined in lqt_codecinfo.h. To create this structure from your statically defined data, use this (lqt_codecapi.h):

lqt_codec_info_t *
lqt_create_codec_info(const lqt_codec_info_static_t * template,
                      char * fourccs[], int num_fourccs,
                      const lqt_codec_parameter_info_t * encoding_parameters,
                      int num_encoding_parameters,
                      const lqt_codec_parameter_info_t * decoding_parameters,
                      int num_decoding_parameters);

This function lets you create a dynamically allocated codec info structure, which will then inserted info the registry by libquicktime. All data are copied, and the allocated memory fill be freed by libquicktime. In the above example the blop codec has no paremeters for decoding. In this case, you can pass NULL for the parameter descriptions.

3.4 Passing codecs to libquicktime

When libqucktime wants to create a codec from the module, it calles one the following functions, which must be defined in the module:

extern lqt_init_video_codec_func_t get_video_codec(int index);
extern lqt_inif_audio_codec_func_t get_audio_codec(int index);

The return values are the same as the function prototypes, which create codes in quicktime4linux:

typedef void (* lqt_init_video_codec_func_t)(quicktime_video_map_t *);
typedef void (* lqt_init_audio_codec_func_t)(quicktime_audio_map_t *);

You need only one of these functions if your module has only audio or only video codecs. For the blup and blop codecs we would write the following:

extern lqt_init_video_codec_func_t get_video_codec(int index)
  {
  switch(index)
    {
    case 0:
      return quicktime_init_codec_blup;
    case 1:
      return quicktime_inif_codec_blop;
    }
  return (lqt_init_video_codec_func_t)0;
  }

The return values are the functions for creating single codecs as described above.

A note for all, who think, this is too complicated:

Remember the flexibility, we can have with this interface. We can port codecs between libquicktime and quicktime4linux by just adding/removing the libquicktime structures and functions described above. Since you must define the interface functions yourself, you can give them an arbitrary level of intellegence. The mjpa and jpeg codecs for example, share the functions and encoding parameters but have different names and descriptions. All this is possible.

3.5 Encoding video

This part is currently unknown to the author. Use the codec source to reseach this.

3.6 Decoding video

This part is currently unknown to the author. Use the codec source to reseach this.

3.7 Encoding audio

This part is currently unknown to the author. Use the codec source to reseach this.

3.8 Decoding audio

This part is currently unknown to the author. Use the codec source to reseach this.