00001
00002
00003
00004
package org.nees.rbnb;
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
import java.io.*;
00039
import java.util.*;
00040
import java.awt.Dimension;
00041
import java.awt.Image;
00042
import java.awt.image.BufferedImage;
00043
00044
import javax.media.*;
00045
import javax.media.control.*;
00046
import javax.media.protocol.*;
00047
import javax.media.protocol.DataSource;
00048
import javax.media.datasink.*;
00049
import javax.media.format.VideoFormat;
00050
import javax.media.format.AudioFormat;
00051
import javax.imageio.ImageIO;
00052
import com.sun.image.codec.jpeg.*;
00053
00054
import com.sun.media.multiplexer.*;
00055
00060 public class JpegImagesToMovie implements ControllerListener, DataSinkListener {
00061
00062
public boolean doIt(
float frameRate, byte[][] images, MediaLocator outML)
00063 {
00064
int width = 480;
00065
int height = 320;
00066
00067 byte[] data = images[0];
00068
00069 JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(
new ByteArrayInputStream(data));
00070
00071
00072 BufferedImage bi;
00073
try {
00074 bi = decoder.decodeAsBufferedImage();
00075 height = bi.getHeight();
00076 width = bi.getWidth();
00077 }
catch (IOException e){
00078 System.err.println(
"Failed to decode input JPEG image, for height and width.");
00079 }
00080
00081 PullBufferDataSource pbds =
00082 (PullBufferDataSource)
new ImageDataSourceArray(width, height, frameRate, images);
00083
return makeMovieFromPullBufferDataSource(width, height, frameRate, pbds, outML);
00084 }
00085
00086
public boolean doIt(
int width,
int height,
float frameRate, Vector inFiles, MediaLocator outML)
00087 {
00088 PullBufferDataSource ids =
00089 (PullBufferDataSource)
new ImageDataSourceFile(width, height, frameRate, inFiles);
00090
00091
return makeMovieFromPullBufferDataSource(width, height, frameRate, ids, outML);
00092 }
00093
00094
public boolean makeMovieFromPullBufferDataSource(
00095
int width,
int height,
float frameRate,
00096 PullBufferDataSource ids, MediaLocator outML)
00097 {
00098 Processor p;
00099
00100
try {
00101 System.err.println(
"- create processor for the image datasource ...");
00102 p = Manager.createProcessor(ids);
00103 }
catch (Exception e) {
00104 System.err.println(
"Yikes! Cannot create a processor from the data source.");
00105
return false;
00106 }
00107
00108 p.addControllerListener(
this);
00109
00110
00111
00112 p.configure();
00113
if (!
waitForState(p, p.Configured)) {
00114 System.err.println(
"Failed to configure the processor.");
00115
return false;
00116 }
00117
00118
00119 p.setContentDescriptor(
new ContentDescriptor(FileTypeDescriptor.QUICKTIME));
00120
00121
00122
00123 TrackControl tcs[] = p.getTrackControls();
00124 Format f[] = tcs[0].getSupportedFormats();
00125
if (f == null || f.length <= 0) {
00126 System.err.println(
"The mux does not support the input format: " + tcs[0].getFormat());
00127
return false;
00128 }
00129
00130 System.out.println(
"Found count="+f.length);
00131
00132
for (
int i=0; i<f.length;i++ ) System.out.println(
"Found "+f[i]);
00133
00134 tcs[0].setFormat(f[0]);
00135
00136 System.err.println(
"Setting the track format to: " + f[0]);
00137
00138
00139
00140 p.realize();
00141
if (!
waitForState(p, p.Realized)) {
00142 System.err.println(
"Failed to realize the processor.");
00143
return false;
00144 }
00145
00146 ContentDescriptor[] descriptors = p.getSupportedContentDescriptors();
00147
for (
int n = 0; n < descriptors.length; n++) {
00148 System.out.println(
"Desc: " + descriptors[n].toString());
00149 }
00150
00151 DataSource output = p.getDataOutput();
00152
00153 System.out.println(
"DataSource type: ");
00154 Class cls = output.getClass();
00155
while (cls != null) {
00156 System.out.println(cls.toString());
00157 cls = cls.getSuperclass();
00158 }
00159
00160
00161 DataSink dsink;
00162
if ((dsink =
createDataSink(p, outML)) == null) {
00163 System.err.println(
"Failed to create a DataSink for the given output MediaLocator: " + outML);
00164
return false;
00165 }
00166
00167 dsink.addDataSinkListener(
this);
00168
00169 fileDone =
false;
00170
00171 System.err.println(
"start processing...");
00172
00173
00174
try {
00175 p.start();
00176 dsink.start();
00177 }
catch (Exception e) {
00178 System.err.println(
"IO error during processing");
00179
return false;
00180 }
00181
00182
00183
waitForFileDone();
00184
00185
00186
try {
00187 dsink.close();
00188 }
catch (Exception e) {}
00189 p.removeControllerListener(
this);
00190
00191 System.err.println(
"...done processing.");
00192
00193
return true;
00194 }
00195
00199 DataSink
createDataSink(Processor p, MediaLocator outML) {
00200
00201 DataSource ds;
00202
00203
if ((ds = p.getDataOutput()) == null) {
00204 System.err.println(
"Something is really wrong: the processor does not have an output DataSource");
00205
return null;
00206 }
00207
00208 DataSink dsink;
00209
00210
try {
00211 System.err.println(
"- create DataSink for: " + outML);
00212 dsink = Manager.createDataSink(ds, outML);
00213 dsink.open();
00214 }
catch (Exception e) {
00215 System.err.println(
"Cannot create the DataSink: " + e);
00216
return null;
00217 }
00218
00219
return dsink;
00220 }
00221
00222
00223 Object waitSync =
new Object();
00224
boolean stateTransitionOK =
true;
00225
00230 boolean waitForState(Processor p,
int state) {
00231
synchronized (waitSync) {
00232
try {
00233
while (p.getState() < state && stateTransitionOK)
00234 waitSync.wait();
00235 }
catch (Exception e) {}
00236 }
00237
return stateTransitionOK;
00238 }
00239
00243 public void controllerUpdate(ControllerEvent evt) {
00244
00245
if (evt instanceof ConfigureCompleteEvent ||
00246 evt instanceof RealizeCompleteEvent ||
00247 evt instanceof PrefetchCompleteEvent) {
00248
synchronized (waitSync) {
00249 stateTransitionOK =
true;
00250 waitSync.notifyAll();
00251 }
00252 }
else if (evt instanceof ResourceUnavailableEvent) {
00253
synchronized (waitSync) {
00254 stateTransitionOK =
false;
00255 waitSync.notifyAll();
00256 }
00257 }
else if (evt instanceof EndOfMediaEvent) {
00258 evt.getSourceController().stop();
00259 evt.getSourceController().close();
00260 }
00261 }
00262
00263
00264 Object waitFileSync =
new Object();
00265
boolean fileDone =
false;
00266
boolean fileSuccess =
true;
00267
00271 boolean waitForFileDone() {
00272
synchronized (waitFileSync) {
00273
try {
00274
while (!fileDone)
00275 waitFileSync.wait();
00276 }
catch (Exception e) {}
00277 }
00278
return fileSuccess;
00279 }
00280
00281
00285 public void dataSinkUpdate(DataSinkEvent evt) {
00286
00287
if (evt instanceof EndOfStreamEvent) {
00288
synchronized (waitFileSync) {
00289 fileDone =
true;
00290 waitFileSync.notifyAll();
00291 }
00292 }
else if (evt instanceof DataSinkErrorEvent) {
00293
synchronized (waitFileSync) {
00294 fileDone =
true;
00295 fileSuccess =
false;
00296 waitFileSync.notifyAll();
00297 }
00298 }
00299 }
00300
00301
00302
public static void main(String args[]) {
00303
00304
if (args.length == 0)
00305 prUsage();
00306
00307
00308
int i = 0;
00309
int width = -1, height = -1;
00310
float frameRate = (
float)1.0;
00311 Vector inputFiles =
new Vector();
00312 String outputURL = null;
00313
00314
while (i < args.length) {
00315
00316
if (args[i].equals(
"-w")) {
00317 i++;
00318
if (i >= args.length)
00319 prUsage();
00320 width =
new Integer(args[i]).intValue();
00321 }
else if (args[i].equals(
"-h")) {
00322 i++;
00323
if (i >= args.length)
00324 prUsage();
00325 height =
new Integer(args[i]).intValue();
00326 }
else if (args[i].equals(
"-f")) {
00327 i++;
00328
if (i >= args.length)
00329 prUsage();
00330
00331 frameRate = Float.parseFloat(args[i]);
00332 }
else if (args[i].equals(
"-o")) {
00333 i++;
00334
if (i >= args.length)
00335 prUsage();
00336 outputURL = args[i];
00337 }
else {
00338 inputFiles.addElement(args[i]);
00339 }
00340 i++;
00341 }
00342
00343
if (outputURL == null || inputFiles.size() == 0)
00344 prUsage();
00345
00346
00347
if (!outputURL.endsWith(
".mov") && !outputURL.endsWith(
".MOV")) {
00348 System.err.println(
"The output file extension should end with a .mov extension");
00349 prUsage();
00350 }
00351
00352
if (width < 0 || height < 0) {
00353 System.err.println(
"Please specify the correct image size.");
00354 prUsage();
00355 }
00356
00357
00358
if (frameRate < (
float)1.0)
00359 frameRate = (
float)1.0;
00360
00361
00362 MediaLocator oml;
00363
00364
if ((oml =
createMediaLocator(outputURL)) == null) {
00365 System.err.println(
"Cannot build media locator from: " + outputURL);
00366 System.exit(0);
00367 }
00368
00369 JpegImagesToMovie imageToMovie =
new JpegImagesToMovie();
00370 imageToMovie.doIt(width, height, frameRate, inputFiles, oml);
00371
00372 System.exit(0);
00373 }
00374
00375
static void prUsage() {
00376 System.err.println(
"Usage: java JpegImagesToMovie -w <width> -h <height> -f <frame rate> -o <output URL> <input JPEG file 1> <input JPEG file 2> ...");
00377 System.exit(-1);
00378 }
00379
00383 static MediaLocator
createMediaLocator(String url) {
00384
00385 MediaLocator ml;
00386
00387
if (url.indexOf(
":") > 0 && (ml =
new MediaLocator(url)) != null)
00388
return ml;
00389
00390
if (url.startsWith(File.separator)) {
00391
if ((ml =
new MediaLocator(
"file:" + url)) != null)
00392
return ml;
00393 }
else {
00394 String file =
"file:" + System.getProperty(
"user.dir") + File.separator + url;
00395
if ((ml =
new MediaLocator(file)) != null)
00396
return ml;
00397 }
00398
00399
return null;
00400 }
00401
00402
00404
00405
00407
00413 class ImageDataSourceArray extends PullBufferDataSource
00414 {
00415
00416 ImageDataSourceArrayStream streams[];
00417
00418
ImageDataSourceArray(
int width,
int height,
float frameRate, byte[][] images) {
00419 streams =
new ImageDataSourceArrayStream[1];
00420 streams[0] =
new ImageDataSourceArrayStream(width, height, frameRate, images);
00421 }
00422
00423
public void setLocator(MediaLocator source) {
00424 }
00425
00426
public MediaLocator getLocator() {
00427
return null;
00428 }
00429
00434 public String
getContentType() {
00435
return ContentDescriptor.RAW;
00436 }
00437
00438
public void connect() {
00439 }
00440
00441
public void disconnect() {
00442 }
00443
00444
public void start() {
00445 }
00446
00447
public void stop() {
00448 }
00449
00453 public PullBufferStream[]
getStreams() {
00454
return streams;
00455 }
00456
00462 public Time
getDuration() {
00463
return DURATION_UNKNOWN;
00464 }
00465
00466
public Object[] getControls() {
00467
return new Object[0];
00468 }
00469
00470
public Object getControl(String type) {
00471
return null;
00472 }
00473 }
00474
00475
class ImageDataSourceArrayStream
implements PullBufferStream
00476 {
00477
00478 byte[][] images;
00479
int width, height;
00480 VideoFormat format;
00481
00482
int nextImage = 0;
00483
boolean ended =
false;
00484
00485
public ImageDataSourceArrayStream(
int width,
int height,
float frameRate, byte[][] images) {
00486
this.width = width;
00487
this.height = height;
00488
this.images = images;
00489
00490 format =
new VideoFormat(VideoFormat.JPEG,
00491
new Dimension(width, height),
00492 Format.NOT_SPECIFIED,
00493 Format.byteArray,
00494 frameRate);
00495 }
00496
00500
public boolean willReadBlock() {
00501
return false;
00502 }
00503
00508
public void read(Buffer buf)
throws IOException {
00509
00510
00511
if (nextImage >= images.length) {
00512
00513 System.err.println(
"Array: Done processing all images.");
00514 buf.setEOM(
true);
00515 buf.setOffset(0);
00516 buf.setLength(0);
00517 ended =
true;
00518
return;
00519 }
00520
00521 byte[] data = images[nextImage];
00522 nextImage++;
00523
00524 buf.setOffset(0);
00525 buf.setLength(data.length);
00526 buf.setFormat(format);
00527 buf.setFlags(buf.getFlags() | buf.FLAG_KEY_FRAME);
00528 buf.setData(data);
00529
00530
00531
00532
00533 JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(
new ByteArrayInputStream(data));
00534
00535
00536 BufferedImage bi;
00537
try {
00538 bi = decoder.decodeAsBufferedImage();
00539 System.out.println(
"h="+bi.getHeight()+
" w="+bi.getWidth());
00540
if ( height != bi.getHeight() || width != bi.getWidth() ) {
00541 System.out.println(
"Resizing... to "+width+
" x "+height);
00542
00543 Image newimg = bi.getScaledInstance(width, height, 0);
00544
00545 System.out.println(
"Converting back to buffered image...");
00546
00547 BufferedImage dest = null;
00548 dest =
new BufferedImage(width, height, dest.TYPE_INT_RGB);
00549 dest.getGraphics().drawImage((Image) newimg, 0, 0, null);
00550
00551 System.out.println(
"resized height="+dest.getHeight()+
" w="+dest.getWidth());
00552
00553
00554 ByteArrayOutputStream out =
new ByteArrayOutputStream();
00555 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
00556
try {
00557 System.out.println(
"Encoding resized image");
00558 encoder.encode(dest);
00559 System.out.println(
"Setting image as buffer");
00560
00561 byte[] newdata = out.toByteArray();
00562 buf.setData(newdata);
00563 System.out.println(
"Length="+newdata.length);
00564 buf.setLength(newdata.length);
00565 }
catch (IOException e) {
00566 System.err.println(
"Failed to encode output JPEG image, skipping.");
00567 }
00568 }
00569
00570 }
catch (IOException e){
00571 System.err.println(
"Failed to decode input JPEG image, skipping.");
00572
00573 }
00574
00575 }
00576
00580
public Format getFormat() {
00581
return format;
00582 }
00583
00584
public ContentDescriptor getContentDescriptor() {
00585
return new ContentDescriptor(ContentDescriptor.RAW);
00586 }
00587
00588
public long getContentLength() {
00589
return 0;
00590 }
00591
00592
public boolean endOfStream() {
00593
return ended;
00594 }
00595
00596
public Object[] getControls() {
00597
return new Object[0];
00598 }
00599
00600
public Object getControl(String type) {
00601
return null;
00602 }
00603 }
00604
00605
00611 class ImageDataSourceFile extends PullBufferDataSource {
00612
00613
ImageSourceStream streams[];
00614
00615
ImageDataSourceFile(
int width,
int height,
float frameRate, Vector images) {
00616 streams =
new ImageSourceStream[1];
00617 streams[0] =
new ImageSourceStream(width, height, frameRate, images);
00618 }
00619
00620
public void setLocator(MediaLocator source) {
00621 }
00622
00623
public MediaLocator getLocator() {
00624
return null;
00625 }
00626
00631 public String
getContentType() {
00632
return ContentDescriptor.RAW;
00633 }
00634
00635
public void connect() {
00636 }
00637
00638
public void disconnect() {
00639 }
00640
00641
public void start() {
00642 }
00643
00644
public void stop() {
00645 }
00646
00650 public PullBufferStream[]
getStreams() {
00651
return streams;
00652 }
00653
00659 public Time
getDuration() {
00660
return DURATION_UNKNOWN;
00661 }
00662
00663
public Object[] getControls() {
00664
return new Object[0];
00665 }
00666
00667
public Object getControl(String type) {
00668
return null;
00669 }
00670 }
00671
00675 class ImageSourceStream implements PullBufferStream {
00676
00677 Vector images;
00678
int width, height;
00679 VideoFormat format;
00680
00681
int nextImage = 0;
00682
boolean ended =
false;
00683
00684
public ImageSourceStream(
int width,
int height,
float frameRate, Vector images) {
00685
this.width = width;
00686
this.height = height;
00687
this.images = images;
00688
00689 format =
new VideoFormat(VideoFormat.JPEG,
00690
new Dimension(width, height),
00691 Format.NOT_SPECIFIED,
00692 Format.byteArray,
00693 frameRate);
00694 }
00695
00699 public boolean willReadBlock() {
00700
return false;
00701 }
00702
00707 public void read(Buffer buf)
throws IOException {
00708
00709
00710
if (nextImage >= images.size()) {
00711
00712 System.err.println(
"Done reading all images.");
00713 buf.setEOM(
true);
00714 buf.setOffset(0);
00715 buf.setLength(0);
00716 ended =
true;
00717
return;
00718 }
00719
00720 String imageFile = (String)images.elementAt(nextImage);
00721 nextImage++;
00722
00723 System.err.println(
" - reading image file: " + imageFile);
00724
00725
00726 RandomAccessFile raFile;
00727 raFile =
new RandomAccessFile(imageFile,
"r");
00728
00729 byte data[] = null;
00730
00731
00732
00733
00734
00735
00736
00737
if (data == null || data.length < raFile.length()) {
00738 data =
new byte[(
int)raFile.length()];
00739 }
00740
00741
00742 raFile.readFully(data, 0, (
int)raFile.length());
00743
00744 System.err.println(
" read " + raFile.length() +
" bytes.");
00745
00746 buf.setOffset(0);
00747 buf.setLength((
int)raFile.length());
00748 buf.setFormat(format);
00749 buf.setFlags(buf.getFlags() | buf.FLAG_KEY_FRAME);
00750 buf.setData(data);
00751
00752
00753
00754
00755 JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(
new ByteArrayInputStream(data));
00756
00757
00758 BufferedImage bi;
00759
try {
00760 bi = decoder.decodeAsBufferedImage();
00761 System.out.println(
"h="+bi.getHeight()+
" w="+bi.getWidth());
00762
if ( height != bi.getHeight() || width != bi.getWidth() ) {
00763 System.out.println(
"Resizing... to "+width+
" x "+height);
00764
00765 Image newimg = bi.getScaledInstance(width, height, 0);
00766
00767 System.out.println(
"Converting back to buffered image...");
00768
00769 BufferedImage dest = null;
00770 dest =
new BufferedImage(width, height, dest.TYPE_INT_RGB);
00771 dest.getGraphics().drawImage((Image) newimg, 0, 0, null);
00772
00773 System.out.println(
"resized height="+dest.getHeight()+
" w="+dest.getWidth());
00774
00775
00776 ByteArrayOutputStream out =
new ByteArrayOutputStream();
00777 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
00778
try {
00779 System.out.println(
"Encoding resized image");
00780 encoder.encode(dest);
00781 System.out.println(
"Setting image as buffer");
00782
00783 byte[] newdata = out.toByteArray();
00784 buf.setData(newdata);
00785 System.out.println(
"Length="+newdata.length);
00786 buf.setLength(newdata.length);
00787 }
catch (IOException e) {
00788 System.err.println(
"Failed to encode output JPEG image, skipping.");
00789 }
00790 }
00791
00792 }
catch (IOException e){
00793 System.err.println(
"Failed to decode input JPEG image, skipping.");
00794
00795 }
00796
00797
00798 raFile.close();
00799 }
00800
00804 public Format
getFormat() {
00805
return format;
00806 }
00807
00808
public ContentDescriptor getContentDescriptor() {
00809
return new ContentDescriptor(ContentDescriptor.RAW);
00810 }
00811
00812
public long getContentLength() {
00813
return 0;
00814 }
00815
00816
public boolean endOfStream() {
00817
return ended;
00818 }
00819
00820
public Object[] getControls() {
00821
return new Object[0];
00822 }
00823
00824
public Object getControl(String type) {
00825
return null;
00826 }
00827 }
00828
00829 }