aboutsummaryrefslogtreecommitdiffstats
path: root/src/mp3_decode.c
diff options
context:
space:
mode:
authorWarren Dukes <warren.dukes@gmail.com>2004-05-31 01:21:17 +0000
committerWarren Dukes <warren.dukes@gmail.com>2004-05-31 01:21:17 +0000
commitfd6aa253594e18877ca2380961c0425a7de21b2e (patch)
treeb86fc645573adef9c0de9bd5f22eadffe3d16814 /src/mp3_decode.c
parentd7893a3e76d261b33b83fd9333d85892b3308594 (diff)
downloadmpd-fd6aa253594e18877ca2380961c0425a7de21b2e.tar.gz
mpd-fd6aa253594e18877ca2380961c0425a7de21b2e.tar.xz
mpd-fd6aa253594e18877ca2380961c0425a7de21b2e.zip
mp3 and ogg plugin stuff
git-svn-id: https://svn.musicpd.org/mpd/trunk@1245 09075e82-0dd4-0310-85a5-a0d7c8717e4f
Diffstat (limited to 'src/mp3_decode.c')
-rw-r--r--src/mp3_decode.c620
1 files changed, 0 insertions, 620 deletions
diff --git a/src/mp3_decode.c b/src/mp3_decode.c
deleted file mode 100644
index 467a656df..000000000
--- a/src/mp3_decode.c
+++ /dev/null
@@ -1,620 +0,0 @@
-/* the Music Player Daemon (MPD)
- * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
- * This project's homepage is: http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "mp3_decode.h"
-
-#ifdef HAVE_MAD
-
-#include "pcm_utils.h"
-#ifdef USE_MPD_MAD
-#include "libmad/mad.h"
-#else
-#include <mad.h>
-#endif
-#ifdef HAVE_ID3TAG
-#ifdef USE_MPD_ID3TAG
-#include "libid3tag/id3tag.h"
-#else
-#include <id3tag.h>
-#endif
-#endif
-#include "playerData.h"
-#include "log.h"
-#include "utils.h"
-#include "inputStream.h"
-#include "outputBuffer.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-
-#define FRAMES_CUSHION 2000
-
-#define READ_BUFFER_SIZE 40960
-
-#define DECODE_SKIP -3
-#define DECODE_BREAK -2
-#define DECODE_CONT -1
-#define DECODE_OK 0
-
-#define MUTEFRAME_SKIP 1
-#define MUTEFRAME_SEEK 2
-
-/* this is stolen from mpg321! */
-struct audio_dither {
- mad_fixed_t error[3];
- mad_fixed_t random;
-};
-
-unsigned long prng(unsigned long state) {
- return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
-}
-
-signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, struct audio_dither *dither) {
- unsigned int scalebits;
- mad_fixed_t output, mask, random;
-
- enum {
- MIN = -MAD_F_ONE,
- MAX = MAD_F_ONE - 1
- };
-
- sample += dither->error[0] - dither->error[1] + dither->error[2];
-
- dither->error[2] = dither->error[1];
- dither->error[1] = dither->error[0] / 2;
-
- output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
-
- scalebits = MAD_F_FRACBITS + 1 - bits;
- mask = (1L << scalebits) - 1;
-
- random = prng(dither->random);
- output += (random & mask) - (dither->random & mask);
-
- dither->random = random;
-
- if (output > MAX) {
- output = MAX;
-
- if (sample > MAX)
- sample = MAX;
- }
- else if (output < MIN) {
- output = MIN;
-
- if (sample < MIN)
- sample = MIN;
- }
-
- output &= ~mask;
-
- dither->error[0] = sample - output;
-
- return output >> scalebits;
-}
-/* end of stolen stuff from mpg321 */
-
-/* decoder stuff is based on madlld */
-
-#define MP3_DATA_OUTPUT_BUFFER_SIZE 4096
-
-typedef struct _mp3DecodeData {
- struct mad_stream stream;
- struct mad_frame frame;
- struct mad_synth synth;
- mad_timer_t timer;
- unsigned char readBuffer[READ_BUFFER_SIZE];
- char outputBuffer[MP3_DATA_OUTPUT_BUFFER_SIZE];
- char * outputPtr;
- char * outputBufferEnd;
- float totalTime;
- float elapsedTime;
- int muteFrame;
- long * frameOffset;
- mad_timer_t * times;
- long highestFrame;
- long maxFrames;
- long currentFrame;
- int flush;
- unsigned long bitRate;
- InputStream * inStream;
-} mp3DecodeData;
-
-void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) {
- data->outputPtr = data->outputBuffer;
- data->outputBufferEnd = data->outputBuffer+MP3_DATA_OUTPUT_BUFFER_SIZE;
- data->muteFrame = 0;
- data->highestFrame = 0;
- data->maxFrames = 0;
- data->frameOffset = NULL;
- data->times = NULL;
- data->currentFrame = 0;
- data->flush = 1;
- data->inStream = inStream;
-
- mad_stream_init(&data->stream);
- mad_frame_init(&data->frame);
- mad_synth_init(&data->synth);
- mad_timer_reset(&data->timer);
-}
-
-int seekMp3InputBuffer(mp3DecodeData * data, long offset) {
- if(seekInputStream(data->inStream,offset,SEEK_SET) < 0) {
- return -1;
- }
-
- mad_stream_buffer(&data->stream,data->readBuffer,0);
- (data->stream).error = 0;
-
- return 0;
-}
-
-int fillMp3InputBuffer(mp3DecodeData * data) {
- size_t readSize;
- size_t remaining;
- size_t readed;
- unsigned char * readStart;
-
- if((data->stream).next_frame!=NULL) {
- remaining = (data->stream).bufend-(data->stream).next_frame;
- memmove(data->readBuffer,(data->stream).next_frame,remaining);
- readStart = (data->readBuffer)+remaining;
- readSize = READ_BUFFER_SIZE-remaining;
- }
- else {
- readSize = READ_BUFFER_SIZE;
- readStart = data->readBuffer,
- remaining = 0;
- }
-
- readed = readFromInputStream(data->inStream, readStart, (size_t)1,
- readSize);
- if(readed <= 0 && inputStreamAtEOF(data->inStream)) return -1;
- /* sleep for a fraction of a second! */
- else if(readed <= 0) my_usleep(10000);
-
- mad_stream_buffer(&data->stream,data->readBuffer,readed+remaining);
- (data->stream).error = 0;
-
- return 0;
-}
-
-int decodeNextFrameHeader(mp3DecodeData * data) {
- if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) {
- if(fillMp3InputBuffer(data) < 0) {
- return DECODE_BREAK;
- }
- }
- if(mad_header_decode(&data->frame.header,&data->stream)) {
-#ifdef HAVE_ID3TAG
- if((data->stream).error==MAD_ERROR_LOSTSYNC &&
- (data->stream).this_frame)
- {
- signed long tagsize = id3_tag_query(
- (data->stream).this_frame,
- (data->stream).bufend-
- (data->stream).this_frame);
- if(tagsize>0) {
- mad_stream_skip(&(data->stream),tagsize);
- return DECODE_CONT;
- }
- }
-#endif
- if(MAD_RECOVERABLE((data->stream).error)) {
- return DECODE_SKIP;
- }
- else {
- if((data->stream).error==MAD_ERROR_BUFLEN) return DECODE_CONT;
- else
- {
- ERROR("unrecoverable frame level error "
- "(%s).\n",
- mad_stream_errorstr(&data->stream));
- data->flush = 0;
- return DECODE_BREAK;
- }
- }
- }
-
- return DECODE_OK;
-}
-
-int decodeNextFrame(mp3DecodeData * data) {
- if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) {
- if(fillMp3InputBuffer(data) < 0) {
- return DECODE_BREAK;
- }
- }
- if(mad_frame_decode(&data->frame,&data->stream)) {
-#ifdef HAVE_ID3TAG
- if((data->stream).error==MAD_ERROR_LOSTSYNC) {
- signed long tagsize = id3_tag_query(
- (data->stream).this_frame,
- (data->stream).bufend-
- (data->stream).this_frame);
- if(tagsize>0) {
- mad_stream_skip(&(data->stream),tagsize);
- return DECODE_CONT;
- }
- }
-#endif
- if(MAD_RECOVERABLE((data->stream).error)) {
- return DECODE_SKIP;
- }
- else {
- if((data->stream).error==MAD_ERROR_BUFLEN) return DECODE_CONT;
- else
- {
- ERROR("unrecoverable frame level error "
- "(%s).\n",
- mad_stream_errorstr(&data->stream));
- data->flush = 0;
- return DECODE_BREAK;
- }
- }
- }
-
- return DECODE_OK;
-}
-
-/* xing stuff stolen from alsaplayer */
-# define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
-
-struct xing {
- long flags; /* valid fields (see below) */
- unsigned long frames; /* total number of frames */
- unsigned long bytes; /* total number of bytes */
- unsigned char toc[100]; /* 100-point seek table */
- long scale; /* ?? */
-};
-
-enum {
- XING_FRAMES = 0x00000001L,
- XING_BYTES = 0x00000002L,
- XING_TOC = 0x00000004L,
- XING_SCALE = 0x00000008L
-};
-
-int parse_xing(struct xing *xing, struct mad_bitptr ptr, unsigned int bitlen)
-{
- if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC) goto fail;
-
- xing->flags = mad_bit_read(&ptr, 32);
- bitlen -= 64;
-
- if (xing->flags & XING_FRAMES) {
- if (bitlen < 32) goto fail;
- xing->frames = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
-
- if (xing->flags & XING_BYTES) {
- if (bitlen < 32) goto fail;
- xing->bytes = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
-
- if (xing->flags & XING_TOC) {
- int i;
- if (bitlen < 800) goto fail;
- for (i = 0; i < 100; ++i) xing->toc[i] = mad_bit_read(&ptr, 8);
- bitlen -= 800;
- }
-
- if (xing->flags & XING_SCALE) {
- if (bitlen < 32) goto fail;
- xing->scale = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
-
- return 1;
-
-fail:
- xing->flags = 0;
- return 0;
-}
-
-int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc) {
- struct xing xing;
- int ret;
- int skip;
-
- memset(&xing,0,sizeof(struct xing));
- xing.flags = 0;
-
- while(1) {
- skip = 0;
- while((ret = decodeNextFrameHeader(data))==DECODE_CONT &&
- (!dc || !dc->stop));
- if(ret==DECODE_SKIP) skip = 1;
- else if(ret==DECODE_BREAK || (dc && dc->stop)) return -1;
- while((ret = decodeNextFrame(data))==DECODE_CONT &&
- (!dc || !dc->stop));
- if(ret==DECODE_BREAK || (dc && dc->stop)) return -1;
- if(!skip && ret==DECODE_OK) break;
- }
-
- if(parse_xing(&xing,data->stream.anc_ptr,data->stream.anc_bitlen)) {
- if(xing.flags & XING_FRAMES) {
- mad_timer_t duration = data->frame.header.duration;
- mad_timer_multiply(&duration,xing.frames);
- data->muteFrame = MUTEFRAME_SKIP;
- data->totalTime = ((float)mad_timer_count(duration,
- MAD_UNITS_MILLISECONDS))/1000;
- data->maxFrames = xing.frames;
- }
- }
- else {
- size_t offset = data->inStream->offset;
- mad_timer_t duration = data->frame.header.duration;
- float frameTime = ((float)mad_timer_count(duration,
- MAD_UNITS_MILLISECONDS))/1000;
- if(data->stream.this_frame!=NULL) {
- offset-= data->stream.bufend-data->stream.this_frame;
- }
- else {
- offset-= data->stream.bufend-data->stream.buffer;
- }
- if(data->inStream->size >= offset) {
- data->totalTime = ((data->inStream->size-offset)*8.0)/
- (data->frame).header.bitrate;
- data->maxFrames =
- data->totalTime/frameTime+FRAMES_CUSHION;
- }
- else {
- data->maxFrames = FRAMES_CUSHION;
- data->totalTime = 0;
- }
- }
-
- data->frameOffset = malloc(sizeof(long)*data->maxFrames);
- data->times = malloc(sizeof(mad_timer_t)*data->maxFrames);
-
- return 0;
-}
-
-void mp3DecodeDataFinalize(mp3DecodeData * data) {
- mad_synth_finish(&data->synth);
- mad_frame_finish(&data->frame);
- mad_stream_finish(&data->stream);
-
- closeInputStream(data->inStream);
- if(data->frameOffset) free(data->frameOffset);
- if(data->times) free(data->times);
-}
-
-/* this is primarily used for getting total time for tags */
-int getMp3TotalTime(char * file) {
- InputStream inStream;
- mp3DecodeData data;
- int ret;
-
- if(openInputStream(&inStream, file) < 0) return -1;
- initMp3DecodeData(&data,&inStream);
- data.stream.options |= MAD_OPTION_IGNORECRC;
- if(decodeFirstFrame(&data, NULL)<0) ret = -1;
- else ret = data.totalTime+0.5;
- mp3DecodeDataFinalize(&data);
-
- return ret;
-}
-
-int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
- DecoderControl * dc, int ignoreCrc)
-{
- initMp3DecodeData(data, inStream);
- if(ignoreCrc) data->stream.options |= MAD_OPTION_IGNORECRC;
- if(decodeFirstFrame(data, dc)<0) {
- mp3DecodeDataFinalize(data);
- return -1;
- }
-
- return 0;
-}
-
-int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
- int i;
- int ret;
- struct audio_dither dither;
- int skip;
-
- if(data->currentFrame>=data->highestFrame) {
- mad_timer_add(&data->timer,(data->frame).header.duration);
- data->bitRate = (data->frame).header.bitrate;
- if(data->currentFrame>=data->maxFrames) {
- data->currentFrame = data->maxFrames - 1;
- }
- else data->highestFrame++;
- data->frameOffset[data->currentFrame] = data->inStream->offset;
- if(data->stream.this_frame!=NULL) {
- data->frameOffset[data->currentFrame]-=
- data->stream.bufend-
- data->stream.this_frame;
- }
- else {
- data->frameOffset[data->currentFrame]-=
- data->stream.bufend-data->stream.buffer;
- }
- data->times[data->currentFrame] = data->timer;
- }
- else data->timer = data->times[data->currentFrame];
- data->currentFrame++;
- data->elapsedTime = ((float)mad_timer_count(data->timer,MAD_UNITS_MILLISECONDS))/1000;
-
- switch(data->muteFrame) {
- case MUTEFRAME_SKIP:
- data->muteFrame = 0;
- break;
- case MUTEFRAME_SEEK:
- if(dc->seekWhere<=data->elapsedTime) {
- data->outputPtr = data->outputBuffer;
- clearOutputBuffer(cb);
- data->muteFrame = 0;
- dc->seek = 0;
- }
- break;
- default:
- mad_synth_frame(&data->synth,&data->frame);
-
- for(i=0;i<(data->synth).pcm.length;i++) {
- mpd_sint16 * sample;
-
- sample = (mpd_sint16 *)data->outputPtr;
- *sample = (mpd_sint16) audio_linear_dither(16,
- (data->synth).pcm.samples[0][i],
- &dither);
- data->outputPtr+=2;
-
- if(MAD_NCHANNELS(&(data->frame).header)==2) {
- sample = (mpd_sint16 *)data->outputPtr;
- *sample = (mpd_sint16) audio_linear_dither(16,
- (data->synth).pcm.samples[1][i],
- &dither);
- data->outputPtr+=2;
- }
-
- if(data->outputPtr==data->outputBufferEnd) {
- long ret;
- ret = sendDataToOutputBuffer(cb,
- data->inStream,
- dc,
- data->inStream->seekable,
- data->outputBuffer,
- MP3_DATA_OUTPUT_BUFFER_SIZE,
- data->elapsedTime,
- data->bitRate/1000);
- if(ret == OUTPUT_BUFFER_DC_STOP) {
- return DECODE_BREAK;
- }
-
- data->outputPtr = data->outputBuffer;
-
- if(ret == OUTPUT_BUFFER_DC_SEEK) break;
- }
- }
-
- if(dc->seek && data->inStream->seekable) {
- long i = 0;
- data->muteFrame = MUTEFRAME_SEEK;
- while(i<data->highestFrame && dc->seekWhere >
- ((float)mad_timer_count(data->times[i],
- MAD_UNITS_MILLISECONDS))/1000)
- {
- i++;
- }
- if(i<data->highestFrame) {
- if(seekMp3InputBuffer(data,
- data->frameOffset[i]) == 0)
- {
- data->outputPtr = data->outputBuffer;
- clearOutputBuffer(cb);
- data->currentFrame = i;
- }
- else dc->seekError = 1;
- data->muteFrame = 0;
- dc->seek = 0;
- }
- }
- else if(dc->seek && !data->inStream->seekable) {
- dc->seek = 0;
- dc->seekError = 1;
- }
- }
-
- while(1) {
- skip = 0;
- while((ret = decodeNextFrameHeader(data))==DECODE_CONT &&
- !dc->stop && !dc->seek);
- if(ret==DECODE_BREAK || dc->stop || dc->seek) break;
- else if(ret==DECODE_SKIP) skip = 1;
- if(!data->muteFrame) {
- while((ret = decodeNextFrame(data))==DECODE_CONT &&
- !dc->stop && !dc->seek);
- if(ret==DECODE_BREAK || dc->stop || dc->seek) break;
- }
- if(!skip && ret==DECODE_OK) break;
- }
-
- if(dc->stop) return DECODE_BREAK;
-
- return ret;
-}
-
-void initAudioFormatFromMp3DecodeData(mp3DecodeData * data, AudioFormat * af) {
- af->bits = 16;
- af->sampleRate = (data->frame).header.samplerate;
- af->channels = MAD_NCHANNELS(&(data->frame).header);
-}
-
-int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream,
- int ignoreCrc)
-{
- mp3DecodeData data;
-
- if(openMp3FromInputStream(inStream, &data, dc, ignoreCrc) < 0) {
- closeInputStream(inStream);
- if(!dc->stop) {
- ERROR("Input does not appear to be a mp3 bit stream.\n");
- return -1;
- }
- else {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- }
- return 0;
- }
-
- initAudioFormatFromMp3DecodeData(&data, &(dc->audioFormat));
- getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
-
- dc->totalTime = data.totalTime;
- dc->state = DECODE_STATE_DECODE;
-
- while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
- /* send last little bit if not dc->stop */
- if(data.outputPtr!=data.outputBuffer && data.flush) {
- sendDataToOutputBuffer(cb, NULL, dc,
- data.inStream->seekable,
- data.outputBuffer,
- data.outputPtr-data.outputBuffer,
- data.elapsedTime,data.bitRate/1000);
- }
-
- flushOutputBuffer(cb);
- mp3DecodeDataFinalize(&data);
-
- /*if(dc->seek) {
- dc->seekError = 1;
- dc->seek = 0;
- }*/
-
- if(dc->stop) {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- }
- else dc->state = DECODE_STATE_STOP;
-
- return 0;
-}
-
-#endif
-/* vim:set shiftwidth=8 tabstop=8 expandtab: */