diff options
author | Mario Torre <neugens@limasoftware.net> | 2007-07-09 16:32:20 +0000 |
---|---|---|
committer | Mario Torre <neugens@limasoftware.net> | 2007-07-09 16:32:20 +0000 |
commit | 9afb84648bf4fc9cfa9dd2ee4dd5937a71338e4d (patch) | |
tree | 82b0e55156d12b1b8e5d816975ac3687b9967d02 /native | |
parent | de78d5b68527b0c5028826b5a4e98790be2b6fd9 (diff) | |
download | classpath-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.am | 10 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/.cvsignore | 7 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/GStreamerIOPeer.c | 772 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/Makefile.am | 22 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gstclasspathsrc.c | 332 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gstclasspathsrc.h | 88 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gstinputstream.c | 494 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gstinputstream.h | 99 |
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__ */ |