Copyright 2013-01-06 Werner Randelshofer

org.monte.media.avi
Class AVIOutputStream

java.lang.Object
  extended by org.monte.media.avi.AbstractAVIStream
      extended by org.monte.media.avi.AVIOutputStream
Direct Known Subclasses:
AVIWriter

public class AVIOutputStream
extends AbstractAVIStream

Provides low-level support for writing already encoded audio and video samples into an AVI 1.0 file.

The length of an AVI 1.0 file is limited to 1 GB. This class supports lengths of up to 4 GB, but such files may not work on all players.

For detailed information about the AVI 1.0 file format see:
msdn.microsoft.com AVI RIFF
www.microsoft.com FOURCC for Video Compression
www.saettler.com RIFF

Version:
$Id: AVIOutputStream.java 306 2013-01-04 16:19:29Z werner $
Author:
Werner Randelshofer

Nested Class Summary
protected static class AVIOutputStream.States
          The states of the movie output stream.
 
Nested classes/interfaces inherited from class org.monte.media.avi.AbstractAVIStream
AbstractAVIStream.AudioTrack, AbstractAVIStream.AVIMediaType, AbstractAVIStream.Chunk, AbstractAVIStream.CompositeChunk, AbstractAVIStream.DataChunk, AbstractAVIStream.FixedSizeDataChunk, AbstractAVIStream.MainHeader, AbstractAVIStream.MidiTrack, AbstractAVIStream.Sample, AbstractAVIStream.TextTrack, AbstractAVIStream.Track, AbstractAVIStream.VideoTrack
 
Field Summary
protected  AbstractAVIStream.CompositeChunk aviChunk
          This chunk holds the whole AVI content.
protected  AbstractAVIStream.FixedSizeDataChunk avihChunk
          This chunk holds the AVI Main Header.
protected  AbstractAVIStream.CompositeChunk moviChunk
          This chunk holds the movie frames.
protected  AVIOutputStream.States state
          The current state of the movie output stream.
 
Fields inherited from class org.monte.media.avi.AbstractAVIStream
AVI_ID, AVIH_FLAG_COPYRIGHTED, AVIH_FLAG_HAS_INDEX, AVIH_FLAG_IS_INTERLEAVED, AVIH_FLAG_MUST_USE_INDEX, AVIH_FLAG_TRUST_CK_TYPE, AVIH_FLAG_WAS_CAPTURE_FILE, AVIH_ID, AVIX_ID, CHUNK_SUBTYPE_MASK, DB_ID, DC_ID, HDRL_ID, IDX1_ID, LIST_ID, MOVI_ID, out, PC_ID, REC_ID, RIFF_ID, STRD_ID, streamOffset, STRF_ID, STRH_FLAG_DISABLED, STRH_FLAG_VIDEO_PALETTE_CHANGES, STRH_ID, STRL_ID, STRN_ID, tracks, WB_ID
 
Constructor Summary
AVIOutputStream(java.io.File file)
          Creates a new instance.
AVIOutputStream(javax.imageio.stream.ImageOutputStream out)
          Creates a new instance.
 
Method Summary
 int addAudioTrack(int waveFormatTag, long scale, long rate, int numberOfChannels, int sampleSizeInBits, boolean isCompressed, int frameDuration, int frameSize)
          Adds an audio track.
 int addVideoTrack(java.lang.String fccHandler, long scale, long rate, int width, int height, int depth, int syncInterval)
          Adds a video track.
 void close()
          Closes the stream.
protected  void ensureFinished()
          Sets the state of the QuickTimeOutpuStream to finished.
protected  void ensureStarted()
          Sets the state of the QuickTimeOutpuStream to started.
 void finish()
          Finishes writing the contents of the AVI output stream without closing the underlying stream.
 float getCompressionQuality(int track)
          Returns the compression quality of a track.
 java.lang.String[] getExtraHeaderFourCCs(int track)
          Returns the fourcc's of all extra stream headers.
 long getMediaDuration(int track)
          Returns the duration of the track in media time scale.
 java.awt.Dimension getVideoDimension(int track)
          Gets the dimension of a track.
 boolean isDataLimitReached()
          Returns true if the limit for media samples has been reached.
 void putExtraHeader(int track, java.lang.String fourcc, byte[] data)
          Returns the contents of the extra track header.
 void setCompressionQuality(int track, float newValue)
          Sets the compression quality of a track.
 void setName(int track, java.lang.String name)
           
 void setPalette(int track, java.awt.image.ColorModel palette)
          Sets the global color palette.
 void writePalette(int track, byte[] data, int off, int len, boolean isKeyframe)
          Writes an already encoded palette change into the specified track.
 void writeSample(int track, byte[] data, int off, int len, boolean isKeyframe)
          Writes an already encoded sample from a byte array into a track.
 void writeSample(int track, java.io.File file, boolean isKeyframe)
          Writes an already encoded sample from a file to the specified track.
 void writeSample(int track, java.io.InputStream in, boolean isKeyframe)
          Writes an already encoded sample from an input stream to the specified track.
 void writeSamples(int track, int sampleCount, byte[] data, int off, int len, boolean isKeyframe)
          Writes multiple already encoded samples from a byte array into a track.
 
Methods inherited from class org.monte.media.avi.AbstractAVIStream
getRelativeStreamPosition, intToType, isFlagSet, seekRelative, typeToInt
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

state

protected AVIOutputStream.States state
The current state of the movie output stream.


aviChunk

protected AbstractAVIStream.CompositeChunk aviChunk
This chunk holds the whole AVI content.


moviChunk

protected AbstractAVIStream.CompositeChunk moviChunk
This chunk holds the movie frames.


avihChunk

protected AbstractAVIStream.FixedSizeDataChunk avihChunk
This chunk holds the AVI Main Header.

Constructor Detail

AVIOutputStream

public AVIOutputStream(java.io.File file)
                throws java.io.IOException
Creates a new instance.

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

AVIOutputStream

public AVIOutputStream(javax.imageio.stream.ImageOutputStream out)
                throws java.io.IOException
Creates a new instance.

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

addVideoTrack

public int addVideoTrack(java.lang.String fccHandler,
                         long scale,
                         long rate,
                         int width,
                         int height,
                         int depth,
                         int syncInterval)
                  throws java.io.IOException
Adds a video track.

Parameters:
fccHandler - The 4-character code of the format.
scale - The numerator of the sample rate.
rate - The denominator of the sample rate.
width - The width of a video image. Must be greater than 0.
height - The height of a video image. Must be greater than 0.
depth - The number of bits per pixel. Must be greater than 0.
syncInterval - Interval for sync-samples. 0=automatic. 1=all frames are keyframes. Values larger than 1 specify that for every n-th frame is a keyframe.
Returns:
Returns the track index.
Throws:
java.lang.IllegalArgumentException - if the width or the height is smaller than 1.
java.io.IOException

addAudioTrack

public int addAudioTrack(int waveFormatTag,
                         long scale,
                         long rate,
                         int numberOfChannels,
                         int sampleSizeInBits,
                         boolean isCompressed,
                         int frameDuration,
                         int frameSize)
                  throws java.io.IOException
Adds an audio track.

Parameters:
waveFormatTag - The format of the audio stream given in MMREG.H, for example 0x0001 for WAVE_FORMAT_PCM.
scale - The numerator of the sample rate.
rate - The denominator of the sample rate.
numberOfChannels - The number of channels: 1 for mono, 2 for stereo.
sampleSizeInBits - The number of bits in a sample: 8 or 16.
isCompressed - Whether the sound is compressed.
frameDuration - The frame duration, expressed in the media’s timescale, where the timescale is equal to the sample rate. For uncompressed formats, this field is always 1.
frameSize - For uncompressed audio, the number of bytes in a sample for a single channel (sampleSize divided by 8). For compressed audio, the number of bytes in a frame.
Returns:
Returns the track index.
Throws:
java.lang.IllegalArgumentException - if the format is not 4 characters long, if the time scale is not between 1 and 2^32, if the integer portion of the sampleRate is not equal to the scale, if numberOfChannels is not 1 or 2.
java.io.IOException

setPalette

public void setPalette(int track,
                       java.awt.image.ColorModel palette)
Sets the global color palette.


getVideoDimension

public java.awt.Dimension getVideoDimension(int track)
Gets the dimension of a track.


putExtraHeader

public void putExtraHeader(int track,
                           java.lang.String fourcc,
                           byte[] data)
                    throws java.io.IOException
Returns the contents of the extra track header. Returns null if the header is not present.

Note: this method can only be performed before media data has been written into the tracks.

Parameters:
track -
fourcc -
data - the extra header as a byte array
Throws:
java.io.IOException

getExtraHeaderFourCCs

public java.lang.String[] getExtraHeaderFourCCs(int track)
                                         throws java.io.IOException
Returns the fourcc's of all extra stream headers.

Parameters:
track -
Returns:
An array of fourcc's of all extra stream headers.
Throws:
java.io.IOException

setName

public void setName(int track,
                    java.lang.String name)

setCompressionQuality

public void setCompressionQuality(int track,
                                  float newValue)
Sets the compression quality of a track.

A value of 0 stands for "high compression is important" a value of 1 for "high image quality is important".

Changing this value affects the encoding of video frames which are subsequently written into the track. Frames which have already been written are not changed.

This value has no effect on videos encoded with lossless encoders such as the PNG format.

The default value is 0.97.

Parameters:
newValue -

getCompressionQuality

public float getCompressionQuality(int track)
Returns the compression quality of a track.

Returns:
compression quality

ensureStarted

protected void ensureStarted()
                      throws java.io.IOException
Sets the state of the QuickTimeOutpuStream to started.

If the state is changed by this method, the prolog is written.

Throws:
java.io.IOException

ensureFinished

protected void ensureFinished()
                       throws java.io.IOException
Sets the state of the QuickTimeOutpuStream to finished.

If the state is changed by this method, the prolog is written.

Throws:
java.io.IOException

writePalette

public void writePalette(int track,
                         byte[] data,
                         int off,
                         int len,
                         boolean isKeyframe)
                  throws java.io.IOException
Writes an already encoded palette change into the specified track.

If a track contains palette changes, then all key frames must be immediately preceeded by a palette change chunk which also is a key frame. If a key frame is not preceeded by a key frame palette change chunk, it will be downgraded to a delta frame.

Throws:
java.lang.IllegalArgumentException - if the track is not a video track.
java.io.IOException

writeSample

public void writeSample(int track,
                        java.io.File file,
                        boolean isKeyframe)
                 throws java.io.IOException
Writes an already encoded sample from a file to the specified track.

This method does not inspect the contents of the file. For example, Its your responsibility to only append JPG files if you have chosen the JPEG video format.

If you append all frames from files or from input streams, then you have to explicitly set the dimension of the video track before you call finish() or close().

Parameters:
file - The file which holds the sample data.
Throws:
java.lang.IllegalStateException - if the duration is less than 1.
java.io.IOException - if writing the sample data failed.

writeSample

public void writeSample(int track,
                        java.io.InputStream in,
                        boolean isKeyframe)
                 throws java.io.IOException
Writes an already encoded sample from an input stream to the specified track.

This method does not inspect the contents of the file. For example, its your responsibility to only append JPG files if you have chosen the JPEG video format.

If you append all frames from files or from input streams, then you have to explicitly set the dimension of the video track before you call finish() or close().

Parameters:
track - The track number.
in - The input stream which holds the sample data.
isKeyframe - True if the sample is a key frame.
Throws:
java.lang.IllegalArgumentException - if the duration is less than 1.
java.io.IOException - if writing the sample data failed.

writeSample

public void writeSample(int track,
                        byte[] data,
                        int off,
                        int len,
                        boolean isKeyframe)
                 throws java.io.IOException
Writes an already encoded sample from a byte array into a track.

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

If a track contains palette changes, then all key frames must be immediately preceeded by a palette change chunk. If a key frame is not preceeded by a palette change chunk, it will be downgraded to a delta frame.

Parameters:
track - The track index.
data - The encoded sample data.
off - The startTime offset in the data.
len - The number of bytes to write.
isKeyframe - Whether the sample is a sync sample (keyframe).
Throws:
java.lang.IllegalArgumentException - if the duration is less than 1.
java.io.IOException - if writing the sample data failed.

writeSamples

public void writeSamples(int track,
                         int sampleCount,
                         byte[] data,
                         int off,
                         int len,
                         boolean isKeyframe)
                  throws java.io.IOException
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 startTime offset in the data.
len - The number of bytes to write. Must be dividable by sampleCount.
isKeyframe - Whether the samples are sync samples. All samples must either be sync samples or non-sync samples.
Throws:
java.lang.IllegalArgumentException - if the duration is less than 1.
java.io.IOException - if writing the sample data failed.

getMediaDuration

public long getMediaDuration(int track)
Returns the duration of the track in media time scale.


close

public void close()
           throws java.io.IOException
Closes the stream.

Throws:
java.io.IOException - if an I/O error has occurred

finish

public void finish()
            throws java.io.IOException
Finishes writing the contents of the AVI output stream without closing the underlying stream. Use this method when applying multiple filters in succession to the same output stream.

Throws:
java.lang.IllegalStateException - if the dimension of the video track has not been specified or determined yet.
java.io.IOException - if an I/O exception has occurred

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.

AVI 1.0 files have a file size limit of 2 GB. This method returns true if a file size of 1.8 GB has been reached.


Copyright 2013-01-06 Werner Randelshofer