[xiph-commits] r7170 - in trunk/ezstream: . conf src win32

oddsock at dactyl.lonelymoon.com oddsock
Sun Jul 18 20:12:35 PDT 2004


Author: oddsock
Date: Sun Jul 18 20:12:35 2004
New Revision: 7170

Added:
trunk/ezstream/conf/ezstream_reencoding_example.xml
Modified:
trunk/ezstream/README
trunk/ezstream/conf/Makefile.am
trunk/ezstream/configure.in
trunk/ezstream/src/configfile.c
trunk/ezstream/src/configfile.h
trunk/ezstream/src/ezstream.c
trunk/ezstream/win32/ezstream.dsp
Log:
Added reencoding capabilities to ezstream.


Modified: trunk/ezstream/README
===================================================================
--- trunk/ezstream/README	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/README	2004-07-19 03:12:31 UTC (rev 7170)
@@ -10,7 +10,7 @@
controlled via a XML config file (a few examples are provided in the conf
directory).

-ezstream can stream mp3 and ogg vorbis files as well as reading from stdin.
+ezstream can stream mp3, ogg vorbis, and ogg theora files as well as reading from stdin.
ID3v1 tags are supported in mp3 files and all ogg vorbis tags are propagated
as metadata as well.

@@ -23,7 +23,7 @@
<ezstream>
<url>http://localhost:8000/testmount.ogg</url>
<sourcepassword>hackme</sourcepassword>
-    <format>OGGVORBIS</format>
+    <format>VORBIS</format>
<filename>sunking.ogg</filename>
<svrinfoname>My Stream</svrinfoname>
<svrinfourl>http://www.oddsock.org</svrinfourl>
@@ -34,13 +34,17 @@
<svrinfochannels>2</svrinfochannels>
<svrinfosamplerate>44100</svrinfosamplerate>
<svrinfopublic>1</svrinfopublic>
+    <reencode>
+	<enable>0</enable>
+    </reencode>
</ezstream>

URL - this URL specified the location and mountpoint of the icecast server
to which the stream will be sent.
SOURCEPASSWORD - the source password for the icecast server
-FORMAT - either MP3 or OGGVORBIS, you must specify which format you input
-         files are in.
+FORMAT - either MP3, VORBIS or THEORA, This is the output format of your stream.
+         If you are not reencoding, then this also must be the same format as your
+	 input files.
FILENAME - This can be a single file (in which ezstream will stream that
file over and over continuously) or can be a .m3u file which
is a playlist of files.  currently, ezstream will go through
@@ -60,3 +64,76 @@
SVRINFOSAMPLERATE - (informational only) (used for YP)
SVRINFOPUBLIC - Indicates wether to list this stream in a public YP.

+
+REENCODING
+:::::::::::::::
+ezstream now support reencoding.  This means that your output stream need not
+be the same bitrate/samplerate or even format as your input files.
+
+Reencoding is supported via the use of external programs.  When you enable reencoding
+you need to make sure of a few things :
+
+1. You define a "decoder" for each type of input file.
+2. You define a "encoder" for each possible type of output stream.
+
+So if you had a mixture of mp3 and vorbis files in your playlist, you will need to make
+sure that a decoder is provided for each type.  Ezstream will take the output of the
+decoder and send it directly to the specific encoder.  All output of the decoder should
+be written to stdout and should be in raw form.  Most decoder support this mode.  Encoders
+should all be configured also with raw input and should read it from stdin.
+
+The following decoder/encoders can be used :
+
+For MP3 :
+decoder : madplay
+encoder : lame
+
+For Vorbis :
+decoder : oggdec
+encoder : oggenc
+
+For FLAC :
+decoder : FLAC
+encoder : not yet supported by libshout, and thus not by ezstream.
+
+Additional decoders and encoders may be used, as long as they follow the rules defined above.
+
+The following config file section defines the reencoding parameters :
+
+<reencode>
+	<enable>1</enable>
+	<encdec>
+	<!-- Support for FLAC decoding (input files) -->
+		<format>FLAC</format> <!-- format = output stream format -->
+		<match>.flac</match>  <!-- match = input file format -->
+		<decode>flac -s -d --force-raw-format --sign=signed --endian=little @T@ -o -</decode>
+		<encode>Not supported Yet</encode>
+	</encdec>
+	<encdec>
+	<!-- Support for MP3 decoding via madplay, and encoding via LAME -->
+		<format>MP3</format>
+		<match>.mp3</match>
+		<decode>madplay -o raw:- @T@ 2>/dev/null</decode>
+		<encode>lame -r -x -b 56 -s 44.1 --resample 22.05 -a - - 2>/dev/null</encode>
+	</encdec>
+	<encdec>
+	<!-- Support for Vorbis decoding via oggdec, and encoding via oggenc -->
+		<format>VORBIS</format>
+		<match>.ogg</match>
+		<decode>oggdec --raw=1 @T@ -o - 2>/dev/null</decode>
+		<encode>oggenc -Q -r -q 0 --resample=44100 --downmix -t "@M@" -c STREAMER=ezstream -</encode>
+	</encdec>
+</reencode>
+
+
+Note that the following keywords can be used :
+
+ at T@ = The fully qualified name of the track being played in the playlist
+ at M@ = The metadata for the current track
+
+All encoding options (bitrate/samplerate/channels/quality) are set as command line options of
+each of the encoders.  Each encoder has slightly different options that control these values.
+The examples here can be used as a guide, but please make sure you check the manual for each
+encoder for the correct encoding options.  In all cases, the encoder should be configured to
+read RAW audio data from stdin.
+

Modified: trunk/ezstream/conf/Makefile.am
===================================================================
--- trunk/ezstream/conf/Makefile.am	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/conf/Makefile.am	2004-07-19 03:12:31 UTC (rev 7170)
@@ -2,4 +2,4 @@

AUTOMAKE_OPTIONS = foreign

-EXTRA_DIST = ezstream_m3u.xml ezstream_mp3.xml ezstream_vorbis.xml
+EXTRA_DIST = ezstream_m3u.xml ezstream_mp3.xml ezstream_vorbis.xml ezstream_reencoding_example.xml

Added: trunk/ezstream/conf/ezstream_reencoding_example.xml
===================================================================
--- trunk/ezstream/conf/ezstream_reencoding_example.xml	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/conf/ezstream_reencoding_example.xml	2004-07-19 03:12:31 UTC (rev 7170)
@@ -0,0 +1,60 @@
+<ezstream>
+    <url>http://192.168.6.1:8000/testmount.ogg</url>
+    <sourcepassword>hackme</sourcepassword>
+    <!-- This is what form your output will take. If you are
+         reencoding, this is the format to reencode to, if not
+         then you need to make sure all your input files are in this
+         format -->
+    <format>VORBIS</format>
+    <filename>tracks.m3u</filename>
+    <!-- The following settings are used to describe your stream
+         to the server.  It's up to you to make sure the
+         bitrate/quality/samplerate/channels
+         match up to your output stream -->
+    <svrinfoname>My Stream</svrinfoname>
+    <svrinfourl>http://www.oddsock.org</svrinfourl>
+    <svrinfogenre>RockNRoll</svrinfogenre>
+    <svrinfodescription>This is a stream description</svrinfodescription>
+    <svrinfobitrate>128</svrinfobitrate>
+    <!-- Quality is only applicable to ogg vorbis streams -->
+    <!-- <svrinfoquality>1.0</svrinfoquality> -->
+    <svrinfochannels>2</svrinfochannels>
+    <svrinfosamplerate>44100</svrinfosamplerate>
+    <svrinfopublic>1</svrinfopublic>
+    <reencode>
+	<enable>1</enable>
+        <!-- Each encdec block specifies a pair of programs used for decoding and
+             encoding of the stream.  If reencoding is enabled, then all input files
+             must be first decoded before being sent to the encoder.  EZSTREAM uses
+             file extensions to match up input files with the appropraite decoder,
+             and uses the <format> setting to match up the output format with the
+             appropriate encoder.
+
+             Note: It it up to you to set the appropriate bitrate/samplerate/channels
+             of the output stream by using command line paramters to the encoders. Use
+             the examples defined here as a guide.  All output from decoders should be in
+             RAW format, and all input to the encoders should also be in RAW format. -->
+	<encdec>
+		<!-- Support for FLAC decoding (input files) -->
+		<format>FLAC</format>
+		<match>.flac</match>
+		<decode>flac -s -d --force-raw-format --sign=signed --endian=little @T@ -o -</decode>
+		<encode>Not supported Yet</encode>
+	</encdec>
+	<encdec>
+		<!-- Support for MP3 decoding via madplay, and encoding via LAME -->
+		<format>MP3</format>
+		<match>.mp3</match>
+		<decode>madplay -o raw:- @T@ 2>/dev/null</decode>
+		<encode>lame -r -x -b 56 -s 44.1 --resample 22.05 -a - - 2>/dev/null</encode>
+	</encdec>
+	<encdec>
+		<!-- Support for Vorbis decoding via oggdec, and encoding via oggenc -->
+		<format>VORBIS</format>
+		<match>.ogg</match>
+		<decode>oggdec --raw=1 @T@ -o - 2>/dev/null</decode>
+		<encode>oggenc -Q -r -q 0 --resample=44100 --downmix -t "@M@" -c STREAMER=ezstream -</encode>
+	</encdec>
+	<!-- New encdec sections can be added for new input/output formats -->
+    </reencode>
+</ezstream>

Modified: trunk/ezstream/configure.in
===================================================================
--- trunk/ezstream/configure.in	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/configure.in	2004-07-19 03:12:31 UTC (rev 7170)
@@ -77,8 +77,8 @@
XIPH_VAR_PREPEND([XIPH_LIBS], [$SHOUT_LIBS])

XIPH_PATH_VORBIS(, AC_MSG_ERROR([must have Ogg Vorbis v1.0 installed!]))
-XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$VORBIS_CFLAGS])
-XIPH_VAR_PREPEND([XIPH_LIBS],[$VORBIS_LIBS])
+XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$VORBIS_CFLAGS $VORBISFILE_CFLAGS])
+XIPH_VAR_PREPEND([XIPH_LIBS],[$VORBIS_LIBS $VORBISFILE_LIBS])

dnl Make substitutions


Modified: trunk/ezstream/src/configfile.c
===================================================================
--- trunk/ezstream/src/configfile.c	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/src/configfile.c	2004-07-19 03:12:31 UTC (rev 7170)
@@ -2,13 +2,54 @@
#include "configfile.h"

static EZCONFIG	ezConfig;
+static char	*blankString = "";

EZCONFIG *getEZConfig() {
return &ezConfig;
}

+char*	getFormatEncoder(char *format)
+{
+	int i = 0;
+	for (i=0;i<ezConfig.numEncoderDecoders;i++) {
+		if (ezConfig.encoderDecoders[i]) {
+			if (ezConfig.encoderDecoders[i]->format) {
+				if (!strcmp(ezConfig.encoderDecoders[i]->format, format)) {
+					if (ezConfig.encoderDecoders[i]->encoder) {
+						return ezConfig.encoderDecoders[i]->encoder;
+					}
+					else {
+						return blankString;
+					}
+				}
+			}
+		}
+	}
+	return blankString;
+}
+
+char*	getFormatDecoder(char *match)
+{
+	int i = 0;
+	for (i=0;i<ezConfig.numEncoderDecoders;i++) {
+		if (ezConfig.encoderDecoders[i]) {
+			if (ezConfig.encoderDecoders[i]->match) {
+				if (!strcmp(ezConfig.encoderDecoders[i]->match, match)) {
+					if (ezConfig.encoderDecoders[i]->decoder) {
+						return ezConfig.encoderDecoders[i]->decoder;
+					}
+					else {
+						return blankString;
+					}
+				}
+			}
+		}
+	}
+	return blankString;
+}
void printConfig()
{
+	int i = 0;
if (ezConfig.URL) {
printf("URL to connect to (%s)\n", ezConfig.URL);
}
@@ -24,9 +65,12 @@
if (ezConfig.format == MP3_FORMAT) {
printf("Broadcasting in MP3 format\n");
}
-	if (ezConfig.format == OGG_FORMAT) {
-		printf("Broadcasting in Ogg format\n");
+	if (ezConfig.format == VORBIS_FORMAT) {
+		printf("Broadcasting in Ogg Vorbis format\n");
}
+	if (ezConfig.format == THEORA_FORMAT) {
+		printf("Broadcasting in Ogg Theora format\n");
+	}
if (ezConfig.format == 0) {
printf("Broadcast format not set\n");
}
@@ -90,6 +134,44 @@
else {
printf("Server is a private server\n");
}
+	if (ezConfig.reencode) {
+		printf("We will reencode using the following information:\n");
+		printf("\tEncoders/Decoders:\n");
+		for (i=0;i<ezConfig.numEncoderDecoders;i++) {
+			if (ezConfig.encoderDecoders[i]) {
+				if (ezConfig.encoderDecoders[i]->match) {
+					if (ezConfig.encoderDecoders[i]->decoder) {
+							printf("\t\tFor files of extension (%s)\n", ezConfig.encoderDecoders[i]->match);
+							printf("\t\t\tDecoder: (%s)\n", ezConfig.encoderDecoders[i]->decoder);
+					}
+					else {
+						printf("\t\tNull decoder\n");
+					}
+				}
+				else {
+					printf("\t\tNull match\n");
+				}
+				if (ezConfig.encoderDecoders[i]->format) {
+					if (ezConfig.encoderDecoders[i]->encoder) {
+						printf("\t\tFor output formats of type (%s)\n", ezConfig.encoderDecoders[i]->format);
+						printf("\t\t\tEncoder: (%s)\n", ezConfig.encoderDecoders[i]->encoder);
+					}
+					else {
+						printf("\t\tNull encoder\n");
+					}
+				}
+				else {
+					printf("\t\tNull match\n");
+				}
+			}
+			else {
+				printf("Error, NULL GRABBER\n");
+			}
+		}
+	}
+	else {
+		printf("We will NOT reencode.\n");
+	}

}
int parseConfig(char *fileName)
@@ -142,12 +224,9 @@
if (cur->xmlChildrenNode != NULL) {
ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode,1);
if ( strlen(ls_xmlContentPtr) > 0 ) {
-					if (!strcmp(ls_xmlContentPtr, "MP3")) {
-						ezConfig.format = MP3_FORMAT;
-					}
-					if (!strcmp(ls_xmlContentPtr, "OGG")) {
-						ezConfig.format = OGG_FORMAT;
-					}
+					ezConfig.format = (char *)malloc(strlen(ls_xmlContentPtr) +1);
+					memset(ezConfig.format, '\000', strlen(ls_xmlContentPtr) +1);
+					strcpy(ezConfig.format, ls_xmlContentPtr);
}
xmlFree(ls_xmlContentPtr);
}
@@ -261,6 +340,77 @@
xmlFree(ls_xmlContentPtr);
}
}
+		if (!xmlStrcmp(cur->name, (const xmlChar *) "reencode")) {
+			xmlNodePtr cur2;
+			cur2 = cur->xmlChildrenNode;
+			while (cur2 != NULL) {
+				if (!xmlStrcmp(cur2->name, (const xmlChar *) "enable")) {
+					if (cur2->xmlChildrenNode != NULL) {
+						ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur2->xmlChildrenNode,1);
+						if ( strlen(ls_xmlContentPtr) > 0 ) {
+							ezConfig.reencode = atoi(ls_xmlContentPtr);
+						}
+						xmlFree(ls_xmlContentPtr);
+					}
+				}
+				if (!xmlStrcmp(cur2->name, (const xmlChar *) "encdec")) {
+					FORMAT_ENCDEC	*pformatEncDec = malloc(sizeof(FORMAT_ENCDEC));
+					memset(pformatEncDec, '\000', sizeof(FORMAT_ENCDEC));
+					xmlNodePtr cur3;
+					cur3 = cur2->xmlChildrenNode;
+					while (cur3 != NULL) {
+						if (!xmlStrcmp(cur3->name, (const xmlChar *) "format")) {
+							if (cur3->xmlChildrenNode != NULL) {
+								ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur3->xmlChildrenNode,1);
+								if ( strlen(ls_xmlContentPtr) > 0 ) {
+									pformatEncDec->format = (char *)malloc(strlen(ls_xmlContentPtr) +1);
+									memset(pformatEncDec->format, '\000', strlen(ls_xmlContentPtr) +1);
+									strcpy(pformatEncDec->format, ls_xmlContentPtr);
+								}
+								xmlFree(ls_xmlContentPtr);
+							}
+						}
+						if (!xmlStrcmp(cur3->name, (const xmlChar *) "match")) {
+							if (cur3->xmlChildrenNode != NULL) {
+								ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur3->xmlChildrenNode,1);
+								if ( strlen(ls_xmlContentPtr) > 0 ) {
+									pformatEncDec->match = (char *)malloc(strlen(ls_xmlContentPtr) +1);
+									memset(pformatEncDec->match, '\000', strlen(ls_xmlContentPtr) +1);
+									strcpy(pformatEncDec->match, ls_xmlContentPtr);
+								}
+								xmlFree(ls_xmlContentPtr);
+							}
+						}
+						if (!xmlStrcmp(cur3->name, (const xmlChar *) "decode")) {
+							if (cur3->xmlChildrenNode != NULL) {
+								ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur3->xmlChildrenNode,1);
+								if ( strlen(ls_xmlContentPtr) > 0 ) {
+									pformatEncDec->decoder = (char *)malloc(strlen(ls_xmlContentPtr) +1);
+									memset(pformatEncDec->decoder, '\000', strlen(ls_xmlContentPtr) +1);
+									strcpy(pformatEncDec->decoder, ls_xmlContentPtr);
+								}
+								xmlFree(ls_xmlContentPtr);
+							}
+						}
+						if (!xmlStrcmp(cur3->name, (const xmlChar *) "encode")) {
+							if (cur3->xmlChildrenNode != NULL) {
+								ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur3->xmlChildrenNode,1);
+								if ( strlen(ls_xmlContentPtr) > 0 ) {
+									pformatEncDec->encoder = (char *)malloc(strlen(ls_xmlContentPtr) +1);
+									memset(pformatEncDec->encoder, '\000', strlen(ls_xmlContentPtr) +1);
+									strcpy(pformatEncDec->encoder, ls_xmlContentPtr);
+								}
+								xmlFree(ls_xmlContentPtr);
+							}
+						}
+						cur3 = cur3->next;
+					}
+					ezConfig.encoderDecoders[ezConfig.numEncoderDecoders] = pformatEncDec;
+					ezConfig.numEncoderDecoders++;
+				}
+				cur2 = cur2->next;
+			}
+		}
cur = cur->next;
}
return(1);

Modified: trunk/ezstream/src/configfile.h
===================================================================
--- trunk/ezstream/src/configfile.h	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/src/configfile.h	2004-07-19 03:12:31 UTC (rev 7170)
@@ -4,13 +4,23 @@
#include <libxml/parser.h>


-#define MP3_FORMAT 1
-#define OGG_FORMAT 2
+#define MP3_FORMAT "MP3"
+#define VORBIS_FORMAT "VORBIS"
+#define THEORA_FORMAT "THEORA"

+#define MAX_FORMAT_ENCDEC	15
+
+typedef struct tag_FORMAT_ENCDEC {
+	char	*format;
+	char	*match;
+	char	*encoder;
+	char	*decoder;
+} FORMAT_ENCDEC;
+
typedef struct tag_EZCONFIG {
char	*URL;
char	*password;
-	int		format;
+	char	*format;
char	*fileName;
char	*serverName;
char	*serverURL;
@@ -21,9 +31,18 @@
char	*serverSamplerate;
char	*serverQuality;
int		serverPublic;
+	int	reencode;
+	FORMAT_ENCDEC	*encoderDecoders[MAX_FORMAT_ENCDEC];
+	int	numEncoderDecoders;
} EZCONFIG;

+
+
void printConfig();
int parseConfig(char *fileName);
EZCONFIG *getEZConfig();
+char*   getFormatEncoder(char *format);
+char*   getFormatDecoder(char *match);
+char*   getMetadataGrabber(char *match);
+
#endif

Modified: trunk/ezstream/src/ezstream.c
===================================================================
--- trunk/ezstream/src/ezstream.c	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/src/ezstream.c	2004-07-19 03:12:31 UTC (rev 7170)
@@ -10,9 +10,14 @@
#include <shout/shout.h>
#include <getopt.h>
#include "configfile.h"
+#ifndef WIN32
+#include <libgen.h>
+#endif
+#include <vorbis/vorbisfile.h>

EZCONFIG	*pezConfig = NULL;
int rereadPlaylist = 0;
+static char	*blankString = "";

#ifndef WIN32
#include <signal.h>
@@ -23,6 +28,12 @@
printf("Will reread the playlist on next song\n");
}
#endif
+#ifdef WIN32
+#define STRNCASECMP strnicmp
+#define popen _popen
+#else
+#define STRNCASECMP strncasecmp
+#endif

typedef struct tag_ID3Tag {
char tag[3];
@@ -87,44 +98,241 @@

}

+void ReplaceString(char *source, char *dest, char *from, char *to)
+{
+	char *p2 = (char *)1;
+	char	*p1 = source;
+	while (p2) {
+		p2 = strstr(p1, from);
+		if (p2) {
+			strncat(dest, p1, p2-p1);
+			strcat(dest, to);
+			p1 = p2 + strlen(from);
+		}
+		else {
+			strcat(dest, p1);
+		}
+	}
+}
+
+void setMetadata(shout_t *shout, char *metadata)
+{
+	shout_metadata_t *shoutMetadata = shout_metadata_new();
+	shout_metadata_add(shoutMetadata, "song", metadata);
+	shout_set_metadata(shout, shoutMetadata);
+	shout_metadata_free(shoutMetadata);
+}
+
+char* buildCommandString(char *extension, char *fileName, char *metadata)
+{
+	char	*commandString = NULL;
+	char *encoder = NULL;
+	char *decoder = NULL;
+	int	newDecoderLen = 0;
+	char *newDecoder = NULL;
+	char *newEncoder = NULL;
+	int	newEncoderLen = 0;
+	int	commandStringLen = 0;
+
+	decoder = strdup(getFormatDecoder(extension));
+	if (strlen(decoder) == 0) {
+		printf("Unknown extension %s, cannot decode\n", extension);
+		return commandString;
+	}
+	encoder = strdup(getFormatEncoder(pezConfig->format));
+	if (strlen(encoder) == 0) {
+		printf("Unknown format %s, cannot encode\n", pezConfig->format);
+		return commandString;
+	}
+	newDecoderLen = strlen(decoder) + strlen(fileName) + 1;
+	newDecoder = (char *)malloc(newDecoderLen);
+	memset(newDecoder, '\000', newDecoderLen);
+	ReplaceString(decoder, newDecoder, "@T@", fileName);
+
+	newEncoderLen = strlen(encoder) + strlen(metadata) + 1;
+	newEncoder = (char *)malloc(newEncoderLen);
+	memset(newEncoder, '\000', newEncoderLen);
+	ReplaceString(encoder, newEncoder, "@M@", metadata);
+
+	commandStringLen = strlen(newDecoder) + strlen(" | ") + strlen(newEncoder) + 1;
+	commandString = (char *)malloc(commandStringLen);
+	memset(commandString, '\000', commandStringLen);
+	sprintf(commandString, "%s | %s", newDecoder, newEncoder);
+	printf("Going to execute (%s)\n", commandString);
+	return(commandString);
+}
+
+#ifdef WIN32
+char *basename(char *fileName) {
+	char *pLast = strrchr(fileName, '\\');
+	if (pLast) {
+		return pLast+1;
+	}
+	return NULL;
+}
+#endif
+char * processMetadata(shout_t *shout, char *extension, char *fileName) {
+	FILE	*filepstream = NULL;
+	char	*artist = NULL;
+	char	*title = NULL;
+	char	*songInfo = NULL;
+	int songLen = 0;
+	ID3Tag	id3tag;
+
+	filepstream = fopen(fileName, "rb");
+	if (filepstream == NULL) {
+		printf("Cannot open (%s) - No metadata support.\n", fileName);
+		return strdup(blankString);
+	}
+
+	if (!strcmp(extension, ".mp3")) {
+		/* Look for the ID3 tag */
+		if (filepstream) {
+			memset(&id3tag, '\000', sizeof(id3tag));
+			fseek(filepstream, -128L, SEEK_END);
+			fread(&id3tag, 1, 127, filepstream);
+			if (!strncmp(id3tag.tag, "TAG", strlen("TAG"))) {
+				/* We have an Id3 tag */
+				songLen = strlen(id3tag.artistName) + strlen(" - ") + strlen(id3tag.trackName);
+				songInfo = (char *)malloc(songLen);
+				memset(songInfo, '\000', songLen);
+
+				sprintf(songInfo, "%s - %s", id3tag.artistName, id3tag.trackName);
+			}
+		}
+	}
+	if (!strcmp(extension, ".ogg")) {
+		OggVorbis_File vf;
+		if(ov_open(filepstream, &vf, NULL, 0) < 0) {
+			printf("Input does not appear to be an Ogg Vorbis bitstream. No metadata support.\n");
+		}
+		else {
+			char **ptr=ov_comment(&vf,-1)->user_comments;
+			while(*ptr){
+				if (!STRNCASECMP(*ptr, "ARTIST", strlen("ARTIST"))) {
+					artist = (char *)strdup(*ptr + strlen("ARTIST="));
+				}
+				if (!STRNCASECMP(*ptr, "TITLE", strlen("TITLE"))) {
+					title = (char *)strdup(*ptr + strlen("TITLE="));
+				}
+				++ptr;
+			}
+			if (artist) {
+				songLen = songLen + strlen(artist);
+			}
+			if (title) {
+				songLen = songLen + strlen(title);
+			}
+			songLen = songLen + strlen(" - ") + 1;
+			songInfo = (char *)malloc(songLen);
+			memset(songInfo, '\000', songLen);
+			if (artist) {
+				strcat(songInfo, artist);
+				strcat(songInfo, " - ");
+				free(artist);
+			}
+			if (title) {
+				strcat(songInfo, title);
+				free(title);
+			}
+			ov_clear(&vf);
+			filepstream = NULL;
+		}
+
+	}
+	if (!songInfo) {
+		/* If we didn't get any song info via tags or comments,
+		   then lets just use the filename */
+		char *p1 = NULL;
+		char *p2 = basename(fileName);
+		if (p2) {
+			songInfo = strdup(p2);
+			p1 = strrchr(songInfo, '.');
+			if (p1) {
+				*p1 = '\000';
+			}
+		}
+	}
+
+	if (songInfo) {
+		shout_metadata_t *pmetadata = shout_metadata_new();
+		shout_metadata_add(pmetadata, "song", songInfo);
+		shout_set_metadata(shout, pmetadata);
+		shout_metadata_free(pmetadata);
+	}
+	else {
+		songInfo = strdup(blankString);
+	}
+	if (filepstream) {
+		fclose(filepstream);
+	}
+	printf("Songinfo is (%s)\n", songInfo);
+	return songInfo;
+}
+
+FILE *openResource(shout_t *shout, char *fileName)
+{
+	FILE	*filep = NULL;
+
+	if (!strcmp(fileName, "stdin")) {
+#ifdef WIN32
+		_setmode(_fileno(stdin), _O_BINARY);
+#endif
+		filep = stdin;
+	}
+	else {
+		char extension[25];
+		char *p1 = NULL;
+		char *pMetadata = NULL;
+		char *pCommandString = NULL;
+		memset(extension, '\000', sizeof(extension));
+		p1 = strrchr(fileName, '.');
+		if (p1) {
+			strncpy(extension, p1, sizeof(extension)-1);
+		}
+
+		pMetadata = processMetadata(shout, extension, fileName);
+		if (pezConfig->reencode) {
+			/* Lets set the metadata first */
+			if (strlen(extension) > 0) {
+				pCommandString = buildCommandString(extension, fileName, pMetadata);
+				/* Open up the decode/encode loop using popen() */
+				filep = popen(pCommandString, "r");
+				free(pMetadata);
+				free(pCommandString);
+				return filep;
+			}
+			else {
+				printf("Cannot determine extension, don't know how to deal with (%s)\n", fileName);
+				free(pMetadata);
+				return NULL;
+			}
+			free(pMetadata);
+
+		}
+		else {
+			filep = fopen(fileName, "rb");
+			return filep;
+		}
+	}
+	return NULL;
+
+}
+
+
int streamFile(shout_t *shout, char *fileName) {
FILE	*filepstream = NULL;
char buff[4096];
long read, ret, total;
-	ID3Tag	id3tag;


printf("Streaming %s\n", fileName);

-	if (!strcmp(pezConfig->fileName, "stdin")) {
-#ifdef WIN32
-		_setmode(_fileno(stdin), _O_BINARY);
-#endif
-		filepstream = stdin;
-	}
-	else {
-		filepstream = fopen(fileName, "rb");
-	}
+	filepstream = openResource(shout, fileName);
if (!filepstream) {
printf("Cannot open %s\n", fileName);
return 0;
}
-	if (pezConfig->format == MP3_FORMAT) {
-		/* Look for the ID3 tag */
-		memset(&id3tag, '\000', sizeof(id3tag));
-		fseek(filepstream, -128L, SEEK_END);
-		fread(&id3tag, 1, sizeof(id3tag), filepstream);
-		if (!strncmp(id3tag.tag, "TAG", strlen("TAG"))) {
-			/* We have an Id3 tag */
-			shout_metadata_t	*pmetadata = shout_metadata_new();
-			char	songInfo[135] = "";
-			sprintf(songInfo, "%s - %s", id3tag.artistName, id3tag.trackName);
-			shout_metadata_add(pmetadata, "song", songInfo);
-			shout_set_metadata(shout, pmetadata);
-			shout_metadata_free(pmetadata);
-		}
-		rewind(filepstream);
-	}
total = 0;
while (!feof(filepstream)) {
read = fread(buff, 1, sizeof(buff), filepstream);
@@ -159,52 +367,52 @@
return(0);
}
while (loop) {
-			while (!feof(filep)) {
-				memset(streamFileName, '\000', sizeof(streamFileName));
-				fgets(streamFileName, sizeof(streamFileName), filep);
-				streamFileName[strlen(streamFileName)-1] = '\000';
-				if (strlen(streamFileName) > 0) {
-					memset(lastStreamFileName, '\000', sizeof(lastStreamFileName));
-					strcpy(lastStreamFileName, streamFileName);
-					/* Skip entries that begin with a # */
-					if (strncmp(streamFileName, "#", 1)) {
-						streamFile(shout, streamFileName);
-					}
+		while (!feof(filep)) {
+			memset(streamFileName, '\000', sizeof(streamFileName));
+			fgets(streamFileName, sizeof(streamFileName), filep);
+			streamFileName[strlen(streamFileName)-1] = '\000';
+			if (strlen(streamFileName) > 0) {
+				memset(lastStreamFileName, '\000', sizeof(lastStreamFileName));
+				strcpy(lastStreamFileName, streamFileName);
+				/* Skip entries that begin with a # */
+				if (strncmp(streamFileName, "#", 1)) {
+					streamFile(shout, streamFileName);
}
-				if (rereadPlaylist) {
-					rereadPlaylist = 0;
-					fclose(filep);
-					printf("Reopening playlist\n");
-					filep = fopen(fileName, "r");
-					if (filep == 0) {
-						printf("Cannot open %s\n", fileName);
-						return(0);
-					}
-					else {
-						int loop2 = 1;
-						printf("Repositioning to (%s)\n", lastStreamFileName);
-						while (loop2) {
-							/* If we reach the end before finding
-							   our last spot, we will start over at the
-							   beginning */
-							if (feof(filep)) {
+			}
+			if (rereadPlaylist) {
+				rereadPlaylist = 0;
+				fclose(filep);
+				printf("Reopening playlist\n");
+				filep = fopen(fileName, "r");
+				if (filep == 0) {
+					printf("Cannot open %s\n", fileName);
+					return(0);
+				}
+				else {
+					int loop2 = 1;
+					printf("Repositioning to (%s)\n", lastStreamFileName);
+					while (loop2) {
+						/* If we reach the end before finding
+						   our last spot, we will start over at the
+						   beginning */
+						if (feof(filep)) {
+							loop2 = 0;
+						}
+						else {
+							memset(streamFileName, '\000', sizeof(streamFileName));
+							fgets(streamFileName, sizeof(streamFileName), filep);
+							streamFileName[strlen(streamFileName)-1] = '\000';
+							if (!strcmp(streamFileName, lastStreamFileName)) {
+							/* If we found our last position, then bump out of the loop */
loop2 = 0;
}
-							else {
-								memset(streamFileName, '\000', sizeof(streamFileName));
-								fgets(streamFileName, sizeof(streamFileName), filep);
-								streamFileName[strlen(streamFileName)-1] = '\000';
-								if (!strcmp(streamFileName, lastStreamFileName)) {
-								/* If we found our last position, then bump out of the loop */
-									loop2 = 0;
-								}
-							}
}
+					}

-					}
}
}
-			rewind(filep);
+		}
+		rewind(filep);
}
return(1);
}
@@ -246,7 +454,7 @@
else {
parseConfig(configFile);
}
-
+
if (pezConfig->URL) {
host = (char *)malloc(strlen(pezConfig->URL) +1);
memset(host, '\000', strlen(pezConfig->URL) +1);
@@ -277,7 +485,7 @@
usage();
}
if (pezConfig->format == 0) {
-		printf("You must specify a format type of MP3 or OGGVORBIS\n");
+		printf("You must specify a format type of MP3, VORBIS, or THEORA\n");
}
if (!(shout = shout_new())) {
printf("Could not allocate shout_t\n");
@@ -314,18 +522,24 @@
return 1;
}

-	if (pezConfig->format == MP3_FORMAT) {
+	if (!strcmp(pezConfig->format, MP3_FORMAT)) {
if (shout_set_format(shout, SHOUT_FORMAT_MP3) != SHOUTERR_SUCCESS) {
printf("Error setting user: %s\n", shout_get_error(shout));
return 1;
}
}
-	if (pezConfig->format == OGG_FORMAT) {
+	if (!strcmp(pezConfig->format, VORBIS_FORMAT)) {
if (shout_set_format(shout, SHOUT_FORMAT_OGG) != SHOUTERR_SUCCESS) {
printf("Error setting user: %s\n", shout_get_error(shout));
return 1;
}
}
+	if (!strcmp(pezConfig->format, THEORA_FORMAT)) {
+		if (shout_set_format(shout, SHOUT_FORMAT_OGG) != SHOUTERR_SUCCESS) {
+			printf("Error setting user: %s\n", shout_get_error(shout));
+			return 1;
+		}
+	}

if (pezConfig->serverName) {
if (shout_set_name(shout, pezConfig->serverName) != SHOUTERR_SUCCESS) {

Modified: trunk/ezstream/win32/ezstream.dsp
===================================================================
--- trunk/ezstream/win32/ezstream.dsp	2004-07-17 07:38:37 UTC (rev 7169)
+++ trunk/ezstream/win32/ezstream.dsp	2004-07-19 03:12:31 UTC (rev 7170)
@@ -66,7 +66,7 @@
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../libshout/include" /I "../src" /I "../../libxml2/include" /I "../../iconv/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../oggvorbis-win32sdk-1.0.1/include" /I "../../libshout/include" /I "../src" /I "../../libxml2/include" /I "../../iconv/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
@@ -74,7 +74,7 @@
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\..\libshout\win32\Debug\libshout.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\ogg_static.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\vorbis_static.lib ..\..\pthreads\pthreadVSE.lib ws2_32.lib winmm.lib libxml2.lib iconv.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../libshout-2.0/win32/Debug" /libpath:"../../libxml2/lib" /libpath:"../../iconv/lib"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\..\libshout\win32\Debug\libshout.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\ogg_static.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\vorbis_static.lib ..\..\pthreads\pthreadVSE.lib ws2_32.lib winmm.lib libxml2.lib iconv.lib vorbisfile.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../oggvorbis-win32sdk-1.0.1/lib" /libpath:"../../libshout-2.0/win32/Debug" /libpath:"../../libxml2/lib" /libpath:"../../iconv/lib"

!ENDIF




More information about the commits mailing list