diff --git a/src/add-ons/media/plugins/theora/libtheora/Jamfile b/src/add-ons/media/plugins/theora/libtheora/Jamfile new file mode 100644 index 0000000000..58a40fae84 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/Jamfile @@ -0,0 +1,28 @@ +SubDir OBOS_TOP src add-ons media plugins theora libtheora ; + +SubDirHdrs [ FDirName $(SUBDIR) .. .. ogg libogg ] ; + +SubDirCcFlags -DPACKAGE=\\\"libtheora\\\" -DVERSION=\\\"0.0\\\" ; +SubDirCcFlags -D_REENTRANT -DPIC -DTRUE=true ; + +StaticLibrary theora : + blockmap.c + comment.c + dct.c + dct_decode.c + dct_encode.c + decode.c + encode.c + frarray.c + frinit.c + huffman.c + idct.c + mcomp.c + misc_common.c + pb.c + pp.c + quant.c + reconstruct.c + scan.c + toplevel.c +; diff --git a/src/add-ons/media/plugins/theora/libtheora/block_inline.h b/src/add-ons/media/plugins/theora/libtheora/block_inline.h new file mode 100644 index 0000000000..4442ca6e58 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/block_inline.h @@ -0,0 +1,38 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: block_inline.h,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include "encoder_internal.h" + +static ogg_int32_t MBOrderMap[4] = { 0, 2, 3, 1 }; +static ogg_int32_t BlockOrderMap1[4][4] = { + { 0, 1, 3, 2 }, + { 0, 2, 3, 1 }, + { 0, 2, 3, 1 }, + { 3, 2, 0, 1 } +}; + +static ogg_int32_t QuadMapToIndex1( ogg_int32_t (*BlockMap)[4][4], + ogg_uint32_t SB, ogg_uint32_t MB, + ogg_uint32_t B ){ + return BlockMap[SB][MBOrderMap[MB]][BlockOrderMap1[MB][B]]; +} + + +static ogg_int32_t QuadMapToMBTopLeft( ogg_int32_t (*BlockMap)[4][4], + ogg_uint32_t SB, ogg_uint32_t MB ){ + return BlockMap[SB][MBOrderMap[MB]][0]; +} diff --git a/src/add-ons/media/plugins/theora/libtheora/blockmap.c b/src/add-ons/media/plugins/theora/libtheora/blockmap.c new file mode 100644 index 0000000000..b7acd65b6a --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/blockmap.c @@ -0,0 +1,100 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: blockmap.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include "encoder_internal.h" + +static void CreateMapping ( ogg_int32_t (*BlockMap)[4][4], + ogg_uint32_t FirstSB, + ogg_uint32_t FirstFrag, ogg_uint32_t HFrags, + ogg_uint32_t VFrags ){ + ogg_uint32_t i, j; + ogg_uint32_t xpos; + ogg_uint32_t ypos; + ogg_uint32_t SBrow, SBcol; + ogg_uint32_t SBRows, SBCols; + ogg_uint32_t MB, B; + + ogg_uint32_t SB=FirstSB; + ogg_uint32_t FragIndex=FirstFrag; + + /* Set Super-Block dimensions */ + SBRows = VFrags/4 + ( VFrags%4 ? 1 : 0 ); + SBCols = HFrags/4 + ( HFrags%4 ? 1 : 0 ); + + /* Map each Super-Block */ + for ( SBrow=0; SBrow +#include +#include +#include "encoder_internal.h" + +void theora_comment_init(theora_comment *tc){ + memset(tc,0,sizeof(*tc)); +} + +void theora_comment_add(theora_comment *tc,char *comment){ + tc->user_comments=_ogg_realloc(tc->user_comments, + (tc->comments+2)*sizeof(*tc->user_comments)); + tc->comment_lengths=_ogg_realloc(tc->comment_lengths, + (tc->comments+2)*sizeof(*tc->comment_lengths)); + tc->comment_lengths[tc->comments]=strlen(comment); + tc->user_comments[tc->comments]=_ogg_malloc(tc->comment_lengths[tc->comments]+1); + strcpy(tc->user_comments[tc->comments], comment); + tc->comments++; + tc->user_comments[tc->comments]=NULL; +} + +void theora_comment_add_tag(theora_comment *tc, char *tag, char *value){ + char *comment=_ogg_malloc(strlen(tag)+strlen(value)+2); /* +2 for = and \0 */ + strcpy(comment, tag); + strcat(comment, "="); + strcat(comment, value); + theora_comment_add(tc, comment); + _ogg_free(comment); +} + +/* 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 */ +static int tagcompare(const char *s1, const char *s2, int n){ + int c=0; + while(c < n){ + if(toupper(s1[c]) != toupper(s2[c])) + return !0; + c++; + } + return 0; +} + +char *theora_comment_query(theora_comment *tc, char *tag, int count){ + long i; + int found = 0; + int taglen = strlen(tag)+1; /* +1 for the = we append */ + char *fulltag = _ogg_malloc(taglen+ 1); + + strcpy(fulltag, tag); + strcat(fulltag, "="); + + for(i=0;icomments;i++){ + if(!tagcompare(tc->user_comments[i], fulltag, taglen)){ + if(count == found){ + _ogg_free(fulltag); + /* We return a pointer to the data, not a copy */ + return tc->user_comments[i] + taglen; + } + else + found++; + } + } + _ogg_free(fulltag); + return NULL; /* didn't find anything */ +} + +int theora_comment_query_count(theora_comment *tc, char *tag){ + int i,count=0; + int taglen = strlen(tag)+1; /* +1 for the = we append */ + char *fulltag = _ogg_malloc(taglen+1); + strcpy(fulltag,tag); + strcat(fulltag, "="); + + for(i=0;icomments;i++){ + if(!tagcompare(tc->user_comments[i], fulltag, taglen)) + count++; + } + _ogg_free(fulltag); + return count; +} + +void theora_comment_clear(theora_comment *tc){ + if(tc){ + long i; + for(i=0;icomments;i++) + if(tc->user_comments[i])_ogg_free(tc->user_comments[i]); + if(tc->user_comments)_ogg_free(tc->user_comments); + if(tc->comment_lengths)_ogg_free(tc->comment_lengths); + if(tc->vendor)_ogg_free(tc->vendor); + } + memset(tc,0,sizeof(*tc)); +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/dct.c b/src/add-ons/media/plugins/theora/libtheora/dct.c new file mode 100644 index 0000000000..46e4ef6e01 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/dct.c @@ -0,0 +1,253 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: dct.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include "encoder_internal.h" + +static ogg_int32_t xC1S7 = 64277; +static ogg_int32_t xC2S6 = 60547; +static ogg_int32_t xC3S5 = 54491; +static ogg_int32_t xC4S4 = 46341; +static ogg_int32_t xC5S3 = 36410; +static ogg_int32_t xC6S2 = 25080; +static ogg_int32_t xC7S1 = 12785; + +#define SIGNBITDUPPED(X) ((signed )(((X) & 0x80000000)) >> 31) +#define DOROUND(X) ( (SIGNBITDUPPED(X) & (0xffff)) + (X) ) + +void fdct_short ( ogg_int16_t * InputData, ogg_int16_t * OutputData ){ + int loop; + + ogg_int32_t is07, is12, is34, is56; + ogg_int32_t is0734, is1256; + ogg_int32_t id07, id12, id34, id56; + + ogg_int32_t irot_input_x, irot_input_y; + ogg_int32_t icommon_product1; /* Re-used product (c4s4 * (s12 - s56)). */ + ogg_int32_t icommon_product2; /* Re-used product (c4s4 * (d12 + d56)). */ + + ogg_int32_t temp1, temp2; /* intermediate variable for computation */ + + ogg_int32_t InterData[64]; + ogg_int32_t *ip = InterData; + ogg_int16_t * op = OutputData; + for (loop = 0; loop < 8; loop++){ + /* Pre calculate some common sums and differences. */ + is07 = InputData[0] + InputData[7]; + is12 = InputData[1] + InputData[2]; + is34 = InputData[3] + InputData[4]; + is56 = InputData[5] + InputData[6]; + + id07 = InputData[0] - InputData[7]; + id12 = InputData[1] - InputData[2]; + id34 = InputData[3] - InputData[4]; + id56 = InputData[5] - InputData[6]; + + is0734 = is07 + is34; + is1256 = is12 + is56; + + /* Pre-Calculate some common product terms. */ + icommon_product1 = xC4S4*(is12 - is56); + icommon_product1 = DOROUND(icommon_product1); + icommon_product1>>=16; + + icommon_product2 = xC4S4*(id12 + id56); + icommon_product2 = DOROUND(icommon_product2); + icommon_product2>>=16; + + + ip[0] = (xC4S4*(is0734 + is1256)); + ip[0] = DOROUND(ip[0]); + ip[0] >>= 16; + + ip[4] = (xC4S4*(is0734 - is1256)); + ip[4] = DOROUND(ip[4]); + ip[4] >>= 16; + + /* Define inputs to rotation for outputs 2 and 6 */ + irot_input_x = id12 - id56; + irot_input_y = is07 - is34; + + /* Apply rotation for outputs 2 and 6. */ + temp1=xC6S2*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC2S6*irot_input_y; + temp2=DOROUND(temp2); + temp2>>=16; + ip[2] = temp1 + temp2; + + temp1=xC6S2*irot_input_y; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC2S6*irot_input_x ; + temp2=DOROUND(temp2); + temp2>>=16; + ip[6] = temp1 -temp2 ; + + /* Define inputs to rotation for outputs 1 and 7 */ + irot_input_x = icommon_product1 + id07; + irot_input_y = -( id34 + icommon_product2 ); + + /* Apply rotation for outputs 1 and 7. */ + + temp1=xC1S7*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC7S1*irot_input_y; + temp2=DOROUND(temp2); + temp2>>=16; + ip[1] = temp1 - temp2; + + temp1=xC7S1*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC1S7*irot_input_y ; + temp2=DOROUND(temp2); + temp2>>=16; + ip[7] = temp1 + temp2 ; + + /* Define inputs to rotation for outputs 3 and 5 */ + irot_input_x = id07 - icommon_product1; + irot_input_y = id34 - icommon_product2; + + /* Apply rotation for outputs 3 and 5. */ + temp1=xC3S5*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC5S3*irot_input_y ; + temp2=DOROUND(temp2); + temp2>>=16; + ip[3] = temp1 - temp2 ; + + temp1=xC5S3*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC3S5*irot_input_y; + temp2=DOROUND(temp2); + temp2>>=16; + ip[5] = temp1 + temp2; + + /* Increment data pointer for next row. */ + InputData += 8 ; + ip += 8; /* advance pointer to next row */ + + } + + + /* Performed DCT on rows, now transform the columns */ + ip = InterData; + for (loop = 0; loop < 8; loop++){ + /* Pre calculate some common sums and differences. */ + is07 = ip[0 * 8] + ip[7 * 8]; + is12 = ip[1 * 8] + ip[2 * 8]; + is34 = ip[3 * 8] + ip[4 * 8]; + is56 = ip[5 * 8] + ip[6 * 8]; + + id07 = ip[0 * 8] - ip[7 * 8]; + id12 = ip[1 * 8] - ip[2 * 8]; + id34 = ip[3 * 8] - ip[4 * 8]; + id56 = ip[5 * 8] - ip[6 * 8]; + + is0734 = is07 + is34; + is1256 = is12 + is56; + + /* Pre-Calculate some common product terms. */ + icommon_product1 = xC4S4*(is12 - is56) ; + icommon_product2 = xC4S4*(id12 + id56) ; + icommon_product1 = DOROUND(icommon_product1); + icommon_product2 = DOROUND(icommon_product2); + icommon_product1>>=16; + icommon_product2>>=16; + + + temp1 = xC4S4*(is0734 + is1256) ; + temp2 = xC4S4*(is0734 - is1256) ; + temp1 = DOROUND(temp1); + temp2 = DOROUND(temp2); + temp1>>=16; + temp2>>=16; + op[0*8] = (ogg_int16_t) temp1; + op[4*8] = (ogg_int16_t) temp2; + + /* Define inputs to rotation for outputs 2 and 6 */ + irot_input_x = id12 - id56; + irot_input_y = is07 - is34; + + /* Apply rotation for outputs 2 and 6. */ + temp1=xC6S2*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC2S6*irot_input_y; + temp2=DOROUND(temp2); + temp2>>=16; + op[2*8] = (ogg_int16_t) (temp1 + temp2); + + temp1=xC6S2*irot_input_y; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC2S6*irot_input_x ; + temp2=DOROUND(temp2); + temp2>>=16; + op[6*8] = (ogg_int16_t) (temp1 -temp2) ; + + /* Define inputs to rotation for outputs 1 and 7 */ + irot_input_x = icommon_product1 + id07; + irot_input_y = -( id34 + icommon_product2 ); + + /* Apply rotation for outputs 1 and 7. */ + temp1=xC1S7*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC7S1*irot_input_y; + temp2=DOROUND(temp2); + temp2>>=16; + op[1*8] = (ogg_int16_t) (temp1 - temp2); + + temp1=xC7S1*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC1S7*irot_input_y ; + temp2=DOROUND(temp2); + temp2>>=16; + op[7*8] = (ogg_int16_t) (temp1 + temp2); + + /* Define inputs to rotation for outputs 3 and 5 */ + irot_input_x = id07 - icommon_product1; + irot_input_y = id34 - icommon_product2; + + /* Apply rotation for outputs 3 and 5. */ + temp1=xC3S5*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC5S3*irot_input_y ; + temp2=DOROUND(temp2); + temp2>>=16; + op[3*8] = (ogg_int16_t) (temp1 - temp2) ; + + temp1=xC5S3*irot_input_x; + temp1=DOROUND(temp1); + temp1>>=16; + temp2=xC3S5*irot_input_y; + temp2=DOROUND(temp2); + temp2>>=16; + op[5*8] = (ogg_int16_t) (temp1 + temp2); + + /* Increment data pointer for next column. */ + ip ++; + op ++; + } +} diff --git a/src/add-ons/media/plugins/theora/libtheora/dct_decode.c b/src/add-ons/media/plugins/theora/libtheora/dct_decode.c new file mode 100644 index 0000000000..a5e1e807f1 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/dct_decode.c @@ -0,0 +1,1198 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: dct_decode.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include "encoder_internal.h" + + +#define GOLDEN_FRAME_THRESH_Q 50 +#define PUR 8 +#define PU 4 +#define PUL 2 +#define PL 1 +#define HIGHBITDUPPED(X) (((signed short) X) >> 15) + +static const ogg_uint32_t LoopFilterLimitValuesV1[Q_TABLE_SIZE] = { + 30, 25, 20, 20, 15, 15, 14, 14, + 13, 13, 12, 12, 11, 11, 10, 10, + 9, 9, 8, 8, 7, 7, 7, 7, + 6, 6, 6, 6, 5, 5, 5, 5, + 4, 4, 4, 4, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const ogg_uint32_t LoopFilterLimitValuesV2[Q_TABLE_SIZE] = { + 30, 25, 20, 20, 15, 15, 14, 14, + 13, 13, 12, 12, 11, 11, 10, 10, + 9, 9, 8, 8, 7, 7, 7, 7, + 6, 6, 6, 6, 5, 5, 5, 5, + 4, 4, 4, 4, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static const int ModeUsesMC[MAX_MODES] = { 0, 0, 1, 1, 1, 0, 1, 1 }; + +static void SetupBoundingValueArray_Generic(PB_INSTANCE *pbi, + ogg_int32_t FLimit){ + + ogg_int32_t * BoundingValuePtr = pbi->FiltBoundingValue+256; + ogg_int32_t i; + + /* Set up the bounding value array. */ + memset ( pbi->FiltBoundingValue, 0, (512*sizeof(*pbi->FiltBoundingValue)) ); + for ( i = 0; i < FLimit; i++ ){ + BoundingValuePtr[-i-FLimit] = (-FLimit+i); + BoundingValuePtr[-i] = -i; + BoundingValuePtr[i] = i; + BoundingValuePtr[i+FLimit] = FLimit-i; + } +} + +void SetupLoopFilter(PB_INSTANCE *pbi){ + ogg_int32_t FLimit; + + FLimit = LoopFilterLimitValuesV2[pbi->FrameQIndex]; + SetupBoundingValueArray_Generic(pbi, FLimit); +} + +void CopyBlock(unsigned char *src, + unsigned char *dest, + unsigned int srcstride){ + unsigned char *s = src; + unsigned char *d = dest; + unsigned int stride = srcstride; + + int j; + for ( j = 0; j < 8; j++ ){ + ((ogg_uint32_t*)d)[0] = ((ogg_uint32_t*)s)[0]; + ((ogg_uint32_t*)d)[1] = ((ogg_uint32_t*)s)[1]; + s+=stride; + d+=stride; + } +} + +static void ExpandKFBlock ( PB_INSTANCE *pbi, ogg_int32_t FragmentNumber ){ + ogg_uint32_t ReconPixelsPerLine; + ogg_int32_t ReconPixelIndex; + + /* Select the appropriate inverse Q matrix and line stride */ + if ( FragmentNumber<(ogg_int32_t)pbi->YPlaneFragments ){ + ReconPixelsPerLine = pbi->YStride; + pbi->dequant_coeffs = pbi->dequant_Y_coeffs; + }else{ + ReconPixelsPerLine = pbi->UVStride; + pbi->dequant_coeffs = pbi->dequant_UV_coeffs; + } + + /* Set up pointer into the quantisation buffer. */ + pbi->quantized_list = &pbi->QFragData[FragmentNumber][0]; + + /* Invert quantisation and DCT to get pixel data. */ + switch(pbi->FragCoefEOB[FragmentNumber]){ + case 0:case 1: + IDct1( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer ); + break; + case 2: case 3:case 4:case 5:case 6:case 7:case 8: case 9:case 10: + IDct10( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer ); + break; + default: + IDctSlow( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer ); + } + + /* Convert fragment number to a pixel offset in a reconstruction buffer. */ + ReconPixelIndex = pbi->recon_pixel_index_table[FragmentNumber]; + + /* Get the pixel index for the first pixel in the fragment. */ + ReconIntra( pbi, (unsigned char *)(&pbi->ThisFrameRecon[ReconPixelIndex]), + (ogg_uint16_t *)pbi->ReconDataBuffer, ReconPixelsPerLine ); + +} + +static void ExpandBlock ( PB_INSTANCE *pbi, ogg_int32_t FragmentNumber ){ + unsigned char *LastFrameRecPtr; /* Pointer into previous frame + reconstruction. */ + unsigned char *LastFrameRecPtr2; /* Pointer into previous frame + reconstruction for 1/2 pixel MC. */ + + ogg_uint32_t ReconPixelsPerLine; /* Pixels per line */ + ogg_int32_t ReconPixelIndex; /* Offset for block into a + reconstruction buffer */ + ogg_int32_t ReconPtr2Offset; /* Offset for second + reconstruction in half pixel + MC */ + ogg_int32_t MVOffset; /* Baseline motion vector offset */ + ogg_int32_t MvShift ; /* Shift to correct to 1/2 or 1/4 pixel */ + ogg_int32_t MvModMask; /* Mask to determine whether 1/2 + pixel is used */ + + /* Get coding mode for this block */ + if ( GetFrameType(pbi) == BASE_FRAME ){ + pbi->CodingMode = CODE_INTRA; + }else{ + /* Get Motion vector and mode for this block. */ + pbi->CodingMode = pbi->FragCodingMethod[FragmentNumber]; + } + + /* Select the appropriate inverse Q matrix and line stride */ + if ( FragmentNumber<(ogg_int32_t)pbi->YPlaneFragments ) { + ReconPixelsPerLine = pbi->YStride; + MvShift = 1; + MvModMask = 0x00000001; + + /* Select appropriate dequantiser matrix. */ + if ( pbi->CodingMode == CODE_INTRA ) + pbi->dequant_coeffs = pbi->dequant_Y_coeffs; + else + pbi->dequant_coeffs = pbi->dequant_Inter_coeffs; + }else{ + ReconPixelsPerLine = pbi->UVStride; + MvShift = 2; + MvModMask = 0x00000003; + + /* Select appropriate dequantiser matrix. */ + if ( pbi->CodingMode == CODE_INTRA ) + pbi->dequant_coeffs = pbi->dequant_UV_coeffs; + else + pbi->dequant_coeffs = pbi->dequant_Inter_coeffs; + } + + /* Set up pointer into the quantisation buffer. */ + pbi->quantized_list = &pbi->QFragData[FragmentNumber][0]; + + /* Invert quantisation and DCT to get pixel data. */ + switch(pbi->FragCoefEOB[FragmentNumber]){ + case 0:case 1: + IDct1( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer ); + break; + case 2: case 3:case 4:case 5:case 6:case 7:case 8: case 9:case 10: + IDct10( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer ); + break; + default: + IDctSlow( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer ); + } + + /* Convert fragment number to a pixel offset in a reconstruction buffer. */ + ReconPixelIndex = pbi->recon_pixel_index_table[FragmentNumber]; + + /* Action depends on decode mode. */ + if ( pbi->CodingMode == CODE_INTER_NO_MV ){ + /* Inter with no motion vector */ + /* Reconstruct the pixel data using the last frame reconstruction + and change data when the motion vector is (0,0), the recon is + based on the lastframe without loop filtering---- for testing */ + ReconInter( pbi, &pbi->ThisFrameRecon[ReconPixelIndex], + &pbi->LastFrameRecon[ReconPixelIndex], + pbi->ReconDataBuffer, ReconPixelsPerLine ); + + }else if ( ModeUsesMC[pbi->CodingMode] ) { + /* The mode uses a motion vector. */ + /* Get vector from list */ + pbi->MVector.x = pbi->FragMVect[FragmentNumber].x; + pbi->MVector.y = pbi->FragMVect[FragmentNumber].y; + + /* Work out the base motion vector offset and the 1/2 pixel offset + if any. For the U and V planes the MV specifies 1/4 pixel + accuracy. This is adjusted to 1/2 pixel as follows ( 0->0, + 1/4->1/2, 1/2->1/2, 3/4->1/2 ). */ + MVOffset = 0; + ReconPtr2Offset = 0; + if ( pbi->MVector.x > 0 ){ + MVOffset = pbi->MVector.x >> MvShift; + if ( pbi->MVector.x & MvModMask ) + ReconPtr2Offset += 1; + } else if ( pbi->MVector.x < 0 ) { + MVOffset -= (-pbi->MVector.x) >> MvShift; + if ( (-pbi->MVector.x) & MvModMask ) + ReconPtr2Offset -= 1; + } + + if ( pbi->MVector.y > 0 ){ + MVOffset += (pbi->MVector.y >> MvShift) * ReconPixelsPerLine; + if ( pbi->MVector.y & MvModMask ) + ReconPtr2Offset += ReconPixelsPerLine; + } else if ( pbi->MVector.y < 0 ){ + MVOffset -= ((-pbi->MVector.y) >> MvShift) * ReconPixelsPerLine; + if ( (-pbi->MVector.y) & MvModMask ) + ReconPtr2Offset -= ReconPixelsPerLine; + } + + /* Set up the first of the two reconstruction buffer pointers. */ + if ( pbi->CodingMode==CODE_GOLDEN_MV ) { + LastFrameRecPtr = &pbi->GoldenFrame[ReconPixelIndex] + MVOffset; + }else{ + LastFrameRecPtr = &pbi->LastFrameRecon[ReconPixelIndex] + MVOffset; + } + + /* Set up the second of the two reconstruction pointers. */ + LastFrameRecPtr2 = LastFrameRecPtr + ReconPtr2Offset; + + /* Select the appropriate reconstruction function */ + if ( (int)(LastFrameRecPtr - LastFrameRecPtr2) == 0 ) { + /* Reconstruct the pixel dats from the reference frame and change data + (no half pixel in this case as the two references were the same. */ + ReconInter( pbi, &pbi->ThisFrameRecon[ReconPixelIndex], + LastFrameRecPtr, pbi->ReconDataBuffer, + ReconPixelsPerLine ); + }else{ + /* Fractional pixel reconstruction. */ + /* Note that we only use two pixels per reconstruction even for + the diagonal. */ + ReconInterHalfPixel2( pbi,&pbi->ThisFrameRecon[ReconPixelIndex], + LastFrameRecPtr, LastFrameRecPtr2, + pbi->ReconDataBuffer, ReconPixelsPerLine ); + } + } else if ( pbi->CodingMode == CODE_USING_GOLDEN ){ + /* Golden frame with motion vector */ + /* Reconstruct the pixel data using the golden frame + reconstruction and change data */ + ReconInter( pbi, &pbi->ThisFrameRecon[ReconPixelIndex], + &pbi->GoldenFrame[ ReconPixelIndex ], + pbi->ReconDataBuffer, ReconPixelsPerLine ); + } else { + /* Simple Intra coding */ + /* Get the pixel index for the first pixel in the fragment. */ + ReconIntra( pbi, &pbi->ThisFrameRecon[ReconPixelIndex], + pbi->ReconDataBuffer, ReconPixelsPerLine ); + } +} + +static void UpdateUMV_HBorders( PB_INSTANCE *pbi, + unsigned char * DestReconPtr, + ogg_uint32_t PlaneFragOffset ) { + ogg_uint32_t i; + ogg_uint32_t PixelIndex; + + ogg_uint32_t PlaneStride; + ogg_uint32_t BlockVStep; + ogg_uint32_t PlaneFragments; + ogg_uint32_t LineFragments; + ogg_uint32_t PlaneBorderWidth; + + unsigned char *SrcPtr1; + unsigned char *SrcPtr2; + unsigned char *DestPtr1; + unsigned char *DestPtr2; + + /* Work out various plane specific values */ + if ( PlaneFragOffset == 0 ) { + /* Y Plane */ + BlockVStep = (pbi->YStride * + (VFRAGPIXELS - 1)); + PlaneStride = pbi->YStride; + PlaneBorderWidth = UMV_BORDER; + PlaneFragments = pbi->YPlaneFragments; + LineFragments = pbi->HFragments; + }else{ + /* U or V plane. */ + BlockVStep = (pbi->UVStride * + (VFRAGPIXELS - 1)); + PlaneStride = pbi->UVStride; + PlaneBorderWidth = UMV_BORDER / 2; + PlaneFragments = pbi->UVPlaneFragments; + LineFragments = pbi->HFragments / 2; + } + + /* Setup the source and destination pointers for the top and bottom + borders */ + PixelIndex = pbi->recon_pixel_index_table[PlaneFragOffset]; + SrcPtr1 = &DestReconPtr[ PixelIndex - PlaneBorderWidth ]; + DestPtr1 = SrcPtr1 - (PlaneBorderWidth * PlaneStride); + + PixelIndex = pbi->recon_pixel_index_table[PlaneFragOffset + + PlaneFragments - LineFragments] + + BlockVStep; + SrcPtr2 = &DestReconPtr[ PixelIndex - PlaneBorderWidth]; + DestPtr2 = SrcPtr2 + PlaneStride; + + /* Now copy the top and bottom source lines into each line of the + respective borders */ + for ( i = 0; i < PlaneBorderWidth; i++ ) { + memcpy( DestPtr1, SrcPtr1, PlaneStride ); + memcpy( DestPtr2, SrcPtr2, PlaneStride ); + DestPtr1 += PlaneStride; + DestPtr2 += PlaneStride; + } +} + +static void UpdateUMV_VBorders( PB_INSTANCE *pbi, + unsigned char * DestReconPtr, + ogg_uint32_t PlaneFragOffset ){ + ogg_uint32_t i; + ogg_uint32_t PixelIndex; + + ogg_uint32_t PlaneStride; + ogg_uint32_t LineFragments; + ogg_uint32_t PlaneBorderWidth; + ogg_uint32_t PlaneHeight; + + unsigned char *SrcPtr1; + unsigned char *SrcPtr2; + unsigned char *DestPtr1; + unsigned char *DestPtr2; + + /* Work out various plane specific values */ + if ( PlaneFragOffset == 0 ) { + /* Y Plane */ + PlaneStride = pbi->YStride; + PlaneBorderWidth = UMV_BORDER; + LineFragments = pbi->HFragments; + PlaneHeight = pbi->info.height; + }else{ + /* U or V plane. */ + PlaneStride = pbi->UVStride; + PlaneBorderWidth = UMV_BORDER / 2; + LineFragments = pbi->HFragments / 2; + PlaneHeight = pbi->info.height / 2; + } + + /* Setup the source data values and destination pointers for the + left and right edge borders */ + PixelIndex = pbi->recon_pixel_index_table[PlaneFragOffset]; + SrcPtr1 = &DestReconPtr[ PixelIndex ]; + DestPtr1 = &DestReconPtr[ PixelIndex - PlaneBorderWidth ]; + + PixelIndex = pbi->recon_pixel_index_table[PlaneFragOffset + + LineFragments - 1] + + (HFRAGPIXELS - 1); + SrcPtr2 = &DestReconPtr[ PixelIndex ]; + DestPtr2 = &DestReconPtr[ PixelIndex + 1 ]; + + /* Now copy the top and bottom source lines into each line of the + respective borders */ + for ( i = 0; i < PlaneHeight; i++ ) { + memset( DestPtr1, SrcPtr1[0], PlaneBorderWidth ); + memset( DestPtr2, SrcPtr2[0], PlaneBorderWidth ); + SrcPtr1 += PlaneStride; + SrcPtr2 += PlaneStride; + DestPtr1 += PlaneStride; + DestPtr2 += PlaneStride; + } +} + +void UpdateUMVBorder( PB_INSTANCE *pbi, + unsigned char * DestReconPtr ) { + ogg_uint32_t PlaneFragOffset; + + /* Y plane */ + PlaneFragOffset = 0; + UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset ); + UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset ); + + /* Then the U and V Planes */ + PlaneFragOffset = pbi->YPlaneFragments; + UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset ); + UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset ); + + PlaneFragOffset = pbi->YPlaneFragments + pbi->UVPlaneFragments; + UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset ); + UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset ); +} + +static void CopyRecon( PB_INSTANCE *pbi, unsigned char * DestReconPtr, + unsigned char * SrcReconPtr ) { + ogg_uint32_t i; + ogg_uint32_t PlaneLineStep; /* Pixels per line */ + ogg_uint32_t PixelIndex; + + unsigned char *SrcPtr; /* Pointer to line of source image data */ + unsigned char *DestPtr; /* Pointer to line of destination image data */ + + /* Copy over only updated blocks.*/ + + /* First Y plane */ + PlaneLineStep = pbi->YStride; + for ( i = 0; i < pbi->YPlaneFragments; i++ ) { + if ( pbi->display_fragments[i] ) { + PixelIndex = pbi->recon_pixel_index_table[i]; + SrcPtr = &SrcReconPtr[ PixelIndex ]; + DestPtr = &DestReconPtr[ PixelIndex ]; + + CopyBlock(SrcPtr, DestPtr, PlaneLineStep); + } + } + + /* Then U and V */ + PlaneLineStep = pbi->UVStride; + for ( i = pbi->YPlaneFragments; i < pbi->UnitFragments; i++ ) { + if ( pbi->display_fragments[i] ) { + PixelIndex = pbi->recon_pixel_index_table[i]; + SrcPtr = &SrcReconPtr[ PixelIndex ]; + DestPtr = &DestReconPtr[ PixelIndex ]; + + CopyBlock(SrcPtr, DestPtr, PlaneLineStep); + + } + } + + /* We may need to update the UMV border */ + UpdateUMVBorder(pbi, DestReconPtr); + +} + +static void CopyNotRecon( PB_INSTANCE *pbi, unsigned char * DestReconPtr, + unsigned char * SrcReconPtr ) { + ogg_uint32_t i; + ogg_uint32_t PlaneLineStep; /* Pixels per line */ + ogg_uint32_t PixelIndex; + + unsigned char *SrcPtr; /* Pointer to line of source image data */ + unsigned char *DestPtr; /* Pointer to line of destination image data*/ + + /* Copy over only updated blocks. */ + + /* First Y plane */ + PlaneLineStep = pbi->YStride; + for ( i = 0; i < pbi->YPlaneFragments; i++ ) { + if ( !pbi->display_fragments[i] ) { + PixelIndex = pbi->recon_pixel_index_table[i]; + SrcPtr = &SrcReconPtr[ PixelIndex ]; + DestPtr = &DestReconPtr[ PixelIndex ]; + + CopyBlock(SrcPtr, DestPtr, PlaneLineStep); + } + } + + /* Then U and V */ + PlaneLineStep = pbi->UVStride; + for ( i = pbi->YPlaneFragments; i < pbi->UnitFragments; i++ ) { + if ( !pbi->display_fragments[i] ) { + PixelIndex = pbi->recon_pixel_index_table[i]; + SrcPtr = &SrcReconPtr[ PixelIndex ]; + DestPtr = &DestReconPtr[ PixelIndex ]; + + CopyBlock(SrcPtr, DestPtr, PlaneLineStep); + + } + } + + /* We may need to update the UMV border */ + UpdateUMVBorder(pbi, DestReconPtr); + +} + +void ExpandToken( Q_LIST_ENTRY * ExpandedBlock, + unsigned char * CoeffIndex, ogg_uint32_t Token, + ogg_int32_t ExtraBits ){ + /* Is the token is a combination run and value token. */ + if ( Token >= DCT_RUN_CATEGORY1 ){ + /* Expand the token and additional bits to a zero run length and + data value. */ + if ( Token < DCT_RUN_CATEGORY2 ) { + /* Decoding method depends on token */ + if ( Token < DCT_RUN_CATEGORY1B ) { + /* Step on by the zero run length */ + *CoeffIndex += (unsigned char)((Token - DCT_RUN_CATEGORY1) + 1); + + /* The extra bit determines the sign. */ + if ( ExtraBits & 0x01 ) + ExpandedBlock[*CoeffIndex] = -1; + else + ExpandedBlock[*CoeffIndex] = 1; + } else if ( Token == DCT_RUN_CATEGORY1B ) { + /* Bits 0-1 determines the zero run length */ + *CoeffIndex += (6 + (ExtraBits & 0x03)); + + /* Bit 2 determines the sign */ + if ( ExtraBits & 0x04 ) + ExpandedBlock[*CoeffIndex] = -1; + else + ExpandedBlock[*CoeffIndex] = 1; + }else{ + /* Bits 0-2 determines the zero run length */ + *CoeffIndex += (10 + (ExtraBits & 0x07)); + + /* Bit 3 determines the sign */ + if ( ExtraBits & 0x08 ) + ExpandedBlock[*CoeffIndex] = -1; + else + ExpandedBlock[*CoeffIndex] = 1; + } + }else{ + /* If token == DCT_RUN_CATEGORY2 we have a single 0 followed by + a value */ + if ( Token == DCT_RUN_CATEGORY2 ){ + /* Step on by the zero run length */ + *CoeffIndex += 1; + + /* Bit 1 determines sign, bit 0 the value */ + if ( ExtraBits & 0x02 ) + ExpandedBlock[*CoeffIndex] = -(2 + (ExtraBits & 0x01)); + else + ExpandedBlock[*CoeffIndex] = 2 + (ExtraBits & 0x01); + }else{ + /* else we have 2->3 zeros followed by a value */ + /* Bit 0 determines the zero run length */ + *CoeffIndex += 2 + (ExtraBits & 0x01); + + /* Bit 2 determines the sign, bit 1 the value */ + if ( ExtraBits & 0x04 ) + ExpandedBlock[*CoeffIndex] = -(2 + ((ExtraBits & 0x02) >> 1)); + else + ExpandedBlock[*CoeffIndex] = 2 + ((ExtraBits & 0x02) >> 1); + } + } + + /* Step on over value */ + *CoeffIndex += 1; + + } else if ( Token == DCT_SHORT_ZRL_TOKEN ) { + /* Token is a ZRL token so step on by the appropriate number of zeros */ + *CoeffIndex += ExtraBits + 1; + } else if ( Token == DCT_ZRL_TOKEN ) { + /* Token is a ZRL token so step on by the appropriate number of zeros */ + *CoeffIndex += ExtraBits + 1; + } else if ( Token < LOW_VAL_TOKENS ) { + /* Token is a small single value token. */ + switch ( Token ) { + case ONE_TOKEN: + ExpandedBlock[*CoeffIndex] = 1; + break; + case MINUS_ONE_TOKEN: + ExpandedBlock[*CoeffIndex] = -1; + break; + case TWO_TOKEN: + ExpandedBlock[*CoeffIndex] = 2; + break; + case MINUS_TWO_TOKEN: + ExpandedBlock[*CoeffIndex] = -2; + break; + } + + /* Step on the coefficient index. */ + *CoeffIndex += 1; + }else{ + /* Token is a larger single value token */ + /* Expand the token and additional bits to a data value. */ + if ( Token < DCT_VAL_CATEGORY3 ) { + /* Offset from LOW_VAL_TOKENS determines value */ + Token = Token - LOW_VAL_TOKENS; + + /* Extra bit determines sign */ + if ( ExtraBits ) + ExpandedBlock[*CoeffIndex] = + -((Q_LIST_ENTRY)(Token + DCT_VAL_CAT2_MIN)); + else + ExpandedBlock[*CoeffIndex] = + (Q_LIST_ENTRY)(Token + DCT_VAL_CAT2_MIN); + } else if ( Token == DCT_VAL_CATEGORY3 ) { + /* Bit 1 determines sign, Bit 0 the value */ + if ( ExtraBits & 0x02 ) + ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT3_MIN + (ExtraBits & 0x01)); + else + ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT3_MIN + (ExtraBits & 0x01); + } else if ( Token == DCT_VAL_CATEGORY4 ) { + /* Bit 2 determines sign, Bit 0-1 the value */ + if ( ExtraBits & 0x04 ) + ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT4_MIN + (ExtraBits & 0x03)); + else + ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT4_MIN + (ExtraBits & 0x03); + } else if ( Token == DCT_VAL_CATEGORY5 ) { + /* Bit 3 determines sign, Bit 0-2 the value */ + if ( ExtraBits & 0x08 ) + ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT5_MIN + (ExtraBits & 0x07)); + else + ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT5_MIN + (ExtraBits & 0x07); + } else if ( Token == DCT_VAL_CATEGORY6 ) { + /* Bit 4 determines sign, Bit 0-3 the value */ + if ( ExtraBits & 0x10 ) + ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT6_MIN + (ExtraBits & 0x0F)); + else + ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT6_MIN + (ExtraBits & 0x0F); + } else if ( Token == DCT_VAL_CATEGORY7 ) { + /* Bit 5 determines sign, Bit 0-4 the value */ + if ( ExtraBits & 0x20 ) + ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT7_MIN + (ExtraBits & 0x1F)); + else + ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT7_MIN + (ExtraBits & 0x1F); + } else if ( Token == DCT_VAL_CATEGORY8 ) { + /* Bit 9 determines sign, Bit 0-8 the value */ + if ( ExtraBits & 0x200 ) + ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT8_MIN + (ExtraBits & 0x1FF)); + else + ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT8_MIN + (ExtraBits & 0x1FF); + } + + /* Step on the coefficient index. */ + *CoeffIndex += 1; + } +} + +void ClearDownQFragData(PB_INSTANCE *pbi){ + ogg_int32_t i,j; + Q_LIST_ENTRY * QFragPtr; + + for ( i = 0; i < pbi->CodedBlockIndex; i++ ) { + /* Get the linear index for the current fragment. */ + QFragPtr = pbi->QFragData[pbi->CodedBlockList[i]]; + for ( j = 0; j < 64; j++ ) QFragPtr[j] = 0; + } +} + +static void FilterHoriz(unsigned char * PixelPtr, + ogg_int32_t LineLength, + ogg_int32_t *BoundingValuePtr){ + ogg_int32_t j; + ogg_int32_t FiltVal; + + for ( j = 0; j < 8; j++ ){ + FiltVal = + ( PixelPtr[0] ) - + ( PixelPtr[1] * 3 ) + + ( PixelPtr[2] * 3 ) - + ( PixelPtr[3] ); + + FiltVal = *(BoundingValuePtr+((FiltVal + 4) >> 3)); + + PixelPtr[1] = clamp255(PixelPtr[1] + FiltVal); + PixelPtr[2] = clamp255(PixelPtr[2] - FiltVal); + + PixelPtr += LineLength; + } +} + +static void FilterVert(unsigned char * PixelPtr, + ogg_int32_t LineLength, + ogg_int32_t *BoundingValuePtr){ + ogg_int32_t j; + ogg_int32_t FiltVal; + + /* the math was correct, but negative array indicies are forbidden + by ANSI/C99 and will break optimization on several modern + compilers */ + + PixelPtr -= 2*LineLength; + + for ( j = 0; j < 8; j++ ) { + FiltVal = ( (ogg_int32_t)PixelPtr[0] ) - + ( (ogg_int32_t)PixelPtr[LineLength] * 3 ) + + ( (ogg_int32_t)PixelPtr[2 * LineLength] * 3 ) - + ( (ogg_int32_t)PixelPtr[3 * LineLength] ); + + FiltVal = *(BoundingValuePtr+((FiltVal + 4) >> 3)); + + PixelPtr[LineLength] = clamp255(PixelPtr[LineLength] + FiltVal); + PixelPtr[2 * LineLength] = clamp255(PixelPtr[2*LineLength] - FiltVal); + + PixelPtr ++; + } +} + +void LoopFilter(PB_INSTANCE *pbi){ + ogg_int32_t i; + + ogg_int32_t * BoundingValuePtr=pbi->FiltBoundingValue+256; + int FragsAcross=pbi->HFragments; + int FromFragment,ToFragment; + int FragsDown = pbi->VFragments; + ogg_int32_t LineFragments; + ogg_int32_t LineLength; + ogg_int32_t FLimit; + int QIndex; + int j,m,n; + + /* Set the limit value for the loop filter based upon the current + quantizer. */ + QIndex = Q_TABLE_SIZE - 1; + while ( QIndex >= 0 ) { + if ( (QIndex == 0) || + ( pbi->QThreshTable[QIndex] >= pbi->ThisFrameQualityValue) ) + break; + QIndex --; + } + + /* Encoder version specific clause */ + FLimit = LoopFilterLimitValuesV1[QIndex]; + + if ( FLimit == 0 ) return; + + SetupBoundingValueArray_Generic(pbi, FLimit); + + + for ( j = 0; j < 3 ; j++){ + switch(j) { + case 0: /* y */ + FromFragment = 0; + ToFragment = pbi->YPlaneFragments; + FragsAcross = pbi->HFragments; + FragsDown = pbi->VFragments; + LineLength = pbi->YStride; + LineFragments = pbi->HFragments; + break; + case 1: /* u */ + FromFragment = pbi->YPlaneFragments; + ToFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments ; + FragsAcross = pbi->HFragments >> 1; + FragsDown = pbi->VFragments >> 1; + LineLength = pbi->UVStride; + LineFragments = pbi->HFragments / 2; + break; + /*case 2: v */ + default: + FromFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments; + ToFragment = pbi->YPlaneFragments + (2 * pbi->UVPlaneFragments) ; + FragsAcross = pbi->HFragments >> 1; + FragsDown = pbi->VFragments >> 1; + LineLength = pbi->UVStride; + LineFragments = pbi->HFragments / 2; + break; + } + + i=FromFragment; + + /************************************************************** + First Row + **************************************************************/ + /* first column conditions */ + /* only do 2 prediction if fragment coded and on non intra or if + all fragments are intra */ + if( pbi->display_fragments[i]){ + /* Filter right hand border only if the block to the right is + not coded */ + if ( !pbi->display_fragments[ i + 1 ] ){ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i]+6, + LineLength,BoundingValuePtr); + } + + /* Bottom done if next row set */ + if( !pbi->display_fragments[ i + LineFragments] ){ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i+LineFragments], + LineLength, BoundingValuePtr); + } + } + i++; + + /***************************************************************/ + /* middle columns */ + for ( n = 1 ; n < FragsAcross - 1 ; n++, i++) { + if( pbi->display_fragments[i]){ + /* Filter Left edge always */ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i]-2, + LineLength, BoundingValuePtr); + + /* Filter right hand border only if the block to the right is + not coded */ + if ( !pbi->display_fragments[ i + 1 ] ){ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i]+6, + LineLength, BoundingValuePtr); + } + + /* Bottom done if next row set */ + if( !pbi->display_fragments[ i + LineFragments] ){ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i + LineFragments], + LineLength, BoundingValuePtr); + } + + } + } + + /***************************************************************/ + /* Last Column */ + if( pbi->display_fragments[i]){ + /* Filter Left edge always */ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] - 2 , + LineLength, BoundingValuePtr); + + /* Bottom done if next row set */ + if( !pbi->display_fragments[ i + LineFragments] ){ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i + LineFragments], + LineLength, BoundingValuePtr); + } + } + i++; + + /***************************************************************/ + /* Middle Rows */ + /***************************************************************/ + for ( m = 1 ; m < FragsDown-1 ; m++) { + + /*****************************************************************/ + /* first column conditions */ + /* only do 2 prediction if fragment coded and on non intra or if + all fragments are intra */ + if( pbi->display_fragments[i]){ + /* TopRow is always done */ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i], + LineLength, BoundingValuePtr); + + /* Filter right hand border only if the block to the right is + not coded */ + if ( !pbi->display_fragments[ i + 1 ] ){ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] + 6, + LineLength, BoundingValuePtr); + } + + /* Bottom done if next row set */ + if( !pbi->display_fragments[ i + LineFragments] ){ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i + LineFragments], + LineLength, BoundingValuePtr); + } + } + i++; + + /*****************************************************************/ + /* middle columns */ + for ( n = 1 ; n < FragsAcross - 1 ; n++, i++){ + if( pbi->display_fragments[i]){ + /* Filter Left edge always */ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] - 2, + LineLength, BoundingValuePtr); + + /* TopRow is always done */ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i], + LineLength, BoundingValuePtr); + + /* Filter right hand border only if the block to the right + is not coded */ + if ( !pbi->display_fragments[ i + 1 ] ){ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] + 6, + LineLength, BoundingValuePtr); + } + + /* Bottom done if next row set */ + if( !pbi->display_fragments[ i + LineFragments] ){ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i + LineFragments], + LineLength, BoundingValuePtr); + } + } + } + + /******************************************************************/ + /* Last Column */ + if( pbi->display_fragments[i]){ + /* Filter Left edge always*/ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] - 2, + LineLength, BoundingValuePtr); + + /* TopRow is always done */ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i], + LineLength, BoundingValuePtr); + + /* Bottom done if next row set */ + if( !pbi->display_fragments[ i + LineFragments] ){ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i + LineFragments], + LineLength, BoundingValuePtr); + } + } + i++; + + } + + /*******************************************************************/ + /* Last Row */ + + /* first column conditions */ + /* only do 2 prediction if fragment coded and on non intra or if + all fragments are intra */ + if( pbi->display_fragments[i]){ + + /* TopRow is always done */ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i], + LineLength, BoundingValuePtr); + + /* Filter right hand border only if the block to the right is + not coded */ + if ( !pbi->display_fragments[ i + 1 ] ){ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] + 6, + LineLength, BoundingValuePtr); + } + } + i++; + + /******************************************************************/ + /* middle columns */ + for ( n = 1 ; n < FragsAcross - 1 ; n++, i++){ + if( pbi->display_fragments[i]){ + /* Filter Left edge always */ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] - 2, + LineLength, BoundingValuePtr); + + /* TopRow is always done */ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i], + LineLength, BoundingValuePtr); + + /* Filter right hand border only if the block to the right is + not coded */ + if ( !pbi->display_fragments[ i + 1 ] ){ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] + 6, + LineLength, BoundingValuePtr); + } + } + } + + /******************************************************************/ + /* Last Column */ + if( pbi->display_fragments[i]){ + /* Filter Left edge always */ + FilterHoriz(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i] - 2, + LineLength, BoundingValuePtr); + + /* TopRow is always done */ + FilterVert(pbi->LastFrameRecon+ + pbi->recon_pixel_index_table[i], + LineLength, BoundingValuePtr); + + } + i++; + } +} + +void ReconRefFrames (PB_INSTANCE *pbi){ + ogg_int32_t i; + unsigned char *SwapReconBuffersTemp; + + /* predictor multiplier up-left, up, up-right,left, shift + Entries are packed in the order L, UL, U, UR, with missing entries + moved to the end (before the shift parameters). */ + static const ogg_int16_t pc[16][6]={ + {0,0,0,0,0,0}, + {1,0,0,0,0,0}, /* PL */ + {1,0,0,0,0,0}, /* PUL */ + {1,0,0,0,0,0}, /* PUL|PL */ + {1,0,0,0,0,0}, /* PU */ + {1,1,0,0,1,1}, /* PU|PL */ + {0,1,0,0,0,0}, /* PU|PUL */ + {29,-26,29,0,5,31}, /* PU|PUL|PL */ + {1,0,0,0,0,0}, /* PUR */ + {75,53,0,0,7,127}, /* PUR|PL */ + {1,1,0,0,1,1}, /* PUR|PUL */ + {75,0,53,0,7,127}, /* PUR|PUL|PL */ + {1,0,0,0,0,0}, /* PUR|PU */ + {75,0,53,0,7,127}, /* PUR|PU|PL */ + {3,10,3,0,4,15}, /* PUR|PU|PUL */ + {29,-26,29,0,5,31} /* PUR|PU|PUL|PL */ + }; + + /* boundary case bit masks. */ + static const int bc_mask[8]={ + /* normal case no boundary condition */ + PUR|PU|PUL|PL, + /* left column */ + PUR|PU, + /* top row */ + PL, + /* top row, left column */ + 0, + /* right column */ + PU|PUL|PL, + /* right and left column */ + PU, + /* top row, right column */ + PL, + /* top row, right and left column */ + 0 + }; + + /* value left value up-left, value up, value up-right, missing + values skipped. */ + int v[4]; + + /* fragment number left, up-left, up, up-right */ + int fn[4]; + + /* predictor count. */ + int pcount; + + short wpc; + static const short Mode2Frame[] = { + 1, /* CODE_INTER_NO_MV 0 => Encoded diff from same MB last frame */ + 0, /* CODE_INTRA 1 => DCT Encoded Block */ + 1, /* CODE_INTER_PLUS_MV 2 => Encoded diff from included MV MB last frame */ + 1, /* CODE_INTER_LAST_MV 3 => Encoded diff from MRU MV MB last frame */ + 1, /* CODE_INTER_PRIOR_MV 4 => Encoded diff from included 4 separate MV blocks */ + 2, /* CODE_USING_GOLDEN 5 => Encoded diff from same MB golden frame */ + 2, /* CODE_GOLDEN_MV 6 => Encoded diff from included MV MB golden frame */ + 1 /* CODE_INTER_FOUR_MV 7 => Encoded diff from included 4 separate MV blocks */ + }; + short Last[3]; + short PredictedDC; + int FragsAcross=pbi->HFragments; + int FromFragment,ToFragment; + int FragsDown = pbi->VFragments; + + int WhichFrame; + int WhichCase; + int j,k,m,n; + + void (*ExpandBlockA) ( PB_INSTANCE *pbi, ogg_int32_t FragmentNumber ); + + if ( GetFrameType(pbi) == BASE_FRAME ) + ExpandBlockA=ExpandKFBlock; + else + ExpandBlockA=ExpandBlock; + + SetupLoopFilter(pbi); + + /* for y,u,v */ + for ( j = 0; j < 3 ; j++) { + /* pick which fragments based on Y, U, V */ + switch(j){ + case 0: /* y */ + FromFragment = 0; + ToFragment = pbi->YPlaneFragments; + FragsAcross = pbi->HFragments; + FragsDown = pbi->VFragments; + break; + case 1: /* u */ + FromFragment = pbi->YPlaneFragments; + ToFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments ; + FragsAcross = pbi->HFragments >> 1; + FragsDown = pbi->VFragments >> 1; + break; + /*case 2: v */ + default: + FromFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments; + ToFragment = pbi->YPlaneFragments + (2 * pbi->UVPlaneFragments) ; + FragsAcross = pbi->HFragments >> 1; + FragsDown = pbi->VFragments >> 1; + break; + } + + /* initialize our array of last used DC Components */ + for(k=0;k<3;k++) + Last[k]=0; + + i=FromFragment; + + /* do prediction on all of Y, U or V */ + for ( m = 0 ; m < FragsDown ; m++) { + for ( n = 0 ; n < FragsAcross ; n++, i++){ + + /* only do 2 prediction if fragment coded and on non intra or + if all fragments are intra */ + if( pbi->display_fragments[i] || (GetFrameType(pbi) == BASE_FRAME) ){ + /* Type of Fragment */ + WhichFrame = Mode2Frame[pbi->FragCodingMethod[i]]; + + /* Check Borderline Cases */ + WhichCase = (n==0) + ((m==0) << 1) + ((n+1 == FragsAcross) << 2); + + fn[0]=i-1; + fn[1]=i-FragsAcross-1; + fn[2]=i-FragsAcross; + fn[3]=i-FragsAcross+1; + + /* fragment valid for prediction use if coded and it comes + from same frame as the one we are predicting */ + for(k=pcount=wpc=0; k<4; k++) { + int pflag; + pflag=1<display_fragments[fn[k]] && + (Mode2Frame[pbi->FragCodingMethod[fn[k]]] == WhichFrame)){ + v[pcount]=pbi->QFragData[fn[k]][0]; + wpc|=pflag; + pcount++; + } + } + + if(wpc==0){ + /* fall back to the last coded fragment */ + pbi->QFragData[i][0] += Last[WhichFrame]; + + }else{ + + /* don't do divide if divisor is 1 or 0 */ + PredictedDC = pc[wpc][0]*v[0]; + for(k=1; k>= pc[wpc][4]; + } + + /* check for outranging on the two predictors that can outrange */ + if((wpc&(PU|PUL|PL)) == (PU|PUL|PL)){ + if( abs(PredictedDC - v[2]) > 128) { + PredictedDC = v[2]; + } else if( abs(PredictedDC - v[0]) > 128) { + PredictedDC = v[0]; + } else if( abs(PredictedDC - v[1]) > 128) { + PredictedDC = v[1]; + } + } + + pbi->QFragData[i][0] += PredictedDC; + + } + + /* Save the last fragment coded for whatever frame we are + predicting from */ + Last[WhichFrame] = pbi->QFragData[i][0]; + + /* Inverse DCT and reconstitute buffer in thisframe */ + ExpandBlockA( pbi, i ); + + } + } + } + } + + /* Copy the current reconstruction back to the last frame recon buffer. */ + if(pbi->CodedBlockIndex > (ogg_int32_t) (pbi->UnitFragments >> 1)){ + SwapReconBuffersTemp = pbi->ThisFrameRecon; + pbi->ThisFrameRecon = pbi->LastFrameRecon; + pbi->LastFrameRecon = SwapReconBuffersTemp; + CopyNotRecon( pbi, pbi->LastFrameRecon, pbi->ThisFrameRecon ); + }else{ + CopyRecon( pbi, pbi->LastFrameRecon, pbi->ThisFrameRecon ); + } + + /* Apply a loop filter to edge pixels of updated blocks */ + LoopFilter(pbi); + + + /* Reconstruct the golden frame if necessary. + For VFW codec only on key frames */ + if ( GetFrameType(pbi) == BASE_FRAME ) + CopyRecon( pbi, pbi->GoldenFrame, pbi->LastFrameRecon ); + +} diff --git a/src/add-ons/media/plugins/theora/libtheora/dct_encode.c b/src/add-ons/media/plugins/theora/libtheora/dct_encode.c new file mode 100644 index 0000000000..3b87005a5f --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/dct_encode.c @@ -0,0 +1,557 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: dct_encode.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include "encoder_internal.h" + +static int ModeUsesMC[MAX_MODES] = { 0, 0, 1, 1, 1, 0, 1, 1 }; + +static void Sub8 (unsigned char *FiltPtr, unsigned char *ReconPtr, + ogg_int16_t *DctInputPtr, unsigned char *old_ptr1, + unsigned char *new_ptr1, ogg_uint32_t PixelsPerLine, + ogg_uint32_t ReconPixelsPerLine ) { + int i; + + /* For each block row */ + for ( i=0; i 0 ) + TokenListPtr[1] = 0; + else + TokenListPtr[1] = 1; + tokens_added = 2; + } else if ( AbsDataVal <= 8 ) { + /* Bit 1 determines sign, Bit 0 the value */ + TokenListPtr[0] = DCT_VAL_CATEGORY3; + if ( DataValue > 0 ) + TokenListPtr[1] = (AbsDataVal - DCT_VAL_CAT3_MIN); + else + TokenListPtr[1] = (0x02) + (AbsDataVal - DCT_VAL_CAT3_MIN); + tokens_added = 2; + } else if ( AbsDataVal <= 12 ) { + /* Bit 2 determines sign, Bit 0-2 the value */ + TokenListPtr[0] = DCT_VAL_CATEGORY4; + if ( DataValue > 0 ) + TokenListPtr[1] = (AbsDataVal - DCT_VAL_CAT4_MIN); + else + TokenListPtr[1] = (0x04) + (AbsDataVal - DCT_VAL_CAT4_MIN); + tokens_added = 2; + } else if ( AbsDataVal <= 20 ) { + /* Bit 3 determines sign, Bit 0-2 the value */ + TokenListPtr[0] = DCT_VAL_CATEGORY5; + if ( DataValue > 0 ) + TokenListPtr[1] = (AbsDataVal - DCT_VAL_CAT5_MIN); + else + TokenListPtr[1] = (0x08) + (AbsDataVal - DCT_VAL_CAT5_MIN); + tokens_added = 2; + } else if ( AbsDataVal <= 36 ) { + /* Bit 4 determines sign, Bit 0-3 the value */ + TokenListPtr[0] = DCT_VAL_CATEGORY6; + if ( DataValue > 0 ) + TokenListPtr[1] = (AbsDataVal - DCT_VAL_CAT6_MIN); + else + TokenListPtr[1] = (0x010) + (AbsDataVal - DCT_VAL_CAT6_MIN); + tokens_added = 2; + } else if ( AbsDataVal <= 68 ) { + /* Bit 5 determines sign, Bit 0-4 the value */ + TokenListPtr[0] = DCT_VAL_CATEGORY7; + if ( DataValue > 0 ) + TokenListPtr[1] = (AbsDataVal - DCT_VAL_CAT7_MIN); + else + TokenListPtr[1] = (0x20) + (AbsDataVal - DCT_VAL_CAT7_MIN); + tokens_added = 2; + } else if ( AbsDataVal <= 511 ) { + /* Bit 9 determines sign, Bit 0-8 the value */ + TokenListPtr[0] = DCT_VAL_CATEGORY8; + if ( DataValue > 0 ) + TokenListPtr[1] = (AbsDataVal - DCT_VAL_CAT8_MIN); + else + TokenListPtr[1] = (0x200) + (AbsDataVal - DCT_VAL_CAT8_MIN); + tokens_added = 2; + } else { + TokenListPtr[0] = DCT_VAL_CATEGORY8; + if ( DataValue > 0 ) + TokenListPtr[1] = (511 - DCT_VAL_CAT8_MIN); + else + TokenListPtr[1] = (0x200) + (511 - DCT_VAL_CAT8_MIN); + tokens_added = 2; + } + + /* Return the total number of tokens added */ + return tokens_added; +} + +static unsigned char TokenizeDctRunValue (unsigned char RunLength, + ogg_int16_t DataValue, + ogg_uint32_t * TokenListPtr ){ + unsigned char tokens_added = 0; + ogg_uint32_t AbsDataVal = abs( (ogg_int32_t)DataValue ); + + /* Values are tokenised as category value and a number of additional + bits that define the category. */ + if ( DataValue == 0 ) return 0; + if ( AbsDataVal == 1 ) { + /* Zero runs of 1-5 */ + if ( RunLength <= 5 ) { + TokenListPtr[0] = DCT_RUN_CATEGORY1 + (RunLength - 1); + if ( DataValue > 0 ) + TokenListPtr[1] = 0; + else + TokenListPtr[1] = 1; + } else if ( RunLength <= 9 ) { + /* Zero runs of 6-9 */ + TokenListPtr[0] = DCT_RUN_CATEGORY1B; + if ( DataValue > 0 ) + TokenListPtr[1] = (RunLength - 6); + else + TokenListPtr[1] = 0x04 + (RunLength - 6); + } else { + /* Zero runs of 10-17 */ + TokenListPtr[0] = DCT_RUN_CATEGORY1C; + if ( DataValue > 0 ) + TokenListPtr[1] = (RunLength - 10); + else + TokenListPtr[1] = 0x08 + (RunLength - 10); + } + tokens_added = 2; + } else if ( AbsDataVal <= 3 ) { + if ( RunLength == 1 ) { + TokenListPtr[0] = DCT_RUN_CATEGORY2; + + /* Extra bits token bit 1 indicates sign, bit 0 indicates value */ + if ( DataValue > 0 ) + TokenListPtr[1] = (AbsDataVal - 2); + else + TokenListPtr[1] = (0x02) + (AbsDataVal - 2); + tokens_added = 2; + }else{ + TokenListPtr[0] = DCT_RUN_CATEGORY2 + 1; + + /* Extra bits token. */ + /* bit 2 indicates sign, bit 1 indicates value, bit 0 indicates + run length */ + if ( DataValue > 0 ) + TokenListPtr[1] = ((AbsDataVal - 2) << 1) + (RunLength - 2); + else + TokenListPtr[1] = (0x04) + ((AbsDataVal - 2) << 1) + (RunLength - 2); + tokens_added = 2; + } + } else { + tokens_added = 2; /* ERROR */ + /*IssueWarning( "Bad Input to TokenizeDctRunValue" );*/ + } + + /* Return the total number of tokens added */ + return tokens_added; +} + +static unsigned char TokenizeDctBlock (ogg_int16_t * RawData, + ogg_uint32_t * TokenListPtr ) { + ogg_uint32_t i; + unsigned char run_count; + unsigned char token_count = 0; /* Number of tokens crated. */ + ogg_uint32_t AbsData; + + + /* Tokenize the block */ + for( i = 0; i < BLOCK_SIZE; i++ ){ + run_count = 0; + + /* Look for a zero run. */ + /* NOTE the use of & instead of && which is faster (and + equivalent) in this instance. */ + /* NO, NO IT ISN'T --Monty */ + while( (i < BLOCK_SIZE) && (!RawData[i]) ){ + run_count++; + i++; + } + + /* If we have reached the end of the block then code EOB */ + if ( i == BLOCK_SIZE ){ + TokenListPtr[token_count] = DCT_EOB_TOKEN; + token_count++; + }else{ + /* If we have a short zero run followed by a low data value code + the two as a composite token. */ + if ( run_count ){ + AbsData = abs(RawData[i]); + + if ( ((AbsData == 1) && (run_count <= 17)) || + ((AbsData <= 3) && (run_count <= 3)) ) { + /* Tokenise the run and subsequent value combination value */ + token_count += TokenizeDctRunValue( run_count, + RawData[i], + &TokenListPtr[token_count] ); + }else{ + + /* Else if we have a long non-EOB run or a run followed by a + value token > MAX_RUN_VAL then code the run and token + seperately */ + if ( run_count <= 8 ) + TokenListPtr[token_count] = DCT_SHORT_ZRL_TOKEN; + else + TokenListPtr[token_count] = DCT_ZRL_TOKEN; + + token_count++; + TokenListPtr[token_count] = run_count - 1; + token_count++; + + /* Now tokenize the value */ + token_count += TokenizeDctValue( RawData[i], + &TokenListPtr[token_count] ); + } + }else{ + /* Else there was NO zero run. */ + /* Tokenise the value */ + token_count += TokenizeDctValue( RawData[i], + &TokenListPtr[token_count] ); + } + } + } + + /* Return the total number of tokens (including additional bits + tokens) used. */ + return token_count; +} + +ogg_uint32_t DPCMTokenizeBlock (CP_INSTANCE *cpi, + ogg_int32_t FragIndex){ + ogg_uint32_t token_count; + + if ( GetFrameType(&cpi->pb) == BASE_FRAME ){ + /* Key frame so code block in INTRA mode. */ + cpi->pb.CodingMode = CODE_INTRA; + }else{ + /* Get Motion vector and mode for this block. */ + cpi->pb.CodingMode = cpi->pb.FragCodingMethod[FragIndex]; + } + + /* Tokenise the dct data. */ + token_count = TokenizeDctBlock( cpi->pb.QFragData[FragIndex], + cpi->pb.TokenList[FragIndex] ); + + cpi->FragTokenCounts[FragIndex] = token_count; + cpi->TotTokenCount += token_count; + + /* Return number of pixels coded (i.e. 8x8). */ + return BLOCK_SIZE; +} + +static int AllZeroDctData( Q_LIST_ENTRY * QuantList ){ + ogg_uint32_t i; + + for ( i = 0; i < 64; i ++ ) + if ( QuantList[i] != 0 ) + return 0; + + return 1; +} + +static void MotionBlockDifference (CP_INSTANCE * cpi, unsigned char * FiltPtr, + ogg_int16_t *DctInputPtr, ogg_int32_t MvDevisor, + unsigned char* old_ptr1, unsigned char* new_ptr1, + ogg_uint32_t FragIndex,ogg_uint32_t PixelsPerLine, + ogg_uint32_t ReconPixelsPerLine) { + + ogg_int32_t MvShift; + ogg_int32_t MvModMask; + ogg_int32_t AbsRefOffset; + ogg_int32_t AbsXOffset; + ogg_int32_t AbsYOffset; + ogg_int32_t MVOffset; /* Baseline motion vector offset */ + ogg_int32_t ReconPtr2Offset; /* Offset for second reconstruction in + half pixel MC */ + unsigned char *ReconPtr1; /* DCT reconstructed image pointers */ + unsigned char *ReconPtr2; /* Pointer used in half pixel MC */ + + + switch(MvDevisor) { + case 2: + MvShift = 1; + MvModMask = 1; + break; + case 4: + MvShift = 2; + MvModMask = 3; + break; + default: + break; + } + + cpi->MVector.x = cpi->pb.FragMVect[FragIndex].x; + cpi->MVector.y = cpi->pb.FragMVect[FragIndex].y; + + /* Set up the baseline offset for the motion vector. */ + MVOffset = ((cpi->MVector.y / MvDevisor) * ReconPixelsPerLine) + + (cpi->MVector.x / MvDevisor); + + /* Work out the offset of the second reference position for 1/2 + pixel interpolation. For the U and V planes the MV specifies 1/4 + pixel accuracy. This is adjusted to 1/2 pixel as follows ( 0->0, + 1/4->1/2, 1/2->1/2, 3/4->1/2 ). */ + ReconPtr2Offset = 0; + AbsXOffset = cpi->MVector.x % MvDevisor; + AbsYOffset = cpi->MVector.y % MvDevisor; + + if ( AbsXOffset ) { + if ( cpi->MVector.x > 0 ) + ReconPtr2Offset += 1; + else + ReconPtr2Offset -= 1; + } + + if ( AbsYOffset ) { + if ( cpi->MVector.y > 0 ) + ReconPtr2Offset += ReconPixelsPerLine; + else + ReconPtr2Offset -= ReconPixelsPerLine; + } + + if ( cpi->pb.CodingMode==CODE_GOLDEN_MV ) { + ReconPtr1 = &cpi-> + pb.GoldenFrame[cpi->pb.recon_pixel_index_table[FragIndex]]; + } else { + ReconPtr1 = &cpi-> + pb.LastFrameRecon[cpi->pb.recon_pixel_index_table[FragIndex]]; + } + + ReconPtr1 += MVOffset; + ReconPtr2 = ReconPtr1 + ReconPtr2Offset; + + AbsRefOffset = abs((int)(ReconPtr1 - ReconPtr2)); + + /* Is the MV offset exactly pixel alligned */ + if ( AbsRefOffset == 0 ){ + Sub8( FiltPtr, ReconPtr1, DctInputPtr, old_ptr1, new_ptr1, + PixelsPerLine, ReconPixelsPerLine ); + } else { + /* Fractional pixel MVs. */ + /* Note that we only use two pixel values even for the diagonal */ + Sub8Av2(FiltPtr, ReconPtr1,ReconPtr2,DctInputPtr, old_ptr1, + new_ptr1, PixelsPerLine, ReconPixelsPerLine ); + } +} + +void TransformQuantizeBlock (CP_INSTANCE *cpi, ogg_int32_t FragIndex, + ogg_uint32_t PixelsPerLine ) { + unsigned char *new_ptr1; /* Pointers into current frame */ + unsigned char *old_ptr1; /* Pointers into old frame */ + unsigned char *FiltPtr; /* Pointers to srf filtered pixels */ + ogg_int16_t *DctInputPtr; /* Pointer into buffer containing input to DCT */ + int LeftEdge; /* Flag if block at left edge of component */ + ogg_uint32_t ReconPixelsPerLine; /* Line length for recon buffers. */ + + unsigned char *ReconPtr1; /* DCT reconstructed image pointers */ + ogg_int32_t MvDevisor; /* Defines MV resolution (2 = 1/2 + pixel for Y or 4 = 1/4 for UV) */ + + new_ptr1 = &cpi->yuv1ptr[cpi->pb.pixel_index_table[FragIndex]]; + old_ptr1 = &cpi->yuv0ptr[cpi->pb.pixel_index_table[FragIndex]]; + DctInputPtr = cpi->DCTDataBuffer; + + /* Set plane specific values */ + if (FragIndex < (ogg_int32_t)cpi->pb.YPlaneFragments){ + ReconPixelsPerLine = cpi->pb.YStride; + MvDevisor = 2; /* 1/2 pixel accuracy in Y */ + }else{ + ReconPixelsPerLine = cpi->pb.UVStride; + MvDevisor = 4; /* UV planes at 1/2 resolution of Y */ + } + + /* adjusted / filtered pointers */ + FiltPtr = &cpi->ConvDestBuffer[cpi->pb.pixel_index_table[FragIndex]]; + + if ( GetFrameType(&cpi->pb) == BASE_FRAME ) { + /* Key frame so code block in INTRA mode. */ + cpi->pb.CodingMode = CODE_INTRA; + }else{ + /* Get Motion vector and mode for this block. */ + cpi->pb.CodingMode = cpi->pb.FragCodingMethod[FragIndex]; + } + + /* Selection of Quantiser matirx and set other plane related values. */ + if ( FragIndex < (ogg_int32_t)cpi->pb.YPlaneFragments ){ + LeftEdge = !(FragIndex%cpi->pb.HFragments); + + /* Select the approrpriate Y quantiser matrix */ + if ( cpi->pb.CodingMode == CODE_INTRA ) + select_Y_quantiser(&cpi->pb); + else + select_Inter_quantiser(&cpi->pb); + }else{ + LeftEdge = !((FragIndex-cpi->pb.YPlaneFragments)%(cpi->pb.HFragments>>1)); + + /* Select the approrpriate UV quantiser matrix */ + if ( cpi->pb.CodingMode == CODE_INTRA ) + select_UV_quantiser(&cpi->pb); + else + select_Inter_quantiser(&cpi->pb); + } + + if ( ModeUsesMC[cpi->pb.CodingMode] ){ + + MotionBlockDifference(cpi, FiltPtr, DctInputPtr, MvDevisor, + old_ptr1, new_ptr1, FragIndex, PixelsPerLine, + ReconPixelsPerLine); + + } else if ( (cpi->pb.CodingMode==CODE_INTER_NO_MV ) || + ( cpi->pb.CodingMode==CODE_USING_GOLDEN ) ) { + if ( cpi->pb.CodingMode==CODE_INTER_NO_MV ) { + ReconPtr1 = &cpi-> + pb.LastFrameRecon[cpi->pb.recon_pixel_index_table[FragIndex]]; + } else { + ReconPtr1 = &cpi-> + pb.GoldenFrame[cpi->pb.recon_pixel_index_table[FragIndex]]; + } + + Sub8( FiltPtr, ReconPtr1, DctInputPtr, old_ptr1, new_ptr1, + PixelsPerLine, ReconPixelsPerLine ); + } else if ( cpi->pb.CodingMode==CODE_INTRA ) { + Sub8_128(FiltPtr, DctInputPtr, old_ptr1, new_ptr1, PixelsPerLine); + + } + + /* Proceed to encode the data into the encode buffer if the encoder + is enabled. */ + /* Perform a 2D DCT transform on the data. */ + fdct_short( cpi->DCTDataBuffer, cpi->DCT_codes ); + + /* Quantize that transform data. */ + quantize ( &cpi->pb, cpi->DCT_codes, cpi->pb.QFragData[FragIndex] ); + + if ( (cpi->pb.CodingMode == CODE_INTER_NO_MV) && + ( AllZeroDctData(cpi->pb.QFragData[FragIndex]) ) ) { + cpi->pb.display_fragments[FragIndex] = 0; + } + +} diff --git a/src/add-ons/media/plugins/theora/libtheora/decode.c b/src/add-ons/media/plugins/theora/libtheora/decode.c new file mode 100644 index 0000000000..ce434f7532 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/decode.c @@ -0,0 +1,838 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: decode.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include "encoder_internal.h" +#include "block_inline.h" + +static const CODING_MODE ModeAlphabet[MODE_METHODS-2][MAX_MODES] = { + + /* Last motion vector dominates */ + { CODE_INTER_LAST_MV, CODE_INTER_PRIOR_LAST, + CODE_INTER_PLUS_MV, CODE_INTER_NO_MV, + CODE_INTRA, CODE_USING_GOLDEN, + CODE_GOLDEN_MV, CODE_INTER_FOURMV }, + + { CODE_INTER_LAST_MV, CODE_INTER_PRIOR_LAST, + CODE_INTER_NO_MV, CODE_INTER_PLUS_MV, + CODE_INTRA, CODE_USING_GOLDEN, + CODE_GOLDEN_MV, CODE_INTER_FOURMV }, + + { CODE_INTER_LAST_MV, CODE_INTER_PLUS_MV, + CODE_INTER_PRIOR_LAST, CODE_INTER_NO_MV, + CODE_INTRA, CODE_USING_GOLDEN, + CODE_GOLDEN_MV, CODE_INTER_FOURMV }, + + { CODE_INTER_LAST_MV, CODE_INTER_PLUS_MV, + CODE_INTER_NO_MV, CODE_INTER_PRIOR_LAST, + CODE_INTRA, CODE_USING_GOLDEN, + CODE_GOLDEN_MV, CODE_INTER_FOURMV }, + + /* No motion vector dominates */ + { CODE_INTER_NO_MV, CODE_INTER_LAST_MV, + CODE_INTER_PRIOR_LAST, CODE_INTER_PLUS_MV, + CODE_INTRA, CODE_USING_GOLDEN, + CODE_GOLDEN_MV, CODE_INTER_FOURMV }, + + { CODE_INTER_NO_MV, CODE_USING_GOLDEN, + CODE_INTER_LAST_MV, CODE_INTER_PRIOR_LAST, + CODE_INTER_PLUS_MV, CODE_INTRA, + CODE_GOLDEN_MV, CODE_INTER_FOURMV }, + +}; + +int GetFrameType(PB_INSTANCE *pbi){ + return pbi->FrameType; +} + +static int LoadFrameHeader(PB_INSTANCE *pbi){ + long ret; + unsigned char DctQMask; + unsigned char SpareBits; /* Spare cfg bits */ + + /* Is the frame and inter frame or a key frame */ + theora_read(pbi->opb,1,&ret); + pbi->FrameType = (unsigned char)ret; + + /* Quality (Q) index */ + theora_read(pbi->opb,6,&ret); + DctQMask = (unsigned char)ret; + + /* spare bit for possible additional Q indicies - should be 0 */ + theora_read(pbi->opb,1,&ret); + SpareBits = (unsigned char)ret; + + if ( (pbi->FrameType == BASE_FRAME) ){ + /* Read the type / coding method for the key frame. */ + theora_read(pbi->opb,1,&ret); + pbi->KeyFrameType = (unsigned char)ret; + + theora_read(pbi->opb,2,&ret); + SpareBits = (unsigned char)ret; + + } + + /* Set this frame quality value from Q Index */ + pbi->ThisFrameQualityValue = pbi->QThreshTable[DctQMask]; + + return 1; +} + +void SetFrameType( PB_INSTANCE *pbi,unsigned char FrType ){ + /* Set the appropriate frame type according to the request. */ + switch ( FrType ){ + + case BASE_FRAME: + pbi->FrameType = FrType; + break; + + default: + pbi->FrameType = FrType; + break; + } +} + +static int LoadFrame(PB_INSTANCE *pbi){ + + /* Load the frame header (including the frame size). */ + if ( LoadFrameHeader(pbi) ){ + /* Read in the updated block map */ + QuadDecodeDisplayFragments( pbi ); + return 1; + } + + return 0; +} + +static void DecodeModes (PB_INSTANCE *pbi, + ogg_uint32_t SBRows, + ogg_uint32_t SBCols){ + long ret; + ogg_int32_t FragIndex; + ogg_uint32_t MB; + ogg_uint32_t SBrow; + ogg_uint32_t SBcol; + ogg_uint32_t SB=0; + CODING_MODE CodingMethod; + + ogg_uint32_t UVRow; + ogg_uint32_t UVColumn; + ogg_uint32_t UVFragOffset; + + ogg_uint32_t CodingScheme; + + ogg_uint32_t MBListIndex = 0; + + ogg_uint32_t i; + + /* If the frame is an intra frame then all blocks have mode intra. */ + if ( GetFrameType(pbi) == BASE_FRAME ){ + for ( i = 0; i < pbi->UnitFragments; i++ ){ + pbi->FragCodingMethod[i] = CODE_INTRA; + } + }else{ + ogg_uint32_t ModeEntry; /* Mode bits read */ + CODING_MODE CustomModeAlphabet[MAX_MODES]; + const CODING_MODE *ModeList; + + /* Read the coding method */ + theora_read(pbi->opb, MODE_METHOD_BITS, &ret); + CodingScheme=ret; + + /* If the coding method is method 0 then we have to read in a + custom coding scheme */ + if ( CodingScheme == 0 ){ + /* Read the coding scheme. */ + for ( i = 0; i < MAX_MODES; i++ ){ + theora_read(pbi->opb, MODE_BITS, &ret); + CustomModeAlphabet[ret]=i; + } + ModeList=CustomModeAlphabet; + } + else{ + ModeList=ModeAlphabet[CodingScheme-1]; + } + + /* Unravel the quad-tree */ + for ( SBrow=0; SBrowBlockMap, SB,MB) >= 0){ + /* Is the Macro-Block coded: */ + if ( pbi->MBCodedFlags[MBListIndex++] ){ + /* Upack the block level modes and motion vectors */ + FragIndex = QuadMapToMBTopLeft( pbi->BlockMap, SB, MB ); + + /* Unpack the mode. */ + if ( CodingScheme == (MODE_METHODS-1) ){ + /* This is the fall back coding scheme. */ + /* Simply MODE_BITS bits per mode entry. */ + theora_read(pbi->opb, MODE_BITS, &ret); + CodingMethod = (CODING_MODE)ret; + }else{ + ModeEntry = FrArrayUnpackMode(pbi); + CodingMethod = ModeList[ModeEntry]; + } + + /* Note the coding mode for each block in macro block. */ + pbi->FragCodingMethod[FragIndex] = CodingMethod; + pbi->FragCodingMethod[FragIndex + 1] = CodingMethod; + pbi->FragCodingMethod[FragIndex + pbi->HFragments] = + CodingMethod; + pbi->FragCodingMethod[FragIndex + pbi->HFragments + 1] = + CodingMethod; + + /* Matching fragments in the U and V planes */ + UVRow = (FragIndex / (pbi->HFragments * 2)); + UVColumn = (FragIndex % pbi->HFragments) / 2; + UVFragOffset = (UVRow * (pbi->HFragments / 2)) + UVColumn; + pbi->FragCodingMethod[pbi->YPlaneFragments + UVFragOffset] = + CodingMethod; + pbi->FragCodingMethod[pbi->YPlaneFragments + + pbi->UVPlaneFragments + UVFragOffset] = + CodingMethod; + + } + } + } + + /* Next Super-Block */ + SB++; + } + } + } +} + +static ogg_int32_t ExtractMVectorComponentA(PB_INSTANCE *pbi){ + long ret; + ogg_int32_t MVectComponent; + ogg_uint32_t MVCode = 0; + ogg_uint32_t ExtraBits = 0; + + /* Get group to which coded component belongs */ + theora_read(pbi->opb, 3, &ret); + MVCode=ret; + + /* Now extract the appropriate number of bits to identify the component */ + switch ( MVCode ){ + case 0: + MVectComponent = 0; + break; + case 1: + MVectComponent = 1; + break; + case 2: + MVectComponent = -1; + break; + case 3: + theora_read(pbi->opb,1,&ret); + if (ret) + MVectComponent = -2; + else + MVectComponent = 2; + break; + case 4: + theora_read(pbi->opb,1,&ret); + if (ret) + MVectComponent = -3; + else + MVectComponent = 3; + break; + case 5: + theora_read(pbi->opb,2,&ret); + ExtraBits=ret; + MVectComponent = 4 + ExtraBits; + theora_read(pbi->opb,1,&ret); + if (ret) + MVectComponent = -MVectComponent; + break; + case 6: + theora_read(pbi->opb,3,&ret); + ExtraBits=ret; + MVectComponent = 8 + ExtraBits; + theora_read(pbi->opb,1,&ret); + if (ret) + MVectComponent = -MVectComponent; + break; + case 7: + theora_read(pbi->opb,4,&ret); + ExtraBits=ret; + MVectComponent = 16 + ExtraBits; + theora_read(pbi->opb,1,&ret); + if (ret) + MVectComponent = -MVectComponent; + break; + } + + return MVectComponent; +} + +static ogg_int32_t ExtractMVectorComponentB(PB_INSTANCE *pbi){ + long ret; + ogg_int32_t MVectComponent; + + /* Get group to which coded component belongs */ + theora_read(pbi->opb,5,&ret); + MVectComponent=ret; + theora_read(pbi->opb,1,&ret); + if (ret) + MVectComponent = -MVectComponent; + + return MVectComponent; +} + +static void DecodeMVectors ( PB_INSTANCE *pbi, + ogg_uint32_t SBRows, + ogg_uint32_t SBCols ){ + long ret; + ogg_int32_t FragIndex; + ogg_uint32_t MB; + ogg_uint32_t SBrow; + ogg_uint32_t SBcol; + ogg_uint32_t SB=0; + ogg_uint32_t CodingMethod; + + MOTION_VECTOR MVect[6]; + MOTION_VECTOR TmpMVect; + MOTION_VECTOR LastInterMV; + MOTION_VECTOR PriorLastInterMV; + ogg_int32_t (*ExtractMVectorComponent)(PB_INSTANCE *pbi); + + ogg_uint32_t UVRow; + ogg_uint32_t UVColumn; + ogg_uint32_t UVFragOffset; + + ogg_uint32_t MBListIndex = 0; + + /* Should not be decoding motion vectors if in INTRA only mode. */ + if ( GetFrameType(pbi) == BASE_FRAME ){ + return; + } + + /* set the default motion vector to 0,0 */ + MVect[0].x = 0; + MVect[0].y = 0; + LastInterMV.x = 0; + LastInterMV.y = 0; + PriorLastInterMV.x = 0; + PriorLastInterMV.y = 0; + + /* Read the entropy method used and set up the appropriate decode option */ + theora_read(pbi->opb, 1, &ret); + if ( ret == 0 ) + ExtractMVectorComponent = ExtractMVectorComponentA; + else + ExtractMVectorComponent = ExtractMVectorComponentB; + + /* Unravel the quad-tree */ + for ( SBrow=0; SBrowBlockMap, SB,MB) >= 0 ) { + /* Is the Macro-Block further coded: */ + if ( pbi->MBCodedFlags[MBListIndex++] ){ + /* Upack the block level modes and motion vectors */ + FragIndex = QuadMapToMBTopLeft( pbi->BlockMap, SB, MB ); + + /* Clear the motion vector before we start. */ + MVect[0].x = 0; + MVect[0].y = 0; + + /* Unpack the mode (and motion vectors if necessary). */ + CodingMethod = pbi->FragCodingMethod[FragIndex]; + + /* Read the motion vector or vectors if present. */ + if ( (CodingMethod == CODE_INTER_PLUS_MV) || + (CodingMethod == CODE_GOLDEN_MV) ){ + MVect[0].x = ExtractMVectorComponent(pbi); + MVect[1].x = MVect[0].x; + MVect[2].x = MVect[0].x; + MVect[3].x = MVect[0].x; + MVect[4].x = MVect[0].x; + MVect[5].x = MVect[0].x; + MVect[0].y = ExtractMVectorComponent(pbi); + MVect[1].y = MVect[0].y; + MVect[2].y = MVect[0].y; + MVect[3].y = MVect[0].y; + MVect[4].y = MVect[0].y; + MVect[5].y = MVect[0].y; + }else if ( CodingMethod == CODE_INTER_FOURMV ){ + /* Extrac the 4 Y MVs */ + MVect[0].x = ExtractMVectorComponent(pbi); + MVect[0].y = ExtractMVectorComponent(pbi); + + MVect[1].x = ExtractMVectorComponent(pbi); + MVect[1].y = ExtractMVectorComponent(pbi); + + MVect[2].x = ExtractMVectorComponent(pbi); + MVect[2].y = ExtractMVectorComponent(pbi); + + MVect[3].x = ExtractMVectorComponent(pbi); + MVect[3].y = ExtractMVectorComponent(pbi); + + /* Calculate the U and V plane MVs as the average of the + Y plane MVs. */ + /* First .x component */ + MVect[4].x = MVect[0].x + MVect[1].x + MVect[2].x + MVect[3].x; + if ( MVect[4].x >= 0 ) + MVect[4].x = (MVect[4].x + 2) / 4; + else + MVect[4].x = (MVect[4].x - 2) / 4; + MVect[5].x = MVect[4].x; + /* Then .y component */ + MVect[4].y = MVect[0].y + MVect[1].y + MVect[2].y + MVect[3].y; + if ( MVect[4].y >= 0 ) + MVect[4].y = (MVect[4].y + 2) / 4; + else + MVect[4].y = (MVect[4].y - 2) / 4; + MVect[5].y = MVect[4].y; + } + + /* Keep track of last and prior last inter motion vectors. */ + if ( CodingMethod == CODE_INTER_PLUS_MV ){ + PriorLastInterMV.x = LastInterMV.x; + PriorLastInterMV.y = LastInterMV.y; + LastInterMV.x = MVect[0].x; + LastInterMV.y = MVect[0].y; + }else if ( CodingMethod == CODE_INTER_LAST_MV ){ + /* Use the last coded Inter motion vector. */ + MVect[0].x = LastInterMV.x; + MVect[1].x = MVect[0].x; + MVect[2].x = MVect[0].x; + MVect[3].x = MVect[0].x; + MVect[4].x = MVect[0].x; + MVect[5].x = MVect[0].x; + MVect[0].y = LastInterMV.y; + MVect[1].y = MVect[0].y; + MVect[2].y = MVect[0].y; + MVect[3].y = MVect[0].y; + MVect[4].y = MVect[0].y; + MVect[5].y = MVect[0].y; + }else if ( CodingMethod == CODE_INTER_PRIOR_LAST ){ + /* Use the next-to-last coded Inter motion vector. */ + MVect[0].x = PriorLastInterMV.x; + MVect[1].x = MVect[0].x; + MVect[2].x = MVect[0].x; + MVect[3].x = MVect[0].x; + MVect[4].x = MVect[0].x; + MVect[5].x = MVect[0].x; + MVect[0].y = PriorLastInterMV.y; + MVect[1].y = MVect[0].y; + MVect[2].y = MVect[0].y; + MVect[3].y = MVect[0].y; + MVect[4].y = MVect[0].y; + MVect[5].y = MVect[0].y; + + /* Swap the prior and last MV cases over */ + TmpMVect.x = PriorLastInterMV.x; + TmpMVect.y = PriorLastInterMV.y; + PriorLastInterMV.x = LastInterMV.x; + PriorLastInterMV.y = LastInterMV.y; + LastInterMV.x = TmpMVect.x; + LastInterMV.y = TmpMVect.y; + }else if ( CodingMethod == CODE_INTER_FOURMV ){ + /* Update last MV and prior last mv */ + PriorLastInterMV.x = LastInterMV.x; + PriorLastInterMV.y = LastInterMV.y; + LastInterMV.x = MVect[3].x; + LastInterMV.y = MVect[3].y; + } + + /* Note the coding mode and vector for each block in the + current macro block. */ + pbi->FragMVect[FragIndex].x = MVect[0].x; + pbi->FragMVect[FragIndex].y = MVect[0].y; + + pbi->FragMVect[FragIndex + 1].x = MVect[1].x; + pbi->FragMVect[FragIndex + 1].y = MVect[1].y; + + pbi->FragMVect[FragIndex + pbi->HFragments].x = MVect[2].x; + pbi->FragMVect[FragIndex + pbi->HFragments].y = MVect[2].y; + + pbi->FragMVect[FragIndex + pbi->HFragments + 1].x = MVect[3].x; + pbi->FragMVect[FragIndex + pbi->HFragments + 1].y = MVect[3].y; + + /* Matching fragments in the U and V planes */ + UVRow = (FragIndex / (pbi->HFragments * 2)); + UVColumn = (FragIndex % pbi->HFragments) / 2; + UVFragOffset = (UVRow * (pbi->HFragments / 2)) + UVColumn; + + pbi->FragMVect[pbi->YPlaneFragments + UVFragOffset].x = MVect[4].x; + pbi->FragMVect[pbi->YPlaneFragments + UVFragOffset].y = MVect[4].y; + + pbi->FragMVect[pbi->YPlaneFragments + pbi->UVPlaneFragments + + UVFragOffset].x = MVect[5].x; + pbi->FragMVect[pbi->YPlaneFragments + pbi->UVPlaneFragments + + UVFragOffset].y = MVect[5].y; + } + } + } + + /* Next Super-Block */ + SB++; + } + } +} + +static ogg_uint32_t ExtractToken(oggpack_buffer *opb, + HUFF_ENTRY * CurrentRoot){ + long ret; + ogg_uint32_t Token; + /* Loop searches down through tree based upon bits read from the + bitstream */ + /* until it hits a leaf at which point we have decoded a token */ + while ( CurrentRoot->Value < 0 ){ + + theora_read(opb, 1, &ret); + if (ret) + CurrentRoot = CurrentRoot->OneChild; + else + CurrentRoot = CurrentRoot->ZeroChild; + + } + Token = CurrentRoot->Value; + return Token; +} + +static void UnpackAndExpandDcToken( PB_INSTANCE *pbi, + Q_LIST_ENTRY *ExpandedBlock, + unsigned char * CoeffIndex ){ + long ret; + ogg_int32_t ExtraBits = 0; + ogg_uint32_t Token; + + Token = ExtractToken(pbi->opb, pbi->HuffRoot_VP3x[pbi->DcHuffChoice]); + + + /* Now.. if we are using the DCT optimised coding system, extract any + * assosciated additional bits token. + */ + if ( pbi->ExtraBitLengths_VP3x[Token] > 0 ){ + /* Extract the appropriate number of extra bits. */ + theora_read(pbi->opb,pbi->ExtraBitLengths_VP3x[Token], &ret); + ExtraBits = ret; + } + + /* Take token dependant action */ + if ( Token >= DCT_SHORT_ZRL_TOKEN ) { + /* "Value", "zero run" and "zero run value" tokens */ + ExpandToken(ExpandedBlock, CoeffIndex, Token, ExtraBits ); + if ( *CoeffIndex >= BLOCK_SIZE ) + pbi->BlocksToDecode --; + } else if ( Token == DCT_EOB_TOKEN ){ + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + }else{ + /* Special action and EOB tokens */ + switch ( Token ){ + case DCT_EOB_PAIR_TOKEN: + pbi->EOB_Run = 1; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_EOB_TRIPLE_TOKEN: + pbi->EOB_Run = 2; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN_TOKEN: + pbi->EOB_Run = ExtraBits + 3; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN2_TOKEN: + pbi->EOB_Run = ExtraBits + 7; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN3_TOKEN: + pbi->EOB_Run = ExtraBits + 15; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN4_TOKEN: + pbi->EOB_Run = ExtraBits - 1; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + } + } +} + +static void UnpackAndExpandAcToken( PB_INSTANCE *pbi, + Q_LIST_ENTRY * ExpandedBlock, + unsigned char * CoeffIndex ) { + long ret; + ogg_int32_t ExtraBits = 0; + ogg_uint32_t Token; + + Token = ExtractToken(pbi->opb, pbi->HuffRoot_VP3x[pbi->ACHuffChoice]); + + /* Now.. if we are using the DCT optimised coding system, extract any + * assosciated additional bits token. + */ + if ( pbi->ExtraBitLengths_VP3x[Token] > 0 ){ + /* Extract the appropriate number of extra bits. */ + theora_read(pbi->opb,pbi->ExtraBitLengths_VP3x[Token], &ret); + ExtraBits = ret; + } + + /* Take token dependant action */ + if ( Token >= DCT_SHORT_ZRL_TOKEN ){ + /* "Value", "zero run" and "zero run value" tokens */ + ExpandToken(ExpandedBlock, CoeffIndex, Token, ExtraBits ); + if ( *CoeffIndex >= BLOCK_SIZE ) + pbi->BlocksToDecode --; + } else if ( Token == DCT_EOB_TOKEN ) { + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + } else { + /* Special action and EOB tokens */ + switch ( Token ) { + case DCT_EOB_PAIR_TOKEN: + pbi->EOB_Run = 1; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_EOB_TRIPLE_TOKEN: + pbi->EOB_Run = 2; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN_TOKEN: + pbi->EOB_Run = ExtraBits + 3; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN2_TOKEN: + pbi->EOB_Run = ExtraBits + 7; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN3_TOKEN: + pbi->EOB_Run = ExtraBits + 15; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + case DCT_REPEAT_RUN4_TOKEN: + pbi->EOB_Run = ExtraBits - 1; + *CoeffIndex = BLOCK_SIZE; + pbi->BlocksToDecode --; + break; + } + } +} + +static void UnPackVideo (PB_INSTANCE *pbi){ + long ret; + ogg_int32_t EncodedCoeffs = 1; + ogg_int32_t FragIndex; + ogg_int32_t * CodedBlockListPtr; + ogg_int32_t * CodedBlockListEnd; + + unsigned char AcHuffIndex1; + unsigned char AcHuffIndex2; + unsigned char AcHuffChoice1; + unsigned char AcHuffChoice2; + + unsigned char DcHuffChoice1; + unsigned char DcHuffChoice2; + + + /* Bail out immediately if a decode error has already been reported. */ + if ( pbi->DecoderErrorCode ) return; + + /* Clear down the array that indicates the current coefficient index + for each block. */ + memset(pbi->FragCoeffs, 0, pbi->UnitFragments); + memset(pbi->FragCoefEOB, 0, pbi->UnitFragments); + + /* Clear down the pbi->QFragData structure for all coded blocks. */ + ClearDownQFragData(pbi); + + /* Note the number of blocks to decode */ + pbi->BlocksToDecode = pbi->CodedBlockIndex; + + /* Get the DC huffman table choice for Y and then UV */ + theora_read(pbi->opb,DC_HUFF_CHOICE_BITS,&ret); + DcHuffChoice1 = ret + DC_HUFF_OFFSET; + theora_read(pbi->opb,DC_HUFF_CHOICE_BITS,&ret); + DcHuffChoice2 = ret + DC_HUFF_OFFSET; + + /* UnPack DC coefficients / tokens */ + CodedBlockListPtr = pbi->CodedBlockList; + CodedBlockListEnd = &pbi->CodedBlockList[pbi->CodedBlockIndex]; + while ( CodedBlockListPtr < CodedBlockListEnd ) { + /* Get the block data index */ + FragIndex = *CodedBlockListPtr; + pbi->FragCoefEOB[FragIndex] = pbi->FragCoeffs[FragIndex]; + + /* Select the appropriate huffman table offset according to + whether the token is from a Y or UV block */ + if ( FragIndex < (ogg_int32_t)pbi->YPlaneFragments ) + pbi->DcHuffChoice = DcHuffChoice1; + else + pbi->DcHuffChoice = DcHuffChoice2; + + /* If we are in the middle of an EOB run */ + if ( pbi->EOB_Run ){ + /* Mark the current block as fully expanded and decrement + EOB_RUN count */ + pbi->FragCoeffs[FragIndex] = BLOCK_SIZE; + pbi->EOB_Run --; + pbi->BlocksToDecode --; + }else{ + /* Else unpack a DC token */ + UnpackAndExpandDcToken( pbi, + pbi->QFragData[FragIndex], + &pbi->FragCoeffs[FragIndex] ); + } + CodedBlockListPtr++; + } + + /* Get the AC huffman table choice for Y and then for UV. */ + + theora_read(pbi->opb,AC_HUFF_CHOICE_BITS,&ret); + AcHuffIndex1 = ret + AC_HUFF_OFFSET; + theora_read(pbi->opb,AC_HUFF_CHOICE_BITS,&ret); + AcHuffIndex2 = ret + AC_HUFF_OFFSET; + + /* Unpack Lower AC coefficients. */ + while ( EncodedCoeffs < 64 ) { + /* Repeatedly scan through the list of blocks. */ + CodedBlockListPtr = pbi->CodedBlockList; + CodedBlockListEnd = &pbi->CodedBlockList[pbi->CodedBlockIndex]; + + /* Huffman table selection based upon which AC coefficient we are on */ + if ( EncodedCoeffs <= AC_TABLE_2_THRESH ){ + AcHuffChoice1 = AcHuffIndex1; + AcHuffChoice2 = AcHuffIndex2; + }else if ( EncodedCoeffs <= AC_TABLE_3_THRESH ){ + AcHuffChoice1 = AcHuffIndex1 + AC_HUFF_CHOICES; + AcHuffChoice2 = AcHuffIndex2 + AC_HUFF_CHOICES; + } else if ( EncodedCoeffs <= AC_TABLE_4_THRESH ){ + AcHuffChoice1 = AcHuffIndex1 + (AC_HUFF_CHOICES * 2); + AcHuffChoice2 = AcHuffIndex2 + (AC_HUFF_CHOICES * 2); + } else { + AcHuffChoice1 = AcHuffIndex1 + (AC_HUFF_CHOICES * 3); + AcHuffChoice2 = AcHuffIndex2 + (AC_HUFF_CHOICES * 3); + } + + while( CodedBlockListPtr < CodedBlockListEnd ) { + /* Get the linear index for the current fragment. */ + FragIndex = *CodedBlockListPtr; + + /* Should we decode a token for this block on this pass. */ + if ( pbi->FragCoeffs[FragIndex] <= EncodedCoeffs ) { + pbi->FragCoefEOB[FragIndex] = pbi->FragCoeffs[FragIndex]; + /* If we are in the middle of an EOB run */ + if ( pbi->EOB_Run ) { + /* Mark the current block as fully expanded and decrement + EOB_RUN count */ + pbi->FragCoeffs[FragIndex] = BLOCK_SIZE; + pbi->EOB_Run --; + pbi->BlocksToDecode --; + }else{ + /* Else unpack an AC token */ + /* Work out which huffman table to use, then decode a token */ + if ( FragIndex < (ogg_int32_t)pbi->YPlaneFragments ) + pbi->ACHuffChoice = AcHuffChoice1; + else + pbi->ACHuffChoice = AcHuffChoice2; + + UnpackAndExpandAcToken( pbi, pbi->QFragData[FragIndex], + &pbi->FragCoeffs[FragIndex] ); + } + } + CodedBlockListPtr++; + } + + /* Test for condition where there are no blocks left with any + tokesn to decode */ + if ( !pbi->BlocksToDecode ) + break; + + EncodedCoeffs ++; + } +} + +static void DecodeData(PB_INSTANCE *pbi){ + ogg_uint32_t i; + + /* Bail out immediately if a decode error has already been reported. */ + if ( pbi->DecoderErrorCode ) return; + + /* Clear down the macro block level mode and MV arrays. */ + for ( i = 0; i < pbi->UnitFragments; i++ ){ + pbi->FragCodingMethod[i] = CODE_INTER_NO_MV; /* Default coding mode */ + pbi->FragMVect[i].x = 0; + pbi->FragMVect[i].y = 0; + } + + /* Zero Decoder EOB run count */ + pbi->EOB_Run = 0; + + /* Make a not of the number of coded blocks this frame */ + pbi->CodedBlocksThisFrame = pbi->CodedBlockIndex; + + /* Decode the modes data */ + DecodeModes( pbi, pbi->YSBRows, pbi->YSBCols); + + /* Unpack and decode the motion vectors. */ + DecodeMVectors ( pbi, pbi->YSBRows, pbi->YSBCols); + + /* Unpack and decode the actual video data. */ + UnPackVideo(pbi); + + /* Reconstruct and display the frame */ + ReconRefFrames(pbi); + +} + + +int LoadAndDecode(PB_INSTANCE *pbi){ + int LoadFrameOK; + + /* Reset the DC predictors. */ + pbi->InvLastIntraDC = 0; + pbi->InvLastInterDC = 0; + + /* Load the next frame. */ + LoadFrameOK = LoadFrame(pbi); + + if ( LoadFrameOK ){ + if ( (pbi->ThisFrameQualityValue != pbi->LastFrameQualityValue) ){ + /* Initialise DCT tables. */ + UpdateQ( pbi, pbi->ThisFrameQualityValue ); + pbi->LastFrameQualityValue = pbi->ThisFrameQualityValue; + } + + + /* Decode the data into the fragment buffer. */ + DecodeData(pbi); + return(0); + } + + return(OC_BADPACKET); +} diff --git a/src/add-ons/media/plugins/theora/libtheora/encode.c b/src/add-ons/media/plugins/theora/libtheora/encode.c new file mode 100644 index 0000000000..553c451177 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/encode.c @@ -0,0 +1,1491 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: encode.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include "encoder_internal.h" +#include "encoder_lookup.h" +#include "block_inline.h" + +#define PUR 8 +#define PU 4 +#define PUL 2 +#define PL 1 +#define HIGHBITDUPPED(X) (((ogg_int16_t) X) >> 15) + +static ogg_uint32_t QuadCodeComponent ( CP_INSTANCE *cpi, + ogg_uint32_t FirstSB, + ogg_uint32_t SBRows, + ogg_uint32_t SBCols, + ogg_uint32_t PixelsPerLine ){ + + ogg_int32_t FragIndex; /* Fragment number */ + ogg_uint32_t MB, B; /* Macro-Block, Block indices */ + ogg_uint32_t SBrow; /* Super-Block row number */ + ogg_uint32_t SBcol; /* Super-Block row number */ + ogg_uint32_t SB=FirstSB; /* Super-Block index, initialised to first + of this component */ + ogg_uint32_t coded_pixels=0; /* Number of pixels coded */ + int MBCodedFlag; + + /* actually transform and quantize the image now that we've decided + on the modes Parse in quad-tree ordering */ + + SB=FirstSB; + for ( SBrow=0; SBrowpb.BlockMap,SB,MB) >= 0 ) { + + MBCodedFlag = 0; + + /* Now actually code the blocks */ + for ( B=0; B<4; B++ ) { + FragIndex = QuadMapToIndex1( cpi->pb.BlockMap, SB, MB, B ); + + /* Does Block lie in frame: */ + if ( FragIndex >= 0 ) { + /* In Frame: Is it coded: */ + if ( cpi->pb.display_fragments[FragIndex] ) { + + /* transform and quantize block */ + TransformQuantizeBlock( cpi, FragIndex, PixelsPerLine ); + + /* Has the block got struck off (no MV and no data + generated after DCT) If not then mark it and the + assosciated MB as coded. */ + if ( cpi->pb.display_fragments[FragIndex] ) { + /* Create linear list of coded block indices */ + cpi->pb.CodedBlockList[cpi->pb.CodedBlockIndex] = FragIndex; + cpi->pb.CodedBlockIndex++; + + /* MB is still coded */ + MBCodedFlag = 1; + cpi->MBCodingMode = cpi->pb.FragCodingMethod[FragIndex]; + + } + } + } + } + /* If the MB is marked as coded and we are in the Y plane then */ + /* the mode list needs to be updated. */ + if ( MBCodedFlag && (FirstSB == 0) ){ + /* Make a note of the selected mode in the mode list */ + cpi->ModeList[cpi->ModeListCount] = cpi->MBCodingMode; + cpi->ModeListCount++; + } + } + } + + SB++; + + } + } + + /* Return number of pixels coded */ + return coded_pixels; +} + +static void EncodeDcTokenList (CP_INSTANCE *cpi) { + ogg_int32_t i,j; + ogg_uint32_t Token; + ogg_uint32_t ExtraBitsToken; + ogg_uint32_t HuffIndex; + + ogg_uint32_t BestDcBits; + ogg_uint32_t DcHuffChoice[2]; + ogg_uint32_t EntropyTableBits[2][DC_HUFF_CHOICES]; + + oggpack_buffer *opb=cpi->oggbuffer; + + /* Clear table data structure */ + memset ( EntropyTableBits, 0, sizeof(ogg_uint32_t)*DC_HUFF_CHOICES*2 ); + + /* Analyse token list to see which is the best entropy table to use */ + for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) { + /* Count number of bits for each table option */ + Token = (ogg_uint32_t)cpi->OptimisedTokenList[i]; + for ( j = 0; j < DC_HUFF_CHOICES; j++ ){ + EntropyTableBits[cpi->OptimisedTokenListPl[i]][j] += + cpi->pb.HuffCodeLengthArray_VP3x[DC_HUFF_OFFSET + j][Token]; + } + } + + /* Work out which table option is best for Y */ + BestDcBits = EntropyTableBits[0][0]; + DcHuffChoice[0] = 0; + for ( j = 1; j < DC_HUFF_CHOICES; j++ ) { + if ( EntropyTableBits[0][j] < BestDcBits ) { + BestDcBits = EntropyTableBits[0][j]; + DcHuffChoice[0] = j; + } + } + + /* Add the DC huffman table choice to the bitstream */ + oggpackB_write( opb, DcHuffChoice[0], DC_HUFF_CHOICE_BITS ); + + /* Work out which table option is best for UV */ + BestDcBits = EntropyTableBits[1][0]; + DcHuffChoice[1] = 0; + for ( j = 1; j < DC_HUFF_CHOICES; j++ ) { + if ( EntropyTableBits[1][j] < BestDcBits ) { + BestDcBits = EntropyTableBits[1][j]; + DcHuffChoice[1] = j; + } + } + + /* Add the DC huffman table choice to the bitstream */ + oggpackB_write( opb, DcHuffChoice[1], DC_HUFF_CHOICE_BITS ); + + /* Encode the token list */ + for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) { + + /* Get the token and extra bits */ + Token = (ogg_uint32_t)cpi->OptimisedTokenList[i]; + ExtraBitsToken = (ogg_uint32_t)cpi->OptimisedTokenListEb[i]; + + /* Select the huffman table */ + if ( cpi->OptimisedTokenListPl[i] == 0) + HuffIndex = (ogg_uint32_t)DC_HUFF_OFFSET + (ogg_uint32_t)DcHuffChoice[0]; + else + HuffIndex = (ogg_uint32_t)DC_HUFF_OFFSET + (ogg_uint32_t)DcHuffChoice[1]; + + /* Add the bits to the encode holding buffer. */ + cpi->FrameBitCount += cpi->pb.HuffCodeLengthArray_VP3x[HuffIndex][Token]; + oggpackB_write( opb, cpi->pb.HuffCodeArray_VP3x[HuffIndex][Token], + (ogg_uint32_t)cpi-> + pb.HuffCodeLengthArray_VP3x[HuffIndex][Token] ); + + /* If the token is followed by an extra bits token then code it */ + if ( cpi->pb.ExtraBitLengths_VP3x[Token] > 0 ) { + /* Add the bits to the encode holding buffer. */ + cpi->FrameBitCount += cpi->pb.ExtraBitLengths_VP3x[Token]; + oggpackB_write( opb, ExtraBitsToken, + (ogg_uint32_t)cpi->pb.ExtraBitLengths_VP3x[Token] ); + } + } + + /* Reset the count of second order optimised tokens */ + cpi->OptimisedTokenCount = 0; +} + +static void EncodeAcTokenList (CP_INSTANCE *cpi) { + ogg_int32_t i,j; + ogg_uint32_t Token; + ogg_uint32_t ExtraBitsToken; + ogg_uint32_t HuffIndex; + + ogg_uint32_t BestAcBits; + ogg_uint32_t AcHuffChoice[2]; + ogg_uint32_t EntropyTableBits[2][AC_HUFF_CHOICES]; + + oggpack_buffer *opb=cpi->oggbuffer; + + memset ( EntropyTableBits, 0, sizeof(ogg_uint32_t)*AC_HUFF_CHOICES*2 ); + + /* Analyse token list to see which is the best entropy table to use */ + for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) { + /* Count number of bits for each table option */ + Token = (ogg_uint32_t)cpi->OptimisedTokenList[i]; + HuffIndex = cpi->OptimisedTokenListHi[i]; + for ( j = 0; j < AC_HUFF_CHOICES; j++ ) { + EntropyTableBits[cpi->OptimisedTokenListPl[i]][j] += + cpi->pb.HuffCodeLengthArray_VP3x[HuffIndex + j][Token]; + } + } + + /* Select the best set of AC tables for Y */ + BestAcBits = EntropyTableBits[0][0]; + AcHuffChoice[0] = 0; + for ( j = 1; j < AC_HUFF_CHOICES; j++ ) { + if ( EntropyTableBits[0][j] < BestAcBits ) { + BestAcBits = EntropyTableBits[0][j]; + AcHuffChoice[0] = j; + } + } + + /* Add the AC-Y huffman table choice to the bitstream */ + oggpackB_write( opb, AcHuffChoice[0], AC_HUFF_CHOICE_BITS ); + + /* Select the best set of AC tables for UV */ + BestAcBits = EntropyTableBits[1][0]; + AcHuffChoice[1] = 0; + for ( j = 1; j < AC_HUFF_CHOICES; j++ ) { + if ( EntropyTableBits[1][j] < BestAcBits ) { + BestAcBits = EntropyTableBits[1][j]; + AcHuffChoice[1] = j; + } + } + + /* Add the AC-UV huffman table choice to the bitstream */ + oggpackB_write( opb, AcHuffChoice[1], AC_HUFF_CHOICE_BITS ); + + /* Encode the token list */ + for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) { + /* Get the token and extra bits */ + Token = (ogg_uint32_t)cpi->OptimisedTokenList[i]; + ExtraBitsToken = (ogg_uint32_t)cpi->OptimisedTokenListEb[i]; + + /* Select the huffman table */ + HuffIndex = (ogg_uint32_t)cpi->OptimisedTokenListHi[i] + + AcHuffChoice[cpi->OptimisedTokenListPl[i]]; + + /* Add the bits to the encode holding buffer. */ + cpi->FrameBitCount += cpi->pb.HuffCodeLengthArray_VP3x[HuffIndex][Token]; + oggpackB_write( opb, cpi->pb.HuffCodeArray_VP3x[HuffIndex][Token], + (ogg_uint32_t)cpi-> + pb.HuffCodeLengthArray_VP3x[HuffIndex][Token] ); + + /* If the token is followed by an extra bits token then code it */ + if ( cpi->pb.ExtraBitLengths_VP3x[Token] > 0 ) { + /* Add the bits to the encode holding buffer. */ + cpi->FrameBitCount += cpi->pb.ExtraBitLengths_VP3x[Token]; + oggpackB_write( opb, ExtraBitsToken, + (ogg_uint32_t)cpi->pb.ExtraBitLengths_VP3x[Token] ); + } + } + + /* Reset the count of second order optimised tokens */ + cpi->OptimisedTokenCount = 0; +} + +static void PackModes (CP_INSTANCE *cpi) { + ogg_uint32_t i,j; + unsigned char ModeIndex; + unsigned char *SchemeList; + + unsigned char BestModeSchemes[MAX_MODES]; + ogg_int32_t ModeCount[MAX_MODES]; + ogg_int32_t TmpFreq = -1; + ogg_int32_t TmpIndex = -1; + + ogg_uint32_t BestScheme; + ogg_uint32_t BestSchemeScore; + ogg_uint32_t SchemeScore; + + oggpack_buffer *opb=cpi->oggbuffer; + + /* Build a frequency map for the modes in this frame */ + memset( ModeCount, 0, MAX_MODES*sizeof(ogg_int32_t) ); + for ( i = 0; i < cpi->ModeListCount; i++ ) + ModeCount[cpi->ModeList[i]] ++; + + /* Order the modes from most to least frequent. Store result as + scheme 0 */ + for ( j = 0; j < MAX_MODES; j++ ) { + TmpFreq = -1; /* need to re-initialize for each loop */ + /* Find the most frequent */ + for ( i = 0; i < MAX_MODES; i++ ) { + /* Is this the best scheme so far ??? */ + if ( ModeCount[i] > TmpFreq ) { + TmpFreq = ModeCount[i]; + TmpIndex = i; + } + } + /* I don't know if the above loop ever fails to match, but it's + better safe than sorry. Plus this takes care of gcc warning */ + if ( TmpIndex != -1 ) { + ModeCount[TmpIndex] = -1; + BestModeSchemes[TmpIndex] = (unsigned char)j; + } + } + + /* Default/ fallback scheme uses MODE_BITS bits per mode entry */ + BestScheme = (MODE_METHODS - 1); + BestSchemeScore = cpi->ModeListCount * 3; + /* Get a bit score for the available schemes. */ + for ( j = 0; j < (MODE_METHODS - 1); j++ ) { + + /* Reset the scheme score */ + if ( j == 0 ){ + /* Scheme 0 additional cost of sending frequency order */ + SchemeScore = 24; + SchemeList = BestModeSchemes; + } else { + SchemeScore = 0; + SchemeList = ModeSchemes[j-1]; + } + + /* Find the total bits to code using each avaialable scheme */ + for ( i = 0; i < cpi->ModeListCount; i++ ) + SchemeScore += ModeBitLengths[SchemeList[cpi->ModeList[i]]]; + + /* Is this the best scheme so far ??? */ + if ( SchemeScore < BestSchemeScore ) { + BestSchemeScore = SchemeScore; + BestScheme = j; + } + } + + /* Encode the best scheme. */ + oggpackB_write( opb, BestScheme, (ogg_uint32_t)MODE_METHOD_BITS ); + + /* If the chosen schems is scheme 0 send details of the mode + frequency order */ + if ( BestScheme == 0 ) { + for ( j = 0; j < MAX_MODES; j++ ) + /* Note that the last two entries are implicit */ + oggpackB_write( opb, BestModeSchemes[j], (ogg_uint32_t)MODE_BITS ); + SchemeList = BestModeSchemes; + } + else { + SchemeList = ModeSchemes[BestScheme-1]; + } + + /* Are we using one of the alphabet based schemes or the fallback scheme */ + if ( BestScheme < (MODE_METHODS - 1)) { + /* Pack and encode the Mode list */ + for ( i = 0; i < cpi->ModeListCount; i++ ) { + /* Add the appropriate mode entropy token. */ + ModeIndex = SchemeList[cpi->ModeList[i]]; + oggpackB_write( opb, ModeBitPatterns[ModeIndex], + (ogg_uint32_t)ModeBitLengths[ModeIndex] ); + } + }else{ + /* Fall back to MODE_BITS per entry */ + for ( i = 0; i < cpi->ModeListCount; i++ ) { + /* Add the appropriate mode entropy token. */ + oggpackB_write( opb, cpi->ModeList[i], MODE_BITS ); + } + } +} + +static void PackMotionVectors (CP_INSTANCE *cpi) { + ogg_int32_t i; + ogg_uint32_t MethodBits[2] = {0,0}; + ogg_uint32_t * MvBitsPtr; + ogg_uint32_t * MvPatternPtr; + + oggpack_buffer *opb=cpi->oggbuffer; + + /* Choose the coding method */ + MvBitsPtr = &MvBits[MAX_MV_EXTENT]; + for ( i = 0; i < (ogg_int32_t)cpi->MvListCount; i++ ) { + MethodBits[0] += MvBitsPtr[cpi->MVList[i].x]; + MethodBits[0] += MvBitsPtr[cpi->MVList[i].y]; + MethodBits[1] += 12; /* Simple six bits per mv component fallback + mechanism */ + } + + /* Select entropy table */ + if ( MethodBits[0] < MethodBits[1] ) { + oggpackB_write( opb, 0, 1 ); + MvBitsPtr = &MvBits[MAX_MV_EXTENT]; + MvPatternPtr = &MvPattern[MAX_MV_EXTENT]; + }else{ + oggpackB_write( opb, 1, 1 ); + MvBitsPtr = &MvBits2[MAX_MV_EXTENT]; + MvPatternPtr = &MvPattern2[MAX_MV_EXTENT]; + } + + /* Pack and encode the motion vectors */ + for ( i = 0; i < (ogg_int32_t)cpi->MvListCount; i++ ) { + oggpackB_write( opb, MvPatternPtr[cpi->MVList[i].x], + (ogg_uint32_t)MvBitsPtr[cpi->MVList[i].x] ); + oggpackB_write( opb, MvPatternPtr[cpi->MVList[i].y], + (ogg_uint32_t)MvBitsPtr[cpi->MVList[i].y] ); + } +} + +static void PackEOBRun( CP_INSTANCE *cpi) { + if(cpi->RunLength == 0) + return; + + /* Note the appropriate EOB or EOB run token and any extra bits in + the optimised token list. Use the huffman index assosciated with + the first token in the run */ + + /* Mark out which plane the block belonged to */ + cpi->OptimisedTokenListPl[cpi->OptimisedTokenCount] = + (unsigned char)cpi->RunPlaneIndex; + + /* Note the huffman index to be used */ + cpi->OptimisedTokenListHi[cpi->OptimisedTokenCount] = + (unsigned char)cpi->RunHuffIndex; + + if ( cpi->RunLength <= 3 ) { + if ( cpi->RunLength == 1 ) { + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = DCT_EOB_TOKEN; + } else if ( cpi->RunLength == 2 ) { + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = DCT_EOB_PAIR_TOKEN; + } else { + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = DCT_EOB_TRIPLE_TOKEN; + } + + cpi->RunLength = 0; + + } else { + + /* Choose a token appropriate to the run length. */ + if ( cpi->RunLength < 8 ) { + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = + DCT_REPEAT_RUN_TOKEN; + cpi->OptimisedTokenListEb[cpi->OptimisedTokenCount] = + cpi->RunLength - 4; + cpi->RunLength = 0; + } else if ( cpi->RunLength < 16 ) { + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = + DCT_REPEAT_RUN2_TOKEN; + cpi->OptimisedTokenListEb[cpi->OptimisedTokenCount] = + cpi->RunLength - 8; + cpi->RunLength = 0; + } else if ( cpi->RunLength < 32 ) { + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = + DCT_REPEAT_RUN3_TOKEN; + cpi->OptimisedTokenListEb[cpi->OptimisedTokenCount] = + cpi->RunLength - 16; + cpi->RunLength = 0; + } else if ( cpi->RunLength < 4096) { + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = + DCT_REPEAT_RUN4_TOKEN; + cpi->OptimisedTokenListEb[cpi->OptimisedTokenCount] = + cpi->RunLength; + cpi->RunLength = 0; + } + + } + + cpi->OptimisedTokenCount++; + /* Reset run EOB length */ + cpi->RunLength = 0; +} + +static void PackToken ( CP_INSTANCE *cpi, ogg_int32_t FragmentNumber, + ogg_uint32_t HuffIndex ) { + ogg_uint32_t Token = + cpi->pb.TokenList[FragmentNumber][cpi->FragTokens[FragmentNumber]]; + ogg_uint32_t ExtraBitsToken = + cpi->pb.TokenList[FragmentNumber][cpi->FragTokens[FragmentNumber] + 1]; + ogg_uint32_t OneOrTwo; + ogg_uint32_t OneOrZero; + + /* Update the record of what coefficient we have got up to for this + block and unpack the encoded token back into the quantised data + array. */ + if ( Token == DCT_EOB_TOKEN ) + cpi->pb.FragCoeffs[FragmentNumber] = BLOCK_SIZE; + else + ExpandToken( cpi->pb.QFragData[FragmentNumber], + &cpi->pb.FragCoeffs[FragmentNumber], + Token, ExtraBitsToken ); + + /* Update record of tokens coded and where we are in this fragment. */ + /* Is there an extra bits token */ + OneOrTwo= 1 + ( cpi->pb.ExtraBitLengths_VP3x[Token] > 0 ); + /* Advance to the next real token. */ + cpi->FragTokens[FragmentNumber] += (unsigned char)OneOrTwo; + + /* Update the counts of tokens coded */ + cpi->TokensCoded += OneOrTwo; + cpi->TokensToBeCoded -= OneOrTwo; + + OneOrZero = ( FragmentNumber < (ogg_int32_t)cpi->pb.YPlaneFragments ); + + if ( Token == DCT_EOB_TOKEN ) { + if ( cpi->RunLength == 0 ) { + cpi->RunHuffIndex = HuffIndex; + cpi->RunPlaneIndex = 1 - OneOrZero; + } + cpi->RunLength++; + + /* we have exceeded our longest run length xmit an eob run token; */ + if ( cpi->RunLength == 4095 ) PackEOBRun(cpi); + + }else{ + + /* If we have an EOB run then code it up first */ + if ( cpi->RunLength > 0 ) PackEOBRun( cpi); + + /* Mark out which plane the block belonged to */ + cpi->OptimisedTokenListPl[cpi->OptimisedTokenCount] = + (unsigned char)(1 - OneOrZero); + + /* Note the token, extra bits and hufman table in the optimised + token list */ + cpi->OptimisedTokenList[cpi->OptimisedTokenCount] = + (unsigned char)Token; + cpi->OptimisedTokenListEb[cpi->OptimisedTokenCount] = + ExtraBitsToken; + cpi->OptimisedTokenListHi[cpi->OptimisedTokenCount] = + (unsigned char)HuffIndex; + + cpi->OptimisedTokenCount++; + } +} + +static ogg_uint32_t GetBlockReconErrorSlow( CP_INSTANCE *cpi, + ogg_int32_t BlockIndex ) { + ogg_uint32_t i; + ogg_uint32_t ErrorVal = 0; + + unsigned char * SrcDataPtr = + &cpi->ConvDestBuffer[cpi->pb.pixel_index_table[BlockIndex]]; + unsigned char * RecDataPtr = + &cpi->pb.LastFrameRecon[cpi->pb.recon_pixel_index_table[BlockIndex]]; + ogg_int32_t SrcStride; + ogg_int32_t RecStride; + + /* Is the block a Y block or a UV block. */ + if ( BlockIndex < (ogg_int32_t)cpi->pb.YPlaneFragments ) { + SrcStride = cpi->pb.info.width; + RecStride = cpi->pb.YStride; + }else{ + SrcStride = cpi->pb.info.width >> 1; + RecStride = cpi->pb.UVStride; + } + + + /* Decide on standard or MMX implementation */ + for ( i=0; i < BLOCK_HEIGHT_WIDTH; i++ ) { + ErrorVal += abs( ((int)SrcDataPtr[0]) - ((int)RecDataPtr[0]) ); + ErrorVal += abs( ((int)SrcDataPtr[1]) - ((int)RecDataPtr[1]) ); + ErrorVal += abs( ((int)SrcDataPtr[2]) - ((int)RecDataPtr[2]) ); + ErrorVal += abs( ((int)SrcDataPtr[3]) - ((int)RecDataPtr[3]) ); + ErrorVal += abs( ((int)SrcDataPtr[4]) - ((int)RecDataPtr[4]) ); + ErrorVal += abs( ((int)SrcDataPtr[5]) - ((int)RecDataPtr[5]) ); + ErrorVal += abs( ((int)SrcDataPtr[6]) - ((int)RecDataPtr[6]) ); + ErrorVal += abs( ((int)SrcDataPtr[7]) - ((int)RecDataPtr[7]) ); + /* Step to next row of block. */ + SrcDataPtr += SrcStride; + RecDataPtr += RecStride; + } + return ErrorVal; +} + +static void PackCodedVideo (CP_INSTANCE *cpi) { + ogg_int32_t i; + ogg_int32_t EncodedCoeffs = 1; + ogg_int32_t FragIndex; + ogg_uint32_t HuffIndex; /* Index to group of tables used to code a token */ + + /* Reset the count of second order optimised tokens */ + cpi->OptimisedTokenCount = 0; + + cpi->TokensToBeCoded = cpi->TotTokenCount; + cpi->TokensCoded = 0; + + /* Calculate the bit rate at which this frame should be capped. */ + cpi->MaxBitTarget = (ogg_uint32_t)((double)(cpi->ThisFrameTargetBytes * 8) * + cpi->BitRateCapFactor); + + /* Blank the various fragment data structures before we start. */ + memset(cpi->pb.FragCoeffs, 0, cpi->pb.UnitFragments); + memset(cpi->FragTokens, 0, cpi->pb.UnitFragments); + + /* Clear down the QFragData structure for all coded blocks. */ + ClearDownQFragData(&cpi->pb); + + /* The tree is not needed (implicit) for key frames */ + if ( GetFrameType(&cpi->pb) != BASE_FRAME ){ + /* Pack the quad tree fragment mapping. */ + PackAndWriteDFArray( cpi ); + } + + /* Note the number of bits used to code the tree itself. */ + cpi->FrameBitCount = oggpackB_bytes(cpi->oggbuffer) << 3; + + /* Mode and MV data not needed for key frames. */ + if ( GetFrameType(&cpi->pb) != BASE_FRAME ){ + /* Pack and code the mode list. */ + PackModes(cpi); + /* Pack the motion vectors */ + PackMotionVectors (cpi); + } + + cpi->FrameBitCount = oggpackB_bytes(cpi->oggbuffer) << 3; + + /* Optimise the DC tokens */ + for ( i = 0; i < cpi->pb.CodedBlockIndex; i++ ) { + /* Get the linear index for the current fragment. */ + FragIndex = cpi->pb.CodedBlockList[i]; + + cpi->pb.FragCoefEOB[FragIndex]=(unsigned char)EncodedCoeffs; + PackToken(cpi, FragIndex, DC_HUFF_OFFSET ); + + } + + /* Pack any outstanding EOB tokens */ + PackEOBRun(cpi); + + /* Now output the optimised DC token list using the appropriate + entropy tables. */ + EncodeDcTokenList(cpi); + + /* Work out the number of DC bits coded */ + + /* Optimise the AC tokens */ + while ( EncodedCoeffs < 64 ) { + /* Huffman table adjustment based upon coefficient number. */ + if ( EncodedCoeffs <= AC_TABLE_2_THRESH ) + HuffIndex = AC_HUFF_OFFSET; + else if ( EncodedCoeffs <= AC_TABLE_3_THRESH ) + HuffIndex = AC_HUFF_OFFSET + AC_HUFF_CHOICES; + else if ( EncodedCoeffs <= AC_TABLE_4_THRESH ) + HuffIndex = AC_HUFF_OFFSET + (AC_HUFF_CHOICES * 2); + else + HuffIndex = AC_HUFF_OFFSET + (AC_HUFF_CHOICES * 3); + + /* Repeatedly scan through the list of blocks. */ + for ( i = 0; i < cpi->pb.CodedBlockIndex; i++ ) { + /* Get the linear index for the current fragment. */ + FragIndex = cpi->pb.CodedBlockList[i]; + + /* Should we code a token for this block on this pass. */ + if ( cpi->FragTokens[FragIndex] < cpi->FragTokenCounts[FragIndex] + && cpi->pb.FragCoeffs[FragIndex] <= EncodedCoeffs ) { + /* Bit pack and a token for this block */ + cpi->pb.FragCoefEOB[FragIndex]=(unsigned char)EncodedCoeffs; + PackToken( cpi, FragIndex, HuffIndex ); + } + } + + EncodedCoeffs ++; + } + + /* Pack any outstanding EOB tokens */ + PackEOBRun(cpi); + + /* Now output the optimised AC token list using the appropriate + entropy tables. */ + EncodeAcTokenList(cpi); + +} + +static ogg_uint32_t QuadCodeDisplayFragments (CP_INSTANCE *cpi) { + ogg_int32_t i,j; + ogg_uint32_t coded_pixels=0; + int QIndex; + int k,m,n; + + /* predictor multiplier up-left, up, up-right,left, shift + Entries are packed in the order L, UL, U, UR, with missing entries + moved to the end (before the shift parameters). */ + static const ogg_int16_t pc[16][6]={ + {0,0,0,0,0,0}, + {1,0,0,0,0,0}, /* PL */ + {1,0,0,0,0,0}, /* PUL */ + {1,0,0,0,0,0}, /* PUL|PL */ + {1,0,0,0,0,0}, /* PU */ + {1,1,0,0,1,1}, /* PU|PL */ + {0,1,0,0,0,0}, /* PU|PUL */ + {29,-26,29,0,5,31}, /* PU|PUL|PL */ + {1,0,0,0,0,0}, /* PUR */ + {75,53,0,0,7,127}, /* PUR|PL */ + {1,1,0,0,1,1}, /* PUR|PUL */ + {75,0,53,0,7,127}, /* PUR|PUL|PL */ + {1,0,0,0,0,0}, /* PUR|PU */ + {75,0,53,0,7,127}, /* PUR|PU|PL */ + {3,10,3,0,4,15}, /* PUR|PU|PUL */ + {29,-26,29,0,5,31} /* PUR|PU|PUL|PL */ + }; + + /* boundary case bit masks. */ + static const int bc_mask[8]={ + /* normal case no boundary condition */ + PUR|PU|PUL|PL, + /* left column */ + PUR|PU, + /* top row */ + PL, + /* top row, left column */ + 0, + /* right column */ + PU|PUL|PL, + /* right and left column */ + PU, + /* top row, right column */ + PL, + /* top row, right and left column */ + 0 + }; + + /* value left value up-left, value up, value up-right */ + int v[4]; + + /* fragment number left, up-left, up, up-right */ + int fn[4]; + + /* predictor count. */ + int pcount; + + /*which predictor constants to use */ + ogg_int16_t wpc; + + /* last used inter predictor (Raster Order) */ + ogg_int16_t Last[3]; /* last value used for given frame */ + + int FragsAcross=cpi->pb.HFragments; + int FragsDown = cpi->pb.VFragments; + int FromFragment,ToFragment; + ogg_int32_t FragIndex; + int WhichFrame; + int WhichCase; + + ogg_int16_t Mode2Frame[] = { + 1, /* CODE_INTER_NO_MV 0 => Encoded diff from same MB last frame */ + 0, /* CODE_INTRA 1 => DCT Encoded Block */ + 1, /* CODE_INTER_PLUS_MV 2 => Encoded diff from included MV MB last frame */ + 1, /* CODE_INTER_LAST_MV 3 => Encoded diff from MRU MV MB last frame */ + 1, /* CODE_INTER_PRIOR_MV 4 => Encoded diff from included 4 separate MV blocks */ + 2, /* CODE_USING_GOLDEN 5 => Encoded diff from same MB golden frame */ + 2, /* CODE_GOLDEN_MV 6 => Encoded diff from included MV MB golden frame */ + 1 /* CODE_INTER_FOUR_MV 7 => Encoded diff from included 4 separate MV blocks */ + }; + + ogg_int16_t PredictedDC; + + /* Initialise the coded block indices variables. These allow + subsequent linear access to the quad tree ordered list of coded + blocks */ + cpi->pb.CodedBlockIndex = 0; + + /* Set the inter/intra descision control variables. */ + QIndex = Q_TABLE_SIZE - 1; + while ( QIndex >= 0 ) { + if ( (QIndex == 0) || + ( cpi->pb.QThreshTable[QIndex] >= cpi->pb.ThisFrameQualityValue) ) + break; + QIndex --; + } + + + /* Encode and tokenise the Y, U and V components */ + coded_pixels = QuadCodeComponent(cpi, 0, cpi->pb.YSBRows, cpi->pb.YSBCols, + cpi->pb.info.width ); + coded_pixels += QuadCodeComponent(cpi, cpi->pb.YSuperBlocks, + cpi->pb.UVSBRows, + cpi->pb.UVSBCols, + cpi->pb.info.width>>1 ); + coded_pixels += QuadCodeComponent(cpi, + cpi->pb.YSuperBlocks+cpi->pb.UVSuperBlocks, + cpi->pb.UVSBRows, cpi->pb.UVSBCols, + cpi->pb.info.width>>1 ); + + /* for y,u,v */ + for ( j = 0; j < 3 ; j++) { + /* pick which fragments based on Y, U, V */ + switch(j){ + case 0: /* y */ + FromFragment = 0; + ToFragment = cpi->pb.YPlaneFragments; + FragsAcross = cpi->pb.HFragments; + FragsDown = cpi->pb.VFragments; + break; + case 1: /* u */ + FromFragment = cpi->pb.YPlaneFragments; + ToFragment = cpi->pb.YPlaneFragments + cpi->pb.UVPlaneFragments ; + FragsAcross = cpi->pb.HFragments >> 1; + FragsDown = cpi->pb.VFragments >> 1; + break; + /*case 2: v */ + default: + FromFragment = cpi->pb.YPlaneFragments + cpi->pb.UVPlaneFragments; + ToFragment = cpi->pb.YPlaneFragments + (2 * cpi->pb.UVPlaneFragments) ; + FragsAcross = cpi->pb.HFragments >> 1; + FragsDown = cpi->pb.VFragments >> 1; + break; + } + + /* initialize our array of last used DC Components */ + for(k=0;k<3;k++)Last[k]=0; + i=FromFragment; + + /* do prediction on all of Y, U or V */ + for ( m = 0 ; m < FragsDown ; m++) { + for ( n = 0 ; n < FragsAcross ; n++, i++) { + cpi->OriginalDC[i] = cpi->pb.QFragData[i][0]; + + /* only do 2 prediction if fragment coded and on non intra or + if all fragments are intra */ + if( cpi->pb.display_fragments[i] || + (GetFrameType(&cpi->pb) == BASE_FRAME) ) { + /* Type of Fragment */ + WhichFrame = Mode2Frame[cpi->pb.FragCodingMethod[i]]; + + /* Check Borderline Cases */ + WhichCase = (n==0) + ((m==0) << 1) + ((n+1 == FragsAcross) << 2); + + fn[0]=i-1; + fn[1]=i-FragsAcross-1; + fn[2]=i-FragsAcross; + fn[3]=i-FragsAcross+1; + + /* fragment valid for prediction use if coded and it comes + from same frame as the one we are predicting */ + for(k=pcount=wpc=0; k<4; k++) { + int pflag; + pflag=1<pb.display_fragments[fn[k]] && + (Mode2Frame[cpi->pb.FragCodingMethod[fn[k]]] == WhichFrame)){ + v[pcount]=cpi->OriginalDC[fn[k]]; + wpc|=pflag; + pcount++; + } + } + + if(wpc==0) { + + /* fall back to the last coded fragment */ + cpi->pb.QFragData[i][0] -= Last[WhichFrame]; + + } else { + + /* don't do divide if divisor is 1 or 0 */ + PredictedDC = pc[wpc][0]*v[0]; + for(k=1; k>= pc[wpc][4]; + + } + + /* check for outranging on the two predictors that can outrange */ + if((wpc&(PU|PUL|PL)) == (PU|PUL|PL)){ + if( abs(PredictedDC - v[2]) > 128) { + PredictedDC = v[2]; + } else if( abs(PredictedDC - v[0]) > 128) { + PredictedDC = v[0]; + } else if( abs(PredictedDC - v[1]) > 128) { + PredictedDC = v[1]; + } + } + + cpi->pb.QFragData[i][0] -= PredictedDC; + } + + /* Save the last fragment coded for whatever frame we are + predicting from */ + + Last[WhichFrame] = cpi->OriginalDC[i]; + + } + } + } + } + + /* Pack DC tokens and adjust the ones we couldn't predict 2d */ + for ( i = 0; i < cpi->pb.CodedBlockIndex; i++ ) { + /* Get the linear index for the current coded fragment. */ + FragIndex = cpi->pb.CodedBlockList[i]; + coded_pixels += DPCMTokenizeBlock ( cpi, FragIndex); + + } + + + /* Bit pack the video data data */ + PackCodedVideo(cpi); + + /* End the bit packing run. */ + /* EndAddBitsToBuffer(cpi); */ + + /* Reconstruct the reference frames */ + ReconRefFrames(&cpi->pb); + + UpdateFragQIndex(&cpi->pb); + + /* Measure the inter reconstruction error for all the blocks that + were coded */ + /* for use as part of the recovery monitoring process in subsequent frames. */ + for ( i = 0; i < cpi->pb.CodedBlockIndex; i++ ) { + cpi->LastCodedErrorScore[ cpi->pb.CodedBlockList[i] ] = + GetBlockReconErrorSlow( cpi, cpi->pb.CodedBlockList[i] ); + + } + + /* Return total number of coded pixels */ + return coded_pixels; +} + +ogg_uint32_t EncodeData(CP_INSTANCE *cpi){ + ogg_uint32_t coded_pixels = 0; + + /* Zero the count of tokens so far this frame. */ + cpi->TotTokenCount = 0; + + /* Zero the mode and MV list indices. */ + cpi->ModeListCount = 0; + + /* Zero Decoder EOB run count */ + cpi->pb.EOB_Run = 0; + + /* Encode any fragments coded using DCT. */ + coded_pixels += QuadCodeDisplayFragments (cpi); + + return coded_pixels; + +} + +ogg_uint32_t PickIntra( CP_INSTANCE *cpi, + ogg_uint32_t SBRows, + ogg_uint32_t SBCols){ + + ogg_int32_t FragIndex; /* Fragment number */ + ogg_uint32_t MB, B; /* Macro-Block, Block indices */ + ogg_uint32_t SBrow; /* Super-Block row number */ + ogg_uint32_t SBcol; /* Super-Block row number */ + ogg_uint32_t SB=0; /* Super-Block index, initialised to first of + this component */ + + ogg_uint32_t UVRow; + ogg_uint32_t UVColumn; + ogg_uint32_t UVFragOffset; + + /* decide what block type and motion vectors to use on all of the frames */ + for ( SBrow=0; SBrowpb.BlockMap,SB,MB) >= 0 ) { + + cpi->MBCodingMode = CODE_INTRA; + + /* Now actually code the blocks. */ + for ( B=0; B<4; B++ ) { + FragIndex = QuadMapToIndex1( cpi->pb.BlockMap, SB, MB, B ); + cpi->pb.FragCodingMethod[FragIndex] = cpi->MBCodingMode; + } + + /* Matching fragments in the U and V planes */ + UVRow = (FragIndex / (cpi->pb.HFragments * 2)); + UVColumn = (FragIndex % cpi->pb.HFragments) / 2; + UVFragOffset = (UVRow * (cpi->pb.HFragments / 2)) + UVColumn; + + cpi->pb.FragCodingMethod[cpi->pb.YPlaneFragments + UVFragOffset] = + cpi->MBCodingMode; + cpi->pb.FragCodingMethod[cpi->pb.YPlaneFragments + + cpi->pb.UVPlaneFragments + UVFragOffset] = + cpi->MBCodingMode; + + } + } + + /* Next Super-Block */ + SB++; + } + } + return 0; +} + +static void AddMotionVector(CP_INSTANCE *cpi, + MOTION_VECTOR *ThisMotionVector) { + cpi->MVList[cpi->MvListCount].x = ThisMotionVector->x; + cpi->MVList[cpi->MvListCount].y = ThisMotionVector->y; + cpi->MvListCount++; +} + +static void SetFragMotionVectorAndMode(CP_INSTANCE *cpi, + ogg_int32_t FragIndex, + MOTION_VECTOR *ThisMotionVector){ + /* Note the coding mode and vector for each block */ + cpi->pb.FragMVect[FragIndex].x = ThisMotionVector->x; + cpi->pb.FragMVect[FragIndex].y = ThisMotionVector->y; + cpi->pb.FragCodingMethod[FragIndex] = cpi->MBCodingMode; +} + +static void SetMBMotionVectorsAndMode(CP_INSTANCE *cpi, + ogg_int32_t YFragIndex, + ogg_int32_t UFragIndex, + ogg_int32_t VFragIndex, + MOTION_VECTOR *ThisMotionVector){ + SetFragMotionVectorAndMode(cpi, YFragIndex, ThisMotionVector); + SetFragMotionVectorAndMode(cpi, YFragIndex + 1, ThisMotionVector); + SetFragMotionVectorAndMode(cpi, YFragIndex + cpi->pb.HFragments, + ThisMotionVector); + SetFragMotionVectorAndMode(cpi, YFragIndex + cpi->pb.HFragments + 1, + ThisMotionVector); + SetFragMotionVectorAndMode(cpi, UFragIndex, ThisMotionVector); + SetFragMotionVectorAndMode(cpi, VFragIndex, ThisMotionVector); +} + +ogg_uint32_t PickModes(CP_INSTANCE *cpi, + ogg_uint32_t SBRows, ogg_uint32_t SBCols, + ogg_uint32_t PixelsPerLine, + ogg_uint32_t *InterError, ogg_uint32_t *IntraError) { + ogg_int32_t YFragIndex; + ogg_int32_t UFragIndex; + ogg_int32_t VFragIndex; + ogg_uint32_t MB, B; /* Macro-Block, Block indices */ + ogg_uint32_t SBrow; /* Super-Block row number */ + ogg_uint32_t SBcol; /* Super-Block row number */ + ogg_uint32_t SB=0; /* Super-Block index, initialised to first + of this component */ + + ogg_uint32_t MBIntraError; /* Intra error for macro block */ + ogg_uint32_t MBGFError; /* Golden frame macro block error */ + ogg_uint32_t MBGF_MVError; /* Golden frame plus MV error */ + ogg_uint32_t LastMBGF_MVError; /* Golden frame error with + last used GF motion + vector. */ + ogg_uint32_t MBInterError; /* Inter no MV macro block error */ + ogg_uint32_t MBLastInterError; /* Inter with last used MV */ + ogg_uint32_t MBPriorLastInterError; /* Inter with prior last MV */ + ogg_uint32_t MBInterMVError; /* Inter MV macro block error */ + ogg_uint32_t MBInterMVExError; /* Inter MV (exhaustive + search) macro block error */ + ogg_uint32_t MBInterFOURMVError; /* Inter MV error when using 4 + motion vectors per macro + block */ + ogg_uint32_t BestError; /* Best error so far. */ + + MOTION_VECTOR FourMVect[6]; /* storage for last used vectors (one + entry for each block in MB) */ + MOTION_VECTOR LastInterMVect; /* storage for last used Inter frame + MB motion vector */ + MOTION_VECTOR PriorLastInterMVect; /* storage for prior last used + Inter frame MB motion vector */ + MOTION_VECTOR TmpMVect; /* Temporary MV storage */ + MOTION_VECTOR LastGFMVect; /* storage for last used Golden + Frame MB motion vector */ + MOTION_VECTOR InterMVect; /* storage for motion vector */ + MOTION_VECTOR InterMVectEx; /* storage for motion vector result + from exhaustive search */ + MOTION_VECTOR GFMVect; /* storage for motion vector */ + MOTION_VECTOR ZeroVect; + + ogg_uint32_t UVRow; + ogg_uint32_t UVColumn; + ogg_uint32_t UVFragOffset; + + int MBCodedFlag; + unsigned char QIndex; + + /* initialize error scores */ + *InterError = 0; + *IntraError = 0; + + /* clear down the default motion vector. */ + cpi->MvListCount = 0; + FourMVect[0].x = 0; + FourMVect[0].y = 0; + FourMVect[1].x = 0; + FourMVect[1].y = 0; + FourMVect[2].x = 0; + FourMVect[2].y = 0; + FourMVect[3].x = 0; + FourMVect[3].y = 0; + FourMVect[4].x = 0; + FourMVect[4].y = 0; + FourMVect[5].x = 0; + FourMVect[5].y = 0; + LastInterMVect.x = 0; + LastInterMVect.y = 0; + PriorLastInterMVect.x = 0; + PriorLastInterMVect.y = 0; + LastGFMVect.x = 0; + LastGFMVect.y = 0; + InterMVect.x = 0; + InterMVect.y = 0; + GFMVect.x = 0; + GFMVect.y = 0; + + ZeroVect.x = 0; + ZeroVect.y = 0; + + QIndex = (unsigned char)cpi->pb.FrameQIndex; + + + + /* change the quatization matrix to the one at best Q to compute the + new error score */ + cpi->MinImprovementForNewMV = (MvThreshTable[QIndex] << 12); + cpi->InterTripOutThresh = (5000<<12); + cpi->MVChangeFactor = MVChangeFactorTable[QIndex]; /* 0.9 */ + + if ( cpi->pb.info.quick_p ) { + cpi->ExhaustiveSearchThresh = (1000<<12); + cpi->FourMVThreshold = (2500<<12); + } else { + cpi->ExhaustiveSearchThresh = (250<<12); + cpi->FourMVThreshold = (500<<12); + } + cpi->MinImprovementForFourMV = cpi->MinImprovementForNewMV * 4; + + if(cpi->MinImprovementForFourMV < (40<<12)) + cpi->MinImprovementForFourMV = (40<<12); + + cpi->FourMvChangeFactor = 8; /* cpi->MVChangeFactor - 0.05; */ + + /* decide what block type and motion vectors to use on all of the frames */ + for ( SBrow=0; SBrowpb.BlockMap,SB,MB) < 0 ) continue; + + /* Is the current macro block coded (in part or in whole) */ + MBCodedFlag = 0; + for ( B=0; B<4; B++ ) { + YFragIndex = QuadMapToIndex1( cpi->pb.BlockMap, SB, MB, B ); + + /* Does Block lie in frame: */ + if ( YFragIndex >= 0 ) { + /* In Frame: Is it coded: */ + if ( cpi->pb.display_fragments[YFragIndex] ) { + MBCodedFlag = 1; + break; + } + } else + MBCodedFlag = 0; + } + + /* This one isn't coded go to the next one */ + if(!MBCodedFlag) continue; + + /* Calculate U and V FragIndex from YFragIndex */ + YFragIndex = QuadMapToMBTopLeft(cpi->pb.BlockMap, SB,MB); + UVRow = (YFragIndex / (cpi->pb.HFragments * 2)); + UVColumn = (YFragIndex % cpi->pb.HFragments) / 2; + UVFragOffset = (UVRow * (cpi->pb.HFragments / 2)) + UVColumn; + UFragIndex = cpi->pb.YPlaneFragments + UVFragOffset; + VFragIndex = cpi->pb.YPlaneFragments + cpi->pb.UVPlaneFragments + + UVFragOffset; + + + /************************************************************** + Find the block choice with the lowest error + + NOTE THAT if U or V is coded but no Y from a macro block then + the mode will be CODE_INTER_NO_MV as this is the default + state to which the mode data structure is initialised in + encoder and decoder at the start of each frame. */ + + BestError = HUGE_ERROR; + + + /* Look at the intra coding error. */ + MBIntraError = GetMBIntraError( cpi, YFragIndex, PixelsPerLine ); + BestError = (BestError > MBIntraError) ? MBIntraError : BestError; + + /* Get the golden frame error */ + MBGFError = GetMBInterError( cpi, cpi->ConvDestBuffer, + cpi->pb.GoldenFrame, YFragIndex, + 0, 0, PixelsPerLine ); + BestError = (BestError > MBGFError) ? MBGFError : BestError; + + /* Calculate the 0,0 case. */ + MBInterError = GetMBInterError( cpi, cpi->ConvDestBuffer, + cpi->pb.LastFrameRecon, + YFragIndex, 0, 0, PixelsPerLine ); + BestError = (BestError > MBInterError) ? MBInterError : BestError; + + /* Measure error for last MV */ + MBLastInterError = GetMBInterError( cpi, cpi->ConvDestBuffer, + cpi->pb.LastFrameRecon, + YFragIndex, LastInterMVect.x, + LastInterMVect.y, PixelsPerLine ); + BestError = (BestError > MBLastInterError) ? + MBLastInterError : BestError; + + /* Measure error for prior last MV */ + MBPriorLastInterError = GetMBInterError( cpi, cpi->ConvDestBuffer, + cpi->pb.LastFrameRecon, + YFragIndex, + PriorLastInterMVect.x, + PriorLastInterMVect.y, + PixelsPerLine ); + BestError = (BestError > MBPriorLastInterError) ? + MBPriorLastInterError : BestError; + + /* Temporarily force usage of no motionvector blocks */ + MBInterMVError = HUGE_ERROR; + InterMVect.x = 0; /* Set 0,0 motion vector */ + InterMVect.y = 0; + + /* If the best error is above the required threshold search + for a new inter MV */ + if ( BestError > cpi->MinImprovementForNewMV ) { + /* Use a mix of heirachical and exhaustive searches for + quick mode. */ + if ( cpi->pb.info.quick_p ) { + MBInterMVError = GetMBMVInterError( cpi, cpi->pb.LastFrameRecon, + YFragIndex, PixelsPerLine, + cpi->MVPixelOffsetY, + &InterMVect ); + + /* If we still do not have a good match try an exhaustive + MBMV search */ + if ( (MBInterMVError > cpi->ExhaustiveSearchThresh) && + (BestError > cpi->ExhaustiveSearchThresh) ) { + + MBInterMVExError = + GetMBMVExhaustiveSearch( cpi, cpi->pb.LastFrameRecon, + YFragIndex, PixelsPerLine, + &InterMVectEx ); + + /* Is the Variance measure for the EX search + better... If so then use it. */ + if ( MBInterMVExError < MBInterMVError ) { + MBInterMVError = MBInterMVExError; + InterMVect.x = InterMVectEx.x; + InterMVect.y = InterMVectEx.y; + } + } + }else{ + /* Use an exhaustive search */ + MBInterMVError = + GetMBMVExhaustiveSearch( cpi, cpi->pb.LastFrameRecon, + YFragIndex, PixelsPerLine, + &InterMVect ); + } + + + /* Is the improvement, if any, good enough to justify a new MV */ + if ( (16 * MBInterMVError < (BestError * cpi->MVChangeFactor)) && + ((MBInterMVError + cpi->MinImprovementForNewMV) < BestError) ){ + BestError = MBInterMVError; + } + + } + + /* If the best error is still above the required threshold + search for a golden frame MV */ + MBGF_MVError = HUGE_ERROR; + GFMVect.x = 0; /* Set 0,0 motion vector */ + GFMVect.y = 0; + if ( BestError > cpi->MinImprovementForNewMV ) { + /* Do an MV search in the golden reference frame */ + MBGF_MVError = GetMBMVInterError( cpi, cpi->pb.GoldenFrame, + YFragIndex, PixelsPerLine, + cpi->MVPixelOffsetY, &GFMVect ); + + /* Measure error for last GFMV */ + LastMBGF_MVError = GetMBInterError( cpi, cpi->ConvDestBuffer, + cpi->pb.GoldenFrame, + YFragIndex, LastGFMVect.x, + LastGFMVect.y, PixelsPerLine ); + + /* Check against last GF motion vector and reset if the + search has thrown a worse result. */ + if ( LastMBGF_MVError < MBGF_MVError ) { + GFMVect.x = LastGFMVect.x; + GFMVect.y = LastGFMVect.y; + MBGF_MVError = LastMBGF_MVError; + }else{ + LastGFMVect.x = GFMVect.x; + LastGFMVect.y = GFMVect.y; + } + + /* Is the improvement, if any, good enough to justify a new MV */ + if ( (16 * MBGF_MVError < (BestError * cpi->MVChangeFactor)) && + ((MBGF_MVError + cpi->MinImprovementForNewMV) < BestError) ) { + BestError = MBGF_MVError; + } + } + + /* Finally... If the best error is still to high then consider + the 4MV mode */ + MBInterFOURMVError = HUGE_ERROR; + if ( BestError > cpi->FourMVThreshold ) { + /* Get the 4MV error. */ + MBInterFOURMVError = + GetFOURMVExhaustiveSearch( cpi, cpi->pb.LastFrameRecon, + YFragIndex, PixelsPerLine, FourMVect ); + + /* If the improvement is great enough then use the four MV mode */ + if ( ((MBInterFOURMVError + cpi->MinImprovementForFourMV) < + BestError) && (16 * MBInterFOURMVError < + (BestError * cpi->FourMvChangeFactor))) { + BestError = MBInterFOURMVError; + } + } + + /******************************************************** + end finding the best error + ******************************************************* + + Figure out what to do with the block we chose + + Over-ride and force intra if error high and Intra error similar + Now choose a mode based on lowest error (with bias towards no MV) */ + + if ( (BestError > cpi->InterTripOutThresh) && + (10 * BestError > MBIntraError * 7 ) ) { + cpi->MBCodingMode = CODE_INTRA; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&ZeroVect); + } else if ( BestError == MBInterError ) { + cpi->MBCodingMode = CODE_INTER_NO_MV; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&ZeroVect); + } else if ( BestError == MBGFError ) { + cpi->MBCodingMode = CODE_USING_GOLDEN; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&ZeroVect); + } else if ( BestError == MBLastInterError ) { + cpi->MBCodingMode = CODE_INTER_LAST_MV; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&LastInterMVect); + } else if ( BestError == MBPriorLastInterError ) { + cpi->MBCodingMode = CODE_INTER_PRIOR_LAST; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&PriorLastInterMVect); + + /* Swap the prior and last MV cases over */ + TmpMVect.x = PriorLastInterMVect.x; + TmpMVect.y = PriorLastInterMVect.y; + PriorLastInterMVect.x = LastInterMVect.x; + PriorLastInterMVect.y = LastInterMVect.y; + LastInterMVect.x = TmpMVect.x; + LastInterMVect.y = TmpMVect.y; + + } else if ( BestError == MBInterMVError ) { + + cpi->MBCodingMode = CODE_INTER_PLUS_MV; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&InterMVect); + + /* Update Prior last mv with last mv */ + PriorLastInterMVect.x = LastInterMVect.x; + PriorLastInterMVect.y = LastInterMVect.y; + + /* Note last inter MV for future use */ + LastInterMVect.x = InterMVect.x; + LastInterMVect.y = InterMVect.y; + + AddMotionVector( cpi, &InterMVect); + + } else if ( BestError == MBGF_MVError ) { + + cpi->MBCodingMode = CODE_GOLDEN_MV; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&GFMVect); + + /* Note last inter GF MV for future use */ + LastGFMVect.x = GFMVect.x; + LastGFMVect.y = GFMVect.y; + + AddMotionVector( cpi, &GFMVect); + } else if ( BestError == MBInterFOURMVError ) { + cpi->MBCodingMode = CODE_INTER_FOURMV; + + /* Calculate the UV vectors as the average of the Y plane ones. */ + /* First .x component */ + FourMVect[4].x = FourMVect[0].x + FourMVect[1].x + + FourMVect[2].x + FourMVect[3].x; + if ( FourMVect[4].x >= 0 ) + FourMVect[4].x = (FourMVect[4].x + 2) / 4; + else + FourMVect[4].x = (FourMVect[4].x - 2) / 4; + FourMVect[5].x = FourMVect[4].x; + + /* Then .y component */ + FourMVect[4].y = FourMVect[0].y + FourMVect[1].y + + FourMVect[2].y + FourMVect[3].y; + if ( FourMVect[4].y >= 0 ) + FourMVect[4].y = (FourMVect[4].y + 2) / 4; + else + FourMVect[4].y = (FourMVect[4].y - 2) / 4; + FourMVect[5].y = FourMVect[4].y; + + SetFragMotionVectorAndMode(cpi, YFragIndex, &FourMVect[0]); + SetFragMotionVectorAndMode(cpi, YFragIndex + 1, &FourMVect[1]); + SetFragMotionVectorAndMode(cpi, YFragIndex + cpi->pb.HFragments, + &FourMVect[2]); + SetFragMotionVectorAndMode(cpi, YFragIndex + cpi->pb.HFragments + 1, + &FourMVect[3]); + SetFragMotionVectorAndMode(cpi, UFragIndex, &FourMVect[4]); + SetFragMotionVectorAndMode(cpi, VFragIndex, &FourMVect[5]); + + /* Note the four MVs values for current macro-block. */ + AddMotionVector( cpi, &FourMVect[0]); + AddMotionVector( cpi, &FourMVect[1]); + AddMotionVector( cpi, &FourMVect[2]); + AddMotionVector( cpi, &FourMVect[3]); + + /* Update Prior last mv with last mv */ + PriorLastInterMVect.x = LastInterMVect.x; + PriorLastInterMVect.y = LastInterMVect.y; + + /* Note last inter MV for future use */ + LastInterMVect.x = FourMVect[3].x; + LastInterMVect.y = FourMVect[3].y; + + } else { + + cpi->MBCodingMode = CODE_INTRA; + SetMBMotionVectorsAndMode(cpi,YFragIndex,UFragIndex, + VFragIndex,&ZeroVect); + } + + + /* setting up mode specific block types + *******************************************************/ + + *InterError += (BestError>>8); + *IntraError += (MBIntraError>>8); + + + } + SB++; + + } + } + + /* Return number of pixels coded */ + return 0; +} + +void WriteFrameHeader( CP_INSTANCE *cpi) { + ogg_uint32_t i; + oggpack_buffer *opb=cpi->oggbuffer; + + /* Output the frame type (base/key frame or inter frame) */ + oggpackB_write( opb, cpi->pb.FrameType, 1 ); + + /* Write out details of the current value of Q... variable resolution. */ + for ( i = 0; i < Q_TABLE_SIZE; i++ ) { + if ( cpi->pb.ThisFrameQualityValue == cpi->pb.QThreshTable[i] ) { + oggpackB_write( opb, i, 6 ); + break; + } + } + + if ( i == Q_TABLE_SIZE ) { + /* An invalid DCT value was specified. */ + /*IssueWarning( "Invalid Q Multiplier" );*/ + oggpackB_write( opb, 31, 6 ); + } + + /* we only support on Q index per frame */ + oggpackB_write( opb, 0, 1 ); + + /* If the frame was a base frame then write out the frame dimensions. */ + if ( cpi->pb.FrameType == BASE_FRAME ) { + /* Key frame type / method */ + oggpackB_write( opb, cpi->pb.KeyFrameType, 1 ); + + /* Spare configuration bits */ + oggpackB_write( opb, 0, 2 ); + } +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/encoder_internal.h b/src/add-ons/media/plugins/theora/libtheora/encoder_internal.h new file mode 100644 index 0000000000..550bcd5122 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/encoder_internal.h @@ -0,0 +1,800 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: encoder_internal.h,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#ifndef ENCODER_INTERNAL_H +#define ENCODER_INTERNAL_H + +#include +#include "huffman.h" + +#ifndef LIBOGG2 +#define theora_read(x,y,z) ( *z = oggpackB_read(x,y) ) +#else +#define theora_read(x,y,z) ( oggpackB_read(x,y,z) ) +#endif + +#define CURRENT_ENCODE_VERSION 1 +#define HUGE_ERROR (1<<28) /* Out of range test value */ + +/* Baseline dct height and width. */ +#define BLOCK_HEIGHT_WIDTH 8 +#define HFRAGPIXELS 8 +#define VFRAGPIXELS 8 + +/* Baseline dct block size */ +#define BLOCK_SIZE (BLOCK_HEIGHT_WIDTH * BLOCK_HEIGHT_WIDTH) + +/* Border is for unrestricted mv's */ +#define UMV_BORDER 16 +#define STRIDE_EXTRA (UMV_BORDER * 2) +#define Q_TABLE_SIZE 64 + +#define BASE_FRAME 0 +#define NORMAL_FRAME 1 + +#define MAX_MODES 8 +#define MODE_BITS 3 +#define MODE_METHODS 8 +#define MODE_METHOD_BITS 3 + +/* Different key frame types/methods */ +#define DCT_KEY_FRAME 0 + +#define KEY_FRAME_CONTEXT 5 + +/* Preprocessor defines */ +#define MAX_PREV_FRAMES 16 + +/* Number of search sites for a 4-step search (at pixel accuracy) */ +#define MAX_SEARCH_SITES 33 + +#define VERY_BEST_Q 10 +#define MIN_BPB_FACTOR 0.3 +#define MAX_BPB_FACTOR 3.0 + +#define MAX_MV_EXTENT 31 /* Max search distance in half pixel increments */ + +typedef struct CONFIG_TYPE2{ + double OutputFrameRate; + ogg_uint32_t TargetBandwidth; + ogg_uint32_t KeyFrameDataTarget ; /* Data rate target for key frames */ + + ogg_uint32_t FirstFrameQ; + ogg_uint32_t BaseQ; + ogg_uint32_t MaxQ; /* Absolute Max Q allowed. */ + ogg_uint32_t ActiveMaxQ; /* Currently active Max Q */ + +} CONFIG_TYPE2; + +typedef struct coeffNode{ + int i; + struct coeffNode *next; +} COEFFNODE; + +typedef struct{ + unsigned char * Yuv0ptr; + unsigned char * Yuv1ptr; + unsigned char * SrfWorkSpcPtr; + unsigned char * disp_fragments; + + ogg_uint32_t * RegionIndex; /* Gives pixel index for top left of + each block */ + ogg_uint32_t VideoFrameHeight; + ogg_uint32_t VideoFrameWidth; + +} SCAN_CONFIG_DATA; + +typedef unsigned char YUV_BUFFER_ENTRY; + +typedef struct{ + ogg_int32_t x; + ogg_int32_t y; +} MOTION_VECTOR; + +typedef MOTION_VECTOR COORDINATE; + +typedef ogg_int16_t Q_LIST_ENTRY; + +typedef struct PP_INSTANCE { + ogg_uint32_t PrevFrameLimit; + + ogg_uint32_t *ScanPixelIndexTable; + signed char *ScanDisplayFragments; + + signed char *PrevFragments[MAX_PREV_FRAMES]; + + ogg_uint32_t *FragScores; /* The individual frame difference ratings. */ + signed char *SameGreyDirPixels; + signed char *BarBlockMap; + + /* Number of pixels changed by diff threshold in row of a fragment. */ + unsigned char *FragDiffPixels; + + unsigned char *PixelScores; + unsigned char *PixelChangedMap; + unsigned char *ChLocals; + ogg_int16_t *yuv_differences; + ogg_int32_t *RowChangedPixels; + signed char *TmpCodedMap; + + /* Plane pointers and dimension variables */ + unsigned char * YPlanePtr0; + unsigned char * YPlanePtr1; + unsigned char * UPlanePtr0; + unsigned char * UPlanePtr1; + unsigned char * VPlanePtr0; + unsigned char * VPlanePtr1; + + ogg_uint32_t VideoYPlaneWidth; + ogg_uint32_t VideoYPlaneHeight; + ogg_uint32_t VideoUVPlaneWidth; + ogg_uint32_t VideoUVPlaneHeight; + + ogg_uint32_t VideoYPlaneStride; + ogg_uint32_t VideoUPlaneStride; + ogg_uint32_t VideoVPlaneStride; + + /* Scan control variables. */ + unsigned char HFragPixels; + unsigned char VFragPixels; + + ogg_uint32_t ScanFrameFragments; + ogg_uint32_t ScanYPlaneFragments; + ogg_uint32_t ScanUVPlaneFragments; + ogg_uint32_t ScanHFragments; + ogg_uint32_t ScanVFragments; + + ogg_uint32_t YFramePixels; + ogg_uint32_t UVFramePixels; + + ogg_uint32_t SgcThresh; + + ogg_uint32_t OutputBlocksUpdated; + ogg_uint32_t KFIndicator; + + /* The pre-processor scan configuration. */ + SCAN_CONFIG_DATA ScanConfig; + + ogg_int32_t SRFGreyThresh; + ogg_int32_t SRFColThresh; + ogg_int32_t SgcLevelThresh; + ogg_int32_t SuvcLevelThresh; + + ogg_uint32_t NoiseSupLevel; + + /* Block Thresholds. */ + ogg_uint32_t PrimaryBlockThreshold; + unsigned char LineSearchTripTresh; + + int PAKEnabled; + + int LevelThresh; + int NegLevelThresh; + int SrfThresh; + int NegSrfThresh; + int HighChange; + int NegHighChange; + + /* Threshold lookup tables */ + unsigned char SrfPakThreshTable[512]; + unsigned char SrfThreshTable[512]; + unsigned char SgcThreshTable[512]; + + /* Variables controlling S.A.D. break outs. */ + ogg_uint32_t GrpLowSadThresh; + ogg_uint32_t GrpHighSadThresh; + ogg_uint32_t ModifiedGrpLowSadThresh; + ogg_uint32_t ModifiedGrpHighSadThresh; + + ogg_int32_t PlaneHFragments; + ogg_int32_t PlaneVFragments; + ogg_int32_t PlaneHeight; + ogg_int32_t PlaneWidth; + ogg_int32_t PlaneStride; + + ogg_uint32_t BlockThreshold; + ogg_uint32_t BlockSgcThresh; + double UVBlockThreshCorrection; + double UVSgcCorrection; + + double YUVPlaneCorrectionFactor; + double AbsDiff_ScoreMultiplierTable[256]; + unsigned char NoiseScoreBoostTable[256]; + unsigned char MaxLineSearchLen; + + ogg_int32_t YuvDiffsCircularBufferSize; + ogg_int32_t ChLocalsCircularBufferSize; + ogg_int32_t PixelMapCircularBufferSize; + +} PP_INSTANCE; + + +typedef enum{ + CODE_INTER_NO_MV = 0x0, /* INTER prediction, (0,0) motion + vector implied. */ + CODE_INTRA = 0x1, /* INTRA i.e. no prediction. */ + CODE_INTER_PLUS_MV = 0x2, /* INTER prediction, non zero motion + vector. */ + CODE_INTER_LAST_MV = 0x3, /* Use Last Motion vector */ + CODE_INTER_PRIOR_LAST = 0x4, /* Prior last motion vector */ + CODE_USING_GOLDEN = 0x5, /* 'Golden frame' prediction (no MV). */ + CODE_GOLDEN_MV = 0x6, /* 'Golden frame' prediction plus MV. */ + CODE_INTER_FOURMV = 0x7 /* Inter prediction 4MV per macro block. */ +} CODING_MODE; + +typedef struct HUFF_ENTRY { + struct HUFF_ENTRY *ZeroChild; + struct HUFF_ENTRY *OneChild; + struct HUFF_ENTRY *Previous; + struct HUFF_ENTRY *Next; + ogg_int32_t Value; + ogg_uint32_t Frequency; + +} HUFF_ENTRY; + +typedef struct codec_setup_info { + ogg_uint32_t QThreshTable[Q_TABLE_SIZE]; + Q_LIST_ENTRY DcScaleFactorTable[Q_TABLE_SIZE]; + Q_LIST_ENTRY Y_coeffs[64]; + Q_LIST_ENTRY UV_coeffs[64]; + Q_LIST_ENTRY Inter_coeffs[64]; + + HUFF_ENTRY *HuffRoot[NUM_HUFF_TABLES]; +} codec_setup_info; + +typedef struct PB_INSTANCE { + oggpack_buffer *opb; + theora_info info; + /* how far do we shift the granulepos to seperate out P frame counts? */ + int keyframe_granule_shift; + + + /***********************************************************************/ + /* Decoder and Frame Type Information */ + + int DecoderErrorCode; + int FramesHaveBeenSkipped; + + int PostProcessEnabled; + ogg_uint32_t PostProcessingLevel; /* Perform post processing */ + + /* Frame Info */ + CODING_MODE CodingMode; + unsigned char FrameType; + unsigned char KeyFrameType; + ogg_uint32_t QualitySetting; + ogg_uint32_t FrameQIndex; /* Quality specified as a + table index */ + ogg_uint32_t ThisFrameQualityValue; /* Quality value for this frame */ + ogg_uint32_t LastFrameQualityValue; /* Last Frame's Quality */ + ogg_int32_t CodedBlockIndex; /* Number of Coded Blocks */ + ogg_uint32_t CodedBlocksThisFrame; /* Index into coded blocks */ + ogg_uint32_t FrameSize; /* The number of bytes in the frame. */ + + /**********************************************************************/ + /* Frame Size & Index Information */ + + ogg_uint32_t YPlaneSize; + ogg_uint32_t UVPlaneSize; + ogg_uint32_t YStride; + ogg_uint32_t UVStride; + ogg_uint32_t VFragments; + ogg_uint32_t HFragments; + ogg_uint32_t UnitFragments; + ogg_uint32_t YPlaneFragments; + ogg_uint32_t UVPlaneFragments; + + ogg_uint32_t ReconYPlaneSize; + ogg_uint32_t ReconUVPlaneSize; + + ogg_uint32_t YDataOffset; + ogg_uint32_t UDataOffset; + ogg_uint32_t VDataOffset; + ogg_uint32_t ReconYDataOffset; + ogg_uint32_t ReconUDataOffset; + ogg_uint32_t ReconVDataOffset; + ogg_uint32_t YSuperBlocks; /* Number of SuperBlocks in a Y frame */ + ogg_uint32_t UVSuperBlocks; /* Number of SuperBlocks in a U or V frame */ + ogg_uint32_t SuperBlocks; /* Total number of SuperBlocks in a + Y,U,V frame */ + + ogg_uint32_t YSBRows; /* Number of rows of SuperBlocks in a + Y frame */ + ogg_uint32_t YSBCols; /* Number of cols of SuperBlocks in a + Y frame */ + ogg_uint32_t UVSBRows; /* Number of rows of SuperBlocks in a + U or V frame */ + ogg_uint32_t UVSBCols; /* Number of cols of SuperBlocks in a + U or V frame */ + + ogg_uint32_t YMacroBlocks; /* Number of Macro-Blocks in Y component */ + ogg_uint32_t UVMacroBlocks; /* Number of Macro-Blocks in U/V component */ + ogg_uint32_t MacroBlocks; /* Total number of Macro-Blocks */ + + /**********************************************************************/ + /* Frames */ + YUV_BUFFER_ENTRY *ThisFrameRecon; + YUV_BUFFER_ENTRY *GoldenFrame; + YUV_BUFFER_ENTRY *LastFrameRecon; + YUV_BUFFER_ENTRY *PostProcessBuffer; + + /**********************************************************************/ + /* Fragment Information */ + ogg_uint32_t *pixel_index_table; /* start address of first + pixel of fragment in + source */ + ogg_uint32_t *recon_pixel_index_table; /* start address of first + pixel in recon buffer */ + + unsigned char *display_fragments; /* Fragment update map */ + unsigned char *skipped_display_fragments;/* whether fragment YUV + Conversion and update is to be + skipped */ + ogg_int32_t *CodedBlockList; /* A list of fragment indices for + coded blocks. */ + MOTION_VECTOR *FragMVect; /* fragment motion vectors */ + + ogg_uint32_t *FragTokenCounts; /* Number of tokens per fragment */ + ogg_uint32_t (*TokenList)[128]; /* Fragment Token Pointers */ + + ogg_int32_t *FragmentVariances; + ogg_uint32_t *FragQIndex; /* Fragment Quality used in + PostProcess */ + Q_LIST_ENTRY (*PPCoefBuffer)[64]; /* PostProcess Buffer for + coefficients data */ + + unsigned char *FragCoeffs; /* # of coeffs decoded so far for + fragment */ + unsigned char *FragCoefEOB; /* Position of last non 0 coef + within QFragData */ + Q_LIST_ENTRY (*QFragData)[64]; /* Fragment Coefficients + Array Pointers */ + CODING_MODE *FragCodingMethod; /* coding method for the + fragment */ + + /***********************************************************************/ + /* pointers to addresses used for allocation and deallocation the + others are rounded up to the nearest 32 bytes */ + + COEFFNODE *_Nodes; + ogg_uint32_t *transIndex; /* ptr to table of + transposed indexes */ + + /***********************************************************************/ + ogg_int32_t bumpLast; + + /* Macro Block and SuperBlock Information */ + ogg_int32_t (*BlockMap)[4][4]; /* super block + sub macro + block + sub frag -> + FragIndex */ + + /* Coded flag arrays and counters for them */ + unsigned char *SBCodedFlags; + unsigned char *SBFullyFlags; + unsigned char *MBCodedFlags; + unsigned char *MBFullyFlags; + + /**********************************************************************/ + ogg_uint32_t EOB_Run; + + COORDINATE *FragCoordinates; + MOTION_VECTOR MVector; + ogg_int32_t ReconPtr2Offset; /* Offset for second reconstruction + in half pixel MC */ + Q_LIST_ENTRY *quantized_list; + ogg_int16_t *ReconDataBuffer; + Q_LIST_ENTRY InvLastIntraDC; + Q_LIST_ENTRY InvLastInterDC; + Q_LIST_ENTRY LastIntraDC; + Q_LIST_ENTRY LastInterDC; + + ogg_uint32_t BlocksToDecode; /* Blocks to be decoded this frame */ + ogg_uint32_t DcHuffChoice; /* Huffman table selection variables */ + unsigned char ACHuffChoice; + ogg_uint32_t QuadMBListIndex; + + ogg_int32_t ByteCount; + + ogg_uint32_t bit_pattern; + unsigned char bits_so_far; + unsigned char NextBit; + ogg_int32_t BitsLeft; + + ogg_int16_t *DequantBuffer; + + ogg_int32_t fp_quant_InterUV_coeffs[64]; + ogg_int32_t fp_quant_InterUV_round[64]; + ogg_int32_t fp_ZeroBinSize_InterUV[64]; + + ogg_int16_t *TmpReconBuffer; + ogg_int16_t *TmpDataBuffer; + + /* Loop filter bounding values */ + ogg_int32_t FiltBoundingValue[512]; + + /* Dequantiser and rounding tables */ + ogg_uint32_t QThreshTable[Q_TABLE_SIZE]; + Q_LIST_ENTRY DcScaleFactorTable[Q_TABLE_SIZE]; + Q_LIST_ENTRY Y_coeffs[64]; + Q_LIST_ENTRY UV_coeffs[64]; + Q_LIST_ENTRY Inter_coeffs[64]; + Q_LIST_ENTRY *dequant_InterUV_coeffs; + unsigned int quant_index[64]; + ogg_int32_t quant_Y_coeffs[64]; + ogg_int32_t quant_UV_coeffs[64]; + ogg_int32_t fp_quant_Y_coeffs[64]; /* used in reiniting quantizers */ + + HUFF_ENTRY *HuffRoot_VP3x[NUM_HUFF_TABLES]; + ogg_uint32_t *HuffCodeArray_VP3x[NUM_HUFF_TABLES]; + unsigned char *HuffCodeLengthArray_VP3x[NUM_HUFF_TABLES]; + unsigned char *ExtraBitLengths_VP3x; + + /* Quantiser and rounding tables */ + ogg_int32_t fp_quant_UV_coeffs[64]; + ogg_int32_t fp_quant_Inter_coeffs[64]; + ogg_int32_t fp_quant_Y_round[64]; + ogg_int32_t fp_quant_UV_round[64]; + ogg_int32_t fp_quant_Inter_round[64]; + ogg_int32_t fp_ZeroBinSize_Y[64]; + ogg_int32_t fp_ZeroBinSize_UV[64]; + ogg_int32_t fp_ZeroBinSize_Inter[64]; + ogg_int32_t *fquant_coeffs; + ogg_int32_t *fquant_round; + ogg_int32_t *fquant_ZbSize; + Q_LIST_ENTRY *dequant_Y_coeffs; + Q_LIST_ENTRY *dequant_UV_coeffs; + Q_LIST_ENTRY *dequant_Inter_coeffs; + Q_LIST_ENTRY *dequant_coeffs; + + /* Predictor used in choosing entropy table for decoding block patterns. */ + unsigned char BlockPatternPredictor; + + short Modifier[4][512]; + short *ModifierPointer[4]; + + unsigned char *DataOutputInPtr; + + +} PB_INSTANCE; + +typedef struct CP_INSTANCE { + + /* Compressor Configuration */ + SCAN_CONFIG_DATA ScanConfig; + CONFIG_TYPE2 Configuration; + int GoldenFrameEnabled; + int InterPrediction; + int MotionCompensation; + + ogg_uint32_t LastKeyFrame ; + ogg_int32_t DropCount ; + ogg_int32_t MaxConsDroppedFrames ; + ogg_int32_t DropFrameTriggerBytes; + int DropFrameCandidate; + + /* Compressor Statistics */ + double TotErrScore; + ogg_int64_t KeyFrameCount; /* Count of key frames. */ + ogg_int64_t TotKeyFrameBytes; + ogg_uint32_t LastKeyFrameSize; + ogg_uint32_t PriorKeyFrameSize[KEY_FRAME_CONTEXT]; + ogg_uint32_t PriorKeyFrameDistance[KEY_FRAME_CONTEXT]; + ogg_int32_t FrameQuality[6]; + int DecoderErrorCode; /* Decoder error flag. */ + ogg_int32_t ThreshMapThreshold; + ogg_int32_t TotalMotionScore; + ogg_int64_t TotalByteCount; + ogg_int32_t FixedQ; + + /* Frame Statistics */ + signed char InterCodeCount; + ogg_int64_t CurrentFrame; + ogg_int64_t CarryOver ; + ogg_uint32_t LastFrameSize; + ogg_uint32_t FrameBitCount; + int ThisIsFirstFrame; + int ThisIsKeyFrame; + + ogg_int32_t MotionScore; + ogg_uint32_t RegulationBlocks; + ogg_int32_t RecoveryMotionScore; + int RecoveryBlocksAdded ; + double ProportionRecBlocks; + double MaxRecFactor ; + + /* Rate Targeting variables. */ + ogg_uint32_t ThisFrameTargetBytes; + double BpbCorrectionFactor; + + /* Up regulation variables */ + ogg_uint32_t FinalPassLastPos; /* Used to regulate a final + unrestricted high quality + pass. */ + ogg_uint32_t LastEndSB; /* Where we were in the loop + last time. */ + ogg_uint32_t ResidueLastEndSB; /* Where we were in the residue + update loop last time. */ + + /* Controlling Block Selection */ + ogg_uint32_t MVChangeFactor; + ogg_uint32_t FourMvChangeFactor; + ogg_uint32_t MinImprovementForNewMV; + ogg_uint32_t ExhaustiveSearchThresh; + ogg_uint32_t MinImprovementForFourMV; + ogg_uint32_t FourMVThreshold; + + /* Module shared data structures. */ + ogg_int32_t frame_target_rate; + ogg_int32_t BaseLineFrameTargetRate; + ogg_int32_t min_blocks_per_frame; + ogg_uint32_t tot_bytes_old; + + /*********************************************************************/ + /* Frames Used in the selecetive convolution filtering of the Y plane. */ + unsigned char *ConvDestBuffer; + YUV_BUFFER_ENTRY *yuv0ptr; + YUV_BUFFER_ENTRY *yuv1ptr; + /*********************************************************************/ + + /*********************************************************************/ + /* Token Buffers */ + ogg_uint32_t *OptimisedTokenListEb; /* Optimised token list extra bits */ + unsigned char *OptimisedTokenList; /* Optimised token list. */ + unsigned char *OptimisedTokenListHi; /* Optimised token list huffman + table index */ + + unsigned char *OptimisedTokenListPl; /* Plane to which the token + belongs Y = 0 or UV = 1 */ + ogg_int32_t OptimisedTokenCount; /* Count of Optimized tokens */ + ogg_uint32_t RunHuffIndex; /* Huffman table in force at + the start of a run */ + ogg_uint32_t RunPlaneIndex; /* The plane (Y=0 UV=1) to + which the first token in + an EOB run belonged. */ + + + ogg_uint32_t TotTokenCount; + ogg_int32_t TokensToBeCoded; + ogg_int32_t TokensCoded; + /********************************************************************/ + + /* SuperBlock, MacroBLock and Fragment Information */ + /* Coded flag arrays and counters for them */ + unsigned char *PartiallyCodedFlags; + unsigned char *PartiallyCodedMbPatterns; + unsigned char *UncodedMbFlags; + + unsigned char *extra_fragments; /* extra updates not + recommended by pre-processor */ + ogg_int16_t *OriginalDC; + + ogg_uint32_t *FragmentLastQ; /* Array used to keep track of + quality at which each + fragment was last + updated. */ + unsigned char *FragTokens; + ogg_uint32_t *FragTokenCounts; /* Number of tokens per fragment */ + + ogg_uint32_t *RunHuffIndices; + ogg_uint32_t *LastCodedErrorScore; + ogg_uint32_t *ModeList; + MOTION_VECTOR *MVList; + + unsigned char *BlockCodedFlags; + + ogg_uint32_t MvListCount; + ogg_uint32_t ModeListCount; + + + unsigned char *DataOutputBuffer; + /*********************************************************************/ + + ogg_uint32_t RunLength; + ogg_uint32_t MaxBitTarget; /* Cut off target for rate capping */ + double BitRateCapFactor; /* Factor relating normal frame target + to cut off target. */ + + unsigned char MBCodingMode; /* Coding mode flags */ + + ogg_int32_t MVPixelOffsetY[MAX_SEARCH_SITES]; + ogg_uint32_t InterTripOutThresh; + unsigned char MVEnabled; + ogg_uint32_t MotionVectorSearchCount; + ogg_uint32_t FrameMVSearcOunt; + ogg_int32_t MVSearchSteps; + ogg_int32_t MVOffsetX[MAX_SEARCH_SITES]; + ogg_int32_t MVOffsetY[MAX_SEARCH_SITES]; + ogg_int32_t HalfPixelRef2Offset[9]; /* Offsets for half pixel + compensation */ + signed char HalfPixelXOffset[9]; /* Half pixel MV offsets for X */ + signed char HalfPixelYOffset[9]; /* Half pixel MV offsets for Y */ + + ogg_uint32_t bit_pattern ; + unsigned char bits_so_far ; + ogg_uint32_t lastval ; + ogg_uint32_t lastrun ; + + Q_LIST_ENTRY *quantized_list; + + MOTION_VECTOR MVector; + ogg_uint32_t TempBitCount; + ogg_int16_t *DCT_codes; /* Buffer that stores the result of + Forward DCT */ + ogg_int16_t *DCTDataBuffer; /* Input data buffer for Forward DCT */ + + /* Motion compensation related variables */ + ogg_uint32_t MvMaxExtent; + + double QTargetModifier[Q_TABLE_SIZE]; + + /* instances (used for reconstructing buffers and to hold tokens etc.) */ + PP_INSTANCE pp; /* preprocessor */ + PB_INSTANCE pb; /* playback */ + + /* ogg bitpacker for use in packet coding, other API state */ + oggpack_buffer *oggbuffer; +#ifdef LIBOGG2 /* Remember, this is just until we drop libogg1 */ + ogg_buffer_state *oggbufferstate; +#endif + int readyflag; + int packetflag; + int doneflag; + +} CP_INSTANCE; + +#define clamp255(x) ((unsigned char)((((x)<0)-1) & ((x) | -((x)>255)))) + +extern void ConfigurePP( PP_INSTANCE *ppi, int Level ) ; +extern ogg_uint32_t YUVAnalyseFrame( PP_INSTANCE *ppi, + ogg_uint32_t * KFIndicator ); + +extern void ClearPPInstance(PP_INSTANCE *ppi); +extern void InitPPInstance(PP_INSTANCE *ppi); +extern int GetFrameType(PB_INSTANCE *pbi); +extern void InitPBInstance(PB_INSTANCE *pbi); +extern void ClearPBInstance(PB_INSTANCE *pbi); + + +extern void IDctSlow( Q_LIST_ENTRY * InputData, + ogg_int16_t *QuantMatrix, + ogg_int16_t * OutputData ) ; + +extern void IDct10( Q_LIST_ENTRY * InputData, + ogg_int16_t *QuantMatrix, + ogg_int16_t * OutputData ); + +extern void IDct1( Q_LIST_ENTRY * InputData, + ogg_int16_t *QuantMatrix, + ogg_int16_t * OutputData ); + +extern void ReconIntra( PB_INSTANCE *pbi, unsigned char * ReconPtr, + ogg_int16_t * ChangePtr, ogg_uint32_t LineStep ); + +extern void ReconInter( PB_INSTANCE *pbi, unsigned char * ReconPtr, + unsigned char * RefPtr, ogg_int16_t * ChangePtr, + ogg_uint32_t LineStep ) ; + +extern void ReconInterHalfPixel2( PB_INSTANCE *pbi, unsigned char * ReconPtr, + unsigned char * RefPtr1, + unsigned char * RefPtr2, + ogg_int16_t * ChangePtr, + ogg_uint32_t LineStep ) ; + +extern void SetupLoopFilter(PB_INSTANCE *pbi); +extern void CopyBlock(unsigned char *src, + unsigned char *dest, + unsigned int srcstride); +extern void LoopFilter(PB_INSTANCE *pbi); +extern void ReconRefFrames (PB_INSTANCE *pbi); +extern void ExpandToken( Q_LIST_ENTRY * ExpandedBlock, + unsigned char * CoeffIndex, ogg_uint32_t Token, + ogg_int32_t ExtraBits ); +extern void ClearDownQFragData(PB_INSTANCE *pbi); +extern void select_Y_quantiser ( PB_INSTANCE *pbi ); +extern void select_Inter_quantiser ( PB_INSTANCE *pbi ); +extern void select_UV_quantiser ( PB_INSTANCE *pbi ); +extern void select_InterUV_quantiser ( PB_INSTANCE *pbi ); +extern void quantize( PB_INSTANCE *pbi, + ogg_int16_t * DCT_block, + Q_LIST_ENTRY * quantized_list); +extern void UpdateQ( PB_INSTANCE *pbi, ogg_uint32_t NewQ ); +extern void UpdateQC( CP_INSTANCE *cpi, ogg_uint32_t NewQ ); +extern void fdct_short ( ogg_int16_t * InputData, ogg_int16_t * OutputData ); +extern ogg_uint32_t DPCMTokenizeBlock (CP_INSTANCE *cpi, + ogg_int32_t FragIndex); +extern void TransformQuantizeBlock (CP_INSTANCE *cpi, ogg_int32_t FragIndex, + ogg_uint32_t PixelsPerLine ) ; +extern void ClearFragmentInfo(PB_INSTANCE * pbi); +extern void InitFragmentInfo(PB_INSTANCE * pbi); +extern void ClearFrameInfo(PB_INSTANCE * pbi); +extern void InitFrameInfo(PB_INSTANCE * pbi, unsigned int FrameSize); +extern void InitializeFragCoordinates(PB_INSTANCE *pbi); +extern void InitFrameDetails(PB_INSTANCE *pbi); +extern void WriteQTables(PB_INSTANCE *pbi,oggpack_buffer *opb); +extern int ReadQTables(codec_setup_info *ci,oggpack_buffer* opb); +extern void CopyQTables(PB_INSTANCE *pbi, codec_setup_info *ci); +extern void InitQTables( PB_INSTANCE *pbi ); +extern void InitHuffmanSet( PB_INSTANCE *pbi ); +extern void ClearHuffmanSet( PB_INSTANCE *pbi ); +extern int ReadHuffmanTrees(codec_setup_info *ci, oggpack_buffer *opb); +extern void WriteHuffmanTrees(HUFF_ENTRY *HuffRoot[NUM_HUFF_TABLES], + oggpack_buffer *opb); +extern void InitHuffmanTrees(PB_INSTANCE *pbi, const codec_setup_info *ci); +extern void ClearHuffmanTrees(HUFF_ENTRY *HuffRoot[NUM_HUFF_TABLES]); +extern void QuadDecodeDisplayFragments ( PB_INSTANCE *pbi ); +extern void PackAndWriteDFArray( CP_INSTANCE *cpi ); +extern void UpdateFragQIndex(PB_INSTANCE *pbi); +extern void PostProcess(PB_INSTANCE *pbi); +extern void InitMotionCompensation ( CP_INSTANCE *cpi ); +extern ogg_uint32_t GetMBIntraError (CP_INSTANCE *cpi, ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine ) ; +extern ogg_uint32_t GetMBInterError (CP_INSTANCE *cpi, + unsigned char * SrcPtr, + unsigned char * RefPtr, + ogg_uint32_t FragIndex, + ogg_int32_t LastXMV, + ogg_int32_t LastYMV, + ogg_uint32_t PixelsPerLine ) ; +extern void WriteFrameHeader( CP_INSTANCE *cpi) ; +extern ogg_uint32_t GetMBMVInterError (CP_INSTANCE *cpi, + unsigned char * RefFramePtr, + ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine, + ogg_int32_t *MVPixelOffset, + MOTION_VECTOR *MV ); +extern ogg_uint32_t GetMBMVExhaustiveSearch (CP_INSTANCE *cpi, + unsigned char * RefFramePtr, + ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine, + MOTION_VECTOR *MV ); +extern ogg_uint32_t GetFOURMVExhaustiveSearch (CP_INSTANCE *cpi, + unsigned char * RefFramePtr, + ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine, + MOTION_VECTOR *MV ) ; +extern ogg_uint32_t EncodeData(CP_INSTANCE *cpi); +extern ogg_uint32_t PickIntra( CP_INSTANCE *cpi, + ogg_uint32_t SBRows, + ogg_uint32_t SBCols); +extern ogg_uint32_t PickModes(CP_INSTANCE *cpi, + ogg_uint32_t SBRows, + ogg_uint32_t SBCols, + ogg_uint32_t PixelsPerLine, + ogg_uint32_t *InterError, + ogg_uint32_t *IntraError); + +extern CODING_MODE FrArrayUnpackMode(PB_INSTANCE *pbi); +extern void CreateBlockMapping ( ogg_int32_t (*BlockMap)[4][4], + ogg_uint32_t YSuperBlocks, + ogg_uint32_t UVSuperBlocks, + ogg_uint32_t HFrags, ogg_uint32_t VFrags ); +extern void UpRegulateDataStream (CP_INSTANCE *cpi, ogg_uint32_t RegulationQ, + ogg_int32_t RecoveryBlocks ) ; +extern void RegulateQ( CP_INSTANCE *cpi, ogg_int32_t UpdateScore ); +extern void CopyBackExtraFrags(CP_INSTANCE *cpi); +extern void UpdateUMVBorder( PB_INSTANCE *pbi, + unsigned char * DestReconPtr ); +extern void PInitFrameInfo(PP_INSTANCE * ppi); +extern int GetFrameType(PB_INSTANCE *pbi); +extern void SetFrameType( PB_INSTANCE *pbi,unsigned char FrType ); +extern double GetEstimatedBpb( CP_INSTANCE *cpi, ogg_uint32_t TargetQ ); +extern void ClearTmpBuffers(PB_INSTANCE * pbi); +extern void InitTmpBuffers(PB_INSTANCE * pbi); +extern void ScanYUVInit( PP_INSTANCE * ppi, + SCAN_CONFIG_DATA * ScanConfigPtr); +extern int LoadAndDecode(PB_INSTANCE *pbi); +#endif diff --git a/src/add-ons/media/plugins/theora/libtheora/encoder_lookup.h b/src/add-ons/media/plugins/theora/libtheora/encoder_lookup.h new file mode 100644 index 0000000000..c716ec8549 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/encoder_lookup.h @@ -0,0 +1,120 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: simple static lookups for VP3 frame encoder + last mod: $Id: encoder_lookup.h,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include "encoder_internal.h" + +ogg_uint32_t MvPattern[(MAX_MV_EXTENT * 2) + 1] = { + 0x000000ff, 0x000000fd, 0x000000fb, 0x000000f9, + 0x000000f7, 0x000000f5, 0x000000f3, 0x000000f1, + 0x000000ef, 0x000000ed, 0x000000eb, 0x000000e9, + 0x000000e7, 0x000000e5, 0x000000e3, 0x000000e1, + 0x0000006f, 0x0000006d, 0x0000006b, 0x00000069, + 0x00000067, 0x00000065, 0x00000063, 0x00000061, + 0x0000002f, 0x0000002d, 0x0000002b, 0x00000029, + 0x00000009, 0x00000007, 0x00000002, 0x00000000, + 0x00000001, 0x00000006, 0x00000008, 0x00000028, + 0x0000002a, 0x0000002c, 0x0000002e, 0x00000060, + 0x00000062, 0x00000064, 0x00000066, 0x00000068, + 0x0000006a, 0x0000006c, 0x0000006e, 0x000000e0, + 0x000000e2, 0x000000e4, 0x000000e6, 0x000000e8, + 0x000000ea, 0x000000ec, 0x000000ee, 0x000000f0, + 0x000000f2, 0x000000f4, 0x000000f6, 0x000000f8, + 0x000000fa, 0x000000fc, 0x000000fe, +}; + +ogg_uint32_t MvBits[(MAX_MV_EXTENT * 2) + 1] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 4, 4, 3, 3, + 3, 4, 4, 6, 6, 6, 6, 7, + 7, 7, 7, 7, 7, 7, 7, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, +}; + +ogg_uint32_t MvPattern2[(MAX_MV_EXTENT * 2) + 1] = { + 0x0000003f, 0x0000003d, 0x0000003b, 0x00000039, + 0x00000037, 0x00000035, 0x00000033, 0x00000031, + 0x0000002f, 0x0000002d, 0x0000002b, 0x00000029, + 0x00000027, 0x00000025, 0x00000023, 0x00000021, + 0x0000001f, 0x0000001d, 0x0000001b, 0x00000019, + 0x00000017, 0x00000015, 0x00000013, 0x00000011, + 0x0000000f, 0x0000000d, 0x0000000b, 0x00000009, + 0x00000007, 0x00000005, 0x00000003, 0x00000000, + 0x00000002, 0x00000004, 0x00000006, 0x00000008, + 0x0000000a, 0x0000000c, 0x0000000e, 0x00000010, + 0x00000012, 0x00000014, 0x00000016, 0x00000018, + 0x0000001a, 0x0000001c, 0x0000001e, 0x00000020, + 0x00000022, 0x00000024, 0x00000026, 0x00000028, + 0x0000002a, 0x0000002c, 0x0000002e, 0x00000030, + 0x00000032, 0x00000034, 0x00000036, 0x00000038, + 0x0000003a, 0x0000003c, 0x0000003e, +}; + +ogg_uint32_t MvBits2[(MAX_MV_EXTENT * 2) + 1] = { + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, +}; + +ogg_uint32_t ModeBitPatterns[MAX_MODES] = { + 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0x7E, 0x7F }; + +ogg_int32_t ModeBitLengths[MAX_MODES] = { + 1, 2, 3, 4, 5, 6, 7, 7 }; + +unsigned char ModeSchemes[MODE_METHODS-2][MAX_MODES] = { + /* Last Mv dominates */ + { 3, 4, 2, 0, 1, 5, 6, 7 }, /* L P M N I G GM 4 */ + { 2, 4, 3, 0, 1, 5, 6, 7 }, /* L P N M I G GM 4 */ + { 3, 4, 1, 0, 2, 5, 6, 7 }, /* L M P N I G GM 4 */ + { 2, 4, 1, 0, 3, 5, 6, 7 }, /* L M N P I G GM 4 */ + + /* No MV dominates */ + { 0, 4, 3, 1, 2, 5, 6, 7 }, /* N L P M I G GM 4 */ + { 0, 5, 4, 2, 3, 1, 6, 7 }, /* N G L P M I GM 4 */ + +}; + + +ogg_uint32_t MvThreshTable[Q_TABLE_SIZE] = { + 65, 65, 65, 65, 50, 50, 50, 50, + 40, 40, 40, 40, 40, 40, 40, 40, + 30, 30, 30, 30, 30, 30, 30, 30, + 20, 20, 20, 20, 20, 20, 20, 20, + 15, 15, 15, 15, 15, 15, 15, 15, + 10, 10, 10, 10, 10, 10, 10, 10, + 5, 5, 5, 5, 5, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +ogg_uint32_t MVChangeFactorTable[Q_TABLE_SIZE] = { + 11, 11, 11, 11, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15 +}; diff --git a/src/add-ons/media/plugins/theora/libtheora/frarray.c b/src/add-ons/media/plugins/theora/libtheora/frarray.c new file mode 100644 index 0000000000..00c4565c8e --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/frarray.c @@ -0,0 +1,614 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: frarray.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include "encoder_internal.h" +#include "block_inline.h" + +static ogg_uint32_t FrArrayCodeSBRun( CP_INSTANCE *cpi, ogg_uint32_t value ){ + ogg_uint32_t CodedVal = 0; + ogg_uint32_t CodedBits = 0; + + /* Coding scheme: + Codeword RunLength + 0 1 + 10x 2-3 + 110x 4-5 + 1110xx 6-9 + 11110xxx 10-17 + 111110xxxx 18-33 + 111111xxxxxxxxxxxx 34-4129 */ + + if ( value == 1 ){ + CodedVal = 0; + CodedBits = 1; + } else if ( value <= 3 ) { + CodedVal = 0x0004 + (value - 2); + CodedBits = 3; + } else if ( value <= 5 ) { + CodedVal = 0x000C + (value - 4); + CodedBits = 4; + } else if ( value <= 9 ) { + CodedVal = 0x0038 + (value - 6); + CodedBits = 6; + } else if ( value <= 17 ) { + CodedVal = 0x00F0 + (value - 10); + CodedBits = 8; + } else if ( value <= 33 ) { + CodedVal = 0x03E0 + (value - 18); + CodedBits = 10; + } else { + CodedVal = 0x3F000 + (value - 34); + CodedBits = 18; + } + + /* Add the bits to the encode holding buffer. */ + oggpackB_write( cpi->oggbuffer, CodedVal, (ogg_uint32_t)CodedBits ); + + return CodedBits; +} + +static ogg_uint32_t FrArrayCodeBlockRun( CP_INSTANCE *cpi, + ogg_uint32_t value ) { + ogg_uint32_t CodedVal = 0; + ogg_uint32_t CodedBits = 0; + + /* Coding scheme: + Codeword RunLength + 0x 1-2 + 10x 3-4 + 110x 5-6 + 1110xx 7-10 + 11110xx 11-14 + 11111xxxx 15-30 */ + + if ( value <= 2 ) { + CodedVal = value - 1; + CodedBits = 2; + } else if ( value <= 4 ) { + CodedVal = 0x0004 + (value - 3); + CodedBits = 3; + + } else if ( value <= 6 ) { + CodedVal = 0x000C + (value - 5); + CodedBits = 4; + + } else if ( value <= 10 ) { + CodedVal = 0x0038 + (value - 7); + CodedBits = 6; + + } else if ( value <= 14 ) { + CodedVal = 0x0078 + (value - 11); + CodedBits = 7; + } else { + CodedVal = 0x01F0 + (value - 15); + CodedBits = 9; + } + + /* Add the bits to the encode holding buffer. */ + oggpackB_write( cpi->oggbuffer, CodedVal, (ogg_uint32_t)CodedBits ); + + return CodedBits; +} + +void PackAndWriteDFArray( CP_INSTANCE *cpi ){ + ogg_uint32_t i; + unsigned char val; + ogg_uint32_t run_count; + + ogg_uint32_t SB, MB, B; /* Block, MB and SB loop variables */ + ogg_uint32_t BListIndex = 0; + ogg_uint32_t LastSbBIndex = 0; + ogg_int32_t DfBlockIndex; /* Block index in display_fragments */ + + /* Initialise workspaces */ + memset( cpi->pb.SBFullyFlags, 1, cpi->pb.SuperBlocks); + memset( cpi->pb.SBCodedFlags, 0, cpi->pb.SuperBlocks ); + memset( cpi->PartiallyCodedFlags, 0, cpi->pb.SuperBlocks ); + memset( cpi->BlockCodedFlags, 0, cpi->pb.UnitFragments); + + for( SB = 0; SB < cpi->pb.SuperBlocks; SB++ ) { + /* Check for coded blocks and macro-blocks */ + for ( MB=0; MB<4; MB++ ) { + /* If MB in frame */ + if ( QuadMapToMBTopLeft(cpi->pb.BlockMap,SB,MB) >= 0 ) { + for ( B=0; B<4; B++ ) { + DfBlockIndex = QuadMapToIndex1( cpi->pb.BlockMap,SB, MB, B ); + + /* Does Block lie in frame: */ + if ( DfBlockIndex >= 0 ) { + /* In Frame: If it is not coded then this SB is only + partly coded.: */ + if ( cpi->pb.display_fragments[DfBlockIndex] ) { + cpi->pb.SBCodedFlags[SB] = 1; /* SB at least partly coded */ + cpi->BlockCodedFlags[BListIndex] = 1; /* Block is coded */ + }else{ + cpi->pb.SBFullyFlags[SB] = 0; /* SB not fully coded */ + cpi->BlockCodedFlags[BListIndex] = 0; /* Block is not coded */ + } + + BListIndex++; + } + } + } + } + + /* Is the SB fully coded or uncoded. + If so then backup BListIndex and MBListIndex */ + if ( cpi->pb.SBFullyFlags[SB] || !cpi->pb.SBCodedFlags[SB] ) { + BListIndex = LastSbBIndex; /* Reset to values from previous SB */ + }else{ + cpi->PartiallyCodedFlags[SB] = 1; /* Set up list of partially + coded SBs */ + LastSbBIndex = BListIndex; + } + } + + /* Code list of partially coded Super-Block. */ + val = cpi->PartiallyCodedFlags[0]; + oggpackB_write( cpi->oggbuffer, (ogg_uint32_t)val, 1); + i = 0; + while ( i < cpi->pb.SuperBlocks ) { + run_count = 0; + while ( (ipb.SuperBlocks) && (cpi->PartiallyCodedFlags[i]==val) ) { + i++; + run_count++; + } + + /* Code the run */ + FrArrayCodeSBRun( cpi, run_count ); + val = ( val == 0 ) ? 1 : 0; + } + + /* RLC Super-Block fully/not coded. */ + i = 0; + + /* Skip partially coded blocks */ + while( (i < cpi->pb.SuperBlocks) && cpi->PartiallyCodedFlags[i] ) + i++; + + if ( i < cpi->pb.SuperBlocks ) { + val = cpi->pb.SBFullyFlags[i]; + oggpackB_write( cpi->oggbuffer, (ogg_uint32_t)val, 1); + + while ( i < cpi->pb.SuperBlocks ) { + run_count = 0; + while ( (i < cpi->pb.SuperBlocks) && (cpi->pb.SBFullyFlags[i] == val) ) { + i++; + /* Skip partially coded blocks */ + while( (i < cpi->pb.SuperBlocks) && cpi->PartiallyCodedFlags[i] ) + i++; + run_count++; + } + + /* Code the run */ + FrArrayCodeSBRun( cpi, run_count ); + val = ( val == 0 ) ? 1 : 0; + } + } + + /* Now code the block flags */ + if ( BListIndex > 0 ) { + /* Code the block flags start value */ + val = cpi->BlockCodedFlags[0]; + oggpackB_write( cpi->oggbuffer, (ogg_uint32_t)val, 1); + + /* Now code the block flags. */ + for ( i = 0; i < BListIndex; ) { + run_count = 0; + while ( (cpi->BlockCodedFlags[i] == val) && (i < BListIndex) ) { + i++; + run_count++; + } + + FrArrayCodeBlockRun( cpi, run_count ); + val = ( val == 0 ) ? 1 : 0; + + } + } +} + +static void FrArrayDeCodeInit(PB_INSTANCE *pbi){ + /* Initialise the decoding of a run. */ + pbi->bit_pattern = 0; + pbi->bits_so_far = 0; +} + +static int FrArrayDeCodeBlockRun( PB_INSTANCE *pbi, ogg_uint32_t bit_value, + ogg_int32_t * run_value ){ + int ret_val = 0; + + /* Add in the new bit value. */ + pbi->bits_so_far++; + pbi->bit_pattern = (pbi->bit_pattern << 1) + (bit_value & 1); + + /* Coding scheme: + Codeword RunLength + 0x 1-2 + 10x 3-4 + 110x 5-6 + 1110xx 7-10 + 11110xx 11-14 + 11111xxxx 15-30 + */ + + switch ( pbi->bits_so_far ){ + case 2: + /* If bit 1 is clear */ + if ( !(pbi->bit_pattern & 0x0002) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0001) + 1; + } + break; + + case 3: + /* If bit 1 is clear */ + if ( !(pbi->bit_pattern & 0x0002) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0001) + 3; + } + break; + + case 4: + /* If bit 1 is clear */ + if ( !(pbi->bit_pattern & 0x0002) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0001) + 5; + } + break; + + case 6: + /* If bit 2 is clear */ + if ( !(pbi->bit_pattern & 0x0004) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0003) + 7; + } + break; + + case 7: + /* If bit 2 is clear */ + if ( !(pbi->bit_pattern & 0x0004) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0003) + 11; + } + break; + + case 9: + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x000F) + 15; + break; + } + + return ret_val; +} + +static int FrArrayDeCodeSBRun (PB_INSTANCE *pbi, ogg_uint32_t bit_value, + ogg_int32_t * run_value ){ + int ret_val = 0; + + /* Add in the new bit value. */ + pbi->bits_so_far++; + pbi->bit_pattern = (pbi->bit_pattern << 1) + (bit_value & 1); + + /* Coding scheme: + Codeword RunLength + 0 1 + 10x 2-3 + 110x 4-5 + 1110xx 6-9 + 11110xxx 10-17 + 111110xxxx 18-33 + 111111xxxxxxxxxxxx 34-4129 + */ + + switch ( pbi->bits_so_far ){ + case 1: + if ( pbi->bit_pattern == 0 ){ + ret_val = 1; + *run_value = 1; + } + break; + + case 3: + /* Bit 1 clear */ + if ( !(pbi->bit_pattern & 0x0002) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0001) + 2; + } + break; + + case 4: + /* Bit 1 clear */ + if ( !(pbi->bit_pattern & 0x0002) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0001) + 4; + } + break; + + case 6: + /* Bit 2 clear */ + if ( !(pbi->bit_pattern & 0x0004) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0003) + 6; + } + break; + + case 8: + /* Bit 3 clear */ + if ( !(pbi->bit_pattern & 0x0008) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0007) + 10; + } + break; + + case 10: + /* Bit 4 clear */ + if ( !(pbi->bit_pattern & 0x0010) ){ + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x000F) + 18; + } + break; + + case 18: + ret_val = 1; + *run_value = (pbi->bit_pattern & 0x0FFF) + 34; + break; + + default: + ret_val = 0; + break; + } + + return ret_val; +} + +static void GetNextBInit(PB_INSTANCE *pbi){ + long ret; + + theora_read(pbi->opb,1,&ret); + pbi->NextBit = (unsigned char)ret; + + /* Read run length */ + FrArrayDeCodeInit(pbi); + do theora_read(pbi->opb,1,&ret); + while (FrArrayDeCodeBlockRun(pbi,ret,&pbi->BitsLeft)==0); + +} + +static unsigned char GetNextBBit (PB_INSTANCE *pbi){ + long ret; + if ( !pbi->BitsLeft ){ + /* Toggle the value. */ + pbi->NextBit = ( pbi->NextBit == 1 ) ? 0 : 1; + + /* Read next run */ + FrArrayDeCodeInit(pbi); + do theora_read(pbi->opb,1,&ret); + while (FrArrayDeCodeBlockRun(pbi,ret,&pbi->BitsLeft)==0); + + } + + /* Have read a bit */ + pbi->BitsLeft--; + + /* Return next bit value */ + return pbi->NextBit; +} + +static void GetNextSbInit(PB_INSTANCE *pbi){ + long ret; + + theora_read(pbi->opb,1,&ret); + pbi->NextBit = (unsigned char)ret; + + /* Read run length */ + FrArrayDeCodeInit(pbi); + do theora_read(pbi->opb,1,&ret); + while (FrArrayDeCodeSBRun(pbi,ret,&pbi->BitsLeft)==0); + +} + +static unsigned char GetNextSbBit (PB_INSTANCE *pbi){ + long ret; + + if ( !pbi->BitsLeft ){ + /* Toggle the value. */ + pbi->NextBit = ( pbi->NextBit == 1 ) ? 0 : 1; + + /* Read next run */ + FrArrayDeCodeInit(pbi); + do theora_read(pbi->opb,1,&ret); + while (FrArrayDeCodeSBRun(pbi,ret,&pbi->BitsLeft)==0); + + } + + /* Have read a bit */ + pbi->BitsLeft--; + + /* Return next bit value */ + return pbi->NextBit; +} + +void QuadDecodeDisplayFragments ( PB_INSTANCE *pbi ){ + ogg_uint32_t SB, MB, B; + int DataToDecode; + + ogg_int32_t dfIndex; + ogg_uint32_t MBIndex = 0; + + /* Reset various data structures common to key frames and inter frames. */ + pbi->CodedBlockIndex = 0; + memset ( pbi->display_fragments, 0, pbi->UnitFragments ); + + /* For "Key frames" mark all blocks as coded and return. */ + /* Else initialise the ArrayPtr array to 0 (all blocks uncoded by default) */ + if ( GetFrameType(pbi) == BASE_FRAME ) { + memset( pbi->SBFullyFlags, 1, pbi->SuperBlocks ); + memset( pbi->SBCodedFlags, 1, pbi->SuperBlocks ); + memset( pbi->MBCodedFlags, 0, pbi->MacroBlocks ); + }else{ + memset( pbi->SBFullyFlags, 0, pbi->SuperBlocks ); + memset( pbi->MBCodedFlags, 0, pbi->MacroBlocks ); + + /* Un-pack the list of partially coded Super-Blocks */ + GetNextSbInit(pbi); + for( SB = 0; SB < pbi->SuperBlocks; SB++){ + pbi->SBCodedFlags[SB] = GetNextSbBit (pbi); + } + + /* Scan through the list of super blocks. Unless all are marked + as partially coded we have more to do. */ + DataToDecode = 0; + for ( SB=0; SBSuperBlocks; SB++ ) { + if ( !pbi->SBCodedFlags[SB] ) { + DataToDecode = 1; + break; + } + } + + /* Are there further block map bits to decode ? */ + if ( DataToDecode ) { + /* Un-pack the Super-Block fully coded flags. */ + GetNextSbInit(pbi); + for( SB = 0; SB < pbi->SuperBlocks; SB++) { + /* Skip blocks already marked as partially coded */ + while( (SB < pbi->SuperBlocks) && pbi->SBCodedFlags[SB] ) + SB++; + + if ( SB < pbi->SuperBlocks ) { + pbi->SBFullyFlags[SB] = GetNextSbBit (pbi); + + if ( pbi->SBFullyFlags[SB] ) /* If SB is fully coded. */ + pbi->SBCodedFlags[SB] = 1; /* Mark the SB as coded */ + } + } + } + + /* Scan through the list of coded super blocks. If at least one + is marked as partially coded then we have a block list to + decode. */ + for ( SB=0; SBSuperBlocks; SB++ ) { + if ( pbi->SBCodedFlags[SB] && !pbi->SBFullyFlags[SB] ) { + /* Initialise the block list decoder. */ + GetNextBInit(pbi); + break; + } + } + } + + /* Decode the block data from the bit stream. */ + for ( SB=0; SBSuperBlocks; SB++ ){ + for ( MB=0; MB<4; MB++ ){ + /* If MB is in the frame */ + if ( QuadMapToMBTopLeft(pbi->BlockMap, SB,MB) >= 0 ){ + /* Only read block level data if SB was fully or partially coded */ + if ( pbi->SBCodedFlags[SB] ) { + for ( B=0; B<4; B++ ){ + /* If block is valid (in frame)... */ + dfIndex = QuadMapToIndex1( pbi->BlockMap, SB, MB, B ); + if ( dfIndex >= 0 ){ + if ( pbi->SBFullyFlags[SB] ) + pbi->display_fragments[dfIndex] = 1; + else + pbi->display_fragments[dfIndex] = GetNextBBit(pbi); + + /* Create linear list of coded block indices */ + if ( pbi->display_fragments[dfIndex] ) { + pbi->MBCodedFlags[MBIndex] = 1; + pbi->CodedBlockList[pbi->CodedBlockIndex] = dfIndex; + pbi->CodedBlockIndex++; + } + } + } + } + MBIndex++; + + } + } + } +} + +CODING_MODE FrArrayUnpackMode(PB_INSTANCE *pbi){ + long ret; + /* Coding scheme: + Token Codeword Bits + Entry 0 (most frequent) 0 1 + Entry 1 10 2 + Entry 2 110 3 + Entry 3 1110 4 + Entry 4 11110 5 + Entry 5 111110 6 + Entry 6 1111110 7 + Entry 7 1111111 7 + */ + + /* Initialise the decoding. */ + pbi->bits_so_far = 0; + + theora_read(pbi->opb,1,&ret); + pbi->bit_pattern = ret; + + /* Do we have a match */ + if ( pbi->bit_pattern == 0 ) + return (CODING_MODE)0; + + /* Get the next bit */ + theora_read(pbi->opb,1,&ret); + pbi->bit_pattern = (pbi->bit_pattern << 1) | ret; + + /* Do we have a match */ + if ( pbi->bit_pattern == 0x0002 ) + return (CODING_MODE)1; + + theora_read(pbi->opb,1,&ret); + pbi->bit_pattern = (pbi->bit_pattern << 1) | ret; + + /* Do we have a match */ + if ( pbi->bit_pattern == 0x0006 ) + return (CODING_MODE)2; + + theora_read(pbi->opb,1,&ret); + pbi->bit_pattern = (pbi->bit_pattern << 1) | ret; + + /* Do we have a match */ + if ( pbi->bit_pattern == 0x000E ) + return (CODING_MODE)3; + + theora_read(pbi->opb,1,&ret); + pbi->bit_pattern = (pbi->bit_pattern << 1) | ret; + + /* Do we have a match */ + if ( pbi->bit_pattern == 0x001E ) + return (CODING_MODE)4; + + theora_read(pbi->opb,1,&ret); + pbi->bit_pattern = (pbi->bit_pattern << 1) | ret; + + /* Do we have a match */ + if ( pbi->bit_pattern == 0x003E ) + return (CODING_MODE)5; + + theora_read(pbi->opb,1,&ret); + pbi->bit_pattern = (pbi->bit_pattern << 1) | ret; + + /* Do we have a match */ + if ( pbi->bit_pattern == 0x007E ) + return (CODING_MODE)6; + else + return (CODING_MODE)7; +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/frinit.c b/src/add-ons/media/plugins/theora/libtheora/frinit.c new file mode 100644 index 0000000000..aebc5145ef --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/frinit.c @@ -0,0 +1,394 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: frinit.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include "encoder_internal.h" + + +void InitializeFragCoordinates(PB_INSTANCE *pbi){ + + ogg_uint32_t i, j; + + ogg_uint32_t HorizFrags = pbi->HFragments; + ogg_uint32_t VertFrags = pbi->VFragments; + ogg_uint32_t StartFrag = 0; + + /* Y */ + + for(i = 0; i< VertFrags; i++){ + for(j = 0; j< HorizFrags; j++){ + + ogg_uint32_t ThisFrag = i * HorizFrags + j; + pbi->FragCoordinates[ ThisFrag ].x=j * BLOCK_HEIGHT_WIDTH; + pbi->FragCoordinates[ ThisFrag ].y=i * BLOCK_HEIGHT_WIDTH; + + } + } + + /* U */ + HorizFrags >>= 1; + VertFrags >>= 1; + StartFrag = pbi->YPlaneFragments; + + for(i = 0; i< VertFrags; i++) { + for(j = 0; j< HorizFrags; j++) { + ogg_uint32_t ThisFrag = StartFrag + i * HorizFrags + j; + pbi->FragCoordinates[ ThisFrag ].x=j * BLOCK_HEIGHT_WIDTH; + pbi->FragCoordinates[ ThisFrag ].y=i * BLOCK_HEIGHT_WIDTH; + + } + } + + /* V */ + StartFrag = pbi->YPlaneFragments + pbi->UVPlaneFragments; + for(i = 0; i< VertFrags; i++) { + for(j = 0; j< HorizFrags; j++) { + ogg_uint32_t ThisFrag = StartFrag + i * HorizFrags + j; + pbi->FragCoordinates[ ThisFrag ].x=j * BLOCK_HEIGHT_WIDTH; + pbi->FragCoordinates[ ThisFrag ].y=i * BLOCK_HEIGHT_WIDTH; + + } + } +} + +static void CalcPixelIndexTable( PB_INSTANCE *pbi){ + ogg_uint32_t i; + ogg_uint32_t * PixelIndexTablePtr; + + /* Calculate the pixel index table for normal image buffers */ + PixelIndexTablePtr = pbi->pixel_index_table; + for ( i = 0; i < pbi->YPlaneFragments; i++ ) { + PixelIndexTablePtr[ i ] = + ((i / pbi->HFragments) * VFRAGPIXELS * + pbi->info.width); + PixelIndexTablePtr[ i ] += + ((i % pbi->HFragments) * HFRAGPIXELS); + } + + PixelIndexTablePtr = &pbi->pixel_index_table[pbi->YPlaneFragments]; + for ( i = 0; i < ((pbi->HFragments >> 1) * pbi->VFragments); i++ ) { + PixelIndexTablePtr[ i ] = + ((i / (pbi->HFragments / 2) ) * + (VFRAGPIXELS * + (pbi->info.width / 2)) ); + PixelIndexTablePtr[ i ] += + ((i % (pbi->HFragments / 2) ) * + HFRAGPIXELS) + pbi->YPlaneSize; + } + + /************************************************************************/ + /* Now calculate the pixel index table for image reconstruction buffers */ + PixelIndexTablePtr = pbi->recon_pixel_index_table; + for ( i = 0; i < pbi->YPlaneFragments; i++ ){ + PixelIndexTablePtr[ i ] = + ((i / pbi->HFragments) * VFRAGPIXELS * + pbi->YStride); + PixelIndexTablePtr[ i ] += + ((i % pbi->HFragments) * HFRAGPIXELS) + + pbi->ReconYDataOffset; + } + + /* U blocks */ + PixelIndexTablePtr = &pbi->recon_pixel_index_table[pbi->YPlaneFragments]; + for ( i = 0; i < pbi->UVPlaneFragments; i++ ) { + PixelIndexTablePtr[ i ] = + ((i / (pbi->HFragments / 2) ) * + (VFRAGPIXELS * (pbi->UVStride)) ); + PixelIndexTablePtr[ i ] += + ((i % (pbi->HFragments / 2) ) * + HFRAGPIXELS) + pbi->ReconUDataOffset; + } + + /* V blocks */ + PixelIndexTablePtr = + &pbi->recon_pixel_index_table[pbi->YPlaneFragments + + pbi->UVPlaneFragments]; + + for ( i = 0; i < pbi->UVPlaneFragments; i++ ) { + PixelIndexTablePtr[ i ] = + ((i / (pbi->HFragments / 2) ) * + (VFRAGPIXELS * (pbi->UVStride)) ); + PixelIndexTablePtr[ i ] += + ((i % (pbi->HFragments / 2) ) * HFRAGPIXELS) + + pbi->ReconVDataOffset; + } +} + +void ClearFragmentInfo(PB_INSTANCE * pbi){ + + /* free prior allocs if present */ + if(pbi->display_fragments) _ogg_free(pbi->display_fragments); + if(pbi->pixel_index_table) _ogg_free(pbi->pixel_index_table); + if(pbi->recon_pixel_index_table) _ogg_free(pbi->recon_pixel_index_table); + if(pbi->FragTokenCounts) _ogg_free(pbi->FragTokenCounts); + if(pbi->CodedBlockList) _ogg_free(pbi->CodedBlockList); + if(pbi->FragMVect) _ogg_free(pbi->FragMVect); + if(pbi->FragCoeffs) _ogg_free(pbi->FragCoeffs); + if(pbi->FragCoefEOB) _ogg_free(pbi->FragCoefEOB); + if(pbi->skipped_display_fragments) _ogg_free(pbi->skipped_display_fragments); + if(pbi->QFragData) _ogg_free(pbi->QFragData); + if(pbi->TokenList) _ogg_free(pbi->TokenList); + if(pbi->FragCodingMethod) _ogg_free(pbi->FragCodingMethod); + if(pbi->FragCoordinates) _ogg_free(pbi->FragCoordinates); + + if(pbi->FragQIndex) _ogg_free(pbi->FragQIndex); + if(pbi->PPCoefBuffer) _ogg_free(pbi->PPCoefBuffer); + if(pbi->FragmentVariances) _ogg_free(pbi->FragmentVariances); + + if(pbi->BlockMap) _ogg_free(pbi->BlockMap); + + if(pbi->SBCodedFlags) _ogg_free(pbi->SBCodedFlags); + if(pbi->SBFullyFlags) _ogg_free(pbi->SBFullyFlags); + if(pbi->MBFullyFlags) _ogg_free(pbi->MBFullyFlags); + if(pbi->MBCodedFlags) _ogg_free(pbi->MBCodedFlags); + + if(pbi->_Nodes) _ogg_free(pbi->_Nodes); + pbi->_Nodes = 0; + + pbi->QFragData = 0; + pbi->TokenList = 0; + pbi->skipped_display_fragments = 0; + pbi->FragCoeffs = 0; + pbi->FragCoefEOB = 0; + pbi->display_fragments = 0; + pbi->pixel_index_table = 0; + pbi->recon_pixel_index_table = 0; + pbi->FragTokenCounts = 0; + pbi->CodedBlockList = 0; + pbi->FragCodingMethod = 0; + pbi->FragMVect = 0; + pbi->MBCodedFlags = 0; + pbi->MBFullyFlags = 0; + pbi->BlockMap = 0; + + pbi->SBCodedFlags = 0; + pbi->SBFullyFlags = 0; + pbi->QFragData = 0; + pbi->TokenList = 0; + pbi->skipped_display_fragments = 0; + pbi->FragCoeffs = 0; + pbi->FragCoefEOB = 0; + pbi->display_fragments = 0; + pbi->pixel_index_table = 0; + pbi->recon_pixel_index_table = 0; + pbi->FragTokenCounts = 0; + pbi->CodedBlockList = 0; + pbi->FragCodingMethod = 0; + pbi->FragCoordinates = 0; + pbi->FragMVect = 0; + + pbi->PPCoefBuffer=0; + pbi->PPCoefBuffer=0; + pbi->FragQIndex = 0; + pbi->FragQIndex = 0; + pbi->FragmentVariances= 0; + pbi->FragmentVariances = 0 ; +} + +void InitFragmentInfo(PB_INSTANCE * pbi){ + + /* clear any existing info */ + ClearFragmentInfo(pbi); + + /* Perform Fragment Allocations */ + pbi->display_fragments = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->display_fragments)); + + pbi->pixel_index_table = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->pixel_index_table)); + + pbi->recon_pixel_index_table = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->recon_pixel_index_table)); + + pbi->FragTokenCounts = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragTokenCounts)); + + pbi->CodedBlockList = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->CodedBlockList)); + + pbi->FragMVect = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragMVect)); + + pbi->FragCoeffs = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragCoeffs)); + + pbi->FragCoefEOB = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragCoefEOB)); + + pbi->skipped_display_fragments = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->skipped_display_fragments)); + + pbi->QFragData = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->QFragData)); + + pbi->TokenList = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->TokenList)); + + pbi->FragCodingMethod = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragCodingMethod)); + + pbi->FragCoordinates = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragCoordinates)); + + pbi->FragQIndex = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragQIndex)); + + pbi->PPCoefBuffer = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->PPCoefBuffer)); + + pbi->FragmentVariances = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->FragmentVariances)); + + pbi->_Nodes = + _ogg_malloc(pbi->UnitFragments * sizeof(*pbi->_Nodes)); + + /* Super Block Initialization */ + pbi->SBCodedFlags = + _ogg_malloc(pbi->SuperBlocks * sizeof(*pbi->SBCodedFlags)); + + pbi->SBFullyFlags = + _ogg_malloc(pbi->SuperBlocks * sizeof(*pbi->SBFullyFlags)); + + /* Macro Block Initialization */ + pbi->MBCodedFlags = + _ogg_malloc(pbi->MacroBlocks * sizeof(*pbi->MBCodedFlags)); + + pbi->MBFullyFlags = + _ogg_malloc(pbi->MacroBlocks * sizeof(*pbi->MBFullyFlags)); + + pbi->BlockMap = + _ogg_malloc(pbi->SuperBlocks * sizeof(*pbi->BlockMap)); + +} + +void ClearFrameInfo(PB_INSTANCE * pbi){ + if(pbi->ThisFrameRecon ) + _ogg_free(pbi->ThisFrameRecon ); + if(pbi->GoldenFrame) + _ogg_free(pbi->GoldenFrame); + if(pbi->LastFrameRecon) + _ogg_free(pbi->LastFrameRecon); + if(pbi->PostProcessBuffer) + _ogg_free(pbi->PostProcessBuffer); + + + pbi->ThisFrameRecon = 0; + pbi->GoldenFrame = 0; + pbi->LastFrameRecon = 0; + pbi->PostProcessBuffer = 0; + + + pbi->ThisFrameRecon = 0; + pbi->GoldenFrame = 0; + pbi->LastFrameRecon = 0; + pbi->PostProcessBuffer = 0; + +} + +void InitFrameInfo(PB_INSTANCE * pbi, unsigned int FrameSize){ + + /* clear any existing info */ + ClearFrameInfo(pbi); + + /* allocate frames */ + pbi->ThisFrameRecon = + _ogg_malloc(FrameSize*sizeof(*pbi->ThisFrameRecon)); + + pbi->GoldenFrame = + _ogg_malloc(FrameSize*sizeof(*pbi->GoldenFrame)); + + pbi->LastFrameRecon = + _ogg_malloc(FrameSize*sizeof(*pbi->LastFrameRecon)); + + pbi->PostProcessBuffer = + _ogg_malloc(FrameSize*sizeof(*pbi->PostProcessBuffer)); + +} + +void InitFrameDetails(PB_INSTANCE *pbi){ + int FrameSize; + + /*pbi->PostProcessingLevel = 0; + pbi->PostProcessingLevel = 4; + pbi->PostProcessingLevel = 5; + pbi->PostProcessingLevel = 6;*/ + + pbi->PostProcessingLevel = 0; + + + /* Set the frame size etc. */ + + pbi->YPlaneSize = pbi->info.width * + pbi->info.height; + pbi->UVPlaneSize = pbi->YPlaneSize / 4; + pbi->HFragments = pbi->info.width / HFRAGPIXELS; + pbi->VFragments = pbi->info.height / VFRAGPIXELS; + pbi->UnitFragments = ((pbi->VFragments * pbi->HFragments)*3)/2; + pbi->YPlaneFragments = pbi->HFragments * pbi->VFragments; + pbi->UVPlaneFragments = pbi->YPlaneFragments / 4; + + pbi->YStride = (pbi->info.width + STRIDE_EXTRA); + pbi->UVStride = pbi->YStride / 2; + pbi->ReconYPlaneSize = pbi->YStride * + (pbi->info.height + STRIDE_EXTRA); + pbi->ReconUVPlaneSize = pbi->ReconYPlaneSize / 4; + FrameSize = pbi->ReconYPlaneSize + 2 * pbi->ReconUVPlaneSize; + + pbi->YDataOffset = 0; + pbi->UDataOffset = pbi->YPlaneSize; + pbi->VDataOffset = pbi->YPlaneSize + pbi->UVPlaneSize; + pbi->ReconYDataOffset = + (pbi->YStride * UMV_BORDER) + UMV_BORDER; + pbi->ReconUDataOffset = pbi->ReconYPlaneSize + + (pbi->UVStride * (UMV_BORDER/2)) + (UMV_BORDER/2); + pbi->ReconVDataOffset = pbi->ReconYPlaneSize + pbi->ReconUVPlaneSize + + (pbi->UVStride * (UMV_BORDER/2)) + (UMV_BORDER/2); + + /* Image dimensions in Super-Blocks */ + pbi->YSBRows = (pbi->info.height/32) + + ( pbi->info.height%32 ? 1 : 0 ); + pbi->YSBCols = (pbi->info.width/32) + + ( pbi->info.width%32 ? 1 : 0 ); + pbi->UVSBRows = ((pbi->info.height/2)/32) + + ( (pbi->info.height/2)%32 ? 1 : 0 ); + pbi->UVSBCols = ((pbi->info.width/2)/32) + + ( (pbi->info.width/2)%32 ? 1 : 0 ); + + /* Super-Blocks per component */ + pbi->YSuperBlocks = pbi->YSBRows * pbi->YSBCols; + pbi->UVSuperBlocks = pbi->UVSBRows * pbi->UVSBCols; + pbi->SuperBlocks = pbi->YSuperBlocks+2*pbi->UVSuperBlocks; + + /* Useful externals */ + pbi->YMacroBlocks = ((pbi->VFragments+1)/2)*((pbi->HFragments+1)/2); + pbi->UVMacroBlocks = ((pbi->VFragments/2+1)/2)*((pbi->HFragments/2+1)/2); + pbi->MacroBlocks = pbi->YMacroBlocks+2*pbi->UVMacroBlocks; + + InitFragmentInfo(pbi); + InitFrameInfo(pbi, FrameSize); + InitializeFragCoordinates(pbi); + + /* Configure mapping between quad-tree and fragments */ + CreateBlockMapping ( pbi->BlockMap, pbi->YSuperBlocks, + pbi->UVSuperBlocks, pbi->HFragments, pbi->VFragments); + + /* Re-initialise the pixel index table. */ + + CalcPixelIndexTable( pbi ); + +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/huffman.c b/src/add-ons/media/plugins/theora/libtheora/huffman.c new file mode 100644 index 0000000000..33a78ccd7f --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/huffman.c @@ -0,0 +1,309 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: huffman.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include "encoder_internal.h" +#include "hufftables.h" + +static void CreateHuffmanList(HUFF_ENTRY ** HuffRoot, + ogg_uint32_t HIndex, ogg_uint32_t *FreqList ) { + int i; + HUFF_ENTRY *entry_ptr; + HUFF_ENTRY *search_ptr; + + /* Create a HUFF entry for token zero. */ + HuffRoot[HIndex] = (HUFF_ENTRY *)_ogg_calloc(1,sizeof(*HuffRoot[HIndex])); + + HuffRoot[HIndex]->Previous = NULL; + HuffRoot[HIndex]->Next = NULL; + HuffRoot[HIndex]->ZeroChild = NULL; + HuffRoot[HIndex]->OneChild = NULL; + HuffRoot[HIndex]->Value = 0; + HuffRoot[HIndex]->Frequency = FreqList[0]; + + if ( HuffRoot[HIndex]->Frequency == 0 ) + HuffRoot[HIndex]->Frequency = 1; + + /* Now add entries for all the other possible tokens. */ + for ( i = 1; i < MAX_ENTROPY_TOKENS; i++ ) { + entry_ptr = (HUFF_ENTRY *)_ogg_calloc(1,sizeof(*entry_ptr)); + + entry_ptr->Value = i; + entry_ptr->Frequency = FreqList[i]; + entry_ptr->ZeroChild = NULL; + entry_ptr->OneChild = NULL; + + /* Force min value of 1. This prevents the tree getting too deep. */ + if ( entry_ptr->Frequency == 0 ) + entry_ptr->Frequency = 1; + + if ( entry_ptr->Frequency <= HuffRoot[HIndex]->Frequency ){ + entry_ptr->Next = HuffRoot[HIndex]; + HuffRoot[HIndex]->Previous = entry_ptr; + entry_ptr->Previous = NULL; + HuffRoot[HIndex] = entry_ptr; + }else{ + search_ptr = HuffRoot[HIndex]; + while ( (search_ptr->Next != NULL) && + (search_ptr->Frequency < entry_ptr->Frequency) ){ + search_ptr = (HUFF_ENTRY *)search_ptr->Next; + } + + if ( search_ptr->Frequency < entry_ptr->Frequency ){ + entry_ptr->Next = NULL; + entry_ptr->Previous = search_ptr; + search_ptr->Next = entry_ptr; + }else{ + entry_ptr->Next = search_ptr; + entry_ptr->Previous = search_ptr->Previous; + search_ptr->Previous->Next = entry_ptr; + search_ptr->Previous = entry_ptr; + } + } + } +} + +static void CreateCodeArray( HUFF_ENTRY * HuffRoot, + ogg_uint32_t *HuffCodeArray, + unsigned char *HuffCodeLengthArray, + ogg_uint32_t CodeValue, + unsigned char CodeLength ) { + + /* If we are at a leaf then fill in a code array entry. */ + if ( ( HuffRoot->ZeroChild == NULL ) && ( HuffRoot->OneChild == NULL ) ){ + HuffCodeArray[HuffRoot->Value] = CodeValue; + HuffCodeLengthArray[HuffRoot->Value] = CodeLength; + }else{ + /* Recursive calls to scan down the tree. */ + CodeLength++; + CreateCodeArray(HuffRoot->ZeroChild, HuffCodeArray, HuffCodeLengthArray, + ((CodeValue << 1) + 0), CodeLength); + CreateCodeArray(HuffRoot->OneChild, HuffCodeArray, HuffCodeLengthArray, + ((CodeValue << 1) + 1), CodeLength); + } +} + +static void BuildHuffmanTree( HUFF_ENTRY **HuffRoot, + ogg_uint32_t *HuffCodeArray, + unsigned char *HuffCodeLengthArray, + ogg_uint32_t HIndex, + ogg_uint32_t *FreqList ){ + + HUFF_ENTRY *entry_ptr; + HUFF_ENTRY *search_ptr; + + /* First create a sorted linked list representing the frequencies of + each token. */ + CreateHuffmanList( HuffRoot, HIndex, FreqList ); + + /* Now build the tree from the list. */ + + /* While there are at least two items left in the list. */ + while ( HuffRoot[HIndex]->Next != NULL ){ + /* Create the new node as the parent of the first two in the list. */ + entry_ptr = (HUFF_ENTRY *)_ogg_calloc(1,sizeof(*entry_ptr)); + entry_ptr->Value = -1; + entry_ptr->Frequency = HuffRoot[HIndex]->Frequency + + HuffRoot[HIndex]->Next->Frequency ; + entry_ptr->ZeroChild = HuffRoot[HIndex]; + entry_ptr->OneChild = HuffRoot[HIndex]->Next; + + /* If there are still more items in the list then insert the new + node into the list. */ + if (entry_ptr->OneChild->Next != NULL ){ + /* Set up the provisional 'new root' */ + HuffRoot[HIndex] = entry_ptr->OneChild->Next; + HuffRoot[HIndex]->Previous = NULL; + + /* Now scan through the remaining list to insert the new entry + at the appropriate point. */ + if ( entry_ptr->Frequency <= HuffRoot[HIndex]->Frequency ){ + entry_ptr->Next = HuffRoot[HIndex]; + HuffRoot[HIndex]->Previous = entry_ptr; + entry_ptr->Previous = NULL; + HuffRoot[HIndex] = entry_ptr; + }else{ + search_ptr = HuffRoot[HIndex]; + while ( (search_ptr->Next != NULL) && + (search_ptr->Frequency < entry_ptr->Frequency) ){ + search_ptr = search_ptr->Next; + } + + if ( search_ptr->Frequency < entry_ptr->Frequency ){ + entry_ptr->Next = NULL; + entry_ptr->Previous = search_ptr; + search_ptr->Next = entry_ptr; + }else{ + entry_ptr->Next = search_ptr; + entry_ptr->Previous = search_ptr->Previous; + search_ptr->Previous->Next = entry_ptr; + search_ptr->Previous = entry_ptr; + } + } + }else{ + /* Build has finished. */ + entry_ptr->Next = NULL; + entry_ptr->Previous = NULL; + HuffRoot[HIndex] = entry_ptr; + } + + /* Delete the Next/Previous properties of the children (PROB NOT NEC). */ + entry_ptr->ZeroChild->Next = NULL; + entry_ptr->ZeroChild->Previous = NULL; + entry_ptr->OneChild->Next = NULL; + entry_ptr->OneChild->Previous = NULL; + + } + + /* Now build a code array from the tree. */ + CreateCodeArray( HuffRoot[HIndex], HuffCodeArray, + HuffCodeLengthArray, 0, 0); +} + +static void DestroyHuffTree(HUFF_ENTRY *root_ptr){ + if (root_ptr){ + if ( root_ptr->ZeroChild ) + DestroyHuffTree(root_ptr->ZeroChild); + + if ( root_ptr->OneChild ) + DestroyHuffTree(root_ptr->OneChild); + + _ogg_free(root_ptr); + } +} + +void ClearHuffmanSet( PB_INSTANCE *pbi ){ + int i; + + ClearHuffmanTrees(pbi->HuffRoot_VP3x); + + for ( i = 0; i < NUM_HUFF_TABLES; i++ ) + if (pbi->HuffCodeArray_VP3x[i]) + _ogg_free (pbi->HuffCodeArray_VP3x[i]); + + for ( i = 0; i < NUM_HUFF_TABLES; i++ ) + if (pbi->HuffCodeLengthArray_VP3x[i]) + _ogg_free (pbi->HuffCodeLengthArray_VP3x[i]); +} + +void InitHuffmanSet( PB_INSTANCE *pbi ){ + int i; + + ClearHuffmanSet(pbi); + + pbi->ExtraBitLengths_VP3x = ExtraBitLengths_VP31; + + for ( i = 0; i < NUM_HUFF_TABLES; i++ ){ + pbi->HuffCodeArray_VP3x[i] = + _ogg_calloc(MAX_ENTROPY_TOKENS, + sizeof(*pbi->HuffCodeArray_VP3x[i])); + pbi->HuffCodeLengthArray_VP3x[i] = + _ogg_calloc(MAX_ENTROPY_TOKENS, + sizeof(*pbi->HuffCodeLengthArray_VP3x[i])); + BuildHuffmanTree( pbi->HuffRoot_VP3x, + pbi->HuffCodeArray_VP3x[i], + pbi->HuffCodeLengthArray_VP3x[i], + i, FrequencyCounts_VP3[i]); + } +} + +static int ReadHuffTree(HUFF_ENTRY * HuffRoot, int depth, + oggpack_buffer *opb) { + long bit; + long ret; + theora_read(opb,1,&bit); + if(bit < 0) return OC_BADHEADER; + else if(!bit) { + int ret; + if (++depth > 32) return OC_BADHEADER; + HuffRoot->ZeroChild = (HUFF_ENTRY *)_ogg_calloc(1, sizeof(HUFF_ENTRY)); + ret = ReadHuffTree(HuffRoot->ZeroChild, depth, opb); + if (ret < 0) return ret; + HuffRoot->OneChild = (HUFF_ENTRY *)_ogg_calloc(1, sizeof(HUFF_ENTRY)); + ret = ReadHuffTree(HuffRoot->OneChild, depth, opb); + if (ret < 0) return ret; + HuffRoot->Value = -1; + } else { + HuffRoot->ZeroChild = NULL; + HuffRoot->OneChild = NULL; + theora_read(opb,5,&ret); + HuffRoot->Value=ret;; + if (HuffRoot->Value < 0) return OC_BADHEADER; + } + return 0; +} + +int ReadHuffmanTrees(codec_setup_info *ci, oggpack_buffer *opb) { + int i; + for (i=0; iHuffRoot[i] = (HUFF_ENTRY *)_ogg_calloc(1, sizeof(HUFF_ENTRY)); + ret = ReadHuffTree(ci->HuffRoot[i], 0, opb); + if (ret) return ret; + } + return 0; +} + +static void WriteHuffTree(HUFF_ENTRY *HuffRoot, oggpack_buffer *opb) { + if (HuffRoot->Value >= 0) { + oggpackB_write(opb, 1, 1); + oggpackB_write(opb, HuffRoot->Value, 5); + } else { + oggpackB_write(opb, 0, 1); + WriteHuffTree(HuffRoot->ZeroChild, opb); + WriteHuffTree(HuffRoot->OneChild, opb); + } +} + +void WriteHuffmanTrees(HUFF_ENTRY *HuffRoot[NUM_HUFF_TABLES], + oggpack_buffer *opb) { + int i; + for(i=0; iValue = HuffSrc->Value; + if (HuffSrc->Value < 0) { + HuffDst->ZeroChild = CopyHuffTree(HuffSrc->ZeroChild); + HuffDst->OneChild = CopyHuffTree(HuffSrc->OneChild); + } + return HuffDst; + } + return NULL; +} + +void InitHuffmanTrees(PB_INSTANCE *pbi, const codec_setup_info *ci) { + int i; + pbi->ExtraBitLengths_VP3x = ExtraBitLengths_VP31; + for(i=0; iHuffRoot_VP3x[i] = CopyHuffTree(ci->HuffRoot[i]); + } +} + +void ClearHuffmanTrees(HUFF_ENTRY *HuffRoot[NUM_HUFF_TABLES]){ + int i; + for(i=0; i= 2 */ +ogg_uint32_t FrequencyCounts_VP3[NUM_HUFF_TABLES][MAX_ENTROPY_TOKENS] = { + /* DC Intra bias */ + { 272, 84, 31, 36, 10, 2, 1, 92, 1, + 701, 872, 410, 478, + 630, 502, 417, 356, 582, 824, 985, 965, 697, 606, + 125, 119, 40, 3, 9, 15, 10, + 73, 37, + }, + { 311, 107, 41, 51, 18, 4, 2, 120, 1, + 824, 1037, 468, 541, + 714, 555, 451, 374, 595, 819, 929, 817, 474, 220, + 172, 142, 27, 4, 9, 10, 2, + 98, 48, + }, + { 353, 125, 49, 66, 24, 6, 2, 124, 1, + 926, 1172, 512, 594, + 766, 581, 458, 379, 590, 789, 849, 665, 306, 80, + 204, 147, 25, 5, 12, 9, 2, + 108, 54, + }, + { 392, 141, 57, 75, 31, 7, 4, 138, 1, + 1050, 1321, 559, 649, + 806, 594, 460, 372, 568, 727, 710, 475, 155, 19, + 251, 174, 27, 7, 16, 8, 2, + 126, 62, + }, + { 455, 168, 66, 87, 39, 10, 6, 124, 2, + 1143, 1455, 592, 692, + 824, 596, 453, 361, 542, 657, 592, 329, 78, 5, + 269, 184, 27, 9, 19, 7, 2, + 127, 66, + }, + { 544, 201, 80, 102, 45, 11, 6, 99, 1, + 1236, 1587, 610, 720, + 833, 590, 444, 348, 506, 588, 487, 226, 39, 2, + 253, 178, 27, 10, 20, 7, 2, + 118, 65, + }, + { 649, 241, 98, 121, 54, 14, 8, 84, 1, + 1349, 1719, 634, 763, + 847, 583, 428, 323, 456, 492, 349, 120, 13, 1, + 231, 170, 24, 8, 19, 7, 1, + 109, 67, + }, + { 824, 304, 129, 158, 66, 19, 10, 44, 2, + 1476, 1925, 644, 794, + 838, 559, 396, 289, 392, 384, 223, 53, 3, 1, + 159, 121, 17, 6, 16, 6, 2, + 69, 53, + }, + + /* DC Inter Bias */ + { 534, 174, 71, 68, 10, 1, 1, 68, 119, + 1674, 1526, 560, 536, + 539, 331, 229, 168, 233, 262, 231, 149, 71, 51, + 629, 530, 284, 126, 182, 208, 184, + 148, 87, + }, + { 594, 195, 77, 71, 9, 1, 1, 47, 89, + 1723, 1592, 595, 570, + 574, 351, 241, 176, 243, 271, 234, 144, 65, 37, + 534, 449, 240, 117, 167, 277, 153, + 96, 54, + }, + { 642, 213, 88, 83, 12, 1, 1, 40, 80, + 1751, 1630, 621, 600, + 598, 367, 250, 183, 251, 276, 235, 143, 62, 28, + 485, 397, 212, 110, 161, 193, 141, + 84, 48, + }, + { 693, 258, 114, 131, 27, 3, 1, 44, 79, + 1794, 1644, 550, 533, + 518, 314, 213, 154, 209, 223, 174, 97, 40, 14, + 584, 463, 236, 138, 196, 249, 143, + 94, 54, + }, + { 758, 303, 144, 189, 53, 8, 1, 37, 69, + 1842, 1732, 513, 504, + 478, 287, 191, 137, 182, 186, 137, 72, 31, 6, + 589, 469, 199, 128, 177, 264, 161, + 89, 49, + }, + { 817, 344, 170, 243, 84, 18, 2, 30, 65, + 1836, 1733, 518, 511, + 477, 281, 185, 130, 169, 166, 117, 59, 25, 3, + 572, 450, 185, 121, 173, 232, 146, + 80, 43, + }, + { 865, 389, 204, 322, 139, 42, 9, 26, 51, + 1848, 1766, 531, 522, + 477, 275, 177, 122, 153, 144, 97, 50, 16, 1, + 485, 378, 167, 115, 164, 203, 128, + 74, 42, + }, + { 961, 447, 243, 407, 196, 74, 26, 12, 34, + 2003, 1942, 571, 565, + 494, 278, 173, 116, 141, 129, 85, 44, 8, 1, + 285, 223, 101, 66, 104, 120, 74, + 35, 22, + }, + + /* AC INTRA Tables */ + /* AC Intra bias group 1 tables */ + { 245, 68, 25, 28, 5, 1, 1, 359, 4, + 910, 904, 570, 571, + 766, 620, 478, 375, 554, 684, 652, 441, 182, 30, + 535, 206, 118, 77, 69, 90, 16, + 299, 100, + }, + { 302, 86, 32, 36, 8, 1, 1, 362, 3, + 974, 968, 599, 599, + 774, 635, 469, 365, 528, 628, 557, 337, 118, 14, + 577, 219, 136, 82, 69, 65, 13, + 317, 112, + }, + { 348, 102, 39, 44, 9, 2, 1, 363, 3, + 1062, 1055, 607, 609, + 787, 626, 457, 348, 494, 550, 452, 233, 60, 2, + 636, 244, 159, 92, 74, 68, 12, + 327, 119, + }, + { 400, 121, 47, 51, 11, 2, 1, 366, 3, + 1109, 1102, 620, 622, + 786, 624, 450, 331, 459, 490, 366, 163, 29, 1, + 673, 257, 175, 98, 77, 63, 14, + 344, 131, + }, + { 470, 151, 59, 67, 15, 3, 1, 354, 4, + 1198, 1189, 640, 643, + 769, 603, 410, 294, 386, 381, 240, 78, 5, 1, + 746, 282, 205, 113, 87, 64, 15, + 368, 145, + }, + { 553, 189, 77, 94, 24, 6, 1, 347, 4, + 1244, 1232, 650, 653, + 739, 551, 360, 249, 303, 261, 129, 24, 1, 1, + 828, 313, 245, 135, 108, 77, 17, + 403, 169, + }, + { 701, 253, 109, 140, 42, 12, 2, 350, 6, + 1210, 1197, 652, 647, + 673, 495, 299, 189, 211, 151, 50, 2, 1, 1, + 892, 336, 284, 162, 134, 101, 25, + 455, 205, + }, + { 924, 390, 180, 248, 85, 31, 13, 286, 14, + 1242, 1206, 601, 577, + 519, 342, 175, 100, 85, 36, 1, 1, 1, 1, + 1031, 348, 346, 204, 166, 131, 34, + 473, 197, + }, + /* AC Inter bias group 1 tables */ + { 459, 128, 50, 48, 8, 1, 1, 224, 69, + 1285, 1227, 587, 565, + 573, 406, 261, 180, 228, 213, 130, 47, 11, 3, + 1069, 540, 309, 231, 147, 279, 157, + 383, 165, + }, + { 524, 155, 62, 64, 14, 2, 1, 209, 63, + 1345, 1288, 523, 507, + 515, 358, 225, 153, 183, 160, 87, 29, 7, 2, + 1151, 591, 365, 282, 179, 308, 133, + 344, 157, + }, + { 588, 181, 75, 81, 19, 3, 1, 204, 68, + 1344, 1288, 517, 503, + 505, 346, 216, 141, 169, 139, 71, 21, 5, 1, + 1146, 584, 366, 286, 170, 298, 153, + 342, 157, + }, + { 634, 196, 82, 89, 22, 4, 1, 194, 60, + 1356, 1312, 515, 502, + 489, 331, 199, 127, 145, 111, 51, 14, 3, 1, + 1156, 589, 393, 300, 182, 285, 144, + 340, 159, + }, + { 715, 231, 98, 113, 31, 7, 1, 181, 57, + 1345, 1303, 498, 490, + 448, 291, 166, 101, 106, 75, 30, 9, 1, 1, + 1175, 584, 416, 321, 209, 333, 164, + 330, 159, + }, + { 825, 283, 125, 149, 44, 11, 2, 160, 59, + 1343, 1308, 476, 469, + 405, 247, 131, 75, 76, 47, 18, 5, 1, 1, + 1192, 579, 432, 332, 217, 327, 176, + 320, 154, + }, + { 961, 361, 170, 215, 70, 20, 5, 161, 55, + 1250, 1218, 463, 460, + 354, 204, 101, 52, 48, 28, 11, 1, 1, 1, + 1172, 570, 449, 350, 222, 332, 169, + 338, 174, + }, + { 1139, 506, 266, 387, 156, 57, 26, 114, 48, + 1192, 1170, 366, 366, + 226, 113, 47, 22, 22, 12, 1, 1, 1, 1, + 1222, 551, 462, 391, 220, 322, 156, + 290, 136, + }, + + /* AC Intra bias group 2 tables */ + { 245, 49, 15, 11, 1, 1, 1, 332, 38, + 1163, 1162, 685, 683, + 813, 623, 437, 318, 421, 424, 288, 109, 14, 1, + 729, 303, 179, 112, 87, 199, 46, + 364, 135, + }, + { 305, 67, 22, 17, 2, 1, 1, 329, 39, + 1250, 1245, 706, 705, + 801, 584, 385, 267, 330, 296, 165, 40, 3, 1, + 798, 340, 206, 131, 108, 258, 52, + 382, 154, + }, + { 356, 82, 28, 23, 3, 1, 1, 312, 42, + 1340, 1334, 701, 703, + 770, 545, 346, 227, 269, 223, 100, 17, 1, 1, + 846, 359, 222, 142, 120, 284, 55, + 379, 157, + }, + { 402, 95, 33, 30, 4, 1, 1, 300, 43, + 1379, 1371, 710, 714, + 724, 486, 289, 182, 202, 144, 47, 5, 1, 1, + 908, 394, 250, 161, 141, 350, 60, + 391, 171, + }, + { 499, 122, 44, 42, 7, 1, 1, 267, 45, + 1439, 1436, 690, 694, + 628, 385, 213, 122, 117, 62, 14, 1, 1, 1, + 992, 441, 288, 187, 167, 446, 82, + 378, 176, + }, + { 641, 168, 62, 60, 12, 1, 1, 247, 49, + 1435, 1436, 662, 669, + 527, 298, 142, 71, 55, 22, 3, 1, 1, 1, + 1036, 470, 319, 208, 193, 548, 106, + 362, 184, + }, + { 860, 274, 111, 113, 23, 4, 1, 229, 59, + 1331, 1323, 629, 645, + 419, 192, 72, 30, 19, 6, 1, 1, 1, 1, + 1022, 478, 339, 225, 213, 690, 142, + 342, 198, + }, + { 1059, 437, 218, 285, 84, 17, 2, 152, 44, + 1284, 1313, 530, 561, + 212, 66, 17, 6, 3, 1, 1, 1, 1, 1, + 1034, 485, 346, 226, 207, 819, 185, + 248, 145, + }, + /* AC Inter bias group 2 tables */ + { 407, 93, 31, 24, 2, 1, 1, 232, 108, + 1365, 1349, 581, 578, + 498, 305, 170, 100, 103, 67, 24, 5, 1, 1, + 1175, 604, 393, 268, 209, 506, 217, + 379, 193, + }, + { 521, 129, 46, 39, 4, 1, 1, 199, 116, + 1419, 1403, 543, 540, + 446, 263, 138, 78, 75, 44, 13, 2, 1, 1, + 1201, 605, 392, 267, 214, 533, 252, + 334, 167, + }, + { 575, 144, 52, 46, 6, 1, 1, 193, 124, + 1394, 1384, 528, 528, + 406, 227, 112, 59, 54, 28, 7, 1, 1, 1, + 1210, 621, 412, 284, 235, 604, 265, + 320, 167, + }, + { 673, 174, 64, 59, 9, 1, 1, 177, 128, + 1392, 1385, 499, 499, + 352, 183, 85, 42, 35, 16, 3, 1, 1, 1, + 1210, 626, 418, 289, 246, 675, 297, + 292, 158, + }, + { 804, 225, 85, 77, 12, 1, 1, 150, 129, + 1387, 1384, 455, 455, + 277, 129, 53, 23, 17, 7, 1, 1, 1, 1, + 1212, 635, 433, 306, 268, 760, 313, + 249, 137, + }, + { 975, 305, 123, 117, 20, 2, 1, 135, 140, + 1312, 1310, 401, 399, + 201, 80, 28, 11, 8, 2, 1, 1, 1, 1, + 1162, 623, 439, 314, 283, 906, 368, + 203, 121, + }, + { 1205, 452, 208, 231, 50, 6, 1, 123, 149, + 1161, 1164, 370, 370, + 137, 45, 14, 4, 2, 1, 1, 1, 1, 1, + 1047, 562, 413, 300, 277, 1020, 404, + 168, 105, + }, + { 1297, 662, 389, 574, 200, 39, 4, 55, 120, + 1069, 1076, 273, 265, + 66, 14, 2, 1, 1, 1, 1, 1, 1, 1, + 930, 475, 345, 249, 236, 1124, 376, + 91, 56, + }, + + /* AC Intra bias group 3 tables */ + { 278, 55, 17, 12, 1, 1, 1, 288, 71, + 1315, 1304, 725, 724, + 733, 506, 307, 195, 225, 175, 77, 12, 1, 1, + 904, 414, 246, 170, 126, 290, 205, + 423, 185, + }, + { 382, 80, 26, 21, 2, 1, 1, 239, 64, + 1442, 1429, 706, 701, + 664, 420, 239, 146, 152, 105, 34, 2, 1, 1, + 975, 440, 263, 185, 140, 332, 229, + 397, 169, + }, + { 451, 97, 32, 27, 4, 1, 1, 223, 75, + 1462, 1454, 682, 680, + 574, 343, 179, 101, 98, 54, 9, 1, 1, 1, + 1031, 482, 293, 210, 163, 400, 297, + 384, 181, + }, + { 551, 128, 43, 37, 5, 1, 1, 201, 78, + 1497, 1487, 642, 651, + 493, 269, 133, 70, 60, 24, 2, 1, 1, 1, + 1065, 504, 312, 228, 178, 451, 352, + 351, 174, + }, + { 693, 179, 63, 54, 8, 1, 1, 169, 78, + 1502, 1497, 580, 591, + 375, 186, 77, 35, 21, 4, 1, 1, 1, 1, + 1099, 533, 341, 253, 206, 542, 432, + 306, 164, + }, + { 867, 263, 105, 96, 16, 2, 1, 152, 81, + 1435, 1439, 521, 525, + 270, 107, 32, 8, 3, 1, 1, 1, 1, 1, + 1085, 537, 361, 277, 223, 616, 549, + 258, 156, + }, + { 1022, 385, 182, 207, 46, 7, 1, 158, 88, + 1290, 1318, 501, 502, + 184, 38, 6, 1, 1, 1, 1, 1, 1, 1, + 1023, 480, 345, 301, 232, 665, 661, + 210, 133, + }, + { 1184, 555, 307, 457, 185, 44, 6, 115, 41, + 1236, 1253, 329, 340, + 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1017, 385, 316, 370, 246, 672, 788, + 85, 23, + }, + /* AC Inter bias group 3 tables */ + { 502, 106, 33, 22, 1, 1, 1, 151, 132, + 1446, 1451, 502, 499, + 343, 181, 84, 42, 36, 16, 3, 1, 1, 1, + 1211, 661, 429, 312, 242, 637, 498, + 288, 156, + }, + { 651, 147, 48, 35, 3, 1, 1, 145, 140, + 1419, 1420, 469, 466, + 281, 132, 56, 25, 18, 6, 1, 1, 1, 1, + 1175, 656, 435, 328, 260, 715, 556, + 252, 147, + }, + { 749, 179, 59, 43, 4, 1, 1, 123, 135, + 1423, 1431, 413, 409, + 221, 95, 36, 15, 9, 2, 1, 1, 1, 1, + 1159, 658, 444, 340, 272, 782, 656, + 205, 124, + }, + { 902, 243, 86, 67, 7, 1, 1, 114, 141, + 1385, 1385, 387, 383, + 178, 67, 22, 7, 4, 1, 1, 1, 1, 1, + 1096, 632, 434, 339, 277, 813, 735, + 171, 109, + }, + { 1081, 337, 133, 112, 15, 1, 1, 92, 137, + 1350, 1349, 311, 309, + 115, 34, 8, 2, 1, 1, 1, 1, 1, 1, + 1016, 595, 418, 342, 283, 870, 883, + 114, 78, + }, + { 1253, 467, 210, 205, 34, 3, 1, 80, 130, + 1318, 1313, 258, 260, + 68, 12, 2, 1, 1, 1, 1, 1, 1, 1, + 874, 516, 378, 330, 273, 877, 1000, + 72, 53, + }, + { 1362, 626, 333, 423, 100, 10, 1, 73, 106, + 1311, 1313, 241, 231, + 31, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 620, 368, 286, 302, 245, 814, 1127, + 34, 28, + }, + { 1203, 743, 460, 774, 284, 36, 1, 13, 25, + 1956, 1961, 103, 106, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 248, 131, 149, 272, 165, 535, 813, + 3, 3, + }, + + /* AC Intra bias group 4 tables */ + { 599, 150, 55, 50, 9, 1, 1, 181, 19, + 1487, 1487, 625, 625, + 473, 271, 138, 74, 71, 42, 11, 1, 1, 1, + 1187, 591, 356, 239, 170, 351, 137, + 395, 194, + }, + { 758, 209, 79, 74, 15, 2, 1, 147, 25, + 1514, 1514, 521, 520, + 334, 165, 74, 36, 30, 11, 1, 1, 1, 1, + 1252, 644, 409, 279, 211, 472, 203, + 318, 171, + }, + { 852, 252, 100, 98, 20, 3, 1, 130, 26, + 1493, 1498, 481, 473, + 268, 123, 51, 23, 15, 3, 1, 1, 1, 1, + 1256, 652, 426, 294, 231, 543, 242, + 278, 156, + }, + { 971, 309, 130, 136, 30, 5, 1, 113, 28, + 1458, 1467, 443, 435, + 215, 90, 31, 12, 5, 1, 1, 1, 1, 1, + 1232, 643, 426, 303, 243, 590, 300, + 235, 136, + }, + { 1100, 399, 180, 206, 53, 9, 1, 101, 29, + 1419, 1425, 375, 374, + 158, 47, 10, 1, 1, 1, 1, 1, 1, 1, + 1193, 609, 426, 319, 256, 643, 383, + 166, 103, + }, + { 1195, 505, 249, 326, 98, 20, 3, 102, 25, + 1370, 1356, 355, 347, + 104, 11, 1, 1, 1, 1, 1, 1, 1, 1, + 1100, 568, 381, 330, 261, 642, 466, + 105, 69, + }, + { 1176, 608, 345, 559, 244, 57, 6, 110, 9, + 1370, 1332, 372, 367, + 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 859, 427, 269, 359, 375, 608, 451, + 35, 20, + }, + { 1140, 613, 391, 797, 458, 180, 37, 2, 1, + 2037, 1697, 95, 31, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 360, 49, 23, 198, 1001, 719, 160, + 1, 1, + }, + /* AC Inter bias group 4 tables */ + { 931, 272, 105, 96, 16, 1, 1, 91, 52, + 1481, 1489, 347, 349, + 174, 74, 28, 12, 8, 3, 1, 1, 1, 1, + 1247, 719, 490, 356, 279, 706, 363, + 187, 110, + }, + { 1095, 358, 148, 143, 25, 3, 1, 74, 61, + 1439, 1457, 304, 302, + 127, 46, 15, 5, 3, 1, 1, 1, 1, 1, + 1138, 664, 469, 347, 282, 768, 487, + 139, 87, + }, + { 1192, 423, 188, 189, 36, 4, 1, 64, 61, + 1457, 1475, 284, 282, + 106, 35, 10, 3, 1, 1, 1, 1, 1, 1, + 1078, 624, 440, 329, 264, 744, 507, + 117, 73, + }, + { 1275, 496, 231, 258, 52, 6, 1, 53, 55, + 1458, 1470, 248, 245, + 77, 20, 5, 1, 1, 1, 1, 1, 1, 1, + 984, 576, 414, 323, 260, 771, 569, + 84, 54, + }, + { 1377, 603, 302, 367, 87, 11, 1, 37, 52, + 1522, 1532, 207, 204, + 47, 8, 1, 1, 1, 1, 1, 1, 1, 1, + 840, 493, 366, 291, 231, 690, 636, + 52, 32, + }, + { 1409, 708, 385, 529, 148, 24, 1, 23, 37, + 1672, 1670, 163, 162, + 22, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 647, 364, 291, 262, 210, 574, 643, + 26, 14, + }, + { 1348, 778, 481, 755, 245, 53, 4, 13, 19, + 2114, 2089, 141, 139, + 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 302, 183, 162, 181, 182, 344, 437, + 8, 3, + }, + { 1560, 769, 410, 664, 243, 58, 1, 1, 1, + 3017, 2788, 17, 24, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 34, 16, 8, 55, 134, 105, 86, + 1, 1, + }, +}; + +#else /* Frequency tables for encoder version < 2 */ + +ogg_uint32_t FrequencyCounts_VP3[NUM_HUFF_TABLES][MAX_ENTROPY_TOKENS] = { + /* DC Intra bias */ + { 198, 62, 22, 31, 14, 6, 6, 205, 3, + 843, 843, 415, 516, + 660, 509, 412, 347, 560, 779, 941, 930, 661, 377, + 170, 155, 39, 2, 9, 15, 11, + 128, 86, + }, + { 299, 92, 34, 39, 15, 6, 6, 132, 1, + 851, 851, 484, 485, + 666, 514, 416, 351, 567, 788, 953, 943, 670, 383, + 117, 119, 26, 4, 17, 7, 1, + 93, 56, + }, + { 367, 115, 42, 47, 16, 6, 6, 105, 1, + 896, 896, 492, 493, + 667, 510, 408, 342, 547, 760, 932, 927, 656, 379, + 114, 103, 10, 3, 6, 2, 1, + 88, 49, + }, + { 462, 158, 63, 76, 28, 9, 8, 145, 1, + 1140, 1140, 573, 574, + 754, 562, 435, 357, 555, 742, 793, 588, 274, 81, + 154, 117, 13, 6, 12, 2, 1, + 104, 62, + }, + { 558, 196, 81, 99, 36, 11, 9, 135, 1, + 1300, 1301, 606, 607, + 779, 560, 429, 349, 536, 680, 644, 405, 153, 30, + 171, 120, 12, 5, 14, 3, 1, + 104, 53, + }, + { 635, 233, 100, 122, 46, 14, 12, 113, 1, + 1414, 1415, 631, 631, + 785, 555, 432, 335, 513, 611, 521, 284, 89, 13, + 170, 113, 10, 5, 14, 3, 1, + 102, 62, + }, + { 720, 276, 119, 154, 62, 20, 16, 101, 1, + 1583, 1583, 661, 661, + 794, 556, 407, 318, 447, 472, 343, 153, 35, 1, + 172, 115, 11, 7, 14, 3, 1, + 112, 70, + }, + { 853, 326, 144, 184, 80, 27, 19, 52, 1, + 1739, 1740, 684, 685, + 800, 540, 381, 277, 364, 352, 218, 78, 13, 1, + 139, 109, 9, 6, 20, 2, 1, + 94, 50, + }, + + /* DC Inter Bias */ + { 490, 154, 57, 53, 10, 2, 1, 238, 160, + 1391, 1390, 579, 578, + 491, 273, 172, 118, 152, 156, 127, 79, 41, 39, + 712, 547, 316, 125, 183, 306, 237, + 451, 358, + }, + { 566, 184, 70, 65, 11, 2, 1, 235, 51, + 1414, 1414, 599, 598, + 510, 285, 180, 124, 157, 161, 131, 82, 42, 40, + 738, 551, 322, 138, 195, 188, 93, + 473, 365, + }, + { 711, 261, 111, 126, 27, 4, 1, 137, 52, + 1506, 1505, 645, 645, + 567, 316, 199, 136, 172, 175, 142, 88, 45, 48, + 548, 449, 255, 145, 184, 174, 121, + 260, 227, + }, + { 823, 319, 144, 175, 43, 7, 1, 53, 42, + 1648, 1648, 653, 652, + 583, 329, 205, 139, 175, 176, 139, 84, 44, 34, + 467, 389, 211, 137, 181, 186, 107, + 106, 85, + }, + { 948, 411, 201, 276, 85, 16, 2, 39, 33, + 1778, 1777, 584, 583, + 489, 265, 162, 111, 140, 140, 108, 64, 38, 23, + 428, 356, 201, 139, 186, 165, 94, + 78, 63, + }, + { 1002, 470, 248, 386, 153, 39, 6, 23, 23, + 1866, 1866, 573, 573, + 467, 249, 155, 103, 130, 128, 94, 60, 38, 14, + 323, 263, 159, 111, 156, 153, 74, + 46, 34, + }, + { 1020, 518, 291, 504, 242, 78, 18, 14, 14, + 1980, 1979, 527, 526, + 408, 219, 132, 87, 110, 104, 79, 55, 31, 7, + 265, 213, 129, 91, 131, 111, 50, + 31, 20, + }, + { 1018, 544, 320, 591, 338, 139, 47, 5, 2, + 2123, 2123, 548, 547, + 414, 212, 126, 83, 101, 96, 79, 60, 23, 1, + 120, 97, 55, 39, 60, 38, 15, + 11, 8, + }, + + /* AC INTRA Tables */ + /* AC Intra bias group 1 tables */ + { 242, 62, 22, 20, 4, 1, 1, 438, 1, + 593, 593, 489, 490, + 657, 580, 471, 374, 599, 783, 869, 770, 491, 279, + 358, 144, 82, 54, 49, 70, 5, + 289, 107, + }, + { 317, 95, 38, 41, 8, 1, 1, 479, 1, + 653, 654, 500, 501, + 682, 611, 473, 376, 582, 762, 806, 656, 358, 155, + 419, 162, 86, 58, 36, 34, 1, + 315, 126, + }, + { 382, 121, 49, 59, 15, 3, 1, 496, 1, + 674, 674, 553, 554, + 755, 636, 487, 391, 576, 718, 701, 488, 221, 72, + 448, 161, 107, 56, 37, 29, 1, + 362, 156, + }, + { 415, 138, 57, 73, 21, 5, 1, 528, 1, + 742, 741, 562, 563, + 753, 669, 492, 388, 563, 664, 589, 340, 129, 26, + 496, 184, 139, 71, 48, 33, 2, + 387, 166, + }, + { 496, 170, 73, 94, 31, 8, 2, 513, 1, + 855, 855, 604, 604, + 769, 662, 477, 356, 486, 526, 381, 183, 51, 5, + 590, 214, 160, 85, 60, 39, 3, + 427, 203, + }, + { 589, 207, 89, 116, 40, 13, 3, 491, 1, + 919, 919, 631, 631, + 769, 633, 432, 308, 408, 378, 247, 94, 17, 1, + 659, 247, 201, 105, 73, 51, 3, + 466, 242, + }, + { 727, 266, 115, 151, 49, 17, 6, 439, 1, + 977, 977, 642, 642, + 718, 572, 379, 243, 285, 251, 133, 40, 1, 1, + 756, 287, 253, 126, 94, 66, 4, + 492, 280, + }, + { 940, 392, 180, 247, 82, 30, 14, 343, 1, + 1064, 1064, 615, 616, + 596, 414, 235, 146, 149, 108, 41, 1, 1, 1, + 882, 314, 346, 172, 125, 83, 6, + 489, 291, + }, + /* AC Inter bias group 1 tables */ + { 440, 102, 33, 23, 2, 1, 1, 465, 85, + 852, 852, 744, 743, + 701, 496, 297, 193, 225, 200, 129, 58, 18, 2, + 798, 450, 269, 202, 145, 308, 154, + 646, 389, + }, + { 592, 151, 53, 43, 6, 1, 1, 409, 34, + 875, 875, 748, 747, + 723, 510, 305, 196, 229, 201, 130, 59, 18, 2, + 800, 436, 253, 185, 115, 194, 88, + 642, 368, + }, + { 759, 222, 86, 85, 17, 2, 1, 376, 46, + 888, 888, 689, 688, + 578, 408, 228, 143, 165, 141, 84, 35, 7, 1, + 878, 488, 321, 244, 147, 266, 124, + 612, 367, + }, + { 912, 298, 122, 133, 34, 7, 1, 261, 44, + 1092, 1091, 496, 496, + 409, 269, 150, 95, 106, 87, 49, 16, 1, 1, + 1102, 602, 428, 335, 193, 323, 157, + 423, 253, + }, + { 1072, 400, 180, 210, 60, 16, 3, 210, 40, + 1063, 1063, 451, 451, + 345, 221, 121, 73, 79, 64, 31, 6, 1, 1, + 1105, 608, 462, 358, 202, 330, 155, + 377, 228, + }, + { 1164, 503, 254, 330, 109, 34, 9, 167, 35, + 1038, 1037, 390, 390, + 278, 170, 89, 54, 56, 40, 13, 1, 1, 1, + 1110, 607, 492, 401, 218, 343, 141, + 323, 192, + }, + { 1173, 583, 321, 486, 196, 68, 23, 124, 23, + 1037, 1037, 347, 346, + 232, 139, 69, 40, 37, 20, 2, 1, 1, 1, + 1128, 584, 506, 410, 199, 301, 113, + 283, 159, + }, + { 1023, 591, 366, 699, 441, 228, 113, 79, 5, + 1056, 1056, 291, 291, + 173, 96, 38, 19, 8, 1, 1, 1, 1, 1, + 1187, 527, 498, 409, 147, 210, 56, + 263, 117, + }, + + /* AC Intra bias group 2 tables */ + { 311, 74, 27, 27, 5, 1, 1, 470, 24, + 665, 667, 637, 638, + 806, 687, 524, 402, 585, 679, 609, 364, 127, 20, + 448, 210, 131, 76, 52, 111, 19, + 393, 195, + }, + { 416, 104, 39, 38, 8, 1, 1, 545, 33, + 730, 731, 692, 692, + 866, 705, 501, 365, 495, 512, 387, 168, 39, 2, + 517, 240, 154, 86, 64, 127, 19, + 461, 247, + }, + { 474, 117, 43, 42, 9, 1, 1, 560, 40, + 783, 783, 759, 760, + 883, 698, 466, 318, 404, 377, 215, 66, 7, 1, + 559, 259, 176, 110, 87, 170, 22, + 520, 278, + }, + { 582, 149, 53, 53, 12, 2, 1, 473, 39, + 992, 993, 712, 713, + 792, 593, 373, 257, 299, 237, 114, 25, 1, 1, + 710, 329, 221, 143, 116, 226, 26, + 490, 259, + }, + { 744, 210, 78, 77, 16, 2, 1, 417, 37, + 1034, 1035, 728, 728, + 718, 509, 296, 175, 184, 122, 42, 3, 1, 1, + 791, 363, 255, 168, 145, 311, 35, + 492, 272, + }, + { 913, 291, 121, 128, 28, 4, 1, 334, 40, + 1083, 1084, 711, 712, + 624, 378, 191, 107, 95, 50, 7, 1, 1, 1, + 876, 414, 288, 180, 164, 382, 39, + 469, 275, + }, + { 1065, 405, 184, 216, 53, 8, 1, 236, 36, + 1134, 1134, 685, 686, + 465, 253, 113, 48, 41, 9, 1, 1, 1, 1, + 965, 451, 309, 179, 166, 429, 53, + 414, 249, + }, + { 1148, 548, 301, 438, 160, 42, 6, 84, 17, + 1222, 1223, 574, 575, + 272, 111, 23, 6, 2, 1, 1, 1, 1, 1, + 1060, 502, 328, 159, 144, 501, 54, + 302, 183, + }, + /* AC Inter bias group 2 tables */ + { 403, 80, 24, 17, 1, 1, 1, 480, 90, + 899, 899, 820, 819, + 667, 413, 228, 133, 139, 98, 42, 10, 1, 1, + 865, 470, 316, 222, 171, 419, 213, + 645, 400, + }, + { 698, 169, 59, 49, 6, 1, 1, 414, 101, + 894, 893, 761, 761, + 561, 338, 171, 96, 97, 64, 26, 6, 1, 1, + 896, 494, 343, 239, 192, 493, 215, + 583, 366, + }, + { 914, 255, 94, 80, 10, 1, 1, 345, 128, + 935, 935, 670, 671, + 415, 222, 105, 55, 51, 30, 10, 1, 1, 1, + 954, 530, 377, 274, 232, 641, 295, + 456, 298, + }, + { 1103, 359, 146, 135, 20, 1, 1, 235, 119, + 1042, 1042, 508, 507, + 293, 146, 65, 33, 30, 16, 4, 1, 1, 1, + 1031, 561, 407, 296, 265, 813, 317, + 301, 192, + }, + { 1255, 504, 238, 265, 51, 5, 1, 185, 113, + 1013, 1013, 437, 438, + 212, 92, 41, 18, 15, 6, 1, 1, 1, 1, + 976, 530, 386, 276, 260, 927, 357, + 224, 148, + }, + { 1292, 610, 332, 460, 127, 16, 1, 136, 99, + 1014, 1015, 384, 384, + 153, 65, 25, 11, 6, 1, 1, 1, 1, 1, + 942, 487, 343, 241, 238, 970, 358, + 174, 103, + }, + { 1219, 655, 407, 700, 280, 55, 2, 100, 60, + 1029, 1029, 337, 336, + 119, 43, 11, 3, 2, 1, 1, 1, 1, 1, + 894, 448, 305, 199, 213, 1005, 320, + 136, 77, + }, + { 1099, 675, 435, 971, 581, 168, 12, 37, 16, + 1181, 1081, 319, 318, + 66, 11, 6, 1, 1, 1, 1, 1, 1, 1, + 914, 370, 235, 138, 145, 949, 128, + 94, 41, + }, + + /* AC Intra bias group 3 tables */ + { 486, 112, 39, 34, 6, 1, 1, 541, 67, + 819, 818, 762, 763, + 813, 643, 403, 280, 332, 295, 164, 53, 6, 1, + 632, 294, 180, 131, 105, 208, 109, + 594, 295, + }, + { 723, 191, 69, 65, 12, 1, 1, 445, 79, + 865, 865, 816, 816, + 750, 515, 290, 172, 184, 122, 46, 5, 1, 1, + 740, 340, 213, 165, 129, 270, 168, + 603, 326, + }, + { 884, 264, 102, 103, 21, 3, 1, 382, 68, + 897, 897, 836, 836, + 684, 427, 227, 119, 119, 70, 16, 1, 1, 1, + 771, 367, 234, 184, 143, 272, 178, + 555, 326, + }, + { 1028, 347, 153, 161, 36, 8, 1, 251, 44, + 1083, 1084, 735, 735, + 541, 289, 144, 77, 57, 23, 3, 1, 1, 1, + 926, 422, 270, 215, 176, 301, 183, + 443, 248, + }, + { 1155, 465, 224, 264, 71, 14, 3, 174, 27, + 1110, 1111, 730, 731, + 429, 206, 79, 30, 19, 4, 1, 1, 1, 1, + 929, 443, 279, 225, 194, 298, 196, + 354, 223, + }, + { 1191, 576, 296, 415, 144, 36, 8, 114, 16, + 1162, 1162, 749, 749, + 338, 108, 29, 8, 5, 1, 1, 1, 1, 1, + 947, 458, 273, 207, 194, 248, 145, + 258, 152, + }, + { 1169, 619, 366, 603, 247, 92, 23, 46, 1, + 1236, 1236, 774, 775, + 191, 35, 14, 1, 1, 1, 1, 1, 1, 1, + 913, 449, 260, 214, 194, 180, 82, + 174, 98, + }, + { 1006, 537, 381, 897, 504, 266, 101, 39, 1, + 1307, 1307, 668, 667, + 116, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1175, 261, 295, 70, 164, 107, 31, + 10, 76, + }, + /* AC Inter bias group 3 tables */ + { 652, 156, 53, 43, 5, 1, 1, 368, 128, + 983, 984, 825, 825, + 583, 331, 163, 88, 84, 48, 15, 1, 1, 1, + 870, 480, 316, 228, 179, 421, 244, + 562, 349, + }, + { 988, 280, 104, 87, 12, 1, 1, 282, 194, + 980, 981, 738, 739, + 395, 189, 80, 37, 31, 12, 2, 1, 1, 1, + 862, 489, 333, 262, 214, 600, 446, + 390, 260, + }, + { 1176, 399, 165, 154, 24, 2, 1, 218, 224, + 1017, 1018, 651, 651, + 280, 111, 42, 16, 9, 3, 1, 1, 1, 1, + 787, 469, 324, 269, 229, 686, 603, + 267, 194, + }, + { 1319, 530, 255, 268, 47, 4, 1, 113, 183, + 1149, 1150, 461, 461, + 173, 58, 17, 5, 3, 1, 1, 1, 1, 1, + 768, 450, 305, 261, 221, 716, 835, + 136, 97, + }, + { 1362, 669, 355, 465, 104, 9, 1, 76, 153, + 1253, 1253, 398, 397, + 102, 21, 5, 1, 1, 1, 1, 1, 1, 1, + 596, 371, 238, 228, 196, 660, 954, + 68, 53, + }, + { 1354, 741, 446, 702, 174, 15, 1, 38, 87, + 1498, 1498, 294, 294, + 43, 7, 1, 1, 1, 1, 1, 1, 1, 1, + 381, 283, 165, 181, 155, 544, 1039, + 25, 21, + }, + { 1262, 885, 546, 947, 263, 18, 1, 18, 27, + 1908, 1908, 163, 162, + 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 195, 152, 83, 125, 109, 361, 827, + 7, 5, + }, + { 2539, 951, 369, 554, 212, 18, 1, 1, 1, + 2290, 2289, 64, 64, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 18, 18, 9, 55, 36, 184, 323, + 1, 1, + }, + + + /* AC Intra bias group 4 tables */ + { 921, 264, 101, 100, 19, 2, 1, 331, 98, + 1015, 1016, 799, 799, + 512, 269, 119, 60, 50, 17, 1, 1, 1, 1, + 841, 442, 307, 222, 182, 493, 256, + 438, 310, + }, + { 1147, 412, 184, 206, 50, 6, 1, 242, 141, + 977, 976, 808, 807, + 377, 135, 40, 10, 7, 1, 1, 1, 1, 1, + 788, 402, 308, 223, 205, 584, 406, + 316, 227, + }, + { 1243, 504, 238, 310, 79, 11, 1, 184, 150, + 983, 984, 814, 813, + 285, 56, 10, 1, 1, 1, 1, 1, 1, 1, + 713, 377, 287, 217, 180, 615, 558, + 208, 164, + }, + { 1266, 606, 329, 484, 161, 27, 1, 79, 92, + 1187, 1188, 589, 588, + 103, 10, 1, 1, 1, 1, 1, 1, 1, 1, + 680, 371, 278, 221, 244, 614, 728, + 80, 62, + }, + { 1126, 828, 435, 705, 443, 90, 8, 10, 55, + 1220, 1219, 350, 350, + 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 602, 330, 222, 168, 158, 612, 919, + 104, 5, + }, + { 1210, 506, 1014, 926, 474, 240, 4, 1, 44, + 1801, 1801, 171, 171, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 900, 132, 36, 11, 47, 191, 316, + 2, 1, + }, + { 1210, 506, 1014, 926, 474, 240, 4, 1, 44, + 1801, 1801, 171, 171, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 900, 132, 36, 11, 47, 191, 316, + 2, 1, + }, + { 1210, 506, 1014, 926, 474, 240, 4, 1, 44, + 1801, 1801, 171, 171, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 900, 132, 36, 11, 47, 191, 316, + 2, 1, + }, + /* AC Inter bias group 4 tables */ + { 1064, 325, 129, 117, 20, 2, 1, 266, 121, + 1000, 1000, 706, 706, + 348, 162, 67, 32, 25, 11, 1, 1, 1, 1, + 876, 513, 363, 274, 225, 627, 384, + 370, 251, + }, + { 1311, 517, 238, 254, 45, 3, 1, 188, 160, + 1070, 1070, 635, 635, + 239, 85, 30, 11, 6, 1, 1, 1, 1, 1, + 744, 420, 313, 239, 206, 649, 541, + 221, 155, + }, + { 1394, 632, 322, 385, 78, 7, 1, 134, 152, + 1163, 1164, 607, 607, + 185, 51, 12, 3, 1, 1, 1, 1, 1, 1, + 631, 331, 275, 203, 182, 604, 620, + 146, 98, + }, + { 1410, 727, 407, 546, 146, 19, 1, 67, 88, + 1485, 1486, 419, 418, + 103, 18, 3, 1, 1, 1, 1, 1, 1, 1, + 555, 261, 234, 164, 148, 522, 654, + 67, 39, + }, + { 1423, 822, 492, 719, 216, 22, 1, 28, 59, + 1793, 1793, 323, 324, + 37, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 376, 138, 158, 102, 119, 400, 604, + 28, 9, + }, + { 1585, 923, 563, 918, 207, 25, 1, 5, 20, + 2229, 2230, 172, 172, + 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 191, 40, 56, 22, 65, 243, 312, + 2, 1, + }, + { 2225, 1100, 408, 608, 133, 8, 1, 1, 1, + 2658, 2658, 25, 24, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 125, 16, + 1, 1, + }, + { 2539, 951, 369, 554, 212, 18, 1, 1, 1, + 2290, 2289, 64, 64, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 18, 18, 9, 55, 36, 184, 323, + 1, 1, + }, +}; + +#endif /* NEW_FREQS */ diff --git a/src/add-ons/media/plugins/theora/libtheora/idct.c b/src/add-ons/media/plugins/theora/libtheora/idct.c new file mode 100644 index 0000000000..d89530ff55 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/idct.c @@ -0,0 +1,472 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: idct.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include "encoder_internal.h" +#include "quant_lookup.h" + +#define IdctAdjustBeforeShift 8 +#define xC1S7 64277 +#define xC2S6 60547 +#define xC3S5 54491 +#define xC4S4 46341 +#define xC5S3 36410 +#define xC6S2 25080 +#define xC7S1 12785 + +static void dequant_slow( ogg_int16_t * dequant_coeffs, + ogg_int16_t * quantized_list, + ogg_int32_t * DCT_block) { + int i; + for(i=0;i<64;i++) + DCT_block[dequant_index[i]] = quantized_list[i] * dequant_coeffs[i]; +} + +void IDctSlow( Q_LIST_ENTRY * InputData, + ogg_int16_t *QuantMatrix, + ogg_int16_t * OutputData ) { + ogg_int32_t IntermediateData[64]; + ogg_int32_t * ip = IntermediateData; + ogg_int16_t * op = OutputData; + + ogg_int32_t _A, _B, _C, _D, _Ad, _Bd, _Cd, _Dd, _E, _F, _G, _H; + ogg_int32_t _Ed, _Gd, _Add, _Bdd, _Fd, _Hd; + ogg_int32_t t1, t2; + + int loop; + + dequant_slow( QuantMatrix, InputData, IntermediateData); + + /* Inverse DCT on the rows now */ + for ( loop = 0; loop < 8; loop++){ + /* Check for non-zero values */ + if ( ip[0] | ip[1] | ip[2] | ip[3] | ip[4] | ip[5] | ip[6] | ip[7] ) { + t1 = (xC1S7 * ip[1]); + t2 = (xC7S1 * ip[7]); + t1 >>= 16; + t2 >>= 16; + _A = t1 + t2; + + t1 = (xC7S1 * ip[1]); + t2 = (xC1S7 * ip[7]); + t1 >>= 16; + t2 >>= 16; + _B = t1 - t2; + + t1 = (xC3S5 * ip[3]); + t2 = (xC5S3 * ip[5]); + t1 >>= 16; + t2 >>= 16; + _C = t1 + t2; + + t1 = (xC3S5 * ip[5]); + t2 = (xC5S3 * ip[3]); + t1 >>= 16; + t2 >>= 16; + _D = t1 - t2; + + t1 = (xC4S4 * (_A - _C)); + t1 >>= 16; + _Ad = t1; + + t1 = (xC4S4 * (_B - _D)); + t1 >>= 16; + _Bd = t1; + + + _Cd = _A + _C; + _Dd = _B + _D; + + t1 = (xC4S4 * (ip[0] + ip[4])); + t1 >>= 16; + _E = t1; + + t1 = (xC4S4 * (ip[0] - ip[4])); + t1 >>= 16; + _F = t1; + + t1 = (xC2S6 * ip[2]); + t2 = (xC6S2 * ip[6]); + t1 >>= 16; + t2 >>= 16; + _G = t1 + t2; + + t1 = (xC6S2 * ip[2]); + t2 = (xC2S6 * ip[6]); + t1 >>= 16; + t2 >>= 16; + _H = t1 - t2; + + + _Ed = _E - _G; + _Gd = _E + _G; + + _Add = _F + _Ad; + _Bdd = _Bd - _H; + + _Fd = _F - _Ad; + _Hd = _Bd + _H; + + /* Final sequence of operations over-write original inputs. */ + ip[0] = (ogg_int16_t)((_Gd + _Cd ) >> 0); + ip[7] = (ogg_int16_t)((_Gd - _Cd ) >> 0); + + ip[1] = (ogg_int16_t)((_Add + _Hd ) >> 0); + ip[2] = (ogg_int16_t)((_Add - _Hd ) >> 0); + + ip[3] = (ogg_int16_t)((_Ed + _Dd ) >> 0); + ip[4] = (ogg_int16_t)((_Ed - _Dd ) >> 0); + + ip[5] = (ogg_int16_t)((_Fd + _Bdd ) >> 0); + ip[6] = (ogg_int16_t)((_Fd - _Bdd ) >> 0); + + } + + ip += 8; /* next row */ + } + + ip = IntermediateData; + + for ( loop = 0; loop < 8; loop++){ + /* Check for non-zero values (bitwise or faster than ||) */ + if ( ip[0 * 8] | ip[1 * 8] | ip[2 * 8] | ip[3 * 8] | + ip[4 * 8] | ip[5 * 8] | ip[6 * 8] | ip[7 * 8] ) { + + t1 = (xC1S7 * ip[1*8]); + t2 = (xC7S1 * ip[7*8]); + t1 >>= 16; + t2 >>= 16; + _A = t1 + t2; + + t1 = (xC7S1 * ip[1*8]); + t2 = (xC1S7 * ip[7*8]); + t1 >>= 16; + t2 >>= 16; + _B = t1 - t2; + + t1 = (xC3S5 * ip[3*8]); + t2 = (xC5S3 * ip[5*8]); + t1 >>= 16; + t2 >>= 16; + _C = t1 + t2; + + t1 = (xC3S5 * ip[5*8]); + t2 = (xC5S3 * ip[3*8]); + t1 >>= 16; + t2 >>= 16; + _D = t1 - t2; + + t1 = (xC4S4 * (_A - _C)); + t1 >>= 16; + _Ad = t1; + + t1 = (xC4S4 * (_B - _D)); + t1 >>= 16; + _Bd = t1; + + + _Cd = _A + _C; + _Dd = _B + _D; + + t1 = (xC4S4 * (ip[0*8] + ip[4*8])); + t1 >>= 16; + _E = t1; + + t1 = (xC4S4 * (ip[0*8] - ip[4*8])); + t1 >>= 16; + _F = t1; + + t1 = (xC2S6 * ip[2*8]); + t2 = (xC6S2 * ip[6*8]); + t1 >>= 16; + t2 >>= 16; + _G = t1 + t2; + + t1 = (xC6S2 * ip[2*8]); + t2 = (xC2S6 * ip[6*8]); + t1 >>= 16; + t2 >>= 16; + _H = t1 - t2; + + _Ed = _E - _G; + _Gd = _E + _G; + + _Add = _F + _Ad; + _Bdd = _Bd - _H; + + _Fd = _F - _Ad; + _Hd = _Bd + _H; + + _Gd += IdctAdjustBeforeShift; + _Add += IdctAdjustBeforeShift; + _Ed += IdctAdjustBeforeShift; + _Fd += IdctAdjustBeforeShift; + + /* Final sequence of operations over-write original inputs. */ + op[0*8] = (ogg_int16_t)((_Gd + _Cd ) >> 4); + op[7*8] = (ogg_int16_t)((_Gd - _Cd ) >> 4); + + op[1*8] = (ogg_int16_t)((_Add + _Hd ) >> 4); + op[2*8] = (ogg_int16_t)((_Add - _Hd ) >> 4); + + op[3*8] = (ogg_int16_t)((_Ed + _Dd ) >> 4); + op[4*8] = (ogg_int16_t)((_Ed - _Dd ) >> 4); + + op[5*8] = (ogg_int16_t)((_Fd + _Bdd ) >> 4); + op[6*8] = (ogg_int16_t)((_Fd - _Bdd ) >> 4); + }else{ + op[0*8] = 0; + op[7*8] = 0; + op[1*8] = 0; + op[2*8] = 0; + op[3*8] = 0; + op[4*8] = 0; + op[5*8] = 0; + op[6*8] = 0; + } + + ip++; /* next column */ + op++; + } +} + +/************************ + 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 +*************************/ + +static void dequant_slow10( ogg_int16_t * dequant_coeffs, + ogg_int16_t * quantized_list, + ogg_int32_t * DCT_block){ + int i; + memset(DCT_block,0, 128); + for(i=0;i<10;i++) + DCT_block[dequant_index[i]] = quantized_list[i] * dequant_coeffs[i]; + +} + +void IDct10( Q_LIST_ENTRY * InputData, + ogg_int16_t *QuantMatrix, + ogg_int16_t * OutputData ){ + ogg_int32_t IntermediateData[64]; + ogg_int32_t * ip = IntermediateData; + ogg_int16_t * op = OutputData; + + ogg_int32_t _A, _B, _C, _D, _Ad, _Bd, _Cd, _Dd, _E, _F, _G, _H; + ogg_int32_t _Ed, _Gd, _Add, _Bdd, _Fd, _Hd; + ogg_int32_t t1, t2; + + int loop; + + dequant_slow10( QuantMatrix, InputData, IntermediateData); + + /* Inverse DCT on the rows now */ + for ( loop = 0; loop < 4; loop++){ + /* Check for non-zero values */ + if ( ip[0] | ip[1] | ip[2] | ip[3] ){ + t1 = (xC1S7 * ip[1]); + t1 >>= 16; + _A = t1; + + t1 = (xC7S1 * ip[1]); + t1 >>= 16; + _B = t1 ; + + t1 = (xC3S5 * ip[3]); + t1 >>= 16; + _C = t1; + + t2 = (xC5S3 * ip[3]); + t2 >>= 16; + _D = -t2; + + + t1 = (xC4S4 * (_A - _C)); + t1 >>= 16; + _Ad = t1; + + t1 = (xC4S4 * (_B - _D)); + t1 >>= 16; + _Bd = t1; + + + _Cd = _A + _C; + _Dd = _B + _D; + + t1 = (xC4S4 * ip[0] ); + t1 >>= 16; + _E = t1; + + _F = t1; + + t1 = (xC2S6 * ip[2]); + t1 >>= 16; + _G = t1; + + t1 = (xC6S2 * ip[2]); + t1 >>= 16; + _H = t1 ; + + + _Ed = _E - _G; + _Gd = _E + _G; + + _Add = _F + _Ad; + _Bdd = _Bd - _H; + + _Fd = _F - _Ad; + _Hd = _Bd + _H; + + /* Final sequence of operations over-write original inputs. */ + ip[0] = (ogg_int16_t)((_Gd + _Cd ) >> 0); + ip[7] = (ogg_int16_t)((_Gd - _Cd ) >> 0); + + ip[1] = (ogg_int16_t)((_Add + _Hd ) >> 0); + ip[2] = (ogg_int16_t)((_Add - _Hd ) >> 0); + + ip[3] = (ogg_int16_t)((_Ed + _Dd ) >> 0); + ip[4] = (ogg_int16_t)((_Ed - _Dd ) >> 0); + + ip[5] = (ogg_int16_t)((_Fd + _Bdd ) >> 0); + ip[6] = (ogg_int16_t)((_Fd - _Bdd ) >> 0); + + } + + ip += 8; /* next row */ + } + + ip = IntermediateData; + + for ( loop = 0; loop < 8; loop++) { + /* Check for non-zero values (bitwise or faster than ||) */ + if ( ip[0 * 8] | ip[1 * 8] | ip[2 * 8] | ip[3 * 8] ) { + + t1 = (xC1S7 * ip[1*8]); + t1 >>= 16; + _A = t1 ; + + t1 = (xC7S1 * ip[1*8]); + t1 >>= 16; + _B = t1 ; + + t1 = (xC3S5 * ip[3*8]); + t1 >>= 16; + _C = t1 ; + + t2 = (xC5S3 * ip[3*8]); + t2 >>= 16; + _D = - t2; + + + t1 = (xC4S4 * (_A - _C)); + t1 >>= 16; + _Ad = t1; + + t1 = (xC4S4 * (_B - _D)); + t1 >>= 16; + _Bd = t1; + + + _Cd = _A + _C; + _Dd = _B + _D; + + t1 = (xC4S4 * ip[0*8]); + t1 >>= 16; + _E = t1; + _F = t1; + + t1 = (xC2S6 * ip[2*8]); + t1 >>= 16; + _G = t1; + + t1 = (xC6S2 * ip[2*8]); + t1 >>= 16; + _H = t1; + + + _Ed = _E - _G; + _Gd = _E + _G; + + _Add = _F + _Ad; + _Bdd = _Bd - _H; + + _Fd = _F - _Ad; + _Hd = _Bd + _H; + + _Gd += IdctAdjustBeforeShift; + _Add += IdctAdjustBeforeShift; + _Ed += IdctAdjustBeforeShift; + _Fd += IdctAdjustBeforeShift; + + /* Final sequence of operations over-write original inputs. */ + op[0*8] = (ogg_int16_t)((_Gd + _Cd ) >> 4); + op[7*8] = (ogg_int16_t)((_Gd - _Cd ) >> 4); + + op[1*8] = (ogg_int16_t)((_Add + _Hd ) >> 4); + op[2*8] = (ogg_int16_t)((_Add - _Hd ) >> 4); + + op[3*8] = (ogg_int16_t)((_Ed + _Dd ) >> 4); + op[4*8] = (ogg_int16_t)((_Ed - _Dd ) >> 4); + + op[5*8] = (ogg_int16_t)((_Fd + _Bdd ) >> 4); + op[6*8] = (ogg_int16_t)((_Fd - _Bdd ) >> 4); + }else{ + op[0*8] = 0; + op[7*8] = 0; + op[1*8] = 0; + op[2*8] = 0; + op[3*8] = 0; + op[4*8] = 0; + op[5*8] = 0; + op[6*8] = 0; + } + + ip++; /* next column */ + op++; + } +} + +/*************************** + 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 + 0 0 0 0 0 0 0 0 +**************************/ + +void IDct1( Q_LIST_ENTRY * InputData, + ogg_int16_t *QuantMatrix, + ogg_int16_t * OutputData ){ + int loop; + + ogg_int16_t OutD; + + OutD=(ogg_int16_t) ((ogg_int32_t)(InputData[0]*QuantMatrix[0]+15)>>5); + + for(loop=0;loop<64;loop++) + OutputData[loop]=OutD; + +} diff --git a/src/add-ons/media/plugins/theora/libtheora/mcomp.c b/src/add-ons/media/plugins/theora/libtheora/mcomp.c new file mode 100644 index 0000000000..08f72185c9 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/mcomp.c @@ -0,0 +1,947 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: mcomp.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include "encoder_internal.h" + +/* Initialises motion compentsation. */ +void InitMotionCompensation ( CP_INSTANCE *cpi ){ + int i; + int SearchSite=0; + int Len; + int LineStepY = (ogg_int32_t)cpi->pb.YStride; + + Len=((MAX_MV_EXTENT/2)+1)/2; + + + /* How many search stages are there. */ + cpi->MVSearchSteps = 0; + + /* Set up offsets arrays used in half pixel correction. */ + cpi->HalfPixelRef2Offset[0] = -LineStepY - 1; + cpi->HalfPixelRef2Offset[1] = -LineStepY; + cpi->HalfPixelRef2Offset[2] = -LineStepY + 1; + cpi->HalfPixelRef2Offset[3] = - 1; + cpi->HalfPixelRef2Offset[4] = 0; + cpi->HalfPixelRef2Offset[5] = 1; + cpi->HalfPixelRef2Offset[6] = LineStepY - 1; + cpi->HalfPixelRef2Offset[7] = LineStepY; + cpi->HalfPixelRef2Offset[8] = LineStepY + 1; + + cpi->HalfPixelXOffset[0] = -1; + cpi->HalfPixelXOffset[1] = 0; + cpi->HalfPixelXOffset[2] = 1; + cpi->HalfPixelXOffset[3] = -1; + cpi->HalfPixelXOffset[4] = 0; + cpi->HalfPixelXOffset[5] = 1; + cpi->HalfPixelXOffset[6] = -1; + cpi->HalfPixelXOffset[7] = 0; + cpi->HalfPixelXOffset[8] = 1; + + cpi->HalfPixelYOffset[0] = -1; + cpi->HalfPixelYOffset[1] = -1; + cpi->HalfPixelYOffset[2] = -1; + cpi->HalfPixelYOffset[3] = 0; + cpi->HalfPixelYOffset[4] = 0; + cpi->HalfPixelYOffset[5] = 0; + cpi->HalfPixelYOffset[6] = 1; + cpi->HalfPixelYOffset[7] = 1; + cpi->HalfPixelYOffset[8] = 1; + + + /* Generate offsets for 8 search sites per step. */ + while ( Len>0 ) { + /* Another step. */ + cpi->MVSearchSteps += 1; + + /* Compute offsets for search sites. */ + cpi->MVOffsetX[SearchSite] = -Len; + cpi->MVOffsetY[SearchSite++] = -Len; + cpi->MVOffsetX[SearchSite] = 0; + cpi->MVOffsetY[SearchSite++] = -Len; + cpi->MVOffsetX[SearchSite] = Len; + cpi->MVOffsetY[SearchSite++] = -Len; + cpi->MVOffsetX[SearchSite] = -Len; + cpi->MVOffsetY[SearchSite++] = 0; + cpi->MVOffsetX[SearchSite] = Len; + cpi->MVOffsetY[SearchSite++] = 0; + cpi->MVOffsetX[SearchSite] = -Len; + cpi->MVOffsetY[SearchSite++] = Len; + cpi->MVOffsetX[SearchSite] = 0; + cpi->MVOffsetY[SearchSite++] = Len; + cpi->MVOffsetX[SearchSite] = Len; + cpi->MVOffsetY[SearchSite++] = Len; + + /* Contract. */ + Len /= 2; + } + + /* Compute pixel index offsets. */ + for ( i=SearchSite-1; i>=0; i-- ) + cpi->MVPixelOffsetY[i] = (cpi->MVOffsetY[i]*LineStepY) + cpi->MVOffsetX[i]; +} + +static ogg_uint32_t GetInterErr (unsigned char * NewDataPtr, + unsigned char * RefDataPtr1, + unsigned char * RefDataPtr2, + ogg_uint32_t PixelsPerLine ) { + ogg_uint32_t i; + ogg_int32_t XSum=0; + ogg_int32_t XXSum=0; + ogg_int32_t DiffVal; + ogg_int32_t AbsRefOffset = abs((int)(RefDataPtr1 - RefDataPtr2)); + + /* Mode of interpolation chosen based upon on the offset of the + second reference pointer */ + if ( AbsRefOffset == 0 ) { + for ( i=0; i BestSoFar )break; + + /* Step to next row of block. */ + NewDataPtr += PixelsPerLine; + RefDataPtr += STRIDE_EXTRA+PixelsPerLine; + } + + return DiffVal; +} + +static ogg_uint32_t GetHalfPixelSumAbsDiffs (unsigned char * SrcData, + unsigned char * RefDataPtr1, + unsigned char * RefDataPtr2, + ogg_uint32_t PixelsPerLine, + ogg_uint32_t ErrorSoFar, + ogg_uint32_t BestSoFar ) { + + ogg_uint32_t i; + ogg_uint32_t DiffVal = ErrorSoFar; + ogg_int32_t RefOffset = (int)(RefDataPtr1 - RefDataPtr2); + ogg_uint32_t RefPixelsPerLine = PixelsPerLine + STRIDE_EXTRA; + + if ( RefOffset == 0 ) { + /* Simple case as for non 0.5 pixel */ + DiffVal += GetSumAbsDiffs( SrcData, RefDataPtr1, PixelsPerLine, + ErrorSoFar); + } else { + for ( i=0; i < BLOCK_HEIGHT_WIDTH; i++ ) { + DiffVal += abs( ((int)SrcData[0]) - (((int)RefDataPtr1[0] + + (int)RefDataPtr2[0]) / 2) ); + DiffVal += abs( ((int)SrcData[1]) - (((int)RefDataPtr1[1] + + (int)RefDataPtr2[1]) / 2) ); + DiffVal += abs( ((int)SrcData[2]) - (((int)RefDataPtr1[2] + + (int)RefDataPtr2[2]) / 2) ); + DiffVal += abs( ((int)SrcData[3]) - (((int)RefDataPtr1[3] + + (int)RefDataPtr2[3]) / 2) ); + DiffVal += abs( ((int)SrcData[4]) - (((int)RefDataPtr1[4] + + (int)RefDataPtr2[4]) / 2) ); + DiffVal += abs( ((int)SrcData[5]) - (((int)RefDataPtr1[5] + + (int)RefDataPtr2[5]) / 2) ); + DiffVal += abs( ((int)SrcData[6]) - (((int)RefDataPtr1[6] + + (int)RefDataPtr2[6]) / 2) ); + DiffVal += abs( ((int)SrcData[7]) - (((int)RefDataPtr1[7] + + (int)RefDataPtr2[7]) / 2) ); + + if ( DiffVal > BestSoFar ) break; + + /* Step to next row of block. */ + SrcData += PixelsPerLine; + RefDataPtr1 += RefPixelsPerLine; + RefDataPtr2 += RefPixelsPerLine; + } + } + + return DiffVal; +} + +static ogg_uint32_t GetIntraError (unsigned char * DataPtr, + ogg_uint32_t PixelsPerLine ) { + ogg_uint32_t i; + ogg_uint32_t XSum=0; + ogg_uint32_t XXSum=0; + unsigned char *DiffPtr; + + /* Loop expanded out for speed. */ + DiffPtr = DataPtr; + + for ( i=0; ipb.display_fragments[LocalFragIndex] ) + IntraError += + GetIntraError(&cpi-> + ConvDestBuffer[cpi->pb.pixel_index_table[LocalFragIndex]], + PixelsPerLine ); + + + LocalFragIndex++; + if ( cpi->pb.display_fragments[LocalFragIndex] ) + IntraError += + GetIntraError(&cpi-> + ConvDestBuffer[cpi->pb.pixel_index_table[LocalFragIndex]], + PixelsPerLine ); + + LocalFragIndex = FragIndex + cpi->pb.HFragments; + if ( cpi->pb.display_fragments[LocalFragIndex] ) + IntraError += + GetIntraError(&cpi-> + ConvDestBuffer[cpi->pb.pixel_index_table[LocalFragIndex]], + PixelsPerLine ); + + LocalFragIndex++; + if ( cpi->pb.display_fragments[LocalFragIndex] ) + IntraError += + GetIntraError(&cpi-> + ConvDestBuffer[cpi->pb.pixel_index_table[LocalFragIndex]], + PixelsPerLine ); + + return IntraError; +} + +ogg_uint32_t GetMBInterError (CP_INSTANCE *cpi, + unsigned char * SrcPtr, + unsigned char * RefPtr, + ogg_uint32_t FragIndex, + ogg_int32_t LastXMV, + ogg_int32_t LastYMV, + ogg_uint32_t PixelsPerLine ) { + ogg_uint32_t RefPixelsPerLine = cpi->pb.YStride; + ogg_uint32_t LocalFragIndex = FragIndex; + ogg_int32_t PixelIndex; + ogg_int32_t RefPixelIndex; + ogg_int32_t RefPixelOffset; + ogg_int32_t RefPtr2Offset; + + ogg_uint32_t InterError = 0; + + unsigned char * SrcPtr1; + unsigned char * RefPtr1; + + /* Work out pixel offset into source buffer. */ + PixelIndex = cpi->pb.pixel_index_table[LocalFragIndex]; + + /* Work out the pixel offset in reference buffer for the default + motion vector */ + RefPixelIndex = cpi->pb.recon_pixel_index_table[LocalFragIndex]; + RefPixelOffset = ((LastYMV/2) * RefPixelsPerLine) + (LastXMV/2); + + /* Work out the second reference pointer offset. */ + RefPtr2Offset = 0; + if ( LastXMV % 2 ) { + if ( LastXMV > 0 ) + RefPtr2Offset += 1; + else + RefPtr2Offset -= 1; + } + if ( LastYMV % 2 ) { + if ( LastYMV > 0 ) + RefPtr2Offset += RefPixelsPerLine; + else + RefPtr2Offset -= RefPixelsPerLine; + } + + /* Add together the errors for those blocks in the macro block that + are coded (Y only) */ + if ( cpi->pb.display_fragments[LocalFragIndex] ) { + SrcPtr1 = &SrcPtr[PixelIndex]; + RefPtr1 = &RefPtr[RefPixelIndex + RefPixelOffset]; + InterError += GetInterErr( SrcPtr1, RefPtr1, + &RefPtr1[RefPtr2Offset], PixelsPerLine ); + } + + LocalFragIndex++; + if ( cpi->pb.display_fragments[LocalFragIndex] ) { + PixelIndex = cpi->pb.pixel_index_table[LocalFragIndex]; + RefPixelIndex = cpi->pb.recon_pixel_index_table[LocalFragIndex]; + SrcPtr1 = &SrcPtr[PixelIndex]; + RefPtr1 = &RefPtr[RefPixelIndex + RefPixelOffset]; + InterError += GetInterErr( SrcPtr1, RefPtr1, + &RefPtr1[RefPtr2Offset], PixelsPerLine ); + + } + + LocalFragIndex = FragIndex + cpi->pb.HFragments; + if ( cpi->pb.display_fragments[LocalFragIndex] ) { + PixelIndex = cpi->pb.pixel_index_table[LocalFragIndex]; + RefPixelIndex = cpi->pb.recon_pixel_index_table[LocalFragIndex]; + SrcPtr1 = &SrcPtr[PixelIndex]; + RefPtr1 = &RefPtr[RefPixelIndex + RefPixelOffset]; + InterError += GetInterErr( SrcPtr1, RefPtr1, + &RefPtr1[RefPtr2Offset], PixelsPerLine ); + } + + LocalFragIndex++; + if ( cpi->pb.display_fragments[LocalFragIndex] ) { + PixelIndex = cpi->pb.pixel_index_table[LocalFragIndex]; + RefPixelIndex = cpi->pb.recon_pixel_index_table[LocalFragIndex]; + SrcPtr1 = &SrcPtr[PixelIndex]; + RefPtr1 = &RefPtr[RefPixelIndex + RefPixelOffset]; + InterError += GetInterErr( SrcPtr1, RefPtr1, + &RefPtr1[RefPtr2Offset], PixelsPerLine ); + } + return InterError; +} + +ogg_uint32_t GetMBMVInterError (CP_INSTANCE *cpi, + unsigned char * RefFramePtr, + ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine, + ogg_int32_t *MVPixelOffset, + MOTION_VECTOR *MV ) { + ogg_uint32_t Error = 0; + ogg_uint32_t MinError; + ogg_uint32_t InterMVError = 0; + + ogg_int32_t i; + ogg_int32_t x=0, y=0; + ogg_int32_t step; + ogg_int32_t SearchSite=0; + + unsigned char *SrcPtr[4] = {NULL,NULL,NULL,NULL}; + unsigned char *RefPtr=NULL; + unsigned char *CandidateBlockPtr=NULL; + unsigned char *BestBlockPtr=NULL; + + ogg_uint32_t RefRow2Offset = cpi->pb.YStride * 8; + + int MBlockDispFrags[4]; + + /* Half pixel variables */ + ogg_int32_t HalfPixelError; + ogg_int32_t BestHalfPixelError; + unsigned char BestHalfOffset; + unsigned char * RefDataPtr1; + unsigned char * RefDataPtr2; + + /* Note which of the four blocks in the macro block are to be + included in the search. */ + MBlockDispFrags[0] = + cpi->pb.display_fragments[FragIndex]; + MBlockDispFrags[1] = + cpi->pb.display_fragments[FragIndex + 1]; + MBlockDispFrags[2] = + cpi->pb.display_fragments[FragIndex + cpi->pb.HFragments]; + MBlockDispFrags[3] = + cpi->pb.display_fragments[FragIndex + cpi->pb.HFragments + 1]; + + /* Set up the source pointers for the four source blocks. */ + SrcPtr[0] = &cpi->ConvDestBuffer[cpi->pb.pixel_index_table[FragIndex]]; + SrcPtr[1] = SrcPtr[0] + 8; + SrcPtr[2] = SrcPtr[0] + (PixelsPerLine * 8); + SrcPtr[3] = SrcPtr[2] + 8; + + /* Set starting reference point for search. */ + RefPtr = &RefFramePtr[cpi->pb.recon_pixel_index_table[FragIndex]]; + + /* Check the 0,0 candidate. */ + if ( MBlockDispFrags[0] ) { + Error = GetSumAbsDiffs( SrcPtr[0], RefPtr, + PixelsPerLine, Error); + } + if ( MBlockDispFrags[1] ) { + Error = GetSumAbsDiffs( SrcPtr[1], RefPtr + 8, + PixelsPerLine, Error); + } + if ( MBlockDispFrags[2] ) { + Error = GetSumAbsDiffs( SrcPtr[2], RefPtr + RefRow2Offset, + PixelsPerLine, Error); + } + if ( MBlockDispFrags[3] ) { + Error = GetSumAbsDiffs( SrcPtr[3], RefPtr + RefRow2Offset + 8, + PixelsPerLine, Error); + } + + /* Set starting values to results of 0, 0 vector. */ + MinError = Error; + BestBlockPtr = RefPtr; + x = 0; + y = 0; + MV->x = 0; + MV->y = 0; + + /* Proceed through N-steps. */ + for ( step=0; stepMVSearchSteps; step++ ) { + /* Search the 8-neighbours at distance pertinent to current step.*/ + for ( i=0; i<8; i++ ) { + /* Set pointer to next candidate matching block. */ + CandidateBlockPtr = RefPtr + MVPixelOffset[SearchSite]; + + /* Reset error */ + Error = 0; + + /* Get the score for the current offset */ + if ( MBlockDispFrags[0] ) { + Error = GetSumAbsDiffs( SrcPtr[0], CandidateBlockPtr, + PixelsPerLine, Error); + } + + if ( MBlockDispFrags[1] && (Error < MinError) ) { + Error = GetNextSumAbsDiffs( SrcPtr[1], CandidateBlockPtr + 8, + PixelsPerLine, Error, MinError ); + } + + if ( MBlockDispFrags[2] && (Error < MinError) ) { + Error = GetNextSumAbsDiffs( SrcPtr[2], CandidateBlockPtr + RefRow2Offset, + PixelsPerLine, Error, MinError ); + } + + if ( MBlockDispFrags[3] && (Error < MinError) ) { + Error = GetNextSumAbsDiffs( SrcPtr[3], + CandidateBlockPtr + RefRow2Offset + 8, + PixelsPerLine, Error, MinError ); + } + + if ( Error < MinError ) { + /* Remember best match. */ + MinError = Error; + BestBlockPtr = CandidateBlockPtr; + + /* Where is it. */ + x = MV->x + cpi->MVOffsetX[SearchSite]; + y = MV->y + cpi->MVOffsetY[SearchSite]; + } + + /* Move to next search location. */ + SearchSite += 1; + } + + /* Move to best location this step. */ + RefPtr = BestBlockPtr; + MV->x = x; + MV->y = y; + } + + /* Factor vectors to 1/2 pixel resoultion. */ + MV->x = (MV->x * 2); + MV->y = (MV->y * 2); + + /* Now do the half pixel pass */ + BestHalfOffset = 4; /* Default to the no offset case. */ + BestHalfPixelError = MinError; + + /* Get the half pixel error for each half pixel offset */ + for ( i=0; i < 9; i++ ) { + HalfPixelError = 0; + + if ( MBlockDispFrags[0] ) { + RefDataPtr1 = BestBlockPtr; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[0], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( MBlockDispFrags[1] && (HalfPixelError < BestHalfPixelError) ) { + RefDataPtr1 = BestBlockPtr + 8; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[1], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( MBlockDispFrags[2] && (HalfPixelError < BestHalfPixelError) ) { + RefDataPtr1 = BestBlockPtr + RefRow2Offset; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[2], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( MBlockDispFrags[3] && (HalfPixelError < BestHalfPixelError) ) { + RefDataPtr1 = BestBlockPtr + RefRow2Offset + 8; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[3], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( HalfPixelError < BestHalfPixelError ) { + BestHalfOffset = (unsigned char)i; + BestHalfPixelError = HalfPixelError; + } + } + + /* Half pixel adjust the MV */ + MV->x += cpi->HalfPixelXOffset[BestHalfOffset]; + MV->y += cpi->HalfPixelYOffset[BestHalfOffset]; + + /* Get the error score for the chosen 1/2 pixel offset as a variance. */ + InterMVError = GetMBInterError( cpi, cpi->ConvDestBuffer, RefFramePtr, + FragIndex, MV->x, MV->y, PixelsPerLine ); + + /* Return score of best matching block. */ + return InterMVError; +} + +ogg_uint32_t GetMBMVExhaustiveSearch (CP_INSTANCE *cpi, + unsigned char * RefFramePtr, + ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine, + MOTION_VECTOR *MV ) { + ogg_uint32_t Error = 0; + ogg_uint32_t MinError = HUGE_ERROR; + ogg_uint32_t InterMVError = 0; + + ogg_int32_t i, j; + ogg_int32_t x=0, y=0; + + unsigned char *SrcPtr[4] = {NULL,NULL,NULL,NULL}; + unsigned char *RefPtr; + unsigned char *CandidateBlockPtr=NULL; + unsigned char *BestBlockPtr=NULL; + + ogg_uint32_t RefRow2Offset = cpi->pb.YStride * 8; + + int MBlockDispFrags[4]; + + /* Half pixel variables */ + ogg_int32_t HalfPixelError; + ogg_int32_t BestHalfPixelError; + unsigned char BestHalfOffset; + unsigned char * RefDataPtr1; + unsigned char * RefDataPtr2; + + /* Note which of the four blocks in the macro block are to be + included in the search. */ + MBlockDispFrags[0] = cpi-> + pb.display_fragments[FragIndex]; + MBlockDispFrags[1] = cpi-> + pb.display_fragments[FragIndex + 1]; + MBlockDispFrags[2] = cpi-> + pb.display_fragments[FragIndex + cpi->pb.HFragments]; + MBlockDispFrags[3] = cpi-> + pb.display_fragments[FragIndex + cpi->pb.HFragments + 1]; + + /* Set up the source pointers for the four source blocks. */ + SrcPtr[0] = &cpi-> + ConvDestBuffer[cpi->pb.pixel_index_table[FragIndex]]; + SrcPtr[1] = SrcPtr[0] + 8; + SrcPtr[2] = SrcPtr[0] + (PixelsPerLine * 8); + SrcPtr[3] = SrcPtr[2] + 8; + + RefPtr = &RefFramePtr[cpi->pb.recon_pixel_index_table[FragIndex]]; + RefPtr = RefPtr - ((MAX_MV_EXTENT/2) * cpi-> + pb.YStride) - (MAX_MV_EXTENT/2); + + /* Search each pixel alligned site */ + for ( i = 0; i < (ogg_int32_t)MAX_MV_EXTENT; i ++ ) { + /* Starting position in row */ + CandidateBlockPtr = RefPtr; + + for ( j = 0; j < (ogg_int32_t)MAX_MV_EXTENT; j++ ) { + /* Reset error */ + Error = 0; + + /* Summ errors for each block. */ + if ( MBlockDispFrags[0] ) { + Error = GetSumAbsDiffs( SrcPtr[0], CandidateBlockPtr, + PixelsPerLine, Error); + } + if ( MBlockDispFrags[1] ){ + Error = GetSumAbsDiffs( SrcPtr[1], CandidateBlockPtr + 8, + PixelsPerLine, Error); + } + if ( MBlockDispFrags[2] ){ + Error = GetSumAbsDiffs( SrcPtr[2], CandidateBlockPtr + RefRow2Offset, + PixelsPerLine, Error); + } + if ( MBlockDispFrags[3] ){ + Error = GetSumAbsDiffs( SrcPtr[3], CandidateBlockPtr + RefRow2Offset + 8, + PixelsPerLine, Error); + } + + /* Was this the best so far */ + if ( Error < MinError ) { + MinError = Error; + BestBlockPtr = CandidateBlockPtr; + x = 16 + j - MAX_MV_EXTENT; + y = 16 + i - MAX_MV_EXTENT; + } + + /* Move the the next site */ + CandidateBlockPtr ++; + } + + /* Move on to the next row. */ + RefPtr += cpi->pb.YStride; + + } + + /* Factor vectors to 1/2 pixel resoultion. */ + MV->x = (x * 2); + MV->y = (y * 2); + + /* Now do the half pixel pass */ + BestHalfOffset = 4; /* Default to the no offset case. */ + BestHalfPixelError = MinError; + + /* Get the half pixel error for each half pixel offset */ + for ( i=0; i < 9; i++ ) { + HalfPixelError = 0; + + if ( MBlockDispFrags[0] ) { + RefDataPtr1 = BestBlockPtr; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[0], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( MBlockDispFrags[1] && (HalfPixelError < BestHalfPixelError) ) { + RefDataPtr1 = BestBlockPtr + 8; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[1], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( MBlockDispFrags[2] && (HalfPixelError < BestHalfPixelError) ) { + RefDataPtr1 = BestBlockPtr + RefRow2Offset; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[2], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( MBlockDispFrags[3] && (HalfPixelError < BestHalfPixelError) ) { + RefDataPtr1 = BestBlockPtr + RefRow2Offset + 8; + RefDataPtr2 = RefDataPtr1 + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr[3], RefDataPtr1, RefDataPtr2, + PixelsPerLine, HalfPixelError, BestHalfPixelError ); + } + + if ( HalfPixelError < BestHalfPixelError ){ + BestHalfOffset = (unsigned char)i; + BestHalfPixelError = HalfPixelError; + } + } + + /* Half pixel adjust the MV */ + MV->x += cpi->HalfPixelXOffset[BestHalfOffset]; + MV->y += cpi->HalfPixelYOffset[BestHalfOffset]; + + /* Get the error score for the chosen 1/2 pixel offset as a variance. */ + InterMVError = GetMBInterError( cpi, cpi->ConvDestBuffer, RefFramePtr, + FragIndex, MV->x, MV->y, PixelsPerLine ); + + /* Return score of best matching block. */ + return InterMVError; +} + +static ogg_uint32_t GetBMVExhaustiveSearch (CP_INSTANCE *cpi, + unsigned char * RefFramePtr, + ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine, + MOTION_VECTOR *MV ) { + ogg_uint32_t Error = 0; + ogg_uint32_t MinError = HUGE_ERROR; + ogg_uint32_t InterMVError = 0; + + ogg_int32_t i, j; + ogg_int32_t x=0, y=0; + + unsigned char *SrcPtr = NULL; + unsigned char *RefPtr; + unsigned char *CandidateBlockPtr=NULL; + unsigned char *BestBlockPtr=NULL; + + /* Half pixel variables */ + ogg_int32_t HalfPixelError; + ogg_int32_t BestHalfPixelError; + unsigned char BestHalfOffset; + unsigned char * RefDataPtr2; + + /* Set up the source pointer for the block. */ + SrcPtr = &cpi-> + ConvDestBuffer[cpi->pb.pixel_index_table[FragIndex]]; + + RefPtr = &RefFramePtr[cpi->pb.recon_pixel_index_table[FragIndex]]; + RefPtr = RefPtr - ((MAX_MV_EXTENT/2) * + cpi->pb.YStride) - (MAX_MV_EXTENT/2); + + /* Search each pixel alligned site */ + for ( i = 0; i < (ogg_int32_t)MAX_MV_EXTENT; i ++ ) { + /* Starting position in row */ + CandidateBlockPtr = RefPtr; + + for ( j = 0; j < (ogg_int32_t)MAX_MV_EXTENT; j++ ){ + /* Get the block error score. */ + Error = GetSumAbsDiffs( SrcPtr, CandidateBlockPtr, + PixelsPerLine, 0); + + /* Was this the best so far */ + if ( Error < MinError ) { + MinError = Error; + BestBlockPtr = CandidateBlockPtr; + x = 16 + j - MAX_MV_EXTENT; + y = 16 + i - MAX_MV_EXTENT; + } + + /* Move the the next site */ + CandidateBlockPtr ++; + } + + /* Move on to the next row. */ + RefPtr += cpi->pb.YStride; + } + + /* Factor vectors to 1/2 pixel resoultion. */ + MV->x = (x * 2); + MV->y = (y * 2); + + /* Now do the half pixel pass */ + BestHalfOffset = 4; /* Default to the no offset case. */ + BestHalfPixelError = MinError; + + /* Get the half pixel error for each half pixel offset */ + for ( i=0; i < 9; i++ ) { + RefDataPtr2 = BestBlockPtr + cpi->HalfPixelRef2Offset[i]; + HalfPixelError = + GetHalfPixelSumAbsDiffs( SrcPtr, BestBlockPtr, RefDataPtr2, + PixelsPerLine, 0, BestHalfPixelError ); + + if ( HalfPixelError < BestHalfPixelError ){ + BestHalfOffset = (unsigned char)i; + BestHalfPixelError = HalfPixelError; + } + } + + /* Half pixel adjust the MV */ + MV->x += cpi->HalfPixelXOffset[BestHalfOffset]; + MV->y += cpi->HalfPixelYOffset[BestHalfOffset]; + + /* Get the variance score at the chosen offset */ + RefDataPtr2 = BestBlockPtr + cpi->HalfPixelRef2Offset[BestHalfOffset]; + + InterMVError = + GetInterErr( SrcPtr, BestBlockPtr, RefDataPtr2, PixelsPerLine ); + + /* Return score of best matching block. */ + return InterMVError; +} + +ogg_uint32_t GetFOURMVExhaustiveSearch (CP_INSTANCE *cpi, + unsigned char * RefFramePtr, + ogg_uint32_t FragIndex, + ogg_uint32_t PixelsPerLine, + MOTION_VECTOR *MV ) { + ogg_uint32_t InterMVError; + + /* For the moment the 4MV mode is only deemd to be valid if all four + Y blocks are to be updated */ + /* This May be adapted later. */ + if ( cpi->pb.display_fragments[FragIndex] && + cpi->pb.display_fragments[FragIndex + 1] && + cpi->pb.display_fragments[FragIndex + cpi->pb.HFragments] && + cpi->pb.display_fragments[FragIndex + cpi->pb.HFragments + 1] ) { + + /* Reset the error score. */ + InterMVError = 0; + + /* Get the error component from each coded block */ + InterMVError += + GetBMVExhaustiveSearch(cpi, RefFramePtr, FragIndex, + PixelsPerLine, &(MV[0]) ); + InterMVError += + GetBMVExhaustiveSearch(cpi, RefFramePtr, (FragIndex + 1), + PixelsPerLine, &(MV[1]) ); + InterMVError += + GetBMVExhaustiveSearch(cpi, RefFramePtr, + (FragIndex + cpi->pb.HFragments), + PixelsPerLine, &(MV[2]) ); + InterMVError += + GetBMVExhaustiveSearch(cpi, RefFramePtr, + (FragIndex + cpi->pb.HFragments + 1), + PixelsPerLine, &(MV[3]) ); + }else{ + InterMVError = HUGE_ERROR; + } + + /* Return score of best matching block. */ + return InterMVError; +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/misc_common.c b/src/add-ons/media/plugins/theora/libtheora/misc_common.c new file mode 100644 index 0000000000..60499c3d76 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/misc_common.c @@ -0,0 +1,337 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: misc_common.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include "encoder_internal.h" +#include "block_inline.h" + +#define FIXED_Q 150 +#define MAX_UP_REG_LOOPS 2 + +/* Gives the initial bytes per block estimate for each Q value */ +double BpbTable[Q_TABLE_SIZE] = { + 0.42, 0.45, 0.46, 0.49, 0.51, 0.53, 0.56, 0.58, + 0.61, 0.64, 0.68, 0.71, 0.74, 0.77, 0.80, 0.84, + 0.89, 0.92, 0.98, 1.01, 1.04, 1.13, 1.17, 1.23, + 1.28, 1.34, 1.41, 1.45, 1.51, 1.59, 1.69, 1.80, + 1.84, 1.94, 2.02, 2.15, 2.23, 2.34, 2.44, 2.50, + 2.69, 2.80, 2.87, 3.04, 3.16, 3.29, 3.59, 3.66, + 3.86, 3.94, 4.22, 4.50, 4.64, 4.70, 5.24, 5.34, + 5.61, 5.87, 6.11, 6.41, 6.71, 6.99, 7.36, 7.69 +}; + +double KfBpbTable[Q_TABLE_SIZE] = { + 0.74, 0.81, 0.88, 0.94, 1.00, 1.06, 1.14, 1.19, + 1.27, 1.34, 1.42, 1.49, 1.54, 1.59, 1.66, 1.73, + 1.80, 1.87, 1.97, 2.01, 2.08, 2.21, 2.25, 2.36, + 2.39, 2.50, 2.55, 2.65, 2.71, 2.82, 2.95, 3.01, + 3.11, 3.19, 3.31, 3.42, 3.58, 3.66, 3.78, 3.89, + 4.11, 4.26, 4.36, 4.39, 4.63, 4.76, 4.85, 5.04, + 5.26, 5.29, 5.47, 5.64, 5.76, 6.05, 6.35, 6.67, + 6.91, 7.17, 7.40, 7.56, 8.02, 8.45, 8.86, 9.38 +}; + +double GetEstimatedBpb( CP_INSTANCE *cpi, ogg_uint32_t TargetQ ){ + ogg_uint32_t i; + ogg_int32_t ThreshTableIndex = Q_TABLE_SIZE - 1; + double BytesPerBlock; + + /* Search for the Q table index that matches the given Q. */ + for ( i = 0; i < Q_TABLE_SIZE; i++ ) { + if ( TargetQ >= cpi->pb.QThreshTable[i] ) { + ThreshTableIndex = i; + break; + } + } + + /* Adjust according to Q shift and type of frame */ + if ( GetFrameType(&cpi->pb) == BASE_FRAME ) { + /* Get primary prediction */ + BytesPerBlock = KfBpbTable[ThreshTableIndex]; + } else { + /* Get primary prediction */ + BytesPerBlock = BpbTable[ThreshTableIndex]; + BytesPerBlock = BytesPerBlock * cpi->BpbCorrectionFactor; + } + + return BytesPerBlock; +} + +static void UpRegulateMB( CP_INSTANCE *cpi, ogg_uint32_t RegulationQ, + ogg_uint32_t SB, ogg_uint32_t MB, int NoCheck ) { + ogg_int32_t FragIndex; + ogg_uint32_t B; + + /* Variables used in calculating corresponding row,col and index in + UV planes */ + ogg_uint32_t UVRow; + ogg_uint32_t UVColumn; + ogg_uint32_t UVFragOffset; + + /* There may be MB's lying out of frame which must be ignored. For + these MB's Top left block will have a negative Fragment Index. */ + if ( QuadMapToMBTopLeft(cpi->pb.BlockMap, SB, MB ) >= 0 ) { + /* Up regulate the component blocks Y then UV. */ + for ( B=0; B<4; B++ ){ + FragIndex = QuadMapToIndex1( cpi->pb.BlockMap, SB, MB, B ); + + if ( ( !cpi->pb.display_fragments[FragIndex] ) && + ( (NoCheck) || (cpi->FragmentLastQ[FragIndex] > RegulationQ) ) ){ + cpi->pb.display_fragments[FragIndex] = 1; + cpi->extra_fragments[FragIndex] = 1; + cpi->FragmentLastQ[FragIndex] = RegulationQ; + cpi->MotionScore++; + } + } + + /* Check the two UV blocks */ + FragIndex = QuadMapToMBTopLeft(cpi->pb.BlockMap, SB, MB ); + + UVRow = (FragIndex / (cpi->pb.HFragments * 2)); + UVColumn = (FragIndex % cpi->pb.HFragments) / 2; + UVFragOffset = (UVRow * (cpi->pb.HFragments / 2)) + UVColumn; + + FragIndex = cpi->pb.YPlaneFragments + UVFragOffset; + if ( ( !cpi->pb.display_fragments[FragIndex] ) && + ( (NoCheck) || (cpi->FragmentLastQ[FragIndex] > RegulationQ) ) ) { + cpi->pb.display_fragments[FragIndex] = 1; + cpi->extra_fragments[FragIndex] = 1; + cpi->FragmentLastQ[FragIndex] = RegulationQ; + cpi->MotionScore++; + } + + FragIndex += cpi->pb.UVPlaneFragments; + if ( ( !cpi->pb.display_fragments[FragIndex] ) && + ( (NoCheck) || (cpi->FragmentLastQ[FragIndex] > RegulationQ) ) ) { + cpi->pb.display_fragments[FragIndex] = 1; + cpi->extra_fragments[FragIndex] = 1; + cpi->FragmentLastQ[FragIndex] = RegulationQ; + cpi->MotionScore++; + } + } +} + +static void UpRegulateBlocks (CP_INSTANCE *cpi, ogg_uint32_t RegulationQ, + ogg_int32_t RecoveryBlocks, + ogg_uint32_t * LastSB, ogg_uint32_t * LastMB ) { + + ogg_uint32_t LoopTimesRound = 0; + ogg_uint32_t MaxSB = cpi->pb.YSBRows * + cpi->pb.YSBCols; /* Tot super blocks in image */ + ogg_uint32_t SB, MB; /* Super-Block and macro block indices. */ + + /* First scan for blocks for which a residue update is outstanding. */ + while ( (cpi->MotionScore < RecoveryBlocks) && + (LoopTimesRound < MAX_UP_REG_LOOPS) ) { + LoopTimesRound++; + + for ( SB = (*LastSB); SB < MaxSB; SB++ ) { + /* Check its four Macro-Blocks */ + for ( MB=(*LastMB); MB<4; MB++ ) { + /* Mark relevant blocks for update */ + UpRegulateMB( cpi, RegulationQ, SB, MB, 0 ); + + /* Keep track of the last refresh MB. */ + (*LastMB) += 1; + if ( (*LastMB) == 4 ) + (*LastMB) = 0; + + /* Termination clause */ + if (cpi->MotionScore >= RecoveryBlocks) { + /* Make sure we don't stall at SB level */ + if ( *LastMB == 0 ) + SB++; + break; + } + } + + /* Termination clause */ + if (cpi->MotionScore >= RecoveryBlocks) + break; + } + + /* Update super block start index */ + if ( SB >= MaxSB){ + (*LastSB) = 0; + }else{ + (*LastSB) = SB; + } + } +} + +void UpRegulateDataStream (CP_INSTANCE *cpi, ogg_uint32_t RegulationQ, + ogg_int32_t RecoveryBlocks ) { + ogg_uint32_t LastPassMBPos = 0; + ogg_uint32_t StdLastMBPos = 0; + + ogg_uint32_t MaxSB = cpi->pb.YSBRows * + cpi->pb.YSBCols; /* Tot super blocks in image */ + + ogg_uint32_t SB=0; /* Super-Block index */ + ogg_uint32_t MB; /* Macro-Block index */ + + /* Decduct the number of blocks in an MB / 2 from the recover block count. + This will compensate for the fact that once we start checking an MB + we test every block in that macro block */ + if ( RecoveryBlocks > 3 ) + RecoveryBlocks -= 3; + + /* Up regulate blocks last coded at higher Q */ + UpRegulateBlocks( cpi, RegulationQ, RecoveryBlocks, + &cpi->LastEndSB, &StdLastMBPos ); + + /* If we have still not used up the minimum number of blocks and are + at the minimum Q then run through a final pass of the data to + insure that each block gets a final refresh. */ + if ( (RegulationQ == VERY_BEST_Q) && + (cpi->MotionScore < RecoveryBlocks) ) { + if ( cpi->FinalPassLastPos < MaxSB ) { + for ( SB = cpi->FinalPassLastPos; SB < MaxSB; SB++ ) { + /* Check its four Macro-Blocks */ + for ( MB=LastPassMBPos; MB<4; MB++ ) { + /* Mark relevant blocks for update */ + UpRegulateMB( cpi, RegulationQ, SB, MB, 1 ); + + /* Keep track of the last refresh MB. */ + LastPassMBPos += 1; + if ( LastPassMBPos == 4 ) { + LastPassMBPos = 0; + + /* Increment SB index */ + cpi->FinalPassLastPos += 1; + } + + /* Termination clause */ + if (cpi->MotionScore >= RecoveryBlocks) + break; + } + + /* Termination clause */ + if (cpi->MotionScore >= RecoveryBlocks) + break; + + } + } + } +} + +void RegulateQ( CP_INSTANCE *cpi, ogg_int32_t UpdateScore ) { + double TargetUnitScoreBytes = (double)cpi->ThisFrameTargetBytes / + (double)UpdateScore; + double PredUnitScoreBytes; + double LastBitError = 10000.0; /* Silly high number */ + ogg_uint32_t QIndex = Q_TABLE_SIZE - 1; + ogg_uint32_t i; + + /* Search for the best Q for the target bitrate. */ + for ( i = 0; i < Q_TABLE_SIZE; i++ ) { + PredUnitScoreBytes = GetEstimatedBpb( cpi, cpi->pb.QThreshTable[i] ); + if ( PredUnitScoreBytes > TargetUnitScoreBytes ) { + if ( (PredUnitScoreBytes - TargetUnitScoreBytes) <= LastBitError ) { + QIndex = i; + } else { + QIndex = i - 1; + } + break; + } else { + LastBitError = TargetUnitScoreBytes - PredUnitScoreBytes; + } + } + + /* QIndex should now indicate the optimal Q. */ + cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[QIndex]; + + /* Apply range restrictions for key frames. */ + if ( GetFrameType(&cpi->pb) == BASE_FRAME ) { + if ( cpi->pb.ThisFrameQualityValue > cpi->pb.QThreshTable[20] ) + cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[20]; + else if ( cpi->pb.ThisFrameQualityValue < cpi->pb.QThreshTable[50] ) + cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[50]; + } + + /* Limit the Q value to the maximum available value */ + if (cpi->pb.ThisFrameQualityValue > + cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ]) { + cpi->pb.ThisFrameQualityValue = + (ogg_uint32_t)cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ]; + } + + if(cpi->FixedQ) { + if ( GetFrameType(&cpi->pb) == BASE_FRAME ) { + cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[43]; + cpi->pb.ThisFrameQualityValue = cpi->FixedQ; + } else { + cpi->pb.ThisFrameQualityValue = cpi->FixedQ; + } + } + + /* If th quantiser value has changed then re-initialise it */ + if ( cpi->pb.ThisFrameQualityValue != cpi->pb.LastFrameQualityValue ) { + /* Initialise quality tables. */ + UpdateQC( cpi, cpi->pb.ThisFrameQualityValue ); + cpi->pb.LastFrameQualityValue = cpi->pb.ThisFrameQualityValue; + } +} + +void CopyBackExtraFrags(CP_INSTANCE *cpi){ + ogg_uint32_t i,j; + unsigned char * SrcPtr; + unsigned char * DestPtr; + ogg_uint32_t PlaneLineStep; + ogg_uint32_t PixelIndex; + + /* Copy back for Y plane. */ + PlaneLineStep = cpi->pb.info.width; + for ( i = 0; i < cpi->pb.YPlaneFragments; i++ ) { + /* We are only interested in updated fragments. */ + if ( cpi->extra_fragments[i] ) { + /* Get the start index for the fragment. */ + PixelIndex = cpi->pb.pixel_index_table[i]; + SrcPtr = &cpi->yuv1ptr[PixelIndex]; + DestPtr = &cpi->ConvDestBuffer[PixelIndex]; + + for ( j = 0; j < VFRAGPIXELS; j++ ) { + memcpy( DestPtr, SrcPtr, HFRAGPIXELS); + + SrcPtr += PlaneLineStep; + DestPtr += PlaneLineStep; + } + } + } + + /* Now the U and V planes */ + PlaneLineStep = cpi->pb.info.width / 2; + for ( i = cpi->pb.YPlaneFragments; + i < (cpi->pb.YPlaneFragments + (2 * cpi->pb.UVPlaneFragments)) ; + i++ ) { + + /* We are only interested in updated fragments. */ + if ( cpi->extra_fragments[i] ) { + /* Get the start index for the fragment. */ + PixelIndex = cpi->pb.pixel_index_table[i]; + SrcPtr = &cpi->yuv1ptr[PixelIndex]; + DestPtr = &cpi->ConvDestBuffer[PixelIndex]; + + for ( j = 0; j < VFRAGPIXELS; j++ ) { + memcpy( DestPtr, SrcPtr, HFRAGPIXELS); + SrcPtr += PlaneLineStep; + DestPtr += PlaneLineStep; + } + } + } +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/pb.c b/src/add-ons/media/plugins/theora/libtheora/pb.c new file mode 100644 index 0000000000..3065fa9a0b --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/pb.c @@ -0,0 +1,117 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: pb.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include "encoder_internal.h" + +void ClearTmpBuffers(PB_INSTANCE * pbi){ + + if(pbi->ReconDataBuffer) + _ogg_free(pbi->ReconDataBuffer); + if(pbi->DequantBuffer) + _ogg_free(pbi->DequantBuffer); + if(pbi->TmpDataBuffer) + _ogg_free(pbi->TmpDataBuffer); + if(pbi->TmpReconBuffer) + _ogg_free(pbi->TmpReconBuffer); + if(pbi->dequant_Y_coeffs) + _ogg_free(pbi->dequant_Y_coeffs); + if(pbi->dequant_UV_coeffs) + _ogg_free(pbi->dequant_UV_coeffs); + if(pbi->dequant_Inter_coeffs) + _ogg_free(pbi->dequant_Inter_coeffs); + if(pbi->dequant_InterUV_coeffs) + _ogg_free(pbi->dequant_InterUV_coeffs); + + + pbi->ReconDataBuffer=0; + pbi->DequantBuffer = 0; + pbi->TmpDataBuffer = 0; + pbi->TmpReconBuffer = 0; + pbi->dequant_Y_coeffs = 0; + pbi->dequant_UV_coeffs = 0; + pbi->dequant_InterUV_coeffs = 0; + pbi->dequant_Inter_coeffs = 0; + +} + +void InitTmpBuffers(PB_INSTANCE * pbi){ + + /* clear any existing info */ + ClearTmpBuffers(pbi); + + /* Adjust the position of all of our temporary */ + pbi->ReconDataBuffer = + _ogg_malloc(64*sizeof(*pbi->ReconDataBuffer)); + + pbi->DequantBuffer = + _ogg_malloc(64 * sizeof(*pbi->DequantBuffer)); + + pbi->TmpDataBuffer = + _ogg_malloc(64 * sizeof(*pbi->TmpDataBuffer)); + + pbi->TmpReconBuffer = + _ogg_malloc(64 * sizeof(*pbi->TmpReconBuffer)); + + pbi->dequant_Y_coeffs = + _ogg_malloc(64 * sizeof(*pbi->dequant_Y_coeffs)); + + pbi->dequant_UV_coeffs = + _ogg_malloc(64 * sizeof(*pbi->dequant_UV_coeffs)); + + pbi->dequant_Inter_coeffs = + _ogg_malloc(64 * sizeof(*pbi->dequant_Inter_coeffs)); + + pbi->dequant_InterUV_coeffs = + _ogg_malloc(64 * sizeof(*pbi->dequant_InterUV_coeffs)); + +} + +void ClearPBInstance(PB_INSTANCE *pbi){ + if(pbi){ + ClearTmpBuffers(pbi); + if (pbi->opb) { + _ogg_free(pbi->opb); + } + } +} + +void InitPBInstance(PB_INSTANCE *pbi){ + /* initialize whole structure to 0 */ + memset(pbi, 0, sizeof(*pbi)); + + InitTmpBuffers(pbi); + + /* allocate memory for the oggpack_buffer */ +#ifndef LIBOGG2 + pbi->opb = _ogg_malloc(sizeof(oggpack_buffer)); +#else + pbi->opb = _ogg_malloc(oggpack_buffersize()); +#endif + + /* variables needing initialization (not being set to 0) */ + + pbi->ModifierPointer[0] = &pbi->Modifier[0][255]; + pbi->ModifierPointer[1] = &pbi->Modifier[1][255]; + pbi->ModifierPointer[2] = &pbi->Modifier[2][255]; + pbi->ModifierPointer[3] = &pbi->Modifier[3][255]; + + pbi->DecoderErrorCode = 0; + pbi->KeyFrameType = DCT_KEY_FRAME; + pbi->FramesHaveBeenSkipped = 0; +} diff --git a/src/add-ons/media/plugins/theora/libtheora/pp.c b/src/add-ons/media/plugins/theora/libtheora/pp.c new file mode 100644 index 0000000000..4d5550f503 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/pp.c @@ -0,0 +1,951 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: pp.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include "encoder_internal.h" +#include "pp.h" + +#define MAX(a, b) ((a>b)?a:b) +#define MIN(a, b) ((aScanPixelIndexTable) _ogg_free(ppi->ScanPixelIndexTable); + ppi->ScanPixelIndexTable=0; + + if(ppi->ScanDisplayFragments) _ogg_free(ppi->ScanDisplayFragments); + ppi->ScanDisplayFragments=0; + + for(i = 0 ; i < MAX_PREV_FRAMES ; i ++) + if(ppi->PrevFragments[i]){ + _ogg_free(ppi->PrevFragments[i]); + ppi->PrevFragments[i]=0; + } + + if(ppi->FragScores) _ogg_free(ppi->FragScores); + ppi->FragScores=0; + + if(ppi->SameGreyDirPixels) _ogg_free(ppi->SameGreyDirPixels); + ppi->SameGreyDirPixels=0; + + if(ppi->FragDiffPixels) _ogg_free(ppi->FragDiffPixels); + ppi->FragDiffPixels=0; + + if(ppi->BarBlockMap) _ogg_free(ppi->BarBlockMap); + ppi->BarBlockMap=0; + + if(ppi->TmpCodedMap) _ogg_free(ppi->TmpCodedMap); + ppi->TmpCodedMap=0; + + if(ppi->RowChangedPixels) _ogg_free(ppi->RowChangedPixels); + ppi->RowChangedPixels=0; + + if(ppi->PixelScores) _ogg_free(ppi->PixelScores); + ppi->PixelScores=0; + + if(ppi->PixelChangedMap) _ogg_free(ppi->PixelChangedMap); + ppi->PixelChangedMap=0; + + if(ppi->ChLocals) _ogg_free(ppi->ChLocals); + ppi->ChLocals=0; + + if(ppi->yuv_differences) _ogg_free(ppi->yuv_differences); + ppi->yuv_differences=0; + +} + +void PInitFrameInfo(PP_INSTANCE * ppi){ + int i; + PClearFrameInfo(ppi); + + ppi->ScanPixelIndexTable = + _ogg_malloc(ppi->ScanFrameFragments*sizeof(*ppi->ScanPixelIndexTable)); + + ppi->ScanDisplayFragments = + _ogg_malloc(ppi->ScanFrameFragments*sizeof(*ppi->ScanDisplayFragments)); + + for(i = 0 ; i < MAX_PREV_FRAMES ; i ++) + ppi->PrevFragments[i] = + _ogg_malloc(ppi->ScanFrameFragments*sizeof(*ppi->PrevFragments)); + + ppi->FragScores = + _ogg_malloc(ppi->ScanFrameFragments*sizeof(*ppi->FragScores)); + + ppi->SameGreyDirPixels = + _ogg_malloc(ppi->ScanFrameFragments*sizeof(*ppi->SameGreyDirPixels)); + + ppi->FragDiffPixels = + _ogg_malloc(ppi->ScanFrameFragments*sizeof(*ppi->FragScores)); + + ppi->BarBlockMap= + _ogg_malloc(3 * ppi->ScanHFragments*sizeof(*ppi->BarBlockMap)); + + ppi->TmpCodedMap = + _ogg_malloc(ppi->ScanHFragments*sizeof(*ppi->TmpCodedMap)); + + ppi->RowChangedPixels = + _ogg_malloc(3 * ppi->ScanConfig.VideoFrameHeight* + sizeof(*ppi->RowChangedPixels)); + + ppi->PixelScores = + _ogg_malloc(ppi->ScanConfig.VideoFrameWidth* + sizeof(*ppi->PixelScores) * PSCORE_CB_ROWS); + + ppi->PixelChangedMap = + _ogg_malloc(ppi->ScanConfig.VideoFrameWidth* + sizeof(*ppi->PixelChangedMap) * PMAP_CB_ROWS); + + ppi->ChLocals = + _ogg_malloc(ppi->ScanConfig.VideoFrameWidth* + sizeof(*ppi->ChLocals) * CHLOCALS_CB_ROWS); + + ppi->yuv_differences = + _ogg_malloc(ppi->ScanConfig.VideoFrameWidth* + sizeof(*ppi->yuv_differences) * YDIFF_CB_ROWS); +} + +void ClearPPInstance(PP_INSTANCE *ppi){ + PClearFrameInfo(ppi); +} + + +void InitPPInstance(PP_INSTANCE *ppi){ + + memset(ppi,0,sizeof(*ppi)); + + /* Initializations */ + ppi->PrevFrameLimit = 3; /* Must not exceed MAX_PREV_FRAMES (Note + that this number includes the current + frame so "1 = no effect") */ + + /* Scan control variables. */ + ppi->HFragPixels = 8; + ppi->VFragPixels = 8; + + ppi->SRFGreyThresh = 4; + ppi->SRFColThresh = 5; + ppi->NoiseSupLevel = 3; + ppi->SgcLevelThresh = 3; + ppi->SuvcLevelThresh = 4; + + /* Variables controlling S.A.D. breakouts. */ + ppi->GrpLowSadThresh = 10; + ppi->GrpHighSadThresh = 64; + ppi->PrimaryBlockThreshold = 5; + ppi->SgcThresh = 16; /* (Default values for 8x8 blocks). */ + + ppi->UVBlockThreshCorrection = 1.25; + ppi->UVSgcCorrection = 1.5; + + ppi->MaxLineSearchLen = MAX_SEARCH_LINE_LEN; +} + +static void DeringBlockStrong(unsigned char *SrcPtr, + unsigned char *DstPtr, + ogg_int32_t Pitch, + ogg_uint32_t FragQIndex, + ogg_uint32_t *QuantScale){ + + ogg_int16_t UDMod[72]; + ogg_int16_t LRMod[72]; + unsigned int j,k,l; + const unsigned char * Src; + unsigned int QValue = QuantScale[FragQIndex]; + + unsigned char p; + unsigned char pl; + unsigned char pr; + unsigned char pu; + unsigned char pd; + + int al; + int ar; + int au; + int ad; + + int atot; + int B; + int newVal; + + const unsigned char *curRow = SrcPtr - 1; /* avoid negative array indexes */ + unsigned char *dstRow = DstPtr; + const unsigned char *lastRow = SrcPtr-Pitch; + const unsigned char *nextRow = SrcPtr+Pitch; + + unsigned int rowOffset = 0; + unsigned int round = (1<<6); + + int High; + int Low; + int TmpMod; + + int Sharpen = SharpenModifier[FragQIndex]; + High = 3 * QValue; + if(High>32)High=32; + Low = 0; + + + /* Initialize the Mod Data */ + Src = SrcPtr-Pitch; + for(k=0;k<9;k++){ + for(j=0;j<8;j++){ + + TmpMod = 32 + QValue - (abs(Src[j+Pitch]-Src[j])); + + if(TmpMod< -64) + TmpMod = Sharpen; + + else if(TmpModHigh) + TmpMod = High; + + UDMod[k*8+j] = (ogg_int16_t)TmpMod; + } + Src +=Pitch; + } + + Src = SrcPtr-1; + + for(k=0;k<8;k++){ + for(j=0;j<9;j++){ + TmpMod = 32 + QValue - (abs(Src[j+1]-Src[j])); + + if(TmpMod< -64 ) + TmpMod = Sharpen; + + else if(TmpMod<0) + TmpMod = Low; + + else if(TmpMod>High) + TmpMod = High; + + LRMod[k*9+j] = (ogg_int16_t)TmpMod; + } + Src+=Pitch; + } + + for(k=0;k<8;k++){ + /* In the case that this function called with same buffer for + source and destination, To keep the c and the mmx version to have + consistant results, intermediate buffer is used to store the + eight pixel value before writing them to destination + (i.e. Overwriting souce for the speical case) */ + for(l=0;l<8;l++){ + + atot = 128; + B = round; + p = curRow[ rowOffset +l +1]; + + pl = curRow[ rowOffset +l]; + al = LRMod[k*9+l]; + atot -= al; + B += al * pl; + + pu = lastRow[ rowOffset +l]; + au = UDMod[k*8+l]; + atot -= au; + B += au * pu; + + pd = nextRow[ rowOffset +l]; + ad = UDMod[(k+1)*8+l]; + atot -= ad; + B += ad * pd; + + pr = curRow[ rowOffset +l+2]; + ar = LRMod[k*9+l+1]; + atot -= ar; + B += ar * pr; + + newVal = ( atot * p + B) >> 7; + + dstRow[ rowOffset +l]= clamp255( newVal ); + } + rowOffset += Pitch; + } +} + +static void DeringBlockWeak(unsigned char *SrcPtr, + unsigned char *DstPtr, + ogg_int32_t Pitch, + ogg_uint32_t FragQIndex, + ogg_uint32_t *QuantScale){ + + ogg_int16_t UDMod[72]; + ogg_int16_t LRMod[72]; + unsigned int j,k; + const unsigned char * Src; + unsigned int QValue = QuantScale[FragQIndex]; + + unsigned char p; + unsigned char pl; + unsigned char pr; + unsigned char pu; + unsigned char pd; + + int al; + int ar; + int au; + int ad; + + int atot; + int B; + int newVal; + + const unsigned char *curRow = SrcPtr-1; + unsigned char *dstRow = DstPtr; + const unsigned char *lastRow = SrcPtr-Pitch; + const unsigned char *nextRow = SrcPtr+Pitch; + + unsigned int rowOffset = 0; + unsigned int round = (1<<6); + + int High; + int Low; + int TmpMod; + int Sharpen = SharpenModifier[FragQIndex]; + + High = 3 * QValue; + if(High>24) + High=24; + Low = 0 ; + + /* Initialize the Mod Data */ + Src=SrcPtr-Pitch; + for(k=0;k<9;k++) { + for(j=0;j<8;j++) { + + TmpMod = 32 + QValue - 2*(abs(Src[j+Pitch]-Src[j])); + + if(TmpMod< -64) + TmpMod = Sharpen; + + else if(TmpModHigh) + TmpMod = High; + + UDMod[k*8+j] = (ogg_int16_t)TmpMod; + } + Src +=Pitch; + } + + Src = SrcPtr-1; + + for(k=0;k<8;k++){ + for(j=0;j<9;j++){ + TmpMod = 32 + QValue - 2*(abs(Src[j+1]-Src[j])); + + if(TmpMod< -64 ) + TmpMod = Sharpen; + + else if(TmpModHigh) + TmpMod = High; + + LRMod[k*9+j] = (ogg_int16_t)TmpMod; + } + Src+=Pitch; + } + + for(k=0;k<8;k++) { + for(j=0;j<8;j++){ + atot = 128; + B = round; + p = curRow[ rowOffset +j+1]; + + pl = curRow[ rowOffset +j]; + al = LRMod[k*9+j]; + atot -= al; + B += al * pl; + + pu = lastRow[ rowOffset +j]; + au = UDMod[k*8+j]; + atot -= au; + B += au * pu; + + pd = nextRow[ rowOffset +j]; + ad = UDMod[(k+1)*8+j]; + atot -= ad; + B += ad * pd; + + pr = curRow[ rowOffset +j+2]; + ar = LRMod[k*9+j+1]; + atot -= ar; + B += ar * pr; + + newVal = ( atot * p + B) >> 7; + + dstRow[ rowOffset +j] = clamp255( newVal ); + } + + rowOffset += Pitch; + } +} + +static void DeringFrame(PB_INSTANCE *pbi, + unsigned char *Src, unsigned char *Dst){ + ogg_uint32_t col,row; + unsigned char *SrcPtr; + unsigned char *DestPtr; + ogg_uint32_t BlocksAcross,BlocksDown; + ogg_uint32_t *QuantScale; + ogg_uint32_t Block; + ogg_uint32_t LineLength; + + ogg_int32_t Thresh1,Thresh2,Thresh3,Thresh4; + + Thresh1 = 384; + Thresh2 = 4 * Thresh1; + Thresh3 = 5 * Thresh2/4; + Thresh4 = 5 * Thresh2/2; + + QuantScale = DeringModifierV1; + + BlocksAcross = pbi->HFragments; + BlocksDown = pbi->VFragments; + + SrcPtr = Src + pbi->ReconYDataOffset; + DestPtr = Dst + pbi->ReconYDataOffset; + LineLength = pbi->YStride; + + Block = 0; + + for ( row = 0 ; row < BlocksDown; row ++){ + for (col = 0; col < BlocksAcross; col ++){ + ogg_uint32_t Quality = pbi->FragQIndex[Block]; + ogg_int32_t Variance = pbi->FragmentVariances[Block]; + + if( pbi->PostProcessingLevel >5 && Variance > Thresh3 ){ + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + + if( (col > 0 && + pbi->FragmentVariances[Block-1] > Thresh4 ) || + (col + 1 < BlocksAcross && + pbi->FragmentVariances[Block+1] > Thresh4 ) || + (row + 1 < BlocksDown && + pbi->FragmentVariances[Block+BlocksAcross] > Thresh4) || + (row > 0 && + pbi->FragmentVariances[Block-BlocksAcross] > Thresh4) ){ + + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + } + } else if(Variance > Thresh2 ) { + + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + } else if(Variance > Thresh1 ) { + + DeringBlockWeak(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + + } else { + + CopyBlock(SrcPtr + 8 * col, DestPtr + 8 * col, LineLength); + + } + + ++Block; + + } + SrcPtr += 8 * LineLength; + DestPtr += 8 * LineLength; + } + + /* Then U */ + + BlocksAcross /= 2; + BlocksDown /= 2; + LineLength /= 2; + + SrcPtr = Src + pbi->ReconUDataOffset; + DestPtr = Dst + pbi->ReconUDataOffset; + for ( row = 0 ; row < BlocksDown; row ++) { + for (col = 0; col < BlocksAcross; col ++) { + ogg_uint32_t Quality = pbi->FragQIndex[Block]; + ogg_int32_t Variance = pbi->FragmentVariances[Block]; + + if( pbi->PostProcessingLevel >5 && Variance > Thresh4 ) { + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + + }else if(Variance > Thresh2 ){ + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + }else if(Variance > Thresh1 ){ + DeringBlockWeak(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + }else{ + CopyBlock(SrcPtr + 8 * col, DestPtr + 8 * col, LineLength); + } + + ++Block; + + } + SrcPtr += 8 * LineLength; + DestPtr += 8 * LineLength; + } + + /* Then V */ + SrcPtr = Src + pbi->ReconVDataOffset; + DestPtr = Dst + pbi->ReconVDataOffset; + + for ( row = 0 ; row < BlocksDown; row ++){ + for (col = 0; col < BlocksAcross; col ++){ + + ogg_uint32_t Quality = pbi->FragQIndex[Block]; + ogg_int32_t Variance = pbi->FragmentVariances[Block]; + + + if( pbi->PostProcessingLevel >5 && Variance > Thresh4 ) { + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + + }else if(Variance > Thresh2 ){ + DeringBlockStrong(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + }else if(Variance > Thresh1 ){ + DeringBlockWeak(SrcPtr + 8 * col, DestPtr + 8 * col, + LineLength,Quality,QuantScale); + }else{ + CopyBlock(SrcPtr + 8 * col, DestPtr + 8 * col, LineLength); + } + + ++Block; + + } + SrcPtr += 8 * LineLength; + DestPtr += 8 * LineLength; + + } + +} + +void UpdateFragQIndex(PB_INSTANCE *pbi){ + + ogg_uint32_t ThisFrameQIndex; + ogg_uint32_t i; + + /* Check this frame quality index */ + ThisFrameQIndex = pbi->FrameQIndex; + + + /* It is not a key frame, so only reset those are coded */ + for( i = 0; i < pbi->UnitFragments; i++ ) + if( pbi->display_fragments[i]) + pbi->FragQIndex[i] = ThisFrameQIndex; + +} + +static void DeblockLoopFilteredBand(PB_INSTANCE *pbi, + unsigned char *SrcPtr, + unsigned char *DesPtr, + ogg_uint32_t PlaneLineStep, + ogg_uint32_t FragsAcross, + ogg_uint32_t StartFrag, + ogg_uint32_t *QuantScale){ + ogg_uint32_t j,k; + ogg_uint32_t CurrentFrag=StartFrag; + ogg_int32_t QStep; + ogg_int32_t FLimit; + unsigned char *Src, *Des; + ogg_int32_t x[10]; + ogg_int32_t Sum1, Sum2; + + while(CurrentFrag < StartFrag + FragsAcross){ + + Src=SrcPtr+8*(CurrentFrag-StartFrag)-PlaneLineStep*5; + Des=DesPtr+8*(CurrentFrag-StartFrag)-PlaneLineStep*4; + + QStep = QuantScale[pbi->FragQIndex[CurrentFrag+FragsAcross]]; + FLimit = ( QStep * 3 ) >> 2; + + for( j=0; j<8 ; j++){ + x[0] = Src[0]; + x[1] = Src[PlaneLineStep]; + x[2] = Src[PlaneLineStep*2]; + x[3] = Src[PlaneLineStep*3]; + x[4] = Src[PlaneLineStep*4]; + x[5] = Src[PlaneLineStep*5]; + x[6] = Src[PlaneLineStep*6]; + x[7] = Src[PlaneLineStep*7]; + x[8] = Src[PlaneLineStep*8]; + x[9] = Src[PlaneLineStep*9]; + + Sum1=Sum2=0; + + for(k=1;k<=4;k++){ + Sum1 += abs(x[k]-x[k-1]); + Sum2 += abs(x[k+4]-x[k+5]); + } + + pbi->FragmentVariances[CurrentFrag] +=((Sum1>255)?255:Sum1); + pbi->FragmentVariances[CurrentFrag + FragsAcross] += ((Sum2>255)?255:Sum2); + + if( Sum1 < FLimit && + Sum2 < FLimit && + (x[5] - x[4]) < QStep && + (x[4] - x[5]) < QStep ){ + + /* low pass filtering (LPF7: 1 1 1 2 1 1 1) */ + Des[0 ] = (x[0] + x[0] +x[0] + x[1] * 2 + + x[2] + x[3] +x[4] + 4) >> 3; + Des[PlaneLineStep ] = (x[0] + x[0] +x[1] + x[2] * 2 + + x[3] + x[4] +x[5] + 4) >> 3; + Des[PlaneLineStep*2] = (x[0] + x[1] +x[2] + x[3] * 2 + + x[4] + x[5] +x[6] + 4) >> 3; + Des[PlaneLineStep*3] = (x[1] + x[2] +x[3] + x[4] * 2 + + x[5] + x[6] +x[7] + 4) >> 3; + Des[PlaneLineStep*4] = (x[2] + x[3] +x[4] + x[5] * 2 + + x[6] + x[7] +x[8] + 4) >> 3; + Des[PlaneLineStep*5] = (x[3] + x[4] +x[5] + x[6] * 2 + + x[7] + x[8] +x[9] + 4) >> 3; + Des[PlaneLineStep*6] = (x[4] + x[5] +x[6] + x[7] * 2 + + x[8] + x[9] +x[9] + 4) >> 3; + Des[PlaneLineStep*7] = (x[5] + x[6] +x[7] + x[8] * 2 + + x[9] + x[9] +x[9] + 4) >> 3; + + }else { + /* copy the pixels to destination */ + Des[0 ]= (unsigned char)x[1]; + Des[PlaneLineStep ]= (unsigned char)x[2]; + Des[PlaneLineStep*2]= (unsigned char)x[3]; + Des[PlaneLineStep*3]= (unsigned char)x[4]; + Des[PlaneLineStep*4]= (unsigned char)x[5]; + Des[PlaneLineStep*5]= (unsigned char)x[6]; + Des[PlaneLineStep*6]= (unsigned char)x[7]; + Des[PlaneLineStep*7]= (unsigned char)x[8]; + } + Src ++; + Des ++; + } + + + /* done with filtering the horizontal edge, now let's do the + vertical one */ + /* skip the first one */ + if(CurrentFrag==StartFrag) + CurrentFrag++; + else{ + Des=DesPtr-8*PlaneLineStep+8*(CurrentFrag-StartFrag); + Src=Des-5; + Des-=4; + + QStep = QuantScale[pbi->FragQIndex[CurrentFrag]]; + FLimit = ( QStep * 3 ) >> 2; + + for( j=0; j<8 ; j++){ + x[0] = Src[0]; + x[1] = Src[1]; + x[2] = Src[2]; + x[3] = Src[3]; + x[4] = Src[4]; + x[5] = Src[5]; + x[6] = Src[6]; + x[7] = Src[7]; + x[8] = Src[8]; + x[9] = Src[9]; + + Sum1=Sum2=0; + + for(k=1;k<=4;k++){ + Sum1 += abs(x[k]-x[k-1]); + Sum2 += abs(x[k+4]-x[k+5]); + } + + pbi->FragmentVariances[CurrentFrag-1] += ((Sum1>255)?255:Sum1); + pbi->FragmentVariances[CurrentFrag] += ((Sum2>255)?255:Sum2); + + if( Sum1 < FLimit && + Sum2 < FLimit && + (x[5] - x[4]) < QStep && + (x[4] - x[5]) < QStep ){ + + /* low pass filtering (LPF7: 1 1 1 2 1 1 1) */ + Des[0] = (x[0] + x[0] +x[0] + x[1] * 2 + x[2] + x[3] +x[4] + 4) >> 3; + Des[1] = (x[0] + x[0] +x[1] + x[2] * 2 + x[3] + x[4] +x[5] + 4) >> 3; + Des[2] = (x[0] + x[1] +x[2] + x[3] * 2 + x[4] + x[5] +x[6] + 4) >> 3; + Des[3] = (x[1] + x[2] +x[3] + x[4] * 2 + x[5] + x[6] +x[7] + 4) >> 3; + Des[4] = (x[2] + x[3] +x[4] + x[5] * 2 + x[6] + x[7] +x[8] + 4) >> 3; + Des[5] = (x[3] + x[4] +x[5] + x[6] * 2 + x[7] + x[8] +x[9] + 4) >> 3; + Des[6] = (x[4] + x[5] +x[6] + x[7] * 2 + x[8] + x[9] +x[9] + 4) >> 3; + Des[7] = (x[5] + x[6] +x[7] + x[8] * 2 + x[9] + x[9] +x[9] + 4) >> 3; + } + + Src += PlaneLineStep; + Des += PlaneLineStep; + } + CurrentFrag ++; + } + } +} + +static void DeblockVerticalEdgesInLoopFilteredBand(PB_INSTANCE *pbi, + unsigned char *SrcPtr, + unsigned char *DesPtr, + ogg_uint32_t PlaneLineStep, + ogg_uint32_t FragsAcross, + ogg_uint32_t StartFrag, + ogg_uint32_t *QuantScale){ + ogg_uint32_t j,k; + ogg_uint32_t CurrentFrag=StartFrag; + ogg_int32_t QStep; + ogg_int32_t FLimit; + unsigned char *Src, *Des; + ogg_int32_t x[10]; + ogg_int32_t Sum1, Sum2; + + while(CurrentFrag < StartFrag + FragsAcross-1) { + + Src=SrcPtr+8*(CurrentFrag-StartFrag+1)-5; + Des=DesPtr+8*(CurrentFrag-StartFrag+1)-4; + + QStep = QuantScale[pbi->FragQIndex[CurrentFrag+1]]; + FLimit = ( QStep * 3)>>2 ; + + for( j=0; j<8 ; j++){ + x[0] = Src[0]; + x[1] = Src[1]; + x[2] = Src[2]; + x[3] = Src[3]; + x[4] = Src[4]; + x[5] = Src[5]; + x[6] = Src[6]; + x[7] = Src[7]; + x[8] = Src[8]; + x[9] = Src[9]; + + Sum1=Sum2=0; + + for(k=1;k<=4;k++){ + Sum1 += abs(x[k]-x[k-1]); + Sum2 += abs(x[k+4]-x[k+5]); + } + + pbi->FragmentVariances[CurrentFrag] += ((Sum1>255)?255:Sum1); + pbi->FragmentVariances[CurrentFrag+1] += ((Sum2>255)?255:Sum2); + + + if( Sum1 < FLimit && + Sum2 < FLimit && + (x[5] - x[4]) < QStep && + (x[4] - x[5]) < QStep ){ + + /* low pass filtering (LPF7: 1 1 1 2 1 1 1) */ + Des[0] = (x[0] + x[0] +x[0] + x[1] * 2 + x[2] + x[3] +x[4] + 4) >> 3; + Des[1] = (x[0] + x[0] +x[1] + x[2] * 2 + x[3] + x[4] +x[5] + 4) >> 3; + Des[2] = (x[0] + x[1] +x[2] + x[3] * 2 + x[4] + x[5] +x[6] + 4) >> 3; + Des[3] = (x[1] + x[2] +x[3] + x[4] * 2 + x[5] + x[6] +x[7] + 4) >> 3; + Des[4] = (x[2] + x[3] +x[4] + x[5] * 2 + x[6] + x[7] +x[8] + 4) >> 3; + Des[5] = (x[3] + x[4] +x[5] + x[6] * 2 + x[7] + x[8] +x[9] + 4) >> 3; + Des[6] = (x[4] + x[5] +x[6] + x[7] * 2 + x[8] + x[9] +x[9] + 4) >> 3; + Des[7] = (x[5] + x[6] +x[7] + x[8] * 2 + x[9] + x[9] +x[9] + 4) >> 3; + } + Src +=PlaneLineStep; + Des +=PlaneLineStep; + + } + CurrentFrag ++; + } +} + +static void DeblockPlane(PB_INSTANCE *pbi, + unsigned char *SourceBuffer, + unsigned char *DestinationBuffer, + ogg_uint32_t Channel ){ + + ogg_uint32_t i,k; + ogg_uint32_t PlaneLineStep=0; + ogg_uint32_t StartFrag =0; + ogg_uint32_t PixelIndex=0; + unsigned char * SrcPtr=0, * DesPtr=0; + ogg_uint32_t FragsAcross=0; + ogg_uint32_t FragsDown=0; + ogg_uint32_t *QuantScale=0; + + switch( Channel ){ + case 0: + /* Get the parameters */ + PlaneLineStep = pbi->YStride; + FragsAcross = pbi->HFragments; + FragsDown = pbi->VFragments; + StartFrag = 0; + PixelIndex = pbi->ReconYDataOffset; + SrcPtr = & SourceBuffer[PixelIndex]; + DesPtr = & DestinationBuffer[PixelIndex]; + break; + + case 1: + /* Get the parameters */ + PlaneLineStep = pbi->UVStride; + FragsAcross = pbi->HFragments / 2; + FragsDown = pbi->VFragments / 2; + StartFrag = pbi->YPlaneFragments; + + PixelIndex = pbi->ReconUDataOffset; + SrcPtr = & SourceBuffer[PixelIndex]; + DesPtr = & DestinationBuffer[PixelIndex]; + break; + + default: + /* Get the parameters */ + PlaneLineStep = pbi->UVStride; + FragsAcross = pbi->HFragments / 2; + FragsDown = pbi->VFragments / 2; + StartFrag = pbi->YPlaneFragments + pbi->UVPlaneFragments; + + PixelIndex = pbi->ReconVDataOffset; + SrcPtr = & SourceBuffer[PixelIndex]; + DesPtr = & DestinationBuffer[PixelIndex]; + break; + } + + QuantScale = DcQuantScaleV1; + + for(i=0;i<4;i++) + memcpy(DesPtr+i*PlaneLineStep, SrcPtr+i*PlaneLineStep, PlaneLineStep); + + k = 1; + + while( k < FragsDown ){ + + SrcPtr += 8*PlaneLineStep; + DesPtr += 8*PlaneLineStep; + + /* Filter both the horizontal and vertical block edges inside the band */ + DeblockLoopFilteredBand(pbi, SrcPtr, DesPtr, PlaneLineStep, + FragsAcross, StartFrag, QuantScale); + + /* Move Pointers */ + StartFrag += FragsAcross; + + k ++; + } + + /* The Last band */ + for(i=0;i<4;i++) + memcpy(DesPtr+(i+4)*PlaneLineStep, + SrcPtr+(i+4)*PlaneLineStep, + PlaneLineStep); + + DeblockVerticalEdgesInLoopFilteredBand(pbi,SrcPtr,DesPtr,PlaneLineStep, + FragsAcross,StartFrag,QuantScale); + +} + +static void DeblockFrame(PB_INSTANCE *pbi, unsigned char *SourceBuffer, + unsigned char *DestinationBuffer){ + + memset(pbi->FragmentVariances, 0 , sizeof(ogg_int32_t) * pbi->UnitFragments); + + + UpdateFragQIndex(pbi); + + + SetupLoopFilter(pbi); + + /* Y */ + DeblockPlane( pbi, SourceBuffer, DestinationBuffer, 0); + + /* U */ + DeblockPlane( pbi, SourceBuffer, DestinationBuffer, 1); + + /* V */ + DeblockPlane( pbi, SourceBuffer, DestinationBuffer, 2); + +} + +void PostProcess(PB_INSTANCE *pbi){ + + switch (pbi->PostProcessingLevel){ + case 8: + /* on a slow machine, use a simpler and faster deblocking filter */ + DeblockFrame(pbi, pbi->LastFrameRecon,pbi->PostProcessBuffer); + break; + + case 6: + DeblockFrame(pbi, pbi->LastFrameRecon,pbi->PostProcessBuffer); + UpdateUMVBorder(pbi, pbi->PostProcessBuffer ); + DeringFrame(pbi, pbi->PostProcessBuffer, pbi->PostProcessBuffer); + break; + + case 5: + DeblockFrame(pbi, pbi->LastFrameRecon,pbi->PostProcessBuffer); + UpdateUMVBorder(pbi, pbi->PostProcessBuffer ); + DeringFrame(pbi, pbi->PostProcessBuffer, pbi->PostProcessBuffer); + break; + case 4: + DeblockFrame(pbi, pbi->LastFrameRecon, pbi->PostProcessBuffer); + break; + case 1: + UpdateFragQIndex(pbi); + break; + + case 0: + break; + + default: + DeblockFrame(pbi, pbi->LastFrameRecon, pbi->PostProcessBuffer); + UpdateUMVBorder(pbi, pbi->PostProcessBuffer ); + DeringFrame(pbi, pbi->PostProcessBuffer, pbi->PostProcessBuffer); + break; + } +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/pp.h b/src/add-ons/media/plugins/theora/libtheora/pp.h new file mode 100644 index 0000000000..752010d974 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/pp.h @@ -0,0 +1,48 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: pp.h,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +/* Constants. */ +#define INTERNAL_BLOCK_HEIGHT 8 +#define INTERNAL_BLOCK_WIDTH 8 + + +/* NEW Line search values. */ +#define UP 0 +#define DOWN 1 +#define LEFT 2 +#define RIGHT 3 + +#define FIRST_ROW 0 +#define NOT_EDGE_ROW 1 +#define LAST_ROW 2 + +#define YDIFF_CB_ROWS (INTERNAL_BLOCK_HEIGHT * 3) +#define CHLOCALS_CB_ROWS (INTERNAL_BLOCK_HEIGHT * 3) +#define PMAP_CB_ROWS (INTERNAL_BLOCK_HEIGHT * 3) +#define PSCORE_CB_ROWS (INTERNAL_BLOCK_HEIGHT * 4) + +/* Status values in block coding map */ +#define CANDIDATE_BLOCK_LOW -2 +#define CANDIDATE_BLOCK -1 +#define BLOCK_NOT_CODED 0 +#define BLOCK_CODED_BAR 3 +#define BLOCK_CODED_SGC 4 +#define BLOCK_CODED_LOW 4 +#define BLOCK_CODED 5 + +#define MAX_PREV_FRAMES 16 +#define MAX_SEARCH_LINE_LEN 7 diff --git a/src/add-ons/media/plugins/theora/libtheora/quant.c b/src/add-ons/media/plugins/theora/libtheora/quant.c new file mode 100644 index 0000000000..68ec2435f1 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/quant.c @@ -0,0 +1,693 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: quant.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include "encoder_internal.h" +#include "quant_lookup.h" + +static ogg_uint32_t QThreshTableV1[Q_TABLE_SIZE] = { + 500, 450, 400, 370, 340, 310, 285, 265, + 245, 225, 210, 195, 185, 180, 170, 160, + 150, 145, 135, 130, 125, 115, 110, 107, + 100, 96, 93, 89, 85, 82, 75, 74, + 70, 68, 64, 60, 57, 56, 52, 50, + 49, 45, 44, 43, 40, 38, 37, 35, + 33, 32, 30, 29, 28, 25, 24, 22, + 21, 19, 18, 17, 15, 13, 12, 10 +}; + +static Q_LIST_ENTRY DcScaleFactorTableV1[ Q_TABLE_SIZE ] = { + 220, 200, 190, 180, 170, 170, 160, 160, + 150, 150, 140, 140, 130, 130, 120, 120, + 110, 110, 100, 100, 90, 90, 90, 80, + 80, 80, 70, 70, 70, 60, 60, 60, + 60, 50, 50, 50, 50, 40, 40, 40, + 40, 40, 30, 30, 30, 30, 30, 30, + 30, 20, 20, 20, 20, 20, 20, 20, + 20, 10, 10, 10, 10, 10, 10, 10 +}; + +/* dbm -- defined some alternative tables to test header packing */ +#define NEW_QTABLES 0 +#if NEW_QTABLES + +static Q_LIST_ENTRY Y_coeffsV1[64] = +{ + 8, 16, 16, 16, 20, 20, 20, 20, + 16, 16, 16, 16, 20, 20, 20, 20, + 16, 16, 16, 16, 22, 22, 22, 22, + 16, 16, 16, 16, 22, 22, 22, 22, + 20, 20, 22, 22, 24, 24, 24, 24, + 20, 20, 22, 22, 24, 24, 24, 24, + 20, 20, 22, 22, 24, 24, 24, 24, + 20, 20, 22, 22, 24, 24, 24, 24 +}; + +static Q_LIST_ENTRY UV_coeffsV1[64] = +{ 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + +/* Different matrices for different encoder versions */ +static Q_LIST_ENTRY Inter_coeffsV1[64] = +{ + 12, 16, 16, 16, 20, 20, 20, 20, + 16, 16, 16, 16, 20, 20, 20, 20, + 16, 16, 16, 16, 22, 22, 22, 22, + 16, 16, 16, 16, 22, 22, 22, 22, + 20, 20, 22, 22, 24, 24, 24, 24, + 20, 20, 22, 22, 24, 24, 24, 24, + 20, 20, 22, 22, 24, 24, 24, 24, + 20, 20, 22, 22, 24, 24, 24, 24 +}; + +#else /* these are the old VP3 values: */ + +static Q_LIST_ENTRY Y_coeffsV1[64] ={ + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 58, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; + +static Q_LIST_ENTRY UV_coeffsV1[64] ={ + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + +/* Different matrices for different encoder versions */ +static Q_LIST_ENTRY Inter_coeffsV1[64] ={ + 16, 16, 16, 20, 24, 28, 32, 40, + 16, 16, 20, 24, 28, 32, 40, 48, + 16, 20, 24, 28, 32, 40, 48, 64, + 20, 24, 28, 32, 40, 48, 64, 64, + 24, 28, 32, 40, 48, 64, 64, 64, + 28, 32, 40, 48, 64, 64, 64, 96, + 32, 40, 48, 64, 64, 64, 96, 128, + 40, 48, 64, 64, 64, 96, 128, 128 +}; + +#endif + +void WriteQTables(PB_INSTANCE *pbi,oggpack_buffer* opb) { + int x; + for(x=0; x<64; x++) { + oggpackB_write(opb, pbi->QThreshTable[x],16); + } + for(x=0; x<64; x++) { + oggpackB_write(opb, pbi->DcScaleFactorTable[x],16); + } + for(x=0; x<64; x++) { + oggpackB_write(opb, pbi->Y_coeffs[x],8); + } + for(x=0; x<64; x++) { + oggpackB_write(opb, pbi->UV_coeffs[x],8); + } + for(x=0; x<64; x++) { + oggpackB_write(opb, pbi->Inter_coeffs[x],8); + } +} + +int ReadQTables(codec_setup_info *ci, oggpack_buffer* opb) { + long bits; + int x; + for(x=0; xQThreshTable[x]=bits; + } + for(x=0; xDcScaleFactorTable[x]=(Q_LIST_ENTRY)bits; + } + for(x=0; x<64; x++) { + theora_read(opb,8,&bits); + if(bits<0)return OC_BADHEADER; + ci->Y_coeffs[x]=(Q_LIST_ENTRY)bits; + } + for(x=0; x<64; x++) { + theora_read(opb,8,&bits); + if(bits<0)return OC_BADHEADER; + ci->UV_coeffs[x]=(Q_LIST_ENTRY)bits; + } + for(x=0; x<64; x++) { + theora_read(opb,8,&bits); + if(bits<0)return OC_BADHEADER; + ci->Inter_coeffs[x]=(Q_LIST_ENTRY)bits; + } + return 0; +} + +void CopyQTables(PB_INSTANCE *pbi, codec_setup_info *ci) { + memcpy(pbi->QThreshTable, ci->QThreshTable, sizeof(pbi->QThreshTable)); + memcpy(pbi->DcScaleFactorTable, ci->DcScaleFactorTable, + sizeof(pbi->DcScaleFactorTable)); + memcpy(pbi->Y_coeffs, ci->Y_coeffs, sizeof(pbi->Y_coeffs)); + memcpy(pbi->UV_coeffs, ci->UV_coeffs, sizeof(pbi->UV_coeffs)); + memcpy(pbi->Inter_coeffs, ci->Inter_coeffs, sizeof(pbi->Inter_coeffs)); +} + +/* Initialize custom qtables using the VP31 values. + Someday we can change the quant tables to be adaptive, or just plain + better.*/ +void InitQTables( PB_INSTANCE *pbi ){ + memcpy(pbi->QThreshTable, QThreshTableV1, sizeof(pbi->QThreshTable)); + memcpy(pbi->DcScaleFactorTable, DcScaleFactorTableV1, + sizeof(pbi->DcScaleFactorTable)); + memcpy(pbi->Y_coeffs, Y_coeffsV1, sizeof(pbi->Y_coeffs)); + memcpy(pbi->UV_coeffs, UV_coeffsV1, sizeof(pbi->UV_coeffs)); + memcpy(pbi->Inter_coeffs, Inter_coeffsV1, sizeof(pbi->Inter_coeffs)); +} + +static void BuildQuantIndex_Generic(PB_INSTANCE *pbi){ + ogg_int32_t i,j; + + /* invert the dequant index into the quant index */ + for ( i = 0; i < BLOCK_SIZE; i++ ){ + j = dequant_index[i]; + pbi->quant_index[j] = i; + } +} + +static void init_quantizer ( CP_INSTANCE *cpi, + ogg_uint32_t scale_factor, + unsigned char QIndex ){ + int i; + double ZBinFactor; + double RoundingFactor; + + double temp_fp_quant_coeffs; + double temp_fp_quant_round; + double temp_fp_ZeroBinSize; + PB_INSTANCE *pbi = &cpi->pb; + + Q_LIST_ENTRY * Inter_coeffs; + Q_LIST_ENTRY * Y_coeffs; + Q_LIST_ENTRY * UV_coeffs; + Q_LIST_ENTRY * DcScaleFactorTable; + Q_LIST_ENTRY * UVDcScaleFactorTable; + + /* Notes on setup of quantisers. The initial multiplication by + the scale factor is done in the ogg_int32_t domain to insure that the + precision in the quantiser is the same as in the inverse + quantiser where all calculations are integer. The "<< 2" is a + normalisation factor for the forward DCT transform. */ + + /* New version rounding and ZB characteristics. */ + Inter_coeffs = Inter_coeffsV1; + Y_coeffs = Y_coeffsV1; + UV_coeffs = UV_coeffsV1; + DcScaleFactorTable = DcScaleFactorTableV1; + UVDcScaleFactorTable = DcScaleFactorTableV1; + ZBinFactor = 0.9; + + switch(cpi->pb.info.sharpness){ + case 0: + ZBinFactor = 0.65; + if ( scale_factor <= 50 ) + RoundingFactor = 0.499; + else + RoundingFactor = 0.46; + break; + case 1: + ZBinFactor = 0.75; + if ( scale_factor <= 50 ) + RoundingFactor = 0.476; + else + RoundingFactor = 0.400; + break; + + default: + ZBinFactor = 0.9; + if ( scale_factor <= 50 ) + RoundingFactor = 0.476; + else + RoundingFactor = 0.333; + break; + } + + /* Use fixed multiplier for intra Y DC */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(DcScaleFactorTable[QIndex] * Y_coeffs[0])/100) << 2); + if ( temp_fp_quant_coeffs < MIN_LEGAL_QUANT_ENTRY * 2 ) + temp_fp_quant_coeffs = MIN_LEGAL_QUANT_ENTRY * 2; + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_Y_round[0] = (ogg_int32_t) (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_Y[0] = (ogg_int32_t) (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs = 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_Y_coeffs[0] = (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + /* Intra UV */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(UVDcScaleFactorTable[QIndex] * UV_coeffs[0])/100) << 2); + if ( temp_fp_quant_coeffs < MIN_LEGAL_QUANT_ENTRY * 2) + temp_fp_quant_coeffs = MIN_LEGAL_QUANT_ENTRY * 2; + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_UV_round[0] = (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_UV[0] = (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs = 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_UV_coeffs[0]= (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + /* Inter Y */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(DcScaleFactorTable[QIndex] * Inter_coeffs[0])/100) << 2); + if ( temp_fp_quant_coeffs < MIN_LEGAL_QUANT_ENTRY * 4) + temp_fp_quant_coeffs = MIN_LEGAL_QUANT_ENTRY * 4; + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_Inter_round[0]= (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_Inter[0]= (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs= 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_Inter_coeffs[0]= (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + /* Inter UV */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(UVDcScaleFactorTable[QIndex] * Inter_coeffs[0])/100) << 2); + if ( temp_fp_quant_coeffs < MIN_LEGAL_QUANT_ENTRY * 4) + temp_fp_quant_coeffs = MIN_LEGAL_QUANT_ENTRY * 4; + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_InterUV_round[0]= (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_InterUV[0]= (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs= 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_InterUV_coeffs[0]= + (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + for ( i = 1; i < 64; i++ ){ + /* now scale coefficients by required compression factor */ + /* Intra Y */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(scale_factor * Y_coeffs[i]) / 100 ) << 2 ); + if ( temp_fp_quant_coeffs < (MIN_LEGAL_QUANT_ENTRY) ) + temp_fp_quant_coeffs = (MIN_LEGAL_QUANT_ENTRY); + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_Y_round[i] = (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_Y[i] = (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs = 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_Y_coeffs[i] = (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + /* Intra UV */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(scale_factor * UV_coeffs[i]) / 100 ) << 2 ); + if ( temp_fp_quant_coeffs < (MIN_LEGAL_QUANT_ENTRY)) + temp_fp_quant_coeffs = (MIN_LEGAL_QUANT_ENTRY); + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_UV_round[i] = (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_UV[i] = (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs = 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_UV_coeffs[i]= (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + /* Inter Y */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(scale_factor * Inter_coeffs[i]) / 100 ) << 2 ); + if ( temp_fp_quant_coeffs < (MIN_LEGAL_QUANT_ENTRY * 2) ) + temp_fp_quant_coeffs = (MIN_LEGAL_QUANT_ENTRY * 2); + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_Inter_round[i]= (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_Inter[i]= (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs = 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_Inter_coeffs[i]= (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + /* Inter UV */ + temp_fp_quant_coeffs = + (((ogg_uint32_t)(scale_factor * Inter_coeffs[i]) / 100 ) << 2 ); + if ( temp_fp_quant_coeffs < (MIN_LEGAL_QUANT_ENTRY * 2) ) + temp_fp_quant_coeffs = (MIN_LEGAL_QUANT_ENTRY * 2); + + temp_fp_quant_round = temp_fp_quant_coeffs * RoundingFactor; + pbi->fp_quant_InterUV_round[i]= (0.5 + temp_fp_quant_round); + + temp_fp_ZeroBinSize = temp_fp_quant_coeffs * ZBinFactor; + pbi->fp_ZeroBinSize_InterUV[i]= (0.5 + temp_fp_ZeroBinSize); + + temp_fp_quant_coeffs = 1.0 / temp_fp_quant_coeffs; + pbi->fp_quant_InterUV_coeffs[i]= (0.5 + SHIFT16 * temp_fp_quant_coeffs); + + } + + pbi->fquant_coeffs = pbi->fp_quant_Y_coeffs; + +} + +void select_Y_quantiser ( PB_INSTANCE *pbi ){ + pbi->fquant_coeffs = pbi->fp_quant_Y_coeffs; + pbi->fquant_round = pbi->fp_quant_Y_round; + pbi->fquant_ZbSize = pbi->fp_ZeroBinSize_Y; +} + +void select_Inter_quantiser ( PB_INSTANCE *pbi ){ + pbi->fquant_coeffs = pbi->fp_quant_Inter_coeffs; + pbi->fquant_round = pbi->fp_quant_Inter_round; + pbi->fquant_ZbSize = pbi->fp_ZeroBinSize_Inter; +} + +void select_UV_quantiser ( PB_INSTANCE *pbi ){ + pbi->fquant_coeffs = pbi->fp_quant_UV_coeffs; + pbi->fquant_round = pbi->fp_quant_UV_round; + pbi->fquant_ZbSize = pbi->fp_quant_UV_round; +} + +void select_InterUV_quantiser ( PB_INSTANCE *pbi ){ + pbi->fquant_coeffs = pbi->fp_quant_InterUV_coeffs; + pbi->fquant_round = pbi->fp_quant_InterUV_round; + pbi->fquant_ZbSize = pbi->fp_ZeroBinSize_InterUV; +} + +void quantize( PB_INSTANCE *pbi, + ogg_int16_t * DCT_block, + Q_LIST_ENTRY * quantized_list){ + ogg_uint32_t i; /* Row index */ + Q_LIST_ENTRY val; /* Quantised value. */ + + ogg_int32_t * FquantRoundPtr = pbi->fquant_round; + ogg_int32_t * FquantCoeffsPtr = pbi->fquant_coeffs; + ogg_int32_t * FquantZBinSizePtr = pbi->fquant_ZbSize; + ogg_int16_t * DCT_blockPtr = DCT_block; + ogg_uint32_t * QIndexPtr = (ogg_uint32_t *)pbi->quant_index; + ogg_int32_t temp; + + /* Set the quantized_list to default to 0 */ + memset( quantized_list, 0, 64 * sizeof(Q_LIST_ENTRY) ); + + /* Note that we add half divisor to effect rounding on positive number */ + for( i = 0; i < VFRAGPIXELS; i++) { + /* Column 0 */ + if ( DCT_blockPtr[0] >= FquantZBinSizePtr[0] ) { + temp = FquantCoeffsPtr[0] * ( DCT_blockPtr[0] + FquantRoundPtr[0] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[0]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[0] <= -FquantZBinSizePtr[0] ) { + temp = FquantCoeffsPtr[0] * + ( DCT_blockPtr[0] - FquantRoundPtr[0] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[0]] = ( val < -511 ) ? -511 : val; + } + + /* Column 1 */ + if ( DCT_blockPtr[1] >= FquantZBinSizePtr[1] ) { + temp = FquantCoeffsPtr[1] * + ( DCT_blockPtr[1] + FquantRoundPtr[1] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[1]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[1] <= -FquantZBinSizePtr[1] ) { + temp = FquantCoeffsPtr[1] * + ( DCT_blockPtr[1] - FquantRoundPtr[1] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[1]] = ( val < -511 ) ? -511 : val; + } + + /* Column 2 */ + if ( DCT_blockPtr[2] >= FquantZBinSizePtr[2] ) { + temp = FquantCoeffsPtr[2] * + ( DCT_blockPtr[2] + FquantRoundPtr[2] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[2]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[2] <= -FquantZBinSizePtr[2] ) { + temp = FquantCoeffsPtr[2] * + ( DCT_blockPtr[2] - FquantRoundPtr[2] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[2]] = ( val < -511 ) ? -511 : val; + } + + /* Column 3 */ + if ( DCT_blockPtr[3] >= FquantZBinSizePtr[3] ) { + temp = FquantCoeffsPtr[3] * + ( DCT_blockPtr[3] + FquantRoundPtr[3] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[3]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[3] <= -FquantZBinSizePtr[3] ) { + temp = FquantCoeffsPtr[3] * + ( DCT_blockPtr[3] - FquantRoundPtr[3] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[3]] = ( val < -511 ) ? -511 : val; + } + + /* Column 4 */ + if ( DCT_blockPtr[4] >= FquantZBinSizePtr[4] ) { + temp = FquantCoeffsPtr[4] * + ( DCT_blockPtr[4] + FquantRoundPtr[4] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[4]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[4] <= -FquantZBinSizePtr[4] ) { + temp = FquantCoeffsPtr[4] * + ( DCT_blockPtr[4] - FquantRoundPtr[4] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[4]] = ( val < -511 ) ? -511 : val; + } + + /* Column 5 */ + if ( DCT_blockPtr[5] >= FquantZBinSizePtr[5] ) { + temp = FquantCoeffsPtr[5] * + ( DCT_blockPtr[5] + FquantRoundPtr[5] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[5]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[5] <= -FquantZBinSizePtr[5] ) { + temp = FquantCoeffsPtr[5] * + ( DCT_blockPtr[5] - FquantRoundPtr[5] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[5]] = ( val < -511 ) ? -511 : val; + } + + /* Column 6 */ + if ( DCT_blockPtr[6] >= FquantZBinSizePtr[6] ) { + temp = FquantCoeffsPtr[6] * + ( DCT_blockPtr[6] + FquantRoundPtr[6] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[6]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[6] <= -FquantZBinSizePtr[6] ) { + temp = FquantCoeffsPtr[6] * + ( DCT_blockPtr[6] - FquantRoundPtr[6] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[6]] = ( val < -511 ) ? -511 : val; + } + + /* Column 7 */ + if ( DCT_blockPtr[7] >= FquantZBinSizePtr[7] ) { + temp = FquantCoeffsPtr[7] * + ( DCT_blockPtr[7] + FquantRoundPtr[7] ) ; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[7]] = ( val > 511 ) ? 511 : val; + } else if ( DCT_blockPtr[7] <= -FquantZBinSizePtr[7] ) { + temp = FquantCoeffsPtr[7] * + ( DCT_blockPtr[7] - FquantRoundPtr[7] ) + MIN16; + val = (Q_LIST_ENTRY) (temp>>16); + quantized_list[QIndexPtr[7]] = ( val < -511 ) ? -511 : val; + } + + FquantRoundPtr += 8; + FquantCoeffsPtr += 8; + FquantZBinSizePtr += 8; + DCT_blockPtr += 8; + QIndexPtr += 8; + } +} + +static void init_dequantizer ( PB_INSTANCE *pbi, + ogg_uint32_t scale_factor, + unsigned char QIndex ){ + int i, j; + + Q_LIST_ENTRY * Inter_coeffs; + Q_LIST_ENTRY * Y_coeffs; + Q_LIST_ENTRY * UV_coeffs; + Q_LIST_ENTRY * DcScaleFactorTable; + Q_LIST_ENTRY * UVDcScaleFactorTable; + + Inter_coeffs = pbi->Inter_coeffs; + Y_coeffs = pbi->Y_coeffs; + UV_coeffs = pbi->UV_coeffs; + DcScaleFactorTable = pbi->DcScaleFactorTable; + UVDcScaleFactorTable = pbi->DcScaleFactorTable; + + /* invert the dequant index into the quant index + the dxer has a different order than the cxer. */ + BuildQuantIndex_Generic(pbi); + + /* Reorder dequantisation coefficients into dct zigzag order. */ + for ( i = 0; i < BLOCK_SIZE; i++ ) { + j = pbi->quant_index[i]; + pbi->dequant_Y_coeffs[j] = Y_coeffs[i]; + } + for ( i = 0; i < BLOCK_SIZE; i++ ){ + j = pbi->quant_index[i]; + pbi->dequant_Inter_coeffs[j] = Inter_coeffs[i]; + } + for ( i = 0; i < BLOCK_SIZE; i++ ){ + j = pbi->quant_index[i]; + pbi->dequant_UV_coeffs[j] = UV_coeffs[i]; + } + for ( i = 0; i < BLOCK_SIZE; i++ ){ + j = pbi->quant_index[i]; + pbi->dequant_InterUV_coeffs[j] = Inter_coeffs[i]; + } + + /* Intra Y */ + pbi->dequant_Y_coeffs[0] = + ((DcScaleFactorTable[QIndex] * pbi->dequant_Y_coeffs[0])/100); + if ( pbi->dequant_Y_coeffs[0] < MIN_DEQUANT_VAL * 2 ) + pbi->dequant_Y_coeffs[0] = MIN_DEQUANT_VAL * 2; + pbi->dequant_Y_coeffs[0] = + pbi->dequant_Y_coeffs[0] << IDCT_SCALE_FACTOR; + + /* Intra UV */ + pbi->dequant_UV_coeffs[0] = + ((UVDcScaleFactorTable[QIndex] * pbi->dequant_UV_coeffs[0])/100); + if ( pbi->dequant_UV_coeffs[0] < MIN_DEQUANT_VAL * 2 ) + pbi->dequant_UV_coeffs[0] = MIN_DEQUANT_VAL * 2; + pbi->dequant_UV_coeffs[0] = + pbi->dequant_UV_coeffs[0] << IDCT_SCALE_FACTOR; + + /* Inter Y */ + pbi->dequant_Inter_coeffs[0] = + ((DcScaleFactorTable[QIndex] * pbi->dequant_Inter_coeffs[0])/100); + if ( pbi->dequant_Inter_coeffs[0] < MIN_DEQUANT_VAL * 4 ) + pbi->dequant_Inter_coeffs[0] = MIN_DEQUANT_VAL * 4; + pbi->dequant_Inter_coeffs[0] = + pbi->dequant_Inter_coeffs[0] << IDCT_SCALE_FACTOR; + + /* Inter UV */ + pbi->dequant_InterUV_coeffs[0] = + ((UVDcScaleFactorTable[QIndex] * pbi->dequant_InterUV_coeffs[0])/100); + if ( pbi->dequant_InterUV_coeffs[0] < MIN_DEQUANT_VAL * 4 ) + pbi->dequant_InterUV_coeffs[0] = MIN_DEQUANT_VAL * 4; + pbi->dequant_InterUV_coeffs[0] = + pbi->dequant_InterUV_coeffs[0] << IDCT_SCALE_FACTOR; + + for ( i = 1; i < 64; i++ ){ + /* now scale coefficients by required compression factor */ + pbi->dequant_Y_coeffs[i] = + (( scale_factor * pbi->dequant_Y_coeffs[i] ) / 100); + if ( pbi->dequant_Y_coeffs[i] < MIN_DEQUANT_VAL ) + pbi->dequant_Y_coeffs[i] = MIN_DEQUANT_VAL; + pbi->dequant_Y_coeffs[i] = + pbi->dequant_Y_coeffs[i] << IDCT_SCALE_FACTOR; + + pbi->dequant_UV_coeffs[i] = + (( scale_factor * pbi->dequant_UV_coeffs[i] ) / 100); + if ( pbi->dequant_UV_coeffs[i] < MIN_DEQUANT_VAL ) + pbi->dequant_UV_coeffs[i] = MIN_DEQUANT_VAL; + pbi->dequant_UV_coeffs[i] = + pbi->dequant_UV_coeffs[i] << IDCT_SCALE_FACTOR; + + pbi->dequant_Inter_coeffs[i] = + (( scale_factor * pbi->dequant_Inter_coeffs[i] ) / 100); + if ( pbi->dequant_Inter_coeffs[i] < (MIN_DEQUANT_VAL * 2) ) + pbi->dequant_Inter_coeffs[i] = MIN_DEQUANT_VAL * 2; + pbi->dequant_Inter_coeffs[i] = + pbi->dequant_Inter_coeffs[i] << IDCT_SCALE_FACTOR; + + pbi->dequant_InterUV_coeffs[i] = + (( scale_factor * pbi->dequant_InterUV_coeffs[i] ) / 100); + if ( pbi->dequant_InterUV_coeffs[i] < (MIN_DEQUANT_VAL * 2) ) + pbi->dequant_InterUV_coeffs[i] = MIN_DEQUANT_VAL * 2; + pbi->dequant_InterUV_coeffs[i] = + pbi->dequant_InterUV_coeffs[i] << IDCT_SCALE_FACTOR; + } + + pbi->dequant_coeffs = pbi->dequant_Y_coeffs; +} + +void UpdateQ( PB_INSTANCE *pbi, ogg_uint32_t NewQ ){ + ogg_uint32_t qscale; + + /* Do bounds checking and convert to a float. */ + qscale = NewQ; + if ( qscale < pbi->QThreshTable[Q_TABLE_SIZE-1] ) + qscale = pbi->QThreshTable[Q_TABLE_SIZE-1]; + else if ( qscale > pbi->QThreshTable[0] ) + qscale = pbi->QThreshTable[0]; + + /* Set the inter/intra descision control variables. */ + pbi->FrameQIndex = Q_TABLE_SIZE - 1; + while ( (ogg_int32_t) pbi->FrameQIndex >= 0 ) { + if ( (pbi->FrameQIndex == 0) || + ( pbi->QThreshTable[pbi->FrameQIndex] >= NewQ) ) + break; + pbi->FrameQIndex --; + } + + /* Re-initialise the q tables for forward and reverse transforms. */ + init_dequantizer ( pbi, qscale, (unsigned char) pbi->FrameQIndex ); +} + +void UpdateQC( CP_INSTANCE *cpi, ogg_uint32_t NewQ ){ + ogg_uint32_t qscale; + PB_INSTANCE *pbi = &cpi->pb; + + /* Do bounds checking and convert to a float. */ + qscale = NewQ; + if ( qscale < pbi->QThreshTable[Q_TABLE_SIZE-1] ) + qscale = pbi->QThreshTable[Q_TABLE_SIZE-1]; + else if ( qscale > pbi->QThreshTable[0] ) + qscale = pbi->QThreshTable[0]; + + /* Set the inter/intra descision control variables. */ + pbi->FrameQIndex = Q_TABLE_SIZE - 1; + while ((ogg_int32_t) pbi->FrameQIndex >= 0 ) { + if ( (pbi->FrameQIndex == 0) || + ( pbi->QThreshTable[pbi->FrameQIndex] >= NewQ) ) + break; + pbi->FrameQIndex --; + } + + /* Re-initialise the q tables for forward and reverse transforms. */ + init_quantizer ( cpi, qscale, (unsigned char) pbi->FrameQIndex ); + init_dequantizer ( pbi, qscale, (unsigned char) pbi->FrameQIndex ); +} diff --git a/src/add-ons/media/plugins/theora/libtheora/quant_lookup.h b/src/add-ons/media/plugins/theora/libtheora/quant_lookup.h new file mode 100644 index 0000000000..d415bcbf6e --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/quant_lookup.h @@ -0,0 +1,37 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: quant_lookup.h,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include "encoder_internal.h" + +#define MIN16 ((1<<16)-1) +#define SHIFT16 (1<<16) + +#define MIN_LEGAL_QUANT_ENTRY 8 +#define MIN_DEQUANT_VAL 2 +#define IDCT_SCALE_FACTOR 2 /* Shift left bits to improve IDCT precision */ +#define OLD_SCHEME 1 + +static ogg_uint32_t dequant_index[64] = { + 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 +}; diff --git a/src/add-ons/media/plugins/theora/libtheora/reconstruct.c b/src/add-ons/media/plugins/theora/libtheora/reconstruct.c new file mode 100644 index 0000000000..2faec5a7af --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/reconstruct.c @@ -0,0 +1,85 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: reconstruct.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include "encoder_internal.h" + +void ReconIntra( PB_INSTANCE *pbi, unsigned char * ReconPtr, + ogg_int16_t * ChangePtr, ogg_uint32_t LineStep ) { + ogg_uint32_t i; + + for ( i = 0; i < BLOCK_HEIGHT_WIDTH; i++ ){ + /* Convert the data back to 8 bit unsigned */ + /* Saturate the output to unsigend 8 bit values */ + ReconPtr[0] = clamp255( ChangePtr[0] + 128 ); + ReconPtr[1] = clamp255( ChangePtr[1] + 128 ); + ReconPtr[2] = clamp255( ChangePtr[2] + 128 ); + ReconPtr[3] = clamp255( ChangePtr[3] + 128 ); + ReconPtr[4] = clamp255( ChangePtr[4] + 128 ); + ReconPtr[5] = clamp255( ChangePtr[5] + 128 ); + ReconPtr[6] = clamp255( ChangePtr[6] + 128 ); + ReconPtr[7] = clamp255( ChangePtr[7] + 128 ); + + ReconPtr += LineStep; + ChangePtr += BLOCK_HEIGHT_WIDTH; + } + +} + +void ReconInter( PB_INSTANCE *pbi, unsigned char * ReconPtr, + unsigned char * RefPtr, ogg_int16_t * ChangePtr, + ogg_uint32_t LineStep ) { + ogg_uint32_t i; + + for ( i = 0; i < BLOCK_HEIGHT_WIDTH; i++) { + ReconPtr[0] = clamp255(RefPtr[0] + ChangePtr[0]); + ReconPtr[1] = clamp255(RefPtr[1] + ChangePtr[1]); + ReconPtr[2] = clamp255(RefPtr[2] + ChangePtr[2]); + ReconPtr[3] = clamp255(RefPtr[3] + ChangePtr[3]); + ReconPtr[4] = clamp255(RefPtr[4] + ChangePtr[4]); + ReconPtr[5] = clamp255(RefPtr[5] + ChangePtr[5]); + ReconPtr[6] = clamp255(RefPtr[6] + ChangePtr[6]); + ReconPtr[7] = clamp255(RefPtr[7] + ChangePtr[7]); + + ChangePtr += BLOCK_HEIGHT_WIDTH; + ReconPtr += LineStep; + RefPtr += LineStep; + } + +} + +void ReconInterHalfPixel2( PB_INSTANCE *pbi, unsigned char * ReconPtr, + unsigned char * RefPtr1, unsigned char * RefPtr2, + ogg_int16_t * ChangePtr, ogg_uint32_t LineStep ) { + ogg_uint32_t i; + + for ( i = 0; i < BLOCK_HEIGHT_WIDTH; i++ ){ + ReconPtr[0] = clamp255((((int)RefPtr1[0] + (int)RefPtr2[0]) >> 1) + ChangePtr[0] ); + ReconPtr[1] = clamp255((((int)RefPtr1[1] + (int)RefPtr2[1]) >> 1) + ChangePtr[1] ); + ReconPtr[2] = clamp255((((int)RefPtr1[2] + (int)RefPtr2[2]) >> 1) + ChangePtr[2] ); + ReconPtr[3] = clamp255((((int)RefPtr1[3] + (int)RefPtr2[3]) >> 1) + ChangePtr[3] ); + ReconPtr[4] = clamp255((((int)RefPtr1[4] + (int)RefPtr2[4]) >> 1) + ChangePtr[4] ); + ReconPtr[5] = clamp255((((int)RefPtr1[5] + (int)RefPtr2[5]) >> 1) + ChangePtr[5] ); + ReconPtr[6] = clamp255((((int)RefPtr1[6] + (int)RefPtr2[6]) >> 1) + ChangePtr[6] ); + ReconPtr[7] = clamp255((((int)RefPtr1[7] + (int)RefPtr2[7]) >> 1) + ChangePtr[7] ); + + ChangePtr += BLOCK_HEIGHT_WIDTH; + ReconPtr += LineStep; + RefPtr1 += LineStep; + RefPtr2 += LineStep; + } + +} diff --git a/src/add-ons/media/plugins/theora/libtheora/scan.c b/src/add-ons/media/plugins/theora/libtheora/scan.c new file mode 100644 index 0000000000..802de038e7 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/scan.c @@ -0,0 +1,2351 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: scan.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include +#include "encoder_internal.h" + +#define MAX_SEARCH_LINE_LEN 7 + +static ogg_uint32_t LineLengthScores[ MAX_SEARCH_LINE_LEN + 1 ] = { + 0, 0, 0, 0, 2, 4, 12, 24 +}; + +static ogg_uint32_t BodyNeighbourScore = 8; +static double DiffDevisor = 0.0625; +#define HISTORY_BLOCK_FACTOR 2 +#define MIN_STEP_THRESH 6 +#define SCORE_MULT_LOW 0.5 +#define SCORE_MULT_HIGH 4 + +#define UP 0 +#define DOWN 1 +#define LEFT 2 +#define RIGHT 3 + +#define INTERNAL_BLOCK_HEIGHT 8 +#define INTERNAL_BLOCK_WIDTH 8 + +#define BLOCK_NOT_CODED 0 +#define BLOCK_CODED_BAR 3 +#define BLOCK_CODED_SGC 4 +#define BLOCK_CODED_LOW 4 +#define BLOCK_CODED 5 + +#define CANDIDATE_BLOCK_LOW -2 +#define CANDIDATE_BLOCK -1 + +#define FIRST_ROW 0 +#define NOT_EDGE_ROW 1 +#define LAST_ROW 2 + +#define YDIFF_CB_ROWS (INTERNAL_BLOCK_HEIGHT * 3) +#define CHLOCALS_CB_ROWS (INTERNAL_BLOCK_HEIGHT * 3) +#define PMAP_CB_ROWS (INTERNAL_BLOCK_HEIGHT * 3) + +void ConfigurePP( PP_INSTANCE *ppi, int Level ) { + switch ( Level ){ + case 0: + ppi->SRFGreyThresh = 1; + ppi->SRFColThresh = 1; + ppi->NoiseSupLevel = 2; + ppi->SgcLevelThresh = 1; + ppi->SuvcLevelThresh = 1; + ppi->GrpLowSadThresh = 6; + ppi->GrpHighSadThresh = 24; + ppi->PrimaryBlockThreshold = 2; + ppi->SgcThresh = 10; + + ppi->PAKEnabled = 0; + break; + + case 1: + ppi->SRFGreyThresh = 2; + ppi->SRFColThresh = 2; + ppi->NoiseSupLevel = 2; + ppi->SgcLevelThresh = 2; + ppi->SuvcLevelThresh = 2; + ppi->GrpLowSadThresh = 8; + ppi->GrpHighSadThresh = 32; + ppi->PrimaryBlockThreshold = 5; + ppi->SgcThresh = 12; + + ppi->PAKEnabled = 1; + break; + + case 2: /* Default VP3 settings */ + ppi->SRFGreyThresh = 3; + ppi->SRFColThresh = 3; + ppi->NoiseSupLevel = 2; + ppi->SgcLevelThresh = 2; + ppi->SuvcLevelThresh = 2; + ppi->GrpLowSadThresh = 8; + ppi->GrpHighSadThresh = 32; + ppi->PrimaryBlockThreshold = 5; + ppi->SgcThresh = 16; + + ppi->PAKEnabled = 1; + break; + + case 3: + ppi->SRFGreyThresh = 4; + ppi->SRFColThresh = 4; + ppi->NoiseSupLevel = 3; + ppi->SgcLevelThresh = 3; + ppi->SuvcLevelThresh = 3; + ppi->GrpLowSadThresh = 10; + ppi->GrpHighSadThresh = 48; + ppi->PrimaryBlockThreshold = 5; + ppi->SgcThresh = 18; + + ppi->PAKEnabled = 1; + break; + + case 4: + ppi->SRFGreyThresh = 5; + ppi->SRFColThresh = 5; + ppi->NoiseSupLevel = 3; + ppi->SgcLevelThresh = 4; + ppi->SuvcLevelThresh = 4; + ppi->GrpLowSadThresh = 12; + ppi->GrpHighSadThresh = 48; + ppi->PrimaryBlockThreshold = 5; + ppi->SgcThresh = 20; + + ppi->PAKEnabled = 1; + break; + + case 5: + ppi->SRFGreyThresh = 6; + ppi->SRFColThresh = 6; + ppi->NoiseSupLevel = 3; + ppi->SgcLevelThresh = 4; + ppi->SuvcLevelThresh = 4; + ppi->GrpLowSadThresh = 12; + ppi->GrpHighSadThresh = 64; + ppi->PrimaryBlockThreshold = 10; + ppi->SgcThresh = 24; + + ppi->PAKEnabled = 1; + break; + + case 6: + ppi->SRFGreyThresh = 6; + ppi->SRFColThresh = 7; + ppi->NoiseSupLevel = 3; + ppi->SgcLevelThresh = 4; + ppi->SuvcLevelThresh = 4; + ppi->GrpLowSadThresh = 12; + ppi->GrpHighSadThresh = 64; + ppi->PrimaryBlockThreshold = 10; + ppi->SgcThresh = 24; + + ppi->PAKEnabled = 1; + break; + + default: + ppi->SRFGreyThresh = 3; + ppi->SRFColThresh = 3; + ppi->NoiseSupLevel = 2; + ppi->SgcLevelThresh = 2; + ppi->SuvcLevelThresh = 2; + ppi->GrpLowSadThresh = 10; + ppi->GrpHighSadThresh = 32; + ppi->PrimaryBlockThreshold = 5; + ppi->SgcThresh = 16; + ppi->PAKEnabled = 1; + break; + } +} + +static void ScanCalcPixelIndexTable(PP_INSTANCE *ppi){ + ogg_uint32_t i; + ogg_uint32_t * PixelIndexTablePtr = ppi->ScanPixelIndexTable; + + /* If appropriate add on extra inices for U and V planes. */ + for ( i = 0; i < (ppi->ScanYPlaneFragments); i++ ) { + PixelIndexTablePtr[ i ] = + ((i / ppi->ScanHFragments) * + VFRAGPIXELS * ppi->ScanConfig.VideoFrameWidth); + PixelIndexTablePtr[ i ] += + ((i % ppi->ScanHFragments) * HFRAGPIXELS); + } + + PixelIndexTablePtr = &ppi->ScanPixelIndexTable[ppi->ScanYPlaneFragments]; + + for ( i = 0; i < (ppi->ScanUVPlaneFragments * 2); i++ ){ + PixelIndexTablePtr[ i ] = + ((i / (ppi->ScanHFragments >> 1) ) * + (VFRAGPIXELS * (ppi->ScanConfig.VideoFrameWidth >> 1)) ); + PixelIndexTablePtr[ i ] += + ((i % (ppi->ScanHFragments >> 1) ) * + HFRAGPIXELS) + ppi->YFramePixels; + } +} + +static void InitScanMapArrays(PP_INSTANCE *ppi){ + int i; + unsigned char StepThresh; + + /* Clear down the fragment level map arrays for the current frame. */ + memset( ppi->FragScores, 0, + ppi->ScanFrameFragments * sizeof(*ppi->FragScores) ); + memset( ppi->SameGreyDirPixels, 0, + ppi->ScanFrameFragments ); + memset( ppi->FragDiffPixels, 0, + ppi->ScanFrameFragments ); + memset( ppi->RowChangedPixels, 0, + 3* ppi->ScanConfig.VideoFrameHeight*sizeof(*ppi->RowChangedPixels)); + + memset( ppi->ScanDisplayFragments, BLOCK_NOT_CODED, ppi->ScanFrameFragments); + + /* Threshold used in setting up ppi->NoiseScoreBoostTable[] */ + StepThresh = (unsigned int)(ppi->SRFGreyThresh >> 1); + if ( StepThresh < MIN_STEP_THRESH ) + StepThresh = MIN_STEP_THRESH; + ppi->SrfThresh = (int)ppi->SRFGreyThresh; + + /* Set up various tables used to tweak pixel score values and + scoring rules based upon absolute value of a pixel change */ + for ( i = 0; i < 256; i++ ){ + /* Score multiplier table indexed by absolute difference. */ + ppi->AbsDiff_ScoreMultiplierTable[i] = (double)i * DiffDevisor; + if ( ppi->AbsDiff_ScoreMultiplierTable[i] < SCORE_MULT_LOW ) + ppi->AbsDiff_ScoreMultiplierTable[i] = SCORE_MULT_LOW; + else if ( ppi->AbsDiff_ScoreMultiplierTable[i] > SCORE_MULT_HIGH) + ppi->AbsDiff_ScoreMultiplierTable[i] = SCORE_MULT_HIGH; + + /* Table that facilitates a relaxation of the changed locals rules + in NoiseScoreRow() for pixels that have changed by a large + amount. */ + if ( i < (ppi->SrfThresh + StepThresh) ) + ppi->NoiseScoreBoostTable[i] = 0; + else if ( i < (ppi->SrfThresh + (StepThresh * 4)) ) + ppi->NoiseScoreBoostTable[i] = 1; + else if ( i < (ppi->SrfThresh + (StepThresh * 6)) ) + ppi->NoiseScoreBoostTable[i] = 2; + else + ppi->NoiseScoreBoostTable[i] = 3; + + } + + /* Set various other threshold parameters. */ + + /* Set variables that control access to the line search algorithms. */ + ppi->LineSearchTripTresh = 16; + if ( ppi->LineSearchTripTresh > ppi->PrimaryBlockThreshold ) + ppi->LineSearchTripTresh = (unsigned int)(ppi->PrimaryBlockThreshold + 1); + + /* Adjust line search length if block threshold low */ + ppi->MaxLineSearchLen = MAX_SEARCH_LINE_LEN; + while ( (ppi->MaxLineSearchLen > 0) && + (LineLengthScores[ppi->MaxLineSearchLen-1] > + ppi->PrimaryBlockThreshold) ) + ppi->MaxLineSearchLen -= 1; + +} + +void ScanYUVInit( PP_INSTANCE * ppi, SCAN_CONFIG_DATA * ScanConfigPtr){ + int i; + + /* Set up the various imported data structure pointers. */ + ppi->ScanConfig.Yuv0ptr = ScanConfigPtr->Yuv0ptr; + ppi->ScanConfig.Yuv1ptr = ScanConfigPtr->Yuv1ptr; + ppi->ScanConfig.SrfWorkSpcPtr = ScanConfigPtr->SrfWorkSpcPtr; + ppi->ScanConfig.disp_fragments = ScanConfigPtr->disp_fragments; + + ppi->ScanConfig.RegionIndex = ScanConfigPtr->RegionIndex; + + ppi->ScanConfig.VideoFrameWidth = ScanConfigPtr->VideoFrameWidth; + ppi->ScanConfig.VideoFrameHeight = ScanConfigPtr->VideoFrameHeight; + + /* UV plane sizes. */ + ppi->VideoUVPlaneWidth = ScanConfigPtr->VideoFrameWidth / 2; + ppi->VideoUVPlaneHeight = ScanConfigPtr->VideoFrameHeight / 2; + + /* Note the size of each plane in pixels. */ + ppi->YFramePixels = ppi->ScanConfig.VideoFrameWidth * + ppi->ScanConfig.VideoFrameHeight; + ppi->UVFramePixels = ppi->VideoUVPlaneWidth * ppi->VideoUVPlaneHeight; + + /* Work out various fragment related values. */ + ppi->ScanYPlaneFragments = ppi->YFramePixels / + (HFRAGPIXELS * VFRAGPIXELS); + ppi->ScanUVPlaneFragments = ppi->UVFramePixels / + (HFRAGPIXELS * VFRAGPIXELS);; + ppi->ScanHFragments = ppi->ScanConfig.VideoFrameWidth / HFRAGPIXELS; + ppi->ScanVFragments = ppi->ScanConfig.VideoFrameHeight / VFRAGPIXELS; + ppi->ScanFrameFragments = ppi->ScanYPlaneFragments + + (2 * ppi->ScanUVPlaneFragments); + + PInitFrameInfo(ppi); + + /* Set up the scan pixel index table. */ + ScanCalcPixelIndexTable(ppi); + + /* Initialise the previous frame block history lists */ + for ( i = 0; i < MAX_PREV_FRAMES; i++ ) + memset( ppi->PrevFragments[i], BLOCK_NOT_CODED, ppi->ScanFrameFragments); + + /* YUVAnalyseFrame() is not called for the first frame in a sequence + (a key frame obviously). This memset insures that for the second + frame all blocks are marked for coding in line with the behaviour + for other key frames. */ + memset( ppi->PrevFragments[ppi->PrevFrameLimit-1], + BLOCK_CODED, ppi->ScanFrameFragments ); + + /* Initialise scan arrays */ + InitScanMapArrays(ppi); +} + +static void SetFromPrevious(PP_INSTANCE *ppi) { + unsigned int i,j; + + /* We buld up the list of previously updated blocks in the zero + index list of PrevFragments[] so we must start by reseting its + contents */ + memset( ppi->PrevFragments[0], BLOCK_NOT_CODED, ppi->ScanFrameFragments ); + + if ( ppi->PrevFrameLimit > 1 ){ + /* Now build up PrevFragments[0] from PrevFragments[1 to PrevFrameLimit] */ + for ( i = 0; i < ppi->ScanFrameFragments; i++ ){ + for ( j = 1; j < ppi->PrevFrameLimit; j++ ){ + if ( ppi->PrevFragments[j][i] > BLOCK_CODED_BAR ){ + ppi->PrevFragments[0][i] = BLOCK_CODED; + break; + } + } + } + } +} + +static void UpdatePreviousBlockLists(PP_INSTANCE *ppi) { + int i; + + /* Shift previous frame block lists along. */ + for ( i = ppi->PrevFrameLimit; i > 1; i-- ){ + memcpy( ppi->PrevFragments[i], ppi->PrevFragments[i-1], + ppi->ScanFrameFragments ); + } + + /* Now copy in this frames block list */ + memcpy( ppi->PrevFragments[1], ppi->ScanDisplayFragments, + ppi->ScanFrameFragments ); +} + +static void CreateOutputDisplayMap( PP_INSTANCE *ppi, + char *InternalFragmentsPtr, + char *RecentHistoryPtr, + unsigned char *ExternalFragmentsPtr ) { + ogg_uint32_t i; + ogg_uint32_t HistoryBlocksAdded = 0; + ogg_uint32_t YBand = (ppi->ScanYPlaneFragments/8); /* 1/8th of Y image. */ + + ppi->OutputBlocksUpdated = 0; + for ( i = 0; i < ppi->ScanFrameFragments; i++ ) { + if ( InternalFragmentsPtr[i] > BLOCK_NOT_CODED ) { + ppi->OutputBlocksUpdated ++; + ExternalFragmentsPtr[i] = 1; + }else if ( RecentHistoryPtr[i] == BLOCK_CODED ){ + HistoryBlocksAdded ++; + ExternalFragmentsPtr[i] = 1; + }else{ + ExternalFragmentsPtr[i] = 0; + } + } + + /* Add in a weighting for the history blocks that have been added */ + ppi->OutputBlocksUpdated += (HistoryBlocksAdded / HISTORY_BLOCK_FACTOR); + + /* Now calculate a key frame candidate indicator. This is based + upon Y data only and ignores the top and bottom 1/8 of the + image. Also ignore history blocks and BAR blocks. */ + ppi->KFIndicator = 0; + for ( i = YBand; i < (ppi->ScanYPlaneFragments - YBand); i++ ) + if ( InternalFragmentsPtr[i] > BLOCK_CODED_BAR ) + ppi->KFIndicator ++; + + /* Convert the KF score to a range 0-100 */ + ppi->KFIndicator = ((ppi->KFIndicator*100)/((ppi->ScanYPlaneFragments*3)/4)); +} + +static ogg_uint32_t ScalarRowSAD( unsigned char * Src1, + unsigned char * Src2 ){ + ogg_uint32_t SadValue; + ogg_uint32_t SadValue1; + + SadValue = abs( Src1[0] - Src2[0] ) + abs( Src1[1] - Src2[1] ) + + abs( Src1[2] - Src2[2] ) + abs( Src1[3] - Src2[3] ); + + SadValue1 = abs( Src1[4] - Src2[4] ) + abs( Src1[5] - Src2[5] ) + + abs( Src1[6] - Src2[6] ) + abs( Src1[7] - Src2[7] ); + + SadValue = ( SadValue > SadValue1 ) ? SadValue : SadValue1; + + return SadValue; +} + +static ogg_uint32_t ScalarColSAD( PP_INSTANCE *ppi, + unsigned char * Src1, + unsigned char * Src2 ){ + ogg_uint32_t SadValue[8] = {0,0,0,0,0,0,0,0}; + ogg_uint32_t SadValue2[8] = {0,0,0,0,0,0,0,0}; + ogg_uint32_t MaxSad = 0; + ogg_uint32_t i; + + for ( i = 0; i < 4; i++ ){ + SadValue[0] += abs(Src1[0] - Src2[0]); + SadValue[1] += abs(Src1[1] - Src2[1]); + SadValue[2] += abs(Src1[2] - Src2[2]); + SadValue[3] += abs(Src1[3] - Src2[3]); + SadValue[4] += abs(Src1[4] - Src2[4]); + SadValue[5] += abs(Src1[5] - Src2[5]); + SadValue[6] += abs(Src1[6] - Src2[6]); + SadValue[7] += abs(Src1[7] - Src2[7]); + + Src1 += ppi->PlaneStride; + Src2 += ppi->PlaneStride; + } + + for ( i = 0; i < 4; i++ ){ + SadValue2[0] += abs(Src1[0] - Src2[0]); + SadValue2[1] += abs(Src1[1] - Src2[1]); + SadValue2[2] += abs(Src1[2] - Src2[2]); + SadValue2[3] += abs(Src1[3] - Src2[3]); + SadValue2[4] += abs(Src1[4] - Src2[4]); + SadValue2[5] += abs(Src1[5] - Src2[5]); + SadValue2[6] += abs(Src1[6] - Src2[6]); + SadValue2[7] += abs(Src1[7] - Src2[7]); + + Src1 += ppi->PlaneStride; + Src2 += ppi->PlaneStride; + } + + for ( i = 0; i < 8; i++ ){ + if ( SadValue[i] > MaxSad ) + MaxSad = SadValue[i]; + if ( SadValue2[i] > MaxSad ) + MaxSad = SadValue2[i]; + } + + return MaxSad; +} + + +static int RowSadScan( PP_INSTANCE *ppi, + unsigned char * YuvPtr1, + unsigned char * YuvPtr2, + signed char * DispFragPtr){ + ogg_int32_t i, j; + ogg_uint32_t GrpSad; + ogg_uint32_t LocalGrpLowSadThresh = ppi->ModifiedGrpLowSadThresh; + ogg_uint32_t LocalGrpHighSadThresh = ppi->ModifiedGrpHighSadThresh; + signed char *LocalDispFragPtr; + unsigned char *LocalYuvPtr1; + unsigned char *LocalYuvPtr2; + + int InterestingBlocksInRow = 0; + + /* For each row of pixels in the row of blocks */ + for ( j = 0; j < VFRAGPIXELS; j++ ){ + /* Set local block map pointer. */ + LocalDispFragPtr = DispFragPtr; + + /* Set the local pixel data pointers for this row.*/ + LocalYuvPtr1 = YuvPtr1; + LocalYuvPtr2 = YuvPtr2; + + /* Scan along the row of pixels If the block to which a group of + pixels belongs is already marked for update then do nothing. */ + for ( i = 0; i < ppi->PlaneHFragments; i ++ ){ + if ( *LocalDispFragPtr <= BLOCK_NOT_CODED ){ + /* Calculate the SAD score for the block row */ + GrpSad = ScalarRowSAD(LocalYuvPtr1,LocalYuvPtr2); + + /* Now test the group SAD score */ + if ( GrpSad > LocalGrpLowSadThresh ){ + /* If SAD very high we must update else we have candidate block */ + if ( GrpSad > LocalGrpHighSadThresh ){ + /* Force update */ + *LocalDispFragPtr = BLOCK_CODED; + }else{ + /* Possible Update required */ + *LocalDispFragPtr = CANDIDATE_BLOCK; + } + InterestingBlocksInRow = 1; + } + } + LocalDispFragPtr++; + + LocalYuvPtr1 += 8; + LocalYuvPtr2 += 8; + } + + /* Increment the base data pointers to the start of the next line. */ + YuvPtr1 += ppi->PlaneStride; + YuvPtr2 += ppi->PlaneStride; + } + + return InterestingBlocksInRow; + +} + +static int ColSadScan( PP_INSTANCE *ppi, + unsigned char * YuvPtr1, + unsigned char * YuvPtr2, + signed char * DispFragPtr ){ + ogg_int32_t i; + ogg_uint32_t MaxSad; + ogg_uint32_t LocalGrpLowSadThresh = ppi->ModifiedGrpLowSadThresh; + ogg_uint32_t LocalGrpHighSadThresh = ppi->ModifiedGrpHighSadThresh; + signed char * LocalDispFragPtr; + + unsigned char * LocalYuvPtr1; + unsigned char * LocalYuvPtr2; + + int InterestingBlocksInRow = 0; + + /* Set the local pixel data pointers for this row. */ + LocalYuvPtr1 = YuvPtr1; + LocalYuvPtr2 = YuvPtr2; + + /* Set local block map pointer. */ + LocalDispFragPtr = DispFragPtr; + + /* Scan along the row of blocks */ + for ( i = 0; i < ppi->PlaneHFragments; i ++ ){ + /* Skip if block already marked to be coded. */ + if ( *LocalDispFragPtr <= BLOCK_NOT_CODED ){ + /* Calculate the SAD score for the block column */ + MaxSad = ScalarColSAD( ppi, LocalYuvPtr1, LocalYuvPtr2 ); + + /* Now test the group SAD score */ + if ( MaxSad > LocalGrpLowSadThresh ){ + /* If SAD very high we must update else we have candidate block */ + if ( MaxSad > LocalGrpHighSadThresh ){ + /* Force update */ + *LocalDispFragPtr = BLOCK_CODED; + }else{ + /* Possible Update required */ + *LocalDispFragPtr = CANDIDATE_BLOCK; + } + InterestingBlocksInRow = 1; + } + } + + /* Increment the block map pointer. */ + LocalDispFragPtr++; + + /* Step data pointers on ready for next block */ + LocalYuvPtr1 += HFRAGPIXELS; + LocalYuvPtr2 += HFRAGPIXELS; + } + + return InterestingBlocksInRow; +} + +static void SadPass2( PP_INSTANCE *ppi, + ogg_int32_t RowNumber, + signed char * DispFragPtr ){ + ogg_int32_t i; + + /* First row */ + if ( RowNumber == 0 ) { + /* First block in row. */ + if ( DispFragPtr[0] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[1] == BLOCK_CODED) || + (DispFragPtr[ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[ppi->PlaneHFragments+1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[0] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[0] = DispFragPtr[0]; + } + }else{ + ppi->TmpCodedMap[0] = DispFragPtr[0]; + } + + /* All but first and last in row */ + for ( i = 1; (i < ppi->PlaneHFragments-1); i++ ){ + if ( DispFragPtr[i] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[i-1] == BLOCK_CODED) || + (DispFragPtr[i+1] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments-1] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments+1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[i] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + } + + /* Last block in row. */ + i = ppi->PlaneHFragments-1; + if ( DispFragPtr[i] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[i-1] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments-1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[i] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else if ( RowNumber < (ppi->PlaneVFragments - 1) ){ + /* General case */ + /* First block in row. */ + if ( DispFragPtr[0] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[1] == BLOCK_CODED) || + (DispFragPtr[(-ppi->PlaneHFragments)] == BLOCK_CODED) || + (DispFragPtr[(-ppi->PlaneHFragments)+1] == BLOCK_CODED) || + (DispFragPtr[ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[ppi->PlaneHFragments+1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[0] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[0] = DispFragPtr[0]; + } + }else{ + ppi->TmpCodedMap[0] = DispFragPtr[0]; + } + + /* All but first and last in row */ + for ( i = 1; (i < ppi->PlaneHFragments-1); i++ ){ + if ( DispFragPtr[i] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[i-1] == BLOCK_CODED) || + (DispFragPtr[i+1] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments-1] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments+1] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments-1] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments+1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[i] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + } + + /* Last block in row. */ + i = ppi->PlaneHFragments-1; + if ( DispFragPtr[i] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[i-1] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments-1] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i+ppi->PlaneHFragments-1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[i] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else{ + /* Last row */ + /* First block in row. */ + if ( DispFragPtr[0] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[1] == BLOCK_CODED) || + (DispFragPtr[(-ppi->PlaneHFragments)] == BLOCK_CODED) || + (DispFragPtr[(-ppi->PlaneHFragments)+1] == BLOCK_CODED)){ + ppi->TmpCodedMap[0] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[0] = DispFragPtr[0]; + } + }else{ + ppi->TmpCodedMap[0] = DispFragPtr[0]; + } + + /* All but first and last in row */ + for ( i = 1; (i < ppi->PlaneHFragments-1); i++ ){ + if ( DispFragPtr[i] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[i-1] == BLOCK_CODED) || + (DispFragPtr[i+1] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments-1] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments+1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[i] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + } + + /* Last block in row. */ + i = ppi->PlaneHFragments-1; + if ( DispFragPtr[i] == CANDIDATE_BLOCK ){ + if ( (DispFragPtr[i-1] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments] == BLOCK_CODED) || + (DispFragPtr[i-ppi->PlaneHFragments-1] == BLOCK_CODED) ){ + ppi->TmpCodedMap[i] = BLOCK_CODED_LOW; + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + }else{ + ppi->TmpCodedMap[i] = DispFragPtr[i]; + } + } + + /* Now copy back the modified Fragment data */ + memcpy( &DispFragPtr[0], &ppi->TmpCodedMap[0], (ppi->PlaneHFragments) ); +} + +static unsigned char ApplyPakLowPass( PP_INSTANCE *ppi, + unsigned char * SrcPtr ){ + unsigned char * SrcPtr1 = SrcPtr - 1; + unsigned char * SrcPtr0 = SrcPtr1 - ppi->PlaneStride; /* Note the + use of + stride not + width. */ + unsigned char * SrcPtr2 = SrcPtr1 + ppi->PlaneStride; + + return (unsigned char)( ( (ogg_uint32_t)SrcPtr0[0] + + (ogg_uint32_t)SrcPtr0[1] + + (ogg_uint32_t)SrcPtr0[2] + + (ogg_uint32_t)SrcPtr1[0] + + (ogg_uint32_t)SrcPtr1[2] + + (ogg_uint32_t)SrcPtr2[0] + + (ogg_uint32_t)SrcPtr2[1] + + (ogg_uint32_t)SrcPtr2[2] ) >> 3 ); + +} + +static void RowDiffScan( PP_INSTANCE *ppi, + unsigned char * YuvPtr1, + unsigned char * YuvPtr2, + ogg_int16_t * YUVDiffsPtr, + unsigned char * bits_map_ptr, + signed char * SgcPtr, + signed char * DispFragPtr, + unsigned char * FDiffPixels, + ogg_int32_t * RowDiffsPtr, + unsigned char * ChLocalsPtr, int EdgeRow ){ + + ogg_int32_t i,j; + ogg_int32_t FragChangedPixels; + + ogg_int16_t Diff; /* Temp local workspace. */ + + /* Cannot use kernel if at edge or if PAK disabled */ + if ( (!ppi->PAKEnabled) || EdgeRow ){ + for ( i = 0; i < ppi->PlaneWidth; i += HFRAGPIXELS ){ + /* Reset count of pixels changed for the current fragment. */ + FragChangedPixels = 0; + + /* Test for break out conditions to save time. */ + if (*DispFragPtr == CANDIDATE_BLOCK){ + + /* Clear down entries in changed locals array */ + memset(ChLocalsPtr,0,8); + + for ( j = 0; j < HFRAGPIXELS; j++ ){ + /* Take a local copy of the measured difference. */ + Diff = (int)YuvPtr1[j] - (int)YuvPtr2[j]; + + /* Store the actual difference value */ + YUVDiffsPtr[j] = Diff; + + /* Test against the Level thresholds and record the results */ + SgcPtr[0] += ppi->SgcThreshTable[Diff+255]; + + /* Test against the SRF thresholds */ + bits_map_ptr[j] = ppi->SrfThreshTable[Diff+255]; + FragChangedPixels += ppi->SrfThreshTable[Diff+255]; + } + }else{ + /* If we are breaking out here mark all pixels as changed. */ + if ( *DispFragPtr > BLOCK_NOT_CODED ){ + memset(bits_map_ptr,1,8); + memset(ChLocalsPtr,8,8); + }else{ + memset(ChLocalsPtr,0,8); + } + } + + *RowDiffsPtr += FragChangedPixels; + *FDiffPixels += (unsigned char)FragChangedPixels; + + YuvPtr1 += HFRAGPIXELS; + YuvPtr2 += HFRAGPIXELS; + bits_map_ptr += HFRAGPIXELS; + ChLocalsPtr += HFRAGPIXELS; + YUVDiffsPtr += HFRAGPIXELS; + SgcPtr ++; + FDiffPixels ++; + + /* If we have a lot of changed pixels for this fragment on this + row then the fragment is almost sure to be picked (e.g. through + the line search) so we can mark it as selected and then ignore + it. */ + if (FragChangedPixels >= 7){ + *DispFragPtr = BLOCK_CODED_LOW; + } + DispFragPtr++; + } + }else{ + + /*************************************************************/ + /* First fragment of row !! */ + + i = 0; + /* Reset count of pixels changed for the current fragment. */ + FragChangedPixels = 0; + + /* Test for break out conditions to save time. */ + if (*DispFragPtr == CANDIDATE_BLOCK){ + /* Clear down entries in changed locals array */ + memset(ChLocalsPtr,0,8); + + for ( j = 0; j < HFRAGPIXELS; j++ ){ + /* Take a local copy of the measured difference. */ + Diff = (int)YuvPtr1[j] - (int)YuvPtr2[j]; + + /* Store the actual difference value */ + YUVDiffsPtr[j] = Diff; + + /* Test against the Level thresholds and record the results */ + SgcPtr[0] += ppi->SgcThreshTable[Diff+255]; + + if (j>0 && ppi->SrfPakThreshTable[Diff+255] ) + Diff = (int)ApplyPakLowPass( ppi, &YuvPtr1[j] ) - + (int)ApplyPakLowPass( ppi, &YuvPtr2[j] ); + + /* Test against the SRF thresholds */ + bits_map_ptr[j] = ppi->SrfThreshTable[Diff+255]; + FragChangedPixels += ppi->SrfThreshTable[Diff+255]; + } + }else{ + /* If we are breaking out here mark all pixels as changed. */ + if ( *DispFragPtr > BLOCK_NOT_CODED ){ + memset(bits_map_ptr,1,8); + memset(ChLocalsPtr,8,8); + }else{ + memset(ChLocalsPtr,0,8); + } + } + + *RowDiffsPtr += FragChangedPixels; + *FDiffPixels += (unsigned char)FragChangedPixels; + + YuvPtr1 += HFRAGPIXELS; + YuvPtr2 += HFRAGPIXELS; + bits_map_ptr += HFRAGPIXELS; + ChLocalsPtr += HFRAGPIXELS; + YUVDiffsPtr += HFRAGPIXELS; + SgcPtr ++; + FDiffPixels ++; + + /* If we have a lot of changed pixels for this fragment on this + row then the fragment is almost sure to be picked + (e.g. through the line search) so we can mark it as selected + and then ignore it. */ + if (FragChangedPixels >= 7){ + *DispFragPtr = BLOCK_CODED_LOW; + } + DispFragPtr++; + /*************************************************************/ + /* Fragment in between!! */ + + for ( i = HFRAGPIXELS ; i < ppi->PlaneWidth-HFRAGPIXELS; + i += HFRAGPIXELS ){ + /* Reset count of pixels changed for the current fragment. */ + FragChangedPixels = 0; + + /* Test for break out conditions to save time. */ + if (*DispFragPtr == CANDIDATE_BLOCK){ + /* Clear down entries in changed locals array */ + memset(ChLocalsPtr,0,8); + for ( j = 0; j < HFRAGPIXELS; j++ ){ + /* Take a local copy of the measured difference. */ + Diff = (int)YuvPtr1[j] - (int)YuvPtr2[j]; + + /* Store the actual difference value */ + YUVDiffsPtr[j] = Diff; + + /* Test against the Level thresholds and record the results */ + SgcPtr[0] += ppi->SgcThreshTable[Diff+255]; + + if (ppi->SrfPakThreshTable[Diff+255] ) + Diff = (int)ApplyPakLowPass( ppi, &YuvPtr1[j] ) - + (int)ApplyPakLowPass( ppi, &YuvPtr2[j] ); + + + /* Test against the SRF thresholds */ + bits_map_ptr[j] = ppi->SrfThreshTable[Diff+255]; + FragChangedPixels += ppi->SrfThreshTable[Diff+255]; + } + }else{ + /* If we are breaking out here mark all pixels as changed. */ + if ( *DispFragPtr > BLOCK_NOT_CODED ){ + memset(bits_map_ptr,1,8); + memset(ChLocalsPtr,8,8); + }else{ + memset(ChLocalsPtr,0,8); + } + } + + *RowDiffsPtr += FragChangedPixels; + *FDiffPixels += (unsigned char)FragChangedPixels; + + YuvPtr1 += HFRAGPIXELS; + YuvPtr2 += HFRAGPIXELS; + bits_map_ptr += HFRAGPIXELS; + ChLocalsPtr += HFRAGPIXELS; + YUVDiffsPtr += HFRAGPIXELS; + SgcPtr ++; + FDiffPixels ++; + + /* If we have a lot of changed pixels for this fragment on this + row then the fragment is almost sure to be picked + (e.g. through the line search) so we can mark it as selected + and then ignore it. */ + if (FragChangedPixels >= 7){ + *DispFragPtr = BLOCK_CODED_LOW; + } + DispFragPtr++; + } + /*************************************************************/ + /* Last fragment of row !! */ + + /* Reset count of pixels changed for the current fragment. */ + FragChangedPixels = 0; + + /* Test for break out conditions to save time. */ + if (*DispFragPtr == CANDIDATE_BLOCK){ + /* Clear down entries in changed locals array */ + memset(ChLocalsPtr,0,8); + + for ( j = 0; j < HFRAGPIXELS; j++ ){ + /* Take a local copy of the measured difference. */ + Diff = (int)YuvPtr1[j] - (int)YuvPtr2[j]; + + /* Store the actual difference value */ + YUVDiffsPtr[j] = Diff; + + /* Test against the Level thresholds and record the results */ + SgcPtr[0] += ppi->SgcThreshTable[Diff+255]; + + if (j<7 && ppi->SrfPakThreshTable[Diff+255] ) + Diff = (int)ApplyPakLowPass( ppi, &YuvPtr1[j] ) - + (int)ApplyPakLowPass( ppi, &YuvPtr2[j] ); + + + /* Test against the SRF thresholds */ + bits_map_ptr[j] = ppi->SrfThreshTable[Diff+255]; + FragChangedPixels += ppi->SrfThreshTable[Diff+255]; + } + }else{ + /* If we are breaking out here mark all pixels as changed.*/ + if ( *DispFragPtr > BLOCK_NOT_CODED ) { + memset(bits_map_ptr,1,8); + memset(ChLocalsPtr,8,8); + }else{ + memset(ChLocalsPtr,0,8); + } + } + /* If we have a lot of changed pixels for this fragment on this + row then the fragment is almost sure to be picked (e.g. through + the line search) so we can mark it as selected and then ignore + it. */ + *RowDiffsPtr += FragChangedPixels; + *FDiffPixels += (unsigned char)FragChangedPixels; + + /* If we have a lot of changed pixels for this fragment on this + row then the fragment is almost sure to be picked (e.g. through + the line search) so we can mark it as selected and then ignore + it. */ + if (FragChangedPixels >= 7){ + *DispFragPtr = BLOCK_CODED_LOW; + } + DispFragPtr++; + + } +} + +static void ConsolidateDiffScanResults( PP_INSTANCE *ppi, + unsigned char * FDiffPixels, + signed char * SgcScoresPtr, + signed char * DispFragPtr ){ + ogg_int32_t i; + + for ( i = 0; i < ppi->PlaneHFragments; i ++ ){ + /* Consider only those blocks that were candidates in the + difference scan. Ignore definite YES and NO cases. */ + if ( DispFragPtr[i] == CANDIDATE_BLOCK ){ + if ( ((ogg_uint32_t)abs(SgcScoresPtr[i]) > ppi->BlockSgcThresh) ){ + /* Block marked for update due to Sgc change */ + DispFragPtr[i] = BLOCK_CODED_SGC; + }else if ( FDiffPixels[i] == 0 ){ + /* Block is no longer a candidate for the main tests but will + still be considered a candidate in RowBarEnhBlockMap() */ + DispFragPtr[i] = CANDIDATE_BLOCK_LOW; + } + } + } +} + +static void RowChangedLocalsScan( PP_INSTANCE *ppi, + unsigned char * PixelMapPtr, + unsigned char * ChLocalsPtr, + signed char * DispFragPtr, + unsigned char RowType ){ + + unsigned char changed_locals = 0; + unsigned char * PixelsChangedPtr0; + unsigned char * PixelsChangedPtr1; + unsigned char * PixelsChangedPtr2; + ogg_int32_t i, j; + ogg_int32_t LastRowIndex = ppi->PlaneWidth - 1; + + /* Set up the line based pointers into the bits changed map. */ + PixelsChangedPtr0 = PixelMapPtr - ppi->PlaneWidth; + if ( PixelsChangedPtr0 < ppi->PixelChangedMap ) + PixelsChangedPtr0 += ppi->PixelMapCircularBufferSize; + PixelsChangedPtr0 -= 1; + + PixelsChangedPtr1 = PixelMapPtr - 1; + + PixelsChangedPtr2 = PixelMapPtr + ppi->PlaneWidth; + if ( PixelsChangedPtr2 >= + (ppi->PixelChangedMap + ppi->PixelMapCircularBufferSize) ) + PixelsChangedPtr2 -= ppi->PixelMapCircularBufferSize; + PixelsChangedPtr2 -= 1; + + if ( RowType == NOT_EDGE_ROW ){ + /* Scan through the row of pixels and calculate changed locals. */ + for ( i = 0; i < ppi->PlaneWidth; i += HFRAGPIXELS ){ + /* Skip a group of 8 pixels if the assosciated fragment has no + pixels of interest. */ + if ( *DispFragPtr == CANDIDATE_BLOCK ){ + for ( j = 0; j < HFRAGPIXELS; j++ ){ + changed_locals = 0; + + /* If the pixel itself has changed */ + if ( PixelsChangedPtr1[1] ){ + if ( (i > 0) || (j > 0) ){ + changed_locals += PixelsChangedPtr0[0]; + changed_locals += PixelsChangedPtr1[0]; + changed_locals += PixelsChangedPtr2[0]; + } + + changed_locals += PixelsChangedPtr0[1]; + changed_locals += PixelsChangedPtr2[1]; + + if ( (i + j) < LastRowIndex ){ + changed_locals += PixelsChangedPtr0[2]; + changed_locals += PixelsChangedPtr1[2]; + changed_locals += PixelsChangedPtr2[2]; + } + + /* Store the number of changed locals */ + *ChLocalsPtr |= changed_locals; + } + + /* Increment to next pixel in the row */ + ChLocalsPtr++; + PixelsChangedPtr0++; + PixelsChangedPtr1++; + PixelsChangedPtr2++; + } + }else{ + if ( *DispFragPtr > BLOCK_NOT_CODED ) + memset(ChLocalsPtr,0,8); + + /* Step pointers */ + ChLocalsPtr += HFRAGPIXELS; + PixelsChangedPtr0 += HFRAGPIXELS; + PixelsChangedPtr1 += HFRAGPIXELS; + PixelsChangedPtr2 += HFRAGPIXELS; + } + + /* Move on to next fragment. */ + DispFragPtr++; + + } + }else{ + /* Scan through the row of pixels and calculate changed locals. */ + for ( i = 0; i < ppi->PlaneWidth; i += HFRAGPIXELS ){ + /* Skip a group of 8 pixels if the assosciated fragment has no + pixels of interest */ + if ( *DispFragPtr == CANDIDATE_BLOCK ){ + for ( j = 0; j < HFRAGPIXELS; j++ ){ + changed_locals = 0; + + /* If the pixel itself has changed */ + if ( PixelsChangedPtr1[1] ){ + if ( RowType == FIRST_ROW ){ + if ( (i > 0) || (j > 0) ){ + changed_locals += PixelsChangedPtr1[0]; + changed_locals += PixelsChangedPtr2[0]; + } + + changed_locals += PixelsChangedPtr2[1]; + + if ( (i + j) < LastRowIndex ){ + changed_locals += PixelsChangedPtr1[2]; + changed_locals += PixelsChangedPtr2[2]; + } + }else{ + if ( (i > 0) || (j > 0 ) ){ + changed_locals += PixelsChangedPtr0[0]; + changed_locals += PixelsChangedPtr1[0]; + } + + changed_locals += PixelsChangedPtr0[1]; + + if ( (i + j) < LastRowIndex ){ + changed_locals += PixelsChangedPtr0[2]; + changed_locals += PixelsChangedPtr1[2]; + } + } + + /* Store the number of changed locals */ + *ChLocalsPtr |= changed_locals; + } + + /* Increment to next pixel in the row */ + ChLocalsPtr++; + PixelsChangedPtr0++; + PixelsChangedPtr1++; + PixelsChangedPtr2++; + } + }else{ + if ( *DispFragPtr > BLOCK_NOT_CODED ) + memset(ChLocalsPtr,0,8); + + /* Step pointers */ + ChLocalsPtr += HFRAGPIXELS; + PixelsChangedPtr0 += HFRAGPIXELS; + PixelsChangedPtr1 += HFRAGPIXELS; + PixelsChangedPtr2 += HFRAGPIXELS; + } + + /* Move on to next fragment. */ + DispFragPtr++; + } + } +} + +static void NoiseScoreRow( PP_INSTANCE *ppi, + unsigned char * PixelMapPtr, + unsigned char * ChLocalsPtr, + ogg_int16_t * YUVDiffsPtr, + unsigned char * PixelNoiseScorePtr, + ogg_uint32_t * FragScorePtr, + signed char * DispFragPtr, + ogg_int32_t * RowDiffsPtr ){ + ogg_int32_t i,j; + unsigned char changed_locals = 0; + ogg_int32_t Score; + ogg_uint32_t FragScore; + ogg_int32_t AbsDiff; + + /* For each pixel in the row */ + for ( i = 0; i < ppi->PlaneWidth; i += HFRAGPIXELS ){ + /* Skip a group of 8 pixels if the assosciated fragment has no + pixels of interest. */ + if ( *DispFragPtr == CANDIDATE_BLOCK ){ + /* Reset the cumulative fragment score. */ + FragScore = 0; + + /* Pixels grouped along the row into fragments */ + for ( j = 0; j < HFRAGPIXELS; j++ ){ + if ( PixelMapPtr[j] ){ + AbsDiff = (ogg_int32_t)( abs(YUVDiffsPtr[j]) ); + changed_locals = ChLocalsPtr[j]; + + /* Give this pixel a score based on changed locals and level + of its own change. */ + Score = (1 + ((ogg_int32_t)(changed_locals + + ppi->NoiseScoreBoostTable[AbsDiff]) - + ppi->NoiseSupLevel)); + + /* For no zero scores adjust by a level based score multiplier. */ + if ( Score > 0 ){ + Score = ((double)Score * + ppi->AbsDiff_ScoreMultiplierTable[AbsDiff] ); + if ( Score < 1 ) + Score = 1; + }else{ + /* Set -ve values to 0 */ + Score = 0; + + /* If there are no changed locals then clear the pixel + changed flag and decrement the pixels changed in + fragment count to speed later stages. */ + if ( changed_locals == 0 ){ + PixelMapPtr[j] = 0; + *RowDiffsPtr -= 1; + } + } + + /* Update the pixel scores etc. */ + PixelNoiseScorePtr[j] = (unsigned char)Score; + FragScore += (ogg_uint32_t)Score; + } + } + + /* Add fragment score (with plane correction factor) into main + data structure */ + *FragScorePtr += (ogg_int32_t)(FragScore * + ppi->YUVPlaneCorrectionFactor); + + /* If score is greater than trip threshold then mark blcok for update. */ + if ( *FragScorePtr > ppi->BlockThreshold ){ + *DispFragPtr = BLOCK_CODED_LOW; + } + } + + /* Increment the various pointers */ + FragScorePtr++; + DispFragPtr++; + PixelNoiseScorePtr += HFRAGPIXELS; + PixelMapPtr += HFRAGPIXELS; + ChLocalsPtr += HFRAGPIXELS; + YUVDiffsPtr += HFRAGPIXELS; + } +} + +static void PrimaryEdgeScoreRow( PP_INSTANCE *ppi, + unsigned char * ChangedLocalsPtr, + ogg_int16_t * YUVDiffsPtr, + unsigned char * PixelNoiseScorePtr, + ogg_uint32_t * FragScorePtr, + signed char * DispFragPtr, + unsigned char RowType ){ + ogg_uint32_t BodyNeighbours; + ogg_uint32_t AbsDiff; + unsigned char changed_locals = 0; + ogg_int32_t Score; + ogg_uint32_t FragScore; + unsigned char * CHLocalsPtr0; + unsigned char * CHLocalsPtr1; + unsigned char * CHLocalsPtr2; + ogg_int32_t i,j; + ogg_int32_t LastRowIndex = ppi->PlaneWidth - 1; + + /* Set up pointers into the current previous and next row of the + changed locals data structure. */ + CHLocalsPtr0 = ChangedLocalsPtr - ppi->PlaneWidth; + if ( CHLocalsPtr0 < ppi->ChLocals ) + CHLocalsPtr0 += ppi->ChLocalsCircularBufferSize; + CHLocalsPtr0 -= 1; + + CHLocalsPtr1 = ChangedLocalsPtr - 1; + + CHLocalsPtr2 = ChangedLocalsPtr + ppi->PlaneWidth; + if ( CHLocalsPtr2 >= (ppi->ChLocals + ppi->ChLocalsCircularBufferSize) ) + CHLocalsPtr2 -= ppi->ChLocalsCircularBufferSize; + CHLocalsPtr2 -= 1; + + + /* The defining rule used here is as follows. */ + /* An edge pixels has 3-5 changed locals. */ + /* And one or more of these changed locals has itself got 7-8 + changed locals. */ + + if ( RowType == NOT_EDGE_ROW ){ + /* Loop for all pixels in the row. */ + for ( i = 0; i < ppi->PlaneWidth; i += HFRAGPIXELS ){ + /* Does the fragment contain anything interesting to work with. */ + if ( *DispFragPtr == CANDIDATE_BLOCK ){ + /* Reset the cumulative fragment score. */ + FragScore = 0; + + /* Pixels grouped along the row into fragments */ + for ( j = 0; j < HFRAGPIXELS; j++ ){ + /* How many changed locals has the current pixel got. */ + changed_locals = ChangedLocalsPtr[j]; + + /* Is the pixel a suitable candidate */ + if ( (changed_locals > 2) && (changed_locals < 6) ){ + /* The pixel may qualify... have a closer look. */ + BodyNeighbours = 0; + + /* Count the number of "BodyNeighbours" .. Pixels that + have 7 or more changed neighbours. */ + if ( (i > 0) || (j > 0 ) ){ + if ( CHLocalsPtr0[0] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr1[0] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr2[0] >= 7 ) + BodyNeighbours++; + } + + if ( CHLocalsPtr0[1] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr2[1] >= 7 ) + BodyNeighbours++; + + if ( (i + j) < LastRowIndex ){ + if ( CHLocalsPtr0[2] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr1[2] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr2[2] >= 7 ) + BodyNeighbours++; + } + + if ( BodyNeighbours > 0 ){ + AbsDiff = abs( YUVDiffsPtr[j] ); + Score = (ogg_int32_t) + ( (double)(BodyNeighbours * + BodyNeighbourScore) * + ppi->AbsDiff_ScoreMultiplierTable[AbsDiff] ); + if ( Score < 1 ) + Score = 1; + + /* Increment the score by a value determined by the + number of body neighbours. */ + PixelNoiseScorePtr[j] += (unsigned char)Score; + FragScore += (ogg_uint32_t)Score; + } + } + + /* Increment pointers into changed locals buffer */ + CHLocalsPtr0 ++; + CHLocalsPtr1 ++; + CHLocalsPtr2 ++; + } + + /* Add fragment score (with plane correction factor) into main + data structure */ + *FragScorePtr += (ogg_int32_t)(FragScore * + ppi->YUVPlaneCorrectionFactor); + + /* If score is greater than trip threshold then mark blcok for + update. */ + if ( *FragScorePtr > ppi->BlockThreshold ){ + *DispFragPtr = BLOCK_CODED_LOW; + } + + }else{ + /* Nothing to do for this fragment group */ + /* Advance pointers into changed locals buffer */ + CHLocalsPtr0 += HFRAGPIXELS; + CHLocalsPtr1 += HFRAGPIXELS; + CHLocalsPtr2 += HFRAGPIXELS; + } + + /* Increment the various pointers */ + FragScorePtr++; + DispFragPtr++; + PixelNoiseScorePtr += HFRAGPIXELS; + ChangedLocalsPtr += HFRAGPIXELS; + YUVDiffsPtr += HFRAGPIXELS; + } + }else{ + /* This is either the top or bottom row of pixels in a plane. */ + /* Loop for all pixels in the row. */ + for ( i = 0; i < ppi->PlaneWidth; i += HFRAGPIXELS ){ + /* Does the fragment contain anything interesting to work with. */ + if ( *DispFragPtr == CANDIDATE_BLOCK ){ + /* Reset the cumulative fragment score. */ + FragScore = 0; + + /* Pixels grouped along the row into fragments */ + for ( j = 0; j < HFRAGPIXELS; j++ ){ + /* How many changed locals has the current pixel got. */ + changed_locals = ChangedLocalsPtr[j]; + + /* Is the pixel a suitable candidate */ + if ( (changed_locals > 2) && (changed_locals < 6) ){ + /* The pixel may qualify... have a closer look. */ + BodyNeighbours = 0; + + /* Count the number of "BodyNeighbours" .. Pixels + that have 7 or more changed neighbours. */ + if ( RowType == LAST_ROW ){ + /* Test for cases where it could be the first pixel on + the line */ + if ( (i > 0) || (j > 0) ){ + if ( CHLocalsPtr0[0] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr1[0] >= 7 ) + BodyNeighbours++; + } + + if ( CHLocalsPtr0[1] >= 7 ) + BodyNeighbours++; + + /* Test for the end of line case */ + if ( (i + j) < LastRowIndex ){ + if ( CHLocalsPtr0[2] >= 7 ) + BodyNeighbours++; + + if ( CHLocalsPtr1[2] >= 7 ) + BodyNeighbours++; + } + }else{ + /* First Row */ + /* Test for cases where it could be the first pixel on + the line */ + if ( (i > 0) || (j > 0) ){ + if ( CHLocalsPtr1[0] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr2[0] >= 7 ) + BodyNeighbours++; + } + + /* Test for the end of line case */ + if ( CHLocalsPtr2[1] >= 7 ) + BodyNeighbours++; + + if ( (i + j) < LastRowIndex ){ + if ( CHLocalsPtr1[2] >= 7 ) + BodyNeighbours++; + if ( CHLocalsPtr2[2] >= 7 ) + BodyNeighbours++; + } + } + + /* Allocate a score according to the number of Body neighbours. */ + if ( BodyNeighbours > 0 ){ + AbsDiff = abs( YUVDiffsPtr[j] ); + Score = (ogg_int32_t) + ( (double)(BodyNeighbours * BodyNeighbourScore) * + ppi->AbsDiff_ScoreMultiplierTable[AbsDiff] ); + if ( Score < 1 ) + Score = 1; + + PixelNoiseScorePtr[j] += (unsigned char)Score; + FragScore += (ogg_uint32_t)Score; + } + } + + /* Increment pointers into changed locals buffer */ + CHLocalsPtr0 ++; + CHLocalsPtr1 ++; + CHLocalsPtr2 ++; + } + + /* Add fragment score (with plane correction factor) into main + data structure */ + *FragScorePtr += + (ogg_int32_t)(FragScore * ppi->YUVPlaneCorrectionFactor); + + /* If score is greater than trip threshold then mark blcok for + update. */ + if ( *FragScorePtr > ppi->BlockThreshold ){ + *DispFragPtr = BLOCK_CODED_LOW; + } + + }else{ + /* Nothing to do for this fragment group */ + /* Advance pointers into changed locals buffer */ + CHLocalsPtr0 += HFRAGPIXELS; + CHLocalsPtr1 += HFRAGPIXELS; + CHLocalsPtr2 += HFRAGPIXELS; + } + + /* Increment the various pointers */ + FragScorePtr++; + DispFragPtr++; + PixelNoiseScorePtr += HFRAGPIXELS; + ChangedLocalsPtr += HFRAGPIXELS; + YUVDiffsPtr += HFRAGPIXELS; + } + } +} + +static void PixelLineSearch( PP_INSTANCE *ppi, + unsigned char * ChangedLocalsPtr, + ogg_int32_t RowNumber, + ogg_int32_t ColNumber, + unsigned char direction, + ogg_uint32_t * line_length ){ + /* Exit if the pixel does not qualify or we have fallen off the edge + of either the image plane or the row. */ + if ( ((*ChangedLocalsPtr) <= 1) || + ((*ChangedLocalsPtr) >= 6) || + (RowNumber < 0) || + (RowNumber >= ppi->PlaneHeight) || + (ColNumber < 0) || + (ColNumber >= ppi->PlaneWidth) ){ + /* If not then it isn't part of any line. */ + return; + } + + if (*line_length < ppi->MaxLineSearchLen){ + ogg_uint32_t TmpLineLength; + ogg_uint32_t BestLineLength; + unsigned char * search_ptr; + + /* Increment the line length to include this pixel. */ + *line_length += 1; + BestLineLength = *line_length; + + /* Continue search */ + /* up */ + if ( direction == UP ){ + TmpLineLength = *line_length; + + search_ptr = ChangedLocalsPtr - ppi->PlaneWidth; + if ( search_ptr < ppi->ChLocals ) + search_ptr += ppi->ChLocalsCircularBufferSize; + + PixelLineSearch( ppi, search_ptr, RowNumber - 1, ColNumber, + direction, &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + + /* up and left */ + if ( (BestLineLength < ppi->MaxLineSearchLen) && + ((direction == UP) || (direction == LEFT)) ){ + TmpLineLength = *line_length; + + search_ptr = ChangedLocalsPtr - ppi->PlaneWidth; + if ( search_ptr < ppi->ChLocals ) + search_ptr += ppi->ChLocalsCircularBufferSize; + search_ptr -= 1; + + PixelLineSearch( ppi, search_ptr, RowNumber - 1, ColNumber - 1, + direction, &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + + /* up and right */ + if ( (BestLineLength < ppi->MaxLineSearchLen) && + ((direction == UP) || (direction == RIGHT)) ){ + TmpLineLength = *line_length; + + search_ptr = ChangedLocalsPtr - ppi->PlaneWidth; + if ( search_ptr < ppi->ChLocals ) + search_ptr += ppi->ChLocalsCircularBufferSize; + search_ptr += 1; + + PixelLineSearch( ppi, search_ptr, RowNumber - 1, ColNumber + 1, + direction, &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + + /* left */ + if ( (BestLineLength < ppi->MaxLineSearchLen) && ( direction == LEFT ) ){ + TmpLineLength = *line_length; + PixelLineSearch( ppi, ChangedLocalsPtr - 1, RowNumber, ColNumber - 1, + direction, &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + + /* right */ + if ( (BestLineLength < ppi->MaxLineSearchLen) && ( direction == RIGHT ) ){ + TmpLineLength = *line_length; + PixelLineSearch( ppi, ChangedLocalsPtr + 1, RowNumber, ColNumber + 1, + direction, &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + + /* Down */ + if ( BestLineLength < ppi->MaxLineSearchLen ){ + TmpLineLength = *line_length; + if ( direction == DOWN ){ + search_ptr = ChangedLocalsPtr + ppi->PlaneWidth; + if ( search_ptr >= (ppi->ChLocals + ppi->ChLocalsCircularBufferSize) ) + search_ptr -= ppi->ChLocalsCircularBufferSize; + + PixelLineSearch( ppi, search_ptr, RowNumber + 1, ColNumber, direction, + &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + + + /* down and left */ + if ( (BestLineLength < ppi->MaxLineSearchLen) && + ((direction == DOWN) || (direction == LEFT)) ){ + TmpLineLength = *line_length; + + search_ptr = ChangedLocalsPtr + ppi->PlaneWidth; + if ( search_ptr >= (ppi->ChLocals + ppi->ChLocalsCircularBufferSize) ) + search_ptr -= ppi->ChLocalsCircularBufferSize; + search_ptr -= 1; + + PixelLineSearch( ppi, search_ptr, RowNumber + 1, ColNumber - 1, + direction, &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + + /* down and right */ + if ( (BestLineLength < ppi->MaxLineSearchLen) && + ((direction == DOWN) || (direction == RIGHT)) ){ + TmpLineLength = *line_length; + + search_ptr = ChangedLocalsPtr + ppi->PlaneWidth; + if ( search_ptr >= (ppi->ChLocals + ppi->ChLocalsCircularBufferSize) ) + search_ptr -= ppi->ChLocalsCircularBufferSize; + search_ptr += 1; + + PixelLineSearch( ppi, search_ptr, RowNumber + 1, ColNumber + 1, + direction, &TmpLineLength ); + + if ( TmpLineLength > BestLineLength ) + BestLineLength = TmpLineLength; + } + } + + /* Note the search value for this pixel. */ + *line_length = BestLineLength; + } +} + +static unsigned char LineSearchScorePixel( PP_INSTANCE *ppi, + unsigned char * ChangedLocalsPtr, + ogg_int32_t RowNumber, + ogg_int32_t ColNumber ){ + ogg_uint32_t line_length = 0; + ogg_uint32_t line_length2 = 0; + ogg_uint32_t line_length_score = 0; + ogg_uint32_t tmp_line_length = 0; + ogg_uint32_t tmp_line_length2 = 0; + + /* Look UP and Down */ + PixelLineSearch( ppi, ChangedLocalsPtr, RowNumber, + ColNumber, UP, &tmp_line_length ); + + if (tmp_line_length < ppi->MaxLineSearchLen) { + /* Look DOWN */ + PixelLineSearch( ppi, ChangedLocalsPtr, RowNumber, + ColNumber, DOWN, &tmp_line_length2 ); + line_length = tmp_line_length + tmp_line_length2 - 1; + + if ( line_length > ppi->MaxLineSearchLen ) + line_length = ppi->MaxLineSearchLen; + }else + line_length = tmp_line_length; + + /* If no max length line found then look left and right */ + if ( line_length < ppi->MaxLineSearchLen ){ + tmp_line_length = 0; + tmp_line_length2 = 0; + + PixelLineSearch( ppi, ChangedLocalsPtr, RowNumber, + ColNumber, LEFT, &tmp_line_length ); + if (tmp_line_length < ppi->MaxLineSearchLen){ + PixelLineSearch( ppi, ChangedLocalsPtr, RowNumber, + ColNumber, RIGHT, &tmp_line_length2 ); + line_length2 = tmp_line_length + tmp_line_length2 - 1; + + if ( line_length2 > ppi->MaxLineSearchLen ) + line_length2 = ppi->MaxLineSearchLen; + }else + line_length2 = tmp_line_length; + + } + + /* Take the largest line length */ + if ( line_length2 > line_length ) + line_length = line_length2; + + /* Create line length score */ + line_length_score = LineLengthScores[line_length]; + + return (unsigned char)line_length_score; +} + +static void LineSearchScoreRow( PP_INSTANCE *ppi, + unsigned char * ChangedLocalsPtr, + ogg_int16_t * YUVDiffsPtr, + unsigned char * PixelNoiseScorePtr, + ogg_uint32_t * FragScorePtr, + signed char * DispFragPtr, + ogg_int32_t RowNumber ){ + ogg_uint32_t AbsDiff; + unsigned char changed_locals = 0; + ogg_int32_t Score; + ogg_uint32_t FragScore; + ogg_int32_t i,j; + + /* The defining rule used here is as follows. */ + /* An edge pixels has 2-5 changed locals. */ + /* And one or more of these changed locals has itself got 7-8 + changed locals. */ + + /* Loop for all pixels in the row. */ + for ( i = 0; i < ppi->PlaneWidth; i += HFRAGPIXELS ){ + /* Does the fragment contain anything interesting to work with. */ + if ( *DispFragPtr == CANDIDATE_BLOCK ){ + /* Reset the cumulative fragment score. */ + FragScore = 0; + + /* Pixels grouped along the row into fragments */ + for ( j = 0; j < HFRAGPIXELS; j++ ){ + /* How many changed locals has the current pixel got. */ + changed_locals = ChangedLocalsPtr[j]; + + /* Is the pixel a suitable candidate for edge enhancement */ + if ( (changed_locals > 1) && (changed_locals < 6) && + (PixelNoiseScorePtr[j] < ppi->LineSearchTripTresh) ) { + Score = (ogg_int32_t) + LineSearchScorePixel( ppi, &ChangedLocalsPtr[j], RowNumber, i+j ); + + if ( Score ){ + AbsDiff = abs( YUVDiffsPtr[j] ); + Score = (ogg_int32_t) + ( (double)Score * ppi->AbsDiff_ScoreMultiplierTable[AbsDiff] ); + if ( Score < 1 ) + Score = 1; + + PixelNoiseScorePtr[j] += (unsigned char)Score; + FragScore += (ogg_uint32_t)Score; + } + } + } + + /* Add fragment score (with plane correction factor) into main + data structure */ + *FragScorePtr += + (ogg_int32_t)(FragScore * ppi->YUVPlaneCorrectionFactor); + + /* If score is greater than trip threshold then mark blcok for update. */ + if ( *FragScorePtr > ppi->BlockThreshold ){ + *DispFragPtr = BLOCK_CODED_LOW; + } + } + + /* Increment the various pointers */ + FragScorePtr++; + DispFragPtr++; + PixelNoiseScorePtr += HFRAGPIXELS; + ChangedLocalsPtr += HFRAGPIXELS; + YUVDiffsPtr += HFRAGPIXELS; + + } +} + +static void RowCopy( PP_INSTANCE *ppi, ogg_uint32_t BlockMapIndex ){ + + ogg_uint32_t i,j; + + ogg_uint32_t PixelIndex = ppi->ScanPixelIndexTable[BlockMapIndex]; + signed char * BlockMapPtr = &ppi->ScanDisplayFragments[BlockMapIndex]; + signed char * PrevFragmentsPtr = &ppi->PrevFragments[0][BlockMapIndex]; + + unsigned char * SourcePtr; + unsigned char * DestPtr; + + /* Copy pixels from changed blocks back to reference frame. */ + for ( i = 0; i < (ogg_uint32_t)ppi->PlaneHFragments; i ++ ){ + /* If the fragement is marked for update or was recently marked + for update (PrevFragmentsPtr[i]) */ + if ( (BlockMapPtr[i] > BLOCK_NOT_CODED) || + (PrevFragmentsPtr[i] == BLOCK_CODED) ){ + /* Set up the various pointers required. */ + SourcePtr = &ppi->ScanConfig.Yuv1ptr[PixelIndex]; + DestPtr = &ppi->ScanConfig.SrfWorkSpcPtr[PixelIndex]; + + /* For each row of the block */ + for ( j = 0; j < VFRAGPIXELS; j++ ){ + /* Copy the data unaltered from source to destination */ + memcpy(DestPtr,SourcePtr,8); + + /* Increment pointers for next line in the block */ + SourcePtr += ppi->PlaneWidth; + DestPtr += ppi->PlaneWidth; + } + } + + /* Increment pixel index for next block. */ + PixelIndex += HFRAGPIXELS; + } +} + +static void RowBarEnhBlockMap( PP_INSTANCE *ppi, + signed char * UpdatedBlockMapPtr, + signed char * BarBlockMapPtr, + ogg_uint32_t RowNumber ){ + int i; + + /* Start by blanking the row in the bar block map structure. */ + memset( BarBlockMapPtr, BLOCK_NOT_CODED, ppi->PlaneHFragments ); + + /* First row */ + if ( RowNumber == 0 ){ + + /* For each fragment in the row. */ + for ( i = 0; i < ppi->PlaneHFragments; i ++ ){ + /* Test for CANDIDATE_BLOCK or CANDIDATE_BLOCK_LOW. Uncoded or + coded blocks will be ignored. */ + if ( UpdatedBlockMapPtr[i] <= CANDIDATE_BLOCK ){ + /* Is one of the immediate neighbours updated in the main map. */ + /* Note special cases for blocks at the start and end of rows. */ + if ( i == 0 ){ + + if ((UpdatedBlockMapPtr[i+1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments]>BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments+1]>BLOCK_NOT_CODED ) ) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + + + }else if ( i == (ppi->PlaneHFragments - 1) ){ + + if ((UpdatedBlockMapPtr[i-1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments-1]>BLOCK_NOT_CODED) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments]>BLOCK_NOT_CODED) ) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + + }else{ + if((UpdatedBlockMapPtr[i-1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments-1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments+1] > BLOCK_NOT_CODED) ) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + } + } + } + + } else if ( RowNumber == (ogg_uint32_t)(ppi->PlaneVFragments-1)) { + + /* Last row */ + /* Used to read PlaneHFragments */ + + /* For each fragment in the row. */ + for ( i = 0; i < ppi->PlaneHFragments; i ++ ){ + /* Test for CANDIDATE_BLOCK or CANDIDATE_BLOCK_LOW + Uncoded or coded blocks will be ignored. */ + if ( UpdatedBlockMapPtr[i] <= CANDIDATE_BLOCK ){ + /* Is one of the immediate neighbours updated in the main map. */ + /* Note special cases for blocks at the start and end of rows. */ + if ( i == 0 ){ + if((UpdatedBlockMapPtr[i+1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments+1] > BLOCK_NOT_CODED )) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + + }else if ( i == (ppi->PlaneHFragments - 1) ){ + if((UpdatedBlockMapPtr[i-1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments-1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments] > BLOCK_NOT_CODED ) ) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + }else{ + if((UpdatedBlockMapPtr[i-1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments-1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments+1] > BLOCK_NOT_CODED) ) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + } + } + } + + }else{ + /* All other rows */ + /* For each fragment in the row. */ + for ( i = 0; i < ppi->PlaneHFragments; i ++ ){ + /* Test for CANDIDATE_BLOCK or CANDIDATE_BLOCK_LOW */ + /* Uncoded or coded blocks will be ignored. */ + if ( UpdatedBlockMapPtr[i] <= CANDIDATE_BLOCK ){ + /* Is one of the immediate neighbours updated in the main map. */ + /* Note special cases for blocks at the start and end of rows. */ + if ( i == 0 ){ + + if((UpdatedBlockMapPtr[i+1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments+1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments+1] > BLOCK_NOT_CODED) ) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + + }else if ( i == (ppi->PlaneHFragments - 1) ){ + + if((UpdatedBlockMapPtr[i-1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments-1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments-1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments] > BLOCK_NOT_CODED ) ) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + + }else{ + if((UpdatedBlockMapPtr[i-1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+1] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments-1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i-ppi->PlaneHFragments+1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments-1] > BLOCK_NOT_CODED)|| + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments] > BLOCK_NOT_CODED ) || + (UpdatedBlockMapPtr[i+ppi->PlaneHFragments+1] > BLOCK_NOT_CODED )) + BarBlockMapPtr[i] = BLOCK_CODED_BAR; + } + } + } + } +} + +static void BarCopyBack( PP_INSTANCE *ppi, + signed char * UpdatedBlockMapPtr, + signed char * BarBlockMapPtr ){ + ogg_int32_t i; + + /* For each fragment in the row. */ + for ( i = 0; i < ppi->PlaneHFragments; i ++ ){ + if ( BarBlockMapPtr[i] > BLOCK_NOT_CODED ){ + UpdatedBlockMapPtr[i] = BarBlockMapPtr[i]; + } + } +} + +static void AnalysePlane( PP_INSTANCE *ppi, + unsigned char * PlanePtr0, + unsigned char * PlanePtr1, + ogg_uint32_t FragArrayOffset, + ogg_uint32_t PWidth, + ogg_uint32_t PHeight, + ogg_uint32_t PStride ) { + unsigned char * RawPlanePtr0; + unsigned char * RawPlanePtr1; + + ogg_int16_t * YUVDiffsPtr; + ogg_int16_t * YUVDiffsPtr1; + ogg_int16_t * YUVDiffsPtr2; + + ogg_uint32_t FragIndex; + ogg_uint32_t ScoreFragIndex1; + ogg_uint32_t ScoreFragIndex2; + ogg_uint32_t ScoreFragIndex3; + ogg_uint32_t ScoreFragIndex4; + + int UpdatedOrCandidateBlocks = 0; + + unsigned char * ChLocalsPtr0; + unsigned char * ChLocalsPtr1; + unsigned char * ChLocalsPtr2; + + unsigned char * PixelsChangedPtr0; + unsigned char * PixelsChangedPtr1; + + unsigned char * PixelScoresPtr1; + unsigned char * PixelScoresPtr2; + + signed char * DispFragPtr0; + signed char * DispFragPtr1; + signed char * DispFragPtr2; + + ogg_uint32_t * FragScoresPtr1; + ogg_uint32_t * FragScoresPtr2; + + ogg_int32_t * RowDiffsPtr; + ogg_int32_t * RowDiffsPtr1; + ogg_int32_t * RowDiffsPtr2; + + ogg_int32_t i,j; + + ogg_int32_t RowNumber1; + ogg_int32_t RowNumber2; + ogg_int32_t RowNumber3; + ogg_int32_t RowNumber4; + + int EdgeRow; + ogg_int32_t LineSearchRowNumber = 0; + + /* Variables used as temporary stores for frequently used values. */ + ogg_int32_t Row0Mod3; + ogg_int32_t Row1Mod3; + ogg_int32_t Row2Mod3; + ogg_int32_t BlockRowPixels; + + /* Set pixel difference threshold */ + if ( FragArrayOffset == 0 ){ + /* Luminance */ + ppi->LevelThresh = (int)ppi->SgcLevelThresh; + ppi->NegLevelThresh = -ppi->LevelThresh; + + ppi->SrfThresh = (int)ppi->SRFGreyThresh; + ppi->NegSrfThresh = -ppi->SrfThresh; + + /* Scores correction for Y pixels. */ + ppi->YUVPlaneCorrectionFactor = 1.0; + + ppi->BlockThreshold = ppi->PrimaryBlockThreshold; + ppi->BlockSgcThresh = ppi->SgcThresh; + }else{ + /* Chrominance */ + ppi->LevelThresh = (int)ppi->SuvcLevelThresh; + ppi->NegLevelThresh = -ppi->LevelThresh; + + ppi->SrfThresh = (int)ppi->SRFColThresh; + ppi->NegSrfThresh = -ppi->SrfThresh; + + /* Scores correction for UV pixels. */ + ppi->YUVPlaneCorrectionFactor = 1.5; + + /* Block threholds different for subsampled U and V blocks */ + ppi->BlockThreshold = + (ppi->PrimaryBlockThreshold / ppi->UVBlockThreshCorrection); + ppi->BlockSgcThresh = + (ppi->SgcThresh / ppi->UVSgcCorrection); + } + + /* Initialise the SRF thresh table and pointer. */ + memset( ppi->SrfThreshTable, 1, 512 ); + for ( i = ppi->NegSrfThresh; i <= ppi->SrfThresh; i++ ) + ppi->SrfThreshTable[i+255] = 0; + + /* Initialise the PAK thresh table. */ + for ( i = -255; i <= 255; i++ ) + if ( ppi->SrfThreshTable[i+255] && + (i <= ppi->HighChange) && + (i >= ppi->NegHighChange) ) + ppi->SrfPakThreshTable[i+255] = 1; + else + ppi->SrfPakThreshTable[i+255] = 0; + + /* Initialise the SGc lookup table */ + for ( i = -255; i <= 255; i++ ){ + if ( i <= ppi->NegLevelThresh ) + ppi->SgcThreshTable[i+255] = -1; + else if ( i >= ppi->LevelThresh ) + ppi->SgcThreshTable[i+255] = 1; + else + ppi->SgcThreshTable[i+255] = 0; + } + + /* Set up plane dimension variables */ + ppi->PlaneHFragments = PWidth / HFRAGPIXELS; + ppi->PlaneVFragments = PHeight / VFRAGPIXELS; + ppi->PlaneWidth = PWidth; + ppi->PlaneHeight = PHeight; + ppi->PlaneStride = PStride; + + /* Set up local pointers into the raw image data. */ + RawPlanePtr0 = PlanePtr0; + RawPlanePtr1 = PlanePtr1; + + /* Note size and endo points for circular buffers. */ + ppi->YuvDiffsCircularBufferSize = YDIFF_CB_ROWS * ppi->PlaneWidth; + ppi->ChLocalsCircularBufferSize = CHLOCALS_CB_ROWS * ppi->PlaneWidth; + ppi->PixelMapCircularBufferSize = PMAP_CB_ROWS * ppi->PlaneWidth; + + /* Set high change thresh where PAK not needed */ + ppi->HighChange = ppi->SrfThresh * 4; + ppi->NegHighChange = -ppi->HighChange; + + /* Set up row difference pointers. */ + RowDiffsPtr = ppi->RowChangedPixels; + RowDiffsPtr1 = ppi->RowChangedPixels; + RowDiffsPtr2 = ppi->RowChangedPixels; + + BlockRowPixels = ppi->PlaneWidth * VFRAGPIXELS; + + for ( i = 0; i < (ppi->PlaneVFragments + 4); i++ ){ + RowNumber1 = (i - 1); + RowNumber2 = (i - 2); + RowNumber3 = (i - 3); + RowNumber4 = (i - 4); + + /* Pre calculate some frequently used values */ + Row0Mod3 = i % 3; + Row1Mod3 = RowNumber1 % 3; + Row2Mod3 = RowNumber2 % 3; + + /* For row diff scan last two iterations are invalid */ + if ( i < ppi->PlaneVFragments ){ + FragIndex = (i * ppi->PlaneHFragments) + FragArrayOffset; + YUVDiffsPtr = &ppi->yuv_differences[Row0Mod3 * BlockRowPixels]; + + PixelsChangedPtr0 = (&ppi->PixelChangedMap[Row0Mod3 * BlockRowPixels]); + DispFragPtr0 = &ppi->ScanDisplayFragments[FragIndex]; + + ChLocalsPtr0 = (&ppi->ChLocals[Row0Mod3 * BlockRowPixels]); + + } + + /* Set up the changed locals pointer to trail behind by one row of + fragments. */ + if ( i > 0 ){ + /* For last iteration the ch locals and noise scans are invalid */ + if ( RowNumber1 < ppi->PlaneVFragments ){ + ScoreFragIndex1 = (RowNumber1 * ppi->PlaneHFragments) + + FragArrayOffset; + + ChLocalsPtr1 = &ppi->ChLocals[Row1Mod3 * BlockRowPixels]; + PixelsChangedPtr1 = + &ppi->PixelChangedMap[(Row1Mod3) * BlockRowPixels]; + + PixelScoresPtr1 = &ppi->PixelScores[(RowNumber1 % 4) * BlockRowPixels]; + + YUVDiffsPtr1 = &ppi->yuv_differences[Row1Mod3 * BlockRowPixels]; + FragScoresPtr1 = &ppi->FragScores[ScoreFragIndex1]; + DispFragPtr1 = &ppi->ScanDisplayFragments[ScoreFragIndex1]; + + } + + if ( RowNumber2 >= 0 ){ + ScoreFragIndex2 = (RowNumber2 * ppi->PlaneHFragments) + + FragArrayOffset; + ChLocalsPtr2 = (&ppi->ChLocals[Row2Mod3 * BlockRowPixels]); + YUVDiffsPtr2 = &ppi->yuv_differences[Row2Mod3 * BlockRowPixels]; + + PixelScoresPtr2 = &ppi->PixelScores[(RowNumber2 % 4) * BlockRowPixels]; + + FragScoresPtr2 = &ppi->FragScores[ScoreFragIndex2]; + DispFragPtr2 = &ppi->ScanDisplayFragments[ScoreFragIndex2]; + }else{ + ChLocalsPtr2 = NULL; + } + }else{ + ChLocalsPtr1 = NULL; + ChLocalsPtr2 = NULL; + } + + /* Fast break out test for obvious yes and no cases in this row of + blocks */ + if ( i < ppi->PlaneVFragments ){ + UpdatedOrCandidateBlocks = + RowSadScan( ppi, RawPlanePtr0, RawPlanePtr1, DispFragPtr0 ); + if( ColSadScan( ppi, RawPlanePtr0, RawPlanePtr1, DispFragPtr0 ) ) + UpdatedOrCandidateBlocks = 1; + }else{ + /* Make sure we still call other functions if RowSadScan() disabled */ + UpdatedOrCandidateBlocks = 1; + } + + /* Consolidation and fast break ot tests at Row 1 level */ + if ( (i > 0) && (RowNumber1 < ppi->PlaneVFragments) ){ + /* Mark as coded any candidate block that lies adjacent to a + coded block. */ + SadPass2( ppi, RowNumber1, DispFragPtr1 ); + + /* Check results of diff scan in last set of blocks. */ + /* Eliminate NO cases and add in +SGC cases */ + ConsolidateDiffScanResults( ppi, &ppi->FragDiffPixels[ScoreFragIndex1], + &ppi->SameGreyDirPixels[ScoreFragIndex1], + DispFragPtr1 + ); + } + + for ( j = 0; j < VFRAGPIXELS; j++ ){ + /* Last two iterations do not apply */ + if ( i < ppi->PlaneVFragments ){ + /* Is the current fragment at an edge. */ + EdgeRow = ( ( (i == 0) && (j == 0) ) || + ( (i == (ppi->PlaneVFragments - 1)) && + (j == (VFRAGPIXELS - 1)) ) ); + + /* Clear the arrays that will be used for the changed pixels maps */ + memset( PixelsChangedPtr0, 0, ppi->PlaneWidth ); + + /* Difference scan and map each row */ + if ( UpdatedOrCandidateBlocks ){ + /* Scan the row for interesting differences */ + /* Also clear the array that will be used for changed locals map */ + RowDiffScan( ppi, RawPlanePtr0, RawPlanePtr1, + YUVDiffsPtr, PixelsChangedPtr0, + &ppi->SameGreyDirPixels[FragIndex], + DispFragPtr0, &ppi->FragDiffPixels[FragIndex], + RowDiffsPtr, ChLocalsPtr0, EdgeRow); + }else{ + /* Clear the array that will be used for changed locals map */ + memset( ChLocalsPtr0, 0, ppi->PlaneWidth ); + } + + /* The actual image plane pointers must be incremented by + stride as this may be different (more) than the plane + width. Our own internal buffers use ppi->PlaneWidth. */ + RawPlanePtr0 += ppi->PlaneStride; + RawPlanePtr1 += ppi->PlaneStride; + PixelsChangedPtr0 += ppi->PlaneWidth; + ChLocalsPtr0 += ppi->PlaneWidth; + YUVDiffsPtr += ppi->PlaneWidth; + RowDiffsPtr++; + } + + /* Run behind calculating the changed locals data and noise scores. */ + if ( ChLocalsPtr1 != NULL ){ + /* Last few iterations do not apply */ + if ( RowNumber1 < ppi->PlaneVFragments ){ + /* Blank the next row in the pixel scores data structure. */ + memset( PixelScoresPtr1, 0, ppi->PlaneWidth ); + + /* Don't bother doing anything if there are no changed + pixels in this row */ + if ( *RowDiffsPtr1 ){ + /* Last valid row is a special case */ + if ( i < ppi->PlaneVFragments ) + RowChangedLocalsScan( ppi, PixelsChangedPtr1, ChLocalsPtr1, + DispFragPtr1, + ( (((i-1)==0) && (j==0)) ? + FIRST_ROW : NOT_EDGE_ROW) ); + else + RowChangedLocalsScan( ppi, PixelsChangedPtr1, ChLocalsPtr1, + DispFragPtr1, + ((j==(VFRAGPIXELS-1)) ? + LAST_ROW : NOT_EDGE_ROW) ); + + NoiseScoreRow( ppi, PixelsChangedPtr1, ChLocalsPtr1, YUVDiffsPtr1, + PixelScoresPtr1, FragScoresPtr1, DispFragPtr1, + RowDiffsPtr1 ); + } + + ChLocalsPtr1 += ppi->PlaneWidth; + PixelsChangedPtr1 += ppi->PlaneWidth; + YUVDiffsPtr1 += ppi->PlaneWidth; + PixelScoresPtr1 += ppi->PlaneWidth; + RowDiffsPtr1 ++; + } + + /* Run edge enhancement algorithms */ + if ( RowNumber2 < ppi->PlaneVFragments ){ + if ( ChLocalsPtr2 != NULL ){ + /* Don't bother doing anything if there are no changed + pixels in this row */ + if ( *RowDiffsPtr2 ){ + if ( RowNumber1 < ppi->PlaneVFragments ){ + PrimaryEdgeScoreRow( ppi, ChLocalsPtr2, YUVDiffsPtr2, + PixelScoresPtr2, FragScoresPtr2, + DispFragPtr2, + ( (((i-2)==0) && (j==0)) ? + FIRST_ROW : NOT_EDGE_ROW) ); + }else{ + /* Edge enhancement */ + PrimaryEdgeScoreRow( ppi, ChLocalsPtr2, YUVDiffsPtr2, + PixelScoresPtr2, FragScoresPtr2, + DispFragPtr2, + ((j==(VFRAGPIXELS-1)) ? + LAST_ROW : NOT_EDGE_ROW) ); + } + + /* Recursive line search */ + LineSearchScoreRow( ppi, ChLocalsPtr2, YUVDiffsPtr2, + PixelScoresPtr2, FragScoresPtr2, + DispFragPtr2, + LineSearchRowNumber ); + } + + ChLocalsPtr2 += ppi->PlaneWidth; + YUVDiffsPtr2 += ppi->PlaneWidth; + PixelScoresPtr2 += ppi->PlaneWidth; + LineSearchRowNumber += 1; + RowDiffsPtr2 ++; + } + } + } + } + + /* BAR algorithm */ + if ( (RowNumber3 >= 0) && (RowNumber3 < ppi->PlaneVFragments) ){ + ScoreFragIndex3 = (RowNumber3 * ppi->PlaneHFragments) + FragArrayOffset; + RowBarEnhBlockMap(ppi, + &ppi->ScanDisplayFragments[ScoreFragIndex3], + &ppi->BarBlockMap[(RowNumber3 % 3) * + ppi->PlaneHFragments], + RowNumber3 ); + } + + /* BAR copy back and "ppi->SRF filtering" or "pixel copy back" */ + if ( (RowNumber4 >= 0) && (RowNumber4 < ppi->PlaneVFragments) ){ + /* BAR copy back stage must lag by one more row to avoid BAR blocks + being used in BAR descisions. */ + ScoreFragIndex4 = (RowNumber4 * ppi->PlaneHFragments) + FragArrayOffset; + + BarCopyBack(ppi, &ppi->ScanDisplayFragments[ScoreFragIndex4], + &ppi->BarBlockMap[(RowNumber4 % 3) * ppi->PlaneHFragments]); + + /* Copy over the data from any blocks marked for update into the + output buffer. */ + RowCopy(ppi, ScoreFragIndex4); + } + } +} + +ogg_uint32_t YUVAnalyseFrame( PP_INSTANCE *ppi, ogg_uint32_t * KFIndicator ){ + + /* Initialise the map arrays. */ + InitScanMapArrays(ppi); + + /* If the motion level in the previous frame was high then adjust + the high and low SAD thresholds to speed things up. */ + ppi->ModifiedGrpLowSadThresh = ppi->GrpLowSadThresh; + ppi->ModifiedGrpHighSadThresh = ppi->GrpHighSadThresh; + + + /* Set up the internal plane height and width variables. */ + ppi->VideoYPlaneWidth = ppi->ScanConfig.VideoFrameWidth; + ppi->VideoYPlaneHeight = ppi->ScanConfig.VideoFrameHeight; + ppi->VideoUVPlaneWidth = ppi->ScanConfig.VideoFrameWidth / 2; + ppi->VideoUVPlaneHeight = ppi->ScanConfig.VideoFrameHeight / 2; + + /* To start with the strides will be set from the widths */ + ppi->VideoYPlaneStride = ppi->VideoYPlaneWidth; + ppi->VideoUPlaneStride = ppi->VideoUVPlaneWidth; + ppi->VideoVPlaneStride = ppi->VideoUVPlaneWidth; + + /* Set up the plane pointers */ + ppi->YPlanePtr0 = ppi->ScanConfig.Yuv0ptr; + ppi->YPlanePtr1 = ppi->ScanConfig.Yuv1ptr; + ppi->UPlanePtr0 = (ppi->ScanConfig.Yuv0ptr + ppi->YFramePixels); + ppi->UPlanePtr1 = (ppi->ScanConfig.Yuv1ptr + ppi->YFramePixels); + ppi->VPlanePtr0 = (ppi->ScanConfig.Yuv0ptr + ppi->YFramePixels + + ppi->UVFramePixels); + ppi->VPlanePtr1 = (ppi->ScanConfig.Yuv1ptr + ppi->YFramePixels + + ppi->UVFramePixels); + + /* Check previous frame lists and if necessary mark extra blocks for + update. */ + SetFromPrevious(ppi); + + /* Ananlyse the U and V palnes. */ + AnalysePlane( ppi, ppi->UPlanePtr0, ppi->UPlanePtr1, + ppi->ScanYPlaneFragments, ppi->VideoUVPlaneWidth, + ppi->VideoUVPlaneHeight, ppi->VideoUPlaneStride ); + AnalysePlane( ppi, ppi->VPlanePtr0, ppi->VPlanePtr1, + (ppi->ScanYPlaneFragments + ppi->ScanUVPlaneFragments), + ppi->VideoUVPlaneWidth, ppi->VideoUVPlaneHeight, + ppi->VideoVPlaneStride ); + + /* Now analyse the Y plane. */ + AnalysePlane( ppi, ppi->YPlanePtr0, ppi->YPlanePtr1, 0, + ppi->VideoYPlaneWidth, ppi->VideoYPlaneHeight, + ppi->VideoYPlaneStride ); + + /* Update the list of previous frame block updates. */ + UpdatePreviousBlockLists(ppi); + + /* Create an output block map for the calling process. */ + CreateOutputDisplayMap( ppi, ppi->ScanDisplayFragments, + ppi->PrevFragments[0], + ppi->ScanConfig.disp_fragments ); + + /* Set the candidate key frame indicator (0-100) */ + *KFIndicator = ppi->KFIndicator; + + /* Return the normalised block count (this is actually a motion + level weighting not a true block count). */ + return ppi->OutputBlocksUpdated; +} + diff --git a/src/add-ons/media/plugins/theora/libtheora/theora/theora.h b/src/add-ons/media/plugins/theora/libtheora/theora/theora.h new file mode 100644 index 0000000000..ec20f313e0 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/theora/theora.h @@ -0,0 +1,148 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: theora.h,v 1.1 2004/02/24 13:50:14 shatty Exp $ + + ********************************************************************/ + +#ifndef _O_THEORA_H_ +#define _O_THEORA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LIBOGG2 +#include +#else +#include +/* This is temporary until libogg2 is more complete */ +ogg_buffer_state *ogg_buffer_create(void); +#endif + +typedef struct { + int y_width; + int y_height; + int y_stride; + + int uv_width; + int uv_height; + int uv_stride; + char *y; + char *u; + char *v; + +} yuv_buffer; + +typedef enum { + OC_CS_UNSPECIFIED, + OC_CS_ITU_REC_470M, + OC_CS_ITU_REC_470BG, +} theora_colorspace; + +typedef struct { + ogg_uint32_t width; + ogg_uint32_t height; + ogg_uint32_t frame_width; + ogg_uint32_t frame_height; + ogg_uint32_t offset_x; + ogg_uint32_t offset_y; + ogg_uint32_t fps_numerator; + ogg_uint32_t fps_denominator; + ogg_uint32_t aspect_numerator; + ogg_uint32_t aspect_denominator; + theora_colorspace colorspace; + int target_bitrate; + int quality; + int quick_p; /* quick encode/decode */ + + /* decode only */ + unsigned char version_major; + unsigned char version_minor; + unsigned char version_subminor; + + void *codec_setup; + + /* encode only */ + int dropframes_p; + int keyframe_auto_p; + ogg_uint32_t keyframe_frequency; + ogg_uint32_t keyframe_frequency_force; /* also used for decode init to + get granpos shift correct */ + ogg_uint32_t keyframe_data_target_bitrate; + ogg_int32_t keyframe_auto_threshold; + ogg_uint32_t keyframe_mindistance; + ogg_int32_t noise_sensitivity; + ogg_int32_t sharpness; + +} theora_info; + +typedef struct{ + theora_info *i; + ogg_int64_t granulepos; + + void *internal_encode; + void *internal_decode; + +} theora_state; + +typedef struct theora_comment{ + char **user_comments; + int *comment_lengths; + int comments; + char *vendor; + +} theora_comment; + +#define OC_FAULT -1 +#define OC_EINVAL -10 +#define OC_BADHEADER -20 +#define OC_NOTFORMAT -21 +#define OC_VERSION -22 +#define OC_IMPL -23 +#define OC_BADPACKET -24 +#define OC_NEWPACKET -25 + +extern const char *theora_version_string(void); +extern ogg_uint32_t theora_version_number(void); +extern int theora_encode_init(theora_state *th, theora_info *c); +extern int theora_encode_YUVin(theora_state *t, yuv_buffer *yuv); +extern int theora_encode_packetout( theora_state *t, int last_p, + ogg_packet *op); +extern int theora_encode_header(theora_state *t, ogg_packet *op); +extern int theora_encode_comment(theora_comment *tc, ogg_packet *op); +extern int theora_encode_tables(theora_state *t, ogg_packet *op); +extern int theora_decode_header(theora_info *ci, theora_comment *cc, + ogg_packet *op); +extern int theora_decode_init(theora_state *th, theora_info *c); +extern int theora_decode_packetin(theora_state *th,ogg_packet *op); +extern int theora_decode_YUVout(theora_state *th,yuv_buffer *yuv); +extern double theora_granule_time(theora_state *th,ogg_int64_t granulepos); +extern void theora_info_init(theora_info *c); +extern void theora_info_clear(theora_info *c); +extern void theora_clear(theora_state *t); + +extern void theora_comment_init(theora_comment *tc); +extern void theora_comment_add(theora_comment *tc, char *comment); +extern void theora_comment_add_tag(theora_comment *tc, + char *tag, char *value); +extern char *theora_comment_query(theora_comment *tc, char *tag, int count); +extern int theora_comment_query_count(theora_comment *tc, char *tag); +extern void theora_comment_clear(theora_comment *tc); + + +#ifdef __cplusplus +} +#endif + +#endif /* _O_THEORA_H_ */ diff --git a/src/add-ons/media/plugins/theora/libtheora/toplevel.c b/src/add-ons/media/plugins/theora/libtheora/toplevel.c new file mode 100644 index 0000000000..ffc24933a0 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/toplevel.c @@ -0,0 +1,1565 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: toplevel.c,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include +#include +#include "encoder_internal.h" +#include "toplevel_lookup.h" + +#define VERSION_MAJOR 3 +#define VERSION_MINOR 2 +#define VERSION_SUB 0 + +#define VENDOR_STRING "Xiph.Org libTheora I 20031026 3 2 0" + +#define A_TABLE_SIZE 29 +#define DF_CANDIDATE_WINDOW 5 + +static void EClearFragmentInfo(CP_INSTANCE * cpi){ + if(cpi->extra_fragments) + _ogg_free(cpi->extra_fragments); + if(cpi->FragmentLastQ) + _ogg_free(cpi->FragmentLastQ); + if(cpi->FragTokens) + _ogg_free(cpi->FragTokens); + if(cpi->FragTokenCounts) + _ogg_free(cpi->FragTokenCounts); + if(cpi->RunHuffIndices) + _ogg_free(cpi->RunHuffIndices); + if(cpi->LastCodedErrorScore) + _ogg_free(cpi->LastCodedErrorScore); + if(cpi->ModeList) + _ogg_free(cpi->ModeList); + if(cpi->MVList) + _ogg_free(cpi->MVList); + if(cpi->DCT_codes ) + _ogg_free( cpi->DCT_codes ); + if(cpi->DCTDataBuffer ) + _ogg_free( cpi->DCTDataBuffer); + if(cpi->quantized_list) + _ogg_free( cpi->quantized_list); + if(cpi->OriginalDC) + _ogg_free( cpi->OriginalDC); + if(cpi->PartiallyCodedFlags) + _ogg_free(cpi->PartiallyCodedFlags); + if(cpi->PartiallyCodedMbPatterns) + _ogg_free(cpi->PartiallyCodedMbPatterns); + if(cpi->UncodedMbFlags) + _ogg_free(cpi->UncodedMbFlags); + + if(cpi->BlockCodedFlags) + _ogg_free(cpi->BlockCodedFlags); + + cpi->extra_fragments = 0; + cpi->FragmentLastQ = 0; + cpi->FragTokens = 0; + cpi->FragTokenCounts = 0; + cpi->RunHuffIndices = 0; + cpi->LastCodedErrorScore = 0; + cpi->ModeList = 0; + cpi->MVList = 0; + cpi->DCT_codes = 0; + cpi->DCTDataBuffer = 0; + cpi->quantized_list = 0; + cpi->OriginalDC = 0; + cpi->BlockCodedFlags = 0; +} + +static void EInitFragmentInfo(CP_INSTANCE * cpi){ + + /* clear any existing info */ + EClearFragmentInfo(cpi); + + /* Perform Fragment Allocations */ + cpi->extra_fragments = + _ogg_malloc(cpi->pb.UnitFragments*sizeof(unsigned char)); + + /* A note to people reading and wondering why malloc returns aren't + checked: + + lines like the following that implement a general strategy of + 'check the return of malloc; a zero pointer means we're out of + memory!'...: + + if(!cpi->extra_fragments) { EDeleteFragmentInfo(cpi); return FALSE; } + + ...are not useful. It's true that many platforms follow this + malloc behavior, but many do not. The more modern malloc + strategy is only to allocate virtual pages, which are not mapped + until the memory on that page is touched. At *that* point, if + the machine is out of heap, the page fails to be mapped and a + SEGV is generated. + + That means that if we want to deal with out of memory conditions, + we *must* be prepared to process a SEGV. If we implement the + SEGV handler, there's no reason to to check malloc return; it is + a waste of code. */ + + cpi->FragmentLastQ = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->FragmentLastQ)); + cpi->FragTokens = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->FragTokens)); + cpi->OriginalDC = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->OriginalDC)); + cpi->FragTokenCounts = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->FragTokenCounts)); + cpi->RunHuffIndices = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->RunHuffIndices)); + cpi->LastCodedErrorScore = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->LastCodedErrorScore)); + cpi->BlockCodedFlags = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->BlockCodedFlags)); + cpi->ModeList = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(*cpi->ModeList)); + cpi->MVList = + _ogg_malloc(cpi->pb.UnitFragments* + sizeof(cpi->MVList)); + cpi->DCT_codes = + _ogg_malloc(64* + sizeof(*cpi->DCT_codes)); + cpi->DCTDataBuffer = + _ogg_malloc(64* + sizeof(*cpi->DCTDataBuffer)); + cpi->quantized_list = + _ogg_malloc(64* + sizeof(*cpi->quantized_list)); + cpi->PartiallyCodedFlags = + _ogg_malloc(cpi->pb.MacroBlocks* + sizeof(*cpi->PartiallyCodedFlags)); + cpi->PartiallyCodedMbPatterns = + _ogg_malloc(cpi->pb.MacroBlocks* + sizeof(*cpi->PartiallyCodedMbPatterns)); + cpi->UncodedMbFlags = + _ogg_malloc(cpi->pb.MacroBlocks* + sizeof(*cpi->UncodedMbFlags)); + +} + +static void EClearFrameInfo(CP_INSTANCE * cpi) { + if(cpi->ConvDestBuffer ) + _ogg_free(cpi->ConvDestBuffer ); + cpi->ConvDestBuffer = 0; + + if(cpi->yuv0ptr) + _ogg_free(cpi->yuv0ptr); + cpi->yuv0ptr = 0; + + if(cpi->yuv1ptr) + _ogg_free(cpi->yuv1ptr); + cpi->yuv1ptr = 0; + + if(cpi->OptimisedTokenListEb ) + _ogg_free(cpi->OptimisedTokenListEb); + cpi->OptimisedTokenListEb = 0; + + if(cpi->OptimisedTokenList ) + _ogg_free(cpi->OptimisedTokenList); + cpi->OptimisedTokenList = 0; + + if(cpi->OptimisedTokenListHi ) + _ogg_free(cpi->OptimisedTokenListHi); + cpi->OptimisedTokenListHi = 0; + + if(cpi->OptimisedTokenListPl ) + _ogg_free(cpi->OptimisedTokenListPl); + cpi->OptimisedTokenListPl = 0; + +} + +static void EInitFrameInfo(CP_INSTANCE * cpi){ + int FrameSize = cpi->pb.ReconYPlaneSize + 2 * cpi->pb.ReconUVPlaneSize; + + /* clear any existing info */ + EClearFrameInfo(cpi); + + /* allocate frames */ + cpi->ConvDestBuffer = + _ogg_malloc(FrameSize* + sizeof(*cpi->ConvDestBuffer)); + cpi->yuv0ptr = + _ogg_malloc(FrameSize* + sizeof(*cpi->yuv0ptr)); + cpi->yuv1ptr = + _ogg_malloc(FrameSize* + sizeof(*cpi->yuv1ptr)); + cpi->OptimisedTokenListEb = + _ogg_malloc(FrameSize* + sizeof(*cpi->OptimisedTokenListEb)); + cpi->OptimisedTokenList = + _ogg_malloc(FrameSize* + sizeof(*cpi->OptimisedTokenList)); + cpi->OptimisedTokenListHi = + _ogg_malloc(FrameSize* + sizeof(*cpi->OptimisedTokenListHi)); + cpi->OptimisedTokenListPl = + _ogg_malloc(FrameSize* + sizeof(*cpi->OptimisedTokenListPl)); +} + +static void SetupKeyFrame(CP_INSTANCE *cpi) { + /* Make sure the "last frame" buffer contains the first frame data + as well. */ + memcpy ( cpi->yuv0ptr, cpi->yuv1ptr, + cpi->pb.ReconYPlaneSize + 2 * cpi->pb.ReconUVPlaneSize ); + + /* Initialise the cpi->pb.display_fragments and other fragment + structures for the first frame. */ + memset( cpi->pb.display_fragments, 1, cpi->pb.UnitFragments ); + memset( cpi->extra_fragments, 1, cpi->pb.UnitFragments ); + + /* Set up for a BASE/KEY FRAME */ + SetFrameType( &cpi->pb,BASE_FRAME ); +} + +static void AdjustKeyFrameContext(CP_INSTANCE *cpi) { + ogg_uint32_t i; + ogg_uint32_t AvKeyFrameFrequency = + (ogg_uint32_t) (cpi->CurrentFrame / cpi->KeyFrameCount); + ogg_uint32_t AvKeyFrameBytes = + (ogg_uint32_t) (cpi->TotKeyFrameBytes / cpi->KeyFrameCount); + ogg_uint32_t TotalWeight=0; + ogg_int32_t AvKeyFramesPerSecond; + ogg_int32_t MinFrameTargetRate; + + /* Update the frame carry over. */ + cpi->TotKeyFrameBytes += oggpackB_bytes(cpi->oggbuffer); + + /* reset keyframe context and calculate weighted average of last + KEY_FRAME_CONTEXT keyframes */ + for( i = 0 ; i < KEY_FRAME_CONTEXT ; i ++ ) { + if ( i < KEY_FRAME_CONTEXT -1) { + cpi->PriorKeyFrameSize[i] = cpi->PriorKeyFrameSize[i+1]; + cpi->PriorKeyFrameDistance[i] = cpi->PriorKeyFrameDistance[i+1]; + } else { + cpi->PriorKeyFrameSize[KEY_FRAME_CONTEXT - 1] = + oggpackB_bytes(cpi->oggbuffer); + cpi->PriorKeyFrameDistance[KEY_FRAME_CONTEXT - 1] = + cpi->LastKeyFrame; + } + + AvKeyFrameBytes += PriorKeyFrameWeight[i] * + cpi->PriorKeyFrameSize[i]; + AvKeyFrameFrequency += PriorKeyFrameWeight[i] * + cpi->PriorKeyFrameDistance[i]; + TotalWeight += PriorKeyFrameWeight[i]; + } + AvKeyFrameBytes /= TotalWeight; + AvKeyFrameFrequency /= TotalWeight; + AvKeyFramesPerSecond = 100 * cpi->Configuration.OutputFrameRate / + AvKeyFrameFrequency ; + + /* Calculate a new target rate per frame allowing for average key + frame frequency over newest frames . */ + if ( 100 * cpi->Configuration.TargetBandwidth > + AvKeyFrameBytes * AvKeyFramesPerSecond && + (100 * cpi->Configuration.OutputFrameRate - AvKeyFramesPerSecond )){ + cpi->frame_target_rate = + (ogg_int32_t)(100* cpi->Configuration.TargetBandwidth - + AvKeyFrameBytes * AvKeyFramesPerSecond ) / + ( (100 * cpi->Configuration.OutputFrameRate - AvKeyFramesPerSecond ) ); + } else { + /* don't let this number get too small!!! */ + cpi->frame_target_rate = 1; + } + + /* minimum allowable frame_target_rate */ + MinFrameTargetRate = (cpi->Configuration.TargetBandwidth / + cpi->Configuration.OutputFrameRate) / 3; + + if(cpi->frame_target_rate < MinFrameTargetRate ) { + cpi->frame_target_rate = MinFrameTargetRate; + } + + cpi->LastKeyFrame = 1; + cpi->LastKeyFrameSize=oggpackB_bytes(cpi->oggbuffer); + +} + +static void UpdateFrame(CP_INSTANCE *cpi){ + + double CorrectionFactor; + + /* Reset the DC predictors. */ + cpi->pb.LastIntraDC = 0; + cpi->pb.InvLastIntraDC = 0; + cpi->pb.LastInterDC = 0; + cpi->pb.InvLastInterDC = 0; + + /* Initialise bit packing mechanism. */ +#ifndef LIBOGG2 + oggpackB_reset(cpi->oggbuffer); +#else + oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate); +#endif + /* mark as video frame */ + oggpackB_write(cpi->oggbuffer,0,1); + + /* Write out the frame header information including size. */ + WriteFrameHeader(cpi); + + /* Copy back any extra frags that are to be updated by the codec + as part of the background cleanup task */ + CopyBackExtraFrags(cpi); + + /* Encode the data. */ + EncodeData(cpi); + + /* Adjust drop frame trigger. */ + if ( GetFrameType(&cpi->pb) != BASE_FRAME ) { + /* Apply decay factor then add in the last frame size. */ + cpi->DropFrameTriggerBytes = + ((cpi->DropFrameTriggerBytes * (DF_CANDIDATE_WINDOW-1)) / + DF_CANDIDATE_WINDOW) + oggpackB_bytes(cpi->oggbuffer); + }else{ + /* Increase cpi->DropFrameTriggerBytes a little. Just after a key + frame may actually be a good time to drop a frame. */ + cpi->DropFrameTriggerBytes = + (cpi->DropFrameTriggerBytes * DF_CANDIDATE_WINDOW) / + (DF_CANDIDATE_WINDOW-1); + } + + /* Test for overshoot which may require a dropped frame next time + around. If we are already in a drop frame condition but the + previous frame was not dropped then the threshold for continuing + to allow dropped frames is reduced. */ + if ( cpi->DropFrameCandidate ) { + if ( cpi->DropFrameTriggerBytes > + (cpi->frame_target_rate * (DF_CANDIDATE_WINDOW+1)) ) + cpi->DropFrameCandidate = 1; + else + cpi->DropFrameCandidate = 0; + } else { + if ( cpi->DropFrameTriggerBytes > + (cpi->frame_target_rate * ((DF_CANDIDATE_WINDOW*2)-2)) ) + cpi->DropFrameCandidate = 1; + else + cpi->DropFrameCandidate = 0; + } + + /* Update the BpbCorrectionFactor variable according to whether or + not we were close enough with our selection of DCT quantiser. */ + if ( GetFrameType(&cpi->pb) != BASE_FRAME ) { + /* Work out a size correction factor. */ + CorrectionFactor = (double)oggpackB_bytes(cpi->oggbuffer) / + (double)cpi->ThisFrameTargetBytes; + + if ( (CorrectionFactor > 1.05) && + (cpi->pb.ThisFrameQualityValue < + cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ]) ) { + CorrectionFactor = 1.0 + ((CorrectionFactor - 1.0)/2); + if ( CorrectionFactor > 1.5 ) + cpi->BpbCorrectionFactor *= 1.5; + else + cpi->BpbCorrectionFactor *= CorrectionFactor; + + /* Keep BpbCorrectionFactor within limits */ + if ( cpi->BpbCorrectionFactor > MAX_BPB_FACTOR ) + cpi->BpbCorrectionFactor = MAX_BPB_FACTOR; + } else if ( (CorrectionFactor < 0.95) && + (cpi->pb.ThisFrameQualityValue > VERY_BEST_Q) ){ + CorrectionFactor = 1.0 - ((1.0 - CorrectionFactor)/2); + if ( CorrectionFactor < 0.75 ) + cpi->BpbCorrectionFactor *= 0.75; + else + cpi->BpbCorrectionFactor *= CorrectionFactor; + + /* Keep BpbCorrectionFactor within limits */ + if ( cpi->BpbCorrectionFactor < MIN_BPB_FACTOR ) + cpi->BpbCorrectionFactor = MIN_BPB_FACTOR; + } + } + + /* Adjust carry over and or key frame context. */ + if ( GetFrameType(&cpi->pb) == BASE_FRAME ) { + /* Adjust the key frame context unless the key frame was very small */ + AdjustKeyFrameContext(cpi); + } else { + /* Update the frame carry over */ + cpi->CarryOver += ((ogg_int32_t)cpi->frame_target_rate - + (ogg_int32_t)oggpackB_bytes(cpi->oggbuffer)); + } + cpi->TotalByteCount += oggpackB_bytes(cpi->oggbuffer); +} + +static void CompressFirstFrame(CP_INSTANCE *cpi) { + ogg_uint32_t i; + + /* set up context of key frame sizes and distances for more local + datarate control */ + for( i = 0 ; i < KEY_FRAME_CONTEXT ; i ++ ) { + cpi->PriorKeyFrameSize[i] = cpi->Configuration.KeyFrameDataTarget; + cpi->PriorKeyFrameDistance[i] = cpi->pb.info.keyframe_frequency_force; + } + + /* Keep track of the total number of Key Frames Coded. */ + cpi->KeyFrameCount = 1; + cpi->LastKeyFrame = 1; + cpi->TotKeyFrameBytes = 0; + + /* A key frame is not a dropped frame there for reset the count of + consequative dropped frames. */ + cpi->DropCount = 0; + + SetupKeyFrame(cpi); + + /* Calculate a new target rate per frame allowing for average key + frame frequency and size thus far. */ + if ( cpi->Configuration.TargetBandwidth > + ((cpi->Configuration.KeyFrameDataTarget * + cpi->Configuration.OutputFrameRate)/ + cpi->pb.info.keyframe_frequency) ) { + + cpi->frame_target_rate = + (ogg_int32_t)((cpi->Configuration.TargetBandwidth - + ((cpi->Configuration.KeyFrameDataTarget * + cpi->Configuration.OutputFrameRate)/ + cpi->pb.info.keyframe_frequency)) / + cpi->Configuration.OutputFrameRate); + }else + cpi->frame_target_rate = 1; + + /* Set baseline frame target rate. */ + cpi->BaseLineFrameTargetRate = cpi->frame_target_rate; + + /* A key frame is not a dropped frame there for reset the count of + consequative dropped frames. */ + cpi->DropCount = 0; + + /* Initialise drop frame trigger to 5 frames worth of data. */ + cpi->DropFrameTriggerBytes = cpi->frame_target_rate * DF_CANDIDATE_WINDOW; + + /* Set a target size for this key frame based upon the baseline + target and frequency */ + cpi->ThisFrameTargetBytes = cpi->Configuration.KeyFrameDataTarget; + + /* Get a DCT quantizer level for the key frame. */ + cpi->MotionScore = cpi->pb.UnitFragments; + + RegulateQ(cpi, cpi->pb.UnitFragments); + + cpi->pb.LastFrameQualityValue = cpi->pb.ThisFrameQualityValue; + + /* Initialise quantizer. */ + UpdateQC(cpi, cpi->pb.ThisFrameQualityValue ); + + /* Initialise the cpi->pb.display_fragments and other fragment + structures for the first frame. */ + for ( i = 0; i < cpi->pb.UnitFragments; i ++ ) + cpi->FragmentLastQ[i] = cpi->pb.ThisFrameQualityValue; + + /* Compress and output the frist frame. */ + PickIntra( cpi, + cpi->pb.YSBRows, cpi->pb.YSBCols); + UpdateFrame(cpi); + + /* Initialise the carry over rate targeting variables. */ + cpi->CarryOver = 0; + +} + +static void CompressKeyFrame(CP_INSTANCE *cpi){ + ogg_uint32_t i; + + /* Before we compress reset the carry over to the actual frame carry over */ + cpi->CarryOver = cpi->Configuration.TargetBandwidth * cpi->CurrentFrame / + cpi->Configuration.OutputFrameRate - cpi->TotalByteCount; + + /* Keep track of the total number of Key Frames Coded */ + cpi->KeyFrameCount += 1; + + /* A key frame is not a dropped frame there for reset the count of + consequative dropped frames. */ + cpi->DropCount = 0; + + SetupKeyFrame(cpi); + + /* set a target size for this frame */ + cpi->ThisFrameTargetBytes = (ogg_int32_t) cpi->frame_target_rate + + ( (cpi->Configuration.KeyFrameDataTarget - cpi->frame_target_rate) * + cpi->LastKeyFrame / cpi->pb.info.keyframe_frequency_force ); + + if ( cpi->ThisFrameTargetBytes > cpi->Configuration.KeyFrameDataTarget ) + cpi->ThisFrameTargetBytes = cpi->Configuration.KeyFrameDataTarget; + + /* Get a DCT quantizer level for the key frame. */ + cpi->MotionScore = cpi->pb.UnitFragments; + + RegulateQ(cpi, cpi->pb.UnitFragments); + + cpi->pb.LastFrameQualityValue = cpi->pb.ThisFrameQualityValue; + + /* Initialise DCT tables. */ + UpdateQC(cpi, cpi->pb.ThisFrameQualityValue ); + + /* Initialise the cpi->pb.display_fragments and other fragment + structures for the first frame. */ + for ( i = 0; i < cpi->pb.UnitFragments; i ++ ) + cpi->FragmentLastQ[i] = cpi->pb.ThisFrameQualityValue; + + + /* Compress and output the frist frame. */ + PickIntra( cpi, + cpi->pb.YSBRows, cpi->pb.YSBCols); + UpdateFrame(cpi); + +} + +static void CompressFrame( CP_INSTANCE *cpi) { + ogg_int32_t min_blocks_per_frame; + ogg_uint32_t i; + int DropFrame = 0; + ogg_uint32_t ResidueBlocksAdded=0; + ogg_uint32_t KFIndicator = 0; + + double QModStep; + double QModifier = 1.0; + + /* Clear down the macro block level mode and MV arrays. */ + for ( i = 0; i < cpi->pb.UnitFragments; i++ ) { + cpi->pb.FragCodingMethod[i] = CODE_INTER_NO_MV; /* Default coding mode */ + cpi->pb.FragMVect[i].x = 0; + cpi->pb.FragMVect[i].y = 0; + } + + /* Default to normal frames. */ + SetFrameType( &cpi->pb, NORMAL_FRAME ); + + /* Clear down the difference arrays for the current frame. */ + memset( cpi->pb.display_fragments, 0, cpi->pb.UnitFragments ); + memset( cpi->extra_fragments, 0, cpi->pb.UnitFragments ); + + /* Calculate the target bytes for this frame. */ + cpi->ThisFrameTargetBytes = cpi->frame_target_rate; + + /* Correct target to try and compensate for any overall rate error + that is developing */ + + /* Set the max allowed Q for this frame based upon carry over + history. First set baseline worst Q for this frame */ + cpi->Configuration.ActiveMaxQ = cpi->Configuration.MaxQ + 10; + if ( cpi->Configuration.ActiveMaxQ >= Q_TABLE_SIZE ) + cpi->Configuration.ActiveMaxQ = Q_TABLE_SIZE - 1; + + /* Make a further adjustment based upon the carry over and recent + history.. cpi->Configuration.ActiveMaxQ reduced by 1 for each 1/2 + seconds worth of -ve carry over up to a limit of 6. Also + cpi->Configuration.ActiveMaxQ reduced if frame is a + "DropFrameCandidate". Remember that if we are behind the bit + target carry over is -ve. */ + if ( cpi->CarryOver < 0 ) { + if ( cpi->DropFrameCandidate ) { + cpi->Configuration.ActiveMaxQ -= 4; + } + + if ( cpi->CarryOver < + -((ogg_int32_t)cpi->Configuration.TargetBandwidth*3) ) + cpi->Configuration.ActiveMaxQ -= 6; + else + cpi->Configuration.ActiveMaxQ += + (ogg_int32_t) ((cpi->CarryOver*2) / + (ogg_int32_t)cpi->Configuration.TargetBandwidth); + + /* Check that we have not dropped quality too far */ + if ( cpi->Configuration.ActiveMaxQ < cpi->Configuration.MaxQ ) + cpi->Configuration.ActiveMaxQ = cpi->Configuration.MaxQ; + } + + /* Calculate the Q Modifier step size required to cause a step down + from full target bandwidth to 40% of target between max Q and + best Q */ + QModStep = 0.5 / (double)((Q_TABLE_SIZE - 1) - + cpi->Configuration.ActiveMaxQ); + + /* Set up the cpi->QTargetModifier[] table. */ + for ( i = 0; i < cpi->Configuration.ActiveMaxQ; i++ ) { + cpi->QTargetModifier[i] = QModifier; + } + for ( i = cpi->Configuration.ActiveMaxQ; i < Q_TABLE_SIZE; i++ ) { + cpi->QTargetModifier[i] = QModifier; + QModifier -= QModStep; + } + + /* if we are allowed to drop frames and are falling behind (eg more + than x frames worth of bandwidth) */ + if ( cpi->pb.info.dropframes_p && + ( cpi->DropCount < cpi->MaxConsDroppedFrames) && + ( cpi->CarryOver < + -((ogg_int32_t)cpi->Configuration.TargetBandwidth)) && + ( cpi->DropFrameCandidate) ) { + /* (we didn't do this frame so we should have some left over for + the next frame) */ + cpi->CarryOver += cpi->frame_target_rate; + DropFrame = 1; + cpi->DropCount ++; + + /* Adjust DropFrameTriggerBytes to account for the saving achieved. */ + cpi->DropFrameTriggerBytes = + (cpi->DropFrameTriggerBytes * + (DF_CANDIDATE_WINDOW-1))/DF_CANDIDATE_WINDOW; + + /* Even if we drop a frame we should account for it when + considering key frame seperation. */ + cpi->LastKeyFrame++; + } else if ( cpi->CarryOver < + -((ogg_int32_t)cpi->Configuration.TargetBandwidth * 2) ) { + /* Reduce frame bit target by 1.75% for each 1/10th of a seconds + worth of -ve carry over down to a minimum of 65% of its + un-modified value. */ + + cpi->ThisFrameTargetBytes = + (ogg_uint32_t)(cpi->ThisFrameTargetBytes * 0.65); + } else if ( cpi->CarryOver < 0 ) { + /* Note that cpi->CarryOver is a -ve here hence 1.0 "+" ... */ + cpi->ThisFrameTargetBytes = + (ogg_uint32_t)(cpi->ThisFrameTargetBytes * + (1.0 + ( ((cpi->CarryOver * 10)/ + ((ogg_int32_t)cpi-> + Configuration.TargetBandwidth)) * 0.0175) )); + } + + if ( !DropFrame ) { + /* pick all the macroblock modes and motion vectors */ + ogg_uint32_t InterError; + ogg_uint32_t IntraError; + + + /* Set Baseline filter level. */ + ConfigurePP( &cpi->pp, cpi->pb.info.noise_sensitivity); + + /* Score / analyses the fragments. */ + cpi->MotionScore = YUVAnalyseFrame(&cpi->pp, &KFIndicator ); + + /* Get the baseline Q value */ + RegulateQ( cpi, cpi->MotionScore ); + + /* Recode blocks if the error score in last frame was high. */ + ResidueBlocksAdded = 0; + for ( i = 0; i < cpi->pb.UnitFragments; i++ ){ + if ( !cpi->pb.display_fragments[i] ){ + if ( cpi->LastCodedErrorScore[i] >= + ResidueErrorThresh[cpi->pb.FrameQIndex] ) { + cpi->pb.display_fragments[i] = 1; /* Force block update */ + cpi->extra_fragments[i] = 1; /* Insures up to date + pixel data is used. */ + ResidueBlocksAdded ++; + } + } + } + + /* Adjust the motion score to allow for residue blocks + added. These are assumed to have below average impact on + bitrate (Hence ResidueBlockFactor). */ + cpi->MotionScore = cpi->MotionScore + + (ResidueBlocksAdded / ResidueBlockFactor[cpi->pb.FrameQIndex]); + + /* Estimate the min number of blocks at best Q */ + min_blocks_per_frame = + (ogg_int32_t)(cpi->ThisFrameTargetBytes / + GetEstimatedBpb( cpi, VERY_BEST_Q )); + if ( min_blocks_per_frame == 0 ) + min_blocks_per_frame = 1; + + /* If we have less than this number then consider adding in some + extra blocks */ + if ( cpi->MotionScore < min_blocks_per_frame ) { + min_blocks_per_frame = + cpi->MotionScore + + (ogg_int32_t)(((min_blocks_per_frame - cpi->MotionScore) * 4) / 3 ); + UpRegulateDataStream( cpi, VERY_BEST_Q, min_blocks_per_frame ); + }else{ + /* Reset control variable for best quality final pass. */ + cpi->FinalPassLastPos = 0; + } + + /* Get the modified Q prediction taking into account extra blocks added. */ + RegulateQ( cpi, cpi->MotionScore ); + + /* Unless we are already well ahead (4 seconds of data) of the + projected bitrate */ + if ( cpi->CarryOver < + (ogg_int32_t)(cpi->Configuration.TargetBandwidth * 4) ){ + /* Look at the predicted Q (pbi->FrameQIndex). Adjust the + target bits for this frame based upon projected Q and + re-calculate. The idea is that if the Q is better than a + given (good enough) level then we will try and save some bits + for use in more difficult segments. */ + cpi->ThisFrameTargetBytes = + (ogg_int32_t) (cpi->ThisFrameTargetBytes * + cpi->QTargetModifier[cpi->pb.FrameQIndex]); + + /* Recalculate Q again */ + RegulateQ( cpi, cpi->MotionScore ); + } + + + /* Select modes and motion vectors for each of the blocks : return + an error score for inter and intra */ + PickModes( cpi, cpi->pb.YSBRows, cpi->pb.YSBCols, + cpi->pb.info.width, + &InterError, &IntraError ); + + /* decide whether we really should have made this frame a key frame */ + + if( cpi->pb.info.keyframe_auto_p){ + if( ( ( 2* IntraError < 5 * InterError ) + && ( KFIndicator >= (ogg_uint32_t) + cpi->pb.info.keyframe_auto_threshold) + && ( cpi->LastKeyFrame > cpi->pb.info.keyframe_mindistance) + ) || + (cpi->LastKeyFrame >= (ogg_uint32_t) + cpi->pb.info.keyframe_frequency_force) ){ + + CompressKeyFrame(cpi); /* Code a key frame */ + return; + } + + } + + /* Increment the frames since last key frame count */ + cpi->LastKeyFrame++; + + if ( cpi->MotionScore > 0 ){ + cpi->DropCount = 0; + + /* Proceed with the frame update. */ + UpdateFrame(cpi); + + /* Note the Quantizer used for each block coded. */ + for ( i = 0; i < cpi->pb.UnitFragments; i++ ){ + if ( cpi->pb.display_fragments[i] ){ + cpi->FragmentLastQ[i] = cpi->pb.ThisFrameQualityValue; + } + } + + } + }else{ + /* even if we 'drop' a frame, a placeholder must be written as we + currently assume fixed frame rate timebase as Ogg mapping + invariant */ + UpdateFrame(cpi); + } +} + +static int _ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + + +/********************** The toplevel: encode ***********************/ + +const char *theora_version_string(void){ + return VENDOR_STRING; +} + +ogg_uint32_t theora_version_number(void){ + return (VERSION_MAJOR<<16) + (VERSION_MINOR<<8) + (VERSION_SUB); +} + +int theora_encode_init(theora_state *th, theora_info *c){ + int i; + + CP_INSTANCE *cpi; + + memset(th, 0, sizeof(*th)); + th->internal_encode=cpi=_ogg_calloc(1,sizeof(*cpi)); + + c->version_major=VERSION_MAJOR; + c->version_minor=VERSION_MINOR; + c->version_subminor=VERSION_SUB; + + InitTmpBuffers(&cpi->pb); + InitPPInstance(&cpi->pp); + + /* Initialise Configuration structure to legal values */ + if(c->quality>63)c->quality=63; + if(c->quality<0)c->quality=32; + cpi->Configuration.BaseQ = c->quality; + cpi->Configuration.FirstFrameQ = c->quality; + cpi->Configuration.MaxQ = c->quality; + cpi->Configuration.ActiveMaxQ = c->quality; + + cpi->MVChangeFactor = 14; + cpi->FourMvChangeFactor = 8; + cpi->MinImprovementForNewMV = 25; + cpi->ExhaustiveSearchThresh = 2500; + cpi->MinImprovementForFourMV = 100; + cpi->FourMVThreshold = 10000; + cpi->BitRateCapFactor = 1.50; + cpi->InterTripOutThresh = 5000; + cpi->MVEnabled = 1; + cpi->InterCodeCount = 127; + cpi->BpbCorrectionFactor = 1.0; + cpi->GoldenFrameEnabled = 1; + cpi->InterPrediction = 1; + cpi->MotionCompensation = 1; + cpi->ThreshMapThreshold = 5; + cpi->MaxConsDroppedFrames = 1; + + /* Set encoder flags. */ + /* if not AutoKeyframing cpi->ForceKeyFrameEvery = is frequency */ + if(!c->keyframe_auto_p) + c->keyframe_frequency_force = c->keyframe_frequency; + + /* Set the frame rate variables. */ + if ( c->fps_numerator < 1 ) + c->fps_numerator = 1; + if ( c->fps_denominator < 1 ) + c->fps_denominator = 1; + + /* don't go too nuts on keyframe spacing; impose a high limit to + make certain the granulepos encoding strategy works */ + if(c->keyframe_frequency_force>32768)c->keyframe_frequency_force=32768; + if(c->keyframe_mindistance>32768)c->keyframe_mindistance=32768; + if(c->keyframe_mindistance>c->keyframe_frequency_force) + c->keyframe_mindistance=c->keyframe_frequency_force; + cpi->pb.keyframe_granule_shift=_ilog(c->keyframe_frequency_force-1); + + /* copy in config */ + memcpy(&cpi->pb.info,c,sizeof(*c)); + th->i=&cpi->pb.info; + th->granulepos=-1; + + /* Set up default values for QTargetModifier[Q_TABLE_SIZE] table */ + for ( i = 0; i < Q_TABLE_SIZE; i++ ) + cpi->QTargetModifier[i] = 1.0; + + /* Set up an encode buffer */ +#ifndef LIBOGG2 + cpi->oggbuffer = _ogg_malloc(sizeof(oggpack_buffer)); + oggpackB_writeinit(cpi->oggbuffer); +#else + cpi->oggbuffer = _ogg_malloc(oggpack_buffersize()); + cpi->oggbufferstate = ogg_buffer_create(); + oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate); +#endif + + /* Set data rate related variables. */ + cpi->Configuration.TargetBandwidth = (c->target_bitrate) / 8; + + cpi->Configuration.OutputFrameRate = + (double)( c->fps_numerator / + c->fps_denominator ); + + cpi->frame_target_rate = cpi->Configuration.TargetBandwidth / + cpi->Configuration.OutputFrameRate; + + /* Set key frame data rate target; this is nominal keyframe size */ + cpi->Configuration.KeyFrameDataTarget = (c->keyframe_data_target_bitrate * + c->fps_numerator / + c->fps_denominator ) / 8; + + /* Note the height and width in the pre-processor control structure. */ + cpi->ScanConfig.VideoFrameHeight = cpi->pb.info.height; + cpi->ScanConfig.VideoFrameWidth = cpi->pb.info.width; + + InitFrameDetails(&cpi->pb); + EInitFragmentInfo(cpi); + EInitFrameInfo(cpi); + + /* Set up pre-processor config pointers. */ + cpi->ScanConfig.Yuv0ptr = cpi->yuv0ptr; + cpi->ScanConfig.Yuv1ptr = cpi->yuv1ptr; + cpi->ScanConfig.SrfWorkSpcPtr = cpi->ConvDestBuffer; + cpi->ScanConfig.disp_fragments = cpi->pb.display_fragments; + cpi->ScanConfig.RegionIndex = cpi->pb.pixel_index_table; + + /* Initialise the pre-processor module. */ + ScanYUVInit(&cpi->pp, &(cpi->ScanConfig)); + + /* Initialise Motion compensation */ + InitMotionCompensation(cpi); + + /* Initialise the compression process. */ + /* We always start at frame 1 */ + cpi->CurrentFrame = 1; + + /* Reset the rate targeting correction factor. */ + cpi->BpbCorrectionFactor = 1.0; + + cpi->TotalByteCount = 0; + cpi->TotalMotionScore = 0; + + /* Up regulation variables. */ + cpi->FinalPassLastPos = 0; /* Used to regulate a final unrestricted pass. */ + cpi->LastEndSB = 0; /* Where we were in the loop last time. */ + cpi->ResidueLastEndSB = 0; /* Where we were in the residue update + loop last time. */ + + InitHuffmanSet(&cpi->pb); + + /* This makes sure encoder version specific tables are initialised */ + InitQTables(&cpi->pb); + + /* Indicate that the next frame to be compressed is the first in the + current clip. */ + cpi->ThisIsFirstFrame = 1; + cpi->readyflag = 1; + + return 0; +} + +int theora_encode_YUVin(theora_state *t, + yuv_buffer *yuv){ + ogg_int32_t i; + unsigned char *LocalDataPtr; + unsigned char *InputDataPtr; + CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode); + + if(!cpi->readyflag)return OC_EINVAL; + if(cpi->doneflag)return OC_EINVAL; + + /* If frame size has changed, abort out for now */ + if (yuv->y_height != (int)cpi->pb.info.height || + yuv->y_width != (int)cpi->pb.info.width ) + return(-1); + + + /* Copy over input YUV to internal YUV buffers. */ + /* we invert the image for backward compatibility with VP3 */ + /* First copy over the Y data */ + LocalDataPtr = cpi->yuv1ptr + yuv->y_width*(yuv->y_height - 1); + InputDataPtr = yuv->y; + for ( i = 0; i < yuv->y_height; i++ ){ + memcpy( LocalDataPtr, InputDataPtr, yuv->y_width ); + LocalDataPtr -= yuv->y_width; + InputDataPtr += yuv->y_stride; + } + + /* Now copy over the U data */ + LocalDataPtr = &cpi->yuv1ptr[(yuv->y_height * yuv->y_width)]; + LocalDataPtr += yuv->uv_width*(yuv->uv_height - 1); + InputDataPtr = yuv->u; + for ( i = 0; i < yuv->uv_height; i++ ){ + memcpy( LocalDataPtr, InputDataPtr, yuv->uv_width ); + LocalDataPtr -= yuv->uv_width; + InputDataPtr += yuv->uv_stride; + } + + /* Now copy over the V data */ + LocalDataPtr = + &cpi->yuv1ptr[((yuv->y_height*yuv->y_width)*5)/4]; + LocalDataPtr += yuv->uv_width*(yuv->uv_height - 1); + InputDataPtr = yuv->v; + for ( i = 0; i < yuv->uv_height; i++ ){ + memcpy( LocalDataPtr, InputDataPtr, yuv->uv_width ); + LocalDataPtr -= yuv->uv_width; + InputDataPtr += yuv->uv_stride; + } + + /* Special case for first frame */ + if ( cpi->ThisIsFirstFrame ){ + CompressFirstFrame(cpi); + cpi->ThisIsFirstFrame = 0; + cpi->ThisIsKeyFrame = 0; + } else if ( cpi->ThisIsKeyFrame ) { + CompressKeyFrame(cpi); + cpi->ThisIsKeyFrame = 0; + } else { + /* Compress the frame. */ + CompressFrame( cpi ); + } + + /* Update stats variables. */ + cpi->LastFrameSize = oggpackB_bytes(cpi->oggbuffer); + cpi->CurrentFrame++; + cpi->packetflag=1; + + t->granulepos= + ((cpi->CurrentFrame-cpi->LastKeyFrame-1)<pb.keyframe_granule_shift)+ + cpi->LastKeyFrame-1; + + return 0; +} + +int theora_encode_packetout( theora_state *t, int last_p, ogg_packet *op){ + CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode); + long bytes=oggpackB_bytes(cpi->oggbuffer); + + if(!bytes)return(0); + if(!cpi->packetflag)return(0); + if(cpi->doneflag)return(-1); + +#ifndef LIBOGG2 + op->packet=oggpackB_get_buffer(cpi->oggbuffer); +#else + op->packet=oggpackB_writebuffer(cpi->oggbuffer); +#endif + op->bytes=bytes; + op->b_o_s=0; + op->e_o_s=last_p; + + op->packetno=cpi->CurrentFrame; + op->granulepos=t->granulepos; + + cpi->packetflag=0; + if(last_p)cpi->doneflag=1; + + return 1; +} + +static void _tp_readbuffer(oggpack_buffer *opb, char *buf, const long len) +{ + long i; + long ret; + + for (i = 0; i < len; i++) { + theora_read(opb, 8, &ret); + *buf++=(char)ret; + } +} + +static void _tp_readlsbint(oggpack_buffer *opb, long *value) +{ + int i; + long ret[4]; + + for (i = 0; i < 4; i++) { + theora_read(opb,8,&ret[i]); + } + *value = ret[0]|ret[1]<<8|ret[2]<<16|ret[3]<<24; +} + +static void _tp_writebuffer(oggpack_buffer *opb, const char *buf, const long len) +{ + long i; + + for (i = 0; i < len; i++) + oggpackB_write(opb, *buf++, 8); +} + +static void _tp_writelsbint(oggpack_buffer *opb, long value) +{ + oggpackB_write(opb, value&0xFF, 8); + oggpackB_write(opb, value>>8&0xFF, 8); + oggpackB_write(opb, value>>16&0xFF, 8); + oggpackB_write(opb, value>>24&0xFF, 8); +} + +/* build the initial short header for stream recognition and format */ +int theora_encode_header(theora_state *t, ogg_packet *op){ + CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode); + +#ifndef LIBOGG2 + oggpackB_reset(cpi->oggbuffer); +#else + oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate); +#endif + oggpackB_write(cpi->oggbuffer,0x80,8); + _tp_writebuffer(cpi->oggbuffer, "theora", 6); + + oggpackB_write(cpi->oggbuffer,VERSION_MAJOR,8); + oggpackB_write(cpi->oggbuffer,VERSION_MINOR,8); + oggpackB_write(cpi->oggbuffer,VERSION_SUB,8); + + oggpackB_write(cpi->oggbuffer,cpi->pb.info.width>>4,16); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.height>>4,16); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.frame_width,24); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.frame_height,24); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.offset_x,8); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.offset_y,8); + + oggpackB_write(cpi->oggbuffer,cpi->pb.info.fps_numerator,32); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.fps_denominator,32); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.aspect_numerator,24); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.aspect_denominator,24); + + oggpackB_write(cpi->oggbuffer,cpi->pb.info.colorspace,8); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.target_bitrate,24); + oggpackB_write(cpi->oggbuffer,cpi->pb.info.quality,6); + + oggpackB_write(cpi->oggbuffer,cpi->pb.keyframe_granule_shift,5); + + oggpackB_write(cpi->oggbuffer,0,5); /* spare config bits */ + +#ifndef LIBOGG2 + op->packet=oggpackB_get_buffer(cpi->oggbuffer); +#else + op->packet=oggpackB_writebuffer(cpi->oggbuffer); +#endif + op->bytes=oggpackB_bytes(cpi->oggbuffer); + + op->b_o_s=1; + op->e_o_s=0; + + op->packetno=0; + + op->granulepos=0; + cpi->packetflag=0; + + return(0); +} + +/* build the comment header packet from the passed metadata */ +int theora_encode_comment(theora_comment *tc, ogg_packet *op) +{ + const char *vendor = theora_version_string(); + const int vendor_length = strlen(vendor); + oggpack_buffer *opb; + +#ifndef LIBOGG2 + opb = malloc(sizeof(oggpack_buffer)); + oggpackB_writeinit(opb); +#else + opb = malloc(oggpack_buffersize()); + oggpackB_writeinit(opb, ogg_buffer_create()); +#endif + oggpackB_write(opb, 0x81, 8); + _tp_writebuffer(opb, "theora", 6); + + _tp_writelsbint(opb, vendor_length); + _tp_writebuffer(opb, vendor, vendor_length); + + _tp_writelsbint(opb, tc->comments); + if(tc->comments){ + int i; + for(i=0;icomments;i++){ + if(tc->user_comments[i]){ + _tp_writelsbint(opb,tc->comment_lengths[i]); + _tp_writebuffer(opb,tc->user_comments[i],tc->comment_lengths[i]); + }else{ + oggpackB_write(opb,0,32); + } + } + } + op->bytes=oggpack_bytes(opb); + +#ifndef LIBOGG2 + /* So we're expecting the application with free this? */ + op->packet=malloc(oggpack_bytes(opb)); + memcpy(op->packet, oggpack_get_buffer(opb), oggpack_bytes(opb)); + oggpack_writeclear(opb); +#else + op->packet = oggpack_writebuffer(opb); + /* When the application puts op->packet into a stream_state object, + it becomes the property of libogg2's internal memory management. */ +#endif + + free(opb); + + op->b_o_s=0; + op->e_o_s=0; + + op->packetno=0; + op->granulepos=0; + + return (0); +} + +/* build the final header packet with the tables required + for decode */ +int theora_encode_tables(theora_state *t, ogg_packet *op){ + CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode); + +#ifndef LIBOGG2 + oggpackB_reset(cpi->oggbuffer); +#else + oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate); +#endif + oggpackB_write(cpi->oggbuffer,0x82,8); + _tp_writebuffer(cpi->oggbuffer,"theora",6); + + WriteQTables(&cpi->pb,cpi->oggbuffer); + WriteHuffmanTrees(cpi->pb.HuffRoot_VP3x,cpi->oggbuffer); + +#ifndef LIBOGG2 + op->packet=oggpackB_get_buffer(cpi->oggbuffer); +#else + op->packet=oggpackB_writebuffer(cpi->oggbuffer); +#endif + op->bytes=oggpackB_bytes(cpi->oggbuffer); + + op->b_o_s=0; + op->e_o_s=0; + + op->packetno=0; + + op->granulepos=0; + cpi->packetflag=0; + + return(0); +} + +void theora_info_init(theora_info *c) { + memset(c,0,sizeof(*c)); + c->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info)); +} + +void theora_info_clear(theora_info *c) { + codec_setup_info *ci=c->codec_setup; + if(ci){ + ClearHuffmanTrees(ci->HuffRoot); + _ogg_free(ci); + } + memset(c,0,sizeof(*c)); +} + +void theora_clear(theora_state *t){ + if(t){ + CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode); + PB_INSTANCE *pbi=(PB_INSTANCE *)(t->internal_decode); + + if(cpi){ + + ClearHuffmanSet(&cpi->pb); + ClearFragmentInfo(&cpi->pb); + ClearFrameInfo(&cpi->pb); + EClearFragmentInfo(cpi); + EClearFrameInfo(cpi); + ClearTmpBuffers(&cpi->pb); + ClearPPInstance(&cpi->pp); + + _ogg_free(cpi->oggbuffer); + _ogg_free(t->internal_encode); + } + + if(pbi){ + + theora_info_clear(&pbi->info); + ClearHuffmanSet(pbi); + ClearFragmentInfo(pbi); + ClearFrameInfo(pbi); + ClearPBInstance(pbi); + + _ogg_free(t->internal_decode); + } + + t->internal_encode=NULL; + t->internal_decode=NULL; + } +} + +/********************** The toplevel: decode ***********************/ + +static int _theora_unpack_info(theora_info *ci, oggpack_buffer *opb){ + long ret; + + theora_read(opb,8,&ret); + ci->version_major=(unsigned char)ret; + theora_read(opb,8,&ret); + ci->version_minor=(unsigned char)ret; + theora_read(opb,8,&ret); + ci->version_subminor=(unsigned char)ret; + + if(ci->version_major!=VERSION_MAJOR)return(OC_VERSION); + if(ci->version_minor>VERSION_MINOR)return(OC_VERSION); + + theora_read(opb,16,&ret); + ci->width=ret<<4; + theora_read(opb,16,&ret); + ci->height=ret<<4; + theora_read(opb,24,&ret); + ci->frame_width=ret; + theora_read(opb,24,&ret); + ci->frame_height=ret; + theora_read(opb,8,&ret); + ci->offset_x=ret; + theora_read(opb,8,&ret); + ci->offset_y=ret; + + theora_read(opb,32,&ret); + ci->fps_numerator=ret; + theora_read(opb,32,&ret); + ci->fps_denominator=ret; + theora_read(opb,24,&ret); + ci->aspect_numerator=ret; + theora_read(opb,24,&ret); + ci->aspect_denominator=ret; + + theora_read(opb,8,&ret); + ci->colorspace=ret; + theora_read(opb,24,&ret); + ci->target_bitrate=ret; + theora_read(opb,6,&ret); + ci->quality=ret=ret; + + theora_read(opb,5,&ret); + ci->keyframe_frequency_force=1<vendor=_ogg_calloc(1,len+1); + _tp_readbuffer(opb,tc->vendor, len); + tc->vendor[len]='\0'; + + _tp_readlsbint(opb,(long *) &tc->comments); + if(tc->comments<0)goto parse_err; + tc->user_comments=_ogg_calloc(tc->comments,sizeof(*tc->user_comments)); + tc->comment_lengths=_ogg_calloc(tc->comments,sizeof(*tc->comment_lengths)); + for(i=0;icomments;i++){ + _tp_readlsbint(opb,(long *)&len); + if(len<0)goto parse_err; + tc->user_comments[i]=_ogg_calloc(1,len+1); + _tp_readbuffer(opb,tc->user_comments[i],len); + tc->user_comments[i][len]='\0'; + tc->comment_lengths[i]=len; + } + return(0); + +parse_err: + theora_comment_clear(tc); + return(OC_BADHEADER); +} + +static int _theora_unpack_tables(theora_info *c, oggpack_buffer *opb){ + codec_setup_info *ci; + int ret; + + ci=(codec_setup_info *)c->codec_setup; + + ret=ReadQTables(ci, opb); + if(ret)return ret; + return ReadHuffmanTrees(ci, opb); +} + +int theora_decode_header(theora_info *ci, theora_comment *cc, ogg_packet *op){ + long ret; + oggpack_buffer *opb; + + if(!op)return OC_BADHEADER; + +#ifndef LIBOGG2 + opb = malloc(sizeof(oggpack_buffer)); + oggpackB_readinit(opb,op->packet,op->bytes); +#else + opb = malloc(oggpack_buffersize()); + oggpackB_readinit(opb,op->packet); +#endif + { + char id[6]; + int typeflag; + + theora_read(opb,8,&ret); + typeflag = ret; + if(!(typeflag&0x80)) { + free(opb); + return(OC_NOTFORMAT); + } + + _tp_readbuffer(opb,id,6); + if(memcmp(id,"theora",6)) { + free(opb); + return(OC_NOTFORMAT); + } + + switch(typeflag){ + case 0x80: + if(!op->b_o_s){ + /* Not the initial packet */ + free(opb); + return(OC_BADHEADER); + } + if(ci->version_major!=0){ + /* previously initialized info header */ + free(opb); + return OC_BADHEADER; + } + + ret = _theora_unpack_info(ci,opb); + free(opb); + return(ret); + + case 0x81: + if(ci->version_major==0){ + /* um... we didn't get the initial header */ + free(opb); + return(OC_BADHEADER); + } + + ret = _theora_unpack_comment(cc,opb); + free(opb); + return(ret); + + case 0x82: + if(ci->version_major==0 || cc->vendor==NULL){ + /* um... we didn't get the initial header or comments yet */ + free(opb); + return(OC_BADHEADER); + } + + ret = _theora_unpack_tables(ci,opb); + free(opb); + return(ret); + + default: + free(opb); + if(ci->version_major==0 || cc->vendor==NULL || + ((codec_setup_info *)ci->codec_setup)->HuffRoot[0]==NULL){ + /* we haven't gotten the three required headers */ + return(OC_BADHEADER); + } + /* ignore any trailing header packets for forward compatibility */ + return(OC_NEWPACKET); + } + } + /* I don't think it's possible to get this far, but better safe.. */ + free(opb); + return(OC_BADHEADER); +} + +int theora_decode_init(theora_state *th, theora_info *c){ + PB_INSTANCE *pbi; + codec_setup_info *ci; + + ci=(codec_setup_info *)c->codec_setup; + th->internal_decode=pbi=_ogg_calloc(1,sizeof(*pbi)); + + InitPBInstance(pbi); + memcpy(&pbi->info,c,sizeof(*c)); + pbi->info.codec_setup=NULL; + th->i=&pbi->info; + th->granulepos=-1; + + InitFrameDetails(pbi); + + pbi->keyframe_granule_shift=_ilog(c->keyframe_frequency_force-1); + + pbi->LastFrameQualityValue = 0; + pbi->DecoderErrorCode = 0; + + /* Clear down the YUVtoRGB conversion skipped list. */ + memset(pbi->skipped_display_fragments, 0, pbi->UnitFragments ); + + /* Initialise version specific quantiser values */ + CopyQTables(pbi, ci); + + /* Huffman setup */ + InitHuffmanTrees(pbi, ci); + + return(0); + +} + +int theora_decode_packetin(theora_state *th,ogg_packet *op){ + long ret; + PB_INSTANCE *pbi=(PB_INSTANCE *)(th->internal_decode); + + pbi->DecoderErrorCode = 0; + +#ifndef LIBOGG2 + oggpackB_readinit(pbi->opb,op->packet,op->bytes); +#else + oggpackB_readinit(pbi->opb,op->packet); +#endif + + /* verify that this is a video frame */ + theora_read(pbi->opb,1,&ret); + + if (ret==0) { + ret=LoadAndDecode(pbi); + + if(ret)return ret; + + if(pbi->PostProcessingLevel) + PostProcess(pbi); + + if(op->granulepos>-1) + th->granulepos=op->granulepos; + else{ + if(th->granulepos==-1){ + th->granulepos=0; + }else{ + if(pbi->FrameType==BASE_FRAME){ + long frames= th->granulepos & ((1<keyframe_granule_shift)-1); + th->granulepos>>=pbi->keyframe_granule_shift; + th->granulepos+=frames+1; + th->granulepos<<=pbi->keyframe_granule_shift; + }else + th->granulepos++; + } + } + + return(0); + } + + return OC_BADPACKET; +} + +int theora_decode_YUVout(theora_state *th,yuv_buffer *yuv){ + PB_INSTANCE *pbi=(PB_INSTANCE *)(th->internal_decode); + + yuv->y_width = pbi->info.width; + yuv->y_height = pbi->info.height; + yuv->y_stride = pbi->YStride; + + yuv->uv_width = pbi->info.width / 2; + yuv->uv_height = pbi->info.height / 2; + yuv->uv_stride = pbi->UVStride; + + if(pbi->PostProcessingLevel){ + yuv->y = &pbi->PostProcessBuffer[pbi->ReconYDataOffset]; + yuv->u = &pbi->PostProcessBuffer[pbi->ReconUDataOffset]; + yuv->v = &pbi->PostProcessBuffer[pbi->ReconVDataOffset]; + }else{ + yuv->y = &pbi->LastFrameRecon[pbi->ReconYDataOffset]; + yuv->u = &pbi->LastFrameRecon[pbi->ReconUDataOffset]; + yuv->v = &pbi->LastFrameRecon[pbi->ReconVDataOffset]; + } + + /* we must flip the internal representation, + so make the stride negative and start at the end */ + yuv->y += yuv->y_stride * (yuv->y_height - 1); + yuv->u += yuv->uv_stride * (yuv->uv_height - 1); + yuv->v += yuv->uv_stride * (yuv->uv_height - 1); + yuv->y_stride = - yuv->y_stride; + yuv->uv_stride = - yuv->uv_stride; + + return 0; +} + +/* returns, in seconds, absolute time of current packet in given + logical stream */ +double theora_granule_time(theora_state *th,ogg_int64_t granulepos){ + CP_INSTANCE *cpi=(CP_INSTANCE *)(th->internal_encode); + PB_INSTANCE *pbi=(PB_INSTANCE *)(th->internal_decode); + + if(cpi)pbi=&cpi->pb; + + if(granulepos>=0){ + ogg_int64_t iframe=granulepos>>pbi->keyframe_granule_shift; + ogg_int64_t pframe=granulepos-(iframe<keyframe_granule_shift); + + return (iframe+pframe)* + ((double)pbi->info.fps_denominator/pbi->info.fps_numerator); + + } + + return(-1); +} diff --git a/src/add-ons/media/plugins/theora/libtheora/toplevel_lookup.h b/src/add-ons/media/plugins/theora/libtheora/toplevel_lookup.h new file mode 100644 index 0000000000..f6a1d935f9 --- /dev/null +++ b/src/add-ons/media/plugins/theora/libtheora/toplevel_lookup.h @@ -0,0 +1,40 @@ +/******************************************************************** + * * + * 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-2003 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: toplevel_lookup.h,v 1.1 2004/02/24 13:50:13 shatty Exp $ + + ********************************************************************/ + +#include "encoder_internal.h" + +ogg_uint32_t PriorKeyFrameWeight[KEY_FRAME_CONTEXT] = { 1,2,3,4,5 }; + +/* Data structures controlling addition of residue blocks */ +ogg_uint32_t ResidueErrorThresh[Q_TABLE_SIZE] = { + 750, 700, 650, 600, 590, 580, 570, 560, + 550, 540, 530, 520, 510, 500, 490, 480, + 470, 460, 450, 440, 430, 420, 410, 400, + 390, 380, 370, 360, 350, 340, 330, 320, + 310, 300, 290, 280, 270, 260, 250, 245, + 240, 235, 230, 225, 220, 215, 210, 205, + 200, 195, 190, 185, 180, 175, 170, 165, + 160, 155, 150, 145, 140, 135, 130, 130 }; +ogg_uint32_t ResidueBlockFactor[Q_TABLE_SIZE] = { + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2 }; diff --git a/src/add-ons/media/plugins/theora/theoraCodecPlugin.cpp b/src/add-ons/media/plugins/theora/theoraCodecPlugin.cpp new file mode 100644 index 0000000000..bcc8a4c071 --- /dev/null +++ b/src/add-ons/media/plugins/theora/theoraCodecPlugin.cpp @@ -0,0 +1,284 @@ +#include +#include +#include +#include +#include +#include +#include +#include "theoraCodecPlugin.h" +#include "OggTheoraFormats.h" + +#define TRACE_THIS 1 +#if TRACE_THIS + #define TRACE printf +#else + #define TRACE(a...) +#endif + +#define DECODE_BUFFER_SIZE (32 * 1024) + + +static media_format +theora_decoded_media_format() +{ + media_format format; + format.type = B_MEDIA_RAW_VIDEO; + init_theora_media_raw_video_format(&format.u.raw_video); + return format; +} + + +/* + * TheoraDecoder + */ + + +TheoraDecoder::TheoraDecoder() +{ + TRACE("TheoraDecoder::TheoraDecoder\n"); + theora_info_init(&fInfo); + theora_comment_init(&fComment); + fStartTime = 0; + memset(&fOutput, sizeof(fOutput), 0); +} + + +TheoraDecoder::~TheoraDecoder() +{ + TRACE("TheoraDecoder::~TheoraDecoder\n"); + theora_info_clear(&fInfo); + theora_comment_clear(&fComment); +} + + +void +TheoraDecoder::GetCodecInfo(media_codec_info *info) +{ + strncpy(info->short_name, "theora-libtheora", sizeof(info->short_name)); + strncpy(info->pretty_name, "theora decoder[libtheora], by Andrew Bachmann", sizeof(info->pretty_name)); +} + + +status_t +TheoraDecoder::Setup(media_format *inputFormat, + const void *infoBuffer, int32 infoSize) +{ + TRACE("TheoraDecoder::Setup\n"); + if (!format_is_compatible(theora_encoded_media_format(),*inputFormat)) { + return B_MEDIA_BAD_FORMAT; + } + // grab header packets from meta data + if (inputFormat->MetaDataSize() != sizeof(std::vector)) { + TRACE("TheoraDecoder::Setup not called with ogg_packet meta data: not theora\n"); + return B_ERROR; + } + std::vector * packets = (std::vector *)inputFormat->MetaData(); + if (packets->size() != 3) { + TRACE("TheoraDecoder::Setup not called with three ogg_packets: not theora\n"); + return B_ERROR; + } + // parse header packet + if (theora_decode_header(&fInfo,&fComment,&(*packets)[0]) != 0) { + TRACE("TheoraDecoder::Setup: theora_synthesis_headerin failed: not theora header\n"); + return B_ERROR; + } + // parse comment packet + if (theora_decode_header(&fInfo,&fComment,&(*packets)[1]) != 0) { + TRACE("theoraDecoder::Setup: theora_synthesis_headerin failed: not theora comment\n"); + return B_ERROR; + } + // parse codec setup packet + if (theora_decode_header(&fInfo,&fComment,&(*packets)[2]) != 0) { + TRACE("theoraDecoder::Setup: theora_synthesis_headerin failed: not theora codec setup\n"); + return B_ERROR; + } + // initialize decoder + theora_decode_init(&fState,&fInfo); + // setup default output + media_format requested_format = theora_decoded_media_format(); + ((media_raw_video_format)requested_format.u.raw_video) = inputFormat->u.encoded_video.output; + return NegotiateOutputFormat(&requested_format); +} + + +status_t +TheoraDecoder::NegotiateOutputFormat(media_format *ioDecodedFormat) +{ + TRACE("TheoraDecoder::NegotiateOutputFormat\n"); + // BMediaTrack::DecodedFormat + // Pass in ioFormat the format that you want (with wildcards + // as applicable). The codec will find and return in ioFormat + // its best matching format. + // + // BMediaDecoder::SetOutputFormat + // sets the format the decoder should output. On return, + // the outputFormat is changed to match the actual format + // that will be output; this can be different if you + // specified any wildcards. + // + // Be R5 behavior seems to be that we can never fail. If we + // don't support the requested format, just return one we do. + media_format format = theora_decoded_media_format(); + if (fInfo.fps_denominator != 0) { + format.u.raw_video.field_rate = + (double)fInfo.fps_numerator / (double)fInfo.fps_denominator; + } + format.u.raw_video.first_active = fInfo.offset_y; + format.u.raw_video.last_active = fInfo.offset_y + fInfo.frame_height; + format.u.raw_video.pixel_width_aspect = fInfo.aspect_numerator; + format.u.raw_video.pixel_height_aspect = fInfo.aspect_denominator; + format.u.raw_video.display.line_width = fInfo.frame_width; + format.u.raw_video.display.line_count = fInfo.frame_height; + if (!format_is_compatible(format,*ioDecodedFormat)) { + *ioDecodedFormat = format; + } + ioDecodedFormat->SpecializeTo(&format); + // setup output variables + fOutput = ioDecodedFormat->u.raw_video; + return B_OK; +} + + +status_t +TheoraDecoder::Seek(uint32 seekTo, + int64 seekFrame, int64 *frame, + bigtime_t seekTime, bigtime_t *time) +{ + TRACE("TheoraDecoder::Seek\n"); + // throw the old samples away! +/* int samples = theora_synthesis_pcmout(&fDspState,&pcm); + theora_synthesis_read(&fDspState,samples); +*/ + return B_OK; +} + + +status_t +TheoraDecoder::Decode(void *buffer, int64 *frameCount, + media_header *mediaHeader, media_decode_info *info /* = 0 */) +{ + TRACE("TheoraDecoder::Decode\n"); + debugger("in"); + status_t status = B_OK; + + bool synced = false; + + // get a new packet + void *chunkBuffer; + int32 chunkSize; + media_header mh; + status = GetNextChunk(&chunkBuffer, &chunkSize, &mh); + if (status == B_LAST_BUFFER_ERROR) { + goto done; + } + if (status != B_OK) { + TRACE("TheoraDecoder::Decode: GetNextChunk failed\n"); + return status; + } + if (chunkSize != sizeof(ogg_packet)) { + TRACE("TheoraDecoder::Decode: chunk not ogg_packet-sized\n"); + return B_ERROR; + } + + // decode the packet + { + ogg_packet * packet = static_cast(chunkBuffer); + // push the packet in and get the decoded yuv output + theora_decode_packetin(&fState, packet); + yuv_buffer yuv; + theora_decode_YUVout(&fState, &yuv); + // now copy the decoded yuv output to the buffer + uint8 * out = static_cast(buffer); + // the following represents a simple YV12 [YUV12?] -> YUY2 [YCbCr422] transform + // it possibly (probably) doesn't work when bytes_per_line != line_width + uint draw_bytes_per_line = yuv.y_width + yuv.uv_width*2; + uint bytes_per_line = draw_bytes_per_line; + for (uint line = 0 ; line < fOutput.display.line_count ; line++) { + char * y = yuv.y; + char * u = yuv.u; + char * v = yuv.v; + for (uint pos = 0 ; pos < draw_bytes_per_line ; pos += 4) { + out[pos] = *(y++); + out[pos+1] = *(u++); + out[pos+2] = *(y++); + out[pos+3] = *(v++); + } + out += bytes_per_line; + yuv.y += yuv.y_stride; + if (line % 2 == 1) { + yuv.u += yuv.uv_stride; + yuv.v += yuv.uv_stride; + } + } + } + + if (!synced) { + if (mh.start_time > 0) { + mediaHeader->start_time = mh.start_time - (bigtime_t) (1000000LL / fOutput.field_rate); + synced = true; + } + } +done: + if (!synced) { + mediaHeader->start_time = fStartTime; + } + fStartTime = (bigtime_t) mediaHeader->start_time + (bigtime_t) (1000000LL / fOutput.field_rate); + + *frameCount = 1; + + return status; +} + + +/* + * TheoraDecoderPlugin + */ + + +Decoder * +TheoraDecoderPlugin::NewDecoder(uint index) +{ + static BLocker locker; + static bool initdone = false; + BAutolock lock(locker); + if (!initdone) { + initdone = true; + } + return new TheoraDecoder; +} + +static media_format theora_formats[1]; + +status_t +TheoraDecoderPlugin::GetSupportedFormats(media_format ** formats, size_t * count) +{ + media_format_description description = theora_description(); + media_format format = theora_encoded_media_format(); + + BMediaFormats mediaFormats; + status_t result = mediaFormats.InitCheck(); + if (result != B_OK) { + return result; + } + result = mediaFormats.MakeFormatFor(&description, 1, &format); + if (result != B_OK) { + return result; + } + theora_formats[0] = format; + + *formats = theora_formats; + *count = 1; + + return result; +} + + +/* + * instantiate_plugin + */ + + +MediaPlugin *instantiate_plugin() +{ + return new TheoraDecoderPlugin; +} diff --git a/src/add-ons/media/plugins/theora/theoraCodecPlugin.h b/src/add-ons/media/plugins/theora/theoraCodecPlugin.h new file mode 100644 index 0000000000..fce6b64c74 --- /dev/null +++ b/src/add-ons/media/plugins/theora/theoraCodecPlugin.h @@ -0,0 +1,45 @@ +#ifndef _THEORA_CODEC_PLUGIN_H_ +#define _THEORA_CODEC_PLUGIN_H_ + +#include "DecoderPlugin.h" + +#include "libtheora/theora/theora.h" + +class TheoraDecoder : public Decoder +{ +public: + TheoraDecoder(); + ~TheoraDecoder(); + + void GetCodecInfo(media_codec_info *info); + status_t Setup(media_format *inputFormat, + const void *infoBuffer, int32 infoSize); + + status_t NegotiateOutputFormat(media_format *ioDecodedFormat); + + status_t Seek(uint32 seekTo, + int64 seekFrame, int64 *frame, + bigtime_t seekTime, bigtime_t *time); + + + status_t Decode(void *buffer, int64 *frameCount, + media_header *mediaHeader, media_decode_info *info); + +private: + theora_info fInfo; + theora_comment fComment; + theora_state fState; + + bigtime_t fStartTime; + media_raw_video_format fOutput; +}; + + +class TheoraDecoderPlugin : public DecoderPlugin +{ +public: + Decoder * NewDecoder(uint index); + status_t GetSupportedFormats(media_format ** formats, size_t * count); +}; + +#endif _THEORA_CODEC_PLUGIN_H_