前面已经讨论过,在没有B帧的情况下如何提取P帧的运动矢量,没有考虑B帧. 现在考虑P帧,假设视频有12帧,x264对其进行编码,编码的帧结构为:IDR BBPBBPBBPBP. 故共有4个P帧. (视频格式是qcif格式)
我们知道,在H.264中,P帧中可以有I宏块,本人为了便于数据处理,认为I宏块也有运动矢量,其值为零. 与MPEG2不同的是:在H.264中,一个宏块可以继续进行分块,所以并不是一个宏块对应一个运动矢量,而是每个分块都有各自的运动的矢量,为了方便起见,仅仅考虑提取宏块最左上角的那个4*4块对应的运动矢量.
如此一来,4个P帧总共的宏块个数为99 * 4 = 396个, 对应396个运动矢量. 下面来看看重要的read_one_macroblock函数:
// 用x264编码12帧 宏块总数为99 * 12 = 1188
// 编码的帧结构为:IDR BBPBBPBBPBP
// 1个I帧,7个B帧,共4个P帧
int read_one_macroblock(struct img_par *img,struct inp_par *inp)
{
// 12帧共1188个宏块,此处被调用1188次
int i;
SyntaxElement currSE;
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
Slice *currSlice = img->currentSlice;
DataPartition *dP;
int *partMap = assignSE2partition[currSlice->dp_mode];
Macroblock *topMB = NULL;
int prevMbSkipped = 0;
int img_block_y;
int check_bottom, read_bottom, read_top;
if (img->MbaffFrameFlag)
{
if (img->current_mb_nr%2)
{
topMB= &img->mb_data[img->current_mb_nr-1];
if(!(img->type == B_SLICE))
prevMbSkipped = (topMB->mb_type == 0);
else
prevMbSkipped = (topMB->mb_type == 0 && topMB->cbp == 0);
}
else
prevMbSkipped = 0;
}
if (img->current_mb_nr%2 == 0)
currMB->mb_field = 0;
else
currMB->mb_field = img->mb_data[img->current_mb_nr-1].mb_field;
currMB->qp = img->qp ;
currSE.type = SE_MBTYPE;
// read MB mode *****************************************************************
dP = &(currSlice->partArr[partMap[currSE.type]]);
if (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag)
currSE.mapping = linfo_ue;
if(img->type == I_SLICE || img->type == SI_SLICE)
{
// 只有一个I帧(片), 99个宏块,刚好被调用99次
// read MB aff
if (img->MbaffFrameFlag && img->current_mb_nr%2==0)
{
TRACE_STRING("mb_field_decoding_flag");
if (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag)
{
currSE.len = 1;
readSyntaxElement_FLC(&currSE, dP->bitstream);
}
else
{
currSE.reading = readFieldModeInfo_CABAC;
dP->readSyntaxElement(&currSE,img,inp,dP);
}
currMB->mb_field = currSE.value1;
}
if(active_pps->entropy_coding_mode_flag == CABAC)
CheckAvailabilityOfNeighborsCABAC();
// read MB type
TRACE_STRING("mb_type");
currSE.reading = readMB_typeInfo_CABAC;
dP->readSyntaxElement(&currSE,img,inp,dP);
currMB->mb_type = currSE.value1;
if(!dP->bitstream->ei_flag)
currMB->ei_flag = 0;
}// I帧内的宏块到此为止
// non I/SI-slice CABAC
else if (active_pps->entropy_coding_mode_flag == CABAC)
{
// read MB skipflag
if (img->MbaffFrameFlag && (img->current_mb_nr%2 == 0||prevMbSkipped))
field_flag_inference();
CheckAvailabilityOfNeighborsCABAC();
TRACE_STRING("mb_skip_flag");
currSE.reading = readMB_skip_flagInfo_CABAC;
dP->readSyntaxElement(&currSE,img,inp,dP);
currMB->mb_type = currSE.value1;
if (img->type==B_SLICE)
currMB->cbp = currSE.value2;
if(!dP->bitstream->ei_flag)
currMB->ei_flag = 0;
if ((img->type==B_SLICE) && currSE.value1==0 && currSE.value2==0)
img->cod_counter=0;
// read MB aff
if (img->MbaffFrameFlag)
{
check_bottom=read_bottom=read_top=0;
if (img->current_mb_nr%2==0)
{
check_bottom = (img->type!=B_SLICE)?
(currMB->mb_type == 0):
(currMB->mb_type == 0 && currMB->cbp == 0);
read_top = !check_bottom;
}
else
read_bottom = (img->type!=B_SLICE)?
(topMB->mb_type == 0 && currMB->mb_type != 0) :
((topMB->mb_type == 0 && topMB->cbp == 0) && (currMB->mb_type != 0 || currMB->cbp != 0));
if (read_bottom || read_top)
{
TRACE_STRING("mb_field_decoding_flag");
currSE.reading = readFieldModeInfo_CABAC;
dP->readSyntaxElement(&currSE,img,inp,dP);
currMB->mb_field = currSE.value1;
}
if (check_bottom)
check_next_mb_and_get_field_mode_CABAC(&currSE,img,inp,dP);
}
if(active_pps->entropy_coding_mode_flag == CABAC)
CheckAvailabilityOfNeighborsCABAC();
// read MB type
if (currMB->mb_type != 0 )
{
currSE.reading = readMB_typeInfo_CABAC;
TRACE_STRING("mb_type");
dP->readSyntaxElement(&currSE,img,inp,dP);
currMB->mb_type = currSE.value1;
if(!dP->bitstream->ei_flag)
currMB->ei_flag = 0;
}
}
// VLC Non-Intra
else
{
if(img->cod_counter == -1)
{
TRACE_STRING("mb_skip_run");
dP->readSyntaxElement(&currSE,img,inp,dP);
img->cod_counter = currSE.value1;
}
if (img->cod_counter==0)
{
// read MB aff
if ((img->MbaffFrameFlag) && ((img->current_mb_nr%2==0) || ((img->current_mb_nr%2) && prevMbSkipped)))
{
TRACE_STRING("mb_field_decoding_flag");
currSE.len = 1;
readSyntaxElement_FLC(&currSE, dP->bitstream);
currMB->mb_field = currSE.value1;
}
// read MB type
TRACE_STRING("mb_type");
dP->readSyntaxElement(&currSE,img,inp,dP);
if(img->type == P_SLICE || img->type == SP_SLICE)
currSE.value1++;
currMB->mb_type = currSE.value1;
if(!dP->bitstream->ei_flag)
currMB->ei_flag = 0;
img->cod_counter--;
}
else
{
img->cod_counter--;
currMB->mb_type = 0;
currMB->ei_flag = 0;
// read field flag of bottom block
if(img->MbaffFrameFlag)
{
if(img->cod_counter == 0 && (img->current_mb_nr%2 == 0))
{
TRACE_STRING("mb_field_decoding_flag (of coded bottom mb)");
currSE.len = 1;
readSyntaxElement_FLC(&currSE, dP->bitstream);
dP->bitstream->frame_bitoffset--;
currMB->mb_field = currSE.value1;
}
else if(img->cod_counter > 0 && (img->current_mb_nr%2 == 0))
{
// check left macroblock pair first
if (mb_is_available(img->current_mb_nr-2, img->current_mb_nr)&&((img->current_mb_nr%(img->PicWidthInMbs*2))!=0))
{
currMB->mb_field = img->mb_data[img->current_mb_nr-2].mb_field;
}
else
{
// check top macroblock pair
if (mb_is_available(img->current_mb_nr-2*img->PicWidthInMbs, img->current_mb_nr))
{
currMB->mb_field = img->mb_data[img->current_mb_nr-2*img->PicWidthInMbs].mb_field;
}
else
currMB->mb_field = 0;
}
}
}
}
}
dec_picture->mb_field[img->current_mb_nr] = currMB->mb_field;
img->siblock[img->mb_x][img->mb_y]=0;
if ((img->type==P_SLICE )) // inter frame
interpret_mb_mode_P(img);
else if (img->type==I_SLICE) // intra frame
interpret_mb_mode_I(img);
else if ((img->type==B_SLICE)) // B frame
interpret_mb_mode_B(img);
else if ((img->type==SP_SLICE)) // SP frame
interpret_mb_mode_P(img);
else if (img->type==SI_SLICE) // SI frame
interpret_mb_mode_SI(img);
if(img->MbaffFrameFlag)
{
if(currMB->mb_field)
{
img->num_ref_idx_l0_active <<=1;
img->num_ref_idx_l1_active <<=1;
}
}
//====== READ 8x8 SUB-PARTITION MODES (modes of 8x8 blocks) and Intra VBST block modes ======
if (IS_P8x8 (currMB))
{
currSE.type = SE_MBTYPE;
dP = &(currSlice->partArr[partMap[SE_MBTYPE]]);
for (i=0; i<4; i++)
{
if (active_pps->entropy_coding_mode_flag ==UVLC || dP->bitstream->ei_flag)
currSE.mapping = linfo_ue;
else
currSE.reading = readB8_typeInfo_CABAC;
TRACE_STRING("sub_mb_type");
dP->readSyntaxElement (&currSE, img, inp, dP);
SetB8Mode (img, currMB, currSE.value1, i);
}
}
if(active_pps->constrained_intra_pred_flag && (img->type==P_SLICE|| img->type==B_SLICE)) // inter frame
{
if( !IS_INTRA(currMB) )
{
img->intra_block[img->current_mb_nr] = 0;
}
}
//! TO for Error Concelament
//! If we have an INTRA Macroblock and we lost the partition
//! which contains the intra coefficients Copy MB would be better
//! than just a grey block.
//! Seems to be a bit at the wrong place to do this right here, but for this case
//! up to now there is no other way.
dP = &(currSlice->partArr[partMap[SE_CBP_INTRA]]);
if(IS_INTRA (currMB) && dP->bitstream->ei_flag && img->number)
{
currMB->mb_type = 0;
currMB->ei_flag = 1;
for (i=0;i<4;i++) {currMB->b8mode[i]=currMB->b8pdir[i]=0; }
}
dP = &(currSlice->partArr[partMap[currSE.type]]);
//! End TO
//--- init macroblock data ---
init_macroblock (img);
// 此处被调用1188次
// 下面这个部分是提取运动矢量的重头戏
// 1188个宏块如何分配呢?
// 1188 = 325 + 78 + 785
if (IS_DIRECT (currMB) && img->cod_counter >= 0)
{
// 此处被调用325次
// 由于涉及到B宏块,所以,不理它
currMB->cbp = 0;
reset_coeffs();
if (active_pps->entropy_coding_mode_flag ==CABAC)
img->cod_counter=-1;
return DECODE_MB;
}
if (IS_COPY (currMB)) //keep last macroblock
{
// IS_COPY表示skip形式的P宏块(不表示skip形式的B宏块)
// 用H.264visa观察到4个P帧共有78个skip形式的P宏块
// 此处刚好被调用78次
int i, j, k, pmv[2];
int zeroMotionAbove;
int zeroMotionLeft;
PixelPos mb_a, mb_b;
int a_mv_y = 0;
int a_ref_idx = 0;
int b_mv_y = 0;
int b_ref_idx = 0;
int list_offset = ((img->MbaffFrameFlag)&&(currMB->mb_field))? img->current_mb_nr%2 ? 4 : 2 : 0;
getLuma4x4Neighbour(img->current_mb_nr,0,0,-1, 0,&mb_a);
getLuma4x4Neighbour(img->current_mb_nr,0,0, 0,-1,&mb_b);
if (mb_a.available)
{
a_mv_y = dec_picture->mv[LIST_0][mb_a.pos_x][mb_a.pos_y][1];
a_ref_idx = dec_picture->ref_idx[LIST_0][mb_a.pos_x][mb_a.pos_y];
if (currMB->mb_field && !img->mb_data[mb_a.mb_addr].mb_field)
{
a_mv_y /=2;
a_ref_idx *=2;
}
if (!currMB->mb_field && img->mb_data[mb_a.mb_addr].mb_field)
{
a_mv_y *=2;
a_ref_idx >>=1;
}
}
if (mb_b.available)
{
b_mv_y = dec_picture->mv[LIST_0][mb_b.pos_x][mb_b.pos_y][1];
b_ref_idx = dec_picture->ref_idx[LIST_0][mb_b.pos_x][mb_b.pos_y];
if (currMB->mb_field && !img->mb_data[mb_b.mb_addr].mb_field)
{
b_mv_y /=2;
b_ref_idx *=2;
}
if (!currMB->mb_field && img->mb_data[mb_b.mb_addr].mb_field)
{
b_mv_y *=2;
b_ref_idx >>=1;
}
}
zeroMotionLeft = !mb_a.available ? 1 : a_ref_idx==0 && dec_picture->mv[LIST_0][mb_a.pos_x][mb_a.pos_y][0]==0 && a_mv_y==0 ? 1 : 0;
zeroMotionAbove = !mb_b.available ? 1 : b_ref_idx==0 && dec_picture->mv[LIST_0][mb_b.pos_x][mb_b.pos_y][0]==0 && b_mv_y==0 ? 1 : 0;
currMB->cbp = 0;
reset_coeffs();
img_block_y = img->block_y;
if (zeroMotionAbove || zeroMotionLeft)
{
// 这些skip形式的P宏块的运动矢量为零
fprintf(myMV, "%-4d %-4d ", 0, 0);
for(i=0;i<BLOCK_SIZE;i++)
for(j=0;j<BLOCK_SIZE;j++)
for (k=0;k<2;k++)
dec_picture->mv[LIST_0][img->block_x+i][img->block_y+j][k] = 0;
}
else
{
SetMotionVectorPredictor (img, pmv, pmv+1, 0, LIST_0, dec_picture->ref_idx, dec_picture->mv, 0, 0, 16, 16);
// 这些skip形式的P宏块的运动矢量为(pmv[0], pmv[1])
fprintf(myMV, "%-4d %-4d ", pmv[0], pmv[1]);
for(i=0;i<BLOCK_SIZE;i++)
for(j=0;j<BLOCK_SIZE;j++)
for (k=0;k<2;k++)
{
dec_picture->mv[LIST_0][img->block_x+i][img_block_y+j][k] = pmv[k];
}
}
for(i=0;i<BLOCK_SIZE;i++)
for(j=0;j<BLOCK_SIZE;j++)
{
dec_picture->ref_idx[LIST_0][img->block_x+i][img_block_y+j] = 0;
dec_picture->ref_pic_id[LIST_0][img->block_x+i][img_block_y+j] = dec_picture->ref_pic_num[img->current_slice_nr][LIST_0 + list_offset][dec_picture->ref_idx[LIST_0][img->block_x+i][img_block_y+j]];
}
return DECODE_MB;
}// skip形式的P宏块结束
if(currMB->mb_type!=IPCM)
{
// 有785个宏块进入到此处,此处被调用785次
// intra prediction modes for a macroblock 4x4 **********************************************
read_ipred_modes(img,inp);
// read inter frame vector data *********************************************************
if (IS_INTERMV (currMB))
{
// 此处被调用632次
// 下面这个是一个极为关键的函数
// B宏块和P宏块都有可能进入该函数
// 如果只提取P帧的运动矢量,则要加限制
readMotionInfoFromNAL (img, inp);
}
// 下面这些else if是本人加的,目的是为了方便数据处理
// 认为P帧中I宏块的运动矢量为(0, 0),便于统一操作
// 785 - 632 = 153, 153 = 99 + 37 + 17
else if(img->type == I_SLICE)
{
// 此处被调用99次,刚好是I帧中的宏块数
NULL; // 空语句
}
else if(img->type == P_SLICE)
{
// 此处被调用37次
// 4个P帧的I宏块刚好37个
// 为了数据对齐,认为P帧中I宏块的运动矢量为零
fprintf(myMV, "%-4d %-4d ", 0, 0);
}
else if(img->type == B_SLICE)
{
// 此处被调用17次
// 7个B帧的B_Direct_16x16宏块刚好17个
NULL;
}
// read CBP and Coeffs ***************************************************************
readCBPandCoeffsFromNAL (img,inp);
}
else
{
//read pcm_alignment_zero_bit and pcm_byte[i]
// here dP is assigned with the same dP as SE_MBTYPE, because IPCM syntax is in the
// same category as MBTYPE
dP = &(currSlice->partArr[partMap[SE_MBTYPE]]);
readIPCMcoeffsFromNAL(img,inp,dP);
}
return DECODE_MB;
}
接着看重要的函数readMotionInfoFromNAL函数:
void readMotionInfoFromNAL (struct img_par *img, struct inp_par *inp)
{
int controlFlag = 0;
int i,j,k;
int step_h,step_v;
int curr_mvd;
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
SyntaxElement currSE;
Slice *currSlice = img->currentSlice;
DataPartition *dP;
int *partMap = assignSE2partition[currSlice->dp_mode];
int bframe = (img->type==B_SLICE);
int partmode = (IS_P8x8(currMB)?4:currMB->mb_type);
int step_h0 = BLOCK_STEP [partmode][0];
int step_v0 = BLOCK_STEP [partmode][1];
int mv_mode, i0, j0, refframe;
int pmv[2];
int j4, i4, ii,jj;
int vec;
int mv_scale = 0;
int flag_mode;
int list_offset = ((img->MbaffFrameFlag)&&(currMB->mb_field))? img->current_mb_nr%2 ? 4 : 2 : 0;
byte ** moving_block;
int **** co_located_mv;
int *** co_located_ref_idx;
int64 *** co_located_ref_id;
if ((img->MbaffFrameFlag)&&(currMB->mb_field))
{
if(img->current_mb_nr%2)
{
moving_block = Co_located->bottom_moving_block;
co_located_mv = Co_located->bottom_mv;
co_located_ref_idx = Co_located->bottom_ref_idx;
co_located_ref_id = Co_located->bottom_ref_pic_id;
}
else
{
moving_block = Co_located->top_moving_block;
co_located_mv = Co_located->top_mv;
co_located_ref_idx = Co_located->top_ref_idx;
co_located_ref_id = Co_located->top_ref_pic_id;
}
}
else
{
moving_block = Co_located->moving_block;
co_located_mv = Co_located->mv;
co_located_ref_idx = Co_located->ref_idx;
co_located_ref_id = Co_located->ref_pic_id;
}
if (bframe && IS_P8x8 (currMB))
{
if (img->direct_type)
{
int imgblock_y= ((img->MbaffFrameFlag)&&(currMB->mb_field))? (img->current_mb_nr%2) ? (img->block_y-4)/2:img->block_y/2: img->block_y;
int fw_rFrameL, fw_rFrameU, fw_rFrameUL, fw_rFrameUR;
int bw_rFrameL, bw_rFrameU, bw_rFrameUL, bw_rFrameUR;
PixelPos mb_left, mb_up, mb_upleft, mb_upright;
int fw_rFrame,bw_rFrame;
int pmvfw[2]={0,0},pmvbw[2]={0,0};
getLuma4x4Neighbour(img->current_mb_nr, 0, 0, -1, 0, &mb_left);
getLuma4x4Neighbour(img->current_mb_nr, 0, 0, 0, -1, &mb_up);
getLuma4x4Neighbour(img->current_mb_nr, 0, 0, 16, -1, &mb_upright);
getLuma4x4Neighbour(img->current_mb_nr, 0, 0, -1, -1, &mb_upleft);
if (!img->MbaffFrameFlag)
{
fw_rFrameL = mb_left.available ? dec_picture->ref_idx[LIST_0][mb_left.pos_x][mb_left.pos_y] : -1;
fw_rFrameU = mb_up.available ? dec_picture->ref_idx[LIST_0][mb_up.pos_x][mb_up.pos_y] : -1;
fw_rFrameUL = mb_upleft.available ? dec_picture->ref_idx[LIST_0][mb_upleft.pos_x][mb_upleft.pos_y] : -1;
fw_rFrameUR = mb_upright.available ? dec_picture->ref_idx[LIST_0][mb_upright.pos_x][mb_upright.pos_y] : fw_rFrameUL;
bw_rFrameL = mb_left.available ? dec_picture->ref_idx[LIST_1][mb_left.pos_x][mb_left.pos_y] : -1;
bw_rFrameU = mb_up.available ? dec_picture->ref_idx[LIST_1][mb_up.pos_x][mb_up.pos_y] : -1;
bw_rFrameUL = mb_upleft.available ? dec_picture->ref_idx[LIST_1][mb_upleft.pos_x][mb_upleft.pos_y] : -1;
bw_rFrameUR = mb_upright.available ? dec_picture->ref_idx[LIST_1][mb_upright.pos_x][mb_upright.pos_y] : bw_rFrameUL;
}
else
{
if (img->mb_data[img->current_mb_nr].mb_field)
{
fw_rFrameL = mb_left.available ?
img->mb_data[mb_left.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_left.pos_x][mb_left.pos_y] < 0?
dec_picture->ref_idx[LIST_0][mb_left.pos_x][mb_left.pos_y] :
dec_picture->ref_idx[LIST_0][mb_left.pos_x][mb_left.pos_y] * 2: -1;
fw_rFrameU = mb_up.available ?
img->mb_data[mb_up.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_up.pos_x][mb_up.pos_y] < 0?
dec_picture->ref_idx[LIST_0][mb_up.pos_x][mb_up.pos_y] :
dec_picture->ref_idx[LIST_0][mb_up.pos_x][mb_up.pos_y] * 2: -1;
fw_rFrameUL = mb_upleft.available ?
img->mb_data[mb_upleft.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_upleft.pos_x][mb_upleft.pos_y] < 0?
dec_picture->ref_idx[LIST_0][mb_upleft.pos_x][mb_upleft.pos_y] :
dec_picture->ref_idx[LIST_0][mb_upleft.pos_x][mb_upleft.pos_y] *2: -1;
fw_rFrameUR = mb_upright.available ?
img->mb_data[mb_upright.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_upright.pos_x][mb_upright.pos_y] < 0 ?
dec_picture->ref_idx[LIST_0][mb_upright.pos_x][mb_upright.pos_y] :
dec_picture->ref_idx[LIST_0][mb_upright.pos_x][mb_upright.pos_y] * 2: fw_rFrameUL;
bw_rFrameL = mb_left.available ?
img->mb_data[mb_left.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_left.pos_x][mb_left.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_left.pos_x][mb_left.pos_y] :
dec_picture->ref_idx[LIST_1][mb_left.pos_x][mb_left.pos_y] * 2: -1;
bw_rFrameU = mb_up.available ?
img->mb_data[mb_up.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_up.pos_x][mb_up.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_up.pos_x][mb_up.pos_y] :
dec_picture->ref_idx[LIST_1][mb_up.pos_x][mb_up.pos_y] * 2: -1;
bw_rFrameUL = mb_upleft.available ?
img->mb_data[mb_upleft.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_upleft.pos_x][mb_upleft.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_upleft.pos_x][mb_upleft.pos_y] :
dec_picture->ref_idx[LIST_1][mb_upleft.pos_x][mb_upleft.pos_y] *2: -1;
bw_rFrameUR = mb_upright.available ?
img->mb_data[mb_upright.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_upright.pos_x][mb_upright.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_upright.pos_x][mb_upright.pos_y] :
dec_picture->ref_idx[LIST_1][mb_upright.pos_x][mb_upright.pos_y] * 2: bw_rFrameUL;
}
else
{
fw_rFrameL = mb_left.available ?
img->mb_data[mb_left.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_left.pos_x][mb_left.pos_y] < 0 ?
dec_picture->ref_idx[LIST_0][mb_left.pos_x][mb_left.pos_y] >> 1 :
dec_picture->ref_idx[LIST_0][mb_left.pos_x][mb_left.pos_y]: -1;
fw_rFrameU = mb_up.available ?
img->mb_data[mb_up.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_up.pos_x][mb_up.pos_y] < 0 ?
dec_picture->ref_idx[LIST_0][mb_up.pos_x][mb_up.pos_y] >> 1 :
dec_picture->ref_idx[LIST_0][mb_up.pos_x][mb_up.pos_y] : -1;
fw_rFrameUL = mb_upleft.available ?
img->mb_data[mb_upleft.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_upleft.pos_x][mb_upleft.pos_y] < 0 ?
dec_picture->ref_idx[LIST_0][mb_upleft.pos_x][mb_upleft.pos_y]>> 1 :
dec_picture->ref_idx[LIST_0][mb_upleft.pos_x][mb_upleft.pos_y] : -1;
fw_rFrameUR = mb_upright.available ?
img->mb_data[mb_upright.mb_addr].mb_field || dec_picture->ref_idx[LIST_0][mb_upright.pos_x][mb_upright.pos_y] < 0 ?
dec_picture->ref_idx[LIST_0][mb_upright.pos_x][mb_upright.pos_y] >> 1 :
dec_picture->ref_idx[LIST_0][mb_upright.pos_x][mb_upright.pos_y] : fw_rFrameUL;
bw_rFrameL = mb_left.available ?
img->mb_data[mb_left.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_left.pos_x][mb_left.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_left.pos_x][mb_left.pos_y] >> 1 :
dec_picture->ref_idx[LIST_1][mb_left.pos_x][mb_left.pos_y] : -1;
bw_rFrameU = mb_up.available ?
img->mb_data[mb_up.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_up.pos_x][mb_up.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_up.pos_x][mb_up.pos_y] >> 1 :
dec_picture->ref_idx[LIST_1][mb_up.pos_x][mb_up.pos_y] : -1;
bw_rFrameUL = mb_upleft.available ?
img->mb_data[mb_upleft.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_upleft.pos_x][mb_upleft.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_upleft.pos_x][mb_upleft.pos_y] >> 1 :
dec_picture->ref_idx[LIST_1][mb_upleft.pos_x][mb_upleft.pos_y] : -1;
bw_rFrameUR = mb_upright.available ?
img->mb_data[mb_upright.mb_addr].mb_field || dec_picture->ref_idx[LIST_1][mb_upright.pos_x][mb_upright.pos_y] < 0 ?
dec_picture->ref_idx[LIST_1][mb_upright.pos_x][mb_upright.pos_y] >> 1:
dec_picture->ref_idx[LIST_1][mb_upright.pos_x][mb_upright.pos_y] : bw_rFrameUL;
}
}
fw_rFrame = (fw_rFrameL >= 0 && fw_rFrameU >= 0) ? min(fw_rFrameL,fw_rFrameU): max(fw_rFrameL,fw_rFrameU);
fw_rFrame = (fw_rFrame >= 0 && fw_rFrameUR >= 0) ? min(fw_rFrame,fw_rFrameUR): max(fw_rFrame,fw_rFrameUR);
bw_rFrame = (bw_rFrameL >= 0 && bw_rFrameU >= 0) ? min(bw_rFrameL,bw_rFrameU): max(bw_rFrameL,bw_rFrameU);
bw_rFrame = (bw_rFrame >= 0 && bw_rFrameUR >= 0) ? min(bw_rFrame,bw_rFrameUR): max(bw_rFrame,bw_rFrameUR);
if (fw_rFrame >=0)
SetMotionVectorPredictor (img, pmvfw, pmvfw+1, fw_rFrame, LIST_0, dec_picture->ref_idx, dec_picture->mv, 0, 0, 16, 16);
if (bw_rFrame >=0)
SetMotionVectorPredictor (img, pmvbw, pmvbw+1, bw_rFrame, LIST_1, dec_picture->ref_idx, dec_picture->mv, 0, 0, 16, 16);
for (i=0;i<4;i++)
{
if (currMB->b8mode[i] == 0)
for(j=2*(i/2);j<2*(i/2)+2;j++)
for(k=2*(i%2);k<2*(i%2)+2;k++)
{
int j6 = imgblock_y+j;
j4 = img->block_y+j;
i4 = img->block_x+k;
if (fw_rFrame >= 0)
{
if (!fw_rFrame && ((!moving_block[i4][j6]) && (!listX[1+list_offset][0]->is_long_term)))
{
dec_picture->mv [LIST_0][i4][j4][0] = 0;
dec_picture->mv [LIST_0][i4][j4][1] = 0;
dec_picture->ref_idx[LIST_0][i4][j4] = 0;
}
else
{
dec_picture->mv [LIST_0][i4][j4][0] = pmvfw[0];
dec_picture->mv [LIST_0][i4][j4][1] = pmvfw[1];
dec_picture->ref_idx[LIST_0][i4][j4] = fw_rFrame;
}
}
else
{
dec_picture->mv [LIST_0][i4][j4][0] = 0;
dec_picture->mv [LIST_0][i4][j4][1] = 0;
dec_picture->ref_idx[LIST_0][i4][j4] = -1;
}
if (bw_rFrame >= 0)
{
if (bw_rFrame==0 && ((!moving_block[i4][j6])&& (!listX[1+list_offset][0]->is_long_term)))
{
dec_picture->mv [LIST_1][i4][j4][0] = 0;
dec_picture->mv [LIST_1][i4][j4][1] = 0;
dec_picture->ref_idx[LIST_1][i4][j4] = 0;
}
else
{
dec_picture->mv [LIST_1][i4][j4][0] = pmvbw[0];
dec_picture->mv [LIST_1][i4][j4][1] = pmvbw[1];
dec_picture->ref_idx[LIST_1][i4][j4] = bw_rFrame;
}
}
else
{
dec_picture->mv [LIST_1][i4][j4][0] = 0;
dec_picture->mv [LIST_1][i4][j4][1] = 0;
dec_picture->ref_idx[LIST_1][i4][j4] = -1;
}
if (fw_rFrame <0 && bw_rFrame <0)
{
dec_picture->ref_idx[LIST_0][i4][j4] = 0;
dec_picture->ref_idx[LIST_1][i4][j4] = 0;
}
}
}
}
else
{
for (i=0;i<4;i++)
{
if (currMB->b8mode[i] == 0)
{
for(j=2*(i/2);j<2*(i/2)+2;j++)
{
for(k=2*(i%2);k<2*(i%2)+2;k++)
{
int list_offset = ((img->MbaffFrameFlag)&&(currMB->mb_field))? img->current_mb_nr%2 ? 4 : 2 : 0;
int imgblock_y= ((img->MbaffFrameFlag)&&(currMB->mb_field))? (img->current_mb_nr%2) ? (img->block_y-4)/2 : img->block_y/2 : img->block_y;
int refList = co_located_ref_idx[LIST_0 ][img->block_x+k][imgblock_y+j]== -1 ? LIST_1 : LIST_0;
int ref_idx = co_located_ref_idx[refList][img->block_x + k][imgblock_y + j];
int mapped_idx=-1, iref;
if (ref_idx == -1)
{
dec_picture->ref_idx [LIST_0][img->block_x + k][img->block_y + j] = 0;
dec_picture->ref_idx [LIST_1][img->block_x + k][img->block_y + j] = 0;
}
else
{
for (iref=0;iref<min(img->num_ref_idx_l0_active,listXsize[LIST_0 + list_offset]);iref++)
{
if (dec_picture->ref_pic_num[img->current_slice_nr][LIST_0 + list_offset][iref]==co_located_ref_id[refList][img->block_x + k][imgblock_y + j])
{
mapped_idx=iref;
break;
}
else //! invalid index. Default to zero even though this case should not happen
mapped_idx=INVALIDINDEX;
}
if (INVALIDINDEX == mapped_idx)
{
error("temporal direct error\ncolocated block has ref that is unavailable",-1111);
}
dec_picture->ref_idx [LIST_0][img->block_x + k][img->block_y + j] = mapped_idx;
dec_picture->ref_idx [LIST_1][img->block_x + k][img->block_y + j] = 0;
}
}
}
}
}
}
}
// If multiple ref. frames, read reference frame for the MB *********************************
if(img->num_ref_idx_l0_active>1)
{
flag_mode = ( img->num_ref_idx_l0_active == 2 ? 1 : 0);
currSE.type = SE_REFFRAME;
dP = &(currSlice->partArr[partMap[SE_REFFRAME]]);
if (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag) currSE.mapping = linfo_ue;
else currSE.reading = readRefFrame_CABAC;
for (j0=0; j0<4; j0+=step_v0)
{
for (i0=0; i0<4; i0+=step_h0)
{
k=2*(j0/2)+(i0/2);
if ((currMB->b8pdir[k]==0 || currMB->b8pdir[k]==2) && currMB->b8mode[k]!=0)
{
TRACE_STRING("ref_idx_l0");
img->subblock_x = i0;
img->subblock_y = j0;
if (!IS_P8x8 (currMB) || bframe || (!bframe && !img->allrefzero))
{
currSE.context = BType2CtxRef (currMB->b8mode[k]);
if( (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag) && flag_mode )
{
currSE.len = 1;
readSyntaxElement_FLC(&currSE, dP->bitstream);
currSE.value1 = 1 - currSE.value1;
}
else
{
currSE.value2 = LIST_0;
dP->readSyntaxElement (&currSE,img,inp,dP);
}
refframe = currSE.value1;
}
else
{
refframe = 0;
}
/*
if (bframe && refframe>img->buf_cycle) // img->buf_cycle should be correct for field MBs now
{
set_ec_flag(SE_REFFRAME);
refframe = 1;
}
*/
for (j=j0; j<j0+step_v0;j++)
for (i=i0; i<i0+step_h0;i++)
{
dec_picture->ref_idx[LIST_0][img->block_x + i][img->block_y + j] = refframe;
}
}
}
}
}
else
{
for (j0=0; j0<4; j0+=step_v0)
{
for (i0=0; i0<4; i0+=step_h0)
{
k=2*(j0/2)+(i0/2);
if ((currMB->b8pdir[k]==0 || currMB->b8pdir[k]==2) && currMB->b8mode[k]!=0)
{
for (j=j0; j<j0+step_v0;j++)
for (i=i0; i<i0+step_h0;i++)
{
dec_picture->ref_idx[LIST_0][img->block_x + i][img->block_y + j] = 0;
}
}
}
}
}
// If backward multiple ref. frames, read backward reference frame for the MB *********************************
if(img->num_ref_idx_l1_active>1)
{
flag_mode = ( img->num_ref_idx_l1_active == 2 ? 1 : 0);
currSE.type = SE_REFFRAME;
dP = &(currSlice->partArr[partMap[SE_REFFRAME]]);
if (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag) currSE.mapping = linfo_ue;
else currSE.reading = readRefFrame_CABAC;
for (j0=0; j0<4; j0+=step_v0)
{
for (i0=0; i0<4; i0+=step_h0)
{
k=2*(j0/2)+(i0/2);
if ((currMB->b8pdir[k]==1 || currMB->b8pdir[k]==2) && currMB->b8mode[k]!=0)
{
TRACE_STRING("ref_idx_l1");
img->subblock_x = i0;
img->subblock_y = j0;
currSE.context = BType2CtxRef (currMB->b8mode[k]);
if( (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag) && flag_mode )
{
currSE.len = 1;
readSyntaxElement_FLC(&currSE, dP->bitstream);
currSE.value1 = 1-currSE.value1;
}
else
{
currSE.value2 = LIST_1;
dP->readSyntaxElement (&currSE,img,inp,dP);
}
refframe = currSE.value1;
for (j=j0; j<j0+step_v0;j++)
{
for (i=i0; i<i0+step_h0;i++)
{
dec_picture->ref_idx[LIST_1][img->block_x + i][img->block_y + j] = refframe;
}
}
}
}
}
}
else
{
for (j0=0; j0<4; j0+=step_v0)
{
for (i0=0; i0<4; i0+=step_h0)
{
k=2*(j0/2)+(i0/2);
if ((currMB->b8pdir[k]==1 || currMB->b8pdir[k]==2) && currMB->b8mode[k]!=0)
{
for (j=j0; j<j0+step_v0;j++)
for (i=i0; i<i0+step_h0;i++)
{
dec_picture->ref_idx[LIST_1][img->block_x + i][img->block_y + j] = 0;
}
}
}
}
}
//===== READ FORWARD MOTION VECTORS =====
currSE.type = SE_MVD;
dP = &(currSlice->partArr[partMap[SE_MVD]]);
if (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag) currSE.mapping = linfo_se;
else currSE.reading = readMVD_CABAC;
for (j0=0; j0<4; j0+=step_v0)
for (i0=0; i0<4; i0+=step_h0)
{
k=2*(j0/2)+(i0/2);
if ((currMB->b8pdir[k]==0 || currMB->b8pdir[k]==2) && (currMB->b8mode[k] !=0))//has forward vector
{
mv_mode = currMB->b8mode[k];
step_h = BLOCK_STEP [mv_mode][0];
step_v = BLOCK_STEP [mv_mode][1];
refframe = dec_picture->ref_idx[LIST_0][img->block_x+i0][img->block_y+j0];
for (j=j0; j<j0+step_v0; j+=step_v)
{
for (i=i0; i<i0+step_h0; i+=step_h)
{
j4 = img->block_y+j;
i4 = img->block_x+i;
// first make mv-prediction
SetMotionVectorPredictor (img, pmv, pmv+1, refframe, LIST_0, dec_picture->ref_idx, dec_picture->mv, i, j, 4*step_h, 4*step_v);
for (k=0; k < 2; k++)
{
TRACE_STRING("mvd_l0");
img->subblock_x = i; // position used for context determination
img->subblock_y = j; // position used for context determination
currSE.value2 = k<<1; // identifies the component; only used for context determination
dP->readSyntaxElement(&currSE,img,inp,dP);
curr_mvd = currSE.value1;
// 运动矢量就在此
vec=curr_mvd+pmv[k]; /* find motion vector */
// 取每个宏块的最左上角的那个4 * 4块的运动矢量
// 故用controlFlag <= 2 来限制x分量和y分量
// 由于B宏块也会进入到这里,所以要用P_SLICE限制
// skip形式的P宏块不会进入到这里来,所以不用担心
controlFlag++;
if(controlFlag <= 2 && img->type == P_SLICE)
{
//another++;
//printf("********%d another\n", another);
fprintf(myMV, "%-4d ", vec);
}
for(ii=0;ii<step_h;ii++)
{
for(jj=0;jj<step_v;jj++)
{
dec_picture->mv [LIST_0][i4+ii][j4+jj][k] = vec;
currMB->mvd [LIST_0][j+jj] [i+ii] [k] = curr_mvd;
}
}
}
}
}
}
else if (currMB->b8mode[k=2*(j0/2)+(i0/2)]==0)
{
if (!img->direct_type)
{
int list_offset = ((img->MbaffFrameFlag)&&(currMB->mb_field))? img->current_mb_nr%2 ? 4 : 2 : 0;
int imgblock_y= ((img->MbaffFrameFlag)&&(currMB->mb_field))? (img->current_mb_nr%2) ? (img->block_y-4)/2:img->block_y/2 : img->block_y;
int refList = (co_located_ref_idx[LIST_0][img->block_x+i0][imgblock_y+j0]== -1 ? LIST_1 : LIST_0);
int ref_idx = co_located_ref_idx[refList][img->block_x+i0][imgblock_y+j0];
if (ref_idx==-1)
{
for (j=j0; j<j0+step_v0; j++)
for (i=i0; i<i0+step_h0; i++)
{
dec_picture->ref_idx [LIST_1][img->block_x+i][img->block_y+j]=0;
dec_picture->ref_idx [LIST_0][img->block_x+i][img->block_y+j]=0;
j4 = img->block_y+j;
i4 = img->block_x+i;
for (ii=0; ii < 2; ii++)
{
dec_picture->mv [LIST_0][i4][j4][ii]=0;
dec_picture->mv [LIST_1][i4][j4][ii]=0;
}
}
}
else
{
int mapped_idx=-1, iref;
int j6;
for (iref=0;iref<min(img->num_ref_idx_l0_active,listXsize[LIST_0 + list_offset]);iref++)
{
if (dec_picture->ref_pic_num[img->current_slice_nr][LIST_0 + list_offset][iref]==co_located_ref_id[refList][img->block_x+i0][imgblock_y+j0])
{
mapped_idx=iref;
break;
}
else //! invalid index. Default to zero even though this case should not happen
mapped_idx=INVALIDINDEX;
}
if (INVALIDINDEX == mapped_idx)
{
error("temporal direct error\ncolocated block has ref that is unavailable",-1111);
}
for (j=j0; j<j0+step_v0; j++)
for (i=i0; i<i0+step_h0; i++)
{
{
mv_scale = img->mvscale[LIST_0 + list_offset][mapped_idx];
dec_picture->ref_idx [LIST_0][img->block_x+i][img->block_y+j] = mapped_idx;
dec_picture->ref_idx [LIST_1][img->block_x+i][img->block_y+j] = 0;
j4 = img->block_y+j;
j6 = imgblock_y+j;
i4 = img->block_x+i;
for (ii=0; ii < 2; ii++)
{
//if (iTRp==0)
if (mv_scale == 9999 || listX[LIST_0+list_offset][mapped_idx]->is_long_term)
// if (mv_scale==9999 || Co_located->is_long_term)
{
dec_picture->mv [LIST_0][i4][j4][ii]=co_located_mv[refList][i4][j6][ii];
dec_picture->mv [LIST_1][i4][j4][ii]=0;
}
else
{
dec_picture->mv [LIST_0][i4][j4][ii]=(mv_scale * co_located_mv[refList][i4][j6][ii] + 128 ) >> 8;
dec_picture->mv [LIST_1][i4][j4][ii]=dec_picture->mv[LIST_0][i4][j4][ii] - co_located_mv[refList][i4][j6][ii];
}
}
}
}
}
}
}
}
//===== READ BACKWARD MOTION VECTORS =====
currSE.type = SE_MVD;
dP = &(currSlice->partArr[partMap[SE_MVD]]);
if (active_pps->entropy_coding_mode_flag == UVLC || dP->bitstream->ei_flag) currSE.mapping = linfo_se;
else currSE.reading = readMVD_CABAC;
for (j0=0; j0<4; j0+=step_v0)
{
for (i0=0; i0<4; i0+=step_h0)
{
k=2*(j0/2)+(i0/2);
if ((currMB->b8pdir[k]==1 || currMB->b8pdir[k]==2) && (currMB->b8mode[k]!=0))//has backward vector
{
mv_mode = currMB->b8mode[k];
step_h = BLOCK_STEP [mv_mode][0];
step_v = BLOCK_STEP [mv_mode][1];
refframe = dec_picture->ref_idx[LIST_1][img->block_x+i0][img->block_y+j0];
for (j=j0; j<j0+step_v0; j+=step_v)
{
for (i=i0; i<i0+step_h0; i+=step_h)
{
j4 = img->block_y+j;
i4 = img->block_x+i;
// first make mv-prediction
SetMotionVectorPredictor (img, pmv, pmv+1, refframe, LIST_1, dec_picture->ref_idx, dec_picture->mv, i, j, 4*step_h, 4*step_v);
for (k=0; k < 2; k++)
{
TRACE_STRING("mvd_l1");
img->subblock_x = i; // position used for context determination
img->subblock_y = j; // position used for context determination
currSE.value2 = (k<<1) +1; // identifies the component; only used for context determination
dP->readSyntaxElement(&currSE,img,inp,dP);
curr_mvd = currSE.value1;
vec=curr_mvd+pmv[k]; /* find motion vector */
for(ii=0;ii<step_h;ii++)
{
for(jj=0;jj<step_v;jj++)
{
dec_picture->mv [LIST_1][i4+ii][j4+jj][k] = vec;
currMB->mvd [LIST_1][j+jj] [i+ii] [k] = curr_mvd;
}
}
}
}
}
}
}
}
// record reference picture Ids for deblocking decisions
for(i4=img->block_x;i4<(img->block_x+4);i4++)
for(j4=img->block_y;j4<(img->block_y+4);j4++)
{
if(dec_picture->ref_idx[LIST_0][i4][j4]>=0)
dec_picture->ref_pic_id[LIST_0][i4][j4] = dec_picture->ref_pic_num[img->current_slice_nr][LIST_0 + list_offset][dec_picture->ref_idx[LIST_0][i4][j4]];
else
dec_picture->ref_pic_id[LIST_0][i4][j4] = INT64_MIN;
if(dec_picture->ref_idx[LIST_1][i4][j4]>=0)
dec_picture->ref_pic_id[LIST_1][i4][j4] = dec_picture->ref_pic_num[img->current_slice_nr][LIST_1 + list_offset][dec_picture->ref_idx[LIST_1][i4][j4]];
else
dec_picture->ref_pic_id[LIST_1][i4][j4] = INT64_MIN;
}
}
经验证,上面提取的运动矢量的结果和H.264visa提取的运动矢量的结果完全一致. OK, 这样就实现了对码流中P帧运动矢量的提取. 最后强调一句:实际运动矢量是上述运动矢量除以4.