mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 10:58:15 -05:00
Update #44 - WebAssembly GC support, fix more WebRTC bugs
This commit is contained in:
538
sources/wasm-gc-teavm/java/com/jcraft/jogg/StreamState.java
Normal file
538
sources/wasm-gc-teavm/java/com/jcraft/jogg/StreamState.java
Normal file
@ -0,0 +1,538 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.jcraft.jogg;
|
||||
|
||||
public class StreamState {
|
||||
byte[] body_data; /* bytes from packet bodies */
|
||||
int body_storage; /* storage elements allocated */
|
||||
int body_fill; /* elements stored; fill mark */
|
||||
private int body_returned; /* elements of fill returned */
|
||||
|
||||
int[] lacing_vals; /* The values that will go to the segment table */
|
||||
long[] granule_vals; /*
|
||||
* pcm_pos values for headers. Not compact this way, but it is simple coupled to
|
||||
* the lacing fifo
|
||||
*/
|
||||
int lacing_storage;
|
||||
int lacing_fill;
|
||||
int lacing_packet;
|
||||
int lacing_returned;
|
||||
|
||||
byte[] header = new byte[282]; /* working space for header encode */
|
||||
int header_fill;
|
||||
|
||||
public int e_o_s; /*
|
||||
* set when we have buffered the last packet in the logical bitstream
|
||||
*/
|
||||
int b_o_s; /*
|
||||
* set after we've written the initial page of a logical bitstream
|
||||
*/
|
||||
int serialno;
|
||||
int pageno;
|
||||
long packetno; /*
|
||||
* sequence number for decode; the framing knows where there's a hole in the
|
||||
* data, but we need coupling so that the codec (which is in a seperate
|
||||
* abstraction layer) also knows about the gap
|
||||
*/
|
||||
long granulepos;
|
||||
|
||||
public StreamState() {
|
||||
init();
|
||||
}
|
||||
|
||||
StreamState(int serialno) {
|
||||
this();
|
||||
init(serialno);
|
||||
}
|
||||
|
||||
void init() {
|
||||
body_storage = 16 * 1024;
|
||||
body_data = new byte[body_storage];
|
||||
lacing_storage = 1024;
|
||||
lacing_vals = new int[lacing_storage];
|
||||
granule_vals = new long[lacing_storage];
|
||||
}
|
||||
|
||||
public void init(int serialno) {
|
||||
if (body_data == null) {
|
||||
init();
|
||||
} else {
|
||||
for (int i = 0; i < body_data.length; i++)
|
||||
body_data[i] = 0;
|
||||
for (int i = 0; i < lacing_vals.length; i++)
|
||||
lacing_vals[i] = 0;
|
||||
for (int i = 0; i < granule_vals.length; i++)
|
||||
granule_vals[i] = 0;
|
||||
}
|
||||
this.serialno = serialno;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
body_data = null;
|
||||
lacing_vals = null;
|
||||
granule_vals = null;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void body_expand(int needed) {
|
||||
if (body_storage <= body_fill + needed) {
|
||||
body_storage += (needed + 1024);
|
||||
byte[] foo = new byte[body_storage];
|
||||
System.arraycopy(body_data, 0, foo, 0, body_data.length);
|
||||
body_data = foo;
|
||||
}
|
||||
}
|
||||
|
||||
void lacing_expand(int needed) {
|
||||
if (lacing_storage <= lacing_fill + needed) {
|
||||
lacing_storage += (needed + 32);
|
||||
int[] foo = new int[lacing_storage];
|
||||
System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
|
||||
lacing_vals = foo;
|
||||
|
||||
long[] bar = new long[lacing_storage];
|
||||
System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
|
||||
granule_vals = bar;
|
||||
}
|
||||
}
|
||||
|
||||
/* submit data to the internal buffer of the framing engine */
|
||||
public int packetin(Packet op) {
|
||||
int lacing_val = op.bytes / 255 + 1;
|
||||
|
||||
if (body_returned != 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
|
||||
*/
|
||||
|
||||
body_fill -= body_returned;
|
||||
if (body_fill != 0) {
|
||||
System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned = 0;
|
||||
}
|
||||
|
||||
/* make sure we have the buffer storage */
|
||||
body_expand(op.bytes);
|
||||
lacing_expand(lacing_val);
|
||||
|
||||
/*
|
||||
* 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(op.packet_base, op.packet, body_data, body_fill, op.bytes);
|
||||
body_fill += op.bytes;
|
||||
|
||||
/* Store lacing vals for this packet */
|
||||
int j;
|
||||
for (j = 0; j < lacing_val - 1; j++) {
|
||||
lacing_vals[lacing_fill + j] = 255;
|
||||
granule_vals[lacing_fill + j] = granulepos;
|
||||
}
|
||||
lacing_vals[lacing_fill + j] = (op.bytes) % 255;
|
||||
granulepos = granule_vals[lacing_fill + j] = op.granulepos;
|
||||
|
||||
/* flag the first segment as the beginning of the packet */
|
||||
lacing_vals[lacing_fill] |= 0x100;
|
||||
|
||||
lacing_fill += lacing_val;
|
||||
|
||||
/* for the sake of completeness */
|
||||
packetno++;
|
||||
|
||||
if (op.e_o_s != 0)
|
||||
e_o_s = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int packetout(Packet op) {
|
||||
|
||||
/*
|
||||
* 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 = lacing_returned;
|
||||
|
||||
if (lacing_packet <= ptr) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((lacing_vals[ptr] & 0x400) != 0) {
|
||||
/* We lost sync here; let the app know */
|
||||
lacing_returned++;
|
||||
|
||||
/*
|
||||
* we need to tell the codec there's a gap; it might need to handle previous
|
||||
* packet dependencies.
|
||||
*/
|
||||
packetno++;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Gather the whole packet. We'll have no holes or a partial packet */
|
||||
{
|
||||
int size = lacing_vals[ptr] & 0xff;
|
||||
int bytes = 0;
|
||||
|
||||
op.packet_base = body_data;
|
||||
op.packet = body_returned;
|
||||
op.e_o_s = lacing_vals[ptr] & 0x200; /* last packet of the stream? */
|
||||
op.b_o_s = lacing_vals[ptr] & 0x100; /* first packet of the stream? */
|
||||
bytes += size;
|
||||
|
||||
while (size == 255) {
|
||||
int val = lacing_vals[++ptr];
|
||||
size = val & 0xff;
|
||||
if ((val & 0x200) != 0)
|
||||
op.e_o_s = 0x200;
|
||||
bytes += size;
|
||||
}
|
||||
|
||||
op.packetno = packetno;
|
||||
op.granulepos = granule_vals[ptr];
|
||||
op.bytes = bytes;
|
||||
|
||||
body_returned += bytes;
|
||||
|
||||
lacing_returned = ptr + 1;
|
||||
}
|
||||
packetno++;
|
||||
return (1);
|
||||
}
|
||||
|
||||
// add the incoming page to the stream state; we decompose the page
|
||||
// into packet segments here as well.
|
||||
|
||||
public int pagein(Page og) {
|
||||
byte[] header_base = og.header_base;
|
||||
int header = og.header;
|
||||
byte[] body_base = og.body_base;
|
||||
int body = og.body;
|
||||
int bodysize = og.body_len;
|
||||
int segptr = 0;
|
||||
|
||||
int version = og.version();
|
||||
int continued = og.continued();
|
||||
int bos = og.bos();
|
||||
int eos = og.eos();
|
||||
long granulepos = og.granulepos();
|
||||
int _serialno = og.serialno();
|
||||
int _pageno = og.pageno();
|
||||
int segments = header_base[header + 26] & 0xff;
|
||||
|
||||
// clean up 'returned data'
|
||||
{
|
||||
int lr = lacing_returned;
|
||||
int br = body_returned;
|
||||
|
||||
// body data
|
||||
if (br != 0) {
|
||||
body_fill -= br;
|
||||
if (body_fill != 0) {
|
||||
System.arraycopy(body_data, br, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned = 0;
|
||||
}
|
||||
|
||||
if (lr != 0) {
|
||||
// segment table
|
||||
if ((lacing_fill - lr) != 0) {
|
||||
System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill - lr);
|
||||
System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill - lr);
|
||||
}
|
||||
lacing_fill -= lr;
|
||||
lacing_packet -= lr;
|
||||
lacing_returned = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check the serial number
|
||||
if (_serialno != serialno)
|
||||
return (-1);
|
||||
if (version > 0)
|
||||
return (-1);
|
||||
|
||||
lacing_expand(segments + 1);
|
||||
|
||||
// are we in sequence?
|
||||
if (_pageno != pageno) {
|
||||
int i;
|
||||
|
||||
// unroll previous partial packet (if any)
|
||||
for (i = lacing_packet; i < lacing_fill; i++) {
|
||||
body_fill -= lacing_vals[i] & 0xff;
|
||||
// System.out.println("??");
|
||||
}
|
||||
lacing_fill = lacing_packet;
|
||||
|
||||
// make a note of dropped data in segment table
|
||||
if (pageno != -1) {
|
||||
lacing_vals[lacing_fill++] = 0x400;
|
||||
lacing_packet++;
|
||||
}
|
||||
|
||||
// are we a 'continued packet' page? If so, we'll need to skip
|
||||
// some segments
|
||||
if (continued != 0) {
|
||||
bos = 0;
|
||||
for (; segptr < segments; segptr++) {
|
||||
int val = (header_base[header + 27 + segptr] & 0xff);
|
||||
body += val;
|
||||
bodysize -= val;
|
||||
if (val < 255) {
|
||||
segptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bodysize != 0) {
|
||||
body_expand(bodysize);
|
||||
System.arraycopy(body_base, body, body_data, body_fill, bodysize);
|
||||
body_fill += bodysize;
|
||||
}
|
||||
|
||||
{
|
||||
int saved = -1;
|
||||
while (segptr < segments) {
|
||||
int val = (header_base[header + 27 + segptr] & 0xff);
|
||||
lacing_vals[lacing_fill] = val;
|
||||
granule_vals[lacing_fill] = -1;
|
||||
|
||||
if (bos != 0) {
|
||||
lacing_vals[lacing_fill] |= 0x100;
|
||||
bos = 0;
|
||||
}
|
||||
|
||||
if (val < 255)
|
||||
saved = lacing_fill;
|
||||
|
||||
lacing_fill++;
|
||||
segptr++;
|
||||
|
||||
if (val < 255)
|
||||
lacing_packet = lacing_fill;
|
||||
}
|
||||
|
||||
/* set the granulepos on the last pcmval of the last full packet */
|
||||
if (saved != -1) {
|
||||
granule_vals[saved] = granulepos;
|
||||
}
|
||||
}
|
||||
|
||||
if (eos != 0) {
|
||||
e_o_s = 1;
|
||||
if (lacing_fill > 0)
|
||||
lacing_vals[lacing_fill - 1] |= 0x200;
|
||||
}
|
||||
|
||||
pageno = _pageno + 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 gurantee that all
|
||||
* packets have flushed. Only a return value of 0 from ogg_stream_flush
|
||||
* indicates all packet data is flushed into pages.
|
||||
*
|
||||
* ogg_stream_page 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 need to flush an undersized page in the middle
|
||||
* of a stream for some reason.
|
||||
*/
|
||||
|
||||
public int flush(Page og) {
|
||||
|
||||
int i;
|
||||
int vals = 0;
|
||||
int maxvals = (lacing_fill > 255 ? 255 : lacing_fill);
|
||||
int bytes = 0;
|
||||
int acc = 0;
|
||||
long granule_pos = granule_vals[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 (b_o_s == 0) { /* 'initial header page' case */
|
||||
granule_pos = 0;
|
||||
for (vals = 0; vals < maxvals; vals++) {
|
||||
if ((lacing_vals[vals] & 0x0ff) < 255) {
|
||||
vals++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (vals = 0; vals < maxvals; vals++) {
|
||||
if (acc > 4096)
|
||||
break;
|
||||
acc += (lacing_vals[vals] & 0x0ff);
|
||||
granule_pos = granule_vals[vals];
|
||||
}
|
||||
}
|
||||
|
||||
/* construct the header in temp storage */
|
||||
System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
|
||||
|
||||
/* stream structure version */
|
||||
header[4] = 0x00;
|
||||
|
||||
/* continued packet flag? */
|
||||
header[5] = 0x00;
|
||||
if ((lacing_vals[0] & 0x100) == 0)
|
||||
header[5] |= 0x01;
|
||||
/* first page flag? */
|
||||
if (b_o_s == 0)
|
||||
header[5] |= 0x02;
|
||||
/* last page flag? */
|
||||
if (e_o_s != 0 && lacing_fill == vals)
|
||||
header[5] |= 0x04;
|
||||
b_o_s = 1;
|
||||
|
||||
/* 64 bits of PCM position */
|
||||
for (i = 6; i < 14; i++) {
|
||||
header[i] = (byte) granule_pos;
|
||||
granule_pos >>>= 8;
|
||||
}
|
||||
|
||||
/* 32 bits of stream serial number */
|
||||
{
|
||||
int _serialno = serialno;
|
||||
for (i = 14; i < 18; i++) {
|
||||
header[i] = (byte) _serialno;
|
||||
_serialno >>>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 32 bits of page counter (we have both counter and page header because this
|
||||
* val can roll over)
|
||||
*/
|
||||
if (pageno == -1)
|
||||
pageno = 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 = pageno++;
|
||||
for (i = 18; i < 22; i++) {
|
||||
header[i] = (byte) _pageno;
|
||||
_pageno >>>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* zero for computation; filled in later */
|
||||
header[22] = 0;
|
||||
header[23] = 0;
|
||||
header[24] = 0;
|
||||
header[25] = 0;
|
||||
|
||||
/* segment table */
|
||||
header[26] = (byte) vals;
|
||||
for (i = 0; i < vals; i++) {
|
||||
header[i + 27] = (byte) lacing_vals[i];
|
||||
bytes += (header[i + 27] & 0xff);
|
||||
}
|
||||
|
||||
/* set pointers in the ogg_page struct */
|
||||
og.header_base = header;
|
||||
og.header = 0;
|
||||
og.header_len = header_fill = vals + 27;
|
||||
og.body_base = body_data;
|
||||
og.body = body_returned;
|
||||
og.body_len = bytes;
|
||||
|
||||
/* advance the lacing data and set the body_returned pointer */
|
||||
|
||||
lacing_fill -= vals;
|
||||
System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill * 4);
|
||||
System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill * 8);
|
||||
body_returned += bytes;
|
||||
|
||||
/* calculate the checksum */
|
||||
|
||||
og.checksum();
|
||||
|
||||
/* done */
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 og) {
|
||||
if ((e_o_s != 0 && lacing_fill != 0) || /* 'were done, now flush' case */
|
||||
body_fill - body_returned > 4096 || /* 'page nominal size' case */
|
||||
lacing_fill >= 255 || /* 'segment table full' case */
|
||||
(lacing_fill != 0 && b_o_s == 0)) { /* 'initial header page' case */
|
||||
return flush(og);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int eof() {
|
||||
return e_o_s;
|
||||
}
|
||||
|
||||
public int reset() {
|
||||
body_fill = 0;
|
||||
body_returned = 0;
|
||||
|
||||
lacing_fill = 0;
|
||||
lacing_packet = 0;
|
||||
lacing_returned = 0;
|
||||
|
||||
header_fill = 0;
|
||||
|
||||
e_o_s = 0;
|
||||
b_o_s = 0;
|
||||
pageno = -1;
|
||||
packetno = 0;
|
||||
granulepos = 0;
|
||||
return (0);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user