Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.media.sound;
   27   
   28   import java.util.Vector;
   29   import java.io.File;
   30   import java.io.InputStream;
   31   import java.io.OutputStream;
   32   import java.io.IOException;
   33   import java.io.EOFException;
   34   import java.net.URL;
   35   import java.net.MalformedURLException;
   36   
   37   import java.io.BufferedInputStream;
   38   import java.io.BufferedOutputStream;
   39   import java.io.DataInputStream;
   40   import java.io.FileInputStream;
   41   import java.io.DataOutputStream;
   42   import java.io.FileOutputStream;
   43   import java.io.ByteArrayInputStream;
   44   import java.io.ByteArrayOutputStream;
   45   import java.io.SequenceInputStream;
   46   
   47   import javax.sound.sampled.AudioFileFormat;
   48   import javax.sound.sampled.AudioInputStream;
   49   import javax.sound.sampled.AudioFormat;
   50   import javax.sound.sampled.AudioSystem;
   51   import javax.sound.sampled.UnsupportedAudioFileException;
   52   
   53   
   54   
   55   /**
   56    * WAVE file reader.
   57    *
   58    * @author Kara Kytle
   59    * @author Jan Borgersen
   60    * @author Florian Bomers
   61    */
   62   public class WaveFileReader extends SunFileReader {
   63   
   64       private static final int MAX_READ_LENGTH = 12;
   65   
   66       /**
   67        * WAVE reader type
   68        */
   69   
   70       public static final AudioFileFormat.Type types[] = {
   71           AudioFileFormat.Type.WAVE
   72       };
   73   
   74   
   75       /**
   76        * Constructs a new WaveFileReader object.
   77        */
   78       public WaveFileReader() {
   79       }
   80   
   81   
   82       /**
   83        * Obtains the audio file format of the input stream provided.  The stream must
   84        * point to valid audio file data.  In general, audio file providers may
   85        * need to read some data from the stream before determining whether they
   86        * support it.  These parsers must
   87        * be able to mark the stream, read enough data to determine whether they
   88        * support the stream, and, if not, reset the stream's read pointer to its original
   89        * position.  If the input stream does not support this, this method may fail
   90        * with an IOException.
   91        * @param stream the input stream from which file format information should be
   92        * extracted
   93        * @return an <code>AudioFileFormat</code> object describing the audio file format
   94        * @throws UnsupportedAudioFileException if the stream does not point to valid audio
   95        * file data recognized by the system
   96        * @throws IOException if an I/O exception occurs
   97        * @see InputStream#markSupported
   98        * @see InputStream#mark
   99        */
  100       public AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException {
  101           // fix for 4489272: AudioSystem.getAudioFileFormat() fails for InputStream, but works for URL
  102           AudioFileFormat aff = getFMT(stream, true);
  103           // the following is not strictly necessary - but was implemented like that in 1.3.0 - 1.4.1
  104           // so I leave it as it was. May remove this for 1.5.0
  105           stream.reset();
  106           return aff;
  107       }
  108   
  109   
  110       /**
  111        * Obtains the audio file format of the URL provided.  The URL must
  112        * point to valid audio file data.
  113        * @param url the URL from which file format information should be
  114        * extracted
  115        * @return an <code>AudioFileFormat</code> object describing the audio file format
  116        * @throws UnsupportedAudioFileException if the URL does not point to valid audio
  117        * file data recognized by the system
  118        * @throws IOException if an I/O exception occurs
  119        */
  120       public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException {
  121           InputStream urlStream = url.openStream(); // throws IOException
  122           AudioFileFormat fileFormat = null;
  123           try {
  124               fileFormat = getFMT(urlStream, false);
  125           } finally {
  126               urlStream.close();
  127           }
  128           return fileFormat;
  129       }
  130   
  131   
  132       /**
  133        * Obtains the audio file format of the File provided.  The File must
  134        * point to valid audio file data.
  135        * @param file the File from which file format information should be
  136        * extracted
  137        * @return an <code>AudioFileFormat</code> object describing the audio file format
  138        * @throws UnsupportedAudioFileException if the File does not point to valid audio
  139        * file data recognized by the system
  140        * @throws IOException if an I/O exception occurs
  141        */
  142       public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException {
  143           AudioFileFormat fileFormat = null;
  144           FileInputStream fis = new FileInputStream(file);       // throws IOException
  145           // part of fix for 4325421
  146           try {
  147               fileFormat = getFMT(fis, false);
  148           } finally {
  149               fis.close();
  150           }
  151   
  152           return fileFormat;
  153       }
  154   
  155   
  156       /**
  157        * Obtains an audio stream from the input stream provided.  The stream must
  158        * point to valid audio file data.  In general, audio file providers may
  159        * need to read some data from the stream before determining whether they
  160        * support it.  These parsers must
  161        * be able to mark the stream, read enough data to determine whether they
  162        * support the stream, and, if not, reset the stream's read pointer to its original
  163        * position.  If the input stream does not support this, this method may fail
  164        * with an IOException.
  165        * @param stream the input stream from which the <code>AudioInputStream</code> should be
  166        * constructed
  167        * @return an <code>AudioInputStream</code> object based on the audio file data contained
  168        * in the input stream.
  169        * @throws UnsupportedAudioFileException if the stream does not point to valid audio
  170        * file data recognized by the system
  171        * @throws IOException if an I/O exception occurs
  172        * @see InputStream#markSupported
  173        * @see InputStream#mark
  174        */
  175       public AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException {
  176           // getFMT leaves the input stream at the beginning of the audio data
  177           AudioFileFormat fileFormat = getFMT(stream, true); // throws UnsupportedAudioFileException, IOException
  178   
  179           // we've got everything, and the stream is at the
  180           // beginning of the audio data, so return an AudioInputStream.
  181           return new AudioInputStream(stream, fileFormat.getFormat(), fileFormat.getFrameLength());
  182       }
  183   
  184   
  185       /**
  186        * Obtains an audio stream from the URL provided.  The URL must
  187        * point to valid audio file data.
  188        * @param url the URL for which the <code>AudioInputStream</code> should be
  189        * constructed
  190        * @return an <code>AudioInputStream</code> object based on the audio file data pointed
  191        * to by the URL
  192        * @throws UnsupportedAudioFileException if the URL does not point to valid audio
  193        * file data recognized by the system
  194        * @throws IOException if an I/O exception occurs
  195        */
  196       public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
  197           InputStream urlStream = url.openStream();  // throws IOException
  198           AudioFileFormat fileFormat = null;
  199           try {
  200               fileFormat = getFMT(urlStream, false);
  201           } finally {
  202               if (fileFormat == null) {
  203                   urlStream.close();
  204               }
  205           }
  206           return new AudioInputStream(urlStream, fileFormat.getFormat(), fileFormat.getFrameLength());
  207       }
  208   
  209   
  210       /**
  211        * Obtains an audio stream from the File provided.  The File must
  212        * point to valid audio file data.
  213        * @param file the File for which the <code>AudioInputStream</code> should be
  214        * constructed
  215        * @return an <code>AudioInputStream</code> object based on the audio file data pointed
  216        * to by the File
  217        * @throws UnsupportedAudioFileException if the File does not point to valid audio
  218        * file data recognized by the system
  219        * @throws IOException if an I/O exception occurs
  220        */
  221       public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException {
  222           FileInputStream fis = new FileInputStream(file); // throws IOException
  223           AudioFileFormat fileFormat = null;
  224           // part of fix for 4325421
  225           try {
  226               fileFormat = getFMT(fis, false);
  227           } finally {
  228               if (fileFormat == null) {
  229                   fis.close();
  230               }
  231           }
  232           return new AudioInputStream(fis, fileFormat.getFormat(), fileFormat.getFrameLength());
  233       }
  234   
  235   
  236       //--------------------------------------------------------------------
  237   
  238   
  239       private AudioFileFormat getFMT(InputStream stream, boolean doReset) throws UnsupportedAudioFileException, IOException {
  240   
  241           // assumes sream is rewound
  242   
  243           int bytesRead;
  244           int nread = 0;
  245           int fmt;
  246           int length = 0;
  247           int wav_type = 0;
  248           short channels;
  249           long sampleRate;
  250           long avgBytesPerSec;
  251           short blockAlign;
  252           int sampleSizeInBits;
  253           AudioFormat.Encoding encoding = null;
  254   
  255           DataInputStream dis = new DataInputStream( stream );
  256   
  257           if (doReset) {
  258               dis.mark(MAX_READ_LENGTH);
  259           }
  260   
  261           int magic = dis.readInt();
  262           int fileLength = rllong(dis);
  263           int waveMagic = dis.readInt();
  264           int totallength;
  265           if (fileLength <= 0) {
  266               fileLength = AudioSystem.NOT_SPECIFIED;
  267               totallength = AudioSystem.NOT_SPECIFIED;
  268           } else {
  269               totallength = fileLength + 8;
  270           }
  271   
  272           if ((magic != WaveFileFormat.RIFF_MAGIC) || (waveMagic != WaveFileFormat.WAVE_MAGIC)) {
  273               // not WAVE, throw UnsupportedAudioFileException
  274               if (doReset) {
  275                   dis.reset();
  276               }
  277               throw new UnsupportedAudioFileException("not a WAVE file");
  278           }
  279   
  280           // find and read the "fmt" chunk
  281           // we break out of this loop either by hitting EOF or finding "fmt "
  282           while(true) {
  283   
  284               try {
  285                   fmt = dis.readInt();
  286                   nread += 4;
  287                   if( fmt==WaveFileFormat.FMT_MAGIC ) {
  288                       // we've found the 'fmt' chunk
  289                       break;
  290                   } else {
  291                       // else not 'fmt', skip this chunk
  292                       length = rllong(dis);
  293                       nread += 4;
  294                       if (length % 2 > 0) length++;
  295                       nread += dis.skipBytes(length);
  296                   }
  297               } catch (EOFException eof) {
  298                                   // we've reached the end of the file without finding the 'fmt' chunk
  299                   throw new UnsupportedAudioFileException("Not a valid WAV file");
  300               }
  301           }
  302   
  303           // Read the format chunk size.
  304           length = rllong(dis);
  305           nread += 4;
  306   
  307           // This is the nread position at the end of the format chunk
  308           int endLength = nread + length;
  309   
  310           // Read the wave format data out of the format chunk.
  311   
  312           // encoding.
  313           wav_type = rlshort(dis); nread += 2;
  314   
  315           if (wav_type == WaveFileFormat.WAVE_FORMAT_PCM)
  316               encoding = AudioFormat.Encoding.PCM_SIGNED;  // if 8-bit, we need PCM_UNSIGNED, below...
  317           else if ( wav_type == WaveFileFormat.WAVE_FORMAT_ALAW )
  318               encoding = AudioFormat.Encoding.ALAW;
  319           else if ( wav_type == WaveFileFormat.WAVE_FORMAT_MULAW )
  320               encoding = AudioFormat.Encoding.ULAW;
  321           else {
  322               // we don't support any other WAVE formats....
  323               throw new UnsupportedAudioFileException("Not a supported WAV file");
  324           }
  325           // channels
  326           channels = rlshort(dis); nread += 2;
  327   
  328           // sample rate.
  329           sampleRate = rllong(dis); nread += 4;
  330   
  331           // this is the avgBytesPerSec
  332           avgBytesPerSec = rllong(dis); nread += 4;
  333   
  334           // this is blockAlign value
  335           blockAlign = rlshort(dis); nread += 2;
  336   
  337           // this is the PCM-specific value bitsPerSample
  338           sampleSizeInBits = (int)rlshort(dis); nread += 2;
  339   
  340           // if sampleSizeInBits==8, we need to use PCM_UNSIGNED
  341           if ((sampleSizeInBits==8) && encoding.equals(AudioFormat.Encoding.PCM_SIGNED))
  342               encoding = AudioFormat.Encoding.PCM_UNSIGNED;
  343   
  344           // skip any difference between the length of the format chunk
  345           // and what we read
  346   
  347           // if the length of the chunk is odd, there's an extra pad byte
  348           // at the end.  i've never seen this in the fmt chunk, but we
  349           // should check to make sure.
  350   
  351           if (length % 2 != 0) length += 1;
  352   
  353           // $$jb: 07.28.99: endLength>nread, not length>nread.
  354           //       This fixes #4257986
  355           if (endLength > nread)
  356               nread += dis.skipBytes(endLength - nread);
  357   
  358           // we have a format now, so find the "data" chunk
  359           // we break out of this loop either by hitting EOF or finding "data"
  360           // $$kk: if "data" chunk precedes "fmt" chunk we are hosed -- can this legally happen?
  361           nread = 0;
  362           while(true) {
  363               try{
  364                   int datahdr = dis.readInt();
  365                   nread+=4;
  366                   if (datahdr == WaveFileFormat.DATA_MAGIC) {
  367                       // we've found the 'data' chunk
  368                       break;
  369                   } else {
  370                       // else not 'data', skip this chunk
  371                       int thisLength = rllong(dis); nread += 4;
  372                       if (thisLength % 2 > 0) thisLength++;
  373                       nread += dis.skipBytes(thisLength);
  374                   }
  375               } catch (EOFException eof) {
  376                   // we've reached the end of the file without finding the 'data' chunk
  377                   throw new UnsupportedAudioFileException("Not a valid WAV file");
  378               }
  379           }
  380           // this is the length of the data chunk
  381           int dataLength = rllong(dis); nread += 4;
  382   
  383           // now build the new AudioFileFormat and return
  384   
  385           AudioFormat format = new AudioFormat(encoding,
  386                                                (float)sampleRate,
  387                                                sampleSizeInBits, channels,
  388                                                calculatePCMFrameSize(sampleSizeInBits, channels),
  389                                                (float)sampleRate, false);
  390   
  391           return new WaveFileFormat(AudioFileFormat.Type.WAVE,
  392                                     totallength,
  393                                     format,
  394                                     dataLength / format.getFrameSize());
  395       }
  396   
  397   }

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]