Commit 29e9ebcf authored by Ronald S. Bultje's avatar Ronald S. Bultje
Browse files

Add C-based local matroska/EBML plugin, remove libmatroska/libebml c++ one

Original commit message from CVS:
Add C-based local matroska/EBML plugin, remove libmatroska/libebml c++ one
parent e21d05a3
......@@ -287,6 +287,7 @@ GST_PLUGINS_ALL="\
intfloat \
law \
level \
matroska \
median \
mixmatrix \
mpeg1sys \
......@@ -956,15 +957,6 @@ GST_CHECK_FEATURE(MAD, [mad mp3 decoder], mad, [
])
AC_SUBST(MAD_LIBS)
dnl *** matroska ***
translit(dnm, m, l) AM_CONDITIONAL(USE_MATROSKA, true)
GST_CHECK_FEATURE(MATROSKA, [matroska muxer/demuxer], matroska muxer/demuxer, [
PATH_EBML([HAVE_MATROSKA=yes], [HAVE_MATROSKA=no])
if test x$HAVE_MATROSKA = xyes; then
PATH_MATROSKA(0.4.4, [HAVE_MATROSKA=yes], [HAVE_MATROSKA=no])
fi
])
dnl *** mikmod ***
translit(dnm, m, l) AM_CONDITIONAL(USE_MIKMOD, true)
GST_CHECK_FEATURE(MIKMOD, [mikmod plug-in], mikmod, [
......@@ -1316,6 +1308,7 @@ gst/id3/Makefile
gst/intfloat/Makefile
gst/law/Makefile
gst/level/Makefile
gst/matroska/Makefile
gst/median/Makefile
gst/mixmatrix/Makefile
gst/mpeg1sys/Makefile
......@@ -1401,7 +1394,6 @@ ext/libfame/Makefile
ext/libpng/Makefile
ext/mad/Makefile
ext/mas/Makefile
ext/matroska/Makefile
ext/mikmod/Makefile
ext/mpeg2dec/Makefile
ext/mplex/Makefile
......
......@@ -172,12 +172,6 @@ else
MAD_DIR=
endif
if USE_MATROSKA
MATROSKA_DIR=matroska
else
MATROSKA_DIR=
endif
if USE_MIKMOD
MIKMOD_DIR=mikmod
else
......@@ -309,7 +303,6 @@ SUBDIRS=\
$(LIBPNG_DIR) \
$(MAD_DIR) \
$(MAS_DIR) \
$(MATROSKA_DIR) \
$(MIKMOD_DIR) \
$(MPEG2DEC_DIR) \
$(MPLEX_DIR) \
......@@ -357,7 +350,6 @@ DIST_SUBDIRS=\
libfame \
libpng \
mad \
matroska \
mikmod \
mpeg2dec \
mplex \
......
plugin_LTLIBRARIES = libgstmatroska.la
libgstmatroska_la_SOURCES = \
ebml-read.c \
matroska.c \
matroska-demux.c
noinst_HEADERS = \
ebml-ids.h \
ebml-read.h \
matroska-demux.h \
matroska-ids.h
libgstmatroska_la_CFLAGS = $(GST_CFLAGS)
libgstmatroska_la_LIBADD =
libgstmatroska_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
/* GStreamer EBML I/O
* (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* ebml-ids.h: definition of EBML data IDs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_EBML_IDS_H__
#define __GST_EBML_IDS_H__
G_BEGIN_DECLS
/* EBML version supported */
#define GST_EBML_VERSION 1
/* top-level master-IDs */
#define GST_EBML_ID_HEADER 0x1A45DFA3
/* IDs in the HEADER master */
#define GST_EBML_ID_EBMLVERSION 0x4286
#define GST_EBML_ID_EBMLREADVERSION 0x42F7
#define GST_EBML_ID_EBMLMAXIDLENGTH 0x42F2
#define GST_EBML_ID_EBMLMAXSIZELENGTH 0x42F3
#define GST_EBML_ID_DOCTYPE 0x4282
#define GST_EBML_ID_DOCTYPEVERSION 0x4287
#define GST_EBML_ID_DOCTYPEREADVERSION 0x4285
/* general EBML types */
#define GST_EBML_ID_VOID 0xEC
G_END_DECLS
#endif /* __GST_EBML_IDS_H__ */
/* GStreamer EBML I/O
* (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* ebml-read.c: read EBML data from file/stream
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "ebml-read.h"
#include "ebml-ids.h"
enum {
/* FILL ME */
LAST_SIGNAL
};
static void gst_ebml_read_class_init (GstEbmlReadClass *klass);
static void gst_ebml_read_init (GstEbmlRead *ebml);
static GstElementStateReturn
gst_ebml_read_change_state (GstElement *element);
static GstElementClass *parent_class = NULL;
GType
gst_ebml_read_get_type (void)
{
static GType gst_ebml_read_type = 0;
if (!gst_ebml_read_type) {
static const GTypeInfo gst_ebml_read_info = {
sizeof (GstEbmlReadClass),
NULL,
NULL,
(GClassInitFunc) gst_ebml_read_class_init,
NULL,
NULL,
sizeof (GstEbmlRead),
0,
(GInstanceInitFunc) gst_ebml_read_init,
};
gst_ebml_read_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstEbmlRead",
&gst_ebml_read_info, 0);
}
return gst_ebml_read_type;
}
static void
gst_ebml_read_class_init (GstEbmlReadClass *klass)
{
GstElementClass *gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
gstelement_class->change_state = gst_ebml_read_change_state;
}
static void
gst_ebml_read_init (GstEbmlRead *ebml)
{
ebml->sinkpad = NULL;
ebml->bs = NULL;
ebml->level = NULL;
}
static GstElementStateReturn
gst_ebml_read_change_state (GstElement *element)
{
GstEbmlRead *ebml = GST_EBML_READ (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_PAUSED:
if (!ebml->sinkpad)
return GST_STATE_FAILURE;
ebml->bs = gst_bytestream_new (ebml->sinkpad);
break;
case GST_STATE_PAUSED_TO_READY:
gst_bytestream_destroy (ebml->bs);
while (ebml->level) {
GstEbmlLevel *level = ebml->level->data;
ebml->level = g_list_remove (ebml->level, level);
g_free (level);
}
break;
default:
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
/*
* Return: the amount of levels in the hierarchy that the
* current element lies higher than the previous one.
* The opposite isn't done - that's auto-done using master
* element reading.
*/
static guint
gst_ebml_read_element_level_up (GstEbmlRead *ebml)
{
guint num = 0;
guint64 pos = gst_bytestream_tell (ebml->bs);
while (ebml->level != NULL) {
GList *last = g_list_last (ebml->level);
GstEbmlLevel *level = last->data;
if (pos >= level->start + level->length) {
ebml->level = g_list_remove (ebml->level, level);
g_free (level);
num++;
} else
break;
}
return num;
}
/*
* Read: the element content data ID.
* Return: the number of bytes read or -1 on error.
*/
static gint
gst_ebml_read_element_id (GstEbmlRead *ebml,
guint32 *id,
guint *level_up)
{
guint8 *data;
gint len_mask = 0x80, read = 1, n = 1;
guint32 total;
if (gst_bytestream_peek_bytes (ebml->bs, &data, 1) != 1) {
/*gst_element_error (GST_ELEMENT (ebml), "Read error");*/
return -1;
}
total = data[0];
while (read <= 4 && !(total & len_mask)) {
read++;
len_mask >>= 1;
}
if (read > 4) {
gst_element_error (GST_ELEMENT (ebml),
"Invalid EBML ID size tag (0x%x)", data[0]);
return -1;
}
if (gst_bytestream_peek_bytes (ebml->bs, &data, read) != read) {
/*gst_element_error (GST_ELEMENT (ebml), "Read error");*/
return -1;
}
while (n < read)
total = (total << 8) | data[n++];
*id = total;
/* level */
if (level_up)
*level_up = gst_ebml_read_element_level_up (ebml);
return read;
}
/*
* Read: element content length.
* Return: the number of bytes read or -1 on error.
*/
static gint
gst_ebml_read_element_length (GstEbmlRead *ebml,
guint64 *length)
{
guint8 *data;
gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
guint64 total;
if (gst_bytestream_peek_bytes (ebml->bs, &data, 1) != 1) {
/*gst_element_error (GST_ELEMENT (ebml), "Read error");*/
return -1;
}
total = data[0];
while (read <= 8 && !(total & len_mask)) {
read++;
len_mask >>= 1;
}
if (read > 8) {
gst_element_error (GST_ELEMENT (ebml),
"Invalid EBML length size tag (0x%x)", data[0]);
return -1;
}
if ((total &= (len_mask - 1)) == len_mask - 1)
num_ffs++;
if (gst_bytestream_peek_bytes (ebml->bs, &data, read) != read) {
/*gst_element_error (GST_ELEMENT (ebml), "Read error");*/
return -1;
}
while (n < read) {
if (data[n] == 0xff)
num_ffs++;
total = (total << 8) | data[n];
n++;
}
if (!total) {
gst_element_error (GST_ELEMENT (ebml),
"Invalid length 0");
return -1;
}
if (read == num_ffs)
*length = G_MAXUINT64;
else
*length = total;
return read;
}
/*
* Read: the actual data.
* Return: the data, as a GstBuffer.
*/
static GstBuffer *
gst_ebml_read_element_data (GstEbmlRead *ebml,
guint64 length)
{
GstBuffer *buf = NULL;
if (gst_bytestream_peek (ebml->bs, &buf, length) != length) {
/*gst_element_error (GST_ELEMENT (ebml), "Read error");*/
if (buf)
gst_buffer_unref (buf);
return NULL;
}
gst_bytestream_flush_fast (ebml->bs, length);
return buf;
}
/*
* Return: the ID of the next element.
* Level_up contains the amount of levels that this
* next element lies higher than the previous one.
*/
guint32
gst_ebml_peek_id (GstEbmlRead *ebml,
guint *level_up)
{
guint32 id;
guint my_level_up;
g_return_val_if_fail (level_up != NULL, 0);
if (gst_ebml_read_element_id (ebml, &id, &my_level_up) < 0)
return 0;
if (level_up)
*level_up = my_level_up;
return id;
}
/*
* Seek to a given offset.
*/
void
gst_ebml_read_seek (GstEbmlRead *ebml,
guint64 offset)
{
gst_bytestream_seek (ebml->bs, offset, GST_SEEK_METHOD_SET);
}
/*
* Skip the next element.
*/
gboolean
gst_ebml_read_skip (GstEbmlRead *ebml)
{
gint bytes;
guint32 id;
guint64 length;
if ((bytes = gst_ebml_read_element_id (ebml, &id, NULL)) < 0)
return FALSE;
gst_bytestream_flush_fast (ebml->bs, bytes);
if ((bytes = gst_ebml_read_element_length (ebml, &length)) < 0)
return FALSE;
gst_bytestream_flush_fast (ebml->bs, bytes);
return gst_bytestream_flush (ebml->bs, length);
}
/*
* Read the next element as a GstBuffer (binary).
*/
gboolean
gst_ebml_read_buffer (GstEbmlRead *ebml,
guint32 *id,
GstBuffer **buf)
{
gint bytes;
guint64 length;
if ((bytes = gst_ebml_read_element_id (ebml, id, NULL)) < 0)
return FALSE;
gst_bytestream_flush_fast (ebml->bs, bytes);
if ((bytes = gst_ebml_read_element_length (ebml, &length)) < 0)
return FALSE;
gst_bytestream_flush_fast (ebml->bs, bytes);
return ((*buf = gst_ebml_read_element_data (ebml, length)) != NULL);
}
/*
* Read the next element as an unsigned int.
*/
gboolean
gst_ebml_read_uint (GstEbmlRead *ebml,
guint32 *id,
guint64 *num)
{
GstBuffer *buf;
guint8 *data;
guint size;
if (!gst_ebml_read_buffer (ebml, id, &buf))
return FALSE;
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
if (size < 1 || size > 8) {
gst_element_error (GST_ELEMENT (ebml),
"Invalid integer element size %d", size);
gst_buffer_unref (buf);
return FALSE;
}
*num = 0;
while (size > 0) {
*num = (*num << 8) | data[GST_BUFFER_SIZE (buf) - size];
size--;
}
gst_buffer_unref (buf);
return TRUE;
}
/*
* Read the next element as a signed int.
*/
gboolean
gst_ebml_read_sint (GstEbmlRead *ebml,
guint32 *id,
gint64 *num)
{
GstBuffer *buf;
guint8 *data;
guint size;
if (!gst_ebml_read_buffer (ebml, id, &buf))
return FALSE;
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
if (size < 1 || size > 8) {
gst_element_error (GST_ELEMENT (ebml),
"Invalid integer element size %d", size);
gst_buffer_unref (buf);
return FALSE;
}
*num = 0;
while (size > 0) {
*num = (*num << 8) | data[GST_BUFFER_SIZE (buf) - size];
size--;
}
/* make signed */
*num -= (1LL << ((8 * GST_BUFFER_SIZE (buf)) - 1));
gst_buffer_unref (buf);
return TRUE;
}
/*
* Read the next element as a float.
*/
gboolean
gst_ebml_read_float (GstEbmlRead *ebml,
guint32 *id,
gdouble *num)
{
GstBuffer *buf;
guint8 *data;
guint size;
if (!gst_ebml_read_buffer (ebml, id, &buf))
return FALSE;
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
if (size != 4 && size != 8 && size != 10) {
gst_element_error (GST_ELEMENT (ebml),
"Invalid float element size %d", size);
gst_buffer_unref (buf);
return FALSE;
}
if (size == 10) {
gst_element_error (GST_ELEMENT (ebml),
"FIXME! 10-byte floats unimplemented");
gst_buffer_unref (buf);
return FALSE;
}
if (size == 4) {
gfloat f;
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
f = * (gfloat *) data;
#else
while (size > 0) {
((guint8 *) &f)[size - 1] = data[4 - size];
size--;
}
#endif
*num = f;
} else {
gdouble d;
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
d = * (gdouble *) data;
#else
while (size > 0) {
((guint8 *) &d)[size - 1] = data[8 - size];
size--;
}
#endif
*num = d;
}
gst_buffer_unref (buf);
return TRUE;
}
/*
* Read the next element as an ASCII string.
*/
gboolean
gst_ebml_read_ascii (GstEbmlRead *ebml,