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 }