/* * mpadec - MPEG audio decoder * Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru) * * 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 */ /* $Id: mpadec.c,v 1.2 2004/07/28 06:46:49 metal_man Exp $ */ #include "mpadec_internal.h" extern const uint16_t crc_table[256]; extern void *synth_table[2][2][4][4]; const uint32_t bitmask[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; const int32_t frequency_table[9] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000 }; const int16_t bitrate_table[2][3][16] = { { { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 560 }, { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448 }, { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 } }, { { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 320 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192 } } }; extern void init_tables(mpadec_t mpadec, FLOAT scale, int32_t sblimit); extern void decode_layer1(mpadec_t mpadec, uint8_t *buffer); extern void decode_layer2(mpadec_t mpadec, uint8_t *buffer); extern void decode_layer3(mpadec_t mpadec, uint8_t *buffer); uint32_t getbits(mpadec_t mpadec, unsigned n) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; while ((mpa->bits_left <= 24) && mpa->bytes_left) { mpa->bit_buffer = (mpa->bit_buffer << 8) | *mpa->next_byte++; mpa->bits_left += (uint8_t)8; mpa->bytes_left--; } while (mpa->bits_left <= 24) { mpa->bit_buffer = (mpa->bit_buffer << 8); mpa->bits_left += (uint8_t)8; } mpa->bits_left -= (uint8_t)n; return (mpa->bit_buffer >> mpa->bits_left) & bitmask[n]; } uint16_t update_crc(uint16_t init, uint8_t *buf, int length) { register uint32_t crc = (uint32_t)init, tmp; register int l = length; register uint8_t *b = buf; for (; l >= 8; l -= 8) crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (*b++)) & 0xFF]; tmp = (uint32_t)(*b) << 8; while (l--) { tmp <<= 1; crc <<= 1; if ((crc ^ tmp) & 0x10000) crc ^= 0x8005; } return (uint16_t)crc; } static uint32_t detect_frame_size(mpadec_t mpadec) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; register uint8_t *buf = mpa->next_byte; uint32_t i = mpa->bytes_left, hdr = 0; if (i < (mpa->frame.frame_size + 4)) return 0; buf += mpa->frame.frame_size; i -= mpa->frame.frame_size; while (i >= 4) { register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) { if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) && (mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) && (mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) { if (mpa->config.dblsync) { uint32_t fs = mpa->bytes_left - i - mpa->frame.padding + ((tmp >> 9) & 1); if (i >= (fs + 4)) { buf += fs; tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; buf -= fs; if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) { if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) && (mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) && (mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) { hdr = tmp; break; } } } else return 0; } else { hdr = tmp; break; } } } buf++; i--; } return (hdr ? (mpa->bytes_left - i) : 0); } static int decode_header(mpadec_t mpadec, uint32_t header) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; unsigned int layer, bridx, fridx; layer = 4 - ((header >> 17) & 3); bridx = ((header >> 12) & 0x0F); fridx = ((header >> 10) & 3); if ((fridx == 3) || (layer == 4) || ((layer != 3) && !bridx)) return FALSE; if (header & (1 << 20)) { mpa->frame.LSF = (uint8_t)((header & (1 << 19)) ? FALSE : TRUE); mpa->frame.MPEG25 = FALSE; } else mpa->frame.LSF = mpa->frame.MPEG25 = TRUE; mpa->frame.layer = (uint8_t)layer; mpa->frame.bitrate_index = bridx; mpa->frame.bitrate = bitrate_table[mpa->frame.LSF][layer - 1][bridx]; mpa->frame.frequency_index = (fridx += 3*(mpa->frame.LSF + mpa->frame.MPEG25)); mpa->frame.frequency = frequency_table[fridx]; mpa->frame.decoded_frequency = mpa->frame.frequency >> mpa->config.quality; mpa->frame.CRC = (uint8_t)(((header >> 16) & 1) ^ 1); mpa->frame.padding = ((header >> 9) & 1); mpa->frame.extension = (uint8_t)((header >> 8) & 1); mpa->frame.mode = (uint8_t)((header >> 6) & 3); mpa->frame.mode_ext = (uint8_t)((header >> 4) & 3); mpa->frame.copyright = (uint8_t)((header >> 3) & 1); mpa->frame.original = (uint8_t)((header >> 2) & 1); mpa->frame.emphasis = (uint8_t)(header & 3); mpa->frame.channels = (uint8_t)((mpa->frame.mode == MPG_MD_MONO) ? 1 : 2); switch (mpa->config.mode) { case MPADEC_CONFIG_CHANNEL1: case MPADEC_CONFIG_CHANNEL2: case MPADEC_CONFIG_MONO: mpa->frame.decoded_channels = 1; break; case MPADEC_CONFIG_STEREO: mpa->frame.decoded_channels = 2; break; default: mpa->frame.decoded_channels = mpa->frame.channels; } mpa->free_format = FALSE; switch (mpa->frame.layer) { case 1: mpa->frame.frame_samples = 384; mpa->frame.frame_size = (12000*mpa->frame.bitrate/mpa->frame.frequency + mpa->frame.padding) << 2; mpa->ssize = 0; break; case 2: mpa->frame.frame_samples = 1152; mpa->frame.frame_size = 144000*mpa->frame.bitrate/mpa->frame.frequency + mpa->frame.padding; mpa->ssize = 0; break; case 3: mpa->frame.frame_samples = 1152 >> mpa->frame.LSF; if (mpa->frame.LSF) mpa->ssize = (mpa->frame.channels > 1) ? 17 : 9; else mpa->ssize = (mpa->frame.channels > 1) ? 32 : 17; if (mpa->frame.bitrate_index) { mpa->frame.frame_size = 144000*mpa->frame.bitrate/(mpa->frame.frequency << mpa->frame.LSF) + mpa->frame.padding; mpa->prev_frame_size = 0; } else { register uint32_t div = 125*mpa->frame.frame_samples; if (!mpa->prev_frame_size) { mpa->frame.frame_size = (mpa->frame.CRC ? 6 : 4) + mpa->ssize + mpa->frame.padding; mpa->prev_frame_size = detect_frame_size(mpa); if (mpa->prev_frame_size) mpa->prev_frame_size -= mpa->frame.padding; } mpa->frame.frame_size = mpa->prev_frame_size + mpa->frame.padding; mpa->frame.bitrate = (mpa->frame.frame_size*mpa->frame.frequency + (div >> 1))/div; mpa->free_format = TRUE; } break; } mpa->frame.decoded_samples = mpa->frame.frame_samples >> mpa->config.quality; mpa->frame.downsample = FALSE; mpa->frame.downsample_sblimit = SBLIMIT; mpa->frame.decoded_size = mpa->frame.decoded_samples*mpa->frame.decoded_channels; switch (mpa->config.format) { case MPADEC_CONFIG_24BIT: mpa->frame.decoded_size *= 3; break; case MPADEC_CONFIG_32BIT: case MPADEC_CONFIG_FLOAT: mpa->frame.decoded_size <<= 2; break; default: mpa->frame.decoded_size <<= 1; break; } mpa->hsize = mpa->frame.CRC ? 6 : 4; if (mpa->frame.frame_size < (mpa->hsize + mpa->ssize)) mpa->frame.frame_size = mpa->hsize + mpa->ssize; mpa->dsize = mpa->frame.frame_size - (mpa->hsize + mpa->ssize); return TRUE; } static uint32_t sync_buffer(mpadec_t mpadec) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; register uint8_t *buf = mpa->next_byte; uint32_t retval = 0, i = mpa->bytes_left; if (mpa->state == MPADEC_STATE_START) { while (i >= 4) { register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) { if (mpa->config.dblsync) { if (decode_header(mpa, tmp)) { if ((i < (mpa->frame.frame_size + 4)) || (mpa->free_format && !mpa->prev_frame_size)) break; else { register uint32_t tmp2 = (buf[mpa->frame.frame_size] << 24) | (buf[mpa->frame.frame_size + 1] << 16) | (buf[mpa->frame.frame_size + 2] << 8) | buf[mpa->frame.frame_size + 3]; if (((tmp2 & 0xFFE00000) == 0xFFE00000) && (tmp2 & (3 << 17)) && ((tmp2 & (3 << 10)) != (3 << 10))) { if ((mpa->frame.layer == (uint8_t)(4 - ((tmp2 >> 17) & 3))) && (mpa->frame.frequency_index == (((tmp2 >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) && (mpa->frame.channels == ((((tmp2 >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) { retval = tmp; break; } } } } } else { retval = tmp; break; } } buf++; i--; } } else { while (i >= 4) { register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) { if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) && (mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) && (mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) { retval = tmp; break; } } buf++; i--; } } if (i < mpa->bytes_left) { i = mpa->bytes_left - i; mpa->next_byte = buf;; mpa->bytes_left -= i; if (i >= 512) { mpa->reservoir_size = 0; i = 512; } memcpy(mpa->reservoir + mpa->reservoir_size, mpa->next_byte - i, i); mpa->reservoir_size += i; } return retval; } static int first_frame(mpadec_t mpadec) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; int i, skip = FALSE; uint32_t framesize; FLOAT scale; if (mpa->frame.channels > 1) i = ((mpa->config.mode == MPADEC_CONFIG_STEREO) || (mpa->config.mode == MPADEC_CONFIG_AUTO)) ? 3 : 2; else i = (mpa->config.mode == MPADEC_CONFIG_STEREO) ? 1 : 0; mpa->synth_func = synth_table[mpa->config.quality][mpa->config.endian][mpa->config.format][i]; mpa->sample_size = mpa->frame.decoded_channels; switch (mpa->config.format) { case MPADEC_CONFIG_24BIT: mpa->sample_size *= 3; scale = 0x800000; break; case MPADEC_CONFIG_32BIT: mpa->sample_size <<= 2; scale = 0x80000000; break; case MPADEC_CONFIG_FLOAT: mpa->sample_size <<= 2; scale = 1; break; default: mpa->sample_size <<= 1; scale = 0x8000; break; } mpa->synth_size = (mpa->sample_size << 5) >> mpa->config.quality; if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_CUSTOM) { mpa->config.gain = 0.0; mpa->replay_gain = 1.0; } mpa->skip_samples = 0; mpa->padding_samples = 0; mpa->decoded_frames = 0; mpa->decoded_samples = 0; memset(&mpa->tag_info, 0, sizeof(mpa->tag_info)); framesize = (mpa->frame.frame_size < mpa->bytes_left) ? mpa->frame.frame_size : mpa->bytes_left; if ((mpa->frame.layer == 3) && (framesize >= (mpa->ssize + 124))) { register uint8_t *buf = mpa->next_byte + 4 + mpa->ssize; if (((buf[0] == 'X') && (buf[1] == 'i') && (buf[2] == 'n') && (buf[3] == 'g')) || ((buf[0] == 'I') && (buf[1] == 'n') && (buf[2] == 'f') && (buf[3] == 'o'))) { skip = TRUE; mpa->next_byte += framesize; mpa->bytes_left -= framesize; buf += 4; mpa->tag_info.flags = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; buf += 4; if (mpa->tag_info.flags & 1) { mpa->tag_info.frames = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; buf += 4; }; if (mpa->tag_info.flags & 2) { mpa->tag_info.bytes = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; buf += 4; }; if (mpa->tag_info.flags & 4) { memcpy(mpa->tag_info.toc, buf, 100); buf += 100; }; if (mpa->tag_info.flags & 8) buf += 4; mpa->tag_info.flags &= 7; if (framesize >= mpa->ssize + 160) { buf += 15; mpa->tag_info.replay_gain[0] = ((buf[0] << 8) | buf[1]) & 0x1FF; if (buf[0] & 2) mpa->tag_info.replay_gain[0] = -mpa->tag_info.replay_gain[0]; buf += 2; mpa->tag_info.replay_gain[1] = ((buf[0] << 8) | buf[1]) & 0x1FF; if (buf[0] & 2) mpa->tag_info.replay_gain[1] = -mpa->tag_info.replay_gain[1]; buf += 4; mpa->tag_info.enc_delay = (buf[0] << 4) | ((buf[1] >> 4) & 0x0F); mpa->tag_info.enc_padding = ((buf[1] & 0x0F) << 8) | buf[2]; if (((mpa->tag_info.enc_delay < 0) || (mpa->tag_info.enc_delay > 3000)) || ((mpa->tag_info.enc_padding < 0) || (mpa->tag_info.enc_padding > 3000))) { mpa->tag_info.replay_gain[0] = mpa->tag_info.replay_gain[1] = 0; mpa->tag_info.enc_delay = 0; mpa->tag_info.enc_padding = 0; } else { if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_RADIO) { mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[0])/10.0; } else if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE) { mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[1])/10.0; } } mpa->skip_samples = mpa->tag_info.enc_delay; mpa->padding_samples = mpa->tag_info.enc_padding; } } } mpa->replay_gain = pow(10.0, mpa->config.gain/20.0); if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_NONE) scale *= mpa->replay_gain; init_tables(mpa, scale, SBLIMIT >> mpa->config.quality); if (mpa->frame.layer == 3) { mpa->skip_samples += 529; if ((mpa->tag_info.flags & 1) && (mpa->padding_samples > 529)) mpa->padding_samples -= 529; else mpa->padding_samples = 0; } else { mpa->skip_samples += 241; mpa->padding_samples = 0; } mpa->padding_start = mpa->tag_info.frames*mpa->frame.frame_samples; if (mpa->padding_start > mpa->padding_samples) mpa->padding_start -= mpa->padding_samples; else mpa->padding_start = 0; mpa->state = MPADEC_STATE_DECODE; return skip; } mpadec_t MPADECAPI mpadec_init(void) { register struct mpadec_t *mpa = (struct mpadec_t *)malloc(sizeof(struct mpadec_t)); uint8_t temp[2]; if (!mpa) return NULL; memset(mpa, 0, sizeof(struct mpadec_t)); mpa->size = sizeof(struct mpadec_t); *((int16_t *)temp) = 1; mpa->config.quality = MPADEC_CONFIG_FULL_QUALITY; mpa->config.mode = MPADEC_CONFIG_AUTO; mpa->config.format = MPADEC_CONFIG_16BIT; mpa->config.endian = (uint8_t)((uint8_t)temp[0] ? MPADEC_CONFIG_LITTLE_ENDIAN : MPADEC_CONFIG_BIG_ENDIAN); mpa->config.replaygain = MPADEC_CONFIG_REPLAYGAIN_NONE; mpa->config.skip = TRUE; mpa->config.crc = TRUE; mpa->config.dblsync = TRUE; mpa->config.gain = 0.0; mpa->replay_gain = 1.0; init_tables(mpa, 0x8000, SBLIMIT); mpa->synth_bufoffs = 1; mpa->state = MPADEC_STATE_START; return mpa; } int MPADECAPI mpadec_uninit(mpadec_t mpadec) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; if (mpa && (mpa->size == sizeof(struct mpadec_t))) { mpa->size = mpa->state = 0; free(mpa); return MPADEC_RETCODE_OK; } else return MPADEC_RETCODE_INVALID_HANDLE; } int MPADECAPI mpadec_reset(mpadec_t mpadec) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; if (mpa && (mpa->size == sizeof(struct mpadec_t))) { memset(mpa->hybrid_in, 0, sizeof(mpa->hybrid_in)); memset(mpa->hybrid_out, 0, sizeof(mpa->hybrid_out)); memset(mpa->hybrid_buffers, 0, sizeof(mpa->hybrid_buffers)); memset(mpa->synth_buffers, 0, sizeof(mpa->synth_buffers)); mpa->hybrid_block[0] = mpa->hybrid_block[1] = 0; mpa->synth_bufoffs = 1; memset(&mpa->tag_info, 0, sizeof(mpa->tag_info)); if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_CUSTOM) mpa->config.gain = 0.0; mpa->prev_frame_size = 0; mpa->free_format = FALSE; mpa->error = FALSE; mpa->reservoir_size = 0; mpa->replay_gain = 1.0; mpa->skip_samples = 0; mpa->padding_samples = 0; mpa->decoded_frames = 0; mpa->decoded_samples = 0; mpa->state = MPADEC_STATE_START; return MPADEC_RETCODE_OK; } else return MPADEC_RETCODE_INVALID_HANDLE; } int MPADECAPI mpadec_configure(mpadec_t mpadec, mpadec_config_t *cfg) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; int32_t i, sblimit; FLOAT scale; if (mpa && (mpa->size == sizeof(struct mpadec_t))) { if (!cfg) return MPADEC_RETCODE_INVALID_PARAMETERS; if ((cfg->quality > MPADEC_CONFIG_HALF_QUALITY) || (cfg->mode > MPADEC_CONFIG_CHANNEL2) || (cfg->format > MPADEC_CONFIG_FLOAT) || (cfg->endian > MPADEC_CONFIG_BIG_ENDIAN) || (cfg->replaygain > MPADEC_CONFIG_REPLAYGAIN_CUSTOM)) return MPADEC_RETCODE_INVALID_PARAMETERS; mpa->config.quality = cfg->quality; mpa->config.mode = cfg->mode; mpa->config.format = cfg->format; mpa->config.endian = cfg->endian; mpa->config.replaygain = cfg->replaygain; mpa->config.skip = (uint8_t)(cfg->skip ? TRUE : FALSE); mpa->config.crc = (uint8_t)(cfg->crc ? TRUE : FALSE); mpa->config.dblsync = (uint8_t)(cfg->dblsync ? TRUE : FALSE); if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_CUSTOM) { mpa->config.gain = cfg->gain; } else { mpa->config.gain = 0.0; if (mpa->tag_info.flags) { if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_RADIO) { mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[0])/10.0; } else if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE) { mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[1])/10.0; } } } mpa->replay_gain = pow(10.0, mpa->config.gain/20.0); switch (mpa->config.format) { case MPADEC_CONFIG_24BIT: scale = 0x800000; break; case MPADEC_CONFIG_32BIT: scale = 0x80000000; break; case MPADEC_CONFIG_FLOAT: scale = 1; break; default: scale = 0x8000; break; } sblimit = SBLIMIT >> mpa->config.quality; if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_NONE) scale *= mpa->replay_gain; init_tables(mpa, scale, sblimit); if ((mpa->state > MPADEC_STATE_START) && mpa->header) { decode_header(mpa, mpa->header); if (mpa->frame.channels < 2) i = (mpa->config.mode == MPADEC_CONFIG_STEREO) ? 1 : 0; else i = ((mpa->config.mode == MPADEC_CONFIG_STEREO) || (mpa->config.mode == MPADEC_CONFIG_AUTO)) ? 3 : 2; mpa->synth_func = synth_table[mpa->config.quality][mpa->config.endian][mpa->config.format][i]; mpa->sample_size = mpa->frame.decoded_channels; switch (mpa->config.format) { case MPADEC_CONFIG_24BIT: mpa->sample_size *= 3; break; case MPADEC_CONFIG_32BIT: case MPADEC_CONFIG_FLOAT: mpa->sample_size <<= 2; break; default: mpa->sample_size <<= 1; break; } mpa->synth_size = (mpa->sample_size << 5) >> mpa->config.quality; } else mpa->state = MPADEC_STATE_START; return MPADEC_RETCODE_OK; } else return MPADEC_RETCODE_INVALID_HANDLE; } int MPADECAPI mpadec_get_info(mpadec_t mpadec, void *info, int info_type) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; if (!mpa || (mpa->size != sizeof(struct mpadec_t))) return MPADEC_RETCODE_INVALID_HANDLE; if (!info) return MPADEC_RETCODE_INVALID_PARAMETERS; if (info_type == MPADEC_INFO_CONFIG) { register mpadec_config_t *cfg = (mpadec_config_t *)info; cfg->quality = mpa->config.quality; cfg->mode = mpa->config.mode; cfg->format = mpa->config.format; cfg->endian = mpa->config.endian; cfg->replaygain = mpa->config.replaygain; cfg->skip = mpa->config.skip; cfg->crc = mpa->config.crc; cfg->dblsync = mpa->config.dblsync; cfg->gain = mpa->config.gain; } else if (info_type == MPADEC_INFO_TAG) { register mp3tag_info_t *tag = (mp3tag_info_t *)info; if (mpa->state < MPADEC_STATE_DECODE) { memset(tag, 0, sizeof(mp3tag_info_t)); return MPADEC_RETCODE_BAD_STATE; } else memcpy(tag, &mpa->tag_info, sizeof(mpa->tag_info)); } else if (info_type == MPADEC_INFO_STREAM) { register mpadec_info_t *inf = (mpadec_info_t *)info; if (mpa->state < MPADEC_STATE_DECODE) { memset(inf, 0, sizeof(mpadec_info_t)); return MPADEC_RETCODE_BAD_STATE; } else { inf->layer = mpa->frame.layer; inf->channels = mpa->frame.channels; inf->frequency = mpa->frame.frequency; inf->bitrate = mpa->frame.bitrate; inf->mode = mpa->frame.mode; inf->copyright = mpa->frame.copyright; inf->original = mpa->frame.original; inf->emphasis = mpa->frame.emphasis; inf->decoded_channels = mpa->frame.decoded_channels; inf->decoded_frequency = mpa->frame.decoded_frequency; inf->decoded_sample_size = mpa->sample_size; inf->frame_size = mpa->frame.frame_size; inf->frame_samples = mpa->frame.frame_samples; inf->decoded_frame_samples = mpa->frame.decoded_samples; if (mpa->tag_info.flags & 1) { inf->frames = mpa->tag_info.frames; inf->duration = (mpa->tag_info.frames*mpa->frame.frame_samples + (mpa->frame.frequency >> 1))/mpa->frame.frequency; } else { inf->frames = 0; inf->duration = 0; } } } else return MPADEC_RETCODE_INVALID_PARAMETERS; return MPADEC_RETCODE_OK; } int MPADECAPI mpadec_decode(mpadec_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *srcused, uint32_t *dstused) { register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; int retcode = MPADEC_RETCODE_OK; uint32_t decoded_size = 0; if (srcused) *srcused = 0; if (dstused) *dstused = 0; if (!dstbuf) dstsize = 0; if (!mpa || (mpa->size != sizeof(struct mpadec_t))) return MPADEC_RETCODE_INVALID_HANDLE; if (mpa->state < MPADEC_STATE_START) return MPADEC_RETCODE_BAD_STATE; if (!srcbuf || ((mpa->state > MPADEC_STATE_START) && !dstbuf )) return MPADEC_RETCODE_INVALID_PARAMETERS; mpa->next_byte = srcbuf; mpa->bytes_left = srcsize; while (mpa->bytes_left >= 4) { mpa->error = FALSE; mpa->bits_left = 0; mpa->header = sync_buffer(mpa); if (!mpa->header) { if (!decoded_size) retcode = MPADEC_RETCODE_NO_SYNC; break; } decode_header(mpa, mpa->header); if ((mpa->bytes_left < mpa->frame.frame_size) || (mpa->free_format && !mpa->prev_frame_size)) { retcode = MPADEC_RETCODE_NEED_MORE_DATA; break; } if (mpa->state == MPADEC_STATE_START) { if (first_frame(mpa)) continue; } else if ((mpa->frame.layer == 3) && (mpa->frame.frame_size >= (mpa->ssize + 12))) { register uint8_t *buf = mpa->next_byte + 4 + mpa->ssize; if (((buf[0] == 'X') && (buf[1] == 'i') && (buf[2] == 'n') && (buf[3] == 'g')) || ((buf[0] == 'I') && (buf[1] == 'n') && (buf[2] == 'f') && (buf[3] == 'o'))) { mpa->next_byte += mpa->frame.frame_size; mpa->bytes_left -= mpa->frame.frame_size; continue; } } if (dstsize < mpa->frame.decoded_size) { retcode = MPADEC_RETCODE_BUFFER_TOO_SMALL; break; } if (mpa->config.crc && mpa->frame.CRC) { mpa->frame.crc = (uint16_t)((mpa->next_byte[4] << 8) | mpa->next_byte[5]); mpa->crc = update_crc(0xFFFF, mpa->next_byte + 2, 16); } mpa->next_byte += mpa->hsize; mpa->bytes_left -= mpa->hsize; switch (mpa->frame.layer) { case 1: decode_layer1(mpa, dstbuf); break; case 2: decode_layer2(mpa, dstbuf); break; case 3: decode_layer3(mpa, dstbuf); break; } if (mpa->config.crc && mpa->error) memset(dstbuf, 0, mpa->frame.decoded_size); dstbuf += mpa->frame.decoded_size; dstsize -= mpa->frame.decoded_size; decoded_size += mpa->frame.decoded_size; mpa->decoded_samples += mpa->frame.frame_samples; mpa->decoded_frames++; if (mpa->config.skip) { if (mpa->skip_samples) { if (mpa->skip_samples >= mpa->frame.frame_samples) { dstbuf -= mpa->frame.decoded_size; dstsize += mpa->frame.decoded_size; decoded_size -= mpa->frame.decoded_size; mpa->skip_samples -= mpa->frame.frame_samples; } else { uint32_t tmp = mpa->frame.frame_samples - mpa->skip_samples; tmp = mpa->sample_size*(tmp >> mpa->config.quality); memmove(dstbuf - mpa->frame.decoded_size, dstbuf - tmp, tmp); dstbuf -= mpa->frame.decoded_size - tmp; dstsize += mpa->frame.decoded_size - tmp; decoded_size -= mpa->frame.decoded_size - tmp; mpa->skip_samples = 0; } } else if ((mpa->padding_samples) && (mpa->decoded_samples > mpa->padding_start)) { uint32_t tmp = mpa->decoded_samples - mpa->padding_start; if (tmp > mpa->padding_samples) tmp = mpa->padding_samples; mpa->padding_start += tmp; mpa->padding_samples -= tmp; tmp = mpa->sample_size*(tmp >> mpa->config.quality); dstbuf -= tmp; dstsize += tmp; decoded_size -= tmp; } } } if (srcused) *srcused = srcsize - mpa->bytes_left; if (dstused) *dstused = decoded_size; if ((retcode == MPADEC_RETCODE_OK) && mpa->bytes_left) retcode = MPADEC_RETCODE_NEED_MORE_DATA; if (!dstbuf && (retcode == MPADEC_RETCODE_BUFFER_TOO_SMALL)) retcode = MPADEC_RETCODE_OK; return retcode; } char * MPADECAPI mpadec_error(int code) { static char *mpa_errors[] = { "No error", "Invalid handle", "Not enough memory", "Bad decoder state", "Invalid parameters", "Need more data", "Output buffer too small", "Unable to synchronize", "Unknown error" }; if (code > MPADEC_RETCODE_UNKNOWN) code = MPADEC_RETCODE_UNKNOWN; return mpa_errors[code]; } mpadec2_t MPADECAPI mpadec2_init(void) { register struct mpadec2_t *mpa = (struct mpadec2_t *)malloc(sizeof(struct mpadec2_t)); if (!mpa) return NULL; mpa->size = sizeof(struct mpadec2_t); mpa->buffers = NULL; mpa->in_buffer_offset = mpa->in_buffer_used = 0; mpa->out_buffer_offset = mpa->out_buffer_used = 0; mpa->mpadec = mpadec_init(); if (!mpa->mpadec) { free(mpa); return NULL; } return mpa; } int MPADECAPI mpadec2_uninit(mpadec2_t mpadec) { register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec; if (mpa && (mpa->size == sizeof(struct mpadec2_t))) { struct mpabuffer_t *buf = mpa->buffers, *tmp; while (buf) { tmp = buf; buf = buf->next; free(tmp); } mpadec_uninit(mpa->mpadec); free(mpa); return MPADEC_RETCODE_OK; } else return MPADEC_RETCODE_INVALID_HANDLE; } int MPADECAPI mpadec2_reset(mpadec2_t mpadec) { register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec; if (mpa && (mpa->size == sizeof(struct mpadec2_t))) { struct mpabuffer_t *buf = mpa->buffers, *tmp; while (buf) { tmp = buf; buf = buf->next; free(tmp); } mpa->buffers = NULL; mpa->in_buffer_offset = mpa->in_buffer_used = 0; mpa->out_buffer_offset = mpa->out_buffer_used = 0; mpadec_reset(mpa->mpadec); return MPADEC_RETCODE_OK; } else return MPADEC_RETCODE_INVALID_HANDLE; } int MPADECAPI mpadec2_configure(mpadec2_t mpadec, mpadec_config_t *cfg) { register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec; if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE; mpa->out_buffer_offset = mpa->out_buffer_used = 0; return (mpadec_configure(mpa->mpadec, cfg)); } int MPADECAPI mpadec2_get_info(mpadec2_t mpadec, void *info, int info_type) { register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec; if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE; return (mpadec_get_info(mpa->mpadec, info, info_type)); } int MPADECAPI mpadec2_decode(mpadec2_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *dstused) { register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec; uint32_t n, src_used, dst_used; int r; if (dstused) *dstused = 0; if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE; if (((struct mpadec_t *)mpa->mpadec)->state < MPADEC_STATE_START) return MPADEC_RETCODE_BAD_STATE; if (srcbuf && srcsize) { struct mpabuffer_t *last = mpa->buffers, *buf; if (last) { while (last->next) last = last->next; if ((last->offset + last->used) < last->size) { n = last->size - (last->offset + last->used); if (n > srcsize) n = srcsize; memcpy(last->buffer + last->offset + last->used, srcbuf, n); last->used += n; srcbuf += n; srcsize -= n; } } if (srcsize) { n = (srcsize > 4096) ? srcsize : 4096; buf = (struct mpabuffer_t *)malloc(n + sizeof(struct mpabuffer_t)); if (buf) { buf->size = n; buf->offset = buf->used = 0; buf->buffer = (uint8_t *)buf + sizeof(struct mpabuffer_t); buf->next = NULL; memcpy(buf->buffer, srcbuf, srcsize); buf->used = srcsize; if (last) last->next = buf; else mpa->buffers = buf; } else return MPADEC_RETCODE_NOT_ENOUGH_MEMORY; } } if (!dstbuf || !dstsize) return MPADEC_RETCODE_OK; while (dstsize) { struct mpabuffer_t *buf = mpa->buffers; if (mpa->out_buffer_used) { n = (dstsize < mpa->out_buffer_used) ? dstsize : mpa->out_buffer_used; memcpy(dstbuf, mpa->out_buffer + mpa->out_buffer_offset, n); mpa->out_buffer_offset += n; mpa->out_buffer_used -= n; dstbuf += n; dstsize -= n; if (dstused) *dstused += n; } if (!dstsize) break; if (mpa->in_buffer_used && mpa->in_buffer_offset) memmove(mpa->in_buffer, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used); mpa->in_buffer_offset = 0; while (buf && (mpa->in_buffer_used < sizeof(mpa->in_buffer))) { if (buf->used) { n = sizeof(mpa->in_buffer) - mpa->in_buffer_used; if (n > buf->used) n = buf->used; memcpy(mpa->in_buffer + mpa->in_buffer_offset + mpa->in_buffer_used, buf->buffer + buf->offset, n); buf->offset += n; buf->used -= n; mpa->in_buffer_used += n; } if (!buf->used) { struct mpabuffer_t *tmp = buf; buf = buf->next; free(tmp); } } mpa->buffers = buf; r = mpadec_decode(mpa->mpadec, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used, dstbuf, dstsize, &src_used, &dst_used); mpa->in_buffer_offset += src_used; mpa->in_buffer_used -= src_used; dstbuf += dst_used; dstsize -= dst_used; if (dstused) *dstused += dst_used; if (r == MPADEC_RETCODE_BUFFER_TOO_SMALL) { mpa->out_buffer_offset = mpa->out_buffer_used = 0; mpadec_decode(mpa->mpadec, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used, mpa->out_buffer, sizeof(mpa->out_buffer), &src_used, &mpa->out_buffer_used); mpa->in_buffer_offset += src_used; mpa->in_buffer_used -= src_used; if (!mpa->out_buffer_used) break; } else if (!mpa->buffers) break; } return MPADEC_RETCODE_OK; }