From 6f9c770863e22a6b7ffe06b8af7bcc10185e65d7 Mon Sep 17 00:00:00 2001 From: sarxos Date: Tue, 8 Jan 2013 13:07:03 +0100 Subject: [PATCH] Java core dump when terminating Webcam Capture process fixes #13 --- .../sarxos/webcam/WebcamViewerExample.java | 10 ++-- .../java/com/github/sarxos/webcam/Webcam.java | 50 +++++++++++++------ .../sarxos/webcam/WebcamDeallocator.java | 13 +++-- .../github/sarxos/webcam/WebcamListener.java | 6 +++ .../com/github/sarxos/webcam/WebcamPanel.java | 5 ++ .../github/sarxos/webcam/WebcamStreamer.java | 5 ++ .../ds/buildin/WebcamDefaultDevice.java | 28 +++++++++-- 7 files changed, 87 insertions(+), 30 deletions(-) diff --git a/webcam-capture/src/example/java/com/github/sarxos/webcam/WebcamViewerExample.java b/webcam-capture/src/example/java/com/github/sarxos/webcam/WebcamViewerExample.java index ec9e86ec..c3dd8567 100644 --- a/webcam-capture/src/example/java/com/github/sarxos/webcam/WebcamViewerExample.java +++ b/webcam-capture/src/example/java/com/github/sarxos/webcam/WebcamViewerExample.java @@ -8,11 +8,6 @@ import javax.swing.JPanel; import javax.swing.SwingUtilities; -import com.github.sarxos.webcam.Webcam; -import com.github.sarxos.webcam.WebcamEvent; -import com.github.sarxos.webcam.WebcamListener; -import com.github.sarxos.webcam.WebcamPanel; - /** * Proof of concept of how to handle webcam video stream from Java @@ -78,6 +73,10 @@ public void webcamClosed(WebcamEvent we) { pack(); } + @Override + public void webcamDisposed(WebcamEvent we) { + } + @Override public void windowActivated(WindowEvent e) { // TODO Auto-generated method stub @@ -109,4 +108,5 @@ public void windowDeiconified(WindowEvent e) { public void windowIconified(WindowEvent e) { view.pause(); } + } 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 a309bd57..b7d0d8d1 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 @@ -68,7 +68,9 @@ public void run() { private ShutdownHook hook = null; private WebcamDevice device = null; - private boolean open = false; + + private volatile boolean open = false; + private volatile boolean disposed = false; /** * Webcam class. @@ -264,12 +266,19 @@ public void setViewSize(Dimension size) { * * @return Captured image */ - public synchronized BufferedImage getImage() { - if (!open) { - LOG.debug("Try to get image on closed webcam, opening it automatically"); - open(); + public BufferedImage getImage() { + + if (disposed) { + return null; + } + + synchronized (this) { + if (!open) { + LOG.debug("Try to get image on closed webcam, opening it automatically"); + open(); + } + return device.getImage(); } - return device.getImage(); } /** @@ -290,15 +299,13 @@ public static List getWebcams() { driver = new WebcamDefaultDriver(); } - List devices = driver.getDevices(); + for (WebcamDevice device : driver.getDevices()) { + webcams.add(new Webcam(device)); + } if (deallocOnTermSignal) { LOG.warn("Automated deallocation on TERM signal is enabled!"); - WebcamDeallocator.store(devices.toArray(new WebcamDevice[devices.size()])); - } - - for (WebcamDevice device : devices) { - webcams.add(new Webcam(device)); + WebcamDeallocator.store(webcams.toArray(new Webcam[webcams.size()])); } if (LOG.isInfoEnabled()) { @@ -471,8 +478,23 @@ public WebcamDevice getDevice() { * used any more and reinstantiation is required. */ protected void dispose() { - device.close(); - device.dispose(); + + open = false; + disposed = true; + + WebcamEvent we = new WebcamEvent(this); + for (WebcamListener l : listeners) { + try { + l.webcamDisposed(we); + } catch (Exception e) { + LOG.error(String.format("Notify webcam disposed, exception when calling %s listener", l.getClass()), e); + } + } + + synchronized (this) { + device.close(); + device.dispose(); + } } /** diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDeallocator.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDeallocator.java index 87fae7e7..003850b1 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDeallocator.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDeallocator.java @@ -7,7 +7,6 @@ import java.util.Observer; - /** * Deallocator which goal is to release all devices resources when SIGTERM * signal is detected. @@ -16,7 +15,7 @@ */ class WebcamDeallocator implements Observer { - private WebcamDevice[] devices = null; + private Webcam[] webcams = null; private WebcamSignalHandler handler = new WebcamSignalHandler(); /** @@ -25,9 +24,9 @@ class WebcamDeallocator implements Observer { * * @param devices the devices to be stored in deallocator */ - private WebcamDeallocator(WebcamDevice[] devices) { + private WebcamDeallocator(Webcam[] devices) { if (devices != null && devices.length > 0) { - this.devices = devices; + this.webcams = devices; this.handler.listen("TERM", this); } } @@ -37,15 +36,15 @@ private WebcamDeallocator(WebcamDevice[] devices) { * * @param devices the devices array to be stored by deallocator */ - protected static final void store(WebcamDevice[] devices) { + protected static final void store(Webcam[] devices) { new WebcamDeallocator(devices); } @Override public void update(Observable observable, Object object) { - for (WebcamDevice device : devices) { + for (Webcam device : webcams) { try { - device.close(); + device.dispose(); } catch (Throwable t) { caugh(t); } diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamListener.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamListener.java index 4ae634bb..bf7c5035 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamListener.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamListener.java @@ -21,4 +21,10 @@ public interface WebcamListener { */ public void webcamClosed(WebcamEvent we); + /** + * Webcam has been disposed + * + * @param we a webcam event + */ + public void webcamDisposed(WebcamEvent we); } 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 05118f8f..040c10d7 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 @@ -313,6 +313,11 @@ public void webcamClosed(WebcamEvent we) { } } + @Override + public void webcamDisposed(WebcamEvent we) { + webcamClosed(we); + } + /** * Open webcam and start rendering. */ diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamStreamer.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamStreamer.java index a4a5406b..f7eb15c2 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamStreamer.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamStreamer.java @@ -247,10 +247,15 @@ public void webcamOpen(WebcamEvent we) { public void webcamClosed(WebcamEvent we) { } + @Override + public void webcamDisposed(WebcamEvent we) { + } + public static void main(String[] args) throws InterruptedException { new WebcamStreamer(8081, Webcam.getDefault(), 0.5, true); do { Thread.sleep(1000); } while (true); } + } diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/ds/buildin/WebcamDefaultDevice.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/ds/buildin/WebcamDefaultDevice.java index cef18020..6284fc63 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/ds/buildin/WebcamDefaultDevice.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/ds/buildin/WebcamDefaultDevice.java @@ -109,13 +109,20 @@ public class WebcamDefaultDevice implements WebcamDevice { private volatile boolean opening = false; private volatile boolean disposed = false; + private String name = null; + private String id = null; + private String fullname = null; + protected WebcamDefaultDevice(Device device) { this.device = device; + this.name = device.getNameStr(); + this.id = device.getIdentifierStr(); + this.fullname = String.format("%s %s", this.name, this.id); } @Override public String getName() { - return String.format("%s %s", device.getNameStr(), device.getIdentifierStr()); + return fullname; } @Override @@ -136,8 +143,13 @@ public void setSize(Dimension size) { @Override public BufferedImage getImage() { + if (disposed) { + throw new WebcamException("Cannot get image since device is already disposed"); + } + if (!open) { - throw new WebcamException("Cannot get image when webcam device is not open"); + LOG.error("Cannot get image when device is closed"); + return null; } frameTask.nextFrame(); @@ -163,8 +175,7 @@ public BufferedImage getImage() { public void open() { if (disposed) { - LOG.warn("Cannot open webcam when it's already disposed"); - return; + throw new WebcamException("Cannot open webcam when device it's already disposed"); } synchronized (device) { @@ -223,6 +234,11 @@ public void open() { frameTask.nextFrame(); imageTask.getImage(size); + if (disposed) { + opening = false; + return; + } + try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -257,6 +273,10 @@ public void close() { @Override public void dispose() { + if (disposed) { + return; + } + close(); disposed = true; }