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]);
}
}
JM代码学习笔记-宏块访问模块(1)&spm=1001.2101.3001.5002&articleId=47277269&d=1&t=3&u=0b41771575814268a56ed7ab9534cce2)
7486

被折叠的 条评论
为什么被折叠?



