static const int frame_size_index[] = {24000, 72000, 72000};
static const char *mode_text[] = {"stereo", "joint stereo", "dual channel", "mono", "invalid"};
+static char *make_taginfo(char *title, char *artist, char *album, char *year,
+ char *comment)
+{
+ return make_message("%s: %s, by %s\n" /* taginfo1 */
+ "%s: A: %s, Y: %s, C: %s\n", /* taginfo 2*/
+ status_item_list[SI_TAGINFO1],
+ (title && *title)? title : "(title tag not set)",
+ (artist && *artist)? artist : "(artist tag not set)",
+ status_item_list[SI_TAGINFO2],
+ (album && *album)? album : "(album tag not set)",
+ (year && *year)? year : "????",
+ (comment && *comment)? comment : "(comment tag not set)"
+ );
+}
+
+#ifdef HAVE_LIBID3TAG
+
+#include <id3tag.h>
+
+static char *get_latin1(id3_ucs4_t const *string)
+{
+ if (!string)
+ return NULL;
+ return (char *)id3_ucs4_latin1duplicate(string);
+}
+
+char *get_stringlist(union id3_field *field)
+{
+ unsigned int k, nstrings = id3_field_getnstrings(field);
+ char *result = NULL;
+
+ for (k = 0; k < nstrings; k++) {
+ char *tmp = (char *)get_latin1(id3_field_getstrings(field, k));
+ if (result) {
+ char *tmp2 = result;
+ result = make_message("%s %s", tmp2, tmp);
+ free(tmp);
+ free(tmp2);
+ } else
+ result = tmp;
+ }
+ return result;
+}
+
+static char *get_string(union id3_field *field)
+{
+ id3_ucs4_t const *string = id3_field_getfullstring(field);
+
+ return get_latin1(string);
+}
+
+#define FOR_EACH_FIELD(f, j, fr) for (j = 0; j < (fr)->nfields && \
+ (f = id3_frame_field((fr), j)); j++)
+
+static char *get_strings(struct id3_frame *fr)
+{
+ int j;
+ union id3_field *field;
+
+ FOR_EACH_FIELD(field, j, fr) {
+ enum id3_field_type type = id3_field_type(field);
+
+ if (type == ID3_FIELD_TYPE_STRINGLIST)
+ return get_stringlist(field);
+ if (type == ID3_FIELD_TYPE_STRINGFULL)
+ return get_string(field);
+ }
+ return NULL;
+}
+
+static char *mp3_get_id3(__a_unused unsigned char *map,
+ __a_unused size_t numbytes, int fd)
+{
+ int i;
+ struct id3_tag *id3_t;
+ char *title = NULL, *artist = NULL, *album = NULL, *year = NULL,
+ *comment = NULL, *result;
+ struct id3_file *id3_f = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY);
+
+ if (!id3_f)
+ goto no_tag;
+ id3_t = id3_file_tag(id3_f);
+ if (!id3_t)
+ goto no_tag;
+ for (i = 0; i < id3_t->nframes; i++) {
+ struct id3_frame *fr = id3_t->frames[i];
+ if (!strcmp(fr->id, "TIT2")) {
+ if (!title)
+ title = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "TPE1")) {
+ if (!artist)
+ artist = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "TALB")) {
+ if (!album)
+ album = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "TDRC")) {
+ if (!year)
+ year = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "COMM")) {
+ if (!comment)
+ comment = get_strings(fr);
+ continue;
+ }
+ }
+ id3_file_close(id3_f);
+ result = make_taginfo(title, artist, album, year, comment);
+ free(title);
+ free(artist);
+ free(album);
+ free(year);
+ free(comment);
+ return result;
+no_tag:
+ if (id3_f)
+ id3_file_close(id3_f);
+ return make_message("%s: (no id3 v1/v2 tag)\n%s:\n",
+ status_item_list[SI_TAGINFO1],
+ status_item_list[SI_TAGINFO2]);
+}
+
+#else /* HAVE_LIBID3TAG */
+
/*
* Remove trailing whitespace from the end of a string
*/
return string;
}
-static char *mp3_get_id3(unsigned char *map, size_t numbytes)
+static char *mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd)
{
char title[31], artist[31], album[31], year[5], comment[31];
off_t fpos;
unpad(album);
unpad(year);
unpad(comment);
- return make_message("%s: %s, by %s\n" /* taginfo1 */
- "%s: A: %s, Y: %s, C: %s\n", /* taginfo 2*/
- status_item_list[SI_TAGINFO1],
- *title? title : "(title tag not set)",
- *artist? artist : "(artist tag not set)",
- status_item_list[SI_TAGINFO2],
- *album? album : "(album tag not set)",
- *year? year : "????",
- *comment? comment : "(comment tag not set)"
- );
+ return make_taginfo(title, artist, album, year, comment);
}
+#endif /* HAVE_LIBID3TAG */
static int header_frequency(struct mp3header *h)
{
return frame_len;
}
-static int mp3_read_info(unsigned char *map, size_t numbytes,
+static int mp3_read_info(unsigned char *map, size_t numbytes, int fd,
struct afh_info *afhi)
{
long freq_avg = 0, br_avg = 0;
afhi->chunks_total = 0;
afhi->chunk_table = para_malloc(chunk_table_size * sizeof(size_t));
- taginfo = mp3_get_id3(map, numbytes);
+ taginfo = mp3_get_id3(map, numbytes, fd);
while (1) {
unsigned long freq, br, fl;
struct timeval tmp, cct; /* current chunk time */
{
int ret;
- ret = mp3_read_info((unsigned char *)map, numbytes, afhi);
+ ret = mp3_read_info((unsigned char *)map, numbytes, fd, afhi);
if (ret < 0)
return ret;
if (afhi->seconds_total < 2 || !afhi->chunks_total)