(二)JM代码学习笔记-宏块访问模块(1)



1,qcif视频一帧图像的宏块划分如下


0(0,0)

1(1,0)

2(2,0)

 3(3,0)

4(4,0)

5(5,0)

6(6,0)

7(7,0)

8(8,0)

9 (9,0)   

10 (10,0)   

 

 

D

B

C

 

 

 

 

 

 

 

 

A

CurrMb

 

27(5,5)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

88(0,8)

 

 

 

 

 

 

 

 

 

98(10,8)  

                          图1, 宽 X 高=176X144 的一帧图像

   

 

       A

                     图2, 16X16的宏块

  一些概念:

     宏块地址:指的是宏块在一帧图像中的序号,比如图一中的0,1,2,3……98.

     宏块坐标:坐标的基本单位是宏块,比如图1中,宏块地址为27,其宏块坐标为(5,5)。需要注意的是宏块地址和宏块坐标都从0开始。

     宏块的绝对坐标:即采样坐标,宏块左上角像素的绝对坐标。比如宏块地址为27,宏块坐标为(5,5),其宏块绝对坐标为(80,80)。

    像素的绝对坐标是以图像左上角的像素为原点的。

    像素的相对坐标是以宏块左上角的像素为原点的。

2,对JM参考软件中mb_access.c文件进行代码分析

  (1) mb_is_available()函数

  (2)CheckAvailabilityOfNeighbors()函数             调用                mb_is_available()

 

  (3)get_mb_pos() 函数   通过函数指针get_mb_block_pos   调用   get_mb_block_pos_normal()和  get_mb_block_pos_mbaff()


  (4)get_mb_block_pos_normal()函数


  (5)get_mb_block_pos_mbaff()函数


  (6)getAffNeighbour()函数

 

  (7)getNonAffNeighbour()函数

 

  (8)get4x4Neighbour()函数 通过函数指针getNeighbour 调用  getNonAffNeighbour()和getAffNeighbour()

    

        以下是具体的函数分析

      mb_is_available()

   

/*!
 ************************************************************************
 * \brief
 *    returns 1 if the macroblock at the given address is available
    功能:给定一个宏块地址判断该宏块是否可用,若可用,返回1,不可用,返回0
	参数:mbAddr 输入的宏块地址,currMB 当前宏块
 ************************************************************************
 */
Boolean mb_is_available(int mbAddr, Macroblock *currMB)
{
  VideoParameters *p_Vid = currMB->p_Vid;
  if ((mbAddr < 0) || (mbAddr > ((int)p_Vid->PicSizeInMbs - 1)))//判断是否超出了宏块地址范围(0,MaxMbNum-1)
    return FALSE;

  // the following line checks both: slice number and if the mb has been decoded
  if (!currMB->DeblockCall)//如果当前块没有做去块滤波操作并且输入的宏块地址所代表的宏块
  {                        //和当前宏块不属于同一个片,则给定的宏块不可用。反过来说,如果
    if (p_Vid->mb_data[mbAddr].slice_nr != currMB->slice_nr)//当前宏块做去块滤波操作或者给定宏块和当前宏块
      return FALSE;                                        //所属同一片中,则给定宏块可用。
  }

  return TRUE;
}



  CheckAvailabilityOfNeighbors()函数

 

void CheckAvailabilityOfNeighbors(Macroblock *currMB)
{
  VideoParameters *p_Vid = currMB->p_Vid;
  const int mb_nr = currMB->mbAddrX;//mbAddrX:当前宏块地址。
  BlockPos *PicPos = p_Vid->PicPos;//PicPos 为一个指向BlockPos类型的指针,BlockPos为一个结构体,
                                   //内有变量x,y,构成宏块坐标。
  // mark all neighbors as unavailable
  currMB->mb_up   = NULL;//mb_up,mb_left指向相邻宏块的指针,标记为NULL。
  currMB->mb_left = NULL;

  if (p_Vid->mb_aff_frame_flag)//是否采用自适应帧场编码模式,若是,编码的是宏块对,而不是单个宏块,
  {                            //通常是16亮度像素宽和32亮度像素高的单元组成
    int cur_mb_pair = mb_nr >> 1;
    currMB->mbAddrA = 2 * (cur_mb_pair - 1);
    currMB->mbAddrB = 2 * (cur_mb_pair - p_Vid->PicWidthInMbs);
    currMB->mbAddrC = 2 * (cur_mb_pair - p_Vid->PicWidthInMbs + 1);
    currMB->mbAddrD = 2 * (cur_mb_pair - p_Vid->PicWidthInMbs - 1);

    currMB->mbAvailA = (byte) (mb_is_available(currMB->mbAddrA, currMB) && ((PicPos[cur_mb_pair    ].x)!=0));
    currMB->mbAvailB = (byte) (mb_is_available(currMB->mbAddrB, currMB));
    currMB->mbAvailC = (byte) (mb_is_available(currMB->mbAddrC, currMB) && ((PicPos[cur_mb_pair + 1].x)!=0));
    currMB->mbAvailD = (byte) (mb_is_available(currMB->mbAddrD, currMB) && ((PicPos[cur_mb_pair    ].x)!=0));
  }
  else
  {
    currMB->mbAddrA = mb_nr - 1;//A为当前块的左边,为当前宏块地址减一
    currMB->mbAddrB = mb_nr - p_Vid->PicWidthInMbs;
    currMB->mbAddrC = mb_nr - p_Vid->PicWidthInMbs + 1;
    currMB->mbAddrD = mb_nr - p_Vid->PicWidthInMbs - 1;

    currMB->mbAvailA = (byte) (mb_is_available(currMB->mbAddrA, currMB) && ((PicPos[mb_nr    ].x)!=0));//待解决:假设(mb_is_availa    ble(currMB->mbAddrA, currMB)为真时,PicPos[mb_nr    ].x)=0,当前宏块都在左边界,既然宏块在图像的左边界了,那作为当前宏块的左相邻块为什么还可以存在呢?
    currMB->mbAvailB = (byte) (mb_is_available(currMB->mbAddrB, currMB));                              
    currMB->mbAvailC = (byte) (mb_is_available(currMB->mbAddrC, currMB) && ((PicPos[mb_nr + 1].x)!=0));
    currMB->mbAvailD = (byte) (mb_is_available(currMB->mbAddrD, currMB) && ((PicPos[mb_nr    ].x)!=0));
  }

  if (currMB->mbAvailA) currMB->mb_left = &(p_Vid->mb_data[currMB->mbAddrA]);//如果A可用,保存该宏块的数据信息的内存地址。
  if (currMB->mbAvailB) currMB->mb_up   = &(p_Vid->mb_data[currMB->mbAddrB]);
}


  get_mb_pos()函数

 

/*!
 ************************************************************************
 * \brief
 *    returns the x and y sample coordinates for a given MbAddress
    输入参数:mb_addr当前宏块地址
	          mb_size[2] 宏块的大小,即宏块的宽和高。
			  x:用来保存宏块绝对坐标的横坐标
			  y: 用来保存宏块绝对坐标的纵坐标
	功能:得到宏块的绝对坐标,即给定宏块左上角的像素点相对于图像的绝对坐标。
 ************************************************************************
 */
void get_mb_pos (VideoParameters *p_Vid, int mb_addr, int mb_size[2], short *x, short *y)
{
  p_Vid->get_mb_block_pos(p_Vid->PicPos, mb_addr, x, y);//通过函数指针调用get_mb_block_pos_normal()函数或get_mb_block_pos_mbaff ()函数
                                                        
  (*x) = (short) ((*x) * mb_size[0]);
  (*y) = (short) ((*y) * mb_size[1]);
}


  get_mb_block_pos_normal()函数

 

 

/*!
 ************************************************************************
 * \brief
 *    returns the x and y macroblock coordinates for a given MbAddress
      输入参数:PicPos:指向BlockPos结构体类型的指针,表示的是宏块坐标,
	            可以通过改变指针所指向的变量改变结构体中变量的值
	            mb_addr:宏块地址
				x:用来保存宏块坐标的横坐标
				y:用来保存宏块坐标的纵坐标
 ************************************************************************
 */
void get_mb_block_pos_normal (BlockPos *PicPos, int mb_addr, short *x, short *y)
{
  *x = (short) PicPos[ mb_addr ].x;//当前宏块坐标的横坐标
  *y = (short) PicPos[ mb_addr ].y;//当前宏块坐标的纵坐标
}


    get_mb_block_pos_mbaff()函数和get_mb_block_pos_normal()函数功能类似,只不过是在宏块帧场级自适应的编码方式下。

 

   get4x4Neighbour()函数


 

/*!
 ************************************************************************
 * \brief
 *    get neighboring 4x4 block
     得到4x4块相邻像素的绝对坐标和其所在宏块的相对坐标
 * \param currMB
 *   current macroblock
 * \param block_x
 *    input x block position相对当前宏块原点的横坐标
 * \param block_y
 *    input y block position相对当前宏块原点的纵坐标
 * \param mb_size
 *    Macroblock size in pixel (according to luma or chroma MB access)宏块大小
 * \param pix
 *    returns position informations
     返回的是4x4块相邻像素的绝对坐标和其所在宏块的相对坐标
 ************************************************************************
 */
void get4x4Neighbour (Macroblock *currMB, int block_x, int block_y, int mb_size[2], PixelPos *pix)
{
  currMB->p_Vid->getNeighbour(currMB, block_x, block_y, mb_size, pix);//通过函数指针调用getNonAffNeighbour()或者getAffNeighbour()函数

  if (pix->available)//对可用像素点的位置这样处理,这样的原因可能是在参数传入之前,位置作了左移处理
  {
    pix->x >>= 2;
    pix->y >>= 2;//具体原因,待解释。
    pix->pos_x >>= 2;
    pix->pos_y >>= 2;
  }
}

    getNonAffNeighbour()函数

 

/*!
 ************************************************************************
 * \brief
 *    get neighbouring positions for non-aff coding
 * \param currMB
 *   current macroblock
 * \param xN
 *    input x position
 * \param yN
 *    input y position
 * \param mb_size
 *    Macroblock size in pixel (according to luma or chroma MB access)
 * \param pix
 *    returns position informations
     用pix指针来保存得到的位置信息。

   简述:相邻像素的可用性由其所在宏块的可用性决定。所以判断相邻像素的可用性,
   无非是判断该像素是否属于当前红块的左,左上,上,右上宏块内,再由之前的函数
   判断宏块的可用性。函数中的几个if……else语句就是来判断其是否输入当前宏块的
   相邻宏块。
   这里这里需要注意的是,输入进来的相邻像素的位置,是以当前宏块为原点坐标的
   ,所以当相邻像素属于当前宏块的左宏块时,xN<0,,当相邻像素属于当前宏块的左上
   宏块时,xN<0,yN<0.最终,我们要得到是相邻像素在所属宏块的相对坐标和其绝对坐标,
   所以在最后的if语句中,用与运算,将相邻像素相对当前宏块的坐标映射到其所属宏块
   中的相对坐标,再计算出其绝对坐标。
 ************************************************************************
 */
void getNonAffNeighbour(Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix)
{
  BlockPos *PicPos = currMB->p_Vid->PicPos;
  if (xN < 0)
  {
    if (yN < 0)
    {
      pix->mb_addr   = currMB->mbAddrD;
      pix->available = currMB->mbAvailD;
    }
    else if ((yN >= 0)&&(yN < mb_size[1]))
    {
      pix->mb_addr   = currMB->mbAddrA;
      pix->available = currMB->mbAvailA;
    }
    else
    {
      pix->available = FALSE;
    }
  }
  else if ((xN >= 0)&&(xN < mb_size[0]))
  {
    if (yN<0)
    {
      pix->mb_addr   = currMB->mbAddrB;
      pix->available = currMB->mbAvailB;
    }
    else if (((yN >= 0)&&(yN < mb_size[1])))
    {
      pix->mb_addr   = currMB->mbAddrX;
      pix->available = TRUE;
    }
    else
    {
      pix->available = FALSE;
    }
  }
  else if ((xN >= mb_size[0])&&(yN < 0))
  {
    pix->mb_addr   = currMB->mbAddrC;
    pix->available = currMB->mbAvailC;
  }
  else
  {
    pix->available = FALSE;
  }

  if (pix->available || currMB->DeblockCall)
  {
    pix->x     = (short) (xN & (mb_size[0] - 1));//x:像素相对所属宏块的坐标,即像素的相对坐标。
	//yN=-1;
    pix->y     = (short) (yN & (mb_size[1] - 1)); //用了单步调试,xN或yN为负数时,采用与运算,是可以映射为所属宏块的相对坐标。
	//printf("pix->y=%d\n",pix->y);
    pix->pos_x = (short) (pix->x + PicPos[ pix->mb_addr ].x * mb_size[0]);    
    pix->pos_y = (short) (pix->y + PicPos[ pix->mb_addr ].y * mb_size[1]);
  }
}



 


 

  





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值