直接预测是B帧上一种独有的预测方式,其中直接预测又分为两种模式: 时域直接模式(temporal direct)、空域直接模式(spatial direct)。html
在分析这两种模式以前,有一个前提概念须要了解:共同位置4x4子宏块分割块(co-located 4x4 sub-macroblock partitions),下面简称为co-located。api
共同位置4x4子宏块分割块,故名思义,该块大小为4x4。co-located的主要功能是获得出该4x4块的运动向量以及参考帧,以供后面的直接预测作后续处理,若是当前宏块进行的是直接预测,不管时域或空域,都会用到该co-located,所以须要先求出该4x4co-located的具体位置。app
要求co-located的位置,首先须要知道co-located所在的图像colPic的位置,colPic能够肯定在当前图像的第一个后向参考图像RefPicList1[ 0 ]内,可是colPic能够为帧或场,这取决于当期图像与参考图像,是以帧图像进行编码,仍是以场图像进行编码,或者以互补场对(宏块级帧场自适应)方式进行编码。ide
$\begin{align*}
topAbsDiffPOC &= |DiffPicOrderCnt( firstRefPicL1Top, CurrPic )|\\
bottomAbsDiffPOC &= |DiffPicOrderCnt( firstRefPicL1Bottom, CurrPic )|
\end{align*}$this
添加这些条件是为了在采用宏块级帧场自适编码方式时,应选择距离当前图像最近的顶场或底场做为col_Pic编码
注:其实第二项RefPicList1[ 0 ]是一个被动选项,由于它是根据当前图像的编码方式是帧、场或宏块帧场自适应决定的,若是当前图像是场,那么RefPicList1[ 0 ]就有多是已解码的场或者以解码帧中的一场;若是当前图像是帧(非MBAFF),那么RefPicList1[ 0 ]就是帧;若是当前宏块是帧而且为MBAFF,那么RefPicList1[ 0 ]就是一个互补场对(两个场能够组成一个帧)spa
实际上,若是获得了colPic,就能够经过当前宏块的16个4x4块的绝对位置(以4x4块为单位相对于图像左上角(0,0)的绝对位置( opic_block_x,opic_block_y)),获得co-located在colPic的位置。3d
(注:像在jm18.6中,实际计算时,不会出现当前图像为场,colPic为帧的状况,由于场的参考图像都会被分为场后加入参考图像队列,因此最终计算时也会先根据当前场的是顶场或底场挑出参考帧中对应的场做为colPic )code
在标准中,先定位co-located所在宏块mbAddrCol,而后再定位co-located在该宏块内的地址(xcol,yM)。因为采用了不一样于上述的4x4块定位方法,因此计算方式略复杂,可是获得的结果是同样的,最终会定位到同一个co-locatedorm
$\begin{align*}
mbAddrCol1 &= 2 \times PicWidthInMbs \times( CurrMbAddr / PicWidthInMbs ) +( CurrMbAddr \ \% \ PicWidthInMbs ) + PicWidthInMbs \times ( yCol / 8 ) \\
mbAddrCol2 &= 2 \times CurrMbAddr + ( yCol / 8 ) \\
mbAddrCol3 &= 2 \times CurrMbAddr + bottom\_field\_flag \\
mbAddrCol4 &= PicWidthInMbs \times( CurrMbAddr / ( 2 \times PicWidthInMbs ) ) +( CurrMbAddr\ \% \ PicWidthInMbs ) \\
mbAddrCol5 &= CurrMbAddr / 2 \\
mbAddrCol6 &= 2 \times ( CurrMbAddr / 2 ) + ( ( topAbsDiffPOC < bottomAbsDiffPOC ) ? 0 : 1 ) \\
mbAddrCol7 &= 2 \times( CurrMbAddr / 2 ) + ( yCol / 8 )
\end{align*}$
(FAQ:为什么表中没有FRM与AFRM配对?由于一个sps内只能定义为FRM或者AFRM(MBAFF),在一个序列内二者是不可能共存的;为什么表中能够有FRM与FLD共存?由于sps能够定义PAFF(图像帧场自适应))
另外,为了减小计算量,还能够设定direct_8x8_inference_flag等于1,这样会致使8x8块共用一个4x4的co-located的运动向量,共用方式为一个宏块的4个8x8块分别只用该宏块4个角的4x4块做为co-located
(注:标准规定参考图像选择的最小单位为8x8块,也就是说8x8块中的4个4x4块共享一个参考图像索引,请参考h.264语法结构分析中的ref_idx_l0以及ref_idx_l1关键字)
该模式是基于下图求出当前4x4块的先后向mvL0与mvL1,以及前向参考帧List0 reference的索引
已知的变量有:
未知的变量有:
求解方法:
因为这些在标准(8.4.1.2.3)中讲的都很是细致,因此这里简要说明一下而已。
空域模式基于一种假设:当前编码宏块与其相邻宏块都向着同一个方向运动,你们有着相似的运动向量与参考帧(以下图)。在这种假设前提上,空域模式主要思想为采用相邻块来对当前宏块的参考索引以及运动向量进行预测。因为标准中8.4.1.3有很是详细的描述,因此在此略过。
可是上述假设也颇有可能不成立,有可能当前宏块的相邻块都是运动的,但当前宏块是静止的(以下图)。好比说当前宏块是背景的一部分,而相邻块则是移动着的前景。这时候就须要判断当前宏块是不是运动的,以获得更准确的空域预测,co-located在这里就是用来判断当前宏块是不是运动宏块的。若是co-located的mvCol[0]与mvCol[1]能保证在某个范围以内,则代表当前宏块为静止宏块,那么将把当前宏块的mvL0与mvL1赋值为0,具体在标准8.4.1.2.2中描述得至关详细,不做细述。
jm18.6 mv_direct.c
/*! ************************************************************************************* * \file mv_direct.c * * \brief * Direct Motion Vector Generation * * \author * Main contributors (see contributors.h for copyright, address and affiliation details) * - Alexis Michael Tourapis <alexismt@ieee.org> * ************************************************************************************* */ #include "contributors.h" #include <math.h> #include <limits.h> #include <time.h> #include "global.h" #include "image.h" #include "mv_search.h" #include "refbuf.h" #include "memalloc.h" #include "mb_access.h" #include "macroblock.h" #include "mc_prediction.h" #include "conformance.h" #include "mode_decision.h" /*! ************************************************************************ * \brief * Calculate Temporal Direct Mode Motion Vectors ************************************************************************ */ void Get_Direct_MV_Temporal (Macroblock *currMB) { Slice *currSlice = currMB->p_Slice; int block_x, block_y, pic_block_x, pic_block_y, opic_block_x, opic_block_y; MotionVector *****all_mvs; int mv_scale; int refList; int ref_idx; VideoParameters *p_Vid = currMB->p_Vid; int list_offset = currMB->list_offset;//若是当前currSlice->mb_aff_frame_flag 且 currMB->mb_field ,list_offset>0 StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; PicMotionParams colocated; //temporal direct mode copy from decoder for (block_y = 0; block_y < 4; block_y++) { pic_block_y = currMB->block_y + block_y; opic_block_y = (currMB->opix_y >> 2) + block_y; for (block_x = 0; block_x < 4; block_x++) { pic_block_x = currMB->block_x + block_x; opic_block_x = (currMB->pix_x>>2) + block_x; all_mvs = currSlice->all_mv; if (p_Vid->active_sps->direct_8x8_inference_flag) { if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) colocated = list1[0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(opic_block_y)][RSD(opic_block_x)]; else colocated = list1[0]->mv_info[RSD(opic_block_y)][RSD(opic_block_x)]; if(currSlice->mb_aff_frame_flag && currMB->mb_field && currSlice->listX[LIST_1][0]->coded_frame) {//mbaff场宏块 int iPosBlkY; if(currSlice->listX[LIST_1][0]->motion.mb_field[currMB->mbAddrX] ) //当前宏块是mbaff且为场编码,参考帧宏块为场编码,不过由于此处计算ref_pic用的是frame,即一个场宏块对应两个帧宏块 //场宏块>>2后*8,能够对比下面帧宏块>>3后再*8 //>>2表明一个场宏块, //*8表明宏块对(两个帧宏块), //*4表明选择对应宏块(顶宏块或者底宏块其中之一(field重建回frame时,对于宏块的mv_info,是以宏块对方式组建的?)), //&3表明4x4子块 //另外因为每个8x8块对应一个参考帧因此最后也有RSD(opic_block_x) iPosBlkY = (opic_block_y>>2)*8+4*(currMB->mbAddrX&1)+(opic_block_y&0x03); else //由于当前是场(mb_field)?而下面参考帧采用的是帧,则表明field->frame,因此*2 iPosBlkY = RSD(opic_block_y)*2; //因为标准规定(8.4.1.2.2最后一段)在colocated中应该在其所在的8x8分割块中选取参考帧,因此须要进行如下步骤 if(colocated.ref_idx[LIST_0]>=0)//ref_idx>=0说明有前/后向参考帧,可是下面还须要根据当前宏块与colpic进行精肯定位(在8x8分割块中选取某块的参考帧) colocated.ref_pic[LIST_0] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_0]; if(colocated.ref_idx[LIST_1]>=0) colocated.ref_pic[LIST_1] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_1]; } } else { if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) colocated = list1[0]->JVmv_info[currMB->p_Slice->colour_plane_id][opic_block_y][opic_block_x]; else colocated = list1[0]->mv_info[opic_block_y][opic_block_x]; } if(currSlice->mb_aff_frame_flag) { if(!currMB->mb_field && ((currSlice->listX[LIST_1][0]->coded_frame && currSlice->listX[LIST_1][>motion.mb_field[currMB->mbAddrX]) || (!currSlice->listX[LIST_1][0]->coded_frame))) {//mbaff帧宏块 if (iabs(p_Vid->enc_picture->poc - currSlice->listX[LIST_1+4][0]->poc)> iabs(p_Vid->enc_picture->poc -rSlice->listX[LIST_1+2][0]->poc) ) { if ( p_Vid->active_sps->direct_8x8_inference_flag) { if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) colocated = currSlice->listX[LIST_1+2][0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(c_block_y)>>1][RSD(opic_block_x)]; else colocated = currSlice->listX[LIST_1+2][0]->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)]; } else { if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) colocated = currSlice->listX[LIST_1+2][0]->JVmv_info[currMB->p_Slice->colour_plane_id][(c_block_y)>>1][(opic_block_x)]; else colocated = currSlice->listX[LIST_1+2][0]->mv_info[(opic_block_y)>>1][opic_block_x]; } if(currSlice->listX[LIST_1][0]->coded_frame) {//帧宏块,因此下面>>3后再*8,能够对比上面场宏块>>2后再*8 int iPosBlkY = (RSD(opic_block_y)>>3)*8 + ((RSD(opic_block_y)>>1) & 0x03); if(colocated.ref_idx[LIST_0] >=0) // && !colocated.ref_pic[LIST_0]) colocated.ref_pic[LIST_0] = currSlice->listX[LIST_1+2][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[T_0]; if(colocated.ref_idx[LIST_1] >=0) // && !colocated.ref_pic[LIST_1]) colocated.ref_pic[LIST_1] = currSlice->listX[LIST_1+2][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[T_1]; } } else { if (p_Vid->active_sps->direct_8x8_inference_flag ) { if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) colocated = currSlice->listX[LIST_1+4][0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(c_block_y)>>1][RSD(opic_block_x)]; else colocated = currSlice->listX[LIST_1+4][0]->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)]; } else { if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) colocated = currSlice->listX[LIST_1+4][0]->JVmv_info[currMB->p_Slice->colour_plane_id][(c_block_y)>>1][opic_block_x]; else colocated = currSlice->listX[LIST_1+4][0]->mv_info[(opic_block_y)>>1][opic_block_x]; } if(currSlice->listX[LIST_1][0]->coded_frame) { int iPosBlkY = (RSD(opic_block_y)>>3)*8 + ((RSD(opic_block_y)>>1) & 0x03)+4; if(colocated.ref_idx[LIST_0] >=0) // && !colocated.ref_pic[LIST_0]) colocated.ref_pic[LIST_0] = currSlice->listX[LIST_1+4][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[T_0]; if(colocated.ref_idx[LIST_1] >=0)// && !colocated.ref_pic[LIST_1]) colocated.ref_pic[LIST_1] = currSlice->listX[LIST_1+4][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[T_1]; } } } } else if(!p_Vid->active_sps->frame_mbs_only_flag && !currSlice->structure && !currSlice->listX[LIST_1][>coded_frame) {//图像级帧场自适应帧图像编码(即list1[0]有可能为场编码) if (iabs(p_Vid->enc_picture->poc - list1[0]->bottom_field->poc)> iabs(p_Vid->enc_picture->poc -list1[>top_field->poc) ) { colocated = p_Vid->active_sps->direct_8x8_inference_flag ? list1[0]->top_field->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)] : list1[0]->top_field->mv_info[(c_block_y)>>1][opic_block_x]; } else { colocated = p_Vid->active_sps->direct_8x8_inference_flag ? list1[0]->bottom_field->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)] : list1[0]->bottom_field->mv_info[(c_block_y)>>1][opic_block_x]; } } else if(!p_Vid->active_sps->frame_mbs_only_flag && currSlice->structure && list1[0]->coded_frame) {//场图像编码 int iPosBlkY; int currentmb = 2*(list1[0]->size_x>>4) * (opic_block_y >> 2)+ (opic_block_x>>2)*2 + ((c_block_y>>1) & 0x01); if(currSlice->structure!=list1[0]->structure) { if (currSlice->structure == TOP_FIELD) { colocated = p_Vid->active_sps->direct_8x8_inference_flag ? list1[0]->frame->top_field->mv_info[RSD(opic_block_y)][RSD(opic_block_x)] : list1[>frame->top_field->mv_info[opic_block_y][opic_block_x]; } else { colocated = p_Vid->active_sps->direct_8x8_inference_flag ? list1[0]->frame->bottom_field->mv_info[RSD(opic_block_y)][RSD(opic_block_x)] : list1[>frame->bottom_field->mv_info[opic_block_y][opic_block_x]; } } if(!currSlice->listX[LIST_1][0]->frame->mb_aff_frame_flag || !list1[0]->frame->motion.mb_field[currentmb]) iPosBlkY = 2*(RSD(opic_block_y)); else iPosBlkY = (RSD(opic_block_y)>>2)*8 + (RSD(opic_block_y) & 0x03)+4*(currSlice->structure == BOTTOM_FIELD); if(colocated.ref_idx[LIST_0] >=0) // && !colocated.ref_pic[LIST_0]) colocated.ref_pic[LIST_0] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_0]; if(colocated.ref_idx[LIST_1] >=0)// && !colocated.ref_pic[LIST_1]) colocated.ref_pic[LIST_1] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_1]; } //最后剩下的是全序列采用帧图像编码(frame_mbs_only_flag = 1),这样的话colocated._pic确定是存在的,而且不用进行帧场转换,也就是采用原来的就能够,所以不用从新赋值 //colocated在开头判断direct_8x8_inference_flag的两个分支处便可得到 refList = ((colocated.ref_idx[LIST_0] == -1 || (p_Vid->view_id && colocated.ref_idx[LIST_0]==list1[0]->ref_pic_na[)? LIST_1 : LIST_0); ref_idx = colocated.ref_idx[refList]; // next P is intra mode if (ref_idx == -1 || (p_Vid->view_id && ref_idx==list1[0]->ref_pic_na[refList])) { all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = 0; currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = 0; currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; } // next P is skip or inter mode else { int mapped_idx=INVALIDINDEX; int iref; if (colocated.ref_pic[refList] == NULL) { printf("invalid index found\n"); } else { //获得前向参考帧ref0,即下面的mapped_idx //Let refIdxL0Frm be the lowest valued reference index in the current reference picture list RefPicList0 that //references the frame or complementary field pair that contains the field refPicCol if( (currSlice->mb_aff_frame_flag && ( (currMB->mb_field && colocated.ref_pic[List]->structure==FRAME) || //currSlice :mbaff & mb_field, ref_pic :frame (!currMB->mb_field && colocated.ref_pic[refList]->structure!=FRAME))) //currSlice :mb_frame , ref_pic :field (!currSlice->mb_aff_frame_flag && ((currSlice->structure==FRAME && colocated.ref_pic[List]->structure!=FRAME)|| //currSlice :frame only , ref_pic :field (currSlice->structure!=FRAME && colocated.ref_pic[refList]->structure==FRAME))) //currSlice :field , ref_pic :frame {//该判断条件表示currSlice与ref_pic用不一样的帧场编码方式 //! Frame with field co-located for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]); f++) { if (currSlice->listX[LIST_0 + list_offset][iref]->top_field == colocated.ref_pic[refList] || currSlice->listX[LIST_0 + list_offset][iref]->bottom_field == colocated.ref_pic[refList] || currSlice->listX[LIST_0 + list_offset][iref]->frame == colocated.ref_pic[refList] ) { if ((p_Vid->field_picture==1) && (currSlice->listX[LIST_0 + list_offset][iref]->structure != rSlice->structure)) {//currSlice :field , ref_pic :frame 会进来这里? mapped_idx=INVALIDINDEX; } else { mapped_idx = iref; break; } } else //! invalid index. Default to zero even though this case should not happen mapped_idx=INVALIDINDEX; } } else {//currSlice 与 ref_pic 采用相同帧场编码方式 for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]);iref++) { if(currSlice->listX[LIST_0 + list_offset][iref] == colocated.ref_pic[refList]) { mapped_idx = iref; break; } else //! invalid index. Default to zero even though this case should not happen { mapped_idx=INVALIDINDEX; } } } } if (mapped_idx != INVALIDINDEX) { MotionVector mv = colocated.mv[refList]; mv_scale = currSlice->mvscale[LIST_0 + list_offset][mapped_idx]; if((currSlice->mb_aff_frame_flag && !currMB->mb_field && colocated.ref_pic[refList]->structure!=FRAME) (!currSlice->mb_aff_frame_flag && currSlice->structure==FRAME && colocated.ref_pic[List]->structure!=FRAME)) mv.mv_y *= 2; else if((currSlice->mb_aff_frame_flag && currMB->mb_field && colocated.ref_pic[List]->structure==FRAME) || (!currSlice->mb_aff_frame_flag && currSlice->structure!=FRAME && colocated.ref_pic[List]->structure==FRAME)) mv.mv_y /= 2; //mvL0,mvL1 if (mv_scale==9999) { // forward all_mvs[LIST_0][0][0][block_y][block_x] = mv; // backward all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; } else { //mv_scale = DistScaleFactor (in function compute_colocated) // forward all_mvs[LIST_0][mapped_idx][0][block_y][block_x].mv_x = (short) ((mv_scale * mv.mv_x + 128) >> 8); all_mvs[LIST_0][mapped_idx][0][block_y][block_x].mv_y = (short) ((mv_scale * mv.mv_y + 128) >> 8); // backward all_mvs[LIST_1][ 0][0][block_y][block_x].mv_x = (short) (((mv_scale - 256) * mv.mv_x + 128) >> 8); all_mvs[LIST_1][ 0][0][block_y][block_x].mv_y = (short) (((mv_scale - 256) * mv.mv_y + 128) >> 8); } //refIdx0,refIdx1 // Test Level Limits if satisfied. if ( out_of_bounds_mvs(p_Vid, &all_mvs[LIST_0][mapped_idx][0][block_y][block_x])|| out_of_bounds_mvs(p_Vid, &all_mvs[T_1][0][0][block_y][block_x])) { currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = -1; currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = -1; currSlice->direct_pdir[pic_block_y][pic_block_x] = -1; } else { currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = (char) mapped_idx; currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = 0; currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; } } else { currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = -1; currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = -1; currSlice->direct_pdir[pic_block_y][pic_block_x] = -1; } } if (p_Vid->active_pps->weighted_bipred_idc == 1 && currSlice->direct_pdir[pic_block_y][pic_block_x] == 2) { int weight_sum, i; short l0_refX = currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0]; short l1_refX = currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1]; for (i=0;i< (p_Vid->active_sps->chroma_format_idc == YUV400 ? 1 : 3); i++) { weight_sum = currSlice->wbp_weight[0][l0_refX][l1_refX][i] + currSlice->wbp_weight[1][l0_refX][l1_refX][i]; if (weight_sum < -128 || weight_sum > 127) { currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = -1; currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = -1; currSlice->direct_pdir [pic_block_y][pic_block_x] = -1; break; } } } } } } static inline void set_direct_references(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info) { if (mb->available) { char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; *l0_rFrame = ref_idx[LIST_0]; *l1_rFrame = ref_idx[LIST_1]; } else { *l0_rFrame = -1; *l1_rFrame = -1; } } static void set_direct_references_mb_field(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info, Macroblock _data) { if (mb->available) { char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; if (mb_data[mb->mb_addr].mb_field) { *l0_rFrame = ref_idx[LIST_0]; *l1_rFrame = ref_idx[LIST_1]; } else { *l0_rFrame = (ref_idx[LIST_0] < 0) ? ref_idx[LIST_0] : ref_idx[LIST_0] * 2; *l1_rFrame = (ref_idx[LIST_1] < 0) ? ref_idx[LIST_1] : ref_idx[LIST_1] * 2; } } else { *l0_rFrame = -1; *l1_rFrame = -1; } } static void set_direct_references_mb_frame(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info, Macroblock _data) { if (mb->available) { char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; if (mb_data[mb->mb_addr].mb_field) { *l0_rFrame = (ref_idx[LIST_0] >> 1); *l1_rFrame = (ref_idx[LIST_1] >> 1); } else { *l0_rFrame = ref_idx[LIST_0]; *l1_rFrame = ref_idx[LIST_1]; } } else { *l0_rFrame = -1; *l1_rFrame = -1; } } static void test_valid_direct(Slice *currSlice, seq_parameter_set_rbsp_t *active_sps, char *direct_ref_idx, short l0_refX, short refX, int pic_block_y, int pic_block_x) { int weight_sum, i; Boolean invalid_wp = FALSE; for (i=0;i< (active_sps->chroma_format_idc == YUV400 ? 1 : 3); i++) { weight_sum = currSlice->wbp_weight[0][l0_refX][l1_refX][i] + currSlice->wbp_weight[1][l0_refX][l1_refX][i]; if (weight_sum < -128 || weight_sum > 127) { invalid_wp = TRUE; break; } } if (invalid_wp == FALSE) currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; else { direct_ref_idx[LIST_0] = -1; direct_ref_idx[LIST_1] = -1; currSlice->direct_pdir[pic_block_y][pic_block_x] = -1; } } /*! ************************************************************************************* * \brief * Temporary function for colocated info when direct_inference is enabled. * ************************************************************************************* */ int get_colocated_info(Macroblock *currMB, StorablePicture *list1, int i, int j) { if (list1->is_long_term) return 1; else { Slice *currSlice = currMB->p_Slice; VideoParameters *p_Vid = currMB->p_Vid; if( (currSlice->mb_aff_frame_flag) || (!p_Vid->active_sps->frame_mbs_only_flag && ((!currSlice->structure && !list1->coded_frame) || (rSlice->structure!=list1->structure && list1->coded_frame)))) { int jj = RSD(j); int ii = RSD(i); int jdiv = (jj>>1); int moving; PicMotionParams *fs = &list1->mv_info[jj][ii]; if(currSlice->structure && currSlice->structure!=list1->structure && list1->coded_frame) { if(currSlice->structure == TOP_FIELD) fs = list1->top_field->mv_info[jj] + ii; else fs = list1->bottom_field->mv_info[jj] + ii; } else { if( (currSlice->mb_aff_frame_flag && ((!currMB->mb_field && list1->motion.mb_field[currMB->mbAddrX]) (!currMB->mb_field && !list1->coded_frame))) || (!currSlice->mb_aff_frame_flag)) { if (iabs(p_Vid->enc_picture->poc - list1->bottom_field->poc)> iabs(p_Vid->enc_picture->poc -t1->top_field->poc) ) { fs = list1->top_field->mv_info[jdiv] + ii; } else { fs = list1->bottom_field->mv_info[jdiv] + ii; } } } moving = !((((fs->ref_idx[LIST_0] == 0) && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) || ((fs->ref_idx[LIST_0] == -1) && (fs->ref_idx[LIST_1] == 0) && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); return moving; } else { PicMotionParams *fs = &list1->mv_info[RSD(j)][RSD(i)]; int moving; if(currMB->p_Vid->yuv_format == YUV444 && !currSlice->P444_joined) fs = &list1->JVmv_info[(int)(p_Vid->colour_plane_id)][RSD(j)][RSD(i)]; moving= !((((fs->ref_idx[LIST_0] == 0) && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) || ((fs->ref_idx[LIST_0] == -1) && (fs->ref_idx[LIST_1] == 0) && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); return moving; } } } /*! ************************************************************************************* * \brief * Colocated info <= direct_inference is disabled. ************************************************************************************* */ int get_colocated_info_4x4(Macroblock *currMB, StorablePicture *list1, int i, int j) { if (list1->is_long_term) return 1; else { PicMotionParams *fs = &list1->mv_info[j][i]; int moving = !((((fs->ref_idx[LIST_0] == 0) && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) || ((fs->ref_idx[LIST_0] == -1) && (fs->ref_idx[LIST_1] == 0) && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); return moving; } } /*! ************************************************************************ * \brief * Calculate Spatial Direct Mode Motion Vectors ************************************************************************ */ void Get_Direct_MV_Spatial_Normal (Macroblock *currMB) { Slice *currSlice = currMB->p_Slice; VideoParameters *p_Vid = currMB->p_Vid; PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; char l0_refA, l0_refB, l0_refC; char l1_refA, l1_refB, l1_refC; char l0_refX,l1_refX; MotionVector pmvfw = zero_mv, pmvbw = zero_mv; int block_x, block_y, pic_block_x, pic_block_y, opic_block_x, opic_block_y; MotionVector *****all_mvs; char *direct_ref_idx; StorablePicture **list1 = currSlice->listX[LIST_1]; PixelPos mb[4]; get_neighbors(currMB, mb, 0, 0, 16); set_direct_references(&mb[0], &l0_refA, &l1_refA, mv_info); set_direct_references(&mb[1], &l0_refB, &l1_refB, mv_info); set_direct_references(&mb[2], &l0_refC, &l1_refC, mv_info); l0_refX = (char) imin(imin((unsigned char) l0_refA, (unsigned char) l0_refB), (unsigned char) l0_refC); l1_refX = (char) imin(imin((unsigned char) l1_refA, (unsigned char) l1_refB), (unsigned char) l1_refC); if (l0_refX >= 0) currMB->GetMVPredictor (currMB, mb, &pmvfw, l0_refX, mv_info, LIST_0, 0, 0, 16, 16); if (l1_refX >= 0) currMB->GetMVPredictor (currMB, mb, &pmvbw, l1_refX, mv_info, LIST_1, 0, 0, 16, 16); if (l0_refX == -1 && l1_refX == -1) { for (block_y=0; block_y<4; block_y++) { pic_block_y = currMB->block_y + block_y; for (block_x=0; block_x<4; block_x++) { pic_block_x = currMB->block_x + block_x; direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; currSlice->all_mv[LIST_0][0][0][block_y][block_x] = zero_mv; currSlice->all_mv[LIST_1][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_0] = direct_ref_idx[LIST_1] = 0; if (p_Vid->active_pps->weighted_bipred_idc == 1) test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, 0, 0, pic_block_y, pic_block_x); else currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; } } } else if (l0_refX == 0 || l1_refX == 0) { int (*get_colocated)(Macroblock *currMB, StorablePicture *list1, int i, int j) = p_Vid->active_sps->direct_8x8_inference_flag ? get_colocated_info : get_colocated_info_4x4; int is_moving_block; for (block_y = 0; block_y < 4; block_y++) { pic_block_y = currMB->block_y + block_y; opic_block_y = (currMB->opix_y >> 2) + block_y; for (block_x=0; block_x<4; block_x++) { pic_block_x = currMB->block_x + block_x; direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; opic_block_x = (currMB->pix_x >> 2) + block_x; all_mvs = currSlice->all_mv; is_moving_block = (get_colocated(currMB, list1[0], opic_block_x, opic_block_y) == 0); if (l0_refX < 0) { all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_0] = -1; } else if ((l0_refX == 0) && is_moving_block) { all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_0] = 0; } else { all_mvs[LIST_0][(short) l0_refX][0][block_y][block_x] = pmvfw; direct_ref_idx[LIST_0] = (char)l0_refX; } if (l1_refX < 0) { all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_1] = -1; } else if((l1_refX == 0) && is_moving_block) { all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_1] = 0; } else { all_mvs[LIST_1][(short) l1_refX][0][block_y][block_x] = pmvbw; direct_ref_idx[LIST_1] = (char)l1_refX; } if (direct_ref_idx[LIST_1] == -1) currSlice->direct_pdir[pic_block_y][pic_block_x] = 0; else if (direct_ref_idx[LIST_0] == -1) currSlice->direct_pdir[pic_block_y][pic_block_x] = 1; else if (p_Vid->active_pps->weighted_bipred_idc == 1) test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, l0_refX, l1_refX, pic_block_y, pic_block_x); else currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; } } } else { for (block_y=0; block_y<4; block_y++) { pic_block_y = currMB->block_y + block_y; for (block_x=0; block_x<4; block_x++) { pic_block_x = currMB->block_x + block_x; direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; all_mvs = currSlice->all_mv; if (l0_refX > 0) { all_mvs[LIST_0][(short) l0_refX][0][block_y][block_x] = pmvfw; direct_ref_idx[LIST_0]= (char)l0_refX; } else { all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_0]=-1; } if (l1_refX > 0) { all_mvs[LIST_1][(short) l1_refX][0][block_y][block_x] = pmvbw; direct_ref_idx[LIST_1] = (char)l1_refX; } else { all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_1] = -1; } if (direct_ref_idx[LIST_1] == -1) currSlice->direct_pdir[pic_block_y][pic_block_x] = 0; else if (direct_ref_idx[LIST_0] == -1) currSlice->direct_pdir[pic_block_y][pic_block_x] = 1; else if (p_Vid->active_pps->weighted_bipred_idc == 1) test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, l0_refX, l1_refX, pic_block_y, pic_block_x); else currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; } } } } /*! ************************************************************************ * \brief * Calculate Spatial Direct Mode Motion Vectors ************************************************************************ */ void Get_Direct_MV_Spatial_MBAFF (Macroblock *currMB) { char l0_refA, l0_refB, l0_refC; char l1_refA, l1_refB, l1_refC; char l0_refX,l1_refX; MotionVector pmvfw = zero_mv, pmvbw = zero_mv; int block_x, block_y, pic_block_x, pic_block_y, opic_block_x, opic_block_y; MotionVector *****all_mvs; char *direct_ref_idx; int is_moving_block; Slice *currSlice = currMB->p_Slice; VideoParameters *p_Vid = currMB->p_Vid; PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; StorablePicture **list1 = currSlice->listX[LIST_1 + currMB->list_offset]; int (*get_colocated)(Macroblock *currMB, StorablePicture *list1, int i, int j) = p_Vid->active_sps->direct_8x8_inference_flag ? get_colocated_info : get_colocated_info_4x4; PixelPos mb[4]; get_neighbors(currMB, mb, 0, 0, 16); if (currMB->mb_field) { set_direct_references_mb_field(&mb[0], &l0_refA, &l1_refA, mv_info, p_Vid->mb_data); set_direct_references_mb_field(&mb[1], &l0_refB, &l1_refB, mv_info, p_Vid->mb_data); set_direct_references_mb_field(&mb[2], &l0_refC, &l1_refC, mv_info, p_Vid->mb_data); } else { set_direct_references_mb_frame(&mb[0], &l0_refA, &l1_refA, mv_info, p_Vid->mb_data); set_direct_references_mb_frame(&mb[1], &l0_refB, &l1_refB, mv_info, p_Vid->mb_data); set_direct_references_mb_frame(&mb[2], &l0_refC, &l1_refC, mv_info, p_Vid->mb_data); } l0_refX = (char) imin(imin((unsigned char) l0_refA, (unsigned char) l0_refB), (unsigned char) l0_refC); l1_refX = (char) imin(imin((unsigned char) l1_refA, (unsigned char) l1_refB), (unsigned char) l1_refC); if (l0_refX >=0) currMB->GetMVPredictor (currMB, mb, &pmvfw, l0_refX, mv_info, LIST_0, 0, 0, 16, 16); if (l1_refX >=0) currMB->GetMVPredictor (currMB, mb, &pmvbw, l1_refX, mv_info, LIST_1, 0, 0, 16, 16); for (block_y=0; block_y<4; block_y++) { pic_block_y = currMB->block_y + block_y; opic_block_y = (currMB->opix_y >> 2) + block_y; for (block_x=0; block_x<4; block_x++) { pic_block_x = currMB->block_x + block_x; direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; opic_block_x = (currMB->pix_x >> 2) + block_x; is_moving_block = (get_colocated(currMB, list1[0], opic_block_x, opic_block_y) == 0); all_mvs = currSlice->all_mv; if (l0_refX >=0) { if (!l0_refX && is_moving_block) { all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_0] = 0; } else { all_mvs[LIST_0][(short) l0_refX][0][block_y][block_x] = pmvfw; direct_ref_idx[LIST_0] = (char)l0_refX; } } else { all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_0] = -1; } if (l1_refX >=0) { if(l1_refX==0 && is_moving_block) { all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_1] = (char)l1_refX; } else { all_mvs[LIST_1][(short) l1_refX][0][block_y][block_x] = pmvbw; direct_ref_idx[LIST_1] = (char)l1_refX; } } else { all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; direct_ref_idx[LIST_1] = -1; } // Test Level Limits if satisfied. // Test Level Limits if satisfied. if ((out_of_bounds_mvs(p_Vid, &all_mvs[LIST_0][l0_refX < 0? 0 : l0_refX][0][block_y][block_x]) || out_of_bounds_mvs(p_Vid, &all_mvs[LIST_1][l1_refX < 0? 0 : l1_refX][0][block_y][block_x]))) { direct_ref_idx[LIST_0] = -1; direct_ref_idx[LIST_1] = -1; currSlice->direct_pdir [pic_block_y][pic_block_x] = -1; } else { if (l0_refX < 0 && l1_refX < 0) { direct_ref_idx[LIST_0] = direct_ref_idx[LIST_1] = 0; l0_refX = 0; l1_refX = 0; } if (direct_ref_idx[LIST_1] == -1) currSlice->direct_pdir[pic_block_y][pic_block_x] = 0; else if (direct_ref_idx[LIST_0] == -1) currSlice->direct_pdir[pic_block_y][pic_block_x] = 1; else if (p_Vid->active_pps->weighted_bipred_idc == 1) test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, l0_refX, l1_refX, pic_block_y, pic_block_x); else currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; } } } }