/*
* JPEGImagesToVideo.java
*
* From http://java.sun.com/javase/technologies/desktop/media/jmf/2.1.1/solutions/JpegImagesToMovie.java 1.3 01/03/13
*
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear facility.
* Licensee represents and warrants that it will not use or redistribute the
* Software for such purposes.
*/
package com.eteks.sweethome3d.swing;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import javax.media.ConfigureCompleteEvent;
import javax.media.Controller;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DataSink;
import javax.media.EndOfMediaEvent;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoProcessorException;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.ResourceUnavailableEvent;
import javax.media.control.TrackControl;
import javax.media.datasink.DataSinkErrorEvent;
import javax.media.datasink.DataSinkEvent;
import javax.media.datasink.DataSinkListener;
import javax.media.datasink.EndOfStreamEvent;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;
/**
* This program takes a list of images and convert them into a
* QuickTime movie.
*/
public class JPEGImagesToVideo {
private Object waitSync;
private boolean stateTransitionOK;
private Object waitFileSync;
private boolean fileDone;
private String fileError;
/**
* Creates a video file at the given size and frame rate.
*/
public void createVideoFile(int width, int height, int frameRate, DataSource dataSource, File file) throws IOException {
this.waitSync = new Object();
this.stateTransitionOK = true;
this.waitFileSync = new Object();
this.fileDone = false;
this.fileError = null;
ControllerListener controllerListener = new ControllerListener() {
public void controllerUpdate(ControllerEvent ev) {
if (ev instanceof ConfigureCompleteEvent
|| ev instanceof RealizeCompleteEvent
|| ev instanceof PrefetchCompleteEvent) {
synchronized (waitSync) {
stateTransitionOK = true;
waitSync.notifyAll();
}
} else if (ev instanceof ResourceUnavailableEvent) {
synchronized (waitSync) {
stateTransitionOK = false;
waitSync.notifyAll();
}
} else if (ev instanceof EndOfMediaEvent) {
ev.getSourceController().stop();
ev.getSourceController().close();
}
}
};
DataSinkListener dataSinkListener = new DataSinkListener() {
public void dataSinkUpdate(DataSinkEvent ev) {
if (ev instanceof EndOfStreamEvent) {
synchronized (waitFileSync) {
fileDone = true;
waitFileSync.notifyAll();
}
} else if (ev instanceof DataSinkErrorEvent) {
synchronized (waitFileSync) {
fileDone = true;
fileError = "Data sink error";
waitFileSync.notifyAll();
}
}
}
};
Processor processor = null;
DataSink dataSink = null;
try {
processor = Manager.createProcessor(dataSource);
processor.addControllerListener(controllerListener);
processor.configure();
// Put the Processor into configured state so we can set
// some processing options on the processor.
if (!waitForState(processor, Processor.Configured)) {
throw new IOException("Failed to configure the processor.");
}
// Set the output content descriptor to QuickTime.
processor.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.QUICKTIME));
// Query for the processor for supported formats.
// Then set it on the processor.
TrackControl trackControls[] = processor.getTrackControls();
Format format[] = trackControls [0].getSupportedFormats();
if (format == null || format.length <= 0) {
throw new IOException("The mux does not support the input format: " + trackControls [0].getFormat());
}
trackControls [0].setFormat(format [0]);
// We are done with programming the processor. Let's just realize it.
processor.realize();
if (!waitForState(processor, Controller.Realized)) {
throw new IOException("Failed to realize the processor.");
}
// Now, we'll need to create a DataSink.
// Caution: do not use file.toURI().toURL() with JMF
dataSink = Manager.createDataSink(processor.getDataOutput(),
new MediaLocator(file.toURL()));
dataSink.open();
dataSink.addDataSinkListener(dataSinkListener);
this.fileDone = false;
// Start the actual transcoding
processor.start();
dataSink.start();
// Wait for EndOfStream event.
synchronized (this.waitFileSync) {
while (!this.fileDone) {
this.waitFileSync.wait();
}
}
if (this.fileError != null) {
throw new IOException(this.fileError);
}
} catch (NoProcessorException ex) {
IOException ex2 = new IOException(ex.getMessage());
ex2.initCause(ex);
throw ex2;
} catch (NoDataSinkException ex) {
IOException ex2 = new IOException("Failed to create a DataSink for the given output MediaLocator");
ex2.initCause(ex);
throw ex2;
} catch (InterruptedException ex) {
if (dataSink != null) {
dataSink.stop();
}
throw new InterruptedIOException("Video creation interrupted");
} finally {
if (dataSink != null) {
dataSink.close();
dataSink.removeDataSinkListener(dataSinkListener);
}
if (processor != null) {
processor.close();
processor.removeControllerListener(controllerListener);
}
}
}
/**
* Blocks until the processor has transitioned to the given state. Return false
* if the transition failed.
*/
private boolean waitForState(Processor p, int state) throws InterruptedException {
synchronized (waitSync) {
while (p.getState() < state && stateTransitionOK) {
waitSync.wait();
}
}
return stateTransitionOK;
}
}