direct x264编译中16字节对齐修改

先说说x264,x264是实现H264编码的最实用开源码,目前在官网http://www.videolan.org/developers/x264.html上可供下载,不过由于源码在linux上进行开发,因此down下的代码并不能直接在VS2010上进行编译调试,这给很多windows用户的开发者带来了不少的麻烦和工作量。不过庆幸的是,sourceforge上有大牛已经帮你解决了大部分windows移植的问题,具体代码大家可以用svn到http://sourceforge.net/p/direct264/code/HEAD/tree/网站下载其中的x264代码。

下载完之后,在\direct264-code-424\x264\build\win32目录下即可找到基于Visual Studio的解决方案文件,这里有基于VS2008和VS2010两种,大家可以根据自己的VS版本打开相应的solution,这里我主要针对x264_vs2010.sln来说明以下问题。

打开x264_vs2010.sln文件之后,只需少量改动即可实现编译,这里的少量改动对于一个有C/C++基础的人来说应该都没有问题的,就是C和C++之间关于变量申明的不同,所以此处略去。然后,大家可以上http://media.xiph.org/video/derf/网站下载几个y4m素材进行编码测试,把x264项目设置为启动项目,在项目属性->配置属性->调试->命令参数中填入“-o bowing_cif.264 bowing_cif.y4m”,其中bowing_cif.y4m为我下载的测试素材,然后应用确定,F5跑起来,然后。。。大家可以看到崩了。。。

这是什么问题呢?我们找到crash的函数,笔者第一次crash的地方指向x264_frame_deblock_row()中的FILTER( _intra, 0, 0, qp_left, qpc_left );语句,我们退出程序后在FILTER( _intra, 0, 0, qp_left, qpc_left );语句旁打上断点后重新运行,停止在断点处后单步进入,我们发现最后程序是在函数deblock_edge_intra()中的pf_intra( pix, i_stride, alpha, beta );语句处崩的。再次退出程序,并在pf_intra( pix, i_stride, alpha, beta );语句旁打上断点,再次F5至此语句处,然后ALT+8进入反汇编,我们用F11单步进入函数并单步执行,会发现最后我们其实进入了一个名为_x264_deblock_h_luma_intra_sse2的汇编函数中,继续执行,我们又发现了,其实最后程序是在执行汇编语言movdqa xmm0,xmmword ptr [esi+ecx*2]时崩掉的,这样我们终于找到了真正引起crash的地方。顺便提一下,其实我们一开始就可以从VS2010启动调试崩掉时的堆栈窗口发现具体的crash地方,只要打开反汇编,在堆栈中最后一个名称上双击即能发现程序停在了那条汇编语句处。

找到这条汇编语句是罪魁祸首之后,我就该分析这条语句为什么会导致程序crash掉了。这是因为我们程序默认启用了汇编优化,可以通过HAVE_MMX等来屏蔽这个功能。我们可以通过查阅intel汇编手册知道,movdqa xmm0,xmmword ptr [esi+ecx*2]这条语句是要把esi+ecx*2地址中的值放到xmm0寄存器中的,那什么是XMM0寄存器?这个就要讲到intel硬件的发展史了,因为要讲的内容很多,所以就简单提一下了。XMM0寄存器其实在SSE指令中经常用到的指令,它是一个128bits的寄存器,使用SSE指令可以加快数据的存取和运算,使Intel计算的效率大幅提升(具体的大家可以查阅相关资料了)。不过SSE指令有个要求,使用SSE指令的地址必须是16位对齐的!!!这就是问题所在了,也就是说esi+ecx*2的值需要是16的整数倍,那我们刚刚调试的地方是不是呢?我们可以从寄存器中得到ESI和ECX的十六进制值,我们都转化成十进制并计算esi+ecx*2的结果,然后除以16,我们就会发现果然不能整除,现在我们终于就找到问题的根源了!!!

知道问题所在,接下来我们就需要修改问题点了,那如何修改?关键是要保证16位对齐,也就是说我们需要在函数被调用之前保证传入的参数都是16字节对齐的就行。现在说一下本人的方法:

1、先插入一个头文件vs_align.h,如下图1所示:


图1

2、根据我们后面会碰到的所有崩的地方,我们可以申明几个函数,如图2所示


图2

3、接下来我们需要为我们的函数定义,先插入一个vs_align.asm文件,文件中分别为头文件中的各函数定义,这里举其中一个函数为例,如图3所示


图3

主要的过程是,先保存好ebp,然后将esp的地址保存到ebp中,因为后面esp地址会变化,然后在栈上开辟一个16字节大小的空间,为什么是16字节?因为我们这里是4个参数,每个参数占4字节,所以其他参数个数的话就依次类推了。然后将esp地址和~15做与运算,使新开辟的空间保证16字节对齐,再然后就是把下一步要调用的函数名及4个参数分别转移到ecx和新对齐的地址中了,然后调用ecx即调用下一步的函数并恢复堆栈原来的值,这样就完成了地址对齐任务。

4、最后,需要在原来崩掉的外围函数处,增加我们的对齐函数,如图4所示


图4

其他会发生crash的地方也就依葫芦画瓢了,修改完所有的crash之后,就可以正式启用汇编优化的部分了,大家可以分别在项目命令行中用“-o bowing_cif.264 bowing_cif.y4m”和“-o bowing_cif.264 bowing_cif.y4m --no-asm”来对比启用汇编优化和不启用汇编优化的编码速度差距。

搞定了,大家好好享受x264编码吧。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值