public void close ( ) throws IOException { if ( r != null ) { r = null ; ogg . close ( ) ; ogg = null ; } if ( w != null ) { // First, write the initial packet of each stream // Skeleton (if present) goes first, then video, then audio(s) OggPacketWriter sw = null ; if ( skeleton != null ) { sw = ogg . getPacketWriter ( ) ; sw . bufferPacket ( skeleton . getFishead ( ) . write ( ) , true ) ; } w . bufferPacket ( info . write ( ) , true ) ; for ( OggAudioStreamHeaders audio : soundtrackWriters . keySet ( ) ) { OggPacketWriter aw = soundtrackWriters . get ( audio ) ; aw . bufferPacket ( audio . getInfo ( ) . write ( ) , true ) ; } // Next, provide the rest of the skeleton information, to // make it easy to work out what's what if ( skeleton != null ) { for ( SkeletonFisbone bone : skeleton . getFisbones ( ) ) { sw . bufferPacket ( bone . write ( ) , true ) ; } for ( SkeletonKeyFramePacket frame : skeleton . getKeyFrames ( ) ) { sw . bufferPacket ( frame . write ( ) , true ) ; } } // Next is the rest of the Theora headers w . bufferPacket ( comments . write ( ) , true ) ; w . bufferPacket ( setup . write ( ) , true ) ; // Finish the headers with the soundtrack stream remaining headers for ( OggAudioStreamHeaders audio : soundtrackWriters . keySet ( ) ) { OggPacketWriter aw = soundtrackWriters . get ( audio ) ; aw . bufferPacket ( audio . getTags ( ) . write ( ) , true ) ; if ( audio . getSetup ( ) != null ) { aw . bufferPacket ( audio . getSetup ( ) . write ( ) , true ) ; } } // Write the audio visual data, along with their granules long lastGranule = 0 ; for ( AudioVisualDataAndSid avData : writtenPackets ) { OggPacketWriter avw = w ; if ( avData . sid != sid ) { avw = soundtrackWriters . get ( avData . sid ) ; } // Update the granule position as we go // TODO Is this the correct logic for multi-stream writing? if ( avData . data . getGranulePosition ( ) >= 0 && lastGranule != avData . data . getGranulePosition ( ) ) { avw . flush ( ) ; lastGranule = avData . data . getGranulePosition ( ) ; avw . setGranulePosition ( lastGranule ) ; } // Write the data, flushing if needed avw . bufferPacket ( avData . data . write ( ) ) ; if ( avw . getSizePendingFlush ( ) > 16384 ) { avw . flush ( ) ; } } // Close down all our writers w . close ( ) ; w = null ; if ( sw != null ) { sw . close ( ) ; sw = null ; } for ( OggPacketWriter aw : soundtrackWriters . values ( ) ) { aw . close ( ) ; } ogg . close ( ) ; ogg = null ; } }
In Reading mode will close the underlying ogg file and free its resources . In Writing mode will write out the Info Comment Tags objects and then the video and audio data .