[xiph-commits] r7056 - icecast/trunk/libshout/src
brendan at dactyl.lonelymoon.com
brendan
Thu Jul 8 13:54:13 PDT 2004
Author: brendan
Date: Thu Jul 8 13:54:13 2004
New Revision: 7056
Modified:
icecast/trunk/libshout/src/ogg.c
Log:
A reorganised version of Karl's multicodec support. Only Vorbis has been ported
in this patch - Theora is up next.
Modified: icecast/trunk/libshout/src/ogg.c
===================================================================
--- icecast/trunk/libshout/src/ogg.c 2004-07-08 20:37:07 UTC (rev 7055)
+++ icecast/trunk/libshout/src/ogg.c 2004-07-08 20:54:12 UTC (rev 7056)
@@ -36,37 +36,69 @@
#include "shout_private.h"
/* -- local datatypes -- */
-typedef struct {
- /* total pages broadcasted */
- unsigned int pages;
+typedef struct _ogg_codec_tag {
+ ogg_stream_state os;
- unsigned int samplerate;
+ unsigned int headers;
+ uint64_t senttime;
+ void *codec_data;
+ int (*read_page)(struct _ogg_codec_tag *codec, ogg_page *page);
+ void (*free_data)(void *codec_data);
+
+ struct _ogg_codec_tag *next;
+} ogg_codec_t;
+
+typedef struct {
ogg_sync_state oy;
- ogg_stream_state os;
+ ogg_codec_t *codecs;
+ char bos;
+} ogg_data_t;
- int headers;
+typedef struct {
vorbis_info vi;
vorbis_comment vc;
int prevW;
-
- long serialno;
- int initialised;
} vorbis_data_t;
/* -- static prototypes -- */
static int send_ogg(shout_t *self, const unsigned char *data, size_t len);
static void close_ogg(shout_t *self);
+static int open_codec(ogg_codec_t *codec, ogg_page *page);
+static void free_codec(ogg_codec_t *codec);
+static void free_codecs(ogg_data_t *ogg_data);
+static int send_page(shout_t *self, ogg_page *page);
+/* vorbis handler */
+static int open_vorbis(ogg_codec_t *codec, ogg_page *page);
+static int read_vorbis_page(ogg_codec_t *codec, ogg_page *page);
+static void free_vorbis_data(void *codec_data);
+static int vorbis_blocksize(vorbis_data_t *vd, ogg_packet *p);
+
+#ifdef HAVE_THEORA
+/* theora handler */
+static int open_theora(ogg_codec_t *codec, ogg_page *page);
+#endif
+
+typedef int (*codec_open_t)(ogg_codec_t *codec, ogg_page *page);
+static codec_open_t codecs[] = {
+ open_vorbis,
+#ifdef HAVE_THEORA
+ open_theora,
+#endif
+ NULL
+};
+
int shout_open_ogg(shout_t *self)
{
- vorbis_data_t *vorbis_data;
+ ogg_data_t *ogg_data;
- if (!(vorbis_data = (vorbis_data_t *)calloc(1, sizeof(vorbis_data_t))))
- return SHOUTERR_MALLOC;
- self->format_data = vorbis_data;
+ if (!(ogg_data = (ogg_data_t *)calloc(1, sizeof(ogg_data_t))))
+ return self->error = SHOUTERR_MALLOC;
+ self->format_data = ogg_data;
- ogg_sync_init(&vorbis_data->oy);
+ ogg_sync_init(&ogg_data->oy);
+ ogg_data->bos = 1;
self->send = send_ogg;
self->close = close_ogg;
@@ -74,95 +106,200 @@
return SHOUTERR_SUCCESS;
}
-static int blocksize(vorbis_data_t *vd, ogg_packet *p)
+static int send_ogg(shout_t *self, const unsigned char *data, size_t len)
{
- int this = vorbis_packet_blocksize(&vd->vi, p);
- int ret = (this + vd->prevW)/4;
+ ogg_data_t *ogg_data = (ogg_data_t *)self->format_data;
+ ogg_codec_t *codec;
+ char *buffer;
+ ogg_page page;
- if(!vd->prevW) {
- vd->prevW = this;
- return 0;
+ buffer = ogg_sync_buffer(&ogg_data->oy, len);
+ memcpy(buffer, data, len);
+ ogg_sync_wrote(&ogg_data->oy, len);
+
+ while (ogg_sync_pageout(&ogg_data->oy, &page) == 1) {
+ if (ogg_page_bos (&page)) {
+ if (! ogg_data->bos) {
+ free_codecs(ogg_data);
+ ogg_data->bos = 1;
+ }
+
+ ogg_codec_t *codec = calloc(1, sizeof(ogg_codec_t));
+ if (! codec)
+ return self->error = SHOUTERR_MALLOC;
+
+ if ((self->error = open_codec(codec, &page)) != SHOUTERR_SUCCESS)
+ return self->error;
+
+ codec->headers = 1;
+ codec->senttime = self->senttime;
+ codec->next = ogg_data->codecs;
+ ogg_data->codecs = codec;
+ } else {
+ ogg_data->bos = 0;
+
+ codec = ogg_data->codecs;
+ while (codec) {
+ if (ogg_page_serialno(&page) == codec->os.serialno) {
+ if (codec->read_page) {
+ ogg_stream_pagein(&codec->os, &page);
+ codec->read_page(codec, &page);
+
+ if (self->senttime < codec->senttime)
+ self->senttime = codec->senttime;
+ }
+
+ break;
+ }
+
+ codec = codec->next;
+ }
+ }
+
+ if ((self->error = send_page(self, &page)) != SHOUTERR_SUCCESS)
+ return self->error;
}
- vd->prevW = this;
- return ret;
+ return self->error = SHOUTERR_SUCCESS;
}
-static int send_ogg(shout_t *self, const unsigned char *data, size_t len)
+static void close_ogg(shout_t *self)
{
- vorbis_data_t *vorbis_data = (vorbis_data_t *)self->format_data;
- int ret;
- char *buffer;
- ogg_page og;
- ogg_packet op;
- uint64_t samples;
+ ogg_data_t *ogg_data = (ogg_data_t *)self->format_data;
+ free_codecs(ogg_data);
+ ogg_sync_clear(&ogg_data->oy);
+ free(ogg_data);
+}
- buffer = ogg_sync_buffer(&vorbis_data->oy, len);
- memcpy(buffer, data, len);
- ogg_sync_wrote(&vorbis_data->oy, len);
+static int open_codec(ogg_codec_t *codec, ogg_page *page)
+{
+ codec_open_t open_codec;
+ int i = 0;
- while (ogg_sync_pageout(&vorbis_data->oy, &og) == 1) {
- if (vorbis_data->serialno != ogg_page_serialno(&og) ||
- !vorbis_data->initialised)
- {
- /* Clear the old one - this is safe even if there was no previous
- * stream */
- vorbis_comment_clear(&vorbis_data->vc);
- vorbis_info_clear(&vorbis_data->vi);
- ogg_stream_clear(&vorbis_data->os);
+ while ((open_codec = codecs[i])) {
+ ogg_stream_init(&codec->os, ogg_page_serialno(page));
+ ogg_stream_pagein(&codec->os, page);
- vorbis_data->serialno = ogg_page_serialno(&og);
+ if (open_codec(codec, page) == SHOUTERR_SUCCESS)
+ return SHOUTERR_SUCCESS;
- ogg_stream_init(&vorbis_data->os, vorbis_data->serialno);
+ ogg_stream_clear(&codec->os);
+ i++;
+ }
+
+ /* if no handler is found, we currently just fall back to untimed send_raw */
+ return SHOUTERR_SUCCESS;
+}
- vorbis_info_init(&vorbis_data->vi);
- vorbis_comment_init(&vorbis_data->vc);
+static void free_codecs(ogg_data_t *ogg_data)
+{
+ ogg_codec_t *codec, *next;
- vorbis_data->initialised = 1;
+ if (ogg_data == NULL)
+ return;
- vorbis_data->headers = 1;
- }
+ codec = ogg_data->codecs;
+ while (codec) {
+ next = codec->next;
+ free_codec(codec);
+ codec = next;
+ }
+ ogg_data->codecs = NULL;
+}
- samples = 0;
+static void free_codec(ogg_codec_t *codec)
+{
+ if (codec->free_data)
+ codec->free_data(codec->codec_data);
+ ogg_stream_clear(&codec->os);
+ free(codec);
+}
- ogg_stream_pagein(&vorbis_data->os, &og);
- while(ogg_stream_packetout(&vorbis_data->os, &op) == 1) {
- int size;
+static int send_page(shout_t *self, ogg_page *page)
+{
+ int ret;
- if(vorbis_data->headers > 0 && vorbis_data->headers <= 3) {
- vorbis_synthesis_headerin(&vorbis_data->vi, &vorbis_data->vc,
- &op);
- if(vorbis_data->headers == 1)
- vorbis_data->samplerate = vorbis_data->vi.rate;
+ ret = shout_send_raw(self, page->header, page->header_len);
+ if (ret != page->header_len)
+ return self->error = SHOUTERR_SOCKET;
+ ret = shout_send_raw(self, page->body, page->body_len);
+ if (ret != page->body_len)
+ return self->error = SHOUTERR_SOCKET;
- vorbis_data->headers++;
- continue;
- }
+ return SHOUTERR_SUCCESS;
+}
- vorbis_data->headers = 0;
- size = blocksize(vorbis_data, &op);
- samples += size;
- }
- self->senttime += (samples * 1000000) /
- (vorbis_data->samplerate);
+/* -- vorbis functions -- */
+static int open_vorbis(ogg_codec_t *codec, ogg_page *page)
+{
+ vorbis_data_t *vorbis_data = calloc(1, sizeof(vorbis_data_t));
+ ogg_packet packet;
- ret = sock_write_bytes(self->socket, og.header, og.header_len);
- if (ret != og.header_len)
- return self->error = SHOUTERR_SOCKET;
+ if (!vorbis_data)
+ return SHOUTERR_MALLOC;
- ret = sock_write_bytes(self->socket, og.body, og.body_len);
- if (ret != og.body_len)
- return self->error = SHOUTERR_SOCKET;
+ vorbis_info_init(&vorbis_data->vi);
+ vorbis_comment_init(&vorbis_data->vc);
- vorbis_data->pages++;
+ ogg_stream_packetout(&codec->os, &packet);
+
+ if (vorbis_synthesis_headerin(&vorbis_data->vi, &vorbis_data->vc, &packet) < 0) {
+ free_vorbis_data(vorbis_data);
+
+ return SHOUTERR_UNSUPPORTED;
}
- return self->error = SHOUTERR_SUCCESS;
+ codec->codec_data = vorbis_data;
+ codec->read_page = read_vorbis_page;
+ codec->free_data = free_vorbis_data;
+
+ return SHOUTERR_SUCCESS;
}
-static void close_ogg(shout_t *self)
+static int read_vorbis_page(ogg_codec_t *codec, ogg_page *page)
{
- vorbis_data_t *vorbis_data = (vorbis_data_t *)self->format_data;
- ogg_sync_clear(&vorbis_data->oy);
+ ogg_packet packet;
+ vorbis_data_t *vorbis_data = codec->codec_data;
+
+ if (codec->headers < 3) {
+ while (ogg_stream_packetout (&codec->os, &packet) > 0) {
+ if (vorbis_synthesis_headerin(&vorbis_data->vi, &vorbis_data->vc, &packet) < 0)
+ return SHOUTERR_INSANE;
+ codec->headers++;
+ }
+
+ return SHOUTERR_SUCCESS;
+ }
+
+ uint64_t samples = 0;
+
+ while (ogg_stream_packetout (&codec->os, &packet) > 0)
+ samples += vorbis_blocksize(vorbis_data, &packet);
+
+ codec->senttime += ((samples * 1000000) / vorbis_data->vi.rate);
+
+ return SHOUTERR_SUCCESS;
+}
+
+static void free_vorbis_data(void *codec_data)
+{
+ vorbis_data_t *vorbis_data = (vorbis_data_t *)codec_data;
+
+ vorbis_info_clear(&vorbis_data->vi);
+ vorbis_comment_clear(&vorbis_data->vc);
free(vorbis_data);
}
+
+static int vorbis_blocksize(vorbis_data_t *vd, ogg_packet *p)
+{
+ int this = vorbis_packet_blocksize(&vd->vi, p);
+ int ret = (this + vd->prevW)/4;
+
+ if(!vd->prevW) {
+ vd->prevW = this;
+ return 0;
+ }
+
+ vd->prevW = this;
+ return ret;
+}
More information about the commits
mailing list