Rewrote id3Dup to search for tags manually. Now libid3tag will actually tell us the version of the tag we got. As an added benefit we also do fewer reads/mallocs when scanning mp3s during database update/creation.
git-svn-id: https://svn.musicpd.org/mpd/trunk@4277 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
30df7d49c5
commit
bdf4107117
@ -252,7 +252,9 @@ void mp3_getReplayGainInfo(struct id3_tag * tag, ReplayGainInfo ** infoPtr) {
|
|||||||
*infoPtr = NULL;
|
*infoPtr = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
static void mp3_parseId3Tag(mp3DecodeData * data, signed long tagsize, MpdTag ** mpdTag, ReplayGainInfo ** replayGainInfo) {
|
static void mp3_parseId3Tag(mp3DecodeData * data, signed long tagsize, MpdTag ** mpdTag, ReplayGainInfo ** replayGainInfo) {
|
||||||
struct id3_tag * id3Tag = NULL;
|
struct id3_tag * id3Tag = NULL;
|
||||||
id3_length_t count;
|
id3_length_t count;
|
||||||
|
148
src/tag.c
148
src/tag.c
@ -43,6 +43,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
|
#define isId3v1(tag) (id3_tag_options(tag, 0, 0) & ID3_TAG_OPTION_ID3V1)
|
||||||
|
/* Size of the buffer to use for peeking at tag headers. We reuse this buffer
|
||||||
|
if the whole tag fits in it, so make it big to avoid a malloc(). */
|
||||||
|
#define ID3_TAG_BUFLEN 1024
|
||||||
#ifndef ID3_FRAME_COMPOSER
|
#ifndef ID3_FRAME_COMPOSER
|
||||||
#define ID3_FRAME_COMPOSER "TCOM"
|
#define ID3_FRAME_COMPOSER "TCOM"
|
||||||
#endif
|
#endif
|
||||||
@ -181,29 +185,149 @@ MpdTag * parseId3Tag(struct id3_tag * tag) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
static int fillBuffer(void *buf, size_t size, FILE *stream,
|
||||||
|
long offset, int whence)
|
||||||
|
{
|
||||||
|
if (fseek(stream, offset, whence) != 0) return 0;
|
||||||
|
return fread(buf, 1, size, stream);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
static int getId3v2FooterSize(FILE * stream, long offset, int whence)
|
||||||
|
{
|
||||||
|
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
||||||
|
int bufsize;
|
||||||
|
|
||||||
|
bufsize = fillBuffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
|
||||||
|
if (bufsize <= 0) return 0;
|
||||||
|
return id3_tag_query(buf, bufsize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
static struct id3_tag * getId3Tag(FILE * stream, long offset, int whence)
|
||||||
|
{
|
||||||
|
struct id3_tag * tag;
|
||||||
|
id3_byte_t * buf[ID3_TAG_BUFLEN];
|
||||||
|
id3_byte_t * mbuf;
|
||||||
|
int tagsize;
|
||||||
|
int bufsize;
|
||||||
|
int mbufsize;
|
||||||
|
|
||||||
|
/* It's ok if we get less than we asked for */
|
||||||
|
bufsize = fillBuffer(buf, ID3_TAG_BUFLEN, stream, offset, whence);
|
||||||
|
if (bufsize <= 0) return NULL;
|
||||||
|
|
||||||
|
/* Look for a tag header */
|
||||||
|
tagsize = id3_tag_query((const id3_byte_t *)buf, bufsize);
|
||||||
|
if (tagsize <= 0) return NULL;
|
||||||
|
|
||||||
|
if (tagsize <= bufsize) {
|
||||||
|
/* Got an id3 tag, and it fits in buf */
|
||||||
|
tag = id3_tag_parse((const id3_byte_t *)buf, tagsize);
|
||||||
|
} else {
|
||||||
|
/* Got an id3tag that overflows buf, so get a new one */
|
||||||
|
mbuf = malloc(tagsize);
|
||||||
|
if (!mbuf) return NULL;
|
||||||
|
|
||||||
|
mbufsize = fillBuffer(mbuf, tagsize, stream, offset, whence);
|
||||||
|
if (mbufsize < tagsize) {
|
||||||
|
free(mbuf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = id3_tag_parse((const id3_byte_t *)mbuf, tagsize);
|
||||||
|
|
||||||
|
free(mbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
static struct id3_tag * findId3TagFromBeginning(FILE * stream)
|
||||||
|
{
|
||||||
|
struct id3_tag * tag;
|
||||||
|
struct id3_tag * seektag;
|
||||||
|
struct id3_frame * frame;
|
||||||
|
int seek;
|
||||||
|
|
||||||
|
tag = getId3Tag(stream, 0, SEEK_SET);
|
||||||
|
if (!tag) {
|
||||||
|
return NULL;
|
||||||
|
} else if (isId3v1(tag)) {
|
||||||
|
/* id3v1 tags don't belong here */
|
||||||
|
id3_tag_delete(tag);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have an id3v2 tag, so let's look for SEEK frames */
|
||||||
|
while ((frame = id3_tag_findframe(tag, "SEEK", 0))) {
|
||||||
|
/* Found a SEEK frame, get it's value */
|
||||||
|
seek = id3_field_getint(id3_frame_field(frame, 0));
|
||||||
|
if (seek < 0) break;
|
||||||
|
|
||||||
|
/* Get the tag specified by the SEEK frame */
|
||||||
|
seektag = getId3Tag(stream, seek, SEEK_CUR);
|
||||||
|
if (!seektag || isId3v1(seektag)) break;
|
||||||
|
|
||||||
|
/* Replace the old tag with the new one */
|
||||||
|
id3_tag_delete(tag);
|
||||||
|
tag = seektag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
static struct id3_tag * findId3TagFromEnd(FILE * stream)
|
||||||
|
{
|
||||||
|
struct id3_tag * tag;
|
||||||
|
struct id3_tag * v1tag;
|
||||||
|
int tagsize;
|
||||||
|
|
||||||
|
/* Get an id3v1 tag from the end of file for later use */
|
||||||
|
v1tag = getId3Tag(stream, -128, SEEK_END);
|
||||||
|
|
||||||
|
/* Get the id3v2 tag size from the footer (located before v1tag) */
|
||||||
|
tagsize = getId3v2FooterSize(stream, (v1tag ? -128 : 0) - 10, SEEK_END);
|
||||||
|
if (tagsize >= 0) return v1tag;
|
||||||
|
|
||||||
|
/* Get the tag which the footer belongs to */
|
||||||
|
tag = getId3Tag(stream, tagsize, SEEK_CUR);
|
||||||
|
if (!tag) return v1tag;
|
||||||
|
|
||||||
|
/* We have an id3v2 tag, so ditch v1tag */
|
||||||
|
id3_tag_delete(v1tag);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
MpdTag * id3Dup(char * file) {
|
MpdTag * id3Dup(char * file) {
|
||||||
MpdTag * ret = NULL;
|
MpdTag * ret = NULL;
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
struct id3_file * id3_file;
|
|
||||||
struct id3_tag * tag;
|
struct id3_tag * tag;
|
||||||
|
FILE * stream;
|
||||||
|
|
||||||
id3_file = id3_file_open(file, ID3_FILE_MODE_READONLY);
|
stream = fopen(file, "r");
|
||||||
|
if (!stream) {
|
||||||
if(!id3_file) {
|
|
||||||
DEBUG("id3Dup: Failed to open file: '%s', %s\n",file, strerror(errno));
|
DEBUG("id3Dup: Failed to open file: '%s', %s\n",file, strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tag = id3_file_tag(id3_file);
|
tag = findId3TagFromBeginning(stream);
|
||||||
if(!tag) {
|
if (!tag) tag = findId3TagFromEnd(stream);
|
||||||
id3_file_close(id3_file);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fclose(stream);
|
||||||
|
|
||||||
|
if (!tag) return NULL;
|
||||||
ret = parseId3Tag(tag);
|
ret = parseId3Tag(tag);
|
||||||
|
id3_tag_delete(tag);
|
||||||
id3_file_close(id3_file);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user