From 16da97e4c80b375f6976690e0a04102eff0a6bbd Mon Sep 17 00:00:00 2001
From: Warren Dukes <warren.dukes@gmail.com>
Date: Tue, 1 Jun 2004 12:50:15 +0000
Subject: parsing mp3 id3v2 tags on the fly for streams

git-svn-id: https://svn.musicpd.org/mpd/trunk@1281 09075e82-0dd4-0310-85a5-a0d7c8717e4f
---
 TODO                          |  5 +--
 src/decode.c                  |  2 +-
 src/inputPlugins/mp3_plugin.c | 88 ++++++++++++++++++++++++++++++++++++++-----
 src/tag.c                     | 49 +++++++++++++-----------
 src/tag.h                     | 11 ++++++
 5 files changed, 118 insertions(+), 37 deletions(-)

diff --git a/TODO b/TODO
index db9abaadc..3027f1105 100644
--- a/TODO
+++ b/TODO
@@ -1,9 +1,6 @@
 1) play streams
 	a) put some sort of error reporting for streaming/inputStream!
-	b) parse metadata on the fly in decoders
-	c) command for dealing with the changing metadata, currentsonginfo
-		or something
-	d) in songinfo add a metadata tag item for indicating stream
+	b) in songinfo add a metadata tag item for indicating stream
 
 2) http stuff
 	a) allow http proxy
diff --git a/src/decode.c b/src/decode.c
index e5c1bfa03..4d04e4c74 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -608,7 +608,7 @@ void decode() {
 		strncpy(dc->metadata+pos, string, \
                                 DECODE_METADATA_LENGTH-1-pos); \
 		element = pos; \
-		pos += slen; \
+		pos += slen+1; \
 	} \
 }
 
diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c
index 8f57fb590..d0d98b045 100644
--- a/src/inputPlugins/mp3_plugin.c
+++ b/src/inputPlugins/mp3_plugin.c
@@ -196,7 +196,56 @@ int fillMp3InputBuffer(mp3DecodeData * data) {
 	return 0;
 }
 
-int decodeNextFrameHeader(mp3DecodeData * data) {
+#ifdef HAVE_ID3TAG
+static MpdTag * mp3_parseId3Tag(mp3DecodeData * data, signed long tagsize) {
+	MpdTag * ret = NULL;
+	struct id3_tag * id3Tag = NULL;
+	id3_length_t count;
+	id3_byte_t const *id3_data;
+	id3_byte_t * allocated = NULL;
+
+	count = data->stream.bufend - data->stream.this_frame;
+
+	if(tagsize <= count) {
+		id3_data = data->stream.this_frame;
+		mad_stream_skip(&(data->stream), tagsize);
+	}
+	else {
+		allocated = malloc(tagsize);
+		if(!allocated) goto fail;
+
+		memcpy(allocated, data->stream.this_frame, count);
+		mad_stream_skip(&(data->stream), count);
+
+		while(count < tagsize) {
+			int len;
+
+			len = readFromInputStream(data->inStream, 
+				allocated+count, (size_t)1, 
+				tagsize-count);
+			if(len <= 0 && inputStreamAtEOF(data->inStream))				{
+				break;
+			}
+			else if(len <= 0) my_usleep(10000);
+			else count += len;
+		}
+
+		if(count != tagsize) goto fail;
+
+		id3_data = allocated;
+	}
+
+	id3Tag = id3_tag_parse(id3_data, tagsize);
+ 
+	ret = parseId3Tag(id3Tag);
+
+fail:
+	if(allocated) free(allocated);
+	return ret;
+}
+#endif
+
+int decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag) {
 	if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) {
 		if(fillMp3InputBuffer(data) < 0) {
 			return DECODE_BREAK;
@@ -211,13 +260,23 @@ int decodeNextFrameHeader(mp3DecodeData * data) {
 					(data->stream).this_frame,
 					(data->stream).bufend-
 					(data->stream).this_frame);
+
+			printf("HERE 1\n");
 			if(tagsize>0) {
-				mad_stream_skip(&(data->stream),tagsize);
+				printf("HERE 1-1\n");
+				if(tag) *tag =mp3_parseId3Tag(data, tagsize);
+				else {
+					mad_stream_skip(&(data->stream),
+							tagsize);
+				}
+				printf("HERE 1-2\n");
 				return DECODE_CONT;
 			}
+			printf("HERE 2\n");
 		}
 #endif
 		if(MAD_RECOVERABLE((data->stream).error)) {
+			if(tag) printf("AHHH\n");
 			return DECODE_SKIP;
 		}
 		else {
@@ -331,7 +390,9 @@ fail:
   	return 0;
 }
 
-int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc) {
+int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc,
+		MpdTag ** tag) 
+{
 	struct xing xing;
 	int ret;
 	int skip;
@@ -341,7 +402,7 @@ int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc) {
 
 	while(1) {
 		skip = 0;
-		while((ret = decodeNextFrameHeader(data))==DECODE_CONT && 
+		while((ret = decodeNextFrameHeader(data, tag))==DECODE_CONT && 
 				(!dc || !dc->stop));
 		if(ret==DECODE_SKIP) skip = 1;
 		else if(ret==DECODE_BREAK || (dc && dc->stop)) return -1;
@@ -409,7 +470,7 @@ int getMp3TotalTime(char * file) {
         if(openInputStream(&inStream, file) < 0) return -1;
 	initMp3DecodeData(&data,&inStream);
         data.stream.options |= MAD_OPTION_IGNORECRC;
-	if(decodeFirstFrame(&data, NULL)<0) ret = -1;
+	if(decodeFirstFrame(&data, NULL, NULL)<0) ret = -1;
 	else ret = data.totalTime+0.5;
 	mp3DecodeDataFinalize(&data);
 
@@ -417,12 +478,14 @@ int getMp3TotalTime(char * file) {
 }
 
 int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
-		DecoderControl * dc) 
+		DecoderControl * dc, MpdTag ** tag) 
 {
 	initMp3DecodeData(data, inStream);
         data->stream.options |= MAD_OPTION_IGNORECRC;
-	if(decodeFirstFrame(data, dc)<0) {
+	*tag = NULL;
+	if(decodeFirstFrame(data, dc, tag)<0) {
 		mp3DecodeDataFinalize(data);
+		if(tag && *tag) freeMpdTag(*tag);
 		return -1;
 	}
 
@@ -540,7 +603,7 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
 
 	while(1) {
 		skip = 0;
-		while((ret = decodeNextFrameHeader(data))==DECODE_CONT &&
+		while((ret = decodeNextFrameHeader(data, NULL))==DECODE_CONT &&
 				!dc->stop && !dc->seek);
 		if(ret==DECODE_BREAK || dc->stop || dc->seek) break;
 		else if(ret==DECODE_SKIP) skip = 1;
@@ -565,8 +628,9 @@ void initAudioFormatFromMp3DecodeData(mp3DecodeData * data, AudioFormat * af) {
 
 int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
 	mp3DecodeData data;
+	MpdTag * tag;
 
-	if(openMp3FromInputStream(inStream, &data, dc) < 0) {
+	if(openMp3FromInputStream(inStream, &data, dc, &tag) < 0) {
                 closeInputStream(inStream);
 		if(!dc->stop) {
                         ERROR("Input does not appear to be a mp3 bit stream.\n");
@@ -583,6 +647,12 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
         getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
         
 	dc->totalTime = data.totalTime;
+
+	if(tag) {
+		copyMpdTagToDecoderControlMetadata(dc, tag);
+		freeMpdTag(tag);
+	}
+
 	dc->state = DECODE_STATE_DECODE;
 
 	while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
diff --git a/src/tag.c b/src/tag.c
index ae9d41040..50c1dcd86 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -37,13 +37,6 @@
 #include <FLAC/file_decoder.h>
 #include <FLAC/metadata.h>
 #endif
-#ifdef HAVE_ID3TAG
-#ifdef USE_MPD_ID3TAG
-#include "libid3tag/id3tag.h"
-#else
-#include <id3tag.h>
-#endif
-#endif
 
 void printMpdTag(FILE * fp, MpdTag * tag) {
 	if(tag->artist) myfprintf(fp,"Artist: %s\n",tag->artist);
@@ -95,25 +88,11 @@ char * getID3Info(struct id3_tag * tag, char * id) {
 }
 #endif
 
-MpdTag * id3Dup(char * file) {
-	MpdTag * ret = NULL;
 #ifdef HAVE_ID3TAG
-	struct id3_file * id3_file;
-	struct id3_tag * tag;
+MpdTag * parseId3Tag(struct id3_tag * tag) {
+	MpdTag * ret = NULL;
 	char * str;
 
-	id3_file = id3_file_open(file, ID3_FILE_MODE_READONLY);
-			
-	if(!id3_file) {
-		return NULL;
-	}
-
-	tag = id3_file_tag(id3_file);
-	if(!tag) {
-		id3_file_close(id3_file);
-		return NULL;
-	}
-
 	str = getID3Info(tag,ID3_FRAME_ARTIST);
 	if(str) {
 		if(!ret) ret = newMpdTag();
@@ -142,6 +121,30 @@ MpdTag * id3Dup(char * file) {
 		ret->track = str;
 	}
 
+	return ret;
+}
+#endif
+
+MpdTag * id3Dup(char * file) {
+	MpdTag * ret = NULL;
+#ifdef HAVE_ID3TAG
+	struct id3_file * id3_file;
+	struct id3_tag * tag;
+
+	id3_file = id3_file_open(file, ID3_FILE_MODE_READONLY);
+			
+	if(!id3_file) {
+		return NULL;
+	}
+
+	tag = id3_file_tag(id3_file);
+	if(!tag) {
+		id3_file_close(id3_file);
+		return NULL;
+	}
+
+	ret = parseId3Tag(tag);
+
 	id3_file_close(id3_file);
 
 #endif
diff --git a/src/tag.h b/src/tag.h
index 87cac2b97..225b3189e 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -22,6 +22,13 @@
 #include "../config.h"
 
 #include <stdio.h>
+#ifdef HAVE_ID3TAG
+#ifdef USE_MPD_ID3TAG
+#include "libid3tag/id3tag.h"
+#else
+#include <id3tag.h>
+#endif
+#endif
 
 typedef struct _MpdTag {
 	char * artist;
@@ -31,6 +38,10 @@ typedef struct _MpdTag {
 	int time;
 } MpdTag;
 
+#ifdef HAVE_ID3TAG
+MpdTag * parseId3Tag(struct id3_tag *);
+#endif
+
 MpdTag * id3Dup(char * file);
 
 MpdTag * newMpdTag();
-- 
cgit v1.2.3