[xiph-commits] r8304 - in icecast/branches/kh/icecast: . doc src

karl at motherfish-iii.xiph.org karl at motherfish-iii.xiph.org
Mon Nov 29 07:45:58 PST 2004


Author: karl
Date: 2004-11-29 07:45:57 -0800 (Mon, 29 Nov 2004)
New Revision: 8304

Added:
   icecast/branches/kh/icecast/src/format_speex.c
   icecast/branches/kh/icecast/src/format_speex.h
   icecast/branches/kh/icecast/src/format_theora.c
   icecast/branches/kh/icecast/src/format_theora.h
Modified:
   icecast/branches/kh/icecast/configure.in
   icecast/branches/kh/icecast/doc/icecast2_config_file.html
   icecast/branches/kh/icecast/src/Makefile.am
   icecast/branches/kh/icecast/src/cfgfile.c
   icecast/branches/kh/icecast/src/cfgfile.h
   icecast/branches/kh/icecast/src/format.c
   icecast/branches/kh/icecast/src/format.h
   icecast/branches/kh/icecast/src/format_ogg.c
   icecast/branches/kh/icecast/src/format_ogg.h
   icecast/branches/kh/icecast/src/format_vorbis.c
   icecast/branches/kh/icecast/src/format_vorbis.h
   icecast/branches/kh/icecast/src/main.c
Log:
merge the two ogg modules (multi-codec and vorbis rebuild), split out the
codec specific bits into separate files, fixup m4 macros. need to check YP
update triggers


Modified: icecast/branches/kh/icecast/configure.in
===================================================================
--- icecast/branches/kh/icecast/configure.in	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/configure.in	2004-11-29 15:45:57 UTC (rev 8304)
@@ -74,21 +74,34 @@
 XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$XSLT_CFLAGS])
 XIPH_VAR_PREPEND([XIPH_LIBS],[$XSLT_LIBS])
 
-XIPH_PATH_VORBIS(, AC_MSG_ERROR([must have Ogg Vorbis v1.0 or above installed!]))
-XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$VORBIS_CFLAGS])
-XIPH_VAR_PREPEND([XIPH_LIBS],[$VORBIS_LIBS])
-XIPH_VAR_APPEND([XIPH_LDFLAGS],[$VORBIS_LDFLAGS])
+XIPH_PATH_VORBIS([
+    XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$VORBIS_CFLAGS])
+    XIPH_VAR_PREPEND([XIPH_LIBS],[$VORBIS_LIBS])
+    XIPH_VAR_APPEND([XIPH_LDFLAGS],[$VORBIS_LDFLAGS])
+    ICECAST_OPTIONAL="$ICECAST_OPTIONAL format_ogg.o format_vorbis.o"
+    ],
+    [AC_MSG_ERROR([must have Ogg Vorbis v1.0 or above installed])
+    ])
 
-XIPH_PATH_THEORA(, AC_MSG_WARN([Theora not found disabled!]))
-XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$THEORA_CFLAGS])
-XIPH_VAR_PREPEND([XIPH_LIBS],[$THEORA_LIBS])
-XIPH_VAR_APPEND([XIPH_LDFLAGS],[$THEORA_LDFLAGS])
 
-XIPH_PATH_SPEEX(, AC_MSG_WARN([Speex support disabled!]))
-XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$SPEEX_CFLAGS])
-XIPH_VAR_PREPEND([XIPH_LIBS],[$SPEEX_LIBS])
-XIPH_VAR_APPEND([XIPH_LDFLAGS],[$SPEEX_LDFLAGS])
+XIPH_PATH_THEORA([
+    XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$THEORA_CFLAGS])
+    XIPH_VAR_APPEND([XIPH_LDFLAGS],[$THEORA_LDFLAGS])
+    XIPH_VAR_PREPEND([XIPH_LIBS],[$THEORA_LIBS])
+    ICECAST_OPTIONAL="$ICECAST_OPTIONAL format_theora.o"
+    ],
+    [ AC_MSG_WARN([Theora not found, disabled!])
+    ])
 
+XIPH_PATH_SPEEX(
+    [ XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$SPEEX_CFLAGS])
+    XIPH_VAR_PREPEND([XIPH_LIBS],[$SPEEX_LIBS])
+    XIPH_VAR_APPEND([XIPH_LDFLAGS],[$SPEEX_LDFLAGS])
+    ICECAST_OPTIONAL="$ICECAST_OPTIONAL format_speex.o"
+    ],
+    [ AC_MSG_WARN([Speex support disabled!])
+    ])
+
 ACX_PTHREAD(, AC_MSG_ERROR([POSIX threads missing]))
 XIPH_VAR_APPEND([XIPH_CFLAGS],[$PTHREAD_CFLAGS])
 XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$PTHREAD_CPPFLAGS])
@@ -128,17 +141,7 @@
         AC_DEFINE([HAVE_LOGGING_IP],,[Define to log IP to access log])
 fi
 
-# use the older format_vorbis with metadata updates
-AC_ARG_ENABLE([vorbis-updates],
-        AC_HELP_STRING([--enable-vorbis-updates],[Allow for metadata via URL, only vorbis supported]),
-        vorbis_updates="$enableval",
-        vorbis_updates="no"
-        )
-if test x$vorbis_updates = xyes; then
-    ICECAST_OPTIONAL="$ICECAST_OPTIONAL format_vorbis.o"
-else
-    ICECAST_OPTIONAL="$ICECAST_OPTIONAL format_ogg.o"
-fi
+ICECAST_OPTIONAL="$ICECAST_OPTIONAL auth_cmd.o"
 
 dnl Make substitutions
 

Modified: icecast/branches/kh/icecast/doc/icecast2_config_file.html
===================================================================
--- icecast/branches/kh/icecast/doc/icecast2_config_file.html	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/doc/icecast2_config_file.html	2004-11-29 15:45:57 UTC (rev 8304)
@@ -350,8 +350,10 @@
         <fallback-mount>/example2.ogg</fallback-mount>
         <fallback-override>1</fallback-override>
         <no-yp>1</no-yp>
+        <hidden>1</hidden>
         <burst-size>65536</burst-size>
         <mp3-metadata-interval>8192</mp3-metadata-interval>
+        <ogg-rebuild>1</ogg-rebuild>
         <authentication type="htpasswd">
                 <option name="filename" value="myauth"/>
                 <option name="allow_duplicate_users" value="0"/>
@@ -427,6 +429,15 @@
 is sent every so many bytes, this setting allows for overriding the default for this
 mountpoint. A value of 0 means no metadata is sent to the client even if icecast receives it.
 </div>
+<h4>ogg-rebuild</h4>
+<div class="indentedbox">
+In certain situations some people may prefer to use URL updating of artist/title, this
+requires the stream to be rebuilt.  Even if url updates are not wanted, some may want the
+stream to be rebuilt as the source client/relay may be producing ogg pages that have too
+many samples causing larger, more infrequent writes on low bandwidth streams. The url
+updating mechanism is disabled if multiple codecs are used as not all logical streams
+can be rebuilt.
+</div>
 <h4>authentication</h4>
 <div class="indentedbox">
 This specifies that the named mount point will require listener authentication.  Currently, we only support a file-based authentication scheme (type=htpasswd).  Users and encrypted password are placed in this file (separated by a :) and all requests for this mountpoint will require that a user and password be supplied for authentication purposes.  These values are passed in via normal HTTP Basic Authentication means (i.e. http://user:password@stream:port/mountpoint.ogg).  Users and Passwords are maintained via the web admin interface.  A mountpoint configured with an authenticator will display a red key next to the mount point name on the admin screens.  You can read more about listener authentication <a href="icecast2_listenerauth.html">here</a>.

Modified: icecast/branches/kh/icecast/src/Makefile.am
===================================================================
--- icecast/branches/kh/icecast/src/Makefile.am	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/Makefile.am	2004-11-29 15:45:57 UTC (rev 8304)
@@ -7,13 +7,15 @@
 bin_PROGRAMS = icecast
 
 noinst_HEADERS = admin.h cfgfile.h os.h logging.h sighandler.h connection.h \
-	global.h util.h slave.h source.h stats.h refbuf.h client.h format.h \
-	format_ogg.h format_vorbis.h compat.h format_mp3.h fserve.h xslt.h yp.h \
-	event.h auth.h auth_htpasswd.h auth_cmd.h auth_url.h md5.h
+    global.h util.h slave.h source.h stats.h refbuf.h client.h format.h \
+    compat.h format_mp3.h fserve.h xslt.h yp.h event.h md5.h \
+    auth.h auth_htpasswd.h auth_cmd.h auth_url.h format_ogg.h \
+    format_vorbis.h format_theora.h format_speex.h
 icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \
-	 util.c slave.c source.c stats.c refbuf.c client.c format.c format_mp3.c \
-     xslt.c fserve.c event.c admin.c auth.c auth_htpasswd.c auth_cmd.c md5.c
-EXTRA_icecast_SOURCES = yp.c format_vorbis.c format_ogg.c auth_url.c
+    util.c slave.c source.c stats.c refbuf.c client.c format.c \
+    format_mp3.c xslt.c fserve.c event.c admin.c auth.c auth_htpasswd.c md5.c
+EXTRA_icecast_SOURCES = yp.c \
+    format_vorbis.c format_theora.c format_speex.c
     
 icecast_DEPENDENCIES = @ICECAST_OPTIONAL@ net/libicenet.la thread/libicethread.la \
     httpp/libicehttpp.la log/libicelog.la avl/libiceavl.la timing/libicetiming.la

Modified: icecast/branches/kh/icecast/src/cfgfile.c
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.c	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/cfgfile.c	2004-11-29 15:45:57 UTC (rev 8304)
@@ -604,6 +604,11 @@
             mount->mp3_meta_interval = atoi(tmp);
             if(tmp) xmlFree(tmp);
         }
+        else if (strcmp(node->name, "ogg-rebuild") == 0) {
+            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+            mount->ogg_rebuild = atoi(tmp);
+            if(tmp) xmlFree(tmp);
+        }
         else if (strcmp(node->name, "hidden") == 0) {
             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
             mount->hidden = atoi(tmp);

Modified: icecast/branches/kh/icecast/src/cfgfile.h
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.h	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/cfgfile.h	2004-11-29 15:45:57 UTC (rev 8304)
@@ -65,6 +65,7 @@
     int hidden; /* Do we list this on the xsl pages */
     unsigned int source_timeout;  /* source timeout in seconds */
     int mp3_meta_interval; /* outgoing per-stream metadata interval */
+    int ogg_rebuild;
 
     char *auth_type; /* Authentication type */
     config_options_t *auth_options; /* Options for this type */

Modified: icecast/branches/kh/icecast/src/format.c
===================================================================
--- icecast/branches/kh/icecast/src/format.c	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format.c	2004-11-29 15:45:57 UTC (rev 8304)
@@ -307,8 +307,3 @@
 }
 
 
-void format_initialise ()
-{
-    format_ogg_initialise ();
-}
-

Modified: icecast/branches/kh/icecast/src/format.h
===================================================================
--- icecast/branches/kh/icecast/src/format.h	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format.h	2004-11-29 15:45:57 UTC (rev 8304)
@@ -62,7 +62,6 @@
         struct source_tag *source, client_t *client);
 int format_http_write_to_client (struct source_tag *source, client_t *client);
 int format_intro_write_to_client (struct source_tag *source, client_t *client);
-void format_initialise();
 
 #endif  /* __FORMAT_H__ */
 

Modified: icecast/branches/kh/icecast/src/format_ogg.c
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.c	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_ogg.c	2004-11-29 15:45:57 UTC (rev 8304)
@@ -25,13 +25,6 @@
 #include <string.h>
 
 #include <ogg/ogg.h>
-#include <vorbis/codec.h>
-#ifdef HAVE_THEORA
-#include <theora/theora.h>
-#endif
-#ifdef HAVE_SPEEX
-#include <speex/speex_header.h>
-#endif
 
 #include "refbuf.h"
 #include "source.h"
@@ -39,45 +32,31 @@
 
 #include "stats.h"
 #include "format.h"
+#include "format_ogg.h"
+#include "format_vorbis.h"
+#ifdef HAVE_THEORA
+#include "format_theora.h"
+#endif
+#ifdef HAVE_SPEEX
+#include "format_speex.h"
+#endif
 
 #define CATMODULE "format-ogg"
 #include "logging.h"
 
 struct _ogg_state_tag;
 
-/* per codec/logical structure */
-typedef struct _ogg_codec_tag
-{
-    ogg_stream_state os;
-    unsigned headers;
-    void *specific;
-    struct _ogg_state_tag *feed;
-    struct _ogg_codec_tag *next;
-    refbuf_t *(*process_page)(struct _ogg_codec_tag *codec, ogg_page *page);
-    void (*codec_free)(struct _ogg_codec_tag *codec);
-    refbuf_t        *possible_start;
-} ogg_codec_t;
+static void format_ogg_free_plugin (format_plugin_t *plugin);
+static int  create_ogg_client_data(source_t *source, client_t *client);
+static void free_ogg_client_data (client_t *client);
+static void format_ogg_apply_settings (source_t *source, mount_proxy *mount);
 
+static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf);
+static refbuf_t *ogg_get_buffer (source_t *source);
+static int write_buf_to_client (source_t *source, client_t *client);
 
-typedef struct _ogg_state_tag
-{
-    char *mount;
-    ogg_sync_state oy;
 
-    ogg_codec_t *codecs;
-    char *artist;
-    char *title;
-    int send_yp_info;
-    refbuf_t *file_headers;
-    refbuf_t *header_pages;
-    refbuf_t *header_pages_tail;
-    int headers_completed;
-    long bitrate;
-    ogg_codec_t *codec_sync;
-} ogg_state_t;
-
-
-struct client_vorbis
+struct ogg_client
 {
     refbuf_t *headers;
     refbuf_t *header_page;
@@ -96,12 +75,15 @@
     if (ogg_info->codec_sync)
     {
         if (ogg_info->codec_sync->possible_start == refbuf)
+        {
+            refbuf_release (refbuf);
             ogg_info->codec_sync->possible_start = NULL;
+        }
     }
 }
 
 
-static refbuf_t *make_refbuf_with_page (ogg_page *page)
+refbuf_t *make_refbuf_with_page (ogg_page *page)
 {
     refbuf_t *refbuf = refbuf_new (page->header_len + page->body_len);
 
@@ -125,393 +107,6 @@
 
 
 
-/**** vorbis ****/
-typedef struct _vorbis_codec_tag
-{
-    vorbis_info vi;
-    vorbis_comment vc;
-} vorbis_codec_t;
-
-
-static void vorbis_codec_free (ogg_codec_t *codec)
-{
-    vorbis_codec_t *vorbis = codec->specific;
-
-    codec->feed->artist = NULL;
-    codec->feed->title = NULL;
-    vorbis_info_clear (&vorbis->vi);
-    vorbis_comment_clear (&vorbis->vc);
-    ogg_stream_clear (&codec->os);
-    free (vorbis);
-    free (codec);
-}
-
-static refbuf_t *process_vorbis_page (ogg_codec_t *codec, ogg_page *page)
-{
-    refbuf_t *refbuf;
-
-    if (ogg_page_granulepos (page) == 0)
-    {
-        vorbis_codec_t *vorbis = codec->specific;
-        ogg_packet packet;
-
-        ogg_stream_pagein (&codec->os, page);
-        while (ogg_stream_packetout (&codec->os, &packet) > 0)
-        {
-           if (vorbis_synthesis_headerin (&vorbis->vi, &vorbis->vc, &packet) < 0)
-           {
-               /* set some error code */
-               return NULL;
-           }
-           codec->headers++;
-        }
-        /* add header page to associated list */
-        format_ogg_attach_header (codec->feed, page);
-        if (codec->headers == 3)
-        {
-            ogg_state_t *ogg_info = codec->feed;
-
-            ogg_info->send_yp_info = 1;
-            ogg_info->title  = vorbis_comment_query (&vorbis->vc, "TITLE", 0);
-            ogg_info->artist = vorbis_comment_query (&vorbis->vc, "ARTIST", 0);
-            ogg_info->bitrate += vorbis->vi.bitrate_nominal;
-            stats_event_args (codec->feed->mount, "audio-samplerate", "%ld", (long)vorbis->vi.rate);
-            stats_event_args (codec->feed->mount, "audio-channels", "%ld", (long)vorbis->vi.channels);
-            stats_event_args (codec->feed->mount, "audio-bitrate", "%ld", (long)vorbis->vi.bitrate_nominal);
-        }
-        return NULL;
-    }
-    refbuf = make_refbuf_with_page (page);
-    if (codec->feed->codec_sync == NULL)
-        refbuf->sync_point = 1;
-    return refbuf;
-}
-
-
-static ogg_codec_t *initial_vorbis_page (ogg_page *page)
-{
-    ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
-    ogg_packet packet;
-
-    vorbis_codec_t *vorbis_codec = calloc (1, sizeof (vorbis_codec_t));
-
-    ogg_stream_init (&codec->os, ogg_page_serialno (page));
-    ogg_stream_pagein (&codec->os, page);
-
-    vorbis_info_init (&vorbis_codec->vi);
-    vorbis_comment_init (&vorbis_codec->vc);
-
-    ogg_stream_packetout (&codec->os, &packet);
-
-    DEBUG0("checking for vorbis codec");
-    if (vorbis_synthesis_headerin (&vorbis_codec->vi, &vorbis_codec->vc, &packet) < 0)
-    {
-        ogg_stream_clear (&codec->os);
-        vorbis_info_clear (&vorbis_codec->vi);
-        vorbis_comment_clear (&vorbis_codec->vc);
-        free (vorbis_codec);
-        free (codec);
-        return NULL;
-    }
-    INFO0 ("seen initial vorbis header");
-    codec->specific = vorbis_codec;
-    codec->process_page = process_vorbis_page;
-    codec->codec_free = vorbis_codec_free;
-    codec->headers = 1;
-    return codec;
-}
-
-
-/* Writ codec handler */
-static void writ_codec_free (ogg_codec_t *codec)
-{
-    ogg_stream_clear (&codec->os);
-    free (codec);
-}
-
-
-static refbuf_t *process_writ_page (ogg_codec_t *codec, ogg_page *page)
-{
-    refbuf_t *refbuf;
-
-    if (codec->headers)
-    {
-        ogg_packet pkt;
-
-        ogg_stream_pagein (&codec->os, page);
-        while (ogg_stream_packetout (&codec->os, &pkt) > 0)
-        {
-            if (pkt.bytes >= 5 && pkt.packet[0] != (unsigned char)'\xff' &&
-                        memcmp (pkt.packet+1, "writ", 4) == 0)
-            {
-                codec->headers++;
-                continue;
-            }
-            codec->headers = 0;
-        }
-        if (codec->headers)
-        {
-            /* add header page to associated list */
-            format_ogg_attach_header (codec->feed, page);
-            return NULL;
-        }
-    }
-    refbuf = make_refbuf_with_page (page);
-    /* allow clients to start here if nothing prevents it */
-    if (codec->feed->codec_sync == NULL)
-        refbuf->sync_point = 1;
-    return refbuf;
-}
-
-
-static ogg_codec_t *initial_writ_page (ogg_page *page)
-{
-    ogg_packet packet;
-    ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
-
-    ogg_stream_init (&codec->os, ogg_page_serialno (page));
-    ogg_stream_pagein (&codec->os, page);
-
-    DEBUG0("checking for writ codec");
-    ogg_stream_packetout (&codec->os, &packet);
-    if (memcmp (packet.packet, "\x00writ", 5) == 0)
-    {
-
-        INFO0 ("seen initial writ header");
-        codec->process_page = process_writ_page;
-        codec->codec_free = writ_codec_free;
-        codec->headers = 1;
-        return codec;
-    }
-    ogg_stream_clear (&codec->os);
-    free (codec);
-
-    return NULL;
-}
-
-
-#ifdef HAVE_SPEEX
-
-static void speex_codec_free (ogg_codec_t *codec)
-{
-    ogg_stream_clear (&codec->os);
-    free (codec);
-}
-
-
-static refbuf_t *process_speex_page (ogg_codec_t *codec, ogg_page *page)
-{
-    refbuf_t *refbuf;
-
-    if (codec->headers < 2)
-    {
-        ogg_packet packet;
-
-        ogg_stream_pagein (&codec->os, page);
-        while (ogg_stream_packetout (&codec->os, &packet) > 0)
-        {
-           /* first time around (normal case) yields comments */
-           codec->headers++;
-        }
-        /* add header page to associated list */
-        format_ogg_attach_header (codec->feed, page);
-        return NULL;
-    }
-    refbuf = make_refbuf_with_page (page);
-    if (codec->feed->codec_sync == NULL)
-        refbuf->sync_point = 1;
-    return refbuf;
-}
-
-
-static ogg_codec_t *initial_speex_page (ogg_page *page)
-{
-    ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
-    ogg_packet packet;
-    SpeexHeader *header;
-
-    ogg_stream_init (&codec->os, ogg_page_serialno (page));
-    ogg_stream_pagein (&codec->os, page);
-
-    ogg_stream_packetout (&codec->os, &packet);
-
-    DEBUG0("checking for speex codec");
-    header = speex_packet_to_header (packet.packet, packet.bytes);
-    if (header == NULL)
-    {
-        ogg_stream_clear (&codec->os);
-        free (header);
-        free (codec);
-        return NULL;
-    }
-    INFO0 ("seen initial speex header");
-    codec->process_page = process_speex_page;
-    codec->codec_free = speex_codec_free;
-    codec->headers = 1;
-    free (header);
-    return codec;
-}
-#endif
-
-#ifdef HAVE_THEORA
-
-typedef struct _theora_codec_tag
-{
-    theora_info     ti;
-    theora_comment  tc;
-    int             granule_shift;
-    ogg_int64_t     last_iframe;
-    ogg_int64_t     prev_granulepos;
-} theora_codec_t;
-
-
-static void theora_codec_free (ogg_codec_t *codec)
-{
-    theora_codec_t *theora = codec->specific;
-
-    theora_info_clear (&theora->ti);
-    theora_comment_clear (&theora->tc);
-    ogg_stream_clear (&codec->os);
-    free (theora);
-    free (codec);
-}
-
-
-static int _ilog (unsigned int v)
-{ 
-  int ret=0;
-  while(v){
-    ret++;
-    v>>=1;
-  }
-  return ret;
-}
-
-
-static refbuf_t *process_theora_page (ogg_codec_t *codec, ogg_page *page)
-{
-    refbuf_t *refbuf;
-    theora_codec_t *theora = codec->specific;
-    ogg_int64_t granulepos;
-
-    granulepos = ogg_page_granulepos (page);
-    // printf ("   granulepos of page %ld is %lld\n", ogg_page_pageno (page), granulepos);
-    if (granulepos == 0)
-    {
-        ogg_packet packet;
-        ogg_state_t *ogg_info = codec->feed;
-
-        ogg_stream_pagein (&codec->os, page);
-        // printf ("page %ld processing\n", ogg_page_pageno (page));
-        while (ogg_stream_packetout (&codec->os, &packet) > 0)
-        {
-           if (theora_decode_header (&theora->ti, &theora->tc, &packet) < 0)
-           {
-               /* set some error code */
-               WARN0 ("problem with theora header");
-               return NULL;
-           }
-           codec->headers++;
-           // printf ("header packets: %d\n", codec->headers);
-           if (codec->headers == 3)
-           {
-               theora->granule_shift = _ilog (theora->ti.keyframe_frequency_force - 1);
-               DEBUG1 ("granule shift is %lu", theora->granule_shift);
-               theora->last_iframe = (ogg_int64_t)-1;
-               codec->possible_start = NULL;
-               ogg_info->bitrate += theora->ti.target_bitrate;
-               stats_event_args (codec->feed->mount, "video_bitrate",
-                       "%ld", (long)theora->ti.target_bitrate);
-               stats_event_args (codec->feed->mount, "frame_size",
-                       "%ld x %ld", (long)theora->ti.frame_width, (long)theora->ti.frame_height);
-               stats_event_args (codec->feed->mount, "framerate",
-                       "%.2f", (float)theora->ti.fps_numerator/theora->ti.fps_denominator);
-           }
-        }
-        /* add page to associated list */
-        format_ogg_attach_header (ogg_info, page);
-
-        return NULL;
-    }
-    refbuf = make_refbuf_with_page (page);
-
-    // DEBUG2 ("granulepos is %lld,  %p", granulepos, refbuf);
-    if (granulepos == -1 || granulepos == theora->prev_granulepos)
-    {
-        if (codec->possible_start == NULL)
-        {
-            // DEBUG1 ("granulepos is unset, possible beginning %p", refbuf);
-            codec->possible_start = refbuf;
-        }
-        // DEBUG1 ("possible start is %p", codec->possible_start);
-    }
-    else
-    {
-        if ((granulepos >> theora->granule_shift) != theora->last_iframe)
-        {
-            theora->last_iframe = (granulepos >> theora->granule_shift);
-            // DEBUG2 ("iframe changed to %lld (%p)", theora->last_iframe, refbuf);
-            if (codec->possible_start == NULL)
-                codec->possible_start = refbuf;
-            codec->possible_start->sync_point = 1;
-            // DEBUG1 ("possible start is %p", codec->possible_start);
-        }
-        else
-        {
-            if (theora->prev_granulepos != -1)
-                codec->possible_start = refbuf;
-        }
-    }
-    theora->prev_granulepos = granulepos;
-
-    return refbuf;
-}
-
-
-static ogg_codec_t *initial_theora_page (ogg_page *page)
-{
-    ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
-    ogg_packet packet;
-
-    theora_codec_t *theora_codec = calloc (1, sizeof (theora_codec_t));
-
-    ogg_stream_init (&codec->os, ogg_page_serialno (page));
-    ogg_stream_pagein (&codec->os, page);
-
-    theora_info_init (&theora_codec->ti);
-    theora_comment_init (&theora_codec->tc);
-
-    ogg_stream_packetout (&codec->os, &packet);
-
-    DEBUG0("checking for theora codec");
-    if (theora_decode_header (&theora_codec->ti, &theora_codec->tc, &packet) < 0)
-    {
-        theora_info_clear (&theora_codec->ti);
-        theora_comment_clear (&theora_codec->tc);
-        ogg_stream_clear (&codec->os);
-        free (theora_codec);
-        free (codec);
-        return NULL;
-    }
-    INFO0 ("seen initial theora header");
-    // printf ("initial page %ld processing\n", ogg_page_pageno (page));
-    codec->specific = theora_codec;
-    codec->process_page = process_theora_page;
-    codec->codec_free = theora_codec_free;
-    codec->headers = 1;
-    return codec;
-}
-#endif /* THEORA */
-
-static void format_ogg_free_plugin (format_plugin_t *plugin);
-static int  create_ogg_client_data(source_t *source, client_t *client);
-static void free_ogg_client_data (client_t *client);
-
-static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf);
-static refbuf_t *ogg_get_buffer (source_t *source);
-static int write_buf_to_client (source_t *source, client_t *client);
-
-
 static void free_ogg_codecs (ogg_state_t *ogg_info)
 {
     ogg_codec_t *codec;
@@ -520,6 +115,7 @@
     if (ogg_info == NULL)
         return;
     /* release the header pages first */
+    DEBUG0 ("releasing header pages");
     header = ogg_info->header_pages;
     while (header)
     {
@@ -532,13 +128,15 @@
 
     /* now free the codecs */
     codec = ogg_info->codecs;
+    DEBUG0 ("freeing codecs");
     while (codec)
     {
         ogg_codec_t *next = codec->next;
-        codec->codec_free (codec);
+        codec->codec_free (ogg_info, codec);
         codec = next;
     }
     ogg_info->codecs = NULL;
+    ogg_info->current = NULL;
     ogg_info->headers_completed = 0;
 }
 
@@ -556,6 +154,7 @@
     plugin->write_buf_to_file = write_ogg_to_file;
     plugin->create_client_data = create_ogg_client_data;
     plugin->free_plugin = format_ogg_free_plugin;
+    plugin->apply_settings = format_ogg_apply_settings;
     plugin->set_tag = NULL;
     plugin->prerelease = refbuf_page_prerelease;
     plugin->contenttype = "application/ogg";
@@ -576,6 +175,8 @@
 
     /* free memory associated with this plugin instance */
     free_ogg_codecs (state);
+    free (state->artist);
+    free (state->title);
 
     /* free state memory */
     ogg_sync_clear (&state->oy);
@@ -587,8 +188,9 @@
 
 
 
-static int process_initial_page (ogg_state_t *ogg_info, ogg_page *page)
+static int process_initial_page (format_plugin_t *plugin, ogg_page *page)
 {
+    ogg_state_t *ogg_info = plugin->_state;
     ogg_codec_t *codec;
 
     if (ogg_info->headers_completed)
@@ -600,26 +202,19 @@
     }
     do
     {
-        codec = initial_vorbis_page (page);
+        codec = initial_vorbis_page (plugin, page);
         if (codec)
             break;
-        codec = initial_writ_page (page);
-        if (codec)
-            break;
 #ifdef HAVE_THEORA
-        codec = initial_theora_page (page);
+        codec = initial_theora_page (plugin, page);
         if (codec)
-        {
-            ogg_info->codec_sync = codec;
             break;
-        }
 #endif
 #ifdef HAVE_SPEEX
-        codec = initial_speex_page (page);
+        codec = initial_speex_page (plugin, page);
         if (codec)
             break;
 #endif
-
         /* any others */
         INFO0 ("Seen BOS page with unknown type");
         return -1;
@@ -630,121 +225,142 @@
         /* add codec to list */
         codec->next = ogg_info->codecs;
         ogg_info->codecs = codec;
-
-        codec->feed = ogg_info;
-        format_ogg_attach_header (ogg_info, page);
     }
 
     return 0;
 }
 
 
+
+static void update_comments (source_t *source)
+{
+    ogg_state_t *ogg_info = source->format->_state;
+    char *title = ogg_info->title;
+    char *artist = ogg_info->artist;
+    char *metadata = NULL;
+    unsigned int len = 0;
+
+    if (ogg_info->artist)
+    {
+        if (title)
+        {
+            len += strlen(artist) + strlen(title) + 3;
+            metadata = calloc (1, len);
+            snprintf (metadata, len, "%s - %s", artist, title);
+        }
+        else
+        {
+            len += strlen(artist);
+            metadata = calloc (1, len);
+            snprintf (metadata, len, "%s", artist);
+        }
+    }
+    else
+    {
+        if (title)
+        {
+            len += strlen (title);
+            metadata = calloc (1, len);
+            snprintf (metadata, len, "%s", title);
+        }
+    }
+    if (metadata)
+    {
+        logging_playlist (source->mount, metadata, source->listeners);
+        free (metadata);
+    }
+    yp_touch (ogg_info->mount);
+}
+
+
+static refbuf_t *complete_buffer (source_t *source, refbuf_t *refbuf)
+{
+    ogg_state_t *ogg_info = source->format->_state;
+    refbuf_t *header = ogg_info->header_pages;
+
+    while (header)
+    {
+        refbuf_addref (header);
+        header = header->next;
+    }
+    refbuf->associated = ogg_info->header_pages;
+
+    if (ogg_info->log_metadata)
+    {
+        update_comments (source);
+        ogg_info->log_metadata = 0;
+    }
+    if (ogg_info->codec_sync == NULL)
+        refbuf->sync_point = 1;
+    return refbuf;
+}
+
+
 static refbuf_t *process_ogg_page (ogg_state_t *ogg_info, ogg_page *page)
 {
     ogg_codec_t *codec = ogg_info->codecs;
+    refbuf_t *refbuf = NULL;
 
     while (codec)
     {
         if (ogg_page_serialno (page) == codec->os.serialno)
         {
-            refbuf_t *refbuf = codec->process_page (codec, page);
-            if (refbuf)
-            {
-                refbuf_t *header = ogg_info->header_pages;
-                while (header)
-                {
-                    refbuf_addref (header);
-                    header = header->next;
-                }
-                refbuf->associated = ogg_info->header_pages;
-            }
-            return refbuf;
+            if (codec->process_page)
+                refbuf = codec->process_page (ogg_info, codec, page);
+            break;
         }
+
         codec = codec->next;
     }
-    return NULL;
+    ogg_info->current = codec;
+    return refbuf;
 }
 
 
+
 static refbuf_t *ogg_get_buffer (source_t *source)
 {
     ogg_state_t *ogg_info = source->format->_state;
     char *data = NULL;
     int bytes;
-    ogg_page page;
-    refbuf_t *refbuf = NULL;
 
     while (1)
     {
         while (1)
         {
+            ogg_page page;
+            refbuf_t *refbuf;
+            ogg_codec_t *codec = ogg_info->current;
+
+            if (codec && codec->process)
+            {
+                refbuf = codec->process (ogg_info, codec);
+                if (refbuf)
+                    return complete_buffer (source, refbuf);
+
+                ogg_info->current = NULL;
+            }
+
             if (ogg_sync_pageout (&ogg_info->oy, &page) > 0)
             {
                 if (ogg_page_bos (&page))
                 {
-                    process_initial_page (ogg_info, &page);
+                    process_initial_page (source->format, &page);
                     continue;
                 }
                 ogg_info->headers_completed = 1;
-                /* process the extracted page */
                 refbuf = process_ogg_page (ogg_info, &page);
-
-                if (ogg_info->send_yp_info)
+                if (ogg_info->error)
                 {
-                    char *title;
-                    char *artist;
-                    char *metadata = NULL;
-                    unsigned int len = 0;
-
-                    title = ogg_info->title;
-                    if (title)
-                        INFO1("Updating title \"%s\"", title);
-                    stats_event (source->mount, "title", title);
-
-                    artist = ogg_info->artist;
-                    if (artist)
-                        INFO1("Updating artist \"%s\"", artist);
-                    stats_event (source->mount, "artist", artist);
-                    if (artist)
-                    {
-                        if (title)
-                        {
-                            len += strlen(artist) + strlen(title) + 3;
-                            metadata = calloc (1, len);
-                            snprintf (metadata, len, "%s - %s", artist, title);
-                        }
-                        else
-                        {
-                            len += strlen(artist);
-                            metadata = calloc (1, len);
-                            snprintf (metadata, len, "%s", artist);
-                        }
-                    }
-                    else
-                    {
-                        if (title)
-                        {
-                            len += strlen (title);
-                            metadata = calloc (1, len);
-                            snprintf (metadata, len, "%s", title);
-                        }
-                    }
-                    if (metadata)
-                    {
-                        logging_playlist (source->mount, metadata, source->listeners);
-                        free (metadata);
-                    }
-
-                    if (ogg_info->bitrate)
-                        stats_event_args (source->mount, "ice-bitrate", "%u", ogg_info->bitrate/1000);
-
-                    ogg_info->send_yp_info = 0;
-                    yp_touch (source->mount);
+                    ERROR0 ("Problem processing stream");
+                    source->running = 0;
+                    return NULL;
                 }
                 if (refbuf)
-                    return refbuf;
+                    return complete_buffer (source, refbuf);
                 continue;
             }
+            /* need more stream data */
             break;
         }
         /* we need more data to continue getting pages */
@@ -774,7 +390,7 @@
 
 static int create_ogg_client_data (source_t *source, client_t *client) 
 {
-    struct client_vorbis *client_data = calloc (1, sizeof (struct client_vorbis));
+    struct ogg_client *client_data = calloc (1, sizeof (struct ogg_client));
     int ret = -1;
 
     if (client_data)
@@ -798,7 +414,7 @@
 
 static int send_ogg_headers (client_t *client, refbuf_t *headers)
 {
-    struct client_vorbis *client_data = client->format_data;
+    struct ogg_client *client_data = client->format_data;
     refbuf_t *refbuf;
     int written = 0;
 
@@ -839,7 +455,7 @@
     refbuf_t *refbuf = client->refbuf;
     char *buf;
     unsigned len;
-    struct client_vorbis *client_data = client->format_data;
+    struct ogg_client *client_data = client->format_data;
     int ret, written = 0;
 
     if (refbuf->next == NULL && client->pos == refbuf->len)
@@ -912,4 +528,15 @@
     write_ogg_data (source, refbuf);
 }
 
+static void format_ogg_apply_settings (source_t *source, mount_proxy *mount)
+{
+    ogg_state_t *ogg_info = source->format->_state;
 
+    ogg_info->rebuild = 0;
+    if (mount->ogg_rebuild)
+    {
+        ogg_info->rebuild = 1;
+        DEBUG0 ("rebuilding stream enabled");
+    }
+}
+

Modified: icecast/branches/kh/icecast/src/format_ogg.h
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.h	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_ogg.h	2004-11-29 15:45:57 UTC (rev 8304)
@@ -18,7 +18,50 @@
 #ifndef __FORMAT_OGG_H__
 #define __FORMAT_OGG_H__
 
+#include <ogg/ogg.h>
+#include "refbuf.h"
+#include "format.h"
+
+typedef struct ogg_state_tag
+{
+    char *mount;
+    ogg_sync_state oy;
+    int error;
+
+    struct ogg_codec_tag *codecs;
+    char *artist;
+    char *title;
+    int log_metadata;
+    refbuf_t *file_headers;
+    refbuf_t *header_pages;
+    refbuf_t *header_pages_tail;
+    int headers_completed;
+    int rebuild;
+    long bitrate;
+    struct ogg_codec_tag *current;
+    struct ogg_codec_tag *codec_sync;
+} ogg_state_t;
+
+
+/* per codec/logical structure */
+typedef struct ogg_codec_tag
+{
+    struct ogg_codec_tag *next;
+    ogg_stream_state os;
+    unsigned headers;
+    void *specific;
+    refbuf_t        *possible_start;
+    refbuf_t        *page;
+
+    refbuf_t *(*process)(ogg_state_t *ogg_info, struct ogg_codec_tag *codec);
+    refbuf_t *(*process_page)(ogg_state_t *ogg_info,
+            struct ogg_codec_tag *codec, ogg_page *page);
+    void (*codec_free)(ogg_state_t *ogg_info, struct ogg_codec_tag *codec);
+} ogg_codec_t;
+
+
+refbuf_t *make_refbuf_with_page (ogg_page *page);
+void format_ogg_attach_header (ogg_state_t *ogg_info, ogg_page *page);
 int format_ogg_get_plugin (source_t *source);
-#define format_ogg_initialise() do{}while(0)
 
 #endif  /* __FORMAT_OGG_H__ */

Added: icecast/branches/kh/icecast/src/format_speex.c
===================================================================
--- icecast/branches/kh/icecast/src/format_speex.c	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_speex.c	2004-11-29 15:45:57 UTC (rev 8304)
@@ -0,0 +1,92 @@
+/* Icecast
+ *  
+ *  This program is distributed under the GNU General Public License, version 2.
+ *  A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org>, 
+ *                      Michael Smith <msmith at xiph.org>,
+ *                      oddsock <oddsock at xiph.org>,
+ *                      Karl Heyes <karl at xiph.org>
+ *                      and others (see AUTHORS for details).
+ */
+
+
+/* Ogg codec handler for speex streams */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <ogg/ogg.h>
+#include <speex/speex_header.h>
+
+typedef struct source_tag source_t;
+
+#include "format_speex.h"
+#include "refbuf.h"
+#include "client.h"
+
+#define CATMODULE "format-speex"
+#include "logging.h"
+
+static void speex_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec)
+{
+    ogg_stream_clear (&codec->os);
+    free (codec);
+}
+
+
+static refbuf_t *process_speex_page (ogg_state_t *ogg_info,
+        ogg_codec_t *codec, ogg_page *page)
+{
+    refbuf_t *refbuf;
+
+    if (codec->headers < 2)
+    {
+        ogg_packet packet;
+
+        ogg_stream_pagein (&codec->os, page);
+        while (ogg_stream_packetout (&codec->os, &packet) > 0)
+        {
+           /* first time around (normal case) yields comments */
+           codec->headers++;
+        }
+        /* add header page to associated list */
+        format_ogg_attach_header (ogg_info, page);
+        return NULL;
+    }
+    refbuf = make_refbuf_with_page (page);
+    return refbuf;
+}
+
+
+ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page)
+{
+    ogg_state_t *ogg_info = plugin->_state;
+    ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+    ogg_packet packet;
+    SpeexHeader *header;
+
+    ogg_stream_init (&codec->os, ogg_page_serialno (page));
+    ogg_stream_pagein (&codec->os, page);
+
+    ogg_stream_packetout (&codec->os, &packet);
+
+    DEBUG0("checking for speex codec");
+    header = speex_packet_to_header (packet.packet, packet.bytes);
+    if (header == NULL)
+    {
+        ogg_stream_clear (&codec->os);
+        free (header);
+        free (codec);
+        return NULL;
+    }
+    INFO0 ("seen initial speex header");
+    codec->process_page = process_speex_page;
+    codec->codec_free = speex_codec_free;
+    codec->headers = 1;
+    format_ogg_attach_header (ogg_info, page);
+    free (header);
+    return codec;
+}

Added: icecast/branches/kh/icecast/src/format_speex.h
===================================================================
--- icecast/branches/kh/icecast/src/format_speex.h	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_speex.h	2004-11-29 15:45:57 UTC (rev 8304)
@@ -0,0 +1,21 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org, 
+ *                      Michael Smith <msmith at xiph.org>,
+ *                      oddsock <oddsock at xiph.org>,
+ *                      Karl Heyes <karl at xiph.org>
+ *                      and others (see AUTHORS for details).
+ */
+
+
+#ifndef __FORMAT_SPEEX_H
+#define __FORMAT_SPEEX_H
+
+#include "format_ogg.h"
+
+ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page);
+
+#endif /* __FORMAT_SPEEX_H */

Added: icecast/branches/kh/icecast/src/format_theora.c
===================================================================
--- icecast/branches/kh/icecast/src/format_theora.c	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_theora.c	2004-11-29 15:45:57 UTC (rev 8304)
@@ -0,0 +1,189 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org, 
+ *                      Michael Smith <msmith at xiph.org>,
+ *                      oddsock <oddsock at xiph.org>,
+ *                      Karl Heyes <karl at xiph.org>
+ *                      and others (see AUTHORS for details).
+ */
+
+
+/* Ogg codec handler for theora logical streams */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <ogg/ogg.h>
+#include <theora/theora.h>
+
+typedef struct source_tag source_t;
+
+#include "refbuf.h"
+#include "format_ogg.h"
+#include "format_theora.h"
+#include "client.h"
+#include "stats.h"
+
+#define CATMODULE "format-theora"
+#include "logging.h"
+
+
+typedef struct _theora_codec_tag
+{
+    theora_info     ti;
+    theora_comment  tc;
+    int             granule_shift;
+    ogg_int64_t     last_iframe;
+    ogg_int64_t     prev_granulepos;
+} theora_codec_t;
+
+
+static void theora_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec)
+{
+    theora_codec_t *theora = codec->specific;
+
+    DEBUG0 ("freeing theora codec");
+    stats_event (ogg_info->mount, "video_bitrate", NULL);
+    stats_event (ogg_info->mount, "framerate", NULL);
+    stats_event (ogg_info->mount, "frame_size", NULL);
+    theora_info_clear (&theora->ti);
+    theora_comment_clear (&theora->tc);
+    ogg_stream_clear (&codec->os);
+    free (theora);
+    free (codec);
+}
+
+
+static int _ilog (unsigned int v)
+{ 
+  int ret=0;
+  while(v){
+    ret++;
+    v>>=1;
+  }
+  return ret;
+}
+
+
+static refbuf_t *process_theora_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page)
+{
+    refbuf_t *refbuf;
+    theora_codec_t *theora = codec->specific;
+    ogg_int64_t granulepos;
+
+    granulepos = ogg_page_granulepos (page);
+    if (codec->headers < 3)
+    {
+        ogg_packet packet;
+
+        ogg_stream_pagein (&codec->os, page);
+        while (ogg_stream_packetout (&codec->os, &packet) > 0)
+        {
+           if (theora_packet_isheader (&packet) == 0 || 
+                   theora_decode_header (&theora->ti, &theora->tc, &packet) < 0)
+           {
+               ogg_info->error = 1;
+               WARN0 ("problem with theora header");
+               return NULL;
+           }
+           codec->headers++;
+           if (codec->headers == 3)
+           {
+               theora->granule_shift = _ilog (theora->ti.keyframe_frequency_force - 1);
+               DEBUG1 ("granule shift is %lu", theora->granule_shift);
+               theora->last_iframe = (ogg_int64_t)-1;
+               codec->possible_start = NULL;
+               ogg_info->bitrate += theora->ti.target_bitrate;
+               stats_event_args (ogg_info->mount, "video_bitrate",
+                       "%ld", (long)theora->ti.target_bitrate);
+               stats_event_args (ogg_info->mount, "frame_size",
+                       "%ld x %ld", (long)theora->ti.frame_width, (long)theora->ti.frame_height);
+               stats_event_args (ogg_info->mount, "framerate",
+                       "%.2f", (float)theora->ti.fps_numerator/theora->ti.fps_denominator);
+           }
+        }
+        /* add page to associated list */
+        format_ogg_attach_header (ogg_info, page);
+
+        return NULL;
+    }
+    refbuf = make_refbuf_with_page (page);
+    refbuf->sync_point = 1;
+
+    if (granulepos == -1 || granulepos == theora->prev_granulepos)
+    {
+        if (codec->possible_start == NULL)
+        {
+            refbuf_addref (refbuf);
+            codec->possible_start = refbuf;
+        }
+    }
+    else
+    {
+        if ((granulepos >> theora->granule_shift) != theora->last_iframe)
+        {
+            theora->last_iframe = (granulepos >> theora->granule_shift);
+            if (codec->possible_start == NULL)
+            {
+                refbuf_addref (refbuf);
+                codec->possible_start = refbuf;
+            }
+            codec->possible_start->sync_point = 1;
+        }
+        else
+        {
+            if (theora->prev_granulepos != -1)
+            {
+                if (codec->possible_start)
+                    refbuf_release (codec->possible_start);
+                refbuf_addref (refbuf);
+                codec->possible_start = refbuf;
+            }
+        }
+    }
+    theora->prev_granulepos = granulepos;
+
+    return refbuf;
+}
+
+
+ogg_codec_t *initial_theora_page (format_plugin_t *plugin, ogg_page *page)
+{
+    ogg_state_t *ogg_info = plugin->_state;
+    ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+    ogg_packet packet;
+
+    theora_codec_t *theora_codec = calloc (1, sizeof (theora_codec_t));
+
+    ogg_stream_init (&codec->os, ogg_page_serialno (page));
+    ogg_stream_pagein (&codec->os, page);
+
+    theora_info_init (&theora_codec->ti);
+    theora_comment_init (&theora_codec->tc);
+
+    ogg_stream_packetout (&codec->os, &packet);
+
+    DEBUG0("checking for theora codec");
+    if (theora_decode_header (&theora_codec->ti, &theora_codec->tc, &packet) < 0)
+    {
+        theora_info_clear (&theora_codec->ti);
+        theora_comment_clear (&theora_codec->tc);
+        ogg_stream_clear (&codec->os);
+        free (theora_codec);
+        free (codec);
+        return NULL;
+    }
+    INFO0 ("seen initial theora header");
+    codec->specific = theora_codec;
+    codec->process_page = process_theora_page;
+    codec->codec_free = theora_codec_free;
+    codec->headers = 1;
+    format_ogg_attach_header (ogg_info, page);
+    return codec;
+}
+

Added: icecast/branches/kh/icecast/src/format_theora.h
===================================================================
--- icecast/branches/kh/icecast/src/format_theora.h	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_theora.h	2004-11-29 15:45:57 UTC (rev 8304)
@@ -0,0 +1,21 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org, 
+ *                      Michael Smith <msmith at xiph.org>,
+ *                      oddsock <oddsock at xiph.org>,
+ *                      Karl Heyes <karl at xiph.org>
+ *                      and others (see AUTHORS for details).
+ */
+
+
+#ifndef __FORMAT_THEORA_H
+#define __FORMAT_THEORA_H
+
+#include "format_ogg.h"
+
+ogg_codec_t *initial_theora_page (format_plugin_t *plugin, ogg_page *page);
+
+#endif /* __FORMAT_THEORA_H */

Modified: icecast/branches/kh/icecast/src/format_vorbis.c
===================================================================
--- icecast/branches/kh/icecast/src/format_vorbis.c	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_vorbis.c	2004-11-29 15:45:57 UTC (rev 8304)
@@ -10,96 +10,62 @@
  *                      and others (see AUTHORS for details).
  */
 
-/* format_vorbis.c
-**
-** format plugin for vorbis
-**
-*/
 
+/* Ogg codec handler for vorbis streams */
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-
 #include <ogg/ogg.h>
 #include <vorbis/codec.h>
+#include <memory.h>
 
 #include "refbuf.h"
 #include "source.h"
 #include "client.h"
 
+#include "format_ogg.h"
 #include "stats.h"
 #include "format.h"
 
 #define CATMODULE "format-vorbis"
 #include "logging.h"
 
-static ogg_int64_t next_rebuild_serialno = 0;
-static mutex_t serial_lock;
 
-typedef struct _vstate_tag
+typedef struct vorbis_codec_tag
 {
-    ogg_sync_state oy;
-    ogg_stream_state os, out_os;
     vorbis_info vi;
     vorbis_comment vc;
 
-    ogg_packet *prev_packet;
-    refbuf_t *file_headers;
-
-    int initial_audio_packet;
+    int rebuild_comment;
     int stream_notify;
-    int use_url_comment;
-    int to_terminate;
-    int more_headers;
-    int prev_window;
+
+    ogg_stream_state new_os;
     int page_samples_trigger;
+    ogg_int64_t prev_granulepos;
+    ogg_packet *prev_packet;
     ogg_int64_t granulepos;
     ogg_int64_t samples_in_page;
-    ogg_int64_t prev_samples;
-    ogg_int64_t prev_page_samples;
+    int prev_window;
+    int initial_audio_packet;
 
-    refbuf_t *headers_head;
-    refbuf_t *headers_tail;
     ogg_packet *header [3];
-    ogg_packet url_comment;
-    char *url_artist;
-    char *url_title;
+    ogg_int64_t prev_page_samples;
 
-    int (*process_packet)(source_t *);
-    refbuf_t *(*get_buffer_page)(struct _vstate_tag *source_vorbis);
+    int (*process_packet)(ogg_state_t *ogg_info, ogg_codec_t *codec);
+    refbuf_t *(*get_buffer_page)(ogg_state_t *ogg_info, ogg_codec_t *codec);
 
-} vstate_t;
+} vorbis_codec_t;
 
-struct client_vorbis
-{
-    refbuf_t *headers;
-    refbuf_t *header_page;
-    unsigned pos;
-    int headers_sent;
-};
-
-
-static ogg_int64_t get_next_serialno ()
-{
-    ogg_int64_t serialno;
-    thread_mutex_lock (&serial_lock);
-    serialno = next_rebuild_serialno++;
-    thread_mutex_unlock (&serial_lock);
-    return serialno;
-}
-
-static void format_vorbis_free_plugin (format_plugin_t *plugin);
-static int  create_vorbis_client_data(source_t *source, client_t *client);
-static void free_vorbis_client_data (client_t *client);
-
-static void write_vorbis_to_file (struct source_tag *source, refbuf_t *refbuf);
-static refbuf_t *vorbis_get_buffer (source_t *source);
-static int vorbis_write_buf_to_client (source_t *source, client_t *client);
+static int process_vorbis_headers (ogg_state_t *ogg_info, ogg_codec_t *codec);
+static refbuf_t *process_vorbis_page (ogg_state_t *ogg_info,
+                ogg_codec_t *codec, ogg_page *page);
+static refbuf_t *process_vorbis (ogg_state_t *ogg_info, ogg_codec_t *codec);
 static void vorbis_set_tag (format_plugin_t *plugin, char *tag, char *value);
+static refbuf_t *vorbis_page (ogg_state_t *ogg_info,
+        ogg_codec_t *codec, ogg_page *page);
 
 
 static void free_ogg_packet (ogg_packet *packet)
@@ -112,75 +78,27 @@
 }
 
 
-int format_ogg_get_plugin (source_t *source)
+static void vorbis_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
-    format_plugin_t *plugin;
-    vstate_t *state;
-    vorbis_comment vc;
+    vorbis_codec_t *vorbis = codec->specific;
 
-    plugin = (format_plugin_t *)calloc(1, sizeof(format_plugin_t));
-
-    plugin->type = FORMAT_TYPE_OGG;
-    plugin->get_buffer = vorbis_get_buffer;
-    plugin->write_buf_to_client = vorbis_write_buf_to_client;
-    plugin->write_buf_to_file = write_vorbis_to_file;
-    plugin->create_client_data = create_vorbis_client_data;
-    plugin->free_plugin = format_vorbis_free_plugin;
-    plugin->set_tag = vorbis_set_tag;
-    plugin->contenttype = "application/ogg";
-
-    state = (vstate_t *)calloc(1, sizeof(vstate_t));
-    ogg_sync_init(&state->oy);
-    ogg_stream_init (&state->out_os, get_next_serialno());
-
-    vorbis_comment_init (&vc);
-    vorbis_commentheader_out (&vc, &state->url_comment);
-    vorbis_comment_clear (&vc);
-
-    plugin->_state = (void *)state;
-    source->format = plugin;
-
-    return 0;
+    DEBUG0 ("freeing vorbis codec");
+    stats_event (ogg_info->mount, "audio-bitrate", NULL);
+    stats_event (ogg_info->mount, "audio-channels", NULL);
+    stats_event (ogg_info->mount, "audio-samplerate", NULL);
+    vorbis_info_clear (&vorbis->vi);
+    vorbis_comment_clear (&vorbis->vc);
+    ogg_stream_clear (&codec->os);
+    ogg_stream_clear (&vorbis->new_os);
+    free_ogg_packet (vorbis->header[0]);
+    free_ogg_packet (vorbis->header[1]);
+    free_ogg_packet (vorbis->header[2]);
+    free_ogg_packet (vorbis->prev_packet);
+    free (vorbis);
+    free (codec);
 }
 
-void format_vorbis_free_plugin (format_plugin_t *plugin)
-{
-    vstate_t *state = plugin->_state;
 
-    /* free memory associated with this plugin instance */
-
-    /* free state memory */
-    ogg_sync_clear (&state->oy);
-    ogg_stream_clear (&state->os);
-    ogg_stream_clear (&state->out_os);
-    vorbis_comment_clear (&state->vc);
-    vorbis_info_clear (&state->vi);
-
-    free_ogg_packet (state->header[0]);
-    free_ogg_packet (state->header[1]);
-    free_ogg_packet (state->header[2]);
-    if (state->prev_packet)
-        free_ogg_packet (state->prev_packet);
-
-    while (state->headers_head)
-    {
-        refbuf_t *to_go = state->headers_head;
-        state->headers_head = to_go->next;
-        /* printf ("releasing vorbis header %p\n", to_go); */
-        refbuf_release (to_go);
-    }
-
-    free (state->url_artist);
-    free (state->url_title);
-    ogg_packet_clear (&state->url_comment);
-
-    free (state);
-
-    /* free the plugin instance */
-    free (plugin);
-}
-
-
 static ogg_packet *copy_ogg_packet (ogg_packet *packet)
 {
     ogg_packet *next;
@@ -196,14 +114,14 @@
         memcpy (next->packet, packet->packet, next->bytes);
         return next;
     } while (0);
-                                                                                                                                           
+
     if (next)
         free (next);
     return NULL;
 }
 
 
-static void add_audio_packet (vstate_t *source_vorbis, ogg_packet *packet)
+static void add_audio_packet (vorbis_codec_t *source_vorbis, ogg_packet *packet)
 {
     if (source_vorbis->initial_audio_packet)
     {
@@ -212,66 +130,48 @@
     }
     else
     {
-        source_vorbis->samples_in_page += (packet->granulepos - source_vorbis->prev_samples);
-        source_vorbis->prev_samples = packet->granulepos;
+        source_vorbis->samples_in_page +=
+            (packet->granulepos - source_vorbis->prev_granulepos);
+        source_vorbis->prev_granulepos = packet->granulepos;
         source_vorbis->granulepos += source_vorbis->prev_window;
     }
-    /* printf ("Adding packet %lld, granulepos %lld (%ld)\n", packet->packetno,
-            packet->granulepos, vorbis_packet_blocksize (&source_vorbis->vi, packet)/4); */
-    ogg_stream_packetin (&source_vorbis->out_os, packet);
+    ogg_stream_packetin (&source_vorbis->new_os, packet);
 }
 
 
-static refbuf_t *get_buffer_audio (vstate_t *source_vorbis)
+static refbuf_t *get_buffer_audio (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
     refbuf_t *refbuf = NULL;
     ogg_page page;
+    vorbis_codec_t *source_vorbis = codec->specific;
     int (*get_ogg_page)(ogg_stream_state*, ogg_page *) = ogg_stream_pageout;
 
-    /* printf ("current sample count is %lld, %ld\n", source_vorbis->samples_in_page, source_vorbis->vi.rate>>1); */
     if (source_vorbis->samples_in_page > source_vorbis->page_samples_trigger)
     {
         get_ogg_page = ogg_stream_flush;
-        /* printf ("forcing flush with %lld samples\n", source_vorbis->samples_in_page); */
     }
-    if (get_ogg_page (&source_vorbis->out_os, &page) > 0)
+    if (get_ogg_page (&source_vorbis->new_os, &page) > 0)
     {
         /* printf ("got audio page %lld\n", ogg_page_granulepos (&page)); */
         /* squeeze a page copy into a buffer */
         source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples);
         source_vorbis->prev_page_samples = ogg_page_granulepos (&page);
 
-        refbuf = refbuf_new (page.header_len + page.body_len);
-        memcpy (refbuf->data, page.header, page.header_len);
-        memcpy (refbuf->data+page.header_len, page.body, page.body_len);
-        /* printf ("setting associated to %p\n", refbuf->associated); */
+        refbuf = make_refbuf_with_page (&page);
     }
     return refbuf;
 }
 
 
-static refbuf_t *get_buffer_header (vstate_t *source_vorbis)
+static refbuf_t *get_buffer_header (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
     int headers_flushed = 0;
     ogg_page page;
+    vorbis_codec_t *source_vorbis = codec->specific;
 
-    /* printf ("in buffer_header\n"); */
-    while (ogg_stream_flush (&source_vorbis->out_os, &page) > 0)
+    while (ogg_stream_flush (&source_vorbis->new_os, &page) > 0)
     {
-        refbuf_t *refbuf;
-        /* squeeze a page copy into a buffer */
-        refbuf = refbuf_new (page.header_len + page.body_len);
-        memcpy (refbuf->data, page.header, page.header_len);
-        memcpy (refbuf->data+page.header_len, page.body, page.body_len);
-        refbuf->len = page.header_len + page.body_len;
-
-        /* store header page for associated list */
-        if (source_vorbis->headers_tail)
-            source_vorbis->headers_tail->next = refbuf;
-        if (source_vorbis->headers_head == NULL)
-            source_vorbis->headers_head = refbuf;
-        source_vorbis->headers_tail = refbuf;
-        /* printf ("Stored vorbis header %p\n", refbuf); */
+        format_ogg_attach_header (ogg_info, &page);
         headers_flushed = 1;
     }
     if (headers_flushed)
@@ -283,50 +183,49 @@
 }
 
 
-static refbuf_t *get_buffer_finished (vstate_t *source_vorbis)
+static refbuf_t *get_buffer_finished (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
+    vorbis_codec_t *source_vorbis = codec->specific;
     ogg_page page;
     refbuf_t *refbuf;
 
-    if (ogg_stream_flush (&source_vorbis->out_os, &page) > 0)
+    if (ogg_stream_flush (&source_vorbis->new_os, &page) > 0)
     {
         /* printf ("EOS stream flush %lld\n", ogg_page_granulepos (&page)); */
 
         source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples);
         source_vorbis->prev_page_samples = ogg_page_granulepos (&page);
 
-        refbuf = refbuf_new (page.header_len + page.body_len);
-        memcpy (refbuf->data, page.header, page.header_len);
-        memcpy (refbuf->data+page.header_len, page.body, page.body_len);
-        refbuf->len = page.header_len + page.body_len;
-        refbuf->associated = source_vorbis->headers_head;
+        refbuf = make_refbuf_with_page (&page);
+        DEBUG0 ("flushing page");
         return refbuf;
     }
-    ogg_stream_clear (&source_vorbis->out_os);
-    ogg_stream_init (&source_vorbis->out_os, get_next_serialno());
-    refbuf = source_vorbis->headers_head;
+    ogg_stream_clear (&source_vorbis->new_os);
+    ogg_stream_init (&source_vorbis->new_os, rand());
+
+    refbuf = ogg_info->header_pages;
     while (refbuf)
     {
         refbuf_t *to_go = refbuf;
         refbuf = refbuf->next;
-        /* printf ("releasing vorbis header %p\n", to_go); */
         refbuf_release (to_go);
     }
-    source_vorbis->headers_head = NULL;
-    source_vorbis->headers_tail = NULL;
-    source_vorbis->get_buffer_page = get_buffer_header;
+    ogg_info->header_pages = NULL;
+    ogg_info->header_pages_tail = NULL;
+    source_vorbis->get_buffer_page = NULL;
+    source_vorbis->process_packet = process_vorbis_headers;
     return NULL;
 }
 
 
-/* pushed last packet into stream marked with eos */
-static void initiate_flush (vstate_t *source_vorbis)
+/* push last packet into stream marked with eos */
+static void initiate_flush (vorbis_codec_t *source_vorbis)
 {
+    DEBUG0 ("adding EOS packet");
     if (source_vorbis->prev_packet)
     {
         /* insert prev_packet with eos */
         source_vorbis->prev_packet->e_o_s = 1;
-        /* printf ("adding stored packet marked as EOS\n"); */
         add_audio_packet (source_vorbis, source_vorbis->prev_packet);
         source_vorbis->prev_packet->e_o_s = 0;
     }
@@ -334,11 +233,11 @@
     source_vorbis->initial_audio_packet = 1;
 }
 
-/* just deal with ogg vorbis streams at the moment */
 
-static int process_vorbis_audio (source_t *source)
+
+static int process_vorbis_audio (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
-    vstate_t *source_vorbis = source->format->_state;
+    vorbis_codec_t *source_vorbis = codec->specific;
     int result = 0;
 
     while (1)
@@ -347,14 +246,12 @@
         ogg_packet packet;
 
         /* now, lets extract what packets we can */
-        if (ogg_stream_packetout (&source_vorbis->os, &packet) <= 0)
+        if (ogg_stream_packetout (&codec->os, &packet) <= 0)
             return result;
-        
-        result = 1;
 
         /* calculate granulepos for the packet */
         window = vorbis_packet_blocksize (&source_vorbis->vi, &packet) / 4;
-        
+
         source_vorbis->granulepos += window;
         if (source_vorbis->prev_packet)
         {
@@ -362,10 +259,7 @@
             if (packet.b_o_s)
                 prev_packet->e_o_s = 1;
             add_audio_packet (source_vorbis, prev_packet);
-            /* printf ("Adding prev packet %lld, granulepos %lld (%d) samples %lld\n", prev_packet->packetno,
-                    prev_packet->granulepos, source_vorbis->prev_window, source_vorbis->samples_in_page); */
             free_ogg_packet (prev_packet);
-
             packet . granulepos = source_vorbis->granulepos;
         }
         else
@@ -377,128 +271,97 @@
         /* copy the next packet */
         source_vorbis->prev_packet = copy_ogg_packet (&packet);
 
+        if (source_vorbis->stream_notify)
+        {
+            initiate_flush (source_vorbis);
+            source_vorbis->stream_notify = 0;
+        }
+
         /* allow for pages to be flushed if there's over a certain number of samples */
         if (source_vorbis->samples_in_page > source_vorbis->page_samples_trigger)
             return 1;
     }
 }
 
+
 /* handle the headers we want going to the clients */
-static int process_vorbis_headers (source_t *source)
+static int process_vorbis_headers (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
-    vstate_t *source_vorbis = source->format->_state;
+    vorbis_codec_t *source_vorbis = codec->specific;
 
-    /* trap for missing initial header, this means we're expecting
-       headers coming in, so jump out and try in a short while */
     if (source_vorbis->header [0] == NULL)
         return 0;
-    /* printf ("Adding the 3 header packets\n"); */
-    ogg_stream_packetin (&source_vorbis->out_os, source_vorbis->header [0]);
+
+    DEBUG0 ("Adding the 3 header packets");
+    ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [0]);
     /* NOTE: we could build a separate comment packet each time */
-    if (source_vorbis->use_url_comment)
-        ogg_stream_packetin (&source_vorbis->out_os, &source_vorbis->url_comment);
+    if (source_vorbis->rebuild_comment)
+    {
+        vorbis_comment vc;
+        ogg_packet header;
+
+        vorbis_comment_init (&vc);
+        if (ogg_info->artist) 
+            vorbis_comment_add_tag (&vc, "artist", ogg_info->artist);
+        if (ogg_info->title)
+            vorbis_comment_add_tag (&vc, "title", ogg_info->title);
+        vorbis_comment_add (&vc, "server=" ICECAST_VERSION_STRING);
+        vorbis_commentheader_out (&vc, &header);
+
+        ogg_stream_packetin (&source_vorbis->new_os, &header);
+        vorbis_comment_clear (&vc);
+        ogg_packet_clear (&header);
+    }
     else
-        ogg_stream_packetin (&source_vorbis->out_os, source_vorbis->header [1]);
-    ogg_stream_packetin (&source_vorbis->out_os, source_vorbis->header [2]);
-    source_vorbis->use_url_comment = 0;
+        ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [1]);
+    ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [2]);
+    source_vorbis->rebuild_comment = 0;
 
+    ogg_info->log_metadata = 1;
+    source_vorbis->get_buffer_page = get_buffer_header;
     source_vorbis->process_packet = process_vorbis_audio;
     source_vorbis->granulepos = 0;
     source_vorbis->initial_audio_packet = 1;
     return 1;
 }
 
-static void update_stats (source_t *source, vorbis_comment *vc)
-{
-    char *artist;
-    char *title;
-    char *metadata = NULL;
-    unsigned int len = 1;
 
-    /* put known comments in the stats, this could be site specific */
-    title = vorbis_comment_query (vc, "TITLE", 0);
-    if (title)
-    {
-        INFO1 ("title set to \"%s\"", title);
-        len += strlen (title);
-    }
-    stats_event (source->mount, "title", title);
-
-    artist = vorbis_comment_query (vc, "ARTIST", 0);
-    if (artist)
-    {
-        INFO1 ("artist set to \"%s\"", artist);
-        len += strlen (artist);
-    }
-    stats_event (source->mount, "artist", artist);
-    if (artist)
-    {
-        if (title)
-        {
-            len += strlen(artist) + strlen(title) + 3;
-            metadata = calloc (1, len);
-            snprintf (metadata, len, "%s - %s", artist, title);
-        }
-        else
-        {
-            len += strlen(artist);
-            metadata = calloc (1, len);
-            snprintf (metadata, len, "%s", artist);
-        }
-    }
-    else
-    {
-        if (title)
-        {
-            len += strlen (title);
-            metadata = calloc (1, len);
-            snprintf (metadata, len, "%s", title);
-        }
-    }
-    if (metadata)
-    {
-        logging_playlist (source->mount, metadata, source->listeners);
-        free (metadata);
-    }
-}
-
-
 /* this is called with the first page after the initial header */
 /* it processes any headers that have come in on the stream */
-static int process_vorbis_incoming_hdrs (source_t *source)
+static int process_vorbis_incoming_hdrs (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
     ogg_packet header;
-    vstate_t *source_vorbis = source->format->_state;
+    vorbis_codec_t *source_vorbis = codec->specific;
 
-    /* printf ("processing incoming header packet\n"); */
-    while (source_vorbis->more_headers)
+    DEBUG1 ("processing incoming header packet (%d)", codec->headers);
+    while (codec->headers < 3)
     {
         /* now, lets extract the packets */
-        int result = ogg_stream_packetout (&source_vorbis->os, &header);
-        
+        int result = ogg_stream_packetout (&codec->os, &header);
+
         if (result <= 0)
-            return result;   /* need more pages */
+            return -1;   /* need more pages */
 
         /* change comments here if need be */
         if (vorbis_synthesis_headerin (&source_vorbis->vi, &source_vorbis->vc, &header) < 0)
         {
+            ogg_info->error = 1;
             WARN0 ("Problem parsing ogg vorbis header");
             return -1;
         }
         header.granulepos = 0;
-        /* printf ("Parsing [%d] vorbis header %lld,  %lld\n", source_vorbis->more_headers, header.packetno, header.granulepos); */
-        source_vorbis->header [3-source_vorbis->more_headers] = copy_ogg_packet (&header);
-        source_vorbis->more_headers--;
+        source_vorbis->header [codec->headers] = copy_ogg_packet (&header);
+        codec->headers++;
     }
+    DEBUG0 ("we have the header packets now");
 
     /* we have all headers */
 
-    update_stats (source, &source_vorbis->vc);
+    stats_event_args (ogg_info->mount, "audio-samplerate", "%ld", (long)source_vorbis->vi.rate);
+    stats_event_args (ogg_info->mount, "audio-channels", "%ld", (long)source_vorbis->vi.channels);
+    stats_event_args (ogg_info->mount, "audio-bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal);
+    stats_event_args (ogg_info->mount, "ice-bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal/1000);
 
-    stats_event_args (source->mount, "audio-samplerate", "%ld", (long)source_vorbis->vi.rate);
-    stats_event_args (source->mount, "audio-channels", "%ld", (long)source_vorbis->vi.channels);
-    stats_event_args (source->mount, "audio-bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal);
-    stats_event_args (source->mount, "ice-bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal/1000);
     /* set queued pages to contain a 1/4 of a second worth of samples */
     source_vorbis->page_samples_trigger = source_vorbis->vi.rate / 4;
 
@@ -509,80 +372,82 @@
 }
 
 
-
-static int initial_vorbis_page (vstate_t *source_vorbis, ogg_packet *packet)
+ogg_codec_t *initial_vorbis_page (format_plugin_t *plugin, ogg_page *page)
 {
-    /* init vi and vc */
-    vorbis_comment_clear (&source_vorbis->vc);
-    vorbis_info_clear (&source_vorbis->vi);
+    ogg_state_t *ogg_info = plugin->_state;
+    ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+    ogg_packet packet;
 
+    vorbis_codec_t *source_vorbis = calloc (1, sizeof (vorbis_codec_t));
+
+    ogg_stream_init (&codec->os, ogg_page_serialno (page));
+    ogg_stream_pagein (&codec->os, page);
+
     vorbis_info_init (&source_vorbis->vi);
     vorbis_comment_init (&source_vorbis->vc);
 
-    /* printf ("processing initial page\n"); */
-    if (vorbis_synthesis_headerin (&source_vorbis->vi, &source_vorbis->vc, packet) < 0)
+    ogg_stream_packetout (&codec->os, &packet);
+
+    DEBUG0("checking for vorbis codec");
+    if (vorbis_synthesis_headerin (&source_vorbis->vi, &source_vorbis->vc, &packet) < 0)
     {
-        /* printf ("not a vorbis packet\n"); */
-        return -1;
+        ogg_stream_clear (&codec->os);
+        vorbis_info_clear (&source_vorbis->vi);
+        vorbis_comment_clear (&source_vorbis->vc);
+        free (source_vorbis);
+        free (codec);
+        return NULL;
     }
+    INFO0 ("seen initial vorbis header");
+    codec->specific = source_vorbis;
+    codec->codec_free = vorbis_codec_free;
+    codec->headers = 1;
 
-    /* printf ("Handling ogg vorbis header\n"); */
-    free_ogg_packet (source_vorbis->header[0]);
-    free_ogg_packet (source_vorbis->header[1]);
-    free_ogg_packet (source_vorbis->header[2]);
-    memset (source_vorbis->header, 0, sizeof (source_vorbis->header));
-    source_vorbis->header [0] = copy_ogg_packet (packet);
-    source_vorbis->more_headers = 2;
+    /* */
+    if (ogg_info->rebuild)
+    {
+        free_ogg_packet (source_vorbis->header[0]);
+        free_ogg_packet (source_vorbis->header[1]);
+        free_ogg_packet (source_vorbis->header[2]);
+        memset (source_vorbis->header, 0, sizeof (source_vorbis->header));
+        source_vorbis->header [0] = copy_ogg_packet (&packet);
+        ogg_stream_init (&source_vorbis->new_os, rand());
 
-    initiate_flush (source_vorbis);
-    source_vorbis->process_packet = process_vorbis_incoming_hdrs;
-    /* free previous audio packet, it maybe in a different format */
-    free_ogg_packet (source_vorbis->prev_packet);
-    source_vorbis->prev_packet = NULL;
-    source_vorbis->prev_window = 0;
-
-    source_vorbis->initial_audio_packet = 1;
-
-    return 0;
-}
-
-
-static int process_initial_page (source_t *source, ogg_page *page)
-{
-    vstate_t *source_vorbis = source->format->_state;
-    int ret = -1;
-    ogg_packet packet;
-
-    ogg_stream_clear (&source_vorbis->os);
-    ogg_stream_init (&source_vorbis->os, ogg_page_serialno (page));
-
-    ogg_stream_pagein (&source_vorbis->os, page);
-    do
+        codec->process_page = process_vorbis_page;
+        codec->process = process_vorbis;
+        plugin->set_tag = vorbis_set_tag;
+        source_vorbis->process_packet = process_vorbis_incoming_hdrs;
+    }
+    else
     {
-        if (ogg_stream_packetout (&source_vorbis->os, &packet) <= 0)
-            break;
-        ret = 0;
-        if (initial_vorbis_page (source_vorbis, &packet) == 0)
-            break;
-        /* any others */
-        ret = -1;
-    } while (0);
-    /* printf ("processed initial page\n"); */
-    return ret;
+        codec->process_page = vorbis_page;
+        format_ogg_attach_header (ogg_info, page);
+    }
+    
+    return codec;
 }
 
 
 static void vorbis_set_tag (format_plugin_t *plugin, char *tag, char *value)
-{
-    vstate_t *source_vorbis = plugin->_state;
+{   
+    ogg_state_t *ogg_info = plugin->_state;
+    ogg_codec_t *codec = ogg_info->codecs;
+    vorbis_codec_t *source_vorbis;
     int change = 0;
+
+    /* avoid updating if multiple codecs in use */
+    if (codec && codec->next == NULL)
+        source_vorbis = codec->specific;
+    else
+        return;
+
     if (strcmp (tag, "artist") == 0)
     {
         char *p = strdup (value);
         if (p)
         {
-            free (source_vorbis->url_artist);
-            source_vorbis->url_artist = p;
+            free (ogg_info->artist);
+            ogg_info->artist = p;
             change = 1;
         }
     }
@@ -591,8 +456,8 @@
         char *p = strdup (value);
         if (p)
         {
-            free (source_vorbis->url_title);
-            source_vorbis->url_title = p;
+            free (ogg_info->title);
+            ogg_info->title = p;
             change = 1;
         }
     }
@@ -601,277 +466,100 @@
         char *p = strdup (value);
         if (p)
         {
-            free (source_vorbis->url_artist);
-            free (source_vorbis->url_title);
-            source_vorbis->url_title = p;
+            free (ogg_info->artist);
+            free (ogg_info->title);
+            ogg_info->title = p;
             change = 1;
         }
     }
     if (change)
+    {
         source_vorbis->stream_notify = 1;
+        source_vorbis->rebuild_comment = 1;
+    }
 }
 
 
-static void update_comments (source_t *source)
+static refbuf_t *process_vorbis (ogg_state_t *ogg_info, ogg_codec_t *codec)
 {
-    vstate_t *source_vorbis = source->format->_state;
-    vorbis_comment vc;
-    ogg_packet header;
+    vorbis_codec_t *source_vorbis = codec->specific;
+    refbuf_t *refbuf;
 
-    initiate_flush (source_vorbis);
-
-    /* printf ("updated comment header\n"); */
-    vorbis_comment_init (&vc);
-    if (source_vorbis->url_artist)
-        vorbis_comment_add_tag (&vc, "artist", source_vorbis->url_artist);
-    if (source_vorbis->url_title)
-        vorbis_comment_add_tag (&vc, "title", source_vorbis->url_title);
-    vorbis_comment_add (&vc, "server=" ICECAST_VERSION_STRING);
-    ogg_packet_clear (&source_vorbis->url_comment);
-    update_stats (source, &vc);
-    vorbis_commentheader_out (&vc, &source_vorbis->url_comment);
-    vorbis_comment_clear (&vc);
-    header.packetno = 1;
-    source_vorbis->use_url_comment = 1;
-    source_vorbis->process_packet = process_vorbis_headers;
-}
-
-static refbuf_t *vorbis_get_buffer (source_t *source)
-{
-    vstate_t *source_vorbis = source->format->_state;
-    char *data = NULL;
-    int bytes = 1;
-    ogg_page page;
-    refbuf_t *refbuf = NULL;
-
     while (1)
     {
-        while (1)
+        if (source_vorbis->get_buffer_page)
         {
-            if (source_vorbis->get_buffer_page)
-                refbuf = source_vorbis->get_buffer_page (source_vorbis);
+            refbuf = source_vorbis->get_buffer_page (ogg_info, codec);
             if (refbuf)
-            {
-                refbuf_t *header = source_vorbis->headers_head;
-                refbuf->associated = source_vorbis->headers_head;
-                while (header)
-                {
-                    refbuf_addref (header);
-                    header = header->next;
-                }
-                refbuf->sync_point = 1;
                 return refbuf;
-            }
-            
-            /* printf ("check for processed packets\n"); */
-            if (source_vorbis->process_packet && source_vorbis->process_packet (source) > 0)
-                continue;
-            /* printf ("Checking for more in-pages\n"); */
-            if (ogg_sync_pageout (&source_vorbis->oy, &page) > 0)
-            {
-                /* lets see what we do with it */
-                if (ogg_page_bos (&page))
-                {
-                    process_initial_page (source, &page);
-                    return NULL;
-                }
-                /* printf ("Adding in page to out_os\n"); */
-                ogg_stream_pagein (&source_vorbis->os, &page);
-                continue;
-            }
-            break;
         }
-        if (source_vorbis->to_terminate)
-        {
-            /* normal exit path */
-            source->running = 0;
-            source_vorbis->to_terminate = 0;
-            return NULL;
-        }
-        /* see if any non-stream updates are requested */
-        if (source_vorbis->stream_notify)
-        {
-            update_comments (source);
-            source_vorbis->stream_notify = 0;
+
+        if (source_vorbis->process_packet &&
+                source_vorbis->process_packet (ogg_info, codec) > 0)
             continue;
-        }
-        if (data == NULL)
-            data = ogg_sync_buffer (&source_vorbis->oy, 4096);
-        /* printf ("reading data in\n"); */
-        bytes = sock_read_bytes (source->con->sock, data, 4096);
-        if (bytes < 0)
-        {
-            if (sock_recoverable (sock_error()))
-                return NULL;
-            WARN0 ("source connection has died");
-            ogg_sync_wrote (&source_vorbis->oy, 0);
-            source_vorbis->to_terminate = 1;
-            initiate_flush (source_vorbis);
-            return NULL;
-        }
-        if (bytes == 0)
-        {
-            INFO1 ("End of Stream %s", source->mount);
-            ogg_sync_wrote (&source_vorbis->oy, 0);
-            source_vorbis->to_terminate = 1;
-            initiate_flush (source_vorbis);
-            return NULL;
-        }
-        ogg_sync_wrote (&source_vorbis->oy, bytes);
-        data = NULL;
+        return NULL;
     }
 }
 
 
-static int create_vorbis_client_data (source_t *source, client_t *client) 
+static refbuf_t *process_vorbis_page (ogg_state_t *ogg_info,
+        ogg_codec_t *codec, ogg_page *page)
 {
-    struct client_vorbis *client_data = calloc (1, sizeof (struct client_vorbis));
-    if (client_data == NULL)
-    {
-        ERROR0("malloc failed");
-        return -1;
-    }
-    client_data->headers_sent = 1;
-    client->format_data = client_data;
-    client->free_client_data = free_vorbis_client_data;
-    return 0;
+    if (ogg_stream_pagein (&codec->os, page) < 0)
+        ogg_info->error = 1;
+    return NULL;
 }
 
-static void free_vorbis_client_data (client_t *client)
-{
-    free (client->format_data);
-    client->format_data = NULL;
-}
 
-
-static int send_vorbis_headers (client_t *client, refbuf_t *headers)
+static refbuf_t *vorbis_page (ogg_state_t *ogg_info,
+        ogg_codec_t *codec, ogg_page *page)
 {
-    struct client_vorbis *client_data = client->format_data;
-    refbuf_t *refbuf;
-    int written = 0;
-
-    if (client_data->headers_sent)
+    if (codec->headers < 3)
     {
-        /* printf ("setting client_data header to %p\n", headers); */
-        client_data->header_page = headers;
-        client_data->pos = 0;
-        client_data->headers_sent = 0;
-    }
-    refbuf = client_data->header_page;
-    while (refbuf)
-    {
-        char *data = refbuf->data + client_data->pos;
-        unsigned len = refbuf->len - client_data->pos;
-        int ret;
+        vorbis_codec_t *vorbis = codec->specific;
+        ogg_packet packet;
 
-        /* printf ("....sending header at %p\n", refbuf); */
-        ret = client_send_bytes (client, data, len);
-        if (ret > 0)
-           written += ret;
-        if (ret < (int)len)
-            return written ? written : -1;
-        client_data->pos += ret;
-        if (client_data->pos == refbuf->len)
+        ogg_stream_pagein (&codec->os, page);
+        while (ogg_stream_packetout (&codec->os, &packet) > 0)
         {
-            refbuf = refbuf->next;
-            client_data->header_page = refbuf;
-            client_data->pos = 0;
+            if (vorbis_synthesis_headerin (&vorbis->vi, &vorbis->vc, &packet) < 0)
+            {
+                ogg_info->error = 1;
+                WARN0 ("error processing vorbis header packet");
+                return NULL;
+            }
+            codec->headers++;
         }
-    }
-    client_data->headers_sent = 1;
-    client_data->headers = headers;
-    return written;
-}
-
-
-static int vorbis_write_buf_to_client (source_t *source, client_t *client)
-{
-    refbuf_t *refbuf = client->refbuf;
-    char *buf;
-    unsigned len;
-    struct client_vorbis *client_data = client->format_data;
-    int ret, written = 0;
-
-    /* rare but the listener could connect before audio is ready */
-    if (refbuf == NULL)
-        return 0;
-    /* printf ("client %p (%p) @ %lu\n", refbuf, refbuf->next,  client->pos); */
-    if (refbuf->next == NULL && client->pos == refbuf->len)
-        return 0;
-
-    if (refbuf->next && client->pos == refbuf->len)
-    {
-        client_set_queue (client, refbuf->next);
-        refbuf = client->refbuf;
-    }
-    refbuf = client->refbuf;
-    buf = refbuf->data + client->pos;
-    len = refbuf->len - client->pos;
-    do
-    {
-        if (client_data->headers != refbuf->associated)
+        /* add header page to associated list */
+        format_ogg_attach_header (ogg_info, page);
+        DEBUG1 ("header page processed, headers at %d", codec->headers);
+        if (codec->headers == 3)
         {
-            /* printf ("sending header data %p\n", refbuf->associated); */
-            ret = send_vorbis_headers (client, refbuf->associated);
-            if (client_data->headers_sent == 0)
-                break;
-            written += ret;
-        }
-        /* printf ("sending audio data\n"); */
-        ret = client_send_bytes (client, buf, len);
+            char *comment;
+            free (ogg_info->title);
+            comment = vorbis_comment_query (&vorbis->vc, "TITLE", 0);
+            if (comment)
+                ogg_info->title = strdup (comment);
+            else
+                ogg_info->title = NULL;
 
-        if (ret > 0)
-            client->pos += ret;
+            free (ogg_info->artist);
+            comment = vorbis_comment_query (&vorbis->vc, "ARTIST", 0);
+            if (comment)
+                ogg_info->artist = strdup (comment);
+            else
+                ogg_info->artist = NULL;
 
-        if (ret < (int)len)
-            break;
-        written += ret;
-        /* we have now written the header page(s) */
-        ret = 0;
-    } while (0);
-
-    if (ret > 0)
-       written += ret;
-    return written ? written : -1;
-}
-
-
-static int write_vorbis_data (struct source_tag *source, refbuf_t *refbuf)
-{
-    int ret = 1;
-    if (fwrite (refbuf->data, 1, refbuf->len, source->dumpfile) != refbuf->len)
-    {
-        WARN0 ("Write to dump file failed, disabling");
-        fclose (source->dumpfile);
-        source->dumpfile = NULL;
-        ret = 0;
-    }
-    return ret;
-}
-
-
-static void write_vorbis_to_file (struct source_tag *source, refbuf_t *refbuf)
-{
-    vstate_t *source_vorbis = source->format->_state;
-
-    if (source_vorbis->file_headers != refbuf->associated)
-    {
-        refbuf_t *header = refbuf->associated;
-        while (header)
-        {
-            if (write_vorbis_data (source, header) == 0)
-                return;
-            header = header->next;
+            ogg_info->bitrate += vorbis->vi.bitrate_nominal;
+            stats_event_args (ogg_info->mount, "audio-samplerate", "%ld", (long)vorbis->vi.rate);
+            stats_event_args (ogg_info->mount, "audio-channels", "%ld", (long)vorbis->vi.channels);
+            stats_event_args (ogg_info->mount, "audio-bitrate", "%ld", (long)vorbis->vi.bitrate_nominal);
+            ogg_info->log_metadata = 1;
         }
-        source_vorbis->file_headers = refbuf->associated;
+        return NULL;
     }
-    write_vorbis_data (source, refbuf);
+    return make_refbuf_with_page (page);
 }
 
 
-void format_ogg_initialise (void)
-{
-    next_rebuild_serialno = 1;
-    thread_mutex_create ("serial", &serial_lock);
-}
 

Modified: icecast/branches/kh/icecast/src/format_vorbis.h
===================================================================
--- icecast/branches/kh/icecast/src/format_vorbis.h	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/format_vorbis.h	2004-11-29 15:45:57 UTC (rev 8304)
@@ -10,15 +10,12 @@
  *                      and others (see AUTHORS for details).
  */
 
-/* format_vorbis.h
-**
-** vorbis format plugin header
-**
-*/
-#ifndef __FORMAT_VORBIS_H__
-#define __FORMAT_VORBIS_H__
 
-int format_ogg_get_plugin (source_t *source);
-void format_ogg_initialise (void);
+#ifndef __FORMAT_VORBIS_H
+#define __FORMAT_VORBIS_H
 
-#endif  /* __FORMAT_VORBIS_H__ */
+#include "format_ogg.h"
+
+ogg_codec_t *initial_vorbis_page (format_plugin_t *plugin, ogg_page *page);
+
+#endif /* __FORMAT_VORBIS_H */

Modified: icecast/branches/kh/icecast/src/main.c
===================================================================
--- icecast/branches/kh/icecast/src/main.c	2004-11-29 15:42:20 UTC (rev 8303)
+++ icecast/branches/kh/icecast/src/main.c	2004-11-29 15:45:57 UTC (rev 8304)
@@ -102,7 +102,6 @@
     global_initialize();
     refbuf_initialize();
     xslt_initialize();
-    format_initialise();
 }
 
 static void _shutdown_subsystems(void)



More information about the commits mailing list