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);