From bd53abaac3dfccba77f8eb50ea46086d545857cd Mon Sep 17 00:00:00 2001 From: Bartosz Firyn Date: Thu, 2 May 2013 14:46:56 +0200 Subject: [PATCH] Stop WebcamPanel doesn't stop all required threads, fixes #90 --- .../src/example/java/WebcamPanelExample.java | 21 ++- .../src/example/resources/logback.xml | 2 +- .../com/github/sarxos/webcam/WebcamPanel.java | 136 ++++++++++-------- .../webcam/log/WebcamLogConfigurator.java | 7 + 4 files changed, 104 insertions(+), 62 deletions(-) diff --git a/webcam-capture/src/example/java/WebcamPanelExample.java b/webcam-capture/src/example/java/WebcamPanelExample.java index 59b08c72..8613cbbb 100644 --- a/webcam-capture/src/example/java/WebcamPanelExample.java +++ b/webcam-capture/src/example/java/WebcamPanelExample.java @@ -1,17 +1,19 @@ - - import javax.swing.JFrame; import com.github.sarxos.webcam.Webcam; import com.github.sarxos.webcam.WebcamPanel; +import com.github.sarxos.webcam.log.WebcamLogConfigurator; public class WebcamPanelExample { - public static void main(String[] args) { + public static void main(String[] args) throws InterruptedException { + + WebcamLogConfigurator.configure("src/example/resources/logback.xml"); + JFrame window = new JFrame("Test webcam panel"); - WebcamPanel panel = new WebcamPanel(Webcam.getDefault()); + final WebcamPanel panel = new WebcamPanel(Webcam.getDefault()); panel.setFPSDisplayed(true); // display FPS on screen panel.setFPSLimited(false); // no FPS limit panel.setFillArea(true); // image will be resized with window @@ -20,6 +22,15 @@ public static void main(String[] args) { window.pack(); window.setVisible(true); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } + Thread.sleep(5000); + panel.stop(); + Thread.sleep(5000); + panel.start(); + Thread.sleep(5000); + panel.pause(); + Thread.sleep(5000); + panel.resume(); + + } } diff --git a/webcam-capture/src/example/resources/logback.xml b/webcam-capture/src/example/resources/logback.xml index 8c4d33ce..2bb01a64 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/WebcamPanel.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamPanel.java index 272d0574..438c4b85 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 @@ -211,64 +211,82 @@ public Thread newThread(Runnable r) { /** * Scheduled executor acting as timer. */ - private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, THREAD_FACTORY); + private ScheduledExecutorService executor = null; /** - * Repainter updates panel when it is being started. + * Image updater reads images from camera and force panel to be repainted. * - * @author Bartosz Firyn (sarxos) + * @author Bartosz Firyn (SarXos) */ - private class Repainter extends Thread { + private class ImageUpdater implements Runnable { - public Repainter() { - setUncaughtExceptionHandler(WebcamExceptionHandler.getInstance()); - setName(String.format("repainter-%s", webcam.getName())); - setDaemon(true); - } + /** + * Repainter updates panel when it is being started. + * + * @author Bartosz Firyn (sarxos) + */ + private class RepaintScheduler extends Thread { - @Override - public void run() { + public RepaintScheduler() { + setUncaughtExceptionHandler(WebcamExceptionHandler.getInstance()); + setName(String.format("repaint-scheduler-%s", webcam.getName())); + setDaemon(true); + } - repaint(); + @Override + public void run() { - while (starting) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - throw new RuntimeException(e); + if (!running.get()) { + return; } - } - if (webcam.isOpen()) { - if (isFPSLimited()) { - executor.scheduleAtFixedRate(updater, 0, (long) (1000 / frequency), TimeUnit.MILLISECONDS); + repaint(); + + while (starting) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + if (webcam.isOpen()) { + if (isFPSLimited()) { + executor.scheduleAtFixedRate(updater, 0, (long) (1000 / frequency), TimeUnit.MILLISECONDS); + } else { + executor.scheduleWithFixedDelay(updater, 100, 1, TimeUnit.MILLISECONDS); + } } else { - executor.scheduleWithFixedDelay(updater, 100, 1, TimeUnit.MILLISECONDS); + executor.schedule(this, 500, TimeUnit.MILLISECONDS); } - } else { - executor.schedule(this, 500, TimeUnit.MILLISECONDS); } + } - } + private Thread scheduler = new RepaintScheduler(); - /** - * Image updater reads images from camera and force panel to be repainted. - * - * @author Bartosz Firyn (SarXos) - */ - private class ImageUpdater implements Runnable { + private AtomicBoolean running = new AtomicBoolean(false); - public ImageUpdater() { + public void start() { + if (running.compareAndSet(false, true)) { + executor = Executors.newScheduledThreadPool(1, THREAD_FACTORY); + scheduler.start(); + } } - public void start() { - new Repainter().start(); + public void stop() { + if (running.compareAndSet(true, false)) { + executor.shutdown(); + } } @Override public void run() { + if (!running.get()) { + return; + } + if (!webcam.isOpen()) { return; } @@ -333,7 +351,7 @@ public void run() { * Repainter is used to fetch images from camera and force panel repaint * when image is ready. */ - private volatile ImageUpdater updater = new ImageUpdater(); + private volatile ImageUpdater updater = null; /** * Webcam is currently starting. @@ -425,13 +443,7 @@ public WebcamPanel(Webcam webcam, Dimension size, boolean start) { } if (start) { - updater.start(); - try { - errored = !webcam.open(); - } catch (WebcamException e) { - errored = true; - throw e; - } + start(); } } @@ -480,9 +492,7 @@ public void webcamOpen(WebcamEvent we) { @Override public void webcamClosed(WebcamEvent we) { - if (updater != null) { - updater = null; - } + stop(); } @Override @@ -504,6 +514,8 @@ public void start() { return; } + LOG.debug("Starting panel rendering and trying to open attached webcam"); + starting = true; if (updater == null) { @@ -526,14 +538,22 @@ public void start() { * Stop rendering and close webcam. */ public void stop() { - if (started.compareAndSet(true, false)) { - image = null; - try { - errored = !webcam.close(); - } catch (WebcamException e) { - errored = true; - throw e; - } + if (!started.compareAndSet(true, false)) { + return; + } + + LOG.debug("Stopping panel rendering and closing attached webcam"); + + updater.stop(); + updater = null; + + image = null; + + try { + errored = !webcam.close(); + } catch (WebcamException e) { + errored = true; + throw e; } } @@ -544,6 +564,9 @@ public void pause() { if (paused) { return; } + + LOG.debug("Pausing panel rendering"); + paused = true; } @@ -551,13 +574,14 @@ public void pause() { * Resume rendering. */ public void resume() { + if (!paused) { return; } + + LOG.debug("Resuming panel rendering"); + paused = false; - synchronized (updater) { - updater.notifyAll(); - } } /** diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/log/WebcamLogConfigurator.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/log/WebcamLogConfigurator.java index 5803e4a2..8dc6b450 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/log/WebcamLogConfigurator.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/log/WebcamLogConfigurator.java @@ -33,6 +33,13 @@ public class WebcamLogConfigurator { */ public static void configure(InputStream is) { + try { + Class.forName("ch.qos.logback.classic.LoggerContext"); + } catch (ClassNotFoundException e1) { + LOG.error("Cannot configure logger because logback LoggerContext is not available in classpath"); + return; + } + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(context);