Skip to content

Commit 95e37e9

Browse files
Merge pull request #234 from codelerity/gstiterator
Stop GstIterator keeping references alive until GC.
2 parents 31e4361 + 1ff6ce7 commit 95e37e9

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)