📄 skl_mpg4_anl.cpp
字号:
}static inline void Median(SKL_MV Dst, const SKL_MV A, const SKL_MV B, const SKL_MV C){ Dst[0] = Median(A[0],B[0],C[0]); Dst[1] = Median(A[1],B[1],C[1]);}static inline void Median2(SKL_MV Dst, const SKL_MV A, const SKL_MV B){ Dst[0] = Median(A[0],B[0],0); Dst[1] = Median(A[1],B[1],0);}inline void ME_MAP::Set_MV_Predictor(const SKL_MV * const Src, const int MV_Stride, const int Blk, const int ABits){ SKL_ASSERT(Blk>=0 && Blk<4); const SKL_MV * const MV_L = Src - 1; const SKL_MV * const MV_T = Src - MV_Stride; const SKL_MV * const MV_TR = MV_T + Top_Neighbors[Blk]; const int Pred_Type = Pred_Type_ABits[ABits][Blk]; switch(Pred_Type) { default: case 0: Median(Pred, MV_L[0], MV_T[0], MV_TR[0]); break; case 1: SKL_COPY_MV(Pred, *MV_L); break; case 2: Median2(Pred, MV_T[0], MV_TR[0]); break; case 3: Median2(Pred, MV_L[0], MV_TR[0]); break; case 4: Median2(Pred, MV_L[0], MV_T[0]); break; case 5: SKL_COPY_MV(Pred, *MV_T); break; case 6: SKL_COPY_MV(Pred, *MV_TR ); break; case 7: SKL_ZERO_MV(Pred); break; } if (Sub_Prec_Shift==2) { IPred[0] = Pred[0]/4; IPred[1] = Pred[1]/4; // IPred[0] = (Pred[0]+2)>>2; // IPred[1] = (Pred[1]+2)>>2; } else { IPred[0] = Pred[0]/2; IPred[1] = Pred[1]/2; // IPred[0] = (Pred[0]+1)>>1; // IPred[1] = (Pred[1]+1)>>1; }}inline void ME_MAP::Set_FP_MV_Predictor(SKL_MV Pred, const SKL_MP4_MAP * const Map, const int Map_Stride, const int ABits){ const SKL_MV * const MV_L = &Map[-1].MV; const SKL_MV * const MV_T = &Map[-Map_Stride].MV; const SKL_MV * const MV_TR = &Map[-Map_Stride+1].MV; const int Pred_Type = Pred_Type_ABits[ABits][0]; switch(Pred_Type) { default: case 0: Median(Pred, MV_L[0], MV_T[0], MV_TR[0]); break; case 1: SKL_COPY_MV(Pred, *MV_L); break; case 2: Median2(Pred, MV_T[0], MV_TR[0]); break; case 3: Median2(Pred, MV_L[0], MV_TR[0]); break; case 4: Median2(Pred, MV_L[0], MV_T[0]); break; case 5: SKL_COPY_MV(Pred, *MV_T); break; case 6: SKL_COPY_MV(Pred, *MV_TR ); break; case 7: SKL_ZERO_MV(Pred); break; }}//////////////////////////////////////////////////////////// global pass//////////////////////////////////////////////////////////static inline void Update_Map_Data(SKL_MP4_MAP *const Map, SKL_MP4_MAP *const pMap, SKL_UINT32 Sad16, const SKL_MV MV){ Map->Sad16 = Sad16; SKL_COPY_MV(Map->MV, MV); if (pMap) { Map->Acc[0] = 2*Map->MV[0] - pMap->MV[0]; Map->Acc[1] = 2*Map->MV[1] - pMap->MV[1]; } else { SKL_ZERO_MV(Map->Acc); }} // Populates MVs[], Map->Type and Map->Flagsvoid SKL_MP4_ANALYZER_I::Global_Pass(SKL_MP4_INFOS * const Frame){ const int FCode = RND(MV_Search_Window); int Nb_Intras = 0; int Nb_Relevant = 0; Reset_Stats(); // will store previous Last_Avrg_MV (if any) ME_MAP Cursor(Frame); SKL_UINT32 SAD_Hi = SAD_Hi_Limit; SKL_UINT32 SAD_Lo = SAD_Low_Limit; // for now, disable 4v search with reduced VOP const int Search_4V = (Reduced_Frame<1) && (Inter4V_Probing>0); const int BpS = Frame->BpS; SKL_UINT32 Sad4_Penalty; // penalty for 4v SKL_UINT32 Sad2_Penalty; // penalty for field interlacing METRIC Metric_16x16, Metric_8x8, Metric_16x8; METRIC_AVRG Metric_16x16_Avrg, Metric_8x8_Avrg, Metric_16x8_Avrg; METRIC_DEV Metric_Dev; switch( Search_Metric ) { case 2: Metric_16x16 = Frame->Img_Dsp->Hadamard_SAD_16x16; Metric_16x8 = Frame->Img_Dsp->Hadamard_SAD_16x8_Field; Metric_8x8 = Frame->Img_Dsp->Hadamard_SAD_8x8; Metric_Dev = Frame->Img_Dsp->Hadamard_Dev_16x16; Metric_16x16_Avrg = Frame->Img_Dsp->SAD_Avrg_16x16; Metric_16x8_Avrg = Frame->Img_Dsp->SAD_Avrg_16x8; Metric_8x8_Avrg = Frame->Img_Dsp->SAD_Avrg_8x8; Cursor.Lambda = (int)( Q_Cur*0.9f*Lambda ); SAD_Lo = 2*SAD_Lo; SAD_Hi = 2*SAD_Hi; Sad4_Penalty = (SKL_UINT32)( .2f * Q_Cur*Lambda ); Sad2_Penalty = (SKL_UINT32)( .6f * Q_Cur*Lambda ); break; case 1: Metric_16x16 = Frame->Img_Dsp->SSD_16x16; Metric_16x8 = Frame->Img_Dsp->SSD_16x8_Field; Metric_8x8 = Frame->Img_Dsp->SSD_8x8; Metric_Dev = Frame->Img_Dsp->Sqr_Dev_16x16; Metric_16x16_Avrg = Frame->Img_Dsp->SAD_Avrg_16x16; Metric_16x8_Avrg = Frame->Img_Dsp->SAD_Avrg_16x8; Metric_8x8_Avrg = Frame->Img_Dsp->SAD_Avrg_8x8; Cursor.Lambda = (int)( Q_Cur*Q_Cur*3.5f*Lambda ); SAD_Lo = SAD_Lo; SAD_Hi = SAD_Hi; Sad4_Penalty = (SKL_UINT32)( 0.1f * Q_Cur * Q_Cur*Lambda ); Sad2_Penalty = (SKL_UINT32)( 3.8f * Q_Cur * Q_Cur*Lambda ); break; default: Metric_16x16 = Frame->Img_Dsp->SAD_16x16; Metric_16x8 = Frame->Img_Dsp->SAD_16x8_Field; Metric_8x8 = Frame->Img_Dsp->SAD_8x8; Metric_Dev = Frame->Img_Dsp->Abs_Dev_16x16; Metric_16x16_Avrg = Frame->Img_Dsp->SAD_Avrg_16x16; Metric_16x8_Avrg = Frame->Img_Dsp->SAD_Avrg_16x8; Metric_8x8_Avrg = Frame->Img_Dsp->SAD_Avrg_8x8; Cursor.Lambda = (int)( Q_Cur*0.8f*Lambda ); SAD_Lo = 2*SAD_Lo; SAD_Hi = 2*SAD_Hi; Sad4_Penalty = (SKL_UINT32)( 2.4f * Q_Cur*Lambda ); Sad2_Penalty = (SKL_UINT32)( 0.7f * Q_Cur*Lambda ); break; } const SKL_UINT32 SKIP_Limit = SAD_Lo >> 2; // TODO: Fine tune. Is it a good idea, btw? Cursor.Search_Method = MV_Searchs[Search_Method]; Cursor.Metric = Metric_16x16; Cursor.Metric_Avrg = Metric_16x16_Avrg; Cursor.Set_FCode( FCode, Subpixel_Precision ); const int MV_Stride = Frame->MV_Stride; const int Map_Stride = Frame->MB_W; SKL_MP4_MAP *Map = Frame->Cur->Map; SKL_MV *MVs = Frame->Cur->MV; SKL_MV *pMVs = (Frame->Past ? Frame->Past->MV : 0); SKL_MP4_MAP *pMap = (Frame->Past ? Frame->Past->Map : 0); // Note: Hi_Mem is only worth of QPel const int Use_HPels = (Hi_Mem && Frame->Past!=0) && (Subpixel_Precision==2); if (Use_HPels) Set_Half_Pels(Frame, Frame->Past); else _HPels[0] = 0; // sanity check for(int y=0; y<Frame->Height; y+=16) { Cursor.New_Scanline(y); for(int x=0; x<Frame->Width; x+=16) {// SKL_MV Maxs[2]; const int ABits = (x>0) | ((y>0)<<1) | ((x+16<Frame->Width)<<2) | ((y+16<Frame->Height)<<3); Cursor.Set_MV_Predictor(&MVs[0], MV_Stride, 0, ABits); SKL_UINT32 Dist0 = Cursor.Start(Metric_16x16, Metric_16x16_Avrg); // Dist0 is distortion for mv=(0,0) SKL_UINT32 Sad0 = Dist0 + Cursor.MV_Bits_Cost(0,0); // Cost for mv=(0,0) Cursor.Cache_Sad(Cursor.xM<0 ? Cursor.xM : Cursor.xm>0 ? Cursor.xm : 0, Cursor.yM<0 ? Cursor.yM : Cursor.ym>0 ? Cursor.ym : 0, Sad0); Nb_Relevant += (Dist0>300); Map->Flags = 0; // a priori: no field-DCT Map->dQ = 0; Map->Sad = Sad0; Map->Sad16 = Sad0; Map->Type = SKL_MAP_16x16; // default mode: INTER, with 1MV SKL_ASSERT(Cursor.xo == x && Cursor.yo==y); SKL_ASSERT(Cursor.Src == Frame->Cur->Y + x + y*BpS); SKL_ASSERT(Cursor.Ref == Frame->Past->Y + x + y*BpS); SKL_UINT32 Sad_Limit;#if 1 if (Dist0<SKIP_Limit) { SKL_UINT32 Chroma_SAD; const int Chroma_Off = (x/2) + (y/2)*BpS; Chroma_SAD = Metric_8x8(Frame->Cur->U + Chroma_Off, Frame->Past->U + Chroma_Off, BpS); Chroma_SAD += Metric_8x8(Frame->Cur->V + Chroma_Off, Frame->Past->V + Chroma_Off, BpS); if (Chroma_SAD*2<SKIP_Limit) { Map->Type = SKL_MAP_SKIPPED; SKL_ZERO_MV(MVs[0]); // <- prepare, in case it gets later promoted to INTER_16x16 (GMC) Update_Map_Data(Map, pMap, Dist0, MVs[0]); goto Done_16x16; } }// if (Dist0<SAD_Lo*2) Cursor.Best_Sad = SAD_Lo*2;// else if (Dist0>SAD_Hi*2) Cursor.Best_Sad = SAD_Hi*2;#endif Cursor.Eval_If_Valid(Cursor.Pred);#if 1 if (ABits&7) { SKL_MV Med; Cursor.Set_FP_MV_Predictor(Med, Map, Map_Stride, ABits); Cursor.Eval_FP_If_Valid(Med); }#endif if (Cursor.Best_Sad<256) goto Skip_Search; Sad_Limit = Map[0].Sad16; if (pMap) {// Cursor.Eval_FP_If_Valid(pMap[0].MV); // past colocated if (ABits&4) Cursor.Eval_FP_If_Valid(pMap[1].MV); // past left } if (ABits&1) { // left Cursor.Eval_FP_If_Valid(Map[-1].MV); if (Map[-1].Sad16<Sad_Limit) Sad_Limit = Map[-1].Sad16; } if (ABits&2) { // top Cursor.Eval_FP_If_Valid(Map[-Map_Stride].MV); if (Map[-Map_Stride].Sad16<Sad_Limit) Sad_Limit = Map[-Map_Stride].Sad16; if (ABits&4) { // top-right Cursor.Eval_FP_If_Valid(Map[-Map_Stride+1].MV); if (Map[-Map_Stride+1].Sad16<Sad_Limit) Sad_Limit = Map[-Map_Stride+1].Sad16; } } if (Cursor.Best_Sad < Sad_Limit) goto Skip_Search; if (pMap && Cursor.Best_Sad>2*SAD_Lo) {#if 1 if (ABits&1) Cursor.Eval_FP_If_Valid(pMap[-1].MV); // past left if (ABits&4) Cursor.Eval_FP_If_Valid(pMap[ 1].MV); // past right if (ABits&2) Cursor.Eval_FP_If_Valid(pMap[-Map_Stride].MV); // past top if (ABits&8) Cursor.Eval_FP_If_Valid(pMap[ Map_Stride].MV); // past bottom Cursor.Eval_FP_If_Valid(pMap[0].Acc); // accelerator#endif Cursor.Eval_If_Valid(Last_Avrg_MV); // Last avrg MV Cursor.Eval_FP_If_Valid(pMap[0].MV); // past colocated if ((ABits&12)==12) Cursor.Eval_FP_If_Valid(pMap[Map_Stride+1].MV); // past bottom right if (Cursor.Best_Sad < Sad_Limit) goto Skip_Search;// if (IS_EQUAL_MV(Cursor.Best_MV,pMap[0].MV) && Cursor.Best_Sad<pMap[0].Sad16)// goto Skip_Search; } Cursor.Search();Skip_Search: Update_Map_Data(Map, pMap, Cursor.Best_Sad, Cursor.Best_MV); if (Cursor.Best_Sad > SAD_Hi && Cursor.Best_Sad > Metric_Dev(Cursor.Src, BpS)) { Map->Type = SKL_MAP_INTRA; Nb_Intras++; SKL_ZERO_MV(MVs[0]); goto Done_16x16; } if (Use_HPels) Cursor.Refine_MV_HPels(MVs[0], Subpixel_Precision, Rounding, _HPels); else Cursor.Refine_MV_16x16(MVs[0], Subpixel_Precision, Rounding); Map->Sad = Cursor.Best_Sad; if (Interlace_Field>0) { if (Field_Pred_Probing<100) { // 50-60% is a good compromise between speed and probing const SKL_UINT32 Sad_Sub_Limit = Cursor.Best_Sad * (100-Field_Pred_Probing) /100; const SKL_BYTE * Rf = Cursor.Ref + Cursor.Best_MV[0] + Cursor.Best_MV[1]*BpS; SKL_UINT32 Sad2_0; Sad2_0 = Metric_16x8(Cursor.Src , Rf, BpS); if (Sad2_0>=Sad_Sub_Limit) goto Go_Field_Pred; Sad2_0 = Metric_16x8(Cursor.Src + BpS, Rf, BpS); if (Sad2_0>=Sad_Sub_Limit) goto Go_Field_Pred; goto Done_Field; }Go_Field_Pred: { SKL_UINT32 Sad2, Sad16, Saved_Sad = Cursor.Best_Sad; SKL_MV Saved_MV, Best_MV; SKL_COPY_MV( MVs[1], MVs[0] ); SKL_COPY_MV( Saved_MV, MVs[0] ); SKL_COPY_MV( Best_MV, Cursor.Best_MV ); Cursor.Metric = Metric_16x8; Cursor.Metric_Avrg = Metric_16x8_Avrg; Sad16 = Cursor.Sub_Search(Map[0].MV, 0,0); Sad2 = Cursor.Refine_MV_16x8(MVs[0], Subpixel_Precision, Rounding); Sad16 += Cursor.Sub_Search(Map[0].MV, 0,1); Sad2 += Cursor.Refine_MV_16x8(MVs[1], Subpixel_Precision, Rounding); // penalty for going field-pred is very high (we'll pay 2mv+1bit per mb) Sad2 = Sad2*12/10 + Sad2_Penalty; Cursor.Set_Sub_Offset(0,0); if (Sad2<Saved_Sad || Interlace_Field==2) { Map->Type = SKL_MAP_16x8; // -> use Field_Pred Map->Sad = Sad2; MVs[1][1] += 1; // compensate Src bottom field offset MVs[MV_Stride+0][0] = (MVs[0][0]+MVs[1][0])>>1; MVs[MV_Stride+0][1] = (MVs[0][1]+MVs[1][1])>>1; SKL_COPY_MV(MVs[MV_Stride+1], MVs[MV_Stride+0]); Update_Map_Data(Map, pMap, Sad16, MVs[MV_Stride+0]); Add_To_Stats(MVs[0]); Add_To_Stats(MVs[1]); goto Done; } else { SKL_COPY_MV( MVs[0], Saved_MV ); // wasn't worth... SKL_COPY_MV( Cursor.Best_MV, Best_MV ); Cursor.Best_Sad = Saved_Sad; Cursor.Metric = Metric_16x16; Cursor.Metric_Avrg = Metric_16x16_Avrg; } } }Done_Field: // at this point, MVs[0] is in half/quarter pel unit... SKL_ASSERT(Cursor.Is_In_Range(MVs[0])); SKL_ASSERT(Map->Type==SKL_MAP_16x16);// Set_Max(Maxs[0], MVs[0], Cursor.Pred); if (Search_4V) {#if 1 if (Inter4V_Probing<100) { const SKL_UINT32 Sad_Sub_Limit = Cursor.Best_Sad * (100-Inter4V_Probing) / 100; const SKL_BYTE * Rf = Cursor.Ref + Cursor.Best_MV[0] + Cursor.Best_MV[1]*BpS; SKL_UINT32 Sad4_0; Sad4_0 = Metric_8x8(Cursor.Src , Rf, BpS); if (Sad4_0>=Sad_Sub_Limit) goto Go_4v; Sad4_0 = Metric_8x8(Cursor.Src + 8 , Rf+8, BpS); if (Sad4_0>=Sad_Sub_Limit) goto Go_4v; Rf += 8*BpS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -