一、概述
1.libmad介绍
MAD (libmad) is a high-quality MPEG audio decoder. It currently supports
MPEG-1 and the MPEG-2 extension to Lower Sampling Frequencies, as well as
the so-called MPEG 2.5 format. All three audio layers (Layer I, Layer II,
and Layer III a.k.a. MP3) are fully implemented.
MAD does not yet support MPEG-2 multichannel audio (although it should be
backward compatible with such streams) nor does it currently support AAC.
MAD has the following special features:
- 24-bit PCM output
- 100% fixed-point (integer) computation
- completely new implementation based on the ISO/IEC standards
- distributed under the terms of the GNU General Public License (GPL)
2.libao介绍
libao is a cross platform audio library that allows program to output audio using a simple API on a wide varity of platform. It currently supports:
. Null output (handy for testing without a sound device)
. Wav files
. AV files
. OSS (open sound system, used on linux and freebsd)
. ALSA (advanced linux sound archiecture)
. PulseAudio (next generation GNOME sound server )
. esd (EsounD or enlightened sound daemon)
. AIX
. Sun/ NetBSD/OpenBSD
. IRIX
. NAS (network audio server)
二、源代码说明
libmad附带了一个示例程序minimad, 但是仅仅是将解码结果输出到屏幕上,而libao则是基于OSS、ALSA等之上的音频高级API,可以将pcm输出,通过多种方式播放出来,因此将两者结合起来,编写一个可以播放mp3的程序。
编译用的脚本
#!/bin/bash
gcc -o minimad minimad.c -I . -lmad -lao -lm
~
改进后的源代码清单
# include <stdio.h>
# include <unistd.h>
# include <sys/stat.h>
# include <sys/mman.h>
# include "mad.h"
#i nclude <ao/ao.h>
#i nclude <math.h>
/*
* This is perhaps the simplest example use of the MAD high-level API.
* Standard input is mapped into memory via mmap(), then the high-level API
* is invoked with three callbacks: input, output, and error. The output
* callback converts MAD's high-resolution PCM samples to 16 bits, then
* writes them to standard output in little-endian, stereo-interleaved
* format.
*/
static int decode(unsigned char const *, unsigned long);
static void myplay();
ao_device *device;
ao_sample_format format;
int default_driver;
int main(int argc, char *argv[])
{
struct stat stat;
void *fdm;
//gn add begin
ao_initialize();
// -- Setup for default driver --
default_driver = ao_default_driver_id();
format.bits = 16;
format.channels = 2;
format.rate = 44100;
format.byte_format = AO_FMT_LITTLE;
// -- Open driver --
device = ao_open_live(default_driver, &format, NULL );
if (device == NULL) {
fprintf(stderr, "Error opening device.n");
exit (1);
}
//gn add end
if (argc != 1)
return 1;
if (fstat(STDIN_FILENO, &stat) == -1 ||
stat.st_size == 0)
return 2;
fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, STDIN_FILENO, 0);
if (fdm == MAP_FAILED)
return 3;
decode(fdm, stat.st_size);
if (munmap(fdm, stat.st_size) == -1)
return 4;
//gnadd begin
//myplay();
ao_close(device);
ao_shutdown();
//gnadd end
return 0;
}
/*
* This is a private message structure. A generic pointer to this structure
* is passed to each of the callback functions. Put here any data you need
* to access from within the callbacks.
*/
struct buffer {
unsigned char const *start;
unsigned long length;
};
/*
* This is the input callback. The purpose of this callback is to (re)fill
* the stream buffer which is to be decoded. In this example, an entire file
* has been mapped into memory, so we just call mad_stream_buffer() with the
* address and length of the mapping. When this callback is called a second
* time, we are finished decoding.
*/
static
enum mad_flow input(void *data,
struct mad_stream *stream)
{
struct buffer *buffer = data;
if (!buffer->length)
return MAD_FLOW_STOP;
mad_stream_buffer(stream, buffer->start, buffer->length);
buffer->length = 0;
return MAD_FLOW_CONTINUE;
}
/*
* The following utility routine performs simple rounding, clipping, and
* scaling of MAD's high-resolution samples down to 16 bits. It does not
* perform any dithering or noise shaping, which would be recommended to
* obtain any exceptional audio quality. It is therefore not recommended to
* use this routine if high-quality output is desired.
*/
static inline
signed int scale(mad_fixed_t sample)
{
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
/*
* This is the output callback function. It is called after each frame of
* MPEG audio data has been completely decoded. The purpose of this callback
* is to output (or play) the decoded PCM audio.
*/
static void myplay()
{
char *buffer;
int buf_size;
int sample;
float freq = 440.0;
int i;
buf_size = format.bits/8 * format.channels * format.rate;
buffer = calloc(buf_size,
sizeof(char));
for (i = 0; i < format.rate; i++) {
sample = (int)(0.75 * 32768.0 *
sin(2 * M_PI * freq * ((float) i/format.rate)));
/* Put the same stuff in left and right channel */
buffer[4*i] = buffer[4*i+2] = sample & 0xff;
buffer[4*i+1] = buffer[4*i+3] = (sample >> 8) & 0xff;
}
ao_play(device, buffer, buf_size);
}
struct audio_dither {
mad_fixed_t error[3];
mad_fixed_t random;
};
/*
* NAME: prng()
* DESCRIPTION: 32-bit pseudo-random number generator
*/
static inline
unsigned long prng(unsigned long state)
{
return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
}
/*
* NAME: audio_linear_dither()
* DESCRIPTION: generic linear sample quantize and dither routine
*/
inline
signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample,
struct audio_dither *dither)
{
unsigned int scalebits;
mad_fixed_t output, mask, random;
enum {
MIN = -MAD_F_ONE,
MAX = MAD_F_ONE - 1
};
/* noise shape */
sample += dither->error[0] - dither->error[1] + dither->error[2];
dither->error[2] = dither->error[1];
dither->error[1] = dither->error[0] / 2;
/* bias */
output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
scalebits = MAD_F_FRACBITS + 1 - bits;
mask = (1L << scalebits) - 1;
/* dither */
random = prng(dither->random);
output += (random & mask) - (dither->random & mask);
dither->random = random;
/* clip */
if (output > MAX) {
output = MAX;
if (sample > MAX)
sample = MAX;
}
else if (output < MIN) {
output = MIN;
if (sample < MIN)
sample = MIN;
}
/* quantize */
output &= ~mask;
/* error feedback */
dither->error[0] = sample - output;
/* scale */
return output >> scalebits;
}
enum mad_flow output(void *data,
struct mad_header const *header,
struct mad_pcm *pcm)
{
register int nsamples = pcm->length;
mad_fixed_t const *left_ch = pcm->samples[0], *right_ch = pcm->samples[1];
static unsigned char stream[1152*4]; /* 1152 because that's what mad has as a max; *4 because
there are 4 distinct bytes per sample (in 2 channel case) */
static unsigned int rate = 0;
static int channels = 0;
static struct audio_dither dither;
register char * ptr = stream;
register signed int sample;
register mad_fixed_t tempsample;
/* We need to know information about the file before we can open the playdevice
in some cases. So, we do it here. */
if (pcm->channels == 2)
{
while (nsamples--)
{
signed int sample;
sample = scale(*left_ch++);
// sample = (signed int) audio_linear_dither(16, tempsample, &dither);
stream[(pcm->length-nsamples)*4 ] = ((sample >> 0) & 0xff);
stream[(pcm->length-nsamples)*4 +1] = ((sample >> 8) & 0xff);
sample = scale(*right_ch++);
stream[(pcm->length-nsamples)*4+2 ] = ((sample >> 0) & 0xff);
stream[(pcm->length-nsamples)*4 +3] = ((sample >> 8) & 0xff);
}
ao_play(device, stream, pcm->length * 4);
}
else /* Just straight mono output */
{
while (nsamples--)
{
signed int sample;
sample = scale(*left_ch++);
stream[(pcm->length-nsamples)*2 ] = ((sample >> 0) & 0xff);
stream[(pcm->length-nsamples)*2 +1] = ((sample >> 8) & 0xff);
}
ao_play(device, stream, pcm->length * 2);
}
return MAD_FLOW_CONTINUE;
}
/*
* This is the error callback function. It is called whenever a decoding
* error occurs. The error is indicated by stream->error; the list of
* possible MAD_ERROR_* errors can be found in the mad.h (or
* libmad/stream.h) header file.
*/
static
enum mad_flow error(void *data,
struct mad_stream *stream,
struct mad_frame *frame)
{
struct buffer *buffer = data;
fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %un",
stream->error, mad_stream_errorstr(stream),
stream->this_frame - buffer->start);
/* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
return MAD_FLOW_CONTINUE;
}
/*
* This is the function called by main() above to perform all the
* decoding. It instantiates a decoder object and configures it with the
* input, output, and error callback functions above. A single call to
* mad_decoder_run() continues until a callback function returns
* MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
* signal an error).
*/
static
int decode(unsigned char const *start, unsigned long length)
{
struct buffer buffer;
struct mad_decoder decoder;
int result;
/* initialize our private message structure */
buffer.start = start;
buffer.length = length;
/* configure input, output, and error functions */
mad_decoder_init(&decoder, &buffer,
input, 0 /* header */, 0 /* filter */, output,
error, 0 /* message */);
/* start decoding */
result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
/* release the decoder */
mad_decoder_finish(&decoder);
return result;
}