Intra Chroma Prediction
帧内预测依赖于当前宏块的相邻宏块,如果任何一个相邻宏块不可用,那么会直接影响到当前宏块的预测方式。
那么宏块怎么才谓之可用?
满足以下几个条件的相邻宏块为不可用:
- 相邻宏块超出边界,即(x<0 || x>PicWidthInMbs),(y<0 || y>PicHeightInMbs)
- 相邻宏块与当前处理的宏块不在同一slice
- 如果强制要求当前宏块的相邻宏块为intra(constrained_intra_pred_flag = 1),但实际上相邻宏块的编码方式为inter,该相邻宏块就不可用。
当然以上只适用于判断相邻宏块是否可用于intra预测;而对于inter预测,只要判断条件1与2;而在进行deblocking的情况下只需判断条件1。
(以下的"可用"都为"可用于Intra预测")
Intra Chroma Prediction
帧内色度预测有四种预测模式。
1 . Intra_Chroma_DC
DC模式会选取相邻Chroma宏块的相应像素,取像素平均值来预测当前4x4块的像素值。由于预测块大小为4x4,因此相邻块像素值也取四个为一组:
$\begin{align*}
Sum_{up} &=\sum_{x=0}^{3}Pixel(x,-1)\\
Sum_{left} &=\sum_{y=0}^{3}Pixel(-1,y)\\
Sum_{default} &=1<<(BitDepth-1)
\end{align*}$
DC模式分为三种情况
- 如果Top与Left可用
$Pred_{4\times4}(x,y) = (Sum_{up} + Sum_{left})>>3$
- 否则如果只有Top或者只有Left可用
$ Pred_{4\times4}(x,y)=Sum_{up} >>2$ or $Pred_{4\times4}(x,y)=Sum_{left}>>2$
- 否则Top与Left都不可用
$Pred_{4\times4}(x,y)=Sum_{default}$
- 如果Top可用
$ Pred_{4\times4}(x,y)=Sum_{up} >>2$
- 否则如果left可用
$Pred_{4\times4}(x,y)=Sum_{left}>>2$
- 否则
$Pred_{4\times4}(x,y)=Sum_{default}$
- 如果left可用
$Pred_{4\times4}(x,y)=Sum_{left}>>2$
- 否则如果Top可用
$ Pred_{4\times4}(x,y)=Sum_{up} >>2$
- 否则
$Pred_{4\times4}(x,y)=Sum_{default}$

2 . Intra Chroma Horizon
只有当左相邻宏块的像素点Pixel(-1,y)被标记为可以用于帧内预测时才能采用这种预测方式
$Pred(x,y)=Pixel(-1,y)$

3 . Intra Chroma Vertical
只有当上方相邻宏块的像素点Pixel(x,-1)被标记为可以用于帧内预测时才能采用这种预测方式
$Pred(x,y)=Pixel(x,-1)$

4 . Intra Chroma Plane
只有当左相邻宏块像素点Pixel(-1,y)以及上方相邻宏块像素点Pixel(x,-1)都被标记为可以用于Intra预测时才能采用这种预测方式
首先我们来看标准中的两个式子
$\begin{align*}
H&=\sum_{x=0}^{3+xCF}(x+1)\times{(Pixel(4+xCF+x,-1)-Pixel(2+xCF-x,-1))}\\
V&=\sum_{y=0}^{3+yCF}(y+1)\times{(Pixel(-1,4+yCF+y)-Pixel(-1,2+yCF-y))}
\end{align*}$
由于xCF与yCF是YUV格式相关参数,当为0时表示为4:2:0
$\begin{align*}
H&=\sum_{x=0}^{3}(x+1)\times{(Pixel(4+x,-1)-Pixel(2-x,-1))}\\
V&=\sum_{y=0}^{3}(y+1)\times{(Pixel(-1,4+y)-Pixel(-1,2-y))}
\end{align*}$
我们在这里令$M= Pixel(4+x,-1)-Pixel(2-x,-1)$,令x为x轴,M为y轴,H为z轴,得到以下图像

可以看出在x越大的情况下(趋向于宏块两端),如果M(两端像素差)越大,那么得到的值也就越大,因此该参数H表明了Pixel(x,-1)的变化趋势,是变大呢(H值很大),变小呢(H值为负,很小),还是平缓(H值在0附近)。
同理,V在y轴上也是这种情况。
按照上面的说法,这就是一个线性系数,那么我们就可以把H与V做一下调整,归一化得到线性系数b与c
$\begin{align*}
b &= (34+29\times{H})>>6 \\
c &= (34+29\times{V})>>6
\end{align*}$
得到系数后,再确定常量(基准值)就可以得到一个完整的式子了。那么如何确定基准值?这里假设像素是按照左下->右上的方式变化的,即像素值在该方向上线性变化。

那么取中心点为基准值,该基准值为左相邻宏块的最低端与上相邻宏块最右端的平均值
$Pred(3,3)=(Pixel(width-1,-1)+Pixel(-1,height-1))>>1$
$a =16\times{(Pixel(width-1,-1)+Pixel(-1,height-1))}$
最后得到预测公式
$Pred(x,y)=(a+b\times{(x-3-xCF)}+c\times{(y-3-yCF)}+16)>>5$
JM18.6
/*!
************************************************************************
* \brief
* Intra prediction of the chrminance layers of one macroblock
************************************************************************
*/
void intra_chroma_prediction (Macroblock *currMB, int *mb_up, int *mb_left, int*mb_up_left)
{
int s, i, j; int uv;
int b8, b4;
imgpel vline[16]; int mb_available_up;
int mb_available_left[2];
int mb_available_up_left; PixelPos pix_c; //!< pixel position p(0,-1)
PixelPos pix_d;
PixelPos pix_a; //!< pixel positions p(-1, -1..15) Slice *currSlice = currMB->p_Slice;
VideoParameters *p_Vid = currSlice->p_Vid;
InputParameters *p_Inp = currSlice->p_Inp;
int cr_MB_x = p_Vid->mb_cr_size_x;
int cr_MB_y = p_Vid->mb_cr_size_y;
imgpel **cur_pred = NULL; imgpel *hline = NULL; int yuv = p_Vid->yuv_format - 1;
int dc_pred_value_chroma = p_Vid->dc_pred_value_comp[1];
int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; static const int block_pos[3][4][4]= //[yuv][b8][b4]
{
{ {0, 1, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}},
{ {0, 1, 2, 3},{2, 3, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0}},
{ {0, 1, 2, 3},{1, 1, 3, 3},{2, 3, 2, 3},{3, 3, 3, 3}}
}; p_Vid->getNeighbour(currMB, -1, -1, p_Vid->mb_size[IS_CHROMA], &pix_d);
p_Vid->getNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_CHROMA], &pix_a);
p_Vid->getNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &pix_c); mb_available_up = pix_c.available;
mb_available_up_left = pix_d.available;
mb_available_left[0] = mb_available_left[1] = pix_a.available; //强制要求相邻宏块使用帧内预测,否则不可用
if(p_Inp->UseConstrainedIntraPred)
{
mb_available_up = pix_c.available ? p_Vid->intra_block[pix_c.mb_addr] : 0;
mb_available_left[0] = mb_available_left[1] = pix_a.available ? p_Vid->intra_block[pix_a.mb_addr] : 0;
mb_available_up_left = pix_d.available ? p_Vid->intra_block[pix_d.mb_addr] : 0;
} if (mb_up)
*mb_up = mb_available_up;
if (mb_left)
*mb_left = mb_available_left[0];
if (mb_up_left)
*mb_up_left = mb_available_up_left; // compute all chroma intra prediction modes for both U and V
for (uv=0; uv<2; uv++)
{
imgpel **image = p_Vid->enc_picture->imgUV[uv];
imgpel ***curr_mpr_16x16 = currSlice->mpr_16x16[uv + 1]; // DC prediction
for(b8=0; b8<p_Vid->num_blk8x8_uv >> 1;b8++)
{
for (b4 = 0; b4 < 4; b4++)
{
int block_y = subblk_offset_y[yuv][b8][b4];
int block_x = subblk_offset_x[yuv][b8][b4];
int blk_x = block_x; s = dc_pred_value_chroma; //===== get prediction value =====
switch (block_pos[yuv][b8][b4])
{
case 0: //===== TOP LEFT =====
{
int s0 = 0, s2 = 0;
if (mb_available_up)
{
int pos_x = pix_c.pos_x + blk_x;
int pos_y = pix_c.pos_y; for (i = 0; i < BLOCK_SIZE; i++)
s0 += image[pos_y][pos_x++];
}
if (mb_available_left[0])
{
int pos_x = pix_a.pos_x;
int pos_y = pix_a.pos_y + block_y; for (i = 0; i < BLOCK_SIZE;i++)
s2 += image[pos_y++][pos_x];
}
if (mb_available_up && mb_available_left[0])
s = (s0 + s2 + 4) >> 3;
else if (mb_available_up)
s = (s0 + 2) >> 2;
else if (mb_available_left[0])
s = (s2 + 2) >> 2;
}
break;
case 1: //===== TOP RIGHT =====
{
int s1 = 0, s2 = 0;
if (mb_available_up)
{
int pos_x = pix_c.pos_x + blk_x;
int pos_y = pix_c.pos_y;
for (i = 0; i < BLOCK_SIZE; i++)
s1 += image[pos_y][pos_x++];
}
else if (mb_available_left[0])
{
int pos_x = pix_a.pos_x;
int pos_y = pix_a.pos_y + block_y; for (i = 0; i < BLOCK_SIZE; i++)
s2 += image[pos_y++][pos_x];
}
if (mb_available_up)
s = (s1 +2) >> 2;
else if (mb_available_left[0])
s = (s2 +2) >> 2;
}
break;
case 2: //===== BOTTOM LEFT =====
if (mb_available_left[0])
{
int pos_x = pix_a.pos_x;
int pos_y = pix_a.pos_y + block_y;
int s3 = 0; for (i = 0; i < BLOCK_SIZE; i++)
s3 += image[pos_y++][pos_x];
s = (s3 + 2) >> 2;
}
else if (mb_available_up)
{
int pos_x = pix_c.pos_x + blk_x;
int pos_y = pix_c.pos_y; int s0 = 0;
for (i = 0; i < BLOCK_SIZE; i++)
s0 += image[pos_y][pos_x++];
s = (s0 + 2) >> 2;
}
break;
case 3: //===== BOTTOM RIGHT =====
{
int s1 = 0, s3 = 0;
if (mb_available_up)
for (i=blk_x;i<(blk_x+4);i++)
s1 += image[pix_c.pos_y][pix_c.pos_x + i];
if (mb_available_left[0])
{
int pos_x = pix_a.pos_x;
int pos_y = pix_a.pos_y + block_y;
for (i = 0; i < BLOCK_SIZE;i++)
s3 += image[pos_y++][pos_x];
}
if (mb_available_up && mb_available_left[0])
s = (s1 + s3 + 4) >> 3;
else if (mb_available_up)
s = (s1 + 2) >> 2;
else if (mb_available_left[0])
s = (s3 + 2) >> 2;
}
break;
} //===== prediction =====
cur_pred = curr_mpr_16x16[DC_PRED_8];
for (j = block_y; j < block_y+4; j++)
{
for (i = block_x; i < block_x+4; i++)
{
cur_pred[j][i] = (imgpel) s;
}
}
}
} // vertical prediction
if (mb_available_up)
{
cur_pred = curr_mpr_16x16[VERT_PRED_8];
hline = &image[pix_c.pos_y][pix_c.pos_x];
for (j=0; j<cr_MB_y; j++)
memcpy(cur_pred[j], hline, cr_MB_x * sizeof(imgpel));
} // horizontal prediction
if (mb_available_left[0])
{
int pos_x = pix_a.pos_x;
int pos_y = pix_a.pos_y;
cur_pred = curr_mpr_16x16[HOR_PRED_8];
for (i=0; i<cr_MB_y; i++)
vline[i] = image[pos_y++][pos_x]; for (j=0; j<cr_MB_y; j++)
{
int predictor = vline[j];
for (i = 0; i < cr_MB_x; i++)
cur_pred[j][i] = (imgpel) predictor;
}
} // plane prediction
if (mb_available_left[0] && mb_available_up && mb_available_up_left)
{
int cr_x = (cr_MB_x >> 1);
int cr_y = (cr_MB_y >> 1); int iaa, iv, ib, ic;
int ih = cr_x * (hline[cr_MB_x-1] - image[pix_d.pos_y][pix_d.pos_x]); for (i = 0; i < cr_x - 1; i++)
ih += (i + 1)*(hline[cr_x + i] - hline[cr_x - 2 - i]); iv = cr_y * (vline[cr_MB_y-1] - image[pix_d.pos_y][pix_d.pos_x]);
for (i = 0; i < cr_y - 1; i++)
iv += (i + 1) * (vline[cr_y + i] - vline[cr_y - 2 - i]); if (cr_MB_x == 8)
ib = (17 * ih + 2 * cr_MB_x) >> 5;
else
ib = ( 5 * ih + 2 * cr_MB_x) >> 6; if (cr_MB_y == 8)
ic = (17 * iv + 2 * cr_MB_y) >> 5;
else
ic = ( 5 * iv + 2 * cr_MB_y) >> 6; iaa = 16 * (hline[cr_MB_x - 1] + vline[cr_MB_y - 1]);
cur_pred = curr_mpr_16x16[PLANE_8];
iaa += (1 - cr_x) * ib + (1 - cr_y) * ic;
for (j = 0; j < cr_MB_y; j++)
for (i = 0; i < cr_MB_x; i++)
cur_pred[j][i]= (imgpel) iClip1( max_imgpel_value_uv, (iaa + i * ib + j * ic + 16)>>5);
}
} if (!p_Inp->rdopt) // the rd-opt part does not work correctly (see encode_one_macroblock)
{ // since ipredmodes could be overwritten => encoder-decoder-mismatches
currSlice->rdo_low_intra_chroma_decision(currMB, mb_available_up, mb_available_left, mb_available_up_left);
}
}
Intra Chroma Prediction的更多相关文章
- Intra Luma Prediction
在宏块的帧内预测过程中,有四种宏块类型:I_4x4,I_8x8,I16x16,I_PCM.他们都需要在相邻块做去块滤波之前进行帧内预测. 亮度帧内预测的总体流程 1-4获取当前block的帧内预测模式 ...
- h.264语法结构分析
NAL Unit Stream Network Abstraction Layer,简称NAL. h.264把原始的yuv文件编码成码流文件,生成的码流文件就是NAL单元流(NAL unit Stre ...
- h.264宏块与子宏块类型
宏块类型mb_type 宏块类型表示的是宏块不同的分割和编码方式,在h.264的语法结构中,宏块类型在宏块层(macroblock_layer)中用mb_type表示(请参考h.264语法结构分析中的 ...
- [ffmpeg] h.264解码所用的主要缓冲区介绍
在进行h264解码过程中,有两个最重要的结构体,分别为H264Picture.H264SliceContext. H264Picture H264Picture用于维护一帧图像以及与该图像相关的语法元 ...
- x264阅读记录-2
x264阅读记录-2 7. x264_encoder_encode函数-1 查看该函数代码(Encoder.c文件)可以发现,该函数中注释很详细,对编码的整个步骤展示的也相对比较清晰. 在查看具体的代 ...
- 解决ffmpeg拉流转发频繁丢包问题max delay reached. need to consume packet
软件: 1.流媒体服务器EasyDarwin-windows-8.1.0-1901141151 2.ffmpeg-20181001-dcbd89e-win64-static 3.直播源:rtsp:// ...
- 【二】H.264/MPEG-4 Part 10 White Paper 翻译之 Prediction of Intra Macroblocks
翻译版权所有,转载请注明出处~ xzrch@2018.09.14 ------------------------------------------------------------------- ...
- x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- 【HEVC帧间预测论文】P1.4 Motion Vectors Merging: Low Complexity Prediction Unit Decision
Motion Vectors Merging: Low Complexity Prediction Unit Decision Heuristic for the inter-Prediction o ...
随机推荐
- CreateThread函数
当使用CreateProcess调用时,系统将创建一个进程和一个主线程. CreateThread将在主线程的基础上创建一个新线程,大致做例如以下步骤: 1在内核对象中分配一个线程标识/句柄,可供管理 ...
- caffe源代码分析--math_functions.cu代码研究
当中用到一个宏定义CUDA_KERNEL_LOOP 在common.hpp中有. #defineCUDA_KERNEL_LOOP(i,n) \ for(inti = blockIdx.x * bloc ...
- service redis does not support chkconfig的解决办法
原文链接: http://my.oschina.net/maczhao/blog/322931 问题解决办法如下: 必须把下面两行注释放在/etc/init.d/redis文件靠前的注释中: # ch ...
- Exception in thread "main" brut.androlib.AndrolibException: brut.androlib.AndrolibException: brut.common.BrutException: could not exec command
错误如下: Exception in thread "main" brut.androlib.AndrolibException: brut.androlib.AndrolibEx ...
- Redis的AOF功能
引言: Redis是基于内存的数据库,同时也提供了若干持久化的方案,允许用户把内存中的数据,写入本地文件系统,以备下次重启或者当机之后继续使用.本文将描述如何基于Redis来设置AOF功能 什么是R ...
- 自己编写SqlHelper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...
- Android之使用json进行网络数据交换
JSON作为一种轻量级的数据交换格式,凭借其易于阅读和编写.易于解析.传输速度快等优点流行了起来.最近正好在学习Android端从服务端端取数据,Json便派上了用场.好,下面开始切入主题. 1.准备 ...
- Xcode工程添加第三方文件的详细分析 Create folder references for any added folders
在开发iOS项目的时候需要导入第三方的库文件,但是通过Xcode导入第三方源文件的时候会提示一些信息,不知所以然. 现在看到的文档都是针对Xcode3的,针对Xcode4的说明很少,现在分享出来. 官 ...
- JavaScript--循环--打印星星和99乘法表
1.打印99乘法表 function chengfa(){ //反复调用公式 for(var r=1;r<=9;r++){ for(var i=1,str="";i<= ...
- Android单位度量
px(像素):屏幕上的点. in(英寸):长度单位.mm(毫米):长度单位.pt(磅):1/72英寸.dp(与密度无关的像素):一种基于屏幕密度的抽象单位.在每英寸160点的显示器上,1dp = 1p ...