LIBMAD+ALSA implementation of ARM MP3 playback

Source: Internet
Author: User
Tags bz2

2015-10-10 18:42:55
Original

Libmad is an open source MP3 decoding library, lightweight and efficient, MPlayer also use this library to decode MP3. ALSA (Advanced Linux Sound architecture) is a kernel component in Linux that provides voice device drivers to replace the original open sound system (open Sound system,ossv3). In addition to sound device drivers, ALSA also contains a library of user-space functions to facilitate developers using advanced APIs to use drive capabilities without having to interact directly with kernel drivers.
With these two powerful tools, it can be implemented on the ARM board to play MP3 function. Of course, the board must have the amplifier.

1. Download libmad-0.15.1b.tar.gz in http://www.linuxfromscratch.org/blfs/view/svn/multimedia/libmad.html.
Download alsa-lib-1.0.29.tar.bz2 in Http://www.alsa-project.org/main/index.php/Download

2. Extract it
Tar-xvz-f libmad-0.15.1b.tar.gz
Tar-xvj-f alsa-lib-1.0.29.tar.bz2

3. Cross-Compile installation Libmad
Into the directory after Libmad decompression, to configure, where the library's installation directory set to/usr/local/libmab/mad, compiled tools with ARM-LINUX-GCC
./configure Cc=arm-linux-gcc–host=arm-linux–disable-shared–disable-debugging–prefix=/usr/local/libmab/mad

Then install:
Make
Make install
If make has an error: error:unrecognized command line option "-fforce-mem", locate the "-fforce-mem" string in makefile and delete it.
Re-make&make Install
The Include and Lib two directories will then appear under the specified installation directory/usr/local/libmab/mad
Copy the mad.h in the include directory to the Include directory in the compiler ARM-LINUX-GCC directory, I'm here/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/ include/
Copy the LIBMAD.A and libmad.la files in the Lib directory to the Lib directory under the compiler ARM-LINUX-GCC directory, I'm here/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi /lib/

After this is deployed, add header files to the program # include ' Mad.h '
Compile-time plus options-lmad
You can use Libmad in your program to decode it.

4. Cross-Compile installation Alsa-lib
Into the alsa-lib after the decompression of the directory, to configure, where the library installation directory set to/usr/local/arm-alsa, compiled tools with ARM-LINUX-GCC
./configure Cc=arm-linux-gcc–host=arm-linux–prefix=/usr/local/arm-alsa
And then install
Make
Make install
Several directories, including include and Lib, appear under the specified installation directory/usr/local/arm-alsa.

Copy the Alsa folder in the Include directory to the Include directory in the compilation tool ARM-LINUX-GCC directory.

In the Lib directory, the files except the Pkgconfig folder are copied to the Lib directory of the compilation tool ARM-LINUX-GCC directory.

After this is deployed, add header files to the program # include ' Alsa/asoundlib.h '
Compile-time plus options-lasound
You can use the ALSA driver to play audio in your program.

5. The next step is the actual test.
Using Libmad API to decode a MP3 of the general flow of the site http://m.baert.free.fr/contrib/docs/libmad/doxy/html/high-level.html the above is very clear, the exact words are:
The need a mad_decoder struct. This holds all information about how to want your stream decoded, such as input/output functions, error handling function s, etc.

Mad_decoder_init () Sets this structure to 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 be set to Input_callback, the function called after MPEG headers hav E been decoded is Header_func, the function called after all sound data has been decoded to PCM (for output) is output_cal Lback, 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 ' no more data,
    quit decode the header and
Cal L Header_func
decode the MPEG audio data call the "filter function" Call the
output function
loop

Now, this is a oversimplification obviously. The important thing to realise was that in every step of the process of your can tell MAD what to do.
It probably means: first, create a mad_decoder structure to install the options you want to decode this time, such as which input function you want to use, which output function, and so on. Then the input function, output function and so on decoding need to use the callback function is written, as the API function Mad_decoder_init parameters. Mad_decoder_init will deposit this information into the Mad_decoder structure (the construction of this structure can be seen on this site, which is described in detail).

Set well then you can call the Mad_decoder_run function to decode it. The process is as simple as that.
The internal loop of the Mad_decoder_run function is as follows:

If this part of the decoding is done,
Call the input function and load the next piece of data in
If all the decoding is done,
Exit
Decode the head, then call the header function, output header information, which contains the number of channels, sampling rate and other information
Decode this piece of data
Calling the filter function
Call output function
Continue looping

By modifying functions such as header,input,output, you can fully control the decoding process.
-– Translation completed-–

Of course, the actual application will not be so simplified, there are some initialization or release of work to do, Libmad official gave a minimad.c example, can decode MP3 output. The following ALSA_MINIMAD.C is a minimad.c based on the ALSA call, so that the decoded data output to the amplifier, while the volume can be controlled.
ALSA_MINIMAD.C: Divided into three parts, main function, ALSA settings, Libmad settings

Click (here) to collapse or open

# include <stdio.h> # include <unistd.h> # include <sys/stat.h> # include <sys/mman.h> # include & Lt;sys/fcntl.h> # include "Mad.h" # include "alsa/asoundlib.h" static int decode (unsigned char const *, unsigned long
);
int SET_PCM ();
void Set_volume (long volume); snd_pcm_t* Handle=null;
  PCI device handle snd_pcm_hw_params_t* params=null;//hardware information and PCM stream configuration int main (int argc, char *argv[]) {struct STAT stat;

  void *FDM;
    if (argc!= 3) {printf ("Usage:minimad + MP3 file name + volume\n");
    return 1;
  int FD;
  Fd=open (ARGV[1],O_RDWR);
    if (fd<0) {perror ("Open file failed:");
  return 1; } if (Fstat (fd, &stat) = =-1 | |
    Stat.st_size = = 0) {printf ("Fstat failed:\n");
  return 2;
  } FDM = mmap (0, Stat.st_size, Prot_read, map_shared, FD, 0);


  if (FDM = = map_failed) return 3;
        if (SET_PCM ()!=0)//set PCM parameter {printf ("set_pcm fialed:\n");
    return 1;
    } set_volume (Atoi (argv[2)); Decode (fDM, stat.st_size);

    if (Munmap (FDM, stat.st_size) = = 1) return 4;
    Snd_pcm_drain (handle);

  Snd_pcm_close (handle);
return 0; }//---------------------------------------------------------------------------//alsa set correlation function int SET_PCM () {int RC
    ;
    int dir=0; int rate = 44100;; /* Sampling frequency 44.1khz*///int format = Snd_pcm_format_s16_le; /* Quantization number of digits/int channels = 2;
    /* Channel number 2 */Rc=snd_pcm_open (&handle, "Default", Snd_pcm_stream_playback, 0);
      if (rc<0) {perror ("\nopen PCM device failed:");
    Exit (1); } snd_pcm_hw_params_alloca (&params); Assign params struct rc=snd_pcm_hw_params_any (handle, params);//Initialize params if (rc<0) {perror ("\nsnd_pcm_hw_p
      Arams_any: ");
    Exit (1); } rc=snd_pcm_hw_params_set_access (handle, params, snd_pcm_access_rw_interleaved);
      Initialize access permission if (rc<0) {perror ("\nsed_pcm_hw_set_access:");
    Exit (1); } rc=snd_pcm_hw_params_set_format (Handle, PARams, Snd_pcm_format_s16_le);
      Set 16-bit sampling precision if (rc<0) {perror ("Snd_pcm_hw_params_set_format failed:");
    Exit (1); } rc=snd_pcm_hw_params_set_channels (handle, params, channels);
      Set the channel, 1 for single sound > channel, 2 for Stereo if (rc<0) {perror ("\nsnd_pcm_hw_params_set_channels:");
    Exit (1); } rc=snd_pcm_hw_params_set_rate_near (handle, params, &rate, &dir);
      Set > Frequency if (rc<0) {perror ("\nsnd_pcm_hw_params_set_rate_near:");
    Exit (1);
    rc = Snd_pcm_hw_params (handle, params);
      if (rc<0) {perror ("\nsnd_pcm_hw_params:");
    Exit (1);
return 0;
  } void Set_volume (long volume) {snd_mixer_t *mixerfd;
  Snd_mixer_elem_t *elem;
  Long Minvolume = 0,maxvolume = 100;
  int result;
        Open the mixer if (result = Snd_mixer_open (&AMP;MIXERFD, 0)) < 0) {printf ("Snd_mixer_open error!\n");
   MIXERFD = NULL; //Attach an HCTL to a opened mixer if (result = Snd_mixer_attAch (mixerfd, "Default")) < 0) {printf ("Snd_mixer_attach error!\n");
        Snd_mixer_close (MIXERFD);
   MIXERFD = NULL; //Register Mixer if (result = Snd_mixer_selem_register (MIXERFD, NULL, NULL)) < 0) {printf ("snd_mixer_selem_
        Register error!\n ");
        Snd_mixer_close (MIXERFD);
  MIXERFD = NULL;
        ///Load Mixer if ((Result = Snd_mixer_load (MIXERFD)) < 0) {printf ("snd_mixer_load error!\n");
        Snd_mixer_close (MIXERFD);
  MIXERFD = NULL; }//Traversal mixer element for (Elem=snd_mixer_first_elem (MIXERFD); Elem Elem=snd_mixer_elem_next (Elem)) {if (snd_m Ixer_elem_get_type (elem) = = Snd_mixer_elem_simple && snd_mixer_selem_is_active (elem))//Find available, activated E
            Lem {snd_mixer_selem_get_playback_volume_range (Elem, &minvolume, &maxvolume);
        Snd_mixer_selem_set_playback_volume_all (Elem, volume);
} snd_mixer_close (MIXERFD); }




////////////Libmad Set Correlation function * * This is a private message structure. A generic pointer to this structure * are passed to each of the callback functions.
 Put this any data for your need * to access from within the callbacks.
  * * struct Buffer {unsigned char const *start;
unsigned long length;

}; * * * is the input callback. The purpose of this callback are to (re) fill * The stream buffer which are to decoded. In this example, a entire file * has been mapped into memory, so we just call Mad_stream_buffer D length of the mapping.
 When this callback are 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 the MAD ' s high-resolution samples down to bits. It does not * perform any dithering or noise shaping, which would is recommended to * obtain any exceptional audio ity.
 It is therefore the recommended to * use this routine if high-quality the 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 on each frame of * MPEG audio data has been completely decoded.
 The purpose of this callback * are to output (or play) the decoded PCM audio. */static enum Mad_flow output (void *data, struct mad_header const *header, struct MAD_PCM *pcm ) {unsigned int nchannels, nsamples,n;

  mad_fixed_t Const *LEFT_CH, *right_ch;
  /* Pcm->samplerate contains the sampling frequency * * Nchannels = pcm->channels;
  N=nsamples = pcm->length;
  Left_ch = pcm->samples[0];

  Right_ch = pcm->samples[1];
  unsigned char output[6912], *outputptr;


   int FMT, wrote, speed, exact_rate, err, dir;

   Outputptr = Output;

    while (nsamples--) {signed int sample;

    /* Output sample (s) in 16-bit signed Little-endian PCM */sample = scale (*left_ch++);
    * (outputptr++) = sample >> 0;
    * (outputptr++) = sample >> 8;
            if (nchannels = = 2) {sample = scale (*right_ch++);
            * (outputptr++) = sample >> 0;
        * (outputptr++) = sample >> 8;
    } outputptr = Output;
    Snd_pcm_writei (handle, OUTPUTPTR, n);

  Outputptr = Output;
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 is found in the mad.h (or stream.h) * header file.
  */static enum Mad_flow error (void *data, struct mad_stream *stream, struct mad_frame *frame) {
  struct buffer *buffer = data;
  printf ("This is Mad_flow error\n");
      fprintf (stderr, "Decoding error 0x%04x (%s) at byte offset%u\n", Stream->error, Mad_stream_errorstr (stream),

  Stream->this_frame-buffer->start);
/* Return Mad_flow_break this to stop decoding (and propagate an error) * * return mad_flow_continue;
 } * * is the function called by Main () above to perform all 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 M Ad_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/* H

  Eader * *, 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;
 }

Compile with ARM-LINUX-GCC:
Arm-linux-gcc-o Alsaplayer Alsa_minimad.c-lmad-lasound
Get Alsaplayer
How to use: Alsaplayer file name Volume
For example: Alsaplayer Voice.mp3 20

The program has a shortage of places, that is, the default can only play two-channel MP3, not implemented according to the solution of the dock file transform single two channels to play.

Finally recommend an introduction LIBMAD structure of the website, explain very detailed, do not know is not official website: http://m.baert.free.fr/contrib/docs/libmad/doxy/html/high-level.html

Write link content here

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.