Okay, how do I drop a changeset/patchset/tag for you folks from SVN?
At this point, I have written three examples of how to use the basics of
the ogg streaming and decoding in Tremor. I heartily welcome any
suggestions, improvements and corrections that you can point out in the
code.
The examples required me to make some small modifications to the main
tremor library. However, the changes are confined to only wrapping
direct data structure access code with static inline functions. The
changes are pretty minimal and no functionality change should have
occurred. In fact, a good optimizing compiler probably won't even make
any binary code changes as the static inline functions will compile down
to the original direct structure access.
The examples are:
ogg_reader_example.c - vacuums up all ogg pages
streamer_example.c - creates a packet stream from pages and eats them
decoder_example.c - use lower-level vorbis API to decode the stream
Each one of these programs builds upon the previous so that you can see
how to evolve each loop from one to the next. This was my biggest
problem in untangling the vorbisfile.c code.
There are lots of comments in decoder_example.c. I would recommend that
the developers read them as they document my frustrations in groveling
through the lower-level API. At the very least, they generally record
things which probably need to get documented in an eventual API
document. At best, they may serve as guideposts for future adjustments
to the API to make life easier for developers.
Let me know what you guys need.
Thanks,
-a
-------------- next part --------------
/*
* Takes an ogg stream from stdin and reads all of the pages.
* It will happily read all pages of even concatenated ogg streams.
* It writes nothing out. It is meant as a basic skeleton to
* demonstrate how to cope with the ogg2 included in tremor.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ivorbiscodec.h"
#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
#include <io.h>
#include <fcntl.h>
#endif
#if defined(__MACOS__) && defined(__MWERKS__)
#include <console.h> /* CodeWarrior's Mac
"command-line" support */
#endif
#define dprintf(...) fprintf(stderr, __VA_ARGS__)
#define BCHUNKSIZE 8192
static long bytesConsumed = 0;
// FIXME: This is one of the places that can throw errors
int grabData(ogg_sync_state *oy) {
unsigned char* bb = ogg_sync_bufferin(oy, BCHUNKSIZE);
long bytesRead = fread(bb, 1, BCHUNKSIZE, stdin);
dprintf("Consumed: %ld bytes\n", bytesRead);
if (bytesRead == 0) {
// For now, EOF
return(-1);
}
ogg_sync_wrote(oy, bytesRead);
bytesConsumed += bytesRead;
return(0);
}
int main() {
int rv0 = 0;
int dr0 = 0;
// These abbreviations use the ogg internal conventions
// Caution: libogg uses NULL as a sentinel in places. If you feed non-NULL,
// on initial calls you can get into trouble
ogg_sync_state *oy = NULL;
// FIXME: Why is this magic required to make ogg_page work?
// FIXME: Why is there no ogg_page_create?
ogg_page og_allocated = {0, 0, 0, 0};
ogg_page *og = &og_allocated;
oy = ogg_sync_create();
int flgBail = 0;
int pageCount = -1;
while(!flgBail) {
dprintf("Page: %d\n", pageCount);
rv0 = 0;
while(rv0 != 1 && !flgBail) {
rv0 = ogg_sync_pageout(oy, og);
if (rv0 > 0) {
// Only increment page on valid packet
++pageCount;
}
if (rv0 <= 0) {
if (rv0 < 0) {
dprintf("Skipping bytes...\n");
}
if (rv0 == 0) {
dprintf("Need more data...\n");
}
dr0 = grabData(oy);
if (dr0 < 0) {
dprintf("Data error encountered.\n");
flgBail = 1;
}
}
}
}
dprintf("System bailing\n");
// System has bailed -- clean up
ogg_page_release(og);
ogg_sync_destroy(oy);
dprintf("Done. Consumed: %ld\n", bytesConsumed);
return(0);
}
-------------- next part --------------
/*
* Takes an ogg stream from stdin and reads all of the pages.
* as well as all of the packets. It is capable of crossing
* a boundary of a concatenated stream.
*
* It writes nothing out. It is meant as a basic skeleton to
* demonstrate how to cope with the ogg2 included in tremor.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ivorbiscodec.h"
#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
#include <io.h>
#include <fcntl.h>
#endif
#if defined(__MACOS__) && defined(__MWERKS__)
#include <console.h> /* CodeWarrior's Mac
"command-line" support */
#endif
#define dprintf(...) fprintf(stderr, __VA_ARGS__)
#define BCHUNKSIZE 8192
static long bytesConsumed = 0;
// FIXME: This is one of the places that can throw errors
int grabData(ogg_sync_state *oy) {
unsigned char* bb = ogg_sync_bufferin(oy, BCHUNKSIZE);
long bytesRead = fread(bb, 1, BCHUNKSIZE, stdin);
dprintf("Consumed: %ld bytes\n", bytesRead);
if (bytesRead == 0) {
// For now, EOF
return(-1);
}
ogg_sync_wrote(oy, bytesRead);
bytesConsumed += bytesRead;
return(0);
}
int main() {
int o_rv0 = 0;
int o_dr0 = 0;
int s_rv0 = 0;
// These abbreviations use the ogg internal conventions
// Caution: libogg uses NULL as a sentinel in places. If you feed non-NULL,
// on initial calls you can get into trouble
// OGG data structures
ogg_sync_state *oy = NULL;
// FIXME: Why is this magic required to make ogg_page work?
// FIXME: Why is there no ogg_page_create?
ogg_page og_allocated = {0, 0, 0, 0};
ogg_page* og = &og_allocated;
// Stream data structures
ogg_stream_state *os = NULL;
// FIXME: Why is this magic required to make ogg_page work?
// FIXME: Why is there no ogg_packet_create?
ogg_packet op_allocated = {0, 0, 0, 0, 0, 0};
ogg_packet* op = &op_allocated;
// Ogg init
oy = ogg_sync_create();
// Stream init
// Need to set the serial number later
os = ogg_stream_create(-1);
// CAUTION: Just about anything you do wrong pops a bus error.
// You need to be fairly aggressive about checking return codes
// and initializing properly.
int flgBailError = 0;
int pageCount = -1;
int flgPacketsConsumed = 0;
int packetCount = -1;
int flgEOSPage = 0;
while(!flgBailError) {
dprintf("Page: %d\n", pageCount);
if (pageCount != -1) {
if (pageCount == 0) {
// FIXME: Silly pageCount used to indicate serial number change
// because ogg_stream_pagein does braindead release on error and
// ogg_page_bos() doesn't seem to work for a concatenated stream.
dprintf("Beginning of stream found\n");
// Use hex to match ogginfo return
dprintf("Setting serial number: %x\n", ogg_page_serialno(og));
ogg_stream_reset_serialno(os, ogg_page_serialno(og));
}
// EOS test has to be up front because, of course, everything in the
universe
// releases the page so you have to get to it *before* it disappears
// and store it yourself in spite of the fact that the page stores it
// very nicely (until it gets freed). Grrrrrrr ...
if (ogg_page_eos(og)) {
flgEOSPage = 1;
dprintf("End of stream found\n");
}
s_rv0 = ogg_stream_pagein(os, og);
dprintf("Page in: %d %d %p %p\n", pageCount, s_rv0, os, og);
if (s_rv0 < 0) {
// FIXME: ARRRGGGGHHH!!! ogg_stream_pagein releases the page on error.
// This is silly on serial number mismatch. Actually, it's probably
// silly in general on an error because it means you can't actually
// examine the page to see what's wrong because it just disappeared.
if (s_rv0 == OGG_ESERIAL) {
// Useless, because page is gone and can't be resubmitted. Grrrrr.
dprintf("Bailing on stream submit fail\n");
flgBailError = 1;
// FIXME: What we would like to do if ogg_stream_pagein wasn't braindead
...
// Serial number mismatch -- generally indicates start of stream
// Go back around and resubmit after resetting serial number
} else {
dprintf("Bailing on stream submit fail\n");
flgBailError = 1;
}
}
flgPacketsConsumed = 0;
while (!flgPacketsConsumed && !flgBailError) {
// Valid page submitted to stream, now pull out as packets
// There may be more than 1 packet per page. Pull all packets
// before asking for another page.
s_rv0 = ogg_stream_packetout(os, op);
dprintf("Packet out: %d %d %d %p %p\n", pageCount, packetCount,
s_rv0, os, op);
if (s_rv0 < 0) {
flgBailError = 1;
dprintf("Packet consumption error bail\n");
} else if (s_rv0 == 0) {
dprintf("Packets consumed. Get more data.\n");
flgPacketsConsumed = 1;
}
if (s_rv0 > 0) {
// Only increment packet counter on valid packet
++packetCount;
// Packet valid & counts valid ... do something with it
dprintf("Packet val: %d %d %d %p %p\n", pageCount, packetCount,
s_rv0, os, op);
}
}
}
// Don't pull another page at EOS. Let that occur after reset on
another
// trip through so that we match the normal uninitialized case.
if (!flgEOSPage) {
o_rv0 = 0;
while(o_rv0 != 1 && !flgBailError) {
o_rv0 = ogg_sync_pageout(oy, og);
if (o_rv0 > 0) {
// Only increment page on valid packet
++pageCount;
}
if (o_rv0 <= 0) {
if (o_rv0 < 0) {
dprintf("Skipping bytes...\n");
}
if (o_rv0 == 0) {
dprintf("Need more data...\n");
}
o_dr0 = grabData(oy);
if (o_dr0 < 0) {
dprintf("Data error encountered.\n");
flgBailError = 1;
}
}
}
}
if (flgEOSPage) {
// More data might still available, reset system
flgEOSPage = 0;
pageCount = -1;
packetCount = -1;
ogg_stream_destroy(os);
os = ogg_stream_create(-1);
}
}
dprintf("System bailing\n");
// System has bailed -- clean up
ogg_stream_destroy(os);
ogg_page_release(og);
ogg_sync_destroy(oy);
dprintf("Done. Consumed: %ld\n", bytesConsumed);
return(0);
}
-------------- next part --------------
/*
* Takes a stereo ogg stream from stdin and writes 16 bit pcm out to
* the stdout. It writes lots of debugging info to stderr.
*
* This is meant as a skeleton so that people can see how to
* use the lower level vorbis API.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ivorbiscodec.h"
#include "misc.h"
#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
#include <io.h>
#include <fcntl.h>
#endif
#if defined(__MACOS__) && defined(__MWERKS__)
#include <console.h> /* CodeWarrior's Mac
"command-line" support */
#endif
/* FIXME: Shouldn't this be declared somewhere else? Like ivorbiscode.h or
something? */
#define LAST_VORBIS_HEADER_PACKET 2
#define dprintf(...) fprintf(stderr, __VA_ARGS__)
#define BCHUNKSIZE 8192
static long bytesConsumed = 0;
int main() {
int o_rv0 = 0;
int s_rv0 = 0;
int v_rv0 = 0;
/*
// These abbreviations use the ogg internal conventions
// Caution: libogg uses NULL as a sentinel in places. If you feed non-NULL,
// on initial calls you can get into trouble
*/
/* OGG data structures */
ogg_sync_state *oy = NULL;
/* FIXME: Why is this magic required to make ogg_page work? */
/* FIXME: Why is there no ogg_page_create? Or ogg_page_init? */
ogg_page og_allocated = {0, 0, 0, 0};
ogg_page* og = &og_allocated;
/* Stream data structures */
ogg_stream_state *os = NULL;
/* FIXME: Why is this magic required to make ogg_page work? */
/* FIXME: Why is there no ogg_packet_create? Or ogg_packet_init? */
ogg_packet op_allocated = {0, 0, 0, 0, 0, 0};
ogg_packet* op = &op_allocated;
/*
// Vorbis data structures
// FIXME: These should probably get a *_create or similar so that
// they don't have to be manually managed but instead are managed
// by the system.
*/
vorbis_info vi_allocated;
vorbis_info* vi = &vi_allocated;
vorbis_comment vc_allocated;
vorbis_comment* vc = &vc_allocated;
vorbis_dsp_state vd_allocated;
vorbis_dsp_state* vd = &vd_allocated;
vorbis_block vb_allocated;
vorbis_block *vb = &vb_allocated;
/*
// CAUTION: Just about anything you do wrong pops a bus error.
// You need to be fairly aggressive about checking return codes
// and initializing properly.
*/
int flgBailError = 0;
int flgInitialPageRead = 0xdeadbeef;
int flgPacketsConsumed = 0xdeadbeef;
int packetCount = 0xdeadbeef;
int flgEOSPage = 0xdecafbad;
int flgBailEOS = 0xc0ffee00;
/* Ogg init */
oy = ogg_sync_create();
/* Stream init */
/* Need to set the serial number later, or the stream will reject input */
os = ogg_stream_create(-1);
/*
// There is only one physical stream here. Do *NOT* reinitialize
// it upon changing logical streams or you will lose any data which
// has already been read and buffered by the ogg system.
*/
while(!flgBailError) { /* This while loop iterates over ogg logical streams */
/* Vorbis init */
vorbis_info_init(vi);
vorbis_comment_init(vc);
/* Page iteration init */
flgInitialPageRead = 0;
packetCount = -1;
flgEOSPage = 0;
/*
// This is probably redundant with flgEOSPage. However, it is
// easier to keep track of a separate flag which is set only
// after all packets have been consumed rather than: at the
// beginning of the page, but before the stream has been decoded
// and before the packets have been consumed, and ...
*/
flgBailEOS = 0;
while(!flgBailEOS && !flgBailError) { /* This while loop iterates
over ogg pages */
if (flgInitialPageRead) { /* Page system has been initialized and is valid
*/
dprintf("Page: %d\n", ogg_page_pageno(og));
if (ogg_page_bos(og)) {
dprintf("Beginning of stream found: %d\n", ogg_page_bos(og));
// Use hex to match ogginfo return
dprintf("Setting serial number: %x\n", ogg_page_serialno(og));
ogg_stream_reset_serialno(os, ogg_page_serialno(og));
}
/*
// EOS test has to be up front because, of course, everything in the universe
// releases the page so you have to get to it *before* it disappears
// and store it yourself in spite of the fact that the page stores it
// very nicely (until it gets freed). Grrrrrrr ...
*/
if (ogg_page_eos(og)) {
flgEOSPage = 1;
dprintf("End of stream found\n");
}
s_rv0 = ogg_stream_pagein(os, og);
dprintf("Page in: %d %p %p\n", s_rv0, os, og);
if (s_rv0 < 0) {
/*
// FIXME: ARRRGGGGHHH!!! ogg_stream_pagein releases the page on error.
// This is silly on serial number mismatch. Actually, it's probably
// silly in general on an error because it means you can't actually
// examine the page to see what's wrong because it just disappeared.
*/
if (s_rv0 == OGG_ESERIAL) {
/* Useless, because page is gone and can't be examined. Grrrrr. */
dprintf("Bailing on serial submit fail\n");
flgBailError = 1;
} else {
dprintf("Bailing on stream submit fail\n");
flgBailError = 1;
}
}
flgPacketsConsumed = 0;
while (!flgPacketsConsumed && !flgBailError) { /* Iterates over packets
*/
/*
// Valid page submitted to stream, now pull out as packets
// There may be more than 1 packet per page. Pull all packets
// before asking for another page.
*/
s_rv0 = ogg_stream_packetout(os, op);
dprintf("Packet out: %d %d %p %p\n", packetCount, s_rv0, os, op);
if (s_rv0 < 0) {
flgBailError = 1;
dprintf("Packet consumption error bail\n");
} else if (s_rv0 == 0) {
dprintf("Packets consumed. Get more data.\n");
flgPacketsConsumed = 1;
}
if (s_rv0 > 0) { /* Packet valid */
/* Only increment packet counter on valid packet */
++packetCount;
/* Packet valid & counts valid ... do something with it */
dprintf("Packet val: %d %d %lld %p %p\n", packetCount, s_rv0,
ogg_packet_get_packetno(op), os, op);
/*
// Use the actual packet for packet numbers as a dropped packet will
// mess up the running packetCount total (which should be removed
eventually)
*/
if (ogg_packet_get_packetno(op) <= LAST_VORBIS_HEADER_PACKET) {
// Currently decoding inside the vorbis headers (first three packets)
v_rv0 = vorbis_synthesis_headerin(vi, vc, op);
dprintf("Header decode: %d %p %p %p\n", v_rv0, vi, vc, op);
if (ogg_packet_get_packetno(op) == LAST_VORBIS_HEADER_PACKET) {
/*
// WARNING! DO NOT CALL vorbis_synthesis_init BEFORE YOU HAVE
// PROCESSED **ALL** THE HEADERS. FAILURE TO DO SO WILL CAUSE
// MALLOC/FREE PROBLEMS LATER.
// FIXME: vorbis_synthesis_init needs a renaming/refactoring. It
// really isn't an independent init like others. It has a
// dependency upon having a fully filled out vorbis_info structure.
// Such a dependency really should cause a change in the name
// to something like vorbis_synthesis_postheader_init.
// FIXME: Does vorbis_block_init have a post-dependency upon
// vorbis_synthesis_init?
*/
vorbis_synthesis_init(vd, vi);
vorbis_block_init(vd, vb);
}
} else {
/* Stream packet, not a header packet */
v_rv0 = vorbis_synthesis(vb, op, 1);
dprintf("Vorbis synthesis: %d %p %p\n", v_rv0, vb, op);
if (v_rv0 == 0) {
/* Block is valid for synthesis and synthesis is ready */
v_rv0 = vorbis_synthesis_blockin(vd, vb);
if (v_rv0 == 0) {
/* Synthesis was successful. Pull out the data */
int pcmSamples = 1;
ogg_int32_t **pcm;
int numChannels = 2; /* FIXME: Should really pull this from info */
int ii, jj;
while(pcmSamples > 0) {
pcmSamples = vorbis_synthesis_pcmout(vd, &pcm);
/* Interleaver for output PCM */
for(ii=0; ii<pcmSamples; ++ii) {
for(jj=0; jj<numChannels; ++jj) {
ogg_int32_t *srcChannelArray = pcm[jj];
ogg_int32_t srcValue = srcChannelArray[ii];
short dstValue = CLIP_TO_15(srcValue>>9);
long bytesWritten = fwrite(&dstValue, 2, 1, stdout);
}
}
/* Let the decoder know how many samples we actually consumed */
vorbis_synthesis_read(vd, pcmSamples);
}
}
}
}
} /* Packet valid */
} /* Iterates over packets */
} /* Page system has been initialized and is valid */
/*
// Don't pull another page at EOS. Let that occur after reset on
another
// trip through so that we match the normal uninitialized case.
*/
if (!flgEOSPage && !flgBailError) {
o_rv0 = 0;
while(o_rv0 != 1 && !flgBailError) {
o_rv0 = ogg_sync_pageout(oy, og);
if (o_rv0 > 0) {
flgInitialPageRead = 1;
}
if (o_rv0 <= 0) {
if (o_rv0 < 0) {
dprintf("Skipping bytes...\n");
} else {
dprintf("Need more data...\n");
}
if (o_rv0 == 0) {
unsigned char* bb = ogg_sync_bufferin(oy, BCHUNKSIZE);
long bytesRead = fread(bb, 1, BCHUNKSIZE, stdin);
dprintf("Consumed: %ld bytes\n", bytesRead);
if (bytesRead > 0) {
// Got bytes
ogg_sync_wrote(oy, bytesRead);
bytesConsumed += bytesRead;
} else if (bytesRead == 0) {
// EOF
dprintf("EOF error bail\n");
flgBailError = 1;
} else {
// Error
dprintf("Data error encountered: %ld\n", bytesRead);
flgBailError = 1;
}
}
}
}
}
if (flgEOSPage && !flgBailError) {
dprintf("EOS flagged\n");
/*
// System has eaten all available stream packets
// System should now reset and recycle
*/
flgBailEOS = 1;
}
if (flgBailEOS || flgBailError) {
dprintf("Bailing\n");
/*
// FIXME: This is effectively broken.
// CAUTION: If you do not manage to do a clean vorbis_synthesis_init
// these functions will have nasty malloc/free problems. You may *NOT*
// just clear these and hope for the best. It doesn't work.
//
// Originally, I was calling vorbis_synthesis_init too early and then
// vorbis_info_clear was throwing malloc/free failures.
*/
vorbis_block_clear(vb);
vorbis_dsp_clear(vd); // Inverse of vorbis_synthesis_init() ???
vorbis_comment_clear(vc);
vorbis_info_clear(vi);
}
} /* This while loop iterates over ogg pages */
} /* This while loop iterates over ogg logical streams */
dprintf("Destroying stream state\n");
/* System has terminated -- clean up */
ogg_stream_destroy(os);
ogg_sync_destroy(oy);
dprintf("System bailing\n");
dprintf("Done. Consumed: %ld\n", bytesConsumed);
return(0);
}
-------------- next part --------------
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: subsumed libogg includes
********************************************************************/
#ifndef _OGG_H
#define _OGG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "os_types.h"
typedef struct ogg_buffer_state{
struct ogg_buffer *unused_buffers;
struct ogg_reference *unused_references;
int outstanding;
int shutdown;
} ogg_buffer_state;
typedef struct ogg_buffer {
unsigned char *data;
long size;
int refcount;
union {
ogg_buffer_state *owner;
struct ogg_buffer *next;
} ptr;
} ogg_buffer;
typedef struct ogg_reference {
ogg_buffer *buffer;
long begin;
long length;
struct ogg_reference *next;
} ogg_reference;
typedef struct oggpack_buffer {
int headbit;
unsigned char *headptr;
long headend;
/* memory management */
ogg_reference *head;
ogg_reference *tail;
/* render the byte/bit counter API constant time */
long count; /* doesn't count the tail */
} oggpack_buffer;
typedef struct oggbyte_buffer {
ogg_reference *baseref;
ogg_reference *ref;
unsigned char *ptr;
long pos;
long end;
} oggbyte_buffer;
typedef struct ogg_sync_state {
/* decode memory management pool */
ogg_buffer_state *bufferpool;
/* stream buffers */
ogg_reference *fifo_head;
ogg_reference *fifo_tail;
long fifo_fill;
/* stream sync management */
int unsynced;
int headerbytes;
int bodybytes;
} ogg_sync_state;
typedef struct ogg_stream_state {
ogg_reference *header_head;
ogg_reference *header_tail;
ogg_reference *body_head;
ogg_reference *body_tail;
int e_o_s; /* set when we have buffered the last
packet in the logical bitstream */
int b_o_s; /* set after we've written the initial page
of a logical bitstream */
long serialno;
long pageno;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a seperate abstraction
layer) also knows about the gap */
ogg_int64_t granulepos;
int lacing_fill;
ogg_uint32_t body_fill;
/* decode-side state data */
int holeflag;
int spanflag;
int clearflag;
int laceptr;
ogg_uint32_t body_fill_next;
} ogg_stream_state;
typedef struct {
ogg_reference *packet;
long bytes;
long b_o_s;
long e_o_s;
ogg_int64_t granulepos;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a seperate abstraction
layer) also knows about the gap */
} ogg_packet;
typedef struct {
ogg_reference *header;
int header_len;
ogg_reference *body;
long body_len;
} ogg_page;
/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
extern void oggpack_readinit(oggpack_buffer *b,ogg_reference *r);
extern long oggpack_look(oggpack_buffer *b,int bits);
extern void oggpack_adv(oggpack_buffer *b,int bits);
extern long oggpack_read(oggpack_buffer *b,int bits);
extern long oggpack_bytes(oggpack_buffer *b);
extern long oggpack_bits(oggpack_buffer *b);
extern int oggpack_eop(oggpack_buffer *b);
/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
extern ogg_sync_state *ogg_sync_create(void);
extern int ogg_sync_destroy(ogg_sync_state *oy);
extern int ogg_sync_reset(ogg_sync_state *oy);
extern unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long size);
extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
/* Ogg BITSTREAM PRIMITIVES: general ***************************/
extern ogg_stream_state *ogg_stream_create(int serialno);
extern int ogg_stream_destroy(ogg_stream_state *os);
extern int ogg_stream_reset(ogg_stream_state *os);
extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
extern int ogg_stream_eos(ogg_stream_state *os);
extern int ogg_page_checksum_set(ogg_page *og);
extern int ogg_page_version(ogg_page *og);
extern int ogg_page_continued(ogg_page *og);
extern int ogg_page_bos(ogg_page *og);
extern int ogg_page_eos(ogg_page *og);
extern ogg_int64_t ogg_page_granulepos(ogg_page *og);
extern ogg_uint32_t ogg_page_serialno(ogg_page *og);
extern ogg_uint32_t ogg_page_pageno(ogg_page *og);
extern int ogg_page_packets(ogg_page *og);
extern int ogg_page_getbuffer(ogg_page *og, unsigned char **buffer);
extern int ogg_packet_release(ogg_packet *op);
extern int ogg_page_release(ogg_page *og);
extern void ogg_page_dup(ogg_page *d, ogg_page *s);
/* Ogg BITSTREAM PRIMITIVES: return codes ***************************/
#define OGG_SUCCESS 0
#define OGG_HOLE -10
#define OGG_SPAN -11
#define OGG_EVERSION -12
#define OGG_ESERIAL -13
#define OGG_EINVAL -14
#define OGG_EEOS -15
/* Static inline accessors to avoid hitting the struct directly */
static inline long ogg_stream_state_get_serialno(ogg_stream_state* os) {return
os->serialno;};
static inline long ogg_packet_get_bytes(ogg_packet* op) {return op->bytes;};
static inline ogg_int64_t ogg_packet_get_granulepos(ogg_packet* op) {return
op->granulepos;};
static inline ogg_int64_t ogg_packet_get_packetno(ogg_packet* op) {return
op->packetno;};
static inline long ogg_packet_get_b_o_s(ogg_packet* op) {return op->b_o_s;};
static inline long ogg_packet_get_e_o_s(ogg_packet* op) {return op->e_o_s;};
static inline int ogg_page_header_len(ogg_page* og) {return og->header_len;};
static inline long ogg_page_body_len(ogg_page* og) {return og->body_len;};
static inline void oggpack_readinit_opaque(oggpack_buffer *b, ogg_packet *op)
{oggpack_readinit(b, op->packet);};
#ifdef __cplusplus
}
#endif
#endif /* _OGG_H */