Skip to content

Commit

Permalink
Add Linux support to GStreamer capture driver, refs #100
Browse files Browse the repository at this point in the history
  • Loading branch information
sarxos committed May 12, 2013
1 parent e407785 commit e4f0080
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

This is GStreamer driver for Webcam Capture project. It allows Webcam Capture to
handle pictures from build-in or USB-connected webcams. It has been designed to
work with Windows **only**. To make use of it user have to
[download](http://code.google.com/p/ossbuild/) and install GStreamer application.
work with Windows and Linux **only**. To make use of it user have to
[download](http://code.google.com/p/ossbuild/) and install GStreamer application
on Windows or use _apt-get_, _yum_ or other packages manager to install it on Linux.

Currently supported GStreamer version is 0.10.x, so make sure you are installing
the correct one! It is **not** compatible with GStreamer 1.0 and above!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
<artifactId>gstreamer-java</artifactId>
<version>1.5</version>
</dependency>
<!-- uncomment if you would like debug prints to be visible -->
<!--
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.9</version>
</dependency>
-->
<!-- end uncomment -->
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import java.awt.Dimension;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.ds.gstreamer.GStreamerDriver;


public class ListSupportedResolutions {

// uncomment if you would like debug prints to be visible, and don't
// forget to add logback JAR and XML file as well
static {
// WebcamLogConfigurator.configure("src/example/resources/logback.xml");
}

static {
Webcam.setDriver(new GStreamerDriver());
}

public static void main(String[] args) {

for (Webcam webcam : Webcam.getWebcams()) {
System.out.println("webcam --- " + webcam.getName());
for (Dimension d : webcam.getViewSizes()) {
System.out.println("supported resolution: " + d.width + "x" + d.height);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
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.bridj.Platform;
import org.gstreamer.Caps;
import org.gstreamer.Element;
import org.gstreamer.ElementFactory;
Expand Down Expand Up @@ -36,17 +38,21 @@ public class GStreamerDevice implements WebcamDevice, RGBDataSink.Listener, Webc
/**
* Video format to capture.
*/
private static final String FORMAT = "video/x-raw-yuv";
private static final String FORMAT_MIME = "video/x-raw-yuv";

/**
* All possible resolutions - populated while initialization phase.
*/
private Dimension[] resolutions = null;

/**
* Device name, immutable.
* Device name, immutable. Used only on Windows platform.
*/
private final String name;
/**
* Device name, immutable. Used only on Linux platform.
*/
private final File vfile;

/* gstreamer stuff */

Expand Down Expand Up @@ -79,6 +85,12 @@ public class GStreamerDevice implements WebcamDevice, RGBDataSink.Listener, Webc
*/
protected GStreamerDevice(String name) {
this.name = name;
this.vfile = null;
}

protected GStreamerDevice(File vfile) {
this.name = null;
this.vfile = vfile;
}

/**
Expand All @@ -94,8 +106,13 @@ private synchronized void init() {

pipe = new Pipeline(name);

source = ElementFactory.make("dshowvideosrc", "source");
source.set("device-name", name);
if (Platform.isWindows()) {
source = ElementFactory.make("dshowvideosrc", "source");
source.set("device-name", name);
} else if (Platform.isLinux()) {
source = ElementFactory.make("v4l2src", "source");
source.set("device", vfile.getAbsolutePath());
}

sink = new RGBDataSink(name, this);
sink.setPassDirectBuffer(true);
Expand All @@ -104,7 +121,19 @@ private synchronized void init() {

filter = ElementFactory.make("capsfilter", "filter");

if (Platform.isLinux()) {
pipe.addMany(source, filter, sink);
Element.linkMany(source, filter, sink);
pipe.setState(State.READY);
}

resolutions = parseResolutions(source.getPads().get(0));

if (Platform.isLinux()) {
pipe.setState(State.NULL);
Element.unlinkMany(source, filter, sink);
pipe.removeMany(source, filter, sink);
}
}

/**
Expand All @@ -120,7 +149,7 @@ private static final Dimension[] parseResolutions(Pad pad) {
Caps caps = pad.getCaps();

Structure structure = null;
String format = null;
String mime = null;

int n = caps.size();
int i = 0;
Expand All @@ -134,12 +163,20 @@ private static final Dimension[] parseResolutions(Pad pad) {

LOG.debug("Found format structure {}", structure);

format = structure.getName();

if (format.equals(FORMAT)) {
w = structure.getRange("width").getMinInt();
h = structure.getRange("height").getMinInt();
dimensions.add(new Dimension(w, h));
mime = structure.getName();

if (mime.equals(FORMAT_MIME)) {
if (Platform.isWindows()) {
w = structure.getRange("width").getMinInt();
h = structure.getRange("height").getMinInt();
dimensions.add(new Dimension(w, h));
} else if (Platform.isLinux()) {
if ("YUY2".equals(structure.getFourccString("format"))) {
w = structure.getInteger("width");
h = structure.getInteger("height");
dimensions.add(new Dimension(w, h));
}
}
}

} while (i < n);
Expand All @@ -149,7 +186,13 @@ private static final Dimension[] parseResolutions(Pad pad) {

@Override
public String getName() {
return name;
if (Platform.isWindows()) {
return name;
} else if (Platform.isLinux()) {
return vfile.getAbsolutePath();
} else {
throw new RuntimeException("Platform not supported by GStreamer capture driver");
}
}

@Override
Expand Down Expand Up @@ -196,7 +239,7 @@ public void open() {
caps.dispose();
}

caps = Caps.fromString(String.format("%s,width=%d,height=%d", FORMAT, size.width, size.height));
caps = Caps.fromString(String.format("%s,width=%d,height=%d", FORMAT_MIME, size.width, size.height));

filter.setCaps(caps);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.sarxos.webcam.ds.gstreamer;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
Expand All @@ -14,6 +15,7 @@
import com.github.sarxos.webcam.WebcamDevice;
import com.github.sarxos.webcam.WebcamDriver;
import com.github.sarxos.webcam.WebcamException;
import com.github.sarxos.webcam.ds.gstreamer.impl.VideoDeviceFilenameFilter;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Platform;

Expand Down Expand Up @@ -45,30 +47,41 @@ public GStreamerDriver() {

private static final void init() {

if (!Platform.isWindows()) {
throw new WebcamException(String.format("%s has been designed to work only on Windows platforms", GStreamerDriver.class.getSimpleName()));
}
// if (!Platform.isWindows()) {
// throw new
// WebcamException(String.format("%s has been designed to work only on Windows platforms",
// GStreamerDriver.class.getSimpleName()));
// }

LOG.debug("GStreamer initialization");

String gpath = null;

for (String path : System.getenv("PATH").split(";")) {
LOG.trace("Search %PATH% for gstreamer bin {}", path);
if (path.indexOf("GStreamer\\v0.10.") != -1) {
gpath = path;
break;
if (Platform.isWindows()) {
for (String path : System.getenv("PATH").split(";")) {
LOG.trace("Search %PATH% for gstreamer bin {}", path);
if (path.indexOf("GStreamer\\v0.10.") != -1) {
gpath = path;
break;
}
}
}

if (gpath != null) {
LOG.debug("Add bin directory to JNA search paths {}", gpath);
NativeLibrary.addSearchPath("gstreamer-0.10", gpath);
} else {
throw new WebcamException("GStreamer has not been installed or not in %PATH%");
if (gpath != null) {
LOG.debug("Add bin directory to JNA search paths {}", gpath);
NativeLibrary.addSearchPath("gstreamer-0.10", gpath);
} else {
throw new WebcamException("GStreamer has not been installed or not in %PATH%");
}
}

Gst.init(GStreamerDriver.class.getSimpleName(), new String[0]);
//@formatter:off
String[] args = new String[] {
//"--gst-plugin-path", new File(".").getAbsolutePath(),
};
//@formatter:on

Gst.init(GStreamerDriver.class.getSimpleName(), args);

Runtime.getRuntime().addShutdownHook(new GStreamerShutdownHook());
}

Expand All @@ -77,11 +90,28 @@ public List<WebcamDevice> getDevices() {

List<WebcamDevice> devices = new ArrayList<WebcamDevice>();

Element dshowsrc = ElementFactory.make("dshowvideosrc", "source");
String srcname = null;
if (Platform.isWindows()) {
srcname = "dshowvideosrc";
} else {
srcname = "v4l2src";
}

Element dshowsrc = ElementFactory.make(srcname, "source");

try {
PropertyProbe probe = PropertyProbe.wrap(dshowsrc);
for (Object name : probe.getValues("device-name")) {
devices.add(new GStreamerDevice(name.toString()));
if (Platform.isWindows()) {
PropertyProbe probe = PropertyProbe.wrap(dshowsrc);
for (Object name : probe.getValues("device-name")) {
devices.add(new GStreamerDevice(name.toString()));
}
} else if (Platform.isLinux()) {
VideoDeviceFilenameFilter vfilter = new VideoDeviceFilenameFilter();
for (File vfile : vfilter.getVideoFiles()) {
devices.add(new GStreamerDevice(vfile));
}
} else {
throw new RuntimeException("Platform unsupported by GStreamer capture driver");
}
} finally {
if (dshowsrc != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.github.sarxos.webcam.ds.gstreamer.impl;

import java.io.File;
import java.io.FilenameFilter;


public class VideoDeviceFilenameFilter implements FilenameFilter {

private static final File DEV = new File("/dev");

@Override
public boolean accept(File dir, String name) {
return dir.getName().equals("dev") && name.startsWith("video") && Character.isDigit(name.charAt(5));
}

public File[] getVideoFiles() {

String[] names = DEV.list(this);
File[] files = new File[names.length];

for (int i = 0; i < names.length; i++) {
files[i] = new File(DEV, names[i]);
}

return files;
}
}

0 comments on commit e4f0080

Please sign in to comment.