All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gstreamer.lowlevel.GNative Maven / Gradle / Ivy

There is a newer version: 1.6
Show newest version
/*
 * 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 synchronized  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 synchronized 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);
        }
        
        @SuppressWarnings("null")
        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");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy