aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/src/inputPlugins
diff options
context:
space:
mode:
authorJ. Alexander Treuman <jat@spatialrift.net>2007-05-28 15:50:45 +0000
committerJ. Alexander Treuman <jat@spatialrift.net>2007-05-28 15:50:45 +0000
commit4e05a161e54fe05902b99eff521aa0759b102f05 (patch)
tree9014ab8ce74e4fb2f0115c5518c62879bc269324 /trunk/src/inputPlugins
parente45bc035931b2c9ef13b85f98a3d4833a8dec8a9 (diff)
downloadmpd-4e05a161e54fe05902b99eff521aa0759b102f05.tar.gz
mpd-4e05a161e54fe05902b99eff521aa0759b102f05.tar.xz
mpd-4e05a161e54fe05902b99eff521aa0759b102f05.zip
Making branch for 0.13.0 fixes.
git-svn-id: https://svn.musicpd.org/mpd/branches/branch-0.13.0-fixes@6330 09075e82-0dd4-0310-85a5-a0d7c8717e4f
Diffstat (limited to 'trunk/src/inputPlugins')
-rw-r--r--trunk/src/inputPlugins/_flac_common.c211
-rw-r--r--trunk/src/inputPlugins/_flac_common.h187
-rw-r--r--trunk/src/inputPlugins/_ogg_common.c73
-rw-r--r--trunk/src/inputPlugins/_ogg_common.h35
-rw-r--r--trunk/src/inputPlugins/aac_plugin.c475
-rw-r--r--trunk/src/inputPlugins/audiofile_plugin.c188
-rw-r--r--trunk/src/inputPlugins/flac_plugin.c530
-rw-r--r--trunk/src/inputPlugins/mod_plugin.c299
-rw-r--r--trunk/src/inputPlugins/mp3_plugin.c1092
-rw-r--r--trunk/src/inputPlugins/mp4_plugin.c455
-rw-r--r--trunk/src/inputPlugins/mpc_plugin.c359
-rw-r--r--trunk/src/inputPlugins/oggflac_plugin.c423
-rw-r--r--trunk/src/inputPlugins/oggvorbis_plugin.c434
13 files changed, 0 insertions, 4761 deletions
diff --git a/trunk/src/inputPlugins/_flac_common.c b/trunk/src/inputPlugins/_flac_common.c
deleted file mode 100644
index 11126cd1b..000000000
--- a/trunk/src/inputPlugins/_flac_common.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * Common data structures and functions used by FLAC and OggFLAC
- * (c) 2005 by Eric Wong <normalperson@yhbt.net>
- *
- * 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 "../inputPlugin.h"
-
-#if defined(HAVE_FLAC) || defined(HAVE_OGGFLAC)
-
-#include "_flac_common.h"
-
-#include "../log.h"
-#include "../tag.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-#include "../decode.h"
-#include "../replayGain.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <FLAC/format.h>
-#include <FLAC/metadata.h>
-
-void init_FlacData(FlacData * data, OutputBuffer * cb,
- DecoderControl * dc, InputStream * inStream)
-{
- data->chunk_length = 0;
- data->time = 0;
- data->position = 0;
- data->bitRate = 0;
- data->cb = cb;
- data->dc = dc;
- data->inStream = inStream;
- data->replayGainInfo = NULL;
- data->tag = NULL;
-}
-
-static int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block,
- const char *cmnt, float *fl)
-{
- int offset =
- FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, cmnt);
-
- if (offset >= 0) {
- size_t pos = strlen(cmnt) + 1; /* 1 is for '=' */
- int len = block->data.vorbis_comment.comments[offset].length
- - pos;
- if (len > 0) {
- unsigned char tmp;
- unsigned char *dup = &(block->data.vorbis_comment.
- comments[offset].entry[pos]);
- tmp = dup[len];
- dup[len] = '\0';
- *fl = atof((char *)dup);
- dup[len] = tmp;
-
- return 1;
- }
- }
-
- return 0;
-}
-
-/* replaygain stuff by AliasMrJones */
-static void flacParseReplayGain(const FLAC__StreamMetadata * block,
- FlacData * data)
-{
- int found = 0;
-
- if (data->replayGainInfo)
- freeReplayGainInfo(data->replayGainInfo);
-
- data->replayGainInfo = newReplayGainInfo();
-
- found |= flacFindVorbisCommentFloat(block, "replaygain_album_gain",
- &data->replayGainInfo->albumGain);
- found |= flacFindVorbisCommentFloat(block, "replaygain_album_peak",
- &data->replayGainInfo->albumPeak);
- found |= flacFindVorbisCommentFloat(block, "replaygain_track_gain",
- &data->replayGainInfo->trackGain);
- found |= flacFindVorbisCommentFloat(block, "replaygain_track_peak",
- &data->replayGainInfo->trackPeak);
-
- if (!found) {
- freeReplayGainInfo(data->replayGainInfo);
- data->replayGainInfo = NULL;
- }
-}
-
-/* tracknumber is used in VCs, MPD uses "track" ..., all the other
- * tag names match */
-static const char *VORBIS_COMMENT_TRACK_KEY = "tracknumber";
-static const char *VORBIS_COMMENT_DISC_KEY = "discnumber";
-
-static unsigned int commentMatchesAddToTag(const
- FLAC__StreamMetadata_VorbisComment_Entry
- * entry, unsigned int itemType,
- MpdTag ** tag)
-{
- const char *str;
- size_t slen;
- int vlen;
-
- switch (itemType) {
- case TAG_ITEM_TRACK:
- str = VORBIS_COMMENT_TRACK_KEY;
- break;
- case TAG_ITEM_DISC:
- str = VORBIS_COMMENT_DISC_KEY;
- break;
- default:
- str = mpdTagItemKeys[itemType];
- }
- slen = strlen(str);
- vlen = entry->length - slen - 1;
-
- if ((vlen > 0) && (0 == strncasecmp(str, (char *)entry->entry, slen))
- && (*(entry->entry + slen) == '=')) {
- if (!*tag)
- *tag = newMpdTag();
-
- addItemToMpdTagWithLen(*tag, itemType,
- (char *)(entry->entry + slen + 1), vlen);
-
- return 1;
- }
-
- return 0;
-}
-
-MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
- MpdTag * tag)
-{
- unsigned int i, j;
- FLAC__StreamMetadata_VorbisComment_Entry *comments;
-
- comments = block->data.vorbis_comment.comments;
-
- for (i = block->data.vorbis_comment.num_comments; i != 0; --i) {
- for (j = TAG_NUM_OF_ITEM_TYPES; j--;) {
- if (commentMatchesAddToTag(comments, j, &tag))
- break;
- }
- comments++;
- }
-
- return tag;
-}
-
-void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
- FlacData * data)
-{
- DecoderControl *dc = data->dc;
- const FLAC__StreamMetadata_StreamInfo *si = &(block->data.stream_info);
-
- switch (block->type) {
- case FLAC__METADATA_TYPE_STREAMINFO:
- dc->audioFormat.bits = si->bits_per_sample;
- dc->audioFormat.sampleRate = si->sample_rate;
- dc->audioFormat.channels = si->channels;
- dc->totalTime = ((float)si->total_samples) / (si->sample_rate);
- getOutputAudioFormat(&(dc->audioFormat),
- &(data->cb->audioFormat));
- break;
- case FLAC__METADATA_TYPE_VORBIS_COMMENT:
- flacParseReplayGain(block, data);
- default:
- break;
- }
-}
-
-void flac_error_common_cb(const char *plugin,
- const FLAC__StreamDecoderErrorStatus status,
- FlacData * data)
-{
- if (data->dc->stop)
- return;
-
- switch (status) {
- case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
- ERROR("%s lost sync\n", plugin);
- break;
- case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
- ERROR("bad %s header\n", plugin);
- break;
- case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
- ERROR("%s crc mismatch\n", plugin);
- break;
- default:
- ERROR("unknown %s error\n", plugin);
- }
-}
-
-#endif /* HAVE_FLAC || HAVE_OGGFLAC */
diff --git a/trunk/src/inputPlugins/_flac_common.h b/trunk/src/inputPlugins/_flac_common.h
deleted file mode 100644
index e04e70693..000000000
--- a/trunk/src/inputPlugins/_flac_common.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * Common data structures and functions used by FLAC and OggFLAC
- * (c) 2005 by Eric Wong <normalperson@yhbt.net>
- *
- * 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
- */
-
-#ifndef _FLAC_COMMON_H
-#define _FLAC_COMMON_H
-
-#include "../inputPlugin.h"
-
-#if defined(HAVE_FLAC) || defined(HAVE_OGGFLAC)
-
-#include "../tag.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-#include "../decode.h"
-#include <FLAC/export.h>
-#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
-# include <FLAC/seekable_stream_decoder.h>
-# define flac_decoder FLAC__SeekableStreamDecoder
-# define flac_new() FLAC__seekable_stream_decoder_new()
-
-# define flac_ogg_init(a,b,c,d,e,f,g,h,i,j) (0)
-
-# define flac_get_decode_position(x,y) \
- FLAC__seekable_stream_decoder_get_decode_position(x,y)
-# define flac_get_state(x) FLAC__seekable_stream_decoder_get_state(x)
-# define flac_process_single(x) FLAC__seekable_stream_decoder_process_single(x)
-# define flac_process_metadata(x) \
- FLAC__seekable_stream_decoder_process_until_end_of_metadata(x)
-# define flac_seek_absolute(x,y) \
- FLAC__seekable_stream_decoder_seek_absolute(x,y)
-# define flac_finish(x) FLAC__seekable_stream_decoder_finish(x)
-# define flac_delete(x) FLAC__seekable_stream_decoder_delete(x)
-
-# define flac_decoder_eof FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM
-
-typedef unsigned flac_read_status_size_t;
-# define flac_read_status FLAC__SeekableStreamDecoderReadStatus
-# define flac_read_status_continue \
- FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK
-# define flac_read_status_eof FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK
-# define flac_read_status_abort \
- FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR
-
-# define flac_seek_status FLAC__SeekableStreamDecoderSeekStatus
-# define flac_seek_status_ok FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK
-# define flac_seek_status_error FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR
-
-# define flac_tell_status FLAC__SeekableStreamDecoderTellStatus
-# define flac_tell_status_ok FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK
-# define flac_tell_status_error \
- FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
-# define flac_tell_status_unsupported \
- FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
-
-# define flac_length_status FLAC__SeekableStreamDecoderLengthStatus
-# define flac_length_status_ok FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK
-# define flac_length_status_error \
- FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
-# define flac_length_status_unsupported \
- FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
-
-# ifdef HAVE_OGGFLAC
-# include <OggFLAC/seekable_stream_decoder.h>
-# endif
-#else /* FLAC_API_VERSION_CURRENT >= 7 */
-
- /* OggFLAC support is handled by our flac_plugin already, and
- * thus we *can* always have it if libFLAC was compiled with it */
-# ifndef HAVE_OGGFLAC
-# define HAVE_OGGFLAC 1
-# endif
-# include "_ogg_common.h"
-# undef HAVE_OGGFLAC /* we don't need this defined anymore */
-
-# include <FLAC/stream_decoder.h>
-# define flac_decoder FLAC__StreamDecoder
-# define flac_new() FLAC__stream_decoder_new()
-
-# define flac_init(a,b,c,d,e,f,g,h,i,j) \
- (FLAC__stream_decoder_init_stream(a,b,c,d,e,f,g,h,i,j) \
- == FLAC__STREAM_DECODER_INIT_STATUS_OK)
-# define flac_ogg_init(a,b,c,d,e,f,g,h,i,j) \
- (FLAC__stream_decoder_init_ogg_stream(a,b,c,d,e,f,g,h,i,j) \
- == FLAC__STREAM_DECODER_INIT_STATUS_OK)
-
-# define flac_get_decode_position(x,y) \
- FLAC__stream_decoder_get_decode_position(x,y)
-# define flac_get_state(x) FLAC__stream_decoder_get_state(x)
-# define flac_process_single(x) FLAC__stream_decoder_process_single(x)
-# define flac_process_metadata(x) \
- FLAC__stream_decoder_process_until_end_of_metadata(x)
-# define flac_seek_absolute(x,y) FLAC__stream_decoder_seek_absolute(x,y)
-# define flac_finish(x) FLAC__stream_decoder_finish(x)
-# define flac_delete(x) FLAC__stream_decoder_delete(x)
-
-# define flac_decoder_eof FLAC__STREAM_DECODER_END_OF_STREAM
-
-typedef size_t flac_read_status_size_t;
-# define flac_read_status FLAC__StreamDecoderReadStatus
-# define flac_read_status_continue \
- FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
-# define flac_read_status_eof FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
-# define flac_read_status_abort FLAC__STREAM_DECODER_READ_STATUS_ABORT
-
-# define flac_seek_status FLAC__StreamDecoderSeekStatus
-# define flac_seek_status_ok FLAC__STREAM_DECODER_SEEK_STATUS_OK
-# define flac_seek_status_error FLAC__STREAM_DECODER_SEEK_STATUS_ERROR
-# define flac_seek_status_unsupported \
- FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
-
-# define flac_tell_status FLAC__StreamDecoderTellStatus
-# define flac_tell_status_ok FLAC__STREAM_DECODER_TELL_STATUS_OK
-# define flac_tell_status_error FLAC__STREAM_DECODER_TELL_STATUS_ERROR
-# define flac_tell_status_unsupported \
- FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
-
-# define flac_length_status FLAC__StreamDecoderLengthStatus
-# define flac_length_status_ok FLAC__STREAM_DECODER_LENGTH_STATUS_OK
-# define flac_length_status_error FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR
-# define flac_length_status_unsupported \
- FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
-
-#endif /* FLAC_API_VERSION_CURRENT >= 7 */
-
-#include <FLAC/metadata.h>
-
-#define FLAC_CHUNK_SIZE 4080
-
-typedef struct {
- unsigned char chunk[FLAC_CHUNK_SIZE];
- int chunk_length;
- float time;
- int bitRate;
- FLAC__uint64 position;
- OutputBuffer *cb;
- DecoderControl *dc;
- InputStream *inStream;
- ReplayGainInfo *replayGainInfo;
- MpdTag *tag;
-} FlacData;
-
-/* initializes a given FlacData struct */
-void init_FlacData(FlacData * data, OutputBuffer * cb,
- DecoderControl * dc, InputStream * inStream);
-void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
- FlacData * data);
-void flac_error_common_cb(const char *plugin,
- FLAC__StreamDecoderErrorStatus status,
- FlacData * data);
-
-MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
- MpdTag * tag);
-
-/* keep this inlined, this is just macro but prettier :) */
-static inline int flacSendChunk(FlacData * data)
-{
- if (sendDataToOutputBuffer(data->cb, NULL, data->dc, 1, data->chunk,
- data->chunk_length, data->time,
- data->bitRate,
- data->replayGainInfo) ==
- OUTPUT_BUFFER_DC_STOP)
- return -1;
-
- return 0;
-}
-
-#endif /* HAVE_FLAC || HAVE_OGGFLAC */
-
-#endif /* _FLAC_COMMON_H */
diff --git a/trunk/src/inputPlugins/_ogg_common.c b/trunk/src/inputPlugins/_ogg_common.c
deleted file mode 100644
index c83e46103..000000000
--- a/trunk/src/inputPlugins/_ogg_common.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC)
- * (c) 2005 by Eric Wong <normalperson@yhbt.net>
- *
- * 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 "../inputPlugin.h"
-
-#if defined(HAVE_OGGFLAC) || defined(HAVE_OGGVORBIS)
-
-#include "../utils.h"
-#include "_ogg_common.h"
-
-#include <string.h>
-
-ogg_stream_type ogg_stream_type_detect(InputStream * inStream)
-{
- /* oggflac detection based on code in ogg123 and this post
- * http://lists.xiph.org/pipermail/flac/2004-December/000393.html
- * ogg123 trunk still doesn't have this patch as of June 2005 */
- unsigned char buf[41];
- size_t r, to_read = 41;
-
- seekInputStream(inStream, 0, SEEK_SET);
-
- while (to_read) {
- r = readFromInputStream(inStream, buf, 1, to_read);
- if (inStream->error)
- break;
- to_read -= r;
- if (!r && !inputStreamAtEOF(inStream))
- my_usleep(10000);
- else
- break;
- }
-
- seekInputStream(inStream, 0, SEEK_SET);
-
- if (r >= 32 && memcmp(buf, "OggS", 4) == 0 && ((memcmp
- (buf + 29, "FLAC",
- 4) == 0
- && memcmp(buf + 37,
- "fLaC",
- 4) == 0)
- ||
- (memcmp
- (buf + 28, "FLAC",
- 4) == 0)
- ||
- (memcmp
- (buf + 28, "fLaC",
- 4) == 0))) {
- return FLAC;
- }
- return VORBIS;
-}
-
-#endif /* defined(HAVE_OGGFLAC || defined(HAVE_OGGVORBIS) */
diff --git a/trunk/src/inputPlugins/_ogg_common.h b/trunk/src/inputPlugins/_ogg_common.h
deleted file mode 100644
index 5821e6641..000000000
--- a/trunk/src/inputPlugins/_ogg_common.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC)
- * (c) 2005 by Eric Wong <normalperson@yhbt.net>
- *
- * 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
- */
-
-#ifndef _OGG_COMMON_H
-#define _OGG_COMMON_H
-
-#include "../inputPlugin.h"
-
-#if defined(HAVE_OGGFLAC) || defined(HAVE_OGGVORBIS)
-
-typedef enum _ogg_stream_type { VORBIS, FLAC } ogg_stream_type;
-
-ogg_stream_type ogg_stream_type_detect(InputStream * inStream);
-
-#endif /* defined(HAVE_OGGFLAC || defined(HAVE_OGGVORBIS) */
-
-#endif /* _OGG_COMMON_H */
diff --git a/trunk/src/inputPlugins/aac_plugin.c b/trunk/src/inputPlugins/aac_plugin.c
deleted file mode 100644
index 529689706..000000000
--- a/trunk/src/inputPlugins/aac_plugin.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * 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 "../inputPlugin.h"
-
-#ifdef HAVE_FAAD
-
-#define AAC_MAX_CHANNELS 6
-
-#include "../utils.h"
-#include "../audio.h"
-#include "../log.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <faad.h>
-
-/* all code here is either based on or copied from FAAD2's frontend code */
-typedef struct {
- InputStream *inStream;
- long bytesIntoBuffer;
- long bytesConsumed;
- long fileOffset;
- unsigned char *buffer;
- int atEof;
-} AacBuffer;
-
-static void fillAacBuffer(AacBuffer * b)
-{
- if (b->bytesConsumed > 0) {
- int bread;
-
- if (b->bytesIntoBuffer) {
- memmove((void *)b->buffer, (void *)(b->buffer +
- b->bytesConsumed),
- b->bytesIntoBuffer);
- }
-
- if (!b->atEof) {
- bread = readFromInputStream(b->inStream,
- (void *)(b->buffer +
- b->
- bytesIntoBuffer),
- 1, b->bytesConsumed);
- if (bread != b->bytesConsumed)
- b->atEof = 1;
- b->bytesIntoBuffer += bread;
- }
-
- b->bytesConsumed = 0;
-
- if (b->bytesIntoBuffer > 3) {
- if (memcmp(b->buffer, "TAG", 3) == 0)
- b->bytesIntoBuffer = 0;
- }
- if (b->bytesIntoBuffer > 11) {
- if (memcmp(b->buffer, "LYRICSBEGIN", 11) == 0) {
- b->bytesIntoBuffer = 0;
- }
- }
- if (b->bytesIntoBuffer > 8) {
- if (memcmp(b->buffer, "APETAGEX", 8) == 0) {
- b->bytesIntoBuffer = 0;
- }
- }
- }
-}
-
-static void advanceAacBuffer(AacBuffer * b, int bytes)
-{
- b->fileOffset += bytes;
- b->bytesConsumed = bytes;
- b->bytesIntoBuffer -= bytes;
-}
-
-static int adtsSampleRates[] =
- { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
- 16000, 12000, 11025, 8000, 7350, 0, 0, 0
-};
-
-static int adtsParse(AacBuffer * b, float *length)
-{
- int frames, frameLength;
- int tFrameLength = 0;
- int sampleRate = 0;
- float framesPerSec, bytesPerFrame;
-
- /* Read all frames to ensure correct time and bitrate */
- for (frames = 0;; frames++) {
- fillAacBuffer(b);
-
- if (b->bytesIntoBuffer > 7) {
- /* check syncword */
- if (!((b->buffer[0] == 0xFF) &&
- ((b->buffer[1] & 0xF6) == 0xF0))) {
- break;
- }
-
- if (frames == 0) {
- sampleRate = adtsSampleRates[(b->
- buffer[2] & 0x3c)
- >> 2];
- }
-
- frameLength = ((((unsigned int)b->buffer[3] & 0x3))
- << 11) | (((unsigned int)b->buffer[4])
- << 3) | (b->buffer[5] >> 5);
-
- tFrameLength += frameLength;
-
- if (frameLength > b->bytesIntoBuffer)
- break;
-
- advanceAacBuffer(b, frameLength);
- } else
- break;
- }
-
- framesPerSec = (float)sampleRate / 1024.0;
- if (frames != 0) {
- bytesPerFrame = (float)tFrameLength / (float)(frames * 1000);
- } else
- bytesPerFrame = 0;
- if (framesPerSec != 0)
- *length = (float)frames / framesPerSec;
-
- return 1;
-}
-
-static void initAacBuffer(InputStream * inStream, AacBuffer * b, float *length,
- size_t * retFileread, size_t * retTagsize)
-{
- size_t fileread;
- size_t bread;
- size_t tagsize;
-
- if (length)
- *length = -1;
-
- memset(b, 0, sizeof(AacBuffer));
-
- b->inStream = inStream;
-
- fileread = inStream->size;
-
- b->buffer = xmalloc(FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
- memset(b->buffer, 0, FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
-
- bread = readFromInputStream(inStream, b->buffer, 1,
- FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
- b->bytesIntoBuffer = bread;
- b->bytesConsumed = 0;
- b->fileOffset = 0;
-
- if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS)
- b->atEof = 1;
-
- tagsize = 0;
- if (!memcmp(b->buffer, "ID3", 3)) {
- tagsize = (b->buffer[6] << 21) | (b->buffer[7] << 14) |
- (b->buffer[8] << 7) | (b->buffer[9] << 0);
-
- tagsize += 10;
- advanceAacBuffer(b, tagsize);
- fillAacBuffer(b);
- }
-
- if (retFileread)
- *retFileread = fileread;
- if (retTagsize)
- *retTagsize = tagsize;
-
- if (length == NULL)
- return;
-
- if ((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) {
- adtsParse(b, length);
- seekInputStream(b->inStream, tagsize, SEEK_SET);
-
- bread = readFromInputStream(b->inStream, b->buffer, 1,
- FAAD_MIN_STREAMSIZE *
- AAC_MAX_CHANNELS);
- if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS)
- b->atEof = 1;
- else
- b->atEof = 0;
- b->bytesIntoBuffer = bread;
- b->bytesConsumed = 0;
- b->fileOffset = tagsize;
- } else if (memcmp(b->buffer, "ADIF", 4) == 0) {
- int bitRate;
- int skipSize = (b->buffer[4] & 0x80) ? 9 : 0;
- bitRate =
- ((unsigned int)(b->
- buffer[4 +
- skipSize] & 0x0F) << 19) | ((unsigned
- int)b->
- buffer[5
- +
- skipSize]
- << 11) |
- ((unsigned int)b->
- buffer[6 + skipSize] << 3) | ((unsigned int)b->buffer[7 +
- skipSize]
- & 0xE0);
-
- if (fileread != 0 && bitRate != 0)
- *length = fileread * 8.0 / bitRate;
- else
- *length = fileread;
- }
-}
-
-static float getAacFloatTotalTime(char *file)
-{
- AacBuffer b;
- float length;
- size_t fileread, tagsize;
- faacDecHandle decoder;
- faacDecConfigurationPtr config;
- unsigned long sampleRate;
- unsigned char channels;
- InputStream inStream;
- long bread;
-
- if (openInputStream(&inStream, file) < 0)
- return -1;
-
- initAacBuffer(&inStream, &b, &length, &fileread, &tagsize);
-
- if (length < 0) {
- decoder = faacDecOpen();
-
- config = faacDecGetCurrentConfiguration(decoder);
- config->outputFormat = FAAD_FMT_16BIT;
- faacDecSetConfiguration(decoder, config);
-
- fillAacBuffer(&b);
-#ifdef HAVE_FAAD_BUFLEN_FUNCS
- bread = faacDecInit(decoder, b.buffer, b.bytesIntoBuffer,
- &sampleRate, &channels);
-#else
- bread = faacDecInit(decoder, b.buffer, &sampleRate, &channels);
-#endif
- if (bread >= 0 && sampleRate > 0 && channels > 0)
- length = 0;
-
- faacDecClose(decoder);
- }
-
- if (b.buffer)
- free(b.buffer);
- closeInputStream(&inStream);
-
- return length;
-}
-
-static int getAacTotalTime(char *file)
-{
- int time = -1;
- float length;
-
- if ((length = getAacFloatTotalTime(file)) >= 0)
- time = length + 0.5;
-
- return time;
-}
-
-static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
-{
- float time;
- float totalTime;
- faacDecHandle decoder;
- faacDecFrameInfo frameInfo;
- faacDecConfigurationPtr config;
- long bread;
- unsigned long sampleRate;
- unsigned char channels;
- int eof = 0;
- unsigned int sampleCount;
- char *sampleBuffer;
- size_t sampleBufferLen;
- /*float * seekTable;
- long seekTableEnd = -1;
- int seekPositionFound = 0; */
- mpd_uint16 bitRate = 0;
- AacBuffer b;
- InputStream inStream;
-
- if ((totalTime = getAacFloatTotalTime(path)) < 0)
- return -1;
-
- if (openInputStream(&inStream, path) < 0)
- return -1;
-
- initAacBuffer(&inStream, &b, NULL, NULL, NULL);
-
- decoder = faacDecOpen();
-
- config = faacDecGetCurrentConfiguration(decoder);
- config->outputFormat = FAAD_FMT_16BIT;
-#ifdef HAVE_FAACDECCONFIGURATION_DOWNMATRIX
- config->downMatrix = 1;
-#endif
-#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
- config->dontUpSampleImplicitSBR = 0;
-#endif
- faacDecSetConfiguration(decoder, config);
-
- fillAacBuffer(&b);
-
-#ifdef HAVE_FAAD_BUFLEN_FUNCS
- bread = faacDecInit(decoder, b.buffer, b.bytesIntoBuffer,
- &sampleRate, &channels);
-#else
- bread = faacDecInit(decoder, b.buffer, &sampleRate, &channels);
-#endif
- if (bread < 0) {
- ERROR("Error not a AAC stream.\n");
- faacDecClose(decoder);
- closeInputStream(b.inStream);
- if (b.buffer)
- free(b.buffer);
- return -1;
- }
-
- dc->audioFormat.bits = 16;
-
- dc->totalTime = totalTime;
-
- time = 0.0;
-
- advanceAacBuffer(&b, bread);
-
- while (!eof) {
- fillAacBuffer(&b);
-
- if (b.bytesIntoBuffer == 0) {
- eof = 1;
- break;
- }
-#ifdef HAVE_FAAD_BUFLEN_FUNCS
- sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer,
- b.bytesIntoBuffer);
-#else
- sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer);
-#endif
-
- if (frameInfo.error > 0) {
- ERROR("error decoding AAC file: %s\n", path);
- ERROR("faad2 error: %s\n",
- faacDecGetErrorMessage(frameInfo.error));
- eof = 1;
- break;
- }
-#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
- sampleRate = frameInfo.samplerate;
-#endif
-
- if (dc->state != DECODE_STATE_DECODE) {
- dc->audioFormat.channels = frameInfo.channels;
- dc->audioFormat.sampleRate = sampleRate;
- getOutputAudioFormat(&(dc->audioFormat),
- &(cb->audioFormat));
- dc->state = DECODE_STATE_DECODE;
- }
-
- advanceAacBuffer(&b, frameInfo.bytesconsumed);
-
- sampleCount = (unsigned long)(frameInfo.samples);
-
- if (sampleCount > 0) {
- bitRate = frameInfo.bytesconsumed * 8.0 *
- frameInfo.channels * sampleRate /
- frameInfo.samples / 1000 + 0.5;
- time +=
- (float)(frameInfo.samples) / frameInfo.channels /
- sampleRate;
- }
-
- sampleBufferLen = sampleCount * 2;
-
- sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer,
- sampleBufferLen, time, bitRate, NULL);
- if (dc->seek) {
- dc->seekError = 1;
- dc->seek = 0;
- } else if (dc->stop) {
- eof = 1;
- break;
- }
- }
-
- flushOutputBuffer(cb);
-
- faacDecClose(decoder);
- closeInputStream(b.inStream);
- if (b.buffer)
- free(b.buffer);
-
- if (dc->state != DECODE_STATE_DECODE)
- return -1;
-
- 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;
-}
-
-static MpdTag *aacTagDup(char *file)
-{
- MpdTag *ret = NULL;
- int time;
-
- time = getAacTotalTime(file);
-
- if (time >= 0) {
- if ((ret = id3Dup(file)) == NULL)
- ret = newMpdTag();
- ret->time = time;
- } else {
- DEBUG("aacTagDup: Failed to get total song time from: %s\n",
- file);
- }
-
- return ret;
-}
-
-static char *aacSuffixes[] = { "aac", NULL };
-
-InputPlugin aacPlugin = {
- "aac",
- NULL,
- NULL,
- NULL,
- NULL,
- aac_decode,
- aacTagDup,
- INPUT_PLUGIN_STREAM_FILE,
- aacSuffixes,
- NULL
-};
-
-#else
-
-InputPlugin aacPlugin;
-
-#endif /* HAVE_FAAD */
diff --git a/trunk/src/inputPlugins/audiofile_plugin.c b/trunk/src/inputPlugins/audiofile_plugin.c
deleted file mode 100644
index 35fb48b8a..000000000
--- a/trunk/src/inputPlugins/audiofile_plugin.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.net>
- *
- * 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 "../inputPlugin.h"
-
-#ifdef HAVE_AUDIOFILE
-
-#include "../utils.h"
-#include "../audio.h"
-#include "../log.h"
-#include "../pcm_utils.h"
-#include "../playerData.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <audiofile.h>
-
-static int getAudiofileTotalTime(char *file)
-{
- int time;
- AFfilehandle af_fp = afOpenFile(file, "r", NULL);
- if (af_fp == AF_NULL_FILEHANDLE) {
- return -1;
- }
- time = (int)
- ((double)afGetFrameCount(af_fp, AF_DEFAULT_TRACK)
- / afGetRate(af_fp, AF_DEFAULT_TRACK));
- afCloseFile(af_fp);
- return time;
-}
-
-static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
-{
- int fs, frame_count;
- AFfilehandle af_fp;
- int bits;
- mpd_uint16 bitRate;
- struct stat st;
-
- if (stat(path, &st) < 0) {
- ERROR("failed to stat: %s\n", path);
- return -1;
- }
-
- af_fp = afOpenFile(path, "r", NULL);
- if (af_fp == AF_NULL_FILEHANDLE) {
- ERROR("failed to open: %s\n", path);
- return -1;
- }
-
- afSetVirtualSampleFormat(af_fp, AF_DEFAULT_TRACK,
- AF_SAMPFMT_TWOSCOMP, 16);
- afGetVirtualSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &bits);
- dc->audioFormat.bits = bits;
- dc->audioFormat.sampleRate = afGetRate(af_fp, AF_DEFAULT_TRACK);
- dc->audioFormat.channels = afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK);
- getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
-
- frame_count = afGetFrameCount(af_fp, AF_DEFAULT_TRACK);
-
- dc->totalTime =
- ((float)frame_count / (float)dc->audioFormat.sampleRate);
-
- bitRate = st.st_size * 8.0 / dc->totalTime / 1000.0 + 0.5;
-
- if (dc->audioFormat.bits != 8 && dc->audioFormat.bits != 16) {
- ERROR("Only 8 and 16-bit files are supported. %s is %i-bit\n",
- path, dc->audioFormat.bits);
- afCloseFile(af_fp);
- return -1;
- }
-
- fs = (int)afGetVirtualFrameSize(af_fp, AF_DEFAULT_TRACK, 1);
-
- dc->state = DECODE_STATE_DECODE;
- {
- int ret, eof = 0, current = 0;
- char chunk[CHUNK_SIZE];
-
- while (!eof) {
- if (dc->seek) {
- clearOutputBuffer(cb);
- current = dc->seekWhere *
- dc->audioFormat.sampleRate;
- afSeekFrame(af_fp, AF_DEFAULT_TRACK, current);
- dc->seek = 0;
- }
-
- ret =
- afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk,
- CHUNK_SIZE / fs);
- if (ret <= 0)
- eof = 1;
- else {
- current += ret;
- sendDataToOutputBuffer(cb,
- NULL,
- dc,
- 1,
- chunk,
- ret * fs,
- (float)current /
- (float)dc->audioFormat.
- sampleRate, bitRate,
- NULL);
- if (dc->stop)
- break;
- }
- }
-
- flushOutputBuffer(cb);
-
- /*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;
- }
- afCloseFile(af_fp);
-
- return 0;
-}
-
-static MpdTag *audiofileTagDup(char *file)
-{
- MpdTag *ret = NULL;
- int time = getAudiofileTotalTime(file);
-
- if (time >= 0) {
- if (!ret)
- ret = newMpdTag();
- ret->time = time;
- } else {
- DEBUG
- ("audiofileTagDup: Failed to get total song time from: %s\n",
- file);
- }
-
- return ret;
-}
-
-static char *audiofileSuffixes[] = { "wav", "au", "aiff", "aif", NULL };
-
-InputPlugin audiofilePlugin = {
- "audiofile",
- NULL,
- NULL,
- NULL,
- NULL,
- audiofile_decode,
- audiofileTagDup,
- INPUT_PLUGIN_STREAM_FILE,
- audiofileSuffixes,
- NULL
-};
-
-#else
-
-InputPlugin audiofilePlugin;
-
-#endif /* HAVE_AUDIOFILE */
diff --git a/trunk/src/inputPlugins/flac_plugin.c b/trunk/src/inputPlugins/flac_plugin.c
deleted file mode 100644
index 3f3a4b4f1..000000000
--- a/trunk/src/inputPlugins/flac_plugin.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * 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 "_flac_common.h"
-
-#ifdef HAVE_FLAC
-
-#include "../utils.h"
-#include "../log.h"
-#include "../pcm_utils.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-#include "../replayGain.h"
-#include "../audio.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-
-/* this code was based on flac123, from flac-tools */
-
-static flac_read_status flacRead(const flac_decoder * flacDec,
- FLAC__byte buf[],
- flac_read_status_size_t *bytes,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
- size_t r;
-
- while (1) {
- r = readFromInputStream(data->inStream, (void *)buf, 1, *bytes);
- if (r == 0 && !inputStreamAtEOF(data->inStream) &&
- !data->dc->stop)
- my_usleep(10000);
- else
- break;
- }
- *bytes = r;
-
- if (r == 0 && !data->dc->stop) {
- if (inputStreamAtEOF(data->inStream))
- return flac_read_status_eof;
- else
- return flac_read_status_abort;
- }
- return flac_read_status_continue;
-}
-
-static flac_seek_status flacSeek(const flac_decoder * flacDec,
- FLAC__uint64 offset,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- if (seekInputStream(data->inStream, offset, SEEK_SET) < 0) {
- return flac_seek_status_error;
- }
-
- return flac_seek_status_ok;
-}
-
-static flac_tell_status flacTell(const flac_decoder * flacDec,
- FLAC__uint64 * offset,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- *offset = (long)(data->inStream->offset);
-
- return flac_tell_status_ok;
-}
-
-static flac_length_status flacLength(const flac_decoder * flacDec,
- FLAC__uint64 * length,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- *length = (size_t) (data->inStream->size);
-
- return flac_length_status_ok;
-}
-
-static FLAC__bool flacEOF(const flac_decoder * flacDec, void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- if (inputStreamAtEOF(data->inStream) == 1)
- return true;
- return false;
-}
-
-static void flacError(const flac_decoder *dec,
- FLAC__StreamDecoderErrorStatus status, void *fdata)
-{
- flac_error_common_cb("flac", status, (FlacData *) fdata);
-}
-
-#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
-static void flacPrintErroredState(FLAC__SeekableStreamDecoderState state)
-{
- const char *str = ""; /* "" to silence compiler warning */
- switch (state) {
- case FLAC__SEEKABLE_STREAM_DECODER_OK:
- case FLAC__SEEKABLE_STREAM_DECODER_SEEKING:
- case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM:
- return;
- case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
- str = "allocation error";
- break;
- case FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR:
- str = "read error";
- break;
- case FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR:
- str = "seek error";
- break;
- case FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR:
- str = "seekable stream error";
- break;
- case FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED:
- str = "decoder already initialized";
- break;
- case FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK:
- str = "invalid callback";
- break;
- case FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED:
- str = "decoder uninitialized";
- }
- ERROR("flac %s\n", str);
-}
-
-static int flac_init(FLAC__SeekableStreamDecoder *dec,
- FLAC__SeekableStreamDecoderReadCallback read_cb,
- FLAC__SeekableStreamDecoderSeekCallback seek_cb,
- FLAC__SeekableStreamDecoderTellCallback tell_cb,
- FLAC__SeekableStreamDecoderLengthCallback length_cb,
- FLAC__SeekableStreamDecoderEofCallback eof_cb,
- FLAC__SeekableStreamDecoderWriteCallback write_cb,
- FLAC__SeekableStreamDecoderMetadataCallback metadata_cb,
- FLAC__SeekableStreamDecoderErrorCallback error_cb,
- void *data)
-{
- int s = 1;
- s &= FLAC__seekable_stream_decoder_set_read_callback(dec, read_cb);
- s &= FLAC__seekable_stream_decoder_set_seek_callback(dec, seek_cb);
- s &= FLAC__seekable_stream_decoder_set_tell_callback(dec, tell_cb);
- s &= FLAC__seekable_stream_decoder_set_length_callback(dec, length_cb);
- s &= FLAC__seekable_stream_decoder_set_eof_callback(dec, eof_cb);
- s &= FLAC__seekable_stream_decoder_set_write_callback(dec, write_cb);
- s &= FLAC__seekable_stream_decoder_set_metadata_callback(dec,
- metadata_cb);
- s &= FLAC__seekable_stream_decoder_set_metadata_respond(dec,
- FLAC__METADATA_TYPE_VORBIS_COMMENT);
- s &= FLAC__seekable_stream_decoder_set_error_callback(dec, error_cb);
- s &= FLAC__seekable_stream_decoder_set_client_data(dec, data);
- if (!s || (FLAC__seekable_stream_decoder_init(dec) !=
- FLAC__SEEKABLE_STREAM_DECODER_OK))
- return 0;
- return 1;
-}
-#else /* FLAC_API_VERSION_CURRENT >= 7 */
-static void flacPrintErroredState(FLAC__StreamDecoderState state)
-{
- const char *str = ""; /* "" to silence compiler warning */
- switch (state) {
- case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
- case FLAC__STREAM_DECODER_READ_METADATA:
- case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
- case FLAC__STREAM_DECODER_READ_FRAME:
- case FLAC__STREAM_DECODER_END_OF_STREAM:
- return;
- case FLAC__STREAM_DECODER_OGG_ERROR:
- str = "error in the Ogg layer";
- break;
- case FLAC__STREAM_DECODER_SEEK_ERROR:
- str = "seek error";
- break;
- case FLAC__STREAM_DECODER_ABORTED:
- str = "decoder aborted by read";
- break;
- case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
- str = "allocation error";
- break;
- case FLAC__STREAM_DECODER_UNINITIALIZED:
- str = "decoder uninitialized";
- }
- ERROR("flac %s\n", str);
-}
-#endif /* FLAC_API_VERSION_CURRENT >= 7 */
-
-static void flacMetadata(const flac_decoder * dec,
- const FLAC__StreamMetadata * block, void *vdata)
-{
- flac_metadata_common_cb(block, (FlacData *) vdata);
-}
-
-static FLAC__StreamDecoderWriteStatus flacWrite(const flac_decoder *dec,
- const FLAC__Frame * frame,
- const FLAC__int32 * const buf[],
- void *vdata)
-{
- FlacData *data = (FlacData *) vdata;
- FLAC__uint32 samples = frame->header.blocksize;
- FLAC__uint16 u16;
- unsigned char *uc;
- int c_samp, c_chan, d_samp;
- int i;
- float timeChange;
- FLAC__uint64 newPosition = 0;
-
- timeChange = ((float)samples) / frame->header.sample_rate;
- data->time += timeChange;
-
- flac_get_decode_position(dec, &newPosition);
- if (data->position) {
- data->bitRate =
- ((newPosition - data->position) * 8.0 / timeChange)
- / 1000 + 0.5;
- }
- data->position = newPosition;
-
- for (c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) {
- for (c_chan = 0; c_chan < frame->header.channels;
- c_chan++, d_samp++) {
- u16 = buf[c_chan][c_samp];
- uc = (unsigned char *)&u16;
- for (i = 0; i < (data->dc->audioFormat.bits / 8); i++) {
- if (data->chunk_length >= FLAC_CHUNK_SIZE) {
- if (flacSendChunk(data) < 0) {
- return
- FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
- }
- data->chunk_length = 0;
- if (data->dc->seek) {
- return
- FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
- }
- }
- data->chunk[data->chunk_length++] = *(uc++);
- }
- }
- }
-
- return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-}
-
-static MpdTag *flacMetadataDup(char *file, int *vorbisCommentFound)
-{
- MpdTag *ret = NULL;
- FLAC__Metadata_SimpleIterator *it;
- FLAC__StreamMetadata *block = NULL;
-
- *vorbisCommentFound = 0;
-
- it = FLAC__metadata_simple_iterator_new();
- if (!FLAC__metadata_simple_iterator_init(it, file, 1, 0)) {
- switch (FLAC__metadata_simple_iterator_status(it)) {
- case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
- DEBUG
- ("flacMetadataDup: Reading '%s' metadata gave the following error: Illegal Input\n",
- file);
- break;
- case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
- DEBUG
- ("flacMetadataDup: Reading '%s' metadata gave the following error: Error Opening File\n",
- file);
- break;
- case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
- DEBUG
- ("flacMetadataDup: Reading '%s' metadata gave the following error: Not A Flac File\n",
- file);
- break;
- default:
- DEBUG("flacMetadataDup: Reading '%s' metadata failed\n",
- file);
- }
- FLAC__metadata_simple_iterator_delete(it);
- return ret;
- }
-
- do {
- block = FLAC__metadata_simple_iterator_get_block(it);
- if (!block)
- break;
- if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
- ret = copyVorbisCommentBlockToMpdTag(block, ret);
-
- if (ret)
- *vorbisCommentFound = 1;
- } else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
- if (!ret)
- ret = newMpdTag();
- ret->time = ((float)block->data.stream_info.
- total_samples) /
- block->data.stream_info.sample_rate + 0.5;
- }
- FLAC__metadata_object_delete(block);
- } while (FLAC__metadata_simple_iterator_next(it));
-
- FLAC__metadata_simple_iterator_delete(it);
- return ret;
-}
-
-static MpdTag *flacTagDup(char *file)
-{
- MpdTag *ret = NULL;
- int foundVorbisComment = 0;
-
- ret = flacMetadataDup(file, &foundVorbisComment);
- if (!ret) {
- DEBUG("flacTagDup: Failed to grab information from: %s\n",
- file);
- return NULL;
- }
- if (!foundVorbisComment) {
- MpdTag *temp = id3Dup(file);
- if (temp) {
- temp->time = ret->time;
- freeMpdTag(ret);
- ret = temp;
- }
- }
-
- return ret;
-}
-
-static int flac_decode_internal(OutputBuffer * cb, DecoderControl * dc,
- InputStream * inStream, int is_ogg)
-{
- flac_decoder *flacDec;
- FlacData data;
- const char *err = NULL;
-
- if (!(flacDec = flac_new()))
- return -1;
- init_FlacData(&data, cb, dc, inStream);
- if (is_ogg) {
- if (!flac_ogg_init(flacDec, flacRead, flacSeek, flacTell,
- flacLength, flacEOF, flacWrite, flacMetadata,
- flacError, (void *)&data)) {
- err = "doing Ogg init()";
- goto fail;
- }
- } else {
- if (!flac_init(flacDec, flacRead, flacSeek, flacTell,
- flacLength, flacEOF, flacWrite, flacMetadata,
- flacError, (void *)&data)) {
- err = "doing init()";
- goto fail;
- }
- if (!flac_process_metadata(flacDec)) {
- err = "problem reading metadata";
- goto fail;
- }
- }
-
- dc->state = DECODE_STATE_DECODE;
-
- while (1) {
- if (!flac_process_single(flacDec))
- break;
- if (flac_get_state(flacDec) == flac_decoder_eof)
- break;
- if (dc->seek) {
- FLAC__uint64 sampleToSeek = dc->seekWhere *
- dc->audioFormat.sampleRate + 0.5;
- if (flac_seek_absolute(flacDec, sampleToSeek)) {
- clearOutputBuffer(cb);
- data.time = ((float)sampleToSeek) /
- dc->audioFormat.sampleRate;
- data.position = 0;
- } else
- dc->seekError = 1;
- dc->seek = 0;
- }
- }
- if (!dc->stop) {
- flacPrintErroredState(flac_get_state(flacDec));
- flac_finish(flacDec);
- }
- /* send last little bit */
- if (data.chunk_length > 0 && !dc->stop) {
- flacSendChunk(&data);
- flushOutputBuffer(data.cb);
- }
-
- /*if(dc->seek) {
- dc->seekError = 1;
- dc->seek = 0;
- } */
-
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
-
-fail:
- if (data.replayGainInfo)
- freeReplayGainInfo(data.replayGainInfo);
-
- if (flacDec)
- flac_delete(flacDec);
-
- closeInputStream(inStream);
-
- if (err) {
- ERROR("flac %s\n", err);
- return -1;
- }
- return 0;
-}
-
-static int flac_decode(OutputBuffer * cb, DecoderControl * dc,
- InputStream * inStream)
-{
- return flac_decode_internal(cb, dc, inStream, 0);
-}
-
-#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
-# define flac_plugin_init NULL
-#else /* FLAC_API_VERSION_CURRENT >= 7 */
-/* some of this stuff is duplicated from oggflac_plugin.c */
-extern InputPlugin oggflacPlugin;
-
-static MpdTag *oggflac_tag_dup(char *file)
-{
- MpdTag *ret = NULL;
- FLAC__Metadata_Iterator *it;
- FLAC__StreamMetadata *block;
- FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
-
- if (!(FLAC__metadata_chain_read_ogg(chain, file)))
- goto out;
- it = FLAC__metadata_iterator_new();
- FLAC__metadata_iterator_init(it, chain);
- do {
- if (!(block = FLAC__metadata_iterator_get_block(it)))
- break;
- if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
- ret = copyVorbisCommentBlockToMpdTag(block, ret);
- } else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
- if (!ret)
- ret = newMpdTag();
- ret->time = ((float)block->data.stream_info.
- total_samples) /
- block->data.stream_info.sample_rate + 0.5;
- }
- } while (FLAC__metadata_iterator_next(it));
- FLAC__metadata_iterator_delete(it);
-out:
- FLAC__metadata_chain_delete(chain);
- return ret;
-}
-
-static int oggflac_decode(OutputBuffer * cb, DecoderControl * dc,
- InputStream * inStream)
-{
- return flac_decode_internal(cb, dc, inStream, 1);
-}
-
-static unsigned int oggflac_try_decode(InputStream * inStream)
-{
- return (ogg_stream_type_detect(inStream) == FLAC) ? 1 : 0;
-}
-
-static char *oggflac_suffixes[] = { "ogg", NULL };
-static char *oggflac_mime_types[] = { "audio/x-flac+ogg",
- "application/ogg",
- "application/x-ogg",
- NULL };
-
-static int flac_plugin_init(void)
-{
- if (!FLAC_API_SUPPORTS_OGG_FLAC) {
- DEBUG("libFLAC does not support OggFLAC\n");
- return 1;
- }
- DEBUG("libFLAC supports OggFLAC, initializing OggFLAC support\n");
- assert(oggflacPlugin.name == NULL);
- oggflacPlugin.name = "oggflac";
- oggflacPlugin.tryDecodeFunc = oggflac_try_decode;
- oggflacPlugin.streamDecodeFunc = oggflac_decode;
- oggflacPlugin.tagDupFunc = oggflac_tag_dup;
- oggflacPlugin.streamTypes = INPUT_PLUGIN_STREAM_URL |
- INPUT_PLUGIN_STREAM_FILE;
- oggflacPlugin.suffixes = oggflac_suffixes;
- oggflacPlugin.mimeTypes = oggflac_mime_types;
- loadInputPlugin(&oggflacPlugin);
- return 1;
-}
-
-#endif /* FLAC_API_VERSION_CURRENT >= 7 */
-
-static char *flacSuffixes[] = { "flac", NULL };
-static char *flac_mime_types[] = { "audio/x-flac",
- "application/x-flac",
- NULL };
-
-InputPlugin flacPlugin = {
- "flac",
- flac_plugin_init,
- NULL,
- NULL,
- flac_decode,
- NULL,
- flacTagDup,
- INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
- flacSuffixes,
- flac_mime_types
-};
-
-#else /* !HAVE_FLAC */
-
-InputPlugin flacPlugin;
-
-#endif /* HAVE_FLAC */
diff --git a/trunk/src/inputPlugins/mod_plugin.c b/trunk/src/inputPlugins/mod_plugin.c
deleted file mode 100644
index 800abc95f..000000000
--- a/trunk/src/inputPlugins/mod_plugin.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * 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 "../inputPlugin.h"
-
-#ifdef HAVE_MIKMOD
-
-#include "../utils.h"
-#include "../audio.h"
-#include "../log.h"
-#include "../pcm_utils.h"
-#include "../playerData.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <mikmod.h>
-
-/* this is largely copied from alsaplayer */
-
-#define MIKMOD_FRAME_SIZE 4096
-
-static BOOL mod_mpd_Init(void)
-{
- return VC_Init();
-}
-
-static void mod_mpd_Exit(void)
-{
- VC_Exit();
-}
-
-static void mod_mpd_Update(void)
-{
-}
-
-static BOOL mod_mpd_IsThere(void)
-{
- return 1;
-}
-
-static MDRIVER drv_mpd = {
- NULL,
- "MPD",
- "MPD Output Driver v0.1",
- 0,
- 255,
-#if (LIBMIKMOD_VERSION > 0x030106)
- "mpd", /* Alias */
-#if (LIBMIKMOD_VERSION > 0x030200)
- NULL, /* CmdLineHelp */
-#endif
- NULL, /* CommandLine */
-#endif
- mod_mpd_IsThere,
- VC_SampleLoad,
- VC_SampleUnload,
- VC_SampleSpace,
- VC_SampleLength,
- mod_mpd_Init,
- mod_mpd_Exit,
- NULL,
- VC_SetNumVoices,
- VC_PlayStart,
- VC_PlayStop,
- mod_mpd_Update,
- NULL,
- VC_VoiceSetVolume,
- VC_VoiceGetVolume,
- VC_VoiceSetFrequency,
- VC_VoiceGetFrequency,
- VC_VoiceSetPanning,
- VC_VoiceGetPanning,
- VC_VoicePlay,
- VC_VoiceStop,
- VC_VoiceStopped,
- VC_VoiceGetPosition,
- VC_VoiceRealVolume
-};
-
-static int mod_mikModInitiated;
-static int mod_mikModInitError;
-
-static int mod_initMikMod(void)
-{
- if (mod_mikModInitError)
- return -1;
-
- if (!mod_mikModInitiated) {
- mod_mikModInitiated = 1;
-
- md_device = 0;
- md_reverb = 0;
-
- MikMod_RegisterDriver(&drv_mpd);
- MikMod_RegisterAllLoaders();
- }
-
- md_pansep = 64;
- md_mixfreq = 44100;
- md_mode = (DMODE_SOFT_MUSIC | DMODE_INTERP | DMODE_STEREO |
- DMODE_16BITS);
-
- if (MikMod_Init("")) {
- ERROR("Could not init MikMod: %s\n",
- MikMod_strerror(MikMod_errno));
- mod_mikModInitError = 1;
- return -1;
- }
-
- return 0;
-}
-
-static void mod_finishMikMod(void)
-{
- MikMod_Exit();
-}
-
-typedef struct _mod_Data {
- MODULE *moduleHandle;
- SBYTE *audio_buffer;
-} mod_Data;
-
-static mod_Data *mod_open(char *path)
-{
- MODULE *moduleHandle;
- mod_Data *data;
-
- if (!(moduleHandle = Player_Load(path, 128, 0)))
- return NULL;
-
- /* Prevent module from looping forever */
- moduleHandle->loop = 0;
-
- data = xmalloc(sizeof(mod_Data));
-
- data->audio_buffer = xmalloc(MIKMOD_FRAME_SIZE);
- data->moduleHandle = moduleHandle;
-
- Player_Start(data->moduleHandle);
-
- return data;
-}
-
-static void mod_close(mod_Data * data)
-{
- Player_Stop();
- Player_Free(data->moduleHandle);
- free(data->audio_buffer);
- free(data);
-}
-
-static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
-{
- mod_Data *data;
- float time = 0.0;
- int ret;
- float secPerByte;
-
- if (mod_initMikMod() < 0)
- return -1;
-
- if (!(data = mod_open(path))) {
- ERROR("failed to open mod: %s\n", path);
- MikMod_Exit();
- return -1;
- }
-
- dc->totalTime = 0;
- dc->audioFormat.bits = 16;
- dc->audioFormat.sampleRate = 44100;
- dc->audioFormat.channels = 2;
- getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
-
- secPerByte =
- 1.0 / ((dc->audioFormat.bits * dc->audioFormat.channels / 8.0) *
- (float)dc->audioFormat.sampleRate);
-
- dc->state = DECODE_STATE_DECODE;
- while (1) {
- if (dc->seek) {
- dc->seekError = 1;
- dc->seek = 0;
- }
-
- if (dc->stop)
- break;
-
- if (!Player_Active())
- break;
-
- ret = VC_WriteBytes(data->audio_buffer, MIKMOD_FRAME_SIZE);
- time += ret * secPerByte;
- sendDataToOutputBuffer(cb, NULL, dc, 0,
- (char *)data->audio_buffer, ret, time,
- 0, NULL);
- }
-
- flushOutputBuffer(cb);
-
- mod_close(data);
-
- MikMod_Exit();
-
- if (dc->stop) {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- } else
- dc->state = DECODE_STATE_STOP;
-
- return 0;
-}
-
-static MpdTag *modTagDup(char *file)
-{
- MpdTag *ret = NULL;
- MODULE *moduleHandle;
- char *title;
-
- if (mod_initMikMod() < 0) {
- DEBUG("modTagDup: Failed to initialize MikMod\n");
- return NULL;
- }
-
- if (!(moduleHandle = Player_Load(file, 128, 0))) {
- DEBUG("modTagDup: Failed to open file: %s\n", file);
- MikMod_Exit();
- return NULL;
-
- }
- Player_Free(moduleHandle);
-
- ret = newMpdTag();
-
- ret->time = 0;
- title = xstrdup(Player_LoadTitle(file));
- if (title)
- addItemToMpdTag(ret, TAG_ITEM_TITLE, title);
-
- MikMod_Exit();
-
- return ret;
-}
-
-static char *modSuffixes[] = { "amf",
- "dsm",
- "far",
- "gdm",
- "imf",
- "it",
- "med",
- "mod",
- "mtm",
- "s3m",
- "stm",
- "stx",
- "ult",
- "uni",
- "xm",
- NULL
-};
-
-InputPlugin modPlugin = {
- "mod",
- NULL,
- mod_finishMikMod,
- NULL,
- NULL,
- mod_decode,
- modTagDup,
- INPUT_PLUGIN_STREAM_FILE,
- modSuffixes,
- NULL
-};
-
-#else
-
-InputPlugin modPlugin;
-
-#endif /* HAVE_MIKMOD */
diff --git a/trunk/src/inputPlugins/mp3_plugin.c b/trunk/src/inputPlugins/mp3_plugin.c
deleted file mode 100644
index a920b98a1..000000000
--- a/trunk/src/inputPlugins/mp3_plugin.c
+++ /dev/null
@@ -1,1092 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * 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 "../inputPlugin.h"
-
-#ifdef HAVE_MAD
-
-#include "../pcm_utils.h"
-#include <mad.h>
-
-#ifdef HAVE_ID3TAG
-#include <id3tag.h>
-#endif
-
-#include "../log.h"
-#include "../utils.h"
-#include "../replayGain.h"
-#include "../tag.h"
-#include "../conf.h"
-
-#include <stdio.h>
-#include <stdlib.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
-
-/* the number of samples of silence the decoder inserts at start */
-#define DECODERDELAY 529
-
-#define DEFAULT_GAPLESS_MP3_PLAYBACK 1
-
-static int gaplessPlayback;
-
-/* this is stolen from mpg321! */
-struct audio_dither {
- mad_fixed_t error[3];
- mad_fixed_t random;
-};
-
-static unsigned long prng(unsigned long state)
-{
- return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
-}
-
-static 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 */
-
-static int mp3_plugin_init(void)
-{
- gaplessPlayback = getBoolConfigParam(CONF_GAPLESS_MP3_PLAYBACK);
- if (gaplessPlayback == -1) gaplessPlayback = DEFAULT_GAPLESS_MP3_PLAYBACK;
- else if (gaplessPlayback < 0) exit(EXIT_FAILURE);
- return 1;
-}
-
-/* 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 dropFramesAtStart;
- int dropFramesAtEnd;
- int dropSamplesAtStart;
- int dropSamplesAtEnd;
- int foundXing;
- int foundFirstFrame;
- int decodedFirstFrame;
- int flush;
- unsigned long bitRate;
- InputStream *inStream;
- struct audio_dither dither;
- enum mad_layer layer;
-} mp3DecodeData;
-
-static 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->dropFramesAtStart = 0;
- data->dropFramesAtEnd = 0;
- data->dropSamplesAtStart = 0;
- data->dropSamplesAtEnd = 0;
- data->foundXing = 0;
- data->foundFirstFrame = 0;
- data->decodedFirstFrame = 0;
- data->flush = 1;
- data->inStream = inStream;
- data->layer = 0;
- memset(&(data->dither), 0, sizeof(struct audio_dither));
-
- mad_stream_init(&data->stream);
- mad_stream_options(&data->stream, MAD_OPTION_IGNORECRC);
- mad_frame_init(&data->frame);
- mad_synth_init(&data->synth);
- mad_timer_reset(&data->timer);
-}
-
-static 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;
-}
-
-static 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;
- }
-
- /* we've exhausted the read buffer, so give up!, these potential
- * mp3 frames are way too big, and thus unlikely to be mp3 frames */
- if (readSize == 0)
- return -1;
-
- 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) {
- readed = 0;
- my_usleep(10000);
- }
-
- mad_stream_buffer(&data->stream, data->readBuffer, readed + remaining);
- (data->stream).error = 0;
-
- return 0;
-}
-
-#ifdef HAVE_ID3TAG
-static ReplayGainInfo *parseId3ReplayGainInfo(struct id3_tag *tag)
-{
- int i;
- char *key;
- char *value;
- struct id3_frame *frame;
- int found = 0;
- ReplayGainInfo *replayGainInfo;
-
- replayGainInfo = newReplayGainInfo();
-
- for (i = 0; (frame = id3_tag_findframe(tag, "TXXX", i)); i++) {
- if (frame->nfields < 3)
- continue;
-
- key = (char *)
- id3_ucs4_latin1duplicate(id3_field_getstring
- (&frame->fields[1]));
- value = (char *)
- id3_ucs4_latin1duplicate(id3_field_getstring
- (&frame->fields[2]));
-
- if (strcasecmp(key, "replaygain_track_gain") == 0) {
- replayGainInfo->trackGain = atof(value);
- found = 1;
- } else if (strcasecmp(key, "replaygain_album_gain") == 0) {
- replayGainInfo->albumGain = atof(value);
- found = 1;
- } else if (strcasecmp(key, "replaygain_track_peak") == 0) {
- replayGainInfo->trackPeak = atof(value);
- found = 1;
- } else if (strcasecmp(key, "replaygain_album_peak") == 0) {
- replayGainInfo->albumPeak = atof(value);
- found = 1;
- }
-
- free(key);
- free(value);
- }
-
- if (found)
- return replayGainInfo;
- freeReplayGainInfo(replayGainInfo);
- return NULL;
-}
-#endif
-
-#ifdef HAVE_ID3TAG
-static void mp3_parseId3Tag(mp3DecodeData * data, signed long tagsize,
- MpdTag ** mpdTag, ReplayGainInfo ** replayGainInfo)
-{
- struct id3_tag *id3Tag = NULL;
- id3_length_t count;
- id3_byte_t const *id3_data;
- id3_byte_t *allocated = NULL;
- MpdTag *tmpMpdTag;
- ReplayGainInfo *tmpReplayGainInfo;
-
- count = data->stream.bufend - data->stream.this_frame;
-
- if (tagsize <= count) {
- id3_data = data->stream.this_frame;
- mad_stream_skip(&(data->stream), tagsize);
- } else {
- allocated = xmalloc(tagsize);
- if (!allocated)
- goto fail;
-
- memcpy(allocated, data->stream.this_frame, count);
- mad_stream_skip(&(data->stream), count);
-
- while (count < tagsize) {
- int len;
-
- len = readFromInputStream(data->inStream,
- allocated + count, (size_t) 1,
- tagsize - count);
- if (len <= 0 && inputStreamAtEOF(data->inStream)) {
- break;
- } else if (len <= 0)
- my_usleep(10000);
- else
- count += len;
- }
-
- if (count != tagsize) {
- DEBUG("mp3_decode: error parsing ID3 tag\n");
- goto fail;
- }
-
- id3_data = allocated;
- }
-
- id3Tag = id3_tag_parse(id3_data, tagsize);
- if (!id3Tag)
- goto fail;
-
- if (mpdTag) {
- tmpMpdTag = parseId3Tag(id3Tag);
- if (tmpMpdTag) {
- if (*mpdTag)
- freeMpdTag(*mpdTag);
- *mpdTag = tmpMpdTag;
- }
- }
-
- if (replayGainInfo) {
- tmpReplayGainInfo = parseId3ReplayGainInfo(id3Tag);
- if (tmpReplayGainInfo) {
- if (*replayGainInfo)
- freeReplayGainInfo(*replayGainInfo);
- *replayGainInfo = tmpReplayGainInfo;
- }
- }
-
- id3_tag_delete(id3Tag);
-fail:
- if (allocated)
- free(allocated);
-}
-#endif
-
-static int decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag,
- ReplayGainInfo ** replayGainInfo)
-{
- enum mad_layer layer;
-
- 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) {
- if (tag && !(*tag)) {
- mp3_parseId3Tag(data, tagsize, tag,
- replayGainInfo);
- } else {
- 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;
- }
- }
- }
-
- layer = data->frame.header.layer;
- if (!data->layer) {
- if (layer != MAD_LAYER_II && layer != MAD_LAYER_III) {
- /* Only layer 2 and 3 have been tested to work */
- return DECODE_SKIP;
- }
- data->layer = layer;
- } else if (layer != data->layer) {
- /* Don't decode frames with a different layer than the first */
- return DECODE_SKIP;
- }
-
- return DECODE_OK;
-}
-
-static 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, and heavily modified by jat */
-#define XI_MAGIC (('X' << 8) | 'i')
-#define NG_MAGIC (('n' << 8) | 'g')
-#define IN_MAGIC (('I' << 8) | 'n')
-#define FO_MAGIC (('f' << 8) | 'o')
-
-enum xing_magic {
- XING_MAGIC_XING, /* VBR */
- XING_MAGIC_INFO /* CBR */
-};
-
-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; /* VBR quality */
- enum xing_magic magic; /* header magic */
-};
-
-enum {
- XING_FRAMES = 0x00000001L,
- XING_BYTES = 0x00000002L,
- XING_TOC = 0x00000004L,
- XING_SCALE = 0x00000008L
-};
-
-struct lame {
- char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */
-#if 0
- /* See related comment in parse_lame() */
- float peak; /* replaygain peak */
- float trackGain; /* replaygain track gain */
- float albumGain; /* replaygain album gain */
-#endif
- int encoderDelay; /* # of added samples at start of mp3 */
- int encoderPadding; /* # of added samples at end of mp3 */
-};
-
-static int parse_xing(struct xing *xing, struct mad_bitptr *ptr, int *oldbitlen)
-{
- unsigned long bits;
- int bitlen;
- int bitsleft;
- int i;
-
- bitlen = *oldbitlen;
-
- if (bitlen < 16) goto fail;
- bits = mad_bit_read(ptr, 16);
- bitlen -= 16;
-
- if (bits == XI_MAGIC) {
- if (bitlen < 16) goto fail;
- if (mad_bit_read(ptr, 16) != NG_MAGIC) goto fail;
- bitlen -= 16;
- xing->magic = XING_MAGIC_XING;
- } else if (bits == IN_MAGIC) {
- if (bitlen < 16) goto fail;
- if (mad_bit_read(ptr, 16) != FO_MAGIC) goto fail;
- bitlen -= 16;
- xing->magic = XING_MAGIC_INFO;
- }
- else if (bits == NG_MAGIC) xing->magic = XING_MAGIC_XING;
- else if (bits == FO_MAGIC) xing->magic = XING_MAGIC_INFO;
- else goto fail;
-
- if (bitlen < 32) goto fail;
- xing->flags = mad_bit_read(ptr, 32);
- bitlen -= 32;
-
- 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) {
- 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;
- }
-
- /* Make sure we consume no less than 120 bytes (960 bits) in hopes that
- * the LAME tag is found there, and not right after the Xing header */
- bitsleft = 960 - ((*oldbitlen) - bitlen);
- if (bitsleft < 0) goto fail;
- else if (bitsleft > 0) {
- mad_bit_read(ptr, bitsleft);
- bitlen -= bitsleft;
- }
-
- *oldbitlen = bitlen;
-
- return 1;
-fail:
- xing->flags = 0;
- return 0;
-}
-
-static int parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
-{
- int i;
-
- /* Unlike the xing header, the lame tag has a fixed length. Fail if
- * not all 36 bytes (288 bits) are there. */
- if (*bitlen < 288) return 0;
-
- for (i = 0; i < 9; i++) lame->encoder[i] = (char)mad_bit_read(ptr, 8);
- lame->encoder[9] = '\0';
-
- /* This is technically incorrect, since the encoder might not be lame.
- * But there's no other way to determine if this is a lame tag, and we
- * wouldn't want to go reading a tag that's not there. */
- if (strncmp(lame->encoder, "LAME", 4) != 0) return 0;
-
-#if 0
- /* Apparently lame versions <3.97b1 do not calculate replaygain. I'm
- * using lame 3.97b2, and while it does calculate replaygain, it's
- * setting the values to 0. Using --replaygain-(fast|accurate) doesn't
- * make any difference. Leaving this code unused until we have a way
- * of testing it. -- jat */
-
- mad_bit_read(ptr, 16);
-
- mad_bit_read(ptr, 32); /* peak */
-
- mad_bit_read(ptr, 6); /* header */
- bits = mad_bit_read(ptr, 1); /* sign bit */
- lame->trackGain = mad_bit_read(ptr, 9); /* gain*10 */
- lame->trackGain = (bits ? -lame->trackGain : lame->trackGain) / 10;
-
- mad_bit_read(ptr, 6); /* header */
- bits = mad_bit_read(ptr, 1); /* sign bit */
- lame->albumGain = mad_bit_read(ptr, 9); /* gain*10 */
- lame->albumGain = (bits ? -lame->albumGain : lame->albumGain) / 10;
-
- mad_bit_read(ptr, 16);
-#else
- mad_bit_read(ptr, 96);
-#endif
-
- lame->encoderDelay = mad_bit_read(ptr, 12);
- lame->encoderPadding = mad_bit_read(ptr, 12);
-
- mad_bit_read(ptr, 96);
-
- *bitlen -= 288;
-
- return 1;
-}
-
-static int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc,
- MpdTag ** tag, ReplayGainInfo ** replayGainInfo)
-{
- struct xing xing;
- struct lame lame;
- struct mad_bitptr ptr;
- int bitlen;
- int ret;
-
- /* stfu gcc */
- memset(&xing, 0, sizeof(struct xing));
- xing.flags = 0;
-
- while (1) {
- while ((ret = decodeNextFrameHeader(data, tag, replayGainInfo)) == DECODE_CONT &&
- (!dc || !dc->stop));
- if (ret == DECODE_BREAK || (dc && dc->stop)) return -1;
- if (ret == DECODE_SKIP) continue;
-
- while ((ret = decodeNextFrame(data)) == DECODE_CONT &&
- (!dc || !dc->stop));
- if (ret == DECODE_BREAK || (dc && dc->stop)) return -1;
- if (ret == DECODE_OK) break;
- }
-
- ptr = data->stream.anc_ptr;
- bitlen = data->stream.anc_bitlen;
-
- /*
- * Attempt to calulcate the length of the song from filesize
- */
- {
- 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;
- }
- }
- /*
- * if an xing tag exists, use that!
- */
- if (parse_xing(&xing, &ptr, &bitlen)) {
- data->foundXing = 1;
- data->muteFrame = MUTEFRAME_SKIP;
-
- if (gaplessPlayback && data->inStream->seekable &&
- parse_lame(&lame, &ptr, &bitlen)) {
- data->dropSamplesAtStart = lame.encoderDelay + DECODERDELAY;
- data->dropSamplesAtEnd = lame.encoderPadding;
- }
-
- if ((xing.flags & XING_FRAMES) && xing.frames) {
- mad_timer_t duration = data->frame.header.duration;
- mad_timer_multiply(&duration, xing.frames);
- data->totalTime = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000;
- data->maxFrames = xing.frames;
- }
- }
-
- if (!data->maxFrames) return -1;
-
- data->frameOffset = xmalloc(sizeof(long) * data->maxFrames);
- data->times = xmalloc(sizeof(mad_timer_t) * data->maxFrames);
-
- return 0;
-}
-
-static void mp3DecodeDataFinalize(mp3DecodeData * data)
-{
- mad_synth_finish(&data->synth);
- mad_frame_finish(&data->frame);
- mad_stream_finish(&data->stream);
-
- if (data->frameOffset) free(data->frameOffset);
- if (data->times) free(data->times);
-}
-
-/* this is primarily used for getting total time for tags */
-static int getMp3TotalTime(char *file)
-{
- InputStream inStream;
- mp3DecodeData data;
- int ret;
-
- if (openInputStream(&inStream, file) < 0)
- return -1;
- initMp3DecodeData(&data, &inStream);
- if (decodeFirstFrame(&data, NULL, NULL, NULL) < 0)
- ret = -1;
- else
- ret = data.totalTime + 0.5;
- mp3DecodeDataFinalize(&data);
- closeInputStream(&inStream);
-
- return ret;
-}
-
-static int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
- DecoderControl * dc, MpdTag ** tag,
- ReplayGainInfo ** replayGainInfo)
-{
- initMp3DecodeData(data, inStream);
- *tag = NULL;
- if (decodeFirstFrame(data, dc, tag, replayGainInfo) < 0) {
- mp3DecodeDataFinalize(data);
- if (tag && *tag)
- freeMpdTag(*tag);
- return -1;
- }
-
- return 0;
-}
-
-static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
- ReplayGainInfo ** replayGainInfo)
-{
- int samplesPerFrame;
- int samplesLeft;
- int i;
- int ret;
- 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);
-
- if (!data->foundFirstFrame) {
- samplesPerFrame = (data->synth).pcm.length;
- data->dropFramesAtStart = data->dropSamplesAtStart / samplesPerFrame;
- data->dropFramesAtEnd = data->dropSamplesAtEnd / samplesPerFrame;
- data->dropSamplesAtStart = data->dropSamplesAtStart % samplesPerFrame;
- data->dropSamplesAtEnd = data->dropSamplesAtEnd % samplesPerFrame;
- data->foundFirstFrame = 1;
- }
-
- if (data->dropFramesAtStart > 0) {
- data->dropFramesAtStart--;
- break;
- } else if ((data->dropFramesAtEnd > 0) &&
- (data->currentFrame == (data->maxFrames + 1 - data->dropFramesAtEnd))) {
- /* stop decoding, effectively dropping all remaining
- * frames */
- return DECODE_BREAK;
- }
-
- if (data->inStream->metaTitle) {
- MpdTag *tag = newMpdTag();
- if (data->inStream->metaName) {
- addItemToMpdTag(tag,
- TAG_ITEM_NAME,
- data->inStream->metaName);
- }
- addItemToMpdTag(tag, TAG_ITEM_TITLE,
- data->inStream->metaTitle);
- free(data->inStream->metaTitle);
- data->inStream->metaTitle = NULL;
- copyMpdTagToOutputBuffer(cb, tag);
- freeMpdTag(tag);
- }
-
- samplesLeft = (data->synth).pcm.length;
-
- for (i = 0; i < (data->synth).pcm.length; i++) {
- mpd_sint16 *sample;
-
- samplesLeft--;
-
- if (!data->decodedFirstFrame &&
- (i < data->dropSamplesAtStart)) {
- continue;
- } else if (data->dropSamplesAtEnd &&
- (data->currentFrame == (data->maxFrames - data->dropFramesAtEnd)) &&
- (samplesLeft < data->dropSamplesAtEnd)) {
- /* stop decoding, effectively dropping
- * all remaining samples */
- return DECODE_BREAK;
- }
-
- sample = (mpd_sint16 *) data->outputPtr;
- *sample = (mpd_sint16) audio_linear_dither(16,
- (data->synth).pcm.samples[0][i],
- &(data->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],
- &(data->dither));
- data->outputPtr += 2;
- }
-
- if (data->outputPtr >= data->outputBufferEnd) {
- ret = sendDataToOutputBuffer(cb,
- data->inStream,
- dc,
- data->inStream->seekable,
- data->outputBuffer,
- data->outputPtr - data->outputBuffer,
- data->elapsedTime,
- data->bitRate / 1000,
- (replayGainInfo != NULL) ? *replayGainInfo : NULL);
- if (ret == OUTPUT_BUFFER_DC_STOP) {
- data->flush = 0;
- return DECODE_BREAK;
- }
-
- data->outputPtr = data->outputBuffer;
-
- if (ret == OUTPUT_BUFFER_DC_SEEK)
- break;
- }
- }
-
- data->decodedFirstFrame = 1;
-
- if (dc->seek && data->inStream->seekable) {
- long j = 0;
- data->muteFrame = MUTEFRAME_SEEK;
- while (j < data->highestFrame && dc->seekWhere >
- ((float)mad_timer_count(data->times[j],
- MAD_UNITS_MILLISECONDS))
- / 1000) {
- j++;
- }
- if (j < data->highestFrame) {
- if (seekMp3InputBuffer(data,
- data->frameOffset[j]) ==
- 0) {
- data->outputPtr = data->outputBuffer;
- clearOutputBuffer(cb);
- data->currentFrame = j;
- } 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, NULL,
- replayGainInfo)) == DECODE_CONT
- && !dc->stop) ;
- 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;
-}
-
-static void initAudioFormatFromMp3DecodeData(mp3DecodeData * data,
- AudioFormat * af)
-{
- af->bits = 16;
- af->sampleRate = (data->frame).header.samplerate;
- af->channels = MAD_NCHANNELS(&(data->frame).header);
-}
-
-static int mp3_decode(OutputBuffer * cb, DecoderControl * dc,
- InputStream * inStream)
-{
- mp3DecodeData data;
- MpdTag *tag = NULL;
- ReplayGainInfo *replayGainInfo = NULL;
-
- if (openMp3FromInputStream(inStream, &data, dc, &tag, &replayGainInfo) <
- 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;
-
- if (inStream->metaTitle) {
- if (tag)
- freeMpdTag(tag);
- tag = newMpdTag();
- addItemToMpdTag(tag, TAG_ITEM_TITLE, inStream->metaTitle);
- free(inStream->metaTitle);
- inStream->metaTitle = NULL;
- if (inStream->metaName) {
- addItemToMpdTag(tag, TAG_ITEM_NAME, inStream->metaName);
- }
- copyMpdTagToOutputBuffer(cb, tag);
- freeMpdTag(tag);
- } else if (tag) {
- if (inStream->metaName) {
- clearItemsFromMpdTag(tag, TAG_ITEM_NAME);
- addItemToMpdTag(tag, TAG_ITEM_NAME, inStream->metaName);
- }
- copyMpdTagToOutputBuffer(cb, tag);
- freeMpdTag(tag);
- } else if (inStream->metaName) {
- tag = newMpdTag();
- if (inStream->metaName) {
- addItemToMpdTag(tag, TAG_ITEM_NAME, inStream->metaName);
- }
- copyMpdTagToOutputBuffer(cb, tag);
- freeMpdTag(tag);
- }
-
- dc->state = DECODE_STATE_DECODE;
-
- while (mp3Read(&data, cb, dc, &replayGainInfo) != DECODE_BREAK) ;
- /* send last little bit if not dc->stop */
- if (!dc->stop && data.outputPtr != data.outputBuffer && data.flush) {
- sendDataToOutputBuffer(cb, NULL, dc,
- data.inStream->seekable,
- data.outputBuffer,
- data.outputPtr - data.outputBuffer,
- data.elapsedTime, data.bitRate / 1000,
- replayGainInfo);
- }
-
- if (replayGainInfo)
- freeReplayGainInfo(replayGainInfo);
-
- closeInputStream(inStream);
-
- if (dc->seek && data.muteFrame == MUTEFRAME_SEEK) {
- clearOutputBuffer(cb);
- dc->seek = 0;
- }
-
- flushOutputBuffer(cb);
- mp3DecodeDataFinalize(&data);
-
- if (dc->stop) {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- } else
- dc->state = DECODE_STATE_STOP;
-
- return 0;
-}
-
-static MpdTag *mp3_tagDup(char *file)
-{
- MpdTag *ret = NULL;
- int time;
-
- ret = id3Dup(file);
-
- time = getMp3TotalTime(file);
-
- if (time >= 0) {
- if (!ret)
- ret = newMpdTag();
- ret->time = time;
- } else {
- DEBUG("mp3_tagDup: Failed to get total song time from: %s\n",
- file);
- }
-
- return ret;
-}
-
-static char *mp3_suffixes[] = { "mp3", "mp2", NULL };
-static char *mp3_mimeTypes[] = { "audio/mpeg", NULL };
-
-InputPlugin mp3Plugin = {
- "mp3",
- mp3_plugin_init,
- NULL,
- NULL,
- mp3_decode,
- NULL,
- mp3_tagDup,
- INPUT_PLUGIN_STREAM_FILE | INPUT_PLUGIN_STREAM_URL,
- mp3_suffixes,
- mp3_mimeTypes
-};
-#else
-
-InputPlugin mp3Plugin;
-
-#endif /* HAVE_MAD */
diff --git a/trunk/src/inputPlugins/mp4_plugin.c b/trunk/src/inputPlugins/mp4_plugin.c
deleted file mode 100644
index 1ebf556c6..000000000
--- a/trunk/src/inputPlugins/mp4_plugin.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * 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 "../inputPlugin.h"
-
-#ifdef HAVE_FAAD
-
-#include "../utils.h"
-#include "../audio.h"
-#include "../log.h"
-#include "../pcm_utils.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-#include "../decode.h"
-
-#include "../mp4ff/mp4ff.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <faad.h>
-
-/* all code here is either based on or copied from FAAD2's frontend code */
-
-static int mp4_getAACTrack(mp4ff_t * infile)
-{
- /* find AAC track */
- int i, rc;
- int numTracks = mp4ff_total_tracks(infile);
-
- for (i = 0; i < numTracks; i++) {
- unsigned char *buff = NULL;
- unsigned int buff_size = 0;
-#ifdef HAVE_MP4AUDIOSPECIFICCONFIG
- mp4AudioSpecificConfig mp4ASC;
-#else
- unsigned long dummy1_32;
- unsigned char dummy2_8, dummy3_8, dummy4_8, dummy5_8, dummy6_8,
- dummy7_8, dummy8_8;
-#endif
-
- mp4ff_get_decoder_config(infile, i, &buff, &buff_size);
-
- if (buff) {
-#ifdef HAVE_MP4AUDIOSPECIFICCONFIG
- rc = AudioSpecificConfig(buff, buff_size, &mp4ASC);
-#else
- rc = AudioSpecificConfig(buff, &dummy1_32, &dummy2_8,
- &dummy3_8, &dummy4_8,
- &dummy5_8, &dummy6_8,
- &dummy7_8, &dummy8_8);
-#endif
- free(buff);
- if (rc < 0)
- continue;
- return i;
- }
- }
-
- /* can't decode this */
- return -1;
-}
-
-static uint32_t mp4_inputStreamReadCallback(void *inStream, void *buffer,
- uint32_t length)
-{
- return readFromInputStream((InputStream *) inStream, buffer, 1, length);
-}
-
-static uint32_t mp4_inputStreamSeekCallback(void *inStream, uint64_t position)
-{
- return seekInputStream((InputStream *) inStream, position, SEEK_SET);
-}
-
-static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
-{
- mp4ff_t *mp4fh;
- mp4ff_callback_t *mp4cb;
- int32_t track;
- float time;
- int32_t scale;
- faacDecHandle decoder;
- faacDecFrameInfo frameInfo;
- faacDecConfigurationPtr config;
- unsigned char *mp4Buffer;
- unsigned int mp4BufferSize;
- unsigned long sampleRate;
- unsigned char channels;
- long sampleId;
- long numSamples;
- int eof = 0;
- long dur;
- unsigned int sampleCount;
- char *sampleBuffer;
- size_t sampleBufferLen;
- unsigned int initial = 1;
- float *seekTable;
- long seekTableEnd = -1;
- int seekPositionFound = 0;
- long offset;
- mpd_uint16 bitRate = 0;
- InputStream inStream;
- int seeking = 0;
-
- if (openInputStream(&inStream, path) < 0) {
- ERROR("failed to open %s\n", path);
- return -1;
- }
-
- mp4cb = xmalloc(sizeof(mp4ff_callback_t));
- mp4cb->read = mp4_inputStreamReadCallback;
- mp4cb->seek = mp4_inputStreamSeekCallback;
- mp4cb->user_data = &inStream;
-
- mp4fh = mp4ff_open_read(mp4cb);
- if (!mp4fh) {
- ERROR("Input does not appear to be a mp4 stream.\n");
- free(mp4cb);
- closeInputStream(&inStream);
- return -1;
- }
-
- track = mp4_getAACTrack(mp4fh);
- if (track < 0) {
- ERROR("No AAC track found in mp4 stream.\n");
- mp4ff_close(mp4fh);
- closeInputStream(&inStream);
- free(mp4cb);
- return -1;
- }
-
- decoder = faacDecOpen();
-
- config = faacDecGetCurrentConfiguration(decoder);
- config->outputFormat = FAAD_FMT_16BIT;
-#ifdef HAVE_FAACDECCONFIGURATION_DOWNMATRIX
- config->downMatrix = 1;
-#endif
-#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
- config->dontUpSampleImplicitSBR = 0;
-#endif
- faacDecSetConfiguration(decoder, config);
-
- dc->audioFormat.bits = 16;
-
- mp4Buffer = NULL;
- mp4BufferSize = 0;
- mp4ff_get_decoder_config(mp4fh, track, &mp4Buffer, &mp4BufferSize);
-
- if (faacDecInit2
- (decoder, mp4Buffer, mp4BufferSize, &sampleRate, &channels) < 0) {
- ERROR("Error not a AAC stream.\n");
- faacDecClose(decoder);
- mp4ff_close(mp4fh);
- free(mp4cb);
- closeInputStream(&inStream);
- return -1;
- }
-
- dc->audioFormat.sampleRate = sampleRate;
- dc->audioFormat.channels = channels;
- time = mp4ff_get_track_duration_use_offsets(mp4fh, track);
- scale = mp4ff_time_scale(mp4fh, track);
-
- if (mp4Buffer)
- free(mp4Buffer);
-
- if (scale < 0) {
- ERROR("Error getting audio format of mp4 AAC track.\n");
- faacDecClose(decoder);
- mp4ff_close(mp4fh);
- closeInputStream(&inStream);
- free(mp4cb);
- return -1;
- }
- dc->totalTime = ((float)time) / scale;
-
- numSamples = mp4ff_num_samples(mp4fh, track);
-
- time = 0.0;
-
- seekTable = xmalloc(sizeof(float) * numSamples);
-
- for (sampleId = 0; sampleId < numSamples && !eof; sampleId++) {
- if (dc->seek)
- seeking = 1;
-
- if (seeking && seekTableEnd > 1 &&
- seekTable[seekTableEnd] >= dc->seekWhere) {
- int i = 2;
- while (seekTable[i] < dc->seekWhere)
- i++;
- sampleId = i - 1;
- time = seekTable[sampleId];
- }
-
- dur = mp4ff_get_sample_duration(mp4fh, track, sampleId);
- offset = mp4ff_get_sample_offset(mp4fh, track, sampleId);
-
- if (sampleId > seekTableEnd) {
- seekTable[sampleId] = time;
- seekTableEnd = sampleId;
- }
-
- if (sampleId == 0)
- dur = 0;
- if (offset > dur)
- dur = 0;
- else
- dur -= offset;
- time += ((float)dur) / scale;
-
- if (seeking && time > dc->seekWhere)
- seekPositionFound = 1;
-
- if (seeking && seekPositionFound) {
- seekPositionFound = 0;
- clearOutputBuffer(cb);
- seeking = 0;
- dc->seek = 0;
- }
-
- if (seeking)
- continue;
-
- if (mp4ff_read_sample(mp4fh, track, sampleId, &mp4Buffer,
- &mp4BufferSize) == 0) {
- eof = 1;
- continue;
- }
-#ifdef HAVE_FAAD_BUFLEN_FUNCS
- sampleBuffer = faacDecDecode(decoder, &frameInfo, mp4Buffer,
- mp4BufferSize);
-#else
- sampleBuffer = faacDecDecode(decoder, &frameInfo, mp4Buffer);
-#endif
-
- if (mp4Buffer)
- free(mp4Buffer);
- if (frameInfo.error > 0) {
- ERROR("error decoding MP4 file: %s\n", path);
- ERROR("faad2 error: %s\n",
- faacDecGetErrorMessage(frameInfo.error));
- eof = 1;
- break;
- }
-
- if (dc->state != DECODE_STATE_DECODE) {
- channels = frameInfo.channels;
-#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
- scale = frameInfo.samplerate;
-#endif
- dc->audioFormat.sampleRate = scale;
- dc->audioFormat.channels = frameInfo.channels;
- getOutputAudioFormat(&(dc->audioFormat),
- &(cb->audioFormat));
- dc->state = DECODE_STATE_DECODE;
- }
-
- if (channels * (dur + offset) > frameInfo.samples) {
- dur = frameInfo.samples / channels;
- offset = 0;
- }
-
- sampleCount = (unsigned long)(dur * channels);
-
- if (sampleCount > 0) {
- initial = 0;
- bitRate = frameInfo.bytesconsumed * 8.0 *
- frameInfo.channels * scale /
- frameInfo.samples / 1000 + 0.5;
- }
-
- sampleBufferLen = sampleCount * 2;
-
- sampleBuffer += offset * channels * 2;
-
- sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer,
- sampleBufferLen, time, bitRate, NULL);
- if (dc->stop) {
- eof = 1;
- break;
- }
- }
-
- free(seekTable);
- faacDecClose(decoder);
- mp4ff_close(mp4fh);
- closeInputStream(&inStream);
- free(mp4cb);
-
- if (dc->state != DECODE_STATE_DECODE)
- return -1;
-
- if (dc->seek && seeking) {
- clearOutputBuffer(cb);
- dc->seek = 0;
- }
- flushOutputBuffer(cb);
-
- if (dc->stop) {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- } else
- dc->state = DECODE_STATE_STOP;
-
- return 0;
-}
-
-static MpdTag *mp4DataDup(char *file, int *mp4MetadataFound)
-{
- MpdTag *ret = NULL;
- InputStream inStream;
- mp4ff_t *mp4fh;
- mp4ff_callback_t *cb;
- int32_t track;
- int32_t time;
- int32_t scale;
- int i;
-
- *mp4MetadataFound = 0;
-
- if (openInputStream(&inStream, file) < 0) {
- DEBUG("mp4DataDup: Failed to open file: %s\n", file);
- return NULL;
- }
-
- cb = xmalloc(sizeof(mp4ff_callback_t));
- cb->read = mp4_inputStreamReadCallback;
- cb->seek = mp4_inputStreamSeekCallback;
- cb->user_data = &inStream;
-
- mp4fh = mp4ff_open_read(cb);
- if (!mp4fh) {
- free(cb);
- closeInputStream(&inStream);
- return NULL;
- }
-
- track = mp4_getAACTrack(mp4fh);
- if (track < 0) {
- mp4ff_close(mp4fh);
- closeInputStream(&inStream);
- free(cb);
- return NULL;
- }
-
- ret = newMpdTag();
- time = mp4ff_get_track_duration_use_offsets(mp4fh, track);
- scale = mp4ff_time_scale(mp4fh, track);
- if (scale < 0) {
- mp4ff_close(mp4fh);
- closeInputStream(&inStream);
- free(cb);
- freeMpdTag(ret);
- return NULL;
- }
- ret->time = ((float)time) / scale + 0.5;
-
- for (i = 0; i < mp4ff_meta_get_num_items(mp4fh); i++) {
- char *item;
- char *value;
-
- mp4ff_meta_get_by_index(mp4fh, i, &item, &value);
-
- if (0 == strcasecmp("artist", item)) {
- addItemToMpdTag(ret, TAG_ITEM_ARTIST, value);
- *mp4MetadataFound = 1;
- } else if (0 == strcasecmp("title", item)) {
- addItemToMpdTag(ret, TAG_ITEM_TITLE, value);
- *mp4MetadataFound = 1;
- } else if (0 == strcasecmp("album", item)) {
- addItemToMpdTag(ret, TAG_ITEM_ALBUM, value);
- *mp4MetadataFound = 1;
- } else if (0 == strcasecmp("track", item)) {
- addItemToMpdTag(ret, TAG_ITEM_TRACK, value);
- *mp4MetadataFound = 1;
- } else if (0 == strcasecmp("disc", item)) { /* Is that the correct id? */
- addItemToMpdTag(ret, TAG_ITEM_DISC, value);
- *mp4MetadataFound = 1;
- } else if (0 == strcasecmp("genre", item)) {
- addItemToMpdTag(ret, TAG_ITEM_GENRE, value);
- *mp4MetadataFound = 1;
- } else if (0 == strcasecmp("date", item)) {
- addItemToMpdTag(ret, TAG_ITEM_DATE, value);
- *mp4MetadataFound = 1;
- }
-
- free(item);
- free(value);
- }
-
- mp4ff_close(mp4fh);
- closeInputStream(&inStream);
- free(cb);
-
- return ret;
-}
-
-static MpdTag *mp4TagDup(char *file)
-{
- MpdTag *ret = NULL;
- int mp4MetadataFound = 0;
-
- ret = mp4DataDup(file, &mp4MetadataFound);
- if (!ret)
- return NULL;
- if (!mp4MetadataFound) {
- MpdTag *temp = id3Dup(file);
- if (temp) {
- temp->time = ret->time;
- freeMpdTag(ret);
- ret = temp;
- }
- }
-
- return ret;
-}
-
-static char *mp4Suffixes[] = { "m4a", "mp4", NULL };
-
-InputPlugin mp4Plugin = {
- "mp4",
- NULL,
- NULL,
- NULL,
- NULL,
- mp4_decode,
- mp4TagDup,
- INPUT_PLUGIN_STREAM_FILE,
- mp4Suffixes,
- NULL
-};
-
-#else
-
-InputPlugin mp4Plugin;
-
-#endif /* HAVE_FAAD */
diff --git a/trunk/src/inputPlugins/mpc_plugin.c b/trunk/src/inputPlugins/mpc_plugin.c
deleted file mode 100644
index 885f6cfc9..000000000
--- a/trunk/src/inputPlugins/mpc_plugin.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * 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 "../inputPlugin.h"
-
-#ifdef HAVE_MPCDEC
-
-#include "../utils.h"
-#include "../audio.h"
-#include "../log.h"
-#include "../pcm_utils.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-#include "../replayGain.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <mpcdec/mpcdec.h>
-#include <errno.h>
-#include <math.h>
-
-typedef struct _MpcCallbackData {
- InputStream *inStream;
- DecoderControl *dc;
-} MpcCallbackData;
-
-static mpc_int32_t mpc_read_cb(void *vdata, void *ptr, mpc_int32_t size)
-{
- mpc_int32_t ret = 0;
- MpcCallbackData *data = (MpcCallbackData *) vdata;
-
- while (1) {
- ret = readFromInputStream(data->inStream, ptr, 1, size);
- if (ret == 0 && !inputStreamAtEOF(data->inStream) &&
- (data->dc && !data->dc->stop)) {
- my_usleep(10000);
- } else
- break;
- }
-
- return ret;
-}
-
-static mpc_bool_t mpc_seek_cb(void *vdata, mpc_int32_t offset)
-{
- MpcCallbackData *data = (MpcCallbackData *) vdata;
-
- return seekInputStream(data->inStream, offset, SEEK_SET) < 0 ? 0 : 1;
-}
-
-static mpc_int32_t mpc_tell_cb(void *vdata)
-{
- MpcCallbackData *data = (MpcCallbackData *) vdata;
-
- return (long)(data->inStream->offset);
-}
-
-static mpc_bool_t mpc_canseek_cb(void *vdata)
-{
- MpcCallbackData *data = (MpcCallbackData *) vdata;
-
- return data->inStream->seekable;
-}
-
-static mpc_int32_t mpc_getsize_cb(void *vdata)
-{
- MpcCallbackData *data = (MpcCallbackData *) vdata;
-
- return data->inStream->size;
-}
-
-/* this _looks_ performance-critical, don't de-inline -- eric */
-static inline mpd_sint16 convertSample(MPC_SAMPLE_FORMAT sample)
-{
- /* only doing 16-bit audio for now */
- mpd_sint32 val;
-
- const int clip_min = -1 << (16 - 1);
- const int clip_max = (1 << (16 - 1)) - 1;
-
-#ifdef MPC_FIXED_POINT
- const int shift = 16 - MPC_FIXED_POINT_SCALE_SHIFT;
-
- if (sample > 0) {
- sample <<= shift;
- } else if (shift < 0) {
- sample >>= -shift;
- }
- val = sample;
-#else
- const int float_scale = 1 << (16 - 1);
-
- val = sample * float_scale;
-#endif
-
- if (val < clip_min)
- val = clip_min;
- else if (val > clip_max)
- val = clip_max;
-
- return val;
-}
-
-static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
- InputStream * inStream)
-{
- mpc_decoder decoder;
- mpc_reader reader;
- mpc_streaminfo info;
-
- MpcCallbackData data;
-
- MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH];
-
- int eof = 0;
- long ret;
-#define MPC_CHUNK_SIZE 4096
- char chunk[MPC_CHUNK_SIZE];
- int chunkpos = 0;
- long bitRate = 0;
- mpd_sint16 *s16 = (mpd_sint16 *) chunk;
- unsigned long samplePos = 0;
- mpc_uint32_t vbrUpdateAcc;
- mpc_uint32_t vbrUpdateBits;
- float time;
- int i;
- ReplayGainInfo *replayGainInfo = NULL;
-
- data.inStream = inStream;
- data.dc = dc;
-
- reader.read = mpc_read_cb;
- reader.seek = mpc_seek_cb;
- reader.tell = mpc_tell_cb;
- reader.get_size = mpc_getsize_cb;
- reader.canseek = mpc_canseek_cb;
- reader.data = &data;
-
- mpc_streaminfo_init(&info);
-
- if ((ret = mpc_streaminfo_read(&info, &reader)) != ERROR_CODE_OK) {
- closeInputStream(inStream);
- if (!dc->stop) {
- ERROR("Not a valid musepack stream");
- return -1;
- } else {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- }
- return 0;
- }
-
- mpc_decoder_setup(&decoder, &reader);
-
- if (!mpc_decoder_initialize(&decoder, &info)) {
- closeInputStream(inStream);
- if (!dc->stop) {
- ERROR("Not a valid musepack stream");
- } else {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- }
- }
-
- dc->totalTime = mpc_streaminfo_get_length(&info);
-
- dc->audioFormat.bits = 16;
- dc->audioFormat.channels = info.channels;
- dc->audioFormat.sampleRate = info.sample_freq;
-
- getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
-
- replayGainInfo = newReplayGainInfo();
- replayGainInfo->albumGain = info.gain_album * 0.01;
- replayGainInfo->albumPeak = info.peak_album / 32767.0;
- replayGainInfo->trackGain = info.gain_title * 0.01;
- replayGainInfo->trackPeak = info.peak_title / 32767.0;
-
- dc->state = DECODE_STATE_DECODE;
-
- while (!eof) {
- if (dc->seek) {
- samplePos = dc->seekWhere * dc->audioFormat.sampleRate;
- if (mpc_decoder_seek_sample(&decoder, samplePos)) {
- clearOutputBuffer(cb);
- s16 = (mpd_sint16 *) chunk;
- chunkpos = 0;
- } else
- dc->seekError = 1;
- dc->seek = 0;
- }
-
- vbrUpdateAcc = 0;
- vbrUpdateBits = 0;
- ret = mpc_decoder_decode(&decoder, sample_buffer,
- &vbrUpdateAcc, &vbrUpdateBits);
-
- if (ret <= 0 || dc->stop) {
- eof = 1;
- break;
- }
-
- samplePos += ret;
-
- /* ret is in samples, and we have stereo */
- ret *= 2;
-
- for (i = 0; i < ret; i++) {
- /* 16 bit audio again */
- *s16 = convertSample(sample_buffer[i]);
- chunkpos += 2;
- s16++;
-
- if (chunkpos >= MPC_CHUNK_SIZE) {
- time = ((float)samplePos) /
- dc->audioFormat.sampleRate;
-
- bitRate = vbrUpdateBits *
- dc->audioFormat.sampleRate / 1152 / 1000;
-
- sendDataToOutputBuffer(cb, inStream, dc,
- inStream->seekable,
- chunk, chunkpos,
- time,
- bitRate, replayGainInfo);
-
- chunkpos = 0;
- s16 = (mpd_sint16 *) chunk;
- if (dc->stop) {
- eof = 1;
- break;
- }
- }
- }
- }
-
- if (!dc->stop && chunkpos > 0) {
- time = ((float)samplePos) / dc->audioFormat.sampleRate;
-
- bitRate =
- vbrUpdateBits * dc->audioFormat.sampleRate / 1152 / 1000;
-
- sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
- chunk, chunkpos, time, bitRate,
- replayGainInfo);
- }
-
- closeInputStream(inStream);
-
- flushOutputBuffer(cb);
-
- freeReplayGainInfo(replayGainInfo);
-
- if (dc->stop) {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- } else {
- dc->state = DECODE_STATE_STOP;
- }
-
- return 0;
-}
-
-static float mpcGetTime(char *file)
-{
- InputStream inStream;
- float time = -1;
-
- mpc_reader reader;
- mpc_streaminfo info;
- MpcCallbackData data;
-
- data.inStream = &inStream;
- data.dc = NULL;
-
- reader.read = mpc_read_cb;
- reader.seek = mpc_seek_cb;
- reader.tell = mpc_tell_cb;
- reader.get_size = mpc_getsize_cb;
- reader.canseek = mpc_canseek_cb;
- reader.data = &data;
-
- mpc_streaminfo_init(&info);
-
- if (openInputStream(&inStream, file) < 0) {
- DEBUG("mpcGetTime: Failed to open file: %s\n", file);
- return -1;
- }
-
- if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
- closeInputStream(&inStream);
- return -1;
- }
-
- time = mpc_streaminfo_get_length(&info);
-
- closeInputStream(&inStream);
-
- return time;
-}
-
-static MpdTag *mpcTagDup(char *file)
-{
- MpdTag *ret = NULL;
- float time = mpcGetTime(file);
-
- if (time < 0) {
- DEBUG("mpcTagDup: Failed to get Songlength of file: %s\n",
- file);
- return NULL;
- }
-
- ret = apeDup(file);
- if (!ret)
- ret = id3Dup(file);
- if (!ret)
- ret = newMpdTag();
- ret->time = time;
-
- return ret;
-}
-
-static char *mpcSuffixes[] = { "mpc", NULL };
-
-InputPlugin mpcPlugin = {
- "mpc",
- NULL,
- NULL,
- NULL,
- mpc_decode,
- NULL,
- mpcTagDup,
- INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
- mpcSuffixes,
- NULL
-};
-
-#else
-
-InputPlugin mpcPlugin;
-
-#endif /* HAVE_MPCDEC */
diff --git a/trunk/src/inputPlugins/oggflac_plugin.c b/trunk/src/inputPlugins/oggflac_plugin.c
deleted file mode 100644
index 58eb0a5f7..000000000
--- a/trunk/src/inputPlugins/oggflac_plugin.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * OggFLAC support (half-stolen from flac_plugin.c :))
- * (c) 2005 by Eric Wong <normalperson@yhbt.net>
- *
- * 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 "_flac_common.h"
-
-#ifdef HAVE_OGGFLAC
-
-#include "_ogg_common.h"
-
-#include "../utils.h"
-#include "../log.h"
-#include "../pcm_utils.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-#include "../replayGain.h"
-#include "../audio.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-static void oggflac_cleanup(InputStream * inStream,
- FlacData * data,
- OggFLAC__SeekableStreamDecoder * decoder)
-{
- if (data->replayGainInfo)
- freeReplayGainInfo(data->replayGainInfo);
- if (decoder)
- OggFLAC__seekable_stream_decoder_delete(decoder);
- closeInputStream(inStream);
-}
-
-static OggFLAC__SeekableStreamDecoderReadStatus of_read_cb(const
- OggFLAC__SeekableStreamDecoder
- * decoder,
- FLAC__byte buf[],
- unsigned *bytes,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
- size_t r;
-
- while (1) {
- r = readFromInputStream(data->inStream, (void *)buf, 1, *bytes);
- if (r == 0 && !inputStreamAtEOF(data->inStream) &&
- !data->dc->stop)
- my_usleep(10000);
- else
- break;
- }
- *bytes = r;
-
- if (r == 0 && !inputStreamAtEOF(data->inStream) && !data->dc->stop)
- return OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
-
- return OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
-}
-
-static OggFLAC__SeekableStreamDecoderSeekStatus of_seek_cb(const
- OggFLAC__SeekableStreamDecoder
- * decoder,
- FLAC__uint64 offset,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- if (seekInputStream(data->inStream, offset, SEEK_SET) < 0) {
- return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
- }
-
- return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
-}
-
-static OggFLAC__SeekableStreamDecoderTellStatus of_tell_cb(const
- OggFLAC__SeekableStreamDecoder
- * decoder,
- FLAC__uint64 *
- offset, void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- *offset = (long)(data->inStream->offset);
-
- return OggFLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
-}
-
-static OggFLAC__SeekableStreamDecoderLengthStatus of_length_cb(const
- OggFLAC__SeekableStreamDecoder
- * decoder,
- FLAC__uint64 *
- length,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- *length = (size_t) (data->inStream->size);
-
- return OggFLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
-}
-
-static FLAC__bool of_EOF_cb(const OggFLAC__SeekableStreamDecoder * decoder,
- void *fdata)
-{
- FlacData *data = (FlacData *) fdata;
-
- if (inputStreamAtEOF(data->inStream) == 1)
- return true;
- return false;
-}
-
-static void of_error_cb(const OggFLAC__SeekableStreamDecoder * decoder,
- FLAC__StreamDecoderErrorStatus status, void *fdata)
-{
- flac_error_common_cb("oggflac", status, (FlacData *) fdata);
-}
-
-static void oggflacPrintErroredState(OggFLAC__SeekableStreamDecoderState state)
-{
- switch (state) {
- case OggFLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
- ERROR("oggflac allocation error\n");
- break;
- case OggFLAC__SEEKABLE_STREAM_DECODER_READ_ERROR:
- ERROR("oggflac read error\n");
- break;
- case OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR:
- ERROR("oggflac seek error\n");
- break;
- case OggFLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR:
- ERROR("oggflac seekable stream error\n");
- break;
- case OggFLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED:
- ERROR("oggflac decoder already initialized\n");
- break;
- case OggFLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK:
- ERROR("invalid oggflac callback\n");
- break;
- case OggFLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED:
- ERROR("oggflac decoder uninitialized\n");
- break;
- case OggFLAC__SEEKABLE_STREAM_DECODER_OK:
- case OggFLAC__SEEKABLE_STREAM_DECODER_SEEKING:
- case OggFLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM:
- break;
- }
-}
-
-static FLAC__StreamDecoderWriteStatus oggflacWrite(const
- OggFLAC__SeekableStreamDecoder
- * decoder,
- const FLAC__Frame * frame,
- const FLAC__int32 *
- const buf[], void *vdata)
-{
- FlacData *data = (FlacData *) vdata;
- FLAC__uint32 samples = frame->header.blocksize;
- FLAC__uint16 u16;
- unsigned char *uc;
- int c_samp, c_chan, d_samp;
- int i;
- float timeChange;
-
- timeChange = ((float)samples) / frame->header.sample_rate;
- data->time += timeChange;
-
- /* ogg123 uses a complicated method of calculating bitrate
- * with averaging which I'm not too fond of.
- * (waste of memory/CPU cycles, especially given this is _lossless_)
- * a get_decode_position() is not available in OggFLAC, either
- *
- * this does not give an accurate bitrate:
- * (bytes_last_read was set in the read callback)
- data->bitRate = ((8.0 * data->bytes_last_read *
- frame->header.sample_rate)
- /((float)samples * 1000)) + 0.5;
- */
-
- for (c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) {
- for (c_chan = 0; c_chan < frame->header.channels;
- c_chan++, d_samp++) {
- u16 = buf[c_chan][c_samp];
- uc = (unsigned char *)&u16;
- for (i = 0; i < (data->dc->audioFormat.bits / 8); i++) {
- if (data->chunk_length >= FLAC_CHUNK_SIZE) {
- if (flacSendChunk(data) < 0) {
- return
- FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
- }
- data->chunk_length = 0;
- if (data->dc->seek) {
- return
- FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
- }
- }
- data->chunk[data->chunk_length++] = *(uc++);
- }
- }
- }
-
- return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-}
-
-/* used by TagDup */
-static void of_metadata_dup_cb(const OggFLAC__SeekableStreamDecoder * decoder,
- const FLAC__StreamMetadata * block, void *vdata)
-{
- FlacData *data = (FlacData *) vdata;
-
- switch (block->type) {
- case FLAC__METADATA_TYPE_STREAMINFO:
- if (!data->tag)
- data->tag = newMpdTag();
- data->tag->time = ((float)block->data.stream_info.
- total_samples) /
- block->data.stream_info.sample_rate + 0.5;
- return;
- case FLAC__METADATA_TYPE_VORBIS_COMMENT:
- copyVorbisCommentBlockToMpdTag(block, data->tag);
- default:
- break;
- }
-}
-
-/* used by decode */
-static void of_metadata_decode_cb(const OggFLAC__SeekableStreamDecoder * dec,
- const FLAC__StreamMetadata * block,
- void *vdata)
-{
- flac_metadata_common_cb(block, (FlacData *) vdata);
-}
-
-static OggFLAC__SeekableStreamDecoder
- * full_decoder_init_and_read_metadata(FlacData * data,
- unsigned int metadata_only)
-{
- OggFLAC__SeekableStreamDecoder *decoder = NULL;
- unsigned int s = 1;
-
- if (!(decoder = OggFLAC__seekable_stream_decoder_new()))
- return NULL;
-
- if (metadata_only) {
- s &= OggFLAC__seekable_stream_decoder_set_metadata_callback
- (decoder, of_metadata_dup_cb);
- s &= OggFLAC__seekable_stream_decoder_set_metadata_respond
- (decoder, FLAC__METADATA_TYPE_STREAMINFO);
- } else {
- s &= OggFLAC__seekable_stream_decoder_set_metadata_callback
- (decoder, of_metadata_decode_cb);
- }
-
- s &= OggFLAC__seekable_stream_decoder_set_read_callback(decoder,
- of_read_cb);
- s &= OggFLAC__seekable_stream_decoder_set_seek_callback(decoder,
- of_seek_cb);
- s &= OggFLAC__seekable_stream_decoder_set_tell_callback(decoder,
- of_tell_cb);
- s &= OggFLAC__seekable_stream_decoder_set_length_callback(decoder,
- of_length_cb);
- s &= OggFLAC__seekable_stream_decoder_set_eof_callback(decoder,
- of_EOF_cb);
- s &= OggFLAC__seekable_stream_decoder_set_write_callback(decoder,
- oggflacWrite);
- s &= OggFLAC__seekable_stream_decoder_set_metadata_respond(decoder,
- FLAC__METADATA_TYPE_VORBIS_COMMENT);
- s &= OggFLAC__seekable_stream_decoder_set_error_callback(decoder,
- of_error_cb);
- s &= OggFLAC__seekable_stream_decoder_set_client_data(decoder,
- (void *)data);
-
- if (!s) {
- ERROR("oggflac problem before init()\n");
- goto fail;
- }
- if (OggFLAC__seekable_stream_decoder_init(decoder) !=
- OggFLAC__SEEKABLE_STREAM_DECODER_OK) {
- ERROR("oggflac problem doing init()\n");
- goto fail;
- }
- if (!OggFLAC__seekable_stream_decoder_process_until_end_of_metadata
- (decoder)) {
- ERROR("oggflac problem reading metadata\n");
- goto fail;
- }
-
- return decoder;
-
-fail:
- oggflacPrintErroredState(OggFLAC__seekable_stream_decoder_get_state
- (decoder));
- OggFLAC__seekable_stream_decoder_delete(decoder);
- return NULL;
-}
-
-/* public functions: */
-static MpdTag *oggflac_TagDup(char *file)
-{
- InputStream inStream;
- OggFLAC__SeekableStreamDecoder *decoder;
- FlacData data;
-
- if (openInputStream(&inStream, file) < 0)
- return NULL;
- if (ogg_stream_type_detect(&inStream) != FLAC) {
- closeInputStream(&inStream);
- return NULL;
- }
-
- init_FlacData(&data, NULL, NULL, &inStream);
-
- /* errors here won't matter,
- * data.tag will be set or unset, that's all we care about */
- decoder = full_decoder_init_and_read_metadata(&data, 1);
-
- oggflac_cleanup(&inStream, &data, decoder);
-
- return data.tag;
-}
-
-static unsigned int oggflac_try_decode(InputStream * inStream)
-{
- return (ogg_stream_type_detect(inStream) == FLAC) ? 1 : 0;
-}
-
-static int oggflac_decode(OutputBuffer * cb, DecoderControl * dc,
- InputStream * inStream)
-{
- OggFLAC__SeekableStreamDecoder *decoder = NULL;
- FlacData data;
- int ret = 0;
-
- init_FlacData(&data, cb, dc, inStream);
-
- if (!(decoder = full_decoder_init_and_read_metadata(&data, 0))) {
- ret = -1;
- goto fail;
- }
-
- dc->state = DECODE_STATE_DECODE;
-
- while (1) {
- OggFLAC__seekable_stream_decoder_process_single(decoder);
- if (OggFLAC__seekable_stream_decoder_get_state(decoder) !=
- OggFLAC__SEEKABLE_STREAM_DECODER_OK) {
- break;
- }
- if (dc->seek) {
- FLAC__uint64 sampleToSeek = dc->seekWhere *
- dc->audioFormat.sampleRate + 0.5;
- if (OggFLAC__seekable_stream_decoder_seek_absolute
- (decoder, sampleToSeek)) {
- clearOutputBuffer(cb);
- data.time = ((float)sampleToSeek) /
- dc->audioFormat.sampleRate;
- data.position = 0;
- } else
- dc->seekError = 1;
- dc->seek = 0;
- }
- }
-
- if (!dc->stop) {
- oggflacPrintErroredState
- (OggFLAC__seekable_stream_decoder_get_state(decoder));
- OggFLAC__seekable_stream_decoder_finish(decoder);
- }
- /* send last little bit */
- if (data.chunk_length > 0 && !dc->stop) {
- flacSendChunk(&data);
- flushOutputBuffer(data.cb);
- }
-
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
-
-fail:
- oggflac_cleanup(inStream, &data, decoder);
-
- return ret;
-}
-
-static char *oggflac_Suffixes[] = { "ogg", NULL };
-static char *oggflac_mime_types[] = { "audio/x-flac+ogg",
- "application/ogg",
- "application/x-ogg",
- NULL };
-
-InputPlugin oggflacPlugin = {
- "oggflac",
- NULL,
- NULL,
- oggflac_try_decode,
- oggflac_decode,
- NULL,
- oggflac_TagDup,
- INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
- oggflac_Suffixes,
- oggflac_mime_types
-};
-
-#else /* !HAVE_FLAC */
-
-InputPlugin oggflacPlugin;
-
-#endif /* HAVE_OGGFLAC */
diff --git a/trunk/src/inputPlugins/oggvorbis_plugin.c b/trunk/src/inputPlugins/oggvorbis_plugin.c
deleted file mode 100644
index 4b4b87c8a..000000000
--- a/trunk/src/inputPlugins/oggvorbis_plugin.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * 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
- */
-
-/* TODO 'ogg' should probably be replaced with 'oggvorbis' in all instances */
-
-#include "../inputPlugin.h"
-
-#ifdef HAVE_OGGVORBIS
-
-#include "_ogg_common.h"
-
-#include "../utils.h"
-#include "../audio.h"
-#include "../log.h"
-#include "../pcm_utils.h"
-#include "../inputStream.h"
-#include "../outputBuffer.h"
-#include "../replayGain.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef HAVE_TREMOR
-#include <vorbis/vorbisfile.h>
-#else
-#include <tremor/ivorbisfile.h>
-/* Macros to make Tremor's API look like libogg. Tremor always
- returns host-byte-order 16-bit signed data, and uses integer
- milliseconds where libogg uses double seconds.
-*/
-#define ov_read(VF, BUFFER, LENGTH, BIGENDIANP, WORD, SGNED, BITSTREAM) \
- ov_read(VF, BUFFER, LENGTH, BITSTREAM)
-#define ov_time_total(VF, I) ((double)ov_time_total(VF, I)/1000)
-#define ov_time_tell(VF) ((double)ov_time_tell(VF)/1000)
-#define ov_time_seek_page(VF, S) (ov_time_seek_page(VF, (S)*1000))
-#endif /* HAVE_TREMOR */
-
-#include <errno.h>
-
-#ifdef WORDS_BIGENDIAN
-#define OGG_DECODE_USE_BIGENDIAN 1
-#else
-#define OGG_DECODE_USE_BIGENDIAN 0
-#endif
-
-typedef struct _OggCallbackData {
- InputStream *inStream;
- DecoderControl *dc;
-} OggCallbackData;
-
-static size_t ogg_read_cb(void *ptr, size_t size, size_t nmemb, void *vdata)
-{
- size_t ret = 0;
- OggCallbackData *data = (OggCallbackData *) vdata;
-
- while (1) {
- ret = readFromInputStream(data->inStream, ptr, size, nmemb);
- if (ret == 0 && !inputStreamAtEOF(data->inStream) &&
- !data->dc->stop) {
- my_usleep(10000);
- } else
- break;
- }
- errno = 0;
- /*if(ret<0) errno = ((InputStream *)inStream)->error; */
-
- return ret;
-}
-
-static int ogg_seek_cb(void *vdata, ogg_int64_t offset, int whence)
-{
- OggCallbackData *data = (OggCallbackData *) vdata;
-
- return seekInputStream(data->inStream, offset, whence);
-}
-
-static int ogg_close_cb(void *vdata)
-{
- OggCallbackData *data = (OggCallbackData *) vdata;
-
- return closeInputStream(data->inStream);
-}
-
-static long ogg_tell_cb(void *vdata)
-{
- OggCallbackData *data = (OggCallbackData *) vdata;
-
- return (long)(data->inStream->offset);
-}
-
-static char *ogg_parseComment(char *comment, char *needle)
-{
- int len = strlen(needle);
-
- if (strncasecmp(comment, needle, len) == 0 && *(comment + len) == '=') {
- return comment + len + 1;
- }
-
- return NULL;
-}
-
-static void ogg_getReplayGainInfo(char **comments, ReplayGainInfo ** infoPtr)
-{
- char *temp;
- int found = 0;
-
- if (*infoPtr)
- freeReplayGainInfo(*infoPtr);
- *infoPtr = newReplayGainInfo();
-
- while (*comments) {
- if ((temp =
- ogg_parseComment(*comments, "replaygain_track_gain"))) {
- (*infoPtr)->trackGain = atof(temp);
- found = 1;
- } else if ((temp = ogg_parseComment(*comments,
- "replaygain_album_gain"))) {
- (*infoPtr)->albumGain = atof(temp);
- found = 1;
- } else if ((temp = ogg_parseComment(*comments,
- "replaygain_track_peak"))) {
- (*infoPtr)->trackPeak = atof(temp);
- found = 1;
- } else if ((temp = ogg_parseComment(*comments,
- "replaygain_album_peak"))) {
- (*infoPtr)->albumPeak = atof(temp);
- found = 1;
- }
-
- comments++;
- }
-
- if (!found) {
- freeReplayGainInfo(*infoPtr);
- *infoPtr = NULL;
- }
-}
-
-static const char *VORBIS_COMMENT_TRACK_KEY = "tracknumber";
-static const char *VORBIS_COMMENT_DISC_KEY = "discnumber";
-
-static unsigned int ogg_parseCommentAddToTag(char *comment,
- unsigned int itemType,
- MpdTag ** tag)
-{
- const char *needle;
- unsigned int len;
- switch (itemType) {
- case TAG_ITEM_TRACK:
- needle = VORBIS_COMMENT_TRACK_KEY;
- break;
- case TAG_ITEM_DISC:
- needle = VORBIS_COMMENT_DISC_KEY;
- break;
- default:
- needle = mpdTagItemKeys[itemType];
- }
- len = strlen(needle);
-
- if (strncasecmp(comment, needle, len) == 0 && *(comment + len) == '=') {
- if (!*tag)
- *tag = newMpdTag();
-
- addItemToMpdTag(*tag, itemType, comment + len + 1);
-
- return 1;
- }
-
- return 0;
-}
-
-static MpdTag *oggCommentsParse(char **comments)
-{
- MpdTag *tag = NULL;
-
- while (*comments) {
- int j;
- for (j = TAG_NUM_OF_ITEM_TYPES; --j >= 0;) {
- if (ogg_parseCommentAddToTag(*comments, j, &tag))
- break;
- }
- comments++;
- }
-
- return tag;
-}
-
-static void putOggCommentsIntoOutputBuffer(OutputBuffer * cb, char *streamName,
- char **comments)
-{
- MpdTag *tag;
-
- tag = oggCommentsParse(comments);
- if (!tag && streamName) {
- tag = newMpdTag();
- }
- if (!tag)
- return;
-
- /*if(tag->artist) printf("Artist: %s\n", tag->artist);
- if(tag->album) printf("Album: %s\n", tag->album);
- if(tag->track) printf("Track: %s\n", tag->track);
- if(tag->title) printf("Title: %s\n", tag->title); */
-
- if (streamName) {
- clearItemsFromMpdTag(tag, TAG_ITEM_NAME);
- addItemToMpdTag(tag, TAG_ITEM_NAME, streamName);
- }
-
- copyMpdTagToOutputBuffer(cb, tag);
-
- freeMpdTag(tag);
-}
-
-/* public */
-static int oggvorbis_decode(OutputBuffer * cb, DecoderControl * dc,
- InputStream * inStream)
-{
- OggVorbis_File vf;
- ov_callbacks callbacks;
- OggCallbackData data;
- int current_section;
- int prev_section = -1;
- int eof = 0;
- long ret;
-#define OGG_CHUNK_SIZE 4096
- char chunk[OGG_CHUNK_SIZE];
- int chunkpos = 0;
- long bitRate = 0;
- long test;
- ReplayGainInfo *replayGainInfo = NULL;
- char **comments;
- char *errorStr;
-
- data.inStream = inStream;
- data.dc = dc;
-
- callbacks.read_func = ogg_read_cb;
- callbacks.seek_func = ogg_seek_cb;
- callbacks.close_func = ogg_close_cb;
- callbacks.tell_func = ogg_tell_cb;
-
- if ((ret = ov_open_callbacks(&data, &vf, NULL, 0, callbacks)) < 0) {
- closeInputStream(inStream);
- if (!dc->stop) {
- switch (ret) {
- case OV_EREAD:
- errorStr = "read error";
- break;
- case OV_ENOTVORBIS:
- errorStr = "not vorbis stream";
- break;
- case OV_EVERSION:
- errorStr = "vorbis version mismatch";
- break;
- case OV_EBADHEADER:
- errorStr = "invalid vorbis header";
- break;
- case OV_EFAULT:
- errorStr = "internal logic error";
- break;
- default:
- errorStr = "unknown error";
- break;
- }
- ERROR("Error decoding Ogg Vorbis stream: %s\n",
- errorStr);
- return -1;
- } else {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- }
- return 0;
- }
-
- dc->totalTime = ov_time_total(&vf, -1);
- if (dc->totalTime < 0)
- dc->totalTime = 0;
-
- dc->audioFormat.bits = 16;
-
- while (!eof) {
- if (dc->seek) {
- if (0 == ov_time_seek_page(&vf, dc->seekWhere)) {
- clearOutputBuffer(cb);
- chunkpos = 0;
- } else
- dc->seekError = 1;
- dc->seek = 0;
- }
- ret = ov_read(&vf, chunk + chunkpos,
- OGG_CHUNK_SIZE - chunkpos,
- OGG_DECODE_USE_BIGENDIAN, 2, 1, &current_section);
-
- if (current_section != prev_section) {
- /*printf("new song!\n"); */
- vorbis_info *vi = ov_info(&vf, -1);
- dc->audioFormat.channels = vi->channels;
- dc->audioFormat.sampleRate = vi->rate;
- if (dc->state == DECODE_STATE_START) {
- getOutputAudioFormat(&(dc->audioFormat),
- &(cb->audioFormat));
- dc->state = DECODE_STATE_DECODE;
- }
- comments = ov_comment(&vf, -1)->user_comments;
- putOggCommentsIntoOutputBuffer(cb, inStream->metaName,
- comments);
- ogg_getReplayGainInfo(comments, &replayGainInfo);
- }
-
- prev_section = current_section;
-
- if (ret <= 0 && ret != OV_HOLE) {
- eof = 1;
- break;
- }
- if (ret == OV_HOLE)
- ret = 0;
-
- chunkpos += ret;
-
- if (chunkpos >= OGG_CHUNK_SIZE) {
- if ((test = ov_bitrate_instant(&vf)) > 0) {
- bitRate = test / 1000;
- }
- sendDataToOutputBuffer(cb, inStream, dc,
- inStream->seekable,
- chunk, chunkpos,
- ov_pcm_tell(&vf) /
- dc->audioFormat.sampleRate,
- bitRate, replayGainInfo);
- chunkpos = 0;
- if (dc->stop)
- break;
- }
- }
-
- if (!dc->stop && chunkpos > 0) {
- sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
- chunk, chunkpos,
- ov_time_tell(&vf), bitRate,
- replayGainInfo);
- }
-
- if (replayGainInfo)
- freeReplayGainInfo(replayGainInfo);
-
- ov_clear(&vf);
-
- flushOutputBuffer(cb);
-
- if (dc->stop) {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- } else
- dc->state = DECODE_STATE_STOP;
-
- return 0;
-}
-
-static MpdTag *oggvorbis_TagDup(char *file)
-{
- MpdTag *ret = NULL;
- FILE *fp;
- OggVorbis_File vf;
-
- fp = fopen(file, "r");
- if (!fp) {
- DEBUG("oggvorbis_TagDup: Failed to open file: '%s', %s\n",
- file, strerror(errno));
- return NULL;
- }
- if (ov_open(fp, &vf, NULL, 0) < 0) {
- fclose(fp);
- return NULL;
- }
-
- ret = oggCommentsParse(ov_comment(&vf, -1)->user_comments);
-
- if (!ret)
- ret = newMpdTag();
- ret->time = (int)(ov_time_total(&vf, -1) + 0.5);
-
- ov_clear(&vf);
-
- return ret;
-}
-
-static unsigned int oggvorbis_try_decode(InputStream * inStream)
-{
- return (ogg_stream_type_detect(inStream) == VORBIS) ? 1 : 0;
-}
-
-static char *oggvorbis_Suffixes[] = { "ogg", NULL };
-static char *oggvorbis_MimeTypes[] = { "application/ogg",
- "audio/x-vorbis+ogg",
- "application/x-ogg",
- NULL };
-
-InputPlugin oggvorbisPlugin = {
- "oggvorbis",
- NULL,
- NULL,
- oggvorbis_try_decode,
- oggvorbis_decode,
- NULL,
- oggvorbis_TagDup,
- INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
- oggvorbis_Suffixes,
- oggvorbis_MimeTypes
-};
-
-#else /* !HAVE_OGGVORBIS */
-
-InputPlugin oggvorbisPlugin;
-
-#endif /* HAVE_OGGVORBIS */