return -E_STSZ;
}
+static int atom_cmp(unsigned char *buf1, char *buf2)
+{
+ unsigned char *b2 = (unsigned char *)buf2;
+
+ if (buf1[0] != b2[0])
+ return 1;
+ if (buf1[1] != b2[1])
+ return 1;
+ if (buf1[2] != b2[2])
+ return 1;
+ if (buf1[3] != b2[3])
+ return 1;
+ return 0;
+}
+
+static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char type[5])
+{
+ int i;
+ uint64_t size = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+
+ memcpy(type, buf + 4, 4);
+ type[4] = '\0';
+
+ PARA_DEBUG_LOG("size: %llu, type: %s\n", (long long unsigned)size, type);
+ if (size != 1) {
+ *subsize = size;
+ return 8;
+ }
+ buf += 4;
+ size = 0;
+ for (i = 0; i < 8; i++)
+ size |= ((uint64_t)buf[i]) << ((7 - i) * 8);
+ *subsize = size;
+ return 16;
+}
+
+static char *get_tag(unsigned char *p, int size)
+{
+ char *buf;
+
+ assert(size > 0);
+ buf = para_malloc(size + 1);
+
+ memcpy(buf, p, size);
+ buf[size] = '\0';
+ PARA_DEBUG_LOG("size: %d: %s\n", size, buf);
+ return buf;
+}
+
+static char *read_tags(unsigned char *buf, size_t buflen)
+{
+ unsigned char *p = buf;
+ char *title = NULL, *artist = NULL, *album = NULL, *year = NULL,
+ *comment = NULL, *result;
+
+ while (p + 32 < buf + buflen) {
+ unsigned char *q, type1[5], type2[5];
+ uint64_t size1, size2;
+ int ret, ret2;
+
+ ret = read_atom_header(p, &size1, type1);
+ ret2 = read_atom_header(p + ret, &size2, type2);
+
+ if (size2 <= 16 || atom_cmp(type2, "data")) {
+ p += size1;
+ continue;
+ }
+ size2 -= 16;
+ q = p + ret + ret2 + 8;
+ if (q + size2 > buf + buflen)
+ break;
+ if (!atom_cmp(type1, "©ART"))
+ artist = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©alb"))
+ album = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©nam"))
+ title = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©cmt"))
+ comment = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©day"))
+ year = get_tag(q, size2);
+ p += size1;
+ }
+ result = make_taginfo(title, artist, album, year, comment);
+ free(title);
+ free(artist);
+ free(album);
+ free(year);
+ free(comment);
+ return result;
+}
+
+static char *read_meta(unsigned char *buf, size_t buflen)
+{
+ unsigned char *p = buf;
+
+ while (p + 4 < buf + buflen) {
+
+ if (p[0] != 'i' || p[1] != 'l' || p[2] != 's' || p[3] != 't') {
+ p++;
+ continue;
+ }
+ p += 4;
+ return read_tags(p, buflen - (p - buf));
+ }
+ return make_taginfo(NULL, NULL, NULL, NULL, NULL);
+}
+
+static char *aac_get_taginfo(unsigned char *buf, size_t buflen)
+{
+ int i;
+ uint64_t subsize;
+ unsigned char type[5];
+
+ for (i = 0; i + 24 < buflen; i++) {
+ unsigned char *p = buf + i;
+ if (p[0] != 'm' || p[1] != 'e' || p[2] != 't' || p[3] != 'a')
+ continue;
+ PARA_INFO_LOG("found metadata at offset %d\n", i);
+ i += 8;
+ p = buf + i;
+ i += read_atom_header(p, &subsize, type);
+ p = buf + i;
+ return read_meta(p, buflen - i);
+ }
+ PARA_INFO_LOG("no meta data\n");
+ return make_taginfo(NULL, NULL, NULL, NULL, NULL);
+}
+
static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
unsigned char *map, size_t numbytes)
{
mp4AudioSpecificConfig mp4ASC;
NeAACDecHandle handle = NULL;
unsigned char *umap = (unsigned char *) map;
+ char *taginfo;
ret = aac_find_esds(umap, numbytes, &skip, &decoder_len);
if (ret < 0)
goto out;
+ taginfo = aac_get_taginfo(umap, numbytes);
handle = aac_open();
ret = -E_AAC_AFH_INIT;
if (NeAACDecInit(handle, umap + skip, decoder_len, &rate, &channels))
ret = (afhi->chunk_table[afhi->chunks_total] - afhi->chunk_table[0]) * 8; /* bits */
ret += (channels * afhi->seconds_total * 500); /* avoid rounding error */
afhi->bitrate = ret / (channels * afhi->seconds_total * 1000);
- afhi->info_string = make_message("%s:\n%s:\n%s:\n",
+ afhi->info_string = make_message("%s:\n%s",
status_item_list[SI_AUDIO_FILE_INFO],
- status_item_list[SI_TAGINFO1],
- status_item_list[SI_TAGINFO2]
- );
+ taginfo);
+ free(taginfo);
tv_scale(20, &afhi->chunk_tv, &afhi->eof_tv);
ret = 1;
out: