diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/.classpath b/webcam-capture-drivers/webcam-capture-driver-ipcam/.classpath index e147e777..7690b17d 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/.classpath +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/.classpath @@ -1,32 +1,11 @@ - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - + + + diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/pom.xml b/webcam-capture-drivers/webcam-capture-driver-ipcam/pom.xml index 01b2e58e..5a288eb8 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/pom.xml +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/pom.xml @@ -77,12 +77,17 @@ org.apache.httpcomponents httpclient - 4.2.2 + 4.2.3 org.apache.httpcomponents httpmime - 4.2.2 + 4.2.3 + + + ch.qos.logback + logback-classic + 1.0.9 diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/com/github/sarxos/webcam/ds/ipcam/JpegExample.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/com/github/sarxos/webcam/ds/ipcam/JpegExample.java index a7689708..ea160ac7 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/com/github/sarxos/webcam/ds/ipcam/JpegExample.java +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/java/com/github/sarxos/webcam/ds/ipcam/JpegExample.java @@ -1,8 +1,12 @@ package com.github.sarxos.webcam.ds.ipcam; +import java.awt.Dimension; +import java.awt.GridLayout; import java.net.MalformedURLException; -import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import javax.swing.BorderFactory; import javax.swing.JFrame; import com.github.sarxos.webcam.Webcam; @@ -17,23 +21,28 @@ public static void main(String[] args) throws MalformedURLException { // available to be viewed online. Here in this example we are creating // IP camera device working in PULL mode to request static JPEG images. - String address = "http://www.dasding.de/ext/webcam/webcam770.php?cam=1"; - IpCamDevice livecam = new IpCamDevice("dasding", new URL(address), IpCamMode.PULL); + JFrame f = new JFrame("Dasding Studio Live IP Cameras"); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + f.setLayout(new GridLayout(0, 3, 1, 1)); + + List panels = new ArrayList(); - IpCamDriver driver = new IpCamDriver(); - driver.register(livecam); + for (Webcam webcam : Webcam.getWebcams()) { - Webcam.setDriver(driver); + WebcamPanel panel = new WebcamPanel(webcam, new Dimension(256, 144), false); + panel.setFillArea(true); + panel.setFPS(0.2); // 0.2 FPS = 1 frame per 5 seconds + panel.setBorder(BorderFactory.createEmptyBorder()); - WebcamPanel panel = new WebcamPanel(Webcam.getDefault()); - panel.setFPS(0.2); // 1 frame per 5 seconds + f.add(panel); + panels.add(panel); + } - JFrame f = new JFrame("Dasding Studio Live IP Camera"); - f.add(panel); f.pack(); f.setVisible(true); - f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + for (WebcamPanel panel : panels) { + panel.start(); + } } - } diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/resources/cameras.xml b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/resources/cameras.xml new file mode 100644 index 00000000..46258ec0 --- /dev/null +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/examples/resources/cameras.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDevice.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDevice.java index ba8b96ba..6000d172 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDevice.java +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDevice.java @@ -245,14 +245,21 @@ public Dimension[] getSizes() { open(); } - BufferedImage img = getImage(); - int w = img.getWidth(); - int h = img.getHeight(); - - sizes = new Dimension[] { new Dimension(w, h) }; + int attempts = 0; + do { + BufferedImage img = getImage(); + if (img != null) { + sizes = new Dimension[] { new Dimension(img.getWidth(), img.getHeight()) }; + break; + } + } while (attempts++ < 5); close(); + if (sizes == null) { + throw new WebcamException("Cannot get initial image from IP camera device " + getName()); + } + return sizes; } diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDeviceRegistry.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDeviceRegistry.java index 344c9674..248028c6 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDeviceRegistry.java +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDeviceRegistry.java @@ -2,9 +2,8 @@ import java.net.URL; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Collections; import java.util.List; -import java.util.Set; import com.github.sarxos.webcam.WebcamDevice; import com.github.sarxos.webcam.WebcamException; @@ -20,7 +19,7 @@ public class IpCamDeviceRegistry { /** * Contains IP cameras. */ - private static final Set DEVICES = new HashSet(); + private static final List DEVICES = new ArrayList(); /** * Register IP camera. @@ -41,6 +40,10 @@ public static void register(String name, URL url, IpCamMode mode) { register(new IpCamDevice(name, url, mode)); } + public static void register(String name, URL url, IpCamMode mode, IpCamAuth auth) { + register(new IpCamDevice(name, url, mode, auth)); + } + public static boolean isRegistered(IpCamDevice ipcam) { for (IpCamDevice d : DEVICES) { if (d.getName().equals(ipcam.getName())) { @@ -83,6 +86,6 @@ public static void unregister(IpCamDevice ipcam) { * @return Collection of registered IP cameras */ public static List getIpCameras() { - return new ArrayList(DEVICES); + return Collections.unmodifiableList(DEVICES); } } diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDriver.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDriver.java index 7e438419..8ca04452 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDriver.java +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamDriver.java @@ -14,6 +14,16 @@ */ public class IpCamDriver implements WebcamDriver { + public IpCamDriver() { + this(null); + } + + public IpCamDriver(IpCamStorage storage) { + if (storage != null) { + storage.open(); + } + } + @Override public List getDevices() { return Collections.unmodifiableList((List) IpCamDeviceRegistry.getIpCameras()); diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamMode.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamMode.java index 101eb428..bbd4a9c2 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamMode.java +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamMode.java @@ -1,20 +1,27 @@ package com.github.sarxos.webcam.ds.ipcam; +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlEnumValue; + + /** * How to obtain new images from IP cameras. * * @author Bartosz Firyn (SarXos) */ +@XmlEnum public enum IpCamMode { /** * Device will pull image from IP camera. */ + @XmlEnumValue("pull") PULL, /** * IP camera HTTP server will push new image to the device. */ + @XmlEnumValue("pull") PUSH, } diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamStorage.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamStorage.java new file mode 100644 index 00000000..838b96e7 --- /dev/null +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/IpCamStorage.java @@ -0,0 +1,73 @@ +package com.github.sarxos.webcam.ds.ipcam; + +import java.io.File; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import com.github.sarxos.webcam.WebcamException; +import com.github.sarxos.webcam.ds.ipcam.impl.IpCamDescriptor; + + +@XmlRootElement(name = "storage") +@XmlAccessorType(XmlAccessType.FIELD) +public class IpCamStorage { + + private static final Class[] CLASSES = new Class[] { + IpCamStorage.class, + IpCamDescriptor.class, + }; + + private static final JAXBContext CTX; + static { + JAXBContext c = null; + try { + c = JAXBContext.newInstance(CLASSES); + } catch (JAXBException e) { + throw new RuntimeException(e); + } finally { + CTX = c; + } + } + + @XmlElement(name = "ipcam") + private List descriptors = null; + + private transient File file = null; + + protected IpCamStorage() { + } + + public IpCamStorage(String file) { + this(new File(file)); + } + + public IpCamStorage(File file) { + this.file = file; + } + + protected List getDescriptors() { + return descriptors; + } + + public void open() { + + IpCamStorage storage = null; + try { + Unmarshaller unmarshaller = CTX.createUnmarshaller(); + storage = (IpCamStorage) unmarshaller.unmarshal(file); + } catch (JAXBException e) { + throw new WebcamException(e); + } + + for (IpCamDescriptor d : storage.getDescriptors()) { + IpCamDeviceRegistry.register(d.getName(), d.getURL(), d.getMode(), d.getAuth()); + } + } +} diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/impl/IpCamDescriptor.java b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/impl/IpCamDescriptor.java new file mode 100644 index 00000000..442535a7 --- /dev/null +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/main/java/com/github/sarxos/webcam/ds/ipcam/impl/IpCamDescriptor.java @@ -0,0 +1,78 @@ +package com.github.sarxos.webcam.ds.ipcam.impl; + +import java.net.MalformedURLException; +import java.net.URL; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; + +import com.github.sarxos.webcam.WebcamException; +import com.github.sarxos.webcam.ds.ipcam.IpCamAuth; +import com.github.sarxos.webcam.ds.ipcam.IpCamMode; + + +@XmlAccessorType(XmlAccessType.FIELD) +public class IpCamDescriptor { + + @XmlAccessorType(XmlAccessType.FIELD) + protected static class AuthParams { + + @XmlAttribute + private String user = null; + + @XmlAttribute + private String password = null; + + public String getUser() { + return user; + } + + public String getPassword() { + return password; + } + } + + @XmlAttribute + private String name = null; + + @XmlAttribute(name = "url") + private String urlString = null; + + private transient URL url = null; + + @XmlAttribute + private IpCamMode mode = IpCamMode.PULL; + + @XmlElement(name = "auth") + private AuthParams authParams = null; + + private transient IpCamAuth auth = null; + + public String getName() { + return name; + } + + public URL getURL() { + if (urlString != null && url == null) { + try { + url = new URL(urlString); + } catch (MalformedURLException e) { + throw new WebcamException(e); + } + } + return url; + } + + public IpCamMode getMode() { + return mode; + } + + public IpCamAuth getAuth() { + if (authParams != null && auth == null) { + auth = new IpCamAuth(authParams.getUser(), authParams.getPassword()); + } + return auth; + } +} diff --git a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/test/resources/logback.xml b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/test/resources/logback.xml index 8bae4eb7..dea70d74 100644 --- a/webcam-capture-drivers/webcam-capture-driver-ipcam/src/test/resources/logback.xml +++ b/webcam-capture-drivers/webcam-capture-driver-ipcam/src/test/resources/logback.xml @@ -11,7 +11,6 @@ - diff --git a/webcam-capture/pom.xml b/webcam-capture/pom.xml index 4729be64..3cdbe799 100644 --- a/webcam-capture/pom.xml +++ b/webcam-capture/pom.xml @@ -87,13 +87,13 @@ ch.qos.logback logback-classic - 1.0.7 + 1.0.9 provided junit junit - 4.10 + 4.11 test 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 f8a64dc0..60b4eb2c 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 @@ -48,7 +48,7 @@ public ShutdownHook(Webcam webcam) { @Override public void run() { - LOG.info("Automatic resource deallocation"); + LOG.info("Automatic {} deallocation", webcam.getName()); super.run(); webcam.dispose(); webcam.close0(); 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 040c10d7..e54a1c08 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 @@ -1,7 +1,9 @@ package com.github.sarxos.webcam; +import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; @@ -105,6 +107,25 @@ public void paintPanel(WebcamPanel owner, Graphics2D g2) { @Override public void paintImage(WebcamPanel owner, BufferedImage image, Graphics2D g2) { + + int w = getWidth(); + int h = getHeight(); + + if (fillArea && image.getWidth() != w && image.getHeight() != h) { + + BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D gr = resized.createGraphics(); + gr.setComposite(AlphaComposite.Src); + gr.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + gr.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gr.drawImage(image, 0, 0, w, h, null); + gr.dispose(); + resized.flush(); + + image = resized; + } + g2.drawImage(image, 0, 0, null); } } @@ -158,15 +179,26 @@ public void run() { while (webcam.isOpen()) { - image = webcam.getImage(); - if (image == null) { - LOG.error("Image is null"); - } + BufferedImage tmp = webcam.getImage(); try { - if (paused) { - synchronized (this) { - this.wait(); + + if (tmp == null) { + + if (webcam.isOpen()) { + break; + } + + LOG.error("Image is null"); + + } else { + + image = tmp; + + if (paused) { + synchronized (this) { + this.wait(); + } } } @@ -181,6 +213,8 @@ public void run() { } } + private boolean fillArea = false; + /** * Painting frequency. */ @@ -242,6 +276,22 @@ public WebcamPanel(Webcam webcam) { * @param start true if webcam shall be automatically started */ public WebcamPanel(Webcam webcam, boolean start) { + this(webcam, null, start); + } + +/** + * Creates new webcam panel which display image from camera in you your + * Swing application. If panel size argument is null, then image size will + * be used. If you would like to fill panel area with image even if its size + * is different, then you can use {@link #setFillArea(boolean)) method to + * configure this. + * + * @param webcam the webcam to be used to fetch images + * @param size the size of panel + * @param start true if webcam shall be automatically started + * @see WebcamPanel#setFillArea(boolean) + */ + public WebcamPanel(Webcam webcam, Dimension size, boolean start) { if (webcam == null) { throw new IllegalArgumentException(String.format("Webcam argument in %s constructor cannot be null!", getClass().getSimpleName())); @@ -252,7 +302,11 @@ public WebcamPanel(Webcam webcam, boolean start) { repainter.setName(String.format("%s-repainter", webcam.getName())); - setPreferredSize(webcam.getViewSize()); + if (size == null) { + setPreferredSize(webcam.getViewSize()); + } else { + setPreferredSize(size); + } if (start) { if (!webcam.isOpen()) { @@ -399,4 +453,25 @@ public void setFPS(double frequency) { public boolean isStarting() { return starting; } + + /** + * Image will be resized to fill panel area if true. If false then image + * will be rendered as it was obtained from webcam instance. + * + * @param fillArea shall image be resided to fill panel area + */ + public void setFillArea(boolean fillArea) { + this.fillArea = fillArea; + } + + /** + * Get value of fill area setting. Image will be resized to fill panel area + * if true. If false then image will be rendered as it was obtained from + * webcam instance. + * + * @return True if image is being resized, false otherwise + */ + public boolean isFillArea() { + return fillArea; + } } \ No newline at end of file