Skip to content

Instantly share code, notes, and snippets.

@devijvers
Last active December 30, 2015 11:28
Show Gist options
  • Select an option

  • Save devijvers/7822395 to your computer and use it in GitHub Desktop.

Select an option

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.
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
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