diff options
author | Jack Moffitt <jack@xiph.org> | 2000-09-03 05:54:26 +0000 |
---|---|---|
committer | Jack Moffitt <jack@xiph.org> | 2000-09-03 05:54:26 +0000 |
commit | f49beca1438135e247e96b3feef7b0750c9340d9 (patch) | |
tree | 1d5ac0d04a81d4954932d3073ea096bd576abf2c | |
download | ogg-git-f49beca1438135e247e96b3feef7b0750c9340d9.tar.gz |
Initial revision
svn path=/trunk/ogg/; revision=618
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | COPYING | 481 | ||||
-rw-r--r-- | Makefile.am | 13 | ||||
-rw-r--r-- | README | 1 | ||||
-rwxr-xr-x | autogen.sh | 47 | ||||
-rw-r--r-- | configure.in | 221 | ||||
-rw-r--r-- | doc/Makefile.am | 9 | ||||
-rw-r--r-- | doc/framing.html | 384 | ||||
-rw-r--r-- | doc/index.html | 3 | ||||
-rw-r--r-- | doc/oggstream.html | 192 | ||||
-rw-r--r-- | doc/stream.png | bin | 0 -> 2327 bytes | |||
-rw-r--r-- | doc/white-ogg.png | bin | 0 -> 1181 bytes | |||
-rw-r--r-- | doc/white-xifish.png | bin | 0 -> 965 bytes | |||
-rw-r--r-- | include/Makefile.am | 5 | ||||
-rw-r--r-- | include/ogg/Makefile.am | 7 | ||||
-rw-r--r-- | include/ogg/ogg.h | 154 | ||||
-rw-r--r-- | include/ogg/os_types.h.in | 55 | ||||
-rw-r--r-- | libogg.spec | 73 | ||||
-rw-r--r-- | src/Makefile.am | 16 | ||||
-rw-r--r-- | src/bitwise.c | 434 | ||||
-rw-r--r-- | src/framing.c | 1622 |
22 files changed, 3722 insertions, 0 deletions
@@ -0,0 +1,3 @@ +Monty <monty@xiph.org> + +and the rest of the Xiphophorus Company. @@ -0,0 +1,2 @@ +- Sat Sep 02 2000 Jack Moffitt <jack@icecast.org> + + separated from vorbis @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..82dd451 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,13 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign dist-zip + +SUBDIRS = src include doc + +EXTRA_DIST = README AUTHORS CHANGES COPYING libogg.spec + +debug: + $(MAKE) all CFLAGS="@DEBUG@" + +profile: + $(MAKE) all CFLAGS="@PROFILE@" @@ -0,0 +1 @@ +This is the Ogg bistream library diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..5b2c05d --- /dev/null +++ b/autogen.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. +# (basically ripped directly from enlightenment's autogen.sh) + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +cd "$srcdir" +DIE=0 + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile libogg." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have automake installed to compile libogg." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if test -z "$*"; then + echo "I am going to run ./configure with no arguments - if you wish " + echo "to pass any to it, please specify them on the $0 command line." +fi + +echo "Generating configuration files for libogg, please wait...." + +echo " aclocal $ACLOCAL_FLAGS" +aclocal $ACLOCAL_FLAGS +echo " autoheader" +autoheader +echo " automake --add-missing" +automake --add-missing +echo " autoconf" +autoconf + +$srcdir/configure "$@" && echo diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..c653ba4 --- /dev/null +++ b/configure.in @@ -0,0 +1,221 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(src/framing.c) + +AM_INIT_AUTOMAKE(libogg,1.0.0) + +AC_PROG_CC +AM_PROG_LIBTOOL + +dnl Set some options based on environment + +if test -z "$GCC"; then + case $host in + *-*-irix*) + DEBUG="-g -signed" + CFLAGS="-O2 -w -signed" + PROFILE="-p -g3 -O2 -signed" + ;; + sparc-sun-solaris*) + DEBUG="-v -g" + CFLAGS="-xO4 -fast -w -fsimple -native -xcg92" + PROFILE="-v -xpg -g -xO4 -fast -native -fsimple -xcg92 -Dsuncc" + ;; + *) + DEBUG="-g" + CFLAGS="-O" + PROFILE="-g -p" + ;; + esac +else + case $host in + *-*-linux*) + DEBUG="-g -Wall -fsigned-char" + CFLAGS="-O20 -ffast-math -fsigned-char" + PROFILE="-Wall -W -pg -g -O20 -ffast-math -fsigned-char" + ;; + sparc-sun-*) + DEBUG="-g -Wall -fsigned-char -mv8" + CFLAGS="-O20 -ffast-math -fsigned-char -mv8" + PROFILE="-pg -g -O20 -fsigned-char -mv8" + ;; + *) + DEBUG="-g -Wall -fsigned-char" + CFLAGS="-O20 -fsigned-char" + PROFILE="-O20 -g -pg -fsigned-char" + ;; + esac +fi + +dnl Checks for programs. + +dnl Checks for libraries. + +dnl Checks for header files. +AC_HEADER_STDC + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +dnl Check for types + +AC_MSG_CHECKING(for int16_t) +AC_CACHE_VAL(has_int16_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int16_t foo; +int main() {return 0;} +], +has_int16_t=yes, +has_int16_t=no, +has_int16_t=no +)]) +AC_MSG_RESULT($has_int16_t) + +AC_MSG_CHECKING(for int32_t) +AC_CACHE_VAL(has_int32_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int32_t foo; +int main() {return 0;} +], +has_int32_t=yes, +has_int32_t=no, +has_int32_t=no +)]) +AC_MSG_RESULT($has_int32_t) + +AC_MSG_CHECKING(for uint32_t) +AC_CACHE_VAL(has_uint32_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +uint32_t foo; +int main() {return 0;} +], +has_uint32_t=yes, +has_uint32_t=no, +has_uint32_t=no +)]) +AC_MSG_RESULT($has_uint32_t) + +AC_MSG_CHECKING(for u_int32_t) +AC_CACHE_VAL(has_u_int32_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +u_int32_t foo; +int main() {return 0;} +], +has_u_int32_t=yes, +has_u_int32_t=no, +has_u_int32_t=no +)]) +AC_MSG_RESULT($has_u_int32_t) + +AC_MSG_CHECKING(for int64_t) +AC_CACHE_VAL(has_int64_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int64_t foo; +int main() {return 0;} +], +has_int64_t=yes, +has_int64_t=no, +has_int64_t=no +)]) +AC_MSG_RESULT($has_int64_t) + +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(long long) + + +if test x$has_int16_t = "xyes" ; then + SIZE16="int16_t" +else + case 2 in + $ac_cv_sizeof_short) SIZE16="short";; + $ac_cv_sizeof_int) SIZE16="int";; + esac +fi + +if test x$has_int32_t = "xyes" ; then + SIZE32="int32_t" +else + case 4 in + $ac_cv_sizeof_short) SIZE32="short";; + $ac_cv_sizeof_int) SIZE32="int";; + $ac_cv_sizeof_long) SIZE32="long";; + esac +fi + +if test x$has_uint32_t = "xyes" ; then + USIZE32="uint32_t" +else + if test x$has_u_int32_t = "xyes" ; then + USIZE32="u_int32_t" + else + case 4 in + $ac_cv_sizeof_short) USIZE32="unsigned short";; + $ac_cv_sizeof_int) USIZE32="unsigned int";; + $ac_cv_sizeof_long) USIZE32="unsigned long";; + esac + fi +fi + +if test x$has_int64_t = "xyes" ; then + SIZE64="int64_t" +else +case 8 in + $ac_cv_sizeof_int) SIZE64="int";; + $ac_cv_sizeof_long) SIZE64="long";; + $ac_cv_sizeof_long_long) SIZE64="long long";; +esac +fi + +if test -z "$SIZE16"; then + AC_MSG_ERROR(No 16 bit type found on this platform!) +fi +if test -z "$SIZE32"; then + AC_MSG_ERROR(No 32 bit type found on this platform!) +fi +if test -z "$USIZE32"; then + AC_MSG_ERROR(No unsigned 32 bit type found on this platform!) +fi +if test -z "$SIZE64"; then + AC_MSG_WARN(No 64 bit type found on this platform!) +fi + +dnl Checks for library functions. +AC_FUNC_MEMCMP + +dnl Make substitutions + +AC_SUBST(LIBTOOL_DEPS) +AC_SUBST(SIZE16) +AC_SUBST(SIZE32) +AC_SUBST(USIZE32) +AC_SUBST(SIZE64) +AC_SUBST(OPT) +AC_SUBST(LIBS) +AC_SUBST(DEBUG) +AC_SUBST(CFLAGS) +AC_SUBST(PROFILE) +AC_SUBST(CC) +AC_SUBST(RANLIB) + +AC_OUTPUT(Makefile src/Makefile doc/Makefile include/Makefile include/ogg/Makefile include/ogg/os_types.h) diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..8893207 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,9 @@ +## Process this with automake to create Makefile.in + +AUTOMAKE_OPTIONS = foreign + +docdir = $(prefix)/doc/$(PACKAGE)-$(VERSION) + +doc_DATA = index.html framing.html oggstream.html white-xifish.png stream.png white-ogg.png + +EXTRA_DIST = $(doc_DATA) diff --git a/doc/framing.html b/doc/framing.html new file mode 100644 index 0000000..51054c7 --- /dev/null +++ b/doc/framing.html @@ -0,0 +1,384 @@ +<HTML><HEAD><TITLE>xiph.org: Ogg Vorbis documentation</TITLE> +<BODY bgcolor="#ffffff" text="#202020" link="#006666" vlink="#000000"> +<nobr><a href="vorbis.html"><img src="white-ogg.png" border=0><img +src="vorbisword2.png" border=0></a></nobr><p> + +<h1><font color=#000070> +Ogg logical bitstream framing +</font></h1> + +<em>Last update to this document: July 15, 1999</em><br> + +<h2>Ogg bitstreams</h2> + +Vorbis encodes short-time blocks of PCM data into raw packets of +bit-packed data. These raw packets may be used directly by transport +mechanisms that provide their own framing and packet-seperation +mechanisms (such as UDP datagrams). For stream based storage (such as +files) and transport (such as TCP streams or pipes), Vorbis uses the +Ogg bitstream format to provide framing/sync, sync recapture +after error, landmarks during seeking, and enough information to +properly seperate data back into packets at the original packet +boundaries without relying on decoding to find packet boundaries.<p> + +<h2>Design constraints for Ogg bitstreams</h2> + +<ol><li>True streaming; we must not need to seek to build a 100% + complete bitstream. + +<li> Use no more than approximately 1-2% of bitstream bandwidth for + packet boundary marking, high-level framing, sync and seeking. + +<li> Specification of absolute position within the original sample + stream. + +<li> Simple mechanism to ease limited editing, such as a simplified + concatenation mechanism. + +<li> Detection of corruption, recapture after error and direct, random + access to data at arbitrary positions in the bitstream. +</ol> + +<h2>Logical and Physical Bitstreams</h2> + +A <em>logical</em> Ogg bitstream is a contiguous stream of +sequential pages belonging only to the logical bitstream. A +<em>physical</em> Ogg bitstream is constructed from one or more +than one logical Ogg bitstream (the simplest physical bitstream +is simply a single logical bitstream). We describe below the exact +formatting of an Ogg logical bitstream. Combining logical +bitstreams into more complex physical bitstreams is described in the +<a href="oggstream.html">Ogg bitstream overview</a>. The exact +mapping of raw Vorbis packets into a valid Ogg Vorbis physical +bitstream is described in <a href="vorbis-stream.html">Vorbis +bitstream mapping</a>. + +<h2>Bitstream structure</h2> + +An Ogg stream is structured by dividing incoming packets into +segments of up to 255 bytes and then wrapping a group of contiguous +packet segments into a variable length page preceeded by a page +header. Both the header size and page size are variable; the page +header contains sizing information and checksum data to determine +header/page size and data integrity.<p> + +The bitstream is captured (or recaptured) by looking for the beginning +of a page, specifically the capture pattern. Once the capture pattern +is found, the decoder verifies page sync and integrity by computing +and comparing the checksum. At that point, the decoder can extract the +packets themselves.<p> + +<h3>Packet segmentation</h3> + +Packets are logically divided into multiple segments before encoding +into a page. Note that the segmentation and fragmentation process is a +logical one; it's used to compute page header values and the original +page data need not be disturbed, even when a packet spans page +boundaries.<p> + +The raw packet is logically divided into [n] 255 byte segments and a +last fractional segment of < 255 bytes. A packet size may well +consist only of the trailing fractional segment, and a fractional +segment may be zero length. These values, called "lacing values" are +then saved and placed into the header segment table.<p> + +An example should make the basic concept clear:<p> + +<pre> +<tt> +raw packet: + ___________________________________________ + |______________packet data__________________| 753 bytes + +lacing values for page header segment table: 255,255,243 +</tt> +</pre> + +We simply add the lacing values for the total size; the last lacing +value for a packet is always the value that is less than 255. Note +that this encoding both avoids imposing a maximum packet size as well +as imposing minimum overhead on small packets (as opposed to, eg, +simply using two bytes at the head of every packet and having a max +packet size of 32k. Small packets (<255, the typical case) are +penalized with twice the segmentation overhead). Using the lacing +values as suggested, small packets see the minimum possible +byte-aligned overheade (1 byte) and large packets, over 512 bytes or +so, see a fairly constant ~.5% overhead on encoding space.<p> + +Note that a lacing value of 255 implies that a second lacing value +follows in the packet, and a value of < 255 marks the end of the +packet after that many additional bytes. A packet of 255 bytes (or a +multiple of 255 bytes) is terminated by a lacing value of 0:<p> + +<pre><tt> +raw packet: + _______________________________ + |________packet data____________| 255 bytes + +lacing values: 255, 0 +</tt></pre> + +Note also that a 'nil' (zero length) packet is not an error; it +consists of nothing more than a lacing value of zero in the header.<p> + +<h3>Packets spanning pages</h3> + +Packets are not resticted to beginning and ending within a page, +although individual segments are, by definition, required to do so. +Packets are not restricted to a maximum size, although excessively +large packets in the data stream are discouraged; the Ogg +bitstream specification strongly recommends nominal page size of +approximately 4-8kB (large packets are forseen as being useful for +initialization data at the beginning of a logical bitstream).<p> + +After segmenting a packet, the encoder may decide not to place all the +resulting segments into the current page; to do so, the encoder places +the lacing values of the segments it wishes to belong to the current +page into the current segment table, then finishes the page. The next +page is begun with the first value in the segment table belonging to +the next packet segment, thus continuing the packet (data in the +packet body must also correspond properly to the lacing values in the +spanned pages. The segment data in the first packet corresponding to +the lacing values of the first page belong in that page; packet +segments listed in the segment table of the following page must begin +the page body of the subsequent page).<p> + +The last mechanic to spanning a page boundary is to set the header +flag in the new page to indicate that the first lacing value in the +segment table continues rather than begins a packet; a header flag of +0x01 is set to indicate a continued packet. Although mandatory, it +is not actually algorithmically necessary; one could inspect the +preceeding segment table to determine if the packet is new or +continued. Adding the information to the packet_header flag allows a +simpler design (with no overhead) that needs only inspect the current +page header after frame capture. This also allows faster error +recovery in the event that the packet originates in a corrupt +preceeding page, implying that the previous page's segment table +cannot be trusted.<p> + +Note that a packet can span an arbitrary number of pages; the above +spanning process is repeated for each spanned page boundary. Also a +'zero termination' on a packet size that is an even multiple of 255 +must appear even if the lacing value appears in the next page as a +zero-length continuation of the current packet. The header flag +should be set to 0x01 to indicate that the packet spanned, even though +the span is a nil case as far as data is concerned.<p> + +The encoding looks odd, but is properly optimized for speed and the +expected case of the majority of packets being between 50 and 200 +bytes (note that it is designed such that packets of wildly different +sizes can be handled within the model; placing packet size +restrictions on the encoder would have only slightly simplified design +in page generation and increased overall encoder complexity).<p> + +The main point behind tracking individual packets (and packet +segments) is to allow more flexible encoding tricks that requiring +explicit knowledge of packet size. An example is simple bandwidth +limiting, implemented by simply truncating packets in the nominal case +if the packet is arranged so that the least sensitive portion of the +data comes last.<p> + +<h3>Page header</h3> + +The headering mechanism is designed to avoid copying and re-assembly +of the packet data (ie, making the packet segmentation process a +logical one); the header can be generated directly from incoming +packet data. The encoder buffers packet data until it finishes a +complete page at which point it writes the header followed by the +buffered packet segments.<p> + +<h4>capture_pattern</h4> + + A header begins with a capture pattern that simplifies identifying + pages; once the decoder has found the capture pattern it can do a more + intensive job of verifying that it has in fact found a page boundary + (as opposed to an inadvertant coincidence in the byte stream).<p> + +<pre><tt> + byte value + + 0 0x4f 'O' + 1 0x67 'g' + 2 0x67 'g' + 3 0x53 'S' +</tt></pre> + +<h4>stream_structure_version</h4> + + The capture pattern is followed by the stream structure revision: + +<pre><tt> + byte value + + 4 0x00 +</tt></pre> + +<h4>header_type_flag</h4> + + The header type flag identifies this page's context in the bitstream: + +<pre><tt> + byte value + + 5 bitflags: 0x01: unset = fresh packet + set = continued packet + 0x02: unset = not first page of logical bitstream + set = first page of logical bitstream (bos) + 0x04: unset = not last page of logical bitstream + set = last page of logical bitstream (eos) +</tt></pre> + +<h4>PCM absolute position</h4> + + (This is packed in the same way the rest of Ogg data is packed; + LSb of LSB first. Note that the 'position' data specifies a 'sample' + number (eg, in a CD quality sample is four octets, 16 bits for left + and 16 bits for right; in video it would be the frame number). The + position specified is the total samples encoded after including all + packets finished on this page (packets begun on this page but + continuing on to thenext page do not count). The rationale here is + that the position specified in the frame header of the last page + tells how long the PCM data coded by the bitstream is. A truncated + stream will still return the proper number of samples that can be + decoded fully. + +<pre><tt> + byte value + + 6 0xXX LSB + 7 0xXX + 8 0xXX + 9 0xXX + 10 0xXX + 11 0xXX + 12 0xXX + 13 0xXX MSB +</tt></pre> + +<h4>stream serial number</h4> + + Ogg allows for seperate logical bitstreams to be mixed at page + granularity in a physical bitstream. The most common case would be + sequential arrangement, but it is possible to interleave pages for + two seperate bitstreams to be decoded concurrently. The serial + number is the means by which pages physical pages are associated with + a particular logical stream. Each logical stream must have a unique + serial number within a physical stream: + +<pre><tt> + byte value + + 14 0xXX LSB + 15 0xXX + 16 0xXX + 17 0xXX MSB +</tt></pre> + +<h4>page sequence no</h4> + + Page counter; lets us know if a page is lost (useful where packets + span page boundaries). + +<pre><tt> + byte value + + 18 0xXX LSB + 19 0xXX + 20 0xXX + 21 0xXX MSB +</tt></pre> + +<h4>page checksum</h4> + + 32 bit CRC value (direct algorithm, initial val and final XOR = 0, + generator polynomial=0x04c11db7). The value is computed over the + entire header (with the CRC field in the header set to zero) and then + continued over the page. The CRC field is then filled with the + computed value.<p> + + (A thorough discussion of CRC algorithms can be found in <a + href="ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt">"A + Painless Guide to CRC Error Detection Algorithms"</a> by Ross + Williams <a + href="mailto:ross@guest.adelaide.edu.au">ross@guest.adelaide.edu.au</a>.) + +<pre><tt> + byte value + + 22 0xXX LSB + 23 0xXX + 24 0xXX + 25 0xXX MSB +</tt></pre> + +<h4>page_segments</h4> + + The number of segment entries to appear in the segment table. The + maximum number of 255 segments (255 bytes each) sets the maximum + possible physical page size at 65307 bytes or just under 64kB (thus + we know that a header corrupted so as destroy sizing/alignment + information will not cause a runaway bitstream. We'll read in the + page according to the corrupted size information that's guaranteed to + be a reasonable size regardless, notice the checksum mismatch, drop + sync and then look for recapture).<p> + +<pre><tt> + byte value + + 26 0x00-0xff (0-255) +</tt></pre> + +<h4>segment_table (containing packet lacing values)</h4> + + The lacing values for each packet segment physically appearing in + this page are listed in contiguous order. + +<pre><tt> + byte value + + 27 0x00-0xff (0-255) + [...] + n 0x00-0xff (0-255, n=page_segments+26) +</tt></pre> + +Total page size is calculated directly from the known header size and +lacing values in the segment table. Packet data segments follow +immediately after the header.<p> + +Page headers typically impose a flat .25-.5% space overhead assuming +nominal ~8k page sizes. The segmentation table needed for exact +packet recovery in the streaming layer adds approximately .5-1% +nominal assuming expected encoder behavior in the 44.1kHz, 128kbps +stereo encodings.<p> + +<hr> +<a href="http://www.xiph.org/"> +<img src="white-xifish.png" align=left border=0> +</a> +<font size=-2 color=#505050> + +Ogg is a <a href="http://www.xiph.org">Xiphophorus</a> effort to +protect essential tenets of Internet multimedia from corporate +hostage-taking; Open Source is the net's greatest tool to keep +everyone honest. See <a href="http://www.xiph.org/about.html">About +Xiphophorus</a> for details. +<p> + +Ogg Vorbis is the first Ogg audio CODEC. Anyone may +freely use and distribute the Ogg and Vorbis specification, +whether in a private, public or corporate capacity. However, +Xiphophorus and the Ogg project (xiph.org) reserve the right to set +the Ogg/Vorbis specification and certify specification compliance.<p> + +Xiphophorus's Vorbis software CODEC implementation is distributed +under the Lessr/Library GNU Public License. This does not restrict +third parties from distributing independent implementations of Vorbis +software under other licenses.<p> + +OggSquish, Vorbis, Xiphophorus and their logos are trademarks (tm) of +<a href="http://www.xiph.org/">Xiphophorus</a>. These pages are +copyright (C) 1994-2000 Xiphophorus. All rights reserved.<p> + +</body> + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..9b4232b --- /dev/null +++ b/doc/index.html @@ -0,0 +1,3 @@ +<a href="oggstream.html">Ogg logical and physical bitstream overview</a><br> +<a href="framing.html">Ogg logical bitstream framing</a><br> + diff --git a/doc/oggstream.html b/doc/oggstream.html new file mode 100644 index 0000000..46a221c --- /dev/null +++ b/doc/oggstream.html @@ -0,0 +1,192 @@ +<HTML><HEAD><TITLE>xiph.org: Ogg Vorbis documentation</TITLE> +<BODY bgcolor="#ffffff" text="#202020" link="#006666" vlink="#000000"> +<nobr><a href="vorbis.html"><img src="white-ogg.png" border=0><img +src="vorbisword2.png" border=0></a></nobr><p> + + +<h1><font color=#000070> +Ogg logical and physical bitstream overview +</font></h1> + +<em>Last update to this document: July 18, 1999</em><br> + +<h2>Ogg bitstreams</h2> + +Ogg codecs use octet vectors of raw, compressed data +(<em>packets</em>). These compressed packets do not have any +high-level structure or boundary information; strung together, they +appear to be streams of random bytes with no landmarks.<p> + +Raw packets may be used directly by transport mechanisms that provide +their own framing and packet-seperation mechanisms (such as UDP +datagrams). For stream based storage (such as files) and transport +(such as TCP streams or pipes), Vorbis and other future Ogg codecs use +the Ogg bitstream format to provide framing/sync, sync recapture +after error, landmarks during seeking, and enough information to +properly seperate data back into packets at the original packet +boundaries without relying on decoding to find packet boundaries.<p> + +<h2>Logical and physical bitstreams</h2> + +Raw packets are grouped and encoded into contiguous pages of +structured bitstream data called <em>logical bitstreams</em>. A +logical bitstream consists of pages, in order, belonging to a single +codec instance. Each page is a self contained entity (although it is +possible that a packet may be split and encoded across one or more +pages); that is, the page decode mechanism is designed to recognize, +verify and handle single pages at a time from the overall bitstream.<p> + +Multiple logical bitstreams can be combined (with restricctions) into +a single <em>physical bitstream</em>. A physical bitstream consists +of multiple logical bitstreams multiplexed at the page level. Whole +pages are taken in order from multiple logical bitstreams and combined +into a single physical stream of pages. The decoder reconstructs the +original logical bitstreams from the physical bitstream by taking the +pages in order fromt he physical bitstream and redirecting them into +the appropriate logical decoding entitiy. The simplest physical +bitstream is a single, unmultiplexed logical bitstream. <p> + +<a href=framing.html>Ogg Logical Bitstream Framing</a> discusses +the page format of an Ogg bitstream, the packet coding process +and logical bitstreams in detail. The remainder of this document +specifies requirements for constructing finished, physical Ogg +bitstreams.<p> + +<h2>Mapping Restrictions</h2> + +Logical bitstreams may not be mapped/multiplexed into physical +bitstreams without restriction. Here we discuss design restrictions +on Ogg physical bitstreams in general, mostly to introduce +design rationale. Each 'media' format defines its own (generally more +restrictive) mapping. An '<a href="vorbis-stream.html">Ogg Vorbis +Audio Bitstream</a>', for example, has a <a +href="vorbis-stream.html">specific physical bitstream structure</a>. +An 'Ogg A/V' bitstream (not currently specified) will also mandate a +specific, restricted physical bitstream format.<p> + +<h3>additional end-to-end structure</h3> + +The <a href="framing.html">framing specification</a> defines +'beginning of stream' and 'end of stream' page markers via a header +flag (it is possible for a stream to consist of a single page). A +stream always consists of an integer number of pages, an easy +requirement given the variable size nature of pages.<p> + +In addition to the header flag marking the first and last pages of a +logical bitstream, the first page of an Ogg bitstream obeys +additional restrictions. Each individual media mapping specifies its +own implementation details regarding these restrictions.<p> + +The first page of a logical Ogg bitstream consists of a single, +small 'initial header' packet that includes sufficient information to +identify the exact CODEC type and media requirements of the logical +bitstream. The intent of this restriction is to simplify identifying +the bitstream type and content; for a given media type (or across all +Ogg media types) we can know that we only need a small, fixed +amount of data to uniquely identify the bitstream type.<p> + +As an example, Ogg Vorbis places the name and revision of the Vorbis +CODEC, the audio rate and the audio quality into this initial header, +thus simplifying vastly the certain identification of an Ogg Vorbis +audio bitstream.<p> + +<h3>sequential multiplexing (chaining)</h3> + +The simplest form of logical bitstream multiplexing is concatenation +(<em>chaining</em>). Complete logical bitstreams are strung +one-after-another in order. The bitstreams do not overlap; the final +page of a given logical bitstream is immediately followed by the +initial page of the next. Chaining is the only logical->physical +mapping allowed by Ogg Vorbis.<p> + +Each chained logical bitstream must have a unique serial number within +the scope of the physical bitstream.<p> + +<h3>concurrent multiplexing (grouping)</h3> + +Logical bitstreams may also be multiplexed 'in parallel' +(<em>grouped</em>). An example of grouping would be to allow +streaming of seperate audio and video streams, using differnt codecs +and different logical bitstreams, in the same physical bitstream. +Whole pages from multiple logical bitstreams are mixed together.<p> + +The initial pages of each logical bitstream must appear first; the +media mapping specifies the order of the initial pages. For example, +Ogg A/V will eventually specify an Ogg video bitstream with +audio. The mapping may specify that the physical bitstream must begin +with the initial page of a logical video bitstream, followed by the +initial page of an audio stream. Unlike initial pages, terminal pages +for the logical bitstreams need not all occur contiguously (although a +specific media mapping may require this; it is not mandated by the +generic Ogg stream spec). Terminal pages may be 'nil' pages, +that is, pages containing no content but simply a page header with +position information and the 'last page of bitstream' flag set in the +page header.<p> + +Each grouped bitstream must have a unique serial number within the +scope of the physical bitstream.<p> + +<h3>sequential and concurrent multiplexing</h3> + +Groups of concurrently multiplexed bitstreams may be chained +consecutively. Such a physical bitstream obeys all the rules of both +grouped and chained multiplexed streams; the groups, when unchained , +must stand on their own as a valid concurrently multiplexed +bitstream.<p> + +<h3>multiplexing example</h3> + +Below, we present an example of a grouped and chained bitstream:<p> + +<img src=stream.png><p> + +In this example, we see pages from five total logical bitstreams +multiplexed into a physical bitstream. Note the following +characteristics: + +<ol><li>Grouped bitstreams begin together; all of the initial pages +must appear before any data pages. When concurrently multiplexed +groups are chained, the new group does not begin until all the +bitstreams in the previous group have terminated.<p> + +<li>The pages of concurrently multiplexed bitstreams need not conform +to a regular order; the only requirement is that page <tt>n</tt> of a +logical bitstream follow page <tt>n-1</tt> in the physical bitstream. +There are no restrictions on intervening pages belonging to other +logical bitstreams. (Tying page appearence to bitrate demands is one +logical strategy, ie, the page appears at the chronological point +where decode requires more information). + +</ol> + +<hr> +<a href="http://www.xiph.org/"> +<img src="white-xifish.png" align=left border=0> +</a> +<font size=-2 color=#505050> + +Ogg is a <a href="http://www.xiph.org">Xiphophorus</a> effort to +protect essential tenets of Internet multimedia from corporate +hostage-taking; Open Source is the net's greatest tool to keep +everyone honest. See <a href="http://www.xiph.org/about.html">About +Xiphophorus</a> for details. +<p> + +Ogg Vorbis is the first Ogg audio CODEC. Anyone may +freely use and distribute the Ogg and Vorbis specification, +whether in a private, public or corporate capacity. However, +Xiphophorus and the Ogg project (xiph.org) reserve the right to set +the Ogg/Vorbis specification and certify specification compliance.<p> + +Xiphophorus's Vorbis software CODEC implementation is distributed +under the Lesser/Library GNU Public License. This does not restrict +third parties from distributing independent implementations of Vorbis +software under other licenses.<p> + +OggSquish, Vorbis, Xiphophorus and their logos are trademarks (tm) of +<a href="http://www.xiph.org/">Xiphophorus</a>. These pages are +copyright (C) 1994-2000 Xiphophorus. All rights reserved.<p> + +</body> + + diff --git a/doc/stream.png b/doc/stream.png Binary files differnew file mode 100644 index 0000000..6e9dca8 --- /dev/null +++ b/doc/stream.png diff --git a/doc/white-ogg.png b/doc/white-ogg.png Binary files differnew file mode 100644 index 0000000..45dc0ac --- /dev/null +++ b/doc/white-ogg.png diff --git a/doc/white-xifish.png b/doc/white-xifish.png Binary files differnew file mode 100644 index 0000000..ab25cc8 --- /dev/null +++ b/doc/white-xifish.png diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..3dc04e7 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = ogg diff --git a/include/ogg/Makefile.am b/include/ogg/Makefile.am new file mode 100644 index 0000000..a272f8c --- /dev/null +++ b/include/ogg/Makefile.am @@ -0,0 +1,7 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign + +includedir = $(prefix)/include/ogg + +include_HEADERS = ogg.h os_types.h diff --git a/include/ogg/ogg.h b/include/ogg/ogg.h new file mode 100644 index 0000000..7853fa7 --- /dev/null +++ b/include/ogg/ogg.h @@ -0,0 +1,154 @@ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <ogg/os_types.h> + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + 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; + int 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; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t frameno; + 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 { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look_huff(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern int oggpack_adv_huff(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *_oggpack_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(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); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_eof(ogg_stream_state *os); + +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_frameno(ogg_page *og); +extern int ogg_page_serialno(ogg_page *og); +extern int ogg_page_pageno(ogg_page *og); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/include/ogg/os_types.h.in b/include/ogg/os_types.h.in new file mode 100644 index 0000000..7864170 --- /dev/null +++ b/include/ogg/os_types.h.in @@ -0,0 +1,55 @@ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os_types.h.in,v 1.1 2000/09/03 05:54:27 jack Exp $ + + ********************************************************************/ + +#ifdef _WIN32 +#ifndef __GNUC__ + +/* MSVC/Borland */ +typedef __int64 ogg_int64_t; +typedef __int32 ogg_int32_t; +typedef unsigned __int32 ogg_uint32_t; +typedef __int16 ogg_int16_t; + +#else + +/* Cygwin */ +#include <_G_config.h> +typedef _G_int64_t ogg_int64_t; +typedef _G_int32_t ogg_int32_t; +typedef unsigned _G_int32_t ogg_uint32_t; +typedef _G_int16_t ogg_int16_t; +#endif +#else + +#ifdef __BEOS__ +/* Be */ +#include <inttypes.h> +#endif + +#include <sys/types.h> + +/* filled in by configure */ +typedef @SIZE16@ ogg_int16_t; +typedef @SIZE32@ ogg_int32_t; +typedef @USIZE32@ ogg_uint32_t; +typedef @SIZE64@ ogg_int64_t; + +#endif /* _WIN32 */ +#endif /* _OS_TYPES_H */ diff --git a/libogg.spec b/libogg.spec new file mode 100644 index 0000000..a9672da --- /dev/null +++ b/libogg.spec @@ -0,0 +1,73 @@ +%define name libogg +%define version 1.0.0 +%define release 1 + +Summary: Ogg Bitstream Library +Name: %{name} +Version: %{version} +Release: %{release} +Group: Libraries/Multimedia +Copyright: LGPL +URL: http://www.xiph.org/ +Vendor: Xiphophorus <team@xiph.org> +Source: ftp://ftp.xiph.org/pub/ogg/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-root + +%description +Libogg is a library for manipulating ogg bitstreams. It handles +both making ogg bitstreams and getting packets from ogg bitstreams. + +%package devel +Summary: Ogg Bitstream Library Development +Group: Development/Libraries + +%description devel +The libogg-devel package contains the header files and documentation +needed to develop applications with libogg. + +%prep +%setup -q -n %{name}-%{version} + +%build +if [ ! -f configure ]; then + CFLAGS="$RPM_FLAGS" ./autogen.sh --prefix=/usr +else + CFLAGS="$RPM_FLAGS" ./configure --prefix=/usr +fi +make + +%install +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install + +%files +%defattr(-,root,root) +%doc AUTHORS +%doc CHANGES +%doc COPYING +%doc README +/usr/lib/libogg.so.* +/usr/lib/libogg.a + +%files devel +%doc doc/index.html +%doc doc/framing.html +%doc doc/oggstream.html +%doc doc/white-ogg.png +%doc doc/white-xifish.png +%doc doc/stream.png +/usr/include/ogg/ogg.h +/usr/include/ogg/os_types.h + +%clean +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%changelog +* Sat Sep 02 2000 Jack Moffitt <jack@icecast.org> +- initial spec file created diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ba76e64 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign + +INCLUDES = -I$(top_srcdir)/include + +lib_LTLIBRARIES = libogg.la + +libogg_la_SOURCES = framing.c bitwise.c +libogg_la_LDFLAGS = -version-info 1:0:0 + +debug: + $(MAKE) all CFLAGS="@DEBUG@" + +profile: + $(MAKE) all CFLAGS="@PROFILE@" diff --git a/src/bitwise.c b/src/bitwise.c new file mode 100644 index 0000000..cf2a237 --- /dev/null +++ b/src/bitwise.c @@ -0,0 +1,434 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: packing variable sized words into an octet stream + last mod: $Id: bitwise.c,v 1.1 2000/09/03 05:54:28 jack Exp $ + + ********************************************************************/ + +/* We're 'LSb' endian; if we write a word but read individual bits, + then we'll read the lsb first */ + +#include <string.h> +#include <stdlib.h> +#include <ogg/ogg.h> + +#define BUFFER_INCREMENT 256 + +static unsigned long mask[]= +{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, + 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, + 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, + 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, + 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, + 0x3fffffff,0x7fffffff,0xffffffff }; + +void _oggpack_writeinit(oggpack_buffer *b){ + memset(b,0,sizeof(oggpack_buffer)); + b->ptr=b->buffer=malloc(BUFFER_INCREMENT); + b->buffer[0]='\0'; + b->storage=BUFFER_INCREMENT; +} + +void _oggpack_reset(oggpack_buffer *b){ + b->ptr=b->buffer; + b->buffer[0]=0; + b->endbit=b->endbyte=0; +} + +void _oggpack_writeclear(oggpack_buffer *b){ + free(b->buffer); + memset(b,0,sizeof(oggpack_buffer)); +} + +void _oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + memset(b,0,sizeof(oggpack_buffer)); + b->buffer=b->ptr=buf; + b->storage=bytes; +} + +/* Takes only up to 32 bits. */ +void _oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ + if(b->endbyte+4>=b->storage){ + b->buffer=realloc(b->buffer,b->storage+BUFFER_INCREMENT); + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value&=mask[bits]; + bits+=b->endbit; + + b->ptr[0]|=value<<b->endbit; + + if(bits>=8){ + b->ptr[1]=value>>(8-b->endbit); + if(bits>=16){ + b->ptr[2]=value>>(16-b->endbit); + if(bits>=24){ + b->ptr[3]=value>>(24-b->endbit); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=value>>(32-b->endbit); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long _oggpack_look(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m=mask[bits]; + + bits+=b->endbit; + + if(b->endbyte+4>=b->storage){ + /* not the main path */ + if(b->endbyte+(bits-1)/8>=b->storage)return(-1); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + return(m&ret); +} + +long _oggpack_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>b->endbit)&1); +} + +/* Read in bits without advancing the bitptr; bits <= 8 */ +/* we never return 'out of bits'; we'll handle it on _adv */ +long _oggpack_look_huff(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m=mask[bits]; + + bits+=b->endbit; + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + } + return(m&ret); +} + +void _oggpack_adv(oggpack_buffer *b,int bits){ + bits+=b->endbit; + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; +} + +void _oggpack_adv1(oggpack_buffer *b){ + if(++(b->endbit)>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } +} + +/* have to check for overflow now. return -1 on overflow */ +int _oggpack_adv_huff(oggpack_buffer *b,int bits){ + if(b->endbyte+(b->endbit+bits-1)/8>=b->storage)return(-1); + bits+=b->endbit; + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return 0; +} + +/* bits <= 32 */ +long _oggpack_read(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m=mask[bits]; + + bits+=b->endbit; + + if(b->endbyte+4>=b->storage){ + /* not the main path */ + ret=-1; + if(b->endbyte+(bits-1)/8>=b->storage)goto overflow; + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit){ + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + } + ret&=m; + + overflow: + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return(ret); +} + +long _oggpack_read1(oggpack_buffer *b){ + unsigned long ret; + + if(b->endbyte>=b->storage){ + /* not the main path */ + ret=-1; + goto overflow; + } + + ret=(b->ptr[0]>>b->endbit)&1; + + overflow: + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return(ret); +} + +long _oggpack_bytes(oggpack_buffer *b){ + return(b->endbyte+(b->endbit+7)/8); +} + +long _oggpack_bits(oggpack_buffer *b){ + return(b->endbyte*8+b->endbit); +} + +unsigned char *_oggpack_buffer(oggpack_buffer *b){ + return(b->buffer); +} + +/* Self test of the bitwise routines; everything else is based on + them, so they damned well better be solid. */ + +#ifdef _V_SELFTEST +#include <stdio.h> + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +oggpack_buffer o; +oggpack_buffer r; + +void report(char *in){ + fprintf(stderr,"%s",in); + exit(1); +} + +void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ + long bytes,i; + unsigned char *buffer; + + _oggpack_reset(&o); + for(i=0;i<vals;i++) + _oggpack_write(&o,b[i],bits?bits:ilog(b[i])); + buffer=_oggpack_buffer(&o); + bytes=_oggpack_bytes(&o); + if(bytes!=compsize)report("wrong number of bytes!\n"); + for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){ + for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]); + report("wrote incorrect value!\n"); + } + _oggpack_readinit(&r,buffer,bytes); + for(i=0;i<vals;i++){ + int tbit=bits?bits:ilog(b[i]); + if(_oggpack_look(&r,tbit)==-1) + report("out of data!\n"); + if(_oggpack_look(&r,tbit)!=(b[i]&mask[tbit])) + report("looked at incorrect value!\n"); + if(tbit==1) + if(_oggpack_look1(&r)!=(b[i]&mask[tbit])) + report("looked at single bit incorrect value!\n"); + if(tbit==1){ + if(_oggpack_read1(&r)!=(b[i]&mask[tbit])) + report("read incorrect single bit value!\n"); + }else{ + if(_oggpack_read(&r,tbit)!=(b[i]&mask[tbit])) + report("read incorrect value!\n"); + } + } + if(_oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n"); +} + +int main(void){ + unsigned char *buffer; + long bytes,i; + static unsigned long testbuffer1[]= + {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7, + 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4}; + int test1size=43; + + static unsigned long testbuffer2[]= + {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212, + 1233432,534,5,346435231,14436467,7869299,76326614,167548585, + 85525151,0,12321,1,349528352}; + int test2size=21; + + static unsigned long large[]= + {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212, + 1233432,534,5,2146435231,14436467,7869299,76326614,167548585, + 85525151,0,12321,1,2146528352}; + + static unsigned long testbuffer3[]= + {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1, + 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1}; + int test3size=56; + + int onesize=33; + static int one[]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40, + 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172, + 223,4}; + + int twosize=6; + static int two[]={61,255,255,251,231,29}; + + int threesize=54; + static int three[]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254, + 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83, + 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10, + 100,52,4,14,18,86,77,1}; + + int foursize=38; + static int four[]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72, + 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169, + 28,2,133,0,1}; + + int fivesize=45; + static int five[]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62, + 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169, + 84,75,159,2,1,0,132,192,8,0,0,18,22}; + + int sixsize=7; + static int six[]={17,177,170,242,169,19,148}; + + /* Test read/write together */ + /* Later we test against pregenerated bitstreams */ + _oggpack_writeinit(&o); + + fprintf(stderr,"\nSmall preclipped packing: "); + cliptest(testbuffer1,test1size,0,one,onesize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nNull bit call: "); + cliptest(testbuffer3,test3size,0,two,twosize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nLarge preclipped packing: "); + cliptest(testbuffer2,test2size,0,three,threesize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\n32 bit preclipped packing: "); + _oggpack_reset(&o); + for(i=0;i<test2size;i++) + _oggpack_write(&o,large[i],32); + buffer=_oggpack_buffer(&o); + bytes=_oggpack_bytes(&o); + _oggpack_readinit(&r,buffer,bytes); + for(i=0;i<test2size;i++){ + if(_oggpack_look(&r,32)==-1)report("out of data. failed!"); + if(_oggpack_look(&r,32)!=large[i]){ + fprintf(stderr,"%ld != %ld (%lx!=%lx):",_oggpack_look(&r,32),large[i], + _oggpack_look(&r,32),large[i]); + report("read incorrect value!\n"); + } + _oggpack_adv(&r,32); + } + if(_oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n"); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nSmall unclipped packing: "); + cliptest(testbuffer1,test1size,7,four,foursize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nLarge unclipped packing: "); + cliptest(testbuffer2,test2size,17,five,fivesize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nSingle bit unclicpped packing: "); + cliptest(testbuffer3,test3size,1,six,sixsize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nTesting read past end: "); + _oggpack_readinit(&r,"\0\0\0\0\0\0\0\0",8); + for(i=0;i<64;i++){ + if(_oggpack_read(&r,1)!=0){ + fprintf(stderr,"failed; got -1 prematurely.\n"); + exit(1); + } + } + if(_oggpack_look(&r,1)!=-1 || + _oggpack_read(&r,1)!=-1){ + fprintf(stderr,"failed; read past end without -1.\n"); + exit(1); + } + _oggpack_readinit(&r,"\0\0\0\0\0\0\0\0",8); + if(_oggpack_read(&r,30)!=0 || _oggpack_read(&r,16)!=0){ + fprintf(stderr,"failed 2; got -1 prematurely.\n"); + exit(1); + } + + if(_oggpack_look(&r,18)!=0 || + _oggpack_look(&r,18)!=0){ + fprintf(stderr,"failed 3; got -1 prematurely.\n"); + exit(1); + } + if(_oggpack_look(&r,19)!=-1 || + _oggpack_look(&r,19)!=-1){ + fprintf(stderr,"failed; read past end without -1.\n"); + exit(1); + } + if(_oggpack_look(&r,32)!=-1 || + _oggpack_look(&r,32)!=-1){ + fprintf(stderr,"failed; read past end without -1.\n"); + exit(1); + } + fprintf(stderr,"ok.\n\n"); + + + return(0); +} +#endif /* _V_SELFTEST */ + +#undef BUFFER_INCREMENT diff --git a/src/framing.c b/src/framing.c new file mode 100644 index 0000000..0069a3f --- /dev/null +++ b/src/framing.c @@ -0,0 +1,1622 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and the XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: code raw [Vorbis] packets into framed OggSquish stream and + decode Ogg streams back into raw packets + last mod: $Id: framing.c,v 1.1 2000/09/03 05:54:28 jack Exp $ + + note: The CRC code is directly derived from public domain code by + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html + for details. + + ********************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <ogg/ogg.h> + +/* A complete description of Ogg framing exists in docs/framing.html */ + +int ogg_page_version(ogg_page *og){ + return((int)(og->header[4])); +} + +int ogg_page_continued(ogg_page *og){ + return((int)(og->header[5]&0x01)); +} + +int ogg_page_bos(ogg_page *og){ + return((int)(og->header[5]&0x02)); +} + +int ogg_page_eos(ogg_page *og){ + return((int)(og->header[5]&0x04)); +} + +ogg_int64_t ogg_page_frameno(ogg_page *og){ + unsigned char *page=og->header; + ogg_int64_t granulepos=page[13]&(0xff); + 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); + return(granulepos); +} + +int ogg_page_serialno(ogg_page *og){ + return(og->header[14] | + (og->header[15]<<8) | + (og->header[16]<<16) | + (og->header[17]<<24)); +} + +int ogg_page_pageno(ogg_page *og){ + return(og->header[18] | + (og->header[19]<<8) | + (og->header[20]<<16) | + (og->header[21]<<24)); +} + +/* helper to initialize lookup for direct-table CRC */ + +static ogg_uint32_t crc_lookup[256]; +static int crc_ready=0; + +static ogg_uint32_t _ogg_crc_entry(unsigned long index){ + int i; + unsigned long r; + + r = index << 24; + for (i=0; i<8; i++) + if (r & 0x80000000UL) + r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator + polynomial, although we use an + unreflected alg and an init/final + of 0, not 0xffffffff */ + else + r<<=1; + return (r & 0xffffffffUL); +} + +/* mind this in threaded code; sync_init and stream_init call it. + It's thread safe only after the first time it returns */ + +static void _ogg_crc_init(void){ + if(!crc_ready){ + /* initialize the crc_lookup table */ + int i; + for (i=0;i<256;i++) + crc_lookup[i]=_ogg_crc_entry((unsigned long)i); + crc_ready=0; + } +} + +/* init the encode/decode logical stream state */ + +int ogg_stream_init(ogg_stream_state *os,int serialno){ + if(os){ + memset(os,0,sizeof(ogg_stream_state)); + os->body_storage=16*1024; + os->body_data=malloc(os->body_storage*sizeof(char)); + + os->lacing_storage=1024; + os->lacing_vals=malloc(os->lacing_storage*sizeof(int)); + os->granule_vals=malloc(os->lacing_storage*sizeof(ogg_int64_t)); + + /* initialize the crc_lookup table if not done */ + _ogg_crc_init(); + + os->serialno=serialno; + + return(0); + } + return(-1); +} + +/* _clear does not free os, only the non-flat storage within */ +int ogg_stream_clear(ogg_stream_state *os){ + if(os){ + if(os->body_data)free(os->body_data); + if(os->lacing_vals)free(os->lacing_vals); + if(os->granule_vals)free(os->granule_vals); + + memset(os,0,sizeof(ogg_stream_state)); + } + return(0); +} + +int ogg_stream_destroy(ogg_stream_state *os){ + if(os){ + ogg_stream_clear(os); + free(os); + } + return(0); +} + +/* Helpers for ogg_stream_encode; this keeps the structure and + what's happening fairly clear */ + +static void _os_body_expand(ogg_stream_state *os,int needed){ + if(os->body_storage<=os->body_fill+needed){ + os->body_storage+=(needed+1024); + os->body_data=realloc(os->body_data,os->body_storage); + } +} + +static void _os_lacing_expand(ogg_stream_state *os,int needed){ + if(os->lacing_storage<=os->lacing_fill+needed){ + os->lacing_storage+=(needed+32); + os->lacing_vals=realloc(os->lacing_vals,os->lacing_storage*sizeof(int)); + os->granule_vals=realloc(os->granule_vals,os->lacing_storage*sizeof(ogg_int64_t)); + } +} + +/* checksum the page */ +/* Direct table CRC; note that this will be faster in the future if we + perform the checksum silmultaneously with other copies */ + +static void _os_checksum(ogg_page *og){ + ogg_uint32_t crc_reg=0; + int i; + + for(i=0;i<og->header_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; + for(i=0;i<og->body_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; + + og->header[22]=crc_reg&0xff; + og->header[23]=(crc_reg>>8)&0xff; + og->header[24]=(crc_reg>>16)&0xff; + og->header[25]=(crc_reg>>24)&0xff; +} + +/* submit data to the internal buffer of the framing engine */ +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ + int lacing_vals=op->bytes/255+1,i; + + if(os->body_returned){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + os->body_fill-=os->body_returned; + if(os->body_fill) + memmove(os->body_data,os->body_data+os->body_returned, + os->body_fill*sizeof(char)); + os->body_returned=0; + } + + /* make sure we have the buffer storage */ + _os_body_expand(os,op->bytes); + _os_lacing_expand(os,lacing_vals); + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + memcpy(os->body_data+os->body_fill,op->packet,op->bytes); + os->body_fill+=op->bytes; + + /* Store lacing vals for this packet */ + for(i=0;i<lacing_vals-1;i++){ + os->lacing_vals[os->lacing_fill+i]=255; + os->granule_vals[os->lacing_fill+i]=os->granulepos; + } + os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255; + os->granulepos=os->granule_vals[os->lacing_fill+i]=op->frameno; + + /* flag the first segment as the beginning of the packet */ + os->lacing_vals[os->lacing_fill]|= 0x100; + + os->lacing_fill+=lacing_vals; + + /* for the sake of completeness */ + os->packetno++; + + if(op->e_o_s)os->e_o_s=1; + + return(0); +} + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not gurantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + ogg_stream_page will flush the last page in a stream even if it's + undersized; you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you need to flush an undersized + page in the middle of a stream for some reason. */ + +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ + int i; + int vals=0; + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); + int bytes=0; + long acc=0; + ogg_int64_t granule_pos=os->granule_vals[0]; + + if(maxvals==0)return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(os->b_o_s==0){ /* 'initial header page' case */ + granule_pos=0; + for(vals=0;vals<maxvals;vals++){ + if((os->lacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + }else{ + for(vals=0;vals<maxvals;vals++){ + if(acc>4096)break; + acc+=os->lacing_vals[vals]&0x0ff; + granule_pos=os->granule_vals[vals]; + } + } + + /* construct the header in temp storage */ + memcpy(os->header,"OggS",4); + + /* stream structure version */ + os->header[4]=0x00; + + /* continued packet flag? */ + os->header[5]=0x00; + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; + /* first page flag? */ + if(os->b_o_s==0)os->header[5]|=0x02; + /* last page flag? */ + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; + os->b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + os->header[i]=(granule_pos&0xff); + granule_pos>>=8; + } + + /* 32 bits of stream serial number */ + { + long serialno=os->serialno; + for(i=14;i<18;i++){ + os->header[i]=(serialno&0xff); + serialno>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(os->pageno==-1)os->pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + long pageno=os->pageno++; + for(i=18;i<22;i++){ + os->header[i]=(pageno&0xff); + pageno>>=8; + } + } + + /* zero for computation; filled in later */ + os->header[22]=0; + os->header[23]=0; + os->header[24]=0; + os->header[25]=0; + + /* segment table */ + os->header[26]=vals&0xff; + for(i=0;i<vals;i++) + bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff); + + /* set pointers in the ogg_page struct */ + og->header=os->header; + og->header_len=os->header_fill=vals+27; + og->body=os->body_data+os->body_returned; + og->body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + + os->lacing_fill-=vals; + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int)); + memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(ogg_int64_t)); + os->body_returned+=bytes; + + /* calculate the checksum */ + + _os_checksum(og); + + /* done */ + return(1); +} + + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */ + os->lacing_fill>=255 || /* 'segment table full' case */ + (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */ + + return(ogg_stream_flush(os,og)); + } + + /* not enough data to construct a page and not end of stream */ + return(0); +} + +int ogg_stream_eof(ogg_stream_state *os){ + return os->e_o_s; +} + +/* 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. See the 'frame-prog.txt' docs for details and + example code. */ + +/* initialize the struct to a known state */ +int ogg_sync_init(ogg_sync_state *oy){ + if(oy){ + memset(oy,0,sizeof(ogg_sync_state)); + _ogg_crc_init(); + } + return(0); +} + +/* clear non-flat storage within */ +int ogg_sync_clear(ogg_sync_state *oy){ + if(oy){ + if(oy->data)free(oy->data); + ogg_sync_init(oy); + } + return(0); +} + +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ + + /* first, clear out any space that has been previously returned */ + if(oy->returned){ + oy->fill-=oy->returned; + if(oy->fill>0) + memmove(oy->data,oy->data+oy->returned, + (oy->fill)*sizeof(char)); + 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 */ + + if(oy->data) + oy->data=realloc(oy->data,newsize); + else + oy->data=malloc(newsize); + oy->storage=newsize; + } + + /* expose a segment at least as large as requested at the fill mark */ + return((char *)oy->data+oy->fill); +} + +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ + if(oy->fill+bytes>oy->storage)return(-1); + oy->fill+=bytes; + 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 + +*/ + +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ + unsigned char *page=oy->data+oy->returned; + unsigned char *next; + long bytes=oy->fill-oy->returned; + + 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))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 */ + char chksum[4]; + ogg_page log; + + 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; + _os_checksum(&log); + + /* Compare */ + if(memcmp(chksum,page+22,4)){ + /* 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); + + /* Bad checksum. Lose sync */ + goto sync_fail; + } + } + + /* yes, have a whole page all ready to go */ + { + unsigned char *page=oy->data+oy->returned; + long bytes; + + if(og){ + og->header=page; + og->header_len=oy->headerbytes; + og->body=page+oy->headerbytes; + og->body_len=oy->bodybytes; + } + + oy->unsynced=0; + oy->returned+=(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) + next=oy->data+oy->fill; + + oy->returned=next-oy->data; + return(-(next-page)); +} + +/* sync the stream and get a page. Keep trying until we find a page. + Supress '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 */ + +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ + + /* 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 */ + + while(1){ + 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){ + oy->unsynced=1; + return(-1); + } + + /* loop. keep looking */ + + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ + unsigned char *header=og->header; + unsigned char *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); + ogg_int64_t granulepos=ogg_page_frameno(og); + int serialno=ogg_page_serialno(og); + int pageno=ogg_page_pageno(og); + int segments=header[26]; + + /* clean up 'returned data' */ + { + long lr=os->lacing_returned; + long br=os->body_returned; + + /* body data */ + if(br){ + os->body_fill-=br; + if(os->body_fill) + memmove(os->body_data,os->body_data+br,os->body_fill); + os->body_returned=0; + } + + if(lr){ + /* segment table */ + if(os->lacing_fill-lr){ + memmove(os->lacing_vals,os->lacing_vals+lr, + (os->lacing_fill-lr)*sizeof(int)); + memmove(os->granule_vals,os->granule_vals+lr, + (os->lacing_fill-lr)*sizeof(ogg_int64_t)); + } + 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); + + _os_lacing_expand(os,segments+1); + + /* are we in sequence? */ + if(pageno!=os->pageno){ + int 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'll need to skip + some segments */ + if(continued){ + bos=0; + for(;segptr<segments;segptr++){ + int val=header[27+segptr]; + body+=val; + bodysize-=val; + if(val<255){ + segptr++; + break; + } + } + } + } + + if(bodysize){ + _os_body_expand(os,bodysize); + memcpy(os->body_data+os->body_fill,body,bodysize); + os->body_fill+=bodysize; + } + + { + int 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){ + 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){ + os->e_o_s=1; + if(os->lacing_fill>0) + os->lacing_vals[os->lacing_fill-1]|=0x200; + } + + os->pageno=pageno+1; + + return(0); +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int ogg_sync_reset(ogg_sync_state *oy){ + oy->fill=0; + oy->returned=0; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return(0); +} + +int ogg_stream_reset(ogg_stream_state *os){ + os->body_fill=0; + os->body_returned=0; + + os->lacing_fill=0; + os->lacing_packet=0; + os->lacing_returned=0; + + os->header_fill=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->granulepos=0; + + return(0); +} + +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ + + /* 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) */ + + int ptr=os->lacing_returned; + + if(os->lacing_packet<=ptr)return(0); + + if(os->lacing_vals[ptr]&0x400){ + /* We lost sync here; let the app know */ + os->lacing_returned++; + + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + os->packetno++; + return(-1); + } + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=os->lacing_vals[ptr]&0xff; + int bytes=0; + + op->packet=os->body_data+os->body_returned; + op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ + op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ + bytes+=size; + + while(size==255){ + int val=os->lacing_vals[++ptr]; + size=val&0xff; + if(val&0x200)op->e_o_s=0x200; + bytes+=size; + } + + op->packetno=os->packetno; + op->frameno=os->granule_vals[ptr]; + op->bytes=bytes; + + os->body_returned+=bytes; + os->lacing_returned=ptr+1; + } + os->packetno++; + return(1); +} + +#ifdef _V_SELFTEST +#include <stdio.h> + +ogg_stream_state os_en, os_de; +ogg_sync_state oy; + +void checkpacket(ogg_packet *op,int len, int no, int pos){ + long j; + static int sequence=0; + static int lastno=0; + + if(op->bytes!=len){ + fprintf(stderr,"incorrect packet length!\n"); + exit(1); + } + if(op->frameno!=pos){ + fprintf(stderr,"incorrect packet position!\n"); + exit(1); + } + + /* packet number just follows sequence/gap; adjust the input number + for that */ + if(no==0){ + sequence=0; + }else{ + sequence++; + if(no>lastno+1) + sequence++; + } + lastno=no; + if(op->packetno!=sequence){ + fprintf(stderr,"incorrect packet sequence %ld != %d\n", + (long)(op->packetno),sequence); + exit(1); + } + + /* Test data */ + for(j=0;j<op->bytes;j++) + if(op->packet[j]!=((j+no)&0xff)){ + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", + j,op->packet[j],(j+no)&0xff); + exit(1); + } +} + +void check_page(unsigned char *data,const int *header,ogg_page *og){ + long j; + /* Test data */ + for(j=0;j<og->body_len;j++) + if(og->body[j]!=data[j]){ + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", + j,data[j],og->body[j]); + exit(1); + } + + /* Test header */ + for(j=0;j<og->header_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;j<header[26]+27;j++) + fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]); + fprintf(stderr,"\n"); + exit(1); + } + } + if(og->header_len!=header[26]+27){ + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", + og->header_len,header[26]+27); + exit(1); + } +} + +void print_header(ogg_page *og){ + int j; + fprintf(stderr,"\nHEADER:\n"); + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", + og->header[0],og->header[1],og->header[2],og->header[3], + (int)og->header[4],(int)og->header[5]); + + fprintf(stderr," granulepos: %d serialno: %d pageno: %d\n", + (og->header[9]<<24)|(og->header[8]<<16)| + (og->header[7]<<8)|og->header[6], + (og->header[17]<<24)|(og->header[16]<<16)| + (og->header[15]<<8)|og->header[14], + (og->header[21]<<24)|(og->header[20]<<16)| + (og->header[19]<<8)|og->header[18]); + + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", + (int)og->header[22],(int)og->header[23], + (int)og->header[24],(int)og->header[25], + (int)og->header[26]); + + for(j=27;j<og->header_len;j++) + fprintf(stderr,"%d ",(int)og->header[j]); + fprintf(stderr,")\n\n"); +} + +void copy_page(ogg_page *og){ + unsigned char *temp=malloc(og->header_len); + memcpy(temp,og->header,og->header_len); + og->header=temp; + + temp=malloc(og->body_len); + memcpy(temp,og->body,og->body_len); + og->body=temp; +} + +void error(void){ + fprintf(stderr,"error!\n"); + exit(1); +} + +/* 17 only */ +const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x15,0xed,0xec,0x91, + 1, + 17}; + +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ +const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x59,0x10,0x6c,0x2c, + 1, + 17}; +const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x89,0x33,0x85,0xce, + 13, + 254,255,0,255,1,255,245,255,255,0, + 255,255,90}; + +/* nil packets; beginning,middle,end */ +const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; +const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x5c,0x3f,0x66,0xcb, + 17, + 17,254,255,0,0,255,1,0,255,245,255,255,0, + 255,255,90,0}; + +/* large initial packet */ +const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x01,0x27,0x31,0xaa, + 18, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10}; + +const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x7f,0x4e,0x8a,0xd2, + 4, + 255,4,255,0}; + + +/* continuing packet test */ +const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x34,0x24,0xd5,0x29, + 17, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255}; + +const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xc8,0xc3,0xcb,0xed, + 5, + 10,255,4,255,0}; + + +/* page with the 255 segment limit */ +const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xed,0x2a,0x2e,0xa7, + 255, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10}; + +const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x6c,0x3b,0x82,0x3d, + 1, + 50}; + + +/* packet that overspans over an entire page */ +const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x3c,0xd9,0x4d,0x3f, + 17, + 100,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255}; + +const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xbd,0xd5,0xb5,0x8b, + 17, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255}; + +const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,3,0,0,0, + 0xef,0xdd,0x88,0xde, + 7, + 255,255,75,255,4,255,0}; + +/* packet that overspans over an entire page */ +const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x3c,0xd9,0x4d,0x3f, + 17, + 100,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255}; + +const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xd4,0xe0,0x60,0xe5, + 1,0}; + +void test_pack(const int *pl, const int **headers){ + unsigned char *data=malloc(1024*1024); /* for scripted test cases only */ + long inptr=0; + long outptr=0; + long deptr=0; + long depacket=0; + long granule_pos=7; + int i,j,packets,pageno=0,pageout=0; + int eosflag=0; + int bosflag=0; + + ogg_stream_reset(&os_en); + ogg_stream_reset(&os_de); + ogg_sync_reset(&oy); + + for(packets=0;;packets++)if(pl[packets]==-1)break; + + for(i=0;i<packets;i++){ + /* construct a test packet */ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.frameno=granule_pos; + + granule_pos+=1024; + + for(j=0;j<len;j++)data[inptr++]=i+j; + + /* submit the test packet */ + ogg_stream_packetin(&os_en,&op); + + /* retrieve any finished pages */ + { + ogg_page og; + + while(ogg_stream_pageout(&os_en,&og)){ + /* We have a page. Check it carefully */ + + fprintf(stderr,"%d, ",pageno); + + if(headers[pageno]==NULL){ + fprintf(stderr,"coded too many pages!\n"); + exit(1); + } + + check_page(data+outptr,headers[pageno],&og); + + outptr+=og.body_len; + pageno++; + + /* have a complete page; submit it to sync/decode */ + + { + ogg_page og_de; + ogg_packet op_de; + char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len); + memcpy(buf,og.header,og.header_len); + memcpy(buf+og.header_len,og.body,og.body_len); + ogg_sync_wrote(&oy,og.header_len+og.body_len); + + while(ogg_sync_pageout(&oy,&og_de)>0){ + /* got a page. Happy happy. Verify that it's good. */ + + check_page(data+deptr,headers[pageout],&og_de); + deptr+=og_de.body_len; + pageout++; + + /* submit it to deconstitution */ + ogg_stream_pagein(&os_de,&og_de); + + /* packets out? */ + while(ogg_stream_packetout(&os_de,&op_de)>0){ + + /* verify the packet! */ + /* check data */ + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", + depacket); + exit(1); + } + /* check bos flag */ + if(bosflag==0 && op_de.b_o_s==0){ + fprintf(stderr,"b_o_s flag not set on packet!\n"); + exit(1); + } + if(bosflag && op_de.b_o_s){ + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); + exit(1); + } + bosflag=1; + depacket+=op_de.bytes; + + /* check eos flag */ + if(eosflag){ + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); + exit(1); + } + + if(op_de.e_o_s)eosflag=1; + + /* check granulepos flag */ + if(op_de.frameno!=-1){ + fprintf(stderr," granule:%ld ",(long)op_de.frameno); + } + } + } + } + } + } + } + free(data); + if(headers[pageno]!=NULL){ + fprintf(stderr,"did not write last page!\n"); + exit(1); + } + if(headers[pageout]!=NULL){ + fprintf(stderr,"did not decode last page!\n"); + exit(1); + } + if(inptr!=outptr){ + fprintf(stderr,"encoded page data incomplete!\n"); + exit(1); + } + if(inptr!=deptr){ + fprintf(stderr,"decoded page data incomplete!\n"); + exit(1); + } + if(inptr!=depacket){ + fprintf(stderr,"decoded packet data incomplete!\n"); + exit(1); + } + if(!eosflag){ + fprintf(stderr,"Never got a packet with EOS set!\n"); + exit(1); + } + fprintf(stderr,"ok.\n"); +} + +int main(void){ + + ogg_stream_init(&os_en,0x04030201); + ogg_stream_init(&os_de,0x04030201); + ogg_sync_init(&oy); + + /* Exercise each code path in the framing code. Also verify that + the checksums are working. */ + + { + /* 17 only */ + const int packets[]={17, -1}; + const int *headret[]={head1_0,NULL}; + + fprintf(stderr,"testing single page encoding... "); + test_pack(packets,headret); + } + + { + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; + const int *headret[]={head1_1,head2_1,NULL}; + + fprintf(stderr,"testing basic page encoding... "); + test_pack(packets,headret); + } + + { + /* nil packets; beginning,middle,end */ + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; + const int *headret[]={head1_2,head2_2,NULL}; + + fprintf(stderr,"testing basic nil packets... "); + test_pack(packets,headret); + } + + { + /* large initial packet */ + const int packets[]={4345,259,255,-1}; + const int *headret[]={head1_3,head2_3,NULL}; + + fprintf(stderr,"testing initial-packet lacing > 4k... "); + test_pack(packets,headret); + } + + { + /* continuing packet test */ + const int packets[]={0,4345,259,255,-1}; + const int *headret[]={head1_4,head2_4,head3_4,NULL}; + + fprintf(stderr,"testing single packet page span... "); + test_pack(packets,headret); + } + + /* page with the 255 segment limit */ + { + + const int packets[]={0,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,50,-1}; + const int *headret[]={head1_5,head2_5,head3_5,NULL}; + + fprintf(stderr,"testing max packet segments... "); + test_pack(packets,headret); + } + + { + /* packet that overspans over an entire page */ + const int packets[]={0,100,9000,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing very large packets... "); + test_pack(packets,headret); + } + + { + /* term only page. why not? */ + const int packets[]={0,100,4080,-1}; + const int *headret[]={head1_7,head2_7,head3_7,NULL}; + + fprintf(stderr,"testing zero data page (1 nil packet)... "); + test_pack(packets,headret); + } + + + + { + /* build a bunch of pages for testing */ + unsigned char *data=malloc(1024*1024); + int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1}; + int inptr=0,i,j; + ogg_page og[5]; + + ogg_stream_reset(&os_en); + + for(i=0;pl[i]!=-1;i++){ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.frameno=(i+1)*1000; + + for(j=0;j<len;j++)data[inptr++]=i+j; + ogg_stream_packetin(&os_en,&op); + } + + free(data); + + /* retrieve finished pages */ + for(i=0;i<5;i++){ + if(ogg_stream_pageout(&os_en,&og[i])==0){ + fprintf(stderr,"Too few pages output building sync tests!\n"); + exit(1); + } + copy_page(&og[i]); + } + + /* Test lost pages on pagein/packetout: no rollback */ + { + ogg_page temp; + ogg_packet test; + + fprintf(stderr,"Testing loss of pages... "); + + ogg_sync_reset(&oy); + ogg_stream_reset(&os_de); + for(i=0;i<5;i++){ + memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, + og[i].header_len); + ogg_sync_wrote(&oy,og[i].header_len); + memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); + ogg_sync_wrote(&oy,og[i].body_len); + } + + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + /* skip */ + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + + /* do we get the expected results/packets? */ + + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,0,0,0); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,100,1,-1); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,4079,2,3000); + if(ogg_stream_packetout(&os_de,&test)!=-1){ + fprintf(stderr,"Error: loss of page did not return error\n"); + exit(1); + } + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,76,5,-1); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,34,6,-1); + fprintf(stderr,"ok.\n"); + } + + /* Test lost pages on pagein/packetout: rollback with continuation */ + { + ogg_page temp; + ogg_packet test; + + fprintf(stderr,"Testing loss of pages (rollback required)... "); + + ogg_sync_reset(&oy); + ogg_stream_reset(&os_de); + for(i=0;i<5;i++){ + memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, + og[i].header_len); + ogg_sync_wrote(&oy,og[i].header_len); + memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); + ogg_sync_wrote(&oy,og[i].body_len); + } + + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + /* skip */ + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + + /* do we get the expected results/packets? */ + + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,0,0,0); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,100,1,-1); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,4079,2,3000); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,2956,3,4000); + if(ogg_stream_packetout(&os_de,&test)!=-1){ + fprintf(stderr,"Error: loss of page did not return error\n"); + exit(1); + } + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,300,13,14000); + fprintf(stderr,"ok.\n"); + } + + /* the rest only test sync */ + { + ogg_page og_de; + /* Test fractional page inputs: incomplete capture */ + fprintf(stderr,"Testing sync on partial inputs... "); + ogg_sync_reset(&oy); + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 3); + ogg_sync_wrote(&oy,3); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete fixed header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, + 5); + ogg_sync_wrote(&oy,5); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete body */ + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, + og[1].header_len-28); + ogg_sync_wrote(&oy,og[1].header_len-28); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); + ogg_sync_wrote(&oy,1000); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, + og[1].body_len-1000); + ogg_sync_wrote(&oy,og[1].body_len-1000); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test fractional page inputs: page + incomplete capture */ + { + ogg_page og_de; + fprintf(stderr,"Testing sync on 1+partial inputs... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, + og[1].header_len-20); + ogg_sync_wrote(&oy,og[1].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing search for capture... "); + ogg_sync_reset(&oy); + + /* 'garbage' */ + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, + og[2].header_len-20); + ogg_sync_wrote(&oy,og[2].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len); + ogg_sync_wrote(&oy,og[2].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: page + garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing recapture... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len-5); + ogg_sync_wrote(&oy,og[2].body_len-5); + + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, + og[3].header_len); + ogg_sync_wrote(&oy,og[3].header_len); + + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, + og[3].body_len); + ogg_sync_wrote(&oy,og[3].body_len); + + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + } + + return(0); +} + +#endif + + + + |