static int _os_lacing_expand(ref ogg_stream_state os, int needed) { if (os.lacing_storage <= os.lacing_fill + needed) { void *ret = _ogg_realloc(os.lacing_vals, (os.lacing_storage + needed + 32) * sizeof(int)); if (ret == null) { ogg_stream_clear(ref os); return(-1); } os.lacing_vals = (int *)ret; ret = _ogg_realloc(os.granule_vals, (os.lacing_storage + needed + 32) * sizeof(long)); if (ret == null) { ogg_stream_clear(ref os); return(-1); } os.granule_vals = (long *)ret; os.lacing_storage += (needed + 32); } return(0); }
static public int ogg_stream_packetin(ref ogg_stream_state os, ref ogg_packet op) { ogg_iovec_t[] iov = new ogg_iovec_t[1]; iov[0].iov_base = op.packet; iov[0].iov_len = op.bytes; return(ogg_stream_iovecin(ref os, ref iov, 1, op.e_o_s, op.granulepos)); }
static public int ogg_stream_packetpeek(ref ogg_stream_state os, ref ogg_packet op) { if (ogg_stream_check(ref os) != 0) { return(0); } else { return(_packetout(ref os, ref op, 0)); } }
static public int ogg_stream_eos(ref ogg_stream_state os) { if (ogg_stream_check(ref os) != 0) { return(1); } else { return(os.e_o_s); } }
static public int ogg_stream_reset_serialno(ref ogg_stream_state os, int serialno) { if (ogg_stream_check(ref os) != 0) { return(-1); } ogg_stream_reset(ref os); os.serialno = serialno; return(0); }
static public int ogg_stream_clear(ref ogg_stream_state os) { if (os == null) { return(-1); } if (os.header != null) { _ogg_free(os.header); } if (os.body_data != null) { _ogg_free(os.body_data); } if (os.lacing_vals != null) { _ogg_free(os.lacing_vals); } if (os.granule_vals != null) { _ogg_free(os.granule_vals); } os.body_data = null; os.body_storage = 0; os.body_fill = 0; os.body_returned = 0; os.lacing_vals = null; os.granule_vals = null; os.lacing_storage = 1024; os.lacing_fill = 0; os.lacing_packet = 0; os.lacing_returned = 0; os.header = null; os.header_fill = 0; os.b_o_s = 0; os.e_o_s = 0; os.serialno = 0; os.pageno = 0; os.packetno = 0; os.granulepos = 0; return(0); }
static public int ogg_stream_check(ref ogg_stream_state os) { if (os == null) { return(-1); } else if (os.body_data == null) { return(-1); } else { return(0); } }
/* Like the above, but an argument is provided to adjust the nominal page size for applications which are smart enough to provide their * own delay based flushing */ static public int ogg_stream_pageout_fill(ref ogg_stream_state os, ref ogg_page og, int nfill) { int force = 0; if (ogg_stream_check(ref os) != 0) { return(0); } if ((os.e_o_s != 0 && os.lacing_fill != 0) || (os.lacing_fill != 0 && os.b_o_s == 0)) { force = 1; } return(ogg_stream_flush_i(ref os, ref og, force, nfill)); }
/* Helpers for ogg_stream_encode; this keeps the structure and what's happening fairly clear */ static int _os_body_expand(ref ogg_stream_state os, int needed) { if (os.body_storage <= os.body_fill + needed) { void *ret = _ogg_realloc(os.body_data, (os.body_storage + needed + 1024) * sizeof(byte)); if (ret == null) { ogg_stream_clear(ref os); return(-1); } os.body_storage += (needed + 1024); os.body_data = (byte *)ret; } return(0); }
static public int ogg_stream_init(ref ogg_stream_state os, int serialno) { if (ogg_stream_clear(ref os) != 0) { return(1); } os.body_storage = 16 * 1024; os.lacing_storage = 1024; os.header = (byte *)_ogg_malloc(ogg_stream_state.HEADER_SIZE); os.body_data = (byte *)_ogg_malloc(os.body_storage * sizeof(byte)); os.lacing_vals = (int *)_ogg_malloc(os.lacing_storage * sizeof(int)); os.granule_vals = (long *)_ogg_malloc(os.lacing_storage * sizeof(long)); if (os.header == null || os.body_data == null || os.lacing_vals == null || os.granule_vals == null) { return(-1); } os.serialno = serialno; return(0); }
static public int ogg_stream_reset(ref ogg_stream_state os) { if (ogg_stream_check(ref os) != 0) { return(-1); } os.body_fill = 0; os.body_returned = 0; os.lacing_fill = 0; os.lacing_packet = 0; os.lacing_returned = 0; os.header_fill = 0; os.e_o_s = 0; os.b_o_s = 0; os.pageno = -1; os.packetno = 0; os.granulepos = 0; return(0); }
public static extern int ogg_stream_flush_fill(ref ogg_stream_state os, ref ogg_page og, int fillbytes);
public static extern int ogg_stream_flush(ref ogg_stream_state os, ref ogg_page og);
public static extern int ogg_stream_packetin(ref ogg_stream_state os, ref ogg_packet op);
/* add the incoming page to the stream state; we decompose the page * into packet segments here as well. */ static public int ogg_stream_pagein(ref ogg_stream_state os, ref ogg_page og) { byte *header = og.header; byte *body = og.body; int bodysize = og.body_len; int version = ogg_page_version(ref og); int continued = ogg_page_continued(ref og); int bos = ogg_page_bos(ref og); int eos = ogg_page_eos(ref og); long granulepos = ogg_page_granulepos(ref og); int serialno = ogg_page_serialno(ref og); int pageno = ogg_page_pageno(ref og); int segments = header[26]; if (ogg_stream_check(ref os) != 0) { return(-1); } /* clean up 'returned data' */ { int lr = os.lacing_returned; int br = os.body_returned; /* body data */ if (br > 0) { os.body_fill -= br; if (os.body_fill > 0) { CopyMemory(os.body_data, os.body_data + br, os.body_fill); } os.body_returned = 0; } /* segment table */ if (lr > 0) { if (os.lacing_fill - lr > 0) { CopyMemory(os.lacing_vals, os.lacing_vals + lr, (os.lacing_fill - lr) * sizeof(int)); } else { CopyMemory(os.granule_vals, os.granule_vals + lr, (os.lacing_fill - lr) * sizeof(long)); } } os.lacing_fill -= lr; os.lacing_packet -= lr; os.lacing_returned = 0; } /* check the serial number */ if (serialno != os.serialno) { return(-1); } if (version > 0) { return(-1); } if (_os_lacing_expand(ref os, segments + 1) != 0) { return(-1); } /* are we in sequence? */ if (pageno != os.pageno) { /* unroll previous partial packet (if any) */ for (int i = os.lacing_packet; i < os.lacing_fill; i++) { os.body_fill -= os.lacing_vals[i] & 0xff; } os.lacing_fill = os.lacing_packet; /* make a note of dropped data in segment table */ if (os.pageno != -1) { os.lacing_vals[os.lacing_fill++] = 0x400; os.lacing_packet++; } } int segptr = 0; /* are we a 'continued packet' page? If so, we may need to skip some segments */ if (continued != 0) { if (os.lacing_fill < 1 || os.lacing_vals[os.lacing_fill - 1] == 0x400) { bos = 0; for (segptr = 0; segptr < segments; segptr++) { int val = header[27 + segptr]; body += val; bodysize -= val; if (val < 255) { segptr++; break; } } } } if (bodysize > 0) { if (_os_body_expand(ref os, bodysize) != 0) { return(-1); } CopyMemory(os.body_data + os.body_fill, body, bodysize); os.body_fill += bodysize; } int saved = -1; while (segptr < segments) { int val = og.header[27 + segptr]; os.lacing_vals[os.lacing_fill] = val; os.granule_vals[os.lacing_fill] = -1; if (bos != 0) { os.lacing_vals[os.lacing_fill] |= 0x100; bos = 0; } if (val < 255) { saved = os.lacing_fill; } os.lacing_fill++; segptr++; if (val < 255) { os.lacing_packet = os.lacing_fill; } } if (saved != -1) { os.granule_vals[saved] = granulepos; } if (eos != 0) { os.e_o_s = 1; if (os.lacing_fill > 0) { os.lacing_vals[os.lacing_fill - 1] |= 0x200; } } os.pageno = pageno + 1; return(0); }
static public int _packetout(ref ogg_stream_state os, ref ogg_packet op, int adv) { /* 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 = os.lacing_returned; if (os.lacing_packet <= ptr) { return(0); } /* we need to tell the codec there's a gap; it might need to handle previous packet dependencies. */ if ((os.lacing_vals[ptr] & 0x400) != 0) { os.lacing_returned++; os.packetno++; return(-1); } /* just using peek as an inexpensive way to ask if there's a whole packet waiting */ if (op == null && adv == 0) { return(1); } /* Gather the whole packet. We'll have no holes or a partial packet */ { int size = os.lacing_vals[ptr] & 0xff; int bytes = size; int eos = os.lacing_vals[ptr] & 0x200; int bos = os.lacing_vals[ptr] & 0x100; while (size == 255) { int val = os.lacing_vals[++ptr]; size = val & 0xff; if ((val & 0x200) != 0) { eos = 0x200; } bytes += size; } if (op != null) { op.e_o_s = eos; op.b_o_s = bos; op.packet = os.body_data + os.body_returned; op.packetno = os.packetno; op.granulepos = os.granule_vals[ptr]; op.bytes = bytes; } if (adv != 0) { os.body_returned += bytes; os.lacing_returned = ptr + 1; os.packetno++; } } return(1); }
public static extern int ogg_stream_reset_serialno(ref ogg_stream_state os, int serialno);
public static extern int ogg_stream_clear(ref ogg_stream_state os);
public static extern int ogg_stream_init(ref ogg_stream_state os, int serialno);
/* submit data to the internal buffer of the framing engine */ static public int ogg_stream_iovecin(ref ogg_stream_state os, ref ogg_iovec_t[] iov, int count, int e_o_s, long granulepos) { int bytes = 0; int lacing_vals; int i; if (ogg_stream_check(ref os) != 0) { return(-1); } for (i = 0; i < count; ++i) { bytes += iov[i].iov_len; } lacing_vals = bytes / 255 + 1; if (os.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 */ os.body_fill -= os.body_returned; if (os.body_fill > 0) { CopyMemory(os.body_data, os.body_data + os.body_returned, os.body_fill); } os.body_returned = 0; } /* make sure we have the buffer storage */ if (_os_body_expand(ref os, bytes) != 0 || _os_lacing_expand(ref os, lacing_vals) != 0) { return(-1); } /* 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 */ for (i = 0; i < count; i++) { CopyMemory(os.body_data + os.body_fill, iov[i].iov_base, iov[i].iov_len); os.body_fill += (int)iov[i].iov_len; } /* Store lacing vals for this packet */ for (i = 0; i < lacing_vals - 1; i++) { os.lacing_vals[os.lacing_fill + i] = 255; os.granule_vals[os.lacing_fill + i] = os.granulepos; } os.lacing_vals[os.lacing_fill + i] = bytes % 255; os.granulepos = os.granule_vals[os.lacing_fill + i] = granulepos; /* flag the first segment as the beginning of the packet */ os.lacing_vals[os.lacing_fill] |= 0x100; os.lacing_fill += lacing_vals; /* for the sake of completeness */ os.packetno++; if (e_o_s != 0) { os.e_o_s = 1; } return(0); }
static public int ogg_stream_packetpeek(ref ogg_stream_state os) { ogg_packet op_null = null; return(ogg_stream_packetpeek(ref os, ref op_null)); }
static public int ogg_stream_destroy(ref ogg_stream_state os) { ogg_stream_clear(ref os); return(0); }
public static extern int ogg_stream_check(ref ogg_stream_state os);
/* Conditionally flush a page; force==0 will only flush nominal-size pages, force==1 forces us to flush a page regardless of page size so long as there's any data available at all. */ static public int ogg_stream_flush_i(ref ogg_stream_state os, ref ogg_page og, int force, int nfill) { int i; int vals = 0; int maxvals = (os.lacing_fill > 255 ? 255 : os.lacing_fill); int bytes = 0; int acc = 0; long granule_pos = -1; if (ogg_stream_check(ref os) != 0) { return(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 (os.b_o_s == 0) /* 'initial header page' case */ { granule_pos = 0; for (vals = 0; vals < maxvals; vals++) { if ((os.lacing_vals[vals] & 0xff) < 255) { vals++; break; } } } else { int packets_done = 0; int packet_just_done = 0; for (vals = 0; vals < maxvals; vals++) { if (acc > nfill && packet_just_done >= 4) { force = 1; break; } acc += os.lacing_vals[vals] & 0xff; if ((os.lacing_vals[vals] & 0xff) < 255) { granule_pos = os.granule_vals[vals]; packet_just_done = ++packets_done; } else { packet_just_done = 0; } if (vals == 255) { force = 1; } } } if (force == 0) { return(0); } /* construct the header in temp storage */ os.header[0] = (byte)'O'; os.header[1] = (byte)'g'; os.header[2] = (byte)'g'; os.header[3] = (byte)'S'; /* stream structure version */ os.header[4] = 0; /* continued packet flag? */ os.header[5] = 0; if ((os.lacing_vals[0] & 0x100) == 0) { os.header[5] += 0x01; } /* first page flag? */ if (os.b_o_s == 0) { os.header[5] += 0x02; } /* last page flag? */ if (os.e_o_s != 0 && os.lacing_fill == vals) { os.header[5] += 0x04; } os.b_o_s = 1; /* 64 bits of PCM position */ for (i = 6; i < 14; i++) { os.header[i] = (byte)(granule_pos & 0xff); granule_pos >>= 8; } /* 32 bits of stream serial number */ { long serialno = os.serialno; for (i = 14; i < 18; i++) { os.header[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 (os.pageno == -1) { /* because someone called stream_reset; this would be a strange thing to do in an encode stream, but it has plausible uses */ os.pageno = 0; } long pageno = os.pageno++; for (i = 18; i < 22; i++) { os.header[i] = (byte)(pageno & 0xff); pageno >>= 8; } /* zero for computation; filled in later */ os.header[22] = 0; os.header[23] = 0; os.header[24] = 0; os.header[25] = 0; /* segment table */ os.header[26] = (byte)(vals & 0xff); for (i = 0; i < vals; i++) { os.header[i + 27] = (byte)(os.lacing_vals[i] & 0xff); bytes += os.header[i + 27]; } /* set pointers in the ogg_page struct */ og.header = os.header; og.header_len = vals + 27; os.header_fill = vals + 27; og.body = os.body_data + os.body_returned; og.body_len = bytes; /* advance the lacing data and set the body_returned pointer */ os.lacing_fill -= vals; CopyMemory(os.lacing_vals, os.lacing_vals + vals, os.lacing_fill * sizeof(int)); CopyMemory(os.granule_vals, os.granule_vals + vals, os.lacing_fill * sizeof(long)); os.body_returned += bytes; /* calculate the checksum */ ogg_page_checksum_set(ref og); /* done */ return(1); }
public static extern int ogg_stream_reset(ref ogg_stream_state os);
/* 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 a page regardless of size in the middle of a stream. */ static public int ogg_stream_flush(ref ogg_stream_state os, ref ogg_page og) { return(ogg_stream_flush_i(ref os, ref og, 1, 4096)); }
public static extern int ogg_stream_destroy(ref ogg_stream_state os);
/* Like the above, but an argument is provided to adjust the nominal page size for applications which are smart enough to provide their * own delay based flushing */ static public int ogg_stream_flush_fill(ref ogg_stream_state os, ref ogg_page og, int nfill) { return(ogg_stream_flush_i(ref os, ref og, 1, nfill)); }