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 + -
显示快捷键?