[xiph-commits] r17259 - in branches/theorarm-merge-branch: . lib lib/arm rjw rjw/ogg rjw/tremolo

robin at svn.xiph.org robin at svn.xiph.org
Sun May 30 08:45:07 PDT 2010


Author: robin
Date: 2010-05-30 08:45:07 -0700 (Sun, 30 May 2010)
New Revision: 17259

Added:
   branches/theorarm-merge-branch/arm2gnu.pl
   branches/theorarm-merge-branch/lib/arm/ARMbitwise2.s
   branches/theorarm-merge-branch/rjw/
   branches/theorarm-merge-branch/rjw/Makefile.rjw
   branches/theorarm-merge-branch/rjw/ogg/
   branches/theorarm-merge-branch/rjw/ogg/ogg.h
   branches/theorarm-merge-branch/rjw/testtheora.c
   branches/theorarm-merge-branch/rjw/tremolo/
   branches/theorarm-merge-branch/rjw/tremolo/codec_internal.h
   branches/theorarm-merge-branch/rjw/tremolo/ivorbiscodec.h
Modified:
   branches/theorarm-merge-branch/lib/arm/ARMdecode.s
   branches/theorarm-merge-branch/lib/bitpack.h
   branches/theorarm-merge-branch/lib/decinfo.c
   branches/theorarm-merge-branch/lib/decode.c
   branches/theorarm-merge-branch/lib/huffdec.c
   branches/theorarm-merge-branch/lib/internal.c
Log:
Add ARM 2 gnu format perl script.
Add ARM bitreading functions.
Tweak routines to use Tremolo bitreading code properly.
Add test app.




Added: branches/theorarm-merge-branch/arm2gnu.pl
===================================================================
--- branches/theorarm-merge-branch/arm2gnu.pl	                        (rev 0)
+++ branches/theorarm-merge-branch/arm2gnu.pl	2010-05-30 15:45:07 UTC (rev 17259)
@@ -0,0 +1,265 @@
+#!/usr/bin/perl
+
+my $bigend;  # little/big endian
+
+eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
+    if $running_under_some_shell;
+
+while ($ARGV[0] =~ /^-/) {
+    $_ = shift;
+  last if /^--/;
+    if (/^-n/) {
+    $nflag++;
+    next;
+    }
+    die "I don't recognize this switch: $_\\n";
+}
+$printit++ unless $nflag;
+
+$\ = "\n";      # automatically add newline on print
+$n=0;
+
+$thumb = 0;     # ARM mode by default, not Thumb.
+
+LINE:
+while (<>) {
+
+    # For ADRLs we need to add a new line after the substituted one.
+    $addPadding = 0;
+
+    # First, we do not dare to touch *anything* inside double quotes, do we?
+    # Second, if you want a dollar character in the string,
+    # insert two of them -- that's how ARM C and assembler treat strings.
+    s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1:   .ascii \"/   && do { s/\$\$/\$/g; next };
+    s/\bDCB\b[ \t]*\"/.ascii \"/                          && do { s/\$\$/\$/g; next };
+    s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/                    && do { s/\$\$/\$/g; next };
+    # If substituted -- leave immediately !
+
+    s/@/,:/;
+    s/;/@/;
+    while ( /@.*'/ ) {
+      s/(@.*)'/$1/g;
+    }
+    s/\{FALSE\}/0/g;
+    s/\{TRUE\}/1/g;
+    s/\{(\w\w\w\w+)\}/$1/g;
+    s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/;
+    s/\bGET[ \t]*([^ \t\n]+)/.include \"$1\"/;
+    s/\bIMPORT\b/.extern/;
+    s/\bEXPORT\b/.global/;
+    s/^(\s+)\[/$1IF/;
+    s/^(\s+)\|/$1ELSE/;
+    s/^(\s+)\]/$1ENDIF/;
+    s/IF *:DEF:/ .ifdef/;
+    s/IF *:LNOT: *:DEF:/ .ifndef/;
+    s/ELSE/ .else/;
+    s/ENDIF/ .endif/;
+
+    if( /\bIF\b/ ) {
+      s/\bIF\b/ .if/;
+      s/=/==/;
+    }
+    if ( $n == 2) {
+        s/\$/\\/g;
+    }
+    if ($n == 1) {
+        s/\$//g;
+        s/label//g;
+    $n = 2;
+      }
+    if ( /MACRO/ ) {
+      s/MACRO *\n/.macro/;
+      $n=1;
+    }
+    if ( /\bMEND\b/ ) {
+      s/\bMEND\b/.endm/;
+      $n=0;
+    }
+
+    # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there.
+    #
+    if ( /\bAREA\b/ ) {
+        s/^(.+)CODE(.+)READONLY(.*)/    .text/;
+        s/^(.+)DATA(.+)READONLY(.*)/    .section .rdata\n    .align 2/;
+        s/^(.+)\|\|\.data\|\|(.+)/    .data\n    .align 2/;
+        s/^(.+)\|\|\.bss\|\|(.+)/    .bss/;
+    }
+
+    s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/;       # ||.constdata$3||
+    s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/;               # ||.bss$2||
+    s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/;             # ||.data$2||
+    s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/;
+    s/^(\s+)\%(\s)/    .space $1/;
+
+    s/\|(.+)\.(\d+)\|/\.$1_$2/;                     # |L80.123| -> .L80_123
+    s/\bCODE32\b/.code 32/ && do {$thumb = 0};
+    s/\bCODE16\b/.code 16/ && do {$thumb = 1};
+    if (/\bPROC\b/)
+    {
+        print "    .thumb_func" if ($thumb);
+        s/\bPROC\b/@ $&/;
+    }
+    s/\bENDP\b/@ $&/;
+    s/\bSUBT\b/@ $&/;
+    s/\bDATA\b/@ $&/;   # DATA directive is deprecated -- Asm guide, p.7-25
+    s/\bKEEP\b/@ $&/;
+    s/\bEXPORTAS\b/@ $&/;
+    s/\|\|(.)+\bEQU\b/@ $&/;
+    s/\|\|([\w\$]+)\|\|/$1/;
+    s/\bENTRY\b/@ $&/;
+    s/\bASSERT\b/@ $&/;
+    s/\bGBLL\b/@ $&/;
+    s/\bGBLA\b/@ $&/;
+    s/^\W+OPT\b/@ $&/;
+    s/:OR:/|/g;
+    s/:SHL:/<</g;
+    s/:SHR:/>>/g;
+    s/:AND:/&/g;
+    s/:LAND:/&&/g;
+    s/CPSR/cpsr/;
+    s/SPSR/spsr/;
+    s/ALIGN$/.balign 4/;
+    s/psr_cxsf/psr_all/;
+    s/LTORG/.ltorg/;
+    s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/;
+    s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/;
+    s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/;
+    s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/;
+
+    #  {PC} + 0xdeadfeed  -->  . + 0xdeadfeed
+    s/\{PC\} \+/ \. +/;
+
+    # Single hex constant on the line !
+    #
+    # >>> NOTE <<<
+    #   Double-precision floats in gcc are always mixed-endian, which means
+    #   bytes in two words are little-endian, but words are big-endian.
+    #   So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address
+    #   and 0xfeed0000 at high address.
+    #
+    s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/;
+    # Only decimal constants on the line, no hex !
+    s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/;
+
+    # Single hex constant on the line !
+#    s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/;
+    # Only decimal constants on the line, no hex !
+#    s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/;
+    s/\bDCFS[ \t]+0x/.word 0x/;
+    s/\bDCFS\b/.float/;
+
+    s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/;
+    s/\bDCD\b/.word/;
+    s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/;
+    s/\bDCW\b/.short/;
+    s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/;
+    s/\bDCB\b/.byte/;
+    s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/;
+    s/^[A-Za-z_\.]\w+/$&:/;
+    s/^(\d+)/$1:/;
+    s/\%(\d+)/$1b_or_f/;
+    s/\%[Bb](\d+)/$1b/;
+    s/\%[Ff](\d+)/$1f/;
+    s/\%[Ff][Tt](\d+)/$1f/;
+    s/&([\dA-Fa-f]+)/0x$1/;
+    if ( /\b2_[01]+\b/ ) {
+      s/\b2_([01]+)\b/conv$1&&&&/g;
+      while ( /[01][01][01][01]&&&&/ ) {
+        s/0000&&&&/&&&&0/g;
+        s/0001&&&&/&&&&1/g;
+        s/0010&&&&/&&&&2/g;
+        s/0011&&&&/&&&&3/g;
+        s/0100&&&&/&&&&4/g;
+        s/0101&&&&/&&&&5/g;
+        s/0110&&&&/&&&&6/g;
+        s/0111&&&&/&&&&7/g;
+        s/1000&&&&/&&&&8/g;
+        s/1001&&&&/&&&&9/g;
+        s/1010&&&&/&&&&A/g;
+        s/1011&&&&/&&&&B/g;
+        s/1100&&&&/&&&&C/g;
+        s/1101&&&&/&&&&D/g;
+        s/1110&&&&/&&&&E/g;
+        s/1111&&&&/&&&&F/g;
+      }
+      s/000&&&&/&&&&0/g;
+      s/001&&&&/&&&&1/g;
+      s/010&&&&/&&&&2/g;
+      s/011&&&&/&&&&3/g;
+      s/100&&&&/&&&&4/g;
+      s/101&&&&/&&&&5/g;
+      s/110&&&&/&&&&6/g;
+      s/111&&&&/&&&&7/g;
+      s/00&&&&/&&&&0/g;
+      s/01&&&&/&&&&1/g;
+      s/10&&&&/&&&&2/g;
+      s/11&&&&/&&&&3/g;
+      s/0&&&&/&&&&0/g;
+      s/1&&&&/&&&&1/g;
+      s/conv&&&&/0x/g;
+    }
+
+    if ( /commandline/)
+    {
+        if( /-bigend/)
+        {
+            $bigend=1;
+        }
+    }
+
+    if ( /\bDCDU\b/ )
+    {
+        my $cmd=$_;
+        my $value;
+        my $w1;
+        my $w2;
+        my $w3;
+        my $w4;
+
+        s/\s+DCDU\b/@ $&/;
+
+        $cmd =~ /\bDCDU\b\s+0x(\d+)/;
+        $value = $1;
+        $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
+        $w1 = $1;
+        $w2 = $2;
+        $w3 = $3;
+        $w4 = $4;
+
+        if( $bigend ne "")
+        {
+            # big endian
+
+            print "        .byte      0x".$w1;
+            print "        .byte      0x".$w2;
+            print "        .byte      0x".$w3;
+            print "        .byte      0x".$w4;
+        }
+        else
+        {
+            # little endian
+
+            print "        .byte      0x".$w4;
+            print "        .byte      0x".$w3;
+            print "        .byte      0x".$w2;
+            print "        .byte      0x".$w1;
+        }
+
+    }
+
+
+    if ( /\badrl\b/i )
+    {
+        s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i;
+        $addPadding = 1;
+    }
+    s/\bEND\b/@ END/;
+} continue {
+    printf ("%s", $_) if $printit;
+    if ($addPadding != 0)
+    {
+        printf ("   mov r0,r0\n");
+        $addPadding = 0;
+    }
+}
+


Property changes on: branches/theorarm-merge-branch/arm2gnu.pl
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/theorarm-merge-branch/lib/arm/ARMbitwise2.s
===================================================================
--- branches/theorarm-merge-branch/lib/arm/ARMbitwise2.s	                        (rev 0)
+++ branches/theorarm-merge-branch/lib/arm/ARMbitwise2.s	2010-05-30 15:45:07 UTC (rev 17259)
@@ -0,0 +1,421 @@
+; Theorarm library
+; Copyright (C) 2009 Robin Watts for Pinknoise Productions Ltd
+
+	AREA	|.text|, CODE, READONLY
+
+	EXPORT	theorapackB_lookARM
+	EXPORT	theorapackB_readARM
+	EXPORT	theorapackB_read1ARM
+
+theorapackB_lookARM
+	; r0 = oggpack_buffer *b
+	; r1 = int             bits
+	STMFD	r13!,{r9,r10,r11,r14}
+	LDMIA	r0,{r2,r3,r12}
+					; r2 = bitsLeftInSegment
+					; r3 = ptr
+					; r12= bitsLeftInWord
+	SUBS	r2, r2, r1		; bitsLeftinSegment -= bits
+	BLT	lookBE_slow		; Not enough bits in this segment for
+					; this request. Do it slowly.
+	LDR	r10,[r3]		; r10= ptr[0]
+	RSB	r14,r12,#32		; r14= 32-bitsLeftInWord
+
+	MVN	r9, #0xFF00
+	EOR	r11,r10,r10,ROR #16
+	AND	r11,r9, r11,LSR #8
+	EOR	r10,r11,r10,ROR #8	; r10= REV(ptr[0])
+
+	CMP	r12,r1			; if (bitsLeftInWord < bits)
+	LDRLT	r11,[r3, #4]!		; r11= ptr[1]
+	MOV	r10,r10,LSL r14		; r10= REV(ptr[0])<<(32-bitsLeftInWd)
+	RSB	r1, r1, #32
+
+	EOR	r0, r11,r11,ROR #16
+	AND	r0, r9, r0, LSR #8
+	EOR	r11,r0, r11,ROR #8	; r11 = REV(ptr[1])
+
+	ORRLT	r10,r10,r11,LSR r12	; r10= Next 32 bits.
+	MOV	r0, r10,LSR r1
+	LDMFD	r13!,{r9,r10,r11,PC}
+
+lookBE_slow
+	STMFD	r13!,{r5,r6}
+	ADDS	r10,r2, r1		; r10= bitsLeftInSegment + bits (i.e.
+					; the initial value of bitsLeftInSeg)
+	; r10 = bitsLeftInSegment (initial)
+	; r12 = bitsLeftInWord
+	RSB	r14,r12,#32		; r14= 32-bitsLeftInWord
+	MOV	r5, r10			; r5 = bitsLeftInSegment (initial)
+	BLT	lookBE_overrun
+	BEQ	lookBE_next_segment	; r10= r12 = 0, if we branch
+	CMP	r12,r10			; If bitsLeftInWord < bitsLeftInSeg
+					; there must be more in the next word
+	LDR	r10,[r3], #4		; r10= ptr[0]
+	LDRLT	r6, [r3]		; r6 = ptr[1]
+
+	MVN	r9, #0xFF00
+	EOR	r11,r10,r10,ROR #16
+	AND	r11,r9, r11,LSR #8
+	EOR	r10,r11,r10,ROR #8	; r10= REV(ptr[0])
+	MOV	r10,r10,LSL r14		; r10= first bitsLeftInWord bits
+
+	EOR	r11,r6, r6, ROR #16
+	AND	r11,r9, r11,LSR #8
+	EOR	r6, r11,r6, ROR #8	; r6 = REV(ptr[1])
+	ORRLT	r10,r10,r6, LSR r12	; r10= first bitsLeftInSeg bits+crap
+
+	RSB	r11,r5, #32
+	MOV	r10,r10,LSR r11		; r10= first r5 bits
+	; Load the next segments data
+lookBE_next_segment
+	; At this point, r10 contains the first r5 bits of the result
+	LDR	r11,[r0, #12]		; r11= head = b->head
+	; Stall
+	; Stall
+lookBE_next_segment_2
+	LDR	r11,[r11,#12]		; r11= head = head->next
+	; Stall
+	; Stall
+	CMP	r11,#0
+	BEQ	lookBE_out_of_data
+	LDMIA	r11,{r6,r12,r14}	; r6 = buffer
+					; r12= begin
+					; r14= length
+	LDR	r6, [r6]		; r6 = buffer->data
+	CMP	r14,#0
+	BEQ	lookBE_next_segment_2
+	ADD	r6, r6, r12		; r6 = buffer->data+begin
+lookBE_slow_loop
+	LDRB	r12,[r6], #1		; r12= *buffer
+	SUBS	r14,r14,#1		; r14= length
+	ADD	r5, r5, #8
+	ORR	r10,r12,r10,LSL #8	; r10= first r5+8 bits
+	BLE	lookBE_really_slow
+	SUBS	r9, r5, r1
+	BLT	lookBE_slow_loop
+	MOV	r0, r10,LSR r9
+	LDMFD	r13!,{r5,r6,r9,r10,r11,PC}
+
+lookBE_really_slow
+	SUBS	r9, r5, r1
+	BLT	lookBE_next_segment_2
+	MOV	r0, r10,LSR r9
+	LDMFD	r13!,{r5,r6,r9,r10,r11,PC}
+
+lookBE_out_of_data
+	; r10 holds the first r5 bits
+	SUB	r9, r1, r5
+	MOV	r0, r10,LSL r9			; return what we have
+	LDMFD	r13!,{r5,r6,r9,r10,r11,PC}
+
+lookBE_overrun
+	; We had overrun when we started, so we need to skip -r10 bits.
+	LDR	r11,[r0,#12]		; r11 = head = b->head
+	; stall
+	; stall
+lookBE_overrun_next_segment
+	LDR	r11,[r11,#12]		; r11 = head->next
+	; stall
+	; stall
+	CMP	r11,#0
+	BEQ	lookBE_out_of_data
+	LDMIA	r11,{r6,r7,r14}		; r6 = buffer
+					; r7 = begin
+					; r14= length
+	LDR	r6, [r6]		; r6 = buffer->data
+	; stall
+	; stall
+	ADD	r6, r6, r7		; r6 = buffer->data+begin
+	MOV	r14,r14,LSL #3		; r14= length in bits
+	ADDS	r14,r14,r10		; r14= length in bits-bits to skip
+	MOVLE	r10,r14
+	BLE	lookBE_overrun_next_segment
+	RSB	r10,r10,#0		; r10= bits to skip
+	ADD	r6, r1, r10,LSR #3	; r6 = pointer to data
+	MOV	r10,#0
+	B	lookBE_slow_loop
+
+theorapackB_readARM
+	; r0 = oggpack_buffer *b
+	; r1 = int             bits
+	STMFD	r13!,{r9,r10,r11,r14}
+	LDMIA	r0,{r2,r3,r12}
+					; r2 = bitsLeftInSegment
+					; r3 = ptr
+					; r12= bitsLeftInWord
+	SUBS	r2, r2, r1		; bitsLeftinSegment -= bits
+	BLT	readBE_slow		; Not enough bits in this segment for
+					; this request. Do it slowly.
+	LDR	r10,[r3], #4		; r10= ptr[0]
+
+	MVN	r9, #&FF00
+	RSB	r14,r12,#32		; r14= 32-bitsLeftInWord
+	EOR	r11,r10,r10,ROR #16
+	AND	r11,r9, r11,LSR #8
+	EOR	r10,r11,r10,ROR #8	; r10= REV(ptr[0])
+
+	MOV	r10,r10,LSL r14		; r10= REV(ptr[0])<<(32-bitsLeftInWd)
+	SUBS	r14,r12,r1		; r12= bitsLeftInWord -= bits
+	LDRLT	r11,[r3]		; r11= ptr[1]
+	STR	r2, [r0]
+	STRLE	r3, [r0, #4]
+	EOR	r3, r11,r11,ROR #16
+	AND	r3, r9, r3, LSR #8
+	EOR	r11,r3, r11,ROR #8	; r11= REV(ptr[1])
+	ORR	r10,r10,r11,LSR r12	; r10= Next 32 bits.
+	ADDLE	r14,r14,#32		; r12= bitsLeftInWord += 32
+	STR	r14,[r0, #8]
+	RSB	r1, r1, #32
+	MOV	r0, r10,LSR r1
+	LDMFD	r13!,{r9,r10,r11,PC}
+
+readBE_slow
+	STMFD	r13!,{r5,r6}
+	ADDS	r10,r2, r1		; r10= bitsLeftInSegment + bits (i.e.
+					; the initial value of bitsLeftInSeg)
+	; r10 = bitsLeftInSegment (initial)
+	; r12 = bitsLeftInWord
+	RSB	r14,r12,#32		; r14= 32-bitsLeftInWord
+	MOV	r5, r10			; r5 = bitsLeftInSegment (initial)
+	BLT	readBE_overrun
+	BEQ	readBE_next_segment	; r10= r12 = 0, if we branch
+	CMP	r12,r10			; If bitsLeftInWord < bitsLeftInSeg
+					; there must be more in the next word
+	LDR	r10,[r3],#4		; r10= ptr[0]
+	LDRLT	r6, [r3]		; r6 = ptr[1]
+
+	MVN	r9, #0xFF00
+	EOR	r11,r10,r10,ROR #16
+	AND	r11,r9, r11,LSR #8
+	EOR	r10,r11,r10,ROR #8	; r10= REV(ptr[0])
+	MOV	r10,r10,LSL r14		; r10= first bitsLeftInWord bits
+
+	EOR	r11,r6, r6, ROR #16
+	AND	r11,r9, r11,LSR #8
+	EOR	r6, r11,r6, ROR #8	; r6 = REV(ptr[1])
+	ORRLT	r10,r10,r6, LSR r12	; r10= first bitsLeftInSeg bits+crap
+
+	RSB	r11,r5, #32
+	MOV	r10,r10,LSR r11		; r10= first r5 bits
+	; Load the next segments data
+readBE_next_segment
+	; At this point, r10 contains the first r5 bits of the result
+	LDR	r11,[r0, #12]		; r11= head = b->head
+	; Stall
+readBE_next_segment_2
+	; r11 = head
+	LDR	r6, [r0, #20]		; r6 = count
+	LDR	r12,[r11,#8]		; r12= length
+	LDR	r11,[r11,#12]		; r11= head = head->next
+	; Stall
+	ADD	r6, r6, r12		; count += length
+	CMP	r11,#0
+	BEQ	readBE_out_of_data
+	STR	r11,[r0, #12]
+	STR	r6, [r0, #20]		; b->count = count
+	LDMIA	r11,{r6,r12,r14}	; r6 = buffer
+					; r12= begin
+					; r14= length
+	LDR	r6, [r6]		; r6 = buffer->data
+	CMP	r14,#0
+	BEQ	readBE_next_segment_2
+	ADD	r6, r6, r12		; r6 = buffer->data+begin
+readBE_slow_loop
+	LDRB	r12,[r6], #1		; r12= *buffer
+	SUBS	r14,r14,#1		; r14= length
+	ADD	r5, r5, #8
+	ORR	r10,r12,r10,LSL #8	; r10= first r5+8 bits
+	BLE	readBE_really_slow
+	SUBS	r9, r5, r1
+	BLT	readBE_slow_loop
+readBE_end
+	; Store back the new position
+	; r2 = -number of bits to go from this segment
+	; r6 = ptr
+	; r14= bytesLeftInSegment
+	; r11= New head value
+	LDMIA	r11,{r3,r6,r14}		; r3 = buffer
+					; r6 = begin
+					; r14= length
+	LDR	r3,[r3]			; r3 = buffer->data
+	ADD	r1,r2,r14,LSL #3	; r1 = bitsLeftInSegment
+	; stall
+	ADD	r6,r3,r6		; r6 = pointer
+	AND	r3,r6,#3		; r3 = bytes used in first word
+	RSB	r3,r2,r3,LSL #3		; r3 = bits used in first word
+	BIC	r2,r6,#3		; r2 = word ptr
+	RSBS	r3,r3,#32		; r3 = bitsLeftInWord
+	ADDLE	r3,r3,#32
+	ADDLE	r2,r2,#4
+	STMIA	r0,{r1,r2,r3}
+
+	MOV	r0, r10,LSR r9
+	LDMFD	r13!,{r5,r6,r9,r10,r11,PC}
+
+
+readBE_really_slow
+	SUBS	r9, r5, r1
+	BGE	readBE_end
+	LDR	r14,[r11,#8]		; r14= length of segment just done
+	; stall
+	; stall
+	ADD	r2, r2, r14,LSL #3	; r2 = -bits to use from next seg
+	B	readBE_next_segment_2
+
+readBE_out_of_data
+	; Store back the new position
+	; r2 = -number of bits to go from this segment
+	; r6 = ptr
+	; r14= bytesLeftInSegment
+	; RJW: This may be overkill - we leave the buffer empty, with -1
+	; bits left in it. We might get away with just storing the
+	; bitsLeftInSegment as -1.
+	LDR	r11,[r0, #12]		; r11=head
+	; Stall (2 on Xscale)
+	LDMIA	r11,{r3,r6,r14}		; r3 = buffer
+					; r6 = begin
+					; r14= length
+	LDR	r3, [r3]		; r3 = buffer->data
+	MVN	r1, #0			; r1 = -1 = bitsLeftInSegment
+	; Stall on Xscale
+	ADD	r6, r3, r6		; r6 = pointer
+	ADD	r6, r6, r14
+	AND	r3, r6, #3		; r3 = bytes used in first word
+	MOV	r3, r3, LSL #3		; r3 = bits used in first word
+	BIC	r2, r6, #3		; r2 = word ptr
+	RSBS	r3, r3, #32		; r3 = bitsLeftInWord
+	STMIA	r0,{r1,r2,r3}
+	MVN	r0, #0			; return -1
+	LDMFD	r13!,{r5,r6,r9,r10,r11,PC}
+
+readBE_overrun
+	; We had overrun when we started, so we need to skip -r10 bits.
+	LDR	r11,[r0,#12]		; r11 = head = b->head
+	; stall
+	; stall
+readBE_overrun_next_segment
+	LDR	r11,[r11,#12]		; r11 = head->next
+	; stall
+	; stall
+	CMP	r11,#0
+	BEQ	readBE_out_of_data
+	LDMIA	r11,{r6,r7,r14}		; r6 = buffer
+					; r7 = begin
+					; r14= length
+	LDR	r6, [r6]		; r6 = buffer->data
+	; stall
+	; stall
+	ADD	r6, r6, r7		; r6 = buffer->data+begin
+	MOV	r14,r14,LSL #3		; r14= length in bits
+	ADDS	r14,r14,r10		; r14= length in bits-bits to skip
+	MOVLE	r10,r14
+	BLE	readBE_overrun_next_segment
+	RSB	r10,r10,#0		; r10= bits to skip
+	ADD	r6, r10,r10,LSR #3	; r6 = pointer to data
+	MOV	r10,#0
+	B	readBE_slow_loop
+
+theorapackB_read1ARM
+	; r0 = oggpack_buffer *b
+	STMFD	r13!,{r10,r11,r14}
+	LDMIA	r0,{r2,r3,r12}
+					; r2 = bitsLeftInSegment
+					; r3 = ptr
+					; r12= bitsLeftInWord
+	SUBS	r2, r2, #1		; bitsLeftinSegment -= bits
+	BLT	read1BE_slow		; Not enough bits in this segment for
+					; this request. Do it slowly.
+	LDR	r10,[r3], #4		; r10= ptr[0]
+
+	MVN	r1, #&FF00
+	SUB	r14,r12,#1		; r14= 32-bitsLeftInWord
+	EOR	r11,r10,r10,ROR #16
+	AND	r11,r1, r11,LSR #8
+	EOR	r10,r11,r10,ROR #8	; r10= REV(ptr[0])
+
+	MOV	r10,r10,LSR r14		; r10= REV(ptr[0])>>(bitsLeftInWrd-1)
+	SUBS	r14,r12,#1		; r12= bitsLeftInWord -= bits
+	STR	r2, [r0]
+	STRLE	r3, [r0, #4]
+	ADDLE	r14,r14,#32		; r12= bitsLeftInWord += 32
+	STR	r14,[r0, #8]
+	AND	r0, r10,#1
+	LDMFD	r13!,{r10,r11,PC}
+
+read1BE_slow
+	; r12 = bitsLeftInWord
+	RSB	r14,r12,#32		; r14= 32-bitsLeftInWord
+	; Load the next segments data
+read1BE_next_segment
+	LDR	r11,[r0, #12]		; r11= head = b->head
+	; Stall
+read1BE_next_segment_2
+	; r11 = head
+	LDR	r10,[r0, #20]		; r10= count
+	LDR	r12,[r11,#8]		; r12= length
+	LDR	r11,[r11,#12]		; r11= head = head->next
+	; Stall
+	ADD	r10,r10,r12		; count += length
+	CMP	r11,#0
+	BEQ	read1BE_out_of_data
+	STR	r11,[r0, #12]
+	STR	r10,[r0, #20]		; b->count = count
+	LDMIA	r11,{r10,r12,r14}	; r10= buffer
+					; r12= begin
+					; r14= length
+	LDR	r10,[r10]		; r10= buffer->data
+	CMP	r14,#0
+	BEQ	read1BE_next_segment_2
+	LDRB	r10,[r10,r12]		; r10= *(buffer->data+begin)
+read1BE_end
+	; Store back the new position
+	; r2 = -number of bits to go from this segment
+	; r6 = ptr
+	; r14= bytesLeftInSegment
+	; r11= New head value
+	LDMIA	r11,{r3,r12,r14}	; r3 = buffer
+					; r12= begin
+					; r14= length
+	LDR	r3,[r3]			; r3 = buffer->data
+	ADD	r1,r2,r14,LSL #3	; r1 = bitsLeftInSegment
+	; stall
+	ADD	r12,r3,r12		; r12= pointer
+	AND	r3, r12,#3		; r3 = bytes used in first word
+	RSB	r3, r2, r3,LSL #3	; r3 = bits used in first word
+	BIC	r2, r12,#3		; r2 = word ptr
+	RSBS	r3, r3, #32		; r3 = bitsLeftInWord
+	ADDLE	r3, r3, #32
+	ADDLE	r2, r2, #4
+	STMIA	r0,{r1,r2,r3}
+
+	MOV	r0, r10,LSR #7
+	LDMFD	r13!,{r10,r11,PC}
+
+read1BE_out_of_data
+	; Store back the new position
+	; r2 = -number of bits to go from this segment
+	; r6 = ptr
+	; r14= bytesLeftInSegment
+	; RJW: This may be overkill - we leave the buffer empty, with -1
+	; bits left in it. We might get away with just storing the
+	; bitsLeftInSegment as -1.
+	LDR	r11,[r0, #12]		; r11=head
+	; Stall (2 on Xscale)
+	LDMIA	r11,{r3,r12,r14}	; r3 = buffer
+					; r12= begin
+					; r14= length
+	LDR	r3, [r3]		; r3 = buffer->data
+	MVN	r1, #0			; r1 = -1 = bitsLeftInSegment
+	; Stall on Xscale
+	ADD	r12,r3, r12		; r12= pointer
+	ADD	r12,r12,r14
+	AND	r3, r12,#3		; r3 = bytes used in first word
+	MOV	r3, r3, LSL #3		; r3 = bits used in first word
+	BIC	r2, r12,#3		; r2 = word ptr
+	RSBS	r3, r3, #32		; r3 = bitsLeftInWord
+	STMIA	r0,{r1,r2,r3}
+	MOV	r0, #0			; return 0
+	LDMFD	r13!,{r10,r11,PC}
+
+	END

Modified: branches/theorarm-merge-branch/lib/arm/ARMdecode.s
===================================================================
--- branches/theorarm-merge-branch/lib/arm/ARMdecode.s	2010-05-30 15:27:19 UTC (rev 17258)
+++ branches/theorarm-merge-branch/lib/arm/ARMdecode.s	2010-05-30 15:45:07 UTC (rev 17259)
@@ -12,15 +12,15 @@
 	EXPORT	oc_dec_coded_sb_flags_unpack
 	EXPORT	oc_dec_coded_flags_unpack
 
-	IMPORT	oc_pack_look
-	IMPORT	oc_pack_read1
-	IMPORT	oc_pack_adv
+	IMPORT	theorapackB_lookARM
+	IMPORT	theorapackB_read1ARM
+	IMPORT	oggpack_adv
 
 oc_sb_run_unpack
 	STMFD	r13!,{r0,r4,r14}
 
 	MOV	r1, #18
-	BL	oc_pack_look
+	BL	theorapackB_lookARM
 	MOV	r1, #1		; r1 = adv = 1
 	MVN	r2, #0		; r2 = sub = -1
 	TST	r0, #0x20000	; if (bits&0x20000)
@@ -44,7 +44,7 @@
 	RSB	r4, r1, #18
 	RSB	r4, r2, r0, LSR r4; (r4 = bits>>(18-adv))-sub
 	LDR	r0, [r13],#4
-	BL	oc_pack_adv
+	BL	oggpack_adv
 	MOV	r0, r4
 
 	LDMFD	r13!,{r4,PC}
@@ -53,7 +53,7 @@
 	STMFD	r13!,{r0,r4,r14}
 
 	MOV	r1, #9
-	BL	oc_pack_look
+	BL	theorapackB_lookARM
 	MOV	r1, #2		; r1 = adv = 2
 	MVN	r2, #0		; r2 = sub = -1
 	TST	r0, #0x100	; if (bits&0x100)
@@ -74,7 +74,7 @@
 	RSB	r4, r1, #9
 	RSB	r4, r2, r0, LSR r4; (r4 = bits>>(9-adv))-sub
 	LDR	r0, [r13],#4
-	BL	oc_pack_adv
+	BL	oggpack_adv
 	SUB	r0, r4, #1
 
 	LDMFD	r13!,{r4,PC}
@@ -94,7 +94,7 @@
 odpsfu_lp
 	CMP	r7, #0x1000		; if (full_run) (i.e. if >= 0)
 	MOVGE	r0, r11
-	BLGE	oc_pack_read1		; r0 = oc_pack_read1
+	BLGE	theorapackB_read1ARM	; r0 = oc_pack_read1
 	MOV	r6, r0			; r6 = flag
 	MOV	r0, r11
 	BL	oc_sb_run_unpack
@@ -139,7 +139,7 @@
 odcsfu_lp2
 	CMP	r7, #0x1000		; if (full_run) (i.e. if >= 0)
 	MOVGE	r0, r11
-	BLGE	oc_pack_read1		; r0 = oc_pack_read1
+	BLGE	theorapackB_read1ARM	; r0 = oc_pack_read1
 	MOV	r6, r0			; r6 = flag
 	MOV	r0, r11
 	BL	oc_sb_run_unpack
@@ -181,7 +181,7 @@
 	CMP	r7, #0				; if (npartial>0)
 	MOVLE	r0, #1
 	MOVGT	r0, r5
-	BLGT	oc_pack_read1		;    flag=!oc_pack_read1(opb)
+	BLGT	theorapackB_read1ARM		;    flag=!oc_pack_read1(opb)
 	EOR	r9, r0, #1			; else flag = 0
 	STMFD	r13!,{r4,r5}
 

Modified: branches/theorarm-merge-branch/lib/bitpack.h
===================================================================
--- branches/theorarm-merge-branch/lib/bitpack.h	2010-05-30 15:27:19 UTC (rev 17258)
+++ branches/theorarm-merge-branch/lib/bitpack.h	2010-05-30 15:45:07 UTC (rev 17259)
@@ -33,7 +33,32 @@
 # define OC_LOTS_OF_BITS (0x40000000)
 
 
+#ifdef OC_LIBOGG2
+#define oc_pack_buf oggpack_buffer
 
+#define oc_pack_adv(B,A) theorapackB_adv(B,A)
+#define oc_pack_look(B,A) theorapackB_look(B,A)
+#define oc_pack_readinit(B,R) theorapackB_readinit(B,R)
+#define oc_pack_read(B,L) theorapackB_read((B),(L))
+#define oc_pack_read1(B) theorapackB_read1((B))
+#define oc_pack_bytes_left(B) theorapackB_bytesleft(B)
+
+long theorapackB_lookARM(oggpack_buffer *_b, int bits);
+long theorapackB_readARM(oggpack_buffer *_b,int _bits);
+long theorapackB_read1ARM(oggpack_buffer *_b);
+
+#define theorapackB_look theorapackB_lookARM
+#define theorapackB_read theorapackB_readARM
+#define theorapackB_read1 theorapackB_read1ARM
+#define theorapackB_adv  oggpack_adv
+#define theorapackB_readinit oggpack_readinit
+#define theorapackB_bytes oggpack_bytes
+#define theorapackB_bits oggpack_bits
+#define theorapackB_bytesleft oggpack_bytesleft
+
+#define oggpack_bytesleft(B) (((B)->bitsLeftInSegment+7)>>3)
+
+#else
 struct oc_pack_buf{
   oc_pb_window         window;
   const unsigned char *ptr;
@@ -56,5 +81,6 @@
   Here we assume 0<=_bits&&_bits<=32.*/
 long oc_pack_look(oc_pack_buf *_b,int _bits);
 void oc_pack_adv(oc_pack_buf *_b,int _bits);
+#endif
 
 #endif

Modified: branches/theorarm-merge-branch/lib/decinfo.c
===================================================================
--- branches/theorarm-merge-branch/lib/decinfo.c	2010-05-30 15:27:19 UTC (rev 17258)
+++ branches/theorarm-merge-branch/lib/decinfo.c	2010-05-30 15:45:07 UTC (rev 17259)
@@ -234,7 +234,11 @@
   oc_pack_buf opb;
   if(_op==NULL)return TH_EBADHEADER;
   if(_info==NULL)return TH_EFAULT;
+#if OC_LIBOGG2
+  oggpack_readinit(&opb,_op->packet);
+#else
   oc_pack_readinit(&opb,_op->packet,_op->bytes);
+#endif
   return oc_dec_headerin(&opb,_info,_tc,_setup,_op);
 }
 

Modified: branches/theorarm-merge-branch/lib/decode.c
===================================================================
--- branches/theorarm-merge-branch/lib/decode.c	2010-05-30 15:27:19 UTC (rev 17258)
+++ branches/theorarm-merge-branch/lib/decode.c	2010-05-30 15:45:07 UTC (rev 17259)
@@ -2198,7 +2198,7 @@
     int                   notstart;
     int                   notdone;
 #ifdef OC_LIBOGG2
-    oc_pack_readinit(&_dec->opb,_op->packet);
+    oggpack_readinit(&_dec->opb,_op->packet);
 #else
     oc_pack_readinit(&_dec->opb,_op->packet,_op->bytes);
 #endif

Modified: branches/theorarm-merge-branch/lib/huffdec.c
===================================================================
--- branches/theorarm-merge-branch/lib/huffdec.c	2010-05-30 15:27:19 UTC (rev 17258)
+++ branches/theorarm-merge-branch/lib/huffdec.c	2010-05-30 15:45:07 UTC (rev 17259)
@@ -103,7 +103,7 @@
    they are only used here.
   Declaring local static versions so they can be inlined saves considerable
    function call overhead.*/
-
+#ifndef OC_LIBOGG2
 static oc_pb_window oc_pack_refill(oc_pack_buf *_b,int _bits){
   const unsigned char *ptr;
   const unsigned char *stop;
@@ -152,8 +152,8 @@
   _b->window<<=_bits;
   _b->bits-=_bits;
 }
+#endif
 
-
 /*The log_2 of the size of a lookup table is allowed to grow to relative to
    the number of unique nodes it contains.
   E.g., if OC_HUFF_SLUSH is 2, then at most 75% of the space in the tree is

Modified: branches/theorarm-merge-branch/lib/internal.c
===================================================================
--- branches/theorarm-merge-branch/lib/internal.c	2010-05-30 15:27:19 UTC (rev 17258)
+++ branches/theorarm-merge-branch/lib/internal.c	2010-05-30 15:45:07 UTC (rev 17259)
@@ -253,7 +253,7 @@
   Note that this correctly interprets a 0-byte packet as a video data packet.
   Return: 1 for a header packet, 0 for a data packet.*/
 int th_packet_isheader(ogg_packet *_op){
-#ifdef WORK_WITH_TREMOLO
+#ifdef OC_LIBOGG2
     return _op->bytes>0?_op->packet->buffer->data[0]>>7:0;
 #else
     return _op->bytes>0?_op->packet[0]>>7:0;
@@ -265,7 +265,7 @@
   Return: 1 for a key frame, 0 for a delta frame, and -1 for a header
            packet.*/
 int th_packet_iskeyframe(ogg_packet *_op){
-#ifdef WORK_WITH_TREMOLO
+#ifdef OC_LIBOGG2
   return _op->bytes<=0?0:_op->packet->buffer->data[0]&0x80?-1:!(_op->packet->buffer->data[0]&0x40);
 #else
   return _op->bytes<=0?0:_op->packet[0]&0x80?-1:!(_op->packet[0]&0x40);

Added: branches/theorarm-merge-branch/rjw/Makefile.rjw
===================================================================
--- branches/theorarm-merge-branch/rjw/Makefile.rjw	                        (rev 0)
+++ branches/theorarm-merge-branch/rjw/Makefile.rjw	2010-05-30 15:45:07 UTC (rev 17259)
@@ -0,0 +1,74 @@
+# This is a temporary makefile used for testing this branch until the merge
+# completes. It doesn't use the config system etc, so should be considered
+# a poor relation to doing it properly.
+#
+# Use:
+#
+#   make -f Makefile.rjw
+#
+# This relies on ogg/ogg.h, tremolo/codec_internal.h and tremolo/ivorbiscodec.h
+# being available on the VPATH. Personally I copy them into the rjw directory.
+
+VPATH = examples:lib:lib/dec:lib/yuv2rgb:tests:rjw:lib/arm
+
+CC    = arm-none-linux-gnueabi-gcc
+AS    = arm-none-linux-gnueabi-as
+STRIP = arm-none-linux-gnueabi-strip
+
+CFLAGS  = -Iinclude -Iinclude/ogg -I../Tremolo -Irjw
+CFLAGS += -Ilib -Ilib/dec -Ilib/tremolo -Ilib/yuv2rgb 
+CFLAGS += -O3 -mfpu=neon -mcpu=cortex-a8
+CFLAGS += -DOC_LIBOGG2 -D_ARM_ASSEM_
+
+TREMOLOLIB = ../Tremolo/libTremoloL.lib
+
+all: testtheora
+
+clean:
+	rm build/*
+
+# Compilation rule
+build/%.o: %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+# Assembly header rule
+build/ARMoptions.s: lib/arm/ARMoptions.s
+	./arm2gnu.pl < $< > $@
+
+# Structure offset header rule
+build/ARMoffsets.s: lib/arm/ARMoffsets.s
+	./arm2gnu.pl < $< > $@
+
+# Assembly rule
+build/%.o: lib/arm/%.s build/ARMoffsets.s build/ARMoptions.s
+	./arm2gnu.pl < $< > build/$*.S
+	$(CC) -Ibuild $(CFLAGS) -c build/$*.S -o $@
+	$(STRIP) -x $@
+
+theoraobjs = \
+	build/apiwrapper.o \
+	build/ARMbitwise2.o \
+	build/decapiwrapper.o \
+	build/decinfo.o \
+	build/decode.o \
+	build/ARMdecode.o \
+	build/dequant.o \
+	build/ARMfrag.o \
+	build/fragment.o \
+	build/huffdec.o \
+	build/idct.o \
+	build/ARMidct.o \
+	build/info.o \
+	build/internal.o \
+	build/ARMpp.o \
+	build/quant.o \
+	build/state.o \
+	build/ARMstate.o \
+	build/testtheora.o
+
+# Unused files
+#	build/floor1ARM.o \
+#	build/mdctARM.o \
+
+testtheora: $(theoraobjs) $(TREMOLOLIB)
+	$(CC) $^ -o $@ -Wl,-d,-Map,testtheora.map

Added: branches/theorarm-merge-branch/rjw/ogg/ogg.h
===================================================================
--- branches/theorarm-merge-branch/rjw/ogg/ogg.h	                        (rev 0)
+++ branches/theorarm-merge-branch/rjw/ogg/ogg.h	2010-05-30 15:45:07 UTC (rev 17259)
@@ -0,0 +1,211 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: subsumed libogg includes
+
+ ********************************************************************/
+#ifndef _OGG_H
+#define _OGG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "os_types.h"
+
+typedef struct ogg_buffer_state{
+  struct ogg_buffer    *unused_buffers;
+  struct ogg_reference *unused_references;
+  int                   outstanding;
+  int                   shutdown;
+} ogg_buffer_state;
+
+typedef struct ogg_buffer {
+  unsigned char      *data;
+  long                size;
+  int                 refcount;
+  
+  union {
+    ogg_buffer_state  *owner;
+    struct ogg_buffer *next;
+  } ptr;
+} ogg_buffer;
+
+typedef struct ogg_reference {
+  ogg_buffer    *buffer;
+  long           begin;
+  long           length;
+
+  struct ogg_reference *next;
+} ogg_reference;
+
+typedef struct oggpack_buffer {
+#ifdef _ARM_ASSEM_
+  int            bitsLeftInSegment;
+  ogg_uint32_t  *ptr;
+  long           bitsLeftInWord;
+#else
+  int            headbit;
+  unsigned char *headptr;
+  long           headend;
+#endif
+  /* memory management */
+  ogg_reference *head;
+  ogg_reference *tail;
+
+  /* render the byte/bit counter API constant time */
+  long              count; /* doesn't count the tail */
+} oggpack_buffer;
+
+typedef struct oggbyte_buffer {
+  ogg_reference *baseref;
+
+  ogg_reference *ref;
+  unsigned char *ptr;
+  long           pos;
+  long           end;
+} oggbyte_buffer;
+
+typedef struct ogg_sync_state {
+  /* decode memory management pool */
+  ogg_buffer_state *bufferpool;
+
+  /* stream buffers */
+  ogg_reference    *fifo_head;
+  ogg_reference    *fifo_tail;
+  long              fifo_fill;
+
+  /* stream sync management */
+  int               unsynced;
+  int               headerbytes;
+  int               bodybytes;
+
+} ogg_sync_state;
+
+typedef struct ogg_stream_state {
+  ogg_reference *header_head;
+  ogg_reference *header_tail;
+  ogg_reference *body_head;
+  ogg_reference *body_tail;
+
+  int            e_o_s;    /* set when we have buffered the last
+                              packet in the logical bitstream */
+  int            b_o_s;    /* set after we've written the initial page
+                              of a logical bitstream */
+  long           serialno;
+  long           pageno;
+  ogg_int64_t    packetno; /* sequence number for decode; the framing
+                              knows where there's a hole in the data,
+                              but we need coupling so that the codec
+                              (which is in a seperate abstraction
+                              layer) also knows about the gap */
+  ogg_int64_t    granulepos;
+
+  int            lacing_fill;
+  ogg_uint32_t   body_fill;
+
+  /* decode-side state data */
+  int            holeflag;
+  int            spanflag;
+  int            clearflag;
+  int            laceptr;
+  ogg_uint32_t   body_fill_next;
+  
+} ogg_stream_state;
+
+typedef struct {
+  ogg_reference *packet;
+  long           bytes;
+  long           b_o_s;
+  long           e_o_s;
+  ogg_int64_t    granulepos;
+  ogg_int64_t    packetno;     /* sequence number for decode; the framing
+                                  knows where there's a hole in the data,
+                                  but we need coupling so that the codec
+                                  (which is in a seperate abstraction
+                                  layer) also knows about the gap */
+} ogg_packet;
+
+typedef struct {
+  ogg_reference *header;
+  int            header_len;
+  ogg_reference *body;
+  long           body_len;
+} ogg_page;
+
+/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
+
+extern void  oggpack_readinit(oggpack_buffer *b,ogg_reference *r);
+extern long  oggpack_look(oggpack_buffer *b,int bits);
+extern void  oggpack_adv(oggpack_buffer *b,int bits);
+extern long  oggpack_read(oggpack_buffer *b,int bits);
+extern long  oggpack_bytes(oggpack_buffer *b);
+extern long  oggpack_bits(oggpack_buffer *b);
+extern int   oggpack_eop(oggpack_buffer *b);
+
+/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
+
+extern ogg_sync_state *ogg_sync_create(void);
+extern int      ogg_sync_destroy(ogg_sync_state *oy);
+extern int      ogg_sync_reset(ogg_sync_state *oy);
+
+extern unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long size);
+extern int      ogg_sync_wrote(ogg_sync_state *oy, long bytes);
+extern long     ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
+extern int      ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
+extern int      ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
+extern int      ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
+extern int      ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
+
+/* Ogg BITSTREAM PRIMITIVES: general ***************************/
+
+extern ogg_stream_state *ogg_stream_create(int serialno);
+extern int      ogg_stream_destroy(ogg_stream_state *os);
+extern int      ogg_stream_reset(ogg_stream_state *os);
+extern int      ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
+extern int      ogg_stream_eos(ogg_stream_state *os);
+
+extern int      ogg_page_checksum_set(ogg_page *og);
+
+extern int      ogg_page_version(ogg_page *og);
+extern int      ogg_page_continued(ogg_page *og);
+extern int      ogg_page_bos(ogg_page *og);
+extern int      ogg_page_eos(ogg_page *og);
+extern ogg_int64_t  ogg_page_granulepos(ogg_page *og);
+extern ogg_uint32_t ogg_page_serialno(ogg_page *og);
+extern ogg_uint32_t ogg_page_pageno(ogg_page *og);
+extern int      ogg_page_packets(ogg_page *og);
+extern int      ogg_page_getbuffer(ogg_page *og, unsigned char **buffer);
+
+extern int      ogg_packet_release(ogg_packet *op);
+extern int      ogg_page_release(ogg_page *og);
+
+extern void     ogg_page_dup(ogg_page *d, ogg_page *s);
+
+/* Ogg BITSTREAM PRIMITIVES: return codes ***************************/
+
+#define  OGG_SUCCESS   0
+
+#define  OGG_HOLE     -10
+#define  OGG_SPAN     -11
+#define  OGG_EVERSION -12
+#define  OGG_ESERIAL  -13
+#define  OGG_EINVAL   -14
+#define  OGG_EEOS     -15
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _OGG_H */

Added: branches/theorarm-merge-branch/rjw/testtheora.c
===================================================================
--- branches/theorarm-merge-branch/rjw/testtheora.c	                        (rev 0)
+++ branches/theorarm-merge-branch/rjw/testtheora.c	2010-05-30 15:45:07 UTC (rev 17259)
@@ -0,0 +1,1871 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2007                *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ *                                                                  *
+ ********************************************************************
+
+  function: example dumpvid application; dumps  Theora streams
+  last mod: $Id: dump_video.c 15400 2008-10-15 12:10:58Z tterribe $
+
+ ********************************************************************/
+
+/* By Robin Watts (robin at wss.co.uk). Actually, this was originally
+ * dump_video.c by Mauricio Piacentini (mauricio at xiph.org), but I've
+ * hacked it around horribly, so it's probably not nice to blame him
+ * for it in any way! */
+
+/* Do *not* use this file as an example of how to correctly sync audio
+ * and video. It's designed to be just good enough so I know that audio
+ * and video decode are actually working. */
+
+/* Enable/disable the following to determine if we post process */
+//#define POST_PROCESS
+
+/* Enable the following if your source file is coming from a slow device
+ * to get more realistic timings */
+#define PRE_READ_FILE
+
+/* Enable the following to set the screen depth */
+#define SCREEN_DEPTH 16
+//#define OVERLAY
+
+/* Ideally we should get details of fb and audio ioctls from the correct
+ * linux headers. If, like me, you're crosscompiling on a system that
+ * doesn't have these headers available, you'll need to use a hideous
+ * embarrassing hack. */
+#define MISSING_LINUX_HEADERS
+
+#define STATIC
+
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#if !defined(_LARGEFILE_SOURCE)
+#define _LARGEFILE_SOURCE
+#endif
+#if !defined(_LARGEFILE64_SOURCE)
+#define _LARGEFILE64_SOURCE
+#endif
+#if !defined(_FILE_OFFSET_BITS)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#include <stdio.h>
+//#if !defined(_WIN32)
+//#include <getopt.h>
+//#include <unistd.h>
+//#else
+//#include "getopt.h"
+//#endif
+#include <stdlib.h>
+#include <string.h>
+//#include <sys/timeb.h>
+//#include <sys/types.h>
+//#include <sys/stat.h>
+/*Yes, yes, we're going to hell.*/
+//#if defined(_WIN32)
+//#include <io.h>
+//#endif
+//#include <fcntl.h>
+#include <math.h>
+//#include <signal.h>
+#include <stdarg.h>
+#include "theora/theora.h"
+#include "tremolo/ivorbiscodec.h"
+#include "tremolo/codec_internal.h"
+#ifdef HAVE_YUVLIB
+#include "yuv2rgb.h"
+#endif
+
+#ifdef _WIN32_WCE
+#include <windows.h>
+
+#define clock GetTickCount
+#define CLOCKS_PER_SEC 1000
+typedef long clock_t;
+
+#else
+#include <time.h>
+#endif
+
+char text[4096];
+
+void Output(const char *fmt, ...)
+{
+  va_list  ap;
+#ifdef _WIN32_WCE
+  char    *t = text;
+  WCHAR    uni[4096];
+  WCHAR   *u = uni;
+
+  va_start(ap,fmt);
+  vsprintf(text, fmt, ap);
+  va_end(ap);
+
+  while (*t != 0)
+  {
+      *u++ = (WCHAR)(*t++);
+  }
+  *u++ = 0;
+  OutputDebugString(uni);
+#else
+  va_start(ap,fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+#endif
+}
+
+#ifdef _WIN32_WCE
+typedef struct _RawFrameBufferInfo
+{
+   WORD wFormat;
+   WORD wBPP;
+   VOID *pFramePointer;
+   int  cxStride;
+   int  cyStride;
+   int  cxPixels;
+   int  cyPixels;
+}
+RawFrameBufferInfo;
+
+#define GETRAWFRAMEBUFFER   0x00020001
+#define FORMAT_565 1
+#define FORMAT_555 2
+#define FORMAT_OTHER 3
+
+struct GXDisplayProperties
+{
+    DWORD cxWidth;
+    DWORD cyHeight; /* notice lack of 'th' in the word height */
+    long cbxPitch;  /* number of bytes to move right one x pixel - can be negative */
+    long cbyPitch;  /* number of bytes to move down one y pixel - can be negative */
+    long cBPP;      /* # of bits in each pixel */
+    DWORD ffFormat; /* format flags */
+};
+typedef struct GXDisplayProperties(*getGXProperties)(void);
+
+void *find_screen_mem(int *width,
+                      int *height)
+{
+    HDC                hdc;
+    int                result;
+    RawFrameBufferInfo frameBufferInfo;
+
+    /* First, we'll try using GETRAWFRAMEBUFFER. This should work on all
+     * modern WinCEs, but some 2003's get it wrong. */
+    hdc = GetDC(NULL);
+    result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL,
+                       sizeof(RawFrameBufferInfo), (char *)&frameBufferInfo);
+
+    if (result > 0)
+    {
+        *width  = frameBufferInfo.cxPixels;
+        *height = frameBufferInfo.cyPixels;
+        return frameBufferInfo.pFramePointer;
+    }
+
+    return NULL;
+}
+#endif
+
+static int screen_width  = 0;
+static int screen_height = 0;
+static int screen_depth  = 16;
+static int dither = 0;
+
+#ifdef MISSING_LINUX_HEADERS
+/* Massively gross hack alert! */
+
+/* Stuff from ioctl.h/mmap.h */
+#define PROT_READ  1
+#define PROT_WRITE 2
+#define MAP_SHARED 1
+#define O_WRONLY 1
+#define O_RDWR   2
+extern void*mmap(void*addr,size_t len, int prot, int flags, int fd, int off);
+extern int ioctl(int fd, unsigned long request, ...);
+
+typedef unsigned int __u32;
+typedef unsigned short __u16;
+
+/* Stuff from fb.h */
+#define FBIOGET_VSCREENINFO 0x4600
+#define FBIOPUT_VSCREENINFO 0x4601
+#define FBIOGET_FSCREENINFO 0x4602
+
+struct fb_fix_screeninfo {
+    char id[16];
+    unsigned long smem_start;
+    __u32 smem_len;
+    __u32 type;
+    __u32 type_aux;
+    __u32 visual;
+    __u16 xpanstep;
+    __u16 ypanstep;
+    __u16 ywrapstep;
+    __u32 line_length;
+    unsigned long mmio_start;
+    __u32 mmio_len;
+    __u32 mmio_accel;
+    __u16 reserved[3];
+};
+
+struct fb_bitfield {
+    __u32 offset;
+    __u32 length;
+    __u32 msb_right;
+};
+
+struct fb_var_screeninfo {
+    __u32 xres;
+    __u32 yres;
+    __u32 xres_virtual;
+    __u32 yres_virtual;
+    __u32 xoffset;
+    __u32 yoffset;
+    __u32 bits_per_pixel;
+    __u32 grayscale;
+
+    struct fb_bitfield red;
+    struct fb_bitfield green;
+    struct fb_bitfield blue;
+    struct fb_bitfield transp;
+
+    __u32 nonstd;
+    __u32 activate;
+    __u32 height;
+    __u32 width;
+    __u32 accel_flags;
+
+    __u32 pixclock;
+    __u32 left_margin;
+    __u32 right_margin;
+    __u32 upper_margin;
+    __u32 lower_margin;
+    __u32 hsync_len;
+    __u32 vsync_len;
+    __u32 sync;
+    __u32 vmode;
+    __u32 rotate;
+    __u32 reserved[5];
+};
+
+/* Stuff lifted from soundcard.h */
+#define _IOC_NRBITS      8
+#define _IOC_TYPEBITS    8
+#define _IOC_SIZEBITS    14
+#define _IOC_DIRBITS     2
+#define _IOC_NRSHIFT     0
+#define _IOC_TYPESHIFT   (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT   (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT    (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+#define _IOC(dir,type,nr,size)   \
+   (((dir)  << _IOC_DIRSHIFT)  | \
+    ((type) << _IOC_TYPESHIFT) | \
+    ((nr)   << _IOC_NRSHIFT)   | \
+    ((size) << _IOC_SIZESHIFT))
+extern unsigned int __invalid_size_argument_for_IOC;
+#define _IOC_NONE  0U
+#define _IOC_WRITE 1U
+#define _IOC_READ  2U
+#define _IOC_TYPECHECK(t) \
+        ((sizeof(t) == sizeof(t[1]) && \
+          sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
+          sizeof(t) : __invalid_size_argument_for_IOC)
+#define _IOWR(type, nr, size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOR(type, nr, size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOW(type, nr, size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _SIOWR _IOWR
+#define _SIOR _IOR
+#define _SIOW _IOW
+#define SNDCTL_DSP_SPEED      _SIOWR('P', 2, int)
+#define SNDCTL_DSP_CHANNELS   _SIOWR('P', 6, int)
+#define SNDCTL_DSP_SETFMT     _SIOWR('P', 5, int)
+#define SNDCTL_DSP_GETOSPACE  _SIOR('P', 12, audio_buf_info)
+#define SNDCTL_DSP_SETTRIGGER _SIOW('P', 16, int)
+#define SNDCTL_DSP_GETTRIGGER _SIOR('P', 16, int)
+#define AFMT_S16_LE          (0x00000010)
+#define PCM_ENABLE_OUTPUT    2
+
+typedef struct audio_buf_info {
+  int fragments;
+  int fragstotal;
+  int fragsize;
+  int bytes;
+} audio_buf_info;
+
+
+#else
+#include <linux/fb.h>
+#include <sys/mman.h>
+#endif
+
+void *open_screen(int width, int height)
+{
+  char *buff = NULL;
+
+#ifdef _WIN32_WCE
+  buff = find_screen_mem(&screen_width, &screen_height);
+
+  Output("Screen %d x %d @ %x\n", screen_width, screen_height, buff);
+#else
+#ifdef OVERLAY
+  struct fb_var_screeninfo fbvar;
+  int fbdev = open("/dev/fb1", O_RDWR);
+
+  if (fbdev == 0)
+  {
+      Output("Failed to open /dev/fb1\n");
+      exit(1);
+  }
+
+  {
+      int i;
+
+      if (ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar) != 0)
+          Output("Failed to get info on screen\n");
+
+      for(i=0; i<20; i++)
+        Output("%d\n", ((int*)&fbvar)[i]);
+
+      screen_width =fbvar.xres;
+      screen_height=fbvar.yres;
+      screen_depth =fbvar.bits_per_pixel;
+      screen_depth=2;
+#else
+  int fbdev = open("/dev/fb0", O_RDWR);
+
+  if (fbdev == 0)
+  {
+      Output("Failed to open /dev/fb0\n");
+      exit(1);
+  }
+
+  {
+      int i;
+#define FB_SCREEN_WIDTH  720
+#define FB_SCREEN_HEIGHT 574
+#if SCREEN_DEPTH == 32
+      struct fb_var_screeninfo fbvar =
+      {
+          FB_SCREEN_WIDTH, FB_SCREEN_HEIGHT,
+          FB_SCREEN_WIDTH, FB_SCREEN_HEIGHT,
+          0, 0, 32, 0,
+          {16,8,0},{8,8,0},{0,8,0},{0,0,0},
+          0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+      };
+#elif SCREEN_DEPTH == 24
+      struct fb_var_screeninfo fbvar =
+      {
+          FB_SCREEN_WIDTH, FB_SCREEN_HEIGHT,
+          FB_SCREEN_WIDTH, FB_SCREEN_HEIGHT,
+          0, 0, 24, 0,
+          {16,8,0},{8,8,0},{0,8,0},{0,0,0},
+          0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+      };
+#else
+      struct fb_var_screeninfo fbvar =
+      {
+          FB_SCREEN_WIDTH, FB_SCREEN_HEIGHT,
+          FB_SCREEN_WIDTH, FB_SCREEN_HEIGHT,
+          0, 0, 16, 0,
+          {11,5,0},{5,6,0},{0,5,0},{0,0,0},
+          0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+      };
+#endif
+      if (ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar) != 0)
+          Output("Failed to set screen mode\n");
+      if (ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar) != 0)
+          Output("Failed to get info on screen\n");
+
+      screen_width =fbvar.xres;
+      screen_height=fbvar.yres;
+      screen_depth =fbvar.bits_per_pixel;
+#endif
+  }
+
+  buff = (char    *)mmap(0,
+                         screen_width*screen_height*(screen_depth>>3),
+                         PROT_WRITE, MAP_SHARED, fbdev, 0);
+#endif
+
+  if (buff != NULL)
+  {
+    memset(buff, 0, screen_width*screen_height*(screen_depth>>3));
+
+    /* Centre the output */
+    if (width < screen_width)
+    {
+      buff += ((screen_width-width)>>1)*(screen_depth>>3);
+    }
+    if (height < screen_height)
+    {
+      buff += ((screen_height-height)>>1)*screen_width*(screen_depth>>3);
+    }
+
+    return buff;
+  }
+
+  return NULL;
+}
+
+#ifdef PRE_READ_FILE
+static char *pre_read_buffer = NULL;
+static char *pre_read_ptr    = NULL;
+static int   pre_read_left   = 0;
+
+STATIC int pre_read_file(FILE *infile)
+{
+    long len;
+
+    Output("Pre-reading file...");
+
+    fseek(infile, 0, SEEK_END);
+    len = ftell(infile);
+    Output(" %d bytes\n", len);
+    fseek(infile, 0, SEEK_SET);
+    pre_read_buffer = malloc(len);
+    if (pre_read_buffer == NULL)
+        return 1;
+    len=fread(pre_read_buffer,1,len,infile);
+    fclose(infile);
+    Output("Read %d bytes\n", len);
+    pre_read_ptr  = pre_read_buffer;
+    pre_read_left = len;
+    return 0;
+}
+
+STATIC void pre_read_dump(void)
+{
+    free(pre_read_buffer);
+    pre_read_buffer = NULL;
+    pre_read_ptr    = NULL;
+    pre_read_left   = 0;
+}
+
+#define FEOF(infile) ((infile == NULL) ? (pre_read_left==0) : (feof(infile)))
+
+#else
+#define FEOF(infile) feof(infile)
+#endif
+
+/* Helper; just grab some more compressed bitstream and sync it for
+   page extraction */
+int buffer_data(FILE *in,ogg_sync_state *oy){
+  char *buffer=ogg_sync_bufferin(oy,4096);
+  int bytes;
+
+#ifdef PRE_READ_FILE
+  if (in == NULL){
+    bytes = pre_read_left;
+    if (bytes > 4096)
+        bytes = 4096;
+    pre_read_left -= bytes;
+    memcpy(buffer, pre_read_ptr, bytes);
+    pre_read_ptr += bytes;
+  }
+  else
+#endif
+  {
+    bytes=fread(buffer,1,4096,in);
+  }
+  ogg_sync_wrote(oy,bytes);
+  return(bytes);
+}
+
+/* never forget that globals are a one-way ticket to Hell */
+/* Ogg and codec state for demux/decode */
+ogg_sync_state    oy;
+ogg_page          og;
+ogg_stream_state  vo;
+ogg_stream_state  to;
+theora_info       ti;
+theora_comment    tc;
+theora_state      td;
+vorbis_info       vi;
+vorbis_dsp_state  vd;
+vorbis_comment    vc;
+
+int              theora_p;
+int              vorbis_p;
+int              stateflag;
+
+/* single frame video buffering */
+int          videobuf_ready;
+ogg_int64_t  videobuf_granulepos;
+double       videobuf_time;
+
+/* single audio fragment audio buffering */
+int          audiobuf_ready;
+ogg_int16_t *audiobuf;
+ogg_int64_t  audiobuf_granulepos; /* time position of last sample */
+#define PCM_SIZE (1<<15)
+ogg_int16_t  pcm[PCM_SIZE];
+int          pcmstart; /* In samples */
+int          pcmsent;  /* In samples */
+int          pcmend;   /* In samples */
+ogg_int64_t  audio_samples;
+int          audio_sendtime;
+
+typedef enum
+{
+    Playback_DecodeVideo = 1,
+    Playback_DecodeAudio = 2,
+    Playback_PlayVideo   = 4,
+    Playback_PlayAudio   = 8,
+    Playback_Sync        = 16,
+    Playback_CRC         = 32,
+    Playback_ShowCRC     = 64
+} Playback;
+
+Playback        playback;
+
+#ifdef _WIN32_WCE
+static HWAVEOUT wince_audio_dev;
+static WAVEHDR whdr1;
+static WAVEHDR whdr2;
+#else
+static int audio_dev = 0;
+static int audio_started = 0;
+#endif
+
+void open_audio(void)
+{
+#ifdef _WIN32_WCE
+  WAVEFORMATEX wfx;
+  MMRESULT     res;
+
+  wince_audio_dev = NULL;
+  wfx.wFormatTag      = WAVE_FORMAT_PCM;
+  wfx.nChannels       = vi.channels;
+  wfx.nSamplesPerSec  = vi.rate;
+  wfx.wBitsPerSample  = 16;
+  wfx.nBlockAlign     = (wfx.wBitsPerSample*vi.channels)>>3;
+  wfx.nAvgBytesPerSec = vi.rate*wfx.nBlockAlign;
+  wfx.cbSize          = 0;
+  res = waveOutOpen(&wince_audio_dev,
+                    0,
+                    &wfx,
+                    0,
+                    0,
+                    CALLBACK_NULL);
+  if (res!= MMSYSERR_NOERROR)
+  {
+    /* Failed */
+    wince_audio_dev = NULL;
+  }
+  whdr1.dwBufferLength = 0;
+  whdr1.dwFlags = WHDR_DONE;
+  whdr2.dwBufferLength = 0;
+  whdr2.dwFlags = WHDR_DONE;
+#else
+  audio_started = 0;
+  audio_dev = open("/dev/audio", O_WRONLY);
+  if (audio_dev == 0)
+      return;
+  {
+    int format   = AFMT_S16_LE;
+    int channels = vi.channels;
+    int speed    = vi.rate;
+    int enable   = ~PCM_ENABLE_OUTPUT;
+
+    if (ioctl(audio_dev, SNDCTL_DSP_SETFMT, &format) != 0)
+    {
+      Output("Failed to set 16bit PCM\n");
+      close(audio_dev);
+      audio_dev = 0;
+      return;
+    }
+    if (ioctl(audio_dev, SNDCTL_DSP_CHANNELS, &channels) != 0)
+    {
+      Output("Failed to get number of channels\n");
+      close(audio_dev);
+      audio_dev = 0;
+      return;
+    }
+    if (ioctl(audio_dev, SNDCTL_DSP_SPEED, &speed) != 0)
+    {
+      Output("Failed to set sample speed\n");
+      close(audio_dev);
+      audio_dev = 0;
+      return;
+    }
+    if (ioctl(audio_dev, SNDCTL_DSP_SETTRIGGER, &enable) != 0)
+    {
+      Output("Failed to disable PCM\n");
+      close(audio_dev);
+      audio_dev = 0;
+      return;
+    }
+  }
+#endif
+  pcmstart = 0;
+  pcmsent  = 0;
+  pcmend   = 0;
+  audio_samples = 0;
+  audio_sendtime = clock();
+}
+
+#if 1
+#define AUDIO_CHECK()
+#else
+#define AUDIO_CHECK() do {audio_check();}while(0==1)
+void audio_check(void)
+{
+    if ((pcmstart <0) || (pcmstart >= PCM_SIZE))
+    {
+        Output("pcmstart out of range! %04x\n", pcmstart);
+        pcmsent = (pcmsent>>1)<<1;
+    }
+    if ((pcmsent <0) || (pcmsent >= PCM_SIZE))
+    {
+        Output("pcmsent out of range! %04x\n", pcmsent);
+        pcmsent = (pcmsent>>1)<<1;
+    }
+    if ((pcmend <0) || (pcmend >= PCM_SIZE))
+    {
+        Output("pcmend out of range! %04x\n", pcmend);
+        pcmend = (pcmend>>1)<<1;
+    }
+    Output("start=%04x sent=%04x end=%04x\n", pcmstart, pcmsent, pcmend);
+    if (pcmstart == pcmend)
+    {
+        if (pcmsent != pcmstart)
+        {
+            Output("pcmsent Broken!\n");
+            pcmsent = (pcmsent>>1)<<1;
+        }
+    }
+    if (pcmstart < pcmend)
+    {
+        if ((pcmsent < pcmstart) || (pcmsent > pcmend))
+        {
+            Output("pcmsent Broken! (2)\n");
+            pcmsent = (pcmsent>>1)<<1;
+        }
+    }
+    if (pcmstart > pcmend)
+    {
+        if ((pcmsent < pcmstart) && (pcmsent > pcmend))
+        {
+            Output("pcmsent Broken! (3) start=%04x sent=%04x end=%04x\n", pcmstart, pcmsent, pcmend);
+            pcmsent = (pcmsent>>1)<<1;
+        }
+    }
+}
+#endif
+
+void audio_close(void)
+{
+#ifdef _WIN32_WCE
+  if (wince_audio_dev != NULL)
+  {
+    waveOutClose(wince_audio_dev);
+    wince_audio_dev = NULL;
+  }
+#else
+  if (audio_dev != 0)
+  {
+    close(audio_dev);
+    audio_dev = 0;
+  }
+#endif
+}
+
+int audio_fillblock(ogg_int16_t **pos)
+{
+    *pos = &pcm[pcmend];
+    if (pcmstart == pcmend)
+    {
+        /* Empty buffer */
+        //Output("Sound buffer empty, requesting %d samples\n", PCM_SIZE/4);
+        return PCM_SIZE/4;
+    }
+    else if ((pcmstart - pcmend) > (PCM_SIZE/4))
+    {
+        /* [***.......#########*****] */
+        /*     ^end   ^start   ^sent */
+        //Output("Sound buffer wrapped, requesting %d samples\n", PCM_SIZE/4);
+        return PCM_SIZE/4;
+    }
+    else if ((pcmstart == 0) && (pcmend >= 3*PCM_SIZE/4))
+    {
+        return 0;
+    }
+    else if (pcmend > pcmstart)
+    {
+        int max;
+        /* [...##########******.....] */
+        /*     ^start    ^sent ^end   */
+
+        max = PCM_SIZE-pcmend;
+        if (max > PCM_SIZE/4)
+            max = PCM_SIZE/4;
+        //Output("Sound buffer unwrapped, requesting %d samples\n", max);
+        return max;
+    }
+    //Output("Sound buffer full\n");
+    return 0;
+}
+
+double audio_time()
+{
+    int extratime;
+
+    extratime = clock()-audio_sendtime;
+    if (!vorbis_p)
+      return (double)extratime/CLOCKS_PER_SEC;
+    return ((double)audio_samples/vi.channels/vi.rate +
+            (double)extratime/CLOCKS_PER_SEC);
+}
+
+void audio_filled(int samples)
+{
+  int fill;
+
+  if ((playback & Playback_PlayAudio) == 0)
+  {
+      audiobuf_ready = 1;
+      return;
+  }
+
+  //Output("Sound buffer filled with %d samples\n", samples);
+  pcmend += samples;
+  if (pcmend == PCM_SIZE)
+    pcmend = 0;
+  AUDIO_CHECK();
+
+  fill = pcmend - pcmstart;
+  if (fill < 0)
+    fill = PCM_SIZE - fill;
+  audiobuf_ready = (fill >= PCM_SIZE/2);
+}
+
+STATIC void kick_audio(void)
+{
+  int enable = PCM_ENABLE_OUTPUT;
+
+  ioctl(audio_dev, SNDCTL_DSP_SETTRIGGER, &enable);
+  audio_started = 1;
+}
+
+STATIC void audio_write_nonblocking(void)
+{
+  int      len;
+#ifdef _WIN32_WCE
+  MMRESULT res;
+  DWORD    flags1;
+  DWORD    flags2;
+
+  if (wince_audio_dev != NULL)
+  {
+    flags1 = whdr1.dwFlags;
+    if ((flags1 & WHDR_DONE) != 0)
+    {
+      pcmstart += whdr1.dwBufferLength>>1;
+      if (pcmstart >= PCM_SIZE)
+        pcmstart -= PCM_SIZE;
+      whdr1.dwBufferLength = 0;
+      AUDIO_CHECK();
+    }
+    flags2 = whdr2.dwFlags;
+    if ((flags1 & WHDR_DONE) != 0)
+    {
+      pcmstart += whdr2.dwBufferLength>>1;
+      if (pcmstart >= PCM_SIZE)
+        pcmstart -= PCM_SIZE;
+      whdr2.dwBufferLength = 0;
+      AUDIO_CHECK();
+    }
+    len = (pcmend-pcmsent);
+    if (len < 0)
+      len = PCM_SIZE-pcmsent;
+    if (len == 0)
+    {
+        /* Nothing to do, as everything sent */
+    }
+    else if ((flags1 & WHDR_DONE) != 0)
+    {
+      whdr1.lpData         = (LPSTR)&pcm[pcmsent];
+      whdr1.dwBufferLength = len*2; /* Bytes */
+      whdr1.dwFlags        = 0;
+      res = waveOutPrepareHeader(wince_audio_dev, &whdr1, sizeof(whdr1));
+      res = waveOutWrite(wince_audio_dev, &whdr1, sizeof(whdr1));
+      audio_samples += len;
+      audio_sendtime = clock();
+      //Output("Sending %d samples\n", len);
+      pcmsent += len;
+      if (pcmsent == PCM_SIZE)
+        pcmsent = 0;
+      AUDIO_CHECK();
+    }
+    else if ((flags2 & WHDR_DONE) != 0)
+    {
+      whdr2.lpData         = (LPSTR)&pcm[pcmsent];
+      whdr2.dwBufferLength = len*2; /* Bytes */
+      whdr2.dwFlags        = 0;
+      res = waveOutPrepareHeader(wince_audio_dev, &whdr2, sizeof(whdr2));
+      res = waveOutWrite(wince_audio_dev, &whdr2, sizeof(whdr2));
+      audio_samples += len;
+      audio_sendtime = clock();
+      //Output("Sending %d samples\n", len);
+      pcmsent += len;
+      if (pcmsent == PCM_SIZE)
+        pcmsent = 0;
+      AUDIO_CHECK();
+    }
+  }
+#else
+  if (audio_dev != 0)
+  {
+    len = (pcmend-pcmsent);
+    if (len < 0)
+      len = PCM_SIZE-pcmsent;
+    len &= ~4093;
+    if (len > 0)
+    {
+      audio_buf_info info;
+
+      if (!audio_started)
+      {
+        /* We mustn't start until we have at least half a buffer full */
+        if (len < PCM_SIZE/2)
+            return;
+      }
+
+      ioctl(audio_dev, SNDCTL_DSP_GETOSPACE, &info);
+      /* Don't get too far ahead of ourselves */
+      //if ((info.fragstotal - info.fragments)*info.fragsize > PCM_SIZE*2)
+      //  return;
+      if (info.bytes < len*2)
+      {
+        if (!audio_started)
+          kick_audio();
+        return;
+      }
+
+      //printf("Sending %d samples from offset %d\n", len, pcmsent);
+      write(audio_dev, &pcm[pcmsent], len*2);
+      pcmsent += len;
+      audio_samples += len;
+      if (pcmsent == PCM_SIZE)
+        pcmsent = 0;
+      pcmstart += len;
+      if (pcmstart == PCM_SIZE)
+        pcmstart = 0;
+      audio_sendtime = clock();
+      info.bytes -= len*2;
+
+      if ((!audio_started) && (info.bytes < info.fragsize))
+      {
+        kick_audio();
+      }
+
+      AUDIO_CHECK();
+    }
+  }
+#endif
+  audiobuf_ready = 0;
+}
+
+int   raw;
+char *rgb_frame;
+
+FILE *outfile;
+
+void display_video(void *base)
+{
+#ifdef HAVE_YUVLIB
+  int w, h;
+
+  yuv_buffer yuv;
+  theora_decode_YUVout(&td,&yuv);
+
+  w = yuv.y_width;
+  if (w > screen_width)
+      w = screen_width;
+  h = yuv.y_height;
+  if (h > screen_height)
+      h = screen_height;
+  switch (screen_depth)
+  {
+    case 16:
+      if ((yuv.y_width == yuv.uv_width) && (yuv.y_height == yuv.uv_height))
+      {
+        yuv444_2_rgb565(base,
+                        yuv.y,
+                        yuv.u,
+                        yuv.v,
+                        w,
+                        h,
+                        yuv.y_stride,
+                        yuv.uv_stride,
+                        screen_width*2,
+                        yuv2rgb565_table,
+                        dither++);
+      }
+      else if (yuv.y_height == yuv.uv_height)
+      {
+        yuv422_2_rgb565(base,
+                        yuv.y,
+                        yuv.u,
+                        yuv.v,
+                        w,
+                        h,
+                        yuv.y_stride,
+                        yuv.uv_stride,
+                        screen_width*2,
+                        yuv2rgb565_table,
+                        dither++);
+      }
+      else
+      {
+        yuv420_2_rgb565(base,
+                        yuv.y,
+                        yuv.u,
+                        yuv.v,
+                        w,
+                        h,
+                        yuv.y_stride,
+                        yuv.uv_stride,
+                        screen_width*2,
+                        yuv2rgb565_table,
+                        dither++);
+      }
+      break;
+    case 24:
+      if ((yuv.y_width == yuv.uv_width) && (yuv.y_height == yuv.uv_height))
+      {
+        yuv444_2_rgb888(base,
+                        yuv.y,
+                        yuv.u,
+                        yuv.v,
+                        w,
+                        h,
+                        yuv.y_stride,
+                        yuv.uv_stride,
+                        screen_width*3,
+                        yuv2rgb565_table,
+                        dither++);
+      }
+      else if (yuv.y_height == yuv.uv_height)
+      {
+        yuv422_2_rgb888(base,
+                        yuv.y,
+                        yuv.u,
+                        yuv.v,
+                        w,
+                        h,
+                        yuv.y_stride,
+                        yuv.uv_stride,
+                        screen_width*3,
+                        yuv2rgb565_table,
+                        dither++);
+      }
+      else
+      {
+        yuv420_2_rgb888(base,
+                        yuv.y,
+                        yuv.u,
+                        yuv.v,
+                        w,
+                        h,
+                        yuv.y_stride,
+                        yuv.uv_stride,
+                        screen_width*3,
+                        yuv2rgb565_table,
+                        dither++);
+      }
+      break;
+    case 32:
+      if ((yuv.y_width == yuv.uv_width) && (yuv.y_height == yuv.uv_height))
+      {
+        yuv444_2_rgb8888(base,
+                         yuv.y,
+                         yuv.u,
+                         yuv.v,
+                         w,
+                         h,
+                         yuv.y_stride,
+                         yuv.uv_stride,
+                         screen_width*4,
+                         yuv2rgb565_table,
+                         dither++);
+      }
+      else if (yuv.y_height == yuv.uv_height)
+      {
+        yuv422_2_rgb8888(base,
+                         yuv.y,
+                         yuv.u,
+                         yuv.v,
+                         w,
+                         h,
+                         yuv.y_stride,
+                         yuv.uv_stride,
+                         screen_width*4,
+                         yuv2rgb565_table,
+                         dither++);
+      }
+      else
+      {
+        yuv420_2_rgb8888(base,
+                         yuv.y,
+                         yuv.u,
+                         yuv.v,
+                         w,
+                         h,
+                         yuv.y_stride,
+                         yuv.uv_stride,
+                         screen_width*4,
+                         yuv2rgb565_table,
+                         dither++);
+      }
+      break;
+    default:
+      break;
+  }
+#endif
+}
+
+#if 0
+int got_sigint=0;
+static void sigint_handler (int signal) {
+  got_sigint = 1;
+}
+#endif
+
+/* this is a nop in the current implementation. we could
+   open a file here or something if so moved. */
+STATIC void open_video(void){
+  return;
+}
+
+/* write out the planar YUV frame, uncropped */
+STATIC void video_write(void){
+  yuv_buffer yuv;
+  theora_decode_YUVout(&td,&yuv);
+
+#ifdef HAVE_YUVLIB
+  if (rgb_frame == NULL)
+  {
+    rgb_frame = malloc(yuv.y_height*yuv.y_width*sizeof(short));
+    if (rgb_frame == NULL)
+      Output("Failed to malloc output rgb buffer!\n");
+  }
+  if (rgb_frame != NULL)
+  {
+      yuv420_2_rgb565(rgb_frame,
+                      yuv.y,
+                      yuv.u,
+                      yuv.v,
+                      yuv.y_width,
+                      yuv.y_height,
+                      yuv.y_stride,
+                      yuv.uv_stride,
+                      yuv.y_height*2,
+                      yuv2rgb565_table,
+                      dither++);
+    Output("Saving RGB Frame\n");
+    fwrite(rgb_frame, 1, yuv.y_height*yuv.y_width*sizeof(short), outfile);
+  }
+
+#else
+  if(outfile){
+    int i;
+    Output("Saving Frame\n");
+    if(!raw)
+      fprintf(outfile, "FRAME\n");
+    for(i=0;i<yuv.y_height;i++)
+      fwrite(yuv.y+yuv.y_stride*i, 1, yuv.y_width, outfile);
+    for(i=0;i<yuv.uv_height;i++)
+      fwrite(yuv.u+yuv.uv_stride*i, 1, yuv.uv_width, outfile);
+    for(i=0;i<yuv.uv_height;i++)
+      fwrite(yuv.v+yuv.uv_stride*i, 1, yuv.uv_width, outfile);
+  }
+#endif
+}
+
+STATIC void do_crc(unsigned char *in, int width, int *crc_ref)
+{
+    int crc = *crc_ref;
+
+    while (--width > 0)
+    {
+      int i = *in++;
+
+      if (--width > 0)
+          i |= (*in++)<<8;
+
+      crc = ((crc<<1) | (crc>>15)) ^ i;
+      crc &= 65535;
+    }
+
+    *crc_ref = crc;
+}
+
+STATIC void video_crc(int *crcref){
+  int i;
+
+  yuv_buffer yuv;
+  theora_decode_YUVout(&td,&yuv);
+
+  for(i=0;i<yuv.y_height;i++)
+    do_crc(yuv.y+yuv.y_stride*i, yuv.y_width, crcref);
+  for(i=0;i<yuv.uv_height;i++)
+    do_crc(yuv.u+yuv.uv_stride*i, yuv.uv_width, crcref);
+  for(i=0;i<yuv.uv_height;i++)
+    do_crc(yuv.v+yuv.uv_stride*i, yuv.uv_width, crcref);
+
+  if ((playback & Playback_ShowCRC) != 0)
+      Output("Cumulative CRC = %04x\n", *crcref);
+}
+
+/* dump the theora comment header */
+STATIC int dump_comments(theora_comment *tc){
+  int i, len;
+  char *value;
+
+  Output("Encoded by %s\n",tc->vendor);
+  if(tc->comments){
+    Output("theora comment header:\n");
+    for(i=0;i<tc->comments;i++){
+      if(tc->user_comments[i]){
+        len=tc->comment_lengths[i];
+        value=malloc(len+1);
+        memcpy(value,tc->user_comments[i],len);
+        value[len]='\0';
+        Output("\t%s\n", value);
+        free(value);
+      }
+    }
+  }
+  return(0);
+}
+
+
+
+/* helper: push a page into the appropriate steam */
+/* this can be done blindly; a stream won't accept a page
+                that doesn't belong to it */
+STATIC int queue_page(ogg_page *page){
+  if(theora_p)ogg_stream_pagein(&to,page);
+  if(vorbis_p)ogg_stream_pagein(&vo,page);
+  return 0;
+}
+
+STATIC void syntax(void){
+  Output( "Usage: testtheora <infile.ogv> {[<crc_or_outfile>] [maxframes]\n"
+          "where <crc_or_outfile> is:\n"
+          " -<xxxx>    play A/V unsynced displaying crcs\n"
+          " :<xxxx>    play A/V unsynced and display final crc\n"
+          " ;          decode A/V (no playback or crcs) (for speed/timings)\n"
+          " +          play A/V synced (badly)\n"
+          " *          play A/V unsynced\n"
+          " @<xxxx>    decode A/V, but only play video\n"
+          " <filename> output file\n"
+          "\n"
+          "In the above, xxxx is the expected 4 digit hex CRC of the decoded frame."
+          "\n"
+  );
+  exit(1);
+}
+
+int main(int argc,char *const *argv){
+
+  ogg_packet op;
+
+  void *framebuffer = NULL;
+  int max_frames = 0x7FFFFFFF;
+  int frames     = 0;
+  int crc        = 0;
+  int refcrc     = -1;
+#ifdef POST_PROCESS
+  int pp_level_max;
+  int pp_level;
+  int pp_inc;
+#endif
+
+  clock_t start_clock, end_clock;
+  FILE *infile   = stdin;
+  outfile        = NULL;
+  rgb_frame      = NULL;
+
+  /* Process option arguments. */
+  if (argc < 2)
+    syntax();
+
+  infile=fopen(argv[1],"rb");
+  if(infile==NULL){
+    Output("Unable to open '%s' for extraction.\n", argv[1]);
+    syntax();
+  }
+
+#ifdef PRE_READ_FILE
+  if (pre_read_file(infile) == 0)
+  {
+      infile = NULL;
+  }
+#endif
+
+  playback = Playback_DecodeVideo;
+  if (argc >= 3)
+  {
+    char *p = argv[2];
+    if (p[0] == '-')
+    {
+      playback |= Playback_DecodeAudio | Playback_PlayVideo | Playback_PlayAudio | Playback_ShowCRC;
+    }
+    else if (p[0] == ':')
+    {
+      playback |= Playback_DecodeAudio | Playback_PlayVideo | Playback_PlayAudio;
+    }
+    else if (p[0] == ';')
+    {
+      playback |= Playback_DecodeAudio;
+    }
+    else if (p[0] == '+')
+    {
+      playback |= Playback_DecodeAudio | Playback_PlayVideo | Playback_PlayAudio | Playback_CRC | Playback_Sync; /* Really crap attempt at syncing */
+    }
+    else if (p[0] == '*')
+    {
+      playback |= Playback_DecodeAudio | Playback_PlayVideo | Playback_PlayAudio;
+    }
+    else if (p[0] == '@')
+    {
+      playback |= Playback_DecodeAudio | Playback_PlayVideo;
+    }
+    else
+    {
+      outfile=fopen(argv[2],"wb");
+      if(outfile==NULL){
+        Output("Unable to open output file '%s'\n", argv[2]);
+        exit(1);
+      }
+      p = NULL;
+    }
+    if ((p != NULL) && (p[1] != '0'))
+    {
+        sscanf(&p[1], "%x", &refcrc);
+        playback |= Playback_CRC;
+    }
+  }
+
+  if (argc >= 4)
+  {
+    max_frames=atoi(argv[3]);
+  }
+
+  theora_p = 0;
+  vorbis_p = 0;
+  stateflag = 0;
+  videobuf_ready=0;
+  videobuf_granulepos=-1;
+  videobuf_time=0;
+  audiobuf_ready=0;
+  audiobuf_granulepos=0; /* time position of last sample */
+  raw=0;
+
+  /*
+     Ok, Ogg parsing. The idea here is we have a bitstream
+     that is made up of Ogg pages. The libogg sync layer will
+     find them for us. There may be pages from several logical
+     streams interleaved; we find the first theora stream and
+     ignore any others.
+
+     Then we pass the pages for our stream to the libogg stream
+     layer which assembles our original set of packets out of
+     them. It's the packets that libtheora actually knows how
+     to handle.
+  */
+
+  /* start up Ogg stream synchronization layer */
+  ogg_sync_init(&oy);
+
+  /* init supporting Vorbis structures needed in header parsing */
+  vorbis_info_init(&vi);
+  vorbis_comment_init(&vc);
+
+  /* init supporting Theora structures needed in header parsing */
+  theora_comment_init(&tc);
+  theora_info_init(&ti);
+
+  memset(&op, 0, sizeof(op));
+
+  /* Ogg file open; parse the headers */
+
+  /* Vorbis and Theora both depend on some initial header packets
+     for decoder setup and initialization. We retrieve these first
+     before entering the main decode loop. */
+
+  /* Only interested in Theora streams */
+  while(!stateflag){
+    int ret=buffer_data(infile,&oy);
+    if(ret==0)break;
+    while(ogg_sync_pageout(&oy,&og)>0){
+      ogg_stream_state test;
+
+      /* is this a mandated initial header? If not, stop parsing */
+      if(!ogg_page_bos(&og)){
+        /* don't leak the page; get it into the appropriate stream */
+        queue_page(&og);
+        stateflag=1;
+        break;
+      }
+
+      ogg_stream_init(&test,ogg_page_serialno(&og));
+      ogg_stream_pagein(&test,&og);
+      ogg_stream_packetout(&test,&op);
+
+      /* identify the codec: try theora */
+      if(!theora_p && theora_decode_header(&ti,&tc,&op)>=0){
+        /* it is theora -- save this stream state */
+        memcpy(&to,&test,sizeof(test));
+        theora_p=1;
+      }else if(((playback & Playback_DecodeAudio) != 0) &&
+               (!vorbis_p && vorbis_dsp_headerin(&vi,&vc,&op)>=0)){
+        /* it is vorbis */
+        memcpy(&vo,&test,sizeof(test));
+        vorbis_p=1;
+      }else{
+        /* whatever it is, we don't care about it */
+        ogg_stream_clear(&test);
+      }
+    }
+    /* fall through to non-bos page parsing */
+  }
+
+  /* we're expecting more header packets. */
+  while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)){
+    int ret;
+
+    /* look for further theora headers */
+    while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){
+      if(ret<0){
+        Output("Error parsing Theora stream headers; corrupt stream?\n");
+        exit(1);
+      }
+      if(theora_decode_header(&ti,&tc,&op)){
+        Output("Error parsing Theora stream headers; corrupt stream?\n");
+        exit(1);
+      }
+      theora_p++;
+    }
+
+    /* look for more vorbis header packets */
+    while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){
+      if(ret<0){
+        fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
+        exit(1);
+      }
+      if(vorbis_dsp_headerin(&vi,&vc,&op)){
+        fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
+        exit(1);
+      }
+      vorbis_p++;
+    }
+
+    /* The header pages/packets will arrive before anything else we
+       care about, or the stream is not obeying spec */
+
+    if(ogg_sync_pageout(&oy,&og)>0){
+      queue_page(&og); /* demux into the appropriate stream */
+    }else{
+      int ret=buffer_data(infile,&oy); /* someone needs more data */
+      if(ret==0){
+        Output("End of file while searching for codec headers.\n");
+        exit(1);
+      }
+    }
+  }
+
+  /* and now we have it all.  initialize decoders */
+  if(theora_p){
+    theora_decode_init(&td,&ti);
+    Output("Ogg logical stream %lx is Theora %dx%d %.02f fps video\n"
+           "Encoded frame content is %dx%d with %dx%d offset\n",
+           to.serialno,ti.width,ti.height,
+           (double)ti.fps_numerator/ti.fps_denominator,
+           ti.frame_width,ti.frame_height,ti.offset_x,ti.offset_y);
+    if ((playback & Playback_PlayVideo) != 0)
+      framebuffer = open_screen(ti.width, ti.height);
+    dump_comments(&tc);
+#ifdef POST_PROCESS
+    theora_control(&td,TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max,
+     sizeof(pp_level_max));
+    pp_level=pp_level_max;
+    theora_control(&td,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level));
+    pp_inc=0;
+#endif
+  }else{
+    /* tear down the partial theora setup */
+    theora_info_clear(&ti);
+    theora_comment_clear(&tc);
+  }
+
+  if(vorbis_p){
+    vorbis_dsp_init(&vd,&vi);
+    Output("Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n",
+           vo.serialno,vi.channels,vi.rate);
+  }else{
+    /* tear down the partial vorbis setup */
+    vorbis_info_clear(&vi);
+    vorbis_comment_clear(&vc);
+  }
+
+  /* open audio */
+  if(vorbis_p)open_audio();
+
+  /* open video */
+  if(theora_p)open_video();
+
+  if(!raw && outfile){
+    Output("YUV4MPEG2 W%d H%d F%d:%d I%c A%d:%d\n",
+           ti.width,ti.height,ti.fps_numerator,ti.fps_denominator,'p',
+           ti.aspect_numerator,ti.aspect_denominator);
+  }
+
+#if 0
+  /* install signal handler */
+  signal (SIGINT, sigint_handler);
+#endif
+
+  start_clock = clock();
+
+  /* Finally the main decode loop.
+
+     It's one Theora packet per frame, so this is pretty
+     straightforward if we're not trying to maintain sync
+     with other multiplexed streams.
+
+     the videobuf_ready flag is used to maintain the input
+     buffer in the libogg stream state. If there's no output
+     frame available at the end of the decode step, we must
+     need more input data. We could simplify this by just
+     using the return code on ogg_page_packetout(), but the
+     flag system extends easily to the case were you care
+     about more than one multiplexed stream (like with audio
+     playback). In that case, just maintain a flag for each
+     decoder you care about, and pull data when any one of
+     them stalls.
+
+     videobuf_time holds the presentation time of the currently
+     buffered video frame. We ignore this value.
+  */
+
+  stateflag=0; /* playback has not begun */
+  /* queue any remaining pages from data we buffered but that did not
+      contain headers */
+  while(ogg_sync_pageout(&oy,&og)>0){
+    queue_page(&og);
+  }
+
+  //if(fps_only){
+  //  ftime(&start);
+  //  ftime(&last);
+  //}
+
+  //while(!got_sigint){
+  while(max_frames > 0){
+
+    /* we want a video and audio frame ready to go at all times.  If
+       we have to buffer incoming, buffer the compressed data (ie, let
+       ogg do the buffering) */
+    while(vorbis_p && !audiobuf_ready){
+      int ret;
+      ogg_int16_t *fillbase;
+
+      /* if there's pending, decoded audio, grab it */
+      ret=audio_fillblock(&fillbase);
+      if (ret==0)
+          break;
+      ret=vorbis_dsp_pcmout(&vd,fillbase,ret/vi.channels);
+      if(ret>0){
+        vorbis_dsp_read(&vd,ret);
+        if(vd.granulepos>=0)
+          audiobuf_granulepos=vd.granulepos;
+        else
+          audiobuf_granulepos+=ret;
+        ret *= vi.channels;
+        audio_filled(ret);
+
+      }else{
+
+        /* no pending audio; is there a pending packet to decode? */
+        if(ogg_stream_packetout(&vo,&op)>0){
+          vorbis_dsp_synthesis(&vd,&op,1);//==0) /* test for success! */
+            //vorbis_synthesis_blockin(&vd,&vb);
+        }else   /* we need more data; break out to suck in another page */
+          break;
+      }
+    }
+
+    while(theora_p && !videobuf_ready){
+      /* theora is one in, one out... */
+      if(ogg_stream_packetout(&to,&op)>0){
+        int ret;
+
+#ifdef POST_PROCESS
+        if(pp_inc){
+          pp_level+=pp_inc;
+          theora_control(&td,TH_DECCTL_SET_PPLEVEL,&pp_level,
+           sizeof(pp_level));
+          pp_inc=0;
+        }
+#endif
+
+        ret=theora_decode_packetin(&td,&op);
+        if (ret<0)
+        {
+          Output("Decode returned %d\n",ret);
+        }
+        videobuf_granulepos=td.granulepos;
+        videobuf_time=theora_granule_time(&td,videobuf_granulepos);
+        videobuf_ready=1;
+        frames++;
+        max_frames--;
+        //if(fps_only)
+        //  ftime(&after);
+
+      }else
+        break;
+    }
+
+    if(!videobuf_ready && !audiobuf_ready && FEOF(infile))break;
+
+    if((theora_p && !videobuf_ready) || (vorbis_p && !audiobuf_ready)){
+      /* no data yet for somebody.  Grab another page */
+      buffer_data(infile,&oy);
+      while(ogg_sync_pageout(&oy,&og)>0){
+        queue_page(&og);
+      }
+    }
+
+    /* If playback has begun, top audio buffer off immediately. */
+    if(stateflag) audio_write_nonblocking();
+
+    /* dumpvideo frame, and get new one */
+    if(stateflag && videobuf_ready &&
+       (((playback & Playback_Sync) == 0) || (videobuf_time < audio_time())))
+    {
+      if (outfile)
+      {
+        video_write();
+      }
+      else
+      {
+        if ((playback & Playback_CRC) != 0)
+        {
+          video_crc(&crc);
+        }
+        if ((videobuf_ready) &&
+            (framebuffer != NULL) &&
+            ((playback & Playback_PlayVideo) != 0))
+        {
+          display_video(framebuffer);
+        }
+      }
+      videobuf_ready=0;
+    }
+
+    /* if our buffers either don't exist or are ready to go,
+       we can begin playback */
+    if((!theora_p || videobuf_ready) &&
+       (!vorbis_p || audiobuf_ready))stateflag=1;
+    /* same if we've run out of input */
+    if(FEOF(infile))stateflag=1;
+
+  }
+
+  end_clock = clock();
+
+  /* end of decoder loop -- close everything */
+  audio_close();
+
+  if(vorbis_p){
+    ogg_stream_clear(&vo);
+    vorbis_dsp_clear(&vd);
+    vorbis_comment_clear(&vc);
+    vorbis_info_clear(&vi);
+  }
+  if(theora_p){
+    ogg_stream_clear(&to);
+    theora_clear(&td);
+    theora_comment_clear(&tc);
+    theora_info_clear(&ti);
+  }
+  ogg_sync_clear(&oy);
+
+  free(rgb_frame);
+
+  if(infile && infile!=stdin)fclose(infile);
+  if(outfile) fclose(outfile);
+  if((playback & Playback_CRC) != 0)
+  {
+    if (refcrc == -1)
+        Output("CRC %04x\n", crc);
+    else if (crc == refcrc)
+      Output("CRC good!\n");
+    else
+      Output("CRC bad! %04x, but expected %04x\n", crc, refcrc);
+  }
+
+  end_clock -= start_clock;
+  Output("\n\n%d frames in %f ms  (%f fps)\n",
+         frames, ((float)end_clock)/CLOCKS_PER_SEC,
+         ((float)frames)*CLOCKS_PER_SEC/end_clock);
+  Output("\nDone.\n");
+
+#ifdef PRE_READ_FILE
+  pre_read_dump();
+#endif
+
+  return(0);
+
+}
+
+#ifdef _WIN32_WCE
+
+typedef struct
+{
+    int    argc;
+    char **argv;
+}
+thread_args;
+
+DWORD WINAPI thread_starter(void *args_)
+{
+    thread_args *args = (thread_args *)args_;
+
+    return main(args->argc, args->argv);
+}
+
+unsigned __int64 FILETIME_to_uint64(FILETIME ft)
+{
+    unsigned __int64 ret;
+    ret = ft.dwHighDateTime;
+    ret <<= 32;
+    ret |= ft.dwLowDateTime;
+    return ret;
+}
+
+int profile(int argc, char *argv[])
+{
+    HANDLE      thread;
+    thread_args args;
+    DWORD       threadId;
+    DWORD       exitcode = 1;
+    //FILETIME    create, exit, kernel, user;
+    int         total_time = 0;
+    unsigned __int64 oldTime = 0;
+    CONTEXT     context;
+    int        *profile;
+    int         bin;
+    int         tickcount = 0;
+
+#define PROFILE_START (0x11000)
+#define PROFILE_STOP  (0x39900)
+#define PROFILE_SIZE  (PROFILE_STOP-PROFILE_START)
+#define PROFILE_QUANT (4)
+
+    args.argc = argc;
+    args.argv = argv;
+
+    profile = calloc(PROFILE_SIZE>>PROFILE_QUANT, 4);
+    if (profile == NULL)
+    {
+        Output("Failed to allocate profile space!\n");
+        return 1;
+    }
+
+    thread = CreateThread(NULL,
+                          0,
+                          (LPTHREAD_START_ROUTINE)&thread_starter,
+                          &args,
+                          0,
+                          &threadId);
+
+    while (1 == 1)
+    {
+        BOOL  done;
+
+        done = GetExitCodeThread(thread, &exitcode);
+        if ((!done) || (exitcode != STILL_ACTIVE))
+            break;
+#if 0
+        done = GetThreadTimes(thread,
+                              &create,
+                              &exit,
+                              &kernel,
+                              &user);
+        if (done)
+        {
+            unsigned __int64 t64;
+
+            t64 = FILETIME_to_uint64(user) + FILETIME_to_uint64(kernel);
+            oldTime = (t64-oldTime)/10000;
+            total_time += (int)oldTime;
+            oldTime = t64;
+        }
+#endif
+        context.ContextFlags = CONTEXT_FULL;
+        done = GetThreadContext(thread, &context);
+
+        if (done)
+        {
+            bin = (context.Pc & 0x7FFFFFFF)>>(PROFILE_QUANT+2);
+            if (bin != 0)
+                bin -= PROFILE_START>>(PROFILE_QUANT+2);
+            if ((bin < 0) || (bin >= PROFILE_SIZE))
+            {
+                /* Try again, but with r14 */
+                bin = (context.Lr & 0x7FFFFFFF)>>(PROFILE_QUANT+2);
+                if (bin != 0)
+                    bin -= PROFILE_START>>(PROFILE_QUANT+2);
+            }
+            if ((bin < 0) || (bin >= PROFILE_SIZE))
+            {
+                bin = 0;
+                //Output("PC=%x r14=%x PSR=%x\n", context.Pc, context.Lr, context.Psr);
+            }
+            profile[bin]++;
+            tickcount++;
+        }
+
+        Sleep(1);
+    }
+
+    Output("Profiler shutting down: %x\n", total_time);
+
+    {
+        FILE *file;
+
+        file = fopen("\\Storage Card\\profile.out", "wb");
+        if (file != NULL)
+        {
+            int i;
+
+            fputc('P',file);
+            fputc('R',file);
+            fputc('O',file);
+            fputc('F',file);
+            i = 1; /* File version */
+            fwrite(&i, sizeof(int), 1, file);
+            i = 1000; /* Frequency */
+            fwrite(&i, sizeof(int), 1, file);
+            fwrite(&tickcount, sizeof(int), 1, file);
+            i = 1; /* Sections */
+            fwrite(&i, sizeof(int), 1, file);
+            i = PROFILE_QUANT; /* Granularity */
+            fwrite(&i, sizeof(int), 1, file);
+            i = PROFILE_START; /* Start */
+            fwrite(&i, sizeof(int), 1, file);
+            i = PROFILE_SIZE>>PROFILE_QUANT; /* Size */
+            fwrite(&i, sizeof(int), 1, file);
+            fwrite(profile, sizeof(int), PROFILE_SIZE>>PROFILE_QUANT, file);
+            fclose(file);
+        }
+    }
+
+    return exitcode;
+}
+
+
+#define TESTFILE 0
+
+#include "ddraw.h"
+
+int WinMain(HINSTANCE h,HINSTANCE i,LPWSTR l,int n)
+{
+    int ret;
+    char *argv0[] = { "testtheorarm",
+                     "\\Storage Card\\theorarm\\matrix-55.ogg",
+#ifdef POST_PROCESS
+                     "-47e5", // Full PP
+#else
+                     "-662c", // No PP
+#endif
+                     "10",
+                     NULL
+                   };
+    char *argv1[]= { "testtheorarm",
+                     "\\Storage Card\\theorarm\\matrix-300-varAQ.ogg",
+                     //"\\Storage Card\\theorarm\\matrix-300-varAQ.out",
+#ifdef POST_PROCESS
+                     "-3ddf", // Full PP
+#else
+                     "-90d6", // No PP
+#endif
+                     "10",
+                     NULL
+                   };
+    char *argv0v[] = { "testtheorarm",
+                     "\\Storage Card\\theorarm\\matrix-55.ogg",
+                     "+",
+                     "100",
+                     NULL
+                   };
+    char *argv1v[]= { "testtheorarm",
+                     "\\Storage Card\\theorarm\\matrix-300-varAQ.ogg",
+                     //"\\Storage Card\\theorarm\\matrix-300-varAQ.out",
+                     "+",
+                     "100",
+                     NULL
+                   };
+    char *argv2v[]= { "testtheorarm",
+                     //"\\Storage Card\\theorarm\\my-matrix.ogg",
+                     "\\my-matrix2.ogg",
+                     //"*",
+#if 1
+                     ";",
+#else
+#ifdef POST_PROCESS
+                     //":0000",
+#else
+                     //":4a08",
+#endif
+#endif
+                     "100000000",
+                     NULL
+                   };
+    char *argv3v[]= { "testtheorarm",
+                     "\\Storage Card\\theorarm\\ducks_take_off_444_720p25.ogg",
+                     "*",
+                     "30",
+                     NULL
+                   };
+    char *argv4v[]= { "testtheorarm",
+                     "\\Storage Card\\theorarm\\mobile_422_ntsc.ogg",
+                     "*",
+                     "30",
+                     NULL
+                   };
+
+    ret = main(4, argv0);
+    if (ret == 0)
+        ret = main(4, argv1);
+    if (ret == 0)
+        ret = main(4, argv4v);
+    if (ret == 0)
+        ret = main(4, argv0v);
+    if (ret == 0)
+        ret = main(4, argv1v);
+    if (ret == 0)
+        ret = main(4, argv3v);
+    if (ret == 0)
+        ret = profile(4, argv2v);
+    return ret;
+}
+
+int wmain(int argc,char *const *argv)
+{
+    return WinMain(0,0,0,0);
+}
+
+#endif

Added: branches/theorarm-merge-branch/rjw/tremolo/codec_internal.h
===================================================================
--- branches/theorarm-merge-branch/rjw/tremolo/codec_internal.h	                        (rev 0)
+++ branches/theorarm-merge-branch/rjw/tremolo/codec_internal.h	2010-05-30 15:45:07 UTC (rev 17259)
@@ -0,0 +1,213 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: libvorbis codec headers
+
+ ********************************************************************/
+
+#ifndef _V_CODECI_H_
+#define _V_CODECI_H_
+
+#define CHUNKSIZE 1024
+
+#include "codebook.h"
+#include "ivorbiscodec.h"
+
+#define VI_TRANSFORMB 1
+#define VI_WINDOWB 1
+#define VI_TIMEB 1
+#define VI_FLOORB 2
+#define VI_RESB 3
+#define VI_MAPB 1
+
+typedef void vorbis_info_floor;
+
+/* vorbis_dsp_state buffers the current vorbis audio
+   analysis/synthesis state.  The DSP state belongs to a specific
+   logical bitstream ****************************************************/
+struct vorbis_dsp_state{
+  vorbis_info    *vi;
+  oggpack_buffer  opb;
+
+  ogg_int32_t   **work;
+  ogg_int32_t   **mdctright;
+  int             out_begin;
+  int             out_end;
+
+  long lW;
+  long W;
+
+  ogg_int64_t granulepos;
+  ogg_int64_t sequence;
+  ogg_int64_t sample_count;
+
+};
+
+
+/* Floor backend generic *****************************************/
+
+extern vorbis_info_floor *floor0_info_unpack(vorbis_info *,oggpack_buffer *);
+extern void floor0_free_info(vorbis_info_floor *);
+extern int floor0_memosize(vorbis_info_floor *);
+extern ogg_int32_t *floor0_inverse1(struct vorbis_dsp_state *,
+				    vorbis_info_floor *,ogg_int32_t *);
+extern int floor0_inverse2 (struct vorbis_dsp_state *,vorbis_info_floor *,
+			    ogg_int32_t *buffer,ogg_int32_t *);
+
+extern vorbis_info_floor *floor1_info_unpack(vorbis_info *,oggpack_buffer *);
+extern void floor1_free_info(vorbis_info_floor *);
+extern int floor1_memosize(vorbis_info_floor *);
+extern ogg_int32_t *floor1_inverse1(struct vorbis_dsp_state *,
+				    vorbis_info_floor *,ogg_int32_t *);
+extern int floor1_inverse2 (struct vorbis_dsp_state *,vorbis_info_floor *,
+			    ogg_int32_t *buffer,ogg_int32_t *);
+
+typedef struct{
+  int   order;
+  long  rate;
+  long  barkmap;
+
+  int   ampbits;
+  int   ampdB;
+
+  int   numbooks; /* <= 16 */
+  char  books[16];
+
+} vorbis_info_floor0;
+
+typedef struct{
+  char  class_dim;        /* 1 to 8 */
+  char  class_subs;       /* 0,1,2,3 (bits: 1<<n poss) */
+  unsigned char  class_book;       /* subs ^ dim entries */
+  unsigned char  class_subbook[8]; /* [VIF_CLASS][subs] */
+} floor1class;  
+
+typedef struct{
+  floor1class  *class;          /* [VIF_CLASS] */
+  char         *partitionclass; /* [VIF_PARTS]; 0 to 15 */
+  ogg_uint16_t *postlist;       /* [VIF_POSIT+2]; first two implicit */ 
+  char         *forward_index;  /* [VIF_POSIT+2]; */
+  char         *hineighbor;     /* [VIF_POSIT]; */
+  char         *loneighbor;     /* [VIF_POSIT]; */
+
+  int          partitions;    /* 0 to 31 */
+  int          posts;
+  int          mult;          /* 1 2 3 or 4 */ 
+
+} vorbis_info_floor1;
+
+/* Residue backend generic *****************************************/
+
+typedef struct vorbis_info_residue{
+  int type;
+  unsigned char *stagemasks;
+  unsigned char *stagebooks;
+
+/* block-partitioned VQ coded straight residue */
+  long begin;
+  long end;
+
+  /* first stage (lossless partitioning) */
+  int           grouping;         /* group n vectors per partition */
+  char          partitions;       /* possible codebooks for a partition */
+  unsigned char groupbook;        /* huffbook for partitioning */
+  char          stages;
+} vorbis_info_residue;
+
+extern void res_clear_info(vorbis_info_residue *info);
+extern int res_unpack(vorbis_info_residue *info,
+		      vorbis_info *vi,oggpack_buffer *opb);
+extern int res_inverse(vorbis_dsp_state *,vorbis_info_residue *info,
+		       ogg_int32_t **in,int *nonzero,int ch);
+
+/* mode ************************************************************/
+typedef struct {
+  unsigned char blockflag;
+  unsigned char mapping;
+} vorbis_info_mode;
+
+/* Mapping backend generic *****************************************/
+typedef struct coupling_step{
+  unsigned char mag;
+  unsigned char ang;
+} coupling_step;
+
+typedef struct submap{
+  char floor;
+  char residue;
+} submap;
+
+typedef struct vorbis_info_mapping{
+  int            submaps; 
+  
+  unsigned char *chmuxlist;
+  submap        *submaplist;
+
+  int            coupling_steps;
+  coupling_step *coupling;
+} vorbis_info_mapping;
+
+extern int mapping_info_unpack(vorbis_info_mapping *,vorbis_info *,
+			       oggpack_buffer *);
+extern void mapping_clear_info(vorbis_info_mapping *);
+extern int mapping_inverse(struct vorbis_dsp_state *,vorbis_info_mapping *);
+
+/* codec_setup_info contains all the setup information specific to the
+   specific compression/decompression mode in progress (eg,
+   psychoacoustic settings, channel setup, options, codebook
+   etc).  
+*********************************************************************/
+
+typedef struct codec_setup_info {
+
+  /* Vorbis supports only short and long blocks, but allows the
+     encoder to choose the sizes */
+
+  long blocksizes[2];
+
+  /* modes are the primary means of supporting on-the-fly different
+     blocksizes, different channel mappings (LR or M/A),
+     different residue backends, etc.  Each mode consists of a
+     blocksize flag and a mapping (along with the mapping setup */
+
+  int        modes;
+  int        maps;
+  int        floors;
+  int        residues;
+  int        books;
+
+  vorbis_info_mode       *mode_param;
+  vorbis_info_mapping    *map_param;
+  char                   *floor_type;
+  vorbis_info_floor     **floor_param;
+  vorbis_info_residue    *residue_param;
+  codebook               *book_param;
+
+} codec_setup_info;
+
+extern vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi);
+extern void     vorbis_dsp_destroy(vorbis_dsp_state *v);
+extern int      vorbis_dsp_headerin(vorbis_info *vi,vorbis_comment *vc,
+				    ogg_packet *op);
+
+extern int      vorbis_dsp_restart(vorbis_dsp_state *v);
+extern int      vorbis_dsp_synthesis(vorbis_dsp_state *vd,
+				     ogg_packet *op,int decodep);
+extern int      vorbis_dsp_pcmout(vorbis_dsp_state *v,
+				  ogg_int16_t *pcm,int samples);
+extern int      vorbis_dsp_read(vorbis_dsp_state *v,int samples);
+extern long     vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
+
+
+
+#endif

Added: branches/theorarm-merge-branch/rjw/tremolo/ivorbiscodec.h
===================================================================
--- branches/theorarm-merge-branch/rjw/tremolo/ivorbiscodec.h	                        (rev 0)
+++ branches/theorarm-merge-branch/rjw/tremolo/ivorbiscodec.h	2010-05-30 15:45:07 UTC (rev 17259)
@@ -0,0 +1,104 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: libvorbis codec headers
+
+ ********************************************************************/
+
+#ifndef _vorbis_codec_h_
+#define _vorbis_codec_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include "ogg.h"
+
+struct vorbis_dsp_state;
+typedef struct vorbis_dsp_state vorbis_dsp_state;
+
+typedef struct vorbis_info{
+  int version;
+  int channels;
+  long rate;
+
+  /* The below bitrate declarations are *hints*.
+     Combinations of the three values carry the following implications:
+     
+     all three set to the same value: 
+       implies a fixed rate bitstream
+     only nominal set: 
+       implies a VBR stream that averages the nominal bitrate.  No hard 
+       upper/lower limit
+     upper and or lower set: 
+       implies a VBR bitstream that obeys the bitrate limits. nominal 
+       may also be set to give a nominal rate.
+     none set:
+       the coder does not care to speculate.
+  */
+
+  long bitrate_upper;
+  long bitrate_nominal;
+  long bitrate_lower;
+  long bitrate_window;
+
+  void *codec_setup;
+} vorbis_info;
+
+typedef struct vorbis_comment{
+  char **user_comments;
+  int   *comment_lengths;
+  int    comments;
+  char  *vendor;
+
+} vorbis_comment;
+
+
+/* Vorbis PRIMITIVES: general ***************************************/
+
+extern void     vorbis_info_init(vorbis_info *vi);
+extern void     vorbis_info_clear(vorbis_info *vi);
+extern int      vorbis_info_blocksize(vorbis_info *vi,int zo);
+extern void     vorbis_comment_init(vorbis_comment *vc);
+extern void     vorbis_comment_add(vorbis_comment *vc, char *comment); 
+extern void     vorbis_comment_add_tag(vorbis_comment *vc, 
+				       char *tag, char *contents);
+extern char    *vorbis_comment_query(vorbis_comment *vc, char *tag, int count);
+extern int      vorbis_comment_query_count(vorbis_comment *vc, char *tag);
+extern void     vorbis_comment_clear(vorbis_comment *vc);
+
+/* Vorbis ERRORS and return codes ***********************************/
+
+#define OV_FALSE      -1  
+#define OV_EOF        -2
+#define OV_HOLE       -3
+
+#define OV_EREAD      -128
+#define OV_EFAULT     -129
+#define OV_EIMPL      -130
+#define OV_EINVAL     -131
+#define OV_ENOTVORBIS -132
+#define OV_EBADHEADER -133
+#define OV_EVERSION   -134
+#define OV_ENOTAUDIO  -135
+#define OV_EBADPACKET -136
+#define OV_EBADLINK   -137
+#define OV_ENOSEEK    -138
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+



More information about the commits mailing list