[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