?? skl_mpg4_enc.cpp
字號:
} } if (Field_DCT>=0) // interlace? { if (Cbp!=0) Bits->Put_Bits( Field_DCT, 1 ); if (B_Type!=SKL_MB_DIRECT) { Bits->Put_Bits( Field_Pred, 1 ); if (Field_Pred) { if (B_Type!=SKL_MB_BWD) Bits->Put_Bits( Field_Dir&3, 2 ); // Fwd Top/Bottom field select. if (B_Type!=SKL_MB_FWD) Bits->Put_Bits( Field_Dir>>2, 2 ); // Bwd Top/Bottom field select. } } } const SKL_SAFE_INT Pos = Bits->Write_Bit_Pos(); if (B_Type == SKL_MB_DIRECT) { if (!ModB1) Write_Vector(Bits, dMVs[0], 1); // FCode=1, always } else { if (B_Type!=SKL_MB_BWD) { Write_Vector(Bits, dMVs[0], Fwd_Code); if (Field_Pred) Write_Vector(Bits, dMVs[1], Fwd_Code); } if (B_Type!=SKL_MB_FWD) { Write_Vector(Bits, dMVs[2], Bwd_Code); if (Field_Pred) Write_Vector(Bits, dMVs[3], Bwd_Code); } } MV_Bits += Bits->Write_Bit_Pos() - Pos; const SKL_SAFE_INT Pos2 = Bits->Write_Bit_Pos(); SKL_INT16 *C = In; for(int blk=0; blk<6; ++blk) { if (Last[blk]>=0) Write_Coeffs( Bits, C, SKL_MP4_I::Scan_Order[0], Last[blk], B16_17_Tabs[0]); C += 64; } Texture_Bits += Bits->Write_Bit_Pos() - Pos2; Set_Not_Intra();}//////////////////////////////////////////////////////////// encoder-only MB ops//////////////////////////////////////////////////////////void SKL_MB_ENC::Copy_8To16(SKL_INT16 Out[6*64]) const{ VOL->MB_Ops.Copy_16x8_8To16(Out+0*64, Y1, YBpS); VOL->MB_Ops.Copy_16x8_8To16(Out+2*64, Y2, YBpS); VOL->MB_Ops.Copy_8x8_8To16( Out+4*64, U, BpS); VOL->MB_Ops.Copy_8x8_8To16( Out+5*64, V, BpS);}void SKL_MB_ENC::Diff_8To16(SKL_INT16 Out[6*64]) const{ VOL->MB_Ops.Diff_16x8_8To16(Out+0*64, Y1, YBpS); VOL->MB_Ops.Diff_16x8_8To16(Out+2*64, Y2, YBpS); VOL->MB_Ops.Diff_8x8_8To16( Out+4*64, U, BpS); VOL->MB_Ops.Diff_8x8_8To16( Out+5*64, V, BpS);}//////////////////////////////////////////////////////////// DC/AC prediction//////////////////////////////////////////////////////////int SKL_MB_ENC::Select_DC_AC_Pred(SKL_INT16 In[6*64], int Pred_Dirs[6]){ int i, blk; int Preds[6][7+1]; // 7 predictors/blk + 1 'worthiness' flag SKL_INT16 *C; int S_With_AC = 0; int S_Without_AC = 0; for(C=In, blk=0; blk<6; ++blk) { int Pred_DC; SKL_INT16 * const Left_AC = Lefts[blk]; const SKL_MB_DATA * const Top = Tops[blk]; SKL_MB_DATA * const Cur = Curs[blk]; const int AC_Q = Quant; const int DC_Q = SKL_MP4_I::DC_Scales[(blk<4)][AC_Q-1]; Preds[blk][7] = 1; // a priori guess: it's worth predicting // first, deal with DC const SKL_INT16 a = Cur[-1].DC; const SKL_INT16 b = Top[-1].DC; const SKL_INT16 c = Top[ 0].DC; if (ABS(a-b)<ABS(c-b)) { // vertical Pred_DC = c; if (Top[0].Q<=0) // Potential prediction block is not intra. Preds[blk][7] = 0; // => Not worth AC predicting (dflt coeffs={0}). Pred_Dirs[blk] = 1; } else { // horizontal Pred_DC = a; if (Cur[-1].Q<=0) // Potential prediction block is not intra. Preds[blk][7] = 0; // => Not worth AC predicting (dflt coeffs={0}). Pred_Dirs[blk] = 2; } // predict DC no matter what Cur->DC = C[0] * DC_Q; // TODO: redundant with Dequant_XXX (except saturation?) Cur->Q = AC_Q; // this will mark the block as 'Intra' SKL_ASSERT(C[0]>=0 && Pred_DC>=0); if (Pred_DC>0) C[0] -= ( Pred_DC + (DC_Q>>1) ) / DC_Q; if (!Preds[blk][7]) // done? goto End; // guess whether AC prediction is worth it or not if (Pred_Dirs[blk]==1) { // vertical for(i=0; i<7; ++i) { Preds[blk][i] = C[i+1]; if (Top->AC[i]!=0) { S_Without_AC += ABS(C[i+1]); if (Top[0].Q!=AC_Q) { int Corr = Top->AC[i]*Top[0].Q; Preds[blk][i] -= DIV_ROUND(Corr, AC_Q); } else Preds[blk][i] -= Top->AC[i]; S_With_AC += ABS(Preds[blk][i]); } // else: if AC[i]==0, both predicted and // unpredicted coeffs will weight the same // in sums, and cancel each others. // So we don't add either of them. } } else { // horizontal for(i=0; i<7; ++i) { Preds[blk][i] = C[8*(i+1)]; if (Left_AC[i]!=0) { S_Without_AC += ABS(C[8*(i+1)]); if (Cur[-1].Q!=AC_Q) { int Corr = Left_AC[i]*Cur[-1].Q; Preds[blk][i] -= DIV_ROUND(Corr, AC_Q); } else Preds[blk][i] -= Left_AC[i]; S_With_AC += ABS(Preds[blk][i]); } } }End: // store for other predictions for(i=0; i<7; ++i) { Cur->AC[i] = C[i+1]; Left_AC[i] = C[8*(i+1)]; } C += 64; } if (S_Without_AC>S_With_AC) // Ok. Go for it! { for(C=In, blk=0; blk<6; ++blk) { if (Preds[blk][7]) { if (Pred_Dirs[blk]==1) for(i=0; i<7; ++i) C[i+1] = Preds[blk][i]; else for(i=0; i<7; ++i) C[8*(i+1)] = Preds[blk][i]; } C += 64; } return 1; } else return 0; // was no avail...}////////////////////////////////////////////////////////////// Compressive part//// Let's explain a little bit what's going on. We're here// to perform the following steps://// 1) Import YUV 8b-data from picture to 16b DCT-coeffs C[]// 2) FDCT( C[] )// 3) C[] /= Q (quantization)// 4) C[] -= Preds[] (remove prediction, if any)// 5) Encode C[] (into bitstream)// 6) Decode C[]// 7) C[] += Preds// 8) C[] *= Q (dequantization)// 9) IDCT( C[] ) (backward transform)// 10) Export reconstructed data to picture//// Notes:// . Using FDCT and scale-based quantization is not mandatory// in itself. Only does the MPEG familly of hybrid encoder// requires it. But you can instead try wavelets, cosmic rays-based// quantization, whatever. :) The encoder (almost) doesn't care.//// . Also, the actual way spatio(-temporal) predictors are chosen// pertain to the encoding format (here: MPEG4) only.// The frame analyzer/motion estimator shouldn't care (much)// about it. MPEG2 used to use different predictors, for instance.//// . Steps 6->10 are reserved to the decoder, but we// have, as an encoder, to keep sync with what will// be perceived by the decoder. ////// Anyway, the *only* lossy step is 3). Afterward, C[] // remain constant until step 8). Hence, we need not perform// steps 6-7: just save C[] after quantization, and restore it // for step 8).//// Now, we can reorder the job as://// a) Import(C) | FDCT(C) | C/=Q | Copy C in C' | C'*=Q / IDCT(C') | Export(C')// b) C -= Preds | Encode(C)//// Step a) is function 'Decimate_Intra()', whereas step b) is 'Encode_Intra()'//// There are additional subtleties possible during the// FDCT| C/=Q | C*=Q | IDCT stage. In particular, one can save some// transposes, at the expense of playing with zigzag orders, predicted// directions, etc. One can also try to combine the C/=Q and C*=Q steps// in a efficient manner, mix with DCTs, etc... Research is open.//// Finally, note that Inter coding is almost the same. Only does it requires// some kind of motion estimation to Import() efficiently. But you can// try random Motion Vectors too, no pb.//// That's it. Now, go!////////////////////////////////////////////////////////////void SKL_MB_ENC::Decimate_Intra(SKL_INT16 Out[12*64]) const{ Copy_8To16(Out+6*64); // import SKL_INT16 *C = Out; // Decimate const SKL_MP4_ENC_I * const Vol = (const SKL_MP4_ENC_I *)VOL; for(int blk=0; blk<6; ++blk) { const int DC_Q = SKL_MP4_I::DC_Scales[(blk<4)][Quant-1]; Vol->Decimate_Intra(C, C+6*64, Quant, DC_Q); C += 64; } Copy_16To8(Out+6*64); // transfer back decimated data}void SKL_MB_ENC::Decimate_Inter(SKL_INT16 Out[12*64]){ SKL_ASSERT(MC_Sel==0); if (MB_Type==SKL_MB_SKIPPED) { Predict_With_0MV(VOL->Copy_Ops, 1); Store_Zero_MV(); return; } // Fwd predict int Skippable = (dQuant==0) && SKL_IS_ZERO_MV(MVs[0]) && (VOL->Coding!=S_VOP); Copy_8To16(Out + 6*64); // save original data if (Field_Pred) { // form predictions Predict_Fields(MVs, VOL->Copy_Ops, 1, Field_Dir); Store_16x8_MV(&MVs2[0], &MVs[0]); SKL_COPY_MV(MVs[1], MVs2[0]); // update left predictor if (Skippable) Skippable &= SKL_IS_ZERO_MV(MVs2[0]); } else { if (MB_Type!=SKL_MB_INTER4V) { Predict_With_1MV(MVs[0], VOL->Copy_Ops, 1); Store_16x16_MV(); } else { Predict_With_4MV(&MVs[0], &MVs2[0], VOL->Copy_Ops, 1); if (Skippable) { Skippable &= SKL_IS_ZERO_MV(MVs [1]); Skippable &= SKL_IS_ZERO_MV(MVs2[0]); Skippable &= SKL_IS_ZERO_MV(MVs2[1]); } } } Diff_8To16(Out + 6*64); // diff original/predicted data SKL_INT16 *C = Out; // Decimate and set Cbp Cbp = 0x00; const SKL_MP4_ENC_I * const Vol = (const SKL_MP4_ENC_I*)VOL; for(int blk=0; blk<6; ++blk) { const int SAV = Vol->Decimate_Inter(C, C+6*64, Quant); if (SAV>0) { Last[blk] = Find_Last(C, SKL_MP4_I::Scan_Order[0], 63); SKL_ASSERT(Last[blk]>=0); Cbp |= 1<<(5-blk); } else Last[blk] = -1; C += 64; } if (!Skippable || Cbp!=0) Add_16To8(Out + 6*64); // transfer back decimated delta data else MB_Type = SKL_MB_SKIPPED; // won't be coded (don't transfer back data)}void SKL_MB_ENC::Decimate_Inter_GMC(SKL_INT16 Out[12*64]){ SKL_ASSERT(Field_Pred==0 && MC_Sel!=0); SKL_ASSERT(MB_Type==SKL_MB_INTER || MB_Type==SKL_MB_SKIPPED); if (MB_Type!=SKL_MB_SKIPPED) Copy_8To16(Out+6*64); // save original data Predict_GMC(); if (MB_Type!=SKL_MB_SKIPPED) Diff_8To16(Out+6*64); // diff original/predicted data else return; // Done SKL_INT16 *C = Out; // Decimate and set Cbp Cbp = 0x00; const SKL_MP4_ENC_I * const Vol = (const SKL_MP4_ENC_I *)VOL; for(int blk=0; blk<6; ++blk) { const int SAV = Vol->Decimate_Inter(C, C+6*64, Quant); if (SAV>0) { Last[blk] = Find_Last(C, SKL_MP4_I::Scan_Order[0], 63); SKL_ASSERT(Last[blk]>=0); Cbp |= 1<<(5-blk); } else Last[blk] = -1; C += 64; } const int Skippable = (dQuant==0); if (!Skippable || Cbp!=0) Add_16To8(Out+6*64); // transfer back decimated delta data else MB_Type = SKL_MB_SKIPPED; // won't be coded (don't transfer back data)}//////////////////////////////////////////////////////////// bitstream coding//////////////////////////////////////////////////////////static void Stuffed_Align(SKL_FBB * const Bits) // hardcoded Table 6.2{ int Left = 8 - (Bits->Bits_Left & 7); Bits->Put_Bits( SKL_BMASKS::And[Left-1], Left ); Bits->Flush_Write();}static void Write_User_Data(SKL_FBB * const Bits, int Len, const SKL_BYTE *Data){ Bits->Flush_Write(); Bits->Put_DWord( USER_DATA_CODE ); // TODO: check data doesn't emulate a start code? while(Len-->0) Bits->Put_Bits( *Data++, 8 ); Stuffed_Align(Bits);}static void Write_Matrix(SKL_FBB * const Bits, const SKL_BYTE *M){ int Last = M[SKL_MP4_I::Scan_Order[0][63]]; int i, j; for(j=62; j>0; --j) if (M[SKL_MP4_I::Scan_Order[0][j]]!=Last) break; for(i=0; i<=j; ++i) Bits->Put_Bits( M[SKL_MP4_I::Scan_Order[0][i]], 8 ); if (j<63) Bits->Put_Bits(0, 8);}static void Write_Sprite_Comp(SKL_FBB * const Bits, int v){ if (v) { int Size; const int Sign = (v<0); if (Sign) { Size = SKL_BMASKS::Log2(-v); v += SKL_BMASKS::And[Size]; } else { Size = SKL_BMASKS::Log2(v); v |= SKL_BMASKS::Or[Size]; } SKL_ASSERT(Size>=0 && Size<15); Bits->Put_Bits(Spr_Tab_B33[Size].Val,Spr_Tab_B33[Size].Len); Bits->Put_Bits(v, Size); } else Bits->Put_Bits(Spr_Tab_B33[0].Val,Spr_Tab_B33[0].Len);}static void Write_Sprite_Trajectory(SKL_FBB * const Bits, const int Pts[][2], int Nb){ for(int n=0; n<Nb; ++n) { Write_Sprite_Comp(Bits, Pts[n][0]); Bits->Put_Bits(1,1); // marker bit Write_Sprite_Comp(Bits, Pts[n][1]); Bits->Put_Bits(1,1); // marker bit }} // section 6.2.3void SKL_MP4_ENC_I::Write_VOL_Header(SKL_FBB * const Bits) const{ int Verid = (Quarter>0 || Reduced_VOP>=0 || Sprite_Mode>=SPRITE_GMC) ? 2 : 1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -