summaryrefslogtreecommitdiff
path: root/lib/rbcodec/metadata
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/metadata')
-rw-r--r--lib/rbcodec/metadata/a52.c103
-rw-r--r--lib/rbcodec/metadata/adx.c124
-rw-r--r--lib/rbcodec/metadata/aiff.c108
-rw-r--r--lib/rbcodec/metadata/ape.c182
-rw-r--r--lib/rbcodec/metadata/asap.c254
-rw-r--r--lib/rbcodec/metadata/asf.c591
-rw-r--r--lib/rbcodec/metadata/au.c105
-rw-r--r--lib/rbcodec/metadata/ay.c148
-rw-r--r--lib/rbcodec/metadata/flac.c127
-rw-r--r--lib/rbcodec/metadata/gbs.c65
-rw-r--r--lib/rbcodec/metadata/hes.c39
-rw-r--r--lib/rbcodec/metadata/id3tags.c1199
-rw-r--r--lib/rbcodec/metadata/kss.c53
-rw-r--r--lib/rbcodec/metadata/metadata.c641
-rw-r--r--lib/rbcodec/metadata/metadata.h353
-rw-r--r--lib/rbcodec/metadata/metadata_common.c374
-rw-r--r--lib/rbcodec/metadata/metadata_common.h69
-rw-r--r--lib/rbcodec/metadata/metadata_parsers.h59
-rw-r--r--lib/rbcodec/metadata/mod.c103
-rw-r--r--lib/rbcodec/metadata/monkeys.c97
-rw-r--r--lib/rbcodec/metadata/mp3.c193
-rw-r--r--lib/rbcodec/metadata/mp3data.c849
-rw-r--r--lib/rbcodec/metadata/mp3data.h89
-rw-r--r--lib/rbcodec/metadata/mp4.c842
-rw-r--r--lib/rbcodec/metadata/mpc.c220
-rw-r--r--lib/rbcodec/metadata/nsf.c278
-rw-r--r--lib/rbcodec/metadata/ogg.c215
-rw-r--r--lib/rbcodec/metadata/oma.c189
-rw-r--r--lib/rbcodec/metadata/replaygain.c222
-rw-r--r--lib/rbcodec/metadata/replaygain.h34
-rw-r--r--lib/rbcodec/metadata/rm.c464
-rw-r--r--lib/rbcodec/metadata/sgc.c67
-rw-r--r--lib/rbcodec/metadata/sid.c89
-rw-r--r--lib/rbcodec/metadata/smaf.c470
-rw-r--r--lib/rbcodec/metadata/spc.c130
-rw-r--r--lib/rbcodec/metadata/tta.c123
-rw-r--r--lib/rbcodec/metadata/vgm.c195
-rw-r--r--lib/rbcodec/metadata/vorbis.c381
-rw-r--r--lib/rbcodec/metadata/vox.c49
-rw-r--r--lib/rbcodec/metadata/wave.c432
-rw-r--r--lib/rbcodec/metadata/wavpack.c160
41 files changed, 10485 insertions, 0 deletions
diff --git a/lib/rbcodec/metadata/a52.c b/lib/rbcodec/metadata/a52.c
new file mode 100644
index 0000000000..a8aad3fa4f
--- /dev/null
+++ b/lib/rbcodec/metadata/a52.c
@@ -0,0 +1,103 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include "metadata.h"
24#include "logf.h"
25
26#include "metadata_parsers.h"
27
28static const unsigned short a52_bitrates[] =
29{
30 32, 40, 48, 56, 64, 80, 96, 112, 128, 160,
31 192, 224, 256, 320, 384, 448, 512, 576, 640
32};
33
34/* Only store frame sizes for 44.1KHz - others are simply multiples
35 of the bitrate */
36static const unsigned short a52_441framesizes[] =
37{
38 69 * 2, 70 * 2, 87 * 2, 88 * 2, 104 * 2, 105 * 2, 121 * 2,
39 122 * 2, 139 * 2, 140 * 2, 174 * 2, 175 * 2, 208 * 2, 209 * 2,
40 243 * 2, 244 * 2, 278 * 2, 279 * 2, 348 * 2, 349 * 2, 417 * 2,
41 418 * 2, 487 * 2, 488 * 2, 557 * 2, 558 * 2, 696 * 2, 697 * 2,
42 835 * 2, 836 * 2, 975 * 2, 976 * 2, 1114 * 2, 1115 * 2, 1253 * 2,
43 1254 * 2, 1393 * 2, 1394 * 2
44};
45
46bool get_a52_metadata(int fd, struct mp3entry *id3)
47{
48 /* Use the trackname part of the id3 structure as a temporary buffer */
49 unsigned char* buf = (unsigned char *)id3->path;
50 unsigned long totalsamples;
51 int i;
52
53 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 5) < 5))
54 {
55 return false;
56 }
57
58 if ((buf[0] != 0x0b) || (buf[1] != 0x77))
59 {
60 logf("not an A52/AC3 file\n");
61 return false;
62 }
63
64 i = buf[4] & 0x3e;
65
66 if (i > 36)
67 {
68 logf("A52: Invalid frmsizecod: %d\n",i);
69 return false;
70 }
71
72 id3->bitrate = a52_bitrates[i >> 1];
73 id3->vbr = false;
74 id3->filesize = filesize(fd);
75
76 switch (buf[4] & 0xc0)
77 {
78 case 0x00:
79 id3->frequency = 48000;
80 id3->bytesperframe=id3->bitrate * 2 * 2;
81 break;
82
83 case 0x40:
84 id3->frequency = 44100;
85 id3->bytesperframe = a52_441framesizes[i];
86 break;
87
88 case 0x80:
89 id3->frequency = 32000;
90 id3->bytesperframe = id3->bitrate * 3 * 2;
91 break;
92
93 default:
94 logf("A52: Invalid samplerate code: 0x%02x\n", buf[4] & 0xc0);
95 return false;
96 break;
97 }
98
99 /* One A52 frame contains 6 blocks, each containing 256 samples */
100 totalsamples = id3->filesize / id3->bytesperframe * 6 * 256;
101 id3->length = totalsamples / id3->frequency * 1000;
102 return true;
103}
diff --git a/lib/rbcodec/metadata/adx.c b/lib/rbcodec/metadata/adx.c
new file mode 100644
index 0000000000..7c341b4835
--- /dev/null
+++ b/lib/rbcodec/metadata/adx.c
@@ -0,0 +1,124 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "debug.h"
32
33bool get_adx_metadata(int fd, struct mp3entry* id3)
34{
35 /* Use the trackname part of the id3 structure as a temporary buffer */
36 unsigned char * buf = (unsigned char *)id3->path;
37 int chanstart, channels;
38 int looping = 0, start_adr = 0, end_adr = 0;
39
40 /* try to get the basic header */
41 if ((lseek(fd, 0, SEEK_SET) < 0)
42 || (read(fd, buf, 0x38) < 0x38))
43 {
44 DEBUGF("lseek or read failed\n");
45 return false;
46 }
47
48 /* ADX starts with 0x80 */
49 if (buf[0] != 0x80) {
50 DEBUGF("get_adx_metadata: wrong first byte %c\n",buf[0]);
51 return false;
52 }
53
54 /* check for a reasonable offset */
55 chanstart = ((buf[2] << 8) | buf[3]) + 4;
56 if (chanstart > 4096) {
57 DEBUGF("get_adx_metadata: bad chanstart %i\n", chanstart);
58 return false;
59 }
60
61 /* check for a workable number of channels */
62 channels = buf[7];
63 if (channels != 1 && channels != 2) {
64 DEBUGF("get_adx_metadata: bad channel count %i\n",channels);
65 return false;
66 }
67
68 id3->frequency = get_long_be(&buf[8]);
69 /* 32 samples per 18 bytes */
70 id3->bitrate = id3->frequency * channels * 18 * 8 / 32 / 1000;
71 id3->length = get_long_be(&buf[12]) / id3->frequency * 1000;
72 id3->vbr = false;
73 id3->filesize = filesize(fd);
74
75 /* get loop info */
76 if (!memcmp(buf+0x10,"\x01\xF4\x03",3)) {
77 /* Soul Calibur 2 style (type 03) */
78 DEBUGF("get_adx_metadata: type 03 found\n");
79 /* check if header is too small for loop data */
80 if (chanstart-6 < 0x2c) looping=0;
81 else {
82 looping = get_long_be(&buf[0x18]);
83 end_adr = get_long_be(&buf[0x28]);
84 start_adr = get_long_be(&buf[0x1c])/32*channels*18+chanstart;
85 }
86 } else if (!memcmp(buf+0x10,"\x01\xF4\x04",3)) {
87 /* Standard (type 04) */
88 DEBUGF("get_adx_metadata: type 04 found\n");
89 /* check if header is too small for loop data */
90 if (chanstart-6 < 0x38) looping=0;
91 else {
92 looping = get_long_be(&buf[0x24]);
93 end_adr = get_long_be(&buf[0x34]);
94 start_adr = get_long_be(&buf[0x28])/32*channels*18+chanstart;
95 }
96 } else {
97 DEBUGF("get_adx_metadata: error, couldn't determine ADX type\n");
98 return false;
99 }
100
101 /* is file using encryption */
102 if (buf[0x13]==0x08) {
103 DEBUGF("get_adx_metadata: error, encrypted ADX not supported\n");
104 return false;
105 }
106
107 if (looping) {
108 /* 2 loops, 10 second fade */
109 id3->length = (start_adr-chanstart + 2*(end_adr-start_adr))
110 *8 / id3->bitrate + 10000;
111 }
112
113 /* try to get the channel header */
114 if ((lseek(fd, chanstart-6, SEEK_SET) < 0)
115 || (read(fd, buf, 6) < 6))
116 {
117 return false;
118 }
119
120 /* check channel header */
121 if (memcmp(buf, "(c)CRI", 6) != 0) return false;
122
123 return true;
124}
diff --git a/lib/rbcodec/metadata/aiff.c b/lib/rbcodec/metadata/aiff.c
new file mode 100644
index 0000000000..654f37cf98
--- /dev/null
+++ b/lib/rbcodec/metadata/aiff.c
@@ -0,0 +1,108 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31
32#include "debug.h"
33
34/* compressionType: AIFC QuickTime IMA ADPCM */
35#define AIFC_FORMAT_QT_IMA_ADPCM "ima4"
36
37bool get_aiff_metadata(int fd, struct mp3entry* id3)
38{
39 unsigned char buf[512];
40 unsigned long numChannels = 0;
41 unsigned long numSampleFrames = 0;
42 unsigned long numbytes = 0;
43 bool is_aifc = false;
44
45 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, &buf[0], 12) < 12) ||
46 (memcmp(&buf[0], "FORM", 4) != 0) || (memcmp(&buf[8], "AIF", 3) != 0) ||
47 (!(is_aifc = (buf[11] == 'C')) && buf[11] != 'F'))
48 {
49 return false;
50 }
51
52 while (read(fd, &buf[0], 8) == 8)
53 {
54 size_t size = get_long_be(&buf[4]); /* chunkSize */
55
56 if (memcmp(&buf[0], "SSND", 4) == 0)
57 {
58 numbytes = size - 8;
59 break; /* assume COMM was already read */
60 }
61
62 /* odd chunk sizes must be padded */
63 size += size & 1;
64
65 if (size > sizeof(buf))
66 {
67 DEBUGF("AIFF \"%4.4s\" chunk too large (%zd > %zd)",
68 (char*) &buf[0], size, sizeof(buf));
69 }
70
71 if (memcmp(&buf[0], "COMM", 4) == 0)
72 {
73 if (size > sizeof(buf) || read(fd, &buf[0], size) != (ssize_t)size)
74 return false;
75
76 numChannels = ((buf[0]<<8)|buf[1]);
77
78 numSampleFrames = get_long_be(&buf[2]);
79
80 /* sampleRate */
81 id3->frequency = get_long_be(&buf[10]);
82 id3->frequency >>= (16+14-buf[9]);
83
84 /* save format infos */
85 id3->bitrate = ((buf[6]<<8)|buf[7]) * numChannels * id3->frequency;
86 id3->bitrate /= 1000;
87
88 if (!is_aifc || memcmp(&buf[18], AIFC_FORMAT_QT_IMA_ADPCM, 4) != 0)
89 id3->length = ((int64_t) numSampleFrames * 1000) / id3->frequency;
90 else
91 {
92 /* QuickTime IMA ADPCM is 1block = 64 data for each channel */
93 id3->length = ((int64_t) numSampleFrames * 64000LL) / id3->frequency;
94 }
95
96 id3->vbr = false; /* AIFF files are CBR */
97 id3->filesize = filesize(fd);
98 }
99 else
100 {
101 /* skip chunk */
102 if (lseek(fd, size, SEEK_CUR) < 0)
103 return false;
104 }
105 }
106
107 return numbytes && numChannels;
108}
diff --git a/lib/rbcodec/metadata/ape.c b/lib/rbcodec/metadata/ape.c
new file mode 100644
index 0000000000..0bd2477431
--- /dev/null
+++ b/lib/rbcodec/metadata/ape.c
@@ -0,0 +1,182 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "structec.h"
32
33#define APETAG_HEADER_LENGTH 32
34#define APETAG_HEADER_FORMAT "8llll8"
35#define APETAG_ITEM_HEADER_FORMAT "ll"
36#define APETAG_ITEM_TYPE_MASK 3
37
38#ifdef HAVE_ALBUMART
39/* The AA header consists of the pseudo filename "Album Cover (Front).ext"
40 * whereas ".ext" is the file extension. For now ".jpg" and ".png" are
41 * supported by this APE metadata parser. Therefore the length is 22. */
42#define APETAG_AA_HEADER_LENGTH 22
43#endif
44
45struct apetag_header
46{
47 char id[8];
48 long version;
49 long length;
50 long item_count;
51 long flags;
52 char reserved[8];
53};
54
55struct apetag_item_header
56{
57 long length;
58 long flags;
59};
60
61/* Read the items in an APEV2 tag. Only looks for a tag at the end of a
62 * file. Returns true if a tag was found and fully read, false otherwise.
63 */
64bool read_ape_tags(int fd, struct mp3entry* id3)
65{
66 struct apetag_header header;
67
68 if ((lseek(fd, -APETAG_HEADER_LENGTH, SEEK_END) < 0)
69 || (ecread(fd, &header, 1, APETAG_HEADER_FORMAT, IS_BIG_ENDIAN)
70 != APETAG_HEADER_LENGTH)
71 || (memcmp(header.id, "APETAGEX", sizeof(header.id))))
72 {
73 return false;
74 }
75
76 if ((header.version == 2000) && (header.item_count > 0)
77 && (header.length > APETAG_HEADER_LENGTH))
78 {
79 char *buf = id3->id3v2buf;
80 unsigned int buf_remaining = sizeof(id3->id3v2buf)
81 + sizeof(id3->id3v1buf);
82 unsigned int tag_remaining = header.length - APETAG_HEADER_LENGTH;
83 int i;
84
85 if (lseek(fd, -header.length, SEEK_END) < 0)
86 {
87 return false;
88 }
89
90 for (i = 0; i < header.item_count; i++)
91 {
92 struct apetag_item_header item;
93 char name[TAG_NAME_LENGTH];
94 char value[TAG_VALUE_LENGTH];
95 long r;
96
97 if (tag_remaining < sizeof(item))
98 {
99 break;
100 }
101
102 if (ecread(fd, &item, 1, APETAG_ITEM_HEADER_FORMAT, IS_BIG_ENDIAN)
103 < (long) sizeof(item))
104 {
105 return false;
106 }
107
108 tag_remaining -= sizeof(item);
109 r = read_string(fd, name, sizeof(name), 0, tag_remaining);
110
111 if (r == -1)
112 {
113 return false;
114 }
115
116 tag_remaining -= r + item.length;
117
118 if ((item.flags & APETAG_ITEM_TYPE_MASK) == 0)
119 {
120 long len;
121
122 if (read_string(fd, value, sizeof(value), -1, item.length)
123 != item.length)
124 {
125 return false;
126 }
127
128 len = parse_tag(name, value, id3, buf, buf_remaining,
129 TAGTYPE_APE);
130 buf += len;
131 buf_remaining -= len;
132 }
133 else
134 {
135#ifdef HAVE_ALBUMART
136 if (strcasecmp(name, "cover art (front)") == 0)
137 {
138 /* Allow to read at least APETAG_AA_HEADER_LENGTH bytes. */
139 r = read_string(fd, name, sizeof(name), 0, APETAG_AA_HEADER_LENGTH);
140 if (r == -1)
141 {
142 return false;
143 }
144
145 /* Gather the album art format from the pseudo file name's ending. */
146 strcpy(name, name + strlen(name) - 4);
147 id3->albumart.type = AA_TYPE_UNKNOWN;
148 if (strcasecmp(name, ".jpg") == 0)
149 {
150 id3->albumart.type = AA_TYPE_JPG;
151 }
152 else if (strcasecmp(name, ".png") == 0)
153 {
154 id3->albumart.type = AA_TYPE_PNG;
155 }
156
157 /* Set the album art size and position. */
158 if (id3->albumart.type != AA_TYPE_UNKNOWN)
159 {
160 id3->albumart.pos = lseek(fd, 0, SEEK_CUR);
161 id3->albumart.size = item.length - r;
162 id3->has_embedded_albumart = true;
163 }
164
165 /* Seek back to this APE items begin. */
166 if (lseek(fd, -r, SEEK_CUR) < 0)
167 {
168 return false;
169 }
170 }
171#endif
172 /* Seek to the next APE item. */
173 if (lseek(fd, item.length, SEEK_CUR) < 0)
174 {
175 return false;
176 }
177 }
178 }
179 }
180
181 return true;
182}
diff --git a/lib/rbcodec/metadata/asap.c b/lib/rbcodec/metadata/asap.c
new file mode 100644
index 0000000000..9e7f227031
--- /dev/null
+++ b/lib/rbcodec/metadata/asap.c
@@ -0,0 +1,254 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 Dominik Wenger
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32#include "debug.h"
33
34#define MAX_SONGS 32
35
36static bool parse_dec(int *retval, const char *p, int minval, int maxval)
37{
38 int r = 0;
39 do {
40 char c = *p;
41 if (c >= '0' && c <= '9')
42 r = 10 * r + c - '0';
43 else
44 return false;
45 if (r > maxval)
46 return false;
47 } while (*++p != '\0');
48 if (r < minval)
49 return false;
50 *retval = r;
51 return true;
52}
53
54static bool parse_text(char *retval, const char *p)
55{
56 int i;
57 if (*p != '"')
58 return false;
59 p++;
60 if (p[0] == '<' && p[1] == '?' && p[2] == '>' && p[3] == '"')
61 return true;
62 i = 0;
63 while (*p != '"') {
64 if (i >= 127)
65 return false;
66 if (*p == '\0')
67 return false;
68 retval[i++] = *p++;
69 }
70 retval[i] = '\0';
71 return true;
72}
73
74static int ASAP_ParseDuration(const char *s)
75{
76 int r;
77 if (*s < '0' || *s > '9')
78 return -1;
79 r = *s++ - '0';
80 if (*s >= '0' && *s <= '9')
81 r = 10 * r + *s++ - '0';
82 if (*s == ':') {
83 s++;
84 if (*s < '0' || *s > '5')
85 return -1;
86 r = 60 * r + (*s++ - '0') * 10;
87 if (*s < '0' || *s > '9')
88 return -1;
89 r += *s++ - '0';
90 }
91 r *= 1000;
92 if (*s != '.')
93 return r;
94 s++;
95 if (*s < '0' || *s > '9')
96 return r;
97 r += 100 * (*s++ - '0');
98 if (*s < '0' || *s > '9')
99 return r;
100 r += 10 * (*s++ - '0');
101 if (*s < '0' || *s > '9')
102 return r;
103 r += *s - '0';
104 return r;
105}
106
107static bool read_asap_string(char* source, char** buf, char** buffer_end, char** dest)
108{
109 if(parse_text(*buf,source) == false)
110 return false;
111
112 /* set dest pointer */
113 *dest = *buf;
114
115 /* move buf ptr */
116 *buf += strlen(*buf)+1;
117
118 /* check size */
119 if(*buf >= *buffer_end)
120 {
121 DEBUGF("Buffer full\n");
122 return false;
123 }
124 return true;
125}
126
127static bool parse_sap_header(int fd, struct mp3entry* id3, int file_len)
128{
129 int module_index = 0;
130 int sap_signature = -1;
131 int duration_index = 0;
132 unsigned char cur_char = 0;
133 int i;
134
135 /* set defaults */
136 int numSongs = 1;
137 int defSong = 0;
138 int durations[MAX_SONGS];
139 for (i = 0; i < MAX_SONGS; i++)
140 durations[i] = -1;
141
142 /* use id3v2 buffer for our strings */
143 char* buffer = id3->id3v2buf;
144 char* buffer_end = id3->id3v2buf + ID3V2_BUF_SIZE;
145
146 /* parse file */
147 while (1)
148 {
149 char line[256];
150 char *p;
151
152 if (module_index + 8 >= file_len)
153 return false;
154 /* read a char */
155 read(fd,&cur_char,1);
156 /* end of header */
157 if (cur_char == 0xff)
158 break;
159
160 i = 0;
161 while (cur_char != 0x0d)
162 {
163 line[i++] = cur_char;
164 module_index++;
165 if (module_index >= file_len || (unsigned)i >= sizeof(line) - 1)
166 return false;
167 /* read a char */
168 read(fd,&cur_char,1);
169 }
170 if (++module_index >= file_len )
171 return false;
172 /* read a char */
173 read(fd,&cur_char,1);
174 if ( cur_char != 0x0a)
175 return false;
176
177 line[i] = '\0';
178 for (p = line; *p != '\0'; p++) {
179 if (*p == ' ') {
180 *p++ = '\0';
181 break;
182 }
183 }
184
185 /* parse tags */
186 if(strcmp(line, "SAP") == 0)
187 sap_signature = 1;
188 if (sap_signature == -1)
189 return false;
190 if (strcmp(line, "AUTHOR") == 0)
191 {
192 if(read_asap_string(p, &buffer, &buffer_end, &id3->artist) == false)
193 return false;
194 }
195 else if(strcmp(line, "NAME") == 0)
196 {
197 if(read_asap_string(p, &buffer, &buffer_end, &id3->title) == false)
198 return false;
199 }
200 else if(strcmp(line, "DATE") == 0)
201 {
202 if(read_asap_string(p, &buffer, &buffer_end, &id3->year_string) == false)
203 return false;
204 }
205 else if (strcmp(line, "SONGS") == 0)
206 {
207 if (parse_dec(&numSongs, p, 1, MAX_SONGS) == false )
208 return false;
209 }
210 else if (strcmp(line, "DEFSONG") == 0)
211 {
212 if (parse_dec(&defSong, p, 0, MAX_SONGS) == false)
213 return false;
214 }
215 else if (strcmp(line, "TIME") == 0)
216 {
217 int durationTemp = ASAP_ParseDuration(p);
218 if (durationTemp < 0 || duration_index >= MAX_SONGS)
219 return false;
220 durations[duration_index++] = durationTemp;
221 }
222 }
223
224 /* set length: */
225 int length = durations[defSong];
226 if (length < 0)
227 length = 180 * 1000;
228 id3->length = length;
229
230 lseek(fd, 0, SEEK_SET);
231 return true;
232}
233
234
235bool get_asap_metadata(int fd, struct mp3entry* id3)
236{
237
238 int filelength = filesize(fd);
239
240 if(parse_sap_header(fd, id3, filelength) == false)
241 {
242 DEBUGF("parse sap header failed.\n");
243 return false;
244 }
245
246 id3->bitrate = 706;
247 id3->frequency = 44100;
248
249 id3->vbr = false;
250 id3->filesize = filelength;
251 id3->genre_string = id3_get_num_genre(36);
252
253 return true;
254}
diff --git a/lib/rbcodec/metadata/asf.c b/lib/rbcodec/metadata/asf.c
new file mode 100644
index 0000000000..b815c09769
--- /dev/null
+++ b/lib/rbcodec/metadata/asf.c
@@ -0,0 +1,591 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * $Id$
10 *
11 * Copyright (C) 2007 Dave Chapman
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <ctype.h>
26#include <inttypes.h>
27
28#include "metadata.h"
29#include "replaygain.h"
30#include "debug.h"
31#include "rbunicode.h"
32#include "metadata_common.h"
33#include "metadata_parsers.h"
34#include "system.h"
35#include <codecs/libasf/asf.h>
36
37/* TODO: Just read the GUIDs into a 16-byte array, and use memcmp to compare */
38struct guid_s {
39 uint32_t v1;
40 uint16_t v2;
41 uint16_t v3;
42 uint8_t v4[8];
43};
44typedef struct guid_s guid_t;
45
46struct asf_object_s {
47 guid_t guid;
48 uint64_t size;
49 uint64_t datalen;
50};
51typedef struct asf_object_s asf_object_t;
52
53static const guid_t asf_guid_null =
54{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
55
56/* top level object guids */
57
58static const guid_t asf_guid_header =
59{0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
60
61static const guid_t asf_guid_data =
62{0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
63
64static const guid_t asf_guid_index =
65{0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
66
67/* header level object guids */
68
69static const guid_t asf_guid_file_properties =
70{0x8cabdca1, 0xa947, 0x11cf, {0x8E, 0xe4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
71
72static const guid_t asf_guid_stream_properties =
73{0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
74
75static const guid_t asf_guid_content_description =
76{0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
77
78static const guid_t asf_guid_extended_content_description =
79{0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
80
81static const guid_t asf_guid_content_encryption =
82{0x2211b3fb, 0xbd23, 0x11d2, {0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}};
83
84static const guid_t asf_guid_extended_content_encryption =
85{0x298ae614, 0x2622, 0x4c17, {0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c}};
86
87/* stream type guids */
88
89static const guid_t asf_guid_stream_type_audio =
90{0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
91
92static int asf_guid_match(const guid_t *guid1, const guid_t *guid2)
93{
94 if((guid1->v1 != guid2->v1) ||
95 (guid1->v2 != guid2->v2) ||
96 (guid1->v3 != guid2->v3) ||
97 (memcmp(guid1->v4, guid2->v4, 8))) {
98 return 0;
99 }
100
101 return 1;
102}
103
104/* Read the 16 byte GUID from a file */
105static void asf_readGUID(int fd, guid_t* guid)
106{
107 read_uint32le(fd, &guid->v1);
108 read_uint16le(fd, &guid->v2);
109 read_uint16le(fd, &guid->v3);
110 read(fd, guid->v4, 8);
111}
112
113static void asf_read_object_header(asf_object_t *obj, int fd)
114{
115 asf_readGUID(fd, &obj->guid);
116 read_uint64le(fd, &obj->size);
117 obj->datalen = 0;
118}
119
120/* Parse an integer from the extended content object - we always
121 convert to an int, regardless of native format.
122*/
123static int asf_intdecode(int fd, int type, int length)
124{
125 uint16_t tmp16;
126 uint32_t tmp32;
127 uint64_t tmp64;
128
129 if (type == 3) {
130 read_uint32le(fd, &tmp32);
131 lseek(fd,length - 4,SEEK_CUR);
132 return (int)tmp32;
133 } else if (type == 4) {
134 read_uint64le(fd, &tmp64);
135 lseek(fd,length - 8,SEEK_CUR);
136 return (int)tmp64;
137 } else if (type == 5) {
138 read_uint16le(fd, &tmp16);
139 lseek(fd,length - 2,SEEK_CUR);
140 return (int)tmp16;
141 }
142
143 return 0;
144}
145
146/* Decode a LE utf16 string from a disk buffer into a fixed-sized
147 utf8 buffer.
148*/
149
150static void asf_utf16LEdecode(int fd,
151 uint16_t utf16bytes,
152 unsigned char **utf8,
153 int* utf8bytes
154 )
155{
156 unsigned long ucs;
157 int n;
158 unsigned char utf16buf[256];
159 unsigned char* utf16 = utf16buf;
160 unsigned char* newutf8;
161
162 n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes));
163 utf16bytes -= n;
164
165 while (n > 0) {
166 /* Check for a surrogate pair */
167 if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) {
168 if (n < 4) {
169 /* Run out of utf16 bytes, read some more */
170 utf16buf[0] = utf16[0];
171 utf16buf[1] = utf16[1];
172
173 n = read(fd, utf16buf + 2, MIN(sizeof(utf16buf)-2, utf16bytes));
174 utf16 = utf16buf;
175 utf16bytes -= n;
176 n += 2;
177 }
178
179 if (n < 4) {
180 /* Truncated utf16 string, abort */
181 break;
182 }
183 ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18)
184 | utf16[2] | ((utf16[3] - 0xDC) << 8));
185 utf16 += 4;
186 n -= 4;
187 } else {
188 ucs = (utf16[0] | (utf16[1] << 8));
189 utf16 += 2;
190 n -= 2;
191 }
192
193 if (*utf8bytes > 6) {
194 newutf8 = utf8encode(ucs, *utf8);
195 *utf8bytes -= (newutf8 - *utf8);
196 *utf8 += (newutf8 - *utf8);
197 }
198
199 /* We have run out of utf16 bytes, read more if available */
200 if ((n == 0) && (utf16bytes > 0)) {
201 n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes));
202 utf16 = utf16buf;
203 utf16bytes -= n;
204 }
205 }
206
207 *utf8[0] = 0;
208 --*utf8bytes;
209
210 if (utf16bytes > 0) {
211 /* Skip any remaining bytes */
212 lseek(fd, utf16bytes, SEEK_CUR);
213 }
214 return;
215}
216
217static int asf_parse_header(int fd, struct mp3entry* id3,
218 asf_waveformatex_t* wfx)
219{
220 asf_object_t current;
221 asf_object_t header;
222 uint64_t datalen;
223 int i;
224 int fileprop = 0;
225 uint64_t play_duration;
226 uint16_t flags;
227 uint32_t subobjects;
228 uint8_t utf8buf[512];
229 int id3buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
230 unsigned char* id3buf = (unsigned char*)id3->id3v2buf;
231
232 asf_read_object_header((asf_object_t *) &header, fd);
233
234 //DEBUGF("header.size=%d\n",(int)header.size);
235 if (header.size < 30) {
236 /* invalid size for header object */
237 return ASF_ERROR_OBJECT_SIZE;
238 }
239
240 read_uint32le(fd, &subobjects);
241
242 /* Two reserved bytes - do we need to read them? */
243 lseek(fd, 2, SEEK_CUR);
244
245 //DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects);
246
247 if (subobjects > 0) {
248 header.datalen = header.size - 30;
249
250 /* TODO: Check that we have datalen bytes left in the file */
251 datalen = header.datalen;
252
253 for (i=0; i<(int)subobjects; i++) {
254 //DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen);
255 if (datalen < 24) {
256 //DEBUGF("not enough data for reading object\n");
257 break;
258 }
259
260 asf_read_object_header(&current, fd);
261
262 if (current.size > datalen || current.size < 24) {
263 //DEBUGF("invalid object size - current.size=%d, datalen=%d\n",(int)current.size,(int)datalen);
264 break;
265 }
266
267 if (asf_guid_match(&current.guid, &asf_guid_file_properties)) {
268 if (current.size < 104)
269 return ASF_ERROR_OBJECT_SIZE;
270
271 if (fileprop) {
272 /* multiple file properties objects not allowed */
273 return ASF_ERROR_INVALID_OBJECT;
274 }
275
276 fileprop = 1;
277
278 /* Get the number of logical packets - uint16_t at offset 31
279 * (Big endian byte order) */
280 lseek(fd, 31, SEEK_CUR);
281 read_uint16be(fd, &wfx->numpackets);
282
283 /* Now get the play duration - uint64_t at offset 40 */
284 lseek(fd, 7, SEEK_CUR);
285 read_uint64le(fd, &play_duration);
286 id3->length = play_duration / 10000;
287
288 //DEBUGF("****** length = %lums\n", id3->length);
289
290 /* Read the packet size - uint32_t at offset 68 */
291 lseek(fd, 20, SEEK_CUR);
292 read_uint32le(fd, &wfx->packet_size);
293
294 /* Skip bytes remaining in object */
295 lseek(fd, current.size - 24 - 72, SEEK_CUR);
296 } else if (asf_guid_match(&current.guid, &asf_guid_stream_properties)) {
297 guid_t guid;
298 uint32_t propdatalen;
299
300 if (current.size < 78)
301 return ASF_ERROR_OBJECT_SIZE;
302
303#if 0
304 asf_byteio_getGUID(&guid, current->data);
305 datalen = asf_byteio_getDWLE(current->data + 40);
306 flags = asf_byteio_getWLE(current->data + 48);
307#endif
308
309 asf_readGUID(fd, &guid);
310
311 lseek(fd, 24, SEEK_CUR);
312 read_uint32le(fd, &propdatalen);
313 lseek(fd, 4, SEEK_CUR);
314 read_uint16le(fd, &flags);
315
316 if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) {
317 //DEBUGF("Found stream properties for non audio stream, skipping\n");
318 lseek(fd,current.size - 24 - 50,SEEK_CUR);
319 } else if (wfx->audiostream == -1) {
320 lseek(fd, 4, SEEK_CUR);
321 //DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f);
322
323 if (propdatalen < 18) {
324 return ASF_ERROR_INVALID_LENGTH;
325 }
326
327#if 0
328 if (asf_byteio_getWLE(data + 16) > datalen - 16) {
329 return ASF_ERROR_INVALID_LENGTH;
330 }
331#endif
332 read_uint16le(fd, &wfx->codec_id);
333 read_uint16le(fd, &wfx->channels);
334 read_uint32le(fd, &wfx->rate);
335 read_uint32le(fd, &wfx->bitrate);
336 wfx->bitrate *= 8;
337 read_uint16le(fd, &wfx->blockalign);
338 read_uint16le(fd, &wfx->bitspersample);
339 read_uint16le(fd, &wfx->datalen);
340
341 /* Round bitrate to the nearest kbit */
342 id3->bitrate = (wfx->bitrate + 500) / 1000;
343 id3->frequency = wfx->rate;
344
345 if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {
346 read(fd, wfx->data, 4);
347 lseek(fd,current.size - 24 - 72 - 4,SEEK_CUR);
348 wfx->audiostream = flags&0x7f;
349 } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) {
350 read(fd, wfx->data, 6);
351 lseek(fd,current.size - 24 - 72 - 6,SEEK_CUR);
352 wfx->audiostream = flags&0x7f;
353 } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) {
354 /* wma pro decoder needs the extra-data */
355 read(fd, wfx->data, wfx->datalen);
356 lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
357 wfx->audiostream = flags&0x7f;
358 /* Correct codectype to redirect playback to the proper .codec */
359 id3->codectype = AFMT_WMAPRO;
360 } else if (wfx->codec_id == ASF_CODEC_ID_WMAVOICE) {
361 read(fd, wfx->data, wfx->datalen);
362 lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
363 wfx->audiostream = flags&0x7f;
364 id3->codectype = AFMT_WMAVOICE;
365 } else {
366 DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n");
367 lseek(fd,current.size - 24 - 72,SEEK_CUR);
368 }
369
370 }
371 } else if (asf_guid_match(&current.guid, &asf_guid_content_description)) {
372 /* Object contains five 16-bit string lengths, followed by the five strings:
373 title, artist, copyright, description, rating
374 */
375 uint16_t strlength[5];
376 int i;
377
378 //DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24));
379
380 /* Read the 5 string lengths - number of bytes included trailing zero */
381 for (i=0; i<5; i++) {
382 read_uint16le(fd, &strlength[i]);
383 //DEBUGF("strlength = %u\n",strlength[i]);
384 }
385
386 if (strlength[0] > 0) { /* 0 - Title */
387 id3->title = id3buf;
388 asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining);
389 }
390
391 if (strlength[1] > 0) { /* 1 - Artist */
392 id3->artist = id3buf;
393 asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining);
394 }
395
396 lseek(fd, strlength[2], SEEK_CUR); /* 2 - copyright */
397
398 if (strlength[3] > 0) { /* 3 - description */
399 id3->comment = id3buf;
400 asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining);
401 }
402
403 lseek(fd, strlength[4], SEEK_CUR); /* 4 - rating */
404 } else if (asf_guid_match(&current.guid, &asf_guid_extended_content_description)) {
405 uint16_t count;
406 int i;
407 int bytesleft = current.size - 24;
408 //DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n");
409
410 read_uint16le(fd, &count);
411 bytesleft -= 2;
412 //DEBUGF("extended metadata count = %u\n",count);
413
414 for (i=0; i < count; i++) {
415 uint16_t length, type;
416 unsigned char* utf8 = utf8buf;
417 int utf8length = 512;
418
419 read_uint16le(fd, &length);
420 asf_utf16LEdecode(fd, length, &utf8, &utf8length);
421 bytesleft -= 2 + length;
422
423 read_uint16le(fd, &type);
424 read_uint16le(fd, &length);
425
426 if (!strcmp("WM/TrackNumber",utf8buf)) {
427 if (type == 0) {
428 id3->track_string = id3buf;
429 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
430 id3->tracknum = atoi(id3->track_string);
431 } else if ((type >=2) && (type <= 5)) {
432 id3->tracknum = asf_intdecode(fd, type, length);
433 } else {
434 lseek(fd, length, SEEK_CUR);
435 }
436 } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
437 id3->genre_string = id3buf;
438 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
439 } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
440 id3->album = id3buf;
441 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
442 } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
443 id3->albumartist = id3buf;
444 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
445 } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
446 id3->composer = id3buf;
447 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
448 } else if (!strcmp("WM/Year", utf8buf)) {
449 if (type == 0) {
450 id3->year_string = id3buf;
451 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
452 id3->year = atoi(id3->year_string);
453 } else if ((type >=2) && (type <= 5)) {
454 id3->year = asf_intdecode(fd, type, length);
455 } else {
456 lseek(fd, length, SEEK_CUR);
457 }
458 } else if (!strncmp("replaygain_", utf8buf, 11)) {
459 char *value = id3buf;
460 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
461 parse_replaygain(utf8buf, value, id3);
462 } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
463 id3->mb_track_id = id3buf;
464 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
465#ifdef HAVE_ALBUMART
466 } else if (!strcmp("WM/Picture", utf8buf)) {
467 uint32_t datalength, strlength;
468 /* Expected is either "01 00 xx xx 03 yy yy yy yy" or
469 * "03 yy yy yy yy". xx is the size of the WM/Picture
470 * container in bytes. yy equals the raw data length of
471 * the embedded image. */
472 lseek(fd, -4, SEEK_CUR);
473 read(fd, &type, 1);
474 if (type == 1) {
475 lseek(fd, 3, SEEK_CUR);
476 read(fd, &type, 1);
477 /* In case the parsing will fail in the next step we
478 * might at least be able to skip the whole section. */
479 datalength = length - 1;
480 }
481 if (type == 3) {
482 /* Read the raw data length of the embedded image. */
483 read_uint32le(fd, &datalength);
484
485 /* Reset utf8 buffer */
486 utf8 = utf8buf;
487 utf8length = 512;
488
489 /* Gather the album art format, this string has a
490 * double zero-termination. */
491 asf_utf16LEdecode(fd, 32, &utf8, &utf8length);
492 strlength = (strlen(utf8buf) + 2) * 2;
493 lseek(fd, strlength-32, SEEK_CUR);
494 if (!strcmp("image/jpeg", utf8buf)) {
495 id3->albumart.type = AA_TYPE_JPG;
496 } else if (!strcmp("image/png", utf8buf)) {
497 id3->albumart.type = AA_TYPE_PNG;
498 } else {
499 id3->albumart.type = AA_TYPE_UNKNOWN;
500 }
501
502 /* Set the album art size and position. */
503 if (id3->albumart.type != AA_TYPE_UNKNOWN) {
504 id3->albumart.pos = lseek(fd, 0, SEEK_CUR);
505 id3->albumart.size = datalength;
506 id3->has_embedded_albumart = true;
507 }
508 }
509
510 lseek(fd, datalength, SEEK_CUR);
511#endif
512 } else {
513 lseek(fd, length, SEEK_CUR);
514 }
515 bytesleft -= 4 + length;
516 }
517
518 lseek(fd, bytesleft, SEEK_CUR);
519 } else if (asf_guid_match(&current.guid, &asf_guid_content_encryption)
520 || asf_guid_match(&current.guid, &asf_guid_extended_content_encryption)) {
521 //DEBUGF("File is encrypted\n");
522 return ASF_ERROR_ENCRYPTED;
523 } else {
524 //DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24));
525 lseek(fd,current.size - 24,SEEK_CUR);
526 }
527
528 //DEBUGF("Parsed object - size = %d\n",(int)current.size);
529 datalen -= current.size;
530 }
531
532 if (i != (int)subobjects || datalen != 0) {
533 //DEBUGF("header data doesn't match given subobject count\n");
534 return ASF_ERROR_INVALID_VALUE;
535 }
536
537 //DEBUGF("%d subobjects read successfully\n", i);
538 }
539
540#if 0
541 tmp = asf_parse_header_validate(file, &header);
542 if (tmp < 0) {
543 /* header read ok but doesn't validate correctly */
544 return tmp;
545 }
546#endif
547
548 //DEBUGF("header validated correctly\n");
549
550 return 0;
551}
552
553bool get_asf_metadata(int fd, struct mp3entry* id3)
554{
555 int res;
556 asf_object_t obj;
557 asf_waveformatex_t wfx;
558
559 wfx.audiostream = -1;
560
561 res = asf_parse_header(fd, id3, &wfx);
562
563 if (res < 0) {
564 DEBUGF("ASF: parsing error - %d\n",res);
565 return false;
566 }
567
568 if (wfx.audiostream == -1) {
569 DEBUGF("ASF: No WMA streams found\n");
570 return false;
571 }
572
573 asf_read_object_header(&obj, fd);
574
575 if (!asf_guid_match(&obj.guid, &asf_guid_data)) {
576 DEBUGF("ASF: No data object found\n");
577 return false;
578 }
579
580 /* Store the current file position - no need to parse the header
581 again in the codec. The +26 skips the rest of the data object
582 header.
583 */
584 id3->first_frame_offset = lseek(fd, 0, SEEK_CUR) + 26;
585 id3->filesize = filesize(fd);
586 /* We copy the wfx struct to the MP3 TOC field in the id3 struct so
587 the codec doesn't need to parse the header object again */
588 memcpy(id3->toc, &wfx, sizeof(wfx));
589
590 return true;
591}
diff --git a/lib/rbcodec/metadata/au.c b/lib/rbcodec/metadata/au.c
new file mode 100644
index 0000000000..94e7453644
--- /dev/null
+++ b/lib/rbcodec/metadata/au.c
@@ -0,0 +1,105 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24
25#include "system.h"
26#include "metadata.h"
27#include "metadata_common.h"
28#include "metadata_parsers.h"
29#include "logf.h"
30
31static const unsigned char bitspersamples[9] = {
32 0, /* encoding */
33 8, /* 1: G.711 MULAW */
34 8, /* 2: Linear PCM 8bit */
35 16, /* 3: Linear PCM 16bit */
36 24, /* 4: Linear PCM 24bit */
37 32, /* 5: Linear PCM 32bit */
38 32, /* 6: IEEE float 32bit */
39 64, /* 7: IEEE float 64bit */
40 /* encoding 8 - 26 unsupported. */
41 8, /* 27: G.711 ALAW */
42};
43
44static inline unsigned char get_au_bitspersample(unsigned int encoding)
45{
46 if (encoding < 8)
47 return bitspersamples[encoding];
48 else if (encoding == 27)
49 return bitspersamples[8];
50
51 return 0;
52}
53
54bool get_au_metadata(int fd, struct mp3entry* id3)
55{
56 /* temporary buffer */
57 unsigned char* buf = (unsigned char *)id3->path;
58 unsigned long numbytes = 0;
59 int offset;
60
61 id3->vbr = false; /* All Sun audio files are CBR */
62 id3->filesize = filesize(fd);
63 id3->length = 0;
64
65 lseek(fd, 0, SEEK_SET);
66 if ((read(fd, buf, 24) < 24) || (memcmp(buf, ".snd", 4) != 0))
67 {
68 /*
69 * no header
70 *
71 * frequency: 8000 Hz
72 * bits per sample: 8 bit
73 * channel: mono
74 */
75 numbytes = id3->filesize;
76 id3->frequency = 8000;
77 id3->bitrate = 8;
78 }
79 else
80 {
81 /* parse header */
82
83 /* data offset */
84 offset = get_long_be(buf + 4);
85 if (offset < 24)
86 {
87 DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset);
88 return false;
89 }
90 /* data size */
91 numbytes = get_long_be(buf + 8);
92 if (numbytes == (uint32_t)0xffffffff)
93 numbytes = id3->filesize - offset;
94
95 id3->frequency = get_long_be(buf + 16);
96 id3->bitrate = get_au_bitspersample(get_long_be(buf + 12)) * get_long_be(buf + 20)
97 * id3->frequency / 1000;
98 }
99
100 /* Calculate track length [ms] */
101 if (id3->bitrate)
102 id3->length = (numbytes << 3) / id3->bitrate;
103
104 return true;
105}
diff --git a/lib/rbcodec/metadata/ay.c b/lib/rbcodec/metadata/ay.c
new file mode 100644
index 0000000000..5d00264b3d
--- /dev/null
+++ b/lib/rbcodec/metadata/ay.c
@@ -0,0 +1,148 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13/* Taken from blargg's Game_Music_Emu library */
14
15typedef unsigned char byte;
16
17/* AY file header */
18enum { header_size = 0x14 };
19struct header_t
20{
21 byte tag[8];
22 byte vers;
23 byte player;
24 byte unused[2];
25 byte author[2];
26 byte comment[2];
27 byte max_track;
28 byte first_track;
29 byte track_info[2];
30};
31
32struct file_t {
33 struct header_t const* header;
34 byte const* tracks;
35 byte const* end; /* end of file data */
36};
37
38static int get_be16( const void *a )
39{
40 return get_short_be( (void*) a );
41}
42
43/* Given pointer to 2-byte offset of data, returns pointer to data, or NULL if
44 * offset is 0 or there is less than min_size bytes of data available. */
45static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size )
46{
47 int offset = (int16_t) get_be16( ptr );
48 int pos = ptr - (byte const*) file->header;
49 int size = file->end - (byte const*) file->header;
50 int limit = size - min_size;
51 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit )
52 return NULL;
53 return ptr + offset;
54}
55
56static const char *parse_header( byte const in [], int size, struct file_t* out )
57{
58 if ( size < header_size )
59 return "wrong file type";
60
61 out->header = (struct header_t const*) in;
62 out->end = in + size;
63 struct header_t const* h = (struct header_t const*) in;
64 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) )
65 return "wrong file type";
66
67 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 );
68 if ( !out->tracks )
69 return "missing track data";
70
71 return 0;
72}
73
74static void copy_ay_fields( struct file_t const* file, struct mp3entry* id3, int track )
75{
76 int track_count = file->header->max_track + 1;
77
78 /* calculate track length based on number of subtracks */
79 if (track_count > 1) {
80 id3->length = file->header->max_track * 1000;
81 } else {
82 byte const* track_info = get_data( file, file->tracks + track * 4 + 2, 6 );
83 if (track_info)
84 id3->length = get_be16( track_info + 4 ) * (1000 / 50); /* frames to msec */
85 else id3->length = 120 * 1000;
86 }
87
88 if ( id3->length <= 0 )
89 id3->length = 120 * 1000; /* 2 minutes */
90
91 /* If meta info was found in the m3u skip next step */
92 if (id3->title && id3->title[0]) return;
93
94 /* If file has more than one track will
95 use file name as title */
96 char * tmp;
97 if (track_count <= 1) {
98 tmp = (char *) get_data( file, file->tracks + track * 4, 1 );
99 if ( tmp ) id3->title = tmp;
100 }
101
102 /* Author */
103 tmp = (char *) get_data( file, file->header->author, 1 );
104 if (tmp) id3->artist = tmp;
105
106 /* Comment */
107 tmp = (char *) get_data( file, file->header->comment, 1 );
108 if (tmp) id3->comment = tmp;
109}
110
111static bool parse_ay_header(int fd, struct mp3entry *id3)
112{
113 /* Use the trackname part of the id3 structure as a temporary buffer */
114 unsigned char* buf = (unsigned char *)id3->id3v2buf;
115 struct file_t file;
116 int read_bytes;
117
118 lseek(fd, 0, SEEK_SET);
119 if ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) < header_size)
120 return false;
121
122 buf [ID3V2_BUF_SIZE] = '\0';
123 if ( parse_header( buf, read_bytes, &file ) )
124 return false;
125
126 copy_ay_fields( &file, id3, 0 );
127 return true;
128}
129
130bool get_ay_metadata(int fd, struct mp3entry* id3)
131{
132 char ay_type[8];
133 if ((lseek(fd, 0, SEEK_SET) < 0) ||
134 read(fd, ay_type, 8) < 8)
135 return false;
136
137 id3->vbr = false;
138 id3->filesize = filesize(fd);
139
140 id3->bitrate = 706;
141 id3->frequency = 44100;
142
143 /* Make sure this is a ZX Ay file */
144 if (memcmp( ay_type, "ZXAYEMUL", 8 ) != 0)
145 return false;
146
147 return parse_ay_header(fd, id3);
148}
diff --git a/lib/rbcodec/metadata/flac.c b/lib/rbcodec/metadata/flac.c
new file mode 100644
index 0000000000..29937173fd
--- /dev/null
+++ b/lib/rbcodec/metadata/flac.c
@@ -0,0 +1,127 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33bool get_flac_metadata(int fd, struct mp3entry* id3)
34{
35 /* A simple parser to read vital metadata from a FLAC file - length,
36 * frequency, bitrate etc. This code should either be moved to a
37 * seperate file, or discarded in favour of the libFLAC code.
38 * The FLAC stream specification can be found at
39 * http://flac.sourceforge.net/format.html#stream
40 */
41
42 /* Use the trackname part of the id3 structure as a temporary buffer */
43 unsigned char* buf = (unsigned char *)id3->path;
44 bool last_metadata = false;
45 bool rc = false;
46
47 if (!skip_id3v2(fd, id3) || (read(fd, buf, 4) < 4))
48 {
49 return rc;
50 }
51
52 if (memcmp(buf, "fLaC", 4) != 0)
53 {
54 return rc;
55 }
56
57 while (!last_metadata)
58 {
59 unsigned long i;
60 int type;
61
62 if (read(fd, buf, 4) < 0)
63 {
64 return rc;
65 }
66
67 last_metadata = buf[0] & 0x80;
68 type = buf[0] & 0x7f;
69 /* The length of the block */
70 i = (buf[1] << 16) | (buf[2] << 8) | buf[3];
71
72 if (type == 0) /* 0 is the STREAMINFO block */
73 {
74 unsigned long totalsamples;
75
76 if (i >= sizeof(id3->path) || read(fd, buf, i) < 0)
77 {
78 return rc;
79 }
80
81 id3->vbr = true; /* All FLAC files are VBR */
82 id3->filesize = filesize(fd);
83 id3->frequency = (buf[10] << 12) | (buf[11] << 4)
84 | ((buf[12] & 0xf0) >> 4);
85 rc = true; /* Got vital metadata */
86
87 /* totalsamples is a 36-bit field, but we assume <= 32 bits are used */
88 totalsamples = get_long_be(&buf[14]);
89
90 if(totalsamples > 0)
91 {
92 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */
93 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
94 id3->bitrate = (id3->filesize * 8) / id3->length;
95 }
96 else if (totalsamples == 0)
97 {
98 id3->length = 0;
99 id3->bitrate = 0;
100 }
101 else
102 {
103 logf("flac length invalid!");
104 return false;
105 }
106
107 }
108 else if (type == 4) /* 4 is the VORBIS_COMMENT block */
109 {
110 /* The next i bytes of the file contain the VORBIS COMMENTS. */
111 if (read_vorbis_tags(fd, id3, i) == 0)
112 {
113 return rc;
114 }
115 }
116 else if (!last_metadata)
117 {
118 /* Skip to next metadata block */
119 if (lseek(fd, i, SEEK_CUR) < 0)
120 {
121 return rc;
122 }
123 }
124 }
125
126 return true;
127}
diff --git a/lib/rbcodec/metadata/gbs.c b/lib/rbcodec/metadata/gbs.c
new file mode 100644
index 0000000000..68f2b2a393
--- /dev/null
+++ b/lib/rbcodec/metadata/gbs.c
@@ -0,0 +1,65 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13static bool parse_gbs_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17 lseek(fd, 0, SEEK_SET);
18 if (read(fd, buf, 112) < 112)
19 return false;
20
21 /* Calculate track length with number of subtracks */
22 id3->length = buf[4] * 1000;
23
24 /* If meta info was found in the m3u skip next step */
25 if (id3->title && id3->title[0]) return true;
26
27 char *p = id3->id3v2buf;
28
29 /* Some metadata entries have 32 bytes length */
30 /* Game */
31 memcpy(p, &buf[16], 32); *(p + 33) = '\0';
32 id3->title = p;
33 p += strlen(p)+1;
34
35 /* Artist */
36 memcpy(p, &buf[48], 32); *(p + 33) = '\0';
37 id3->artist = p;
38 p += strlen(p)+1;
39
40 /* Copyright */
41 memcpy(p, &buf[80], 32); *(p + 33) = '\0';
42 id3->album = p;
43
44 return true;
45}
46
47bool get_gbs_metadata(int fd, struct mp3entry* id3)
48{
49 char gbs_type[3];
50 if ((lseek(fd, 0, SEEK_SET) < 0) ||
51 (read(fd, gbs_type, 3) < 3))
52 return false;
53
54 id3->vbr = false;
55 id3->filesize = filesize(fd);
56 /* we only render 16 bits, 44.1KHz, Stereo */
57 id3->bitrate = 706;
58 id3->frequency = 44100;
59
60 /* Check for GBS magic */
61 if (memcmp( gbs_type, "GBS", 3 ) != 0)
62 return false;
63
64 return parse_gbs_header(fd, id3);
65}
diff --git a/lib/rbcodec/metadata/hes.c b/lib/rbcodec/metadata/hes.c
new file mode 100644
index 0000000000..6d99d523cb
--- /dev/null
+++ b/lib/rbcodec/metadata/hes.c
@@ -0,0 +1,39 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12#include "plugin.h"
13
14bool get_hes_metadata(int fd, struct mp3entry* id3)
15{
16 /* Use the id3v2 buffer part of the id3 structure as a temporary buffer */
17 unsigned char* buf = (unsigned char *)id3->id3v2buf;
18 int read_bytes;
19
20 if ((lseek(fd, 0, SEEK_SET) < 0)
21 || ((read_bytes = read(fd, buf, 4)) < 4))
22 return false;
23
24 /* Verify this is a HES file */
25 if (memcmp(buf,"HESM",4) != 0)
26 return false;
27
28 id3->vbr = false;
29 id3->filesize = filesize(fd);
30 /* we only render 16 bits, 44.1KHz, Stereo */
31 id3->bitrate = 706;
32 id3->frequency = 44100;
33
34 /* Set default track count (length)*/
35 id3->length = 255 * 1000;
36
37 return true;
38}
39
diff --git a/lib/rbcodec/metadata/id3tags.c b/lib/rbcodec/metadata/id3tags.c
new file mode 100644
index 0000000000..2dd1c662ed
--- /dev/null
+++ b/lib/rbcodec/metadata/id3tags.c
@@ -0,0 +1,1199 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21/*
22 * Parts of this code has been stolen from the Ample project and was written
23 * by David H�deman. It has since been extended and enhanced pretty much by
24 * all sorts of friendly Rockbox people.
25 *
26 */
27
28 /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <errno.h>
35#include <stdbool.h>
36#include <stddef.h>
37#include <ctype.h>
38#include "string-extra.h"
39#include "config.h"
40#include "file.h"
41#include "logf.h"
42#include "system.h"
43#include "replaygain.h"
44#include "rbunicode.h"
45
46#include "metadata.h"
47#include "mp3data.h"
48#if CONFIG_CODEC == SWCODEC
49#include "metadata_common.h"
50#endif
51#include "metadata_parsers.h"
52#include "misc.h"
53
54static unsigned long unsync(unsigned long b0,
55 unsigned long b1,
56 unsigned long b2,
57 unsigned long b3)
58{
59 return (((long)(b0 & 0x7F) << (3*7)) |
60 ((long)(b1 & 0x7F) << (2*7)) |
61 ((long)(b2 & 0x7F) << (1*7)) |
62 ((long)(b3 & 0x7F) << (0*7)));
63}
64
65static const char* const genres[] = {
66 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
67 "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
68 "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
69 "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
70 "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
71 "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
72 "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
73 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
74 "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
75 "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
76 "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
77 "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
78 "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
79
80 /* winamp extensions */
81 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob",
82 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
83 "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
84 "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
85 "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
86 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
87 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
88 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
89 "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
90 "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap",
91 "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
92 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop",
93 "Synthpop"
94};
95
96#if CONFIG_CODEC != SWCODEC
97static
98#endif
99char* id3_get_num_genre(unsigned int genre_num)
100{
101 if (genre_num < ARRAYLEN(genres))
102 return (char*)genres[genre_num];
103 return NULL;
104}
105
106/*
107 HOW TO ADD ADDITIONAL ID3 VERSION 2 TAGS
108 Code and comments by Thomas Paul Diffenbach
109
110 To add another ID3v2 Tag, do the following:
111 1. add a char* named for the tag to struct mp3entry in id3.h,
112 (I (tpd) prefer to use char* rather than ints, even for what seems like
113 numerical values, for cases where a number won't do, e.g.,
114 YEAR: "circa 1765", "1790/1977" (composed/performed), "28 Feb 1969"
115 TRACK: "1/12", "1 of 12", GENRE: "Freeform genre name"
116 Text is more flexible, and as the main use of id3 data is to
117 display it, converting it to an int just means reconverting to
118 display it, at a runtime cost.)
119
120 2. If any special processing beyond copying the tag value from the Id3
121 block to the struct mp3entry is rrequired (such as converting to an
122 int), write a function to perform this special processing.
123
124 This function's prototype must match that of
125 typedef tagPostProcessFunc, that is it must be:
126 int func( struct mp3entry*, char* tag, int bufferpos )
127 the first argument is a pointer to the current mp3entry structure the
128 second argument is a pointer to the null terminated string value of the
129 tag found the third argument is the offset of the next free byte in the
130 mp3entry's buffer your function should return the corrected offset; if
131 you don't lengthen or shorten the tag string, you can return the third
132 argument unchanged.
133
134 Unless you have a good reason no to, make the function static.
135 TO JUST COPY THE TAG NO SPECIAL PROCESSING FUNCTION IS NEEDED.
136
137 3. add one or more entries to the tagList array, using the format:
138 char* ID3 Tag symbolic name -- see the ID3 specification for these,
139 sizeof() that name minus 1,
140 offsetof( struct mp3entry, variable_name_in_struct_mp3entry ),
141 pointer to your special processing function or NULL
142 if you need no special processing
143 flag indicating if this tag is binary or textual
144 Many ID3 symbolic names come in more than one form. You can add both
145 forms, each referencing the same variable in struct mp3entry.
146 If both forms are present, the last found will be used.
147 Note that the offset can be zero, in which case no entry will be set
148 in the mp3entry struct; the frame is still read into the buffer and
149 the special processing function is called (several times, if there
150 are several frames with the same name).
151
152 4. Alternately, use the TAG_LIST_ENTRY macro with
153 ID3 tag symbolic name,
154 variable in struct mp3entry,
155 special processing function address
156
157 5. Add code to wps-display.c function get_tag to assign a printf-like
158 format specifier for the tag */
159
160/* Structure for ID3 Tag extraction information */
161struct tag_resolver {
162 const char* tag;
163 int tag_length;
164 size_t offset;
165 int (*ppFunc)(struct mp3entry*, char* tag, int bufferpos);
166 bool binary;
167};
168
169static bool global_ff_found;
170
171static int unsynchronize(char* tag, int len, bool *ff_found)
172{
173 int i;
174 unsigned char c;
175 unsigned char *rp, *wp;
176
177 wp = rp = (unsigned char *)tag;
178
179 rp = (unsigned char *)tag;
180 for(i = 0;i < len;i++) {
181 /* Read the next byte and write it back, but don't increment the
182 write pointer */
183 c = *rp++;
184 *wp = c;
185 if(*ff_found) {
186 /* Increment the write pointer if it isn't an unsynch pattern */
187 if(c != 0)
188 wp++;
189 *ff_found = false;
190 } else {
191 if(c == 0xff)
192 *ff_found = true;
193 wp++;
194 }
195 }
196 return (long)wp - (long)tag;
197}
198
199static int unsynchronize_frame(char* tag, int len)
200{
201 bool ff_found = false;
202
203 return unsynchronize(tag, len, &ff_found);
204}
205
206static int read_unsynched(int fd, void *buf, int len)
207{
208 int i;
209 int rc;
210 int remaining = len;
211 char *wp;
212 char *rp;
213
214 wp = buf;
215
216 while(remaining) {
217 rp = wp;
218 rc = read(fd, rp, remaining);
219 if(rc <= 0)
220 return rc;
221
222 i = unsynchronize(wp, remaining, &global_ff_found);
223 remaining -= i;
224 wp += i;
225 }
226
227 return len;
228}
229
230static int skip_unsynched(int fd, int len)
231{
232 int rc;
233 int remaining = len;
234 int rlen;
235 char buf[32];
236
237 while(remaining) {
238 rlen = MIN(sizeof(buf), (unsigned int)remaining);
239 rc = read(fd, buf, rlen);
240 if(rc <= 0)
241 return rc;
242
243 remaining -= unsynchronize(buf, rlen, &global_ff_found);
244 }
245
246 return len;
247}
248
249/* parse numeric value from string */
250static int parsetracknum( struct mp3entry* entry, char* tag, int bufferpos )
251{
252 entry->tracknum = atoi( tag );
253 return bufferpos;
254}
255
256/* parse numeric value from string */
257static int parsediscnum( struct mp3entry* entry, char* tag, int bufferpos )
258{
259 entry->discnum = atoi( tag );
260 return bufferpos;
261}
262
263/* parse numeric value from string */
264static int parseyearnum( struct mp3entry* entry, char* tag, int bufferpos )
265{
266 entry->year = atoi( tag );
267 return bufferpos;
268}
269
270/* parse numeric genre from string, version 2.2 and 2.3 */
271static int parsegenre( struct mp3entry* entry, char* tag, int bufferpos )
272{
273 /* Use bufferpos to hold current position in entry->id3v2buf. */
274 bufferpos = tag - entry->id3v2buf;
275
276 if(entry->id3version >= ID3_VER_2_4) {
277 /* In version 2.4 and up, there are no parentheses, and the genre frame
278 is a list of strings, either numbers or text. */
279
280 /* Is it a number? */
281 if(isdigit(tag[0])) {
282 entry->genre_string = id3_get_num_genre(atoi( tag ));
283 return bufferpos;
284 } else {
285 entry->genre_string = tag;
286 return bufferpos + strlen(tag) + 1;
287 }
288 } else {
289 if( tag[0] == '(' && tag[1] != '(' ) {
290 entry->genre_string = id3_get_num_genre(atoi( tag + 1 ));
291 return bufferpos;
292 }
293 else {
294 entry->genre_string = tag;
295 return bufferpos + strlen(tag) + 1;
296 }
297 }
298}
299
300#ifdef HAVE_ALBUMART
301/* parse embed albumart */
302static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos )
303{
304 entry->has_embedded_albumart = false;
305
306 /* we currently don't support unsynchronizing albumart */
307 if (entry->albumart.type == AA_TYPE_UNSYNC)
308 return bufferpos;
309
310 entry->albumart.type = AA_TYPE_UNKNOWN;
311
312 char *start = tag;
313 /* skip text encoding */
314 tag += 1;
315
316 if (memcmp(tag, "image/", 6) == 0)
317 {
318 /* ID3 v2.3+ */
319 tag += 6;
320 if (strcmp(tag, "jpeg") == 0)
321 {
322 entry->albumart.type = AA_TYPE_JPG;
323 tag += 5;
324 }
325 else if (strcmp(tag, "png") == 0)
326 {
327 entry->albumart.type = AA_TYPE_PNG;
328 tag += 4;
329 }
330 }
331 else
332 {
333 /* ID3 v2.2 */
334 if (memcmp(tag, "JPG", 3) == 0)
335 entry->albumart.type = AA_TYPE_JPG;
336 else if (memcmp(tag, "PNG", 3) == 0)
337 entry->albumart.type = AA_TYPE_PNG;
338 tag += 3;
339 }
340
341 if (entry->albumart.type != AA_TYPE_UNKNOWN)
342 {
343 /* skip picture type */
344 tag += 1;
345 /* skip description */
346 tag = strchr(tag, '\0') + 1;
347 /* fixup offset&size for image data */
348 entry->albumart.pos += tag - start;
349 entry->albumart.size -= tag - start;
350 entry->has_embedded_albumart = true;
351 }
352 /* return bufferpos as we didn't store anything in id3v2buf */
353 return bufferpos;
354}
355#endif
356
357/* parse user defined text, looking for album artist and replaygain
358 * information.
359 */
360static int parseuser( struct mp3entry* entry, char* tag, int bufferpos )
361{
362 char* value = NULL;
363 int desc_len = strlen(tag);
364 int length = 0;
365
366 if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) {
367 /* At least part of the value was read, so we can safely try to
368 * parse it */
369 value = tag + desc_len + 1;
370
371 if (!strcasecmp(tag, "ALBUM ARTIST")) {
372 length = strlen(value) + 1;
373 strlcpy(tag, value, length);
374 entry->albumartist = tag;
375#if CONFIG_CODEC == SWCODEC
376 } else {
377 /* Call parse_replaygain(). */
378 parse_replaygain(tag, value, entry);
379#endif
380 }
381 }
382
383 return tag - entry->id3v2buf + length;
384}
385
386#if CONFIG_CODEC == SWCODEC
387/* parse RVA2 binary data and convert to replaygain information. */
388static int parserva2( struct mp3entry* entry, char* tag, int bufferpos)
389{
390 int desc_len = strlen(tag);
391 int start_pos = tag - entry->id3v2buf;
392 int end_pos = start_pos + desc_len + 5;
393 unsigned char* value = tag + desc_len + 1;
394
395 /* Only parse RVA2 replaygain tags if tag version == 2.4 and channel
396 * type is master volume.
397 */
398 if (entry->id3version == ID3_VER_2_4 && end_pos < bufferpos
399 && *value++ == 1) {
400 long gain = 0;
401 long peak = 0;
402 long peakbits;
403 long peakbytes;
404 bool album = false;
405
406 /* The RVA2 specification is unclear on some things (id string and
407 * peak volume), but this matches how Quod Libet use them.
408 */
409
410 gain = (int16_t) ((value[0] << 8) | value[1]);
411 value += 2;
412 peakbits = *value++;
413 peakbytes = (peakbits + 7) / 8;
414
415 /* Only use the topmost 24 bits for peak volume */
416 if (peakbytes > 3) {
417 peakbytes = 3;
418 }
419
420 /* Make sure the peak bits were read */
421 if (end_pos + peakbytes < bufferpos) {
422 long shift = ((8 - (peakbits & 7)) & 7) + (3 - peakbytes) * 8;
423
424 for ( ; peakbytes; peakbytes--) {
425 peak <<= 8;
426 peak += *value++;
427 }
428
429 peak <<= shift;
430
431 if (peakbits > 24) {
432 peak += *value >> (8 - shift);
433 }
434 }
435
436 if (strcasecmp(tag, "album") == 0) {
437 album = true;
438 } else if (strcasecmp(tag, "track") != 0) {
439 /* Only accept non-track values if we don't have any previous
440 * value.
441 */
442 if (entry->track_gain != 0) {
443 return start_pos;
444 }
445 }
446
447 parse_replaygain_int(album, gain, peak * 2, entry);
448 }
449
450 return start_pos;
451}
452#endif
453
454static int parsembtid( struct mp3entry* entry, char* tag, int bufferpos )
455{
456 char* value = NULL;
457 int desc_len = strlen(tag);
458 /*DEBUGF("MBID len: %d\n", desc_len);*/
459 /* Musicbrainz track IDs are always 36 chars long */
460 const size_t mbtid_len = 36;
461
462 if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos)
463 {
464 value = tag + desc_len + 1;
465
466 if (strcasecmp(tag, "http://musicbrainz.org") == 0)
467 {
468 if (mbtid_len == strlen(value))
469 {
470 entry->mb_track_id = value;
471 return bufferpos + mbtid_len + 1;
472 }
473 }
474 }
475
476 return bufferpos;
477}
478
479static const struct tag_resolver taglist[] = {
480 { "TPE1", 4, offsetof(struct mp3entry, artist), NULL, false },
481 { "TP1", 3, offsetof(struct mp3entry, artist), NULL, false },
482 { "TIT2", 4, offsetof(struct mp3entry, title), NULL, false },
483 { "TT2", 3, offsetof(struct mp3entry, title), NULL, false },
484 { "TALB", 4, offsetof(struct mp3entry, album), NULL, false },
485 { "TAL", 3, offsetof(struct mp3entry, album), NULL, false },
486 { "TRK", 3, offsetof(struct mp3entry, track_string), &parsetracknum, false },
487 { "TPOS", 4, offsetof(struct mp3entry, disc_string), &parsediscnum, false },
488 { "TPA", 3, offsetof(struct mp3entry, disc_string), &parsediscnum, false },
489 { "TRCK", 4, offsetof(struct mp3entry, track_string), &parsetracknum, false },
490 { "TDRC", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false },
491 { "TYER", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false },
492 { "TYE", 3, offsetof(struct mp3entry, year_string), &parseyearnum, false },
493 { "TCOM", 4, offsetof(struct mp3entry, composer), NULL, false },
494 { "TCM", 3, offsetof(struct mp3entry, composer), NULL, false },
495 { "TPE2", 4, offsetof(struct mp3entry, albumartist), NULL, false },
496 { "TP2", 3, offsetof(struct mp3entry, albumartist), NULL, false },
497 { "TIT1", 4, offsetof(struct mp3entry, grouping), NULL, false },
498 { "TT1", 3, offsetof(struct mp3entry, grouping), NULL, false },
499 { "COMM", 4, offsetof(struct mp3entry, comment), NULL, false },
500 { "COM", 3, offsetof(struct mp3entry, comment), NULL, false },
501 { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false },
502 { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false },
503#ifdef HAVE_ALBUMART
504 { "APIC", 4, 0, &parsealbumart, true },
505 { "PIC", 3, 0, &parsealbumart, true },
506#endif
507 { "TXXX", 4, 0, &parseuser, false },
508#if CONFIG_CODEC == SWCODEC
509 { "RVA2", 4, 0, &parserva2, true },
510#endif
511 { "UFID", 4, 0, &parsembtid, false },
512};
513
514#define TAGLIST_SIZE ((int)ARRAYLEN(taglist))
515
516/* Get the length of an ID3 string in the given encoding. Returns the length
517 * in bytes, including end nil, or -1 if the encoding is unknown.
518 */
519static int unicode_len(char encoding, const void* string)
520{
521 int len = 0;
522
523 if (encoding == 0x01 || encoding == 0x02) {
524 char first;
525 const char *s = string;
526 /* string might be unaligned, so using short* can crash on ARM and SH1 */
527 do {
528 first = *s++;
529 } while ((first | *s++) != 0);
530
531 len = s - (const char*) string;
532 } else {
533 len = strlen((char*) string) + 1;
534 }
535
536 return len;
537}
538
539/* Checks to see if the passed in string is a 16-bit wide Unicode v2
540 string. If it is, we convert it to a UTF-8 string. If it's not unicode,
541 we convert from the default codepage */
542static int unicode_munge(char* string, char* utf8buf, int *len) {
543 long tmp;
544 bool le = false;
545 int i = 0;
546 unsigned char *str = (unsigned char *)string;
547 int templen = 0;
548 unsigned char* utf8 = (unsigned char *)utf8buf;
549
550 switch (str[0]) {
551 case 0x00: /* Type 0x00 is ordinary ISO 8859-1 */
552 str++;
553 (*len)--;
554 utf8 = iso_decode(str, utf8, -1, *len);
555 *utf8 = 0;
556 *len = (unsigned long)utf8 - (unsigned long)utf8buf;
557 break;
558
559 case 0x01: /* Unicode with or without BOM */
560 case 0x02:
561 (*len)--;
562 str++;
563
564 /* Handle frames with more than one string
565 (needed for TXXX frames).*/
566 do {
567 tmp = bytes2int(0, 0, str[0], str[1]);
568
569 /* Now check if there is a BOM
570 (zero-width non-breaking space, 0xfeff)
571 and if it is in little or big endian format */
572 if(tmp == 0xfffe) { /* Little endian? */
573 le = true;
574 str += 2;
575 (*len)-=2;
576 } else if(tmp == 0xfeff) { /* Big endian? */
577 str += 2;
578 (*len)-=2;
579 } else
580 /* If there is no BOM (which is a specification violation),
581 let's try to guess it. If one of the bytes is 0x00, it is
582 probably the most significant one. */
583 if(str[1] == 0)
584 le = true;
585
586 while ((i < *len) && (str[0] || str[1])) {
587 if(le)
588 utf8 = utf16LEdecode(str, utf8, 1);
589 else
590 utf8 = utf16BEdecode(str, utf8, 1);
591
592 str+=2;
593 i += 2;
594 }
595
596 *utf8++ = 0; /* Terminate the string */
597 templen += (strlen(&utf8buf[templen]) + 1);
598 str += 2;
599 i+=2;
600 } while(i < *len);
601 *len = templen - 1;
602 break;
603
604 case 0x03: /* UTF-8 encoded string */
605 for(i=0; i < *len; i++)
606 utf8[i] = str[i+1];
607 (*len)--;
608 break;
609
610 default: /* Plain old string */
611 utf8 = iso_decode(str, utf8, -1, *len);
612 *utf8 = 0;
613 *len = (unsigned long)utf8 - (unsigned long)utf8buf;
614 break;
615 }
616 return 0;
617}
618
619/*
620 * Sets the title of an MP3 entry based on its ID3v1 tag.
621 *
622 * Arguments: file - the MP3 file to scen for a ID3v1 tag
623 * entry - the entry to set the title in
624 *
625 * Returns: true if a title was found and created, else false
626 */
627bool setid3v1title(int fd, struct mp3entry *entry)
628{
629 unsigned char buffer[128];
630 static const char offsets[] = {3, 33, 63, 97, 93, 125, 127};
631 int i, j;
632 unsigned char* utf8;
633
634 if (-1 == lseek(fd, -128, SEEK_END))
635 return false;
636
637 if (read(fd, buffer, sizeof buffer) != sizeof buffer)
638 return false;
639
640 if (strncmp((char *)buffer, "TAG", 3))
641 return false;
642
643 entry->id3v1len = 128;
644 entry->id3version = ID3_VER_1_0;
645
646 for (i=0; i < (int)sizeof offsets; i++) {
647 unsigned char* ptr = (unsigned char *)buffer + offsets[i];
648
649 switch(i) {
650 case 0:
651 case 1:
652 case 2:
653 /* kill trailing space in strings */
654 for (j=29; j && (ptr[j]==0 || ptr[j]==' '); j--)
655 ptr[j] = 0;
656 /* convert string to utf8 */
657 utf8 = (unsigned char *)entry->id3v1buf[i];
658 utf8 = iso_decode(ptr, utf8, -1, 30);
659 /* make sure string is terminated */
660 *utf8 = 0;
661 break;
662
663 case 3:
664 /* kill trailing space in strings */
665 for (j=27; j && (ptr[j]==0 || ptr[j]==' '); j--)
666 ptr[j] = 0;
667 /* convert string to utf8 */
668 utf8 = (unsigned char *)entry->id3v1buf[3];
669 utf8 = iso_decode(ptr, utf8, -1, 28);
670 /* make sure string is terminated */
671 *utf8 = 0;
672 break;
673
674 case 4:
675 ptr[4] = 0;
676 entry->year = atoi((char *)ptr);
677 break;
678
679 case 5:
680 /* id3v1.1 uses last two bytes of comment field for track
681 number: first must be 0 and second is track num */
682 if (!ptr[0] && ptr[1]) {
683 entry->tracknum = ptr[1];
684 entry->id3version = ID3_VER_1_1;
685 }
686 break;
687
688 case 6:
689 /* genre */
690 entry->genre_string = id3_get_num_genre(ptr[0]);
691 break;
692 }
693 }
694
695 entry->title = entry->id3v1buf[0];
696 entry->artist = entry->id3v1buf[1];
697 entry->album = entry->id3v1buf[2];
698 entry->comment = entry->id3v1buf[3];
699
700 return true;
701}
702
703
704/*
705 * Sets the title of an MP3 entry based on its ID3v2 tag.
706 *
707 * Arguments: file - the MP3 file to scan for a ID3v2 tag
708 * entry - the entry to set the title in
709 *
710 * Returns: true if a title was found and created, else false
711 */
712void setid3v2title(int fd, struct mp3entry *entry)
713{
714 int minframesize;
715 int size;
716 long bufferpos = 0, totframelen, framelen;
717 char header[10];
718 char tmp[4];
719 unsigned char version;
720 char *buffer = entry->id3v2buf;
721 int bytesread = 0;
722 int buffersize = sizeof(entry->id3v2buf);
723 unsigned char global_flags;
724 int flags;
725 bool global_unsynch = false;
726 bool unsynch = false;
727 int i, j;
728 int rc;
729#if CONFIG_CODEC == SWCODEC
730 bool itunes_gapless = false;
731#endif
732
733 global_ff_found = false;
734
735 /* Bail out if the tag is shorter than 10 bytes */
736 if(entry->id3v2len < 10)
737 return;
738
739 /* Read the ID3 tag version from the header */
740 lseek(fd, 0, SEEK_SET);
741 if(10 != read(fd, header, 10))
742 return;
743
744 /* Get the total ID3 tag size */
745 size = entry->id3v2len - 10;
746
747 version = header[3];
748 switch ( version ) {
749 case 2:
750 version = ID3_VER_2_2;
751 minframesize = 8;
752 break;
753
754 case 3:
755 version = ID3_VER_2_3;
756 minframesize = 12;
757 break;
758
759 case 4:
760 version = ID3_VER_2_4;
761 minframesize = 12;
762 break;
763
764 default:
765 /* unsupported id3 version */
766 return;
767 }
768 entry->id3version = version;
769 entry->tracknum = entry->year = entry->discnum = 0;
770 entry->title = entry->artist = entry->album = NULL; /* FIXME incomplete */
771
772 global_flags = header[5];
773
774 /* Skip the extended header if it is present */
775 if(global_flags & 0x40) {
776 if(version == ID3_VER_2_3) {
777 if(10 != read(fd, header, 10))
778 return;
779 /* The 2.3 extended header size doesn't include the header size
780 field itself. Also, it is not unsynched. */
781 framelen =
782 bytes2int(header[0], header[1], header[2], header[3]) + 4;
783
784 /* Skip the rest of the header */
785 lseek(fd, framelen - 10, SEEK_CUR);
786 }
787
788 if(version >= ID3_VER_2_4) {
789 if(4 != read(fd, header, 4))
790 return;
791
792 /* The 2.4 extended header size does include the entire header,
793 so here we can just skip it. This header is unsynched. */
794 framelen = unsync(header[0], header[1],
795 header[2], header[3]);
796
797 lseek(fd, framelen - 4, SEEK_CUR);
798 }
799 }
800
801 /* Is unsynchronization applied? */
802 if(global_flags & 0x80) {
803 global_unsynch = true;
804 }
805
806 /*
807 * We must have at least minframesize bytes left for the
808 * remaining frames to be interesting
809 */
810 while (size >= minframesize && bufferpos < buffersize - 1) {
811 flags = 0;
812
813 /* Read frame header and check length */
814 if(version >= ID3_VER_2_3) {
815 if(global_unsynch && version <= ID3_VER_2_3)
816 rc = read_unsynched(fd, header, 10);
817 else
818 rc = read(fd, header, 10);
819 if(rc != 10)
820 return;
821 /* Adjust for the 10 bytes we read */
822 size -= 10;
823
824 flags = bytes2int(0, 0, header[8], header[9]);
825
826 if (version >= ID3_VER_2_4) {
827 framelen = unsync(header[4], header[5],
828 header[6], header[7]);
829 } else {
830 /* version .3 files don't use synchsafe ints for
831 * size */
832 framelen = bytes2int(header[4], header[5],
833 header[6], header[7]);
834 }
835 } else {
836 if(6 != read(fd, header, 6))
837 return;
838 /* Adjust for the 6 bytes we read */
839 size -= 6;
840
841 framelen = bytes2int(0, header[3], header[4], header[5]);
842 }
843
844 logf("framelen = %ld, flags = 0x%04x", framelen, flags);
845 if(framelen == 0){
846 if (header[0] == 0 && header[1] == 0 && header[2] == 0)
847 return;
848 else
849 continue;
850 }
851
852 unsynch = false;
853
854 if(flags)
855 {
856 if (version >= ID3_VER_2_4) {
857 if(flags & 0x0040) { /* Grouping identity */
858 lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
859 framelen--;
860 }
861 } else {
862 if(flags & 0x0020) { /* Grouping identity */
863 lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
864 framelen--;
865 }
866 }
867
868 if(flags & 0x000c) /* Compression or encryption */
869 {
870 /* Skip it */
871 size -= framelen;
872 lseek(fd, framelen, SEEK_CUR);
873 continue;
874 }
875
876 if(flags & 0x0002) /* Unsynchronization */
877 unsynch = true;
878
879 if (version >= ID3_VER_2_4) {
880 if(flags & 0x0001) { /* Data length indicator */
881 if(4 != read(fd, tmp, 4))
882 return;
883
884 /* We don't need the data length */
885 framelen -= 4;
886 }
887 }
888 }
889
890 if (framelen == 0)
891 continue;
892
893 if (framelen < 0)
894 return;
895
896 /* Keep track of the remaining frame size */
897 totframelen = framelen;
898
899 /* If the frame is larger than the remaining buffer space we try
900 to read as much as would fit in the buffer */
901 if(framelen >= buffersize - bufferpos)
902 framelen = buffersize - bufferpos - 1;
903
904 /* Limit the maximum length of an id3 data item to ID3V2_MAX_ITEM_SIZE
905 bytes. This reduces the chance that the available buffer is filled
906 by single metadata items like large comments. */
907 if (ID3V2_MAX_ITEM_SIZE < framelen)
908 framelen = ID3V2_MAX_ITEM_SIZE;
909
910 logf("id3v2 frame: %.4s", header);
911
912 /* Check for certain frame headers
913
914 'size' is the amount of frame bytes remaining. We decrement it by
915 the amount of bytes we read. If we fail to read as many bytes as
916 we expect, we assume that we can't read from this file, and bail
917 out.
918
919 For each frame. we will iterate over the list of supported tags,
920 and read the tag into entry's buffer. All tags will be kept as
921 strings, for cases where a number won't do, e.g., YEAR: "circa
922 1765", "1790/1977" (composed/performed), "28 Feb 1969" TRACK:
923 "1/12", "1 of 12", GENRE: "Freeform genre name" Text is more
924 flexible, and as the main use of id3 data is to display it,
925 converting it to an int just means reconverting to display it, at a
926 runtime cost.
927
928 For tags that the current code does convert to ints, a post
929 processing function will be called via a pointer to function. */
930
931 for (i=0; i<TAGLIST_SIZE; i++) {
932 const struct tag_resolver* tr = &taglist[i];
933 char** ptag = tr->offset ? (char**) (((char*)entry) + tr->offset)
934 : NULL;
935 char* tag;
936
937 /* Only ID3_VER_2_2 uses frames with three-character names. */
938 if (((version == ID3_VER_2_2) && (tr->tag_length != 3))
939 || ((version > ID3_VER_2_2) && (tr->tag_length != 4))) {
940 continue;
941 }
942
943 if( !memcmp( header, tr->tag, tr->tag_length ) ) {
944
945 /* found a tag matching one in tagList, and not yet filled */
946 tag = buffer + bufferpos;
947
948 if(global_unsynch && version <= ID3_VER_2_3)
949 bytesread = read_unsynched(fd, tag, framelen);
950 else
951 bytesread = read(fd, tag, framelen);
952
953 if( bytesread != framelen )
954 return;
955
956 size -= bytesread;
957
958 if(unsynch || (global_unsynch && version >= ID3_VER_2_4))
959 bytesread = unsynchronize_frame(tag, bytesread);
960
961 /* the COMM frame has a 3 char field to hold an ISO-639-1
962 * language string and an optional short description;
963 * remove them so unicode_munge can work correctly
964 */
965
966 if((tr->tag_length == 4 && !memcmp( header, "COMM", 4)) ||
967 (tr->tag_length == 3 && !memcmp( header, "COM", 3))) {
968 int offset;
969 if(bytesread >= 8 && !strncmp(tag+4, "iTun", 4)) {
970#if CONFIG_CODEC == SWCODEC
971 /* check for iTunes gapless information */
972 if(bytesread >= 12 && !strncmp(tag+4, "iTunSMPB", 8))
973 itunes_gapless = true;
974 else
975#endif
976 /* ignore other with iTunes tags */
977 break;
978 }
979
980 offset = 3 + unicode_len(*tag, tag + 4);
981 if(bytesread > offset) {
982 bytesread -= offset;
983 memmove(tag + 1, tag + 1 + offset, bytesread - 1);
984 }
985 }
986
987 /* Attempt to parse Unicode string only if the tag contents
988 aren't binary */
989 if(!tr->binary) {
990 /* UTF-8 could potentially be 3 times larger */
991 /* so we need to create a new buffer */
992 char utf8buf[(3 * bytesread) + 1];
993
994 unicode_munge( tag, utf8buf, &bytesread );
995
996 if(bytesread >= buffersize - bufferpos)
997 bytesread = buffersize - bufferpos - 1;
998
999 if ( /* Is it an embedded cuesheet? */
1000 (tr->tag_length == 4 && !memcmp(header, "TXXX", 4)) &&
1001 (bytesread >= 14 && !strncmp(utf8buf, "CUESHEET", 8))
1002 ) {
1003 unsigned char char_enc = 0;
1004 /* [enc type]+"CUESHEET\0" = 10 */
1005 unsigned char cuesheet_offset = 10;
1006 switch (tag[0]) {
1007 case 0x00:
1008 char_enc = CHAR_ENC_ISO_8859_1;
1009 break;
1010 case 0x01:
1011 tag++;
1012 if (!memcmp(tag,
1013 BOM_UTF_16_BE, BOM_UTF_16_SIZE)) {
1014 char_enc = CHAR_ENC_UTF_16_BE;
1015 } else if (!memcmp(tag,
1016 BOM_UTF_16_LE, BOM_UTF_16_SIZE)) {
1017 char_enc = CHAR_ENC_UTF_16_LE;
1018 }
1019 /* \1 + BOM(2) + C0U0E0S0H0E0E0T000 = 21 */
1020 cuesheet_offset = 21;
1021 break;
1022 case 0x02:
1023 char_enc = CHAR_ENC_UTF_16_BE;
1024 /* \2 + 0C0U0E0S0H0E0E0T00 = 19 */
1025 cuesheet_offset = 19;
1026 break;
1027 case 0x03:
1028 char_enc = CHAR_ENC_UTF_8;
1029 break;
1030 }
1031 if (char_enc > 0) {
1032 entry->has_embedded_cuesheet = true;
1033 entry->embedded_cuesheet.pos = lseek(fd, 0, SEEK_CUR)
1034 - framelen + cuesheet_offset;
1035 entry->embedded_cuesheet.size = totframelen
1036 - cuesheet_offset;
1037 entry->embedded_cuesheet.encoding = char_enc;
1038 }
1039 break;
1040 }
1041
1042 for (j = 0; j < bytesread; j++)
1043 tag[j] = utf8buf[j];
1044
1045 /* remove trailing spaces */
1046 while ( bytesread > 0 && isspace(tag[bytesread-1]))
1047 bytesread--;
1048 }
1049
1050 if(bytesread == 0)
1051 /* Skip empty frames */
1052 break;
1053
1054 tag[bytesread] = 0;
1055 bufferpos += bytesread + 1;
1056
1057#if CONFIG_CODEC == SWCODEC
1058 /* parse the tag if it contains iTunes gapless info */
1059 if (itunes_gapless)
1060 {
1061 itunes_gapless = false;
1062 entry->lead_trim = get_itunes_int32(tag, 1);
1063 entry->tail_trim = get_itunes_int32(tag, 2);
1064 }
1065#endif
1066
1067 /* Note that parser functions sometimes set *ptag to NULL, so
1068 * the "!*ptag" check here doesn't always have the desired
1069 * effect. Should the parser functions (parsegenre in
1070 * particular) be updated to handle the case of being called
1071 * multiple times, or should the "*ptag" check be removed?
1072 */
1073 if (ptag && !*ptag)
1074 *ptag = tag;
1075
1076#ifdef HAVE_ALBUMART
1077 /* albumart */
1078 if ((!entry->has_embedded_albumart) &&
1079 ((tr->tag_length == 4 && !memcmp( header, "APIC", 4)) ||
1080 (tr->tag_length == 3 && !memcmp( header, "PIC" , 3))))
1081 {
1082 if (unsynch || (global_unsynch && version <= ID3_VER_2_3))
1083 entry->albumart.type = AA_TYPE_UNSYNC;
1084 else
1085 {
1086 entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen;
1087 entry->albumart.size = totframelen;
1088 entry->albumart.type = AA_TYPE_UNKNOWN;
1089 }
1090 }
1091#endif
1092 if( tr->ppFunc )
1093 bufferpos = tr->ppFunc(entry, tag, bufferpos);
1094 break;
1095 }
1096 }
1097
1098 if( i == TAGLIST_SIZE ) {
1099 /* no tag in tagList was found, or it was a repeat.
1100 skip it using the total size */
1101
1102 if(global_unsynch && version <= ID3_VER_2_3) {
1103 size -= skip_unsynched(fd, totframelen);
1104 } else {
1105 size -= totframelen;
1106 if( lseek(fd, totframelen, SEEK_CUR) == -1 )
1107 return;
1108 }
1109 } else {
1110 /* Seek to the next frame */
1111 if(framelen < totframelen)
1112 lseek(fd, totframelen - framelen, SEEK_CUR);
1113 }
1114 }
1115}
1116
1117/*
1118 * Calculates the size of the ID3v2 tag.
1119 *
1120 * Arguments: file - the file to search for a tag.
1121 *
1122 * Returns: the size of the tag or 0 if none was found
1123 */
1124int getid3v2len(int fd)
1125{
1126 char buf[6];
1127 int offset;
1128
1129 /* Make sure file has a ID3 tag */
1130 if((-1 == lseek(fd, 0, SEEK_SET)) ||
1131 (read(fd, buf, 6) != 6) ||
1132 (strncmp(buf, "ID3", strlen("ID3")) != 0))
1133 offset = 0;
1134
1135 /* Now check what the ID3v2 size field says */
1136 else
1137 if(read(fd, buf, 4) != 4)
1138 offset = 0;
1139 else
1140 offset = unsync(buf[0], buf[1], buf[2], buf[3]) + 10;
1141
1142 logf("ID3V2 Length: 0x%x", offset);
1143 return offset;
1144}
1145
1146#ifdef DEBUG_STANDALONE
1147
1148char *secs2str(int ms)
1149{
1150 static char buffer[32];
1151 int secs = ms/1000;
1152 ms %= 1000;
1153 snprintf(buffer, sizeof(buffer), "%d:%02d.%d", secs/60, secs%60, ms/100);
1154 return buffer;
1155}
1156
1157int main(int argc, char **argv)
1158{
1159 int i;
1160 for(i=1; i<argc; i++) {
1161 struct mp3entry mp3;
1162 mp3.album = "Bogus";
1163 if(mp3info(&mp3, argv[i], false)) {
1164 printf("Failed to get %s\n", argv[i]);
1165 return 0;
1166 }
1167
1168 printf("****** File: %s\n"
1169 " Title: %s\n"
1170 " Artist: %s\n"
1171 " Album: %s\n"
1172 " Genre: %s (%d) \n"
1173 " Composer: %s\n"
1174 " Year: %s (%d)\n"
1175 " Track: %s (%d)\n"
1176 " Length: %s / %d s\n"
1177 " Bitrate: %d\n"
1178 " Frequency: %d\n",
1179 argv[i],
1180 mp3.title?mp3.title:"<blank>",
1181 mp3.artist?mp3.artist:"<blank>",
1182 mp3.album?mp3.album:"<blank>",
1183 mp3.genre_string?mp3.genre_string:"<blank>",
1184 mp3.genre,
1185 mp3.composer?mp3.composer:"<blank>",
1186 mp3.year_string?mp3.year_string:"<blank>",
1187 mp3.year,
1188 mp3.track_string?mp3.track_string:"<blank>",
1189 mp3.tracknum,
1190 secs2str(mp3.length),
1191 mp3.length/1000,
1192 mp3.bitrate,
1193 mp3.frequency);
1194 }
1195
1196 return 0;
1197}
1198
1199#endif
diff --git a/lib/rbcodec/metadata/kss.c b/lib/rbcodec/metadata/kss.c
new file mode 100644
index 0000000000..2ae0cf50b0
--- /dev/null
+++ b/lib/rbcodec/metadata/kss.c
@@ -0,0 +1,53 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13static bool parse_kss_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17
18 lseek(fd, 0, SEEK_SET);
19 if (read(fd, buf, 0x20) < 0x20)
20 return false;
21
22 /* calculate track length with number of tracks */
23 id3->length = 0;
24 if (buf[14] == 0x10) {
25 id3->length = (get_short_le((void *)(buf + 26)) + 1) * 1000;
26 }
27
28 if (id3->length <= 0)
29 id3->length = 255 * 1000; /* 255 tracks */
30
31 return true;
32}
33
34
35bool get_kss_metadata(int fd, struct mp3entry* id3)
36{
37 uint32_t kss_type;
38 if ((lseek(fd, 0, SEEK_SET) < 0) ||
39 read_uint32be(fd, &kss_type) != (int)sizeof(kss_type))
40 return false;
41
42 id3->vbr = false;
43 id3->filesize = filesize(fd);
44 /* we only render 16 bits, 44.1KHz, Stereo */
45 id3->bitrate = 706;
46 id3->frequency = 44100;
47
48 /* Make sure this is an SGC file */
49 if (kss_type != FOURCC('K','S','C','C') && kss_type != FOURCC('K','S','S','X'))
50 return false;
51
52 return parse_kss_header(fd, id3);
53}
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c
new file mode 100644
index 0000000000..b91e00cc4e
--- /dev/null
+++ b/lib/rbcodec/metadata/metadata.c
@@ -0,0 +1,641 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include "string-extra.h"
25
26#include "debug.h"
27#include "logf.h"
28#include "settings.h"
29#include "cuesheet.h"
30#include "metadata.h"
31
32#include "metadata_parsers.h"
33
34#if CONFIG_CODEC == SWCODEC
35
36/* For trailing tag stripping and base audio data types */
37#include "buffering.h"
38
39#include "metadata/metadata_common.h"
40
41static bool get_shn_metadata(int fd, struct mp3entry *id3)
42{
43 /* TODO: read the id3v2 header if it exists */
44 id3->vbr = true;
45 id3->filesize = filesize(fd);
46 return skip_id3v2(fd, id3);
47}
48
49static bool get_other_asap_metadata(int fd, struct mp3entry *id3)
50{
51 id3->bitrate = 706;
52 id3->frequency = 44100;
53 id3->vbr = false;
54 id3->filesize = filesize(fd);
55 id3->genre_string = id3_get_num_genre(36);
56 return true;
57}
58#endif /* CONFIG_CODEC == SWCODEC */
59bool write_metadata_log = false;
60
61const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
62{
63 /* Unknown file format */
64 [0 ... AFMT_NUM_CODECS-1] =
65 AFMT_ENTRY("???", NULL, NULL, NULL, "\0" ),
66
67 /* MPEG Audio layer 2 */
68 [AFMT_MPA_L2] =
69 AFMT_ENTRY("MP2", "mpa", NULL, get_mp3_metadata, "mpa\0mp2\0"),
70
71#if CONFIG_CODEC != SWCODEC
72 /* MPEG Audio layer 3 on HWCODEC: .talk clips, no encoder */
73 [AFMT_MPA_L3] =
74 AFMT_ENTRY("MP3", "mpa", NULL, get_mp3_metadata, "mp3\0talk\0"),
75
76#else /* CONFIG_CODEC == SWCODEC */
77 /* MPEG Audio layer 3 on SWCODEC */
78 [AFMT_MPA_L3] =
79 AFMT_ENTRY("MP3", "mpa", "mp3_enc", get_mp3_metadata, "mp3\0"),
80
81 /* MPEG Audio layer 1 */
82 [AFMT_MPA_L1] =
83 AFMT_ENTRY("MP1", "mpa", NULL, get_mp3_metadata, "mp1\0"),
84 /* Audio Interchange File Format */
85 [AFMT_AIFF] =
86 AFMT_ENTRY("AIFF", "aiff", "aiff_enc", get_aiff_metadata, "aiff\0aif\0"),
87 /* Uncompressed PCM in a WAV file OR ATRAC3 stream in WAV file (.at3) */
88 [AFMT_PCM_WAV] =
89 AFMT_ENTRY("WAV", "wav", "wav_enc", get_wave_metadata, "wav\0at3\0"),
90 /* Ogg Vorbis */
91 [AFMT_OGG_VORBIS] =
92 AFMT_ENTRY("Ogg", "vorbis", NULL, get_ogg_metadata, "ogg\0oga\0"),
93 /* FLAC */
94 [AFMT_FLAC] =
95 AFMT_ENTRY("FLAC", "flac", NULL, get_flac_metadata, "flac\0"),
96 /* Musepack SV7 */
97 [AFMT_MPC_SV7] =
98 AFMT_ENTRY("MPCv7", "mpc", NULL, get_musepack_metadata,"mpc\0"),
99 /* A/52 (aka AC3) audio */
100 [AFMT_A52] =
101 AFMT_ENTRY("AC3", "a52", NULL, get_a52_metadata, "a52\0ac3\0"),
102 /* WavPack */
103 [AFMT_WAVPACK] =
104 AFMT_ENTRY("WV","wavpack","wavpack_enc",get_wavpack_metadata,"wv\0"),
105 /* Apple Lossless Audio Codec */
106 [AFMT_MP4_ALAC] =
107 AFMT_ENTRY("ALAC", "alac", NULL, get_mp4_metadata, "m4a\0m4b\0"),
108 /* Advanced Audio Coding in M4A container */
109 [AFMT_MP4_AAC] =
110 AFMT_ENTRY("AAC", "aac", NULL, get_mp4_metadata, "mp4\0"),
111 /* Shorten */
112 [AFMT_SHN] =
113 AFMT_ENTRY("SHN","shorten", NULL, get_shn_metadata, "shn\0"),
114 /* SID File Format */
115 [AFMT_SID] =
116 AFMT_ENTRY("SID", "sid", NULL, get_sid_metadata, "sid\0"),
117 /* ADX File Format */
118 [AFMT_ADX] =
119 AFMT_ENTRY("ADX", "adx", NULL, get_adx_metadata, "adx\0"),
120 /* NESM (NES Sound Format) */
121 [AFMT_NSF] =
122 AFMT_ENTRY("NSF", "nsf", NULL, get_nsf_metadata, "nsf\0nsfe\0"),
123 /* Speex File Format */
124 [AFMT_SPEEX] =
125 AFMT_ENTRY("Speex", "speex",NULL, get_ogg_metadata, "spx\0"),
126 /* SPC700 Save State */
127 [AFMT_SPC] =
128 AFMT_ENTRY("SPC", "spc", NULL, get_spc_metadata, "spc\0"),
129 /* APE (Monkey's Audio) */
130 [AFMT_APE] =
131 AFMT_ENTRY("APE", "ape", NULL, get_monkeys_metadata,"ape\0mac\0"),
132 /* WMA (WMAV1/V2 in ASF) */
133 [AFMT_WMA] =
134 AFMT_ENTRY("WMA", "wma", NULL, get_asf_metadata,"wma\0wmv\0asf\0"),
135 /* WMA Professional in ASF */
136 [AFMT_WMAPRO] =
137 AFMT_ENTRY("WMAPro","wmapro",NULL, NULL, "wma\0wmv\0asf\0"),
138 /* Amiga MOD File */
139 [AFMT_MOD] =
140 AFMT_ENTRY("MOD", "mod", NULL, get_mod_metadata, "mod\0"),
141 /* Atari SAP File */
142 [AFMT_SAP] =
143 AFMT_ENTRY("SAP", "asap", NULL, get_asap_metadata, "sap\0"),
144 /* Cook in RM/RA */
145 [AFMT_RM_COOK] =
146 AFMT_ENTRY("Cook", "cook", NULL, get_rm_metadata,"rm\0ra\0rmvb\0"),
147 /* AAC in RM/RA */
148 [AFMT_RM_AAC] =
149 AFMT_ENTRY("RAAC", "raac", NULL, NULL, "rm\0ra\0rmvb\0"),
150 /* AC3 in RM/RA */
151 [AFMT_RM_AC3] =
152 AFMT_ENTRY("AC3", "a52_rm", NULL, NULL, "rm\0ra\0rmvb\0"),
153 /* ATRAC3 in RM/RA */
154 [AFMT_RM_ATRAC3] =
155 AFMT_ENTRY("ATRAC3","atrac3_rm",NULL, NULL, "rm\0ra\0rmvb\0"),
156 /* Atari CMC File */
157 [AFMT_CMC] =
158 AFMT_ENTRY("CMC", "asap", NULL, get_other_asap_metadata,"cmc\0"),
159 /* Atari CM3 File */
160 [AFMT_CM3] =
161 AFMT_ENTRY("CM3", "asap", NULL, get_other_asap_metadata,"cm3\0"),
162 /* Atari CMR File */
163 [AFMT_CMR] =
164 AFMT_ENTRY("CMR", "asap", NULL, get_other_asap_metadata,"cmr\0"),
165 /* Atari CMS File */
166 [AFMT_CMS] =
167 AFMT_ENTRY("CMS", "asap", NULL, get_other_asap_metadata,"cms\0"),
168 /* Atari DMC File */
169 [AFMT_DMC] =
170 AFMT_ENTRY("DMC", "asap", NULL, get_other_asap_metadata,"dmc\0"),
171 /* Atari DLT File */
172 [AFMT_DLT] =
173 AFMT_ENTRY("DLT", "asap", NULL, get_other_asap_metadata,"dlt\0"),
174 /* Atari MPT File */
175 [AFMT_MPT] =
176 AFMT_ENTRY("MPT", "asap", NULL, get_other_asap_metadata,"mpt\0"),
177 /* Atari MPD File */
178 [AFMT_MPD] =
179 AFMT_ENTRY("MPD", "asap", NULL, get_other_asap_metadata,"mpd\0"),
180 /* Atari RMT File */
181 [AFMT_RMT] =
182 AFMT_ENTRY("RMT", "asap", NULL, get_other_asap_metadata,"rmt\0"),
183 /* Atari TMC File */
184 [AFMT_TMC] =
185 AFMT_ENTRY("TMC", "asap", NULL, get_other_asap_metadata,"tmc\0"),
186 /* Atari TM8 File */
187 [AFMT_TM8] =
188 AFMT_ENTRY("TM8", "asap", NULL, get_other_asap_metadata,"tm8\0"),
189 /* Atari TM2 File */
190 [AFMT_TM2] =
191 AFMT_ENTRY("TM2", "asap", NULL, get_other_asap_metadata,"tm2\0"),
192 /* Atrac3 in Sony OMA Container */
193 [AFMT_OMA_ATRAC3] =
194 AFMT_ENTRY("ATRAC3","atrac3_oma",NULL, get_oma_metadata, "oma\0aa3\0"),
195 /* SMAF (Synthetic music Mobile Application Format) */
196 [AFMT_SMAF] =
197 AFMT_ENTRY("SMAF", "smaf", NULL, get_smaf_metadata, "mmf\0"),
198 /* Sun Audio file */
199 [AFMT_AU] =
200 AFMT_ENTRY("AU", "au", NULL, get_au_metadata, "au\0snd\0"),
201 /* VOX (Dialogic telephony file formats) */
202 [AFMT_VOX] =
203 AFMT_ENTRY("VOX", "vox", NULL, get_vox_metadata, "vox\0"),
204 /* Wave64 */
205 [AFMT_WAVE64] =
206 AFMT_ENTRY("WAVE64","wav64",NULL, get_wave64_metadata,"w64\0"),
207 /* True Audio */
208 [AFMT_TTA] =
209 AFMT_ENTRY("TTA", "tta", NULL, get_tta_metadata, "tta\0"),
210 /* WMA Voice in ASF */
211 [AFMT_WMAVOICE] =
212 AFMT_ENTRY("WMAVoice","wmavoice",NULL, NULL, "wma\0wmv\0"),
213 /* Musepack SV8 */
214 [AFMT_MPC_SV8] =
215 AFMT_ENTRY("MPCv8", "mpc", NULL, get_musepack_metadata,"mpc\0"),
216 /* Advanced Audio Coding High Efficiency in M4A container */
217 [AFMT_MP4_AAC_HE] =
218 AFMT_ENTRY("AAC-HE","aac", NULL, get_mp4_metadata, "mp4\0"),
219 /* AY (ZX Spectrum, Amstrad CPC Sound Format) */
220 [AFMT_AY] =
221 AFMT_ENTRY("AY", "ay", NULL, get_ay_metadata, "ay\0"),
222 /* GBS (Game Boy Sound Format) */
223 [AFMT_GBS] =
224 AFMT_ENTRY("GBS", "gbs", NULL, get_gbs_metadata, "gbs\0"),
225 /* HES (Hudson Entertainment System Sound Format) */
226 [AFMT_HES] =
227 AFMT_ENTRY("HES", "hes", NULL, get_hes_metadata, "hes\0"),
228 /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */
229 [AFMT_SGC] =
230 AFMT_ENTRY("SGC", "sgc", NULL, get_sgc_metadata, "sgc\0"),
231 /* VGM (Video Game Music Format) */
232 [AFMT_VGM] =
233 AFMT_ENTRY("VGM", "vgm", NULL, get_vgm_metadata, "vgm\0vgz\0"),
234 /* KSS (MSX computer KSS Music File) */
235 [AFMT_KSS] =
236 AFMT_ENTRY("KSS", "kss", NULL, get_kss_metadata, "kss\0"),
237#endif
238};
239
240#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING)
241/* get REC_FORMAT_* corresponding AFMT_* */
242const int rec_format_afmt[REC_NUM_FORMATS] =
243{
244 /* give AFMT_UNKNOWN by default */
245 [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN,
246 /* add new entries below this line */
247 [REC_FORMAT_AIFF] = AFMT_AIFF,
248 [REC_FORMAT_MPA_L3] = AFMT_MPA_L3,
249 [REC_FORMAT_WAVPACK] = AFMT_WAVPACK,
250 [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV,
251};
252
253#if 0 /* Currently unused, left for reference and future use */
254/* get AFMT_* corresponding REC_FORMAT_* */
255const int afmt_rec_format[AFMT_NUM_CODECS] =
256{
257 /* give -1 by default */
258 [0 ... AFMT_NUM_CODECS-1] = -1,
259 /* add new entries below this line */
260 [AFMT_AIFF] = REC_FORMAT_AIFF,
261 [AFMT_MPA_L3] = REC_FORMAT_MPA_L3,
262 [AFMT_WAVPACK] = REC_FORMAT_WAVPACK,
263 [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV,
264};
265#endif
266#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
267
268#if CONFIG_CODEC == SWCODEC
269/* Get the canonical AFMT type */
270int get_audio_base_codec_type(int type)
271{
272 int base_type = type;
273 switch (type) {
274 case AFMT_MPA_L1:
275 case AFMT_MPA_L2:
276 case AFMT_MPA_L3:
277 base_type = AFMT_MPA_L3;
278 break;
279 case AFMT_MPC_SV7:
280 case AFMT_MPC_SV8:
281 base_type = AFMT_MPC_SV7;
282 break;
283 case AFMT_MP4_AAC:
284 case AFMT_MP4_AAC_HE:
285 base_type = AFMT_MP4_AAC;
286 break;
287 case AFMT_SAP:
288 case AFMT_CMC:
289 case AFMT_CM3:
290 case AFMT_CMR:
291 case AFMT_CMS:
292 case AFMT_DMC:
293 case AFMT_DLT:
294 case AFMT_MPT:
295 case AFMT_MPD:
296 case AFMT_RMT:
297 case AFMT_TMC:
298 case AFMT_TM8:
299 case AFMT_TM2:
300 base_type = AFMT_SAP;
301 break;
302 default:
303 break;
304 }
305
306 return base_type;
307}
308
309/* Get the basic audio type */
310enum data_type get_audio_base_data_type(int afmt)
311{
312 if ((unsigned)afmt >= AFMT_NUM_CODECS)
313 return TYPE_UNKNOWN;
314
315 switch (get_audio_base_codec_type(afmt))
316 {
317 case AFMT_NSF:
318 case AFMT_SPC:
319 case AFMT_SID:
320 case AFMT_MOD:
321 case AFMT_SAP:
322 case AFMT_AY:
323 case AFMT_GBS:
324 case AFMT_HES:
325 case AFMT_SGC:
326 case AFMT_VGM:
327 case AFMT_KSS:
328 /* Type must be allocated and loaded in its entirety onto
329 the buffer */
330 return TYPE_ATOMIC_AUDIO;
331
332 default:
333 /* Assume type may be loaded and discarded incrementally */
334 return TYPE_PACKET_AUDIO;
335
336 case AFMT_UNKNOWN:
337 /* Have no idea at all */
338 return TYPE_UNKNOWN;
339 }
340}
341
342/* Is the format allowed to buffer starting at some offset other than 0
343 or first frame only for resume purposes? */
344bool format_buffers_with_offset(int afmt)
345{
346 switch (afmt)
347 {
348 case AFMT_MPA_L1:
349 case AFMT_MPA_L2:
350 case AFMT_MPA_L3:
351 case AFMT_WAVPACK:
352 /* Format may be loaded at the first needed frame */
353 return true;
354 default:
355 /* Format must be loaded from the beginning of the file
356 (does not imply 'atomic', while 'atomic' implies 'no offset') */
357 return false;
358 }
359}
360#endif /* CONFIG_CODEC == SWCODEC */
361
362
363/* Simple file type probing by looking at the filename extension. */
364unsigned int probe_file_format(const char *filename)
365{
366 char *suffix;
367 unsigned int i;
368
369 suffix = strrchr(filename, '.');
370
371 if (suffix == NULL)
372 {
373 return AFMT_UNKNOWN;
374 }
375
376 /* skip '.' */
377 suffix++;
378
379 for (i = 1; i < AFMT_NUM_CODECS; i++)
380 {
381 /* search extension list for type */
382 const char *ext = audio_formats[i].ext_list;
383
384 do
385 {
386 if (strcasecmp(suffix, ext) == 0)
387 {
388 return i;
389 }
390
391 ext += strlen(ext) + 1;
392 }
393 while (*ext != '\0');
394 }
395
396 return AFMT_UNKNOWN;
397}
398
399/* Note, that this returns false for successful, true for error! */
400bool mp3info(struct mp3entry *entry, const char *filename)
401{
402 int fd;
403 bool result;
404
405 fd = open(filename, O_RDONLY);
406 if (fd < 0)
407 return true;
408
409 result = !get_metadata(entry, fd, filename);
410
411 close(fd);
412
413 return result;
414}
415
416/* Get metadata for track - return false if parsing showed problems with the
417 * file that would prevent playback.
418 */
419bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
420{
421 const struct afmt_entry *entry;
422 int logfd = 0;
423 DEBUGF("Read metadata for %s\n", trackname);
424 if (write_metadata_log)
425 {
426 logfd = open("/metadata.log", O_WRONLY | O_APPEND | O_CREAT, 0666);
427 if (logfd >= 0)
428 {
429 write(logfd, trackname, strlen(trackname));
430 write(logfd, "\n", 1);
431 close(logfd);
432 }
433 }
434
435 /* Clear the mp3entry to avoid having bogus pointers appear */
436 wipe_mp3entry(id3);
437
438 /* Take our best guess at the codec type based on file extension */
439 id3->codectype = probe_file_format(trackname);
440
441 /* default values for embedded cuesheets */
442 id3->has_embedded_cuesheet = false;
443 id3->embedded_cuesheet.pos = 0;
444
445 entry = &audio_formats[id3->codectype];
446
447 /* Load codec specific track tag information and confirm the codec type. */
448 if (!entry->parse_func)
449 {
450 DEBUGF("nothing to parse for %s (format %s)", trackname, entry->label);
451 return false;
452 }
453
454 if (!entry->parse_func(fd, id3))
455 {
456 DEBUGF("parsing %s failed (format: %s)", trackname, entry->label);
457 return false;
458 }
459
460 lseek(fd, 0, SEEK_SET);
461 strlcpy(id3->path, trackname, sizeof(id3->path));
462 /* We have successfully read the metadata from the file */
463 return true;
464}
465
466#ifndef __PCTOOL__
467#if CONFIG_CODEC == SWCODEC
468void strip_tags(int handle_id)
469{
470 static const unsigned char tag[] = "TAG";
471 static const unsigned char apetag[] = "APETAGEX";
472 size_t len, version;
473 void *tail;
474
475 if (bufgettail(handle_id, 128, &tail) != 128)
476 return;
477
478 if (memcmp(tail, tag, 3) == 0)
479 {
480 /* Skip id3v1 tag */
481 logf("Cutting off ID3v1 tag");
482 bufcuttail(handle_id, 128);
483 }
484
485 /* Get a new tail, as the old one may have been cut */
486 if (bufgettail(handle_id, 32, &tail) != 32)
487 return;
488
489 /* Check for APE tag (look for the APE tag footer) */
490 if (memcmp(tail, apetag, 8) != 0)
491 return;
492
493 /* Read the version and length from the footer */
494 version = get_long_le(&((unsigned char *)tail)[8]);
495 len = get_long_le(&((unsigned char *)tail)[12]);
496 if (version == 2000)
497 len += 32; /* APEv2 has a 32 byte header */
498
499 /* Skip APE tag */
500 logf("Cutting off APE tag (%ldB)", len);
501 bufcuttail(handle_id, len);
502}
503#endif /* CONFIG_CODEC == SWCODEC */
504#endif /* ! __PCTOOL__ */
505
506#define MOVE_ENTRY(x) if (x) x += offset;
507
508void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig)
509{
510 long offset;
511 if (orig > dest)
512 offset = -((size_t)orig - (size_t)dest);
513 else
514 offset = ((size_t)dest - (size_t)orig);
515
516 MOVE_ENTRY(entry->title)
517 MOVE_ENTRY(entry->artist)
518 MOVE_ENTRY(entry->album)
519
520 if (entry->genre_string > (char*)orig &&
521 entry->genre_string < (char*)orig + sizeof(struct mp3entry))
522 /* Don't adjust that if it points to an entry of the "genres" array */
523 entry->genre_string += offset;
524
525 MOVE_ENTRY(entry->track_string)
526 MOVE_ENTRY(entry->disc_string)
527 MOVE_ENTRY(entry->year_string)
528 MOVE_ENTRY(entry->composer)
529 MOVE_ENTRY(entry->comment)
530 MOVE_ENTRY(entry->albumartist)
531 MOVE_ENTRY(entry->grouping)
532 MOVE_ENTRY(entry->mb_track_id)
533}
534
535void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig)
536{
537 memcpy(dest, orig, sizeof(struct mp3entry));
538 adjust_mp3entry(dest, dest, orig);
539}
540
541/* A shortcut to simplify the common task of clearing the struct */
542void wipe_mp3entry(struct mp3entry *id3)
543{
544 memset(id3, 0, sizeof (struct mp3entry));
545}
546
547#if CONFIG_CODEC == SWCODEC
548/* Glean what is possible from the filename alone - does not parse metadata */
549void fill_metadata_from_path(struct mp3entry *id3, const char *trackname)
550{
551 char *p;
552
553 /* Clear the mp3entry to avoid having bogus pointers appear */
554 wipe_mp3entry(id3);
555
556 /* Find the filename portion of the path */
557 p = strrchr(trackname, '/');
558 strlcpy(id3->id3v2buf, p ? ++p : id3->path, ID3V2_BUF_SIZE);
559
560 /* Get the format from the extension and trim it off */
561 p = strrchr(id3->id3v2buf, '.');
562 if (p)
563 {
564 /* Might be wrong for container formats - should we bother? */
565 id3->codectype = probe_file_format(p);
566
567 if (id3->codectype != AFMT_UNKNOWN)
568 *p = '\0';
569 }
570
571 /* Set the filename as the title */
572 id3->title = id3->id3v2buf;
573
574 /* Copy the path info */
575 strlcpy(id3->path, trackname, sizeof (id3->path));
576}
577#endif /* CONFIG_CODEC == SWCODEC */
578
579#ifndef __PCTOOL__
580#ifdef HAVE_TAGCACHE
581#if CONFIG_CODEC == SWCODEC
582
583enum { AUTORESUMABLE_UNKNOWN = 0, AUTORESUMABLE_TRUE, AUTORESUMABLE_FALSE };
584
585bool autoresumable(struct mp3entry *id3)
586{
587 char *endp, *path;
588 size_t len;
589 bool is_resumable;
590
591 if (id3->autoresumable) /* result cached? */
592 return id3->autoresumable == AUTORESUMABLE_TRUE;
593
594 is_resumable = false;
595
596 if (id3->path)
597 {
598 for (path = global_settings.autoresume_paths;
599 *path; /* search terms left? */
600 path++)
601 {
602 if (*path == ':') /* Skip empty search patterns */
603 continue;
604
605 /* FIXME: As soon as strcspn or strchrnul are made available in
606 the core, the following can be made more efficient. */
607 endp = strchr(path, ':');
608 if (endp)
609 len = endp - path;
610 else
611 len = strlen(path);
612
613 /* Note: At this point, len is always > 0 */
614
615 if (strncasecmp(id3->path, path, len) == 0)
616 {
617 /* Full directory-name matches only. Trailing '/' in
618 search path OK. */
619 if (id3->path[len] == '/' || id3->path[len - 1] == '/')
620 {
621 is_resumable = true;
622 break;
623 }
624 }
625 path += len - 1;
626 }
627 }
628
629 /* cache result */
630 id3->autoresumable =
631 is_resumable ? AUTORESUMABLE_TRUE : AUTORESUMABLE_FALSE;
632
633 logf("autoresumable: %s is%s resumable",
634 id3->path, is_resumable ? "" : " not");
635
636 return is_resumable;
637}
638
639#endif /* SWCODEC */
640#endif /* HAVE_TAGCACHE */
641#endif /* __PCTOOL__ */
diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h
new file mode 100644
index 0000000000..55e4d76f25
--- /dev/null
+++ b/lib/rbcodec/metadata/metadata.h
@@ -0,0 +1,353 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _METADATA_H
23#define _METADATA_H
24
25#include <stdbool.h>
26#include "config.h"
27#include "file.h"
28
29
30/* Audio file types. */
31/* NOTE: The values of the AFMT_* items are used for the %fc tag in the WPS
32 - so new entries MUST be added to the end to maintain compatibility.
33 */
34enum
35{
36 AFMT_UNKNOWN = 0, /* Unknown file format */
37
38 /* start formats */
39 AFMT_MPA_L1, /* MPEG Audio layer 1 */
40 AFMT_MPA_L2, /* MPEG Audio layer 2 */
41 AFMT_MPA_L3, /* MPEG Audio layer 3 */
42
43#if CONFIG_CODEC == SWCODEC
44 AFMT_AIFF, /* Audio Interchange File Format */
45 AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */
46 AFMT_OGG_VORBIS, /* Ogg Vorbis */
47 AFMT_FLAC, /* FLAC */
48 AFMT_MPC_SV7, /* Musepack SV7 */
49 AFMT_A52, /* A/52 (aka AC3) audio */
50 AFMT_WAVPACK, /* WavPack */
51 AFMT_MP4_ALAC, /* Apple Lossless Audio Codec */
52 AFMT_MP4_AAC, /* Advanced Audio Coding (AAC) in M4A container */
53 AFMT_SHN, /* Shorten */
54 AFMT_SID, /* SID File Format */
55 AFMT_ADX, /* ADX File Format */
56 AFMT_NSF, /* NESM (NES Sound Format) */
57 AFMT_SPEEX, /* Ogg Speex speech */
58 AFMT_SPC, /* SPC700 save state */
59 AFMT_APE, /* Monkey's Audio (APE) */
60 AFMT_WMA, /* WMAV1/V2 in ASF */
61 AFMT_WMAPRO, /* WMA Professional in ASF */
62 AFMT_MOD, /* Amiga MOD File Format */
63 AFMT_SAP, /* Atari 8Bit SAP Format */
64 AFMT_RM_COOK, /* Cook in RM/RA */
65 AFMT_RM_AAC, /* AAC in RM/RA */
66 AFMT_RM_AC3, /* AC3 in RM/RA */
67 AFMT_RM_ATRAC3, /* ATRAC3 in RM/RA */
68 AFMT_CMC, /* Atari 8bit cmc format */
69 AFMT_CM3, /* Atari 8bit cm3 format */
70 AFMT_CMR, /* Atari 8bit cmr format */
71 AFMT_CMS, /* Atari 8bit cms format */
72 AFMT_DMC, /* Atari 8bit dmc format */
73 AFMT_DLT, /* Atari 8bit dlt format */
74 AFMT_MPT, /* Atari 8bit mpt format */
75 AFMT_MPD, /* Atari 8bit mpd format */
76 AFMT_RMT, /* Atari 8bit rmt format */
77 AFMT_TMC, /* Atari 8bit tmc format */
78 AFMT_TM8, /* Atari 8bit tm8 format */
79 AFMT_TM2, /* Atari 8bit tm2 format */
80 AFMT_OMA_ATRAC3, /* Atrac3 in Sony OMA container */
81 AFMT_SMAF, /* SMAF */
82 AFMT_AU, /* Sun Audio file */
83 AFMT_VOX, /* VOX */
84 AFMT_WAVE64, /* Wave64 */
85 AFMT_TTA, /* True Audio */
86 AFMT_WMAVOICE, /* WMA Voice in ASF */
87 AFMT_MPC_SV8, /* Musepack SV8 */
88 AFMT_MP4_AAC_HE, /* Advanced Audio Coding (AAC-HE) in M4A container */
89 AFMT_AY, /* AY (ZX Spectrum, Amstrad CPC Sound Format) */
90 AFMT_GBS, /* GBS (Game Boy Sound Format) */
91 AFMT_HES, /* HES (Hudson Entertainment System Sound Format) */
92 AFMT_SGC, /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */
93 AFMT_VGM, /* VGM (Video Game Music Format) */
94 AFMT_KSS, /* KSS (MSX computer KSS Music File) */
95#endif
96
97 /* add new formats at any index above this line to have a sensible order -
98 specified array index inits are used */
99 /* format arrays defined in id3.c */
100
101 AFMT_NUM_CODECS,
102
103#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
104 /* masks to decompose parts */
105 CODEC_AFMT_MASK = 0x0fff,
106 CODEC_TYPE_MASK = 0x7000,
107
108 /* switch for specifying codec type when requesting a filename */
109 CODEC_TYPE_DECODER = (0 << 12), /* default */
110 CODEC_TYPE_ENCODER = (1 << 12),
111#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
112};
113
114#if CONFIG_CODEC == SWCODEC
115#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
116#define CODEC_EXTENSION "so"
117#define CODEC_PREFIX "lib"
118#else
119#define CODEC_EXTENSION "codec"
120#define CODEC_PREFIX ""
121#endif
122
123#ifdef HAVE_RECORDING
124enum rec_format_indexes
125{
126 __REC_FORMAT_START_INDEX = -1,
127
128 /* start formats */
129
130 REC_FORMAT_PCM_WAV,
131 REC_FORMAT_AIFF,
132 REC_FORMAT_WAVPACK,
133 REC_FORMAT_MPA_L3,
134
135 /* add new formats at any index above this line to have a sensible order -
136 specified array index inits are used
137 REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range
138 REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes
139 */
140
141 REC_NUM_FORMATS,
142
143 REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV,
144 REC_FORMAT_CFG_NUM_BITS = 2
145};
146
147#define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3"
148
149/* get REC_FORMAT_* corresponding AFMT_* */
150extern const int rec_format_afmt[REC_NUM_FORMATS];
151/* get AFMT_* corresponding REC_FORMAT_* */
152/* unused: extern const int afmt_rec_format[AFMT_NUM_CODECS]; */
153
154#define AFMT_ENTRY(label, root_fname, enc_root_fname, func, ext_list) \
155 { label, root_fname, enc_root_fname, func, ext_list }
156#else /* !HAVE_RECORDING */
157#define AFMT_ENTRY(label, root_fname, enc_root_fname, func, ext_list) \
158 { label, root_fname, func, ext_list }
159#endif /* HAVE_RECORDING */
160
161#else /* !SWCODEC */
162
163#define AFMT_ENTRY(label, root_fname, enc_root_fname, func, ext_list) \
164 { label, func, ext_list }
165#endif /* CONFIG_CODEC == SWCODEC */
166
167/** Database of audio formats **/
168/* record describing the audio format */
169struct mp3entry;
170struct afmt_entry
171{
172 const char *label; /* format label */
173#if CONFIG_CODEC == SWCODEC
174 const char *codec_root_fn; /* root codec filename (sans _enc and .codec) */
175#ifdef HAVE_RECORDING
176 const char *codec_enc_root_fn; /* filename of encoder codec */
177#endif
178#endif
179 bool (*parse_func)(int fd, struct mp3entry *id3); /* return true on success */
180 const char *ext_list; /* NULL terminated extension
181 list for type with the first as
182 the default for recording */
183};
184
185/* database of labels and codecs. add formats per above enum */
186extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS];
187
188#if MEMORYSIZE > 2
189#define ID3V2_BUF_SIZE 900
190#define ID3V2_MAX_ITEM_SIZE 240
191#else
192#define ID3V2_BUF_SIZE 300
193#define ID3V2_MAX_ITEM_SIZE 90
194#endif
195
196enum {
197 ID3_VER_1_0 = 1,
198 ID3_VER_1_1,
199 ID3_VER_2_2,
200 ID3_VER_2_3,
201 ID3_VER_2_4
202};
203
204#ifdef HAVE_ALBUMART
205enum mp3_aa_type {
206 AA_TYPE_UNSYNC = -1,
207 AA_TYPE_UNKNOWN,
208 AA_TYPE_BMP,
209 AA_TYPE_PNG,
210 AA_TYPE_JPG,
211};
212
213struct mp3_albumart {
214 enum mp3_aa_type type;
215 int size;
216 off_t pos;
217};
218#endif
219
220enum character_encoding {
221 CHAR_ENC_ISO_8859_1 = 1,
222 CHAR_ENC_UTF_8,
223 CHAR_ENC_UTF_16_LE,
224 CHAR_ENC_UTF_16_BE,
225};
226
227/* cache embedded cuesheet details */
228struct embedded_cuesheet {
229 int size;
230 off_t pos;
231 enum character_encoding encoding;
232};
233
234struct mp3entry {
235 char path[MAX_PATH];
236 char* title;
237 char* artist;
238 char* album;
239 char* genre_string;
240 char* disc_string;
241 char* track_string;
242 char* year_string;
243 char* composer;
244 char* comment;
245 char* albumartist;
246 char* grouping;
247 int discnum;
248 int tracknum;
249 int layer;
250 int year;
251 unsigned char id3version;
252 unsigned int codectype;
253 unsigned int bitrate;
254 unsigned long frequency;
255 unsigned long id3v2len;
256 unsigned long id3v1len;
257 unsigned long first_frame_offset; /* Byte offset to first real MP3 frame.
258 Used for skipping leading garbage to
259 avoid gaps between tracks. */
260 unsigned long filesize; /* without headers; in bytes */
261 unsigned long length; /* song length in ms */
262 unsigned long elapsed; /* ms played */
263
264 int lead_trim; /* Number of samples to skip at the beginning */
265 int tail_trim; /* Number of samples to remove from the end */
266
267 /* Added for Vorbis, used by mp4 parser as well. */
268 unsigned long samples; /* number of samples in track */
269
270 /* MP3 stream specific info */
271 unsigned long frame_count; /* number of frames in the file (if VBR) */
272
273 /* Used for A52/AC3 */
274 unsigned long bytesperframe; /* number of bytes per frame (if CBR) */
275
276 /* Xing VBR fields */
277 bool vbr;
278 bool has_toc; /* True if there is a VBR header in the file */
279 unsigned char toc[100]; /* table of contents */
280
281 /* Added for ATRAC3 */
282 unsigned int channels; /* Number of channels in the stream */
283 unsigned int extradata_size; /* Size (in bytes) of the codec's extradata from the container */
284
285 /* Added for AAC HE SBR */
286 bool needs_upsampling_correction; /* flag used by aac codec */
287
288 /* these following two fields are used for local buffering */
289 char id3v2buf[ID3V2_BUF_SIZE];
290 char id3v1buf[4][92];
291
292 /* resume related */
293 unsigned long offset; /* bytes played */
294 int index; /* playlist index */
295
296#ifdef HAVE_TAGCACHE
297 unsigned char autoresumable; /* caches result of autoresumable() */
298
299 /* runtime database fields */
300 long tagcache_idx; /* 0=invalid, otherwise idx+1 */
301 int rating;
302 int score;
303 long playcount;
304 long lastplayed;
305 long playtime;
306#endif
307
308 /* replaygain support */
309#if CONFIG_CODEC == SWCODEC
310 long track_level; /* holds the level in dB * (1<<FP_BITS) */
311 long album_level;
312 long track_gain; /* s19.12 signed fixed point. 0 for no gain. */
313 long album_gain;
314 long track_peak; /* s19.12 signed fixed point. 0 for no peak. */
315 long album_peak;
316#endif
317
318#ifdef HAVE_ALBUMART
319 bool has_embedded_albumart;
320 struct mp3_albumart albumart;
321#endif
322
323 /* Cuesheet support */
324 bool has_embedded_cuesheet;
325 struct embedded_cuesheet embedded_cuesheet;
326 struct cuesheet *cuesheet;
327
328 /* Musicbrainz Track ID */
329 char* mb_track_id;
330};
331
332unsigned int probe_file_format(const char *filename);
333bool get_metadata(struct mp3entry* id3, int fd, const char* trackname);
334bool mp3info(struct mp3entry *entry, const char *filename);
335void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig);
336void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig);
337void wipe_mp3entry(struct mp3entry *id3);
338
339#if CONFIG_CODEC == SWCODEC
340void fill_metadata_from_path(struct mp3entry *id3, const char *trackname);
341int get_audio_base_codec_type(int type);
342void strip_tags(int handle_id);
343enum data_type get_audio_base_data_type(int afmt);
344bool format_buffers_with_offset(int afmt);
345#endif
346
347#ifdef HAVE_TAGCACHE
348bool autoresumable(struct mp3entry *id3);
349#endif
350
351#endif
352
353
diff --git a/lib/rbcodec/metadata/metadata_common.c b/lib/rbcodec/metadata/metadata_common.c
new file mode 100644
index 0000000000..e861644025
--- /dev/null
+++ b/lib/rbcodec/metadata/metadata_common.c
@@ -0,0 +1,374 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include "string-extra.h"
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "replaygain.h"
32
33/* Read a string from the file. Read up to size bytes, or, if eos != -1,
34 * until the eos character is found (eos is not stored in buf, unless it is
35 * nil). Writes up to buf_size chars to buf, always terminating with a nil.
36 * Returns number of chars read or -1 on read error.
37 */
38long read_string(int fd, char* buf, long buf_size, int eos, long size)
39{
40 long read_bytes = 0;
41 char c;
42
43 while (size != 0)
44 {
45 if (read(fd, &c, 1) != 1)
46 {
47 read_bytes = -1;
48 break;
49 }
50
51 read_bytes++;
52 size--;
53
54 if ((eos != -1) && (eos == (unsigned char) c))
55 {
56 break;
57 }
58
59 if (buf_size > 1)
60 {
61 *buf++ = c;
62 buf_size--;
63 }
64 }
65
66 *buf = 0;
67 return read_bytes;
68}
69/* Read an unsigned 8-bit integer from a file. */
70int read_uint8(int fd, uint8_t* buf)
71{
72 size_t n;
73
74 n = read(fd, (char*) buf, 1);
75 return n;
76}
77
78#ifdef ROCKBOX_LITTLE_ENDIAN
79/* Read an unsigned 16-bit integer from a big-endian file. */
80int read_uint16be(int fd, uint16_t* buf)
81{
82 size_t n;
83
84 n = read(fd, (char*) buf, 2);
85 *buf = betoh16(*buf);
86 return n;
87}
88/* Read an unsigned 32-bit integer from a big-endian file. */
89int read_uint32be(int fd, uint32_t* buf)
90{
91 size_t n;
92
93 n = read(fd, (char*) buf, 4);
94 *buf = betoh32(*buf);
95 return n;
96}
97/* Read an unsigned 64-bit integer from a big-endian file. */
98int read_uint64be(int fd, uint64_t* buf)
99{
100 size_t n;
101 uint8_t data[8];
102 int i;
103
104 n = read(fd, data, 8);
105
106 for (i=0, *buf=0; i<=7; i++) {
107 *buf <<= 8;
108 *buf |= data[i];
109 }
110 return n;
111}
112#else
113/* Read unsigned integers from a little-endian file. */
114int read_uint16le(int fd, uint16_t* buf)
115{
116 size_t n;
117
118 n = read(fd, (char*) buf, 2);
119 *buf = letoh16(*buf);
120 return n;
121}
122int read_uint32le(int fd, uint32_t* buf)
123{
124 size_t n;
125
126 n = read(fd, (char*) buf, 4);
127 *buf = letoh32(*buf);
128 return n;
129}
130int read_uint64le(int fd, uint64_t* buf)
131{
132 size_t n;
133 uint8_t data[8];
134 int i;
135
136 n = read(fd, data, 8);
137
138 for (i=7, *buf=0; i>=0; i--) {
139 *buf <<= 8;
140 *buf |= data[i];
141 }
142
143 return n;
144}
145#endif
146
147/* Read an unaligned 64-bit little endian unsigned integer from buffer. */
148uint64_t get_uint64_le(void* buf)
149{
150 unsigned char* p = (unsigned char*) buf;
151
152 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24) | ((uint64_t)p[4] << 32) |
153 ((uint64_t)p[5] << 40) | ((uint64_t)p[6] << 48) | ((uint64_t)p[7] << 56);
154}
155
156/* Read an unaligned 32-bit little endian long from buffer. */
157uint32_t get_long_le(void* buf)
158{
159 unsigned char* p = (unsigned char*) buf;
160
161 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
162}
163
164/* Read an unaligned 16-bit little endian short from buffer. */
165uint16_t get_short_le(void* buf)
166{
167 unsigned char* p = (unsigned char*) buf;
168
169 return p[0] | (p[1] << 8);
170}
171
172/* Read an unaligned 32-bit big endian long from buffer. */
173uint32_t get_long_be(void* buf)
174{
175 unsigned char* p = (unsigned char*) buf;
176
177 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
178}
179
180/* Read an unaligned 16-bit little endian short from buffer. */
181uint16_t get_short_be(void* buf)
182{
183 unsigned char* p = (unsigned char*) buf;
184
185 return (p[0] << 8) | p[1];
186}
187
188/* Read an unaligned 32-bit little endian long from buffer. */
189int32_t get_slong(void* buf)
190{
191 unsigned char* p = (unsigned char*) buf;
192
193 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
194}
195
196uint32_t get_itunes_int32(char* value, int count)
197{
198 static const char hexdigits[] = "0123456789ABCDEF";
199 const char* c;
200 int r = 0;
201
202 while (count-- > 0)
203 {
204 while (isspace(*value))
205 {
206 value++;
207 }
208
209 while (*value && !isspace(*value))
210 {
211 value++;
212 }
213 }
214
215 while (isspace(*value))
216 {
217 value++;
218 }
219
220 while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL))
221 {
222 r = (r << 4) | (c - hexdigits);
223 value++;
224 }
225
226 return r;
227}
228
229/* Skip an ID3v2 tag if it can be found. We assume the tag is located at the
230 * start of the file, which should be true in all cases where we need to skip it.
231 * Returns true if successfully skipped or not skipped, and false if
232 * something went wrong while skipping.
233 */
234bool skip_id3v2(int fd, struct mp3entry *id3)
235{
236 char buf[4];
237
238 read(fd, buf, 4);
239 if (memcmp(buf, "ID3", 3) == 0)
240 {
241 /* We have found an ID3v2 tag at the start of the file - find its
242 length and then skip it. */
243 if ((id3->first_frame_offset = getid3v2len(fd)) == 0)
244 return false;
245
246 if ((lseek(fd, id3->first_frame_offset, SEEK_SET) < 0))
247 return false;
248
249 return true;
250 } else {
251 lseek(fd, 0, SEEK_SET);
252 id3->first_frame_offset = 0;
253 return true;
254 }
255}
256
257/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
258 * String values to keep are written to buf. Returns number of bytes written
259 * to buf (including end nil).
260 */
261long parse_tag(const char* name, char* value, struct mp3entry* id3,
262 char* buf, long buf_remaining, enum tagtype type)
263{
264 long len = 0;
265 char** p;
266
267 if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
268 || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
269 {
270 id3->tracknum = atoi(value);
271 p = &(id3->track_string);
272 }
273 else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0)
274 {
275 id3->discnum = atoi(value);
276 p = &(id3->disc_string);
277 }
278 else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
279 || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
280 {
281 /* Date's can be in any format in Vorbis. However most of them
282 * are in ISO8601 format so if we try and parse the first part
283 * of the tag as a number, we should get the year. If we get crap,
284 * then act like we never parsed it.
285 */
286 id3->year = atoi(value);
287 if (id3->year < 1900)
288 { /* yeah, not likely */
289 id3->year = 0;
290 }
291 p = &(id3->year_string);
292 }
293 else if (strcasecmp(name, "title") == 0)
294 {
295 p = &(id3->title);
296 }
297 else if (strcasecmp(name, "artist") == 0)
298 {
299 p = &(id3->artist);
300 }
301 else if (strcasecmp(name, "album") == 0)
302 {
303 p = &(id3->album);
304 }
305 else if (strcasecmp(name, "genre") == 0)
306 {
307 p = &(id3->genre_string);
308 }
309 else if (strcasecmp(name, "composer") == 0)
310 {
311 p = &(id3->composer);
312 }
313 else if (strcasecmp(name, "comment") == 0)
314 {
315 p = &(id3->comment);
316 }
317 else if (strcasecmp(name, "albumartist") == 0)
318 {
319 p = &(id3->albumartist);
320 }
321 else if (strcasecmp(name, "album artist") == 0)
322 {
323 p = &(id3->albumartist);
324 }
325 else if (strcasecmp(name, "ensemble") == 0)
326 {
327 p = &(id3->albumartist);
328 }
329 else if (strcasecmp(name, "grouping") == 0)
330 {
331 p = &(id3->grouping);
332 }
333 else if (strcasecmp(name, "content group") == 0)
334 {
335 p = &(id3->grouping);
336 }
337 else if (strcasecmp(name, "contentgroup") == 0)
338 {
339 p = &(id3->grouping);
340 }
341 else if (strcasecmp(name, "musicbrainz_trackid") == 0
342 || strcasecmp(name, "http://musicbrainz.org") == 0 )
343 {
344 p = &(id3->mb_track_id);
345 }
346 else
347 {
348 parse_replaygain(name, value, id3);
349 p = NULL;
350 }
351
352 /* Do not overwrite already available metadata. Especially when reading
353 * tags with e.g. multiple genres / artists. This way only the first
354 * of multiple entries is used, all following are dropped. */
355 if (p!=NULL && *p==NULL)
356 {
357 len = strlen(value);
358 len = MIN(len, buf_remaining - 1);
359 len = MIN(len, ID3V2_MAX_ITEM_SIZE); /* Limit max. item size. */
360
361 if (len > 0)
362 {
363 len++;
364 strlcpy(buf, value, len);
365 *p = buf;
366 }
367 else
368 {
369 len = 0;
370 }
371 }
372
373 return len;
374}
diff --git a/lib/rbcodec/metadata/metadata_common.h b/lib/rbcodec/metadata/metadata_common.h
new file mode 100644
index 0000000000..db91729de4
--- /dev/null
+++ b/lib/rbcodec/metadata/metadata_common.h
@@ -0,0 +1,69 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <inttypes.h>
22#include "metadata.h"
23
24#ifdef ROCKBOX_BIG_ENDIAN
25#define IS_BIG_ENDIAN 1
26#else
27#define IS_BIG_ENDIAN 0
28#endif
29
30#define TAG_NAME_LENGTH 32
31#define TAG_VALUE_LENGTH 128
32
33#define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d))
34
35enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS };
36
37bool read_ape_tags(int fd, struct mp3entry* id3);
38long read_vorbis_tags(int fd, struct mp3entry *id3,
39 long tag_remaining);
40
41bool skip_id3v2(int fd, struct mp3entry *id3);
42long read_string(int fd, char* buf, long buf_size, int eos, long size);
43
44int read_uint8(int fd, uint8_t* buf);
45#ifdef ROCKBOX_BIG_ENDIAN
46#define read_uint16be(fd,buf) read((fd), (buf), 2)
47#define read_uint32be(fd,buf) read((fd), (buf), 4)
48#define read_uint64be(fd,buf) read((fd), (buf), 8)
49int read_uint16le(int fd, uint16_t* buf);
50int read_uint32le(int fd, uint32_t* buf);
51int read_uint64le(int fd, uint64_t* buf);
52#else
53int read_uint16be(int fd, uint16_t* buf);
54int read_uint32be(int fd, uint32_t* buf);
55int read_uint64be(int fd, uint64_t* buf);
56#define read_uint16le(fd,buf) read((fd), (buf), 2)
57#define read_uint32le(fd,buf) read((fd), (buf), 4)
58#define read_uint64le(fd,buf) read((fd), (buf), 8)
59#endif
60
61uint64_t get_uint64_le(void* buf);
62uint32_t get_long_le(void* buf);
63uint16_t get_short_le(void* buf);
64uint32_t get_long_be(void* buf);
65uint16_t get_short_be(void* buf);
66int32_t get_slong(void* buf);
67uint32_t get_itunes_int32(char* value, int count);
68long parse_tag(const char* name, char* value, struct mp3entry* id3,
69 char* buf, long buf_remaining, enum tagtype type);
diff --git a/lib/rbcodec/metadata/metadata_parsers.h b/lib/rbcodec/metadata/metadata_parsers.h
new file mode 100644
index 0000000000..304e393538
--- /dev/null
+++ b/lib/rbcodec/metadata/metadata_parsers.h
@@ -0,0 +1,59 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#if CONFIG_CODEC == SWCODEC
23char* id3_get_num_genre(unsigned int genre_num);
24#endif
25int getid3v2len(int fd);
26bool setid3v1title(int fd, struct mp3entry *entry);
27void setid3v2title(int fd, struct mp3entry *entry);
28bool get_mp3_metadata(int fd, struct mp3entry* id3);
29#if CONFIG_CODEC == SWCODEC
30bool get_adx_metadata(int fd, struct mp3entry* id3);
31bool get_aiff_metadata(int fd, struct mp3entry* id3);
32bool get_flac_metadata(int fd, struct mp3entry* id3);
33bool get_mp4_metadata(int fd, struct mp3entry* id3);
34bool get_monkeys_metadata(int fd, struct mp3entry* id3);
35bool get_musepack_metadata(int fd, struct mp3entry *id3);
36bool get_sid_metadata(int fd, struct mp3entry* id3);
37bool get_mod_metadata(int fd, struct mp3entry* id3);
38bool get_spc_metadata(int fd, struct mp3entry* id3);
39bool get_ogg_metadata(int fd, struct mp3entry* id3);
40bool get_wave_metadata(int fd, struct mp3entry* id3);
41bool get_wavpack_metadata(int fd, struct mp3entry* id3);
42bool get_a52_metadata(int fd, struct mp3entry* id3);
43bool get_asf_metadata(int fd, struct mp3entry* id3);
44bool get_asap_metadata(int fd, struct mp3entry* id3);
45bool get_rm_metadata(int fd, struct mp3entry* id3);
46bool get_nsf_metadata(int fd, struct mp3entry* id3);
47bool get_oma_metadata(int fd, struct mp3entry* id3);
48bool get_smaf_metadata(int fd, struct mp3entry* id3);
49bool get_au_metadata(int fd, struct mp3entry* id3);
50bool get_vox_metadata(int fd, struct mp3entry* id3);
51bool get_wave64_metadata(int fd, struct mp3entry* id3);
52bool get_tta_metadata(int fd, struct mp3entry* id3);
53bool get_ay_metadata(int fd, struct mp3entry* id3);
54bool get_gbs_metadata(int fd, struct mp3entry* id3);
55bool get_hes_metadata(int fd, struct mp3entry* id3);
56bool get_sgc_metadata(int fd, struct mp3entry* id3);
57bool get_vgm_metadata(int fd, struct mp3entry* id3);
58bool get_kss_metadata(int fd, struct mp3entry* id3);
59#endif /* CONFIG_CODEC == SWCODEC */
diff --git a/lib/rbcodec/metadata/mod.c b/lib/rbcodec/metadata/mod.c
new file mode 100644
index 0000000000..de76823e91
--- /dev/null
+++ b/lib/rbcodec/metadata/mod.c
@@ -0,0 +1,103 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include <inttypes.h>
25
26#include "system.h"
27#include "metadata.h"
28#include <string-extra.h>
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32
33#define MODULEHEADERSIZE 0x438
34
35bool get_mod_metadata(int fd, struct mp3entry* id3)
36{
37 /* Use the trackname part of the id3 structure as a temporary buffer */
38 unsigned char *buf = id3->id3v2buf;
39 unsigned char id[4];
40 bool is_mod_file = false;
41
42 /* Seek to file begin */
43 if (lseek(fd, 0, SEEK_SET) < 0)
44 return false;
45 /* Use id3v2buf as buffer for the track name */
46 if (read(fd, buf, sizeof(id3->id3v2buf)) < (ssize_t)sizeof(id3->id3v2buf))
47 return false;
48 /* Seek to MOD ID position */
49 if (lseek(fd, MODULEHEADERSIZE, SEEK_SET) < 0)
50 return false;
51 /* Read MOD ID */
52 if (read(fd, id, sizeof(id)) < (ssize_t)sizeof(id))
53 return false;
54
55 /* Mod type checking based on MikMod */
56 /* Protracker and variants */
57 if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) {
58 is_mod_file = true;
59 }
60
61 /* Star Tracker */
62 if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) &&
63 (isdigit(id[3]))) {
64 char numchn = id[3] - '0';
65 if (numchn == 4 || numchn == 8)
66 is_mod_file = true;
67 }
68
69 /* Oktalyzer (Amiga) */
70 if (!memcmp(id, "OKTA", 4)) {
71 is_mod_file = true;
72 }
73
74 /* Oktalyser (Atari) */
75 if (!memcmp(id, "CD81", 4)) {
76 is_mod_file = true;
77 }
78
79 /* Fasttracker */
80 if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) {
81 is_mod_file = true;
82 }
83 /* Fasttracker or Taketracker */
84 if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2)))
85 && (isdigit(id[0])) && (isdigit(id[1]))) {
86 is_mod_file = true;
87 }
88
89 /* Don't try to play if we can't find a known mod type
90 * (there are mod files which have nothing to do with music) */
91 if (!is_mod_file)
92 return false;
93
94 id3->title = id3->id3v2buf; /* Point title to previous read ID3 buffer. */
95 id3->bitrate = filesize(fd)/1024; /* size in kb */
96 id3->frequency = 44100;
97 id3->length = 120*1000;
98 id3->vbr = false;
99 id3->filesize = filesize(fd);
100
101 return true;
102}
103
diff --git a/lib/rbcodec/metadata/monkeys.c b/lib/rbcodec/metadata/monkeys.c
new file mode 100644
index 0000000000..4aff1412aa
--- /dev/null
+++ b/lib/rbcodec/metadata/monkeys.c
@@ -0,0 +1,97 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31
32bool get_monkeys_metadata(int fd, struct mp3entry* id3)
33{
34 /* Use the trackname part of the id3 structure as a temporary buffer */
35 unsigned char* buf = (unsigned char *)id3->path;
36 unsigned char* header;
37 bool rc = false;
38 uint32_t descriptorlength;
39 uint32_t totalsamples;
40 uint32_t blocksperframe, finalframeblocks, totalframes;
41 int fileversion;
42
43 lseek(fd, 0, SEEK_SET);
44
45 if (read(fd, buf, 4) < 4)
46 {
47 return rc;
48 }
49
50 if (memcmp(buf, "MAC ", 4) != 0)
51 {
52 return rc;
53 }
54
55 read(fd, buf + 4, MAX_PATH - 4);
56
57 fileversion = get_short_le(buf+4);
58 if (fileversion < 3970)
59 {
60 /* Not supported */
61 return false;
62 }
63
64 if (fileversion >= 3980)
65 {
66 descriptorlength = get_long_le(buf+8);
67
68 header = buf + descriptorlength;
69
70 blocksperframe = get_long_le(header+4);
71 finalframeblocks = get_long_le(header+8);
72 totalframes = get_long_le(header+12);
73 id3->frequency = get_long_le(header+20);
74 }
75 else
76 {
77 /* v3.95 and later files all have a fixed framesize */
78 blocksperframe = 73728 * 4;
79
80 finalframeblocks = get_long_le(buf+28);
81 totalframes = get_long_le(buf+24);
82 id3->frequency = get_long_le(buf+12);
83 }
84
85 id3->vbr = true; /* All APE files are VBR */
86 id3->filesize = filesize(fd);
87
88 totalsamples = finalframeblocks;
89 if (totalframes > 1)
90 totalsamples += blocksperframe * (totalframes-1);
91
92 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
93 id3->bitrate = (id3->filesize * 8) / id3->length;
94
95 read_ape_tags(fd, id3);
96 return true;
97}
diff --git a/lib/rbcodec/metadata/mp3.c b/lib/rbcodec/metadata/mp3.c
new file mode 100644
index 0000000000..feb1a52f77
--- /dev/null
+++ b/lib/rbcodec/metadata/mp3.c
@@ -0,0 +1,193 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21/*
22 * Parts of this code has been stolen from the Ample project and was written
23 * by David H�deman. It has since been extended and enhanced pretty much by
24 * all sorts of friendly Rockbox people.
25 *
26 */
27
28 /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdbool.h>
35#include "string-extra.h"
36#include "config.h"
37#include "file.h"
38#include "logf.h"
39
40#include "system.h"
41#include "metadata.h"
42#include "mp3data.h"
43#include "metadata_common.h"
44#include "metadata_parsers.h"
45
46/*
47 * Calculates the length (in milliseconds) of an MP3 file.
48 *
49 * Modified to only use integers.
50 *
51 * Arguments: file - the file to calculate the length upon
52 * entry - the entry to update with the length
53 *
54 * Returns: the song length in milliseconds,
55 * 0 means that it couldn't be calculated
56 */
57static int getsonglength(int fd, struct mp3entry *entry)
58{
59 unsigned long filetime = 0;
60 struct mp3info info;
61 long bytecount;
62
63 /* Start searching after ID3v2 header */
64 if(-1 == lseek(fd, entry->id3v2len, SEEK_SET))
65 return 0;
66
67 bytecount = get_mp3file_info(fd, &info);
68
69 logf("Space between ID3V2 tag and first audio frame: 0x%lx bytes",
70 bytecount);
71
72 if(bytecount < 0)
73 return -1;
74
75 bytecount += entry->id3v2len;
76
77 /* Validate byte count, in case the file has been edited without
78 * updating the header.
79 */
80 if (info.byte_count)
81 {
82 const unsigned long expected = entry->filesize - entry->id3v1len
83 - entry->id3v2len;
84 const unsigned long diff = MAX(10240, info.byte_count / 20);
85
86 if ((info.byte_count > expected + diff)
87 || (info.byte_count < expected - diff))
88 {
89 logf("Note: info.byte_count differs from expected value by "
90 "%ld bytes", labs((long) (expected - info.byte_count)));
91 info.byte_count = 0;
92 info.frame_count = 0;
93 info.file_time = 0;
94 info.enc_padding = 0;
95
96 /* Even if the bitrate was based on "known bad" values, it
97 * should still be better for VBR files than using the bitrate
98 * of the first audio frame.
99 */
100 }
101 }
102
103 entry->bitrate = info.bitrate;
104 entry->frequency = info.frequency;
105 entry->layer = info.layer;
106 switch(entry->layer) {
107#if CONFIG_CODEC==SWCODEC
108 case 0:
109 entry->codectype=AFMT_MPA_L1;
110 break;
111#endif
112 case 1:
113 entry->codectype=AFMT_MPA_L2;
114 break;
115 case 2:
116 entry->codectype=AFMT_MPA_L3;
117 break;
118 }
119
120 /* If the file time hasn't been established, this may be a fixed
121 rate MP3, so just use the default formula */
122
123 filetime = info.file_time;
124
125 if(filetime == 0)
126 {
127 /* Prevent a division by zero */
128 if (info.bitrate < 8)
129 filetime = 0;
130 else
131 filetime = (entry->filesize - bytecount) / (info.bitrate / 8);
132 /* bitrate is in kbps so this delivers milliseconds. Doing bitrate / 8
133 * instead of filesize * 8 is exact, because mpeg audio bitrates are
134 * always multiples of 8, and it avoids overflows. */
135 }
136
137 entry->frame_count = info.frame_count;
138
139 entry->vbr = info.is_vbr;
140 entry->has_toc = info.has_toc;
141
142#if CONFIG_CODEC==SWCODEC
143 if (!entry->lead_trim)
144 entry->lead_trim = info.enc_delay;
145 if (!entry->tail_trim)
146 entry->tail_trim = info.enc_padding;
147#endif
148
149 memcpy(entry->toc, info.toc, sizeof(info.toc));
150
151 /* Update the seek point for the first playable frame */
152 entry->first_frame_offset = bytecount;
153 logf("First frame is at %lx", entry->first_frame_offset);
154
155 return filetime;
156}
157
158/*
159 * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc)
160 * about an MP3 file and updates it's entry accordingly.
161 *
162 Note, that this returns true for successful, false for error! */
163bool get_mp3_metadata(int fd, struct mp3entry *entry)
164{
165 entry->title = NULL;
166 entry->filesize = filesize(fd);
167 entry->id3v2len = getid3v2len(fd);
168 entry->tracknum = 0;
169 entry->discnum = 0;
170
171 if (entry->id3v2len)
172 setid3v2title(fd, entry);
173 int len = getsonglength(fd, entry);
174 if (len < 0)
175 return false;
176 entry->length = len;
177
178 /* Subtract the meta information from the file size to get
179 the true size of the MP3 stream */
180 entry->filesize -= entry->first_frame_offset;
181
182 /* only seek to end of file if no id3v2 tags were found */
183 if (!entry->id3v2len) {
184 setid3v1title(fd, entry);
185 }
186
187 if(!entry->length || (entry->filesize < 8 ))
188 /* no song length or less than 8 bytes is hereby considered to be an
189 invalid mp3 and won't be played by us! */
190 return false;
191
192 return true;
193}
diff --git a/lib/rbcodec/metadata/mp3data.c b/lib/rbcodec/metadata/mp3data.c
new file mode 100644
index 0000000000..13ff0a87a7
--- /dev/null
+++ b/lib/rbcodec/metadata/mp3data.c
@@ -0,0 +1,849 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23 * Parts of this code has been stolen from the Ample project and was written
24 * by David Härdeman. It has since been extended and enhanced pretty much by
25 * all sorts of friendly Rockbox people.
26 *
27 * A nice reference for MPEG header info:
28 * http://rockbox.haxx.se/docs/mpeghdr.html
29 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdbool.h>
36#include <limits.h>
37#include "debug.h"
38#include "logf.h"
39#include "mp3data.h"
40#include "file.h"
41#include "system.h"
42
43//#define DEBUG_VERBOSE
44
45#ifdef DEBUG_VERBOSE
46#define VDEBUGF DEBUGF
47#else
48#define VDEBUGF(...) do { } while(0)
49#endif
50
51#define SYNC_MASK (0x7ffL << 21)
52#define VERSION_MASK (3L << 19)
53#define LAYER_MASK (3L << 17)
54#define PROTECTION_MASK (1L << 16)
55#define BITRATE_MASK (0xfL << 12)
56#define SAMPLERATE_MASK (3L << 10)
57#define PADDING_MASK (1L << 9)
58#define PRIVATE_MASK (1L << 8)
59#define CHANNELMODE_MASK (3L << 6)
60#define MODE_EXT_MASK (3L << 4)
61#define COPYRIGHT_MASK (1L << 3)
62#define ORIGINAL_MASK (1L << 2)
63#define EMPHASIS_MASK (3L)
64
65/* Maximum number of bytes needed by Xing/Info/VBRI parser. */
66#define VBR_HEADER_MAX_SIZE (180)
67
68/* MPEG Version table, sorted by version index */
69static const signed char version_table[4] = {
70 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
71};
72
73/* Bitrate table for mpeg audio, indexed by row index and birate index */
74static const short bitrates[5][16] = {
75 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
76 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
77 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
78 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
79 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
80};
81
82/* Bitrate pointer table, indexed by version and layer */
83static const short *bitrate_table[3][3] =
84{
85 {bitrates[0], bitrates[1], bitrates[2]},
86 {bitrates[3], bitrates[4], bitrates[4]},
87 {bitrates[3], bitrates[4], bitrates[4]}
88};
89
90/* Sampling frequency table, indexed by version and frequency index */
91static const unsigned short freq_table[3][3] =
92{
93 {44100, 48000, 32000}, /* MPEG Version 1 */
94 {22050, 24000, 16000}, /* MPEG version 2 */
95 {11025, 12000, 8000}, /* MPEG version 2.5 */
96};
97
98unsigned long bytes2int(unsigned long b0, unsigned long b1,
99 unsigned long b2, unsigned long b3)
100{
101 return (b0 & 0xFF) << (3*8) |
102 (b1 & 0xFF) << (2*8) |
103 (b2 & 0xFF) << (1*8) |
104 (b3 & 0xFF) << (0*8);
105}
106
107/* check if 'head' is a valid mp3 frame header */
108static bool is_mp3frameheader(unsigned long head)
109{
110 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
111 return false;
112 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
113 return false;
114 if (!(head & LAYER_MASK)) /* no layer? */
115 return false;
116#if CONFIG_CODEC != SWCODEC
117 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
118 if ((head & LAYER_MASK) == LAYER_MASK)
119 return false;
120#endif
121 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
122 return false;
123 if (!(head & BITRATE_MASK)) /* no bitrate? */
124 return false;
125 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
126 return false;
127
128 return true;
129}
130
131static bool mp3headerinfo(struct mp3info *info, unsigned long header)
132{
133 int bitindex, freqindex;
134
135 /* MPEG Audio Version */
136 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
137 return false;
138
139 info->version = version_table[(header & VERSION_MASK) >> 19];
140 if (info->version < 0)
141 return false;
142
143 /* Layer */
144 info->layer = 3 - ((header & LAYER_MASK) >> 17);
145 if (info->layer == 3)
146 return false;
147
148/* Rockbox: not used
149 info->protection = (header & PROTECTION_MASK) ? true : false;
150*/
151
152 /* Bitrate */
153 bitindex = (header & BITRATE_MASK) >> 12;
154 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
155 if(info->bitrate == 0)
156 return false;
157
158 /* Sampling frequency */
159 freqindex = (header & SAMPLERATE_MASK) >> 10;
160 if (freqindex == 3)
161 return false;
162 info->frequency = freq_table[info->version][freqindex];
163
164 info->padding = (header & PADDING_MASK) ? 1 : 0;
165
166 /* Calculate number of bytes, calculation depends on layer */
167 if (info->layer == 0) {
168 info->frame_samples = 384;
169 info->frame_size = (12000 * info->bitrate / info->frequency
170 + info->padding) * 4;
171 }
172 else {
173 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
174 info->frame_samples = 576;
175 else
176 info->frame_samples = 1152;
177 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
178 / info->frequency + info->padding;
179 }
180
181 /* Frametime fraction denominator */
182 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
183 info->ft_den = 1; /* integer number of milliseconds */
184 }
185 else { /* 44.1/22.05/11.025 kHz */
186 if (info->layer == 0) /* layer 1 */
187 info->ft_den = 147;
188 else /* layer 2+3 */
189 info->ft_den = 49;
190 }
191 /* Frametime fraction numerator */
192 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
193
194 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
195/* Rockbox: not used
196 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
197 info->emphasis = header & EMPHASIS_MASK;
198*/
199 VDEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
200 "chmode %d, bytes: %d time: %d/%d\n",
201 header, info->version, info->layer+1, info->bitrate,
202 info->frequency, info->channel_mode,
203 info->frame_size, info->ft_num, info->ft_den);
204 return true;
205}
206
207static bool headers_have_same_type(unsigned long header1,
208 unsigned long header2)
209{
210 /* Compare MPEG version, layer and sampling frequency. If header1 is zero
211 * it is assumed both frame headers are of same type. */
212 unsigned int mask = SYNC_MASK | VERSION_MASK | LAYER_MASK | SAMPLERATE_MASK;
213 header1 &= mask;
214 header2 &= mask;
215 return header1 ? (header1 == header2) : true;
216}
217
218/* Helper function to read 4-byte in big endian format. */
219static void read_uint32be_mp3data(int fd, unsigned long *data)
220{
221#ifdef ROCKBOX_BIG_ENDIAN
222 (void)read(fd, (char*)data, 4);
223#else
224 (void)read(fd, (char*)data, 4);
225 *data = betoh32(*data);
226#endif
227}
228
229static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
230 unsigned long reference_header,
231 int(*getfunc)(int fd, unsigned char *c),
232 bool single_header)
233{
234 unsigned long header=0;
235 unsigned char tmp;
236 long pos = 0;
237
238 /* We will search until we find two consecutive MPEG frame headers with
239 * the same MPEG version, layer and sampling frequency. The first header
240 * of this pair is assumed to be the first valid MPEG frame header of the
241 * whole stream. */
242 do {
243 /* Read 1 new byte. */
244 header <<= 8;
245 if (!getfunc(fd, &tmp))
246 return 0;
247 header |= tmp;
248 pos++;
249
250 /* Abort if max_offset is reached. Stop parsing. */
251 if (max_offset > 0 && pos > max_offset)
252 return 0;
253
254 if (is_mp3frameheader(header)) {
255 if (single_header) {
256 /* We search for one _single_ valid header that has the same
257 * type as the reference_header (if reference_header != 0).
258 * In this case we are finished. */
259 if (headers_have_same_type(reference_header, header))
260 break;
261 } else {
262 /* The current header is valid. Now gather the frame size,
263 * seek to this byte position and check if there is another
264 * valid MPEG frame header of the same type. */
265 struct mp3info info;
266
267 /* Gather frame size from given header and seek to next
268 * frame header. */
269 mp3headerinfo(&info, header);
270 lseek(fd, info.frame_size-4, SEEK_CUR);
271
272 /* Read possible next frame header and seek back to last frame
273 * headers byte position. */
274 reference_header = 0;
275 read_uint32be_mp3data(fd, &reference_header);
276 //
277 lseek(fd, -info.frame_size, SEEK_CUR);
278
279 /* If the current header is of the same type as the previous
280 * header we are finished. */
281 if (headers_have_same_type(header, reference_header))
282 break;
283 }
284 }
285
286 } while (true);
287
288 *offset = pos - 4;
289
290 if(*offset)
291 VDEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
292
293 return header;
294}
295
296static int fileread(int fd, unsigned char *c)
297{
298 return read(fd, c, 1);
299}
300
301unsigned long find_next_frame(int fd,
302 long *offset,
303 long max_offset,
304 unsigned long reference_header)
305{
306 return __find_next_frame(fd, offset, max_offset, reference_header,
307 fileread, true);
308}
309
310#ifndef __PCTOOL__
311static int fnf_read_index;
312static int fnf_buf_len;
313static unsigned char *fnf_buf;
314
315static int buf_getbyte(int fd, unsigned char *c)
316{
317 if(fnf_read_index < fnf_buf_len)
318 {
319 *c = fnf_buf[fnf_read_index++];
320 return 1;
321 }
322 else
323 {
324 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
325 if(fnf_buf_len < 0)
326 return -1;
327
328 fnf_read_index = 0;
329
330 if(fnf_buf_len > 0)
331 {
332 *c = fnf_buf[fnf_read_index++];
333 return 1;
334 }
335 else
336 return 0;
337 }
338 return 0;
339}
340
341static int buf_seek(int fd, int len)
342{
343 fnf_read_index += len;
344 if(fnf_read_index > fnf_buf_len)
345 {
346 len = fnf_read_index - fnf_buf_len;
347
348 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
349 if(fnf_buf_len < 0)
350 return -1;
351
352 fnf_read_index = 0;
353 fnf_read_index += len;
354 }
355
356 if(fnf_read_index > fnf_buf_len)
357 {
358 return -1;
359 }
360 else
361 return 0;
362}
363
364static void buf_init(unsigned char* buf, size_t buflen)
365{
366 fnf_buf = buf;
367 fnf_buf_len = buflen;
368 fnf_read_index = 0;
369}
370
371static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
372{
373 return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
374}
375
376static size_t mem_buflen;
377static unsigned char* mem_buf;
378static size_t mem_pos;
379static int mem_cnt;
380static int mem_maxlen;
381
382static int mem_getbyte(int dummy, unsigned char *c)
383{
384 (void)dummy;
385
386 *c = mem_buf[mem_pos++];
387 if(mem_pos >= mem_buflen)
388 mem_pos = 0;
389
390 if(mem_cnt++ >= mem_maxlen)
391 return 0;
392 else
393 return 1;
394}
395
396unsigned long mem_find_next_frame(int startpos,
397 long *offset,
398 long max_offset,
399 unsigned long reference_header,
400 unsigned char* buf, size_t buflen)
401{
402 mem_buf = buf;
403 mem_buflen = buflen;
404 mem_pos = startpos;
405 mem_cnt = 0;
406 mem_maxlen = max_offset;
407
408 return __find_next_frame(0, offset, max_offset, reference_header,
409 mem_getbyte, true);
410}
411#endif
412
413/* Extract information from a 'Xing' or 'Info' header. */
414static void get_xing_info(struct mp3info *info, unsigned char *buf)
415{
416 int i = 8;
417
418 /* Is it a VBR file? */
419 info->is_vbr = !memcmp(buf, "Xing", 4);
420
421 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
422 {
423 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
424 if (info->frame_count <= ULONG_MAX / info->ft_num)
425 info->file_time = info->frame_count * info->ft_num / info->ft_den;
426 else
427 info->file_time = info->frame_count / info->ft_den * info->ft_num;
428 i += 4;
429 }
430
431 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
432 {
433 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
434 i += 4;
435 }
436
437 if (info->file_time && info->byte_count)
438 {
439 if (info->byte_count <= (ULONG_MAX/8))
440 info->bitrate = info->byte_count * 8 / info->file_time;
441 else
442 info->bitrate = info->byte_count / (info->file_time >> 3);
443 }
444
445 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
446 {
447 info->has_toc = true;
448 memcpy( info->toc, buf+i, 100 );
449 i += 100;
450 }
451 if (buf[7] & VBR_QUALITY_FLAG)
452 {
453 /* We don't care about this, but need to skip it */
454 i += 4;
455 }
456#if CONFIG_CODEC==SWCODEC
457 i += 21;
458 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
459 info->enc_padding = ((int)(buf[i+1]&0xF) << 8) | buf[i+2];
460 /* TODO: This sanity checking is rather silly, seeing as how the LAME
461 header contains a CRC field that can be used to verify integrity. */
462 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
463 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
464 {
465 /* Invalid data */
466 info->enc_delay = -1;
467 info->enc_padding = -1;
468 }
469#endif
470}
471
472/* Extract information from a 'VBRI' header. */
473static void get_vbri_info(struct mp3info *info, unsigned char *buf)
474{
475 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
476 /*
477 int i, num_offsets, offset = 0;
478 */
479
480 info->is_vbr = true; /* Yes, it is a FhG VBR file */
481 info->has_toc = false; /* We don't parse the TOC (yet) */
482
483 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
484 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
485 if (info->frame_count <= ULONG_MAX / info->ft_num)
486 info->file_time = info->frame_count * info->ft_num / info->ft_den;
487 else
488 info->file_time = info->frame_count / info->ft_den * info->ft_num;
489
490 if (info->byte_count <= (ULONG_MAX/8))
491 info->bitrate = info->byte_count * 8 / info->file_time;
492 else
493 info->bitrate = info->byte_count / (info->file_time >> 3);
494
495 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
496 info->bitrate, info->frame_size, info->frame_size);
497 VDEBUGF("Frame count: %lx\n", info->frame_count);
498 VDEBUGF("Byte count: %lx\n", info->byte_count);
499
500 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
501 /*
502 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
503 VDEBUGF("Offsets: %d\n", num_offsets);
504 VDEBUGF("Frames/entry: %ld\n", bytes2int(0, 0, buf[24], buf[25]));
505
506 for(i = 0; i < num_offsets; i++)
507 {
508 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
509 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
510 }
511 */
512}
513
514/* Seek to next mpeg header and extract relevant information. */
515static int get_next_header_info(int fd, long *bytecount, struct mp3info *info,
516 bool single_header)
517{
518 long tmp;
519 unsigned long header = 0;
520
521 header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header);
522 if(header == 0)
523 return -1;
524
525 if(!mp3headerinfo(info, header))
526 return -2;
527
528 /* Next frame header is tmp bytes away. */
529 *bytecount += tmp;
530
531 return 0;
532}
533
534int get_mp3file_info(int fd, struct mp3info *info)
535{
536 unsigned char frame[VBR_HEADER_MAX_SIZE], *vbrheader;
537 long bytecount = 0;
538 int result, buf_size;
539
540 /* Initialize info and frame */
541 memset(info, 0, sizeof(struct mp3info));
542 memset(frame, 0, sizeof(frame));
543
544#if CONFIG_CODEC==SWCODEC
545 /* These two are needed for proper LAME gapless MP3 playback */
546 info->enc_delay = -1;
547 info->enc_padding = -1;
548#endif
549
550 /* Get the very first single MPEG frame. */
551 result = get_next_header_info(fd, &bytecount, info, true);
552 if(result)
553 return result;
554
555 /* Read the amount of frame data to the buffer that is required for the
556 * vbr tag parsing. Skip the rest. */
557 buf_size = MIN(info->frame_size-4, (int)sizeof(frame));
558 if(read(fd, frame, buf_size) < 0)
559 return -3;
560 lseek(fd, info->frame_size - 4 - buf_size, SEEK_CUR);
561
562 /* Calculate position of a possible VBR header */
563 if (info->version == MPEG_VERSION1) {
564 if (info->channel_mode == 3) /* mono */
565 vbrheader = frame + 17;
566 else
567 vbrheader = frame + 32;
568 } else {
569 if (info->channel_mode == 3) /* mono */
570 vbrheader = frame + 9;
571 else
572 vbrheader = frame + 17;
573 }
574
575 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
576 {
577 VDEBUGF("-- XING header --\n");
578
579 /* We want to skip the Xing frame when playing the stream */
580 bytecount += info->frame_size;
581
582 /* Now get the next frame to read the real info about the mp3 stream */
583 result = get_next_header_info(fd, &bytecount, info, false);
584 if(result)
585 return result;
586
587 get_xing_info(info, vbrheader);
588 }
589 else if (!memcmp(vbrheader, "VBRI", 4))
590 {
591 VDEBUGF("-- VBRI header --\n");
592
593 /* We want to skip the VBRI frame when playing the stream */
594 bytecount += info->frame_size;
595
596 /* Now get the next frame to read the real info about the mp3 stream */
597 result = get_next_header_info(fd, &bytecount, info, false);
598 if(result)
599 return result;
600
601 get_vbri_info(info, vbrheader);
602 }
603 else
604 {
605 VDEBUGF("-- No VBR header --\n");
606
607 /* There was no VBR header found. So, we seek back to beginning and
608 * search for the first MPEG frame header of the mp3 stream. */
609 lseek(fd, -info->frame_size, SEEK_CUR);
610 result = get_next_header_info(fd, &bytecount, info, false);
611 if(result)
612 return result;
613 }
614
615 return bytecount;
616}
617
618#ifndef __PCTOOL__
619static void long2bytes(unsigned char *buf, long val)
620{
621 buf[0] = (val >> 24) & 0xff;
622 buf[1] = (val >> 16) & 0xff;
623 buf[2] = (val >> 8) & 0xff;
624 buf[3] = val & 0xff;
625}
626
627int count_mp3_frames(int fd, int startpos, int filesize,
628 void (*progressfunc)(int),
629 unsigned char* buf, size_t buflen)
630{
631 unsigned long header = 0;
632 struct mp3info info;
633 int num_frames;
634 long bytes;
635 int cnt;
636 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
637 int progress_cnt = 0;
638 bool is_vbr = false;
639 int last_bitrate = 0;
640 int header_template = 0;
641
642 if(lseek(fd, startpos, SEEK_SET) < 0)
643 return -1;
644
645 buf_init(buf, buflen);
646
647 /* Find out the total number of frames */
648 num_frames = 0;
649 cnt = 0;
650
651 while((header = buf_find_next_frame(fd, &bytes, header_template))) {
652 mp3headerinfo(&info, header);
653
654 if(!header_template)
655 header_template = header;
656
657 /* See if this really is a VBR file */
658 if(last_bitrate && info.bitrate != last_bitrate)
659 {
660 is_vbr = true;
661 }
662 last_bitrate = info.bitrate;
663
664 buf_seek(fd, info.frame_size-4);
665 num_frames++;
666 if(progressfunc)
667 {
668 cnt += bytes + info.frame_size;
669 if(cnt > progress_chunk)
670 {
671 progress_cnt++;
672 progressfunc(progress_cnt);
673 cnt = 0;
674 }
675 }
676 }
677 VDEBUGF("Total number of frames: %d\n", num_frames);
678
679 if(is_vbr)
680 return num_frames;
681 else
682 {
683 DEBUGF("Not a VBR file\n");
684 return 0;
685 }
686}
687
688static const char cooltext[] = "Rockbox - rocks your box";
689
690/* buf needs to be the audio buffer with TOC generation enabled,
691 and at least MAX_XING_HEADER_SIZE bytes otherwise */
692int create_xing_header(int fd, long startpos, long filesize,
693 unsigned char *buf, unsigned long num_frames,
694 unsigned long rec_time, unsigned long header_template,
695 void (*progressfunc)(int), bool generate_toc,
696 unsigned char *tempbuf, size_t tempbuflen )
697{
698 struct mp3info info;
699 unsigned char toc[100];
700 unsigned long header = 0;
701 unsigned long xing_header_template = header_template;
702 unsigned long filepos;
703 long pos, last_pos;
704 long j;
705 long bytes;
706 int i;
707 int index;
708
709 DEBUGF("create_xing_header()\n");
710
711 if(generate_toc)
712 {
713 lseek(fd, startpos, SEEK_SET);
714 buf_init(tempbuf, tempbuflen);
715
716 /* Generate filepos table */
717 last_pos = 0;
718 filepos = 0;
719 header = 0;
720 for(i = 0;i < 100;i++) {
721 /* Calculate the absolute frame number for this seek point */
722 pos = i * num_frames / 100;
723
724 /* Advance from the last seek point to this one */
725 for(j = 0;j < pos - last_pos;j++)
726 {
727 header = buf_find_next_frame(fd, &bytes, header_template);
728 filepos += bytes;
729 mp3headerinfo(&info, header);
730 buf_seek(fd, info.frame_size-4);
731 filepos += info.frame_size;
732
733 if(!header_template)
734 header_template = header;
735 }
736
737 /* Save a header for later use if header_template is empty.
738 We only save one header, and we want to save one in the
739 middle of the stream, just in case the first and the last
740 headers are corrupt. */
741 if(!xing_header_template && i == 1)
742 xing_header_template = header;
743
744 if(progressfunc)
745 {
746 progressfunc(50 + i/2);
747 }
748
749 /* Fill in the TOC entry */
750 /* each toc is a single byte indicating how many 256ths of the
751 * way through the file, is that percent of the way through the
752 * song. the easy method, filepos*256/filesize, chokes when
753 * the upper 8 bits of the file position are nonzero
754 * (i.e. files over 16mb in size).
755 */
756 if (filepos > (ULONG_MAX/256))
757 {
758 /* instead of multiplying filepos by 256, we divide
759 * filesize by 256.
760 */
761 toc[i] = filepos / (filesize >> 8);
762 }
763 else
764 {
765 toc[i] = filepos * 256 / filesize;
766 }
767
768 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
769 i, pos, pos-last_pos, filepos, toc[i]);
770
771 last_pos = pos;
772 }
773 }
774
775 /* Use the template header and create a new one.
776 We ignore the Protection bit even if the rest of the stream is
777 protected. */
778 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
779 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
780
781 if (!mp3headerinfo(&info, header))
782 return 0; /* invalid header */
783
784 if (num_frames == 0 && rec_time) {
785 /* estimate the number of frames based on the recording time */
786 if (rec_time <= ULONG_MAX / info.ft_den)
787 num_frames = rec_time * info.ft_den / info.ft_num;
788 else
789 num_frames = rec_time / info.ft_num * info.ft_den;
790 }
791
792 /* Clear the frame */
793 memset(buf, 0, MAX_XING_HEADER_SIZE);
794
795 /* Write the header to the buffer */
796 long2bytes(buf, header);
797
798 /* Calculate position of VBR header */
799 if (info.version == MPEG_VERSION1) {
800 if (info.channel_mode == 3) /* mono */
801 index = 21;
802 else
803 index = 36;
804 }
805 else {
806 if (info.channel_mode == 3) /* mono */
807 index = 13;
808 else
809 index = 21;
810 }
811
812 /* Create the Xing data */
813 memcpy(&buf[index], "Xing", 4);
814 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
815 | (filesize ? VBR_BYTES_FLAG : 0)
816 | (generate_toc ? VBR_TOC_FLAG : 0));
817 index += 8;
818 if(num_frames)
819 {
820 long2bytes(&buf[index], num_frames);
821 index += 4;
822 }
823
824 if(filesize)
825 {
826 long2bytes(&buf[index], filesize - startpos);
827 index += 4;
828 }
829
830 /* Copy the TOC */
831 memcpy(buf + index, toc, 100);
832
833 /* And some extra cool info */
834 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
835
836#ifdef DEBUG
837 for(i = 0;i < info.frame_size;i++)
838 {
839 if(i && !(i % 16))
840 DEBUGF("\n");
841
842 DEBUGF("%02x ", buf[i]);
843 }
844#endif
845
846 return info.frame_size;
847}
848
849#endif
diff --git a/lib/rbcodec/metadata/mp3data.h b/lib/rbcodec/metadata/mp3data.h
new file mode 100644
index 0000000000..762c2f4583
--- /dev/null
+++ b/lib/rbcodec/metadata/mp3data.h
@@ -0,0 +1,89 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _MP3DATA_H_
23#define _MP3DATA_H_
24
25#define MPEG_VERSION1 0
26#define MPEG_VERSION2 1
27#define MPEG_VERSION2_5 2
28
29#include <string.h> /* size_t */
30
31struct mp3info {
32 /* Standard MP3 frame header fields */
33 int version;
34 int layer;
35 int bitrate;
36 long frequency;
37 int padding;
38 int channel_mode;
39 int frame_size; /* Frame size in bytes */
40 int frame_samples;/* Samples per frame */
41 int ft_num; /* Numerator of frametime in milliseconds */
42 int ft_den; /* Denominator of frametime in milliseconds */
43
44 bool is_vbr; /* True if the file is VBR */
45 bool has_toc; /* True if there is a VBR header in the file */
46 unsigned char toc[100];
47 unsigned long frame_count; /* Number of frames in the file (if VBR) */
48 unsigned long byte_count; /* File size in bytes */
49 unsigned long file_time; /* Length of the whole file in milliseconds */
50 int enc_delay; /* Encoder delay, fetched from LAME header */
51 int enc_padding; /* Padded samples added to last frame. LAME header */
52};
53
54/* Xing header information */
55#define VBR_FRAMES_FLAG 0x01
56#define VBR_BYTES_FLAG 0x02
57#define VBR_TOC_FLAG 0x04
58#define VBR_QUALITY_FLAG 0x08
59
60#define MAX_XING_HEADER_SIZE 576
61
62unsigned long find_next_frame(int fd,
63 long *offset,
64 long max_offset,
65 unsigned long reference_header);
66unsigned long mem_find_next_frame(int startpos,
67 long *offset,
68 long max_offset,
69 unsigned long reference_header,
70 unsigned char* buf, size_t buflen);
71int get_mp3file_info(int fd,
72 struct mp3info *info);
73
74int count_mp3_frames(int fd, int startpos, int filesize,
75 void (*progressfunc)(int),
76 unsigned char* buf, size_t buflen);
77
78int create_xing_header(int fd, long startpos, long filesize,
79 unsigned char *buf, unsigned long num_frames,
80 unsigned long rec_time, unsigned long header_template,
81 void (*progressfunc)(int), bool generate_toc,
82 unsigned char *tempbuf, size_t tempbuflen );
83
84extern unsigned long bytes2int(unsigned long b0,
85 unsigned long b1,
86 unsigned long b2,
87 unsigned long b3);
88
89#endif
diff --git a/lib/rbcodec/metadata/mp4.c b/lib/rbcodec/metadata/mp4.c
new file mode 100644
index 0000000000..df164436f5
--- /dev/null
+++ b/lib/rbcodec/metadata/mp4.c
@@ -0,0 +1,842 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "errno.h"
29#include "metadata.h"
30#include "metadata_common.h"
31#include "metadata_parsers.h"
32#include "logf.h"
33#include "debug.h"
34#include "replaygain.h"
35
36#ifdef DEBUGF
37#undef DEBUGF
38#define DEBUGF(...)
39#endif
40
41#define MP4_3gp6 FOURCC('3', 'g', 'p', '6')
42#define MP4_aART FOURCC('a', 'A', 'R', 'T')
43#define MP4_alac FOURCC('a', 'l', 'a', 'c')
44#define MP4_calb FOURCC(0xa9, 'a', 'l', 'b')
45#define MP4_cART FOURCC(0xa9, 'A', 'R', 'T')
46#define MP4_cgrp FOURCC(0xa9, 'g', 'r', 'p')
47#define MP4_cgen FOURCC(0xa9, 'g', 'e', 'n')
48#define MP4_chpl FOURCC('c', 'h', 'p', 'l')
49#define MP4_cnam FOURCC(0xa9, 'n', 'a', 'm')
50#define MP4_cwrt FOURCC(0xa9, 'w', 'r', 't')
51#define MP4_ccmt FOURCC(0xa9, 'c', 'm', 't')
52#define MP4_cday FOURCC(0xa9, 'd', 'a', 'y')
53#define MP4_covr FOURCC('c', 'o', 'v', 'r')
54#define MP4_disk FOURCC('d', 'i', 's', 'k')
55#define MP4_esds FOURCC('e', 's', 'd', 's')
56#define MP4_ftyp FOURCC('f', 't', 'y', 'p')
57#define MP4_gnre FOURCC('g', 'n', 'r', 'e')
58#define MP4_hdlr FOURCC('h', 'd', 'l', 'r')
59#define MP4_ilst FOURCC('i', 'l', 's', 't')
60#define MP4_isom FOURCC('i', 's', 'o', 'm')
61#define MP4_M4A FOURCC('M', '4', 'A', ' ')
62#define MP4_m4a FOURCC('m', '4', 'a', ' ') /*technically its "M4A "*/
63#define MP4_M4B FOURCC('M', '4', 'B', ' ') /*but files exist with lower case*/
64#define MP4_mdat FOURCC('m', 'd', 'a', 't')
65#define MP4_mdia FOURCC('m', 'd', 'i', 'a')
66#define MP4_mdir FOURCC('m', 'd', 'i', 'r')
67#define MP4_meta FOURCC('m', 'e', 't', 'a')
68#define MP4_minf FOURCC('m', 'i', 'n', 'f')
69#define MP4_moov FOURCC('m', 'o', 'o', 'v')
70#define MP4_mp4a FOURCC('m', 'p', '4', 'a')
71#define MP4_mp42 FOURCC('m', 'p', '4', '2')
72#define MP4_qt FOURCC('q', 't', ' ', ' ')
73#define MP4_soun FOURCC('s', 'o', 'u', 'n')
74#define MP4_stbl FOURCC('s', 't', 'b', 'l')
75#define MP4_stsd FOURCC('s', 't', 's', 'd')
76#define MP4_stts FOURCC('s', 't', 't', 's')
77#define MP4_trak FOURCC('t', 'r', 'a', 'k')
78#define MP4_trkn FOURCC('t', 'r', 'k', 'n')
79#define MP4_udta FOURCC('u', 'd', 't', 'a')
80#define MP4_extra FOURCC('-', '-', '-', '-')
81
82/* Read the tag data from an MP4 file, storing up to buffer_size bytes in
83 * buffer.
84 */
85static unsigned long read_mp4_tag(int fd, unsigned int size_left, char* buffer,
86 unsigned int buffer_left)
87{
88 unsigned int bytes_read = 0;
89
90 if (buffer_left == 0)
91 {
92 lseek(fd, size_left, SEEK_CUR); /* Skip everything */
93 }
94 else
95 {
96 /* Skip the data tag header - maybe we should parse it properly? */
97 lseek(fd, 16, SEEK_CUR);
98 size_left -= 16;
99
100 if (size_left > buffer_left)
101 {
102 read(fd, buffer, buffer_left);
103 lseek(fd, size_left - buffer_left, SEEK_CUR);
104 bytes_read = buffer_left;
105 }
106 else
107 {
108 read(fd, buffer, size_left);
109 bytes_read = size_left;
110 }
111 }
112
113 return bytes_read;
114}
115
116/* Read a string tag from an MP4 file */
117static unsigned int read_mp4_tag_string(int fd, int size_left, char** buffer,
118 unsigned int* buffer_left, char** dest)
119{
120 unsigned int bytes_read = read_mp4_tag(fd, size_left, *buffer,
121 *buffer_left > 0 ? *buffer_left - 1 : 0);
122 unsigned int length = 0;
123
124 if (bytes_read)
125 {
126 /* Do not overwrite already available metadata. Especially when reading
127 * tags with e.g. multiple genres / artists. This way only the first
128 * of multiple entries is used, all following are dropped. */
129 if (*dest == NULL)
130 {
131 (*buffer)[bytes_read] = 0; /* zero-terminate for correct strlen().*/
132 length = strlen(*buffer) + 1;
133 length = MIN(length, ID3V2_MAX_ITEM_SIZE); /* Limit item size. */
134
135 *dest = *buffer;
136 (*buffer)[length-1] = 0; /* zero-terminate buffer. */
137 *buffer_left -= length;
138 *buffer += length;
139 }
140 }
141 else
142 {
143 *dest = NULL;
144 }
145
146 return length;
147}
148
149static unsigned int read_mp4_atom(int fd, uint32_t* size,
150 uint32_t* type, uint32_t size_left)
151{
152 read_uint32be(fd, size);
153 read_uint32be(fd, type);
154
155 if (*size == 1)
156 {
157 /* FAT32 doesn't support files this big, so something seems to
158 * be wrong. (64-bit sizes should only be used when required.)
159 */
160 errno = EFBIG;
161 *type = 0;
162 return 0;
163 }
164
165 if (*size > 0)
166 {
167 if (*size > size_left)
168 {
169 size_left = 0;
170 }
171 else
172 {
173 size_left -= *size;
174 }
175
176 *size -= 8;
177 }
178 else
179 {
180 *size = size_left;
181 size_left = 0;
182 }
183
184 return size_left;
185}
186
187static unsigned int read_mp4_length(int fd, uint32_t* size)
188{
189 unsigned int length = 0;
190 int bytes = 0;
191 unsigned char c;
192
193 do
194 {
195 read(fd, &c, 1);
196 bytes++;
197 (*size)--;
198 length = (length << 7) | (c & 0x7F);
199 }
200 while ((c & 0x80) && (bytes < 4) && (*size > 0));
201
202 return length;
203}
204
205static bool read_mp4_esds(int fd, struct mp3entry* id3, uint32_t* size)
206{
207 unsigned char buf[8];
208 bool sbr = false;
209
210 lseek(fd, 4, SEEK_CUR); /* Version and flags. */
211 read(fd, buf, 1); /* Verify ES_DescrTag. */
212 *size -= 5;
213
214 if (*buf == 3)
215 {
216 /* read length */
217 if (read_mp4_length(fd, size) < 20)
218 {
219 return sbr;
220 }
221
222 lseek(fd, 3, SEEK_CUR);
223 *size -= 3;
224 }
225 else
226 {
227 lseek(fd, 2, SEEK_CUR);
228 *size -= 2;
229 }
230
231 read(fd, buf, 1); /* Verify DecoderConfigDescrTab. */
232 *size -= 1;
233
234 if (*buf != 4)
235 {
236 return sbr;
237 }
238
239 if (read_mp4_length(fd, size) < 13)
240 {
241 return sbr;
242 }
243
244 lseek(fd, 13, SEEK_CUR); /* Skip audio type, bit rates, etc. */
245 read(fd, buf, 1);
246 *size -= 14;
247
248 if (*buf != 5) /* Verify DecSpecificInfoTag. */
249 {
250 return sbr;
251 }
252
253 {
254 static const int sample_rates[] =
255 {
256 96000, 88200, 64000, 48000, 44100, 32000,
257 24000, 22050, 16000, 12000, 11025, 8000
258 };
259 unsigned long bits;
260 unsigned int length;
261 unsigned int index;
262 unsigned int type;
263
264 /* Read the (leading part of the) decoder config. */
265 length = read_mp4_length(fd, size);
266 length = MIN(length, *size);
267 length = MIN(length, sizeof(buf));
268 memset(buf, 0, sizeof(buf));
269 read(fd, buf, length);
270 *size -= length;
271
272 /* Maybe time to write a simple read_bits function... */
273
274 /* Decoder config format:
275 * Object type - 5 bits
276 * Frequency index - 4 bits
277 * Channel configuration - 4 bits
278 */
279 bits = get_long_be(buf);
280 type = bits >> 27; /* Object type - 5 bits */
281 index = (bits >> 23) & 0xf; /* Frequency index - 4 bits */
282
283 if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
284 {
285 id3->frequency = sample_rates[index];
286 }
287
288 if (type == 5)
289 {
290 unsigned int old_index = index;
291
292 sbr = true;
293 index = (bits >> 15) & 0xf; /* Frequency index - 4 bits */
294
295 if (index == 15)
296 {
297 /* 17 bits read so far... */
298 bits = get_long_be(&buf[2]);
299 id3->frequency = (bits >> 7) & 0x00ffffff;
300 }
301 else if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
302 {
303 id3->frequency = sample_rates[index];
304 }
305
306 if (old_index == index)
307 {
308 /* Downsampled SBR */
309 id3->frequency *= 2;
310 }
311 }
312 /* Skip 13 bits from above, plus 3 bits, then read 11 bits */
313 else if ((length >= 4) && (((bits >> 5) & 0x7ff) == 0x2b7))
314 {
315 /* We found an extensionAudioObjectType */
316 type = bits & 0x1f; /* Object type - 5 bits*/
317 bits = get_long_be(&buf[4]);
318
319 if (type == 5)
320 {
321 sbr = bits >> 31;
322
323 if (sbr)
324 {
325 unsigned int old_index = index;
326
327 /* 1 bit read so far */
328 index = (bits >> 27) & 0xf; /* Frequency index - 4 bits */
329
330 if (index == 15)
331 {
332 /* 5 bits read so far */
333 id3->frequency = (bits >> 3) & 0x00ffffff;
334 }
335 else if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
336 {
337 id3->frequency = sample_rates[index];
338 }
339
340 if (old_index == index)
341 {
342 /* Downsampled SBR */
343 id3->frequency *= 2;
344 }
345 }
346 }
347 }
348
349 if (!sbr && (id3->frequency <= 24000) && (length <= 2))
350 {
351 /* Double the frequency for low-frequency files without a "long"
352 * DecSpecificConfig header. The file may or may not contain SBR,
353 * but here we guess it does if the header is short. This can
354 * fail on some files, but it's the best we can do, short of
355 * decoding (parts of) the file.
356 */
357 id3->frequency *= 2;
358 sbr = true;
359 }
360 }
361
362 return sbr;
363}
364
365static bool read_mp4_tags(int fd, struct mp3entry* id3,
366 uint32_t size_left)
367{
368 uint32_t size;
369 uint32_t type;
370 unsigned int buffer_left = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
371 char* buffer = id3->id3v2buf;
372 bool cwrt = false;
373
374 do
375 {
376 size_left = read_mp4_atom(fd, &size, &type, size_left);
377
378 /* DEBUGF("Tag atom: '%c%c%c%c' (%d bytes left)\n", type >> 24 & 0xff,
379 type >> 16 & 0xff, type >> 8 & 0xff, type & 0xff, size); */
380
381 switch (type)
382 {
383 case MP4_cnam:
384 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
385 &id3->title);
386 break;
387
388 case MP4_cART:
389 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
390 &id3->artist);
391 break;
392
393 case MP4_aART:
394 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
395 &id3->albumartist);
396 break;
397
398 case MP4_cgrp:
399 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
400 &id3->grouping);
401 break;
402
403 case MP4_calb:
404 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
405 &id3->album);
406 break;
407
408 case MP4_cwrt:
409 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
410 &id3->composer);
411 cwrt = false;
412 break;
413
414 case MP4_ccmt:
415 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
416 &id3->comment);
417 break;
418
419 case MP4_cday:
420 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
421 &id3->year_string);
422
423 /* Try to parse it as a year, for the benefit of the database.
424 */
425 if(id3->year_string)
426 {
427 id3->year = atoi(id3->year_string);
428 if (id3->year < 1900)
429 {
430 id3->year = 0;
431 }
432 }
433 else
434 id3->year = 0;
435
436 break;
437
438 case MP4_gnre:
439 {
440 unsigned short genre;
441
442 read_mp4_tag(fd, size, (char*) &genre, sizeof(genre));
443 id3->genre_string = id3_get_num_genre(betoh16(genre) - 1);
444 }
445 break;
446
447 case MP4_cgen:
448 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
449 &id3->genre_string);
450 break;
451
452 case MP4_disk:
453 {
454 unsigned short n[2];
455
456 read_mp4_tag(fd, size, (char*) &n, sizeof(n));
457 id3->discnum = betoh16(n[1]);
458 }
459 break;
460
461 case MP4_trkn:
462 {
463 unsigned short n[2];
464
465 read_mp4_tag(fd, size, (char*) &n, sizeof(n));
466 id3->tracknum = betoh16(n[1]);
467 }
468 break;
469
470#ifdef HAVE_ALBUMART
471 case MP4_covr:
472 {
473 int pos = lseek(fd, 0, SEEK_CUR) + 16;
474
475 read_mp4_tag(fd, size, buffer, 8);
476 id3->albumart.type = AA_TYPE_UNKNOWN;
477 if (memcmp(buffer, "\xff\xd8\xff\xe0", 4) == 0)
478 {
479 id3->albumart.type = AA_TYPE_JPG;
480 }
481 else if (memcmp(buffer, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) == 0)
482 {
483 id3->albumart.type = AA_TYPE_PNG;
484 }
485
486 if (id3->albumart.type != AA_TYPE_UNKNOWN)
487 {
488 id3->albumart.pos = pos;
489 id3->albumart.size = size - 16;
490 id3->has_embedded_albumart = true;
491 }
492 }
493 break;
494#endif
495
496 case MP4_extra:
497 {
498 char tag_name[TAG_NAME_LENGTH];
499 uint32_t sub_size;
500
501 /* "mean" atom */
502 read_uint32be(fd, &sub_size);
503 size -= sub_size;
504 lseek(fd, sub_size - 4, SEEK_CUR);
505 /* "name" atom */
506 read_uint32be(fd, &sub_size);
507 size -= sub_size;
508 lseek(fd, 8, SEEK_CUR);
509 sub_size -= 12;
510
511 if (sub_size > sizeof(tag_name) - 1)
512 {
513 read(fd, tag_name, sizeof(tag_name) - 1);
514 lseek(fd, sub_size - (sizeof(tag_name) - 1), SEEK_CUR);
515 tag_name[sizeof(tag_name) - 1] = 0;
516 }
517 else
518 {
519 read(fd, tag_name, sub_size);
520 tag_name[sub_size] = 0;
521 }
522
523 if ((strcasecmp(tag_name, "composer") == 0) && !cwrt)
524 {
525 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
526 &id3->composer);
527 }
528 else if (strcasecmp(tag_name, "iTunSMPB") == 0)
529 {
530 char value[TAG_VALUE_LENGTH];
531 char* value_p = value;
532 char* any;
533 unsigned int length = sizeof(value);
534
535 read_mp4_tag_string(fd, size, &value_p, &length, &any);
536 id3->lead_trim = get_itunes_int32(value, 1);
537 id3->tail_trim = get_itunes_int32(value, 2);
538 DEBUGF("AAC: lead_trim %d, tail_trim %d\n",
539 id3->lead_trim, id3->tail_trim);
540 }
541 else if (strcasecmp(tag_name, "musicbrainz track id") == 0)
542 {
543 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
544 &id3->mb_track_id);
545 }
546 else if ((strcasecmp(tag_name, "album artist") == 0))
547 {
548 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
549 &id3->albumartist);
550 }
551 else
552 {
553 char* any = NULL;
554 unsigned int length = read_mp4_tag_string(fd, size,
555 &buffer, &buffer_left, &any);
556
557 if (length > 0)
558 {
559 /* Re-use the read buffer as the dest buffer... */
560 buffer -= length;
561 buffer_left += length;
562
563 parse_replaygain(tag_name, buffer, id3);
564 }
565 }
566 }
567 break;
568
569 default:
570 lseek(fd, size, SEEK_CUR);
571 break;
572 }
573 }
574 while ((size_left > 0) && (errno == 0));
575
576 return true;
577}
578
579static bool read_mp4_container(int fd, struct mp3entry* id3,
580 uint32_t size_left)
581{
582 uint32_t size = 0;
583 uint32_t type = 0;
584 uint32_t handler = 0;
585 bool rc = true;
586 bool done = false;
587
588 do
589 {
590 size_left = read_mp4_atom(fd, &size, &type, size_left);
591
592 /* DEBUGF("Atom: '%c%c%c%c' (0x%08lx, %lu bytes left)\n",
593 (int) ((type >> 24) & 0xff), (int) ((type >> 16) & 0xff),
594 (int) ((type >> 8) & 0xff), (int) (type & 0xff),
595 type, size); */
596
597 switch (type)
598 {
599 case MP4_ftyp:
600 {
601 uint32_t id;
602
603 read_uint32be(fd, &id);
604 size -= 4;
605
606 if ((id != MP4_M4A) && (id != MP4_M4B) && (id != MP4_mp42)
607 && (id != MP4_qt) && (id != MP4_3gp6) && (id != MP4_m4a)
608 && (id != MP4_isom))
609 {
610 DEBUGF("Unknown MP4 file type: '%c%c%c%c'\n",
611 (int)(id >> 24 & 0xff), (int)(id >> 16 & 0xff),
612 (int)(id >> 8 & 0xff), (int)(id & 0xff));
613 return false;
614 }
615 }
616 break;
617
618 case MP4_meta:
619 lseek(fd, 4, SEEK_CUR); /* Skip version */
620 size -= 4;
621 /* Fall through */
622
623 case MP4_moov:
624 case MP4_udta:
625 case MP4_mdia:
626 case MP4_stbl:
627 case MP4_trak:
628 rc = read_mp4_container(fd, id3, size);
629 size = 0;
630 break;
631
632 case MP4_ilst:
633 /* We need at least a size of 8 to read the next atom. */
634 if (handler == MP4_mdir && size>8)
635 {
636 rc = read_mp4_tags(fd, id3, size);
637 size = 0;
638 }
639 break;
640
641 case MP4_minf:
642 if (handler == MP4_soun)
643 {
644 rc = read_mp4_container(fd, id3, size);
645 size = 0;
646 }
647 break;
648
649 case MP4_stsd:
650 lseek(fd, 8, SEEK_CUR);
651 size -= 8;
652 rc = read_mp4_container(fd, id3, size);
653 size = 0;
654 break;
655
656 case MP4_hdlr:
657 lseek(fd, 8, SEEK_CUR);
658 read_uint32be(fd, &handler);
659 size -= 12;
660 /* DEBUGF(" Handler '%c%c%c%c'\n", handler >> 24 & 0xff,
661 handler >> 16 & 0xff, handler >> 8 & 0xff,handler & 0xff); */
662 break;
663
664 case MP4_stts:
665 {
666 uint32_t entries;
667 unsigned int i;
668
669 /* Reset to false. */
670 id3->needs_upsampling_correction = false;
671
672 lseek(fd, 4, SEEK_CUR);
673 read_uint32be(fd, &entries);
674 id3->samples = 0;
675
676 for (i = 0; i < entries; i++)
677 {
678 uint32_t n;
679 uint32_t l;
680
681 read_uint32be(fd, &n);
682 read_uint32be(fd, &l);
683
684 /* Some AAC file use HE profile. In this case the number
685 * of output samples is doubled to a maximum of 2048
686 * samples per frame. This means that files which already
687 * report a frame size of 2048 in their header will not
688 * need any further special handling. */
689 if (id3->codectype==AFMT_MP4_AAC_HE && l<=1024)
690 {
691 id3->samples += n * l * 2;
692 id3->needs_upsampling_correction = true;
693 }
694 else
695 {
696 id3->samples += n * l;
697 }
698 }
699
700 size = 0;
701 }
702 break;
703
704 case MP4_mp4a:
705 {
706 uint32_t subsize;
707 uint32_t subtype;
708
709 /* Move to the next expected mp4 atom. */
710 lseek(fd, 28, SEEK_CUR);
711 read_mp4_atom(fd, &subsize, &subtype, size);
712 size -= 36;
713
714 if (subtype == MP4_esds)
715 {
716 /* Read esds metadata and return if AAC-HE/SBR is used. */
717 if (read_mp4_esds(fd, id3, &size))
718 id3->codectype = AFMT_MP4_AAC_HE;
719 else
720 id3->codectype = AFMT_MP4_AAC;
721 }
722 }
723 break;
724
725 case MP4_alac:
726 {
727 uint32_t frequency;
728 uint32_t subsize;
729 uint32_t subtype;
730
731 /* Move to the next expected mp4 atom. */
732 lseek(fd, 28, SEEK_CUR);
733 read_mp4_atom(fd, &subsize, &subtype, size);
734 size -= 36;
735#if 0
736 /* We might need to parse for the alac metadata atom. */
737 while (!((subsize==28) && (subtype==MP4_alac)) && (size>0))
738 {
739 lseek(fd, -7, SEEK_CUR);
740 read_mp4_atom(fd, &subsize, &subtype, size);
741 size -= 1;
742 errno = 0; /* will most likely be set while parsing */
743 }
744#endif
745 if (subtype == MP4_alac)
746 {
747 lseek(fd, 24, SEEK_CUR);
748 read_uint32be(fd, &frequency);
749 size -= 28;
750 id3->frequency = frequency;
751 id3->codectype = AFMT_MP4_ALAC;
752 }
753 }
754 break;
755
756 case MP4_mdat:
757 /* Some AAC files appear to contain additional empty mdat chunks.
758 Ignore them. */
759 if(size == 0)
760 break;
761 id3->filesize = size;
762 if(id3->samples > 0) {
763 /* We've already seen the moov chunk. */
764 done = true;
765 }
766 break;
767
768 case MP4_chpl:
769 {
770 /* ADDME: add support for real chapters. Right now it's only
771 * used for Nero's gapless hack */
772 uint8_t chapters;
773 uint64_t timestamp;
774
775 lseek(fd, 8, SEEK_CUR);
776 read_uint8(fd, &chapters);
777 size -= 9;
778
779 /* the first chapter will be used as the lead_trim */
780 if (chapters > 0) {
781 read_uint64be(fd, &timestamp);
782 id3->lead_trim = (timestamp * id3->frequency) / 10000000;
783 size -= 8;
784 }
785 }
786 break;
787
788 default:
789 break;
790 }
791
792 /* Skip final seek. */
793 if (!done)
794 {
795 lseek(fd, size, SEEK_CUR);
796 }
797 } while (rc && (size_left > 0) && (errno == 0) && !done);
798
799 return rc;
800}
801
802bool get_mp4_metadata(int fd, struct mp3entry* id3)
803{
804 id3->codectype = AFMT_UNKNOWN;
805 id3->filesize = 0;
806 errno = 0;
807
808 if (read_mp4_container(fd, id3, filesize(fd)) && (errno == 0)
809 && (id3->samples > 0) && (id3->frequency > 0)
810 && (id3->filesize > 0))
811 {
812 if (id3->codectype == AFMT_UNKNOWN)
813 {
814 logf("Not an ALAC or AAC file");
815 return false;
816 }
817
818 id3->length = ((int64_t) id3->samples * 1000) / id3->frequency;
819
820 id3->vbr = true; /* ALAC is native VBR, AAC very unlikely is CBR. */
821
822 if (id3->length <= 0)
823 {
824 logf("mp4 length invalid!");
825 return false;
826 }
827
828 id3->bitrate = ((int64_t) id3->filesize * 8) / id3->length;
829 DEBUGF("MP4 bitrate %d, frequency %ld Hz, length %ld ms\n",
830 id3->bitrate, id3->frequency, id3->length);
831 }
832 else
833 {
834 logf("MP4 metadata error");
835 DEBUGF("MP4 metadata error. errno %d, samples %ld, frequency %ld, "
836 "filesize %ld\n", errno, id3->samples, id3->frequency,
837 id3->filesize);
838 return false;
839 }
840
841 return true;
842}
diff --git a/lib/rbcodec/metadata/mpc.c b/lib/rbcodec/metadata/mpc.c
new file mode 100644
index 0000000000..0b75ed04dd
--- /dev/null
+++ b/lib/rbcodec/metadata/mpc.c
@@ -0,0 +1,220 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Thom Johansen
11 * Copyright (C) 2010 Andree Buschmann
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include <string.h>
24#include <stdio.h>
25#include <inttypes.h>
26#include "system.h"
27#include "metadata.h"
28#include "metadata_common.h"
29#include "metadata_parsers.h"
30#include "logf.h"
31#include "replaygain.h"
32#include "fixedpoint.h"
33
34/* Needed for replay gain and clipping prevention of SV8 files. */
35#define SV8_TO_SV7_CONVERT_GAIN (6482) /* 64.82 * 100, MPC_OLD_GAIN_REF */
36#define SV8_TO_SV7_CONVERT_PEAK (23119) /* 256 * 20 * log10(32768) */
37
38static int set_replaygain_sv7(struct mp3entry* id3,
39 bool album,
40 long value,
41 long used)
42{
43 long gain = (int16_t) ((value >> 16) & 0xffff);
44 long peak = (uint16_t) (value & 0xffff);
45
46 /* We use a peak value of 0 to indicate a given gain type isn't used. */
47 if (peak != 0) {
48 /* Save the ReplayGain data to id3-structure for further processing. */
49 parse_replaygain_int(album, gain * 512 / 100, peak << 9, id3);
50 }
51
52 return used;
53}
54
55static int set_replaygain_sv8(struct mp3entry* id3,
56 bool album,
57 long gain,
58 long peak,
59 long used)
60{
61 gain = (long)(SV8_TO_SV7_CONVERT_GAIN - ((gain*100)/256));
62
63 /* Transform SV8's logarithmic peak representation to the desired linear
64 * representation: linear = pow(10, peak/256/20).
65 *
66 * FP_BITS = 24 bits = desired fp representation for dsp routines
67 * FRAC_BITS = 12 bits = resolution used for fp_bits
68 * fp_factor(peak*(1<<FRAC_BITS)/256, FRAC_BITS) << (FP_BITS-FRAC_BITS)
69 **/
70 peak = (fp_factor((peak-SV8_TO_SV7_CONVERT_PEAK)*16, 12) << 12);
71
72 /* We use a peak value of 0 to indicate a given gain type isn't used. */
73 if (peak != 0) {
74 /* Save the ReplayGain data to id3-structure for further processing. */
75 parse_replaygain_int(album, gain * 512 / 100, peak, id3);
76 }
77
78 return used;
79}
80
81static int sv8_get_size(uint8_t *buffer, int index, uint64_t *p_size)
82{
83 unsigned char tmp;
84 uint64_t size = 0;
85
86 do {
87 tmp = buffer[index++];
88 size = (size << 7) | (tmp & 0x7F);
89 } while((tmp & 0x80));
90
91 *p_size = size;
92 return index;
93}
94
95bool get_musepack_metadata(int fd, struct mp3entry *id3)
96{
97 static const int32_t sfreqs[4] = { 44100, 48000, 37800, 32000 };
98 uint32_t header[8];
99 uint64_t samples = 0;
100 int i;
101
102 if (!skip_id3v2(fd, id3))
103 return false;
104 if (read(fd, header, 4*8) != 4*8) return false;
105 /* Musepack files are little endian, might need swapping */
106 for (i = 1; i < 8; i++)
107 header[i] = letoh32(header[i]);
108 if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */
109 unsigned int streamversion;
110 header[0] = letoh32(header[0]);
111 streamversion = (header[0] >> 24) & 15;
112 if (streamversion == 7) {
113 unsigned int gapless = (header[5] >> 31) & 0x0001;
114 unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff;
115 unsigned int bufused = 0;
116
117 id3->frequency = sfreqs[(header[2] >> 16) & 0x0003];
118 samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */
119 if (gapless)
120 samples -= 1152 - last_frame_samples;
121 else
122 samples -= 481; /* Musepack subband synth filter delay */
123
124 bufused = set_replaygain_sv7(id3, false, header[3], bufused);
125 bufused = set_replaygain_sv7(id3, true , header[4], bufused);
126
127 id3->codectype = AFMT_MPC_SV7;
128 } else {
129 return false; /* only SV7 is allowed within a "MP+" signature */
130 }
131 } else if (!memcmp(header, "MPCK", 4)) { /* Compare to sig "MPCK" */
132 uint8_t sv8_header[32];
133 /* 4 bytes 'MPCK' */
134 lseek(fd, 4, SEEK_SET);
135 if (read(fd, sv8_header, 2) != 2) return false; /* read frame ID */
136 if (!memcmp(sv8_header, "SH", 2)) { /* Stream Header ID */
137 int32_t k = 0;
138 uint32_t streamversion;
139 uint64_t size = 0; /* tag size */
140 uint64_t dummy = 0; /* used to dummy read data from header */
141
142 /* 4 bytes 'MPCK' + 2 'SH' */
143 lseek(fd, 6, SEEK_SET);
144 if (read(fd, sv8_header, 32) != 32) return false;
145
146 /* Read the size of 'SH'-tag */
147 k = sv8_get_size(sv8_header, k, &size);
148
149 /* Skip crc32 */
150 k += 4;
151
152 /* Read stream version */
153 streamversion = sv8_header[k++];
154 if (streamversion != 8) return false; /* Only SV8 is allowed. */
155
156 /* Number of samples */
157 k = sv8_get_size(sv8_header, k, &samples);
158
159 /* Number of leading zero-samples */
160 k = sv8_get_size(sv8_header, k, &dummy);
161
162 /* Sampling frequency */
163 id3->frequency = sfreqs[(sv8_header[k++] >> 5) & 0x0003];
164
165 /* Number of channels */
166 id3->channels = (sv8_header[k++] >> 4) + 1;
167
168 /* Skip to next tag: k = size -2 */
169 k = size - 2;
170
171 if (!memcmp(sv8_header+k, "RG", 2)) { /* Replay Gain ID */
172 long peak, gain;
173 int bufused = 0;
174
175 k += 2; /* 2 bytes 'RG' */
176
177 /* sv8_get_size must be called to skip the right amount of
178 * bits within the header data. */
179 k = sv8_get_size(sv8_header, k, &size);
180
181 /* Read and set replay gain */
182 if (sv8_header[k++] == 1) {
183 /* Title's peak and gain */
184 gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
185 peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
186 bufused += set_replaygain_sv8(id3, false, gain, peak, bufused);
187
188 /* Album's peak and gain */
189 gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
190 peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
191 bufused += set_replaygain_sv8(id3, true , gain, peak, bufused);
192 }
193 }
194
195 id3->codectype = AFMT_MPC_SV8;
196 } else {
197 /* No sv8 stream header found */
198 return false;
199 }
200 } else {
201 return false; /* SV4-6 is not supported anymore */
202 }
203
204 id3->vbr = true;
205 /* Estimate bitrate, we should probably subtract the various header sizes
206 here for super-accurate results */
207 id3->length = ((int64_t) samples * 1000) / id3->frequency;
208
209 if (id3->length <= 0)
210 {
211 logf("mpc length invalid!");
212 return false;
213 }
214
215 id3->filesize = filesize(fd);
216 id3->bitrate = id3->filesize * 8 / id3->length;
217
218 read_ape_tags(fd, id3);
219 return true;
220}
diff --git a/lib/rbcodec/metadata/nsf.c b/lib/rbcodec/metadata/nsf.c
new file mode 100644
index 0000000000..2fa6f36b12
--- /dev/null
+++ b/lib/rbcodec/metadata/nsf.c
@@ -0,0 +1,278 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12#include "string-extra.h"
13
14/* NOTE: This file was modified to work properly with the new nsf codec based
15 on Game_Music_Emu */
16
17struct NESM_HEADER
18{
19 uint32_t nHeader;
20 uint8_t nHeaderExtra;
21 uint8_t nVersion;
22 uint8_t nTrackCount;
23 uint8_t nInitialTrack;
24 uint16_t nLoadAddress;
25 uint16_t nInitAddress;
26 uint16_t nPlayAddress;
27 uint8_t szGameTitle[32];
28 uint8_t szArtist[32];
29 uint8_t szCopyright[32];
30 uint16_t nSpeedNTSC;
31 uint8_t nBankSwitch[8];
32 uint16_t nSpeedPAL;
33 uint8_t nNTSC_PAL;
34 uint8_t nExtraChip;
35 uint8_t nExpansion[4];
36} __attribute__((packed));
37
38struct NSFE_INFOCHUNK
39{
40 uint16_t nLoadAddress;
41 uint16_t nInitAddress;
42 uint16_t nPlayAddress;
43 uint8_t nIsPal;
44 uint8_t nExt;
45 uint8_t nTrackCount;
46 uint8_t nStartingTrack;
47} __attribute__((packed));
48
49
50#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
51#define CHUNK_INFO 0x0001
52#define CHUNK_DATA 0x0002
53#define CHUNK_NEND 0x0004
54#define CHUNK_plst 0x0008
55#define CHUNK_time 0x0010
56#define CHUNK_fade 0x0020
57#define CHUNK_tlbl 0x0040
58#define CHUNK_auth 0x0080
59#define CHUNK_BANK 0x0100
60
61static bool parse_nsfe(int fd, struct mp3entry *id3)
62{
63 unsigned int chunks_found = 0;
64 long track_count = 0;
65 long playlist_count = 0;
66
67 struct NSFE_INFOCHUNK info;
68 memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
69
70 /* default values */
71 info.nTrackCount = 1;
72 id3->length = 150 * 1000;
73
74 /* begin reading chunks */
75 while (!(chunks_found & CHUNK_NEND))
76 {
77 uint32_t chunk_size, chunk_type;
78
79 if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
80 return false;
81
82 if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t))
83 return false;
84
85 switch (chunk_type)
86 {
87 /* first three types are mandatory (but don't worry about NEND
88 anyway) */
89 case CHAR4_CONST('I', 'N', 'F', 'O'):
90 {
91 if (chunks_found & CHUNK_INFO)
92 return false; /* only one info chunk permitted */
93
94 chunks_found |= CHUNK_INFO;
95
96 /* minimum size */
97 if (chunk_size < 8)
98 return false;
99
100 ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size);
101
102 if (read(fd, &info, size) != size)
103 return false;
104
105 if (size >= 9)
106 track_count = info.nTrackCount;
107
108 chunk_size -= size;
109 break;
110 }
111
112 case CHAR4_CONST('D', 'A', 'T', 'A'):
113 {
114 if (!(chunks_found & CHUNK_INFO))
115 return false;
116
117 if (chunks_found & CHUNK_DATA)
118 return false; /* only one may exist */
119
120 if (chunk_size < 1)
121 return false;
122
123 chunks_found |= CHUNK_DATA;
124 break;
125 }
126
127 case CHAR4_CONST('N', 'E', 'N', 'D'):
128 {
129 /* just end parsing regardless of whether or not this really is the
130 last chunk/data (but it _should_ be) */
131 chunks_found |= CHUNK_NEND;
132 continue;
133 }
134
135 /* remaining types are optional */
136
137 case CHAR4_CONST('a', 'u', 't', 'h'):
138 {
139 if (chunks_found & CHUNK_auth)
140 return false; /* only one may exist */
141
142 chunks_found |= CHUNK_auth;
143
144 /* szGameTitle, szArtist, szCopyright */
145 char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
146
147 char *p = id3->id3v2buf;
148 long buf_rem = sizeof (id3->id3v2buf);
149 unsigned int i;
150
151 for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++)
152 {
153 long len = read_string(fd, p, buf_rem, '\0', chunk_size);
154
155 if (len < 0)
156 return false;
157
158 *ar[i] = p;
159 p += len;
160 buf_rem -= len;
161
162 if (chunk_size >= (uint32_t)len)
163 chunk_size -= len;
164 else
165 chunk_size = 0;
166 }
167
168 break;
169 }
170
171 case CHAR4_CONST('p', 'l', 's', 't'):
172 {
173 if (chunks_found & CHUNK_plst)
174 return false; /* only one may exist */
175
176 chunks_found |= CHUNK_plst;
177
178 /* each byte is the index of one track */
179 playlist_count = chunk_size;
180 break;
181 }
182
183 case CHAR4_CONST('t', 'i', 'm', 'e'):
184 case CHAR4_CONST('f', 'a', 'd', 'e'):
185 case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
186 {
187 /* don't care how many of these there are even though there should
188 be only one */
189 if (!(chunks_found & CHUNK_INFO))
190 return false;
191
192 case CHAR4_CONST('B', 'A', 'N', 'K'):
193 break;
194 }
195
196 default: /* unknown chunk */
197 {
198 /* check the first byte */
199 chunk_type = (uint8_t)chunk_type;
200
201 /* chunk is vital... don't continue */
202 if(chunk_type >= 'A' && chunk_type <= 'Z')
203 return false;
204
205 /* otherwise, just skip it */
206 break;
207 }
208 } /* end switch */
209
210 lseek(fd, chunk_size, SEEK_CUR);
211 } /* end while */
212
213 if (track_count | playlist_count)
214 id3->length = MAX(track_count, playlist_count)*1000;
215
216 /* Single subtrack files will be treated differently
217 by gme's nsf codec */
218 if (id3->length <= 1000) id3->length = 150 * 1000;
219
220 /*
221 * if we exited the while loop without a 'return', we must have hit an NEND
222 * chunk if this is the case, the file was layed out as it was expected.
223 * now.. make sure we found both an info chunk, AND a data chunk... since
224 * these are minimum requirements for a valid NSFE file
225 */
226 return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) ==
227 (CHUNK_INFO | CHUNK_DATA);
228}
229
230static bool parse_nesm(int fd, struct mp3entry *id3)
231{
232 struct NESM_HEADER hdr;
233 char *p = id3->id3v2buf;
234
235 lseek(fd, 0, SEEK_SET);
236 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
237 return false;
238
239 /* Length */
240 id3->length = (hdr.nTrackCount > 1 ? hdr.nTrackCount : 150) * 1000;
241
242 /* Title */
243 id3->title = p;
244 p += strlcpy(p, hdr.szGameTitle, 32) + 1;
245
246 /* Artist */
247 id3->artist = p;
248 p += strlcpy(p, hdr.szArtist, 32) + 1;
249
250 /* Copyright (per codec) */
251 id3->album = p;
252 strlcpy(p, hdr.szCopyright, 32);
253
254 return true;
255}
256
257bool get_nsf_metadata(int fd, struct mp3entry* id3)
258{
259 uint32_t nsf_type;
260 if (lseek(fd, 0, SEEK_SET) < 0 ||
261 read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type))
262 return false;
263
264 id3->vbr = false;
265 id3->filesize = filesize(fd);
266 /* we only render 16 bits, 44.1KHz, Mono */
267 id3->bitrate = 706;
268 id3->frequency = 44100;
269
270 if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E'))
271 return parse_nsfe(fd, id3);
272 else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M'))
273 return parse_nesm(fd, id3);
274
275 /* not a valid format*/
276 return false;
277}
278
diff --git a/lib/rbcodec/metadata/ogg.c b/lib/rbcodec/metadata/ogg.c
new file mode 100644
index 0000000000..3a3cb29998
--- /dev/null
+++ b/lib/rbcodec/metadata/ogg.c
@@ -0,0 +1,215 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33/* A simple parser to read vital metadata from an Ogg Vorbis file.
34 * Can also handle parsing Ogg Speex files for metadata. Returns
35 * false if metadata needed by the codec couldn't be read.
36 */
37bool get_ogg_metadata(int fd, struct mp3entry* id3)
38{
39 /* An Ogg File is split into pages, each starting with the string
40 * "OggS". Each page has a timestamp (in PCM samples) referred to as
41 * the "granule position".
42 *
43 * An Ogg Vorbis has the following structure:
44 * 1) Identification header (containing samplerate, numchannels, etc)
45 * 2) Comment header - containing the Vorbis Comments
46 * 3) Setup header - containing codec setup information
47 * 4) Many audio packets...
48 *
49 * An Ogg Speex has the following structure:
50 * 1) Identification header (containing samplerate, numchannels, etc)
51 * Described in this page: (http://www.speex.org/manual2/node7.html)
52 * 2) Comment header - containing the Vorbis Comments
53 * 3) Many audio packets.
54 */
55
56 /* Use the path name of the id3 structure as a temporary buffer. */
57 unsigned char* buf = (unsigned char *)id3->path;
58 long comment_size;
59 long remaining = 0;
60 long last_serial = 0;
61 long serial, r;
62 int segments, header_size;
63 int i;
64 bool eof = false;
65
66 /* 92 bytes is enough for both Vorbis and Speex headers */
67 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 92) < 92))
68 {
69 return false;
70 }
71
72 /* All Ogg streams start with OggS */
73 if (memcmp(buf, "OggS", 4) != 0)
74 {
75 return false;
76 }
77
78 /* Check for format magic and then get metadata */
79 if (memcmp(&buf[29], "vorbis", 6) == 0)
80 {
81 id3->codectype = AFMT_OGG_VORBIS;
82 id3->frequency = get_long_le(&buf[40]);
83 id3->vbr = true;
84
85 /* Comments are in second Ogg page (byte 58 onwards for Vorbis) */
86 if (lseek(fd, 58, SEEK_SET) < 0)
87 {
88 return false;
89 }
90 }
91 else if (memcmp(&buf[28], "Speex ", 8) == 0)
92 {
93 id3->codectype = AFMT_SPEEX;
94 id3->frequency = get_slong(&buf[64]);
95 id3->vbr = get_long_le(&buf[88]);
96
97 header_size = get_long_le(&buf[60]);
98
99 /* Comments are in second Ogg page (byte 108 onwards for Speex) */
100 if (lseek(fd, 28 + header_size, SEEK_SET) < 0)
101 {
102 return false;
103 }
104 }
105 else
106 {
107 /* Unsupported format, try to print the marker, catches Ogg/FLAC at least */
108 DEBUGF("Usupported format in Ogg stream: %16s\n", &buf[28]);
109 return false;
110 }
111
112 id3->filesize = filesize(fd);
113
114 /* We need to ensure the serial number from this page is the same as the
115 * one from the last page (since we only support a single bitstream).
116 */
117 serial = get_long_le(&buf[14]);
118 comment_size = read_vorbis_tags(fd, id3, remaining);
119
120 /* We now need to search for the last page in the file - identified by
121 * by ('O','g','g','S',0) and retrieve totalsamples.
122 */
123
124 /* A page is always < 64 kB */
125 if (lseek(fd, -(MIN(64 * 1024, id3->filesize)), SEEK_END) < 0)
126 {
127 return false;
128 }
129
130 remaining = 0;
131
132 while (!eof)
133 {
134 r = read(fd, &buf[remaining], MAX_PATH - remaining);
135
136 if (r <= 0)
137 {
138 eof = true;
139 }
140 else
141 {
142 remaining += r;
143 }
144
145 /* Inefficient (but simple) search */
146 i = 0;
147
148 while (i < (remaining - 3))
149 {
150 if ((buf[i] == 'O') && (memcmp(&buf[i], "OggS", 4) == 0))
151 {
152 if (i < (remaining - 17))
153 {
154 /* Note that this only reads the low 32 bits of a
155 * 64 bit value.
156 */
157 id3->samples = get_long_le(&buf[i + 6]);
158 last_serial = get_long_le(&buf[i + 14]);
159
160 /* If this page is very small the beginning of the next
161 * header could be in buffer. Jump near end of this header
162 * and continue */
163 i += 27;
164 }
165 else
166 {
167 break;
168 }
169 }
170 else
171 {
172 i++;
173 }
174 }
175
176 if (i < remaining)
177 {
178 /* Move the remaining bytes to start of buffer.
179 * Reuse var 'segments' as it is no longer needed */
180 segments = 0;
181 while (i < remaining)
182 {
183 buf[segments++] = buf[i++];
184 }
185 remaining = segments;
186 }
187 else
188 {
189 /* Discard the rest of the buffer */
190 remaining = 0;
191 }
192 }
193
194 /* This file has mutiple vorbis bitstreams (or is corrupt). */
195 /* FIXME we should display an error here. */
196 if (serial != last_serial)
197 {
198 logf("serialno mismatch");
199 logf("%ld", serial);
200 logf("%ld", last_serial);
201 return false;
202 }
203
204 id3->length = ((int64_t) id3->samples * 1000) / id3->frequency;
205 if (id3->length <= 0)
206 {
207 logf("ogg length invalid!");
208 return false;
209 }
210
211 id3->bitrate = (((int64_t) id3->filesize - comment_size) * 8) / id3->length;
212
213 return true;
214}
215
diff --git a/lib/rbcodec/metadata/oma.c b/lib/rbcodec/metadata/oma.c
new file mode 100644
index 0000000000..b82c0a4f73
--- /dev/null
+++ b/lib/rbcodec/metadata/oma.c
@@ -0,0 +1,189 @@
1/*
2 * Sony OpenMG (OMA) demuxer
3 *
4 * Copyright (c) 2008 Maxim Poliakovski
5 * 2008 Benjamin Larsson
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24/**
25 * @file oma.c
26 * This is a demuxer for Sony OpenMG Music files
27 *
28 * Known file extensions: ".oma", "aa3"
29 * The format of such files consists of three parts:
30 * - "ea3" header carrying overall info and metadata.
31 * - "EA3" header is a Sony-specific header containing information about
32 * the OpenMG file: codec type (usually ATRAC, can also be MP3 or WMA),
33 * codec specific info (packet size, sample rate, channels and so on)
34 * and DRM related info (file encryption, content id).
35 * - Sound data organized in packets follow the EA3 header
36 * (can be encrypted using the Sony DRM!).
37 *
38 * LIMITATIONS: This version supports only plain (unencrypted) OMA files.
39 * If any DRM-protected (encrypted) file is encountered you will get the
40 * corresponding error message. Try to remove the encryption using any
41 * Sony software (for example SonicStage).
42 * CODEC SUPPORT: Only ATRAC3 codec is currently supported!
43 */
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <inttypes.h>
48#include <string.h>
49#include "metadata.h"
50#include "metadata_parsers.h"
51
52#define EA3_HEADER_SIZE 96
53
54#if 0
55#define DEBUGF printf
56#else
57#define DEBUGF(...)
58#endif
59
60/* Various helper macros taken from ffmpeg for reading *
61 * and writing buffers with a specified endianess. */
62# define AV_RB16(x) \
63 ((((const uint8_t*)(x))[0] << 8) | \
64 ((const uint8_t*)(x))[1])
65# define AV_RB24(x) \
66 ((((const uint8_t*)(x))[0] << 16) | \
67 (((const uint8_t*)(x))[1] << 8) | \
68 ((const uint8_t*)(x))[2])
69# define AV_RB32(x) \
70 ((((const uint8_t*)(x))[0] << 24) | \
71 (((const uint8_t*)(x))[1] << 16) | \
72 (((const uint8_t*)(x))[2] << 8) | \
73 ((const uint8_t*)(x))[3])
74# define AV_WL32(p, d) do { \
75 ((uint8_t*)(p))[0] = (d); \
76 ((uint8_t*)(p))[1] = (d)>>8; \
77 ((uint8_t*)(p))[2] = (d)>>16; \
78 ((uint8_t*)(p))[3] = (d)>>24; \
79 } while(0)
80# define AV_WL16(p, d) do { \
81 ((uint8_t*)(p))[0] = (d); \
82 ((uint8_t*)(p))[1] = (d)>>8; \
83 } while(0)
84
85/* Different codecs that could be present in a Sony OMA *
86 * container file. */
87enum {
88 OMA_CODECID_ATRAC3 = 0,
89 OMA_CODECID_ATRAC3P = 1,
90 OMA_CODECID_MP3 = 3,
91 OMA_CODECID_LPCM = 4,
92 OMA_CODECID_WMA = 5,
93};
94
95/* FIXME: This functions currently read different file *
96 * parameters required for decoding. It still *
97 * does not read the metadata - which should be *
98 * present in the ea3 (first) header. The *
99 * metadata in ea3 is stored as a variation of *
100 * the ID3v2 metadata format. */
101static int oma_read_header(int fd, struct mp3entry* id3)
102{
103 static const uint16_t srate_tab[6] = {320,441,480,882,960,0};
104 int ret, ea3_taglen, EA3_pos, jsflag;
105 uint32_t codec_params;
106 int16_t eid;
107 uint8_t buf[EA3_HEADER_SIZE];
108
109 ret = read(fd, buf, 10);
110 if (ret != 10)
111 return -1;
112
113 ea3_taglen = ((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f);
114
115 EA3_pos = ea3_taglen + 10;
116 if (buf[5] & 0x10)
117 EA3_pos += 10;
118
119 lseek(fd, EA3_pos, SEEK_SET);
120 ret = read(fd, buf, EA3_HEADER_SIZE);
121 if (ret != EA3_HEADER_SIZE)
122 return -1;
123
124 if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}),3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) {
125 DEBUGF("Couldn't find the EA3 header !\n");
126 return -1;
127 }
128
129 eid = AV_RB16(&buf[6]);
130 if (eid != -1 && eid != -128) {
131 DEBUGF("Encrypted file! Eid: %d\n", eid);
132 return -1;
133 }
134
135 codec_params = AV_RB24(&buf[33]);
136
137 switch (buf[32]) {
138 case OMA_CODECID_ATRAC3:
139 id3->frequency = srate_tab[(codec_params >> 13) & 7]*100;
140 if (id3->frequency != 44100) {
141 DEBUGF("Unsupported sample rate, send sample file to developers: %d\n", id3->frequency);
142 return -1;
143 }
144
145 id3->bytesperframe = (codec_params & 0x3FF) * 8;
146 id3->codectype = AFMT_OMA_ATRAC3;
147 jsflag = (codec_params >> 17) & 1; /* get stereo coding mode, 1 for joint-stereo */
148
149 id3->bitrate = id3->frequency * id3->bytesperframe * 8 / (1024 * 1000);
150
151 /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */
152 /* ATRAC3 expects and extra-data size of 14 bytes for wav format, and *
153 * looks for that in the id3v2buf. */
154 id3->extradata_size = 14;
155 AV_WL16(&id3->id3v2buf[0], 1); // always 1
156 AV_WL32(&id3->id3v2buf[2], id3->frequency); // samples rate
157 AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode
158 AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode
159 AV_WL16(&id3->id3v2buf[10], 1); // always 1
160 AV_WL16(&id3->id3v2buf[12], 0); // always 0
161
162 id3->channels = 2;
163 DEBUGF("sample_rate = %d\n", id3->frequency);
164 DEBUGF("frame_size = %d\n", id3->bytesperframe);
165 DEBUGF("stereo_coding_mode = %d\n", jsflag);
166 break;
167 default:
168 DEBUGF("Unsupported codec %d!\n",buf[32]);
169 return -1;
170 break;
171 }
172
173 /* Store the the offset of the first audio frame, to be able to seek to it *
174 * directly in atrac3_oma.codec. */
175 id3->first_frame_offset = EA3_pos + EA3_HEADER_SIZE;
176 return 0;
177}
178
179bool get_oma_metadata(int fd, struct mp3entry* id3)
180{
181 if(oma_read_header(fd, id3) < 0)
182 return false;
183
184 /* Currently, there's no means of knowing the duration *
185 * directly from the the file so we calculate it. */
186 id3->filesize = filesize(fd);
187 id3->length = ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate;
188 return true;
189}
diff --git a/lib/rbcodec/metadata/replaygain.c b/lib/rbcodec/metadata/replaygain.c
new file mode 100644
index 0000000000..a178321385
--- /dev/null
+++ b/lib/rbcodec/metadata/replaygain.c
@@ -0,0 +1,222 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <ctype.h>
23#include <math.h>
24#include <stdbool.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <inttypes.h>
28#include "strlcpy.h"
29#include "strcasecmp.h"
30#include "system.h"
31#include "metadata.h"
32#include "debug.h"
33#include "replaygain.h"
34#include "fixedpoint.h"
35
36#define FP_BITS (12)
37#define FP_ONE (1 << FP_BITS)
38#define FP_MIN (-48 * FP_ONE)
39#define FP_MAX ( 17 * FP_ONE)
40
41void replaygain_itoa(char* buffer, int length, long int_gain)
42{
43 /* int_gain uses Q19.12 format. */
44 int one = abs(int_gain) >> FP_BITS;
45 int cent = ((abs(int_gain) & 0x0fff) * 100 + (FP_ONE/2)) >> FP_BITS;
46 snprintf(buffer, length, "%s%d.%02d dB", (int_gain<0) ? "-":"", one, cent);
47}
48
49static long fp_atof(const char* s, int precision)
50{
51 long int_part = 0;
52 long int_one = BIT_N(precision);
53 long frac_part = 0;
54 long frac_count = 0;
55 long frac_max = ((precision * 4) + 12) / 13;
56 long frac_max_int = 1;
57 long sign = 1;
58 bool point = false;
59
60 while ((*s != '\0') && isspace(*s))
61 {
62 s++;
63 }
64
65 if (*s == '-')
66 {
67 sign = -1;
68 s++;
69 }
70 else if (*s == '+')
71 {
72 s++;
73 }
74
75 while (*s != '\0')
76 {
77 if (*s == '.')
78 {
79 if (point)
80 {
81 break;
82 }
83
84 point = true;
85 }
86 else if (isdigit(*s))
87 {
88 if (point)
89 {
90 if (frac_count < frac_max)
91 {
92 frac_part = frac_part * 10 + (*s - '0');
93 frac_count++;
94 frac_max_int *= 10;
95 }
96 }
97 else
98 {
99 int_part = int_part * 10 + (*s - '0');
100 }
101 }
102 else
103 {
104 break;
105 }
106
107 s++;
108 }
109
110 while (frac_count < frac_max)
111 {
112 frac_part *= 10;
113 frac_count++;
114 frac_max_int *= 10;
115 }
116
117 return sign * ((int_part * int_one)
118 + (((int64_t) frac_part * int_one) / frac_max_int));
119}
120
121static long convert_gain(long gain)
122{
123 /* Don't allow unreasonably low or high gain changes.
124 * Our math code can't handle it properly anyway. :) */
125 gain = MAX(gain, FP_MIN);
126 gain = MIN(gain, FP_MAX);
127
128 return fp_factor(gain, FP_BITS) << (24 - FP_BITS);
129}
130
131/* Get the sample scale factor in Q19.12 format from a gain value. Returns 0
132 * for no gain.
133 *
134 * str Gain in dB as a string. E.g., "-3.45 dB"; the "dB" part is ignored.
135 */
136static long get_replaygain(const char* str)
137{
138 return fp_atof(str, FP_BITS);
139}
140
141/* Get the peak volume in Q7.24 format.
142 *
143 * str Peak volume. Full scale is specified as "1.0". Returns 0 for no peak.
144 */
145static long get_replaypeak(const char* str)
146{
147 return fp_atof(str, 24);
148}
149
150/* Get a sample scale factor in Q7.24 format from a gain value.
151 *
152 * int_gain Gain in dB, multiplied by 100.
153 */
154long get_replaygain_int(long int_gain)
155{
156 return convert_gain(int_gain * FP_ONE / 100);
157}
158
159/* Parse a ReplayGain tag conforming to the "VorbisGain standard". If a
160 * valid tag is found, update mp3entry struct accordingly. Existing values
161 * are not overwritten.
162 *
163 * key Name of the tag.
164 * value Value of the tag.
165 * entry mp3entry struct to update.
166 */
167void parse_replaygain(const char* key, const char* value,
168 struct mp3entry* entry)
169{
170 if (((strcasecmp(key, "replaygain_track_gain") == 0) ||
171 (strcasecmp(key, "rg_radio") == 0)) &&
172 !entry->track_gain)
173 {
174 entry->track_level = get_replaygain(value);
175 entry->track_gain = convert_gain(entry->track_level);
176 }
177 else if (((strcasecmp(key, "replaygain_album_gain") == 0) ||
178 (strcasecmp(key, "rg_audiophile") == 0)) &&
179 !entry->album_gain)
180 {
181 entry->album_level = get_replaygain(value);
182 entry->album_gain = convert_gain(entry->album_level);
183 }
184 else if (((strcasecmp(key, "replaygain_track_peak") == 0) ||
185 (strcasecmp(key, "rg_peak") == 0)) &&
186 !entry->track_peak)
187 {
188 entry->track_peak = get_replaypeak(value);
189 }
190 else if ((strcasecmp(key, "replaygain_album_peak") == 0) &&
191 !entry->album_peak)
192 {
193 entry->album_peak = get_replaypeak(value);
194 }
195}
196
197/* Set ReplayGain values from integers. Existing values are not overwritten.
198 *
199 * album If true, set album values, otherwise set track values.
200 * gain Gain value in dB, multiplied by 512. 0 for no gain.
201 * peak Peak volume in Q7.24 format, where 1.0 is full scale. 0 for no
202 * peak volume.
203 * entry mp3entry struct to update.
204 */
205void parse_replaygain_int(bool album, long gain, long peak,
206 struct mp3entry* entry)
207{
208 gain = gain * FP_ONE / 512;
209
210 if (album)
211 {
212 entry->album_level = gain;
213 entry->album_gain = convert_gain(gain);
214 entry->album_peak = peak;
215 }
216 else
217 {
218 entry->track_level = gain;
219 entry->track_gain = convert_gain(gain);
220 entry->track_peak = peak;
221 }
222}
diff --git a/lib/rbcodec/metadata/replaygain.h b/lib/rbcodec/metadata/replaygain.h
new file mode 100644
index 0000000000..215464dfdf
--- /dev/null
+++ b/lib/rbcodec/metadata/replaygain.h
@@ -0,0 +1,34 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _REPLAYGAIN_H
23#define _REPLAYGAIN_H
24
25#include "metadata.h"
26
27long get_replaygain_int(long int_gain);
28void parse_replaygain(const char* key, const char* value,
29 struct mp3entry* entry);
30void parse_replaygain_int(bool album, long gain, long peak,
31 struct mp3entry* entry);
32void replaygain_itoa(char* buffer, int length, long int_gain);
33
34#endif
diff --git a/lib/rbcodec/metadata/rm.c b/lib/rbcodec/metadata/rm.c
new file mode 100644
index 0000000000..27f541cb25
--- /dev/null
+++ b/lib/rbcodec/metadata/rm.c
@@ -0,0 +1,464 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Mohamed Tarek
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include <codecs/librm/rm.h>
28#include "system.h"
29#include "metadata.h"
30#include "metadata_common.h"
31#include "metadata_parsers.h"
32#include "logf.h"
33
34/* Uncomment the following line for debugging */
35//#define DEBUG_RM
36#ifndef DEBUG_RM
37#undef DEBUGF
38#define DEBUGF(...)
39#endif
40
41#define ID3V1_OFFSET -128
42#define METADATA_FOOTER_OFFSET -140
43
44static inline void print_cook_extradata(RMContext *rmctx) {
45
46 DEBUGF(" cook_version = 0x%08lx\n", rm_get_uint32be(rmctx->codec_extradata));
47 DEBUGF(" samples_per_frame_per_channel = %d\n", rm_get_uint16be(&rmctx->codec_extradata[4]));
48 DEBUGF(" number_of_subbands_in_freq_domain = %d\n", rm_get_uint16be(&rmctx->codec_extradata[6]));
49 if(rmctx->extradata_size == 16) {
50 DEBUGF(" joint_stereo_subband_start = %d\n",rm_get_uint16be(&rmctx->codec_extradata[12]));
51 DEBUGF(" joint_stereo_vlc_bits = %d\n", rm_get_uint16be(&rmctx->codec_extradata[14]));
52 }
53}
54
55
56struct real_object_t
57{
58 uint32_t fourcc;
59 uint32_t size;
60 uint16_t version;
61};
62
63static int real_read_object_header(int fd, struct real_object_t* obj)
64{
65 int n;
66
67 if ((n = read_uint32be(fd, &obj->fourcc)) <= 0)
68 return n;
69 if ((n = read_uint32be(fd, &obj->size)) <= 0)
70 return n;
71 if ((n = read_uint16be(fd, &obj->version)) <= 0)
72 return n;
73
74 return 1;
75}
76
77#if (defined(SIMULATOR) && defined(DEBUG_RM))
78static char* fourcc2str(uint32_t f)
79{
80 static char res[5];
81
82 res[0] = (f & 0xff000000) >> 24;
83 res[1] = (f & 0xff0000) >> 16;
84 res[2] = (f & 0xff00) >> 8;
85 res[3] = (f & 0xff);
86 res[4] = 0;
87
88 return res;
89}
90#endif
91
92static inline int real_read_audio_stream_info(int fd, RMContext *rmctx)
93{
94 int skipped = 0;
95 uint32_t version;
96 struct real_object_t obj;
97#ifdef SIMULATOR
98 uint32_t header_size;
99 uint16_t flavor;
100 uint32_t coded_framesize;
101 uint8_t interleaver_id_length;
102 uint8_t fourcc_length;
103#endif
104 uint32_t interleaver_id;
105 uint32_t fourcc = 0;
106
107 memset(&obj,0,sizeof(obj));
108 read_uint32be(fd, &version);
109 skipped += 4;
110
111 DEBUGF(" version=0x%04lx\n",((version >> 16) & 0xff));
112 if (((version >> 16) & 0xff) == 3) {
113 /* Very old version */
114 } else {
115#ifdef SIMULATOR
116 real_read_object_header(fd, &obj);
117 read_uint32be(fd, &header_size);
118 /* obj.size will be filled with an unknown value, replaced with header_size */
119 DEBUGF(" Object: %s, size: %ld bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version);
120
121 read_uint16be(fd, &flavor);
122 read_uint32be(fd, &coded_framesize);
123#else
124 lseek(fd, 20, SEEK_CUR);
125#endif
126 lseek(fd, 12, SEEK_CUR); /* unknown */
127 read_uint16be(fd, &rmctx->sub_packet_h);
128 read_uint16be(fd, &rmctx->block_align);
129 read_uint16be(fd, &rmctx->sub_packet_size);
130 lseek(fd, 2, SEEK_CUR); /* unknown */
131 skipped += 40;
132 if (((version >> 16) & 0xff) == 5)
133 {
134 lseek(fd, 6, SEEK_CUR); /* unknown */
135 skipped += 6;
136 }
137 read_uint16be(fd, &rmctx->sample_rate);
138 lseek(fd, 4, SEEK_CUR); /* unknown */
139 read_uint16be(fd, &rmctx->nb_channels);
140 skipped += 8;
141 if (((version >> 16) & 0xff) == 4)
142 {
143#ifdef SIMULATOR
144 read_uint8(fd, &interleaver_id_length);
145 read_uint32be(fd, &interleaver_id);
146 read_uint8(fd, &fourcc_length);
147#else
148 lseek(fd, 6, SEEK_CUR);
149#endif
150 read_uint32be(fd, &fourcc);
151 skipped += 10;
152 }
153 if (((version >> 16) & 0xff) == 5)
154 {
155 read_uint32be(fd, &interleaver_id);
156 read_uint32be(fd, &fourcc);
157 skipped += 8;
158 }
159 lseek(fd, 3, SEEK_CUR); /* unknown */
160 skipped += 3;
161 if (((version >> 16) & 0xff) == 5)
162 {
163 lseek(fd, 1, SEEK_CUR); /* unknown */
164 skipped += 1;
165 }
166
167 switch(fourcc) {
168 case FOURCC('c','o','o','k'):
169 rmctx->codec_type = CODEC_COOK;
170 read_uint32be(fd, &rmctx->extradata_size);
171 skipped += 4;
172 read(fd, rmctx->codec_extradata, rmctx->extradata_size);
173 skipped += rmctx->extradata_size;
174 break;
175
176 case FOURCC('r','a','a','c'):
177 case FOURCC('r','a','c','p'):
178 rmctx->codec_type = CODEC_AAC;
179 read_uint32be(fd, &rmctx->extradata_size);
180 skipped += 4;
181 read(fd, rmctx->codec_extradata, rmctx->extradata_size);
182 skipped += rmctx->extradata_size;
183 break;
184
185 case FOURCC('d','n','e','t'):
186 rmctx->codec_type = CODEC_AC3;
187 break;
188
189 case FOURCC('a','t','r','c'):
190 rmctx->codec_type = CODEC_ATRAC;
191 read_uint32be(fd, &rmctx->extradata_size);
192 skipped += 4;
193 read(fd, rmctx->codec_extradata, rmctx->extradata_size);
194 skipped += rmctx->extradata_size;
195 break;
196
197 default: /* Not a supported codec */
198 return -1;
199 }
200
201 DEBUGF(" flavor = %d\n",flavor);
202 DEBUGF(" coded_frame_size = %ld\n",coded_framesize);
203 DEBUGF(" sub_packet_h = %d\n",rmctx->sub_packet_h);
204 DEBUGF(" frame_size = %d\n",rmctx->block_align);
205 DEBUGF(" sub_packet_size = %d\n",rmctx->sub_packet_size);
206 DEBUGF(" sample_rate= %d\n",rmctx->sample_rate);
207 DEBUGF(" channels= %d\n",rmctx->nb_channels);
208 DEBUGF(" fourcc = %s\n",fourcc2str(fourcc));
209 DEBUGF(" codec_extra_data_length = %ld\n",rmctx->extradata_size);
210 DEBUGF(" codec_extradata :\n");
211 if(rmctx->codec_type == CODEC_COOK) {
212 DEBUGF(" cook_extradata :\n");
213 print_cook_extradata(rmctx);
214 }
215
216 }
217
218 return skipped;
219}
220
221static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3)
222{
223 struct real_object_t obj;
224 int res;
225 int skipped;
226 off_t curpos __attribute__((unused));
227 uint8_t len; /* Holds a string_length, which is then passed to read_string() */
228
229#ifdef SIMULATOR
230 uint32_t avg_bitrate = 0;
231 uint32_t max_packet_size;
232 uint32_t avg_packet_size;
233 uint32_t packet_count;
234 uint32_t duration;
235 uint32_t preroll;
236 uint32_t index_offset;
237 uint16_t stream_id;
238 uint32_t start_time;
239 uint32_t codec_data_size;
240#endif
241 uint32_t v;
242 uint32_t max_bitrate;
243 uint16_t num_streams;
244 uint32_t next_data_off;
245 uint8_t header_end;
246
247 memset(&obj,0,sizeof(obj));
248 curpos = lseek(fd, 0, SEEK_SET);
249 res = real_read_object_header(fd, &obj);
250
251 if (obj.fourcc == FOURCC('.','r','a',0xfd))
252 {
253 /* Very old .ra format - not yet supported */
254 return -1;
255 }
256 else if (obj.fourcc != FOURCC('.','R','M','F'))
257 {
258 return -1;
259 }
260
261 lseek(fd, 8, SEEK_CUR); /* unknown */
262
263 DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos);
264
265 res = real_read_object_header(fd, &obj);
266 header_end = 0;
267 while(res)
268 {
269 DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos);
270 skipped = 10;
271 if(obj.fourcc == FOURCC('I','N','D','X'))
272 break;
273 switch (obj.fourcc)
274 {
275 case FOURCC('P','R','O','P'): /* File properties */
276 read_uint32be(fd, &max_bitrate);
277 read_uint32be(fd, &rmctx->bit_rate); /*avg bitrate*/
278#ifdef SIMULATOR
279 read_uint32be(fd, &max_packet_size);
280 read_uint32be(fd, &avg_packet_size);
281 read_uint32be(fd, &packet_count);
282#else
283 lseek(fd, 3*sizeof(uint32_t), SEEK_CUR);
284#endif
285 read_uint32be(fd, &rmctx->duration);
286#ifdef SIMULATOR
287 read_uint32be(fd, &preroll);
288 read_uint32be(fd, &index_offset);
289#else
290 lseek(fd, 2*sizeof(uint32_t), SEEK_CUR);
291#endif
292 read_uint32be(fd, &rmctx->data_offset);
293 read_uint16be(fd, &num_streams);
294 read_uint16be(fd, &rmctx->flags);
295 skipped += 40;
296
297 DEBUGF(" max_bitrate = %ld\n",max_bitrate);
298 DEBUGF(" avg_bitrate = %ld\n",rmctx->bit_rate);
299 DEBUGF(" max_packet_size = %ld\n",max_packet_size);
300 DEBUGF(" avg_packet_size = %ld\n",avg_packet_size);
301 DEBUGF(" packet_count = %ld\n",packet_count);
302 DEBUGF(" duration = %ld\n",rmctx->duration);
303 DEBUGF(" preroll = %ld\n",preroll);
304 DEBUGF(" index_offset = %ld\n",index_offset);
305 DEBUGF(" data_offset = %ld\n",rmctx->data_offset);
306 DEBUGF(" num_streams = %d\n",num_streams);
307 DEBUGF(" flags=0x%04x\n",rmctx->flags);
308 break;
309
310 case FOURCC('C','O','N','T'):
311 /* Four strings - Title, Author, Copyright, Comment */
312 read_uint8(fd,&len);
313 skipped += (int)read_string(fd, id3->id3v1buf[0], sizeof(id3->id3v1buf[0]), '\0', len);
314 read_uint8(fd,&len);
315 skipped += (int)read_string(fd, id3->id3v1buf[1], sizeof(id3->id3v1buf[1]), '\0', len);
316 read_uint8(fd,&len);
317 skipped += (int)read_string(fd, id3->id3v1buf[2], sizeof(id3->id3v1buf[2]), '\0', len);
318 read_uint8(fd,&len);
319 skipped += (int)read_string(fd, id3->id3v1buf[3], sizeof(id3->id3v1buf[3]), '\0', len);
320 skipped += 4;
321
322 DEBUGF(" title=\"%s\"\n",id3->id3v1buf[0]);
323 DEBUGF(" author=\"%s\"\n",id3->id3v1buf[1]);
324 DEBUGF(" copyright=\"%s\"\n",id3->id3v1buf[2]);
325 DEBUGF(" comment=\"%s\"\n",id3->id3v1buf[3]);
326 break;
327
328 case FOURCC('M','D','P','R'): /* Media properties */
329#ifdef SIMULATOR
330 read_uint16be(fd,&stream_id);
331 read_uint32be(fd,&max_bitrate);
332 read_uint32be(fd,&avg_bitrate);
333 read_uint32be(fd,&max_packet_size);
334 read_uint32be(fd,&avg_packet_size);
335 read_uint32be(fd,&start_time);
336 read_uint32be(fd,&preroll);
337 read_uint32be(fd,&duration);
338#else
339 lseek(fd, 30, SEEK_CUR);
340#endif
341 skipped += 30;
342 read_uint8(fd,&len);
343 skipped += 1;
344 lseek(fd, len, SEEK_CUR); /* desc */
345 skipped += len;
346 read_uint8(fd,&len);
347 skipped += 1;
348#ifdef SIMULATOR
349 lseek(fd, len, SEEK_CUR); /* mimetype */
350 read_uint32be(fd,&codec_data_size);
351#else
352 lseek(fd, len + 4, SEEK_CUR);
353#endif
354 skipped += len + 4;
355 read_uint32be(fd,&v);
356 skipped += 4;
357
358 DEBUGF(" stream_id = 0x%04x\n",stream_id);
359 DEBUGF(" max_bitrate = %ld\n",max_bitrate);
360 DEBUGF(" avg_bitrate = %ld\n",avg_bitrate);
361 DEBUGF(" max_packet_size = %ld\n",max_packet_size);
362 DEBUGF(" avg_packet_size = %ld\n",avg_packet_size);
363 DEBUGF(" start_time = %ld\n",start_time);
364 DEBUGF(" preroll = %ld\n",preroll);
365 DEBUGF(" duration = %ld\n",duration);
366 DEBUGF(" codec_data_size = %ld\n",codec_data_size);
367 DEBUGF(" v=\"%s\"\n", fourcc2str(v));
368
369 if (v == FOURCC('.','r','a',0xfd))
370 {
371 int temp;
372 temp= real_read_audio_stream_info(fd, rmctx);
373 if(temp < 0)
374 return -1;
375 else
376 skipped += temp;
377 }
378 else if (v == FOURCC('L','S','D',':'))
379 {
380 DEBUGF("Real audio lossless is not supported.");
381 return -1;
382 }
383 else
384 {
385 /* We shall not abort with -1 here. *.rm file often seem
386 * to have a second media properties header that contains
387 * other metadata. */
388 DEBUGF("Unknown header signature :\"%s\"\n", fourcc2str(v));
389 }
390
391
392 break;
393
394 case FOURCC('D','A','T','A'):
395 read_uint32be(fd,&rmctx->nb_packets);
396 skipped += 4;
397 read_uint32be(fd,&next_data_off);
398 skipped += 4;
399
400 /***
401 * nb_packets correction :
402 * in some samples, number of packets may not exactly form
403 * an integer number of scrambling units. This is corrected
404 * by constructing a partially filled unit out of the few
405 * remaining samples at the end of decoding.
406 ***/
407 if(rmctx->nb_packets % rmctx->sub_packet_h)
408 rmctx->nb_packets += rmctx->sub_packet_h - (rmctx->nb_packets % rmctx->sub_packet_h);
409
410 DEBUGF(" data_nb_packets = %ld\n",rmctx->nb_packets);
411 DEBUGF(" next DATA offset = %ld\n",next_data_off);
412 header_end = 1;
413 break;
414 }
415 if(header_end) break;
416 curpos = lseek(fd, obj.size - skipped, SEEK_CUR);
417 res = real_read_object_header(fd, &obj);
418 }
419
420
421 return 0;
422}
423
424
425bool get_rm_metadata(int fd, struct mp3entry* id3)
426{
427 RMContext *rmctx = (RMContext*) (( (intptr_t)id3->id3v2buf + 3 ) &~ 3);
428 memset(rmctx,0,sizeof(RMContext));
429 if(rm_parse_header(fd, rmctx, id3) < 0)
430 return false;
431
432 if (!setid3v1title(fd, id3)) {
433 /* file has no id3v1 tags, use the tags from CONT chunk */
434 id3->title = id3->id3v1buf[0];
435 id3->artist = id3->id3v1buf[1];
436 id3->comment= id3->id3v1buf[3];
437 }
438
439 switch(rmctx->codec_type)
440 {
441 case CODEC_COOK:
442 /* Already set, do nothing */
443 break;
444 case CODEC_AAC:
445 id3->codectype = AFMT_RM_AAC;
446 break;
447
448 case CODEC_AC3:
449 id3->codectype = AFMT_RM_AC3;
450 break;
451
452 case CODEC_ATRAC:
453 id3->codectype = AFMT_RM_ATRAC3;
454 break;
455 }
456
457 id3->channels = rmctx->nb_channels;
458 id3->extradata_size = rmctx->extradata_size;
459 id3->bitrate = rmctx->bit_rate / 1000;
460 id3->frequency = rmctx->sample_rate;
461 id3->length = rmctx->duration;
462 id3->filesize = filesize(fd);
463 return true;
464}
diff --git a/lib/rbcodec/metadata/sgc.c b/lib/rbcodec/metadata/sgc.c
new file mode 100644
index 0000000000..78cacb9b1b
--- /dev/null
+++ b/lib/rbcodec/metadata/sgc.c
@@ -0,0 +1,67 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13static bool parse_sgc_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17
18 lseek(fd, 0, SEEK_SET);
19 if (read(fd, buf, 0xA0) < 0xA0)
20 return false;
21
22 /* calculate track length with number of tracks */
23 id3->length = buf[37] * 1000;
24
25 /* If meta info was found in the m3u skip next step */
26 if (id3->title && id3->title[0]) return true;
27
28 char *p = id3->id3v2buf;
29
30 /* Some metadata entries have 32 bytes length */
31 /* Game */
32 memcpy(p, &buf[64], 32); *(p + 33) = '\0';
33 id3->title = p;
34 p += strlen(p)+1;
35
36 /* Artist */
37 memcpy(p, &buf[96], 32); *(p + 33) = '\0';
38 id3->artist = p;
39 p += strlen(p)+1;
40
41 /* Copyright */
42 memcpy(p, &buf[128], 32); *(p + 33) = '\0';
43 id3->album = p;
44 p += strlen(p)+1;
45 return true;
46}
47
48
49bool get_sgc_metadata(int fd, struct mp3entry* id3)
50{
51 uint32_t sgc_type;
52 if ((lseek(fd, 0, SEEK_SET) < 0) ||
53 read_uint32be(fd, &sgc_type) != (int)sizeof(sgc_type))
54 return false;
55
56 id3->vbr = false;
57 id3->filesize = filesize(fd);
58 /* we only render 16 bits, 44.1KHz, Stereo */
59 id3->bitrate = 706;
60 id3->frequency = 44100;
61
62 /* Make sure this is an SGC file */
63 if (sgc_type != FOURCC('S','G','C',0x1A))
64 return false;
65
66 return parse_sgc_header(fd, id3);
67}
diff --git a/lib/rbcodec/metadata/sid.c b/lib/rbcodec/metadata/sid.c
new file mode 100644
index 0000000000..50b879b56d
--- /dev/null
+++ b/lib/rbcodec/metadata/sid.c
@@ -0,0 +1,89 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32
33/* PSID metadata info is available here:
34 http://www.unusedino.de/ec64/technical/formats/sidplay.html */
35bool get_sid_metadata(int fd, struct mp3entry* id3)
36{
37 /* Use the trackname part of the id3 structure as a temporary buffer */
38 unsigned char* buf = (unsigned char *)id3->path;
39 char *p;
40
41
42 if ((lseek(fd, 0, SEEK_SET) < 0)
43 || (read(fd, buf, 0x80) < 0x80))
44 {
45 return false;
46 }
47
48 if ((memcmp(buf, "PSID", 4) != 0))
49 {
50 return false;
51 }
52
53 p = id3->id3v2buf;
54
55 /* Copy Title (assumed max 0x1f letters + 1 zero byte) */
56 id3->title = p;
57 buf[0x16+0x1f] = 0;
58 p = iso_decode(&buf[0x16], p, 0, strlen(&buf[0x16])+1);
59
60 /* Copy Artist (assumed max 0x1f letters + 1 zero byte) */
61 id3->artist = p;
62 buf[0x36+0x1f] = 0;
63 p = iso_decode(&buf[0x36], p, 0, strlen(&buf[0x36])+1);
64
65 /* Copy Year (assumed max 4 letters + 1 zero byte) */
66 buf[0x56+0x4] = 0;
67 id3->year = atoi(&buf[0x56]);
68
69 /* Copy Album (assumed max 0x1f-0x05 letters + 1 zero byte) */
70 id3->album = p;
71 buf[0x56+0x1f] = 0;
72 iso_decode(&buf[0x5b], p, 0, strlen(&buf[0x5b])+1);
73
74 id3->bitrate = 706;
75 id3->frequency = 44100;
76 /* New idea as posted by Marco Alanen (ravon):
77 * Set the songlength in seconds to the number of subsongs
78 * so every second represents a subsong.
79 * Users can then skip the current subsong by seeking
80 *
81 * Note: the number of songs is a 16bit value at 0xE, so this code only
82 * uses the lower 8 bits of the counter.
83 */
84 id3->length = (buf[0xf]-1)*1000;
85 id3->vbr = false;
86 id3->filesize = filesize(fd);
87
88 return true;
89}
diff --git a/lib/rbcodec/metadata/smaf.c b/lib/rbcodec/metadata/smaf.c
new file mode 100644
index 0000000000..1b745d3fa1
--- /dev/null
+++ b/lib/rbcodec/metadata/smaf.c
@@ -0,0 +1,470 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <inttypes.h>
22#include <stdio.h>
23
24#include "string-extra.h"
25#include "system.h"
26#include "metadata.h"
27#include "metadata_common.h"
28#include "metadata_parsers.h"
29#include "rbunicode.h"
30#include "logf.h"
31
32static const int basebits[4] = { 4, 8, 12, 16 };
33
34static const int frequency[5] = { 4000, 8000, 11025, 22050, 44100 };
35
36static const int support_codepages[5] = {
37#ifdef HAVE_LCD_BITMAP
38 SJIS, ISO_8859_1, -1, GB_2312, BIG_5,
39#else
40 -1, ISO_8859_1, -1, -1, -1,
41#endif
42};
43
44/* extra codepage */
45#define UCS2 (NUM_CODEPAGES + 1)
46
47/* support id3 tag */
48#define TAG_TITLE (('S'<<8)|'T')
49#define TAG_ARTIST (('A'<<8)|'N')
50#define TAG_COMPOSER (('S'<<8)|'W')
51
52/* convert functions */
53#define CONVERT_SMAF_CHANNELS(c) (((c) >> 7) + 1)
54
55
56static inline int convert_smaf_audio_basebit(unsigned int basebit)
57{
58 if (basebit > 3)
59 return 0;
60 return basebits[basebit];
61}
62
63static inline int convert_smaf_audio_frequency(unsigned int freq)
64{
65 if (freq > 4)
66 return 0;
67 return frequency[freq];
68}
69
70static int convert_smaf_codetype(unsigned int codetype)
71{
72 if (codetype < 5)
73 return support_codepages[codetype];
74 else if (codetype == 0x20 || codetype == 0x24) /* In Rockbox, UCS2 and UTF-16 are same. */
75 return UCS2;
76 else if (codetype == 0x23)
77 return UTF_8;
78 else if (codetype == 0xff)
79 return ISO_8859_1;
80 return -1;
81}
82
83static void set_length(struct mp3entry *id3, unsigned int ch, unsigned int basebit,
84 unsigned int numbytes)
85{
86 int bitspersample = convert_smaf_audio_basebit(basebit);
87
88 if (bitspersample != 0 && id3->frequency != 0)
89 {
90 /* Calculate track length [ms] and bitrate [kbit/s] */
91 id3->length = (uint64_t)numbytes * 8000LL
92 / (bitspersample * CONVERT_SMAF_CHANNELS(ch) * id3->frequency);
93 id3->bitrate = bitspersample * id3->frequency / 1000;
94 }
95
96 /* output contents/wave data/id3 info (for debug) */
97 DEBUGF("contents info ----\n");
98 DEBUGF(" TITLE: %s\n", (id3->title)? id3->title : "(NULL)");
99 DEBUGF(" ARTIST: %s\n", (id3->artist)? id3->artist : "(NULL)");
100 DEBUGF(" COMPOSER: %s\n", (id3->composer)? id3->composer : "(NULL)");
101 DEBUGF("wave data info ----\n");
102 DEBUGF(" channels: %u\n", CONVERT_SMAF_CHANNELS(ch));
103 DEBUGF(" bitspersample: %d\n", bitspersample);
104 DEBUGF(" numbytes; %u\n", numbytes);
105 DEBUGF("id3 info ----\n");
106 DEBUGF(" frquency: %u\n", (unsigned int)id3->frequency);
107 DEBUGF(" bitrate: %d\n", id3->bitrate);
108 DEBUGF(" length: %u\n", (unsigned int)id3->length);
109}
110
111/* contents parse functions */
112
113/* Note:
114 * 1) When the codepage is UTF-8 or UCS2, contents data do not start BOM.
115 * 2) The byte order of contents data is big endian.
116 */
117
118static void decode2utf8(const unsigned char *src, unsigned char **dst,
119 int srcsize, int *dstsize, int codepage)
120{
121 unsigned char tmpbuf[srcsize * 3 + 1];
122 unsigned char *p;
123 int utf8size;
124
125 if (codepage < NUM_CODEPAGES)
126 p = iso_decode(src, tmpbuf, codepage, srcsize);
127 else /* codepage == UCS2 */
128 p = utf16BEdecode(src, tmpbuf, srcsize);
129
130 *p = '\0';
131
132 strlcpy(*dst, tmpbuf, *dstsize);
133 utf8size = (p - tmpbuf) + 1;
134 if (utf8size > *dstsize)
135 {
136 DEBUGF("metadata warning: data length: %d > contents store buffer size: %d\n",
137 utf8size, *dstsize);
138 utf8size = *dstsize;
139 }
140 *dst += utf8size;
141 *dstsize -= utf8size;
142}
143
144static int read_audio_track_contets(int fd, int codepage, unsigned char **dst,
145 int *dstsize)
146{
147 /* value length <= 256 bytes */
148 unsigned char buf[256];
149 unsigned char *p = buf;
150 unsigned char *q = buf;
151 int datasize;
152
153 read(fd, buf, 256);
154
155 while (p - buf < 256 && *p != ',')
156 {
157 /* skip yen mark */
158 if (codepage != UCS2)
159 {
160 if (*p == '\\')
161 p++;
162 }
163 else if (*p == '\0' && *(p+1) == '\\')
164 p += 2;
165
166 if (*p > 0x7f)
167 {
168 if (codepage == UTF_8)
169 {
170 while ((*p & MASK) != COMP)
171 *q++ = *p++;
172 }
173#ifdef HAVE_LCD_BITMAP
174 else if (codepage == SJIS)
175 {
176 if (*p <= 0xa0 || *p >= 0xe0)
177 *q++ = *p++;
178 }
179#endif
180 }
181
182 *q++ = *p++;
183 if (codepage == UCS2)
184 *q++ = *p++;
185 }
186 datasize = p - buf + 1;
187 lseek(fd, datasize - 256, SEEK_CUR);
188
189 if (dst != NULL)
190 decode2utf8(buf, dst, q - buf, dstsize, codepage);
191
192 return datasize;
193}
194
195static void read_score_track_contets(int fd, int codepage, int datasize,
196 unsigned char **dst, int *dstsize)
197{
198 unsigned char buf[datasize];
199
200 read(fd, buf, datasize);
201 decode2utf8(buf, dst, datasize, dstsize, codepage);
202}
203
204/* traverse chunk functions */
205
206static unsigned int search_chunk(int fd, const unsigned char *name, int nlen)
207{
208 unsigned char buf[8];
209 unsigned int chunksize;
210
211 while (read(fd, buf, 8) > 0)
212 {
213 chunksize = get_long_be(buf + 4);
214 if (memcmp(buf, name, nlen) == 0)
215 return chunksize;
216
217 lseek(fd, chunksize, SEEK_CUR);
218 }
219 DEBUGF("metadata error: missing '%s' chunk\n", name);
220 return 0;
221}
222
223static bool parse_smaf_audio_track(int fd, struct mp3entry *id3, unsigned int datasize)
224{
225 /* temporary buffer */
226 unsigned char *tmp = (unsigned char*)id3->path;
227 /* contents stored buffer */
228 unsigned char *buf = id3->id3v2buf;
229 int bufsize = sizeof(id3->id3v2buf);
230
231 unsigned int chunksize = datasize;
232 int valsize;
233
234 int codepage;
235
236 /* parse contents info */
237 read(fd, tmp, 5);
238 codepage = convert_smaf_codetype(tmp[2]);
239 if (codepage < 0)
240 {
241 DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[2]);
242 return false;
243 }
244
245 datasize -= 5;
246 while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL)
247 && (datasize > 0 && bufsize > 0))
248 {
249 if (read(fd, tmp, 3) <= 0)
250 return false;
251
252 if (tmp[2] != ':')
253 {
254 DEBUGF("metadata error: illegal tag: %c%c%c\n", tmp[0], tmp[1], tmp[2]);
255 return false;
256 }
257 switch ((tmp[0]<<8)|tmp[1])
258 {
259 case TAG_TITLE:
260 id3->title = buf;
261 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
262 break;
263 case TAG_ARTIST:
264 id3->artist = buf;
265 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
266 break;
267 case TAG_COMPOSER:
268 id3->composer = buf;
269 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
270 break;
271 default:
272 valsize = read_audio_track_contets(fd, codepage, NULL, &bufsize);
273 break;
274 }
275 datasize -= (valsize + 3);
276 }
277
278 /* search PCM Audio Track Chunk */
279 lseek(fd, 16 + chunksize, SEEK_SET);
280
281 chunksize = search_chunk(fd, "ATR", 3);
282 if (chunksize == 0)
283 {
284 DEBUGF("metadata error: missing PCM Audio Track Chunk\n");
285 return false;
286 }
287
288 /*
289 * get format
290 * tmp
291 * +0: Format Type
292 * +1: Sequence Type
293 * +2: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: frequency
294 * +3: bit 4-7: base bit
295 * +4: TimeBase_D
296 * +5: TimeBase_G
297 *
298 * Note: If PCM Audio Track does not include Sequence Data Chunk,
299 * tmp+6 is the start position of Wave Data Chunk.
300 */
301 read(fd, tmp, 6);
302
303 /* search Wave Data Chunk */
304 chunksize = search_chunk(fd, "Awa", 3);
305 if (chunksize == 0)
306 {
307 DEBUGF("metadata error: missing Wave Data Chunk\n");
308 return false;
309 }
310
311 /* set track length and bitrate */
312 id3->frequency = convert_smaf_audio_frequency(tmp[2] & 0x0f);
313 set_length(id3, tmp[2], tmp[3] >> 4, chunksize);
314 return true;
315}
316
317static bool parse_smaf_score_track(int fd, struct mp3entry *id3)
318{
319 /* temporary buffer */
320 unsigned char *tmp = (unsigned char*)id3->path;
321 unsigned char *p = tmp;
322 /* contents stored buffer */
323 unsigned char *buf = id3->id3v2buf;
324 int bufsize = sizeof(id3->id3v2buf);
325
326 unsigned int chunksize;
327 unsigned int datasize;
328 int valsize;
329
330 int codepage;
331
332 /* parse Optional Data Chunk */
333 read(fd, tmp, 21);
334 if (memcmp(tmp + 5, "OPDA", 4) != 0)
335 {
336 DEBUGF("metadata error: missing Optional Data Chunk\n");
337 return false;
338 }
339
340 /* Optional Data Chunk size */
341 chunksize = get_long_be(tmp + 9);
342
343 /* parse Data Chunk */
344 if (memcmp(tmp + 13, "Dch", 3) != 0)
345 {
346 DEBUGF("metadata error: missing Data Chunk\n");
347 return false;
348 }
349
350 codepage = convert_smaf_codetype(tmp[16]);
351 if (codepage < 0)
352 {
353 DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[16]);
354 return false;
355 }
356
357 /* Data Chunk size */
358 datasize = get_long_be(tmp + 17);
359 while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL)
360 && (datasize > 0 && bufsize > 0))
361 {
362 if (read(fd, tmp, 4) <= 0)
363 return false;
364
365 valsize = (tmp[2] << 8) | tmp[3];
366 datasize -= (valsize + 4);
367 switch ((tmp[0]<<8)|tmp[1])
368 {
369 case TAG_TITLE:
370 id3->title = buf;
371 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
372 break;
373 case TAG_ARTIST:
374 id3->artist = buf;
375 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
376 break;
377 case TAG_COMPOSER:
378 id3->composer = buf;
379 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
380 break;
381 default:
382 lseek(fd, valsize, SEEK_CUR);
383 break;
384 }
385 }
386
387 /* search Score Track Chunk */
388 lseek(fd, 29 + chunksize, SEEK_SET);
389
390 if (search_chunk(fd, "MTR", 3) == 0)
391 {
392 DEBUGF("metadata error: missing Score Track Chunk\n");
393 return false;
394 }
395
396 /*
397 * search next chunk
398 * usually, next chunk ('M***') found within 40 bytes.
399 */
400 chunksize = 40;
401 read(fd, tmp, chunksize);
402
403 tmp[chunksize] = 'M'; /* stopper */
404 while (*p != 'M')
405 p++;
406
407 chunksize -= (p - tmp);
408 if (chunksize == 0)
409 {
410 DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk");
411 return false;
412 }
413
414 /* search Score Track Stream PCM Data Chunk */
415 lseek(fd, -chunksize, SEEK_CUR);
416 if (search_chunk(fd, "Mtsp", 4) == 0)
417 {
418 DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk\n");
419 return false;
420 }
421
422 /*
423 * parse Score Track Stream Wave Data Chunk
424 * tmp
425 * +4-7: chunk size (WaveType(3bytes) + wave data count)
426 * +8: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: base bit
427 * +9: frequency (MSB)
428 * +10: frequency (LSB)
429 */
430 read(fd, tmp, 11);
431 if (memcmp(tmp, "Mwa", 3) != 0)
432 {
433 DEBUGF("metadata error: missing Score Track Stream Wave Data Chunk\n");
434 return false;
435 }
436
437 /* set track length and bitrate */
438 id3->frequency = (tmp[9] << 8) | tmp[10];
439 set_length(id3, tmp[8], tmp[8] & 0x0f, get_long_be(tmp + 4) - 3);
440 return true;
441}
442
443bool get_smaf_metadata(int fd, struct mp3entry* id3)
444{
445 /* temporary buffer */
446 unsigned char *tmp = (unsigned char *)id3->path;
447 unsigned int chunksize;
448
449 id3->title = NULL;
450 id3->artist = NULL;
451 id3->composer = NULL;
452
453 id3->vbr = false; /* All SMAF files are CBR */
454 id3->filesize = filesize(fd);
455
456 /* check File Chunk and Contents Info Chunk */
457 lseek(fd, 0, SEEK_SET);
458 read(fd, tmp, 16);
459 if ((memcmp(tmp, "MMMD", 4) != 0) || (memcmp(tmp + 8, "CNTI", 4) != 0))
460 {
461 DEBUGF("metadata error: does not smaf format\n");
462 return false;
463 }
464
465 chunksize = get_long_be(tmp + 12);
466 if (chunksize > 5)
467 return parse_smaf_audio_track(fd, id3, chunksize);
468
469 return parse_smaf_score_track(fd, id3);
470}
diff --git a/lib/rbcodec/metadata/spc.c b/lib/rbcodec/metadata/spc.c
new file mode 100644
index 0000000000..1c0206205d
--- /dev/null
+++ b/lib/rbcodec/metadata/spc.c
@@ -0,0 +1,130 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "debug.h"
32#include "rbunicode.h"
33
34bool get_spc_metadata(int fd, struct mp3entry* id3)
35{
36 /* Use the trackname part of the id3 structure as a temporary buffer */
37 unsigned char * buf = (unsigned char *)id3->path;
38 char * p;
39
40 unsigned long length;
41 unsigned long fade;
42 bool isbinary = true;
43 int i;
44
45 /* try to get the ID666 tag */
46 if ((lseek(fd, 0x2e, SEEK_SET) < 0)
47 || (read(fd, buf, 0xD2) < 0xD2))
48 {
49 DEBUGF("lseek or read failed\n");
50 return false;
51 }
52
53 p = id3->id3v2buf;
54
55 id3->title = p;
56 buf[31] = 0;
57 p = iso_decode(buf, p, 0, 32);
58 buf += 32;
59
60 id3->album = p;
61 buf[31] = 0;
62 p = iso_decode(buf, p, 0, 32);
63 buf += 48;
64
65 id3->comment = p;
66 buf[31] = 0;
67 p = iso_decode(buf, p, 0, 32);
68 buf += 32;
69
70 /* Date check */
71 if(buf[2] == '/' && buf[5] == '/')
72 isbinary = false;
73
74 /* Reserved bytes check */
75 if(buf[0xD2 - 0x2E - 112] >= '0' &&
76 buf[0xD2 - 0x2E - 112] <= '9' &&
77 buf[0xD3 - 0x2E - 112] == 0x00)
78 isbinary = false;
79
80 /* is length & fade only digits? */
81 for (i=0;i<8 && (
82 (buf[0xA9 - 0x2E - 112+i]>='0'&&buf[0xA9 - 0x2E - 112+i]<='9') ||
83 buf[0xA9 - 0x2E - 112+i]=='\0');
84 i++);
85 if (i==8) isbinary = false;
86
87 if(isbinary) {
88 id3->year = buf[0] | (buf[1]<<8);
89 buf += 11;
90
91 length = (buf[0] | (buf[1]<<8) | (buf[2]<<16)) * 1000;
92 buf += 3;
93
94 fade = (buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24));
95 buf += 4;
96 } else {
97 char tbuf[6];
98
99 buf += 6;
100 buf[4] = 0;
101 id3->year = atoi(buf);
102 buf += 5;
103
104 memcpy(tbuf, buf, 3);
105 tbuf[3] = 0;
106 length = atoi(tbuf) * 1000;
107 buf += 3;
108
109 memcpy(tbuf, buf, 5);
110 tbuf[5] = 0;
111 fade = atoi(tbuf);
112 buf += 5;
113 }
114
115 id3->artist = p;
116 buf[31] = 0;
117 iso_decode(buf, p, 0, 32);
118
119 if (length==0) {
120 length=3*60*1000; /* 3 minutes */
121 fade=5*1000; /* 5 seconds */
122 }
123
124 id3->length = length+fade;
125
126 id3->filesize = filesize(fd);
127 id3->genre_string = id3_get_num_genre(36);
128
129 return true;
130}
diff --git a/lib/rbcodec/metadata/tta.c b/lib/rbcodec/metadata/tta.c
new file mode 100644
index 0000000000..1d3d95f118
--- /dev/null
+++ b/lib/rbcodec/metadata/tta.c
@@ -0,0 +1,123 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33#define TTA1_SIGN 0x31415454
34
35#define TTA_HEADER_ID 0
36#define TTA_HEADER_AUDIO_FORMAT (TTA_HEADER_ID + sizeof(unsigned int))
37#define TTA_HEADER_NUM_CHANNELS (TTA_HEADER_AUDIO_FORMAT + sizeof(unsigned short))
38#define TTA_HEADER_BITS_PER_SAMPLE (TTA_HEADER_NUM_CHANNELS + sizeof(unsigned short))
39#define TTA_HEADER_SAMPLE_RATE (TTA_HEADER_BITS_PER_SAMPLE + sizeof(unsigned short))
40#define TTA_HEADER_DATA_LENGTH (TTA_HEADER_SAMPLE_RATE + sizeof(unsigned int))
41#define TTA_HEADER_CRC32 (TTA_HEADER_DATA_LENGTH + sizeof(unsigned int))
42#define TTA_HEADER_SIZE (TTA_HEADER_CRC32 + sizeof(unsigned int))
43
44#define TTA_HEADER_GETTER_ID(x) get_long_le(x)
45#define TTA_HEADER_GETTER_AUDIO_FORMAT(x) get_short_le(x)
46#define TTA_HEADER_GETTER_NUM_CHANNELS(x) get_short_le(x)
47#define TTA_HEADER_GETTER_BITS_PER_SAMPLE(x) get_short_le(x)
48#define TTA_HEADER_GETTER_SAMPLE_RATE(x) get_long_le(x)
49#define TTA_HEADER_GETTER_DATA_LENGTH(x) get_long_le(x)
50#define TTA_HEADER_GETTER_CRC32(x) get_long_le(x)
51
52#define GET_HEADER(x, tag) TTA_HEADER_GETTER_ ## tag((x) + TTA_HEADER_ ## tag)
53
54static void read_id3_tags(int fd, struct mp3entry* id3)
55{
56 id3->title = NULL;
57 id3->filesize = filesize(fd);
58 id3->id3v2len = getid3v2len(fd);
59 id3->tracknum = 0;
60 id3->discnum = 0;
61 id3->vbr = false; /* All TTA files are CBR */
62
63 /* first get id3v2 tags. if no id3v2 tags ware found, get id3v1 tags */
64 if (id3->id3v2len)
65 {
66 setid3v2title(fd, id3);
67 id3->first_frame_offset = id3->id3v2len;
68 return;
69 }
70 setid3v1title(fd, id3);
71}
72
73bool get_tta_metadata(int fd, struct mp3entry* id3)
74{
75 unsigned char ttahdr[TTA_HEADER_SIZE];
76 unsigned int datasize;
77 unsigned int origsize;
78 int bps;
79
80 lseek(fd, 0, SEEK_SET);
81
82 /* read id3 tags */
83 read_id3_tags(fd, id3);
84 lseek(fd, id3->id3v2len, SEEK_SET);
85
86 /* read TTA header */
87 if (read(fd, ttahdr, TTA_HEADER_SIZE) < 0)
88 return false;
89
90 /* check for TTA3 signature */
91 if ((GET_HEADER(ttahdr, ID)) != TTA1_SIGN)
92 return false;
93
94 /* skip check CRC */
95
96 id3->channels = (GET_HEADER(ttahdr, NUM_CHANNELS));
97 id3->frequency = (GET_HEADER(ttahdr, SAMPLE_RATE));
98 id3->length = ((GET_HEADER(ttahdr, DATA_LENGTH)) / id3->frequency) * 1000LL;
99 bps = (GET_HEADER(ttahdr, BITS_PER_SAMPLE));
100
101 datasize = id3->filesize - id3->first_frame_offset;
102 origsize = (GET_HEADER(ttahdr, DATA_LENGTH)) * ((bps + 7) / 8) * id3->channels;
103
104 id3->bitrate = (int) ((uint64_t) datasize * id3->frequency * id3->channels * bps
105 / (origsize * 1000LL));
106
107 /* output header info (for debug) */
108 DEBUGF("TTA header info ----\n");
109 DEBUGF("id: %x\n", (unsigned int)(GET_HEADER(ttahdr, ID)));
110 DEBUGF("channels: %d\n", id3->channels);
111 DEBUGF("frequency: %ld\n", id3->frequency);
112 DEBUGF("length: %ld\n", id3->length);
113 DEBUGF("bitrate: %d\n", id3->bitrate);
114 DEBUGF("bits per sample: %d\n", bps);
115 DEBUGF("compressed size: %d\n", datasize);
116 DEBUGF("original size: %d\n", origsize);
117 DEBUGF("id3----\n");
118 DEBUGF("artist: %s\n", id3->artist);
119 DEBUGF("title: %s\n", id3->title);
120 DEBUGF("genre: %s\n", id3->genre_string);
121
122 return true;
123}
diff --git a/lib/rbcodec/metadata/vgm.c b/lib/rbcodec/metadata/vgm.c
new file mode 100644
index 0000000000..9ea95b3939
--- /dev/null
+++ b/lib/rbcodec/metadata/vgm.c
@@ -0,0 +1,195 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
14
15typedef unsigned char byte;
16
17enum { header_size = 0x40 };
18enum { max_field = 64 };
19
20struct header_t
21{
22 char tag [4];
23 byte data_size [4];
24 byte version [4];
25 byte psg_rate [4];
26 byte ym2413_rate [4];
27 byte gd3_offset [4];
28 byte track_duration [4];
29 byte loop_offset [4];
30 byte loop_duration [4];
31 byte frame_rate [4];
32 byte noise_feedback [2];
33 byte noise_width;
34 byte unused1;
35 byte ym2612_rate [4];
36 byte ym2151_rate [4];
37 byte data_offset [4];
38 byte unused2 [8];
39};
40
41static byte const* skip_gd3_str( byte const* in, byte const* end )
42{
43 while ( end - in >= 2 )
44 {
45 in += 2;
46 if ( !(in [-2] | in [-1]) )
47 break;
48 }
49 return in;
50}
51
52static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
53{
54 byte const* mid = skip_gd3_str( in, end );
55 int len = (mid - in) / 2 - 1;
56 if ( field && len > 0 )
57 {
58 len = len < (int) max_field ? len : (int) max_field;
59
60 field [len] = 0;
61 /* Conver to utf8 */
62 utf16LEdecode( in, field, len );
63
64 /* Copy string back to id3v2buf */
65 strcpy( (char*) in, field );
66 }
67 return mid;
68}
69
70static byte const* get_gd3_pair( byte const* in, byte const* end, char* field )
71{
72 return skip_gd3_str( get_gd3_str( in, end, field ), end );
73}
74
75static void parse_gd3( byte const* in, byte const* end, struct mp3entry* id3 )
76{
77 char* p = id3->path;
78 id3->title = (char *) in;
79 in = get_gd3_pair( in, end, p ); /* Song */
80
81 id3->album = (char *) in;
82 in = get_gd3_pair( in, end, p ); /* Game */
83
84 in = get_gd3_pair( in, end, NULL ); /* System */
85
86 id3->artist = (char *) in;
87 in = get_gd3_pair( in, end, p ); /* Author */
88
89#if MEMORYSIZE > 2
90 in = get_gd3_str ( in, end, NULL ); /* Copyright */
91 in = get_gd3_pair( in, end, NULL ); /* Dumper */
92
93 id3->comment = (char *) in;
94 in = get_gd3_str ( in, end, p ); /* Comment */
95#endif
96}
97
98int const gd3_header_size = 12;
99
100static long check_gd3_header( byte* h, long remain )
101{
102 if ( remain < gd3_header_size ) return 0;
103 if ( memcmp( h, "Gd3 ", 4 ) ) return 0;
104 if ( get_long_le( h + 4 ) >= 0x200 ) return 0;
105
106 long gd3_size = get_long_le( h + 8 );
107 if ( gd3_size > remain - gd3_header_size )
108 gd3_size = remain - gd3_header_size;
109
110 return gd3_size;
111}
112
113static void get_vgm_length( struct header_t* h, struct mp3entry* id3 )
114{
115 long length = get_long_le( h->track_duration ) * 10 / 441;
116 if ( length > 0 )
117 {
118 long loop_length = 0, intro_length = 0;
119 long loop = get_long_le( h->loop_duration );
120 if ( loop > 0 && get_long_le( h->loop_offset ) )
121 {
122 loop_length = loop * 10 / 441;
123 intro_length = length - loop_length;
124 }
125 else
126 {
127 intro_length = length; /* make it clear that track is no longer than length */
128 loop_length = 0;
129 }
130
131 id3->length = intro_length + 2 * loop_length; /* intro + 2 loops */
132 return;
133 }
134
135 id3->length = 150 * 1000; /* 2.5 minutes */
136}
137
138bool get_vgm_metadata(int fd, struct mp3entry* id3)
139{
140 /* Use the id3v2 part of the id3 structure as a temporary buffer */
141 unsigned char* buf = (unsigned char *)id3->id3v2buf;
142 int read_bytes;
143
144 memset(buf, 0, ID3V2_BUF_SIZE);
145 if ((lseek(fd, 0, SEEK_SET) < 0)
146 || ((read_bytes = read(fd, buf, header_size)) < header_size))
147 {
148 return false;
149 }
150
151 id3->vbr = false;
152 id3->filesize = filesize(fd);
153
154 id3->bitrate = 706;
155 id3->frequency = 44100;
156
157 /* If file is gzipped, will get metadata later */
158 if (memcmp(buf, "Vgm ", 4))
159 {
160 /* We must set a default song length here because
161 the codec can't do it anymore */
162 id3->length = 150 * 1000; /* 2.5 minutes */
163 return true;
164 }
165
166 /* Get song length from header */
167 struct header_t* header = (struct header_t*) buf;
168 get_vgm_length( header, id3 );
169
170 long gd3_offset = get_long_le( header->gd3_offset ) - 0x2C;
171
172 /* No gd3 tag found */
173 if ( gd3_offset < 0 )
174 return true;
175
176 /* Seek to gd3 offset and read as
177 many bytes posible */
178 gd3_offset = id3->filesize - (header_size + gd3_offset);
179 if ((lseek(fd, -gd3_offset, SEEK_END) < 0)
180 || ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) <= 0))
181 return true;
182
183 byte* gd3 = buf;
184 long gd3_size = check_gd3_header( gd3, read_bytes );
185
186 /* GD3 tag is zero */
187 if ( gd3_size == 0 )
188 return true;
189
190 /* Finally, parse gd3 tag */
191 if ( gd3 )
192 parse_gd3( gd3 + gd3_header_size, gd3 + read_bytes, id3 );
193
194 return true;
195}
diff --git a/lib/rbcodec/metadata/vorbis.c b/lib/rbcodec/metadata/vorbis.c
new file mode 100644
index 0000000000..58bd781873
--- /dev/null
+++ b/lib/rbcodec/metadata/vorbis.c
@@ -0,0 +1,381 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "structec.h"
32
33/* Define LOGF_ENABLE to enable logf output in this file */
34/*#define LOGF_ENABLE*/
35#include "logf.h"
36
37struct file
38{
39 int fd;
40 bool packet_ended;
41 long packet_remaining;
42};
43
44
45/* Read an Ogg page header. file->packet_remaining is set to the size of the
46 * first packet on the page; file->packet_ended is set to true if the packet
47 * ended on the current page. Returns true if the page header was
48 * successfully read.
49 */
50static bool file_read_page_header(struct file* file)
51{
52 unsigned char buffer[64];
53 ssize_t table_left;
54
55 /* Size of page header without segment table */
56 if (read(file->fd, buffer, 27) != 27)
57 {
58 return false;
59 }
60
61 if (memcmp("OggS", buffer, 4))
62 {
63 return false;
64 }
65
66 /* Skip pattern (4), version (1), flags (1), granule position (8),
67 * serial (4), pageno (4), checksum (4)
68 */
69 table_left = buffer[26];
70 file->packet_remaining = 0;
71
72 /* Read segment table for the first packet */
73 do
74 {
75 ssize_t count = MIN(sizeof(buffer), (size_t) table_left);
76 int i;
77
78 if (read(file->fd, buffer, count) < count)
79 {
80 return false;
81 }
82
83 table_left -= count;
84
85 for (i = 0; i < count; i++)
86 {
87 file->packet_remaining += buffer[i];
88
89 if (buffer[i] < 255)
90 {
91 file->packet_ended = true;
92
93 /* Skip remainder of the table */
94 if (lseek(file->fd, table_left, SEEK_CUR) < 0)
95 {
96 return false;
97 }
98
99 table_left = 0;
100 break;
101 }
102 }
103 }
104 while (table_left > 0);
105
106 return true;
107}
108
109
110/* Read (up to) buffer_size of data from the file. If buffer is NULL, just
111 * skip ahead buffer_size bytes (like lseek). Returns number of bytes read,
112 * 0 if there is no more data to read (in the packet or the file), < 0 if a
113 * read error occurred.
114 */
115static ssize_t file_read(struct file* file, void* buffer, size_t buffer_size)
116{
117 ssize_t done = 0;
118 ssize_t count = -1;
119
120 do
121 {
122 if (file->packet_remaining <= 0)
123 {
124 if (file->packet_ended)
125 {
126 break;
127 }
128
129 if (!file_read_page_header(file))
130 {
131 count = -1;
132 break;
133 }
134 }
135
136 count = MIN(buffer_size, (size_t) file->packet_remaining);
137
138 if (buffer)
139 {
140 count = read(file->fd, buffer, count);
141 }
142 else
143 {
144 if (lseek(file->fd, count, SEEK_CUR) < 0)
145 {
146 count = -1;
147 }
148 }
149
150 if (count <= 0)
151 {
152 break;
153 }
154
155 if (buffer)
156 {
157 buffer += count;
158 }
159
160 buffer_size -= count;
161 done += count;
162 file->packet_remaining -= count;
163 }
164 while (buffer_size > 0);
165
166 return (count < 0 ? count : done);
167}
168
169
170/* Read an int32 from file. Returns false if a read error occurred.
171 */
172static bool file_read_int32(struct file* file, int32_t* value)
173{
174 char buf[sizeof(int32_t)];
175
176 if (file_read(file, buf, sizeof(buf)) < (ssize_t) sizeof(buf))
177 {
178 return false;
179 }
180
181 *value = get_long_le(buf);
182 return true;
183}
184
185
186/* Read a string from the file. Read up to buffer_size bytes, or, if eos
187 * != -1, until the eos character is found (eos is not stored in buf,
188 * unless it is nil). Writes up to buffer_size chars to buf, always
189 * terminating with a nil. Returns number of chars read or < 0 if a read
190 * error occurred.
191 *
192 * Unfortunately this is a slightly modified copy of read_string() in
193 * metadata_common.c...
194 */
195static long file_read_string(struct file* file, char* buffer,
196 long buffer_size, int eos, long size)
197{
198 long read_bytes = 0;
199
200 while (size > 0)
201 {
202 char c;
203
204 if (file_read(file, &c, 1) != 1)
205 {
206 read_bytes = -1;
207 break;
208 }
209
210 read_bytes++;
211 size--;
212
213 if ((eos != -1) && (eos == (unsigned char) c))
214 {
215 break;
216 }
217
218 if (buffer_size > 1)
219 {
220 *buffer++ = c;
221 buffer_size--;
222 }
223 else if (eos == -1)
224 {
225 /* No point in reading any more, skip remaining data */
226 if (file_read(file, NULL, size) < 0)
227 {
228 read_bytes = -1;
229 }
230 else
231 {
232 read_bytes += size;
233 }
234
235 break;
236 }
237 }
238
239 *buffer = 0;
240 return read_bytes;
241}
242
243
244/* Init struct file for reading from fd. type is the AFMT_* codec type of
245 * the file, and determines if Ogg pages are to be read. remaining is the
246 * max amount to read if codec type is FLAC; it is ignored otherwise.
247 * Returns true if the file was successfully initialized.
248 */
249static bool file_init(struct file* file, int fd, int type, int remaining)
250{
251 memset(file, 0, sizeof(*file));
252 file->fd = fd;
253
254 if (type == AFMT_OGG_VORBIS || type == AFMT_SPEEX)
255 {
256 if (!file_read_page_header(file))
257 {
258 return false;
259 }
260 }
261
262 if (type == AFMT_OGG_VORBIS)
263 {
264 char buffer[7];
265
266 /* Read packet header (type and id string) */
267 if (file_read(file, buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer))
268 {
269 return false;
270 }
271
272 /* The first byte of a packet is the packet type; comment packets
273 * are type 3.
274 */
275 if (buffer[0] != 3)
276 {
277 return false;
278 }
279 }
280 else if (type == AFMT_FLAC)
281 {
282 file->packet_remaining = remaining;
283 file->packet_ended = true;
284 }
285
286 return true;
287}
288
289
290/* Read the items in a Vorbis comment packet. For Ogg files, the file must
291 * be located on a page start, for other files, the beginning of the comment
292 * data (i.e., the vendor string length). Returns total size of the
293 * comments, or 0 if there was a read error.
294 */
295long read_vorbis_tags(int fd, struct mp3entry *id3,
296 long tag_remaining)
297{
298 struct file file;
299 char *buf = id3->id3v2buf;
300 int32_t comment_count;
301 int32_t len;
302 long comment_size = 0;
303 int buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
304 int i;
305
306 if (!file_init(&file, fd, id3->codectype, tag_remaining))
307 {
308 return 0;
309 }
310
311 /* Skip vendor string */
312
313 if (!file_read_int32(&file, &len) || (file_read(&file, NULL, len) < 0))
314 {
315 return 0;
316 }
317
318 if (!file_read_int32(&file, &comment_count))
319 {
320 return 0;
321 }
322
323 comment_size += 4 + len + 4;
324
325 for (i = 0; i < comment_count && file.packet_remaining > 0; i++)
326 {
327 char name[TAG_NAME_LENGTH];
328 int32_t read_len;
329
330 if (!file_read_int32(&file, &len))
331 {
332 return 0;
333 }
334
335 comment_size += 4 + len;
336 read_len = file_read_string(&file, name, sizeof(name), '=', len);
337
338 if (read_len < 0)
339 {
340 return 0;
341 }
342
343 len -= read_len;
344 read_len = file_read_string(&file, id3->path, sizeof(id3->path), -1, len);
345
346 if (read_len < 0)
347 {
348 return 0;
349 }
350
351 logf("Vorbis comment %d: %s=%s", i, name, id3->path);
352
353 /* Is it an embedded cuesheet? */
354 if (!strcasecmp(name, "CUESHEET"))
355 {
356 id3->has_embedded_cuesheet = true;
357 id3->embedded_cuesheet.pos = lseek(file.fd, 0, SEEK_CUR) - read_len;
358 id3->embedded_cuesheet.size = len;
359 id3->embedded_cuesheet.encoding = CHAR_ENC_UTF_8;
360 }
361 else
362 {
363 len = parse_tag(name, id3->path, id3, buf, buf_remaining,
364 TAGTYPE_VORBIS);
365 }
366
367 buf += len;
368 buf_remaining -= len;
369 }
370
371 /* Skip to the end of the block (needed by FLAC) */
372 if (file.packet_remaining)
373 {
374 if (file_read(&file, NULL, file.packet_remaining) < 0)
375 {
376 return 0;
377 }
378 }
379
380 return comment_size;
381}
diff --git a/lib/rbcodec/metadata/vox.c b/lib/rbcodec/metadata/vox.c
new file mode 100644
index 0000000000..f6bc849a88
--- /dev/null
+++ b/lib/rbcodec/metadata/vox.c
@@ -0,0 +1,49 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33bool get_vox_metadata(int fd, struct mp3entry* id3)
34{
35 /*
36 * vox is headerless format
37 *
38 * frequency: 8000 Hz
39 * channels: mono
40 * bitspersample: 4
41 */
42 id3->frequency = 8000;
43 id3->bitrate = 8000 * 4 / 1000;
44 id3->vbr = false; /* All VOX files are CBR */
45 id3->filesize = filesize(fd);
46 id3->length = id3->filesize >> 2;
47
48 return true;
49}
diff --git a/lib/rbcodec/metadata/wave.c b/lib/rbcodec/metadata/wave.c
new file mode 100644
index 0000000000..45acea1fa1
--- /dev/null
+++ b/lib/rbcodec/metadata/wave.c
@@ -0,0 +1,432 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 * Copyright (C) 2010 Yoshihisa Uchida
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25
26#include "system.h"
27#include "metadata.h"
28#include "metadata_common.h"
29#include "metadata_parsers.h"
30#include "rbunicode.h"
31#include "logf.h"
32
33#ifdef DEBUGF
34#undef DEBUGF
35#define DEBUGF(...)
36#endif
37
38/* Wave(RIFF)/Wave64 format */
39
40
41# define AV_WL32(p, d) do { \
42 ((uint8_t*)(p))[0] = (d); \
43 ((uint8_t*)(p))[1] = (d)>>8; \
44 ((uint8_t*)(p))[2] = (d)>>16; \
45 ((uint8_t*)(p))[3] = (d)>>24; \
46 } while(0)
47# define AV_WL16(p, d) do { \
48 ((uint8_t*)(p))[0] = (d); \
49 ((uint8_t*)(p))[1] = (d)>>8; \
50 } while(0)
51
52enum {
53 RIFF_CHUNK = 0,
54 WAVE_CHUNK,
55 FMT_CHUNK,
56 FACT_CHUNK,
57 DATA_CHUNK,
58 LIST_CHUNK,
59};
60
61/* Wave chunk names */
62#define WAVE_CHUNKNAME_LENGTH 4
63#define WAVE_CHUNKSIZE_LENGTH 4
64
65static const unsigned char * const wave_chunklist
66 = "RIFF"
67 "WAVE"
68 "fmt "
69 "fact"
70 "data"
71 "LIST";
72
73/* Wave64 GUIDs */
74#define WAVE64_CHUNKNAME_LENGTH 16
75#define WAVE64_CHUNKSIZE_LENGTH 8
76
77static const unsigned char * const wave64_chunklist
78 = "riff\x2e\x91\xcf\x11\xa5\xd6\x28\xdb\x04\xc1\x00\x00"
79 "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
80 "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
81 "fact\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
82 "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
83 "\xbc\x94\x5f\x92\x5a\x52\xd2\x11\x86\xdc\x00\xc0\x4f\x8e\xdb\x8a";
84
85/* list/info chunk */
86
87struct info_chunk {
88 const unsigned char* tag;
89 size_t offset;
90};
91
92/* info chunk names are common wave/wave64 */
93static const struct info_chunk info_chunks[] = {
94 { "INAM", offsetof(struct mp3entry, title), }, /* title */
95 { "IART", offsetof(struct mp3entry, artist), }, /* artist */
96 { "ISBJ", offsetof(struct mp3entry, albumartist), }, /* albumartist */
97 { "IPRD", offsetof(struct mp3entry, album), }, /* album */
98 { "IWRI", offsetof(struct mp3entry, composer), }, /* composer */
99 { "ICMT", offsetof(struct mp3entry, comment), }, /* comment */
100 { "ISRF", offsetof(struct mp3entry, grouping), }, /* grouping */
101 { "IGNR", offsetof(struct mp3entry, genre_string), }, /* genre */
102 { "ICRD", offsetof(struct mp3entry, year_string), }, /* date */
103 { "IPRT", offsetof(struct mp3entry, track_string), }, /* track/trackcount */
104 { "IFRM", offsetof(struct mp3entry, disc_string), }, /* disc/disccount */
105};
106
107#define INFO_CHUNK_COUNT ((int)ARRAYLEN(info_chunks))
108
109/* support formats */
110enum
111{
112 WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */
113 WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */
114 WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */
115 WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */
116 WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */
117 WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */
118 WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */
119 WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */
120 WAVE_FORMAT_XBOX_ADPCM = 0x0069, /* XBOX ADPCM */
121 IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */
122 IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */
123 WAVE_FORMAT_ATRAC3 = 0x0270, /* Atrac3 stream */
124 WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */
125 WAVE_FORMAT_EXTENSIBLE = 0xFFFE,
126};
127
128struct wave_fmt {
129 unsigned int formattag;
130 unsigned int channels;
131 unsigned int blockalign;
132 unsigned int bitspersample;
133 unsigned int samplesperblock;
134 uint32_t totalsamples;
135 uint64_t numbytes;
136};
137
138static unsigned char *convert_utf8(const unsigned char *src, unsigned char *dst,
139 int size, bool is_64)
140{
141 if (is_64)
142 {
143 /* Note: wave64: metadata codepage is UTF-16 only */
144 return utf16LEdecode(src, dst, size);
145 }
146 return iso_decode(src, dst, -1, size);
147}
148
149static void set_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3)
150{
151 switch (fmt->formattag)
152 {
153 case WAVE_FORMAT_PCM:
154 case WAVE_FORMAT_IEEE_FLOAT:
155 case WAVE_FORMAT_ALAW:
156 case WAVE_FORMAT_MULAW:
157 case IBM_FORMAT_ALAW:
158 case IBM_FORMAT_MULAW:
159 fmt->blockalign = fmt->bitspersample * fmt->channels >> 3;
160 fmt->samplesperblock = 1;
161 break;
162 case WAVE_FORMAT_YAMAHA_ADPCM:
163 if (id3->channels != 0)
164 {
165 fmt->samplesperblock =
166 (fmt->blockalign == ((id3->frequency / 60) + 4) * fmt->channels)?
167 id3->frequency / 30 : (fmt->blockalign << 1) / fmt->channels;
168 }
169 break;
170 case WAVE_FORMAT_DIALOGIC_OKI_ADPCM:
171 fmt->blockalign = 1;
172 fmt->samplesperblock = 2;
173 break;
174 case WAVE_FORMAT_SWF_ADPCM:
175 if (fmt->bitspersample != 0 && id3->channels != 0)
176 {
177 fmt->samplesperblock
178 = (((fmt->blockalign << 3) - 2) / fmt->channels - 22)
179 / fmt->bitspersample + 1;
180 }
181 break;
182 default:
183 break;
184 }
185
186 if (fmt->blockalign != 0)
187 fmt->totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock;
188}
189
190static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt *fmt,
191 struct mp3entry* id3)
192{
193 /* wFormatTag */
194 fmt->formattag = buf[0] | (buf[1] << 8);
195 /* wChannels */
196 fmt->channels = buf[2] | (buf[3] << 8);
197 /* dwSamplesPerSec */
198 id3->frequency = get_long_le(&buf[4]);
199 /* dwAvgBytesPerSec */
200 id3->bitrate = (get_long_le(&buf[8]) * 8) / 1000;
201 /* wBlockAlign */
202 fmt->blockalign = buf[12] | (buf[13] << 8);
203 /* wBitsPerSample */
204 fmt->bitspersample = buf[14] | (buf[15] << 8);
205
206 if (fmt->formattag != WAVE_FORMAT_EXTENSIBLE)
207 {
208 if (fmtsize > 19)
209 {
210 /* wSamplesPerBlock */
211 fmt->samplesperblock = buf[18] | (buf[19] << 8);
212 }
213 }
214 else if (fmtsize > 25)
215 {
216 /* wValidBitsPerSample */
217 fmt->bitspersample = buf[18] | (buf[19] << 8);
218 /* SubFormat */
219 fmt->formattag = buf[24] | (buf[25] << 8);
220 }
221
222 /* Check for ATRAC3 stream */
223 if (fmt->formattag == WAVE_FORMAT_ATRAC3)
224 {
225 int jsflag = 0;
226 if(id3->bitrate == 66 || id3->bitrate == 94)
227 jsflag = 1;
228
229 id3->extradata_size = 14;
230 id3->channels = 2;
231 id3->codectype = AFMT_OMA_ATRAC3;
232 id3->bytesperframe = fmt->blockalign;
233
234 /* Store the extradata for the codec */
235 AV_WL16(&id3->id3v2buf[0], 1); // always 1
236 AV_WL32(&id3->id3v2buf[2], id3->frequency);// samples rate
237 AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode
238 AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode
239 AV_WL16(&id3->id3v2buf[10], 1); // always 1
240 AV_WL16(&id3->id3v2buf[12], 0); // always 0
241 }
242}
243
244static void parse_list_chunk(int fd, struct mp3entry* id3, int chunksize, bool is_64)
245{
246 unsigned char tmpbuf[ID3V2_BUF_SIZE];
247 unsigned char *bp = tmpbuf;
248 unsigned char *endp;
249 unsigned char *data_pos;
250 unsigned char *tag_pos = id3->id3v2buf;
251 int datasize;
252 int infosize;
253 int remain;
254 int i;
255
256 if (is_64)
257 lseek(fd, 4, SEEK_CUR);
258 else if (read(fd, bp, 4) < 4 || memcmp(bp, "INFO", 4))
259 return;
260
261 /* decrease skip bytes */
262 chunksize -= 4;
263
264 infosize = read(fd, bp, (ID3V2_BUF_SIZE > chunksize)? chunksize : ID3V2_BUF_SIZE);
265 if (infosize <= 8)
266 return;
267
268 endp = bp + infosize;
269 while (bp < endp)
270 {
271 datasize = get_long_le(bp + 4);
272 data_pos = bp + 8;
273 remain = ID3V2_BUF_SIZE - (tag_pos - (unsigned char*)id3->id3v2buf);
274 if (remain < 1)
275 break;
276
277 for (i = 0; i < INFO_CHUNK_COUNT; i++)
278 {
279 if (memcmp(bp, info_chunks[i].tag, 4) == 0)
280 {
281 *((char **)(((char*)id3) + info_chunks[i].offset)) = tag_pos;
282 tag_pos = convert_utf8(data_pos, tag_pos,
283 (datasize + 1 >= remain )? remain - 1 : datasize,
284 is_64);
285 *tag_pos++ = 0;
286 break;
287 }
288 }
289 bp = data_pos + datasize + (datasize & 1);
290 };
291}
292
293static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunknames,
294 bool is_64)
295{
296 /* Use the temporary buffer */
297 unsigned char* buf = (unsigned char *)id3->path;
298
299 struct wave_fmt fmt;
300
301 const unsigned int namelen = (is_64)? WAVE64_CHUNKNAME_LENGTH : WAVE_CHUNKNAME_LENGTH;
302 const unsigned int sizelen = (is_64)? WAVE64_CHUNKSIZE_LENGTH : WAVE_CHUNKSIZE_LENGTH;
303 const unsigned int len = namelen + sizelen;
304 uint64_t chunksize;
305 uint64_t offset = len + namelen;
306 int read_data;
307
308 memset(&fmt, 0, sizeof(struct wave_fmt));
309
310 id3->vbr = false; /* All Wave/Wave64 files are CBR */
311 id3->filesize = filesize(fd);
312
313 /* get RIFF chunk header */
314 lseek(fd, 0, SEEK_SET);
315 read(fd, buf, offset);
316
317 if ((memcmp(buf, chunknames + RIFF_CHUNK * namelen, namelen) != 0) ||
318 (memcmp(buf + len, chunknames + WAVE_CHUNK * namelen, namelen) != 0))
319 {
320 DEBUGF("metadata error: missing riff header.\n");
321 return false;
322 }
323
324 /* iterate over WAVE chunks until 'data' chunk */
325 while (read(fd, buf, len) > 0)
326 {
327 offset += len;
328
329 /* get chunk size (when the header is wave64, chunksize includes GUID and data length) */
330 chunksize = (is_64) ? get_uint64_le(buf + namelen) - len :
331 get_long_le(buf + namelen);
332
333 read_data = 0;
334 if (memcmp(buf, chunknames + FMT_CHUNK * namelen, namelen) == 0)
335 {
336 DEBUGF("find 'fmt ' chunk\n");
337
338 if (chunksize < 16)
339 {
340 DEBUGF("metadata error: 'fmt ' chunk is too small: %d\n", (int)chunksize);
341 return false;
342 }
343
344 /* get and parse format */
345 read_data = (chunksize > 25)? 26 : chunksize;
346
347 read(fd, buf, read_data);
348 parse_riff_format(buf, read_data, &fmt, id3);
349 }
350 else if (memcmp(buf, chunknames + FACT_CHUNK * namelen, namelen) == 0)
351 {
352 DEBUGF("find 'fact' chunk\n");
353
354 /* dwSampleLength */
355 if (chunksize >= sizelen)
356 {
357 /* get totalsamples */
358 read_data = sizelen;
359 read(fd, buf, read_data);
360 fmt.totalsamples = (is_64)? get_uint64_le(buf) : get_long_le(buf);
361 }
362 }
363 else if (memcmp(buf, chunknames + DATA_CHUNK * namelen, namelen) == 0)
364 {
365 DEBUGF("find 'data' chunk\n");
366 fmt.numbytes = chunksize;
367 if (fmt.formattag == WAVE_FORMAT_ATRAC3)
368 id3->first_frame_offset = offset;
369 }
370 else if (memcmp(buf, chunknames + LIST_CHUNK * namelen, namelen) == 0)
371 {
372 DEBUGF("find 'LIST' chunk\n");
373 parse_list_chunk(fd, id3, chunksize, is_64);
374 lseek(fd, offset, SEEK_SET);
375 }
376
377 /* padded to next chunk */
378 chunksize += ((is_64)? ((1 + ~chunksize) & 0x07) : (chunksize & 1));
379
380 offset += chunksize;
381 if (offset >= id3->filesize)
382 break;
383
384 lseek(fd, chunksize - read_data, SEEK_CUR);
385 }
386
387 if (fmt.numbytes == 0)
388 {
389 DEBUGF("metadata error: read error or missing 'data' chunk.\n");
390 return false;
391 }
392
393 if (fmt.totalsamples == 0)
394 set_totalsamples(&fmt, id3);
395
396 if (id3->frequency == 0 || id3->bitrate == 0)
397 {
398 DEBUGF("metadata error: frequency or bitrate is 0\n");
399 return false;
400 }
401
402 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */
403 id3->length = (fmt.formattag != WAVE_FORMAT_ATRAC3)?
404 (uint64_t)fmt.totalsamples * 1000 / id3->frequency :
405 ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate;
406
407 /* output header/id3 info (for debug) */
408 DEBUGF("%s header info ----\n", (is_64)? "wave64" : "wave");
409 DEBUGF(" format: %04x\n", (int)fmt.formattag);
410 DEBUGF(" channels: %u\n", fmt.channels);
411 DEBUGF(" blockalign: %u\n", fmt.blockalign);
412 DEBUGF(" bitspersample: %u\n", fmt.bitspersample);
413 DEBUGF(" samplesperblock: %u\n", fmt.samplesperblock);
414 DEBUGF(" totalsamples: %u\n", (unsigned int)fmt.totalsamples);
415 DEBUGF(" numbytes: %u\n", (unsigned int)fmt.numbytes);
416 DEBUGF("id3 info ----\n");
417 DEBUGF(" frequency: %u\n", (unsigned int)id3->frequency);
418 DEBUGF(" bitrate: %d\n", id3->bitrate);
419 DEBUGF(" length: %u\n", (unsigned int)id3->length);
420
421 return true;
422}
423
424bool get_wave_metadata(int fd, struct mp3entry* id3)
425{
426 return read_header(fd, id3, wave_chunklist, false);
427}
428
429bool get_wave64_metadata(int fd, struct mp3entry* id3)
430{
431 return read_header(fd, id3, wave64_chunklist, true);
432}
diff --git a/lib/rbcodec/metadata/wavpack.c b/lib/rbcodec/metadata/wavpack.c
new file mode 100644
index 0000000000..f2811df8f3
--- /dev/null
+++ b/lib/rbcodec/metadata/wavpack.c
@@ -0,0 +1,160 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 David Bryant
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33#define ID_UNIQUE 0x3f
34#define ID_LARGE 0x80
35#define ID_SAMPLE_RATE 0x27
36
37#define MONO_FLAG 4
38#define HYBRID_FLAG 8
39
40static const long wavpack_sample_rates [] =
41{
42 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
43 32000, 44100, 48000, 64000, 88200, 96000, 192000
44};
45
46/* A simple parser to read basic information from a WavPack file. This
47 * now works with self-extrating WavPack files and also will scan the
48 * metadata for non-standard sampling rates. This no longer fails on
49 * WavPack files containing floating-point audio data because these are
50 * now converted to standard Rockbox format in the decoder, and also
51 * handles the case where up to 15 non-audio blocks might occur at the
52 * beginning of the file.
53 */
54
55bool get_wavpack_metadata(int fd, struct mp3entry* id3)
56{
57 /* Use the trackname part of the id3 structure as a temporary buffer */
58 unsigned char* buf = (unsigned char *)id3->path;
59 uint32_t totalsamples = (uint32_t) -1;
60 int i;
61
62 for (i = 0; i < 256; ++i) {
63
64 /* at every 256 bytes into file, try to read a WavPack header */
65
66 if ((lseek(fd, i * 256, SEEK_SET) < 0) || (read(fd, buf, 32) < 32))
67 return false;
68
69 /* if valid WavPack 4 header version, break */
70
71 if (memcmp (buf, "wvpk", 4) == 0 && buf [9] == 4 &&
72 (buf [8] >= 2 && buf [8] <= 0x10))
73 break;
74 }
75
76 if (i == 256) {
77 logf ("Not a WavPack file");
78 return false;
79 }
80
81 id3->vbr = true; /* All WavPack files are VBR */
82 id3->filesize = filesize (fd);
83
84 /* check up to 16 headers before we give up finding one with audio */
85
86 for (i = 0; i < 16; ++i) {
87 uint32_t meta_bytes = get_long_le(&buf [4]) - 24;
88 uint32_t trial_totalsamples = get_long_le(&buf[12]);
89 uint32_t blockindex = get_long_le(&buf[16]);
90 uint32_t blocksamples = get_long_le(&buf[20]);
91 uint32_t flags = get_long_le(&buf[24]);
92
93 if (totalsamples == (uint32_t) -1 && blockindex == 0)
94 totalsamples = trial_totalsamples;
95
96 if (blocksamples) {
97 int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14);
98
99 if (srindx == 15) {
100 uint32_t meta_size;
101
102 id3->frequency = 44100;
103
104 while (meta_bytes >= 6) {
105 if (read(fd, buf, 2) < 2)
106 break;
107
108 if (buf [0] & ID_LARGE) {
109 if (read(fd, buf + 2, 2) < 2)
110 break;
111
112 meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17);
113 meta_bytes -= meta_size + 4;
114 }
115 else {
116 meta_size = buf [1] << 1;
117 meta_bytes -= meta_size + 2;
118
119 if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) {
120 if (meta_size == 4 && read(fd, buf + 2, 4) == 4)
121 id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16);
122
123 break;
124 }
125 }
126
127 if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0)
128 break;
129 }
130 }
131 else
132 id3->frequency = wavpack_sample_rates[srindx];
133
134 /* if the total number of samples is still unknown, make a guess on the high side (for now) */
135
136 if (totalsamples == (uint32_t) -1) {
137 totalsamples = id3->filesize * 3;
138
139 if (!(flags & HYBRID_FLAG))
140 totalsamples /= 2;
141
142 if (!(flags & MONO_FLAG))
143 totalsamples /= 2;
144 }
145
146 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
147 id3->bitrate = id3->filesize / (id3->length / 8);
148
149 read_ape_tags(fd, id3);
150 return true;
151 }
152 else { /* block did not contain audio, so seek to the end and see if there's another */
153 if ((meta_bytes > 0 && lseek(fd, meta_bytes, SEEK_CUR) < 0) ||
154 read(fd, buf, 32) < 32 || memcmp (buf, "wvpk", 4) != 0)
155 break;
156 }
157 }
158
159 return false;
160}