public static ArrayPointer ogg_sync_buffer(ogg_sync_state oy, long size) { if (ogg_sync_check(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) { memmove(oy.data, oy.data + oy.returned, oy.fill); } oy.returned = 0; } if (size > oy.storage - oy.fill) { /* We need to extend the internal buffer */ long newsize = size + oy.fill + 4096; /* an extra page to be nice */ oy.storage = (int)newsize; } /* expose a segment at least as large as requested at the fill mark */ return(oy.data + oy.fill); }
/* 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 */ public static int ogg_sync_pageout(ogg_sync_state oy, ogg_page og) { if (ogg_sync_check(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 (; ;) { long ret = ogg_sync_pageseek(oy, og); if (ret > 0) { /* have a page */ return(1); } if (ret == 0) { /* need more data */ return(0); } /* head did not start a synced page... skipped some bytes */ if (oy.unsynced == 0) { oy.unsynced = 1; return(-1); } /* loop. keep looking */ } }
public static int ogg_sync_check(ogg_sync_state oy) { if (oy.storage < 0) { return(-1); } return(0); }
/* 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 */ public static int ogg_sync_init(ogg_sync_state oy) { oy.storage = -1; /* used as a readiness flag */ oy.stream = new MemoryStream(); oy.data = new ArrayPointer(oy.stream); oy.storage = 0; return(0); }
public static int ogg_sync_wrote(ogg_sync_state oy, long bytes) { if (ogg_sync_check(oy) != 0) { return(-1); } if (oy.fill + bytes > oy.storage) { return(-1); } oy.fill += (int)bytes; return(0); }
static ushort[] convbuffer = new ushort[4096]; /* take 8k out of the data segment, not the stack */ //static long convsize = 4096; public static void Main(string[] args) { /* sync and verify incoming physical bitstream */ var oy = new ogg_sync_state(); /* take physical pages, weld into a logical stream of packets */ var os = new ogg_stream_state(); /* one Ogg bitstream page. Vorbis packets are inside */ var og = new ogg_page(); /* one raw packet of data for decode */ var op = new ogg_packet(); /* struct that stores all the static vorbis bitstream settings */ var vi = new vorbis_info(); /* struct that stores all the bitstream user comments */ var vc = new vorbis_comment(); /* central working state for the packet->PCM decoder */ var vd = new vorbis_dsp_state(); /* local working space for packet->PCM decode */ var vb = new vorbis_block(); var stdin = Console.OpenStandardInput(); var stdout = Console.OpenStandardOutput(); var stderr = Console.OpenStandardError(); /********** Decode setup ************/ ogg_sync_init(oy); /* Now we can read pages */ while (true) { /* we repeat if the bitstream is chained */ /* grab some data at the head of the stream. We want the first page * (which is guaranteed to be small and only contain the Vorbis * stream initial header) We need the first page to get the stream * serialno. */ /* submit a 4k block to libvorbis' Ogg layer */ var buffer = ogg_sync_buffer(oy, 4096); int bytes = fread(buffer, 1, 4096, stdin); ogg_sync_wrote(oy, bytes); /* Get the first page. */ if (ogg_sync_pageout(oy, og) != 1) { /* have we simply run out of data? If so, we're done. */ if (bytes < 4096) { break; } /* error case. Must not be Vorbis data */ fprintf(stderr, "Input does not appear to be an Ogg bitstream.\n"); exit(1); } /* get the serial number and set up the rest of decode. */ /* serialno first; use it to set up a logical stream */ ogg_stream_init(os, ogg_page_serialno(og)); /* extract the initial header from the first page and verify that the * ogg bitstream is in fact vorbis data */ /* i handle the initial header first instead of just having the code * read all three vorbis headers at once because reading the initial * header is an easy way to identify a vorbis bitstream and it's * useful to see that functionality seperated out. */ vorbis_info_init(vi); vorbis_comment_init(vc); if (ogg_stream_pagein(os, og) < 0) { /* error; stream version mismatch perhaps */ fprintf(stderr, "error reading first page of ogg bitstream data.\n"); exit(1); } if (ogg_stream_packetout(os, op) != 1) { /* no page? must not be vorbis */ fprintf(stderr, "error reading initial header packet.\n"); exit(1); } if (vorbis_synthesis_headerin(vi, vc, op) < 0) { /* error case; not a vorbis header */ fprintf(stderr, "this ogg bitstream does not contain vorbis audio data.\n"); exit(1); } //// /* At this point, we're sure we're Vorbis. We've set up the logical //// (Ogg) bitstream decoder. Get the comment and codebook headers and //// set up the Vorbis decoder */ //// /* The next two packets in order are the comment and codebook headers. //// They're likely large and may span multiple pages. Thus we read //// and submit data until we get our two packets, watching that no //// pages are missing. If a page is missing, error out; losing a //// header page is the only place where missing data is fatal. */ //// i = 0; //// while (i < 2) //// { //// while (i < 2) //// { //// int result = ogg_sync_pageout(oggSyncState, oggPage); //// if (result == 0) break; /* Need more data */ //// /* Don't complain about missing or corrupt data yet. We'll //// catch it at the packet output phase */ //// if (result == 1) //// { //// ogg_stream_pagein(oggStreamState, oggPage); /* we can ignore any errors here //// as they'll also become apparent //// at packetout */ //// while (i < 2) //// { //// result = ogg_stream_packetout(oggStreamState, oggPacket); //// if (result == 0) break; //// if (result < 0) //// { //// /* Uh oh; data at some point was corrupted or missing! //// We can't tolerate that in a header. Die. */ //// fprintf(stderr, "Corrupt secondary header. Exiting.\n"); //// exit(1); //// } //// result = vorbis_synthesis_headerin(vorbisInfo, vorbisComment, oggPacket); //// if (result < 0) //// { //// fprintf(stderr, "Corrupt secondary header. Exiting.\n"); //// exit(1); //// } //// i++; //// } //// } //// } //// /* no harm in not checking before adding more */ //// buffer = ogg_sync_buffer(oggSyncState, 4096); //// bytes = fread(buffer, 1, 4096, stdin); //// if (bytes == 0 && i < 2) //// { //// fprintf(stderr, "End of file before finding all Vorbis headers!\n"); //// exit(1); //// } //// ogg_sync_wrote(oggSyncState, bytes); //// } //// /* Throw the comments plus a few lines about the bitstream we're //// decoding */ //// { //// char** ptr = vorbisComment.user_comments; //// while (*ptr) //// { //// fprintf(stderr, "%s\n", *ptr); //// ++ptr; //// } //// fprintf(stderr, "\nBitstream is %d channel, %ldHz\n", vorbisInfo.channels, vorbisInfo.rate); //// fprintf(stderr, "Encoded by: %s\n\n", vorbisComment.vendor); //// } //// convsize = 4096 / vorbisInfo.channels; //// /* OK, got and parsed all three headers. Initialize the Vorbis //// packet->PCM decoder. */ //// if (vorbis_synthesis_init(vorbisDspState, vorbisInfo) == 0) //// { /* central decode state */ //// vorbis_block_init(vorbisDspState, vorbisBlock); /* local state for most of the decode //// so multiple block decodes can //// proceed in parallel. We could init //// multiple vorbis_block structures //// for vd here */ //// /* The rest is just a straight decode loop until end of stream */ //// while (eos == 0) //// { //// while (eos == 0) //// { //// int result = ogg_sync_pageout(oggSyncState, oggPage); //// if (result == 0) break; /* need more data */ //// if (result < 0) //// { /* missing or corrupt data at this page position */ //// fprintf(stderr, "Corrupt or missing data in bitstream; " //// "continuing...\n"); //// } //// else //// { //// ogg_stream_pagein(oggStreamState, oggPage); /* can safely ignore errors at //// this point */ //// while (1) //// { //// result = ogg_stream_packetout(&oggStreamState, &oggPacket); //// if (result == 0) break; /* need more data */ //// if (result < 0) //// { /* missing or corrupt data at this page position */ //// /* no reason to complain; already complained above */ //// } //// else //// { //// /* we have a packet. Decode it */ //// float** pcm; //// int samples; //// if (vorbis_synthesis(&vorbisBlock, &oggPacket) == 0) /* test for success! */ //// vorbis_synthesis_blockin(&vorbisDspState, &vorbisBlock); //// /* //// **pcm is a multichannel float vector. In stereo, for //// example, pcm[0] is left, and pcm[1] is right. samples is //// the size of each channel. Convert the float values //// (-1.<=range<=1.) to whatever PCM format and write it out */ //// while ((samples = vorbis_synthesis_pcmout(&vorbisDspState, &pcm)) > 0) //// { //// int j; //// int clipflag = 0; //// int bout = (samples < convsize ? samples : convsize); //// /* convert floats to 16 bit signed ints (host order) and //// interleave */ //// for (i = 0; i < vorbisInfo.channels; i++) //// { //// ogg_int16_t* ptr = convbuffer + i; //// float* mono = pcm[i]; //// for (j = 0; j < bout; j++) //// { ////#if 1 //// int val=floor(mono[j]*32767.f+.5f); ////#else /* optional dither */ //// int val = mono[j] * 32767.f + drand48() - 0.5f; ////#endif //// /* might as well guard against clipping */ //// if (val > 32767) //// { //// val = 32767; //// clipflag = 1; //// } //// if (val < -32768) //// { //// val = -32768; //// clipflag = 1; //// } //// *ptr = val; //// ptr += vorbisInfo.channels; //// } //// } //// if (clipflag) //// fprintf(stderr, "Clipping in frame %ld\n", (long)(vorbisDspState.sequence)); //// fwrite(convbuffer, 2 * vorbisInfo.channels, bout, stdout); //// vorbis_synthesis_read(vorbisDspState, bout); /* tell libvorbis how //// many samples we //// actually consumed */ //// } //// } //// } //// if (ogg_page_eos(oggPage) != 0) eos = 1; //// } //// } //// if (eos == 0) //// { //// buffer = ogg_sync_buffer(oggSyncState, 4096); //// bytes = fread(buffer, 1, 4096, stdin); //// ogg_sync_wrote(oggSyncState, bytes); //// if (bytes == 0) eos = 1; //// } //// } //// /* ogg_page and ogg_packet structs always point to storage in //// libvorbis. They're never freed or manipulated directly */ //// vorbis_block_clear(vorbisBlock); //// vorbis_dsp_clear(vorbisDspState); //// } //// else //// { //// fprintf(stderr, "Error: Corrupt header during playback initialization.\n"); //// } //// /* clean up this logical bitstream; before exit we see if we're //// followed by another [chained] */ //// ogg_stream_clear(oggStreamState); //// vorbis_comment_clear(vorbisComment); //// vorbis_info_clear(vorbisInfo); /* must be called last */ } /* OK, clean up the framer */ ogg_sync_clear(oy); fprintf(stderr, "Done.\n"); }
/* clear non-flat storage within */ public static int ogg_sync_clear(ogg_sync_state oy) { oy.stream.SetLength(0); return(0); }
/* sync the stream. This is meant to be useful for finding page * boundaries. * * return values for this: * -n) skipped n bytes * 0) page not ready; more data (no bytes skipped) * n) page synced at current location; page length n bytes * */ public static long ogg_sync_pageseek(ogg_sync_state oy, ogg_page og) { ArrayPointer page = oy.data + oy.returned; ArrayPointer next; long bytes = oy.fill - oy.returned; if (ogg_sync_check(oy) != 0) { return(0); } if (oy.headerbytes == 0) { int headerbytes, i; if (bytes < 27) { return(0); /* not enough for a header */ } /* verify capture pattern */ if (memcmp(page, "OggS", 4) != 0) { goto sync_fail; } headerbytes = page[26] + 27; if (bytes < headerbytes) { return(0); /* not enough for header + seg table */ } /* count up body length in the segment table */ for (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 */ { /* Grab the checksum bytes, set the header field to zero */ var chksum = new byte[4]; ogg_page log = new ogg_page(); memcpy(chksum, page + 22, 4); memset(page + 22, 0, 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(log); /* Compare */ if (memcmp(chksum, page + 22, 4) != 0) { /* D'oh. Mismatch! Corrupt page (or miscapture and not a page * at all) */ /* replace the computed checksum with the one actually read in */ memcpy(page + 22, chksum, 4); #if DISABLE_CRC /* Bad checksum. Lose sync */ goto sync_fail; #endif } } /* yes, have a whole page all ready to go */ { og.header = page; og.header_len = oy.headerbytes; og.body = page + oy.headerbytes; og.body_len = oy.bodybytes; oy.unsynced = 0; oy.returned += (int)(bytes = oy.headerbytes + oy.bodybytes); oy.headerbytes = 0; oy.bodybytes = 0; return(bytes); } sync_fail: oy.headerbytes = 0; oy.bodybytes = 0; /* search for possible capture */ next = memchr(page + 1, 'O', bytes - 1); if (next == null) { next = oy.data + oy.fill; } oy.returned = (int)(next - oy.data); return((long)-(next - page)); }