[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