Last active
December 30, 2015 11:28
-
-
Save devijvers/7822395 to your computer and use it in GitHub Desktop.
Discover the properties and signals of an arbitrary GStreamer element with GStreamer-java 1.5.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name (java.lang.String) (RW) | |
| The name of the object | |
| current-level-buffers (java.lang.Integer) (RO) | |
| Current number of buffers in the queue | |
| current-level-bytes (java.lang.Integer) (RO) | |
| Current amount of data in the queue (bytes) | |
| current-level-time (java.lang.Long) (RO) | |
| Current amount of data in the queue (in ns) | |
| max-size-buffers (java.lang.Integer) (RW) | |
| Max. number of buffers in the queue (0=disable) | |
| max-size-bytes (java.lang.Integer) (RW) | |
| Max. amount of data in the queue (bytes, 0=disable) | |
| max-size-time (java.lang.Long) (RW) | |
| Max. amount of data in the queue (in ns, 0=disable) | |
| min-threshold-buffers (java.lang.Integer) (RW) | |
| Min. number of buffers in the queue to allow reading (0=disable) | |
| min-threshold-bytes (java.lang.Integer) (RW) | |
| Min. amount of data in the queue to allow reading (bytes, 0=disable) | |
| min-threshold-time (java.lang.Long) (RW) | |
| Min. amount of data in the queue to allow reading (in ns, 0=disable) | |
| leaky (RW) | |
| Where the queue leaks, if at all | |
| silent (java.lang.Boolean) (RW) | |
| Don't emit queue signals | |
| =========== | |
| underrun | |
| running | |
| overrun | |
| pushing | |
| notify |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.HashMap; | |
| import org.gstreamer.Element; | |
| import org.gstreamer.ElementFactory; | |
| import org.gstreamer.Gst; | |
| import org.gstreamer.lowlevel.GNative; | |
| import org.gstreamer.lowlevel.GObjectAPI; | |
| import org.gstreamer.lowlevel.GType; | |
| import org.gstreamer.lowlevel.GTypeMapper; | |
| import org.gstreamer.lowlevel.GstTypes; | |
| import org.gstreamer.lowlevel.GObjectAPI.GTypeInstance; | |
| import org.junit.Assert; | |
| import com.sun.jna.Library; | |
| import com.sun.jna.Pointer; | |
| import com.sun.jna.ptr.IntByReference; | |
| /** | |
| * <p>Discover the properties and signals of a GStreamer element. | |
| * | |
| * <p><code>GObject</code> has a meta-programming protocol. Properties do | |
| * not have getters and setters like a JavaBean. Instead the properties | |
| * and signals for an element are registered with the <code>GObject</code> | |
| * meta protocol. This allows us to retrieve the list of both registered | |
| * properties and registered signals for an arbitrary GStreamer element. | |
| * | |
| * <p>GStreamer-java release 1.5 does not have the suitable JNA functions to | |
| * retrieve both lists. This code adds those JNA functions and retrieves the | |
| * properties and signals for the GStreamer <code>queue</code> element. | |
| * | |
| * <p>Making this class work on Linux is easy: make sure gstreamer-0.10 (not | |
| * 1.0) has been installed and add this system property: | |
| * | |
| * <pre>-Djna.library.path=/usr/lib</pre> | |
| * | |
| * <p>Getting it to work on Windows is not so easy: | |
| * | |
| * <ol> | |
| * <li>Download <code>gstreamer-0.10</code> <a href="https://code.google.com/p/ossbuild/downloads/list">here</a>. | |
| * I've used <code>GStreamer-WinBuilds-LGPL-x86-Beta04-0.10.7.msi</code>, it's a 32-bit build. | |
| * <li>Run the installer and copy all <code>.dll</code> files found in the resulting folder to one folder, for example | |
| * to <code>c:\gstreamer-libs</code> | |
| * <li>Add this system property and argument: <code>-Djna.path.library=c:/gstreamer-libs --gst-plugin-path=c:/gstreamer-libs</code> | |
| * <li>Make sure you use a 32-bit JRE. | |
| * </ol> | |
| * | |
| */ | |
| public class GstreamerDiscovery { | |
| @SuppressWarnings("serial") | |
| public static void main(final String[] args) { | |
| // Initialize the GStreamer libraries | |
| Gst.init("Test", args); | |
| // Create a new GObject for the GStreamer queue element | |
| final Element queue = ElementFactory.make("queue", "Test0"); | |
| // Magic, basically. | |
| // Copied from org.gstreamer.GObject. | |
| // The GObjectAPIExtended interface (defined in this file, a little bit lower) | |
| // adds JNA functions that are either not defined by GStreamer-java 1.5 | |
| // or are not defined in a convenient way. | |
| final GObjectAPIExtended GOBJECT_API = GNative.loadLibrary("gobject-2.0", | |
| GObjectAPIExtended.class, new HashMap<String, Object>() { | |
| { | |
| put(Library.OPTION_TYPE_MAPPER, new GTypeMapper()); | |
| } | |
| }); | |
| // The glib library has the g_free function which is needed to free pointers. | |
| final GLibAPI GLIB_API = GNative.loadLibrary("glib-2.0", GLibAPI.class, new HashMap<String, Object>()); | |
| // The IntByReference class - provided by JNA - is a placeholder to | |
| // capture a GUINT value that is set by a C function. | |
| final IntByReference propertiesCount = new IntByReference(); | |
| // Retrieve the list of properties for the queue GObject. | |
| // The "native address" of the queue GObject is passed as is the | |
| // "number of properties" placeholder. | |
| final Pointer propertiesPointer = GOBJECT_API | |
| .g_object_class_list_properties(queue.getNativeAddress() | |
| .getPointer(0), propertiesCount); | |
| // The queue GObject has 12 properties defined | |
| // (this includes the 'name' property of its parent class GstObject) | |
| Assert.assertEquals(12, propertiesCount.getValue()); | |
| // Convert the pointer to an array of pointers where each pointer in the | |
| // array points to one GParamSpec struct per property. | |
| final Pointer[] properties = propertiesPointer.getPointerArray(0); | |
| // The property count value returned by the function call matches | |
| // the array length. | |
| Assert.assertEquals(12, properties.length); | |
| // The GParamSpec interface was copied from the GObjectAPI interface | |
| // and slightly modified to get it to work. | |
| // For each property pointer: | |
| for (final Pointer propertyPointer : properties) { | |
| // Pass the pointer to a GParamSpec instance | |
| final GParamSpec property = new GParamSpec(propertyPointer); | |
| // Retrieve the property blurb | |
| final String blurb = GOBJECT_API.g_param_spec_get_blurb(propertyPointer); | |
| // Returns the Java class corresponding to the property's GType | |
| final Class<?> propertyType = forType(property.getValueType()); | |
| // Print the property name | |
| System.out.println( | |
| property.getName() + | |
| (propertyType != null ? " (" + propertyType.getName() + ")" : "") + | |
| // Print whether or not this property is writable | |
| (isWritable(property.getFlags()) ? " (RW)" : " (RO)")); | |
| // Print the property blurb | |
| System.out.println(" " + blurb); | |
| // Unref the GParamSpec pointer. | |
| GOBJECT_API.g_param_spec_unref(propertyPointer); | |
| } | |
| // Free the pointer to the pointer array. | |
| GLIB_API.g_free(propertiesPointer); | |
| // Retrieve the GType for the queue GObject. | |
| // The GType can be thought of as the class of the queue GObject. | |
| final GType gtype = GstTypes.getGType(queue.getNativeAddress()); | |
| Assert.assertNotNull(gtype); | |
| final IntByReference signalCount = new IntByReference(); | |
| // Retrieve the list of signals for this GType | |
| final Pointer signalsPointer = GOBJECT_API.g_signal_list_ids(gtype, signalCount); | |
| // The signal count is only for this GType itself. | |
| // The retuned array also contains the signals for its hierarchical parents. | |
| Assert.assertEquals(4, signalCount.getValue()); | |
| // Convert the pointer to a array of pointers. | |
| final Pointer[] signals = signalsPointer.getPointerArray(0); | |
| // The array also contains the signals of the queue GObject's parents. | |
| // However, some parent signals are missing. | |
| Assert.assertEquals(7, signals.length); | |
| System.out.println("==========="); | |
| // For each pointer: | |
| for (final Pointer signalPointer : signals) { | |
| // Retrieve the signal name. | |
| // We're not retrieving the GSignalQuery. | |
| final String signalName = GOBJECT_API.g_signal_name(signalPointer); | |
| if (signalName != null) { | |
| System.out.println(signalName); | |
| } | |
| } | |
| // Free the pointer to the pointer array. | |
| // In this example this is not useful since the JRE will | |
| // exit anyways. In a non-trivial situation clearing pointers | |
| // will prevent memory leaks. | |
| GLIB_API.g_free(signalsPointer); | |
| } | |
| public interface GObjectAPIExtended extends GObjectAPI { | |
| Pointer g_object_class_list_properties(Pointer oclass, | |
| IntByReference size); | |
| String g_param_spec_get_blurb(Pointer paramSpec); | |
| Pointer g_signal_list_ids(GType itype, IntByReference size); | |
| String g_signal_name(Pointer signal_id); | |
| void g_signal_query(Pointer signal_id, Pointer queryPointer); | |
| void g_param_spec_unref(Pointer pointer); | |
| } | |
| public interface GLibAPI extends Library { | |
| void g_free(Pointer pointer); | |
| } | |
| public static class GParamSpec extends com.sun.jna.Structure { | |
| public volatile GTypeInstance g_type_instance; | |
| public volatile String g_name; | |
| public volatile/* GParamFlags */int g_flags; | |
| public volatile GType value_type; | |
| public volatile GType owner_type; | |
| /* < private > */ | |
| public volatile Pointer _nick; | |
| public volatile Pointer _blurb; | |
| public volatile Pointer qdata; | |
| public volatile int ref_count; | |
| public volatile int param_id; /* sort-criteria */ | |
| public GParamSpec() { | |
| clear(); | |
| } | |
| public GParamSpec(Pointer ptr) { | |
| super(ptr); | |
| read(); | |
| } | |
| public String getName() { | |
| return (String) readField("g_name"); | |
| } | |
| public int getFlags() { | |
| return (Integer) readField("g_flags"); | |
| } | |
| public GType getValueType() { | |
| return (GType) readField("value_type"); | |
| } | |
| public GType getOwnerType() { | |
| return (GType) readField("owner_type"); | |
| } | |
| @Override | |
| public void read() { | |
| } | |
| @Override | |
| public void write() { | |
| } | |
| } | |
| /** | |
| * <p>Returns the Java class corresponding to the GType. | |
| * | |
| * @param type | |
| * @return | |
| */ | |
| private static Class forType(final GType type) { | |
| final Class clazz = GstTypes.classFor(type); | |
| if (clazz != null) { | |
| return clazz; | |
| } else if (type == GType.INT || type == GType.UINT) { | |
| return Integer.class; | |
| } else if (type == GType.INT64 || type == GType.UINT64) { | |
| return Long.class; | |
| } else if (type == GType.LONG || type == GType.ULONG) { | |
| return Long.class; | |
| } else if (type == GType.FLOAT || type == GType.DOUBLE) { | |
| return Double.class; | |
| } else if (type == GType.CHAR || type == GType.UCHAR) { | |
| return Character.class; | |
| } else if (type == GType.STRING) { | |
| return String.class; | |
| } else if (type == GType.BOOLEAN) { | |
| return Boolean.class; | |
| } else { | |
| return null; | |
| } | |
| } | |
| /** | |
| * <p>Returns <code>true</code> if bit 2 is on. | |
| * | |
| * @param gParamFlags the GParamFlags value | |
| * @return whether this property is writeable or not | |
| * @see https://developer.gnome.org/gobject/stable/gobject-GParamSpec.html#GParamFlags | |
| */ | |
| private static boolean isWritable(final int gParamFlags) { | |
| return 2 == (gParamFlags & 0x002); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment