mirror of
https://code.videolan.org/videolan/vlc
synced 2024-10-07 03:56:28 +02:00
19ea8feb6d
waveout, directx, qnx, beos, win32, macosx, and the AltiVec modules. * ALL: removed mention of AC3 in favour of A52. * ./configure.in, ./Makefile*: modules can now be built deeper than 1 directory. As a consequence, the build is even slower (but I'm fixing this) and make clean doesn't work anymore.
175 lines
6.4 KiB
Plaintext
175 lines
6.4 KiB
Plaintext
Subject: [mad-dev] Some information about programming with MAD (in synchronous mode)
|
|
|
|
As the author of mpg321, I too faced the problem of MAD not being
|
|
documented. However, in looking at minimad.c, and re-writing mpg321 to
|
|
use MAD, I came to understand it better. Here's some information which
|
|
will help anybody start out with MAD:
|
|
|
|
First, some 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 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. :)
|
|
|
|
--
|
|
Joe Drew <hoserhead@woot.net> <drew@debian.org>
|
|
|
|
Please encrypt email sent to me.
|