Skip to content

Commit

Permalink
Add possibility to use vlcj-driver on Windows, refs #233
Browse files Browse the repository at this point in the history
  • Loading branch information
sarxos committed Jul 15, 2014
1 parent 885bba4 commit 84a7352
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 86 deletions.
5 changes: 3 additions & 2 deletions webcam-capture-drivers/driver-vlcj/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<MediaListItem> EMPTY = new ArrayList<MediaListItem>();

/* 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,8 @@ protected VlcjDevice(MediaListItem item) {

List<MediaListItem> 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() {
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.
*/
Expand All @@ -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<MediaListItem> 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<MediaListItem> mediaListItems) {
this.mediaListItems = mediaListItems;
initialize();
}

Expand All @@ -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<WebcamDevice> 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<WebcamDevice> getDevicesPreconf() {



List<WebcamDevice> devices = new ArrayList<WebcamDevice>();
List<MediaListItem> videoDevices = videoDeviceList.items();

for (MediaListItem item : videoDevices) {
devices.add(mediaListItemToDevice(item));
MediaListItem mli = new MediaListItem("HP HD Webcam [Fixed]", "dshow://", new ArrayList<MediaListItem>());

devices.add(mediaListItemToDevice(mli));

return devices;
}

@Override
public List<WebcamDevice> 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<WebcamDevice> devices = new ArrayList<WebcamDevice>();

if (mediaListItems != null) {

for (MediaListItem item : mediaListItems) {
devices.add(mediaListItemToDevice(item));
}

} else {

MediaPlayerFactory mediaPlayerFactory = createMediaPlayerFactory();
MediaDiscoverer videoMediaDiscoverer = mediaPlayerFactory.newVideoMediaDiscoverer();
MediaList videoDeviceList = videoMediaDiscoverer.getMediaList();
List<MediaListItem> videoDevices = videoDeviceList.items();

for (MediaListItem item : videoDevices) {
devices.add(mediaListItemToDevice(item));
}

videoDeviceList.release();
videoMediaDiscoverer.release();
mediaPlayerFactory.release();
}

return devices;
}
Expand Down Expand Up @@ -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;
}
}

0 comments on commit 84a7352

Please sign in to comment.