?? skl_mpg4_anl.cpp
字號:
/******************************************************** * Some code. Copyright (C) 2003 by Pascal Massimino. * * All Rights Reserved. (http://skal.planet-d.net) * * For Educational/Academic use ONLY. See 'LICENSE.TXT'.* ********************************************************//* * skl_mpg4_anl.cpp * * Default Built-In analyzer for MPEG4 encoder ********************************************************/#ifndef SKL_AUTO_INCLUDE#include "./skl_mpg4_anl.h"#include <malloc.h> // for alloca()#if defined(__SUN__) || defined(__ALPHA__) || defined(__IRIX__) || defined(__HP__)#include <alloca.h> // for alloca() on Sun, Irix, HP, and Alpha#endifconst int CORE_VERSION = 5;//////////////////////////////////////////////////////////// alignment macros#ifdef SKL_USE_ASM#define SKL_ALIGN 15#else#define SKL_ALIGN 0#endif#define SKL_ALIGN_PTR(P,ALGN) ( ((SKL_SAFE_INT)(P) + (ALGN)) & ~(ALGN) )//////////////////////////////////////////////////////////#define ABS(x) (((x)<0) ? -(x) : (x))//#define BCOST(x) ABS(x)//#define BCOST(x) ( SKL_BMASKS::Log2(ABS(x)) )#define BCOST(x) (Code_Sizes[(x)])#define RND(Q) ((int)((Q)+.5))static inline int IS_VALID_MV(const SKL_MV MV) { return *(SKL_UINT32*)MV != 0x7fff7fff; }static inline int IS_EQUAL_MV(const SKL_MV a, const SKL_MV b) { return *(SKL_UINT32*)a == *(SKL_UINT32*)b; }static inline int IS_ZERO_MV(const SKL_MV MV) { return *(SKL_UINT32*)MV == 0; }//////////////////////////////////////////////////////////// Cursor to hold search parameters and results//////////////////////////////////////////////////////////struct ME_MAP; // note: for SSE2, *Src1 is supposed to be 16b-aligned!!typedef SKL_UINT32 (*METRIC)(const SKL_BYTE *Src1, const SKL_BYTE *Src2, SKL_INT32 BpS);typedef SKL_UINT32 (*METRIC_DEV)(const SKL_BYTE *Src, SKL_INT32 BpS);typedef SKL_UINT32 (*METRIC_AVRG)(const SKL_BYTE *Dst, const SKL_BYTE *Src1, const SKL_BYTE *Src2, SKL_INT32 BpS);typedef int (*SEARCH_MTHD)(ME_MAP * const Cursor);struct ME_MAP{ SKL_MV Pred, IPred, Best_MV; SKL_UINT32 Best_Sad; const SKL_BYTE *Src; // current frame pointer const SKL_BYTE *Ref; // ref frame, relative to Predictor vector int Lambda; int MV_Bits_Shift; int Sub_Prec_Shift; METRIC Metric; METRIC_AVRG Metric_Avrg; int Dir; // bits 0-7: last direction checked, bits 8-15: new direction to check static const SKL_BYTE MV_Bits0[32]; static SKL_BYTE MV_Code_Sizes0[7][2*2048]; static void Init_MV_Code_Sizes(); void Set_FCode(const int FCode, const int Prec); SKL_BYTE * Code_Sizes; SEARCH_MTHD Search_Method; int xo, yo; int BpS; int xm, xM, ym, yM; // MV Limits in full-pel units (disregarding sub-pel units) int xm_Sub, xM_Sub, ym_Sub, yM_Sub; // MV Limits in sub-pel units (either 1 or 2) int Range; // range in *full* pel // int Hit, Miss; // debug const SKL_BYTE *Src0, *Ref0; const SKL_MP4_INFOS * const Frame; SKL_BYTE *Scratch1; // 16x17 tmp buffer SKL_BYTE *Scratch2; // 17x16 tmp buffer enum { MAX_KEY = 2048, CACHE_SIZE = 8 }; // CACHE_SIZE must be a power of 2 SKL_UINT32 Key_Map[CACHE_SIZE*CACHE_SIZE]; // keys SKL_UINT32 Sad_Map[CACHE_SIZE*CACHE_SIZE]; // cache for SAD evaluated so far SKL_UINT32 Min_Key; // offset to avoid erasing Map too often inline void Set_MV_Predictor(const SKL_MV * const Src, const int MV_Stride, const int Blk, const int ABits); inline static void Set_FP_MV_Predictor(SKL_MV Pred, const SKL_MP4_MAP * const Map, const int Map_Stride, const int ABits); inline SKL_UINT32 Hash(int x, int y) const { return Min_Key + x + y*MAX_KEY + 1025*2048; } inline int Slot(int x, int y) const { return (x+y*CACHE_SIZE) & (CACHE_SIZE*CACHE_SIZE-1); } inline void New_Map() { if (Min_Key==0) SKL_BZERO(Key_Map, sizeof(Key_Map)); Min_Key += MAX_KEY*MAX_KEY; } SKL_UINT32 MV_Bits_Cost(const int x, const int y) const { return Lambda*(BCOST((x<<Sub_Prec_Shift)-Pred[0])+BCOST((y<<Sub_Prec_Shift)-Pred[1])); }// SKL_UINT32 MV_Bits_Cost(const int x, const int y) const { return Lambda*(BCOST(x-IPred[0])+BCOST(y-IPred[1])); } SKL_UINT32 MV_Bits_Cost_Raw(const int x, const int y) const { return Lambda*(BCOST(x-Pred[0])+BCOST(y-Pred[1])); } SKL_UINT32 Eval(int x, int y) const { const SKL_UINT32 Sad = Metric(Src, Ref+x+y*BpS, BpS); return Sad + MV_Bits_Cost(x, y); } inline int Sad_Is_Tested(int x, int y) const { const SKL_UINT32 Key = Hash(x,y); const int Off = Slot(x,y); // if (Key_Map[Off]==Key) Hit++; else Miss++; return (Key_Map[Off]==Key); // cache hit } inline SKL_UINT32 *Get_Cached_Sad(int x, int y) { const int Off = Slot(x,y); SKL_ASSERT(Key_Map[Off] == Hash(x,y)); return &Sad_Map[Off]; } inline void Cache_Sad(int x, int y, SKL_UINT32 Sad) { const int Off = Slot(x,y); Key_Map[Off] = Hash(x,y); Sad_Map[Off] = Sad; Best_Sad = Sad; Best_MV[0] = x; Best_MV[1] = y; } inline void Search() { Search_Method(this); } inline SKL_UINT32 Sub_Search(const SKL_MV MVo, const int dx, const int dy) { New_Map(); Set_Sub_Offset(dx, dy); const int x = (IPred[0]<xm) ? xm : (IPred[0]>xM) ? xM : IPred[0]; const int y = (IPred[1]<ym) ? ym : (IPred[1]>yM) ? yM : IPred[1]; Cache_Sad( x,y, Metric(Src, Ref+x+y*BpS, BpS) ); Eval_FP_If_Valid(MVo); Search(); return Best_Sad; } void Print_Cache(int What) const { int x,y; printf("---- (Best SAD:%d at (%d,%d)---------------\n", Best_Sad, Best_MV[0], Best_MV[1]); for(y=0; y<CACHE_SIZE; ++y) { for(x=0; x<CACHE_SIZE; ++x) { SKL_UINT32 v = Key_Map[CACHE_SIZE*y+x]; int Ok = (v<Min_Key + MAX_KEY*MAX_KEY) && (v>=Min_Key); if (What==0) printf( "%c", Ok ? '*' : '.'); else if (What==1) printf( "[%6d]", Ok ? Sad_Map[CACHE_SIZE*y+x] : 0); else printf( " 0x%8x ", Key_Map[CACHE_SIZE*y+x]); } printf("\n"); } } void Start_Search() { Dir = 0x00; // (Best_MV[0]>0 ? 0x02 : Best_MV[0]<0 ? 0x01 : 0x00) | // (Best_MV[1]>0 ? 0x04 : Best_MV[1]<0 ? 0x08 : 0x00); } void Eval_Dir(int x, int y, int Next_Dir) { if (Sad_Is_Tested(x,y)) return; SKL_UINT32 Sad = Eval(x,y); if (Sad<Best_Sad) { Cache_Sad(x,y,Sad); Dir = (Dir & 0xff) | Next_Dir; } } int Eval(const SKL_MV v) { const int x = v[0], y = v[1]; if (Sad_Is_Tested(x,y)) return 0; const SKL_UINT32 Sad = Eval(x,y); if (Sad<Best_Sad) { Cache_Sad(x,y,Sad); return 1; } else return 0; } inline int Is_In_Range(const SKL_MV v) { return (v[0]>=xm_Sub && v[0]<=xM_Sub && v[1]>=ym_Sub && v[1]<=yM_Sub); } inline int Eval_If_In_Range(const SKL_MV v) { if (v[0]<xm || v[0]>xM || v[1]<ym || v[1]>yM) return 0; return Eval(v); } int Eval_If_Valid(const SKL_MV v) { if (!IS_VALID_MV(v)) return 0; if (!Is_In_Range(v)) return 0; SKL_MV V; if (Sub_Prec_Shift==2) { V[0] = v[0]/4; V[1] = v[1]/4; } else { V[0] = v[0]/2; V[1] = v[1]/2; } // V[0] = v[0]>>Sub_Prec_Shift; V[1] = v[1]>>Sub_Prec_Shift; return Eval(V); } int Eval_FP_If_Valid(const SKL_MV v) { if (!IS_VALID_MV(v)) return 0; if (v[0]<xm || v[0]>xM || v[1]<ym || v[1]>yM) return 0; return Eval(v); } SKL_UINT32 Get_Sad(int x, int y) { SKL_ASSERT(x>=xm && x<=xM && y>=ym && y<=yM); const SKL_UINT32 Key = Hash(x,y); const int Off = Slot(x,y); if (Key_Map[Off]==Key) return Sad_Map[Off]; SKL_UINT32 Sad = Eval(x,y); Sad_Map[Off] = Sad; Key_Map[Off] = Key; return Sad; } ME_MAP(const SKL_MP4_INFOS * const frame) : BpS(frame->BpS) , Frame(frame) , Min_Key(0) { Init(); } void Init(); SKL_UINT32 Start(const METRIC metric, const METRIC_AVRG metric_Avrg); // returns Metric(0,0) void New_Scanline(int y); inline void operator++(int) { xo += 16; Src += 16; Ref += 16; } inline void Set_Sub_Offset(const int dx, const int dy); SKL_UINT32 Refine_MV_16x16(SKL_MV MV, const int Prec, const int Rounding); SKL_UINT32 Refine_MV_16x8 (SKL_MV MV, const int Prec, const int Rounding); SKL_UINT32 Refine_MV_8x8 (SKL_MV MV, const int Prec, const int Rounding); SKL_UINT32 Sad_Cost_QP(const SKL_BYTE * const *_HPels, int Offset, const int x, const int y) const; SKL_UINT32 Refine_MV_HPels(SKL_MV MV, const int Prec, const int Rounding, const SKL_BYTE * const *HPels); SKL_UINT32 Get_HP_Sad(SKL_BYTE *Tmp, const SKL_MB_FUNCS * const mb, const SKL_BYTE *Rf, int dx, int dy) const; SKL_UINT32 Get_HP_Sad_8x8(SKL_BYTE *Tmp, const SKL_MB_FUNCS * const mb, const SKL_BYTE *Rf, int dx, int dy) const; int Check_Limits(const SKL_MV mv, SKL_CST_STRING Label=0) const; int Check_Frame_Limits(const SKL_MV mv, SKL_CST_STRING Label=0) const;};//////////////////////////////////////////////////////////const SKL_BYTE ME_MAP::MV_Bits0[32] = { // Table B-12 (with sign bit counted) 3, 4, 5, 7, 8, 8, 8, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13};SKL_BYTE ME_MAP::MV_Code_Sizes0[7][2*2048];void ME_MAP::Init_MV_Code_Sizes(){ static int MV_Code_Sizes_Ok = 0; // not fully MT-safe, but yet ok. if (MV_Code_Sizes_Ok) return; for(int FCode=1; FCode<=7; FCode++) { int MV; const int Fix = FCode - 1; MV_Code_Sizes0[Fix][2048+0] = 1; for(MV=1; MV<=(32<<Fix); ++MV) { const int Code = (MV-1) >> Fix; const int Len = MV_Bits0[Code] + Fix; if (MV<(32<<Fix)) MV_Code_Sizes0[Fix][2048+MV] = Len; MV_Code_Sizes0[Fix][2048-MV] = Len; } for( ; MV<=2048; ++MV) { // sanity check if (MV<2048) MV_Code_Sizes0[Fix][2048+MV] = 255; MV_Code_Sizes0[Fix][2048-MV] = 255; } } MV_Code_Sizes_Ok = 1;}void ME_MAP::Set_FCode(const int FCode, const int Prec){ SKL_ASSERT(FCode>=1 && FCode<=7); Init_MV_Code_Sizes(); Sub_Prec_Shift = 1 + (Prec==2); MV_Bits_Shift = (FCode-1) + 4; Code_Sizes = MV_Code_Sizes0[FCode-1] + 2048; Range = ( 16 << FCode ) >> Sub_Prec_Shift; // -> Range in *full* pel unit}//////////////////////////////////////////////////////////// Various search methods//////////////////////////////////////////////////////////static int MV_Search_Full(ME_MAP * const C){ SKL_UINT32 Best_Sad = C->Best_Sad; const SKL_BYTE *Ref = C->Ref + (C->IPred[1]-C->ym)*C->BpS + C->IPred[0]; int bx=0, by=0; for(int y=C->ym; y<=C->yM; ++y) { for(int x=C->xm; x<=C->xM; ++x) { SKL_UINT32 Sad = C->MV_Bits_Cost(x, y); if (Sad>=Best_Sad) continue; Sad += C->Metric(C->Src, Ref+x, C->BpS); if ( Sad<Best_Sad ) { Best_Sad = Sad; bx = x; by = y; } } Ref += C->BpS; } if (Best_Sad<C->Best_Sad) { C->Best_Sad = Best_Sad; C->Best_MV[0] = bx; C->Best_MV[1] = by; return 1; } else return 0;}static int MV_Search_Log(ME_MAP * const C){ int nx = C->IPred[0]; int ny = C->IPred[1]; int Range = C->Range >> 1; SKL_UINT32 Best_Sad = C->Best_Sad; do { int xm = nx - Range; int xM = nx + Range; int ym = ny - Range; int yM = ny + Range; if (xm<C->xm) xm = C->xm; if (xM>C->xM) xM = C->xM; if (ym<C->ym) ym = C->ym; if (yM>C->yM) yM = C->yM; for(int y=ym; y<=yM; y+=Range) { const SKL_BYTE *Ref = C->Ref + y*C->BpS; for(int x=xm; x<=xM; x+=Range) { SKL_UINT32 Sad = C->MV_Bits_Cost(x,y); if (Sad>=Best_Sad) continue; Sad += C->Metric(C->Src, Ref+x, C->BpS); if (Sad<Best_Sad) { Best_Sad = Sad; nx = x; ny = y; } } } Range >>= 1; } while(Range>0); if (Best_Sad<C->Best_Sad) { C->Best_Sad = Best_Sad; C->Best_MV[0] = nx; C->Best_MV[1] = ny; return 1; } else return 0;} // it's not exactly a genuine PHODS, but works well...static int MV_Search_PHODS(ME_MAP * const C){ SKL_MV mv; SKL_COPY_MV(mv, C->IPred); int dx, dy; dx = dy = C->Range >> 1; SKL_UINT32 Best_Sad = C->Best_Sad; do { if (dx) { int xm = mv[0] - dx; if (xm< C->xm) xm = C->xm; int xM = mv[0] + dx; if (xM>=C->xM) xM = C->xM-1; const SKL_BYTE * const Ref = C->Ref + mv[1]*C->BpS; for(int x=xm; x<=xM; x+=dx) { SKL_UINT32 Sad = C->MV_Bits_Cost(x,mv[1]); if (Sad>=Best_Sad) continue; Sad += C->Metric(C->Src, Ref+x, C->BpS); if (Sad<Best_Sad) { Best_Sad = Sad; mv[0] = x; } } } if (dy) { int ym = mv[1] - dy; if (ym< C->ym) ym = C->ym; int yM = mv[1] + dy; if (yM>=C->yM) yM = C->yM-1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -