ecf7860eb4
tags, and also make it deal with gaps after the header or junk before the actual start of mp3 data. This makes it able to properly extract info from all mp3 files I have.
224 lines
6.9 KiB
Text
224 lines
6.9 KiB
Text
$NetBSD: patch-ae,v 1.9 2009/09/26 21:16:58 martin Exp $
|
|
|
|
--- mserv/mp3info.c.orig 2003-07-29 02:17:48.000000000 +0200
|
|
+++ mserv/mp3info.c 2009-09-26 22:11:43.000000000 +0200
|
|
@@ -26,7 +26,17 @@
|
|
#define h_id(val) ((val>>19)&1)
|
|
#define h_thing(val) ((val>>20)&0xfff)
|
|
|
|
+#ifdef STANDALONE
|
|
+#define VERBOSE
|
|
+#endif
|
|
+#ifdef VERBOSE
|
|
+#define LOGF(ARG) printf ARG
|
|
+#else
|
|
+#define LOGF(ARG)
|
|
+#endif
|
|
+
|
|
#define ID3V2HEADERLEN 10
|
|
+#define min(x,y) ((x)<(y)?(x):(y))
|
|
|
|
/* mp3 bit rate and sampling frequency tables */
|
|
|
|
@@ -45,12 +55,14 @@ const int sampling_freq_table[2][3] =
|
|
/* structure of id3 tag in mp3 file */
|
|
|
|
typedef struct id3tag_disc_str
|
|
-{
|
|
- char title[MP3ID3_TITLELEN];
|
|
- char artist[MP3ID3_ARTISTLEN];
|
|
- char album[MP3ID3_ALBUMLEN];
|
|
- char year[MP3ID3_YEARLEN];
|
|
- char comment[MP3ID3_COMMENTLEN];
|
|
+{ /* These are all fixed lengths.
|
|
+ * Avoid #define'd lengths that get get redefined for other uses
|
|
+ */
|
|
+ char title[30];
|
|
+ char artist[30];
|
|
+ char album[30];
|
|
+ char year[4];
|
|
+ char comment[28];
|
|
unsigned char genre;
|
|
} id3tag_disc;
|
|
|
|
@@ -228,11 +240,28 @@ static int read_id3v2_frame(FILE *f, id3
|
|
if (fread(frame->data, 1, frame->datalen, f) != frame->datalen)
|
|
return -1;
|
|
if (frame->frameid[0] == 'T' && memcmp(frame->frameid + 1, "XXX", 3)) {
|
|
- frame->data[frame->datalen] = 0;
|
|
- if (frame->data[0] == 0) /* Only handle non unicode */
|
|
+ if (frame->data[0] == 0) {
|
|
+ /* ISO8859-1 */
|
|
+ frame->data[frame->datalen] = 0;
|
|
strcpy(frame->data, frame->data + 1);
|
|
- else
|
|
- frame->data[0] = 0;
|
|
+ } else if (frame->data[0] == 1 && frame->datalen >= 5) {
|
|
+ /* unicode, convert as long as it is 8 bit only */
|
|
+ int d = 0, i = 1, off0 = 0, off1 = 1;
|
|
+ /* check BOM vs. endianess */
|
|
+ if ((unsigned char)frame->data[i] == 0xff && (unsigned char)frame->data[i+1] == 0xfe) {
|
|
+ off0 = 1; off1 = 0;
|
|
+ } else if ((unsigned char)frame->data[i] == 0xfe && (unsigned char)frame->data[i+1] == 0xff) {
|
|
+ off1 = 1; off0 = 0;
|
|
+ } else {
|
|
+ return -1;
|
|
+ }
|
|
+ for (i=3; (i+1) < frame->datalen /* && frame->data[i] == 0 */; i+=2) {
|
|
+ frame->data[d++] = frame->data[i+off1];
|
|
+ if (frame->data[i] == 0 && frame->data[i+1] == 0)
|
|
+ break;
|
|
+ }
|
|
+ frame->data[d] = 0;
|
|
+ }
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -264,12 +293,12 @@ int mserv_mp3info_readlen(const char *fn
|
|
{
|
|
FILE *f;
|
|
int bitrate, fs, length, headerlen;
|
|
- long int filelen;
|
|
+ long int filelen, skipped;
|
|
float mean_frame_size;
|
|
char tag[3];
|
|
unsigned char data[4];
|
|
unsigned long int flags;
|
|
- int errnok;
|
|
+ int errnok, found;
|
|
char *e;
|
|
|
|
if (id3tag)
|
|
@@ -281,15 +310,39 @@ int mserv_mp3info_readlen(const char *fn
|
|
if ((headerlen = mp3_id3v2head(f)) == -1)
|
|
goto error;
|
|
|
|
- if (fseek(f, headerlen, SEEK_SET) == -1 || fread(&data, 4, 1, f) != 1)
|
|
+ if (fseek(f, headerlen, SEEK_SET) == -1 || fread(&data[0], 1, 1, f) != 1) {
|
|
+ LOGF(("%s: can't read after headerlen %d\n", fname, headerlen));
|
|
goto error;
|
|
+ }
|
|
|
|
- /* endian independent to 32-bit flags */
|
|
- flags = (data[0]<<24)+(data[1]<<16)+(data[2]<<8)+data[3];
|
|
- if (!is_mp3(flags)) {
|
|
- errno = EDOM;
|
|
+ found = skipped = 0;
|
|
+ for (;;) {
|
|
+ while (data[0] != 0xff) {
|
|
+ /* skip junk at beginning or after header - happens quite often */
|
|
+ if (fread(&data[0], 1, 1, f) != 1)
|
|
+ goto error;
|
|
+ skipped++;
|
|
+ if (headerlen < 1 && skipped > 4096)
|
|
+ break; /* we are not sure this even is a mp3 file */
|
|
+ }
|
|
+ if (fread(&data[1], 1, 3, f) != 3)
|
|
+ goto error;
|
|
+
|
|
+ /* endian independent to 32-bit flags */
|
|
+ flags = (data[0]<<24)+(data[1]<<16)+(data[2]<<8)+data[3];
|
|
+ if (is_mp3(flags)) {
|
|
+ found = 1;
|
|
+ break;
|
|
+ }
|
|
+ if (headerlen < 1 && skipped > 4096)
|
|
+ break; /* we are not sure this even is a mp3 file */
|
|
+ }
|
|
+ if (!found) {
|
|
+ LOGF(("%s: no header found within 4k\n", fname));
|
|
goto error;
|
|
}
|
|
+ if (skipped)
|
|
+ LOGF(("%s: skipped %ld bytes\n", fname, skipped));
|
|
|
|
bitrate = bitrate_table[h_id(flags)][3-h_layer(flags)]
|
|
[h_bitrate_index(flags)];
|
|
@@ -312,38 +365,44 @@ int mserv_mp3info_readlen(const char *fn
|
|
if (id3tag)
|
|
{
|
|
id3tag_disc tag_disc;
|
|
+ int len;
|
|
|
|
if (fread(&tag_disc, 1, 125, f) != 125)
|
|
goto error;
|
|
|
|
id3tag->present = 1;
|
|
|
|
- memcpy(id3tag->title, tag_disc.title, MP3ID3_TITLELEN);
|
|
- id3tag->title[MP3ID3_TITLELEN] = '\0';
|
|
+ len = min(MP3ID3_TITLELEN, sizeof(tag_disc.title));
|
|
+ memcpy(id3tag->title, tag_disc.title, len);
|
|
+ id3tag->title[len] = '\0';
|
|
e = id3tag->title + strlen(id3tag->title);
|
|
while (e > id3tag->title && *(e-1) == ' ')
|
|
*--e = '\0';
|
|
|
|
- memcpy(id3tag->artist, tag_disc.artist, MP3ID3_ARTISTLEN);
|
|
- id3tag->artist[MP3ID3_ARTISTLEN] = '\0';
|
|
+ len = min(MP3ID3_ARTISTLEN, sizeof(tag_disc.artist));
|
|
+ memcpy(id3tag->artist, tag_disc.artist, len);
|
|
+ id3tag->artist[len] = '\0';
|
|
e = id3tag->artist + strlen(id3tag->artist);
|
|
while (e > id3tag->artist && *(e-1) == ' ')
|
|
*--e = '\0';
|
|
|
|
- memcpy(id3tag->album, tag_disc.album, MP3ID3_ALBUMLEN);
|
|
- id3tag->album[MP3ID3_ALBUMLEN] = '\0';
|
|
+ len = min(MP3ID3_ALBUMLEN, sizeof(tag_disc.album));
|
|
+ memcpy(id3tag->album, tag_disc.album, len);
|
|
+ id3tag->album[len] = '\0';
|
|
e = id3tag->album + strlen(id3tag->album);
|
|
while (e > id3tag->album && *(e-1) == ' ')
|
|
*--e = '\0';
|
|
|
|
- memcpy(id3tag->year, tag_disc.year, MP3ID3_YEARLEN);
|
|
- id3tag->year[MP3ID3_YEARLEN] = '\0';
|
|
+ len = min(MP3ID3_YEARLEN, sizeof(tag_disc.year));
|
|
+ memcpy(id3tag->year, tag_disc.year, len);
|
|
+ id3tag->year[len] = '\0';
|
|
e = id3tag->year + strlen(id3tag->year);
|
|
while (e > id3tag->year && *(e-1) == ' ')
|
|
*--e = '\0';
|
|
|
|
- memcpy(id3tag->comment, tag_disc.comment, MP3ID3_COMMENTLEN);
|
|
- id3tag->comment[MP3ID3_COMMENTLEN] = '\0';
|
|
+ len = min(MP3ID3_COMMENTLEN, sizeof(tag_disc.comment));
|
|
+ memcpy(id3tag->comment, tag_disc.comment, len);
|
|
+ id3tag->comment[len] = '\0';
|
|
e = id3tag->comment + strlen(id3tag->comment);
|
|
while (e > id3tag->comment && *(e-1) == ' ')
|
|
*--e = '\0';
|
|
@@ -395,3 +454,32 @@ int mserv_mp3info_readlen(const char *fn
|
|
errno = errnok;
|
|
return -1;
|
|
}
|
|
+
|
|
+#ifdef STANDALONE
|
|
+int main(int argc, char **argv)
|
|
+{
|
|
+ t_id3tag tag;
|
|
+ int bitrate, len;
|
|
+
|
|
+ if (argc < 2) {
|
|
+ printf("usage: minfo (filename)\n");
|
|
+ return 1;
|
|
+ }
|
|
+ len = mserv_mp3info_readlen(argv[1], &bitrate, &tag);
|
|
+ if (len < 0) {
|
|
+ printf("no mp3 found\n");
|
|
+ } else {
|
|
+ if (bitrate)
|
|
+ printf("bitrate %d kbit/s, estimated length "
|
|
+ "%d:%02d.%02d s\n",
|
|
+ bitrate, len/6000, (len%6000)/100, len%100);
|
|
+ if (tag.present) {
|
|
+ printf("title: %s\n", tag.title);
|
|
+ printf("album: %s\n", tag.album);
|
|
+ printf("artist: %s\n", tag.artist);
|
|
+ printf("year: %s\n", tag.year);
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+#endif
|