如何利用JM8.6解码器提取码流中P帧宏块(第一个4*4块)的运动矢量(考虑B帧,设x264编码的12帧为IDR BBPBBPBBPBP)
来源:互联网 发布:软件测试行业前景 编辑:程序博客网 时间:2024/05/22 01:59
前面已经讨论过,在没有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 + 17else 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.
- 如何利用JM8.6解码器提取码流中P帧宏块(所有4*4块)的运动矢量(考虑B帧,设x264编码的12帧为IDR BBPBBPBBPBP)
- 如何利用JM8.6解码器提取码流中P帧宏块(第一个4*4块)的运动矢量(考虑B帧,设x264编码的12帧为IDR BBPBBPBBPBP)
- 如何利用JM8.6解码器提取码流中P帧宏块的运动矢量(假设编码不用B帧,仅为IDR P P)
- 如何在JM8.6中设置编码帧类型为IDR B B P B B P B B P B B I B B P...?
- 如何在JM8.6代码的编码端提取残差(为简便起见,仅以I4x4宏块为例)
- 如何在JM8.6代码的编码端提取残差(为简便起见,仅以I4x4宏块为例)
- I 帧,B帧,P帧,IDR帧的区别
- I帧 B帧 p帧 IDR帧的区别
- I 帧,B帧,P帧,IDR帧的区别
- I帧 B帧 p帧 IDR帧的区别
- I帧 B帧 p帧 IDR帧的区别
- I 帧,B帧,P帧,IDR帧的区别
- I帧 B帧 p帧 IDR帧的区别
- I帧 B帧 p帧 IDR帧的区别
- I 帧,B帧,P帧,IDR帧的区别
- I帧 B帧 p帧 IDR帧的区别
- 如何从JM8.6的编码端和解码端提取滤波前的像素值?
- 如何用JM8.6将所有的帧都编码为I帧?
- 51系列中data,idata,xdata,pdata的区别
- find命令用法
- iOS系统GCD学习(2):Dispatch Queue
- Poj 3525 Most Distant Point from the Sea (二分+半平面求交)
- MFC启动过程&单文档MFC程序的启动详细过程
- 如何利用JM8.6解码器提取码流中P帧宏块(第一个4*4块)的运动矢量(考虑B帧,设x264编码的12帧为IDR BBPBBPBBPBP)
- 关于struts2验证框架,在与spring整合后重复输出错误信息的问题
- 我的2012-分享我的四个项目经验
- MS SQL整理索引碎片
- Android多媒体浅析
- 【木头Cocos2d-x 030】Lua篇(第05章):C++调用Lua的函数
- NTP 资料
- android媒体扫描分享(1)-20121229
- 黑马程序员_多线程