diff --git a/webcam-capture-drivers/driver-gstreamer/pom.xml b/webcam-capture-drivers/driver-gstreamer/pom.xml index 64acc2c5..12780e9c 100644 --- a/webcam-capture-drivers/driver-gstreamer/pom.xml +++ b/webcam-capture-drivers/driver-gstreamer/pom.xml @@ -25,20 +25,14 @@ gstreamer-java 1.5 - - - - junit junit - 4.11 test diff --git a/webcam-capture-drivers/driver-gstreamer/src/example/java/WebcamPanelExample.java b/webcam-capture-drivers/driver-gstreamer/src/example/java/WebcamPanelExample.java new file mode 100644 index 00000000..d7838271 --- /dev/null +++ b/webcam-capture-drivers/driver-gstreamer/src/example/java/WebcamPanelExample.java @@ -0,0 +1,32 @@ +import javax.swing.JFrame; + +import com.github.sarxos.webcam.Webcam; +import com.github.sarxos.webcam.WebcamPanel; +import com.github.sarxos.webcam.WebcamResolution; +import com.github.sarxos.webcam.ds.gstreamer.GStreamerDriver; + + +public class WebcamPanelExample { + + static { + Webcam.setDriver(new GStreamerDriver()); + } + + public static void main(String[] args) { + + Webcam webcam = Webcam.getDefault(); + webcam.setViewSize(WebcamResolution.HD720.getSize()); + + WebcamPanel panel = new WebcamPanel(webcam); + panel.setDisplayDebugInfo(true); + panel.setFPSDisplayed(true); + panel.setFillArea(true); + + JFrame window = new JFrame("Test webcam panel"); + window.add(panel); + window.setResizable(true); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.pack(); + window.setVisible(true); + } +} diff --git a/webcam-capture-drivers/driver-gstreamer/src/example/resources/logback.xml b/webcam-capture-drivers/driver-gstreamer/src/example/resources/logback.xml index 2bb01a64..30ec27f8 100644 --- a/webcam-capture-drivers/driver-gstreamer/src/example/resources/logback.xml +++ b/webcam-capture-drivers/driver-gstreamer/src/example/resources/logback.xml @@ -5,6 +5,6 @@ - + diff --git a/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java b/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java index 9d0306e6..fa436c3d 100644 --- a/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java +++ b/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDevice.java @@ -6,7 +6,8 @@ import java.io.File; import java.nio.IntBuffer; import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -38,10 +39,21 @@ public class GStreamerDevice implements WebcamDevice, RGBDataSink.Listener, Webc */ private static final long LATENESS = 20; // ms + /** + * First formats are better. For example video/x-raw-rgb gives 30 FPS on + * HD720p where video/x-raw-yuv only 10 FPS on the same resolution. The goal + * is to use these "better" formats first, and then fallback to less + * efficient when not available. + */ + private static final String[] BEST_FORMATS = { + "video/x-raw-rgb", + "video/x-raw-yuv", + }; + /** * Video format to capture. */ - private static final String FORMAT_MIME = "video/x-raw-yuv"; + private String format; /** * All possible resolutions - populated while initialization phase. @@ -146,46 +158,79 @@ private synchronized void init() { * @param pad the pad to get resolutions from * @return Array of resolutions supported by device connected with pad */ - private static final Dimension[] parseResolutions(Pad pad) { - - List dimensions = new ArrayList(); + private Dimension[] parseResolutions(Pad pad) { Caps caps = pad.getCaps(); - Structure structure = null; + format = findBestFormat(caps); + + LOG.debug("Best format is {}", format); + + Dimension r = null; + Structure s = null; String mime = null; int n = caps.size(); int i = 0; - int w = -1; - int h = -1; + Map map = new HashMap(); do { - structure = caps.getStructure(i++); + s = caps.getStructure(i++); - LOG.debug("Found format structure {}", structure); + LOG.debug("Found format structure {}", s); - mime = structure.getName(); + mime = s.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)); - } + if (mime.equals(format)) { + if ((r = capStructToResolution(s)) != null) { + map.put(r.width + "x" + r.height, r); } } } while (i < n); - return dimensions.toArray(new Dimension[dimensions.size()]); + Dimension[] resolutions = new ArrayList(map.values()).toArray(new Dimension[map.size()]); + + if (LOG.isDebugEnabled()) { + for (Dimension d : resolutions) { + LOG.debug("Resolution detected {}", d); + } + } + + return resolutions; + } + + private static String findBestFormat(Caps caps) { + for (String f : BEST_FORMATS) { + for (int i = 0, n = caps.size(); i < n; i++) { + if (f.equals(caps.getStructure(i).getName())) { + return f; + } + } + } + return null; + } + + private static Dimension capStructToResolution(Structure structure) { + + int w = -1; + int h = -1; + + if (Platform.isWindows()) { + w = structure.getRange("width").getMinInt(); + h = structure.getRange("height").getMinInt(); + } else if (Platform.isLinux()) { + w = structure.getInteger("width"); + h = structure.getInteger("height"); + } + + if (w > 0 && h > 0) { + return new Dimension(w, h); + } else { + return null; + } } @Override @@ -243,7 +288,7 @@ public void open() { caps.dispose(); } - caps = Caps.fromString(String.format("%s,width=%d,height=%d", FORMAT_MIME, size.width, size.height)); + caps = Caps.fromString(String.format("%s,width=%d,height=%d", format, size.width, size.height)); filter.setCaps(caps); @@ -317,9 +362,8 @@ 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); + tmp.flush(); image = tmp; diff --git a/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java b/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java index 37559174..ec7e2137 100644 --- a/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java +++ b/webcam-capture-drivers/driver-gstreamer/src/main/java/com/github/sarxos/webcam/ds/gstreamer/GStreamerDriver.java @@ -100,15 +100,17 @@ public List getDevices() { String srcname = null; if (Platform.isWindows()) { srcname = "dshowvideosrc"; - } else { + } else if (Platform.isLinux()) { srcname = "v4l2src"; + } else if (Platform.isMac()) { + srcname = "qtkitvideosrc"; } - Element dshowsrc = ElementFactory.make(srcname, "source"); + Element src = ElementFactory.make(srcname, "source"); try { if (Platform.isWindows()) { - PropertyProbe probe = PropertyProbe.wrap(dshowsrc); + PropertyProbe probe = PropertyProbe.wrap(src); for (Object name : probe.getValues("device-name")) { devices.add(new GStreamerDevice(name.toString())); } @@ -120,8 +122,8 @@ public List getDevices() { throw new RuntimeException("Platform unsupported by GStreamer capture driver"); } } finally { - if (dshowsrc != null) { - dshowsrc.dispose(); + if (src != null) { + src.dispose(); } }