/* sync the stream and get a page. Keep trying until we find a page. * Suppress 'sync errors' after reporting the first. * * return values: * -1) recapture (hole in data) * 0) need more data * 1) page returned * * Returns pointers into buffered data; invalidated by next call to * _stream, _clear, _init, or _buffer */ static public int ogg_sync_pageout(ref ogg_sync_state oy, ref ogg_page og) { if (ogg_sync_check(ref oy) != 0) { return(0); } /* all we need to do is verify a page at the head of the stream * buffer. If it doesn't verify, we look for the next potential * frame */ for (;;) { int ret = ogg_sync_pageseek(ref oy, ref og); if (ret > 0) { /* have a page */ return(1); } if (ret == 0) { /* need more data */ return(0); } if (oy.unsynced == 0) { oy.unsynced = 1; return(-1); } } }
static public int ogg_sync_destroy(ref ogg_sync_state oy) { if (oy != null) { ogg_sync_clear(ref oy); } return(0); }
/* clear things to an initial state. Good to call, eg, before seeking */ static public int ogg_sync_reset(ref ogg_sync_state oy) { if (ogg_sync_check(ref oy) != 0) { return(-1); } oy.fill = 0; oy.returned = 0; oy.unsynced = 0; oy.headerbytes = 0; oy.bodybytes = 0; return(0); }
static public int ogg_sync_wrote(ref ogg_sync_state oy, int bytes) { if (ogg_sync_check(ref oy) != 0) { return(-1); } if (oy.fill + bytes > oy.storage) { return(-1); } oy.fill += bytes; return(0); }
static public int ogg_sync_check(ref ogg_sync_state oy) { if (oy == null) { return(-1); } else if (oy.storage < 0) { return(-1); } else { return(0); } }
static public byte *ogg_sync_buffer(ref ogg_sync_state oy, int size) { if (ogg_sync_check(ref oy) != 0) { return(null); } /* first, clear out any space that has been previously returned */ if (oy.returned > 0) { oy.fill -= oy.returned; if (oy.fill > 0) { CopyMemory(oy.data, oy.data + oy.returned, oy.fill); } oy.returned = 0; } if (size > oy.storage - oy.fill) { /* We need to extend the internal buffer */ int newsize = size + oy.fill + 4096; /* an extra page to be nice */ if (oy.data != null) { oy.data = (byte *)_ogg_realloc(oy.data, newsize); } else { oy.data = (byte *)_ogg_malloc(newsize); } oy.storage = newsize; } /* expose a segment at least as large as requested at the fill mark */ return(oy.data + oy.fill); }
static public int ogg_sync_clear(ref ogg_sync_state oy) { if (oy == null) { return(1); } if (oy.data != null) { _ogg_free(oy.data); } oy.data = null; oy.storage = 0; oy.fill = 0; oy.returned = 0; oy.unsynced = 0; oy.headerbytes = 0; oy.bodybytes = 0; return(0); }
public static extern int ogg_sync_pageout(ref ogg_sync_state oy, ref ogg_page og);
public static extern int ogg_sync_wrote(ref ogg_sync_state oy, int bytes);
public static extern IntPtr ogg_sync_buffer(ref ogg_sync_state oy, int size);
public static extern int ogg_sync_reset(ref ogg_sync_state oy);
public static extern int ogg_sync_destroy(ref ogg_sync_state oy);
public static extern int ogg_sync_clear(ref ogg_sync_state oy);
public static extern int ogg_sync_check(ref ogg_sync_state oy);
public static extern int ogg_sync_init(ref ogg_sync_state oy);
/* DECODING PRIMITIVES: packet streaming layer */ /* This has two layers to place more of the multi-serialno and paging control in the application's hands. First, we expose a data buffer * using ogg_sync_buffer(). The app either copies into the buffer, or passes it directly to read(), etc. We then call * ogg_sync_wrote() to tell how many bytes we just added. * * Pages are returned (pointers into the buffer in ogg_sync_state) by ogg_sync_pageout(). The page is then submitted to * ogg_stream_pagein() along with the appropriate ogg_stream_state* (ie, matching serialno). We then get raw packets out calling ogg_stream_packetout() with a * ogg_stream_state. */ /* initialize the struct to a known state */ static public int ogg_sync_init(ref ogg_sync_state oy) { return(ogg_sync_clear(ref oy)); }
static public int ogg_sync_pageseek(ref ogg_sync_state oy, ref ogg_page og) { byte *page = oy.data + oy.returned; byte *next = null; int bytes = oy.fill - oy.returned; if (ogg_sync_check(ref oy) != 0) { return(0); } if (oy.headerbytes == 0) { int headerbytes; if (bytes < 27) { return(0); } if ( page[0] != 'O' || page[1] != 'g' || page[2] != 'g' || page[3] != 'S' ) { goto sync_fail; } else { headerbytes = page[26] + 27; if (bytes < headerbytes) { return(0); } for (int i = 0; i < page[26]; i++) { oy.bodybytes += page[27 + i]; } oy.headerbytes = headerbytes; } } if (oy.bodybytes + oy.headerbytes > bytes) { return(0); } /* The whole test page is buffered. Verify the checksum */ { byte[] chksum = new byte[4]; ogg_page log = new ogg_page(); /* Grab the checksum bytes, set the header field to zero */ Marshal.Copy((IntPtr)(page + 22), chksum, 0, 4); ZeroMemory(page + 22, 4); /* set up a temp page struct and recompute the checksum */ log.header = page; log.header_len = oy.headerbytes; log.body = page + oy.headerbytes; log.body_len = oy.bodybytes; ogg_page_checksum_set(ref log); /* Compare */ if ( chksum[0] != page[22] || chksum[1] != page[23] || chksum[2] != page[24] || chksum[3] != page[25] ) { /* D'oh. Mismatch! Corrupt page (or miscapture and not a page at all) */ /* replace the computed checksum with the one actually read in */ Marshal.Copy(chksum, 0, (IntPtr)(page + 22), 4); /* Bad checksum. Lose sync */ goto sync_fail; } } /* yes, have a whole page all ready to go */ { byte *_page = oy.data + oy.returned; bytes = oy.headerbytes + oy.bodybytes; if (og != null) { og.header = _page; og.header_len = oy.headerbytes; og.body = _page + oy.headerbytes; og.body_len = oy.bodybytes; } oy.unsynced = 0; oy.returned += bytes; oy.headerbytes = 0; oy.bodybytes = 0; return(bytes); } sync_fail: oy.headerbytes = 0; oy.bodybytes = 0; for (int i = 1; i < bytes; i++) { if (page[i] == 'O') { next = (byte *)(page + i); break; } } if (next == null) { next = oy.data + oy.fill; } oy.returned = (int)(next - oy.data); return((int)-(next - page)); }