org.bytedeco.javacv.IPCameraFrameGrabber Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javacv Show documentation
Show all versions of javacv Show documentation
Java interface to OpenCV and more
/*
* Copyright (C) 2013 Greg Perry
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE.txt file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bytedeco.javacv;
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.Loader;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.TimeUnit;
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_imgcodecs.*;
public class IPCameraFrameGrabber extends FrameGrabber {
/*
* excellent reference - http://www.jpegcameras.com/ foscam url
* http://host/videostream.cgi?user=username&pwd=password
* http://192.168.0.59:60/videostream.cgi?user=admin&pwd=password android ip
* cam http://192.168.0.57:8080/videofeed
*/
private static Exception loadingException = null;
public static void tryLoad() throws Exception {
if (loadingException != null) {
throw loadingException;
} else {
try {
Loader.load(org.bytedeco.javacpp.opencv_highgui.class);
} catch (Throwable t) {
throw loadingException = new Exception("Failed to load " + IPCameraFrameGrabber.class, t);
}
}
}
private final FrameConverter converter = new OpenCVFrameConverter.ToIplImage();
private final URL url;
private final int connectionTimeout;
private final int readTimeout;
private DataInputStream input;
private byte[] pixelBuffer = new byte[1024];
private Mat decoded = null;
/**
* @param url The URL to create the camera connection with.
* @param startTimeout How long should this wait on the connection while trying to {@link #start()} before
* timing out.
* If this value is less than zero it will be ignored.
* {@link URLConnection#setConnectTimeout(int)}
* @param grabTimeout How long should grab wait while reading the connection before timing out.
* If this value is less than zero it will be ignored.
* {@link URLConnection#setReadTimeout(int)}
* @param timeUnit The time unit to use for the connection and read timeout.
* If this value is null then the start timeout and grab timeout will be ignored.
*/
public IPCameraFrameGrabber(URL url, int startTimeout, int grabTimeout, TimeUnit timeUnit) {
super(); // Always good practice to do this
if (url == null) {
throw new IllegalArgumentException("URL can not be null");
}
this.url = url;
if (timeUnit != null) {
this.connectionTimeout = toIntExact(TimeUnit.MILLISECONDS.convert(startTimeout, timeUnit));
this.readTimeout = toIntExact(TimeUnit.MILLISECONDS.convert(grabTimeout, timeUnit));
} else {
this.connectionTimeout = -1;
this.readTimeout = -1;
}
}
public IPCameraFrameGrabber(String urlstr, int connectionTimeout, int readTimeout, TimeUnit timeUnit) throws MalformedURLException {
this(new URL(urlstr), connectionTimeout, readTimeout, timeUnit);
}
/**
* @param urlstr A string to be used to create the URL.
* @throws MalformedURLException if the urlstr is a malformed URL
* @deprecated By not setting the connection timeout and the read timeout if your network ever crashes
* then {@link #start()} or {@link #grab()} can hang for upwards of 45 to 60 seconds before failing.
* You should always explicitly set the connectionTimeout and readTimeout so that your application can
* respond appropriately to a loss or failure to connect.
*/
@Deprecated
public IPCameraFrameGrabber(String urlstr) throws MalformedURLException {
this(new URL(urlstr), -1, -1, null);
}
@Override
public void start() throws Exception {
try {
/*
* We don't need to keep a reference to the connection
* after it is opened in the parent class.
* It never uses it outside of start.
*/
final URLConnection connection = url.openConnection();
// If the class was initialized with timeout values then configure those
if (connectionTimeout >= 0) {
connection.setConnectTimeout(connectionTimeout);
}
if (readTimeout >= 0) {
connection.setReadTimeout(readTimeout);
}
input = new DataInputStream(connection.getInputStream());
} catch (IOException e) {
throw new Exception(e.getMessage(), e);
}
}
@Override
public void stop() throws Exception {
if (input != null) {
try {
input.close();
} catch (IOException e) {
throw new Exception(e.getMessage(), e);
} finally {
// Close may have failed but there's really nothing we can do about it at this point
input = null;
// Don't set the url to null, it may be needed to restart this object
releaseDecoded();
}
}
}
@Override
public void trigger() throws Exception {
}
@Override
public Frame grab() throws Exception {
try {
final byte[] b = readImage();
final Mat mat = new Mat(1, b.length, CV_8UC1, new BytePointer(b));
releaseDecoded();
return converter.convert(decoded = imdecode(mat, IMREAD_COLOR));
} catch (IOException e) {
throw new Exception(e.getMessage(), e);
}
}
public BufferedImage grabBufferedImage() throws IOException {
BufferedImage bi = ImageIO.read(new ByteArrayInputStream(readImage()));
return bi;
}
/**
* Ensures that if the decoded image is not null that it gets released and set to null.
* If the image was not set to null then trying to release a null pointer will cause a
* segfault.
*/
private void releaseDecoded() {
if (decoded != null) {
decoded.release();
decoded = null;
}
}
private byte[] readImage() throws IOException {
final StringBuffer sb = new StringBuffer();
int c;
// read http subheader
while ((c = input.read()) != -1) {
if (c > 0) {
sb.append((char) c);
if (c == 13) {
sb.append((char) input.read());// '10'+
c = input.read();
sb.append((char) c);
if (c == 13) {
sb.append((char) input.read());// '10'
break; // done with subheader
}
}
}
}
// find embedded jpeg in stream
/*
* Some cameras return headers 'content-length' using different casing
* Eg. Axis cameras return 'Content-Length:' while TrendNet cameras return 'content-length:'
*/
final String subheader = sb.toString().toLowerCase();
//log.debug(subheader);
// Yay! - server was nice and sent content length
int c0 = subheader.indexOf("content-length: ");
final int c1 = subheader.indexOf('\r', c0);
if (c0 < 0) {
//log.info("no content length returning null");
throw new EOFException("The camera stream ended unexpectedly");
}
c0 += 16;
final int contentLength = Integer.parseInt(subheader.substring(c0, c1).trim());
//log.debug("Content-Length: " + contentLength);
// adaptive size - careful - don't want a 2G jpeg
ensureBufferCapacity(contentLength);
input.readFully(pixelBuffer, 0, contentLength);
input.read();// \r
input.read();// \n
input.read();// \r
input.read();// \n
return pixelBuffer;
}
@Override
public void release() throws Exception {
}
/**
* Grow the pixel buffer if necessary. Using this method instead of allocating a new buffer every time a frame
* is grabbed improves performance by reducing the frequency of garbage collections. In a simple test, the
* original version of IPCameraFrameGrabber that allocated a 4096 element byte array for every read
* caused about 200MB of allocations within 13 seconds. In this version, almost no additional heap space
* is typically allocated per frame.
*/
private void ensureBufferCapacity(int desiredCapacity) {
int capacity = pixelBuffer.length;
while (capacity < desiredCapacity) {
capacity *= 2;
}
if (capacity > pixelBuffer.length) {
pixelBuffer = new byte[capacity];
}
}
/**
* Returns the value of the {@code long} argument;
* throwing an exception if the value overflows an {@code int}.
*
* @param value the long value
* @return the argument as an int
* @throws ArithmeticException if the {@code argument} overflows an int
* @see Java 8 Implementation
*/
private static int toIntExact(long value) {
if ((int) value != value) {
throw new ArithmeticException("integer overflow");
}
return (int) value;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy