Overview | Package | Class | Tree | Deprecated | Index | Help
| Copyright 2012-04-26 Werner Randelshofer
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

## org.monte.media.quicktime
Class QuickTimeWriter

    java.lang.Object
      org.monte.media.quicktime.AbstractQuickTimeStream
          org.monte.media.quicktime.QuickTimeOutputStream
              org.monte.media.quicktime.QuickTimeWriter

All Implemented Interfaces:
  MovieWriter, Multiplexer

Direct Known Subclasses:
  QuickTimeMultiplexer

    public class QuickTimeWriter

extends QuickTimeOutputStream
implements MovieWriter

Supports writing of time-based video and audio data into a QuickTime movie file (.MOV) without the need of native code.

`QuickTimeWriter` works with tracks and samples. After creating a `QuickTimeWriter` one or more video and audio tracks can be added to it. Then samples can be written into the track(s). A sample is a single element in a sequence of time-ordered data. For video data a sample typically consists of a single video frame, for uncompressed stereo audio data a sample contains one PCM impulse per channel. Samples of compressed media data may encompass larger time units.

Tracks support edit lists. An edit list specifies when to play which portion of the media data at what speed. An empty edit can be used to insert an empty time span, for example to offset a track from the start of the movie. Edits can also be used to play the same portion of media data multiple times without having it to store it more than once in the track.
Moreover edit lists are useful for lossless cutting of media data at non-sync frames. For example, MP3 layer III audio data can not be cut at arbitrary frames, because audio data can be 'borrowed' from previous frames. An edit list can be used to select the desired portion of the audio data, while the track stores the media starting from the nearest sync frame.

Samples are stored in a QuickTime file in the same sequence as they are written. In order to getCodec optimal movie playback, the samples from different tracks should be interleaved from time to time. An interleave should occur about twice per second. Furthermore, to overcome any latencies in sound playback, at least one second of sound data needs to be placed at the beginning of the movie. So that the sound and video data is offset from each other in the file by one second.

For convenience, this class has built-in encoders for video frames in the following formats: RAW, ANIMATION, JPEG and PNG. Media data in other formats, including all audio data, must be encoded before it can be written with `QuickTimeWriter`. Alternatively, you can plug in your own codec.

Example: Writing 10 seconds of a movie with 640x480 pixel, 30 fps, PNG-encoded video and 16-bit stereo, 44100 Hz, PCM-encoded audio.

     QuickTimeWriter w = new QuickTimeWriter(new File("mymovie.mov"));
     w.addAudioTrack(new AudioFormat(AudioFormat.Encoding.PCM_SIGNED), 44100, 2, 16, 2, 44100, true)); // audio in track 0
     w.addVideoTrack(QuickTimeWriter.VIDEO_PNG, 30, 640, 480);  // video in track 1

     // calculate total movie sampleDuration in media time units for each track
     long atmax = w.getMediaTimeScale(0) * 10;
     long vtmax = w.getMediaTimeScale(1) * 10;

     // sampleDuration of a single sample
     long asduration = 1;
     long vsduration = 1;

     // half a second in media time units (we interleave twice per second)
     long atstep = w.getMediaTimeScale(0) / 2;
     long vtstep = w.getMediaTimeScale(1) / 2;

     // the time when the next interleave occurs in media time units
     long atnext = w.getMediaTimeScale(0); // offset audio by 1 second
     long vtnext = 0;

     // the current time in media time units
     long atime = 0;
     long vtime = 0;

     // create buffers
     int asamplesize = 2 * 2; // 16-bit stereo * 2 channels
     byte[] audio=new byte[atstep * asamplesize];
     BufferedImage img=new BufferedImage(640, 480, BufferedImage.TYPE_INT_RGB);

     // main loop
     while (atime < atmax || vtime < vtmax) {
          atnext = Math.min(atmax, atnext + atstep); // advance audio to next interleave time
          while (atime < atnext) { // catch up with audio time
              int sampleDuration = (int) Math.min(audio.length / asamplesize, atmax - atime);
              ...fill in audio data for time "atime" and sampleDuration "sampleDuration" here...
              w.writeSamples(0, sampleDuration, audio, 0, sampleDuration * asamplesize, asduration);
              atime += sampleDuration;
          }
          vtnext = Math.min(vtmax, vtnext + vtstep); // advance video to next interleave time
          while (vtime < vtnext) { // catch up with video time
              int sampleDuration = (int) Math.min(1, vtmax - vtime);
              ...fill in image data for time "vtime" and sampleDuration "sampleDuration" here...
              w.write(1, img, vsduration);
              vtime += sampleDuration;
          }
     }
     w.close();

For information about the QuickTime file format see the "QuickTime File Format Specification", Apple Inc. 2010-08-03. (qtff) http://developer.apple.com/library/mac/documentation/QuickTime/QTFF/qtff.pdf

Version:
  1.3.4 2011-03-12 Streamlines the code with `AVIWriter`.
  1.3.3 2011-01-17 Improves writing of compressed movie headers.
  1.3.2 2011-01-17 Fixes out of bounds exception when writing sub-images with ANIMATION codec. Fixes writing of compressed movie headers.
  1.3.1 2011-01-09 Fixes broken RAW codec.
  1.3 2011-01-07 Improves robustness of API. Adds method toWebOptimizedMovie().
  1.2.2 2011-01-07 Reduces file seeking with "ANIMATION" codec.
  1.2.1 2011-01-07 Fixed default syncInterval for "ANIMATION" video.
  1.2 2011-01-05 Adds support for "ANIMATION" encoded video.
  1.1 2011-01-04 Adds "depth" parameter to addVideoTrack method.
  1.0 2011-01-02 Adds support for edit lists. Adds support for MP3 audio format.
  0.1.1 2010-12-05 Updates the link to the QuickTime file format specification.
  0.1 2010-09-30 Created.
Author:
  Werner Randelshofer

Nested Class Summary

Nested classes/interfaces inherited from class org.monte.media.quicktime.AbstractQuickTimeStream
`AbstractQuickTimeStream.Atom, AbstractQuickTimeStream.AudioTrack, AbstractQuickTimeStream.Chunk, AbstractQuickTimeStream.CompositeAtom, AbstractQuickTimeStream.DataAtom, AbstractQuickTimeStream.Edit, AbstractQuickTimeStream.Group, AbstractQuickTimeStream.Sample, AbstractQuickTimeStream.SampleSizeGroup, AbstractQuickTimeStream.States, AbstractQuickTimeStream.TimeToSampleGroup, AbstractQuickTimeStream.Track, AbstractQuickTimeStream.VideoTrack, AbstractQuickTimeStream.WideDataAtom`

Field Summary
`static Format` | `QUICKTIME`
`static Format` | `VIDEO_ANIMATION`
`static Format` | `VIDEO_JPEG`
`static Format` | `VIDEO_PNG`
`static Format` | `VIDEO_RAW`

Fields inherited from class org.monte.media.quicktime.AbstractQuickTimeStream
`creationTime, mdatAtom, mdatOffset, modificationTime, moovAtom, movieMatrix, movieTimeScale, out, state, streamOffset, tracks`

Constructor Summary
`QuickTimeWriter(java.io.File file)` Creates a new QuickTime writer.
`QuickTimeWriter(javax.imageio.stream.ImageOutputStream out)` Creates a new QuickTime writer.

Method Summary
`int` | `addAudioTrack(javax.sound.sampled.AudioFormat format)` Deprecated.
`int` | `addTrack(Format fmt)` Adds a track.
`int` | `addVideoTrack(Format format, int width, int height, int depth, int syncInterval)` Deprecated.
`int` | `addVideoTrack(Format format, long timeScale, int width, int height)` Deprecated.
`Codec` | `getCodec(int track)` Returns the codec of the specified track.
`Rational` | `getDuration(int track)` Returns the sampleDuration of the track in seconds.
`Format` | `getFileFormat()` Returns the file format.
`Format` | `getFormat(int track)` Returns the media format of the specified track.
`int` | `getTrackCount()` Returns the number of tracks.
`boolean` | `isDataLimitReached()` Returns true if the limit for media samples has been reached.
`boolean` | `isVFRSupported()` Returns true because QuickTime supports variable frame rates.
`void` | `setCodec(int track, Codec codec)` Sets the codec for the specified track.
`void` | `write(int track, Buffer buf)` Writes a sample.
`void` | `write(int track, java.awt.image.BufferedImage image, long duration)` Encodes an image as a video frame and writes it into a video track.
`void` | `write(int track, byte[] data, int off, int len, long duration, boolean isSync)` Deprecated.
`void` | `write(int track, int sampleCount, byte[] data, int off, int len, long sampleDuration, boolean isSync)` Deprecated.

Methods inherited from class org.monte.media.quicktime.QuickTimeOutputStream
`addAudioTrack, addVideoTrack, close, ensureOpen, ensureStarted, finish, getCompressionQuality, getMediaDuration, getMediaTimeScale, getMovieDuration, getMovieTimeScale, getSyncInterval, getTrackDuration, getTransformationMatrix, getUneditedTrackDuration, getVideoColorTable, setCompressionQuality, setCreationTime, setEditList, setModificationTime, setMovieTimeScale, setSyncInterval, setTransformationMatrix, setVideoColorTable, toWebOptimizedMovie, writeSample, writeSample, writeSample, writeSample, writeSamples, writeSamples, writeSamples`

Methods inherited from class org.monte.media.quicktime.AbstractQuickTimeStream
`getRelativeStreamPosition, intToType, seekRelative, typeToInt`

Methods inherited from class java.lang.Object
`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

Methods inherited from interface org.monte.media.MovieWriter
`close`

Field Detail

### QUICKTIME

    public static final Format QUICKTIME

### VIDEO_RAW

    public static final Format VIDEO_RAW

### VIDEO_ANIMATION

    public static final Format VIDEO_ANIMATION

### VIDEO_JPEG

    public static final Format VIDEO_JPEG

### VIDEO_PNG

    public static final Format VIDEO_PNG

Constructor Detail

### QuickTimeWriter

    public QuickTimeWriter(java.io.File file)
                    throws java.io.IOException

  Creates a new QuickTime writer.

  Parameters:
    `file` - the output file
  Throws:
    `java.io.IOException`

### QuickTimeWriter

    public QuickTimeWriter(javax.imageio.stream.ImageOutputStream out)
                    throws java.io.IOException

  Creates a new QuickTime writer.

  Parameters:
    `out` - the output stream.
  Throws:
    `java.io.IOException`

Method Detail

### getFileFormat

    public Format getFileFormat()
                         throws java.io.IOException

  Description copied from interface: `MovieWriter`
  Returns the file format.

  Specified by:
    `getFileFormat` in interface `MovieWriter`
  Throws:
    `java.io.IOException`

### getFormat

    public Format getFormat(int track)

  Description copied from interface: `MovieWriter`
  Returns the media format of the specified track. This is a refined version of the format that was requested when the track was added. See `MovieWriter.addTrack(org.monte.media.Format)`.

  Specified by:
    `getFormat` in interface `MovieWriter`
  Parameters:
    `track` - Track number.
  Returns:
    The media format of the track.

### addTrack

    public int addTrack(Format fmt)
                 throws java.io.IOException

  Adds a track.

  Specified by:
    `addTrack` in interface `MovieWriter`
  Parameters:
    `fmt` - The format of the track.
  Returns:
    The track number.
  Throws:
    `java.io.IOException`

### addVideoTrack

    @Deprecated
    public int addVideoTrack(Format format,
                                        long timeScale,
                                        int width,
                                        int height)
                      throws java.io.IOException

  Deprecated.

  Adds a video track.

  Parameters:
    `format` - The QuickTime video format.
    `timeScale` - The media time scale. This is typically the frame rate. If the frame rate is not an integer fraction of a second, specify a multiple of the frame rate and specify a correspondingly multiplied sampleDuration when writing frames. For example, for a rate of 23.976 fps specify a time scale of 23976 and multiply the sampleDuration of a video frame by 1000.
    `width` - The width of a video image. Must be larger than 0.
    `height` - The height of a video image. Must be larger than 0.
  Returns:
    Returns the track index.
  Throws:
    `java.lang.IllegalArgumentException` - if the width or the height is smaller than 1.
    `java.io.IOException`

### addVideoTrack

    @Deprecated
    public int addVideoTrack(Format format,
                                        int width,
                                        int height,
                                        int depth,
                                        int syncInterval)
                      throws java.io.IOException

  Deprecated.

  Adds a video track.

  Parameters:
    `format` - The QuickTime video format.
    `width` - The width of a video image. Must be larger than 0.
    `height` - The height of a video image. Must be larger than 0.
  Returns:
    Returns the track index.
  Throws:
    `java.lang.IllegalArgumentException` - if the width or the height is smaller than 1.
    `java.io.IOException`

### addAudioTrack

    @Deprecated
    public int addAudioTrack(javax.sound.sampled.AudioFormat format)
                      throws java.io.IOException

  Deprecated.

  Adds an audio track, and configures it using an `AudioFormat` object from the javax.sound API.

  Use this method for writing audio data from an `AudioInputStream` into a QuickTime Movie file.

  Parameters:
    `format` - The javax.sound audio format.
  Returns:
    Returns the track index.
  Throws:
    `java.io.IOException`

### getTrackCount

    public int getTrackCount()

  Description copied from interface: `MovieWriter`
  Returns the number of tracks.

  Specified by:
    `getTrackCount` in interface `MovieWriter`

### getDuration

    public Rational getDuration(int track)

  Returns the sampleDuration of the track in seconds.

  Specified by:
    `getDuration` in interface `MovieWriter`

### getCodec

    public Codec getCodec(int track)

  Returns the codec of the specified track.

### setCodec

    public void setCodec(int track,
                         Codec codec)

  Sets the codec for the specified track.

### write

    public void write(int track,
                      Buffer buf)
               throws java.io.IOException

  Writes a sample. Does nothing if the discard-flag in the buffer is set to true.

  Specified by:
    `write` in interface `MovieWriter`
  Specified by:
    `write` in interface `Multiplexer`
  Parameters:
    `track` - The track number.
    `buf` - The buffer containing the sample data.
  Throws:
    `java.io.IOException`

### write

    public void write(int track,
                      java.awt.image.BufferedImage image,
                      long duration)
               throws java.io.IOException

  Encodes an image as a video frame and writes it into a video track.

  Parameters:
    `track` - The track index.
    `image` - The image of the video frame.
    `duration` - The sampleDuration of the video frame in media time scale units.
  Throws:
    `IndexOutofBoundsException` - if the track index is out of bounds.
    `if` - the duration is less than 1, or if the dimension of the frame does not match the dimension of the video.
    `java.lang.UnsupportedOperationException` - if the QuickTimeWriter does not have a built-in codec for this video format.
    `java.io.IOException` - if writing the sample data failed.

### write

    @Deprecated
    public void write(int track,
                                 byte[] data,
                                 int off,
                                 int len,
                                 long duration,
                                 boolean isSync)
               throws java.io.IOException

  Deprecated.

  Writes a sample from a byte array into a track.

  This method encodes the sample if the format of the track does not match the format of the media in this track.

  Parameters:
    `track` - The track index.
    `data` - The sample data.
    `off` - The start offset in the data.
    `len` - The number of bytes to write.
    `duration` - The duration of the sample in media time scale units.
    `isSync` - Whether the sample is a sync sample (keyframe).
  Throws:
    `java.lang.IllegalArgumentException` - if the sampleDuration is less than 1.
    `java.io.IOException` - if writing the sample data failed.

### write

    @Deprecated
    public void write(int track,
                                 int sampleCount,
                                 byte[] data,
                                 int off,
                                 int len,
                                 long sampleDuration,
                                 boolean isSync)
               throws java.io.IOException

  Deprecated.

  Writes multiple already encoded samples from a byte array into a track.

  This method does not inspect the contents of the data. The contents has to match the format and dimensions of the media in this track.

  Parameters:
    `track` - The track index.
    `sampleCount` - The number of samples.
    `data` - The encoded sample data.
    `off` - The start offset in the data.
    `len` - The number of bytes to write. Must be dividable by sampleCount.
    `sampleDuration` - The sampleDuration of a sample. All samples must have the same sampleDuration.
    `isSync` - Whether the samples are sync samples. All samples must either be sync samples or non-sync samples.
  Throws:
    `java.lang.IllegalArgumentException` - if the sampleDuration is less than 1.
    `java.io.IOException` - if writing the sample data failed.

### isVFRSupported

    public boolean isVFRSupported()

  Returns true because QuickTime supports variable frame rates.

### isDataLimitReached

    public boolean isDataLimitReached()

  Returns true if the limit for media samples has been reached. If this limit is reached, no more samples should be added to the movie.

  QuickTime files can be up to 64 TB long, but there are other values that may overflow before this size is reached. This method returns true when the files size exceeds 2^60 or when the media sampleDuration value of a track exceeds 2^61.

  Specified by:
    `isDataLimitReached` in interface `MovieWriter`
  Overrides:
    `isDataLimitReached` in class `QuickTimeOutputStream`

Overview | Package | Class | Tree | Deprecated | Index | Help
| Copyright 2012-04-26 Werner Randelshofer
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD