MAD (Libmad) is an open source High-precision MPEG Audio Decoder library that supports MPEG-1 standards. Libmad provides 24-bit PCM output, fully fixed-point computing, and is ideal for use on embedded hardware platforms without floating-point support. The decoding of MP3 files can be achieved using a series of APIs provided by Libmad.
The "mad.h" header file defines the LIBMAD data structure and API functions [15].
Table 4 The main data structures in Libmad
Main data structure |
Role |
struct Mad_stream |
Storing bitstream data before decoding |
struct Mad_synth |
Storing the PCM data after decoding and synthesizing filtering |
struct MAD_PCM |
Defines the audio sampling rate, number of channels, and PCM sampling data to initialize the audio |
struct Mad_frame |
The data structure of PCM data after MPEG frame decoding is recorded, in which the Mad_header is used to record the basic information of MPEG frames, such as MPEG layer number, channel mode, stream bit rate and sampling bit rate. The channel mode includes mono, two-channel, combined stereo mixing channel and general stereo. |
Mad uses the callback function mechanism to decode, and each callback function returns an enumerated type Mad_flow, through which Mad_flow can control the decoding process. In the case of untreated, the mad general output 32bit, in little endian format stored in the mad_fixed_t data. But most of the sound card does not support output up to 32bit precision data, it must also be quantified, smooth processing and jitter, so that the sampling signal to 16bit precision mad_fixed_t. Mad is responsible for the decoding process, which works by obtaining input from the outside, decoding it by frame, returning information in the decoding process, and then getting the decoded result. Developers to manually set the input output.
The way to decode programmatically is to initialize Mad_decoder, which contains pointers to input, output, filtering, error, and message callback functions. Initialize [16] with the mad_decoder_init () implementation.
struct Mad_decoder decoder;
struct MY_PLAYBUF playbuf; Set data buffers
Mad_decoder_init (&decoder,&playbuf,input_func,header_func,/*filter*/0, Output_func,/*error*/0,/* message * * 0);
In this initialization function, the callback input function points to the Input_func, the function that handles the frame header information points to the Header_func, and the output function is Output_func. Other filtering, error and information functions are not set to 0.
Then, Mad goes into a decoding loop:
The Input_func function is called when decoding the data in the decoding function;
When the Input_func function tells the decoding function that all the data has been decoded, the mad processing exits;
Decoding the frame head and calling the Header_func function;
Decoding the main data in the frame;
Call the Filter_func function;
Will decode the data output, call the Output_func function;
Repeat the above steps.
At the end of each decoding of a frame, Mad asks the state of the mad_flow to determine whether the next frame will be decoded. The data structure of the enum Mad_flow is defined as follows:
Enum mad_flow{
Mad_flow_continue = 0x0000,/* Continue with the next frame decoding * *
Mad_flow_stop = 0x0010,/* Stop decoding the bit stream and exit normally * *
Mad_flow_break = 0x0010,/* Stop decoding the bit stream and return an error * *
Mad_flow_ignore = 0x0020/* Do not decode the frame, jump into the next frame * *
};
In most cases, the callback function returns MAD_FLOW_CONTINUE. The declaration format of the callback function to customize the implementation is:
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 *);
where the void * pointer passes buffered data to these callback functions, the data is processed by the callback function. The Input_func function typically performs the following actions:
if (more_data_available)
Buffer = Refill_buffer ();
Mad_stream_buffer (stream, buffer, length_of_buffer);
return mad_flow_continue;
else return mad_flow_stop;
The Header_func function reads important frame information from the frame header that the mad_header points to, such as assigning the read frame length to mad_timer_t, which can be learned from the mad.h of the data structure that holds the information.
In the Output_func function, use a pointer to the PCM data mad_pcm to perform something like the following:
mad_fixed_t *left_ch = pcm->samples[0], *right_ch =pcm->samples[1]; Output sampled data to left and right channels respectively
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);
Process the left and right channel sampling data, output 16bit little endian format PCM
}
Once you have defined each callback function, you can begin decoding:
Mad_decoder_run (&decoder, Mad_decoder_mode_sync);
After decoding, call Mad_decoder_finish (&decoder);
Libmad Profile <