From 9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e Mon Sep 17 00:00:00 2001 From: Michiel Van Der Kolk Date: Mon, 11 Jul 2005 15:42:37 +0000 Subject: Songdb java version, source. only 1.5 compatible git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657 --- songdbj/org/tritonus/lowlevel/pogg/Buffer.java | 284 +++++++++ songdbj/org/tritonus/lowlevel/pogg/Ogg.java | 104 +++ songdbj/org/tritonus/lowlevel/pogg/Packet.java | 133 ++++ songdbj/org/tritonus/lowlevel/pogg/Page.java | 298 +++++++++ .../org/tritonus/lowlevel/pogg/StreamState.java | 703 +++++++++++++++++++++ songdbj/org/tritonus/lowlevel/pogg/SyncState.java | 339 ++++++++++ songdbj/org/tritonus/lowlevel/pogg/package.html | 12 + 7 files changed, 1873 insertions(+) create mode 100644 songdbj/org/tritonus/lowlevel/pogg/Buffer.java create mode 100644 songdbj/org/tritonus/lowlevel/pogg/Ogg.java create mode 100644 songdbj/org/tritonus/lowlevel/pogg/Packet.java create mode 100644 songdbj/org/tritonus/lowlevel/pogg/Page.java create mode 100644 songdbj/org/tritonus/lowlevel/pogg/StreamState.java create mode 100644 songdbj/org/tritonus/lowlevel/pogg/SyncState.java create mode 100644 songdbj/org/tritonus/lowlevel/pogg/package.html (limited to 'songdbj/org/tritonus/lowlevel/pogg') diff --git a/songdbj/org/tritonus/lowlevel/pogg/Buffer.java b/songdbj/org/tritonus/lowlevel/pogg/Buffer.java new file mode 100644 index 0000000000..6d94c37740 --- /dev/null +++ b/songdbj/org/tritonus/lowlevel/pogg/Buffer.java @@ -0,0 +1,284 @@ +/* + * Buffer.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 - 2005 by Matthias Pfisterer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.lowlevel.pogg; + +import java.io.UnsupportedEncodingException; + +import org.tritonus.share.TDebug; + + +/** Wrapper for oggpack_buffer. + */ +public class Buffer +{ + static + { + Ogg.loadNativeLibrary(); + if (TDebug.TraceOggNative) + { + setTrace(true); + } + } + + + /** + * Holds the pointer to oggpack_buffer + * for the native code. + * This must be long to be 64bit-clean. + */ + private long m_lNativeHandle; + + + + public Buffer() + { + if (TDebug.TraceOggNative) { TDebug.out("Buffer.(): begin"); } + int nReturn = malloc(); + if (nReturn < 0) + { + throw new RuntimeException("malloc of ogg_page failed"); + } + if (TDebug.TraceOggNative) { TDebug.out("Buffer.(): end"); } + } + + + + public void finalize() + { + // TODO: call free() + // call super.finalize() first or last? + // and introduce a flag if free() has already been called? + } + + + + private native int malloc(); + public native void free(); + + + /** Calls oggpack_writeinit(). + */ + public native void writeInit(); + + + /** Calls oggpack_writetrunc(). + */ + public native void writeTrunc(int nBits); + + + /** Calls oggpack_writealign(). + */ + public native void writeAlign(); + + + /** Calls oggpack_writecopy(). + */ + public native void writeCopy(byte[] abSource, int nBits); + + + /** Calls oggpack_reset(). + */ + public native void reset(); + + + /** Calls oggpack_writeclear(). + */ + public native void writeClear(); + + + /** Calls oggpack_readinit(). + */ + public native void readInit(byte[] abBuffer, int nBytes); + + + /** Calls oggpack_write(). + */ + public native void write(int nValue, int nBits); + + + /** Calls oggpack_look(). + */ + public native int look(int nBits); + + + /** Calls oggpack_look1(). + */ + public native int look1(); + + + /** Calls oggpack_adv(). + */ + public native void adv(int nBits); + + + /** Calls oggpack_adv1(). + */ + public native void adv1(); + + + /** Calls oggpack_read(). + */ + public native int read(int nBits); + + + /** Calls oggpack_read1(). + */ + public native int read1(); + + + /** Calls oggpack_bytes(). + */ + public native int bytes(); + + + /** Calls oggpack_bits(). + */ + public native int bits(); + + + /** Calls oggpack_get_buffer(). + */ + public native byte[] getBuffer(); + + + /** Writes a string as UTF-8. + Note: no length coding and no end byte are written, + just the pure string! + */ + public void write(String str) + { + write(str, false); + } + + + /** Writes a string as UTF-8, including a length coding. + In front of the string, the length in bytes is written + as a 32 bit integer. No end byte is written. + */ + public void writeWithLength(String str) + { + write(str, true); + } + + + /** Writes a string as UTF-8, with or without a length coding. + If a length coding is requested, the length in (UTF8-)bytes is written + as a 32 bit integer in front of the string. + No end byte is written. + */ + private void write(String str, boolean bWithLength) + { + byte[] aBytes = null; + try + { + aBytes = str.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException e) + { + if (TDebug.TraceAllExceptions) TDebug.out(e); + } + if (bWithLength) + { + write(aBytes.length, 32); + } + for (int i = 0; i < aBytes.length; i++) + { + write(aBytes[i], 8); + } + } + + + /** Reads a UTF-8 coded string with length coding. + It is expected that at the current read position, + there is a 32 bit integer containing the length in (UTF8-)bytes, + followed by the specified number of bytes in UTF-8 coding. + + @return the string read from the buffer or null if an error occurs. + */ + public String readString() + { + int length = read(32); + if (length < 0) + { + return null; + } + return readString(length); + } + + + /** Reads a UTF-8 coded string without length coding. + It is expected that at the current read position, + there is string in UTF-8 coding. + + @return the string read from the buffer or null if an error occurs. + */ + public String readString(int nLength) + { + byte[] aBytes = new byte[nLength]; + for (int i = 0; i < nLength; i++) + { + aBytes[i] = (byte) read(8); + } + String s = null; + try + { + s = new String(aBytes, "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + if (TDebug.TraceAllExceptions) TDebug.out(e); + } + return s; + } + + + /** Reads a single bit. + */ + public boolean readFlag() + { + return (read(1) != 0); + } + + private static native void setTrace(boolean bTrace); + + // for debugging + public static void outBuffer(byte[] buffer) + { + String s = ""; + for (int i = 0; i < buffer.length; i++) + { + s += "" + buffer[i] + ", "; + } + TDebug.out("buffer: " + s); + } +} + + + +/*** Buffer.java ***/ diff --git a/songdbj/org/tritonus/lowlevel/pogg/Ogg.java b/songdbj/org/tritonus/lowlevel/pogg/Ogg.java new file mode 100644 index 0000000000..086dd0f001 --- /dev/null +++ b/songdbj/org/tritonus/lowlevel/pogg/Ogg.java @@ -0,0 +1,104 @@ +/* + * Ogg.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 - 2001 by Matthias Pfisterer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.lowlevel.pogg; + +import org.tritonus.share.TDebug; + + +/** libogg loading. + */ +public class Ogg +{ + private static boolean sm_bIsLibraryAvailable = false; + + + + static + { + Ogg.loadNativeLibrary(); + } + + + + public static void loadNativeLibrary() + { + if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): begin"); } + + if (! isLibraryAvailable()) + { + loadNativeLibraryImpl(); + } + if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): end"); } + } + + + + /** Load the native library for ogg vorbis. + + This method actually does the loading of the library. Unlike + {@link loadNativeLibrary() loadNativeLibrary()}, it does not + check if the library is already loaded. + + */ + private static void loadNativeLibraryImpl() + { + if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loading native library tritonuspvorbis"); } + try + { + System.loadLibrary("tritonuspvorbis"); + // only reached if no exception occures + sm_bIsLibraryAvailable = true; + } + catch (Error e) + { + if (TDebug.TraceOggNative || + TDebug.TraceAllExceptions) + { + TDebug.out(e); + } + // throw e; + } + if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loaded"); } + } + + + + /** Returns whether the libraries are installed correctly. + */ + public static boolean isLibraryAvailable() + { + return sm_bIsLibraryAvailable; + } +} + + + +/*** Ogg.java ***/ diff --git a/songdbj/org/tritonus/lowlevel/pogg/Packet.java b/songdbj/org/tritonus/lowlevel/pogg/Packet.java new file mode 100644 index 0000000000..15c5d9a66e --- /dev/null +++ b/songdbj/org/tritonus/lowlevel/pogg/Packet.java @@ -0,0 +1,133 @@ +/* + * Packet.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 - 2001 by Matthias Pfisterer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.lowlevel.pogg; + +import org.tritonus.share.TDebug; + + + +/** Wrapper for ogg_packet. + */ +public class Packet +{ + static + { + Ogg.loadNativeLibrary(); + if (TDebug.TraceOggNative) + { + setTrace(true); + } + } + + + /** + * Holds the pointer to ogg_packet + * for the native code. + * This must be long to be 64bit-clean. + */ + private long m_lNativeHandle; + + + + public Packet() + { + if (TDebug.TraceOggNative) { TDebug.out("Packet.(): begin"); } + int nReturn = malloc(); + if (nReturn < 0) + { + throw new RuntimeException("malloc of ogg_packet failed"); + } + if (TDebug.TraceOggNative) { TDebug.out("Packet.(): end"); } + } + + + + public void finalize() + { + // TODO: call free() + // call super.finalize() first or last? + // and introduce a flag if free() has already been called? + } + + + + private native int malloc(); + public native void free(); + + + + /** Calls ogg_packet_clear(). + */ + public native void clear(); + + + + /** Accesses packet and bytes. + */ + public native byte[] getData(); + + + /** Accesses b_o_s. + */ + public native boolean isBos(); + + + /** Accesses e_o_s. + */ + public native boolean isEos(); + + + public native long getGranulePos(); + + + public native long getPacketNo(); + + + /** Sets the data in the packet. + */ + public native void setData(byte[] abData, int nOffset, int nLength); + + + public native void setFlags(boolean bBos, boolean bEos, long lGranulePos, + long lPacketNo); + + public void setFlags(boolean bBos, boolean bEos, long lGranulePos) + { + setFlags(bBos, bEos, lGranulePos, 0); + } + + + private static native void setTrace(boolean bTrace); +} + + + + + +/*** Packet.java ***/ diff --git a/songdbj/org/tritonus/lowlevel/pogg/Page.java b/songdbj/org/tritonus/lowlevel/pogg/Page.java new file mode 100644 index 0000000000..3f89d7166e --- /dev/null +++ b/songdbj/org/tritonus/lowlevel/pogg/Page.java @@ -0,0 +1,298 @@ +/* + * Page.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 - 2001 by Matthias Pfisterer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.lowlevel.pogg; + +import org.tritonus.share.TDebug; + + + +/** Wrapper for ogg_page. + */ +public class Page +{ + private static final int[] crc_lookup = + { + 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9, + 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, + 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61, + 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, + 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9, + 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, + 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011, + 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, + 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039, + 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, + 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81, + 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, + 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49, + 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, + 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1, + 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, + 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae, + 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, + 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16, + 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, + 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde, + 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, + 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066, + 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, + 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e, + 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, + 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6, + 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, + 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e, + 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, + 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686, + 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, + 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637, + 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, + 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f, + 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, + 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47, + 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, + 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff, + 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, + 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7, + 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, + 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f, + 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, + 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7, + 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, + 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f, + 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, + 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640, + 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, + 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8, + 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, + 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30, + 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, + 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088, + 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, + 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0, + 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, + 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18, + 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, + 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0, + 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, + 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668, + 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4 + }; + + + private byte[] m_abHeader; + private int m_nHeaderLength; + private byte[] m_abBody; + private int m_nBodyLength; + + + public Page() + { + if (TDebug.TraceOggNative) { TDebug.out("Page.(): begin"); } + if (TDebug.TraceOggNative) { TDebug.out("Page.(): end"); } + } + + + + private native int malloc(); + + // TODO: remove calls to this method + public void free() + { + } + + + /** Calls ogg_page_version(). + */ + public int getVersion() + { + return m_abHeader[4] & 0xFF; + } + + + /** Calls ogg_page_continued(). + */ + public boolean isContinued() + { + return (m_abHeader[5] & 0x01) != 0; + } + + + + /** Calls ogg_page_packets(). + */ +/* returns the number of packets that are completed on this page (if + the leading packet is begun on a previous page, but ends on this + page, it's counted */ + +/* NOTE: +If a page consists of a packet begun on a previous page, and a new +packet begun (but not completed) on this page, the return will be: + ogg_page_packets(page) ==1, + ogg_page_continued(page) !=0 + +If a page happens to be a single packet that was begun on a +previous page, and spans to the next page (in the case of a three or +more page packet), the return will be: + ogg_page_packets(page) ==0, + ogg_page_continued(page) !=0 +*/ + public int getPackets() + { + int n = m_abHeader[26] & 0xFF; + int count = 0; + for (int i = 0; i < n; i++) + if ((m_abHeader[27 + i] & 0xFF) < 255) + count++; + return count; + } + + + + /** Calls ogg_page_bos(). + */ + public boolean isBos() + { + return (m_abHeader[5] & 0x02) != 0; + } + + + + /** Calls ogg_page_eos(). + */ + public boolean isEos() + { + return (m_abHeader[5] & 0x04) != 0; + } + + + + /** Calls ogg_page_granulepos(). + */ + public long getGranulePos() + { + long granulepos = m_abHeader[13]&(0xff); + granulepos = (granulepos<<8)|(m_abHeader[12] & 0xFF); + granulepos = (granulepos<<8)|(m_abHeader[11] & 0xFF); + granulepos = (granulepos<<8)|(m_abHeader[10] & 0xFF); + granulepos = (granulepos<<8)|(m_abHeader[9] & 0xFF); + granulepos = (granulepos<<8)|(m_abHeader[8] & 0xFF); + granulepos = (granulepos<<8)|(m_abHeader[7] & 0xFF); + granulepos = (granulepos<<8)|(m_abHeader[6] & 0xFF); + return granulepos; + } + + + + /** Calls ogg_page_serialno(). + */ + public int getSerialNo() + { + return m_abHeader[14] | + (m_abHeader[15] << 8) | + (m_abHeader[16] << 16) | + (m_abHeader[17] << 24); + } + + + + /** Calls ogg_page_pageno(). + */ + public int getPageNo() + { + return m_abHeader[18] | + (m_abHeader[19] << 8) | + (m_abHeader[20] << 16) | + (m_abHeader[21] << 24); + } + + + + /** Calls ogg_page_checksum_set(). + */ + public void setChecksum() + { + int crc_reg = 0; + + /* safety; needed for API behavior, but not framing code */ + m_abHeader[22]=0; + m_abHeader[23]=0; + m_abHeader[24]=0; + m_abHeader[25]=0; + + for(int i = 0; i < m_nHeaderLength; i++) + crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (m_abHeader[i] & 0xFF)]; + for(int i = 0; i < m_nBodyLength; i++) + crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (m_abBody[i] & 0xFF)]; + + m_abHeader[22] = (byte) (crc_reg & 0xff); + m_abHeader[23] = (byte) ((crc_reg >> 8) & 0xff); + m_abHeader[24] = (byte) ((crc_reg >> 16) & 0xff); + m_abHeader[25] = (byte) ((crc_reg >> 24) & 0xff); + } + + + + + public byte[] getHeader() + { + byte[] abHeader = new byte[m_nHeaderLength]; + System.arraycopy(m_abHeader, 0, abHeader, 0, m_nHeaderLength); + return abHeader; + } + + + + public byte[] getBody() + { + byte[] abBody = new byte[m_nBodyLength]; + System.arraycopy(m_abBody, 0, abBody, 0, m_nBodyLength); + return abBody; + } + + + + public void setData(byte[] abHeader, int nHeaderOffset, + int nHeaderLength, + byte[] abBody, int nBodyOffset, + int nBodyLength) + { + m_abHeader = new byte[nHeaderLength]; + System.arraycopy(abHeader, nHeaderOffset, m_abHeader, 0, nHeaderLength); + m_nHeaderLength = nHeaderLength; + m_abBody = new byte[nBodyLength]; + System.arraycopy(abBody, nBodyOffset, m_abBody, 0, nBodyLength); + m_nBodyLength = nBodyLength; + } +} + + + + + +/*** Page.java ***/ diff --git a/songdbj/org/tritonus/lowlevel/pogg/StreamState.java b/songdbj/org/tritonus/lowlevel/pogg/StreamState.java new file mode 100644 index 0000000000..3fde33de8f --- /dev/null +++ b/songdbj/org/tritonus/lowlevel/pogg/StreamState.java @@ -0,0 +1,703 @@ +/* + * StreamState.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 - 2005 by Matthias Pfisterer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.lowlevel.pogg; + +import org.tritonus.share.TDebug; + + +/** Wrapper for ogg_stream_state. + */ +public class StreamState +{ + private static final int INITIAL_BODY_DATA_SIZE = 16 * 1024; + private static final int INITIAL_LACING_VALUES_SIZE = 1024; + + /** The serial number of the stream. + This is set by init(). + */ + private int m_nSerialNo; + + /** Storage for packet bodies. + */ + private byte[] m_abBodyData; + + /** Number of bytes used in te body storage. + */ + private int m_nBodyFill; + + /** Number of bytes aready returned (as pages) from the body storage. + */ + private int m_nBodyReturned; + + /** Lacing values. Bit 0 to 7 contain the lacing value (mask + 0xFF). Bit 8 is set if the segment belongs to the first + packet of the stream (mask 0x100). Bit 9 is set ig the + segment belongs to the last packet of the stream (mask 0x200). + */ + private int[] m_anLacingValues; + + /** Granule values. + */ + private long[] m_alGranuleValues; + + /** Number of elements used in m_anLacingValues and m_alGranuleValues. + The elements with the index m_nLacingFill is the first free element. + */ + private int m_nLacingFill; + + /** Pointer to the index in m_anLacingValues where the lacing values + of the last decoded packet start (??) + */ + private int m_nLacingPacket; + + /** + */ + private int m_nLacingReturned; + + private byte[] m_abHeader; + + private int m_nHeaderFill; + + private boolean m_bBos; + private boolean m_bEos; + private int m_nPageNo; + private long m_lPacketNo; + private long m_lGranulePos; + + + + public StreamState() + { + if (TDebug.TraceOggNative) { TDebug.out("StreamState.(): begin"); } + if (TDebug.TraceOggNative) { TDebug.out("StreamState.(): end"); } + } + + + + public void free() + { + } + + + + /** Calls ogg_stream_init(). + */ + public int init(int nSerialNo) + { + m_nSerialNo = nSerialNo; + m_abBodyData = new byte[INITIAL_BODY_DATA_SIZE]; + m_nBodyFill = 0; + m_nBodyReturned = 0; + m_anLacingValues = new int[INITIAL_LACING_VALUES_SIZE]; + m_alGranuleValues = new long[INITIAL_LACING_VALUES_SIZE]; + m_nLacingFill = 0; + m_nLacingPacket = 0; + m_nLacingReturned = 0; + + m_abHeader = new byte[282]; + m_nHeaderFill = 0; + + m_bBos = false; + m_bEos = false; + m_nPageNo = 0; + m_lPacketNo = 0; + m_lGranulePos = 0; + + // TODO: necessary? + for (int i = 0; i < m_abBodyData.length; i++) + m_abBodyData[i] = 0; + for (int i = 0; i < m_anLacingValues.length; i++) + m_anLacingValues[i] = 0; + for (int i = 0; i < m_alGranuleValues.length; i++) + m_alGranuleValues[i] = 0; + + // TODO: remove return value + return 0; + } + + /** Calls ogg_stream_clear(). + */ + public int clear() + { + m_nSerialNo = 0; + m_abBodyData = null; + m_nBodyFill = 0; + m_nBodyReturned = 0; + m_anLacingValues = null; + m_alGranuleValues = null; + m_nLacingFill = 0; + m_nLacingPacket = 0; + m_nLacingReturned = 0; + + m_abHeader = null; + m_nHeaderFill = 0; + + m_bBos = false; + m_bEos = false; + m_nPageNo = 0; + m_lPacketNo = 0; + m_lGranulePos = 0; + + // TODO: remove return value + return 0; + } + + /** Calls ogg_stream_reset(). + */ + public int reset() + { + m_nBodyFill = 0; + m_nBodyReturned = 0; + + m_nLacingFill = 0; + m_nLacingPacket = 0; + m_nLacingReturned = 0; + + m_nHeaderFill = 0; + + m_bBos = false; + m_bEos = false; + m_nPageNo = -1; + m_lPacketNo = 0; + m_lGranulePos = 0; + + // TODO: remove return value + return 0; + } + + /** Calls ogg_stream_eos(). + */ + public boolean isEOSReached() + { + return m_bEos; + } + + /** Calls ogg_stream_packetin(). + */ + /* submit data to the internal buffer of the framing engine */ + public int packetIn(Packet packet) + { + int i; + byte[] abPacketData = packet.getData(); + int lacing_vals = abPacketData.length / 255 + 1; + + if (m_nBodyReturned > 0) + { + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + m_nBodyFill -= m_nBodyReturned; + if (m_nBodyFill > 0) + { + System.arraycopy(m_abBodyData, m_nBodyReturned, + m_abBodyData, 0, m_nBodyFill); + } + m_nBodyReturned = 0; + } + + /* make sure we have the buffer storage */ + assureBodyDataCapacity(abPacketData.length); + assureLacingValuesCapacity(lacing_vals); + + /* Copy in the submitted packet. Yes, the copy is a waste; + this is the liability of overly clean abstraction for the + time being. It will actually be fairly easy to eliminate + the extra copy in the future */ + System.arraycopy(abPacketData, 0, m_abBodyData, m_nBodyFill, + abPacketData.length); + m_nBodyFill += abPacketData.length; + + /* Store lacing vals for this packet */ + for (i = 0; i < lacing_vals - 1; i++) + { + m_anLacingValues[m_nLacingFill + i] = 255; + m_alGranuleValues[m_nLacingFill + i] = m_lGranulePos; + } + m_anLacingValues[m_nLacingFill + i] = abPacketData.length % 255; + m_alGranuleValues[m_nLacingFill + i] = packet.getGranulePos(); + m_lGranulePos = packet.getGranulePos(); + + /* flag the first segment as the beginning of the packet */ + m_anLacingValues[m_nLacingFill] |= 0x100; + + m_nLacingFill += lacing_vals; + + /* for the sake of completeness */ + m_lPacketNo++; + + if (packet.isEos()) + m_bEos = true; + return 0; + } + + + + /** Calls ogg_stream_pageout(). + */ +/* This constructs pages from buffered packet segments. The pointers + returned are to static buffers; do not free. The returned buffers are + good only until the next call (using the same ogg_stream_state) */ + public int pageOut(Page page) + { + if ((m_bEos && m_nLacingFill > 0) || /* 'were done, now flush' */ + m_nBodyFill - m_nBodyReturned > 4096 || /* 'page nominal size' */ + m_nLacingFill >= 255 || /* 'segment table full' */ + (m_nLacingFill > 0 && ! m_bBos)) /* 'initial header page' */ + { + return flush(page); + } + /* not enough data to construct a page and not end of stream */ + return 0; + } + + + + /** Calls ogg_stream_flush(). + */ +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not guarantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + since ogg_stream_flush will flush the last page in a stream even if + it's undersized, you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you specifically need to flush + an page regardless of size in the middle of a stream. +*/ + public int flush(Page page) + { + int i; + int vals = 0; + int maxvals = Math.min(m_nLacingFill, 255); + int bytes = 0; + int acc = 0; + long granule_pos = m_alGranuleValues[0]; + + if (maxvals == 0) + { + return 0; + } + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must + only include the initial header packet */ + if (! m_bBos) + { /* 'initial header page' case */ + granule_pos = 0; + for (vals = 0; vals < maxvals; vals++) + { + if ((m_anLacingValues[vals] & 0x0FF) < 255) + { + vals++; + break; + } + } + } + else + { + for (vals = 0; vals < maxvals; vals++) + { + if (acc > 4096) + break; + acc += (m_anLacingValues[vals] & 0x0FF); + granule_pos = m_alGranuleValues[vals]; + } + } + + /* construct the header in temp storage */ + m_abHeader[0] = (byte) 'O'; + m_abHeader[1] = (byte) 'g'; + m_abHeader[2] = (byte) 'g'; + m_abHeader[3] = (byte) 'S'; + + /* stream structure version */ + m_abHeader[4] = 0; + + m_abHeader[5] = 0x00; + /* continued packet flag? */ + if ((m_anLacingValues[0] & 0x100) == 0) + m_abHeader[5] |= 0x01; + /* first page flag? */ + if (! m_bBos) + m_abHeader[5] |= 0x02; + /* last page flag? */ + if (m_bEos && m_nLacingFill == vals) + m_abHeader[5] |= 0x04; + m_bBos = true; + + /* 64 bits of PCM position */ + for (i = 6; i < 14; i++) + { + m_abHeader[i] = (byte) (granule_pos & 0xFF); + granule_pos >>>= 8; + } + + /* 32 bits of stream serial number */ + int serialno = m_nSerialNo; + for (i = 14; i < 18; i++) + { + m_abHeader[i] = (byte) (serialno & 0xFF); + serialno >>>= 8; + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if (m_nPageNo == -1) + { + m_nPageNo = 0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + } + int pageno = m_nPageNo++; + for (i = 18; i < 22; i++) + { + m_abHeader[i] = (byte) (pageno & 0xFF); + pageno >>>= 8; + } + + /* zero for computation; filled in later */ + m_abHeader[22] = 0; + m_abHeader[23] = 0; + m_abHeader[24] = 0; + m_abHeader[25] = 0; + + /* segment table */ + m_abHeader[26] = (byte) (vals & 0xFF); + for (i = 0; i < vals; i++) + { + m_abHeader[i + 27] = (byte) (m_anLacingValues[i] & 0xFF); + bytes += (m_anLacingValues[i] & 0xFF); + } + + /* set pointers in the ogg_page struct */ + page.setData(m_abHeader, 0, vals + 27, + m_abBodyData, m_nBodyReturned, bytes); + m_nHeaderFill = vals + 27; + + /* advance the lacing data and set the body_returned pointer */ + + m_nLacingFill -= vals; + System.arraycopy(m_anLacingValues, vals, m_anLacingValues, 0, + m_nLacingFill); + System.arraycopy(m_alGranuleValues, vals, m_alGranuleValues, 0, + m_nLacingFill); + m_nBodyReturned += bytes; + + /* calculate the checksum */ + + page.setChecksum(); + + /* done */ + return 1; + } + + + + /** add the incoming page to the stream state; we decompose the + page into packet segments here as well. + + @return 0 on success, -1 if the stream serial number stored in + the page does not match the one stored in the stream state or + if the protocol version stored in the page is greater than 0. + */ + public int pageIn(Page page) + { + byte[] header = page.getHeader(); + byte[] body = page.getBody(); + int nBodyOffset = 0; + int bodysize = body.length; + int segptr = 0; + + int version = page.getVersion(); + boolean continued = page.isContinued(); + boolean bos = page.isBos(); + boolean eos = page.isEos(); + long granulepos = page.getGranulePos(); + int serialno = page.getSerialNo(); + int pageno = page.getPageNo(); + int segments = header[26] & 0xFF; + + /* clean up 'returned data' */ + int lr = m_nLacingReturned; + int br = m_nBodyReturned; + + /* body data */ + if (br > 0) + { + m_nBodyFill -= br; + if (m_nBodyFill > 0) + { + System.arraycopy(m_abBodyData, br, m_abBodyData, 0, + m_nBodyFill); + } + m_nBodyReturned = 0; + } + + if (lr > 0) + { + /* segment table */ + if (m_nLacingFill - lr > 0) + { + System.arraycopy(m_anLacingValues, lr, m_anLacingValues, 0, + m_nLacingFill - lr); + System.arraycopy(m_alGranuleValues, lr, m_alGranuleValues, 0, + m_nLacingFill - lr); + } + m_nLacingFill -= lr; + m_nLacingPacket -= lr; + m_nLacingReturned = 0; + } + + /* check the serial number */ + if (serialno != m_nSerialNo) + return -1; + if (version > 0) + return -1; + + assureLacingValuesCapacity(segments + 1); + + /* are we in sequence? */ + if (pageno != m_nPageNo) + { + int i; + + /* unroll previous partial packet (if any) */ + for (i = m_nLacingPacket; i < m_nLacingFill; i++) + m_nBodyFill -= (m_anLacingValues[i] & 0xFF); + m_nLacingFill = m_nLacingPacket; + + /* make a note of dropped data in segment table */ + if (m_nPageNo != -1) + { + m_anLacingValues[m_nLacingFill] = 0x400; + m_nLacingFill++; + m_nLacingPacket++; + } + + /* are we a 'continued packet' page? If so, we'll need to skip + some segments */ + if (continued) + { + bos = false; + for (; segptr < segments; segptr++) + { + int val = header[27 + segptr] & 0xFF; + nBodyOffset += val; + bodysize -= val; + if (val < 255) + { + segptr++; + break; + } + } + } + } + + if (bodysize > 0) + { + assureBodyDataCapacity(bodysize); + System.arraycopy(body, nBodyOffset, m_abBodyData, m_nBodyFill, + bodysize); + m_nBodyFill += bodysize; + } + + int saved = -1; + while (segptr < segments) + { + int val = header[27 + segptr] & 0xFF; + m_anLacingValues[m_nLacingFill] = val; + m_alGranuleValues[m_nLacingFill] = -1; + + if (bos) + { + m_anLacingValues[m_nLacingFill] |= 0x100; + bos = false; + } + + if (val < 255) + saved = m_nLacingFill; + + m_nLacingFill++; + segptr++; + + if (val < 255) + m_nLacingPacket = m_nLacingFill; + } + + /* set the granulepos on the last granuleval of the last full packet */ + if (saved != -1) + { + m_alGranuleValues[saved] = granulepos; + } + + if (eos) + { + m_bEos = true; + if (m_nLacingFill > 0) + m_anLacingValues[m_nLacingFill - 1] |= 0x200; + } + + m_nPageNo = pageno + 1; + + return 0; + } + + + /** Calls ogg_stream_packetout(). + */ + public int packetOut(Packet packet) + { + return packetOutInternal(packet, true); + } + + + /** Calls ogg_stream_packetpeek(). + */ + public int packetPeek(Packet packet) + { + return packetOutInternal(packet, false); + } + + + /** Retrieves a packet from the internal storage for emission. + This method is called by packetOut and packetPeek. + + @param packet the Packet object to store the retrieved packet + data in. May be null if bAdvance is false. + + @param bAdvance should the internal pointers to the packet + data storage be advanced to the next packet after retrieving + this one? Called with a value of true for ordinary packet out + and with a value of false for packet peek. + + @return + */ + private int packetOutInternal(Packet packet, boolean bAdvance) + { + /* The last part of decode. We have the stream broken into + packet segments. Now we need to group them into packets + (or return the out of sync markers) */ + + int ptr = m_nLacingReturned; + + if (m_nLacingPacket <= ptr) + return 0; + + if ((m_anLacingValues[ptr] & 0x400) != 0) + { + /* we need to tell the codec there's a gap; it might need + to handle previous packet dependencies. */ + m_nLacingReturned++; + m_lPacketNo++; + return -1; + } + + if (packet == null && ! bAdvance) + return 1; /* just using peek as an inexpensive way + to ask if there's a whole packet + waiting */ + + /* Gather the whole packet. We'll have no holes or a partial + * packet */ + int size = m_anLacingValues[ptr] & 0xFF; + int bytes = size; + /* last packet of the stream? */ + boolean eos = (m_anLacingValues[ptr] & 0x200) != 0; + /* first packet of the stream? */ + boolean bos = (m_anLacingValues[ptr] & 0x100) != 0; + + while (size == 255) + { + int val = m_anLacingValues[++ptr]; + size = val & 0xff; + if ((val & 0x200) != 0) + eos = true; + bytes += size; + } + + if (packet != null) + { + packet.setData(m_abBodyData, m_nBodyReturned, bytes); + packet.setFlags(bos, eos, m_alGranuleValues[ptr], m_lPacketNo); + } + + if (bAdvance) + { + m_nBodyReturned += bytes; + m_nLacingReturned = ptr + 1; + m_lPacketNo++; + } + return 1; + } + + + private void assureBodyDataCapacity(int needed) + { + if (m_abBodyData.length <= m_nBodyFill + needed) + { + int nNewSize = m_abBodyData.length + needed + 1024; + byte[] abNewBodyData = new byte[nNewSize]; + System.arraycopy(m_abBodyData, 0, abNewBodyData, 0, + m_abBodyData.length); + m_abBodyData = abNewBodyData; + } + } + + + + private void assureLacingValuesCapacity(int needed) + { + if (m_anLacingValues.length <= m_nLacingFill + needed) + { + int nNewSize = m_anLacingValues.length + needed + 32; + int[] anNewLacingValues = new int[nNewSize]; + System.arraycopy(m_anLacingValues, 0, anNewLacingValues, 0, + m_anLacingValues.length); + m_anLacingValues = anNewLacingValues; + long[] alNewGranuleValues = new long[nNewSize]; + System.arraycopy(m_alGranuleValues, 0, alNewGranuleValues, 0, + m_alGranuleValues.length); + m_alGranuleValues = alNewGranuleValues; + } + } +} + + + + + +/*** StreamState.java ***/ diff --git a/songdbj/org/tritonus/lowlevel/pogg/SyncState.java b/songdbj/org/tritonus/lowlevel/pogg/SyncState.java new file mode 100644 index 0000000000..4246808bd3 --- /dev/null +++ b/songdbj/org/tritonus/lowlevel/pogg/SyncState.java @@ -0,0 +1,339 @@ +/* + * SyncState.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 - 2005 by Matthias Pfisterer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.lowlevel.pogg; + +import org.tritonus.share.TDebug; + + +/** Wrapper for ogg_sync_state. + */ +public class SyncState +{ + /** The stream buffer. + This points to a buffer that holds the incoming data from a stream + until the data is emitted in form of a page. + */ + private byte[] m_abData; + + /** The number of bytes in the stream buffer that are used. This + always counts from the beginning of the buffer. So + m_abData[m_nFill] is the first free byte in the buffer. + */ + private int m_nFill; + + /** Number of bytes that have been used to construct a returned + page. This is counted from the beginning of the + buffer. m_abData[m_nReturned] is the first valid byte in the + buffer. + */ + private int m_nReturned; + + /** + */ + private boolean m_bUnsynced; + + /** + */ + private int m_nHeaderBytes; + + /** + */ + private int m_nBodyBytes; + + /** Page object for re-calculating the checksum. + */ + private Page m_tmpPage; + + /** Storage for the checksum saved from the page. + */ + private byte[] m_abChecksum; + + + public SyncState() + { + if (TDebug.TraceOggNative) { TDebug.out("SyncState.(): begin"); } + m_tmpPage = new Page(); + m_abChecksum = new byte[4]; + if (TDebug.TraceOggNative) { TDebug.out("SyncState.(): end"); } + } + + + // TODO: remove calls to this method + public void free() + { + } + + + + /** Calls ogg_sync_init(). + */ + public void init() + { + m_abData = null; + m_nFill = 0; + m_nReturned = 0; + m_bUnsynced = false; + m_nHeaderBytes = 0; + m_nBodyBytes = 0; + } + + + /** Calls ogg_sync_clear(). + */ + public void clear() + { + init(); + } + + + /** Calls ogg_sync_reset(). + */ + public void reset() + { + m_nFill = 0; + m_nReturned = 0; + m_bUnsynced = false; + m_nHeaderBytes = 0; + m_nBodyBytes = 0; + } + + + /** Writes to the stream buffer. + */ + public int write(byte[] abBuffer, int nBytes) + { + /* Clear out space that has been previously returned. */ + if (m_nReturned > 0) + { + m_nFill -= m_nReturned; + if (m_nFill > 0) + { + System.arraycopy(m_abData, m_nReturned, + m_abData, 0, + m_nFill); + } + m_nReturned = 0; + } + + /* Check for enough space in the stream buffer and if it is + * allocated at all. If there isn't sufficient space, extend + * the buffer. */ + if (m_abData == null || nBytes > m_abData.length - m_nFill) + { + int nNewSize = nBytes + m_nFill + 4096; + byte[] abOldBuffer = m_abData; + m_abData = new byte[nNewSize]; + if (abOldBuffer != null) + { + System.arraycopy(abOldBuffer, 0, m_abData, 0, m_nFill); + } + } + + /* Now finally fill with the new data. */ + System.arraycopy(abBuffer, 0, m_abData, m_nFill, nBytes); + m_nFill += nBytes; + return 0; + } + + + /** Synchronizes the stream. This method looks if there is a + complete, valid page in the stream buffer. If a page is found, + it is returned in the passed Page object. + + @param page The Page to store the result of the page search + in. The content is only changed if the return value is > 0. + + @return if a page has been found at the current location, the + length of the page in bytes is returned. If not enough data + for a page is available in the stream buffer, 0 is + returned. If data in the stream buffer has been skipped + because there is no page at the current position, the skip + amount in bytes is returned as a negative number. + */ + public int pageseek(Page page) + { + int nPage = m_nReturned; + int nBytes = m_nFill - m_nReturned; + + if (m_nHeaderBytes == 0) + { + if (nBytes < 27) + { + /* Not enough data for a header. */ + return 0; + } + /* Verify capture pattern. */ + if (m_abData[nPage] != (byte) 'O' || + m_abData[nPage + 1] != (byte) 'g' || + m_abData[nPage + 2] != (byte) 'g' || + m_abData[nPage + 3] != (byte) 'S') + { + TDebug.out("wrong capture pattern"); + return syncFailure(); + } + int nHeaderBytes = (m_abData[nPage + 26] & 0xFF) + 27; + if (nBytes < nHeaderBytes) + { + /* Not enough data for header + segment table. */ + return 0; + } + /* Count up body length in the segment table. */ + for (int i = 0; i < (m_abData[nPage + 26] & 0xFF); i++) + { + m_nBodyBytes += (m_abData[nPage + 27 + i] & 0xFF); + } + m_nHeaderBytes = nHeaderBytes; + } + + if (m_nBodyBytes + m_nHeaderBytes > nBytes) + { + /* Not enough data for the whole packet. */ + return 0; + } + + /* Save the original checksum, set it to zero and recalculate it. */ + System.arraycopy(m_abData, nPage + 22, m_abChecksum, 0, 4); + m_abData[nPage + 22] = 0; + m_abData[nPage + 23] = 0; + m_abData[nPage + 24] = 0; + m_abData[nPage + 25] = 0; + + m_tmpPage.setData(m_abData, nPage, m_nHeaderBytes, + m_abData, nPage + m_nHeaderBytes, m_nBodyBytes); +// TDebug.out("temporary page:"); +// byte[] abHeader = m_tmpPage.getHeader(); +// TDebug.out("H0:" + m_abData[nPage + 0] + " - " + abHeader[0]); +// TDebug.out("H1:" + m_abData[nPage + 1] + " - " + abHeader[1]); +// TDebug.out("H2:" + m_abData[nPage + 2] + " - " + abHeader[2]); +// TDebug.out("H3:" + m_abData[nPage + 3] + " - " + abHeader[3]); +// TDebug.out("" + m_abChecksum[0] + " - " + abHeader[22]); +// TDebug.out("" + m_abChecksum[1] + " - " + abHeader[23]); +// TDebug.out("" + m_abChecksum[2] + " - " + abHeader[24]); +// TDebug.out("" + m_abChecksum[3] + " - " + abHeader[25]); + m_tmpPage.setChecksum(); + byte[] abHeader = m_tmpPage.getHeader(); + //m_tmpPage.free(); + if (abHeader[22] != m_abChecksum[0] || + abHeader[23] != m_abChecksum[1] || + abHeader[24] != m_abChecksum[2] || + abHeader[25] != m_abChecksum[3]) + { + TDebug.out("wrong checksum"); + TDebug.out("" + m_abChecksum[0] + " - " + abHeader[22]); + TDebug.out("" + m_abChecksum[1] + " - " + abHeader[23]); + TDebug.out("" + m_abChecksum[2] + " - " + abHeader[24]); + TDebug.out("" + m_abChecksum[3] + " - " + abHeader[25]); + /* Copy back the saved checksum. */ + System.arraycopy(m_abChecksum, 0, m_abData, nPage + 22, 4); + return syncFailure(); + } + + /* Ok, we have a correct page to emit. */ + page.setData(m_abData, nPage, m_nHeaderBytes, + m_abData, nPage + m_nHeaderBytes, m_nBodyBytes); + m_bUnsynced = false; + nBytes = m_nHeaderBytes + m_nBodyBytes; + m_nReturned += nBytes; + m_nHeaderBytes = 0; + m_nBodyBytes = 0; + return nBytes; + } + + + /** Auxiliary method for pageseek(). + */ + private int syncFailure() + { + int nPage = m_nReturned; + int nBytes = m_nFill - m_nReturned; + m_nHeaderBytes = 0; + m_nBodyBytes = 0; + int nNext = -1; + for (int i = 0; i < nBytes - 1; i++) + { + if (m_abData[nPage + 1 + i] == (byte) 'O') + { + nNext = nPage + 1 + i; + break; + } + } + if (nNext == -1) + { + nNext = m_nFill; + } + m_nReturned = nNext; + return -(nNext - nPage); + } + + + + + /** Returns a page from the stream buffer, if possible. This + method searches the current data in the stream buffer for the + beginning of a page. If there is one, it is returned in the + passed Page object. A synchronization error is signaled by a + return value of -1. However, only the first synchronization + error is reported. Consecutive sync errors are suppressed. + + @param page The Page to store the result of the page search + in. The content is only changed if the return value is 1. + + @return 1 if a page has been found, 0 if there is not enough + data, -1 if a synchronization error occured. + */ + public int pageOut(Page page) + { + while (true) + { + int nReturn = pageseek(page); + if (nReturn > 0) + { + return 1; + } + else if (nReturn == 0) + { + return 0; + } + else // nReturn < 0 + { + if (! m_bUnsynced) + { + m_bUnsynced = true; + return -1; + } + } + } + } +} + + + + + +/*** SyncState.java ***/ diff --git a/songdbj/org/tritonus/lowlevel/pogg/package.html b/songdbj/org/tritonus/lowlevel/pogg/package.html new file mode 100644 index 0000000000..57b0e50763 --- /dev/null +++ b/songdbj/org/tritonus/lowlevel/pogg/package.html @@ -0,0 +1,12 @@ + + + + + + +

Alternative pure java implementation of the ogg library. + The classes provided here .

+ + @see org.tritonus.sampled.convert.pvorbis + + -- cgit v1.2.3