From 84a7352ca42b05b255271aeab54bb64212507e0b Mon Sep 17 00:00:00 2001 From: Bartosz Firyn Date: Tue, 15 Jul 2014 19:01:13 +0200 Subject: [PATCH] Add possibility to use vlcj-driver on Windows, refs #233 --- webcam-capture-drivers/driver-vlcj/README.md | 5 +- .../example/java/WebcamPanelForWindows.java | 42 ++++++ .../sarxos/webcam/ds/vlcj/VlcjDevice.java | 126 ++++++++---------- .../sarxos/webcam/ds/vlcj/VlcjDriver.java | 97 +++++++++++--- 4 files changed, 184 insertions(+), 86 deletions(-) create mode 100644 webcam-capture-drivers/driver-vlcj/src/example/java/WebcamPanelForWindows.java diff --git a/webcam-capture-drivers/driver-vlcj/README.md b/webcam-capture-drivers/driver-vlcj/README.md index b6ecd87f..d4712992 100644 --- a/webcam-capture-drivers/driver-vlcj/README.md +++ b/webcam-capture-drivers/driver-vlcj/README.md @@ -4,14 +4,15 @@ This is capture driver which uses [vlcj](http://www.capricasoftware.co.uk/projec library from [Caprica Software Limited](http://www.capricasoftware.co.uk/) to gain access to the camera device. -**NOTE!** This capture driver **does not** work on Windows. - Because vlcj saves every frame to the persistent storage (temporary directory on your hard drive) before it is returned by the API method call, the image capture rate is pretty small, indicated by tests to be around ~12 FPS, but it can pe possibly higher or lower depending on the hardware used (e.g. different on hard drive, SSD and flash memory). +**NOTE!** On Windows one needs to provide list of webcam devices manually because +```vlclib``` does not implement video devices discovery on this platform. + The vlcj library is distributed according to the terms of the [GPL](http://www.gnu.org/licenses/gpl.html) license. ## Maven diff --git a/webcam-capture-drivers/driver-vlcj/src/example/java/WebcamPanelForWindows.java b/webcam-capture-drivers/driver-vlcj/src/example/java/WebcamPanelForWindows.java new file mode 100644 index 00000000..e7dac7e2 --- /dev/null +++ b/webcam-capture-drivers/driver-vlcj/src/example/java/WebcamPanelForWindows.java @@ -0,0 +1,42 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.swing.JFrame; + +import uk.co.caprica.vlcj.medialist.MediaListItem; + +import com.github.sarxos.webcam.Webcam; +import com.github.sarxos.webcam.WebcamPanel; +import com.github.sarxos.webcam.ds.vlcj.VlcjDriver; + + +public class WebcamPanelForWindows { + + private static List EMPTY = new ArrayList(); + + /* NOTE! + * + * The vlclib does not implement video device discovery on Windows. + * Therefore, to make it working on this operating system one needs + * to manually provide the list of media list items from vlcj. This + * is not necessary on Linux and Mac. + */ + + private static final MediaListItem dev0 = new MediaListItem("HP HD Webcam [Fixed]", "dshow://", EMPTY); + private static final MediaListItem dev1 = new MediaListItem("USB2.0 Camera", "dshow://", EMPTY); + private static final MediaListItem dev2 = new MediaListItem("Logitech Webcam", "dshow://", EMPTY); + + static { + Webcam.setDriver(new VlcjDriver(Arrays.asList(dev0, dev1, dev2))); + } + + public static void main(String[] args) { + JFrame window = new JFrame("Webcam Panel"); + window.add(new WebcamPanel(Webcam.getDefault())); + window.setResizable(false); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.pack(); + window.setVisible(true); + } +} diff --git a/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDevice.java b/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDevice.java index e4264604..60045986 100644 --- a/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDevice.java +++ b/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDevice.java @@ -96,12 +96,8 @@ protected VlcjDevice(MediaListItem item) { List subs = item.subItems(); - if (subs.isEmpty()) { - throw new RuntimeException("Implementation does not support media list items which are empty!"); - } - this.item = item; - this.sub = subs.get(0); + this.sub = subs.isEmpty() ? item : subs.get(0); } public String getCaptureDevice() { @@ -163,7 +159,7 @@ public BufferedImage getImage() { if (!open) { throw new WebcamException("Cannot get image, webcam device is not open"); } - return player.getSnapshot(); + return player.getSnapshot(size.width, size.height); } @Override @@ -180,75 +176,63 @@ public synchronized void open() { LOG.info("Opening webcam device"); - try { - - factory = getFactory(); - player = factory.newHeadlessMediaPlayer(); - - // for nix systems this should be changed dshow -> ... !! - - String[] options = null; - - switch (OsUtils.getOS()) { - case WIN: - options = new String[] { - ":dshow-vdev=" + getName(), - ":dshow-size=" + size.width + "x" + size.height, - ":dshow-adev=none", // no audio device - }; - break; - case NIX: - options = new String[] { - ":v4l-vdev=" + getVDevice(), - ":v4l-width=" + size.width, - ":v4l-height=" + size.height, - ":v4l-fps=30", - ":v4l-quality=20", - ":v4l-adev=none", // no audio device - }; - break; - case OSX: - options = new String[] { - ":qtcapture-vdev=" + getVDevice(), - ":qtcapture-width=" + size.width, - ":qtcapture-height=" + size.height, - ":qtcapture-adev=none", // no audio device - }; - break; - } - - player.startMedia(getMRL(), options); + factory = getFactory(); + player = factory.newHeadlessMediaPlayer(); - // wait for images + String[] options = null; - int max = 0; - do { - - BufferedImage im = player.getSnapshot(size.width, size.height); - if (im != null && im.getWidth() > 0) { - open = true; - LOG.info("Webcam device is now open: " + getName()); - return; - } + switch (OsUtils.getOS()) { + case WIN: + LOG.debug("Open VLC device {}", getName()); + options = new String[] { + ":dshow-vdev=" + getName(), + ":dshow-size=" + size.width + "x" + size.height, + ":dshow-adev=none", // no audio device + }; + break; + case NIX: + LOG.debug("Open VLC device {}", getVDevice()); + options = new String[] { + ":v4l-vdev=" + getVDevice(), + ":v4l-width=" + size.width, + ":v4l-height=" + size.height, + ":v4l-fps=30", + ":v4l-quality=20", + ":v4l-adev=none", // no audio device + }; + break; + case OSX: + LOG.debug("Open VLC device {}", getVDevice()); + options = new String[] { + ":qtcapture-vdev=" + getVDevice(), + ":qtcapture-width=" + size.width, + ":qtcapture-height=" + size.height, + ":qtcapture-adev=none", // no audio device + }; + break; + } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - return; - } + player.startMedia(getMRL(), options); - } while (max++ < 10); + // wait for images - } finally { + int max = 0; + do { - if (player != null) { - player.release(); + BufferedImage im = player.getSnapshot(size.width, size.height); + if (im != null && im.getWidth() > 0) { + open = true; + LOG.info("Webcam device is now open: " + getName()); + return; } - if (factory != null) { - factory.release(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return; } - } + + } while (max++ < 10); open = false; } @@ -262,8 +246,14 @@ public synchronized void close() { LOG.info("Closing"); - player.release(); - factory.release(); + if (player != null) { + LOG.debug("Releasing player"); + player.release(); + } + if (factory != null) { + LOG.debug("Releasing player"); + factory.release(); + } open = false; } diff --git a/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDriver.java b/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDriver.java index fc737087..55b2667d 100644 --- a/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDriver.java +++ b/webcam-capture-drivers/driver-vlcj/src/main/java/com/github/sarxos/webcam/ds/vlcj/VlcjDriver.java @@ -1,15 +1,19 @@ package com.github.sarxos.webcam.ds.vlcj; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import uk.co.caprica.vlcj.binding.LibVlc; +import uk.co.caprica.vlcj.discovery.NativeDiscovery; import uk.co.caprica.vlcj.medialist.MediaList; import uk.co.caprica.vlcj.medialist.MediaListItem; import uk.co.caprica.vlcj.player.MediaPlayerFactory; import uk.co.caprica.vlcj.player.discoverer.MediaDiscoverer; import uk.co.caprica.vlcj.runtime.RuntimeUtil; +import uk.co.caprica.vlcj.runtime.windows.WindowsRuntimeUtil; import com.github.sarxos.webcam.WebcamDevice; import com.github.sarxos.webcam.WebcamDiscoverySupport; @@ -27,6 +31,12 @@ */ public class VlcjDriver implements WebcamDriver, WebcamDiscoverySupport { + static { + if ("true".equals(System.getProperty("webcam.debug"))) { + System.setProperty("vlcj.log", "DEBUG"); + } + } + /** * Default webcam discovery scan interval in milliseconds. */ @@ -37,15 +47,27 @@ public class VlcjDriver implements WebcamDriver, WebcamDiscoverySupport { */ private static final AtomicBoolean initialized = new AtomicBoolean(); + /** + * Native library discoverer. + */ + private static NativeDiscovery nativeDiscovery; + /** * The scan interval. */ private long scanInterval = -1; + /** + * Preconfigured media list items. + */ + private final List mediaListItems; + public VlcjDriver() { - if (OsUtils.getOS() == OsUtils.WIN) { - System.err.println(String.format("WARNING: %s does not support Windows platform", getClass().getSimpleName())); - } + this(null); + } + + public VlcjDriver(List mediaListItems) { + this.mediaListItems = mediaListItems; initialize(); } @@ -64,27 +86,63 @@ protected static void initialize() { */ protected static void initialize(boolean load) { if (load && initialized.compareAndSet(false, true)) { - Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class); + boolean nativeFound = getNativeDiscovery().discover(); + if (!nativeFound) { + throw new IllegalStateException("The libvlc native library has not been found"); + } + //Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class); } } - @Override - public final List getDevices() { - MediaPlayerFactory mediaPlayerFactory = createMediaPlayerFactory(); - MediaDiscoverer videoMediaDiscoverer = mediaPlayerFactory.newVideoMediaDiscoverer(); - MediaList videoDeviceList = videoMediaDiscoverer.getMediaList(); + /** + * Method to get devices list on Windows. + * + * @return Webcam devices list + */ + private List getDevicesPreconf() { + + List devices = new ArrayList(); - List videoDevices = videoDeviceList.items(); - for (MediaListItem item : videoDevices) { - devices.add(mediaListItemToDevice(item)); + MediaListItem mli = new MediaListItem("HP HD Webcam [Fixed]", "dshow://", new ArrayList()); + + devices.add(mediaListItemToDevice(mli)); + + return devices; + } + + @Override + public List getDevices() { + + if (OsUtils.getOS() == OsUtils.WIN) { + System.err.println("WARNING: VLCj does not support webcam devices discovery on Windows platform"); } - videoDeviceList.release(); - videoMediaDiscoverer.release(); - mediaPlayerFactory.release(); + List devices = new ArrayList(); + + if (mediaListItems != null) { + + for (MediaListItem item : mediaListItems) { + devices.add(mediaListItemToDevice(item)); + } + + } else { + + MediaPlayerFactory mediaPlayerFactory = createMediaPlayerFactory(); + MediaDiscoverer videoMediaDiscoverer = mediaPlayerFactory.newVideoMediaDiscoverer(); + MediaList videoDeviceList = videoMediaDiscoverer.getMediaList(); + List videoDevices = videoDeviceList.items(); + + for (MediaListItem item : videoDevices) { + devices.add(mediaListItemToDevice(item)); + } + + videoDeviceList.release(); + videoMediaDiscoverer.release(); + mediaPlayerFactory.release(); + } return devices; } @@ -140,6 +198,13 @@ public void setScanInterval(long scanInterval) { @Override public boolean isScanPossible() { - return true; + return OsUtils.getOS() != OsUtils.WIN; + } + + protected static NativeDiscovery getNativeDiscovery() { + if (nativeDiscovery == null) { + nativeDiscovery = new NativeDiscovery(); + } + return nativeDiscovery; } }