264标准只定义了码流的格式编码器实现是各公司自己的事,只要形成的码流符合标准就行解码器必须按照这个格式来,这样任何符合标准的码流都可以解出来
Q:什么是SAD,SAE,SATD,SSD,SSE,MAD,MAE,MSD,MSE?
A:SAD(Sum of Absolute Difference)=SAE(Sum of Absolute Error)即绝对误差和
SATD(Sum of Absolute Transformed Difference)即hadamard变换后再绝对值求和
SSD(Sum of Squared Difference)=SSE(Sum of Squared Error)即差值的平方和
MAD(Mean Absolute Difference)=MAE(Mean Absolute Error)即平均绝对差值
MSD(Mean Squared Difference)=MSE(Mean Squared Error)即平均平方误差
Q:如果不用率失真最优化,为什么选择SATD+delta×r(mv,mode)作为模式选择的依据?为什么运动估计中,整象素搜索用SAD,而亚象素用SATD?为什么帧内模式选择要用SATD?
SAD即绝对误差和,仅反映残差时域差异,影响PSNR值,不能有效反映码流的大小。SATD即将残差经哈德曼变换的4×4块的预测残差绝对值总和,可以将其看作简单的时频变换,其值在一定程度上可以反映生成码流的大小。因此,不用率失真最优化时,可将其作为模式选择的依据。
一般帧内要对所有的模式进行检测,帧内预测选用SATD的原因同上。
在做运动估计时,一般而言,离最优匹配点越远,匹配误差值SAD越大,这就是有名的单一平面假设,现有的运动估计快速算法大都利用该特性。但是,转换后SATD值并不满足该条件,如果在整象素中运用SATD搜索,容易陷入局部最优点。而在亚象素中,待搜索点不多,各点处的SAD差异相对不大,可以用SATD选择码流较少的匹配位置。
Q:下面代码的功能是什么?
if(x & (~255))
{
pix[i] = (-x) >> 31;
}
else
{
pix[i] = (unsigned char)x;
}
A:
x的定义是short型,pix定义的是unsigned char型
这段代码可以这么理解(这段代码的功能):
如果x<0,-x为正,-x左移31位肯定为0,那么pix[i]=0,
如果x>255,那么pix[i]=255,否则pix[i]=x;
#include <stdio.h>
main()
{
short x;
unsigned char pix;
x=1024*16;
if(x & (~255))
pix = (-x) >> 16;
else
pix = (unsigned char)x;
printf("pix=%d\n",pix);
}
Q:CABAC中开始时各字符出现的概率是怎么得到的?
A:基于查表实现的
Q:What is RVLC?
A:It is a VLC method which can be decoded from left to right and from right to left exclusively
Q:RDO模型用来干什么?RQ模型又用来干什么?
A: RDO用来确定编码模式的,保证码率比特数和图像失真的最佳权衡点,而 RQ是在上一层码率数一定的情况下用来确定下一层分配的比特数。RQ先于RDO进行。
Q:帧,场,图像的联系与区别是什么?
frame;逐行扫描图像
field:隔行扫描图像,偶数行成为顶场行,奇数行称为为底场行,所有顶场行称为顶场,同样所有底场行称为底场。
pictue:场和帧都可认为是图像
[注:SUPERPUMA语]
顶底场分别编码,对应位置的宏块叫做宏块对。顶场对已编码的顶/底场预测编码。底场一般对顶场预测编码
frame;逐行扫描图像
field:隔行扫描图像,偶数行成为顶场行,奇数行称为为底场行,所有顶场行称为顶场,同样所有底场行称为底场。
pictue:场和帧都可认为是图像
[注:SUPERPUMA语]
顶底场分别编码,对应位置的宏块叫做宏块对。顶场对已编码的顶/底场预测编码。底场一般对顶场预测编码
Q: I帧和P帧的概念比较好懂,B帧的概念有些模糊,只知道加了B帧图像质量会更好,请问对B帧该怎么理解?
A: B 帧在 MPEG-4 中有四种参考模式, 如果是同时参考前后的画面压缩, 则记录的是 和 (前画面 pixel 值 + 后画面 pixel 值)/2 的差值,也就是 和 「前后画面的平均」的差值。所以记录的差值个数和 P 帧一样,只有一个,没有增加。而因为 B 帧位于前后画面的中间,以「前后画面的平均」,也就是「前后画面的中间值」来作为预测数值(预测 B 帧的 pixel 数值为多少?如果有误差,再记录差值),这样这个预测数值会比单独使用前一个画面来预测,更接近目前真正的 B 帧的数值,可想而知,如此所需要记录的差值就会很小甚至可以根本不用记录,所以便可以省下很多的 bits,提高压缩率。
除了压缩率以外,B 帧对画质的影响也是有的,因为 B 帧这种参考前后画面的特性,等于有内插(interpolation)的效果,所以可以减少噪讯。
Golomb 用于运动矢量,模式类型,头信息等编码
CAVLC用于残差编码
CABAC都可以
常用的测试序列选择:
Coastguard :为物体的相对运动和镜头移动
flower :为物体的剧烈运动和镜头的快速移动
garphone :为物体的快速转换
foreman :为物体转换和镜头移动
mobile&calendar :为物体的多种运动和镜头移动
为什么帧内预测要用未滤波的图像而不是滤波后的图像呢?
帧内预测只能用滤波前的值,因为帧内预测的时候边界滤波还不能进行,帧内预测所需要的象素点的边界的滤波不能进行,因为需要等到当前宏块解完后才开始,但是你现在就在解当前宏块,所以为了避免预测和滤波的耦合应该分开来单独做,prediction的时候保存一个line buffer就解决问题了
Q:CQM_4IY,CQM_4IC,CQM_4PY,CQM_4PC,CQM_8IY,CQM_8PY的含义?
A:cqm_4iy->INTRA4X4_LUMA,cqm_4ic->INTRA4X4_CHROMA
cqm_4py->INTER4X4_LUMA,cqm_4ic->INTER4X4_CHROMA
cqm_4py->INTER8X8_LUMA,cqm_4ic->INTER8X8_CHROMA
Q:在x264的x264_cqm_init( x264_t *h )函数中:
for( i = 0; i < 16; i++ )
{
h->dequant4_mf[i_list][q][0] = def_dequant4[q] * h->pps->scaling_list[i_list];
h-> quant4_mf[i_list][q][0] = def_quant4[q] * 16 / h->pps->scaling_list[i_list];
}
第二个式子为什么*16?
A:你不要管这个16,这个16是约定成俗的,要和量化,凡量化一直考虑
Q:unquant4_mf[4][52][16]这个矩阵也是量化里面的,你看量化矩阵和反量化矩阵都是4维的,而这个是3维的
A:unquant4_mf[i_list][q],是0~15,是线性排列,quant4_mf[i_list][q%6][0],是[][]矩阵排列
Q:在上面的程序中量化和反量化矩阵为什么第三维只为0呢?
A:为0才对,因为本来定义[4][4],现在要线性访问16个成员,就必须[0]了
Q:关于skip模式的问题
A:When a Skipped macroblock is signalled in the bitstream, no further da ta is sent for that macroblock. The decoder calculates a vector for the skipped macroblock and reconstructs the macroblock using motion-compensated prediction from the first reference picture in list 0.
p_skip 就是说只计算参考帧中的mv,传输的是0数据,直接把参考中的匹配宏块拿过来就行了,skip模式只传送mb_type,其他信息都是从参考桢中获取,在解码端计算MV及恢复残差数据,MV不是从参考帧获得的,是在解码端计算,mv是根据周围的相邻块的mv进行计算,好像是取中间值,有点像MV在运动估计时候的预测,是只传送mb_type,其他信息都可以计算出来,这就是skip。
To have a SKIP mode in H.264, a macroblock should meet following conditions all together [5]:
(i) the best motion compensation block size is 16x16,
(ii) reference frame is just on e previous on e,
(iii) motion vector is (0,0) or the same as its PMV, and(iv) its transform coefficients are all quantized to zero.
(iv) its transform coefficients are all quantized to zero
FrameSkip,该参数是对原始YUV帧丢弃数,就是说每隔一帧(I或者P,不包括B)丢弃FrameSkip帧。
NumberBFrames,就是两个编码帧中间B帧的数目,该数必须小于FrameSkip
FramesToBeEncoded,总共要编码的帧数,不包括B帧.因为在编码过程中 b帧对其他帧并不产生影响,而且在实时编码中,如果负担过重;或带宽有限,可以有选择的丢弃b帧
IntraPeriod,每IntraPeriod帧(I/P帧)有一个I帧编码
如果你选择的frameskip>=1,numberbframes=0,intraperiod>1,序列类型:ipp...ipp...
如果你选择的frameskip>=1,numberbframes=1,intraperiod>1,序列类型:ipbpb...ipbpb...
如果你选择的frameskip>=2,numberbframes=2,intraperiod>1,序列类型:ipbbpbb...ipbbpbb...
P_Skip的特别之处在于码流中不传输MVD数据,预测块的大小肯定史16*16。当下面四个条件满足任意一个时,当前宏块的MV预测值直接置为(0,0),不满足时当作普通P宏块处理
�C mbAddrA is not available
�C mbAddrB is not available
�C refIdxL0A is equal to 0 and both components of mvL0A are equal to 0
�C refIdxL0B is equal to 0 and both components of mvL0B are equal to 0
Q:为何在cavlc编码的时候,第一个负数要加1?
A:如果拖尾小于3,说明第一个level的绝对值值肯定大于1。因此,level为正时,减1;为负时加1。可降低码流
Q:H.264中,术语IDR的意思是什么,有什么用?
A:IDR-instantaneous decoding refresh (IDR)picture;
A coded picture in which all slices are I or SI slices that causes the decoding process to mark all reference pictures as "unused for reference" immediately after decoding the IDR picture. After the decoding of an IDR picture all following coded pictures in decoding order can be decoded without inter prediction from any picture decoded prior to the IDR picture. The first picture of each coded video sequence is an IDR picture.
也就是说,IDR的出现其实是相当于向解码器发出了一个清理reference buffer的信号吧,上面说前于这一帧的所有已编码帧不能为inter做参考帧了。
Q:jm各个版本之间的代码做了些什么改动,有没有说明这些的文档啊?
A:每个版本源代码的根目录下都有一个 change.txt 文件,里面详细记录了所有版本的更新。
针对对象不同,jm90以上全部是针对高保真的视频的。86基本上可以满足一般处理的所有要求。
Q:在VC环境下是如何读入*.yuv序列的?
A:把*.yuv文件当作一般的文件读就可以了。
如下:
#include <stdio.h>
#include <malloc.h>
void main()
{
char *Y;
char *Cb;
char *Cr;
int width = 352, height = 288;
FILE *fp;
FILE *fy;
int i;
Y = (char*)malloc(width*height);
Cb = (char*)malloc(width*height/4);
Cr = (char*)malloc(width*height/4);
fp= fopen("input.yuv","rb");
if(fp == NULL)
printf("open input.yuv failed\n");
fy = fopen("output.yuv", "ab+");
if(fy == NULL)
printf("open output.yuv failed\n");
for(i = 0; i<1; i++)
{
//fseek(fp, i*width*height, 0);
if(0 == fread(Y, width*height, 1, fp))
printf("read error\n");
if(0 == fwrite(Y, width*height, 1, fy))
printf("write error\n");
fread(Cb, width*height/4, 1, fp);
fread(Cr, width*height/4, 1, fp);
fwrite(Cb, width*height/4, 1, fy);
fwrite(Cr, width*height/4, 1, fy);
}
fclose(fp);
fclose(fy);
free(Y);
free(Cb);
free(Cr);
}
Q:H.264中,术语IDR的意思是什么,有什么用?
A:IDR-instantaneous decoding refresh (解码即时刷新IDR)picture;
A coded picture in which all slices are I or SI slices that causes the decoding process to mark all reference pictures as "unused for reference" immediately after decoding the IDR picture. After the decoding of an IDR picture all following coded pictures in decoding order can be decoded without inter prediction from any picture decoded prior to the IDR picture. The first picture of each coded video sequence is an IDR picture.
也就是说,IDR的出现其实是相当于向解码器发出了一个清理reference buffer的信号吧,上面说前于这一帧的所有已编码帧不能为inter做参考帧了。
Q: YCrCb 4:2:0是什么?像4:4:4和4:2:2一样表示 Y:Cr:Cb是4:2:0吗?
A: 4 : 2 :0 means that Cr and Cb each have half the horizontal and vertical resolution of Y, as shown. The term ‘4 : 2 : 0’ is rather confusing: the numbers do not actually have a sensible interpretation and appear to have been chosen historically as a ‘code’ to identify this particular sampling pattern. 有点4:1:1的味道。
Q:CAVLC的过程
A:
编码
4×4的残差块通过Zig-Zag扫描,得到一系列字符,如:0,3,0,1,-1,-1,0,1,0......
由此序列推导出以下变量:TotalCoeffs(全部的非零系数,包括拖尾系数),TotalZeros(最后一个非零系数前面的所有0的个数,方向为从左到右,比如上面的序列中,最后一个非零系数为1),TrailingOnes(托尾系数的个数,并规定不能超过3个),然后通过NC值查表,把
TotalCoeffs ,和TrailingOnes的组合进行编码,称为编码元素coeff_token。接下来,对每个拖尾系数的符合编码,0表示+,1表示负。再接下来,对剩下的非零系数编码(此时拖尾系数已经被编码了,不再包括),编码方向为从右到左,比如上面的序列中,先编码1,再编码3。这些系数被编码后,是由level_prefix和level_suffix两部分组成的。level_prefix的值通过查表得出,level_suffix是由若干个0组成,0的个数由suffixLength决定。再接着对TotalZeros的值编码。然后对RunBefore(每个非零系数前零的个数)进行编码,这个方向也是从右到左,并且最后一个(从左边数的第一个)非零系数前零的个数不需要编码,因为后面的编过后,剩下多少个0只有一个存放位置,就是最前面。
解码
由计算出的bit串长度读出相应的bits,通过查表得到TotalCoeffs和TrailingOnes的值,此时无输出,接着读取拖尾系数的符合,由编码的顺序知,先读到的是最后一个拖尾系数。解码完拖尾系数并依次输出,接下来是剩下的非零系数的值,通过查表解码并输出。然后解码TotalZeros,此时输出不变,仍为以前的解码值。接下来解码RunBefore,因为编码时是从右往左编的,故第一个解码出来的RunBefore应该插到第一个解码出的拖尾系数的前面,即插入的方向也是从右到左,最后一步时,剩下的RunBefore都插入到最前面。