From dbed63161ddb977e2ecbd4eb68195212c73b8d3f Mon Sep 17 00:00:00 2001 From: Bartosz Firyn Date: Mon, 6 May 2013 21:02:23 +0200 Subject: [PATCH] GStreamer driver for Webcam-Capture, closes #57 --- .../webcam-capture-driver-gstreamer/pom.xml | 7 - .../webcam/ds/gstreamer/GStreamerDevice.java | 193 ++++++++++++++++++ .../webcam/ds/gstreamer/GStreamerDriver.java | 53 +++-- .../java/MjpegLignanoBeachExample.java | 1 - 4 files changed, 226 insertions(+), 28 deletions(-) create mode 100644 webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java diff --git a/webcam-capture-drivers/webcam-capture-driver-gstreamer/pom.xml b/webcam-capture-drivers/webcam-capture-driver-gstreamer/pom.xml index 2ea4e7c5..0457471a 100644 --- a/webcam-capture-drivers/webcam-capture-driver-gstreamer/pom.xml +++ b/webcam-capture-drivers/webcam-capture-driver-gstreamer/pom.xml @@ -33,13 +33,6 @@ org.apache.maven.plugins maven-assembly-plugin - - org.apache.maven.plugins - maven-deploy-plugin - - true - - diff --git a/webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java b/webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java new file mode 100644 index 00000000..ae600daf --- /dev/null +++ b/webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java @@ -0,0 +1,193 @@ +package com.github.sarxos.webcam.ds.gstreamer; + +import java.awt.Dimension; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.gstreamer.Caps; +import org.gstreamer.Element; +import org.gstreamer.ElementFactory; +import org.gstreamer.Pad; +import org.gstreamer.Pipeline; +import org.gstreamer.State; +import org.gstreamer.Structure; +import org.gstreamer.elements.RGBDataSink; + +import com.github.sarxos.webcam.WebcamDevice; +import com.github.sarxos.webcam.WebcamResolution; + + +public class GStreamerDevice implements WebcamDevice, RGBDataSink.Listener { + + /** + * Limit the lateness of frames to no more than 20ms (half a frame at 25fps) + */ + private static final long LATENESS = 20; // ms + + private static final String FORMAT = "video/x-raw-yuv"; + + private final String name; + private final Dimension[] resolutions; + + private Pipeline pipe = null; + private Element source = null; + private Element filter = null; + private RGBDataSink sink = null; + private BufferedImage image = null; + private Caps caps = null; + + private AtomicBoolean open = new AtomicBoolean(false); + private AtomicBoolean disposed = new AtomicBoolean(false); + private Dimension resolution = WebcamResolution.VGA.getSize(); + + protected GStreamerDevice(String name) { + + this.name = name; + + pipe = new Pipeline(name); + + sink = new RGBDataSink(name, this); + sink.setPassDirectBuffer(true); + sink.getSinkElement().setMaximumLateness(LATENESS, TimeUnit.MILLISECONDS); + sink.getSinkElement().setQOSEnabled(true); + + source = ElementFactory.make("dshowvideosrc", "source"); + source.set("device-name", name); + + filter = ElementFactory.make("capsfilter", "filter"); + + resolutions = parseResolutions(source.getPads().get(0)); + } + + private static final Dimension[] parseResolutions(Pad pad) { + + List dimensions = new ArrayList(); + + Caps caps = pad.getCaps(); + + Structure structure = null; + String format = null; + + int n = caps.size(); + int i = 0; + + int w = -1; + int h = -1; + + do { + + structure = caps.getStructure(i++); + format = structure.getName(); + + if (format.equals(FORMAT)) { + w = structure.getRange("width").getMinInt(); + h = structure.getRange("height").getMinInt(); + dimensions.add(new Dimension(w, h)); + } + + } while (i < n); + + return dimensions.toArray(new Dimension[dimensions.size()]); + } + + @Override + public String getName() { + return name; + } + + @Override + public Dimension[] getResolutions() { + return resolutions; + } + + @Override + public Dimension getResolution() { + return resolution; + } + + @Override + public void setResolution(Dimension size) { + this.resolution = size; + } + + @Override + public BufferedImage getImage() { + return image; + } + + @Override + public void open() { + + if (!open.compareAndSet(false, true)) { + return; + } + + Dimension size = getResolution(); + + image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB); + image.setAccelerationPriority(0); + image.flush(); + + if (caps != null) { + caps.dispose(); + } else { + caps = Caps.fromString(String.format("%s,width=%d,height=%d", FORMAT, size.width, size.height)); + } + + filter.setCaps(caps); + + pipe.addMany(source, filter, sink); + Element.linkMany(source, filter, sink); + pipe.setState(State.PLAYING); + } + + @Override + public void close() { + + if (!open.compareAndSet(true, false)) { + return; + } + + pipe.setState(State.NULL); + Element.unlinkMany(source, filter, sink); + pipe.removeMany(source, filter, sink); + } + + @Override + public void dispose() { + + if (!disposed.compareAndSet(false, true)) { + return; + } + + close(); + + filter.dispose(); + source.dispose(); + sink.dispose(); + pipe.dispose(); + caps.dispose(); + } + + @Override + public boolean isOpen() { + return open.get(); + } + + @Override + public void rgbFrame(boolean preroll, int width, int height, IntBuffer rgb) { + + BufferedImage tmp = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + tmp.setAccelerationPriority(0); + tmp.flush(); + + rgb.get(((DataBufferInt) tmp.getRaster().getDataBuffer()).getData(), 0, width * height); + + image = tmp; + } +} diff --git a/webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java b/webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java index e9f72753..4b3f4cf7 100644 --- a/webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java +++ b/webcam-capture-drivers/webcam-capture-driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java @@ -1,18 +1,21 @@ package com.github.sarxos.webcam.ds.gstreamer; +import java.util.ArrayList; import java.util.List; +import javax.swing.JFrame; + import org.gstreamer.Element; import org.gstreamer.ElementFactory; import org.gstreamer.Gst; -import org.gstreamer.Pipeline; -import org.gstreamer.State; import org.gstreamer.interfaces.PropertyProbe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.github.sarxos.webcam.Webcam; import com.github.sarxos.webcam.WebcamDevice; import com.github.sarxos.webcam.WebcamDriver; +import com.github.sarxos.webcam.WebcamPanel; import com.sun.jna.NativeLibrary; @@ -20,6 +23,10 @@ public class GStreamerDriver implements WebcamDriver { private static final Logger LOG = LoggerFactory.getLogger(GStreamerDriver.class); + static { + init(); + } + private static final class GStreamerShutdownHook extends Thread { public GStreamerShutdownHook() { @@ -28,40 +35,33 @@ public GStreamerShutdownHook() { @Override public void run() { + LOG.debug("GStreamer deinitialization"); Gst.deinit(); } } - static { + private static final void init() { + LOG.debug("GStreamer initialization"); NativeLibrary.addSearchPath("gstreamer-0.10", "C:\\Program Files\\OSSBuild\\GStreamer\\v0.10.6\\bin"); Gst.init(GStreamerDriver.class.getSimpleName(), new String[0]); Runtime.getRuntime().addShutdownHook(new GStreamerShutdownHook()); } - private static final Pipeline pipe = new Pipeline(GStreamerDriver.class.getSimpleName()); - @Override public List getDevices() { - Element dshowsrc = ElementFactory.make("dshowvideosrc", "source"); - dshowsrc.setState(State.READY); + List devices = new ArrayList(); + Element dshowsrc = ElementFactory.make("dshowvideosrc", "source"); PropertyProbe probe = PropertyProbe.wrap(dshowsrc); - for (Object device : probe.getValues("device-name")) { - System.out.println(device); - } - dshowsrc.setState(State.NULL); + for (Object name : probe.getValues("device-name")) { + devices.add(new GStreamerDevice(name.toString())); + } - // final Element videosrc = ElementFactory.make("videotestsrc", - // "source"); - // final Element videofilter = ElementFactory.make("capsfilter", - // "filter"); - // videofilter.setCaps(Caps.fromString("video/x-raw-yuv, width=720, height=576" - // + ", bpp=32, depth=32, framerate=25/1")); + dshowsrc.dispose(); - // TODO Auto-generated method stub - return null; + return devices; } @Override @@ -70,6 +70,19 @@ public boolean isThreadSafe() { } public static void main(String[] args) { - new GStreamerDriver().getDevices(); + // WebcamDriver driver = new GStreamerDriver(); + // for (WebcamDevice device : driver.getDevices()) { + // System.out.println(device.getName()); + // for (Dimension d : device.getResolutions()) { + // System.out.println(d); + // } + // } + + Webcam.setDriver(new GStreamerDriver()); + JFrame frame = new JFrame(); + frame.add(new WebcamPanel(Webcam.getWebcams().get(1))); + frame.pack(); + frame.setVisible(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/MjpegLignanoBeachExample.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/MjpegLignanoBeachExample.java index 3246a4e2..477c5757 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/MjpegLignanoBeachExample.java +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/MjpegLignanoBeachExample.java @@ -4,7 +4,6 @@ import com.github.sarxos.webcam.Webcam; import com.github.sarxos.webcam.WebcamPanel; -import com.github.sarxos.webcam.ds.ipcam.IpCamDevice; import com.github.sarxos.webcam.ds.ipcam.IpCamDeviceRegistry; import com.github.sarxos.webcam.ds.ipcam.IpCamDriver; import com.github.sarxos.webcam.ds.ipcam.IpCamMode;