public static long ogg_page_pageno(ogg_page og) { return(og.header[18] | og.header[19] << 8 | og.header[20] << 16 | og.header[21] << 24); }
/* 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_page_serialno(ogg_page og) { return(og.header[14] | og.header[15] << 8 | og.header[16] << 16 | og.header[17] << 24); }
public static long ogg_page_granulepos(ogg_page og) { ArrayPointer page = og.header; long granulepos = page[13] & (0xff); #pragma warning disable CS0675 // Bitwise-or operator used on a sign-extended operand granulepos = (granulepos << 8) | (page[12] & 0xff); granulepos = (granulepos << 8) | (page[11] & 0xff); granulepos = (granulepos << 8) | (page[10] & 0xff); granulepos = (granulepos << 8) | (page[9] & 0xff); granulepos = (granulepos << 8) | (page[8] & 0xff); granulepos = (granulepos << 8) | (page[7] & 0xff); granulepos = (granulepos << 8) | (page[6] & 0xff); #pragma warning restore CS0675 // Bitwise-or operator used on a sign-extended operand return((long)granulepos); }
public static void ogg_page_checksum_set(ogg_page og) { uint crc_reg = 0; /* safety; needed for API behavior, but not framing code */ og.header[22] = 0; og.header[23] = 0; og.header[24] = 0; og.header[25] = 0; crc_reg = _os_update_crc(crc_reg, og.header, og.header_len); crc_reg = _os_update_crc(crc_reg, og.body, og.body_len); og.header[22] = (byte)(crc_reg & 0xff); og.header[23] = (byte)((crc_reg >> 8) & 0xff); og.header[24] = (byte)((crc_reg >> 16) & 0xff); og.header[25] = (byte)((crc_reg >> 24) & 0xff); }
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"); }
public static int ogg_page_eos(ogg_page og) { return((int)(og.header[5] & 0x04)); }
public static int ogg_page_continued(ogg_page og) { return((int)(og.header[5] & 0x01)); }
/* A complete description of Ogg framing exists in docs/framing.html */ public static int ogg_page_version(ogg_page og) { return((int)(og.header[4])); }
/* add the incoming page to the stream state; we decompose the page * into packet segments here as well. */ public static int ogg_stream_pagein(ogg_stream_state os, ogg_page og) { ArrayPointer header = og.header; ArrayPointer body = og.body; long bodysize = og.body_len; int segptr = 0; int version = ogg_page_version(og); int continued = ogg_page_continued(og); int bos = ogg_page_bos(og); int eos = ogg_page_eos(og); long granulepos = ogg_page_granulepos(og); int serialno = ogg_page_serialno(og); long pageno = ogg_page_pageno(og); int segments = header[26]; if (ogg_stream_check(os) != 0) { return(-1); } /* clean up 'returned data' */ { long lr = os.lacing_returned; long br = os.body_returned; /* body data */ if (br != 0) { os.body_fill -= br; if (os.body_fill != 0) { memmove(os.body_data, os.body_data + br, os.body_fill); } os.body_returned = 0; } if (lr != 0) { /* segment table */ if ((os.lacing_fill - lr) != 0) { memmove(os.lacing_vals, /*os.lacing_vals +*/ lr, (os.lacing_fill - lr) /* * sizeof(*os.lacing_vals)*/); memmove(os.granule_vals, /*os.granule_vals +*/ lr, (os.lacing_fill - lr) /* * sizeof(*os.granule_vals)*/); } 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(os, segments + 1) != 0) { return(-1); } /* are we in sequence? */ if (pageno != os.pageno) { long i; /* unroll previous partial packet (if any) */ for (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++; } } /* 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] & 0xff) < 255 || os.lacing_vals[os.lacing_fill - 1] == 0x400) { bos = 0; for (; segptr < segments; segptr++) { int val = header[27 + segptr]; body += val; bodysize -= val; if (val < 255) { segptr++; break; } } } } if (bodysize != 0) { if (_os_body_expand(os, bodysize) != 0) { return(-1); } memcpy(os.body_data + os.body_fill, body, bodysize); os.body_fill += bodysize; } { long saved = -1; while (segptr < segments) { int val = 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; } } /* set the granulepos on the last granuleval of the last full packet */ 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); }
/* 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)); }