ogginputstream.java

来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 556 行 · 第 1/2 页

JAVA
556
字号
/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.jmex.audio.stream;

import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jcraft.jogg.Packet;
import com.jcraft.jogg.Page;
import com.jcraft.jogg.StreamState;
import com.jcraft.jogg.SyncState;
import com.jcraft.jorbis.Block;
import com.jcraft.jorbis.Comment;
import com.jcraft.jorbis.DspState;
import com.jcraft.jorbis.Info;
import com.jmex.audio.filter.Filter;

/**
 * Decompresses an Ogg file as it streams from a source.
 *
 * @author Arman Ozcelik
 * @author Joshua Slack
 * @version $Id: OggInputStream.java,v 1.4 2007/08/20 10:28:29 rherlitz Exp $
 */
public class OggInputStream extends AudioInputStream {
    private static final Logger logger = Logger.getLogger(OggInputStream.class
            .getName());

    // temp vars
    private float[][][] _pcm = new float[1][][];
    private int[] _index;

    // end of stream
    private boolean eos = false;

    // sync and verify incoming physical bitstream
    private SyncState syncState = new SyncState(); 

    // take physical pages, weld into a logical stream of packets
    private StreamState streamState = new StreamState(); 

    // one Ogg bitstream page.  Vorbis packets are inside
    private Page page = new Page(); 

    // one raw packet of data for decode
    private Packet packet = new Packet(); 

    // struct that stores all the static vorbis bitstream settings
    private Info info = new Info(); 

    // struct that stores all the bitstream user comments
    private Comment comment = new Comment(); 

    // central working state for the packet->PCM decoder
    private DspState dspState = new DspState(); 

    // local working space for packet->PCM decode
    private Block block = new Block(dspState); 

    /// Conversion buffer size
    private int convsize = 4096 * 6;
    
    // Conversion buffer
    private byte[] convbuffer = new byte[convsize];
    
    // where we are in the convbuffer
    private int convbufferOff = 0;

    // bytes ready in convbuffer.
    private int convbufferSize = 0;

    // a dummy used by read() to read 1 byte.
    private byte readDummy[] = new byte[1];
    

    /**
     * Creates an OggInputStream that decompressed the specified ogg file.
     * @throws IOException 
     */
    public OggInputStream(URL resource, float length) throws IOException {
        super(resource, length);
        try {
            initVorbis();
            _index = new int[info.channels];
        } catch (Exception e) {
            logger.logp(Level.SEVERE, this.getClass().toString(),
                    "OggInputStream(URL resource, float lengt)", "Exception", e);
            eos = true;
        }
    }

    @Override
    public int getBitRate() {
        return info.rate;
    }

    @Override
    public int getDepth() {
        return 16;
    }


    /**
     * Reads the next byte of data from this input stream. The value byte is
     * returned as an int in the range 0 to 255. If no byte is available because
     * the end of the stream has been reached, the value -1 is returned. This
     * method blocks until input data is available, the end of the stream is
     * detected, or an exception is thrown. 
     * @return the next byte of data, or -1 if the end of the stream is reached.
     */
    public int read() throws IOException {
        int retVal = read(readDummy, 0, 1);
        return (retVal == -1 ? -1 : readDummy[0]);
    }

    
    /**
     * Reads up to len bytes of data from the input stream into an array of bytes.
     * @param b the buffer into which the data is read.
     * @param off the start offset of the data.
     * @param len the maximum number of bytes read.
     * @return the total number of bytes read into the buffer, or -1 if there is
     *         no more data because the end of the stream has been reached. 
     */
    public int read(byte b[], int off, int len) throws IOException {
        if (eos) {
            return -1;
        }

        int bytesRead = 0;
        while (!eos && (len > 0)) {
            fillConvbuffer();
            
            if (!eos) {
                int bytesToCopy = Math.min(len, convbufferSize-convbufferOff);
                System.arraycopy(convbuffer, convbufferOff, b, off, bytesToCopy);
                convbufferOff += bytesToCopy;
                bytesRead += bytesToCopy;
                len -= bytesToCopy;
                off += bytesToCopy;
            }
        }

        return bytesRead;
    }

    
    /**
     * Reads up to len bytes of data from the input stream into a ByteBuffer.
     * @param b the buffer into which the data is read.
     * @param off the start offset of the data.
     * @param len the maximum number of bytes read.
     * @return the total number of bytes read into the buffer, or -1 if there is
     *         no more data because the end of the stream has been reached. 
     */
    public int read(ByteBuffer b, int off, int len) throws IOException {
        byte[] buffer = new byte[b.capacity()];
        int bytesRead = read(buffer, off, len);
        if (bytesRead > 0 && filters.size() > 0) {
            Iterator<Filter> it = filters.iterator();
            while (it.hasNext()) {
                buffer = it.next().filter(buffer);
            }
        }
        b.put(buffer);
        b.position(off);
        return bytesRead;
    }


    /**
     * Helper function. Decodes a packet to the convbuffer if it is empty. 
     * Updates convbufferSize, convbufferOff, and eos.
     */
    private void fillConvbuffer() throws IOException {
        if (convbufferOff >= convbufferSize) {
            convbufferSize = lazyDecodePacket();
            convbufferOff = 0;
            if (convbufferSize == -1) {
                eos = true;
            }
        }
    }


    /**
     * Returns 0 after EOF is reached, otherwise always return 1.
     * <p>
     * Programs should not count on this method to return the actual number of
     * bytes that could be read without blocking.
     * @return 1 before EOF and 0 after EOF is reached. 
     */
    public int available() throws IOException {
        return (eos ? 0 : 1);
    }


    /**
     * OggInputStream does not support mark and reset. This function does nothing.
     */
    public void reset() throws IOException {
    }


    /**
     * OggInputStream does not support mark and reset.
     * @return false.
     */
    public boolean markSupported() {
        return false;
    }


    /**
     * Skips over and discards n bytes of data from the input stream. The skip
     * method may, for a variety of reasons, end up skipping over some smaller
     * number of bytes, possibly 0. The actual number of bytes skipped is returned. 
     * @param n the number of bytes to be skipped. 
     * @return the actual number of bytes skipped.
     */
    public long skip(long n) throws IOException {
        int bytesRead = 0;
        while (bytesRead < n) {
            int res = read();
            if (res == -1) {
                break;
            }

            bytesRead++;
        }
        
        return bytesRead;
    }
    
    
    /**
     * Initalizes the vorbis stream. Reads the stream until info and comment are read.
     */
    private void initVorbis() throws Exception {
        // Now we can read pages
        syncState.init(); 

        // grab some data at the head of the stream.  We want the first page

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?