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 void vorbis_info_clear(vorbis_info vi) { codec_setup_info ci = vi.codec_setup; int i; if (ci != null) { for (i = 0; i < ci.modes; i++) { if (ci.mode_param[i] != null) //_ogg_free(ci.mode_param[i]); { ci.mode_param[i] = null; } } for (i = 0; i < ci.maps; i++) /* unpack does the range checking */ { if (ci.map_param[i] != null) /* this may be cleaning up an aborted * unpack, in which case the below type * cannot be trusted */ //_mapping_P[ci.map_type[i]].free_info(ci.map_param[i]); { ci.map_param[i] = null; } } for (i = 0; i < ci.floors; i++) /* unpack does the range checking */ { if (ci.floor_param[i] != null) /* this may be cleaning up an aborted * unpack, in which case the below type * cannot be trusted */ //_floor_P[ci.floor_type[i]].free_info(ci.floor_param[i]); { ci.floor_param[i] = null; } } for (i = 0; i < ci.residues; i++) /* unpack does the range checking */ { if (ci.residue_param[i] != null) /* this may be cleaning up an aborted * unpack, in which case the below type * cannot be trusted */ //_residue_P[ci.residue_type[i]].free_info(ci.residue_param[i]); { ci.residue_param[i] = null; } } for (i = 0; i < ci.books; i++) { if (ci.book_param[i] != null) { /* knows if the book was not alloced */ vorbis_staticbook_destroy(ci.book_param[i]); } //if (ci.fullbooks != null) // vorbis_book_clear(ci.fullbooks + i); } if (ci.fullbooks != null) { //_ogg_free(ci.fullbooks); ci.fullbooks = null; } for (i = 0; i < ci.psys; i++) { //_vi_psy_free(ci.psy_param[i]); ci.psy_param[i] = null; } //_ogg_free(ci); vi.codec_setup = null; } //memset(vi, 0, sizeof(*vi)); }
/* The Vorbis header is in three packets; the initial small packet in * the first page that identifies basic parameters, a second packet * with bitstream comments and a third packet that holds the * codebook. */ public static int vorbis_synthesis_headerin(vorbis_info vi, vorbis_comment vc, ogg_packet op) { oggpack_buffer opb = new oggpack_buffer(); if (op != null) { oggpack_readinit(opb, op.packet, op.bytes); /* Which of the three types of header is this? */ /* Also verify header-ness, vorbis */ { var buffer = new ArrayPointer(); long packtype = oggpack_read(opb, 8); //memset(buffer, 0, 6); _v_readstring(opb, buffer, 6); if (memcmp(buffer, "vorbis", 6) != 0) { /* not a vorbis header */ return(OV_ENOTVORBIS); } switch (packtype) { case 0x01: /* least significant *bit* is read first */ if (op.b_o_s == 0) { /* Not the initial packet */ return(OV_EBADHEADER); } if (vi.rate != 0) { /* previously initialized info header */ return(OV_EBADHEADER); } return(_vorbis_unpack_info(vi, opb)); case 0x03: /* least significant *bit* is read first */ if (vi.rate == 0) { /* um... we didn't get the initial header */ return(OV_EBADHEADER); } if (vc.vendor != null) { /* previously initialized comment header */ return(OV_EBADHEADER); } return(_vorbis_unpack_comment(vc, opb)); case 0x05: /* least significant *bit* is read first */ if (vi.rate == 0 || vc.vendor == null) { /* um... we didn;t get the initial header or comments yet */ return(OV_EBADHEADER); } if (vi.codec_setup == null) { /* improperly initialized vorbis_info */ return(OV_EFAULT); } if (((codec_setup_info)vi.codec_setup).books > 0) { /* previously initialized setup header */ return(OV_EBADHEADER); } return(_vorbis_unpack_books(vi, opb)); default: /* Not a valid vorbis header type */ return(OV_EBADHEADER); //break; } } } return(OV_EBADHEADER); }
/* all of the real encoding details are here. The modes, books, * everything */ public static int _vorbis_unpack_books(vorbis_info vi, oggpack_buffer opb) { codec_setup_info ci = vi.codec_setup; int i; /* codebooks */ ci.books = (int)oggpack_read(opb, 8) + 1; if (ci.books <= 0) { goto err_out; } for (i = 0; i < ci.books; i++) { ci.book_param[i] = vorbis_staticbook_unpack(opb); if (ci.book_param[i] == null) { goto err_out; } } /* time backend settings; hooks are unused */ { int times = (int)oggpack_read(opb, 6) + 1; if (times <= 0) { goto err_out; } for (i = 0; i < times; i++) { int test = (int)oggpack_read(opb, 16); if (test < 0 || test >= VI_TIMEB) { goto err_out; } } } /* floor backend settings */ ci.floors = (int)oggpack_read(opb, 6) + 1; if (ci.floors <= 0) { goto err_out; } for (i = 0; i < ci.floors; i++) { ci.floor_type[i] = (int)oggpack_read(opb, 16); if (ci.floor_type[i] < 0 || ci.floor_type[i] >= VI_FLOORB) { goto err_out; } ci.floor_param[i] = _floor_P[ci.floor_type[i]].unpack(vi, opb); if (ci.floor_param[i] == null) { goto err_out; } } /* residue backend settings */ ci.residues = (int)oggpack_read(opb, 6) + 1; if (ci.residues <= 0) { goto err_out; } for (i = 0; i < ci.residues; i++) { ci.residue_type[i] = (int)oggpack_read(opb, 16); if (ci.residue_type[i] < 0 || ci.residue_type[i] >= VI_RESB) { goto err_out; } ci.residue_param[i] = _residue_P[ci.residue_type[i]].unpack(vi, opb); if (ci.residue_param[i] == null) { goto err_out; } } /* map backend settings */ ci.maps = (int)oggpack_read(opb, 6) + 1; if (ci.maps <= 0) { goto err_out; } for (i = 0; i < ci.maps; i++) { ci.map_type[i] = (int)oggpack_read(opb, 16); if (ci.map_type[i] < 0 || ci.map_type[i] >= VI_MAPB) { goto err_out; } ci.map_param[i] = _mapping_P[ci.map_type[i]].unpack(vi, opb); if (ci.map_param[i] == null) { goto err_out; } } /* mode settings */ ci.modes = (int)oggpack_read(opb, 6) + 1; if (ci.modes <= 0) { goto err_out; } for (i = 0; i < ci.modes; i++) { ci.mode_param[i] = new vorbis_info_mode(); //_ogg_calloc(1, sizeof(*ci.mode_param[i])); ci.mode_param[i].blockflag = (int)oggpack_read(opb, 1); ci.mode_param[i].windowtype = (int)oggpack_read(opb, 16); ci.mode_param[i].transformtype = (int)oggpack_read(opb, 16); ci.mode_param[i].mapping = (int)oggpack_read(opb, 8); if (ci.mode_param[i].windowtype >= VI_WINDOWB) { goto err_out; } if (ci.mode_param[i].transformtype >= VI_WINDOWB) { goto err_out; } if (ci.mode_param[i].mapping >= ci.maps) { goto err_out; } if (ci.mode_param[i].mapping < 0) { goto err_out; } } if (oggpack_read(opb, 1) != 1) { goto err_out; /* top level EOP check */ } return(0); err_out: vorbis_info_clear(vi); return(OV_EBADHEADER); }
/* used by synthesis, which has a full, alloced vi */ public static void vorbis_info_init(vorbis_info vi) { vi.codec_setup = new codec_setup_info(); }
/* Header packing/unpacking ********************************************/ public static int _vorbis_unpack_info(vorbis_info vi, oggpack_buffer opb) { codec_setup_info ci = vi.codec_setup; int bs; if (ci == null) { return(OV_EFAULT); } vi.version = oggpack_read(opb, 32); if (vi.version != 0) { return(OV_EVERSION); } vi.channels = oggpack_read(opb, 8); vi.rate = oggpack_read(opb, 32); vi.bitrate_upper = (int)oggpack_read(opb, 32); vi.bitrate_nominal = (int)oggpack_read(opb, 32); vi.bitrate_lower = (int)oggpack_read(opb, 32); bs = (int)oggpack_read(opb, 4); if (bs < 0) { goto err_out; } ci.blocksizes[0] = 1 << bs; bs = (int)oggpack_read(opb, 4); if (bs < 0) { goto err_out; } ci.blocksizes[1] = 1 << bs; if (vi.rate < 1) { goto err_out; } if (vi.channels < 1) { goto err_out; } if (ci.blocksizes[0] < 64) { goto err_out; } if (ci.blocksizes[1] < ci.blocksizes[0]) { goto err_out; } if (ci.blocksizes[1] > 8192) { goto err_out; } if (oggpack_read(opb, 1) != 1) { goto err_out; /* EOP check */ } return(0); err_out: vorbis_info_clear(vi); return(OV_EBADHEADER); }