Currently the mp3 audio format handler first looks at id3v2 tags and
ignores any id3v1 tags if a version 2 tag is present. This patch makes
it look at both types of tags, and combine the result if necessary.
We use the opportunity to also get rid of the file descriptor mess
in mp3_get_id3(). It is completely unnecessary as lib3d3tag can make
a id3_t structure from a memory buffer. We simply pass (a part of)
the memory map of the audio file and are done.
The techinfo field of struct audio_format_handler_info is changed
to show which tag versions the various tags were extracted. Possible
values are none, v1, v2 and v1+v2.
-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;
- }
for (i = 0; i < id3_t->nframes; i++) {
struct id3_frame *fr = id3_t->frames[i];
if (!strcmp(fr->id, ID3_FRAME_TITLE)) {
for (i = 0; i < id3_t->nframes; i++) {
struct id3_frame *fr = id3_t->frames[i];
if (!strcmp(fr->id, ID3_FRAME_TITLE)) {
+}
+
+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 */
}
#else /* HAVE_LIBID3TAG */
-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];
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");
if (numbytes < 128 || strncmp("TAG", (char *)map + numbytes - 128, 3)) {
PARA_DEBUG_LOG("no id3 v1 tag\n");
}
fpos = numbytes - 125;
memcpy(title, map + fpos, 30);
}
fpos = numbytes - 125;
memcpy(title, map + fpos, 30);
tags->year = para_strdup(year);
tags->album = para_strdup(album);
tags->comment = para_strdup(comment);
tags->year = para_strdup(year);
tags->album = para_strdup(album);
tags->comment = para_strdup(comment);
}
#endif /* HAVE_LIBID3TAG */
}
#endif /* HAVE_LIBID3TAG */
unsigned chunk_table_size = 1000; /* gets increased on demand */
off_t fpos = 0;
struct mp3header header;
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));
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));
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));
return 1;
err_out:
PARA_ERROR_LOG("%s\n", para_strerror(-ret));