[xiph-commits] r18402 - icecast/trunk/icecast/src

giles at svn.xiph.org giles at svn.xiph.org
Wed Jun 13 14:24:23 PDT 2012


Author: giles
Date: 2012-06-13 14:24:23 -0700 (Wed, 13 Jun 2012)
New Revision: 18402

Added:
   icecast/trunk/icecast/src/format_ebml.c
   icecast/trunk/icecast/src/format_ebml.h
Modified:
   icecast/trunk/icecast/src/Makefile.am
   icecast/trunk/icecast/src/format.c
   icecast/trunk/icecast/src/format.h
Log:
Add WebM support.

This is David Richard's webm support patch from the icecast-webm branch.


Modified: icecast/trunk/icecast/src/Makefile.am
===================================================================
--- icecast/trunk/icecast/src/Makefile.am	2012-06-13 21:11:07 UTC (rev 18401)
+++ icecast/trunk/icecast/src/Makefile.am	2012-06-13 21:24:23 UTC (rev 18402)
@@ -10,13 +10,13 @@
     global.h util.h slave.h source.h stats.h refbuf.h client.h \
     compat.h fserve.h xslt.h yp.h event.h md5.h \
     auth.h auth_htpasswd.h auth_url.h \
-    format.h format_ogg.h format_mp3.h \
+    format.h format_ogg.h format_mp3.h format_ebml.h \
     format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \
     format_kate.h format_skeleton.h format_opus.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 \
     xslt.c fserve.c event.c admin.c md5.c \
-    format.c format_ogg.c format_mp3.c format_midi.c format_flac.c \
+    format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \
     auth.c auth_htpasswd.c format_kate.c format_skeleton.c format_opus.c
 EXTRA_icecast_SOURCES = yp.c \
     auth_url.c \

Modified: icecast/trunk/icecast/src/format.c
===================================================================
--- icecast/trunk/icecast/src/format.c	2012-06-13 21:11:07 UTC (rev 18401)
+++ icecast/trunk/icecast/src/format.c	2012-06-13 21:24:23 UTC (rev 18402)
@@ -40,6 +40,7 @@
 
 #include "format_ogg.h"
 #include "format_mp3.h"
+#include "format_ebml.h"
 
 #include "logging.h"
 #include "stats.h"
@@ -64,6 +65,16 @@
         return FORMAT_TYPE_OGG;
     else if(strcmp(contenttype, "video/ogg") == 0)
         return FORMAT_TYPE_OGG;
+    else if(strcmp(contenttype, "audio/webm") == 0)
+        return FORMAT_TYPE_EBML;
+    else if(strcmp(contenttype, "video/webm") == 0)
+        return FORMAT_TYPE_EBML;
+    else if(strcmp(contenttype, "audio/x-matroska") == 0)
+        return FORMAT_TYPE_EBML;
+    else if(strcmp(contenttype, "video/x-matroska") == 0)
+        return FORMAT_TYPE_EBML;
+    else if(strcmp(contenttype, "video/x-matroska-3d") == 0)
+        return FORMAT_TYPE_EBML;
     else
         /* We default to the Generic format handler, which
            can handle many more formats than just mp3 */
@@ -78,6 +89,9 @@
     case FORMAT_TYPE_OGG:
         ret = format_ogg_get_plugin (source);
         break;
+    case FORMAT_TYPE_EBML:
+        ret = format_ebml_get_plugin (source);
+        break;
     case FORMAT_TYPE_GENERIC:
         ret = format_mp3_get_plugin (source);
         break;

Modified: icecast/trunk/icecast/src/format.h
===================================================================
--- icecast/trunk/icecast/src/format.h	2012-06-13 21:11:07 UTC (rev 18401)
+++ icecast/trunk/icecast/src/format.h	2012-06-13 21:24:23 UTC (rev 18402)
@@ -29,6 +29,7 @@
 {
     FORMAT_ERROR, /* No format, source not processable */
     FORMAT_TYPE_OGG,
+    FORMAT_TYPE_EBML,
     FORMAT_TYPE_GENERIC
 } format_type_t;
 

Added: icecast/trunk/icecast/src/format_ebml.c
===================================================================
--- icecast/trunk/icecast/src/format_ebml.c	                        (rev 0)
+++ icecast/trunk/icecast/src/format_ebml.c	2012-06-13 21:24:23 UTC (rev 18402)
@@ -0,0 +1,469 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License,
+ * version 2. A copy of this license is included with this source.
+ * At your option, this specific source file can also be distributed
+ * under the GNU GPL version 3.
+ *
+ * Copyright 2012,      David Richards, Mozilla Foundation,
+ *                      and others (see AUTHORS for details).
+ */
+
+/* format_ebml.c
+ *
+ * format plugin for WebM/EBML
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "refbuf.h"
+#include "source.h"
+#include "client.h"
+
+#include "stats.h"
+#include "format.h"
+#include "format_ebml.h"
+
+#define CATMODULE "format-ebml"
+
+#include "logging.h"
+
+#define EBML_DEBUG 0
+#define EBML_HEADER_MAX_SIZE 131072
+#define EBML_SLICE_SIZE 4096
+
+
+typedef struct ebml_client_data_st ebml_client_data_t;
+
+struct ebml_client_data_st {
+
+    refbuf_t *header;
+    int header_pos;
+
+};
+
+struct ebml_st {
+
+    char *cluster_id;
+    int cluster_start;
+    
+    int position;
+    unsigned char *input_buffer;
+    unsigned char *buffer;
+
+    int header_read;
+    int header_size;
+    int header_position;
+    int header_read_position;
+    unsigned char *header;
+
+};
+
+static void ebml_free_plugin (format_plugin_t *plugin);
+static refbuf_t *ebml_get_buffer (source_t *source);
+static int  ebml_write_buf_to_client (client_t *client);
+static void  ebml_write_buf_to_file (source_t *source, refbuf_t *refbuf);
+static int  ebml_create_client_data (source_t *source, client_t *client);
+static void ebml_free_client_data (client_t *client);
+
+static ebml_t *ebml_create();
+static void ebml_destroy(ebml_t *ebml);
+static int ebml_read_space(ebml_t *ebml);
+static int ebml_read(ebml_t *ebml, char *buffer, int len);
+static int ebml_last_was_sync(ebml_t *ebml);
+static char *ebml_write_buffer(ebml_t *ebml, int len);
+static int ebml_wrote(ebml_t *ebml, int len);
+
+int format_ebml_get_plugin (source_t *source)
+{
+
+    ebml_source_state_t *ebml_source_state = calloc(1, sizeof(ebml_source_state_t));
+    format_plugin_t *plugin = calloc(1, sizeof(format_plugin_t));
+
+    plugin->get_buffer = ebml_get_buffer;
+    plugin->write_buf_to_client = ebml_write_buf_to_client;
+    plugin->create_client_data = ebml_create_client_data;
+    plugin->free_plugin = ebml_free_plugin;
+    plugin->write_buf_to_file = ebml_write_buf_to_file;
+    plugin->set_tag = NULL;
+    plugin->apply_settings = NULL;
+
+    plugin->contenttype = httpp_getvar (source->parser, "content-type");
+
+    plugin->_state = ebml_source_state;
+    source->format = plugin;
+
+    ebml_source_state->ebml = ebml_create();
+    return 0;
+}
+
+static void ebml_free_plugin (format_plugin_t *plugin)
+{
+
+    ebml_source_state_t *ebml_source_state = plugin->_state;
+
+    refbuf_release (ebml_source_state->header);
+    ebml_destroy(ebml_source_state->ebml);
+    free (ebml_source_state);
+    free (plugin);
+
+}
+
+static int send_ebml_header (client_t *client)
+{
+
+    ebml_client_data_t *ebml_client_data = client->format_data;
+    int len = EBML_SLICE_SIZE;
+    int ret;
+
+    if (ebml_client_data->header->len - ebml_client_data->header_pos < len) 
+    {
+        len = ebml_client_data->header->len - ebml_client_data->header_pos;
+    }
+    ret = client_send_bytes (client, 
+                             ebml_client_data->header->data + ebml_client_data->header_pos,
+                             len);
+
+    if (ret > 0)
+    {
+        ebml_client_data->header_pos += ret;
+    }
+
+    return ret;
+
+}
+
+static int ebml_write_buf_to_client (client_t *client)
+{
+
+    ebml_client_data_t *ebml_client_data = client->format_data;
+
+    if (ebml_client_data->header_pos != ebml_client_data->header->len)
+    {
+        return send_ebml_header (client);
+    }
+    else
+    {
+        client->write_to_client = format_generic_write_to_client;
+        return client->write_to_client(client);
+    }
+
+}
+
+static refbuf_t *ebml_get_buffer (source_t *source)
+{
+
+    ebml_source_state_t *ebml_source_state = source->format->_state;
+    format_plugin_t *format = source->format;
+    char *data = NULL;
+    int bytes = 0;
+    refbuf_t *refbuf;
+    int ret;
+
+    while (1)
+    {
+
+        if ((bytes = ebml_read_space(ebml_source_state->ebml)) > 0)
+        {
+            refbuf = refbuf_new(bytes);
+            ebml_read(ebml_source_state->ebml, refbuf->data, bytes);
+
+            if (ebml_source_state->header == NULL)
+            {
+                ebml_source_state->header = refbuf;
+                continue;
+            }
+
+            if (ebml_last_was_sync(ebml_source_state->ebml))
+            {
+                refbuf->sync_point = 1;
+            }
+            return refbuf;
+
+        }
+        else
+        {
+
+            data = ebml_write_buffer(ebml_source_state->ebml, EBML_SLICE_SIZE);
+            bytes = client_read_bytes (source->client, data, EBML_SLICE_SIZE);
+            if (bytes <= 0)
+            {
+                ebml_wrote (ebml_source_state->ebml, 0);
+                return NULL;
+            }
+            format->read_bytes += bytes;
+            ret = ebml_wrote (ebml_source_state->ebml, bytes);
+            if (ret != bytes) {
+                ERROR0 ("Problem processing stream");
+                source->running = 0;
+                return NULL;
+            }
+        }
+    }
+}
+
+static int ebml_create_client_data (source_t *source, client_t *client)
+{
+
+    ebml_client_data_t *ebml_client_data = calloc(1, sizeof(ebml_client_data_t));
+    ebml_source_state_t *ebml_source_state = source->format->_state;
+
+    int ret = -1;
+
+    if ((ebml_client_data) && (ebml_source_state->header))
+    {
+        ebml_client_data->header = ebml_source_state->header;
+        refbuf_addref (ebml_client_data->header);
+        client->format_data = ebml_client_data;
+        client->free_client_data = ebml_free_client_data;
+        ret = 0;
+    }
+
+    return ret;
+
+}
+
+
+static void ebml_free_client_data (client_t *client)
+{
+
+    ebml_client_data_t *ebml_client_data = client->format_data;
+
+    refbuf_release (ebml_client_data->header);
+    free (client->format_data);
+    client->format_data = NULL;
+}
+
+
+static void ebml_write_buf_to_file_fail (source_t *source)
+{
+    WARN0 ("Write to dump file failed, disabling");
+    fclose (source->dumpfile);
+    source->dumpfile = NULL;
+}
+
+
+static void ebml_write_buf_to_file (source_t *source, refbuf_t *refbuf)
+{
+
+    ebml_source_state_t *ebml_source_state = source->format->_state;
+
+    if (ebml_source_state->file_headers_written == 0)
+    {
+        if (fwrite (ebml_source_state->header->data, 1,
+                    ebml_source_state->header->len, 
+                    source->dumpfile) != ebml_source_state->header->len)
+            ebml_write_buf_to_file_fail(source);
+        else
+            ebml_source_state->file_headers_written = 1;
+    }
+
+    if (fwrite (refbuf->data, 1, refbuf->len, source->dumpfile) != refbuf->len)
+    {
+        ebml_write_buf_to_file_fail(source);
+    }
+
+}
+
+
+/* internal ebml parsing */
+
+static void ebml_destroy(ebml_t *ebml)
+{
+
+    free(ebml->header);
+    free(ebml->input_buffer);
+    free(ebml->buffer);
+    free(ebml);
+
+}
+
+static ebml_t *ebml_create()
+{
+
+    ebml_t *ebml = calloc(1, sizeof(ebml_t));
+
+    ebml->header = calloc(1, EBML_HEADER_MAX_SIZE);
+    ebml->buffer = calloc(1, EBML_SLICE_SIZE * 4);
+    ebml->input_buffer = calloc(1, EBML_SLICE_SIZE);
+
+    ebml->cluster_id = "\x1F\x43\xB6\x75";
+
+    ebml->cluster_start = -2;
+
+    return ebml;
+
+}
+
+static int ebml_read_space(ebml_t *ebml)
+{
+
+    int read_space;
+
+    if (ebml->header_read == 1)
+    {
+        if (ebml->cluster_start > 0)
+            read_space = ebml->cluster_start;
+        else
+            read_space = ebml->position - 4;
+            
+        return read_space;
+    }
+    else
+    {
+        if (ebml->header_size != 0)
+            return ebml->header_size;
+        else
+            return 0;
+    }
+
+}
+
+static int ebml_read(ebml_t *ebml, char *buffer, int len)
+{
+
+    int read_space;
+    int to_read;
+
+    if (len < 1)
+        return 0;
+
+    if (ebml->header_read == 1) 
+    {
+        if (ebml->cluster_start > 0)
+            read_space = ebml->cluster_start;
+        else
+            read_space = ebml->position - 4;
+
+        if (read_space < 1)
+            return 0;
+
+        if (read_space >= len )
+            to_read = len;
+        else
+            to_read = read_space;
+
+        memcpy(buffer, ebml->buffer, to_read);
+        memmove(ebml->buffer, ebml->buffer + to_read, ebml->position - to_read);
+        ebml->position -= to_read;
+        
+        if (ebml->cluster_start > 0)
+            ebml->cluster_start -= to_read;
+    }
+    else
+    {
+        if (ebml->header_size != 0)
+        {
+            read_space = ebml->header_size - ebml->header_read_position;
+
+            if (read_space >= len)
+                to_read = len;
+            else
+                to_read = read_space;
+
+            memcpy(buffer, ebml->header, to_read);
+            ebml->header_read_position += to_read;
+
+            if (ebml->header_read_position == ebml->header_size)
+                ebml->header_read = 1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+
+    return to_read;
+
+}
+
+static int ebml_last_was_sync(ebml_t *ebml)
+{
+
+    if (ebml->cluster_start == 0)
+    {
+        ebml->cluster_start -= 1;
+        return 0;
+    }
+  
+    if (ebml->cluster_start == -1)
+    {
+        ebml->cluster_start -= 1;
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static char *ebml_write_buffer(ebml_t *ebml, int len)
+{
+
+    return (char *)ebml->input_buffer;
+
+}
+
+
+static int ebml_wrote(ebml_t *ebml, int len)
+{
+
+    int b;
+
+    if (ebml->header_size == 0)
+    {
+        if ((ebml->header_position + len) > EBML_HEADER_MAX_SIZE)
+        {
+            ERROR0("EBML Header too large, failing");
+            return -1;
+        }
+        
+        if (EBML_DEBUG)
+        {
+            printf("EBML: Adding to header, ofset is %d size is %d adding %d\n", 
+                   ebml->header_size, ebml->header_position, len);
+        }
+        
+        memcpy(ebml->header + ebml->header_position, ebml->input_buffer, len);
+        ebml->header_position += len;
+    }
+    else
+    {
+        memcpy(ebml->buffer + ebml->position, ebml->input_buffer, len);
+    }
+    
+    for (b = 0; b < len - 4; b++)
+    {
+        if (!memcmp(ebml->input_buffer + b, ebml->cluster_id, 4))
+        {
+            if (EBML_DEBUG)
+            {
+                printf("EBML: found cluster\n");
+            }
+        
+            if (ebml->header_size == 0)
+            {
+                ebml->header_size = ebml->header_position - len + b;
+                memcpy(ebml->buffer, ebml->input_buffer + b, len - b);
+                ebml->position = len - b;
+                ebml->cluster_start = -1;
+                return len;
+            }
+            else
+            {
+                ebml->cluster_start = ebml->position + b;
+            }
+        }
+    }
+    
+    ebml->position += len;
+
+    return len;
+
+}

Added: icecast/trunk/icecast/src/format_ebml.h
===================================================================
--- icecast/trunk/icecast/src/format_ebml.h	                        (rev 0)
+++ icecast/trunk/icecast/src/format_ebml.h	2012-06-13 21:24:23 UTC (rev 18402)
@@ -0,0 +1,35 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License,
+ * version 2. A copy of this license is included with this source.
+ * At your option, this specific source file can also be distributed
+ * under the GNU GPL version 3.
+ *
+ * Copyright 2012,      David Richards, Mozilla Foundation,
+ *                      and others (see AUTHORS for details).
+ */
+
+/* format_ebml.h
+**
+** ebml format plugin header
+**
+*/
+#ifndef __FORMAT_EBML_H__
+#define __FORMAT_EBML_H__
+
+#include "format.h"
+
+typedef struct ebml_st ebml_t;
+typedef struct ebml_source_state_st ebml_source_state_t;
+
+struct ebml_source_state_st {
+
+    ebml_t *ebml;
+    refbuf_t *header;
+    int file_headers_written;
+
+};
+
+int format_ebml_get_plugin (source_t *source);
+
+#endif  /* __FORMAT_EBML_H__ */



More information about the commits mailing list