summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--configure.ac9
-rw-r--r--ext/Makefile.am8
-rw-r--r--ext/xine/Makefile.am11
-rw-r--r--ext/xine/gstxine.h82
-rw-r--r--ext/xine/xine.c169
-rw-r--r--ext/xine/xineaudiodec.c556
-rw-r--r--ext/xine/xinecaps.c119
-rw-r--r--gst/qtdemux/qtdemux.c39
9 files changed, 997 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index 3fae7f22..76a1f9ce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2004-02-20 Benjamin Otte <otte@gnome.org>
+
+ * ext/xine/Makefile.am:
+ * ext/xine/gstxine.h:
+ * ext/xine/xine.c:
+ * ext/xine/xineaudiodec.c:
+ * ext/xine/xinecaps.c:
+ add first version of xine plugin wrapper. Currently only wraps the
+ QDM2 win32 DLL, and even that only in proof-of-concept quality.
+ * configure.ac:
+ * ext/Makefile.am:
+ add xine plugin wrapper, disabled by default. Use --enable-xine to
+ build. Note that it'll segfault on gst-register if you don't remove
+ the goom and tvtime post plugins from xine.
+ * gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_sink_event),
+ (qtdemux_parse), (qtdemux_parse_trak), (qtdemux_audio_caps):
+ add extradata parsing for QDM2.
+ change around debugging prints.
+
2004-02-19 Benjamin Otte <otte@gnome.org>
* ext/lame/gstlame.c: (gst_lame_chain):
diff --git a/configure.ac b/configure.ac
index 3626b82b..4631797a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1320,6 +1320,14 @@ vorbis_synthesis_restart (v);
CFLAGS="$ac_cflags_save"
fi
+dnl *** xine ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_XINE, true)
+GST_CHECK_FEATURE(XINE, [xine wrapper], xine, [
+ PKG_CHECK_MODULES(XINE, libxine >= 1.0.0, HAVE_XINE=yes, HAVE_XINE=no)
+ AC_SUBST(XINE_CFLAGS)
+ AC_SUBST(XINE_LIBS)
+],disabled)
+
dnl *** XVID ***
translit(dnm, m, l) AM_CONDITIONAL(USE_XVID, true)
GST_CHECK_FEATURE(XVID, [xvid plugins], xvid, [
@@ -1664,6 +1672,7 @@ ext/swfdec/Makefile
ext/tarkin/Makefile
ext/theora/Makefile
ext/vorbis/Makefile
+ext/xine/Makefile
ext/xvid/Makefile
gst-libs/Makefile
gst-libs/gst/Makefile
diff --git a/ext/Makefile.am b/ext/Makefile.am
index 4865588c..2f51a467 100644
--- a/ext/Makefile.am
+++ b/ext/Makefile.am
@@ -310,6 +310,12 @@ else
SPEEX_DIR=
endif
+if USE_XINE
+XINE_DIR=xine
+else
+XINE_DIR=
+endif
+
SUBDIRS=\
$(A52DEC_DIR) \
$(AALIB_DIR) \
@@ -361,6 +367,7 @@ SUBDIRS=\
$(THEORA_DIR) \
$(IVORBIS_DIR) \
$(VORBIS_DIR) \
+ $(XINE_DIR) \
$(XVID_DIR)
DIST_SUBDIRS=\
@@ -415,4 +422,5 @@ DIST_SUBDIRS=\
tarkin \
theora \
vorbis \
+ xine \
xvid
diff --git a/ext/xine/Makefile.am b/ext/xine/Makefile.am
new file mode 100644
index 00000000..b67889c7
--- /dev/null
+++ b/ext/xine/Makefile.am
@@ -0,0 +1,11 @@
+plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
+
+plugin_LTLIBRARIES = libgstxine.la
+
+libgstxine_la_SOURCES = xine.c xinecaps.c xineaudiodec.c
+libgstxine_la_CFLAGS = $(GST_CFLAGS) $(XINE_CFLAGS)
+libgstxine_la_LIBADD = $(XINE_LIBS)
+libgstxine_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstxine.h
+
diff --git a/ext/xine/gstxine.h b/ext/xine/gstxine.h
new file mode 100644
index 00000000..9fdc6588
--- /dev/null
+++ b/ext/xine/gstxine.h
@@ -0,0 +1,82 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * 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_XINE_H__
+#define __GST_XINE_H__
+
+#include <gst/gst.h>
+#include <xine.h>
+#include <xine/buffer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_XINE \
+ (gst_xine_get_type())
+#define GST_XINE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XINE,GstXine))
+#define GST_XINE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XINE, GstXineClass))
+#define GST_XINE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XINE,GstXineClass))
+#define GST_IS_XINE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XINE))
+#define GST_IS_XINE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XINE))
+
+typedef struct _GstXine GstXine;
+typedef struct _GstXineClass GstXineClass;
+
+struct _GstXine
+{
+ GstElement element;
+
+ xine_stream_t * stream;
+ xine_ao_driver_t * audio_driver;
+ xine_vo_driver_t * video_driver;
+};
+
+struct _GstXineClass
+{
+ GstElementClass parent_class;
+
+ xine_t * xine;
+
+ xine_ao_driver_t * (* create_audio_driver) (GstXine * xine);
+ xine_vo_driver_t * (* create_video_driver) (GstXine * xine);
+};
+
+GType gst_xine_get_type (void);
+
+xine_stream_t * gst_xine_get_stream (GstXine *xine);
+void gst_xine_free_stream (GstXine *xine);
+
+void gst_buffer_to_xine_buffer (buf_element_t *element, GstBuffer *buffer);
+
+/* conversion functions from xinecaps.c */
+
+const gchar * gst_xine_get_caps_for_format (guint32 format);
+guint32 gst_xine_get_format_for_caps (const GstCaps *caps);
+
+/* init functions for the plugins */
+
+gboolean gst_xine_audio_dec_init_plugin (GstPlugin *plugin);
+
+G_END_DECLS
+
+#endif /* __GST_XINE_H__ */
diff --git a/ext/xine/xine.c b/ext/xine/xine.c
new file mode 100644
index 00000000..f3bfb5ab
--- /dev/null
+++ b/ext/xine/xine.c
@@ -0,0 +1,169 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * 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 "gstxine.h"
+
+GST_BOILERPLATE (GstXine, gst_xine, GstElement, GST_TYPE_ELEMENT)
+
+static GstElementStateReturn gst_xine_change_state (GstElement * element);
+
+static xine_ao_driver_t * _xine_create_audio_driver (GstXine * xine);
+static xine_vo_driver_t * _xine_create_video_driver (GstXine * xine);
+
+
+static void
+gst_xine_base_init (gpointer klass)
+{
+}
+
+static void
+gst_xine_class_init (GstXineClass *klass)
+{
+ GstElementClass *element = GST_ELEMENT_CLASS (klass);
+
+ klass->xine = xine_new ();
+ xine_init (klass->xine);
+
+ klass->create_audio_driver = _xine_create_audio_driver;
+ klass->create_video_driver = _xine_create_video_driver;
+
+ element->change_state = gst_xine_change_state;
+}
+
+static void
+gst_xine_init (GstXine *filter)
+{
+}
+
+static GstElementStateReturn
+gst_xine_change_state (GstElement *element)
+{
+ GstXine *xine = GST_XINE (element);
+
+ switch (GST_STATE_TRANSITION (element)) {
+ case GST_STATE_NULL_TO_READY:
+ break;
+ case GST_STATE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_PAUSED_TO_PLAYING:
+ break;
+ case GST_STATE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_PAUSED_TO_READY:
+ break;
+ case GST_STATE_READY_TO_NULL:
+ if (xine->stream != NULL)
+ gst_xine_free_stream (xine);
+ break;
+ default:
+ GST_ERROR_OBJECT (element, "invalid state change");
+ break;
+ }
+
+ return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, (element), GST_STATE_SUCCESS);
+}
+
+static xine_ao_driver_t *
+_xine_create_audio_driver (GstXine *xine)
+{
+ return xine_open_audio_driver (GST_XINE_GET_CLASS (xine)->xine, "none", NULL);
+}
+
+static xine_vo_driver_t *
+_xine_create_video_driver (GstXine *xine)
+{
+ return xine_open_video_driver (GST_XINE_GET_CLASS (xine)->xine, "none", XINE_VISUAL_TYPE_NONE, NULL);
+}
+
+xine_stream_t *
+gst_xine_get_stream (GstXine *xine)
+{
+ if (!xine->stream) {
+ GstXineClass *klass = GST_XINE_GET_CLASS (xine);
+ g_assert (xine->video_driver == NULL);
+ g_assert (xine->audio_driver == NULL);
+ xine->audio_driver = klass->create_audio_driver (xine);
+ xine->video_driver = klass->create_video_driver (xine);
+ xine->stream = xine_stream_new (klass->xine, xine->audio_driver, xine->video_driver);
+
+ /* FIXME: fail gracefully */
+ g_assert (xine->stream);
+ }
+
+ return xine->stream;
+}
+
+void
+gst_xine_free_stream (GstXine *xine)
+{
+ g_return_if_fail (xine->stream != NULL);
+ g_assert (xine->video_driver != NULL);
+ g_assert (xine->audio_driver != NULL);
+
+ xine_dispose (xine->stream);
+ xine->stream = NULL;
+ xine_close_video_driver (GST_XINE_GET_CLASS (xine)->xine, xine->video_driver);
+ xine->video_driver = NULL;
+ xine_close_audio_driver (GST_XINE_GET_CLASS (xine)->xine, xine->audio_driver);
+ xine->audio_driver = NULL;
+}
+
+static void
+_free_xine_buf_element (buf_element_t *buffer)
+{
+ gst_buffer_unref (GST_BUFFER (buffer->source));
+}
+
+void
+gst_buffer_to_xine_buffer (buf_element_t *ret, GstBuffer *buffer)
+{
+ g_return_if_fail (ret != NULL);
+ g_return_if_fail (buffer != NULL);
+
+ /* FIXME: what's the difference? */
+ ret->mem = GST_BUFFER_DATA (buffer);
+ ret->content = GST_BUFFER_DATA (buffer);
+ ret->size = GST_BUFFER_SIZE (buffer);
+ ret->max_size = GST_BUFFER_MAXSIZE (buffer);
+ /* FIXME: add more */
+ ret->free_buffer = _free_xine_buf_element;
+ ret->source = buffer;
+}
+
+static gboolean
+plugin_init (GstPlugin *plugin)
+{
+ return gst_xine_audio_dec_init_plugin (plugin);
+}
+
+GST_PLUGIN_DEFINE (
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "xine",
+ "wrapper for libxine (version "XINE_VERSION") plugins",
+ plugin_init,
+ VERSION,
+ "GPL",
+ GST_PACKAGE,
+ GST_ORIGIN
+)
diff --git a/ext/xine/xineaudiodec.c b/ext/xine/xineaudiodec.c
new file mode 100644
index 00000000..3d31ef9a
--- /dev/null
+++ b/ext/xine/xineaudiodec.c
@@ -0,0 +1,556 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * 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.
+ */
+
+#include <gst/gst.h>
+#include "gstxine.h"
+#include <xine/xine_internal.h>
+#include <xine/plugin_catalog.h>
+
+#define GST_TYPE_XINE_AUDIO_DEC \
+ (gst_xine_audio_dec_get_type())
+#define GST_XINE_AUDIO_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XINE_AUDIO_DEC,GstXineAudioDec))
+#define GST_XINE_AUDIO_DEC_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XINE_AUDIO_DEC, GstXineAudioDecClass))
+#define GST_XINE_AUDIO_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XINE_AUDIO_DEC,GstXineAudioDecClass))
+#define GST_IS_XINE_AUDIO_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XINE_AUDIO_DEC))
+#define GST_IS_XINE_AUDIO_DEC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XINE_AUDIO_DEC))
+
+GType gst_xine_audio_dec_get_type (void);
+
+typedef struct _GstXineAudioDec GstXineAudioDec;
+typedef struct _GstXineAudioDecClass GstXineAudioDecClass;
+
+struct _GstXineAudioDec
+{
+ GstXine parent;
+
+ GstPad * sinkpad;
+ GstPad * srcpad;
+
+ audio_decoder_t * decoder;
+ guint32 format;
+ xine_waveformatex wave;
+ gboolean setup;
+};
+
+struct _GstXineAudioDecClass
+{
+ GstXineClass parent_class;
+
+ plugin_node_t * plugin_node;
+};
+
+/*** xine audio driver wrapper ************************************************/
+
+typedef struct {
+ xine_ao_driver_t driver;
+ GstXineAudioDec * xine;
+ gboolean open;
+} GstXineAudioDriver;
+
+static guint32
+_driver_get_capabilities (xine_ao_driver_t *driver)
+{
+ /* FIXME: add more when gst handles more than 2 channels */
+ return AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_8BITS;
+}
+
+static gint
+_driver_get_property (xine_ao_driver_t *driver, int property)
+{
+ return 0;
+}
+
+static gint
+_driver_set_property (xine_ao_driver_t * driver, int property, int value)
+{
+ return ~value;
+}
+
+static gint
+_driver_open (xine_ao_driver_t *driver, xine_stream_t *stream, guint32 bits, guint32 rate, int mode)
+{
+ GstCaps *caps;
+ GstXineAudioDriver *xine = ((GstXineAudioDriver *) driver);
+
+ caps = gst_caps_new_simple ("audio/x-raw-int",
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "width", G_TYPE_INT, (gint) bits,
+ "depth", G_TYPE_INT, (gint) bits,
+ "signed", G_TYPE_BOOLEAN, (bits == 8) ? FALSE : TRUE,
+ "channels", G_TYPE_INT, (mode | AO_CAP_MODE_STEREO) ? 2 : 1,
+ "rate", G_TYPE_INT, rate,
+ NULL);
+
+ if (!gst_pad_set_explicit_caps (xine->xine->srcpad, caps)) {
+ gst_caps_free (caps);
+ driver->open = FALSE;
+ return -1;
+ }
+
+ xine->open = TRUE;
+ gst_caps_free (caps);
+ return rate;
+}
+
+static void
+_driver_close (xine_ao_driver_t *driver, xine_stream_t *stream)
+{
+ /* FIXME: unset explicit caps here? And how? */
+ driver->open = FALSE;
+}
+
+static void
+_driver_exit (xine_ao_driver_t *driver)
+{
+ g_free (driver);
+}
+
+static int
+_driver_control (xine_ao_driver_t *driver, int cmd, ...)
+{
+ return 0;
+}
+
+static void
+_driver_flush (xine_ao_driver_t *driver)
+{
+}
+
+static int
+_driver_status (xine_ao_driver_t *driver, xine_stream_t *stream, uint32_t *bits, uint32_t *rate, int *mode)
+{
+ const GstCaps *caps;
+ GstStructure *structure;
+ gint temp;
+ GstXineAudioDriver *xine = (GstXineAudioDriver *) driver;
+
+ if (xine->open == FALSE || !(caps = gst_pad_get_negotiated_caps (xine->xine->srcpad)))
+ return 0;
+
+ structure = gst_caps_get_structure (caps, 0);
+ *bits = 0; /* FIXME */
+ if (!gst_structure_get_int (structure, "rate", &temp)) {
+ g_assert_not_reached (); /* may never happen with negotiated caps */
+ return 0;
+ }
+ *rate = temp;
+ if (!gst_structure_get_int (structure, "channels", &temp)) {
+ g_assert_not_reached (); /* may never happen with negotiated caps */
+ return 0;
+ }
+ *mode = (temp == 2) ? AO_CAP_MODE_STEREO : AO_CAP_MODE_MONO;
+ if (!gst_structure_get_int (structure, "width", &temp)) {
+ g_assert_not_reached (); /* may never happen with negotiated caps */
+ return 0;
+ }
+ if (temp == 8)
+ *mode |= AO_CAP_8BITS;
+
+ return 1;
+}
+
+#define _DRIVER_BUFFER_SIZE 4096
+static audio_buffer_t *
+_driver_get_buffer (xine_ao_driver_t *driver)
+{
+ GstXineAudioDriver *xine = (GstXineAudioDriver *) driver;
+ audio_buffer_t *audio = g_new0 (audio_buffer_t, 1);
+
+ audio->mem = g_malloc (_DRIVER_BUFFER_SIZE);
+ audio->mem_size = _DRIVER_BUFFER_SIZE;
+ audio->stream = gst_xine_get_stream (GST_XINE (xine->xine));
+ /* FIXME: fill more fields */
+
+ return audio;
+}
+
+static void
+_driver_put_buffer (xine_ao_driver_t *driver, audio_buffer_t *audio, xine_stream_t *stream)
+{
+ GstXineAudioDriver *xine = (GstXineAudioDriver *) driver;
+ GstBuffer *buffer;
+
+ buffer = gst_buffer_new ();
+ GST_BUFFER_DATA (buffer) = (guint8 *) audio->mem;
+ GST_BUFFER_SIZE (buffer) = audio->mem_size;
+ GST_BUFFER_MAXSIZE (buffer) = audio->mem_size;
+ /* FIXME: fill more fields */
+ g_free (audio);
+ gst_pad_push (xine->xine->srcpad, GST_DATA (buffer));
+}
+
+static xine_ao_driver_t *
+_gst_xine_audio_dec_create_audio_driver (GstXine *xine)
+{
+ GstXineAudioDriver *driver = g_new (GstXineAudioDriver, 1);
+
+ driver->xine = GST_XINE_AUDIO_DEC (xine);
+ driver->open = FALSE;
+
+ driver->driver.get_buffer = _driver_get_buffer;
+ driver->driver.put_buffer = _driver_put_buffer;
+ driver->driver.get_capabilities = _driver_get_capabilities;
+ driver->driver.get_property = _driver_get_property;
+ driver->driver.set_property = _driver_set_property;
+ driver->driver.open = _driver_open;
+ driver->driver.close = _driver_close;
+ driver->driver.exit = _driver_exit;
+ driver->driver.control = _driver_control;
+ driver->driver.flush = _driver_flush;
+ driver->driver.status = _driver_status;
+
+ return (xine_ao_driver_t *) driver;
+}
+
+/** GstXineAudioDec ***********************************************************/
+
+GST_BOILERPLATE (GstXineAudioDec, gst_xine_audio_dec, GstXine, GST_TYPE_XINE)
+
+static void gst_xine_audio_dec_chain (GstPad *pad, GstData *in);
+static GstElementStateReturn
+ gst_xine_audio_dec_change_state (GstElement *element);
+
+/* this function handles the link with other plug-ins */
+static GstPadLinkReturn
+gst_xine_audio_dec_sink_link (GstPad *pad, const GstCaps *caps)
+{
+ guint temp;
+ GstStructure *structure;
+ GstXineAudioDec *xine = GST_XINE_AUDIO_DEC (gst_object_get_parent (GST_OBJECT (pad)));
+
+ xine->format = gst_xine_get_format_for_caps (caps);
+ if (xine->format == 0) return GST_PAD_LINK_REFUSED;
+
+ /* get setup data */
+ xine->setup = FALSE;
+ structure = gst_caps_get_structure (caps, 0);
+ if (gst_structure_get_int (structure, "channels", &temp))
+ xine->wave.nChannels = temp;
+ if (gst_structure_get_int (structure, "rate", &temp))
+ xine->wave.nSamplesPerSec = temp;
+ xine->wave.wBitsPerSample = 16; /* FIXME: how do we figure this thing out? */
+ /* FIXME: fill wave header better */
+
+ return GST_PAD_LINK_OK;
+}
+
+static void
+gst_xine_audio_dec_base_init (gpointer g_class)
+{
+}
+
+static void
+gst_xine_audio_dec_class_init (GstXineAudioDecClass *klass)
+{
+ GstXineClass *xine = GST_XINE_CLASS (klass);
+ GstElementClass *element = GST_ELEMENT_CLASS (klass);
+
+ element->change_state = gst_xine_audio_dec_change_state;
+
+ xine->create_audio_driver = _gst_xine_audio_dec_create_audio_driver;
+}
+
+static void
+gst_xine_audio_dec_init (GstXineAudioDec *xine)
+{
+ xine->setup = FALSE;
+}
+
+static void
+gst_xine_audio_dec_event (GstXineAudioDec *xine, GstEvent *event)
+{
+ gst_pad_event_default (xine->sinkpad, event);
+}
+
+static void
+gst_xine_audio_dec_chain (GstPad *pad, GstData *in)
+{
+ G_GNUC_UNUSED buf_element_t buffer = { 0, };
+ GstXineAudioDec *xine = GST_XINE_AUDIO_DEC (gst_object_get_parent (GST_OBJECT (pad)));
+
+ if (GST_IS_EVENT (in)) {
+ gst_xine_audio_dec_event (xine, GST_EVENT (in));
+ return;
+ }
+
+ if (xine->format == 0) {
+ /* no caps yet */
+ GST_ELEMENT_ERROR (xine, CORE, NEGOTIATION, (NULL), ("buffer sent before doing caps nego"));
+ gst_data_unref (in);
+ return;
+ }
+
+ if (!xine->setup) {
+ buf_element_t element = { 0, };
+ guint8 stsd[150] = { 0, };
+ guint temp;
+ GstStructure *structure;
+ /* sent setup header */
+ element.type = xine->format;
+ element.decoder_flags = BUF_FLAG_HEADER;
+ element.decoder_info[0] = 0;
+ element.decoder_info[1] = xine->wave.nSamplesPerSec;
+ element.decoder_info[2] = xine->wave.wBitsPerSample;
+ element.decoder_info[3] = xine->wave.nChannels;
+ element.content = (guchar *) &xine->wave;
+ element.size = sizeof (xine_waveformatex);
+ xine->decoder->decode_data (xine->decoder, &element);
+ /* send stsd emulation to the decoder */
+ /* FIXME: qdm2 only right now */
+ g_assert (gst_pad_get_negotiated_caps (xine->sinkpad));
+ structure = gst_caps_get_structure (gst_pad_get_negotiated_caps (xine->sinkpad), 0);
+ *((guint32 *) &stsd[56]) = GUINT32_TO_BE (12);
+ memcpy (&stsd[60], "frmaQDM2", 8);
+ *((guint32 *) &stsd[68]) = GUINT32_TO_BE (36);
+ memcpy (&stsd[72], "QDCA", 4);
+ *((guint32 *) &stsd[76]) = GUINT32_TO_BE (1);
+ if (!gst_structure_get_int (structure, "channels", &temp))
+ temp = 0;
+ *((guint32 *) &stsd[80]) = GUINT32_TO_BE (temp);
+ if (!gst_structure_get_int (structure, "rate", &temp))
+ temp = 0;
+ *((guint32 *) &stsd[84]) = GUINT32_TO_BE (temp);
+ if (!gst_structure_get_int (structure, "bitrate", &temp))
+ temp = 0;
+ *((guint32 *) &stsd[88]) = GUINT32_TO_BE (temp);
+ if (!gst_structure_get_int (structure, "blocksize", &temp))
+ temp = 0;
+ *((guint32 *) &stsd[92]) = GUINT32_TO_BE (temp);
+ *((guint32 *) &stsd[96]) = GUINT32_TO_BE (256);
+ if (!gst_structure_get_int (structure, "framesize", &temp))
+ temp = 0;
+ *((guint32 *) &stsd[100]) = GUINT32_TO_BE (temp);
+ *((guint32 *) &stsd[104]) = GUINT32_TO_BE (28);
+ memcpy (&stsd[108], "QDCP", 4);
+ *((guint32 *) &stsd[112]) = GUINT32_TO_BE (1065353216);
+ *((guint32 *) &stsd[116]) = GUINT32_TO_BE (0);
+ *((guint32 *) &stsd[120]) = GUINT32_TO_BE (1065353216);
+ *((guint32 *) &stsd[124]) = GUINT32_TO_BE (1065353216);
+ *((guint32 *) &stsd[128]) = GUINT32_TO_BE (27);
+ *((guint32 *) &stsd[132]) = GUINT32_TO_BE (8);
+ *((guint32 *) &stsd[136]) = GUINT32_TO_BE (0);
+ *((guint32 *) &stsd[140]) = GUINT32_TO_BE (24);
+ gst_util_dump_mem (stsd, 144);
+ element.decoder_flags = BUF_FLAG_SPECIAL;
+ element.decoder_info[1] = BUF_SPECIAL_STSD_ATOM;
+ element.decoder_info[2] = 144;
+ element.decoder_info[3] = 0;
+ element.decoder_info_ptr[2] = stsd;
+ element.size = 0;
+ element.content = 0;
+ xine->decoder->decode_data (xine->decoder, &element);
+
+ xine->setup = TRUE;
+ }
+
+ gst_buffer_to_xine_buffer (&buffer, GST_BUFFER (in));
+ buffer.type = xine->format;
+ xine->decoder->decode_data (xine->decoder, &buffer);
+ gst_data_unref (in);
+}
+
+static audio_decoder_t *
+_load_decoder (GstXineAudioDec* dec)
+{
+ xine_stream_t *stream = gst_xine_get_stream (GST_XINE (dec));
+ plugin_catalog_t *catalog = stream->xine->plugin_catalog;
+ plugin_node_t *node = GST_XINE_AUDIO_DEC_GET_CLASS (dec)->plugin_node;
+ audio_decoder_t *ret;
+
+ /* FIXME: this is really hacky, but how to force xine to load a plugin? */
+ /* how it works: xine can load a plugin for a particular stream type.
+ * We just take one type, which should not have plugins attached to it,
+ * attach our plugin and load it */
+ g_assert (catalog->audio_decoder_map[DECODER_MAX - 1][0] == NULL);
+ catalog->audio_decoder_map[DECODER_MAX - 1][0] = node;
+ ret = _x_get_audio_decoder (stream, DECODER_MAX - 1);
+ catalog->audio_decoder_map[DECODER_MAX - 1][0] = NULL;
+
+ return ret;
+}
+
+static GstElementStateReturn
+gst_xine_audio_dec_change_state (GstElement *element)
+{
+ GstXineAudioDec *xine = GST_XINE_AUDIO_DEC (element);
+
+ switch (GST_STATE_TRANSITION (element)) {
+ case GST_STATE_NULL_TO_READY:
+ xine->decoder = _load_decoder (xine);
+ if (!xine->decoder)
+ return GST_STATE_FAILURE;
+ break;
+ case GST_STATE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_PAUSED_TO_PLAYING:
+ break;
+ case GST_STATE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_PAUSED_TO_READY:
+ break;
+ case GST_STATE_READY_TO_NULL:
+ xine->setup = FALSE;
+ _x_free_audio_decoder (gst_xine_get_stream (GST_XINE (xine)), xine->decoder);
+ break;
+ default:
+ GST_ERROR_OBJECT (element, "invalid state change");
+ break;
+ }
+
+ return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, (element), GST_STATE_SUCCESS);
+}
+
+/** GstXineAudioDec subclasses ************************************************/
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (
+ "audio/x-raw-int, "
+ "endianness = (int) BYTE_ORDER, "
+ "signed = (boolean) TRUE, "
+ "width = (int) 16, "
+ "depth = (int) 16, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 2 ]; "
+ "audio/x-raw-int, "
+ "signed = (boolean) FALSE, "
+ "width = (int) 8, "
+ "depth = (int) 8, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 2 ]"
+ )
+);
+
+static void
+gst_xine_audio_dec_subclass_init (gpointer g_class, gpointer class_data)
+{
+ GstXineAudioDecClass *xine_class = GST_XINE_AUDIO_DEC_CLASS (g_class);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstElementDetails details = GST_ELEMENT_DETAILS (
+ NULL,
+ "Filter/Decoder/Audio",
+ NULL,
+ "Benjamin Otte <otte@gnome.org>"
+ );
+ GstPadTemplate *template;
+ guint i = 0;
+ GstCaps *caps = gst_caps_new_empty ();
+ decoder_info_t *dec;
+
+ xine_class->plugin_node = class_data;
+ dec = xine_class->plugin_node->info->special_info;
+ details.longname = g_strdup_printf ("%s xine audio decoder", xine_class->plugin_node->info->id);
+ details.description = g_strdup_printf ("decodes audio using the xine '%s' plugin", xine_class->plugin_node->info->id);
+ gst_element_class_set_details (element_class, &details);
+ g_free (details.longname);
+ g_free (details.description);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_template));
+
+ while (dec->supported_types[i] != 0) {
+ const gchar *type_str = gst_xine_get_caps_for_format (dec->supported_types[i]);
+ if (type_str) {
+ gst_caps_append (caps, gst_caps_from_string (type_str));
+ }
+ i++;
+ }
+ template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
+ gst_element_class_add_pad_template (element_class, template);
+}
+
+static void
+gst_xine_audio_dec_sub_init (GTypeInstance *instance, gpointer g_class)
+{
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (instance);
+ GstXineAudioDec *xine = GST_XINE_AUDIO_DEC (instance);
+
+ xine->sinkpad = gst_pad_new_from_template (
+ gst_element_class_get_pad_template (klass, "sink"), "sink");
+ gst_pad_set_link_function (xine->sinkpad, gst_xine_audio_dec_sink_link);
+ gst_pad_set_chain_function (xine->sinkpad, gst_xine_audio_dec_chain);
+ gst_element_add_pad (GST_ELEMENT (xine), xine->sinkpad);
+
+ xine->srcpad = gst_pad_new_from_template (
+ gst_element_class_get_pad_template (klass, "src"), "src");
+ gst_pad_use_explicit_caps (xine->srcpad);
+ gst_element_add_pad (GST_ELEMENT (xine), xine->srcpad);
+}
+
+gboolean
+gst_xine_audio_dec_init_plugin (GstPlugin *plugin)
+{
+ GTypeInfo plugin_info =
+ {
+ sizeof (GstXineAudioDecClass),
+ NULL,
+ NULL,
+ gst_xine_audio_dec_subclass_init,
+ NULL,
+ NULL,
+ sizeof (GstXineAudioDec),
+ 0,
+ gst_xine_audio_dec_sub_init,
+ };
+ xine_node_t *list;
+ GstXineClass *klass;
+
+ klass = g_type_class_ref (GST_TYPE_XINE);
+
+ list = klass->xine->plugin_catalog->audio->first;
+ while (list) {
+ plugin_node_t *node = list->content;
+ decoder_info_t *dec;
+ guint format = 0;
+
+ list = list->next;
+ if (!node) continue;
+
+ dec = node->info->special_info;
+ while (dec->supported_types[format] != 0) {
+ const gchar *caps = gst_xine_get_caps_for_format (dec->supported_types[format]);
+ if (caps) {
+ gchar *plugin_name = g_strdup_printf ("xineaudiodec_%s", node->info->id);
+ gchar *type_name = g_strdup_printf ("GstXineAudioDec%s", node->info->id);
+ GType type;
+ plugin_info.class_data = node;
+ type = g_type_register_static (GST_TYPE_XINE_AUDIO_DEC, type_name, &plugin_info, 0);
+ g_free (type_name);
+ if (!gst_element_register (plugin, plugin_name,
+ MAX (GST_RANK_MARGINAL, GST_RANK_MARGINAL * dec->priority / 10 + 1), type)) {
+ g_free (plugin_name);
+ return FALSE;
+ }
+ g_free (plugin_name);
+ }
+ format++;
+ }
+ }
+
+ g_type_class_unref (klass);
+ return TRUE;
+}
+
diff --git a/ext/xine/xinecaps.c b/ext/xine/xinecaps.c
new file mode 100644
index 00000000..d243f72f
--- /dev/null
+++ b/ext/xine/xinecaps.c
@@ -0,0 +1,119 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * 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.
+ */
+
+#include "gstxine.h"
+#include <xine/buffer.h>
+
+typedef struct {
+ guint32 xine;
+ gchar * caps;
+} GstXineCapsMap;
+
+static GstXineCapsMap _gst_xine_caps_map[] = {
+ { BUF_AUDIO_QDESIGN2, "audio/x-qdm2" },
+/* FIXME:
+#define BUF_AUDIO_A52 0x03000000
+#define BUF_AUDIO_MPEG 0x03010000
+#define BUF_AUDIO_LPCM_BE 0x03020000
+#define BUF_AUDIO_LPCM_LE 0x03030000
+#define BUF_AUDIO_WMAV1 0x03040000
+#define BUF_AUDIO_DTS 0x03050000
+#define BUF_AUDIO_MSADPCM 0x03060000
+#define BUF_AUDIO_MSIMAADPCM 0x03070000
+#define BUF_AUDIO_MSGSM 0x03080000
+#define BUF_AUDIO_VORBIS 0x03090000
+#define BUF_AUDIO_IMC 0x030a0000
+#define BUF_AUDIO_LH 0x030b0000
+#define BUF_AUDIO_VOXWARE 0x030c0000
+#define BUF_AUDIO_ACELPNET 0x030d0000
+#define BUF_AUDIO_AAC 0x030e0000
+#define BUF_AUDIO_DNET 0x030f0000
+#define BUF_AUDIO_VIVOG723 0x03100000
+#define BUF_AUDIO_DK3ADPCM 0x03110000
+#define BUF_AUDIO_DK4ADPCM 0x03120000
+#define BUF_AUDIO_ROQ 0x03130000
+#define BUF_AUDIO_QTIMAADPCM 0x03140000
+#define BUF_AUDIO_MAC3 0x03150000
+#define BUF_AUDIO_MAC6 0x03160000
+#define BUF_AUDIO_QDESIGN1 0x03170000
+#define BUF_AUDIO_QDESIGN2 0x03180000
+#define BUF_AUDIO_QCLP 0x03190000
+#define BUF_AUDIO_SMJPEG_IMA 0x031A0000
+#define BUF_AUDIO_VQA_IMA 0x031B0000
+#define BUF_AUDIO_MULAW 0x031C0000
+#define BUF_AUDIO_ALAW 0x031D0000
+#define BUF_AUDIO_GSM610 0x031E0000
+#define BUF_AUDIO_EA_ADPCM 0x031F0000
+#define BUF_AUDIO_WMAV2 0x03200000
+#define BUF_AUDIO_COOK 0x03210000
+#define BUF_AUDIO_ATRK 0x03220000
+#define BUF_AUDIO_14_4 0x03230000
+#define BUF_AUDIO_28_8 0x03240000
+#define BUF_AUDIO_SIPRO 0x03250000
+#define BUF_AUDIO_WMAV3 0x03260000
+#define BUF_AUDIO_INTERPLAY 0x03270000
+#define BUF_AUDIO_XA_ADPCM 0x03280000
+#define BUF_AUDIO_WESTWOOD 0x03290000
+#define BUF_AUDIO_DIALOGIC_IMA 0x032A0000
+#define BUF_AUDIO_NSF 0x032B0000
+#define BUF_AUDIO_FLAC 0x032C0000
+#define BUF_AUDIO_DV 0x032D0000
+#define BUF_AUDIO_WMAV 0x032E0000
+#define BUF_AUDIO_SPEEX 0x032F0000
+#define BUF_AUDIO_RAWPCM 0x03300000
+#define BUF_AUDIO_4X_ADPCM 0x03310000
+*/
+ { 0, NULL }
+};
+
+const gchar *
+gst_xine_get_caps_for_format (guint32 format)
+{
+ guint i = 0;
+
+ while (_gst_xine_caps_map[i].xine != 0) {
+ if (_gst_xine_caps_map[i].xine == format)
+ return _gst_xine_caps_map[i].caps;
+ i++;
+ }
+
+ return NULL;
+}
+
+guint32
+gst_xine_get_format_for_caps (const GstCaps *caps)
+{
+ guint i = 0;
+ GstCaps *compare, *intersect;
+
+ while (_gst_xine_caps_map[i].xine != 0) {
+ compare = gst_caps_from_string (_gst_xine_caps_map[i].caps);
+ intersect = gst_caps_intersect (caps, compare);
+ gst_caps_free (compare);
+ if (!gst_caps_is_empty (intersect)) {
+ gst_caps_free (intersect);
+ return _gst_xine_caps_map[i].xine;
+ }
+ gst_caps_free (intersect);
+ i++;
+ }
+
+ return 0;
+}
+
diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c
index 96c1b4f6..7cb84f1e 100644
--- a/gst/qtdemux/qtdemux.c
+++ b/gst/qtdemux/qtdemux.c
@@ -153,7 +153,7 @@ static QtNodeType *qtdemux_type_get(guint32 fourcc);
static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node);
static void qtdemux_parse_tree(GstQTDemux *qtdemux);
static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *stsd_data);
-static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc);
+static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *data);
static GType gst_qtdemux_get_type (void)
{
@@ -284,7 +284,7 @@ static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux)
gst_pad_event_default(qtdemux->sinkpad, event);
return FALSE;
case GST_EVENT_FLUSH:
- g_warning("flush event");
+ //g_warning("flush event");
break;
case GST_EVENT_DISCONTINUOUS:
GST_DEBUG ("discontinuous event\n");
@@ -780,15 +780,15 @@ static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int le
QtNodeType *type;
void *end;
- //g_print("qtdemux_parse %p %d\n",buffer, length);
+ g_print("qtdemux_parse %p %d\n",buffer, length);
node_length = QTDEMUX_GUINT32_GET(buffer);
fourcc = QTDEMUX_FOURCC_GET(buffer+4);
type = qtdemux_type_get(fourcc);
- /*g_print("parsing '" GST_FOURCC_FORMAT "', length=%d\n",
- GST_FOURCC_ARGS(fourcc), node_length);*/
+ g_print("parsing '" GST_FOURCC_FORMAT "', length=%d\n",
+ GST_FOURCC_ARGS(fourcc), node_length);
if(type->flags & QT_CONTAINER){
void *buf;
@@ -1301,20 +1301,22 @@ static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak)
g_print("sample rate: %g\n", QTDEMUX_FP32_GET(stsd->data+offset + 16));
stream->rate = QTDEMUX_FP32_GET(stsd->data+offset + 16);
+ offset = 52;
if(version == 0x00010000){
- g_print("samples/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 20));
- stream->samples_per_packet = QTDEMUX_GUINT32_GET(stsd->data+offset + 20);
- g_print("bytes/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 24));
- g_print("bytes/frame: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 28));
- stream->bytes_per_frame = QTDEMUX_GUINT32_GET(stsd->data+offset + 28);
- g_print("bytes/sample: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 32));
+ g_print("samples/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset));
+ stream->samples_per_packet = QTDEMUX_GUINT32_GET(stsd->data+offset);
+ g_print("bytes/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 4));
+ g_print("bytes/frame: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 8));
+ stream->bytes_per_frame = QTDEMUX_GUINT32_GET(stsd->data+offset + 8);
+ g_print("bytes/sample: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 12));
+ offset = 68;
} else {
stream->bytes_per_frame = stream->n_channels * QTDEMUX_GUINT16_GET(stsd->data+offset + 10);
stream->samples_per_packet = 1;
}
stream->caps = qtdemux_audio_caps(qtdemux,
- QTDEMUX_FOURCC_GET(stsd->data+16+4));
+ QTDEMUX_FOURCC_GET(stsd->data+16+4), (QTDEMUX_GUINT32_GET(stsd->data) > offset) ? stsd->data + offset : NULL);
g_print("caps %s\n",gst_caps_to_string(stream->caps));
}else{
g_print("unknown subtype\n");
@@ -1597,7 +1599,7 @@ static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc, const gu
}
}
-static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc)
+static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *data)
{
switch(fourcc){
case GST_MAKE_FOURCC('N','O','N','E'):
@@ -1685,8 +1687,15 @@ static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc)
return gst_caps_from_string ("audio/mpeg, "
"mpegversion = (int) 4");
case GST_MAKE_FOURCC('Q','D','M','2'):
- /* QDesign music version 2 (no constant) */
- return gst_caps_from_string ("audio/x-qdm2");
+ /* FIXME: QDesign music version 2 (no constant) */
+ if (QTDEMUX_GUINT32_GET (data) <= 100) {
+ gst_util_dump_mem ((guint8*)data, 100);
+ return gst_caps_new_simple ("audio/x-qdm2",
+ "framesize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 52),
+ "bitrate", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 40),
+ "blocksize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 44),
+ NULL);
+ }
case GST_MAKE_FOURCC('q','t','v','r'):
/* ? */
case GST_MAKE_FOURCC('Q','D','M','C'):