Skip to content

Commit 4f5c9e7

Browse files
Merge pull request #226 from codelerity/probe-mapping
Add support for generic probes on Pad.
2 parents 79e0c5f + dd6213f commit 4f5c9e7

File tree

8 files changed

+737
-26
lines changed

8 files changed

+737
-26
lines changed

src/org/freedesktop/gstreamer/Pad.java

Lines changed: 131 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019 Neil C Smith
2+
* Copyright (C) 2020 Neil C Smith
33
* Copyright (C) 2018 Antonio Morales
44
* Copyright (C) 2014 Tom Greenwood <[email protected]>
55
* Copyright (C) 2009 Tamas Korodi <[email protected]>
@@ -28,6 +28,7 @@
2828
import com.sun.jna.Pointer;
2929
import java.util.HashSet;
3030
import java.util.Set;
31+
import org.freedesktop.gstreamer.glib.NativeFlags;
3132
import org.freedesktop.gstreamer.glib.Natives;
3233

3334
import org.freedesktop.gstreamer.lowlevel.GstAPI.GstCallback;
@@ -80,7 +81,7 @@
8081
public class Pad extends GstObject {
8182

8283
public static final String GTYPE_NAME = "GstPad";
83-
84+
8485
private static final int EVENT_HAS_INFO_MASK = GstPadAPI.GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GstPadAPI.GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
8586
private final Handle handle;
8687

@@ -95,7 +96,7 @@ private Pad(Handle handle, boolean needRef) {
9596
super(handle, needRef);
9697
this.handle = handle;
9798
}
98-
99+
99100
/**
100101
* Creates a new pad with the given name in the given direction. If name is
101102
* null, a guaranteed unique name (across all pads) will be assigned.
@@ -190,7 +191,7 @@ public Pad getPeer() {
190191
* filter contains the caps accepted by downstream in the preferred order.
191192
* filter might be NULL but if it is not NULL the returned caps will be a
192193
* subset of filter .
193-
*
194+
*
194195
* @param filter Caps to filter by, or null
195196
* @return the {@link Caps} of the peer pad, or null if there is no peer
196197
* pad.
@@ -386,6 +387,85 @@ public void disconnect(UNLINKED listener) {
386387
disconnect(UNLINKED.class, listener);
387388
}
388389

390+
/**
391+
* Be notified of different states of pads. The provided callback is called
392+
* for every state that matches mask.
393+
* <p>
394+
* Probes are called in groups: First {@link PadProbeType#BLOCK} probes are
395+
* called, then others, then finally {@link PadProbeType#IDLE}. The only
396+
* exception here are IDLE probes that are called immediately if the pad is
397+
* already idle while calling addProbe(). In each of the groups, probes are
398+
* called in the order in which they were added.
399+
*
400+
* @param mask set of mask flags for probe - common options are fields of
401+
* {@link PadProbeType}
402+
* @param callback callback that will be called with notifications of the
403+
* pad state
404+
*/
405+
public void addProbe(final Set<PadProbeType> mask, PROBE callback) {
406+
addProbe(NativeFlags.toInt(mask), callback);
407+
}
408+
409+
/**
410+
* Be notified of different states of pads. The provided callback is called
411+
* for every state that matches mask.
412+
* <p>
413+
* Probes are called in groups: First {@link PadProbeType#BLOCK} probes are
414+
* called, then others, then finally {@link PadProbeType#IDLE}. The only
415+
* exception here are IDLE probes that are called immediately if the pad is
416+
* already idle while calling addProbe(). In each of the groups, probes are
417+
* called in the order in which they were added.
418+
*
419+
* @param mask mask flag for probe
420+
* @param callback callback that will be called with notifications of the
421+
* pad state
422+
*/
423+
public void addProbe(PadProbeType mask, PROBE callback) {
424+
addProbe(mask.intValue(), callback);
425+
}
426+
427+
synchronized void addProbe(int mask, PROBE callback) {
428+
final GstPadAPI.PadProbeCallback probe = new GstPadAPI.PadProbeCallback() {
429+
@Override
430+
public PadProbeReturn callback(Pad pad, GstPadProbeInfo probeInfo, Pointer user_data) {
431+
PadProbeInfo info = new PadProbeInfo(probeInfo);
432+
PadProbeReturn ret = callback.probeCallback(pad, info);
433+
info.invalidate();
434+
if (ret == PadProbeReturn.REMOVE) {
435+
// don't want handle to try and remove in GCallback::disconnect
436+
// @TODO move to Map<PROBE, NativeLong> of probes over callback
437+
handle.probes.remove(probeInfo.id);
438+
removeCallback(PROBE.class, callback);
439+
}
440+
return ret;
441+
}
442+
};
443+
444+
NativeLong id = handle.addProbe(mask, probe);
445+
if (id.longValue() == 0) {
446+
// the Probe was an IDLE-Probe and it was already handled synchronously in handle.addProbe,
447+
// so no Callback needs to be registered
448+
return;
449+
}
450+
451+
GCallback cb = new GCallback(id, probe) {
452+
@Override
453+
protected void disconnect() {
454+
handle.removeProbe(id);
455+
}
456+
};
457+
addCallback(PROBE.class, callback, cb);
458+
}
459+
460+
/**
461+
* Remove the provided probe callback from the Pad.
462+
*
463+
* @param callback callback to remove
464+
*/
465+
public synchronized void removeProbe(PROBE callback) {
466+
removeCallback(PROBE.class, callback);
467+
}
468+
389469
public void addEventProbe(final EVENT_PROBE listener) {
390470
final int mask = GstPadAPI.GST_PAD_PROBE_TYPE_EVENT_BOTH | GstPadAPI.GST_PAD_PROBE_TYPE_EVENT_FLUSH;
391471
addEventProbe(listener, mask);
@@ -394,16 +474,20 @@ public void addEventProbe(final EVENT_PROBE listener) {
394474
synchronized void addEventProbe(final EVENT_PROBE listener, final int mask) {
395475
final GstPadAPI.PadProbeCallback probe = new GstPadAPI.PadProbeCallback() {
396476
public PadProbeReturn callback(Pad pad, GstPadProbeInfo probeInfo, Pointer user_data) {
397-
// System.out.println("CALLBACK " + probeInfo.padProbeType);
398477
if ((probeInfo.padProbeType & mask) != 0) {
399478
Event event = null;
400479
if ((probeInfo.padProbeType & EVENT_HAS_INFO_MASK) != 0) {
401480
event = GSTPAD_API.gst_pad_probe_info_get_event(probeInfo);
402481
}
403-
return listener.eventReceived(pad, event);
482+
PadProbeReturn ret = listener.eventReceived(pad, event);
483+
if (ret == PadProbeReturn.REMOVE) {
484+
// don't want handle to try and remove in GCallback::disconnect
485+
handle.probes.remove(probeInfo.id);
486+
removeCallback(EVENT_PROBE.class, listener);
487+
}
488+
return ret;
404489
}
405490

406-
//We have to negate the return value to keep consistency with gstreamer's API
407491
return PadProbeReturn.OK;
408492
}
409493
};
@@ -434,10 +518,15 @@ public synchronized void addDataProbe(final DATA_PROBE listener) {
434518
public PadProbeReturn callback(Pad pad, GstPadProbeInfo probeInfo, Pointer user_data) {
435519
if ((probeInfo.padProbeType & GstPadAPI.GST_PAD_PROBE_TYPE_BUFFER) != 0) {
436520
Buffer buffer = GSTPAD_API.gst_pad_probe_info_get_buffer(probeInfo);
437-
return listener.dataReceived(pad, buffer);
521+
PadProbeReturn ret = listener.dataReceived(pad, buffer);
522+
if (ret == PadProbeReturn.REMOVE) {
523+
// don't want handle to try and remove in GCallback::disconnect
524+
handle.probes.remove(probeInfo.id);
525+
removeCallback(DATA_PROBE.class, listener);
526+
}
527+
return ret;
438528
}
439529

440-
//We have to negate the return value to keep consistency with gstreamer's API
441530
return PadProbeReturn.OK;
442531
}
443532
};
@@ -609,7 +698,6 @@ public PadTemplate getTemplate() {
609698
public boolean hasCurrentCaps() {
610699
return GSTPAD_API.gst_pad_has_current_caps(this);
611700
}
612-
613701

614702
/**
615703
* Signal emitted when new this {@link Pad} is linked to another {@link Pad}
@@ -647,31 +735,55 @@ public static interface UNLINKED {
647735
}
648736

649737
/**
650-
* Signal emitted when an event passes through this <tt>Pad</tt>.
738+
* Callback used by
739+
* {@link #addProbe(java.util.EnumSet, org.freedesktop.gstreamer.Pad.PROBE)}
740+
*/
741+
public static interface PROBE {
742+
743+
/**
744+
* Callback used by
745+
* {@link #addProbe(java.util.EnumSet, org.freedesktop.gstreamer.Pad.PROBE)}.
746+
* Gets called to notify about the current blocking type.
747+
* <p>
748+
* <b>The PadProbeInfo and any Buffer, Event or Query referenced from
749+
* it, is only valid for the duration of the callback.</b>
750+
*
751+
* @param pad Pad that is blocked
752+
* @param info PadProbeInfo with access to underlying data
753+
* @return PadProbeReturn value
754+
*/
755+
public PadProbeReturn probeCallback(Pad pad, PadProbeInfo info);
756+
757+
}
758+
759+
/**
760+
* Probe for listening when an event passes through this Pad.
651761
*
652762
* @see #addEventProbe(EVENT_PROBE)
653763
* @see #removeEventProbe(EVENT_PROBE)
654764
*/
655765
public static interface EVENT_PROBE {
656766

657767
public PadProbeReturn eventReceived(Pad pad, Event event);
768+
658769
}
659770

660771
/**
661-
* Signal emitted when new data is available on the {@link Pad}
772+
* Probe for listening when new data is available on the Pad.
662773
*
663774
* @see #addDataProbe(DATA_PROBE)
664775
* @see #removeDataProbe(DATA_PROBE)
665776
*/
666777
public static interface DATA_PROBE {
667778

668779
public PadProbeReturn dataReceived(Pad pad, Buffer buffer);
780+
669781
}
670-
782+
671783
private static class Handle extends GstObject.Handle {
672-
784+
673785
private final Set<NativeLong> probes;
674-
786+
675787
private Handle(GstPadPtr ptr, boolean ownsHandle) {
676788
super(ptr, ownsHandle);
677789
probes = new HashSet<>();
@@ -681,21 +793,21 @@ private Handle(GstPadPtr ptr, boolean ownsHandle) {
681793
protected GstPadPtr getPointer() {
682794
return (GstPadPtr) super.getPointer();
683795
}
684-
796+
685797
private synchronized NativeLong addProbe(int mask, GstPadAPI.PadProbeCallback probe) {
686798
NativeLong id = GSTPAD_API.gst_pad_add_probe(getPointer(), mask, probe, null, null);
687799
if (id.longValue() != 0) {
688800
probes.add(id);
689801
}
690802
return id;
691803
}
692-
804+
693805
private synchronized void removeProbe(NativeLong id) {
694806
if (probes.remove(id)) {
695807
GSTPAD_API.gst_pad_remove_probe(getPointer(), id);
696808
}
697809
}
698-
810+
699811
private synchronized void clearProbes() {
700812
probes.forEach(id -> GSTPAD_API.gst_pad_remove_probe(getPointer(), id));
701813
probes.clear();
@@ -712,7 +824,6 @@ public void dispose() {
712824
clearProbes();
713825
super.dispose();
714826
}
715-
716-
827+
717828
}
718829
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (C) 2020 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
7+
* the terms of the GNU Lesser General Public License version 3 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13+
* version 3 for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package org.freedesktop.gstreamer;
19+
20+
import java.util.Set;
21+
import org.freedesktop.gstreamer.event.Event;
22+
import org.freedesktop.gstreamer.glib.NativeFlags;
23+
import org.freedesktop.gstreamer.lowlevel.GstPadProbeInfo;
24+
import org.freedesktop.gstreamer.query.Query;
25+
26+
import static org.freedesktop.gstreamer.lowlevel.GstPadAPI.GSTPAD_API;
27+
28+
/**
29+
* Probe info passed in to Pad.PROBE callback.
30+
*/
31+
public final class PadProbeInfo {
32+
33+
private GstPadProbeInfo info;
34+
35+
PadProbeInfo(GstPadProbeInfo info) {
36+
this.info = info;
37+
}
38+
39+
/**
40+
* Get the set of flags for the current probe type.
41+
*
42+
* @return probe type
43+
*/
44+
public Set<PadProbeType> getType() {
45+
return NativeFlags.fromInt(PadProbeType.class, info.padProbeType);
46+
}
47+
48+
/**
49+
* Get the Buffer from the probe, or null.
50+
*
51+
* @return buffer or null
52+
*/
53+
public Buffer getBuffer() {
54+
return GSTPAD_API.gst_pad_probe_info_get_buffer(info);
55+
}
56+
57+
/**
58+
* Get the Event from the probe, or null.
59+
*
60+
* @return event or null
61+
*/
62+
public Event getEvent() {
63+
return GSTPAD_API.gst_pad_probe_info_get_event(info);
64+
}
65+
66+
/**
67+
* Get the query from the probe, or null.
68+
*
69+
* @return query or null
70+
*/
71+
public Query getQuery() {
72+
return GSTPAD_API.gst_pad_probe_info_get_query(info);
73+
}
74+
75+
void invalidate() {
76+
info = null;
77+
}
78+
79+
}

0 commit comments

Comments
 (0)