123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740 |
- /* gstreamer_io_peer.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 "gst_peer.h"
- #include "gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h"
- #include "gst_classpath_src.h"
- #include "gst_input_stream.h"
- /* for caching */
- static jfieldID fileFID = NULL;
- static jfieldID pointerDataID = NULL;
- static jfieldID mimetypeFID = NULL;
- static jfieldID endiannessFID = NULL;
- static jfieldID channelsFID = NULL;
- static jfieldID rateFID = NULL;
- static jfieldID widthFID = NULL;
- static jfieldID depthFID = NULL;
- static jfieldID isSignedFID = NULL;
- static jfieldID nameFID = NULL;
- static jfieldID layerFID = NULL;
- static jfieldID bitrateFID = NULL;
- static jfieldID framedFID = NULL;
- static jfieldID typeFID = NULL;
- 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 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, gpointer data);
-
- 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, jobject header, jfieldID fieldID,
- const gchar *property);
- static void
- free_properties (AudioProperties *properties);
- static void
- reset_properties (AudioProperties *properties);
- static jboolean process_audio (GstElement *source, JNIEnv *env, jobject header);
- /* ***** END: PRIVATE FUNCTIONS DECLARATION ***** */
- /* ***** NATIVE FUNCTIONS ***** */
- JNIEXPORT void JNICALL
- Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_init_1id_1cache
- (JNIEnv *env, jclass clazz __attribute__ ((unused)))
- {
- jclass pointerClass = NULL;
- jclass GstHeader = NULL;
-
- GstHeader = JCL_FindClass(env, "gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer$GstHeader");
- fileFID = (*env)->GetFieldID(env, GstHeader, "file", "Ljava/lang/String;");
- mimetypeFID = (*env)->GetFieldID(env, GstHeader, "mimetype",
- "Ljava/lang/String;");
- endiannessFID = (*env)->GetFieldID(env, GstHeader, "endianness",
- "Ljava/lang/String;");
- channelsFID = (*env)->GetFieldID(env, GstHeader, "channels",
- "Ljava/lang/String;");
- rateFID = (*env)->GetFieldID(env, GstHeader, "rate", "Ljava/lang/String;");
- widthFID = (*env)->GetFieldID(env, GstHeader, "width", "Ljava/lang/String;");
- depthFID = (*env)->GetFieldID(env, GstHeader, "depth", "Ljava/lang/String;");
- isSignedFID = (*env)->GetFieldID(env, GstHeader, "isSigned",
- "Ljava/lang/String;");
- nameFID = (*env)->GetFieldID(env, GstHeader, "name", "Ljava/lang/String;");
- layerFID = (*env)->GetFieldID(env, GstHeader, "layer", "Ljava/lang/String;");
- bitrateFID = (*env)->GetFieldID(env, GstHeader, "bitrate",
- "Ljava/lang/String;");
- framedFID = (*env)->GetFieldID(env, GstHeader, "framed",
- "Ljava/lang/String;");
- typeFID = (*env)->GetFieldID(env, GstHeader, "type", "Ljava/lang/String;");
- #if SIZEOF_VOID_P == 8
- pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64");
- if (pointerClass != NULL)
- {
- pointerDataID = (*env)->GetFieldID (env, pointerClass, "data", "J");
- }
- #else
- # if SIZEOF_VOID_P == 4
- pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32");
- if (pointerClass != NULL)
- {
- pointerDataID = (*env)->GetFieldID(env, pointerClass, "data", "I");
- }
- # else
- # error "Pointer size is not supported."
- # endif /* SIZEOF_VOID_P == 4 */
- #endif /* SIZEOF_VOID_P == 8 */
- }
- JNIEXPORT jboolean JNICALL
- Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1stream
- (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject header,
- jobject pointer)
- {
- GstInputStream *istream = NULL;
- GstElement *source = NULL;
- gboolean result = JNI_FALSE;
-
- if (header == NULL)
- return JNI_FALSE;
-
- if (pointer == NULL)
- return JNI_FALSE;
-
- gst_init (NULL, NULL);
-
- istream = (GstInputStream *) get_object_from_pointer (env, pointer,
- pointerDataID);
- if (istream == NULL)
- return JNI_FALSE;
-
- /* init gstreamer */
- gst_init (NULL, NULL);
- /* SOURCE */
- source = gst_element_factory_make ("classpathsrc", "source");
- if (source == NULL)
- {
- g_warning ("unable to create a source");
- return JNI_FALSE;
- }
- g_object_set (G_OBJECT (source), GST_CLASSPATH_SRC_ISTREAM, istream, NULL);
- result = process_audio (source, env, header);
-
- 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)
- {
- /* source file */
- const char *file = NULL;
-
- /* GStreamer elements */
- GstElement *source = NULL;
- jboolean result = JNI_FALSE;
-
- /* java fields */
- jstring _file = NULL;
- _file = (*env)->GetObjectField(env, header, fileFID);
- file = JCL_jstring_to_cstring (env, _file);
- if (file == NULL)
- {
- return JNI_FALSE;
- }
- gst_init (NULL, NULL);
-
- /* create the source element, will be used to read the file */
- source = gst_element_factory_make ("filesrc", "source");
- if (source == NULL)
- {
- JCL_free_cstring (env, _file, file);
- return JNI_FALSE;
- }
-
- /* set the file name */
- g_object_set (G_OBJECT (source), "location", file, NULL);
- result = process_audio (source, env, header);
- /* free stuff */
- JCL_free_cstring (env, _file, file);
-
- return result;
- }
- /* ***** END: NATIVE FUNCTIONS ***** */
- /* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
- static jboolean process_audio (GstElement *source, JNIEnv *env, jobject header)
- {
- /* will contain the properties we need to put into the given GstHeader */
- AudioProperties *properties = NULL;
-
- /* GStreamer elements */
- GstElement *pipeline = NULL;
- GstElement *decoder = NULL;
-
- GstElement *typefind = NULL;
-
- GstStateChangeReturn res;
- jboolean result = JNI_FALSE;
-
- properties = (AudioProperties *) g_malloc0 (sizeof (AudioProperties));
- if (properties == NULL)
- {
- return result;
- }
- reset_properties(properties);
- /*
- * 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)
- {
- free_properties(properties);
- return result;
- }
-
- /* 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 (decoder));
- free_properties(properties);
- return result;
- }
-
- 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);
-
- /*
- * 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)
- {
- gst_element_set_state (pipeline, GST_STATE_NULL);
- gst_object_unref (GST_OBJECT (pipeline));
-
- free_properties(properties);
-
- return result;
- }
-
- res = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
- if (res != GST_STATE_CHANGE_SUCCESS)
- {
- gst_element_set_state (pipeline, GST_STATE_NULL);
- gst_object_unref (GST_OBJECT (pipeline));
-
- free_properties(properties);
-
- return result;
- }
-
- if (fill_info (decoder, properties))
- {
- result = set_strings (env, properties, header);
- }
-
- /* free stuff */
- gst_element_set_state (pipeline, GST_STATE_NULL);
-
- free_properties (properties);
-
- gst_object_unref (GST_OBJECT (pipeline));
-
- return result;
- }
- 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)),
- gpointer data)
- {
- GstElement *pipeline = NULL;
- GstElement *fakesink = NULL;
- GstPad *sinkpad = NULL;
-
- pipeline = (GstElement *) data;
- if (pipeline == NULL)
- return;
-
- fakesink = gst_element_factory_make ("fakesink", NULL);
- if (fakesink == NULL)
- return;
-
- 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 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, header, mimetypeFID, properties->mimetype);
-
- if (set_string (env, header, endiannessFID, properties->endianness))
- result = JNI_TRUE;
-
- if (set_string (env, header, channelsFID, properties->channels))
- result = JNI_TRUE;
-
- if (set_string (env, header, rateFID, properties->rate))
- result = JNI_TRUE;
-
- if (set_string (env, header, widthFID, properties->width))
- result = JNI_TRUE;
-
- if (set_string (env, header, depthFID, properties->depth))
- result = JNI_TRUE;
-
- if (set_string (env, header, isSignedFID, properties->signess))
- result = JNI_TRUE;
-
- if (set_string (env, header, nameFID, properties->name))
- result = JNI_TRUE;
-
- /* non primary properties */
- set_string (env, header, layerFID, properties->layer);
- set_string (env, header, bitrateFID, properties->bitrate);
- set_string (env, header, framedFID, properties->framed);
- set_string (env, header, typeFID, 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 __attribute__ ((unused)))
- {
- /* FIXME this causes a segfault, a string not allocated by us? double free? */
- /*
- 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, jobject header, jfieldID fieldID,
- const gchar *property)
- {
- jstring property_string_field = NULL;
-
- if (property == NULL || header == NULL)
- {
- return JNI_FALSE;
- }
-
- property_string_field = (*env)->NewStringUTF(env, property);
- if (property_string_field == NULL)
- {
- return JNI_FALSE;
- }
-
- (*env)->SetObjectField(env, header, fieldID, 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 ***** */
|