Skip to content

Instantly share code, notes, and snippets.

@jpzhu
Last active August 29, 2015 14:04
Show Gist options
  • Save jpzhu/4d4fe6d5165c3d5c8e59 to your computer and use it in GitHub Desktop.
Save jpzhu/4d4fe6d5165c3d5c8e59 to your computer and use it in GitHub Desktop.
multimedia

饱和算法

在视频解码算法里会经常出现需要做饱和处理的,也就说在dct变换后数据会出现大于255,或者小于0的数据。 此时需要将数据进行截断,小于0的让等于0,大于255的变回255。通常源码是这样的

if(ra>255) {
    ra = 255;
}
else if(ra<0) {
    ra = 0;
}

优化后的代码

而在一些专业的代码里我们会看到这样的语句。

if((unsigned)ra<255){
}else{
    if(ra>255) {
        ra = 255;
    }
    else if(ra<0) {
        ra = 0;
    }
}

貌似运算变复杂了,其实从概率上来说数据落在0-255之间的概率要比在之外的概率大的多,所以通常都只需一次比较,就可以结束。总的运算量反而变少。

因为在mpeg的解码过程中,在当前帧是B帧的情况下,如果同时用到了前向和后向预测的话,那么就会要用到前一帧和后一帧对应位置上的值作平均后才做运动补偿。
对于没有SIMD指令的处理器来说,那么像象素值这样的8比特数据只能一个字节一个字节的做运算了?对于32位的处理器来说,岂不是要浪费掉24(or 23)比特?
今天在ffmpeg的代码里看到两个宏,就很好的解决了这个问题,一下子可以算4个字节。
#define avg_nornd(a,b) (a&b)+(((a^b)&0xFEFEFEFE)>>1)
#define avg_rnd(a,b) ( a|b)- (((a^b)&0xFEFEFEFE)>>1)
第一个是不带rounding的,第二个带rounding的,算法原理乃是这样
1.不带rouding的那个,后面的异或运算,其实是加法的一种表示,但是1^1的这种情况有进行进位,却没有给进上,a&b的运算正是将丢掉的进位位给补足
2.带rouding的那个,则是先假设除了0加0之外的运算都产生了进位,明显0和1相加是不应该有进位的,应该去掉,后面的那个减a^b正是做这个工作的
至于两个rounding的区别,稍微在最后一位(bit24,bit26,bit8,bit0)上体会一下就能明白
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment