diff --git a/src/org/freedesktop/gstreamer/Bin.java b/src/org/freedesktop/gstreamer/Bin.java index e0df149c..c9e016b7 100644 --- a/src/org/freedesktop/gstreamer/Bin.java +++ b/src/org/freedesktop/gstreamer/Bin.java @@ -26,8 +26,8 @@ import com.sun.jna.Pointer; import java.util.List; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstAPI.GstCallback; -import org.freedesktop.gstreamer.lowlevel.GstTypes; /** * Base class and element that can contain other elements. @@ -86,7 +86,7 @@ protected Bin(Initializer init) { * Creates a new Bin with a unique name. */ public Bin() { - this(initializer(GSTBIN_API.ptr_gst_bin_new(null), false)); + this(Natives.initializer(GSTBIN_API.ptr_gst_bin_new(null), false, true)); } /** @@ -95,7 +95,7 @@ public Bin() { * @param name The Name to assign to the new Bin */ public Bin(String name) { - this(initializer(GSTBIN_API.ptr_gst_bin_new(name), false)); + this(Natives.initializer(GSTBIN_API.ptr_gst_bin_new(name), false, true)); } /** @@ -227,16 +227,16 @@ public Element getElementByNameRecurseUp(String name) { return GSTBIN_API.gst_bin_get_by_name_recurse_up(this, name); } - /** - * Looks for an element inside the bin that implements the given interface. - * If such an element is found, it returns the element. - * - * @param iface The class of the {@link Element} to search for. - * @return The {@link Element} that implements the interface. - */ - public T getElementByInterface(Class iface) { - return iface.cast(GSTBIN_API.gst_bin_get_by_interface(this, GstTypes.typeFor(iface))); - } +// /** +// * Looks for an element inside the bin that implements the given interface. +// * If such an element is found, it returns the element. +// * +// * @param iface The class of the {@link Element} to search for. +// * @return The {@link Element} that implements the interface. +// */ +// public T getElementByInterface(Class iface) { +// return iface.cast(GSTBIN_API.gst_bin_get_by_interface(this, GstTypes.typeFor(iface))); +// } /** * Calls {@link #debugToDotFile(int, String, boolean)} without timestamping diff --git a/src/org/freedesktop/gstreamer/Buffer.java b/src/org/freedesktop/gstreamer/Buffer.java index 3d2bdc5f..4dbc039f 100644 --- a/src/org/freedesktop/gstreamer/Buffer.java +++ b/src/org/freedesktop/gstreamer/Buffer.java @@ -32,6 +32,7 @@ import com.sun.jna.Pointer; import java.util.EnumSet; import org.freedesktop.gstreamer.glib.NativeFlags; +import org.freedesktop.gstreamer.glib.Natives; /** * Buffers are the basic unit of data transfer in GStreamer. They contain the @@ -53,7 +54,7 @@ public class Buffer extends MiniObject { * Creates a newly allocated buffer without any data. */ public Buffer() { - this(initializer(GSTBUFFER_API.ptr_gst_buffer_new())); + this(Natives.initializer(GSTBUFFER_API.ptr_gst_buffer_new())); } /** @@ -66,13 +67,13 @@ public Buffer() { * @param size */ public Buffer(int size) { - this(initializer(allocBuffer(size))); + this(Natives.initializer(allocBuffer(size))); } Buffer(Initializer init) { super(init); mapInfo = new MapInfoStruct(); - struct = new BufferStruct(handle()); + struct = new BufferStruct(getRawPointer()); } private static Pointer allocBuffer(int size) { diff --git a/src/org/freedesktop/gstreamer/BufferPool.java b/src/org/freedesktop/gstreamer/BufferPool.java index 06eacddb..b61d03ca 100644 --- a/src/org/freedesktop/gstreamer/BufferPool.java +++ b/src/org/freedesktop/gstreamer/BufferPool.java @@ -21,6 +21,7 @@ import org.freedesktop.gstreamer.lowlevel.GstBufferPoolAPI; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; /** * A BufferPool is an object that can be used to pre-allocate and recycle @@ -38,7 +39,7 @@ public class BufferPool extends GstObject { * Creates a new instance of BufferPool */ public BufferPool() { - this(initializer(GstBufferPoolAPI.GSTBUFFERPOOL_API.ptr_gst_buffer_pool_new())); + this(Natives.initializer(GstBufferPoolAPI.GSTBUFFERPOOL_API.ptr_gst_buffer_pool_new())); } /** @@ -71,7 +72,7 @@ public Caps getCaps() { Structure config = GstBufferPoolAPI.GSTBUFFERPOOL_API.gst_buffer_pool_get_config(this); Pointer[] ptr = new Pointer[1]; GstBufferPoolAPI.GSTBUFFERPOOL_API.gst_buffer_pool_config_get_params(config, ptr, null, null, null); - return new Caps(new Initializer(ptr[0], false, true)); + return new Caps(Natives.initializer(ptr[0], false, true)); } } diff --git a/src/org/freedesktop/gstreamer/Bus.java b/src/org/freedesktop/gstreamer/Bus.java index f01a453c..b29e241b 100644 --- a/src/org/freedesktop/gstreamer/Bus.java +++ b/src/org/freedesktop/gstreamer/Bus.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.logging.Level; import java.util.logging.Logger; import com.sun.jna.Callback; @@ -36,6 +35,7 @@ import com.sun.jna.Pointer; import com.sun.jna.ptr.PointerByReference; import java.util.Locale; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstAPI.GErrorStruct; import org.freedesktop.gstreamer.lowlevel.GstBusAPI; @@ -44,7 +44,6 @@ import static org.freedesktop.gstreamer.lowlevel.GlibAPI.GLIB_API; import static org.freedesktop.gstreamer.lowlevel.GstBusAPI.GSTBUS_API; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; -import static org.freedesktop.gstreamer.lowlevel.GstMiniObjectAPI.GSTMINIOBJECT_API; /** * The {@link Bus} is an object responsible for delivering {@link Message}s in a @@ -84,7 +83,6 @@ public class Bus extends GstObject { public static final String GTYPE_NAME = "GstBus"; private static final Logger LOG = Logger.getLogger(Bus.class.getName()); - private static final Level LOG_DEBUG = Level.FINE; private final Object lock = new Object(); private Map, Map> signalListeners; @@ -505,7 +503,7 @@ public void connect(final TAG listener) { public boolean callback(Bus bus, Message msg, Pointer user_data) { PointerByReference list = new PointerByReference(); GSTMESSAGE_API.gst_message_parse_tag(msg, list); - TagList tl = new TagList(TagList.initializer(list.getValue())); + TagList tl = new TagList(Natives.initializer(list.getValue())); listener.tagsFound(msg.getSource(), tl); return true; } @@ -741,7 +739,8 @@ public void run() { // Unref the message, since we are dropping it. // (the normal GC will drop other refs to it) // - GSTMINIOBJECT_API.gst_mini_object_unref(msg); +// GSTMINIOBJECT_API.gst_mini_object_unref(msg); + Natives.unref(msg); return BusSyncReply.DROP; } }; diff --git a/src/org/freedesktop/gstreamer/Caps.java b/src/org/freedesktop/gstreamer/Caps.java index 19bb607a..f26a24a7 100644 --- a/src/org/freedesktop/gstreamer/Caps.java +++ b/src/org/freedesktop/gstreamer/Caps.java @@ -20,8 +20,8 @@ */ package org.freedesktop.gstreamer; -import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstCapsAPI.GSTCAPS_API; /** @@ -72,7 +72,7 @@ public class Caps extends MiniObject { * @see #emptyCaps */ public Caps() { - this(initializer(GSTCAPS_API.ptr_gst_caps_new_empty())); + this(Natives.initializer(GSTCAPS_API.ptr_gst_caps_new_empty())); } /** @@ -82,7 +82,7 @@ public Caps() { * @see #fromString */ public Caps(String caps) { - this(initializer(GSTCAPS_API.ptr_gst_caps_from_string(caps))); + this(Natives.initializer(GSTCAPS_API.ptr_gst_caps_from_string(caps))); } /** @@ -92,7 +92,7 @@ public Caps(String caps) { * @see #copy */ public Caps(Caps caps) { - this(initializer(GSTCAPS_API.ptr_gst_caps_copy(caps))); + this(Natives.initializer(GSTCAPS_API.ptr_gst_caps_copy(caps))); } Caps(Initializer init) { @@ -282,7 +282,8 @@ public Caps makeWritable() { * @see Structure */ public Caps normalize() { - this.ref(); // gst_caps_normalize copies "this" and drops one reference +// this.ref(); // gst_caps_normalize copies "this" and drops one reference + Natives.ref(this); return GSTCAPS_API.gst_caps_normalize(this); } @@ -309,7 +310,8 @@ public void setInteger(String field, Integer value) { * @return The new {@link Caps} */ public Caps simplify() { - this.ref(); // gst_caps_simplify copies "this" and drops one reference +// this.ref(); // gst_caps_simplify copies "this" and drops one reference + Natives.ref(this); return GSTCAPS_API.gst_caps_simplify(this); } @@ -348,7 +350,8 @@ public String toString() { * @return truncated copy of the Caps */ public Caps truncate() { - this.ref(); +// this.ref(); + Natives.ref(this); return GSTCAPS_API.gst_caps_truncate(this); } @@ -359,7 +362,7 @@ public Caps truncate() { * @return The new Caps. */ public static Caps anyCaps() { - return new Caps(initializer(GSTCAPS_API.ptr_gst_caps_new_any())); + return new Caps(Natives.initializer(GSTCAPS_API.ptr_gst_caps_new_any())); } /** @@ -369,7 +372,7 @@ public static Caps anyCaps() { * @return The new Caps. */ public static Caps emptyCaps() { - return new Caps(initializer(GSTCAPS_API.ptr_gst_caps_new_empty())); + return new Caps(Natives.initializer(GSTCAPS_API.ptr_gst_caps_new_empty())); } /** @@ -383,7 +386,7 @@ public static Caps emptyCaps() { * @return The new Caps. */ public static Caps fromString(String caps) { - return new Caps(initializer(GSTCAPS_API.ptr_gst_caps_from_string(caps))); + return new Caps(Natives.initializer(GSTCAPS_API.ptr_gst_caps_from_string(caps))); } /** @@ -403,7 +406,4 @@ public static Caps merge(Caps caps1, Caps caps2) { return GSTCAPS_API.gst_caps_merge(caps1, caps2); } - protected static Initializer initializer(Pointer ptr) { - return new Initializer(ptr, false, true); - } } diff --git a/src/org/freedesktop/gstreamer/ClockID.java b/src/org/freedesktop/gstreamer/ClockID.java index a25fa81b..9bb243ad 100644 --- a/src/org/freedesktop/gstreamer/ClockID.java +++ b/src/org/freedesktop/gstreamer/ClockID.java @@ -16,12 +16,10 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer; -import com.sun.jna.Pointer; - -import org.freedesktop.gstreamer.lowlevel.RefCountedObject; +import org.freedesktop.gstreamer.glib.RefCountedObject; +import org.freedesktop.gstreamer.lowlevel.GPointer; import static org.freedesktop.gstreamer.lowlevel.GstClockAPI.GSTCLOCK_API; @@ -29,48 +27,34 @@ * A datatype to hold the handle to an outstanding sync or async clock callback. */ public class ClockID extends RefCountedObject implements Comparable { - public ClockID(Initializer init) { - super(init); - } - - @Override - protected void disposeNativeHandle(Pointer ptr) { - GSTCLOCK_API.gst_clock_id_unref(ptr); - } - @Override - protected void ref() { - GSTCLOCK_API.gst_clock_id_ref(this); + ClockID(Initializer init) { + super(new Handle(init.ptr, init.ownsHandle), init.needRef); } - @Override - protected void unref() { - GSTCLOCK_API.gst_clock_id_unref(this); - } - /** - * Cancel an outstanding request. This can either - * be an outstanding async notification or a pending sync notification. - * After this call, @id cannot be used anymore to receive sync or - * async notifications, you need to create a new #GstClockID. + * Cancel an outstanding request. This can either be an outstanding async + * notification or a pending sync notification. After this call, @id cannot + * be used anymore to receive sync or async notifications, you need to + * create a new #GstClockID. */ public void unschedule() { GSTCLOCK_API.gst_clock_id_unschedule(this); } - + /** * Gets the time of the clock ID *

* Thread safe. - * + * * @return The time of this clock id. */ public long getTime() { return GSTCLOCK_API.gst_clock_id_get_time(this); } - + /** - * Compares this ClockID to another. + * Compares this ClockID to another. * * @param other The other ClockID to compare to * @return negative value if a < b; zero if a = b; positive value if a > b @@ -79,4 +63,28 @@ public long getTime() { public int compareTo(ClockID other) { return GSTCLOCK_API.gst_clock_id_compare_func(this, other); } + + private static final class Handle extends RefCountedObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GSTCLOCK_API.gst_clock_id_unref(ptr); + } + + @Override + protected void ref() { + GSTCLOCK_API.gst_clock_id_ref(getPointer()); + } + + @Override + protected void unref() { + GSTCLOCK_API.gst_clock_id_unref(getPointer()); + } + + } + } diff --git a/src/org/freedesktop/gstreamer/DateTime.java b/src/org/freedesktop/gstreamer/DateTime.java index c00c1f6c..61c3ff5d 100644 --- a/src/org/freedesktop/gstreamer/DateTime.java +++ b/src/org/freedesktop/gstreamer/DateTime.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Neil C Smith * Copyright (c) 2016 Christophe Lafolet * Copyright (c) 2010 Levente Farkas * @@ -14,67 +15,65 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer; import static org.freedesktop.gstreamer.lowlevel.GstDateTimeAPI.GSTDATETIME_API; import org.freedesktop.gstreamer.lowlevel.GType; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.lowlevel.GPointer; /** */ public class DateTime extends NativeObject { - + public static final String GTYPE_NAME = "GstDateTime"; public static final GType GTYPE = GSTDATETIME_API.gst_date_time_get_type(); - public static DateTime createInstanceLocalEpoch(long secs) { - return new DateTime(GSTDATETIME_API.gst_date_time_new_from_unix_epoch_local_time(secs), false, true); + return new DateTime(GSTDATETIME_API.gst_date_time_new_from_unix_epoch_local_time(secs), false, true); } DateTime(Initializer init) { - super(init); - } - - DateTime(Pointer ptr, boolean needRef, boolean ownsHandle) { - this(initializer(ptr, needRef, ownsHandle)); + this(new Handle(init.ptr, init.ownsHandle)); } - @Override - protected void disposeNativeHandle(Pointer ptr) { - GSTDATETIME_API.gst_date_time_unref(ptr); + DateTime(Pointer ptr, boolean needRef, boolean ownsHandle) { + this(new Handle(new GPointer(ptr), ownsHandle)); } + DateTime(Handle handle) { + super(handle); + } + public int getYear() { - return GSTDATETIME_API.gst_date_time_get_year(handle()); + return GSTDATETIME_API.gst_date_time_get_year(getRawPointer()); } - + public int getMonth() { - return GSTDATETIME_API.gst_date_time_get_month(handle()); + return GSTDATETIME_API.gst_date_time_get_month(getRawPointer()); } - + public int getDay() { - return GSTDATETIME_API.gst_date_time_get_day(handle()); + return GSTDATETIME_API.gst_date_time_get_day(getRawPointer()); } public int getHour() { - return GSTDATETIME_API.gst_date_time_get_hour(handle()); + return GSTDATETIME_API.gst_date_time_get_hour(getRawPointer()); } - + public int getMinute() { - return GSTDATETIME_API.gst_date_time_get_minute(handle()); + return GSTDATETIME_API.gst_date_time_get_minute(getRawPointer()); } public int getSecond() { - return GSTDATETIME_API.gst_date_time_get_second(handle()); + return GSTDATETIME_API.gst_date_time_get_second(getRawPointer()); } public int getMicrosecond() { - return GSTDATETIME_API.gst_date_time_get_microsecond(handle()); + return GSTDATETIME_API.gst_date_time_get_microsecond(getRawPointer()); } @Override @@ -82,4 +81,17 @@ public String toString() { return "" + getYear() + "-" + getMonth() + "-" + getDay() + " " + getHour() + ":" + getMinute() + ":" + getSecond() + "." + getMicrosecond(); } + private static final class Handle extends NativeObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GSTDATETIME_API.gst_date_time_unref(ptr.getPointer()); + } + + } + } diff --git a/src/org/freedesktop/gstreamer/Element.java b/src/org/freedesktop/gstreamer/Element.java index d96389ec..f4feb930 100644 --- a/src/org/freedesktop/gstreamer/Element.java +++ b/src/org/freedesktop/gstreamer/Element.java @@ -26,6 +26,7 @@ import org.freedesktop.gstreamer.event.Event; import java.util.List; import java.util.concurrent.TimeUnit; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstAPI.GstCallback; @@ -88,7 +89,7 @@ protected Element(Initializer init) { * @return a raw element. */ protected static Initializer makeRawElement(String factoryName, String elementName) { - return initializer(ElementFactory.makeRawElement(factoryName, elementName)); + return Natives.initializer(ElementFactory.makeRawElement(factoryName, elementName)); } /** diff --git a/src/org/freedesktop/gstreamer/ElementFactory.java b/src/org/freedesktop/gstreamer/ElementFactory.java index 44e7f3bb..f5927213 100644 --- a/src/org/freedesktop/gstreamer/ElementFactory.java +++ b/src/org/freedesktop/gstreamer/ElementFactory.java @@ -18,7 +18,6 @@ */ package org.freedesktop.gstreamer; -import static org.freedesktop.gstreamer.lowlevel.GlibAPI.GLIB_API; import static org.freedesktop.gstreamer.lowlevel.GstElementFactoryAPI.GSTELEMENTFACTORY_API; import static org.freedesktop.gstreamer.lowlevel.GstPadTemplateAPI.GSTPADTEMPLATE_API; import static org.freedesktop.gstreamer.lowlevel.GstPluginAPI.GSTPLUGIN_API; @@ -32,10 +31,9 @@ import org.freedesktop.gstreamer.lowlevel.GlibAPI.GList; import org.freedesktop.gstreamer.lowlevel.GstPadTemplateAPI.GstStaticPadTemplate; -import org.freedesktop.gstreamer.lowlevel.GstTypes; -import org.freedesktop.gstreamer.lowlevel.NativeObject; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; /** * ElementFactory is used to create instances of elements. @@ -55,9 +53,6 @@ public class ElementFactory extends PluginFeature { private static final Level DEBUG = Level.FINE; private static final Logger LOG = Logger.getLogger(ElementFactory.class.getName()); - private static final Map> TYPE_MAP - = new HashMap>(); - /** * Creates a new instance of ElementFactory * @@ -237,7 +232,7 @@ public static List listGetElements(ListType type, Rank minrank) GList next = glist; while (next != null) { if (next.data != null) { - ElementFactory fact = new ElementFactory(initializer(next.data, true, true)); + ElementFactory fact = new ElementFactory(Natives.initializer(next.data, true, true)); list.add(fact); } next = next.next(); @@ -276,7 +271,7 @@ public static List listGetElementsFilter(ListType type, Rank min GList next = gFilterList; while (next != null) { if (next.data != null) { - ElementFactory fact = new ElementFactory(initializer(next.data, true, true)); + ElementFactory fact = new ElementFactory(Natives.initializer(next.data, true, true)); filterList.add(fact); } next = next.next(); @@ -315,25 +310,8 @@ static Pointer makeRawElement(String factoryName, String name) { return elem; } - /** - * Register a new class into the typeMap. - */ - static void registerElement(Class klass, String name) { - TYPE_MAP.put(name, klass); - } - - @SuppressWarnings("unchecked") private static Element elementFor(Pointer ptr, String factoryName) { - Class cls = ElementFactory.TYPE_MAP.get(factoryName); - if (cls == null) { - cls = (Class) GstTypes.classFor(Element.getType(ptr)); - if (cls == null) { - cls = Element.class; - } - - ElementFactory.TYPE_MAP.put(factoryName, cls); - } - return NativeObject.objectFor(ptr, cls, false); + return Natives.objectFor(ptr, Element.class, false); } /** diff --git a/src/org/freedesktop/gstreamer/GhostPad.java b/src/org/freedesktop/gstreamer/GhostPad.java index 9840ba1c..ca5d79a1 100644 --- a/src/org/freedesktop/gstreamer/GhostPad.java +++ b/src/org/freedesktop/gstreamer/GhostPad.java @@ -23,6 +23,7 @@ */ package org.freedesktop.gstreamer; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstGhostPadAPI.GSTGHOSTPAD_API; /** @@ -68,7 +69,7 @@ public class GhostPad extends Pad { * @param target The {@link Pad} to ghost. */ public GhostPad(String name, Pad target) { - this(initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new(name, target))); + this(Natives.initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new(name, target))); } /** @@ -81,7 +82,7 @@ public GhostPad(String name, Pad target) { * @param template The {@link PadTemplate} to use on the ghostpad. */ public GhostPad(String name, Pad target, PadTemplate template) { - this(initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new_from_template(name, target, template))); + this(Natives.initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new_from_template(name, target, template))); } /** @@ -94,7 +95,7 @@ public GhostPad(String name, Pad target, PadTemplate template) { * @param direction The direction of the ghostpad. */ public GhostPad(String name, PadDirection direction) { - this(initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new_no_target(name, direction.ordinal()))); + this(Natives.initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new_no_target(name, direction.ordinal()))); } /** @@ -105,7 +106,7 @@ public GhostPad(String name, PadDirection direction) { * @param template The {@link PadTemplate} to use on the ghostpad. */ public GhostPad(String name, PadTemplate template) { - this(initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new_no_target_from_template(name, template))); + this(Natives.initializer(GSTGHOSTPAD_API.ptr_gst_ghost_pad_new_no_target_from_template(name, template))); } /** diff --git a/src/org/freedesktop/gstreamer/Gst.java b/src/org/freedesktop/gstreamer/Gst.java index 1a509f83..f3b886ac 100644 --- a/src/org/freedesktop/gstreamer/Gst.java +++ b/src/org/freedesktop/gstreamer/Gst.java @@ -19,17 +19,12 @@ */ package org.freedesktop.gstreamer; -import org.freedesktop.gstreamer.webrtc.WebRTCSessionDescription; import org.freedesktop.gstreamer.query.Query; import org.freedesktop.gstreamer.message.Message; import org.freedesktop.gstreamer.event.Event; -import org.freedesktop.gstreamer.glib.GSocket; -import org.freedesktop.gstreamer.glib.GInetSocketAddress; import org.freedesktop.gstreamer.glib.GError; import static org.freedesktop.gstreamer.lowlevel.GstAPI.GST_API; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -42,23 +37,11 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; -import org.freedesktop.gstreamer.elements.AppSink; -import org.freedesktop.gstreamer.elements.AppSrc; -import org.freedesktop.gstreamer.elements.BaseSink; -import org.freedesktop.gstreamer.elements.BaseSrc; -import org.freedesktop.gstreamer.elements.BaseTransform; -import org.freedesktop.gstreamer.elements.DecodeBin; -import org.freedesktop.gstreamer.elements.PlayBin; -import org.freedesktop.gstreamer.elements.URIDecodeBin; -import org.freedesktop.gstreamer.webrtc.WebRTCBin; -import org.freedesktop.gstreamer.glib.GDate; -import org.freedesktop.gstreamer.glib.GInetAddress; -import org.freedesktop.gstreamer.glib.GSocketAddress; import org.freedesktop.gstreamer.glib.MainContextExecutorService; import org.freedesktop.gstreamer.lowlevel.GMainContext; import org.freedesktop.gstreamer.lowlevel.GstAPI.GErrorStruct; import org.freedesktop.gstreamer.lowlevel.GstTypes; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; import com.sun.jna.Memory; import com.sun.jna.Native; @@ -68,21 +51,26 @@ import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; +import java.util.ServiceLoader; import java.util.logging.Level; +import java.util.stream.Stream; +import org.freedesktop.gstreamer.elements.Elements; +import org.freedesktop.gstreamer.glib.GLib; import static org.freedesktop.gstreamer.lowlevel.GstParseAPI.GSTPARSE_API; +import static org.freedesktop.gstreamer.glib.Natives.registration; +import org.freedesktop.gstreamer.webrtc.WebRTC; /** * Media library supporting arbitrary formats and filter graphs. - * */ @SuppressWarnings("deprecation") public final class Gst { - + private final static Logger LOG = Logger.getLogger(Gst.class.getName()); private final static AtomicInteger INIT_COUNT = new AtomicInteger(0); private final static boolean CHECK_VERSIONS = !Boolean.getBoolean("gstreamer.suppressVersionChecks"); - + private final static boolean DISABLE_EXTERNAL = Boolean.getBoolean("gstreamer.disableExternalTypes"); + private static ScheduledExecutorService executorService; private static volatile CountDownLatch quit = new CountDownLatch(1); private static GMainContext mainContext; @@ -90,14 +78,14 @@ public final class Gst { private static List shutdownTasks = Collections.synchronizedList(new ArrayList()); // set minorVersion to a value guaranteed to be >= anything else unless set in init() private static int minorVersion = Integer.MAX_VALUE; - + public static class NativeArgs { - + public IntByReference argcRef; public PointerByReference argvRef; Memory[] argsCopy; Memory argvMemory; - + public NativeArgs(String progname, String[] args) { // // Allocate some native memory to pass the args down to the native layer @@ -111,7 +99,7 @@ public NativeArgs(String progname, String[] args) { Memory arg = new Memory(progname.getBytes().length + 4); arg.setString(0, progname); argsCopy[0] = arg; - + for (int i = 0; i < args.length; i++) { arg = new Memory(args[i].getBytes().length + 1); arg.setString(0, args[i]); @@ -121,7 +109,7 @@ public NativeArgs(String progname, String[] args) { argvRef = new PointerByReference(argvMemory); argcRef = new IntByReference(args.length + 1); } - + String[] toStringArray() { // // Unpack the native arguments back into a String array @@ -267,7 +255,7 @@ public static Element parseLaunch(String pipelineDescription, List error LOG.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage()); } } - + return pipeline; } @@ -316,7 +304,7 @@ public static Element parseLaunch(String[] pipelineDescription, List err LOG.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage()); } } - + return pipeline; } @@ -350,10 +338,10 @@ public static Element parseLaunch(String[] pipelineDescription) { * @throws GstException if the bin could not be created */ public static Bin parseBinFromDescription(String binDescription, boolean ghostUnlinkedPads, List errors) { - + Pointer[] err = {null}; Bin bin = GSTPARSE_API.gst_parse_bin_from_description(binDescription, ghostUnlinkedPads, err); - + if (bin == null) { throw new GstException(new GError(new GErrorStruct(err[0]))); } @@ -366,7 +354,7 @@ public static Bin parseBinFromDescription(String binDescription, boolean ghostUn LOG.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage()); } } - + return bin; } @@ -507,7 +495,7 @@ public static synchronized final String[] init(String progname, String... args) */ public static synchronized final String[] init(Version requestedVersion, String progname, String... args) throws GstException { - + if (CHECK_VERSIONS) { Version availableVersion = getVersion(); if (requestedVersion.getMajor() != 1 || availableVersion.getMajor() != 1) { @@ -534,22 +522,22 @@ public static synchronized final String[] init(Version requestedVersion, } return args; } - + NativeArgs argv = new NativeArgs(progname, args); - + Pointer[] error = {null}; if (!GST_API.gst_init_check(argv.argcRef, argv.argvRef, error)) { INIT_COUNT.decrementAndGet(); throw new GstException(new GError(new GErrorStruct(error[0]))); } - + LOG.fine("after gst_init, argc=" + argv.argcRef.getValue()); - + Version runningVersion = getVersion(); if (runningVersion.getMajor() != 1) { LOG.warning("gst1-java-core only supports GStreamer 1.x"); } - + if (useDefaultContext) { mainContext = GMainContext.getDefaultContext(); executorService = new MainContextExecutorService(mainContext); @@ -559,11 +547,11 @@ public static synchronized final String[] init(Version requestedVersion, } quit = new CountDownLatch(1); loadAllClasses(); - + if (CHECK_VERSIONS) { minorVersion = requestedVersion.getMinor(); } - + return argv.toStringArray(); } @@ -605,7 +593,7 @@ public static synchronized final void deinit() { } } catch (InterruptedException ex) { } - + mainContext = null; System.gc(); // Make sure any dangling objects are unreffed before calling deinit(). GST_API.gst_deinit(); @@ -618,7 +606,7 @@ public static synchronized final void deinit() { * * @param task the task to execute. */ - public static void addStaticShutdownTask(Runnable task) { + static void addStaticShutdownTask(Runnable task) { shutdownTasks.add(task); } @@ -693,7 +681,7 @@ private ThreadGroup getThreadGroup() { return null; } } - + public Thread newThread(Runnable task) { final String name = "gstreamer service thread " + counter.incrementAndGet(); Thread t = new Thread(getThreadGroup(), task, name); @@ -702,89 +690,59 @@ public Thread newThread(Runnable task) { return t; } }; - - private static String getField(Class cls, String name) - throws SecurityException, IllegalArgumentException { - try { - Field f = cls.getDeclaredField(name); - int mod = f.getModifiers(); - if (Modifier.isStatic(mod) && Modifier.isFinal(mod) && f.getType().equals(String.class)) { - f.setAccessible(true); - return (String) f.get(null); - } - } catch (NoSuchFieldException e) { - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return null; - } - - @SuppressWarnings("unchecked") - public static synchronized void registerClass(Class cls) { - String value = null; - value = getField(cls, "GTYPE_NAME"); - if (value != null) { - GstTypes.registerType(cls, value); - } - value = getField(cls, "GST_NAME"); - if (Element.class.isAssignableFrom(cls) && value != null) { - ElementFactory.registerElement((Class) cls, value); - } - } - + @SuppressWarnings("unchecked") private static synchronized void loadAllClasses() { - for (Class cls : nativeClasses) { - registerClass(cls); + Stream.of(new GLib.Types(), + new Types(), + new Event.Types(), + new Message.Types(), + new Query.Types(), + new Elements(), + new WebRTC.Types()) + .flatMap(NativeObject.TypeProvider::types) + .forEachOrdered(GstTypes::register); + if (!DISABLE_EXTERNAL) { + try { + ServiceLoader extProviders + = ServiceLoader.load(NativeObject.TypeProvider.class); + extProviders.iterator().forEachRemaining(prov + -> prov.types().forEachOrdered(GstTypes::register)); + } catch (Throwable t) { + LOG.log(Level.SEVERE, "Error during external types registration", t); + } } } - // to generate the list we use: - // egrep -rl "GST_NAME|GTYPE_NAME" src 2>/dev/null | egrep -v ".svn|Gst.java" | sort - // even though the best would be all subclasses of NativeObject - @SuppressWarnings("rawtypes") - private static List> nativeClasses - = Arrays.>asList( - GDate.class, - GInetAddress.class, - GSocket.class, - GSocketAddress.class, - GInetSocketAddress.class, - TagList.class, - // ----------- Base ------------- - Buffer.class, - BufferPool.class, - Bus.class, - Caps.class, - Clock.class, - DateTime.class, - Element.class, - ElementFactory.class, - Event.class, - GhostPad.class, - Message.class, - Pad.class, - PadTemplate.class, - Plugin.class, - PluginFeature.class, - Promise.class, - Query.class, - Registry.class, - SDPMessage.class, - Sample.class, - WebRTCSessionDescription.class, - // ----------- Elements ------------- - AppSink.class, - AppSrc.class, - BaseSrc.class, - BaseSink.class, - BaseTransform.class, - Bin.class, - DecodeBin.class, - Pipeline.class, - PlayBin.class, - URIDecodeBin.class, - WebRTCBin.class + + public static class Types implements NativeObject.TypeProvider { + + @Override + public Stream> types() { + return Stream.of( + registration(Bin.class, Bin.GTYPE_NAME, Bin::new), + registration(Buffer.class, Buffer.GTYPE_NAME, Buffer::new), + registration(BufferPool.class, BufferPool.GTYPE_NAME, BufferPool::new), + registration(Bus.class, Bus.GTYPE_NAME, Bus::new), + registration(Caps.class, Caps.GTYPE_NAME, Caps::new), + registration(Clock.class, Clock.GTYPE_NAME, Clock::new), + registration(DateTime.class, DateTime.GTYPE_NAME, DateTime::new), + registration(Element.class, Element.GTYPE_NAME, Element::new), + registration(ElementFactory.class, ElementFactory.GTYPE_NAME, ElementFactory::new), + registration(GhostPad.class, GhostPad.GTYPE_NAME, GhostPad::new), + registration(Pad.class, Pad.GTYPE_NAME, Pad::new), + registration(PadTemplate.class, PadTemplate.GTYPE_NAME, PadTemplate::new), + registration(Pipeline.class, Pipeline.GTYPE_NAME, Pipeline::new), + registration(Plugin.class, Plugin.GTYPE_NAME, Plugin::new), + registration(PluginFeature.class, PluginFeature.GTYPE_NAME, PluginFeature::new), + registration(Promise.class, Promise.GTYPE_NAME, Promise::new), + registration(Registry.class, Registry.GTYPE_NAME, Registry::new), + registration(SDPMessage.class, SDPMessage.GTYPE_NAME, SDPMessage::new), + registration(Sample.class, Sample.GTYPE_NAME, Sample::new), + registration(TagList.class, TagList.GTYPE_NAME, TagList::new) ); + } + + } /** * Annotation on classes, methods or fields to show the required GStreamer @@ -794,10 +752,10 @@ private static synchronized void loadAllClasses() { @Retention(RetentionPolicy.RUNTIME) @Documented public static @interface Since { - + public int major() default 1; - + public int minor(); } - + } diff --git a/src/org/freedesktop/gstreamer/GstIterator.java b/src/org/freedesktop/gstreamer/GstIterator.java index 51993879..bf1b465a 100644 --- a/src/org/freedesktop/gstreamer/GstIterator.java +++ b/src/org/freedesktop/gstreamer/GstIterator.java @@ -29,7 +29,8 @@ import org.freedesktop.gstreamer.lowlevel.GType; import org.freedesktop.gstreamer.lowlevel.GValueAPI; import org.freedesktop.gstreamer.lowlevel.GstTypes; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.lowlevel.GPointer; import static org.freedesktop.gstreamer.lowlevel.GstIteratorAPI.GSTITERATOR_API; @@ -41,7 +42,7 @@ class GstIterator extends NativeObject implements java.l private final GType gtype; GstIterator(Pointer ptr, Class cls) { - super(initializer(ptr)); + super(new Handle(new GPointer(ptr), true)); gtype = GstTypes.typeFor(cls); } @@ -50,11 +51,6 @@ public Iterator iterator() { return new IteratorImpl(); } - @Override - protected void disposeNativeHandle(Pointer ptr) { - GSTITERATOR_API.gst_iterator_free(ptr); - } - public List asList() { List list = new LinkedList(); for (T t : this) { @@ -75,7 +71,7 @@ class IteratorImpl implements java.util.Iterator { } private T getNext() { - if (GSTITERATOR_API.gst_iterator_next(handle(), gValue) == 1) { + if (GSTITERATOR_API.gst_iterator_next(getRawPointer(), gValue) == 1) { T result = (T) gValue.getValue(); // reset cached structure or we get a memory leak gValue.reset(); @@ -102,4 +98,17 @@ public void remove() { throw new UnsupportedOperationException("Items cannot be removed."); } } + + private static final class Handle extends NativeObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GSTITERATOR_API.gst_iterator_free(ptr.getPointer()); + } + + } } diff --git a/src/org/freedesktop/gstreamer/GstObject.java b/src/org/freedesktop/gstreamer/GstObject.java index 31e8bd09..37f3b21a 100644 --- a/src/org/freedesktop/gstreamer/GstObject.java +++ b/src/org/freedesktop/gstreamer/GstObject.java @@ -20,16 +20,11 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer; -import org.freedesktop.gstreamer.glib.GObject; -import java.util.EventListener; -import java.util.EventListenerProxy; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Logger; -import com.sun.jna.Pointer; +import java.util.logging.Logger; +import org.freedesktop.gstreamer.glib.GObject; +import org.freedesktop.gstreamer.lowlevel.GstObjectPtr; import static org.freedesktop.gstreamer.lowlevel.GstObjectAPI.GSTOBJECT_API; @@ -41,43 +36,45 @@ * >https://gstreamer.freedesktop.org/data/doc/gstreamer/stable/gstreamer/html/GstObject.html *

* GstObject provides a root for the object hierarchy tree filed in by the - * GStreamer library. It is currently a thin wrapper on top of - * {@link GObject}. It is an abstract class that is not very usable on its own. + * GStreamer library. It is currently a thin wrapper on top of {@link GObject}. + * It is an abstract class that is not very usable on its own. * */ public class GstObject extends GObject { - private static Logger logger = Logger.getLogger(GstObject.class.getName()); - private Map, Map> listenerMap; + + private static Logger LOG = Logger.getLogger(GstObject.class.getName()); /** * Wraps an underlying C GstObject with a Java proxy - * + * * @param init Initialization data */ protected GstObject(Initializer init) { - super(init); + this(new Handle(init.ptr.as(GstObjectPtr.class, GstObjectPtr::new), init.ownsHandle), init.needRef); } + protected GstObject(Handle handle, boolean needRef) { + super(handle, needRef); + } + /** * Sets the name of this object, or gives this object a guaranteed unique * name (if name is null). - * - * Returns: TRUE if the name could be set. Since Objects that have - * a parent cannot be renamed, this function returns FALSE in those - * cases. + * + * Returns: TRUE if the name could be set. Since Objects that have a parent + * cannot be renamed, this function returns FALSE in those cases. * * MT safe. - * + * * @param name new name of object - * @return true if the name was set. Since Objects that have - * a parent cannot be renamed, this function returns false in those - * cases. + * @return true if the name was set. Since Objects that have a parent cannot + * be renamed, this function returns false in those cases. */ public boolean setName(String name) { - logger.entering("GstObject", "setName", name); + LOG.entering("GstObject", "setName", name); return GSTOBJECT_API.gst_object_set_name(this, name); } - + /** * Returns a copy of the name of this object. * @@ -86,53 +83,58 @@ public boolean setName(String name) { * @return the name of this object. */ public String getName() { - logger.entering("GstObject", "getName"); + LOG.entering("GstObject", "getName"); return GSTOBJECT_API.gst_object_get_name(this); } - + /** * Returns this object's parent, if there is one. - * + * * @return parent or null */ public GstObject getParent() { return GSTOBJECT_API.gst_object_get_parent(this); } - + @Override public String toString() { return String.format("%s: [%s]", getClass().getSimpleName(), getName()); } +// protected static Initializer initializer(Pointer ptr) { +// return initializer(ptr, true, true); +// } +// +// protected static Initializer initializer(Pointer ptr, boolean needRef) { +// return initializer(ptr, needRef, true); +// } - @Deprecated - protected void ref() { - GSTOBJECT_API.gst_object_ref(this); - } - - @Override - @Deprecated - protected void sink() { - GSTOBJECT_API.gst_object_ref_sink(this); - } - - @Deprecated - protected void unref() { - GSTOBJECT_API.gst_object_unref(this); - } - - private Map, Map> getListenerMap() { - if (listenerMap == null) { - listenerMap = new HashMap, Map>(); + protected static class Handle extends GObject.Handle { + + public Handle(GstObjectPtr ptr, boolean ownsHandle) { + super(ptr, ownsHandle); } - return listenerMap; - } - - protected static Initializer initializer(Pointer ptr) { - return initializer(ptr, true, true); - } - - protected static Initializer initializer(Pointer ptr, boolean needRef) { - return initializer(ptr, needRef, true); + + @Override + protected void ref() { + GSTOBJECT_API.gst_object_ref(getPointer()); + } + + @Override + protected void sink() { + GSTOBJECT_API.gst_object_ref_sink(getPointer()); + } + + @Override + protected void unref() { + GSTOBJECT_API.gst_object_unref(getPointer()); + } + + @Override + protected GstObjectPtr getPointer() { + return (GstObjectPtr) super.getPointer(); + } + + } } diff --git a/src/org/freedesktop/gstreamer/MiniObject.java b/src/org/freedesktop/gstreamer/MiniObject.java index ccbb0650..b16b1bf6 100644 --- a/src/org/freedesktop/gstreamer/MiniObject.java +++ b/src/org/freedesktop/gstreamer/MiniObject.java @@ -19,17 +19,14 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer; -import com.sun.jna.Native; -import com.sun.jna.Pointer; - -import org.freedesktop.gstreamer.lowlevel.GType; import org.freedesktop.gstreamer.lowlevel.GstMiniObjectAPI.MiniObjectStruct; -import org.freedesktop.gstreamer.lowlevel.RefCountedObject; +import org.freedesktop.gstreamer.glib.RefCountedObject; +import org.freedesktop.gstreamer.lowlevel.GPointer; import static org.freedesktop.gstreamer.lowlevel.GstMiniObjectAPI.GSTMINIOBJECT_API; +import org.freedesktop.gstreamer.lowlevel.GstMiniObjectPtr; /** * Lightweight base class for the GStreamer object hierarchy @@ -42,56 +39,52 @@ * types. */ public abstract class MiniObject extends RefCountedObject { + /** * Creates a new instance of MiniObject */ protected MiniObject(Initializer init) { - super(init); + this(new Handle(init.ptr.as(GstMiniObjectPtr.class, GstMiniObjectPtr::new), + init.ownsHandle), init.needRef); } - - /** - * Gives the type value. - */ - @Deprecated - public static GType getType(Pointer ptr) { - // Quick getter for GType without allocation - // same as : new MiniObjectStruct(ptr).type - if (Native.SIZE_T_SIZE == 8) { - return GType.valueOf(ptr.getLong(0)); - } else if (Native.SIZE_T_SIZE == 4) { - return GType.valueOf( ((long) ptr.getInt(0)) & 0xffffffffL ); - } else { - throw new IllegalStateException("SIZE_T size not supported: " + Native.SIZE_T_SIZE); - } + + protected MiniObject(Handle handle, boolean needRef) { + super(handle, needRef); } /** - * If mini_object has the LOCKABLE flag set, check if the current EXCLUSIVE lock on object is the only one, this means that changes to the object will not be visible to any other object. + * If mini_object has the LOCKABLE flag set, check if the current EXCLUSIVE + * lock on object is the only one, this means that changes to the object + * will not be visible to any other object. * - *

If the LOCKABLE flag is not set, check if the refcount of mini_object is exactly 1, meaning that no other reference exists to the object and that the object is therefore writable. + *

+ *

If the LOCKABLE flag is not set, check if the refcount of mini_object + * is exactly 1, meaning that no other reference exists to the object and + * that the object is therefore writable. * - *

Modification of a mini-object should only be done after verifying that it is writable. + *

+ *

Modification of a mini-object should only be done after verifying + * that it is writable. * * @return true if the object is writable. */ - @Deprecated public boolean isWritable() { return GSTMINIOBJECT_API.gst_mini_object_is_writable(this); } /** * Makes a writable instance of this MiniObject. - *

The result is cast to subclass. + *

+ * The result is cast to subclass. * * @return a writable version (possibly a duplicate) of this MiniObject. */ - @Deprecated protected T makeWritable() { MiniObject result = GSTMINIOBJECT_API.gst_mini_object_make_writable(this); if (result == null) { throw new NullPointerException("Could not make " + this.getClass().getSimpleName() + " writable"); } - return (T)result; + return (T) result; } /** @@ -99,37 +92,45 @@ protected T makeWritable() { * * @return the new MiniObject. */ - @Deprecated public T copy() { MiniObject result = GSTMINIOBJECT_API.gst_mini_object_copy(this); if (result == null) { throw new NullPointerException("Could not make a copy of " + this.getClass().getSimpleName()); } - return (T)result; - } - - @Deprecated - @Override - protected void ref() { - GSTMINIOBJECT_API.gst_mini_object_ref(this); - } - - @Deprecated - @Override - protected void unref() { - GSTMINIOBJECT_API.gst_mini_object_unref(this); + return (T) result; } public int getRefCount() { - final MiniObjectStruct struct = new MiniObjectStruct(handle()); + final MiniObjectStruct struct = new MiniObjectStruct(getRawPointer()); return (Integer) struct.readField("refcount"); } - @Deprecated - @Override - protected void disposeNativeHandle(Pointer ptr) { - if (ownsHandle.get()) { - GSTMINIOBJECT_API.gst_mini_object_unref(ptr); + private static final class Handle extends RefCountedObject.Handle { + + public Handle(GstMiniObjectPtr ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GSTMINIOBJECT_API.gst_mini_object_unref( + ptr.as(GstMiniObjectPtr.class, GstMiniObjectPtr::new)); + } + + @Override + protected void ref() { + GSTMINIOBJECT_API.gst_mini_object_ref(getPointer()); } + + @Override + protected void unref() { + GSTMINIOBJECT_API.gst_mini_object_unref(getPointer()); + } + + @Override + protected GstMiniObjectPtr getPointer() { + return (GstMiniObjectPtr) super.getPointer(); + } + } } diff --git a/src/org/freedesktop/gstreamer/Pad.java b/src/org/freedesktop/gstreamer/Pad.java index a705c0fa..5d310be6 100644 --- a/src/org/freedesktop/gstreamer/Pad.java +++ b/src/org/freedesktop/gstreamer/Pad.java @@ -25,6 +25,7 @@ import org.freedesktop.gstreamer.event.Event; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstAPI.GstCallback; import org.freedesktop.gstreamer.lowlevel.GstPadProbeInfo; @@ -91,7 +92,7 @@ public class Pad extends GstObject { * @param direction The direction of the new pad. */ public Pad(String name, PadDirection direction) { - this(initializer(GSTPAD_API.ptr_gst_pad_new(name, direction), false)); + this(Natives.initializer(GSTPAD_API.ptr_gst_pad_new(name, direction), false)); } /** @@ -104,7 +105,7 @@ public Pad(String name, PadDirection direction) { * @param name The name of the new pad. */ public Pad(PadTemplate template, String name) { - this(initializer(GSTPAD_API.ptr_gst_pad_new_from_template(template, name), false)); + this(Natives.initializer(GSTPAD_API.ptr_gst_pad_new_from_template(template, name), false)); } /** diff --git a/src/org/freedesktop/gstreamer/PadTemplate.java b/src/org/freedesktop/gstreamer/PadTemplate.java index 4a9a7791..1d1f5e5a 100644 --- a/src/org/freedesktop/gstreamer/PadTemplate.java +++ b/src/org/freedesktop/gstreamer/PadTemplate.java @@ -21,6 +21,7 @@ */ package org.freedesktop.gstreamer; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstPadTemplateAPI.GSTPADTEMPLATE_API; /** @@ -62,7 +63,7 @@ public class PadTemplate extends GstObject { * @param caps a {@code Caps} set for the template. */ public PadTemplate(String nameTemplate, PadDirection direction, Caps caps) { - this(initializer(GSTPADTEMPLATE_API.ptr_gst_pad_template_new(nameTemplate, direction, PadPresence.ALWAYS, caps))); + this(Natives.initializer(GSTPADTEMPLATE_API.ptr_gst_pad_template_new(nameTemplate, direction, PadPresence.ALWAYS, caps))); } /** @@ -75,7 +76,7 @@ public PadTemplate(String nameTemplate, PadDirection direction, Caps caps) { * @param caps a {@code Caps} set for the template. */ public PadTemplate(String nameTemplate, PadDirection direction, PadPresence presence, Caps caps) { - this(initializer(GSTPADTEMPLATE_API.ptr_gst_pad_template_new(nameTemplate, direction, presence, caps))); + this(Natives.initializer(GSTPADTEMPLATE_API.ptr_gst_pad_template_new(nameTemplate, direction, presence, caps))); } /** diff --git a/src/org/freedesktop/gstreamer/Pipeline.java b/src/org/freedesktop/gstreamer/Pipeline.java index a42349cc..9398e7d9 100644 --- a/src/org/freedesktop/gstreamer/Pipeline.java +++ b/src/org/freedesktop/gstreamer/Pipeline.java @@ -34,6 +34,7 @@ import static org.freedesktop.gstreamer.lowlevel.GstPipelineAPI.GSTPIPELINE_API; import static org.freedesktop.gstreamer.lowlevel.GstQueryAPI.GSTQUERY_API; import org.freedesktop.gstreamer.glib.NativeFlags; +import org.freedesktop.gstreamer.glib.Natives; /** * A {@code Pipeline} is a special {@link Bin} used as the top level container @@ -102,7 +103,7 @@ protected Pipeline(Initializer init) { * Creates a new instance of Pipeline with a unique name. */ public Pipeline() { - this(initializer(GSTPIPELINE_API.ptr_gst_pipeline_new(null), false)); + this(Natives.initializer(GSTPIPELINE_API.ptr_gst_pipeline_new(null), false)); initBus(); } @@ -118,7 +119,7 @@ public Pipeline(String name) { private static Initializer initializer(String name) { Pointer new_pipeline = GSTPIPELINE_API.ptr_gst_pipeline_new(name); - return initializer(new_pipeline, false); + return Natives.initializer(new_pipeline, false); } private void initBus() { diff --git a/src/org/freedesktop/gstreamer/Promise.java b/src/org/freedesktop/gstreamer/Promise.java index 3f267f4c..4967bac3 100644 --- a/src/org/freedesktop/gstreamer/Promise.java +++ b/src/org/freedesktop/gstreamer/Promise.java @@ -22,6 +22,7 @@ import org.freedesktop.gstreamer.lowlevel.GstAPI.GstCallback; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; /** * A miniobject for future/promise-like functionality @@ -49,7 +50,8 @@ public class Promise extends MiniObject { * Creates a new instance of promise */ public Promise() { - this(initializer(GSTPROMISE_API.ptr_gst_promise_new())); + this(Natives.initializer(GSTPROMISE_API.ptr_gst_promise_new())); + Gst.checkVersion(1, 14); // @TODO ideally this check would be before native call! } /** @@ -59,7 +61,7 @@ public Promise() { * {@link Promise} is changed */ public Promise(final PROMISE_CHANGE listener) { - this(initializer(GSTPROMISE_API.ptr_gst_promise_new_with_change_func(new GstCallback() { + this(Natives.initializer(GSTPROMISE_API.ptr_gst_promise_new_with_change_func(new GstCallback() { @SuppressWarnings("unused") public void callback(Promise promise, Pointer userData) { listener.onChange(promise); @@ -67,11 +69,6 @@ public void callback(Promise promise, Pointer userData) { }), false, false)); } - protected static Initializer initializer(final Pointer ptr) { - Gst.checkVersion(1, 14); - return new Initializer(ptr, false, true); - } - /** * Wait for the promise to move out of the PENDING {@link PromiseResult} * state. If the promise is not in PENDING then it will immediately return. diff --git a/src/org/freedesktop/gstreamer/Registry.java b/src/org/freedesktop/gstreamer/Registry.java index e736ac05..634ec21c 100644 --- a/src/org/freedesktop/gstreamer/Registry.java +++ b/src/org/freedesktop/gstreamer/Registry.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GlibAPI.GList; import static org.freedesktop.gstreamer.lowlevel.GstPluginAPI.GSTPLUGIN_API; @@ -228,7 +229,7 @@ private List objectList(GList glist, Class objectCla GList next = glist; while (next != null) { if (next.data != null) { - list.add(GstObject.objectFor(next.data, objectClass, true, true)); + list.add(Natives.objectFor(next.data, objectClass, true, true)); } next = next.next(); } @@ -251,7 +252,7 @@ public static interface PluginFilter { public static Registry get() { // Need to handle the return value here, as it is a persistent object // i.e. the java proxy should not dispose of the underlying object when finalized - return GstObject.objectFor(GSTREGISTRY_API.gst_registry_get(), Registry.class, + return Natives.objectFor(GSTREGISTRY_API.gst_registry_get(), Registry.class, false, false); } diff --git a/src/org/freedesktop/gstreamer/SDPMessage.java b/src/org/freedesktop/gstreamer/SDPMessage.java index b82121aa..967f640d 100644 --- a/src/org/freedesktop/gstreamer/SDPMessage.java +++ b/src/org/freedesktop/gstreamer/SDPMessage.java @@ -21,9 +21,10 @@ import static org.freedesktop.gstreamer.lowlevel.GstSDPMessageAPI.GSTSDPMESSAGE_API; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.lowlevel.GPointer; /** * Wrapping type and helper methods for dealing with SDP messages. @@ -41,16 +42,20 @@ public class SDPMessage extends NativeObject { * @param init internal initialization data */ SDPMessage(Initializer init) { - super(init); + this(new Handle(init.ptr, init.ownsHandle)); } + SDPMessage(Handle handle) { + super(handle); + } + /** * Creates a new instance of SDPMessage */ public SDPMessage() { - this(initializer()); + this(initHandle()); } - + /** * A SDP formatted string representation of SDPMessage. * @@ -89,13 +94,22 @@ public void parseBuffer(String sdpString) { // return new SDPMessage(initializer(ptr[0])); // } - private static Initializer initializer() { + private static Handle initHandle() { Pointer[] ptr = new Pointer[1]; GSTSDPMESSAGE_API.gst_sdp_message_new(ptr); - return initializer(ptr[0]); + return new Handle(new GPointer(ptr[0]), true); } - protected void disposeNativeHandle(Pointer ptr) { - GSTSDPMESSAGE_API.gst_sdp_message_free(ptr); + private static final class Handle extends NativeObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GSTSDPMESSAGE_API.gst_sdp_message_free(ptr.getPointer()); + } + } } diff --git a/src/org/freedesktop/gstreamer/Structure.java b/src/org/freedesktop/gstreamer/Structure.java index 71c8129b..478b6ee9 100644 --- a/src/org/freedesktop/gstreamer/Structure.java +++ b/src/org/freedesktop/gstreamer/Structure.java @@ -27,7 +27,9 @@ import org.freedesktop.gstreamer.lowlevel.GType; import org.freedesktop.gstreamer.lowlevel.GValueAPI; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.lowlevel.GPointer; import org.freedesktop.gstreamer.lowlevel.GValueAPI.GValue; import static org.freedesktop.gstreamer.lowlevel.GstStructureAPI.GSTSTRUCTURE_API; @@ -72,7 +74,7 @@ public class Structure extends NativeObject { * @param name The name of new structure. */ public Structure(String name) { - this(GSTSTRUCTURE_API.ptr_gst_structure_new_empty(name)); + this(new Handle(new GPointer(GSTSTRUCTURE_API.ptr_gst_structure_new_empty(name)), true)); } /** @@ -85,16 +87,17 @@ public Structure(String name) { * @param data Additional arguments. */ public Structure(String name, String firstFieldName, Object... data) { - this(GSTSTRUCTURE_API.ptr_gst_structure_new(name, firstFieldName, data)); + this(new Handle(new GPointer(GSTSTRUCTURE_API.ptr_gst_structure_new(name, firstFieldName, data)), true)); } /** * Creates a new instance of Structure */ Structure(Initializer init) { - super(init); + this(new Handle(init.ptr, init.ownsHandle)); } - private Structure(Pointer ptr) { - this(initializer(ptr)); + + private Structure(Handle handle) { + super(handle); } public Structure copy() { @@ -597,10 +600,6 @@ public String toString() { return GSTSTRUCTURE_API.gst_structure_to_string(this); } - @Deprecated - protected void disposeNativeHandle(Pointer ptr) { - GSTSTRUCTURE_API.gst_structure_free(ptr); - } /** * Creates a Structure from a string representation. * @@ -608,11 +607,14 @@ protected void disposeNativeHandle(Pointer ptr) { * @return A new Structure or null when the string could not be parsed. */ public static Structure fromString(String data) { - return new Structure(GSTSTRUCTURE_API.ptr_gst_structure_from_string(data, new PointerByReference())); + return new Structure( + new Handle( + new GPointer(GSTSTRUCTURE_API.ptr_gst_structure_from_string(data, new PointerByReference())) + , true)); } static Structure objectFor(Pointer ptr, boolean needRef, boolean ownsHandle) { - return NativeObject.objectFor(ptr, Structure.class, needRef, ownsHandle); + return Natives.objectFor(ptr, Structure.class, needRef, ownsHandle); } public class InvalidFieldException extends RuntimeException { @@ -623,5 +625,17 @@ public InvalidFieldException(String type, String fieldName) { super(String.format("Structure does not contain %s field '%s'", type, fieldName)); } } + + private static final class Handle extends NativeObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + @Override + protected void disposeNativeHandle(GPointer ptr) { + GSTSTRUCTURE_API.gst_structure_free(ptr.getPointer()); + } + + } } diff --git a/src/org/freedesktop/gstreamer/TagList.java b/src/org/freedesktop/gstreamer/TagList.java index 9830f8e5..98951426 100644 --- a/src/org/freedesktop/gstreamer/TagList.java +++ b/src/org/freedesktop/gstreamer/TagList.java @@ -37,6 +37,8 @@ import com.sun.jna.Pointer; import com.sun.jna.ptr.PointerByReference; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; /** * List of tags and values used to describe media metadata. @@ -69,7 +71,7 @@ public TagList() { private static Initializer initializer() { final Pointer ptr_new_tag_list = GSTTAGLIST_API.ptr_gst_tag_list_new_empty(); - return initializer(ptr_new_tag_list); + return Natives.initializer(ptr_new_tag_list); } /** @@ -286,7 +288,8 @@ public Object get(TagList tl, String tag, int index) { if (value.getValue() == null) { return null; } - return new GDate(value.getValue(), false, true); +// return new GDate(value.getValue(), false, true); + return Natives.objectFor(value.getValue(), GDate.class); } }); put(DateTime.GTYPE, new TagGetter() { diff --git a/src/org/freedesktop/gstreamer/device/DeviceMonitor.java b/src/org/freedesktop/gstreamer/device/DeviceMonitor.java index 889d07ad..89a782db 100644 --- a/src/org/freedesktop/gstreamer/device/DeviceMonitor.java +++ b/src/org/freedesktop/gstreamer/device/DeviceMonitor.java @@ -25,6 +25,7 @@ import org.freedesktop.gstreamer.Bus; import org.freedesktop.gstreamer.Caps; import org.freedesktop.gstreamer.GstObject; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GlibAPI.GList; import static org.freedesktop.gstreamer.lowlevel.GstDeviceMonitorAPI.GSTDEVICEMONITOR_API; @@ -49,7 +50,7 @@ public class DeviceMonitor extends GstObject { public static final String GTYPE_NAME = "GstDeviceMonitor"; public DeviceMonitor() { - super(initializer(GSTDEVICEMONITOR_API.ptr_gst_device_monitor_new(), false, true)); + super(Natives.initializer(GSTDEVICEMONITOR_API.ptr_gst_device_monitor_new(), false, true)); } DeviceMonitor(Initializer init) { @@ -130,7 +131,7 @@ public List getDevices() { GList next = glist; while (next != null) { if (next.data != null) { - Device dev = new Device(initializer(next.data, false, true)); + Device dev = new Device(Natives.initializer(next.data, false, true)); list.add(dev); } next = next.next(); diff --git a/src/org/freedesktop/gstreamer/device/DeviceProvider.java b/src/org/freedesktop/gstreamer/device/DeviceProvider.java index 2e72c3bf..0afbc1da 100644 --- a/src/org/freedesktop/gstreamer/device/DeviceProvider.java +++ b/src/org/freedesktop/gstreamer/device/DeviceProvider.java @@ -24,6 +24,7 @@ import org.freedesktop.gstreamer.Bus; import org.freedesktop.gstreamer.GstObject; import org.freedesktop.gstreamer.Plugin; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GType; import org.freedesktop.gstreamer.lowlevel.GlibAPI; import org.freedesktop.gstreamer.lowlevel.GstDeviceProviderAPI; @@ -119,7 +120,7 @@ public List getDevices() { GlibAPI.GList next = glist; while (next != null) { if (next.data != null) { - Device dev = new Device(initializer(next.data, true, true)); + Device dev = new Device(Natives.initializer(next.data, true, true)); list.add(dev); } next = next.next(); diff --git a/src/org/freedesktop/gstreamer/device/DeviceProviderFactory.java b/src/org/freedesktop/gstreamer/device/DeviceProviderFactory.java index 1d334fb5..64d26d15 100644 --- a/src/org/freedesktop/gstreamer/device/DeviceProviderFactory.java +++ b/src/org/freedesktop/gstreamer/device/DeviceProviderFactory.java @@ -23,6 +23,7 @@ import java.util.List; import org.freedesktop.gstreamer.GstObject; import org.freedesktop.gstreamer.PluginFeature.Rank; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GlibAPI.GList; import static org.freedesktop.gstreamer.lowlevel.GstDeviceProviderFactoryAPI.GSTDEVICEPROVIDERFACTORY_API; @@ -129,7 +130,7 @@ public static List getDeviceProviders(Rank minRank) { while (next != null) { if (next.data != null) { DeviceProviderFactory factory = - new DeviceProviderFactory(initializer(next.data, true, true)); + new DeviceProviderFactory(Natives.initializer(next.data, true, true)); list.add(factory); } next = next.next(); diff --git a/src/org/freedesktop/gstreamer/elements/Elements.java b/src/org/freedesktop/gstreamer/elements/Elements.java new file mode 100644 index 00000000..97a887b0 --- /dev/null +++ b/src/org/freedesktop/gstreamer/elements/Elements.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.elements; + +import java.util.stream.Stream; +import org.freedesktop.gstreamer.glib.NativeObject; +import static org.freedesktop.gstreamer.glib.Natives.registration; + +/** + * + * @author Neil C Smith - https://www.neilcsmith.net + */ +public class Elements implements NativeObject.TypeProvider { + + @Override + public Stream> types() { + return Stream.of( + registration(AppSink.class, AppSink.GTYPE_NAME, AppSink::new), + registration(AppSrc.class, AppSrc.GTYPE_NAME, AppSrc::new), + registration(BaseSrc.class, BaseSrc.GTYPE_NAME, BaseSrc::new), + registration(BaseSink.class, BaseSink.GTYPE_NAME, BaseSink::new), + registration(BaseTransform.class, BaseTransform.GTYPE_NAME, BaseTransform::new), + registration(DecodeBin.class, DecodeBin.GTYPE_NAME, DecodeBin::new), + registration(PlayBin.class, PlayBin.GTYPE_NAME, PlayBin::new), + registration(URIDecodeBin.class, URIDecodeBin.GTYPE_NAME, URIDecodeBin::new)); + + } + +} diff --git a/src/org/freedesktop/gstreamer/event/BufferSizeEvent.java b/src/org/freedesktop/gstreamer/event/BufferSizeEvent.java index 5b152078..b31d51ee 100644 --- a/src/org/freedesktop/gstreamer/event/BufferSizeEvent.java +++ b/src/org/freedesktop/gstreamer/event/BufferSizeEvent.java @@ -22,6 +22,7 @@ package org.freedesktop.gstreamer.event; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; @@ -60,7 +61,7 @@ public class BufferSizeEvent extends Event { * @param async thread behaviour */ public BufferSizeEvent(Format format, long minsize, long maxsize, boolean async) { - super(initializer(GSTEVENT_API.ptr_gst_event_new_buffer_size(format, minsize, maxsize, async))); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_buffer_size(format, minsize, maxsize, async))); } /** diff --git a/src/org/freedesktop/gstreamer/event/CapsEvent.java b/src/org/freedesktop/gstreamer/event/CapsEvent.java index 12809d01..04b18406 100644 --- a/src/org/freedesktop/gstreamer/event/CapsEvent.java +++ b/src/org/freedesktop/gstreamer/event/CapsEvent.java @@ -19,6 +19,7 @@ package org.freedesktop.gstreamer.event; import org.freedesktop.gstreamer.Caps; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -46,6 +47,6 @@ public class CapsEvent extends Event { * Creates a new caps event. */ public CapsEvent(final Caps caps) { - super(initializer(GSTEVENT_API.ptr_gst_event_new_caps(caps))); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_caps(caps))); } } diff --git a/src/org/freedesktop/gstreamer/event/EOSEvent.java b/src/org/freedesktop/gstreamer/event/EOSEvent.java index 67645a14..cfc02c3b 100644 --- a/src/org/freedesktop/gstreamer/event/EOSEvent.java +++ b/src/org/freedesktop/gstreamer/event/EOSEvent.java @@ -23,6 +23,7 @@ import org.freedesktop.gstreamer.Bus; import org.freedesktop.gstreamer.FlowReturn; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -60,6 +61,6 @@ public class EOSEvent extends Event { * Creates a new EOS event. */ public EOSEvent() { - super(initializer(GSTEVENT_API.ptr_gst_event_new_eos())); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_eos())); } } diff --git a/src/org/freedesktop/gstreamer/event/Event.java b/src/org/freedesktop/gstreamer/event/Event.java index dce42fdd..9bfbaf2c 100644 --- a/src/org/freedesktop/gstreamer/event/Event.java +++ b/src/org/freedesktop/gstreamer/event/Event.java @@ -16,11 +16,17 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer.event; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; import org.freedesktop.gstreamer.MiniObject; import org.freedesktop.gstreamer.Structure; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.lowlevel.GstEventAPI; import org.freedesktop.gstreamer.lowlevel.ReferenceManager; import org.freedesktop.gstreamer.lowlevel.annotations.HasSubtype; @@ -33,37 +39,78 @@ * https://gstreamer.freedesktop.org/data/doc/gstreamer/stable/gstreamer/html/GstEvent.html *

- * Events are passed between elements in parallel to the data stream. Some events - * are serialized with buffers, others are not. Some events only travel downstream, - * others only upstream. Some events can travel both upstream and downstream. + * Events are passed between elements in parallel to the data stream. Some + * events are serialized with buffers, others are not. Some events only travel + * downstream, others only upstream. Some events can travel both upstream and + * downstream. *

* The events are used to signal special conditions in the datastream such as * EOS (end of stream) or the start of a new stream-segment. *

* Events are also used to flush the pipeline of any pending data. - * + * * @see Pad#pushEvent * @see Pad#sendEvent * @see Element#sendEvent */ @HasSubtype public class Event extends MiniObject { + public static final String GTYPE_NAME = "GstEvent"; + private static final Map> TYPE_MAP + = new EnumMap<>(EventType.class); + + static { + TYPE_MAP.put(EventType.BUFFERSIZE, BufferSizeEvent::new); + TYPE_MAP.put(EventType.EOS, EOSEvent::new); + TYPE_MAP.put(EventType.CAPS, CapsEvent::new); + TYPE_MAP.put(EventType.RECONFIGURE, ReconfigureEvent::new); + TYPE_MAP.put(EventType.STREAM_START, StreamStartEvent::new); + TYPE_MAP.put(EventType.LATENCY, LatencyEvent::new); + TYPE_MAP.put(EventType.FLUSH_START, FlushStartEvent::new); + TYPE_MAP.put(EventType.FLUSH_STOP, FlushStopEvent::new); + TYPE_MAP.put(EventType.NAVIGATION, NavigationEvent::new); + TYPE_MAP.put(EventType.SEGMENT, SegmentEvent::new); + TYPE_MAP.put(EventType.SEEK, SeekEvent::new); + TYPE_MAP.put(EventType.TAG, TagEvent::new); + TYPE_MAP.put(EventType.QOS, QOSEvent::new); + TYPE_MAP.put(EventType.STEP, StepEvent::new); + } + /** * This constructor is for internal use only. + * * @param init initialization data. */ - Event(Initializer init) { - super(init); + Event(Initializer init) { + super(init); } - + /** * Gets the structure containing the data in this event. - * + * * @return a structure. */ public Structure getStructure() { - return ReferenceManager.addKeepAliveReference(GSTEVENT_API.gst_event_get_structure(this), this); + return ReferenceManager.addKeepAliveReference(GSTEVENT_API.gst_event_get_structure(this), this); } + + private static Event create(Initializer init) { + GstEventAPI.EventStruct struct = new GstEventAPI.EventStruct(init.ptr.getPointer()); + EventType type = (EventType) struct.readField("type"); + return TYPE_MAP.getOrDefault(type, Event::new).apply(init); + } + + public static class Types implements TypeProvider { + + @Override + public Stream> types() { + return Stream.of( + Natives.registration(Event.class, GTYPE_NAME, Event::create) + ); + } + + } + } diff --git a/src/org/freedesktop/gstreamer/event/FlushStartEvent.java b/src/org/freedesktop/gstreamer/event/FlushStartEvent.java index 737435ec..af2424e4 100644 --- a/src/org/freedesktop/gstreamer/event/FlushStartEvent.java +++ b/src/org/freedesktop/gstreamer/event/FlushStartEvent.java @@ -23,6 +23,7 @@ import org.freedesktop.gstreamer.FlowReturn; import org.freedesktop.gstreamer.Pad; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -64,6 +65,6 @@ public class FlushStartEvent extends Event { * Creates a new flush start event. */ public FlushStartEvent() { - super(initializer(GSTEVENT_API.ptr_gst_event_new_flush_start())); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_flush_start())); } } diff --git a/src/org/freedesktop/gstreamer/event/FlushStopEvent.java b/src/org/freedesktop/gstreamer/event/FlushStopEvent.java index ec1936bb..9edfc852 100644 --- a/src/org/freedesktop/gstreamer/event/FlushStopEvent.java +++ b/src/org/freedesktop/gstreamer/event/FlushStopEvent.java @@ -21,6 +21,7 @@ */ package org.freedesktop.gstreamer.event; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -54,6 +55,6 @@ public class FlushStopEvent extends Event { * Creates a new flush stop event. */ public FlushStopEvent() { - super(initializer(GSTEVENT_API.ptr_gst_event_new_flush_stop())); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_flush_stop())); } } diff --git a/src/org/freedesktop/gstreamer/event/LatencyEvent.java b/src/org/freedesktop/gstreamer/event/LatencyEvent.java index 8514db95..8d7f1045 100644 --- a/src/org/freedesktop/gstreamer/event/LatencyEvent.java +++ b/src/org/freedesktop/gstreamer/event/LatencyEvent.java @@ -21,6 +21,7 @@ */ package org.freedesktop.gstreamer.event; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -54,7 +55,7 @@ public class LatencyEvent extends Event { * @param latency the new latency value to add to timestamps. */ public LatencyEvent(long latency) { - super(initializer(GSTEVENT_API.ptr_gst_event_new_latency(latency))); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_latency(latency))); } /** diff --git a/src/org/freedesktop/gstreamer/event/NavigationEvent.java b/src/org/freedesktop/gstreamer/event/NavigationEvent.java index 8ae8d2d9..fe71b903 100644 --- a/src/org/freedesktop/gstreamer/event/NavigationEvent.java +++ b/src/org/freedesktop/gstreamer/event/NavigationEvent.java @@ -22,6 +22,7 @@ package org.freedesktop.gstreamer.event; import org.freedesktop.gstreamer.Structure; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GType; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; @@ -50,7 +51,7 @@ public class NavigationEvent extends Event { * @param structure the description of the navigation event. */ public NavigationEvent(Structure structure) { - this(initializer(GSTEVENT_API.ptr_gst_event_new_navigation(structure))); + this(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_navigation(structure))); } /** diff --git a/src/org/freedesktop/gstreamer/event/QOSEvent.java b/src/org/freedesktop/gstreamer/event/QOSEvent.java index c6868179..1894ba41 100644 --- a/src/org/freedesktop/gstreamer/event/QOSEvent.java +++ b/src/org/freedesktop/gstreamer/event/QOSEvent.java @@ -21,6 +21,7 @@ */ package org.freedesktop.gstreamer.event; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -80,7 +81,7 @@ public class QOSEvent extends Event { * @param timestamp the timestamp of the buffer */ public QOSEvent(QOSType type, double proportion, long difference, long timestamp) { - super(initializer(GSTEVENT_API.ptr_gst_event_new_qos(type, proportion, difference, timestamp))); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_qos(type, proportion, difference, timestamp))); } /** diff --git a/src/org/freedesktop/gstreamer/event/ReconfigureEvent.java b/src/org/freedesktop/gstreamer/event/ReconfigureEvent.java index 6d6e0701..1693345c 100644 --- a/src/org/freedesktop/gstreamer/event/ReconfigureEvent.java +++ b/src/org/freedesktop/gstreamer/event/ReconfigureEvent.java @@ -18,6 +18,7 @@ */ package org.freedesktop.gstreamer.event; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -46,7 +47,7 @@ public class ReconfigureEvent extends Event { * Creates a new reconfigure event. */ public ReconfigureEvent() { - super(initializer(GSTEVENT_API.ptr_gst_event_new_reconfigure())); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_reconfigure())); } } diff --git a/src/org/freedesktop/gstreamer/event/SeekEvent.java b/src/org/freedesktop/gstreamer/event/SeekEvent.java index 79c79c30..21da6fec 100644 --- a/src/org/freedesktop/gstreamer/event/SeekEvent.java +++ b/src/org/freedesktop/gstreamer/event/SeekEvent.java @@ -25,6 +25,7 @@ import java.util.EnumSet; import org.freedesktop.gstreamer.Format; import org.freedesktop.gstreamer.glib.NativeFlags; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -88,7 +89,7 @@ public class SeekEvent extends Event { */ public SeekEvent(double rate, Format format, EnumSet flags, SeekType startType, long start, SeekType stopType, long stop) { - super(initializer(GSTEVENT_API.ptr_gst_event_new_seek(sanitizeRate(rate), format, + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_seek(sanitizeRate(rate), format, NativeFlags.toInt(flags), startType, start, stopType, stop))); } diff --git a/src/org/freedesktop/gstreamer/event/SegmentEvent.java b/src/org/freedesktop/gstreamer/event/SegmentEvent.java index 528c5d00..260f0341 100644 --- a/src/org/freedesktop/gstreamer/event/SegmentEvent.java +++ b/src/org/freedesktop/gstreamer/event/SegmentEvent.java @@ -23,6 +23,7 @@ import com.sun.jna.Pointer; import org.freedesktop.gstreamer.Segment; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstAPI; import org.freedesktop.gstreamer.lowlevel.GstAPI.GstSegmentStruct; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; @@ -77,7 +78,7 @@ public class SegmentEvent extends Event { * Allocates a new segment event with the given segment. */ SegmentEvent(GstSegmentStruct segment) { - this(initializer(GSTEVENT_API.ptr_gst_event_new_segment(segment))); + this(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_segment(segment))); } /** diff --git a/src/org/freedesktop/gstreamer/event/StepEvent.java b/src/org/freedesktop/gstreamer/event/StepEvent.java index 33c4d34a..223bc995 100644 --- a/src/org/freedesktop/gstreamer/event/StepEvent.java +++ b/src/org/freedesktop/gstreamer/event/StepEvent.java @@ -20,6 +20,7 @@ package org.freedesktop.gstreamer.event; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -62,6 +63,6 @@ public class StepEvent extends Event { * @param intermediate intermediate steps */ public StepEvent(Format format, long amount, double rate, boolean flush, boolean intermediate) { - super(initializer(GSTEVENT_API.ptr_gst_event_new_step(format, amount, rate, flush, intermediate))); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_step(format, amount, rate, flush, intermediate))); } } diff --git a/src/org/freedesktop/gstreamer/event/StreamStartEvent.java b/src/org/freedesktop/gstreamer/event/StreamStartEvent.java index 57a9ef71..cc5e6f4b 100644 --- a/src/org/freedesktop/gstreamer/event/StreamStartEvent.java +++ b/src/org/freedesktop/gstreamer/event/StreamStartEvent.java @@ -20,6 +20,7 @@ package org.freedesktop.gstreamer.event; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -45,6 +46,6 @@ public class StreamStartEvent extends Event { * @param stream_id identifier for this stream */ public StreamStartEvent(final String stream_id) { - super(initializer(GSTEVENT_API.ptr_gst_event_new_stream_start(stream_id))); + super(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_stream_start(stream_id))); } } \ No newline at end of file diff --git a/src/org/freedesktop/gstreamer/event/TagEvent.java b/src/org/freedesktop/gstreamer/event/TagEvent.java index 19a8d9ac..90cfad47 100644 --- a/src/org/freedesktop/gstreamer/event/TagEvent.java +++ b/src/org/freedesktop/gstreamer/event/TagEvent.java @@ -25,7 +25,8 @@ import org.freedesktop.gstreamer.lowlevel.ReferenceManager; import com.sun.jna.Pointer; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstEventAPI.GSTEVENT_API; /** @@ -61,7 +62,7 @@ public class TagEvent extends Event { * @param taglist the taglist to transmit with the event. */ public TagEvent(TagList taglist) { - this(initializer(GSTEVENT_API.ptr_gst_event_new_tag(taglist))); + this(Natives.initializer(GSTEVENT_API.ptr_gst_event_new_tag(taglist))); } /** @@ -76,7 +77,7 @@ public TagList getTagList() { Pointer[] taglist = new Pointer[1]; GSTEVENT_API.gst_event_parse_tag(this, taglist); // TagList tl = new TagList(taglistInitializer(taglist[0], false, false)); - TagList tl = NativeObject.objectFor(taglist[0], TagList.class, false, false); + TagList tl = Natives.objectFor(taglist[0], TagList.class, false, false); ReferenceManager.addKeepAliveReference(tl, this); return tl; } diff --git a/src/org/freedesktop/gstreamer/glib/GCancellable.java b/src/org/freedesktop/gstreamer/glib/GCancellable.java index 28492deb..a82ebd94 100644 --- a/src/org/freedesktop/gstreamer/glib/GCancellable.java +++ b/src/org/freedesktop/gstreamer/glib/GCancellable.java @@ -26,7 +26,7 @@ public class GCancellable extends GObject{ public static final String GTYPE_NAME = "GCancellable"; public GCancellable() { - this(initializer(GioAPI.g_cancellable_new())); + this(Natives.initializer(GioAPI.g_cancellable_new())); } private GCancellable(Initializer init) { diff --git a/src/org/freedesktop/gstreamer/glib/GDate.java b/src/org/freedesktop/gstreamer/glib/GDate.java index 51776057..e1831f06 100644 --- a/src/org/freedesktop/gstreamer/glib/GDate.java +++ b/src/org/freedesktop/gstreamer/glib/GDate.java @@ -22,9 +22,9 @@ import org.freedesktop.gstreamer.lowlevel.GType; import org.freedesktop.gstreamer.lowlevel.GlibAPI; -import org.freedesktop.gstreamer.lowlevel.NativeObject; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.lowlevel.GPointer; /** * Wrapper to the GDate data structure. @@ -36,24 +36,23 @@ public class GDate extends NativeObject { public static final String GTYPE_NAME = "GDate"; public static final GType GTYPE = GType.valueOf(GTYPE_NAME); - @Deprecated - public GDate(Initializer init) { - super(init); + GDate(Initializer init) { + this(new Handle(init.ptr, init.ownsHandle)); } - @Deprecated - public GDate(Pointer ptr, boolean needRef, boolean ownsHandle) { - this(initializer(ptr, needRef, ownsHandle)); + GDate(Handle handle) { + super(handle); } + public int getDay() { - return GlibAPI.GLIB_API.g_date_get_day(handle()); + return GlibAPI.GLIB_API.g_date_get_day(getRawPointer()); } public int getMonth() { - return GlibAPI.GLIB_API.g_date_get_month(handle()); + return GlibAPI.GLIB_API.g_date_get_month(getRawPointer()); } public int getYear() { - return GlibAPI.GLIB_API.g_date_get_year(handle()); + return GlibAPI.GLIB_API.g_date_get_year(getRawPointer()); } @Override @@ -61,16 +60,27 @@ public String toString() { return "" + getYear() + "-" + getMonth() + "-" + getDay(); } - @Override - protected void disposeNativeHandle(Pointer ptr) { - GlibAPI.GLIB_API.g_date_free(ptr); - } - public static GDate createInstance(int day, int month, int year) { - return new GDate(GlibAPI.GLIB_API.g_date_new_dmy(day, month , year), false, true); + Pointer ptr = GlibAPI.GLIB_API.g_date_new_dmy(day, month, year); + return new GDate(new Handle(new GPointer(ptr), true)); } public static GDate createInstance(int julian_day) { - return new GDate(GlibAPI.GLIB_API.g_date_new_julian(julian_day), false, true); + Pointer ptr = GlibAPI.GLIB_API.g_date_new_julian(julian_day); + return new GDate(new Handle(new GPointer(ptr), true)); } + + private static final class Handle extends NativeObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GlibAPI.GLIB_API.g_date_free(ptr.getPointer()); + } + + } + } diff --git a/src/org/freedesktop/gstreamer/glib/GInetAddress.java b/src/org/freedesktop/gstreamer/glib/GInetAddress.java index 7eca6fdf..856edf8f 100644 --- a/src/org/freedesktop/gstreamer/glib/GInetAddress.java +++ b/src/org/freedesktop/gstreamer/glib/GInetAddress.java @@ -25,13 +25,12 @@ public class GInetAddress extends GObject{ public static final String GTYPE_NAME = "GInetAddress"; - @Deprecated - public GInetAddress(Initializer init) { + GInetAddress(Initializer init) { super(init); } public String getAddress() { - return GioAPI.g_inet_address_to_string(getNativeAddress()); + return GioAPI.g_inet_address_to_string(getRawPointer()); } } diff --git a/src/org/freedesktop/gstreamer/glib/GInetSocketAddress.java b/src/org/freedesktop/gstreamer/glib/GInetSocketAddress.java index 189e85f7..ec1bba73 100644 --- a/src/org/freedesktop/gstreamer/glib/GInetSocketAddress.java +++ b/src/org/freedesktop/gstreamer/glib/GInetSocketAddress.java @@ -31,8 +31,7 @@ public GInetSocketAddress(String address, int port) { this(createRawAddress(address, port)); } - @Deprecated - public GInetSocketAddress(Initializer init) { + GInetSocketAddress(Initializer init) { super(init); } @@ -49,6 +48,6 @@ private static Initializer createRawAddress(String address, int port) { if (nativePointer == null) { throw new GLibException("Can not create "+GInetSocketAddress.class.getSimpleName()+" for "+address+":"+port+", please check that the IP address is valid, with format x.x.x.x"); } - return initializer(nativePointer); + return Natives.initializer(nativePointer); } } diff --git a/src/org/freedesktop/gstreamer/glib/GLib.java b/src/org/freedesktop/gstreamer/glib/GLib.java index 9ae2ada9..a123ceac 100644 --- a/src/org/freedesktop/gstreamer/glib/GLib.java +++ b/src/org/freedesktop/gstreamer/glib/GLib.java @@ -20,7 +20,9 @@ */ package org.freedesktop.gstreamer.glib; +import java.util.stream.Stream; import org.freedesktop.gstreamer.lowlevel.GlibAPI; +import static org.freedesktop.gstreamer.glib.Natives.registration; /** * Miscellaneous Utility Functions — a selection of portable utility functions from GLib @@ -89,4 +91,20 @@ public static String getEnv(String variable) { public static void unsetEnv(String variable) { GlibAPI.GLIB_API.g_unsetenv(variable); } + + public static class Types implements NativeObject.TypeProvider { + + @Override + public Stream> types() { + return Stream.of( + registration(GDate.class, GDate.GTYPE_NAME, GDate::new), + registration(GInetAddress.class, GInetAddress.GTYPE_NAME, GInetAddress::new), + registration(GSocket.class, GSocket.GTYPE_NAME, GSocket::new), + registration(GSocketAddress.class, GSocketAddress.GTYPE_NAME, GSocketAddress::new), + registration(GInetSocketAddress.class, GInetSocketAddress.GTYPE_NAME, GInetSocketAddress::new) + + ); + } + + } } diff --git a/src/org/freedesktop/gstreamer/glib/GObject.java b/src/org/freedesktop/gstreamer/glib/GObject.java index 0404267c..1f80a0d1 100644 --- a/src/org/freedesktop/gstreamer/glib/GObject.java +++ b/src/org/freedesktop/gstreamer/glib/GObject.java @@ -41,8 +41,6 @@ import org.freedesktop.gstreamer.lowlevel.GValueAPI.GValue; import org.freedesktop.gstreamer.lowlevel.GstTypes; import org.freedesktop.gstreamer.lowlevel.IntPtr; -import org.freedesktop.gstreamer.lowlevel.NativeObject; -import org.freedesktop.gstreamer.lowlevel.RefCountedObject; import com.sun.jna.Callback; import com.sun.jna.CallbackThreadInitializer; @@ -52,6 +50,10 @@ import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; import java.util.Arrays; +import org.freedesktop.gstreamer.MiniObject; +import org.freedesktop.gstreamer.lowlevel.GObjectPtr; +import org.freedesktop.gstreamer.lowlevel.GPointer; +import org.freedesktop.gstreamer.lowlevel.GstMiniObjectPtr; /** * GObject is the fundamental type providing the common attributes and methods @@ -71,26 +73,29 @@ public abstract class GObject extends RefCountedObject { = new ConcurrentHashMap(); private static final GObjectAPI.GToggleNotify TOGGLE_NOTIFY = new ToggleNotify(); - + private final Handle handle; private Map, Map> callbackListeners; - private final IntPtr objectID = new IntPtr(System.identityHashCode(this)); protected GObject(Initializer init) { - super(init.needRef ? initializer(init.ptr, false, init.ownsHandle) : init); - LOG.entering("GObject", "", init); - if (init.ownsHandle) { - final boolean is_floating = GOBJECT_API.g_object_is_floating(init.ptr); - LOG.fine(() -> String.format( + this(new Handle(init.ptr.as(GObjectPtr.class, GObjectPtr::new), init.ownsHandle), init.needRef); + } + + protected GObject(Handle handle, boolean needRef) { + super(handle); + this.handle = handle; + if (handle.ownsHandle()) { + final boolean is_floating = GOBJECT_API.g_object_is_floating(handle.getPointer()); + LOG.log(LIFECYCLE, () -> String.format( "Initialising owned handle for %s floating = %b refs = %d need ref = %b", this.getClass().getName(), is_floating, getRefCount(), - init.needRef)); + needRef)); - if (!init.needRef) { + if (!needRef) { if (is_floating) { // Sink floating ref - sink(); + handle.sink(); } } @@ -99,10 +104,10 @@ protected GObject(Initializer init) { STRONG_REFS.put(this, Boolean.TRUE); } - GOBJECT_API.g_object_add_toggle_ref(init.ptr, TOGGLE_NOTIFY, objectID); - if (!init.needRef) { + GOBJECT_API.g_object_add_toggle_ref(handle.getPointer(), TOGGLE_NOTIFY, handle.objectID); + if (!needRef) { // Toggle ref has created extra reference - unref(); + handle.unref(); } } } @@ -134,7 +139,7 @@ public synchronized T emit(Class resultType, String if (result == null) { return null; } else { - return NativeObject.objectFor(result, resultType, false, true); + return Natives.objectFor(result, resultType, false, true); } } @@ -188,10 +193,14 @@ public Object get(String property) { } else if (GVALUE_API.g_value_type_transformable(propType, GType.INT64)) { return GVALUE_API.g_value_get_int64(transform(propValue, GType.INT64)); } else if (propValue.checkHolds(GType.BOXED)) { + // @TODO we already know the GType here - optimise this! Class cls = GstTypes.classFor(propType); if (cls != null) { Pointer ptr = GVALUE_API.g_value_get_boxed(propValue); - return objectFor(ptr, cls, -1, true); + final GPointer gptr = GObject.class.isAssignableFrom(cls) ? new GObjectPtr(ptr) + : MiniObject.class.isAssignableFrom(cls) ? new GstMiniObjectPtr(ptr) + : new GPointer(ptr); + return objectFor(gptr, cls, -1, true); } } throw new IllegalArgumentException("Unknown conversion from GType=" + propType); @@ -276,29 +285,25 @@ public int getRefCount() { // Check if disposed as a disposed object may // have been free'd and we mustn't access it's // memory or we face possible SEGFAULT - if (!isDisposed()) { + GPointer ptr = handle.ptrRef.get(); + + if (ptr != null) { // final GObjectStruct struct = new GObjectStruct(this); // return struct.ref_count; // ref count is after pointer to GTypeInstance - return handle().getInt(Native.POINTER_SIZE); + int count = ptr.getPointer().getInt(Native.POINTER_SIZE); + return count; } return 0; } /** - * Gives the type value. - */ - @Deprecated - public GType getType() { - return GObject.getType(this.handle()); - } - - /** - * Gives the type name. + * Get the native GType type name. + * @return GType type name */ public String getTypeName() { - return this.getType().getTypeName(); + return handle.getPointer().getGType().getTypeName(); } public List listPropertyNames() { @@ -397,24 +402,23 @@ protected synchronized void addCallback(Class listenerClass, T listener, map.put(listener, cb); } - @Override - @Deprecated - protected void disposeNativeHandle(Pointer ptr) { - LOG.log(LIFECYCLE, "Removing toggle ref " + getClass().getSimpleName() + " (" + ptr + ")"); - GOBJECT_API.g_object_remove_toggle_ref(ptr, TOGGLE_NOTIFY, objectID); - STRONG_REFS.remove(this); - } - +// @Override +// @Deprecated +// protected void disposeNativeHandle(Pointer ptr) { +// LOG.log(LIFECYCLE, "Removing toggle ref " + getClass().getSimpleName() + " (" + ptr + ")"); +// GOBJECT_API.g_object_remove_toggle_ref(ptr, TOGGLE_NOTIFY, objectID); +// STRONG_REFS.remove(this); +// } @Override public void invalidate() { try { // Need to increase the ref count before removing the toggle ref, so // ensure the native object is not destroyed. - if (ownsHandle.get()) { - ref(); + if (handle.ownsHandle()) { + handle.ref(); // Disconnect the callback. - GOBJECT_API.g_object_remove_toggle_ref(handle(), TOGGLE_NOTIFY, objectID); + GOBJECT_API.g_object_remove_toggle_ref(handle.getPointer(), TOGGLE_NOTIFY, handle.objectID); } STRONG_REFS.remove(this); } finally { @@ -422,12 +426,6 @@ public void invalidate() { } } - @Override - @Deprecated - protected void ref() { - GOBJECT_API.g_object_ref(this); - } - protected synchronized void removeCallback(Class listenerClass, T listener) { final Map, Map> signals = getCallbackMap(); Map map = signals.get(listenerClass); @@ -445,26 +443,11 @@ protected synchronized void removeCallback(Class listenerClass, T listene } } - /** - * Sink floating reference. This will turn a floating reference into a real - * one. - */ - @Deprecated - protected void sink() { - GOBJECT_API.g_object_ref_sink(this.handle()); - } - - @Override - @Deprecated - protected void unref() { - GOBJECT_API.g_object_unref(this); - } - // public static T objectFor(Pointer ptr, Class defaultClass) { // return objectFor(ptr, defaultClass, true); // } private GObjectAPI.GParamSpec findProperty(String propertyName) { - Pointer ptr = GOBJECT_API.g_object_class_find_property(handle().getPointer(0), propertyName); + Pointer ptr = GOBJECT_API.g_object_class_find_property(getRawPointer().getPointer(0), propertyName); if (ptr == null) { return null; } @@ -472,7 +455,7 @@ private GObjectAPI.GParamSpec findProperty(String propertyName) { } private GObjectAPI.GParamSpecTypeSpecific findProperty(String propertyName, GType type) { - Pointer ptr = GOBJECT_API.g_object_class_find_property(handle().getPointer(0), propertyName); + Pointer ptr = GOBJECT_API.g_object_class_find_property(getRawPointer().getPointer(0), propertyName); if (type.equals(GType.INT)) { return new GObjectAPI.GParamSpecInt(ptr); } else if (type.equals(GType.UINT)) { @@ -510,7 +493,7 @@ private synchronized final Map, Map> getCallbackMap( private GObjectAPI.GParamSpec[] listProperties() { IntByReference len = new IntByReference(); - Pointer ptrs = GOBJECT_API.g_object_class_list_properties(handle().getPointer(0), len); + Pointer ptrs = GOBJECT_API.g_object_class_list_properties(getRawPointer().getPointer(0), len); if (ptrs == null) { return null; } @@ -524,20 +507,6 @@ private GObjectAPI.GParamSpec[] listProperties() { return props; } - @Deprecated - public static GType getType(Pointer ptr) { - // Quick getter for GType without allocation - // same as : new GObjectStruct(ptr).g_type_instance.g_class.g_type - Pointer g_class = ptr.getPointer(0); - if (Native.SIZE_T_SIZE == 8) { - return GType.valueOf(g_class.getLong(0)); - } else if (Native.SIZE_T_SIZE == 4) { - return GType.valueOf(((long) g_class.getInt(0)) & 0xffffffffL); - } else { - throw new IllegalStateException("SIZE_T size not supported: " + Native.SIZE_T_SIZE); - } - } - private static boolean booleanValue(Object value) { if (value instanceof Boolean) { return ((Boolean) value).booleanValue(); @@ -656,6 +625,20 @@ void remove() { // } } + /** + * Base interface for classes that implement a GInterface + */ + public static interface GInterface { + + /** + * Get the GObject implementing this interface. + * + * @return implementing GObject + */ + public GObject getGObject(); + + } + private final class SignalCallback extends GCallback { protected SignalCallback(String signal, Callback cb) { @@ -671,6 +654,55 @@ synchronized protected void disconnect() { } } + protected static class Handle extends RefCountedObject.Handle { + + private final IntPtr objectID; + + public Handle(GObjectPtr ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + this.objectID = new IntPtr(System.identityHashCode(this)); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GOBJECT_API.g_object_remove_toggle_ref((GObjectPtr) ptr, TOGGLE_NOTIFY, objectID); + } + + @Override + protected void ref() { + GOBJECT_API.g_object_ref(getPointer()); + } + + /** + * Sink floating reference. This will turn a floating reference into a + * real one. + */ + protected void sink() { + GOBJECT_API.g_object_ref_sink(getPointer()); + } + + @Override + protected void unref() { + GOBJECT_API.g_object_unref(getPointer()); + } + + @Override + protected GObjectPtr getPointer() { + return (GObjectPtr) super.getPointer(); + } + + @Override + public String toString() { + GObjectPtr ptr = getPointer(); + if (ptr != null) { + return ptr.getGType().getTypeName() + " : " + objectID; + } else { + return "Disposed handle"; + } + } + + } + private static final class ToggleNotify implements GObjectAPI.GToggleNotify { @Override diff --git a/src/org/freedesktop/gstreamer/glib/GSocket.java b/src/org/freedesktop/gstreamer/glib/GSocket.java index cbe73010..7ca4afe2 100644 --- a/src/org/freedesktop/gstreamer/glib/GSocket.java +++ b/src/org/freedesktop/gstreamer/glib/GSocket.java @@ -42,7 +42,10 @@ public GSocket bind(String address, int port) { GInetSocketAddress boundAddress = new GInetSocketAddress(address, port); GErrorStruct reference = new GErrorStruct(); GErrorStruct[] errorArray = (GErrorStruct[]) reference.toArray(1); - if ( ! GioAPI.g_socket_bind(getNativeAddress(), boundAddress.getNativeAddress(), true, reference.getPointer()) ) { + if ( ! GioAPI.g_socket_bind(getRawPointer(), + Natives.getRawPointer(boundAddress), + true, + reference.getPointer()) ) { throw new GLibException(extractAndClearError(errorArray[0])); } return this; @@ -52,7 +55,10 @@ public void connect(String address, int port) { GInetSocketAddress connectedAddress = new GInetSocketAddress(address, port); GErrorStruct reference = new GErrorStruct(); GErrorStruct[] errorArray = (GErrorStruct[]) reference.toArray(1); - if ( ! GioAPI.g_socket_connect(getNativeAddress(), connectedAddress.getNativeAddress(), new GCancellable().getNativeAddress(), reference.getPointer()) ) { + if ( ! GioAPI.g_socket_connect(getRawPointer(), + Natives.getRawPointer(connectedAddress), + Natives.getRawPointer(new GCancellable()), + reference.getPointer()) ) { throw new GLibException(extractAndClearError(errorArray[0])); } } @@ -100,7 +106,7 @@ private static Initializer makeRawSocket(GSocketFamily family, GSocketType type, if (socketPointer == null) { throw new GLibException(extractAndClearError(errorArray[0])); } - return initializer(socketPointer); + return Natives.initializer(socketPointer); } diff --git a/src/org/freedesktop/gstreamer/glib/NativeObject.java b/src/org/freedesktop/gstreamer/glib/NativeObject.java new file mode 100644 index 00000000..cfc159be --- /dev/null +++ b/src/org/freedesktop/gstreamer/glib/NativeObject.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2019 Neil C Smith + * 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.freedesktop.gstreamer.glib; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.sun.jna.Pointer; +import java.lang.ref.ReferenceQueue; +import java.util.Objects; +import java.util.ServiceLoader; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Stream; +import org.freedesktop.gstreamer.Gst; +import org.freedesktop.gstreamer.lowlevel.GPointer; +import org.freedesktop.gstreamer.lowlevel.GType; +import org.freedesktop.gstreamer.lowlevel.GTypedPtr; +import org.freedesktop.gstreamer.lowlevel.GstTypes; + +/** + * + */ +public abstract class NativeObject { + + private static final Level LIFECYCLE = Level.FINE; + private static final Logger LOG = Logger.getLogger(NativeObject.class.getName()); + private static final ConcurrentMap INSTANCES = new ConcurrentHashMap<>(); + + final Handle handle; + private final Pointer ptr; + private final NativeRef nativeRef; + +// /** +// * Creates a new instance of NativeObject +// */ + protected NativeObject(Handle handle) { + this.handle = Objects.requireNonNull(handle); + // + // Only store this object in the map if we can tell when it has been disposed + // (i.e. must be at least a GObject - MiniObject and other NativeObject subclasses + // don't signal destruction, so it is impossible to know if the instance + // is stale or not + // + this.ptr = handle.ptrRef.get().getPointer(); + this.nativeRef = new NativeRef(this, handle); +// if (GObject.class.isAssignableFrom(getClass())) { + + // need to put all nativeRef in map now so WeakReference doesn't go out of scope + INSTANCES.put(this.ptr, nativeRef); +// } + } + + /** + * Disown this object. The underlying native object will no longer be + * disposed of when this Java object is explicitly or implicitly disposed. + *

+ * The underlying reference will remain valid. + */ + public void disown() { + LOG.log(LIFECYCLE, "Disowning " + getRawPointer()); + handle.ownsHandle.set(false); + } + + /** + * Dispose this object, and potentially clear (free, unref, etc.) the + * underlying native object if this object owns the reference.# + *

+ * After calling this method this object should not be used. + */ + public void dispose() { + LOG.log(LIFECYCLE, "Disposing object " + getClass().getName() + " = " + handle); + handle.dispose(); + } + + @Override + public boolean equals(Object o) { + return o instanceof NativeObject && ((NativeObject) o).ptr.equals(ptr); + } + + protected GPointer getPointer() { + GPointer ptr = handle.ptrRef.get(); + if (ptr == null) { + throw new IllegalStateException("Native object has been disposed"); + } + return ptr; + } + + protected Pointer getRawPointer() { + GPointer ptr = handle.ptrRef.get(); + if (ptr == null) { + throw new IllegalStateException("Native object has been disposed"); + } + return ptr.getPointer(); + } + + @Override + public int hashCode() { + return ptr.hashCode(); + } + + /** + * Invalidate this object without clearing (free, unref, etc.) the + * underlying native object. + *

+ * After calling this method this object should not be used. + */ + public void invalidate() { + LOG.log(LIFECYCLE, () -> "Invalidating object " + this + " = " + getRawPointer()); + handle.invalidate(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "(" + getRawPointer() + ")"; + } + + static T objectFor(GPointer gptr, Class cls, int refAdjust, boolean ownsHandle) { + + // Ignore null pointers + if (gptr == null) { + return null; + } + + NativeObject obj = NativeObject.instanceFor(gptr.getPointer()); + + if (obj != null && cls.isInstance(obj)) { + if (refAdjust < 0) { + ((RefCountedObject.Handle) obj.handle).unref(); // Lose the extra ref added by gstreamer + } + return cls.cast(obj); + } + + final GType gtype = gptr instanceof GTypedPtr ? ((GTypedPtr) gptr).getGType() : null; + // + // For a GObject, MiniObject, ..., use the GType field to find the most + // exact class match + // + if (gtype != null) { + TypeRegistration reg = GstTypes.registrationFor(gtype); + if (reg != null) { + return cls.cast(reg.factory.apply( + new Initializer(gptr, refAdjust > 0, ownsHandle))); + } + } + + LOG.log(Level.FINE, () -> String.format("Unregistered type requested : %s", cls.getSimpleName())); + + try { + Constructor constructor = cls.getDeclaredConstructor(Initializer.class); + constructor.setAccessible(true); + T retVal = constructor.newInstance(new Initializer(gptr, refAdjust > 0, ownsHandle)); + //retVal.initNativeHandle(ptr, refAdjust > 0, ownsHandle); + return retVal; + } catch (SecurityException ex) { + throw new RuntimeException(ex); + } catch (IllegalAccessException ex) { + throw new RuntimeException(ex); + } catch (InstantiationException ex) { + throw new RuntimeException(ex); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); + } catch (InvocationTargetException ex) { + throw new RuntimeException(ex); + } + + } + + static NativeObject instanceFor(Pointer ptr) { + WeakReference ref = INSTANCES.get(ptr); + + // + // If the reference was there, but the object it pointed to had been collected, remove it from the map + // + if (ref != null && ref.get() == null) { + INSTANCES.remove(ptr); + } + return ref != null ? ref.get() : null; + } + + /** + * A class for propagating low level pointer arguments up the constructor + * chain. + * + * @see Natives#initializer(com.sun.jna.Pointer, boolean, boolean) + */ + public static final class Initializer { + + public final GPointer ptr; + public final boolean needRef, ownsHandle; + + Initializer(GPointer ptr, boolean needRef, boolean ownsHandle) { + this.ptr = ptr; + this.needRef = needRef; + this.ownsHandle = ownsHandle; + } + + } + + private static final class NativeRef extends WeakReference { + + private static final boolean REAP_ON_EDT = Boolean.getBoolean("glib.reapOnEDT"); + private static final ReferenceQueue QUEUE = new ReferenceQueue<>(); + private static final ExecutorService REAPER + = Executors.newSingleThreadExecutor((r) -> { + Thread t = new Thread(r, "NativeObject Reaper"); + t.setDaemon(true); + return t; + }); + + static { + REAPER.submit(() -> { + while (true) { + try { + NativeRef ref = (NativeRef) QUEUE.remove(); + LOG.log(LIFECYCLE, () -> "Disposing of " + ref.type + " : " + ref.handle.ptrRef.get()); + if (REAP_ON_EDT) { + Gst.invokeLater(ref.handle::dispose); + } else { + ref.handle.dispose(); + } + } catch (Throwable t) { + LOG.log(Level.WARNING, "Reaper thread exception", t); + } + } + }); + } + + private final Handle handle; + private final String type; + + private NativeRef(NativeObject obj, Handle handle) { + super(obj, QUEUE); + this.type = obj.getClass().getSimpleName(); + this.handle = handle; + } + + } + + /** + * A class for managing the underlying native pointer. + */ + protected static abstract class Handle { + + protected final AtomicReference ptrRef; + protected final AtomicBoolean ownsHandle; + + public Handle(GPointer ptr, boolean ownsHandle) { + this.ptrRef = new AtomicReference<>(ptr); + this.ownsHandle = new AtomicBoolean(ownsHandle); + } + + public void disown() { + ownsHandle.set(false); + } + + public void invalidate() { + GPointer ptr = ptrRef.getAndSet(null); + ownsHandle.set(false); + if (ptr != null) { + INSTANCES.remove(ptr.getPointer()); + } + } + + public void dispose() { + GPointer ptr = ptrRef.getAndSet(null); + if (ptr != null) { + INSTANCES.remove(ptr.getPointer()); + if (ownsHandle.compareAndSet(true, false)) { + disposeNativeHandle(ptr); + } + } + } + + public boolean isCacheable() { + return false; + } + + protected abstract void disposeNativeHandle(GPointer ptr); + + protected GPointer getPointer() { + return ptrRef.get(); + } + + protected boolean ownsHandle() { + return ownsHandle.get(); + } + } + + /** + * Registration for creating native object subclasses for specific GTypes. + * + * @see Natives#registration(java.lang.Class, java.lang.String, java.util.function.Function) + * @param type + */ + public static class TypeRegistration { + + private final Class javaType; + private final String gTypeName; + private final Function factory; + + TypeRegistration(Class javaType, String gTypeName, Function factory) { + this.javaType = javaType; + this.gTypeName = gTypeName; + this.factory = factory; + } + + public Class getJavaType() { + return javaType; + } + + public String getGTypeName() { + return gTypeName; + } + + public Function getFactory() { + return factory; + } + + } + + /** + * Register implementations of this interface via the {@link ServiceLoader} + * mechanism to provide new native object registrations externally. + */ + public static interface TypeProvider { + + /** + * A {@link Stream} of {@link TypeRegistration} to register. + * + * @return stream of type registrations + */ + public Stream> types(); + + } +} diff --git a/src/org/freedesktop/gstreamer/glib/Natives.java b/src/org/freedesktop/gstreamer/glib/Natives.java new file mode 100644 index 00000000..097e1028 --- /dev/null +++ b/src/org/freedesktop/gstreamer/glib/Natives.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.glib; + +import com.sun.jna.Pointer; +import java.util.ServiceLoader; +import java.util.function.Function; +import org.freedesktop.gstreamer.MiniObject; +import org.freedesktop.gstreamer.lowlevel.GObjectPtr; +import org.freedesktop.gstreamer.lowlevel.GPointer; +import org.freedesktop.gstreamer.lowlevel.GstMiniObjectPtr; + +/** + * Here be Dragons! + *

+ * This class provides utility functions for working with the underlying native + * bindings, creating {@link NativeObject} from pointers and extracting native + * pointers from NativeObjects. It should normally only be necessary to make use + * of these methods if extending the bindings externally or interacting with + * other native code. + */ +public final class Natives { + + private Natives() { + } + + /** + * Create a {@link NativeObject.Initializer} for the provided Pointer. + *

+ * This initializer will own the handle. + *

+ * This initializer will not request a ref increase (only relevant if used + * with instance of {@link RefCountedObject}) + * + * @param ptr native pointer + * @return initializer + */ + public static final NativeObject.Initializer initializer(Pointer ptr) { + NativeObject.Initializer initializer = initializer(ptr, false, true); + return initializer; + } + + /** + * Create a {@link NativeObject.Initializer} for the provided Pointer. + *

+ * This initializer will own the handle. + * + * @param ptr native pointer + * @param needRef whether to request a ref increase (only relevant if used + * with instance of {@link RefCountedObject}) + * @return initializer + */ + public static final NativeObject.Initializer initializer(Pointer ptr, boolean needRef) { + NativeObject.Initializer initializer = initializer(ptr, needRef, true); + return initializer; + } + + /** + * Create a {@link NativeObject.Initializer} for the provided Pointer. + * + * @param ptr native pointer + * @param needRef whether to request a ref increase (only relevant if used + * with instance of {@link RefCountedObject}) + * @param ownsHandle whether the NativeObject will own the handle, and + * should dispose of the native resource when GC'd or explicitly disposed. + * @return initializer + */ + public static final NativeObject.Initializer initializer(Pointer ptr, boolean needRef, boolean ownsHandle) { + if (ptr == null) { + throw new IllegalArgumentException("Invalid native pointer"); + } + return new NativeObject.Initializer(new GPointer(ptr), needRef, ownsHandle); + } + + /** + * Get a {@link NativeObject} instance of the requested type for the + * provided Pointer. Will return a cached instance if one already exists. + * + * @param NativeObject type to return + * @param ptr native Pointer + * @param cls Class of type T + * @return native object of type T + */ + public static T objectFor(Pointer ptr, Class cls) { + return objectFor(ptr, cls, true); + } + + /** + * Get a {@link NativeObject} instance of the requested type for the + * provided Pointer. Will return a cached instance if one already exists. + * + * @param NativeObject type to return + * @param ptr native Pointer + * @param cls Class of type T + * @param needRef whether to request a ref increase (only relevant if T is + * subclass of {@link RefCountedObject}) + * @return native object of type T + */ + public static T objectFor(Pointer ptr, Class cls, boolean needRef) { + return objectFor(ptr, cls, needRef, true); + } + + /** + * Get a {@link NativeObject} instance of the requested type for the + * provided Pointer. Will return a cached instance if one already exists. + * + * @param NativeObject type to return + * @param ptr native Pointer + * @param cls Class of type T + * @param needRef whether to request a ref increase (only relevant if T is + * subclass of {@link RefCountedObject}) + * @param ownsHandle whether the NativeObject will own the handle, and + * should dispose of the native resource when GC'd or explicitly disposed. + * @return native object of type T + */ + public static T objectFor(Pointer ptr, Class cls, boolean needRef, boolean ownsHandle) { + return objectFor(ptr, cls, needRef ? 1 : 0, ownsHandle); + } + + /** + * Get a {@link NativeObject} instance of the requested type for the + * provided Pointer, for use with native functions returning + * {@code Transfer Full} or {@code Transfer Floating} results. + *

+ * This method will return a cached instance if one already exists. If the + * cached instance is a {@link RefCountedObject} this method will release a + * reference. + * + * @param NativeObject type to return + * @param ptr native Pointer + * @param cls Class of type T + * @return native object of type T + */ + public static T callerOwnsReturn(Pointer ptr, Class cls) { + return objectFor(ptr, cls, -1, true); + } + + private static T objectFor(Pointer ptr, Class cls, int refAdjust, boolean ownsHandle) { + final GPointer gptr = GObject.class.isAssignableFrom(cls) ? new GObjectPtr(ptr) + : MiniObject.class.isAssignableFrom(cls) ? new GstMiniObjectPtr(ptr) + : new GPointer(ptr); + return NativeObject.objectFor(gptr, cls, refAdjust, ownsHandle); + } + + /** + * Get the underlying raw native Pointer for a {@link NativeObject}. + * + * @param obj native object + * @return native pointer + * @throws IllegalStateException if the native reference has been + * invalidated or disposed + */ + public static Pointer getRawPointer(NativeObject obj) { + return obj.getRawPointer(); + } + + /** + * Get the underlying native typed GPointer for a {@link NativeObject}. + * + * @param obj native object + * @return native typed pointer + * @throws IllegalStateException if the native reference has been + * invalidated or disposed + */ + public static GPointer getPointer(NativeObject obj) { + return obj.getPointer(); + } + + /** + * Increase the reference count of a {@link RefCountedObject} + * + * @param type of object + * @param obj object to increase reference count on + * @return object + */ + public static T ref(T obj) { + ((RefCountedObject.Handle) obj.handle).ref(); + return obj; + } + + /** + * Decrease the reference count of a {@link RefCountedObject} + * + * @param type of object + * @param obj object to decrease reference count on + * @return object + */ + public static T unref(T obj) { + ((RefCountedObject.Handle) obj.handle).unref(); + return obj; + } + + /** + * Create a {@link NativeObject.TypeRegistration} for linking + * {@link NativeObject} subclasses to GTypes. + *

+ * Be careful to respect the link between Java type hierarchy of registered + * classes and the underlying GType hierarchy. eg. if the GType is a + * subclass of GObject then the Java type must extend from {@link GObject} + *

+ * The factory function should normally be a constructor reference. + *

+ * Registrations can be provided externally using + * {@link NativeObject.TypeProvider} instances registered for use with + * {@link ServiceLoader} + * + * @param Java type + * @param javaType Java type class + * @param gTypeName name of the GType + * @param factory a factory function to return an instance of T given a + * {@link NativeObject.Initializer}. Normally a constructor reference - + * {@code T::new} + * @return registration + */ + public static NativeObject.TypeRegistration + registration(Class javaType, String gTypeName, Function factory) { + return new NativeObject.TypeRegistration<>(javaType, gTypeName, factory); + } + +} diff --git a/src/org/freedesktop/gstreamer/glib/RefCountedObject.java b/src/org/freedesktop/gstreamer/glib/RefCountedObject.java new file mode 100644 index 00000000..021ff738 --- /dev/null +++ b/src/org/freedesktop/gstreamer/glib/RefCountedObject.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 Neil C Smith + * Copyright (c) 2007, 2008 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.freedesktop.gstreamer.glib; + +import org.freedesktop.gstreamer.lowlevel.GPointer; + +/** + * A {@link NativeObject} that has an associated reference count + */ +public abstract class RefCountedObject extends NativeObject { + +// /** +// * Creates a new instance of RefCountedObject +// */ +// protected RefCountedObject(Initializer init) { +// this(new Handle()) +// if (init.ownsHandle && init.needRef) { +// ref(); +// } +// } + + protected RefCountedObject(Handle handle) { + super(handle); + + } + + protected RefCountedObject(Handle handle, boolean needRef) { + super(handle); + if (needRef) { + handle.ref(); + } + } + + + + // overridden in subclasses +// protected abstract void ref(); +// +// protected abstract void unref(); + + protected static abstract class Handle extends NativeObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + protected abstract void ref(); + + protected abstract void unref(); + + } +} diff --git a/src/org/freedesktop/gstreamer/interfaces/ColorBalance.java b/src/org/freedesktop/gstreamer/interfaces/ColorBalance.java index a132e15c..0c3d7bd1 100644 --- a/src/org/freedesktop/gstreamer/interfaces/ColorBalance.java +++ b/src/org/freedesktop/gstreamer/interfaces/ColorBalance.java @@ -25,7 +25,6 @@ import com.sun.jna.Pointer; import java.util.ArrayList; -import org.freedesktop.gstreamer.glib.GObject; import org.freedesktop.gstreamer.lowlevel.GlibAPI; import static org.freedesktop.gstreamer.lowlevel.GstColorBalanceAPI.GSTCOLORBALANCE_API; diff --git a/src/org/freedesktop/gstreamer/interfaces/ColorBalanceChannel.java b/src/org/freedesktop/gstreamer/interfaces/ColorBalanceChannel.java index dedb9453..1bd7c3f4 100644 --- a/src/org/freedesktop/gstreamer/interfaces/ColorBalanceChannel.java +++ b/src/org/freedesktop/gstreamer/interfaces/ColorBalanceChannel.java @@ -26,6 +26,7 @@ import org.freedesktop.gstreamer.lowlevel.GstColorBalanceAPI; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; public class ColorBalanceChannel extends GObject { public static final String GTYPE_NAME = "GstColorBalanceChannel"; @@ -38,14 +39,14 @@ public class ColorBalanceChannel extends GObject { * * @param init */ - public ColorBalanceChannel(Initializer init) { + ColorBalanceChannel(Initializer init) { super(init); throw new IllegalArgumentException("Cannot instantiate"); } ColorBalanceChannel(ColorBalance colorBalance, Pointer ptr, boolean needRef, boolean ownsHandle) { - super(initializer(ptr, needRef, ownsHandle)); + super(Natives.initializer(ptr, needRef, ownsHandle)); struct = new GstColorBalanceAPI.ColorBalanceChannelStruct(ptr); this.colorBalance = colorBalance; } diff --git a/src/org/freedesktop/gstreamer/interfaces/GstInterface.java b/src/org/freedesktop/gstreamer/interfaces/GstInterface.java index ad6fe9b8..5a0c6ad5 100644 --- a/src/org/freedesktop/gstreamer/interfaces/GstInterface.java +++ b/src/org/freedesktop/gstreamer/interfaces/GstInterface.java @@ -21,27 +21,23 @@ package org.freedesktop.gstreamer.interfaces; import org.freedesktop.gstreamer.lowlevel.GType; -import org.freedesktop.gstreamer.lowlevel.NativeValue; import org.freedesktop.gstreamer.Element; -import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.GObject; /** * Base type for all gstreamer interface proxies */ -public class GstInterface extends NativeValue { - protected final Pointer handle; +class GstInterface implements GObject.GInterface { protected final Element element; protected GstInterface(Element element, GType type) { this.element = element; - handle = element.getNativeAddress(); - } - protected Object nativeValue() { - return handle; - } - public Element getElement() { - return element; } + @Override + public Element getGObject() { + return element; + } + } diff --git a/src/org/freedesktop/gstreamer/lowlevel/GMainContext.java b/src/org/freedesktop/gstreamer/lowlevel/GMainContext.java index b036f498..c61d92f2 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GMainContext.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GMainContext.java @@ -20,34 +20,49 @@ package org.freedesktop.gstreamer.lowlevel; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.glib.RefCountedObject; import static org.freedesktop.gstreamer.lowlevel.GlibAPI.GLIB_API; /** * */ public class GMainContext extends RefCountedObject { + public GMainContext() { - this(initializer(GLIB_API.g_main_context_new())); + this(Natives.initializer(GLIB_API.g_main_context_new())); } private GMainContext(Initializer init) { - super(init); + super(new Handle(init.ptr, init.ownsHandle), init.needRef); } + public int attach(GSource source) { return GLIB_API.g_source_attach(source, this); } public static GMainContext getDefaultContext() { - return new GMainContext(initializer(GLIB_API.g_main_context_default(), false, false)); + return new GMainContext(Natives.initializer(GLIB_API.g_main_context_default(), false, false)); } - protected void ref() { - GLIB_API.g_main_context_ref(handle()); - } - protected void unref() { - GLIB_API.g_main_context_unref(handle()); - } + private static final class Handle extends RefCountedObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GLIB_API.g_main_context_unref(ptr); + } + + @Override + protected void ref() { + GLIB_API.g_main_context_ref(getPointer()); + } - @Override - protected void disposeNativeHandle(Pointer ptr) { - GLIB_API.g_main_context_unref(ptr); + @Override + protected void unref() { + GLIB_API.g_main_context_unref(getPointer()); + } + } } diff --git a/src/org/freedesktop/gstreamer/lowlevel/GObjectAPI.java b/src/org/freedesktop/gstreamer/lowlevel/GObjectAPI.java index 43f3f39a..03701de0 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GObjectAPI.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GObjectAPI.java @@ -63,25 +63,26 @@ interface GClosureNotify extends Callback { NativeLong g_signal_connect_data(GObject obj, String signal, Callback callback, Pointer data, GClosureNotify destroy_data, int connect_flags); void g_signal_handler_disconnect(GObject obj, NativeLong id); - boolean g_object_is_floating(Pointer obj); + boolean g_object_is_floating(GObjectPtr obj); /** Sink floating ref * https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-ref-sink */ Pointer g_object_ref_sink(Pointer ptr); + GObjectPtr g_object_ref_sink(GObjectPtr ptr); interface GToggleNotify extends Callback { void callback(Pointer data, Pointer obj, boolean is_last_ref); } void g_object_add_toggle_ref(Pointer object, GToggleNotify notify, Pointer data); void g_object_remove_toggle_ref(Pointer object, GToggleNotify notify, Pointer data); - void g_object_add_toggle_ref(Pointer object, GToggleNotify notify, IntPtr data); - void g_object_remove_toggle_ref(Pointer object, GToggleNotify notify, IntPtr data); + void g_object_add_toggle_ref(GObjectPtr object, GToggleNotify notify, IntPtr data); + void g_object_remove_toggle_ref(GObjectPtr object, GToggleNotify notify, IntPtr data); interface GWeakNotify extends Callback { void callback(IntPtr data, Pointer obj); } void g_object_weak_ref(GObject object, GWeakNotify notify, IntPtr data); void g_object_weak_unref(GObject object, GWeakNotify notify, IntPtr data); - Pointer g_object_ref(GObject object); - void g_object_unref(GObject object); + Pointer g_object_ref(GObjectPtr object); + void g_object_unref(GObjectPtr object); GParamSpec g_object_class_find_property(GObjectClass oclass, String property_name); Pointer g_object_class_find_property(Pointer oclass, String property_name); @@ -149,11 +150,8 @@ public static final class GObjectStruct extends com.sun.jna.Structure { public volatile int ref_count; public volatile Pointer qdata; public GObjectStruct() {} - public GObjectStruct(GObject obj) { - this(obj.handle()); - } - public GObjectStruct(Pointer ptr) { - super(ptr); + public GObjectStruct(GObjectPtr ptr) { + super(ptr.getPointer()); read(); } diff --git a/src/org/freedesktop/gstreamer/lowlevel/GObjectPtr.java b/src/org/freedesktop/gstreamer/lowlevel/GObjectPtr.java new file mode 100644 index 00000000..dfed07d5 --- /dev/null +++ b/src/org/freedesktop/gstreamer/lowlevel/GObjectPtr.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.lowlevel; + +import com.sun.jna.Native; +import com.sun.jna.Pointer; + +/** + * Base GObject pointer + */ +public class GObjectPtr extends GTypedPtr { + + public GObjectPtr() { + } + + public GObjectPtr(Pointer ptr) { + super(ptr); + } + + @Override + public GType getGType() { + // Quick getter for GType without allocation + // same as : new GObjectStruct(ptr).g_type_instance.g_class.g_type + Pointer g_class = getPointer().getPointer(0); + if (Native.SIZE_T_SIZE == 8) { + return GType.valueOf(g_class.getLong(0)); + } else if (Native.SIZE_T_SIZE == 4) { + return GType.valueOf(((long) g_class.getInt(0)) & 0xffffffffL); + } else { + throw new IllegalStateException("SIZE_T size not supported: " + Native.SIZE_T_SIZE); + } + } + +} diff --git a/src/org/freedesktop/gstreamer/lowlevel/GPointer.java b/src/org/freedesktop/gstreamer/lowlevel/GPointer.java new file mode 100644 index 00000000..6ab4d9b0 --- /dev/null +++ b/src/org/freedesktop/gstreamer/lowlevel/GPointer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.lowlevel; + +import com.sun.jna.Pointer; +import com.sun.jna.PointerType; +import java.util.function.Function; + +/** + * Base GLib pointer + */ +public class GPointer extends PointerType { + + public GPointer() { + } + + public GPointer(Pointer ptr) { + super(ptr); + } + + public T as(Class cls, Function converter) { + if (cls.isInstance(this)) { + return cls.cast(this); + } else { + return converter.apply(this.getPointer()); + } + } + +} diff --git a/src/org/freedesktop/gstreamer/lowlevel/GSource.java b/src/org/freedesktop/gstreamer/lowlevel/GSource.java index 731ac2ca..2b396a4a 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GSource.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GSource.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Neil C Smith * Copyright (c) 2007 Wayne Meissner * * This file is part of gstreamer-java. @@ -23,21 +24,24 @@ import java.util.concurrent.Callable; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.RefCountedObject; /** * */ public class GSource extends RefCountedObject { public GSource(Initializer init) { - super(init); + super(new Handle(init.ptr, init.ownsHandle), init.needRef); } + public int attach(GMainContext context) { return GLIB_API.g_source_attach(this, context); } + public void setCallback(final Callable call) { this.callback = new GlibAPI.GSourceFunc() { public boolean callback(Pointer data) { - if (GLIB_API.g_source_is_destroyed(handle())) { + if (GLIB_API.g_source_is_destroyed(getRawPointer())) { return false; } try { @@ -49,18 +53,30 @@ public boolean callback(Pointer data) { }; GLIB_API.g_source_set_callback(this, callback, null, null); } + private GlibAPI.GSourceFunc callback; - protected void ref() { - GLIB_API.g_source_ref(handle()); - } - protected void unref() { - GLIB_API.g_source_unref(handle()); - } + private static final class Handle extends RefCountedObject.Handle { + + Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GLIB_API.g_source_destroy(ptr.getPointer()); + GLIB_API.g_source_unref(ptr.getPointer()); + } + + @Override + protected void ref() { + GLIB_API.g_source_ref(ptrRef.get().getPointer()); + } - @Override - protected void disposeNativeHandle(Pointer ptr) { - GLIB_API.g_source_destroy(ptr); - GLIB_API.g_source_unref(ptr); + @Override + protected void unref() { + GLIB_API.g_source_unref(ptrRef.get().getPointer()); + } + } } diff --git a/src/org/freedesktop/gstreamer/lowlevel/GTypeMapper.java b/src/org/freedesktop/gstreamer/lowlevel/GTypeMapper.java index df470119..d0b9b2aa 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GTypeMapper.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GTypeMapper.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Neil C Smith * Copyright (c) 2007 Wayne Meissner * * This file is part of gstreamer-java. @@ -21,10 +22,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.URI; -import java.util.concurrent.TimeUnit; - -import org.freedesktop.gstreamer.ClockTime; -import org.freedesktop.gstreamer.query.QueryType; import org.freedesktop.gstreamer.glib.GQuark; import org.freedesktop.gstreamer.lowlevel.annotations.CallerOwnsReturn; import org.freedesktop.gstreamer.lowlevel.annotations.ConstField; @@ -43,6 +40,10 @@ import com.sun.jna.ToNativeContext; import com.sun.jna.ToNativeConverter; import com.sun.jna.TypeConverter; +import org.freedesktop.gstreamer.glib.GObject; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.glib.RefCountedObject; /** * @@ -53,10 +54,10 @@ public class GTypeMapper extends com.sun.jna.DefaultTypeMapper { public GTypeMapper() { addToNativeConverter(URI.class, uriConverter); } - private static ToNativeConverter nativeValueArgumentConverter = new ToNativeConverter() { + private static ToNativeConverter interfaceConverter = new ToNativeConverter() { public Object toNative(Object arg, ToNativeContext context) { - return arg != null ? ((NativeValue) arg).nativeValue() : null; + return arg != null ? Natives.getRawPointer(((GObject.GInterface) arg).getGObject()) : null; } public Class nativeType() { @@ -69,7 +70,7 @@ public Object toNative(Object arg, ToNativeContext context) { if (arg == null) { return null; } - Pointer ptr = ((NativeObject) arg).handle(); + Pointer ptr = Natives.getRawPointer((NativeObject) arg); // // Deal with any adjustments to the proxy neccessitated by gstreamer @@ -84,11 +85,10 @@ public Object toNative(Object arg, ToNativeContext context) { Annotation[] annotations = parameterAnnotations[index]; for (int i = 0; i < annotations.length; ++i) { if (annotations[i] instanceof Invalidate) { - ((Handle) arg).invalidate(); + ((NativeObject) arg).invalidate(); break; } else if (annotations[i] instanceof IncRef) { - ((RefCountedObject) arg).ref(); - break; + Natives.ref((RefCountedObject) arg); } } } @@ -107,16 +107,23 @@ public Object fromNative(Object result, FromNativeContext context) { // returned from functions, so drop a ref here // boolean ownsHandle = ((MethodResultContext) context).getMethod().isAnnotationPresent(CallerOwnsReturn.class); - int refadj = ownsHandle ? -1 : 0; - return NativeObject.objectFor((Pointer) result, (Class) context.getTargetType(), refadj, ownsHandle); +// int refadj = ownsHandle ? -1 : 0; +// return NativeObject.objectFor((Pointer) result, (Class) context.getTargetType(), refadj, ownsHandle); + if (ownsHandle) { + return Natives.callerOwnsReturn((Pointer) result, (Class) context.getTargetType()); + } else { + return Natives.objectFor((Pointer) result, (Class) context.getTargetType(), false, false); + } } if (context instanceof CallbackParameterContext) { - return NativeObject.objectFor((Pointer) result, (Class) context.getTargetType(), 1, true); +// return NativeObject.objectFor((Pointer) result, (Class) context.getTargetType(), 1, true); + return Natives.objectFor((Pointer) result, (Class) context.getTargetType(), true, true); } if (context instanceof StructureReadContext) { StructureReadContext sctx = (StructureReadContext) context; boolean ownsHandle = sctx.getField().getAnnotation(ConstField.class) == null; - return NativeObject.objectFor((Pointer) result, (Class) context.getTargetType(), 1, ownsHandle); +// return NativeObject.objectFor((Pointer) result, (Class) context.getTargetType(), 1, ownsHandle); + return Natives.objectFor((Pointer) result, (Class) context.getTargetType(), true, true); } throw new IllegalStateException("Cannot convert to NativeObject from " + context); } @@ -275,8 +282,8 @@ public FromNativeConverter getFromNativeConverter(Class type) { public ToNativeConverter getToNativeConverter(Class type) { if (NativeObject.class.isAssignableFrom(type)) { return nativeObjectConverter; - } else if (NativeValue.class.isAssignableFrom(type)) { - return nativeValueArgumentConverter; + } else if (GObject.GInterface.class.isAssignableFrom(type)) { + return interfaceConverter; } else if (Enum.class.isAssignableFrom(type)) { return enumConverter; } else if (Boolean.class == type || boolean.class == type) { diff --git a/src/org/freedesktop/gstreamer/lowlevel/GTypedPtr.java b/src/org/freedesktop/gstreamer/lowlevel/GTypedPtr.java new file mode 100644 index 00000000..ad84312c --- /dev/null +++ b/src/org/freedesktop/gstreamer/lowlevel/GTypedPtr.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.lowlevel; + +import com.sun.jna.Pointer; + +/** + * Base GLib pointer with GType + */ +public abstract class GTypedPtr extends GPointer { + + public GTypedPtr() { + } + + public GTypedPtr(Pointer ptr) { + super(ptr); + } + + public abstract GType getGType(); + +} diff --git a/src/org/freedesktop/gstreamer/lowlevel/GValueAPI.java b/src/org/freedesktop/gstreamer/lowlevel/GValueAPI.java index 16d34007..bd2562f1 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GValueAPI.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GValueAPI.java @@ -32,6 +32,8 @@ import com.sun.jna.Library; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; /** * @@ -168,7 +170,8 @@ public Object getValue() { Class cls = GstTypes.classFor(g_type); if (cls != null) { Pointer ptr = GVALUE_API.g_value_get_boxed(this); - return NativeObject.objectFor(ptr, cls, 1, true); +// return NativeObject.objectFor(ptr, cls, 1, true); + return Natives.objectFor(ptr, cls, true, true); } } return GVALUE_API.g_value_get_object(this); diff --git a/src/org/freedesktop/gstreamer/lowlevel/GlibAPI.java b/src/org/freedesktop/gstreamer/lowlevel/GlibAPI.java index 8a23c353..035e71a3 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GlibAPI.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GlibAPI.java @@ -49,17 +49,16 @@ public interface GlibAPI extends Library { boolean g_main_loop_is_running(MainLoop loop); @CallerOwnsReturn GMainContext g_main_loop_get_context(MainLoop loop); void g_main_loop_quit(MainLoop loop); - void g_main_loop_ref(MainLoop ptr); - void g_main_loop_unref(MainLoop ptr); - void g_main_loop_unref(Pointer ptr); + void g_main_loop_ref(GPointer ptr); + void g_main_loop_unref(GPointer ptr); /* * GMainContext functions */ Pointer g_main_context_new(); - void g_main_context_ref(Pointer context); - void g_main_context_unref(Pointer context); + void g_main_context_ref(GPointer context); + void g_main_context_unref(GPointer context); Pointer g_main_context_default(); boolean g_main_context_pending(GMainContext ctx); boolean g_main_context_acquire(GMainContext ctx); diff --git a/src/org/freedesktop/gstreamer/lowlevel/GstClockAPI.java b/src/org/freedesktop/gstreamer/lowlevel/GstClockAPI.java index 8b4f3064..477ca09e 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GstClockAPI.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GstClockAPI.java @@ -58,8 +58,9 @@ void gst_clock_get_calibration(Clock clock, long[] internal, long[] external, /* reference counting */ void gst_clock_id_ref(ClockID id); + void gst_clock_id_ref(GPointer id); void gst_clock_id_unref(ClockID id); - void gst_clock_id_unref(Pointer id); + void gst_clock_id_unref(GPointer id); /* operations on IDs */ int gst_clock_id_compare_func(ClockID id1, ClockID id2); diff --git a/src/org/freedesktop/gstreamer/lowlevel/GstMiniObjectAPI.java b/src/org/freedesktop/gstreamer/lowlevel/GstMiniObjectAPI.java index 0c5c4f98..f3b91ab6 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GstMiniObjectAPI.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GstMiniObjectAPI.java @@ -38,8 +38,8 @@ public interface GstMiniObjectAPI extends com.sun.jna.Library { GstMiniObjectAPI GSTMINIOBJECT_API = GstNative.load(GstMiniObjectAPI.class); - void gst_mini_object_ref(MiniObject ptr); - void gst_mini_object_unref(MiniObject ptr); + void gst_mini_object_ref(GstMiniObjectPtr ptr); + void gst_mini_object_unref(GstMiniObjectPtr ptr); void gst_mini_object_unref(Pointer ptr); @CallerOwnsReturn MiniObject gst_mini_object_make_writable(@Invalidate MiniObject mini_object); diff --git a/src/org/freedesktop/gstreamer/lowlevel/GstMiniObjectPtr.java b/src/org/freedesktop/gstreamer/lowlevel/GstMiniObjectPtr.java new file mode 100644 index 00000000..c2bffad8 --- /dev/null +++ b/src/org/freedesktop/gstreamer/lowlevel/GstMiniObjectPtr.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.lowlevel; + +import com.sun.jna.Native; +import com.sun.jna.Pointer; + +/** + * Base MiniObject pointer + */ +public class GstMiniObjectPtr extends GTypedPtr { + + public GstMiniObjectPtr() { + } + + public GstMiniObjectPtr(Pointer ptr) { + super(ptr); + } + + @Override + public GType getGType() { + // Quick getter for GType without allocation + // same as : new MiniObjectStruct(ptr).type + if (Native.SIZE_T_SIZE == 8) { + return GType.valueOf(getPointer().getLong(0)); + } else if (Native.SIZE_T_SIZE == 4) { + return GType.valueOf( ((long) getPointer().getInt(0)) & 0xffffffffL ); + } else { + throw new IllegalStateException("SIZE_T size not supported: " + Native.SIZE_T_SIZE); + } + } + +} diff --git a/src/org/freedesktop/gstreamer/lowlevel/GstObjectAPI.java b/src/org/freedesktop/gstreamer/lowlevel/GstObjectAPI.java index 59846a6b..bba263dc 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GstObjectAPI.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GstObjectAPI.java @@ -41,9 +41,9 @@ public interface GstObjectAPI extends com.sun.jna.Library { GstObjectAPI GSTOBJECT_API = GstNative.load(GstObjectAPI.class); GType gst_object_get_type(); - void gst_object_ref(GstObject ptr); - void gst_object_unref(GstObject ptr); - void gst_object_ref_sink(GstObject ptr); + void gst_object_ref(GstObjectPtr ptr); + void gst_object_unref(GstObjectPtr ptr); + void gst_object_ref_sink(GstObjectPtr ptr); boolean gst_object_set_name(GstObject obj, String name); @FreeReturnValue String gst_object_get_name(GstObject obj); diff --git a/src/org/freedesktop/gstreamer/lowlevel/GstObjectPtr.java b/src/org/freedesktop/gstreamer/lowlevel/GstObjectPtr.java new file mode 100644 index 00000000..e1d2edfb --- /dev/null +++ b/src/org/freedesktop/gstreamer/lowlevel/GstObjectPtr.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.lowlevel; + +import com.sun.jna.Pointer; + +/** + * Base GObject pointer + */ +public class GstObjectPtr extends GObjectPtr { + + public GstObjectPtr() { + } + + public GstObjectPtr(Pointer ptr) { + super(ptr); + } + +} diff --git a/src/org/freedesktop/gstreamer/lowlevel/GstTypes.java b/src/org/freedesktop/gstreamer/lowlevel/GstTypes.java index 737ea986..a4c15337 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/GstTypes.java +++ b/src/org/freedesktop/gstreamer/lowlevel/GstTypes.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Neil C Smith * Copyright (c) 2016 Christophe Lafolet * Copyright (c) 2009 Levente Farkas * Copyright (c) 2008 Andres Colubri @@ -18,73 +19,85 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer.lowlevel; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject.TypeRegistration; /** * */ public class GstTypes { + private static final Logger logger = Logger.getLogger(GstTypes.class.getName()); - private static final Map> gtypeNameMap - = new ConcurrentHashMap>(); +// private static final Map> gtypeNameMap +// = new ConcurrentHashMap>(); + private static final Map> TYPES + = new ConcurrentHashMap<>(); + + private GstTypes() { + } - private GstTypes() {} - /** * Register a class with its GType name */ - public static void registerType(Class cls, String gTypeName) { - gtypeNameMap.put(gTypeName, cls); +// public static void registerType(Class cls, String gTypeName) { +// gtypeNameMap.put(gTypeName, cls); +// } + public static void register(TypeRegistration registration) { + TYPES.putIfAbsent(registration.getGTypeName(), registration); } - + /** * Retrieve the class of a GType * * @param gType The type of Class * @return The Class of the desired type or null. */ - public static final Class classFor(final GType gType) { - final String gTypeName = gType.getTypeName(); + public static final TypeRegistration registrationFor(final GType gType) { + final String gTypeName = gType.getTypeName(); - // Is this GType still registered in the map ? - Class cls = gtypeNameMap.get(gTypeName); - if (cls != null) { - return cls; + // Is this GType still registered in the map ? + TypeRegistration reg = TYPES.get(gTypeName); + if (reg != null) { + return reg; } // Search for a parent class registration GType type = gType.getParentType(); while (!type.equals(GType.OBJECT) && !type.equals(GType.POINTER) && !type.equals(GType.INVALID)) { - cls = gtypeNameMap.get(type.getTypeName()); - if (cls != null) { + reg = TYPES.get(type.getTypeName()); + if (reg != null) { if (GstTypes.logger.isLoggable(Level.FINER)) { - GstTypes.logger.finer("Found type of " + gType + " = " + cls); + GstTypes.logger.finer("Found type of " + gType + " = " + reg.getJavaType()); } - + // The following line is an optimisation but not compatible with current implementation of GstTypes.typeFor() // Uncomment the following line after refactoring of GstTypes.typeFor() // gtypeNameMap.put(gTypeName, cls); - - return cls; + return reg; } - type = type.getParentType(); + type = type.getParentType(); } // No registered class found for this gType return null; } + + public static final Class classFor(final GType gType) { + TypeRegistration reg = registrationFor(gType); + return reg != null ? reg.getJavaType() : null; + } //TODO : need refactoring to take into account derived class public static final GType typeFor(Class cls) { - for (Map.Entry> e : gtypeNameMap.entrySet()) { - if (e.getValue().equals(cls)) { + for (Map.Entry> e : TYPES.entrySet()) { + if (e.getValue().getJavaType().equals(cls)) { return GType.valueOf(e.getKey()); } } diff --git a/src/org/freedesktop/gstreamer/lowlevel/Handle.java b/src/org/freedesktop/gstreamer/lowlevel/Handle.java deleted file mode 100644 index 73368ad9..00000000 --- a/src/org/freedesktop/gstreamer/lowlevel/Handle.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.freedesktop.gstreamer.lowlevel; - -/** - * - */ -abstract public class Handle extends NativeValue { - - public Handle() { - } - abstract protected void invalidate(); -} diff --git a/src/org/freedesktop/gstreamer/lowlevel/MainLoop.java b/src/org/freedesktop/gstreamer/lowlevel/MainLoop.java index 52169768..613624e6 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/MainLoop.java +++ b/src/org/freedesktop/gstreamer/lowlevel/MainLoop.java @@ -15,7 +15,6 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer.lowlevel; import static org.freedesktop.gstreamer.lowlevel.GlibAPI.GLIB_API; @@ -29,37 +28,45 @@ import org.freedesktop.gstreamer.Gst; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.glib.RefCountedObject; /** * The GLib main loop. */ public class MainLoop extends RefCountedObject { + private static final List bgTasks = new LinkedList(); - - /** + + private Thread bgThread; + + /** * Creates a new instance of {@code MainLoop} - * - *

This will create a new main loop on the default gstreamer main context. - * + * + *

+ * This will create a new main loop on the default gstreamer main context. + * */ public MainLoop() { - super(initializer(GLIB_API.g_main_loop_new(Gst.getMainContext(), false))); + this(Natives.initializer(GLIB_API.g_main_loop_new(Gst.getMainContext(), false))); } public MainLoop(GMainContext ctx) { - super(initializer(GLIB_API.g_main_loop_new(ctx, false))); + this(Natives.initializer(GLIB_API.g_main_loop_new(ctx, false))); } + /** * Creates a new instance of {@code MainLoop} - * - *

This variant is used internally. - * + * + *

+ * This variant is used internally. + * * @param init internal initialization data. */ - public MainLoop(Initializer init) { - super(init); + public MainLoop(Initializer init) { + super(new Handle(init.ptr, init.ownsHandle), init.needRef); } - + /** * Instructs a main loop to stop processing and return from {@link #run}. */ @@ -70,34 +77,34 @@ public void run() { } }); } - + /** * Enter a loop, processing all events. - *

The loop will continue processing events until {@link #quit} is - * called. + *

+ * The loop will continue processing events until {@link #quit} is called. */ public void run() { GLIB_API.g_main_loop_run(this); } - + /** * Returns whether this main loop is currently processing or not. - * + * * @return true if the main loop is currently being run. */ public boolean isRunning() { return GLIB_API.g_main_loop_is_running(this); } - + /** * Gets the main context for this main loop. - * + * * @return a main context. */ public GMainContext getMainContext() { return GLIB_API.g_main_loop_get_context(this); } - + /** * Runs the main loop in a background thread. */ @@ -112,11 +119,12 @@ public void run() { bgThread.setName("gmainloop"); bgThread.start(); } - + /** * Invokes a task on the main loop thread. - *

This method will wait until the task has completed before returning. - * + *

+ * This method will wait until the task has completed before returning. + * * @param r the task to invoke. */ public void invokeAndWait(Runnable r) { @@ -145,11 +153,13 @@ public boolean callback(Pointer source) { return false; } }; + /** * Invokes a task on the main loop thread. - *

This method returns immediately, without waiting for the task to + *

+ * This method returns immediately, without waiting for the task to * complete. - * + * * @param r the task to invoke. */ public void invokeLater(final Runnable r) { @@ -167,33 +177,28 @@ public void invokeLater(final Runnable r) { } } } - - //-------------------------------------------------------------------------- - // protected methods - // - /** - * Increases the reference count on the native {@code GMainLoop} - */ - protected void ref() { - GLIB_API.g_main_loop_ref(this); - } - - /** - * Decreases the reference count on the native {@code GMainLoop} - */ - protected void unref() { - GLIB_API.g_main_loop_unref(this); - } - - /** - * Frees the native {@code GMainLoop} - */ - protected void disposeNativeHandle(Pointer ptr) { - GLIB_API.g_main_loop_unref(ptr); + + private final static class Handle extends RefCountedObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GLIB_API.g_main_loop_unref(ptr); + } + + @Override + protected void ref() { + GLIB_API.g_main_loop_ref(getPointer()); + } + + @Override + protected void unref() { + GLIB_API.g_main_loop_unref(getPointer()); + } + } - - //-------------------------------------------------------------------------- - // Instance variables - // - private Thread bgThread; + } diff --git a/src/org/freedesktop/gstreamer/lowlevel/NativeObject.java b/src/org/freedesktop/gstreamer/lowlevel/NativeObject.java deleted file mode 100644 index 2c7e77e7..00000000 --- a/src/org/freedesktop/gstreamer/lowlevel/NativeObject.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * 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.freedesktop.gstreamer.lowlevel; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.freedesktop.gstreamer.glib.GObject; -import org.freedesktop.gstreamer.Gst; -import org.freedesktop.gstreamer.MiniObject; -import org.freedesktop.gstreamer.lowlevel.annotations.HasSubtype; - -import com.sun.jna.Pointer; - -/** - * - */ -public abstract class NativeObject extends org.freedesktop.gstreamer.lowlevel.Handle { - private static final Logger logger = Logger.getLogger(NativeObject.class.getName()); - private static final Level LIFECYCLE = Level.FINE; - - // Use this to propagate low level pointer arguments up the constructor chain - protected static class Initializer { - public final Pointer ptr; - public final boolean needRef, ownsHandle; - public Initializer() { - this.ptr = null; - this.needRef = false; - this.ownsHandle = false; - } - public Initializer(Pointer ptr, boolean needRef, boolean ownsHandle) { - this.ptr = ptr; - this.needRef = needRef; - this.ownsHandle = ownsHandle; - } - } - protected static final Initializer defaultInit = new Initializer(); - - /* - * The default for new objects is to not need a refcount increase, and that - * they own the native object. Special cases can use the other constructor. - */ - protected static Initializer initializer(Pointer ptr) { - Initializer initializer = initializer(ptr, false, true); - return initializer; - } - protected static Initializer initializer(Pointer ptr, boolean needRef, boolean ownsHandle) { - if (ptr == null) { - throw new IllegalArgumentException("Invalid native pointer"); - } - return new Initializer(ptr, needRef, ownsHandle); - } - /** Creates a new instance of NativeObject */ - protected NativeObject(final Initializer init) { - logger.entering("NativeObject", "", new Object[] { init }); - if (init == null) { - throw new IllegalArgumentException("Initializer cannot be null"); - } - logger.log(LIFECYCLE, "Creating " + getClass().getSimpleName() + " (" + init.ptr + ")"); - nativeRef = new NativeRef(this); - this.handle = init.ptr; - this.ownsHandle.set(init.ownsHandle); - - // - // Only store this object in the map if we can tell when it has been disposed - // (i.e. must be at least a GObject - MiniObject and other NativeObject subclasses - // don't signal destruction, so it is impossible to know if the instance - // is stale or not - // - if (GObject.class.isAssignableFrom(getClass())) { - getInstanceMap().put(init.ptr, nativeRef); - } - - } - - abstract protected void disposeNativeHandle(Pointer ptr); - - public void dispose() { - logger.log(LIFECYCLE, "Disposing object " + getClass().getName() + " = " + handle); -// System.out.println("Disposing " + handle); - if (!disposed.getAndSet(true)) { - getInstanceMap().remove(handle, nativeRef); - if (ownsHandle.get()) { - disposeNativeHandle(handle); - } - valid.set(false); - } - } - - @Override - public void invalidate() { - logger.log(LIFECYCLE, "Invalidating object " + this + " = " + handle()); - getInstanceMap().remove(handle(), nativeRef); - disposed.set(true); - ownsHandle.set(false); - valid.set(false); - } - - @Override - protected void finalize() throws Throwable { - try { - logger.log(LIFECYCLE, "Finalizing " + getClass().getSimpleName() + " (" + handle + ")"); -// System.out.println("Finalizing " + getClass().getSimpleName() + " (" + handle + ")"); - dispose(); - } finally { - super.finalize(); - } - } - @Override - protected Object nativeValue() { - return handle(); - } - protected Pointer handle() { - if (!valid.get() || disposed.get()) { - throw new IllegalStateException("Native object has been disposed"); - } - return handle; - } - public Pointer getNativeAddress() { - return handle; - } - protected boolean isDisposed() { - return disposed.get(); - } - protected static NativeObject instanceFor(Pointer ptr) { - WeakReference ref = getInstanceMap().get(ptr); - - // - // If the reference was there, but the object it pointed to had been collected, remove it from the map - // - if (ref != null && ref.get() == null) { - getInstanceMap().remove(ptr); - } - return ref != null ? ref.get() : null; - } - public static T objectFor(Pointer ptr, Class cls) { - return objectFor(ptr, cls, true); - } - public static T objectFor(Pointer ptr, Class cls, boolean needRef) { - return objectFor(ptr, cls, needRef, true); - } - public static T objectFor(Pointer ptr, Class cls, boolean needRef, boolean ownsHandle) { - return objectFor(ptr, cls, needRef ? 1 : 0, ownsHandle); - } - - public static T objectFor(Pointer ptr, Class cls, int refAdjust, boolean ownsHandle) { - logger.entering("NativeObject", "instanceFor", new Object[] { ptr, refAdjust, ownsHandle }); - - // Ignore null pointers - if (ptr == null) { - return null; - } - NativeObject obj = GObject.class.isAssignableFrom(cls) ? NativeObject.instanceFor(ptr) : null; - if (obj != null && cls.isInstance(obj)) { - if (refAdjust < 0) { - ((RefCountedObject) obj).unref(); // Lose the extra ref added by gstreamer - } - return cls.cast(obj); - } - - final GType gType = - GObject.class.isAssignableFrom(cls) ? GObject.getType(ptr) : - MiniObject.class.isAssignableFrom(cls) ? MiniObject.getType(ptr) : - null; // shall never appears - - // - // For a GObject, MiniObject, ..., use the GType field to find the most - // exact class match - // - if (gType != null) { - cls = NativeObject.classFor(ptr, gType, cls); - } - - try { - Constructor constructor = cls.getDeclaredConstructor(Initializer.class); - constructor.setAccessible(true); - T retVal = constructor.newInstance(initializer(ptr, refAdjust > 0, ownsHandle)); - //retVal.initNativeHandle(ptr, refAdjust > 0, ownsHandle); - return retVal; - } catch (SecurityException ex) { - throw new RuntimeException(ex); - } catch (IllegalAccessException ex) { - throw new RuntimeException(ex); - } catch (InstantiationException ex) { - throw new RuntimeException(ex); - } catch (NoSuchMethodException ex) { - throw new RuntimeException(ex); - } catch (InvocationTargetException ex) { - throw new RuntimeException(ex); - } - - } - - @SuppressWarnings("unchecked") - protected static Class classFor(Pointer ptr, final GType gType, final Class defaultClass) { - Class cls = (Class)GstTypes.classFor(gType); - if (cls == null) cls = defaultClass; - - if (cls.isAnnotationPresent(HasSubtype.class)) { - cls = (Class)SubtypeMapper.subtypeFor(cls, ptr); - } - - return cls; - } - - @Override - public boolean equals(Object o) { - return o instanceof NativeObject && ((NativeObject) o).handle.equals(handle); - } - - @Override - public int hashCode() { - return handle.hashCode(); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "(" + handle() + ")"; - } - - // - // No longer want to garbage collect this object - // - public void disown() { - logger.log(LIFECYCLE, "Disowning " + handle()); - ownsHandle.set(false); - } - - static { - // - // Add a shutdown task to cleanup any dangling object references, so - // Gst.deinit() can shutdown cleanly. Unreffing objects after gst_deinit() - // has been called could be asking for trouble. - // - Gst.addStaticShutdownTask(new Runnable() { - - public void run() { - System.gc(); - int gcCount = 20; - // Give the GC a chance to cleanup nicely - while (!getInstanceMap().isEmpty() && gcCount-- > 0) { - try { - Thread.sleep(10); - System.gc(); - } catch (InterruptedException ex) { - break; - } - } - for (Object o : getInstanceMap().values().toArray()) { - NativeObject obj = ((NativeRef) o).get(); - if (obj != null && !obj.disposed.get()) { -// System.out.println("Disposing " + obj); - obj.dispose(); - } - } - } - }); - } - private static final ConcurrentMap getInstanceMap() { - return StaticData.instanceMap; - } - static class NativeRef extends WeakReference { - public NativeRef(NativeObject obj) { - super(obj); - } - } - private final AtomicBoolean disposed = new AtomicBoolean(false); - private final AtomicBoolean valid = new AtomicBoolean(true); - private final Pointer handle; - protected final AtomicBoolean ownsHandle = new AtomicBoolean(false); - private final NativeRef nativeRef; - private static final class StaticData { - private static final ConcurrentMap instanceMap = new ConcurrentHashMap(); - static { - // - // Add a shutdown task to cleanup any dangling object references, so - // Gst.deinit() can shutdown cleanly. Unreffing objects after gst_deinit() - // has been called could be asking for trouble. - // - Gst.addStaticShutdownTask(new Runnable() { - - public void run() { - System.gc(); - int gcCount = 20; - // Give the GC a chance to cleanup nicely - while (!getInstanceMap().isEmpty() && gcCount-- > 0) { - try { - Thread.sleep(10); - System.gc(); - } catch (InterruptedException ex) { - break; - } - } - for (Object o : getInstanceMap().values().toArray()) { - NativeObject obj = ((NativeRef) o).get(); - if (obj != null && !obj.disposed.get()) { - // System.out.println("Disposing " + obj); - obj.dispose(); - } - } - } - }); - } - } -} diff --git a/src/org/freedesktop/gstreamer/lowlevel/NativeValue.java b/src/org/freedesktop/gstreamer/lowlevel/NativeValue.java deleted file mode 100644 index 3521ef19..00000000 --- a/src/org/freedesktop/gstreamer/lowlevel/NativeValue.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.freedesktop.gstreamer.lowlevel; - -/** - * - */ -public abstract class NativeValue { - - protected NativeValue() { - } - abstract protected Object nativeValue(); -} diff --git a/src/org/freedesktop/gstreamer/lowlevel/RefCountedObject.java b/src/org/freedesktop/gstreamer/lowlevel/RefCountedObject.java deleted file mode 100644 index a1316308..00000000 --- a/src/org/freedesktop/gstreamer/lowlevel/RefCountedObject.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2007, 2008 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.freedesktop.gstreamer.lowlevel; - -/** - * A {@link NativeObject} that has an associated reference count - * @author wayne - */ -abstract public class RefCountedObject extends NativeObject { - /** Creates a new instance of RefCountedObject */ - protected RefCountedObject(Initializer init) { - super(init); - if (init.ownsHandle && init.needRef) { - ref(); - } - } - // overridden in subclasses - abstract protected void ref(); - abstract protected void unref(); -} diff --git a/src/org/freedesktop/gstreamer/lowlevel/ReferenceManager.java b/src/org/freedesktop/gstreamer/lowlevel/ReferenceManager.java index e2c802b8..41ba35bc 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/ReferenceManager.java +++ b/src/org/freedesktop/gstreamer/lowlevel/ReferenceManager.java @@ -22,6 +22,7 @@ import java.lang.ref.WeakReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.freedesktop.gstreamer.glib.RefCountedObject; /** * Manages keep alive links from one object to another. diff --git a/src/org/freedesktop/gstreamer/lowlevel/SubtypeMapper.java b/src/org/freedesktop/gstreamer/lowlevel/SubtypeMapper.java index 165d45d7..7484e7b9 100644 --- a/src/org/freedesktop/gstreamer/lowlevel/SubtypeMapper.java +++ b/src/org/freedesktop/gstreamer/lowlevel/SubtypeMapper.java @@ -61,6 +61,7 @@ import org.freedesktop.gstreamer.query.SegmentQuery; import com.sun.jna.Pointer; +import org.freedesktop.gstreamer.glib.NativeObject; /** * Mapper for classes which have subtypes (e.g. Event, Message, Query). @@ -69,8 +70,8 @@ * raw pointer passed in. */ @SuppressWarnings("serial") -class SubtypeMapper { - static Class subtypeFor(final Class defaultClass, final Pointer ptr) { +public class SubtypeMapper { + public static Class subtypeFor(final Class defaultClass, final Pointer ptr) { Mapper mapper = MapHolder.mappers.get(defaultClass); Class cls = mapper != null ? mapper.subtypeFor(ptr) : null; return cls != null ? cls : defaultClass; diff --git a/src/org/freedesktop/gstreamer/message/BufferingMessage.java b/src/org/freedesktop/gstreamer/message/BufferingMessage.java index d907b01e..1dce6879 100644 --- a/src/org/freedesktop/gstreamer/message/BufferingMessage.java +++ b/src/org/freedesktop/gstreamer/message/BufferingMessage.java @@ -21,6 +21,7 @@ package org.freedesktop.gstreamer.message; import org.freedesktop.gstreamer.GstObject; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; /** @@ -56,7 +57,7 @@ public class BufferingMessage extends Message { * @param percent The buffering percent */ public BufferingMessage(GstObject src, int percent) { - this(initializer(GSTMESSAGE_API.ptr_gst_message_new_buffering(src, percent))); + this(Natives.initializer(GSTMESSAGE_API.ptr_gst_message_new_buffering(src, percent))); } /** diff --git a/src/org/freedesktop/gstreamer/message/DurationChangedMessage.java b/src/org/freedesktop/gstreamer/message/DurationChangedMessage.java index 17e9d5e4..38473465 100644 --- a/src/org/freedesktop/gstreamer/message/DurationChangedMessage.java +++ b/src/org/freedesktop/gstreamer/message/DurationChangedMessage.java @@ -20,6 +20,7 @@ package org.freedesktop.gstreamer.message; import org.freedesktop.gstreamer.GstObject; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; /** @@ -50,6 +51,6 @@ public class DurationChangedMessage extends Message { * @param src The object originating the message. */ public DurationChangedMessage(GstObject src) { - this(initializer(GSTMESSAGE_API.ptr_gst_message_new_duration_changed(src))); + this(Natives.initializer(GSTMESSAGE_API.ptr_gst_message_new_duration_changed(src))); } } diff --git a/src/org/freedesktop/gstreamer/message/EOSMessage.java b/src/org/freedesktop/gstreamer/message/EOSMessage.java index 2d539aa6..523b76ba 100644 --- a/src/org/freedesktop/gstreamer/message/EOSMessage.java +++ b/src/org/freedesktop/gstreamer/message/EOSMessage.java @@ -21,6 +21,7 @@ import org.freedesktop.gstreamer.Bin; import org.freedesktop.gstreamer.GstObject; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; /** @@ -51,6 +52,6 @@ public class EOSMessage extends Message { * @param src The object originating the message. */ public EOSMessage(GstObject src) { - this(initializer(GSTMESSAGE_API.ptr_gst_message_new_eos(src))); + this(Natives.initializer(GSTMESSAGE_API.ptr_gst_message_new_eos(src))); } } diff --git a/src/org/freedesktop/gstreamer/message/LatencyMessage.java b/src/org/freedesktop/gstreamer/message/LatencyMessage.java index fb8abcef..167afa2a 100644 --- a/src/org/freedesktop/gstreamer/message/LatencyMessage.java +++ b/src/org/freedesktop/gstreamer/message/LatencyMessage.java @@ -20,6 +20,7 @@ package org.freedesktop.gstreamer.message; import org.freedesktop.gstreamer.GstObject; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; /** @@ -47,6 +48,6 @@ public class LatencyMessage extends Message { * @param source the object originating the message. */ public LatencyMessage(GstObject source) { - this(initializer(GSTMESSAGE_API.ptr_gst_message_new_latency(source))); + this(Natives.initializer(GSTMESSAGE_API.ptr_gst_message_new_latency(source))); } } diff --git a/src/org/freedesktop/gstreamer/message/Message.java b/src/org/freedesktop/gstreamer/message/Message.java index 8ca33609..42fb387d 100644 --- a/src/org/freedesktop/gstreamer/message/Message.java +++ b/src/org/freedesktop/gstreamer/message/Message.java @@ -19,9 +19,15 @@ */ package org.freedesktop.gstreamer.message; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; import org.freedesktop.gstreamer.GstObject; import org.freedesktop.gstreamer.MiniObject; import org.freedesktop.gstreamer.Structure; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstMessageAPI; import org.freedesktop.gstreamer.lowlevel.ReferenceManager; import org.freedesktop.gstreamer.lowlevel.annotations.HasSubtype; @@ -60,6 +66,22 @@ public class Message extends MiniObject { public static final String GTYPE_NAME = "GstMessage"; + private static final Map> TYPE_MAP + = new EnumMap<>(MessageType.class); + + static { + TYPE_MAP.put(MessageType.EOS, EOSMessage::new); + TYPE_MAP.put(MessageType.ERROR, ErrorMessage::new); + TYPE_MAP.put(MessageType.BUFFERING, BufferingMessage::new); + TYPE_MAP.put(MessageType.DURATION_CHANGED, DurationChangedMessage::new); + TYPE_MAP.put(MessageType.INFO, InfoMessage::new); + TYPE_MAP.put(MessageType.LATENCY, LatencyMessage::new); + TYPE_MAP.put(MessageType.SEGMENT_DONE, SegmentDoneMessage::new); + TYPE_MAP.put(MessageType.STATE_CHANGED, StateChangedMessage::new); + TYPE_MAP.put(MessageType.TAG, TagMessage::new); + TYPE_MAP.put(MessageType.WARNING, WarningMessage::new); + } + private final GstMessageAPI.MessageStruct messageStruct; /** @@ -69,7 +91,7 @@ public class Message extends MiniObject { */ Message(Initializer init) { super(init); - messageStruct = new GstMessageAPI.MessageStruct(init.ptr); + messageStruct = new GstMessageAPI.MessageStruct(init.ptr.getPointer()); } /** @@ -100,4 +122,21 @@ public MessageType getType() { return type; } + private static Message create(Initializer init) { + GstMessageAPI.MessageStruct struct = new GstMessageAPI.MessageStruct(init.ptr.getPointer()); + MessageType type = (MessageType) struct.readField("type"); + return TYPE_MAP.getOrDefault(type, Message::new).apply(init); + } + + public static class Types implements TypeProvider { + + @Override + public Stream> types() { + return Stream.of( + Natives.registration(Message.class, GTYPE_NAME, Message::create) + ); + } + + } + } diff --git a/src/org/freedesktop/gstreamer/message/SegmentDoneMessage.java b/src/org/freedesktop/gstreamer/message/SegmentDoneMessage.java index c8148fbb..76d3256d 100644 --- a/src/org/freedesktop/gstreamer/message/SegmentDoneMessage.java +++ b/src/org/freedesktop/gstreamer/message/SegmentDoneMessage.java @@ -22,6 +22,7 @@ import org.freedesktop.gstreamer.Format; import org.freedesktop.gstreamer.GstObject; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; /** @@ -54,7 +55,7 @@ public class SegmentDoneMessage extends Message { * @param position the position of the segment being done */ public SegmentDoneMessage(GstObject src, Format format, long position) { - this(initializer(GSTMESSAGE_API.ptr_gst_message_new_segment_done(src, format, position))); + this(Natives.initializer(GSTMESSAGE_API.ptr_gst_message_new_segment_done(src, format, position))); } /** diff --git a/src/org/freedesktop/gstreamer/message/StateChangedMessage.java b/src/org/freedesktop/gstreamer/message/StateChangedMessage.java index e71864a8..3d2a186a 100644 --- a/src/org/freedesktop/gstreamer/message/StateChangedMessage.java +++ b/src/org/freedesktop/gstreamer/message/StateChangedMessage.java @@ -22,6 +22,7 @@ import org.freedesktop.gstreamer.GstObject; import org.freedesktop.gstreamer.State; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; /** @@ -52,7 +53,7 @@ public class StateChangedMessage extends Message { * @param pending the pending (target) state. */ public StateChangedMessage(GstObject src, State old, State current, State pending) { - super(initializer(GSTMESSAGE_API.ptr_gst_message_new_state_changed(src, old, current, pending))); + super(Natives.initializer(GSTMESSAGE_API.ptr_gst_message_new_state_changed(src, old, current, pending))); } /** diff --git a/src/org/freedesktop/gstreamer/message/TagMessage.java b/src/org/freedesktop/gstreamer/message/TagMessage.java index 9eb898eb..d7ef3bab 100644 --- a/src/org/freedesktop/gstreamer/message/TagMessage.java +++ b/src/org/freedesktop/gstreamer/message/TagMessage.java @@ -22,6 +22,7 @@ import org.freedesktop.gstreamer.GstObject; import org.freedesktop.gstreamer.TagList; import com.sun.jna.ptr.PointerByReference; +import org.freedesktop.gstreamer.glib.Natives; import static org.freedesktop.gstreamer.lowlevel.GstMessageAPI.GSTMESSAGE_API; /** @@ -53,7 +54,7 @@ public class TagMessage extends Message { * it again after adding it to this message. */ public TagMessage(GstObject src, TagList tagList) { - this(initializer(GSTMESSAGE_API.ptr_gst_message_new_tag(src, tagList))); + this(Natives.initializer(GSTMESSAGE_API.ptr_gst_message_new_tag(src, tagList))); } /** @@ -64,6 +65,6 @@ public TagMessage(GstObject src, TagList tagList) { public TagList getTagList() { PointerByReference list = new PointerByReference(); GSTMESSAGE_API.gst_message_parse_tag(this, list); - return objectFor(list.getValue(), TagList.class, false, true); + return Natives.objectFor(list.getValue(), TagList.class, false, true); } } diff --git a/src/org/freedesktop/gstreamer/query/AllocationQuery.java b/src/org/freedesktop/gstreamer/query/AllocationQuery.java index 29f99d46..697a0f7c 100644 --- a/src/org/freedesktop/gstreamer/query/AllocationQuery.java +++ b/src/org/freedesktop/gstreamer/query/AllocationQuery.java @@ -25,7 +25,8 @@ import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; import com.sun.jna.Pointer; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; +import org.freedesktop.gstreamer.glib.Natives; /** * An allocation query for querying allocation properties. @@ -47,7 +48,7 @@ public class AllocationQuery extends Query { // special case : no ref shall be added // the allocationQuery is an in/out parameter during query notification // so, we shall keep query writable for add methods - super(initializer(init.ptr, false, true)); + super(Natives.initializer(init.ptr.getPointer(), false, true)); } /** @@ -57,7 +58,7 @@ public class AllocationQuery extends Query { * @param need_pool return a pool. */ public AllocationQuery(Caps caps, boolean need_pool) { - this(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_allocation(caps, need_pool))); + this(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_allocation(caps, need_pool))); } /** @@ -80,7 +81,7 @@ public Caps getCaps() { Pointer[] ptr = new Pointer[1]; GstQueryAPI.GSTQUERY_API.gst_query_parse_allocation(this, ptr, null); // return new Caps(new Initializer(ptr[0], false, true)); - return NativeObject.objectFor(ptr[0], Caps.class, false, true); + return Natives.objectFor(ptr[0], Caps.class, false, true); } // @TODO how best not to expose GType? diff --git a/src/org/freedesktop/gstreamer/query/ConvertQuery.java b/src/org/freedesktop/gstreamer/query/ConvertQuery.java index bb64f5d1..25cb7fba 100644 --- a/src/org/freedesktop/gstreamer/query/ConvertQuery.java +++ b/src/org/freedesktop/gstreamer/query/ConvertQuery.java @@ -22,6 +22,7 @@ package org.freedesktop.gstreamer.query; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; /** @@ -46,7 +47,7 @@ public class ConvertQuery extends Query { * @param destFormat the target {@link Format} */ public ConvertQuery(Format srcFormat, long value, Format destFormat) { - this(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_convert(srcFormat, value, destFormat))); + this(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_convert(srcFormat, value, destFormat))); } /** diff --git a/src/org/freedesktop/gstreamer/query/DurationQuery.java b/src/org/freedesktop/gstreamer/query/DurationQuery.java index 4987c179..7ca88d7d 100644 --- a/src/org/freedesktop/gstreamer/query/DurationQuery.java +++ b/src/org/freedesktop/gstreamer/query/DurationQuery.java @@ -22,6 +22,7 @@ package org.freedesktop.gstreamer.query; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; /** @@ -46,7 +47,7 @@ public class DurationQuery extends Query { * @param format the {@link Format} for this duration query. */ public DurationQuery(Format format) { - super(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_duration(format))); + super(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_duration(format))); } /** diff --git a/src/org/freedesktop/gstreamer/query/FormatsQuery.java b/src/org/freedesktop/gstreamer/query/FormatsQuery.java index 522149da..d6eb2cae 100644 --- a/src/org/freedesktop/gstreamer/query/FormatsQuery.java +++ b/src/org/freedesktop/gstreamer/query/FormatsQuery.java @@ -25,6 +25,7 @@ import java.util.List; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; /** @@ -42,7 +43,7 @@ public class FormatsQuery extends Query { * Constructs a new query object for querying formats of the stream. */ public FormatsQuery() { - this(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_formats())); + this(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_formats())); } FormatsQuery(Initializer init) { diff --git a/src/org/freedesktop/gstreamer/query/LatencyQuery.java b/src/org/freedesktop/gstreamer/query/LatencyQuery.java index d5307b18..0180dd17 100644 --- a/src/org/freedesktop/gstreamer/query/LatencyQuery.java +++ b/src/org/freedesktop/gstreamer/query/LatencyQuery.java @@ -21,6 +21,7 @@ */ package org.freedesktop.gstreamer.query; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; /** @@ -43,7 +44,7 @@ public class LatencyQuery extends Query { * format. */ public LatencyQuery() { - super(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_latency())); + super(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_latency())); } /** diff --git a/src/org/freedesktop/gstreamer/query/PositionQuery.java b/src/org/freedesktop/gstreamer/query/PositionQuery.java index a057ebf7..42b8f63b 100644 --- a/src/org/freedesktop/gstreamer/query/PositionQuery.java +++ b/src/org/freedesktop/gstreamer/query/PositionQuery.java @@ -22,6 +22,7 @@ package org.freedesktop.gstreamer.query; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; /** @@ -46,7 +47,7 @@ public class PositionQuery extends Query { * @param format the default {@link Format} for the new query */ public PositionQuery(Format format) { - super(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_position(format))); + super(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_position(format))); } /** diff --git a/src/org/freedesktop/gstreamer/query/Query.java b/src/org/freedesktop/gstreamer/query/Query.java index 20f19d99..f0e2f40d 100644 --- a/src/org/freedesktop/gstreamer/query/Query.java +++ b/src/org/freedesktop/gstreamer/query/Query.java @@ -16,13 +16,18 @@ * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ - package org.freedesktop.gstreamer.query; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; import org.freedesktop.gstreamer.Element; import org.freedesktop.gstreamer.MiniObject; import org.freedesktop.gstreamer.Pad; import org.freedesktop.gstreamer.Structure; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; import org.freedesktop.gstreamer.lowlevel.ReferenceManager; import org.freedesktop.gstreamer.lowlevel.annotations.HasSubtype; @@ -38,17 +43,32 @@ */ @HasSubtype public class Query extends MiniObject { + public static final String GTYPE_NAME = "GstQuery"; + private static final Map> TYPE_MAP + = new EnumMap<>(QueryType.class); + + static { + TYPE_MAP.put(QueryType.ALLOCATION, AllocationQuery::new); + TYPE_MAP.put(QueryType.CONVERT, ConvertQuery::new); + TYPE_MAP.put(QueryType.DURATION, DurationQuery::new); + TYPE_MAP.put(QueryType.FORMATS, FormatsQuery::new); + TYPE_MAP.put(QueryType.LATENCY, LatencyQuery::new); + TYPE_MAP.put(QueryType.POSITION, PositionQuery::new); + TYPE_MAP.put(QueryType.SEEKING, SeekingQuery::new); + TYPE_MAP.put(QueryType.SEGMENT, SegmentQuery::new); + } + /** - * Internally used constructor. Do not use. - * + * Internally used constructor. Do not use. + * * @param init internal initialization data. */ Query(Initializer init) { super(init); } - + /** * Get the structure of this query. * @@ -57,5 +77,22 @@ public class Query extends MiniObject { public Structure getStructure() { return ReferenceManager.addKeepAliveReference(GSTQUERY_API.gst_query_get_structure(this), this); } + + private static Query create(Initializer init) { + GstQueryAPI.QueryStruct struct = new GstQueryAPI.QueryStruct(init.ptr.getPointer()); + QueryType type = (QueryType) struct.readField("type"); + return TYPE_MAP.getOrDefault(type, Query::new).apply(init); + } + public static class Types implements TypeProvider { + + @Override + public Stream> types() { + return Stream.of( + Natives.registration(Query.class, GTYPE_NAME, Query::create) + ); + } + + } + } diff --git a/src/org/freedesktop/gstreamer/query/SeekingQuery.java b/src/org/freedesktop/gstreamer/query/SeekingQuery.java index e2967122..6229d86a 100644 --- a/src/org/freedesktop/gstreamer/query/SeekingQuery.java +++ b/src/org/freedesktop/gstreamer/query/SeekingQuery.java @@ -22,6 +22,7 @@ package org.freedesktop.gstreamer.query; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; /** @@ -45,7 +46,7 @@ public class SeekingQuery extends Query { * @param format the default {@link Format} for the new query. */ public SeekingQuery(Format format) { - this(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_seeking(format))); + this(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_seeking(format))); } /** diff --git a/src/org/freedesktop/gstreamer/query/SegmentQuery.java b/src/org/freedesktop/gstreamer/query/SegmentQuery.java index 961169e8..31b09fff 100644 --- a/src/org/freedesktop/gstreamer/query/SegmentQuery.java +++ b/src/org/freedesktop/gstreamer/query/SegmentQuery.java @@ -22,6 +22,7 @@ package org.freedesktop.gstreamer.query; import org.freedesktop.gstreamer.Format; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; /** @@ -45,7 +46,7 @@ public class SegmentQuery extends Query { * @param format the {@link Format} for the new query. */ public SegmentQuery(Format format) { - this(initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_segment(format))); + this(Natives.initializer(GstQueryAPI.GSTQUERY_API.ptr_gst_query_new_segment(format))); } /** diff --git a/src/org/freedesktop/gstreamer/webrtc/WebRTC.java b/src/org/freedesktop/gstreamer/webrtc/WebRTC.java new file mode 100644 index 00000000..0195e9a6 --- /dev/null +++ b/src/org/freedesktop/gstreamer/webrtc/WebRTC.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Neil C Smith + * + * 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.freedesktop.gstreamer.webrtc; + +import java.util.stream.Stream; +import org.freedesktop.gstreamer.glib.NativeObject; +import static org.freedesktop.gstreamer.glib.Natives.registration; + +/** + * + * @author Neil C Smith - https://www.neilcsmith.net + */ +public class WebRTC { + + private WebRTC() { + } + + public static class Types implements NativeObject.TypeProvider { + + @Override + public Stream> types() { + return Stream.of( + registration(WebRTCSessionDescription.class, + WebRTCSessionDescription.GTYPE_NAME, + WebRTCSessionDescription::new), + registration(WebRTCBin.class, + WebRTCBin.GTYPE_NAME, + WebRTCBin::new)); + + } + + } + +} diff --git a/src/org/freedesktop/gstreamer/webrtc/WebRTCSessionDescription.java b/src/org/freedesktop/gstreamer/webrtc/WebRTCSessionDescription.java index 805061fa..bb24a648 100644 --- a/src/org/freedesktop/gstreamer/webrtc/WebRTCSessionDescription.java +++ b/src/org/freedesktop/gstreamer/webrtc/WebRTCSessionDescription.java @@ -20,10 +20,12 @@ import static org.freedesktop.gstreamer.lowlevel.GstWebRTCSessionDescriptionAPI.GSTWEBRTCSESSIONDESCRIPTION_API; import org.freedesktop.gstreamer.lowlevel.GstWebRTCSessionDescriptionAPI; -import org.freedesktop.gstreamer.lowlevel.NativeObject; +import org.freedesktop.gstreamer.glib.NativeObject; import com.sun.jna.Pointer; import org.freedesktop.gstreamer.SDPMessage; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.lowlevel.GPointer; import static org.freedesktop.gstreamer.lowlevel.GstSDPMessageAPI.GSTSDPMESSAGE_API; /** @@ -44,8 +46,9 @@ public class WebRTCSessionDescription extends NativeObject { * @param init internal initialization data. */ WebRTCSessionDescription(Initializer init) { - super(init); - sessionDescriptionStruct = new GstWebRTCSessionDescriptionAPI.WebRTCSessionDescriptionStruct(handle()); + super(new Handle(init.ptr, init.ownsHandle)); + sessionDescriptionStruct = + new GstWebRTCSessionDescriptionAPI.WebRTCSessionDescriptionStruct(init.ptr.getPointer()); } /** @@ -55,7 +58,7 @@ public class WebRTCSessionDescription extends NativeObject { * @param sdpMessage The {@link SDPMessage} of the session description */ public WebRTCSessionDescription(WebRTCSDPType type, SDPMessage sdpMessage) { - this(initializer(GSTWEBRTCSESSIONDESCRIPTION_API.ptr_gst_webrtc_session_description_new(type, sdpMessage))); + this(Natives.initializer(GSTWEBRTCSESSIONDESCRIPTION_API.ptr_gst_webrtc_session_description_new(type, sdpMessage))); } /** @@ -73,11 +76,20 @@ public SDPMessage getSDPMessage() { Pointer[] ptr = new Pointer[1]; GSTSDPMESSAGE_API.gst_sdp_message_copy(originalSDP, ptr); originalSDP.invalidate(); - return NativeObject.objectFor(ptr[0], SDPMessage.class, false, true); + return Natives.objectFor(ptr[0], SDPMessage.class, false, true); } - @Deprecated - protected void disposeNativeHandle(Pointer ptr) { - GSTWEBRTCSESSIONDESCRIPTION_API.gst_webrtc_session_description_free(ptr); + + private static final class Handle extends NativeObject.Handle { + + public Handle(GPointer ptr, boolean ownsHandle) { + super(ptr, ownsHandle); + } + + @Override + protected void disposeNativeHandle(GPointer ptr) { + GSTWEBRTCSESSIONDESCRIPTION_API.gst_webrtc_session_description_free(ptr.getPointer()); + } + } } diff --git a/test/org/freedesktop/gstreamer/GarbageCollectionEDTTest.java b/test/org/freedesktop/gstreamer/GarbageCollectionEDTTest.java new file mode 100644 index 00000000..89fa908d --- /dev/null +++ b/test/org/freedesktop/gstreamer/GarbageCollectionEDTTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2019 Neil C Smith + * Copyright (c) 2007 Wayne Meissner + * + * This file is part of gstreamer-java. + * + * gstreamer-java is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gstreamer-java 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with gstreamer-java. If not, see . + */ + +package org.freedesktop.gstreamer; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.lang.ref.WeakReference; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +/** + * + */ +public class GarbageCollectionEDTTest { + + public GarbageCollectionEDTTest() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + System.setProperty("glib.reapOnEDT", "true"); + Gst.init("test", new String[] {}); + } + + @AfterClass + public static void tearDownClass() throws Exception { +// Gst.deinit(); + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testElement() throws Exception { + + Element e = ElementFactory.make("fakesrc", "test element"); + GCTracker tracker = new GCTracker(e); + e = null; + assertTrue("Element not garbage collected", tracker.waitGC()); + assertTrue("GObject not destroyed", tracker.waitDestroyed()); + } + @Test + public void testBin() throws Exception { + Bin bin = new Bin("test"); + Element e1 = ElementFactory.make("fakesrc", "source"); + Element e2 = ElementFactory.make("fakesink", "sink"); + bin.addMany(e1, e2); + + assertEquals("source not returned", e1, bin.getElementByName("source")); + assertEquals("sink not returned", e2, bin.getElementByName("sink")); + WeakReference binRef = new WeakReference(bin); + bin = null; + assertTrue("Bin not garbage collected", GCTracker.waitGC(binRef)); + WeakReference e1Ref = new WeakReference(e1); + WeakReference e2Ref = new WeakReference(e2); + e1 = null; + e2 = null; + + assertTrue("First Element not garbage collected", GCTracker.waitGC(e1Ref)); + assertTrue("Second Element not garbage collected", GCTracker.waitGC(e2Ref)); + + } + @Test + public void testBinRetrieval() throws Exception { + Bin bin = new Bin("test"); + Element e1 = ElementFactory.make("fakesrc", "source"); + Element e2 = ElementFactory.make("fakesink", "sink"); + bin.addMany(e1, e2); + int id1 = System.identityHashCode(e1); + int id2 = System.identityHashCode(e2); + + e1 = null; + e2 = null; + System.gc(); + Thread.sleep(10); + // Should return the same object that was put into the bin + assertEquals("source ID does not match", id1, System.identityHashCode(bin.getElementByName("source"))); + assertEquals("sink ID does not match", id2, System.identityHashCode(bin.getElementByName("sink"))); + } + @Test + public void pipeline() { + Pipeline pipe = new Pipeline("test"); + GCTracker pipeTracker = new GCTracker(pipe); + pipe = null; + assertTrue("Pipe not garbage collected", pipeTracker.waitGC()); + System.out.println("checking if pipeline is destroyed"); + assertTrue("Pipe not destroyed", pipeTracker.waitDestroyed()); + } + @Test + public void pipelineBus() { + Pipeline pipe = new Pipeline("test"); + Bus bus = pipe.getBus(); + GCTracker busTracker = new GCTracker(bus); + GCTracker pipeTracker = new GCTracker(pipe); + + pipe = null; + bus = null; + assertTrue("Bus not garbage collected", busTracker.waitGC()); + assertTrue("Bus not destroyed", busTracker.waitDestroyed()); + assertTrue("Pipe not garbage collected", pipeTracker.waitGC()); + assertTrue("Pipe not destroyed", pipeTracker.waitDestroyed()); + + } + @Test + @Ignore("See comment below.") + public void busWithListeners() { + Pipeline pipe = new Pipeline("test"); + Bus bus = pipe.getBus(); + // Reasoning for @Igore: + // + // #connect increments the native reference count this in turn prevents + // the native part of the BUS to get out of scope. + bus.connect(new Bus.EOS() { + + public void endOfStream(GstObject source) { + } + }); + + GCTracker busTracker = new GCTracker(bus); + GCTracker pipeTracker = new GCTracker(pipe); + bus = null; + pipe = null; + assertTrue("Bus not garbage collected", busTracker.waitGC()); + assertTrue("Bus not destroyed", busTracker.waitDestroyed()); + assertTrue("Pipe not garbage collected", pipeTracker.waitGC()); + assertTrue("Pipe not destroyed", pipeTracker.waitDestroyed()); + } +} diff --git a/test/org/freedesktop/gstreamer/GstTypesTest.java b/test/org/freedesktop/gstreamer/GstTypesTest.java index 0588fa47..a543bb52 100644 --- a/test/org/freedesktop/gstreamer/GstTypesTest.java +++ b/test/org/freedesktop/gstreamer/GstTypesTest.java @@ -18,6 +18,8 @@ */ package org.freedesktop.gstreamer; +import org.freedesktop.gstreamer.glib.Natives; +import org.freedesktop.gstreamer.lowlevel.GObjectPtr; import static org.junit.Assert.assertEquals; import org.freedesktop.gstreamer.lowlevel.GType; @@ -64,7 +66,10 @@ public void unregisteredClassTest() { GType elementType = GType.valueOf(Element.GTYPE_NAME); // check a unregistered class which derived from Element Element anElement = ElementFactory.make("avidemux", "avidemux"); - assertEquals(Element.class, GstTypes.classFor(anElement.getType())); +// assertEquals(Element.class, GstTypes.classFor(anElement.getType())); + assertEquals(Element.class, GstTypes.classFor( + Natives.getPointer(anElement) + .as(GObjectPtr.class, GObjectPtr::new).getGType())); // verify GType has not changed for Element.class assertEquals(elementType, GstTypes.typeFor(Element.class)); diff --git a/test/org/freedesktop/gstreamer/PipelineTest.java b/test/org/freedesktop/gstreamer/PipelineTest.java index b43cff43..f38f37e3 100644 --- a/test/org/freedesktop/gstreamer/PipelineTest.java +++ b/test/org/freedesktop/gstreamer/PipelineTest.java @@ -29,8 +29,10 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GObjectAPI.GObjectStruct; +import org.freedesktop.gstreamer.lowlevel.GObjectPtr; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -78,17 +80,19 @@ public boolean waitRefCnt(GObjectStruct struct, int refcnt) throws InterruptedEx @Test public void testPipelineGC() throws Exception { - Pipeline p = new Pipeline(); - int refcnt = new GObjectStruct(p).ref_count; - + Pipeline p = new Pipeline("test pipeline"); + int refcnt = new GObjectStruct((GObjectPtr) Natives.getPointer(p)).ref_count; assertEquals("Refcount should be 1", refcnt, 1); + WeakReference pref = new WeakReference(p); + p = null; + assertTrue("pipe not disposed", GCTracker.waitGC(pref)); } @Test public void testBusGC() throws Exception { Pipeline pipe = new Pipeline("test playbin"); pipe.play(); Bus bus = pipe.getBus(); - GObjectStruct struct = new GObjectStruct(bus); + GObjectStruct struct = new GObjectStruct((GObjectPtr) Natives.getPointer(bus)); int refcnt = struct.ref_count; assertTrue(refcnt > 1); // reget the Bus - should return the same object and not increment ref count diff --git a/test/org/freedesktop/gstreamer/QueryTest.java b/test/org/freedesktop/gstreamer/QueryTest.java index f85f827a..5acb048d 100644 --- a/test/org/freedesktop/gstreamer/QueryTest.java +++ b/test/org/freedesktop/gstreamer/QueryTest.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import org.freedesktop.gstreamer.glib.Natives; import org.freedesktop.gstreamer.lowlevel.GstQueryAPI; import org.freedesktop.gstreamer.query.AllocationQuery; @@ -207,7 +208,8 @@ public void latencyQueryToString() { Query query = new SegmentQuery(Format.TIME); assertTrue("New query is not writable", query.isWritable()); // Bumping the ref count makes this instance non writable - GSTMINIOBJECT_API.gst_mini_object_ref(query); +// GSTMINIOBJECT_API.gst_mini_object_ref(query); + Natives.ref(query); assertFalse("Query with multiple references should not be writable", query.isWritable()); // Now get a new reference that is writable query = query.makeWritable();