• 2004-10-07

    求字节平均的高效算法

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://ffmpeg.blogbus.com/logs/429551.html

     因为在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)上体会一下就能明白


    收藏到:Del.icio.us




    评论

  • 花了一些时间把这两个宏都看完了。第一个很快就理解了,第二个则多花了一点时间,
    谈一下自己的认识:
    or操作对于0,0和1,1的情形都是正确的,但是对于0,1 1,0,则多加了1,所以要减去。但是对最末一位,并没有执行这样的操作,保留了or运算的结果,从而达到了饱和的目的
  • 有道理,是我写错了,应该是0xfefefefe,不然算出来就不对了,呵呵,多谢指正
  • 很可能是你写错了,应该是0xfefefefe



    实际上这可以看作两个集合的运算:交集与并集

    round:

    (a|b)得到最大公共部分,当然是多了0|1和1|0的情况

    然后

    (a^b)得到集合的不同部分,与0xfefefefe进行与运算后,得到取整后的结果(公共部分的最小值),移位后两者的差就成了所谓的round的结果了

    对于no_ round同样分析
  • 还有你所说的rounding是不是指求平均后的结果的取整的过程?

    谢谢

  • 还有你所说的rounding是不是指求平均后的结果的取整的过程?

    谢谢

  • 我感到你的分析不对

    为什么(a^b)要与0xFFFFFFF7进行&运算?

    你的ffmpeg的版本是什么时候的?可能太老了,

    现在的代码是这么实现的:

    from dsputil.h

    #define BYTE_VEC32(c) ((c)*0x01010101UL)



    static inline uint32_t rnd_avg32(uint32_t a, uint32_t b)

    {

    return (a | b) - (((a ^ b) & ~BYTE_VEC32(0x01)) >> 1);

    }



    static inline uint32_t no_rnd_avg32(uint32_t a, uint32_t b)

    {

    return (a & b) + (((a ^ b) & ~BYTE_VEC32(0x01)) >> 1);

    }



    谢谢