diff options
Diffstat (limited to 'apps/metadata/ogg.c')
-rw-r--r-- | apps/metadata/ogg.c | 215 |
1 files changed, 0 insertions, 215 deletions
diff --git a/apps/metadata/ogg.c b/apps/metadata/ogg.c deleted file mode 100644 index 3a3cb29998..0000000000 --- a/apps/metadata/ogg.c +++ /dev/null | |||
@@ -1,215 +0,0 @@ | |||
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 | */ | ||
37 | bool 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 | |||