Path: blob/master/SLICK_HOME/src/org/newdawn/slick/openal/OggDecoder.java
1461 views
package org.newdawn.slick.openal;12import java.io.ByteArrayOutputStream;3import java.io.IOException;4import java.io.InputStream;5import java.nio.ByteBuffer;67/**8* Decode an OGG file to PCM data9*10* @author Kevin Glass11*/12public class OggDecoder {13/** The conversion buffer size */14private int convsize = 4096 * 4;15/** The buffer used to read OGG file */16private byte[] convbuffer = new byte[convsize]; // take 8k out of the data segment, not the stack1718/**19* Create a new OGG decoder20*/21public OggDecoder() {22}2324/**25* Get the data out of an OGG file26*27* @param input The input stream from which to read the OGG file28* @return The data describing the OGG thats been read29* @throws IOException Indicaites a failure to read the OGG file30*/31public OggData getData(InputStream input) throws IOException {32if (input == null) {33throw new IOException("Failed to read OGG, source does not exist?");34}35ByteArrayOutputStream dataout = new ByteArrayOutputStream();3637// SyncState oy = new SyncState(); // sync and verify incoming physical bitstream38// StreamState os = new StreamState(); // take physical pages, weld into a logical stream of packets39// Page og = new Page(); // one Ogg bitstream page. Vorbis packets are inside40// Packet op = new Packet(); // one raw packet of data for decode41//42// Info vi = new Info(); // struct that stores all the static vorbis bitstream settings43// Comment vc = new Comment(); // struct that stores all the bitstream user comments44// DspState vd = new DspState(); // central working state for the packet->PCM decoder45// Block vb = new Block(vd); // local working space for packet->PCM decode46//47// byte[] buffer;48// int bytes = 0;49//50// boolean bigEndian = ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN);51// // Decode setup52//53// oy.init(); // Now we can read pages54//55// while (true) { // we repeat if the bitstream is chained56// int eos = 0;57//58// // grab some data at the head of the stream. We want the first page59// // (which is guaranteed to be small and only contain the Vorbis60// // stream initial header) We need the first page to get the stream61// // serialno.62//63// // submit a 4k block to libvorbis' Ogg layer64// int index = oy.buffer(4096);65//66// buffer = oy.data;67// try {68// bytes = input.read(buffer, index, 4096);69// } catch (Exception e) {70// Log.error("Failure reading in vorbis");71// Log.error(e);72// System.exit(0);73// }74// oy.wrote(bytes);75//76// // Get the first page.77// if (oy.pageout(og) != 1) {78// // have we simply run out of data? If so, we're done.79// if (bytes < 4096)80// break;81//82// // error case. Must not be Vorbis data83// Log.error("Input does not appear to be an Ogg bitstream.");84// System.exit(0);85// }86//87// // Get the serial number and set up the rest of decode.88// // serialno first; use it to set up a logical stream89// os.init(og.serialno());90//91// // extract the initial header from the first page and verify that the92// // Ogg bitstream is in fact Vorbis data93//94// // I handle the initial header first instead of just having the code95// // read all three Vorbis headers at once because reading the initial96// // header is an easy way to identify a Vorbis bitstream and it's97// // useful to see that functionality seperated out.98//99// vi.init();100// vc.init();101// if (os.pagein(og) < 0) {102// // error; stream version mismatch perhaps103// Log.error("Error reading first page of Ogg bitstream data.");104// System.exit(0);105// }106//107// if (os.packetout(op) != 1) {108// // no page? must not be vorbis109// Log.error("Error reading initial header packet.");110// System.exit(0);111// }112//113// if (vi.synthesis_headerin(vc, op) < 0) {114// // error case; not a vorbis header115// Log.error("This Ogg bitstream does not contain Vorbis audio data.");116// System.exit(0);117// }118//119// // At this point, we're sure we're Vorbis. We've set up the logical120// // (Ogg) bitstream decoder. Get the comment and codebook headers and121// // set up the Vorbis decoder122//123// // The next two packets in order are the comment and codebook headers.124// // They're likely large and may span multiple pages. Thus we reead125// // and submit data until we get our two pacakets, watching that no126// // pages are missing. If a page is missing, error out; losing a127// // header page is the only place where missing data is fatal. */128//129// int i = 0;130// while (i < 2) {131// while (i < 2) {132//133// int result = oy.pageout(og);134// if (result == 0)135// break; // Need more data136// // Don't complain about missing or corrupt data yet. We'll137// // catch it at the packet output phase138//139// if (result == 1) {140// os.pagein(og); // we can ignore any errors here141// // as they'll also become apparent142// // at packetout143// while (i < 2) {144// result = os.packetout(op);145// if (result == 0)146// break;147// if (result == -1) {148// // Uh oh; data at some point was corrupted or missing!149// // We can't tolerate that in a header. Die.150// Log.error("Corrupt secondary header. Exiting.");151// System.exit(0);152// }153// vi.synthesis_headerin(vc, op);154// i++;155// }156// }157// }158// // no harm in not checking before adding more159// index = oy.buffer(4096);160// buffer = oy.data;161// try {162// bytes = input.read(buffer, index, 4096);163// } catch (Exception e) {164// Log.error("Failed to read Vorbis: ");165// Log.error(e);166// System.exit(0);167// }168// if (bytes == 0 && i < 2) {169// Log.error("End of file before finding all Vorbis headers!");170// System.exit(0);171// }172// oy.wrote(bytes);173// }174//175// convsize = 4096 / vi.channels;176//177// // OK, got and parsed all three headers. Initialize the Vorbis178// // packet->PCM decoder.179// vd.synthesis_init(vi); // central decode state180// vb.init(vd); // local state for most of the decode181// // so multiple block decodes can182// // proceed in parallel. We could init183// // multiple vorbis_block structures184// // for vd here185//186// float[][][] _pcm = new float[1][][];187// int[] _index = new int[vi.channels];188// // The rest is just a straight decode loop until end of stream189// while (eos == 0) {190// while (eos == 0) {191//192// int result = oy.pageout(og);193// if (result == 0)194// break; // need more data195// if (result == -1) { // missing or corrupt data at this page position196// Log.error("Corrupt or missing data in bitstream; continuing...");197// } else {198// os.pagein(og); // can safely ignore errors at199// // this point200// while (true) {201// result = os.packetout(op);202//203// if (result == 0)204// break; // need more data205// if (result == -1) { // missing or corrupt data at this page position206// // no reason to complain; already complained above207// } else {208// // we have a packet. Decode it209// int samples;210// if (vb.synthesis(op) == 0) { // test for success!211// vd.synthesis_blockin(vb);212// }213//214// // **pcm is a multichannel float vector. In stereo, for215// // example, pcm[0] is left, and pcm[1] is right. samples is216// // the size of each channel. Convert the float values217// // (-1.<=range<=1.) to whatever PCM format and write it out218//219// while ((samples = vd.synthesis_pcmout(_pcm,220// _index)) > 0) {221// float[][] pcm = _pcm[0];222// //boolean clipflag = false;223// int bout = (samples < convsize ? samples224// : convsize);225//226// // convert floats to 16 bit signed ints (host order) and227// // interleave228// for (i = 0; i < vi.channels; i++) {229// int ptr = i * 2;230// //int ptr=i;231// int mono = _index[i];232// for (int j = 0; j < bout; j++) {233// int val = (int) (pcm[i][mono + j] * 32767.);234// // short val=(short)(pcm[i][mono+j]*32767.);235// // int val=(int)Math.round(pcm[i][mono+j]*32767.);236// // might as well guard against clipping237// if (val > 32767) {238// val = 32767;239// //clipflag = true;240// }241// if (val < -32768) {242// val = -32768;243// //clipflag = true;244// }245// if (val < 0)246// val = val | 0x8000;247//248// if (bigEndian) {249// convbuffer[ptr] = (byte) (val >>> 8);250// convbuffer[ptr + 1] = (byte) (val);251// } else {252// convbuffer[ptr] = (byte) (val);253// convbuffer[ptr + 1] = (byte) (val >>> 8);254// }255// ptr += 2 * (vi.channels);256// }257// }258//259// dataout.write(convbuffer, 0, 2 * vi.channels * bout);260//261// vd.synthesis_read(bout); // tell libvorbis how262// // many samples we263// // actually consumed264// }265// }266// }267// if (og.eos() != 0)268// eos = 1;269// }270// }271// if (eos == 0) {272// index = oy.buffer(4096);273// if (index >= 0) {274// buffer = oy.data;275// try {276// bytes = input.read(buffer, index, 4096);277// } catch (Exception e) {278// Log.error("Failure during vorbis decoding");279// Log.error(e);280// return null;281// }282// } else {283// bytes = 0;284// }285// oy.wrote(bytes);286// if (bytes == 0)287// eos = 1;288// }289// }290//291// // clean up this logical bitstream; before exit we see if we're292// // followed by another [chained]293//294// os.clear();295//296// // ogg_page and ogg_packet structs always point to storage in297// // libvorbis. They're never freed or manipulated directly298//299// vb.clear();300// vd.clear();301// vi.clear(); // must be called last302// }303//304// // OK, clean up the framer305// oy.clear();306// OggData ogg = new OggData();307// ogg.channels = vi.channels;308// ogg.rate = vi.rate;309310OggInputStream oggInput = new OggInputStream(input);311312boolean done = false;313while (!oggInput.atEnd()) {314dataout.write(oggInput.read());315}316317OggData ogg = new OggData();318ogg.channels = oggInput.getChannels();319ogg.rate = oggInput.getRate();320321byte[] data = dataout.toByteArray();322ogg.data = ByteBuffer.allocateDirect(data.length);323ogg.data.put(data);324ogg.data.rewind();325326return ogg;327}328}329330331