/*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
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;
/**
* ElementFactory is used to create instances of elements.
*
* Use the {@link #find} and {@link #create} methods to create element instances
* or use {@link #make} as a convenient shortcut.
*
*/
public class ElementFactory extends PluginFeature {
private static Logger logger = Logger.getLogger(ElementFactory.class.getName());
private static Level DEBUG = Level.FINE;
private static final Map<String, Class<? extends Element>> typeMap
= new HashMap<String, Class<? extends Element>>();
public static final String GTYPE_NAME = "GstElementFactory";
/**
* Register a new class into the typeMap.
*/
public static void registerElement(Class<? extends Element> klass, String name) {
typeMap.put(name, klass);
}
/**
* Retrieve an instance of a factory that can produce {@link Element}s
*
* @param name The type of {@link Element} to produce.
* @return An ElementFactory that will produce {@link Element}s of the
* desired type.
*/
public static ElementFactory find(String name) {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "find", name);
}
ElementFactory factory = GSTELEMENTFACTORY_API.gst_element_factory_find(name);
if (factory == null) {
throw new IllegalArgumentException("No such Gstreamer factory: " + name);
}
return factory;
}
/**
* Creates a new Element from the specified factory.
*
* @param factoryName The name of the factory to use to produce the Element
* @param name The name to assign to the created Element
* @return A new GstElemElement
*/
public static Element make(String factoryName, String name) {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "make", new Object[] { factoryName, name});
}
return elementFor(makeRawElement(factoryName, name), factoryName);
}
/**
* Get a list of factories that match the given type. Only elements with a
* rank greater or equal to minrank will be returned. The list of factories
* is returned by decreasing rank.
*
* @param type
* a {@link ElementFactoryListType}
* @param minrank
* Minimum rank
* @return a List of ElementFactory elements.
*/
public static List<ElementFactory> listGetElement(ElementFactoryListType type, Rank minrank) {
GList glist = GSTELEMENTFACTORY_API.gst_element_factory_list_get_elements(type.getValue(), minrank.getValue());
List<ElementFactory> list = new ArrayList<ElementFactory>();
GList next = glist;
while (next != null) {
if (next.data != null) {
ElementFactory fact = new ElementFactory(initializer(next.data, true, true));
list.add(fact);
}
next = next.next();
}
GSTPLUGIN_API.gst_plugin_list_free(glist);
return list;
}
/**
* Filter out all the elementfactories in list that can handle caps in the
* given direction.
*
* If subsetonly is true, then only the elements whose pads templates are a
* complete superset of caps will be returned. Else any element whose pad
* templates caps can intersect with caps will be returned.
*
* @param list
* a {@link List} of {@link ElementFactory} to filter
* @param caps
* a {@link Caps}
* @param direction
* a {@link PadDirection} to filter on
* @param subsetonly
* whether to filter on caps subsets or not.
* @return a {@link List} of {@link ElementFactory} elements that match the
* given requisits.
*/
public static List<ElementFactory> listFilter(List<ElementFactory> list, Caps caps,
PadDirection direction, boolean subsetonly) {
GList glist = null;
List<ElementFactory> filterList = new ArrayList<ElementFactory>();
for (ElementFactory fact : list) {
fact.ref();
glist = GLIB_API.g_list_append(glist, fact.handle());
}
GList gFilterList = GSTELEMENTFACTORY_API.gst_element_factory_list_filter(glist, caps, direction, subsetonly);
GList next = gFilterList;
while (next != null) {
if (next.data != null) {
ElementFactory fact = new ElementFactory(initializer(next.data, true, true));
filterList.add(fact);
}
next = next.next();
}
GSTPLUGIN_API.gst_plugin_list_free(glist);
GSTPLUGIN_API.gst_plugin_list_free(gFilterList);
return filterList;
}
/**
* Get a list of factories that match the given parameter.
*
* It is a combination of listGetElement and listFilter
* passing all the results of the first call to the second.
*
* This method improves performance because there is no need to map to java
* list the elements returned by the first call.
*
* @param type
* a {@link ElementFactoryListType}
* @param minrank
* Minimum rank
* @param caps
* a {@link Caps}
* @param direction
* a {@link PadDirection} to filter on
* @param subsetonly
* whether to filter on caps subsets or not.
* @return a {@link List} of {@link ElementFactory} elements that match the
* given requisits.
*/
public static List<ElementFactory> listGetElementFilter(ElementFactoryListType type, Rank minrank,
Caps caps, PadDirection direction, boolean subsetonly) {
List<ElementFactory> filterList = new ArrayList<ElementFactory>();
GList glist = GSTELEMENTFACTORY_API.gst_element_factory_list_get_elements(type.getValue(), minrank.getValue());
GList gFilterList = GSTELEMENTFACTORY_API.gst_element_factory_list_filter(glist, caps, direction, subsetonly);
GList next = gFilterList;
while (next != null) {
if (next.data != null) {
ElementFactory fact = new ElementFactory(initializer(next.data, true, true));
filterList.add(fact);
}
next = next.next();
}
GSTPLUGIN_API.gst_plugin_list_free(glist);
GSTPLUGIN_API.gst_plugin_list_free(gFilterList);
return filterList;
}
public static Pointer makeRawElement(String factoryName, String name) {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "makeRawElement", new Object[] { factoryName, name});
}
Pointer elem = GSTELEMENTFACTORY_API.ptr_gst_element_factory_make(factoryName, name);
logger.log(DEBUG, "Return from gst_element_factory_make=" + elem);
if (elem == null) {
throw new IllegalArgumentException("No such Gstreamer factory: "
+ factoryName);
}
return elem;
}
@SuppressWarnings("unchecked")
private static Element elementFor(Pointer ptr, String factoryName) {
Class<? extends Element> cls = ElementFactory.typeMap.get(factoryName);
if (cls == null) {
cls = (Class<Element>)GstTypes.classFor(Element.getType(ptr));
if (cls == null) cls = Element.class;
ElementFactory.typeMap.put(factoryName, cls);
}
return NativeObject.objectFor(ptr, cls, false);
}
/**
* Creates a new instance of ElementFactory
* @param init internal initialization data.
*/
public ElementFactory(Initializer init) {
super(init);
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "<init>", new Object[] { init });
}
}
/**
* Creates a new element from the factory.
*
* @param name the name to assign to the created Element
* @return A new {@link Element}
*/
public Element create(String name) {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "create", name);
}
Pointer elem = GSTELEMENTFACTORY_API.ptr_gst_element_factory_create(this, name);
logger.log(DEBUG, "gst_element_factory_create returned: " + elem);
if (elem == null) {
throw new IllegalArgumentException("Cannot create GstElement");
}
return elementFor(elem, getName());
}
/**
* Returns the name of the person who wrote the factory.
*
* @return The name of the author
*/
public String getAuthor() {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "getAuthor");
}
return GSTELEMENTFACTORY_API.gst_element_factory_get_metadata(this, "author");
}
/**
* Returns a description of the factory.
*
* @return A brief description of the factory.
*/
public String getDescription() {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "getDescription");
}
return GSTELEMENTFACTORY_API.gst_element_factory_get_metadata(this, "description");
}
/**
* Returns the long, English name for the factory.
*
* @return The long, English name for the factory.
*/
public String getLongName() {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "getLongName");
}
return GSTELEMENTFACTORY_API.gst_element_factory_get_metadata(this, "long-name");
}
/**
* Returns a string describing the type of factory.
* This is an unordered list separated with slashes ('/').
*
* @return The description of the type of factory.
*/
public String getKlass() {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "getKlass");
}
return GSTELEMENTFACTORY_API.gst_element_factory_get_metadata(this, "klass");
}
/**
* Gets the list of {@link StaticPadTemplate} for this factory.
*
* @return The list of {@link StaticPadTemplate}
*/
public List<StaticPadTemplate> getStaticPadTemplates() {
if (logger.isLoggable(Level.FINER)) {
logger.entering("ElementFactory", "getStaticPadTemplates");
}
GList glist = GSTELEMENTFACTORY_API.gst_element_factory_get_static_pad_templates(this);
logger.log(DEBUG, "GSTELEMENTFACTORY_API.gst_element_factory_get_static_pad_templates returned: " + glist);
List<StaticPadTemplate> templates = new ArrayList<StaticPadTemplate>();
GList next = glist;
while (next != null) {
if (next.data != null) {
GstStaticPadTemplate temp = new GstStaticPadTemplate(next.data);
templates.add(new StaticPadTemplate(temp.getName(), temp.getPadDirection(),
temp.getPadPresence(), GSTPADTEMPLATE_API.gst_static_pad_template_get_caps(temp)));
}
next = next.next();
}
return templates;
}
public enum ElementFactoryListType {
DECODER((long) 1 << 0),
ENCODER((long) 1 << 1),
SINK((long)1 << 2),
SRC((long)1 << 3),
MUXER((long)1 << 4),
DEMUXER((long)1 << 5),
PARSER((long)1 << 6),
PAYLOADER((long)1 << 7),
DEPAYLOADER((long)1 << 8),
FORMATTER((long)1 << 9),
MAX_ELEMENTS((long)1 << 48),
ANY((((long)1) << 49) - 1),
MEDIA_ANY(~((long) 0) << 48),
MEDIA_VIDEO((long)1 << 49),
MEDIA_AUDIO((long)1 << 50),
MEDIA_IMAGE((long)1 << 51),
MEDIA_SUBTITLE((long)1 << 52),
MEDIA_METADATA((long)1 << 53),
VIDEO_ENCODER(ENCODER.getValue() | MEDIA_VIDEO.getValue() | MEDIA_IMAGE.getValue()),
AUDIO_ENCODER(ENCODER.getValue() | MEDIA_AUDIO.getValue()),
AUDIOVIDEO_SINKS(SINK.getValue() | MEDIA_AUDIO.getValue() | MEDIA_VIDEO.getValue() | MEDIA_IMAGE.getValue()),
DECODABLE(ENCODER.getValue() | DEMUXER.getValue() | DEPAYLOADER.getValue() | PARSER.getValue());
private long value;
private ElementFactoryListType(long value) {
this.value = value;
}
public long getValue() {
return value;
}
}
}