diff options
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | src/inputPlugins/mpc_plugin.c | 47 | ||||
-rw-r--r-- | src/tag.c | 107 | ||||
-rw-r--r-- | src/tag.h | 2 | ||||
-rw-r--r-- | src/utils.c | 8 | ||||
-rw-r--r-- | src/utils.h | 2 |
6 files changed, 159 insertions, 9 deletions
@@ -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; } @@ -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; @@ -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 |