| /* | |
| * Copyright (c) Michael Hipp and other authors of the mpglib project. | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include "mpg123.h" | |
| #include "mpglib.h" | |
| /* Global mp .. it's a hack */ | |
| struct mpstr *gmp; | |
| BOOL InitMP3(struct mpstr *mp) | |
| { | |
| static int init = 0; | |
| memset(mp,0,sizeof(struct mpstr)); | |
| mp->framesize = 0; | |
| mp->fsizeold = -1; | |
| mp->bsize = 0; | |
| mp->head = mp->tail = NULL; | |
| mp->fr.single = -1; | |
| mp->bsnum = 0; | |
| mp->synth_bo = 1; | |
| if(!init) { | |
| init = 1; | |
| make_decode_tables(32767); | |
| init_layer2(); | |
| init_layer3(SBLIMIT); | |
| } | |
| return !0; | |
| } | |
| void ExitMP3(struct mpstr *mp) | |
| { | |
| struct buf *b,*bn; | |
| b = mp->tail; | |
| while(b) { | |
| free(b->pnt); | |
| bn = b->next; | |
| free(b); | |
| b = bn; | |
| } | |
| } | |
| static struct buf *addbuf(struct mpstr *mp,char *buf,int size) | |
| { | |
| struct buf *nbuf; | |
| nbuf = malloc( sizeof(struct buf) ); | |
| if(!nbuf) { | |
| fprintf(stderr,"Out of memory!\n"); | |
| return NULL; | |
| } | |
| nbuf->pnt = malloc(size); | |
| if(!nbuf->pnt) { | |
| free(nbuf); | |
| return NULL; | |
| } | |
| nbuf->size = size; | |
| memcpy(nbuf->pnt,buf,size); | |
| nbuf->next = NULL; | |
| nbuf->prev = mp->head; | |
| nbuf->pos = 0; | |
| if(!mp->tail) { | |
| mp->tail = nbuf; | |
| } | |
| else { | |
| mp->head->next = nbuf; | |
| } | |
| mp->head = nbuf; | |
| mp->bsize += size; | |
| return nbuf; | |
| } | |
| static void remove_buf(struct mpstr *mp) | |
| { | |
| struct buf *buf = mp->tail; | |
| mp->tail = buf->next; | |
| if(mp->tail) | |
| mp->tail->prev = NULL; | |
| else { | |
| mp->tail = mp->head = NULL; | |
| } | |
| free(buf->pnt); | |
| free(buf); | |
| } | |
| static int read_buf_byte(struct mpstr *mp) | |
| { | |
| unsigned int b; | |
| int pos; | |
| pos = mp->tail->pos; | |
| while(pos >= mp->tail->size) { | |
| remove_buf(mp); | |
| pos = mp->tail->pos; | |
| if(!mp->tail) { | |
| fprintf(stderr,"Fatal error!\n"); | |
| exit(1); | |
| } | |
| } | |
| b = mp->tail->pnt[pos]; | |
| mp->bsize--; | |
| mp->tail->pos++; | |
| return b; | |
| } | |
| static void read_head(struct mpstr *mp) | |
| { | |
| unsigned long head; | |
| head = read_buf_byte(mp); | |
| head <<= 8; | |
| head |= read_buf_byte(mp); | |
| head <<= 8; | |
| head |= read_buf_byte(mp); | |
| head <<= 8; | |
| head |= read_buf_byte(mp); | |
| mp->header = head; | |
| } | |
| int decodeMP3(struct mpstr *mp,char *in,int isize,char *out, | |
| int osize,int *done) | |
| { | |
| int len; | |
| gmp = mp; | |
| if(osize < 4608) { | |
| fprintf(stderr,"To less out space\n"); | |
| return MP3_ERR; | |
| } | |
| if(in) { | |
| if(addbuf(mp,in,isize) == NULL) { | |
| return MP3_ERR; | |
| } | |
| } | |
| /* First decode header */ | |
| if(mp->framesize == 0) { | |
| if(mp->bsize < 4) { | |
| return MP3_NEED_MORE; | |
| } | |
| read_head(mp); | |
| if (decode_header(&mp->fr,mp->header) == 0) { | |
| return MP3_ERR; | |
| } | |
| mp->framesize = mp->fr.framesize; | |
| } | |
| if(mp->fr.framesize > mp->bsize) | |
| return MP3_NEED_MORE; | |
| wordpointer = mp->bsspace[mp->bsnum] + 512; | |
| mp->bsnum = (mp->bsnum + 1) & 0x1; | |
| bitindex = 0; | |
| len = 0; | |
| while(len < mp->framesize) { | |
| int nlen; | |
| int blen = mp->tail->size - mp->tail->pos; | |
| if( (mp->framesize - len) <= blen) { | |
| nlen = mp->framesize-len; | |
| } | |
| else { | |
| nlen = blen; | |
| } | |
| memcpy(wordpointer+len,mp->tail->pnt+mp->tail->pos,nlen); | |
| len += nlen; | |
| mp->tail->pos += nlen; | |
| mp->bsize -= nlen; | |
| if(mp->tail->pos == mp->tail->size) { | |
| remove_buf(mp); | |
| } | |
| } | |
| *done = 0; | |
| if(mp->fr.error_protection) | |
| getbits(16); | |
| switch(mp->fr.lay) { | |
| case 1: | |
| do_layer1(&mp->fr,(unsigned char *) out,done); | |
| break; | |
| case 2: | |
| do_layer2(&mp->fr,(unsigned char *) out,done); | |
| break; | |
| case 3: | |
| do_layer3(&mp->fr,(unsigned char *) out,done); | |
| break; | |
| } | |
| mp->fsizeold = mp->framesize; | |
| mp->framesize = 0; | |
| return MP3_OK; | |
| } | |
| int set_pointer(long backstep) | |
| { | |
| unsigned char *bsbufold; | |
| if(gmp->fsizeold < 0 && backstep > 0) { | |
| fprintf(stderr,"Can't step back %ld!\n",backstep); | |
| return MP3_ERR; | |
| } | |
| bsbufold = gmp->bsspace[gmp->bsnum] + 512; | |
| wordpointer -= backstep; | |
| if (backstep) | |
| memcpy(wordpointer,bsbufold+gmp->fsizeold-backstep,backstep); | |
| bitindex = 0; | |
| return MP3_OK; | |
| } |