📄 skl_mpg4_anl.cpp
字号:
Sad4_0 = Metric_8x8(Cursor.Src + 8*BpS, Rf, BpS); if (Sad4_0>=Sad_Sub_Limit) goto Go_4v; Sad4_0 = Metric_8x8(Cursor.Src + 8 + 8*BpS, Rf+8, BpS); if (Sad4_0>=Sad_Sub_Limit) goto Go_4v; goto Done_4v; }#endifGo_4v: { SKL_UINT32 Sad4, Sad16, Saved_Sad = Cursor.Best_Sad; SKL_MV Saved_MV; SKL_COPY_MV( Saved_MV, MVs[0] ); Cursor.Metric = Metric_8x8; Cursor.Metric_Avrg = Metric_8x8_Avrg; // Cursor.Pred and Sub_Offset() are ok, here// Cursor.Set_MV_Predictor(&MVs[0], MV_Stride, 0); Sad16 = Cursor.Sub_Search(Map[0].MV, 0,0); if (Use_HPels) Sad4 = Cursor.Refine_MV_HPels(MVs[0], Subpixel_Precision, Rounding, _HPels); else Sad4 = Cursor.Refine_MV_8x8(MVs[0], Subpixel_Precision, Rounding); SKL_ASSERT(Cursor.Is_In_Range(MVs[0]));// Set_Max(Maxs[1], MVs[0], Cursor.Pred); Cursor.Set_MV_Predictor(&MVs[1], MV_Stride, 1, ABits); Sad16 += Cursor.Sub_Search(Map[0].MV, 8,0); if (Use_HPels) Sad4 += Cursor.Refine_MV_HPels(MVs[1], Subpixel_Precision, Rounding, _HPels); else Sad4 += Cursor.Refine_MV_8x8(MVs[1], Subpixel_Precision, Rounding); SKL_ASSERT(Cursor.Is_In_Range(MVs[1]));// Store_Max(Maxs[1], MVs[1], Cursor.Pred); Cursor.Set_MV_Predictor(&MVs[MV_Stride+0], MV_Stride, 2, ABits); Sad16 += Cursor.Sub_Search(Map[0].MV, 0,8); if (Use_HPels) Sad4 += Cursor.Refine_MV_HPels(MVs[MV_Stride+0], Subpixel_Precision, Rounding, _HPels); else Sad4 += Cursor.Refine_MV_8x8(MVs[MV_Stride+0], Subpixel_Precision, Rounding); SKL_ASSERT(Cursor.Is_In_Range(MVs[MV_Stride+0]));// Store_Max(Maxs[1], MVs[MV_Stride+0], Cursor.Pred); Cursor.Set_MV_Predictor(&MVs[MV_Stride+1], MV_Stride, 3, ABits); Sad16 += Cursor.Sub_Search(Map[0].MV, 8,8); if (Use_HPels) Sad4 += Cursor.Refine_MV_HPels(MVs[MV_Stride+1], Subpixel_Precision, Rounding, _HPels); else Sad4 += Cursor.Refine_MV_8x8(MVs[MV_Stride+1], Subpixel_Precision, Rounding); SKL_ASSERT(Cursor.Is_In_Range(MVs[MV_Stride+1]));// Store_Max(Maxs[1], MVs[MV_Stride+1], Cursor.Pred);// printf( "Sad4=%d Sad4_FP=%d Sad16=%d (%d,%d)\n", Sad4, Sad16, Saved_Sad, Map[0].MV[0],Map[0].MV[1]); Sad4 += Sad4_Penalty; if (Sad4<Saved_Sad) { Map->Type = SKL_MAP_8x8; Map->Sad = Sad4; Update_Map_Data(Map, pMap, Sad16, MVs[0]);// Add_Max_MV_To_Stats(Maxs[1]); Add_To_Stats(MVs[0]); Add_To_Stats(MVs[1]); Add_To_Stats(MVs[MV_Stride+0]); Add_To_Stats(MVs[MV_Stride+1]); } else SKL_COPY_MV( MVs[0], Saved_MV ); // wasn't worth... Cursor.Set_Sub_Offset(0,0); // Warning: Cursor.Pred, .IPred, .Best_MV, .Best_Sad, Src, Ref and .Metric* are trashed here } }Done_4v: if (Map->Type==SKL_MAP_16x16) {Done_16x16:// Add_Max_MV_To_Stats(Maxs[0]); Add_To_Stats(MVs[0]); SKL_COPY_MV(MVs[ 1], MVs[0]); SKL_COPY_MV(MVs[MV_Stride+0], MVs[0]); SKL_COPY_MV(MVs[MV_Stride+1], MVs[0]); }Done: if (Interlace_DCT>0) { /* note: for INTER blocks, we should decide field DCT *after* the predictions has been formed, but we expect it to be equally as good as working directly on unpredicted frame source. */ if (Interlace_DCT==2 || Field_DCT_Is_Better(Cursor.Src, Frame)) Map->Flags |= 1; // -> use Field_DCT }#if 0 Cursor.Check_Limits(MVs[0], "[post]:"); Cursor.Check_Limits(MVs[1], "[post]:"); Cursor.Check_Limits(MVs[MV_Stride+0], "[post]:"); Cursor.Check_Limits(MVs[MV_Stride+1], "[post]:"); Cursor.Check_Frame_Limits(MVs[0], "[flm]:");#endif Map++; MVs += 2; if (pMVs!=0) { pMVs += 2; pMap++; } Cursor++; } MVs += 4 + MV_Stride; // skip edge and next line if (pMVs!=0) pMVs += 4 + MV_Stride; } Frame->Img_Dsp->Switch_Off(); Compile_Stats(); // Warning: this func uses floats. Call after EMMS. // last 30% before reaching forced key-frame? // => we artificially raise the perceived number of intras int Scale = 100; const int dCount = 30*Intra_Max - 100*Intra_Count; if (dCount>0) Scale += Scale*dCount/(30*Intra_Max); if (Nb_Intras * Scale > Intra_Limit * Nb_Relevant) { Intra_Count = -1; // real scene change// printf( "Scene change! Nb:%d / %d (/%d) =>%.1f%%\n", Nb_Intras, Nb_Relevant, Frame->MB_W*Frame->MB_H, 100.f*Nb_Intras/Nb_Relevant); }// fprintf( stderr, "Miss:%d, Hit:%d (%.2f%%)\n", Cursor.Miss, Cursor.Hit, 100.f*Cursor.Hit/(Cursor.Miss+Cursor.Hit) );}//////////////////////////////////////////////////////////// GMC pass (experimental)//////////////////////////////////////////////////////////#define GMC_RND(x) ( (x)<0. ? -(int)( -(x)+.5f ) : (int)( (x)+.5f ) )#define GMC_DBG(S) // printf( S )void SKL_MP4_ANALYZER_I::Global_GMC_Pass(SKL_MP4_INFOS * const Frame){ GMC_Mode &= ~1; if (Reduced_Frame>0) return; // no GMC in reduced resolution VOP int Nb_Smpl, i, j; const int MB_W = Frame->MB_W; const int MB_H = Frame->MB_H; const int MV_Up = 2*Frame->MV_Stride; const int BpS = Frame->BpS; int (*Smpl)[2] = (int (*)[2]) alloca(MB_W*MB_H*2*sizeof(int)); SKL_BYTE *Scratch = (SKL_BYTE*) alloca(16*BpS); SKL_MP4_MAP *Map; SKL_MV *MVs; SKL_UINT32 GMC_SAD_PENALTY; // small mv penalty (that's the point of GMC!!) SKL_UINT32 GMC_AUTO_SAD_LIMIT; METRIC Metric_16x16; METRIC_DEV Metric_Dev; switch( Search_Metric ) { case 2: Metric_16x16 = Frame->Img_Dsp->Hadamard_SAD_16x16; Metric_Dev = Frame->Img_Dsp->Hadamard_Dev_16x16; GMC_AUTO_SAD_LIMIT = 150; GMC_SAD_PENALTY = 4; break; case 1: Metric_16x16 = Frame->Img_Dsp->SSD_16x16; Metric_Dev = Frame->Img_Dsp->Sqr_Dev_16x16; GMC_AUTO_SAD_LIMIT = 500; GMC_SAD_PENALTY = 4; break; default: Metric_16x16 = Frame->Img_Dsp->SAD_16x16; Metric_Dev = Frame->Img_Dsp->Abs_Dev_16x16; GMC_AUTO_SAD_LIMIT = 700; GMC_SAD_PENALTY = 4; break; } const int LAPL_LIMIT = 14; float Scale = 1.f * (1<<(3-GMC_Accuracy)); if (Subpixel_Precision==2) Scale *= 0.5f; Nb_Smpl = 0; MVs = Frame->Cur->MV; Map = Frame->Cur->Map; for(j=0; j<MB_H; ++j) { for(i=0; i<MB_W; ++i) { if (Map[i].Type!=SKL_MAP_16x16 && Map[i].Type!=SKL_MAP_8x8) // not INTRA or SKIPPED { GMC_DBG( "." ); continue; } const int vx0 = MVs[2*i][0]; const int vy0 = MVs[2*i][1]; int Lapl_x = 0, Lapl_y = 0; if (i>0) { Lapl_x += MVs[2*i-1][0] - vx0; Lapl_y += MVs[2*i-1][1] - vy0; } if (i<MB_W-1) { Lapl_x += MVs[2*i+1][0] - vx0; Lapl_y += MVs[2*i+1][1] - vy0; } if (j>0) { Lapl_x += MVs[2*i-Frame->MV_Stride][0] - vx0; Lapl_y += MVs[2*i-Frame->MV_Stride][1] - vy0; } if (j<MB_H-1) { Lapl_x += MVs[2*i+Frame->MV_Stride][0] - vx0; Lapl_y += MVs[2*i+Frame->MV_Stride][1] - vy0; } if (ABS(Lapl_x)+ABS(Lapl_y)>LAPL_LIMIT) { GMC_DBG( "-" ); continue; } const SKL_BYTE * const Src = Frame->Cur->Y + i*16 + j*16*BpS; SKL_UINT32 Sad;#if 1 Sad = (i<MB_W-1) ? Metric_16x16(Src, Src+1, BpS) : Metric_16x16(Src, Src-1, BpS); Sad += (j<MB_H-1) ? Metric_16x16(Src, Src+BpS, BpS) : Metric_16x16(Src, Src-BpS, BpS);#else Sad = Metric_Dev(Src, BpS); // enough textured?#endif if (Sad<GMC_AUTO_SAD_LIMIT) { GMC_DBG( "=" ); continue; } Smpl[Nb_Smpl][0] = i; Smpl[Nb_Smpl][1] = j; Nb_Smpl++; GMC_DBG( "*" ); } GMC_DBG("\n"); MVs += MV_Up; Map += MB_W; } GMC_DBG( "\n" ); Frame->Img_Dsp->Switch_Off(); // Note: // // We're about to least-square fit the 6-parameters model: // // mvx(x,y) = vx0 + a.x + b.y // mvy(x,y) = vy0 + c.x + d.y // // that globally interpolates the motion vector (mvx,mvy) at point x,y. // The unknowns are: vx0,vy0, a,b,c,d. The mapping toward the ISO warp // points is pretty straightforward. We always use 3 warp points, leaving // the task of simplifying the sprite motion to the SKL_GMC_DSP module. // // Now, minimizing the overall error E = < (vx-mvx)^2 + (vy-mvy)^2 > // where (vx,vy) are the result of the previous ME pass, and filtering // out the seemingly outliers, gives the set of equations: // // vx0 = <vx> - a.<x> - b.<y> // vy0 = <vy> - c.<x> - d.<y> // {x.vx} = a.{xx} + b.{xy} // {y.vx} = a.{xy} + b.{yy} // {x.vy} = c.{xx} + d.{xy} // {y.vy} = c.{xy} + d.{yy} // // where <f> is the sampled average of quantity 'f', and {fg} is the // deviates of f*g, that is: {fg} = <fg> - <f>.<g>. // Inverting this system easily gives: // // Det = {yy}.{xx} - {xy}.{xy}. // a = ( {x.vx}.{yy} - {y.vx}{xy} ) / Det // b = ( {y.vx}.{xx} - {x.vx}{xy} ) / Det // c = ( {x.vy}.{yy} - {y.vy}{xy} ) / Det // d = ( {y.vy}.{xx} - {x.vy}{xy} ) / Det // // with some special degenerate cases. // Of course, vx0,vy0 are deduced after a,b,c,d are known. // float a=0.,b=0.,c=0.,d=0., vx0=0., vy0=0.; // params float W; while(Nb_Smpl>=8) { a=0.; b=0.; c=0.; d=0.; vx0=0.; vy0=0.; W = 0.; float x=0., y=0., Vx = 0., Vy=0.; // stats float xx=0., yy=0., xy=0.; float xVx=0., yVx=0., xVy=0., yVy=0.; Map = Frame->Cur->Map; MVs = Frame->Cur->MV; int n; for(n=0; n<Nb_Smpl; ++n) { i = Smpl[n][0]; j = Smpl[n][1]; const float xo = 16.f*i; const float yo = 16.f*j; const float vxo = (float)MVs[2*i+j*MV_Up][0]; const float vyo = (float)MVs[2*i+j*MV_Up][1]; SKL_ASSERT(Map[i + j*MB_W].Sad>0); const float w = 1.f / Map[i + j*MB_W].Sad;// flat weighting: const float w = 1.f; W += w; x += w*xo; y += w*yo; Vx += w*vxo; Vy += w*vyo; xx += w*xo*xo; yy += w*yo*yo; xy += w*xo*yo; xVx += w*xo*vxo; xVy += w*xo*vyo; yVx += w*yo*vxo; yVy += w*yo*vyo; }// flat weighting: W = 1.f*n; xx = xx*W - x*x; xy = xy*W - x*y; yy = yy*W - y*y; xVx = xVx*W - x*Vx; xVy = xVy*W - x*Vy; yVx = yVx*W - y*Vx; yVy = yVy*W - y*Vy; float Det = xx*yy - xy*xy; if (fabs(Det)<1.e-3f) { // data aligned?!? // printf( "{xx}:%.6f {yy}:%.6f {xy}:%6f\n", xx, yy, xy ); if (fabs(xy)<1.e-3f) { // => either xx or yy is 0. if (fabs(xx)>=1.e-3f) { Det = Scale / xx; a = xVx * Scale; b = 0.; c = xVy * Scale; d = 0.; } else if (fabs(yy)>=1.e-6f) { Det = Scale / yy; a = 0.; b = yVx * Scale; c = 0.; d = yVy * Scale; } else { a = b = c = d = 0.; } } else { // {xy}.{xy} = {xx}.{yy}. Data are aligned. a = b = c = d = 0.; } } else { Det = Scale / Det; a = ( xVx*yy - yVx*xy ) * Det; b = ( yVx*xx - xVx*xy ) * Det; c = ( xVy*yy - yVy*xy ) * Det; d = ( yVy*xx - xVy*xy ) * Det; } W = 1.f / W; vx0 = ( Scale*Vx - a*x - b*y ) * W; vy0 = ( Scale*Vy - c*x - d*y ) * W;#if 0 vx0 = 0.5f*GMC_RND(2.f*vx0); vy0 = 0.5f*GMC_RND(2.f*vy0); a = (0.5f/Frame->Width )*GMC_RND( a*2.f*Frame->Width ); c = (0.5f/Frame->Width )*GMC_RND( c*2.f*Frame->Width ); b = (0.5f/Frame->Height)*GMC_RND( b*2.f*Frame->Height ); d = (0.5f/Frame->Height)*GMC_RND( d*2.f*Frame->Height );#endif// printf( "Nb Smpl:%d/%d Params:vx0=%.3f vy0=%.3f a=%.3f b=%.3f c=%.3f d=%.3f W=%3f\n", Nb_Smpl, MB_W*MB_H, vx0, vy0, a,b, c,d, W ); float dVx = 0., dVy = 0.; for(n=0; n<Nb_Smpl; ++n) { i = Smpl[n][0]; j = Smpl[n][1]; const float x = 16.f*i; const float y = 16.f*j; Vx = vx0 + a*x + b*y; Vy = vy0 + c*x + d*y;// printf( "%3f/%3f %3f/%3f\n", Vx, Scale*MVs[2*i + j*MV_Up][0], Vy, Scale*MVs[2*i + j*MV_Up][1] ); Vx -= Scale*MVs[2*i + j*MV_Up][0]; Vy -= Scale*MVs[2*i + j*MV_Up][1]; dVx += ABS(Vx); dVy += ABS(Vy); } dVx /= Nb_Smpl; dVy /= Nb_Smpl; if (dVx<0.3f) dVx = 0.3f; if (dVy<0.3f) dVy = 0.3f; int Nb0 = Nb_Smpl; n = 0; while(n<Nb_Smpl) { i = Smpl[n][0]; j = Smpl[n][1]; const float x = 16.f*i; const float y = 16.f*j; Vx = vx0 + a*x + b*y - Scale*MVs[2*i + j*MV_Up][0]; Vy = vy0 + c*x + d*y - Scale*MVs[2*i + j*MV_Up][1]; if (ABS(Vx)>dVx || ABS(Vy)>dVy) { --Nb_Smpl; Smpl[n][0] = Smpl[Nb_Smpl][0]; Smpl[n][1] = Smpl[Nb_Smpl][1]; } else n++; } // printf( "=> Nb_Smpl:%d/%d Box: dVx=%f, dVy=%f\n", Nb_Smpl, Nb0, dVx, dVy ); if (Nb_Smpl<8 || Nb_Smpl==Nb0) break; } if ( (Nb_Smpl<8) && ((GMC_Mode&2)==0) ) return; // Status quo not reached // ok, we seem to have some global motion params available. // Time to clean things up. GMC_Warps[0][0] = GMC_RND( vx0 ); SKL_ASSERT(GMC_Warps[0][0]>=-32768 && GMC_Warps[0][0]<=32767); GMC_Warps[0][1] = GMC_RND( vy0 ); SKL_ASSERT(GMC_Warps[0][0]>=-32768 && GMC_Warps[0][0]<=32767); GMC_Warps[1][0] = GMC_RND( a*Frame->Width ); SKL_ASSERT(GMC_Warps[1][0]>=-32768 && GMC_Warps[1][0]<=32767); GMC_Warps[1][1] = GMC_RND( c*Frame->Width ); SKL_ASSERT(GMC_Warps[1][1]>=-32768 && GMC_Warps[1][1]<=32767); GMC_Warps[2][0] = GMC_RND( b*Frame->Height ); SKL_ASSERT(GMC_Warps[2][0]>=-32768 && GMC_Warps[2][0]<=32767); GMC_Warps[2][1] = GMC_RND( d*Frame->Height ); SKL_ASSERT(GMC_Warps[2][1]>=-32768 && GMC_Warps[2][1]<=32767);// printf( " => (%d,%d) (%d,%d) (%d,%d)\n", GMC_Warps[0][0], GMC_Warps[0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -