Skip to content

Commit 9c8acf3

Browse files
author
sarxos
committed
Deallocate devices on TERM signal (experimental feature)
closes #10
1 parent 064efa2 commit 9c8acf3

File tree

8 files changed

+225
-56
lines changed

8 files changed

+225
-56
lines changed

.project

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
<?xml version="1.0" encoding="UTF-8"?>
2-
<projectDescription>
3-
<name>webcam-capture</name>
4-
<comment></comment>
5-
<projects>
6-
</projects>
7-
<buildSpec>
8-
<buildCommand>
9-
<name>org.eclipse.m2e.core.maven2Builder</name>
10-
<arguments>
11-
</arguments>
12-
</buildCommand>
13-
</buildSpec>
14-
<natures>
15-
<nature>org.eclipse.m2e.core.maven2Nature</nature>
16-
</natures>
17-
</projectDescription>
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>webcam-capture-parent</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.m2e.core.maven2Builder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.m2e.core.maven2Nature</nature>
16+
</natures>
17+
</projectDescription>
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,26 @@
1-
<?xml version="1.0" encoding="UTF-8"?>
2-
<classpath>
3-
<classpathentry kind="src" output="target/classes" path="src/main/java">
4-
<attributes>
5-
<attribute name="optional" value="true"/>
6-
<attribute name="maven.pomderived" value="true"/>
7-
</attributes>
8-
</classpathentry>
9-
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
10-
<attributes>
11-
<attribute name="maven.pomderived" value="true"/>
12-
</attributes>
13-
</classpathentry>
14-
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
15-
<attributes>
16-
<attribute name="optional" value="true"/>
17-
<attribute name="maven.pomderived" value="true"/>
18-
</attributes>
19-
</classpathentry>
20-
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
21-
<attributes>
22-
<attribute name="maven.pomderived" value="true"/>
23-
</attributes>
24-
</classpathentry>
25-
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
26-
<attributes>
27-
<attribute name="maven.pomderived" value="true"/>
28-
</attributes>
29-
</classpathentry>
30-
<classpathentry kind="output" path="target/classes"/>
31-
</classpath>
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="src" output="target/classes" path="src/main/java">
4+
<attributes>
5+
<attribute name="optional" value="true"/>
6+
<attribute name="maven.pomderived" value="true"/>
7+
</attributes>
8+
</classpathentry>
9+
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
10+
<attributes>
11+
<attribute name="optional" value="true"/>
12+
<attribute name="maven.pomderived" value="true"/>
13+
</attributes>
14+
</classpathentry>
15+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
16+
<attributes>
17+
<attribute name="maven.pomderived" value="true"/>
18+
</attributes>
19+
</classpathentry>
20+
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
21+
<attributes>
22+
<attribute name="maven.pomderived" value="true"/>
23+
</attributes>
24+
</classpathentry>
25+
<classpathentry kind="output" path="target/classes"/>
26+
</classpath>

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

+31-4
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ public class Webcam {
2323

2424
private static final Logger LOG = LoggerFactory.getLogger(Webcam.class);
2525

26-
//@formatter:off
26+
// @formatter:off
2727
private static final String[] DRIVERS_DEFAULT = new String[] {
2828
"com.github.sarxos.webcam.ds.openimaj.OpenImajDriver",
2929
"com.github.sarxos.webcam.ds.civil.LtiCivilDriver",
3030
"com.github.sarxos.webcam.ds.jmf.JmfDriver",
3131
};
32-
//@formatter:on
32+
// @formatter:on
3333

3434
private static final List<String> DRIVERS_LIST = new ArrayList<String>(Arrays.asList(DRIVERS_DEFAULT));
3535
private static final List<Class<?>> DRIVERS_CLASS_LIST = new ArrayList<Class<?>>();
@@ -54,6 +54,11 @@ public void run() {
5454
private static WebcamDriver driver = null;
5555
private static List<Webcam> webcams = null;
5656

57+
/**
58+
* Is automated deallocation on TERM signal enabled.
59+
*/
60+
private static volatile boolean deallocOnTermSignal = false;
61+
5762
/**
5863
* Webcam listeners.
5964
*/
@@ -144,7 +149,7 @@ public synchronized void close() {
144149
}
145150

146151
/**
147-
* Close webcam.
152+
* Close webcam (internal impl).
148153
*/
149154
private void close0() {
150155

@@ -285,7 +290,14 @@ public static List<Webcam> getWebcams() {
285290
driver = new WebcamDefaultDriver();
286291
}
287292

288-
for (WebcamDevice device : driver.getDevices()) {
293+
List<WebcamDevice> devices = driver.getDevices();
294+
295+
if (deallocOnTermSignal) {
296+
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) {
289301
webcams.add(new Webcam(device));
290302
}
291303

@@ -462,4 +474,19 @@ protected void dispose() {
462474
device.close();
463475
device.dispose();
464476
}
477+
478+
/**
479+
* <b>CAUTION!!!</b><br>
480+
* <br>
481+
* This is experimental feature to be used mostly in in development phase.
482+
* After you set handle term signal to true, and fetch capture devices,
483+
* Webcam Capture API will listen for TERM signal and try to close all
484+
* devices after it has been received. <b>This feature can be unstable on
485+
* some systems!</b>
486+
*
487+
* @param on
488+
*/
489+
public static void handleTermSignal(boolean on) {
490+
deallocOnTermSignal = on;
491+
}
465492
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.github.sarxos.webcam;
2+
3+
import java.io.File;
4+
import java.io.FileNotFoundException;
5+
import java.io.PrintStream;
6+
import java.util.Observable;
7+
import java.util.Observer;
8+
9+
10+
11+
/**
12+
* Deallocator which goal is to release all devices resources when SIGTERM
13+
* signal is detected.
14+
*
15+
* @author Bartosz Firyn (SarXos)
16+
*/
17+
class WebcamDeallocator implements Observer {
18+
19+
private WebcamDevice[] devices = null;
20+
private WebcamSignalHandler handler = new WebcamSignalHandler();
21+
22+
/**
23+
* This constructor is used internally to create new deallocator for the
24+
* given devices array.
25+
*
26+
* @param devices the devices to be stored in deallocator
27+
*/
28+
private WebcamDeallocator(WebcamDevice[] devices) {
29+
if (devices != null && devices.length > 0) {
30+
this.devices = devices;
31+
this.handler.listen("TERM", this);
32+
}
33+
}
34+
35+
/**
36+
* Store devices to be deallocated when TERM signal has been received.
37+
*
38+
* @param devices the devices array to be stored by deallocator
39+
*/
40+
protected static final void store(WebcamDevice[] devices) {
41+
new WebcamDeallocator(devices);
42+
}
43+
44+
@Override
45+
public void update(Observable observable, Object object) {
46+
for (WebcamDevice device : devices) {
47+
try {
48+
device.close();
49+
} catch (Throwable t) {
50+
caugh(t);
51+
}
52+
}
53+
}
54+
55+
public void caugh(Throwable e) {
56+
File f = new File(String.format("webcam-capture-hs-%s", System.currentTimeMillis()));
57+
PrintStream ps = null;
58+
try {
59+
e.printStackTrace(ps = new PrintStream(f));
60+
} catch (FileNotFoundException e2) {
61+
// ignore, stdout is not working, cannot do anything more
62+
} finally {
63+
if (ps != null) {
64+
ps.close();
65+
}
66+
}
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.github.sarxos.webcam;
2+
3+
import java.util.Observable;
4+
import java.util.Observer;
5+
6+
import sun.misc.Signal;
7+
import sun.misc.SignalHandler;
8+
9+
10+
/**
11+
* Primitive signal handler. This class is using undocumented classes from
12+
* sun.misc.* and therefore should be used with caution.
13+
*
14+
* @author Bartosz Firyn (SarXos)
15+
*/
16+
@SuppressWarnings("restriction")
17+
class WebcamSignalHandler extends Observable implements SignalHandler {
18+
19+
private SignalHandler handler = null;
20+
21+
public void listen(String signal, Observer observer) throws IllegalArgumentException {
22+
addObserver(observer);
23+
handler = Signal.handle(new Signal(signal), this);
24+
}
25+
26+
@Override
27+
public void handle(final sun.misc.Signal signal) {
28+
29+
// do nothing on "signal default" or "signal ignore"
30+
if (handler == SIG_DFL || handler == SIG_IGN) {
31+
return;
32+
}
33+
34+
setChanged();
35+
36+
try {
37+
notifyObservers(signal);
38+
} finally {
39+
handler.handle(signal);
40+
}
41+
}
42+
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class WebcamDefaultDevice implements WebcamDevice {
5050
* Artificial view sizes. I'm really not sure if will fit into other webcams
5151
* but hope that OpenIMAJ can handle this.
5252
*/
53-
//@formatter:off
53+
// @formatter:off
5454
private final static Dimension[] DIMENSIONS = new Dimension[] {
5555
SIZE_QQVGA,
5656
SIZE_QVGA,
@@ -59,7 +59,7 @@ public class WebcamDefaultDevice implements WebcamDevice {
5959
SIZE_VGA,
6060
SIZE_XGA,
6161
};
62-
//@formatter:on
62+
// @formatter:on
6363

6464
/**
6565
* RGB offsets.

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

+23-2
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,38 @@
33
import com.github.sarxos.webcam.ds.buildin.natives.OpenIMAJGrabber;
44

55

6+
/**
7+
* Abstract webcam processor class.
8+
*
9+
* @author Bartosz Firyn (SarXos)
10+
*/
611
public abstract class WebcamGrabberTask {
712

13+
/**
14+
* Native grabber.
15+
*/
816
protected volatile OpenIMAJGrabber grabber = null;
917

10-
protected void process(WebcamGrabberProcessor grabber) {
11-
grabber.process(this);
18+
/**
19+
* Process task by processor thread.
20+
*
21+
* @param processor the processor to be used to process this task
22+
*/
23+
protected void process(WebcamGrabberProcessor processor) {
24+
processor.process(this);
1225
}
1326

27+
/**
28+
* Set grabber connected with specific device.
29+
*
30+
* @param grabber the grabber to be set
31+
*/
1432
public void setGrabber(OpenIMAJGrabber grabber) {
1533
this.grabber = grabber;
1634
}
1735

36+
/**
37+
* Method to be called from inside of the processor thread.
38+
*/
1839
protected abstract void handle();
1940
}

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

+16
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,30 @@
44
import com.github.sarxos.webcam.ds.buildin.WebcamGrabberTask;
55

66

7+
/**
8+
* This task is to close grabber session.
9+
*
10+
* @author Bartosz Firyn (SarXos)
11+
*/
712
public class CloseSessionTask extends WebcamGrabberTask {
813

14+
/**
15+
* Grabber processor.
16+
*/
917
private WebcamGrabberProcessor processor = null;
1018

19+
/**
20+
* Create task closing session of grabber connected with specific device.
21+
*
22+
* @param processor
23+
*/
1124
public CloseSessionTask(WebcamGrabberProcessor processor) {
1225
this.processor = processor;
1326
}
1427

28+
/**
29+
* Method to be called from outside of the processor thread.
30+
*/
1531
public void closeSession() {
1632
process(processor);
1733
}

0 commit comments

Comments
 (0)