/**
* Copyright 2014 Comcast Cable Communications Management, LLC
*
* This file is part of CATS.
*
* CATS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CATS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CATS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.comcast.cats.image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class dealing with stream recording.
*/
public class AxisServerStream {
private static final String IMAGE_FORMAT = "JPG";
private static final String IMAGE_URL = "image.cgi";
private final Logger log = LoggerFactory.getLogger(AxisServerStream.class);
/**
* Axis Server URL.
*/
private URL url;
/**
* Object that transform an InputStream into a BufferedImage
*/
private ImageReader imageReader;
/**
* URL connection.
*/
private HttpURLConnection httpConnection;
/**
* Image stream handle.
*/
private ImageInputStream iis;
/**
* Connection check.
*/
private boolean isConnected;
/**
* Connection timeout for url connection
*/
private int connectionTimeOut = 0;
/**
* Whether the URL provided is image URL or video url
*/
private boolean isImageUrl = false;
/**
* Constructs a stream recorder object.
* @param url The string url representation.
* @throws MalformedURLException on invalid url syntax.
*/
public AxisServerStream(final String url) throws MalformedURLException {
this(new URL(url));
}
/**
* Constructs a stream recorder object.
* @param url The url object representation.
*/
public AxisServerStream(final URL url) {
if (null == url) {
throw new IllegalArgumentException("url cannot be null");
}
this.url = url;
ImageIO.setUseCache(false);
if(url.toExternalForm().toLowerCase().contains(IMAGE_URL)){
isImageUrl = true;
}
}
/**
* Constructs a stream recorder object with Connection timeout set.
* @param url The url object representation.
* @param connectionTimeOut The connection timeout in milliseconds.
*/
public AxisServerStream(final URL url, int connectionTimeOut) {
if (null == url) {
throw new IllegalArgumentException("url cannot be null");
}
this.url = url;
this.connectionTimeOut = connectionTimeOut;
ImageIO.setUseCache(false);
}
public AxisServerStream(final String url, int connectionTimeOut) throws MalformedURLException {
this(new URL(url), connectionTimeOut);
}
/**
* Establishes the http connection.
* @return True if the connection was successful, false otherwise.
*/
public synchronized boolean connect() {
if (!isConnected) {
imageReader = (ImageReader) ImageIO.getImageReadersByFormatName(IMAGE_FORMAT).next();
try {
httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setConnectTimeout(connectionTimeOut);
iis = ImageIO.createImageInputStream(httpConnection.getInputStream());
isConnected = HttpURLConnection.HTTP_OK == httpConnection.getResponseCode();
} catch (IOException ioe) {
log.error("IOException caught trying to make connection: " + ioe.getMessage());
disconnect();
return false;
}
}
return true;
}
/**
* Verifies if connection already exists.
* @return True if connection was established, false otherwise.
*/
public synchronized boolean isConnected() {
return isConnected;
}
/**
* Closes the connection and any related streams.
*/
public synchronized void disconnect() {
isConnected = false;
if (null != imageReader) {
imageReader.abort();
imageReader.dispose();
}
if (null != httpConnection) {
httpConnection.disconnect();
}
try {
if (null != iis) {
iis.close();
}
} catch (IOException ioe) {
log.error("IOException caught trying to close imageInputStream: " + ioe.getMessage());
}
imageReader = null;
httpConnection = null;
iis = null;
}
/**
* Get the url related to this stream.
* @return The streams URL.
*/
public URL getUrl() {
return url;
}
/**
* Captures a JPG from the connection.
* @return BufferedImage from the stream. null if not connected.
*/
public synchronized BufferedImage getNextImage() {
BufferedImage image = null;
if (isConnected()) {
imageReader.setInput(iis, true);
try {
//Do the http header stripping only if the URL is video URL
if (!isImageUrl){
boolean jpegFound = false;
boolean contentTypeFound = false;
String line;
do {
line = iis.readLine();
if (line.indexOf("Content-") > -1) {
contentTypeFound = true;
} else if (contentTypeFound && (line.length() == 0)) {
jpegFound = true;
}
} while (!jpegFound);
}
image = imageReader.read(0);
} catch (Exception e) {
log.error("Error occured while trying to read image: " + e.getMessage() + ". Disconnecting.");
disconnect();
}
} else {
log.debug("axis server stream connection: " + isConnected());
}
return image;
}
}