Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
src/CreateMovie.java
/* |
* QuickTime for Java SDK Sample Code |
Usage subject to restrictions in SDK License Agreement |
* Copyright: © 1996-1999 Apple Computer, Inc. |
*/ |
import java.awt.*; |
import java.awt.event.*; |
import java.io.*; |
import quicktime.qd.*; |
import quicktime.*; |
import quicktime.std.*; |
import quicktime.io.*; |
import quicktime.sound.*; |
import quicktime.std.image.*; |
import quicktime.std.movies.*; |
import quicktime.std.movies.media.*; |
import quicktime.util.*; |
import createmovies.*; |
import quicktime.app.display.*; |
import quicktime.app.image.*; |
import quicktime.app.QTFactory; |
/** |
* CreateMovie Demo. |
*/ |
public class CreateMovie extends Frame implements StdQTConstants, Errors { |
static CreateMovie movieFrame; |
//_________________________ CLASS METHODS |
public static void main(String args[]) { |
try { |
QTSession.open(); |
movieFrame = new CreateMovie("Movie Creation Demo using QuickTime and Java"); |
movieFrame.addWindowListener (new WindowAdapter () { |
public void windowOpened (WindowEvent we) { |
movieFrame.makeMovie(); |
} |
public void windowClosing (WindowEvent e) { |
movieFrame.canv.removeClient(); |
QTSession.close(); |
movieFrame.dispose(); |
} |
public void windowClosed (WindowEvent e) { |
System.exit(0); |
} |
}); |
movieFrame.show(); |
movieFrame.toFront(); |
} catch (Exception e) { |
e.printStackTrace(); |
QTSession.close(); |
} |
} |
public CreateMovie (String frameTitle) throws Exception { |
super(frameTitle); |
soundFile = QTFactory.findAbsolutePath ("sound.aif"); |
canv = new QTCanvas (QTCanvas.kInitialSize, 0.5F, 0.5F); |
add ("Center", canv); |
np = new NumberPainter(numFrames); |
qid = new QTImageDrawer (np, new Dimension (kWidth, kHeight), Redrawable.kMultiFrame); |
qid.setRedrawing(true); |
canv.setClient (qid, true); |
pack(); |
} |
//_________________________ INSTANCE VARIABLES |
private QTCanvas canv; |
private QTImageDrawer qid; |
private NumberPainter np; |
private static final int numFrames = 30; |
private int kWidth = 330; |
private int kHeight = 140; |
private File soundFile; |
//_________________________ INSTANCE METHODS |
private void makeMovie() { |
try { |
// |
// show save-as dialog, create movie file & empty movie |
// |
FileDialog fd = new FileDialog (this, "Save Movie As...", FileDialog.SAVE); |
fd.show(); |
if(fd.getFile() == null) |
throw new QTIOException (userCanceledErr, ""); |
QTFile f = new QTFile(fd.getDirectory() + fd.getFile()); |
Movie theMovie = Movie.createMovieFile (f, |
kMoviePlayer, |
createMovieFileDeleteCurFile | createMovieFileDontCreateResFile); |
// |
// add content |
// |
System.out.println ("Doing Video Track"); |
addVideoTrack( theMovie ); |
System.out.println ("Doing Audio Track"); |
addAudioTrack( theMovie ); |
// |
// save movie to file |
// |
OpenMovieFile outStream = OpenMovieFile.asWrite (f); |
theMovie.addResource( outStream, movieInDataForkResID, f.getName() ); |
outStream.close(); |
System.out.println ("Finished movie"); |
} |
catch (Exception qte) { |
qte.printStackTrace(); |
} |
} |
private void addVideoTrack (Movie theMovie) throws QTException { |
int kNoVolume = 0; |
int kVidTimeScale = 600; |
Track vidTrack = theMovie.addTrack (kWidth, kHeight, kNoVolume); |
VideoMedia vidMedia = new VideoMedia (vidTrack, kVidTimeScale); |
vidMedia.beginEdits(); |
addVideoSample (vidMedia); |
vidMedia.endEdits(); |
int kTrackStart = 0; |
int kMediaTime = 0; |
int kMediaRate = 1; |
vidTrack.insertMedia (kTrackStart, kMediaTime, vidMedia.getDuration(), kMediaRate); |
} |
private void addVideoSample( VideoMedia vidMedia ) throws QTException { |
QDRect rect = new QDRect (kWidth, kHeight); |
QDGraphics gw = new QDGraphics (rect); |
int size = QTImage.getMaxCompressionSize (gw, |
rect, |
gw.getPixMap().getPixelSize(), |
codecNormalQuality, |
kAnimationCodecType, |
CodecComponent.anyCodec); |
QTHandle imageHandle = new QTHandle (size, true); |
imageHandle.lock(); |
RawEncodedImage compressedImage = RawEncodedImage.fromQTHandle(imageHandle); |
CSequence seq = new CSequence (gw, |
rect, |
gw.getPixMap().getPixelSize(), |
kAnimationCodecType, |
CodecComponent.bestFidelityCodec, |
codecNormalQuality, |
codecNormalQuality, |
numFrames, //1 key frame |
null, //cTab, |
0); |
ImageDescription desc = seq.getDescription(); |
//redraw first... |
np.setCurrentFrame (1); |
qid.redraw(null); |
qid.setGWorld (gw); |
qid.setDisplayBounds (rect); |
for (int curSample = 1; curSample <= numFrames; curSample++) { |
np.setCurrentFrame (curSample); |
qid.redraw(null); |
CompressedFrameInfo info = seq.compressFrame (gw, |
rect, |
codecFlagUpdatePrevious, |
compressedImage); |
boolean isKeyFrame = info.getSimilarity() == 0; |
System.out.println ("f#:" + curSample + ",kf=" + isKeyFrame + ",sim=" + info.getSimilarity()); |
vidMedia.addSample (imageHandle, |
0, // dataOffset, |
info.getDataSize(), |
60, // frameDuration, 60/600 = 1/10 of a second, desired time per frame |
desc, |
1, // one sample |
(isKeyFrame ? 0 : mediaSampleNotSync)); // no flags |
} |
//print out ImageDescription for the last video media data -> |
//this has a sample count of 1 because we add each "frame" as an individual media sample |
System.out.println (desc); |
//redraw after finishing... |
qid.setGWorld (canv.getPort()); |
np.setCurrentFrame (numFrames); |
qid.redraw(null); |
} |
static class SoundData { |
QTHandle sampleData; |
SoundDescription description; |
int numSamples; |
} |
private void addAudioTrack (Movie theMovie) throws QTException, IOException { |
int kFullVolume = 1; |
// fills in the above SoundData class fields |
SoundData theSound = getSound(); |
//print out the SoundDescription |
System.out.println (theSound.description); |
//create Sound track with SoundMedia object -> the rounded sample rate is the time scale of the sound media |
Track sndTrack = theMovie.addTrack (0, 0, kFullVolume); |
SoundMedia sndMedia = new SoundMedia (sndTrack, theSound.description.getSampleRateRounded()); |
//add the sample data into the sound media |
sndMedia.beginEdits(); |
sndMedia.addSample (theSound.sampleData, |
0, |
theSound.sampleData.getSize(), |
1, // duration of each sound sample, |
theSound.description, |
theSound.numSamples, |
0); |
sndMedia.endEdits(); |
// insert the media into the track |
int kTrackStart = 0; |
int kMediaTime = 0; |
int kMediaRate = 1; |
sndTrack.insertMedia (kTrackStart, kMediaTime, sndMedia.getDuration(), kMediaRate); |
} |
private SoundData getSound() throws QTException, IOException { |
// |
// read sound.aif file into memory and create a description and read the sound data out of it. |
// |
SndInfo info = SndInfo.parseAIFFHeader (OpenFile.asRead (new QTFile(soundFile))); |
SoundData sd = new SoundData(); |
SoundComponentData mySndInfo = info.sndData; |
sd.description = new SoundDescription (mySndInfo.getFormat()); |
sd.description.setNumberOfChannels (mySndInfo.getNumChannels()); |
sd.description.setSampleSize (mySndInfo.getSampleSize()); |
sd.description.setSampleRate (mySndInfo.getSampleRate()); |
int mySampleDataSize = mySndInfo.getSampleCount() * (mySndInfo.getSampleSize() / 8); |
//read just the sample data into memory |
// it is sample data size and is found at the data offset location in the file |
// as returned by the ParseAIFF header call |
FileInputStream fis = new FileInputStream (soundFile); |
byte[] ar = new byte [mySampleDataSize]; |
fis.skip (info.dataOffset); |
fis.read (ar, 0, mySampleDataSize); |
sd.sampleData = new QTHandle (ar); |
sd.numSamples = mySndInfo.getSampleCount(); |
return sd; |
} |
} |
/* THIS way captures the result of the draw method of the QTImageDrawer |
it then adds the raw pixel data to the movie, getting that raw data and description |
from the ImagePresenter of the QTImageDrawer |
the way we add data above is to compress the GWorld the QTImageDrawer draws to |
using the animation compressor -> which also gives us frame differencing and a smalller data size |
and better playback for the movie. |
this code is presented as an alternative which may be appropriate in certain instances |
-> like adding image data for a sprite where no fidelity on each image is lost. |
in this case the important point is NOT the QTImageDrawer but the addition |
of the raw EncodedImage and ImageDescription -> how we get that is up to the application. |
for (int curSample = 1; curSample <= numFrames; curSample++) { |
QTUtils.reclaimMemory(); |
np.setCurrentFrame (curSample); |
qid.redraw(null); |
ImagePresenter ip = qid.toImagePresenter(); |
ImageDescription desc = ip.getDescription(); |
EncodedImage imageData = ip.getImage(1); |
vidMedia.addSample (QTHandle.fromEncodedImage(imageData), |
0, // dataOffset, |
desc.getDataSize(), |
60, // frameDuration, 60/600 = 1/10 of a second, desired time per frame |
desc, |
1, // one sample |
0 ); // no flags |
} |
*/ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14