diff options
Diffstat (limited to 'lib/liblame/mpglib/interface.c')
-rw-r--r-- | lib/liblame/mpglib/interface.c | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/lib/liblame/mpglib/interface.c b/lib/liblame/mpglib/interface.c new file mode 100644 index 0000000000..79338ae0b1 --- /dev/null +++ b/lib/liblame/mpglib/interface.c @@ -0,0 +1,695 @@ +/* + * interface.c + * + * Copyright (C) 1999-2010 The L.A.M.E. project + * + * Initially written by Michael Hipp, see also AUTHORS and README. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ +/* $Id: interface.c,v 1.52.2.4 2010/03/22 14:17:14 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> + +#include "common.h" +#include "interface.h" +#include "tabinit.h" +#include "layer3.h" +#include "lame.h" +#include "machine.h" +#include "VbrTag.h" +#include "decode_i386.h" + +#include "layer1.h" +#include "layer2.h" + +#ifdef WITH_DMALLOC +#include <dmalloc.h> +#endif + +/* #define HIP_DEBUG */ + +int +InitMP3(PMPSTR mp) +{ + memset(mp, 0, sizeof(MPSTR)); + + mp->framesize = 0; + mp->num_frames = 0; + mp->enc_delay = -1; + mp->enc_padding = -1; + mp->vbr_header = 0; + mp->header_parsed = 0; + mp->side_parsed = 0; + mp->data_parsed = 0; + mp->free_format = 0; + mp->old_free_format = 0; + mp->ssize = 0; + mp->dsize = 0; + mp->fsizeold = -1; + mp->bsize = 0; + mp->head = mp->tail = NULL; + mp->fr.single = -1; + mp->bsnum = 0; + mp->wordpointer = mp->bsspace[mp->bsnum] + 512; + mp->bitindex = 0; + mp->synth_bo = 1; + mp->sync_bitstream = 1; + + make_decode_tables(32767); + + init_layer3(SBLIMIT); + + init_layer2(); + + return 1; +} + +void +ExitMP3(PMPSTR mp) +{ + struct buf *b, *bn; + + b = mp->tail; + while (b) { + free(b->pnt); + bn = b->next; + free(b); + b = bn; + } +} + +static struct buf * +addbuf(PMPSTR mp, unsigned char *buf, int size) +{ + struct buf *nbuf; + + nbuf = (struct buf *) malloc(sizeof(struct buf)); + if (!nbuf) { + fprintf(stderr, "hip: addbuf() Out of memory!\n"); + return NULL; + } + nbuf->pnt = (unsigned char *) malloc((size_t) size); + if (!nbuf->pnt) { + free(nbuf); + return NULL; + } + nbuf->size = size; + memcpy(nbuf->pnt, buf, (size_t) 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; +} + +void +remove_buf(PMPSTR 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(PMPSTR mp) +{ + unsigned int b; + + int pos; + + + pos = mp->tail->pos; + while (pos >= mp->tail->size) { + remove_buf(mp); + if (!mp->tail) { + fprintf(stderr, "hip: Fatal error! tried to read past mp buffer\n"); + exit(1); + } + pos = mp->tail->pos; + } + + b = mp->tail->pnt[pos]; + mp->bsize--; + mp->tail->pos++; + + + return b; +} + + + +static void +read_head(PMPSTR 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; +} + + + + +static void +copy_mp(PMPSTR mp, int size, unsigned char *ptr) +{ + int len = 0; + + while (len < size && mp->tail) { + int nlen; + int blen = mp->tail->size - mp->tail->pos; + if ((size - len) <= blen) { + nlen = size - len; + } + else { + nlen = blen; + } + memcpy(ptr + len, mp->tail->pnt + mp->tail->pos, (size_t) nlen); + len += nlen; + mp->tail->pos += nlen; + mp->bsize -= nlen; + if (mp->tail->pos == mp->tail->size) { + remove_buf(mp); + } + } +} + +/* number of bytes needed by GetVbrTag to parse header */ +#define XING_HEADER_SIZE 194 + +/* +traverse mp data structure without changing it +(just like sync_buffer) +pull out Xing bytes +call vbr header check code from LAME +if we find a header, parse it and also compute the VBR header size +if no header, do nothing. + +bytes = number of bytes before MPEG header. skip this many bytes +before starting to read +return value: number of bytes in VBR header, including syncword +*/ +static int +check_vbr_header(PMPSTR mp, int bytes) +{ + int i, pos; + struct buf *buf = mp->tail; + unsigned char xing[XING_HEADER_SIZE]; + VBRTAGDATA pTagData; + + pos = buf->pos; + /* skip to valid header */ + for (i = 0; i < bytes; ++i) { + while (pos >= buf->size) { + buf = buf->next; + if (!buf) + return -1; /* fatal error */ + pos = buf->pos; + } + ++pos; + } + /* now read header */ + for (i = 0; i < XING_HEADER_SIZE; ++i) { + while (pos >= buf->size) { + buf = buf->next; + if (!buf) + return -1; /* fatal error */ + pos = buf->pos; + } + xing[i] = buf->pnt[pos]; + ++pos; + } + + /* check first bytes for Xing header */ + mp->vbr_header = GetVbrTag(&pTagData, xing); + if (mp->vbr_header) { + mp->num_frames = pTagData.frames; + mp->enc_delay = pTagData.enc_delay; + mp->enc_padding = pTagData.enc_padding; + + /* fprintf(stderr,"hip: delays: %i %i \n",mp->enc_delay,mp->enc_padding); */ + /* fprintf(stderr,"hip: Xing VBR header dectected. MP3 file has %i frames\n", pTagData.frames); */ + if (pTagData.headersize < 1) + return 1; + return pTagData.headersize; + } + return 0; +} + + + + + +static int +sync_buffer(PMPSTR mp, int free_match) +{ + /* traverse mp structure without modifying pointers, looking + * for a frame valid header. + * if free_format, valid header must also have the same + * samplerate. + * return number of bytes in mp, before the header + * return -1 if header is not found + */ + unsigned int b[4] = { 0, 0, 0, 0 }; + int i, h, pos; + struct buf *buf = mp->tail; + if (!buf) + return -1; + + pos = buf->pos; + for (i = 0; i < mp->bsize; i++) { + /* get 4 bytes */ + + b[0] = b[1]; + b[1] = b[2]; + b[2] = b[3]; + while (pos >= buf->size) { + buf = buf->next; + pos = buf->pos; + if (!buf) { + return -1; + /* not enough data to read 4 bytes */ + } + } + b[3] = buf->pnt[pos]; + ++pos; + + if (i >= 3) { + struct frame *fr = &mp->fr; + unsigned long head; + + head = b[0]; + head <<= 8; + head |= b[1]; + head <<= 8; + head |= b[2]; + head <<= 8; + head |= b[3]; + h = head_check(head, fr->lay); + + if (h && free_match) { + /* just to be even more thorough, match the sample rate */ + int mode, stereo, sampling_frequency, mpeg25, lsf; + + if (head & (1 << 20)) { + lsf = (head & (1 << 19)) ? 0x0 : 0x1; + mpeg25 = 0; + } + else { + lsf = 1; + mpeg25 = 1; + } + + mode = ((head >> 6) & 0x3); + stereo = (mode == MPG_MD_MONO) ? 1 : 2; + + if (mpeg25) + sampling_frequency = 6 + ((head >> 10) & 0x3); + else + sampling_frequency = ((head >> 10) & 0x3) + (lsf * 3); + h = ((stereo == fr->stereo) && (lsf == fr->lsf) && (mpeg25 == fr->mpeg25) && + (sampling_frequency == fr->sampling_frequency)); + } + + if (h) { + return i - 3; + } + } + } + return -1; +} + + +void +decode_reset(PMPSTR mp) +{ +#if 0 + remove_buf(mp); + /* start looking for next frame */ + /* mp->fsizeold = mp->framesize; */ + mp->fsizeold = -1; + mp->old_free_format = mp->free_format; + mp->framesize = 0; + mp->header_parsed = 0; + mp->side_parsed = 0; + mp->data_parsed = 0; + mp->sync_bitstream = 1; /* TODO check if this is right */ +#else + InitMP3(mp); /* Less error prone to just to reinitialise. */ +#endif +} + +int +audiodata_precedesframes(PMPSTR mp) +{ + if (mp->fr.lay == 3) + return layer3_audiodata_precedesframes(mp); + else + return 0; /* For Layer 1 & 2 the audio data starts at the frame that describes it, so no audio data precedes. */ +} + +static int +decodeMP3_clipchoice(PMPSTR mp, unsigned char *in, int isize, char *out, int *done, + int (*synth_1to1_mono_ptr) (PMPSTR, real *, unsigned char *, int *), + int (*synth_1to1_ptr) (PMPSTR, real *, int, unsigned char *, int *)) +{ + int i, iret, bits, bytes; + + if (in && isize && addbuf(mp, in, isize) == NULL) + return MP3_ERR; + + /* First decode header */ + if (!mp->header_parsed) { + + if (mp->fsizeold == -1 || mp->sync_bitstream) { + int vbrbytes; + mp->sync_bitstream = 0; + + /* This is the very first call. sync with anything */ + /* bytes= number of bytes before header */ + bytes = sync_buffer(mp, 0); + + /* now look for Xing VBR header */ + if (mp->bsize >= bytes + XING_HEADER_SIZE) { + /* vbrbytes = number of bytes in entire vbr header */ + vbrbytes = check_vbr_header(mp, bytes); + } + else { + /* not enough data to look for Xing header */ +#ifdef HIP_DEBUG + fprintf(stderr, "hip: not enough data to look for Xing header\n"); +#endif + return MP3_NEED_MORE; + } + + if (mp->vbr_header) { + /* do we have enough data to parse entire Xing header? */ + if (bytes + vbrbytes > mp->bsize) { + /* fprintf(stderr,"hip: not enough data to parse entire Xing header\n"); */ + return MP3_NEED_MORE; + } + + /* read in Xing header. Buffer data in case it + * is used by a non zero main_data_begin for the next + * frame, but otherwise dont decode Xing header */ +#ifdef HIP_DEBUG + fprintf(stderr, "hip: found xing header, skipping %i bytes\n", vbrbytes + bytes); +#endif + for (i = 0; i < vbrbytes + bytes; ++i) + read_buf_byte(mp); + /* now we need to find another syncword */ + /* just return and make user send in more data */ + + return MP3_NEED_MORE; + } + } + else { + /* match channels, samplerate, etc, when syncing */ + bytes = sync_buffer(mp, 1); + } + + /* buffer now synchronized */ + if (bytes < 0) { + /* fprintf(stderr,"hip: need more bytes %d\n", bytes); */ + return MP3_NEED_MORE; + } + if (bytes > 0) { + /* there were some extra bytes in front of header. + * bitstream problem, but we are now resynced + * should try to buffer previous data in case new + * frame has nonzero main_data_begin, but we need + * to make sure we do not overflow buffer + */ + int size; + fprintf(stderr, "hip: bitstream problem, resyncing skipping %d bytes...\n", bytes); + mp->old_free_format = 0; +#if 1 + /* FIXME: correct ??? */ + mp->sync_bitstream = 1; +#endif + /* skip some bytes, buffer the rest */ + size = (int) (mp->wordpointer - (mp->bsspace[mp->bsnum] + 512)); + + if (size > MAXFRAMESIZE) { + /* wordpointer buffer is trashed. probably cant recover, but try anyway */ + fprintf(stderr, "hip: wordpointer trashed. size=%i (%i) bytes=%i \n", + size, MAXFRAMESIZE, bytes); + size = 0; + mp->wordpointer = mp->bsspace[mp->bsnum] + 512; + } + + /* buffer contains 'size' data right now + we want to add 'bytes' worth of data, but do not + exceed MAXFRAMESIZE, so we through away 'i' bytes */ + i = (size + bytes) - MAXFRAMESIZE; + for (; i > 0; --i) { + --bytes; + read_buf_byte(mp); + } + + copy_mp(mp, bytes, mp->wordpointer); + mp->fsizeold += bytes; + } + + read_head(mp); + decode_header(&mp->fr, mp->header); + mp->header_parsed = 1; + mp->framesize = mp->fr.framesize; + mp->free_format = (mp->framesize == 0); + + if (mp->fr.lsf) + mp->ssize = (mp->fr.stereo == 1) ? 9 : 17; + else + mp->ssize = (mp->fr.stereo == 1) ? 17 : 32; + if (mp->fr.error_protection) + mp->ssize += 2; + + mp->bsnum = 1 - mp->bsnum; /* toggle buffer */ + mp->wordpointer = mp->bsspace[mp->bsnum] + 512; + mp->bitindex = 0; + + /* for very first header, never parse rest of data */ + if (mp->fsizeold == -1) { +#ifdef HIP_DEBUG + fprintf(stderr, "hip: not parsing the rest of the data of the first header\n"); +#endif + return MP3_NEED_MORE; + } + } /* end of header parsing block */ + + /* now decode side information */ + if (!mp->side_parsed) { + + /* Layer 3 only */ + if (mp->fr.lay == 3) { + if (mp->bsize < mp->ssize) + return MP3_NEED_MORE; + + copy_mp(mp, mp->ssize, mp->wordpointer); + + if (mp->fr.error_protection) + getbits(mp, 16); + bits = do_layer3_sideinfo(mp); + /* bits = actual number of bits needed to parse this frame */ + /* can be negative, if all bits needed are in the reservoir */ + if (bits < 0) + bits = 0; + + /* read just as many bytes as necessary before decoding */ + mp->dsize = (bits + 7) / 8; + +#ifdef HIP_DEBUG + fprintf(stderr, + "hip: %d bits needed to parse layer III frame, number of bytes to read before decoding dsize = %d\n", + bits, mp->dsize); +#endif + + /* this will force mpglib to read entire frame before decoding */ + /* mp->dsize= mp->framesize - mp->ssize; */ + + } + else { + /* Layers 1 and 2 */ + + /* check if there is enough input data */ + if (mp->fr.framesize > mp->bsize) + return MP3_NEED_MORE; + + /* takes care that the right amount of data is copied into wordpointer */ + mp->dsize = mp->fr.framesize; + mp->ssize = 0; + } + + mp->side_parsed = 1; + } + + /* now decode main data */ + iret = MP3_NEED_MORE; + if (!mp->data_parsed) { + if (mp->dsize > mp->bsize) { + return MP3_NEED_MORE; + } + + copy_mp(mp, mp->dsize, mp->wordpointer); + + *done = 0; + + /*do_layer3(&mp->fr,(unsigned char *) out,done); */ + switch (mp->fr.lay) { + case 1: + if (mp->fr.error_protection) + getbits(mp, 16); + + do_layer1(mp, (unsigned char *) out, done); + break; + + case 2: + if (mp->fr.error_protection) + getbits(mp, 16); + + do_layer2(mp, (unsigned char *) out, done); + break; + + case 3: + do_layer3(mp, (unsigned char *) out, done, synth_1to1_mono_ptr, synth_1to1_ptr); + break; + default: + fprintf(stderr, "hip: invalid layer %d\n", mp->fr.lay); + } + + mp->wordpointer = mp->bsspace[mp->bsnum] + 512 + mp->ssize + mp->dsize; + + mp->data_parsed = 1; + iret = MP3_OK; + } + + + /* remaining bits are ancillary data, or reservoir for next frame + * If free format, scan stream looking for next frame to determine + * mp->framesize */ + if (mp->free_format) { + if (mp->old_free_format) { + /* free format. bitrate must not vary */ + mp->framesize = mp->fsizeold_nopadding + (mp->fr.padding); + } + else { + bytes = sync_buffer(mp, 1); + if (bytes < 0) + return iret; + mp->framesize = bytes + mp->ssize + mp->dsize; + mp->fsizeold_nopadding = mp->framesize - mp->fr.padding; + /* + fprintf(stderr,"hip: freeformat bitstream: estimated bitrate=%ikbs \n", + 8*(4+mp->framesize)*freqs[mp->fr.sampling_frequency]/ + (1000*576*(2-mp->fr.lsf))); + */ + } + } + + /* buffer the ancillary data and reservoir for next frame */ + bytes = mp->framesize - (mp->ssize + mp->dsize); + if (bytes > mp->bsize) { + return iret; + } + + if (bytes > 0) { + int size; +#if 0 + /* FIXME: while loop OK ??? */ + while (bytes > 512) { + read_buf_byte(mp); + bytes--; + mp->framesize--; + } +#endif + copy_mp(mp, bytes, mp->wordpointer); + mp->wordpointer += bytes; + + size = (int) (mp->wordpointer - (mp->bsspace[mp->bsnum] + 512)); + if (size > MAXFRAMESIZE) { + fprintf(stderr, "hip: fatal error. MAXFRAMESIZE not large enough.\n"); + } + + } + + /* the above frame is completely parsed. start looking for next frame */ + mp->fsizeold = mp->framesize; + mp->old_free_format = mp->free_format; + mp->framesize = 0; + mp->header_parsed = 0; + mp->side_parsed = 0; + mp->data_parsed = 0; + + return iret; +} + +int +decodeMP3(PMPSTR mp, unsigned char *in, int isize, char *out, int osize, int *done) +{ + if (osize < 4608) { + fprintf(stderr, "hip: Insufficient memory for decoding buffer %d\n", osize); + return MP3_ERR; + } + + /* passing pointers to the functions which clip the samples */ + return decodeMP3_clipchoice(mp, in, isize, out, done, synth_1to1_mono, synth_1to1); +} + +int +decodeMP3_unclipped(PMPSTR mp, unsigned char *in, int isize, char *out, int osize, int *done) +{ + /* we forbid input with more than 1152 samples per channel for output in unclipped mode */ + if (osize < (int) (1152 * 2 * sizeof(real))) { + fprintf(stderr, "hip: out space too small for unclipped mode\n"); + return MP3_ERR; + } + + /* passing pointers to the functions which don't clip the samples */ + return decodeMP3_clipchoice(mp, in, isize, out, done, synth_1to1_mono_unclipped, + synth_1to1_unclipped); +} |