00001
00002
00003
00004
00005
package org.nees.rbnb;
00006
00007
import java.io.DataInputStream;
00008
import java.io.IOException;
00009
00010
import java.net.URL;
00011
import java.net.URLConnection;
00012
import java.net.MalformedURLException;
00013
00014
import com.rbnb.sapi.ChannelMap;
00015
import com.rbnb.sapi.Source;
00016
import com.rbnb.sapi.SAPIException;
00017
00018
import com.rbnb.utility.ArgHandler;
00019
00020
00032 public class AxisSource extends RBNBBase {
00033
00034
private final static String DEFAULT_RBNB_SOURCE_NANE =
"SourceName";
00035
private final static String DEFAULT_RBNB_SOURCE =
"AxisVideo";
00036
private final static String DEFAULT_RBNB_CHANNEL_NANE =
"ChannelName";
00037
private final static String DEFAULT_RBNB_CHANNEL =
"video.jpg";
00038
private final static String CAMERA_HOST_NAME =
"AxisCameraHost";
00039
private final static String CAMERA_HOST =
"undefined";
00040
00041
private final static long RETRY_INTERVAL = 1000;
00042
00043
private String cameraURLString;
00044
private String cameraHost = CAMERA_HOST;
00045
private String rbnbSourceName = DEFAULT_RBNB_SOURCE;
00046
private String rbnbChannelName = DEFAULT_RBNB_CHANNEL;
00047
00048
private final int requestedFPS = 30;
00049
00050
private static final String CACHE_SIZE_NAME =
"CacheSize";
00051
private static final int DEFAULT_CACHE_SIZE=30;
00052
00053
private int cacheSize = DEFAULT_CACHE_SIZE;
00054
00055 Source source = null;
00056 ChannelMap sMap;
00057
int index;
00058
boolean connected =
false;
00059
00060 Thread timerThread;
00061
boolean runit =
false;
00062
00063
private String[] parameterNameArray;
00064
private String[] parameterTypeArray;
00065
private Object[] parameterDefaultArray;
00066
00067
public static void main(String[] args) {
00068
00069
AxisSource a =
new AxisSource();
00070
if (a.
setArgs(args))
00071 {
00072 a.
connect();
00073 a.
startThread();
00074 }
00075 }
00076
00077
public void printUsage()
00078 {
00079 System.out.println(
"Usage for AxisSource...");
00080 super.printUsage();
00081 System.out.println(
"-A Axis camera host (required)");
00082 System.out.println(
"[-S RBNB Source Name *" + DEFAULT_RBNB_SOURCE +
"]");
00083 System.out.println(
"[-C RBNB Source Channel Name *" + DEFAULT_RBNB_CHANNEL +
"]");
00084 System.out.println(
"[-z cache size *" + DEFAULT_CACHE_SIZE +
"]");
00085 System.out.println();
00086 }
00087
00088
protected boolean setInstanceArgs(String[] args)
throws IllegalArgumentException
00089 {
00090
00091
try {
00092 ArgHandler ah=
new ArgHandler(args);
00093
if (ah.checkFlag(
'A')) {
00094 String a=ah.getOption(
'A');
00095
if (a!=null) cameraHost=a;
00096 }
00097
if (ah.checkFlag(
'S')) {
00098 String a=ah.getOption(
'S');
00099
if (a!=null) rbnbSourceName=a;
00100 }
00101
if (ah.checkFlag(
'C')) {
00102 String a=ah.getOption(
'C');
00103
if (a!=null) rbnbChannelName=a;
00104 }
00105
if (ah.checkFlag(
'z')) {
00106 String a=ah.getOption(
'z');
00107
if (a!=null)
00108
try
00109 {
00110 Integer i =
new Integer(a);
00111
int value = i.intValue();
00112 cacheSize = value;
00113 }
00114
catch (Exception ignore) {}
00115 }
00116 }
catch (Exception e) {
00117
throw new IllegalArgumentException(
"Argument Exception: " + e);
00118 }
00119
00120
if (cameraHost == null)
00121 {
00122 System.err.println(
"Axis Video Camera Host is required. Use AxisSource -h for help");
00123 printUsage();
00124
return false;
00125 }
00126
00127 cameraURLString =
"http://" + cameraHost +
"/axis-cgi/mjpg/video.cgi?camera=1&resolution=352x240&showlength=1&compression=25&clock=0&date=0&text=0&req_fps=30&deltatime=1";
00128
00129 System.out.println(
"Starting AxisSource with... \n"
00130 +
" camera URL = " + cameraURLString
00131 +
";\n RBNB Server = " + getServer()
00132 +
"; RBNB Source name = " + rbnbSourceName
00133 +
"; RBNB Channel name = " + rbnbChannelName
00134 +
"\nUse AxisSource -h to see optional arguments.");
00135
00136
return true;
00137 }
00138
00139
public AxisSource()
00140 {
00141 setParamterArrays();
00142 initialize();
00143 }
00144
00145
protected void setParamterArrays() {
00146
00147 String [] pNameArray = super.getBaseParameterNameArray();
00148 String [] pTypeArray = super.getBaseParameterTypeArray();
00149 Object [] pDefaultArray = super.getBaseParameterDefaultArray();
00150
00151
int base = pNameArray.length;
00152
int numberOfparameters = 4;
00153 parameterNameArray =
new String[base + numberOfparameters];
00154 parameterTypeArray =
new String[base + numberOfparameters];
00155 parameterDefaultArray =
new Object[base + numberOfparameters];
00156
00157
for (
int i = 0; i < base; i++)
00158 {
00159 parameterNameArray[i] = pNameArray[i];
00160 parameterTypeArray[i] = pTypeArray[i];
00161 parameterDefaultArray[i] = pDefaultArray[i];
00162 }
00163
00164 parameterNameArray[base + 0] = DEFAULT_RBNB_SOURCE_NANE;
00165 parameterTypeArray[base + 0] =
RBNBBaseParameterHolder.STRING_TYPE;
00166 parameterDefaultArray[base + 0] =
new String(DEFAULT_RBNB_SOURCE);
00167
00168 parameterNameArray[base + 1] = DEFAULT_RBNB_CHANNEL_NANE;
00169 parameterTypeArray[base + 1] =
RBNBBaseParameterHolder.STRING_TYPE;
00170 parameterDefaultArray[base + 1] =
new String(DEFAULT_RBNB_CHANNEL);
00171
00172 parameterNameArray[base + 2] = CAMERA_HOST_NAME;
00173 parameterTypeArray[base + 2] =
RBNBBaseParameterHolder.STRING_TYPE;
00174 parameterDefaultArray[base + 2] =
new String(CAMERA_HOST);
00175
00176 parameterNameArray[base + 3] = CACHE_SIZE_NAME;
00177 parameterTypeArray[base + 3] =
RBNBBaseParameterHolder.INTEGER_TYPE;
00178 parameterDefaultArray[base + 3] =
new Integer(DEFAULT_CACHE_SIZE);
00179
00180 }
00181
00182
00183
00184
00185 public void setVariablesFromParameters() {
00186 super.setBaseVarialbesFromParametes();
00187
00188 rbnbSourceName = DEFAULT_RBNB_SOURCE;
00189
try{
00190 Object obj = getValueWithDefault(DEFAULT_RBNB_SOURCE_NANE, DEFAULT_RBNB_SOURCE);
00191 rbnbSourceName = (String)obj;
00192 }
catch (Throwable ignore){}
00193
00194 rbnbChannelName = DEFAULT_RBNB_CHANNEL;
00195
try{
00196 Object obj = getValueWithDefault(DEFAULT_RBNB_CHANNEL_NANE, DEFAULT_RBNB_CHANNEL);
00197 rbnbChannelName = (String)obj;
00198 }
catch (Throwable ignore){}
00199
00200 cameraHost = CAMERA_HOST;
00201
try{
00202 Object obj = getValueWithDefault(CAMERA_HOST_NAME, CAMERA_HOST);
00203 cameraHost = (String)obj;
00204 }
catch (Throwable ignore){}
00205
00206 cacheSize = DEFAULT_CACHE_SIZE;
00207
try{
00208 Integer i =
new Integer(DEFAULT_CACHE_SIZE);
00209 Object obj = getValueWithDefault(CACHE_SIZE_NAME, i);
00210 cacheSize = ((Integer)obj).intValue();
00211 }
catch (Throwable ignore){}
00212
00213 }
00214
00215
public void connect()
00216 {
00217
if (connected)
return;
00218
try {
00219
00220 source=
new Source(cacheSize,
"none", 0);
00221 source.OpenRBNBConnection(getServer(),rbnbSourceName);
00222 connected =
true;
00223 System.out.println(
"Starting AxisSource with... \n"
00224 +
" camera URL = " + cameraURLString
00225 +
";\n RBNB Server = " + getServer()
00226 +
"; RBNB Source name = " + rbnbSourceName
00227 +
"; RBNB Channel name = " + rbnbChannelName
00228 +
"/nUse AxisSource -h to see optional arguments.");
00229 }
catch (SAPIException se) { se.printStackTrace(); }
00230 }
00231
00232
private void disconnect() {
00233 source.CloseRBNBConnection();
00234 connected =
false;
00235 source = null;
00236 }
00237
00238
public void startThread()
00239 {
00240
00241
if (!connected)
return;
00242
00243
00244 Runnable r =
new Runnable() {
00245
public void run() {
00246 runWork();
00247 }
00248 };
00249 runit =
true;
00250 timerThread =
new Thread(r,
"Timer");
00251 timerThread.start();
00252 System.out.println(
"WalkerSource: Started thread.");
00253 }
00254
00255
public void stopThread()
00256 {
00257
if (!connected)
return;
00258
00259 runit =
false;
00260 timerThread.interrupt();
00261 System.out.println(
"WalkerSource: Stopped thread.");
00262 }
00263
00264
public void runWork() {
00265
00266
boolean done =
false;
00267
while (!done) {
00268 done = !execute();
00269
try {Thread.sleep(RETRY_INTERVAL); }
catch (Exception e) {}
00270 }
00271
stop();
00272 }
00273
00274
private boolean execute()
00275 {
00276
if (!connected)
return false;
00277
00278 ChannelMap cmap =
new ChannelMap();
00279
int channelId = -1;
00280
try {
00281 channelId = cmap.Add(rbnbChannelName);
00282 }
catch (SAPIException e) {
00283 System.err.println(
"Failed to add video channel to channel map; name = "
00284 + rbnbChannelName);
00285 disconnect();
00286
return false;
00287 }
00288 cmap.PutTimeAuto(
"timeofday");
00289 cmap.PutMime(channelId,
"image/jpeg");
00290
00291 URL cameraURL = null;
00292
try {
00293 cameraURL =
new URL(cameraURLString);
00294 }
catch (MalformedURLException e) {
00295 System.err.println(
"URL is malformed; URL = " + cameraURLString);
00296 disconnect();
00297
return false;
00298 }
00299
00300 URLConnection cameraConnection = null;
00301
try {
00302 cameraConnection = cameraURL.openConnection();
00303 }
catch (IOException e) {
00304 System.err.println(
"Failed to connect to axis host with " + cameraURLString);
00305 disconnect();
00306
return false;
00307 }
00308
00309 DataInputStream dis = null;
00310
try {
00311 dis =
new DataInputStream(cameraConnection.getInputStream());
00312 }
catch (IOException e) {
00313 System.err.println(
"Failed to get data stream from axis host.");
00314 disconnect();
00315
return false;
00316 }
00317
00318 String delimiter =
"";
00319 String contentType =
"";
00320
int contentLength = 0;
00321
int deltaTime = 0;
00322 byte[] imageData;
00323
00324 StringBuffer inputLine =
new StringBuffer();
00325
int currImage = 0;
00326
boolean readingData =
false;
00327
boolean gotHeader =
false;
00328
00329
double lastTime = 0;
00330
double time = 0;
00331
double frameRate = 0;
00332
double averageFrameRate = requestedFPS;
00333
00334
boolean failed =
false;
00335
00336
while(currImage < 1000000) {
00337
00338
if (readingData) {
00339
00340
if (contentLength > 0) {
00341 imageData =
new byte[contentLength];
00342
try {
00343 dis.readFully(imageData);
00344 }
catch (IOException e) {
00345 System.err.println(
"Failed to read JPEG image data from data stream.");
00346 failed =
true;
00347
break;
00348 }
00349 }
else {
00350
int index = 0;
00351 imageData =
new byte[100000];
00352
00353
while (index < imageData.length) {
00354
if (index >= 4 && (
char)imageData[index-4] ==
'\r' && (
char)imageData[index-3] ==
'\n' && (
char)imageData[index-2] ==
'\r' && (
char)imageData[index-1] ==
'\n') {
00355 index = index - 4;
00356
break;
00357 }
00358
00359
try {
00360 imageData[index++] = dis.readByte();
00361 }
catch (IOException e) {
00362 System.err.println(
"Failed to read JPEG image data from data stream.");
00363 failed =
true;
00364
break;
00365 }
00366 }
00367
00368
if (failed)
break;
00369
00370
if (index == imageData.length) {
00371 System.err.println(
"Ran out of space in data buffer.");
00372
continue;
00373 }
00374
00375 }
00376
00377
if (currImage > 0) {
00378 frameRate = 1000/(
double)deltaTime;
00379 averageFrameRate = 0.995*averageFrameRate + 0.005*frameRate;
00380 }
00381
00382
try {
00383 cmap.PutDataAsByteArray(channelId, imageData);
00384 }
catch (SAPIException e) {
00385 System.err.println(
"Failed to put image data into channel map.");
00386 failed =
true;
00387
break;
00388 }
00389
00390
try {
00391 source.Flush(cmap,
true);
00392 }
catch (SAPIException e) {
00393 System.err.println(
"Failed to flush output data to server.");
00394 failed =
true;
00395
break;
00396 }
00397
00398
if (currImage % 30 == 0) System.out.print(((
long)(averageFrameRate*10))/((
double)10) +
" fps \r");
00399
00400 readingData =
false;
00401 gotHeader =
false;
00402
00403 delimiter =
"";
00404 contentType =
"";
00405 contentLength = 0;
00406 deltaTime = 0;
00407
00408 currImage++;
00409
00410 }
else {
00411
char c;
00412
try {
00413 c = (
char) dis.readByte();
00414 }
catch (IOException e) {
00415 System.err.println(
"Failed to read header data.");
00416 failed =
true;
00417
break;
00418 }
00419
00420
if (c ==
'\r') {
00421
try {
00422 dis.readByte();
00423 }
catch (IOException e) {
00424 System.err.println(
"Failed to read header data.");
00425 failed =
true;
00426
break;
00427 }
00428
00429
if (inputLine.toString().startsWith(
"--")) {
00430 delimiter = inputLine.substring(2);
00431 gotHeader =
true;
00432 }
else if (inputLine.toString().toLowerCase().startsWith(
"content-type")) {
00433 contentType = inputLine.substring(14);
00434 }
else if (inputLine.toString().toLowerCase().startsWith(
"content-length")) {
00435 contentLength = Integer.parseInt(inputLine.substring(16));
00436 }
else if (inputLine.toString().toLowerCase().startsWith(
"delta-time")) {
00437 deltaTime = Integer.parseInt(inputLine.substring(12));
00438 }
else if (gotHeader && inputLine.toString().trim().length() == 0) {
00439 readingData =
true;
00440 }
else if (inputLine.toString().trim().length() != 0){
00441 System.out.println(
"Received unexpected data.");
00442 }
00443
00444 inputLine =
new StringBuffer();
00445 }
else {
00446 inputLine.append(c);
00447 }
00448 }
00449 }
00450
00451
try {
00452 dis.close();
00453 }
catch (IOException e) {
00454 System.err.println(
"Failed to close connect to axis host.");
00455 }
00456
00457
return !failed;
00458 }
00459
00460 public boolean isRunning()
00461 {
00462
return (connected && runit);
00463 }
00464
00465
00466
00467
00468 public String[]
getParameterNameArray() {
00469
return parameterNameArray;
00470 }
00471
00472
00473
00474
00475 public String[]
getParameterTypeArray() {
00476
return parameterTypeArray;
00477 }
00478
00479
00480
00481
00482 public Object[]
getParameterDefaultArray() {
00483
return parameterDefaultArray;
00484 }
00485
00486
00487
00488
00489 public boolean start() {
00490
if (
isRunning())
return false;
00491
if (connected) disconnect();
00492
setVariablesFromParameters();
00493 connect();
00494
if (!connected)
return false;
00495 startThread();
00496
return true;
00497 }
00498
00499
00500
00501
00502 public boolean stop() {
00503
if (!
isRunning())
return false;
00504 stopThread();
00505 disconnect();
00506
return true;
00507 }
00508
00509 }
00510