00001
package org.nees.rbnb;
00002
00003
import java.awt.geom.AffineTransform;
00004
import java.awt.image.AffineTransformOp;
00005
import java.awt.image.BufferedImage;
00006
import java.io.ByteArrayInputStream;
00007
import java.io.ByteArrayOutputStream;
00008
import java.io.IOException;
00009
00010
import java.util.Date;
00011
import java.util.TimeZone;
00012
import java.text.SimpleDateFormat;
00013
00014
import com.rbnb.sapi.ChannelMap;
00015
import com.rbnb.sapi.SAPIException;
00016
import com.rbnb.sapi.Sink;
00017
import com.rbnb.sapi.Source;
00018
00019
import com.sun.image.codec.jpeg.JPEGCodec;
00020
import com.sun.image.codec.jpeg.JPEGEncodeParam;
00021
import com.sun.image.codec.jpeg.JPEGImageDecoder;
00022
import com.sun.image.codec.jpeg.JPEGImageEncoder;
00023
00024
00025
import com.rbnb.utility.ArgHandler;
00026
00047 public class JPEGThumbnailer extends RBNBBase {
00048
00052
public JPEGThumbnailer() {
00053 setParamterArrays();
00054 initialize();
00055 }
00056
00057
private final static String DEFAULT_RBNB_OUTPUT_NAME_NAME =
"SourceName";
00058
private final static String DEFAULT_RBNB_OUTPUT_NAME =
"TSource";
00059
private final static String DEFAULT_RBNB_OUTPUT_CHANNEL_NAME =
"ChannelName";
00060
private final static String DEFAULT_RBNB_OUTPUT_CHANNEL =
"thumbnail.jpg";
00061
private final static String DEFAULT_RBNB_SINK_NAME_NAME =
"SinkName";
00062
private final static String DEFAULT_RBNB_SINK_NAME =
"JPEGThumbanilerSink";
00063
private final static String REQUIRED_INPUT_PATH_NAME =
"RequiredInputPath";
00064
private final static String REQUIRED_INPUT_PATH =
"";
00065
private final static String DEFAULT_SAMPLE_RATE_NAME =
"SampleRate";
00066
private final static double DEFAULT_SAMPLE_RATE = 1.0;
00067
private static final String CACHE_SIZE_NAME =
"CacheSize";
00068
private static final int DEFAULT_CACHE_SIZE=10;
00069
00070
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat(
"MMM d, yyyy h:mm:ss aa");
00071
private static final TimeZone TZ = TimeZone.getTimeZone(
"GMT");
00072
00073
static
00074 {
00075 DATE_FORMAT.setTimeZone(TZ);
00076 }
00077
00078
private String rbnbSourceName = DEFAULT_RBNB_OUTPUT_NAME;
00079
private String rbnbSourceChannel = DEFAULT_RBNB_OUTPUT_CHANNEL;
00080
00081
private String rbnbSinkName = DEFAULT_RBNB_SINK_NAME;
00082
00083
private String rbnbInputPath = null;
00084
00085
private double outputSampleRate = DEFAULT_SAMPLE_RATE;
00086
00087
private int cacheSize = DEFAULT_CACHE_SIZE;
00088
00089
private String[] parameterNameArray;
00090
private String[] parameterTypeArray;
00091
private Object[] parameterDefaultArray;
00092
00093 Sink sink;
00094 Source source;
00095 ChannelMap getmap;
00096 ChannelMap reqmap;
00097 ChannelMap cmap;
00098
int outputChannelIndex;
00099
int inputChannelIndex;
00100
00101
private boolean connected =
false;
00102 Thread theThread;
00103
boolean runit =
false;
00104
00105
public void printUsage()
00106 {
00107 System.out.println(
"Usage for JPEGThumbnailer...");
00108 super.printUsage();
00109 System.out.println(
" -v RBNB Sink path for input video (required) ");
00110 System.out.println(
" [-s RBNB Source (output) Name *" + DEFAULT_RBNB_OUTPUT_NAME +
"]");
00111 System.out.println(
" [-c RBNB Source (output) Channel *" + DEFAULT_RBNB_OUTPUT_CHANNEL +
"]");
00112 System.out.println(
" [-f desired output frame rate (in seconds) *" + DEFAULT_SAMPLE_RATE +
"]");
00113 System.out.println(
" [-z cache size *" + DEFAULT_CACHE_SIZE +
"]");
00114 }
00115
00116
00117
00118
00119
protected boolean setInstanceArgs(String[] args)
throws IllegalArgumentException
00120 {
00121
00122
try {
00123 ArgHandler ah=
new ArgHandler(args);
00124
if (ah.checkFlag(
's')) {
00125 String a=ah.getOption(
's');
00126
if (a!=null) rbnbSourceName=a;
00127 }
00128
if (ah.checkFlag(
'c')) {
00129 String a=ah.getOption(
'c');
00130
if (a!=null) rbnbSourceChannel=a;
00131 }
00132
if (ah.checkFlag(
'v')) {
00133 String a=ah.getOption(
'v');
00134
if (a!=null) rbnbInputPath=a;
00135 }
00136
if (ah.checkFlag(
'f')) {
00137 String a=ah.getOption(
'f');
00138
if (a!=null) outputSampleRate = Double.parseDouble(a);
00139 }
00140
if (ah.checkFlag(
'z')) {
00141 String a=ah.getOption(
'z');
00142
if (a!=null)
00143
try
00144 {
00145 Integer i =
new Integer(a);
00146
int value = i.intValue();
00147 cacheSize = value;
00148 }
00149
catch (Exception ignore) {}
00150 }
00151 }
catch (Exception e) {
00152 System.err.println(
"JPEGThumbnailer argument exception "+e.getMessage());
00153 e.printStackTrace();
00154
throw new IllegalArgumentException(
"JPEGThumbnailer argument exception "+e.getMessage());
00155 }
00156
00157
if ((rbnbInputPath == null) || (rbnbInputPath.equals(
"")))
00158 {
00159 System.err.println(
"The source/channel path for the video source is required. "
00160 +
"Use JPEGThumbnailer -h for help");
00161
return false;
00162 }
00163
00164
return true;
00165 }
00166
00167
private void connect()
00168 {
00169 source =
new Source(cacheSize,
"none", 0);
00170
try {
00171 source.OpenRBNBConnection(getServer(), rbnbSourceName);
00172 }
catch (SAPIException e) {
00173 System.err.println(
"Failed to connect to RBNB server for source.");
00174 e.printStackTrace();
00175
return;
00176 }
00177
00178
00179 cmap =
new ChannelMap();
00180 outputChannelIndex = -1;
00181
try {
00182 outputChannelIndex = cmap.Add(rbnbSourceChannel);
00183 }
catch (SAPIException e) {
00184 System.err.println(
"Failed to add output channel to channel map.");
00185 e.printStackTrace();
00186
return;
00187 }
00188 cmap.PutMime(outputChannelIndex,
"image/jpeg");
00189
00190
00191 sink =
new Sink();
00192 reqmap =
new ChannelMap();
00193 inputChannelIndex = -1;
00194
try
00195 {
00196
00197 sink.OpenRBNBConnection(getServer(), rbnbSinkName);
00198 inputChannelIndex = reqmap.Add(rbnbInputPath);
00199 sink.Monitor(reqmap,0);
00200 System.out.println(
"JPGThumNailer: Connection made to server = "
00201 + getServer() +
" as " + rbnbSinkName
00202 +
" requesting " + rbnbInputPath +
".");
00203 }
00204
catch (SAPIException se)
00205 {
00206 se.printStackTrace();
00207
return;
00208 }
00209
00210 connected =
true;
00211
00212 }
00213
00214
private void disconnect()
00215 {
00216 sink.CloseRBNBConnection();
00217 sink = null;
00218 source.CloseRBNBConnection();
00219 source = null;
00220 connected =
false;
00221 }
00222
00223
private void execute() {
00224
00225 byte[] imageData;
00226
double startTime = 0;
00227
double durationTime = 0;
00228
long sleepTime = (
long) (1000.0 * outputSampleRate);
00229
long lastTime = System.currentTimeMillis();
00230
long actualSleepTime;
00231
while (
true) {
00232
00233 actualSleepTime = sleepTime - (System.currentTimeMillis() - lastTime);
00234
if (actualSleepTime < 0) actualSleepTime = 0;
00235
try { Thread.sleep(actualSleepTime); }
catch (Exception ignore) {}
00236 lastTime = System.currentTimeMillis();
00237
00238 getmap = null;
00239
try {
00240 getmap = sink.Fetch(0);
00241 }
catch (SAPIException e) {
00242 System.err.println(
"Failed to fetch input data, retrying.");
00243
continue;
00244 }
00245
00246
00247
if (getmap.GetIfFetchTimedOut()) {
00248 System.err.println(
"Failed to fetch input data, retrying.");
00249
continue;
00250 }
00251
00252 startTime = getmap.GetTimeStart(0);
00253 durationTime = getmap.GetTimeDuration(0);
00254 imageData = getmap.GetData(0);
00255
00256 JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(
new ByteArrayInputStream(imageData));
00257
00258
00259 BufferedImage bi;
00260
try {
00261 bi = decoder.decodeAsBufferedImage();
00262 }
catch (IOException e){
00263 System.err.println(
"Failed to decode input JPEG image, skipping.");
00264
continue;
00265 }
00266
00267
00268 AffineTransformOp op =
new AffineTransformOp(AffineTransform.getScaleInstance(0.5, 0.5), null);
00269 bi = op.filter(bi, null);
00270
00271
00272 ByteArrayOutputStream out =
new ByteArrayOutputStream();
00273 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
00274 JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);
00275 param.setQuality(0.75f,
false);
00276
try {
00277 encoder.encode(bi, param);
00278 }
catch (IOException e) {
00279 System.err.println(
"Failed to encode output JPEG image, skipping.");
00280
continue;
00281 }
00282
00283
00284 imageData = out.toByteArray();
00285
00286
00287
try {
00288 cmap.PutTime(startTime, durationTime);
00289 cmap.PutDataAsByteArray(outputChannelIndex, imageData);
00290 }
catch (SAPIException e) {
00291 System.err.println(
"Failed to put output data to channel map, skipping.");
00292
continue;
00293 }
00294
long unixTime = (
long)(startTime * 1000.0);
00295 String time = DATE_FORMAT.format(
new Date(unixTime));
00296
00297
00298
00299
try {
00300 source.Flush(cmap,
true);
00301 }
catch (SAPIException e) {
00302 System.err.println(
"Failed to flush output data to server, skipping.");
00303
continue;
00304 }
00305 }
00306 }
00307
00308
public static void main(String[] args) {
00309
JPEGThumbnailer t =
new JPEGThumbnailer();
00310
if (t.
setArgs(args))
00311 {
00312 t.
connect();
00313 t.
startThread();
00314 }
00315 }
00316
00317
public void startThread()
00318 {
00319
00320
if (!connected)
return;
00321
00322
00323 Runnable r =
new Runnable() {
00324
public void run() {
00325 runWork();
00326 }
00327 };
00328 runit =
true;
00329 theThread =
new Thread(r,
"Timer");
00330 theThread.start();
00331 System.out.println(
"WalkerSource: Started thread.");
00332 }
00333
00334
public void stopThread()
00335 {
00336
if (!connected)
return;
00337
00338 runit =
false;
00339 theThread.interrupt();
00340 System.out.println(
"WalkerSource: Stopped thread.");
00341 }
00342
00343
private void runWork ()
00344 {
00345 execute();
00346 }
00347
00348 public boolean isRunning()
00349 {
00350
return (connected && runit);
00351 }
00352
00353
00354
00355
00356
protected void setParamterArrays() {
00357 String [] pNameArray = super.getBaseParameterNameArray();
00358 String [] pTypeArray = super.getBaseParameterTypeArray();
00359 Object [] pDefaultArray = super.getBaseParameterDefaultArray();
00360
00361
int base = pNameArray.length;
00362
int numberOfparameters = 6;
00363 parameterNameArray =
new String[base + numberOfparameters];
00364 parameterTypeArray =
new String[base + numberOfparameters];
00365 parameterDefaultArray =
new Object[base + numberOfparameters];
00366
00367
for (
int i = 0; i < base; i++)
00368 {
00369 parameterNameArray[i] = pNameArray[i];
00370 parameterTypeArray[i] = pTypeArray[i];
00371 parameterDefaultArray[i] = pDefaultArray[i];
00372 }
00373
00374 parameterNameArray[base + 0] = DEFAULT_RBNB_OUTPUT_NAME_NAME;
00375 parameterTypeArray[base + 0] = RBNBBaseParameterHolder.STRING_TYPE;
00376 parameterDefaultArray[base + 0] =
new String(DEFAULT_RBNB_OUTPUT_NAME);
00377
00378 parameterNameArray[base + 1] = DEFAULT_RBNB_OUTPUT_CHANNEL_NAME;
00379 parameterTypeArray[base + 1] = RBNBBaseParameterHolder.STRING_TYPE;
00380 parameterDefaultArray[base + 1] =
new String(DEFAULT_RBNB_OUTPUT_CHANNEL);
00381
00382 parameterNameArray[base + 2] = DEFAULT_RBNB_SINK_NAME_NAME;
00383 parameterTypeArray[base + 2] = RBNBBaseParameterHolder.STRING_TYPE;
00384 parameterDefaultArray[base + 2] =
new String(DEFAULT_RBNB_SINK_NAME);
00385
00386 parameterNameArray[base + 3] = REQUIRED_INPUT_PATH_NAME;
00387 parameterTypeArray[base + 3] = RBNBBaseParameterHolder.STRING_TYPE;
00388 parameterDefaultArray[base + 3] =
new String(REQUIRED_INPUT_PATH);
00389
00390 parameterNameArray[base + 4] = DEFAULT_SAMPLE_RATE_NAME;
00391 parameterTypeArray[base + 4] = RBNBBaseParameterHolder.DOUBLE_TYPE;
00392 parameterDefaultArray[base + 4] =
new Double(DEFAULT_SAMPLE_RATE);
00393
00394 parameterNameArray[base + 5] = CACHE_SIZE_NAME;
00395 parameterTypeArray[base + 5] = RBNBBaseParameterHolder.INTEGER_TYPE;
00396 parameterDefaultArray[base + 5] =
new Integer(DEFAULT_CACHE_SIZE);
00397
00398 }
00399
00400
00401
00402
00403 public void setVariablesFromParameters() {
00404 super.setBaseVarialbesFromParametes();
00405
00406 rbnbSourceName = DEFAULT_RBNB_OUTPUT_NAME;
00407
try{
00408 Object obj = getValueWithDefault(DEFAULT_RBNB_OUTPUT_NAME_NAME, DEFAULT_RBNB_OUTPUT_NAME);
00409 rbnbSourceName = (String)obj;
00410 }
catch (Throwable ignore){}
00411
00412 rbnbSourceChannel = DEFAULT_RBNB_OUTPUT_CHANNEL;
00413
try{
00414 Object obj = getValueWithDefault(DEFAULT_RBNB_OUTPUT_CHANNEL_NAME, DEFAULT_RBNB_OUTPUT_CHANNEL);
00415 rbnbSourceChannel = (String)obj;
00416 }
catch (Throwable ignore){}
00417
00418 rbnbSinkName = DEFAULT_RBNB_SINK_NAME;
00419
try{
00420 Object obj = getValueWithDefault(DEFAULT_RBNB_SINK_NAME_NAME, DEFAULT_RBNB_SINK_NAME);
00421 rbnbSinkName = (String)obj;
00422 }
catch (Throwable ignore){}
00423
00424 rbnbInputPath = REQUIRED_INPUT_PATH;
00425
try{
00426 Object obj = getValueWithDefault(REQUIRED_INPUT_PATH_NAME, REQUIRED_INPUT_PATH);
00427 rbnbInputPath = (String)obj;
00428 }
catch (Throwable ignore){}
00429
00430 outputSampleRate = DEFAULT_SAMPLE_RATE;
00431
try{
00432 Double d =
new Double(DEFAULT_SAMPLE_RATE);
00433 Object obj = getValueWithDefault(DEFAULT_SAMPLE_RATE_NAME, d);
00434 outputSampleRate = ((Double)obj).doubleValue();
00435 }
catch (Throwable ignore){}
00436
00437 cacheSize = DEFAULT_CACHE_SIZE;
00438
try{
00439 Integer i =
new Integer(DEFAULT_CACHE_SIZE);
00440 Object obj = getValueWithDefault(CACHE_SIZE_NAME, i);
00441 cacheSize = ((Integer)obj).intValue();
00442 }
catch (Throwable ignore){}
00443
00444 }
00445
00446
00447
00448
00449 public String[]
getParameterNameArray() {
00450
return parameterNameArray;
00451 }
00452
00453
00454
00455
00456 public String[]
getParameterTypeArray() {
00457
return parameterTypeArray;
00458 }
00459
00460
00461
00462
00463 public Object[]
getParameterDefaultArray() {
00464
return parameterDefaultArray;
00465 }
00466
00467
00468
00469
00470 public boolean start() {
00471
if (
isRunning())
return false;
00472
if (connected) disconnect();
00473
setVariablesFromParameters();
00474 connect();
00475
if (!connected)
return false;
00476 startThread();
00477
return true;
00478 }
00479
00480
00481
00482
00483 public boolean stop() {
00484
if (!
isRunning())
return false;
00485 stopThread();
00486 disconnect();
00487
return true;
00488 }
00489 }