org.gstreamer.elements.CustomSink Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gstreamer-java Show documentation
Show all versions of gstreamer-java Show documentation
Java binding for the Gstreamer framework
/*
* Copyright (c) 2009 Levente Farkas
* 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 .
*/
package org.gstreamer.elements;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.gstreamer.Buffer;
import org.gstreamer.Caps;
import org.gstreamer.Element;
import org.gstreamer.FlowReturn;
import org.gstreamer.PadDirection;
import org.gstreamer.PadTemplate;
import org.gstreamer.lowlevel.BaseAPI;
import org.gstreamer.lowlevel.GstPadTemplateAPI;
import org.gstreamer.lowlevel.GType;
import org.gstreamer.lowlevel.GObjectAPI.GBaseInitFunc;
import org.gstreamer.lowlevel.GObjectAPI.GClassInitFunc;
import org.gstreamer.lowlevel.GObjectAPI.GTypeInfo;
import com.sun.jna.Pointer;
import static org.gstreamer.lowlevel.GObjectAPI.GOBJECT_API;
/**
*
* @author wayne
*/
abstract public class CustomSink extends BaseSink {
private final static Logger logger = Logger.getLogger(CustomSink.class.getName());
@SuppressWarnings("unused")
private static class CustomSinkInfo {
GType type;
PadTemplate template;
Caps caps;
// Per-class callbacks used by gstreamer to initialize the subclass
GClassInitFunc classInit;
GBaseInitFunc baseInit;
// Per-instance callback functions
BaseAPI.Render render;
BaseAPI.Render preroll;
BaseAPI.BooleanFunc1 start;
BaseAPI.BooleanFunc1 stop;
BaseAPI.GetCaps getCaps;
BaseAPI.SetCaps setCaps;
}
private static final Map, CustomSinkInfo> customSubclasses = new ConcurrentHashMap, CustomSinkInfo>();
protected CustomSink(Class extends CustomSink> subClass, String name) {
super(initializer(GOBJECT_API.g_object_new(getSubclassType(subClass), "name", name)));
}
private static CustomSinkInfo getSubclassInfo(Class extends CustomSink> subClass) {
synchronized (subClass) {
CustomSinkInfo info = customSubclasses.get(subClass);
if (info == null) {
init(subClass);
info = customSubclasses.get(subClass);
}
return info;
}
}
private static GType getSubclassType(Class extends CustomSink> subClass) {
return getSubclassInfo(subClass).type;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
private @interface SinkCallback {
}
@SinkCallback
protected FlowReturn sinkRender(Buffer buffer) throws IOException {
logger.info(getClass().getSimpleName() + ".sinkRender");
return FlowReturn.WRONG_STATE;
}
@SinkCallback
protected FlowReturn sinkPreRoll(Buffer buffer) throws IOException {
logger.info(getClass().getSimpleName() + ".sinkPreRoll");
return FlowReturn.WRONG_STATE;
}
@SinkCallback
protected boolean sinkStart() {
logger.info(getClass().getSimpleName() + ".sinkStart");
return false;
}
@SinkCallback
protected boolean sinkStop() {
logger.info(getClass().getSimpleName() + ".sinkStop");
return false;
}
@SinkCallback
protected Caps sinkGetCaps() {
logger.info(getClass().getSimpleName() + ".sinkGetCaps");
return null;
}
@SinkCallback
protected boolean sinkSetCaps(Caps caps) {
logger.info(getClass().getSimpleName() + ".sinkSetCaps");
return false;
}
private static class BooleanFunc1 implements BaseAPI.BooleanFunc1 {
private Method method;
public BooleanFunc1(String methodName) {
try {
method = CustomSink.class.getDeclaredMethod(methodName, new Class[0]);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public boolean callback(Element element) {
try {
return ((Boolean) method.invoke(element)).booleanValue();
} catch (Throwable ex) {
return false;
}
}
}
private static final BooleanFunc1 startCallback = new BooleanFunc1("sinkStart");
private static final BooleanFunc1 stopCallback = new BooleanFunc1("sinkStop");
private static final BaseAPI.Render renderCallback = new BaseAPI.Render() {
public FlowReturn callback(BaseSink sink, Buffer buffer) {
try {
return ((CustomSink) sink).sinkRender(buffer);
} catch (Throwable ex) {
ex.printStackTrace();
return FlowReturn.ERROR;
}
}
};
private static final BaseAPI.Render prerollCallback = new BaseAPI.Render() {
public FlowReturn callback(BaseSink sink, Buffer buffer) {
try {
return ((CustomSink) sink).sinkPreRoll(buffer);
} catch (Throwable ex) {
return FlowReturn.ERROR;
}
}
};
private static final BaseAPI.GetCaps getCapsCallback = new BaseAPI.GetCaps() {
public Caps callback(Element element) {
try {
return ((CustomSink) element).sinkGetCaps();
} catch (Throwable ex) {
return null;
}
}
};
private static final BaseAPI.SetCaps setCapsCallback = new BaseAPI.SetCaps() {
public boolean callback(Element element, Caps caps) {
try {
return ((CustomSink) element).sinkSetCaps(caps);
} catch (Throwable ex) {
return false;
}
}
};
private static void init(Class extends CustomSink> sinkClass) {
final CustomSinkInfo info = new CustomSinkInfo();
customSubclasses.put(sinkClass, info);
//
// Trawl through all the methods in the subclass, looking for ones that
// over-ride the ones in CustomSink
//
for (Method m : CustomSink.class.getDeclaredMethods()) {
SinkCallback cb = m.getAnnotation(SinkCallback.class);
if (cb == null) {
continue;
}
try {
Method sinkMethod = sinkClass.getDeclaredMethod(m.getName(), m.getParameterTypes());
if (sinkMethod.equals(m)) {
// Skip it if it is the same as the method in CustomSink
continue;
}
String name = m.getName().toLowerCase().substring("sink".length());
if (name.equals("render")) {
info.render = renderCallback;
} else if (name.equals("preroll")) {
info.preroll = prerollCallback;
} else if (name.equals("start")) {
info.start = startCallback;
} else if (name.equals("stop")) {
info.stop = stopCallback;
} else if (name.equals("getcaps")) {
info.getCaps = getCapsCallback;
} else if (name.equals("setcaps")) {
info.setCaps = setCapsCallback;
}
} catch (NoSuchMethodException ex) {
// } catch (NoSuchFieldException ex) {
// } catch (IllegalAccessException ex) {
}
}
info.classInit = new GClassInitFunc() {
public void callback(Pointer g_class, Pointer class_data) {
BaseAPI.GstBaseSinkClass base = new BaseAPI.GstBaseSinkClass(g_class);
base.render = info.render;
base.preroll = info.preroll;
base.start = info.start;
base.stop = info.stop;
base.write();
}
};
info.baseInit = new GBaseInitFunc() {
public void callback(Pointer g_class) {
info.caps = Caps.anyCaps();
info.template = new PadTemplate("sink", PadDirection.SINK, info.caps);
GstPadTemplateAPI.GSTPADTEMPLATE_API.gst_element_class_add_pad_template(g_class, info.template);
}
};
//
// gstreamer boilerplate to hook the plugin in
//
GTypeInfo ginfo = new GTypeInfo();
ginfo.class_init = info.classInit;
ginfo.base_init = info.baseInit;
ginfo.instance_init = null;
ginfo.class_size = (short)new BaseAPI.GstBaseSinkClass().size();
ginfo.instance_size = (short)new BaseAPI.GstBaseSinkStruct().size();
info.type = GOBJECT_API.g_type_register_static(BaseAPI.BASE_API.gst_base_sink_get_type(),
sinkClass.getSimpleName(), ginfo, 0);
}
}