Skip to content

Commit 6f9c770

Browse files
author
sarxos
committed
Java core dump when terminating Webcam Capture process
fixes #13
1 parent 9c8acf3 commit 6f9c770

File tree

7 files changed

+87
-30
lines changed

7 files changed

+87
-30
lines changed

webcam-capture/src/example/java/com/github/sarxos/webcam/WebcamViewerExample.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@
88
import javax.swing.JPanel;
99
import javax.swing.SwingUtilities;
1010

11-
import com.github.sarxos.webcam.Webcam;
12-
import com.github.sarxos.webcam.WebcamEvent;
13-
import com.github.sarxos.webcam.WebcamListener;
14-
import com.github.sarxos.webcam.WebcamPanel;
15-
1611

1712
/**
1813
* Proof of concept of how to handle webcam video stream from Java
@@ -78,6 +73,10 @@ public void webcamClosed(WebcamEvent we) {
7873
pack();
7974
}
8075

76+
@Override
77+
public void webcamDisposed(WebcamEvent we) {
78+
}
79+
8180
@Override
8281
public void windowActivated(WindowEvent e) {
8382
// TODO Auto-generated method stub
@@ -109,4 +108,5 @@ public void windowDeiconified(WindowEvent e) {
109108
public void windowIconified(WindowEvent e) {
110109
view.pause();
111110
}
111+
112112
}

webcam-capture/src/main/java/com/github/sarxos/webcam/Webcam.java

+36-14
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ public void run() {
6868

6969
private ShutdownHook hook = null;
7070
private WebcamDevice device = null;
71-
private boolean open = false;
71+
72+
private volatile boolean open = false;
73+
private volatile boolean disposed = false;
7274

7375
/**
7476
* Webcam class.
@@ -264,12 +266,19 @@ public void setViewSize(Dimension size) {
264266
*
265267
* @return Captured image
266268
*/
267-
public synchronized BufferedImage getImage() {
268-
if (!open) {
269-
LOG.debug("Try to get image on closed webcam, opening it automatically");
270-
open();
269+
public BufferedImage getImage() {
270+
271+
if (disposed) {
272+
return null;
273+
}
274+
275+
synchronized (this) {
276+
if (!open) {
277+
LOG.debug("Try to get image on closed webcam, opening it automatically");
278+
open();
279+
}
280+
return device.getImage();
271281
}
272-
return device.getImage();
273282
}
274283

275284
/**
@@ -290,15 +299,13 @@ public static List<Webcam> getWebcams() {
290299
driver = new WebcamDefaultDriver();
291300
}
292301

293-
List<WebcamDevice> devices = driver.getDevices();
302+
for (WebcamDevice device : driver.getDevices()) {
303+
webcams.add(new Webcam(device));
304+
}
294305

295306
if (deallocOnTermSignal) {
296307
LOG.warn("Automated deallocation on TERM signal is enabled!");
297-
WebcamDeallocator.store(devices.toArray(new WebcamDevice[devices.size()]));
298-
}
299-
300-
for (WebcamDevice device : devices) {
301-
webcams.add(new Webcam(device));
308+
WebcamDeallocator.store(webcams.toArray(new Webcam[webcams.size()]));
302309
}
303310

304311
if (LOG.isInfoEnabled()) {
@@ -471,8 +478,23 @@ public WebcamDevice getDevice() {
471478
* used any more and reinstantiation is required.
472479
*/
473480
protected void dispose() {
474-
device.close();
475-
device.dispose();
481+
482+
open = false;
483+
disposed = true;
484+
485+
WebcamEvent we = new WebcamEvent(this);
486+
for (WebcamListener l : listeners) {
487+
try {
488+
l.webcamDisposed(we);
489+
} catch (Exception e) {
490+
LOG.error(String.format("Notify webcam disposed, exception when calling %s listener", l.getClass()), e);
491+
}
492+
}
493+
494+
synchronized (this) {
495+
device.close();
496+
device.dispose();
497+
}
476498
}
477499

478500
/**

webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamDeallocator.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.Observer;
88

99

10-
1110
/**
1211
* Deallocator which goal is to release all devices resources when SIGTERM
1312
* signal is detected.
@@ -16,7 +15,7 @@
1615
*/
1716
class WebcamDeallocator implements Observer {
1817

19-
private WebcamDevice[] devices = null;
18+
private Webcam[] webcams = null;
2019
private WebcamSignalHandler handler = new WebcamSignalHandler();
2120

2221
/**
@@ -25,9 +24,9 @@ class WebcamDeallocator implements Observer {
2524
*
2625
* @param devices the devices to be stored in deallocator
2726
*/
28-
private WebcamDeallocator(WebcamDevice[] devices) {
27+
private WebcamDeallocator(Webcam[] devices) {
2928
if (devices != null && devices.length > 0) {
30-
this.devices = devices;
29+
this.webcams = devices;
3130
this.handler.listen("TERM", this);
3231
}
3332
}
@@ -37,15 +36,15 @@ private WebcamDeallocator(WebcamDevice[] devices) {
3736
*
3837
* @param devices the devices array to be stored by deallocator
3938
*/
40-
protected static final void store(WebcamDevice[] devices) {
39+
protected static final void store(Webcam[] devices) {
4140
new WebcamDeallocator(devices);
4241
}
4342

4443
@Override
4544
public void update(Observable observable, Object object) {
46-
for (WebcamDevice device : devices) {
45+
for (Webcam device : webcams) {
4746
try {
48-
device.close();
47+
device.dispose();
4948
} catch (Throwable t) {
5049
caugh(t);
5150
}

webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamListener.java

+6
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,10 @@ public interface WebcamListener {
2121
*/
2222
public void webcamClosed(WebcamEvent we);
2323

24+
/**
25+
* Webcam has been disposed
26+
*
27+
* @param we a webcam event
28+
*/
29+
public void webcamDisposed(WebcamEvent we);
2430
}

webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamPanel.java

+5
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ public void webcamClosed(WebcamEvent we) {
313313
}
314314
}
315315

316+
@Override
317+
public void webcamDisposed(WebcamEvent we) {
318+
webcamClosed(we);
319+
}
320+
316321
/**
317322
* Open webcam and start rendering.
318323
*/

webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamStreamer.java

+5
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,15 @@ public void webcamOpen(WebcamEvent we) {
247247
public void webcamClosed(WebcamEvent we) {
248248
}
249249

250+
@Override
251+
public void webcamDisposed(WebcamEvent we) {
252+
}
253+
250254
public static void main(String[] args) throws InterruptedException {
251255
new WebcamStreamer(8081, Webcam.getDefault(), 0.5, true);
252256
do {
253257
Thread.sleep(1000);
254258
} while (true);
255259
}
260+
256261
}

webcam-capture/src/main/java/com/github/sarxos/webcam/ds/buildin/WebcamDefaultDevice.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,20 @@ public class WebcamDefaultDevice implements WebcamDevice {
109109
private volatile boolean opening = false;
110110
private volatile boolean disposed = false;
111111

112+
private String name = null;
113+
private String id = null;
114+
private String fullname = null;
115+
112116
protected WebcamDefaultDevice(Device device) {
113117
this.device = device;
118+
this.name = device.getNameStr();
119+
this.id = device.getIdentifierStr();
120+
this.fullname = String.format("%s %s", this.name, this.id);
114121
}
115122

116123
@Override
117124
public String getName() {
118-
return String.format("%s %s", device.getNameStr(), device.getIdentifierStr());
125+
return fullname;
119126
}
120127

121128
@Override
@@ -136,8 +143,13 @@ public void setSize(Dimension size) {
136143
@Override
137144
public BufferedImage getImage() {
138145

146+
if (disposed) {
147+
throw new WebcamException("Cannot get image since device is already disposed");
148+
}
149+
139150
if (!open) {
140-
throw new WebcamException("Cannot get image when webcam device is not open");
151+
LOG.error("Cannot get image when device is closed");
152+
return null;
141153
}
142154

143155
frameTask.nextFrame();
@@ -163,8 +175,7 @@ public BufferedImage getImage() {
163175
public void open() {
164176

165177
if (disposed) {
166-
LOG.warn("Cannot open webcam when it's already disposed");
167-
return;
178+
throw new WebcamException("Cannot open webcam when device it's already disposed");
168179
}
169180

170181
synchronized (device) {
@@ -223,6 +234,11 @@ public void open() {
223234
frameTask.nextFrame();
224235
imageTask.getImage(size);
225236

237+
if (disposed) {
238+
opening = false;
239+
return;
240+
}
241+
226242
try {
227243
Thread.sleep(1000);
228244
} catch (InterruptedException e) {
@@ -257,6 +273,10 @@ public void close() {
257273

258274
@Override
259275
public void dispose() {
276+
if (disposed) {
277+
return;
278+
}
279+
close();
260280
disposed = true;
261281
}
262282

0 commit comments

Comments
 (0)