org.gstreamer.lowlevel.GNative Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gstreamer-java Show documentation
Show all versions of gstreamer-java Show documentation
Java binding for the Gstreamer framework
/*
* Copyright (c) 2007 Wayne Meissner
*
* This file is part of gstreamer-java.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3 only, as
* published by the Free Software Foundation.
*
* This code 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 Lesser General Public License
* version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work. If not, see .
*/
package org.gstreamer.lowlevel;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.gstreamer.ClockTime;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Platform;
/**
*
*/
public final class GNative {
private GNative() {
}
public static T loadLibrary(String name, Class interfaceClass, Map options) {
if (Platform.isWindows()) {
return loadWin32Library(name, interfaceClass, options);
}
return loadNativeLibrary(name, interfaceClass, options);
}
private static T loadNativeLibrary(String name, Class interfaceClass, Map options) {
T library = interfaceClass.cast(Native.loadLibrary(name, interfaceClass, options));
boolean needCustom = false;
for (Method m : interfaceClass.getMethods()) {
for (Class> cls : m.getParameterTypes()) {
if (cls.isArray() && getConverter(cls.getComponentType()) != null) {
needCustom = true;
}
}
}
//
// If no custom conversions are needed, just return the JNA proxy
//
if (!needCustom) {
return library;
} else {
// System.out.println("Using custom library proxy for " + interfaceClass.getName());
return interfaceClass.cast(Proxy.newProxyInstance(interfaceClass.getClassLoader(),
new Class[]{ interfaceClass }, new Handler(library, options)));
}
}
private static T loadWin32Library(String name, Class interfaceClass, Map options) {
//
// gstreamer on win32 names the dll files one of foo.dll, libfoo.dll and libfoo-0.dll
//
String[] nameFormats = {
"%s", "lib%s", "lib%s-0",
};
for (int i = 0; i < nameFormats.length; ++i) {
try {
return interfaceClass.cast(loadNativeLibrary(String.format(nameFormats[i], name), interfaceClass, options));
} catch (UnsatisfiedLinkError ex) {
continue;
}
}
throw new UnsatisfiedLinkError("Could not load library " + name);
}
private static NativeLibrary getWin32NativeLibrary(String name) {
//
// gstreamer on win32 names the dll files one of foo.dll, libfoo.dll and libfoo-0.dll
//
String[] nameFormats = {
"%s", "lib%s", "lib%s-0",
};
for (int i = 0; i < nameFormats.length; ++i) {
try {
return NativeLibrary.getInstance(String.format(nameFormats[i], name));
} catch (UnsatisfiedLinkError ex) {
continue;
}
}
throw new UnsatisfiedLinkError("Could not load library " + name);
}
public static NativeLibrary getNativeLibrary(String name) {
if (Platform.isWindows()) {
return getWin32NativeLibrary(name);
}
return NativeLibrary.getInstance(name);
}
private static interface Converter {
Class> nativeType();
Object toNative(Object value);
Object fromNative(Object value, Class> javaType);
}
private static final Converter enumConverter = new Converter() {
public Class> nativeType() {
return int.class;
}
public Object toNative(Object value) {
return value != null ? EnumMapper.getInstance().intValue((Enum>) value) : 0;
}
@SuppressWarnings(value = "unchecked")
public Object fromNative(Object value, Class javaType) {
return EnumMapper.getInstance().valueOf((Integer) value, javaType);
}
};
private static final Converter booleanConverter = new Converter() {
public Class> nativeType() {
return int.class;
}
public Object toNative(Object value) {
return value != null ? Boolean.TRUE.equals(value) ? 1 : 0 : 0;
}
@SuppressWarnings(value = "unchecked")
public Object fromNative(Object value, Class javaType) {
return value != null ? ((Integer) value).intValue() != 0 : 0;
}
};
private static final Converter clocktimeConverter = new Converter() {
public Class> nativeType() {
return long.class;
}
public Object toNative(Object value) {
return value != null ? ((ClockTime) value).toNanos() : 0L;
}
public Object fromNative(Object value, Class> javaType) {
return ClockTime.valueOf(value != null ? (Long) value : 0L, TimeUnit.NANOSECONDS);
}
};
private static Converter getConverter(Class> javaType) {
if (Enum.class.isAssignableFrom(javaType)) {
return enumConverter;
} else if (ClockTime.class == javaType) {
return clocktimeConverter;
} else if (boolean.class == javaType || Boolean.class == javaType) {
return booleanConverter;
}
return null;
}
private static class Handler implements InvocationHandler {
private final InvocationHandler proxy;
@SuppressWarnings("unused") // Keep a reference to stop underlying Library being GC'd
private final T library;
public Handler(T library, Map options) {
this.library = library;
this.proxy = Proxy.getInvocationHandler(library);
}
public Object invoke(Object self, Method method, Object[] args) throws Throwable {
int lastArg = args != null ? args.length : 0;
if (method.isVarArgs()) {
--lastArg;
}
Runnable[] postInvoke = null;
int postCount = 0;
for (int i = 0; i < lastArg; ++i) {
if (args[i] == null) {
continue;
}
final Class> cls = args[i].getClass();
if (!cls.isArray() || cls.getComponentType().isPrimitive() || cls.getComponentType() == String.class) {
continue;
}
final Converter converter = getConverter(cls.getComponentType());
if (converter != null) {
final Object[] src = (Object[]) args[i];
final Object dst = java.lang.reflect.Array.newInstance(converter.nativeType(), src.length);
final ArrayIO io = getArrayIO(converter.nativeType());
for (int a = 0; a < src.length; ++a) {
io.set(dst, a, converter.toNative(src[a]));
}
if (postInvoke == null) {
postInvoke = new Runnable[lastArg];
}
postInvoke[postCount++] = new Runnable() {
public void run() {
for (int a = 0; a < src.length; ++a) {
src[a] = converter.fromNative(io.get(dst, a), cls.getComponentType());
}
}
};
args[i] = dst;
}
}
Object retval = proxy.invoke(self, method, args);
//
// Reload any native arrays into java arrays
//
for (int i = 0; i < postCount; ++i) {
postInvoke[i].run();
}
return retval;
}
@SuppressWarnings("unused")
Class> getNativeClass(Class> cls) {
if (cls == Integer.class) {
return int.class;
} else if (cls == Long.class) {
return long.class;
}
return cls;
}
private static interface ArrayIO {
public void set(Object array, int index, Object data);
public Object get(Object array, int index);
}
private static final ArrayIO intArrayIO = new ArrayIO() {
public void set(Object array, int index, Object data) {
java.lang.reflect.Array.setInt(array, index, data != null ? (Integer) data : 0);
}
public Object get(Object array, int index) {
return java.lang.reflect.Array.getInt(array, index);
}
};
private static final ArrayIO longArrayIO = new ArrayIO() {
public void set(Object array, int index, Object data) {
java.lang.reflect.Array.setLong(array, index, data != null ? (Long) data : 0);
}
public Object get(Object array, int index) {
return java.lang.reflect.Array.getLong(array, index);
}
};
private static ArrayIO getArrayIO(final Class> cls) {
if (cls == int.class || cls == Integer.class) {
return intArrayIO;
} else if (cls == long.class || cls == Long.class) {
return longArrayIO;
}
throw new IllegalArgumentException("No such conversion");
}
}
}