add support for parsing ape tags in musepack files
git-svn-id: https://svn.musicpd.org/mpd/trunk@3030 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
32a1f952e8
commit
01b708bc13
2
TODO
2
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
|
||||
|
@ -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;
|
||||
float time = mpcGetTime(file);
|
||||
|
||||
fp = fopen(file,"r");
|
||||
if(!fp) return NULL;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
107
src/tag.c
107
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;
|
||||
|
@ -64,6 +64,8 @@ typedef struct _MpdTag {
|
||||
MpdTag * parseId3Tag(struct id3_tag *);
|
||||
#endif
|
||||
|
||||
MpdTag * apeDup(char * file);
|
||||
|
||||
MpdTag * id3Dup(char * file);
|
||||
|
||||
MpdTag * newMpdTag();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -35,4 +35,6 @@ int ipv6Supported();
|
||||
|
||||
char * appendToString(char * dest, const char * src);
|
||||
|
||||
unsigned long readLEuint32(const unsigned char * p);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user