1
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2024-11-03 04:17:18 -05:00

Added reencoding capabilities to ezstream.

git-svn-id: https://svn.xiph.org/trunk/ezstream@7170 0101bb08-14d6-0310-b084-bc0e0c8e3800
This commit is contained in:
oddsock 2004-07-19 03:12:31 +00:00
parent ef2bdf0ba2
commit 0968f1773c
8 changed files with 614 additions and 94 deletions

85
README
View File

@ -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 :
<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 @@ The following is an example config file :
<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 @@ 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 :
<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 :
@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.

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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,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;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 @@ 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);

View File

@ -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 @@ 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

View File

@ -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 @@ 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;

View File

@ -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