]> git.sesse.net Git - vlc/blobdiff - doc/mad/API
* ./modules/*: moved plugins to the new tree. Yet untested builds include
[vlc] / doc / mad / API
diff --git a/doc/mad/API b/doc/mad/API
new file mode 100644 (file)
index 0000000..83a8731
--- /dev/null
@@ -0,0 +1,262 @@
+MAD API documentation collected from e-mails of Joe Drew and Rob Leslie.
+The original e-mails can be found in the docs directory. They contain the
+same information as is presented below.
+
+INDEX
+======
+1. I/O Synchronous Mode
+2. Low-level API
+
+
+
+1. I/O SYNCHRONOUS MODE (extract from Joe Drew)
+===============================================
+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 32-bit (well, mad_fixed_t) little-endian data. 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.
+
+Now, the 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_func, 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_func, 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,
+       quit
+decode the header and call header_func
+decode the mpeg audio data
+call the filter function
+call the output function
+loop
+
+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:
+
+enum mad_flow {
+  MAD_FLOW_CONTINUE = 0x0000, /* Keep decoding this stream */
+  MAD_FLOW_STOP     = 0x0010, /* Stop decoding this stream, but exit
+                                normally */
+  MAD_FLOW_BREAK    = 0x0011, /* Stop decoding this stream, and exit
+                                 with an error */
+  MAD_FLOW_IGNORE   = 0x0020  /* 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_CONTINUE;
+else
+  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 =
+pcm->samples[1];
+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
+
+mad_decoder_finish(&decoder);
+
+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. :)
+
+
+2. LOW-LEVEL API (extract from Rob Leslie)
+==========================================
+
+By way of clarification, MAD also has a low-level API which does not use
+callbacks. You can control the entire decoding process yourself more or less
+as follows:
+
+  /* load buffer with your MPEG audio data */
+
+  mad_stream_buffer(&stream, buffer, buflen);
+
+  while (1) {
+    mad_frame_decode(&frame, &stream);
+    mad_synth_frame(&synth, &frame);
+
+    /* output PCM samples in synth.pcm */
+  }
+
+This is vastly simplified, but it shows the general idea. mad_frame_decode()
+decodes the next frame's header and subband samples. mad_synth_frame() takes
+those subband samples and synthesizes PCM samples.
+
+It is also possible to call mad_header_decode() before mad_frame_decode().
+This just gives you the frame's header info, in case that's all you want, or
+perhaps to help you decide whether you want to decode the rest of the frame.
+
+As Joe mentions, each of the stream, frame, and synth structs needs to be
+initialized and "finished" before and after use:
+
+  struct mad_stream stream;
+  struct mad_frame frame;
+  struct mad_synth synth;
+
+  mad_stream_init(&stream);
+  mad_frame_init(&frame);
+  mad_synth_init(&synth);
+
+  /* ... */
+
+  mad_synth_finish(&synth);
+  mad_frame_finish(&frame);
+  mad_stream_finish(&stream);
+
+You can work with just a struct mad_header instead of a struct mad_frame if
+you only want to decode frame headers.
+
+Joe writes:
+> MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take
+> this into account when outputting samples to the sound card.
+
+This isn't quite right: the mad_fixed_t type is not necessarily little-endian.
+It's the same endianness as the native integer types. Also, it's only
+guaranteed to be *at least* 32 bits wide.
+
+The fixed-point sample format is important to understand, and I recommend
+reading the comments in libmad/fixed.h. The thing to remember when converting
+MAD's fixed-point integer samples to 16-bit PCM (or whatever) is that MAD
+encodes samples as numbers in the full-scale range [-1.0, +1.0) where the
+binary point is placed 28 (MAD_F_FRACBITS) bits to the left of the integer.
+However, you need to be prepared to handle clipping as some numbers may be
+less than -1.0 (-MAD_F_ONE) or greater than or equal to +1.0 (MAD_F_ONE, aka
+1 << MAD_F_FRACBITS).
+
+> 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.
+
+In the high-level API, the error callback function is called whenever a
+decoding error occurs. The error number is in stream->error.
+
+The filter callback function is called after decoding a frame, but before
+synthesis. Here it is possible to modify the frame's subband samples, for
+example to perform a uniform attenuation/amplification, or to do other special
+processing in the frequency domain.
+
+The message callback function is only used with MAD_DECODER_MODE_ASYNC, and is
+called whenever the parent process sends a message via mad_decoder_message().
+This callback can generate a reply by overwriting the message buffer that is
+passed to it. (The size of the reply must be the same or smaller than the
+message.)
+
+
+
+