📄 codeinter.cpp
字号:
#include"stdafx.h"
#include"Global.h"
/**********************************************************************
*
* Name: CodeOneInter
* Description: code one image normally or two images
* as a PB-frame (CodeTwoPB and CodeOnePred merged)
*
* Input: pointer to image, prev_image, prev_recon, Q
*
* Returns: pointer to reconstructed image
* Side effects: memory is allocated to recon image
*
************************************************************************/
void CodeOneInter(PictImage *prev,PictImage *curr,
PictImage *pr,PictImage *curr_recon,
int QP, int frameskip, Bits *bits, Pict *pic)
{
ZeroBits(bits);
unsigned char *prev_ipol,*pi,*orig_lum;
PictImage *prev_recon=NULL;
MotionVector *MV[6][MBR+1][MBC+2];
MotionVector ZERO = {0,0,0,0,0};
int i,j,k;
int newgob,Mode;
int *qcoeff_P;
int CBP, CBPB=0;
MB_Structure *recon_data_P;
MB_Structure *diff;
/* 缓冲器控制变量 */
float QP_cumulative = (float)0.0;
int abs_mb_num = 0, QuantChangePostponed = 0;
int QP_new, QP_prev, dquant, QP_xmitted=QP;
QP_new = QP_xmitted = QP_prev = QP; /* 复制旧QP */
/* 图象插值 */
if(!mv_outside_frame)
{
pi = InterpolateImage(pr->lum,pels,lines);
prev_ipol = pi;
prev_recon = pr;
orig_lum = prev->lum;
}
/* 为每个编码块标记MV */
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;
}
/* 超出图象边界的MV置为0 */
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);
#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; /* 复制旧 QP */
}
#else
QP_new = QP_xmitted = QP_prev = QP; /* 复制旧 QP */
#endif
dquant = 0;
for ( j = 0; j < lines/MB_SIZE; j++) {
#ifndef OFFLINE_RATE_CONTROL
if (pic->bit_rate != 0) {
AddBitsPicture(bits);
/* 更新QP */
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;
bits->header += CountBitsPicture(pic);//计算图象层码字
}
else if (pic->use_gobsync && j%pic->use_gobsync == 0) {
bits->header += CountBitsSlice(j,QP); //输出GOB同步头
newgob = 1;
}
for ( i = 0; i < pels/MB_SIZE; i++) {
/* 更新dquant */
dquant = QP_new - QP_prev;
if (dquant != 0 && i != 0 && MV[0][j+1][i+1]->Mode == MODE_INTER4V) {
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_INTER -> MODE_INTER_Q) */
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);//写亮度图像 curr:图像数据 diff:宏块树组
FillChromBlock(i*MB_SIZE, j*MB_SIZE, curr, diff);//写色度图像
}
/* P或INTRA宏块 */
qcoeff_P = MB_Encode(diff, QP_xmitted, Mode); //对宏块数据(P块为残差数据)进行DCT变换量化
CBP = FindCBP(qcoeff_P, Mode, 64);
if (CBP == 0 && (Mode == MODE_INTER || Mode == MODE_INTER_Q))
ZeroMBlock(diff); //宏块数据设为0
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);//重建P图象
Clip(recon_data_P); //使 0<=recon_data_P<=255
free(diff);
if(pic->PB==0)
ZeroVec(MV[5][j+1][i+1]); //PB帧矢量差置为0
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, 16x16 运动矢量为0,PB矢量差为0,
并且编码模式为MODE_INTER或MODE_INTER_Q,跳过该宏块编码*/
if (!syntax_arith_coding)
CountBitsMB(Mode,1,CBP,CBPB,pic,bits);//输出宏块层信息
}
else { /* 正常编码宏块 */
if (!syntax_arith_coding) { /* VLC */
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 {
/* MODE_INTRA 或 MODE_INTRA_Q */
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);//输出系数
} // end VLC
QP_prev = QP_xmitted;
}//end Normal MB
abs_mb_num++;
QP_cumulative += QP_xmitted;
ReconImage(i,j,recon_data_P,curr_recon);//重建图象
free(recon_data_P);
free(qcoeff_P);
}//end for i
}//end for j
pic->QP_mean = QP_cumulative/(float)abs_mb_num;
/* 释放内存 */
free(pi);
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;
}
void ZeroVec(MotionVector *MV)
{
MV->x = 0;
MV->y = 0;
MV->x_half = 0;
MV->y_half = 0;
return;
}
void MarkVec(MotionVector *MV)
{
MV->x = NO_VEC;
MV->y = NO_VEC;
MV->x_half = 0;
MV->y_half = 0;
return;
}
void CopyVec(MotionVector *MV2, MotionVector *MV1)
{
MV2->x = MV1->x;
MV2->x_half = MV1->x_half;
MV2->y = MV1->y;
MV2->y_half = MV1->y_half;
return;
}
int EqualVec(MotionVector *MV2, MotionVector *MV1)
{
if (MV1->x != MV2->x)
return 0;
if (MV1->y != MV2->y)
return 0;
if (MV1->x_half != MV2->x_half)
return 0;
if (MV1->y_half != MV2->y_half)
return 0;
return 1;
}
unsigned char *InterpolateImage(unsigned char *image, int width, int height)
{
unsigned char *ipol_image, *ii, *oo;
int i,j;
ipol_image = (unsigned char *)malloc(sizeof(char)*width*height*4);
ii = ipol_image;
oo = image;
/* main image */
for (j = 0; j < height-1; j++) {
for (i = 0; i < width-1; i++) {
*(ii + (i<<1)) = *(oo + i);
*(ii + (i<<1)+1) = (unsigned char)((*(oo + i) + *(oo + i + 1) + 1)>>1);
*(ii + (i<<1)+(width<<1)) = (unsigned char)((*(oo + i) + *(oo + i + width) + 1)>>1);
*(ii + (i<<1)+1+(width<<1)) = (unsigned char)((*(oo+i) + *(oo+i+1) +
*(oo+i+width) + *(oo+i+1+width) + 2)>>2);
}
/* last pels on each line */
*(ii+ (width<<1) - 2) = *(oo + width - 1);
*(ii+ (width<<1) - 1) = *(oo + width - 1);
*(ii+ (width<<1)+ (width<<1)-2) = (unsigned char)((*(oo+width-1)+*(oo+width+width-1)+1)>>1);
*(ii+ (width<<1)+ (width<<1)-1) = (unsigned char)((*(oo+width-1)+*(oo+width+width-1)+1)>>1);
ii += (width<<2);
oo += width;
}
/* last lines */
for (i = 0; i < width-1; i++) {
*(ii+ (i<<1)) = *(oo + i);
*(ii+ (i<<1)+1) = (unsigned char)((*(oo + i) + *(oo + i + 1) + 1)>>1);
*(ii+ (width<<1)+ (i<<1)) = *(oo + i);
*(ii+ (width<<1)+ (i<<1)+1) = (unsigned char)((*(oo + i) + *(oo + i + 1) + 1)>>1);
}
/* bottom right corner pels */
*(ii + (width<<1) - 2) = *(oo + width -1);
*(ii + (width<<1) - 1) = *(oo + width -1);
*(ii + (width<<2) - 2) = *(oo + width -1);
*(ii + (width<<2) - 1) = *(oo + width -1);
return ipol_image;
}
void MotionEstimatePicture(unsigned char *curr, unsigned char *prev,
unsigned char *prev_ipol, int seek_dist,
MotionVector *MV[6][MBR+1][MBC+2], int gobsync)
{
int i,j,k;
int pmv0,pmv1,xoff,yoff;
int curr_mb[16][16];
int sad8 = INT_MAX, sad16, sad0;
int newgob;
MotionVector *f0,*f1,*f2,*f3,*f4;
/* 运动估计并存储结果MV */
for ( j = 0; j < lines/MB_SIZE; j++) {
newgob = 0;
if (gobsync && j%gobsync == 0) {
newgob = 1;
}
for ( i = 0; i < pels/MB_SIZE; i++) {
for (k = 0; k < 6; k++)
MV[k][j+1][i+1] = (MotionVector *)malloc(sizeof(MotionVector));
/* 整象素搜索 */
f0 = MV[0][j+1][i+1];
f1 = MV[1][j+1][i+1];
f2 = MV[2][j+1][i+1];
f3 = MV[3][j+1][i+1];
f4 = MV[4][j+1][i+1];
FindPMV(MV,i+1,j+1,&pmv0,&pmv1,0,newgob,0);
if (long_vectors) {
xoff = pmv0/2; /* 总是能被2整除 */
yoff = pmv1/2;
}
else {
xoff = yoff = 0;
}
MotionEstimation(curr, prev, i*MB_SIZE, j*MB_SIZE,
xoff, yoff, seek_dist, MV, &sad0);
sad16 = f0->min_error;
if (advanced)
sad8 = f1->min_error + f2->min_error + f3->min_error + f4->min_error;
f0->Mode = ChooseMode(curr,i*MB_SIZE,j*MB_SIZE, mmin(sad8,sad16));
/* 半象素精度搜索 */
if (f0->Mode != MODE_INTRA) {
FindMB(i*MB_SIZE,j*MB_SIZE ,curr, curr_mb);//当前宏块放入curr_mb
FindHalfPel(i*MB_SIZE,j*MB_SIZE,f0, prev_ipol, &curr_mb[0][0],16,0);
sad16 = f0->min_error;
if (advanced) {
FindHalfPel(i*MB_SIZE,j*MB_SIZE,f1, prev_ipol, &curr_mb[0][0],8,0);
FindHalfPel(i*MB_SIZE,j*MB_SIZE,f2, prev_ipol, &curr_mb[0][8],8,1);
FindHalfPel(i*MB_SIZE,j*MB_SIZE,f3, prev_ipol, &curr_mb[8][0],8,2);
FindHalfPel(i*MB_SIZE,j*MB_SIZE,f4, prev_ipol, &curr_mb[8][8],8,3);
sad8 = f1->min_error +f2->min_error +f3->min_error +f4->min_error;
sad8 += PREF_16_VEC;
/* 选择0运动矢量, 基于8x8或16x16的运动矢量 */
if (sad0 < sad8 && sad0 < sad16) {
f0->x = f0->y = 0;
f0->x_half = f0->y_half = 0;
}
else {
if (sad8 < sad16)
f0->Mode = MODE_INTER4V;
}
}
else {
/* 选择0运动矢量或基于16x16的运动矢量 */
if (sad0 < sad16) {
f0->x = f0->y = 0;
f0->x_half = f0->y_half = 0;
}
}
}
else
for (k = 0; k < 5; k++)
ZeroVec(MV[k][j+1][i+1]);
}
}
return;
}
void ZeroMBlock(MB_Structure *data)
{
int n;
register int m;
for (n = 0; n < MB_SIZE; n++)
for (m = 0; m < MB_SIZE; m++)
data->lum[n][m] = 0;
for (n = 0; n < (MB_SIZE>>1); n++)
for (m = 0; m < (MB_SIZE>>1); m++) {
data->Cr[n][m] = 0;
data->Cb[n][m] = 0;
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -