📄 scan.c
字号:
/********************************************************************
* *
* 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:
********************************************************************/
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "codec_internal.h"
#include "dsp.h"
#define MAX_SEARCH_LINE_LEN 7
#define SET8_0(ptr) \
((ogg_uint32_t *)ptr)[0] = 0x00000000; \
((ogg_uint32_t *)ptr)[1] = 0x00000000;
#define SET8_1(ptr) \
((ogg_uint32_t *)ptr)[0] = 0x01010101; \
((ogg_uint32_t *)ptr)[1] = 0x01010101;
#define SET8_8(ptr) \
((ogg_uint32_t *)ptr)[0] = 0x08080808; \
((ogg_uint32_t *)ptr)[1] = 0x08080808;
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 int RowSadScan( PP_INSTANCE *ppi,
unsigned char * YuvPtr1,
unsigned char * YuvPtr2,
signed char * DispFragPtr){
ogg_int32_t i, j;
ogg_uint32_t GrpSad;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -