aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--src/inputPlugins/mpc_plugin.c47
-rw-r--r--src/tag.c107
-rw-r--r--src/tag.h2
-rw-r--r--src/utils.c8
-rw-r--r--src/utils.h2
6 files changed, 159 insertions, 9 deletions
diff --git a/TODO b/TODO
index 450996dee..a9132614f 100644
--- a/TODO
+++ b/TODO
@@ -12,8 +12,6 @@
*) Handle mp1 and mp2 files (including files with mp3 suffixes)
*) add support for playing aac streams (gee, thanks icecast)
*) parsing of lame tags (including getting replaygain and gapless info)
- *) implement apev2 and id3v1 tag reader from xmms-musepack plugin
- *) only use libid3tag for id3v2 tags, use internal impl for id3v1 tags
*) aduio output
*) allowing "pausing" of audio output devices
diff --git a/src/inputPlugins/mpc_plugin.c b/src/inputPlugins/mpc_plugin.c
index 45ef0bd16..9687eba6c 100644
--- a/src/inputPlugins/mpc_plugin.c
+++ b/src/inputPlugins/mpc_plugin.c
@@ -47,7 +47,7 @@ static mpc_int32_t mpc_read_cb(void * vdata, void * ptr, mpc_int32_t size) {
while(1) {
ret = readFromInputStream(data->inStream, ptr, 1, size);
if(ret == 0 && !inputStreamAtEOF(data->inStream) &&
- !data->dc->stop)
+ (data->dc && !data->dc->stop))
{
my_usleep(10000);
}
@@ -272,17 +272,50 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
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) 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;
- FILE * fp;
-
- fp = fopen(file,"r");
- if(!fp) return NULL;
+ float time = mpcGetTime(file);
- /* get tag info here */
+ if(time < 0) return NULL;
+ ret = apeDup(file);
+ if(!ret) ret = id3Dup(file);
if(!ret) ret = newMpdTag();
- ret->time = 0;
+ ret->time = time;
return ret;
}
diff --git a/src/tag.c b/src/tag.c
index 7b1b8e837..41d76087c 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -217,6 +217,113 @@ MpdTag * id3Dup(char * file) {
return ret;
}
+MpdTag * apeDup(char * file) {
+ MpdTag * ret = NULL;
+ FILE * fp = NULL;
+ int tagCount;
+ unsigned char * buffer = NULL;
+ unsigned char * p;
+ int tagLen;
+ int size;
+ unsigned long flags;
+ int i;
+ unsigned char * key;
+
+ struct {
+ unsigned char id[8];
+ unsigned char version[4];
+ unsigned char length[4];
+ unsigned char tagCount[4];
+ unsigned char flags[4];
+ unsigned char reserved[8];
+ } footer;
+
+ char * apeItems[7] =
+ {
+ "title",
+ "artist",
+ "album",
+ "comment",
+ "genre",
+ "track",
+ "year"
+ };
+
+ int tagItems[7] =
+ {
+ TAG_ITEM_TITLE,
+ TAG_ITEM_ARTIST,
+ TAG_ITEM_ALBUM,
+ TAG_ITEM_COMMENT,
+ TAG_ITEM_GENRE,
+ TAG_ITEM_TRACK,
+ TAG_ITEM_DATE,
+ };
+
+ fp = fopen(file, "r");
+ if(!fp) return NULL;
+
+ /* determine if file has an apeV2 tag */
+ if(fseek(fp, 0, SEEK_END)) goto fail;
+ size = ftell(fp);
+ if(fseek(fp, size-sizeof(footer), SEEK_SET)) goto fail;
+ if(fread(&footer, 1, sizeof(footer), fp) != sizeof(footer)) goto fail;
+ if(memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0) goto fail;
+ if(readLEuint32(footer.version) != 2000) goto fail;
+
+ /* find begining of ape tag */
+ tagLen = readLEuint32(footer.length);
+ if(tagLen < sizeof(footer)) goto fail;
+ if(fseek(fp, size-tagLen, SEEK_SET)) goto fail;
+
+ /* read tag into buffer */
+ tagLen -= sizeof(footer);
+ buffer = malloc(tagLen);
+ if(fread(buffer, 1, tagLen, fp) != tagLen) goto fail;
+
+ /* read tags */
+ tagCount = readLEuint32(footer.tagCount);
+ p = buffer;
+ while(tagCount-- && tagLen > 10) {
+ size = readLEuint32(p);
+ p += 4;
+ tagLen -= 4;
+ flags = readLEuint32(p);
+ p += 4;
+ tagLen -= 4;
+
+ /* get the key */
+ key = p;
+ while(tagLen-size > 0 && *p != '\0') {
+ p++;
+ tagLen--;
+ }
+ p++;
+ tagLen--;
+
+ /* get the value */
+ if(tagLen-size < 0) goto fail;
+
+ /* we only care about utf-8 text tags */
+ if(!(flags & (0x3 << 1))) {
+ for(i = 0; i < 7; i++) {
+ if(strcasecmp(key, apeItems[i]) == 0) {
+ if(!ret) ret = newMpdTag();
+ addItemToMpdTagWithLen(
+ ret, tagItems[i], p, size);
+ }
+ }
+ }
+ p += size;
+ tagLen -= size;
+ }
+
+fail:
+ if(fp) fclose(fp);
+ if(buffer) free(buffer);
+ return ret;
+}
+
MpdTag * newMpdTag() {
MpdTag * ret = malloc(sizeof(MpdTag));
ret->items = NULL;
diff --git a/src/tag.h b/src/tag.h
index ffe0c0d49..6720f818d 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -64,6 +64,8 @@ typedef struct _MpdTag {
MpdTag * parseId3Tag(struct id3_tag *);
#endif
+MpdTag * apeDup(char * file);
+
MpdTag * id3Dup(char * file);
MpdTag * newMpdTag();
diff --git a/src/utils.c b/src/utils.c
index a057fa33f..32b079353 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -92,3 +92,11 @@ char * appendToString(char * dest, const char * src) {
return dest;
}
+
+unsigned long readLEuint32(const unsigned char *p)
+{
+ return ((unsigned long) p[0] << 0) |
+ ((unsigned long) p[1] << 8) |
+ ((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24);
+}
+
diff --git a/src/utils.h b/src/utils.h
index 545f1653d..b4a236db7 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -35,4 +35,6 @@ int ipv6Supported();
char * appendToString(char * dest, const char * src);
+unsigned long readLEuint32(const unsigned char * p);
+
#endif