00001
package org.nees.buffalo.video;
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
import com.rbnb.utility.ArgHandler;
00025
import com.rbnb.utility.RBNBProcess;
00026
00027
00028
00029
00030
00051 public class JPEGThumbnailer {
00052
00053
private final static String DEFAULT_RBNB_SERVER =
"localhost";
00054
private final static String DEFAULT_RBNB_PORT =
"3333";
00055
private final static String DEFAULT_RBNB_OUTPUT_NAME =
"TSource";
00056
private final static String DEFAULT_RBNB_OUTPUT_CHANNEL =
"thumbnail.jpg";
00057
private final static String DEFAULT_RBNB_SINK_NAME =
"JPEGThumbanilerSink";
00058
private final static double DEFAULT_SAMPLE_RATE = 1.0;
00059
00060
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat(
"MMM d, yyyy h:mm:ss aa");
00061
private static final TimeZone TZ = TimeZone.getTimeZone(
"GMT");
00062
00063
static
00064 {
00065 DATE_FORMAT.setTimeZone(TZ);
00066 }
00067
00068
private String rbnbServerName = DEFAULT_RBNB_SERVER;
00069
private String rbnbServerPort = DEFAULT_RBNB_PORT;
00070
private String rbnbHostName = rbnbServerName +
":" + rbnbServerPort;
00071
private String rbnbSourceName = DEFAULT_RBNB_OUTPUT_NAME;
00072
private String rbnbSourceChannel = DEFAULT_RBNB_OUTPUT_CHANNEL;
00073
00074
private String rbnbSinkName = DEFAULT_RBNB_SINK_NAME;
00075
00076
private String rbnbInputPath = null;
00077
00078
private double outputSampleRate = DEFAULT_SAMPLE_RATE;
00079
00080
private static final int DEFAULT_CACHE_SIZE=10;
00081
private int cacheSize = DEFAULT_CACHE_SIZE;
00082
00083
private static void printUsage()
00084 {
00085 System.out.println(
"Usage for JPEGThumbnailer...");
00086 System.out.println(
" -v RBNB Sink path for input video (required) ");
00087 System.out.println(
" [-r RBNB Server Name *"+ DEFAULT_RBNB_SERVER +
"]");
00088 System.out.println(
" [-p RBNB Server Port *" + DEFAULT_RBNB_PORT +
"]");
00089 System.out.println(
" [-s RBNB Source (output) Name *" + DEFAULT_RBNB_OUTPUT_NAME +
"]");
00090 System.out.println(
" [-c RBNB Source (output) Channel *" + DEFAULT_RBNB_OUTPUT_CHANNEL +
"]");
00091 System.out.println(
" [-f desired output frame rate (in seconds) *" + DEFAULT_SAMPLE_RATE +
"]");
00092 System.out.println(
" [-z cache size *" + DEFAULT_CACHE_SIZE +
"]");
00093 }
00094
00095
public JPEGThumbnailer(String[] args)
00096 {
00097
00098
try {
00099 ArgHandler ah=
new ArgHandler(args);
00100
if (ah.checkFlag(
'h')) {
00101 printUsage();
00102 RBNBProcess.exit(0);
00103 }
00104
if (ah.checkFlag(
'r')) {
00105 String a=ah.getOption(
'r');
00106
if (a!=null) rbnbServerName=a;
00107 }
00108
if (ah.checkFlag(
'p')) {
00109 String a=ah.getOption(
'p');
00110
if (a!=null) rbnbServerPort=a;
00111 }
00112
if (ah.checkFlag(
's')) {
00113 String a=ah.getOption(
's');
00114
if (a!=null) rbnbSourceName=a;
00115 }
00116
if (ah.checkFlag(
'c')) {
00117 String a=ah.getOption(
'c');
00118
if (a!=null) rbnbSourceChannel=a;
00119 }
00120
if (ah.checkFlag(
'v')) {
00121 String a=ah.getOption(
'v');
00122
if (a!=null) rbnbInputPath=a;
00123 }
00124
if (ah.checkFlag(
'f')) {
00125 String a=ah.getOption(
'f');
00126
if (a!=null) outputSampleRate = Double.parseDouble(a);
00127 }
00128
if (ah.checkFlag(
'z')) {
00129 String a=ah.getOption(
'z');
00130
if (a!=null)
00131
try
00132 {
00133 Integer i =
new Integer(a);
00134
int value = i.intValue();
00135 cacheSize = value;
00136 }
00137
catch (Exception ignore) {}
00138 }
00139 }
catch (Exception e) {
00140 System.err.println(
"JPEGThumbnailer argument exception "+e.getMessage());
00141 e.printStackTrace();
00142 RBNBProcess.exit(0);
00143 }
00144
00145
if (rbnbInputPath == null)
00146 {
00147 System.err.println(
"The source/channel path for the video source is required. "
00148 +
"Use JPEGThumbnailer -h for help");
00149 RBNBProcess.exit(0);
00150 }
00151
00152 rbnbHostName = rbnbServerName +
":" + rbnbServerPort;
00153 }
00154
00155
private void execute() {
00156
00157 Source source =
new Source(cacheSize,
"none", 0);
00158
try {
00159 source.OpenRBNBConnection(rbnbHostName, rbnbSourceName);
00160 }
catch (SAPIException e) {
00161 System.err.println(
"Failed to connect to RBNB server for source.");
00162 e.printStackTrace();
00163
return;
00164 }
00165
00166
00167 ChannelMap cmap =
new ChannelMap();
00168
int outputChannelIndex = -1;
00169
try {
00170 outputChannelIndex = cmap.Add(rbnbSourceChannel);
00171 }
catch (SAPIException e) {
00172 System.err.println(
"Failed to add output channel to channel map.");
00173 e.printStackTrace();
00174
return;
00175 }
00176 cmap.PutMime(outputChannelIndex,
"image/jpeg");
00177
00178
00179 Sink sink =
new Sink();
00180 ChannelMap reqmap =
new ChannelMap();
00181
int inputChannelIndex = -1;
00182
try
00183 {
00184
00185 sink.OpenRBNBConnection(rbnbHostName, rbnbSinkName);
00186 inputChannelIndex = reqmap.Add(rbnbInputPath);
00187 sink.Monitor(reqmap,0);
00188 System.out.println(
"JPGThumNailer: Connection made to sever = "
00189 + rbnbHostName +
" as " + rbnbSinkName
00190 +
" requesting " + rbnbInputPath +
".");
00191 }
00192
catch (SAPIException se)
00193 {
00194 se.printStackTrace();
00195
return;
00196 }
00197
00198 byte[] imageData;
00199
double startTime = 0;
00200
double durationTime = 0;
00201
long sleepTime = (
long) (1000.0 * outputSampleRate);
00202
long lastTime = System.currentTimeMillis();
00203
long actualSleepTime;
00204
while (
true) {
00205
00206 actualSleepTime = sleepTime - (System.currentTimeMillis() - lastTime);
00207
if (actualSleepTime < 0) actualSleepTime = 0;
00208
try { Thread.sleep(actualSleepTime); }
catch (Exception ignore) {}
00209 lastTime = System.currentTimeMillis();
00210
00211 ChannelMap getmap = null;
00212
try {
00213 getmap = sink.Fetch(0);
00214 }
catch (SAPIException e) {
00215 System.err.println(
"Failed to fetch input data, retrying.");
00216
continue;
00217 }
00218
00219
00220
if (getmap.GetIfFetchTimedOut()) {
00221 System.err.println(
"Failed to fetch input data, retrying.");
00222
continue;
00223 }
00224
00225 startTime = getmap.GetTimeStart(inputChannelIndex);
00226 durationTime = getmap.GetTimeDuration(inputChannelIndex);
00227 imageData = getmap.GetData(inputChannelIndex);
00228
00229 JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(
new ByteArrayInputStream(imageData));
00230
00231
00232 BufferedImage bi;
00233
try {
00234 bi = decoder.decodeAsBufferedImage();
00235 }
catch (IOException e){
00236 System.err.println(
"Failed to decode input JPEG image, skipping.");
00237
continue;
00238 }
00239
00240
00241 AffineTransformOp op =
new AffineTransformOp(AffineTransform.getScaleInstance(0.5, 0.5), null);
00242 bi = op.filter(bi, null);
00243
00244
00245 ByteArrayOutputStream out =
new ByteArrayOutputStream();
00246 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
00247 JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);
00248 param.setQuality(0.75f,
false);
00249
try {
00250 encoder.encode(bi, param);
00251 }
catch (IOException e) {
00252 System.err.println(
"Failed to encode output JPEG image, skipping.");
00253
continue;
00254 }
00255
00256
00257 imageData = out.toByteArray();
00258
00259
00260
try {
00261 cmap.PutTime(startTime, durationTime);
00262 cmap.PutDataAsByteArray(outputChannelIndex, imageData);
00263 }
catch (SAPIException e) {
00264 System.err.println(
"Failed to put output data to channel map, skipping.");
00265
continue;
00266 }
00267
long unixTime = (
long)(startTime * 1000.0);
00268 String time = DATE_FORMAT.format(
new Date(unixTime));
00269 System.out.println(
"Thumbnail sent for " + time +
" GMT)");
00270
00271
00272
try {
00273 source.Flush(cmap,
true);
00274 }
catch (SAPIException e) {
00275 System.err.println(
"Failed to flush output data to server, skipping.");
00276
continue;
00277 }
00278
00279 }
00280 }
00281
00282
public static void main(String[] args) {
00283
JPEGThumbnailer t =
new JPEGThumbnailer(args);
00284 t.
execute();
00285 }
00286 }