FileDocCategorySizeDatePackage
VideoSampleBuilder.javaAPI DocExample13698Wed Nov 10 12:37:18 GMT 2004com.oreilly.qtjnotebook.ch08

VideoSampleBuilder

public class VideoSampleBuilder extends Object

Fields Summary
public static final int
VIDEO_TRACK_WIDTH
public static final int
VIDEO_TRACK_HEIGHT
public static final int
VIDEO_TRACK_VOLUME
public static final int
KEY_FRAME_RATE
Properties
userProps
QDRect
startRect
QDRect
endRect
Constructors Summary
public VideoSampleBuilder()


         

        /* try to load "videoSampleBuilder.properties" from 
           current directory.  this contains file.location and
           start.x/y/width/height and end.x/y/width/height params
         */
        try {
            userProps.load (new FileInputStream (new File ("videosamplebuilder.properties")));
            System.out.println ("Loaded \"videosamplebuilder.properties\"");
        } catch (Exception e) {
            System.out.println ("Couldn't load \"videosamplebuilder.properties");
        }

        int CODEC_TYPE = QTUtils.toOSType ("SVQ3");
        // int CODEC_TYPE = QTUtils.toOSType("mp4v");

        // create a new empty movie
        QTFile movFile = new QTFile (new java.io.File("videotrack.mov"));
        Movie movie =
            Movie.createMovieFile(movFile,
                                  StdQTConstants.kMoviePlayer,
                                  StdQTConstants.createMovieFileDeleteCurFile |
                                  StdQTConstants.createMovieFileDontCreateResFile);
        System.out.println ("Created Movie");

        // now create an empty video track
        int timeScale = 600; // 100 units per second
        Track videoTrack = movie.addTrack (VIDEO_TRACK_WIDTH,
                                           VIDEO_TRACK_HEIGHT,
                                           VIDEO_TRACK_VOLUME);
        System.out.println ("Added empty Track");

        // now we need media for this track
		VideoMedia videoMedia = new VideoMedia(videoTrack,
                                               timeScale);

        // get image file from props or dialog
        QTFile imgFile = getImageFile();
        if (imgFile == null)
            return;

        // get a GraphicsImporter
        GraphicsImporter importer = new GraphicsImporter (imgFile);
        System.out.println ("Got GraphicsImporter - Bounds are " +
                            importer.getNaturalBounds());

        // Create an offscreen QDGraphics / GWorld that's the
        // size of our frames.  Importer will draw into this,
        // and we'll then hand it to the CSequence
        QDGraphics gw =
            new QDGraphics (new QDRect (0, 0,
                                        VIDEO_TRACK_WIDTH,
                                        VIDEO_TRACK_HEIGHT));
        System.out.println ("Created GWorld, - Bounds are " +
                            gw.getBounds());

        // get start, end rects
        getRects (importer);
        System.out.println ("startRect = " + startRect);
        System.out.println ("endRect = " + endRect);

        // set importer's gworld
        importer.setGWorld (gw, null);
        System.out.println ("Reset importer's GWorld, now: " +
                            importer.getGWorld());
                            
        // get to work
        videoMedia.beginEdits();

        // figure out per-frame offsets
        QDRect gRect = new QDRect (0, 0,
                                      VIDEO_TRACK_WIDTH,
                                      VIDEO_TRACK_HEIGHT);
        int frames = 300;
        int startX = startRect.getX();
        int startY = startRect.getY();
        int endX = endRect.getX();
        int endY = endRect.getY();
        float xOffPerFrame = ((float)(endX - startX) / (float)frames);
        float yOffPerFrame = ((float)(endY - startY) / (float)frames);
        float widthOffPerFrame = ((float) (endRect.getWidth() -
                                           startRect.getWidth()) /
                                  (float) frames);
        float heightOffPerFrame = ((float) (endRect.getHeight() -
                                           startRect.getHeight()) /
                                  (float) frames);

        System.out.println ("xOffPerFrame=" + xOffPerFrame +
                            ", yOffPerFrame=" + yOffPerFrame +
                            ", widthOffPerFrame=" + widthOffPerFrame +
                            ", heightOffPerFrame=" + heightOffPerFrame);

        // reserve an image with enough space to hold compressed image
        // this is needed by the last arg of CSequence.compressFrame
		int rawImageSize =
            QTImage.getMaxCompressionSize (gw, 
                                           gRect, 
                                           gw.getPixMap().getPixelSize(),
                                           StdQTConstants.codecNormalQuality, 
                                           CODEC_TYPE,
                                           // CodecComponent.anyCodec);
                                           CodecComponent.bestFidelityCodec);
		QTHandle imageHandle = new QTHandle (rawImageSize, true);
		imageHandle.lock();
		RawEncodedImage compressedImage =
            RawEncodedImage.fromQTHandle(imageHandle);

        // create a CSequence
        /* see behavior flags at
http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESI/compresssequencebegin.htm#//apple_ref/c/func/CompressSequenceBegin
        */
		CSequence seq = new CSequence (gw,
                                       gRect, 
                                       gw.getPixMap().getPixelSize(),
                                       CODEC_TYPE,
                                       CodecComponent.bestFidelityCodec,
                                       StdQTConstants.codecNormalQuality, 
                                       StdQTConstants.codecNormalQuality, 
                                       KEY_FRAME_RATE,
                                       null,
                                       0);

        // remember an ImageDescription from this sequence definition
        ImageDescription imgDesc = seq.getDescription();

        // loop through the specified number of frames, drawing 
        // scaled instances into our GWorld and compressing those
        // to the CSequence
        for (int i=1; i<frames; i++) {
            System.out.println ("i==" + i);

            // compute a rect for this frame
            int x = startX + (int) (xOffPerFrame * i);
            int y = startY + (int) (yOffPerFrame * i);
            int width = startRect.getWidth() + (int) (widthOffPerFrame * i);
            int height = startRect.getHeight() + (int) (heightOffPerFrame * i);
            QDRect fromRect = new QDRect (x, y, width, height);

            // create a Matrix to represent the move/scale from
            // the fromRect to the GWorld and make importer use it
            Matrix drawMatrix = new Matrix();
            drawMatrix.rect (fromRect, gRect);
            System.out.println ("fromRect = " + fromRect);
            importer.setMatrix (drawMatrix);

            // have importer draw (scaled) into our GWorld
            importer.draw();
            System.out.println ("Importer drew");

            // compress a frame
            /* behavior flags at
http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESI/compresssequenceframe.htm#//apple_ref/c/func/CompressSequenceFrame
            */
			CompressedFrameInfo cfInfo =
                seq.compressFrame (gw, 
                                   gRect, 
                                   StdQTConstants.codecFlagUpdatePrevious, 
                                   compressedImage);
            System.out.println ("similarity = " + cfInfo.getSimilarity());

            // see http://developer.apple.com/qa/qtmcc/qtmcc20.html
            // for explanation of mediaSampleNotSync
            boolean syncSample = (cfInfo.getSimilarity() == 0);
            int flags = syncSample ? 0 : StdQTConstants.mediaSampleNotSync;

            // add compressed frame to the video media
            videoMedia.addSample (imageHandle, 
                                  0, 
                                  cfInfo.getDataSize(),
                                  20, // time per frame, in timescale
                                  imgDesc,
                                  1, // one sample
                                  flags
                                  );
        } // for

        // done editing
        videoMedia.endEdits();

        // now insert this media into track
        videoTrack.insertMedia (0, // trackStart
                                0, // mediaTime
                                videoMedia.getDuration(), // mediaDuration
                                1); // mediaRate
        System.out.println ("inserted media into video track");

        // save up 
        System.out.println ("Saving...");
        OpenMovieFile omf = OpenMovieFile.asWrite (movFile);
        movie.addResource (omf,
                           StdQTConstants.movieInDataForkResID,
                           movFile.getName());
        System.out.println ("Done");

    
Methods Summary
protected QTFilegetImageFile()
Gets imageFile from props file, or file-preview if that doesn't work.

        // is it in the props?
        QTFile imageFile = null;
        if (userProps.containsKey ("file")) {
            imageFile = new QTFile (userProps.getProperty("file"));
            if (! imageFile.exists())
                imageFile = null;
        }

        // if not, or if that failed, then use a dialog
        if (imageFile == null) {
            int[] types = {};
            imageFile = QTFile.standardGetFilePreview (types);
        }
        return imageFile;
    
protected voidgetRects(GraphicsImporter importer)
Gets startRect, endRect from userProps, or selects randomly if that doesn't work

        Random rand = new Random();
        int rightStop =
            importer.getNaturalBounds().getWidth() - VIDEO_TRACK_WIDTH;
        int bottomStop =
            importer.getNaturalBounds().getHeight() - VIDEO_TRACK_HEIGHT;

        // try to get startRect from userProps
        try {
            int startX = Integer.parseInt (userProps.getProperty("start.x"));
            int startY = Integer.parseInt (userProps.getProperty("start.y"));
            int startWidth = Integer.parseInt (userProps.getProperty("start.width"));
            int startHeight = Integer.parseInt (userProps.getProperty("start.height"));
            startRect = new QDRect (startX, startY, startWidth, startHeight);
        } catch (Exception e) {
            // make random start rect
            int startX = Math.abs (rand.nextInt() % rightStop);
            int startY = Math.abs (rand.nextInt() % bottomStop);
            startRect = new QDRect (startX, startY, 
                                    VIDEO_TRACK_WIDTH,
                                    VIDEO_TRACK_HEIGHT);
        }

        // try to get endRect from userProps
        try {
            int endX = Integer.parseInt (userProps.getProperty("end.x"));
            int endY = Integer.parseInt (userProps.getProperty("end.y"));
            int endWidth = Integer.parseInt (userProps.getProperty("end.width"));
            int endHeight = Integer.parseInt (userProps.getProperty("end.height"));
            endRect = new QDRect (endX, endY, endWidth, endHeight);

        } catch (Exception e) {
            float zoom = (rand.nextFloat() - 0.5f); // -0.5 <= zoom <= 0.5
            System.out.println ("zoom = " + zoom);
            int endX = Math.abs (rand.nextInt() % rightStop);
            int endY = Math.abs (rand.nextInt() % bottomStop);
            endRect = new QDRect (endX, endY,
                                  VIDEO_TRACK_WIDTH * zoom,
                                  VIDEO_TRACK_HEIGHT * zoom);
        }
    
public static voidmain(java.lang.String[] arrrImAPirate)

        try {
            QTSessionCheck.check();
            new VideoSampleBuilder();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);