High-Level API

With the high-level API, after callbacks are configured, a single routine will decode an entire bitstream.

Joe Drew < hoserhead at woot net > posted this interesting message on maddev mailing list: http://www.mars.org/mailman/public/mad-dev/2001-October/000369.html

Most of the following is picked from it.

basic information

MAD operates with callbacks for functions. Each of these functions is expected to return type enum mad_flow ; this allows you to control the decoding process.

MAD always outputs mad_fixed_t data (which is only guaranteed to be *at least* 32 bits wide, and in the same endianness as the native integer types). Take this into account when outputting samples to the sound card.

Related to the above, since MAD outputs type mad_fixed_t, unless you can output with 32-bit accuracy (most sound cards can't), you will have to quantize, round, dither, etc these samples to 16-bit (or whatever you need.) While there is a sample routine in minimad.c, if you want good quality you'll either want to roll your own or take a look in madplay's sources.

Integral to understanding MAD

MAD is a decoding library only. You handle input and output; you're responsible for fast-forwarding and rewinding, if you want that type of functionality. All that MAD will do is take input from you, decode the MPEG frames, give you some information about them, and give you the decoded PCM data.

nitty-gritty information

First, you need a mad_decoder struct. This holds all information about how you want your stream decoded, such as input/output functions, error handling functions, etc.

mad_decoder_init() sets this structure up for you.

 struct mad_decoder decoder;
 struct my_playbuf playbuf;
 mad_decoder_init(&decoder, &playbuf, input_func, header_func,
                 /*filter*/ 0, output_func, /*error*/ 0, /* message */ 0);

In this example, the function called to get more data is set to input_callback, the function called after MPEG headers have been decoded is header_func, the function called after all sound data has been decoded to PCM (for output) is output_callback, and the filter, error, and message functions are unset.

Now, MAD runs in a constant decoding loop. It runs something along the following lines:

    if I'm out of data
    	call input_func
    if input_func says there's no more data,
    decode the header and call header_func
    decode the mpeg audio data
    call the filter function
    call the output function

Now, this is an oversimplification obviously. The important thing to realise is that at every step of the process you can tell MAD what to do.

Since all of these functions return enum mad_flow, you can tell MAD to do any of the following:

Keep decoding this stream
Stop decoding this stream, but exit normally
Stop decoding this stream, and exit with an error
Don't decode this frame, but continue afterwards

Most of the time you'll probably want to return MAD_FLOW_CONTINUE. In every case, you'll have to return one of these values from the functions you define.

This is the definition of each of the functions:

 enum mad_flow (*input_func)(void *, struct mad_stream *);
 enum mad_flow (*header_func)(void *, struct mad_header const *);
 enum mad_flow (*filter_func)(void *, struct mad_stream const *, struct
 mad_frame *);
 enum mad_flow (*output_func)(void *, struct mad_header const *, struct
 mad_pcm *);
 enum mad_flow (*error_func)(void *, struct mad_stream *, struct
 mad_frame *);
 enum mad_flow (*message_func)(void *, void *, unsigned int *);

In each of these functions the void* pointer passed to the function is your "playbuf" structure. This can hold whatever you want - for example, song title, length, number of frames - just remember to re-cast it to the type you've defined.

input_func takes a mad_stream pointer. Most of the time what you'll want to do is something along the lines of the following:

 if (more_data_available)
   buffer = refill_buffer();
   mad_stream_buffer(stream, buffer, length_of_buffer);
   return MAD_FLOW_STOP;

(On many systems you'll want to use mmap() for this.)

header_func takes a mad_header pointer. This contains most of the important information about a given frame; in constant bitrate files, it can contain most of the important information about the stream. It will give you the length of that frame, using mad_timer_t; the audio layer; extension; bitrate... the list is long. Read frame.h or mad.h in the frame.h area for more information. Again, return MAD_FLOW_{CONTINUE,STOP,BREAK} depending on outside conditions.

The only other function I have firsthand information on is output_func; in this case, you are given a pointer to struct mad_pcm. This gives you the sampling rate, number of channels, and number of samples per channel; doing something like the following should work:

 mad_fixed_t *left_channel = pcm->samples[0], *right_channel =
 int nsamples = pcm->length;
 signed int sample;
 unsigned char * buffer = some_buffer;
 unsigned char * ptr = buffer;
 while (nsamples--)
             sample = (signed int) do_downsample(*left_ch++)
             *ptr++ = (unsigned char) (sample >> 0);
             *ptr++ = (unsigned char) (sample >> 8);
             sample = (signed int) do_downsample(*right_ch++)
             *ptr++ = (unsigned char) (sample >> 0);
             *ptr++ = (unsigned char) (sample >> 8);
 output buffer to device.

Be sure to handle the big-endian case (autoconf can test for this), and also the mono (1 channel) case. See mad.c in mpg321, at the end of the file, for an example.

Information on the other (error, filter, message) functions would be appreciated, though I think in knowing this information anyone should be able to puzzle it out.

Now that the decoder is set up with all these callback functions, you call

 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
and then

Once you've called mad_decoder_finish, you can re-use the decoder struct, if you're, for example, within a playlist. Incidentally, all MAD structures have similar mad_(whatever)_init and mad_(whatever)_finish functions.

I hope this helps people get their feet wet with MAD. Read the source, and particularly mad.h - there are a lot of things there you might not expect. Rob has done a good job in making MAD a complete solution. :)

See also:
Low-Level API

Generated on Tue Jun 10 12:14:18 2008 for libmad by  doxygen 1.5.5