Skip to content

Commit

Permalink
Fix updater failure when underlying driver throws exception, fixes #390
Browse files Browse the repository at this point in the history
  • Loading branch information
sarxos committed Sep 12, 2015
1 parent e23df55 commit 0f87892
Showing 1 changed file with 40 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.github.sarxos.webcam;

import static com.github.sarxos.webcam.WebcamExceptionHandler.handle;

import java.awt.image.BufferedImage;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
Expand All @@ -17,47 +19,44 @@


/**
* The goal of webcam updater class is to update image in parallel, so all calls
* to fetch image invoked on webcam instance will be non-blocking (will return
* immediately).
* The goal of webcam updater class is to update image in parallel, so all calls to fetch image
* invoked on webcam instance will be non-blocking (will return immediately).
*
* @author Bartosz Firyn (sarxos)
*/
public class WebcamUpdater implements Runnable {

/**
* Implementation of this interface is responsible for calculating the delay
* between 2 image fetching, when the non-blocking (asynchronous) access to the
* webcam is enabled.
* Implementation of this interface is responsible for calculating the delay between 2 image
* fetching, when the non-blocking (asynchronous) access to the webcam is enabled.
*/
public static interface DelayCalculator {

/**
* Calculates delay before the next image will be fetched from the
* webcam.
* Must return number greater or equal 0.
* Calculates delay before the next image will be fetched from the webcam. Must return
* number greater or equal 0.
*
* @param snapshotDuration - duration of taking the last image
* @param deviceFps - current FPS obtained from the device, or -1 if the
* driver doesn't support it
* @param deviceFps - current FPS obtained from the device, or -1 if the driver doesn't
* support it
* @return interval (in millis)
*/
long calculateDelay(long snapshotDuration, double deviceFps);
}

/**
* Default impl of DelayCalculator, based on TARGET_FPS. Returns 0 delay for
* snapshotDuration > 20 millis.
* Default impl of DelayCalculator, based on TARGET_FPS. Returns 0 delay for snapshotDuration
* > 20 millis.
*/
public static class DefaultDelayCalculator implements DelayCalculator {

@Override
public long calculateDelay(long snapshotDuration, double deviceFps) {
// Calculate delay required to achieve target FPS.
// In some cases it can be less than 0
// Calculate delay required to achieve target FPS.
// In some cases it can be less than 0
// because camera is not able to serve images as fast as
// we would like to. In such case just run with no delay,
// so maximum FPS will be the one supported
// we would like to. In such case just run with no delay,
// so maximum FPS will be the one supported
// by camera device in the moment.

long delay = Math.max((1000 / TARGET_FPS) - snapshotDuration, 0);
Expand Down Expand Up @@ -127,7 +126,7 @@ public Thread newThread(Runnable r) {
* DelayCalculator implementation.
*/
private final DelayCalculator delayCalculator;

/**
* Construct new webcam updater using DefaultDelayCalculator.
*
Expand Down Expand Up @@ -201,9 +200,8 @@ public void run() {
try {
tick();
} catch (Throwable t) {
WebcamExceptionHandler.handle(t);
handle(t);
}

}

private void tick() {
Expand All @@ -212,9 +210,6 @@ private void tick() {
return;
}

long t1 = 0;
long t2 = 0;

// Calculate time required to fetch 1 picture.

WebcamDriver driver = Webcam.getDriver();
Expand All @@ -223,23 +218,25 @@ private void tick() {
assert driver != null;
assert device != null;

BufferedImage img = null;

t1 = System.currentTimeMillis();
img = webcam.transform(new WebcamGetImageTask(driver, device).getImage());
t2 = System.currentTimeMillis();

image.set(img);
imageNew = true;
boolean imageOk = false;
long t1 = System.currentTimeMillis();
try {
image.set(webcam.transform(new WebcamGetImageTask(driver, device).getImage()));
imageNew = true;
imageOk = true;
} catch (WebcamException e) {
handle(e);
}
long t2 = System.currentTimeMillis();

double deviceFps = -1;
if (device instanceof WebcamDevice.FPSSource) {
deviceFps = ((WebcamDevice.FPSSource) device).getFPS();
}

long duration = t2 - t1;
long duration = t2 - t1;
long delay = delayCalculator.calculateDelay(duration, deviceFps);

long delta = duration + 1; // +1 to avoid division by zero
if (deviceFps >= 0) {
fps = deviceFps;
Expand All @@ -259,16 +256,17 @@ private void tick() {

// notify webcam listeners about the new image available

webcam.notifyWebcamImageAcquired(image.get());
if (imageOk) {
webcam.notifyWebcamImageAcquired(image.get());
}
}

/**
* Return currently available image. This method will return immediately
* while it was been called after camera has been open. In case when there
* are parallel threads running and there is a possibility to call this
* method in the opening time, or before camera has been open at all, this
* method will block until webcam return first image. Maximum blocking time
* will be 10 seconds, after this time method will return null.
* Return currently available image. This method will return immediately while it was been
* called after camera has been open. In case when there are parallel threads running and there
* is a possibility to call this method in the opening time, or before camera has been open at
* all, this method will block until webcam return first image. Maximum blocking time will be 10
* seconds, after this time method will return null.
*
* @return Image stored in cache
*/
Expand Down Expand Up @@ -305,8 +303,8 @@ protected boolean isImageNew() {
}

/**
* Return current FPS number. It is calculated in real-time on the base of
* how often camera serve new image.
* Return current FPS number. It is calculated in real-time on the base of how often camera
* serve new image.
*
* @return FPS number
*/
Expand Down

0 comments on commit 0f87892

Please sign in to comment.