?? coder.c
字號:
/************************************************************************ *主編碼程序* ************************************************************************/#include"sim.h"/********************************************************************** * * 函數: CodeOneOrTwo * 功能: 編碼正常的一幀圖像或兩幀PB模式的圖像 * 輸入: 圖像數據指針,前一幀圖像指針,重構圖像指針,量化參數等 * 返回值:重構圖像的指針 ***********************************************************************/void CodeOneOrTwo(PictImage *curr, PictImage *B_image, PictImage *prev, PictImage *pr, int QP, int frameskip, Bits *bits, Pict *pic, PictImage *B_recon, PictImage *recon){ unsigned char *prev_ipol,*pi_edge=NULL,*pi,*orig_lum; PictImage *prev_recon=NULL, *pr_edge=NULL; MotionVector *MV[6][MBR+1][MBC+2]; MotionVector ZERO = {0,0,0,0,0}; MB_Structure *recon_data_P; MB_Structure *recon_data_B=NULL; MB_Structure *diff; int *qcoeff_P; int *qcoeff_B=NULL; int Mode,B; int CBP, CBPB=0; int bquant[] = {5,6,7,8}; int QP_B; int newgob; int i,j,k; /* 編碼所需的存儲 */ float QP_cumulative = (float)0.0; int abs_mb_num = 0, QuantChangePostponed = 0; int QP_new, QP_prev, dquant, QP_xmitted=QP; ZeroBits(bits); /* 內插圖像 */ if (mv_outside_frame) { if (long_vectors) { /* 如果編碼器使用了擴展的運動向量范圍,那么運動向量可能
會進一步指向視頻幀外,從而超出一個正常的搜索范圍。
因此邊界圖像將不得不擴大尺寸 */ B = 16; } else { /* 正常搜索范圍 */ B = 8; } pi_edge = (unsigned char *)malloc(sizeof(char)*(pels+4*B)*(lines+4*B)); if (pi_edge == NULL) { fprintf(stderr,"Couldn't allocate memory for pi_edge\n"); exit(-1); } MakeEdgeImage(pr->lum,pi_edge + (pels + 4*B)*2*B+2*B,pels,lines,2*B); pi = InterpolateImage(pi_edge, pels+4*B, lines+4*B); free(pi_edge); prev_ipol = pi + (2*pels + 8*B) * 4*B + 4*B; /* 非內插圖像的亮度信息 */ pr_edge = InitImage((pels+4*B)*(lines+4*B)); MakeEdgeImage(prev->lum, pr_edge->lum + (pels + 4*B)*2*B+2*B, pels,lines,2*B); orig_lum = pr_edge->lum + (pels + 4*B)*2*B+2*B; /* 非內插圖像 */ MakeEdgeImage(pr->lum,pr_edge->lum + (pels+4*B)*2*B + 2*B,pels,lines,2*B); MakeEdgeImage(pr->Cr,pr_edge->Cr + (pels/2 + 2*B)*B + B,pels/2,lines/2,B); MakeEdgeImage(pr->Cb,pr_edge->Cb + (pels/2 + 2*B)*B + B,pels/2,lines/2,B); prev_recon = (PictImage *)malloc(sizeof(PictImage)); prev_recon->lum = pr_edge->lum + (pels + 4*B)*2*B + 2*B; prev_recon->Cr = pr_edge->Cr + (pels/2 + 2*B)*B + B; prev_recon->Cb = pr_edge->Cb + (pels/2 + 2*B)*B + B; } else { pi = InterpolateImage(pr->lum,pels,lines); prev_ipol = pi; prev_recon = pr; orig_lum = prev->lum; } /* 標記幀外的PMV信息 */ for (i = 1; i < (pels>>4)+1; i++) { for (k = 0; k < 6; k++) { MV[k][0][i] = (MotionVector *)malloc(sizeof(MotionVector)); MarkVec(MV[k][0][i]); } MV[0][0][i]->Mode = MODE_INTRA; } /* 幀外的PMVzero out PMV's outside the frame */ for (i = 0; i < (lines>>4)+1; i++) { for (k = 0; k < 6; k++) { MV[k][i][0] = (MotionVector *)malloc(sizeof(MotionVector)); ZeroVec(MV[k][i][0]); MV[k][i][(pels>>4)+1] = (MotionVector *)malloc(sizeof(MotionVector)); ZeroVec(MV[k][i][(pels>>4)+1]); } MV[0][i][0]->Mode = MODE_INTRA; MV[0][i][(pels>>4)+1]->Mode = MODE_INTRA; } /* 整像素精度和半像素精度的運動估計*/ MotionEstimatePicture(curr->lum,prev_recon->lum,prev_ipol, pic->seek_dist,MV, pic->use_gobsync); /* 注意:整像素精度的運動估計是在之前已重構圖像的基礎上進行的,
而不是基于之前的原始視頻幀圖像。這種方法較為有效。此外,
如利用orig_lum取代prev_recon->lum的話,會造成運動估計中一些
不可逆轉的錯誤,這是因為零向量的SAD值在半像素精度搜索中不會
重新計算。半像素精度的運動估計計算總是基于之前已重構圖像進行的。 */#ifndef OFFLINE_RATE_CONTROL if (pic->bit_rate != 0) { /* 率控制的初始化 */ QP_new = InitializeQuantizer(PCT_INTER, (float)pic->bit_rate, (pic->PB ? pic->target_frame_rate/2 : pic->target_frame_rate), pic->QP_mean); QP_xmitted = QP_prev = QP_new; } else { QP_new = QP_xmitted = QP_prev = QP; /* 復制量化參數的值 */ }#else QP_new = QP_xmitted = QP_prev = QP; /* 復制量化參數的值 */#endif dquant = 0; for ( j = 0; j < lines/MB_SIZE; j++) {#ifndef OFFLINE_RATE_CONTROL if (pic->bit_rate != 0) { /* 每行開始編碼之前更新量化參數 */ AddBitsPicture(bits); QP_new = UpdateQuantizer(abs_mb_num, pic->QP_mean, PCT_INTER, (float)pic->bit_rate, pels/MB_SIZE, lines/MB_SIZE, bits->total); }#endif newgob = 0; if (j == 0) { pic->QUANT = QP_new; bits->header += CountBitsPicture(pic); QP_xmitted = QP_prev = QP_new; } else if (pic->use_gobsync && j%pic->use_gobsync == 0) { bits->header += CountBitsSlice(j,QP_new); /* insert gob sync */ QP_xmitted = QP_prev = QP_new; newgob = 1; } for ( i = 0; i < pels/MB_SIZE; i++) { /* 更新解量化,檢查并保證其限度的正確性 */ dquant = QP_new - QP_prev; if (dquant != 0 && i != 0 && MV[0][j+1][i+1]->Mode == MODE_INTER4V) { /* 在使用8×8向量的時候,編碼器幾乎不可能改變量化器參數。
此外,由于已編碼宏塊需要使用8×8運動向量來完成編碼,
因此在本階段中該運動向量不能置0關閉。基于上述理由,
編碼器在檢測到第一個不含8×8運動向量的宏塊后才去更新
量化器 */ dquant = 0; QP_xmitted = QP_prev; QuantChangePostponed = 1; } else { QP_xmitted = QP_new; QuantChangePostponed = 0; } if (dquant > 2) { dquant = 2; QP_xmitted = QP_prev + dquant;} if (dquant < -2) { dquant = -2; QP_xmitted = QP_prev + dquant;} pic->DQUANT = dquant; /* 如果dquant != 0,則修改量化器模式 */ Mode = ModifyMode(MV[0][j+1][i+1]->Mode,pic->DQUANT); MV[0][j+1][i+1]->Mode = Mode; pic->MB = i + j * (pels/MB_SIZE); if (Mode == MODE_INTER || Mode == MODE_INTER_Q || Mode==MODE_INTER4V) { /* 預測P幀的宏塊 */ diff = Predict_P(curr,prev_recon,prev_ipol, i*MB_SIZE,j*MB_SIZE,MV,pic->PB); } else { diff = (MB_Structure *)malloc(sizeof(MB_Structure)); FillLumBlock(i*MB_SIZE, j*MB_SIZE, curr, diff); FillChromBlock(i*MB_SIZE, j*MB_SIZE, curr, diff); } /* P幀宏塊和幀內宏塊 */ qcoeff_P = MB_Encode(diff, QP_xmitted, Mode); CBP = FindCBP(qcoeff_P, Mode, 64); if (CBP == 0 && (Mode == MODE_INTER || Mode == MODE_INTER_Q)) ZeroMBlock(diff); else MB_Decode(qcoeff_P, diff, QP_xmitted, Mode); recon_data_P = MB_Recon_P(prev_recon, prev_ipol,diff, i*MB_SIZE,j*MB_SIZE,MV,pic->PB); Clip(recon_data_P); free(diff); /* 利用P幀宏塊和已解碼圖像來預測B幀宏塊 */ if (pic->PB) { diff = Predict_B(B_image, prev_recon, prev_ipol,i*MB_SIZE, j*MB_SIZE, MV, recon_data_P, frameskip, pic->TRB); if (QP_xmitted == 0) QP_B = 0; /* QP = 0 表示不進行量化 */ else QP_B = mmax(1,mmin(31,bquant[pic->BQUANT]*QP_xmitted/4)); qcoeff_B = MB_Encode(diff, QP_B, MODE_INTER); CBPB = FindCBP(qcoeff_B, MODE_INTER, 64); if (CBPB) MB_Decode(qcoeff_B, diff, QP_B, MODE_INTER); else ZeroMBlock(diff); recon_data_B = MB_Recon_B(prev_recon, diff,prev_ipol,i*MB_SIZE, j*MB_SIZE,MV,recon_data_P,frameskip, pic->TRB); Clip(recon_data_B); /* 判定MODB類型 */ if (CBPB) { pic->MODB = PBMODE_CBPB_MVDB; } else { if (MV[5][j+1][i+1]->x == 0 && MV[5][j+1][i+1]->y == 0) pic->MODB = PBMODE_NORMAL; else pic->MODB = PBMODE_MVDB; } free(diff); } else ZeroVec(MV[5][j+1][i+1]); /* Zero out PB deltas */ if ((CBP==0) && (CBPB==0) && (EqualVec(MV[0][j+1][i+1],&ZERO)) && (EqualVec(MV[5][j+1][i+1],&ZERO)) && (Mode == MODE_INTER || Mode == MODE_INTER_Q)) { /* 跳過宏塊:CBP和CBPB都等于0,16×16的運動向量也為0。 如果PB幀模式下的運動向量變化為0,那么編碼模式為幀間模式 */ if (Mode == MODE_INTER_Q) { /* DQUANT != 0 but not coded anyway */ QP_xmitted = QP_prev; pic->DQUANT = 0; Mode = MODE_INTER; } if (!syntax_arith_coding) CountBitsMB(Mode,1,CBP,CBPB,pic,bits); else Count_sac_BitsMB(Mode,1,CBP,CBPB,pic,bits); } else { /* 常規的宏塊 */ if (!syntax_arith_coding) { /* 變長編碼 */ CountBitsMB(Mode,0,CBP,CBPB,pic,bits); if (Mode == MODE_INTER || Mode == MODE_INTER_Q) { bits->no_inter++; CountBitsVectors(MV, bits, i, j, Mode, newgob, pic); } else if (Mode == MODE_INTER4V) { bits->no_inter4v++; CountBitsVectors(MV, bits, i, j, Mode, newgob, pic); } else { /* 幀內模式或幀內量化模式 */ bits->no_intra++; if (pic->PB) CountBitsVectors(MV, bits, i, j, Mode, newgob, pic); } if (CBP || Mode == MODE_INTRA || Mode == MODE_INTRA_Q) CountBitsCoeff(qcoeff_P, Mode, CBP, bits, 64); if (CBPB) CountBitsCoeff(qcoeff_B, MODE_INTER, CBPB, bits, 64); } /* 變長編碼結束 */ else { /* SAC編碼 */ Count_sac_BitsMB(Mode,0,CBP,CBPB,pic,bits); if (Mode == MODE_INTER || Mode == MODE_INTER_Q) { bits->no_inter++; Count_sac_BitsVectors(MV, bits, i, j, Mode, newgob, pic); } else if (Mode == MODE_INTER4V) { bits->no_inter4v++; Count_sac_BitsVectors(MV, bits, i, j, Mode, newgob, pic); } else { /* 幀內模式或幀內量化模式 */ bits->no_intra++; if (pic->PB) Count_sac_BitsVectors(MV, bits, i, j, Mode, newgob, pic); } if (CBP || Mode == MODE_INTRA || Mode == MODE_INTRA_Q) Count_sac_BitsCoeff(qcoeff_P, Mode, CBP, bits, 64); if (CBPB) Count_sac_BitsCoeff(qcoeff_B, MODE_INTER, CBPB, bits, 64); } /* SAC編碼結束 */ QP_prev = QP_xmitted; } abs_mb_num++; QP_cumulative += QP_xmitted; #ifdef PRINTQ /* 若量化器在幀內發生變換 */ if (QuantChangePostponed) fprintf(stdout,"@%2d",QP_xmitted); else fprintf(stdout," %2d",QP_xmitted);#endif if (pic->PB) ReconImage(i,j,recon_data_B,B_recon); ReconImage(i,j,recon_data_P,recon); free(recon_data_P); free(qcoeff_P); if (pic->PB) { free(qcoeff_B); free(recon_data_B); } }#ifdef PRINTQ fprintf(stdout,"\n");#endif } pic->QP_mean = QP_cumulative/(float)abs_mb_num; /* 釋放內存 */ free(pi); if (mv_outside_frame) { free(prev_recon); FreeImage(pr_edge); } for (j = 0; j < (lines>>4)+1; j++) for (i = 0; i < (pels>>4)+2; i++) for (k = 0; k < 6; k++) free(MV[k][j][i]); return;}/********************************************************************** * * 函數名: CodeOneIntra * 函數功能: 編碼一幀I幀圖像 * 函數輸入: I幀圖像數據指針及量化參數 * 函數返回值:重構圖像的數據指針 ***********************************************************************/PictImage *CodeOneIntra(PictImage *curr, int QP, Bits *bits, Pict *pic)
{
PictImage *recon; //函數返回值,一個重構的視頻幀
MB_Structure *data = (MB_Structure *)malloc(sizeof(MB_Structure));
int *qcoeff;
int Mode = MODE_INTRA;
int CBP,COD;
int i,j;
//初始化
recon = InitImage(pels*lines);
ZeroBits(bits);
//設定量化參數
pic->QUANT = QP;
bits->header += CountBitsPicture(pic);
COD = 0; /* 所有的編碼塊都在幀內編碼*/
for ( j = 0; j < lines/MB_SIZE; j++) {
/* 在每一個幀圖像分片中插入數據流語義信息 */
if (pic->use_gobsync && j != 0)
bits->header += CountBitsSlice(j,QP);
for ( i = 0; i < pels/MB_SIZE; i++) {
//將幀數據組成宏塊和編碼塊
pic->MB = i + j * (pels/MB_SIZE);
bits->no_intra++;
FillLumBlock(i*MB_SIZE, j*MB_SIZE, curr, data);
FillChromBlock(i*MB_SIZE, j*MB_SIZE, curr, data);
qcoeff = MB_Encode(data, QP, Mode);
CBP = FindCBP(qcoeff,Mode,64);
//使用VLC編碼
if (!syntax_arith_coding) {
CountBitsMB(Mode,COD,CBP,0,pic,bits);
CountBitsCoeff(qcoeff, Mode, CBP,bits,64);
} else { //使用SAC編碼
Count_sac_BitsMB(Mode,COD,CBP,0,pic,bits);
Count_sac_BitsCoeff(qcoeff, Mode, CBP,bits,64);
}
//重構視頻幀,確定輸出
MB_Decode(qcoeff, data, QP, Mode);
Clip(data);
ReconImage(i,j,data,recon);
free(qcoeff);
}
}
pic->QP_mean = (float)QP;
free(data);
return recon;
}
/********************************************************************** * * 函數名: MB_Encode * 函數功能:宏塊的DCT變換與量化 * * 輸入: 宏塊數據結構,量化參數,宏塊信息結構
* 返回值:量化系數的指針 **********************************************************************/int *MB_Encode(MB_Structure *mb_orig, int QP, int I){ int i, j, k, l, row, col; int fblock[64]; int coeff[384]; int *coeff_ind; int *qcoeff; int *qcoeff_ind; if ((qcoeff=(int *)malloc(sizeof(int)*384)) == 0) { fprintf(stderr,"mb_encode(): Couldn't allocate qcoeff.\n"); exit(-1); } coeff_ind = coeff; qcoeff_ind = qcoeff; for (k=0;k<16;k+=8) { for (l=0;l<16;l+=8) { for (i=k,row=0;row<64;i++,row+=8) { for (j=l,col=0;col<8;j++,col++) { *(fblock+row+col) = mb_orig->lum[i][j]; } } Dct(fblock,coeff_ind); Quant(coeff_ind,qcoeff_ind,QP,I); coeff_ind += 64; qcoeff_ind += 64; } } for (i=0;i<8;i++) { for (j=0;j<8;j++) { *(fblock+i*8+j) = mb_orig->Cb[i][j]; } } Dct(fblock,coeff_ind); Quant(coeff_ind,qcoeff_ind,QP,I); coeff_ind += 64; qcoeff_ind += 64; for (i=0;i<8;i++) { for (j=0;j<8;j++) { *(fblock+i*8+j) = mb_orig->Cr[i][j]; } } Dct(fblock,coeff_ind); Quant(coeff_ind,qcoeff_ind,QP,I); return qcoeff;}/********************************************************************** * * 函數名: MB_Decode * 函數功能: 重構一個量化后DCT編碼的宏塊 * 輸入:量化系數、編碼宏塊、量化參數以及宏塊信息 * 返回值:0 * **********************************************************************/ int MB_Decode(int *qcoeff, MB_Structure *mb_recon, int QP, int I){ int i, j, k, l, row, col; int *iblock; int *qcoeff_ind; int *rcoeff, *rcoeff_ind; if ((iblock = (int *)malloc(sizeof(int)*64)) == NULL) { fprintf(stderr,"MB_Coder: Could not allocate space for iblock\n");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -