diff --git a/webcam-capture/src/example/java/com/github/sarxos/webcam/example/CalculateFPSExample.java b/webcam-capture/src/example/java/com/github/sarxos/webcam/example/CalculateFPSExample.java new file mode 100644 index 00000000..d6d3cc39 --- /dev/null +++ b/webcam-capture/src/example/java/com/github/sarxos/webcam/example/CalculateFPSExample.java @@ -0,0 +1,37 @@ +package com.github.sarxos.webcam.example; + +import com.github.sarxos.webcam.Webcam; +import com.github.sarxos.webcam.log.WebcamLogConfigurator; + + +public class CalculateFPSExample { + + public static void main(String[] args) { + + WebcamLogConfigurator.configure("src/example/resources/logback.xml"); + + long t1 = 0; + long t2 = 0; + + int p = 10; + int r = 5; + + Webcam webcam = Webcam.getDefault(); + + for (int k = 0; k < p; k++) { + + webcam.open(); + webcam.getImage(); + + t1 = System.currentTimeMillis(); + for (int i = 0; ++i <= r; webcam.getImage()) { + } + t2 = System.currentTimeMillis(); + + System.out.println("FPS " + k + ": " + (1000 * r / (t2 - t1 + 1))); + + webcam.close(); + } + + } +} diff --git a/webcam-capture/src/example/resources/logback.xml b/webcam-capture/src/example/resources/logback.xml index baeded4b..8c4d33ce 100644 --- a/webcam-capture/src/example/resources/logback.xml +++ b/webcam-capture/src/example/resources/logback.xml @@ -4,7 +4,7 @@ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - + diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/Webcam.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/Webcam.java index 5c2c839c..1aa18154 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/Webcam.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/Webcam.java @@ -165,6 +165,8 @@ public boolean open(boolean async) { if (open.compareAndSet(false, true)) { + assert updater != null; + WebcamOpenTask task = new WebcamOpenTask(driver, device); try { task.open(); @@ -216,6 +218,8 @@ public boolean close() { if (open.compareAndSet(true, false)) { + assert updater != null; + // close webcam WebcamCloseTask task = new WebcamCloseTask(driver, device); @@ -293,6 +297,7 @@ public Dimension[] getViewSizes() { * @param sizes the array of custom resolutions to be supported by webcam */ public void setCustomViewSizes(Dimension[] sizes) { + assert customSizes != null; if (sizes == null) { customSizes.clear(); return; @@ -301,6 +306,7 @@ public void setCustomViewSizes(Dimension[] sizes) { } public Dimension[] getCustomViewSizes() { + assert customSizes != null; return customSizes.toArray(new Dimension[customSizes.size()]); } @@ -334,6 +340,9 @@ public void setViewSize(Dimension size) { Dimension[] predefined = getViewSizes(); Dimension[] custom = getCustomViewSizes(); + assert predefined != null; + assert custom != null; + boolean ok = false; for (Dimension d : predefined) { if (d.width == size.width && d.height == size.height) { @@ -394,6 +403,8 @@ public BufferedImage getImage() { long t1 = 0; long t2 = 0; + assert updater != null; + if (asynchronous) { return updater.getImage(); } else { @@ -422,6 +433,7 @@ public BufferedImage getImage() { } public boolean isImageNew() { + assert updater != null; if (asynchronous) { return updater.isImageNew(); } @@ -429,6 +441,7 @@ public boolean isImageNew() { } protected double getFPS() { + assert updater != null; if (asynchronous) { return updater.getFPS(); } else { @@ -456,6 +469,9 @@ public ByteBuffer getImageBytes() { return null; } + assert driver != null; + assert device != null; + // some devices can support direct image buffers, and for those call // processor task, and for those which does not support direct image // buffers, just convert image to RGB byte array @@ -463,7 +479,12 @@ public ByteBuffer getImageBytes() { if (device instanceof BufferAccess) { return new WebcamReadBufferTask(driver, device).getBuffer(); } else { - return ByteBuffer.wrap(ImageUtils.toRawByteArray(getImage())); + BufferedImage image = getImage(); + if (image != null) { + return ByteBuffer.wrap(ImageUtils.toRawByteArray(image)); + } else { + return null; + } } } @@ -474,6 +495,9 @@ public ByteBuffer getImageBytes() { */ private boolean isReady() { + assert disposed != null; + assert open != null; + if (disposed.get()) { LOG.warn("Cannot get image, webcam has been already disposed"); return false; @@ -495,7 +519,7 @@ private boolean isReady() { * interval for webcam devices to be discovered. By default this time is set * to 1 minute. * - * @return List of webcams existing in the ssytem + * @return List of webcams existing in the system * @throws WebcamException when something is wrong * @see Webcam#getWebcams(long, TimeUnit) */ @@ -518,9 +542,13 @@ public static List getWebcams() throws WebcamException { * @param timeout the time to wait for webcam devices to be discovered * @return List of webcams existing in the ssytem * @throws WebcamException when something is wrong + * @throws IllegalArgumentException when timeout is negative * @see Webcam#getWebcams(long, TimeUnit) */ public static List getWebcams(long timeout) throws TimeoutException, WebcamException { + if (timeout < 0) { + throw new IllegalArgumentException(String.format("Timeout cannot be negative (%d)", timeout)); + } return getWebcams(timeout, TimeUnit.MILLISECONDS); } @@ -533,12 +561,22 @@ public static List getWebcams(long timeout) throws TimeoutException, Web * @return List of webcams * @throws TimeoutException when timeout has been exceeded * @throws WebcamException when something is wrong + * @throws IllegalArgumentException when timeout is negative or tunit null */ public static synchronized List getWebcams(long timeout, TimeUnit tunit) throws TimeoutException, WebcamException { + if (timeout < 0) { + throw new IllegalArgumentException(String.format("Timeout cannot be negative (%d)", timeout)); + } + if (tunit == null) { + throw new IllegalArgumentException("Time unit cannot be null!"); + } + WebcamDiscoveryService discovery = getDiscoveryService(); - List webcams = discovery.getWebcams(timeout, tunit); + assert discovery != null; + + List webcams = discovery.getWebcams(timeout, tunit); if (!discovery.isRunning()) { discovery.start(); } @@ -571,9 +609,13 @@ public static Webcam getDefault() throws WebcamException { * @return Default webcam (first from the list) * @throws TimeoutException when discovery timeout has been exceeded * @throws WebcamException if something is really wrong + * @throws IllegalArgumentException when timeout is negative * @see Webcam#getWebcams(long) */ public static Webcam getDefault(long timeout) throws TimeoutException, WebcamException { + if (timeout < 0) { + throw new IllegalArgumentException(String.format("Timeout cannot be negative (%d)", timeout)); + } return getDefault(timeout, TimeUnit.MILLISECONDS); } @@ -585,12 +627,13 @@ public static Webcam getDefault(long timeout) throws TimeoutException, WebcamExc * @return Default webcam (first from the list) * @throws TimeoutException when discovery timeout has been exceeded * @throws WebcamException if something is really wrong + * @throws IllegalArgumentException when timeout is negative or tunit null * @see Webcam#getWebcams(long, TimeUnit) */ public static Webcam getDefault(long timeout, TimeUnit tunit) throws TimeoutException, WebcamException { if (timeout < 0) { - throw new IllegalArgumentException("Timeout cannot be negative"); + throw new IllegalArgumentException(String.format("Timeout cannot be negative (%d)", timeout)); } if (tunit == null) { throw new IllegalArgumentException("Time unit cannot be null!"); @@ -598,6 +641,8 @@ public static Webcam getDefault(long timeout, TimeUnit tunit) throws TimeoutExce List webcams = getWebcams(timeout, tunit); + assert webcams != null; + if (!webcams.isEmpty()) { return webcams.get(0); } @@ -615,6 +660,7 @@ public static Webcam getDefault(long timeout, TimeUnit tunit) throws TimeoutExce * @return Name */ public String getName() { + assert device != null; return device.getName(); } @@ -633,6 +679,7 @@ public boolean addWebcamListener(WebcamListener l) { if (l == null) { throw new IllegalArgumentException("Webcam listener cannot be null!"); } + assert listeners != null; return listeners.add(l); } @@ -640,6 +687,7 @@ public boolean addWebcamListener(WebcamListener l) { * @return All webcam listeners */ public WebcamListener[] getWebcamListeners() { + assert listeners != null; return listeners.toArray(new WebcamListener[listeners.size()]); } @@ -647,6 +695,7 @@ public WebcamListener[] getWebcamListeners() { * @return Number of webcam listeners */ public int getWebcamListenersCount() { + assert listeners != null; return listeners.size(); } @@ -657,6 +706,7 @@ public int getWebcamListenersCount() { * @return True if listener has been removed, false otherwise */ public boolean removeWebcamListener(WebcamListener l) { + assert listeners != null; return listeners.remove(l); } @@ -713,12 +763,12 @@ public static synchronized void setDriver(WebcamDriver driver) { */ public static synchronized void setDriver(Class driverClass) { - resetDriver(); - if (driverClass == null) { throw new IllegalArgumentException("Webcam driver class cannot be null!"); } + resetDriver(); + try { driver = driverClass.newInstance(); } catch (InstantiationException e) { @@ -780,6 +830,7 @@ public static void registerDriver(String clazzName) { * @return Underlying webcam device instance */ public WebcamDevice getDevice() { + assert device != null; return device; } @@ -789,6 +840,12 @@ public WebcamDevice getDevice() { */ protected void dispose() { + assert disposed != null; + assert open != null; + assert driver != null; + assert device != null; + assert listeners != null; + if (!disposed.compareAndSet(false, true)) { return; } diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDiscoveryService.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDiscoveryService.java index 49c510ff..f6aeea5b 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDiscoveryService.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDiscoveryService.java @@ -1,5 +1,6 @@ package com.github.sarxos.webcam; +import java.lang.Thread.UncaughtExceptionHandler; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -18,11 +19,11 @@ import org.slf4j.LoggerFactory; -public class WebcamDiscoveryService implements Runnable { +public class WebcamDiscoveryService implements Runnable, UncaughtExceptionHandler { private static final Logger LOG = LoggerFactory.getLogger(WebcamDiscoveryService.class); - private static final class WebcamsDiscovery implements Callable>, ThreadFactory { + private static final class WebcamsDiscovery implements Callable>, ThreadFactory, UncaughtExceptionHandler { private final WebcamDriver driver; @@ -39,8 +40,14 @@ public List call() throws Exception { public Thread newThread(Runnable r) { Thread t = new Thread(r, "webcam-discovery-service"); t.setDaemon(true); + t.setUncaughtExceptionHandler(this); return t; } + + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error(String.format("Exception in thread %s", t.getName()), e); + } } private final WebcamDriver driver; @@ -53,6 +60,11 @@ public Thread newThread(Runnable r) { private Thread runner = null; protected WebcamDiscoveryService(WebcamDriver driver) { + + if (driver == null) { + throw new IllegalArgumentException("Driver cannot be null!"); + } + this.driver = driver; this.support = (WebcamDiscoverySupport) (driver instanceof WebcamDiscoverySupport ? driver : null); } @@ -320,6 +332,7 @@ public synchronized void start() { runner = new Thread(this, "webcam-discovery-service"); runner.setDaemon(true); + runner.setUncaughtExceptionHandler(this); runner.start(); } @@ -353,4 +366,9 @@ protected synchronized void shutdown() { WebcamDeallocator.unstore(); } } + + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error(String.format("Exception in thread %s", t.getName()), e); + } } diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamPanel.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamPanel.java index 9a370302..9a97473e 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamPanel.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamPanel.java @@ -66,6 +66,9 @@ public class DefaultPainter implements Painter { @Override public void paintPanel(WebcamPanel owner, Graphics2D g2) { + assert owner != null; + assert g2 != null; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setBackground(Color.BLACK); g2.fillRect(0, 0, getWidth(), getHeight()); diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamUpdater.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamUpdater.java index 220043e0..fd71e0ba 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamUpdater.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamUpdater.java @@ -1,6 +1,7 @@ package com.github.sarxos.webcam; import java.awt.image.BufferedImage; +import java.lang.Thread.UncaughtExceptionHandler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -22,7 +23,7 @@ * * @author Bartosz Firyn (sarxos) */ -public class WebcamUpdater implements Runnable, ThreadFactory { +public class WebcamUpdater implements Runnable, ThreadFactory, UncaughtExceptionHandler { /** * Class used to asynchronously notify all webcam listeners about new image @@ -250,6 +251,12 @@ public double getFPS() { public Thread newThread(Runnable r) { Thread t = new Thread(r, String.format("webcam-updater-thread-%d", number.incrementAndGet())); t.setDaemon(true); + t.setUncaughtExceptionHandler(this); return t; } + + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error(String.format("Exception in thread %s", t.getName()), e); + } }