summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorDan Everton <dan@iocaine.org>2007-12-09 03:16:26 +0000
committerDan Everton <dan@iocaine.org>2007-12-09 03:16:26 +0000
commit6fafb6cd989b449793c4ae065f5a97cab4b95230 (patch)
tree52aa957a3741b9648b6b6a07c0c4f1c0f8dc6832 /apps
parent44d8097dfa460e8c7135d1afe20ae5439ce4a141 (diff)
Unify the Ogg Vorbis and Ogg Speex metadata parsers.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15897 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/metadata.c4
-rw-r--r--apps/metadata/metadata_parsers.h3
-rw-r--r--apps/metadata/ogg.c265
3 files changed, 57 insertions, 215 deletions
diff --git a/apps/metadata.c b/apps/metadata.c
index 556350bfb6..3abbd74c35 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -134,7 +134,7 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
break;
case AFMT_OGG_VORBIS:
- if (!get_vorbis_metadata(fd, id3))/*detects and handles Ogg/Speex files*/
+ if (!get_ogg_metadata(fd, id3))/*detects and handles Ogg/Speex files*/
{
return false;
}
@@ -142,7 +142,7 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
break;
case AFMT_SPEEX:
- if (!get_speex_metadata(fd, id3))
+ if (!get_ogg_metadata(fd, id3))
{
return false;
}
diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h
index 5fbdf6f756..c3265f8a43 100644
--- a/apps/metadata/metadata_parsers.h
+++ b/apps/metadata/metadata_parsers.h
@@ -26,8 +26,7 @@ bool get_monkeys_metadata(int fd, struct mp3entry* id3);
bool get_musepack_metadata(int fd, struct mp3entry *id3);
bool get_sid_metadata(int fd, struct mp3entry* id3);
bool get_spc_metadata(int fd, struct mp3entry* id3);
-bool get_speex_metadata(int fd, struct mp3entry* id3);
-bool get_vorbis_metadata(int fd, struct mp3entry* id3);
+bool get_ogg_metadata(int fd, struct mp3entry* id3);
bool get_wave_metadata(int fd, struct mp3entry* id3);
bool get_wavpack_metadata(int fd, struct mp3entry* id3);
bool get_a52_metadata(int fd, struct mp3entry* id3);
diff --git a/apps/metadata/ogg.c b/apps/metadata/ogg.c
index a109694e9d..9b604a11a4 100644
--- a/apps/metadata/ogg.c
+++ b/apps/metadata/ogg.c
@@ -27,247 +27,89 @@
#include "metadata_common.h"
#include "logf.h"
-/* A simple parser to read vital metadata from an Ogg Speex file. Returns
- * false if metadata needed by the Speex codec couldn't be read.
+/* A simple parser to read vital metadata from an Ogg Vorbis file.
+ * Can also handle parsing Ogg Speex files for metadata. Returns
+ * false if metadata needed by the codec couldn't be read.
*/
-
-bool get_speex_metadata(int fd, struct mp3entry* id3)
+bool get_ogg_metadata(int fd, struct mp3entry* id3)
{
/* An Ogg File is split into pages, each starting with the string
* "OggS". Each page has a timestamp (in PCM samples) referred to as
* the "granule position".
*
+ * An Ogg Vorbis has the following structure:
+ * 1) Identification header (containing samplerate, numchannels, etc)
+ * 2) Comment header - containing the Vorbis Comments
+ * 3) Setup header - containing codec setup information
+ * 4) Many audio packets...
+ *
* An Ogg Speex has the following structure:
* 1) Identification header (containing samplerate, numchannels, etc)
- Described in this page: (http://www.speex.org/manual2/node7.html)
+ * Described in this page: (http://www.speex.org/manual2/node7.html)
* 2) Comment header - containing the Vorbis Comments
- * 3) Many audio packets...
+ * 3) Many audio packets.
*/
/* Use the path name of the id3 structure as a temporary buffer. */
- unsigned char* buf = (unsigned char*)id3->path;
+ unsigned char* buf = (unsigned char *)id3->path;
long comment_size;
long remaining = 0;
long last_serial = 0;
long serial, r;
- int segments;
+ int segments, header_size;
int i;
bool eof = false;
- if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 58) < 33))
+ /* 92 bytes is enough for both Vorbis and Speex headers */
+ if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 92) < 92))
{
return false;
}
-
- if ((memcmp(buf, "OggS", 4) != 0) || (memcmp(&buf[28], "Speex", 5) != 0))
+
+ /* All Ogg streams start with OggS */
+ if (memcmp(buf, "OggS", 4) != 0)
{
return false;
}
- /* We need to ensure the serial number from this page is the same as the
- * one from the last page (since we only support a single bitstream).
- */
- serial = get_long_le(&buf[14]);
- if ((lseek(fd, 33, SEEK_SET) < 0)||(read(fd, buf, 58) < 4))
- {
- return false;
- }
-
- id3->frequency = get_slong(&buf[31]);
- last_serial = get_long_le(&buf[27]);/*temporary, header size*/
- id3->bitrate = get_long_le(&buf[47]);
- id3->vbr = get_long_le(&buf[55]);
- id3->filesize = filesize(fd);
- /* Comments are in second Ogg page */
- if (lseek(fd, 28+last_serial/*(temporary for header size)*/, SEEK_SET) < 0)
+ /* Check for format magic and then get metadata */
+ if (memcmp(&buf[29], "vorbis", 6) == 0)
{
- return false;
- }
+ id3->codectype = AFMT_OGG_VORBIS;
+ id3->frequency = get_long_le(&buf[40]);
+ id3->vbr = true;
- /* Minimum header length for Ogg pages is 27. */
- if (read(fd, buf, 27) < 27)
- {
- return false;
- }
-
- if (memcmp(buf, "OggS", 4) !=0 )
- {
- return false;
- }
-
- segments = buf[26];
- /* read in segment table */
- if (read(fd, buf, segments) < segments)
- {
- return false;
- }
-
- /* The second packet in a vorbis stream is the comment packet. It *may*
- * extend beyond the second page, but usually does not. Here we find the
- * length of the comment packet (or the rest of the page if the comment
- * packet extends to the third page).
- */
- for (i = 0; i < segments; i++)
- {
- remaining += buf[i];
- /* The last segment of a packet is always < 255 bytes */
- if (buf[i] < 255)
+ /* Comments are in second Ogg page (byte 58 onwards for Vorbis) */
+ if (lseek(fd, 58, SEEK_SET) < 0)
{
- break;
+ return false;
}
}
-
- comment_size = remaining;
-
- /* Failure to read the tags isn't fatal. */
- read_vorbis_tags(fd, id3, remaining);
-
- /* We now need to search for the last page in the file - identified by
- * by ('O','g','g','S',0) and retrieve totalsamples.
- */
-
- /* A page is always < 64 kB */
- if (lseek(fd, -(MIN(64 * 1024, id3->filesize)), SEEK_END) < 0)
+ else if (memcmp(&buf[28], "Speex ", 8) == 0)
{
- return false;
- }
-
- remaining = 0;
+ id3->codectype = AFMT_SPEEX;
+ id3->frequency = get_slong(&buf[64]);
+ id3->vbr = get_long_le(&buf[88]);
- while (!eof)
- {
- r = read(fd, &buf[remaining], MAX_PATH - remaining);
-
- if (r <= 0)
- {
- eof = true;
- }
- else
- {
- remaining += r;
- }
-
- /* Inefficient (but simple) search */
- i = 0;
-
- while (i < (remaining - 3))
- {
- if ((buf[i] == 'O') && (memcmp(&buf[i], "OggS", 4) == 0))
- {
- if (i < (remaining - 17))
- {
- /* Note that this only reads the low 32 bits of a
- * 64 bit value.
- */
- id3->samples = get_long_le(&buf[i + 6]);
- last_serial = get_long_le(&buf[i + 14]);
-
- /* If this page is very small the beginning of the next
- * header could be in buffer. Jump near end of this header
- * and continue */
- i += 27;
- }
- else
- {
- break;
- }
- }
- else
- {
- i++;
- }
- }
+ header_size = get_long_le(&buf[60]);
- if (i < remaining)
+ /* Comments are in second Ogg page (byte 108 onwards for Speex) */
+ if (lseek(fd, 28 + header_size, SEEK_SET) < 0)
{
- /* Move the remaining bytes to start of buffer.
- * Reuse var 'segments' as it is no longer needed */
- segments = 0;
- while (i < remaining)
- {
- buf[segments++] = buf[i++];
- }
- remaining = segments;
- }
- else
- {
- /* Discard the rest of the buffer */
- remaining = 0;
+ return false;
}
}
-
- /* This file has mutiple vorbis bitstreams (or is corrupt). */
- /* FIXME we should display an error here. */
- if (serial != last_serial)
- {
- logf("serialno mismatch");
- logf("%ld", serial);
- logf("%ld", last_serial);
- return false;
- }
-
- id3->length = (id3->samples / id3->frequency) * 1000;
- id3->bitrate = (((int64_t) id3->filesize - comment_size) * 8) / id3->length;
- return true;
-}
-
-/* A simple parser to read vital metadata from an Ogg Vorbis file.
- * Calls get_speex_metadata if a speex file is identified. Returns
- * false if metadata needed by the Vorbis codec couldn't be read.
- */
-bool get_vorbis_metadata(int fd, struct mp3entry* id3)
-{
- /* An Ogg File is split into pages, each starting with the string
- * "OggS". Each page has a timestamp (in PCM samples) referred to as
- * the "granule position".
- *
- * An Ogg Vorbis has the following structure:
- * 1) Identification header (containing samplerate, numchannels, etc)
- * 2) Comment header - containing the Vorbis Comments
- * 3) Setup header - containing codec setup information
- * 4) Many audio packets...
- */
-
- /* Use the path name of the id3 structure as a temporary buffer. */
- unsigned char* buf = (unsigned char *)id3->path;
- long comment_size;
- long remaining = 0;
- long last_serial = 0;
- long serial, r;
- int segments;
- int i;
- bool eof = false;
-
- if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 58) < 4))
+ else
{
return false;
}
-
- if ((memcmp(buf, "OggS", 4) != 0) || (memcmp(&buf[29], "vorbis", 6) != 0))
- {
- if ((memcmp(buf, "OggS", 4) != 0) || (memcmp(&buf[28], "Speex", 5) != 0))
- {
- return false;
- }
- else
- {
- id3->codectype = AFMT_SPEEX;
- return get_speex_metadata(fd, id3);
- }
- }
+
+ id3->filesize = filesize(fd);
/* We need to ensure the serial number from this page is the same as the
* one from the last page (since we only support a single bitstream).
*/
serial = get_long_le(&buf[14]);
- id3->frequency = get_long_le(&buf[40]);
- id3->filesize = filesize(fd);
-
- /* Comments are in second Ogg page */
- if (lseek(fd, 58, SEEK_SET) < 0)
- {
- return false;
- }
/* Minimum header length for Ogg pages is 27. */
if (read(fd, buf, 27) < 27)
@@ -304,21 +146,24 @@ bool get_vorbis_metadata(int fd, struct mp3entry* id3)
}
}
- /* Now read in packet header (type and id string) */
- if (read(fd, buf, 7) < 7)
- {
- return false;
- }
-
comment_size = remaining;
- remaining -= 7;
+
+ if (id3->codectype == AFMT_OGG_VORBIS) {
+ /* Now read in packet header (type and id string) */
+ if (read(fd, buf, 7) < 7)
+ {
+ return false;
+ }
- /* The first byte of a packet is the packet type; comment packets are
- * type 3.
- */
- if ((buf[0] != 3) || (memcmp(buf + 1, "vorbis", 6) !=0))
- {
- return false;
+ remaining -= 7;
+
+ /* The first byte of a packet is the packet type; comment packets are
+ * type 3.
+ */
+ if (buf[0] != 3)
+ {
+ return false;
+ }
}
/* Failure to read the tags isn't fatal. */
@@ -409,7 +254,6 @@ bool get_vorbis_metadata(int fd, struct mp3entry* id3)
}
id3->length = ((int64_t) id3->samples * 1000) / id3->frequency;
-
if (id3->length <= 0)
{
logf("ogg length invalid!");
@@ -417,7 +261,6 @@ bool get_vorbis_metadata(int fd, struct mp3entry* id3)
}
id3->bitrate = (((int64_t) id3->filesize - comment_size) * 8) / id3->length;
- id3->vbr = true;
return true;
}