From 0968f1773c7f3a9a91defe75d6cf588a88a1c09d Mon Sep 17 00:00:00 2001 From: oddsock Date: Mon, 19 Jul 2004 03:12:31 +0000 Subject: [PATCH] Added reencoding capabilities to ezstream. git-svn-id: https://svn.xiph.org/trunk/ezstream@7170 0101bb08-14d6-0310-b084-bc0e0c8e3800 --- README | 85 ++++++- conf/Makefile.am | 2 +- conf/ezstream_reencoding_example.xml | 60 +++++ configure.in | 4 +- src/configfile.c | 166 +++++++++++- src/configfile.h | 25 +- src/ezstream.c | 362 +++++++++++++++++++++------ win32/ezstream.dsp | 4 +- 8 files changed, 614 insertions(+), 94 deletions(-) create mode 100644 conf/ezstream_reencoding_example.xml diff --git a/README b/README index 5d60987..67b88b8 100644 --- a/README +++ b/README @@ -10,7 +10,7 @@ server without reencoding and thus requires very little CPU. ezstream is 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 @@ The following is an example config file : http://localhost:8000/testmount.ogg hackme - OGGVORBIS + VORBIS sunking.ogg My Stream http://www.oddsock.org @@ -34,13 +34,17 @@ The following is an example config file : 2 44100 1 + + 0 + 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 @@ SVRINFOCHANNELS - 1 = MONO, 2 = STEREO (informational only) (used for YP) 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 : + + + 1 + + + FLAC + .flac + flac -s -d --force-raw-format --sign=signed --endian=little @T@ -o - + Not supported Yet + + + + MP3 + .mp3 + madplay -o raw:- @T@ 2>/dev/null + lame -r -x -b 56 -s 44.1 --resample 22.05 -a - - 2>/dev/null + + + + VORBIS + .ogg + oggdec --raw=1 @T@ -o - 2>/dev/null + oggenc -Q -r -q 0 --resample=44100 --downmix -t "@M@" -c STREAMER=ezstream - + + + + +Note that the following keywords can be used : + +@T@ = The fully qualified name of the track being played in the playlist +@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. + diff --git a/conf/Makefile.am b/conf/Makefile.am index c479f22..91a44cb 100644 --- a/conf/Makefile.am +++ b/conf/Makefile.am @@ -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 diff --git a/conf/ezstream_reencoding_example.xml b/conf/ezstream_reencoding_example.xml new file mode 100644 index 0000000..814412b --- /dev/null +++ b/conf/ezstream_reencoding_example.xml @@ -0,0 +1,60 @@ + + http://192.168.6.1:8000/testmount.ogg + hackme + + VORBIS + tracks.m3u + + My Stream + http://www.oddsock.org + RockNRoll + This is a stream description + 128 + + + 2 + 44100 + 1 + + 1 + + + + FLAC + .flac + flac -s -d --force-raw-format --sign=signed --endian=little @T@ -o - + Not supported Yet + + + + MP3 + .mp3 + madplay -o raw:- @T@ 2>/dev/null + lame -r -x -b 56 -s 44.1 --resample 22.05 -a - - 2>/dev/null + + + + VORBIS + .ogg + oggdec --raw=1 @T@ -o - 2>/dev/null + oggenc -Q -r -q 0 --resample=44100 --downmix -t "@M@" -c STREAMER=ezstream - + + + + diff --git a/configure.in b/configure.in index 62eac44..c1f108c 100644 --- a/configure.in +++ b/configure.in @@ -77,8 +77,8 @@ XIPH_VAR_APPEND([XIPH_CFLAGS], [$SHOUT_CFLAGS]) 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 diff --git a/src/configfile.c b/src/configfile.c index 55e2035..af248e7 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -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;iformat) { + 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;imatch) { + 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,8 +65,11 @@ void printConfig() 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 @@ void printConfig() 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;imatch) { + 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 @@ int parseConfig(char *fileName) 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 @@ int parseConfig(char *fileName) 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); diff --git a/src/configfile.h b/src/configfile.h index 93f0c43..ab7f2e7 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -4,13 +4,23 @@ #include -#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 @@ typedef struct tag_EZCONFIG { 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 diff --git a/src/ezstream.c b/src/ezstream.c index 01c7998..7545d4e 100644 --- a/src/ezstream.c +++ b/src/ezstream.c @@ -10,9 +10,14 @@ #include #include #include "configfile.h" +#ifndef WIN32 +#include +#endif +#include EZCONFIG *pezConfig = NULL; int rereadPlaylist = 0; +static char *blankString = ""; #ifndef WIN32 #include @@ -23,6 +28,12 @@ void hup_handler(int sig) 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 @@ int urlParse(char *url, char *hostname, int *port, char *mountname) } +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 @@ int streamPlaylist(shout_t *shout, char *fileName) { 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); - } - } - 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; - } - } - } - - } + 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); } } - rewind(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; + } + } + } + + } + } + } + rewind(filep); } return(1); } @@ -246,7 +454,7 @@ int main(int argc, char **argv) else { parseConfig(configFile); } - + if (pezConfig->URL) { host = (char *)malloc(strlen(pezConfig->URL) +1); memset(host, '\000', strlen(pezConfig->URL) +1); @@ -277,7 +485,7 @@ int main(int argc, char **argv) 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,13 +522,19 @@ int main(int argc, char **argv) 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; diff --git a/win32/ezstream.dsp b/win32/ezstream.dsp index 1b59cdb..2ffa832 100644 --- a/win32/ezstream.dsp +++ b/win32/ezstream.dsp @@ -66,7 +66,7 @@ LINK32=link.exe # 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 @@ BSC32=bscmake.exe # 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