return NULL;
}
-static void mp3_get_id3(__a_unused unsigned char *map,
- __a_unused size_t numbytes, int fd, struct taginfo *tags)
+/* this only sets values which are undefined so far */
+static void parse_frames(struct id3_tag *id3_t, struct taginfo *tags)
{
- int i, new_fd;
- struct id3_tag *id3_t;
- struct id3_file *id3_f;
-
- /*
- * We are not supposed to close fd, but to avoid memory leaks we must
- * call id3_file_close() on the id3_file after we are done. As
- * id3_file_close() closes fd, we first create a copy for libid3tag.
- */
- new_fd = dup(fd);
- if (new_fd < 0)
- return;
- id3_f = id3_file_fdopen(new_fd, ID3_FILE_MODE_READONLY);
-
- if (!id3_f)
- return;
- id3_t = id3_file_tag(id3_f);
- if (!id3_t) {
- id3_file_close(id3_f);
- return;
- }
+ int i;
+
for (i = 0; i < id3_t->nframes; i++) {
struct id3_frame *fr = id3_t->frames[i];
if (!strcmp(fr->id, ID3_FRAME_TITLE)) {
continue;
}
}
- id3_file_close(id3_f);
+}
+
+static int mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd,
+ struct taginfo *tags)
+{
+ int ret = 0;
+ struct id3_tag *id3_t;
+
+ /* id3v2 tags are usually located at the beginning. */
+ id3_t = id3_tag_parse(map, numbytes);
+ if (id3_t) {
+ parse_frames(id3_t, tags);
+ ret |= 2;
+ id3_tag_delete(id3_t);
+ }
+ /* Also look for an id3v1 tag at the end of the file. */
+ if (numbytes >= 128) {
+ id3_t = id3_tag_parse(map + numbytes - 128, 128);
+ if (id3_t) {
+ parse_frames(id3_t, tags);
+ ret |= 1;
+ id3_tag_delete(id3_t);
+ }
+ }
+ return ret;
}
#else /* HAVE_LIBID3TAG */
return string;
}
-static void mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd,
+static int mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd,
struct taginfo *tags)
{
char title[31], artist[31], album[31], year[5], comment[31];
if (numbytes < 128 || strncmp("TAG", (char *)map + numbytes - 128, 3)) {
PARA_DEBUG_LOG("no id3 v1 tag\n");
- return;
+ return 0;
}
fpos = numbytes - 125;
memcpy(title, map + fpos, 30);
tags->year = para_strdup(year);
tags->album = para_strdup(album);
tags->comment = para_strdup(comment);
+ return 1;
}
#endif /* HAVE_LIBID3TAG */
unsigned chunk_table_size = 1000; /* gets increased on demand */
off_t fpos = 0;
struct mp3header header;
+ const char *tag_versions[] = {"no", "id3v1", "id3v2", "id3v1+id3v2"};
afhi->chunks_total = 0;
afhi->chunk_table = para_malloc(chunk_table_size * sizeof(uint32_t));
tv_divide(afhi->chunks_total, &total_time, &afhi->chunk_tv);
PARA_DEBUG_LOG("%lu chunks, each %lums\n", afhi->chunks_total,
tv2ms(&afhi->chunk_tv));
- afhi->techinfo = make_message("%cbr, %s", vbr? 'v' : 'c',
- header_mode(&header));
- mp3_get_id3(map, numbytes, fd, &afhi->tags);
+ ret = mp3_get_id3(map, numbytes, fd, &afhi->tags);
+ afhi->techinfo = make_message("%cbr, %s, %s tags", vbr? 'v' : 'c',
+ header_mode(&header), tag_versions[ret]);
return 1;
err_out:
PARA_ERROR_LOG("%s\n", para_strerror(-ret));