/* * Copyright (c) 2009 Levente Farkas * Copyright (C) 2007 Wayne Meissner * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> * 2004 Wim Taymans <wim@fluendo.com> * * 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 <http://www.gnu.org/licenses/>. */ package org.gstreamer; import java.util.List; import org.gstreamer.lowlevel.GstAPI.GErrorStruct; import org.gstreamer.lowlevel.GstAPI.GstCallback; import org.gstreamer.lowlevel.GstBinAPI; import org.gstreamer.lowlevel.GstNative; import org.gstreamer.lowlevel.GstParseAPI; import org.gstreamer.lowlevel.GstTypes; import org.gstreamer.lowlevel.annotations.CallerOwnsReturn; import com.sun.jna.Pointer; /** * Base class and element that can contain other elements. * * Bin is an element that can contain other {@link Element}s, allowing them to be * managed as a group. * <p> * Pads from the child elements can be ghosted to the bin, see {@link GhostPad}. * This makes the bin look like any other elements and enables creation of * higher-level abstraction elements. * <p> * A new {@link Bin} is created with {@link Bin#Bin(String)}. Use a {@link Pipeline} instead if you * want to create a toplevel bin because a normal bin doesn't have a bus or * handle clock distribution of its own. * <p> * After the bin has been created you will typically add elements to it with * {@link Bin#add(Element)}. Elements can be removed with {@link Bin#remove(Element)} * <p> * An element can be retrieved from a bin with {@link Bin#getElementByName(String)}. * <p> * A list of elements contained in a bin can be retrieved with {@link Bin#getElements} * * The {@link ELEMENT_ADDED} signal is fired whenever a new element is added * to the bin. Likewise the {@link ELEMENT_REMOVED} signal is fired * whenever an element is removed from the bin. * */ public class Bin extends Element { public static final String GST_NAME = "bin"; public static final String GTYPE_NAME = "GstBin"; private static interface API extends GstBinAPI, GstParseAPI { @CallerOwnsReturn Pointer ptr_gst_pipeline_new(String name); } private static final API gst = GstNative.load(API.class); public static final int DEBUG_GRAPH_SHOW_MEDIA_TYPE = (1<<0); public static final int DEBUG_GRAPH_SHOW_CAPS_DETAILS = (1<<1); public static final int DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS = (1<<2); public static final int DEBUG_GRAPH_SHOW_STATES = (1<<3); public static final int DEBUG_GRAPH_SHOW_ALL = ((1<<4)-1); public Bin(Initializer init) { super(init); } /** * Creates a new Bin with a unique name. */ public Bin() { this(initializer(gst.ptr_gst_bin_new(null))); } /** * Creates a new Bin with the given name. * @param name The Name to assign to the new Bin */ public Bin(String name) { this(initializer(gst.ptr_gst_bin_new(name))); } /** * Creates a bin from a text bin description. * * This function allows creation of a bin based on the syntax used in the * gst-launch utillity. * * @param binDecription the command line describing the bin * @param ghostUnlinkedPads whether to create ghost pads for the bin from any unlinked pads * @return The new Bin. */ public static Bin launch(String binDecription, boolean ghostUnlinkedPads) { Pointer[] err = { null }; Bin bin = gst.gst_parse_bin_from_description(binDecription, ghostUnlinkedPads, err); if (bin == null) { throw new GstException(new GError(new GErrorStruct(err[0]))); } return bin; } /** * Adds an Element to this Bin. * <p> * Sets the element's parent, and thus takes ownership of the element. * An element can only be added to one bin. * <p> * If the element's pads are linked to other pads, the pads will be unlinked * before the element is added to the bin. * * @param element The {@link Element} to add to this Bin. * @return true if the element was successfully added, false if the Bin * will not accept the element. */ public boolean add(Element element) { return gst.gst_bin_add(this, element); } /** * Adds an array of Element objects to this Bin * * @param elements The array of {@link Element} to add to this Bin * @see Bin#add(Element) */ public void addMany(Element... elements) { gst.gst_bin_add_many(this, elements); } /** * Removes a Element from this Bin * <p> * Removes the element from the bin, unparenting it as well. * * If the element's pads are linked to other pads, the pads will be unlinked * before the element is removed from the bin. * * @param element The {@link Element} to remove * @return true if the element was successfully removed */ public boolean remove(Element element) { return gst.gst_bin_remove(this, element); } /** * Removes an array of {@link Element} objects from this Bin * * @param elements The list {@link Element} to remove */ public void removeMany(Element... elements) { gst.gst_bin_remove_many(this, elements); } private List<Element> elementList(Pointer iter) { return new GstIterator<Element>(iter, Element.class).asList(); } /** * Retrieve a list of the {@link Element}s contained in the Bin. * * @return The List of {@link Element}s. */ public List<Element> getElements() { return elementList(gst.gst_bin_iterate_elements(this)); } /** * Gets an a list of the elements in this bin in topologically * sorted order. This means that the elements are returned from * the most downstream elements (sinks) to the sources. * @return The List of {@link Element}s. */ public List<Element> getElementsSorted() { return elementList(gst.gst_bin_iterate_sorted(this)); } /** * Retrieve a list of the {@link Element}s contained in the Bin and its Bin children. * * This differs from {@link #getElements()} as it will also return {@link Element}s * that are in any Bin elements contained in this Bin, also recursing down those Bins. * * @return The List of {@link Element}s. */ public List<Element> getElementsRecursive() { return elementList(gst.gst_bin_iterate_recurse(this)); } /** * Retrieve a list of the sink {@link Element}s contained in the Bin. * @return The List of sink {@link Element}s. */ public List<Element> getSinks() { return elementList(gst.gst_bin_iterate_sinks(this)); } /** * Retrieve a list of the source {@link Element}s contained in the Bin. * @return The List of source {@link Element}s. */ public List<Element> getSources() { return elementList(gst.gst_bin_iterate_sources(this)); } /** * Gets the {@link Element} with the given name from the bin. This * function recurses into child bins. * * @param name The name of the {@link Element} to find. * @return The {@link Element} if found, else null. */ public Element getElementByName(String name) { return gst.gst_bin_get_by_name(this, name); } /** * Gets the element with the given name from this bin. If the * element is not found, a recursion is performed on the parent bin. * @param name The name of the {@link Element} to find. * @return The {@link Element} if found, else null. */ public Element getElementByNameRecurseUp(String name) { return gst.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 extends Element> T getElementByInterface(Class<T> iface) { return iface.cast(gst.gst_bin_get_by_interface(this, GstTypes.typeFor(iface))); } /** * Calls {@link #debugToDotFile(int, String, boolean)} without timestamping */ public void debugToDotFile(int details, String fileName) { debugToDotFile(details, fileName, false); } /** * To aid debugging applications one can use this method to write out the whole * network of gstreamer elements that form the pipeline into an dot file. * This file can be processed with graphviz to get an image. * e.g. dot -Tpng -oimage.png graph_lowlevel.dot * * The function is only active if gstreamer is configured with * "--gst-enable-gst-debug" and the environment variable * GST_DEBUG_DUMP_DOT_DIR is set to a basepath (e.g. /tmp). * * @param details to show in the graph, e.g. DEBUG_GRAPH_SHOW_ALL * @param fileName output base filename (e.g. "myplayer") * @param timestampFileName if true it adds the current timestamp * to the filename, so that it can be used to take multiple snapshots. */ public void debugToDotFile(int details, String fileName, boolean timestampFileName) { if (timestampFileName) gst._gst_debug_bin_to_dot_file_with_ts(this, details, fileName); else gst._gst_debug_bin_to_dot_file(this, details, fileName); } /** * Signal emitted when an {@link Element} is added to this Bin * * @see #connect(ELEMENT_ADDED) * @see #disconnect(ELEMENT_ADDED) */ public static interface ELEMENT_ADDED { /** * Called when an {@link Element} is added to a {@link Bin} * * @param bin the Bin the element was added to. * @param element the {@link Element} that was added. */ public void elementAdded(Bin bin, Element element); } /** * Add a listener for the <code>element-added</code> signal on this Bin * * @param listener The listener to be called when an {@link Element} is added. */ public void connect(final ELEMENT_ADDED listener) { connect(ELEMENT_ADDED.class, listener, new GstCallback() { @SuppressWarnings("unused") public void callback(Bin bin, Element elem) { listener.elementAdded(bin, elem); } }); } /** * Disconnect the listener for the <code>element-added</code> signal * * @param listener The listener that was registered to receive the signal. */ public void disconnect(ELEMENT_ADDED listener) { disconnect(ELEMENT_ADDED.class, listener); } /** * Signal emitted when an {@link Element} is removed from this Bin * * @see #connect(ELEMENT_REMOVED) * @see #disconnect(ELEMENT_REMOVED) */ public static interface ELEMENT_REMOVED { /** * Called when an {@link Element} is removed from a {@link Bin} * * @param bin the Bin the element was removed from. * @param element the {@link Element} that was removed. */ public void elementRemoved(Bin bin, Element element); } /** * Add a listener for the <code>element-removed</code> signal on this Bin * * @param listener The listener to be called when an {@link Element} is removed. */ public void connect(final ELEMENT_REMOVED listener) { connect(ELEMENT_REMOVED.class, listener, new GstCallback() { @SuppressWarnings("unused") public void callback(Bin bin, Element elem) { listener.elementRemoved(bin, elem); } }); } /** * Disconnect the listener for the <code>element-removed</code> signal * * @param listener The listener that was registered to receive the signal. */ public void disconnect(ELEMENT_REMOVED listener) { disconnect(ELEMENT_REMOVED.class, listener); } /** * Signal emitted when an {@link Element} has latency * * @see #connect(DO_LATENCY) * @see #disconnect(DO_LATENCY) */ public static interface DO_LATENCY { /** * Called when an {@link Element} is removed from a {@link Bin} * * @param bin the Bin the element was removed from. */ public void doLatency(Bin bin); } /** * Add a listener for the <code>do-latency</code> signal on this Bin * * @param listener The listener to be called when an {@link Element} is removed. */ public void connect(final DO_LATENCY listener) { connect(DO_LATENCY.class, listener, new GstCallback() { @SuppressWarnings("unused") public void callback(Bin bin) { listener.doLatency(bin); } }); } /** * Disconnect the listener for the <code>do-latency</code> signal * * @param listener The listener that was registered to receive the signal. */ public void disconnect(DO_LATENCY listener) { disconnect(DO_LATENCY.class, listener); } }