Skip to content

Commit

Permalink
Add timeout to Webcam.getWebcams() and getDefault() methods
Browse files Browse the repository at this point in the history
closes #12
  • Loading branch information
sarxos committed Jan 8, 2013
1 parent 6f9c770 commit 421c070
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 8 deletions.
129 changes: 123 additions & 6 deletions webcam-capture/src/main/java/com/github/sarxos/webcam/Webcam.java
Expand Up @@ -6,6 +6,13 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -34,7 +41,7 @@ public class Webcam {
private static final List<String> DRIVERS_LIST = new ArrayList<String>(Arrays.asList(DRIVERS_DEFAULT));
private static final List<Class<?>> DRIVERS_CLASS_LIST = new ArrayList<Class<?>>();

private static class ShutdownHook extends Thread {
private static final class ShutdownHook extends Thread {

private Webcam webcam = null;

Expand All @@ -51,6 +58,32 @@ public void run() {
}
}

private static final class WebcamsDiscovery implements Callable<List<Webcam>> {

private final WebcamDriver driver;

public WebcamsDiscovery(WebcamDriver driver) {
this.driver = driver;
}

@Override
public List<Webcam> call() throws Exception {
List<Webcam> webcams = new ArrayList<Webcam>();
for (WebcamDevice device : driver.getDevices()) {
webcams.add(new Webcam(device));
}
return webcams;
}
}

/**
* Timeout for devices discovery. By default this is set to 1 minute, but
* can be changed by appropriate static setter.
*
* @see Webcam#setDiscoveryTimeout(long)
*/
private static long timeout = 60000;

private static WebcamDriver driver = null;
private static List<Webcam> webcams = null;

Expand Down Expand Up @@ -202,6 +235,12 @@ public Dimension[] getViewSizes() {
return device.getSizes();
}

/**
* Set custom resolution. If you are using this method you have to make sure
* that your webcam device can support this specific resolution.
*
* @param sizes the array of custom resolutions to be supported by webcam
*/
public void setCustomViewSizes(Dimension[] sizes) {
if (sizes == null) {
customSizes.clear();
Expand All @@ -214,6 +253,14 @@ public Dimension[] getCustomViewSizes() {
return customSizes.toArray(new Dimension[customSizes.size()]);
}

/**
* Set new view size. New size has to exactly the same as one of the default
* sized or exactly the same as one of the custom ones.
*
* @param size the new view size to be set
* @see Webcam#setCustomViewSizes(Dimension[])
* @see Webcam#getViewSizes()
*/
public void setViewSize(Dimension size) {

if (size == null) {
Expand Down Expand Up @@ -285,11 +332,27 @@ public BufferedImage getImage() {
* Get list of webcams to use.
*
* @return List of webcams
* @throws WebcamException when something is wrong
*/
public static List<Webcam> getWebcams() {
if (webcams == null) {
try {
return getWebcams(timeout);
} catch (TimeoutException e) {
throw new WebcamException(e);
}
}

webcams = new ArrayList<Webcam>();
/**
* Get list of webcams to use.
*
* @param timeout the devices discovery timeout
* @return List of webcams
* @throws TimeoutException when timeout has been exceeded
* @throws WebcamException when something is wrong
*/
public static List<Webcam> getWebcams(long timeout) throws TimeoutException {

if (webcams == null) {

if (driver == null) {
driver = WebcamDriverUtils.findDriver(DRIVERS_LIST, DRIVERS_CLASS_LIST);
Expand All @@ -299,8 +362,28 @@ public static List<Webcam> getWebcams() {
driver = new WebcamDefaultDriver();
}

for (WebcamDevice device : driver.getDevices()) {
webcams.add(new Webcam(device));
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<List<Webcam>> future = executor.submit(new WebcamsDiscovery(driver));
executor.shutdown();

try {

executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);

if (future.isDone()) {
webcams = future.get();
} else {
future.cancel(true);
}

} catch (InterruptedException e) {
throw new WebcamException(e);
} catch (ExecutionException e) {
throw new WebcamException(e);
}

if (webcams == null) {
throw new TimeoutException(String.format("Webcams discovery timeout (%d ms) has been exceeded", timeout));
}

if (deallocOnTermSignal) {
Expand All @@ -323,10 +406,28 @@ protected static void clearWebcams() {
}

/**
* Will discover and return first webcam available in the system.
*
* @return Default webcam (first from the list)
* @throws WebcamException if something is wrong
*/
public static Webcam getDefault() {
List<Webcam> webcams = getWebcams();
try {
return getDefault(timeout);
} catch (TimeoutException e) {
throw new WebcamException(e);
}
}

/**
* Will discover and return first webcam available in the system.
*
* @param timeout the webcam discovery timeout (1 minute by default)
* @return Default webcam (first from the list)
* @throws TimeoutException when discovery timeout has been exceeded
*/
public static Webcam getDefault(long timeout) throws TimeoutException {
List<Webcam> webcams = getWebcams(timeout);
if (webcams.isEmpty()) {
throw new WebcamException("No webcam available in the system");
}
Expand Down Expand Up @@ -372,6 +473,12 @@ public WebcamListener[] getWebcamListeners() {
}
}

/**
* Removes webcam listener.
*
* @param l the listener to be removed
* @return True if listener has been removed, false otherwise
*/
public boolean removeWebcamListener(WebcamListener l) {
synchronized (listeners) {
return listeners.remove(l);
Expand Down Expand Up @@ -511,4 +618,14 @@ protected void dispose() {
public static void handleTermSignal(boolean on) {
deallocOnTermSignal = on;
}

/**
* Set new devices discovery timeout. By default this is set to 1 minute
* (60000 milliseconds).
*
* @param timeout the new discovery timeout in milliseconds
*/
public static void setDiscoveryTimeout(long timeout) {
Webcam.timeout = timeout;
}
}
Expand Up @@ -24,7 +24,7 @@ public void listen(String signal, Observer observer) throws IllegalArgumentExcep
}

@Override
public void handle(final sun.misc.Signal signal) {
public void handle(Signal signal) {

// do nothing on "signal default" or "signal ignore"
if (handler == SIG_DFL || handler == SIG_IGN) {
Expand Down
Expand Up @@ -8,16 +8,35 @@
import com.github.sarxos.webcam.ds.buildin.natives.Device;


/**
* Processor task used to discover native webcam devices.
*
* @author Bartosz Firyn (SarXos)
*/
public class GetDevicesTask extends WebcamGrabberTask {

/**
* Devices list.
*/
private AtomicReference<List<Device>> devices = new AtomicReference<List<Device>>();

/**
* Processor.
*/
private WebcamGrabberProcessor processor = null;

/**
* Creates new task used to discover native webcam devices.
*
* @param processor
*/
public GetDevicesTask(WebcamGrabberProcessor processor) {
this.processor = processor;
}

/**
* @return Discovered devices
*/
public List<Device> getDevices() {
process(processor);
return devices.get();
Expand Down
Expand Up @@ -32,7 +32,7 @@ public void cleanup() {
}

@Test
public void test_getDevices() {
public void test_getWebcams() {

List<Webcam> webcams = Webcam.getWebcams();
List<WebcamDevice> devices = DummyDriver.getInstance().getDevices();
Expand Down

0 comments on commit 421c070

Please sign in to comment.