Hi
I was confused about all this myself not too long ago, so to save some
headaches for people, below is a simple decoder example with minimal
code to generate fixed size buffers of PCM samples from an MP3 file.
My understanding is that the decoder in LAME is based on the MPG123
decoder. When you build LAME there is an option to include the decoder
library in the build. I believe this is the default. See also the file
named lame.h for a very minimal description of the decoder functions.
The decoded output in this example program is sent to stdout. It is
quite simple to add code to send the output to a file and add a RIFF
header.
I hope the re-mailer doesn't mess with the format too much -- I've put
this as an attachment too, but I doubt that will make it through. I
don't have any place I can post this but feel free to post it anywhere
yourselves.
If you make mods for re-distribution, I suggest you keep them minimal --
the idea in posting this is KISS, as I found the examples in the LAME
disty burdened with a lot of extraneous nonsense.
This code is provided under LGPL
Anyway, in the hopes that this will save a few days of aggravation:
/***********************************************************************
*********
***
***
***
***
*** MP3 decoding example
***
*** First Revision MLS 11/10/03
***
***
***
*** Disclaimer: This is provided as is with no warranty of any kind
***
*** Use entirely at your own risk.
***
***
***
*** Note: this code makes a number of assumptions about the MP3 file
you are ***
*** Trying to decode, including that the resultant samples are stereo
and ***
*** 16 bits. (The actual sample size, sample rate and channel info is
in ***
*** the mp3data_struct) However this should get you started.
***
***
***
*** The general idea of this file is to provide minimal and readable
code ***
*** for people just getting started with LAME. Please do not contact me
***
*** with questions. If you find a bug here, fix it and post your fix.
***
***
***
*** See also lame.h
***
***
***
*** compile with: gcc -o decoder_example decoder_example.c -lmp3lame
-lm ***
***
***
************************************************************************
*******/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "lame.h"
#define READ_SIZE 1024
typedef struct LAMEDECODERIOSTRUCT {
int fh;;
mp3data_struct mp3;
char readbuf[READ_SIZE];
short pbufL[1152],pbufR[1152];
int samples_left;
int next_sample;
} Lame_Decoder;
Lame_Decoder ld;
int is_mp3_header(unsigned char *b)
{
static const char a[16] = { 0, 7, 7, 7, 0, 7, 0, 0, 0, 0, 0, 8, 8,
8, 8, 8 };
if( ((b[0] & 0xFF) != 0xFF) ||
((b[1] & 0xE0) != 0xE0) ||
((b[1] & 0x18) == 0x08) ||
((b[1] & 0x06) == 0x00) ||
((b[2] & 0xF0) == 0xF0) ||
((b[2] & 0x0C) == 0x0C) )
return 0;
if ((b[1] & 0x06) == 0x04)
if (a[b[2] >> 4] & (1 << (b[3] >> 6)))
return 0;
return 1;
}
/*
* load mp3 header info into dc->mp3
*/
int scan_for_mp3_frame(Lame_Decoder *dc)
{
unsigned char buff[100];
int r,i;
int padding;
int delay;
memset(&(dc->mp3), 0, sizeof(mp3data_struct));
if (read(dc->fh, buff, 4) != 4) //start with a full 4 byte mp3 header
(maybe)
return 0;
//check for a valid header
while (!is_mp3_header(buff)) {
buff[0] = buff[1]; //shift 1, and check next 4 bytes in file
buff[1] = buff[2];
buff[2] = buff[3];
if (read(dc->fh, &buff[3], 1) != 1)
return 0;
}
//got an mpg123 header so decode it. Note: buffer len is 4 (just a
header),
//so we expect no return samples and besides, lame code says first
return
//will not fill buffers until header_parsed
if(lame_decode1_headersB(buff, 4, dc->pbufL, dc->pbufR, &(dc->mp3),
&delay, &padding) < 0)
return 0;
// now feed in buffer fulls until the header is parsed
// again, we expect no data here, and we expect at least >1Kb file
while (!dc->mp3.header_parsed) {
if( read(dc->fh, dc->readbuf, READ_SIZE) != READ_SIZE)
return 0;
r = lame_decode1_headersB(dc->readbuf, READ_SIZE, dc->pbufL,
dc->pbufR, &(dc->mp3), &delay, &padding);
if (r < 0)
return 0;
if(r > 0)
fprintf(stderr,"Data ignored synchronizing headers\n");
}
//we're going to process the whole file anyway, so who cares.....
(dc->mp3).nsamp = 0x7fffffff;
return 1;
}
int init_decoder(Lame_Decoder *ld)
{
lame_decode_init();
return scan_for_mp3_frame(ld);
}
/*
* returns sample count, with sbuff filled with Left/Right samples
* in PCM format (assuming stereo)
* Note: This code has 2 levels of buffering (this can be eliminated
* with a little work): 1 within ld and one within mp structure
* in the decoder library.
*
*/
int get_next_ecoded_data(Lame_Decoder *ld, short *sbuff, int
max_samples)
{
int i, nxtsamp,rdlen,flen;
if(max_samples < 1)
return 0;
//if any samples left from last time, output those first
i = 0;
if(ld->samples_left) {
do {
sbuff[i] = ld->pbufL[ld->next_sample];
sbuff[i+1] = ld->pbufR[ld->next_sample];
i += 2;
++ld->next_sample;
--ld->samples_left;
} while(ld->samples_left && (i < max_samples));
//if we are not done with buffered data, just return
if(ld->samples_left)
return i;
}
do {
//check for bytes already in decoder buffers and use them up if
there
flen = lame_decode1_headers(ld->readbuf, 0, ld->pbufL, ld->pbufR,
&ld->mp3);
//if nothing in decoder buffer, read in data until decoder has
enough (i.e. returns non zero)
if(! flen ) {
do {
if( (rdlen = read(ld->fh, ld->readbuf, READ_SIZE)) < 0)
return 0; //read error -- we're done
flen = lame_decode1_headers(ld->readbuf, rdlen, ld->pbufL,
ld->pbufR, &ld->mp3);
if(flen < 0)
return 0; //decoder error! maybe should return -1
if(flen > 0)
break; //got some data
if(rdlen == 0) //EOF and flen==0
return 0; //then we're all done
} while( 1 );
}
nxtsamp = 0;
//copy samples (back) into 16 bit PCM format
do {
sbuff[i] = ld->pbufL[nxtsamp];
sbuff[i+1] = ld->pbufR[nxtsamp];
i += 2;
++nxtsamp;
--flen;
} while(flen && (i < max_samples));
//if any left, then we'll use them up first next time
if(flen) {
ld->next_sample = nxtsamp;
ld->samples_left = flen;
return i;
}
} while( i < max_samples);
return i;
}
main(int argc, char *argv[])
{
long buff_size,maxsize,count;
char *buf1;
if(argc < 2) {
fprintf(stderr, "Need MP3 file name\n");
fprintf(stderr, "Run as follows: %s <MP3-file-name>
[<PCM-buffer-size>]\n",argv[0]);
fprintf(stderr, "PCM samples are written directly to stdout.\n\n");
exit(1);
}
if(argc > 2)
buff_size = atoi(argv[2]) * 1024;
else
buff_size = 64*1024;
if(! (buf1 = malloc(buff_size)) ) {
fprintf(stderr, "Unable to allocate %ld byte buffer", buff_size);
exit(1);
}
if( (ld.fh = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr,"Unable to open %s\n",argv[1]);
exit(1);
}
if( !init_decoder(&ld) ) {
fprintf(stderr,"Unable to initialize decoder\n");
exit(1);
}
while( (count = get_next_ecoded_data(&ld, (short *) buf1, buff_size /
2)) ) {
//put code here to use PCM samples now in buf1
write(1,buf1,count*2); //just write to stdout.
}
close(ld.fh);
exit(0);
}
_______________________________________________
mp3encoder mailing list
[EMAIL PROTECTED]
http://minnie.tuhs.org/mailman/listinfo/mp3encoder