Skip to content

Commit 1ff6ce7

Browse files
Change GstIterator support to stop keeping parent reference alive until GC.
Migrate lowlevel GstIterator API to typed pointer. Move GstIterator from NativeObject subclass to utility method holder. Directly fill list and free gstiterator eagerly. Update Element (pads) and Bin (elements) methods.
1 parent 31e4361 commit 1ff6ce7

File tree

8 files changed

+119
-119
lines changed

8 files changed

+119
-119
lines changed

src/org/freedesktop/gstreamer/Bin.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 Neil C Smith
2+
* Copyright (c) 2021 Neil C Smith
33
* Copyright (c) 2016 Christophe Lafolet
44
* Copyright (c) 2009 Levente Farkas
55
* Copyright (C) 2007 Wayne Meissner
@@ -24,12 +24,12 @@
2424

2525
import static org.freedesktop.gstreamer.lowlevel.GstBinAPI.GSTBIN_API;
2626

27-
import com.sun.jna.Pointer;
2827
import java.util.EnumSet;
2928
import java.util.List;
3029
import org.freedesktop.gstreamer.glib.NativeFlags;
3130
import org.freedesktop.gstreamer.glib.Natives;
3231
import org.freedesktop.gstreamer.lowlevel.GstAPI.GstCallback;
32+
import org.freedesktop.gstreamer.lowlevel.GstIteratorPtr;
3333
import org.freedesktop.gstreamer.lowlevel.GstObjectPtr;
3434

3535
/**
@@ -145,8 +145,8 @@ public void removeMany(Element... elements) {
145145
GSTBIN_API.gst_bin_remove_many(this, elements);
146146
}
147147

148-
private List<Element> elementList(Pointer iter) {
149-
return new GstIterator<Element>(iter, Element.class).asList();
148+
private List<Element> elementList(GstIteratorPtr iter) {
149+
return GstIterator.asList(iter, Element.class);
150150
}
151151

152152
/**

src/org/freedesktop/gstreamer/Element.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@
3131

3232
import org.freedesktop.gstreamer.lowlevel.GstAPI.GstCallback;
3333
import org.freedesktop.gstreamer.lowlevel.GstContextPtr;
34+
import org.freedesktop.gstreamer.lowlevel.GstIteratorPtr;
35+
import org.freedesktop.gstreamer.lowlevel.GstObjectPtr;
3436

3537
import static org.freedesktop.gstreamer.lowlevel.GstElementAPI.GSTELEMENT_API;
3638
import static org.freedesktop.gstreamer.lowlevel.GObjectAPI.GOBJECT_API;
37-
import org.freedesktop.gstreamer.lowlevel.GstObjectPtr;
3839

3940
/**
4041
* Abstract base class for all pipeline elements.
@@ -82,7 +83,7 @@ public class Element extends GstObject {
8283
protected Element(Initializer init) {
8384
super(init);
8485
}
85-
86+
8687
Element(Handle handle, boolean needRef) {
8788
super(handle, needRef);
8889
}
@@ -346,7 +347,7 @@ public Pad getStaticPad(String padname) {
346347
* @return the List of {@link Pad}s.
347348
*/
348349
public List<Pad> getPads() {
349-
return new GstIterator<Pad>(GSTELEMENT_API.gst_element_iterate_pads(this), Pad.class).asList();
350+
return padList(GSTELEMENT_API.gst_element_iterate_pads(this));
350351
}
351352

352353
/**
@@ -355,7 +356,7 @@ public List<Pad> getPads() {
355356
* @return the List of {@link Pad}s.
356357
*/
357358
public List<Pad> getSrcPads() {
358-
return new GstIterator<Pad>(GSTELEMENT_API.gst_element_iterate_src_pads(this), Pad.class).asList();
359+
return padList(GSTELEMENT_API.gst_element_iterate_src_pads(this));
359360
}
360361

361362
/**
@@ -364,7 +365,11 @@ public List<Pad> getSrcPads() {
364365
* @return the List of {@link Pad}s.
365366
*/
366367
public List<Pad> getSinkPads() {
367-
return new GstIterator<Pad>(GSTELEMENT_API.gst_element_iterate_sink_pads(this), Pad.class).asList();
368+
return padList(GSTELEMENT_API.gst_element_iterate_sink_pads(this));
369+
}
370+
371+
private List<Pad> padList(GstIteratorPtr iter) {
372+
return GstIterator.asList(iter, Pad.class);
368373
}
369374

370375
/**
@@ -770,7 +775,7 @@ public void setContext(Context context) {
770775

771776
/**
772777
* Gets the context with the context_type set on the element or NULL.
773-
*
778+
*
774779
* @param context_type
775780
* @return a context or NULL
776781
*/
@@ -780,11 +785,11 @@ public Context getContext(String context_type) {
780785
}
781786

782787
static class Handle extends GstObject.Handle {
783-
788+
784789
public Handle(GstObjectPtr ptr, boolean ownsHandle) {
785790
super(ptr, ownsHandle);
786791
}
787-
792+
788793
}
789794

790795
}
Lines changed: 18 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
/*
2-
* Copyright (c) 2019 Neil C Smith
3-
* Copyright (c) 2009 Levente Farkas
4-
* Copyright (c) 2007 Wayne Meissner
2+
* Copyright (c) 2021 Neil C Smith
53
*
64
* This file is part of gstreamer-java.
75
*
@@ -19,96 +17,32 @@
1917
*/
2018
package org.freedesktop.gstreamer;
2119

22-
import com.sun.jna.Pointer;
23-
24-
import java.util.Collections;
25-
import java.util.Iterator;
26-
import java.util.LinkedList;
20+
import java.util.ArrayList;
2721
import java.util.List;
2822

23+
import org.freedesktop.gstreamer.glib.NativeObject;
24+
import org.freedesktop.gstreamer.lowlevel.GstIteratorPtr;
25+
import org.freedesktop.gstreamer.lowlevel.GstTypes;
2926
import org.freedesktop.gstreamer.lowlevel.GType;
3027
import org.freedesktop.gstreamer.lowlevel.GValueAPI;
31-
import org.freedesktop.gstreamer.lowlevel.GstTypes;
32-
import org.freedesktop.gstreamer.glib.NativeObject;
33-
import org.freedesktop.gstreamer.lowlevel.GPointer;
3428

3529
import static org.freedesktop.gstreamer.lowlevel.GstIteratorAPI.GSTITERATOR_API;
3630

3731
/**
38-
*
32+
* Utility class for working with gstiterator.
3933
*/
40-
class GstIterator<T extends NativeObject> extends NativeObject implements java.lang.Iterable<T> {
41-
42-
private final GType gtype;
43-
44-
GstIterator(Pointer ptr, Class<T> cls) {
45-
super(new Handle(new GPointer(ptr), true));
46-
gtype = GstTypes.typeFor(cls);
47-
}
48-
49-
@Override
50-
public Iterator<T> iterator() {
51-
return new IteratorImpl();
52-
}
53-
54-
public List<T> asList() {
55-
List<T> list = new LinkedList<T>();
56-
for (T t : this) {
57-
list.add(t);
58-
}
59-
return Collections.unmodifiableList(list);
60-
}
61-
62-
class IteratorImpl implements java.util.Iterator<T> {
63-
64-
final GValueAPI.GValue gValue;
65-
66-
T next;
67-
68-
IteratorImpl() {
69-
gValue = new GValueAPI.GValue(gtype);
70-
next = getNext();
71-
}
72-
73-
private T getNext() {
74-
if (GSTITERATOR_API.gst_iterator_next(getRawPointer(), gValue) == 1) {
75-
T result = (T) gValue.getValue();
76-
// reset cached structure or we get a memory leak
77-
gValue.reset();
78-
return result;
79-
} else {
80-
return null;
81-
}
82-
}
83-
84-
@Override
85-
public boolean hasNext() {
86-
return next != null;
87-
}
88-
89-
@Override
90-
public T next() {
91-
T result = next;
92-
next = getNext();
93-
return result;
94-
}
95-
96-
@Override
97-
public void remove() {
98-
throw new UnsupportedOperationException("Items cannot be removed.");
99-
}
100-
}
34+
class GstIterator {
10135

102-
private static final class Handle extends NativeObject.Handle {
103-
104-
public Handle(GPointer ptr, boolean ownsHandle) {
105-
super(ptr, ownsHandle);
106-
}
107-
108-
@Override
109-
protected void disposeNativeHandle(GPointer ptr) {
110-
GSTITERATOR_API.gst_iterator_free(ptr.getPointer());
111-
}
112-
36+
static <T extends NativeObject> List<T> asList(GstIteratorPtr iter, Class<T> type) {
37+
final GType gtype = GstTypes.typeFor(type);
38+
final GValueAPI.GValue gValue = new GValueAPI.GValue(gtype);
39+
List<T> list = new ArrayList<>();
40+
while (GSTITERATOR_API.gst_iterator_next(iter, gValue) == 1) {
41+
list.add((T) gValue.getValue());
42+
}
43+
gValue.reset();
44+
GSTITERATOR_API.gst_iterator_free(iter);
45+
return list;
11346
}
47+
11448
}

src/org/freedesktop/gstreamer/lowlevel/GstBinAPI.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
* Copyright (c) 2021 Neil C Smith
23
* Copyright (c) 2009 Levente Farkas
34
* Copyright (c) 2007, 2008 Wayne Meissner
45
*
@@ -43,12 +44,12 @@ public interface GstBinAPI extends com.sun.jna.Library {
4344
@CallerOwnsReturn Element gst_bin_get_by_name(Bin bin, String name);
4445
@CallerOwnsReturn Element gst_bin_get_by_name_recurse_up(Bin bin, String name);
4546
@CallerOwnsReturn Element gst_bin_get_by_interface(Bin bin, GType iface);
46-
Pointer gst_bin_iterate_elements(Bin bin);
47-
Pointer gst_bin_iterate_sorted(Bin bin);
48-
Pointer gst_bin_iterate_recurse(Bin bin);
49-
Pointer gst_bin_iterate_sinks(Bin bin);
50-
Pointer gst_bin_iterate_sources(Bin bin);
51-
Pointer gst_bin_iterate_all_by_interface(Bin bin, GType iface);
47+
GstIteratorPtr gst_bin_iterate_elements(Bin bin);
48+
GstIteratorPtr gst_bin_iterate_sorted(Bin bin);
49+
GstIteratorPtr gst_bin_iterate_recurse(Bin bin);
50+
GstIteratorPtr gst_bin_iterate_sinks(Bin bin);
51+
GstIteratorPtr gst_bin_iterate_sources(Bin bin);
52+
GstIteratorPtr gst_bin_iterate_all_by_interface(Bin bin, GType iface);
5253

5354
//Debugging
5455
void gst_debug_bin_to_dot_file (Bin bin, int details, String file_name);

src/org/freedesktop/gstreamer/lowlevel/GstElementAPI.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
* Copyright (c) 2021 Neil C Smith
23
* Copyright (c) 2009 Levente Farkas
34
* Copyright (c) 2007, 2008 Wayne Meissner
45
*
@@ -83,9 +84,9 @@ boolean gst_element_seek(Element elem, double rate, Format format, int flags,
8384
boolean gst_element_link_pads_filtered(Element src, String srcpadname, Element dest, String destpadname,
8485
Caps filter);
8586

86-
Pointer gst_element_iterate_pads(Element element);
87-
Pointer gst_element_iterate_src_pads(Element element);
88-
Pointer gst_element_iterate_sink_pads(Element element);
87+
GstIteratorPtr gst_element_iterate_pads(Element element);
88+
GstIteratorPtr gst_element_iterate_src_pads(Element element);
89+
GstIteratorPtr gst_element_iterate_sink_pads(Element element);
8990
/* factory management */
9091
ElementFactory gst_element_get_factory(Element element);
9192
@CallerOwnsReturn Bus gst_element_get_bus(Element element);

src/org/freedesktop/gstreamer/lowlevel/GstIteratorAPI.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
/*
2-
* Copyright (c) 2016 Neil C Smith
3-
* Copyright (c) 2009 Levente Farkas
4-
* Copyright (c) 2007, 2008 Wayne Meissner
2+
* Copyright (c) 2021 Neil C Smith
53
*
64
* This file is part of gstreamer-java.
75
*
@@ -20,15 +18,14 @@
2018

2119
package org.freedesktop.gstreamer.lowlevel;
2220

23-
import com.sun.jna.Pointer;
24-
2521
/**
2622
* GstIterator functions
2723
*/
2824
public interface GstIteratorAPI extends com.sun.jna.Library {
25+
2926
GstIteratorAPI GSTITERATOR_API = GstNative.load(GstIteratorAPI.class);
3027

31-
void gst_iterator_free(Pointer iter);
32-
int gst_iterator_next(Pointer iter, GValueAPI.GValue next);
33-
void gst_iterator_resync(Pointer iter);
28+
void gst_iterator_free(GstIteratorPtr iter);
29+
int gst_iterator_next(GstIteratorPtr iter, GValueAPI.GValue next);
30+
void gst_iterator_resync(GstIteratorPtr iter);
3431
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2021 Neil C Smith
3+
*
4+
* This file is part of gstreamer-java.
5+
*
6+
* This code is free software: you can redistribute it and/or modify it under the terms of the GNU
7+
* Lesser General Public License version 3 only, as published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10+
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
* Lesser General Public License version 3 for more details.
12+
*
13+
* You should have received a copy of the GNU Lesser General Public License version 3 along with
14+
* this work. If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
package org.freedesktop.gstreamer.lowlevel;
17+
18+
import com.sun.jna.Pointer;
19+
20+
/**
21+
* GstIterator pointer.
22+
*/
23+
public class GstIteratorPtr extends GPointer {
24+
25+
public GstIteratorPtr() {
26+
}
27+
28+
public GstIteratorPtr(Pointer ptr) {
29+
super(ptr);
30+
}
31+
32+
}

test/org/freedesktop/gstreamer/GarbageCollectionTest.java

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static org.junit.Assert.assertTrue;
2424

2525
import java.lang.ref.WeakReference;
26+
import java.util.List;
2627

2728
import org.junit.After;
2829
import org.junit.AfterClass;
@@ -76,16 +77,45 @@ public void testBin() throws Exception {
7677

7778
assertEquals("source not returned", e1, bin.getElementByName("source"));
7879
assertEquals("sink not returned", e2, bin.getElementByName("sink"));
79-
WeakReference<Element> binRef = new WeakReference<Element>(bin);
80+
GCTracker binTracker = new GCTracker(bin);
8081
bin = null;
81-
assertTrue("Bin not garbage collected", GCTracker.waitGC(binRef));
82-
WeakReference<Element> e1Ref = new WeakReference<Element>(e1);
83-
WeakReference<Element> e2Ref = new WeakReference<Element>(e2);
82+
assertTrue("Bin not garbage collected", binTracker.waitGC());
83+
assertTrue("Bin not destroyed", binTracker.waitDestroyed());
84+
GCTracker e1Tracker = new GCTracker(e1);
85+
GCTracker e2Tracker = new GCTracker(e2);
8486
e1 = null;
8587
e2 = null;
8688

87-
assertTrue("First Element not garbage collected", GCTracker.waitGC(e1Ref));
88-
assertTrue("Second Element not garbage collected", GCTracker.waitGC(e2Ref));
89+
assertTrue("First Element not garbage collected", e1Tracker.waitGC());
90+
assertTrue("First Element not destroyed", e1Tracker.waitDestroyed());
91+
assertTrue("Second Element not garbage collected", e2Tracker.waitGC());
92+
assertTrue("Second Element not destroyed", e2Tracker.waitDestroyed());
93+
94+
}
95+
96+
@Test
97+
public void testBinParsed() throws Exception {
98+
Bin bin = Gst.parseBinFromDescription("fakesrc name=source ! fakesink name=sink", false);
99+
int binRefCount = bin.getRefCount();
100+
List<Element> children = bin.getElements();
101+
assertEquals("Iteration increased Bin refcount", binRefCount, bin.getRefCount());
102+
assertEquals("Wrong number of child elements", 2, children.size());
103+
Element e1 = children.get(0);
104+
Element e2 = children.get(1);
105+
GCTracker binTracker = new GCTracker(bin);
106+
bin = null;
107+
assertTrue("Bin not garbage collected", binTracker.waitGC());
108+
assertTrue("Bin not destroyed", binTracker.waitDestroyed());
109+
GCTracker e1Tracker = new GCTracker(e1);
110+
GCTracker e2Tracker = new GCTracker(e2);
111+
children = null;
112+
e1 = null;
113+
e2 = null;
114+
115+
assertTrue("First Element not garbage collected", e1Tracker.waitGC());
116+
assertTrue("First Element not destroyed", e1Tracker.waitDestroyed());
117+
assertTrue("Second Element not garbage collected", e2Tracker.waitGC());
118+
assertTrue("Second Element not destroyed", e2Tracker.waitDestroyed());
89119

90120
}
91121
@Test

0 commit comments

Comments
 (0)