/* Helpers for ogg_stream_encode; this keeps the structure and * what's happening fairly clear */ public static int _os_body_expand(ogg_stream_state os, long needed) { if (os.body_storage - needed <= os.body_fill) { long body_storage; //object ret; if (os.body_storage > long.MaxValue - needed) { ogg_stream_clear(os); return(-1); } body_storage = os.body_storage + needed; // Uses an expanding array, hence reallocation should not be necessary //if (body_storage < long.MaxValue - 1024) body_storage += 1024; //ret = _ogg_realloc(os.body_data, body_storage /* * sizeof(*os.body_data)*/); //if (ret == null) //{ // ogg_stream_clear(os); // return -1; //} os.body_storage = body_storage; //os.body_data = ret; } return(0); }
public static int _os_lacing_expand(ogg_stream_state os, long needed) { if (os.lacing_storage - needed <= os.lacing_fill) { long lacing_storage; object ret; if (os.lacing_storage > long.MaxValue - needed) { ogg_stream_clear(os); return(-1); } lacing_storage = os.lacing_storage + needed; if (lacing_storage < long.MaxValue - 32) { lacing_storage += 32; } ret = _ogg_realloc(os.lacing_vals, lacing_storage /* * sizeof(*os.lacing_vals)*/); if (ret == null) { ogg_stream_clear(os); return(-1); } os.lacing_vals = (int[])ret; ret = _ogg_realloc(os.granule_vals, lacing_storage /* * sizeof(*os.granule_vals)*/); if (ret == null) { ogg_stream_clear(os); return(-1); } os.granule_vals = (long[])ret; os.lacing_storage = lacing_storage; } return(0); }
/* _clear does not free os, only the non-flat storage within */ public static int ogg_stream_clear(ogg_stream_state os) { os.body_data = null; os.lacing_vals = null; os.granule_vals = null; return(0); }
public static int ogg_stream_packetout(ogg_stream_state os, ogg_packet op) { if (ogg_stream_check(os) != 0) { return(0); } return(_packetout(os, op, 1)); }
/* async/delayed error detection for the ogg_stream_state */ public static int ogg_stream_check(ogg_stream_state os) { if (os == null || os.body_data == null) { return(-1); } return(0); }
/* init the encode/decode logical stream state */ public static int ogg_stream_init(ogg_stream_state os, int serialno) { os.body_storage = 16 * 1024; os.lacing_storage = 1024; os.stream = new MemoryStream(); os.body_data = new ArrayPointer(os.stream); // _ogg_malloc(os.body_storage * sizeof(*os.body_data)); os.lacing_vals = new int[os.lacing_storage]; // _ogg_malloc(os.lacing_storage * sizeof(*os.lacing_vals)); os.granule_vals = new long[os.lacing_storage]; // _ogg_malloc(os.lacing_storage * sizeof(*os.granule_vals)); if (os.body_data == null || os.lacing_vals == null || os.granule_vals == null) { ogg_stream_clear(os); return(-1); } os.serialno = serialno; 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"); }
public static int _packetout(ogg_stream_state os, 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) */ long ptr = os.lacing_returned; if (os.lacing_packet <= ptr) { return(0); } if ((os.lacing_vals[ptr] & 0x400) != 0) { /* we need to tell the codec there's a gap; it might need to * handle previous packet dependencies. */ os.lacing_returned++; os.packetno++; return(-1); } if (op == null && adv == 0) { return(1); /* just using peek as an inexpensive way * to ask if there's a whole packet * waiting */ } /* Gather the whole packet. We'll have no holes or a partial packet */ { int size = os.lacing_vals[ptr] & 0xff; long bytes = size; int eos = os.lacing_vals[ptr] & 0x200; /* last packet of the stream? */ int bos = os.lacing_vals[ptr] & 0x100; /* first packet of the stream? */ 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); }
/* 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); }