summaryrefslogtreecommitdiff
path: root/native
diff options
context:
space:
mode:
authorMario Torre <neugens@limasoftware.net>2007-07-09 16:32:20 +0000
committerMario Torre <neugens@limasoftware.net>2007-07-09 16:32:20 +0000
commit9afb84648bf4fc9cfa9dd2ee4dd5937a71338e4d (patch)
tree82b0e55156d12b1b8e5d816975ac3687b9967d02 /native
parentde78d5b68527b0c5028826b5a4e98790be2b6fd9 (diff)
downloadclasspath-9afb84648bf4fc9cfa9dd2ee4dd5937a71338e4d.tar.gz
2007-07-08 Mario Torre <neugens@limasoftware.net>
* gnu/javax/sound/sampled/gstreamer: new package hierarchy. * gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java: new file. * gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java: likewise. * gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java: likewise. * gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java: likewise. * gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java: likewise. * gnu/javax/sound/AudioSecurityManager.java: likewise. * gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java: likewise. * gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java: likewise. * gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java: likewise. * gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java: likewise. * resource/META-INF/services/javax.sound.sampled.spi.AudioFileReader.in: likewise. * resource/META-INF/services/javax.sound.sampled.spi.MixerProvider.in: likewise. * resource/META-INF/services/javax.sound.sampled.spi.MixerProvider: likewise. * native/jni/gstreamer-peer/gstclasspathsrc.c: likewise. * native/jni/gstreamer-peer/gstclasspathsrc.h: likewise. * native/jni/gstreamer-peer/gstinputstream.c: likewise. * native/jni/gstreamer-peer/gstinputstream.h: likewise. * native/jni/gstreamer-peer/GStreamerIOPeer.c: likewise. * native/jni/gstreamer-peer/Makefile.am: likewise. * native/jni/gstreamer-peer/.cvsignore: likewise. * include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h: likewise. * include/Makefile.am: add gstreamer generated headers. * configure.ac: add gstreamer sound backend configuration. The backend is currently disabled by default. * native/jni/Makefile.am: code to allow compilation of the gstreamer sound backend. * javax/sound/sampled/spi/MixerProvider.java (isMixerSupported): indentation fixes. * javax/sound/sampled/AudioFormat.java (toString): fix method to display informations only when available. * javax/sound/sampled/DataLine.java: (Info.isFormatSupported): indentation fixes. (Info): indentation fixes. (Info.toString): indentation fixes. (Info.matches): indentation fixes.
Diffstat (limited to 'native')
-rw-r--r--native/jni/Makefile.am10
-rw-r--r--native/jni/gstreamer-peer/.cvsignore7
-rw-r--r--native/jni/gstreamer-peer/GStreamerIOPeer.c772
-rw-r--r--native/jni/gstreamer-peer/Makefile.am22
-rw-r--r--native/jni/gstreamer-peer/gstclasspathsrc.c332
-rw-r--r--native/jni/gstreamer-peer/gstclasspathsrc.h88
-rw-r--r--native/jni/gstreamer-peer/gstinputstream.c494
-rw-r--r--native/jni/gstreamer-peer/gstinputstream.h99
8 files changed, 1821 insertions, 3 deletions
diff --git a/native/jni/Makefile.am b/native/jni/Makefile.am
index 110540799..b820fe745 100644
--- a/native/jni/Makefile.am
+++ b/native/jni/Makefile.am
@@ -24,16 +24,20 @@ if CREATE_GCONF_PEER_LIBRARIES
CLASSPATH_GCONF_PEER_DIR = gconf-peer
endif
+if CREATE_GSTREAMER_PEER_LIBRARIES
+ CLASSPATH_GSTREAMER_PEER_DIR = gstreamer-peer
+endif
+
if CREATE_XMLJ_LIBRARY
XMLJDIR = xmlj
endif
SUBDIRS = classpath $(JNIDIRS) \
$(ALSADIR) $(DSSIDIR) $(GTKDIR) $(CLASSPATH_QT_PEER_DIR) $(XMLJDIR) \
- $(CLASSPATH_GCONF_PEER_DIR)
+ $(CLASSPATH_GCONF_PEER_DIR) $(CLASSPATH_GSTREAMER_PEER_DIR)
DIST_SUBDIRS = classpath java-io java-lang java-net java-nio java-util \
- gtk-peer gconf-peer qt-peer xmlj midi-alsa midi-dssi \
- native-lib
+ gtk-peer gconf-peer gstreamer-peer qt-peer xmlj midi-alsa \
+ midi-dssi native-lib
all-local:
cd $(top_srcdir) && $(SHELL) ./scripts/check_jni_methods.sh
diff --git a/native/jni/gstreamer-peer/.cvsignore b/native/jni/gstreamer-peer/.cvsignore
new file mode 100644
index 000000000..ba5a55c67
--- /dev/null
+++ b/native/jni/gstreamer-peer/.cvsignore
@@ -0,0 +1,7 @@
+.deps
+.libs
+*.lo
+*.la
+Makefile
+Makefile.in
+
diff --git a/native/jni/gstreamer-peer/GStreamerIOPeer.c b/native/jni/gstreamer-peer/GStreamerIOPeer.c
new file mode 100644
index 000000000..f5d52e8a4
--- /dev/null
+++ b/native/jni/gstreamer-peer/GStreamerIOPeer.c
@@ -0,0 +1,772 @@
+/* GStreamerIOPeer.c -- Implements native methods for class GStreamerNativePeer
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <jni.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include <gdk/gdk.h>
+
+#include <gst/gst.h>
+
+#include "jcl.h"
+
+#include "gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h"
+
+#include "gstclasspathsrc.h"
+#include "gstinputstream.h"
+
+#define _GST_MALLOC_SIZE_ 256
+
+typedef struct _AudioProperties AudioProperties;
+struct _AudioProperties
+{
+ /*
+ * NOTE: descriptions of the properties are taken from:
+ * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/section-types-definitions.html#table-audio-types
+ */
+
+ /* decoder name */
+ const char *name;
+
+ /* audio endiannes */
+ const char *endianness;
+
+ /* header size */
+ const char *header_size;
+
+ /* mime */
+ const char *mimetype;
+
+ /* The sample rate of the data, in samples (per channel) per second */
+ const char *samplerate;
+
+ /* The number of channels of audio data */
+ const char *channels;
+
+ const char *layer;
+
+ const char *bitrate;
+
+ const char *framed;
+
+ /*
+ * Defines if the values of the integer samples are signed or not.
+ * Signed samples use one bit to indicate sign (negative or positive)
+ * of the value. Unsigned samples are always positive.
+ */
+ const char *signess;
+
+ /* */
+ const char *rate;
+
+ /* Number of bits allocated per sample. */
+ const char *width;
+
+ /*
+ * The number of bits used per sample.
+ * If the depth is less than the width, the low bits are assumed to be the
+ * ones used. For example, a width of 32 and a depth of 24 means that
+ * each sample is stored in a 32 bit word, but only the low
+ * 24 bits are actually used.
+ */
+ const char *depth;
+
+ /*
+ * This is set in the case of the mpeg files.
+ */
+ const char *type;
+
+ gboolean done;
+
+};
+
+/* ***** PRIVATE FUNCTIONS DECLARATION ***** */
+
+static gboolean
+set_strings (JNIEnv *env, const jclass GstHeader,
+ const AudioProperties *properties, jobject header);
+
+static gboolean
+typefind_callback(GstElement *typefind, guint probability, const GstCaps *caps,
+ gpointer data);
+
+static void
+element_added (GstBin *bin, GstElement *element, gpointer data);
+
+static void
+new_decoded_pad (GstElement *decoder, GstPad *pad,
+ gboolean last, GstElement *pipeline);
+
+static gboolean
+fill_info (GstElement *decoder, AudioProperties *properties);
+
+static gchar *
+get_string_property (const GstStructure *structure, const gchar *property);
+
+static gchar *
+get_boolean_property (const GstStructure *structure, const gchar *property);
+
+static gboolean
+set_string (JNIEnv *env, const jclass GstHeader, jobject header,
+ const char *field, const gchar *property);
+
+static void
+free_properties (AudioProperties *properties);
+
+static void
+reset_properties (AudioProperties *properties);
+
+/* ***** END: PRIVATE FUNCTIONS DECLARATION ***** */
+
+/* ***** NATIVE FUNCTIONS ***** */
+
+JNIEXPORT jboolean JNICALL
+Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1stream
+ (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject header __attribute__ ((unused)),
+ jobject jstream __attribute__ ((unused)))
+{
+ GstInputStream *istream = NULL;
+ JavaVM *vm = NULL;
+ jclass GstHeader = NULL;
+
+ GstElement *pipeline = NULL;
+
+ GstElement *typefind = NULL;
+ GstElement *decodebin = NULL;
+ GstElement *source = NULL;
+
+ AudioProperties *properties = NULL;
+
+ jboolean result = JNI_FALSE;
+
+ GstHeader = (*env)->GetObjectClass(env, header);
+
+ gst_init (NULL, NULL);
+
+ properties = (AudioProperties *) g_malloc0 (sizeof (AudioProperties));
+ if (properties == NULL)
+ {
+ g_warning ("unable to allocate memory for properties");
+ return JNI_FALSE;
+ }
+
+ /* create the GstInputStream object */
+ istream = g_object_new (GST_TYPE_INPUT_STREAM, NULL);
+ if (istream == NULL)
+ {
+ free_properties (properties);
+
+ g_warning ("unable to create an istream");
+ return JNI_FALSE;
+ }
+
+ source = gst_element_factory_make ("classpathsrc", "source");
+ if (source == NULL)
+ {
+ free_properties (properties);
+ g_free ((gpointer) istream);
+
+ g_warning ("unable to create a source");
+ return JNI_FALSE;
+ }
+
+ /* store the vm and the input stream in the gstinputstream class */
+ (*env)->GetJavaVM(env, &vm);
+ g_object_set (G_OBJECT (istream), GST_ISTREAM_JVM, vm,
+ GST_ISTREAM_READER, jstream,
+ NULL);
+ g_object_set (G_OBJECT (source), GST_CLASSPATH_SRC_ISTREAM, istream, NULL);
+
+ pipeline = gst_pipeline_new ("pipe");
+ if (pipeline == NULL)
+ {
+ gst_object_unref (GST_OBJECT (source));
+ g_free ((gpointer) istream);
+ free_properties (properties);
+
+ g_warning ("unable to create the pipeline");
+ return JNI_FALSE;
+ }
+
+ decodebin = gst_element_factory_make ("decodebin", "decodebin");
+ if (decodebin == NULL)
+ {
+ gst_object_unref (GST_OBJECT (source));
+
+ g_free ((gpointer) istream);
+ free_properties(properties);
+
+ gst_object_unref(GST_OBJECT(pipeline));
+
+ g_warning ("unable to create decodebin");
+ return JNI_FALSE;
+ }
+
+ g_signal_connect (decodebin, "new-decoded-pad", G_CALLBACK (new_decoded_pad),
+ pipeline);
+
+ gst_bin_add_many (GST_BIN (pipeline), source, decodebin, NULL);
+ gst_element_link (source, decodebin);
+
+ typefind = gst_bin_get_by_name (GST_BIN (decodebin), "typefind");
+ if (typefind == NULL)
+ {
+ g_free ((gpointer) istream);
+ free_properties(properties);
+
+ gst_object_unref(GST_OBJECT(pipeline));
+
+ g_warning ("unable to create decodebin");
+ return JNI_FALSE;
+ }
+
+ g_signal_connect (G_OBJECT (typefind), "have-type",
+ G_CALLBACK (typefind_callback), properties);
+
+ gst_element_set_state (GST_ELEMENT(pipeline), GST_STATE_PLAYING);
+ if (gst_element_get_state (pipeline, NULL, NULL, 100000) ==
+ GST_STATE_CHANGE_FAILURE)
+ {
+ g_free ((gpointer) istream);
+ free_properties(properties);
+ gst_object_unref(GST_OBJECT(pipeline));
+
+ g_warning ("Failed to go into PLAYING state");
+ return JNI_FALSE;
+ }
+
+ result = JNI_FALSE;
+ if (fill_info (decodebin, properties))
+ {
+ result = set_strings (env, GstHeader, properties, header);
+ }
+
+ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
+
+ gst_object_unref (GST_OBJECT(pipeline));
+ free_properties (properties);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1file
+ (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject header)
+{
+ /* will contain the properties we need to put into the given GstHeader */
+ AudioProperties *properties = NULL;
+
+ /* source file */
+ const char *file = NULL;
+
+ /* GStreamer elements */
+ GstElement *pipeline = NULL;
+ GstElement *source = NULL;
+ GstElement *decoder = NULL;
+
+ GstElement *typefind = NULL;
+
+ GstStateChangeReturn res;
+
+ jboolean result = JNI_FALSE;
+
+ /* java fields */
+ jfieldID _fid = NULL;
+ jclass GstHeader = NULL;
+ jstring _file = NULL;
+
+ GstHeader = (*env)->GetObjectClass(env, header);
+ _fid = (*env)->GetFieldID(env, GstHeader, "file", "Ljava/lang/String;");
+ if (_fid == NULL)
+ {
+ return JNI_FALSE; /* failed to find the field */
+ }
+
+ _file = (*env)->GetObjectField(env, header, _fid);
+ file = JCL_jstring_to_cstring (env, _file);
+ if (file == NULL)
+ {
+ return JNI_FALSE;
+ }
+
+ gst_init (NULL, NULL);
+
+ properties = (AudioProperties *) g_malloc0 (sizeof (AudioProperties));
+ if (properties == NULL)
+ {
+ free_properties (properties);
+ JCL_free_cstring (env, _file, file);
+ return JNI_FALSE;
+ }
+
+ /* this is not really needed */
+ reset_properties(properties);
+
+ /* create the source element, will be used to read the file */
+ source = gst_element_factory_make ("filesrc", "source");
+ if (source == NULL)
+ {
+ free_properties (properties);
+ JCL_free_cstring (env, _file, file);
+ return JNI_FALSE;
+ }
+
+ /* set the file name */
+ g_object_set (G_OBJECT (source), "location", file, NULL);
+
+ /*
+ * create the decoder element, this will decode the stream and retrieve
+ * its properties.
+ * We connect a signal to this element, to be informed when it is done
+ * in decoding the stream and to get the needed informations about the
+ * audio file.
+ */
+ decoder = gst_element_factory_make ("decodebin", "decoder");
+ if (decoder == NULL)
+ {
+ gst_object_unref (GST_OBJECT (source));
+ free_properties(properties);
+
+ JCL_free_cstring (env, _file, file);
+ return JNI_FALSE;
+ }
+
+ g_signal_connect (decoder, "new-decoded-pad", G_CALLBACK (new_decoded_pad),
+ pipeline);
+ g_signal_connect (G_OBJECT (decoder), "element-added",
+ G_CALLBACK (element_added), properties);
+
+ /* now, we create a pipeline and fill it with the other elements */
+ pipeline = gst_pipeline_new ("pipeline");
+ if (pipeline == NULL)
+ {
+ gst_object_unref (GST_OBJECT (source));
+ gst_object_unref (GST_OBJECT (decoder));
+
+ free_properties(properties);
+
+ JCL_free_cstring (env, _file, file);
+ return JNI_FALSE;
+ }
+
+ /*
+ * we get the typefind from the decodebin to catch the additional properties
+ * that the decodebin does not expose to us
+ */
+ typefind = gst_bin_get_by_name (GST_BIN (decoder), "typefind");
+ if (typefind != NULL)
+ {
+ /*
+ * NOTE: the above is not a typo, we can live without the typefind,
+ * just, our stream detection will not be as accurate as we would.
+ * Anyway, if this fails, there is some problem, probabily a memory
+ * error.
+ */
+ g_signal_connect (G_OBJECT (typefind), "have-type",
+ G_CALLBACK (typefind_callback), properties);
+ }
+
+ gst_bin_add_many (GST_BIN (pipeline), source, decoder, NULL);
+ gst_element_link (source, decoder);
+
+ /*
+ * now, we set the pipeline playing state to pause and traverse it
+ * to get the info we need.
+ */
+
+ res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ if (res == GST_STATE_CHANGE_FAILURE)
+ {
+ JCL_free_cstring (env, _file, file);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (pipeline));
+
+ free_properties(properties);
+
+ return JNI_FALSE;
+ }
+
+ /* (GstClockTime) 300000000 ? */
+ res = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+ if (res != GST_STATE_CHANGE_SUCCESS)
+ {
+ JCL_free_cstring (env, _file, file);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (pipeline));
+
+ free_properties(properties);
+
+ return JNI_FALSE;
+ }
+
+ result = JNI_FALSE;
+ if (fill_info (decoder, properties))
+ {
+ result = set_strings (env, GstHeader, properties, header);
+ }
+
+ /* free stuff */
+ JCL_free_cstring (env, _file, file);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+
+ gst_object_unref (GST_OBJECT (pipeline));
+
+ free_properties (properties);
+
+ return result;
+}
+
+/* ***** END: NATIVE FUNCTIONS ***** */
+
+/* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
+static gboolean typefind_callback(GstElement *typefind __attribute__ ((unused)),
+ guint probability __attribute__ ((unused)),
+ const GstCaps *caps,
+ gpointer data)
+{
+ GstStructure *structure = NULL;
+ AudioProperties *properties = NULL;
+
+ const char *mpeg = NULL;
+
+ properties = (AudioProperties *) data;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* MIMETYPE */
+ properties->mimetype = gst_structure_get_name (structure);
+ mpeg = get_string_property(structure, "mpegversion");
+
+ if (mpeg != NULL)
+ {
+ properties->layer = get_string_property(structure, "layer");
+ properties->type = (gchar *) g_malloc0 (_GST_MALLOC_SIZE_);
+ g_snprintf ((gpointer) properties->type, _GST_MALLOC_SIZE_,
+ "MPEG%sV%s", mpeg,
+ properties->layer);
+
+ g_free ((gpointer) mpeg);
+ }
+
+ return TRUE;
+}
+
+static void
+new_decoded_pad (GstElement *decoder __attribute__ ((unused)),
+ GstPad *pad,
+ gboolean last __attribute__ ((unused)),
+ GstElement *pipeline)
+{
+ GstElement *fakesink = NULL;
+ GstPad *sinkpad = NULL;
+
+ fakesink = gst_element_factory_make ("fakesink", NULL);
+ gst_bin_add (GST_BIN (pipeline), fakesink);
+
+ sinkpad = gst_element_get_pad (fakesink, "sink");
+ if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkpad)))
+ {
+ gst_bin_remove (GST_BIN (pipeline), fakesink);
+ }
+ else
+ {
+ gst_element_set_state (fakesink, GST_STATE_PAUSED);
+ }
+}
+
+static gboolean
+set_strings (JNIEnv *env, const jclass GstHeader,
+ const AudioProperties *properties, jobject header)
+{
+ gboolean result = FALSE;
+
+ /*
+ * we only need at least one of them to be sure we can handle this
+ * kind of audio data.
+ */
+
+ /* now, map our properties to the java class */
+ set_string (env, GstHeader, header, "mimetype", properties->mimetype);
+
+ if (set_string (env, GstHeader, header, "endianness",
+ properties->endianness)) result = JNI_TRUE;
+
+ if (set_string (env, GstHeader, header, "channels",
+ properties->channels)) result = JNI_TRUE;
+
+ if (set_string (env, GstHeader, header, "rate",
+ properties->rate)) result = JNI_TRUE;
+
+ if (set_string (env, GstHeader, header, "width",
+ properties->width)) result = JNI_TRUE;
+
+ if (set_string (env, GstHeader, header, "depth",
+ properties->depth)) result = JNI_TRUE;
+
+ if (set_string (env, GstHeader, header, "isSigned",
+ properties->signess)) result = JNI_TRUE;
+
+ if (set_string (env, GstHeader, header, "name",
+ properties->name)) result = JNI_TRUE;
+
+ /* non primary properties */
+ set_string (env, GstHeader, header, "layer", properties->layer);
+ set_string (env, GstHeader, header, "bitrate", properties->bitrate);
+ set_string (env, GstHeader, header, "framed", properties->framed);
+ set_string (env, GstHeader, header, "type", properties->type);
+
+ return result;
+}
+
+static gboolean fill_info (GstElement *decoder, AudioProperties *properties)
+{
+ GstIterator *it = NULL;
+ gpointer data = NULL;
+ gboolean result = FALSE;
+
+ it = gst_element_iterate_src_pads (decoder);
+ while (gst_iterator_next (it, &data) == GST_ITERATOR_OK)
+ {
+ GstPad *pad = GST_PAD (data);
+ GstCaps *caps;
+
+ GstStructure *structure;
+
+ const gchar *caps_string = NULL;
+
+ caps = gst_pad_get_caps (pad);
+ caps_string = gst_caps_to_string (caps);
+
+ if (g_str_has_prefix (caps_string, "video"))
+ {
+ /* no video support, this is an audio library */
+
+ g_free ((gpointer) caps_string);
+ gst_caps_unref (caps);
+ gst_object_unref (pad);
+
+ continue;
+ }
+
+ g_free ((gpointer) caps_string);
+
+ structure = gst_caps_get_structure (GST_CAPS (caps), 0);
+
+ /* fill the properties we need */
+
+ /* SIGNESS */
+ properties->signess = get_boolean_property(structure, "signed");
+ if (properties->signess != NULL)
+ {
+ result = TRUE;
+ }
+
+ /* ENDIANNESS */
+ properties->endianness = get_string_property(structure, "endianness");
+ if (properties->endianness != NULL)
+ {
+ result = TRUE;
+ }
+
+ /* CHANNELS */
+ properties->channels = get_string_property(structure, "channels");
+ if (properties->channels != NULL)
+ {
+ result = TRUE;
+ }
+
+ /* RATE */
+ properties->rate = get_string_property(structure, "rate");
+ if (properties->rate != NULL)
+ {
+ result = TRUE;
+ }
+
+ /* WIDTH */
+ properties->width = get_string_property(structure, "width");
+ if (properties->width != NULL)
+ {
+ result = TRUE;
+ }
+
+ /* DEPTH */
+ properties->depth = get_string_property(structure, "depth");
+ if (properties->depth != NULL)
+ {
+ result = TRUE;
+ }
+
+ gst_caps_unref (caps);
+ gst_object_unref (pad);
+ }
+
+ return result;
+}
+
+static void free_properties (AudioProperties *properties)
+{
+ if (properties->name != NULL) g_free((gpointer) properties->name);
+ if (properties->endianness != NULL) g_free((gpointer) properties->endianness);
+ if (properties->channels != NULL) g_free((gpointer) properties->channels);
+ if (properties->rate != NULL) g_free((gpointer) properties->rate);
+ if (properties->width != NULL) g_free((gpointer) properties->width);
+ if (properties->depth != NULL) g_free((gpointer) properties->depth);
+ if (properties->layer != NULL) g_free((gpointer) properties->layer);
+ if (properties->bitrate != NULL) g_free((gpointer) properties->bitrate);
+ if (properties->framed != NULL) g_free((gpointer) properties->framed);
+
+ if (properties != NULL) g_free ((gpointer) properties);
+}
+
+static void reset_properties (AudioProperties *properties)
+{
+ properties->done = FALSE;
+ properties->signess = FALSE;
+ properties->name = NULL;
+ properties->endianness = NULL;
+ properties->channels = NULL;
+ properties->rate = NULL;
+ properties->width = NULL;
+ properties->depth = NULL;
+ properties->layer = NULL;
+ properties->bitrate = NULL;
+ properties->framed = NULL;
+}
+
+static gchar *get_string_property (const GstStructure *structure,
+ const gchar *property)
+{
+ int props = 0;
+ gchar *result = NULL;
+
+ if (property == NULL)
+ {
+ return NULL;
+ }
+
+ /* we don't need more */
+ result = (gchar *) g_malloc0 (_GST_MALLOC_SIZE_);
+ if (result == NULL)
+ {
+ /* huston, we have a problem here... */
+ return NULL;
+ }
+
+ if (gst_structure_get_int (structure, property, &props))
+ {
+ g_snprintf (result, _GST_MALLOC_SIZE_, "%d", props);
+ }
+ else
+ {
+ g_free ((gpointer) result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static gchar *get_boolean_property (const GstStructure *structure,
+ const gchar *property)
+{
+ gchar *result = NULL;
+ gboolean props = FALSE;
+
+ result = (gchar *) g_malloc0 (_GST_MALLOC_SIZE_);
+ if (result == NULL)
+ {
+ /* huston, we have a problem here... */
+ return NULL;
+ }
+
+ if (gst_structure_get_boolean (structure, property, &props))
+ {
+ g_snprintf (result, _GST_MALLOC_SIZE_, "%s", (props ? "true" : "false" ));
+ }
+ else
+ {
+ g_free ((gpointer) result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static gboolean set_string (JNIEnv *env, const jclass GstHeader,
+ jobject header,
+ const char *field,
+ const gchar *property)
+{
+ jfieldID _fid = NULL;
+ jstring property_string_field = NULL;
+
+ if (property == NULL || field == NULL || header == NULL || GstHeader == NULL)
+ {
+ return JNI_FALSE;
+ }
+
+ _fid = (*env)->GetFieldID(env, GstHeader, field, "Ljava/lang/String;");
+ if (_fid == NULL)
+ {
+ return JNI_FALSE; /* failed to find the field */
+ }
+
+ property_string_field = (*env)->NewStringUTF(env, property);
+ if (property_string_field == NULL)
+ {
+ return JNI_FALSE;
+ }
+
+ (*env)->SetObjectField(env, header, _fid, property_string_field);
+
+ return JNI_TRUE;
+}
+
+static void
+element_added (GstBin *bin, GstElement *element, gpointer data)
+{
+ GstElementFactory *factory;
+
+ factory = gst_element_get_factory (element);
+ ((AudioProperties *) data)->name = gst_element_factory_get_longname (factory);
+}
+
+/* ***** END: PRIVATE FUNCTIONS IMPLEMENTATION ***** */
diff --git a/native/jni/gstreamer-peer/Makefile.am b/native/jni/gstreamer-peer/Makefile.am
new file mode 100644
index 000000000..c40170fc3
--- /dev/null
+++ b/native/jni/gstreamer-peer/Makefile.am
@@ -0,0 +1,22 @@
+nativeexeclib_LTLIBRARIES = libgstreamerpeer.la
+
+libgstreamerpeer_la_SOURCES = GStreamerIOPeer.c \
+ gstinputstream.c \
+ gstclasspathsrc.c \
+ gstclasspathsrc.h \
+ gstinputstream.h
+
+libgstreamerpeer_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo
+
+libgstreamerpeer_la_LDFLAGS = $(AM_LDFLAGS) @GST_PLUGIN_LDFLAGS@ -avoid-version
+
+AM_LDFLAGS = @CLASSPATH_MODULE@ @GSTREAMER_LIBS@ @GSTREAMER_BASE_LIBS@ \
+ @GSTREAMER_PLUGINS_BASE_LIBS@ @GDK_LIBS@
+
+AM_CPPFLAGS = @CLASSPATH_INCLUDES@
+
+# We cannot use -Wwrite-strings and the strict flags since
+# gstreamer contain broken prototypes (by design).
+AM_CFLAGS = @WARNING_CFLAGS@ -Wno-write-strings -Wno-missing-field-initializers \
+ @ERROR_CFLAGS@ -Wno-unused-parameter @GSTREAMER_BASE_CFLAGS@ \
+ @GDK_CFLAGS@ @GSTREAMER_CFLAGS@ @GSTREAMER_PLUGINS_BASE_CFLAGS@
diff --git a/native/jni/gstreamer-peer/gstclasspathsrc.c b/native/jni/gstreamer-peer/gstclasspathsrc.c
new file mode 100644
index 000000000..afce1f1d4
--- /dev/null
+++ b/native/jni/gstreamer-peer/gstclasspathsrc.c
@@ -0,0 +1,332 @@
+/*gstclasspathsrc.c - Class file for the GstClasspathPlugin
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/*
+ * We don't really use version numbering here, we give it the same version
+ * number of classpath, so that gstreamer is happy.
+ * TODO: Maybe this should be moved in config.h instead?
+ */
+#define CLASSPATH_GST_PLUGIN_VERSION PACKAGE_VERSION
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesrc.h>
+#include <gst/base/gstpushsrc.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include <gdk/gdk.h>
+
+#include "gstclasspathsrc.h"
+#include "gstinputstream.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_classpath_src_debug);
+#define GST_CAT_DEFAULT gst_classpath_src_debug
+
+enum
+{
+ ARG_0,
+ ARG_INPUTSTREAM
+};
+
+static const GstElementDetails gst_classpath_src_details =
+GST_ELEMENT_DETAILS ("ClasspathSrc",
+ "Source/Network",
+ "Read from a java input stream",
+ "Mario Torre <neugens@limasoftware.net>");
+
+static GstStaticPadTemplate _template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+/* ***** plugin init ***** */
+
+static void
+_do_init (GType filesrc_type __attribute__ ((unused)))
+{
+ GST_DEBUG_CATEGORY_INIT (gst_classpath_src_debug, "classpathsrc",
+ 0, "classpathsrc");
+}
+
+GST_BOILERPLATE_FULL (GstClasspathSrc, gst_classpath_src, GstPushSrc,
+ GST_TYPE_PUSH_SRC, _do_init);
+
+static gboolean
+plugin_init (GstPlugin *plugin)
+{
+ return gst_element_register (plugin, "classpathsrc",
+ GST_RANK_NONE, GST_TYPE_CLASSPATH_SRC);
+}
+
+GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "classpathsrc",
+ "Java InputStream Reader",
+ plugin_init, CLASSPATH_GST_PLUGIN_VERSION,
+ GST_LICENSE_UNKNOWN,
+ "Classpath", "http://www.classpath.org/")
+
+/* ***** public class methods ***** */
+
+static void gst_classpath_src_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void gst_classpath_src_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gst_classpath_src_finalize (GObject *object);
+
+static gboolean gst_classpath_src_start (GstBaseSrc *basesrc);
+
+static gboolean gst_classpath_src_stop (GstBaseSrc *basesrc);
+
+static GstFlowReturn gst_classpath_src_create (GstPushSrc *src,
+ GstBuffer **buffer);
+
+/* ***** public class methods: end ***** */
+
+static void
+gst_classpath_src_base_init (gpointer gclass)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (gclass);
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&_template));
+
+ gst_element_class_set_details (gstelement_class, &gst_classpath_src_details);
+}
+
+static void
+gst_classpath_src_class_init (GstClasspathSrcClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSrcClass *gstbasesrc_class;
+ GstPushSrcClass *gstpushsrc_class;
+
+ GParamSpec *pspec;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstelement_class = GST_ELEMENT_CLASS (klass);
+ gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+ gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
+
+ /* getter and setters */
+
+ gobject_class->set_property = gst_classpath_src_set_property;
+ gobject_class->get_property = gst_classpath_src_get_property;
+
+ /* register properties */
+ pspec = g_param_spec_pointer (GST_CLASSPATH_SRC_ISTREAM,
+ "GstInputStream instance",
+ "GstInputStream instance",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, ARG_INPUTSTREAM, pspec);
+
+ /* register callbacks */
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_classpath_src_finalize);
+
+ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_classpath_src_start);
+ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_classpath_src_stop);
+
+ gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_classpath_src_create);
+}
+
+/* ***** */
+
+static void
+gst_classpath_src_init (GstClasspathSrc *src,
+ GstClasspathSrcClass * g_class __attribute__ ((unused)))
+{
+ src->istream = NULL;
+ src->read_position = 0;
+}
+
+static void
+gst_classpath_src_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* ************************************************************************** */
+
+static void
+gst_classpath_src_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GstClasspathSrc *src;
+
+ g_return_if_fail (GST_IS_CLASSPATH_SRC (object));
+
+ src = GST_CLASSPATH_SRC (object);
+
+ GST_OBJECT_LOCK (src);
+ switch (prop_id)
+ {
+ case ARG_INPUTSTREAM:
+ {
+ GST_STATE_LOCK (src);
+ {
+ GstState state;
+ state = GST_STATE (src);
+
+ if (state != GST_STATE_READY && state != GST_STATE_NULL)
+ {
+ GST_DEBUG_OBJECT (src, "setting location in wrong state");
+ GST_STATE_UNLOCK (src);
+ break;
+ }
+ }
+ GST_STATE_UNLOCK (src);
+
+ if (GST_IS_INPUT_STREAM (g_value_get_pointer (value)))
+ {
+ src->istream = g_value_get_pointer (value);
+ }
+ else
+ {
+ GST_INFO_OBJECT (src, "invalid instance of GstInputStream");
+ }
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (src);
+}
+
+static void
+gst_classpath_src_get_property (GObject *object,
+ guint prop_id __attribute__ ((unused)),
+ GValue *value __attribute__ ((unused)),
+ GParamSpec *pspec __attribute__ ((unused)))
+{
+ /* TODO */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* ************************************************************************** */
+
+static GstFlowReturn
+gst_classpath_src_create (GstPushSrc *basesrc,
+ GstBuffer **buffer)
+{
+ GstClasspathSrc *src;
+ int read = -1;
+
+ src = GST_CLASSPATH_SRC (basesrc);
+
+ /* create the buffer */
+ *buffer = gst_buffer_new_and_alloc (2048);
+ if (*buffer == NULL)
+ {
+ return GST_FLOW_ERROR;
+ }
+
+ GST_BUFFER_SIZE (*buffer) = 0;
+
+ GST_OBJECT_LOCK (src);
+ read = gst_input_stream_read (src->istream, (int *) GST_BUFFER_DATA (*buffer), 0,
+ 2048);
+ GST_OBJECT_UNLOCK (src);
+
+ if (G_UNLIKELY (read < 0))
+ {
+ gst_buffer_unref (*buffer);
+ return GST_FLOW_UNEXPECTED;
+ }
+
+ GST_OBJECT_LOCK (src);
+
+ GST_BUFFER_SIZE (*buffer) = read;
+ GST_BUFFER_OFFSET (*buffer) = src->read_position;
+ GST_BUFFER_OFFSET_END (*buffer) = src->read_position + read;
+
+ src->read_position += read;
+
+ GST_OBJECT_UNLOCK (src);
+
+ gst_buffer_set_caps (*buffer, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+gst_classpath_src_start (GstBaseSrc *basesrc)
+{
+ GstClasspathSrc *src;
+
+ src = GST_CLASSPATH_SRC (basesrc);
+
+ if (src->istream == NULL)
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+ ("GstInputStream is still null. you need to pass a valid InputStream"));
+
+ return FALSE;
+ }
+ GST_OBJECT_LOCK (src);
+ src->read_position = 0;
+ GST_OBJECT_UNLOCK (src);
+
+ return TRUE;
+}
+
+static gboolean
+gst_classpath_src_stop (GstBaseSrc *basesrc __attribute__ ((unused)))
+{
+ /* nothing to do */
+ return TRUE;
+}
diff --git a/native/jni/gstreamer-peer/gstclasspathsrc.h b/native/jni/gstreamer-peer/gstclasspathsrc.h
new file mode 100644
index 000000000..f5fa6c83d
--- /dev/null
+++ b/native/jni/gstreamer-peer/gstclasspathsrc.h
@@ -0,0 +1,88 @@
+/*gstclasspathsrc.h - Header file for the GstClasspathPlugin
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifndef __GST_CLASSPATH_SRC_H__
+#define __GST_CLASSPATH_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+#include "gstinputstream.h"
+
+G_BEGIN_DECLS
+
+/* #defines don't like whitespacey bits */
+#define GST_TYPE_CLASSPATH_SRC (gst_classpath_src_get_type())
+
+#define GST_CLASSPATH_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLASSPATH_SRC,GstClasspathSrc))
+
+#define GST_CLASSPATH_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLASSPATH_SRC,GstClasspathSrcClass))
+
+#define GST_IS_CLASSPATH_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLASSPATH_SRC))
+
+#define GST_IS_CLASSPATH_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLASSPATH_SRC))
+
+typedef struct _GstClasspathSrc GstClasspathSrc;
+typedef struct _GstClasspathSrcClass GstClasspathSrcClass;
+
+struct _GstClasspathSrc
+{
+ GstPushSrc element;
+
+ /* TODO: move in a private structure */
+ GstInputStream *istream;
+ int read_position;
+};
+
+struct _GstClasspathSrcClass
+{
+ GstPushSrcClass parent_class;
+};
+
+GType gst_classpath_src_get_type (void);
+
+/* exported properties */
+
+#define GST_CLASSPATH_SRC_ISTREAM "input-stream"
+
+G_END_DECLS
+
+#endif /* __GST_CLASSPATH_SRC_H__ */
diff --git a/native/jni/gstreamer-peer/gstinputstream.c b/native/jni/gstreamer-peer/gstinputstream.c
new file mode 100644
index 000000000..eb4969682
--- /dev/null
+++ b/native/jni/gstreamer-peer/gstinputstream.c
@@ -0,0 +1,494 @@
+/*gstinputstream.c - Header file for the GstClasspathPlugin
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include <jni.h>
+#include <jcl.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gdk/gdk.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include "gstinputstream.h"
+
+struct _GstInputStreamPrivate
+{
+ JavaVM *vm;
+ jobject *reader;
+
+ gboolean eof;
+ guint8 *buffer;
+ long size;
+ long length;
+
+ gboolean disposed;
+};
+
+#define INPUT_STREAM_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_INPUT_STREAM, GstInputStreamPrivate))
+
+/* properties */
+
+enum
+{
+ ARG_0,
+ ARG_JVM,
+ ARG_READER
+};
+
+/* ***** */
+
+static JNIEnv *gst_input_stream_get_jenv(GstInputStream *self);
+
+static void gst_input_stream_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void gst_input_stream_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gst_input_stream_instance_init (GTypeInstance *instance,
+ gpointer g_class);
+
+static void gst_input_stream_class_init (gpointer g_class,
+ gpointer g_class_data);
+
+static GObject *
+gst_input_stream_constructor (GType type, guint n_construct_properties,
+ GObjectConstructParam *construct_properties);
+
+static void
+gst_input_stream_dispose (GObject *obj);
+
+static void
+gst_input_stream_finalize (GObject *obj);
+
+/* ************************************************************************** */
+
+/* class methods */
+
+int
+gst_input_stream_read (GstInputStream *self, int *data, int offset,
+ int length)
+{
+ /* TODO: cache */
+ jmethodID _readID = NULL;
+ jclass InputStream = NULL;
+
+ JNIEnv *env = NULL;
+
+ int ret = -1;
+ jbyteArray buffer;
+ jbyte *bytes = NULL;
+
+ if (self->priv->disposed || self->priv->vm == NULL ||
+ self->priv->reader == NULL)
+ {
+ return -1;
+ }
+
+ env = gst_input_stream_get_jenv (self);
+ if (env == NULL)
+ {
+ g_warning("GstInputStream::gst_input_stream_read failed to get java env");
+ return -1;
+ }
+
+ buffer = (*env)->NewByteArray (env, length);
+ if (buffer == NULL)
+ {
+ g_warning ("GstInputStream::gst_input_stream_read called, failed");
+ return -1;
+ }
+
+ InputStream = (*env)->GetObjectClass(env, self->priv->reader);
+ _readID = (*env)->GetMethodID(env, InputStream, "read", "([BII)I");
+ if (_readID == NULL)
+ {
+ (*env)->DeleteLocalRef(env, buffer);
+ return -1;
+ }
+
+ ret = (*env)->CallIntMethod (env, self->priv->reader, _readID, buffer, 0,
+ length);
+ if (ret == -1)
+ {
+ (*env)->DeleteLocalRef(env, buffer);
+ return ret;
+ }
+
+ bytes = (*env)->GetByteArrayElements (env, buffer, NULL);
+
+ /* copy bytes and release */
+ memcpy (data + offset, bytes, ret);
+
+ (*env)->ReleaseByteArrayElements (env, buffer, bytes, 0);
+ (*env)->DeleteLocalRef (env, buffer);
+
+ return ret;
+}
+
+gboolean
+gst_input_stream_available (GstInputStream *self, guint64 *size)
+{
+ /* TODO: caching */
+
+ jmethodID _availableID = NULL;
+ jclass InputStream = NULL;
+ JNIEnv *env = NULL;
+
+ if (self->priv->disposed || self->priv->vm == NULL ||
+ self->priv->reader == NULL)
+ {
+ return FALSE;
+ }
+
+ env = gst_input_stream_get_jenv(self);
+ if (env == NULL)
+ {
+ g_warning("GstInputStream::gst_input_stream_available failed to get java env");
+ return FALSE;
+ }
+
+ InputStream = (*env)->GetObjectClass(env, self->priv->reader);
+ _availableID = (*env)->GetMethodID(env, InputStream, "available", "()I");
+ if (_availableID == NULL)
+ {
+ return FALSE;
+ }
+
+ *size = (*env)->CallIntMethod (env, self->priv->reader, _availableID);
+
+ return TRUE;
+}
+
+void gst_input_stream_reset (GstInputStream *self)
+{
+ jmethodID _resetID = NULL;
+ jclass InputStream = NULL;
+ JNIEnv *env = NULL;
+
+ if (self->priv->disposed || self->priv->vm == NULL ||
+ self->priv->reader == NULL)
+ {
+ return;
+ }
+
+ env = gst_input_stream_get_jenv(self);
+ if (env == NULL)
+ {
+ g_warning("GstInputStream::gst_input_stream_reset failed to get java env");
+ return;
+ }
+
+ InputStream = (*env)->GetObjectClass(env, self->priv->reader);
+ _resetID = (*env)->GetMethodID(env, InputStream, "reset", "()V");
+ if (_resetID == NULL)
+ {
+ return;
+ }
+
+ (*env)->CallVoidMethod (env, self->priv->reader, _resetID);
+}
+
+long gst_input_stream_skip (GstInputStream *self, long size)
+{
+ jmethodID _seekID = NULL;
+ jclass InputStream = NULL;
+ JNIEnv *env = NULL;
+
+ long skipped = -1;
+
+ if (self->priv->disposed || self->priv->vm == NULL ||
+ self->priv->reader == NULL)
+ {
+ return skipped;
+ }
+
+ env = gst_input_stream_get_jenv(self);
+ if (env == NULL)
+ {
+ g_warning("GstInputStream::gst_input_stream_skip failed to get java env");
+ return size;
+ }
+
+ InputStream = (*env)->GetObjectClass(env, self->priv->reader);
+ _seekID = (*env)->GetMethodID(env, InputStream, "skip", "(J)J");
+ if (_seekID == NULL)
+ {
+ return skipped;
+ }
+
+ size = (*env)->CallIntMethod (env, self->priv->reader, _seekID, size);
+ if (size != 0)
+ {
+ return skipped;
+ }
+
+ return skipped;
+}
+
+gboolean gst_input_stream_can_seek (GstInputStream *self)
+{
+ if (gst_input_stream_skip(self, 0) != 0)
+ {
+ g_warning ("GstInputStream::gst_input_stream_can_seek CANNOT seek");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* ************************************************************************** */
+
+/* getter and setter */
+
+static void
+gst_input_stream_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GstInputStream *self = GST_INPUT_STREAM (object);
+
+ switch (property_id)
+ {
+ case ARG_JVM:
+ {
+ self->priv->vm = g_value_get_pointer(value);
+ }
+ break;
+
+ case ARG_READER:
+ {
+ self->priv->reader = g_value_get_pointer(value);
+ }
+ break;
+
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
+ break;
+ } /* switch */
+}
+
+static void
+gst_input_stream_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GstInputStream *self = GST_INPUT_STREAM (object);
+
+ switch (property_id)
+ {
+ case ARG_JVM:
+ {
+ g_value_set_pointer (value, self->priv->vm);
+ }
+ break;
+
+ case ARG_READER:
+ {
+ g_value_set_pointer (value, self->priv->reader);
+ }
+ break;
+
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
+ break;
+ } /* switch */
+}
+
+/* ************************************************************************** */
+
+static void
+gst_input_stream_instance_init (GTypeInstance *instance,
+ gpointer g_class __attribute__ ((unused)))
+{
+ GstInputStream *self = GST_INPUT_STREAM (instance);
+
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INPUT_STREAM,
+ GstInputStreamPrivate);
+
+ self->priv->vm = NULL;
+ self->priv->reader = NULL;
+ self->priv->disposed = FALSE;
+ self->priv->eof = FALSE;
+ self->priv->buffer = NULL;
+ self->priv->size = 0;
+ self->priv->length = 0;
+}
+
+static void
+gst_input_stream_class_init (gpointer g_class,
+ gpointer g_class_data __attribute__ ((unused)))
+{
+ GObjectClass *gobject_class;
+ GstInputStreamClass *klass;
+ GObjectClass *parent_class;
+
+ GParamSpec *pspec;
+
+ gobject_class = G_OBJECT_CLASS (g_class);
+ klass = GST_INPUT_STREAM_CLASS (g_class);
+ gobject_class = G_OBJECT_CLASS (g_class);
+
+ g_type_class_add_private (klass, sizeof (GstInputStreamPrivate));
+
+ gobject_class->set_property = gst_input_stream_set_property;
+ gobject_class->get_property = gst_input_stream_get_property;
+ gobject_class->dispose = gst_input_stream_dispose;
+ gobject_class->finalize = gst_input_stream_finalize;
+ gobject_class->constructor = gst_input_stream_constructor;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ /* register properties */
+ pspec = g_param_spec_pointer (GST_ISTREAM_JVM,
+ "Set the java environment property",
+ "Set the java environment property",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, ARG_JVM, pspec);
+
+ pspec = g_param_spec_pointer (GST_ISTREAM_READER,
+ "Set the java reader property",
+ "Set the java reader property",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, ARG_READER, pspec);
+
+}
+
+/* class constructors */
+
+static GObject *
+gst_input_stream_constructor (GType type, guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *obj;
+ GObjectClass *parent_class;
+
+ /* parent */
+ GstInputStreamClass *klass;
+ klass = GST_INPUT_STREAM_CLASS (g_type_class_peek (GST_TYPE_INPUT_STREAM));
+ parent_class = g_type_class_peek_parent (klass);
+ obj = parent_class->constructor (type, n_construct_properties,
+ construct_properties);
+ return obj;
+}
+
+static void
+gst_input_stream_dispose (GObject *obj)
+{
+ GObjectClass *parent_class;
+ GstInputStream *self = GST_INPUT_STREAM (obj);
+ if (self->priv->disposed)
+ {
+ /* If dispose did already run, return. */
+ return;
+ }
+
+ /* Make sure dispose does not run twice. */
+ self->priv->disposed = TRUE;
+
+ if (self->priv->buffer != NULL)
+ g_free(self->priv->buffer);
+
+ /* Chain up to the parent class */
+ parent_class = g_type_class_peek_parent (GST_INPUT_STREAM_CLASS (obj));
+ G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+gst_input_stream_finalize (GObject *obj)
+{
+ /* nothing else to do */
+ GObjectClass *parent_class =
+ g_type_class_peek_parent (GST_INPUT_STREAM_CLASS (obj));
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static JNIEnv *
+gst_input_stream_get_jenv(GstInputStream *self)
+{
+ void *env = NULL;
+
+ if ((*self->priv->vm)->GetEnv(self->priv->vm, &env, JNI_VERSION_1_2) != JNI_OK)
+ {
+ if ((*self->priv->vm)->AttachCurrentThreadAsDaemon(self->priv->vm,
+ &env, NULL) < 0)
+ {
+ g_warning ("GstInputStream:- env not attached");
+ return NULL;
+ }
+ }
+
+ return (JNIEnv *) env;
+}
+
+GType gst_input_stream_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info = {
+ sizeof (GstInputStreamClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ gst_input_stream_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GstInputStream),
+ 0, /* n_preallocs */
+ gst_input_stream_instance_init /* instance_init */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "GstInputStreamType",
+ &info, 0);
+ }
+
+ return type;
+}
diff --git a/native/jni/gstreamer-peer/gstinputstream.h b/native/jni/gstreamer-peer/gstinputstream.h
new file mode 100644
index 000000000..1930412fe
--- /dev/null
+++ b/native/jni/gstreamer-peer/gstinputstream.h
@@ -0,0 +1,99 @@
+/*gstinputstream.h - Header file for the GstClasspathPlugin
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifndef __GST_INPUT_STREAM_H__
+#define __GST_INPUT_STREAM_H__
+
+#include <glib-object.h>
+
+/* TODO: is a gobject overkill for that? */
+
+G_BEGIN_DECLS
+
+/* #defines don't like whitespacey bits */
+#define GST_TYPE_INPUT_STREAM (gst_input_stream_get_type())
+
+#define GST_INPUT_STREAM(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_INPUT_STREAM,GstInputStream))
+
+#define GST_INPUT_STREAM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_INPUT_STREAM,GstInputStreamClass))
+
+#define GST_IS_INPUT_STREAM(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_INPUT_STREAM))
+
+#define GST_IS_INPUT_STREAM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_INPUT_STREAM))
+
+typedef struct _GstInputStream GstInputStream;
+typedef struct _GstInputStreamClass GstInputStreamClass;
+typedef struct _GstInputStreamPrivate GstInputStreamPrivate;
+
+struct _GstInputStream
+{
+ GObject parent;
+
+ /* instance members */
+ GstInputStreamPrivate *priv;
+};
+
+struct _GstInputStreamClass
+{
+ GObjectClass parent_class;
+};
+
+GType gst_input_stream_get_type (void);
+
+int gst_input_stream_read (GstInputStream *self, int *data, int offset,
+ int length);
+
+gboolean gst_input_stream_available (GstInputStream *self, guint64 *size);
+
+gboolean gst_input_stream_can_seek (GstInputStream *self);
+
+long gst_input_stream_skip (GstInputStream *self, long size);
+
+void gst_input_stream_reset (GstInputStream *self);
+
+/* exported properties */
+
+#define GST_ISTREAM_JVM "vm"
+#define GST_ISTREAM_READER "reader"
+
+G_END_DECLS
+
+#endif /* __GST_INPUT_STREAM_H__ */