📄 skl_mpg4_dec.cpp
字号:
static const SKL_BYTE Pred_Type_ABits[8][4] = { // index: [ABits (3b)][Blk=0..3] {1, 1, 0, 0}, {7, 1, 2, 0}, {4, 4, 0, 0}, {5, 4, 2, 0}, {3, 3, 0, 0}, {6, 3, 2, 0}, {0, 0, 0, 0}, {2, 0, 2, 0}}; // hardcoded Fig 7-20. There's always 2 fixed predictors exactly // on left and on top. Only the third is wandering on top, according to:static const int Top_Neighbors[4] = { 2, 1, 1, -1 };static inline SKL_INT16 Median(SKL_INT16 x, SKL_INT16 y, SKL_INT16 z) { SKL_INT16 m = x; SKL_INT16 M = x; if (y < m) m = y; else M = y; if (z <= m) return m; else if (z >= M) return M; else return z;}void SKL_MB::Predict_Motion_Vector(SKL_MV MV, const SKL_MV * const Src, const int Blk) const{ 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: MV[0] = Median(MV_L[0][0], MV_T[0][0], MV_TR[0][0]); MV[1] = Median(MV_L[0][1], MV_T[0][1], MV_TR[0][1]); return; break; case 1: SKL_COPY_MV(MV, *MV_L); return; break; case 2: MV[0] = Median(0, MV_T[0][0], MV_TR[0][0]); MV[1] = Median(0, MV_T[0][1], MV_TR[0][1]); return; break; case 3: MV[0] = Median(MV_L[0][0], 0, MV_TR[0][0]); MV[1] = Median(MV_L[0][1], 0, MV_TR[0][1]); return; break; case 4: MV[0] = Median(MV_L[0][0], MV_T[0][0], 0); MV[1] = Median(MV_L[0][1], MV_T[0][1], 0); return; break; case 5: SKL_COPY_MV(MV, *MV_T); return; break; case 6: SKL_COPY_MV(MV, *MV_TR ); return; break; case 7: SKL_ZERO_MV(MV); return; break; }}void SKL_MB::Predict_Motion_Vector_Blk0(SKL_MV MV, const SKL_MV *Src, const SKL_MV * const MV_L) const{ const SKL_MV * const MV_T = Src - MV_Stride; const SKL_MV * const MV_TR = MV_T + 2; const int Pred_Type = Pred_Type_ABits[ABits][0]; switch(Pred_Type) { default: case 0: MV[0] = Median(MV_L[0][0], MV_T[0][0], MV_TR[0][0]); MV[1] = Median(MV_L[0][1], MV_T[0][1], MV_TR[0][1]); return; break; case 1: SKL_COPY_MV(MV, *MV_L); return; break; case 2: MV[0] = Median(0, MV_T[0][0], MV_TR[0][0]); MV[1] = Median(0, MV_T[0][1], MV_TR[0][1]); return; break; case 3: MV[0] = Median(MV_L[0][0], 0, MV_TR[0][0]); MV[1] = Median(MV_L[0][1], 0, MV_TR[0][1]); return; break; case 4: MV[0] = Median(MV_L[0][0], MV_T[0][0], 0); MV[1] = Median(MV_L[0][1], MV_T[0][1], 0); return; break; case 5: SKL_COPY_MV(MV, *MV_T); return; break; case 6: SKL_COPY_MV(MV, *MV_TR ); return; break; case 7: SKL_ZERO_MV(MV); return; break; }}//////////////////////////////////////////////////////////// DC / AC prediction//////////////////////////////////////////////////////////#define ABS(x) (((x)<0) ? -(x) : (x))#define DIV_ROUND(x,y) ( (x)>=0 ? ((x)+((y)>>1))/(y) : ((x)-((y)>>1))/(y) )#define FDIV(x,y) ((x)+((y)>>1)) / (y) // section 7.4.3int SKL_MB_DATA::Choose_Pred_Dir(const SKL_MB_DATA *Top){ const SKL_INT16 A = this[-1].DC; // wow const SKL_INT16 B = Top[-1].DC; const SKL_INT16 C = Top[ 0].DC; if (ABS(A-B)<ABS(C-B)) { DC = C; return 1; // vertical } else { DC = A; return 2; // horizontal }}#define BITS 16#define FIX(a) ((1<<BITS)/(a) + 1)static const int Div_AC[31] = { FIX( 1),FIX( 2),FIX( 3),FIX( 4),FIX( 5),FIX( 6),FIX( 7), FIX( 8),FIX( 9),FIX(10),FIX(11),FIX(12),FIX(13),FIX(14),FIX(15), FIX(16),FIX(17),FIX(18),FIX(19),FIX(20),FIX(21),FIX(22),FIX(23), FIX(24),FIX(25),FIX(26),FIX(27),FIX(28),FIX(29),FIX(30),FIX(31),};#define FDIV_SIGN(x,r,y) ( (x)>=0 ? ((((x)+((r)>>1))*(y))>>BITS) : -(((-(x)+((r)>>1))*(y))>>BITS) )void SKL_MB_DATA::Add_DC_AC_Pred(SKL_INT16 In[64], int Dir, SKL_INT16 Left_AC[7], const SKL_MB_DATA *Top, int AC_Q, int DC_Q){ int i; if (Dir==1) { // vertical if (Top[0].Q>0) { // intra block? if (Top[0].Q==AC_Q) { for(i=0; i<7; ++i) In[i+1] += Top->AC[i]; } else { const int Div = Div_AC[AC_Q-1]; // (1<<16) / AC_Q; for(i=0; i<7; ++i) { if (Top->AC[i]!=0) In[i+1] += FDIV_SIGN(Top[0].Q*Top->AC[i], AC_Q, Div); } } } } else if (Dir==2) { // horizontal if (this[-1].Q>0) { // intra block? if (this[-1].Q==AC_Q) { for(i=0; i<7; ++i) In[8*(i+1)] += Left_AC[i]; } else { const int Div = Div_AC[AC_Q-1]; // (1<<16) / AC_Q; for(i=0; i<7; ++i) { if (Left_AC[i]!=0) In[8*(i+1)] += FDIV_SIGN(this[-1].Q*Left_AC[i], AC_Q, Div); } } } } for(i=0; i<7; ++i) { AC[i] = In[i+1]; Left_AC[i] = In[8*(i+1)]; } if (DC>0) In[0] += FDIV(DC, DC_Q); DC = In[0] * DC_Q; // TODO: redundant with Dequant? (except saturation?) SKL_ASSERT(In[0]>=0 && DC>=0); Q = AC_Q; // this will mark the block as 'Intra'}#undef FDIV_SIGN#undef BITS#undef FIX//////////////////////////////////////////////////////////// I/P(/B) VOP decodingstatic SKL_UINT64 Read_VOP_Time(SKL_FBB *Bits, SKL_MP4_I *VOP){ SKL_UINT64 Time = VOP->Time_Ref; while(Bits->Get_Bits(1)) Time++;// elapsed seconds since last GOV, or I/P VOP Bits->Discard(1); // marker bit Time *= VOP->Time_Frequency; // switch to tick scale Time += Bits->Get_Bits( VOP->Ticks_Bits ); Bits->Discard(1); // marker bit return Time;}//////////////////////////////////////////////////////////static int Read_Video_Packet(SKL_FBB * const Bits, SKL_MP4_I * const VOP){ int Ext_Code = 0; if (VOP->Shape!=RECTANGULAR) { Ext_Code = Bits->Get_Bits(1); if (Ext_Code) // header extension code { if (!(VOP->Sprite_Mode==SPRITE_STATIC && VOP->Is_I_VOP())) { Bits->Discard(13+1); // sprite width + marker bit Bits->Discard(13+1); // sprite height + marker bit Bits->Discard(13+1); // sprite left coord + marker bit Bits->Discard(13+1); // sprite top coord + marker bit } } } const int Nb = SKL_BMASKS::Log2( VOP->MB_W*VOP->MB_H-1 ); const int Pos = (Nb==0) ? 0 : Bits->Get_Bits(Nb); if (VOP->Shape!=BINARY_ONLY) VOP->Quant = Bits->Get_Bits(VOP->Quant_Prec); // now, The Question: why didn't they put the extension // code at the same position, whatever shape, hmm? Why? :( if (VOP->Shape==RECTANGULAR) Ext_Code = Bits->Get_Bits(1); if (Ext_Code) // header extension code { /* SKL_UINT64 Time = */ Read_VOP_Time(Bits, VOP); Bits->Discard(2); // coding type (should match current one) if (VOP->Shape!=RECTANGULAR) { Bits->Discard(1); // change conv. ratio disable. if (!VOP->Is_I_VOP()) Bits->Discard(1); // shape coding type } if (VOP->Shape!=BINARY_ONLY) { VOP->DC_Thresh = DC_Thresh_Tab[ Bits->Get_Bits(3) ]; // intra dc vlc thresh. if (VOP->Sprite_Mode==SPRITE_GMC && VOP->Is_S_VOP() && VOP->Sprite_Nb_Pts>0) VOP->Read_Sprite_Trajectory(Bits); if (VOP->Shape==RECTANGULAR && VOP->Reduced_VOP>=0) { if (VOP->Is_I_VOP() || VOP->Is_P_VOP()) VOP->Reduced_VOP = Bits->Get_Bits(1); else VOP->Reduced_VOP = 0; // disabled for B-VOP } if (!VOP->Is_I_VOP()) VOP->Fwd_Code = Bits->Get_Bits(3); // fwd fixed code if (VOP->Is_B_VOP()) VOP->Bwd_Code = Bits->Get_Bits(3); // bwd fixed code } } if (VOP->New_Pred) { int Nb = VOP->Ticks_Bits + 3; if (Nb>15) Nb = 15; int Id_For_Pred = Bits->Get_Bits( Nb ); if (Bits->Get_Bits(1)) { // id for pred. indications Id_For_Pred = Bits->Get_Bits( Nb ); } Bits->Discard(1); // marker bit } return Pos;}int SKL_MB::Resync_Marker(SKL_FBB * const Bits){ const int Len = Resync - 17; // bit count expected SKL_ASSERT(Len>=0 && Len<=7); SKL_BYTE *Pos = Bits->Pos(); int To_Align = Bits->Bits_Left & 7; if (To_Align==0) { To_Align = 8; Pos++; } // bit stuffing if (Bits->See_Bits(To_Align)!=SKL_BMASKS::And[To_Align-1]) return 0; // marker check if ( Pos[0]!=0 || Pos[1]!=0 || ((Pos[2]>>(7-Len)) != 0x00000001) ) return 0; Bits->Discard( To_Align ); Bits->Discard( 16+1 + Len );// fprintf( stderr, " RESYNC: (%d,%d)", x, y ); const int New_Pos = Read_Video_Packet(Bits, (SKL_MP4_I*)VOL); Resync_Cursor(VOL, New_Pos);// fprintf( stderr, " -> (%d,%d)\n", x, y ); return 1;}//////////////////////////////////////////////////////////// block DCT decoding//////////////////////////////////////////////////////////void SKL_MB::Decode_Intra_Blocks(SKL_FBB * const Bits, SKL_INT16 * const In, const SKL_MP4_I * const VOL) const{ SKL_INT16 *Out = In + 1*64; for(int blk=0; blk<6; ++blk) { const int DC_Q = SKL_MP4_I::DC_Scales[(blk<4)][Quant-1]; int Pred_Dir = Curs[blk]->Choose_Pred_Dir( Tops[blk] ); const int * const Zigzag = VOL->Alt_Vert_Scan ? SKL_MP4_I::Scan_Order[2] : Use_AC_Pred ? SKL_MP4_I::Scan_Order[Pred_Dir] : SKL_MP4_I::Scan_Order[0]; VOL->Quant_Ops.Zero(In); int Off; if (Prev_Quant<VOL->DC_Thresh) { In[0] = Read_DC_Diff( Bits, (blk<4) ); Off = 1; } else Off = 0; if (Cbp & (1<<(5-blk))) // coded Read_Intra_AC(Bits, In, Zigzag, Off); Curs[blk]->Add_DC_AC_Pred(In, Use_AC_Pred ? Pred_Dir : 0, Lefts[blk], Tops[blk], Quant, DC_Q); VOL->Quant_Ops.Dequant_Intra(Out, In, VOL->Q_Intra, Quant, DC_Q); Out += 64; }}void SKL_MB::Decode_Inter_Blocks(SKL_FBB * const Bits, SKL_INT16 * const In, const SKL_MP4_I * const VOL) const{ SKL_INT16 *Out = In + 1*64; const int * const Zigzag = VOL->Alt_Vert_Scan ? SKL_MP4_I::Scan_Order[2] : SKL_MP4_I::Scan_Order[0]; for(int blk=(1<<5); blk; blk>>=1) { if (Cbp & blk) // coded { VOL->Quant_Ops.Zero(In); const int Rows = Read_Inter_AC(Bits, In, Zigzag); VOL->Quant_Ops.Dequant_Inter(Out, In, VOL->Q_Inter, Quant, Rows&0xff); } Out += 64; }}//////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -