mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-23 05:58:26 +02:00
idk how i missed these files and folders
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "apiwrapper.h"
|
||||
|
||||
|
||||
|
||||
const char *theora_version_string(void){
|
||||
return th_version_string();
|
||||
}
|
||||
|
||||
ogg_uint32_t theora_version_number(void){
|
||||
return th_version_number();
|
||||
}
|
||||
|
||||
void theora_info_init(theora_info *_ci){
|
||||
memset(_ci,0,sizeof(*_ci));
|
||||
}
|
||||
|
||||
void theora_info_clear(theora_info *_ci){
|
||||
th_api_wrapper *api;
|
||||
api=(th_api_wrapper *)_ci->codec_setup;
|
||||
memset(_ci,0,sizeof(*_ci));
|
||||
if(api!=NULL){
|
||||
if(api->clear!=NULL)(*api->clear)(api);
|
||||
_ogg_free(api);
|
||||
}
|
||||
}
|
||||
|
||||
void theora_clear(theora_state *_th){
|
||||
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||
if(_th->internal_decode!=NULL){
|
||||
(*((oc_state_dispatch_vtable *)_th->internal_decode)->clear)(_th);
|
||||
}
|
||||
if(_th->internal_encode!=NULL){
|
||||
(*((oc_state_dispatch_vtable *)_th->internal_encode)->clear)(_th);
|
||||
}
|
||||
if(_th->i!=NULL)theora_info_clear(_th->i);
|
||||
memset(_th,0,sizeof(*_th));
|
||||
}
|
||||
|
||||
int theora_control(theora_state *_th,int _req,void *_buf,size_t _buf_sz){
|
||||
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||
if(_th->internal_decode!=NULL){
|
||||
return (*((oc_state_dispatch_vtable *)_th->internal_decode)->control)(_th,
|
||||
_req,_buf,_buf_sz);
|
||||
}
|
||||
else if(_th->internal_encode!=NULL){
|
||||
return (*((oc_state_dispatch_vtable *)_th->internal_encode)->control)(_th,
|
||||
_req,_buf,_buf_sz);
|
||||
}
|
||||
else return TH_EINVAL;
|
||||
}
|
||||
|
||||
ogg_int64_t theora_granule_frame(theora_state *_th,ogg_int64_t _gp){
|
||||
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||
if(_th->internal_decode!=NULL){
|
||||
return (*((oc_state_dispatch_vtable *)_th->internal_decode)->granule_frame)(
|
||||
_th,_gp);
|
||||
}
|
||||
else if(_th->internal_encode!=NULL){
|
||||
return (*((oc_state_dispatch_vtable *)_th->internal_encode)->granule_frame)(
|
||||
_th,_gp);
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
double theora_granule_time(theora_state *_th, ogg_int64_t _gp){
|
||||
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||
if(_th->internal_decode!=NULL){
|
||||
return (*((oc_state_dispatch_vtable *)_th->internal_decode)->granule_time)(
|
||||
_th,_gp);
|
||||
}
|
||||
else if(_th->internal_encode!=NULL){
|
||||
return (*((oc_state_dispatch_vtable *)_th->internal_encode)->granule_time)(
|
||||
_th,_gp);
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
void oc_theora_info2th_info(th_info *_info,const theora_info *_ci){
|
||||
_info->version_major=_ci->version_major;
|
||||
_info->version_minor=_ci->version_minor;
|
||||
_info->version_subminor=_ci->version_subminor;
|
||||
_info->frame_width=_ci->width;
|
||||
_info->frame_height=_ci->height;
|
||||
_info->pic_width=_ci->frame_width;
|
||||
_info->pic_height=_ci->frame_height;
|
||||
_info->pic_x=_ci->offset_x;
|
||||
_info->pic_y=_ci->offset_y;
|
||||
_info->fps_numerator=_ci->fps_numerator;
|
||||
_info->fps_denominator=_ci->fps_denominator;
|
||||
_info->aspect_numerator=_ci->aspect_numerator;
|
||||
_info->aspect_denominator=_ci->aspect_denominator;
|
||||
switch(_ci->colorspace){
|
||||
case OC_CS_ITU_REC_470M:_info->colorspace=TH_CS_ITU_REC_470M;break;
|
||||
case OC_CS_ITU_REC_470BG:_info->colorspace=TH_CS_ITU_REC_470BG;break;
|
||||
default:_info->colorspace=TH_CS_UNSPECIFIED;break;
|
||||
}
|
||||
switch(_ci->pixelformat){
|
||||
case OC_PF_420:_info->pixel_fmt=TH_PF_420;break;
|
||||
case OC_PF_422:_info->pixel_fmt=TH_PF_422;break;
|
||||
case OC_PF_444:_info->pixel_fmt=TH_PF_444;break;
|
||||
default:_info->pixel_fmt=TH_PF_RSVD;
|
||||
}
|
||||
_info->target_bitrate=_ci->target_bitrate;
|
||||
_info->quality=_ci->quality;
|
||||
_info->keyframe_granule_shift=_ci->keyframe_frequency_force>0?
|
||||
OC_MINI(31,oc_ilog(_ci->keyframe_frequency_force-1)):0;
|
||||
}
|
||||
|
||||
int theora_packet_isheader(ogg_packet *_op){
|
||||
return th_packet_isheader(_op);
|
||||
}
|
||||
|
||||
int theora_packet_iskeyframe(ogg_packet *_op){
|
||||
return th_packet_iskeyframe(_op);
|
||||
}
|
||||
|
||||
int theora_granule_shift(theora_info *_ci){
|
||||
/*This breaks when keyframe_frequency_force is not positive or is larger than
|
||||
2**31 (if your int is more than 32 bits), but that's what the original
|
||||
function does.*/
|
||||
return oc_ilog(_ci->keyframe_frequency_force-1);
|
||||
}
|
||||
|
||||
void theora_comment_init(theora_comment *_tc){
|
||||
th_comment_init((th_comment *)_tc);
|
||||
}
|
||||
|
||||
char *theora_comment_query(theora_comment *_tc,char *_tag,int _count){
|
||||
return th_comment_query((th_comment *)_tc,_tag,_count);
|
||||
}
|
||||
|
||||
int theora_comment_query_count(theora_comment *_tc,char *_tag){
|
||||
return th_comment_query_count((th_comment *)_tc,_tag);
|
||||
}
|
||||
|
||||
void theora_comment_clear(theora_comment *_tc){
|
||||
th_comment_clear((th_comment *)_tc);
|
||||
}
|
||||
|
||||
void theora_comment_add(theora_comment *_tc,char *_comment){
|
||||
th_comment_add((th_comment *)_tc,_comment);
|
||||
}
|
||||
|
||||
void theora_comment_add_tag(theora_comment *_tc, char *_tag, char *_value){
|
||||
th_comment_add_tag((th_comment *)_tc,_tag,_value);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: apiwrapper.h 13596 2007-08-23 20:05:38Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_apiwrapper_H)
|
||||
# define _apiwrapper_H (1)
|
||||
# include <ogg/ogg.h>
|
||||
# include <theora/theora.h>
|
||||
# include "theora/theoradec.h"
|
||||
# include "theora/theoraenc.h"
|
||||
# include "state.h"
|
||||
|
||||
typedef struct th_api_wrapper th_api_wrapper;
|
||||
typedef struct th_api_info th_api_info;
|
||||
|
||||
/*Provide an entry point for the codec setup to clear itself in case we ever
|
||||
want to break pieces off into a common base library shared by encoder and
|
||||
decoder.
|
||||
In addition, this makes several other pieces of the API wrapper cleaner.*/
|
||||
typedef void (*oc_setup_clear_func)(void *_ts);
|
||||
|
||||
/*Generally only one of these pointers will be non-NULL in any given instance.
|
||||
Technically we do not even really need this struct, since we should be able
|
||||
to figure out which one from "context", but doing it this way makes sure we
|
||||
don't flub it up.*/
|
||||
struct th_api_wrapper{
|
||||
oc_setup_clear_func clear;
|
||||
th_setup_info *setup;
|
||||
th_dec_ctx *decode;
|
||||
th_enc_ctx *encode;
|
||||
};
|
||||
|
||||
struct th_api_info{
|
||||
th_api_wrapper api;
|
||||
theora_info info;
|
||||
};
|
||||
|
||||
|
||||
void oc_theora_info2th_info(th_info *_info,const theora_info *_ci);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,271 @@
|
||||
#!/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 there's nothing on a line but a comment, don't try to apply any further
|
||||
# substitutions (this is a cheap hack to avoid mucking up the license header)
|
||||
s/^([ \t]*);/$1@/ && 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 \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/;
|
||||
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/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/;
|
||||
s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/;
|
||||
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/ALIGN\s+([0-9x]+)$/.balign $1/;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2010 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: x86int.h 17344 2010-07-21 01:42:18Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_arm_armbits_H)
|
||||
# define _arm_armbits_H (1)
|
||||
# include "../bitpack.h"
|
||||
# include "armcpu.h"
|
||||
|
||||
# if defined(OC_ARM_ASM)
|
||||
# define oc_pack_read oc_pack_read_arm
|
||||
# define oc_pack_read1 oc_pack_read1_arm
|
||||
# define oc_huff_token_decode oc_huff_token_decode_arm
|
||||
# endif
|
||||
|
||||
long oc_pack_read_arm(oc_pack_buf *_b,int _bits);
|
||||
int oc_pack_read1_arm(oc_pack_buf *_b);
|
||||
int oc_huff_token_decode_arm(oc_pack_buf *_b,const ogg_int16_t *_tree);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,227 @@
|
||||
;********************************************************************
|
||||
;* *
|
||||
;* 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-2010 *
|
||||
;* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
;* *
|
||||
;********************************************************************
|
||||
;
|
||||
; function:
|
||||
; last mod: $Id$
|
||||
;
|
||||
;********************************************************************
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
EXPORT oc_pack_read_arm
|
||||
EXPORT oc_pack_read1_arm
|
||||
EXPORT oc_huff_token_decode_arm
|
||||
|
||||
oc_pack_read_arm
|
||||
; r0 = oc_pack_buf *_b
|
||||
; r1 = int _bits
|
||||
ADD r12,r0,#8
|
||||
LDMIA r12,{r2,r3} ; r2 = window
|
||||
; Stall... ; r3 = available
|
||||
; Stall...
|
||||
SUBS r3,r3,r1 ; r3 = available-_bits, available<_bits => LT
|
||||
BLT oc_pack_read_refill
|
||||
RSB r0,r1,#32 ; r0 = 32-_bits
|
||||
MOV r0,r2,LSR r0 ; r0 = window>>32-_bits
|
||||
MOV r2,r2,LSL r1 ; r2 = window<<=_bits
|
||||
STMIA r12,{r2,r3} ; window = r2
|
||||
; available = r3
|
||||
MOV PC,r14
|
||||
|
||||
oc_pack_read1_arm
|
||||
; r0 = oc_pack_buf *_b
|
||||
ADD r12,r0,#8
|
||||
LDMIA r12,{r2,r3} ; r2 = window
|
||||
; Stall... ; r3 = available
|
||||
; Stall...
|
||||
SUBS r3,r3,#1 ; r3 = available-1, available<1 => LT
|
||||
BLT oc_pack_read1_refill
|
||||
MOV r0,r2,LSR #31 ; r0 = window>>31
|
||||
MOV r2,r2,LSL #1 ; r2 = window<<=1
|
||||
STMIA r12,{r2,r3} ; window = r2
|
||||
; available = r3
|
||||
MOV PC,r14
|
||||
|
||||
; We need to refill window.
|
||||
oc_pack_read1_refill
|
||||
MOV r1,#1
|
||||
oc_pack_read_refill
|
||||
STMFD r13!,{r10,r11,r14}
|
||||
LDMIA r0,{r10,r11} ; r10 = stop
|
||||
; r11 = ptr
|
||||
RSB r0,r1,#32 ; r0 = 32-_bits
|
||||
RSB r3,r3,r0 ; r3 = 32-available
|
||||
; We can use unsigned compares for both the pointers and for available
|
||||
; (allowing us to chain condition codes) because available will never be
|
||||
; larger than 32 (or we wouldn't be here), and thus 32-available will never be
|
||||
; negative.
|
||||
CMP r10,r11 ; ptr<stop => HI
|
||||
CMPHI r3,#7 ; available<=24 => HI
|
||||
LDRHIB r14,[r11],#1 ; r14 = *ptr++
|
||||
SUBHI r3,#8 ; available += 8
|
||||
; (HI) Stall...
|
||||
ORRHI r2,r14,LSL r3 ; r2 = window|=r14<<32-available
|
||||
CMPHI r10,r11 ; ptr<stop => HI
|
||||
CMPHI r3,#7 ; available<=24 => HI
|
||||
LDRHIB r14,[r11],#1 ; r14 = *ptr++
|
||||
SUBHI r3,#8 ; available += 8
|
||||
; (HI) Stall...
|
||||
ORRHI r2,r14,LSL r3 ; r2 = window|=r14<<32-available
|
||||
CMPHI r10,r11 ; ptr<stop => HI
|
||||
CMPHI r3,#7 ; available<=24 => HI
|
||||
LDRHIB r14,[r11],#1 ; r14 = *ptr++
|
||||
SUBHI r3,#8 ; available += 8
|
||||
; (HI) Stall...
|
||||
ORRHI r2,r14,LSL r3 ; r2 = window|=r14<<32-available
|
||||
CMPHI r10,r11 ; ptr<stop => HI
|
||||
CMPHI r3,#7 ; available<=24 => HI
|
||||
LDRHIB r14,[r11],#1 ; r14 = *ptr++
|
||||
SUBHI r3,#8 ; available += 8
|
||||
; (HI) Stall...
|
||||
ORRHI r2,r14,LSL r3 ; r2 = window|=r14<<32-available
|
||||
SUBS r3,r0,r3 ; r3 = available-=_bits, available<bits => GT
|
||||
BLT oc_pack_read_refill_last
|
||||
MOV r0,r2,LSR r0 ; r0 = window>>32-_bits
|
||||
MOV r2,r2,LSL r1 ; r2 = window<<=_bits
|
||||
STR r11,[r12,#-4] ; ptr = r11
|
||||
STMIA r12,{r2,r3} ; window = r2
|
||||
; available = r3
|
||||
LDMFD r13!,{r10,r11,PC}
|
||||
|
||||
; Either we wanted to read more than 24 bits and didn't have enough room to
|
||||
; stuff the last byte into the window, or we hit the end of the packet.
|
||||
oc_pack_read_refill_last
|
||||
CMP r11,r10 ; ptr<stop => LO
|
||||
; If we didn't hit the end of the packet, then pull enough of the next byte to
|
||||
; to fill up the window.
|
||||
LDRLOB r14,[r11] ; (LO) r14 = *ptr
|
||||
; Otherwise, set the EOF flag and pretend we have lots of available bits.
|
||||
MOVHS r14,#1 ; (HS) r14 = 1
|
||||
ADDLO r10,r3,r1 ; (LO) r10 = available
|
||||
STRHS r14,[r12,#8] ; (HS) eof = 1
|
||||
ANDLO r10,r10,#7 ; (LO) r10 = available&7
|
||||
MOVHS r3,#1<<30 ; (HS) available = OC_LOTS_OF_BITS
|
||||
ORRLO r2,r14,LSL r10 ; (LO) r2 = window|=*ptr>>(available&7)
|
||||
MOV r0,r2,LSR r0 ; r0 = window>>32-_bits
|
||||
MOV r2,r2,LSL r1 ; r2 = window<<=_bits
|
||||
STR r11,[r12,#-4] ; ptr = r11
|
||||
STMIA r12,{r2,r3} ; window = r2
|
||||
; available = r3
|
||||
LDMFD r13!,{r10,r11,PC}
|
||||
|
||||
|
||||
|
||||
oc_huff_token_decode_arm
|
||||
; r0 = oc_pack_buf *_b
|
||||
; r1 = const ogg_int16_t *_tree
|
||||
STMFD r13!,{r4,r5,r10,r14}
|
||||
LDRSH r10,[r1] ; r10 = n=_tree[0]
|
||||
LDMIA r0,{r2-r5} ; r2 = stop
|
||||
; Stall... ; r3 = ptr
|
||||
; Stall... ; r4 = window
|
||||
; r5 = available
|
||||
CMP r10,r5 ; n>available => GT
|
||||
BGT oc_huff_token_decode_refill0
|
||||
RSB r14,r10,#32 ; r14 = 32-n
|
||||
MOV r14,r4,LSR r14 ; r14 = bits=window>>32-n
|
||||
ADD r14,r1,r14,LSL #1 ; r14 = _tree+bits
|
||||
LDRSH r12,[r14,#2] ; r12 = node=_tree[1+bits]
|
||||
; Stall...
|
||||
; Stall...
|
||||
RSBS r14,r12,#0 ; r14 = -node, node>0 => MI
|
||||
BMI oc_huff_token_decode_continue
|
||||
MOV r10,r14,LSR #8 ; r10 = n=node>>8
|
||||
MOV r4,r4,LSL r10 ; r4 = window<<=n
|
||||
SUB r5,r10 ; r5 = available-=n
|
||||
STMIB r0,{r3-r5} ; ptr = r3
|
||||
; window = r4
|
||||
; available = r5
|
||||
AND r0,r14,#255 ; r0 = node&255
|
||||
LDMFD r13!,{r4,r5,r10,pc}
|
||||
|
||||
; The first tree node wasn't enough to reach a leaf, read another
|
||||
oc_huff_token_decode_continue
|
||||
ADD r12,r1,r12,LSL #1 ; r12 = _tree+node
|
||||
MOV r4,r4,LSL r10 ; r4 = window<<=n
|
||||
SUB r5,r5,r10 ; r5 = available-=n
|
||||
LDRSH r10,[r12],#2 ; r10 = n=_tree[node]
|
||||
; Stall... ; r12 = _tree+node+1
|
||||
; Stall...
|
||||
CMP r10,r5 ; n>available => GT
|
||||
BGT oc_huff_token_decode_refill
|
||||
RSB r14,r10,#32 ; r14 = 32-n
|
||||
MOV r14,r4,LSR r14 ; r14 = bits=window>>32-n
|
||||
ADD r12,r12,r14 ;
|
||||
LDRSH r12,[r12,r14] ; r12 = node=_tree[node+1+bits]
|
||||
; Stall...
|
||||
; Stall...
|
||||
RSBS r14,r12,#0 ; r14 = -node, node>0 => MI
|
||||
BMI oc_huff_token_decode_continue
|
||||
MOV r10,r14,LSR #8 ; r10 = n=node>>8
|
||||
MOV r4,r4,LSL r10 ; r4 = window<<=n
|
||||
SUB r5,r10 ; r5 = available-=n
|
||||
STMIB r0,{r3-r5} ; ptr = r3
|
||||
; window = r4
|
||||
; available = r5
|
||||
AND r0,r14,#255 ; r0 = node&255
|
||||
LDMFD r13!,{r4,r5,r10,pc}
|
||||
|
||||
oc_huff_token_decode_refill0
|
||||
ADD r12,r1,#2 ; r12 = _tree+1
|
||||
oc_huff_token_decode_refill
|
||||
; We can't possibly need more than 15 bits, so available must be <= 15.
|
||||
; Therefore we can load at least two bytes without checking it.
|
||||
CMP r2,r3 ; ptr<stop => HI
|
||||
LDRHIB r14,[r3],#1 ; r14 = *ptr++
|
||||
RSBHI r5,r5,#24 ; (HI) available = 32-(available+=8)
|
||||
RSBLS r5,r5,#32 ; (LS) r5 = 32-available
|
||||
ORRHI r4,r14,LSL r5 ; r4 = window|=r14<<32-available
|
||||
CMPHI r2,r3 ; ptr<stop => HI
|
||||
LDRHIB r14,[r3],#1 ; r14 = *ptr++
|
||||
SUBHI r5,#8 ; available += 8
|
||||
; (HI) Stall...
|
||||
ORRHI r4,r14,LSL r5 ; r4 = window|=r14<<32-available
|
||||
; We can use unsigned compares for both the pointers and for available
|
||||
; (allowing us to chain condition codes) because available will never be
|
||||
; larger than 32 (or we wouldn't be here), and thus 32-available will never be
|
||||
; negative.
|
||||
CMPHI r2,r3 ; ptr<stop => HI
|
||||
CMPHI r5,#7 ; available<=24 => HI
|
||||
LDRHIB r14,[r3],#1 ; r14 = *ptr++
|
||||
SUBHI r5,#8 ; available += 8
|
||||
; (HI) Stall...
|
||||
ORRHI r4,r14,LSL r5 ; r4 = window|=r14<<32-available
|
||||
CMP r2,r3 ; ptr<stop => HI
|
||||
MOVLS r5,#-1<<30 ; (LS) available = OC_LOTS_OF_BITS+32
|
||||
CMPHI r5,#7 ; (HI) available<=24 => HI
|
||||
LDRHIB r14,[r3],#1 ; (HI) r14 = *ptr++
|
||||
SUBHI r5,#8 ; (HI) available += 8
|
||||
; (HI) Stall...
|
||||
ORRHI r4,r14,LSL r5 ; (HI) r4 = window|=r14<<32-available
|
||||
RSB r14,r10,#32 ; r14 = 32-n
|
||||
MOV r14,r4,LSR r14 ; r14 = bits=window>>32-n
|
||||
ADD r12,r12,r14 ;
|
||||
LDRSH r12,[r12,r14] ; r12 = node=_tree[node+1+bits]
|
||||
RSB r5,r5,#32 ; r5 = available
|
||||
; Stall...
|
||||
RSBS r14,r12,#0 ; r14 = -node, node>0 => MI
|
||||
BMI oc_huff_token_decode_continue
|
||||
MOV r10,r14,LSR #8 ; r10 = n=node>>8
|
||||
MOV r4,r4,LSL r10 ; r4 = window<<=n
|
||||
SUB r5,r10 ; r5 = available-=n
|
||||
STMIB r0,{r3-r5} ; ptr = r3
|
||||
; window = r4
|
||||
; available = r5
|
||||
AND r0,r14,#255 ; r0 = node&255
|
||||
LDMFD r13!,{r4,r5,r10,pc}
|
||||
|
||||
END
|
||||
@@ -0,0 +1,116 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2010 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
CPU capability detection for ARM processors.
|
||||
|
||||
function:
|
||||
last mod: $Id: cpu.c 17344 2010-07-21 01:42:18Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include "armcpu.h"
|
||||
|
||||
#if !defined(OC_ARM_ASM)|| \
|
||||
!defined(OC_ARM_ASM_EDSP)&&!defined(OC_ARM_ASM_ARMV6)&& \
|
||||
!defined(OC_ARM_ASM_NEON)
|
||||
ogg_uint32_t oc_cpu_flags_get(void){
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_EXTRA_LEAN
|
||||
# include <windows.h>
|
||||
|
||||
ogg_uint32_t oc_cpu_flags_get(void){
|
||||
ogg_uint32_t flags;
|
||||
flags=0;
|
||||
/*MSVC has no inline __asm support for ARM, but it does let you __emit
|
||||
instructions via their assembled hex code.
|
||||
All of these instructions should be essentially nops.*/
|
||||
# if defined(OC_ARM_ASM_EDSP)
|
||||
__try{
|
||||
/*PLD [r13]*/
|
||||
__emit(0xF5DDF000);
|
||||
flags|=OC_CPU_ARM_EDSP;
|
||||
}
|
||||
__except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
|
||||
/*Ignore exception.*/
|
||||
}
|
||||
# if defined(OC_ARM_ASM_MEDIA)
|
||||
__try{
|
||||
/*SHADD8 r3,r3,r3*/
|
||||
__emit(0xE6333F93);
|
||||
flags|=OC_CPU_ARM_MEDIA;
|
||||
}
|
||||
__except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
|
||||
/*Ignore exception.*/
|
||||
}
|
||||
# if defined(OC_ARM_ASM_NEON)
|
||||
__try{
|
||||
/*VORR q0,q0,q0*/
|
||||
__emit(0xF2200150);
|
||||
flags|=OC_CPU_ARM_NEON;
|
||||
}
|
||||
__except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
|
||||
/*Ignore exception.*/
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
ogg_uint32_t oc_cpu_flags_get(void){
|
||||
ogg_uint32_t flags;
|
||||
FILE *fin;
|
||||
flags=0;
|
||||
/*Reading /proc/self/auxv would be easier, but that doesn't work reliably on
|
||||
Android.
|
||||
This also means that detection will fail in Scratchbox.*/
|
||||
fin=fopen("/proc/cpuinfo","r");
|
||||
if(fin!=NULL){
|
||||
/*512 should be enough for anybody (it's even enough for all the flags that
|
||||
x86 has accumulated... so far).*/
|
||||
char buf[512];
|
||||
while(fgets(buf,511,fin)!=NULL){
|
||||
if(memcmp(buf,"Features",8)==0){
|
||||
char *p;
|
||||
p=strstr(buf," edsp");
|
||||
if(p!=NULL&&(p[5]==' '||p[5]=='\n'))flags|=OC_CPU_ARM_EDSP;
|
||||
p=strstr(buf," neon");
|
||||
if(p!=NULL&&(p[5]==' '||p[5]=='\n'))flags|=OC_CPU_ARM_NEON;
|
||||
}
|
||||
if(memcmp(buf,"CPU architecture:",17)==0){
|
||||
int version;
|
||||
version=atoi(buf+17);
|
||||
if(version>=6)flags|=OC_CPU_ARM_MEDIA;
|
||||
}
|
||||
}
|
||||
fclose(fin);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
#else
|
||||
/*The feature registers which can tell us what the processor supports are
|
||||
accessible in priveleged modes only, so we can't have a general user-space
|
||||
detection method like on x86.*/
|
||||
# error "Configured to use ARM asm but no CPU detection method available for " \
|
||||
"your platform. Reconfigure with --disable-asm (or send patches)."
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2010 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
function:
|
||||
last mod: $Id: cpu.h 17344 2010-07-21 01:42:18Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_arm_armcpu_H)
|
||||
# define _arm_armcpu_H (1)
|
||||
#include "../internal.h"
|
||||
|
||||
/*"Parallel instructions" from ARM v6 and above.*/
|
||||
#define OC_CPU_ARM_MEDIA (1<<24)
|
||||
/*Flags chosen to match arch/arm/include/asm/hwcap.h in the Linux kernel.*/
|
||||
#define OC_CPU_ARM_EDSP (1<<7)
|
||||
#define OC_CPU_ARM_NEON (1<<12)
|
||||
|
||||
ogg_uint32_t oc_cpu_flags_get(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2010 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: x86state.c 17344 2010-07-21 01:42:18Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
#include "armenc.h"
|
||||
|
||||
#if defined(OC_ARM_ASM)
|
||||
|
||||
void oc_enc_accel_init_arm(oc_enc_ctx *_enc){
|
||||
ogg_uint32_t cpu_flags;
|
||||
cpu_flags=_enc->state.cpu_flags;
|
||||
oc_enc_accel_init_c(_enc);
|
||||
# if defined(OC_ENC_USE_VTABLE)
|
||||
/*TODO: Add ARMv4 functions here.*/
|
||||
# endif
|
||||
# if defined(OC_ARM_ASM_EDSP)
|
||||
if(cpu_flags&OC_CPU_ARM_EDSP){
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
/*TODO: Add EDSP functions here.*/
|
||||
# endif
|
||||
}
|
||||
# if defined(OC_ARM_ASM_MEDIA)
|
||||
if(cpu_flags&OC_CPU_ARM_MEDIA){
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
/*TODO: Add Media functions here.*/
|
||||
# endif
|
||||
}
|
||||
# if defined(OC_ARM_ASM_NEON)
|
||||
if(cpu_flags&OC_CPU_ARM_NEON){
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
_enc->opt_vtable.frag_satd=oc_enc_frag_satd_neon;
|
||||
_enc->opt_vtable.frag_satd2=oc_enc_frag_satd2_neon;
|
||||
_enc->opt_vtable.frag_intra_satd=oc_enc_frag_intra_satd_neon;
|
||||
_enc->opt_vtable.enquant_table_init=oc_enc_enquant_table_init_neon;
|
||||
_enc->opt_vtable.enquant_table_fixup=oc_enc_enquant_table_fixup_neon;
|
||||
_enc->opt_vtable.quantize=oc_enc_quantize_neon;
|
||||
# endif
|
||||
_enc->opt_data.enquant_table_size=128*sizeof(ogg_uint16_t);
|
||||
_enc->opt_data.enquant_table_alignment=16;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2010 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: x86int.h 17344 2010-07-21 01:42:18Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_arm_armenc_H)
|
||||
# define _arm_armenc_H (1)
|
||||
# include "armint.h"
|
||||
|
||||
# if defined(OC_ARM_ASM)
|
||||
# define oc_enc_accel_init oc_enc_accel_init_arm
|
||||
# define OC_ENC_USE_VTABLE (1)
|
||||
# endif
|
||||
|
||||
# include "../encint.h"
|
||||
|
||||
# if defined(OC_ARM_ASM)
|
||||
void oc_enc_accel_init_arm(oc_enc_ctx *_enc);
|
||||
|
||||
# if defined(OC_ARM_ASM_EDSP)
|
||||
# if defined(OC_ARM_ASM_MEDIA)
|
||||
# if defined(OC_ARM_ASM_NEON)
|
||||
unsigned oc_enc_frag_satd_neon(int *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_satd2_neon(int *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride);
|
||||
unsigned oc_enc_frag_intra_satd_neon(int *_dc,
|
||||
const unsigned char *_src,int _ystride);
|
||||
|
||||
void oc_enc_enquant_table_init_neon(void *_enquant,
|
||||
const ogg_uint16_t _dequant[64]);
|
||||
void oc_enc_enquant_table_fixup_neon(void *_enquant[3][3][2],int _nqis);
|
||||
int oc_enc_quantize_neon(ogg_int16_t _qdct[64],const ogg_int16_t _dct[64],
|
||||
const ogg_uint16_t _dequant[64],const void *_enquant);
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,645 @@
|
||||
;********************************************************************
|
||||
;* *
|
||||
;* 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-2010 *
|
||||
;* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
;* *
|
||||
;********************************************************************
|
||||
; Original implementation:
|
||||
; Copyright (C) 2009 Robin Watts for Pinknoise Productions Ltd
|
||||
; last mod: $Id$
|
||||
;********************************************************************
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
GET armopts.s
|
||||
|
||||
; Vanilla ARM v4 versions
|
||||
EXPORT oc_frag_copy_list_arm
|
||||
EXPORT oc_frag_recon_intra_arm
|
||||
EXPORT oc_frag_recon_inter_arm
|
||||
EXPORT oc_frag_recon_inter2_arm
|
||||
|
||||
oc_frag_copy_list_arm
|
||||
; r0 = _dst_frame
|
||||
; r1 = _src_frame
|
||||
; r2 = _ystride
|
||||
; r3 = _fragis
|
||||
; <> = _nfragis
|
||||
; <> = _frag_buf_offs
|
||||
LDR r12,[r13] ; r12 = _nfragis
|
||||
STMFD r13!,{r4-r6,r11,r14}
|
||||
SUBS r12, r12, #1
|
||||
LDR r4,[r3],#4 ; r4 = _fragis[fragii]
|
||||
LDRGE r14,[r13,#4*6] ; r14 = _frag_buf_offs
|
||||
BLT ofcl_arm_end
|
||||
SUB r2, r2, #4
|
||||
ofcl_arm_lp
|
||||
LDR r11,[r14,r4,LSL #2] ; r11 = _frag_buf_offs[_fragis[fragii]]
|
||||
SUBS r12, r12, #1
|
||||
; Stall (on XScale)
|
||||
ADD r4, r1, r11 ; r4 = _src_frame+frag_buf_off
|
||||
LDR r6, [r4], #4
|
||||
ADD r11,r0, r11 ; r11 = _dst_frame+frag_buf_off
|
||||
LDR r5, [r4], r2
|
||||
STR r6, [r11],#4
|
||||
LDR r6, [r4], #4
|
||||
STR r5, [r11],r2
|
||||
LDR r5, [r4], r2
|
||||
STR r6, [r11],#4
|
||||
LDR r6, [r4], #4
|
||||
STR r5, [r11],r2
|
||||
LDR r5, [r4], r2
|
||||
STR r6, [r11],#4
|
||||
LDR r6, [r4], #4
|
||||
STR r5, [r11],r2
|
||||
LDR r5, [r4], r2
|
||||
STR r6, [r11],#4
|
||||
LDR r6, [r4], #4
|
||||
STR r5, [r11],r2
|
||||
LDR r5, [r4], r2
|
||||
STR r6, [r11],#4
|
||||
LDR r6, [r4], #4
|
||||
STR r5, [r11],r2
|
||||
LDR r5, [r4], r2
|
||||
STR r6, [r11],#4
|
||||
LDR r6, [r4], #4
|
||||
STR r5, [r11],r2
|
||||
LDR r5, [r4], r2
|
||||
STR r6, [r11],#4
|
||||
LDR r6, [r4], #4
|
||||
STR r5, [r11],r2
|
||||
LDR r5, [r4]
|
||||
LDRGE r4,[r3],#4 ; r4 = _fragis[fragii]
|
||||
STR r6, [r11],#4
|
||||
STR r5, [r11]
|
||||
BGE ofcl_arm_lp
|
||||
ofcl_arm_end
|
||||
LDMFD r13!,{r4-r6,r11,PC}
|
||||
oc_frag_recon_intra_arm
|
||||
; r0 = unsigned char *_dst
|
||||
; r1 = int _ystride
|
||||
; r2 = const ogg_int16_t _residue[64]
|
||||
STMFD r13!,{r4,r5,r14}
|
||||
MOV r14,#8
|
||||
MOV r5, #255
|
||||
SUB r1, r1, #7
|
||||
ofrintra_lp_arm
|
||||
LDRSH r3, [r2], #2
|
||||
LDRSH r4, [r2], #2
|
||||
LDRSH r12,[r2], #2
|
||||
ADDS r3, r3, #128
|
||||
CMPGT r5, r3
|
||||
EORLT r3, r5, r3, ASR #32
|
||||
STRB r3, [r0], #1
|
||||
ADDS r4, r4, #128
|
||||
CMPGT r5, r4
|
||||
EORLT r4, r5, r4, ASR #32
|
||||
LDRSH r3, [r2], #2
|
||||
STRB r4, [r0], #1
|
||||
ADDS r12,r12,#128
|
||||
CMPGT r5, r12
|
||||
EORLT r12,r5, r12,ASR #32
|
||||
LDRSH r4, [r2], #2
|
||||
STRB r12,[r0], #1
|
||||
ADDS r3, r3, #128
|
||||
CMPGT r5, r3
|
||||
EORLT r3, r5, r3, ASR #32
|
||||
LDRSH r12,[r2], #2
|
||||
STRB r3, [r0], #1
|
||||
ADDS r4, r4, #128
|
||||
CMPGT r5, r4
|
||||
EORLT r4, r5, r4, ASR #32
|
||||
LDRSH r3, [r2], #2
|
||||
STRB r4, [r0], #1
|
||||
ADDS r12,r12,#128
|
||||
CMPGT r5, r12
|
||||
EORLT r12,r5, r12,ASR #32
|
||||
LDRSH r4, [r2], #2
|
||||
STRB r12,[r0], #1
|
||||
ADDS r3, r3, #128
|
||||
CMPGT r5, r3
|
||||
EORLT r3, r5, r3, ASR #32
|
||||
STRB r3, [r0], #1
|
||||
ADDS r4, r4, #128
|
||||
CMPGT r5, r4
|
||||
EORLT r4, r5, r4, ASR #32
|
||||
STRB r4, [r0], r1
|
||||
SUBS r14,r14,#1
|
||||
BGT ofrintra_lp_arm
|
||||
LDMFD r13!,{r4,r5,PC}
|
||||
|
||||
oc_frag_recon_inter_arm
|
||||
; r0 = unsigned char *dst
|
||||
; r1 = const unsigned char *src
|
||||
; r2 = int ystride
|
||||
; r3 = const ogg_int16_t residue[64]
|
||||
STMFD r13!,{r5,r9-r11,r14}
|
||||
MOV r9, #8
|
||||
MOV r5, #255
|
||||
SUB r2, r2, #7
|
||||
ofrinter_lp_arm
|
||||
LDRSH r12,[r3], #2
|
||||
LDRB r14,[r1], #1
|
||||
LDRSH r11,[r3], #2
|
||||
LDRB r10,[r1], #1
|
||||
ADDS r12,r12,r14
|
||||
CMPGT r5, r12
|
||||
EORLT r12,r5, r12,ASR #32
|
||||
STRB r12,[r0], #1
|
||||
ADDS r11,r11,r10
|
||||
CMPGT r5, r11
|
||||
LDRSH r12,[r3], #2
|
||||
LDRB r14,[r1], #1
|
||||
EORLT r11,r5, r11,ASR #32
|
||||
STRB r11,[r0], #1
|
||||
ADDS r12,r12,r14
|
||||
CMPGT r5, r12
|
||||
LDRSH r11,[r3], #2
|
||||
LDRB r10,[r1], #1
|
||||
EORLT r12,r5, r12,ASR #32
|
||||
STRB r12,[r0], #1
|
||||
ADDS r11,r11,r10
|
||||
CMPGT r5, r11
|
||||
LDRSH r12,[r3], #2
|
||||
LDRB r14,[r1], #1
|
||||
EORLT r11,r5, r11,ASR #32
|
||||
STRB r11,[r0], #1
|
||||
ADDS r12,r12,r14
|
||||
CMPGT r5, r12
|
||||
LDRSH r11,[r3], #2
|
||||
LDRB r10,[r1], #1
|
||||
EORLT r12,r5, r12,ASR #32
|
||||
STRB r12,[r0], #1
|
||||
ADDS r11,r11,r10
|
||||
CMPGT r5, r11
|
||||
LDRSH r12,[r3], #2
|
||||
LDRB r14,[r1], #1
|
||||
EORLT r11,r5, r11,ASR #32
|
||||
STRB r11,[r0], #1
|
||||
ADDS r12,r12,r14
|
||||
CMPGT r5, r12
|
||||
LDRSH r11,[r3], #2
|
||||
LDRB r10,[r1], r2
|
||||
EORLT r12,r5, r12,ASR #32
|
||||
STRB r12,[r0], #1
|
||||
ADDS r11,r11,r10
|
||||
CMPGT r5, r11
|
||||
EORLT r11,r5, r11,ASR #32
|
||||
STRB r11,[r0], r2
|
||||
SUBS r9, r9, #1
|
||||
BGT ofrinter_lp_arm
|
||||
LDMFD r13!,{r5,r9-r11,PC}
|
||||
|
||||
oc_frag_recon_inter2_arm
|
||||
; r0 = unsigned char *dst
|
||||
; r1 = const unsigned char *src1
|
||||
; r2 = const unsigned char *src2
|
||||
; r3 = int ystride
|
||||
LDR r12,[r13]
|
||||
; r12= const ogg_int16_t residue[64]
|
||||
STMFD r13!,{r4-r8,r14}
|
||||
MOV r14,#8
|
||||
MOV r8, #255
|
||||
SUB r3, r3, #7
|
||||
ofrinter2_lp_arm
|
||||
LDRB r5, [r1], #1
|
||||
LDRB r6, [r2], #1
|
||||
LDRSH r4, [r12],#2
|
||||
LDRB r7, [r1], #1
|
||||
ADD r5, r5, r6
|
||||
ADDS r5, r4, r5, LSR #1
|
||||
CMPGT r8, r5
|
||||
LDRB r6, [r2], #1
|
||||
LDRSH r4, [r12],#2
|
||||
EORLT r5, r8, r5, ASR #32
|
||||
STRB r5, [r0], #1
|
||||
ADD r7, r7, r6
|
||||
ADDS r7, r4, r7, LSR #1
|
||||
CMPGT r8, r7
|
||||
LDRB r5, [r1], #1
|
||||
LDRB r6, [r2], #1
|
||||
LDRSH r4, [r12],#2
|
||||
EORLT r7, r8, r7, ASR #32
|
||||
STRB r7, [r0], #1
|
||||
ADD r5, r5, r6
|
||||
ADDS r5, r4, r5, LSR #1
|
||||
CMPGT r8, r5
|
||||
LDRB r7, [r1], #1
|
||||
LDRB r6, [r2], #1
|
||||
LDRSH r4, [r12],#2
|
||||
EORLT r5, r8, r5, ASR #32
|
||||
STRB r5, [r0], #1
|
||||
ADD r7, r7, r6
|
||||
ADDS r7, r4, r7, LSR #1
|
||||
CMPGT r8, r7
|
||||
LDRB r5, [r1], #1
|
||||
LDRB r6, [r2], #1
|
||||
LDRSH r4, [r12],#2
|
||||
EORLT r7, r8, r7, ASR #32
|
||||
STRB r7, [r0], #1
|
||||
ADD r5, r5, r6
|
||||
ADDS r5, r4, r5, LSR #1
|
||||
CMPGT r8, r5
|
||||
LDRB r7, [r1], #1
|
||||
LDRB r6, [r2], #1
|
||||
LDRSH r4, [r12],#2
|
||||
EORLT r5, r8, r5, ASR #32
|
||||
STRB r5, [r0], #1
|
||||
ADD r7, r7, r6
|
||||
ADDS r7, r4, r7, LSR #1
|
||||
CMPGT r8, r7
|
||||
LDRB r5, [r1], #1
|
||||
LDRB r6, [r2], #1
|
||||
LDRSH r4, [r12],#2
|
||||
EORLT r7, r8, r7, ASR #32
|
||||
STRB r7, [r0], #1
|
||||
ADD r5, r5, r6
|
||||
ADDS r5, r4, r5, LSR #1
|
||||
CMPGT r8, r5
|
||||
LDRB r7, [r1], r3
|
||||
LDRB r6, [r2], r3
|
||||
LDRSH r4, [r12],#2
|
||||
EORLT r5, r8, r5, ASR #32
|
||||
STRB r5, [r0], #1
|
||||
ADD r7, r7, r6
|
||||
ADDS r7, r4, r7, LSR #1
|
||||
CMPGT r8, r7
|
||||
EORLT r7, r8, r7, ASR #32
|
||||
STRB r7, [r0], r3
|
||||
SUBS r14,r14,#1
|
||||
BGT ofrinter2_lp_arm
|
||||
LDMFD r13!,{r4-r8,PC}
|
||||
|
||||
[ OC_ARM_ASM_EDSP
|
||||
EXPORT oc_frag_copy_list_edsp
|
||||
|
||||
oc_frag_copy_list_edsp
|
||||
; r0 = _dst_frame
|
||||
; r1 = _src_frame
|
||||
; r2 = _ystride
|
||||
; r3 = _fragis
|
||||
; <> = _nfragis
|
||||
; <> = _frag_buf_offs
|
||||
LDR r12,[r13] ; r12 = _nfragis
|
||||
STMFD r13!,{r4-r11,r14}
|
||||
SUBS r12, r12, #1
|
||||
LDRGE r5, [r3],#4 ; r5 = _fragis[fragii]
|
||||
LDRGE r14,[r13,#4*10] ; r14 = _frag_buf_offs
|
||||
BLT ofcl_edsp_end
|
||||
ofcl_edsp_lp
|
||||
MOV r4, r1
|
||||
LDR r5, [r14,r5, LSL #2] ; r5 = _frag_buf_offs[_fragis[fragii]]
|
||||
SUBS r12, r12, #1
|
||||
; Stall (on XScale)
|
||||
LDRD r6, [r4, r5]! ; r4 = _src_frame+frag_buf_off
|
||||
LDRD r8, [r4, r2]!
|
||||
; Stall
|
||||
STRD r6, [r5, r0]! ; r5 = _dst_frame+frag_buf_off
|
||||
STRD r8, [r5, r2]!
|
||||
; Stall
|
||||
LDRD r6, [r4, r2]! ; On Xscale at least, doing 3 consecutive
|
||||
LDRD r8, [r4, r2]! ; loads causes a stall, but that's no worse
|
||||
LDRD r10,[r4, r2]! ; than us only doing 2, and having to do
|
||||
; another pair of LDRD/STRD later on.
|
||||
; Stall
|
||||
STRD r6, [r5, r2]!
|
||||
STRD r8, [r5, r2]!
|
||||
STRD r10,[r5, r2]!
|
||||
LDRD r6, [r4, r2]!
|
||||
LDRD r8, [r4, r2]!
|
||||
LDRD r10,[r4, r2]!
|
||||
STRD r6, [r5, r2]!
|
||||
STRD r8, [r5, r2]!
|
||||
STRD r10,[r5, r2]!
|
||||
LDRGE r5, [r3],#4 ; r5 = _fragis[fragii]
|
||||
BGE ofcl_edsp_lp
|
||||
ofcl_edsp_end
|
||||
LDMFD r13!,{r4-r11,PC}
|
||||
]
|
||||
|
||||
[ OC_ARM_ASM_MEDIA
|
||||
EXPORT oc_frag_recon_intra_v6
|
||||
EXPORT oc_frag_recon_inter_v6
|
||||
EXPORT oc_frag_recon_inter2_v6
|
||||
|
||||
oc_frag_recon_intra_v6
|
||||
; r0 = unsigned char *_dst
|
||||
; r1 = int _ystride
|
||||
; r2 = const ogg_int16_t _residue[64]
|
||||
STMFD r13!,{r4-r6,r14}
|
||||
MOV r14,#8
|
||||
MOV r12,r2
|
||||
LDR r6, =0x00800080
|
||||
ofrintra_v6_lp
|
||||
LDRD r2, [r12],#8 ; r2 = 11110000 r3 = 33332222
|
||||
LDRD r4, [r12],#8 ; r4 = 55554444 r5 = 77776666
|
||||
SUBS r14,r14,#1
|
||||
QADD16 r2, r2, r6
|
||||
QADD16 r3, r3, r6
|
||||
QADD16 r4, r4, r6
|
||||
QADD16 r5, r5, r6
|
||||
USAT16 r2, #8, r2 ; r2 = __11__00
|
||||
USAT16 r3, #8, r3 ; r3 = __33__22
|
||||
USAT16 r4, #8, r4 ; r4 = __55__44
|
||||
USAT16 r5, #8, r5 ; r5 = __77__66
|
||||
ORR r2, r2, r2, LSR #8 ; r2 = __111100
|
||||
ORR r3, r3, r3, LSR #8 ; r3 = __333322
|
||||
ORR r4, r4, r4, LSR #8 ; r4 = __555544
|
||||
ORR r5, r5, r5, LSR #8 ; r5 = __777766
|
||||
PKHBT r2, r2, r3, LSL #16 ; r2 = 33221100
|
||||
PKHBT r3, r4, r5, LSL #16 ; r3 = 77665544
|
||||
STRD r2, [r0], r1
|
||||
BGT ofrintra_v6_lp
|
||||
LDMFD r13!,{r4-r6,PC}
|
||||
|
||||
oc_frag_recon_inter_v6
|
||||
; r0 = unsigned char *_dst
|
||||
; r1 = const unsigned char *_src
|
||||
; r2 = int _ystride
|
||||
; r3 = const ogg_int16_t _residue[64]
|
||||
STMFD r13!,{r4-r7,r14}
|
||||
MOV r14,#8
|
||||
ofrinter_v6_lp
|
||||
LDRD r6, [r3], #8 ; r6 = 11110000 r7 = 33332222
|
||||
SUBS r14,r14,#1
|
||||
[ OC_ARM_CAN_UNALIGN_LDRD
|
||||
LDRD r4, [r1], r2 ; Unaligned ; r4 = 33221100 r5 = 77665544
|
||||
|
|
||||
LDR r5, [r1, #4]
|
||||
LDR r4, [r1], r2
|
||||
]
|
||||
PKHBT r12,r6, r7, LSL #16 ; r12= 22220000
|
||||
PKHTB r7, r7, r6, ASR #16 ; r7 = 33331111
|
||||
UXTB16 r6,r4 ; r6 = __22__00
|
||||
UXTB16 r4,r4, ROR #8 ; r4 = __33__11
|
||||
QADD16 r12,r12,r6 ; r12= xx22xx00
|
||||
QADD16 r4, r7, r4 ; r4 = xx33xx11
|
||||
LDRD r6, [r3], #8 ; r6 = 55554444 r7 = 77776666
|
||||
USAT16 r4, #8, r4 ; r4 = __33__11
|
||||
USAT16 r12,#8,r12 ; r12= __22__00
|
||||
ORR r4, r12,r4, LSL #8 ; r4 = 33221100
|
||||
PKHBT r12,r6, r7, LSL #16 ; r12= 66664444
|
||||
PKHTB r7, r7, r6, ASR #16 ; r7 = 77775555
|
||||
UXTB16 r6,r5 ; r6 = __66__44
|
||||
UXTB16 r5,r5, ROR #8 ; r5 = __77__55
|
||||
QADD16 r12,r12,r6 ; r12= xx66xx44
|
||||
QADD16 r5, r7, r5 ; r5 = xx77xx55
|
||||
USAT16 r12,#8, r12 ; r12= __66__44
|
||||
USAT16 r5, #8, r5 ; r4 = __77__55
|
||||
ORR r5, r12,r5, LSL #8 ; r5 = 33221100
|
||||
STRD r4, [r0], r2
|
||||
BGT ofrinter_v6_lp
|
||||
LDMFD r13!,{r4-r7,PC}
|
||||
|
||||
oc_frag_recon_inter2_v6
|
||||
; r0 = unsigned char *_dst
|
||||
; r1 = const unsigned char *_src1
|
||||
; r2 = const unsigned char *_src2
|
||||
; r3 = int _ystride
|
||||
LDR r12,[r13]
|
||||
; r12= const ogg_int16_t _residue[64]
|
||||
STMFD r13!,{r4-r9,r14}
|
||||
MOV r14,#8
|
||||
ofrinter2_v6_lp
|
||||
LDRD r6, [r12,#8] ; r6 = 55554444 r7 = 77776666
|
||||
SUBS r14,r14,#1
|
||||
LDR r4, [r1, #4] ; Unaligned ; r4 = src1[1] = 77665544
|
||||
LDR r5, [r2, #4] ; Unaligned ; r5 = src2[1] = 77665544
|
||||
PKHBT r8, r6, r7, LSL #16 ; r8 = 66664444
|
||||
PKHTB r9, r7, r6, ASR #16 ; r9 = 77775555
|
||||
UHADD8 r4, r4, r5 ; r4 = (src1[7,6,5,4] + src2[7,6,5,4])>>1
|
||||
UXTB16 r5, r4 ; r5 = __66__44
|
||||
UXTB16 r4, r4, ROR #8 ; r4 = __77__55
|
||||
QADD16 r8, r8, r5 ; r8 = xx66xx44
|
||||
QADD16 r9, r9, r4 ; r9 = xx77xx55
|
||||
LDRD r6,[r12],#16 ; r6 = 33332222 r7 = 11110000
|
||||
USAT16 r8, #8, r8 ; r8 = __66__44
|
||||
LDR r4, [r1], r3 ; Unaligned ; r4 = src1[0] = 33221100
|
||||
USAT16 r9, #8, r9 ; r9 = __77__55
|
||||
LDR r5, [r2], r3 ; Unaligned ; r5 = src2[0] = 33221100
|
||||
ORR r9, r8, r9, LSL #8 ; r9 = 77665544
|
||||
PKHBT r8, r6, r7, LSL #16 ; r8 = 22220000
|
||||
UHADD8 r4, r4, r5 ; r4 = (src1[3,2,1,0] + src2[3,2,1,0])>>1
|
||||
PKHTB r7, r7, r6, ASR #16 ; r7 = 33331111
|
||||
UXTB16 r5, r4 ; r5 = __22__00
|
||||
UXTB16 r4, r4, ROR #8 ; r4 = __33__11
|
||||
QADD16 r8, r8, r5 ; r8 = xx22xx00
|
||||
QADD16 r7, r7, r4 ; r7 = xx33xx11
|
||||
USAT16 r8, #8, r8 ; r8 = __22__00
|
||||
USAT16 r7, #8, r7 ; r7 = __33__11
|
||||
ORR r8, r8, r7, LSL #8 ; r8 = 33221100
|
||||
STRD r8, [r0], r3
|
||||
BGT ofrinter2_v6_lp
|
||||
LDMFD r13!,{r4-r9,PC}
|
||||
]
|
||||
|
||||
[ OC_ARM_ASM_NEON
|
||||
EXPORT oc_frag_copy_list_neon
|
||||
EXPORT oc_frag_recon_intra_neon
|
||||
EXPORT oc_frag_recon_inter_neon
|
||||
EXPORT oc_frag_recon_inter2_neon
|
||||
|
||||
oc_frag_copy_list_neon
|
||||
; r0 = _dst_frame
|
||||
; r1 = _src_frame
|
||||
; r2 = _ystride
|
||||
; r3 = _fragis
|
||||
; <> = _nfragis
|
||||
; <> = _frag_buf_offs
|
||||
LDR r12,[r13] ; r12 = _nfragis
|
||||
STMFD r13!,{r4-r7,r14}
|
||||
CMP r12, #1
|
||||
LDRGE r6, [r3] ; r6 = _fragis[fragii]
|
||||
LDRGE r14,[r13,#4*6] ; r14 = _frag_buf_offs
|
||||
BLT ofcl_neon_end
|
||||
; Stall (2 on Xscale)
|
||||
LDR r6, [r14,r6, LSL #2] ; r6 = _frag_buf_offs[_fragis[fragii]]
|
||||
; Stall (on XScale)
|
||||
MOV r7, r6 ; Guarantee PLD points somewhere valid.
|
||||
ofcl_neon_lp
|
||||
ADD r4, r1, r6
|
||||
VLD1.64 {D0}, [r4@64], r2
|
||||
ADD r5, r0, r6
|
||||
VLD1.64 {D1}, [r4@64], r2
|
||||
SUBS r12, r12, #1
|
||||
VLD1.64 {D2}, [r4@64], r2
|
||||
LDRGT r6, [r3,#4]! ; r6 = _fragis[fragii]
|
||||
VLD1.64 {D3}, [r4@64], r2
|
||||
LDRGT r6, [r14,r6, LSL #2] ; r6 = _frag_buf_offs[_fragis[fragii]]
|
||||
VLD1.64 {D4}, [r4@64], r2
|
||||
ADDGT r7, r1, r6
|
||||
VLD1.64 {D5}, [r4@64], r2
|
||||
PLD [r7]
|
||||
VLD1.64 {D6}, [r4@64], r2
|
||||
PLD [r7, r2]
|
||||
VLD1.64 {D7}, [r4@64]
|
||||
PLD [r7, r2, LSL #1]
|
||||
VST1.64 {D0}, [r5@64], r2
|
||||
ADDGT r7, r7, r2, LSL #2
|
||||
VST1.64 {D1}, [r5@64], r2
|
||||
PLD [r7, -r2]
|
||||
VST1.64 {D2}, [r5@64], r2
|
||||
PLD [r7]
|
||||
VST1.64 {D3}, [r5@64], r2
|
||||
PLD [r7, r2]
|
||||
VST1.64 {D4}, [r5@64], r2
|
||||
PLD [r7, r2, LSL #1]
|
||||
VST1.64 {D5}, [r5@64], r2
|
||||
ADDGT r7, r7, r2, LSL #2
|
||||
VST1.64 {D6}, [r5@64], r2
|
||||
PLD [r7, -r2]
|
||||
VST1.64 {D7}, [r5@64]
|
||||
BGT ofcl_neon_lp
|
||||
ofcl_neon_end
|
||||
LDMFD r13!,{r4-r7,PC}
|
||||
|
||||
oc_frag_recon_intra_neon
|
||||
; r0 = unsigned char *_dst
|
||||
; r1 = int _ystride
|
||||
; r2 = const ogg_int16_t _residue[64]
|
||||
MOV r3, #128
|
||||
VDUP.S16 Q0, r3
|
||||
VLDMIA r2, {D16-D31} ; D16= 3333222211110000 etc ; 9(8) cycles
|
||||
VQADD.S16 Q8, Q8, Q0
|
||||
VQADD.S16 Q9, Q9, Q0
|
||||
VQADD.S16 Q10,Q10,Q0
|
||||
VQADD.S16 Q11,Q11,Q0
|
||||
VQADD.S16 Q12,Q12,Q0
|
||||
VQADD.S16 Q13,Q13,Q0
|
||||
VQADD.S16 Q14,Q14,Q0
|
||||
VQADD.S16 Q15,Q15,Q0
|
||||
VQMOVUN.S16 D16,Q8 ; D16= 7766554433221100 ; 1 cycle
|
||||
VQMOVUN.S16 D17,Q9 ; D17= FFEEDDCCBBAA9988 ; 1 cycle
|
||||
VQMOVUN.S16 D18,Q10 ; D18= NNMMLLKKJJIIHHGG ; 1 cycle
|
||||
VST1.64 {D16},[r0@64], r1
|
||||
VQMOVUN.S16 D19,Q11 ; D19= VVUUTTSSRRQQPPOO ; 1 cycle
|
||||
VST1.64 {D17},[r0@64], r1
|
||||
VQMOVUN.S16 D20,Q12 ; D20= ddccbbaaZZYYXXWW ; 1 cycle
|
||||
VST1.64 {D18},[r0@64], r1
|
||||
VQMOVUN.S16 D21,Q13 ; D21= llkkjjiihhggffee ; 1 cycle
|
||||
VST1.64 {D19},[r0@64], r1
|
||||
VQMOVUN.S16 D22,Q14 ; D22= ttssrrqqppoonnmm ; 1 cycle
|
||||
VST1.64 {D20},[r0@64], r1
|
||||
VQMOVUN.S16 D23,Q15 ; D23= !!@@zzyyxxwwvvuu ; 1 cycle
|
||||
VST1.64 {D21},[r0@64], r1
|
||||
VST1.64 {D22},[r0@64], r1
|
||||
VST1.64 {D23},[r0@64], r1
|
||||
MOV PC,R14
|
||||
|
||||
oc_frag_recon_inter_neon
|
||||
; r0 = unsigned char *_dst
|
||||
; r1 = const unsigned char *_src
|
||||
; r2 = int _ystride
|
||||
; r3 = const ogg_int16_t _residue[64]
|
||||
VLDMIA r3, {D16-D31} ; D16= 3333222211110000 etc ; 9(8) cycles
|
||||
VLD1.64 {D0}, [r1], r2
|
||||
VLD1.64 {D2}, [r1], r2
|
||||
VMOVL.U8 Q0, D0 ; Q0 = __77__66__55__44__33__22__11__00
|
||||
VLD1.64 {D4}, [r1], r2
|
||||
VMOVL.U8 Q1, D2 ; etc
|
||||
VLD1.64 {D6}, [r1], r2
|
||||
VMOVL.U8 Q2, D4
|
||||
VMOVL.U8 Q3, D6
|
||||
VQADD.S16 Q8, Q8, Q0
|
||||
VLD1.64 {D0}, [r1], r2
|
||||
VQADD.S16 Q9, Q9, Q1
|
||||
VLD1.64 {D2}, [r1], r2
|
||||
VQADD.S16 Q10,Q10,Q2
|
||||
VLD1.64 {D4}, [r1], r2
|
||||
VQADD.S16 Q11,Q11,Q3
|
||||
VLD1.64 {D6}, [r1], r2
|
||||
VMOVL.U8 Q0, D0
|
||||
VMOVL.U8 Q1, D2
|
||||
VMOVL.U8 Q2, D4
|
||||
VMOVL.U8 Q3, D6
|
||||
VQADD.S16 Q12,Q12,Q0
|
||||
VQADD.S16 Q13,Q13,Q1
|
||||
VQADD.S16 Q14,Q14,Q2
|
||||
VQADD.S16 Q15,Q15,Q3
|
||||
VQMOVUN.S16 D16,Q8
|
||||
VQMOVUN.S16 D17,Q9
|
||||
VQMOVUN.S16 D18,Q10
|
||||
VST1.64 {D16},[r0@64], r2
|
||||
VQMOVUN.S16 D19,Q11
|
||||
VST1.64 {D17},[r0@64], r2
|
||||
VQMOVUN.S16 D20,Q12
|
||||
VST1.64 {D18},[r0@64], r2
|
||||
VQMOVUN.S16 D21,Q13
|
||||
VST1.64 {D19},[r0@64], r2
|
||||
VQMOVUN.S16 D22,Q14
|
||||
VST1.64 {D20},[r0@64], r2
|
||||
VQMOVUN.S16 D23,Q15
|
||||
VST1.64 {D21},[r0@64], r2
|
||||
VST1.64 {D22},[r0@64], r2
|
||||
VST1.64 {D23},[r0@64], r2
|
||||
MOV PC,R14
|
||||
|
||||
oc_frag_recon_inter2_neon
|
||||
; r0 = unsigned char *_dst
|
||||
; r1 = const unsigned char *_src1
|
||||
; r2 = const unsigned char *_src2
|
||||
; r3 = int _ystride
|
||||
LDR r12,[r13]
|
||||
; r12= const ogg_int16_t _residue[64]
|
||||
VLDMIA r12,{D16-D31}
|
||||
VLD1.64 {D0}, [r1], r3
|
||||
VLD1.64 {D4}, [r2], r3
|
||||
VLD1.64 {D1}, [r1], r3
|
||||
VLD1.64 {D5}, [r2], r3
|
||||
VHADD.U8 Q2, Q0, Q2 ; Q2 = FFEEDDCCBBAA99887766554433221100
|
||||
VLD1.64 {D2}, [r1], r3
|
||||
VLD1.64 {D6}, [r2], r3
|
||||
VMOVL.U8 Q0, D4 ; Q0 = __77__66__55__44__33__22__11__00
|
||||
VLD1.64 {D3}, [r1], r3
|
||||
VMOVL.U8 Q2, D5 ; etc
|
||||
VLD1.64 {D7}, [r2], r3
|
||||
VHADD.U8 Q3, Q1, Q3
|
||||
VQADD.S16 Q8, Q8, Q0
|
||||
VQADD.S16 Q9, Q9, Q2
|
||||
VLD1.64 {D0}, [r1], r3
|
||||
VMOVL.U8 Q1, D6
|
||||
VLD1.64 {D4}, [r2], r3
|
||||
VMOVL.U8 Q3, D7
|
||||
VLD1.64 {D1}, [r1], r3
|
||||
VQADD.S16 Q10,Q10,Q1
|
||||
VLD1.64 {D5}, [r2], r3
|
||||
VQADD.S16 Q11,Q11,Q3
|
||||
VLD1.64 {D2}, [r1], r3
|
||||
VHADD.U8 Q2, Q0, Q2
|
||||
VLD1.64 {D6}, [r2], r3
|
||||
VLD1.64 {D3}, [r1], r3
|
||||
VMOVL.U8 Q0, D4
|
||||
VLD1.64 {D7}, [r2], r3
|
||||
VMOVL.U8 Q2, D5
|
||||
VHADD.U8 Q3, Q1, Q3
|
||||
VQADD.S16 Q12,Q12,Q0
|
||||
VQADD.S16 Q13,Q13,Q2
|
||||
VMOVL.U8 Q1, D6
|
||||
VMOVL.U8 Q3, D7
|
||||
VQADD.S16 Q14,Q14,Q1
|
||||
VQADD.S16 Q15,Q15,Q3
|
||||
VQMOVUN.S16 D16,Q8
|
||||
VQMOVUN.S16 D17,Q9
|
||||
VQMOVUN.S16 D18,Q10
|
||||
VST1.64 {D16},[r0@64], r3
|
||||
VQMOVUN.S16 D19,Q11
|
||||
VST1.64 {D17},[r0@64], r3
|
||||
VQMOVUN.S16 D20,Q12
|
||||
VST1.64 {D18},[r0@64], r3
|
||||
VQMOVUN.S16 D21,Q13
|
||||
VST1.64 {D19},[r0@64], r3
|
||||
VQMOVUN.S16 D22,Q14
|
||||
VST1.64 {D20},[r0@64], r3
|
||||
VQMOVUN.S16 D23,Q15
|
||||
VST1.64 {D21},[r0@64], r3
|
||||
VST1.64 {D22},[r0@64], r3
|
||||
VST1.64 {D23},[r0@64], r3
|
||||
MOV PC,R14
|
||||
]
|
||||
|
||||
END
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,126 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2010 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: x86int.h 17344 2010-07-21 01:42:18Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_arm_armint_H)
|
||||
# define _arm_armint_H (1)
|
||||
# include "../internal.h"
|
||||
|
||||
# if defined(OC_ARM_ASM)
|
||||
|
||||
# if defined(__ARMEB__)
|
||||
# error "Big-endian configurations are not supported by the ARM asm. " \
|
||||
"Reconfigure with --disable-asm or undefine OC_ARM_ASM."
|
||||
# endif
|
||||
|
||||
# define oc_state_accel_init oc_state_accel_init_arm
|
||||
/*This function is implemented entirely in asm, so it's helpful to pull out all
|
||||
of the things that depend on structure offsets.
|
||||
We reuse the function pointer with the wrong prototype, though.*/
|
||||
# define oc_state_loop_filter_frag_rows(_state,_bv,_refi,_pli, \
|
||||
_fragy0,_fragy_end) \
|
||||
((oc_loop_filter_frag_rows_arm_func) \
|
||||
(_state)->opt_vtable.state_loop_filter_frag_rows)( \
|
||||
(_state)->ref_frame_data[(_refi)],(_state)->ref_ystride[(_pli)], \
|
||||
(_bv), \
|
||||
(_state)->frags, \
|
||||
(_state)->fplanes[(_pli)].froffset \
|
||||
+(_fragy0)*(ptrdiff_t)(_state)->fplanes[(_pli)].nhfrags, \
|
||||
(_state)->fplanes[(_pli)].froffset \
|
||||
+(_fragy_end)*(ptrdiff_t)(_state)->fplanes[(_pli)].nhfrags, \
|
||||
(_state)->fplanes[(_pli)].froffset, \
|
||||
(_state)->fplanes[(_pli)].froffset+(_state)->fplanes[(_pli)].nfrags, \
|
||||
(_state)->frag_buf_offs, \
|
||||
(_state)->fplanes[(_pli)].nhfrags)
|
||||
/*For everything else the default vtable macros are fine.*/
|
||||
# define OC_STATE_USE_VTABLE (1)
|
||||
# endif
|
||||
|
||||
# include "../state.h"
|
||||
# include "armcpu.h"
|
||||
|
||||
# if defined(OC_ARM_ASM)
|
||||
typedef void (*oc_loop_filter_frag_rows_arm_func)(
|
||||
unsigned char *_ref_frame_data,int _ystride,signed char _bv[256],
|
||||
const oc_fragment *_frags,ptrdiff_t _fragi0,ptrdiff_t _fragi0_end,
|
||||
ptrdiff_t _fragi_top,ptrdiff_t _fragi_bot,
|
||||
const ptrdiff_t *_frag_buf_offs,int _nhfrags);
|
||||
|
||||
void oc_state_accel_init_arm(oc_theora_state *_state);
|
||||
void oc_frag_copy_list_arm(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||
void oc_frag_recon_intra_arm(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter_arm(unsigned char *_dst,const unsigned char *_src,
|
||||
int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter2_arm(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_idct8x8_1_arm(ogg_int16_t _y[64],ogg_uint16_t _dc);
|
||||
void oc_idct8x8_arm(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||
void oc_state_frag_recon_arm(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||
void oc_loop_filter_frag_rows_arm(unsigned char *_ref_frame_data,
|
||||
int _ystride,signed char *_bv,const oc_fragment *_frags,ptrdiff_t _fragi0,
|
||||
ptrdiff_t _fragi0_end,ptrdiff_t _fragi_top,ptrdiff_t _fragi_bot,
|
||||
const ptrdiff_t *_frag_buf_offs,int _nhfrags);
|
||||
|
||||
# if defined(OC_ARM_ASM_EDSP)
|
||||
void oc_frag_copy_list_edsp(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||
|
||||
# if defined(OC_ARM_ASM_MEDIA)
|
||||
void oc_frag_recon_intra_v6(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter_v6(unsigned char *_dst,const unsigned char *_src,
|
||||
int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter2_v6(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_idct8x8_1_v6(ogg_int16_t _y[64],ogg_uint16_t _dc);
|
||||
void oc_idct8x8_v6(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||
void oc_state_frag_recon_v6(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||
void oc_loop_filter_init_v6(signed char *_bv,int _flimit);
|
||||
void oc_loop_filter_frag_rows_v6(unsigned char *_ref_frame_data,
|
||||
int _ystride,signed char *_bv,const oc_fragment *_frags,ptrdiff_t _fragi0,
|
||||
ptrdiff_t _fragi0_end,ptrdiff_t _fragi_top,ptrdiff_t _fragi_bot,
|
||||
const ptrdiff_t *_frag_buf_offs,int _nhfrags);
|
||||
|
||||
# if defined(OC_ARM_ASM_NEON)
|
||||
void oc_frag_copy_list_neon(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||
void oc_frag_recon_intra_neon(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter_neon(unsigned char *_dst,const unsigned char *_src,
|
||||
int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter2_neon(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_idct8x8_1_neon(ogg_int16_t _y[64],ogg_uint16_t _dc);
|
||||
void oc_idct8x8_neon(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||
void oc_state_frag_recon_neon(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||
void oc_loop_filter_init_neon(signed char *_bv,int _flimit);
|
||||
void oc_loop_filter_frag_rows_neon(unsigned char *_ref_frame_data,
|
||||
int _ystride,signed char *_bv,const oc_fragment *_frags,ptrdiff_t _fragi0,
|
||||
ptrdiff_t _fragi0_end,ptrdiff_t _fragi_top,ptrdiff_t _fragi_bot,
|
||||
const ptrdiff_t *_frag_buf_offs,int _nhfrags);
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,664 @@
|
||||
;********************************************************************
|
||||
;* *
|
||||
;* 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-2010 *
|
||||
;* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
;* *
|
||||
;********************************************************************
|
||||
; Original implementation:
|
||||
; Copyright (C) 2009 Robin Watts for Pinknoise Productions Ltd
|
||||
; last mod: $Id$
|
||||
;********************************************************************
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
GET armopts.s
|
||||
|
||||
EXPORT oc_loop_filter_frag_rows_arm
|
||||
|
||||
; Which bit this is depends on the order of packing within a bitfield.
|
||||
; Hopefully that doesn't change among any of the relevant compilers.
|
||||
OC_FRAG_CODED_FLAG * 1
|
||||
|
||||
; Vanilla ARM v4 version
|
||||
loop_filter_h_arm
|
||||
; r0 = unsigned char *_pix
|
||||
; r1 = int _ystride
|
||||
; r2 = int *_bv
|
||||
; preserves r0-r3
|
||||
STMFD r13!,{r3-r6,r14}
|
||||
MOV r14,#8
|
||||
MOV r6, #255
|
||||
lfh_arm_lp
|
||||
LDRB r3, [r0, #-2] ; r3 = _pix[0]
|
||||
LDRB r12,[r0, #1] ; r12= _pix[3]
|
||||
LDRB r4, [r0, #-1] ; r4 = _pix[1]
|
||||
LDRB r5, [r0] ; r5 = _pix[2]
|
||||
SUB r3, r3, r12 ; r3 = _pix[0]-_pix[3]+4
|
||||
ADD r3, r3, #4
|
||||
SUB r12,r5, r4 ; r12= _pix[2]-_pix[1]
|
||||
ADD r12,r12,r12,LSL #1 ; r12= 3*(_pix[2]-_pix[1])
|
||||
ADD r12,r12,r3 ; r12= _pix[0]-_pix[3]+3*(_pix[2]-_pix[1])+4
|
||||
MOV r12,r12,ASR #3
|
||||
LDRSB r12,[r2, r12]
|
||||
; Stall (2 on Xscale)
|
||||
ADDS r4, r4, r12
|
||||
CMPGT r6, r4
|
||||
EORLT r4, r6, r4, ASR #32
|
||||
SUBS r5, r5, r12
|
||||
CMPGT r6, r5
|
||||
EORLT r5, r6, r5, ASR #32
|
||||
STRB r4, [r0, #-1]
|
||||
STRB r5, [r0], r1
|
||||
SUBS r14,r14,#1
|
||||
BGT lfh_arm_lp
|
||||
SUB r0, r0, r1, LSL #3
|
||||
LDMFD r13!,{r3-r6,PC}
|
||||
|
||||
loop_filter_v_arm
|
||||
; r0 = unsigned char *_pix
|
||||
; r1 = int _ystride
|
||||
; r2 = int *_bv
|
||||
; preserves r0-r3
|
||||
STMFD r13!,{r3-r6,r14}
|
||||
MOV r14,#8
|
||||
MOV r6, #255
|
||||
lfv_arm_lp
|
||||
LDRB r3, [r0, -r1, LSL #1] ; r3 = _pix[0]
|
||||
LDRB r12,[r0, r1] ; r12= _pix[3]
|
||||
LDRB r4, [r0, -r1] ; r4 = _pix[1]
|
||||
LDRB r5, [r0] ; r5 = _pix[2]
|
||||
SUB r3, r3, r12 ; r3 = _pix[0]-_pix[3]+4
|
||||
ADD r3, r3, #4
|
||||
SUB r12,r5, r4 ; r12= _pix[2]-_pix[1]
|
||||
ADD r12,r12,r12,LSL #1 ; r12= 3*(_pix[2]-_pix[1])
|
||||
ADD r12,r12,r3 ; r12= _pix[0]-_pix[3]+3*(_pix[2]-_pix[1])+4
|
||||
MOV r12,r12,ASR #3
|
||||
LDRSB r12,[r2, r12]
|
||||
; Stall (2 on Xscale)
|
||||
ADDS r4, r4, r12
|
||||
CMPGT r6, r4
|
||||
EORLT r4, r6, r4, ASR #32
|
||||
SUBS r5, r5, r12
|
||||
CMPGT r6, r5
|
||||
EORLT r5, r6, r5, ASR #32
|
||||
STRB r4, [r0, -r1]
|
||||
STRB r5, [r0], #1
|
||||
SUBS r14,r14,#1
|
||||
BGT lfv_arm_lp
|
||||
SUB r0, r0, #8
|
||||
LDMFD r13!,{r3-r6,PC}
|
||||
|
||||
oc_loop_filter_frag_rows_arm
|
||||
; r0 = _ref_frame_data
|
||||
; r1 = _ystride
|
||||
; r2 = _bv
|
||||
; r3 = _frags
|
||||
; r4 = _fragi0
|
||||
; r5 = _fragi0_end
|
||||
; r6 = _fragi_top
|
||||
; r7 = _fragi_bot
|
||||
; r8 = _frag_buf_offs
|
||||
; r9 = _nhfrags
|
||||
MOV r12,r13
|
||||
STMFD r13!,{r0,r4-r11,r14}
|
||||
LDMFD r12,{r4-r9}
|
||||
ADD r2, r2, #127 ; _bv += 127
|
||||
CMP r4, r5 ; if(_fragi0>=_fragi0_end)
|
||||
BGE oslffri_arm_end ; bail
|
||||
SUBS r9, r9, #1 ; r9 = _nhfrags-1 if (r9<=0)
|
||||
BLE oslffri_arm_end ; bail
|
||||
ADD r3, r3, r4, LSL #2 ; r3 = &_frags[fragi]
|
||||
ADD r8, r8, r4, LSL #2 ; r8 = &_frag_buf_offs[fragi]
|
||||
SUB r7, r7, r9 ; _fragi_bot -= _nhfrags;
|
||||
oslffri_arm_lp1
|
||||
MOV r10,r4 ; r10= fragi = _fragi0
|
||||
ADD r11,r4, r9 ; r11= fragi_end-1=fragi+_nhfrags-1
|
||||
oslffri_arm_lp2
|
||||
LDR r14,[r3], #4 ; r14= _frags[fragi] _frags++
|
||||
LDR r0, [r13] ; r0 = _ref_frame_data
|
||||
LDR r12,[r8], #4 ; r12= _frag_buf_offs[fragi] _frag_buf_offs++
|
||||
TST r14,#OC_FRAG_CODED_FLAG
|
||||
BEQ oslffri_arm_uncoded
|
||||
CMP r10,r4 ; if (fragi>_fragi0)
|
||||
ADD r0, r0, r12 ; r0 = _ref_frame_data + _frag_buf_offs[fragi]
|
||||
BLGT loop_filter_h_arm
|
||||
CMP r4, r6 ; if (_fragi0>_fragi_top)
|
||||
BLGT loop_filter_v_arm
|
||||
CMP r10,r11 ; if(fragi+1<fragi_end)===(fragi<fragi_end-1)
|
||||
LDRLT r12,[r3] ; r12 = _frags[fragi+1]
|
||||
ADD r0, r0, #8
|
||||
ADD r10,r10,#1 ; r10 = fragi+1;
|
||||
ANDLT r12,r12,#OC_FRAG_CODED_FLAG
|
||||
CMPLT r12,#OC_FRAG_CODED_FLAG ; && _frags[fragi+1].coded==0
|
||||
BLLT loop_filter_h_arm
|
||||
CMP r10,r7 ; if (fragi<_fragi_bot)
|
||||
LDRLT r12,[r3, r9, LSL #2] ; r12 = _frags[fragi+1+_nhfrags-1]
|
||||
SUB r0, r0, #8
|
||||
ADD r0, r0, r1, LSL #3
|
||||
ANDLT r12,r12,#OC_FRAG_CODED_FLAG
|
||||
CMPLT r12,#OC_FRAG_CODED_FLAG
|
||||
BLLT loop_filter_v_arm
|
||||
CMP r10,r11 ; while(fragi<=fragi_end-1)
|
||||
BLE oslffri_arm_lp2
|
||||
MOV r4, r10 ; r4 = fragi0 += _nhfrags
|
||||
CMP r4, r5
|
||||
BLT oslffri_arm_lp1
|
||||
oslffri_arm_end
|
||||
LDMFD r13!,{r0,r4-r11,PC}
|
||||
oslffri_arm_uncoded
|
||||
ADD r10,r10,#1
|
||||
CMP r10,r11
|
||||
BLE oslffri_arm_lp2
|
||||
MOV r4, r10 ; r4 = _fragi0 += _nhfrags
|
||||
CMP r4, r5
|
||||
BLT oslffri_arm_lp1
|
||||
LDMFD r13!,{r0,r4-r11,PC}
|
||||
|
||||
[ OC_ARM_ASM_MEDIA
|
||||
EXPORT oc_loop_filter_init_v6
|
||||
EXPORT oc_loop_filter_frag_rows_v6
|
||||
|
||||
oc_loop_filter_init_v6
|
||||
; r0 = _bv
|
||||
; r1 = _flimit (=L from the spec)
|
||||
MVN r1, r1, LSL #1 ; r1 = <0xFFFFFF|255-2*L>
|
||||
AND r1, r1, #255 ; r1 = ll=r1&0xFF
|
||||
ORR r1, r1, r1, LSL #8 ; r1 = <ll|ll>
|
||||
PKHBT r1, r1, r1, LSL #16 ; r1 = <ll|ll|ll|ll>
|
||||
STR r1, [r0]
|
||||
MOV PC,r14
|
||||
|
||||
; We could use the same strategy as the v filter below, but that would require
|
||||
; 40 instructions to load the data and transpose it into columns and another
|
||||
; 32 to write out the results at the end, plus the 52 instructions to do the
|
||||
; filtering itself.
|
||||
; This is slightly less, and less code, even assuming we could have shared the
|
||||
; 52 instructions in the middle with the other function.
|
||||
; It executes slightly fewer instructions than the ARMv6 approach David Conrad
|
||||
; proposed for FFmpeg, but not by much:
|
||||
; http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2010-February/083141.html
|
||||
; His is a lot less code, though, because it only does two rows at once instead
|
||||
; of four.
|
||||
loop_filter_h_v6
|
||||
; r0 = unsigned char *_pix
|
||||
; r1 = int _ystride
|
||||
; r2 = int _ll
|
||||
; preserves r0-r3
|
||||
STMFD r13!,{r4-r11,r14}
|
||||
LDR r12,=0x10003
|
||||
BL loop_filter_h_core_v6
|
||||
ADD r0, r0, r1, LSL #2
|
||||
BL loop_filter_h_core_v6
|
||||
SUB r0, r0, r1, LSL #2
|
||||
LDMFD r13!,{r4-r11,PC}
|
||||
|
||||
loop_filter_h_core_v6
|
||||
; r0 = unsigned char *_pix
|
||||
; r1 = int _ystride
|
||||
; r2 = int _ll
|
||||
; r12= 0x10003
|
||||
; Preserves r0-r3, r12; Clobbers r4-r11.
|
||||
LDR r4,[r0, #-2]! ; r4 = <p3|p2|p1|p0>
|
||||
; Single issue
|
||||
LDR r5,[r0, r1]! ; r5 = <q3|q2|q1|q0>
|
||||
UXTB16 r6, r4, ROR #16 ; r6 = <p0|p2>
|
||||
UXTB16 r4, r4, ROR #8 ; r4 = <p3|p1>
|
||||
UXTB16 r7, r5, ROR #16 ; r7 = <q0|q2>
|
||||
UXTB16 r5, r5, ROR #8 ; r5 = <q3|q1>
|
||||
PKHBT r8, r4, r5, LSL #16 ; r8 = <__|q1|__|p1>
|
||||
PKHBT r9, r6, r7, LSL #16 ; r9 = <__|q2|__|p2>
|
||||
SSUB16 r6, r4, r6 ; r6 = <p3-p0|p1-p2>
|
||||
SMLAD r6, r6, r12,r12 ; r6 = <????|(p3-p0)+3*(p1-p2)+3>
|
||||
SSUB16 r7, r5, r7 ; r7 = <q3-q0|q1-q2>
|
||||
SMLAD r7, r7, r12,r12 ; r7 = <????|(q0-q3)+3*(q2-q1)+4>
|
||||
LDR r4,[r0, r1]! ; r4 = <r3|r2|r1|r0>
|
||||
MOV r6, r6, ASR #3 ; r6 = <??????|(p3-p0)+3*(p1-p2)+3>>3>
|
||||
LDR r5,[r0, r1]! ; r5 = <s3|s2|s1|s0>
|
||||
PKHBT r11,r6, r7, LSL #13 ; r11= <??|-R_q|??|-R_p>
|
||||
UXTB16 r6, r4, ROR #16 ; r6 = <r0|r2>
|
||||
UXTB16 r11,r11 ; r11= <__|-R_q|__|-R_p>
|
||||
UXTB16 r4, r4, ROR #8 ; r4 = <r3|r1>
|
||||
UXTB16 r7, r5, ROR #16 ; r7 = <s0|s2>
|
||||
PKHBT r10,r6, r7, LSL #16 ; r10= <__|s2|__|r2>
|
||||
SSUB16 r6, r4, r6 ; r6 = <r3-r0|r1-r2>
|
||||
UXTB16 r5, r5, ROR #8 ; r5 = <s3|s1>
|
||||
SMLAD r6, r6, r12,r12 ; r6 = <????|(r3-r0)+3*(r2-r1)+3>
|
||||
SSUB16 r7, r5, r7 ; r7 = <r3-r0|r1-r2>
|
||||
SMLAD r7, r7, r12,r12 ; r7 = <????|(s0-s3)+3*(s2-s1)+4>
|
||||
ORR r9, r9, r10, LSL #8 ; r9 = <s2|q2|r2|p2>
|
||||
MOV r6, r6, ASR #3 ; r6 = <??????|(r0-r3)+3*(r2-r1)+4>>3>
|
||||
PKHBT r10,r4, r5, LSL #16 ; r10= <__|s1|__|r1>
|
||||
PKHBT r6, r6, r7, LSL #13 ; r6 = <??|-R_s|??|-R_r>
|
||||
ORR r8, r8, r10, LSL #8 ; r8 = <s1|q1|r1|p1>
|
||||
UXTB16 r6, r6 ; r6 = <__|-R_s|__|-R_r>
|
||||
MOV r10,#0
|
||||
ORR r6, r11,r6, LSL #8 ; r6 = <-R_s|-R_q|-R_r|-R_p>
|
||||
; Single issue
|
||||
; There's no min, max or abs instruction.
|
||||
; SSUB8 and SEL will work for abs, and we can do all the rest with
|
||||
; unsigned saturated adds, which means the GE flags are still all
|
||||
; set when we're done computing lflim(abs(R_i),L).
|
||||
; This allows us to both add and subtract, and split the results by
|
||||
; the original sign of R_i.
|
||||
SSUB8 r7, r10,r6
|
||||
; Single issue
|
||||
SEL r7, r7, r6 ; r7 = abs(R_i)
|
||||
; Single issue
|
||||
UQADD8 r4, r7, r2 ; r4 = 255-max(2*L-abs(R_i),0)
|
||||
; Single issue
|
||||
UQADD8 r7, r7, r4
|
||||
; Single issue
|
||||
UQSUB8 r7, r7, r4 ; r7 = min(abs(R_i),max(2*L-abs(R_i),0))
|
||||
; Single issue
|
||||
UQSUB8 r4, r8, r7
|
||||
UQADD8 r5, r9, r7
|
||||
UQADD8 r8, r8, r7
|
||||
UQSUB8 r9, r9, r7
|
||||
SEL r8, r8, r4 ; r8 = p1+lflim(R_i,L)
|
||||
SEL r9, r9, r5 ; r9 = p2-lflim(R_i,L)
|
||||
MOV r5, r9, LSR #24 ; r5 = s2
|
||||
STRB r5, [r0,#2]!
|
||||
MOV r4, r8, LSR #24 ; r4 = s1
|
||||
STRB r4, [r0,#-1]
|
||||
MOV r5, r9, LSR #8 ; r5 = r2
|
||||
STRB r5, [r0,-r1]!
|
||||
MOV r4, r8, LSR #8 ; r4 = r1
|
||||
STRB r4, [r0,#-1]
|
||||
MOV r5, r9, LSR #16 ; r5 = q2
|
||||
STRB r5, [r0,-r1]!
|
||||
MOV r4, r8, LSR #16 ; r4 = q1
|
||||
STRB r4, [r0,#-1]
|
||||
; Single issue
|
||||
STRB r9, [r0,-r1]!
|
||||
; Single issue
|
||||
STRB r8, [r0,#-1]
|
||||
MOV PC,r14
|
||||
|
||||
; This uses the same strategy as the MMXEXT version for x86, except that UHADD8
|
||||
; computes (a+b>>1) instead of (a+b+1>>1) like PAVGB.
|
||||
; This works just as well, with the following procedure for computing the
|
||||
; filter value, f:
|
||||
; u = ~UHADD8(p1,~p2);
|
||||
; v = UHADD8(~p1,p2);
|
||||
; m = v-u;
|
||||
; a = m^UHADD8(m^p0,m^~p3);
|
||||
; f = UHADD8(UHADD8(a,u1),v1);
|
||||
; where f = 127+R, with R in [-127,128] defined as in the spec.
|
||||
; This is exactly the same amount of arithmetic as the version that uses PAVGB
|
||||
; as the basic operator.
|
||||
; It executes about 2/3 the number of instructions of David Conrad's approach,
|
||||
; but requires more code, because it does all eight columns at once, instead
|
||||
; of four at a time.
|
||||
loop_filter_v_v6
|
||||
; r0 = unsigned char *_pix
|
||||
; r1 = int _ystride
|
||||
; r2 = int _ll
|
||||
; preserves r0-r11
|
||||
STMFD r13!,{r4-r11,r14}
|
||||
LDRD r6, [r0, -r1]! ; r7, r6 = <p5|p1>
|
||||
LDRD r4, [r0, -r1] ; r5, r4 = <p4|p0>
|
||||
LDRD r8, [r0, r1]! ; r9, r8 = <p6|p2>
|
||||
MVN r14,r6 ; r14= ~p1
|
||||
LDRD r10,[r0, r1] ; r11,r10= <p7|p3>
|
||||
; Filter the first four columns.
|
||||
MVN r12,r8 ; r12= ~p2
|
||||
UHADD8 r14,r14,r8 ; r14= v1=~p1+p2>>1
|
||||
UHADD8 r12,r12,r6 ; r12= p1+~p2>>1
|
||||
MVN r10, r10 ; r10=~p3
|
||||
MVN r12,r12 ; r12= u1=~p1+p2+1>>1
|
||||
SSUB8 r14,r14,r12 ; r14= m1=v1-u1
|
||||
; Single issue
|
||||
EOR r4, r4, r14 ; r4 = m1^p0
|
||||
EOR r10,r10,r14 ; r10= m1^~p3
|
||||
UHADD8 r4, r4, r10 ; r4 = (m1^p0)+(m1^~p3)>>1
|
||||
; Single issue
|
||||
EOR r4, r4, r14 ; r4 = a1=m1^((m1^p0)+(m1^~p3)>>1)
|
||||
SADD8 r14,r14,r12 ; r14= v1=m1+u1
|
||||
UHADD8 r4, r4, r12 ; r4 = a1+u1>>1
|
||||
MVN r12,r9 ; r12= ~p6
|
||||
UHADD8 r4, r4, r14 ; r4 = f1=(a1+u1>>1)+v1>>1
|
||||
; Filter the second four columns.
|
||||
MVN r14,r7 ; r14= ~p5
|
||||
UHADD8 r12,r12,r7 ; r12= p5+~p6>>1
|
||||
UHADD8 r14,r14,r9 ; r14= v2=~p5+p6>>1
|
||||
MVN r12,r12 ; r12= u2=~p5+p6+1>>1
|
||||
MVN r11,r11 ; r11=~p7
|
||||
SSUB8 r10,r14,r12 ; r10= m2=v2-u2
|
||||
; Single issue
|
||||
EOR r5, r5, r10 ; r5 = m2^p4
|
||||
EOR r11,r11,r10 ; r11= m2^~p7
|
||||
UHADD8 r5, r5, r11 ; r5 = (m2^p4)+(m2^~p7)>>1
|
||||
; Single issue
|
||||
EOR r5, r5, r10 ; r5 = a2=m2^((m2^p4)+(m2^~p7)>>1)
|
||||
; Single issue
|
||||
UHADD8 r5, r5, r12 ; r5 = a2+u2>>1
|
||||
LDR r12,=0x7F7F7F7F ; r12 = {127}x4
|
||||
UHADD8 r5, r5, r14 ; r5 = f2=(a2+u2>>1)+v2>>1
|
||||
; Now split f[i] by sign.
|
||||
; There's no min or max instruction.
|
||||
; We could use SSUB8 and SEL, but this is just as many instructions and
|
||||
; dual issues more (for v7 without NEON).
|
||||
UQSUB8 r10,r4, r12 ; r10= R_i>0?R_i:0
|
||||
UQSUB8 r4, r12,r4 ; r4 = R_i<0?-R_i:0
|
||||
UQADD8 r11,r10,r2 ; r11= 255-max(2*L-abs(R_i<0),0)
|
||||
UQADD8 r14,r4, r2 ; r14= 255-max(2*L-abs(R_i>0),0)
|
||||
UQADD8 r10,r10,r11
|
||||
UQADD8 r4, r4, r14
|
||||
UQSUB8 r10,r10,r11 ; r10= min(abs(R_i<0),max(2*L-abs(R_i<0),0))
|
||||
UQSUB8 r4, r4, r14 ; r4 = min(abs(R_i>0),max(2*L-abs(R_i>0),0))
|
||||
UQSUB8 r11,r5, r12 ; r11= R_i>0?R_i:0
|
||||
UQADD8 r6, r6, r10
|
||||
UQSUB8 r8, r8, r10
|
||||
UQSUB8 r5, r12,r5 ; r5 = R_i<0?-R_i:0
|
||||
UQSUB8 r6, r6, r4 ; r6 = p1+lflim(R_i,L)
|
||||
UQADD8 r8, r8, r4 ; r8 = p2-lflim(R_i,L)
|
||||
UQADD8 r10,r11,r2 ; r10= 255-max(2*L-abs(R_i<0),0)
|
||||
UQADD8 r14,r5, r2 ; r14= 255-max(2*L-abs(R_i>0),0)
|
||||
UQADD8 r11,r11,r10
|
||||
UQADD8 r5, r5, r14
|
||||
UQSUB8 r11,r11,r10 ; r11= min(abs(R_i<0),max(2*L-abs(R_i<0),0))
|
||||
UQSUB8 r5, r5, r14 ; r5 = min(abs(R_i>0),max(2*L-abs(R_i>0),0))
|
||||
UQADD8 r7, r7, r11
|
||||
UQSUB8 r9, r9, r11
|
||||
UQSUB8 r7, r7, r5 ; r7 = p5+lflim(R_i,L)
|
||||
STRD r6, [r0, -r1] ; [p5:p1] = [r7: r6]
|
||||
UQADD8 r9, r9, r5 ; r9 = p6-lflim(R_i,L)
|
||||
STRD r8, [r0] ; [p6:p2] = [r9: r8]
|
||||
LDMFD r13!,{r4-r11,PC}
|
||||
|
||||
oc_loop_filter_frag_rows_v6
|
||||
; r0 = _ref_frame_data
|
||||
; r1 = _ystride
|
||||
; r2 = _bv
|
||||
; r3 = _frags
|
||||
; r4 = _fragi0
|
||||
; r5 = _fragi0_end
|
||||
; r6 = _fragi_top
|
||||
; r7 = _fragi_bot
|
||||
; r8 = _frag_buf_offs
|
||||
; r9 = _nhfrags
|
||||
MOV r12,r13
|
||||
STMFD r13!,{r0,r4-r11,r14}
|
||||
LDMFD r12,{r4-r9}
|
||||
LDR r2, [r2] ; ll = *(int *)_bv
|
||||
CMP r4, r5 ; if(_fragi0>=_fragi0_end)
|
||||
BGE oslffri_v6_end ; bail
|
||||
SUBS r9, r9, #1 ; r9 = _nhfrags-1 if (r9<=0)
|
||||
BLE oslffri_v6_end ; bail
|
||||
ADD r3, r3, r4, LSL #2 ; r3 = &_frags[fragi]
|
||||
ADD r8, r8, r4, LSL #2 ; r8 = &_frag_buf_offs[fragi]
|
||||
SUB r7, r7, r9 ; _fragi_bot -= _nhfrags;
|
||||
oslffri_v6_lp1
|
||||
MOV r10,r4 ; r10= fragi = _fragi0
|
||||
ADD r11,r4, r9 ; r11= fragi_end-1=fragi+_nhfrags-1
|
||||
oslffri_v6_lp2
|
||||
LDR r14,[r3], #4 ; r14= _frags[fragi] _frags++
|
||||
LDR r0, [r13] ; r0 = _ref_frame_data
|
||||
LDR r12,[r8], #4 ; r12= _frag_buf_offs[fragi] _frag_buf_offs++
|
||||
TST r14,#OC_FRAG_CODED_FLAG
|
||||
BEQ oslffri_v6_uncoded
|
||||
CMP r10,r4 ; if (fragi>_fragi0)
|
||||
ADD r0, r0, r12 ; r0 = _ref_frame_data + _frag_buf_offs[fragi]
|
||||
BLGT loop_filter_h_v6
|
||||
CMP r4, r6 ; if (fragi0>_fragi_top)
|
||||
BLGT loop_filter_v_v6
|
||||
CMP r10,r11 ; if(fragi+1<fragi_end)===(fragi<fragi_end-1)
|
||||
LDRLT r12,[r3] ; r12 = _frags[fragi+1]
|
||||
ADD r0, r0, #8
|
||||
ADD r10,r10,#1 ; r10 = fragi+1;
|
||||
ANDLT r12,r12,#OC_FRAG_CODED_FLAG
|
||||
CMPLT r12,#OC_FRAG_CODED_FLAG ; && _frags[fragi+1].coded==0
|
||||
BLLT loop_filter_h_v6
|
||||
CMP r10,r7 ; if (fragi<_fragi_bot)
|
||||
LDRLT r12,[r3, r9, LSL #2] ; r12 = _frags[fragi+1+_nhfrags-1]
|
||||
SUB r0, r0, #8
|
||||
ADD r0, r0, r1, LSL #3
|
||||
ANDLT r12,r12,#OC_FRAG_CODED_FLAG
|
||||
CMPLT r12,#OC_FRAG_CODED_FLAG
|
||||
BLLT loop_filter_v_v6
|
||||
CMP r10,r11 ; while(fragi<=fragi_end-1)
|
||||
BLE oslffri_v6_lp2
|
||||
MOV r4, r10 ; r4 = fragi0 += nhfrags
|
||||
CMP r4, r5
|
||||
BLT oslffri_v6_lp1
|
||||
oslffri_v6_end
|
||||
LDMFD r13!,{r0,r4-r11,PC}
|
||||
oslffri_v6_uncoded
|
||||
ADD r10,r10,#1
|
||||
CMP r10,r11
|
||||
BLE oslffri_v6_lp2
|
||||
MOV r4, r10 ; r4 = fragi0 += nhfrags
|
||||
CMP r4, r5
|
||||
BLT oslffri_v6_lp1
|
||||
LDMFD r13!,{r0,r4-r11,PC}
|
||||
]
|
||||
|
||||
[ OC_ARM_ASM_NEON
|
||||
EXPORT oc_loop_filter_init_neon
|
||||
EXPORT oc_loop_filter_frag_rows_neon
|
||||
|
||||
oc_loop_filter_init_neon
|
||||
; r0 = _bv
|
||||
; r1 = _flimit (=L from the spec)
|
||||
MOV r1, r1, LSL #1 ; r1 = 2*L
|
||||
VDUP.S16 Q15, r1 ; Q15= 2L in U16s
|
||||
VST1.64 {D30,D31}, [r0@128]
|
||||
MOV PC,r14
|
||||
|
||||
loop_filter_h_neon
|
||||
; r0 = unsigned char *_pix
|
||||
; r1 = int _ystride
|
||||
; r2 = int *_bv
|
||||
; preserves r0-r3
|
||||
; We assume Q15= 2*L in U16s
|
||||
; My best guesses at cycle counts (and latency)--vvv
|
||||
SUB r12,r0, #2
|
||||
; Doing a 2-element structure load saves doing two VTRN's below, at the
|
||||
; cost of using two more slower single-lane loads vs. the faster
|
||||
; all-lane loads.
|
||||
; It's less code this way, though, and benches a hair faster, but it
|
||||
; leaves D2 and D4 swapped.
|
||||
VLD2.16 {D0[],D2[]}, [r12], r1 ; D0 = ____________1100 2,1
|
||||
; D2 = ____________3322
|
||||
VLD2.16 {D4[],D6[]}, [r12], r1 ; D4 = ____________5544 2,1
|
||||
; D6 = ____________7766
|
||||
VLD2.16 {D0[1],D2[1]},[r12], r1 ; D0 = ________99881100 3,1
|
||||
; D2 = ________BBAA3322
|
||||
VLD2.16 {D4[1],D6[1]},[r12], r1 ; D4 = ________DDCC5544 3,1
|
||||
; D6 = ________FFEE7766
|
||||
VLD2.16 {D0[2],D2[2]},[r12], r1 ; D0 = ____GGHH99881100 3,1
|
||||
; D2 = ____JJIIBBAA3322
|
||||
VLD2.16 {D4[2],D6[2]},[r12], r1 ; D4 = ____KKLLDDCC5544 3,1
|
||||
; D6 = ____NNMMFFEE7766
|
||||
VLD2.16 {D0[3],D2[3]},[r12], r1 ; D0 = PPOOGGHH99881100 3,1
|
||||
; D2 = RRQQJJIIBBAA3322
|
||||
VLD2.16 {D4[3],D6[3]},[r12], r1 ; D4 = TTSSKKLLDDCC5544 3,1
|
||||
; D6 = VVUUNNMMFFEE7766
|
||||
VTRN.8 D0, D4 ; D0 = SSOOKKGGCC884400 D4 = TTPPLLHHDD995511 1,1
|
||||
VTRN.8 D2, D6 ; D2 = UUQQMMIIEEAA6622 D6 = VVRRNNJJFFBB7733 1,1
|
||||
VSUBL.U8 Q0, D0, D6 ; Q0 = 00 - 33 in S16s 1,3
|
||||
VSUBL.U8 Q8, D2, D4 ; Q8 = 22 - 11 in S16s 1,3
|
||||
ADD r12,r0, #8
|
||||
VADD.S16 Q0, Q0, Q8 ; 1,3
|
||||
PLD [r12]
|
||||
VADD.S16 Q0, Q0, Q8 ; 1,3
|
||||
PLD [r12,r1]
|
||||
VADD.S16 Q0, Q0, Q8 ; Q0 = [0-3]+3*[2-1] 1,3
|
||||
PLD [r12,r1, LSL #1]
|
||||
VRSHR.S16 Q0, Q0, #3 ; Q0 = f = ([0-3]+3*[2-1]+4)>>3 1,4
|
||||
ADD r12,r12,r1, LSL #2
|
||||
; We want to do
|
||||
; f = CLAMP(MIN(-2L-f,0), f, MAX(2L-f,0))
|
||||
; = ((f >= 0) ? MIN( f ,MAX(2L- f ,0)) : MAX( f , MIN(-2L- f ,0)))
|
||||
; = ((f >= 0) ? MIN(|f|,MAX(2L-|f|,0)) : MAX(-|f|, MIN(-2L+|f|,0)))
|
||||
; = ((f >= 0) ? MIN(|f|,MAX(2L-|f|,0)) :-MIN( |f|,-MIN(-2L+|f|,0)))
|
||||
; = ((f >= 0) ? MIN(|f|,MAX(2L-|f|,0)) :-MIN( |f|, MAX( 2L-|f|,0)))
|
||||
; So we've reduced the left and right hand terms to be the same, except
|
||||
; for a negation.
|
||||
; Stall x3
|
||||
VABS.S16 Q9, Q0 ; Q9 = |f| in U16s 1,4
|
||||
PLD [r12,-r1]
|
||||
VSHR.S16 Q0, Q0, #15 ; Q0 = -1 or 0 according to sign 1,3
|
||||
PLD [r12]
|
||||
VQSUB.U16 Q10,Q15,Q9 ; Q10= MAX(2L-|f|,0) in U16s 1,4
|
||||
PLD [r12,r1]
|
||||
VMOVL.U8 Q1, D2 ; Q2 = __UU__QQ__MM__II__EE__AA__66__22 2,3
|
||||
PLD [r12,r1,LSL #1]
|
||||
VMIN.U16 Q9, Q10,Q9 ; Q9 = MIN(|f|,MAX(2L-|f|)) 1,4
|
||||
ADD r12,r12,r1, LSL #2
|
||||
; Now we need to correct for the sign of f.
|
||||
; For negative elements of Q0, we want to subtract the appropriate
|
||||
; element of Q9. For positive elements we want to add them. No NEON
|
||||
; instruction exists to do this, so we need to negate the negative
|
||||
; elements, and we can then just add them. a-b = a-(1+!b) = a-1+!b
|
||||
VADD.S16 Q9, Q9, Q0 ; 1,3
|
||||
PLD [r12,-r1]
|
||||
VEOR.S16 Q9, Q9, Q0 ; Q9 = real value of f 1,3
|
||||
; Bah. No VRSBW.U8
|
||||
; Stall (just 1 as Q9 not needed to second pipeline stage. I think.)
|
||||
VADDW.U8 Q2, Q9, D4 ; Q1 = xxTTxxPPxxLLxxHHxxDDxx99xx55xx11 1,3
|
||||
VSUB.S16 Q1, Q1, Q9 ; Q2 = xxUUxxQQxxMMxxIIxxEExxAAxx66xx22 1,3
|
||||
VQMOVUN.S16 D4, Q2 ; D4 = TTPPLLHHDD995511 1,1
|
||||
VQMOVUN.S16 D2, Q1 ; D2 = UUQQMMIIEEAA6622 1,1
|
||||
SUB r12,r0, #1
|
||||
VTRN.8 D4, D2 ; D4 = QQPPIIHHAA992211 D2 = MMLLEEDD6655 1,1
|
||||
VST1.16 {D4[0]}, [r12], r1
|
||||
VST1.16 {D2[0]}, [r12], r1
|
||||
VST1.16 {D4[1]}, [r12], r1
|
||||
VST1.16 {D2[1]}, [r12], r1
|
||||
VST1.16 {D4[2]}, [r12], r1
|
||||
VST1.16 {D2[2]}, [r12], r1
|
||||
VST1.16 {D4[3]}, [r12], r1
|
||||
VST1.16 {D2[3]}, [r12], r1
|
||||
MOV PC,r14
|
||||
|
||||
loop_filter_v_neon
|
||||
; r0 = unsigned char *_pix
|
||||
; r1 = int _ystride
|
||||
; r2 = int *_bv
|
||||
; preserves r0-r3
|
||||
; We assume Q15= 2*L in U16s
|
||||
; My best guesses at cycle counts (and latency)--vvv
|
||||
SUB r12,r0, r1, LSL #1
|
||||
VLD1.64 {D0}, [r12@64], r1 ; D0 = SSOOKKGGCC884400 2,1
|
||||
VLD1.64 {D2}, [r12@64], r1 ; D2 = TTPPLLHHDD995511 2,1
|
||||
VLD1.64 {D4}, [r12@64], r1 ; D4 = UUQQMMIIEEAA6622 2,1
|
||||
VLD1.64 {D6}, [r12@64] ; D6 = VVRRNNJJFFBB7733 2,1
|
||||
VSUBL.U8 Q8, D4, D2 ; Q8 = 22 - 11 in S16s 1,3
|
||||
VSUBL.U8 Q0, D0, D6 ; Q0 = 00 - 33 in S16s 1,3
|
||||
ADD r12, #8
|
||||
VADD.S16 Q0, Q0, Q8 ; 1,3
|
||||
PLD [r12]
|
||||
VADD.S16 Q0, Q0, Q8 ; 1,3
|
||||
PLD [r12,r1]
|
||||
VADD.S16 Q0, Q0, Q8 ; Q0 = [0-3]+3*[2-1] 1,3
|
||||
SUB r12, r0, r1
|
||||
VRSHR.S16 Q0, Q0, #3 ; Q0 = f = ([0-3]+3*[2-1]+4)>>3 1,4
|
||||
; We want to do
|
||||
; f = CLAMP(MIN(-2L-f,0), f, MAX(2L-f,0))
|
||||
; = ((f >= 0) ? MIN( f ,MAX(2L- f ,0)) : MAX( f , MIN(-2L- f ,0)))
|
||||
; = ((f >= 0) ? MIN(|f|,MAX(2L-|f|,0)) : MAX(-|f|, MIN(-2L+|f|,0)))
|
||||
; = ((f >= 0) ? MIN(|f|,MAX(2L-|f|,0)) :-MIN( |f|,-MIN(-2L+|f|,0)))
|
||||
; = ((f >= 0) ? MIN(|f|,MAX(2L-|f|,0)) :-MIN( |f|, MAX( 2L-|f|,0)))
|
||||
; So we've reduced the left and right hand terms to be the same, except
|
||||
; for a negation.
|
||||
; Stall x3
|
||||
VABS.S16 Q9, Q0 ; Q9 = |f| in U16s 1,4
|
||||
VSHR.S16 Q0, Q0, #15 ; Q0 = -1 or 0 according to sign 1,3
|
||||
; Stall x2
|
||||
VQSUB.U16 Q10,Q15,Q9 ; Q10= MAX(2L-|f|,0) in U16s 1,4
|
||||
VMOVL.U8 Q2, D4 ; Q2 = __UU__QQ__MM__II__EE__AA__66__22 2,3
|
||||
; Stall x2
|
||||
VMIN.U16 Q9, Q10,Q9 ; Q9 = MIN(|f|,MAX(2L-|f|)) 1,4
|
||||
; Now we need to correct for the sign of f.
|
||||
; For negative elements of Q0, we want to subtract the appropriate
|
||||
; element of Q9. For positive elements we want to add them. No NEON
|
||||
; instruction exists to do this, so we need to negate the negative
|
||||
; elements, and we can then just add them. a-b = a-(1+!b) = a-1+!b
|
||||
; Stall x3
|
||||
VADD.S16 Q9, Q9, Q0 ; 1,3
|
||||
; Stall x2
|
||||
VEOR.S16 Q9, Q9, Q0 ; Q9 = real value of f 1,3
|
||||
; Bah. No VRSBW.U8
|
||||
; Stall (just 1 as Q9 not needed to second pipeline stage. I think.)
|
||||
VADDW.U8 Q1, Q9, D2 ; Q1 = xxTTxxPPxxLLxxHHxxDDxx99xx55xx11 1,3
|
||||
VSUB.S16 Q2, Q2, Q9 ; Q2 = xxUUxxQQxxMMxxIIxxEExxAAxx66xx22 1,3
|
||||
VQMOVUN.S16 D2, Q1 ; D2 = TTPPLLHHDD995511 1,1
|
||||
VQMOVUN.S16 D4, Q2 ; D4 = UUQQMMIIEEAA6622 1,1
|
||||
VST1.64 {D2}, [r12@64], r1
|
||||
VST1.64 {D4}, [r12@64], r1
|
||||
MOV PC,r14
|
||||
|
||||
oc_loop_filter_frag_rows_neon
|
||||
; r0 = _ref_frame_data
|
||||
; r1 = _ystride
|
||||
; r2 = _bv
|
||||
; r3 = _frags
|
||||
; r4 = _fragi0
|
||||
; r5 = _fragi0_end
|
||||
; r6 = _fragi_top
|
||||
; r7 = _fragi_bot
|
||||
; r8 = _frag_buf_offs
|
||||
; r9 = _nhfrags
|
||||
MOV r12,r13
|
||||
STMFD r13!,{r0,r4-r11,r14}
|
||||
LDMFD r12,{r4-r9}
|
||||
CMP r4, r5 ; if(_fragi0>=_fragi0_end)
|
||||
BGE oslffri_neon_end; bail
|
||||
SUBS r9, r9, #1 ; r9 = _nhfrags-1 if (r9<=0)
|
||||
BLE oslffri_neon_end ; bail
|
||||
VLD1.64 {D30,D31}, [r2@128] ; Q15= 2L in U16s
|
||||
ADD r3, r3, r4, LSL #2 ; r3 = &_frags[fragi]
|
||||
ADD r8, r8, r4, LSL #2 ; r8 = &_frag_buf_offs[fragi]
|
||||
SUB r7, r7, r9 ; _fragi_bot -= _nhfrags;
|
||||
oslffri_neon_lp1
|
||||
MOV r10,r4 ; r10= fragi = _fragi0
|
||||
ADD r11,r4, r9 ; r11= fragi_end-1=fragi+_nhfrags-1
|
||||
oslffri_neon_lp2
|
||||
LDR r14,[r3], #4 ; r14= _frags[fragi] _frags++
|
||||
LDR r0, [r13] ; r0 = _ref_frame_data
|
||||
LDR r12,[r8], #4 ; r12= _frag_buf_offs[fragi] _frag_buf_offs++
|
||||
TST r14,#OC_FRAG_CODED_FLAG
|
||||
BEQ oslffri_neon_uncoded
|
||||
CMP r10,r4 ; if (fragi>_fragi0)
|
||||
ADD r0, r0, r12 ; r0 = _ref_frame_data + _frag_buf_offs[fragi]
|
||||
BLGT loop_filter_h_neon
|
||||
CMP r4, r6 ; if (_fragi0>_fragi_top)
|
||||
BLGT loop_filter_v_neon
|
||||
CMP r10,r11 ; if(fragi+1<fragi_end)===(fragi<fragi_end-1)
|
||||
LDRLT r12,[r3] ; r12 = _frags[fragi+1]
|
||||
ADD r0, r0, #8
|
||||
ADD r10,r10,#1 ; r10 = fragi+1;
|
||||
ANDLT r12,r12,#OC_FRAG_CODED_FLAG
|
||||
CMPLT r12,#OC_FRAG_CODED_FLAG ; && _frags[fragi+1].coded==0
|
||||
BLLT loop_filter_h_neon
|
||||
CMP r10,r7 ; if (fragi<_fragi_bot)
|
||||
LDRLT r12,[r3, r9, LSL #2] ; r12 = _frags[fragi+1+_nhfrags-1]
|
||||
SUB r0, r0, #8
|
||||
ADD r0, r0, r1, LSL #3
|
||||
ANDLT r12,r12,#OC_FRAG_CODED_FLAG
|
||||
CMPLT r12,#OC_FRAG_CODED_FLAG
|
||||
BLLT loop_filter_v_neon
|
||||
CMP r10,r11 ; while(fragi<=fragi_end-1)
|
||||
BLE oslffri_neon_lp2
|
||||
MOV r4, r10 ; r4 = _fragi0 += _nhfrags
|
||||
CMP r4, r5
|
||||
BLT oslffri_neon_lp1
|
||||
oslffri_neon_end
|
||||
LDMFD r13!,{r0,r4-r11,PC}
|
||||
oslffri_neon_uncoded
|
||||
ADD r10,r10,#1
|
||||
CMP r10,r11
|
||||
BLE oslffri_neon_lp2
|
||||
MOV r4, r10 ; r4 = _fragi0 += _nhfrags
|
||||
CMP r4, r5
|
||||
BLT oslffri_neon_lp1
|
||||
LDMFD r13!,{r0,r4-r11,PC}
|
||||
]
|
||||
|
||||
END
|
||||
@@ -0,0 +1,39 @@
|
||||
;********************************************************************
|
||||
;* *
|
||||
;* 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-2010 *
|
||||
;* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
;* *
|
||||
;********************************************************************
|
||||
; Original implementation:
|
||||
; Copyright (C) 2009 Robin Watts for Pinknoise Productions Ltd
|
||||
; last mod: $Id$
|
||||
;********************************************************************
|
||||
|
||||
; Set the following to 1 if we have EDSP instructions
|
||||
; (LDRD/STRD, etc., ARMv5E and later).
|
||||
OC_ARM_ASM_EDSP * @HAVE_ARM_ASM_EDSP@
|
||||
|
||||
; Set the following to 1 if we have ARMv6 media instructions.
|
||||
OC_ARM_ASM_MEDIA * @HAVE_ARM_ASM_MEDIA@
|
||||
|
||||
; Set the following to 1 if we have NEON (some ARMv7)
|
||||
OC_ARM_ASM_NEON * @HAVE_ARM_ASM_NEON@
|
||||
|
||||
; Set the following to 1 if LDR/STR can work on unaligned addresses
|
||||
; This is assumed to be true for ARMv6 and later code
|
||||
OC_ARM_CAN_UNALIGN * 0
|
||||
|
||||
; Large unaligned loads and stores are often configured to cause an exception.
|
||||
; They cause an 8 cycle stall when they cross a 128-bit (load) or 64-bit (store)
|
||||
; boundary, so it's usually a bad idea to use them anyway if they can be
|
||||
; avoided.
|
||||
|
||||
; Set the following to 1 if LDRD/STRD can work on unaligned addresses
|
||||
OC_ARM_CAN_UNALIGN_LDRD * 0
|
||||
|
||||
END
|
||||
@@ -0,0 +1,231 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2010 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: x86state.c 17344 2010-07-21 01:42:18Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
#include "armint.h"
|
||||
|
||||
#if defined(OC_ARM_ASM)
|
||||
|
||||
# if defined(OC_ARM_ASM_NEON)
|
||||
/*This table has been modified from OC_FZIG_ZAG by baking an 8x8 transpose into
|
||||
the destination.*/
|
||||
static const unsigned char OC_FZIG_ZAG_NEON[128]={
|
||||
0, 8, 1, 2, 9,16,24,17,
|
||||
10, 3, 4,11,18,25,32,40,
|
||||
33,26,19,12, 5, 6,13,20,
|
||||
27,34,41,48,56,49,42,35,
|
||||
28,21,14, 7,15,22,29,36,
|
||||
43,50,57,58,51,44,37,30,
|
||||
23,31,38,45,52,59,60,53,
|
||||
46,39,47,54,61,62,55,63,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64
|
||||
};
|
||||
# endif
|
||||
|
||||
void oc_state_accel_init_arm(oc_theora_state *_state){
|
||||
oc_state_accel_init_c(_state);
|
||||
_state->cpu_flags=oc_cpu_flags_get();
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
_state->opt_vtable.frag_copy_list=oc_frag_copy_list_arm;
|
||||
_state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_arm;
|
||||
_state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_arm;
|
||||
_state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_arm;
|
||||
_state->opt_vtable.idct8x8=oc_idct8x8_arm;
|
||||
_state->opt_vtable.state_frag_recon=oc_state_frag_recon_arm;
|
||||
/*Note: We _must_ set this function pointer, because the macro in armint.h
|
||||
calls it with different arguments, so the C version will segfault.*/
|
||||
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||
(oc_state_loop_filter_frag_rows_func)oc_loop_filter_frag_rows_arm;
|
||||
# endif
|
||||
# if defined(OC_ARM_ASM_EDSP)
|
||||
if(_state->cpu_flags&OC_CPU_ARM_EDSP){
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
_state->opt_vtable.frag_copy_list=oc_frag_copy_list_edsp;
|
||||
# endif
|
||||
}
|
||||
# if defined(OC_ARM_ASM_MEDIA)
|
||||
if(_state->cpu_flags&OC_CPU_ARM_MEDIA){
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
_state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_v6;
|
||||
_state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_v6;
|
||||
_state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_v6;
|
||||
_state->opt_vtable.idct8x8=oc_idct8x8_v6;
|
||||
_state->opt_vtable.state_frag_recon=oc_state_frag_recon_v6;
|
||||
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_v6;
|
||||
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||
(oc_state_loop_filter_frag_rows_func)oc_loop_filter_frag_rows_v6;
|
||||
# endif
|
||||
}
|
||||
# if defined(OC_ARM_ASM_NEON)
|
||||
if(_state->cpu_flags&OC_CPU_ARM_NEON){
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
_state->opt_vtable.frag_copy_list=oc_frag_copy_list_neon;
|
||||
_state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_neon;
|
||||
_state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_neon;
|
||||
_state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_neon;
|
||||
_state->opt_vtable.state_frag_recon=oc_state_frag_recon_neon;
|
||||
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_neon;
|
||||
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||
(oc_state_loop_filter_frag_rows_func)oc_loop_filter_frag_rows_neon;
|
||||
_state->opt_vtable.idct8x8=oc_idct8x8_neon;
|
||||
# endif
|
||||
_state->opt_data.dct_fzig_zag=OC_FZIG_ZAG_NEON;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
void oc_state_frag_recon_arm(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant){
|
||||
unsigned char *dst;
|
||||
ptrdiff_t frag_buf_off;
|
||||
int ystride;
|
||||
int mb_mode;
|
||||
/*Apply the inverse transform.*/
|
||||
/*Special case only having a DC component.*/
|
||||
if(_last_zzi<2){
|
||||
ogg_uint16_t p;
|
||||
/*We round this dequant product (and not any of the others) because there's
|
||||
no iDCT rounding.*/
|
||||
p=(ogg_uint16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
|
||||
oc_idct8x8_1_arm(_dct_coeffs+64,p);
|
||||
}
|
||||
else{
|
||||
/*First, dequantize the DC coefficient.*/
|
||||
_dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
|
||||
oc_idct8x8_arm(_dct_coeffs+64,_dct_coeffs,_last_zzi);
|
||||
}
|
||||
/*Fill in the target buffer.*/
|
||||
frag_buf_off=_state->frag_buf_offs[_fragi];
|
||||
mb_mode=_state->frags[_fragi].mb_mode;
|
||||
ystride=_state->ref_ystride[_pli];
|
||||
dst=_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_SELF]]+frag_buf_off;
|
||||
if(mb_mode==OC_MODE_INTRA){
|
||||
oc_frag_recon_intra_arm(dst,ystride,_dct_coeffs+64);
|
||||
}
|
||||
else{
|
||||
const unsigned char *ref;
|
||||
int mvoffsets[2];
|
||||
ref=
|
||||
_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_FOR_MODE(mb_mode)]]
|
||||
+frag_buf_off;
|
||||
if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
|
||||
_state->frag_mvs[_fragi])>1){
|
||||
oc_frag_recon_inter2_arm(dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,
|
||||
_dct_coeffs+64);
|
||||
}
|
||||
else oc_frag_recon_inter_arm(dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
|
||||
}
|
||||
}
|
||||
|
||||
# if defined(OC_ARM_ASM_MEDIA)
|
||||
void oc_state_frag_recon_v6(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant){
|
||||
unsigned char *dst;
|
||||
ptrdiff_t frag_buf_off;
|
||||
int ystride;
|
||||
int mb_mode;
|
||||
/*Apply the inverse transform.*/
|
||||
/*Special case only having a DC component.*/
|
||||
if(_last_zzi<2){
|
||||
ogg_uint16_t p;
|
||||
/*We round this dequant product (and not any of the others) because there's
|
||||
no iDCT rounding.*/
|
||||
p=(ogg_uint16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
|
||||
oc_idct8x8_1_v6(_dct_coeffs+64,p);
|
||||
}
|
||||
else{
|
||||
/*First, dequantize the DC coefficient.*/
|
||||
_dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
|
||||
oc_idct8x8_v6(_dct_coeffs+64,_dct_coeffs,_last_zzi);
|
||||
}
|
||||
/*Fill in the target buffer.*/
|
||||
frag_buf_off=_state->frag_buf_offs[_fragi];
|
||||
mb_mode=_state->frags[_fragi].mb_mode;
|
||||
ystride=_state->ref_ystride[_pli];
|
||||
dst=_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_SELF]]+frag_buf_off;
|
||||
if(mb_mode==OC_MODE_INTRA){
|
||||
oc_frag_recon_intra_v6(dst,ystride,_dct_coeffs+64);
|
||||
}
|
||||
else{
|
||||
const unsigned char *ref;
|
||||
int mvoffsets[2];
|
||||
ref=
|
||||
_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_FOR_MODE(mb_mode)]]
|
||||
+frag_buf_off;
|
||||
if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
|
||||
_state->frag_mvs[_fragi])>1){
|
||||
oc_frag_recon_inter2_v6(dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,
|
||||
_dct_coeffs+64);
|
||||
}
|
||||
else oc_frag_recon_inter_v6(dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
|
||||
}
|
||||
}
|
||||
|
||||
# if defined(OC_ARM_ASM_NEON)
|
||||
void oc_state_frag_recon_neon(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant){
|
||||
unsigned char *dst;
|
||||
ptrdiff_t frag_buf_off;
|
||||
int ystride;
|
||||
int mb_mode;
|
||||
/*Apply the inverse transform.*/
|
||||
/*Special case only having a DC component.*/
|
||||
if(_last_zzi<2){
|
||||
ogg_uint16_t p;
|
||||
/*We round this dequant product (and not any of the others) because there's
|
||||
no iDCT rounding.*/
|
||||
p=(ogg_uint16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
|
||||
oc_idct8x8_1_neon(_dct_coeffs+64,p);
|
||||
}
|
||||
else{
|
||||
/*First, dequantize the DC coefficient.*/
|
||||
_dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
|
||||
oc_idct8x8_neon(_dct_coeffs+64,_dct_coeffs,_last_zzi);
|
||||
}
|
||||
/*Fill in the target buffer.*/
|
||||
frag_buf_off=_state->frag_buf_offs[_fragi];
|
||||
mb_mode=_state->frags[_fragi].mb_mode;
|
||||
ystride=_state->ref_ystride[_pli];
|
||||
dst=_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_SELF]]+frag_buf_off;
|
||||
if(mb_mode==OC_MODE_INTRA){
|
||||
oc_frag_recon_intra_neon(dst,ystride,_dct_coeffs+64);
|
||||
}
|
||||
else{
|
||||
const unsigned char *ref;
|
||||
int mvoffsets[2];
|
||||
ref=
|
||||
_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_FOR_MODE(mb_mode)]]
|
||||
+frag_buf_off;
|
||||
if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
|
||||
_state->frag_mvs[_fragi])>1){
|
||||
oc_frag_recon_inter2_neon(dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,
|
||||
_dct_coeffs+64);
|
||||
}
|
||||
else oc_frag_recon_inter_neon(dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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 OggTheora SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: packing variable sized words into an octet stream
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "bitpack.h"
|
||||
|
||||
/*We're 'MSb' endian; if we write a word but read individual bits,
|
||||
then we'll read the MSb first.*/
|
||||
|
||||
void oc_pack_readinit(oc_pack_buf *_b,unsigned char *_buf,long _bytes){
|
||||
memset(_b,0,sizeof(*_b));
|
||||
_b->ptr=_buf;
|
||||
_b->stop=_buf+_bytes;
|
||||
}
|
||||
|
||||
static oc_pb_window oc_pack_refill(oc_pack_buf *_b,int _bits){
|
||||
const unsigned char *ptr;
|
||||
const unsigned char *stop;
|
||||
oc_pb_window window;
|
||||
int available;
|
||||
unsigned shift;
|
||||
stop=_b->stop;
|
||||
ptr=_b->ptr;
|
||||
window=_b->window;
|
||||
available=_b->bits;
|
||||
shift=OC_PB_WINDOW_SIZE-available;
|
||||
while(7<shift&&ptr<stop){
|
||||
shift-=8;
|
||||
window|=(oc_pb_window)*ptr++<<shift;
|
||||
}
|
||||
_b->ptr=ptr;
|
||||
available=OC_PB_WINDOW_SIZE-shift;
|
||||
if(_bits>available){
|
||||
if(ptr>=stop){
|
||||
_b->eof=1;
|
||||
available=OC_LOTS_OF_BITS;
|
||||
}
|
||||
else window|=*ptr>>(available&7);
|
||||
}
|
||||
_b->bits=available;
|
||||
return window;
|
||||
}
|
||||
|
||||
int oc_pack_look1(oc_pack_buf *_b){
|
||||
oc_pb_window window;
|
||||
int available;
|
||||
window=_b->window;
|
||||
available=_b->bits;
|
||||
if(available<1)_b->window=window=oc_pack_refill(_b,1);
|
||||
return window>>OC_PB_WINDOW_SIZE-1;
|
||||
}
|
||||
|
||||
void oc_pack_adv1(oc_pack_buf *_b){
|
||||
_b->window<<=1;
|
||||
_b->bits--;
|
||||
}
|
||||
|
||||
/*Here we assume that 0<=_bits&&_bits<=32.*/
|
||||
long oc_pack_read_c(oc_pack_buf *_b,int _bits){
|
||||
oc_pb_window window;
|
||||
int available;
|
||||
long result;
|
||||
window=_b->window;
|
||||
available=_b->bits;
|
||||
if(_bits==0)return 0;
|
||||
if(available<_bits){
|
||||
window=oc_pack_refill(_b,_bits);
|
||||
available=_b->bits;
|
||||
}
|
||||
result=window>>OC_PB_WINDOW_SIZE-_bits;
|
||||
available-=_bits;
|
||||
window<<=1;
|
||||
window<<=_bits-1;
|
||||
_b->window=window;
|
||||
_b->bits=available;
|
||||
return result;
|
||||
}
|
||||
|
||||
int oc_pack_read1_c(oc_pack_buf *_b){
|
||||
oc_pb_window window;
|
||||
int available;
|
||||
int result;
|
||||
window=_b->window;
|
||||
available=_b->bits;
|
||||
if(available<1){
|
||||
window=oc_pack_refill(_b,1);
|
||||
available=_b->bits;
|
||||
}
|
||||
result=window>>OC_PB_WINDOW_SIZE-1;
|
||||
available--;
|
||||
window<<=1;
|
||||
_b->window=window;
|
||||
_b->bits=available;
|
||||
return result;
|
||||
}
|
||||
|
||||
long oc_pack_bytes_left(oc_pack_buf *_b){
|
||||
if(_b->eof)return -1;
|
||||
return _b->stop-_b->ptr+(_b->bits>>3);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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 OggTheora SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: packing variable sized words into an octet stream
|
||||
last mod: $Id: bitwise.c 7675 2004-09-01 00:34:39Z xiphmont $
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_bitpack_H)
|
||||
# define _bitpack_H (1)
|
||||
# include <stddef.h>
|
||||
# include <limits.h>
|
||||
|
||||
|
||||
|
||||
typedef size_t oc_pb_window;
|
||||
typedef struct oc_pack_buf oc_pack_buf;
|
||||
|
||||
|
||||
|
||||
/*Custom bitpacker implementations.*/
|
||||
# if defined(OC_ARM_ASM)
|
||||
# include "arm/armbits.h"
|
||||
# endif
|
||||
|
||||
# if !defined(oc_pack_read)
|
||||
# define oc_pack_read oc_pack_read_c
|
||||
# endif
|
||||
# if !defined(oc_pack_read1)
|
||||
# define oc_pack_read1 oc_pack_read1_c
|
||||
# endif
|
||||
# if !defined(oc_huff_token_decode)
|
||||
# define oc_huff_token_decode oc_huff_token_decode_c
|
||||
# endif
|
||||
|
||||
# define OC_PB_WINDOW_SIZE ((int)sizeof(oc_pb_window)*CHAR_BIT)
|
||||
/*This is meant to be a large, positive constant that can still be efficiently
|
||||
loaded as an immediate (on platforms like ARM, for example).
|
||||
Even relatively modest values like 100 would work fine.*/
|
||||
# define OC_LOTS_OF_BITS (0x40000000)
|
||||
|
||||
|
||||
|
||||
struct oc_pack_buf{
|
||||
const unsigned char *stop;
|
||||
const unsigned char *ptr;
|
||||
oc_pb_window window;
|
||||
int bits;
|
||||
int eof;
|
||||
};
|
||||
|
||||
void oc_pack_readinit(oc_pack_buf *_b,unsigned char *_buf,long _bytes);
|
||||
int oc_pack_look1(oc_pack_buf *_b);
|
||||
void oc_pack_adv1(oc_pack_buf *_b);
|
||||
/*Here we assume 0<=_bits&&_bits<=32.*/
|
||||
long oc_pack_read_c(oc_pack_buf *_b,int _bits);
|
||||
int oc_pack_read1_c(oc_pack_buf *_b);
|
||||
/* returns -1 for read beyond EOF, or the number of whole bytes available */
|
||||
long oc_pack_bytes_left(oc_pack_buf *_b);
|
||||
|
||||
/*These two functions are implemented locally in huffdec.c*/
|
||||
/*Read in bits without advancing the bitptr.
|
||||
Here we assume 0<=_bits&&_bits<=32.*/
|
||||
/*static int oc_pack_look(oc_pack_buf *_b,int _bits);*/
|
||||
/*static void oc_pack_adv(oc_pack_buf *_b,int _bits);*/
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,934 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: mode selection code
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "collect.h"
|
||||
|
||||
#if defined(OC_COLLECT_METRICS)
|
||||
|
||||
int OC_HAS_MODE_METRICS;
|
||||
double OC_MODE_RD_WEIGHT[OC_LOGQ_BINS][3][2][OC_SAD_BINS];
|
||||
oc_mode_metrics OC_MODE_METRICS[OC_LOGQ_BINS-1][3][2][OC_SAD_BINS];
|
||||
const char *OC_MODE_METRICS_FILENAME="modedec.stats";
|
||||
|
||||
void oc_mode_metrics_add(oc_mode_metrics *_metrics,
|
||||
double _w,int _s,int _q,int _r,double _d){
|
||||
if(_metrics->w>0){
|
||||
double ds;
|
||||
double dq;
|
||||
double dr;
|
||||
double dd;
|
||||
double ds2;
|
||||
double dq2;
|
||||
double s2;
|
||||
double sq;
|
||||
double q2;
|
||||
double sr;
|
||||
double qr;
|
||||
double sd;
|
||||
double qd;
|
||||
double s2q;
|
||||
double sq2;
|
||||
double w;
|
||||
double wa;
|
||||
double rwa;
|
||||
double rwa2;
|
||||
double rwb;
|
||||
double rwb2;
|
||||
double rw2;
|
||||
double rw3;
|
||||
double rw4;
|
||||
wa=_metrics->w;
|
||||
ds=_s-_metrics->s/wa;
|
||||
dq=_q-_metrics->q/wa;
|
||||
dr=_r-_metrics->r/wa;
|
||||
dd=_d-_metrics->d/wa;
|
||||
ds2=ds*ds;
|
||||
dq2=dq*dq;
|
||||
s2=_metrics->s2;
|
||||
sq=_metrics->sq;
|
||||
q2=_metrics->q2;
|
||||
sr=_metrics->sr;
|
||||
qr=_metrics->qr;
|
||||
sd=_metrics->sd;
|
||||
qd=_metrics->qd;
|
||||
s2q=_metrics->s2q;
|
||||
sq2=_metrics->sq2;
|
||||
w=wa+_w;
|
||||
rwa=wa/w;
|
||||
rwb=_w/w;
|
||||
rwa2=rwa*rwa;
|
||||
rwb2=rwb*rwb;
|
||||
rw2=wa*rwb;
|
||||
rw3=rw2*(rwa2-rwb2);
|
||||
rw4=_w*rwa2*rwa2+wa*rwb2*rwb2;
|
||||
_metrics->s2q2+=-2*(ds*sq2+dq*s2q)*rwb
|
||||
+(ds2*q2+4*ds*dq*sq+dq2*s2)*rwb2+ds2*dq2*rw4;
|
||||
_metrics->s2q+=(-2*ds*sq-dq*s2)*rwb+ds2*dq*rw3;
|
||||
_metrics->sq2+=(-ds*q2-2*dq*sq)*rwb+ds*dq2*rw3;
|
||||
_metrics->sqr+=(-ds*qr-dq*sr-dr*sq)*rwb+ds*dq*dr*rw3;
|
||||
_metrics->sqd+=(-ds*qd-dq*sd-dd*sq)*rwb+ds*dq*dd*rw3;
|
||||
_metrics->s2+=ds2*rw2;
|
||||
_metrics->sq+=ds*dq*rw2;
|
||||
_metrics->q2+=dq2*rw2;
|
||||
_metrics->sr+=ds*dr*rw2;
|
||||
_metrics->qr+=dq*dr*rw2;
|
||||
_metrics->r2+=dr*dr*rw2;
|
||||
_metrics->sd+=ds*dd*rw2;
|
||||
_metrics->qd+=dq*dd*rw2;
|
||||
_metrics->d2+=dd*dd*rw2;
|
||||
}
|
||||
_metrics->w+=_w;
|
||||
_metrics->s+=_s*_w;
|
||||
_metrics->q+=_q*_w;
|
||||
_metrics->r+=_r*_w;
|
||||
_metrics->d+=_d*_w;
|
||||
}
|
||||
|
||||
void oc_mode_metrics_merge(oc_mode_metrics *_dst,
|
||||
const oc_mode_metrics *_src,int _n){
|
||||
int i;
|
||||
/*Find a non-empty set of metrics.*/
|
||||
for(i=0;i<_n&&_src[i].w==0;i++);
|
||||
if(i>=_n){
|
||||
memset(_dst,0,sizeof(*_dst));
|
||||
return;
|
||||
}
|
||||
memcpy(_dst,_src+i,sizeof(*_dst));
|
||||
/*And iterate over the remaining non-empty sets of metrics.*/
|
||||
for(i++;i<_n;i++)if(_src[i].w!=0){
|
||||
double ds;
|
||||
double dq;
|
||||
double dr;
|
||||
double dd;
|
||||
double ds2;
|
||||
double dq2;
|
||||
double s2a;
|
||||
double s2b;
|
||||
double sqa;
|
||||
double sqb;
|
||||
double q2a;
|
||||
double q2b;
|
||||
double sra;
|
||||
double srb;
|
||||
double qra;
|
||||
double qrb;
|
||||
double sda;
|
||||
double sdb;
|
||||
double qda;
|
||||
double qdb;
|
||||
double s2qa;
|
||||
double s2qb;
|
||||
double sq2a;
|
||||
double sq2b;
|
||||
double w;
|
||||
double wa;
|
||||
double wb;
|
||||
double rwa;
|
||||
double rwb;
|
||||
double rwa2;
|
||||
double rwb2;
|
||||
double rw2;
|
||||
double rw3;
|
||||
double rw4;
|
||||
wa=_dst->w;
|
||||
wb=_src[i].w;
|
||||
ds=_src[i].s/wb-_dst->s/wa;
|
||||
dq=_src[i].q/wb-_dst->q/wa;
|
||||
dr=_src[i].r/wb-_dst->r/wa;
|
||||
dd=_src[i].d/wb-_dst->d/wa;
|
||||
ds2=ds*ds;
|
||||
dq2=dq*dq;
|
||||
s2a=_dst->s2;
|
||||
sqa=_dst->sq;
|
||||
q2a=_dst->q2;
|
||||
sra=_dst->sr;
|
||||
qra=_dst->qr;
|
||||
sda=_dst->sd;
|
||||
qda=_dst->qd;
|
||||
s2qa=_dst->s2q;
|
||||
sq2a=_dst->sq2;
|
||||
s2b=_src[i].s2;
|
||||
sqb=_src[i].sq;
|
||||
q2b=_src[i].q2;
|
||||
srb=_src[i].sr;
|
||||
qrb=_src[i].qr;
|
||||
sdb=_src[i].sd;
|
||||
qdb=_src[i].qd;
|
||||
s2qb=_src[i].s2q;
|
||||
sq2b=_src[i].sq2;
|
||||
w=wa+wb;
|
||||
if(w==0)rwa=rwb=0;
|
||||
else{
|
||||
rwa=wa/w;
|
||||
rwb=wb/w;
|
||||
}
|
||||
rwa2=rwa*rwa;
|
||||
rwb2=rwb*rwb;
|
||||
rw2=wa*rwb;
|
||||
rw3=rw2*(rwa2-rwb2);
|
||||
rw4=wb*rwa2*rwa2+wa*rwb2*rwb2;
|
||||
/*
|
||||
(1,1,1) ->
|
||||
(0,0,0)#
|
||||
(1,0,0) C(1,1)*C(1,0)*C(1,0)-> d^{1,0,0}*(rwa*B_{0,1,1}-rwb*A_{0,1,1})
|
||||
(0,1,0) C(1,0)*C(1,1)*C(1,0)-> d^{0,1,0}*(rwa*B_{1,0,1}-rwb*A_{1,0,1})
|
||||
(0,0,1) C(1,0)*C(1,0)*C(1,1)-> d^{0,0,1}*(rwa*B_{1,1,0}-rwb*A_{1,1,0})
|
||||
(1,1,0)*
|
||||
(1,0,1)*
|
||||
(0,1,1)*
|
||||
(1,1,1) C(1,1)*C(1,1)*C(1,1)-> d^{1,1,1}*(rwa^3*wb-rwb^3*wa)
|
||||
(2,1) ->
|
||||
(0,0)#
|
||||
(1,0) C(2,1)*C(1,1)->2*d^{1,0}*(rwa*B_{1,1}-rwb*A_{1,1})
|
||||
(0,1) C(2,0)*C(1,1)-> d^{0,1}*(rwa*B_{2,0}-rwb*A_{2,0})
|
||||
(2,0)*
|
||||
(1,1)*
|
||||
(2,1) C(2,2)*C(1,1)-> d^{2,1}*(rwa^3*wb-rwb^3*wa)
|
||||
(2,2) ->
|
||||
(0,0)#
|
||||
(1,0) C(2,1)*C(2,0)->2*d^{1,0}*(rwa*B_{1,2}-rwb*A_{1,2})
|
||||
(0,1) C(2,0)*C(2,1)->2*d^{0,1}*(rwa*B_{2,1}-rwb*A_{2,1})
|
||||
(2,0) C(2,2)*C(2,0)-> d^{2,0}*(rwa^2*B_{0,2}+rwb^2*A_{0,2})
|
||||
(1,1) C(2,1)*C(2,1)->4*d^{1,1}*(rwa^2*B_{1,1}+rwb^2*A_{1,1})
|
||||
(0,2) C(2,0)*C(2,2)-> d^{0,2}*(rwa^2*B_{2,0}+rwb^2*A_{2,0})
|
||||
(1,2)*
|
||||
(2,1)*
|
||||
(2,2) C(2,2)*C(2,2)*d^{2,2}*(rwa^4*wb+rwb^4*wa)
|
||||
*/
|
||||
_dst->s2q2+=_src[i].s2q2+2*(ds*(rwa*sq2b-rwb*sq2a)+dq*(rwa*s2qb-rwb*s2qa))
|
||||
+ds2*(rwa2*q2b+rwb2*q2a)+4*ds*dq*(rwa2*sqb+rwb2*sqa)
|
||||
+dq2*(rwa2*s2b+rwb2*s2a)+ds2*dq2*rw4;
|
||||
_dst->s2q+=_src[i].s2q+2*ds*(rwa*sqb-rwb*sqa)
|
||||
+dq*(rwa*s2b-rwb*s2a)+ds2*dq*rw3;
|
||||
_dst->sq2+=_src[i].sq2+ds*(rwa*q2b-rwb*q2a)
|
||||
+2*dq*(rwa*sqb-rwb*sqa)+ds*dq2*rw3;
|
||||
_dst->sqr+=_src[i].sqr+ds*(rwa*qrb-rwb*qra)+dq*(rwa*srb-rwb*sra)
|
||||
+dr*(rwa*sqb-rwb*sqa)+ds*dq*dr*rw3;
|
||||
_dst->sqd+=_src[i].sqd+ds*(rwa*qdb-rwb*qda)+dq*(rwa*sdb-rwb*sda)
|
||||
+dd*(rwa*sqb-rwb*sqa)+ds*dq*dd*rw3;
|
||||
_dst->s2+=_src[i].s2+ds2*rw2;
|
||||
_dst->sq+=_src[i].sq+ds*dq*rw2;
|
||||
_dst->q2+=_src[i].q2+dq2*rw2;
|
||||
_dst->sr+=_src[i].sr+ds*dr*rw2;
|
||||
_dst->qr+=_src[i].qr+dq*dr*rw2;
|
||||
_dst->r2+=_src[i].r2+dr*dr*rw2;
|
||||
_dst->sd+=_src[i].sd+ds*dd*rw2;
|
||||
_dst->qd+=_src[i].qd+dq*dd*rw2;
|
||||
_dst->d2+=_src[i].d2+dd*dd*rw2;
|
||||
_dst->w+=_src[i].w;
|
||||
_dst->s+=_src[i].s;
|
||||
_dst->q+=_src[i].q;
|
||||
_dst->r+=_src[i].r;
|
||||
_dst->d+=_src[i].d;
|
||||
}
|
||||
}
|
||||
|
||||
/*Adjust a single corner of a set of metric bins to minimize the squared
|
||||
prediction error of R and D.
|
||||
Each bin is assumed to cover a quad like so:
|
||||
(s0,q0) (s1,q0)
|
||||
A----------B
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
C----------Z
|
||||
(s0,q1) (s1,q1)
|
||||
The values A, B, and C are fixed, and Z is the free parameter.
|
||||
Then, for example, R_i is predicted via bilinear interpolation as
|
||||
x_i=(s_i-s0)/(s1-s0)
|
||||
y_i=(q_i-q0)/(q1-q0)
|
||||
dRds1_i=A+(B-A)*x_i
|
||||
dRds2_i=C+(Z-C)*x_i
|
||||
R_i=dRds1_i+(dRds2_i-dRds1_i)*y_i
|
||||
To find the Z that minimizes the squared prediction error over i, this can
|
||||
be rewritten as
|
||||
R_i-(A+(B-A)*x_i+(C-A)*y_i+(A-B-C)*x_i*y_i)=x_i*y_i*Z
|
||||
Letting X={...,x_i*y_i,...}^T and
|
||||
Y={...,R_i-(A+(B-A)*x_i+(C-A)*y_i+(A-B-C)*x_i*y_i),...}^T,
|
||||
the optimal Z is given by Z=(X^T.Y)/(X^T.X).
|
||||
Now, we need to compute these dot products without actually storing data for
|
||||
each sample.
|
||||
Starting with X^T.X, we have
|
||||
X^T.X = sum(x_i^2*y_i^2) = sum((s_i-s0)^2*(q_i-q0)^2)/((s1-s0)^2*(q1-q0)^2).
|
||||
Expanding the interior of the sum in a monomial basis of s_i and q_i gives
|
||||
s0^2*q0^2 *(1)
|
||||
-2*s0*q0^2*(s_i)
|
||||
-2*s0^2*q0*(q_i)
|
||||
+q0^2 *(s_i^2)
|
||||
+4*s0*q0 *(s_i*q_i)
|
||||
+s0^2 *(q_i^2)
|
||||
-2*q0 *(s_i^2*q_i)
|
||||
-2*s0 *(s_i*q_i^2)
|
||||
+1 *(s_i^2*q_i^2).
|
||||
However, computing things directly in this basis leads to gross numerical
|
||||
errors, as most of the terms will have similar size and destructive
|
||||
cancellation results.
|
||||
A much better basis is the central (co-)moment basis:
|
||||
{1,s_i-sbar,q_i-qbar,(s_i-sbar)^2,(s_i-sbar)*(q_i-qbar),(q_i-qbar)^2,
|
||||
(s_i-sbar)^2*(q_i-qbar),(s_i-sbar)*(q_i-qbar)^2,(s_i-sbar)^2*(q_i-qbar)^2},
|
||||
where sbar and qbar are the average s and q values over the bin,
|
||||
respectively.
|
||||
In that basis, letting ds=sbar-s0 and dq=qbar-q0, (s_i-s0)^2*(q_i-q0)^2 is
|
||||
ds^2*dq^2*(1)
|
||||
+dq^2 *((s_i-sbar)^2)
|
||||
+4*ds*dq*((s_i-sbar)*(q_i-qbar))
|
||||
+ds^2 *((q_i-qbar)^2)
|
||||
+2*dq *((s_i-sbar)^2*(q_i-qbar))
|
||||
+2*ds *((s_i-sbar)*(q_i-qbar)^2)
|
||||
+1 *((s_i-sbar)^2*(q_i-qbar)^2).
|
||||
With these expressions in the central (co-)moment bases, all we need to do
|
||||
is compute sums over the (co-)moment terms, which can be done
|
||||
incrementally (see oc_mode_metrics_add() and oc_mode_metrics_merge()),
|
||||
with no need to store the individual samples.
|
||||
Now, for X^T.Y, we have
|
||||
X^T.Y = sum((R_i-A-((B-A)/(s1-s0))*(s_i-s0)-((C-A)/(q1-q0))*(q_i-q0)
|
||||
-((A-B-C)/((s1-s0)*(q1-q0)))*(s_i-s0)*(q_i-q0))*(s_i-s0)*(q_i-q0))/
|
||||
((s1-s0)*(q1-q0)),
|
||||
or, rewriting the constants to simplify notation,
|
||||
X^T.Y = sum((C0+C1*(s_i-s0)+C2*(q_i-q0)
|
||||
+C3*(s_i-s0)*(q_i-q0)+R_i)*(s_i-s0)*(q_i-q0))/((s1-s0)*(q1-q0)).
|
||||
Again, converting to the central (co-)moment basis, the interior of the
|
||||
above sum is
|
||||
ds*dq*(rbar+C0+C1*ds+C2*dq+C3*ds*dq) *(1)
|
||||
+(C1*dq+C3*dq^2) *((s_i-sbar)^2)
|
||||
+(rbar+C0+2*C1*ds+2*C2*dq+4*C3*ds*dq)*((s_i-sbar)*(q_i-qbar))
|
||||
+(C2*ds+C3*ds^2) *((q_i-qbar)^2)
|
||||
+dq *((s_i-sbar)*(r_i-rbar))
|
||||
+ds *((q_i-qbar)*(r_i-rbar))
|
||||
+(C1+2*C3*dq) *((s_i-sbar)^2*(q_i-qbar))
|
||||
+(C2+2*C3*ds) *((s_i-sbar)*(q_i-qbar)^2)
|
||||
+1 *((s_i-sbar)*(q_i-qbar)*(r_i-rbar))
|
||||
+C3 *((s_i-sbar)^2*(q_i-qbar)^2).
|
||||
You might think it would be easier (if perhaps slightly less robust) to
|
||||
accumulate terms directly around s0 and q0.
|
||||
However, we update each corner of the bins in turn, so we would have to
|
||||
change basis to move the sums from corner to corner anyway.*/
|
||||
double oc_mode_metrics_solve(double *_r,double *_d,
|
||||
const oc_mode_metrics *_metrics,const int *_s0,const int *_s1,
|
||||
const int *_q0,const int *_q1,
|
||||
const double *_ra,const double *_rb,const double *_rc,
|
||||
const double *_da,const double *_db,const double *_dc,int _n){
|
||||
double xx;
|
||||
double rxy;
|
||||
double dxy;
|
||||
double wt;
|
||||
int i;
|
||||
xx=rxy=dxy=wt=0;
|
||||
for(i=0;i<_n;i++)if(_metrics[i].w>0){
|
||||
double s10;
|
||||
double q10;
|
||||
double sq10;
|
||||
double ds;
|
||||
double dq;
|
||||
double ds2;
|
||||
double dq2;
|
||||
double r;
|
||||
double d;
|
||||
double s2;
|
||||
double sq;
|
||||
double q2;
|
||||
double sr;
|
||||
double qr;
|
||||
double sd;
|
||||
double qd;
|
||||
double s2q;
|
||||
double sq2;
|
||||
double sqr;
|
||||
double sqd;
|
||||
double s2q2;
|
||||
double c0;
|
||||
double c1;
|
||||
double c2;
|
||||
double c3;
|
||||
double w;
|
||||
w=_metrics[i].w;
|
||||
wt+=w;
|
||||
s10=_s1[i]-_s0[i];
|
||||
q10=_q1[i]-_q0[i];
|
||||
sq10=s10*q10;
|
||||
ds=_metrics[i].s/w-_s0[i];
|
||||
dq=_metrics[i].q/w-_q0[i];
|
||||
ds2=ds*ds;
|
||||
dq2=dq*dq;
|
||||
s2=_metrics[i].s2;
|
||||
sq=_metrics[i].sq;
|
||||
q2=_metrics[i].q2;
|
||||
s2q=_metrics[i].s2q;
|
||||
sq2=_metrics[i].sq2;
|
||||
s2q2=_metrics[i].s2q2;
|
||||
xx+=(dq2*(ds2*w+s2)+4*ds*dq*sq+ds2*q2+2*(dq*s2q+ds*sq2)+s2q2)/(sq10*sq10);
|
||||
r=_metrics[i].r/w;
|
||||
sr=_metrics[i].sr;
|
||||
qr=_metrics[i].qr;
|
||||
sqr=_metrics[i].sqr;
|
||||
c0=-_ra[i];
|
||||
c1=-(_rb[i]-_ra[i])/s10;
|
||||
c2=-(_rc[i]-_ra[i])/q10;
|
||||
c3=-(_ra[i]-_rb[i]-_rc[i])/sq10;
|
||||
rxy+=(ds*dq*(r+c0+c1*ds+c2*dq+c3*ds*dq)*w+(c1*dq+c3*dq2)*s2
|
||||
+(r+c0+2*(c1*ds+(c2+2*c3*ds)*dq))*sq+(c2*ds+c3*ds2)*q2+dq*sr+ds*qr
|
||||
+(c1+2*c3*dq)*s2q+(c2+2*c3*ds)*sq2+sqr+c3*s2q2)/sq10;
|
||||
d=_metrics[i].d/w;
|
||||
sd=_metrics[i].sd;
|
||||
qd=_metrics[i].qd;
|
||||
sqd=_metrics[i].sqd;
|
||||
c0=-_da[i];
|
||||
c1=-(_db[i]-_da[i])/s10;
|
||||
c2=-(_dc[i]-_da[i])/q10;
|
||||
c3=-(_da[i]-_db[i]-_dc[i])/sq10;
|
||||
dxy+=(ds*dq*(d+c0+c1*ds+c2*dq+c3*ds*dq)*w+(c1*dq+c3*dq2)*s2
|
||||
+(d+c0+2*(c1*ds+(c2+2*c3*ds)*dq))*sq+(c2*ds+c3*ds2)*q2+dq*sd+ds*qd
|
||||
+(c1+2*c3*dq)*s2q+(c2+2*c3*ds)*sq2+sqd+c3*s2q2)/sq10;
|
||||
}
|
||||
if(xx>1E-3){
|
||||
*_r=rxy/xx;
|
||||
*_d=dxy/xx;
|
||||
}
|
||||
else{
|
||||
*_r=0;
|
||||
*_d=0;
|
||||
}
|
||||
return wt;
|
||||
}
|
||||
|
||||
/*Compile collected SATD/logq/rate/RMSE metrics into a form that's immediately
|
||||
useful for mode decision.*/
|
||||
void oc_mode_metrics_update(int _niters_min,int _reweight){
|
||||
int niters;
|
||||
int prevdr;
|
||||
int prevdd;
|
||||
int dr;
|
||||
int dd;
|
||||
int pli;
|
||||
int qti;
|
||||
int qi;
|
||||
int si;
|
||||
dd=dr=INT_MAX;
|
||||
niters=0;
|
||||
/*The encoder interpolates rate and RMSE terms bilinearly from an
|
||||
OC_LOGQ_BINS by OC_SAD_BINS grid of sample points in OC_MODE_RD.
|
||||
To find the sample values at the grid points that minimize the total
|
||||
squared prediction error actually requires solving a relatively sparse
|
||||
linear system with a number of variables equal to the number of grid
|
||||
points.
|
||||
Instead of writing a general sparse linear system solver, we just use
|
||||
Gauss-Seidel iteration, i.e., we update one grid point at time until
|
||||
they stop changing.*/
|
||||
do{
|
||||
prevdr=dr;
|
||||
prevdd=dd;
|
||||
dd=dr=0;
|
||||
for(pli=0;pli<3;pli++){
|
||||
for(qti=0;qti<2;qti++){
|
||||
for(qi=0;qi<OC_LOGQ_BINS;qi++){
|
||||
for(si=0;si<OC_SAD_BINS;si++){
|
||||
oc_mode_metrics m[4];
|
||||
int s0[4];
|
||||
int s1[4];
|
||||
int q0[4];
|
||||
int q1[4];
|
||||
double ra[4];
|
||||
double rb[4];
|
||||
double rc[4];
|
||||
double da[4];
|
||||
double db[4];
|
||||
double dc[4];
|
||||
double r;
|
||||
double d;
|
||||
int rate;
|
||||
int rmse;
|
||||
int ds;
|
||||
int n;
|
||||
n=0;
|
||||
/*Collect the statistics for the (up to) four bins grid point
|
||||
(si,qi) touches.*/
|
||||
if(qi>0&&si>0){
|
||||
q0[n]=OC_MODE_LOGQ[qi-1][pli][qti];
|
||||
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
|
||||
s0[n]=si-1<<OC_SAD_SHIFT;
|
||||
s1[n]=si<<OC_SAD_SHIFT;
|
||||
ra[n]=ldexp(OC_MODE_RD[qi-1][pli][qti][si-1].rate,-OC_BIT_SCALE);
|
||||
da[n]=ldexp(OC_MODE_RD[qi-1][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
|
||||
rb[n]=ldexp(OC_MODE_RD[qi-1][pli][qti][si].rate,-OC_BIT_SCALE);
|
||||
db[n]=ldexp(OC_MODE_RD[qi-1][pli][qti][si].rmse,-OC_RMSE_SCALE);
|
||||
rc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si-1].rate,-OC_BIT_SCALE);
|
||||
dc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
|
||||
*(m+n++)=*(OC_MODE_METRICS[qi-1][pli][qti]+si-1);
|
||||
}
|
||||
if(qi>0){
|
||||
ds=si+1<OC_SAD_BINS?1:-1;
|
||||
q0[n]=OC_MODE_LOGQ[qi-1][pli][qti];
|
||||
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
|
||||
s0[n]=si+ds<<OC_SAD_SHIFT;
|
||||
s1[n]=si<<OC_SAD_SHIFT;
|
||||
ra[n]=ldexp(OC_MODE_RD[qi-1][pli][qti][si+ds].rate,-OC_BIT_SCALE);
|
||||
da[n]=
|
||||
ldexp(OC_MODE_RD[qi-1][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
|
||||
rb[n]=ldexp(OC_MODE_RD[qi-1][pli][qti][si].rate,-OC_BIT_SCALE);
|
||||
db[n]=ldexp(OC_MODE_RD[qi-1][pli][qti][si].rmse,-OC_RMSE_SCALE);
|
||||
rc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si+ds].rate,-OC_BIT_SCALE);
|
||||
dc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
|
||||
*(m+n++)=*(OC_MODE_METRICS[qi-1][pli][qti]+si);
|
||||
}
|
||||
if(qi+1<OC_LOGQ_BINS&&si>0){
|
||||
q0[n]=OC_MODE_LOGQ[qi+1][pli][qti];
|
||||
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
|
||||
s0[n]=si-1<<OC_SAD_SHIFT;
|
||||
s1[n]=si<<OC_SAD_SHIFT;
|
||||
ra[n]=ldexp(OC_MODE_RD[qi+1][pli][qti][si-1].rate,-OC_BIT_SCALE);
|
||||
da[n]=ldexp(OC_MODE_RD[qi+1][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
|
||||
rb[n]=ldexp(OC_MODE_RD[qi+1][pli][qti][si].rate,-OC_BIT_SCALE);
|
||||
db[n]=ldexp(OC_MODE_RD[qi+1][pli][qti][si].rmse,-OC_RMSE_SCALE);
|
||||
rc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si-1].rate,-OC_BIT_SCALE);
|
||||
dc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
|
||||
*(m+n++)=*(OC_MODE_METRICS[qi][pli][qti]+si-1);
|
||||
}
|
||||
if(qi+1<OC_LOGQ_BINS){
|
||||
ds=si+1<OC_SAD_BINS?1:-1;
|
||||
q0[n]=OC_MODE_LOGQ[qi+1][pli][qti];
|
||||
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
|
||||
s0[n]=si+ds<<OC_SAD_SHIFT;
|
||||
s1[n]=si<<OC_SAD_SHIFT;
|
||||
ra[n]=ldexp(OC_MODE_RD[qi+1][pli][qti][si+ds].rate,-OC_BIT_SCALE);
|
||||
da[n]=
|
||||
ldexp(OC_MODE_RD[qi+1][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
|
||||
rb[n]=ldexp(OC_MODE_RD[qi+1][pli][qti][si].rate,-OC_BIT_SCALE);
|
||||
db[n]=ldexp(OC_MODE_RD[qi+1][pli][qti][si].rmse,-OC_RMSE_SCALE);
|
||||
rc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si+ds].rate,-OC_BIT_SCALE);
|
||||
dc[n]=ldexp(OC_MODE_RD[qi][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
|
||||
*(m+n++)=*(OC_MODE_METRICS[qi][pli][qti]+si);
|
||||
}
|
||||
/*On the first pass, initialize with a simple weighted average of
|
||||
the neighboring bins.*/
|
||||
if(!OC_HAS_MODE_METRICS&&niters==0){
|
||||
double w;
|
||||
w=r=d=0;
|
||||
while(n-->0){
|
||||
w+=m[n].w;
|
||||
r+=m[n].r;
|
||||
d+=m[n].d;
|
||||
}
|
||||
r=w>1E-3?r/w:0;
|
||||
d=w>1E-3?d/w:0;
|
||||
OC_MODE_RD_WEIGHT[qi][pli][qti][si]=w;
|
||||
}
|
||||
else{
|
||||
/*Update the grid point and save the weight for later.*/
|
||||
OC_MODE_RD_WEIGHT[qi][pli][qti][si]=
|
||||
oc_mode_metrics_solve(&r,&d,m,s0,s1,q0,q1,ra,rb,rc,da,db,dc,n);
|
||||
}
|
||||
rate=OC_CLAMPI(-32768,(int)(ldexp(r,OC_BIT_SCALE)+0.5),32767);
|
||||
rmse=OC_CLAMPI(-32768,(int)(ldexp(d,OC_RMSE_SCALE)+0.5),32767);
|
||||
dr+=abs(rate-OC_MODE_RD[qi][pli][qti][si].rate);
|
||||
dd+=abs(rmse-OC_MODE_RD[qi][pli][qti][si].rmse);
|
||||
OC_MODE_RD[qi][pli][qti][si].rate=(ogg_int16_t)rate;
|
||||
OC_MODE_RD[qi][pli][qti][si].rmse=(ogg_int16_t)rmse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*After a fixed number of initial iterations, only iterate so long as the
|
||||
total change is decreasing.
|
||||
This ensures we don't oscillate forever, which is a danger, as all of our
|
||||
results are rounded fairly coarsely.*/
|
||||
while((dr>0||dd>0)&&(niters++<_niters_min||(dr<prevdr&&dd<prevdd)));
|
||||
if(_reweight){
|
||||
/*Now, reduce the values of the optimal solution until we get enough
|
||||
samples in each bin to overcome the constant OC_ZWEIGHT factor.
|
||||
This encourages sampling under-populated bins and prevents a single large
|
||||
sample early on from discouraging coding in that bin ever again.*/
|
||||
for(pli=0;pli<3;pli++){
|
||||
for(qti=0;qti<2;qti++){
|
||||
for(qi=0;qi<OC_LOGQ_BINS;qi++){
|
||||
for(si=0;si<OC_SAD_BINS;si++){
|
||||
double wt;
|
||||
wt=OC_MODE_RD_WEIGHT[qi][pli][qti][si];
|
||||
wt/=OC_ZWEIGHT+wt;
|
||||
OC_MODE_RD[qi][pli][qti][si].rate=(ogg_int16_t)
|
||||
(OC_MODE_RD[qi][pli][qti][si].rate*wt+0.5);
|
||||
OC_MODE_RD[qi][pli][qti][si].rmse=(ogg_int16_t)
|
||||
(OC_MODE_RD[qi][pli][qti][si].rmse*wt+0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void oc_mode_metrics_dump(void){
|
||||
FILE *fmetrics;
|
||||
fmetrics=fopen(OC_MODE_METRICS_FILENAME,"wb");
|
||||
if(fmetrics!=NULL){
|
||||
(void)fwrite(OC_MODE_METRICS,sizeof(OC_MODE_METRICS),1,fmetrics);
|
||||
(void)fwrite(OC_MODE_LOGQ,sizeof(OC_MODE_LOGQ),1,fmetrics);
|
||||
fclose(fmetrics);
|
||||
}
|
||||
}
|
||||
|
||||
void oc_mode_metrics_print(FILE *_fout){
|
||||
int qii;
|
||||
fprintf(_fout,
|
||||
"/*File generated by libtheora with OC_COLLECT_METRICS"
|
||||
" defined at compile time.*/\n"
|
||||
"#if !defined(_modedec_H)\n"
|
||||
"# define _modedec_H (1)\n"
|
||||
"# include \"encint.h\"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"/*The log of the average quantizer for each of the OC_MODE_RD table rows\n"
|
||||
" (e.g., for the represented qi's, and each pli and qti), in Q10 format.\n"
|
||||
" The actual statistics used by the encoder will be interpolated from\n"
|
||||
" that table based on log_plq for the actual quantization matrix used.*/\n"
|
||||
"# if !defined(OC_COLLECT_METRICS)\n"
|
||||
"static const\n"
|
||||
"# endif\n"
|
||||
"ogg_int16_t OC_MODE_LOGQ[OC_LOGQ_BINS][3][2]={\n");
|
||||
for(qii=0;qii<OC_LOGQ_BINS;qii++){
|
||||
fprintf(_fout," { {0x%04X,0x%04X},{0x%04X,0x%04X},{0x%04X,0x%04X} }%s\n",
|
||||
OC_MODE_LOGQ[qii][0][0],OC_MODE_LOGQ[qii][0][1],OC_MODE_LOGQ[qii][1][0],
|
||||
OC_MODE_LOGQ[qii][1][1],OC_MODE_LOGQ[qii][2][0],OC_MODE_LOGQ[qii][2][1],
|
||||
qii+1<OC_LOGQ_BINS?",":"");
|
||||
}
|
||||
fprintf(_fout,
|
||||
"};\n"
|
||||
"\n"
|
||||
"# if !defined(OC_COLLECT_METRICS)\n"
|
||||
"static const\n"
|
||||
"# endif\n"
|
||||
"oc_mode_rd OC_MODE_RD[OC_LOGQ_BINS][3][2][OC_SAD_BINS]={\n");
|
||||
for(qii=0;qii<OC_LOGQ_BINS;qii++){
|
||||
int pli;
|
||||
fprintf(_fout," {\n");
|
||||
for(pli=0;pli<3;pli++){
|
||||
int qti;
|
||||
fprintf(_fout," {\n");
|
||||
for(qti=0;qti<2;qti++){
|
||||
int bin;
|
||||
int qi;
|
||||
static const char *pl_names[3]={"Y'","Cb","Cr"};
|
||||
static const char *qti_names[2]={"INTRA","INTER"};
|
||||
qi=(63*qii+(OC_LOGQ_BINS-1>>1))/(OC_LOGQ_BINS-1);
|
||||
fprintf(_fout," /*%s qi=%i %s*/\n",
|
||||
pl_names[pli],qi,qti_names[qti]);
|
||||
fprintf(_fout," {\n");
|
||||
fprintf(_fout," ");
|
||||
for(bin=0;bin<OC_SAD_BINS;bin++){
|
||||
if(bin&&!(bin&0x3))fprintf(_fout,"\n ");
|
||||
fprintf(_fout,"{%5i,%5i}",
|
||||
OC_MODE_RD[qii][pli][qti][bin].rate,
|
||||
OC_MODE_RD[qii][pli][qti][bin].rmse);
|
||||
if(bin+1<OC_SAD_BINS)fprintf(_fout,",");
|
||||
}
|
||||
fprintf(_fout,"\n }");
|
||||
if(qti<1)fprintf(_fout,",");
|
||||
fprintf(_fout,"\n");
|
||||
}
|
||||
fprintf(_fout," }");
|
||||
if(pli<2)fprintf(_fout,",");
|
||||
fprintf(_fout,"\n");
|
||||
}
|
||||
fprintf(_fout," }");
|
||||
if(qii+1<OC_LOGQ_BINS)fprintf(_fout,",");
|
||||
fprintf(_fout,"\n");
|
||||
}
|
||||
fprintf(_fout,
|
||||
"};\n"
|
||||
"\n"
|
||||
"#endif\n");
|
||||
}
|
||||
|
||||
|
||||
# if !defined(OC_COLLECT_NO_ENC_FUNCS)
|
||||
void oc_enc_mode_metrics_load(oc_enc_ctx *_enc){
|
||||
oc_restore_fpu(&_enc->state);
|
||||
/*Load any existing mode metrics if we haven't already.*/
|
||||
if(!OC_HAS_MODE_METRICS){
|
||||
FILE *fmetrics;
|
||||
memset(OC_MODE_METRICS,0,sizeof(OC_MODE_METRICS));
|
||||
fmetrics=fopen(OC_MODE_METRICS_FILENAME,"rb");
|
||||
if(fmetrics!=NULL){
|
||||
(void)fread(OC_MODE_METRICS,sizeof(OC_MODE_METRICS),1,fmetrics);
|
||||
(void)fread(OC_MODE_LOGQ,sizeof(OC_MODE_LOGQ),1,fmetrics);
|
||||
fclose(fmetrics);
|
||||
}
|
||||
else{
|
||||
int qii;
|
||||
int qi;
|
||||
int pli;
|
||||
int qti;
|
||||
for(qii=0;qii<OC_LOGQ_BINS;qii++){
|
||||
qi=(63*qii+(OC_LOGQ_BINS-1>>1))/(OC_LOGQ_BINS-1);
|
||||
for(pli=0;pli<3;pli++)for(qti=0;qti<2;qti++){
|
||||
OC_MODE_LOGQ[qii][pli][qti]=_enc->log_plq[qi][pli][qti];
|
||||
}
|
||||
}
|
||||
}
|
||||
oc_mode_metrics_update(100,1);
|
||||
OC_HAS_MODE_METRICS=1;
|
||||
}
|
||||
}
|
||||
|
||||
/*The following token skipping code used to also be used in the decoder (and
|
||||
even at one point other places in the encoder).
|
||||
However, it was obsoleted by other optimizations, and is now only used here.
|
||||
It has been moved here to avoid generating the code when it's not needed.*/
|
||||
|
||||
/*Determines the number of blocks or coefficients to be skipped for a given
|
||||
token value.
|
||||
_token: The token value to skip.
|
||||
_extra_bits: The extra bits attached to this token.
|
||||
Return: A positive value indicates that number of coefficients are to be
|
||||
skipped in the current block.
|
||||
Otherwise, the negative of the return value indicates that number of
|
||||
blocks are to be ended.*/
|
||||
typedef ptrdiff_t (*oc_token_skip_func)(int _token,int _extra_bits);
|
||||
|
||||
/*Handles the simple end of block tokens.*/
|
||||
static ptrdiff_t oc_token_skip_eob(int _token,int _extra_bits){
|
||||
int nblocks_adjust;
|
||||
nblocks_adjust=OC_UNIBBLE_TABLE32(0,1,2,3,7,15,0,0,_token)+1;
|
||||
return -_extra_bits-nblocks_adjust;
|
||||
}
|
||||
|
||||
/*The last EOB token has a special case, where an EOB run of size zero ends all
|
||||
the remaining blocks in the frame.*/
|
||||
static ptrdiff_t oc_token_skip_eob6(int _token,int _extra_bits){
|
||||
/*Note: We want to return -PTRDIFF_MAX, but that requires C99, which is not
|
||||
yet available everywhere; this should be equivalent.*/
|
||||
if(!_extra_bits)return -(~(size_t)0>>1);
|
||||
return -_extra_bits;
|
||||
}
|
||||
|
||||
/*Handles the pure zero run tokens.*/
|
||||
static ptrdiff_t oc_token_skip_zrl(int _token,int _extra_bits){
|
||||
return _extra_bits+1;
|
||||
}
|
||||
|
||||
/*Handles a normal coefficient value token.*/
|
||||
static ptrdiff_t oc_token_skip_val(void){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*Handles a category 1A zero run/coefficient value combo token.*/
|
||||
static ptrdiff_t oc_token_skip_run_cat1a(int _token){
|
||||
return _token-OC_DCT_RUN_CAT1A+2;
|
||||
}
|
||||
|
||||
/*Handles category 1b, 1c, 2a, and 2b zero run/coefficient value combo tokens.*/
|
||||
static ptrdiff_t oc_token_skip_run(int _token,int _extra_bits){
|
||||
int run_cati;
|
||||
int ncoeffs_mask;
|
||||
int ncoeffs_adjust;
|
||||
run_cati=_token-OC_DCT_RUN_CAT1B;
|
||||
ncoeffs_mask=OC_BYTE_TABLE32(3,7,0,1,run_cati);
|
||||
ncoeffs_adjust=OC_BYTE_TABLE32(7,11,2,3,run_cati);
|
||||
return (_extra_bits&ncoeffs_mask)+ncoeffs_adjust;
|
||||
}
|
||||
|
||||
/*A jump table for computing the number of coefficients or blocks to skip for
|
||||
a given token value.
|
||||
This reduces all the conditional branches, etc., needed to parse these token
|
||||
values down to one indirect jump.*/
|
||||
static const oc_token_skip_func OC_TOKEN_SKIP_TABLE[TH_NDCT_TOKENS]={
|
||||
oc_token_skip_eob,
|
||||
oc_token_skip_eob,
|
||||
oc_token_skip_eob,
|
||||
oc_token_skip_eob,
|
||||
oc_token_skip_eob,
|
||||
oc_token_skip_eob,
|
||||
oc_token_skip_eob6,
|
||||
oc_token_skip_zrl,
|
||||
oc_token_skip_zrl,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_val,
|
||||
(oc_token_skip_func)oc_token_skip_run_cat1a,
|
||||
(oc_token_skip_func)oc_token_skip_run_cat1a,
|
||||
(oc_token_skip_func)oc_token_skip_run_cat1a,
|
||||
(oc_token_skip_func)oc_token_skip_run_cat1a,
|
||||
(oc_token_skip_func)oc_token_skip_run_cat1a,
|
||||
oc_token_skip_run,
|
||||
oc_token_skip_run,
|
||||
oc_token_skip_run,
|
||||
oc_token_skip_run
|
||||
};
|
||||
|
||||
/*Determines the number of blocks or coefficients to be skipped for a given
|
||||
token value.
|
||||
_token: The token value to skip.
|
||||
_extra_bits: The extra bits attached to this token.
|
||||
Return: A positive value indicates that number of coefficients are to be
|
||||
skipped in the current block.
|
||||
Otherwise, the negative of the return value indicates that number of
|
||||
blocks are to be ended.
|
||||
0 will never be returned, so that at least one coefficient in one
|
||||
block will always be decoded for every token.*/
|
||||
static ptrdiff_t oc_dct_token_skip(int _token,int _extra_bits){
|
||||
return (*OC_TOKEN_SKIP_TABLE[_token])(_token,_extra_bits);
|
||||
}
|
||||
|
||||
|
||||
void oc_enc_mode_metrics_collect(oc_enc_ctx *_enc){
|
||||
static const unsigned char OC_ZZI_HUFF_OFFSET[64]={
|
||||
0,16,16,16,16,16,32,32,
|
||||
32,32,32,32,32,32,32,48,
|
||||
48,48,48,48,48,48,48,48,
|
||||
48,48,48,48,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64
|
||||
};
|
||||
const oc_fragment *frags;
|
||||
const unsigned *frag_satd;
|
||||
const unsigned *frag_ssd;
|
||||
const ptrdiff_t *coded_fragis;
|
||||
ptrdiff_t ncoded_fragis;
|
||||
ptrdiff_t fragii;
|
||||
double fragw;
|
||||
int modelines[3][3][2];
|
||||
int qti;
|
||||
int qii;
|
||||
int qi;
|
||||
int pli;
|
||||
int zzi;
|
||||
int token;
|
||||
int eb;
|
||||
oc_restore_fpu(&_enc->state);
|
||||
/*Figure out which metric bins to use for this frame's quantizers.*/
|
||||
for(qii=0;qii<_enc->state.nqis;qii++){
|
||||
for(pli=0;pli<3;pli++){
|
||||
for(qti=0;qti<2;qti++){
|
||||
int log_plq;
|
||||
int modeline;
|
||||
log_plq=_enc->log_plq[_enc->state.qis[qii]][pli][qti];
|
||||
for(modeline=0;modeline<OC_LOGQ_BINS-1&&
|
||||
OC_MODE_LOGQ[modeline+1][pli][qti]>log_plq;modeline++);
|
||||
modelines[qii][pli][qti]=modeline;
|
||||
}
|
||||
}
|
||||
}
|
||||
qti=_enc->state.frame_type;
|
||||
frags=_enc->state.frags;
|
||||
frag_satd=_enc->frag_satd;
|
||||
frag_ssd=_enc->frag_ssd;
|
||||
coded_fragis=_enc->state.coded_fragis;
|
||||
ncoded_fragis=fragii=0;
|
||||
/*Weight the fragments by the inverse frame size; this prevents HD content
|
||||
from dominating the statistics.*/
|
||||
fragw=1.0/_enc->state.nfrags;
|
||||
for(pli=0;pli<3;pli++){
|
||||
ptrdiff_t ti[64];
|
||||
int eob_token[64];
|
||||
int eob_run[64];
|
||||
/*Set up token indices and eob run counts.
|
||||
We don't bother trying to figure out the real cost of the runs that span
|
||||
coefficients; instead we use the costs that were available when R-D
|
||||
token optimization was done.*/
|
||||
for(zzi=0;zzi<64;zzi++){
|
||||
ti[zzi]=_enc->dct_token_offs[pli][zzi];
|
||||
if(ti[zzi]>0){
|
||||
token=_enc->dct_tokens[pli][zzi][0];
|
||||
eb=_enc->extra_bits[pli][zzi][0];
|
||||
eob_token[zzi]=token;
|
||||
eob_run[zzi]=-oc_dct_token_skip(token,eb);
|
||||
}
|
||||
else{
|
||||
eob_token[zzi]=OC_NDCT_EOB_TOKEN_MAX;
|
||||
eob_run[zzi]=0;
|
||||
}
|
||||
}
|
||||
/*Scan the list of coded fragments for this plane.*/
|
||||
ncoded_fragis+=_enc->state.ncoded_fragis[pli];
|
||||
for(;fragii<ncoded_fragis;fragii++){
|
||||
ptrdiff_t fragi;
|
||||
int frag_bits;
|
||||
int huffi;
|
||||
int skip;
|
||||
int mb_mode;
|
||||
unsigned satd;
|
||||
int bin;
|
||||
int qtj;
|
||||
fragi=coded_fragis[fragii];
|
||||
frag_bits=0;
|
||||
for(zzi=0;zzi<64;){
|
||||
if(eob_run[zzi]>0){
|
||||
/*We've reached the end of the block.*/
|
||||
eob_run[zzi]--;
|
||||
break;
|
||||
}
|
||||
huffi=_enc->huff_idxs[qti][zzi>0][pli+1>>1]
|
||||
+OC_ZZI_HUFF_OFFSET[zzi];
|
||||
if(eob_token[zzi]<OC_NDCT_EOB_TOKEN_MAX){
|
||||
/*This token caused an EOB run to be flushed.
|
||||
Therefore it gets the bits associated with it.*/
|
||||
frag_bits+=_enc->huff_codes[huffi][eob_token[zzi]].nbits
|
||||
+OC_DCT_TOKEN_EXTRA_BITS[eob_token[zzi]];
|
||||
eob_token[zzi]=OC_NDCT_EOB_TOKEN_MAX;
|
||||
}
|
||||
token=_enc->dct_tokens[pli][zzi][ti[zzi]];
|
||||
eb=_enc->extra_bits[pli][zzi][ti[zzi]];
|
||||
ti[zzi]++;
|
||||
skip=oc_dct_token_skip(token,eb);
|
||||
if(skip<0){
|
||||
eob_token[zzi]=token;
|
||||
eob_run[zzi]=-skip;
|
||||
}
|
||||
else{
|
||||
/*A regular DCT value token; accumulate the bits for it.*/
|
||||
frag_bits+=_enc->huff_codes[huffi][token].nbits
|
||||
+OC_DCT_TOKEN_EXTRA_BITS[token];
|
||||
zzi+=skip;
|
||||
}
|
||||
}
|
||||
mb_mode=frags[fragi].mb_mode;
|
||||
qii=frags[fragi].qii;
|
||||
qi=_enc->state.qis[qii];
|
||||
satd=frag_satd[fragi]<<(pli+1&2);
|
||||
bin=OC_MINI(satd>>OC_SAD_SHIFT,OC_SAD_BINS-1);
|
||||
qtj=mb_mode!=OC_MODE_INTRA;
|
||||
/*Accumulate statistics.
|
||||
The rate (frag_bits) and RMSE (sqrt(frag_ssd)) are not scaled by
|
||||
OC_BIT_SCALE and OC_RMSE_SCALE; this lets us change the scale factor
|
||||
yet still use old data.*/
|
||||
oc_mode_metrics_add(
|
||||
OC_MODE_METRICS[modelines[qii][pli][qtj]][pli][qtj]+bin,
|
||||
fragw,satd,_enc->log_plq[qi][pli][qtj],frag_bits,sqrt(frag_ssd[fragi]));
|
||||
}
|
||||
}
|
||||
/*Update global SATD/logq/rate/RMSE estimation matrix.*/
|
||||
oc_mode_metrics_update(4,1);
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: mode selection code
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_collect_H)
|
||||
# define _collect_H (1)
|
||||
# include "encint.h"
|
||||
# if defined(OC_COLLECT_METRICS)
|
||||
# include <stdio.h>
|
||||
|
||||
|
||||
|
||||
typedef struct oc_mode_metrics oc_mode_metrics;
|
||||
|
||||
|
||||
|
||||
/**Sets the file name to load/store mode metrics from/to.
|
||||
* The file name string is stored by reference, and so must be valid for the
|
||||
* lifetime of the encoder.
|
||||
* Mode metric collection uses global tables; do not attempt to perform
|
||||
* multiple collections at once.
|
||||
* \param[in] _buf <tt>char[]</tt> The file name.
|
||||
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||
#define TH_ENCCTL_SET_METRICS_FILE (0x8000)
|
||||
|
||||
|
||||
|
||||
/*Accumulates various weighted sums of the measurements.
|
||||
w -> weight
|
||||
s -> SATD
|
||||
q -> log quantizer
|
||||
r -> rate (in bits)
|
||||
d -> RMSE
|
||||
All of the single letters correspond to direct, weighted sums, e.g.,
|
||||
w=sum(w_i), s=sum(s_i*w_i), etc.
|
||||
The others correspond to central moments (or co-moments) of the given order,
|
||||
e.g., sq=sum((s_i-s/w)*(q_i-q/w)*w_i).
|
||||
Because we need some moments up to fourth order, we use central moments to
|
||||
minimize the dynamic range and prevent rounding error from dominating the
|
||||
calculations.*/
|
||||
struct oc_mode_metrics{
|
||||
double w;
|
||||
double s;
|
||||
double q;
|
||||
double r;
|
||||
double d;
|
||||
double s2;
|
||||
double sq;
|
||||
double q2;
|
||||
double sr;
|
||||
double qr;
|
||||
double r2;
|
||||
double sd;
|
||||
double qd;
|
||||
double d2;
|
||||
double s2q;
|
||||
double sq2;
|
||||
double sqr;
|
||||
double sqd;
|
||||
double s2q2;
|
||||
};
|
||||
|
||||
|
||||
# define OC_ZWEIGHT (0.25)
|
||||
|
||||
/*TODO: It may be helpful (for block-level quantizers especially) to separate
|
||||
out the contributions from AC and DC into separate tables.*/
|
||||
|
||||
extern ogg_int16_t OC_MODE_LOGQ[OC_LOGQ_BINS][3][2];
|
||||
extern oc_mode_rd OC_MODE_RD[OC_LOGQ_BINS][3][2][OC_SAD_BINS];
|
||||
|
||||
extern int OC_HAS_MODE_METRICS;
|
||||
extern oc_mode_metrics OC_MODE_METRICS[OC_LOGQ_BINS-1][3][2][OC_SAD_BINS];
|
||||
extern const char *OC_MODE_METRICS_FILENAME;
|
||||
|
||||
void oc_mode_metrics_dump();
|
||||
void oc_mode_metrics_print(FILE *_fout);
|
||||
|
||||
void oc_mode_metrics_add(oc_mode_metrics *_metrics,
|
||||
double _w,int _s,int _q,int _r,double _d);
|
||||
void oc_mode_metrics_merge(oc_mode_metrics *_dst,
|
||||
const oc_mode_metrics *_src,int _n);
|
||||
double oc_mode_metrics_solve(double *_r,double *_d,
|
||||
const oc_mode_metrics *_metrics,const int *_s0,const int *_s1,
|
||||
const int *_q0,const int *_q1,
|
||||
const double *_ra,const double *_rb,const double *_rc,
|
||||
const double *_da,const double *_db,const double *_dc,int _n);
|
||||
void oc_mode_metrics_update(int _niters_min,int _reweight);
|
||||
|
||||
void oc_enc_mode_metrics_load(oc_enc_ctx *_enc);
|
||||
void oc_enc_mode_metrics_collect(oc_enc_ctx *_enc);
|
||||
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
/*Definitions shared by the forward and inverse DCT transforms.*/
|
||||
#if !defined(_dct_H)
|
||||
# define _dct_H (1)
|
||||
|
||||
/*cos(n*pi/16) (resp. sin(m*pi/16)) scaled by 65536.*/
|
||||
#define OC_C1S7 ((ogg_int32_t)64277)
|
||||
#define OC_C2S6 ((ogg_int32_t)60547)
|
||||
#define OC_C3S5 ((ogg_int32_t)54491)
|
||||
#define OC_C4S4 ((ogg_int32_t)46341)
|
||||
#define OC_C5S3 ((ogg_int32_t)36410)
|
||||
#define OC_C6S2 ((ogg_int32_t)25080)
|
||||
#define OC_C7S1 ((ogg_int32_t)12785)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: decapiwrapper.c 13596 2007-08-23 20:05:38Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "apiwrapper.h"
|
||||
#include "decint.h"
|
||||
#include "theora/theoradec.h"
|
||||
|
||||
static void th_dec_api_clear(th_api_wrapper *_api){
|
||||
if(_api->setup)th_setup_free(_api->setup);
|
||||
if(_api->decode)th_decode_free(_api->decode);
|
||||
memset(_api,0,sizeof(*_api));
|
||||
}
|
||||
|
||||
static void theora_decode_clear(theora_state *_td){
|
||||
if(_td->i!=NULL)theora_info_clear(_td->i);
|
||||
memset(_td,0,sizeof(*_td));
|
||||
}
|
||||
|
||||
static int theora_decode_control(theora_state *_td,int _req,
|
||||
void *_buf,size_t _buf_sz){
|
||||
return th_decode_ctl(((th_api_wrapper *)_td->i->codec_setup)->decode,
|
||||
_req,_buf,_buf_sz);
|
||||
}
|
||||
|
||||
static ogg_int64_t theora_decode_granule_frame(theora_state *_td,
|
||||
ogg_int64_t _gp){
|
||||
return th_granule_frame(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp);
|
||||
}
|
||||
|
||||
static double theora_decode_granule_time(theora_state *_td,ogg_int64_t _gp){
|
||||
return th_granule_time(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp);
|
||||
}
|
||||
|
||||
static const oc_state_dispatch_vtable OC_DEC_DISPATCH_VTBL={
|
||||
(oc_state_clear_func)theora_decode_clear,
|
||||
(oc_state_control_func)theora_decode_control,
|
||||
(oc_state_granule_frame_func)theora_decode_granule_frame,
|
||||
(oc_state_granule_time_func)theora_decode_granule_time,
|
||||
};
|
||||
|
||||
static void th_info2theora_info(theora_info *_ci,const th_info *_info){
|
||||
_ci->version_major=_info->version_major;
|
||||
_ci->version_minor=_info->version_minor;
|
||||
_ci->version_subminor=_info->version_subminor;
|
||||
_ci->width=_info->frame_width;
|
||||
_ci->height=_info->frame_height;
|
||||
_ci->frame_width=_info->pic_width;
|
||||
_ci->frame_height=_info->pic_height;
|
||||
_ci->offset_x=_info->pic_x;
|
||||
_ci->offset_y=_info->pic_y;
|
||||
_ci->fps_numerator=_info->fps_numerator;
|
||||
_ci->fps_denominator=_info->fps_denominator;
|
||||
_ci->aspect_numerator=_info->aspect_numerator;
|
||||
_ci->aspect_denominator=_info->aspect_denominator;
|
||||
switch(_info->colorspace){
|
||||
case TH_CS_ITU_REC_470M:_ci->colorspace=OC_CS_ITU_REC_470M;break;
|
||||
case TH_CS_ITU_REC_470BG:_ci->colorspace=OC_CS_ITU_REC_470BG;break;
|
||||
default:_ci->colorspace=OC_CS_UNSPECIFIED;break;
|
||||
}
|
||||
switch(_info->pixel_fmt){
|
||||
case TH_PF_420:_ci->pixelformat=OC_PF_420;break;
|
||||
case TH_PF_422:_ci->pixelformat=OC_PF_422;break;
|
||||
case TH_PF_444:_ci->pixelformat=OC_PF_444;break;
|
||||
default:_ci->pixelformat=OC_PF_RSVD;
|
||||
}
|
||||
_ci->target_bitrate=_info->target_bitrate;
|
||||
_ci->quality=_info->quality;
|
||||
_ci->keyframe_frequency_force=1<<_info->keyframe_granule_shift;
|
||||
}
|
||||
|
||||
int theora_decode_init(theora_state *_td,theora_info *_ci){
|
||||
th_api_info *apiinfo;
|
||||
th_api_wrapper *api;
|
||||
th_info info;
|
||||
api=(th_api_wrapper *)_ci->codec_setup;
|
||||
/*Allocate our own combined API wrapper/theora_info struct.
|
||||
We put them both in one malloc'd block so that when the API wrapper is
|
||||
freed, the info struct goes with it.
|
||||
This avoids having to figure out whether or not we need to free the info
|
||||
struct in either theora_info_clear() or theora_clear().*/
|
||||
apiinfo=(th_api_info *)_ogg_calloc(1,sizeof(*apiinfo));
|
||||
if(apiinfo==NULL)return OC_FAULT;
|
||||
/*Make our own copy of the info struct, since its lifetime should be
|
||||
independent of the one we were passed in.*/
|
||||
*&apiinfo->info=*_ci;
|
||||
/*Convert the info struct now instead of saving the the one we decoded with
|
||||
theora_decode_header(), since the user might have modified values (i.e.,
|
||||
color space, aspect ratio, etc. can be specified from a higher level).
|
||||
The user also might be doing something "clever" with the header packets if
|
||||
they are not using an Ogg encapsulation.*/
|
||||
oc_theora_info2th_info(&info,_ci);
|
||||
/*Don't bother to copy the setup info; th_decode_alloc() makes its own copy
|
||||
of the stuff it needs.*/
|
||||
apiinfo->api.decode=th_decode_alloc(&info,api->setup);
|
||||
if(apiinfo->api.decode==NULL){
|
||||
_ogg_free(apiinfo);
|
||||
return OC_EINVAL;
|
||||
}
|
||||
apiinfo->api.clear=(oc_setup_clear_func)th_dec_api_clear;
|
||||
_td->internal_encode=NULL;
|
||||
/*Provide entry points for ABI compatibility with old decoder shared libs.*/
|
||||
_td->internal_decode=(void *)&OC_DEC_DISPATCH_VTBL;
|
||||
_td->granulepos=0;
|
||||
_td->i=&apiinfo->info;
|
||||
_td->i->codec_setup=&apiinfo->api;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int theora_decode_header(theora_info *_ci,theora_comment *_cc,ogg_packet *_op){
|
||||
th_api_wrapper *api;
|
||||
th_info info;
|
||||
int ret;
|
||||
api=(th_api_wrapper *)_ci->codec_setup;
|
||||
/*Allocate an API wrapper struct on demand, since it will not also include a
|
||||
theora_info struct like the ones that are used in a theora_state struct.*/
|
||||
if(api==NULL){
|
||||
_ci->codec_setup=_ogg_calloc(1,sizeof(*api));
|
||||
if(_ci->codec_setup==NULL)return OC_FAULT;
|
||||
api=(th_api_wrapper *)_ci->codec_setup;
|
||||
api->clear=(oc_setup_clear_func)th_dec_api_clear;
|
||||
}
|
||||
/*Convert from the theora_info struct instead of saving our own th_info
|
||||
struct between calls.
|
||||
The user might be doing something "clever" with the header packets if they
|
||||
are not using an Ogg encapsulation, and we don't want to break this.*/
|
||||
oc_theora_info2th_info(&info,_ci);
|
||||
/*We rely on the fact that theora_comment and th_comment structures are
|
||||
actually identical.
|
||||
Take care not to change this fact unless you change the code here as
|
||||
well!*/
|
||||
ret=th_decode_headerin(&info,(th_comment *)_cc,&api->setup,_op);
|
||||
/*We also rely on the fact that the error return code values are the same,
|
||||
and that the implementations of these two functions return the same set of
|
||||
them.
|
||||
Note that theora_decode_header() really can return OC_NOTFORMAT, even
|
||||
though it is not currently documented to do so.*/
|
||||
if(ret<0)return ret;
|
||||
th_info2theora_info(_ci,&info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int theora_decode_packetin(theora_state *_td,ogg_packet *_op){
|
||||
th_api_wrapper *api;
|
||||
ogg_int64_t gp;
|
||||
int ret;
|
||||
if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT;
|
||||
api=(th_api_wrapper *)_td->i->codec_setup;
|
||||
ret=th_decode_packetin(api->decode,_op,&gp);
|
||||
if(ret<0)return OC_BADPACKET;
|
||||
_td->granulepos=gp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int theora_decode_YUVout(theora_state *_td,yuv_buffer *_yuv){
|
||||
th_api_wrapper *api;
|
||||
th_dec_ctx *decode;
|
||||
th_ycbcr_buffer buf;
|
||||
int ret;
|
||||
if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT;
|
||||
api=(th_api_wrapper *)_td->i->codec_setup;
|
||||
decode=(th_dec_ctx *)api->decode;
|
||||
if(!decode)return OC_FAULT;
|
||||
ret=th_decode_ycbcr_out(decode,buf);
|
||||
if(ret>=0){
|
||||
_yuv->y_width=buf[0].width;
|
||||
_yuv->y_height=buf[0].height;
|
||||
_yuv->y_stride=buf[0].stride;
|
||||
_yuv->uv_width=buf[1].width;
|
||||
_yuv->uv_height=buf[1].height;
|
||||
_yuv->uv_stride=buf[1].stride;
|
||||
_yuv->y=buf[0].data;
|
||||
_yuv->u=buf[1].data;
|
||||
_yuv->v=buf[2].data;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "decint.h"
|
||||
|
||||
|
||||
|
||||
/*Unpacks a series of octets from a given byte array into the pack buffer.
|
||||
No checking is done to ensure the buffer contains enough data.
|
||||
_opb: The pack buffer to read the octets from.
|
||||
_buf: The byte array to store the unpacked bytes in.
|
||||
_len: The number of octets to unpack.*/
|
||||
static void oc_unpack_octets(oc_pack_buf *_opb,char *_buf,size_t _len){
|
||||
while(_len-->0){
|
||||
long val;
|
||||
val=oc_pack_read(_opb,8);
|
||||
*_buf++=(char)val;
|
||||
}
|
||||
}
|
||||
|
||||
/*Unpacks a 32-bit integer encoded by octets in little-endian form.*/
|
||||
static long oc_unpack_length(oc_pack_buf *_opb){
|
||||
long ret[4];
|
||||
int i;
|
||||
for(i=0;i<4;i++)ret[i]=oc_pack_read(_opb,8);
|
||||
return ret[0]|ret[1]<<8|ret[2]<<16|ret[3]<<24;
|
||||
}
|
||||
|
||||
static int oc_info_unpack(oc_pack_buf *_opb,th_info *_info){
|
||||
long val;
|
||||
/*Check the codec bitstream version.*/
|
||||
val=oc_pack_read(_opb,8);
|
||||
_info->version_major=(unsigned char)val;
|
||||
val=oc_pack_read(_opb,8);
|
||||
_info->version_minor=(unsigned char)val;
|
||||
val=oc_pack_read(_opb,8);
|
||||
_info->version_subminor=(unsigned char)val;
|
||||
/*verify we can parse this bitstream version.
|
||||
We accept earlier minors and all subminors, by spec*/
|
||||
if(_info->version_major>TH_VERSION_MAJOR||
|
||||
_info->version_major==TH_VERSION_MAJOR&&
|
||||
_info->version_minor>TH_VERSION_MINOR){
|
||||
return TH_EVERSION;
|
||||
}
|
||||
/*Read the encoded frame description.*/
|
||||
val=oc_pack_read(_opb,16);
|
||||
_info->frame_width=(ogg_uint32_t)val<<4;
|
||||
val=oc_pack_read(_opb,16);
|
||||
_info->frame_height=(ogg_uint32_t)val<<4;
|
||||
val=oc_pack_read(_opb,24);
|
||||
_info->pic_width=(ogg_uint32_t)val;
|
||||
val=oc_pack_read(_opb,24);
|
||||
_info->pic_height=(ogg_uint32_t)val;
|
||||
val=oc_pack_read(_opb,8);
|
||||
_info->pic_x=(ogg_uint32_t)val;
|
||||
val=oc_pack_read(_opb,8);
|
||||
_info->pic_y=(ogg_uint32_t)val;
|
||||
val=oc_pack_read(_opb,32);
|
||||
_info->fps_numerator=(ogg_uint32_t)val;
|
||||
val=oc_pack_read(_opb,32);
|
||||
_info->fps_denominator=(ogg_uint32_t)val;
|
||||
if(_info->frame_width==0||_info->frame_height==0||
|
||||
_info->pic_width+_info->pic_x>_info->frame_width||
|
||||
_info->pic_height+_info->pic_y>_info->frame_height||
|
||||
_info->fps_numerator==0||_info->fps_denominator==0){
|
||||
return TH_EBADHEADER;
|
||||
}
|
||||
/*Note: The sense of pic_y is inverted in what we pass back to the
|
||||
application compared to how it is stored in the bitstream.
|
||||
This is because the bitstream uses a right-handed coordinate system, while
|
||||
applications expect a left-handed one.*/
|
||||
_info->pic_y=_info->frame_height-_info->pic_height-_info->pic_y;
|
||||
val=oc_pack_read(_opb,24);
|
||||
_info->aspect_numerator=(ogg_uint32_t)val;
|
||||
val=oc_pack_read(_opb,24);
|
||||
_info->aspect_denominator=(ogg_uint32_t)val;
|
||||
val=oc_pack_read(_opb,8);
|
||||
_info->colorspace=(th_colorspace)val;
|
||||
val=oc_pack_read(_opb,24);
|
||||
_info->target_bitrate=(int)val;
|
||||
val=oc_pack_read(_opb,6);
|
||||
_info->quality=(int)val;
|
||||
val=oc_pack_read(_opb,5);
|
||||
_info->keyframe_granule_shift=(int)val;
|
||||
val=oc_pack_read(_opb,2);
|
||||
_info->pixel_fmt=(th_pixel_fmt)val;
|
||||
if(_info->pixel_fmt==TH_PF_RSVD)return TH_EBADHEADER;
|
||||
val=oc_pack_read(_opb,3);
|
||||
if(val!=0||oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oc_comment_unpack(oc_pack_buf *_opb,th_comment *_tc){
|
||||
long len;
|
||||
int i;
|
||||
/*Read the vendor string.*/
|
||||
len=oc_unpack_length(_opb);
|
||||
if(len<0||len>oc_pack_bytes_left(_opb))return TH_EBADHEADER;
|
||||
_tc->vendor=_ogg_malloc((size_t)len+1);
|
||||
if(_tc->vendor==NULL)return TH_EFAULT;
|
||||
oc_unpack_octets(_opb,_tc->vendor,len);
|
||||
_tc->vendor[len]='\0';
|
||||
/*Read the user comments.*/
|
||||
_tc->comments=(int)oc_unpack_length(_opb);
|
||||
len=_tc->comments;
|
||||
if(len<0||len>(LONG_MAX>>2)||len<<2>oc_pack_bytes_left(_opb)){
|
||||
_tc->comments=0;
|
||||
return TH_EBADHEADER;
|
||||
}
|
||||
_tc->comment_lengths=(int *)_ogg_malloc(
|
||||
_tc->comments*sizeof(_tc->comment_lengths[0]));
|
||||
_tc->user_comments=(char **)_ogg_malloc(
|
||||
_tc->comments*sizeof(_tc->user_comments[0]));
|
||||
if(_tc->comment_lengths==NULL||_tc->user_comments==NULL){
|
||||
_tc->comments=0;
|
||||
return TH_EFAULT;
|
||||
}
|
||||
for(i=0;i<_tc->comments;i++){
|
||||
len=oc_unpack_length(_opb);
|
||||
if(len<0||len>oc_pack_bytes_left(_opb)){
|
||||
_tc->comments=i;
|
||||
return TH_EBADHEADER;
|
||||
}
|
||||
_tc->comment_lengths[i]=len;
|
||||
_tc->user_comments[i]=_ogg_malloc((size_t)len+1);
|
||||
if(_tc->user_comments[i]==NULL){
|
||||
_tc->comments=i;
|
||||
return TH_EFAULT;
|
||||
}
|
||||
oc_unpack_octets(_opb,_tc->user_comments[i],len);
|
||||
_tc->user_comments[i][len]='\0';
|
||||
}
|
||||
return oc_pack_bytes_left(_opb)<0?TH_EBADHEADER:0;
|
||||
}
|
||||
|
||||
static int oc_setup_unpack(oc_pack_buf *_opb,th_setup_info *_setup){
|
||||
int ret;
|
||||
/*Read the quantizer tables.*/
|
||||
ret=oc_quant_params_unpack(_opb,&_setup->qinfo);
|
||||
if(ret<0)return ret;
|
||||
/*Read the Huffman trees.*/
|
||||
return oc_huff_trees_unpack(_opb,_setup->huff_tables);
|
||||
}
|
||||
|
||||
static void oc_setup_clear(th_setup_info *_setup){
|
||||
oc_quant_params_clear(&_setup->qinfo);
|
||||
oc_huff_trees_clear(_setup->huff_tables);
|
||||
}
|
||||
|
||||
static int oc_dec_headerin(oc_pack_buf *_opb,th_info *_info,
|
||||
th_comment *_tc,th_setup_info **_setup,ogg_packet *_op){
|
||||
char buffer[6];
|
||||
long val;
|
||||
int packtype;
|
||||
int ret;
|
||||
val=oc_pack_read(_opb,8);
|
||||
packtype=(int)val;
|
||||
/*If we're at a data packet and we have received all three headers, we're
|
||||
done.*/
|
||||
if(!(packtype&0x80)&&_info->frame_width>0&&_tc->vendor!=NULL&&*_setup!=NULL){
|
||||
return 0;
|
||||
}
|
||||
/*Check the codec string.*/
|
||||
oc_unpack_octets(_opb,buffer,6);
|
||||
if(memcmp(buffer,"theora",6)!=0)return TH_ENOTFORMAT;
|
||||
switch(packtype){
|
||||
/*Codec info header.*/
|
||||
case 0x80:{
|
||||
/*This should be the first packet, and we should not already be
|
||||
initialized.*/
|
||||
if(!_op->b_o_s||_info->frame_width>0)return TH_EBADHEADER;
|
||||
ret=oc_info_unpack(_opb,_info);
|
||||
if(ret<0)th_info_clear(_info);
|
||||
else ret=3;
|
||||
}break;
|
||||
/*Comment header.*/
|
||||
case 0x81:{
|
||||
if(_tc==NULL)return TH_EFAULT;
|
||||
/*We shoud have already decoded the info header, and should not yet have
|
||||
decoded the comment header.*/
|
||||
if(_info->frame_width==0||_tc->vendor!=NULL)return TH_EBADHEADER;
|
||||
ret=oc_comment_unpack(_opb,_tc);
|
||||
if(ret<0)th_comment_clear(_tc);
|
||||
else ret=2;
|
||||
}break;
|
||||
/*Codec setup header.*/
|
||||
case 0x82:{
|
||||
oc_setup_info *setup;
|
||||
if(_tc==NULL||_setup==NULL)return TH_EFAULT;
|
||||
/*We should have already decoded the info header and the comment header,
|
||||
and should not yet have decoded the setup header.*/
|
||||
if(_info->frame_width==0||_tc->vendor==NULL||*_setup!=NULL){
|
||||
return TH_EBADHEADER;
|
||||
}
|
||||
setup=(oc_setup_info *)_ogg_calloc(1,sizeof(*setup));
|
||||
if(setup==NULL)return TH_EFAULT;
|
||||
ret=oc_setup_unpack(_opb,setup);
|
||||
if(ret<0){
|
||||
oc_setup_clear(setup);
|
||||
_ogg_free(setup);
|
||||
}
|
||||
else{
|
||||
*_setup=setup;
|
||||
ret=1;
|
||||
}
|
||||
}break;
|
||||
default:{
|
||||
/*We don't know what this header is.*/
|
||||
return TH_EBADHEADER;
|
||||
}break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*Decodes one header packet.
|
||||
This should be called repeatedly with the packets at the beginning of the
|
||||
stream until it returns 0.*/
|
||||
int th_decode_headerin(th_info *_info,th_comment *_tc,
|
||||
th_setup_info **_setup,ogg_packet *_op){
|
||||
oc_pack_buf opb;
|
||||
if(_op==NULL)return TH_EBADHEADER;
|
||||
if(_info==NULL)return TH_EFAULT;
|
||||
oc_pack_readinit(&opb,_op->packet,_op->bytes);
|
||||
return oc_dec_headerin(&opb,_info,_tc,_setup,_op);
|
||||
}
|
||||
|
||||
void th_setup_free(th_setup_info *_setup){
|
||||
if(_setup!=NULL){
|
||||
oc_setup_clear(_setup);
|
||||
_ogg_free(_setup);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <limits.h>
|
||||
#if !defined(_decint_H)
|
||||
# define _decint_H (1)
|
||||
# include "theora/theoradec.h"
|
||||
# include "state.h"
|
||||
# include "bitpack.h"
|
||||
# include "huffdec.h"
|
||||
# include "dequant.h"
|
||||
|
||||
typedef struct th_setup_info oc_setup_info;
|
||||
typedef struct oc_dec_opt_vtable oc_dec_opt_vtable;
|
||||
typedef struct oc_dec_pipeline_state oc_dec_pipeline_state;
|
||||
typedef struct th_dec_ctx oc_dec_ctx;
|
||||
|
||||
|
||||
|
||||
/*Decoder-specific accelerated functions.*/
|
||||
# if defined(OC_C64X_ASM)
|
||||
# include "c64x/c64xdec.h"
|
||||
# endif
|
||||
|
||||
# if !defined(oc_dec_accel_init)
|
||||
# define oc_dec_accel_init oc_dec_accel_init_c
|
||||
# endif
|
||||
# if defined(OC_DEC_USE_VTABLE)
|
||||
# if !defined(oc_dec_dc_unpredict_mcu_plane)
|
||||
# define oc_dec_dc_unpredict_mcu_plane(_dec,_pipe,_pli) \
|
||||
((*(_dec)->opt_vtable.dc_unpredict_mcu_plane)(_dec,_pipe,_pli))
|
||||
# endif
|
||||
# else
|
||||
# if !defined(oc_dec_dc_unpredict_mcu_plane)
|
||||
# define oc_dec_dc_unpredict_mcu_plane oc_dec_dc_unpredict_mcu_plane_c
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
/*Constants for the packet-in state machine specific to the decoder.*/
|
||||
|
||||
/*Next packet to read: Data packet.*/
|
||||
#define OC_PACKET_DATA (0)
|
||||
|
||||
|
||||
|
||||
struct th_setup_info{
|
||||
/*The Huffman codes.*/
|
||||
ogg_int16_t *huff_tables[TH_NHUFFMAN_TABLES];
|
||||
/*The quantization parameters.*/
|
||||
th_quant_info qinfo;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*Decoder specific functions with accelerated variants.*/
|
||||
struct oc_dec_opt_vtable{
|
||||
void (*dc_unpredict_mcu_plane)(oc_dec_ctx *_dec,
|
||||
oc_dec_pipeline_state *_pipe,int _pli);
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct oc_dec_pipeline_state{
|
||||
/*Decoded DCT coefficients.
|
||||
These are placed here instead of on the stack so that they can persist
|
||||
between blocks, which makes clearing them back to zero much faster when
|
||||
only a few non-zero coefficients were decoded.
|
||||
It requires at least 65 elements because the zig-zag index array uses the
|
||||
65th element as a dumping ground for out-of-range indices to protect us
|
||||
from buffer overflow.
|
||||
We make it fully twice as large so that the second half can serve as the
|
||||
reconstruction buffer, which saves passing another parameter to all the
|
||||
acceleration functios.
|
||||
It also solves problems with 16-byte alignment for NEON on ARM.
|
||||
gcc (as of 4.2.1) only seems to be able to give stack variables 8-byte
|
||||
alignment, and silently produces incorrect results if you ask for 16.
|
||||
Finally, keeping it off the stack means there's less likely to be a data
|
||||
hazard beween the NEON co-processor and the regular ARM core, which avoids
|
||||
unnecessary stalls.*/
|
||||
OC_ALIGN16(ogg_int16_t dct_coeffs[128]);
|
||||
OC_ALIGN16(signed char bounding_values[256]);
|
||||
ptrdiff_t ti[3][64];
|
||||
ptrdiff_t ebi[3][64];
|
||||
ptrdiff_t eob_runs[3][64];
|
||||
const ptrdiff_t *coded_fragis[3];
|
||||
const ptrdiff_t *uncoded_fragis[3];
|
||||
ptrdiff_t ncoded_fragis[3];
|
||||
ptrdiff_t nuncoded_fragis[3];
|
||||
const ogg_uint16_t *dequant[3][3][2];
|
||||
int fragy0[3];
|
||||
int fragy_end[3];
|
||||
int pred_last[3][3];
|
||||
int mcu_nvfrags;
|
||||
int loop_filter;
|
||||
int pp_level;
|
||||
};
|
||||
|
||||
|
||||
struct th_dec_ctx{
|
||||
/*Shared encoder/decoder state.*/
|
||||
oc_theora_state state;
|
||||
/*Whether or not packets are ready to be emitted.
|
||||
This takes on negative values while there are remaining header packets to
|
||||
be emitted, reaches 0 when the codec is ready for input, and goes to 1
|
||||
when a frame has been processed and a data packet is ready.*/
|
||||
int packet_state;
|
||||
/*Buffer in which to assemble packets.*/
|
||||
oc_pack_buf opb;
|
||||
/*Huffman decode trees.*/
|
||||
ogg_int16_t *huff_tables[TH_NHUFFMAN_TABLES];
|
||||
/*The index of the first token in each plane for each coefficient.*/
|
||||
ptrdiff_t ti0[3][64];
|
||||
/*The number of outstanding EOB runs at the start of each coefficient in each
|
||||
plane.*/
|
||||
ptrdiff_t eob_runs[3][64];
|
||||
/*The DCT token lists.*/
|
||||
unsigned char *dct_tokens;
|
||||
/*The extra bits associated with DCT tokens.*/
|
||||
unsigned char *extra_bits;
|
||||
/*The number of dct tokens unpacked so far.*/
|
||||
int dct_tokens_count;
|
||||
/*The out-of-loop post-processing level.*/
|
||||
int pp_level;
|
||||
/*The DC scale used for out-of-loop deblocking.*/
|
||||
int pp_dc_scale[64];
|
||||
/*The sharpen modifier used for out-of-loop deringing.*/
|
||||
int pp_sharp_mod[64];
|
||||
/*The DC quantization index of each block.*/
|
||||
unsigned char *dc_qis;
|
||||
/*The variance of each block.*/
|
||||
int *variances;
|
||||
/*The storage for the post-processed frame buffer.*/
|
||||
unsigned char *pp_frame_data;
|
||||
/*Whether or not the post-processsed frame buffer has space for chroma.*/
|
||||
int pp_frame_state;
|
||||
/*The buffer used for the post-processed frame.
|
||||
Note that this is _not_ guaranteed to have the same strides and offsets as
|
||||
the reference frame buffers.*/
|
||||
th_ycbcr_buffer pp_frame_buf;
|
||||
/*The striped decode callback function.*/
|
||||
th_stripe_callback stripe_cb;
|
||||
oc_dec_pipeline_state pipe;
|
||||
# if defined(OC_DEC_USE_VTABLE)
|
||||
/*Table for decoder acceleration functions.*/
|
||||
oc_dec_opt_vtable opt_vtable;
|
||||
# endif
|
||||
# if defined(HAVE_CAIRO)
|
||||
/*Output metrics for debugging.*/
|
||||
int telemetry;
|
||||
int telemetry_mbmode;
|
||||
int telemetry_mv;
|
||||
int telemetry_qi;
|
||||
int telemetry_bits;
|
||||
int telemetry_frame_bytes;
|
||||
int telemetry_coding_bytes;
|
||||
int telemetry_mode_bytes;
|
||||
int telemetry_mv_bytes;
|
||||
int telemetry_qi_bytes;
|
||||
int telemetry_dc_bytes;
|
||||
unsigned char *telemetry_frame_data;
|
||||
# endif
|
||||
};
|
||||
|
||||
/*Default pure-C implementations of decoder-specific accelerated functions.*/
|
||||
void oc_dec_accel_init_c(oc_dec_ctx *_dec);
|
||||
|
||||
void oc_dec_dc_unpredict_mcu_plane_c(oc_dec_ctx *_dec,
|
||||
oc_dec_pipeline_state *_pipe,int _pli);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,182 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ogg/ogg.h>
|
||||
#include "dequant.h"
|
||||
#include "decint.h"
|
||||
|
||||
int oc_quant_params_unpack(oc_pack_buf *_opb,th_quant_info *_qinfo){
|
||||
th_quant_base *base_mats;
|
||||
long val;
|
||||
int nbase_mats;
|
||||
int sizes[64];
|
||||
int indices[64];
|
||||
int nbits;
|
||||
int bmi;
|
||||
int ci;
|
||||
int qti;
|
||||
int pli;
|
||||
int qri;
|
||||
int qi;
|
||||
int i;
|
||||
val=oc_pack_read(_opb,3);
|
||||
nbits=(int)val;
|
||||
for(qi=0;qi<64;qi++){
|
||||
val=oc_pack_read(_opb,nbits);
|
||||
_qinfo->loop_filter_limits[qi]=(unsigned char)val;
|
||||
}
|
||||
val=oc_pack_read(_opb,4);
|
||||
nbits=(int)val+1;
|
||||
for(qi=0;qi<64;qi++){
|
||||
val=oc_pack_read(_opb,nbits);
|
||||
_qinfo->ac_scale[qi]=(ogg_uint16_t)val;
|
||||
}
|
||||
val=oc_pack_read(_opb,4);
|
||||
nbits=(int)val+1;
|
||||
for(qi=0;qi<64;qi++){
|
||||
val=oc_pack_read(_opb,nbits);
|
||||
_qinfo->dc_scale[qi]=(ogg_uint16_t)val;
|
||||
}
|
||||
val=oc_pack_read(_opb,9);
|
||||
nbase_mats=(int)val+1;
|
||||
base_mats=_ogg_malloc(nbase_mats*sizeof(base_mats[0]));
|
||||
if(base_mats==NULL)return TH_EFAULT;
|
||||
for(bmi=0;bmi<nbase_mats;bmi++){
|
||||
for(ci=0;ci<64;ci++){
|
||||
val=oc_pack_read(_opb,8);
|
||||
base_mats[bmi][ci]=(unsigned char)val;
|
||||
}
|
||||
}
|
||||
nbits=oc_ilog(nbase_mats-1);
|
||||
for(i=0;i<6;i++){
|
||||
th_quant_ranges *qranges;
|
||||
th_quant_base *qrbms;
|
||||
int *qrsizes;
|
||||
qti=i/3;
|
||||
pli=i%3;
|
||||
qranges=_qinfo->qi_ranges[qti]+pli;
|
||||
if(i>0){
|
||||
val=oc_pack_read1(_opb);
|
||||
if(!val){
|
||||
int qtj;
|
||||
int plj;
|
||||
if(qti>0){
|
||||
val=oc_pack_read1(_opb);
|
||||
if(val){
|
||||
qtj=qti-1;
|
||||
plj=pli;
|
||||
}
|
||||
else{
|
||||
qtj=(i-1)/3;
|
||||
plj=(i-1)%3;
|
||||
}
|
||||
}
|
||||
else{
|
||||
qtj=(i-1)/3;
|
||||
plj=(i-1)%3;
|
||||
}
|
||||
*qranges=*(_qinfo->qi_ranges[qtj]+plj);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
val=oc_pack_read(_opb,nbits);
|
||||
indices[0]=(int)val;
|
||||
for(qi=qri=0;qi<63;){
|
||||
val=oc_pack_read(_opb,oc_ilog(62-qi));
|
||||
sizes[qri]=(int)val+1;
|
||||
qi+=(int)val+1;
|
||||
val=oc_pack_read(_opb,nbits);
|
||||
indices[++qri]=(int)val;
|
||||
}
|
||||
/*Note: The caller is responsible for cleaning up any partially
|
||||
constructed qinfo.*/
|
||||
if(qi>63){
|
||||
_ogg_free(base_mats);
|
||||
return TH_EBADHEADER;
|
||||
}
|
||||
qranges->nranges=qri;
|
||||
qranges->sizes=qrsizes=(int *)_ogg_malloc(qri*sizeof(qrsizes[0]));
|
||||
if(qranges->sizes==NULL){
|
||||
/*Note: The caller is responsible for cleaning up any partially
|
||||
constructed qinfo.*/
|
||||
_ogg_free(base_mats);
|
||||
return TH_EFAULT;
|
||||
}
|
||||
memcpy(qrsizes,sizes,qri*sizeof(qrsizes[0]));
|
||||
qrbms=(th_quant_base *)_ogg_malloc((qri+1)*sizeof(qrbms[0]));
|
||||
if(qrbms==NULL){
|
||||
/*Note: The caller is responsible for cleaning up any partially
|
||||
constructed qinfo.*/
|
||||
_ogg_free(base_mats);
|
||||
return TH_EFAULT;
|
||||
}
|
||||
qranges->base_matrices=(const th_quant_base *)qrbms;
|
||||
do{
|
||||
bmi=indices[qri];
|
||||
/*Note: The caller is responsible for cleaning up any partially
|
||||
constructed qinfo.*/
|
||||
if(bmi>=nbase_mats){
|
||||
_ogg_free(base_mats);
|
||||
return TH_EBADHEADER;
|
||||
}
|
||||
memcpy(qrbms[qri],base_mats[bmi],sizeof(qrbms[qri]));
|
||||
}
|
||||
while(qri-->0);
|
||||
}
|
||||
_ogg_free(base_mats);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void oc_quant_params_clear(th_quant_info *_qinfo){
|
||||
int i;
|
||||
for(i=6;i-->0;){
|
||||
int qti;
|
||||
int pli;
|
||||
qti=i/3;
|
||||
pli=i%3;
|
||||
/*Clear any duplicate pointer references.*/
|
||||
if(i>0){
|
||||
int qtj;
|
||||
int plj;
|
||||
qtj=(i-1)/3;
|
||||
plj=(i-1)%3;
|
||||
if(_qinfo->qi_ranges[qti][pli].sizes==
|
||||
_qinfo->qi_ranges[qtj][plj].sizes){
|
||||
_qinfo->qi_ranges[qti][pli].sizes=NULL;
|
||||
}
|
||||
if(_qinfo->qi_ranges[qti][pli].base_matrices==
|
||||
_qinfo->qi_ranges[qtj][plj].base_matrices){
|
||||
_qinfo->qi_ranges[qti][pli].base_matrices=NULL;
|
||||
}
|
||||
}
|
||||
if(qti>0){
|
||||
if(_qinfo->qi_ranges[1][pli].sizes==
|
||||
_qinfo->qi_ranges[0][pli].sizes){
|
||||
_qinfo->qi_ranges[1][pli].sizes=NULL;
|
||||
}
|
||||
if(_qinfo->qi_ranges[1][pli].base_matrices==
|
||||
_qinfo->qi_ranges[0][pli].base_matrices){
|
||||
_qinfo->qi_ranges[1][pli].base_matrices=NULL;
|
||||
}
|
||||
}
|
||||
/*Now free all the non-duplicate storage.*/
|
||||
_ogg_free((void *)_qinfo->qi_ranges[qti][pli].sizes);
|
||||
_ogg_free((void *)_qinfo->qi_ranges[qti][pli].base_matrices);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_dequant_H)
|
||||
# define _dequant_H (1)
|
||||
# include "quant.h"
|
||||
# include "bitpack.h"
|
||||
|
||||
int oc_quant_params_unpack(oc_pack_buf *_opb,
|
||||
th_quant_info *_qinfo);
|
||||
void oc_quant_params_clear(th_quant_info *_qinfo);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "apiwrapper.h"
|
||||
#include "encint.h"
|
||||
#include "theora/theoraenc.h"
|
||||
|
||||
|
||||
|
||||
static void th_enc_api_clear(th_api_wrapper *_api){
|
||||
if(_api->encode)th_encode_free(_api->encode);
|
||||
memset(_api,0,sizeof(*_api));
|
||||
}
|
||||
|
||||
static void theora_encode_clear(theora_state *_te){
|
||||
if(_te->i!=NULL)theora_info_clear(_te->i);
|
||||
memset(_te,0,sizeof(*_te));
|
||||
}
|
||||
|
||||
static int theora_encode_control(theora_state *_te,int _req,
|
||||
void *_buf,size_t _buf_sz){
|
||||
return th_encode_ctl(((th_api_wrapper *)_te->i->codec_setup)->encode,
|
||||
_req,_buf,_buf_sz);
|
||||
}
|
||||
|
||||
static ogg_int64_t theora_encode_granule_frame(theora_state *_te,
|
||||
ogg_int64_t _gp){
|
||||
return th_granule_frame(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
|
||||
}
|
||||
|
||||
static double theora_encode_granule_time(theora_state *_te,ogg_int64_t _gp){
|
||||
return th_granule_time(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
|
||||
}
|
||||
|
||||
static const oc_state_dispatch_vtable OC_ENC_DISPATCH_VTBL={
|
||||
(oc_state_clear_func)theora_encode_clear,
|
||||
(oc_state_control_func)theora_encode_control,
|
||||
(oc_state_granule_frame_func)theora_encode_granule_frame,
|
||||
(oc_state_granule_time_func)theora_encode_granule_time,
|
||||
};
|
||||
|
||||
int theora_encode_init(theora_state *_te,theora_info *_ci){
|
||||
th_api_info *apiinfo;
|
||||
th_info info;
|
||||
ogg_uint32_t keyframe_frequency_force;
|
||||
/*Allocate our own combined API wrapper/theora_info struct.
|
||||
We put them both in one malloc'd block so that when the API wrapper is
|
||||
freed, the info struct goes with it.
|
||||
This avoids having to figure out whether or not we need to free the info
|
||||
struct in either theora_info_clear() or theora_clear().*/
|
||||
apiinfo=(th_api_info *)_ogg_malloc(sizeof(*apiinfo));
|
||||
if(apiinfo==NULL)return TH_EFAULT;
|
||||
/*Make our own copy of the info struct, since its lifetime should be
|
||||
independent of the one we were passed in.*/
|
||||
*&apiinfo->info=*_ci;
|
||||
oc_theora_info2th_info(&info,_ci);
|
||||
apiinfo->api.encode=th_encode_alloc(&info);
|
||||
if(apiinfo->api.encode==NULL){
|
||||
_ogg_free(apiinfo);
|
||||
return OC_EINVAL;
|
||||
}
|
||||
apiinfo->api.clear=(oc_setup_clear_func)th_enc_api_clear;
|
||||
/*Provide entry points for ABI compatibility with old decoder shared libs.*/
|
||||
_te->internal_encode=(void *)&OC_ENC_DISPATCH_VTBL;
|
||||
_te->internal_decode=NULL;
|
||||
_te->granulepos=0;
|
||||
_te->i=&apiinfo->info;
|
||||
_te->i->codec_setup=&apiinfo->api;
|
||||
/*Set the precise requested keyframe frequency.*/
|
||||
keyframe_frequency_force=_ci->keyframe_auto_p?
|
||||
_ci->keyframe_frequency_force:_ci->keyframe_frequency;
|
||||
th_encode_ctl(apiinfo->api.encode,
|
||||
TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
|
||||
&keyframe_frequency_force,sizeof(keyframe_frequency_force));
|
||||
/*TODO: Additional codec setup using the extra fields in theora_info.*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){
|
||||
th_api_wrapper *api;
|
||||
th_ycbcr_buffer buf;
|
||||
int ret;
|
||||
api=(th_api_wrapper *)_te->i->codec_setup;
|
||||
buf[0].width=_yuv->y_width;
|
||||
buf[0].height=_yuv->y_height;
|
||||
buf[0].stride=_yuv->y_stride;
|
||||
buf[0].data=_yuv->y;
|
||||
buf[1].width=_yuv->uv_width;
|
||||
buf[1].height=_yuv->uv_height;
|
||||
buf[1].stride=_yuv->uv_stride;
|
||||
buf[1].data=_yuv->u;
|
||||
buf[2].width=_yuv->uv_width;
|
||||
buf[2].height=_yuv->uv_height;
|
||||
buf[2].stride=_yuv->uv_stride;
|
||||
buf[2].data=_yuv->v;
|
||||
ret=th_encode_ycbcr_in(api->encode,buf);
|
||||
if(ret<0)return ret;
|
||||
_te->granulepos=api->encode->state.granpos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){
|
||||
th_api_wrapper *api;
|
||||
api=(th_api_wrapper *)_te->i->codec_setup;
|
||||
return th_encode_packetout(api->encode,_last_p,_op);
|
||||
}
|
||||
|
||||
int theora_encode_header(theora_state *_te,ogg_packet *_op){
|
||||
oc_enc_ctx *enc;
|
||||
th_api_wrapper *api;
|
||||
int ret;
|
||||
api=(th_api_wrapper *)_te->i->codec_setup;
|
||||
enc=api->encode;
|
||||
/*If we've already started encoding, fail.*/
|
||||
if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
|
||||
return TH_EINVAL;
|
||||
}
|
||||
/*Reset the state to make sure we output an info packet.*/
|
||||
enc->packet_state=OC_PACKET_INFO_HDR;
|
||||
ret=th_encode_flushheader(api->encode,NULL,_op);
|
||||
return ret>=0?0:ret;
|
||||
}
|
||||
|
||||
int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){
|
||||
oggpack_buffer opb;
|
||||
void *buf;
|
||||
int packet_state;
|
||||
int ret;
|
||||
packet_state=OC_PACKET_COMMENT_HDR;
|
||||
oggpackB_writeinit(&opb);
|
||||
ret=oc_state_flushheader(NULL,&packet_state,&opb,NULL,NULL,
|
||||
th_version_string(),(th_comment *)_tc,_op);
|
||||
if(ret>=0){
|
||||
/*The oggpack_buffer's lifetime ends with this function, so we have to
|
||||
copy out the packet contents.
|
||||
Presumably the application knows it is supposed to free this.
|
||||
This part works nothing like the Vorbis API, and the documentation on it
|
||||
has been wrong for some time, claiming libtheora owned the memory.*/
|
||||
buf=_ogg_malloc(_op->bytes);
|
||||
if(buf==NULL){
|
||||
_op->packet=NULL;
|
||||
ret=TH_EFAULT;
|
||||
}
|
||||
else{
|
||||
memcpy(buf,_op->packet,_op->bytes);
|
||||
_op->packet=buf;
|
||||
ret=0;
|
||||
}
|
||||
}
|
||||
oggpack_writeclear(&opb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int theora_encode_tables(theora_state *_te,ogg_packet *_op){
|
||||
oc_enc_ctx *enc;
|
||||
th_api_wrapper *api;
|
||||
int ret;
|
||||
api=(th_api_wrapper *)_te->i->codec_setup;
|
||||
enc=api->encode;
|
||||
/*If we've already started encoding, fail.*/
|
||||
if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
|
||||
return TH_EINVAL;
|
||||
}
|
||||
/*Reset the state to make sure we output a setup packet.*/
|
||||
enc->packet_state=OC_PACKET_SETUP_HDR;
|
||||
ret=th_encode_flushheader(api->encode,NULL,_op);
|
||||
return ret>=0?0:ret;
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "encint.h"
|
||||
|
||||
|
||||
void oc_enc_frag_sub_c(ogg_int16_t _diff[64],const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int j;
|
||||
for(j=0;j<8;j++)_diff[i*8+j]=(ogg_int16_t)(_src[j]-_ref[j]);
|
||||
_src+=_ystride;
|
||||
_ref+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
void oc_enc_frag_sub_128_c(ogg_int16_t *_diff,
|
||||
const unsigned char *_src,int _ystride){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int j;
|
||||
for(j=0;j<8;j++)_diff[i*8+j]=(ogg_int16_t)(_src[j]-128);
|
||||
_src+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_sad_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
unsigned sad;
|
||||
int i;
|
||||
sad=0;
|
||||
for(i=8;i-->0;){
|
||||
int j;
|
||||
for(j=0;j<8;j++)sad+=abs(_src[j]-_ref[j]);
|
||||
_src+=_ystride;
|
||||
_ref+=_ystride;
|
||||
}
|
||||
return sad;
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_sad_thresh_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,unsigned _thresh){
|
||||
unsigned sad;
|
||||
int i;
|
||||
sad=0;
|
||||
for(i=8;i-->0;){
|
||||
int j;
|
||||
for(j=0;j<8;j++)sad+=abs(_src[j]-_ref[j]);
|
||||
if(sad>_thresh)break;
|
||||
_src+=_ystride;
|
||||
_ref+=_ystride;
|
||||
}
|
||||
return sad;
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_sad2_thresh_c(const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride,
|
||||
unsigned _thresh){
|
||||
unsigned sad;
|
||||
int i;
|
||||
sad=0;
|
||||
for(i=8;i-->0;){
|
||||
int j;
|
||||
for(j=0;j<8;j++)sad+=abs(_src[j]-(_ref1[j]+_ref2[j]>>1));
|
||||
if(sad>_thresh)break;
|
||||
_src+=_ystride;
|
||||
_ref1+=_ystride;
|
||||
_ref2+=_ystride;
|
||||
}
|
||||
return sad;
|
||||
}
|
||||
|
||||
static void oc_diff_hadamard(ogg_int16_t _buf[64],const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int t0;
|
||||
int t1;
|
||||
int t2;
|
||||
int t3;
|
||||
int t4;
|
||||
int t5;
|
||||
int t6;
|
||||
int t7;
|
||||
int r;
|
||||
/*Hadamard stage 1:*/
|
||||
t0=_src[0]-_ref[0]+_src[4]-_ref[4];
|
||||
t4=_src[0]-_ref[0]-_src[4]+_ref[4];
|
||||
t1=_src[1]-_ref[1]+_src[5]-_ref[5];
|
||||
t5=_src[1]-_ref[1]-_src[5]+_ref[5];
|
||||
t2=_src[2]-_ref[2]+_src[6]-_ref[6];
|
||||
t6=_src[2]-_ref[2]-_src[6]+_ref[6];
|
||||
t3=_src[3]-_ref[3]+_src[7]-_ref[7];
|
||||
t7=_src[3]-_ref[3]-_src[7]+_ref[7];
|
||||
/*Hadamard stage 2:*/
|
||||
r=t0;
|
||||
t0+=t2;
|
||||
t2=r-t2;
|
||||
r=t1;
|
||||
t1+=t3;
|
||||
t3=r-t3;
|
||||
r=t4;
|
||||
t4+=t6;
|
||||
t6=r-t6;
|
||||
r=t5;
|
||||
t5+=t7;
|
||||
t7=r-t7;
|
||||
/*Hadamard stage 3:*/
|
||||
_buf[0*8+i]=(ogg_int16_t)(t0+t1);
|
||||
_buf[1*8+i]=(ogg_int16_t)(t0-t1);
|
||||
_buf[2*8+i]=(ogg_int16_t)(t2+t3);
|
||||
_buf[3*8+i]=(ogg_int16_t)(t2-t3);
|
||||
_buf[4*8+i]=(ogg_int16_t)(t4+t5);
|
||||
_buf[5*8+i]=(ogg_int16_t)(t4-t5);
|
||||
_buf[6*8+i]=(ogg_int16_t)(t6+t7);
|
||||
_buf[7*8+i]=(ogg_int16_t)(t6-t7);
|
||||
_src+=_ystride;
|
||||
_ref+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
static void oc_diff_hadamard2(ogg_int16_t _buf[64],const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int t0;
|
||||
int t1;
|
||||
int t2;
|
||||
int t3;
|
||||
int t4;
|
||||
int t5;
|
||||
int t6;
|
||||
int t7;
|
||||
int r;
|
||||
/*Hadamard stage 1:*/
|
||||
r=_ref1[0]+_ref2[0]>>1;
|
||||
t4=_ref1[4]+_ref2[4]>>1;
|
||||
t0=_src[0]-r+_src[4]-t4;
|
||||
t4=_src[0]-r-_src[4]+t4;
|
||||
r=_ref1[1]+_ref2[1]>>1;
|
||||
t5=_ref1[5]+_ref2[5]>>1;
|
||||
t1=_src[1]-r+_src[5]-t5;
|
||||
t5=_src[1]-r-_src[5]+t5;
|
||||
r=_ref1[2]+_ref2[2]>>1;
|
||||
t6=_ref1[6]+_ref2[6]>>1;
|
||||
t2=_src[2]-r+_src[6]-t6;
|
||||
t6=_src[2]-r-_src[6]+t6;
|
||||
r=_ref1[3]+_ref2[3]>>1;
|
||||
t7=_ref1[7]+_ref2[7]>>1;
|
||||
t3=_src[3]-r+_src[7]-t7;
|
||||
t7=_src[3]-r-_src[7]+t7;
|
||||
/*Hadamard stage 2:*/
|
||||
r=t0;
|
||||
t0+=t2;
|
||||
t2=r-t2;
|
||||
r=t1;
|
||||
t1+=t3;
|
||||
t3=r-t3;
|
||||
r=t4;
|
||||
t4+=t6;
|
||||
t6=r-t6;
|
||||
r=t5;
|
||||
t5+=t7;
|
||||
t7=r-t7;
|
||||
/*Hadamard stage 3:*/
|
||||
_buf[0*8+i]=(ogg_int16_t)(t0+t1);
|
||||
_buf[1*8+i]=(ogg_int16_t)(t0-t1);
|
||||
_buf[2*8+i]=(ogg_int16_t)(t2+t3);
|
||||
_buf[3*8+i]=(ogg_int16_t)(t2-t3);
|
||||
_buf[4*8+i]=(ogg_int16_t)(t4+t5);
|
||||
_buf[5*8+i]=(ogg_int16_t)(t4-t5);
|
||||
_buf[6*8+i]=(ogg_int16_t)(t6+t7);
|
||||
_buf[7*8+i]=(ogg_int16_t)(t6-t7);
|
||||
_src+=_ystride;
|
||||
_ref1+=_ystride;
|
||||
_ref2+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
static void oc_intra_hadamard(ogg_int16_t _buf[64],const unsigned char *_src,
|
||||
int _ystride){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int t0;
|
||||
int t1;
|
||||
int t2;
|
||||
int t3;
|
||||
int t4;
|
||||
int t5;
|
||||
int t6;
|
||||
int t7;
|
||||
int r;
|
||||
/*Hadamard stage 1:*/
|
||||
t0=_src[0]+_src[4];
|
||||
t4=_src[0]-_src[4];
|
||||
t1=_src[1]+_src[5];
|
||||
t5=_src[1]-_src[5];
|
||||
t2=_src[2]+_src[6];
|
||||
t6=_src[2]-_src[6];
|
||||
t3=_src[3]+_src[7];
|
||||
t7=_src[3]-_src[7];
|
||||
/*Hadamard stage 2:*/
|
||||
r=t0;
|
||||
t0+=t2;
|
||||
t2=r-t2;
|
||||
r=t1;
|
||||
t1+=t3;
|
||||
t3=r-t3;
|
||||
r=t4;
|
||||
t4+=t6;
|
||||
t6=r-t6;
|
||||
r=t5;
|
||||
t5+=t7;
|
||||
t7=r-t7;
|
||||
/*Hadamard stage 3:*/
|
||||
_buf[0*8+i]=(ogg_int16_t)(t0+t1);
|
||||
_buf[1*8+i]=(ogg_int16_t)(t0-t1);
|
||||
_buf[2*8+i]=(ogg_int16_t)(t2+t3);
|
||||
_buf[3*8+i]=(ogg_int16_t)(t2-t3);
|
||||
_buf[4*8+i]=(ogg_int16_t)(t4+t5);
|
||||
_buf[5*8+i]=(ogg_int16_t)(t4-t5);
|
||||
_buf[6*8+i]=(ogg_int16_t)(t6+t7);
|
||||
_buf[7*8+i]=(ogg_int16_t)(t6-t7);
|
||||
_src+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned oc_hadamard_sad(unsigned *_dc,const ogg_int16_t _buf[64]){
|
||||
unsigned sad;
|
||||
unsigned dc;
|
||||
int t0;
|
||||
int t1;
|
||||
int t2;
|
||||
int t3;
|
||||
int t4;
|
||||
int t5;
|
||||
int t6;
|
||||
int t7;
|
||||
int r;
|
||||
int i;
|
||||
sad=dc=0;
|
||||
for(i=0;i<8;i++){
|
||||
/*Hadamard stage 1:*/
|
||||
t0=_buf[i*8+0]+_buf[i*8+4];
|
||||
t4=_buf[i*8+0]-_buf[i*8+4];
|
||||
t1=_buf[i*8+1]+_buf[i*8+5];
|
||||
t5=_buf[i*8+1]-_buf[i*8+5];
|
||||
t2=_buf[i*8+2]+_buf[i*8+6];
|
||||
t6=_buf[i*8+2]-_buf[i*8+6];
|
||||
t3=_buf[i*8+3]+_buf[i*8+7];
|
||||
t7=_buf[i*8+3]-_buf[i*8+7];
|
||||
/*Hadamard stage 2:*/
|
||||
r=t0;
|
||||
t0+=t2;
|
||||
t2=r-t2;
|
||||
r=t1;
|
||||
t1+=t3;
|
||||
t3=r-t3;
|
||||
r=t4;
|
||||
t4+=t6;
|
||||
t6=r-t6;
|
||||
r=t5;
|
||||
t5+=t7;
|
||||
t7=r-t7;
|
||||
/*Hadamard stage 3:*/
|
||||
r=abs(t0+t1);
|
||||
r+=abs(t0-t1);
|
||||
r+=abs(t2+t3);
|
||||
r+=abs(t2-t3);
|
||||
r+=abs(t4+t5);
|
||||
r+=abs(t4-t5);
|
||||
r+=abs(t6+t7);
|
||||
r+=abs(t6-t7);
|
||||
sad+=r;
|
||||
}
|
||||
dc=abs(_buf[0]+_buf[1]+_buf[2]+_buf[3]+_buf[4]+_buf[5]+_buf[6]+_buf[7]);
|
||||
*_dc=dc;
|
||||
return sad-dc;
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_satd_c(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
ogg_int16_t buf[64];
|
||||
oc_diff_hadamard(buf,_src,_ref,_ystride);
|
||||
return oc_hadamard_sad(_dc,buf);
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_satd2_c(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride){
|
||||
ogg_int16_t buf[64];
|
||||
oc_diff_hadamard2(buf,_src,_ref1,_ref2,_ystride);
|
||||
return oc_hadamard_sad(_dc,buf);
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_intra_satd_c(unsigned *_dc,
|
||||
const unsigned char *_src,int _ystride){
|
||||
ogg_int16_t buf[64];
|
||||
oc_intra_hadamard(buf,_src,_ystride);
|
||||
return oc_hadamard_sad(_dc,buf);
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_ssd_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
unsigned ret;
|
||||
int y;
|
||||
int x;
|
||||
ret=0;
|
||||
for(y=0;y<8;y++){
|
||||
for(x=0;x<8;x++)ret+=(_src[x]-_ref[x])*(_src[x]-_ref[x]);
|
||||
_src+=_ystride;
|
||||
_ref+=_ystride;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_border_ssd_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,ogg_int64_t _mask){
|
||||
unsigned ret;
|
||||
int y;
|
||||
int x;
|
||||
ret=0;
|
||||
for(y=0;y<8;y++){
|
||||
for(x=0;x<8;x++,_mask>>=1){
|
||||
if(_mask&1)ret+=(_src[x]-_ref[x])*(_src[x]-_ref[x]);
|
||||
}
|
||||
_src+=_ystride;
|
||||
_ref+=_ystride;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void oc_enc_frag_copy2_c(unsigned char *_dst,
|
||||
const unsigned char *_src1,const unsigned char *_src2,int _ystride){
|
||||
int i;
|
||||
int j;
|
||||
for(i=8;i-->0;){
|
||||
for(j=0;j<8;j++)_dst[j]=_src1[j]+_src2[j]>>1;
|
||||
_dst+=_ystride;
|
||||
_src1+=_ystride;
|
||||
_src2+=_ystride;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "state.h"
|
||||
#include "enquant.h"
|
||||
#include "huffenc.h"
|
||||
|
||||
|
||||
|
||||
/*Packs a series of octets from a given byte array into the pack buffer.
|
||||
_opb: The pack buffer to store the octets in.
|
||||
_buf: The byte array containing the bytes to pack.
|
||||
_len: The number of octets to pack.*/
|
||||
static void oc_pack_octets(oggpack_buffer *_opb,const char *_buf,int _len){
|
||||
int i;
|
||||
for(i=0;i<_len;i++)oggpackB_write(_opb,_buf[i],8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int oc_state_flushheader(oc_theora_state *_state,int *_packet_state,
|
||||
oggpack_buffer *_opb,const th_quant_info *_qinfo,
|
||||
const th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS],
|
||||
const char *_vendor,th_comment *_tc,ogg_packet *_op){
|
||||
unsigned char *packet;
|
||||
int b_o_s;
|
||||
if(_op==NULL)return TH_EFAULT;
|
||||
switch(*_packet_state){
|
||||
/*Codec info header.*/
|
||||
case OC_PACKET_INFO_HDR:{
|
||||
if(_state==NULL)return TH_EFAULT;
|
||||
oggpackB_reset(_opb);
|
||||
/*Mark this packet as the info header.*/
|
||||
oggpackB_write(_opb,0x80,8);
|
||||
/*Write the codec string.*/
|
||||
oc_pack_octets(_opb,"theora",6);
|
||||
/*Write the codec bitstream version.*/
|
||||
oggpackB_write(_opb,TH_VERSION_MAJOR,8);
|
||||
oggpackB_write(_opb,TH_VERSION_MINOR,8);
|
||||
oggpackB_write(_opb,TH_VERSION_SUB,8);
|
||||
/*Describe the encoded frame.*/
|
||||
oggpackB_write(_opb,_state->info.frame_width>>4,16);
|
||||
oggpackB_write(_opb,_state->info.frame_height>>4,16);
|
||||
oggpackB_write(_opb,_state->info.pic_width,24);
|
||||
oggpackB_write(_opb,_state->info.pic_height,24);
|
||||
oggpackB_write(_opb,_state->info.pic_x,8);
|
||||
oggpackB_write(_opb,_state->info.pic_y,8);
|
||||
oggpackB_write(_opb,_state->info.fps_numerator,32);
|
||||
oggpackB_write(_opb,_state->info.fps_denominator,32);
|
||||
oggpackB_write(_opb,_state->info.aspect_numerator,24);
|
||||
oggpackB_write(_opb,_state->info.aspect_denominator,24);
|
||||
oggpackB_write(_opb,_state->info.colorspace,8);
|
||||
oggpackB_write(_opb,_state->info.target_bitrate,24);
|
||||
oggpackB_write(_opb,_state->info.quality,6);
|
||||
oggpackB_write(_opb,_state->info.keyframe_granule_shift,5);
|
||||
oggpackB_write(_opb,_state->info.pixel_fmt,2);
|
||||
/*Spare configuration bits.*/
|
||||
oggpackB_write(_opb,0,3);
|
||||
b_o_s=1;
|
||||
}break;
|
||||
/*Comment header.*/
|
||||
case OC_PACKET_COMMENT_HDR:{
|
||||
int vendor_len;
|
||||
int i;
|
||||
if(_tc==NULL)return TH_EFAULT;
|
||||
vendor_len=strlen(_vendor);
|
||||
oggpackB_reset(_opb);
|
||||
/*Mark this packet as the comment header.*/
|
||||
oggpackB_write(_opb,0x81,8);
|
||||
/*Write the codec string.*/
|
||||
oc_pack_octets(_opb,"theora",6);
|
||||
/*Write the vendor string.*/
|
||||
oggpack_write(_opb,vendor_len,32);
|
||||
oc_pack_octets(_opb,_vendor,vendor_len);
|
||||
oggpack_write(_opb,_tc->comments,32);
|
||||
for(i=0;i<_tc->comments;i++){
|
||||
if(_tc->user_comments[i]!=NULL){
|
||||
oggpack_write(_opb,_tc->comment_lengths[i],32);
|
||||
oc_pack_octets(_opb,_tc->user_comments[i],_tc->comment_lengths[i]);
|
||||
}
|
||||
else oggpack_write(_opb,0,32);
|
||||
}
|
||||
b_o_s=0;
|
||||
}break;
|
||||
/*Codec setup header.*/
|
||||
case OC_PACKET_SETUP_HDR:{
|
||||
int ret;
|
||||
oggpackB_reset(_opb);
|
||||
/*Mark this packet as the setup header.*/
|
||||
oggpackB_write(_opb,0x82,8);
|
||||
/*Write the codec string.*/
|
||||
oc_pack_octets(_opb,"theora",6);
|
||||
/*Write the quantizer tables.*/
|
||||
oc_quant_params_pack(_opb,_qinfo);
|
||||
/*Write the huffman codes.*/
|
||||
ret=oc_huff_codes_pack(_opb,_codes);
|
||||
/*This should never happen, because we validate the tables when they
|
||||
are set.
|
||||
If you see, it's a good chance memory is being corrupted.*/
|
||||
if(ret<0)return ret;
|
||||
b_o_s=0;
|
||||
}break;
|
||||
/*No more headers to emit.*/
|
||||
default:return 0;
|
||||
}
|
||||
/*This is kind of fugly: we hand the user a buffer which they do not own.
|
||||
We will overwrite it when the next packet is output, so the user better be
|
||||
done with it by then.
|
||||
Vorbis is little better: it hands back buffers that it will free the next
|
||||
time the headers are requested, or when the encoder is cleared.
|
||||
Hopefully libogg2 will make this much cleaner.*/
|
||||
packet=oggpackB_get_buffer(_opb);
|
||||
/*If there's no packet, malloc failed while writing.*/
|
||||
if(packet==NULL)return TH_EFAULT;
|
||||
_op->packet=packet;
|
||||
_op->bytes=oggpackB_bytes(_opb);
|
||||
_op->b_o_s=b_o_s;
|
||||
_op->e_o_s=0;
|
||||
_op->granulepos=0;
|
||||
_op->packetno=*_packet_state+3;
|
||||
return ++(*_packet_state)+3;
|
||||
}
|
||||
@@ -0,0 +1,825 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_encint_H)
|
||||
# define _encint_H (1)
|
||||
# include "theora/theoraenc.h"
|
||||
# include "state.h"
|
||||
# include "mathops.h"
|
||||
# include "enquant.h"
|
||||
# include "huffenc.h"
|
||||
/*# define OC_COLLECT_METRICS*/
|
||||
|
||||
|
||||
|
||||
typedef oc_mv oc_mv2[2];
|
||||
|
||||
typedef struct oc_enc_opt_vtable oc_enc_opt_vtable;
|
||||
typedef struct oc_enc_opt_data oc_enc_opt_data;
|
||||
typedef struct oc_mb_enc_info oc_mb_enc_info;
|
||||
typedef struct oc_mode_scheme_chooser oc_mode_scheme_chooser;
|
||||
typedef struct oc_fr_state oc_fr_state;
|
||||
typedef struct oc_qii_state oc_qii_state;
|
||||
typedef struct oc_enc_pipeline_state oc_enc_pipeline_state;
|
||||
typedef struct oc_mode_rd oc_mode_rd;
|
||||
typedef struct oc_iir_filter oc_iir_filter;
|
||||
typedef struct oc_frame_metrics oc_frame_metrics;
|
||||
typedef struct oc_rc_state oc_rc_state;
|
||||
typedef struct th_enc_ctx oc_enc_ctx;
|
||||
typedef struct oc_token_checkpoint oc_token_checkpoint;
|
||||
|
||||
|
||||
|
||||
/*Encoder-specific accelerated functions.*/
|
||||
# if defined(OC_X86_ASM)
|
||||
# if defined(_MSC_VER)
|
||||
# include "x86_vc/x86enc.h"
|
||||
# else
|
||||
# include "x86/x86enc.h"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(oc_enc_accel_init)
|
||||
# define oc_enc_accel_init oc_enc_accel_init_c
|
||||
# endif
|
||||
# if defined(OC_ENC_USE_VTABLE)
|
||||
# if !defined(oc_enc_frag_sub)
|
||||
# define oc_enc_frag_sub(_enc,_diff,_src,_ref,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_sub)(_diff,_src,_ref,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sub_128)
|
||||
# define oc_enc_frag_sub_128(_enc,_diff,_src,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_sub_128)(_diff,_src,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sad)
|
||||
# define oc_enc_frag_sad(_enc,_src,_ref,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_sad)(_src,_ref,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sad_thresh)
|
||||
# define oc_enc_frag_sad_thresh(_enc,_src,_ref,_ystride,_thresh) \
|
||||
((*(_enc)->opt_vtable.frag_sad_thresh)(_src,_ref,_ystride,_thresh))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sad2_thresh)
|
||||
# define oc_enc_frag_sad2_thresh(_enc,_src,_ref1,_ref2,_ystride,_thresh) \
|
||||
((*(_enc)->opt_vtable.frag_sad2_thresh)(_src,_ref1,_ref2,_ystride,_thresh))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_satd)
|
||||
# define oc_enc_frag_satd(_enc,_dc,_src,_ref,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_satd)(_dc,_src,_ref,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_satd2)
|
||||
# define oc_enc_frag_satd2(_enc,_dc,_src,_ref1,_ref2,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_satd2)(_dc,_src,_ref1,_ref2,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_intra_satd)
|
||||
# define oc_enc_frag_intra_satd(_enc,_dc,_src,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_intra_satd)(_dc,_src,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_ssd)
|
||||
# define oc_enc_frag_ssd(_enc,_src,_ref,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_ssd)(_src,_ref,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_border_ssd)
|
||||
# define oc_enc_frag_border_ssd(_enc,_src,_ref,_ystride,_mask) \
|
||||
((*(_enc)->opt_vtable.frag_border_ssd)(_src,_ref,_ystride,_mask))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_copy2)
|
||||
# define oc_enc_frag_copy2(_enc,_dst,_src1,_src2,_ystride) \
|
||||
((*(_enc)->opt_vtable.frag_copy2)(_dst,_src1,_src2,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_enc_enquant_table_init)
|
||||
# define oc_enc_enquant_table_init(_enc,_enquant,_dequant) \
|
||||
((*(_enc)->opt_vtable.enquant_table_init)(_enquant,_dequant))
|
||||
# endif
|
||||
# if !defined(oc_enc_enquant_table_fixup)
|
||||
# define oc_enc_enquant_table_fixup(_enc,_enquant,_nqis) \
|
||||
((*(_enc)->opt_vtable.enquant_table_fixup)(_enquant,_nqis))
|
||||
# endif
|
||||
# if !defined(oc_enc_quantize)
|
||||
# define oc_enc_quantize(_enc,_qdct,_dct,_dequant,_enquant) \
|
||||
((*(_enc)->opt_vtable.quantize)(_qdct,_dct,_dequant,_enquant))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_recon_intra)
|
||||
# define oc_enc_frag_recon_intra(_enc,_dst,_ystride,_residue) \
|
||||
((*(_enc)->opt_vtable.frag_recon_intra)(_dst,_ystride,_residue))
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_recon_inter)
|
||||
# define oc_enc_frag_recon_inter(_enc,_dst,_src,_ystride,_residue) \
|
||||
((*(_enc)->opt_vtable.frag_recon_inter)(_dst,_src,_ystride,_residue))
|
||||
# endif
|
||||
# if !defined(oc_enc_fdct8x8)
|
||||
# define oc_enc_fdct8x8(_enc,_y,_x) \
|
||||
((*(_enc)->opt_vtable.fdct8x8)(_y,_x))
|
||||
# endif
|
||||
# else
|
||||
# if !defined(oc_enc_frag_sub)
|
||||
# define oc_enc_frag_sub(_enc,_diff,_src,_ref,_ystride) \
|
||||
oc_enc_frag_sub_c(_diff,_src,_ref,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sub_128)
|
||||
# define oc_enc_frag_sub_128(_enc,_diff,_src,_ystride) \
|
||||
oc_enc_frag_sub_128_c(_diff,_src,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sad)
|
||||
# define oc_enc_frag_sad(_enc,_src,_ref,_ystride) \
|
||||
oc_enc_frag_sad_c(_src,_ref,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sad_thresh)
|
||||
# define oc_enc_frag_sad_thresh(_enc,_src,_ref,_ystride,_thresh) \
|
||||
oc_enc_frag_sad_thresh_c(_src,_ref,_ystride,_thresh)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_sad2_thresh)
|
||||
# define oc_enc_frag_sad2_thresh(_enc,_src,_ref1,_ref2,_ystride,_thresh) \
|
||||
oc_enc_frag_sad2_thresh_c(_src,_ref1,_ref2,_ystride,_thresh)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_satd)
|
||||
# define oc_enc_frag_satd(_enc,_dc,_src,_ref,_ystride) \
|
||||
oc_enc_frag_satd_c(_dc,_src,_ref,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_satd2)
|
||||
# define oc_enc_frag_satd2(_enc,_dc,_src,_ref1,_ref2,_ystride) \
|
||||
oc_enc_frag_satd2_c(_dc,_src,_ref1,_ref2,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_intra_satd)
|
||||
# define oc_enc_frag_intra_satd(_enc,_dc,_src,_ystride) \
|
||||
oc_enc_frag_intra_satd_c(_dc,_src,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_ssd)
|
||||
# define oc_enc_frag_ssd(_enc,_src,_ref,_ystride) \
|
||||
oc_enc_frag_ssd_c(_src,_ref,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_border_ssd)
|
||||
# define oc_enc_frag_border_ssd(_enc,_src,_ref,_ystride,_mask) \
|
||||
oc_enc_frag_border_ssd_c(_src,_ref,_ystride,_mask)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_copy2)
|
||||
# define oc_enc_frag_copy2(_enc,_dst,_src1,_src2,_ystride) \
|
||||
oc_enc_frag_copy2_c(_dst,_src1,_src2,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_enc_enquant_table_init)
|
||||
# define oc_enc_enquant_table_init(_enc,_enquant,_dequant) \
|
||||
oc_enc_enquant_table_init_c(_enquant,_dequant)
|
||||
# endif
|
||||
# if !defined(oc_enc_enquant_table_fixup)
|
||||
# define oc_enc_enquant_table_fixup(_enc,_enquant,_nqis) \
|
||||
oc_enc_enquant_table_fixup_c(_enquant,_nqis)
|
||||
# endif
|
||||
# if !defined(oc_enc_quantize)
|
||||
# define oc_enc_quantize(_enc,_qdct,_dct,_dequant,_enquant) \
|
||||
oc_enc_quantize_c(_qdct,_dct,_dequant,_enquant)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_recon_intra)
|
||||
# define oc_enc_frag_recon_intra(_enc,_dst,_ystride,_residue) \
|
||||
oc_frag_recon_intra_c(_dst,_ystride,_residue)
|
||||
# endif
|
||||
# if !defined(oc_enc_frag_recon_inter)
|
||||
# define oc_enc_frag_recon_inter(_enc,_dst,_src,_ystride,_residue) \
|
||||
oc_frag_recon_inter_c(_dst,_src,_ystride,_residue)
|
||||
# endif
|
||||
# if !defined(oc_enc_fdct8x8)
|
||||
# define oc_enc_fdct8x8(_enc,_y,_x) oc_enc_fdct8x8_c(_y,_x)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
/*Constants for the packet-out state machine specific to the encoder.*/
|
||||
|
||||
/*Next packet to emit: Data packet, but none are ready yet.*/
|
||||
#define OC_PACKET_EMPTY (0)
|
||||
/*Next packet to emit: Data packet, and one is ready.*/
|
||||
#define OC_PACKET_READY (1)
|
||||
|
||||
/*All features enabled.*/
|
||||
#define OC_SP_LEVEL_SLOW (0)
|
||||
/*Enable early skip.*/
|
||||
#define OC_SP_LEVEL_EARLY_SKIP (1)
|
||||
/*Use analysis shortcuts, single quantizer, and faster tokenization.*/
|
||||
#define OC_SP_LEVEL_FAST_ANALYSIS (2)
|
||||
/*Disable motion compensation.*/
|
||||
#define OC_SP_LEVEL_NOMC (3)
|
||||
/*Maximum valid speed level.*/
|
||||
#define OC_SP_LEVEL_MAX (3)
|
||||
|
||||
|
||||
/*The number of extra bits of precision at which to store rate metrics.*/
|
||||
# define OC_BIT_SCALE (6)
|
||||
/*The number of extra bits of precision at which to store RMSE metrics.
|
||||
This must be at least half OC_BIT_SCALE (rounded up).*/
|
||||
# define OC_RMSE_SCALE (5)
|
||||
/*The number of quantizer bins to partition statistics into.*/
|
||||
# define OC_LOGQ_BINS (8)
|
||||
/*The number of SATD bins to partition statistics into.*/
|
||||
# define OC_SAD_BINS (24)
|
||||
/*The number of bits of precision to drop from SAD scores to assign them to a
|
||||
bin.*/
|
||||
# define OC_SAD_SHIFT (9)
|
||||
|
||||
|
||||
/*Masking is applied by scaling the D used in R-D optimization (via rd_scale)
|
||||
or the lambda parameter (via rd_iscale).
|
||||
These are only equivalent within a single block; when more than one block is
|
||||
being considered, the former is the interpretation used.*/
|
||||
|
||||
/*This must be at least 4 for OC_RD_SKIP_SCALE() to work below.*/
|
||||
# define OC_RD_SCALE_BITS (12-OC_BIT_SCALE)
|
||||
# define OC_RD_ISCALE_BITS (11)
|
||||
|
||||
/*This macro is applied to _ssd values with just 4 bits of headroom
|
||||
((15-OC_RMSE_SCALE)*2+OC_BIT_SCALE+2); since we want to allow rd_scales as
|
||||
large as 16, and need additional fractional bits, our only recourse that
|
||||
doesn't lose precision on blocks with very small SSDs is to use a wider
|
||||
multiply.*/
|
||||
# if LONG_MAX>2147483647
|
||||
# define OC_RD_SCALE(_ssd,_rd_scale) \
|
||||
((unsigned)((unsigned long)(_ssd)*(_rd_scale) \
|
||||
+((1<<OC_RD_SCALE_BITS)>>1)>>OC_RD_SCALE_BITS))
|
||||
# else
|
||||
# define OC_RD_SCALE(_ssd,_rd_scale) \
|
||||
(((_ssd)>>OC_RD_SCALE_BITS)*(_rd_scale) \
|
||||
+(((_ssd)&(1<<OC_RD_SCALE_BITS)-1)*(_rd_scale) \
|
||||
+((1<<OC_RD_SCALE_BITS)>>1)>>OC_RD_SCALE_BITS))
|
||||
# endif
|
||||
# define OC_RD_SKIP_SCALE(_ssd,_rd_scale) \
|
||||
((_ssd)*(_rd_scale)+((1<<OC_RD_SCALE_BITS-4)>>1)>>OC_RD_SCALE_BITS-4)
|
||||
# define OC_RD_ISCALE(_lambda,_rd_iscale) \
|
||||
((_lambda)*(_rd_iscale)+((1<<OC_RD_ISCALE_BITS)>>1)>>OC_RD_ISCALE_BITS)
|
||||
|
||||
|
||||
/*The bits used for each of the MB mode codebooks.*/
|
||||
extern const unsigned char OC_MODE_BITS[2][OC_NMODES];
|
||||
|
||||
/*The bits used for each of the MV codebooks.*/
|
||||
extern const unsigned char OC_MV_BITS[2][64];
|
||||
|
||||
/*The minimum value that can be stored in a SB run for each codeword.
|
||||
The last entry is the upper bound on the length of a single SB run.*/
|
||||
extern const ogg_uint16_t OC_SB_RUN_VAL_MIN[8];
|
||||
/*The bits used for each SB run codeword.*/
|
||||
extern const unsigned char OC_SB_RUN_CODE_NBITS[7];
|
||||
|
||||
/*The bits used for each block run length (starting with 1).*/
|
||||
extern const unsigned char OC_BLOCK_RUN_CODE_NBITS[30];
|
||||
|
||||
|
||||
|
||||
/*Encoder specific functions with accelerated variants.*/
|
||||
struct oc_enc_opt_vtable{
|
||||
void (*frag_sub)(ogg_int16_t _diff[64],const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
void (*frag_sub_128)(ogg_int16_t _diff[64],
|
||||
const unsigned char *_src,int _ystride);
|
||||
unsigned (*frag_sad)(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned (*frag_sad_thresh)(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,unsigned _thresh);
|
||||
unsigned (*frag_sad2_thresh)(const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride,
|
||||
unsigned _thresh);
|
||||
unsigned (*frag_satd)(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned (*frag_satd2)(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride);
|
||||
unsigned (*frag_intra_satd)(unsigned *_dc,const unsigned char *_src,
|
||||
int _ystride);
|
||||
unsigned (*frag_ssd)(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned (*frag_border_ssd)(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,ogg_int64_t _mask);
|
||||
void (*frag_copy2)(unsigned char *_dst,
|
||||
const unsigned char *_src1,const unsigned char *_src2,int _ystride);
|
||||
void (*enquant_table_init)(void *_enquant,
|
||||
const ogg_uint16_t _dequant[64]);
|
||||
void (*enquant_table_fixup)(void *_enquant[3][3][2],int _nqis);
|
||||
int (*quantize)(ogg_int16_t _qdct[64],const ogg_int16_t _dct[64],
|
||||
const ogg_uint16_t _dequant[64],const void *_enquant);
|
||||
void (*frag_recon_intra)(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t _residue[64]);
|
||||
void (*frag_recon_inter)(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride,const ogg_int16_t _residue[64]);
|
||||
void (*fdct8x8)(ogg_int16_t _y[64],const ogg_int16_t _x[64]);
|
||||
};
|
||||
|
||||
|
||||
/*Encoder specific data that varies according to which variants of the above
|
||||
functions are used.*/
|
||||
struct oc_enc_opt_data{
|
||||
/*The size of a single quantizer table.
|
||||
This must be a multiple of enquant_table_alignment.*/
|
||||
size_t enquant_table_size;
|
||||
/*The alignment required for the quantizer tables.
|
||||
This must be a positive power of two.*/
|
||||
int enquant_table_alignment;
|
||||
};
|
||||
|
||||
|
||||
void oc_enc_accel_init(oc_enc_ctx *_enc);
|
||||
|
||||
|
||||
|
||||
/*Encoder-specific macroblock information.*/
|
||||
struct oc_mb_enc_info{
|
||||
/*Neighboring macro blocks that have MVs available from the current frame.*/
|
||||
unsigned cneighbors[4];
|
||||
/*Neighboring macro blocks to use for MVs from the previous frame.*/
|
||||
unsigned pneighbors[4];
|
||||
/*The number of current-frame neighbors.*/
|
||||
unsigned char ncneighbors;
|
||||
/*The number of previous-frame neighbors.*/
|
||||
unsigned char npneighbors;
|
||||
/*Flags indicating which MB modes have been refined.*/
|
||||
unsigned char refined;
|
||||
/*Motion vectors for a macro block for the current frame and the
|
||||
previous two frames.
|
||||
Each is a set of 2 vectors against OC_FRAME_GOLD and OC_FRAME_PREV, which
|
||||
can be used to estimate constant velocity and constant acceleration
|
||||
predictors.
|
||||
Uninitialized MVs are (0,0).*/
|
||||
oc_mv2 analysis_mv[3];
|
||||
/*Current unrefined analysis MVs.*/
|
||||
oc_mv unref_mv[2];
|
||||
/*Unrefined block MVs.*/
|
||||
oc_mv block_mv[4];
|
||||
/*Refined block MVs.*/
|
||||
oc_mv ref_mv[4];
|
||||
/*Minimum motion estimation error from the analysis stage.*/
|
||||
ogg_uint16_t error[2];
|
||||
/*MB error for half-pel refinement for each frame type.*/
|
||||
unsigned satd[2];
|
||||
/*Block error for half-pel refinement.*/
|
||||
unsigned block_satd[4];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*State machine to estimate the opportunity cost of coding a MB mode.*/
|
||||
struct oc_mode_scheme_chooser{
|
||||
/*Pointers to the a list containing the index of each mode in the mode
|
||||
alphabet used by each scheme.
|
||||
The first entry points to the dynamic scheme0_ranks, while the remaining 7
|
||||
point to the constant entries stored in OC_MODE_SCHEMES.*/
|
||||
const unsigned char *mode_ranks[8];
|
||||
/*The ranks for each mode when coded with scheme 0.
|
||||
These are optimized so that the more frequent modes have lower ranks.*/
|
||||
unsigned char scheme0_ranks[OC_NMODES];
|
||||
/*The list of modes, sorted in descending order of frequency, that
|
||||
corresponds to the ranks above.*/
|
||||
unsigned char scheme0_list[OC_NMODES];
|
||||
/*The number of times each mode has been chosen so far.*/
|
||||
unsigned mode_counts[OC_NMODES];
|
||||
/*The list of mode coding schemes, sorted in ascending order of bit cost.*/
|
||||
unsigned char scheme_list[8];
|
||||
/*The number of bits used by each mode coding scheme.*/
|
||||
ptrdiff_t scheme_bits[8];
|
||||
};
|
||||
|
||||
|
||||
void oc_mode_scheme_chooser_init(oc_mode_scheme_chooser *_chooser);
|
||||
|
||||
|
||||
|
||||
/*State to track coded block flags and their bit cost.
|
||||
We use opportunity cost to measure the bits required to code or skip the next
|
||||
block, using the cheaper of the cost to code it fully or partially, so long
|
||||
as both are possible.*/
|
||||
struct oc_fr_state{
|
||||
/*The number of bits required for the coded block flags so far this frame.*/
|
||||
ptrdiff_t bits;
|
||||
/*The length of the current run for the partial super block flag, not
|
||||
including the current super block.*/
|
||||
unsigned sb_partial_count:16;
|
||||
/*The length of the current run for the full super block flag, not
|
||||
including the current super block.*/
|
||||
unsigned sb_full_count:16;
|
||||
/*The length of the coded block flag run when the current super block
|
||||
started.*/
|
||||
unsigned b_coded_count_prev:6;
|
||||
/*The coded block flag when the current super block started.*/
|
||||
signed int b_coded_prev:2;
|
||||
/*The length of the current coded block flag run.*/
|
||||
unsigned b_coded_count:6;
|
||||
/*The current coded block flag.*/
|
||||
signed int b_coded:2;
|
||||
/*The number of blocks processed in the current super block.*/
|
||||
unsigned b_count:5;
|
||||
/*Whether or not it is cheaper to code the current super block partially,
|
||||
even if it could still be coded fully.*/
|
||||
unsigned sb_prefer_partial:1;
|
||||
/*Whether the last super block was coded partially.*/
|
||||
signed int sb_partial:2;
|
||||
/*The number of bits required for the flags for the current super block.*/
|
||||
unsigned sb_bits:6;
|
||||
/*Whether the last non-partial super block was coded fully.*/
|
||||
signed int sb_full:2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct oc_qii_state{
|
||||
ptrdiff_t bits;
|
||||
unsigned qi01_count:14;
|
||||
signed int qi01:2;
|
||||
unsigned qi12_count:14;
|
||||
signed int qi12:2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*Temporary encoder state for the analysis pipeline.*/
|
||||
struct oc_enc_pipeline_state{
|
||||
/*DCT coefficient storage.
|
||||
This is kept off the stack because a) gcc can't align things on the stack
|
||||
reliably on ARM, and b) it avoids (unintentional) data hazards between
|
||||
ARM and NEON code.*/
|
||||
OC_ALIGN16(ogg_int16_t dct_data[128]);
|
||||
OC_ALIGN16(signed char bounding_values[256]);
|
||||
oc_fr_state fr[3];
|
||||
oc_qii_state qs[3];
|
||||
/*Skip SSD storage for the current MCU in each plane.*/
|
||||
unsigned *skip_ssd[3];
|
||||
/*Coded/uncoded fragment lists for each plane for the current MCU.*/
|
||||
ptrdiff_t *coded_fragis[3];
|
||||
ptrdiff_t *uncoded_fragis[3];
|
||||
ptrdiff_t ncoded_fragis[3];
|
||||
ptrdiff_t nuncoded_fragis[3];
|
||||
/*The starting fragment for the current MCU in each plane.*/
|
||||
ptrdiff_t froffset[3];
|
||||
/*The starting row for the current MCU in each plane.*/
|
||||
int fragy0[3];
|
||||
/*The ending row for the current MCU in each plane.*/
|
||||
int fragy_end[3];
|
||||
/*The starting superblock for the current MCU in each plane.*/
|
||||
unsigned sbi0[3];
|
||||
/*The ending superblock for the current MCU in each plane.*/
|
||||
unsigned sbi_end[3];
|
||||
/*The number of tokens for zzi=1 for each color plane.*/
|
||||
int ndct_tokens1[3];
|
||||
/*The outstanding eob_run count for zzi=1 for each color plane.*/
|
||||
int eob_run1[3];
|
||||
/*Whether or not the loop filter is enabled.*/
|
||||
int loop_filter;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*Statistics used to estimate R-D cost of a block in a given coding mode.
|
||||
See modedec.h for more details.*/
|
||||
struct oc_mode_rd{
|
||||
/*The expected bits used by the DCT tokens, shifted by OC_BIT_SCALE.*/
|
||||
ogg_int16_t rate;
|
||||
/*The expected square root of the sum of squared errors, shifted by
|
||||
OC_RMSE_SCALE.*/
|
||||
ogg_int16_t rmse;
|
||||
};
|
||||
|
||||
# if defined(OC_COLLECT_METRICS)
|
||||
# include "collect.h"
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
/*A 2nd order low-pass Bessel follower.
|
||||
We use this for rate control because it has fast reaction time, but is
|
||||
critically damped.*/
|
||||
struct oc_iir_filter{
|
||||
ogg_int32_t c[2];
|
||||
ogg_int64_t g;
|
||||
ogg_int32_t x[2];
|
||||
ogg_int32_t y[2];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*The 2-pass metrics associated with a single frame.*/
|
||||
struct oc_frame_metrics{
|
||||
/*The log base 2 of the scale factor for this frame in Q24 format.*/
|
||||
ogg_int32_t log_scale;
|
||||
/*The number of application-requested duplicates of this frame.*/
|
||||
unsigned dup_count:31;
|
||||
/*The frame type from pass 1.*/
|
||||
unsigned frame_type:1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*Rate control state information.*/
|
||||
struct oc_rc_state{
|
||||
/*The target average bits per frame.*/
|
||||
ogg_int64_t bits_per_frame;
|
||||
/*The current buffer fullness (bits available to be used).*/
|
||||
ogg_int64_t fullness;
|
||||
/*The target buffer fullness.
|
||||
This is where we'd like to be by the last keyframe the appears in the next
|
||||
buf_delay frames.*/
|
||||
ogg_int64_t target;
|
||||
/*The maximum buffer fullness (total size of the buffer).*/
|
||||
ogg_int64_t max;
|
||||
/*The log of the number of pixels in a frame in Q57 format.*/
|
||||
ogg_int64_t log_npixels;
|
||||
/*The exponent used in the rate model in Q8 format.*/
|
||||
unsigned exp[2];
|
||||
/*The number of frames to distribute the buffer usage over.*/
|
||||
int buf_delay;
|
||||
/*The total drop count from the previous frame.
|
||||
This includes duplicates explicitly requested via the
|
||||
TH_ENCCTL_SET_DUP_COUNT API as well as frames we chose to drop ourselves.*/
|
||||
ogg_uint32_t prev_drop_count;
|
||||
/*The log of an estimated scale factor used to obtain the real framerate, for
|
||||
VFR sources or, e.g., 12 fps content doubled to 24 fps, etc.*/
|
||||
ogg_int64_t log_drop_scale;
|
||||
/*The log of estimated scale factor for the rate model in Q57 format.*/
|
||||
ogg_int64_t log_scale[2];
|
||||
/*The log of the target quantizer level in Q57 format.*/
|
||||
ogg_int64_t log_qtarget;
|
||||
/*Will we drop frames to meet bitrate target?*/
|
||||
unsigned char drop_frames;
|
||||
/*Do we respect the maximum buffer fullness?*/
|
||||
unsigned char cap_overflow;
|
||||
/*Can the reservoir go negative?*/
|
||||
unsigned char cap_underflow;
|
||||
/*Second-order lowpass filters to track scale and VFR.*/
|
||||
oc_iir_filter scalefilter[2];
|
||||
int inter_count;
|
||||
int inter_delay;
|
||||
int inter_delay_target;
|
||||
oc_iir_filter vfrfilter;
|
||||
/*Two-pass mode state.
|
||||
0 => 1-pass encoding.
|
||||
1 => 1st pass of 2-pass encoding.
|
||||
2 => 2nd pass of 2-pass encoding.*/
|
||||
int twopass;
|
||||
/*Buffer for current frame metrics.*/
|
||||
unsigned char twopass_buffer[48];
|
||||
/*The number of bytes in the frame metrics buffer.
|
||||
When 2-pass encoding is enabled, this is set to 0 after each frame is
|
||||
submitted, and must be non-zero before the next frame will be accepted.*/
|
||||
int twopass_buffer_bytes;
|
||||
int twopass_buffer_fill;
|
||||
/*Whether or not to force the next frame to be a keyframe.*/
|
||||
unsigned char twopass_force_kf;
|
||||
/*The metrics for the previous frame.*/
|
||||
oc_frame_metrics prev_metrics;
|
||||
/*The metrics for the current frame.*/
|
||||
oc_frame_metrics cur_metrics;
|
||||
/*The buffered metrics for future frames.*/
|
||||
oc_frame_metrics *frame_metrics;
|
||||
int nframe_metrics;
|
||||
int cframe_metrics;
|
||||
/*The index of the current frame in the circular metric buffer.*/
|
||||
int frame_metrics_head;
|
||||
/*The frame count of each type (keyframes, delta frames, and dup frames);
|
||||
32 bits limits us to 2.268 years at 60 fps.*/
|
||||
ogg_uint32_t frames_total[3];
|
||||
/*The number of frames of each type yet to be processed.*/
|
||||
ogg_uint32_t frames_left[3];
|
||||
/*The sum of the scale values for each frame type.*/
|
||||
ogg_int64_t scale_sum[2];
|
||||
/*The start of the window over which the current scale sums are taken.*/
|
||||
int scale_window0;
|
||||
/*The end of the window over which the current scale sums are taken.*/
|
||||
int scale_window_end;
|
||||
/*The frame count of each type in the current 2-pass window; this does not
|
||||
include dup frames.*/
|
||||
int nframes[3];
|
||||
/*The total accumulated estimation bias.*/
|
||||
ogg_int64_t rate_bias;
|
||||
};
|
||||
|
||||
|
||||
void oc_rc_state_init(oc_rc_state *_rc,oc_enc_ctx *_enc);
|
||||
void oc_rc_state_clear(oc_rc_state *_rc);
|
||||
|
||||
void oc_enc_rc_resize(oc_enc_ctx *_enc);
|
||||
int oc_enc_select_qi(oc_enc_ctx *_enc,int _qti,int _clamp);
|
||||
void oc_enc_calc_lambda(oc_enc_ctx *_enc,int _frame_type);
|
||||
int oc_enc_update_rc_state(oc_enc_ctx *_enc,
|
||||
long _bits,int _qti,int _qi,int _trial,int _droppable);
|
||||
int oc_enc_rc_2pass_out(oc_enc_ctx *_enc,unsigned char **_buf);
|
||||
int oc_enc_rc_2pass_in(oc_enc_ctx *_enc,unsigned char *_buf,size_t _bytes);
|
||||
|
||||
|
||||
|
||||
/*The internal encoder state.*/
|
||||
struct th_enc_ctx{
|
||||
/*Shared encoder/decoder state.*/
|
||||
oc_theora_state state;
|
||||
/*Buffer in which to assemble packets.*/
|
||||
oggpack_buffer opb;
|
||||
/*Encoder-specific macroblock information.*/
|
||||
oc_mb_enc_info *mb_info;
|
||||
/*DC coefficients after prediction.*/
|
||||
ogg_int16_t *frag_dc;
|
||||
/*The list of coded macro blocks, in coded order.*/
|
||||
unsigned *coded_mbis;
|
||||
/*The number of coded macro blocks.*/
|
||||
size_t ncoded_mbis;
|
||||
/*Whether or not packets are ready to be emitted.
|
||||
This takes on negative values while there are remaining header packets to
|
||||
be emitted, reaches 0 when the codec is ready for input, and becomes
|
||||
positive when a frame has been processed and data packets are ready.*/
|
||||
int packet_state;
|
||||
/*The maximum distance between keyframes.*/
|
||||
ogg_uint32_t keyframe_frequency_force;
|
||||
/*The number of duplicates to produce for the next frame.*/
|
||||
ogg_uint32_t dup_count;
|
||||
/*The number of duplicates remaining to be emitted for the current frame.*/
|
||||
ogg_uint32_t nqueued_dups;
|
||||
/*The number of duplicates emitted for the last frame.*/
|
||||
ogg_uint32_t prev_dup_count;
|
||||
/*The current speed level.*/
|
||||
int sp_level;
|
||||
/*Whether or not VP3 compatibility mode has been enabled.*/
|
||||
unsigned char vp3_compatible;
|
||||
/*Whether or not any INTER frames have been coded.*/
|
||||
unsigned char coded_inter_frame;
|
||||
/*Whether or not previous frame was dropped.*/
|
||||
unsigned char prevframe_dropped;
|
||||
/*Stores most recently chosen Huffman tables for each frame type, DC and AC
|
||||
coefficients, and luma and chroma tokens.
|
||||
The actual Huffman table used for a given coefficient depends not only on
|
||||
the choice made here, but also its index in the zig-zag ordering.*/
|
||||
unsigned char huff_idxs[2][2][2];
|
||||
/*Current count of bits used by each MV coding mode.*/
|
||||
size_t mv_bits[2];
|
||||
/*The mode scheme chooser for estimating mode coding costs.*/
|
||||
oc_mode_scheme_chooser chooser;
|
||||
/*Temporary encoder state for the analysis pipeline.*/
|
||||
oc_enc_pipeline_state pipe;
|
||||
/*The number of vertical super blocks in an MCU.*/
|
||||
int mcu_nvsbs;
|
||||
/*The SSD error for skipping each fragment in the current MCU.*/
|
||||
unsigned *mcu_skip_ssd;
|
||||
/*The masking scale factors for chroma blocks in the current MCU.*/
|
||||
ogg_uint16_t *mcu_rd_scale;
|
||||
ogg_uint16_t *mcu_rd_iscale;
|
||||
/*The DCT token lists for each coefficient and each plane.*/
|
||||
unsigned char **dct_tokens[3];
|
||||
/*The extra bits associated with each DCT token.*/
|
||||
ogg_uint16_t **extra_bits[3];
|
||||
/*The number of DCT tokens for each coefficient for each plane.*/
|
||||
ptrdiff_t ndct_tokens[3][64];
|
||||
/*Pending EOB runs for each coefficient for each plane.*/
|
||||
ogg_uint16_t eob_run[3][64];
|
||||
/*The offset of the first DCT token for each coefficient for each plane.*/
|
||||
unsigned char dct_token_offs[3][64];
|
||||
/*The last DC coefficient for each plane and reference frame.*/
|
||||
int dc_pred_last[3][3];
|
||||
#if defined(OC_COLLECT_METRICS)
|
||||
/*Fragment SATD statistics for MB mode estimation metrics.*/
|
||||
unsigned *frag_satd;
|
||||
/*Fragment SSD statistics for MB mode estimation metrics.*/
|
||||
unsigned *frag_ssd;
|
||||
#endif
|
||||
/*The R-D optimization parameter.*/
|
||||
int lambda;
|
||||
/*The average block "activity" of the previous frame.*/
|
||||
unsigned activity_avg;
|
||||
/*The average MB luma of the previous frame.*/
|
||||
unsigned luma_avg;
|
||||
/*The huffman tables in use.*/
|
||||
th_huff_code huff_codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS];
|
||||
/*The quantization parameters in use.*/
|
||||
th_quant_info qinfo;
|
||||
/*The original DC coefficients saved off from the dequatization tables.*/
|
||||
ogg_uint16_t dequant_dc[64][3][2];
|
||||
/*Condensed dequantization tables.*/
|
||||
const ogg_uint16_t *dequant[3][3][2];
|
||||
/*Condensed quantization tables.*/
|
||||
void *enquant[3][3][2];
|
||||
/*The full set of quantization tables.*/
|
||||
void *enquant_tables[64][3][2];
|
||||
/*Storage for the quantization tables.*/
|
||||
unsigned char *enquant_table_data;
|
||||
/*An "average" quantizer for each frame type (INTRA or INTER) and qi value.
|
||||
This is used to paramterize the rate control decisions.
|
||||
They are kept in the log domain to simplify later processing.
|
||||
These are DCT domain quantizers, and so are scaled by an additional factor
|
||||
of 4 from the pixel domain.*/
|
||||
ogg_int64_t log_qavg[2][64];
|
||||
/*The "average" quantizer futher partitioned by color plane.
|
||||
This is used to parameterize mode decision.
|
||||
These are DCT domain quantizers, and so are scaled by an additional factor
|
||||
of 4 from the pixel domain.*/
|
||||
ogg_int16_t log_plq[64][3][2];
|
||||
/*The R-D scale factors to apply to chroma blocks for a given frame type
|
||||
(INTRA or INTER) and qi value.
|
||||
The first is the "D" modifier (rd_scale), while the second is the "lambda"
|
||||
modifier (rd_iscale).*/
|
||||
ogg_uint16_t chroma_rd_scale[2][64][2];
|
||||
/*The interpolated mode decision R-D lookup tables for the current
|
||||
quantizers, color plane, and quantization type.*/
|
||||
oc_mode_rd mode_rd[3][3][2][OC_SAD_BINS];
|
||||
/*The buffer state used to drive rate control.*/
|
||||
oc_rc_state rc;
|
||||
# if defined(OC_ENC_USE_VTABLE)
|
||||
/*Table for encoder acceleration functions.*/
|
||||
oc_enc_opt_vtable opt_vtable;
|
||||
# endif
|
||||
/*Table for encoder data used by accelerated functions.*/
|
||||
oc_enc_opt_data opt_data;
|
||||
};
|
||||
|
||||
|
||||
void oc_enc_analyze_intra(oc_enc_ctx *_enc,int _recode);
|
||||
int oc_enc_analyze_inter(oc_enc_ctx *_enc,int _allow_keyframe,int _recode);
|
||||
|
||||
|
||||
|
||||
/*Perform fullpel motion search for a single MB against both reference frames.*/
|
||||
void oc_mcenc_search(oc_enc_ctx *_enc,int _mbi);
|
||||
/*Refine a MB MV for one frame.*/
|
||||
void oc_mcenc_refine1mv(oc_enc_ctx *_enc,int _mbi,int _frame);
|
||||
/*Refine the block MVs.*/
|
||||
void oc_mcenc_refine4mv(oc_enc_ctx *_enc,int _mbi);
|
||||
|
||||
|
||||
|
||||
/*Used to rollback a tokenlog transaction when we retroactively decide to skip
|
||||
a fragment.
|
||||
A checkpoint is taken right before each token is added.*/
|
||||
struct oc_token_checkpoint{
|
||||
/*The color plane the token was added to.*/
|
||||
unsigned char pli;
|
||||
/*The zig-zag index the token was added to.*/
|
||||
unsigned char zzi;
|
||||
/*The outstanding EOB run count before the token was added.*/
|
||||
ogg_uint16_t eob_run;
|
||||
/*The token count before the token was added.*/
|
||||
ptrdiff_t ndct_tokens;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void oc_enc_tokenize_start(oc_enc_ctx *_enc);
|
||||
int oc_enc_tokenize_ac(oc_enc_ctx *_enc,int _pli,ptrdiff_t _fragi,
|
||||
ogg_int16_t *_qdct,const ogg_uint16_t *_dequant,const ogg_int16_t *_dct,
|
||||
int _zzi,oc_token_checkpoint **_stack,int _lambda,int _acmin);
|
||||
int oc_enc_tokenize_ac_fast(oc_enc_ctx *_enc,int _pli,ptrdiff_t _fragi,
|
||||
ogg_int16_t *_qdct,const ogg_uint16_t *_dequant,const ogg_int16_t *_dct,
|
||||
int _zzi,oc_token_checkpoint **_stack,int _lambda,int _acmin);
|
||||
void oc_enc_tokenlog_rollback(oc_enc_ctx *_enc,
|
||||
const oc_token_checkpoint *_stack,int _n);
|
||||
void oc_enc_pred_dc_frag_rows(oc_enc_ctx *_enc,
|
||||
int _pli,int _fragy0,int _frag_yend);
|
||||
void oc_enc_tokenize_dc_frag_list(oc_enc_ctx *_enc,int _pli,
|
||||
const ptrdiff_t *_coded_fragis,ptrdiff_t _ncoded_fragis,
|
||||
int _prev_ndct_tokens1,int _prev_eob_run1);
|
||||
void oc_enc_tokenize_finish(oc_enc_ctx *_enc);
|
||||
|
||||
|
||||
|
||||
/*Utility routine to encode one of the header packets.*/
|
||||
int oc_state_flushheader(oc_theora_state *_state,int *_packet_state,
|
||||
oggpack_buffer *_opb,const th_quant_info *_qinfo,
|
||||
const th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS],
|
||||
const char *_vendor,th_comment *_tc,ogg_packet *_op);
|
||||
|
||||
|
||||
|
||||
/*Default pure-C implementations of encoder-specific accelerated functions.*/
|
||||
void oc_enc_accel_init_c(oc_enc_ctx *_enc);
|
||||
|
||||
void oc_enc_frag_sub_c(ogg_int16_t _diff[64],
|
||||
const unsigned char *_src,const unsigned char *_ref,int _ystride);
|
||||
void oc_enc_frag_sub_128_c(ogg_int16_t _diff[64],
|
||||
const unsigned char *_src,int _ystride);
|
||||
unsigned oc_enc_frag_sad_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_sad_thresh_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,unsigned _thresh);
|
||||
unsigned oc_enc_frag_sad2_thresh_c(const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride,
|
||||
unsigned _thresh);
|
||||
unsigned oc_enc_frag_satd_c(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_satd2_c(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride);
|
||||
unsigned oc_enc_frag_intra_satd_c(unsigned *_dc,const unsigned char *_src,
|
||||
int _ystride);
|
||||
unsigned oc_enc_frag_ssd_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_border_ssd_c(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,ogg_int64_t _mask);
|
||||
void oc_enc_frag_copy2_c(unsigned char *_dst,
|
||||
const unsigned char *_src1,const unsigned char *_src2,int _ystride);
|
||||
void oc_enc_enquant_table_init_c(void *_enquant,
|
||||
const ogg_uint16_t _dequant[64]);
|
||||
void oc_enc_enquant_table_fixup_c(void *_enquant[3][3][2],int _nqis);
|
||||
int oc_enc_quantize_c(ogg_int16_t _qdct[64],const ogg_int16_t _dct[64],
|
||||
const ogg_uint16_t _dequant[64],const void *_enquant);
|
||||
void oc_enc_fdct8x8_c(ogg_int16_t _y[64],const ogg_int16_t _x[64]);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include "apiwrapper.h"
|
||||
#include "encint.h"
|
||||
|
||||
th_enc_ctx *th_encode_alloc(const th_info *_info){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void th_encode_free(th_enc_ctx *_enc){}
|
||||
|
||||
|
||||
int th_encode_ctl(th_enc_ctx *_enc,int _req,void *_buf,size_t _buf_sz){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int th_encode_flushheader(th_enc_ctx *_enc,th_comment *_tc,ogg_packet *_op){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int th_encode_ycbcr_in(th_enc_ctx *_enc,th_ycbcr_buffer _img){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int th_encode_packetout(th_enc_ctx *_enc,int _last_p,ogg_packet *_op){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int theora_encode_init(theora_state *_te,theora_info *_ci){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int theora_encode_header(theora_state *_te,ogg_packet *_op){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
|
||||
int theora_encode_tables(theora_state *_te,ogg_packet *_op){
|
||||
return OC_DISABLED;
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "encint.h"
|
||||
|
||||
|
||||
|
||||
int oc_quant_params_clone(th_quant_info *_dst,const th_quant_info *_src){
|
||||
int i;
|
||||
memcpy(_dst,_src,sizeof(*_dst));
|
||||
memset(_dst->qi_ranges,0,sizeof(_dst->qi_ranges));
|
||||
for(i=0;i<6;i++){
|
||||
int nranges;
|
||||
int qti;
|
||||
int pli;
|
||||
int qtj;
|
||||
int plj;
|
||||
int pdup;
|
||||
int qdup;
|
||||
qti=i/3;
|
||||
pli=i%3;
|
||||
qtj=(i-1)/3;
|
||||
plj=(i-1)%3;
|
||||
nranges=_src->qi_ranges[qti][pli].nranges;
|
||||
/*Check for those duplicates that can be cleanly handled by
|
||||
oc_quant_params_clear().*/
|
||||
pdup=i>0&&nranges<=_src->qi_ranges[qtj][plj].nranges;
|
||||
qdup=qti>0&&nranges<=_src->qi_ranges[0][pli].nranges;
|
||||
_dst->qi_ranges[qti][pli].nranges=nranges;
|
||||
if(pdup&&_src->qi_ranges[qti][pli].sizes==_src->qi_ranges[qtj][plj].sizes){
|
||||
_dst->qi_ranges[qti][pli].sizes=_dst->qi_ranges[qtj][plj].sizes;
|
||||
}
|
||||
else if(qdup&&_src->qi_ranges[1][pli].sizes==_src->qi_ranges[0][pli].sizes){
|
||||
_dst->qi_ranges[1][pli].sizes=_dst->qi_ranges[0][pli].sizes;
|
||||
}
|
||||
else{
|
||||
int *sizes;
|
||||
sizes=(int *)_ogg_malloc(nranges*sizeof(*sizes));
|
||||
/*Note: The caller is responsible for cleaning up any partially
|
||||
constructed qinfo.*/
|
||||
if(sizes==NULL)return TH_EFAULT;
|
||||
memcpy(sizes,_src->qi_ranges[qti][pli].sizes,nranges*sizeof(*sizes));
|
||||
_dst->qi_ranges[qti][pli].sizes=sizes;
|
||||
}
|
||||
if(pdup&&_src->qi_ranges[qti][pli].base_matrices==
|
||||
_src->qi_ranges[qtj][plj].base_matrices){
|
||||
_dst->qi_ranges[qti][pli].base_matrices=
|
||||
_dst->qi_ranges[qtj][plj].base_matrices;
|
||||
}
|
||||
else if(qdup&&_src->qi_ranges[1][pli].base_matrices==
|
||||
_src->qi_ranges[0][pli].base_matrices){
|
||||
_dst->qi_ranges[1][pli].base_matrices=
|
||||
_dst->qi_ranges[0][pli].base_matrices;
|
||||
}
|
||||
else{
|
||||
th_quant_base *base_matrices;
|
||||
base_matrices=(th_quant_base *)_ogg_malloc(
|
||||
(nranges+1)*sizeof(*base_matrices));
|
||||
/*Note: The caller is responsible for cleaning up any partially
|
||||
constructed qinfo.*/
|
||||
if(base_matrices==NULL)return TH_EFAULT;
|
||||
memcpy(base_matrices,_src->qi_ranges[qti][pli].base_matrices,
|
||||
(nranges+1)*sizeof(*base_matrices));
|
||||
_dst->qi_ranges[qti][pli].base_matrices=
|
||||
(const th_quant_base *)base_matrices;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void oc_quant_params_pack(oggpack_buffer *_opb,const th_quant_info *_qinfo){
|
||||
const th_quant_ranges *qranges;
|
||||
const th_quant_base *base_mats[2*3*64];
|
||||
int indices[2][3][64];
|
||||
int nbase_mats;
|
||||
int nbits;
|
||||
int ci;
|
||||
int qi;
|
||||
int qri;
|
||||
int qti;
|
||||
int pli;
|
||||
int qtj;
|
||||
int plj;
|
||||
int bmi;
|
||||
int i;
|
||||
i=_qinfo->loop_filter_limits[0];
|
||||
for(qi=1;qi<64;qi++)i=OC_MAXI(i,_qinfo->loop_filter_limits[qi]);
|
||||
nbits=OC_ILOG_32(i);
|
||||
oggpackB_write(_opb,nbits,3);
|
||||
for(qi=0;qi<64;qi++){
|
||||
oggpackB_write(_opb,_qinfo->loop_filter_limits[qi],nbits);
|
||||
}
|
||||
/*580 bits for VP3.*/
|
||||
i=1;
|
||||
for(qi=0;qi<64;qi++)i=OC_MAXI(_qinfo->ac_scale[qi],i);
|
||||
nbits=OC_ILOGNZ_32(i);
|
||||
oggpackB_write(_opb,nbits-1,4);
|
||||
for(qi=0;qi<64;qi++)oggpackB_write(_opb,_qinfo->ac_scale[qi],nbits);
|
||||
/*516 bits for VP3.*/
|
||||
i=1;
|
||||
for(qi=0;qi<64;qi++)i=OC_MAXI(_qinfo->dc_scale[qi],i);
|
||||
nbits=OC_ILOGNZ_32(i);
|
||||
oggpackB_write(_opb,nbits-1,4);
|
||||
for(qi=0;qi<64;qi++)oggpackB_write(_opb,_qinfo->dc_scale[qi],nbits);
|
||||
/*Consolidate any duplicate base matrices.*/
|
||||
nbase_mats=0;
|
||||
for(qti=0;qti<2;qti++)for(pli=0;pli<3;pli++){
|
||||
qranges=_qinfo->qi_ranges[qti]+pli;
|
||||
for(qri=0;qri<=qranges->nranges;qri++){
|
||||
for(bmi=0;;bmi++){
|
||||
if(bmi>=nbase_mats){
|
||||
base_mats[bmi]=qranges->base_matrices+qri;
|
||||
indices[qti][pli][qri]=nbase_mats++;
|
||||
break;
|
||||
}
|
||||
else if(memcmp(base_mats[bmi][0],qranges->base_matrices[qri],
|
||||
sizeof(base_mats[bmi][0]))==0){
|
||||
indices[qti][pli][qri]=bmi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Write out the list of unique base matrices.
|
||||
1545 bits for VP3 matrices.*/
|
||||
oggpackB_write(_opb,nbase_mats-1,9);
|
||||
for(bmi=0;bmi<nbase_mats;bmi++){
|
||||
for(ci=0;ci<64;ci++)oggpackB_write(_opb,base_mats[bmi][0][ci],8);
|
||||
}
|
||||
/*Now store quant ranges and their associated indices into the base matrix
|
||||
list.
|
||||
46 bits for VP3 matrices.*/
|
||||
nbits=OC_ILOG_32(nbase_mats-1);
|
||||
for(i=0;i<6;i++){
|
||||
qti=i/3;
|
||||
pli=i%3;
|
||||
qranges=_qinfo->qi_ranges[qti]+pli;
|
||||
if(i>0){
|
||||
if(qti>0){
|
||||
if(qranges->nranges==_qinfo->qi_ranges[qti-1][pli].nranges&&
|
||||
memcmp(qranges->sizes,_qinfo->qi_ranges[qti-1][pli].sizes,
|
||||
qranges->nranges*sizeof(qranges->sizes[0]))==0&&
|
||||
memcmp(indices[qti][pli],indices[qti-1][pli],
|
||||
(qranges->nranges+1)*sizeof(indices[qti][pli][0]))==0){
|
||||
oggpackB_write(_opb,1,2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
qtj=(i-1)/3;
|
||||
plj=(i-1)%3;
|
||||
if(qranges->nranges==_qinfo->qi_ranges[qtj][plj].nranges&&
|
||||
memcmp(qranges->sizes,_qinfo->qi_ranges[qtj][plj].sizes,
|
||||
qranges->nranges*sizeof(qranges->sizes[0]))==0&&
|
||||
memcmp(indices[qti][pli],indices[qtj][plj],
|
||||
(qranges->nranges+1)*sizeof(indices[qti][pli][0]))==0){
|
||||
oggpackB_write(_opb,0,1+(qti>0));
|
||||
continue;
|
||||
}
|
||||
oggpackB_write(_opb,1,1);
|
||||
}
|
||||
oggpackB_write(_opb,indices[qti][pli][0],nbits);
|
||||
for(qi=qri=0;qi<63;qri++){
|
||||
oggpackB_write(_opb,qranges->sizes[qri]-1,OC_ILOG_32(62-qi));
|
||||
qi+=qranges->sizes[qri];
|
||||
oggpackB_write(_opb,indices[qti][pli][qri+1],nbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void oc_iquant_init(oc_iquant *_this,ogg_uint16_t _d){
|
||||
ogg_uint32_t t;
|
||||
int l;
|
||||
_d<<=1;
|
||||
l=OC_ILOGNZ_32(_d)-1;
|
||||
t=1+((ogg_uint32_t)1<<16+l)/_d;
|
||||
_this->m=(ogg_int16_t)(t-0x10000);
|
||||
_this->l=l;
|
||||
}
|
||||
|
||||
void oc_enc_enquant_table_init_c(void *_enquant,
|
||||
const ogg_uint16_t _dequant[64]){
|
||||
oc_iquant *enquant;
|
||||
int zzi;
|
||||
/*In the original VP3.2 code, the rounding offset and the size of the
|
||||
dead zone around 0 were controlled by a "sharpness" parameter.
|
||||
We now R-D optimize the tokens for each block after quantization,
|
||||
so the rounding offset should always be 1/2, and an explicit dead
|
||||
zone is unnecessary.
|
||||
Hence, all of that VP3.2 code is gone from here, and the remaining
|
||||
floating point code has been implemented as equivalent integer
|
||||
code with exact precision.*/
|
||||
enquant=(oc_iquant *)_enquant;
|
||||
for(zzi=0;zzi<64;zzi++)oc_iquant_init(enquant+zzi,_dequant[zzi]);
|
||||
}
|
||||
|
||||
void oc_enc_enquant_table_fixup_c(void *_enquant[3][3][2],int _nqis){
|
||||
int pli;
|
||||
int qii;
|
||||
int qti;
|
||||
for(pli=0;pli<3;pli++)for(qii=1;qii<_nqis;qii++)for(qti=0;qti<2;qti++){
|
||||
*((oc_iquant *)_enquant[pli][qii][qti])=
|
||||
*((oc_iquant *)_enquant[pli][0][qti]);
|
||||
}
|
||||
}
|
||||
|
||||
int oc_enc_quantize_c(ogg_int16_t _qdct[64],const ogg_int16_t _dct[64],
|
||||
const ogg_uint16_t _dequant[64],const void *_enquant){
|
||||
const oc_iquant *enquant;
|
||||
int nonzero;
|
||||
int zzi;
|
||||
int val;
|
||||
int d;
|
||||
int s;
|
||||
enquant=(const oc_iquant *)_enquant;
|
||||
nonzero=0;
|
||||
for(zzi=0;zzi<64;zzi++){
|
||||
val=_dct[OC_FZIG_ZAG[zzi]];
|
||||
d=_dequant[zzi];
|
||||
val=val<<1;
|
||||
if(abs(val)>=d){
|
||||
s=OC_SIGNMASK(val);
|
||||
/*The bias added here rounds ties away from zero, since token
|
||||
optimization can only decrease the magnitude of the quantized
|
||||
value.*/
|
||||
val+=d+s^s;
|
||||
/*Note the arithmetic right shift is not guaranteed by ANSI C.
|
||||
Hopefully no one still uses ones-complement architectures.*/
|
||||
val=((enquant[zzi].m*(ogg_int32_t)val>>16)+val>>enquant[zzi].l)-s;
|
||||
_qdct[zzi]=(ogg_int16_t)val;
|
||||
nonzero=zzi;
|
||||
}
|
||||
else _qdct[zzi]=0;
|
||||
}
|
||||
return nonzero;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*This table gives the square root of the fraction of the squared magnitude of
|
||||
each DCT coefficient relative to the total, scaled by 2**16, for both INTRA
|
||||
and INTER modes.
|
||||
These values were measured after motion-compensated prediction, before
|
||||
quantization, over a large set of test video (from QCIF to 1080p) encoded at
|
||||
all possible rates.
|
||||
The DC coefficient takes into account the DPCM prediction (using the
|
||||
quantized values from neighboring blocks, as the encoder does, but still
|
||||
before quantization of the coefficient in the current block).
|
||||
The results differ significantly from the expected variance (e.g., using an
|
||||
AR(1) model of the signal with rho=0.95, as is frequently done to compute
|
||||
the coding gain of the DCT).
|
||||
We use them to estimate an "average" quantizer for a given quantizer matrix,
|
||||
as this is used to parameterize a number of the rate control decisions.
|
||||
These values are themselves probably quantizer-matrix dependent, since the
|
||||
shape of the matrix affects the noise distribution in the reference frames,
|
||||
but they should at least give us _some_ amount of adaptivity to different
|
||||
matrices, as opposed to hard-coding a table of average Q values for the
|
||||
current set.
|
||||
The main features they capture are that a) only a few of the quantizers in
|
||||
the upper-left corner contribute anything significant at all (though INTER
|
||||
mode is significantly flatter) and b) the DPCM prediction of the DC
|
||||
coefficient gives a very minor improvement in the INTRA case and a quite
|
||||
significant one in the INTER case (over the expected variance).*/
|
||||
static const ogg_uint16_t OC_RPSD[2][64]={
|
||||
{
|
||||
52725,17370,10399, 6867, 5115, 3798, 2942, 2076,
|
||||
17370, 9900, 6948, 4994, 3836, 2869, 2229, 1619,
|
||||
10399, 6948, 5516, 4202, 3376, 2573, 2015, 1461,
|
||||
6867, 4994, 4202, 3377, 2800, 2164, 1718, 1243,
|
||||
5115, 3836, 3376, 2800, 2391, 1884, 1530, 1091,
|
||||
3798, 2869, 2573, 2164, 1884, 1495, 1212, 873,
|
||||
2942, 2229, 2015, 1718, 1530, 1212, 1001, 704,
|
||||
2076, 1619, 1461, 1243, 1091, 873, 704, 474
|
||||
},
|
||||
{
|
||||
23411,15604,13529,11601,10683, 8958, 7840, 6142,
|
||||
15604,11901,10718, 9108, 8290, 6961, 6023, 4487,
|
||||
13529,10718, 9961, 8527, 7945, 6689, 5742, 4333,
|
||||
11601, 9108, 8527, 7414, 7084, 5923, 5175, 3743,
|
||||
10683, 8290, 7945, 7084, 6771, 5754, 4793, 3504,
|
||||
8958, 6961, 6689, 5923, 5754, 4679, 3936, 2989,
|
||||
7840, 6023, 5742, 5175, 4793, 3936, 3522, 2558,
|
||||
6142, 4487, 4333, 3743, 3504, 2989, 2558, 1829
|
||||
}
|
||||
};
|
||||
|
||||
/*The fraction of the squared magnitude of the residuals in each color channel
|
||||
relative to the total, scaled by 2**16, for each pixel format.
|
||||
These values were measured after motion-compensated prediction, before
|
||||
quantization, over a large set of test video encoded at all possible rates.
|
||||
TODO: These values are only from INTER frames; they should be re-measured for
|
||||
INTRA frames.*/
|
||||
static const ogg_uint16_t OC_PCD[4][3]={
|
||||
{59926, 3038, 2572},
|
||||
{55201, 5597, 4738},
|
||||
{55201, 5597, 4738},
|
||||
{47682, 9669, 8185}
|
||||
};
|
||||
|
||||
|
||||
/*Compute "average" quantizers for each qi level to use for rate control.
|
||||
We do one for each color channel, as well as an average across color
|
||||
channels, separately for INTER and INTRA, since their behavior is very
|
||||
different.
|
||||
The basic approach is to compute a harmonic average of the squared quantizer,
|
||||
weighted by the expected squared magnitude of the DCT coefficients.
|
||||
Under the (not quite true) assumption that DCT coefficients are
|
||||
Laplacian-distributed, this preserves the product Q*lambda, where
|
||||
lambda=sqrt(2/sigma**2) is the Laplacian distribution parameter (not to be
|
||||
confused with the lambda used in R-D optimization throughout most of the
|
||||
rest of the code), when the distributions from multiple coefficients are
|
||||
pooled.
|
||||
The value Q*lambda completely determines the entropy of coefficients drawn
|
||||
from a Laplacian distribution, and thus the expected bitrate.*/
|
||||
void oc_enquant_qavg_init(ogg_int64_t _log_qavg[2][64],
|
||||
ogg_int16_t _log_plq[64][3][2],ogg_uint16_t _chroma_rd_scale[2][64][2],
|
||||
ogg_uint16_t *_dequant[64][3][2],int _pixel_fmt){
|
||||
int qi;
|
||||
int pli;
|
||||
int qti;
|
||||
int ci;
|
||||
for(qti=0;qti<2;qti++)for(qi=0;qi<64;qi++){
|
||||
ogg_int64_t q2;
|
||||
ogg_uint32_t qp[3];
|
||||
ogg_uint32_t cqp;
|
||||
ogg_uint32_t d;
|
||||
q2=0;
|
||||
for(pli=0;pli<3;pli++){
|
||||
qp[pli]=0;
|
||||
for(ci=0;ci<64;ci++){
|
||||
unsigned rq;
|
||||
unsigned qd;
|
||||
qd=_dequant[qi][pli][qti][OC_IZIG_ZAG[ci]];
|
||||
rq=(OC_RPSD[qti][ci]+(qd>>1))/qd;
|
||||
qp[pli]+=rq*(ogg_uint32_t)rq;
|
||||
}
|
||||
q2+=OC_PCD[_pixel_fmt][pli]*(ogg_int64_t)qp[pli];
|
||||
/*plq=1.0/sqrt(qp)*/
|
||||
_log_plq[qi][pli][qti]=
|
||||
(ogg_int16_t)(OC_Q10(32)-oc_blog32_q10(qp[pli])>>1);
|
||||
}
|
||||
d=OC_PCD[_pixel_fmt][1]+OC_PCD[_pixel_fmt][2];
|
||||
cqp=(ogg_uint32_t)((OC_PCD[_pixel_fmt][1]*(ogg_int64_t)qp[1]+
|
||||
OC_PCD[_pixel_fmt][2]*(ogg_int64_t)qp[2]+(d>>1))/d);
|
||||
/*chroma_rd_scale=clamp(0.25,cqp/qp[0],4)*/
|
||||
d=OC_MAXI(qp[0]+(1<<OC_RD_SCALE_BITS-1)>>OC_RD_SCALE_BITS,1);
|
||||
d=OC_CLAMPI(1<<OC_RD_SCALE_BITS-2,(cqp+(d>>1))/d,4<<OC_RD_SCALE_BITS);
|
||||
_chroma_rd_scale[qti][qi][0]=(ogg_int16_t)d;
|
||||
/*chroma_rd_iscale=clamp(0.25,qp[0]/cqp,4)*/
|
||||
d=OC_MAXI(OC_RD_ISCALE(cqp,1),1);
|
||||
d=OC_CLAMPI(1<<OC_RD_ISCALE_BITS-2,(qp[0]+(d>>1))/d,4<<OC_RD_ISCALE_BITS);
|
||||
_chroma_rd_scale[qti][qi][1]=(ogg_int16_t)d;
|
||||
/*qavg=1.0/sqrt(q2).*/
|
||||
_log_qavg[qti][qi]=OC_Q57(48)-oc_blog64(q2)>>1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#if !defined(_enquant_H)
|
||||
# define _enquant_H (1)
|
||||
# include "quant.h"
|
||||
|
||||
typedef struct oc_iquant oc_iquant;
|
||||
|
||||
#define OC_QUANT_MAX_LOG (OC_Q57(OC_STATIC_ILOG_32(OC_QUANT_MAX)-1))
|
||||
|
||||
/*Used to compute x/d via ((x*m>>16)+x>>l)+(x<0))
|
||||
(i.e., one 16x16->16 mul, 2 shifts, and 2 adds).
|
||||
This is not an approximation; for 16-bit x and d, it is exact.*/
|
||||
struct oc_iquant{
|
||||
ogg_int16_t m;
|
||||
ogg_int16_t l;
|
||||
};
|
||||
|
||||
|
||||
|
||||
int oc_quant_params_clone(th_quant_info *_dst,const th_quant_info *_src);
|
||||
void oc_quant_params_pack(oggpack_buffer *_opb,const th_quant_info *_qinfo);
|
||||
void oc_iquant_init(oc_iquant *_this,ogg_uint16_t _d);
|
||||
void oc_enquant_qavg_init(ogg_int64_t _log_qavg[2][64],
|
||||
ogg_int16_t _log_plq[64][3][2],ogg_uint16_t _pl_rd_scale[2][64][2],
|
||||
ogg_uint16_t *_dequant[64][3][2],int _pixel_fmt);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,417 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include "encint.h"
|
||||
#include "dct.h"
|
||||
|
||||
|
||||
|
||||
/*Performs a forward 8 point Type-II DCT transform.
|
||||
The output is scaled by a factor of 2 from the orthonormal version of the
|
||||
transform.
|
||||
_y: The buffer to store the result in.
|
||||
Data will be placed the first 8 entries (e.g., in a row of an 8x8 block).
|
||||
_x: The input coefficients.
|
||||
Every 8th entry is used (e.g., from a column of an 8x8 block).*/
|
||||
static void oc_fdct8(ogg_int16_t _y[8],const ogg_int16_t *_x){
|
||||
int t0;
|
||||
int t1;
|
||||
int t2;
|
||||
int t3;
|
||||
int t4;
|
||||
int t5;
|
||||
int t6;
|
||||
int t7;
|
||||
int r;
|
||||
int s;
|
||||
int u;
|
||||
int v;
|
||||
/*Stage 1:*/
|
||||
/*0-7 butterfly.*/
|
||||
t0=_x[0<<3]+(int)_x[7<<3];
|
||||
t7=_x[0<<3]-(int)_x[7<<3];
|
||||
/*1-6 butterfly.*/
|
||||
t1=_x[1<<3]+(int)_x[6<<3];
|
||||
t6=_x[1<<3]-(int)_x[6<<3];
|
||||
/*2-5 butterfly.*/
|
||||
t2=_x[2<<3]+(int)_x[5<<3];
|
||||
t5=_x[2<<3]-(int)_x[5<<3];
|
||||
/*3-4 butterfly.*/
|
||||
t3=_x[3<<3]+(int)_x[4<<3];
|
||||
t4=_x[3<<3]-(int)_x[4<<3];
|
||||
/*Stage 2:*/
|
||||
/*0-3 butterfly.*/
|
||||
r=t0+t3;
|
||||
t3=t0-t3;
|
||||
t0=r;
|
||||
/*1-2 butterfly.*/
|
||||
r=t1+t2;
|
||||
t2=t1-t2;
|
||||
t1=r;
|
||||
/*6-5 butterfly.*/
|
||||
r=t6+t5;
|
||||
t5=t6-t5;
|
||||
t6=r;
|
||||
/*Stages 3 and 4 are where all the approximation occurs.
|
||||
These are chosen to be as close to an exact inverse of the approximations
|
||||
made in the iDCT as possible, while still using mostly 16-bit arithmetic.
|
||||
We use some 16x16->32 signed MACs, but those still commonly execute in 1
|
||||
cycle on a 16-bit DSP.
|
||||
For example, s=(27146*t5+0x4000>>16)+t5+(t5!=0) is an exact inverse of
|
||||
t5=(OC_C4S4*s>>16).
|
||||
That is, applying the latter to the output of the former will recover t5
|
||||
exactly (over the valid input range of t5, -23171...23169).
|
||||
We increase the rounding bias to 0xB500 in this particular case so that
|
||||
errors inverting the subsequent butterfly are not one-sided (e.g., the
|
||||
mean error is very close to zero).
|
||||
The (t5!=0) term could be replaced simply by 1, but we want to send 0 to 0.
|
||||
The fDCT of an all-zeros block will still not be zero, because of the
|
||||
biases we added at the very beginning of the process, but it will be close
|
||||
enough that it is guaranteed to round to zero.*/
|
||||
/*Stage 3:*/
|
||||
/*4-5 butterfly.*/
|
||||
s=(27146*t5+0xB500>>16)+t5+(t5!=0)>>1;
|
||||
r=t4+s;
|
||||
t5=t4-s;
|
||||
t4=r;
|
||||
/*7-6 butterfly.*/
|
||||
s=(27146*t6+0xB500>>16)+t6+(t6!=0)>>1;
|
||||
r=t7+s;
|
||||
t6=t7-s;
|
||||
t7=r;
|
||||
/*Stage 4:*/
|
||||
/*0-1 butterfly.*/
|
||||
r=(27146*t0+0x4000>>16)+t0+(t0!=0);
|
||||
s=(27146*t1+0xB500>>16)+t1+(t1!=0);
|
||||
u=r+s>>1;
|
||||
v=r-u;
|
||||
_y[0]=u;
|
||||
_y[4]=v;
|
||||
/*3-2 rotation by 6pi/16*/
|
||||
u=(OC_C6S2*t2+OC_C2S6*t3+0x6CB7>>16)+(t3!=0);
|
||||
s=(OC_C6S2*u>>16)-t2;
|
||||
v=(s*21600+0x2800>>18)+s+(s!=0);
|
||||
_y[2]=u;
|
||||
_y[6]=v;
|
||||
/*6-5 rotation by 3pi/16*/
|
||||
u=(OC_C5S3*t6+OC_C3S5*t5+0x0E3D>>16)+(t5!=0);
|
||||
s=t6-(OC_C5S3*u>>16);
|
||||
v=(s*26568+0x3400>>17)+s+(s!=0);
|
||||
_y[5]=u;
|
||||
_y[3]=v;
|
||||
/*7-4 rotation by 7pi/16*/
|
||||
u=(OC_C7S1*t4+OC_C1S7*t7+0x7B1B>>16)+(t7!=0);
|
||||
s=(OC_C7S1*u>>16)-t4;
|
||||
v=(s*20539+0x3000>>20)+s+(s!=0);
|
||||
_y[1]=u;
|
||||
_y[7]=v;
|
||||
}
|
||||
|
||||
/*Performs a forward 8x8 Type-II DCT transform.
|
||||
The output is scaled by a factor of 4 relative to the orthonormal version
|
||||
of the transform.
|
||||
_y: The buffer to store the result in.
|
||||
This may be the same as _x.
|
||||
_x: The input coefficients. */
|
||||
void oc_enc_fdct8x8_c(ogg_int16_t _y[64],const ogg_int16_t _x[64]){
|
||||
const ogg_int16_t *in;
|
||||
ogg_int16_t *end;
|
||||
ogg_int16_t *out;
|
||||
ogg_int16_t w[64];
|
||||
int i;
|
||||
/*Add two extra bits of working precision to improve accuracy; any more and
|
||||
we could overflow.*/
|
||||
for(i=0;i<64;i++)w[i]=_x[i]<<2;
|
||||
/*These biases correct for some systematic error that remains in the full
|
||||
fDCT->iDCT round trip.*/
|
||||
w[0]+=(w[0]!=0)+1;
|
||||
w[1]++;
|
||||
w[8]--;
|
||||
/*Transform columns of w into rows of _y.*/
|
||||
for(in=w,out=_y,end=out+64;out<end;in++,out+=8)oc_fdct8(out,in);
|
||||
/*Transform columns of _y into rows of w.*/
|
||||
for(in=_y,out=w,end=out+64;out<end;in++,out+=8)oc_fdct8(out,in);
|
||||
/*Round the result back to the external working precision (which is still
|
||||
scaled by four relative to the orthogonal result).
|
||||
TODO: We should just update the external working precision.*/
|
||||
for(i=0;i<64;i++)_y[i]=w[i]+2>>2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*This does not seem to outperform simple LFE border padding before MC.
|
||||
It yields higher PSNR, but much higher bitrate usage.*/
|
||||
#if 0
|
||||
typedef struct oc_extension_info oc_extension_info;
|
||||
|
||||
|
||||
|
||||
/*Information needed to pad boundary blocks.
|
||||
We multiply each row/column by an extension matrix that fills in the padding
|
||||
values as a linear combination of the active values, so that an equivalent
|
||||
number of coefficients are forced to zero.
|
||||
This costs at most 16 multiplies, the same as a 1-D fDCT itself, and as
|
||||
little as 7 multiplies.
|
||||
We compute the extension matrices for every possible shape in advance, as
|
||||
there are only 35.
|
||||
The coefficients for all matrices are stored in a single array to take
|
||||
advantage of the overlap and repetitiveness of many of the shapes.
|
||||
A similar technique is applied to the offsets into this array.
|
||||
This reduces the required table storage by about 48%.
|
||||
See tools/extgen.c for details.
|
||||
We could conceivably do the same for all 256 possible shapes.*/
|
||||
struct oc_extension_info{
|
||||
/*The mask of the active pixels in the shape.*/
|
||||
short mask;
|
||||
/*The number of active pixels in the shape.*/
|
||||
short na;
|
||||
/*The extension matrix.
|
||||
This is (8-na)xna*/
|
||||
const ogg_int16_t *const *ext;
|
||||
/*The pixel indices: na active pixels followed by 8-na padding pixels.*/
|
||||
unsigned char pi[8];
|
||||
/*The coefficient indices: na unconstrained coefficients followed by 8-na
|
||||
coefficients to be forced to zero.*/
|
||||
unsigned char ci[8];
|
||||
};
|
||||
|
||||
|
||||
/*The number of shapes we need.*/
|
||||
#define OC_NSHAPES (35)
|
||||
|
||||
static const ogg_int16_t OC_EXT_COEFFS[229]={
|
||||
0x7FFF,0xE1F8,0x6903,0xAA79,0x5587,0x7FFF,0x1E08,0x7FFF,
|
||||
0x5587,0xAA79,0x6903,0xE1F8,0x7FFF,0x0000,0x0000,0x0000,
|
||||
0x7FFF,0x0000,0x0000,0x7FFF,0x8000,0x7FFF,0x0000,0x0000,
|
||||
0x7FFF,0xE1F8,0x1E08,0xB0A7,0xAA1D,0x337C,0x7FFF,0x4345,
|
||||
0x2267,0x4345,0x7FFF,0x337C,0xAA1D,0xB0A7,0x8A8C,0x4F59,
|
||||
0x03B4,0xE2D6,0x7FFF,0x2CF3,0x7FFF,0xE2D6,0x03B4,0x4F59,
|
||||
0x8A8C,0x1103,0x7AEF,0x5225,0xDF60,0xC288,0xDF60,0x5225,
|
||||
0x7AEF,0x1103,0x668A,0xD6EE,0x3A16,0x0E6C,0xFA07,0x0E6C,
|
||||
0x3A16,0xD6EE,0x668A,0x2A79,0x2402,0x980F,0x50F5,0x4882,
|
||||
0x50F5,0x980F,0x2402,0x2A79,0xF976,0x2768,0x5F22,0x2768,
|
||||
0xF976,0x1F91,0x76C1,0xE9AE,0x76C1,0x1F91,0x7FFF,0xD185,
|
||||
0x0FC8,0xD185,0x7FFF,0x4F59,0x4345,0xED62,0x4345,0x4F59,
|
||||
0xF574,0x5D99,0x2CF3,0x5D99,0xF574,0x5587,0x3505,0x30FC,
|
||||
0xF482,0x953C,0xEAC4,0x7FFF,0x4F04,0x7FFF,0xEAC4,0x953C,
|
||||
0xF482,0x30FC,0x4F04,0x273D,0xD8C3,0x273D,0x1E09,0x61F7,
|
||||
0x1E09,0x273D,0xD8C3,0x273D,0x4F04,0x30FC,0xA57E,0x153C,
|
||||
0x6AC4,0x3C7A,0x1E08,0x3C7A,0x6AC4,0x153C,0xA57E,0x7FFF,
|
||||
0xA57E,0x5A82,0x6AC4,0x153C,0xC386,0xE1F8,0xC386,0x153C,
|
||||
0x6AC4,0x5A82,0xD8C3,0x273D,0x7FFF,0xE1F7,0x7FFF,0x273D,
|
||||
0xD8C3,0x4F04,0x30FC,0xD8C3,0x273D,0xD8C3,0x30FC,0x4F04,
|
||||
0x1FC8,0x67AD,0x1853,0xE038,0x1853,0x67AD,0x1FC8,0x4546,
|
||||
0xE038,0x1FC8,0x3ABA,0x1FC8,0xE038,0x4546,0x3505,0x5587,
|
||||
0xF574,0xBC11,0x78F4,0x4AFB,0xE6F3,0x4E12,0x3C11,0xF8F4,
|
||||
0x4AFB,0x3C7A,0xF88B,0x3C11,0x78F4,0xCAFB,0x7FFF,0x08CC,
|
||||
0x070C,0x236D,0x5587,0x236D,0x070C,0xF88B,0x3C7A,0x4AFB,
|
||||
0xF8F4,0x3C11,0x7FFF,0x153C,0xCAFB,0x153C,0x7FFF,0x1E08,
|
||||
0xE1F8,0x7FFF,0x08CC,0x7FFF,0xCAFB,0x78F4,0x3C11,0x4E12,
|
||||
0xE6F3,0x4AFB,0x78F4,0xBC11,0xFE3D,0x7FFF,0xFE3D,0x2F3A,
|
||||
0x7FFF,0x2F3A,0x89BC,0x7FFF,0x89BC
|
||||
};
|
||||
|
||||
static const ogg_int16_t *const OC_EXT_ROWS[96]={
|
||||
OC_EXT_COEFFS+ 0,OC_EXT_COEFFS+ 0,OC_EXT_COEFFS+ 0,OC_EXT_COEFFS+ 0,
|
||||
OC_EXT_COEFFS+ 0,OC_EXT_COEFFS+ 0,OC_EXT_COEFFS+ 0,OC_EXT_COEFFS+ 6,
|
||||
OC_EXT_COEFFS+ 27,OC_EXT_COEFFS+ 38,OC_EXT_COEFFS+ 43,OC_EXT_COEFFS+ 32,
|
||||
OC_EXT_COEFFS+ 49,OC_EXT_COEFFS+ 58,OC_EXT_COEFFS+ 67,OC_EXT_COEFFS+ 71,
|
||||
OC_EXT_COEFFS+ 62,OC_EXT_COEFFS+ 53,OC_EXT_COEFFS+ 12,OC_EXT_COEFFS+ 15,
|
||||
OC_EXT_COEFFS+ 14,OC_EXT_COEFFS+ 13,OC_EXT_COEFFS+ 76,OC_EXT_COEFFS+ 81,
|
||||
OC_EXT_COEFFS+ 86,OC_EXT_COEFFS+ 91,OC_EXT_COEFFS+ 96,OC_EXT_COEFFS+ 98,
|
||||
OC_EXT_COEFFS+ 93,OC_EXT_COEFFS+ 88,OC_EXT_COEFFS+ 83,OC_EXT_COEFFS+ 78,
|
||||
OC_EXT_COEFFS+ 12,OC_EXT_COEFFS+ 15,OC_EXT_COEFFS+ 15,OC_EXT_COEFFS+ 12,
|
||||
OC_EXT_COEFFS+ 12,OC_EXT_COEFFS+ 15,OC_EXT_COEFFS+ 12,OC_EXT_COEFFS+ 15,
|
||||
OC_EXT_COEFFS+ 15,OC_EXT_COEFFS+ 12,OC_EXT_COEFFS+ 103,OC_EXT_COEFFS+ 108,
|
||||
OC_EXT_COEFFS+ 126,OC_EXT_COEFFS+ 16,OC_EXT_COEFFS+ 137,OC_EXT_COEFFS+ 141,
|
||||
OC_EXT_COEFFS+ 20,OC_EXT_COEFFS+ 130,OC_EXT_COEFFS+ 113,OC_EXT_COEFFS+ 116,
|
||||
OC_EXT_COEFFS+ 146,OC_EXT_COEFFS+ 153,OC_EXT_COEFFS+ 160,OC_EXT_COEFFS+ 167,
|
||||
OC_EXT_COEFFS+ 170,OC_EXT_COEFFS+ 163,OC_EXT_COEFFS+ 156,OC_EXT_COEFFS+ 149,
|
||||
OC_EXT_COEFFS+ 119,OC_EXT_COEFFS+ 122,OC_EXT_COEFFS+ 174,OC_EXT_COEFFS+ 177,
|
||||
OC_EXT_COEFFS+ 182,OC_EXT_COEFFS+ 187,OC_EXT_COEFFS+ 192,OC_EXT_COEFFS+ 197,
|
||||
OC_EXT_COEFFS+ 202,OC_EXT_COEFFS+ 207,OC_EXT_COEFFS+ 210,OC_EXT_COEFFS+ 215,
|
||||
OC_EXT_COEFFS+ 179,OC_EXT_COEFFS+ 189,OC_EXT_COEFFS+ 24,OC_EXT_COEFFS+ 204,
|
||||
OC_EXT_COEFFS+ 184,OC_EXT_COEFFS+ 194,OC_EXT_COEFFS+ 212,OC_EXT_COEFFS+ 199,
|
||||
OC_EXT_COEFFS+ 217,OC_EXT_COEFFS+ 100,OC_EXT_COEFFS+ 134,OC_EXT_COEFFS+ 135,
|
||||
OC_EXT_COEFFS+ 135,OC_EXT_COEFFS+ 12,OC_EXT_COEFFS+ 15,OC_EXT_COEFFS+ 134,
|
||||
OC_EXT_COEFFS+ 134,OC_EXT_COEFFS+ 135,OC_EXT_COEFFS+ 220,OC_EXT_COEFFS+ 223,
|
||||
OC_EXT_COEFFS+ 226,OC_EXT_COEFFS+ 227,OC_EXT_COEFFS+ 224,OC_EXT_COEFFS+ 221
|
||||
};
|
||||
|
||||
static const oc_extension_info OC_EXTENSION_INFO[OC_NSHAPES]={
|
||||
{0x7F,7,OC_EXT_ROWS+ 0,{0,1,2,3,4,5,6,7},{0,1,2,4,5,6,7,3}},
|
||||
{0xFE,7,OC_EXT_ROWS+ 7,{1,2,3,4,5,6,7,0},{0,1,2,4,5,6,7,3}},
|
||||
{0x3F,6,OC_EXT_ROWS+ 8,{0,1,2,3,4,5,7,6},{0,1,3,4,6,7,5,2}},
|
||||
{0xFC,6,OC_EXT_ROWS+ 10,{2,3,4,5,6,7,1,0},{0,1,3,4,6,7,5,2}},
|
||||
{0x1F,5,OC_EXT_ROWS+ 12,{0,1,2,3,4,7,6,5},{0,2,3,5,7,6,4,1}},
|
||||
{0xF8,5,OC_EXT_ROWS+ 15,{3,4,5,6,7,2,1,0},{0,2,3,5,7,6,4,1}},
|
||||
{0x0F,4,OC_EXT_ROWS+ 18,{0,1,2,3,7,6,5,4},{0,2,4,6,7,5,3,1}},
|
||||
{0xF0,4,OC_EXT_ROWS+ 18,{4,5,6,7,3,2,1,0},{0,2,4,6,7,5,3,1}},
|
||||
{0x07,3,OC_EXT_ROWS+ 22,{0,1,2,7,6,5,4,3},{0,3,6,7,5,4,2,1}},
|
||||
{0xE0,3,OC_EXT_ROWS+ 27,{5,6,7,4,3,2,1,0},{0,3,6,7,5,4,2,1}},
|
||||
{0x03,2,OC_EXT_ROWS+ 32,{0,1,7,6,5,4,3,2},{0,4,7,6,5,3,2,1}},
|
||||
{0xC0,2,OC_EXT_ROWS+ 32,{6,7,5,4,3,2,1,0},{0,4,7,6,5,3,2,1}},
|
||||
{0x01,1,OC_EXT_ROWS+ 0,{0,7,6,5,4,3,2,1},{0,7,6,5,4,3,2,1}},
|
||||
{0x80,1,OC_EXT_ROWS+ 0,{7,6,5,4,3,2,1,0},{0,7,6,5,4,3,2,1}},
|
||||
{0x7E,6,OC_EXT_ROWS+ 42,{1,2,3,4,5,6,7,0},{0,1,2,5,6,7,4,3}},
|
||||
{0x7C,5,OC_EXT_ROWS+ 44,{2,3,4,5,6,7,1,0},{0,1,4,5,7,6,3,2}},
|
||||
{0x3E,5,OC_EXT_ROWS+ 47,{1,2,3,4,5,7,6,0},{0,1,4,5,7,6,3,2}},
|
||||
{0x78,4,OC_EXT_ROWS+ 50,{3,4,5,6,7,2,1,0},{0,4,5,7,6,3,2,1}},
|
||||
{0x3C,4,OC_EXT_ROWS+ 54,{2,3,4,5,7,6,1,0},{0,3,4,7,6,5,2,1}},
|
||||
{0x1E,4,OC_EXT_ROWS+ 58,{1,2,3,4,7,6,5,0},{0,4,5,7,6,3,2,1}},
|
||||
{0x70,3,OC_EXT_ROWS+ 62,{4,5,6,7,3,2,1,0},{0,5,7,6,4,3,2,1}},
|
||||
{0x38,3,OC_EXT_ROWS+ 67,{3,4,5,7,6,2,1,0},{0,5,6,7,4,3,2,1}},
|
||||
{0x1C,3,OC_EXT_ROWS+ 72,{2,3,4,7,6,5,1,0},{0,5,6,7,4,3,2,1}},
|
||||
{0x0E,3,OC_EXT_ROWS+ 77,{1,2,3,7,6,5,4,0},{0,5,7,6,4,3,2,1}},
|
||||
{0x60,2,OC_EXT_ROWS+ 82,{5,6,7,4,3,2,1,0},{0,2,7,6,5,4,3,1}},
|
||||
{0x30,2,OC_EXT_ROWS+ 36,{4,5,7,6,3,2,1,0},{0,4,7,6,5,3,2,1}},
|
||||
{0x18,2,OC_EXT_ROWS+ 90,{3,4,7,6,5,2,1,0},{0,1,7,6,5,4,3,2}},
|
||||
{0x0C,2,OC_EXT_ROWS+ 34,{2,3,7,6,5,4,1,0},{0,4,7,6,5,3,2,1}},
|
||||
{0x06,2,OC_EXT_ROWS+ 84,{1,2,7,6,5,4,3,0},{0,2,7,6,5,4,3,1}},
|
||||
{0x40,1,OC_EXT_ROWS+ 0,{6,7,5,4,3,2,1,0},{0,7,6,5,4,3,2,1}},
|
||||
{0x20,1,OC_EXT_ROWS+ 0,{5,7,6,4,3,2,1,0},{0,7,6,5,4,3,2,1}},
|
||||
{0x10,1,OC_EXT_ROWS+ 0,{4,7,6,5,3,2,1,0},{0,7,6,5,4,3,2,1}},
|
||||
{0x08,1,OC_EXT_ROWS+ 0,{3,7,6,5,4,2,1,0},{0,7,6,5,4,3,2,1}},
|
||||
{0x04,1,OC_EXT_ROWS+ 0,{2,7,6,5,4,3,1,0},{0,7,6,5,4,3,2,1}},
|
||||
{0x02,1,OC_EXT_ROWS+ 0,{1,7,6,5,4,3,2,0},{0,7,6,5,4,3,2,1}}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*Pads a single column of a partial block and then performs a forward Type-II
|
||||
DCT on the result.
|
||||
The input is scaled by a factor of 4 and biased appropriately for the current
|
||||
fDCT implementation.
|
||||
The output is scaled by an additional factor of 2 from the orthonormal
|
||||
version of the transform.
|
||||
_y: The buffer to store the result in.
|
||||
Data will be placed the first 8 entries (e.g., in a row of an 8x8 block).
|
||||
_x: The input coefficients.
|
||||
Every 8th entry is used (e.g., from a column of an 8x8 block).
|
||||
_e: The extension information for the shape.*/
|
||||
static void oc_fdct8_ext(ogg_int16_t _y[8],ogg_int16_t *_x,
|
||||
const oc_extension_info *_e){
|
||||
const unsigned char *pi;
|
||||
int na;
|
||||
na=_e->na;
|
||||
pi=_e->pi;
|
||||
if(na==1){
|
||||
int ci;
|
||||
/*While the branch below is still correct for shapes with na==1, we can
|
||||
perform the entire transform with just 1 multiply in this case instead
|
||||
of 23.*/
|
||||
_y[0]=(ogg_int16_t)(OC_DIV2_16(OC_C4S4*(_x[pi[0]])));
|
||||
for(ci=1;ci<8;ci++)_y[ci]=0;
|
||||
}
|
||||
else{
|
||||
const ogg_int16_t *const *ext;
|
||||
int zpi;
|
||||
int api;
|
||||
int nz;
|
||||
/*First multiply by the extension matrix to compute the padding values.*/
|
||||
nz=8-na;
|
||||
ext=_e->ext;
|
||||
for(zpi=0;zpi<nz;zpi++){
|
||||
ogg_int32_t v;
|
||||
v=0;
|
||||
for(api=0;api<na;api++){
|
||||
v+=ext[zpi][api]*(ogg_int32_t)(_x[pi[api]<<3]<<1);
|
||||
}
|
||||
_x[pi[na+zpi]<<3]=(ogg_int16_t)(v+0x8000>>16)+1>>1;
|
||||
}
|
||||
oc_fdct8(_y,_x);
|
||||
}
|
||||
}
|
||||
|
||||
/*Performs a forward 8x8 Type-II DCT transform on blocks which overlap the
|
||||
border of the picture region.
|
||||
This method ONLY works with rectangular regions.
|
||||
_border: A description of which pixels are inside the border.
|
||||
_y: The buffer to store the result in.
|
||||
This may be the same as _x.
|
||||
_x: The input pixel values.
|
||||
Pixel values outside the border will be ignored.*/
|
||||
void oc_fdct8x8_border(const oc_border_info *_border,
|
||||
ogg_int16_t _y[64],const ogg_int16_t _x[64]){
|
||||
ogg_int16_t *in;
|
||||
ogg_int16_t *out;
|
||||
ogg_int16_t w[64];
|
||||
ogg_int64_t mask;
|
||||
const oc_extension_info *cext;
|
||||
const oc_extension_info *rext;
|
||||
int cmask;
|
||||
int rmask;
|
||||
int ri;
|
||||
int ci;
|
||||
/*Identify the shapes of the non-zero rows and columns.*/
|
||||
rmask=cmask=0;
|
||||
mask=_border->mask;
|
||||
for(ri=0;ri<8;ri++){
|
||||
/*This aggregation is _only_ correct for rectangular masks.*/
|
||||
cmask|=((mask&0xFF)!=0)<<ri;
|
||||
rmask|=mask&0xFF;
|
||||
mask>>=8;
|
||||
}
|
||||
/*Find the associated extension info for these shapes.*/
|
||||
if(cmask==0xFF)cext=NULL;
|
||||
else for(cext=OC_EXTENSION_INFO;cext->mask!=cmask;){
|
||||
/*If we somehow can't find the shape, then just do an unpadded fDCT.
|
||||
It won't be efficient, but it should still be correct.*/
|
||||
if(++cext>=OC_EXTENSION_INFO+OC_NSHAPES){
|
||||
oc_enc_fdct8x8_c(_y,_x);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(rmask==0xFF)rext=NULL;
|
||||
else for(rext=OC_EXTENSION_INFO;rext->mask!=rmask;){
|
||||
/*If we somehow can't find the shape, then just do an unpadded fDCT.
|
||||
It won't be efficient, but it should still be correct.*/
|
||||
if(++rext>=OC_EXTENSION_INFO+OC_NSHAPES){
|
||||
oc_enc_fdct8x8_c(_y,_x);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*Add two extra bits of working precision to improve accuracy; any more and
|
||||
we could overflow.*/
|
||||
for(ci=0;ci<64;ci++)w[ci]=_x[ci]<<2;
|
||||
/*These biases correct for some systematic error that remains in the full
|
||||
fDCT->iDCT round trip.
|
||||
We can safely add them before padding, since if these pixel values are
|
||||
overwritten, we didn't care what they were anyway (and the unbiased values
|
||||
will usually yield smaller DCT coefficient magnitudes).*/
|
||||
w[0]+=(w[0]!=0)+1;
|
||||
w[1]++;
|
||||
w[8]--;
|
||||
/*Transform the columns.
|
||||
We can ignore zero columns without a problem.*/
|
||||
in=w;
|
||||
out=_y;
|
||||
if(cext==NULL)for(ci=0;ci<8;ci++)oc_fdct8(out+(ci<<3),in+ci);
|
||||
else for(ci=0;ci<8;ci++)if(rmask&(1<<ci))oc_fdct8_ext(out+(ci<<3),in+ci,cext);
|
||||
/*Transform the rows.
|
||||
We transform even rows that are supposedly zero, because rounding errors
|
||||
may make them slightly non-zero, and this will give a more precise
|
||||
reconstruction with very small quantizers.*/
|
||||
in=_y;
|
||||
out=w;
|
||||
if(rext==NULL)for(ri=0;ri<8;ri++)oc_fdct8(out+(ri<<3),in+ri);
|
||||
else for(ri=0;ri<8;ri++)oc_fdct8_ext(out+(ri<<3),in+ri,rext);
|
||||
/*Round the result back to the external working precision (which is still
|
||||
scaled by four relative to the orthogonal result).
|
||||
TODO: We should just update the external working precision.*/
|
||||
for(ci=0;ci<64;ci++)_y[ci]=w[ci]+2>>2;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include <string.h>
|
||||
#include "internal.h"
|
||||
|
||||
void oc_frag_copy_c(unsigned char *_dst,const unsigned char *_src,int _ystride){
|
||||
int i;
|
||||
for(i=8;i-->0;){
|
||||
memcpy(_dst,_src,8*sizeof(*_dst));
|
||||
_dst+=_ystride;
|
||||
_src+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
/*Copies the fragments specified by the lists of fragment indices from one
|
||||
frame to another.
|
||||
_dst_frame: The reference frame to copy to.
|
||||
_src_frame: The reference frame to copy from.
|
||||
_ystride: The row stride of the reference frames.
|
||||
_fragis: A pointer to a list of fragment indices.
|
||||
_nfragis: The number of fragment indices to copy.
|
||||
_frag_buf_offs: The offsets of fragments in the reference frames.*/
|
||||
void oc_frag_copy_list_c(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs){
|
||||
ptrdiff_t fragii;
|
||||
for(fragii=0;fragii<_nfragis;fragii++){
|
||||
ptrdiff_t frag_buf_off;
|
||||
frag_buf_off=_frag_buf_offs[_fragis[fragii]];
|
||||
oc_frag_copy_c(_dst_frame+frag_buf_off,
|
||||
_src_frame+frag_buf_off,_ystride);
|
||||
}
|
||||
}
|
||||
|
||||
void oc_frag_recon_intra_c(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t _residue[64]){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int j;
|
||||
for(j=0;j<8;j++)_dst[j]=OC_CLAMP255(_residue[i*8+j]+128);
|
||||
_dst+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
void oc_frag_recon_inter_c(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride,const ogg_int16_t _residue[64]){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int j;
|
||||
for(j=0;j<8;j++)_dst[j]=OC_CLAMP255(_residue[i*8+j]+_src[j]);
|
||||
_dst+=_ystride;
|
||||
_src+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
void oc_frag_recon_inter2_c(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t _residue[64]){
|
||||
int i;
|
||||
for(i=0;i<8;i++){
|
||||
int j;
|
||||
for(j=0;j<8;j++)_dst[j]=OC_CLAMP255(_residue[i*8+j]+(_src1[j]+_src2[j]>>1));
|
||||
_dst+=_ystride;
|
||||
_src1+=_ystride;
|
||||
_src2+=_ystride;
|
||||
}
|
||||
}
|
||||
|
||||
void oc_restore_fpu_c(void){}
|
||||
@@ -0,0 +1,525 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ogg/ogg.h>
|
||||
#include "huffdec.h"
|
||||
#include "decint.h"
|
||||
|
||||
|
||||
|
||||
/*Instead of storing every branching in the tree, subtrees can be collapsed
|
||||
into one node, with a table of size 1<<nbits pointing directly to its
|
||||
descedents nbits levels down.
|
||||
This allows more than one bit to be read at a time, and avoids following all
|
||||
the intermediate branches with next to no increased code complexity once
|
||||
the collapsed tree has been built.
|
||||
We do _not_ require that a subtree be complete to be collapsed, but instead
|
||||
store duplicate pointers in the table, and record the actual depth of the
|
||||
node below its parent.
|
||||
This tells us the number of bits to advance the stream after reaching it.
|
||||
|
||||
This turns out to be equivalent to the method described in \cite{Hash95},
|
||||
without the requirement that codewords be sorted by length.
|
||||
If the codewords were sorted by length (so-called ``canonical-codes''), they
|
||||
could be decoded much faster via either Lindell and Moffat's approach or
|
||||
Hashemian's Condensed Huffman Code approach, the latter of which has an
|
||||
extremely small memory footprint.
|
||||
We can't use Choueka et al.'s finite state machine approach, which is
|
||||
extremely fast, because we can't allow multiple symbols to be output at a
|
||||
time; the codebook can and does change between symbols.
|
||||
It also has very large memory requirements, which impairs cache coherency.
|
||||
|
||||
We store the tree packed in an array of 16-bit integers (words).
|
||||
Each node consists of a single word, followed consecutively by two or more
|
||||
indices of its children.
|
||||
Let n be the value of this first word.
|
||||
This is the number of bits that need to be read to traverse the node, and
|
||||
must be positive.
|
||||
1<<n entries follow in the array, each an index to a child node.
|
||||
If the child is positive, then it is the index of another internal node in
|
||||
the table.
|
||||
If the child is negative or zero, then it is a leaf node.
|
||||
These are stored directly in the child pointer to save space, since they only
|
||||
require a single word.
|
||||
If a leaf node would have been encountered before reading n bits, then it is
|
||||
duplicated the necessary number of times in this table.
|
||||
Leaf nodes pack both a token value and their actual depth in the tree.
|
||||
The token in the leaf node is (-leaf&255).
|
||||
The number of bits that need to be consumed to reach the leaf, starting from
|
||||
the current node, is (-leaf>>8).
|
||||
|
||||
@ARTICLE{Hash95,
|
||||
author="Reza Hashemian",
|
||||
title="Memory Efficient and High-Speed Search {Huffman} Coding",
|
||||
journal="{IEEE} Transactions on Communications",
|
||||
volume=43,
|
||||
number=10,
|
||||
pages="2576--2581",
|
||||
month=Oct,
|
||||
year=1995
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
/*The map from external spec-defined tokens to internal tokens.
|
||||
This is constructed so that any extra bits read with the original token value
|
||||
can be masked off the least significant bits of its internal token index.
|
||||
In addition, all of the tokens which require additional extra bits are placed
|
||||
at the start of the list, and grouped by type.
|
||||
OC_DCT_REPEAT_RUN3_TOKEN is placed first, as it is an extra-special case, so
|
||||
giving it index 0 may simplify comparisons on some architectures.
|
||||
These requirements require some substantial reordering.*/
|
||||
static const unsigned char OC_DCT_TOKEN_MAP[TH_NDCT_TOKENS]={
|
||||
/*OC_DCT_EOB1_TOKEN (0 extra bits)*/
|
||||
15,
|
||||
/*OC_DCT_EOB2_TOKEN (0 extra bits)*/
|
||||
16,
|
||||
/*OC_DCT_EOB3_TOKEN (0 extra bits)*/
|
||||
17,
|
||||
/*OC_DCT_REPEAT_RUN0_TOKEN (2 extra bits)*/
|
||||
88,
|
||||
/*OC_DCT_REPEAT_RUN1_TOKEN (3 extra bits)*/
|
||||
80,
|
||||
/*OC_DCT_REPEAT_RUN2_TOKEN (4 extra bits)*/
|
||||
1,
|
||||
/*OC_DCT_REPEAT_RUN3_TOKEN (12 extra bits)*/
|
||||
0,
|
||||
/*OC_DCT_SHORT_ZRL_TOKEN (3 extra bits)*/
|
||||
48,
|
||||
/*OC_DCT_ZRL_TOKEN (6 extra bits)*/
|
||||
14,
|
||||
/*OC_ONE_TOKEN (0 extra bits)*/
|
||||
56,
|
||||
/*OC_MINUS_ONE_TOKEN (0 extra bits)*/
|
||||
57,
|
||||
/*OC_TWO_TOKEN (0 extra bits)*/
|
||||
58,
|
||||
/*OC_MINUS_TWO_TOKEN (0 extra bits)*/
|
||||
59,
|
||||
/*OC_DCT_VAL_CAT2 (1 extra bit)*/
|
||||
60,
|
||||
62,
|
||||
64,
|
||||
66,
|
||||
/*OC_DCT_VAL_CAT3 (2 extra bits)*/
|
||||
68,
|
||||
/*OC_DCT_VAL_CAT4 (3 extra bits)*/
|
||||
72,
|
||||
/*OC_DCT_VAL_CAT5 (4 extra bits)*/
|
||||
2,
|
||||
/*OC_DCT_VAL_CAT6 (5 extra bits)*/
|
||||
4,
|
||||
/*OC_DCT_VAL_CAT7 (6 extra bits)*/
|
||||
6,
|
||||
/*OC_DCT_VAL_CAT8 (10 extra bits)*/
|
||||
8,
|
||||
/*OC_DCT_RUN_CAT1A (1 extra bit)*/
|
||||
18,
|
||||
20,
|
||||
22,
|
||||
24,
|
||||
26,
|
||||
/*OC_DCT_RUN_CAT1B (3 extra bits)*/
|
||||
32,
|
||||
/*OC_DCT_RUN_CAT1C (4 extra bits)*/
|
||||
12,
|
||||
/*OC_DCT_RUN_CAT2A (2 extra bits)*/
|
||||
28,
|
||||
/*OC_DCT_RUN_CAT2B (3 extra bits)*/
|
||||
40
|
||||
};
|
||||
|
||||
/*The log base 2 of number of internal tokens associated with each of the spec
|
||||
tokens (i.e., how many of the extra bits are folded into the token value).
|
||||
Increasing the maximum value beyond 3 will enlarge the amount of stack
|
||||
required for tree construction.*/
|
||||
static const unsigned char OC_DCT_TOKEN_MAP_LOG_NENTRIES[TH_NDCT_TOKENS]={
|
||||
0,0,0,2,3,0,0,3,0,0,0,0,0,1,1,1,1,2,3,1,1,1,2,1,1,1,1,1,3,1,2,3
|
||||
};
|
||||
|
||||
|
||||
/*The size a lookup table is allowed to grow to relative to the number of
|
||||
unique nodes it contains.
|
||||
E.g., if OC_HUFF_SLUSH is 4, then at most 75% of the space in the tree is
|
||||
wasted (1/4 of the space must be used).
|
||||
Larger numbers can decode tokens with fewer read operations, while smaller
|
||||
numbers may save more space.
|
||||
With a sample file:
|
||||
32233473 read calls are required when no tree collapsing is done (100.0%).
|
||||
19269269 read calls are required when OC_HUFF_SLUSH is 1 (59.8%).
|
||||
11144969 read calls are required when OC_HUFF_SLUSH is 2 (34.6%).
|
||||
10538563 read calls are required when OC_HUFF_SLUSH is 4 (32.7%).
|
||||
10192578 read calls are required when OC_HUFF_SLUSH is 8 (31.6%).
|
||||
Since a value of 2 gets us the vast majority of the speed-up with only a
|
||||
small amount of wasted memory, this is what we use.
|
||||
This value must be less than 128, or you could create a tree with more than
|
||||
32767 entries, which would overflow the 16-bit words used to index it.*/
|
||||
#define OC_HUFF_SLUSH (2)
|
||||
/*The root of the tree is on the fast path, and a larger value here is more
|
||||
beneficial than elsewhere in the tree.
|
||||
7 appears to give the best performance, trading off between increased use of
|
||||
the single-read fast path and cache footprint for the tables, though
|
||||
obviously this will depend on your cache size.
|
||||
Using 7 here, the VP3 tables are about twice as large compared to using 2.*/
|
||||
#define OC_ROOT_HUFF_SLUSH (7)
|
||||
|
||||
|
||||
|
||||
/*Unpacks a Huffman codebook.
|
||||
_opb: The buffer to unpack from.
|
||||
_tokens: Stores a list of internal tokens, in the order they were found in
|
||||
the codebook, and the lengths of their corresponding codewords.
|
||||
This is enough to completely define the codebook, while minimizing
|
||||
stack usage and avoiding temporary allocations (for platforms
|
||||
where free() is a no-op).
|
||||
Return: The number of internal tokens in the codebook, or a negative value
|
||||
on error.*/
|
||||
int oc_huff_tree_unpack(oc_pack_buf *_opb,unsigned char _tokens[256][2]){
|
||||
ogg_uint32_t code;
|
||||
int len;
|
||||
int ntokens;
|
||||
int nleaves;
|
||||
code=0;
|
||||
len=ntokens=nleaves=0;
|
||||
for(;;){
|
||||
long bits;
|
||||
bits=oc_pack_read1(_opb);
|
||||
/*Only process nodes so long as there's more bits in the buffer.*/
|
||||
if(oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER;
|
||||
/*Read an internal node:*/
|
||||
if(!bits){
|
||||
len++;
|
||||
/*Don't allow codewords longer than 32 bits.*/
|
||||
if(len>32)return TH_EBADHEADER;
|
||||
}
|
||||
/*Read a leaf node:*/
|
||||
else{
|
||||
ogg_uint32_t code_bit;
|
||||
int neb;
|
||||
int nentries;
|
||||
int token;
|
||||
/*Don't allow more than 32 spec-tokens per codebook.*/
|
||||
if(++nleaves>32)return TH_EBADHEADER;
|
||||
bits=oc_pack_read(_opb,OC_NDCT_TOKEN_BITS);
|
||||
neb=OC_DCT_TOKEN_MAP_LOG_NENTRIES[bits];
|
||||
token=OC_DCT_TOKEN_MAP[bits];
|
||||
nentries=1<<neb;
|
||||
while(nentries-->0){
|
||||
_tokens[ntokens][0]=(unsigned char)token++;
|
||||
_tokens[ntokens][1]=(unsigned char)(len+neb);
|
||||
ntokens++;
|
||||
}
|
||||
code_bit=0x80000000U>>len-1;
|
||||
while(len>0&&(code&code_bit)){
|
||||
code^=code_bit;
|
||||
code_bit<<=1;
|
||||
len--;
|
||||
}
|
||||
if(len<=0)break;
|
||||
code|=code_bit;
|
||||
}
|
||||
}
|
||||
return ntokens;
|
||||
}
|
||||
|
||||
/*Count how many tokens would be required to fill a subtree at depth _depth.
|
||||
_tokens: A list of internal tokens, in the order they are found in the
|
||||
codebook, and the lengths of their corresponding codewords.
|
||||
_depth: The depth of the desired node in the corresponding tree structure.
|
||||
Return: The number of tokens that belong to that subtree.*/
|
||||
static int oc_huff_subtree_tokens(unsigned char _tokens[][2],int _depth){
|
||||
ogg_uint32_t code;
|
||||
int ti;
|
||||
code=0;
|
||||
ti=0;
|
||||
do{
|
||||
if(_tokens[ti][1]-_depth<32)code+=0x80000000U>>_tokens[ti++][1]-_depth;
|
||||
else{
|
||||
/*Because of the expanded internal tokens, we can have codewords as long
|
||||
as 35 bits.
|
||||
A single recursion here is enough to advance past them.*/
|
||||
code++;
|
||||
ti+=oc_huff_subtree_tokens(_tokens+ti,_depth+31);
|
||||
}
|
||||
}
|
||||
while(code<0x80000000U);
|
||||
return ti;
|
||||
}
|
||||
|
||||
/*Compute the number of bits to use for a collapsed tree node at the given
|
||||
depth.
|
||||
_tokens: A list of internal tokens, in the order they are found in the
|
||||
codebook, and the lengths of their corresponding codewords.
|
||||
_ntokens: The number of tokens corresponding to this tree node.
|
||||
_depth: The depth of this tree node.
|
||||
Return: The number of bits to use for a collapsed tree node rooted here.
|
||||
This is always at least one, even if this was a leaf node.*/
|
||||
static int oc_huff_tree_collapse_depth(unsigned char _tokens[][2],
|
||||
int _ntokens,int _depth){
|
||||
int got_leaves;
|
||||
int loccupancy;
|
||||
int occupancy;
|
||||
int slush;
|
||||
int nbits;
|
||||
int best_nbits;
|
||||
slush=_depth>0?OC_HUFF_SLUSH:OC_ROOT_HUFF_SLUSH;
|
||||
/*It's legal to have a tree with just a single node, which requires no bits
|
||||
to decode and always returns the same token.
|
||||
However, no encoder actually does this (yet).
|
||||
To avoid a special case in oc_huff_token_decode(), we force the number of
|
||||
lookahead bits to be at least one.
|
||||
This will produce a tree that looks ahead one bit and then advances the
|
||||
stream zero bits.*/
|
||||
nbits=1;
|
||||
occupancy=2;
|
||||
got_leaves=1;
|
||||
do{
|
||||
int ti;
|
||||
if(got_leaves)best_nbits=nbits;
|
||||
nbits++;
|
||||
got_leaves=0;
|
||||
loccupancy=occupancy;
|
||||
for(occupancy=ti=0;ti<_ntokens;occupancy++){
|
||||
if(_tokens[ti][1]<_depth+nbits)ti++;
|
||||
else if(_tokens[ti][1]==_depth+nbits){
|
||||
got_leaves=1;
|
||||
ti++;
|
||||
}
|
||||
else ti+=oc_huff_subtree_tokens(_tokens+ti,_depth+nbits);
|
||||
}
|
||||
}
|
||||
while(occupancy>loccupancy&&occupancy*slush>=1<<nbits);
|
||||
return best_nbits;
|
||||
}
|
||||
|
||||
/*Determines the size in words of a Huffman tree node that represents a
|
||||
subtree of depth _nbits.
|
||||
_nbits: The depth of the subtree.
|
||||
This must be greater than zero.
|
||||
Return: The number of words required to store the node.*/
|
||||
static size_t oc_huff_node_size(int _nbits){
|
||||
return 1+(1<<_nbits);
|
||||
}
|
||||
|
||||
/*Produces a collapsed-tree representation of the given token list.
|
||||
_tree: The storage for the collapsed Huffman tree.
|
||||
This may be NULL to compute the required storage size instead of
|
||||
constructing the tree.
|
||||
_tokens: A list of internal tokens, in the order they are found in the
|
||||
codebook, and the lengths of their corresponding codewords.
|
||||
_ntokens: The number of tokens corresponding to this tree node.
|
||||
Return: The number of words required to store the tree.*/
|
||||
static size_t oc_huff_tree_collapse(ogg_int16_t *_tree,
|
||||
unsigned char _tokens[][2],int _ntokens){
|
||||
ogg_int16_t node[34];
|
||||
unsigned char depth[34];
|
||||
unsigned char last[34];
|
||||
size_t ntree;
|
||||
int ti;
|
||||
int l;
|
||||
depth[0]=0;
|
||||
last[0]=(unsigned char)(_ntokens-1);
|
||||
ntree=0;
|
||||
ti=0;
|
||||
l=0;
|
||||
do{
|
||||
int nbits;
|
||||
nbits=oc_huff_tree_collapse_depth(_tokens+ti,last[l]+1-ti,depth[l]);
|
||||
node[l]=(ogg_int16_t)ntree;
|
||||
ntree+=oc_huff_node_size(nbits);
|
||||
if(_tree!=NULL)_tree[node[l]++]=(ogg_int16_t)nbits;
|
||||
do{
|
||||
while(ti<=last[l]&&_tokens[ti][1]<=depth[l]+nbits){
|
||||
if(_tree!=NULL){
|
||||
ogg_int16_t leaf;
|
||||
int nentries;
|
||||
nentries=1<<depth[l]+nbits-_tokens[ti][1];
|
||||
leaf=(ogg_int16_t)-(_tokens[ti][1]-depth[l]<<8|_tokens[ti][0]);
|
||||
while(nentries-->0)_tree[node[l]++]=leaf;
|
||||
}
|
||||
ti++;
|
||||
}
|
||||
if(ti<=last[l]){
|
||||
/*We need to recurse*/
|
||||
depth[l+1]=(unsigned char)(depth[l]+nbits);
|
||||
if(_tree!=NULL)_tree[node[l]++]=(ogg_int16_t)ntree;
|
||||
l++;
|
||||
last[l]=
|
||||
(unsigned char)(ti+oc_huff_subtree_tokens(_tokens+ti,depth[l])-1);
|
||||
break;
|
||||
}
|
||||
/*Pop back up a level of recursion.*/
|
||||
else if(l-->0)nbits=depth[l+1]-depth[l];
|
||||
}
|
||||
while(l>=0);
|
||||
}
|
||||
while(l>=0);
|
||||
return ntree;
|
||||
}
|
||||
|
||||
/*Unpacks a set of Huffman trees, and reduces them to a collapsed
|
||||
representation.
|
||||
_opb: The buffer to unpack the trees from.
|
||||
_nodes: The table to fill with the Huffman trees.
|
||||
Return: 0 on success, or a negative value on error.*/
|
||||
int oc_huff_trees_unpack(oc_pack_buf *_opb,
|
||||
ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]){
|
||||
int ret;
|
||||
int i;
|
||||
ret=0;
|
||||
for(i=0;i<TH_NHUFFMAN_TABLES;i++){
|
||||
unsigned char tokens[256][2];
|
||||
int ntokens;
|
||||
ogg_int16_t *tree;
|
||||
size_t size;
|
||||
/*Unpack the full tree into a temporary buffer.*/
|
||||
ntokens=oc_huff_tree_unpack(_opb,tokens);
|
||||
if(ntokens<0){
|
||||
ret=ntokens;
|
||||
break;
|
||||
}
|
||||
/*Figure out how big the collapsed tree will be and allocate space for it.*/
|
||||
size=oc_huff_tree_collapse(NULL,tokens,ntokens);
|
||||
if(size>32767){
|
||||
/*This should never happen; if it does it means you set OC_HUFF_SLUSH or
|
||||
OC_ROOT_HUFF_SLUSH too large.*/
|
||||
ret=TH_EIMPL;
|
||||
break;
|
||||
}
|
||||
tree=(ogg_int16_t *)_ogg_malloc(size*sizeof(*tree));
|
||||
if(tree==NULL){
|
||||
ret=TH_EFAULT;
|
||||
break;
|
||||
}
|
||||
/*Construct the collapsed the tree.*/
|
||||
oc_huff_tree_collapse(tree,tokens,ntokens);
|
||||
_nodes[i]=tree;
|
||||
}
|
||||
if(ret<0)while(i-->0)_ogg_free(_nodes[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Determines the size in words of a Huffman subtree.
|
||||
_tree: The complete Huffman tree.
|
||||
_node: The index of the root of the desired subtree.
|
||||
Return: The number of words required to store the tree.*/
|
||||
static size_t oc_huff_tree_size(const ogg_int16_t *_tree,int _node){
|
||||
size_t size;
|
||||
int nchildren;
|
||||
int n;
|
||||
int i;
|
||||
n=_tree[_node];
|
||||
size=oc_huff_node_size(n);
|
||||
nchildren=1<<n;
|
||||
i=0;
|
||||
do{
|
||||
int child;
|
||||
child=_tree[_node+i+1];
|
||||
if(child<=0)i+=1<<n-(-child>>8);
|
||||
else{
|
||||
size+=oc_huff_tree_size(_tree,child);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
while(i<nchildren);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*Makes a copy of the given set of Huffman trees.
|
||||
_dst: The array to store the copy in.
|
||||
_src: The array of trees to copy.*/
|
||||
int oc_huff_trees_copy(ogg_int16_t *_dst[TH_NHUFFMAN_TABLES],
|
||||
const ogg_int16_t *const _src[TH_NHUFFMAN_TABLES]){
|
||||
int total;
|
||||
int i;
|
||||
total=0;
|
||||
for(i=0;i<TH_NHUFFMAN_TABLES;i++){
|
||||
size_t size;
|
||||
size=oc_huff_tree_size(_src[i],0);
|
||||
total+=size;
|
||||
_dst[i]=(ogg_int16_t *)_ogg_malloc(size*sizeof(*_dst[i]));
|
||||
if(_dst[i]==NULL){
|
||||
while(i-->0)_ogg_free(_dst[i]);
|
||||
return TH_EFAULT;
|
||||
}
|
||||
memcpy(_dst[i],_src[i],size*sizeof(*_dst[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Frees the memory used by a set of Huffman trees.
|
||||
_nodes: The array of trees to free.*/
|
||||
void oc_huff_trees_clear(ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]){
|
||||
int i;
|
||||
for(i=0;i<TH_NHUFFMAN_TABLES;i++)_ogg_free(_nodes[i]);
|
||||
}
|
||||
|
||||
|
||||
/*Unpacks a single token using the given Huffman tree.
|
||||
_opb: The buffer to unpack the token from.
|
||||
_node: The tree to unpack the token with.
|
||||
Return: The token value.*/
|
||||
int oc_huff_token_decode(oc_pack_buf *_opb,const ogg_int16_t *_tree){
|
||||
const unsigned char *ptr;
|
||||
const unsigned char *stop;
|
||||
oc_pb_window window;
|
||||
int available;
|
||||
long bits;
|
||||
int node;
|
||||
int n;
|
||||
ptr=_opb->ptr;
|
||||
window=_opb->window;
|
||||
stop=_opb->stop;
|
||||
available=_opb->bits;
|
||||
node=0;
|
||||
for(;;){
|
||||
n=_tree[node];
|
||||
if(n>available){
|
||||
unsigned shift;
|
||||
shift=OC_PB_WINDOW_SIZE-available;
|
||||
do{
|
||||
/*We don't bother setting eof because we won't check for it after we've
|
||||
started decoding DCT tokens.*/
|
||||
if(ptr>=stop){
|
||||
shift=-OC_LOTS_OF_BITS;
|
||||
break;
|
||||
}
|
||||
shift-=8;
|
||||
window|=(oc_pb_window)*ptr++<<shift;
|
||||
}
|
||||
while(shift>=8);
|
||||
/*Note: We never request more than 24 bits, so there's no need to fill in
|
||||
the last partial byte here.*/
|
||||
available=OC_PB_WINDOW_SIZE-shift;
|
||||
}
|
||||
bits=window>>OC_PB_WINDOW_SIZE-n;
|
||||
node=_tree[node+1+bits];
|
||||
if(node<=0)break;
|
||||
window<<=n;
|
||||
available-=n;
|
||||
}
|
||||
node=-node;
|
||||
n=node>>8;
|
||||
window<<=n;
|
||||
available-=n;
|
||||
_opb->ptr=ptr;
|
||||
_opb->window=window;
|
||||
_opb->bits=available;
|
||||
return node&255;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_huffdec_H)
|
||||
# define _huffdec_H (1)
|
||||
# include "huffman.h"
|
||||
# include "bitpack.h"
|
||||
|
||||
|
||||
|
||||
int oc_huff_trees_unpack(oc_pack_buf *_opb,
|
||||
ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]);
|
||||
int oc_huff_trees_copy(ogg_int16_t *_dst[TH_NHUFFMAN_TABLES],
|
||||
const ogg_int16_t *const _src[TH_NHUFFMAN_TABLES]);
|
||||
void oc_huff_trees_clear(ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]);
|
||||
int oc_huff_token_decode_c(oc_pack_buf *_opb,const ogg_int16_t *_node);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,969 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ogg/ogg.h>
|
||||
#include "huffenc.h"
|
||||
|
||||
|
||||
|
||||
/*The default Huffman codes used for VP3.1.*/
|
||||
const th_huff_code TH_VP31_HUFF_CODES[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS]={
|
||||
{
|
||||
{0x002D, 6},{0x0026, 7},{0x0166, 9},{0x004E, 8},
|
||||
{0x02CE,10},{0x059E,11},{0x027D,11},{0x0008, 5},
|
||||
{0x04F9,12},{0x000F, 4},{0x000E, 4},{0x001B, 5},
|
||||
{0x0006, 4},{0x0008, 4},{0x0005, 4},{0x001A, 5},
|
||||
{0x0015, 5},{0x0007, 4},{0x000C, 4},{0x0001, 3},
|
||||
{0x0000, 3},{0x0009, 4},{0x0017, 5},{0x0029, 6},
|
||||
{0x0028, 6},{0x00B2, 8},{0x04F8,12},{0x059F,11},
|
||||
{0x009E, 9},{0x013F,10},{0x0012, 6},{0x0058, 7}
|
||||
},
|
||||
{
|
||||
{0x0010, 5},{0x0047, 7},{0x01FF, 9},{0x008C, 8},
|
||||
{0x03FC,10},{0x046A,11},{0x0469,11},{0x0022, 6},
|
||||
{0x11A1,13},{0x000E, 4},{0x000D, 4},{0x0004, 4},
|
||||
{0x0005, 4},{0x0009, 4},{0x0006, 4},{0x001E, 5},
|
||||
{0x0016, 5},{0x0007, 4},{0x000C, 4},{0x0001, 3},
|
||||
{0x0000, 3},{0x000A, 4},{0x0017, 5},{0x007D, 7},
|
||||
{0x007E, 7},{0x011B, 9},{0x08D1,12},{0x03FD,10},
|
||||
{0x046B,11},{0x11A0,13},{0x007C, 7},{0x00FE, 8}
|
||||
},
|
||||
{
|
||||
{0x0016, 5},{0x0020, 6},{0x0086, 8},{0x0087, 8},
|
||||
{0x0367,10},{0x06CC,11},{0x06CB,11},{0x006E, 7},
|
||||
{0x366D,14},{0x000F, 4},{0x000E, 4},{0x0004, 4},
|
||||
{0x0005, 4},{0x000A, 4},{0x0006, 4},{0x001A, 5},
|
||||
{0x0011, 5},{0x0007, 4},{0x000C, 4},{0x0001, 3},
|
||||
{0x0000, 3},{0x0009, 4},{0x0017, 5},{0x006F, 7},
|
||||
{0x006D, 7},{0x0364,10},{0x0D9A,12},{0x06CA,11},
|
||||
{0x1B37,13},{0x366C,14},{0x0042, 7},{0x00D8, 8}
|
||||
},
|
||||
{
|
||||
{0x0000, 4},{0x002D, 6},{0x00F7, 8},{0x0058, 7},
|
||||
{0x0167, 9},{0x02CB,10},{0x02CA,10},{0x000E, 6},
|
||||
{0x1661,13},{0x0003, 3},{0x0002, 3},{0x0008, 4},
|
||||
{0x0009, 4},{0x000D, 4},{0x0002, 4},{0x001F, 5},
|
||||
{0x0017, 5},{0x0001, 4},{0x000C, 4},{0x000E, 4},
|
||||
{0x000A, 4},{0x0006, 5},{0x0078, 7},{0x000F, 6},
|
||||
{0x007A, 7},{0x0164, 9},{0x0599,11},{0x02CD,10},
|
||||
{0x0B31,12},{0x1660,13},{0x0079, 7},{0x00F6, 8}
|
||||
},
|
||||
{
|
||||
{0x0003, 4},{0x003C, 6},{0x000F, 7},{0x007A, 7},
|
||||
{0x001D, 8},{0x0020, 9},{0x0072,10},{0x0006, 6},
|
||||
{0x0399,13},{0x0004, 3},{0x0005, 3},{0x0005, 4},
|
||||
{0x0006, 4},{0x000E, 4},{0x0004, 4},{0x0000, 4},
|
||||
{0x0019, 5},{0x0002, 4},{0x000D, 4},{0x0007, 4},
|
||||
{0x001F, 5},{0x0030, 6},{0x0011, 8},{0x0031, 6},
|
||||
{0x0005, 6},{0x0021, 9},{0x00E7,11},{0x0038, 9},
|
||||
{0x01CD,12},{0x0398,13},{0x007B, 7},{0x0009, 7}
|
||||
},
|
||||
{
|
||||
{0x0009, 4},{0x0002, 5},{0x0074, 7},{0x0007, 6},
|
||||
{0x00EC, 8},{0x00D1, 9},{0x01A6,10},{0x0006, 6},
|
||||
{0x0D21,13},{0x0005, 3},{0x0006, 3},{0x0008, 4},
|
||||
{0x0007, 4},{0x000F, 4},{0x0004, 4},{0x0000, 4},
|
||||
{0x001C, 5},{0x0002, 4},{0x0005, 4},{0x0003, 4},
|
||||
{0x000C, 5},{0x0035, 7},{0x01A7,10},{0x001B, 6},
|
||||
{0x0077, 7},{0x01A5,10},{0x0349,11},{0x00D0, 9},
|
||||
{0x0691,12},{0x0D20,13},{0x0075, 7},{0x00ED, 8}
|
||||
},
|
||||
{
|
||||
{0x000A, 4},{0x000C, 5},{0x0012, 6},{0x001B, 6},
|
||||
{0x00B7, 8},{0x016C, 9},{0x0099, 9},{0x005A, 7},
|
||||
{0x16D8,13},{0x0007, 3},{0x0006, 3},{0x0009, 4},
|
||||
{0x0008, 4},{0x0000, 3},{0x0005, 4},{0x0017, 5},
|
||||
{0x000E, 5},{0x0002, 4},{0x0003, 4},{0x000F, 5},
|
||||
{0x001A, 6},{0x004D, 8},{0x2DB3,14},{0x002C, 6},
|
||||
{0x0011, 6},{0x02DA,10},{0x05B7,11},{0x0098, 9},
|
||||
{0x0B6D,12},{0x2DB2,14},{0x0010, 6},{0x0027, 7}
|
||||
},
|
||||
{
|
||||
{0x000D, 4},{0x000F, 5},{0x001D, 6},{0x0008, 5},
|
||||
{0x0051, 7},{0x0056, 8},{0x00AF, 9},{0x002A, 7},
|
||||
{0x148A,13},{0x0007, 3},{0x0000, 2},{0x0008, 4},
|
||||
{0x0009, 4},{0x000C, 4},{0x0006, 4},{0x0017, 5},
|
||||
{0x000B, 5},{0x0016, 5},{0x0015, 5},{0x0009, 5},
|
||||
{0x0050, 7},{0x00AE, 9},{0x2917,14},{0x001C, 6},
|
||||
{0x0014, 6},{0x0290,10},{0x0523,11},{0x0149, 9},
|
||||
{0x0A44,12},{0x2916,14},{0x0053, 7},{0x00A5, 8}
|
||||
},
|
||||
{
|
||||
{0x0001, 4},{0x001D, 6},{0x00F5, 8},{0x00F4, 8},
|
||||
{0x024D,10},{0x0499,11},{0x0498,11},{0x0001, 5},
|
||||
{0x0021, 6},{0x0006, 3},{0x0005, 3},{0x0006, 4},
|
||||
{0x0005, 4},{0x0002, 4},{0x0007, 5},{0x0025, 6},
|
||||
{0x007B, 7},{0x001C, 6},{0x0020, 6},{0x000D, 6},
|
||||
{0x0048, 7},{0x0092, 8},{0x0127, 9},{0x000E, 4},
|
||||
{0x0004, 4},{0x0011, 5},{0x000C, 6},{0x003C, 6},
|
||||
{0x000F, 5},{0x0000, 5},{0x001F, 5},{0x0013, 5}
|
||||
},
|
||||
{
|
||||
{0x0005, 4},{0x003C, 6},{0x0040, 7},{0x000D, 7},
|
||||
{0x0031, 9},{0x0061,10},{0x0060,10},{0x0002, 5},
|
||||
{0x00F5, 8},{0x0006, 3},{0x0005, 3},{0x0007, 4},
|
||||
{0x0006, 4},{0x0002, 4},{0x0009, 5},{0x0025, 6},
|
||||
{0x0007, 6},{0x0021, 6},{0x0024, 6},{0x0010, 6},
|
||||
{0x0041, 7},{0x00F4, 8},{0x0019, 8},{0x000E, 4},
|
||||
{0x0003, 4},{0x0011, 5},{0x0011, 6},{0x003F, 6},
|
||||
{0x003E, 6},{0x007B, 7},{0x0000, 4},{0x0013, 5}
|
||||
},
|
||||
{
|
||||
{0x000A, 4},{0x0007, 5},{0x0001, 6},{0x0009, 6},
|
||||
{0x0131, 9},{0x0261,10},{0x0260,10},{0x0015, 6},
|
||||
{0x0001, 7},{0x0007, 3},{0x0006, 3},{0x0008, 4},
|
||||
{0x0007, 4},{0x0006, 4},{0x0012, 5},{0x002F, 6},
|
||||
{0x0014, 6},{0x0027, 6},{0x002D, 6},{0x0016, 6},
|
||||
{0x004D, 7},{0x0099, 8},{0x0000, 7},{0x0004, 4},
|
||||
{0x0001, 4},{0x0005, 5},{0x0017, 6},{0x002E, 6},
|
||||
{0x002C, 6},{0x0008, 6},{0x0006, 5},{0x0001, 5}
|
||||
},
|
||||
{
|
||||
{0x0000, 3},{0x000E, 5},{0x0017, 6},{0x002A, 6},
|
||||
{0x0010, 7},{0x00F9,10},{0x00F8,10},{0x001E, 7},
|
||||
{0x003F, 8},{0x0007, 3},{0x0006, 3},{0x0009, 4},
|
||||
{0x0008, 4},{0x0006, 4},{0x000F, 5},{0x0005, 5},
|
||||
{0x0016, 6},{0x0029, 6},{0x002B, 6},{0x0015, 6},
|
||||
{0x0050, 7},{0x0011, 7},{0x007D, 9},{0x0004, 4},
|
||||
{0x0017, 5},{0x0006, 5},{0x0014, 6},{0x002C, 6},
|
||||
{0x002D, 6},{0x000E, 6},{0x0009, 6},{0x0051, 7}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x0018, 5},{0x002F, 6},{0x000D, 5},
|
||||
{0x0053, 7},{0x0295,10},{0x0294,10},{0x00A4, 8},
|
||||
{0x007C, 8},{0x0000, 2},{0x0007, 3},{0x0009, 4},
|
||||
{0x0008, 4},{0x001B, 5},{0x000C, 5},{0x0028, 6},
|
||||
{0x006A, 7},{0x001E, 6},{0x001D, 6},{0x0069, 7},
|
||||
{0x00D7, 8},{0x007D, 8},{0x014B, 9},{0x0019, 5},
|
||||
{0x0016, 5},{0x002E, 6},{0x001C, 6},{0x002B, 6},
|
||||
{0x002A, 6},{0x0068, 7},{0x003F, 7},{0x00D6, 8}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x001B, 5},{0x000C, 5},{0x0018, 5},
|
||||
{0x0029, 6},{0x007F, 8},{0x02F0,10},{0x0198, 9},
|
||||
{0x0179, 9},{0x0000, 2},{0x0007, 3},{0x0009, 4},
|
||||
{0x0008, 4},{0x001A, 5},{0x000D, 5},{0x002A, 6},
|
||||
{0x0064, 7},{0x001E, 6},{0x0067, 7},{0x005F, 7},
|
||||
{0x00CD, 8},{0x007E, 8},{0x02F1,10},{0x0016, 5},
|
||||
{0x000E, 5},{0x002E, 6},{0x0065, 7},{0x002B, 6},
|
||||
{0x0028, 6},{0x003E, 7},{0x00BD, 8},{0x0199, 9}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x0007, 4},{0x0016, 5},{0x0006, 4},
|
||||
{0x0036, 6},{0x005C, 7},{0x015D, 9},{0x015C, 9},
|
||||
{0x02BF,10},{0x0000, 2},{0x0007, 3},{0x0009, 4},
|
||||
{0x0008, 4},{0x0018, 5},{0x0034, 6},{0x002A, 6},
|
||||
{0x005E, 7},{0x006A, 7},{0x0064, 7},{0x005D, 7},
|
||||
{0x00CB, 8},{0x00AD, 8},{0x02BE,10},{0x0014, 5},
|
||||
{0x0033, 6},{0x006E, 7},{0x005F, 7},{0x006F, 7},
|
||||
{0x006B, 7},{0x00CA, 8},{0x00AC, 8},{0x015E, 9}
|
||||
},
|
||||
{
|
||||
{0x000F, 4},{0x001D, 5},{0x0018, 5},{0x000B, 4},
|
||||
{0x0019, 5},{0x0029, 6},{0x00D6, 8},{0x0551,11},
|
||||
{0x0AA1,12},{0x0001, 2},{0x0000, 2},{0x0009, 4},
|
||||
{0x0008, 4},{0x001B, 5},{0x0038, 6},{0x0028, 6},
|
||||
{0x0057, 7},{0x006A, 7},{0x0068, 7},{0x0056, 7},
|
||||
{0x00E5, 8},{0x0155, 9},{0x0AA0,12},{0x0073, 7},
|
||||
{0x0069, 7},{0x00D7, 8},{0x00AB, 8},{0x00E4, 8},
|
||||
{0x00A9, 8},{0x0151, 9},{0x0150, 9},{0x02A9,10}
|
||||
},
|
||||
{
|
||||
{0x0008, 5},{0x0025, 7},{0x017A, 9},{0x02F7,10},
|
||||
{0x0BDB,12},{0x17B4,13},{0x2F6B,14},{0x001D, 5},
|
||||
{0x2F6A,14},{0x0008, 4},{0x0007, 4},{0x0001, 4},
|
||||
{0x0002, 4},{0x000A, 4},{0x0006, 4},{0x0000, 4},
|
||||
{0x001C, 5},{0x0009, 4},{0x000D, 4},{0x000F, 4},
|
||||
{0x000C, 4},{0x0003, 4},{0x000A, 5},{0x0016, 5},
|
||||
{0x0013, 6},{0x005D, 7},{0x0024, 7},{0x00BC, 8},
|
||||
{0x005C, 7},{0x05EC,11},{0x000B, 5},{0x005F, 7}
|
||||
},
|
||||
{
|
||||
{0x000F, 5},{0x0010, 6},{0x004B, 8},{0x00C6, 8},
|
||||
{0x031D,10},{0x0C71,12},{0x0C70,12},{0x0001, 4},
|
||||
{0x0C73,12},{0x0008, 4},{0x0009, 4},{0x0002, 4},
|
||||
{0x0003, 4},{0x000B, 4},{0x0006, 4},{0x0000, 4},
|
||||
{0x001C, 5},{0x0005, 4},{0x000D, 4},{0x000F, 4},
|
||||
{0x000A, 4},{0x0019, 5},{0x0013, 6},{0x001D, 5},
|
||||
{0x0030, 6},{0x0062, 7},{0x0024, 7},{0x004A, 8},
|
||||
{0x018F, 9},{0x0C72,12},{0x000E, 5},{0x0011, 6}
|
||||
},
|
||||
{
|
||||
{0x001B, 5},{0x0003, 6},{0x008D, 8},{0x0040, 7},
|
||||
{0x0239,10},{0x0471,11},{0x08E0,12},{0x0003, 4},
|
||||
{0x11C3,13},{0x000A, 4},{0x0009, 4},{0x0004, 4},
|
||||
{0x0005, 4},{0x000E, 4},{0x0007, 4},{0x0001, 4},
|
||||
{0x001E, 5},{0x0006, 4},{0x000C, 4},{0x000B, 4},
|
||||
{0x0002, 4},{0x0000, 5},{0x0041, 7},{0x001F, 5},
|
||||
{0x0022, 6},{0x0002, 6},{0x008F, 8},{0x008C, 8},
|
||||
{0x011D, 9},{0x11C2,13},{0x001A, 5},{0x0021, 6}
|
||||
},
|
||||
{
|
||||
{0x001F, 5},{0x0003, 6},{0x0003, 7},{0x0043, 7},
|
||||
{0x000B, 9},{0x0015,10},{0x0051,12},{0x0003, 4},
|
||||
{0x0050,12},{0x000D, 4},{0x000C, 4},{0x0004, 4},
|
||||
{0x0006, 4},{0x000E, 4},{0x000A, 4},{0x0001, 4},
|
||||
{0x001E, 5},{0x0005, 4},{0x0009, 4},{0x0007, 4},
|
||||
{0x0011, 5},{0x0002, 6},{0x0004, 8},{0x0002, 4},
|
||||
{0x002D, 6},{0x0020, 6},{0x0042, 7},{0x0001, 7},
|
||||
{0x0000, 7},{0x0029,11},{0x0017, 5},{0x002C, 6}
|
||||
},
|
||||
{
|
||||
{0x0003, 4},{0x001F, 6},{0x003A, 7},{0x005D, 7},
|
||||
{0x0173, 9},{0x02E4,10},{0x172D,13},{0x0004, 4},
|
||||
{0x172C,13},{0x000F, 4},{0x000E, 4},{0x0009, 4},
|
||||
{0x0008, 4},{0x000C, 4},{0x000A, 4},{0x0001, 4},
|
||||
{0x0016, 5},{0x0002, 4},{0x0005, 4},{0x001A, 5},
|
||||
{0x002F, 6},{0x0038, 7},{0x05CA,11},{0x0006, 4},
|
||||
{0x0037, 6},{0x001E, 6},{0x003B, 7},{0x0039, 7},
|
||||
{0x00B8, 8},{0x0B97,12},{0x0000, 4},{0x0036, 6}
|
||||
},
|
||||
{
|
||||
{0x0006, 4},{0x0037, 6},{0x005D, 7},{0x000C, 6},
|
||||
{0x00B9, 8},{0x02E3,10},{0x05C4,11},{0x0004, 4},
|
||||
{0x1715,13},{0x0000, 3},{0x000F, 4},{0x0008, 4},
|
||||
{0x0007, 4},{0x000C, 4},{0x0009, 4},{0x001D, 5},
|
||||
{0x0016, 5},{0x001C, 5},{0x001A, 5},{0x000B, 5},
|
||||
{0x005E, 7},{0x0170, 9},{0x1714,13},{0x000A, 4},
|
||||
{0x000A, 5},{0x0036, 6},{0x005F, 7},{0x001B, 7},
|
||||
{0x001A, 7},{0x0B8B,12},{0x0002, 4},{0x0007, 5}
|
||||
},
|
||||
{
|
||||
{0x000C, 4},{0x000B, 5},{0x0079, 7},{0x0022, 6},
|
||||
{0x00F0, 8},{0x0119, 9},{0x0230,10},{0x001D, 5},
|
||||
{0x08C4,12},{0x0001, 3},{0x0000, 3},{0x000A, 4},
|
||||
{0x0009, 4},{0x000B, 4},{0x0007, 4},{0x001C, 5},
|
||||
{0x003D, 6},{0x000D, 5},{0x0008, 5},{0x0015, 6},
|
||||
{0x008D, 8},{0x118B,13},{0x118A,13},{0x000D, 4},
|
||||
{0x0010, 5},{0x0009, 5},{0x0014, 6},{0x0047, 7},
|
||||
{0x00F1, 8},{0x0463,11},{0x001F, 5},{0x000C, 5}
|
||||
},
|
||||
{
|
||||
{0x0000, 3},{0x001A, 5},{0x0033, 6},{0x000C, 5},
|
||||
{0x0046, 7},{0x01E3, 9},{0x03C5,10},{0x0017, 5},
|
||||
{0x1E21,13},{0x0002, 3},{0x0001, 3},{0x0009, 4},
|
||||
{0x000A, 4},{0x0007, 4},{0x001B, 5},{0x003D, 6},
|
||||
{0x001B, 6},{0x0022, 6},{0x0079, 7},{0x00F0, 8},
|
||||
{0x1E20,13},{0x1E23,13},{0x1E22,13},{0x000E, 4},
|
||||
{0x0016, 5},{0x0018, 5},{0x0032, 6},{0x001A, 6},
|
||||
{0x0047, 7},{0x0789,11},{0x001F, 5},{0x0010, 5}
|
||||
},
|
||||
{
|
||||
{0x001D, 5},{0x0061, 7},{0x004E, 8},{0x009E, 9},
|
||||
{0x027C,11},{0x09F5,13},{0x09F4,13},{0x0003, 4},
|
||||
{0x0060, 7},{0x0000, 3},{0x000F, 4},{0x000B, 4},
|
||||
{0x000A, 4},{0x0009, 4},{0x0005, 4},{0x000D, 5},
|
||||
{0x0031, 6},{0x0008, 5},{0x0038, 6},{0x0012, 6},
|
||||
{0x0026, 7},{0x013F,10},{0x04FB,12},{0x000D, 4},
|
||||
{0x0002, 4},{0x000C, 5},{0x0039, 6},{0x001C, 6},
|
||||
{0x000F, 5},{0x001D, 6},{0x0008, 4},{0x0019, 5}
|
||||
},
|
||||
{
|
||||
{0x0007, 4},{0x0019, 6},{0x00AB, 8},{0x00AA, 8},
|
||||
{0x0119,10},{0x0461,12},{0x0460,12},{0x001B, 5},
|
||||
{0x0047, 8},{0x0001, 3},{0x0000, 3},{0x000C, 4},
|
||||
{0x000B, 4},{0x0009, 4},{0x0005, 4},{0x000D, 5},
|
||||
{0x0035, 6},{0x003D, 6},{0x003C, 6},{0x0018, 6},
|
||||
{0x0022, 7},{0x008D, 9},{0x0231,11},{0x000E, 4},
|
||||
{0x001F, 5},{0x0009, 5},{0x002B, 6},{0x0010, 6},
|
||||
{0x0034, 6},{0x0054, 7},{0x0008, 4},{0x0014, 5}
|
||||
},
|
||||
{
|
||||
{0x000C, 4},{0x0005, 5},{0x0008, 6},{0x005B, 7},
|
||||
{0x004D, 9},{0x0131,11},{0x0261,12},{0x001A, 5},
|
||||
{0x0012, 7},{0x0000, 3},{0x000F, 4},{0x000A, 4},
|
||||
{0x0009, 4},{0x0006, 4},{0x001B, 5},{0x0006, 5},
|
||||
{0x001C, 6},{0x002C, 6},{0x0015, 6},{0x005A, 7},
|
||||
{0x0027, 8},{0x0099,10},{0x0260,12},{0x000E, 4},
|
||||
{0x0004, 4},{0x000F, 5},{0x0007, 5},{0x001D, 6},
|
||||
{0x000B, 5},{0x0014, 6},{0x0008, 4},{0x0017, 5}
|
||||
},
|
||||
{
|
||||
{0x000F, 4},{0x0013, 5},{0x0075, 7},{0x0024, 6},
|
||||
{0x0095, 8},{0x0251,10},{0x04A0,11},{0x0010, 5},
|
||||
{0x00C8, 8},{0x0002, 3},{0x0001, 3},{0x0001, 4},
|
||||
{0x0000, 4},{0x001A, 5},{0x0011, 5},{0x002C, 6},
|
||||
{0x0065, 7},{0x0074, 7},{0x004B, 7},{0x00C9, 8},
|
||||
{0x0129, 9},{0x0943,12},{0x0942,12},{0x0003, 3},
|
||||
{0x000A, 4},{0x001C, 5},{0x0018, 5},{0x0033, 6},
|
||||
{0x0017, 5},{0x002D, 6},{0x001B, 5},{0x003B, 6}
|
||||
},
|
||||
{
|
||||
{0x0003, 3},{0x001A, 5},{0x002D, 6},{0x0038, 6},
|
||||
{0x0028, 7},{0x0395,10},{0x0E51,12},{0x0037, 6},
|
||||
{0x00E4, 8},{0x0001, 3},{0x0000, 3},{0x001F, 5},
|
||||
{0x001E, 5},{0x0017, 5},{0x003A, 6},{0x0073, 7},
|
||||
{0x002A, 7},{0x002B, 7},{0x0029, 7},{0x01CB, 9},
|
||||
{0x0729,11},{0x1CA1,13},{0x1CA0,13},{0x0004, 3},
|
||||
{0x000A, 4},{0x0004, 4},{0x0018, 5},{0x0036, 6},
|
||||
{0x000B, 5},{0x002C, 6},{0x0019, 5},{0x003B, 6}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x0004, 4},{0x003F, 6},{0x0017, 5},
|
||||
{0x0075, 7},{0x01F5, 9},{0x07D1,11},{0x0017, 6},
|
||||
{0x01F6, 9},{0x0001, 3},{0x0000, 3},{0x001B, 5},
|
||||
{0x001A, 5},{0x000A, 5},{0x0032, 6},{0x0074, 7},
|
||||
{0x00F8, 8},{0x00F9, 8},{0x01F7, 9},{0x03E9,10},
|
||||
{0x0FA0,12},{0x1F43,13},{0x1F42,13},{0x0003, 3},
|
||||
{0x000A, 4},{0x001E, 5},{0x001C, 5},{0x003B, 6},
|
||||
{0x0018, 5},{0x0016, 6},{0x0016, 5},{0x0033, 6}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x0007, 4},{0x0018, 5},{0x001E, 5},
|
||||
{0x0036, 6},{0x0031, 7},{0x0177, 9},{0x0077, 7},
|
||||
{0x0176, 9},{0x0001, 3},{0x0000, 3},{0x001A, 5},
|
||||
{0x0019, 5},{0x003A, 6},{0x0019, 6},{0x005C, 7},
|
||||
{0x00BA, 8},{0x0061, 8},{0x00C1, 9},{0x0180,10},
|
||||
{0x0302,11},{0x0607,12},{0x0606,12},{0x0002, 3},
|
||||
{0x000A, 4},{0x001F, 5},{0x001C, 5},{0x0037, 6},
|
||||
{0x0016, 5},{0x0076, 7},{0x000D, 5},{0x002F, 6}
|
||||
},
|
||||
{
|
||||
{0x0000, 3},{0x000A, 4},{0x001A, 5},{0x000C, 4},
|
||||
{0x001D, 5},{0x0039, 6},{0x0078, 7},{0x005E, 7},
|
||||
{0x0393,11},{0x0002, 3},{0x0001, 3},{0x0016, 5},
|
||||
{0x000F, 5},{0x002E, 6},{0x005F, 7},{0x0073, 8},
|
||||
{0x00E5, 9},{0x01C8,10},{0x0E4A,13},{0x1C97,14},
|
||||
{0x1C96,14},{0x0E49,13},{0x0E48,13},{0x0004, 3},
|
||||
{0x0006, 4},{0x001F, 5},{0x001B, 5},{0x001D, 6},
|
||||
{0x0038, 6},{0x0038, 7},{0x003D, 6},{0x0079, 7}
|
||||
},
|
||||
{
|
||||
{0x000B, 5},{0x002B, 7},{0x0054, 8},{0x01B7, 9},
|
||||
{0x06D9,11},{0x0DB1,12},{0x0DB0,12},{0x0002, 4},
|
||||
{0x00AB, 9},{0x0009, 4},{0x000A, 4},{0x0007, 4},
|
||||
{0x0008, 4},{0x000F, 4},{0x000C, 4},{0x0003, 4},
|
||||
{0x001D, 5},{0x0004, 4},{0x000B, 4},{0x0006, 4},
|
||||
{0x001A, 5},{0x0003, 6},{0x00AA, 9},{0x0001, 4},
|
||||
{0x0000, 5},{0x0014, 6},{0x006C, 7},{0x00DA, 8},
|
||||
{0x0002, 6},{0x036D,10},{0x001C, 5},{0x0037, 6}
|
||||
},
|
||||
{
|
||||
{0x001D, 5},{0x0004, 6},{0x00B6, 8},{0x006A, 8},
|
||||
{0x05B9,11},{0x16E1,13},{0x16E0,13},{0x0007, 4},
|
||||
{0x016F, 9},{0x000C, 4},{0x000D, 4},{0x0009, 4},
|
||||
{0x0008, 4},{0x000F, 4},{0x000A, 4},{0x0003, 4},
|
||||
{0x0017, 5},{0x0002, 4},{0x0004, 4},{0x001C, 5},
|
||||
{0x002C, 6},{0x006B, 8},{0x0B71,12},{0x0005, 4},
|
||||
{0x0003, 5},{0x001B, 6},{0x005A, 7},{0x0034, 7},
|
||||
{0x0005, 6},{0x02DD,10},{0x0000, 4},{0x000C, 5}
|
||||
},
|
||||
{
|
||||
{0x0003, 4},{0x007F, 7},{0x00A1, 8},{0x00A0, 8},
|
||||
{0x020C,10},{0x0834,12},{0x106B,13},{0x0007, 4},
|
||||
{0x0082, 8},{0x000E, 4},{0x000D, 4},{0x000B, 4},
|
||||
{0x000C, 4},{0x0000, 3},{0x0009, 4},{0x0002, 4},
|
||||
{0x0011, 5},{0x001E, 5},{0x0015, 5},{0x003E, 6},
|
||||
{0x0040, 7},{0x041B,11},{0x106A,13},{0x0006, 4},
|
||||
{0x000A, 5},{0x0029, 6},{0x007E, 7},{0x0051, 7},
|
||||
{0x0021, 6},{0x0107, 9},{0x0004, 4},{0x000B, 5}
|
||||
},
|
||||
{
|
||||
{0x0007, 4},{0x001B, 6},{0x00F6, 8},{0x00E9, 8},
|
||||
{0x03A1,10},{0x0740,11},{0x0E82,12},{0x001F, 5},
|
||||
{0x01EF, 9},{0x0001, 3},{0x0002, 3},{0x000B, 4},
|
||||
{0x000C, 4},{0x000D, 4},{0x0008, 4},{0x001C, 5},
|
||||
{0x0003, 5},{0x0012, 5},{0x0002, 5},{0x0075, 7},
|
||||
{0x01D1, 9},{0x1D07,13},{0x1D06,13},{0x000A, 4},
|
||||
{0x0013, 5},{0x003B, 6},{0x001A, 6},{0x007A, 7},
|
||||
{0x003C, 6},{0x01EE, 9},{0x0000, 4},{0x000C, 5}
|
||||
},
|
||||
{
|
||||
{0x000D, 4},{0x003D, 6},{0x0042, 7},{0x0037, 7},
|
||||
{0x00D9, 9},{0x0362,11},{0x06C6,12},{0x001F, 5},
|
||||
{0x0086, 8},{0x0001, 3},{0x0002, 3},{0x000C, 4},
|
||||
{0x000B, 4},{0x000A, 4},{0x0001, 4},{0x000F, 5},
|
||||
{0x0025, 6},{0x003C, 6},{0x001A, 6},{0x0087, 8},
|
||||
{0x01B0,10},{0x0D8F,13},{0x0D8E,13},{0x000E, 4},
|
||||
{0x0013, 5},{0x000C, 5},{0x0024, 6},{0x0020, 6},
|
||||
{0x0011, 5},{0x006D, 8},{0x0000, 4},{0x000E, 5}
|
||||
},
|
||||
{
|
||||
{0x0000, 3},{0x0012, 5},{0x0076, 7},{0x0077, 7},
|
||||
{0x014D, 9},{0x0533,11},{0x14C9,13},{0x0013, 5},
|
||||
{0x00A5, 8},{0x0002, 3},{0x0003, 3},{0x000B, 4},
|
||||
{0x000C, 4},{0x0008, 4},{0x001A, 5},{0x002B, 6},
|
||||
{0x0075, 7},{0x0074, 7},{0x00A7, 8},{0x0298,10},
|
||||
{0x14C8,13},{0x14CB,13},{0x14CA,13},{0x000F, 4},
|
||||
{0x001C, 5},{0x0007, 5},{0x002A, 6},{0x0028, 6},
|
||||
{0x001B, 5},{0x00A4, 8},{0x0002, 4},{0x0006, 5}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x001A, 5},{0x002B, 6},{0x003A, 6},
|
||||
{0x00ED, 8},{0x0283,10},{0x0A0A,12},{0x0004, 5},
|
||||
{0x00A1, 8},{0x0004, 3},{0x0003, 3},{0x000B, 4},
|
||||
{0x000C, 4},{0x001F, 5},{0x0006, 5},{0x0077, 7},
|
||||
{0x00A3, 8},{0x00A2, 8},{0x0140, 9},{0x1417,13},
|
||||
{0x1416,13},{0x0A09,12},{0x0A08,12},{0x0000, 3},
|
||||
{0x001E, 5},{0x0007, 5},{0x002A, 6},{0x0029, 6},
|
||||
{0x001C, 5},{0x00EC, 8},{0x001B, 5},{0x0005, 5}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x0002, 4},{0x0018, 5},{0x001D, 5},
|
||||
{0x0035, 6},{0x00E4, 8},{0x01CF,11},{0x001D, 7},
|
||||
{0x0072, 9},{0x0004, 3},{0x0005, 3},{0x0006, 4},
|
||||
{0x0007, 4},{0x0006, 5},{0x0073, 7},{0x0038, 8},
|
||||
{0x01CE,11},{0x039B,12},{0x0398,12},{0x0733,13},
|
||||
{0x0732,13},{0x0735,13},{0x0734,13},{0x0000, 3},
|
||||
{0x001F, 5},{0x001B, 5},{0x0034, 6},{0x000F, 6},
|
||||
{0x001E, 5},{0x00E5, 8},{0x0019, 5},{0x0038, 6}
|
||||
},
|
||||
{
|
||||
{0x0016, 5},{0x0050, 7},{0x0172, 9},{0x02E7,10},
|
||||
{0x1732,13},{0x2E67,14},{0x2E66,14},{0x0006, 4},
|
||||
{0x0051, 7},{0x0001, 3},{0x0000, 3},{0x000D, 4},
|
||||
{0x000C, 4},{0x0009, 4},{0x001C, 5},{0x0009, 5},
|
||||
{0x001C, 6},{0x001D, 6},{0x005D, 7},{0x00B8, 8},
|
||||
{0x05CD,11},{0x1731,13},{0x1730,13},{0x000F, 4},
|
||||
{0x0005, 4},{0x000F, 5},{0x0008, 5},{0x0029, 6},
|
||||
{0x001D, 5},{0x002F, 6},{0x0008, 4},{0x0015, 5}
|
||||
},
|
||||
{
|
||||
{0x0009, 4},{0x0021, 6},{0x0040, 7},{0x00AD, 8},
|
||||
{0x02B0,10},{0x1589,13},{0x1588,13},{0x001C, 5},
|
||||
{0x005F, 7},{0x0000, 3},{0x000F, 4},{0x000D, 4},
|
||||
{0x000C, 4},{0x0006, 4},{0x0011, 5},{0x002A, 6},
|
||||
{0x0057, 7},{0x005E, 7},{0x0041, 7},{0x0159, 9},
|
||||
{0x0563,11},{0x158B,13},{0x158A,13},{0x0001, 3},
|
||||
{0x0005, 4},{0x0014, 5},{0x003B, 6},{0x002E, 6},
|
||||
{0x0004, 4},{0x003A, 6},{0x0007, 4},{0x0016, 5}
|
||||
},
|
||||
{
|
||||
{0x000E, 4},{0x0007, 5},{0x0046, 7},{0x0045, 7},
|
||||
{0x0064, 9},{0x032A,12},{0x0657,13},{0x0018, 5},
|
||||
{0x000D, 6},{0x0000, 3},{0x000F, 4},{0x000A, 4},
|
||||
{0x000B, 4},{0x001A, 5},{0x0036, 6},{0x0047, 7},
|
||||
{0x0044, 7},{0x0018, 7},{0x0033, 8},{0x00CB,10},
|
||||
{0x0656,13},{0x0329,12},{0x0328,12},{0x0002, 3},
|
||||
{0x0006, 4},{0x0019, 5},{0x000E, 5},{0x0037, 6},
|
||||
{0x0009, 4},{0x000F, 5},{0x0002, 4},{0x0010, 5}
|
||||
},
|
||||
{
|
||||
{0x0003, 3},{0x0018, 5},{0x0023, 6},{0x0077, 7},
|
||||
{0x0194, 9},{0x1956,13},{0x32AF,14},{0x003A, 6},
|
||||
{0x0076, 7},{0x0002, 3},{0x0001, 3},{0x001F, 5},
|
||||
{0x001E, 5},{0x0014, 5},{0x0022, 6},{0x0064, 7},
|
||||
{0x0197, 9},{0x0196, 9},{0x032B,10},{0x0654,11},
|
||||
{0x32AE,14},{0x1955,13},{0x1954,13},{0x0000, 3},
|
||||
{0x0009, 4},{0x001C, 5},{0x0015, 5},{0x0010, 5},
|
||||
{0x000D, 4},{0x0017, 5},{0x0016, 5},{0x0033, 6}
|
||||
},
|
||||
{
|
||||
{0x0005, 3},{0x0006, 4},{0x003E, 6},{0x0010, 5},
|
||||
{0x0048, 7},{0x093F,12},{0x24FA,14},{0x0032, 6},
|
||||
{0x0067, 7},{0x0002, 3},{0x0001, 3},{0x001B, 5},
|
||||
{0x001E, 5},{0x0034, 6},{0x0066, 7},{0x0092, 8},
|
||||
{0x0126, 9},{0x024E,10},{0x049E,11},{0x49F7,15},
|
||||
{0x49F6,15},{0x24F9,14},{0x24F8,14},{0x0000, 3},
|
||||
{0x0007, 4},{0x0018, 5},{0x0011, 5},{0x003F, 6},
|
||||
{0x000E, 4},{0x0013, 5},{0x0035, 6},{0x0025, 6}
|
||||
},
|
||||
{
|
||||
{0x0005, 3},{0x0008, 4},{0x0012, 5},{0x001C, 5},
|
||||
{0x001C, 6},{0x00EA, 9},{0x1D75,14},{0x001E, 6},
|
||||
{0x0066, 7},{0x0001, 3},{0x0002, 3},{0x001B, 5},
|
||||
{0x001A, 5},{0x001F, 6},{0x003B, 7},{0x0074, 8},
|
||||
{0x01D6,10},{0x03AF,11},{0x1D74,14},{0x1D77,14},
|
||||
{0x1D76,14},{0x0EB9,13},{0x0EB8,13},{0x000F, 4},
|
||||
{0x0006, 4},{0x0013, 5},{0x003B, 6},{0x003A, 6},
|
||||
{0x0000, 3},{0x0018, 5},{0x0032, 6},{0x0067, 7}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x000A, 4},{0x001B, 5},{0x000C, 4},
|
||||
{0x000D, 5},{0x00E6, 8},{0x0684,11},{0x0072, 7},
|
||||
{0x00E7, 8},{0x0002, 3},{0x0001, 3},{0x0017, 5},
|
||||
{0x0016, 5},{0x0018, 6},{0x00D1, 8},{0x01A0, 9},
|
||||
{0x0686,11},{0x0D0F,12},{0x0D0A,12},{0x1A17,13},
|
||||
{0x1A16,13},{0x1A1D,13},{0x1A1C,13},{0x000F, 4},
|
||||
{0x001D, 5},{0x000E, 5},{0x0035, 6},{0x0038, 6},
|
||||
{0x0000, 3},{0x000F, 5},{0x0019, 6},{0x0069, 7}
|
||||
},
|
||||
{
|
||||
{0x0003, 3},{0x000C, 4},{0x001B, 5},{0x0000, 3},
|
||||
{0x0003, 4},{0x002E, 6},{0x0051, 9},{0x00BC, 8},
|
||||
{0x0053, 9},{0x0004, 3},{0x0002, 3},{0x0016, 5},
|
||||
{0x0015, 5},{0x0015, 7},{0x0050, 9},{0x00A4,10},
|
||||
{0x0294,12},{0x052B,13},{0x052A,13},{0x052D,13},
|
||||
{0x052C,13},{0x052F,13},{0x052E,13},{0x000E, 4},
|
||||
{0x001A, 5},{0x0004, 5},{0x0028, 6},{0x0029, 6},
|
||||
{0x000F, 4},{0x000B, 6},{0x005F, 7},{0x00BD, 8}
|
||||
},
|
||||
{
|
||||
{0x0003, 4},{0x0009, 6},{0x00D0, 8},{0x01A3, 9},
|
||||
{0x0344,10},{0x0D14,12},{0x1A2B,13},{0x0004, 4},
|
||||
{0x0015, 7},{0x0000, 3},{0x000F, 4},{0x000B, 4},
|
||||
{0x000C, 4},{0x000E, 4},{0x0009, 4},{0x001B, 5},
|
||||
{0x000A, 5},{0x0014, 5},{0x000D, 5},{0x002A, 6},
|
||||
{0x0014, 7},{0x068B,11},{0x1A2A,13},{0x0008, 4},
|
||||
{0x000B, 5},{0x002B, 6},{0x000B, 6},{0x0069, 7},
|
||||
{0x0035, 6},{0x0008, 6},{0x0007, 4},{0x000C, 5}
|
||||
},
|
||||
{
|
||||
{0x000A, 4},{0x003C, 6},{0x0032, 7},{0x0030, 7},
|
||||
{0x00C5, 9},{0x0621,12},{0x0620,12},{0x001F, 5},
|
||||
{0x0033, 7},{0x0001, 3},{0x0000, 3},{0x000E, 4},
|
||||
{0x000D, 4},{0x000C, 4},{0x0004, 4},{0x000D, 5},
|
||||
{0x0026, 6},{0x0027, 6},{0x0014, 6},{0x0063, 8},
|
||||
{0x0189,10},{0x0623,12},{0x0622,12},{0x000B, 4},
|
||||
{0x0012, 5},{0x003D, 6},{0x0022, 6},{0x0015, 6},
|
||||
{0x000B, 5},{0x0023, 6},{0x0007, 4},{0x0010, 5}
|
||||
},
|
||||
{
|
||||
{0x000F, 4},{0x000C, 5},{0x0043, 7},{0x0010, 6},
|
||||
{0x0044, 8},{0x0114,10},{0x0455,12},{0x0018, 5},
|
||||
{0x0023, 7},{0x0001, 3},{0x0000, 3},{0x000E, 4},
|
||||
{0x000D, 4},{0x0009, 4},{0x0019, 5},{0x0009, 5},
|
||||
{0x0017, 6},{0x0016, 6},{0x0042, 7},{0x008B, 9},
|
||||
{0x0454,12},{0x0457,12},{0x0456,12},{0x000B, 4},
|
||||
{0x0015, 5},{0x000A, 5},{0x0029, 6},{0x0020, 6},
|
||||
{0x000D, 5},{0x0028, 6},{0x0007, 4},{0x0011, 5}
|
||||
},
|
||||
{
|
||||
{0x0001, 3},{0x001A, 5},{0x0029, 6},{0x002A, 6},
|
||||
{0x00A0, 8},{0x0285,10},{0x1425,13},{0x0002, 5},
|
||||
{0x0000, 7},{0x0002, 3},{0x0003, 3},{0x000C, 4},
|
||||
{0x000B, 4},{0x0008, 4},{0x0012, 5},{0x0001, 6},
|
||||
{0x0051, 7},{0x0001, 7},{0x0143, 9},{0x0508,11},
|
||||
{0x1424,13},{0x1427,13},{0x1426,13},{0x000F, 4},
|
||||
{0x001C, 5},{0x0003, 5},{0x0037, 6},{0x002B, 6},
|
||||
{0x0013, 5},{0x0036, 6},{0x001D, 5},{0x0001, 5}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x001F, 5},{0x003D, 6},{0x0006, 5},
|
||||
{0x0016, 7},{0x0053, 9},{0x014A,11},{0x0034, 6},
|
||||
{0x002A, 8},{0x0002, 3},{0x0003, 3},{0x000B, 4},
|
||||
{0x000C, 4},{0x001C, 5},{0x0037, 6},{0x0017, 7},
|
||||
{0x002B, 8},{0x0028, 8},{0x00A4,10},{0x052D,13},
|
||||
{0x052C,13},{0x052F,13},{0x052E,13},{0x0000, 3},
|
||||
{0x001D, 5},{0x0007, 5},{0x0004, 5},{0x0035, 6},
|
||||
{0x0014, 5},{0x0036, 6},{0x0015, 5},{0x003C, 6}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x000A, 4},{0x0007, 5},{0x001D, 5},
|
||||
{0x0009, 6},{0x01F3, 9},{0x07C7,11},{0x0008, 6},
|
||||
{0x01F0, 9},{0x0003, 3},{0x0002, 3},{0x000D, 4},
|
||||
{0x000C, 4},{0x0017, 5},{0x007D, 7},{0x01F2, 9},
|
||||
{0x07C6,11},{0x07C5,11},{0x1F12,13},{0x3E27,14},
|
||||
{0x3E26,14},{0x1F11,13},{0x1F10,13},{0x0000, 3},
|
||||
{0x001E, 5},{0x0006, 5},{0x0039, 6},{0x0038, 6},
|
||||
{0x003F, 6},{0x002C, 6},{0x0005, 5},{0x002D, 6}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x0007, 4},{0x0018, 5},{0x0003, 4},
|
||||
{0x0005, 5},{0x0035, 7},{0x004F, 9},{0x0012, 7},
|
||||
{0x04E5,13},{0x0005, 3},{0x0004, 3},{0x000D, 4},
|
||||
{0x000E, 4},{0x0033, 6},{0x0026, 8},{0x009D,10},
|
||||
{0x04E4,13},{0x04E7,13},{0x04E6,13},{0x04E1,13},
|
||||
{0x04E0,13},{0x04E3,13},{0x04E2,13},{0x0000, 3},
|
||||
{0x001F, 5},{0x000C, 5},{0x003D, 6},{0x003C, 6},
|
||||
{0x0032, 6},{0x0034, 7},{0x001B, 6},{0x0008, 6}
|
||||
},
|
||||
{
|
||||
{0x0000, 3},{0x0004, 4},{0x001C, 5},{0x000F, 4},
|
||||
{0x0002, 4},{0x0007, 5},{0x0075, 7},{0x00E8, 8},
|
||||
{0x1D2A,13},{0x0005, 3},{0x0004, 3},{0x000D, 4},
|
||||
{0x000C, 4},{0x0077, 7},{0x0E96,12},{0x3A57,14},
|
||||
{0x3A56,14},{0x3A5D,14},{0x3A5C,14},{0x3A5F,14},
|
||||
{0x3A5E,14},{0x1D29,13},{0x1D28,13},{0x0003, 3},
|
||||
{0x0006, 5},{0x000A, 5},{0x002C, 7},{0x0017, 6},
|
||||
{0x0076, 7},{0x01D3, 9},{0x03A4,10},{0x002D, 7}
|
||||
},
|
||||
{
|
||||
{0x000A, 4},{0x0024, 6},{0x00BF, 8},{0x0085, 8},
|
||||
{0x0211,10},{0x0842,12},{0x1087,13},{0x0018, 5},
|
||||
{0x0020, 6},{0x0001, 3},{0x0002, 3},{0x000E, 4},
|
||||
{0x000D, 4},{0x0007, 4},{0x0013, 5},{0x0025, 6},
|
||||
{0x005E, 7},{0x0043, 7},{0x00BE, 8},{0x0109, 9},
|
||||
{0x1086,13},{0x0841,12},{0x0840,12},{0x000F, 4},
|
||||
{0x0001, 4},{0x0011, 5},{0x0000, 5},{0x002E, 6},
|
||||
{0x0019, 5},{0x0001, 5},{0x0006, 4},{0x0016, 5}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x000F, 5},{0x006F, 7},{0x0061, 7},
|
||||
{0x0374,10},{0x1BA8,13},{0x3753,14},{0x0012, 5},
|
||||
{0x0036, 6},{0x0000, 3},{0x0001, 3},{0x000A, 4},
|
||||
{0x000B, 4},{0x001A, 5},{0x0031, 6},{0x0060, 7},
|
||||
{0x00DC, 8},{0x01BB, 9},{0x06EB,11},{0x1BAB,13},
|
||||
{0x3752,14},{0x3755,14},{0x3754,14},{0x000E, 4},
|
||||
{0x0006, 4},{0x0013, 5},{0x000E, 5},{0x003E, 6},
|
||||
{0x0008, 4},{0x001E, 5},{0x0019, 5},{0x003F, 6}
|
||||
},
|
||||
{
|
||||
{0x0003, 3},{0x001C, 5},{0x0025, 6},{0x0024, 6},
|
||||
{0x01DA, 9},{0x1DBD,13},{0x3B7C,14},{0x003C, 6},
|
||||
{0x003D, 6},{0x0000, 3},{0x0001, 3},{0x000B, 4},
|
||||
{0x000A, 4},{0x000B, 5},{0x0077, 7},{0x00EC, 8},
|
||||
{0x03B6,10},{0x076E,11},{0x1DBF,13},{0x76FB,15},
|
||||
{0x76FA,15},{0x3B79,14},{0x3B78,14},{0x000D, 4},
|
||||
{0x001F, 5},{0x0013, 5},{0x000A, 5},{0x0008, 5},
|
||||
{0x000C, 4},{0x0008, 4},{0x0009, 5},{0x003A, 6}
|
||||
},
|
||||
{
|
||||
{0x0005, 3},{0x0003, 4},{0x0004, 5},{0x0010, 5},
|
||||
{0x008F, 8},{0x0475,11},{0x11D1,13},{0x0079, 7},
|
||||
{0x0027, 6},{0x0002, 3},{0x0003, 3},{0x0001, 4},
|
||||
{0x0000, 4},{0x0026, 6},{0x0046, 7},{0x011C, 9},
|
||||
{0x0477,11},{0x08ED,12},{0x11D0,13},{0x11D3,13},
|
||||
{0x11D2,13},{0x11D9,13},{0x11D8,13},{0x000D, 4},
|
||||
{0x001F, 5},{0x0012, 5},{0x0005, 5},{0x003D, 6},
|
||||
{0x000C, 4},{0x000E, 4},{0x0022, 6},{0x0078, 7}
|
||||
},
|
||||
{
|
||||
{0x0005, 3},{0x000C, 4},{0x001B, 5},{0x0000, 4},
|
||||
{0x0006, 6},{0x03E2,10},{0x3E3D,14},{0x000F, 7},
|
||||
{0x0034, 6},{0x0003, 3},{0x0002, 3},{0x001E, 5},
|
||||
{0x001D, 5},{0x007D, 7},{0x01F0, 9},{0x07C6,11},
|
||||
{0x3E3C,14},{0x3E3F,14},{0x3E3E,14},{0x3E39,14},
|
||||
{0x3E38,14},{0x3E3B,14},{0x3E3A,14},{0x0008, 4},
|
||||
{0x001C, 5},{0x0002, 5},{0x003F, 6},{0x0035, 6},
|
||||
{0x0009, 4},{0x0001, 3},{0x000E, 7},{0x00F9, 8}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x000B, 4},{0x0001, 4},{0x000A, 4},
|
||||
{0x001E, 6},{0x00E0, 9},{0x0E1E,13},{0x0071, 8},
|
||||
{0x0039, 7},{0x0007, 3},{0x0006, 3},{0x000D, 5},
|
||||
{0x000C, 5},{0x0020, 7},{0x01C2,10},{0x1C3F,14},
|
||||
{0x1C3E,14},{0x0E19,13},{0x0E18,13},{0x0E1B,13},
|
||||
{0x0E1A,13},{0x0E1D,13},{0x0E1C,13},{0x0000, 4},
|
||||
{0x0009, 5},{0x001D, 6},{0x001F, 6},{0x0011, 6},
|
||||
{0x0005, 4},{0x0001, 3},{0x0043, 8},{0x0042, 8}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x000D, 4},{0x0007, 4},{0x0002, 3},
|
||||
{0x0014, 5},{0x016C, 9},{0x16D1,13},{0x02DF,10},
|
||||
{0x016E, 9},{0x0000, 2},{0x0007, 3},{0x002C, 6},
|
||||
{0x002B, 6},{0x02DE,10},{0x16D0,13},{0x16D3,13},
|
||||
{0x16D2,13},{0x2DB5,14},{0x2DB4,14},{0x2DB7,14},
|
||||
{0x2DB6,14},{0x16D9,13},{0x16D8,13},{0x000C, 5},
|
||||
{0x002A, 6},{0x005A, 7},{0x001B, 6},{0x001A, 6},
|
||||
{0x0017, 5},{0x000C, 4},{0x05B7,11},{0x05B5,11}
|
||||
},
|
||||
{
|
||||
{0x0002, 2},{0x000F, 4},{0x001C, 5},{0x000C, 4},
|
||||
{0x003B, 6},{0x01AC, 9},{0x1AD8,13},{0x35B3,14},
|
||||
{0x35B2,14},{0x0001, 2},{0x0000, 2},{0x0069, 7},
|
||||
{0x0068, 7},{0x35BD,14},{0x35BC,14},{0x35BF,14},
|
||||
{0x35BE,14},{0x35B9,14},{0x35B8,14},{0x35BB,14},
|
||||
{0x35BA,14},{0x35B5,14},{0x35B4,14},{0x01A9, 9},
|
||||
{0x01A8, 9},{0x035A,10},{0x00D7, 8},{0x00D5, 8},
|
||||
{0x003A, 6},{0x001B, 5},{0x35B7,14},{0x35B6,14}
|
||||
},
|
||||
{
|
||||
{0x0000, 3},{0x0010, 5},{0x0072, 7},{0x0071, 7},
|
||||
{0x0154, 9},{0x0AAB,12},{0x0AA8,12},{0x0014, 5},
|
||||
{0x0070, 7},{0x0002, 3},{0x0003, 3},{0x000C, 4},
|
||||
{0x000B, 4},{0x0003, 4},{0x0011, 5},{0x0073, 7},
|
||||
{0x0054, 7},{0x00AB, 8},{0x02AB,10},{0x1553,13},
|
||||
{0x1552,13},{0x1555,13},{0x1554,13},{0x000D, 4},
|
||||
{0x001E, 5},{0x0012, 5},{0x003E, 6},{0x002B, 6},
|
||||
{0x0002, 4},{0x003F, 6},{0x001D, 5},{0x0013, 5}
|
||||
},
|
||||
{
|
||||
{0x0003, 3},{0x001F, 5},{0x0029, 6},{0x003D, 6},
|
||||
{0x000C, 7},{0x0069,10},{0x0345,13},{0x0002, 5},
|
||||
{0x0028, 6},{0x0002, 3},{0x0001, 3},{0x000E, 4},
|
||||
{0x000C, 4},{0x0015, 5},{0x0007, 6},{0x001B, 8},
|
||||
{0x006B,10},{0x006A,10},{0x0344,13},{0x0347,13},
|
||||
{0x0346,13},{0x01A1,12},{0x01A0,12},{0x000B, 4},
|
||||
{0x001A, 5},{0x0012, 5},{0x0000, 5},{0x003C, 6},
|
||||
{0x0008, 4},{0x001B, 5},{0x0013, 5},{0x0001, 5}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x0004, 4},{0x003F, 6},{0x0014, 5},
|
||||
{0x0056, 7},{0x015C, 9},{0x15D5,13},{0x003C, 6},
|
||||
{0x002A, 6},{0x0000, 3},{0x0001, 3},{0x000E, 4},
|
||||
{0x000D, 4},{0x000C, 5},{0x00AF, 8},{0x02BB,10},
|
||||
{0x15D4,13},{0x15D7,13},{0x15D6,13},{0x15D1,13},
|
||||
{0x15D0,13},{0x15D3,13},{0x15D2,13},{0x000B, 4},
|
||||
{0x0019, 5},{0x000D, 5},{0x003E, 6},{0x0031, 6},
|
||||
{0x0007, 4},{0x0005, 4},{0x003D, 6},{0x0030, 6}
|
||||
},
|
||||
{
|
||||
{0x0005, 3},{0x0008, 4},{0x001A, 5},{0x0000, 4},
|
||||
{0x0036, 6},{0x0011, 8},{0x0106,12},{0x000A, 7},
|
||||
{0x006E, 7},{0x0002, 3},{0x0003, 3},{0x0003, 4},
|
||||
{0x0002, 4},{0x006F, 7},{0x0021, 9},{0x020F,13},
|
||||
{0x020E,13},{0x0101,12},{0x0100,12},{0x0103,12},
|
||||
{0x0102,12},{0x0105,12},{0x0104,12},{0x000C, 4},
|
||||
{0x001E, 5},{0x0003, 5},{0x003E, 6},{0x003F, 6},
|
||||
{0x0009, 4},{0x000E, 4},{0x000B, 7},{0x0009, 7}
|
||||
},
|
||||
{
|
||||
{0x0002, 3},{0x000E, 4},{0x001E, 5},{0x000C, 4},
|
||||
{0x001F, 5},{0x006E, 7},{0x00AD,10},{0x00AF,10},
|
||||
{0x0014, 7},{0x0004, 3},{0x0003, 3},{0x001A, 5},
|
||||
{0x0017, 5},{0x002A, 8},{0x0576,13},{0x0AEF,14},
|
||||
{0x0AEE,14},{0x0571,13},{0x0570,13},{0x0573,13},
|
||||
{0x0572,13},{0x0575,13},{0x0574,13},{0x0003, 4},
|
||||
{0x0016, 5},{0x0004, 5},{0x0036, 6},{0x000B, 6},
|
||||
{0x000A, 4},{0x0000, 3},{0x006F, 7},{0x00AC,10}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x0005, 4},{0x0003, 3},{0x0001, 3},
|
||||
{0x0004, 4},{0x002F, 6},{0x0526,11},{0x1495,13},
|
||||
{0x00A6, 8},{0x0007, 3},{0x0006, 3},{0x002D, 6},
|
||||
{0x002C, 6},{0x1494,13},{0x1497,13},{0x1496,13},
|
||||
{0x1491,13},{0x1490,13},{0x1493,13},{0x1492,13},
|
||||
{0x293D,14},{0x293C,14},{0x293F,14},{0x0000, 3},
|
||||
{0x0028, 6},{0x00A5, 8},{0x0148, 9},{0x00A7, 8},
|
||||
{0x002E, 6},{0x0015, 5},{0x0A4E,12},{0x293E,14}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x0005, 4},{0x0003, 3},{0x0001, 3},
|
||||
{0x0004, 4},{0x002F, 6},{0x0526,11},{0x1495,13},
|
||||
{0x00A6, 8},{0x0007, 3},{0x0006, 3},{0x002D, 6},
|
||||
{0x002C, 6},{0x1494,13},{0x1497,13},{0x1496,13},
|
||||
{0x1491,13},{0x1490,13},{0x1493,13},{0x1492,13},
|
||||
{0x293D,14},{0x293C,14},{0x293F,14},{0x0000, 3},
|
||||
{0x0028, 6},{0x00A5, 8},{0x0148, 9},{0x00A7, 8},
|
||||
{0x002E, 6},{0x0015, 5},{0x0A4E,12},{0x293E,14}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x0005, 4},{0x0003, 3},{0x0001, 3},
|
||||
{0x0004, 4},{0x002F, 6},{0x0526,11},{0x1495,13},
|
||||
{0x00A6, 8},{0x0007, 3},{0x0006, 3},{0x002D, 6},
|
||||
{0x002C, 6},{0x1494,13},{0x1497,13},{0x1496,13},
|
||||
{0x1491,13},{0x1490,13},{0x1493,13},{0x1492,13},
|
||||
{0x293D,14},{0x293C,14},{0x293F,14},{0x0000, 3},
|
||||
{0x0028, 6},{0x00A5, 8},{0x0148, 9},{0x00A7, 8},
|
||||
{0x002E, 6},{0x0015, 5},{0x0A4E,12},{0x293E,14}
|
||||
},
|
||||
{
|
||||
{0x0003, 3},{0x0011, 5},{0x0020, 6},{0x0074, 7},
|
||||
{0x010D, 9},{0x0863,12},{0x0860,12},{0x000A, 5},
|
||||
{0x0075, 7},{0x0001, 3},{0x0000, 3},{0x000B, 4},
|
||||
{0x000A, 4},{0x0018, 5},{0x0038, 6},{0x0042, 7},
|
||||
{0x010F, 9},{0x010E, 9},{0x0219,10},{0x10C3,13},
|
||||
{0x10C2,13},{0x10C5,13},{0x10C4,13},{0x000F, 4},
|
||||
{0x0004, 4},{0x0019, 5},{0x000B, 5},{0x0039, 6},
|
||||
{0x0009, 4},{0x001B, 5},{0x001A, 5},{0x003B, 6}
|
||||
},
|
||||
{
|
||||
{0x0005, 3},{0x0001, 4},{0x003E, 6},{0x0001, 5},
|
||||
{0x00E2, 8},{0x1C6F,13},{0x38D9,14},{0x0039, 6},
|
||||
{0x001F, 6},{0x0002, 3},{0x0001, 3},{0x0009, 4},
|
||||
{0x0008, 4},{0x0000, 5},{0x0070, 7},{0x01C7, 9},
|
||||
{0x038C,10},{0x071A,11},{0x38D8,14},{0x38DB,14},
|
||||
{0x38DA,14},{0x38DD,14},{0x38DC,14},{0x000D, 4},
|
||||
{0x001D, 5},{0x000E, 5},{0x003F, 6},{0x003C, 6},
|
||||
{0x000C, 4},{0x0006, 4},{0x003D, 6},{0x001E, 6}
|
||||
},
|
||||
{
|
||||
{0x0006, 3},{0x000B, 4},{0x0011, 5},{0x001E, 5},
|
||||
{0x0074, 7},{0x03AA,10},{0x1D5C,13},{0x0001, 6},
|
||||
{0x0021, 6},{0x0001, 3},{0x0002, 3},{0x0007, 4},
|
||||
{0x0006, 4},{0x003E, 6},{0x00EB, 8},{0x01D4, 9},
|
||||
{0x0EAF,12},{0x3ABB,14},{0x3ABA,14},{0x1D59,13},
|
||||
{0x1D58,13},{0x1D5B,13},{0x1D5A,13},{0x000A, 4},
|
||||
{0x001C, 5},{0x0001, 5},{0x003F, 6},{0x003B, 6},
|
||||
{0x0001, 4},{0x0009, 4},{0x0020, 6},{0x0000, 6}
|
||||
},
|
||||
{
|
||||
{0x0004, 3},{0x000A, 4},{0x0017, 5},{0x0004, 4},
|
||||
{0x0016, 6},{0x016A, 9},{0x16B1,13},{0x0017, 7},
|
||||
{0x005B, 7},{0x0006, 3},{0x0007, 3},{0x0001, 4},
|
||||
{0x0000, 4},{0x000A, 6},{0x02D7,10},{0x0B5A,12},
|
||||
{0x16B0,13},{0x16B3,13},{0x16B2,13},{0x2D6D,14},
|
||||
{0x2D6C,14},{0x2D6F,14},{0x2D6E,14},{0x0006, 4},
|
||||
{0x000A, 5},{0x0004, 5},{0x002C, 6},{0x0017, 6},
|
||||
{0x0003, 4},{0x0007, 4},{0x0016, 7},{0x00B4, 8}
|
||||
},
|
||||
{
|
||||
{0x0005, 3},{0x000D, 4},{0x0005, 4},{0x0009, 4},
|
||||
{0x0033, 6},{0x0193, 9},{0x192C,13},{0x0061, 8},
|
||||
{0x0031, 7},{0x0000, 2},{0x0007, 3},{0x0010, 5},
|
||||
{0x0011, 5},{0x00C8, 8},{0x192F,13},{0x325B,14},
|
||||
{0x325A,14},{0x1929,13},{0x1928,13},{0x192B,13},
|
||||
{0x192A,13},{0x325D,14},{0x325C,14},{0x0018, 5},
|
||||
{0x001A, 6},{0x001B, 6},{0x0065, 7},{0x0019, 6},
|
||||
{0x0004, 4},{0x0007, 4},{0x0060, 8},{0x0324,10}
|
||||
},
|
||||
{
|
||||
{0x0006, 3},{0x0000, 3},{0x0002, 4},{0x000F, 4},
|
||||
{0x0039, 6},{0x01D9, 9},{0x1D82,13},{0x0761,11},
|
||||
{0x03BE,10},{0x0001, 2},{0x0002, 2},{0x000F, 6},
|
||||
{0x000E, 6},{0x0762,11},{0x3B07,14},{0x3B06,14},
|
||||
{0x3B1D,14},{0x3B1C,14},{0x3B1F,14},{0x3B1E,14},
|
||||
{0x3B19,14},{0x3B18,14},{0x3B1B,14},{0x0038, 6},
|
||||
{0x01DE, 9},{0x00ED, 8},{0x03BF,10},{0x00EE, 8},
|
||||
{0x003A, 6},{0x0006, 5},{0x0EC0,12},{0x3B1A,14}
|
||||
},
|
||||
{
|
||||
{0x0000, 2},{0x0002, 3},{0x000F, 5},{0x0006, 4},
|
||||
{0x001C, 6},{0x01D0,10},{0x0E8C,13},{0x1D1B,14},
|
||||
{0x1D1A,14},{0x0003, 2},{0x0002, 2},{0x00EA, 9},
|
||||
{0x00E9, 9},{0x0E89,13},{0x0E88,13},{0x0E8B,13},
|
||||
{0x0E8A,13},{0x1D65,14},{0x1D64,14},{0x1D67,14},
|
||||
{0x1D66,14},{0x1D61,14},{0x1D60,14},{0x03AD,11},
|
||||
{0x1D63,14},{0x1D62,14},{0x1D1D,14},{0x1D1C,14},
|
||||
{0x003B, 7},{0x01D7,10},{0x1D1F,14},{0x1D1E,14}
|
||||
},
|
||||
{
|
||||
{0x0002, 2},{0x000F, 4},{0x001C, 5},{0x000C, 4},
|
||||
{0x003B, 6},{0x01AC, 9},{0x1AD8,13},{0x35B3,14},
|
||||
{0x35B2,14},{0x0001, 2},{0x0000, 2},{0x0069, 7},
|
||||
{0x0068, 7},{0x35BD,14},{0x35BC,14},{0x35BF,14},
|
||||
{0x35BE,14},{0x35B9,14},{0x35B8,14},{0x35BB,14},
|
||||
{0x35BA,14},{0x35B5,14},{0x35B4,14},{0x01A9, 9},
|
||||
{0x01A8, 9},{0x035A,10},{0x00D7, 8},{0x00D5, 8},
|
||||
{0x003A, 6},{0x001B, 5},{0x35B7,14},{0x35B6,14}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*A description of a Huffman code value used when encoding the tree.*/
|
||||
typedef struct{
|
||||
/*The bit pattern, left-shifted so that the MSB of all patterns is
|
||||
aligned.*/
|
||||
ogg_uint32_t pattern;
|
||||
/*The amount the bit pattern was shifted.*/
|
||||
int shift;
|
||||
/*The token this bit pattern represents.*/
|
||||
int token;
|
||||
}oc_huff_entry;
|
||||
|
||||
|
||||
|
||||
/*Compares two oc_huff_entry structures by their bit patterns.
|
||||
_c1: The first entry to compare.
|
||||
_c2: The second entry to compare.
|
||||
Return: <0 if _c1<_c2, >0 if _c1>_c2.*/
|
||||
static int huff_entry_cmp(const void *_c1,const void *_c2){
|
||||
ogg_uint32_t b1;
|
||||
ogg_uint32_t b2;
|
||||
b1=((const oc_huff_entry *)_c1)->pattern;
|
||||
b2=((const oc_huff_entry *)_c2)->pattern;
|
||||
return b1<b2?-1:b1>b2?1:0;
|
||||
}
|
||||
|
||||
/*Encodes a description of the given Huffman tables.
|
||||
Although the codes are stored in the encoder as flat arrays, in the bit
|
||||
stream and in the decoder they are structured as a tree.
|
||||
This function recovers the tree structure from the flat array and then
|
||||
writes it out.
|
||||
Note that the codes MUST form a Huffman code, and not merely a prefix-free
|
||||
code, since the binary tree is assumed to be full.
|
||||
_opb: The buffer to store the tree in.
|
||||
_codes: The Huffman tables to pack.
|
||||
Return: 0 on success, or a negative value if one of the given Huffman tables
|
||||
does not form a full, prefix-free code.*/
|
||||
int oc_huff_codes_pack(oggpack_buffer *_opb,
|
||||
const th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS]){
|
||||
int i;
|
||||
for(i=0;i<TH_NHUFFMAN_TABLES;i++){
|
||||
oc_huff_entry entries[TH_NDCT_TOKENS];
|
||||
int bpos;
|
||||
int maxlen;
|
||||
int mask;
|
||||
int j;
|
||||
/*First, find the maximum code length so we can align all the bit
|
||||
patterns.*/
|
||||
maxlen=_codes[i][0].nbits;
|
||||
for(j=1;j<TH_NDCT_TOKENS;j++)maxlen=OC_MAXI(_codes[i][j].nbits,maxlen);
|
||||
/*It's improbable that a code with more than 32 bits could pass the
|
||||
validation below, but abort early in any case.*/
|
||||
if(maxlen>32)return TH_EINVAL;
|
||||
mask=(1<<(maxlen>>1)<<(maxlen+1>>1))-1;
|
||||
/*Copy over the codes into our temporary workspace.
|
||||
The bit patterns are aligned, and the original entry each code is from
|
||||
is stored as well.*/
|
||||
for(j=0;j<TH_NDCT_TOKENS;j++){
|
||||
entries[j].shift=maxlen-_codes[i][j].nbits;
|
||||
entries[j].pattern=_codes[i][j].pattern<<entries[j].shift&mask;
|
||||
entries[j].token=j;
|
||||
}
|
||||
/*Sort the codes into ascending order.
|
||||
This is the order the leaves of the tree will be traversed.*/
|
||||
qsort(entries,TH_NDCT_TOKENS,sizeof(entries[0]),huff_entry_cmp);
|
||||
/*For each leaf of the tree:*/
|
||||
bpos=maxlen;
|
||||
for(j=0;j<TH_NDCT_TOKENS;j++){
|
||||
ogg_uint32_t bit;
|
||||
/*Fail if this code has no bits at all.
|
||||
Technically a codebook with a single 0-bit entry is legal, but the
|
||||
encoder currently does not support codebooks which do not contain all
|
||||
the tokens.*/
|
||||
if(entries[j].shift>=maxlen)return TH_EINVAL;
|
||||
/*Descend into the tree, writing a bit for each branch.*/
|
||||
for(;bpos>entries[j].shift;bpos--)oggpackB_write(_opb,0,1);
|
||||
/*Mark this as a leaf node, and write its value.*/
|
||||
oggpackB_write(_opb,1,1);
|
||||
oggpackB_write(_opb,entries[j].token,5);
|
||||
/*For each 1 branch we've descended, back up the tree until we reach a
|
||||
0 branch.*/
|
||||
bit=(ogg_uint32_t)1<<bpos;
|
||||
for(;entries[j].pattern&bit;bpos++)bit<<=1;
|
||||
/*Validate the code.*/
|
||||
if(j+1<TH_NDCT_TOKENS){
|
||||
mask=~(bit-1)<<1;
|
||||
/*The next entry should have a 1 bit where we had a 0, and should
|
||||
match our code above that bit.
|
||||
This verifies both fullness and prefix-freeness simultaneously.*/
|
||||
if(!(entries[j+1].pattern&bit)||
|
||||
(entries[j].pattern&mask)!=(entries[j+1].pattern&mask)){
|
||||
return TH_EINVAL;
|
||||
}
|
||||
}
|
||||
/*If there are no more codes, we should have ascended back to the top
|
||||
of the tree.*/
|
||||
else if(bpos<maxlen)return TH_EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*This is used to copy the configuration of an existing setup header for use by
|
||||
the encoder.
|
||||
The decoder uses a completely different data structure for the Huffman
|
||||
codebooks.*/
|
||||
int oc_huff_codes_unpack(oc_pack_buf *_opb,
|
||||
th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS]){
|
||||
int ret;
|
||||
int i;
|
||||
ret=0;
|
||||
for(i=0;i<TH_NHUFFMAN_TABLES;i++){
|
||||
ogg_uint32_t code;
|
||||
int len;
|
||||
int ntokens;
|
||||
int nleaves;
|
||||
code=0;
|
||||
len=ntokens=nleaves=0;
|
||||
memset(_codes[i],0,TH_NDCT_TOKENS*sizeof(*_codes[i]));
|
||||
for(;;){
|
||||
long bits;
|
||||
bits=oc_pack_read1(_opb);
|
||||
/*Only process nodes so long as there's more bits in the buffer.*/
|
||||
if(oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER;
|
||||
/*Read an internal node:*/
|
||||
if(!bits){
|
||||
len++;
|
||||
/*Don't allow codewords longer than 32 bits.*/
|
||||
if(len>32)return TH_EBADHEADER;
|
||||
}
|
||||
/*Read a leaf node:*/
|
||||
else{
|
||||
ogg_uint32_t code_bit;
|
||||
/*Don't allow more than 32 tokens per codebook.*/
|
||||
if(++nleaves>32)return TH_EBADHEADER;
|
||||
bits=oc_pack_read(_opb,OC_NDCT_TOKEN_BITS);
|
||||
/*The current encoder does not support codebooks that do not contain
|
||||
all of the tokens.*/
|
||||
if(_codes[i][bits].nbits>0)return TH_EINVAL;
|
||||
_codes[i][bits].pattern=code>>32-len;
|
||||
_codes[i][bits].nbits=len;
|
||||
code_bit=0x80000000U>>len-1;
|
||||
while(len>0&&(code&code_bit)){
|
||||
code^=code_bit;
|
||||
code_bit<<=1;
|
||||
len--;
|
||||
}
|
||||
if(len<=0)break;
|
||||
code|=code_bit;
|
||||
}
|
||||
}
|
||||
/*The current encoder does not support codebooks that do not contain all of
|
||||
the tokens.*/
|
||||
if(nleaves<32)return TH_EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#if !defined(_huffenc_H)
|
||||
# define _huffenc_H (1)
|
||||
# include "huffman.h"
|
||||
# include "bitpack.h"
|
||||
|
||||
|
||||
|
||||
typedef th_huff_code th_huff_table[TH_NDCT_TOKENS];
|
||||
|
||||
|
||||
|
||||
extern const th_huff_code
|
||||
TH_VP31_HUFF_CODES[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS];
|
||||
|
||||
|
||||
|
||||
int oc_huff_codes_pack(oggpack_buffer *_opb,
|
||||
const th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS]);
|
||||
int oc_huff_codes_unpack(oc_pack_buf *_opb,
|
||||
th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS]);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_huffman_H)
|
||||
# define _hufffman_H (1)
|
||||
# include "theora/codec.h"
|
||||
# include "ocintrin.h"
|
||||
|
||||
/*The range of valid quantized DCT coefficient values.
|
||||
VP3 used 511 in the encoder, but the bitstream is capable of 580.*/
|
||||
#define OC_DCT_VAL_RANGE (580)
|
||||
|
||||
#define OC_NDCT_TOKEN_BITS (5)
|
||||
|
||||
#define OC_DCT_EOB1_TOKEN (0)
|
||||
#define OC_DCT_EOB2_TOKEN (1)
|
||||
#define OC_DCT_EOB3_TOKEN (2)
|
||||
#define OC_DCT_REPEAT_RUN0_TOKEN (3)
|
||||
#define OC_DCT_REPEAT_RUN1_TOKEN (4)
|
||||
#define OC_DCT_REPEAT_RUN2_TOKEN (5)
|
||||
#define OC_DCT_REPEAT_RUN3_TOKEN (6)
|
||||
|
||||
#define OC_DCT_SHORT_ZRL_TOKEN (7)
|
||||
#define OC_DCT_ZRL_TOKEN (8)
|
||||
|
||||
#define OC_ONE_TOKEN (9)
|
||||
#define OC_MINUS_ONE_TOKEN (10)
|
||||
#define OC_TWO_TOKEN (11)
|
||||
#define OC_MINUS_TWO_TOKEN (12)
|
||||
|
||||
#define OC_DCT_VAL_CAT2 (13)
|
||||
#define OC_DCT_VAL_CAT3 (17)
|
||||
#define OC_DCT_VAL_CAT4 (18)
|
||||
#define OC_DCT_VAL_CAT5 (19)
|
||||
#define OC_DCT_VAL_CAT6 (20)
|
||||
#define OC_DCT_VAL_CAT7 (21)
|
||||
#define OC_DCT_VAL_CAT8 (22)
|
||||
|
||||
#define OC_DCT_RUN_CAT1A (23)
|
||||
#define OC_DCT_RUN_CAT1B (28)
|
||||
#define OC_DCT_RUN_CAT1C (29)
|
||||
#define OC_DCT_RUN_CAT2A (30)
|
||||
#define OC_DCT_RUN_CAT2B (31)
|
||||
|
||||
#define OC_NDCT_EOB_TOKEN_MAX (7)
|
||||
#define OC_NDCT_ZRL_TOKEN_MAX (9)
|
||||
#define OC_NDCT_VAL_MAX (23)
|
||||
#define OC_NDCT_VAL_CAT1_MAX (13)
|
||||
#define OC_NDCT_VAL_CAT2_MAX (17)
|
||||
#define OC_NDCT_VAL_CAT2_SIZE (OC_NDCT_VAL_CAT2_MAX-OC_DCT_VAL_CAT2)
|
||||
#define OC_NDCT_RUN_MAX (32)
|
||||
#define OC_NDCT_RUN_CAT1A_MAX (28)
|
||||
|
||||
extern const unsigned char OC_DCT_TOKEN_EXTRA_BITS[TH_NDCT_TOKENS];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,329 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "internal.h"
|
||||
#include "dct.h"
|
||||
|
||||
/*Performs an inverse 8 point Type-II DCT transform.
|
||||
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||
the transform.
|
||||
_y: The buffer to store the result in.
|
||||
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||
block).
|
||||
_x: The input coefficients.
|
||||
The first 8 entries are used (e.g., from a row of an 8x8 block).*/
|
||||
static void idct8(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||
ogg_int32_t t[8];
|
||||
ogg_int32_t r;
|
||||
/*Stage 1:*/
|
||||
/*0-1 butterfly.*/
|
||||
t[0]=OC_C4S4*(ogg_int16_t)(_x[0]+_x[4])>>16;
|
||||
t[1]=OC_C4S4*(ogg_int16_t)(_x[0]-_x[4])>>16;
|
||||
/*2-3 rotation by 6pi/16.*/
|
||||
t[2]=(OC_C6S2*_x[2]>>16)-(OC_C2S6*_x[6]>>16);
|
||||
t[3]=(OC_C2S6*_x[2]>>16)+(OC_C6S2*_x[6]>>16);
|
||||
/*4-7 rotation by 7pi/16.*/
|
||||
t[4]=(OC_C7S1*_x[1]>>16)-(OC_C1S7*_x[7]>>16);
|
||||
/*5-6 rotation by 3pi/16.*/
|
||||
t[5]=(OC_C3S5*_x[5]>>16)-(OC_C5S3*_x[3]>>16);
|
||||
t[6]=(OC_C5S3*_x[5]>>16)+(OC_C3S5*_x[3]>>16);
|
||||
t[7]=(OC_C1S7*_x[1]>>16)+(OC_C7S1*_x[7]>>16);
|
||||
/*Stage 2:*/
|
||||
/*4-5 butterfly.*/
|
||||
r=t[4]+t[5];
|
||||
t[5]=OC_C4S4*(ogg_int16_t)(t[4]-t[5])>>16;
|
||||
t[4]=r;
|
||||
/*7-6 butterfly.*/
|
||||
r=t[7]+t[6];
|
||||
t[6]=OC_C4S4*(ogg_int16_t)(t[7]-t[6])>>16;
|
||||
t[7]=r;
|
||||
/*Stage 3:*/
|
||||
/*0-3 butterfly.*/
|
||||
r=t[0]+t[3];
|
||||
t[3]=t[0]-t[3];
|
||||
t[0]=r;
|
||||
/*1-2 butterfly.*/
|
||||
r=t[1]+t[2];
|
||||
t[2]=t[1]-t[2];
|
||||
t[1]=r;
|
||||
/*6-5 butterfly.*/
|
||||
r=t[6]+t[5];
|
||||
t[5]=t[6]-t[5];
|
||||
t[6]=r;
|
||||
/*Stage 4:*/
|
||||
/*0-7 butterfly.*/
|
||||
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||
/*1-6 butterfly.*/
|
||||
_y[1<<3]=(ogg_int16_t)(t[1]+t[6]);
|
||||
/*2-5 butterfly.*/
|
||||
_y[2<<3]=(ogg_int16_t)(t[2]+t[5]);
|
||||
/*3-4 butterfly.*/
|
||||
_y[3<<3]=(ogg_int16_t)(t[3]+t[4]);
|
||||
_y[4<<3]=(ogg_int16_t)(t[3]-t[4]);
|
||||
_y[5<<3]=(ogg_int16_t)(t[2]-t[5]);
|
||||
_y[6<<3]=(ogg_int16_t)(t[1]-t[6]);
|
||||
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||
}
|
||||
|
||||
/*Performs an inverse 8 point Type-II DCT transform.
|
||||
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||
the transform.
|
||||
_y: The buffer to store the result in.
|
||||
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||
block).
|
||||
_x: The input coefficients.
|
||||
Only the first 4 entries are used.
|
||||
The other 4 are assumed to be 0.*/
|
||||
static void idct8_4(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||
ogg_int32_t t[8];
|
||||
ogg_int32_t r;
|
||||
/*Stage 1:*/
|
||||
t[0]=OC_C4S4*_x[0]>>16;
|
||||
t[2]=OC_C6S2*_x[2]>>16;
|
||||
t[3]=OC_C2S6*_x[2]>>16;
|
||||
t[4]=OC_C7S1*_x[1]>>16;
|
||||
t[5]=-(OC_C5S3*_x[3]>>16);
|
||||
t[6]=OC_C3S5*_x[3]>>16;
|
||||
t[7]=OC_C1S7*_x[1]>>16;
|
||||
/*Stage 2:*/
|
||||
r=t[4]+t[5];
|
||||
t[5]=OC_C4S4*(ogg_int16_t)(t[4]-t[5])>>16;
|
||||
t[4]=r;
|
||||
r=t[7]+t[6];
|
||||
t[6]=OC_C4S4*(ogg_int16_t)(t[7]-t[6])>>16;
|
||||
t[7]=r;
|
||||
/*Stage 3:*/
|
||||
t[1]=t[0]+t[2];
|
||||
t[2]=t[0]-t[2];
|
||||
r=t[0]+t[3];
|
||||
t[3]=t[0]-t[3];
|
||||
t[0]=r;
|
||||
r=t[6]+t[5];
|
||||
t[5]=t[6]-t[5];
|
||||
t[6]=r;
|
||||
/*Stage 4:*/
|
||||
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||
_y[1<<3]=(ogg_int16_t)(t[1]+t[6]);
|
||||
_y[2<<3]=(ogg_int16_t)(t[2]+t[5]);
|
||||
_y[3<<3]=(ogg_int16_t)(t[3]+t[4]);
|
||||
_y[4<<3]=(ogg_int16_t)(t[3]-t[4]);
|
||||
_y[5<<3]=(ogg_int16_t)(t[2]-t[5]);
|
||||
_y[6<<3]=(ogg_int16_t)(t[1]-t[6]);
|
||||
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||
}
|
||||
|
||||
/*Performs an inverse 8 point Type-II DCT transform.
|
||||
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||
the transform.
|
||||
_y: The buffer to store the result in.
|
||||
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||
block).
|
||||
_x: The input coefficients.
|
||||
Only the first 3 entries are used.
|
||||
The other 5 are assumed to be 0.*/
|
||||
static void idct8_3(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||
ogg_int32_t t[8];
|
||||
ogg_int32_t r;
|
||||
/*Stage 1:*/
|
||||
t[0]=OC_C4S4*_x[0]>>16;
|
||||
t[2]=OC_C6S2*_x[2]>>16;
|
||||
t[3]=OC_C2S6*_x[2]>>16;
|
||||
t[4]=OC_C7S1*_x[1]>>16;
|
||||
t[7]=OC_C1S7*_x[1]>>16;
|
||||
/*Stage 2:*/
|
||||
t[5]=OC_C4S4*t[4]>>16;
|
||||
t[6]=OC_C4S4*t[7]>>16;
|
||||
/*Stage 3:*/
|
||||
t[1]=t[0]+t[2];
|
||||
t[2]=t[0]-t[2];
|
||||
r=t[0]+t[3];
|
||||
t[3]=t[0]-t[3];
|
||||
t[0]=r;
|
||||
r=t[6]+t[5];
|
||||
t[5]=t[6]-t[5];
|
||||
t[6]=r;
|
||||
/*Stage 4:*/
|
||||
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||
_y[1<<3]=(ogg_int16_t)(t[1]+t[6]);
|
||||
_y[2<<3]=(ogg_int16_t)(t[2]+t[5]);
|
||||
_y[3<<3]=(ogg_int16_t)(t[3]+t[4]);
|
||||
_y[4<<3]=(ogg_int16_t)(t[3]-t[4]);
|
||||
_y[5<<3]=(ogg_int16_t)(t[2]-t[5]);
|
||||
_y[6<<3]=(ogg_int16_t)(t[1]-t[6]);
|
||||
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||
}
|
||||
|
||||
/*Performs an inverse 8 point Type-II DCT transform.
|
||||
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||
the transform.
|
||||
_y: The buffer to store the result in.
|
||||
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||
block).
|
||||
_x: The input coefficients.
|
||||
Only the first 2 entries are used.
|
||||
The other 6 are assumed to be 0.*/
|
||||
static void idct8_2(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||
ogg_int32_t t[8];
|
||||
ogg_int32_t r;
|
||||
/*Stage 1:*/
|
||||
t[0]=OC_C4S4*_x[0]>>16;
|
||||
t[4]=OC_C7S1*_x[1]>>16;
|
||||
t[7]=OC_C1S7*_x[1]>>16;
|
||||
/*Stage 2:*/
|
||||
t[5]=OC_C4S4*t[4]>>16;
|
||||
t[6]=OC_C4S4*t[7]>>16;
|
||||
/*Stage 3:*/
|
||||
r=t[6]+t[5];
|
||||
t[5]=t[6]-t[5];
|
||||
t[6]=r;
|
||||
/*Stage 4:*/
|
||||
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||
_y[1<<3]=(ogg_int16_t)(t[0]+t[6]);
|
||||
_y[2<<3]=(ogg_int16_t)(t[0]+t[5]);
|
||||
_y[3<<3]=(ogg_int16_t)(t[0]+t[4]);
|
||||
_y[4<<3]=(ogg_int16_t)(t[0]-t[4]);
|
||||
_y[5<<3]=(ogg_int16_t)(t[0]-t[5]);
|
||||
_y[6<<3]=(ogg_int16_t)(t[0]-t[6]);
|
||||
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||
}
|
||||
|
||||
/*Performs an inverse 8 point Type-II DCT transform.
|
||||
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||
the transform.
|
||||
_y: The buffer to store the result in.
|
||||
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||
block).
|
||||
_x: The input coefficients.
|
||||
Only the first entry is used.
|
||||
The other 7 are assumed to be 0.*/
|
||||
static void idct8_1(ogg_int16_t *_y,const ogg_int16_t _x[1]){
|
||||
_y[0<<3]=_y[1<<3]=_y[2<<3]=_y[3<<3]=
|
||||
_y[4<<3]=_y[5<<3]=_y[6<<3]=_y[7<<3]=(ogg_int16_t)(OC_C4S4*_x[0]>>16);
|
||||
}
|
||||
|
||||
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||
version of the transform.
|
||||
All coefficients but the first 3 in zig-zag scan order are assumed to be 0:
|
||||
x x 0 0 0 0 0 0
|
||||
x 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
_y: The buffer to store the result in.
|
||||
This may be the same as _x.
|
||||
_x: The input coefficients.*/
|
||||
static void oc_idct8x8_3(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||
ogg_int16_t w[64];
|
||||
int i;
|
||||
/*Transform rows of x into columns of w.*/
|
||||
idct8_2(w,_x);
|
||||
idct8_1(w+1,_x+8);
|
||||
/*Transform rows of w into columns of y.*/
|
||||
for(i=0;i<8;i++)idct8_2(_y+i,w+i*8);
|
||||
/*Adjust for the scale factor.*/
|
||||
for(i=0;i<64;i++)_y[i]=(ogg_int16_t)(_y[i]+8>>4);
|
||||
/*Clear input data for next block (decoder only).*/
|
||||
if(_x!=_y)_x[0]=_x[1]=_x[8]=0;
|
||||
}
|
||||
|
||||
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||
version of the transform.
|
||||
All coefficients but the first 10 in zig-zag scan order are assumed to be 0:
|
||||
x x x x 0 0 0 0
|
||||
x x x 0 0 0 0 0
|
||||
x x 0 0 0 0 0 0
|
||||
x 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
_y: The buffer to store the result in.
|
||||
This may be the same as _x.
|
||||
_x: The input coefficients.*/
|
||||
static void oc_idct8x8_10(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||
ogg_int16_t w[64];
|
||||
int i;
|
||||
/*Transform rows of x into columns of w.*/
|
||||
idct8_4(w,_x);
|
||||
idct8_3(w+1,_x+8);
|
||||
idct8_2(w+2,_x+16);
|
||||
idct8_1(w+3,_x+24);
|
||||
/*Transform rows of w into columns of y.*/
|
||||
for(i=0;i<8;i++)idct8_4(_y+i,w+i*8);
|
||||
/*Adjust for the scale factor.*/
|
||||
for(i=0;i<64;i++)_y[i]=(ogg_int16_t)(_y[i]+8>>4);
|
||||
/*Clear input data for next block (decoder only).*/
|
||||
if(_x!=_y)_x[0]=_x[1]=_x[2]=_x[3]=_x[8]=_x[9]=_x[10]=_x[16]=_x[17]=_x[24]=0;
|
||||
}
|
||||
|
||||
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||
version of the transform.
|
||||
_y: The buffer to store the result in.
|
||||
This may be the same as _x.
|
||||
_x: The input coefficients.*/
|
||||
static void oc_idct8x8_slow(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||
ogg_int16_t w[64];
|
||||
int i;
|
||||
/*Transform rows of x into columns of w.*/
|
||||
for(i=0;i<8;i++)idct8(w+i,_x+i*8);
|
||||
/*Transform rows of w into columns of y.*/
|
||||
for(i=0;i<8;i++)idct8(_y+i,w+i*8);
|
||||
/*Adjust for the scale factor.*/
|
||||
for(i=0;i<64;i++)_y[i]=(ogg_int16_t)(_y[i]+8>>4);
|
||||
if(_x!=_y)for(i=0;i<64;i++)_x[i]=0;
|
||||
}
|
||||
|
||||
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||
version of the transform.*/
|
||||
void oc_idct8x8_c(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi){
|
||||
/*_last_zzi is subtly different from an actual count of the number of
|
||||
coefficients we decoded for this block.
|
||||
It contains the value of zzi BEFORE the final token in the block was
|
||||
decoded.
|
||||
In most cases this is an EOB token (the continuation of an EOB run from a
|
||||
previous block counts), and so this is the same as the coefficient count.
|
||||
However, in the case that the last token was NOT an EOB token, but filled
|
||||
the block up with exactly 64 coefficients, _last_zzi will be less than 64.
|
||||
Provided the last token was not a pure zero run, the minimum value it can
|
||||
be is 46, and so that doesn't affect any of the cases in this routine.
|
||||
However, if the last token WAS a pure zero run of length 63, then _last_zzi
|
||||
will be 1 while the number of coefficients decoded is 64.
|
||||
Thus, we will trigger the following special case, where the real
|
||||
coefficient count would not.
|
||||
Note also that a zero run of length 64 will give _last_zzi a value of 0,
|
||||
but we still process the DC coefficient, which might have a non-zero value
|
||||
due to DC prediction.
|
||||
Although convoluted, this is arguably the correct behavior: it allows us to
|
||||
use a smaller transform when the block ends with a long zero run instead
|
||||
of a normal EOB token.
|
||||
It could be smarter... multiple separate zero runs at the end of a block
|
||||
will fool it, but an encoder that generates these really deserves what it
|
||||
gets.
|
||||
Needless to say we inherited this approach from VP3.*/
|
||||
/*Then perform the iDCT.*/
|
||||
if(_last_zzi<=3)oc_idct8x8_3(_y,_x);
|
||||
else if(_last_zzi<=10)oc_idct8x8_10(_y,_x);
|
||||
else oc_idct8x8_slow(_y,_x);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
|
||||
/*This is more or less the same as strncasecmp, but that doesn't exist
|
||||
everywhere, and this is a fairly trivial function, so we include it.
|
||||
Note: We take advantage of the fact that we know _n is less than or equal to
|
||||
the length of at least one of the strings.*/
|
||||
static int oc_tagcompare(const char *_s1,const char *_s2,int _n){
|
||||
int c;
|
||||
for(c=0;c<_n;c++){
|
||||
if(toupper(_s1[c])!=toupper(_s2[c]))return !0;
|
||||
}
|
||||
return _s1[c]!='=';
|
||||
}
|
||||
|
||||
|
||||
|
||||
void th_info_init(th_info *_info){
|
||||
memset(_info,0,sizeof(*_info));
|
||||
_info->version_major=TH_VERSION_MAJOR;
|
||||
_info->version_minor=TH_VERSION_MINOR;
|
||||
_info->version_subminor=TH_VERSION_SUB;
|
||||
_info->keyframe_granule_shift=6;
|
||||
}
|
||||
|
||||
void th_info_clear(th_info *_info){
|
||||
memset(_info,0,sizeof(*_info));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void th_comment_init(th_comment *_tc){
|
||||
memset(_tc,0,sizeof(*_tc));
|
||||
}
|
||||
|
||||
void th_comment_add(th_comment *_tc,char *_comment){
|
||||
char **user_comments;
|
||||
int *comment_lengths;
|
||||
int comment_len;
|
||||
user_comments=_ogg_realloc(_tc->user_comments,
|
||||
(_tc->comments+2)*sizeof(*_tc->user_comments));
|
||||
if(user_comments==NULL)return;
|
||||
_tc->user_comments=user_comments;
|
||||
comment_lengths=_ogg_realloc(_tc->comment_lengths,
|
||||
(_tc->comments+2)*sizeof(*_tc->comment_lengths));
|
||||
if(comment_lengths==NULL)return;
|
||||
_tc->comment_lengths=comment_lengths;
|
||||
comment_len=strlen(_comment);
|
||||
comment_lengths[_tc->comments]=comment_len;
|
||||
user_comments[_tc->comments]=_ogg_malloc(comment_len+1);
|
||||
if(user_comments[_tc->comments]==NULL)return;
|
||||
memcpy(_tc->user_comments[_tc->comments],_comment,comment_len+1);
|
||||
_tc->comments++;
|
||||
_tc->user_comments[_tc->comments]=NULL;
|
||||
}
|
||||
|
||||
void th_comment_add_tag(th_comment *_tc,char *_tag,char *_val){
|
||||
char *comment;
|
||||
int tag_len;
|
||||
int val_len;
|
||||
tag_len=strlen(_tag);
|
||||
val_len=strlen(_val);
|
||||
/*+2 for '=' and '\0'.*/
|
||||
comment=_ogg_malloc(tag_len+val_len+2);
|
||||
if(comment==NULL)return;
|
||||
memcpy(comment,_tag,tag_len);
|
||||
comment[tag_len]='=';
|
||||
memcpy(comment+tag_len+1,_val,val_len+1);
|
||||
th_comment_add(_tc,comment);
|
||||
_ogg_free(comment);
|
||||
}
|
||||
|
||||
char *th_comment_query(th_comment *_tc,char *_tag,int _count){
|
||||
long i;
|
||||
int found;
|
||||
int tag_len;
|
||||
tag_len=strlen(_tag);
|
||||
found=0;
|
||||
for(i=0;i<_tc->comments;i++){
|
||||
if(!oc_tagcompare(_tc->user_comments[i],_tag,tag_len)){
|
||||
/*We return a pointer to the data, not a copy.*/
|
||||
if(_count==found++)return _tc->user_comments[i]+tag_len+1;
|
||||
}
|
||||
}
|
||||
/*Didn't find anything.*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int th_comment_query_count(th_comment *_tc,char *_tag){
|
||||
long i;
|
||||
int tag_len;
|
||||
int count;
|
||||
tag_len=strlen(_tag);
|
||||
count=0;
|
||||
for(i=0;i<_tc->comments;i++){
|
||||
if(!oc_tagcompare(_tc->user_comments[i],_tag,tag_len))count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void th_comment_clear(th_comment *_tc){
|
||||
if(_tc!=NULL){
|
||||
long i;
|
||||
for(i=0;i<_tc->comments;i++)_ogg_free(_tc->user_comments[i]);
|
||||
_ogg_free(_tc->user_comments);
|
||||
_ogg_free(_tc->comment_lengths);
|
||||
_ogg_free(_tc->vendor);
|
||||
memset(_tc,0,sizeof(*_tc));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
|
||||
/*A map from the index in the zig zag scan to the coefficient number in a
|
||||
block.
|
||||
All zig zag indices beyond 63 are sent to coefficient 64, so that zero runs
|
||||
past the end of a block in bogus streams get mapped to a known location.*/
|
||||
const unsigned char OC_FZIG_ZAG[128]={
|
||||
0, 1, 8,16, 9, 2, 3,10,
|
||||
17,24,32,25,18,11, 4, 5,
|
||||
12,19,26,33,40,48,41,34,
|
||||
27,20,13, 6, 7,14,21,28,
|
||||
35,42,49,56,57,50,43,36,
|
||||
29,22,15,23,30,37,44,51,
|
||||
58,59,52,45,38,31,39,46,
|
||||
53,60,61,54,47,55,62,63,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64
|
||||
};
|
||||
|
||||
/*A map from the coefficient number in a block to its index in the zig zag
|
||||
scan.*/
|
||||
const unsigned char OC_IZIG_ZAG[64]={
|
||||
0, 1, 5, 6,14,15,27,28,
|
||||
2, 4, 7,13,16,26,29,42,
|
||||
3, 8,12,17,25,30,41,43,
|
||||
9,11,18,24,31,40,44,53,
|
||||
10,19,23,32,39,45,52,54,
|
||||
20,22,33,38,46,51,55,60,
|
||||
21,34,37,47,50,56,59,61,
|
||||
35,36,48,49,57,58,62,63
|
||||
};
|
||||
|
||||
/*A map from physical macro block ordering to bitstream macro block
|
||||
ordering within a super block.*/
|
||||
const unsigned char OC_MB_MAP[2][2]={{0,3},{1,2}};
|
||||
|
||||
/*A list of the indices in the oc_mb.map array that can be valid for each of
|
||||
the various chroma decimation types.*/
|
||||
const unsigned char OC_MB_MAP_IDXS[TH_PF_NFORMATS][12]={
|
||||
{0,1,2,3,4,8},
|
||||
{0,1,2,3,4,5,8,9},
|
||||
{0,1,2,3,4,6,8,10},
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11}
|
||||
};
|
||||
|
||||
/*The number of indices in the oc_mb.map array that can be valid for each of
|
||||
the various chroma decimation types.*/
|
||||
const unsigned char OC_MB_MAP_NIDXS[TH_PF_NFORMATS]={6,8,8,12};
|
||||
|
||||
/*The number of extra bits that are coded with each of the DCT tokens.
|
||||
Each DCT token has some fixed number of additional bits (possibly 0) stored
|
||||
after the token itself, containing, for example, coefficient magnitude,
|
||||
sign bits, etc.*/
|
||||
const unsigned char OC_DCT_TOKEN_EXTRA_BITS[TH_NDCT_TOKENS]={
|
||||
0,0,0,2,3,4,12,3,6,
|
||||
0,0,0,0,
|
||||
1,1,1,1,2,3,4,5,6,10,
|
||||
1,1,1,1,1,3,4,
|
||||
2,3
|
||||
};
|
||||
|
||||
|
||||
|
||||
int oc_ilog(unsigned _v){
|
||||
int ret;
|
||||
for(ret=0;_v;ret++)_v>>=1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *oc_aligned_malloc(size_t _sz,size_t _align){
|
||||
unsigned char *p;
|
||||
if(_align>UCHAR_MAX||(_align&_align-1)||_sz>~(size_t)0-_align)return NULL;
|
||||
p=(unsigned char *)_ogg_malloc(_sz+_align);
|
||||
if(p!=NULL){
|
||||
int offs;
|
||||
offs=((p-(unsigned char *)0)-1&_align-1);
|
||||
p[offs]=offs;
|
||||
p+=offs+1;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void oc_aligned_free(void *_ptr){
|
||||
unsigned char *p;
|
||||
p=(unsigned char *)_ptr;
|
||||
if(p!=NULL){
|
||||
int offs;
|
||||
offs=*--p;
|
||||
_ogg_free(p-offs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void **oc_malloc_2d(size_t _height,size_t _width,size_t _sz){
|
||||
size_t rowsz;
|
||||
size_t colsz;
|
||||
size_t datsz;
|
||||
char *ret;
|
||||
colsz=_height*sizeof(void *);
|
||||
rowsz=_sz*_width;
|
||||
datsz=rowsz*_height;
|
||||
/*Alloc array and row pointers.*/
|
||||
ret=(char *)_ogg_malloc(datsz+colsz);
|
||||
if(ret==NULL)return NULL;
|
||||
/*Initialize the array.*/
|
||||
if(ret!=NULL){
|
||||
size_t i;
|
||||
void **p;
|
||||
char *datptr;
|
||||
p=(void **)ret;
|
||||
i=_height;
|
||||
for(datptr=ret+colsz;i-->0;p++,datptr+=rowsz)*p=(void *)datptr;
|
||||
}
|
||||
return (void **)ret;
|
||||
}
|
||||
|
||||
void **oc_calloc_2d(size_t _height,size_t _width,size_t _sz){
|
||||
size_t colsz;
|
||||
size_t rowsz;
|
||||
size_t datsz;
|
||||
char *ret;
|
||||
colsz=_height*sizeof(void *);
|
||||
rowsz=_sz*_width;
|
||||
datsz=rowsz*_height;
|
||||
/*Alloc array and row pointers.*/
|
||||
ret=(char *)_ogg_calloc(datsz+colsz,1);
|
||||
if(ret==NULL)return NULL;
|
||||
/*Initialize the array.*/
|
||||
if(ret!=NULL){
|
||||
size_t i;
|
||||
void **p;
|
||||
char *datptr;
|
||||
p=(void **)ret;
|
||||
i=_height;
|
||||
for(datptr=ret+colsz;i-->0;p++,datptr+=rowsz)*p=(void *)datptr;
|
||||
}
|
||||
return (void **)ret;
|
||||
}
|
||||
|
||||
void oc_free_2d(void *_ptr){
|
||||
_ogg_free(_ptr);
|
||||
}
|
||||
|
||||
/*Fills in a Y'CbCr buffer with a pointer to the image data in the first
|
||||
buffer, but with the opposite vertical orientation.
|
||||
_dst: The destination buffer.
|
||||
This can be the same as _src.
|
||||
_src: The source buffer.*/
|
||||
void oc_ycbcr_buffer_flip(th_ycbcr_buffer _dst,
|
||||
const th_ycbcr_buffer _src){
|
||||
int pli;
|
||||
for(pli=0;pli<3;pli++){
|
||||
_dst[pli].width=_src[pli].width;
|
||||
_dst[pli].height=_src[pli].height;
|
||||
_dst[pli].stride=-_src[pli].stride;
|
||||
_dst[pli].data=_src[pli].data
|
||||
+(1-_dst[pli].height)*(ptrdiff_t)_dst[pli].stride;
|
||||
}
|
||||
}
|
||||
|
||||
const char *th_version_string(void){
|
||||
return OC_VENDOR_STRING;
|
||||
}
|
||||
|
||||
ogg_uint32_t th_version_number(void){
|
||||
return (TH_VERSION_MAJOR<<16)+(TH_VERSION_MINOR<<8)+TH_VERSION_SUB;
|
||||
}
|
||||
|
||||
/*Determines the packet type.
|
||||
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){
|
||||
return _op->bytes>0?_op->packet[0]>>7:0;
|
||||
}
|
||||
|
||||
/*Determines the frame type of a video data packet.
|
||||
Note that this correctly interprets a 0-byte packet as a delta frame.
|
||||
Return: 1 for a key frame, 0 for a delta frame, and -1 for a header
|
||||
packet.*/
|
||||
int th_packet_iskeyframe(ogg_packet *_op){
|
||||
return _op->bytes<=0?0:_op->packet[0]&0x80?-1:!(_op->packet[0]&0x40);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_internal_H)
|
||||
# define _internal_H (1)
|
||||
# include <stdlib.h>
|
||||
# include <limits.h>
|
||||
# if defined(HAVE_CONFIG_H)
|
||||
# include "config.h"
|
||||
# endif
|
||||
# include "theora/codec.h"
|
||||
# include "theora/theora.h"
|
||||
# include "ocintrin.h"
|
||||
|
||||
# if defined(_MSC_VER)
|
||||
/*Disable missing EMMS warnings.*/
|
||||
# pragma warning(disable:4799)
|
||||
/*Thank you Microsoft, I know the order of operations.*/
|
||||
# pragma warning(disable:4554)
|
||||
# endif
|
||||
/*You, too, gcc.*/
|
||||
# if defined(__GNUC_PREREQ)
|
||||
# if __GNUC_PREREQ(4,2)
|
||||
# pragma GCC diagnostic ignored "-Wparentheses"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/*Some assembly constructs require aligned operands.
|
||||
The following macros are _only_ intended for structure member declarations.
|
||||
Although they will sometimes work on stack variables, gcc will often silently
|
||||
ignore them.
|
||||
A separate set of macros could be made for manual stack alignment, but we
|
||||
don't actually require it anywhere.*/
|
||||
# if defined(OC_X86_ASM)||defined(OC_ARM_ASM)
|
||||
# if defined(__GNUC__)
|
||||
# define OC_ALIGN8(expr) expr __attribute__((aligned(8)))
|
||||
# define OC_ALIGN16(expr) expr __attribute__((aligned(16)))
|
||||
# elif defined(_MSC_VER)
|
||||
# define OC_ALIGN8(expr) __declspec (align(8)) expr
|
||||
# define OC_ALIGN16(expr) __declspec (align(16)) expr
|
||||
# else
|
||||
# error "Alignment macros required for this platform."
|
||||
# endif
|
||||
# endif
|
||||
# if !defined(OC_ALIGN8)
|
||||
# define OC_ALIGN8(expr) expr
|
||||
# endif
|
||||
# if !defined(OC_ALIGN16)
|
||||
# define OC_ALIGN16(expr) expr
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
/*This library's version.*/
|
||||
# define OC_VENDOR_STRING "Xiph.Org libtheora 1.2.0alpha 20100923 (Ptalarbvorm)"
|
||||
|
||||
/*Theora bitstream version.*/
|
||||
# define TH_VERSION_MAJOR (3)
|
||||
# define TH_VERSION_MINOR (2)
|
||||
# define TH_VERSION_SUB (1)
|
||||
# define TH_VERSION_CHECK(_info,_maj,_min,_sub) \
|
||||
((_info)->version_major>(_maj)||(_info)->version_major==(_maj)&& \
|
||||
((_info)->version_minor>(_min)||(_info)->version_minor==(_min)&& \
|
||||
(_info)->version_subminor>=(_sub)))
|
||||
|
||||
|
||||
|
||||
/*A map from the index in the zig zag scan to the coefficient number in a
|
||||
block.*/
|
||||
extern const unsigned char OC_FZIG_ZAG[128];
|
||||
/*A map from the coefficient number in a block to its index in the zig zag
|
||||
scan.*/
|
||||
extern const unsigned char OC_IZIG_ZAG[64];
|
||||
/*A map from physical macro block ordering to bitstream macro block
|
||||
ordering within a super block.*/
|
||||
extern const unsigned char OC_MB_MAP[2][2];
|
||||
/*A list of the indices in the oc_mb_map array that can be valid for each of
|
||||
the various chroma decimation types.*/
|
||||
extern const unsigned char OC_MB_MAP_IDXS[TH_PF_NFORMATS][12];
|
||||
/*The number of indices in the oc_mb_map array that can be valid for each of
|
||||
the various chroma decimation types.*/
|
||||
extern const unsigned char OC_MB_MAP_NIDXS[TH_PF_NFORMATS];
|
||||
|
||||
|
||||
|
||||
int oc_ilog(unsigned _v);
|
||||
void *oc_aligned_malloc(size_t _sz,size_t _align);
|
||||
void oc_aligned_free(void *_ptr);
|
||||
void **oc_malloc_2d(size_t _height,size_t _width,size_t _sz);
|
||||
void **oc_calloc_2d(size_t _height,size_t _width,size_t _sz);
|
||||
void oc_free_2d(void *_ptr);
|
||||
|
||||
void oc_ycbcr_buffer_flip(th_ycbcr_buffer _dst,
|
||||
const th_ycbcr_buffer _src);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,314 @@
|
||||
#include "mathops.h"
|
||||
#include <limits.h>
|
||||
|
||||
/*The fastest fallback strategy for platforms with fast multiplication appears
|
||||
to be based on de Bruijn sequences~\cite{LP98}.
|
||||
Define OC_ILOG_NODEBRUIJN to use a simpler fallback on platforms where
|
||||
multiplication or table lookups are too expensive.
|
||||
|
||||
@UNPUBLISHED{LP98,
|
||||
author="Charles E. Leiserson and Harald Prokop",
|
||||
title="Using de {Bruijn} Sequences to Index a 1 in a Computer Word",
|
||||
month=Jun,
|
||||
year=1998,
|
||||
note="\url{http://supertech.csail.mit.edu/papers/debruijn.pdf}"
|
||||
}*/
|
||||
#if !defined(OC_ILOG_NODEBRUIJN)&&!defined(OC_CLZ32)
|
||||
static const unsigned char OC_DEBRUIJN_IDX32[32]={
|
||||
0, 1,28, 2,29,14,24, 3,30,22,20,15,25,17, 4, 8,
|
||||
31,27,13,23,21,19,16, 7,26,12,18, 6,11, 5,10, 9
|
||||
};
|
||||
#endif
|
||||
|
||||
int oc_ilog32(ogg_uint32_t _v){
|
||||
#if defined(OC_CLZ32)
|
||||
return OC_CLZ32_OFFS-OC_CLZ32(_v)&-!!_v;
|
||||
#else
|
||||
/*On a Pentium M, this branchless version tested as the fastest version without
|
||||
multiplications on 1,000,000,000 random 32-bit integers, edging out a
|
||||
similar version with branches, and a 256-entry LUT version.*/
|
||||
# if defined(OC_ILOG_NODEBRUIJN)
|
||||
int ret;
|
||||
int m;
|
||||
ret=_v>0;
|
||||
m=(_v>0xFFFFU)<<4;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
m=(_v>0xFFU)<<3;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
m=(_v>0xFU)<<2;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
m=(_v>3)<<1;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
ret+=_v>1;
|
||||
return ret;
|
||||
/*This de Bruijn sequence version is faster if you have a fast multiplier.*/
|
||||
# else
|
||||
int ret;
|
||||
_v|=_v>>1;
|
||||
_v|=_v>>2;
|
||||
_v|=_v>>4;
|
||||
_v|=_v>>8;
|
||||
_v|=_v>>16;
|
||||
ret=_v&1;
|
||||
_v=(_v>>1)+1;
|
||||
ret+=OC_DEBRUIJN_IDX32[_v*0x77CB531U>>27&0x1F];
|
||||
return ret;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int oc_ilog64(ogg_int64_t _v){
|
||||
#if defined(OC_CLZ64)
|
||||
return OC_CLZ64_OFFS-OC_CLZ64(_v)&-!!_v;
|
||||
#else
|
||||
/*If we don't have a fast 64-bit word implementation, split it into two 32-bit
|
||||
halves.*/
|
||||
# if defined(OC_ILOG_NODEBRUIJN)|| \
|
||||
defined(OC_CLZ32)||LONG_MAX<9223372036854775807LL
|
||||
ogg_uint32_t v;
|
||||
int ret;
|
||||
int m;
|
||||
m=(_v>0xFFFFFFFFU)<<5;
|
||||
v=(ogg_uint32_t)(_v>>m);
|
||||
# if defined(OC_CLZ32)
|
||||
ret=m+OC_CLZ32_OFFS-OC_CLZ32(v)&-!!v;
|
||||
# elif defined(OC_ILOG_NODEBRUIJN)
|
||||
ret=v>0|m;
|
||||
m=(v>0xFFFFU)<<4;
|
||||
v>>=m;
|
||||
ret|=m;
|
||||
m=(v>0xFFU)<<3;
|
||||
v>>=m;
|
||||
ret|=m;
|
||||
m=(v>0xFU)<<2;
|
||||
v>>=m;
|
||||
ret|=m;
|
||||
m=(v>3)<<1;
|
||||
v>>=m;
|
||||
ret|=m;
|
||||
ret+=v>1;
|
||||
return ret;
|
||||
# else
|
||||
v|=v>>1;
|
||||
v|=v>>2;
|
||||
v|=v>>4;
|
||||
v|=v>>8;
|
||||
v|=v>>16;
|
||||
ret=v&1|m;
|
||||
v=(v>>1)+1;
|
||||
ret+=OC_DEBRUIJN_IDX32[v*0x77CB531U>>27&0x1F];
|
||||
# endif
|
||||
return ret;
|
||||
/*Otherwise do it in one 64-bit multiply.*/
|
||||
# else
|
||||
static const unsigned char OC_DEBRUIJN_IDX64[64]={
|
||||
0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40,
|
||||
5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
|
||||
63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,
|
||||
62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
|
||||
};
|
||||
int ret;
|
||||
_v|=_v>>1;
|
||||
_v|=_v>>2;
|
||||
_v|=_v>>4;
|
||||
_v|=_v>>8;
|
||||
_v|=_v>>16;
|
||||
_v|=_v>>32;
|
||||
ret=(int)_v&1;
|
||||
_v=(_v>>1)+1;
|
||||
ret+=OC_DEBRUIJN_IDX64[_v*0x218A392CD3D5DBF>>58&0x3F];
|
||||
return ret;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*round(2**(62+i)*atanh(2**(-(i+1)))/log(2))*/
|
||||
static const ogg_int64_t OC_ATANH_LOG2[32]={
|
||||
0x32B803473F7AD0F4LL,0x2F2A71BD4E25E916LL,0x2E68B244BB93BA06LL,
|
||||
0x2E39FB9198CE62E4LL,0x2E2E683F68565C8FLL,0x2E2B850BE2077FC1LL,
|
||||
0x2E2ACC58FE7B78DBLL,0x2E2A9E2DE52FD5F2LL,0x2E2A92A338D53EECLL,
|
||||
0x2E2A8FC08F5E19B6LL,0x2E2A8F07E51A485ELL,0x2E2A8ED9BA8AF388LL,
|
||||
0x2E2A8ECE2FE7384ALL,0x2E2A8ECB4D3E4B1ALL,0x2E2A8ECA94940FE8LL,
|
||||
0x2E2A8ECA6669811DLL,0x2E2A8ECA5ADEDD6ALL,0x2E2A8ECA57FC347ELL,
|
||||
0x2E2A8ECA57438A43LL,0x2E2A8ECA57155FB4LL,0x2E2A8ECA5709D510LL,
|
||||
0x2E2A8ECA5706F267LL,0x2E2A8ECA570639BDLL,0x2E2A8ECA57060B92LL,
|
||||
0x2E2A8ECA57060008LL,0x2E2A8ECA5705FD25LL,0x2E2A8ECA5705FC6CLL,
|
||||
0x2E2A8ECA5705FC3ELL,0x2E2A8ECA5705FC33LL,0x2E2A8ECA5705FC30LL,
|
||||
0x2E2A8ECA5705FC2FLL,0x2E2A8ECA5705FC2FLL
|
||||
};
|
||||
|
||||
/*Computes the binary exponential of _z, a log base 2 in Q57 format.*/
|
||||
ogg_int64_t oc_bexp64(ogg_int64_t _z){
|
||||
ogg_int64_t w;
|
||||
ogg_int64_t z;
|
||||
int ipart;
|
||||
ipart=(int)(_z>>57);
|
||||
if(ipart<0)return 0;
|
||||
if(ipart>=63)return 0x7FFFFFFFFFFFFFFFLL;
|
||||
z=_z-OC_Q57(ipart);
|
||||
if(z){
|
||||
ogg_int64_t mask;
|
||||
long wlo;
|
||||
int i;
|
||||
/*C doesn't give us 64x64->128 muls, so we use CORDIC.
|
||||
This is not particularly fast, but it's not being used in time-critical
|
||||
code; it is very accurate.*/
|
||||
/*z is the fractional part of the log in Q62 format.
|
||||
We need 1 bit of headroom since the magnitude can get larger than 1
|
||||
during the iteration, and a sign bit.*/
|
||||
z<<=5;
|
||||
/*w is the exponential in Q61 format (since it also needs headroom and can
|
||||
get as large as 2.0); we could get another bit if we dropped the sign,
|
||||
but we'll recover that bit later anyway.
|
||||
Ideally this should start out as
|
||||
\lim_{n->\infty} 2^{61}/\product_{i=1}^n \sqrt{1-2^{-2i}}
|
||||
but in order to guarantee convergence we have to repeat iterations 4,
|
||||
13 (=3*4+1), and 40 (=3*13+1, etc.), so it winds up somewhat larger.*/
|
||||
w=0x26A3D0E401DD846DLL;
|
||||
for(i=0;;i++){
|
||||
mask=-(z<0);
|
||||
w+=(w>>i+1)+mask^mask;
|
||||
z-=OC_ATANH_LOG2[i]+mask^mask;
|
||||
/*Repeat iteration 4.*/
|
||||
if(i>=3)break;
|
||||
z<<=1;
|
||||
}
|
||||
for(;;i++){
|
||||
mask=-(z<0);
|
||||
w+=(w>>i+1)+mask^mask;
|
||||
z-=OC_ATANH_LOG2[i]+mask^mask;
|
||||
/*Repeat iteration 13.*/
|
||||
if(i>=12)break;
|
||||
z<<=1;
|
||||
}
|
||||
for(;i<32;i++){
|
||||
mask=-(z<0);
|
||||
w+=(w>>i+1)+mask^mask;
|
||||
z=z-(OC_ATANH_LOG2[i]+mask^mask)<<1;
|
||||
}
|
||||
wlo=0;
|
||||
/*Skip the remaining iterations unless we really require that much
|
||||
precision.
|
||||
We could have bailed out earlier for smaller iparts, but that would
|
||||
require initializing w from a table, as the limit doesn't converge to
|
||||
61-bit precision until n=30.*/
|
||||
if(ipart>30){
|
||||
/*For these iterations, we just update the low bits, as the high bits
|
||||
can't possibly be affected.
|
||||
OC_ATANH_LOG2 has also converged (it actually did so one iteration
|
||||
earlier, but that's no reason for an extra special case).*/
|
||||
for(;;i++){
|
||||
mask=-(z<0);
|
||||
wlo+=(w>>i)+mask^mask;
|
||||
z-=OC_ATANH_LOG2[31]+mask^mask;
|
||||
/*Repeat iteration 40.*/
|
||||
if(i>=39)break;
|
||||
z<<=1;
|
||||
}
|
||||
for(;i<61;i++){
|
||||
mask=-(z<0);
|
||||
wlo+=(w>>i)+mask^mask;
|
||||
z=z-(OC_ATANH_LOG2[31]+mask^mask)<<1;
|
||||
}
|
||||
}
|
||||
w=(w<<1)+wlo;
|
||||
}
|
||||
else w=(ogg_int64_t)1<<62;
|
||||
if(ipart<62)w=(w>>61-ipart)+1>>1;
|
||||
return w;
|
||||
}
|
||||
|
||||
/*Computes the binary logarithm of _w, returned in Q57 format.*/
|
||||
ogg_int64_t oc_blog64(ogg_int64_t _w){
|
||||
ogg_int64_t z;
|
||||
int ipart;
|
||||
if(_w<=0)return -1;
|
||||
ipart=OC_ILOGNZ_64(_w)-1;
|
||||
if(ipart>61)_w>>=ipart-61;
|
||||
else _w<<=61-ipart;
|
||||
z=0;
|
||||
if(_w&_w-1){
|
||||
ogg_int64_t x;
|
||||
ogg_int64_t y;
|
||||
ogg_int64_t u;
|
||||
ogg_int64_t mask;
|
||||
int i;
|
||||
/*C doesn't give us 64x64->128 muls, so we use CORDIC.
|
||||
This is not particularly fast, but it's not being used in time-critical
|
||||
code; it is very accurate.*/
|
||||
/*z is the fractional part of the log in Q61 format.*/
|
||||
/*x and y are the cosh() and sinh(), respectively, in Q61 format.
|
||||
We are computing z=2*atanh(y/x)=2*atanh((_w-1)/(_w+1)).*/
|
||||
x=_w+((ogg_int64_t)1<<61);
|
||||
y=_w-((ogg_int64_t)1<<61);
|
||||
for(i=0;i<4;i++){
|
||||
mask=-(y<0);
|
||||
z+=(OC_ATANH_LOG2[i]>>i)+mask^mask;
|
||||
u=x>>i+1;
|
||||
x-=(y>>i+1)+mask^mask;
|
||||
y-=u+mask^mask;
|
||||
}
|
||||
/*Repeat iteration 4.*/
|
||||
for(i--;i<13;i++){
|
||||
mask=-(y<0);
|
||||
z+=(OC_ATANH_LOG2[i]>>i)+mask^mask;
|
||||
u=x>>i+1;
|
||||
x-=(y>>i+1)+mask^mask;
|
||||
y-=u+mask^mask;
|
||||
}
|
||||
/*Repeat iteration 13.*/
|
||||
for(i--;i<32;i++){
|
||||
mask=-(y<0);
|
||||
z+=(OC_ATANH_LOG2[i]>>i)+mask^mask;
|
||||
u=x>>i+1;
|
||||
x-=(y>>i+1)+mask^mask;
|
||||
y-=u+mask^mask;
|
||||
}
|
||||
/*OC_ATANH_LOG2 has converged.*/
|
||||
for(;i<40;i++){
|
||||
mask=-(y<0);
|
||||
z+=(OC_ATANH_LOG2[31]>>i)+mask^mask;
|
||||
u=x>>i+1;
|
||||
x-=(y>>i+1)+mask^mask;
|
||||
y-=u+mask^mask;
|
||||
}
|
||||
/*Repeat iteration 40.*/
|
||||
for(i--;i<62;i++){
|
||||
mask=-(y<0);
|
||||
z+=(OC_ATANH_LOG2[31]>>i)+mask^mask;
|
||||
u=x>>i+1;
|
||||
x-=(y>>i+1)+mask^mask;
|
||||
y-=u+mask^mask;
|
||||
}
|
||||
z=z+8>>4;
|
||||
}
|
||||
return OC_Q57(ipart)+z;
|
||||
}
|
||||
|
||||
/*Polynomial approximation of a binary exponential.
|
||||
Q10 input, Q0 output.*/
|
||||
ogg_uint32_t oc_bexp32_q10(int _z){
|
||||
unsigned n;
|
||||
int ipart;
|
||||
ipart=_z>>10;
|
||||
n=(_z&(1<<10)-1)<<4;
|
||||
n=(n*((n*((n*((n*3548>>15)+6817)>>15)+15823)>>15)+22708)>>15)+16384;
|
||||
return 14-ipart>0?n+(1<<13-ipart)>>14-ipart:n<<ipart-14;
|
||||
}
|
||||
|
||||
/*Polynomial approximation of a binary logarithm.
|
||||
Q0 input, Q10 output.*/
|
||||
int oc_blog32_q10(ogg_uint32_t _w){
|
||||
int n;
|
||||
int ipart;
|
||||
int fpart;
|
||||
if(_w<=0)return -1;
|
||||
ipart=OC_ILOGNZ_32(_w);
|
||||
n=(ipart-16>0?_w>>ipart-16:_w<<16-ipart)-32768-16384;
|
||||
fpart=(n*((n*((n*((n*-1402>>15)+2546)>>15)-5216)>>15)+15745)>>15)-6793;
|
||||
return (ipart<<10)+(fpart>>4);
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#if !defined(_mathops_H)
|
||||
# define _mathops_H (1)
|
||||
# include <ogg/ogg.h>
|
||||
|
||||
# ifdef __GNUC_PREREQ
|
||||
# if __GNUC_PREREQ(3,4)
|
||||
# include <limits.h>
|
||||
/*Note the casts to (int) below: this prevents OC_CLZ{32|64}_OFFS from
|
||||
"upgrading" the type of an entire expression to an (unsigned) size_t.*/
|
||||
# if INT_MAX>=2147483647
|
||||
# define OC_CLZ32_OFFS ((int)sizeof(unsigned)*CHAR_BIT)
|
||||
# define OC_CLZ32(_x) (__builtin_clz(_x))
|
||||
# elif LONG_MAX>=2147483647L
|
||||
# define OC_CLZ32_OFFS ((int)sizeof(unsigned long)*CHAR_BIT)
|
||||
# define OC_CLZ32(_x) (__builtin_clzl(_x))
|
||||
# endif
|
||||
# if INT_MAX>=9223372036854775807LL
|
||||
# define OC_CLZ64_OFFS ((int)sizeof(unsigned)*CHAR_BIT)
|
||||
# define OC_CLZ64(_x) (__builtin_clz(_x))
|
||||
# elif LONG_MAX>=9223372036854775807LL
|
||||
# define OC_CLZ64_OFFS ((int)sizeof(unsigned long)*CHAR_BIT)
|
||||
# define OC_CLZ64(_x) (__builtin_clzl(_x))
|
||||
# elif LLONG_MAX>=9223372036854775807LL|| \
|
||||
__LONG_LONG_MAX__>=9223372036854775807LL
|
||||
# define OC_CLZ64_OFFS ((int)sizeof(unsigned long long)*CHAR_BIT)
|
||||
# define OC_CLZ64(_x) (__builtin_clzll(_x))
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* oc_ilog32 - Integer binary logarithm of a 32-bit value.
|
||||
* @_v: A 32-bit value.
|
||||
* Returns floor(log2(_v))+1, or 0 if _v==0.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
* The OC_ILOG_32() or OC_ILOGNZ_32() macros may be able to use a builtin
|
||||
* function instead, which should be faster.
|
||||
*/
|
||||
int oc_ilog32(ogg_uint32_t _v);
|
||||
/**
|
||||
* oc_ilog64 - Integer binary logarithm of a 64-bit value.
|
||||
* @_v: A 64-bit value.
|
||||
* Returns floor(log2(_v))+1, or 0 if _v==0.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
* The OC_ILOG_64() or OC_ILOGNZ_64() macros may be able to use a builtin
|
||||
* function instead, which should be faster.
|
||||
*/
|
||||
int oc_ilog64(ogg_int64_t _v);
|
||||
|
||||
|
||||
# if defined(OC_CLZ32)
|
||||
/**
|
||||
* OC_ILOGNZ_32 - Integer binary logarithm of a non-zero 32-bit value.
|
||||
* @_v: A non-zero 32-bit value.
|
||||
* Returns floor(log2(_v))+1.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
* If _v is zero, the return value is undefined; use OC_ILOG_32() instead.
|
||||
*/
|
||||
# define OC_ILOGNZ_32(_v) (OC_CLZ32_OFFS-OC_CLZ32(_v))
|
||||
/**
|
||||
* OC_ILOG_32 - Integer binary logarithm of a 32-bit value.
|
||||
* @_v: A 32-bit value.
|
||||
* Returns floor(log2(_v))+1, or 0 if _v==0.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
*/
|
||||
# define OC_ILOG_32(_v) (OC_ILOGNZ_32(_v)&-!!(_v))
|
||||
# else
|
||||
# define OC_ILOGNZ_32(_v) (oc_ilog32(_v))
|
||||
# define OC_ILOG_32(_v) (oc_ilog32(_v))
|
||||
# endif
|
||||
|
||||
# if defined(CLZ64)
|
||||
/**
|
||||
* OC_ILOGNZ_64 - Integer binary logarithm of a non-zero 64-bit value.
|
||||
* @_v: A non-zero 64-bit value.
|
||||
* Returns floor(log2(_v))+1.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
* If _v is zero, the return value is undefined; use OC_ILOG_64() instead.
|
||||
*/
|
||||
# define OC_ILOGNZ_64(_v) (CLZ64_OFFS-CLZ64(_v))
|
||||
/**
|
||||
* OC_ILOG_64 - Integer binary logarithm of a 64-bit value.
|
||||
* @_v: A 64-bit value.
|
||||
* Returns floor(log2(_v))+1, or 0 if _v==0.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
*/
|
||||
# define OC_ILOG_64(_v) (OC_ILOGNZ_64(_v)&-!!(_v))
|
||||
# else
|
||||
# define OC_ILOGNZ_64(_v) (oc_ilog64(_v))
|
||||
# define OC_ILOG_64(_v) (oc_ilog64(_v))
|
||||
# endif
|
||||
|
||||
# define OC_STATIC_ILOG0(_v) (!!(_v))
|
||||
# define OC_STATIC_ILOG1(_v) (((_v)&0x2)?2:OC_STATIC_ILOG0(_v))
|
||||
# define OC_STATIC_ILOG2(_v) \
|
||||
(((_v)&0xC)?2+OC_STATIC_ILOG1((_v)>>2):OC_STATIC_ILOG1(_v))
|
||||
# define OC_STATIC_ILOG3(_v) \
|
||||
(((_v)&0xF0)?4+OC_STATIC_ILOG2((_v)>>4):OC_STATIC_ILOG2(_v))
|
||||
# define OC_STATIC_ILOG4(_v) \
|
||||
(((_v)&0xFF00)?8+OC_STATIC_ILOG3((_v)>>8):OC_STATIC_ILOG3(_v))
|
||||
# define OC_STATIC_ILOG5(_v) \
|
||||
(((_v)&0xFFFF0000)?16+OC_STATIC_ILOG4((_v)>>16):OC_STATIC_ILOG4(_v))
|
||||
# define OC_STATIC_ILOG6(_v) \
|
||||
(((_v)&0xFFFFFFFF00000000ULL)?32+OC_STATIC_ILOG5((_v)>>32):OC_STATIC_ILOG5(_v))
|
||||
/**
|
||||
* OC_STATIC_ILOG_32 - The integer logarithm of an (unsigned, 32-bit) constant.
|
||||
* @_v: A non-negative 32-bit constant.
|
||||
* Returns floor(log2(_v))+1, or 0 if _v==0.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
* This macro is suitable for evaluation at compile time, but it should not be
|
||||
* used on values that can change at runtime, as it operates via exhaustive
|
||||
* search.
|
||||
*/
|
||||
# define OC_STATIC_ILOG_32(_v) (OC_STATIC_ILOG5((ogg_uint32_t)(_v)))
|
||||
/**
|
||||
* OC_STATIC_ILOG_64 - The integer logarithm of an (unsigned, 64-bit) constant.
|
||||
* @_v: A non-negative 64-bit constant.
|
||||
* Returns floor(log2(_v))+1, or 0 if _v==0.
|
||||
* This is the number of bits that would be required to represent _v in two's
|
||||
* complement notation with all of the leading zeros stripped.
|
||||
* This macro is suitable for evaluation at compile time, but it should not be
|
||||
* used on values that can change at runtime, as it operates via exhaustive
|
||||
* search.
|
||||
*/
|
||||
# define OC_STATIC_ILOG_64(_v) (OC_STATIC_ILOG6((ogg_int64_t)(_v)))
|
||||
|
||||
#define OC_Q57(_v) ((ogg_int64_t)(_v)<<57)
|
||||
#define OC_Q10(_v) ((_v)<<10)
|
||||
|
||||
ogg_int64_t oc_bexp64(ogg_int64_t _z);
|
||||
ogg_int64_t oc_blog64(ogg_int64_t _w);
|
||||
|
||||
ogg_uint32_t oc_bexp32_q10(int _z);
|
||||
int oc_blog32_q10(ogg_uint32_t _w);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,777 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "encint.h"
|
||||
|
||||
|
||||
|
||||
typedef struct oc_mcenc_ctx oc_mcenc_ctx;
|
||||
|
||||
|
||||
|
||||
/*Temporary state used for motion estimation.*/
|
||||
struct oc_mcenc_ctx{
|
||||
/*The candidate motion vectors.*/
|
||||
int candidates[13][2];
|
||||
/*The start of the Set B candidates.*/
|
||||
int setb0;
|
||||
/*The total number of candidates.*/
|
||||
int ncandidates;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*The maximum Y plane SAD value for accepting the median predictor.*/
|
||||
#define OC_YSAD_THRESH1 (256)
|
||||
/*The amount to right shift the minimum error by when inflating it for
|
||||
computing the second maximum Y plane SAD threshold.*/
|
||||
#define OC_YSAD_THRESH2_SCALE_BITS (4)
|
||||
/*The amount to add to the second maximum Y plane threshold when inflating
|
||||
it.*/
|
||||
#define OC_YSAD_THRESH2_OFFSET (64)
|
||||
|
||||
/*The vector offsets in the X direction for each search site in the square
|
||||
pattern.*/
|
||||
static const int OC_SQUARE_DX[9]={-1,0,1,-1,0,1,-1,0,1};
|
||||
/*The vector offsets in the Y direction for each search site in the square
|
||||
pattern.*/
|
||||
static const int OC_SQUARE_DY[9]={-1,-1,-1,0,0,0,1,1,1};
|
||||
/*The number of sites to search for each boundary condition in the square
|
||||
pattern.
|
||||
Bit flags for the boundary conditions are as follows:
|
||||
1: -16==dx
|
||||
2: dx==15(.5)
|
||||
4: -16==dy
|
||||
8: dy==15(.5)*/
|
||||
static const int OC_SQUARE_NSITES[11]={8,5,5,0,5,3,3,0,5,3,3};
|
||||
/*The list of sites to search for each boundary condition in the square
|
||||
pattern.*/
|
||||
static const int OC_SQUARE_SITES[11][8]={
|
||||
/* -15.5<dx<31, -15.5<dy<15(.5)*/
|
||||
{0,1,2,3,5,6,7,8},
|
||||
/*-15.5==dx, -15.5<dy<15(.5)*/
|
||||
{1,2,5,7,8},
|
||||
/* dx==15(.5), -15.5<dy<15(.5)*/
|
||||
{0,1,3,6,7},
|
||||
/*-15.5==dx==15(.5), -15.5<dy<15(.5)*/
|
||||
{-1},
|
||||
/* -15.5<dx<15(.5), -15.5==dy*/
|
||||
{3,5,6,7,8},
|
||||
/*-15.5==dx, -15.5==dy*/
|
||||
{5,7,8},
|
||||
/* dx==15(.5), -15.5==dy*/
|
||||
{3,6,7},
|
||||
/*-15.5==dx==15(.5), -15.5==dy*/
|
||||
{-1},
|
||||
/*-15.5dx<15(.5), dy==15(.5)*/
|
||||
{0,1,2,3,5},
|
||||
/*-15.5==dx, dy==15(.5)*/
|
||||
{1,2,5},
|
||||
/* dx==15(.5), dy==15(.5)*/
|
||||
{0,1,3}
|
||||
};
|
||||
|
||||
|
||||
static void oc_mcenc_find_candidates(oc_enc_ctx *_enc,oc_mcenc_ctx *_mcenc,
|
||||
oc_mv _accum,int _mbi,int _frame){
|
||||
oc_mb_enc_info *embs;
|
||||
int accum_x;
|
||||
int accum_y;
|
||||
int a[3][2];
|
||||
int ncandidates;
|
||||
unsigned nmbi;
|
||||
int i;
|
||||
embs=_enc->mb_info;
|
||||
/*Skip a position to store the median predictor in.*/
|
||||
ncandidates=1;
|
||||
if(embs[_mbi].ncneighbors>0){
|
||||
/*Fill in the first part of set A: the vectors from adjacent blocks.*/
|
||||
for(i=0;i<embs[_mbi].ncneighbors;i++){
|
||||
nmbi=embs[_mbi].cneighbors[i];
|
||||
_mcenc->candidates[ncandidates][0]=
|
||||
OC_MV_X(embs[nmbi].analysis_mv[0][_frame]);
|
||||
_mcenc->candidates[ncandidates][1]=
|
||||
OC_MV_Y(embs[nmbi].analysis_mv[0][_frame]);
|
||||
ncandidates++;
|
||||
}
|
||||
}
|
||||
accum_x=OC_MV_X(_accum);
|
||||
accum_y=OC_MV_Y(_accum);
|
||||
/*Add a few additional vectors to set A: the vectors used in the previous
|
||||
frames and the (0,0) vector.*/
|
||||
_mcenc->candidates[ncandidates][0]=OC_CLAMPI(-31,accum_x,31);
|
||||
_mcenc->candidates[ncandidates][1]=OC_CLAMPI(-31,accum_y,31);
|
||||
ncandidates++;
|
||||
_mcenc->candidates[ncandidates][0]=OC_CLAMPI(-31,
|
||||
OC_MV_X(embs[_mbi].analysis_mv[1][_frame])+accum_x,31);
|
||||
_mcenc->candidates[ncandidates][1]=OC_CLAMPI(-31,
|
||||
OC_MV_Y(embs[_mbi].analysis_mv[1][_frame])+accum_y,31);
|
||||
ncandidates++;
|
||||
_mcenc->candidates[ncandidates][0]=0;
|
||||
_mcenc->candidates[ncandidates][1]=0;
|
||||
ncandidates++;
|
||||
/*Use the first three vectors of set A to find our best predictor: their
|
||||
median.*/
|
||||
memcpy(a,_mcenc->candidates+1,sizeof(a));
|
||||
OC_SORT2I(a[0][0],a[1][0]);
|
||||
OC_SORT2I(a[0][1],a[1][1]);
|
||||
OC_SORT2I(a[1][0],a[2][0]);
|
||||
OC_SORT2I(a[1][1],a[2][1]);
|
||||
OC_SORT2I(a[0][0],a[1][0]);
|
||||
OC_SORT2I(a[0][1],a[1][1]);
|
||||
_mcenc->candidates[0][0]=a[1][0];
|
||||
_mcenc->candidates[0][1]=a[1][1];
|
||||
/*Fill in set B: accelerated predictors for this and adjacent macro blocks.*/
|
||||
_mcenc->setb0=ncandidates;
|
||||
/*The first time through the loop use the current macro block.*/
|
||||
nmbi=_mbi;
|
||||
for(i=0;;i++){
|
||||
_mcenc->candidates[ncandidates][0]=OC_CLAMPI(-31,
|
||||
2*OC_MV_X(embs[_mbi].analysis_mv[1][_frame])
|
||||
-OC_MV_X(embs[_mbi].analysis_mv[2][_frame])+accum_x,31);
|
||||
_mcenc->candidates[ncandidates][1]=OC_CLAMPI(-31,
|
||||
2*OC_MV_Y(embs[_mbi].analysis_mv[1][_frame])
|
||||
-OC_MV_Y(embs[_mbi].analysis_mv[2][_frame])+accum_y,31);
|
||||
ncandidates++;
|
||||
if(i>=embs[_mbi].npneighbors)break;
|
||||
nmbi=embs[_mbi].pneighbors[i];
|
||||
}
|
||||
/*Truncate to full-pel positions.*/
|
||||
for(i=0;i<ncandidates;i++){
|
||||
_mcenc->candidates[i][0]=OC_DIV2(_mcenc->candidates[i][0]);
|
||||
_mcenc->candidates[i][1]=OC_DIV2(_mcenc->candidates[i][1]);
|
||||
}
|
||||
_mcenc->ncandidates=ncandidates;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned oc_sad16_halfpel(const oc_enc_ctx *_enc,
|
||||
const ptrdiff_t *_frag_buf_offs,const ptrdiff_t _fragis[4],
|
||||
int _mvoffset0,int _mvoffset1,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,unsigned _best_err){
|
||||
unsigned err;
|
||||
int bi;
|
||||
err=0;
|
||||
for(bi=0;bi<4;bi++){
|
||||
ptrdiff_t frag_offs;
|
||||
frag_offs=_frag_buf_offs[_fragis[bi]];
|
||||
err+=oc_enc_frag_sad2_thresh(_enc,_src+frag_offs,_ref+frag_offs+_mvoffset0,
|
||||
_ref+frag_offs+_mvoffset1,_ystride,_best_err-err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned oc_satd16_halfpel(const oc_enc_ctx *_enc,
|
||||
const ptrdiff_t *_frag_buf_offs,const ptrdiff_t _fragis[4],
|
||||
int _mvoffset0,int _mvoffset1,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,unsigned _best_err){
|
||||
unsigned err;
|
||||
unsigned dc;
|
||||
int bi;
|
||||
err=0;
|
||||
for(bi=0;bi<4;bi++){
|
||||
ptrdiff_t frag_offs;
|
||||
frag_offs=_frag_buf_offs[_fragis[bi]];
|
||||
err+=oc_enc_frag_satd2(_enc,&dc,_src+frag_offs,
|
||||
_ref+frag_offs+_mvoffset0,_ref+frag_offs+_mvoffset1,_ystride);
|
||||
err+=dc;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static unsigned oc_mcenc_ysad_check_mbcandidate_fullpel(const oc_enc_ctx *_enc,
|
||||
const ptrdiff_t *_frag_buf_offs,const ptrdiff_t _fragis[4],int _dx,int _dy,
|
||||
const unsigned char *_src,const unsigned char *_ref,int _ystride,
|
||||
unsigned _block_err[4]){
|
||||
unsigned err;
|
||||
int mvoffset;
|
||||
int bi;
|
||||
mvoffset=_dx+_dy*_ystride;
|
||||
err=0;
|
||||
for(bi=0;bi<4;bi++){
|
||||
ptrdiff_t frag_offs;
|
||||
unsigned block_err;
|
||||
frag_offs=_frag_buf_offs[_fragis[bi]];
|
||||
block_err=oc_enc_frag_sad(_enc,
|
||||
_src+frag_offs,_ref+frag_offs+mvoffset,_ystride);
|
||||
_block_err[bi]=block_err;
|
||||
err+=block_err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int oc_mcenc_ysatd_check_mbcandidate_fullpel(const oc_enc_ctx *_enc,
|
||||
const ptrdiff_t *_frag_buf_offs,const ptrdiff_t _fragis[4],int _dx,int _dy,
|
||||
const unsigned char *_src,const unsigned char *_ref,int _ystride){
|
||||
int mvoffset;
|
||||
int err;
|
||||
int bi;
|
||||
mvoffset=_dx+_dy*_ystride;
|
||||
err=0;
|
||||
for(bi=0;bi<4;bi++){
|
||||
ptrdiff_t frag_offs;
|
||||
unsigned dc;
|
||||
frag_offs=_frag_buf_offs[_fragis[bi]];
|
||||
err+=oc_enc_frag_satd(_enc,&dc,
|
||||
_src+frag_offs,_ref+frag_offs+mvoffset,_ystride);
|
||||
err+=dc;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static unsigned oc_mcenc_ysatd_check_bcandidate_fullpel(const oc_enc_ctx *_enc,
|
||||
ptrdiff_t _frag_offs,int _dx,int _dy,
|
||||
const unsigned char *_src,const unsigned char *_ref,int _ystride){
|
||||
unsigned err;
|
||||
unsigned dc;
|
||||
err=oc_enc_frag_satd(_enc,&dc,
|
||||
_src+_frag_offs,_ref+_frag_offs+_dx+_dy*_ystride,_ystride);
|
||||
return err+dc;
|
||||
}
|
||||
|
||||
/*Perform a motion vector search for this macro block against a single
|
||||
reference frame.
|
||||
As a bonus, individual block motion vectors are computed as well, as much of
|
||||
the work can be shared.
|
||||
The actual motion vector is stored in the appropriate place in the
|
||||
oc_mb_enc_info structure.
|
||||
_accum: Drop frame/golden MV accumulators.
|
||||
_mbi: The macro block index.
|
||||
_frame: The frame to use for SATD calculations and refinement,
|
||||
either OC_FRAME_PREV or OC_FRAME_GOLD.
|
||||
_frame_full: The frame to perform the 1px search on, one of OC_FRAME_PREV,
|
||||
OC_FRAME_GOLD, OC_FRAME_PREV_ORIG, or OC_FRAME_GOLD_ORIG.*/
|
||||
void oc_mcenc_search_frame(oc_enc_ctx *_enc,oc_mv _accum,int _mbi,int _frame,
|
||||
int _frame_full){
|
||||
/*Note: Traditionally this search is done using a rate-distortion objective
|
||||
function of the form D+lambda*R.
|
||||
However, xiphmont tested this and found it produced a small degredation,
|
||||
while requiring extra computation.
|
||||
This is most likely due to Theora's peculiar MV encoding scheme: MVs are
|
||||
not coded relative to a predictor, and the only truly cheap way to use a
|
||||
MV is in the LAST or LAST2 MB modes, which are not being considered here.
|
||||
Therefore if we use the MV found here, it's only because both LAST and
|
||||
LAST2 performed poorly, and therefore the MB is not likely to be uniform
|
||||
or suffer from the aperture problem.
|
||||
Furthermore we would like to re-use the MV found here for as many MBs as
|
||||
possible, so picking a slightly sub-optimal vector to save a bit or two
|
||||
may cause increased degredation in many blocks to come.
|
||||
We could artificially reduce lambda to compensate, but it's faster to just
|
||||
disable it entirely, and use D (the distortion) as the sole criterion.*/
|
||||
oc_mcenc_ctx mcenc;
|
||||
const ptrdiff_t *frag_buf_offs;
|
||||
const ptrdiff_t *fragis;
|
||||
const unsigned char *src;
|
||||
const unsigned char *ref;
|
||||
const unsigned char *satd_ref;
|
||||
int ystride;
|
||||
oc_mb_enc_info *embs;
|
||||
ogg_int32_t hit_cache[31];
|
||||
ogg_int32_t hitbit;
|
||||
unsigned best_block_err[4];
|
||||
unsigned block_err[4];
|
||||
unsigned best_err;
|
||||
int best_vec[2];
|
||||
int best_block_vec[4][2];
|
||||
int candx;
|
||||
int candy;
|
||||
int bi;
|
||||
embs=_enc->mb_info;
|
||||
/*Find some candidate motion vectors.*/
|
||||
oc_mcenc_find_candidates(_enc,&mcenc,_accum,_mbi,_frame);
|
||||
/*Clear the cache of locations we've examined.*/
|
||||
memset(hit_cache,0,sizeof(hit_cache));
|
||||
/*Start with the median predictor.*/
|
||||
candx=mcenc.candidates[0][0];
|
||||
candy=mcenc.candidates[0][1];
|
||||
hit_cache[candy+15]|=(ogg_int32_t)1<<candx+15;
|
||||
frag_buf_offs=_enc->state.frag_buf_offs;
|
||||
fragis=_enc->state.mb_maps[_mbi][0];
|
||||
src=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[OC_FRAME_IO]];
|
||||
ref=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[_frame_full]];
|
||||
satd_ref=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[_frame]];
|
||||
ystride=_enc->state.ref_ystride[0];
|
||||
/*TODO: customize error function for speed/(quality+size) tradeoff.*/
|
||||
best_err=oc_mcenc_ysad_check_mbcandidate_fullpel(_enc,
|
||||
frag_buf_offs,fragis,candx,candy,src,ref,ystride,block_err);
|
||||
best_vec[0]=candx;
|
||||
best_vec[1]=candy;
|
||||
if(_frame==OC_FRAME_PREV){
|
||||
for(bi=0;bi<4;bi++){
|
||||
best_block_err[bi]=block_err[bi];
|
||||
best_block_vec[bi][0]=candx;
|
||||
best_block_vec[bi][1]=candy;
|
||||
}
|
||||
}
|
||||
/*If this predictor fails, move on to set A.*/
|
||||
if(best_err>OC_YSAD_THRESH1){
|
||||
unsigned err;
|
||||
unsigned t2;
|
||||
int ncs;
|
||||
int ci;
|
||||
/*Compute the early termination threshold for set A.*/
|
||||
t2=embs[_mbi].error[_frame];
|
||||
ncs=OC_MINI(3,embs[_mbi].ncneighbors);
|
||||
for(ci=0;ci<ncs;ci++){
|
||||
t2=OC_MAXI(t2,embs[embs[_mbi].cneighbors[ci]].error[_frame]);
|
||||
}
|
||||
t2+=(t2>>OC_YSAD_THRESH2_SCALE_BITS)+OC_YSAD_THRESH2_OFFSET;
|
||||
/*Examine the candidates in set A.*/
|
||||
for(ci=1;ci<mcenc.setb0;ci++){
|
||||
candx=mcenc.candidates[ci][0];
|
||||
candy=mcenc.candidates[ci][1];
|
||||
/*If we've already examined this vector, then we would be using it if it
|
||||
was better than what we are using.*/
|
||||
hitbit=(ogg_int32_t)1<<candx+15;
|
||||
if(hit_cache[candy+15]&hitbit)continue;
|
||||
hit_cache[candy+15]|=hitbit;
|
||||
err=oc_mcenc_ysad_check_mbcandidate_fullpel(_enc,
|
||||
frag_buf_offs,fragis,candx,candy,src,ref,ystride,block_err);
|
||||
if(err<best_err){
|
||||
best_err=err;
|
||||
best_vec[0]=candx;
|
||||
best_vec[1]=candy;
|
||||
}
|
||||
if(_frame==OC_FRAME_PREV){
|
||||
for(bi=0;bi<4;bi++)if(block_err[bi]<best_block_err[bi]){
|
||||
best_block_err[bi]=block_err[bi];
|
||||
best_block_vec[bi][0]=candx;
|
||||
best_block_vec[bi][1]=candy;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(best_err>t2){
|
||||
/*Examine the candidates in set B.*/
|
||||
for(;ci<mcenc.ncandidates;ci++){
|
||||
candx=mcenc.candidates[ci][0];
|
||||
candy=mcenc.candidates[ci][1];
|
||||
hitbit=(ogg_int32_t)1<<candx+15;
|
||||
if(hit_cache[candy+15]&hitbit)continue;
|
||||
hit_cache[candy+15]|=hitbit;
|
||||
err=oc_mcenc_ysad_check_mbcandidate_fullpel(_enc,
|
||||
frag_buf_offs,fragis,candx,candy,src,ref,ystride,block_err);
|
||||
if(err<best_err){
|
||||
best_err=err;
|
||||
best_vec[0]=candx;
|
||||
best_vec[1]=candy;
|
||||
}
|
||||
if(_frame==OC_FRAME_PREV){
|
||||
for(bi=0;bi<4;bi++)if(block_err[bi]<best_block_err[bi]){
|
||||
best_block_err[bi]=block_err[bi];
|
||||
best_block_vec[bi][0]=candx;
|
||||
best_block_vec[bi][1]=candy;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Use the same threshold for set B as in set A.*/
|
||||
if(best_err>t2){
|
||||
int best_site;
|
||||
int nsites;
|
||||
int sitei;
|
||||
int site;
|
||||
int b;
|
||||
/*Square pattern search.*/
|
||||
for(;;){
|
||||
best_site=4;
|
||||
/*Compose the bit flags for boundary conditions.*/
|
||||
b=OC_DIV16(-best_vec[0]+1)|OC_DIV16(best_vec[0]+1)<<1|
|
||||
OC_DIV16(-best_vec[1]+1)<<2|OC_DIV16(best_vec[1]+1)<<3;
|
||||
nsites=OC_SQUARE_NSITES[b];
|
||||
for(sitei=0;sitei<nsites;sitei++){
|
||||
site=OC_SQUARE_SITES[b][sitei];
|
||||
candx=best_vec[0]+OC_SQUARE_DX[site];
|
||||
candy=best_vec[1]+OC_SQUARE_DY[site];
|
||||
hitbit=(ogg_int32_t)1<<candx+15;
|
||||
if(hit_cache[candy+15]&hitbit)continue;
|
||||
hit_cache[candy+15]|=hitbit;
|
||||
err=oc_mcenc_ysad_check_mbcandidate_fullpel(_enc,
|
||||
frag_buf_offs,fragis,candx,candy,src,ref,ystride,block_err);
|
||||
if(err<best_err){
|
||||
best_err=err;
|
||||
best_site=site;
|
||||
}
|
||||
if(_frame==OC_FRAME_PREV){
|
||||
for(bi=0;bi<4;bi++)if(block_err[bi]<best_block_err[bi]){
|
||||
best_block_err[bi]=block_err[bi];
|
||||
best_block_vec[bi][0]=candx;
|
||||
best_block_vec[bi][1]=candy;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(best_site==4)break;
|
||||
best_vec[0]+=OC_SQUARE_DX[best_site];
|
||||
best_vec[1]+=OC_SQUARE_DY[best_site];
|
||||
}
|
||||
/*Final 4-MV search.*/
|
||||
/*Simply use 1/4 of the macro block set A and B threshold as the
|
||||
individual block threshold.*/
|
||||
if(_frame==OC_FRAME_PREV){
|
||||
t2>>=2;
|
||||
for(bi=0;bi<4;bi++){
|
||||
if(best_block_err[bi]>t2){
|
||||
/*Square pattern search.
|
||||
We do this in a slightly interesting manner.
|
||||
We continue to check the SAD of all four blocks in the
|
||||
macro block.
|
||||
This gives us two things:
|
||||
1) We can continue to use the hit_cache to avoid duplicate
|
||||
checks.
|
||||
Otherwise we could continue to read it, but not write to it
|
||||
without saving and restoring it for each block.
|
||||
Note that we could still eliminate a large number of
|
||||
duplicate checks by taking into account the site we came
|
||||
from when choosing the site list.
|
||||
We can still do that to avoid extra hit_cache queries, and
|
||||
it might even be a speed win.
|
||||
2) It gives us a slightly better chance of escaping local
|
||||
minima.
|
||||
We would not be here if we weren't doing a fairly bad job
|
||||
in finding a good vector, and checking these vectors can
|
||||
save us from 100 to several thousand points off our SAD 1
|
||||
in 15 times.
|
||||
TODO: Is this a good idea?
|
||||
Who knows.
|
||||
It needs more testing.*/
|
||||
for(;;){
|
||||
int bestx;
|
||||
int besty;
|
||||
int bj;
|
||||
bestx=best_block_vec[bi][0];
|
||||
besty=best_block_vec[bi][1];
|
||||
/*Compose the bit flags for boundary conditions.*/
|
||||
b=OC_DIV16(-bestx+1)|OC_DIV16(bestx+1)<<1|
|
||||
OC_DIV16(-besty+1)<<2|OC_DIV16(besty+1)<<3;
|
||||
nsites=OC_SQUARE_NSITES[b];
|
||||
for(sitei=0;sitei<nsites;sitei++){
|
||||
site=OC_SQUARE_SITES[b][sitei];
|
||||
candx=bestx+OC_SQUARE_DX[site];
|
||||
candy=besty+OC_SQUARE_DY[site];
|
||||
hitbit=(ogg_int32_t)1<<candx+15;
|
||||
if(hit_cache[candy+15]&hitbit)continue;
|
||||
hit_cache[candy+15]|=hitbit;
|
||||
err=oc_mcenc_ysad_check_mbcandidate_fullpel(_enc,
|
||||
frag_buf_offs,fragis,candx,candy,src,ref,ystride,block_err);
|
||||
if(err<best_err){
|
||||
best_err=err;
|
||||
best_vec[0]=candx;
|
||||
best_vec[1]=candy;
|
||||
}
|
||||
for(bj=0;bj<4;bj++)if(block_err[bj]<best_block_err[bj]){
|
||||
best_block_err[bj]=block_err[bj];
|
||||
best_block_vec[bj][0]=candx;
|
||||
best_block_vec[bj][1]=candy;
|
||||
}
|
||||
}
|
||||
if(best_block_vec[bi][0]==bestx&&best_block_vec[bi][1]==besty){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
embs[_mbi].error[_frame]=(ogg_uint16_t)best_err;
|
||||
candx=best_vec[0];
|
||||
candy=best_vec[1];
|
||||
embs[_mbi].satd[_frame]=oc_mcenc_ysatd_check_mbcandidate_fullpel(_enc,
|
||||
frag_buf_offs,fragis,candx,candy,src,satd_ref,ystride);
|
||||
embs[_mbi].analysis_mv[0][_frame]=OC_MV(candx<<1,candy<<1);
|
||||
if(_frame==OC_FRAME_PREV){
|
||||
for(bi=0;bi<4;bi++){
|
||||
candx=best_block_vec[bi][0];
|
||||
candy=best_block_vec[bi][1];
|
||||
embs[_mbi].block_satd[bi]=oc_mcenc_ysatd_check_bcandidate_fullpel(_enc,
|
||||
frag_buf_offs[fragis[bi]],candx,candy,src,satd_ref,ystride);
|
||||
embs[_mbi].block_mv[bi]=OC_MV(candx<<1,candy<<1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void oc_mcenc_search(oc_enc_ctx *_enc,int _mbi){
|
||||
oc_mv2 *mvs;
|
||||
oc_mv accum_p;
|
||||
oc_mv accum_g;
|
||||
oc_mv mv2_p;
|
||||
mvs=_enc->mb_info[_mbi].analysis_mv;
|
||||
if(_enc->prevframe_dropped)accum_p=mvs[0][OC_FRAME_PREV];
|
||||
else accum_p=0;
|
||||
accum_g=mvs[2][OC_FRAME_GOLD];
|
||||
/*Move the motion vector predictors back a frame.*/
|
||||
mv2_p=mvs[2][OC_FRAME_PREV];
|
||||
mvs[2][OC_FRAME_GOLD]=mvs[1][OC_FRAME_GOLD];
|
||||
mvs[2][OC_FRAME_PREV]=mvs[1][OC_FRAME_PREV];
|
||||
mvs[1][OC_FRAME_GOLD]=mvs[0][OC_FRAME_GOLD];
|
||||
mvs[1][OC_FRAME_PREV]=OC_MV_SUB(mvs[0][OC_FRAME_PREV],mv2_p);
|
||||
/*Search the last frame.*/
|
||||
oc_mcenc_search_frame(_enc,accum_p,_mbi,OC_FRAME_PREV,OC_FRAME_PREV_ORIG);
|
||||
mvs[2][OC_FRAME_PREV]=accum_p;
|
||||
/*GOLDEN MVs are different from PREV MVs in that they're each absolute
|
||||
offsets from some frame in the past rather than relative offsets from the
|
||||
frame before.
|
||||
For predictor calculation to make sense, we need them to be in the same
|
||||
form as PREV MVs.*/
|
||||
mvs[1][OC_FRAME_GOLD]=OC_MV_SUB(mvs[1][OC_FRAME_GOLD],mvs[2][OC_FRAME_GOLD]);
|
||||
mvs[2][OC_FRAME_GOLD]=OC_MV_SUB(mvs[2][OC_FRAME_GOLD],accum_g);
|
||||
/*Search the golden frame.*/
|
||||
oc_mcenc_search_frame(_enc,accum_g,_mbi,OC_FRAME_GOLD,OC_FRAME_GOLD_ORIG);
|
||||
/*Put GOLDEN MVs back into absolute offset form.
|
||||
The newest MV is already an absolute offset.*/
|
||||
mvs[2][OC_FRAME_GOLD]=OC_MV_ADD(mvs[2][OC_FRAME_GOLD],accum_g);
|
||||
mvs[1][OC_FRAME_GOLD]=OC_MV_ADD(mvs[1][OC_FRAME_GOLD],mvs[2][OC_FRAME_GOLD]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int oc_mcenc_ysad_halfpel_mbrefine(const oc_enc_ctx *_enc,int _mbi,
|
||||
int _vec[2],int _best_err,int _frame){
|
||||
const unsigned char *src;
|
||||
const unsigned char *ref;
|
||||
const ptrdiff_t *frag_buf_offs;
|
||||
const ptrdiff_t *fragis;
|
||||
int offset_y[9];
|
||||
int ystride;
|
||||
int mvoffset_base;
|
||||
int best_site;
|
||||
int sitei;
|
||||
int err;
|
||||
src=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[OC_FRAME_IO]];
|
||||
ref=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[_framei]];
|
||||
frag_buf_offs=_enc->state.frag_buf_offs;
|
||||
fragis=_enc->state.mb_maps[_mbi][0];
|
||||
ystride=_enc->state.ref_ystride[0];
|
||||
mvoffset_base=_vec[0]+_vec[1]*ystride;
|
||||
offset_y[0]=offset_y[1]=offset_y[2]=-ystride;
|
||||
offset_y[3]=offset_y[5]=0;
|
||||
offset_y[6]=offset_y[7]=offset_y[8]=ystride;
|
||||
best_site=4;
|
||||
for(sitei=0;sitei<8;sitei++){
|
||||
int site;
|
||||
int xmask;
|
||||
int ymask;
|
||||
int dx;
|
||||
int dy;
|
||||
int mvoffset0;
|
||||
int mvoffset1;
|
||||
site=OC_SQUARE_SITES[0][sitei];
|
||||
dx=OC_SQUARE_DX[site];
|
||||
dy=OC_SQUARE_DY[site];
|
||||
/*The following code SHOULD be equivalent to
|
||||
oc_state_get_mv_offsets(&_mcenc->enc.state,&mvoffset0,&mvoffset1,
|
||||
(_vec[0]<<1)+dx,(_vec[1]<<1)+dy,ref_ystride,0);
|
||||
However, it should also be much faster, as it involves no multiplies and
|
||||
doesn't have to handle chroma vectors.*/
|
||||
xmask=OC_SIGNMASK(((_vec[0]<<1)+dx)^dx);
|
||||
ymask=OC_SIGNMASK(((_vec[1]<<1)+dy)^dy);
|
||||
mvoffset0=mvoffset_base+(dx&xmask)+(offset_y[site]&ymask);
|
||||
mvoffset1=mvoffset_base+(dx&~xmask)+(offset_y[site]&~ymask);
|
||||
err=oc_sad16_halfpel(_enc,frag_buf_offs,fragis,
|
||||
mvoffset0,mvoffset1,src,ref,ystride,_best_err);
|
||||
if(err<_best_err){
|
||||
_best_err=err;
|
||||
best_site=site;
|
||||
}
|
||||
}
|
||||
_vec[0]=(_vec[0]<<1)+OC_SQUARE_DX[best_site];
|
||||
_vec[1]=(_vec[1]<<1)+OC_SQUARE_DY[best_site];
|
||||
return _best_err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned oc_mcenc_ysatd_halfpel_mbrefine(const oc_enc_ctx *_enc,
|
||||
int _mbi,int _vec[2],unsigned _best_err,int _frame){
|
||||
const unsigned char *src;
|
||||
const unsigned char *ref;
|
||||
const ptrdiff_t *frag_buf_offs;
|
||||
const ptrdiff_t *fragis;
|
||||
int offset_y[9];
|
||||
int ystride;
|
||||
int mvoffset_base;
|
||||
int best_site;
|
||||
int sitei;
|
||||
int err;
|
||||
src=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[OC_FRAME_IO]];
|
||||
ref=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[_frame]];
|
||||
frag_buf_offs=_enc->state.frag_buf_offs;
|
||||
fragis=_enc->state.mb_maps[_mbi][0];
|
||||
ystride=_enc->state.ref_ystride[0];
|
||||
mvoffset_base=_vec[0]+_vec[1]*ystride;
|
||||
offset_y[0]=offset_y[1]=offset_y[2]=-ystride;
|
||||
offset_y[3]=offset_y[5]=0;
|
||||
offset_y[6]=offset_y[7]=offset_y[8]=ystride;
|
||||
best_site=4;
|
||||
for(sitei=0;sitei<8;sitei++){
|
||||
int site;
|
||||
int xmask;
|
||||
int ymask;
|
||||
int dx;
|
||||
int dy;
|
||||
int mvoffset0;
|
||||
int mvoffset1;
|
||||
site=OC_SQUARE_SITES[0][sitei];
|
||||
dx=OC_SQUARE_DX[site];
|
||||
dy=OC_SQUARE_DY[site];
|
||||
/*The following code SHOULD be equivalent to
|
||||
oc_state_get_mv_offsets(&_mcenc->enc.state,&mvoffset0,&mvoffset1,
|
||||
(_vec[0]<<1)+dx,(_vec[1]<<1)+dy,ref_ystride,0);
|
||||
However, it should also be much faster, as it involves no multiplies and
|
||||
doesn't have to handle chroma vectors.*/
|
||||
xmask=OC_SIGNMASK(((_vec[0]<<1)+dx)^dx);
|
||||
ymask=OC_SIGNMASK(((_vec[1]<<1)+dy)^dy);
|
||||
mvoffset0=mvoffset_base+(dx&xmask)+(offset_y[site]&ymask);
|
||||
mvoffset1=mvoffset_base+(dx&~xmask)+(offset_y[site]&~ymask);
|
||||
err=oc_satd16_halfpel(_enc,frag_buf_offs,fragis,
|
||||
mvoffset0,mvoffset1,src,ref,ystride,_best_err);
|
||||
if(err<_best_err){
|
||||
_best_err=err;
|
||||
best_site=site;
|
||||
}
|
||||
}
|
||||
_vec[0]=(_vec[0]<<1)+OC_SQUARE_DX[best_site];
|
||||
_vec[1]=(_vec[1]<<1)+OC_SQUARE_DY[best_site];
|
||||
return _best_err;
|
||||
}
|
||||
|
||||
void oc_mcenc_refine1mv(oc_enc_ctx *_enc,int _mbi,int _frame){
|
||||
oc_mb_enc_info *embs;
|
||||
int vec[2];
|
||||
embs=_enc->mb_info;
|
||||
vec[0]=OC_DIV2(OC_MV_X(embs[_mbi].analysis_mv[0][_frame]));
|
||||
vec[1]=OC_DIV2(OC_MV_Y(embs[_mbi].analysis_mv[0][_frame]));
|
||||
embs[_mbi].satd[_frame]=oc_mcenc_ysatd_halfpel_mbrefine(_enc,
|
||||
_mbi,vec,embs[_mbi].satd[_frame],_frame);
|
||||
embs[_mbi].analysis_mv[0][_frame]=OC_MV(vec[0],vec[1]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int oc_mcenc_ysad_halfpel_brefine(const oc_enc_ctx *_enc,
|
||||
int _vec[2],const unsigned char *_src,const unsigned char *_ref,int _ystride,
|
||||
int _offset_y[9],unsigned _best_err){
|
||||
int mvoffset_base;
|
||||
int best_site;
|
||||
int sitei;
|
||||
mvoffset_base=_vec[0]+_vec[1]*_ystride;
|
||||
best_site=4;
|
||||
for(sitei=0;sitei<8;sitei++){
|
||||
unsigned err;
|
||||
int site;
|
||||
int xmask;
|
||||
int ymask;
|
||||
int dx;
|
||||
int dy;
|
||||
int mvoffset0;
|
||||
int mvoffset1;
|
||||
site=OC_SQUARE_SITES[0][sitei];
|
||||
dx=OC_SQUARE_DX[site];
|
||||
dy=OC_SQUARE_DY[site];
|
||||
/*The following code SHOULD be equivalent to
|
||||
oc_state_get_mv_offsets(&_mcenc->enc.state,&mvoffset0,&mvoffset1,
|
||||
(_vec[0]<<1)+dx,(_vec[1]<<1)+dy,ref_ystride,0);
|
||||
However, it should also be much faster, as it involves no multiplies and
|
||||
doesn't have to handle chroma vectors.*/
|
||||
xmask=OC_SIGNMASK(((_vec[0]<<1)+dx)^dx);
|
||||
ymask=OC_SIGNMASK(((_vec[1]<<1)+dy)^dy);
|
||||
mvoffset0=mvoffset_base+(dx&xmask)+(_offset_y[site]&ymask);
|
||||
mvoffset1=mvoffset_base+(dx&~xmask)+(_offset_y[site]&~ymask);
|
||||
err=oc_enc_frag_sad2_thresh(_enc,_src,
|
||||
_ref+mvoffset0,_ref+mvoffset1,ystride,_best_err);
|
||||
if(err<_best_err){
|
||||
_best_err=err;
|
||||
best_site=site;
|
||||
}
|
||||
}
|
||||
_vec[0]=(_vec[0]<<1)+OC_SQUARE_DX[best_site];
|
||||
_vec[1]=(_vec[1]<<1)+OC_SQUARE_DY[best_site];
|
||||
return _best_err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned oc_mcenc_ysatd_halfpel_brefine(const oc_enc_ctx *_enc,
|
||||
int _vec[2],const unsigned char *_src,const unsigned char *_ref,int _ystride,
|
||||
int _offset_y[9],unsigned _best_err){
|
||||
int mvoffset_base;
|
||||
int best_site;
|
||||
int sitei;
|
||||
mvoffset_base=_vec[0]+_vec[1]*_ystride;
|
||||
best_site=4;
|
||||
for(sitei=0;sitei<8;sitei++){
|
||||
unsigned err;
|
||||
unsigned dc;
|
||||
int site;
|
||||
int xmask;
|
||||
int ymask;
|
||||
int dx;
|
||||
int dy;
|
||||
int mvoffset0;
|
||||
int mvoffset1;
|
||||
site=OC_SQUARE_SITES[0][sitei];
|
||||
dx=OC_SQUARE_DX[site];
|
||||
dy=OC_SQUARE_DY[site];
|
||||
/*The following code SHOULD be equivalent to
|
||||
oc_state_get_mv_offsets(&_enc->state,&mvoffsets,0,
|
||||
(_vec[0]<<1)+dx,(_vec[1]<<1)+dy);
|
||||
However, it should also be much faster, as it involves no multiplies and
|
||||
doesn't have to handle chroma vectors.*/
|
||||
xmask=OC_SIGNMASK(((_vec[0]<<1)+dx)^dx);
|
||||
ymask=OC_SIGNMASK(((_vec[1]<<1)+dy)^dy);
|
||||
mvoffset0=mvoffset_base+(dx&xmask)+(_offset_y[site]&ymask);
|
||||
mvoffset1=mvoffset_base+(dx&~xmask)+(_offset_y[site]&~ymask);
|
||||
err=oc_enc_frag_satd2(_enc,&dc,_src,
|
||||
_ref+mvoffset0,_ref+mvoffset1,_ystride);
|
||||
err+=dc;
|
||||
if(err<_best_err){
|
||||
_best_err=err;
|
||||
best_site=site;
|
||||
}
|
||||
}
|
||||
_vec[0]=(_vec[0]<<1)+OC_SQUARE_DX[best_site];
|
||||
_vec[1]=(_vec[1]<<1)+OC_SQUARE_DY[best_site];
|
||||
return _best_err;
|
||||
}
|
||||
|
||||
void oc_mcenc_refine4mv(oc_enc_ctx *_enc,int _mbi){
|
||||
oc_mb_enc_info *embs;
|
||||
const ptrdiff_t *frag_buf_offs;
|
||||
const ptrdiff_t *fragis;
|
||||
const unsigned char *src;
|
||||
const unsigned char *ref;
|
||||
int offset_y[9];
|
||||
int ystride;
|
||||
int bi;
|
||||
ystride=_enc->state.ref_ystride[0];
|
||||
frag_buf_offs=_enc->state.frag_buf_offs;
|
||||
fragis=_enc->state.mb_maps[_mbi][0];
|
||||
src=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[OC_FRAME_IO]];
|
||||
ref=_enc->state.ref_frame_data[_enc->state.ref_frame_idx[OC_FRAME_PREV]];
|
||||
offset_y[0]=offset_y[1]=offset_y[2]=-ystride;
|
||||
offset_y[3]=offset_y[5]=0;
|
||||
offset_y[6]=offset_y[7]=offset_y[8]=ystride;
|
||||
embs=_enc->mb_info;
|
||||
for(bi=0;bi<4;bi++){
|
||||
ptrdiff_t frag_offs;
|
||||
int vec[2];
|
||||
frag_offs=frag_buf_offs[fragis[bi]];
|
||||
vec[0]=OC_DIV2(OC_MV_X(embs[_mbi].block_mv[bi]));
|
||||
vec[1]=OC_DIV2(OC_MV_Y(embs[_mbi].block_mv[bi]));
|
||||
embs[_mbi].block_satd[bi]=oc_mcenc_ysatd_halfpel_brefine(_enc,vec,
|
||||
src+frag_offs,ref+frag_offs,ystride,offset_y,embs[_mbi].block_satd[bi]);
|
||||
embs[_mbi].ref_mv[bi]=OC_MV(vec[0],vec[1]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,528 @@
|
||||
/*File generated by libtheora with OC_COLLECT_METRICS defined at compile time.*/
|
||||
#if !defined(_modedec_H)
|
||||
# define _modedec_H (1)
|
||||
# include "encint.h"
|
||||
|
||||
|
||||
|
||||
/*The log of the average quantizer for each of the OC_MODE_RD table rows
|
||||
(e.g., for the represented qi's, and each pli and qti), in Q10 format.
|
||||
The actual statistics used by the encoder will be interpolated from
|
||||
that table based on log_plq for the actual quantization matrix used.*/
|
||||
# if !defined(OC_COLLECT_METRICS)
|
||||
static const
|
||||
# endif
|
||||
ogg_int16_t OC_MODE_LOGQ[OC_LOGQ_BINS][3][2]={
|
||||
{ {0x1F05,0x2101},{0x206E,0x2101},{0x206E,0x2101} },
|
||||
{ {0x1C9A,0x1EAC},{0x1E0E,0x1EAC},{0x1E0E,0x1EAC} },
|
||||
{ {0x1A31,0x1C48},{0x1B6F,0x1C48},{0x1B6F,0x1C48} },
|
||||
{ {0x17B0,0x19E7},{0x1938,0x19E7},{0x1938,0x19E7} },
|
||||
{ {0x152F,0x178F},{0x16AB,0x178F},{0x16AB,0x178F} },
|
||||
{ {0x12F1,0x1534},{0x145D,0x1534},{0x145D,0x1534} },
|
||||
{ {0x0FF3,0x1321},{0x11BE,0x1321},{0x11BE,0x1321} },
|
||||
{ {0x0E1F,0x1073},{0x0E93,0x1073},{0x0E93,0x1073} }
|
||||
};
|
||||
|
||||
# if !defined(OC_COLLECT_METRICS)
|
||||
static const
|
||||
# endif
|
||||
oc_mode_rd OC_MODE_RD[OC_LOGQ_BINS][3][2][OC_SAD_BINS]={
|
||||
{
|
||||
{
|
||||
/*Y' qi=0 INTRA*/
|
||||
{
|
||||
{ 57, 1550},{ 121, 2460},{ 185, 3901},{ 336, 5189},
|
||||
{ 406, 6243},{ 501, 7329},{ 565, 8292},{ 674, 9257},
|
||||
{ 746,10219},{ 843,11056},{ 961,11822},{ 1120,12512},
|
||||
{ 1208,13233},{ 1394,13600},{ 1409,14381},{ 1492,15129},
|
||||
{ 1593,15804},{ 1639,16573},{ 1731,17161},{ 1844,17707},
|
||||
{ 1949,18300},{ 2073,18654},{ 2140,19465},{ 2278,19794}
|
||||
},
|
||||
/*Y' qi=0 INTER*/
|
||||
{
|
||||
{ -18, 1274},{ 23, 2505},{ 32, 3612},{ 57, 5153},
|
||||
{ 79, 6636},{ 97, 8082},{ 109, 9505},{ 122,10924},
|
||||
{ 134,12293},{ 145,13634},{ 158,14942},{ 172,16212},
|
||||
{ 186,17422},{ 198,18604},{ 209,19757},{ 218,20875},
|
||||
{ 235,21980},{ 253,23056},{ 276,24121},{ 305,25184},
|
||||
{ 342,26202},{ 393,27140},{ 439,28140},{ 556,28659}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=0 INTRA*/
|
||||
{
|
||||
{ 32, 1763},{ 56, 2150},{ 78, 2336},{ 88, 2608},
|
||||
{ 105, 2975},{ 121, 3297},{ 113, 3460},{ 126, 3993},
|
||||
{ 142, 4432},{ 177, 4733},{ 185, 5058},{ 194, 5447},
|
||||
{ 220, 5812},{ 227, 6202},{ 246, 6415},{ 269, 6821},
|
||||
{ 279, 7026},{ 313, 7313},{ 321, 7708},{ 316, 8021},
|
||||
{ 370, 8203},{ 389, 8573},{ 410, 8607},{ 431, 8816}
|
||||
},
|
||||
/*Cb qi=0 INTER*/
|
||||
{
|
||||
{ 3, 282},{ 3, 1200},{ 3, 1605},{ 6, 2190},
|
||||
{ 15, 2519},{ 18, 2798},{ 21, 3115},{ 25, 3460},
|
||||
{ 33, 3839},{ 40, 4217},{ 47, 4592},{ 51, 4958},
|
||||
{ 56, 5326},{ 59, 5710},{ 63, 6066},{ 65, 6412},
|
||||
{ 67, 6762},{ 68, 7104},{ 70, 7461},{ 72, 7829},
|
||||
{ 77, 8200},{ 80, 8566},{ 86, 8906},{ 90, 9203}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=0 INTRA*/
|
||||
{
|
||||
{ 27, 1720},{ 44, 1920},{ 66, 2255},{ 73, 2429},
|
||||
{ 95, 2988},{ 103, 3279},{ 123, 3691},{ 129, 4012},
|
||||
{ 151, 4415},{ 150, 4760},{ 183, 5008},{ 193, 5351},
|
||||
{ 211, 5788},{ 235, 6134},{ 263, 6400},{ 276, 6711},
|
||||
{ 291, 7100},{ 346, 7285},{ 329, 7616},{ 387, 7827},
|
||||
{ 361, 8214},{ 430, 8534},{ 429, 8608},{ 450, 8823}
|
||||
},
|
||||
/*Cr qi=0 INTER*/
|
||||
{
|
||||
{ 4, 439},{ 2, 1131},{ 3, 1593},{ 6, 2130},
|
||||
{ 14, 2535},{ 17, 2786},{ 21, 3128},{ 27, 3494},
|
||||
{ 35, 3875},{ 42, 4256},{ 48, 4637},{ 53, 5019},
|
||||
{ 57, 5395},{ 61, 5777},{ 64, 6156},{ 66, 6512},
|
||||
{ 68, 6853},{ 71, 7183},{ 77, 7511},{ 81, 7841},
|
||||
{ 83, 8192},{ 88, 8510},{ 93, 8834},{ 98, 9138}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
/*Y' qi=9 INTRA*/
|
||||
{
|
||||
{ 76, 777},{ 178, 1995},{ 340, 3162},{ 591, 4097},
|
||||
{ 746, 4973},{ 916, 5847},{ 1047, 6687},{ 1218, 7430},
|
||||
{ 1385, 8079},{ 1566, 8685},{ 1755, 9167},{ 1992, 9572},
|
||||
{ 2164,10023},{ 2395,10270},{ 2536,10755},{ 2694,11285},
|
||||
{ 2895,11580},{ 3029,12143},{ 3182,12543},{ 3377,12800},
|
||||
{ 3525,13228},{ 3718,13463},{ 3878,13852},{ 4077,14001}
|
||||
},
|
||||
/*Y' qi=9 INTER*/
|
||||
{
|
||||
{ 10, 770},{ 45, 1845},{ 59, 3227},{ 99, 4708},
|
||||
{ 135, 6092},{ 164, 7425},{ 190, 8729},{ 218, 9991},
|
||||
{ 246,11234},{ 281,12427},{ 315,13573},{ 354,14678},
|
||||
{ 402,15734},{ 467,16728},{ 543,17709},{ 639,18610},
|
||||
{ 736,19503},{ 855,20312},{ 995,21033},{ 1151,21656},
|
||||
{ 1341,22130},{ 1525,22582},{ 1735,22922},{ 1922,23102}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=9 INTRA*/
|
||||
{
|
||||
{ 41, 1227},{ 70, 1452},{ 102, 1697},{ 110, 1967},
|
||||
{ 134, 2326},{ 153, 2695},{ 160, 3007},{ 196, 3393},
|
||||
{ 232, 3769},{ 266, 4067},{ 297, 4376},{ 326, 4728},
|
||||
{ 351, 5040},{ 390, 5299},{ 398, 5538},{ 443, 5900},
|
||||
{ 448, 6107},{ 506, 6370},{ 519, 6636},{ 525, 6953},
|
||||
{ 567, 7177},{ 625, 7386},{ 622, 7613},{ 654, 7764}
|
||||
},
|
||||
/*Cb qi=9 INTER*/
|
||||
{
|
||||
{ 7, 377},{ 2, 1102},{ 7, 1262},{ 19, 1693},
|
||||
{ 22, 1957},{ 27, 2302},{ 35, 2654},{ 43, 3034},
|
||||
{ 52, 3431},{ 58, 3826},{ 63, 4207},{ 67, 4570},
|
||||
{ 71, 4927},{ 75, 5283},{ 79, 5624},{ 82, 5944},
|
||||
{ 85, 6279},{ 88, 6616},{ 94, 6955},{ 102, 7284},
|
||||
{ 108, 7622},{ 116, 7944},{ 124, 8293},{ 133, 8568}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=9 INTRA*/
|
||||
{
|
||||
{ 38, 1217},{ 61, 1473},{ 88, 1650},{ 100, 1908},
|
||||
{ 137, 2400},{ 147, 2777},{ 176, 3149},{ 205, 3433},
|
||||
{ 227, 3772},{ 249, 4092},{ 286, 4370},{ 313, 4746},
|
||||
{ 342, 5053},{ 368, 5261},{ 411, 5530},{ 442, 5859},
|
||||
{ 494, 6061},{ 526, 6340},{ 532, 6646},{ 580, 6799},
|
||||
{ 567, 7203},{ 649, 7357},{ 625, 7559},{ 660, 7709}
|
||||
},
|
||||
/*Cr qi=9 INTER*/
|
||||
{
|
||||
{ 5, 408},{ 3, 1197},{ 7, 1275},{ 16, 1695},
|
||||
{ 22, 1979},{ 30, 2324},{ 38, 2691},{ 47, 3071},
|
||||
{ 53, 3462},{ 59, 3857},{ 64, 4255},{ 69, 4612},
|
||||
{ 74, 4975},{ 76, 5347},{ 81, 5694},{ 86, 6020},
|
||||
{ 91, 6357},{ 96, 6687},{ 102, 7020},{ 108, 7351},
|
||||
{ 115, 7663},{ 122, 7979},{ 125, 8298},{ 136, 8576}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
/*Y' qi=18 INTRA*/
|
||||
{
|
||||
{ 83, 534},{ 261, 1697},{ 507, 2691},{ 852, 3418},
|
||||
{ 1127, 4094},{ 1378, 4775},{ 1626, 5442},{ 1905, 5975},
|
||||
{ 2164, 6468},{ 2445, 6913},{ 2704, 7301},{ 3001, 7631},
|
||||
{ 3285, 7934},{ 3536, 8217},{ 3837, 8489},{ 4076, 8814},
|
||||
{ 4325, 9046},{ 4590, 9313},{ 4794, 9546},{ 5062, 9751},
|
||||
{ 5285, 9963},{ 5578,10079},{ 5777,10302},{ 6054,10296}
|
||||
},
|
||||
/*Y' qi=18 INTER*/
|
||||
{
|
||||
{ 33, 490},{ 62, 1599},{ 96, 3015},{ 164, 4378},
|
||||
{ 225, 5633},{ 285, 6831},{ 351, 7999},{ 427, 9133},
|
||||
{ 526,10181},{ 652,11141},{ 829,11991},{ 1049,12732},
|
||||
{ 1310,13367},{ 1592,13896},{ 1881,14350},{ 2207,14667},
|
||||
{ 2529,14877},{ 2873,14980},{ 3231,14949},{ 3571,14926},
|
||||
{ 3922,14816},{ 4246,14715},{ 4559,14579},{ 4778,14590}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=18 INTRA*/
|
||||
{
|
||||
{ 55, 825},{ 95, 1021},{ 131, 1276},{ 150, 1618},
|
||||
{ 180, 1958},{ 220, 2306},{ 256, 2608},{ 322, 2939},
|
||||
{ 385, 3239},{ 436, 3530},{ 475, 3771},{ 518, 4078},
|
||||
{ 557, 4348},{ 604, 4592},{ 620, 4851},{ 676, 5083},
|
||||
{ 704, 5363},{ 739, 5582},{ 788, 5782},{ 819, 6000},
|
||||
{ 893, 6158},{ 940, 6418},{ 984, 6499},{ 1035, 6596}
|
||||
},
|
||||
/*Cb qi=18 INTER*/
|
||||
{
|
||||
{ -2, 642},{ 12, 771},{ 20, 1054},{ 29, 1394},
|
||||
{ 35, 1721},{ 45, 2080},{ 53, 2450},{ 63, 2835},
|
||||
{ 73, 3225},{ 81, 3596},{ 87, 3952},{ 95, 4300},
|
||||
{ 102, 4634},{ 109, 4959},{ 115, 5283},{ 120, 5608},
|
||||
{ 130, 5931},{ 139, 6254},{ 152, 6571},{ 163, 6887},
|
||||
{ 179, 7204},{ 191, 7508},{ 198, 7834},{ 224, 8066}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=18 INTRA*/
|
||||
{
|
||||
{ 49, 780},{ 86, 986},{ 120, 1261},{ 137, 1588},
|
||||
{ 183, 1998},{ 228, 2339},{ 291, 2670},{ 334, 2938},
|
||||
{ 376, 3239},{ 412, 3522},{ 459, 3783},{ 490, 4113},
|
||||
{ 547, 4321},{ 593, 4571},{ 640, 4828},{ 675, 5137},
|
||||
{ 730, 5254},{ 774, 5524},{ 821, 5754},{ 859, 5911},
|
||||
{ 887, 6178},{ 982, 6266},{ 941, 6536},{ 996, 6630}
|
||||
},
|
||||
/*Cr qi=18 INTER*/
|
||||
{
|
||||
{ 0, 741},{ 9, 743},{ 16, 1034},{ 26, 1385},
|
||||
{ 39, 1741},{ 48, 2090},{ 56, 2459},{ 64, 2850},
|
||||
{ 72, 3242},{ 81, 3622},{ 89, 3980},{ 98, 4323},
|
||||
{ 104, 4667},{ 110, 5005},{ 118, 5337},{ 126, 5675},
|
||||
{ 137, 5998},{ 146, 6311},{ 156, 6621},{ 170, 6914},
|
||||
{ 181, 7205},{ 196, 7490},{ 203, 7779},{ 232, 8012}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
/*Y' qi=27 INTRA*/
|
||||
{
|
||||
{ 121, 378},{ 379, 1464},{ 810, 2335},{ 1447, 2725},
|
||||
{ 1851, 3194},{ 2311, 3655},{ 2747, 4081},{ 3211, 4393},
|
||||
{ 3640, 4672},{ 4056, 4933},{ 4427, 5150},{ 4842, 5259},
|
||||
{ 5220, 5381},{ 5584, 5443},{ 5925, 5648},{ 6233, 5783},
|
||||
{ 6547, 5944},{ 6905, 6056},{ 7203, 6181},{ 7526, 6207},
|
||||
{ 7800, 6330},{ 8175, 6312},{ 8415, 6437},{ 8705, 6459}
|
||||
},
|
||||
/*Y' qi=27 INTER*/
|
||||
{
|
||||
{ 48, 199},{ 90, 1458},{ 167, 2824},{ 291, 4050},
|
||||
{ 434, 5144},{ 638, 6133},{ 901, 7011},{ 1249, 7743},
|
||||
{ 1726, 8280},{ 2317, 8616},{ 2957, 8789},{ 3561, 8896},
|
||||
{ 4126, 8936},{ 4646, 8933},{ 5115, 8931},{ 5579, 8890},
|
||||
{ 6008, 8804},{ 6411, 8744},{ 6774, 8646},{ 7153, 8549},
|
||||
{ 7475, 8462},{ 7790, 8372},{ 8069, 8280},{ 8299, 8278}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=27 INTRA*/
|
||||
{
|
||||
{ 75, 612},{ 117, 751},{ 160, 1068},{ 195, 1406},
|
||||
{ 240, 1741},{ 305, 2066},{ 364, 2359},{ 454, 2639},
|
||||
{ 538, 2899},{ 609, 3149},{ 664, 3384},{ 730, 3625},
|
||||
{ 785, 3860},{ 836, 4094},{ 872, 4312},{ 948, 4507},
|
||||
{ 1023, 4677},{ 1081, 4843},{ 1165, 4985},{ 1238, 5092},
|
||||
{ 1316, 5235},{ 1418, 5345},{ 1430, 5478},{ 1505, 5538}
|
||||
},
|
||||
/*Cb qi=27 INTER*/
|
||||
{
|
||||
{ 16, 637},{ 13, 634},{ 32, 869},{ 46, 1230},
|
||||
{ 55, 1583},{ 67, 1950},{ 79, 2320},{ 93, 2690},
|
||||
{ 107, 3052},{ 120, 3399},{ 133, 3733},{ 146, 4054},
|
||||
{ 162, 4367},{ 175, 4679},{ 191, 4984},{ 211, 5285},
|
||||
{ 232, 5581},{ 252, 5875},{ 276, 6155},{ 305, 6433},
|
||||
{ 333, 6706},{ 364, 6967},{ 398, 7244},{ 474, 7394}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=27 INTRA*/
|
||||
{
|
||||
{ 64, 632},{ 107, 763},{ 147, 1054},{ 176, 1411},
|
||||
{ 255, 1770},{ 324, 2079},{ 411, 2359},{ 475, 2621},
|
||||
{ 545, 2880},{ 590, 3158},{ 647, 3425},{ 709, 3648},
|
||||
{ 766, 3878},{ 831, 4082},{ 911, 4260},{ 960, 4493},
|
||||
{ 1042, 4558},{ 1115, 4760},{ 1200, 4852},{ 1280, 4950},
|
||||
{ 1327, 5186},{ 1445, 5157},{ 1443, 5431},{ 1518, 5493}
|
||||
},
|
||||
/*Cr qi=27 INTER*/
|
||||
{
|
||||
{ 12, 688},{ 11, 660},{ 28, 869},{ 46, 1227},
|
||||
{ 60, 1598},{ 68, 1954},{ 79, 2318},{ 93, 2693},
|
||||
{ 108, 3054},{ 123, 3406},{ 138, 3748},{ 151, 4078},
|
||||
{ 165, 4400},{ 180, 4716},{ 197, 5024},{ 217, 5314},
|
||||
{ 243, 5599},{ 275, 5866},{ 301, 6128},{ 327, 6394},
|
||||
{ 352, 6644},{ 375, 6894},{ 376, 7180},{ 458, 7334}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
/*Y' qi=36 INTRA*/
|
||||
{
|
||||
{ 156, 263},{ 484, 1370},{ 1174, 2110},{ 1914, 2456},
|
||||
{ 2601, 2695},{ 3221, 2984},{ 3865, 3284},{ 4450, 3530},
|
||||
{ 4979, 3739},{ 5470, 3928},{ 5905, 4080},{ 6375, 4200},
|
||||
{ 6761, 4373},{ 7175, 4429},{ 7615, 4616},{ 8069, 4687},
|
||||
{ 8417, 4820},{ 8813, 4908},{ 9211, 5001},{ 9508, 5073},
|
||||
{ 9888, 5133},{10209, 5140},{10529, 5196},{10830, 5173}
|
||||
},
|
||||
/*Y' qi=36 INTER*/
|
||||
{
|
||||
{ 68, 151},{ 107, 1413},{ 262, 2665},{ 542, 3715},
|
||||
{ 946, 4584},{ 1508, 5279},{ 2167, 5829},{ 2968, 6179},
|
||||
{ 3758, 6392},{ 4481, 6517},{ 5139, 6577},{ 5706, 6636},
|
||||
{ 6271, 6612},{ 6746, 6585},{ 7216, 6533},{ 7622, 6496},
|
||||
{ 8045, 6403},{ 8393, 6389},{ 8799, 6272},{ 9062, 6281},
|
||||
{ 9436, 6184},{ 9637, 6238},{ 9864, 6215},{10147, 6215}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=36 INTRA*/
|
||||
{
|
||||
{ 91, 385},{ 138, 613},{ 205, 932},{ 265, 1239},
|
||||
{ 353, 1549},{ 443, 1839},{ 518, 2104},{ 655, 2341},
|
||||
{ 764, 2559},{ 876, 2756},{ 967, 2950},{ 1088, 3107},
|
||||
{ 1184, 3266},{ 1295, 3396},{ 1375, 3548},{ 1502, 3664},
|
||||
{ 1610, 3764},{ 1731, 3844},{ 1839, 3938},{ 1954, 4016},
|
||||
{ 2069, 4100},{ 2207, 4167},{ 2274, 4253},{ 2374, 4289}
|
||||
},
|
||||
/*Cb qi=36 INTER*/
|
||||
{
|
||||
{ 59, 18},{ 56, 463},{ 50, 790},{ 76, 1155},
|
||||
{ 90, 1515},{ 108, 1877},{ 125, 2226},{ 150, 2562},
|
||||
{ 177, 2890},{ 203, 3203},{ 231, 3501},{ 259, 3789},
|
||||
{ 289, 4074},{ 325, 4348},{ 367, 4608},{ 418, 4857},
|
||||
{ 486, 5093},{ 574, 5307},{ 677, 5494},{ 784, 5688},
|
||||
{ 914, 5844},{ 1033, 6004},{ 1142, 6179},{ 1307, 6220}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=36 INTRA*/
|
||||
{
|
||||
{ 87, 376},{ 132, 616},{ 190, 931},{ 268, 1260},
|
||||
{ 358, 1550},{ 457, 1833},{ 592, 2082},{ 685, 2318},
|
||||
{ 781, 2548},{ 867, 2757},{ 968, 2953},{ 1080, 3124},
|
||||
{ 1173, 3255},{ 1282, 3390},{ 1410, 3477},{ 1528, 3593},
|
||||
{ 1645, 3612},{ 1766, 3739},{ 1885, 3789},{ 1954, 3892},
|
||||
{ 2115, 3987},{ 2202, 4052},{ 2280, 4172},{ 2379, 4213}
|
||||
},
|
||||
/*Cr qi=36 INTER*/
|
||||
{
|
||||
{ 53, 45},{ 50, 467},{ 45, 789},{ 76, 1150},
|
||||
{ 92, 1531},{ 107, 1877},{ 125, 2219},{ 147, 2561},
|
||||
{ 176, 2893},{ 206, 3209},{ 231, 3514},{ 260, 3808},
|
||||
{ 298, 4085},{ 350, 4344},{ 411, 4587},{ 475, 4814},
|
||||
{ 532, 5037},{ 587, 5261},{ 647, 5480},{ 707, 5694},
|
||||
{ 793, 5900},{ 891, 6093},{ 1017, 6292},{ 1205, 6307}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
/*Y' qi=45 INTRA*/
|
||||
{
|
||||
{ 47, 170},{ 955, 1217},{ 1713, 2014},{ 3050, 2094},
|
||||
{ 3954, 2179},{ 4801, 2357},{ 5629, 2494},{ 6313, 2614},
|
||||
{ 6962, 2716},{ 7566, 2820},{ 8138, 2886},{ 8613, 2949},
|
||||
{ 9097, 3031},{ 9574, 3044},{10053, 3142},{10514, 3134},
|
||||
{10897, 3241},{11397, 3275},{11775, 3297},{12200, 3350},
|
||||
{12527, 3350},{12959, 3393},{13246, 3401},{13573, 3397}
|
||||
},
|
||||
/*Y' qi=45 INTER*/
|
||||
{
|
||||
{ 53, 73},{ 175, 1343},{ 649, 2439},{ 1339, 3250},
|
||||
{ 2297, 3837},{ 3395, 4203},{ 4438, 4400},{ 5401, 4529},
|
||||
{ 6222, 4588},{ 7018, 4564},{ 7713, 4532},{ 8378, 4464},
|
||||
{ 8959, 4414},{ 9464, 4364},{ 9980, 4315},{10401, 4291},
|
||||
{10805, 4260},{11172, 4260},{11501, 4231},{11798, 4248},
|
||||
{12082, 4254},{12381, 4262},{12572, 4285},{12877, 4289}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=45 INTRA*/
|
||||
{
|
||||
{ 112, -14},{ 173, 495},{ 260, 827},{ 355, 1122},
|
||||
{ 451, 1420},{ 579, 1695},{ 697, 1934},{ 917, 2101},
|
||||
{ 1104, 2244},{ 1266, 2381},{ 1417, 2520},{ 1609, 2611},
|
||||
{ 1801, 2689},{ 1973, 2764},{ 2108, 2864},{ 2298, 2948},
|
||||
{ 2452, 3008},{ 2588, 3080},{ 2732, 3161},{ 2888, 3203},
|
||||
{ 3052, 3266},{ 3240, 3294},{ 3342, 3351},{ 3467, 3373}
|
||||
},
|
||||
/*Cb qi=45 INTER*/
|
||||
{
|
||||
{ 41, -49},{ 52, 385},{ 87, 743},{ 110, 1102},
|
||||
{ 135, 1453},{ 162, 1788},{ 207, 2096},{ 272, 2391},
|
||||
{ 330, 2677},{ 392, 2950},{ 464, 3205},{ 556, 3442},
|
||||
{ 674, 3656},{ 827, 3847},{ 1030, 4006},{ 1275, 4132},
|
||||
{ 1544, 4234},{ 1809, 4317},{ 2089, 4408},{ 2377, 4456},
|
||||
{ 2647, 4532},{ 2919, 4595},{ 3256, 4659},{ 3465, 4657}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=45 INTRA*/
|
||||
{
|
||||
{ 99, -14},{ 164, 493},{ 247, 832},{ 358, 1123},
|
||||
{ 468, 1416},{ 599, 1680},{ 795, 1886},{ 958, 2063},
|
||||
{ 1133, 2211},{ 1300, 2345},{ 1480, 2461},{ 1664, 2554},
|
||||
{ 1807, 2656},{ 1995, 2742},{ 2146, 2799},{ 2331, 2856},
|
||||
{ 2440, 2894},{ 2592, 2996},{ 2751, 3033},{ 2865, 3112},
|
||||
{ 3073, 3162},{ 3210, 3208},{ 3330, 3306},{ 3454, 3332}
|
||||
},
|
||||
/*Cr qi=45 INTER*/
|
||||
{
|
||||
{ 39, -33},{ 48, 403},{ 86, 744},{ 110, 1101},
|
||||
{ 134, 1461},{ 165, 1779},{ 205, 2095},{ 259, 2401},
|
||||
{ 318, 2686},{ 386, 2958},{ 481, 3204},{ 610, 3415},
|
||||
{ 753, 3603},{ 908, 3780},{ 1055, 3959},{ 1220, 4132},
|
||||
{ 1422, 4281},{ 1656, 4419},{ 1939, 4512},{ 2259, 4574},
|
||||
{ 2593, 4593},{ 2950, 4569},{ 3339, 4505},{ 3542, 4497}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
/*Y' qi=54 INTRA*/
|
||||
{
|
||||
{ 339, 30},{ 785, 1251},{ 2395, 1971},{ 4075, 2063},
|
||||
{ 4924, 2135},{ 5806, 2270},{ 6604, 2372},{ 7224, 2497},
|
||||
{ 7879, 2608},{ 8400, 2729},{ 8951, 2829},{ 9379, 2864},
|
||||
{ 9782, 2955},{10230, 3020},{10704, 3132},{11264, 3272},
|
||||
{11618, 3284},{12034, 3394},{12500, 3482},{12767, 3484},
|
||||
{13162, 3580},{13552, 3565},{13997, 3732},{14320, 3715}
|
||||
},
|
||||
/*Y' qi=54 INTER*/
|
||||
{
|
||||
{ 65, 95},{ 269, 1312},{ 1152, 2242},{ 2336, 2863},
|
||||
{ 3728, 3239},{ 4944, 3439},{ 6034, 3543},{ 7064, 3580},
|
||||
{ 7991, 3586},{ 8849, 3568},{ 9605, 3561},{10306, 3550},
|
||||
{10919, 3544},{11466, 3530},{11972, 3528},{12401, 3536},
|
||||
{12818, 3511},{13185, 3522},{13523, 3505},{13827, 3505},
|
||||
{14114, 3522},{14395, 3521},{14625, 3533},{14909, 3532}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=54 INTRA*/
|
||||
{
|
||||
{ 148, -3},{ 218, 480},{ 351, 787},{ 437, 1069},
|
||||
{ 550, 1350},{ 730, 1592},{ 931, 1784},{ 1243, 1884},
|
||||
{ 1499, 1984},{ 1680, 2115},{ 1864, 2244},{ 2062, 2334},
|
||||
{ 2278, 2407},{ 2442, 2496},{ 2602, 2603},{ 2783, 2686},
|
||||
{ 2928, 2771},{ 3073, 2856},{ 3207, 2938},{ 3368, 2998},
|
||||
{ 3516, 3077},{ 3699, 3122},{ 3818, 3202},{ 3939, 3230}
|
||||
},
|
||||
/*Cb qi=54 INTER*/
|
||||
{
|
||||
{ 48, -11},{ 54, 407},{ 86, 743},{ 122, 1083},
|
||||
{ 176, 1400},{ 241, 1699},{ 347, 1968},{ 496, 2208},
|
||||
{ 664, 2431},{ 863, 2637},{ 1120, 2816},{ 1442, 2961},
|
||||
{ 1835, 3066},{ 2261, 3140},{ 2676, 3203},{ 3092, 3245},
|
||||
{ 3480, 3266},{ 3862, 3286},{ 4254, 3305},{ 4604, 3316},
|
||||
{ 4989, 3335},{ 5306, 3351},{ 5654, 3339},{ 5855, 3345}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=54 INTRA*/
|
||||
{
|
||||
{ 137, 10},{ 212, 492},{ 315, 795},{ 470, 1061},
|
||||
{ 612, 1333},{ 821, 1539},{ 1105, 1680},{ 1335, 1811},
|
||||
{ 1566, 1927},{ 1773, 2038},{ 1973, 2153},{ 2148, 2259},
|
||||
{ 2311, 2352},{ 2474, 2460},{ 2647, 2516},{ 2810, 2607},
|
||||
{ 2928, 2638},{ 3085, 2742},{ 3232, 2815},{ 3348, 2899},
|
||||
{ 3533, 2993},{ 3679, 3029},{ 3803, 3138},{ 3925, 3170}
|
||||
},
|
||||
/*Cr qi=54 INTER*/
|
||||
{
|
||||
{ 46, 2},{ 47, 419},{ 87, 746},{ 125, 1083},
|
||||
{ 177, 1401},{ 249, 1687},{ 342, 1964},{ 453, 2226},
|
||||
{ 627, 2454},{ 869, 2641},{ 1152, 2800},{ 1455, 2942},
|
||||
{ 1776, 3077},{ 2135, 3187},{ 2524, 3287},{ 2984, 3325},
|
||||
{ 3425, 3344},{ 3881, 3328},{ 4313, 3274},{ 4701, 3218},
|
||||
{ 5027, 3171},{ 5299, 3130},{ 5597, 3107},{ 5791, 3120}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
/*Y' qi=63 INTRA*/
|
||||
{
|
||||
{ -86, 167},{ 2070, 1104},{ 5138, 1428},{ 7014, 1535},
|
||||
{ 8430, 1629},{ 9663, 1690},{10576, 1745},{11277, 1809},
|
||||
{12003, 1869},{12663, 1925},{13258, 1983},{13701, 2016},
|
||||
{14228, 2073},{14756, 2088},{15203, 2164},{15993, 2175},
|
||||
{16378, 2256},{16917, 2240},{17361, 2332},{17782, 2312},
|
||||
{18376, 2381},{18728, 2362},{19224, 2408},{19705, 2392}
|
||||
},
|
||||
/*Y' qi=63 INTER*/
|
||||
{
|
||||
{ -529, 154},{ 967, 1233},{ 4201, 1610},{ 6285, 1800},
|
||||
{ 8058, 1908},{ 9439, 1968},{10737, 1987},{11999, 1979},
|
||||
{13003, 1972},{13854, 1963},{14584, 1965},{15217, 1955},
|
||||
{15773, 1956},{16229, 1949},{16735, 1952},{17085, 1956},
|
||||
{17508, 1956},{17821, 1961},{18191, 1961},{18465, 1982},
|
||||
{18792, 1975},{19158, 1995},{19378, 2010},{19817, 2021}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cb qi=63 INTRA*/
|
||||
{
|
||||
{ 136, 4},{ 338, 438},{ 593, 730},{ 835, 974},
|
||||
{ 1168, 1188},{ 1602, 1345},{ 2004, 1467},{ 2465, 1505},
|
||||
{ 2799, 1574},{ 3091, 1669},{ 3384, 1758},{ 3673, 1817},
|
||||
{ 3950, 1861},{ 4190, 1924},{ 4444, 1993},{ 4701, 2051},
|
||||
{ 4915, 2123},{ 5119, 2166},{ 5329, 2231},{ 5576, 2259},
|
||||
{ 5793, 2310},{ 6001, 2334},{ 6198, 2384},{ 6344, 2401}
|
||||
},
|
||||
/*Cb qi=63 INTER*/
|
||||
{
|
||||
{ 49, 4},{ 51, 403},{ 98, 729},{ 185, 1034},
|
||||
{ 352, 1304},{ 622, 1533},{ 1068, 1696},{ 1604, 1821},
|
||||
{ 2203, 1924},{ 2890, 1988},{ 3622, 2017},{ 4359, 2019},
|
||||
{ 5025, 2005},{ 5586, 2002},{ 6090, 1989},{ 6519, 1977},
|
||||
{ 6927, 1977},{ 7305, 1968},{ 7730, 1984},{ 8087, 1981},
|
||||
{ 8435, 1991},{ 8822, 1987},{ 9155, 2008},{ 9392, 2011}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*Cr qi=63 INTRA*/
|
||||
{
|
||||
{ 131, 11},{ 334, 448},{ 569, 739},{ 929, 946},
|
||||
{ 1285, 1145},{ 1718, 1274},{ 2176, 1343},{ 2531, 1424},
|
||||
{ 2866, 1504},{ 3176, 1580},{ 3475, 1657},{ 3736, 1728},
|
||||
{ 3962, 1807},{ 4232, 1872},{ 4425, 1921},{ 4657, 1976},
|
||||
{ 4817, 2009},{ 5063, 2082},{ 5281, 2129},{ 5480, 2199},
|
||||
{ 5743, 2258},{ 5887, 2283},{ 6124, 2358},{ 6273, 2378}
|
||||
},
|
||||
/*Cr qi=63 INTER*/
|
||||
{
|
||||
{ 47, 15},{ 40, 405},{ 100, 730},{ 189, 1037},
|
||||
{ 351, 1303},{ 625, 1526},{ 984, 1719},{ 1512, 1862},
|
||||
{ 2189, 1947},{ 2895, 2003},{ 3576, 2046},{ 4249, 2072},
|
||||
{ 4901, 2068},{ 5514, 2043},{ 6079, 2009},{ 6528, 1977},
|
||||
{ 6927, 1940},{ 7274, 1915},{ 7580, 1894},{ 7910, 1910},
|
||||
{ 8211, 1902},{ 8472, 1920},{ 8742, 1926},{ 8981, 1930}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
/*Some common macros for potential platform-specific optimization.*/
|
||||
#include <math.h>
|
||||
#if !defined(_ocintrin_H)
|
||||
# define _ocintrin_H (1)
|
||||
|
||||
/*Some specific platforms may have optimized intrinsic or inline assembly
|
||||
versions of these functions which can substantially improve performance.
|
||||
We define macros for them to allow easy incorporation of these non-ANSI
|
||||
features.*/
|
||||
|
||||
/*Note that we do not provide a macro for abs(), because it is provided as a
|
||||
library function, which we assume is translated into an intrinsic to avoid
|
||||
the function call overhead and then implemented in the smartest way for the
|
||||
target platform.
|
||||
With modern gcc (4.x), this is true: it uses cmov instructions if the
|
||||
architecture supports it and branchless bit-twiddling if it does not (the
|
||||
speed difference between the two approaches is not measurable).
|
||||
Interestingly, the bit-twiddling method was patented in 2000 (US 6,073,150)
|
||||
by Sun Microsystems, despite prior art dating back to at least 1996:
|
||||
http://web.archive.org/web/19961201174141/www.x86.org/ftp/articles/pentopt/PENTOPT.TXT
|
||||
On gcc 3.x, however, our assumption is not true, as abs() is translated to a
|
||||
conditional jump, which is horrible on deeply piplined architectures (e.g.,
|
||||
all consumer architectures for the past decade or more).
|
||||
Also be warned that -C*abs(x) where C is a constant is mis-optimized as
|
||||
abs(C*x) on every gcc release before 4.2.3.
|
||||
See bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34130 */
|
||||
|
||||
/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if
|
||||
given an appropriate architecture, but the branchless bit-twiddling versions
|
||||
are just as fast, and do not require any special target architecture.
|
||||
Earlier gcc versions (3.x) compiled both code to the same assembly
|
||||
instructions, because of the way they represented ((_b)>(_a)) internally.*/
|
||||
#define OC_MAXI(_a,_b) ((_a)-((_a)-(_b)&-((_b)>(_a))))
|
||||
#define OC_MINI(_a,_b) ((_a)+((_b)-(_a)&-((_b)<(_a))))
|
||||
/*Clamps an integer into the given range.
|
||||
If _a>_c, then the lower bound _a is respected over the upper bound _c (this
|
||||
behavior is required to meet our documented API behavior).
|
||||
_a: The lower bound.
|
||||
_b: The value to clamp.
|
||||
_c: The upper boud.*/
|
||||
#define OC_CLAMPI(_a,_b,_c) (OC_MAXI(_a,OC_MINI(_b,_c)))
|
||||
#define OC_CLAMP255(_x) ((unsigned char)((((_x)<0)-1)&((_x)|-((_x)>255))))
|
||||
/*This has a chance of compiling branchless, and is just as fast as the
|
||||
bit-twiddling method, which is slightly less portable, since it relies on a
|
||||
sign-extended rightshift, which is not guaranteed by ANSI (but present on
|
||||
every relevant platform).*/
|
||||
#define OC_SIGNI(_a) (((_a)>0)-((_a)<0))
|
||||
/*Slightly more portable than relying on a sign-extended right-shift (which is
|
||||
not guaranteed by ANSI), and just as fast, since gcc (3.x and 4.x both)
|
||||
compile it into the right-shift anyway.*/
|
||||
#define OC_SIGNMASK(_a) (-((_a)<0))
|
||||
/*Divides an integer by a power of two, truncating towards 0.
|
||||
_dividend: The integer to divide.
|
||||
_shift: The non-negative power of two to divide by.
|
||||
_rmask: (1<<_shift)-1*/
|
||||
#define OC_DIV_POW2(_dividend,_shift,_rmask)\
|
||||
((_dividend)+(OC_SIGNMASK(_dividend)&(_rmask))>>(_shift))
|
||||
/*Divides _x by 65536, truncating towards 0.*/
|
||||
#define OC_DIV2_16(_x) OC_DIV_POW2(_x,16,0xFFFF)
|
||||
/*Divides _x by 2, truncating towards 0.*/
|
||||
#define OC_DIV2(_x) OC_DIV_POW2(_x,1,0x1)
|
||||
/*Divides _x by 8, truncating towards 0.*/
|
||||
#define OC_DIV8(_x) OC_DIV_POW2(_x,3,0x7)
|
||||
/*Divides _x by 16, truncating towards 0.*/
|
||||
#define OC_DIV16(_x) OC_DIV_POW2(_x,4,0xF)
|
||||
/*Right shifts _dividend by _shift, adding _rval, and subtracting one for
|
||||
negative dividends first.
|
||||
When _rval is (1<<_shift-1), this is equivalent to division with rounding
|
||||
ties away from zero.*/
|
||||
#define OC_DIV_ROUND_POW2(_dividend,_shift,_rval)\
|
||||
((_dividend)+OC_SIGNMASK(_dividend)+(_rval)>>(_shift))
|
||||
/*Divides a _x by 2, rounding towards even numbers.*/
|
||||
#define OC_DIV2_RE(_x) ((_x)+((_x)>>1&1)>>1)
|
||||
/*Divides a _x by (1<<(_shift)), rounding towards even numbers.*/
|
||||
#define OC_DIV_POW2_RE(_x,_shift) \
|
||||
((_x)+((_x)>>(_shift)&1)+((1<<(_shift))-1>>1)>>(_shift))
|
||||
/*Swaps two integers _a and _b if _a>_b.*/
|
||||
#define OC_SORT2I(_a,_b) \
|
||||
do{ \
|
||||
int t__; \
|
||||
t__=((_a)^(_b))&-((_b)<(_a)); \
|
||||
(_a)^=t__; \
|
||||
(_b)^=t__; \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
/*Accesses one of four (signed) bytes given an index.
|
||||
This can be used to avoid small lookup tables.*/
|
||||
#define OC_BYTE_TABLE32(_a,_b,_c,_d,_i) \
|
||||
((signed char) \
|
||||
(((_a)&0xFF|((_b)&0xFF)<<8|((_c)&0xFF)<<16|((_d)&0xFF)<<24)>>(_i)*8))
|
||||
/*Accesses one of eight (unsigned) nibbles given an index.
|
||||
This can be used to avoid small lookup tables.*/
|
||||
#define OC_UNIBBLE_TABLE32(_a,_b,_c,_d,_e,_f,_g,_h,_i) \
|
||||
((((_a)&0xF|((_b)&0xF)<<4|((_c)&0xF)<<8|((_d)&0xF)<<12| \
|
||||
((_e)&0xF)<<16|((_f)&0xF)<<20|((_g)&0xF)<<24|((_h)&0xF)<<28)>>(_i)*4)&0xF)
|
||||
|
||||
|
||||
|
||||
/*All of these macros should expect floats as arguments.*/
|
||||
#define OC_MAXF(_a,_b) ((_a)<(_b)?(_b):(_a))
|
||||
#define OC_MINF(_a,_b) ((_a)>(_b)?(_b):(_a))
|
||||
#define OC_CLAMPF(_a,_b,_c) (OC_MINF(_a,OC_MAXF(_b,_c)))
|
||||
#define OC_FABSF(_f) ((float)fabs(_f))
|
||||
#define OC_SQRTF(_f) ((float)sqrt(_f))
|
||||
#define OC_POWF(_b,_e) ((float)pow(_b,_e))
|
||||
#define OC_LOGF(_f) ((float)log(_f))
|
||||
#define OC_IFLOORF(_f) ((int)floor(_f))
|
||||
#define OC_ICEILF(_f) ((int)ceil(_f))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ogg/ogg.h>
|
||||
#include "quant.h"
|
||||
#include "decint.h"
|
||||
|
||||
/*The maximum output of the DCT with +/- 255 inputs is +/- 8157.
|
||||
These minimum quantizers ensure the result after quantization (and after
|
||||
prediction for DC) will be no more than +/- 510.
|
||||
The tokenization system can handle values up to +/- 580, so there is no need
|
||||
to do any coefficient clamping.
|
||||
I would rather have allowed smaller quantizers and had to clamp, but these
|
||||
minimums were required when constructing the original VP3 matrices and have
|
||||
been formalized in the spec.*/
|
||||
static const unsigned OC_DC_QUANT_MIN[2]={4<<2,8<<2};
|
||||
static const unsigned OC_AC_QUANT_MIN[2]={2<<2,4<<2};
|
||||
|
||||
/*Initializes the dequantization tables from a set of quantizer info.
|
||||
Currently the dequantizer (and elsewhere enquantizer) tables are expected to
|
||||
be initialized as pointing to the storage reserved for them in the
|
||||
oc_theora_state (resp. oc_enc_ctx) structure.
|
||||
If some tables are duplicates of others, the pointers will be adjusted to
|
||||
point to a single copy of the tables, but the storage for them will not be
|
||||
freed.
|
||||
If you're concerned about the memory footprint, the obvious thing to do is
|
||||
to move the storage out of its fixed place in the structures and allocate
|
||||
it on demand.
|
||||
However, a much, much better option is to only store the quantization
|
||||
matrices being used for the current frame, and to recalculate these as the
|
||||
qi values change between frames (this is what VP3 did).*/
|
||||
void oc_dequant_tables_init(ogg_uint16_t *_dequant[64][3][2],
|
||||
int _pp_dc_scale[64],const th_quant_info *_qinfo){
|
||||
/*Coding mode: intra or inter.*/
|
||||
int qti;
|
||||
/*Y', C_b, C_r*/
|
||||
int pli;
|
||||
for(qti=0;qti<2;qti++)for(pli=0;pli<3;pli++){
|
||||
/*Quality index.*/
|
||||
int qi;
|
||||
/*Range iterator.*/
|
||||
int qri;
|
||||
for(qi=0,qri=0;qri<=_qinfo->qi_ranges[qti][pli].nranges;qri++){
|
||||
th_quant_base base;
|
||||
ogg_uint32_t q;
|
||||
int qi_start;
|
||||
int qi_end;
|
||||
memcpy(base,_qinfo->qi_ranges[qti][pli].base_matrices[qri],
|
||||
sizeof(base));
|
||||
qi_start=qi;
|
||||
if(qri==_qinfo->qi_ranges[qti][pli].nranges)qi_end=qi+1;
|
||||
else qi_end=qi+_qinfo->qi_ranges[qti][pli].sizes[qri];
|
||||
/*Iterate over quality indicies in this range.*/
|
||||
for(;;){
|
||||
ogg_uint32_t qfac;
|
||||
int zzi;
|
||||
int ci;
|
||||
/*In the original VP3.2 code, the rounding offset and the size of the
|
||||
dead zone around 0 were controlled by a "sharpness" parameter.
|
||||
The size of our dead zone is now controlled by the per-coefficient
|
||||
quality thresholds returned by our HVS module.
|
||||
We round down from a more accurate value when the quality of the
|
||||
reconstruction does not fall below our threshold and it saves bits.
|
||||
Hence, all of that VP3.2 code is gone from here, and the remaining
|
||||
floating point code has been implemented as equivalent integer code
|
||||
with exact precision.*/
|
||||
qfac=(ogg_uint32_t)_qinfo->dc_scale[qi]*base[0];
|
||||
/*For postprocessing, not dequantization.*/
|
||||
if(_pp_dc_scale!=NULL)_pp_dc_scale[qi]=(int)(qfac/160);
|
||||
/*Scale DC the coefficient from the proper table.*/
|
||||
q=(qfac/100)<<2;
|
||||
q=OC_CLAMPI(OC_DC_QUANT_MIN[qti],q,OC_QUANT_MAX);
|
||||
_dequant[qi][pli][qti][0]=(ogg_uint16_t)q;
|
||||
/*Now scale AC coefficients from the proper table.*/
|
||||
for(zzi=1;zzi<64;zzi++){
|
||||
q=((ogg_uint32_t)_qinfo->ac_scale[qi]*base[OC_FZIG_ZAG[zzi]]/100)<<2;
|
||||
q=OC_CLAMPI(OC_AC_QUANT_MIN[qti],q,OC_QUANT_MAX);
|
||||
_dequant[qi][pli][qti][zzi]=(ogg_uint16_t)q;
|
||||
}
|
||||
/*If this is a duplicate of a previous matrix, use that instead.
|
||||
This simple check helps us improve cache coherency later.*/
|
||||
{
|
||||
int dupe;
|
||||
int qtj;
|
||||
int plj;
|
||||
dupe=0;
|
||||
for(qtj=0;qtj<=qti;qtj++){
|
||||
for(plj=0;plj<(qtj<qti?3:pli);plj++){
|
||||
if(!memcmp(_dequant[qi][pli][qti],_dequant[qi][plj][qtj],
|
||||
sizeof(oc_quant_table))){
|
||||
dupe=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(dupe)break;
|
||||
}
|
||||
if(dupe)_dequant[qi][pli][qti]=_dequant[qi][plj][qtj];
|
||||
}
|
||||
if(++qi>=qi_end)break;
|
||||
/*Interpolate the next base matrix.*/
|
||||
for(ci=0;ci<64;ci++){
|
||||
base[ci]=(unsigned char)(
|
||||
(2*((qi_end-qi)*_qinfo->qi_ranges[qti][pli].base_matrices[qri][ci]+
|
||||
(qi-qi_start)*_qinfo->qi_ranges[qti][pli].base_matrices[qri+1][ci])
|
||||
+_qinfo->qi_ranges[qti][pli].sizes[qri])/
|
||||
(2*_qinfo->qi_ranges[qti][pli].sizes[qri]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_quant_H)
|
||||
# define _quant_H (1)
|
||||
# include "theora/codec.h"
|
||||
# include "ocintrin.h"
|
||||
|
||||
typedef ogg_uint16_t oc_quant_table[64];
|
||||
|
||||
|
||||
/*Maximum scaled quantizer value.*/
|
||||
#define OC_QUANT_MAX (1024<<2)
|
||||
|
||||
|
||||
void oc_dequant_tables_init(ogg_uint16_t *_dequant[64][3][2],
|
||||
int _pp_dc_scale[64],const th_quant_info *_qinfo);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,544 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: internal.h 17337 2010-07-19 16:08:54Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
#if !defined(_state_H)
|
||||
# define _state_H (1)
|
||||
# include "internal.h"
|
||||
# include "huffman.h"
|
||||
# include "quant.h"
|
||||
|
||||
|
||||
|
||||
/*A single quadrant of the map from a super block to fragment numbers.*/
|
||||
typedef ptrdiff_t oc_sb_map_quad[4];
|
||||
/*A map from a super block to fragment numbers.*/
|
||||
typedef oc_sb_map_quad oc_sb_map[4];
|
||||
/*A single plane of the map from a macro block to fragment numbers.*/
|
||||
typedef ptrdiff_t oc_mb_map_plane[4];
|
||||
/*A map from a macro block to fragment numbers.*/
|
||||
typedef oc_mb_map_plane oc_mb_map[3];
|
||||
/*A motion vector.*/
|
||||
typedef ogg_int16_t oc_mv;
|
||||
|
||||
typedef struct oc_sb_flags oc_sb_flags;
|
||||
typedef struct oc_border_info oc_border_info;
|
||||
typedef struct oc_fragment oc_fragment;
|
||||
typedef struct oc_fragment_plane oc_fragment_plane;
|
||||
typedef struct oc_base_opt_vtable oc_base_opt_vtable;
|
||||
typedef struct oc_base_opt_data oc_base_opt_data;
|
||||
typedef struct oc_state_dispatch_vtable oc_state_dispatch_vtable;
|
||||
typedef struct oc_theora_state oc_theora_state;
|
||||
|
||||
|
||||
|
||||
/*Shared accelerated functions.*/
|
||||
# if defined(OC_X86_ASM)
|
||||
# if defined(_MSC_VER)
|
||||
# include "x86_vc/x86int.h"
|
||||
# else
|
||||
# include "x86/x86int.h"
|
||||
# endif
|
||||
# endif
|
||||
# if defined(OC_ARM_ASM)
|
||||
# include "arm/armint.h"
|
||||
# endif
|
||||
# if defined(OC_C64X_ASM)
|
||||
# include "c64x/c64xint.h"
|
||||
# endif
|
||||
|
||||
# if !defined(oc_state_accel_init)
|
||||
# define oc_state_accel_init oc_state_accel_init_c
|
||||
# endif
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
# if !defined(oc_frag_copy)
|
||||
# define oc_frag_copy(_state,_dst,_src,_ystride) \
|
||||
((*(_state)->opt_vtable.frag_copy)(_dst,_src,_ystride))
|
||||
# endif
|
||||
# if !defined(oc_frag_copy_list)
|
||||
# define oc_frag_copy_list(_state,_dst_frame,_src_frame,_ystride, \
|
||||
_fragis,_nfragis,_frag_buf_offs) \
|
||||
((*(_state)->opt_vtable.frag_copy_list)(_dst_frame,_src_frame,_ystride, \
|
||||
_fragis,_nfragis,_frag_buf_offs))
|
||||
# endif
|
||||
# if !defined(oc_frag_recon_intra)
|
||||
# define oc_frag_recon_intra(_state,_dst,_dst_ystride,_residue) \
|
||||
((*(_state)->opt_vtable.frag_recon_intra)(_dst,_dst_ystride,_residue))
|
||||
# endif
|
||||
# if !defined(oc_frag_recon_inter)
|
||||
# define oc_frag_recon_inter(_state,_dst,_src,_ystride,_residue) \
|
||||
((*(_state)->opt_vtable.frag_recon_inter)(_dst,_src,_ystride,_residue))
|
||||
# endif
|
||||
# if !defined(oc_frag_recon_inter2)
|
||||
# define oc_frag_recon_inter2(_state,_dst,_src1,_src2,_ystride,_residue) \
|
||||
((*(_state)->opt_vtable.frag_recon_inter2)(_dst, \
|
||||
_src1,_src2,_ystride,_residue))
|
||||
# endif
|
||||
# if !defined(oc_idct8x8)
|
||||
# define oc_idct8x8(_state,_y,_x,_last_zzi) \
|
||||
((*(_state)->opt_vtable.idct8x8)(_y,_x,_last_zzi))
|
||||
# endif
|
||||
# if !defined(oc_state_frag_recon)
|
||||
# define oc_state_frag_recon(_state,_fragi, \
|
||||
_pli,_dct_coeffs,_last_zzi,_dc_quant) \
|
||||
((*(_state)->opt_vtable.state_frag_recon)(_state,_fragi, \
|
||||
_pli,_dct_coeffs,_last_zzi,_dc_quant))
|
||||
# endif
|
||||
# if !defined(oc_loop_filter_init)
|
||||
# define oc_loop_filter_init(_state,_bv,_flimit) \
|
||||
((*(_state)->opt_vtable.loop_filter_init)(_bv,_flimit))
|
||||
# endif
|
||||
# if !defined(oc_state_loop_filter_frag_rows)
|
||||
# define oc_state_loop_filter_frag_rows(_state, \
|
||||
_bv,_refi,_pli,_fragy0,_fragy_end) \
|
||||
((*(_state)->opt_vtable.state_loop_filter_frag_rows)(_state, \
|
||||
_bv,_refi,_pli,_fragy0,_fragy_end))
|
||||
# endif
|
||||
# if !defined(oc_restore_fpu)
|
||||
# define oc_restore_fpu(_state) \
|
||||
((*(_state)->opt_vtable.restore_fpu)())
|
||||
# endif
|
||||
# else
|
||||
# if !defined(oc_frag_copy)
|
||||
# define oc_frag_copy(_state,_dst,_src,_ystride) \
|
||||
oc_frag_copy_c(_dst,_src,_ystride)
|
||||
# endif
|
||||
# if !defined(oc_frag_copy_list)
|
||||
# define oc_frag_copy_list(_state,_dst_frame,_src_frame,_ystride, \
|
||||
_fragis,_nfragis,_frag_buf_offs) \
|
||||
oc_frag_copy_list_c(_dst_frame,_src_frame,_ystride, \
|
||||
_fragis,_nfragis,_frag_buf_offs)
|
||||
# endif
|
||||
# if !defined(oc_frag_recon_intra)
|
||||
# define oc_frag_recon_intra(_state,_dst,_dst_ystride,_residue) \
|
||||
oc_frag_recon_intra_c(_dst,_dst_ystride,_residue)
|
||||
# endif
|
||||
# if !defined(oc_frag_recon_inter)
|
||||
# define oc_frag_recon_inter(_state,_dst,_src,_ystride,_residue) \
|
||||
oc_frag_recon_inter_c(_dst,_src,_ystride,_residue)
|
||||
# endif
|
||||
# if !defined(oc_frag_recon_inter2)
|
||||
# define oc_frag_recon_inter2(_state,_dst,_src1,_src2,_ystride,_residue) \
|
||||
oc_frag_recon_inter2_c(_dst,_src1,_src2,_ystride,_residue)
|
||||
# endif
|
||||
# if !defined(oc_idct8x8)
|
||||
# define oc_idct8x8(_state,_y,_x,_last_zzi) oc_idct8x8_c(_y,_x,_last_zzi)
|
||||
# endif
|
||||
# if !defined(oc_state_frag_recon)
|
||||
# define oc_state_frag_recon oc_state_frag_recon_c
|
||||
# endif
|
||||
# if !defined(oc_loop_filter_init)
|
||||
# define oc_loop_filter_init(_state,_bv,_flimit) \
|
||||
oc_loop_filter_init_c(_bv,_flimit)
|
||||
# endif
|
||||
# if !defined(oc_state_loop_filter_frag_rows)
|
||||
# define oc_state_loop_filter_frag_rows oc_state_loop_filter_frag_rows_c
|
||||
# endif
|
||||
# if !defined(oc_restore_fpu)
|
||||
# define oc_restore_fpu(_state) do{}while(0)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
/*A keyframe.*/
|
||||
# define OC_INTRA_FRAME (0)
|
||||
/*A predicted frame.*/
|
||||
# define OC_INTER_FRAME (1)
|
||||
/*A frame of unknown type (frame type decision has not yet been made).*/
|
||||
# define OC_UNKWN_FRAME (-1)
|
||||
|
||||
/*The amount of padding to add to the reconstructed frame buffers on all
|
||||
sides.
|
||||
This is used to allow unrestricted motion vectors without special casing.
|
||||
This must be a multiple of 2.*/
|
||||
# define OC_UMV_PADDING (16)
|
||||
|
||||
/*Frame classification indices.*/
|
||||
/*The previous golden frame.*/
|
||||
# define OC_FRAME_GOLD (0)
|
||||
/*The previous frame.*/
|
||||
# define OC_FRAME_PREV (1)
|
||||
/*The current frame.*/
|
||||
# define OC_FRAME_SELF (2)
|
||||
|
||||
/*The input or output buffer.*/
|
||||
# define OC_FRAME_IO (3)
|
||||
/*Uncompressed prev golden frame.*/
|
||||
# define OC_FRAME_GOLD_ORIG (4)
|
||||
/*Uncompressed previous frame. */
|
||||
# define OC_FRAME_PREV_ORIG (5)
|
||||
|
||||
/*Macroblock modes.*/
|
||||
/*Macro block is invalid: It is never coded.*/
|
||||
# define OC_MODE_INVALID (-1)
|
||||
/*Encoded difference from the same macro block in the previous frame.*/
|
||||
# define OC_MODE_INTER_NOMV (0)
|
||||
/*Encoded with no motion compensated prediction.*/
|
||||
# define OC_MODE_INTRA (1)
|
||||
/*Encoded difference from the previous frame offset by the given motion
|
||||
vector.*/
|
||||
# define OC_MODE_INTER_MV (2)
|
||||
/*Encoded difference from the previous frame offset by the last coded motion
|
||||
vector.*/
|
||||
# define OC_MODE_INTER_MV_LAST (3)
|
||||
/*Encoded difference from the previous frame offset by the second to last
|
||||
coded motion vector.*/
|
||||
# define OC_MODE_INTER_MV_LAST2 (4)
|
||||
/*Encoded difference from the same macro block in the previous golden
|
||||
frame.*/
|
||||
# define OC_MODE_GOLDEN_NOMV (5)
|
||||
/*Encoded difference from the previous golden frame offset by the given motion
|
||||
vector.*/
|
||||
# define OC_MODE_GOLDEN_MV (6)
|
||||
/*Encoded difference from the previous frame offset by the individual motion
|
||||
vectors given for each block.*/
|
||||
# define OC_MODE_INTER_MV_FOUR (7)
|
||||
/*The number of (coded) modes.*/
|
||||
# define OC_NMODES (8)
|
||||
|
||||
/*Determines the reference frame used for a given MB mode.*/
|
||||
# define OC_FRAME_FOR_MODE(_x) \
|
||||
OC_UNIBBLE_TABLE32(OC_FRAME_PREV,OC_FRAME_SELF,OC_FRAME_PREV,OC_FRAME_PREV, \
|
||||
OC_FRAME_PREV,OC_FRAME_GOLD,OC_FRAME_GOLD,OC_FRAME_PREV,(_x))
|
||||
|
||||
/*Constants for the packet state machine common between encoder and decoder.*/
|
||||
|
||||
/*Next packet to emit/read: Codec info header.*/
|
||||
# define OC_PACKET_INFO_HDR (-3)
|
||||
/*Next packet to emit/read: Comment header.*/
|
||||
# define OC_PACKET_COMMENT_HDR (-2)
|
||||
/*Next packet to emit/read: Codec setup header.*/
|
||||
# define OC_PACKET_SETUP_HDR (-1)
|
||||
/*No more packets to emit/read.*/
|
||||
# define OC_PACKET_DONE (INT_MAX)
|
||||
|
||||
|
||||
|
||||
#define OC_MV(_x,_y) ((oc_mv)((_x)&0xFF|(_y)<<8))
|
||||
#define OC_MV_X(_mv) ((signed char)(_mv))
|
||||
#define OC_MV_Y(_mv) ((_mv)>>8)
|
||||
#define OC_MV_ADD(_mv1,_mv2) \
|
||||
OC_MV(OC_MV_X(_mv1)+OC_MV_X(_mv2), \
|
||||
OC_MV_Y(_mv1)+OC_MV_Y(_mv2))
|
||||
#define OC_MV_SUB(_mv1,_mv2) \
|
||||
OC_MV(OC_MV_X(_mv1)-OC_MV_X(_mv2), \
|
||||
OC_MV_Y(_mv1)-OC_MV_Y(_mv2))
|
||||
|
||||
|
||||
|
||||
/*Super blocks are 32x32 segments of pixels in a single color plane indexed
|
||||
in image order.
|
||||
Internally, super blocks are broken up into four quadrants, each of which
|
||||
contains a 2x2 pattern of blocks, each of which is an 8x8 block of pixels.
|
||||
Quadrants, and the blocks within them, are indexed in a special order called
|
||||
a "Hilbert curve" within the super block.
|
||||
|
||||
In order to differentiate between the Hilbert-curve indexing strategy and
|
||||
the regular image order indexing strategy, blocks indexed in image order
|
||||
are called "fragments".
|
||||
Fragments are indexed in image order, left to right, then bottom to top,
|
||||
from Y' plane to Cb plane to Cr plane.
|
||||
|
||||
The co-located fragments in all image planes corresponding to the location
|
||||
of a single quadrant of a luma plane super block form a macro block.
|
||||
Thus there is only a single set of macro blocks for all planes, each of which
|
||||
contains between 6 and 12 fragments, depending on the pixel format.
|
||||
Therefore macro block information is kept in a separate set of arrays from
|
||||
super blocks to avoid unused space in the other planes.
|
||||
The lists are indexed in super block order.
|
||||
That is, the macro block corresponding to the macro block mbi in (luma plane)
|
||||
super block sbi is at index (sbi<<2|mbi).
|
||||
Thus the number of macro blocks in each dimension is always twice the number
|
||||
of super blocks, even when only an odd number fall inside the coded frame.
|
||||
These "extra" macro blocks are just an artifact of our internal data layout,
|
||||
and not part of the coded stream; they are flagged with a negative MB mode.*/
|
||||
|
||||
|
||||
|
||||
/*Super block information.*/
|
||||
struct oc_sb_flags{
|
||||
unsigned char coded_fully:1;
|
||||
unsigned char coded_partially:1;
|
||||
unsigned char quad_valid:4;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*Information about a fragment which intersects the border of the displayable
|
||||
region.
|
||||
This marks which pixels belong to the displayable region.*/
|
||||
struct oc_border_info{
|
||||
/*A bit mask marking which pixels are in the displayable region.
|
||||
Pixel (x,y) corresponds to bit (y<<3|x).*/
|
||||
ogg_int64_t mask;
|
||||
/*The number of pixels in the displayable region.
|
||||
This is always positive, and always less than 64.*/
|
||||
int npixels;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*Fragment information.*/
|
||||
struct oc_fragment{
|
||||
/*A flag indicating whether or not this fragment is coded.*/
|
||||
unsigned coded:1;
|
||||
/*A flag indicating that this entire fragment lies outside the displayable
|
||||
region of the frame.
|
||||
Note the contrast with an invalid macro block, which is outside the coded
|
||||
frame, not just the displayable one.
|
||||
There are no fragments outside the coded frame by construction.*/
|
||||
unsigned invalid:1;
|
||||
/*The index of the quality index used for this fragment's AC coefficients.*/
|
||||
unsigned qii:6;
|
||||
/*The mode of the macroblock this fragment belongs to.*/
|
||||
unsigned mb_mode:3;
|
||||
/*The index of the associated border information for fragments which lie
|
||||
partially outside the displayable region.
|
||||
For fragments completely inside or outside this region, this is -1.
|
||||
Note that the C standard requires an explicit signed keyword for bitfield
|
||||
types, since some compilers may treat them as unsigned without it.*/
|
||||
signed int borderi:5;
|
||||
/*The prediction-corrected DC component.
|
||||
Note that the C standard requires an explicit signed keyword for bitfield
|
||||
types, since some compilers may treat them as unsigned without it.*/
|
||||
signed int dc:16;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*A description of each fragment plane.*/
|
||||
struct oc_fragment_plane{
|
||||
/*The number of fragments in the horizontal direction.*/
|
||||
int nhfrags;
|
||||
/*The number of fragments in the vertical direction.*/
|
||||
int nvfrags;
|
||||
/*The offset of the first fragment in the plane.*/
|
||||
ptrdiff_t froffset;
|
||||
/*The total number of fragments in the plane.*/
|
||||
ptrdiff_t nfrags;
|
||||
/*The number of super blocks in the horizontal direction.*/
|
||||
unsigned nhsbs;
|
||||
/*The number of super blocks in the vertical direction.*/
|
||||
unsigned nvsbs;
|
||||
/*The offset of the first super block in the plane.*/
|
||||
unsigned sboffset;
|
||||
/*The total number of super blocks in the plane.*/
|
||||
unsigned nsbs;
|
||||
};
|
||||
|
||||
|
||||
typedef void (*oc_state_loop_filter_frag_rows_func)(
|
||||
const oc_theora_state *_state,signed char _bv[256],int _refi,int _pli,
|
||||
int _fragy0,int _fragy_end);
|
||||
|
||||
/*The shared (encoder and decoder) functions that have accelerated variants.*/
|
||||
struct oc_base_opt_vtable{
|
||||
void (*frag_copy)(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride);
|
||||
void (*frag_copy_list)(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||
void (*frag_recon_intra)(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t _residue[64]);
|
||||
void (*frag_recon_inter)(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride,const ogg_int16_t _residue[64]);
|
||||
void (*frag_recon_inter2)(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t _residue[64]);
|
||||
void (*idct8x8)(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||
void (*state_frag_recon)(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||
void (*loop_filter_init)(signed char _bv[256],int _flimit);
|
||||
oc_state_loop_filter_frag_rows_func state_loop_filter_frag_rows;
|
||||
void (*restore_fpu)(void);
|
||||
};
|
||||
|
||||
/*The shared (encoder and decoder) tables that vary according to which variants
|
||||
of the above functions are used.*/
|
||||
struct oc_base_opt_data{
|
||||
const unsigned char *dct_fzig_zag;
|
||||
};
|
||||
|
||||
|
||||
/*State information common to both the encoder and decoder.*/
|
||||
struct oc_theora_state{
|
||||
/*The stream information.*/
|
||||
th_info info;
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
/*Table for shared accelerated functions.*/
|
||||
oc_base_opt_vtable opt_vtable;
|
||||
# endif
|
||||
/*Table for shared data used by accelerated functions.*/
|
||||
oc_base_opt_data opt_data;
|
||||
/*CPU flags to detect the presence of extended instruction sets.*/
|
||||
ogg_uint32_t cpu_flags;
|
||||
/*The fragment plane descriptions.*/
|
||||
oc_fragment_plane fplanes[3];
|
||||
/*The list of fragments, indexed in image order.*/
|
||||
oc_fragment *frags;
|
||||
/*The the offset into the reference frame buffer to the upper-left pixel of
|
||||
each fragment.*/
|
||||
ptrdiff_t *frag_buf_offs;
|
||||
/*The motion vector for each fragment.*/
|
||||
oc_mv *frag_mvs;
|
||||
/*The total number of fragments in a single frame.*/
|
||||
ptrdiff_t nfrags;
|
||||
/*The list of super block maps, indexed in image order.*/
|
||||
oc_sb_map *sb_maps;
|
||||
/*The list of super block flags, indexed in image order.*/
|
||||
oc_sb_flags *sb_flags;
|
||||
/*The total number of super blocks in a single frame.*/
|
||||
unsigned nsbs;
|
||||
/*The fragments from each color plane that belong to each macro block.
|
||||
Fragments are stored in image order (left to right then top to bottom).
|
||||
When chroma components are decimated, the extra fragments have an index of
|
||||
-1.*/
|
||||
oc_mb_map *mb_maps;
|
||||
/*The list of macro block modes.
|
||||
A negative number indicates the macro block lies entirely outside the
|
||||
coded frame.*/
|
||||
signed char *mb_modes;
|
||||
/*The number of macro blocks in the X direction.*/
|
||||
unsigned nhmbs;
|
||||
/*The number of macro blocks in the Y direction.*/
|
||||
unsigned nvmbs;
|
||||
/*The total number of macro blocks.*/
|
||||
size_t nmbs;
|
||||
/*The list of coded fragments, in coded order.
|
||||
Uncoded fragments are stored in reverse order from the end of the list.*/
|
||||
ptrdiff_t *coded_fragis;
|
||||
/*The number of coded fragments in each plane.*/
|
||||
ptrdiff_t ncoded_fragis[3];
|
||||
/*The total number of coded fragments.*/
|
||||
ptrdiff_t ntotal_coded_fragis;
|
||||
/*The index of the buffers being used for each OC_FRAME_* reference frame.*/
|
||||
int ref_frame_idx[6];
|
||||
/*The actual buffers used for the reference frames.*/
|
||||
th_ycbcr_buffer ref_frame_bufs[6];
|
||||
/*The storage for the reference frame buffers.*/
|
||||
unsigned char *ref_frame_data[6];
|
||||
/*The strides for each plane in the reference frames.*/
|
||||
int ref_ystride[3];
|
||||
/*The number of unique border patterns.*/
|
||||
int nborders;
|
||||
/*The unique border patterns for all border fragments.
|
||||
The borderi field of fragments which straddle the border indexes this
|
||||
list.*/
|
||||
oc_border_info borders[16];
|
||||
/*The frame number of the last keyframe.*/
|
||||
ogg_int64_t keyframe_num;
|
||||
/*The frame number of the current frame.*/
|
||||
ogg_int64_t curframe_num;
|
||||
/*The granpos of the current frame.*/
|
||||
ogg_int64_t granpos;
|
||||
/*The type of the current frame.*/
|
||||
signed char frame_type;
|
||||
/*The bias to add to the frame count when computing granule positions.*/
|
||||
unsigned char granpos_bias;
|
||||
/*The number of quality indices used in the current frame.*/
|
||||
unsigned char nqis;
|
||||
/*The quality indices of the current frame.*/
|
||||
unsigned char qis[3];
|
||||
/*The dequantization tables, stored in zig-zag order, and indexed by
|
||||
qi, pli, qti, and zzi.*/
|
||||
ogg_uint16_t *dequant_tables[64][3][2];
|
||||
OC_ALIGN16(oc_quant_table dequant_table_data[64][3][2]);
|
||||
/*Loop filter strength parameters.*/
|
||||
unsigned char loop_filter_limits[64];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*The function type used to fill in the chroma plane motion vectors for a
|
||||
macro block when 4 different motion vectors are specified in the luma
|
||||
plane.
|
||||
_cbmvs: The chroma block-level motion vectors to fill in.
|
||||
_lmbmv: The luma macro-block level motion vector to fill in for use in
|
||||
prediction.
|
||||
_lbmvs: The luma block-level motion vectors.*/
|
||||
typedef void (*oc_set_chroma_mvs_func)(oc_mv _cbmvs[4],const oc_mv _lbmvs[4]);
|
||||
|
||||
|
||||
|
||||
/*A table of functions used to fill in the Cb,Cr plane motion vectors for a
|
||||
macro block when 4 different motion vectors are specified in the luma
|
||||
plane.*/
|
||||
extern const oc_set_chroma_mvs_func OC_SET_CHROMA_MVS_TABLE[TH_PF_NFORMATS];
|
||||
|
||||
|
||||
|
||||
int oc_state_init(oc_theora_state *_state,const th_info *_info,int _nrefs);
|
||||
void oc_state_clear(oc_theora_state *_state);
|
||||
void oc_state_accel_init_c(oc_theora_state *_state);
|
||||
void oc_state_borders_fill_rows(oc_theora_state *_state,int _refi,int _pli,
|
||||
int _y0,int _yend);
|
||||
void oc_state_borders_fill_caps(oc_theora_state *_state,int _refi,int _pli);
|
||||
void oc_state_borders_fill(oc_theora_state *_state,int _refi);
|
||||
void oc_state_fill_buffer_ptrs(oc_theora_state *_state,int _buf_idx,
|
||||
th_ycbcr_buffer _img);
|
||||
int oc_state_mbi_for_pos(oc_theora_state *_state,int _mbx,int _mby);
|
||||
int oc_state_get_mv_offsets(const oc_theora_state *_state,int _offsets[2],
|
||||
int _pli,oc_mv _mv);
|
||||
|
||||
void oc_loop_filter_init_c(signed char _bv[256],int _flimit);
|
||||
void oc_state_loop_filter(oc_theora_state *_state,int _frame);
|
||||
# if defined(OC_DUMP_IMAGES)
|
||||
int oc_state_dump_frame(const oc_theora_state *_state,int _frame,
|
||||
const char *_suf);
|
||||
# endif
|
||||
|
||||
/*Default pure-C implementations of shared accelerated functions.*/
|
||||
void oc_frag_copy_c(unsigned char *_dst,
|
||||
const unsigned char *_src,int _src_ystride);
|
||||
void oc_frag_copy_list_c(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||
void oc_frag_recon_intra_c(unsigned char *_dst,int _dst_ystride,
|
||||
const ogg_int16_t _residue[64]);
|
||||
void oc_frag_recon_inter_c(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride,const ogg_int16_t _residue[64]);
|
||||
void oc_frag_recon_inter2_c(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t _residue[64]);
|
||||
void oc_idct8x8_c(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||
void oc_state_frag_recon_c(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||
void oc_state_loop_filter_frag_rows_c(const oc_theora_state *_state,
|
||||
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||
void oc_restore_fpu_c(void);
|
||||
|
||||
/*We need a way to call a few encoder functions without introducing a link-time
|
||||
dependency into the decoder, while still allowing the old alpha API which
|
||||
does not distinguish between encoder and decoder objects to be used.
|
||||
We do this by placing a function table at the start of the encoder object
|
||||
which can dispatch into the encoder library.
|
||||
We do a similar thing for the decoder in case we ever decide to split off a
|
||||
common base library.*/
|
||||
typedef void (*oc_state_clear_func)(theora_state *_th);
|
||||
typedef int (*oc_state_control_func)(theora_state *th,int _req,
|
||||
void *_buf,size_t _buf_sz);
|
||||
typedef ogg_int64_t (*oc_state_granule_frame_func)(theora_state *_th,
|
||||
ogg_int64_t _granulepos);
|
||||
typedef double (*oc_state_granule_time_func)(theora_state *_th,
|
||||
ogg_int64_t _granulepos);
|
||||
|
||||
|
||||
struct oc_state_dispatch_vtable{
|
||||
oc_state_clear_func clear;
|
||||
oc_state_control_func control;
|
||||
oc_state_granule_frame_func granule_frame;
|
||||
oc_state_granule_time_func granule_time;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,904 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: dsp_mmx.c 14579 2008-03-12 06:42:40Z xiphmont $
|
||||
|
||||
********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include "x86enc.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
unsigned oc_enc_frag_sad_mmxext(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
ptrdiff_t ystride3;
|
||||
ptrdiff_t ret;
|
||||
__asm__ __volatile__(
|
||||
/*Load the first 4 rows of each block.*/
|
||||
"movq (%[src]),%%mm0\n\t"
|
||||
"movq (%[ref]),%%mm1\n\t"
|
||||
"movq (%[src],%[ystride]),%%mm2\n\t"
|
||||
"movq (%[ref],%[ystride]),%%mm3\n\t"
|
||||
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t"
|
||||
"movq (%[src],%[ystride],2),%%mm4\n\t"
|
||||
"movq (%[ref],%[ystride],2),%%mm5\n\t"
|
||||
"movq (%[src],%[ystride3]),%%mm6\n\t"
|
||||
"movq (%[ref],%[ystride3]),%%mm7\n\t"
|
||||
/*Compute their SADs and add them in %%mm0*/
|
||||
"psadbw %%mm1,%%mm0\n\t"
|
||||
"psadbw %%mm3,%%mm2\n\t"
|
||||
"lea (%[src],%[ystride],4),%[src]\n\t"
|
||||
"paddw %%mm2,%%mm0\n\t"
|
||||
"lea (%[ref],%[ystride],4),%[ref]\n\t"
|
||||
/*Load the next 3 rows as registers become available.*/
|
||||
"movq (%[src]),%%mm2\n\t"
|
||||
"movq (%[ref]),%%mm3\n\t"
|
||||
"psadbw %%mm5,%%mm4\n\t"
|
||||
"psadbw %%mm7,%%mm6\n\t"
|
||||
"paddw %%mm4,%%mm0\n\t"
|
||||
"movq (%[ref],%[ystride]),%%mm5\n\t"
|
||||
"movq (%[src],%[ystride]),%%mm4\n\t"
|
||||
"paddw %%mm6,%%mm0\n\t"
|
||||
"movq (%[ref],%[ystride],2),%%mm7\n\t"
|
||||
"movq (%[src],%[ystride],2),%%mm6\n\t"
|
||||
/*Start adding their SADs to %%mm0*/
|
||||
"psadbw %%mm3,%%mm2\n\t"
|
||||
"psadbw %%mm5,%%mm4\n\t"
|
||||
"paddw %%mm2,%%mm0\n\t"
|
||||
"psadbw %%mm7,%%mm6\n\t"
|
||||
/*Load last row as registers become available.*/
|
||||
"movq (%[src],%[ystride3]),%%mm2\n\t"
|
||||
"movq (%[ref],%[ystride3]),%%mm3\n\t"
|
||||
/*And finish adding up their SADs.*/
|
||||
"paddw %%mm4,%%mm0\n\t"
|
||||
"psadbw %%mm3,%%mm2\n\t"
|
||||
"paddw %%mm6,%%mm0\n\t"
|
||||
"paddw %%mm2,%%mm0\n\t"
|
||||
"movd %%mm0,%[ret]\n\t"
|
||||
:[ret]"=a"(ret),[src]"+%r"(_src),[ref]"+r"(_ref),[ystride3]"=&r"(ystride3)
|
||||
:[ystride]"r"((ptrdiff_t)_ystride)
|
||||
);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_sad_thresh_mmxext(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,unsigned _thresh){
|
||||
/*Early termination is for suckers.*/
|
||||
return oc_enc_frag_sad_mmxext(_src,_ref,_ystride);
|
||||
}
|
||||
|
||||
/*Assumes the first two rows of %[ref1] and %[ref2] are in %%mm0...%%mm3, the
|
||||
first two rows of %[src] are in %%mm4,%%mm5, and {1}x8 is in %%mm7.
|
||||
We pre-load the next two rows of data as registers become available.*/
|
||||
#define OC_SAD2_LOOP \
|
||||
"#OC_SAD2_LOOP\n\t" \
|
||||
/*We want to compute (%%mm0+%%mm1>>1) on unsigned bytes without overflow, but \
|
||||
pavgb computes (%%mm0+%%mm1+1>>1). \
|
||||
The latter is exactly 1 too large when the low bit of two corresponding \
|
||||
bytes is only set in one of them. \
|
||||
Therefore we pxor the operands, pand to mask out the low bits, and psubb to \
|
||||
correct the output of pavgb. \
|
||||
TODO: This should be rewritten to compute ~pavgb(~a,~b) instead, which \
|
||||
schedules better; currently, however, this function is unused.*/ \
|
||||
"movq %%mm0,%%mm6\n\t" \
|
||||
"lea (%[ref1],%[ystride],2),%[ref1]\n\t" \
|
||||
"pxor %%mm1,%%mm0\n\t" \
|
||||
"pavgb %%mm1,%%mm6\n\t" \
|
||||
"lea (%[ref2],%[ystride],2),%[ref2]\n\t" \
|
||||
"movq %%mm2,%%mm1\n\t" \
|
||||
"pand %%mm7,%%mm0\n\t" \
|
||||
"pavgb %%mm3,%%mm2\n\t" \
|
||||
"pxor %%mm3,%%mm1\n\t" \
|
||||
"movq (%[ref2],%[ystride]),%%mm3\n\t" \
|
||||
"psubb %%mm0,%%mm6\n\t" \
|
||||
"movq (%[ref1]),%%mm0\n\t" \
|
||||
"pand %%mm7,%%mm1\n\t" \
|
||||
"psadbw %%mm6,%%mm4\n\t" \
|
||||
"movd %[ret],%%mm6\n\t" \
|
||||
"psubb %%mm1,%%mm2\n\t" \
|
||||
"movq (%[ref2]),%%mm1\n\t" \
|
||||
"lea (%[src],%[ystride],2),%[src]\n\t" \
|
||||
"psadbw %%mm2,%%mm5\n\t" \
|
||||
"movq (%[ref1],%[ystride]),%%mm2\n\t" \
|
||||
"paddw %%mm4,%%mm5\n\t" \
|
||||
"movq (%[src]),%%mm4\n\t" \
|
||||
"paddw %%mm5,%%mm6\n\t" \
|
||||
"movq (%[src],%[ystride]),%%mm5\n\t" \
|
||||
"movd %%mm6,%[ret]\n\t" \
|
||||
|
||||
/*Same as above, but does not pre-load the next two rows.*/
|
||||
#define OC_SAD2_TAIL \
|
||||
"#OC_SAD2_TAIL\n\t" \
|
||||
"movq %%mm0,%%mm6\n\t" \
|
||||
"pavgb %%mm1,%%mm0\n\t" \
|
||||
"pxor %%mm1,%%mm6\n\t" \
|
||||
"movq %%mm2,%%mm1\n\t" \
|
||||
"pand %%mm7,%%mm6\n\t" \
|
||||
"pavgb %%mm3,%%mm2\n\t" \
|
||||
"pxor %%mm3,%%mm1\n\t" \
|
||||
"psubb %%mm6,%%mm0\n\t" \
|
||||
"pand %%mm7,%%mm1\n\t" \
|
||||
"psadbw %%mm0,%%mm4\n\t" \
|
||||
"psubb %%mm1,%%mm2\n\t" \
|
||||
"movd %[ret],%%mm6\n\t" \
|
||||
"psadbw %%mm2,%%mm5\n\t" \
|
||||
"paddw %%mm4,%%mm5\n\t" \
|
||||
"paddw %%mm5,%%mm6\n\t" \
|
||||
"movd %%mm6,%[ret]\n\t" \
|
||||
|
||||
unsigned oc_enc_frag_sad2_thresh_mmxext(const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride,
|
||||
unsigned _thresh){
|
||||
ptrdiff_t ret;
|
||||
__asm__ __volatile__(
|
||||
"movq (%[ref1]),%%mm0\n\t"
|
||||
"movq (%[ref2]),%%mm1\n\t"
|
||||
"movq (%[ref1],%[ystride]),%%mm2\n\t"
|
||||
"movq (%[ref2],%[ystride]),%%mm3\n\t"
|
||||
"xor %[ret],%[ret]\n\t"
|
||||
"movq (%[src]),%%mm4\n\t"
|
||||
"pxor %%mm7,%%mm7\n\t"
|
||||
"pcmpeqb %%mm6,%%mm6\n\t"
|
||||
"movq (%[src],%[ystride]),%%mm5\n\t"
|
||||
"psubb %%mm6,%%mm7\n\t"
|
||||
OC_SAD2_LOOP
|
||||
OC_SAD2_LOOP
|
||||
OC_SAD2_LOOP
|
||||
OC_SAD2_TAIL
|
||||
:[ret]"=&a"(ret),[src]"+r"(_src),[ref1]"+%r"(_ref1),[ref2]"+r"(_ref2)
|
||||
:[ystride]"r"((ptrdiff_t)_ystride)
|
||||
);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
|
||||
/*Load an 8x4 array of pixel values from %[src] and %[ref] and compute their
|
||||
16-bit difference in %%mm0...%%mm7.*/
|
||||
#define OC_LOAD_SUB_8x4(_off) \
|
||||
"#OC_LOAD_SUB_8x4\n\t" \
|
||||
"movd "#_off"(%[src]),%%mm0\n\t" \
|
||||
"movd "#_off"(%[ref]),%%mm4\n\t" \
|
||||
"movd "#_off"(%[src],%[src_ystride]),%%mm1\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"movd "#_off"(%[ref],%[ref_ystride]),%%mm5\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"movd "#_off"(%[src]),%%mm2\n\t" \
|
||||
"movd "#_off"(%[ref]),%%mm7\n\t" \
|
||||
"movd "#_off"(%[src],%[src_ystride]),%%mm3\n\t" \
|
||||
"movd "#_off"(%[ref],%[ref_ystride]),%%mm6\n\t" \
|
||||
"punpcklbw %%mm4,%%mm0\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"punpcklbw %%mm4,%%mm4\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"psubw %%mm4,%%mm0\n\t" \
|
||||
"movd "#_off"(%[src]),%%mm4\n\t" \
|
||||
"movq %%mm0,"OC_MEM_OFFS(_off*2,buf)"\n\t" \
|
||||
"movd "#_off"(%[ref]),%%mm0\n\t" \
|
||||
"punpcklbw %%mm5,%%mm1\n\t" \
|
||||
"punpcklbw %%mm5,%%mm5\n\t" \
|
||||
"psubw %%mm5,%%mm1\n\t" \
|
||||
"movd "#_off"(%[src],%[src_ystride]),%%mm5\n\t" \
|
||||
"punpcklbw %%mm7,%%mm2\n\t" \
|
||||
"punpcklbw %%mm7,%%mm7\n\t" \
|
||||
"psubw %%mm7,%%mm2\n\t" \
|
||||
"movd "#_off"(%[ref],%[ref_ystride]),%%mm7\n\t" \
|
||||
"punpcklbw %%mm6,%%mm3\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"punpcklbw %%mm6,%%mm6\n\t" \
|
||||
"psubw %%mm6,%%mm3\n\t" \
|
||||
"movd "#_off"(%[src]),%%mm6\n\t" \
|
||||
"punpcklbw %%mm0,%%mm4\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"punpcklbw %%mm0,%%mm0\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"psubw %%mm0,%%mm4\n\t" \
|
||||
"movd "#_off"(%[ref]),%%mm0\n\t" \
|
||||
"punpcklbw %%mm7,%%mm5\n\t" \
|
||||
"neg %[src_ystride]\n\t" \
|
||||
"punpcklbw %%mm7,%%mm7\n\t" \
|
||||
"psubw %%mm7,%%mm5\n\t" \
|
||||
"movd "#_off"(%[src],%[src_ystride]),%%mm7\n\t" \
|
||||
"punpcklbw %%mm0,%%mm6\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"punpcklbw %%mm0,%%mm0\n\t" \
|
||||
"neg %[ref_ystride]\n\t" \
|
||||
"psubw %%mm0,%%mm6\n\t" \
|
||||
"movd "#_off"(%[ref],%[ref_ystride]),%%mm0\n\t" \
|
||||
"lea (%[src],%[src_ystride],8),%[src]\n\t" \
|
||||
"punpcklbw %%mm0,%%mm7\n\t" \
|
||||
"neg %[src_ystride]\n\t" \
|
||||
"punpcklbw %%mm0,%%mm0\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],8),%[ref]\n\t" \
|
||||
"psubw %%mm0,%%mm7\n\t" \
|
||||
"neg %[ref_ystride]\n\t" \
|
||||
"movq "OC_MEM_OFFS(_off*2,buf)",%%mm0\n\t" \
|
||||
|
||||
/*Load an 8x4 array of pixel values from %[src] into %%mm0...%%mm7.*/
|
||||
#define OC_LOAD_8x4(_off) \
|
||||
"#OC_LOAD_8x4\n\t" \
|
||||
"movd "#_off"(%[src]),%%mm0\n\t" \
|
||||
"movd "#_off"(%[src],%[ystride]),%%mm1\n\t" \
|
||||
"movd "#_off"(%[src],%[ystride],2),%%mm2\n\t" \
|
||||
"pxor %%mm7,%%mm7\n\t" \
|
||||
"movd "#_off"(%[src],%[ystride3]),%%mm3\n\t" \
|
||||
"punpcklbw %%mm7,%%mm0\n\t" \
|
||||
"movd "#_off"(%[src4]),%%mm4\n\t" \
|
||||
"punpcklbw %%mm7,%%mm1\n\t" \
|
||||
"movd "#_off"(%[src4],%[ystride]),%%mm5\n\t" \
|
||||
"punpcklbw %%mm7,%%mm2\n\t" \
|
||||
"movd "#_off"(%[src4],%[ystride],2),%%mm6\n\t" \
|
||||
"punpcklbw %%mm7,%%mm3\n\t" \
|
||||
"movd "#_off"(%[src4],%[ystride3]),%%mm7\n\t" \
|
||||
"punpcklbw %%mm4,%%mm4\n\t" \
|
||||
"punpcklbw %%mm5,%%mm5\n\t" \
|
||||
"psrlw $8,%%mm4\n\t" \
|
||||
"psrlw $8,%%mm5\n\t" \
|
||||
"punpcklbw %%mm6,%%mm6\n\t" \
|
||||
"punpcklbw %%mm7,%%mm7\n\t" \
|
||||
"psrlw $8,%%mm6\n\t" \
|
||||
"psrlw $8,%%mm7\n\t" \
|
||||
|
||||
/*Performs the first two stages of an 8-point 1-D Hadamard transform.
|
||||
The transform is performed in place, except that outputs 0-3 are swapped with
|
||||
outputs 4-7.
|
||||
Outputs 2, 3, 6, and 7 from the second stage are negated (which allows us to
|
||||
perform this stage in place with no temporary registers).*/
|
||||
#define OC_HADAMARD_AB_8x4 \
|
||||
"#OC_HADAMARD_AB_8x4\n\t" \
|
||||
/*Stage A: \
|
||||
Outputs 0-3 are swapped with 4-7 here.*/ \
|
||||
"paddw %%mm1,%%mm5\n\t" \
|
||||
"paddw %%mm2,%%mm6\n\t" \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
"paddw %%mm2,%%mm2\n\t" \
|
||||
"psubw %%mm5,%%mm1\n\t" \
|
||||
"psubw %%mm6,%%mm2\n\t" \
|
||||
"paddw %%mm3,%%mm7\n\t" \
|
||||
"paddw %%mm0,%%mm4\n\t" \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
"paddw %%mm0,%%mm0\n\t" \
|
||||
"psubw %%mm7,%%mm3\n\t" \
|
||||
"psubw %%mm4,%%mm0\n\t" \
|
||||
/*Stage B:*/ \
|
||||
"paddw %%mm2,%%mm0\n\t" \
|
||||
"paddw %%mm3,%%mm1\n\t" \
|
||||
"paddw %%mm6,%%mm4\n\t" \
|
||||
"paddw %%mm7,%%mm5\n\t" \
|
||||
"paddw %%mm2,%%mm2\n\t" \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
"paddw %%mm6,%%mm6\n\t" \
|
||||
"paddw %%mm7,%%mm7\n\t" \
|
||||
"psubw %%mm0,%%mm2\n\t" \
|
||||
"psubw %%mm1,%%mm3\n\t" \
|
||||
"psubw %%mm4,%%mm6\n\t" \
|
||||
"psubw %%mm5,%%mm7\n\t" \
|
||||
|
||||
/*Performs the last stage of an 8-point 1-D Hadamard transform in place.
|
||||
Outputs 1, 3, 5, and 7 are negated (which allows us to perform this stage in
|
||||
place with no temporary registers).*/
|
||||
#define OC_HADAMARD_C_8x4 \
|
||||
"#OC_HADAMARD_C_8x4\n\t" \
|
||||
/*Stage C:*/ \
|
||||
"paddw %%mm1,%%mm0\n\t" \
|
||||
"paddw %%mm3,%%mm2\n\t" \
|
||||
"paddw %%mm5,%%mm4\n\t" \
|
||||
"paddw %%mm7,%%mm6\n\t" \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
"paddw %%mm7,%%mm7\n\t" \
|
||||
"psubw %%mm0,%%mm1\n\t" \
|
||||
"psubw %%mm2,%%mm3\n\t" \
|
||||
"psubw %%mm4,%%mm5\n\t" \
|
||||
"psubw %%mm6,%%mm7\n\t" \
|
||||
|
||||
/*Performs an 8-point 1-D Hadamard transform.
|
||||
The transform is performed in place, except that outputs 0-3 are swapped with
|
||||
outputs 4-7.
|
||||
Outputs 1, 2, 5 and 6 are negated (which allows us to perform the transform
|
||||
in place with no temporary registers).*/
|
||||
#define OC_HADAMARD_8x4 \
|
||||
OC_HADAMARD_AB_8x4 \
|
||||
OC_HADAMARD_C_8x4 \
|
||||
|
||||
/*Performs the first part of the final stage of the Hadamard transform and
|
||||
summing of absolute values.
|
||||
At the end of this part, %%mm1 will contain the DC coefficient of the
|
||||
transform.*/
|
||||
#define OC_HADAMARD_C_ABS_ACCUM_A_8x4(_r6,_r7) \
|
||||
/*We use the fact that \
|
||||
(abs(a+b)+abs(a-b))/2=max(abs(a),abs(b)) \
|
||||
to merge the final butterfly with the abs and the first stage of \
|
||||
accumulation. \
|
||||
Thus we can avoid using pabsw, which is not available until SSSE3. \
|
||||
Emulating pabsw takes 3 instructions, so the straightforward MMXEXT \
|
||||
implementation would be (3+3)*8+7=55 instructions (+4 for spilling \
|
||||
registers). \
|
||||
Even with pabsw, it would be (3+1)*8+7=39 instructions (with no spills). \
|
||||
This implementation is only 26 (+4 for spilling registers).*/ \
|
||||
"#OC_HADAMARD_C_ABS_ACCUM_A_8x4\n\t" \
|
||||
"movq %%mm7,"OC_MEM_OFFS(_r7,buf)"\n\t" \
|
||||
"movq %%mm6,"OC_MEM_OFFS(_r6,buf)"\n\t" \
|
||||
/*mm7={0x7FFF}x4 \
|
||||
mm0=max(abs(mm0),abs(mm1))-0x7FFF*/ \
|
||||
"pcmpeqb %%mm7,%%mm7\n\t" \
|
||||
"movq %%mm0,%%mm6\n\t" \
|
||||
"psrlw $1,%%mm7\n\t" \
|
||||
"paddw %%mm1,%%mm6\n\t" \
|
||||
"pmaxsw %%mm1,%%mm0\n\t" \
|
||||
"paddsw %%mm7,%%mm6\n\t" \
|
||||
"psubw %%mm6,%%mm0\n\t" \
|
||||
/*mm2=max(abs(mm2),abs(mm3))-0x7FFF \
|
||||
mm4=max(abs(mm4),abs(mm5))-0x7FFF*/ \
|
||||
"movq %%mm2,%%mm6\n\t" \
|
||||
"movq %%mm4,%%mm1\n\t" \
|
||||
"pmaxsw %%mm3,%%mm2\n\t" \
|
||||
"pmaxsw %%mm5,%%mm4\n\t" \
|
||||
"paddw %%mm3,%%mm6\n\t" \
|
||||
"paddw %%mm5,%%mm1\n\t" \
|
||||
"movq "OC_MEM_OFFS(_r7,buf)",%%mm3\n\t" \
|
||||
|
||||
/*Performs the second part of the final stage of the Hadamard transform and
|
||||
summing of absolute values.*/
|
||||
#define OC_HADAMARD_C_ABS_ACCUM_B_8x4(_r6,_r7) \
|
||||
"#OC_HADAMARD_C_ABS_ACCUM_B_8x4\n\t" \
|
||||
"paddsw %%mm7,%%mm6\n\t" \
|
||||
"movq "OC_MEM_OFFS(_r6,buf)",%%mm5\n\t" \
|
||||
"paddsw %%mm7,%%mm1\n\t" \
|
||||
"psubw %%mm6,%%mm2\n\t" \
|
||||
"psubw %%mm1,%%mm4\n\t" \
|
||||
/*mm7={1}x4 (needed for the horizontal add that follows) \
|
||||
mm0+=mm2+mm4+max(abs(mm3),abs(mm5))-0x7FFF*/ \
|
||||
"movq %%mm3,%%mm6\n\t" \
|
||||
"pmaxsw %%mm5,%%mm3\n\t" \
|
||||
"paddw %%mm2,%%mm0\n\t" \
|
||||
"paddw %%mm5,%%mm6\n\t" \
|
||||
"paddw %%mm4,%%mm0\n\t" \
|
||||
"paddsw %%mm7,%%mm6\n\t" \
|
||||
"paddw %%mm3,%%mm0\n\t" \
|
||||
"psrlw $14,%%mm7\n\t" \
|
||||
"psubw %%mm6,%%mm0\n\t" \
|
||||
|
||||
/*Performs the last stage of an 8-point 1-D Hadamard transform, takes the
|
||||
absolute value of each component, and accumulates everything into mm0.
|
||||
This is the only portion of SATD which requires MMXEXT (we could use plain
|
||||
MMX, but it takes 4 instructions and an extra register to work around the
|
||||
lack of a pmaxsw, which is a pretty serious penalty).*/
|
||||
#define OC_HADAMARD_C_ABS_ACCUM_8x4(_r6,_r7) \
|
||||
OC_HADAMARD_C_ABS_ACCUM_A_8x4(_r6,_r7) \
|
||||
OC_HADAMARD_C_ABS_ACCUM_B_8x4(_r6,_r7) \
|
||||
|
||||
/*Performs an 8-point 1-D Hadamard transform, takes the absolute value of each
|
||||
component, and accumulates everything into mm0.
|
||||
Note that mm0 will have an extra 4 added to each column, and that after
|
||||
removing this value, the remainder will be half the conventional value.*/
|
||||
#define OC_HADAMARD_ABS_ACCUM_8x4(_r6,_r7) \
|
||||
OC_HADAMARD_AB_8x4 \
|
||||
OC_HADAMARD_C_ABS_ACCUM_8x4(_r6,_r7)
|
||||
|
||||
/*Performs two 4x4 transposes (mostly) in place.
|
||||
On input, {mm0,mm1,mm2,mm3} contains rows {e,f,g,h}, and {mm4,mm5,mm6,mm7}
|
||||
contains rows {a,b,c,d}.
|
||||
On output, {0x40,0x50,0x60,0x70}+_off(%[buf]) contains {e,f,g,h}^T, and
|
||||
{mm4,mm5,mm6,mm7} contains the transposed rows {a,b,c,d}^T.*/
|
||||
#define OC_TRANSPOSE_4x4x2(_off) \
|
||||
"#OC_TRANSPOSE_4x4x2\n\t" \
|
||||
/*First 4x4 transpose:*/ \
|
||||
"movq %%mm5,"OC_MEM_OFFS(0x10+(_off),buf)"\n\t" \
|
||||
/*mm0 = e3 e2 e1 e0 \
|
||||
mm1 = f3 f2 f1 f0 \
|
||||
mm2 = g3 g2 g1 g0 \
|
||||
mm3 = h3 h2 h1 h0*/ \
|
||||
"movq %%mm2,%%mm5\n\t" \
|
||||
"punpcklwd %%mm3,%%mm2\n\t" \
|
||||
"punpckhwd %%mm3,%%mm5\n\t" \
|
||||
"movq %%mm0,%%mm3\n\t" \
|
||||
"punpcklwd %%mm1,%%mm0\n\t" \
|
||||
"punpckhwd %%mm1,%%mm3\n\t" \
|
||||
/*mm0 = f1 e1 f0 e0 \
|
||||
mm3 = f3 e3 f2 e2 \
|
||||
mm2 = h1 g1 h0 g0 \
|
||||
mm5 = h3 g3 h2 g2*/ \
|
||||
"movq %%mm0,%%mm1\n\t" \
|
||||
"punpckldq %%mm2,%%mm0\n\t" \
|
||||
"punpckhdq %%mm2,%%mm1\n\t" \
|
||||
"movq %%mm3,%%mm2\n\t" \
|
||||
"punpckhdq %%mm5,%%mm3\n\t" \
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x40+(_off),buf)"\n\t" \
|
||||
"punpckldq %%mm5,%%mm2\n\t" \
|
||||
/*mm0 = h0 g0 f0 e0 \
|
||||
mm1 = h1 g1 f1 e1 \
|
||||
mm2 = h2 g2 f2 e2 \
|
||||
mm3 = h3 g3 f3 e3*/ \
|
||||
"movq "OC_MEM_OFFS(0x10+(_off),buf)",%%mm5\n\t" \
|
||||
/*Second 4x4 transpose:*/ \
|
||||
/*mm4 = a3 a2 a1 a0 \
|
||||
mm5 = b3 b2 b1 b0 \
|
||||
mm6 = c3 c2 c1 c0 \
|
||||
mm7 = d3 d2 d1 d0*/ \
|
||||
"movq %%mm6,%%mm0\n\t" \
|
||||
"punpcklwd %%mm7,%%mm6\n\t" \
|
||||
"movq %%mm1,"OC_MEM_OFFS(0x50+(_off),buf)"\n\t" \
|
||||
"punpckhwd %%mm7,%%mm0\n\t" \
|
||||
"movq %%mm4,%%mm7\n\t" \
|
||||
"punpcklwd %%mm5,%%mm4\n\t" \
|
||||
"movq %%mm2,"OC_MEM_OFFS(0x60+(_off),buf)"\n\t" \
|
||||
"punpckhwd %%mm5,%%mm7\n\t" \
|
||||
/*mm4 = b1 a1 b0 a0 \
|
||||
mm7 = b3 a3 b2 a2 \
|
||||
mm6 = d1 c1 d0 c0 \
|
||||
mm0 = d3 c3 d2 c2*/ \
|
||||
"movq %%mm4,%%mm5\n\t" \
|
||||
"punpckldq %%mm6,%%mm4\n\t" \
|
||||
"movq %%mm3,"OC_MEM_OFFS(0x70+(_off),buf)"\n\t" \
|
||||
"punpckhdq %%mm6,%%mm5\n\t" \
|
||||
"movq %%mm7,%%mm6\n\t" \
|
||||
"punpckhdq %%mm0,%%mm7\n\t" \
|
||||
"punpckldq %%mm0,%%mm6\n\t" \
|
||||
/*mm4 = d0 c0 b0 a0 \
|
||||
mm5 = d1 c1 b1 a1 \
|
||||
mm6 = d2 c2 b2 a2 \
|
||||
mm7 = d3 c3 b3 a3*/ \
|
||||
|
||||
static unsigned oc_int_frag_satd_mmxext(unsigned *_dc,
|
||||
const unsigned char *_src,int _src_ystride,
|
||||
const unsigned char *_ref,int _ref_ystride){
|
||||
OC_ALIGN8(ogg_int16_t buf[64]);
|
||||
unsigned ret;
|
||||
unsigned ret2;
|
||||
unsigned dc;
|
||||
__asm__ __volatile__(
|
||||
OC_LOAD_SUB_8x4(0x00)
|
||||
OC_HADAMARD_8x4
|
||||
OC_TRANSPOSE_4x4x2(0x00)
|
||||
/*Finish swapping out this 8x4 block to make room for the next one.
|
||||
mm0...mm3 have been swapped out already.*/
|
||||
"movq %%mm4,"OC_MEM_OFFS(0x00,buf)"\n\t"
|
||||
"movq %%mm5,"OC_MEM_OFFS(0x10,buf)"\n\t"
|
||||
"movq %%mm6,"OC_MEM_OFFS(0x20,buf)"\n\t"
|
||||
"movq %%mm7,"OC_MEM_OFFS(0x30,buf)"\n\t"
|
||||
OC_LOAD_SUB_8x4(0x04)
|
||||
OC_HADAMARD_8x4
|
||||
OC_TRANSPOSE_4x4x2(0x08)
|
||||
/*Here the first 4x4 block of output from the last transpose is the second
|
||||
4x4 block of input for the next transform.
|
||||
We have cleverly arranged that it already be in the appropriate place, so
|
||||
we only have to do half the loads.*/
|
||||
"movq "OC_MEM_OFFS(0x10,buf)",%%mm1\n\t"
|
||||
"movq "OC_MEM_OFFS(0x20,buf)",%%mm2\n\t"
|
||||
"movq "OC_MEM_OFFS(0x30,buf)",%%mm3\n\t"
|
||||
"movq "OC_MEM_OFFS(0x00,buf)",%%mm0\n\t"
|
||||
/*We split out the stages here so we can save the DC coefficient in the
|
||||
middle.*/
|
||||
OC_HADAMARD_AB_8x4
|
||||
OC_HADAMARD_C_ABS_ACCUM_A_8x4(0x28,0x38)
|
||||
"movd %%mm1,%[dc]\n\t"
|
||||
OC_HADAMARD_C_ABS_ACCUM_B_8x4(0x28,0x38)
|
||||
/*Up to this point, everything fit in 16 bits (8 input + 1 for the
|
||||
difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1
|
||||
for the factor of two we dropped + 3 for the vertical accumulation).
|
||||
Now we finally have to promote things to dwords.
|
||||
We break this part out of OC_HADAMARD_ABS_ACCUM_8x4 to hide the long
|
||||
latency of pmaddwd by starting the next series of loads now.*/
|
||||
"pmaddwd %%mm7,%%mm0\n\t"
|
||||
"movq "OC_MEM_OFFS(0x50,buf)",%%mm1\n\t"
|
||||
"movq "OC_MEM_OFFS(0x58,buf)",%%mm5\n\t"
|
||||
"movq %%mm0,%%mm4\n\t"
|
||||
"movq "OC_MEM_OFFS(0x60,buf)",%%mm2\n\t"
|
||||
"punpckhdq %%mm0,%%mm0\n\t"
|
||||
"movq "OC_MEM_OFFS(0x68,buf)",%%mm6\n\t"
|
||||
"paddd %%mm0,%%mm4\n\t"
|
||||
"movq "OC_MEM_OFFS(0x70,buf)",%%mm3\n\t"
|
||||
"movd %%mm4,%[ret2]\n\t"
|
||||
"movq "OC_MEM_OFFS(0x78,buf)",%%mm7\n\t"
|
||||
/*The sums produced by OC_HADAMARD_ABS_ACCUM_8x4 each have an extra 4
|
||||
added to them, and a factor of two removed; correct the final sum here.*/
|
||||
"movq "OC_MEM_OFFS(0x40,buf)",%%mm0\n\t"
|
||||
"movq "OC_MEM_OFFS(0x48,buf)",%%mm4\n\t"
|
||||
OC_HADAMARD_ABS_ACCUM_8x4(0x68,0x78)
|
||||
"pmaddwd %%mm7,%%mm0\n\t"
|
||||
/*Compute abs(dc).*/
|
||||
"movsx %w[dc],%[ret]\n\t"
|
||||
"cdq\n\t"
|
||||
"add %[ret2],%[ret2]\n\t"
|
||||
"add %[dc],%[ret]\n\t"
|
||||
"movq %%mm0,%%mm4\n\t"
|
||||
"punpckhdq %%mm0,%%mm0\n\t"
|
||||
"xor %[ret],%[dc]\n\t"
|
||||
"paddd %%mm0,%%mm4\n\t"
|
||||
"sub %[dc],%[ret2]\n\t"
|
||||
"movd %%mm4,%[ret]\n\t"
|
||||
"lea -64(%[ret2],%[ret],2),%[ret]\n\t"
|
||||
/*Although it looks like we're using 8 registers here, gcc can alias %[ret]
|
||||
and %[ret2] with some of the inputs, since for once we don't write to
|
||||
them until after we're done using everything but %[buf].*/
|
||||
/*Note that _src_ystride and _ref_ystride must be given non-overlapping
|
||||
constraints, otherewise if gcc can prove they're equal it will allocate
|
||||
them to the same register (which is bad); _src and _ref face a similar
|
||||
problem, though those are never actually the same.*/
|
||||
:[ret]"=a"(ret),[ret2]"=r"(ret2),[dc]"=d"(dc),
|
||||
[buf]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,buf,64))
|
||||
:[src]"r"(_src),[src_ystride]"c"((ptrdiff_t)_src_ystride),
|
||||
[ref]"r"(_ref),[ref_ystride]"d"((ptrdiff_t)_ref_ystride)
|
||||
/*We have to use neg, so we actually clobber the condition codes for once
|
||||
(not to mention cmp, sub, and add).*/
|
||||
:"cc"
|
||||
);
|
||||
*_dc=dc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_satd_mmxext(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
return oc_int_frag_satd_mmxext(_dc,_src,_ystride,_ref,_ystride);
|
||||
}
|
||||
|
||||
/*Our internal implementation of frag_copy2 takes an extra stride parameter so
|
||||
we can share code with oc_enc_frag_satd2_mmxext().*/
|
||||
void oc_int_frag_copy2_mmxext(unsigned char *_dst,int _dst_ystride,
|
||||
const unsigned char *_src1,const unsigned char *_src2,int _src_ystride){
|
||||
__asm__ __volatile__(
|
||||
/*Load the first 3 rows.*/
|
||||
"movq (%[src1]),%%mm0\n\t"
|
||||
"movq (%[src2]),%%mm1\n\t"
|
||||
"movq (%[src1],%[src_ystride]),%%mm2\n\t"
|
||||
"lea (%[src1],%[src_ystride],2),%[src1]\n\t"
|
||||
"movq (%[src2],%[src_ystride]),%%mm3\n\t"
|
||||
"lea (%[src2],%[src_ystride],2),%[src2]\n\t"
|
||||
"pxor %%mm7,%%mm7\n\t"
|
||||
"movq (%[src1]),%%mm4\n\t"
|
||||
"pcmpeqb %%mm6,%%mm6\n\t"
|
||||
"movq (%[src2]),%%mm5\n\t"
|
||||
/*mm7={1}x8.*/
|
||||
"psubb %%mm6,%%mm7\n\t"
|
||||
/*Start averaging %%mm0 and %%mm1 into %%mm6.*/
|
||||
"movq %%mm0,%%mm6\n\t"
|
||||
"pxor %%mm1,%%mm0\n\t"
|
||||
"pavgb %%mm1,%%mm6\n\t"
|
||||
/*%%mm1 is free, start averaging %%mm3 into %%mm2 using %%mm1.*/
|
||||
"movq %%mm2,%%mm1\n\t"
|
||||
"pand %%mm7,%%mm0\n\t"
|
||||
"pavgb %%mm3,%%mm2\n\t"
|
||||
"pxor %%mm3,%%mm1\n\t"
|
||||
/*%%mm3 is free.*/
|
||||
"psubb %%mm0,%%mm6\n\t"
|
||||
/*%%mm0 is free, start loading the next row.*/
|
||||
"movq (%[src1],%[src_ystride]),%%mm0\n\t"
|
||||
/*Start averaging %%mm5 and %%mm4 using %%mm3.*/
|
||||
"movq %%mm4,%%mm3\n\t"
|
||||
/*%%mm6 (row 0) is done; write it out.*/
|
||||
"movq %%mm6,(%[dst])\n\t"
|
||||
"pand %%mm7,%%mm1\n\t"
|
||||
"pavgb %%mm5,%%mm4\n\t"
|
||||
"psubb %%mm1,%%mm2\n\t"
|
||||
/*%%mm1 is free, continue loading the next row.*/
|
||||
"movq (%[src2],%[src_ystride]),%%mm1\n\t"
|
||||
"pxor %%mm5,%%mm3\n\t"
|
||||
"lea (%[src1],%[src_ystride],2),%[src1]\n\t"
|
||||
/*%%mm2 (row 1) is done; write it out.*/
|
||||
"movq %%mm2,(%[dst],%[dst_ystride])\n\t"
|
||||
"pand %%mm7,%%mm3\n\t"
|
||||
/*Start loading the next row.*/
|
||||
"movq (%[src1]),%%mm2\n\t"
|
||||
"lea (%[dst],%[dst_ystride],2),%[dst]\n\t"
|
||||
"psubb %%mm3,%%mm4\n\t"
|
||||
"lea (%[src2],%[src_ystride],2),%[src2]\n\t"
|
||||
/*%%mm4 (row 2) is done; write it out.*/
|
||||
"movq %%mm4,(%[dst])\n\t"
|
||||
/*Continue loading the next row.*/
|
||||
"movq (%[src2]),%%mm3\n\t"
|
||||
/*Start averaging %%mm0 and %%mm1 into %%mm6.*/
|
||||
"movq %%mm0,%%mm6\n\t"
|
||||
"pxor %%mm1,%%mm0\n\t"
|
||||
/*Start loading the next row.*/
|
||||
"movq (%[src1],%[src_ystride]),%%mm4\n\t"
|
||||
"pavgb %%mm1,%%mm6\n\t"
|
||||
/*%%mm1 is free; start averaging %%mm3 into %%mm2 using %%mm1.*/
|
||||
"movq %%mm2,%%mm1\n\t"
|
||||
"pand %%mm7,%%mm0\n\t"
|
||||
/*Continue loading the next row.*/
|
||||
"movq (%[src2],%[src_ystride]),%%mm5\n\t"
|
||||
"pavgb %%mm3,%%mm2\n\t"
|
||||
"lea (%[src1],%[src_ystride],2),%[src1]\n\t"
|
||||
"pxor %%mm3,%%mm1\n\t"
|
||||
/*%%mm3 is free.*/
|
||||
"psubb %%mm0,%%mm6\n\t"
|
||||
/*%%mm0 is free, start loading the next row.*/
|
||||
"movq (%[src1]),%%mm0\n\t"
|
||||
/*Start averaging %%mm5 into %%mm4 using %%mm3.*/
|
||||
"movq %%mm4,%%mm3\n\t"
|
||||
/*%%mm6 (row 3) is done; write it out.*/
|
||||
"movq %%mm6,(%[dst],%[dst_ystride])\n\t"
|
||||
"pand %%mm7,%%mm1\n\t"
|
||||
"lea (%[src2],%[src_ystride],2),%[src2]\n\t"
|
||||
"pavgb %%mm5,%%mm4\n\t"
|
||||
"lea (%[dst],%[dst_ystride],2),%[dst]\n\t"
|
||||
"psubb %%mm1,%%mm2\n\t"
|
||||
/*%%mm1 is free; continue loading the next row.*/
|
||||
"movq (%[src2]),%%mm1\n\t"
|
||||
"pxor %%mm5,%%mm3\n\t"
|
||||
/*%%mm2 (row 4) is done; write it out.*/
|
||||
"movq %%mm2,(%[dst])\n\t"
|
||||
"pand %%mm7,%%mm3\n\t"
|
||||
/*Start loading the next row.*/
|
||||
"movq (%[src1],%[src_ystride]),%%mm2\n\t"
|
||||
"psubb %%mm3,%%mm4\n\t"
|
||||
/*Start averaging %%mm0 and %%mm1 into %%mm6.*/
|
||||
"movq %%mm0,%%mm6\n\t"
|
||||
/*Continue loading the next row.*/
|
||||
"movq (%[src2],%[src_ystride]),%%mm3\n\t"
|
||||
/*%%mm4 (row 5) is done; write it out.*/
|
||||
"movq %%mm4,(%[dst],%[dst_ystride])\n\t"
|
||||
"pxor %%mm1,%%mm0\n\t"
|
||||
"pavgb %%mm1,%%mm6\n\t"
|
||||
/*%%mm4 is free; start averaging %%mm3 into %%mm2 using %%mm4.*/
|
||||
"movq %%mm2,%%mm4\n\t"
|
||||
"pand %%mm7,%%mm0\n\t"
|
||||
"pavgb %%mm3,%%mm2\n\t"
|
||||
"pxor %%mm3,%%mm4\n\t"
|
||||
"lea (%[dst],%[dst_ystride],2),%[dst]\n\t"
|
||||
"psubb %%mm0,%%mm6\n\t"
|
||||
"pand %%mm7,%%mm4\n\t"
|
||||
/*%%mm6 (row 6) is done, write it out.*/
|
||||
"movq %%mm6,(%[dst])\n\t"
|
||||
"psubb %%mm4,%%mm2\n\t"
|
||||
/*%%mm2 (row 7) is done, write it out.*/
|
||||
"movq %%mm2,(%[dst],%[dst_ystride])\n\t"
|
||||
:[dst]"+r"(_dst),[src1]"+%r"(_src1),[src2]"+r"(_src2)
|
||||
:[dst_ystride]"r"((ptrdiff_t)_dst_ystride),
|
||||
[src_ystride]"r"((ptrdiff_t)_src_ystride)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_satd2_mmxext(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride){
|
||||
OC_ALIGN8(unsigned char ref[64]);
|
||||
oc_int_frag_copy2_mmxext(ref,8,_ref1,_ref2,_ystride);
|
||||
return oc_int_frag_satd_mmxext(_dc,_src,_ystride,ref,8);
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_intra_satd_mmxext(unsigned *_dc,
|
||||
const unsigned char *_src,int _ystride){
|
||||
OC_ALIGN8(ogg_int16_t buf[64]);
|
||||
unsigned ret;
|
||||
unsigned ret2;
|
||||
unsigned dc;
|
||||
__asm__ __volatile__(
|
||||
OC_LOAD_8x4(0x00)
|
||||
OC_HADAMARD_8x4
|
||||
OC_TRANSPOSE_4x4x2(0x00)
|
||||
/*Finish swapping out this 8x4 block to make room for the next one.
|
||||
mm0...mm3 have been swapped out already.*/
|
||||
"movq %%mm4,"OC_MEM_OFFS(0x00,buf)"\n\t"
|
||||
"movq %%mm5,"OC_MEM_OFFS(0x10,buf)"\n\t"
|
||||
"movq %%mm6,"OC_MEM_OFFS(0x20,buf)"\n\t"
|
||||
"movq %%mm7,"OC_MEM_OFFS(0x30,buf)"\n\t"
|
||||
OC_LOAD_8x4(0x04)
|
||||
OC_HADAMARD_8x4
|
||||
OC_TRANSPOSE_4x4x2(0x08)
|
||||
/*Here the first 4x4 block of output from the last transpose is the second
|
||||
4x4 block of input for the next transform.
|
||||
We have cleverly arranged that it already be in the appropriate place, so
|
||||
we only have to do half the loads.*/
|
||||
"movq "OC_MEM_OFFS(0x10,buf)",%%mm1\n\t"
|
||||
"movq "OC_MEM_OFFS(0x20,buf)",%%mm2\n\t"
|
||||
"movq "OC_MEM_OFFS(0x30,buf)",%%mm3\n\t"
|
||||
"movq "OC_MEM_OFFS(0x00,buf)",%%mm0\n\t"
|
||||
/*We split out the stages here so we can save the DC coefficient in the
|
||||
middle.*/
|
||||
OC_HADAMARD_AB_8x4
|
||||
OC_HADAMARD_C_ABS_ACCUM_A_8x4(0x28,0x38)
|
||||
"movd %%mm1,%[dc]\n\t"
|
||||
OC_HADAMARD_C_ABS_ACCUM_B_8x4(0x28,0x38)
|
||||
/*Up to this point, everything fit in 16 bits (8 input + 1 for the
|
||||
difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1
|
||||
for the factor of two we dropped + 3 for the vertical accumulation).
|
||||
Now we finally have to promote things to dwords.
|
||||
We break this part out of OC_HADAMARD_ABS_ACCUM_8x4 to hide the long
|
||||
latency of pmaddwd by starting the next series of loads now.*/
|
||||
"pmaddwd %%mm7,%%mm0\n\t"
|
||||
"movq "OC_MEM_OFFS(0x50,buf)",%%mm1\n\t"
|
||||
"movq "OC_MEM_OFFS(0x58,buf)",%%mm5\n\t"
|
||||
"movq "OC_MEM_OFFS(0x60,buf)",%%mm2\n\t"
|
||||
"movq %%mm0,%%mm4\n\t"
|
||||
"movq "OC_MEM_OFFS(0x68,buf)",%%mm6\n\t"
|
||||
"punpckhdq %%mm0,%%mm0\n\t"
|
||||
"movq "OC_MEM_OFFS(0x70,buf)",%%mm3\n\t"
|
||||
"paddd %%mm0,%%mm4\n\t"
|
||||
"movq "OC_MEM_OFFS(0x78,buf)",%%mm7\n\t"
|
||||
"movd %%mm4,%[ret]\n\t"
|
||||
"movq "OC_MEM_OFFS(0x40,buf)",%%mm0\n\t"
|
||||
"movq "OC_MEM_OFFS(0x48,buf)",%%mm4\n\t"
|
||||
OC_HADAMARD_ABS_ACCUM_8x4(0x68,0x78)
|
||||
"pmaddwd %%mm7,%%mm0\n\t"
|
||||
/*We assume that the DC coefficient is always positive (which is true,
|
||||
because the input to the INTRA transform was not a difference).*/
|
||||
"movzx %w[dc],%[dc]\n\t"
|
||||
"add %[ret],%[ret]\n\t"
|
||||
"sub %[dc],%[ret]\n\t"
|
||||
"movq %%mm0,%%mm4\n\t"
|
||||
"punpckhdq %%mm0,%%mm0\n\t"
|
||||
"paddd %%mm0,%%mm4\n\t"
|
||||
"movd %%mm4,%[ret2]\n\t"
|
||||
"lea -64(%[ret],%[ret2],2),%[ret]\n\t"
|
||||
/*Although it looks like we're using 8 registers here, gcc can alias %[ret]
|
||||
and %[ret2] with some of the inputs, since for once we don't write to
|
||||
them until after we're done using everything but %[buf] (which is also
|
||||
listed as an output to ensure gcc _doesn't_ alias them against it).*/
|
||||
:[ret]"=a"(ret),[ret2]"=r"(ret2),[dc]"=r"(dc),
|
||||
[buf]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,buf,64))
|
||||
:[src]"r"(_src),[src4]"r"(_src+4*_ystride),
|
||||
[ystride]"r"((ptrdiff_t)_ystride),[ystride3]"r"((ptrdiff_t)3*_ystride)
|
||||
/*We have to use sub, so we actually clobber the condition codes for once
|
||||
(not to mention add).*/
|
||||
:"cc"
|
||||
);
|
||||
*_dc=dc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void oc_enc_frag_sub_mmx(ogg_int16_t _residue[64],
|
||||
const unsigned char *_src,const unsigned char *_ref,int _ystride){
|
||||
int i;
|
||||
__asm__ __volatile__("pxor %%mm7,%%mm7\n\t"::);
|
||||
for(i=4;i-->0;){
|
||||
__asm__ __volatile__(
|
||||
/*mm0=[src]*/
|
||||
"movq (%[src]),%%mm0\n\t"
|
||||
/*mm1=[ref]*/
|
||||
"movq (%[ref]),%%mm1\n\t"
|
||||
/*mm4=[src+ystride]*/
|
||||
"movq (%[src],%[ystride]),%%mm4\n\t"
|
||||
/*mm5=[ref+ystride]*/
|
||||
"movq (%[ref],%[ystride]),%%mm5\n\t"
|
||||
/*Compute [src]-[ref].*/
|
||||
"movq %%mm0,%%mm2\n\t"
|
||||
"punpcklbw %%mm7,%%mm0\n\t"
|
||||
"movq %%mm1,%%mm3\n\t"
|
||||
"punpckhbw %%mm7,%%mm2\n\t"
|
||||
"punpcklbw %%mm7,%%mm1\n\t"
|
||||
"punpckhbw %%mm7,%%mm3\n\t"
|
||||
"psubw %%mm1,%%mm0\n\t"
|
||||
"psubw %%mm3,%%mm2\n\t"
|
||||
/*Compute [src+ystride]-[ref+ystride].*/
|
||||
"movq %%mm4,%%mm1\n\t"
|
||||
"punpcklbw %%mm7,%%mm4\n\t"
|
||||
"movq %%mm5,%%mm3\n\t"
|
||||
"punpckhbw %%mm7,%%mm1\n\t"
|
||||
"lea (%[src],%[ystride],2),%[src]\n\t"
|
||||
"punpcklbw %%mm7,%%mm5\n\t"
|
||||
"lea (%[ref],%[ystride],2),%[ref]\n\t"
|
||||
"punpckhbw %%mm7,%%mm3\n\t"
|
||||
"psubw %%mm5,%%mm4\n\t"
|
||||
"psubw %%mm3,%%mm1\n\t"
|
||||
/*Write the answer out.*/
|
||||
"movq %%mm0,0x00(%[residue])\n\t"
|
||||
"movq %%mm2,0x08(%[residue])\n\t"
|
||||
"movq %%mm4,0x10(%[residue])\n\t"
|
||||
"movq %%mm1,0x18(%[residue])\n\t"
|
||||
"lea 0x20(%[residue]),%[residue]\n\t"
|
||||
:[residue]"+r"(_residue),[src]"+r"(_src),[ref]"+r"(_ref)
|
||||
:[ystride]"r"((ptrdiff_t)_ystride)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void oc_enc_frag_sub_128_mmx(ogg_int16_t _residue[64],
|
||||
const unsigned char *_src,int _ystride){
|
||||
ptrdiff_t ystride3;
|
||||
__asm__ __volatile__(
|
||||
/*mm0=[src]*/
|
||||
"movq (%[src]),%%mm0\n\t"
|
||||
/*mm1=[src+ystride]*/
|
||||
"movq (%[src],%[ystride]),%%mm1\n\t"
|
||||
/*mm6={-1}x4*/
|
||||
"pcmpeqw %%mm6,%%mm6\n\t"
|
||||
/*mm2=[src+2*ystride]*/
|
||||
"movq (%[src],%[ystride],2),%%mm2\n\t"
|
||||
/*[ystride3]=3*[ystride]*/
|
||||
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t"
|
||||
/*mm6={1}x4*/
|
||||
"psllw $15,%%mm6\n\t"
|
||||
/*mm3=[src+3*ystride]*/
|
||||
"movq (%[src],%[ystride3]),%%mm3\n\t"
|
||||
/*mm6={128}x4*/
|
||||
"psrlw $8,%%mm6\n\t"
|
||||
/*mm7=0*/
|
||||
"pxor %%mm7,%%mm7\n\t"
|
||||
/*[src]=[src]+4*[ystride]*/
|
||||
"lea (%[src],%[ystride],4),%[src]\n\t"
|
||||
/*Compute [src]-128 and [src+ystride]-128*/
|
||||
"movq %%mm0,%%mm4\n\t"
|
||||
"punpcklbw %%mm7,%%mm0\n\t"
|
||||
"movq %%mm1,%%mm5\n\t"
|
||||
"punpckhbw %%mm7,%%mm4\n\t"
|
||||
"psubw %%mm6,%%mm0\n\t"
|
||||
"punpcklbw %%mm7,%%mm1\n\t"
|
||||
"psubw %%mm6,%%mm4\n\t"
|
||||
"punpckhbw %%mm7,%%mm5\n\t"
|
||||
"psubw %%mm6,%%mm1\n\t"
|
||||
"psubw %%mm6,%%mm5\n\t"
|
||||
/*Write the answer out.*/
|
||||
"movq %%mm0,0x00(%[residue])\n\t"
|
||||
"movq %%mm4,0x08(%[residue])\n\t"
|
||||
"movq %%mm1,0x10(%[residue])\n\t"
|
||||
"movq %%mm5,0x18(%[residue])\n\t"
|
||||
/*mm0=[src+4*ystride]*/
|
||||
"movq (%[src]),%%mm0\n\t"
|
||||
/*mm1=[src+5*ystride]*/
|
||||
"movq (%[src],%[ystride]),%%mm1\n\t"
|
||||
/*Compute [src+2*ystride]-128 and [src+3*ystride]-128*/
|
||||
"movq %%mm2,%%mm4\n\t"
|
||||
"punpcklbw %%mm7,%%mm2\n\t"
|
||||
"movq %%mm3,%%mm5\n\t"
|
||||
"punpckhbw %%mm7,%%mm4\n\t"
|
||||
"psubw %%mm6,%%mm2\n\t"
|
||||
"punpcklbw %%mm7,%%mm3\n\t"
|
||||
"psubw %%mm6,%%mm4\n\t"
|
||||
"punpckhbw %%mm7,%%mm5\n\t"
|
||||
"psubw %%mm6,%%mm3\n\t"
|
||||
"psubw %%mm6,%%mm5\n\t"
|
||||
/*Write the answer out.*/
|
||||
"movq %%mm2,0x20(%[residue])\n\t"
|
||||
"movq %%mm4,0x28(%[residue])\n\t"
|
||||
"movq %%mm3,0x30(%[residue])\n\t"
|
||||
"movq %%mm5,0x38(%[residue])\n\t"
|
||||
/*mm2=[src+6*ystride]*/
|
||||
"movq (%[src],%[ystride],2),%%mm2\n\t"
|
||||
/*mm3=[src+7*ystride]*/
|
||||
"movq (%[src],%[ystride3]),%%mm3\n\t"
|
||||
/*Compute [src+4*ystride]-128 and [src+5*ystride]-128*/
|
||||
"movq %%mm0,%%mm4\n\t"
|
||||
"punpcklbw %%mm7,%%mm0\n\t"
|
||||
"movq %%mm1,%%mm5\n\t"
|
||||
"punpckhbw %%mm7,%%mm4\n\t"
|
||||
"psubw %%mm6,%%mm0\n\t"
|
||||
"punpcklbw %%mm7,%%mm1\n\t"
|
||||
"psubw %%mm6,%%mm4\n\t"
|
||||
"punpckhbw %%mm7,%%mm5\n\t"
|
||||
"psubw %%mm6,%%mm1\n\t"
|
||||
"psubw %%mm6,%%mm5\n\t"
|
||||
/*Write the answer out.*/
|
||||
"movq %%mm0,0x40(%[residue])\n\t"
|
||||
"movq %%mm4,0x48(%[residue])\n\t"
|
||||
"movq %%mm1,0x50(%[residue])\n\t"
|
||||
"movq %%mm5,0x58(%[residue])\n\t"
|
||||
/*Compute [src+6*ystride]-128 and [src+7*ystride]-128*/
|
||||
"movq %%mm2,%%mm4\n\t"
|
||||
"punpcklbw %%mm7,%%mm2\n\t"
|
||||
"movq %%mm3,%%mm5\n\t"
|
||||
"punpckhbw %%mm7,%%mm4\n\t"
|
||||
"psubw %%mm6,%%mm2\n\t"
|
||||
"punpcklbw %%mm7,%%mm3\n\t"
|
||||
"psubw %%mm6,%%mm4\n\t"
|
||||
"punpckhbw %%mm7,%%mm5\n\t"
|
||||
"psubw %%mm6,%%mm3\n\t"
|
||||
"psubw %%mm6,%%mm5\n\t"
|
||||
/*Write the answer out.*/
|
||||
"movq %%mm2,0x60(%[residue])\n\t"
|
||||
"movq %%mm4,0x68(%[residue])\n\t"
|
||||
"movq %%mm3,0x70(%[residue])\n\t"
|
||||
"movq %%mm5,0x78(%[residue])\n\t"
|
||||
:[src]"+r"(_src),[ystride3]"=&r"(ystride3)
|
||||
:[residue]"r"(_residue),[ystride]"r"((ptrdiff_t)_ystride)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
|
||||
void oc_enc_frag_copy2_mmxext(unsigned char *_dst,
|
||||
const unsigned char *_src1,const unsigned char *_src2,int _ystride){
|
||||
oc_int_frag_copy2_mmxext(_dst,_ystride,_src1,_src2,_ystride);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,665 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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) 1999-2006 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
/*MMX fDCT implementation for x86_32*/
|
||||
/*$Id: fdct_ses2.c 14579 2008-03-12 06:42:40Z xiphmont $*/
|
||||
#include "x86enc.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
# define OC_FDCT_STAGE1_8x4 \
|
||||
"#OC_FDCT_STAGE1_8x4\n\t" \
|
||||
/*Stage 1:*/ \
|
||||
/*mm0=t7'=t0-t7*/ \
|
||||
"psubw %%mm7,%%mm0\n\t" \
|
||||
"paddw %%mm7,%%mm7\n\t" \
|
||||
/*mm1=t6'=t1-t6*/ \
|
||||
"psubw %%mm6,%%mm1\n\t" \
|
||||
"paddw %%mm6,%%mm6\n\t" \
|
||||
/*mm2=t5'=t2-t5*/ \
|
||||
"psubw %%mm5,%%mm2\n\t" \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
/*mm3=t4'=t3-t4*/ \
|
||||
"psubw %%mm4,%%mm3\n\t" \
|
||||
"paddw %%mm4,%%mm4\n\t" \
|
||||
/*mm7=t0'=t0+t7*/ \
|
||||
"paddw %%mm0,%%mm7\n\t" \
|
||||
/*mm6=t1'=t1+t6*/ \
|
||||
"paddw %%mm1,%%mm6\n\t" \
|
||||
/*mm5=t2'=t2+t5*/ \
|
||||
"paddw %%mm2,%%mm5\n\t" \
|
||||
/*mm4=t3'=t3+t4*/ \
|
||||
"paddw %%mm3,%%mm4\n\t" \
|
||||
|
||||
# define OC_FDCT8x4(_r0,_r1,_r2,_r3,_r4,_r5,_r6,_r7) \
|
||||
"#OC_FDCT8x4\n\t" \
|
||||
/*Stage 2:*/ \
|
||||
/*mm7=t3''=t0'-t3'*/ \
|
||||
"psubw %%mm4,%%mm7\n\t" \
|
||||
"paddw %%mm4,%%mm4\n\t" \
|
||||
/*mm6=t2''=t1'-t2'*/ \
|
||||
"psubw %%mm5,%%mm6\n\t" \
|
||||
"movq %%mm7,"_r6"(%[y])\n\t" \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
/*mm1=t5''=t6'-t5'*/ \
|
||||
"psubw %%mm2,%%mm1\n\t" \
|
||||
"movq %%mm6,"_r2"(%[y])\n\t" \
|
||||
/*mm4=t0''=t0'+t3'*/ \
|
||||
"paddw %%mm7,%%mm4\n\t" \
|
||||
"paddw %%mm2,%%mm2\n\t" \
|
||||
/*mm5=t1''=t1'+t2'*/ \
|
||||
"movq %%mm4,"_r0"(%[y])\n\t" \
|
||||
"paddw %%mm6,%%mm5\n\t" \
|
||||
/*mm2=t6''=t6'+t5'*/ \
|
||||
"paddw %%mm1,%%mm2\n\t" \
|
||||
"movq %%mm5,"_r4"(%[y])\n\t" \
|
||||
/*mm0=t7', mm1=t5'', mm2=t6'', mm3=t4'.*/ \
|
||||
/*mm4, mm5, mm6, mm7 are free.*/ \
|
||||
/*Stage 3:*/ \
|
||||
/*mm6={2}x4, mm7={27146,0xB500>>1}x2*/ \
|
||||
"mov $0x5A806A0A,%[a]\n\t" \
|
||||
"pcmpeqb %%mm6,%%mm6\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"psrlw $15,%%mm6\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"paddw %%mm6,%%mm6\n\t" \
|
||||
/*mm0=0, m2={-1}x4 \
|
||||
mm5:mm4=t5''*27146+0xB500*/ \
|
||||
"movq %%mm1,%%mm4\n\t" \
|
||||
"movq %%mm1,%%mm5\n\t" \
|
||||
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||
"movq %%mm2,"_r3"(%[y])\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"movq %%mm0,"_r7"(%[y])\n\t" \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||
"pxor %%mm0,%%mm0\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"pcmpeqb %%mm2,%%mm2\n\t" \
|
||||
/*mm2=t6'', mm1=t5''+(t5''!=0) \
|
||||
mm4=(t5''*27146+0xB500>>16)*/ \
|
||||
"pcmpeqw %%mm1,%%mm0\n\t" \
|
||||
"psrad $16,%%mm4\n\t" \
|
||||
"psubw %%mm2,%%mm0\n\t" \
|
||||
"movq "_r3"(%[y]),%%mm2\n\t" \
|
||||
"psrad $16,%%mm5\n\t" \
|
||||
"paddw %%mm0,%%mm1\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
/*mm4=s=(t5''*27146+0xB500>>16)+t5''+(t5''!=0)>>1*/ \
|
||||
"paddw %%mm1,%%mm4\n\t" \
|
||||
"movq "_r7"(%[y]),%%mm0\n\t" \
|
||||
"psraw $1,%%mm4\n\t" \
|
||||
"movq %%mm3,%%mm1\n\t" \
|
||||
/*mm3=t4''=t4'+s*/ \
|
||||
"paddw %%mm4,%%mm3\n\t" \
|
||||
/*mm1=t5'''=t4'-s*/ \
|
||||
"psubw %%mm4,%%mm1\n\t" \
|
||||
/*mm1=0, mm3={-1}x4 \
|
||||
mm5:mm4=t6''*27146+0xB500*/ \
|
||||
"movq %%mm2,%%mm4\n\t" \
|
||||
"movq %%mm2,%%mm5\n\t" \
|
||||
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||
"movq %%mm1,"_r5"(%[y])\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"movq %%mm3,"_r1"(%[y])\n\t" \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||
"pxor %%mm1,%%mm1\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"pcmpeqb %%mm3,%%mm3\n\t" \
|
||||
/*mm2=t6''+(t6''!=0), mm4=(t6''*27146+0xB500>>16)*/ \
|
||||
"psrad $16,%%mm4\n\t" \
|
||||
"pcmpeqw %%mm2,%%mm1\n\t" \
|
||||
"psrad $16,%%mm5\n\t" \
|
||||
"psubw %%mm3,%%mm1\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
"paddw %%mm1,%%mm2\n\t" \
|
||||
/*mm1=t1'' \
|
||||
mm4=s=(t6''*27146+0xB500>>16)+t6''+(t6''!=0)>>1*/ \
|
||||
"paddw %%mm2,%%mm4\n\t" \
|
||||
"movq "_r4"(%[y]),%%mm1\n\t" \
|
||||
"psraw $1,%%mm4\n\t" \
|
||||
"movq %%mm0,%%mm2\n\t" \
|
||||
/*mm7={54491-0x7FFF,0x7FFF}x2 \
|
||||
mm0=t7''=t7'+s*/ \
|
||||
"paddw %%mm4,%%mm0\n\t" \
|
||||
/*mm2=t6'''=t7'-s*/ \
|
||||
"psubw %%mm4,%%mm2\n\t" \
|
||||
/*Stage 4:*/ \
|
||||
/*mm0=0, mm2=t0'' \
|
||||
mm5:mm4=t1''*27146+0xB500*/ \
|
||||
"movq %%mm1,%%mm4\n\t" \
|
||||
"movq %%mm1,%%mm5\n\t" \
|
||||
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||
"movq %%mm2,"_r3"(%[y])\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"movq "_r0"(%[y]),%%mm2\n\t" \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||
"movq %%mm0,"_r7"(%[y])\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"pxor %%mm0,%%mm0\n\t" \
|
||||
/*mm7={27146,0x4000>>1}x2 \
|
||||
mm0=s=(t1''*27146+0xB500>>16)+t1''+(t1''!=0)*/ \
|
||||
"psrad $16,%%mm4\n\t" \
|
||||
"mov $0x20006A0A,%[a]\n\t" \
|
||||
"pcmpeqw %%mm1,%%mm0\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"psrad $16,%%mm5\n\t" \
|
||||
"psubw %%mm3,%%mm0\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
"paddw %%mm1,%%mm0\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"paddw %%mm4,%%mm0\n\t" \
|
||||
/*mm6={0x00000E3D}x2 \
|
||||
mm1=-(t0''==0), mm5:mm4=t0''*27146+0x4000*/ \
|
||||
"movq %%mm2,%%mm4\n\t" \
|
||||
"movq %%mm2,%%mm5\n\t" \
|
||||
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||
"mov $0x0E3D,%[a]\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||
"movd %[a],%%mm6\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"pxor %%mm1,%%mm1\n\t" \
|
||||
"punpckldq %%mm6,%%mm6\n\t" \
|
||||
"pcmpeqw %%mm2,%%mm1\n\t" \
|
||||
/*mm4=r=(t0''*27146+0x4000>>16)+t0''+(t0''!=0)*/ \
|
||||
"psrad $16,%%mm4\n\t" \
|
||||
"psubw %%mm3,%%mm1\n\t" \
|
||||
"psrad $16,%%mm5\n\t" \
|
||||
"paddw %%mm1,%%mm2\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
"movq "_r5"(%[y]),%%mm1\n\t" \
|
||||
"paddw %%mm2,%%mm4\n\t" \
|
||||
/*mm2=t6'', mm0=_y[0]=u=r+s>>1 \
|
||||
The naive implementation could cause overflow, so we use \
|
||||
u=(r&s)+((r^s)>>1).*/ \
|
||||
"movq "_r3"(%[y]),%%mm2\n\t" \
|
||||
"movq %%mm0,%%mm7\n\t" \
|
||||
"pxor %%mm4,%%mm0\n\t" \
|
||||
"pand %%mm4,%%mm7\n\t" \
|
||||
"psraw $1,%%mm0\n\t" \
|
||||
"mov $0x7FFF54DC,%[a]\n\t" \
|
||||
"paddw %%mm7,%%mm0\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
/*mm7={54491-0x7FFF,0x7FFF}x2 \
|
||||
mm4=_y[4]=v=r-u*/ \
|
||||
"psubw %%mm0,%%mm4\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"movq %%mm4,"_r4"(%[y])\n\t" \
|
||||
/*mm0=0, mm7={36410}x4 \
|
||||
mm1=(t5'''!=0), mm5:mm4=54491*t5'''+0x0E3D*/ \
|
||||
"movq %%mm1,%%mm4\n\t" \
|
||||
"movq %%mm1,%%mm5\n\t" \
|
||||
"punpcklwd %%mm1,%%mm4\n\t" \
|
||||
"mov $0x8E3A8E3A,%[a]\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"movq %%mm0,"_r0"(%[y])\n\t" \
|
||||
"punpckhwd %%mm1,%%mm5\n\t" \
|
||||
"pxor %%mm0,%%mm0\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"pcmpeqw %%mm0,%%mm1\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"psubw %%mm3,%%mm1\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"paddd %%mm6,%%mm4\n\t" \
|
||||
"paddd %%mm6,%%mm5\n\t" \
|
||||
/*mm0=0 \
|
||||
mm3:mm1=36410*t6'''+((t5'''!=0)<<16)*/ \
|
||||
"movq %%mm2,%%mm6\n\t" \
|
||||
"movq %%mm2,%%mm3\n\t" \
|
||||
"pmulhw %%mm7,%%mm6\n\t" \
|
||||
"paddw %%mm2,%%mm1\n\t" \
|
||||
"pmullw %%mm7,%%mm3\n\t" \
|
||||
"pxor %%mm0,%%mm0\n\t" \
|
||||
"paddw %%mm1,%%mm6\n\t" \
|
||||
"movq %%mm3,%%mm1\n\t" \
|
||||
"punpckhwd %%mm6,%%mm3\n\t" \
|
||||
"punpcklwd %%mm6,%%mm1\n\t" \
|
||||
/*mm3={-1}x4, mm6={1}x4 \
|
||||
mm4=_y[5]=u=(54491*t5'''+36410*t6'''+0x0E3D>>16)+(t5'''!=0)*/ \
|
||||
"paddd %%mm3,%%mm5\n\t" \
|
||||
"paddd %%mm1,%%mm4\n\t" \
|
||||
"psrad $16,%%mm5\n\t" \
|
||||
"pxor %%mm6,%%mm6\n\t" \
|
||||
"psrad $16,%%mm4\n\t" \
|
||||
"pcmpeqb %%mm3,%%mm3\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
"psubw %%mm3,%%mm6\n\t" \
|
||||
/*mm1=t7'', mm7={26568,0x3400}x2 \
|
||||
mm2=s=t6'''-(36410*u>>16)*/ \
|
||||
"movq %%mm4,%%mm1\n\t" \
|
||||
"mov $0x340067C8,%[a]\n\t" \
|
||||
"pmulhw %%mm7,%%mm4\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"movq %%mm1,"_r5"(%[y])\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"paddw %%mm1,%%mm4\n\t" \
|
||||
"movq "_r7"(%[y]),%%mm1\n\t" \
|
||||
"psubw %%mm4,%%mm2\n\t" \
|
||||
/*mm6={0x00007B1B}x2 \
|
||||
mm0=(s!=0), mm5:mm4=s*26568+0x3400*/ \
|
||||
"movq %%mm2,%%mm4\n\t" \
|
||||
"movq %%mm2,%%mm5\n\t" \
|
||||
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||
"pcmpeqw %%mm2,%%mm0\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"mov $0x7B1B,%[a]\n\t" \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||
"movd %[a],%%mm6\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"psubw %%mm3,%%mm0\n\t" \
|
||||
"punpckldq %%mm6,%%mm6\n\t" \
|
||||
/*mm7={64277-0x7FFF,0x7FFF}x2 \
|
||||
mm2=_y[3]=v=(s*26568+0x3400>>17)+s+(s!=0)*/ \
|
||||
"psrad $17,%%mm4\n\t" \
|
||||
"paddw %%mm0,%%mm2\n\t" \
|
||||
"psrad $17,%%mm5\n\t" \
|
||||
"mov $0x7FFF7B16,%[a]\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"paddw %%mm4,%%mm2\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
/*mm0=0, mm7={12785}x4 \
|
||||
mm1=(t7''!=0), mm2=t4'', mm5:mm4=64277*t7''+0x7B1B*/ \
|
||||
"movq %%mm1,%%mm4\n\t" \
|
||||
"movq %%mm1,%%mm5\n\t" \
|
||||
"movq %%mm2,"_r3"(%[y])\n\t" \
|
||||
"punpcklwd %%mm1,%%mm4\n\t" \
|
||||
"movq "_r1"(%[y]),%%mm2\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"mov $0x31F131F1,%[a]\n\t" \
|
||||
"punpckhwd %%mm1,%%mm5\n\t" \
|
||||
"pxor %%mm0,%%mm0\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"pcmpeqw %%mm0,%%mm1\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"psubw %%mm3,%%mm1\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"paddd %%mm6,%%mm4\n\t" \
|
||||
"paddd %%mm6,%%mm5\n\t" \
|
||||
/*mm3:mm1=12785*t4'''+((t7''!=0)<<16)*/ \
|
||||
"movq %%mm2,%%mm6\n\t" \
|
||||
"movq %%mm2,%%mm3\n\t" \
|
||||
"pmulhw %%mm7,%%mm6\n\t" \
|
||||
"pmullw %%mm7,%%mm3\n\t" \
|
||||
"paddw %%mm1,%%mm6\n\t" \
|
||||
"movq %%mm3,%%mm1\n\t" \
|
||||
"punpckhwd %%mm6,%%mm3\n\t" \
|
||||
"punpcklwd %%mm6,%%mm1\n\t" \
|
||||
/*mm3={-1}x4, mm6={1}x4 \
|
||||
mm4=_y[1]=u=(12785*t4'''+64277*t7''+0x7B1B>>16)+(t7''!=0)*/ \
|
||||
"paddd %%mm3,%%mm5\n\t" \
|
||||
"paddd %%mm1,%%mm4\n\t" \
|
||||
"psrad $16,%%mm5\n\t" \
|
||||
"pxor %%mm6,%%mm6\n\t" \
|
||||
"psrad $16,%%mm4\n\t" \
|
||||
"pcmpeqb %%mm3,%%mm3\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
"psubw %%mm3,%%mm6\n\t" \
|
||||
/*mm1=t3'', mm7={20539,0x3000}x2 \
|
||||
mm4=s=(12785*u>>16)-t4''*/ \
|
||||
"movq %%mm4,"_r1"(%[y])\n\t" \
|
||||
"pmulhw %%mm7,%%mm4\n\t" \
|
||||
"mov $0x3000503B,%[a]\n\t" \
|
||||
"movq "_r6"(%[y]),%%mm1\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"psubw %%mm2,%%mm4\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
/*mm6={0x00006CB7}x2 \
|
||||
mm0=(s!=0), mm5:mm4=s*20539+0x3000*/ \
|
||||
"movq %%mm4,%%mm5\n\t" \
|
||||
"movq %%mm4,%%mm2\n\t" \
|
||||
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||
"pcmpeqw %%mm2,%%mm0\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"mov $0x6CB7,%[a]\n\t" \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||
"movd %[a],%%mm6\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"psubw %%mm3,%%mm0\n\t" \
|
||||
"punpckldq %%mm6,%%mm6\n\t" \
|
||||
/*mm7={60547-0x7FFF,0x7FFF}x2 \
|
||||
mm2=_y[7]=v=(s*20539+0x3000>>20)+s+(s!=0)*/ \
|
||||
"psrad $20,%%mm4\n\t" \
|
||||
"paddw %%mm0,%%mm2\n\t" \
|
||||
"psrad $20,%%mm5\n\t" \
|
||||
"mov $0x7FFF6C84,%[a]\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"paddw %%mm4,%%mm2\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
/*mm0=0, mm7={25080}x4 \
|
||||
mm2=t2'', mm5:mm4=60547*t3''+0x6CB7*/ \
|
||||
"movq %%mm1,%%mm4\n\t" \
|
||||
"movq %%mm1,%%mm5\n\t" \
|
||||
"movq %%mm2,"_r7"(%[y])\n\t" \
|
||||
"punpcklwd %%mm1,%%mm4\n\t" \
|
||||
"movq "_r2"(%[y]),%%mm2\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"mov $0x61F861F8,%[a]\n\t" \
|
||||
"punpckhwd %%mm1,%%mm5\n\t" \
|
||||
"pxor %%mm0,%%mm0\n\t" \
|
||||
"pmaddwd %%mm7,%%mm5\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"pcmpeqw %%mm0,%%mm1\n\t" \
|
||||
"psubw %%mm3,%%mm1\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"paddd %%mm6,%%mm4\n\t" \
|
||||
"paddd %%mm6,%%mm5\n\t" \
|
||||
/*mm3:mm1=25080*t2''+((t3''!=0)<<16)*/ \
|
||||
"movq %%mm2,%%mm6\n\t" \
|
||||
"movq %%mm2,%%mm3\n\t" \
|
||||
"pmulhw %%mm7,%%mm6\n\t" \
|
||||
"pmullw %%mm7,%%mm3\n\t" \
|
||||
"paddw %%mm1,%%mm6\n\t" \
|
||||
"movq %%mm3,%%mm1\n\t" \
|
||||
"punpckhwd %%mm6,%%mm3\n\t" \
|
||||
"punpcklwd %%mm6,%%mm1\n\t" \
|
||||
/*mm1={-1}x4 \
|
||||
mm4=u=(25080*t2''+60547*t3''+0x6CB7>>16)+(t3''!=0)*/ \
|
||||
"paddd %%mm3,%%mm5\n\t" \
|
||||
"paddd %%mm1,%%mm4\n\t" \
|
||||
"psrad $16,%%mm5\n\t" \
|
||||
"mov $0x28005460,%[a]\n\t" \
|
||||
"psrad $16,%%mm4\n\t" \
|
||||
"pcmpeqb %%mm1,%%mm1\n\t" \
|
||||
"packssdw %%mm5,%%mm4\n\t" \
|
||||
/*mm5={1}x4, mm6=_y[2]=u, mm7={21600,0x2800}x2 \
|
||||
mm4=s=(25080*u>>16)-t2''*/ \
|
||||
"movq %%mm4,%%mm6\n\t" \
|
||||
"pmulhw %%mm7,%%mm4\n\t" \
|
||||
"pxor %%mm5,%%mm5\n\t" \
|
||||
"movd %[a],%%mm7\n\t" \
|
||||
"psubw %%mm1,%%mm5\n\t" \
|
||||
"punpckldq %%mm7,%%mm7\n\t" \
|
||||
"psubw %%mm2,%%mm4\n\t" \
|
||||
/*mm2=s+(s!=0) \
|
||||
mm4:mm3=s*21600+0x2800*/ \
|
||||
"movq %%mm4,%%mm3\n\t" \
|
||||
"movq %%mm4,%%mm2\n\t" \
|
||||
"punpckhwd %%mm5,%%mm4\n\t" \
|
||||
"pcmpeqw %%mm2,%%mm0\n\t" \
|
||||
"pmaddwd %%mm7,%%mm4\n\t" \
|
||||
"psubw %%mm1,%%mm0\n\t" \
|
||||
"punpcklwd %%mm5,%%mm3\n\t" \
|
||||
"paddw %%mm0,%%mm2\n\t" \
|
||||
"pmaddwd %%mm7,%%mm3\n\t" \
|
||||
/*mm0=_y[4], mm1=_y[7], mm4=_y[0], mm5=_y[5] \
|
||||
mm3=_y[6]=v=(s*21600+0x2800>>18)+s+(s!=0)*/ \
|
||||
"movq "_r4"(%[y]),%%mm0\n\t" \
|
||||
"psrad $18,%%mm4\n\t" \
|
||||
"movq "_r5"(%[y]),%%mm5\n\t" \
|
||||
"psrad $18,%%mm3\n\t" \
|
||||
"movq "_r7"(%[y]),%%mm1\n\t" \
|
||||
"packssdw %%mm4,%%mm3\n\t" \
|
||||
"movq "_r0"(%[y]),%%mm4\n\t" \
|
||||
"paddw %%mm2,%%mm3\n\t" \
|
||||
|
||||
/*On input, mm4=_y[0], mm6=_y[2], mm0=_y[4], mm5=_y[5], mm3=_y[6], mm1=_y[7].
|
||||
On output, {_y[4],mm1,mm2,mm3} contains the transpose of _y[4...7] and
|
||||
{mm4,mm5,mm6,mm7} contains the transpose of _y[0...3].*/
|
||||
# define OC_TRANSPOSE8x4(_r0,_r1,_r2,_r3,_r4,_r5,_r6,_r7) \
|
||||
"#OC_TRANSPOSE8x4\n\t" \
|
||||
/*First 4x4 transpose:*/ \
|
||||
/*mm0 = e3 e2 e1 e0 \
|
||||
mm5 = f3 f2 f1 f0 \
|
||||
mm3 = g3 g2 g1 g0 \
|
||||
mm1 = h3 h2 h1 h0*/ \
|
||||
"movq %%mm0,%%mm2\n\t" \
|
||||
"punpcklwd %%mm5,%%mm0\n\t" \
|
||||
"punpckhwd %%mm5,%%mm2\n\t" \
|
||||
"movq %%mm3,%%mm5\n\t" \
|
||||
"punpcklwd %%mm1,%%mm3\n\t" \
|
||||
"punpckhwd %%mm1,%%mm5\n\t" \
|
||||
/*mm0 = f1 e1 f0 e0 \
|
||||
mm2 = f3 e3 f2 e2 \
|
||||
mm3 = h1 g1 h0 g0 \
|
||||
mm5 = h3 g3 h2 g2*/ \
|
||||
"movq %%mm0,%%mm1\n\t" \
|
||||
"punpckldq %%mm3,%%mm0\n\t" \
|
||||
"movq %%mm0,"_r4"(%[y])\n\t" \
|
||||
"punpckhdq %%mm3,%%mm1\n\t" \
|
||||
"movq "_r1"(%[y]),%%mm0\n\t" \
|
||||
"movq %%mm2,%%mm3\n\t" \
|
||||
"punpckldq %%mm5,%%mm2\n\t" \
|
||||
"punpckhdq %%mm5,%%mm3\n\t" \
|
||||
"movq "_r3"(%[y]),%%mm5\n\t" \
|
||||
/*_y[4] = h0 g0 f0 e0 \
|
||||
mm1 = h1 g1 f1 e1 \
|
||||
mm2 = h2 g2 f2 e2 \
|
||||
mm3 = h3 g3 f3 e3*/ \
|
||||
/*Second 4x4 transpose:*/ \
|
||||
/*mm4 = a3 a2 a1 a0 \
|
||||
mm0 = b3 b2 b1 b0 \
|
||||
mm6 = c3 c2 c1 c0 \
|
||||
mm5 = d3 d2 d1 d0*/ \
|
||||
"movq %%mm4,%%mm7\n\t" \
|
||||
"punpcklwd %%mm0,%%mm4\n\t" \
|
||||
"punpckhwd %%mm0,%%mm7\n\t" \
|
||||
"movq %%mm6,%%mm0\n\t" \
|
||||
"punpcklwd %%mm5,%%mm6\n\t" \
|
||||
"punpckhwd %%mm5,%%mm0\n\t" \
|
||||
/*mm4 = b1 a1 b0 a0 \
|
||||
mm7 = b3 a3 b2 a2 \
|
||||
mm6 = d1 c1 d0 c0 \
|
||||
mm0 = d3 c3 d2 c2*/ \
|
||||
"movq %%mm4,%%mm5\n\t" \
|
||||
"punpckldq %%mm6,%%mm4\n\t" \
|
||||
"punpckhdq %%mm6,%%mm5\n\t" \
|
||||
"movq %%mm7,%%mm6\n\t" \
|
||||
"punpckhdq %%mm0,%%mm7\n\t" \
|
||||
"punpckldq %%mm0,%%mm6\n\t" \
|
||||
/*mm4 = d0 c0 b0 a0 \
|
||||
mm5 = d1 c1 b1 a1 \
|
||||
mm6 = d2 c2 b2 a2 \
|
||||
mm7 = d3 c3 b3 a3*/ \
|
||||
|
||||
/*MMX implementation of the fDCT.*/
|
||||
void oc_enc_fdct8x8_mmx(ogg_int16_t _y[64],const ogg_int16_t _x[64]){
|
||||
ptrdiff_t a;
|
||||
__asm__ __volatile__(
|
||||
/*Add two extra bits of working precision to improve accuracy; any more and
|
||||
we could overflow.*/
|
||||
/*We also add biases to correct for some systematic error that remains in
|
||||
the full fDCT->iDCT round trip.*/
|
||||
"movq 0x00(%[x]),%%mm0\n\t"
|
||||
"movq 0x10(%[x]),%%mm1\n\t"
|
||||
"movq 0x20(%[x]),%%mm2\n\t"
|
||||
"movq 0x30(%[x]),%%mm3\n\t"
|
||||
"pcmpeqb %%mm4,%%mm4\n\t"
|
||||
"pxor %%mm7,%%mm7\n\t"
|
||||
"movq %%mm0,%%mm5\n\t"
|
||||
"psllw $2,%%mm0\n\t"
|
||||
"pcmpeqw %%mm7,%%mm5\n\t"
|
||||
"movq 0x70(%[x]),%%mm7\n\t"
|
||||
"psllw $2,%%mm1\n\t"
|
||||
"psubw %%mm4,%%mm5\n\t"
|
||||
"psllw $2,%%mm2\n\t"
|
||||
"mov $1,%[a]\n\t"
|
||||
"pslld $16,%%mm5\n\t"
|
||||
"movd %[a],%%mm6\n\t"
|
||||
"psllq $16,%%mm5\n\t"
|
||||
"mov $0x10001,%[a]\n\t"
|
||||
"psllw $2,%%mm3\n\t"
|
||||
"movd %[a],%%mm4\n\t"
|
||||
"punpckhwd %%mm6,%%mm5\n\t"
|
||||
"psubw %%mm6,%%mm1\n\t"
|
||||
"movq 0x60(%[x]),%%mm6\n\t"
|
||||
"paddw %%mm5,%%mm0\n\t"
|
||||
"movq 0x50(%[x]),%%mm5\n\t"
|
||||
"paddw %%mm4,%%mm0\n\t"
|
||||
"movq 0x40(%[x]),%%mm4\n\t"
|
||||
/*We inline stage1 of the transform here so we can get better instruction
|
||||
scheduling with the shifts.*/
|
||||
/*mm0=t7'=t0-t7*/
|
||||
"psllw $2,%%mm7\n\t"
|
||||
"psubw %%mm7,%%mm0\n\t"
|
||||
"psllw $2,%%mm6\n\t"
|
||||
"paddw %%mm7,%%mm7\n\t"
|
||||
/*mm1=t6'=t1-t6*/
|
||||
"psllw $2,%%mm5\n\t"
|
||||
"psubw %%mm6,%%mm1\n\t"
|
||||
"psllw $2,%%mm4\n\t"
|
||||
"paddw %%mm6,%%mm6\n\t"
|
||||
/*mm2=t5'=t2-t5*/
|
||||
"psubw %%mm5,%%mm2\n\t"
|
||||
"paddw %%mm5,%%mm5\n\t"
|
||||
/*mm3=t4'=t3-t4*/
|
||||
"psubw %%mm4,%%mm3\n\t"
|
||||
"paddw %%mm4,%%mm4\n\t"
|
||||
/*mm7=t0'=t0+t7*/
|
||||
"paddw %%mm0,%%mm7\n\t"
|
||||
/*mm6=t1'=t1+t6*/
|
||||
"paddw %%mm1,%%mm6\n\t"
|
||||
/*mm5=t2'=t2+t5*/
|
||||
"paddw %%mm2,%%mm5\n\t"
|
||||
/*mm4=t3'=t3+t4*/
|
||||
"paddw %%mm3,%%mm4\n\t"
|
||||
OC_FDCT8x4("0x00","0x10","0x20","0x30","0x40","0x50","0x60","0x70")
|
||||
OC_TRANSPOSE8x4("0x00","0x10","0x20","0x30","0x40","0x50","0x60","0x70")
|
||||
/*Swap out this 8x4 block for the next one.*/
|
||||
"movq 0x08(%[x]),%%mm0\n\t"
|
||||
"movq %%mm7,0x30(%[y])\n\t"
|
||||
"movq 0x78(%[x]),%%mm7\n\t"
|
||||
"movq %%mm1,0x50(%[y])\n\t"
|
||||
"movq 0x18(%[x]),%%mm1\n\t"
|
||||
"movq %%mm6,0x20(%[y])\n\t"
|
||||
"movq 0x68(%[x]),%%mm6\n\t"
|
||||
"movq %%mm2,0x60(%[y])\n\t"
|
||||
"movq 0x28(%[x]),%%mm2\n\t"
|
||||
"movq %%mm5,0x10(%[y])\n\t"
|
||||
"movq 0x58(%[x]),%%mm5\n\t"
|
||||
"movq %%mm3,0x70(%[y])\n\t"
|
||||
"movq 0x38(%[x]),%%mm3\n\t"
|
||||
/*And increase its working precision, too.*/
|
||||
"psllw $2,%%mm0\n\t"
|
||||
"movq %%mm4,0x00(%[y])\n\t"
|
||||
"psllw $2,%%mm7\n\t"
|
||||
"movq 0x48(%[x]),%%mm4\n\t"
|
||||
/*We inline stage1 of the transform here so we can get better instruction
|
||||
scheduling with the shifts.*/
|
||||
/*mm0=t7'=t0-t7*/
|
||||
"psubw %%mm7,%%mm0\n\t"
|
||||
"psllw $2,%%mm1\n\t"
|
||||
"paddw %%mm7,%%mm7\n\t"
|
||||
"psllw $2,%%mm6\n\t"
|
||||
/*mm1=t6'=t1-t6*/
|
||||
"psubw %%mm6,%%mm1\n\t"
|
||||
"psllw $2,%%mm2\n\t"
|
||||
"paddw %%mm6,%%mm6\n\t"
|
||||
"psllw $2,%%mm5\n\t"
|
||||
/*mm2=t5'=t2-t5*/
|
||||
"psubw %%mm5,%%mm2\n\t"
|
||||
"psllw $2,%%mm3\n\t"
|
||||
"paddw %%mm5,%%mm5\n\t"
|
||||
"psllw $2,%%mm4\n\t"
|
||||
/*mm3=t4'=t3-t4*/
|
||||
"psubw %%mm4,%%mm3\n\t"
|
||||
"paddw %%mm4,%%mm4\n\t"
|
||||
/*mm7=t0'=t0+t7*/
|
||||
"paddw %%mm0,%%mm7\n\t"
|
||||
/*mm6=t1'=t1+t6*/
|
||||
"paddw %%mm1,%%mm6\n\t"
|
||||
/*mm5=t2'=t2+t5*/
|
||||
"paddw %%mm2,%%mm5\n\t"
|
||||
/*mm4=t3'=t3+t4*/
|
||||
"paddw %%mm3,%%mm4\n\t"
|
||||
OC_FDCT8x4("0x08","0x18","0x28","0x38","0x48","0x58","0x68","0x78")
|
||||
OC_TRANSPOSE8x4("0x08","0x18","0x28","0x38","0x48","0x58","0x68","0x78")
|
||||
/*Here the first 4x4 block of output from the last transpose is the second
|
||||
4x4 block of input for the next transform.
|
||||
We have cleverly arranged that it already be in the appropriate place,
|
||||
so we only have to do half the stores and loads.*/
|
||||
"movq 0x00(%[y]),%%mm0\n\t"
|
||||
"movq %%mm1,0x58(%[y])\n\t"
|
||||
"movq 0x10(%[y]),%%mm1\n\t"
|
||||
"movq %%mm2,0x68(%[y])\n\t"
|
||||
"movq 0x20(%[y]),%%mm2\n\t"
|
||||
"movq %%mm3,0x78(%[y])\n\t"
|
||||
"movq 0x30(%[y]),%%mm3\n\t"
|
||||
OC_FDCT_STAGE1_8x4
|
||||
OC_FDCT8x4("0x00","0x10","0x20","0x30","0x08","0x18","0x28","0x38")
|
||||
OC_TRANSPOSE8x4("0x00","0x10","0x20","0x30","0x08","0x18","0x28","0x38")
|
||||
/*mm0={-2}x4*/
|
||||
"pcmpeqw %%mm0,%%mm0\n\t"
|
||||
"paddw %%mm0,%%mm0\n\t"
|
||||
/*Round the results.*/
|
||||
"psubw %%mm0,%%mm1\n\t"
|
||||
"psubw %%mm0,%%mm2\n\t"
|
||||
"psraw $2,%%mm1\n\t"
|
||||
"psubw %%mm0,%%mm3\n\t"
|
||||
"movq %%mm1,0x18(%[y])\n\t"
|
||||
"psraw $2,%%mm2\n\t"
|
||||
"psubw %%mm0,%%mm4\n\t"
|
||||
"movq 0x08(%[y]),%%mm1\n\t"
|
||||
"psraw $2,%%mm3\n\t"
|
||||
"psubw %%mm0,%%mm5\n\t"
|
||||
"psraw $2,%%mm4\n\t"
|
||||
"psubw %%mm0,%%mm6\n\t"
|
||||
"psraw $2,%%mm5\n\t"
|
||||
"psubw %%mm0,%%mm7\n\t"
|
||||
"psraw $2,%%mm6\n\t"
|
||||
"psubw %%mm0,%%mm1\n\t"
|
||||
"psraw $2,%%mm7\n\t"
|
||||
"movq 0x40(%[y]),%%mm0\n\t"
|
||||
"psraw $2,%%mm1\n\t"
|
||||
"movq %%mm7,0x30(%[y])\n\t"
|
||||
"movq 0x78(%[y]),%%mm7\n\t"
|
||||
"movq %%mm1,0x08(%[y])\n\t"
|
||||
"movq 0x50(%[y]),%%mm1\n\t"
|
||||
"movq %%mm6,0x20(%[y])\n\t"
|
||||
"movq 0x68(%[y]),%%mm6\n\t"
|
||||
"movq %%mm2,0x28(%[y])\n\t"
|
||||
"movq 0x60(%[y]),%%mm2\n\t"
|
||||
"movq %%mm5,0x10(%[y])\n\t"
|
||||
"movq 0x58(%[y]),%%mm5\n\t"
|
||||
"movq %%mm3,0x38(%[y])\n\t"
|
||||
"movq 0x70(%[y]),%%mm3\n\t"
|
||||
"movq %%mm4,0x00(%[y])\n\t"
|
||||
"movq 0x48(%[y]),%%mm4\n\t"
|
||||
OC_FDCT_STAGE1_8x4
|
||||
OC_FDCT8x4("0x40","0x50","0x60","0x70","0x48","0x58","0x68","0x78")
|
||||
OC_TRANSPOSE8x4("0x40","0x50","0x60","0x70","0x48","0x58","0x68","0x78")
|
||||
/*mm0={-2}x4*/
|
||||
"pcmpeqw %%mm0,%%mm0\n\t"
|
||||
"paddw %%mm0,%%mm0\n\t"
|
||||
/*Round the results.*/
|
||||
"psubw %%mm0,%%mm1\n\t"
|
||||
"psubw %%mm0,%%mm2\n\t"
|
||||
"psraw $2,%%mm1\n\t"
|
||||
"psubw %%mm0,%%mm3\n\t"
|
||||
"movq %%mm1,0x58(%[y])\n\t"
|
||||
"psraw $2,%%mm2\n\t"
|
||||
"psubw %%mm0,%%mm4\n\t"
|
||||
"movq 0x48(%[y]),%%mm1\n\t"
|
||||
"psraw $2,%%mm3\n\t"
|
||||
"psubw %%mm0,%%mm5\n\t"
|
||||
"movq %%mm2,0x68(%[y])\n\t"
|
||||
"psraw $2,%%mm4\n\t"
|
||||
"psubw %%mm0,%%mm6\n\t"
|
||||
"movq %%mm3,0x78(%[y])\n\t"
|
||||
"psraw $2,%%mm5\n\t"
|
||||
"psubw %%mm0,%%mm7\n\t"
|
||||
"movq %%mm4,0x40(%[y])\n\t"
|
||||
"psraw $2,%%mm6\n\t"
|
||||
"psubw %%mm0,%%mm1\n\t"
|
||||
"movq %%mm5,0x50(%[y])\n\t"
|
||||
"psraw $2,%%mm7\n\t"
|
||||
"movq %%mm6,0x60(%[y])\n\t"
|
||||
"psraw $2,%%mm1\n\t"
|
||||
"movq %%mm7,0x70(%[y])\n\t"
|
||||
"movq %%mm1,0x48(%[y])\n\t"
|
||||
:[a]"=&r"(a)
|
||||
:[y]"r"(_y),[x]"r"(_x)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,368 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
/*MMX acceleration of fragment reconstruction for motion compensation.
|
||||
Originally written by Rudolf Marek.
|
||||
Additional optimization by Nils Pipenbrinck.
|
||||
Note: Loops are unrolled for best performance.
|
||||
The iteration each instruction belongs to is marked in the comments as #i.*/
|
||||
#include <stddef.h>
|
||||
#include "x86int.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
/*Copies an 8x8 block of pixels from _src to _dst, assuming _ystride bytes
|
||||
between rows.*/
|
||||
# define OC_FRAG_COPY_MMX(_dst,_src,_ystride) \
|
||||
do{ \
|
||||
const unsigned char *src; \
|
||||
unsigned char *dst; \
|
||||
ptrdiff_t ystride3; \
|
||||
src=(_src); \
|
||||
dst=(_dst); \
|
||||
__asm__ __volatile__( \
|
||||
/*src+0*ystride*/ \
|
||||
"movq (%[src]),%%mm0\n\t" \
|
||||
/*src+1*ystride*/ \
|
||||
"movq (%[src],%[ystride]),%%mm1\n\t" \
|
||||
/*ystride3=ystride*3*/ \
|
||||
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t" \
|
||||
/*src+2*ystride*/ \
|
||||
"movq (%[src],%[ystride],2),%%mm2\n\t" \
|
||||
/*src+3*ystride*/ \
|
||||
"movq (%[src],%[ystride3]),%%mm3\n\t" \
|
||||
/*dst+0*ystride*/ \
|
||||
"movq %%mm0,(%[dst])\n\t" \
|
||||
/*dst+1*ystride*/ \
|
||||
"movq %%mm1,(%[dst],%[ystride])\n\t" \
|
||||
/*Pointer to next 4.*/ \
|
||||
"lea (%[src],%[ystride],4),%[src]\n\t" \
|
||||
/*dst+2*ystride*/ \
|
||||
"movq %%mm2,(%[dst],%[ystride],2)\n\t" \
|
||||
/*dst+3*ystride*/ \
|
||||
"movq %%mm3,(%[dst],%[ystride3])\n\t" \
|
||||
/*Pointer to next 4.*/ \
|
||||
"lea (%[dst],%[ystride],4),%[dst]\n\t" \
|
||||
/*src+0*ystride*/ \
|
||||
"movq (%[src]),%%mm0\n\t" \
|
||||
/*src+1*ystride*/ \
|
||||
"movq (%[src],%[ystride]),%%mm1\n\t" \
|
||||
/*src+2*ystride*/ \
|
||||
"movq (%[src],%[ystride],2),%%mm2\n\t" \
|
||||
/*src+3*ystride*/ \
|
||||
"movq (%[src],%[ystride3]),%%mm3\n\t" \
|
||||
/*dst+0*ystride*/ \
|
||||
"movq %%mm0,(%[dst])\n\t" \
|
||||
/*dst+1*ystride*/ \
|
||||
"movq %%mm1,(%[dst],%[ystride])\n\t" \
|
||||
/*dst+2*ystride*/ \
|
||||
"movq %%mm2,(%[dst],%[ystride],2)\n\t" \
|
||||
/*dst+3*ystride*/ \
|
||||
"movq %%mm3,(%[dst],%[ystride3])\n\t" \
|
||||
:[dst]"+r"(dst),[src]"+r"(src),[ystride3]"=&r"(ystride3) \
|
||||
:[ystride]"r"((ptrdiff_t)(_ystride)) \
|
||||
:"memory" \
|
||||
); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
/*Copies an 8x8 block of pixels from _src to _dst, assuming _ystride bytes
|
||||
between rows.*/
|
||||
void oc_frag_copy_mmx(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride){
|
||||
OC_FRAG_COPY_MMX(_dst,_src,_ystride);
|
||||
}
|
||||
|
||||
/*Copies the fragments specified by the lists of fragment indices from one
|
||||
frame to another.
|
||||
_dst_frame: The reference frame to copy to.
|
||||
_src_frame: The reference frame to copy from.
|
||||
_ystride: The row stride of the reference frames.
|
||||
_fragis: A pointer to a list of fragment indices.
|
||||
_nfragis: The number of fragment indices to copy.
|
||||
_frag_buf_offs: The offsets of fragments in the reference frames.*/
|
||||
void oc_frag_copy_list_mmx(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs){
|
||||
ptrdiff_t fragii;
|
||||
for(fragii=0;fragii<_nfragis;fragii++){
|
||||
ptrdiff_t frag_buf_off;
|
||||
frag_buf_off=_frag_buf_offs[_fragis[fragii]];
|
||||
OC_FRAG_COPY_MMX(_dst_frame+frag_buf_off,
|
||||
_src_frame+frag_buf_off,_ystride);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void oc_frag_recon_intra_mmx(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t *_residue){
|
||||
__asm__ __volatile__(
|
||||
/*Set mm0 to 0xFFFFFFFFFFFFFFFF.*/
|
||||
"pcmpeqw %%mm0,%%mm0\n\t"
|
||||
/*#0 Load low residue.*/
|
||||
"movq 0*8(%[residue]),%%mm1\n\t"
|
||||
/*#0 Load high residue.*/
|
||||
"movq 1*8(%[residue]),%%mm2\n\t"
|
||||
/*Set mm0 to 0x8000800080008000.*/
|
||||
"psllw $15,%%mm0\n\t"
|
||||
/*#1 Load low residue.*/
|
||||
"movq 2*8(%[residue]),%%mm3\n\t"
|
||||
/*#1 Load high residue.*/
|
||||
"movq 3*8(%[residue]),%%mm4\n\t"
|
||||
/*Set mm0 to 0x0080008000800080.*/
|
||||
"psrlw $8,%%mm0\n\t"
|
||||
/*#2 Load low residue.*/
|
||||
"movq 4*8(%[residue]),%%mm5\n\t"
|
||||
/*#2 Load high residue.*/
|
||||
"movq 5*8(%[residue]),%%mm6\n\t"
|
||||
/*#0 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm1\n\t"
|
||||
/*#0 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm2\n\t"
|
||||
/*#0 Pack to byte.*/
|
||||
"packuswb %%mm2,%%mm1\n\t"
|
||||
/*#1 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm3\n\t"
|
||||
/*#1 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm4\n\t"
|
||||
/*#1 Pack to byte.*/
|
||||
"packuswb %%mm4,%%mm3\n\t"
|
||||
/*#2 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm5\n\t"
|
||||
/*#2 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm6\n\t"
|
||||
/*#2 Pack to byte.*/
|
||||
"packuswb %%mm6,%%mm5\n\t"
|
||||
/*#0 Write row.*/
|
||||
"movq %%mm1,(%[dst])\n\t"
|
||||
/*#1 Write row.*/
|
||||
"movq %%mm3,(%[dst],%[ystride])\n\t"
|
||||
/*#2 Write row.*/
|
||||
"movq %%mm5,(%[dst],%[ystride],2)\n\t"
|
||||
/*#3 Load low residue.*/
|
||||
"movq 6*8(%[residue]),%%mm1\n\t"
|
||||
/*#3 Load high residue.*/
|
||||
"movq 7*8(%[residue]),%%mm2\n\t"
|
||||
/*#4 Load high residue.*/
|
||||
"movq 8*8(%[residue]),%%mm3\n\t"
|
||||
/*#4 Load high residue.*/
|
||||
"movq 9*8(%[residue]),%%mm4\n\t"
|
||||
/*#5 Load high residue.*/
|
||||
"movq 10*8(%[residue]),%%mm5\n\t"
|
||||
/*#5 Load high residue.*/
|
||||
"movq 11*8(%[residue]),%%mm6\n\t"
|
||||
/*#3 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm1\n\t"
|
||||
/*#3 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm2\n\t"
|
||||
/*#3 Pack to byte.*/
|
||||
"packuswb %%mm2,%%mm1\n\t"
|
||||
/*#4 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm3\n\t"
|
||||
/*#4 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm4\n\t"
|
||||
/*#4 Pack to byte.*/
|
||||
"packuswb %%mm4,%%mm3\n\t"
|
||||
/*#5 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm5\n\t"
|
||||
/*#5 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm6\n\t"
|
||||
/*#5 Pack to byte.*/
|
||||
"packuswb %%mm6,%%mm5\n\t"
|
||||
/*#3 Write row.*/
|
||||
"movq %%mm1,(%[dst],%[ystride3])\n\t"
|
||||
/*#4 Write row.*/
|
||||
"movq %%mm3,(%[dst4])\n\t"
|
||||
/*#5 Write row.*/
|
||||
"movq %%mm5,(%[dst4],%[ystride])\n\t"
|
||||
/*#6 Load low residue.*/
|
||||
"movq 12*8(%[residue]),%%mm1\n\t"
|
||||
/*#6 Load high residue.*/
|
||||
"movq 13*8(%[residue]),%%mm2\n\t"
|
||||
/*#7 Load low residue.*/
|
||||
"movq 14*8(%[residue]),%%mm3\n\t"
|
||||
/*#7 Load high residue.*/
|
||||
"movq 15*8(%[residue]),%%mm4\n\t"
|
||||
/*#6 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm1\n\t"
|
||||
/*#6 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm2\n\t"
|
||||
/*#6 Pack to byte.*/
|
||||
"packuswb %%mm2,%%mm1\n\t"
|
||||
/*#7 Bias low residue.*/
|
||||
"paddsw %%mm0,%%mm3\n\t"
|
||||
/*#7 Bias high residue.*/
|
||||
"paddsw %%mm0,%%mm4\n\t"
|
||||
/*#7 Pack to byte.*/
|
||||
"packuswb %%mm4,%%mm3\n\t"
|
||||
/*#6 Write row.*/
|
||||
"movq %%mm1,(%[dst4],%[ystride],2)\n\t"
|
||||
/*#7 Write row.*/
|
||||
"movq %%mm3,(%[dst4],%[ystride3])\n\t"
|
||||
:
|
||||
:[residue]"r"(_residue),
|
||||
[dst]"r"(_dst),
|
||||
[dst4]"r"(_dst+(_ystride<<2)),
|
||||
[ystride]"r"((ptrdiff_t)_ystride),
|
||||
[ystride3]"r"((ptrdiff_t)_ystride*3)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
|
||||
void oc_frag_recon_inter_mmx(unsigned char *_dst,const unsigned char *_src,
|
||||
int _ystride,const ogg_int16_t *_residue){
|
||||
int i;
|
||||
/*Zero mm0.*/
|
||||
__asm__ __volatile__("pxor %%mm0,%%mm0\n\t"::);
|
||||
for(i=4;i-->0;){
|
||||
__asm__ __volatile__(
|
||||
/*#0 Load source.*/
|
||||
"movq (%[src]),%%mm3\n\t"
|
||||
/*#1 Load source.*/
|
||||
"movq (%[src],%[ystride]),%%mm7\n\t"
|
||||
/*#0 Get copy of src.*/
|
||||
"movq %%mm3,%%mm4\n\t"
|
||||
/*#0 Expand high source.*/
|
||||
"punpckhbw %%mm0,%%mm4\n\t"
|
||||
/*#0 Expand low source.*/
|
||||
"punpcklbw %%mm0,%%mm3\n\t"
|
||||
/*#0 Add residue high.*/
|
||||
"paddsw 8(%[residue]),%%mm4\n\t"
|
||||
/*#1 Get copy of src.*/
|
||||
"movq %%mm7,%%mm2\n\t"
|
||||
/*#0 Add residue low.*/
|
||||
"paddsw (%[residue]), %%mm3\n\t"
|
||||
/*#1 Expand high source.*/
|
||||
"punpckhbw %%mm0,%%mm2\n\t"
|
||||
/*#0 Pack final row pixels.*/
|
||||
"packuswb %%mm4,%%mm3\n\t"
|
||||
/*#1 Expand low source.*/
|
||||
"punpcklbw %%mm0,%%mm7\n\t"
|
||||
/*#1 Add residue low.*/
|
||||
"paddsw 16(%[residue]),%%mm7\n\t"
|
||||
/*#1 Add residue high.*/
|
||||
"paddsw 24(%[residue]),%%mm2\n\t"
|
||||
/*Advance residue.*/
|
||||
"lea 32(%[residue]),%[residue]\n\t"
|
||||
/*#1 Pack final row pixels.*/
|
||||
"packuswb %%mm2,%%mm7\n\t"
|
||||
/*Advance src.*/
|
||||
"lea (%[src],%[ystride],2),%[src]\n\t"
|
||||
/*#0 Write row.*/
|
||||
"movq %%mm3,(%[dst])\n\t"
|
||||
/*#1 Write row.*/
|
||||
"movq %%mm7,(%[dst],%[ystride])\n\t"
|
||||
/*Advance dst.*/
|
||||
"lea (%[dst],%[ystride],2),%[dst]\n\t"
|
||||
:[residue]"+r"(_residue),[dst]"+r"(_dst),[src]"+r"(_src)
|
||||
:[ystride]"r"((ptrdiff_t)_ystride)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void oc_frag_recon_inter2_mmx(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue){
|
||||
int i;
|
||||
/*Zero mm7.*/
|
||||
__asm__ __volatile__("pxor %%mm7,%%mm7\n\t"::);
|
||||
for(i=4;i-->0;){
|
||||
__asm__ __volatile__(
|
||||
/*#0 Load src1.*/
|
||||
"movq (%[src1]),%%mm0\n\t"
|
||||
/*#0 Load src2.*/
|
||||
"movq (%[src2]),%%mm2\n\t"
|
||||
/*#0 Copy src1.*/
|
||||
"movq %%mm0,%%mm1\n\t"
|
||||
/*#0 Copy src2.*/
|
||||
"movq %%mm2,%%mm3\n\t"
|
||||
/*#1 Load src1.*/
|
||||
"movq (%[src1],%[ystride]),%%mm4\n\t"
|
||||
/*#0 Unpack lower src1.*/
|
||||
"punpcklbw %%mm7,%%mm0\n\t"
|
||||
/*#1 Load src2.*/
|
||||
"movq (%[src2],%[ystride]),%%mm5\n\t"
|
||||
/*#0 Unpack higher src1.*/
|
||||
"punpckhbw %%mm7,%%mm1\n\t"
|
||||
/*#0 Unpack lower src2.*/
|
||||
"punpcklbw %%mm7,%%mm2\n\t"
|
||||
/*#0 Unpack higher src2.*/
|
||||
"punpckhbw %%mm7,%%mm3\n\t"
|
||||
/*Advance src1 ptr.*/
|
||||
"lea (%[src1],%[ystride],2),%[src1]\n\t"
|
||||
/*Advance src2 ptr.*/
|
||||
"lea (%[src2],%[ystride],2),%[src2]\n\t"
|
||||
/*#0 Lower src1+src2.*/
|
||||
"paddsw %%mm2,%%mm0\n\t"
|
||||
/*#0 Higher src1+src2.*/
|
||||
"paddsw %%mm3,%%mm1\n\t"
|
||||
/*#1 Copy src1.*/
|
||||
"movq %%mm4,%%mm2\n\t"
|
||||
/*#0 Build lo average.*/
|
||||
"psraw $1,%%mm0\n\t"
|
||||
/*#1 Copy src2.*/
|
||||
"movq %%mm5,%%mm3\n\t"
|
||||
/*#1 Unpack lower src1.*/
|
||||
"punpcklbw %%mm7,%%mm4\n\t"
|
||||
/*#0 Build hi average.*/
|
||||
"psraw $1,%%mm1\n\t"
|
||||
/*#1 Unpack higher src1.*/
|
||||
"punpckhbw %%mm7,%%mm2\n\t"
|
||||
/*#0 low+=residue.*/
|
||||
"paddsw (%[residue]),%%mm0\n\t"
|
||||
/*#1 Unpack lower src2.*/
|
||||
"punpcklbw %%mm7,%%mm5\n\t"
|
||||
/*#0 high+=residue.*/
|
||||
"paddsw 8(%[residue]),%%mm1\n\t"
|
||||
/*#1 Unpack higher src2.*/
|
||||
"punpckhbw %%mm7,%%mm3\n\t"
|
||||
/*#1 Lower src1+src2.*/
|
||||
"paddsw %%mm4,%%mm5\n\t"
|
||||
/*#0 Pack and saturate.*/
|
||||
"packuswb %%mm1,%%mm0\n\t"
|
||||
/*#1 Higher src1+src2.*/
|
||||
"paddsw %%mm2,%%mm3\n\t"
|
||||
/*#0 Write row.*/
|
||||
"movq %%mm0,(%[dst])\n\t"
|
||||
/*#1 Build lo average.*/
|
||||
"psraw $1,%%mm5\n\t"
|
||||
/*#1 Build hi average.*/
|
||||
"psraw $1,%%mm3\n\t"
|
||||
/*#1 low+=residue.*/
|
||||
"paddsw 16(%[residue]),%%mm5\n\t"
|
||||
/*#1 high+=residue.*/
|
||||
"paddsw 24(%[residue]),%%mm3\n\t"
|
||||
/*#1 Pack and saturate.*/
|
||||
"packuswb %%mm3,%%mm5\n\t"
|
||||
/*#1 Write row ptr.*/
|
||||
"movq %%mm5,(%[dst],%[ystride])\n\t"
|
||||
/*Advance residue ptr.*/
|
||||
"add $32,%[residue]\n\t"
|
||||
/*Advance dest ptr.*/
|
||||
"lea (%[dst],%[ystride],2),%[dst]\n\t"
|
||||
:[dst]"+r"(_dst),[residue]"+r"(_residue),
|
||||
[src1]"+%r"(_src1),[src2]"+r"(_src2)
|
||||
:[ystride]"r"((ptrdiff_t)_ystride)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void oc_restore_fpu_mmx(void){
|
||||
__asm__ __volatile__("emms\n\t");
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,562 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
/*MMX acceleration of Theora's iDCT.
|
||||
Originally written by Rudolf Marek, based on code from On2's VP3.*/
|
||||
#include "x86int.h"
|
||||
#include "../dct.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
/*These are offsets into the table of constants below.*/
|
||||
/*7 rows of cosines, in order: pi/16 * (1 ... 7).*/
|
||||
#define OC_COSINE_OFFSET (0)
|
||||
/*A row of 8's.*/
|
||||
#define OC_EIGHT_OFFSET (56)
|
||||
|
||||
|
||||
|
||||
/*38 cycles*/
|
||||
#define OC_IDCT_BEGIN(_y,_x) \
|
||||
"#OC_IDCT_BEGIN\n\t" \
|
||||
"movq "OC_I(3,_x)",%%mm2\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x30,c)",%%mm6\n\t" \
|
||||
"movq %%mm2,%%mm4\n\t" \
|
||||
"movq "OC_J(5,_x)",%%mm7\n\t" \
|
||||
"pmulhw %%mm6,%%mm4\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x50,c)",%%mm1\n\t" \
|
||||
"pmulhw %%mm7,%%mm6\n\t" \
|
||||
"movq %%mm1,%%mm5\n\t" \
|
||||
"pmulhw %%mm2,%%mm1\n\t" \
|
||||
"movq "OC_I(1,_x)",%%mm3\n\t" \
|
||||
"pmulhw %%mm7,%%mm5\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x10,c)",%%mm0\n\t" \
|
||||
"paddw %%mm2,%%mm4\n\t" \
|
||||
"paddw %%mm7,%%mm6\n\t" \
|
||||
"paddw %%mm1,%%mm2\n\t" \
|
||||
"movq "OC_J(7,_x)",%%mm1\n\t" \
|
||||
"paddw %%mm5,%%mm7\n\t" \
|
||||
"movq %%mm0,%%mm5\n\t" \
|
||||
"pmulhw %%mm3,%%mm0\n\t" \
|
||||
"paddw %%mm7,%%mm4\n\t" \
|
||||
"pmulhw %%mm1,%%mm5\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x70,c)",%%mm7\n\t" \
|
||||
"psubw %%mm2,%%mm6\n\t" \
|
||||
"paddw %%mm3,%%mm0\n\t" \
|
||||
"pmulhw %%mm7,%%mm3\n\t" \
|
||||
"movq "OC_I(2,_x)",%%mm2\n\t" \
|
||||
"pmulhw %%mm1,%%mm7\n\t" \
|
||||
"paddw %%mm1,%%mm5\n\t" \
|
||||
"movq %%mm2,%%mm1\n\t" \
|
||||
"pmulhw "OC_MEM_OFFS(0x20,c)",%%mm2\n\t" \
|
||||
"psubw %%mm5,%%mm3\n\t" \
|
||||
"movq "OC_J(6,_x)",%%mm5\n\t" \
|
||||
"paddw %%mm7,%%mm0\n\t" \
|
||||
"movq %%mm5,%%mm7\n\t" \
|
||||
"psubw %%mm4,%%mm0\n\t" \
|
||||
"pmulhw "OC_MEM_OFFS(0x20,c)",%%mm5\n\t" \
|
||||
"paddw %%mm1,%%mm2\n\t" \
|
||||
"pmulhw "OC_MEM_OFFS(0x60,c)",%%mm1\n\t" \
|
||||
"paddw %%mm4,%%mm4\n\t" \
|
||||
"paddw %%mm0,%%mm4\n\t" \
|
||||
"psubw %%mm6,%%mm3\n\t" \
|
||||
"paddw %%mm7,%%mm5\n\t" \
|
||||
"paddw %%mm6,%%mm6\n\t" \
|
||||
"pmulhw "OC_MEM_OFFS(0x60,c)",%%mm7\n\t" \
|
||||
"paddw %%mm3,%%mm6\n\t" \
|
||||
"movq %%mm4,"OC_I(1,_y)"\n\t" \
|
||||
"psubw %%mm5,%%mm1\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x40,c)",%%mm4\n\t" \
|
||||
"movq %%mm3,%%mm5\n\t" \
|
||||
"pmulhw %%mm4,%%mm3\n\t" \
|
||||
"paddw %%mm2,%%mm7\n\t" \
|
||||
"movq %%mm6,"OC_I(2,_y)"\n\t" \
|
||||
"movq %%mm0,%%mm2\n\t" \
|
||||
"movq "OC_I(0,_x)",%%mm6\n\t" \
|
||||
"pmulhw %%mm4,%%mm0\n\t" \
|
||||
"paddw %%mm3,%%mm5\n\t" \
|
||||
"movq "OC_J(4,_x)",%%mm3\n\t" \
|
||||
"psubw %%mm1,%%mm5\n\t" \
|
||||
"paddw %%mm0,%%mm2\n\t" \
|
||||
"psubw %%mm3,%%mm6\n\t" \
|
||||
"movq %%mm6,%%mm0\n\t" \
|
||||
"pmulhw %%mm4,%%mm6\n\t" \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
"paddw %%mm0,%%mm3\n\t" \
|
||||
"paddw %%mm5,%%mm1\n\t" \
|
||||
"pmulhw %%mm3,%%mm4\n\t" \
|
||||
"paddw %%mm0,%%mm6\n\t" \
|
||||
"psubw %%mm2,%%mm6\n\t" \
|
||||
"paddw %%mm2,%%mm2\n\t" \
|
||||
"movq "OC_I(1,_y)",%%mm0\n\t" \
|
||||
"paddw %%mm6,%%mm2\n\t" \
|
||||
"paddw %%mm3,%%mm4\n\t" \
|
||||
"psubw %%mm1,%%mm2\n\t" \
|
||||
"#end OC_IDCT_BEGIN\n\t" \
|
||||
|
||||
/*38+8=46 cycles.*/
|
||||
#define OC_ROW_IDCT(_y,_x) \
|
||||
"#OC_ROW_IDCT\n" \
|
||||
OC_IDCT_BEGIN(_y,_x) \
|
||||
/*r3=D'*/ \
|
||||
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||
/*r4=E'=E-G*/ \
|
||||
"psubw %%mm7,%%mm4\n\t" \
|
||||
/*r1=H'+H'*/ \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
/*r7=G+G*/ \
|
||||
"paddw %%mm7,%%mm7\n\t" \
|
||||
/*r1=R1=A''+H'*/ \
|
||||
"paddw %%mm2,%%mm1\n\t" \
|
||||
/*r7=G'=E+G*/ \
|
||||
"paddw %%mm4,%%mm7\n\t" \
|
||||
/*r4=R4=E'-D'*/ \
|
||||
"psubw %%mm3,%%mm4\n\t" \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
/*r6=R6=F'-B''*/ \
|
||||
"psubw %%mm5,%%mm6\n\t" \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
/*r3=R3=E'+D'*/ \
|
||||
"paddw %%mm4,%%mm3\n\t" \
|
||||
/*r5=R5=F'+B''*/ \
|
||||
"paddw %%mm6,%%mm5\n\t" \
|
||||
/*r7=R7=G'-C'*/ \
|
||||
"psubw %%mm0,%%mm7\n\t" \
|
||||
"paddw %%mm0,%%mm0\n\t" \
|
||||
/*Save R1.*/ \
|
||||
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||
/*r0=R0=G.+C.*/ \
|
||||
"paddw %%mm7,%%mm0\n\t" \
|
||||
"#end OC_ROW_IDCT\n\t" \
|
||||
|
||||
/*The following macro does two 4x4 transposes in place.
|
||||
At entry, we assume:
|
||||
r0 = a3 a2 a1 a0
|
||||
I(1) = b3 b2 b1 b0
|
||||
r2 = c3 c2 c1 c0
|
||||
r3 = d3 d2 d1 d0
|
||||
|
||||
r4 = e3 e2 e1 e0
|
||||
r5 = f3 f2 f1 f0
|
||||
r6 = g3 g2 g1 g0
|
||||
r7 = h3 h2 h1 h0
|
||||
|
||||
At exit, we have:
|
||||
I(0) = d0 c0 b0 a0
|
||||
I(1) = d1 c1 b1 a1
|
||||
I(2) = d2 c2 b2 a2
|
||||
I(3) = d3 c3 b3 a3
|
||||
|
||||
J(4) = h0 g0 f0 e0
|
||||
J(5) = h1 g1 f1 e1
|
||||
J(6) = h2 g2 f2 e2
|
||||
J(7) = h3 g3 f3 e3
|
||||
|
||||
I(0) I(1) I(2) I(3) is the transpose of r0 I(1) r2 r3.
|
||||
J(4) J(5) J(6) J(7) is the transpose of r4 r5 r6 r7.
|
||||
|
||||
Since r1 is free at entry, we calculate the Js first.*/
|
||||
/*19 cycles.*/
|
||||
#define OC_TRANSPOSE(_y) \
|
||||
"#OC_TRANSPOSE\n\t" \
|
||||
"movq %%mm4,%%mm1\n\t" \
|
||||
"punpcklwd %%mm5,%%mm4\n\t" \
|
||||
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||
"punpckhwd %%mm5,%%mm1\n\t" \
|
||||
"movq %%mm6,%%mm0\n\t" \
|
||||
"punpcklwd %%mm7,%%mm6\n\t" \
|
||||
"movq %%mm4,%%mm5\n\t" \
|
||||
"punpckldq %%mm6,%%mm4\n\t" \
|
||||
"punpckhdq %%mm6,%%mm5\n\t" \
|
||||
"movq %%mm1,%%mm6\n\t" \
|
||||
"movq %%mm4,"OC_J(4,_y)"\n\t" \
|
||||
"punpckhwd %%mm7,%%mm0\n\t" \
|
||||
"movq %%mm5,"OC_J(5,_y)"\n\t" \
|
||||
"punpckhdq %%mm0,%%mm6\n\t" \
|
||||
"movq "OC_I(0,_y)",%%mm4\n\t" \
|
||||
"punpckldq %%mm0,%%mm1\n\t" \
|
||||
"movq "OC_I(1,_y)",%%mm5\n\t" \
|
||||
"movq %%mm4,%%mm0\n\t" \
|
||||
"movq %%mm6,"OC_J(7,_y)"\n\t" \
|
||||
"punpcklwd %%mm5,%%mm0\n\t" \
|
||||
"movq %%mm1,"OC_J(6,_y)"\n\t" \
|
||||
"punpckhwd %%mm5,%%mm4\n\t" \
|
||||
"movq %%mm2,%%mm5\n\t" \
|
||||
"punpcklwd %%mm3,%%mm2\n\t" \
|
||||
"movq %%mm0,%%mm1\n\t" \
|
||||
"punpckldq %%mm2,%%mm0\n\t" \
|
||||
"punpckhdq %%mm2,%%mm1\n\t" \
|
||||
"movq %%mm4,%%mm2\n\t" \
|
||||
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||
"punpckhwd %%mm3,%%mm5\n\t" \
|
||||
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||
"punpckhdq %%mm5,%%mm4\n\t" \
|
||||
"punpckldq %%mm5,%%mm2\n\t" \
|
||||
"movq %%mm4,"OC_I(3,_y)"\n\t" \
|
||||
"movq %%mm2,"OC_I(2,_y)"\n\t" \
|
||||
"#end OC_TRANSPOSE\n\t" \
|
||||
|
||||
/*38+19=57 cycles.*/
|
||||
#define OC_COLUMN_IDCT(_y) \
|
||||
"#OC_COLUMN_IDCT\n" \
|
||||
OC_IDCT_BEGIN(_y,_y) \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm2\n\t" \
|
||||
/*r1=H'+H'*/ \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
/*r1=R1=A''+H'*/ \
|
||||
"paddw %%mm2,%%mm1\n\t" \
|
||||
/*r2=NR2*/ \
|
||||
"psraw $4,%%mm2\n\t" \
|
||||
/*r4=E'=E-G*/ \
|
||||
"psubw %%mm7,%%mm4\n\t" \
|
||||
/*r1=NR1*/ \
|
||||
"psraw $4,%%mm1\n\t" \
|
||||
/*r3=D'*/ \
|
||||
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||
/*r7=G+G*/ \
|
||||
"paddw %%mm7,%%mm7\n\t" \
|
||||
/*Store NR2 at I(2).*/ \
|
||||
"movq %%mm2,"OC_I(2,_y)"\n\t" \
|
||||
/*r7=G'=E+G*/ \
|
||||
"paddw %%mm4,%%mm7\n\t" \
|
||||
/*Store NR1 at I(1).*/ \
|
||||
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||
/*r4=R4=E'-D'*/ \
|
||||
"psubw %%mm3,%%mm4\n\t" \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm4\n\t" \
|
||||
/*r3=D'+D'*/ \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
/*r3=R3=E'+D'*/ \
|
||||
"paddw %%mm4,%%mm3\n\t" \
|
||||
/*r4=NR4*/ \
|
||||
"psraw $4,%%mm4\n\t" \
|
||||
/*r6=R6=F'-B''*/ \
|
||||
"psubw %%mm5,%%mm6\n\t" \
|
||||
/*r3=NR3*/ \
|
||||
"psraw $4,%%mm3\n\t" \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm6\n\t" \
|
||||
/*r5=B''+B''*/ \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
/*r5=R5=F'+B''*/ \
|
||||
"paddw %%mm6,%%mm5\n\t" \
|
||||
/*r6=NR6*/ \
|
||||
"psraw $4,%%mm6\n\t" \
|
||||
/*Store NR4 at J(4).*/ \
|
||||
"movq %%mm4,"OC_J(4,_y)"\n\t" \
|
||||
/*r5=NR5*/ \
|
||||
"psraw $4,%%mm5\n\t" \
|
||||
/*Store NR3 at I(3).*/ \
|
||||
"movq %%mm3,"OC_I(3,_y)"\n\t" \
|
||||
/*r7=R7=G'-C'*/ \
|
||||
"psubw %%mm0,%%mm7\n\t" \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm7\n\t" \
|
||||
/*r0=C'+C'*/ \
|
||||
"paddw %%mm0,%%mm0\n\t" \
|
||||
/*r0=R0=G'+C'*/ \
|
||||
"paddw %%mm7,%%mm0\n\t" \
|
||||
/*r7=NR7*/ \
|
||||
"psraw $4,%%mm7\n\t" \
|
||||
/*Store NR6 at J(6).*/ \
|
||||
"movq %%mm6,"OC_J(6,_y)"\n\t" \
|
||||
/*r0=NR0*/ \
|
||||
"psraw $4,%%mm0\n\t" \
|
||||
/*Store NR5 at J(5).*/ \
|
||||
"movq %%mm5,"OC_J(5,_y)"\n\t" \
|
||||
/*Store NR7 at J(7).*/ \
|
||||
"movq %%mm7,"OC_J(7,_y)"\n\t" \
|
||||
/*Store NR0 at I(0).*/ \
|
||||
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||
"#end OC_COLUMN_IDCT\n\t" \
|
||||
|
||||
static void oc_idct8x8_slow_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||
/*This routine accepts an 8x8 matrix, but in partially transposed form.
|
||||
Every 4x4 block is transposed.*/
|
||||
__asm__ __volatile__(
|
||||
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||
#define OC_J(_k,_y) OC_MEM_OFFS(((_k)-4)*16+8,_y)
|
||||
OC_ROW_IDCT(y,x)
|
||||
OC_TRANSPOSE(y)
|
||||
#undef OC_I
|
||||
#undef OC_J
|
||||
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16+64,_y)
|
||||
#define OC_J(_k,_y) OC_MEM_OFFS(((_k)-4)*16+72,_y)
|
||||
OC_ROW_IDCT(y,x)
|
||||
OC_TRANSPOSE(y)
|
||||
#undef OC_I
|
||||
#undef OC_J
|
||||
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||
OC_COLUMN_IDCT(y)
|
||||
#undef OC_I
|
||||
#undef OC_J
|
||||
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16+8,_y)
|
||||
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||
OC_COLUMN_IDCT(y)
|
||||
#undef OC_I
|
||||
#undef OC_J
|
||||
:[y]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_y,64)
|
||||
:[x]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64),
|
||||
[c]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128)
|
||||
);
|
||||
if(_x!=_y){
|
||||
int i;
|
||||
__asm__ __volatile__("pxor %%mm0,%%mm0\n\t"::);
|
||||
for(i=0;i<4;i++){
|
||||
__asm__ __volatile__(
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x08,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x18,x)"\n\t"
|
||||
:[x]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_x+16*i,16)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*25 cycles.*/
|
||||
#define OC_IDCT_BEGIN_10(_y,_x) \
|
||||
"#OC_IDCT_BEGIN_10\n\t" \
|
||||
"movq "OC_I(3,_x)",%%mm2\n\t" \
|
||||
"nop\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x30,c)",%%mm6\n\t" \
|
||||
"movq %%mm2,%%mm4\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x50,c)",%%mm1\n\t" \
|
||||
"pmulhw %%mm6,%%mm4\n\t" \
|
||||
"movq "OC_I(1,_x)",%%mm3\n\t" \
|
||||
"pmulhw %%mm2,%%mm1\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x10,c)",%%mm0\n\t" \
|
||||
"paddw %%mm2,%%mm4\n\t" \
|
||||
"pxor %%mm6,%%mm6\n\t" \
|
||||
"paddw %%mm1,%%mm2\n\t" \
|
||||
"movq "OC_I(2,_x)",%%mm5\n\t" \
|
||||
"pmulhw %%mm3,%%mm0\n\t" \
|
||||
"movq %%mm5,%%mm1\n\t" \
|
||||
"paddw %%mm3,%%mm0\n\t" \
|
||||
"pmulhw "OC_MEM_OFFS(0x70,c)",%%mm3\n\t" \
|
||||
"psubw %%mm2,%%mm6\n\t" \
|
||||
"pmulhw "OC_MEM_OFFS(0x20,c)",%%mm5\n\t" \
|
||||
"psubw %%mm4,%%mm0\n\t" \
|
||||
"movq "OC_I(2,_x)",%%mm7\n\t" \
|
||||
"paddw %%mm4,%%mm4\n\t" \
|
||||
"paddw %%mm5,%%mm7\n\t" \
|
||||
"paddw %%mm0,%%mm4\n\t" \
|
||||
"pmulhw "OC_MEM_OFFS(0x60,c)",%%mm1\n\t" \
|
||||
"psubw %%mm6,%%mm3\n\t" \
|
||||
"movq %%mm4,"OC_I(1,_y)"\n\t" \
|
||||
"paddw %%mm6,%%mm6\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x40,c)",%%mm4\n\t" \
|
||||
"paddw %%mm3,%%mm6\n\t" \
|
||||
"movq %%mm3,%%mm5\n\t" \
|
||||
"pmulhw %%mm4,%%mm3\n\t" \
|
||||
"movq %%mm6,"OC_I(2,_y)"\n\t" \
|
||||
"movq %%mm0,%%mm2\n\t" \
|
||||
"movq "OC_I(0,_x)",%%mm6\n\t" \
|
||||
"pmulhw %%mm4,%%mm0\n\t" \
|
||||
"paddw %%mm3,%%mm5\n\t" \
|
||||
"paddw %%mm0,%%mm2\n\t" \
|
||||
"psubw %%mm1,%%mm5\n\t" \
|
||||
"pmulhw %%mm4,%%mm6\n\t" \
|
||||
"paddw "OC_I(0,_x)",%%mm6\n\t" \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
"movq %%mm6,%%mm4\n\t" \
|
||||
"paddw %%mm5,%%mm1\n\t" \
|
||||
"psubw %%mm2,%%mm6\n\t" \
|
||||
"paddw %%mm2,%%mm2\n\t" \
|
||||
"movq "OC_I(1,_y)",%%mm0\n\t" \
|
||||
"paddw %%mm6,%%mm2\n\t" \
|
||||
"psubw %%mm1,%%mm2\n\t" \
|
||||
"nop\n\t" \
|
||||
"#end OC_IDCT_BEGIN_10\n\t" \
|
||||
|
||||
/*25+8=33 cycles.*/
|
||||
#define OC_ROW_IDCT_10(_y,_x) \
|
||||
"#OC_ROW_IDCT_10\n\t" \
|
||||
OC_IDCT_BEGIN_10(_y,_x) \
|
||||
/*r3=D'*/ \
|
||||
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||
/*r4=E'=E-G*/ \
|
||||
"psubw %%mm7,%%mm4\n\t" \
|
||||
/*r1=H'+H'*/ \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
/*r7=G+G*/ \
|
||||
"paddw %%mm7,%%mm7\n\t" \
|
||||
/*r1=R1=A''+H'*/ \
|
||||
"paddw %%mm2,%%mm1\n\t" \
|
||||
/*r7=G'=E+G*/ \
|
||||
"paddw %%mm4,%%mm7\n\t" \
|
||||
/*r4=R4=E'-D'*/ \
|
||||
"psubw %%mm3,%%mm4\n\t" \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
/*r6=R6=F'-B''*/ \
|
||||
"psubw %%mm5,%%mm6\n\t" \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
/*r3=R3=E'+D'*/ \
|
||||
"paddw %%mm4,%%mm3\n\t" \
|
||||
/*r5=R5=F'+B''*/ \
|
||||
"paddw %%mm6,%%mm5\n\t" \
|
||||
/*r7=R7=G'-C'*/ \
|
||||
"psubw %%mm0,%%mm7\n\t" \
|
||||
"paddw %%mm0,%%mm0\n\t" \
|
||||
/*Save R1.*/ \
|
||||
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||
/*r0=R0=G'+C'*/ \
|
||||
"paddw %%mm7,%%mm0\n\t" \
|
||||
"#end OC_ROW_IDCT_10\n\t" \
|
||||
|
||||
/*25+19=44 cycles'*/
|
||||
#define OC_COLUMN_IDCT_10(_y) \
|
||||
"#OC_COLUMN_IDCT_10\n\t" \
|
||||
OC_IDCT_BEGIN_10(_y,_y) \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm2\n\t" \
|
||||
/*r1=H'+H'*/ \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
/*r1=R1=A''+H'*/ \
|
||||
"paddw %%mm2,%%mm1\n\t" \
|
||||
/*r2=NR2*/ \
|
||||
"psraw $4,%%mm2\n\t" \
|
||||
/*r4=E'=E-G*/ \
|
||||
"psubw %%mm7,%%mm4\n\t" \
|
||||
/*r1=NR1*/ \
|
||||
"psraw $4,%%mm1\n\t" \
|
||||
/*r3=D'*/ \
|
||||
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||
/*r7=G+G*/ \
|
||||
"paddw %%mm7,%%mm7\n\t" \
|
||||
/*Store NR2 at I(2).*/ \
|
||||
"movq %%mm2,"OC_I(2,_y)"\n\t" \
|
||||
/*r7=G'=E+G*/ \
|
||||
"paddw %%mm4,%%mm7\n\t" \
|
||||
/*Store NR1 at I(1).*/ \
|
||||
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||
/*r4=R4=E'-D'*/ \
|
||||
"psubw %%mm3,%%mm4\n\t" \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm4\n\t" \
|
||||
/*r3=D'+D'*/ \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
/*r3=R3=E'+D'*/ \
|
||||
"paddw %%mm4,%%mm3\n\t" \
|
||||
/*r4=NR4*/ \
|
||||
"psraw $4,%%mm4\n\t" \
|
||||
/*r6=R6=F'-B''*/ \
|
||||
"psubw %%mm5,%%mm6\n\t" \
|
||||
/*r3=NR3*/ \
|
||||
"psraw $4,%%mm3\n\t" \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm6\n\t" \
|
||||
/*r5=B''+B''*/ \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
/*r5=R5=F'+B''*/ \
|
||||
"paddw %%mm6,%%mm5\n\t" \
|
||||
/*r6=NR6*/ \
|
||||
"psraw $4,%%mm6\n\t" \
|
||||
/*Store NR4 at J(4).*/ \
|
||||
"movq %%mm4,"OC_J(4,_y)"\n\t" \
|
||||
/*r5=NR5*/ \
|
||||
"psraw $4,%%mm5\n\t" \
|
||||
/*Store NR3 at I(3).*/ \
|
||||
"movq %%mm3,"OC_I(3,_y)"\n\t" \
|
||||
/*r7=R7=G'-C'*/ \
|
||||
"psubw %%mm0,%%mm7\n\t" \
|
||||
"paddw "OC_MEM_OFFS(0x00,c)",%%mm7\n\t" \
|
||||
/*r0=C'+C'*/ \
|
||||
"paddw %%mm0,%%mm0\n\t" \
|
||||
/*r0=R0=G'+C'*/ \
|
||||
"paddw %%mm7,%%mm0\n\t" \
|
||||
/*r7=NR7*/ \
|
||||
"psraw $4,%%mm7\n\t" \
|
||||
/*Store NR6 at J(6).*/ \
|
||||
"movq %%mm6,"OC_J(6,_y)"\n\t" \
|
||||
/*r0=NR0*/ \
|
||||
"psraw $4,%%mm0\n\t" \
|
||||
/*Store NR5 at J(5).*/ \
|
||||
"movq %%mm5,"OC_J(5,_y)"\n\t" \
|
||||
/*Store NR7 at J(7).*/ \
|
||||
"movq %%mm7,"OC_J(7,_y)"\n\t" \
|
||||
/*Store NR0 at I(0).*/ \
|
||||
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||
"#end OC_COLUMN_IDCT_10\n\t" \
|
||||
|
||||
static void oc_idct8x8_10_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||
__asm__ __volatile__(
|
||||
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||
#define OC_J(_k,_y) OC_MEM_OFFS(((_k)-4)*16+8,_y)
|
||||
/*Done with dequant, descramble, and partial transpose.
|
||||
Now do the iDCT itself.*/
|
||||
OC_ROW_IDCT_10(y,x)
|
||||
OC_TRANSPOSE(y)
|
||||
#undef OC_I
|
||||
#undef OC_J
|
||||
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||
OC_COLUMN_IDCT_10(y)
|
||||
#undef OC_I
|
||||
#undef OC_J
|
||||
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16+8,_y)
|
||||
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||
OC_COLUMN_IDCT_10(y)
|
||||
#undef OC_I
|
||||
#undef OC_J
|
||||
:[y]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_y,64)
|
||||
:[x]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64),
|
||||
[c]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128)
|
||||
);
|
||||
if(_x!=_y){
|
||||
__asm__ __volatile__(
|
||||
"pxor %%mm0,%%mm0\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x20,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x30,x)"\n\t"
|
||||
:[x]"+m"OC_ARRAY_OPERAND(ogg_int16_t,_x,28)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||
version of the transform.*/
|
||||
void oc_idct8x8_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi){
|
||||
/*_last_zzi is subtly different from an actual count of the number of
|
||||
coefficients we decoded for this block.
|
||||
It contains the value of zzi BEFORE the final token in the block was
|
||||
decoded.
|
||||
In most cases this is an EOB token (the continuation of an EOB run from a
|
||||
previous block counts), and so this is the same as the coefficient count.
|
||||
However, in the case that the last token was NOT an EOB token, but filled
|
||||
the block up with exactly 64 coefficients, _last_zzi will be less than 64.
|
||||
Provided the last token was not a pure zero run, the minimum value it can
|
||||
be is 46, and so that doesn't affect any of the cases in this routine.
|
||||
However, if the last token WAS a pure zero run of length 63, then _last_zzi
|
||||
will be 1 while the number of coefficients decoded is 64.
|
||||
Thus, we will trigger the following special case, where the real
|
||||
coefficient count would not.
|
||||
Note also that a zero run of length 64 will give _last_zzi a value of 0,
|
||||
but we still process the DC coefficient, which might have a non-zero value
|
||||
due to DC prediction.
|
||||
Although convoluted, this is arguably the correct behavior: it allows us to
|
||||
use a smaller transform when the block ends with a long zero run instead
|
||||
of a normal EOB token.
|
||||
It could be smarter... multiple separate zero runs at the end of a block
|
||||
will fool it, but an encoder that generates these really deserves what it
|
||||
gets.
|
||||
Needless to say we inherited this approach from VP3.*/
|
||||
/*Then perform the iDCT.*/
|
||||
if(_last_zzi<=10)oc_idct8x8_10_mmx(_y,_x);
|
||||
else oc_idct8x8_slow_mmx(_y,_x);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
#if !defined(_x86_mmxloop_H)
|
||||
# define _x86_mmxloop_H (1)
|
||||
# include <stddef.h>
|
||||
# include "x86int.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
/*On entry, mm0={a0,...,a7}, mm1={b0,...,b7}, mm2={c0,...,c7}, mm3={d0,...d7}.
|
||||
On exit, mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)} and
|
||||
mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}; mm0 and mm3 are clobbered.*/
|
||||
#define OC_LOOP_FILTER8_MMX \
|
||||
"#OC_LOOP_FILTER8_MMX\n\t" \
|
||||
/*mm7=0*/ \
|
||||
"pxor %%mm7,%%mm7\n\t" \
|
||||
/*mm6:mm0={a0,...,a7}*/ \
|
||||
"movq %%mm0,%%mm6\n\t" \
|
||||
"punpcklbw %%mm7,%%mm0\n\t" \
|
||||
"punpckhbw %%mm7,%%mm6\n\t" \
|
||||
/*mm3:mm5={d0,...,d7}*/ \
|
||||
"movq %%mm3,%%mm5\n\t" \
|
||||
"punpcklbw %%mm7,%%mm3\n\t" \
|
||||
"punpckhbw %%mm7,%%mm5\n\t" \
|
||||
/*mm6:mm0={a0-d0,...,a7-d7}*/ \
|
||||
"psubw %%mm3,%%mm0\n\t" \
|
||||
"psubw %%mm5,%%mm6\n\t" \
|
||||
/*mm3:mm1={b0,...,b7}*/ \
|
||||
"movq %%mm1,%%mm3\n\t" \
|
||||
"punpcklbw %%mm7,%%mm1\n\t" \
|
||||
"movq %%mm2,%%mm4\n\t" \
|
||||
"punpckhbw %%mm7,%%mm3\n\t" \
|
||||
/*mm5:mm4={c0,...,c7}*/ \
|
||||
"movq %%mm2,%%mm5\n\t" \
|
||||
"punpcklbw %%mm7,%%mm4\n\t" \
|
||||
"punpckhbw %%mm7,%%mm5\n\t" \
|
||||
/*mm7={3}x4 \
|
||||
mm5:mm4={c0-b0,...,c7-b7}*/ \
|
||||
"pcmpeqw %%mm7,%%mm7\n\t" \
|
||||
"psubw %%mm1,%%mm4\n\t" \
|
||||
"psrlw $14,%%mm7\n\t" \
|
||||
"psubw %%mm3,%%mm5\n\t" \
|
||||
/*Scale by 3.*/ \
|
||||
"pmullw %%mm7,%%mm4\n\t" \
|
||||
"pmullw %%mm7,%%mm5\n\t" \
|
||||
/*mm7={4}x4 \
|
||||
mm5:mm4=f={a0-d0+3*(c0-b0),...,a7-d7+3*(c7-b7)}*/ \
|
||||
"psrlw $1,%%mm7\n\t" \
|
||||
"paddw %%mm0,%%mm4\n\t" \
|
||||
"psllw $2,%%mm7\n\t" \
|
||||
"movq (%[ll]),%%mm0\n\t" \
|
||||
"paddw %%mm6,%%mm5\n\t" \
|
||||
/*R_i has the range [-127,128], so we compute -R_i instead. \
|
||||
mm4=-R_i=-(f+4>>3)=0xFF^(f-4>>3)*/ \
|
||||
"psubw %%mm7,%%mm4\n\t" \
|
||||
"psubw %%mm7,%%mm5\n\t" \
|
||||
"psraw $3,%%mm4\n\t" \
|
||||
"psraw $3,%%mm5\n\t" \
|
||||
"pcmpeqb %%mm7,%%mm7\n\t" \
|
||||
"packsswb %%mm5,%%mm4\n\t" \
|
||||
"pxor %%mm6,%%mm6\n\t" \
|
||||
"pxor %%mm7,%%mm4\n\t" \
|
||||
"packuswb %%mm3,%%mm1\n\t" \
|
||||
/*Now compute lflim of -mm4 cf. Section 7.10 of the sepc.*/ \
|
||||
/*There's no unsigned byte+signed byte with unsigned saturation op code, so \
|
||||
we have to split things by sign (the other option is to work in 16 bits, \
|
||||
but working in 8 bits gives much better parallelism). \
|
||||
We compute abs(R_i), but save a mask of which terms were negative in mm6. \
|
||||
Then we compute mm4=abs(lflim(R_i,L))=min(abs(R_i),max(2*L-abs(R_i),0)). \
|
||||
Finally, we split mm4 into positive and negative pieces using the mask in \
|
||||
mm6, and add and subtract them as appropriate.*/ \
|
||||
/*mm4=abs(-R_i)*/ \
|
||||
/*mm7=255-2*L*/ \
|
||||
"pcmpgtb %%mm4,%%mm6\n\t" \
|
||||
"psubb %%mm0,%%mm7\n\t" \
|
||||
"pxor %%mm6,%%mm4\n\t" \
|
||||
"psubb %%mm0,%%mm7\n\t" \
|
||||
"psubb %%mm6,%%mm4\n\t" \
|
||||
/*mm7=255-max(2*L-abs(R_i),0)*/ \
|
||||
"paddusb %%mm4,%%mm7\n\t" \
|
||||
/*mm4=min(abs(R_i),max(2*L-abs(R_i),0))*/ \
|
||||
"paddusb %%mm7,%%mm4\n\t" \
|
||||
"psubusb %%mm7,%%mm4\n\t" \
|
||||
/*Now split mm4 by the original sign of -R_i.*/ \
|
||||
"movq %%mm4,%%mm5\n\t" \
|
||||
"pand %%mm6,%%mm4\n\t" \
|
||||
"pandn %%mm5,%%mm6\n\t" \
|
||||
/*mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)}*/ \
|
||||
/*mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}*/ \
|
||||
"paddusb %%mm4,%%mm1\n\t" \
|
||||
"psubusb %%mm4,%%mm2\n\t" \
|
||||
"psubusb %%mm6,%%mm1\n\t" \
|
||||
"paddusb %%mm6,%%mm2\n\t" \
|
||||
|
||||
/*On entry, mm0={a0,...,a7}, mm1={b0,...,b7}, mm2={c0,...,c7}, mm3={d0,...d7}.
|
||||
On exit, mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)} and
|
||||
mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}.
|
||||
All other MMX registers are clobbered.*/
|
||||
#define OC_LOOP_FILTER8_MMXEXT \
|
||||
"#OC_LOOP_FILTER8_MMXEXT\n\t" \
|
||||
/*R_i=(a_i-3*b_i+3*c_i-d_i+4>>3) has the range [-127,128], so we compute \
|
||||
-R_i=(-a_i+3*b_i-3*c_i+d_i+3>>3) instead.*/ \
|
||||
/*This first part is based on the transformation \
|
||||
f = -(3*(c-b)+a-d+4>>3) \
|
||||
= -(3*(c+255-b)+(a+255-d)+4-1020>>3) \
|
||||
= -(3*(c+~b)+(a+~d)-1016>>3) \
|
||||
= 127-(3*(c+~b)+(a+~d)>>3) \
|
||||
= 128+~(3*(c+~b)+(a+~d)>>3) (mod 256). \
|
||||
Although pavgb(a,b) = (a+b+1>>1) (biased up), we rely heavily on the \
|
||||
fact that ~pavgb(~a,~b) = (a+b>>1) (biased down). \
|
||||
Using this, the last expression above can be computed in 8 bits of working \
|
||||
precision via: \
|
||||
u = ~pavgb(~b,c); \
|
||||
v = pavgb(b,~c); \
|
||||
This mask is 0 or 0xFF, and controls whether t is biased up or down: \
|
||||
m = u-v; \
|
||||
t = m^pavgb(m^~a,m^d); \
|
||||
f = 128+pavgb(pavgb(t,u),v); \
|
||||
This required some careful analysis to ensure that carries are propagated \
|
||||
correctly in all cases, but has been checked exhaustively.*/ \
|
||||
/*input (a, b, c, d, ., ., ., .)*/ \
|
||||
/*ff=0xFF; \
|
||||
u=b; \
|
||||
v=c; \
|
||||
ll=255-2*L;*/ \
|
||||
"pcmpeqb %%mm7,%%mm7\n\t" \
|
||||
"movq %%mm1,%%mm4\n\t" \
|
||||
"movq %%mm2,%%mm5\n\t" \
|
||||
"movq (%[ll]),%%mm6\n\t" \
|
||||
/*allocated u, v, ll, ff: (a, b, c, d, u, v, ll, ff)*/ \
|
||||
/*u^=ff; \
|
||||
v^=ff;*/ \
|
||||
"pxor %%mm7,%%mm4\n\t" \
|
||||
"pxor %%mm7,%%mm5\n\t" \
|
||||
/*allocated ll: (a, b, c, d, u, v, ll, ff)*/ \
|
||||
/*u=pavgb(u,c); \
|
||||
v=pavgb(v,b);*/ \
|
||||
"pavgb %%mm2,%%mm4\n\t" \
|
||||
"pavgb %%mm1,%%mm5\n\t" \
|
||||
/*u^=ff; \
|
||||
a^=ff;*/ \
|
||||
"pxor %%mm7,%%mm4\n\t" \
|
||||
"pxor %%mm7,%%mm0\n\t" \
|
||||
/*m=u-v;*/ \
|
||||
"psubb %%mm5,%%mm4\n\t" \
|
||||
/*freed u, allocated m: (a, b, c, d, m, v, ll, ff)*/ \
|
||||
/*a^=m; \
|
||||
d^=m;*/ \
|
||||
"pxor %%mm4,%%mm0\n\t" \
|
||||
"pxor %%mm4,%%mm3\n\t" \
|
||||
/*t=pavgb(a,d);*/ \
|
||||
"pavgb %%mm3,%%mm0\n\t" \
|
||||
"psllw $7,%%mm7\n\t" \
|
||||
/*freed a, d, ff, allocated t, of: (t, b, c, ., m, v, ll, of)*/ \
|
||||
/*t^=m; \
|
||||
u=m+v;*/ \
|
||||
"pxor %%mm4,%%mm0\n\t" \
|
||||
"paddb %%mm5,%%mm4\n\t" \
|
||||
/*freed t, m, allocated f, u: (f, b, c, ., u, v, ll, of)*/ \
|
||||
/*f=pavgb(f,u); \
|
||||
of=128;*/ \
|
||||
"pavgb %%mm4,%%mm0\n\t" \
|
||||
"packsswb %%mm7,%%mm7\n\t" \
|
||||
/*freed u, ff, allocated ll: (f, b, c, ., ll, v, ll, of)*/ \
|
||||
/*f=pavgb(f,v);*/ \
|
||||
"pavgb %%mm5,%%mm0\n\t" \
|
||||
"movq %%mm7,%%mm3\n\t" \
|
||||
"movq %%mm6,%%mm4\n\t" \
|
||||
/*freed v, allocated of: (f, b, c, of, ll, ., ll, of)*/ \
|
||||
/*Now compute lflim of R_i=-(128+mm0) cf. Section 7.10 of the sepc.*/ \
|
||||
/*There's no unsigned byte+signed byte with unsigned saturation op code, so \
|
||||
we have to split things by sign (the other option is to work in 16 bits, \
|
||||
but staying in 8 bits gives much better parallelism).*/ \
|
||||
/*Instead of adding the offset of 128 in mm3, we use it to split mm0. \
|
||||
This is the same number of instructions as computing a mask and splitting \
|
||||
after the lflim computation, but has shorter dependency chains.*/ \
|
||||
/*mm0=R_i<0?-R_i:0 (denoted abs(R_i<0))\
|
||||
mm3=R_i>0?R_i:0* (denoted abs(R_i>0))*/ \
|
||||
"psubusb %%mm0,%%mm3\n\t" \
|
||||
"psubusb %%mm7,%%mm0\n\t" \
|
||||
/*mm6=255-max(2*L-abs(R_i<0),0) \
|
||||
mm4=255-max(2*L-abs(R_i>0),0)*/ \
|
||||
"paddusb %%mm3,%%mm4\n\t" \
|
||||
"paddusb %%mm0,%%mm6\n\t" \
|
||||
/*mm0=min(abs(R_i<0),max(2*L-abs(R_i<0),0)) \
|
||||
mm3=min(abs(R_i>0),max(2*L-abs(R_i>0),0))*/ \
|
||||
"paddusb %%mm4,%%mm3\n\t" \
|
||||
"paddusb %%mm6,%%mm0\n\t" \
|
||||
"psubusb %%mm4,%%mm3\n\t" \
|
||||
"psubusb %%mm6,%%mm0\n\t" \
|
||||
/*mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)}*/ \
|
||||
/*mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}*/ \
|
||||
"paddusb %%mm3,%%mm1\n\t" \
|
||||
"psubusb %%mm3,%%mm2\n\t" \
|
||||
"psubusb %%mm0,%%mm1\n\t" \
|
||||
"paddusb %%mm0,%%mm2\n\t" \
|
||||
|
||||
#define OC_LOOP_FILTER_V(_filter,_pix,_ystride,_ll) \
|
||||
do{ \
|
||||
ptrdiff_t ystride3__; \
|
||||
__asm__ __volatile__( \
|
||||
/*mm0={a0,...,a7}*/ \
|
||||
"movq (%[pix]),%%mm0\n\t" \
|
||||
/*ystride3=_ystride*3*/ \
|
||||
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t" \
|
||||
/*mm3={d0,...,d7}*/ \
|
||||
"movq (%[pix],%[ystride3]),%%mm3\n\t" \
|
||||
/*mm1={b0,...,b7}*/ \
|
||||
"movq (%[pix],%[ystride]),%%mm1\n\t" \
|
||||
/*mm2={c0,...,c7}*/ \
|
||||
"movq (%[pix],%[ystride],2),%%mm2\n\t" \
|
||||
_filter \
|
||||
/*Write it back out.*/ \
|
||||
"movq %%mm1,(%[pix],%[ystride])\n\t" \
|
||||
"movq %%mm2,(%[pix],%[ystride],2)\n\t" \
|
||||
:[ystride3]"=&r"(ystride3__) \
|
||||
:[pix]"r"(_pix-_ystride*2),[ystride]"r"((ptrdiff_t)(_ystride)), \
|
||||
[ll]"r"(_ll) \
|
||||
:"memory" \
|
||||
); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#define OC_LOOP_FILTER_H(_filter,_pix,_ystride,_ll) \
|
||||
do{ \
|
||||
unsigned char *pix__; \
|
||||
ptrdiff_t ystride3__; \
|
||||
ptrdiff_t d__; \
|
||||
pix__=(_pix)-2; \
|
||||
__asm__ __volatile__( \
|
||||
/*x x x x d0 c0 b0 a0*/ \
|
||||
"movd (%[pix]),%%mm0\n\t" \
|
||||
/*x x x x d1 c1 b1 a1*/ \
|
||||
"movd (%[pix],%[ystride]),%%mm1\n\t" \
|
||||
/*ystride3=_ystride*3*/ \
|
||||
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t" \
|
||||
/*x x x x d2 c2 b2 a2*/ \
|
||||
"movd (%[pix],%[ystride],2),%%mm2\n\t" \
|
||||
/*x x x x d3 c3 b3 a3*/ \
|
||||
"lea (%[pix],%[ystride],4),%[d]\n\t" \
|
||||
"movd (%[pix],%[ystride3]),%%mm3\n\t" \
|
||||
/*x x x x d4 c4 b4 a4*/ \
|
||||
"movd (%[d]),%%mm4\n\t" \
|
||||
/*x x x x d5 c5 b5 a5*/ \
|
||||
"movd (%[d],%[ystride]),%%mm5\n\t" \
|
||||
/*x x x x d6 c6 b6 a6*/ \
|
||||
"movd (%[d],%[ystride],2),%%mm6\n\t" \
|
||||
/*x x x x d7 c7 b7 a7*/ \
|
||||
"movd (%[d],%[ystride3]),%%mm7\n\t" \
|
||||
/*mm0=d1 d0 c1 c0 b1 b0 a1 a0*/ \
|
||||
"punpcklbw %%mm1,%%mm0\n\t" \
|
||||
/*mm2=d3 d2 c3 c2 b3 b2 a3 a2*/ \
|
||||
"punpcklbw %%mm3,%%mm2\n\t" \
|
||||
/*mm3=d1 d0 c1 c0 b1 b0 a1 a0*/ \
|
||||
"movq %%mm0,%%mm3\n\t" \
|
||||
/*mm0=b3 b2 b1 b0 a3 a2 a1 a0*/ \
|
||||
"punpcklwd %%mm2,%%mm0\n\t" \
|
||||
/*mm3=d3 d2 d1 d0 c3 c2 c1 c0*/ \
|
||||
"punpckhwd %%mm2,%%mm3\n\t" \
|
||||
/*mm1=b3 b2 b1 b0 a3 a2 a1 a0*/ \
|
||||
"movq %%mm0,%%mm1\n\t" \
|
||||
/*mm4=d5 d4 c5 c4 b5 b4 a5 a4*/ \
|
||||
"punpcklbw %%mm5,%%mm4\n\t" \
|
||||
/*mm6=d7 d6 c7 c6 b7 b6 a7 a6*/ \
|
||||
"punpcklbw %%mm7,%%mm6\n\t" \
|
||||
/*mm5=d5 d4 c5 c4 b5 b4 a5 a4*/ \
|
||||
"movq %%mm4,%%mm5\n\t" \
|
||||
/*mm4=b7 b6 b5 b4 a7 a6 a5 a4*/ \
|
||||
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||
/*mm5=d7 d6 d5 d4 c7 c6 c5 c4*/ \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||
/*mm2=d3 d2 d1 d0 c3 c2 c1 c0*/ \
|
||||
"movq %%mm3,%%mm2\n\t" \
|
||||
/*mm0=a7 a6 a5 a4 a3 a2 a1 a0*/ \
|
||||
"punpckldq %%mm4,%%mm0\n\t" \
|
||||
/*mm1=b7 b6 b5 b4 b3 b2 b1 b0*/ \
|
||||
"punpckhdq %%mm4,%%mm1\n\t" \
|
||||
/*mm2=c7 c6 c5 c4 c3 c2 c1 c0*/ \
|
||||
"punpckldq %%mm5,%%mm2\n\t" \
|
||||
/*mm3=d7 d6 d5 d4 d3 d2 d1 d0*/ \
|
||||
"punpckhdq %%mm5,%%mm3\n\t" \
|
||||
_filter \
|
||||
/*mm2={b0+R_0'',...,b7+R_7''}*/ \
|
||||
"movq %%mm1,%%mm0\n\t" \
|
||||
/*mm1={b0+R_0'',c0-R_0'',...,b3+R_3'',c3-R_3''}*/ \
|
||||
"punpcklbw %%mm2,%%mm1\n\t" \
|
||||
/*mm2={b4+R_4'',c4-R_4'',...,b7+R_7'',c7-R_7''}*/ \
|
||||
"punpckhbw %%mm2,%%mm0\n\t" \
|
||||
/*[d]=c1 b1 c0 b0*/ \
|
||||
"movd %%mm1,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix])\n\t" \
|
||||
"psrlq $32,%%mm1\n\t" \
|
||||
"shr $16,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix],%[ystride])\n\t" \
|
||||
/*[d]=c3 b3 c2 b2*/ \
|
||||
"movd %%mm1,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix],%[ystride],2)\n\t" \
|
||||
"shr $16,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix],%[ystride3])\n\t" \
|
||||
"lea (%[pix],%[ystride],4),%[pix]\n\t" \
|
||||
/*[d]=c5 b5 c4 b4*/ \
|
||||
"movd %%mm0,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix])\n\t" \
|
||||
"psrlq $32,%%mm0\n\t" \
|
||||
"shr $16,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix],%[ystride])\n\t" \
|
||||
/*[d]=c7 b7 c6 b6*/ \
|
||||
"movd %%mm0,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix],%[ystride],2)\n\t" \
|
||||
"shr $16,%[d]\n\t" \
|
||||
"movw %w[d],1(%[pix],%[ystride3])\n\t" \
|
||||
:[pix]"+r"(pix__),[ystride3]"=&r"(ystride3__),[d]"=&r"(d__) \
|
||||
:[ystride]"r"((ptrdiff_t)(_ystride)),[ll]"r"(_ll) \
|
||||
:"memory" \
|
||||
); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,228 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
/*MMX acceleration of complete fragment reconstruction algorithm.
|
||||
Originally written by Rudolf Marek.*/
|
||||
#include <string.h>
|
||||
#include "x86int.h"
|
||||
#include "mmxloop.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
void oc_state_frag_recon_mmx(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant){
|
||||
unsigned char *dst;
|
||||
ptrdiff_t frag_buf_off;
|
||||
int ystride;
|
||||
int mb_mode;
|
||||
/*Apply the inverse transform.*/
|
||||
/*Special case only having a DC component.*/
|
||||
if(_last_zzi<2){
|
||||
/*Note that this value must be unsigned, to keep the __asm__ block from
|
||||
sign-extending it when it puts it in a register.*/
|
||||
ogg_uint16_t p;
|
||||
int i;
|
||||
/*We round this dequant product (and not any of the others) because there's
|
||||
no iDCT rounding.*/
|
||||
p=(ogg_int16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
|
||||
/*Fill _dct_coeffs with p.*/
|
||||
__asm__ __volatile__(
|
||||
/*mm0=0000 0000 0000 AAAA*/
|
||||
"movd %[p],%%mm0\n\t"
|
||||
/*mm0=0000 0000 AAAA AAAA*/
|
||||
"punpcklwd %%mm0,%%mm0\n\t"
|
||||
/*mm0=AAAA AAAA AAAA AAAA*/
|
||||
"punpckldq %%mm0,%%mm0\n\t"
|
||||
:
|
||||
:[p]"r"((unsigned)p)
|
||||
);
|
||||
for(i=0;i<4;i++){
|
||||
__asm__ __volatile__(
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x00,y)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x08,y)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x10,y)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x18,y)"\n\t"
|
||||
:[y]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_dct_coeffs+64+16*i,16)
|
||||
);
|
||||
}
|
||||
}
|
||||
else{
|
||||
/*Dequantize the DC coefficient.*/
|
||||
_dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
|
||||
oc_idct8x8(_state,_dct_coeffs+64,_dct_coeffs,_last_zzi);
|
||||
}
|
||||
/*Fill in the target buffer.*/
|
||||
frag_buf_off=_state->frag_buf_offs[_fragi];
|
||||
mb_mode=_state->frags[_fragi].mb_mode;
|
||||
ystride=_state->ref_ystride[_pli];
|
||||
dst=_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_SELF]]+frag_buf_off;
|
||||
if(mb_mode==OC_MODE_INTRA)oc_frag_recon_intra_mmx(dst,ystride,_dct_coeffs+64);
|
||||
else{
|
||||
const unsigned char *ref;
|
||||
int mvoffsets[2];
|
||||
ref=
|
||||
_state->ref_frame_data[_state->ref_frame_idx[OC_FRAME_FOR_MODE(mb_mode)]]
|
||||
+frag_buf_off;
|
||||
if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
|
||||
_state->frag_mvs[_fragi])>1){
|
||||
oc_frag_recon_inter2_mmx(dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,
|
||||
_dct_coeffs+64);
|
||||
}
|
||||
else oc_frag_recon_inter_mmx(dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
|
||||
}
|
||||
}
|
||||
|
||||
/*We copy these entire function to inline the actual MMX routines so that we
|
||||
use only a single indirect call.*/
|
||||
|
||||
void oc_loop_filter_init_mmx(signed char _bv[256],int _flimit){
|
||||
memset(_bv,_flimit,8);
|
||||
}
|
||||
|
||||
/*Apply the loop filter to a given set of fragment rows in the given plane.
|
||||
The filter may be run on the bottom edge, affecting pixels in the next row of
|
||||
fragments, so this row also needs to be available.
|
||||
_bv: The bounding values array.
|
||||
_refi: The index of the frame buffer to filter.
|
||||
_pli: The color plane to filter.
|
||||
_fragy0: The Y coordinate of the first fragment row to filter.
|
||||
_fragy_end: The Y coordinate of the fragment row to stop filtering at.*/
|
||||
void oc_state_loop_filter_frag_rows_mmx(const oc_theora_state *_state,
|
||||
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end){
|
||||
OC_ALIGN8(unsigned char ll[8]);
|
||||
const oc_fragment_plane *fplane;
|
||||
const oc_fragment *frags;
|
||||
const ptrdiff_t *frag_buf_offs;
|
||||
unsigned char *ref_frame_data;
|
||||
ptrdiff_t fragi_top;
|
||||
ptrdiff_t fragi_bot;
|
||||
ptrdiff_t fragi0;
|
||||
ptrdiff_t fragi0_end;
|
||||
int ystride;
|
||||
int nhfrags;
|
||||
memset(ll,_state->loop_filter_limits[_state->qis[0]],sizeof(ll));
|
||||
fplane=_state->fplanes+_pli;
|
||||
nhfrags=fplane->nhfrags;
|
||||
fragi_top=fplane->froffset;
|
||||
fragi_bot=fragi_top+fplane->nfrags;
|
||||
fragi0=fragi_top+_fragy0*(ptrdiff_t)nhfrags;
|
||||
fragi0_end=fragi0+(_fragy_end-_fragy0)*(ptrdiff_t)nhfrags;
|
||||
ystride=_state->ref_ystride[_pli];
|
||||
frags=_state->frags;
|
||||
frag_buf_offs=_state->frag_buf_offs;
|
||||
ref_frame_data=_state->ref_frame_data[_refi];
|
||||
/*The following loops are constructed somewhat non-intuitively on purpose.
|
||||
The main idea is: if a block boundary has at least one coded fragment on
|
||||
it, the filter is applied to it.
|
||||
However, the order that the filters are applied in matters, and VP3 chose
|
||||
the somewhat strange ordering used below.*/
|
||||
while(fragi0<fragi0_end){
|
||||
ptrdiff_t fragi;
|
||||
ptrdiff_t fragi_end;
|
||||
fragi=fragi0;
|
||||
fragi_end=fragi+nhfrags;
|
||||
while(fragi<fragi_end){
|
||||
if(frags[fragi].coded){
|
||||
unsigned char *ref;
|
||||
ref=ref_frame_data+frag_buf_offs[fragi];
|
||||
if(fragi>fragi0){
|
||||
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMX,ref,ystride,ll);
|
||||
}
|
||||
if(fragi0>fragi_top){
|
||||
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMX,ref,ystride,ll);
|
||||
}
|
||||
if(fragi+1<fragi_end&&!frags[fragi+1].coded){
|
||||
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMX,ref+8,ystride,ll);
|
||||
}
|
||||
if(fragi+nhfrags<fragi_bot&&!frags[fragi+nhfrags].coded){
|
||||
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMX,ref+(ystride<<3),ystride,ll);
|
||||
}
|
||||
}
|
||||
fragi++;
|
||||
}
|
||||
fragi0+=nhfrags;
|
||||
}
|
||||
}
|
||||
|
||||
void oc_loop_filter_init_mmxext(signed char _bv[256],int _flimit){
|
||||
memset(_bv,~(_flimit<<1),8);
|
||||
}
|
||||
|
||||
/*Apply the loop filter to a given set of fragment rows in the given plane.
|
||||
The filter may be run on the bottom edge, affecting pixels in the next row of
|
||||
fragments, so this row also needs to be available.
|
||||
_bv: The bounding values array.
|
||||
_refi: The index of the frame buffer to filter.
|
||||
_pli: The color plane to filter.
|
||||
_fragy0: The Y coordinate of the first fragment row to filter.
|
||||
_fragy_end: The Y coordinate of the fragment row to stop filtering at.*/
|
||||
void oc_state_loop_filter_frag_rows_mmxext(const oc_theora_state *_state,
|
||||
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end){
|
||||
const oc_fragment_plane *fplane;
|
||||
const oc_fragment *frags;
|
||||
const ptrdiff_t *frag_buf_offs;
|
||||
unsigned char *ref_frame_data;
|
||||
ptrdiff_t fragi_top;
|
||||
ptrdiff_t fragi_bot;
|
||||
ptrdiff_t fragi0;
|
||||
ptrdiff_t fragi0_end;
|
||||
int ystride;
|
||||
int nhfrags;
|
||||
fplane=_state->fplanes+_pli;
|
||||
nhfrags=fplane->nhfrags;
|
||||
fragi_top=fplane->froffset;
|
||||
fragi_bot=fragi_top+fplane->nfrags;
|
||||
fragi0=fragi_top+_fragy0*(ptrdiff_t)nhfrags;
|
||||
fragi0_end=fragi_top+_fragy_end*(ptrdiff_t)nhfrags;
|
||||
ystride=_state->ref_ystride[_pli];
|
||||
frags=_state->frags;
|
||||
frag_buf_offs=_state->frag_buf_offs;
|
||||
ref_frame_data=_state->ref_frame_data[_refi];
|
||||
/*The following loops are constructed somewhat non-intuitively on purpose.
|
||||
The main idea is: if a block boundary has at least one coded fragment on
|
||||
it, the filter is applied to it.
|
||||
However, the order that the filters are applied in matters, and VP3 chose
|
||||
the somewhat strange ordering used below.*/
|
||||
while(fragi0<fragi0_end){
|
||||
ptrdiff_t fragi;
|
||||
ptrdiff_t fragi_end;
|
||||
fragi=fragi0;
|
||||
fragi_end=fragi+nhfrags;
|
||||
while(fragi<fragi_end){
|
||||
if(frags[fragi].coded){
|
||||
unsigned char *ref;
|
||||
ref=ref_frame_data+frag_buf_offs[fragi];
|
||||
if(fragi>fragi0){
|
||||
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMXEXT,ref,ystride,_bv);
|
||||
}
|
||||
if(fragi0>fragi_top){
|
||||
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMXEXT,ref,ystride,_bv);
|
||||
}
|
||||
if(fragi+1<fragi_end&&!frags[fragi+1].coded){
|
||||
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMXEXT,ref+8,ystride,_bv);
|
||||
}
|
||||
if(fragi+nhfrags<fragi_bot&&!frags[fragi+nhfrags].coded){
|
||||
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMXEXT,ref+(ystride<<3),ystride,_bv);
|
||||
}
|
||||
}
|
||||
fragi++;
|
||||
}
|
||||
fragi0+=nhfrags;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,498 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: dsp_mmx.c 14579 2008-03-12 06:42:40Z xiphmont $
|
||||
|
||||
********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include "x86enc.h"
|
||||
#include "sse2trans.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
/*Load a 4x8 array of pixels values from %[src] and %[ref] and compute their
|
||||
16-bit differences.
|
||||
On output, these are stored in _m0, xmm1, xmm2, and xmm3.
|
||||
xmm4 and xmm5 are clobbered.*/
|
||||
#define OC_LOAD_SUB_4x8(_m0) \
|
||||
"#OC_LOAD_SUB_4x8\n\t" \
|
||||
/*Load the first three rows.*/ \
|
||||
"movq (%[src]),"_m0"\n\t" \
|
||||
"movq (%[ref]),%%xmm4\n\t" \
|
||||
"movq (%[src],%[ystride]),%%xmm1\n\t" \
|
||||
"movq (%[ref],%[ystride]),%%xmm3\n\t" \
|
||||
"movq (%[src],%[ystride],2),%%xmm2\n\t" \
|
||||
"movq (%[ref],%[ystride],2),%%xmm5\n\t" \
|
||||
/*Unpack and subtract.*/ \
|
||||
"punpcklbw %%xmm4,"_m0"\n\t" \
|
||||
"punpcklbw %%xmm4,%%xmm4\n\t" \
|
||||
"punpcklbw %%xmm3,%%xmm1\n\t" \
|
||||
"punpcklbw %%xmm3,%%xmm3\n\t" \
|
||||
"psubw %%xmm4,"_m0"\n\t" \
|
||||
"psubw %%xmm3,%%xmm1\n\t" \
|
||||
/*Load the last row.*/ \
|
||||
"movq (%[src],%[ystride3]),%%xmm3\n\t" \
|
||||
"movq (%[ref],%[ystride3]),%%xmm4\n\t" \
|
||||
/*Unpack, subtract, and advance the pointers.*/ \
|
||||
"punpcklbw %%xmm5,%%xmm2\n\t" \
|
||||
"punpcklbw %%xmm5,%%xmm5\n\t" \
|
||||
"lea (%[src],%[ystride],4),%[src]\n\t" \
|
||||
"psubw %%xmm5,%%xmm2\n\t" \
|
||||
"punpcklbw %%xmm4,%%xmm3\n\t" \
|
||||
"punpcklbw %%xmm4,%%xmm4\n\t" \
|
||||
"lea (%[ref],%[ystride],4),%[ref]\n\t" \
|
||||
"psubw %%xmm4,%%xmm3\n\t" \
|
||||
|
||||
/*Square and accumulate four rows of differences in _m0, xmm1, xmm2, and xmm3.
|
||||
On output, xmm0 contains the sum of two of the rows, and the other two are
|
||||
added to xmm7.*/
|
||||
#define OC_SSD_4x8(_m0) \
|
||||
"pmaddwd "_m0","_m0"\n\t" \
|
||||
"pmaddwd %%xmm1,%%xmm1\n\t" \
|
||||
"pmaddwd %%xmm2,%%xmm2\n\t" \
|
||||
"pmaddwd %%xmm3,%%xmm3\n\t" \
|
||||
"paddd %%xmm1,"_m0"\n\t" \
|
||||
"paddd %%xmm3,%%xmm2\n\t" \
|
||||
"paddd %%xmm2,%%xmm7\n\t" \
|
||||
|
||||
unsigned oc_enc_frag_ssd_sse2(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
unsigned ret;
|
||||
__asm__ __volatile__(
|
||||
OC_LOAD_SUB_4x8("%%xmm7")
|
||||
OC_SSD_4x8("%%xmm7")
|
||||
OC_LOAD_SUB_4x8("%%xmm0")
|
||||
OC_SSD_4x8("%%xmm0")
|
||||
"paddd %%xmm0,%%xmm7\n\t"
|
||||
"movdqa %%xmm7,%%xmm6\n\t"
|
||||
"punpckhqdq %%xmm7,%%xmm7\n\t"
|
||||
"paddd %%xmm6,%%xmm7\n\t"
|
||||
"pshufd $1,%%xmm7,%%xmm6\n\t"
|
||||
"paddd %%xmm6,%%xmm7\n\t"
|
||||
"movd %%xmm7,%[ret]\n\t"
|
||||
:[ret]"=a"(ret)
|
||||
:[src]"r"(_src),[ref]"r"(_ref),[ystride]"r"((ptrdiff_t)_ystride),
|
||||
[ystride3]"r"((ptrdiff_t)_ystride*3)
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const unsigned char __attribute__((aligned(16))) OC_MASK_CONSTS[8]={
|
||||
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
|
||||
};
|
||||
|
||||
/*Load a 2x8 array of pixels values from %[src] and %[ref] and compute their
|
||||
horizontal sums as well as their 16-bit differences subject to a mask.
|
||||
%%xmm5 must contain OC_MASK_CONSTS[0...7] and %%xmm6 must contain 0.*/
|
||||
#define OC_LOAD_SUB_MASK_2x8 \
|
||||
"#OC_LOAD_SUB_MASK_2x8\n\t" \
|
||||
/*Start the loads and expand the next 8 bits of the mask.*/ \
|
||||
"shl $8,%[m]\n\t" \
|
||||
"movq (%[src]),%%xmm0\n\t" \
|
||||
"mov %h[m],%b[m]\n\t" \
|
||||
"movq (%[ref]),%%xmm2\n\t" \
|
||||
"movd %[m],%%xmm4\n\t" \
|
||||
"shr $8,%[m]\n\t" \
|
||||
"pshuflw $0x00,%%xmm4,%%xmm4\n\t" \
|
||||
"mov %h[m],%b[m]\n\t" \
|
||||
"pand %%xmm6,%%xmm4\n\t" \
|
||||
"pcmpeqb %%xmm6,%%xmm4\n\t" \
|
||||
/*Perform the masking.*/ \
|
||||
"pand %%xmm4,%%xmm0\n\t" \
|
||||
"pand %%xmm4,%%xmm2\n\t" \
|
||||
/*Finish the loads while unpacking the first set of rows, and expand the next
|
||||
8 bits of the mask.*/ \
|
||||
"movd %[m],%%xmm4\n\t" \
|
||||
"movq (%[src],%[ystride]),%%xmm1\n\t" \
|
||||
"pshuflw $0x00,%%xmm4,%%xmm4\n\t" \
|
||||
"movq (%[ref],%[ystride]),%%xmm3\n\t" \
|
||||
"pand %%xmm6,%%xmm4\n\t" \
|
||||
"punpcklbw %%xmm2,%%xmm0\n\t" \
|
||||
"pcmpeqb %%xmm6,%%xmm4\n\t" \
|
||||
"punpcklbw %%xmm2,%%xmm2\n\t" \
|
||||
/*Mask and unpack the second set of rows.*/ \
|
||||
"pand %%xmm4,%%xmm1\n\t" \
|
||||
"pand %%xmm4,%%xmm3\n\t" \
|
||||
"punpcklbw %%xmm3,%%xmm1\n\t" \
|
||||
"punpcklbw %%xmm3,%%xmm3\n\t" \
|
||||
"psubw %%xmm2,%%xmm0\n\t" \
|
||||
"psubw %%xmm3,%%xmm1\n\t" \
|
||||
|
||||
unsigned oc_enc_frag_border_ssd_sse2(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,ogg_int64_t _mask){
|
||||
ptrdiff_t ystride;
|
||||
unsigned ret;
|
||||
int i;
|
||||
ystride=_ystride;
|
||||
__asm__ __volatile__(
|
||||
"pxor %%xmm7,%%xmm7\n\t"
|
||||
"movq %[c],%%xmm6\n\t"
|
||||
:
|
||||
:[c]"m"(OC_CONST_ARRAY_OPERAND(unsigned char,OC_MASK_CONSTS,8))
|
||||
);
|
||||
for(i=0;i<4;i++){
|
||||
unsigned m;
|
||||
m=_mask&0xFFFF;
|
||||
_mask>>=16;
|
||||
if(m){
|
||||
__asm__ __volatile__(
|
||||
OC_LOAD_SUB_MASK_2x8
|
||||
"pmaddwd %%xmm0,%%xmm0\n\t"
|
||||
"pmaddwd %%xmm1,%%xmm1\n\t"
|
||||
"paddd %%xmm0,%%xmm7\n\t"
|
||||
"paddd %%xmm1,%%xmm7\n\t"
|
||||
:[src]"+r"(_src),[ref]"+r"(_ref),[ystride]"+r"(ystride),[m]"+Q"(m)
|
||||
);
|
||||
}
|
||||
_src+=2*ystride;
|
||||
_ref+=2*ystride;
|
||||
}
|
||||
__asm__ __volatile__(
|
||||
"movdqa %%xmm7,%%xmm6\n\t"
|
||||
"punpckhqdq %%xmm7,%%xmm7\n\t"
|
||||
"paddd %%xmm6,%%xmm7\n\t"
|
||||
"pshufd $1,%%xmm7,%%xmm6\n\t"
|
||||
"paddd %%xmm6,%%xmm7\n\t"
|
||||
"movd %%xmm7,%[ret]\n\t"
|
||||
:[ret]"=a"(ret)
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*Load an 8x8 array of pixel values from %[src] and %[ref] and compute their
|
||||
16-bit difference in %%xmm0...%%xmm7.*/
|
||||
#define OC_LOAD_SUB_8x8 \
|
||||
"#OC_LOAD_SUB_8x8\n\t" \
|
||||
"movq (%[src]),%%xmm0\n\t" \
|
||||
"movq (%[ref]),%%xmm4\n\t" \
|
||||
"movq (%[src],%[src_ystride]),%%xmm1\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"movq (%[ref],%[ref_ystride]),%%xmm5\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"movq (%[src]),%%xmm2\n\t" \
|
||||
"movq (%[ref]),%%xmm7\n\t" \
|
||||
"movq (%[src],%[src_ystride]),%%xmm3\n\t" \
|
||||
"movq (%[ref],%[ref_ystride]),%%xmm6\n\t" \
|
||||
"punpcklbw %%xmm4,%%xmm0\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"punpcklbw %%xmm4,%%xmm4\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"psubw %%xmm4,%%xmm0\n\t" \
|
||||
"movq (%[src]),%%xmm4\n\t" \
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||
"movq (%[ref]),%%xmm0\n\t" \
|
||||
"punpcklbw %%xmm5,%%xmm1\n\t" \
|
||||
"punpcklbw %%xmm5,%%xmm5\n\t" \
|
||||
"psubw %%xmm5,%%xmm1\n\t" \
|
||||
"movq (%[src],%[src_ystride]),%%xmm5\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm2\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm7\n\t" \
|
||||
"psubw %%xmm7,%%xmm2\n\t" \
|
||||
"movq (%[ref],%[ref_ystride]),%%xmm7\n\t" \
|
||||
"punpcklbw %%xmm6,%%xmm3\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"punpcklbw %%xmm6,%%xmm6\n\t" \
|
||||
"psubw %%xmm6,%%xmm3\n\t" \
|
||||
"movq (%[src]),%%xmm6\n\t" \
|
||||
"punpcklbw %%xmm0,%%xmm4\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"punpcklbw %%xmm0,%%xmm0\n\t" \
|
||||
"lea (%[src],%[src_ystride],2),%[src]\n\t" \
|
||||
"psubw %%xmm0,%%xmm4\n\t" \
|
||||
"movq (%[ref]),%%xmm0\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm5\n\t" \
|
||||
"neg %[src_ystride]\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm7\n\t" \
|
||||
"psubw %%xmm7,%%xmm5\n\t" \
|
||||
"movq (%[src],%[src_ystride]),%%xmm7\n\t" \
|
||||
"punpcklbw %%xmm0,%%xmm6\n\t" \
|
||||
"lea (%[ref],%[ref_ystride],2),%[ref]\n\t" \
|
||||
"punpcklbw %%xmm0,%%xmm0\n\t" \
|
||||
"neg %[ref_ystride]\n\t" \
|
||||
"psubw %%xmm0,%%xmm6\n\t" \
|
||||
"movq (%[ref],%[ref_ystride]),%%xmm0\n\t" \
|
||||
"punpcklbw %%xmm0,%%xmm7\n\t" \
|
||||
"punpcklbw %%xmm0,%%xmm0\n\t" \
|
||||
"psubw %%xmm0,%%xmm7\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm0\n\t" \
|
||||
|
||||
/*Load an 8x8 array of pixel values from %[src] into %%xmm0...%%xmm7.*/
|
||||
#define OC_LOAD_8x8 \
|
||||
"#OC_LOAD_8x8\n\t" \
|
||||
"movq (%[src]),%%xmm0\n\t" \
|
||||
"movq (%[src],%[ystride]),%%xmm1\n\t" \
|
||||
"movq (%[src],%[ystride],2),%%xmm2\n\t" \
|
||||
"pxor %%xmm7,%%xmm7\n\t" \
|
||||
"movq (%[src],%[ystride3]),%%xmm3\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm0\n\t" \
|
||||
"movq (%[src4]),%%xmm4\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm1\n\t" \
|
||||
"movq (%[src4],%[ystride]),%%xmm5\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm2\n\t" \
|
||||
"movq (%[src4],%[ystride],2),%%xmm6\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm3\n\t" \
|
||||
"movq (%[src4],%[ystride3]),%%xmm7\n\t" \
|
||||
"punpcklbw %%xmm4,%%xmm4\n\t" \
|
||||
"punpcklbw %%xmm5,%%xmm5\n\t" \
|
||||
"psrlw $8,%%xmm4\n\t" \
|
||||
"psrlw $8,%%xmm5\n\t" \
|
||||
"punpcklbw %%xmm6,%%xmm6\n\t" \
|
||||
"punpcklbw %%xmm7,%%xmm7\n\t" \
|
||||
"psrlw $8,%%xmm6\n\t" \
|
||||
"psrlw $8,%%xmm7\n\t" \
|
||||
|
||||
/*Performs the first two stages of an 8-point 1-D Hadamard transform in place.
|
||||
Outputs 1, 3, 4, and 5 from the second stage are negated (which allows us to
|
||||
perform this stage in place with no temporary registers).*/
|
||||
#define OC_HADAMARD_AB_8x8 \
|
||||
"#OC_HADAMARD_AB_8x8\n\t" \
|
||||
/*Stage A:*/ \
|
||||
"paddw %%xmm5,%%xmm1\n\t" \
|
||||
"paddw %%xmm6,%%xmm2\n\t" \
|
||||
"paddw %%xmm5,%%xmm5\n\t" \
|
||||
"paddw %%xmm6,%%xmm6\n\t" \
|
||||
"psubw %%xmm1,%%xmm5\n\t" \
|
||||
"psubw %%xmm2,%%xmm6\n\t" \
|
||||
"paddw %%xmm7,%%xmm3\n\t" \
|
||||
"paddw %%xmm4,%%xmm0\n\t" \
|
||||
"paddw %%xmm7,%%xmm7\n\t" \
|
||||
"paddw %%xmm4,%%xmm4\n\t" \
|
||||
"psubw %%xmm3,%%xmm7\n\t" \
|
||||
"psubw %%xmm0,%%xmm4\n\t" \
|
||||
/*Stage B:*/ \
|
||||
"paddw %%xmm2,%%xmm0\n\t" \
|
||||
"paddw %%xmm3,%%xmm1\n\t" \
|
||||
"paddw %%xmm6,%%xmm4\n\t" \
|
||||
"paddw %%xmm7,%%xmm5\n\t" \
|
||||
"paddw %%xmm2,%%xmm2\n\t" \
|
||||
"paddw %%xmm3,%%xmm3\n\t" \
|
||||
"paddw %%xmm6,%%xmm6\n\t" \
|
||||
"paddw %%xmm7,%%xmm7\n\t" \
|
||||
"psubw %%xmm0,%%xmm2\n\t" \
|
||||
"psubw %%xmm1,%%xmm3\n\t" \
|
||||
"psubw %%xmm4,%%xmm6\n\t" \
|
||||
"psubw %%xmm5,%%xmm7\n\t" \
|
||||
|
||||
/*Performs the last stage of an 8-point 1-D Hadamard transform in place.
|
||||
Outputs 1, 3, 5, and 7 are negated (which allows us to perform this stage in
|
||||
place with no temporary registers).*/
|
||||
#define OC_HADAMARD_C_8x8 \
|
||||
"#OC_HADAMARD_C_8x8\n\t" \
|
||||
/*Stage C:*/ \
|
||||
"paddw %%xmm1,%%xmm0\n\t" \
|
||||
"paddw %%xmm3,%%xmm2\n\t" \
|
||||
"paddw %%xmm5,%%xmm4\n\t" \
|
||||
"paddw %%xmm7,%%xmm6\n\t" \
|
||||
"paddw %%xmm1,%%xmm1\n\t" \
|
||||
"paddw %%xmm3,%%xmm3\n\t" \
|
||||
"paddw %%xmm5,%%xmm5\n\t" \
|
||||
"paddw %%xmm7,%%xmm7\n\t" \
|
||||
"psubw %%xmm0,%%xmm1\n\t" \
|
||||
"psubw %%xmm2,%%xmm3\n\t" \
|
||||
"psubw %%xmm4,%%xmm5\n\t" \
|
||||
"psubw %%xmm6,%%xmm7\n\t" \
|
||||
|
||||
/*Performs an 8-point 1-D Hadamard transform in place.
|
||||
Outputs 1, 2, 4, and 7 are negated (which allows us to perform the transform
|
||||
in place with no temporary registers).*/
|
||||
#define OC_HADAMARD_8x8 \
|
||||
OC_HADAMARD_AB_8x8 \
|
||||
OC_HADAMARD_C_8x8 \
|
||||
|
||||
/*Performs the first part of the final stage of the Hadamard transform and
|
||||
summing of absolute values.
|
||||
At the end of this part, %%xmm1 will contain the DC coefficient of the
|
||||
transform.*/
|
||||
#define OC_HADAMARD_C_ABS_ACCUM_A_8x8 \
|
||||
/*We use the fact that \
|
||||
(abs(a+b)+abs(a-b))/2=max(abs(a),abs(b)) \
|
||||
to merge the final butterfly with the abs and the first stage of \
|
||||
accumulation. \
|
||||
Thus we can avoid using pabsw, which is not available until SSSE3. \
|
||||
Emulating pabsw takes 3 instructions, so the straightforward SSE2 \
|
||||
implementation would be (3+3)*8+7=55 instructions (+4 for spilling \
|
||||
registers). \
|
||||
Even with pabsw, it would be (3+1)*8+7=39 instructions (with no spills). \
|
||||
This implementation is only 26 (+4 for spilling registers).*/ \
|
||||
"#OC_HADAMARD_C_ABS_ACCUM_A_8x8\n\t" \
|
||||
"movdqa %%xmm7,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||
"movdqa %%xmm6,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||
/*xmm7={0x7FFF}x4 \
|
||||
xmm4=max(abs(xmm4),abs(xmm5))-0x7FFF*/ \
|
||||
"pcmpeqb %%xmm7,%%xmm7\n\t" \
|
||||
"movdqa %%xmm4,%%xmm6\n\t" \
|
||||
"psrlw $1,%%xmm7\n\t" \
|
||||
"paddw %%xmm5,%%xmm6\n\t" \
|
||||
"pmaxsw %%xmm5,%%xmm4\n\t" \
|
||||
"paddsw %%xmm7,%%xmm6\n\t" \
|
||||
"psubw %%xmm6,%%xmm4\n\t" \
|
||||
/*xmm2=max(abs(xmm2),abs(xmm3))-0x7FFF \
|
||||
xmm0=max(abs(xmm0),abs(xmm1))-0x7FFF*/ \
|
||||
"movdqa %%xmm2,%%xmm6\n\t" \
|
||||
"movdqa %%xmm0,%%xmm5\n\t" \
|
||||
"pmaxsw %%xmm3,%%xmm2\n\t" \
|
||||
"pmaxsw %%xmm1,%%xmm0\n\t" \
|
||||
"paddw %%xmm3,%%xmm6\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm3\n\t" \
|
||||
"paddw %%xmm5,%%xmm1\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm5\n\t" \
|
||||
|
||||
/*Performs the second part of the final stage of the Hadamard transform and
|
||||
summing of absolute values.*/
|
||||
#define OC_HADAMARD_C_ABS_ACCUM_B_8x8 \
|
||||
"#OC_HADAMARD_C_ABS_ACCUM_B_8x8\n\t" \
|
||||
"paddsw %%xmm7,%%xmm6\n\t" \
|
||||
"paddsw %%xmm7,%%xmm1\n\t" \
|
||||
"psubw %%xmm6,%%xmm2\n\t" \
|
||||
"psubw %%xmm1,%%xmm0\n\t" \
|
||||
/*xmm7={1}x4 (needed for the horizontal add that follows) \
|
||||
xmm0+=xmm2+xmm4+max(abs(xmm3),abs(xmm5))-0x7FFF*/ \
|
||||
"movdqa %%xmm3,%%xmm6\n\t" \
|
||||
"pmaxsw %%xmm5,%%xmm3\n\t" \
|
||||
"paddw %%xmm2,%%xmm0\n\t" \
|
||||
"paddw %%xmm5,%%xmm6\n\t" \
|
||||
"paddw %%xmm4,%%xmm0\n\t" \
|
||||
"paddsw %%xmm7,%%xmm6\n\t" \
|
||||
"paddw %%xmm3,%%xmm0\n\t" \
|
||||
"psrlw $14,%%xmm7\n\t" \
|
||||
"psubw %%xmm6,%%xmm0\n\t" \
|
||||
|
||||
/*Performs the last stage of an 8-point 1-D Hadamard transform, takes the
|
||||
absolute value of each component, and accumulates everything into xmm0.*/
|
||||
#define OC_HADAMARD_C_ABS_ACCUM_8x8 \
|
||||
OC_HADAMARD_C_ABS_ACCUM_A_8x8 \
|
||||
OC_HADAMARD_C_ABS_ACCUM_B_8x8 \
|
||||
|
||||
/*Performs an 8-point 1-D Hadamard transform, takes the absolute value of each
|
||||
component, and accumulates everything into xmm0.
|
||||
Note that xmm0 will have an extra 4 added to each column, and that after
|
||||
removing this value, the remainder will be half the conventional value.*/
|
||||
#define OC_HADAMARD_ABS_ACCUM_8x8 \
|
||||
OC_HADAMARD_AB_8x8 \
|
||||
OC_HADAMARD_C_ABS_ACCUM_8x8
|
||||
|
||||
static unsigned oc_int_frag_satd_sse2(unsigned *_dc,
|
||||
const unsigned char *_src,int _src_ystride,
|
||||
const unsigned char *_ref,int _ref_ystride){
|
||||
OC_ALIGN16(ogg_int16_t buf[16]);
|
||||
unsigned ret;
|
||||
unsigned dc;
|
||||
__asm__ __volatile__(
|
||||
OC_LOAD_SUB_8x8
|
||||
OC_HADAMARD_8x8
|
||||
OC_TRANSPOSE_8x8
|
||||
/*We split out the stages here so we can save the DC coefficient in the
|
||||
middle.*/
|
||||
OC_HADAMARD_AB_8x8
|
||||
OC_HADAMARD_C_ABS_ACCUM_A_8x8
|
||||
"movd %%xmm1,%[dc]\n\t"
|
||||
OC_HADAMARD_C_ABS_ACCUM_B_8x8
|
||||
/*Up to this point, everything fit in 16 bits (8 input + 1 for the
|
||||
difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1
|
||||
for the factor of two we dropped + 3 for the vertical accumulation).
|
||||
Now we finally have to promote things to dwords.
|
||||
We break this part out of OC_HADAMARD_ABS_ACCUM_8x8 to hide the long
|
||||
latency of pmaddwd by computing abs(dc) here.*/
|
||||
"pmaddwd %%xmm7,%%xmm0\n\t"
|
||||
"movsx %w[dc],%[ret]\n\t"
|
||||
"cdq\n\t"
|
||||
"movdqa %%xmm0,%%xmm1\n\t"
|
||||
"punpckhqdq %%xmm0,%%xmm0\n\t"
|
||||
"add %[dc],%[ret]\n\t"
|
||||
"paddd %%xmm1,%%xmm0\n\t"
|
||||
"pshufd $1,%%xmm0,%%xmm1\n\t"
|
||||
"xor %[ret],%[dc]\n\t"
|
||||
"paddd %%xmm1,%%xmm0\n\t"
|
||||
"movd %%xmm0,%[ret]\n\t"
|
||||
/*The sums produced by OC_HADAMARD_ABS_ACCUM_8x8 each have an extra 4
|
||||
added to them, and a factor of two removed; correct the final sum here.*/
|
||||
"lea -64(%[ret],%[ret]),%[ret]\n\t"
|
||||
"sub %[dc],%[ret]\n\t"
|
||||
/*Although it looks like we're using 7 registers here, gcc can alias %[ret]
|
||||
and %[dc] with some of the inputs, since for once we don't write to
|
||||
them until after we're done using everything but %[buf].*/
|
||||
/*Note that _src_ystride and _ref_ystride must be given non-overlapping
|
||||
constraints, otherewise if gcc can prove they're equal it will allocate
|
||||
them to the same register (which is bad); _src and _ref face a similar
|
||||
problem.
|
||||
All four are destructively modified, but if we list them as output
|
||||
constraints, gcc can't alias them with other outputs.*/
|
||||
:[ret]"=a"(ret),[dc]"=d"(dc),[buf]"=m"(OC_ARRAY_OPERAND(short,buf,16))
|
||||
:[src]"S"(_src),[src_ystride]"c"((ptrdiff_t)_src_ystride),
|
||||
[ref]"a"(_ref),[ref_ystride]"d"((ptrdiff_t)_ref_ystride)
|
||||
/*We have to use neg, so we actually clobber the condition codes for once
|
||||
(not to mention sub, and add).*/
|
||||
:"cc"
|
||||
);
|
||||
*_dc=dc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_satd_sse2(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride){
|
||||
return oc_int_frag_satd_sse2(_dc,_src,_ystride,_ref,_ystride);
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_satd2_sse2(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride){
|
||||
OC_ALIGN8(unsigned char ref[64]);
|
||||
oc_int_frag_copy2_mmxext(ref,8,_ref1,_ref2,_ystride);
|
||||
return oc_int_frag_satd_sse2(_dc,_src,_ystride,ref,8);
|
||||
}
|
||||
|
||||
unsigned oc_enc_frag_intra_satd_sse2(unsigned *_dc,
|
||||
const unsigned char *_src,int _ystride){
|
||||
OC_ALIGN16(ogg_int16_t buf[16]);
|
||||
unsigned ret;
|
||||
unsigned dc;
|
||||
__asm__ __volatile__(
|
||||
OC_LOAD_8x8
|
||||
OC_HADAMARD_8x8
|
||||
OC_TRANSPOSE_8x8
|
||||
/*We split out the stages here so we can save the DC coefficient in the
|
||||
middle.*/
|
||||
OC_HADAMARD_AB_8x8
|
||||
OC_HADAMARD_C_ABS_ACCUM_A_8x8
|
||||
"movd %%xmm1,%[dc]\n\t"
|
||||
OC_HADAMARD_C_ABS_ACCUM_B_8x8
|
||||
/*Up to this point, everything fit in 16 bits (8 input + 1 for the
|
||||
difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1
|
||||
for the factor of two we dropped + 3 for the vertical accumulation).
|
||||
Now we finally have to promote things to dwords.*/
|
||||
"pmaddwd %%xmm7,%%xmm0\n\t"
|
||||
/*We assume that the DC coefficient is always positive (which is true,
|
||||
because the input to the INTRA transform was not a difference).*/
|
||||
"movzx %w[dc],%[dc]\n\t"
|
||||
"movdqa %%xmm0,%%xmm1\n\t"
|
||||
"punpckhqdq %%xmm0,%%xmm0\n\t"
|
||||
"paddd %%xmm1,%%xmm0\n\t"
|
||||
"pshufd $1,%%xmm0,%%xmm1\n\t"
|
||||
"paddd %%xmm1,%%xmm0\n\t"
|
||||
"movd %%xmm0,%[ret]\n\t"
|
||||
"lea -64(%[ret],%[ret]),%[ret]\n\t"
|
||||
"sub %[dc],%[ret]\n\t"
|
||||
/*Although it looks like we're using 7 registers here, gcc can alias %[ret]
|
||||
and %[dc] with some of the inputs, since for once we don't write to
|
||||
them until after we're done using everything but %[buf].*/
|
||||
:[ret]"=a"(ret),[dc]"=r"(dc),[buf]"=m"(OC_ARRAY_OPERAND(short,buf,16))
|
||||
:[src]"r"(_src),[src4]"r"(_src+4*_ystride),
|
||||
[ystride]"r"((ptrdiff_t)_ystride),[ystride3]"r"((ptrdiff_t)3*_ystride)
|
||||
/*We have to use sub, so we actually clobber the condition codes for once.*/
|
||||
:"cc"
|
||||
);
|
||||
*_dc=dc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,449 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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) 1999-2006 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
/*SSE2 fDCT implementation for x86_64.*/
|
||||
/*$Id: fdct_ses2.c 14579 2008-03-12 06:42:40Z xiphmont $*/
|
||||
#include <stddef.h>
|
||||
#include "x86enc.h"
|
||||
#include "sse2trans.h"
|
||||
|
||||
#if defined(OC_X86_64_ASM)
|
||||
|
||||
# define OC_FDCT_8x8 \
|
||||
/*Note: xmm15={0}x8 and xmm14={-1}x8.*/ \
|
||||
"#OC_FDCT_8x8\n\t" \
|
||||
/*Stage 1:*/ \
|
||||
"movdqa %%xmm0,%%xmm11\n\t" \
|
||||
"movdqa %%xmm1,%%xmm10\n\t" \
|
||||
"movdqa %%xmm2,%%xmm9\n\t" \
|
||||
"movdqa %%xmm3,%%xmm8\n\t" \
|
||||
/*xmm11=t7'=t0-t7*/ \
|
||||
"psubw %%xmm7,%%xmm11\n\t" \
|
||||
/*xmm10=t6'=t1-t6*/ \
|
||||
"psubw %%xmm6,%%xmm10\n\t" \
|
||||
/*xmm9=t5'=t2-t5*/ \
|
||||
"psubw %%xmm5,%%xmm9\n\t" \
|
||||
/*xmm8=t4'=t3-t4*/ \
|
||||
"psubw %%xmm4,%%xmm8\n\t" \
|
||||
/*xmm0=t0'=t0+t7*/ \
|
||||
"paddw %%xmm7,%%xmm0\n\t" \
|
||||
/*xmm1=t1'=t1+t6*/ \
|
||||
"paddw %%xmm6,%%xmm1\n\t" \
|
||||
/*xmm5=t2'=t2+t5*/ \
|
||||
"paddw %%xmm2,%%xmm5\n\t" \
|
||||
/*xmm4=t3'=t3+t4*/ \
|
||||
"paddw %%xmm3,%%xmm4\n\t" \
|
||||
/*xmm2,3,6,7 are now free.*/ \
|
||||
/*Stage 2:*/ \
|
||||
"movdqa %%xmm0,%%xmm3\n\t" \
|
||||
"mov $0x5A806A0A,%[a]\n\t" \
|
||||
"movdqa %%xmm1,%%xmm2\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"movdqa %%xmm10,%%xmm6\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
/*xmm2=t2''=t1'-t2'*/ \
|
||||
"psubw %%xmm5,%%xmm2\n\t" \
|
||||
"pxor %%xmm12,%%xmm12\n\t" \
|
||||
/*xmm3=t3''=t0'-t3'*/ \
|
||||
"psubw %%xmm4,%%xmm3\n\t" \
|
||||
"psubw %%xmm14,%%xmm12\n\t" \
|
||||
/*xmm10=t5''=t6'-t5'*/ \
|
||||
"psubw %%xmm9,%%xmm10\n\t" \
|
||||
"paddw %%xmm12,%%xmm12\n\t" \
|
||||
/*xmm4=t0''=t0'+t3'*/ \
|
||||
"paddw %%xmm0,%%xmm4\n\t" \
|
||||
/*xmm1=t1''=t1'+t2'*/ \
|
||||
"paddw %%xmm5,%%xmm1\n\t" \
|
||||
/*xmm6=t6''=t6'+t5'*/ \
|
||||
"paddw %%xmm9,%%xmm6\n\t" \
|
||||
/*xmm0,xmm5,xmm9 are now free.*/ \
|
||||
/*Stage 3:*/ \
|
||||
/*xmm10:xmm5=t5''*27146+0xB500 \
|
||||
xmm0=t5''*/ \
|
||||
"movdqa %%xmm10,%%xmm5\n\t" \
|
||||
"movdqa %%xmm10,%%xmm0\n\t" \
|
||||
"punpckhwd %%xmm12,%%xmm10\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm10\n\t" \
|
||||
"punpcklwd %%xmm12,%%xmm5\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm5\n\t" \
|
||||
/*xmm5=(t5''*27146+0xB500>>16)+t5''*/ \
|
||||
"psrad $16,%%xmm10\n\t" \
|
||||
"psrad $16,%%xmm5\n\t" \
|
||||
"packssdw %%xmm10,%%xmm5\n\t" \
|
||||
"paddw %%xmm0,%%xmm5\n\t" \
|
||||
/*xmm0=s=(t5''*27146+0xB500>>16)+t5''+(t5''!=0)>>1*/ \
|
||||
"pcmpeqw %%xmm15,%%xmm0\n\t" \
|
||||
"psubw %%xmm14,%%xmm0\n\t" \
|
||||
"paddw %%xmm5,%%xmm0\n\t" \
|
||||
"movdqa %%xmm8,%%xmm5\n\t" \
|
||||
"psraw $1,%%xmm0\n\t" \
|
||||
/*xmm5=t5'''=t4'-s*/ \
|
||||
"psubw %%xmm0,%%xmm5\n\t" \
|
||||
/*xmm8=t4''=t4'+s*/ \
|
||||
"paddw %%xmm0,%%xmm8\n\t" \
|
||||
/*xmm0,xmm7,xmm9,xmm10 are free.*/ \
|
||||
/*xmm7:xmm9=t6''*27146+0xB500*/ \
|
||||
"movdqa %%xmm6,%%xmm7\n\t" \
|
||||
"movdqa %%xmm6,%%xmm9\n\t" \
|
||||
"punpckhwd %%xmm12,%%xmm7\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm7\n\t" \
|
||||
"punpcklwd %%xmm12,%%xmm9\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm9\n\t" \
|
||||
/*xmm9=(t6''*27146+0xB500>>16)+t6''*/ \
|
||||
"psrad $16,%%xmm7\n\t" \
|
||||
"psrad $16,%%xmm9\n\t" \
|
||||
"packssdw %%xmm7,%%xmm9\n\t" \
|
||||
"paddw %%xmm6,%%xmm9\n\t" \
|
||||
/*xmm9=s=(t6''*27146+0xB500>>16)+t6''+(t6''!=0)>>1*/ \
|
||||
"pcmpeqw %%xmm15,%%xmm6\n\t" \
|
||||
"psubw %%xmm14,%%xmm6\n\t" \
|
||||
"paddw %%xmm6,%%xmm9\n\t" \
|
||||
"movdqa %%xmm11,%%xmm7\n\t" \
|
||||
"psraw $1,%%xmm9\n\t" \
|
||||
/*xmm7=t6'''=t7'-s*/ \
|
||||
"psubw %%xmm9,%%xmm7\n\t" \
|
||||
/*xmm9=t7''=t7'+s*/ \
|
||||
"paddw %%xmm11,%%xmm9\n\t" \
|
||||
/*xmm0,xmm6,xmm10,xmm11 are free.*/ \
|
||||
/*Stage 4:*/ \
|
||||
/*xmm10:xmm0=t1''*27146+0xB500*/ \
|
||||
"movdqa %%xmm1,%%xmm0\n\t" \
|
||||
"movdqa %%xmm1,%%xmm10\n\t" \
|
||||
"punpcklwd %%xmm12,%%xmm0\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm0\n\t" \
|
||||
"punpckhwd %%xmm12,%%xmm10\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm10\n\t" \
|
||||
/*xmm0=(t1''*27146+0xB500>>16)+t1''*/ \
|
||||
"psrad $16,%%xmm0\n\t" \
|
||||
"psrad $16,%%xmm10\n\t" \
|
||||
"mov $0x20006A0A,%[a]\n\t" \
|
||||
"packssdw %%xmm10,%%xmm0\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"paddw %%xmm1,%%xmm0\n\t" \
|
||||
/*xmm0=s=(t1''*27146+0xB500>>16)+t1''+(t1''!=0)*/ \
|
||||
"pcmpeqw %%xmm15,%%xmm1\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"psubw %%xmm14,%%xmm1\n\t" \
|
||||
"paddw %%xmm1,%%xmm0\n\t" \
|
||||
/*xmm10:xmm4=t0''*27146+0x4000*/ \
|
||||
"movdqa %%xmm4,%%xmm1\n\t" \
|
||||
"movdqa %%xmm4,%%xmm10\n\t" \
|
||||
"punpcklwd %%xmm12,%%xmm4\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm4\n\t" \
|
||||
"punpckhwd %%xmm12,%%xmm10\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm10\n\t" \
|
||||
/*xmm4=(t0''*27146+0x4000>>16)+t0''*/ \
|
||||
"psrad $16,%%xmm4\n\t" \
|
||||
"psrad $16,%%xmm10\n\t" \
|
||||
"mov $0x6CB7,%[a]\n\t" \
|
||||
"packssdw %%xmm10,%%xmm4\n\t" \
|
||||
"movd %[a],%%xmm12\n\t" \
|
||||
"paddw %%xmm1,%%xmm4\n\t" \
|
||||
/*xmm4=r=(t0''*27146+0x4000>>16)+t0''+(t0''!=0)*/ \
|
||||
"pcmpeqw %%xmm15,%%xmm1\n\t" \
|
||||
"pshufd $00,%%xmm12,%%xmm12\n\t" \
|
||||
"psubw %%xmm14,%%xmm1\n\t" \
|
||||
"mov $0x7FFF6C84,%[a]\n\t" \
|
||||
"paddw %%xmm1,%%xmm4\n\t" \
|
||||
/*xmm0=_y[0]=u=r+s>>1 \
|
||||
The naive implementation could cause overflow, so we use \
|
||||
u=(r&s)+((r^s)>>1).*/ \
|
||||
"movdqa %%xmm0,%%xmm6\n\t" \
|
||||
"pxor %%xmm4,%%xmm0\n\t" \
|
||||
"pand %%xmm4,%%xmm6\n\t" \
|
||||
"psraw $1,%%xmm0\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"paddw %%xmm6,%%xmm0\n\t" \
|
||||
/*xmm4=_y[4]=v=r-u*/ \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"psubw %%xmm0,%%xmm4\n\t" \
|
||||
/*xmm1,xmm6,xmm10,xmm11 are free.*/ \
|
||||
/*xmm6:xmm10=60547*t3''+0x6CB7*/ \
|
||||
"movdqa %%xmm3,%%xmm10\n\t" \
|
||||
"movdqa %%xmm3,%%xmm6\n\t" \
|
||||
"punpcklwd %%xmm3,%%xmm10\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm10\n\t" \
|
||||
"mov $0x61F861F8,%[a]\n\t" \
|
||||
"punpckhwd %%xmm3,%%xmm6\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm6\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"paddd %%xmm12,%%xmm10\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"paddd %%xmm12,%%xmm6\n\t" \
|
||||
/*xmm1:xmm2=25080*t2'' \
|
||||
xmm12=t2''*/ \
|
||||
"movdqa %%xmm2,%%xmm11\n\t" \
|
||||
"movdqa %%xmm2,%%xmm12\n\t" \
|
||||
"pmullw %%xmm13,%%xmm2\n\t" \
|
||||
"pmulhw %%xmm13,%%xmm11\n\t" \
|
||||
"movdqa %%xmm2,%%xmm1\n\t" \
|
||||
"punpcklwd %%xmm11,%%xmm2\n\t" \
|
||||
"punpckhwd %%xmm11,%%xmm1\n\t" \
|
||||
/*xmm10=u=(25080*t2''+60547*t3''+0x6CB7>>16)+(t3''!=0)*/ \
|
||||
"paddd %%xmm2,%%xmm10\n\t" \
|
||||
"paddd %%xmm1,%%xmm6\n\t" \
|
||||
"psrad $16,%%xmm10\n\t" \
|
||||
"pcmpeqw %%xmm15,%%xmm3\n\t" \
|
||||
"psrad $16,%%xmm6\n\t" \
|
||||
"psubw %%xmm14,%%xmm3\n\t" \
|
||||
"packssdw %%xmm6,%%xmm10\n\t" \
|
||||
"paddw %%xmm3,%%xmm10\n\t" \
|
||||
/*xmm2=_y[2]=u \
|
||||
xmm10=s=(25080*u>>16)-t2''*/ \
|
||||
"movdqa %%xmm10,%%xmm2\n\t" \
|
||||
"pmulhw %%xmm13,%%xmm10\n\t" \
|
||||
"psubw %%xmm12,%%xmm10\n\t" \
|
||||
/*xmm1:xmm6=s*21600+0x2800*/ \
|
||||
"pxor %%xmm12,%%xmm12\n\t" \
|
||||
"psubw %%xmm14,%%xmm12\n\t" \
|
||||
"mov $0x28005460,%[a]\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"movdqa %%xmm10,%%xmm6\n\t" \
|
||||
"movdqa %%xmm10,%%xmm1\n\t" \
|
||||
"punpcklwd %%xmm12,%%xmm6\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm6\n\t" \
|
||||
"mov $0x0E3D,%[a]\n\t" \
|
||||
"punpckhwd %%xmm12,%%xmm1\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm1\n\t" \
|
||||
/*xmm6=(s*21600+0x2800>>18)+s*/ \
|
||||
"psrad $18,%%xmm6\n\t" \
|
||||
"psrad $18,%%xmm1\n\t" \
|
||||
"movd %[a],%%xmm12\n\t" \
|
||||
"packssdw %%xmm1,%%xmm6\n\t" \
|
||||
"pshufd $00,%%xmm12,%%xmm12\n\t" \
|
||||
"paddw %%xmm10,%%xmm6\n\t" \
|
||||
/*xmm6=_y[6]=v=(s*21600+0x2800>>18)+s+(s!=0)*/ \
|
||||
"mov $0x7FFF54DC,%[a]\n\t" \
|
||||
"pcmpeqw %%xmm15,%%xmm10\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"psubw %%xmm14,%%xmm10\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"paddw %%xmm10,%%xmm6\n\t " \
|
||||
/*xmm1,xmm3,xmm10,xmm11 are free.*/ \
|
||||
/*xmm11:xmm10=54491*t5'''+0x0E3D*/ \
|
||||
"movdqa %%xmm5,%%xmm10\n\t" \
|
||||
"movdqa %%xmm5,%%xmm11\n\t" \
|
||||
"punpcklwd %%xmm5,%%xmm10\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm10\n\t" \
|
||||
"mov $0x8E3A8E3A,%[a]\n\t" \
|
||||
"punpckhwd %%xmm5,%%xmm11\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm11\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"paddd %%xmm12,%%xmm10\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"paddd %%xmm12,%%xmm11\n\t" \
|
||||
/*xmm7:xmm12=36410*t6''' \
|
||||
xmm1=t6'''*/ \
|
||||
"movdqa %%xmm7,%%xmm3\n\t" \
|
||||
"movdqa %%xmm7,%%xmm1\n\t" \
|
||||
"pmulhw %%xmm13,%%xmm3\n\t" \
|
||||
"pmullw %%xmm13,%%xmm7\n\t" \
|
||||
"paddw %%xmm1,%%xmm3\n\t" \
|
||||
"movdqa %%xmm7,%%xmm12\n\t" \
|
||||
"punpckhwd %%xmm3,%%xmm7\n\t" \
|
||||
"punpcklwd %%xmm3,%%xmm12\n\t" \
|
||||
/*xmm10=u=(54491*t5'''+36410*t6'''+0x0E3D>>16)+(t5'''!=0)*/ \
|
||||
"paddd %%xmm12,%%xmm10\n\t" \
|
||||
"paddd %%xmm7,%%xmm11\n\t" \
|
||||
"psrad $16,%%xmm10\n\t" \
|
||||
"pcmpeqw %%xmm15,%%xmm5\n\t" \
|
||||
"psrad $16,%%xmm11\n\t" \
|
||||
"psubw %%xmm14,%%xmm5\n\t" \
|
||||
"packssdw %%xmm11,%%xmm10\n\t" \
|
||||
"pxor %%xmm12,%%xmm12\n\t" \
|
||||
"paddw %%xmm5,%%xmm10\n\t" \
|
||||
/*xmm5=_y[5]=u \
|
||||
xmm1=s=t6'''-(36410*u>>16)*/ \
|
||||
"psubw %%xmm14,%%xmm12\n\t" \
|
||||
"movdqa %%xmm10,%%xmm5\n\t" \
|
||||
"mov $0x340067C8,%[a]\n\t" \
|
||||
"pmulhw %%xmm13,%%xmm10\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"paddw %%xmm5,%%xmm10\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"psubw %%xmm10,%%xmm1\n\t" \
|
||||
/*xmm11:xmm3=s*26568+0x3400*/ \
|
||||
"movdqa %%xmm1,%%xmm3\n\t" \
|
||||
"movdqa %%xmm1,%%xmm11\n\t" \
|
||||
"punpcklwd %%xmm12,%%xmm3\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm3\n\t" \
|
||||
"mov $0x7B1B,%[a]\n\t" \
|
||||
"punpckhwd %%xmm12,%%xmm11\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm11\n\t" \
|
||||
/*xmm3=(s*26568+0x3400>>17)+s*/ \
|
||||
"psrad $17,%%xmm3\n\t" \
|
||||
"psrad $17,%%xmm11\n\t" \
|
||||
"movd %[a],%%xmm12\n\t" \
|
||||
"packssdw %%xmm11,%%xmm3\n\t" \
|
||||
"pshufd $00,%%xmm12,%%xmm12\n\t" \
|
||||
"paddw %%xmm1,%%xmm3\n\t" \
|
||||
/*xmm3=_y[3]=v=(s*26568+0x3400>>17)+s+(s!=0)*/ \
|
||||
"mov $0x7FFF7B16,%[a]\n\t" \
|
||||
"pcmpeqw %%xmm15,%%xmm1\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"psubw %%xmm14,%%xmm1\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"paddw %%xmm1,%%xmm3\n\t " \
|
||||
/*xmm1,xmm7,xmm10,xmm11 are free.*/ \
|
||||
/*xmm11:xmm10=64277*t7''+0x7B1B*/ \
|
||||
"movdqa %%xmm9,%%xmm10\n\t" \
|
||||
"movdqa %%xmm9,%%xmm11\n\t" \
|
||||
"punpcklwd %%xmm9,%%xmm10\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm10\n\t" \
|
||||
"mov $0x31F131F1,%[a]\n\t" \
|
||||
"punpckhwd %%xmm9,%%xmm11\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm11\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"paddd %%xmm12,%%xmm10\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
"paddd %%xmm12,%%xmm11\n\t" \
|
||||
/*xmm12:xmm7=12785*t4''*/ \
|
||||
"movdqa %%xmm8,%%xmm7\n\t" \
|
||||
"movdqa %%xmm8,%%xmm1\n\t" \
|
||||
"pmullw %%xmm13,%%xmm7\n\t" \
|
||||
"pmulhw %%xmm13,%%xmm1\n\t" \
|
||||
"movdqa %%xmm7,%%xmm12\n\t" \
|
||||
"punpcklwd %%xmm1,%%xmm7\n\t" \
|
||||
"punpckhwd %%xmm1,%%xmm12\n\t" \
|
||||
/*xmm10=u=(12785*t4''+64277*t7''+0x7B1B>>16)+(t7''!=0)*/ \
|
||||
"paddd %%xmm7,%%xmm10\n\t" \
|
||||
"paddd %%xmm12,%%xmm11\n\t" \
|
||||
"psrad $16,%%xmm10\n\t" \
|
||||
"pcmpeqw %%xmm15,%%xmm9\n\t" \
|
||||
"psrad $16,%%xmm11\n\t" \
|
||||
"psubw %%xmm14,%%xmm9\n\t" \
|
||||
"packssdw %%xmm11,%%xmm10\n\t" \
|
||||
"pxor %%xmm12,%%xmm12\n\t" \
|
||||
"paddw %%xmm9,%%xmm10\n\t" \
|
||||
/*xmm1=_y[1]=u \
|
||||
xmm10=s=(12785*u>>16)-t4''*/ \
|
||||
"psubw %%xmm14,%%xmm12\n\t" \
|
||||
"movdqa %%xmm10,%%xmm1\n\t" \
|
||||
"mov $0x3000503B,%[a]\n\t" \
|
||||
"pmulhw %%xmm13,%%xmm10\n\t" \
|
||||
"movd %[a],%%xmm13\n\t" \
|
||||
"psubw %%xmm8,%%xmm10\n\t" \
|
||||
"pshufd $00,%%xmm13,%%xmm13\n\t" \
|
||||
/*xmm8:xmm7=s*20539+0x3000*/ \
|
||||
"movdqa %%xmm10,%%xmm7\n\t" \
|
||||
"movdqa %%xmm10,%%xmm8\n\t" \
|
||||
"punpcklwd %%xmm12,%%xmm7\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm7\n\t" \
|
||||
"punpckhwd %%xmm12,%%xmm8\n\t" \
|
||||
"pmaddwd %%xmm13,%%xmm8\n\t" \
|
||||
/*xmm7=(s*20539+0x3000>>20)+s*/ \
|
||||
"psrad $20,%%xmm7\n\t" \
|
||||
"psrad $20,%%xmm8\n\t" \
|
||||
"packssdw %%xmm8,%%xmm7\n\t" \
|
||||
"paddw %%xmm10,%%xmm7\n\t" \
|
||||
/*xmm7=_y[7]=v=(s*20539+0x3000>>20)+s+(s!=0)*/ \
|
||||
"pcmpeqw %%xmm15,%%xmm10\n\t" \
|
||||
"psubw %%xmm14,%%xmm10\n\t" \
|
||||
"paddw %%xmm10,%%xmm7\n\t " \
|
||||
|
||||
/*SSE2 implementation of the fDCT for x86-64 only.
|
||||
Because of the 8 extra XMM registers on x86-64, this version can operate
|
||||
without any temporary stack access at all.*/
|
||||
void oc_enc_fdct8x8_x86_64sse2(ogg_int16_t _y[64],const ogg_int16_t _x[64]){
|
||||
ptrdiff_t a;
|
||||
__asm__ __volatile__(
|
||||
/*Load the input.*/
|
||||
"movdqa 0x00(%[x]),%%xmm0\n\t"
|
||||
"movdqa 0x10(%[x]),%%xmm1\n\t"
|
||||
"movdqa 0x20(%[x]),%%xmm2\n\t"
|
||||
"movdqa 0x30(%[x]),%%xmm3\n\t"
|
||||
"movdqa 0x40(%[x]),%%xmm4\n\t"
|
||||
"movdqa 0x50(%[x]),%%xmm5\n\t"
|
||||
"movdqa 0x60(%[x]),%%xmm6\n\t"
|
||||
"movdqa 0x70(%[x]),%%xmm7\n\t"
|
||||
/*Add two extra bits of working precision to improve accuracy; any more and
|
||||
we could overflow.*/
|
||||
/*We also add a few biases to correct for some systematic error that
|
||||
remains in the full fDCT->iDCT round trip.*/
|
||||
/*xmm15={0}x8*/
|
||||
"pxor %%xmm15,%%xmm15\n\t"
|
||||
/*xmm14={-1}x8*/
|
||||
"pcmpeqb %%xmm14,%%xmm14\n\t"
|
||||
"psllw $2,%%xmm0\n\t"
|
||||
/*xmm8=xmm0*/
|
||||
"movdqa %%xmm0,%%xmm8\n\t"
|
||||
"psllw $2,%%xmm1\n\t"
|
||||
/*xmm8={_x[7...0]==0}*/
|
||||
"pcmpeqw %%xmm15,%%xmm8\n\t"
|
||||
"psllw $2,%%xmm2\n\t"
|
||||
/*xmm8={_x[7...0]!=0}*/
|
||||
"psubw %%xmm14,%%xmm8\n\t"
|
||||
"psllw $2,%%xmm3\n\t"
|
||||
/*%[a]=1*/
|
||||
"mov $1,%[a]\n\t"
|
||||
/*xmm8={_x[6]!=0,0,_x[4]!=0,0,_x[2]!=0,0,_x[0]!=0,0}*/
|
||||
"pslld $16,%%xmm8\n\t"
|
||||
"psllw $2,%%xmm4\n\t"
|
||||
/*xmm9={0,0,0,0,0,0,0,1}*/
|
||||
"movd %[a],%%xmm9\n\t"
|
||||
/*xmm8={0,0,_x[2]!=0,0,_x[0]!=0,0}*/
|
||||
"pshufhw $0x00,%%xmm8,%%xmm8\n\t"
|
||||
"psllw $2,%%xmm5\n\t"
|
||||
/*%[a]={1}x2*/
|
||||
"mov $0x10001,%[a]\n\t"
|
||||
/*xmm8={0,0,0,0,0,0,0,_x[0]!=0}*/
|
||||
"pshuflw $0x01,%%xmm8,%%xmm8\n\t"
|
||||
"psllw $2,%%xmm6\n\t"
|
||||
/*xmm10={0,0,0,0,0,0,1,1}*/
|
||||
"movd %[a],%%xmm10\n\t"
|
||||
/*xmm0=_x[7...0]+{0,0,0,0,0,0,0,_x[0]!=0}*/
|
||||
"paddw %%xmm8,%%xmm0\n\t"
|
||||
"psllw $2,%%xmm7\n\t"
|
||||
/*xmm0=_x[7...0]+{0,0,0,0,0,0,1,(_x[0]!=0)+1}*/
|
||||
"paddw %%xmm10,%%xmm0\n\t"
|
||||
/*xmm1=_x[15...8]-{0,0,0,0,0,0,0,1}*/
|
||||
"psubw %%xmm9,%%xmm1\n\t"
|
||||
/*Transform columns.*/
|
||||
OC_FDCT_8x8
|
||||
/*Transform rows.*/
|
||||
OC_TRANSPOSE_8x8
|
||||
OC_FDCT_8x8
|
||||
/*TODO: zig-zag ordering?*/
|
||||
OC_TRANSPOSE_8x8
|
||||
/*xmm14={-2,-2,-2,-2,-2,-2,-2,-2}*/
|
||||
"paddw %%xmm14,%%xmm14\n\t"
|
||||
"psubw %%xmm14,%%xmm0\n\t"
|
||||
"psubw %%xmm14,%%xmm1\n\t"
|
||||
"psraw $2,%%xmm0\n\t"
|
||||
"psubw %%xmm14,%%xmm2\n\t"
|
||||
"psraw $2,%%xmm1\n\t"
|
||||
"psubw %%xmm14,%%xmm3\n\t"
|
||||
"psraw $2,%%xmm2\n\t"
|
||||
"psubw %%xmm14,%%xmm4\n\t"
|
||||
"psraw $2,%%xmm3\n\t"
|
||||
"psubw %%xmm14,%%xmm5\n\t"
|
||||
"psraw $2,%%xmm4\n\t"
|
||||
"psubw %%xmm14,%%xmm6\n\t"
|
||||
"psraw $2,%%xmm5\n\t"
|
||||
"psubw %%xmm14,%%xmm7\n\t"
|
||||
"psraw $2,%%xmm6\n\t"
|
||||
"psraw $2,%%xmm7\n\t"
|
||||
/*Store the result.*/
|
||||
"movdqa %%xmm0,0x00(%[y])\n\t"
|
||||
"movdqa %%xmm1,0x10(%[y])\n\t"
|
||||
"movdqa %%xmm2,0x20(%[y])\n\t"
|
||||
"movdqa %%xmm3,0x30(%[y])\n\t"
|
||||
"movdqa %%xmm4,0x40(%[y])\n\t"
|
||||
"movdqa %%xmm5,0x50(%[y])\n\t"
|
||||
"movdqa %%xmm6,0x60(%[y])\n\t"
|
||||
"movdqa %%xmm7,0x70(%[y])\n\t"
|
||||
:[a]"=&r"(a)
|
||||
:[y]"r"(_y),[x]"r"(_x)
|
||||
:"memory"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,460 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: mmxidct.c 16503 2009-08-22 18:14:02Z giles $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
/*SSE2 acceleration of Theora's iDCT.*/
|
||||
#include "x86enc.h"
|
||||
#include "sse2trans.h"
|
||||
#include "../dct.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
/*A table of constants used by the MMX routines.*/
|
||||
const short __attribute__((aligned(16),used)) OC_IDCT_CONSTS[64]={
|
||||
8, 8, 8, 8, 8, 8, 8, 8,
|
||||
OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,
|
||||
OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,
|
||||
OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,
|
||||
OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,
|
||||
OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,
|
||||
OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,
|
||||
OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1
|
||||
};
|
||||
|
||||
|
||||
/*Performs the first three stages of the iDCT.
|
||||
xmm2, xmm6, xmm3, and xmm5 must contain the corresponding rows of the input
|
||||
(accessed in that order).
|
||||
The remaining rows must be in _x at their corresponding locations.
|
||||
On output, xmm7 down to xmm4 contain rows 0 through 3, and xmm0 up to xmm3
|
||||
contain rows 4 through 7.*/
|
||||
#define OC_IDCT_8x8_ABC(_x) \
|
||||
"#OC_IDCT_8x8_ABC\n\t" \
|
||||
/*Stage 1:*/ \
|
||||
/*2-3 rotation by 6pi/16. \
|
||||
xmm4=xmm7=C6, xmm0=xmm1=C2, xmm2=X2, xmm6=X6.*/ \
|
||||
"movdqa "OC_MEM_OFFS(0x20,c)",%%xmm1\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x60,c)",%%xmm4\n\t" \
|
||||
"movdqa %%xmm1,%%xmm0\n\t" \
|
||||
"pmulhw %%xmm2,%%xmm1\n\t" \
|
||||
"movdqa %%xmm4,%%xmm7\n\t" \
|
||||
"pmulhw %%xmm6,%%xmm0\n\t" \
|
||||
"pmulhw %%xmm2,%%xmm7\n\t" \
|
||||
"pmulhw %%xmm6,%%xmm4\n\t" \
|
||||
"paddw %%xmm6,%%xmm0\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x30,c)",%%xmm6\n\t" \
|
||||
"paddw %%xmm1,%%xmm2\n\t" \
|
||||
"psubw %%xmm0,%%xmm7\n\t" \
|
||||
"movdqa %%xmm7,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||
"paddw %%xmm4,%%xmm2\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x50,c)",%%xmm4\n\t" \
|
||||
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||
/*5-6 rotation by 3pi/16. \
|
||||
xmm4=xmm2=C5, xmm1=xmm6=C3, xmm3=X3, xmm5=X5.*/ \
|
||||
"movdqa %%xmm4,%%xmm2\n\t" \
|
||||
"movdqa %%xmm6,%%xmm1\n\t" \
|
||||
"pmulhw %%xmm3,%%xmm4\n\t" \
|
||||
"pmulhw %%xmm5,%%xmm1\n\t" \
|
||||
"pmulhw %%xmm3,%%xmm6\n\t" \
|
||||
"pmulhw %%xmm5,%%xmm2\n\t" \
|
||||
"paddw %%xmm3,%%xmm4\n\t" \
|
||||
"paddw %%xmm5,%%xmm3\n\t" \
|
||||
"paddw %%xmm6,%%xmm3\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x70,_x)",%%xmm6\n\t" \
|
||||
"paddw %%xmm5,%%xmm1\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x10,_x)",%%xmm5\n\t" \
|
||||
"paddw %%xmm3,%%xmm2\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x70,c)",%%xmm3\n\t" \
|
||||
"psubw %%xmm4,%%xmm1\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x10,c)",%%xmm4\n\t" \
|
||||
/*4-7 rotation by 7pi/16. \
|
||||
xmm4=xmm7=C1, xmm3=xmm0=C7, xmm5=X1, xmm6=X7.*/ \
|
||||
"movdqa %%xmm3,%%xmm0\n\t" \
|
||||
"movdqa %%xmm4,%%xmm7\n\t" \
|
||||
"pmulhw %%xmm5,%%xmm3\n\t" \
|
||||
"pmulhw %%xmm5,%%xmm7\n\t" \
|
||||
"pmulhw %%xmm6,%%xmm4\n\t" \
|
||||
"pmulhw %%xmm6,%%xmm0\n\t" \
|
||||
"paddw %%xmm6,%%xmm4\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x40,_x)",%%xmm6\n\t" \
|
||||
"paddw %%xmm5,%%xmm7\n\t" \
|
||||
"psubw %%xmm4,%%xmm3\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x40,c)",%%xmm4\n\t" \
|
||||
"paddw %%xmm7,%%xmm0\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x00,_x)",%%xmm7\n\t" \
|
||||
/*0-1 butterfly. \
|
||||
xmm4=xmm5=C4, xmm7=X0, xmm6=X4.*/ \
|
||||
"paddw %%xmm7,%%xmm6\n\t" \
|
||||
"movdqa %%xmm4,%%xmm5\n\t" \
|
||||
"pmulhw %%xmm6,%%xmm4\n\t" \
|
||||
"paddw %%xmm7,%%xmm7\n\t" \
|
||||
"psubw %%xmm6,%%xmm7\n\t" \
|
||||
"paddw %%xmm6,%%xmm4\n\t" \
|
||||
/*Stage 2:*/ \
|
||||
/*4-5 butterfly: xmm3=t[4], xmm1=t[5] \
|
||||
7-6 butterfly: xmm2=t[6], xmm0=t[7]*/ \
|
||||
"movdqa %%xmm3,%%xmm6\n\t" \
|
||||
"paddw %%xmm1,%%xmm3\n\t" \
|
||||
"psubw %%xmm1,%%xmm6\n\t" \
|
||||
"movdqa %%xmm5,%%xmm1\n\t" \
|
||||
"pmulhw %%xmm7,%%xmm5\n\t" \
|
||||
"paddw %%xmm7,%%xmm5\n\t" \
|
||||
"movdqa %%xmm0,%%xmm7\n\t" \
|
||||
"paddw %%xmm2,%%xmm0\n\t" \
|
||||
"psubw %%xmm2,%%xmm7\n\t" \
|
||||
"movdqa %%xmm1,%%xmm2\n\t" \
|
||||
"pmulhw %%xmm6,%%xmm1\n\t" \
|
||||
"pmulhw %%xmm7,%%xmm2\n\t" \
|
||||
"paddw %%xmm6,%%xmm1\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm6\n\t" \
|
||||
"paddw %%xmm7,%%xmm2\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm7\n\t" \
|
||||
/*Stage 3: \
|
||||
6-5 butterfly: xmm1=t[5], xmm2=t[6] -> xmm1=t[6]+t[5], xmm2=t[6]-t[5] \
|
||||
0-3 butterfly: xmm4=t[0], xmm7=t[3] -> xmm7=t[0]+t[3], xmm4=t[0]-t[3] \
|
||||
1-2 butterfly: xmm5=t[1], xmm6=t[2] -> xmm6=t[1]+t[2], xmm5=t[1]-t[2]*/ \
|
||||
"paddw %%xmm2,%%xmm1\n\t" \
|
||||
"paddw %%xmm5,%%xmm6\n\t" \
|
||||
"paddw %%xmm4,%%xmm7\n\t" \
|
||||
"paddw %%xmm2,%%xmm2\n\t" \
|
||||
"paddw %%xmm4,%%xmm4\n\t" \
|
||||
"paddw %%xmm5,%%xmm5\n\t" \
|
||||
"psubw %%xmm1,%%xmm2\n\t" \
|
||||
"psubw %%xmm7,%%xmm4\n\t" \
|
||||
"psubw %%xmm6,%%xmm5\n\t" \
|
||||
|
||||
/*Performs the last stage of the iDCT.
|
||||
On input, xmm7 down to xmm4 contain rows 0 through 3, and xmm0 up to xmm3
|
||||
contain rows 4 through 7.
|
||||
On output, xmm0 through xmm7 contain the corresponding rows.*/
|
||||
#define OC_IDCT_8x8_D \
|
||||
"#OC_IDCT_8x8_D\n\t" \
|
||||
/*Stage 4: \
|
||||
0-7 butterfly: xmm7=t[0], xmm0=t[7] -> xmm0=t[0]+t[7], xmm7=t[0]-t[7] \
|
||||
1-6 butterfly: xmm6=t[1], xmm1=t[6] -> xmm1=t[1]+t[6], xmm6=t[1]-t[6] \
|
||||
2-5 butterfly: xmm5=t[2], xmm2=t[5] -> xmm2=t[2]+t[5], xmm5=t[2]-t[5] \
|
||||
3-4 butterfly: xmm4=t[3], xmm3=t[4] -> xmm3=t[3]+t[4], xmm4=t[3]-t[4]*/ \
|
||||
"psubw %%xmm0,%%xmm7\n\t" \
|
||||
"psubw %%xmm1,%%xmm6\n\t" \
|
||||
"psubw %%xmm2,%%xmm5\n\t" \
|
||||
"psubw %%xmm3,%%xmm4\n\t" \
|
||||
"paddw %%xmm0,%%xmm0\n\t" \
|
||||
"paddw %%xmm1,%%xmm1\n\t" \
|
||||
"paddw %%xmm2,%%xmm2\n\t" \
|
||||
"paddw %%xmm3,%%xmm3\n\t" \
|
||||
"paddw %%xmm7,%%xmm0\n\t" \
|
||||
"paddw %%xmm6,%%xmm1\n\t" \
|
||||
"paddw %%xmm5,%%xmm2\n\t" \
|
||||
"paddw %%xmm4,%%xmm3\n\t" \
|
||||
|
||||
/*Performs the last stage of the iDCT.
|
||||
On input, xmm7 down to xmm4 contain rows 0 through 3, and xmm0 up to xmm3
|
||||
contain rows 4 through 7.
|
||||
On output, xmm0 through xmm7 contain the corresponding rows.*/
|
||||
#define OC_IDCT_8x8_D_STORE \
|
||||
"#OC_IDCT_8x8_D_STORE\n\t" \
|
||||
/*Stage 4: \
|
||||
0-7 butterfly: xmm7=t[0], xmm0=t[7] -> xmm0=t[0]+t[7], xmm7=t[0]-t[7] \
|
||||
1-6 butterfly: xmm6=t[1], xmm1=t[6] -> xmm1=t[1]+t[6], xmm6=t[1]-t[6] \
|
||||
2-5 butterfly: xmm5=t[2], xmm2=t[5] -> xmm2=t[2]+t[5], xmm5=t[2]-t[5] \
|
||||
3-4 butterfly: xmm4=t[3], xmm3=t[4] -> xmm3=t[3]+t[4], xmm4=t[3]-t[4]*/ \
|
||||
"psubw %%xmm3,%%xmm4\n\t" \
|
||||
"movdqa %%xmm4,"OC_MEM_OFFS(0x40,y)"\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x00,c)",%%xmm4\n\t" \
|
||||
"psubw %%xmm0,%%xmm7\n\t" \
|
||||
"psubw %%xmm1,%%xmm6\n\t" \
|
||||
"psubw %%xmm2,%%xmm5\n\t" \
|
||||
"paddw %%xmm4,%%xmm7\n\t" \
|
||||
"paddw %%xmm4,%%xmm6\n\t" \
|
||||
"paddw %%xmm4,%%xmm5\n\t" \
|
||||
"paddw "OC_MEM_OFFS(0x40,y)",%%xmm4\n\t" \
|
||||
"paddw %%xmm0,%%xmm0\n\t" \
|
||||
"paddw %%xmm1,%%xmm1\n\t" \
|
||||
"paddw %%xmm2,%%xmm2\n\t" \
|
||||
"paddw %%xmm3,%%xmm3\n\t" \
|
||||
"paddw %%xmm7,%%xmm0\n\t" \
|
||||
"paddw %%xmm6,%%xmm1\n\t" \
|
||||
"psraw $4,%%xmm0\n\t" \
|
||||
"paddw %%xmm5,%%xmm2\n\t" \
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,y)"\n\t" \
|
||||
"psraw $4,%%xmm1\n\t" \
|
||||
"paddw %%xmm4,%%xmm3\n\t" \
|
||||
"movdqa %%xmm1,"OC_MEM_OFFS(0x10,y)"\n\t" \
|
||||
"psraw $4,%%xmm2\n\t" \
|
||||
"movdqa %%xmm2,"OC_MEM_OFFS(0x20,y)"\n\t" \
|
||||
"psraw $4,%%xmm3\n\t" \
|
||||
"movdqa %%xmm3,"OC_MEM_OFFS(0x30,y)"\n\t" \
|
||||
"psraw $4,%%xmm4\n\t" \
|
||||
"movdqa %%xmm4,"OC_MEM_OFFS(0x40,y)"\n\t" \
|
||||
"psraw $4,%%xmm5\n\t" \
|
||||
"movdqa %%xmm5,"OC_MEM_OFFS(0x50,y)"\n\t" \
|
||||
"psraw $4,%%xmm6\n\t" \
|
||||
"movdqa %%xmm6,"OC_MEM_OFFS(0x60,y)"\n\t" \
|
||||
"psraw $4,%%xmm7\n\t" \
|
||||
"movdqa %%xmm7,"OC_MEM_OFFS(0x70,y)"\n\t" \
|
||||
|
||||
static void oc_idct8x8_slow_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||
OC_ALIGN16(ogg_int16_t buf[16]);
|
||||
/*This routine accepts an 8x8 matrix pre-transposed.*/
|
||||
__asm__ __volatile__(
|
||||
/*Load rows 2, 3, 5, and 6 for the first stage of the iDCT.*/
|
||||
"movdqa "OC_MEM_OFFS(0x20,x)",%%xmm2\n\t"
|
||||
"movdqa "OC_MEM_OFFS(0x60,x)",%%xmm6\n\t"
|
||||
"movdqa "OC_MEM_OFFS(0x30,x)",%%xmm3\n\t"
|
||||
"movdqa "OC_MEM_OFFS(0x50,x)",%%xmm5\n\t"
|
||||
OC_IDCT_8x8_ABC(x)
|
||||
OC_IDCT_8x8_D
|
||||
OC_TRANSPOSE_8x8
|
||||
/*Clear out rows 0, 1, 4, and 7 for the first stage of the iDCT.*/
|
||||
"movdqa %%xmm7,"OC_MEM_OFFS(0x70,y)"\n\t"
|
||||
"movdqa %%xmm4,"OC_MEM_OFFS(0x40,y)"\n\t"
|
||||
"movdqa %%xmm1,"OC_MEM_OFFS(0x10,y)"\n\t"
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,y)"\n\t"
|
||||
OC_IDCT_8x8_ABC(y)
|
||||
OC_IDCT_8x8_D_STORE
|
||||
:[buf]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,buf,16)),
|
||||
[y]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,_y,64))
|
||||
:[x]"m"(OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64)),
|
||||
[c]"m"(OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128))
|
||||
);
|
||||
if(_x!=_y){
|
||||
int i;
|
||||
__asm__ __volatile__("pxor %%xmm0,%%xmm0\n\t"::);
|
||||
/*Clear input data for next block (decoder only).*/
|
||||
for(i=0;i<2;i++){
|
||||
__asm__ __volatile__(
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x20,x)"\n\t"
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x30,x)"\n\t"
|
||||
:[x]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,_x+i*32,32))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*For the first step of the 10-coefficient version of the 8x8 iDCT, we only
|
||||
need to work with four columns at a time.
|
||||
Doing this in MMX is faster on processors with a 64-bit data path.*/
|
||||
#define OC_IDCT_8x8_10_MMX \
|
||||
"#OC_IDCT_8x8_10_MMX\n\t" \
|
||||
/*Stage 1:*/ \
|
||||
/*2-3 rotation by 6pi/16. \
|
||||
mm7=C6, mm6=C2, mm2=X2, X6=0.*/ \
|
||||
"movq "OC_MEM_OFFS(0x60,c)",%%mm7\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x20,c)",%%mm6\n\t" \
|
||||
"pmulhw %%mm2,%%mm6\n\t" \
|
||||
"pmulhw %%mm2,%%mm7\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x50,c)",%%mm5\n\t" \
|
||||
"paddw %%mm6,%%mm2\n\t" \
|
||||
"movq %%mm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x30,c)",%%mm2\n\t" \
|
||||
"movq %%mm7,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||
/*5-6 rotation by 3pi/16. \
|
||||
mm5=C5, mm2=C3, mm3=X3, X5=0.*/ \
|
||||
"pmulhw %%mm3,%%mm5\n\t" \
|
||||
"pmulhw %%mm3,%%mm2\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x10,c)",%%mm7\n\t" \
|
||||
"paddw %%mm3,%%mm5\n\t" \
|
||||
"paddw %%mm3,%%mm2\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x70,c)",%%mm3\n\t" \
|
||||
/*4-7 rotation by 7pi/16. \
|
||||
mm7=C1, mm3=C7, mm1=X1, X7=0.*/ \
|
||||
"pmulhw %%mm1,%%mm3\n\t" \
|
||||
"pmulhw %%mm1,%%mm7\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x40,c)",%%mm4\n\t" \
|
||||
"movq %%mm3,%%mm6\n\t" \
|
||||
"paddw %%mm1,%%mm7\n\t" \
|
||||
/*0-1 butterfly. \
|
||||
mm4=C4, mm0=X0, X4=0.*/ \
|
||||
/*Stage 2:*/ \
|
||||
/*4-5 butterfly: mm3=t[4], mm5=t[5] \
|
||||
7-6 butterfly: mm2=t[6], mm7=t[7]*/ \
|
||||
"psubw %%mm5,%%mm3\n\t" \
|
||||
"paddw %%mm5,%%mm6\n\t" \
|
||||
"movq %%mm4,%%mm1\n\t" \
|
||||
"pmulhw %%mm0,%%mm4\n\t" \
|
||||
"paddw %%mm0,%%mm4\n\t" \
|
||||
"movq %%mm7,%%mm0\n\t" \
|
||||
"movq %%mm4,%%mm5\n\t" \
|
||||
"paddw %%mm2,%%mm0\n\t" \
|
||||
"psubw %%mm2,%%mm7\n\t" \
|
||||
"movq %%mm1,%%mm2\n\t" \
|
||||
"pmulhw %%mm6,%%mm1\n\t" \
|
||||
"pmulhw %%mm7,%%mm2\n\t" \
|
||||
"paddw %%mm6,%%mm1\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x00,buf)",%%mm6\n\t" \
|
||||
"paddw %%mm7,%%mm2\n\t" \
|
||||
"movq "OC_MEM_OFFS(0x10,buf)",%%mm7\n\t" \
|
||||
/*Stage 3: \
|
||||
6-5 butterfly: mm1=t[5], mm2=t[6] -> mm1=t[6]+t[5], mm2=t[6]-t[5] \
|
||||
0-3 butterfly: mm4=t[0], mm7=t[3] -> mm7=t[0]+t[3], mm4=t[0]-t[3] \
|
||||
1-2 butterfly: mm5=t[1], mm6=t[2] -> mm6=t[1]+t[2], mm5=t[1]-t[2]*/ \
|
||||
"paddw %%mm2,%%mm1\n\t" \
|
||||
"paddw %%mm5,%%mm6\n\t" \
|
||||
"paddw %%mm4,%%mm7\n\t" \
|
||||
"paddw %%mm2,%%mm2\n\t" \
|
||||
"paddw %%mm4,%%mm4\n\t" \
|
||||
"paddw %%mm5,%%mm5\n\t" \
|
||||
"psubw %%mm1,%%mm2\n\t" \
|
||||
"psubw %%mm7,%%mm4\n\t" \
|
||||
"psubw %%mm6,%%mm5\n\t" \
|
||||
/*Stage 4: \
|
||||
0-7 butterfly: mm7=t[0], mm0=t[7] -> mm0=t[0]+t[7], mm7=t[0]-t[7] \
|
||||
1-6 butterfly: mm6=t[1], mm1=t[6] -> mm1=t[1]+t[6], mm6=t[1]-t[6] \
|
||||
2-5 butterfly: mm5=t[2], mm2=t[5] -> mm2=t[2]+t[5], mm5=t[2]-t[5] \
|
||||
3-4 butterfly: mm4=t[3], mm3=t[4] -> mm3=t[3]+t[4], mm4=t[3]-t[4]*/ \
|
||||
"psubw %%mm0,%%mm7\n\t" \
|
||||
"psubw %%mm1,%%mm6\n\t" \
|
||||
"psubw %%mm2,%%mm5\n\t" \
|
||||
"psubw %%mm3,%%mm4\n\t" \
|
||||
"paddw %%mm0,%%mm0\n\t" \
|
||||
"paddw %%mm1,%%mm1\n\t" \
|
||||
"paddw %%mm2,%%mm2\n\t" \
|
||||
"paddw %%mm3,%%mm3\n\t" \
|
||||
"paddw %%mm7,%%mm0\n\t" \
|
||||
"paddw %%mm6,%%mm1\n\t" \
|
||||
"paddw %%mm5,%%mm2\n\t" \
|
||||
"paddw %%mm4,%%mm3\n\t" \
|
||||
|
||||
#define OC_IDCT_8x8_10_ABC \
|
||||
"#OC_IDCT_8x8_10_ABC\n\t" \
|
||||
/*Stage 1:*/ \
|
||||
/*2-3 rotation by 6pi/16. \
|
||||
xmm7=C6, xmm6=C2, xmm2=X2, X6=0.*/ \
|
||||
"movdqa "OC_MEM_OFFS(0x60,c)",%%xmm7\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x20,c)",%%xmm6\n\t" \
|
||||
"pmulhw %%xmm2,%%xmm6\n\t" \
|
||||
"pmulhw %%xmm2,%%xmm7\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x50,c)",%%xmm5\n\t" \
|
||||
"paddw %%xmm6,%%xmm2\n\t" \
|
||||
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x30,c)",%%xmm2\n\t" \
|
||||
"movdqa %%xmm7,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||
/*5-6 rotation by 3pi/16. \
|
||||
xmm5=C5, xmm2=C3, xmm3=X3, X5=0.*/ \
|
||||
"pmulhw %%xmm3,%%xmm5\n\t" \
|
||||
"pmulhw %%xmm3,%%xmm2\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x10,c)",%%xmm7\n\t" \
|
||||
"paddw %%xmm3,%%xmm5\n\t" \
|
||||
"paddw %%xmm3,%%xmm2\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x70,c)",%%xmm3\n\t" \
|
||||
/*4-7 rotation by 7pi/16. \
|
||||
xmm7=C1, xmm3=C7, xmm1=X1, X7=0.*/ \
|
||||
"pmulhw %%xmm1,%%xmm3\n\t" \
|
||||
"pmulhw %%xmm1,%%xmm7\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x40,c)",%%xmm4\n\t" \
|
||||
"movdqa %%xmm3,%%xmm6\n\t" \
|
||||
"paddw %%xmm1,%%xmm7\n\t" \
|
||||
/*0-1 butterfly. \
|
||||
xmm4=C4, xmm0=X0, X4=0.*/ \
|
||||
/*Stage 2:*/ \
|
||||
/*4-5 butterfly: xmm3=t[4], xmm5=t[5] \
|
||||
7-6 butterfly: xmm2=t[6], xmm7=t[7]*/ \
|
||||
"psubw %%xmm5,%%xmm3\n\t" \
|
||||
"paddw %%xmm5,%%xmm6\n\t" \
|
||||
"movdqa %%xmm4,%%xmm1\n\t" \
|
||||
"pmulhw %%xmm0,%%xmm4\n\t" \
|
||||
"paddw %%xmm0,%%xmm4\n\t" \
|
||||
"movdqa %%xmm7,%%xmm0\n\t" \
|
||||
"movdqa %%xmm4,%%xmm5\n\t" \
|
||||
"paddw %%xmm2,%%xmm0\n\t" \
|
||||
"psubw %%xmm2,%%xmm7\n\t" \
|
||||
"movdqa %%xmm1,%%xmm2\n\t" \
|
||||
"pmulhw %%xmm6,%%xmm1\n\t" \
|
||||
"pmulhw %%xmm7,%%xmm2\n\t" \
|
||||
"paddw %%xmm6,%%xmm1\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm6\n\t" \
|
||||
"paddw %%xmm7,%%xmm2\n\t" \
|
||||
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm7\n\t" \
|
||||
/*Stage 3: \
|
||||
6-5 butterfly: xmm1=t[5], xmm2=t[6] -> xmm1=t[6]+t[5], xmm2=t[6]-t[5] \
|
||||
0-3 butterfly: xmm4=t[0], xmm7=t[3] -> xmm7=t[0]+t[3], xmm4=t[0]-t[3] \
|
||||
1-2 butterfly: xmm5=t[1], xmm6=t[2] -> xmm6=t[1]+t[2], xmm5=t[1]-t[2]*/ \
|
||||
"paddw %%xmm2,%%xmm1\n\t" \
|
||||
"paddw %%xmm5,%%xmm6\n\t" \
|
||||
"paddw %%xmm4,%%xmm7\n\t" \
|
||||
"paddw %%xmm2,%%xmm2\n\t" \
|
||||
"paddw %%xmm4,%%xmm4\n\t" \
|
||||
"paddw %%xmm5,%%xmm5\n\t" \
|
||||
"psubw %%xmm1,%%xmm2\n\t" \
|
||||
"psubw %%xmm7,%%xmm4\n\t" \
|
||||
"psubw %%xmm6,%%xmm5\n\t" \
|
||||
|
||||
static void oc_idct8x8_10_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||
OC_ALIGN16(ogg_int16_t buf[16]);
|
||||
/*This routine accepts an 8x8 matrix pre-transposed.*/
|
||||
__asm__ __volatile__(
|
||||
"movq "OC_MEM_OFFS(0x20,x)",%%mm2\n\t"
|
||||
"movq "OC_MEM_OFFS(0x30,x)",%%mm3\n\t"
|
||||
"movq "OC_MEM_OFFS(0x10,x)",%%mm1\n\t"
|
||||
"movq "OC_MEM_OFFS(0x00,x)",%%mm0\n\t"
|
||||
OC_IDCT_8x8_10_MMX
|
||||
OC_TRANSPOSE_8x4_MMX2SSE
|
||||
OC_IDCT_8x8_10_ABC
|
||||
OC_IDCT_8x8_D_STORE
|
||||
:[buf]"=m"(OC_ARRAY_OPERAND(short,buf,16)),
|
||||
[y]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,_y,64))
|
||||
:[x]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64),
|
||||
[c]"m"(OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128))
|
||||
);
|
||||
if(_x!=_y){
|
||||
/*Clear input data for next block (decoder only).*/
|
||||
__asm__ __volatile__(
|
||||
"pxor %%mm0,%%mm0\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x20,x)"\n\t"
|
||||
"movq %%mm0,"OC_MEM_OFFS(0x30,x)"\n\t"
|
||||
:[x]"+m"(OC_ARRAY_OPERAND(ogg_int16_t,_x,28))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||
version of the transform.*/
|
||||
void oc_idct8x8_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi){
|
||||
/*_last_zzi is subtly different from an actual count of the number of
|
||||
coefficients we decoded for this block.
|
||||
It contains the value of zzi BEFORE the final token in the block was
|
||||
decoded.
|
||||
In most cases this is an EOB token (the continuation of an EOB run from a
|
||||
previous block counts), and so this is the same as the coefficient count.
|
||||
However, in the case that the last token was NOT an EOB token, but filled
|
||||
the block up with exactly 64 coefficients, _last_zzi will be less than 64.
|
||||
Provided the last token was not a pure zero run, the minimum value it can
|
||||
be is 46, and so that doesn't affect any of the cases in this routine.
|
||||
However, if the last token WAS a pure zero run of length 63, then _last_zzi
|
||||
will be 1 while the number of coefficients decoded is 64.
|
||||
Thus, we will trigger the following special case, where the real
|
||||
coefficient count would not.
|
||||
Note also that a zero run of length 64 will give _last_zzi a value of 0,
|
||||
but we still process the DC coefficient, which might have a non-zero value
|
||||
due to DC prediction.
|
||||
Although convoluted, this is arguably the correct behavior: it allows us to
|
||||
use a smaller transform when the block ends with a long zero run instead
|
||||
of a normal EOB token.
|
||||
It could be smarter... multiple separate zero runs at the end of a block
|
||||
will fool it, but an encoder that generates these really deserves what it
|
||||
gets.
|
||||
Needless to say we inherited this approach from VP3.*/
|
||||
/*Then perform the iDCT.*/
|
||||
if(_last_zzi<=10)oc_idct8x8_10_sse2(_y,_x);
|
||||
else oc_idct8x8_slow_sse2(_y,_x);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: sse2trans.h 15675 2009-02-06 09:43:27Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_x86_sse2trans_H)
|
||||
# define _x86_sse2trans_H (1)
|
||||
# include "../encint.h"
|
||||
# include "x86enc.h"
|
||||
|
||||
# if defined(OC_X86_64_ASM)
|
||||
/*On x86-64 we can transpose in-place without spilling registers.
|
||||
By clever choices of the order to apply the butterflies and the order of
|
||||
their outputs, we can take the rows in order and output the columns in order
|
||||
without any extra operations and using just one temporary register.*/
|
||||
# define OC_TRANSPOSE_8x8 \
|
||||
"#OC_TRANSPOSE_8x8\n\t" \
|
||||
"movdqa %%xmm4,%%xmm8\n\t" \
|
||||
/*xmm4 = f3 e3 f2 e2 f1 e1 f0 e0*/ \
|
||||
"punpcklwd %%xmm5,%%xmm4\n\t" \
|
||||
/*xmm8 = f7 e7 f6 e6 f5 e5 f4 e4*/ \
|
||||
"punpckhwd %%xmm5,%%xmm8\n\t" \
|
||||
/*xmm5 is free.*/ \
|
||||
"movdqa %%xmm0,%%xmm5\n\t" \
|
||||
/*xmm0 = b3 a3 b2 a2 b1 a1 b0 a0*/ \
|
||||
"punpcklwd %%xmm1,%%xmm0\n\t" \
|
||||
/*xmm5 = b7 a7 b6 a6 b5 a5 b4 a4*/ \
|
||||
"punpckhwd %%xmm1,%%xmm5\n\t" \
|
||||
/*xmm1 is free.*/ \
|
||||
"movdqa %%xmm6,%%xmm1\n\t" \
|
||||
/*xmm6 = h3 g3 h2 g2 h1 g1 h0 g0*/ \
|
||||
"punpcklwd %%xmm7,%%xmm6\n\t" \
|
||||
/*xmm1 = h7 g7 h6 g6 h5 g5 h4 g4*/ \
|
||||
"punpckhwd %%xmm7,%%xmm1\n\t" \
|
||||
/*xmm7 is free.*/ \
|
||||
"movdqa %%xmm2,%%xmm7\n\t" \
|
||||
/*xmm2 = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||
"punpckhwd %%xmm3,%%xmm2\n\t" \
|
||||
/*xmm7 = d3 c3 d2 c2 d1 c1 d0 c0*/ \
|
||||
"punpcklwd %%xmm3,%%xmm7\n\t" \
|
||||
/*xmm3 is free.*/ \
|
||||
"movdqa %%xmm0,%%xmm3\n\t" \
|
||||
/*xmm0 = d1 c1 b1 a1 d0 c0 b0 a0*/ \
|
||||
"punpckldq %%xmm7,%%xmm0\n\t" \
|
||||
/*xmm3 = d3 c3 b3 a3 d2 c2 b2 a2*/ \
|
||||
"punpckhdq %%xmm7,%%xmm3\n\t" \
|
||||
/*xmm7 is free.*/ \
|
||||
"movdqa %%xmm5,%%xmm7\n\t" \
|
||||
/*xmm5 = d5 c5 b5 a5 d4 c4 b4 a4*/ \
|
||||
"punpckldq %%xmm2,%%xmm5\n\t" \
|
||||
/*xmm7 = d7 c7 b7 a7 d6 c6 b6 a6*/ \
|
||||
"punpckhdq %%xmm2,%%xmm7\n\t" \
|
||||
/*xmm2 is free.*/ \
|
||||
"movdqa %%xmm4,%%xmm2\n\t" \
|
||||
/*xmm4 = h3 g3 f3 e3 h2 g2 f2 e2*/ \
|
||||
"punpckhdq %%xmm6,%%xmm4\n\t" \
|
||||
/*xmm2 = h1 g1 f1 e1 h0 g0 f0 e0*/ \
|
||||
"punpckldq %%xmm6,%%xmm2\n\t" \
|
||||
/*xmm6 is free.*/ \
|
||||
"movdqa %%xmm8,%%xmm6\n\t" \
|
||||
/*xmm6 = h5 g5 f5 e5 h4 g4 f4 e4*/ \
|
||||
"punpckldq %%xmm1,%%xmm6\n\t" \
|
||||
/*xmm8 = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||
"punpckhdq %%xmm1,%%xmm8\n\t" \
|
||||
/*xmm1 is free.*/ \
|
||||
"movdqa %%xmm0,%%xmm1\n\t" \
|
||||
/*xmm0 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||
"punpcklqdq %%xmm2,%%xmm0\n\t" \
|
||||
/*xmm1 = h1 g1 f1 e1 d1 c1 b1 a1*/ \
|
||||
"punpckhqdq %%xmm2,%%xmm1\n\t" \
|
||||
/*xmm2 is free.*/ \
|
||||
"movdqa %%xmm3,%%xmm2\n\t" \
|
||||
/*xmm3 = h3 g3 f3 e3 d3 c3 b3 a3*/ \
|
||||
"punpckhqdq %%xmm4,%%xmm3\n\t" \
|
||||
/*xmm2 = h2 g2 f2 e2 d2 c2 b2 a2*/ \
|
||||
"punpcklqdq %%xmm4,%%xmm2\n\t" \
|
||||
/*xmm4 is free.*/ \
|
||||
"movdqa %%xmm5,%%xmm4\n\t" \
|
||||
/*xmm5 = h5 g5 f5 e5 d5 c5 b5 a5*/ \
|
||||
"punpckhqdq %%xmm6,%%xmm5\n\t" \
|
||||
/*xmm4 = h4 g4 f4 e4 d4 c4 b4 a4*/ \
|
||||
"punpcklqdq %%xmm6,%%xmm4\n\t" \
|
||||
/*xmm6 is free.*/ \
|
||||
"movdqa %%xmm7,%%xmm6\n\t" \
|
||||
/*xmm7 = h7 g7 f7 e7 d7 c7 b7 a7*/ \
|
||||
"punpckhqdq %%xmm8,%%xmm7\n\t" \
|
||||
/*xmm6 = h6 g6 f6 e6 d6 c6 b6 a6*/ \
|
||||
"punpcklqdq %%xmm8,%%xmm6\n\t" \
|
||||
/*xmm8 is free.*/ \
|
||||
|
||||
# else
|
||||
/*Otherwise, we need to spill some values to %[buf] temporarily.
|
||||
Again, the butterflies are carefully arranged to get the columns to come out
|
||||
in order, minimizing register spills and maximizing the delay between a load
|
||||
and when the value loaded is actually used.*/
|
||||
# define OC_TRANSPOSE_8x8 \
|
||||
"#OC_TRANSPOSE_8x8\n\t" \
|
||||
/*buf[0] = a7 a6 a5 a4 a3 a2 a1 a0*/ \
|
||||
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||
/*xmm0 is free.*/ \
|
||||
"movdqa %%xmm2,%%xmm0\n\t" \
|
||||
/*xmm2 = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||
"punpckhwd %%xmm3,%%xmm2\n\t" \
|
||||
/*xmm0 = d3 c3 d2 c2 d1 c1 d0 c0*/ \
|
||||
"punpcklwd %%xmm3,%%xmm0\n\t" \
|
||||
/*xmm3 = a7 a6 a5 a4 a3 a2 a1 a0*/ \
|
||||
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm3\n\t" \
|
||||
/*buf[1] = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||
/*xmm2 is free.*/ \
|
||||
"movdqa %%xmm6,%%xmm2\n\t" \
|
||||
/*xmm6 = h3 g3 h2 g2 h1 g1 h0 g0*/ \
|
||||
"punpcklwd %%xmm7,%%xmm6\n\t" \
|
||||
/*xmm2 = h7 g7 h6 g6 h5 g5 h4 g4*/ \
|
||||
"punpckhwd %%xmm7,%%xmm2\n\t" \
|
||||
/*xmm7 is free.*/ \
|
||||
"movdqa %%xmm4,%%xmm7\n\t" \
|
||||
/*xmm4 = f3 e3 f2 e2 f1 e1 f0 e0*/ \
|
||||
"punpcklwd %%xmm5,%%xmm4\n\t" \
|
||||
/*xmm7 = f7 e7 f6 e6 f5 e5 f4 e4*/ \
|
||||
"punpckhwd %%xmm5,%%xmm7\n\t" \
|
||||
/*xmm5 is free.*/ \
|
||||
"movdqa %%xmm3,%%xmm5\n\t" \
|
||||
/*xmm3 = b3 a3 b2 a2 b1 a1 b0 a0*/ \
|
||||
"punpcklwd %%xmm1,%%xmm3\n\t" \
|
||||
/*xmm5 = b7 a7 b6 a6 b5 a5 b4 a4*/ \
|
||||
"punpckhwd %%xmm1,%%xmm5\n\t" \
|
||||
/*xmm1 is free.*/ \
|
||||
"movdqa %%xmm7,%%xmm1\n\t" \
|
||||
/*xmm7 = h5 g5 f5 e5 h4 g4 f4 e4*/ \
|
||||
"punpckldq %%xmm2,%%xmm7\n\t" \
|
||||
/*xmm1 = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||
"punpckhdq %%xmm2,%%xmm1\n\t" \
|
||||
/*xmm2 = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm2\n\t" \
|
||||
/*buf[0] = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||
"movdqa %%xmm1,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||
/*xmm1 is free.*/ \
|
||||
"movdqa %%xmm3,%%xmm1\n\t" \
|
||||
/*xmm3 = d3 c3 b3 a3 d2 c2 b2 a2*/ \
|
||||
"punpckhdq %%xmm0,%%xmm3\n\t" \
|
||||
/*xmm1 = d1 c1 b1 a1 d0 c0 b0 a0*/ \
|
||||
"punpckldq %%xmm0,%%xmm1\n\t" \
|
||||
/*xmm0 is free.*/ \
|
||||
"movdqa %%xmm4,%%xmm0\n\t" \
|
||||
/*xmm4 = h3 g3 f3 e3 h2 g2 f2 e2*/ \
|
||||
"punpckhdq %%xmm6,%%xmm4\n\t" \
|
||||
/*xmm0 = h1 g1 f1 e1 h0 g0 f0 e0*/ \
|
||||
"punpckldq %%xmm6,%%xmm0\n\t" \
|
||||
/*xmm6 is free.*/ \
|
||||
"movdqa %%xmm5,%%xmm6\n\t" \
|
||||
/*xmm5 = d5 c5 b5 a5 d4 c4 b4 a4*/ \
|
||||
"punpckldq %%xmm2,%%xmm5\n\t" \
|
||||
/*xmm6 = d7 c7 b7 a7 d6 c6 b6 a6*/ \
|
||||
"punpckhdq %%xmm2,%%xmm6\n\t" \
|
||||
/*xmm2 is free.*/ \
|
||||
"movdqa %%xmm1,%%xmm2\n\t" \
|
||||
/*xmm1 = h1 g1 f1 e1 d1 c1 b1 a1*/ \
|
||||
"punpckhqdq %%xmm0,%%xmm1\n\t" \
|
||||
/*xmm2 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||
"punpcklqdq %%xmm0,%%xmm2\n\t" \
|
||||
/*xmm0 = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm0\n\t" \
|
||||
/*buf[1] = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||
/*xmm2 is free.*/ \
|
||||
"movdqa %%xmm3,%%xmm2\n\t" \
|
||||
/*xmm3 = h3 g3 f3 e3 d3 c3 b3 a3*/ \
|
||||
"punpckhqdq %%xmm4,%%xmm3\n\t" \
|
||||
/*xmm2 = h2 g2 f2 e2 d2 c2 b2 a2*/ \
|
||||
"punpcklqdq %%xmm4,%%xmm2\n\t" \
|
||||
/*xmm4 is free.*/ \
|
||||
"movdqa %%xmm5,%%xmm4\n\t" \
|
||||
/*xmm5 = h5 g5 f5 e5 d5 c5 b5 a5*/ \
|
||||
"punpckhqdq %%xmm7,%%xmm5\n\t" \
|
||||
/*xmm4 = h4 g4 f4 e4 d4 c4 b4 a4*/ \
|
||||
"punpcklqdq %%xmm7,%%xmm4\n\t" \
|
||||
/*xmm7 is free.*/ \
|
||||
"movdqa %%xmm6,%%xmm7\n\t" \
|
||||
/*xmm6 = h6 g6 f6 e6 d6 c6 b6 a6*/ \
|
||||
"punpcklqdq %%xmm0,%%xmm6\n\t" \
|
||||
/*xmm7 = h7 g7 f7 e7 d7 c7 b7 a7*/ \
|
||||
"punpckhqdq %%xmm0,%%xmm7\n\t" \
|
||||
/*xmm0 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm0\n\t" \
|
||||
|
||||
# endif
|
||||
|
||||
/*Transpose 4 values in each of 8 MMX registers into 8 values in the first
|
||||
four SSE registers.
|
||||
No need to be clever here; we have plenty of room.*/
|
||||
# define OC_TRANSPOSE_8x4_MMX2SSE \
|
||||
"#OC_TRANSPOSE_8x4_MMX2SSE\n\t" \
|
||||
"movq2dq %%mm0,%%xmm0\n\t" \
|
||||
"movq2dq %%mm1,%%xmm1\n\t" \
|
||||
/*xmmA = b3 a3 b2 a2 b1 a1 b0 a0*/ \
|
||||
"punpcklwd %%xmm1,%%xmm0\n\t" \
|
||||
"movq2dq %%mm2,%%xmm3\n\t" \
|
||||
"movq2dq %%mm3,%%xmm2\n\t" \
|
||||
/*xmmC = d3 c3 d2 c2 d1 c1 d0 c0*/ \
|
||||
"punpcklwd %%xmm2,%%xmm3\n\t" \
|
||||
"movq2dq %%mm4,%%xmm4\n\t" \
|
||||
"movq2dq %%mm5,%%xmm5\n\t" \
|
||||
/*xmmE = f3 e3 f2 e2 f1 e1 f0 e0*/ \
|
||||
"punpcklwd %%xmm5,%%xmm4\n\t" \
|
||||
"movq2dq %%mm6,%%xmm7\n\t" \
|
||||
"movq2dq %%mm7,%%xmm6\n\t" \
|
||||
/*xmmG = h3 g3 h2 g2 h1 g1 h0 g0*/ \
|
||||
"punpcklwd %%xmm6,%%xmm7\n\t" \
|
||||
"movdqa %%xmm0,%%xmm2\n\t" \
|
||||
/*xmm0 = d1 c1 b1 a1 d0 c0 b0 a0*/ \
|
||||
"punpckldq %%xmm3,%%xmm0\n\t" \
|
||||
/*xmm2 = d3 c3 b3 a3 d2 c2 b2 a2*/ \
|
||||
"punpckhdq %%xmm3,%%xmm2\n\t" \
|
||||
"movdqa %%xmm4,%%xmm5\n\t" \
|
||||
/*xmm4 = h1 g1 f1 e1 h0 g0 f0 e0*/ \
|
||||
"punpckldq %%xmm7,%%xmm4\n\t" \
|
||||
/*xmm3 = h3 g3 f3 e3 h2 g2 f2 e2*/ \
|
||||
"punpckhdq %%xmm7,%%xmm5\n\t" \
|
||||
"movdqa %%xmm0,%%xmm1\n\t" \
|
||||
/*xmm0 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||
"punpcklqdq %%xmm4,%%xmm0\n\t" \
|
||||
/*xmm1 = h1 g1 f1 e1 d1 c1 b1 a1*/ \
|
||||
"punpckhqdq %%xmm4,%%xmm1\n\t" \
|
||||
"movdqa %%xmm2,%%xmm3\n\t" \
|
||||
/*xmm2 = h2 g2 f2 e2 d2 c2 b2 a2*/ \
|
||||
"punpcklqdq %%xmm5,%%xmm2\n\t" \
|
||||
/*xmm3 = h3 g3 f3 e3 d3 c3 b3 a3*/ \
|
||||
"punpckhqdq %%xmm5,%%xmm3\n\t" \
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,182 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
CPU capability detection for x86 processors.
|
||||
Originally written by Rudolf Marek.
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include "x86cpu.h"
|
||||
|
||||
#if !defined(OC_X86_ASM)
|
||||
ogg_uint32_t oc_cpu_flags_get(void){
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
# if defined(__amd64__)||defined(__x86_64__)
|
||||
/*On x86-64, gcc seems to be able to figure out how to save %rbx for us when
|
||||
compiling with -fPIC.*/
|
||||
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||
__asm__ __volatile__( \
|
||||
"cpuid\n\t" \
|
||||
:[eax]"=a"(_eax),[ebx]"=b"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
|
||||
:"a"(_op) \
|
||||
:"cc" \
|
||||
)
|
||||
# else
|
||||
/*On x86-32, not so much.*/
|
||||
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||
__asm__ __volatile__( \
|
||||
"xchgl %%ebx,%[ebx]\n\t" \
|
||||
"cpuid\n\t" \
|
||||
"xchgl %%ebx,%[ebx]\n\t" \
|
||||
:[eax]"=a"(_eax),[ebx]"=r"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
|
||||
:"a"(_op) \
|
||||
:"cc" \
|
||||
)
|
||||
# endif
|
||||
|
||||
static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||
ogg_uint32_t flags;
|
||||
/*If there isn't even MMX, give up.*/
|
||||
if(!(_edx&0x00800000))return 0;
|
||||
flags=OC_CPU_X86_MMX;
|
||||
if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;
|
||||
if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;
|
||||
if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;
|
||||
if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;
|
||||
if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;
|
||||
if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||
ogg_uint32_t flags;
|
||||
/*If there isn't even MMX, give up.*/
|
||||
if(!(_edx&0x00800000))return 0;
|
||||
flags=OC_CPU_X86_MMX;
|
||||
if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;
|
||||
if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;
|
||||
if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;
|
||||
if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;
|
||||
if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;
|
||||
return flags;
|
||||
}
|
||||
|
||||
ogg_uint32_t oc_cpu_flags_get(void){
|
||||
ogg_uint32_t flags;
|
||||
ogg_uint32_t eax;
|
||||
ogg_uint32_t ebx;
|
||||
ogg_uint32_t ecx;
|
||||
ogg_uint32_t edx;
|
||||
# if !defined(__amd64__)&&!defined(__x86_64__)
|
||||
/*Not all x86-32 chips support cpuid, so we have to check.*/
|
||||
__asm__ __volatile__(
|
||||
"pushfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %[a]\n\t"
|
||||
"movl %[a],%[b]\n\t"
|
||||
"xorl $0x200000,%[a]\n\t"
|
||||
"pushl %[a]\n\t"
|
||||
"popfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %[a]\n\t"
|
||||
"popfl\n\t"
|
||||
:[a]"=r"(eax),[b]"=r"(ebx)
|
||||
:
|
||||
:"cc"
|
||||
);
|
||||
/*No cpuid.*/
|
||||
if(eax==ebx)return 0;
|
||||
# endif
|
||||
cpuid(0,eax,ebx,ecx,edx);
|
||||
/* l e t n I e n i u n e G*/
|
||||
if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547||
|
||||
/* 6 8 x M T e n i u n e G*/
|
||||
ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){
|
||||
int family;
|
||||
int model;
|
||||
/*Intel, Transmeta (tested with Crusoe TM5800):*/
|
||||
cpuid(1,eax,ebx,ecx,edx);
|
||||
flags=oc_parse_intel_flags(edx,ecx);
|
||||
family=(eax>>8)&0xF;
|
||||
model=(eax>>4)&0xF;
|
||||
/*The SSE unit on the Pentium M and Core Duo is much slower than the MMX
|
||||
unit, so don't use it.*/
|
||||
if(family==6&&(model==9||model==13||model==14)){
|
||||
flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI);
|
||||
}
|
||||
}
|
||||
/* D M A c i t n e h t u A*/
|
||||
else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541||
|
||||
/* C S N y b e d o e G*/
|
||||
ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){
|
||||
/*AMD, Geode:*/
|
||||
cpuid(0x80000000,eax,ebx,ecx,edx);
|
||||
if(eax<0x80000001)flags=0;
|
||||
else{
|
||||
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||
flags=oc_parse_amd_flags(edx,ecx);
|
||||
}
|
||||
/*Also check for SSE.*/
|
||||
cpuid(1,eax,ebx,ecx,edx);
|
||||
flags|=oc_parse_intel_flags(edx,ecx);
|
||||
}
|
||||
/*Technically some VIA chips can be configured in the BIOS to return any
|
||||
string here the user wants.
|
||||
There is a special detection method that can be used to identify such
|
||||
processors, but in my opinion, if the user really wants to change it, they
|
||||
deserve what they get.*/
|
||||
/* s l u a H r u a t n e C*/
|
||||
else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){
|
||||
/*VIA:*/
|
||||
/*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)
|
||||
chips (thanks to the engineers from Centaur Technology who provided it).
|
||||
These chips support Intel-like cpuid info.
|
||||
The C3-2 (Nehemiah) cores appear to, as well.*/
|
||||
cpuid(1,eax,ebx,ecx,edx);
|
||||
flags=oc_parse_intel_flags(edx,ecx);
|
||||
if(eax>=0x80000001){
|
||||
/*The (non-Nehemiah) C3 processors support AMD-like cpuid info.
|
||||
We need to check this even if the Intel test succeeds to pick up 3DNow!
|
||||
support on these processors.
|
||||
Unlike actual AMD processors, we cannot _rely_ on this info, since
|
||||
some cores (e.g., the 693 stepping of the Nehemiah) claim to support
|
||||
this function, yet return edx=0, despite the Intel test indicating
|
||||
MMX support.
|
||||
Therefore the features detected here are strictly added to those
|
||||
detected by the Intel test.*/
|
||||
/*TODO: How about earlier chips?*/
|
||||
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||
/*Note: As of the C7, this function returns Intel-style extended feature
|
||||
flags, not AMD-style.
|
||||
Currently, this only defines bits 11, 20, and 29 (0x20100800), which
|
||||
do not conflict with any of the AMD flags we inspect.
|
||||
For the remaining bits, Intel tells us, "Do not count on their value",
|
||||
but VIA assures us that they will all be zero (at least on the C7 and
|
||||
Isaiah chips).
|
||||
In the (unlikely) event a future processor uses bits 18, 19, 30, or 31
|
||||
(0xC0C00000) for something else, we will have to add code to detect
|
||||
the model to decide when it is appropriate to inspect them.*/
|
||||
flags|=oc_parse_amd_flags(edx,ecx);
|
||||
}
|
||||
}
|
||||
else{
|
||||
/*Implement me.*/
|
||||
flags=0;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_x86_x86cpu_H)
|
||||
# define _x86_x86cpu_H (1)
|
||||
#include "../internal.h"
|
||||
|
||||
#define OC_CPU_X86_MMX (1<<0)
|
||||
#define OC_CPU_X86_3DNOW (1<<1)
|
||||
#define OC_CPU_X86_3DNOWEXT (1<<2)
|
||||
#define OC_CPU_X86_MMXEXT (1<<3)
|
||||
#define OC_CPU_X86_SSE (1<<4)
|
||||
#define OC_CPU_X86_SSE2 (1<<5)
|
||||
#define OC_CPU_X86_PNI (1<<6)
|
||||
#define OC_CPU_X86_SSSE3 (1<<7)
|
||||
#define OC_CPU_X86_SSE4_1 (1<<8)
|
||||
#define OC_CPU_X86_SSE4_2 (1<<9)
|
||||
#define OC_CPU_X86_SSE4A (1<<10)
|
||||
#define OC_CPU_X86_SSE5 (1<<11)
|
||||
|
||||
ogg_uint32_t oc_cpu_flags_get(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: x86state.c 15675 2009-02-06 09:43:27Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
#include "x86enc.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
void oc_enc_accel_init_x86(oc_enc_ctx *_enc){
|
||||
ogg_uint32_t cpu_flags;
|
||||
cpu_flags=_enc->state.cpu_flags;
|
||||
oc_enc_accel_init_c(_enc);
|
||||
# if defined(OC_ENC_USE_VTABLE)
|
||||
if(cpu_flags&OC_CPU_X86_MMX){
|
||||
_enc->opt_vtable.frag_sub=oc_enc_frag_sub_mmx;
|
||||
_enc->opt_vtable.frag_sub_128=oc_enc_frag_sub_128_mmx;
|
||||
_enc->opt_vtable.frag_recon_intra=oc_frag_recon_intra_mmx;
|
||||
_enc->opt_vtable.frag_recon_inter=oc_frag_recon_inter_mmx;
|
||||
_enc->opt_vtable.fdct8x8=oc_enc_fdct8x8_mmx;
|
||||
}
|
||||
if(cpu_flags&OC_CPU_X86_MMXEXT){
|
||||
_enc->opt_vtable.frag_sad=oc_enc_frag_sad_mmxext;
|
||||
_enc->opt_vtable.frag_sad_thresh=oc_enc_frag_sad_thresh_mmxext;
|
||||
_enc->opt_vtable.frag_sad2_thresh=oc_enc_frag_sad2_thresh_mmxext;
|
||||
_enc->opt_vtable.frag_satd=oc_enc_frag_satd_mmxext;
|
||||
_enc->opt_vtable.frag_satd2=oc_enc_frag_satd2_mmxext;
|
||||
_enc->opt_vtable.frag_intra_satd=oc_enc_frag_intra_satd_mmxext;
|
||||
_enc->opt_vtable.frag_copy2=oc_enc_frag_copy2_mmxext;
|
||||
}
|
||||
if(cpu_flags&OC_CPU_X86_SSE2){
|
||||
# if defined(OC_X86_64_ASM)
|
||||
_enc->opt_vtable.fdct8x8=oc_enc_fdct8x8_x86_64sse2;
|
||||
# endif
|
||||
_enc->opt_vtable.frag_ssd=oc_enc_frag_ssd_sse2;
|
||||
_enc->opt_vtable.frag_border_ssd=oc_enc_frag_border_ssd_sse2;
|
||||
_enc->opt_vtable.frag_satd=oc_enc_frag_satd_sse2;
|
||||
_enc->opt_vtable.frag_satd2=oc_enc_frag_satd2_sse2;
|
||||
_enc->opt_vtable.frag_intra_satd=oc_enc_frag_intra_satd_sse2;
|
||||
_enc->opt_vtable.enquant_table_init=oc_enc_enquant_table_init_x86;
|
||||
_enc->opt_vtable.enquant_table_fixup=oc_enc_enquant_table_fixup_x86;
|
||||
_enc->opt_vtable.quantize=oc_enc_quantize_sse2;
|
||||
# endif
|
||||
_enc->opt_data.enquant_table_size=128*sizeof(ogg_uint16_t);
|
||||
_enc->opt_data.enquant_table_alignment=16;
|
||||
# if defined(OC_ENC_USE_VTABLE)
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: x86int.h 15675 2009-02-06 09:43:27Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_x86_x86enc_H)
|
||||
# define _x86_x86enc_H (1)
|
||||
# include "x86int.h"
|
||||
|
||||
# if defined(OC_X86_ASM)
|
||||
# define oc_enc_accel_init oc_enc_accel_init_x86
|
||||
# if defined(OC_X86_64_ASM)
|
||||
/*x86-64 guarantees SIMD support up through at least SSE2.
|
||||
If the best routine we have available only needs SSE2 (which at the moment
|
||||
covers all of them), then we can avoid runtime detection and the indirect
|
||||
call.*/
|
||||
# define oc_enc_frag_sub(_enc,_diff,_x,_y,_stride) \
|
||||
oc_enc_frag_sub_mmx(_diff,_x,_y,_stride)
|
||||
# define oc_enc_frag_sub_128(_enc,_diff,_x,_stride) \
|
||||
oc_enc_frag_sub_128_mmx(_diff,_x,_stride)
|
||||
# define oc_enc_frag_sad(_enc,_src,_ref,_ystride) \
|
||||
oc_enc_frag_sad_mmxext(_src,_ref,_ystride)
|
||||
# define oc_enc_frag_sad_thresh(_enc,_src,_ref,_ystride,_thresh) \
|
||||
oc_enc_frag_sad_thresh_mmxext(_src,_ref,_ystride,_thresh)
|
||||
# define oc_enc_frag_sad2_thresh(_enc,_src,_ref1,_ref2,_ystride,_thresh) \
|
||||
oc_enc_frag_sad2_thresh_mmxext(_src,_ref1,_ref2,_ystride,_thresh)
|
||||
# define oc_enc_frag_satd(_enc,_dc,_src,_ref,_ystride) \
|
||||
oc_enc_frag_satd_sse2(_dc,_src,_ref,_ystride)
|
||||
# define oc_enc_frag_satd2(_enc,_dc,_src,_ref1,_ref2,_ystride) \
|
||||
oc_enc_frag_satd2_sse2(_dc,_src,_ref1,_ref2,_ystride)
|
||||
# define oc_enc_frag_intra_satd(_enc,_dc,_src,_ystride) \
|
||||
oc_enc_frag_intra_satd_sse2(_dc,_src,_ystride)
|
||||
# define oc_enc_frag_ssd(_enc,_src,_ref,_ystride) \
|
||||
oc_enc_frag_ssd_sse2(_src,_ref,_ystride)
|
||||
# define oc_enc_frag_border_ssd(_enc,_src,_ref,_ystride,_mask) \
|
||||
oc_enc_frag_border_ssd_sse2(_src,_ref,_ystride,_mask)
|
||||
# define oc_enc_frag_copy2(_enc,_dst,_src1,_src2,_ystride) \
|
||||
oc_int_frag_copy2_mmxext(_dst,_ystride,_src1,_src2,_ystride)
|
||||
# define oc_enc_enquant_table_init(_enc,_enquant,_dequant) \
|
||||
oc_enc_enquant_table_init_x86(_enquant,_dequant)
|
||||
# define oc_enc_enquant_table_fixup(_enc,_enquant,_nqis) \
|
||||
oc_enc_enquant_table_fixup_x86(_enquant,_nqis)
|
||||
# define oc_enc_quantize(_enc,_qdct,_dct,_dequant,_enquant) \
|
||||
oc_enc_quantize_sse2(_qdct,_dct,_dequant,_enquant)
|
||||
# define oc_enc_frag_recon_intra(_enc,_dst,_ystride,_residue) \
|
||||
oc_frag_recon_intra_mmx(_dst,_ystride,_residue)
|
||||
# define oc_enc_frag_recon_inter(_enc,_dst,_src,_ystride,_residue) \
|
||||
oc_frag_recon_inter_mmx(_dst,_src,_ystride,_residue)
|
||||
# define oc_enc_fdct8x8(_enc,_y,_x) \
|
||||
oc_enc_fdct8x8_x86_64sse2(_y,_x)
|
||||
# else
|
||||
# define OC_ENC_USE_VTABLE (1)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# include "../encint.h"
|
||||
|
||||
void oc_enc_accel_init_x86(oc_enc_ctx *_enc);
|
||||
|
||||
void oc_enc_frag_sub_mmx(ogg_int16_t _diff[64],
|
||||
const unsigned char *_x,const unsigned char *_y,int _stride);
|
||||
void oc_enc_frag_sub_128_mmx(ogg_int16_t _diff[64],
|
||||
const unsigned char *_x,int _stride);
|
||||
unsigned oc_enc_frag_sad_mmxext(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_sad_thresh_mmxext(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,unsigned _thresh);
|
||||
unsigned oc_enc_frag_sad2_thresh_mmxext(const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride,
|
||||
unsigned _thresh);
|
||||
unsigned oc_enc_frag_satd_mmxext(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_satd_sse2(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_satd2_mmxext(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride);
|
||||
unsigned oc_enc_frag_satd2_sse2(unsigned *_dc,const unsigned char *_src,
|
||||
const unsigned char *_ref1,const unsigned char *_ref2,int _ystride);
|
||||
unsigned oc_enc_frag_intra_satd_mmxext(unsigned *_dc,
|
||||
const unsigned char *_src,int _ystride);
|
||||
unsigned oc_enc_frag_intra_satd_sse2(unsigned *_dc,
|
||||
const unsigned char *_src,int _ystride);
|
||||
unsigned oc_enc_frag_ssd_sse2(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride);
|
||||
unsigned oc_enc_frag_border_ssd_sse2(const unsigned char *_src,
|
||||
const unsigned char *_ref,int _ystride,ogg_int64_t _mask);
|
||||
void oc_int_frag_copy2_mmxext(unsigned char *_dst,int _dst_ystride,
|
||||
const unsigned char *_src1,const unsigned char *_src2,int _src_ystride);
|
||||
void oc_enc_frag_copy2_mmxext(unsigned char *_dst,
|
||||
const unsigned char *_src1,const unsigned char *_src2,int _ystride);
|
||||
void oc_enc_enquant_table_init_x86(void *_enquant,
|
||||
const ogg_uint16_t _dequant[64]);
|
||||
void oc_enc_enquant_table_fixup_x86(void *_enquant[3][3][2],int _nqis);
|
||||
int oc_enc_quantize_sse2(ogg_int16_t _qdct[64],const ogg_int16_t _dct[64],
|
||||
const ogg_uint16_t _dequant[64],const void *_enquant);
|
||||
void oc_enc_fdct8x8_mmx(ogg_int16_t _y[64],const ogg_int16_t _x[64]);
|
||||
|
||||
# if defined(OC_X86_64_ASM)
|
||||
void oc_enc_fdct8x8_x86_64sse2(ogg_int16_t _y[64],const ogg_int16_t _x[64]);
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id: mmxstate.c 17247 2010-05-28 05:35:32Z tterribe $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include "x86enc.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
|
||||
|
||||
/*The default enquant table is not quite suitable for SIMD purposes.
|
||||
First, the m and l parameters need to be separated so that an entire row full
|
||||
of m's or l's can be loaded at a time.
|
||||
Second, x86 SIMD has no element-wise arithmetic right-shift, so we have to
|
||||
emulate one with a multiply.
|
||||
Therefore we translate the shift count into a scale factor.*/
|
||||
void oc_enc_enquant_table_init_x86(void *_enquant,
|
||||
const ogg_uint16_t _dequant[64]){
|
||||
ogg_int16_t *m;
|
||||
ogg_int16_t *l;
|
||||
int zzi;
|
||||
m=(ogg_int16_t *)_enquant;
|
||||
l=m+64;
|
||||
for(zzi=0;zzi<64;zzi++){
|
||||
oc_iquant q;
|
||||
oc_iquant_init(&q,_dequant[zzi]);
|
||||
m[zzi]=q.m;
|
||||
/*q.l must be at least 2 for this to work; fortunately, once all the scale
|
||||
factors are baked in, the minimum quantizer is much larger than that.*/
|
||||
l[zzi]=1<<16-q.l;
|
||||
}
|
||||
}
|
||||
|
||||
void oc_enc_enquant_table_fixup_x86(void *_enquant[3][3][2],int _nqis){
|
||||
int pli;
|
||||
int qii;
|
||||
int qti;
|
||||
for(pli=0;pli<3;pli++)for(qii=1;qii<_nqis;qii++)for(qti=0;qti<2;qti++){
|
||||
((ogg_int16_t *)_enquant[pli][qii][qti])[0]=
|
||||
((ogg_int16_t *)_enquant[pli][0][qti])[0];
|
||||
((ogg_int16_t *)_enquant[pli][qii][qti])[64]=
|
||||
((ogg_int16_t *)_enquant[pli][0][qti])[64];
|
||||
}
|
||||
}
|
||||
|
||||
/*Convert DCT coefficients in %[dct] from natural order into zig-zag scan order
|
||||
and store them in %[qdct].
|
||||
The index of each output element in the original 64-element array should wind
|
||||
up in the following 8x8 matrix (the letters indicate the order we compute
|
||||
each 4-tuple below):
|
||||
A 0 1 8 16 9 2 3 10 B
|
||||
C 17 24 32 25 18 11 4 5 D
|
||||
E 12 19 26 33 40 48 41 34 I
|
||||
H 27 20 13 6 7 14 21 28 G
|
||||
K 35 42 49 56 57 50 43 36 J
|
||||
F 29 22 15 23 30 37 44 51 M
|
||||
P 58 59 52 45 38 31 39 46 L
|
||||
N 53 60 61 54 47 55 62 63 O
|
||||
The order of the coefficients within each tuple is reversed in the comments
|
||||
below to reflect the usual MSB to LSB notation.*/
|
||||
#define OC_ZIG_ZAG_MMXEXT \
|
||||
"movq 0x00(%[dct]),%%mm0\n\t" /*mm0=03 02 01 00*/ \
|
||||
"movq 0x08(%[dct]),%%mm1\n\t" /*mm1=07 06 05 04*/ \
|
||||
"movq 0x10(%[dct]),%%mm2\n\t" /*mm2=11 10 09 08*/ \
|
||||
"movq 0x20(%[dct]),%%mm3\n\t" /*mm3=19 18 17 16*/ \
|
||||
"movq 0x30(%[dct]),%%mm4\n\t" /*mm4=27 26 25 24*/ \
|
||||
"movq 0x40(%[dct]),%%mm5\n\t" /*mm5=35 34 33 32*/ \
|
||||
"movq %%mm2,%%mm7\n\t" /*mm7=11 10 09 08*/ \
|
||||
"punpcklwd %%mm3,%%mm2\n\t" /*mm2=17 09 16 08*/ \
|
||||
"movq %%mm0,%%mm6\n\t" /*mm6=03 02 01 00*/ \
|
||||
"punpckldq %%mm2,%%mm0\n\t" /*mm0=16 08 01 00 *A*/ \
|
||||
"movq %%mm0,0x00(%[qdct])\n\t" \
|
||||
"movq 0x18(%[dct]),%%mm0\n\t" /*mm0=15 14 13 12*/ \
|
||||
"punpckhdq %%mm6,%%mm6\n\t" /*mm6=03 02 03 02*/ \
|
||||
"psrlq $16,%%mm7\n\t" /*mm7=.. 11 10 09*/ \
|
||||
"punpckldq %%mm7,%%mm6\n\t" /*mm6=10 09 03 02*/ \
|
||||
"punpckhwd %%mm7,%%mm3\n\t" /*mm3=.. 19 11 18*/ \
|
||||
"pshufw $0xD2,%%mm6,%%mm6\n\t" /*mm6=10 03 02 09 *B*/ \
|
||||
"movq %%mm6,0x08(%[qdct])\n\t" \
|
||||
"psrlq $48,%%mm2\n\t" /*mm2=.. .. .. 17*/ \
|
||||
"movq %%mm1,%%mm6\n\t" /*mm6=07 06 05 04*/ \
|
||||
"punpcklwd %%mm5,%%mm2\n\t" /*mm2=33 .. 32 17*/ \
|
||||
"movq %%mm3,%%mm7\n\t" /*mm7=.. 19 11 18*/ \
|
||||
"punpckldq %%mm1,%%mm3\n\t" /*mm3=05 04 11 18 *C*/ \
|
||||
"por %%mm2,%%mm7\n\t" /*mm7=33 19 ?? ??*/ \
|
||||
"punpcklwd %%mm4,%%mm2\n\t" /*mm2=25 32 24 17 *D**/ \
|
||||
"movq %%mm2,0x10(%[qdct])\n\t" \
|
||||
"movq %%mm3,0x18(%[qdct])\n\t" \
|
||||
"movq 0x28(%[dct]),%%mm2\n\t" /*mm2=23 22 21 20*/ \
|
||||
"movq 0x38(%[dct]),%%mm1\n\t" /*mm1=31 30 29 28*/ \
|
||||
"pshufw $0x9C,%%mm0,%%mm3\n\t" /*mm3=14 13 15 12*/ \
|
||||
"punpckhdq %%mm7,%%mm7\n\t" /*mm7=33 19 33 19*/ \
|
||||
"punpckhwd %%mm3,%%mm6\n\t" /*mm6=14 07 13 06*/ \
|
||||
"punpckldq %%mm0,%%mm0\n\t" /*mm0=13 12 13 12*/ \
|
||||
"punpcklwd %%mm1,%%mm3\n\t" /*mm3=29 15 28 12*/ \
|
||||
"punpckhwd %%mm4,%%mm0\n\t" /*mm0=27 13 26 12*/ \
|
||||
"pshufw $0xB4,%%mm3,%%mm3\n\t" /*mm3=15 29 28 12*/ \
|
||||
"psrlq $48,%%mm4\n\t" /*mm4=.. .. .. 27*/ \
|
||||
"punpcklwd %%mm7,%%mm0\n\t" /*mm0=33 26 19 12 *E*/ \
|
||||
"punpcklwd %%mm1,%%mm4\n\t" /*mm4=29 .. 28 27*/ \
|
||||
"punpckhwd %%mm2,%%mm3\n\t" /*mm3=23 15 22 29 *F*/ \
|
||||
"movq %%mm0,0x20(%[qdct])\n\t" \
|
||||
"movq %%mm3,0x50(%[qdct])\n\t" \
|
||||
"movq 0x60(%[dct]),%%mm3\n\t" /*mm3=51 50 49 48*/ \
|
||||
"movq 0x70(%[dct]),%%mm7\n\t" /*mm7=59 58 57 56*/ \
|
||||
"movq 0x50(%[dct]),%%mm0\n\t" /*mm0=43 42 41 40*/ \
|
||||
"punpcklwd %%mm4,%%mm2\n\t" /*mm2=28 21 27 20*/ \
|
||||
"psrlq $32,%%mm5\n\t" /*mm5=.. .. 35 34*/ \
|
||||
"movq %%mm2,%%mm4\n\t" /*mm4=28 21 27 20*/ \
|
||||
"punpckldq %%mm6,%%mm2\n\t" /*mm2=13 06 27 20*/ \
|
||||
"punpckhdq %%mm4,%%mm6\n\t" /*mm6=28 21 14 07 *G*/ \
|
||||
"movq %%mm3,%%mm4\n\t" /*mm4=51 50 49 48*/ \
|
||||
"pshufw $0xB1,%%mm2,%%mm2\n\t" /*mm2=06 13 20 27 *H*/ \
|
||||
"movq %%mm2,0x30(%[qdct])\n\t" \
|
||||
"movq %%mm6,0x38(%[qdct])\n\t" \
|
||||
"movq 0x48(%[dct]),%%mm2\n\t" /*mm2=39 38 37 36*/ \
|
||||
"punpcklwd %%mm5,%%mm4\n\t" /*mm4=35 49 34 48*/ \
|
||||
"movq 0x58(%[dct]),%%mm5\n\t" /*mm5=47 46 45 44*/ \
|
||||
"punpckldq %%mm7,%%mm6\n\t" /*mm6=57 56 14 07*/ \
|
||||
"psrlq $32,%%mm3\n\t" /*mm3=.. .. 51 50*/ \
|
||||
"punpckhwd %%mm0,%%mm6\n\t" /*mm6=43 57 42 56*/ \
|
||||
"punpcklwd %%mm4,%%mm0\n\t" /*mm0=34 41 48 40 *I*/ \
|
||||
"pshufw $0x4E,%%mm6,%%mm6\n\t" /*mm6=42 56 43 57*/ \
|
||||
"movq %%mm0,0x28(%[qdct])\n\t" \
|
||||
"punpcklwd %%mm2,%%mm3\n\t" /*mm3=37 51 36 50*/ \
|
||||
"punpckhwd %%mm6,%%mm4\n\t" /*mm4=42 35 56 49*/ \
|
||||
"punpcklwd %%mm3,%%mm6\n\t" /*mm6=36 43 50 57 *J*/ \
|
||||
"pshufw $0x4E,%%mm4,%%mm4\n\t" /*mm4=56 49 42 35 *K*/ \
|
||||
"movq %%mm4,0x40(%[qdct])\n\t" \
|
||||
"movq %%mm6,0x48(%[qdct])\n\t" \
|
||||
"movq 0x68(%[dct]),%%mm6\n\t" /*mm6=55 54 53 52*/ \
|
||||
"movq 0x78(%[dct]),%%mm0\n\t" /*mm0=63 62 61 60*/ \
|
||||
"psrlq $32,%%mm1\n\t" /*mm1=.. .. 31 30*/ \
|
||||
"pshufw $0xD8,%%mm5,%%mm5\n\t" /*mm5=47 45 46 44*/ \
|
||||
"pshufw $0x0B,%%mm3,%%mm3\n\t" /*mm3=50 50 51 37*/ \
|
||||
"punpcklwd %%mm5,%%mm1\n\t" /*mm1=46 31 44 30*/ \
|
||||
"pshufw $0xC9,%%mm6,%%mm6\n\t" /*mm6=55 52 54 53*/ \
|
||||
"punpckhwd %%mm1,%%mm2\n\t" /*mm2=46 39 31 38 *L*/ \
|
||||
"punpcklwd %%mm3,%%mm1\n\t" /*mm1=51 44 37 30 *M*/ \
|
||||
"movq %%mm2,0x68(%[qdct])\n\t" \
|
||||
"movq %%mm1,0x58(%[qdct])\n\t" \
|
||||
"punpckhwd %%mm6,%%mm5\n\t" /*mm5=55 47 52 45*/ \
|
||||
"punpckldq %%mm0,%%mm6\n\t" /*mm6=61 60 54 53*/ \
|
||||
"pshufw $0x10,%%mm5,%%mm4\n\t" /*mm4=45 52 45 45*/ \
|
||||
"pshufw $0x78,%%mm6,%%mm6\n\t" /*mm6=53 60 61 54 *N*/ \
|
||||
"punpckhdq %%mm0,%%mm5\n\t" /*mm5=63 62 55 47 *O*/ \
|
||||
"punpckhdq %%mm4,%%mm7\n\t" /*mm7=45 52 59 58 *P*/ \
|
||||
"movq %%mm6,0x70(%[qdct])\n\t" \
|
||||
"movq %%mm5,0x78(%[qdct])\n\t" \
|
||||
"movq %%mm7,0x60(%[qdct])\n\t" \
|
||||
|
||||
int oc_enc_quantize_sse2(ogg_int16_t _qdct[64],const ogg_int16_t _dct[64],
|
||||
const ogg_uint16_t _dequant[64],const void *_enquant){
|
||||
ptrdiff_t r;
|
||||
__asm__ __volatile__(
|
||||
/*Put the input in zig-zag order.*/
|
||||
OC_ZIG_ZAG_MMXEXT
|
||||
"xor %[r],%[r]\n\t"
|
||||
/*Loop through two rows at a time.*/
|
||||
".p2align 4\n\t"
|
||||
"0:\n\t"
|
||||
/*Load the first two rows of the data and the quant matrices.*/
|
||||
"movdqa 0x00(%[qdct],%[r]),%%xmm0\n\t"
|
||||
"movdqa 0x10(%[qdct],%[r]),%%xmm1\n\t"
|
||||
"movdqa 0x00(%[dq],%[r]),%%xmm2\n\t"
|
||||
"movdqa 0x10(%[dq],%[r]),%%xmm3\n\t"
|
||||
"movdqa 0x00(%[q],%[r]),%%xmm4\n\t"
|
||||
"movdqa 0x10(%[q],%[r]),%%xmm5\n\t"
|
||||
/*Double the input and propagate its sign to the rounding factor.
|
||||
Using SSSE3's psignw would help here, but we need the mask later anyway.*/
|
||||
"movdqa %%xmm0,%%xmm6\n\t"
|
||||
"psraw $15,%%xmm0\n\t"
|
||||
"movdqa %%xmm1,%%xmm7\n\t"
|
||||
"paddw %%xmm6,%%xmm6\n\t"
|
||||
"psraw $15,%%xmm1\n\t"
|
||||
"paddw %%xmm7,%%xmm7\n\t"
|
||||
"paddw %%xmm0,%%xmm2\n\t"
|
||||
"paddw %%xmm1,%%xmm3\n\t"
|
||||
"pxor %%xmm0,%%xmm2\n\t"
|
||||
"pxor %%xmm1,%%xmm3\n\t"
|
||||
/*Add the rounding factor and perform the first multiply.*/
|
||||
"paddw %%xmm2,%%xmm6\n\t"
|
||||
"paddw %%xmm3,%%xmm7\n\t"
|
||||
"pmulhw %%xmm6,%%xmm4\n\t"
|
||||
"pmulhw %%xmm7,%%xmm5\n\t"
|
||||
"movdqa 0x80(%[q],%[r]),%%xmm2\n\t"
|
||||
"movdqa 0x90(%[q],%[r]),%%xmm3\n\t"
|
||||
"paddw %%xmm4,%%xmm6\n\t"
|
||||
"paddw %%xmm5,%%xmm7\n\t"
|
||||
/*Emulate an element-wise right-shift via a second multiply.*/
|
||||
"pmulhw %%xmm2,%%xmm6\n\t"
|
||||
"pmulhw %%xmm3,%%xmm7\n\t"
|
||||
"add $32,%[r]\n\t"
|
||||
"cmp $96,%[r]\n\t"
|
||||
/*Correct for the sign.*/
|
||||
"psubw %%xmm0,%%xmm6\n\t"
|
||||
"psubw %%xmm1,%%xmm7\n\t"
|
||||
/*Save the result.*/
|
||||
"movdqa %%xmm6,-0x20(%[qdct],%[r])\n\t"
|
||||
"movdqa %%xmm7,-0x10(%[qdct],%[r])\n\t"
|
||||
"jle 0b\n\t"
|
||||
/*Now find the location of the last non-zero value.*/
|
||||
"movdqa 0x50(%[qdct]),%%xmm5\n\t"
|
||||
"movdqa 0x40(%[qdct]),%%xmm4\n\t"
|
||||
"packsswb %%xmm7,%%xmm6\n\t"
|
||||
"packsswb %%xmm5,%%xmm4\n\t"
|
||||
"pxor %%xmm0,%%xmm0\n\t"
|
||||
"mov $-1,%k[dq]\n\t"
|
||||
"pcmpeqb %%xmm0,%%xmm6\n\t"
|
||||
"pcmpeqb %%xmm0,%%xmm4\n\t"
|
||||
"pmovmskb %%xmm6,%k[q]\n\t"
|
||||
"pmovmskb %%xmm4,%k[r]\n\t"
|
||||
"shl $16,%k[q]\n\t"
|
||||
"or %k[r],%k[q]\n\t"
|
||||
"mov $32,%[r]\n\t"
|
||||
/*We have to use xor here instead of not in order to set the flags.*/
|
||||
"xor %k[dq],%k[q]\n\t"
|
||||
"jnz 1f\n\t"
|
||||
"movdqa 0x30(%[qdct]),%%xmm7\n\t"
|
||||
"movdqa 0x20(%[qdct]),%%xmm6\n\t"
|
||||
"movdqa 0x10(%[qdct]),%%xmm5\n\t"
|
||||
"movdqa 0x00(%[qdct]),%%xmm4\n\t"
|
||||
"packsswb %%xmm7,%%xmm6\n\t"
|
||||
"packsswb %%xmm5,%%xmm4\n\t"
|
||||
"pcmpeqb %%xmm0,%%xmm6\n\t"
|
||||
"pcmpeqb %%xmm0,%%xmm4\n\t"
|
||||
"pmovmskb %%xmm6,%k[q]\n\t"
|
||||
"pmovmskb %%xmm4,%k[r]\n\t"
|
||||
"shl $16,%k[q]\n\t"
|
||||
"or %k[r],%k[q]\n\t"
|
||||
"xor %[r],%[r]\n\t"
|
||||
"not %k[q]\n\t"
|
||||
"or $1,%k[q]\n\t"
|
||||
"1:\n\t"
|
||||
"bsr %k[q],%k[q]\n\t"
|
||||
"add %k[q],%k[r]\n\t"
|
||||
:[r]"=&a"(r),[q]"+r"(_enquant),[dq]"+r"(_dequant)
|
||||
:[dct]"r"(_dct),[qdct]"r"(_qdct)
|
||||
:"cc","memory"
|
||||
);
|
||||
return (int)r;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#if !defined(_x86_x86int_H)
|
||||
# define _x86_x86int_H (1)
|
||||
# include "../internal.h"
|
||||
|
||||
# if defined(OC_X86_ASM)
|
||||
# define oc_state_accel_init oc_state_accel_init_x86
|
||||
# if defined(OC_X86_64_ASM)
|
||||
/*x86-64 guarantees SIMD support up through at least SSE2.
|
||||
If the best routine we have available only needs SSE2 (which at the moment
|
||||
covers all of them), then we can avoid runtime detection and the indirect
|
||||
call.*/
|
||||
# define oc_frag_copy(_state,_dst,_src,_ystride) \
|
||||
oc_frag_copy_mmx(_dst,_src,_ystride)
|
||||
# define oc_frag_copy_list(_state,_dst_frame,_src_frame,_ystride, \
|
||||
_fragis,_nfragis,_frag_buf_offs) \
|
||||
oc_frag_copy_list_mmx(_dst_frame,_src_frame,_ystride, \
|
||||
_fragis,_nfragis,_frag_buf_offs)
|
||||
# define oc_frag_recon_intra(_state,_dst,_ystride,_residue) \
|
||||
oc_frag_recon_intra_mmx(_dst,_ystride,_residue)
|
||||
# define oc_frag_recon_inter(_state,_dst,_src,_ystride,_residue) \
|
||||
oc_frag_recon_inter_mmx(_dst,_src,_ystride,_residue)
|
||||
# define oc_frag_recon_inter2(_state,_dst,_src1,_src2,_ystride,_residue) \
|
||||
oc_frag_recon_inter2_mmx(_dst,_src1,_src2,_ystride,_residue)
|
||||
# define oc_idct8x8(_state,_y,_x,_last_zzi) \
|
||||
oc_idct8x8_sse2(_y,_x,_last_zzi)
|
||||
# define oc_state_frag_recon oc_state_frag_recon_mmx
|
||||
# define oc_loop_filter_init(_state,_bv,_flimit) \
|
||||
oc_loop_filter_init_mmxext(_bv,_flimit)
|
||||
# define oc_state_loop_filter_frag_rows oc_state_loop_filter_frag_rows_mmxext
|
||||
# define oc_restore_fpu(_state) \
|
||||
oc_restore_fpu_mmx()
|
||||
# else
|
||||
# define OC_STATE_USE_VTABLE (1)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# include "../state.h"
|
||||
# include "x86cpu.h"
|
||||
|
||||
/*Converts the expression in the argument to a string.*/
|
||||
#define OC_M2STR(_s) #_s
|
||||
|
||||
/*Memory operands do not always include an offset.
|
||||
To avoid warnings, we force an offset with %H (which adds 8).*/
|
||||
# if defined(__GNUC_PREREQ)
|
||||
# if __GNUC_PREREQ(4,0)
|
||||
# define OC_MEM_OFFS(_offs,_name) \
|
||||
OC_M2STR(_offs-8+%H[_name])
|
||||
# endif
|
||||
# endif
|
||||
/*If your gcc version does't support %H, then you get to suffer the warnings.
|
||||
Note that Apple's gas breaks on things like _offs+(%esp): it throws away the
|
||||
whole offset, instead of substituting in 0 for the missing operand to +.*/
|
||||
# if !defined(OC_MEM_OFFS)
|
||||
# define OC_MEM_OFFS(_offs,_name) \
|
||||
OC_M2STR(_offs+%[_name])
|
||||
# endif
|
||||
|
||||
/*Declare an array operand with an exact size.
|
||||
This tells gcc we're going to clobber this memory region, without having to
|
||||
clobber all of "memory" and lets us access local buffers directly using the
|
||||
stack pointer, without allocating a separate register to point to them.*/
|
||||
#define OC_ARRAY_OPERAND(_type,_ptr,_size) \
|
||||
(*({ \
|
||||
struct{_type array_value__[(_size)];} *array_addr__=(void *)(_ptr); \
|
||||
array_addr__; \
|
||||
}))
|
||||
|
||||
/*Declare an array operand with an exact size.
|
||||
This tells gcc we're going to clobber this memory region, without having to
|
||||
clobber all of "memory" and lets us access local buffers directly using the
|
||||
stack pointer, without allocating a separate register to point to them.*/
|
||||
#define OC_CONST_ARRAY_OPERAND(_type,_ptr,_size) \
|
||||
(*({ \
|
||||
const struct{_type array_value__[(_size)];} *array_addr__= \
|
||||
(const void *)(_ptr); \
|
||||
array_addr__; \
|
||||
}))
|
||||
|
||||
extern const short __attribute__((aligned(16))) OC_IDCT_CONSTS[64];
|
||||
|
||||
void oc_state_accel_init_x86(oc_theora_state *_state);
|
||||
|
||||
void oc_frag_copy_mmx(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride);
|
||||
void oc_frag_copy_list_mmx(unsigned char *_dst_frame,
|
||||
const unsigned char *_src_frame,int _ystride,
|
||||
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||
void oc_frag_recon_intra_mmx(unsigned char *_dst,int _ystride,
|
||||
const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter_mmx(unsigned char *_dst,
|
||||
const unsigned char *_src,int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_frag_recon_inter2_mmx(unsigned char *_dst,const unsigned char *_src1,
|
||||
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue);
|
||||
void oc_idct8x8_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||
void oc_idct8x8_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||
void oc_state_frag_recon_mmx(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||
void oc_loop_filter_init_mmx(signed char _bv[256],int _flimit);
|
||||
void oc_loop_filter_init_mmxext(signed char _bv[256],int _flimit);
|
||||
void oc_state_loop_filter_frag_rows_mmx(const oc_theora_state *_state,
|
||||
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||
void oc_state_loop_filter_frag_rows_mmxext(const oc_theora_state *_state,
|
||||
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||
void oc_restore_fpu_mmx(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* 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-2009 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include "x86int.h"
|
||||
|
||||
#if defined(OC_X86_ASM)
|
||||
|
||||
/*This table has been modified from OC_FZIG_ZAG by baking a 4x4 transpose into
|
||||
each quadrant of the destination.*/
|
||||
static const unsigned char OC_FZIG_ZAG_MMX[128]={
|
||||
0, 8, 1, 2, 9,16,24,17,
|
||||
10, 3,32,11,18,25, 4,12,
|
||||
5,26,19,40,33,34,41,48,
|
||||
27, 6,13,20,28,21,14, 7,
|
||||
56,49,42,35,43,50,57,36,
|
||||
15,22,29,30,23,44,37,58,
|
||||
51,59,38,45,52,31,60,53,
|
||||
46,39,47,54,61,62,55,63,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64
|
||||
};
|
||||
|
||||
/*This table has been modified from OC_FZIG_ZAG by baking an 8x8 transpose into
|
||||
the destination.*/
|
||||
static const unsigned char OC_FZIG_ZAG_SSE2[128]={
|
||||
0, 8, 1, 2, 9,16,24,17,
|
||||
10, 3, 4,11,18,25,32,40,
|
||||
33,26,19,12, 5, 6,13,20,
|
||||
27,34,41,48,56,49,42,35,
|
||||
28,21,14, 7,15,22,29,36,
|
||||
43,50,57,58,51,44,37,30,
|
||||
23,31,38,45,52,59,60,53,
|
||||
46,39,47,54,61,62,55,63,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64,
|
||||
64,64,64,64,64,64,64,64
|
||||
};
|
||||
|
||||
void oc_state_accel_init_x86(oc_theora_state *_state){
|
||||
oc_state_accel_init_c(_state);
|
||||
_state->cpu_flags=oc_cpu_flags_get();
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
if(_state->cpu_flags&OC_CPU_X86_MMX){
|
||||
_state->opt_vtable.frag_copy=oc_frag_copy_mmx;
|
||||
_state->opt_vtable.frag_copy_list=oc_frag_copy_list_mmx;
|
||||
_state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_mmx;
|
||||
_state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_mmx;
|
||||
_state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_mmx;
|
||||
_state->opt_vtable.idct8x8=oc_idct8x8_mmx;
|
||||
_state->opt_vtable.state_frag_recon=oc_state_frag_recon_mmx;
|
||||
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_mmx;
|
||||
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||
oc_state_loop_filter_frag_rows_mmx;
|
||||
_state->opt_vtable.restore_fpu=oc_restore_fpu_mmx;
|
||||
_state->opt_data.dct_fzig_zag=OC_FZIG_ZAG_MMX;
|
||||
}
|
||||
if(_state->cpu_flags&OC_CPU_X86_MMXEXT){
|
||||
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_mmxext;
|
||||
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||
oc_state_loop_filter_frag_rows_mmxext;
|
||||
}
|
||||
if(_state->cpu_flags&OC_CPU_X86_SSE2){
|
||||
_state->opt_vtable.idct8x8=oc_idct8x8_sse2;
|
||||
# endif
|
||||
_state->opt_data.dct_fzig_zag=OC_FZIG_ZAG_SSE2;
|
||||
# if defined(OC_STATE_USE_VTABLE)
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user