Skip to content

Commit

Permalink
Add listener event for image obtained, fixes #64, fixes #46
Browse files Browse the repository at this point in the history
  • Loading branch information
sarxos committed Mar 17, 2013
1 parent 3260243 commit 0ca8419
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 13 deletions.
Expand Up @@ -77,6 +77,10 @@ public void webcamDisposed(WebcamEvent we) {
System.out.println("webcam disposed");
}

@Override
public void webcamImageObtained(WebcamEvent we) {
}

@Override
public void windowActivated(WindowEvent e) {
}
Expand Down
Expand Up @@ -72,6 +72,11 @@ public void webcamDisposed(WebcamEvent we) {
System.out.println("webcam disposed");
}

@Override
public void webcamImageObtained(WebcamEvent we) {
// do nothing
}

@Override
public void windowActivated(WindowEvent e) {
}
Expand Down
21 changes: 17 additions & 4 deletions webcam-capture/src/main/java/com/github/sarxos/webcam/Webcam.java
Expand Up @@ -115,7 +115,7 @@ public class Webcam {
/**
* Webcam image updater.
*/
private WebcamUpdater updater = null;
private WebcamUpdater updater = new WebcamUpdater(this);

/**
* Webcam class.
Expand Down Expand Up @@ -184,9 +184,6 @@ public boolean open(boolean async) {
asynchronous = async;

if (async) {
if (updater == null) {
updater = new WebcamUpdater(this);
}
updater.start();
}

Expand Down Expand Up @@ -398,10 +395,19 @@ public BufferedImage getImage() {
return updater.getImage();
} else {

// get image

long time = System.currentTimeMillis();
BufferedImage image = new WebcamReadImageTask(driver, device).getImage();

// calculate FPS

fps = (4 * fps + 1000 / (double) (System.currentTimeMillis() - time)) / 5;

// notify webcam listeners about new image available

updater.notifyWebcamImageAcquired(this, image);

return image;
}
}
Expand Down Expand Up @@ -621,6 +627,13 @@ public WebcamListener[] getWebcamListeners() {
return listeners.toArray(new WebcamListener[listeners.size()]);
}

/**
* @return Number of webcam listeners
*/
public int getWebcamListenersCount() {
return listeners.size();
}

/**
* Removes webcam listener.
*
Expand Down
@@ -1,5 +1,6 @@
package com.github.sarxos.webcam;

import java.awt.image.BufferedImage;
import java.util.EventObject;


Expand All @@ -10,20 +11,46 @@
*/
public class WebcamEvent extends EventObject {

private static final long serialVersionUID = 7701762815832038598L;
private static final long serialVersionUID = 1L;

/**
* Image acquired from webcam
*/
private BufferedImage image = null;

/**
* Webcam event.
*
* @param w - webcam object
* @param w the webcam object
*/
public WebcamEvent(Webcam w) {
this(w, null);
}

/**
* Webcam event.
*
* @param w the webcam object
* @param image the image acquired from webcam
*/
public WebcamEvent(Webcam w, BufferedImage image) {
super(w);
this.image = image;
}

@Override
public Webcam getSource() {
return (Webcam) super.getSource();
}

/**
* Return image acquired by webcam. This method will return not-null object
* <b>only</b> in case new image acquisition event. For all other events, it
* will simply return null.
*
* @return Acquired image
*/
public BufferedImage getImage() {
return image;
}
}
Expand Up @@ -12,19 +12,26 @@ public interface WebcamListener {
*
* @param we a webcam event
*/
public void webcamOpen(WebcamEvent we);
void webcamOpen(WebcamEvent we);

/**
* Webcam has been closed
*
* @param we a webcam event
*/
public void webcamClosed(WebcamEvent we);
void webcamClosed(WebcamEvent we);

/**
* Webcam has been disposed
*
* @param we a webcam event
*/
public void webcamDisposed(WebcamEvent we);
void webcamDisposed(WebcamEvent we);

/**
* Webcam image has been obtained.
*
* @param we a webcam event
*/
void webcamImageObtained(WebcamEvent we);
}
Expand Up @@ -179,7 +179,7 @@ private class Repainter extends Thread {

public Repainter() {
setDaemon(true);
setName(String.format("%s-repainter", webcam.getName()));
setName(String.format("repainter-%s", webcam.getName()));
}

@Override
Expand Down Expand Up @@ -416,6 +416,11 @@ public void webcamDisposed(WebcamEvent we) {
webcamClosed(we);
}

@Override
public void webcamImageObtained(WebcamEvent we) {
// do nothing
}

/**
* Open webcam and start rendering.
*/
Expand Down
Expand Up @@ -258,17 +258,21 @@ public void webcamOpen(WebcamEvent we) {

@Override
public void webcamClosed(WebcamEvent we) {
// TODO: shutdown executor?
}

@Override
public void webcamDisposed(WebcamEvent we) {
}

@Override
public void webcamImageObtained(WebcamEvent we) {
}

public static void main(String[] args) throws InterruptedException {
new WebcamStreamer(8081, Webcam.getDefault(), 0.5, true);
do {
Thread.sleep(1000);
} while (true);
}

}
@@ -1,9 +1,12 @@
package com.github.sarxos.webcam;

import java.awt.image.BufferedImage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import org.slf4j.Logger;
Expand All @@ -19,13 +22,62 @@
*
* @author Bartosz Firyn (sarxos)
*/
public class WebcamUpdater implements Runnable {
public class WebcamUpdater implements Runnable, ThreadFactory {

/**
* Class used to asynchronously notify all webcam listeners about new image
* available.
*
* @author Bartosz Firyn (sarxos)
*/
private static class ImageNotification implements Runnable {

/**
* Camera.
*/
private final Webcam webcam;

/**
* Acquired image.
*/
private final BufferedImage image;

/**
* Create new notification.
*
* @param webcam the webcam from which image has been acquired
* @param image the acquired image
*/
public ImageNotification(Webcam webcam, BufferedImage image) {
this.webcam = webcam;
this.image = image;
}

@Override
public void run() {
if (image != null) {
WebcamEvent we = new WebcamEvent(webcam, image);
for (WebcamListener l : webcam.getWebcamListeners()) {
try {
l.webcamImageObtained(we);
} catch (Exception e) {
LOG.error(String.format("Notify image acquired, exception when calling listener %s", l.getClass()), e);
}
}
}
}
}

/**
* Logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(WebcamUpdater.class);

/**
* Used to count thread in the executor pool.
*/
private static final AtomicInteger number = new AtomicInteger(0);

/**
* Target FPS.
*/
Expand All @@ -34,7 +86,12 @@ public class WebcamUpdater implements Runnable {
/**
* Executor service.
*/
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();;
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(this);

/**
* Executor service for image notifications.
*/
private final ExecutorService notificator = Executors.newSingleThreadExecutor(this);

/**
* Cached image.
Expand Down Expand Up @@ -106,7 +163,28 @@ public void run() {

fps = (4 * fps + 1000 / (double) time) / 5;

// reschedule task

executor.schedule(this, delay, TimeUnit.MILLISECONDS);

// notify webcam listeners about the new image available

notifyWebcamImageAcquired(webcam, image.get());
}

/**
* Asynchronously start new thread which will notify all webcam listeners
* about the new image available.
*/
protected void notifyWebcamImageAcquired(Webcam webcam, BufferedImage image) {

// notify webcam listeners of new image available, do that only if there
// are any webcam listeners available because there is no sense to start
// additional threads for no purpose

if (webcam.getWebcamListenersCount() > 0) {
notificator.execute(new ImageNotification(webcam, image));
}
}

/**
Expand Down Expand Up @@ -153,4 +231,11 @@ public BufferedImage getImage() {
public double getFPS() {
return fps;
}

@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, String.format("webcam-updater-thread-%d", number.incrementAndGet()));
t.setDaemon(true);
return t;
}
}

0 comments on commit 0ca8419

Please sign in to comment.