预处理
将H中的16个像素全部设值为dc_pred_value,即128
if (*up_available)
{
memcpy(&PredPel[1], &img_enc[pix_b.pos_y][pix_b.pos_x], MB_BLOCK_SIZE * sizeof(imgpel));
}
else
{
for (i = 1; i < 17; ++i)
PredPel[i] = (imgpel) p_Vid->dc_pred_value;
}
将V中的16个像素全部设值为dc_pred_value,即128
if (*left_available)
{
int pos_y = pix_a.pos_y;
int pos_x = pix_a.pos_x;
for (i = 1; i < MB_BLOCK_SIZE + 1; ++i)
PredPel[i + 16] = img_enc[pos_y++][pos_x];
}
else
{
for (i = 17; i < 33; ++i)
PredPel[i] = (imgpel) p_Vid->dc_pred_value;
}
设置左上角的像素点为dc_pred_value,即128
if (*all_available)
{
PredPel[0] = img_enc[pix_d.pos_y][pix_d.pos_x];
}
else
{
PredPel[0] = p_Vid->dc_pred_value;
}
关于dc_pred_value
dc_pred_value的值与图像的位深有关:dc_pred_value = 2 b i t d e p t h − 1 =2^{bitdepth-1} =2bitdepth−1,一般的,当 b i t d e p t h = 8 bitdepth=8 bitdepth=8时,有dc_pred_value=128
cps->dc_pred_value_comp[0] = (uint32) (1<<(cps->bitdepth_luma - 1));
四种模式
四种模式分别为
mode0 vertical
mode1 horizontal
mode2 DC
mode3 plane
enum {
VERT_PRED_16 = 0,
HOR_PRED_16 = 1,
DC_PRED_16 = 2,
PLANE_16 = 3
} I16x16PredModes;
mode0 vertical
将H中的16个像素向下复制即可
#define MB_BLOCK_SIZE 16
static inline void get_i16x16_vertical(imgpel **cur_pred, imgpel *PredPel)
{
int j;
for (j = 0; j < MB_BLOCK_SIZE; j++)
memcpy(cur_pred[j], &PredPel[1], MB_BLOCK_SIZE * sizeof(imgpel));
}
mode1 horizontal
将V中的16个像素向右复制即可
#define MB_BLOCK_SIZE 16
static inline void get_i16x16_horizontal(imgpel **cur_pred, imgpel *PredPel)
{
int i, j;
imgpel *prediction = &PredPel[16];
for (j = 0; j < MB_BLOCK_SIZE; j++)
{
prediction++;
for (i = 0; i < MB_BLOCK_SIZE; i++)
{
cur_pred[j][i] = *prediction;
}
}
}
mode2 DC
同I_4x4一样:
若H和V都有,则mean(H+V)
若只有H,则mean(H)
若只有V,则mean(V)
若H和V都没,则mean = 128
#define MB_BLOCK_SIZE 16
#define MB_BLOCK_SHIFT 4
static inline void get_i16x16_dc(imgpel **cur_pred, imgpel *PredPel, int left_available, int up_available)
{
int i, j, s0 = 0, s1 = 0, s2 = 0;
if (up_available)
{
for (i = 1; i < MB_BLOCK_SIZE + 1; ++i)
s1 += PredPel[i];
}
if (left_available)
{
for (i = 17; i < 33; ++i)
s2 += PredPel[i]; // sum vert pix
}
if (up_available)
{
s0 = left_available
? rshift_rnd_sf((s1 + s2),(MB_BLOCK_SHIFT + 1)) // all edge
: rshift_rnd_sf(s1, MB_BLOCK_SHIFT); // left edge
}
else
{
s0 = left_available
? rshift_rnd_sf(s2, MB_BLOCK_SHIFT) // upper edge
: PredPel[1]; // top left corner, nothing to predict from;预处理中PredPel[1] = dc_pred_value
}
for (j = 0; j < MB_BLOCK_SIZE; j++)
{
for (i = 0; i < MB_BLOCK_SIZE; i++)
cur_pred[j][i] = (imgpel) s0;
}
}
mode3 plane
根据源码分析有如下公式(意义尚不明确,欢迎指点)
H
=
∑
x
′
=
0
7
(
x
′
+
1
)
∗
(
p
[
8
+
x
′
,
−
1
]
−
p
[
6
−
x
′
,
−
1
]
)
V
=
∑
y
′
=
0
7
(
y
′
+
1
)
∗
(
p
[
−
1
,
8
+
y
′
]
−
p
[
−
1
,
6
−
y
′
]
)
a
=
16
∗
(
p
[
−
1
,
15
]
+
p
[
15
,
−
1
]
)
b
=
(
5
∗
H
+
32
)
>
>
6
c
=
(
5
∗
V
+
32
)
>
>
6
p
r
e
d
L
[
x
,
y
]
=
C
l
i
p
1
(
(
a
+
b
∗
(
x
−
7
)
+
c
∗
(
y
−
7
)
+
16
)
)
H=\sum_{x'=0}^{7} (x'+1)*(p[8+x',-1]-p[6-x',-1])\\ V=\sum_{y'=0}^{7} (y'+1)*(p[-1,8+y']-p[-1,6-y'])\\ a=16*(p[-1,15]+p[15,-1])\\ b=(5*H+32)>>6\\ c=(5*V+32)>>6\\ pred_L[x,y]=Clip1( (a+b*(x-7)+c*(y-7)+16) )
H=x′=0∑7(x′+1)∗(p[8+x′,−1]−p[6−x′,−1])V=y′=0∑7(y′+1)∗(p[−1,8+y′]−p[−1,6−y′])a=16∗(p[−1,15]+p[15,−1])b=(5∗H+32)>>6c=(5∗V+32)>>6predL[x,y]=Clip1((a+b∗(x−7)+c∗(y−7)+16))
static inline void get_i16x16_plane(imgpel **cur_pred, imgpel *PredPel, int max_imgpel_value)
{
int i, j;
// plane prediction
int ih=0, iv=0;
int ib, ic, iaa;
imgpel *t_pred = &PredPel[25];
imgpel *u_pred = &PredPel[8];
imgpel *b_pred = &PredPel[23];
for (i = 1; i < 8;++i)
{
ih += i*(*(u_pred + i) - *(u_pred - i));
iv += i*(*t_pred++ - *b_pred--);
}
ih += 8 * (*(u_pred + 8) - PredPel[0]);
iv += 8 * (*t_pred++ - PredPel[0]);
ib = (5 * ih + 32) >> 6;
ic = (5 * iv + 32) >> 6;
iaa=16 * (PredPel[16] + PredPel[32]);
for (j=0;j< MB_BLOCK_SIZE;++j)
{
for (i=0;i< MB_BLOCK_SIZE;++i)
{
//iClip1(max , a)将a限定在[0,max]范围中,这里则是限定在[0,255]中,保证像素值有意义
cur_pred[j][i]= (imgpel) iClip1( max_imgpel_value, rshift_rnd_sf((iaa + (i - 7) * ib + (j - 7) * ic), 5));// store plane prediction
}
}
}
模式的选择
遍历4种预测模式vertical horizontal DC plane,计算各种模式下的开销(SAD SSE SATD),选择开销最小的模式。
//rd_intra_jm.c
int find_best_mode_I16x16_MB (Macroblock *currMB, int lambda, distblk min_cost)
{
Slice *currSlice = currMB->p_Slice;
currMB->luma_transform_size_8x8_flag = FALSE;
return (int) currSlice->find_sad_16x16 (currMB);
}
distblk find_sad_16x16_JM(Macroblock *currMB)
{
Slice *currSlice = currMB->p_Slice; //得到当前MB的slice
VideoParameters *p_Vid = currMB->p_Vid; //得到video参数
InputParameters *p_Inp = currMB->p_Inp; //得到input参数
distblk current_intra_sad_2, best_intra_sad2 = DISTBLK_MAX; //初始化当前intra模式和最优intra模式的sad为最大值
int k;
imgpel ***curr_mpr_16x16 = currSlice->mpr_16x16[0];
int up_avail, left_avail, left_up_avail;
currMB->i16mode = DC_PRED_16; //暂设当前MB为DC
currSlice->set_intrapred_16x16(currMB, PLANE_Y, &left_avail, &up_avail, &left_up_avail); //对Y进行边缘像素预处理
// For speed purposes, we should just unify all planes
if (currSlice->P444_joined) //若是YUV444格式
{
currSlice->set_intrapred_16x16(currMB, PLANE_U, &left_avail, &up_avail, &left_up_avail); //对U进行边缘像素预处理
currSlice->set_intrapred_16x16(currMB, PLANE_V, &left_avail, &up_avail, &left_up_avail); //对V进行边缘像素预处理
}
for (k = VERT_PRED_16; k <= PLANE_16; k++) //遍历4种模式 vertical horizontal DC plane
{
if (p_Inp->IntraDisableInterOnly == 0 || (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) )
{
if (p_Inp->Intra16x16ParDisable && (k == VERT_PRED_16||k == HOR_PRED_16))
continue;
if (p_Inp->Intra16x16PlaneDisable && k == PLANE_16)
continue;
}
//check if there are neighbours to predict from
if (!((k == VERT_PRED_16 && !up_avail) || (k == HOR_PRED_16 && !left_avail) || (k == PLANE_16 && (!left_avail || !up_avail || !left_up_avail))))
{ //若当前模式为vertical且up像素不可用 或 当前模式horizontal且left像素不可用 或 当前模式plane且left/up/left_up像素存在不可用
get_intrapred_16x16(currMB, PLANE_Y, k, left_avail, up_avail); //对Y使用当前模式k
current_intra_sad_2 = currSlice->distI16x16(currMB, p_Vid->pCurImg, curr_mpr_16x16[k], best_intra_sad2); //计算该模式下的开销
if (currSlice->P444_joined)
{
get_intrapred_16x16(currMB, PLANE_U, k, left_avail, up_avail);
current_intra_sad_2 += currSlice->distI16x16(currMB, p_Vid->pImgOrg[1], currSlice->mpr_16x16[1][k], best_intra_sad2);
get_intrapred_16x16(currMB, PLANE_V, k, left_avail, up_avail);
current_intra_sad_2 += currSlice->distI16x16(currMB, p_Vid->pImgOrg[2], currSlice->mpr_16x16[2][k], best_intra_sad2);
}
if (current_intra_sad_2 < best_intra_sad2) //若当前模式的开销小于最优模式的开销
{
//更新最优模式
best_intra_sad2 = current_intra_sad_2;
currMB->i16mode = (char) k; // update best intra mode
}
}
}
return best_intra_sad2; //返回最优模式的开销
}
void get_intrapred_16x16(Macroblock *currMB, ColorPlane pl, int i16x16_mode, int left_available, int up_available)
{
imgpel *PredPel = currMB->intra16x16_pred[pl]; // array of predictor pels
imgpel ***curr_mpr_16x16 = currMB->p_Slice->mpr_16x16[pl];
switch (i16x16_mode)
{
case VERT_PRED_16 :
get_i16x16_vertical(curr_mpr_16x16[VERT_PRED_16], PredPel);
break;
case HOR_PRED_16 :
get_i16x16_horizontal(curr_mpr_16x16[HOR_PRED_16], PredPel);
break;
case DC_PRED_16 :
get_i16x16_dc(curr_mpr_16x16[DC_PRED_16], PredPel, left_available, up_available);
break;
case PLANE_16 :
get_i16x16_plane(curr_mpr_16x16[PLANE_16], PredPel, currMB->p_Vid->max_imgpel_value);
break;
default:
printf("invalid prediction mode \n");
break;
}
}
-
distI16x16函数指针指向的函数在Intra-prediction(4)之三种开销的计算模式中有讲到,它返回该预测模式下的开销
代码参考:JM19.0