经过一周半的努力,终于从ffmpeg中提取了一个包含asf解析功能和wmapro解码功能,并能在VC2005上运行的工程,当然现在还很简陋,呵呵。
这个是我第一次从ffmpeg中提取解码器模块,ffmpeg是个相当大的工程,这给提取工作带来了很大的麻烦,更大的麻烦其实在于ffmpeg遵循了C99的标准,而VC不支持。以前没怎么接触C99,经过这次移植对它稍稍了解了一下,也许是我C的水平不够,我感觉有些规定像是败笔,引用国外牛人的话就是——“stop adding shits to C”。
总之,不论C99给C语言带来了什么影响,它给我的提取移植工作带来了很多的麻烦。
谈谈我的提取经验吧:
1. 首先,是确定你的解码器依赖哪些文件。
理论上讲,要知道依赖的文件,最好是将源代码过一遍,建立一个测试工程,将找出来的那些文件添加进去,编译,看看有没有缺失函数的错误,再寻找缺失的文件,一直这样做下去,直至测试通过。
但ffmpeg是个很大的工程,内部的依赖关系很复杂,用上面的方法,估计即使能成功,耗时也肯定很多。当初我浏览了一遍ffmpeg的源码,搞清楚大体架构之后,我觉得上面的方法对于第一次使用ffmpeg的我来说,可能还不如直接看懂解码器原理,然后自己写一个来得快。
当我苦苦的啃代码的时候,别人教给了我一个简便的方法——就是使用ffmpeg自己的configure命令来定制编解码器,然后通过生成的.o文件来判断需要的.c文件。这是一个很快也很保险的方法,于是我定制了一个只包含asf解析、wmapro解码、pcm_s16le编码和wav封装的ffmpeg工程,其他没用的都disable掉。试了几次,直至测试解码通过,然后根据生成的.o文件轻易的就确定了相关的.c源文件,当然,为了得到一个clean的针对wmapro解码的工程,还有很多冗余代码要删除,不过相对于原来面对整个ffmpeg工程来说是简单多了。
还有最好使用libavcodec和libavformat库里面的API自己写一个main函数,这样不仅可以加深对ffmpeg架构和解码流程的理解,还能大大提高删减工作的效率。
2. 然后,就是向VC 2005移植了。
为什么要移植到VC呢?一是我想做一个兼容VC、Linux和VDSP的工程,以后的定点和优化工作就能很便利。还有最好在VC 2005以上的版本,VC 6会遇到额外的问题。
将源文件添加到VC的工程中,编译会遇到很多问题。
C99相关:
01. 首先很多问题是关于stdint.h和inttypes.h,在gcc的标准库中找到这两个文件,对照它们的对使用了的类型进行相应的定义即可。注意64位数据的定义VC上为__int64。
02. 还有就是结构体全局变量初始化,C99中支持比较灵活的初始化方式,改成C89的方式就行。
03. C99的数组初始化大小可以是变量,改为动态内存分配malloc。
04. 数字后缀,如”ll”之类,我感觉作用和原来的强制类型转换差不多,如100ll等价于(int64_t)100。
05. 宏可以带变元,在宏定义中用省略号(...)表示。内部预处理标识符__VA_ARGS__决定变元将在何处得到替换。例:#define MySum(...) sum(__VA_ARGS__),没想到替换方法,程序中用到的地方就av_log和dprintf两个信息输出函数,可以去掉。
平台相关:
01. 关于inline关键字,VC中对应__inline,snprintf函数,VC中对应_snprintf。
02. 使用了strings.h文件中的一些函数,如strcasecmp()函数,VC没有此头文件和相应函数,得自己添加。Google了一下,解决方法如下:
int strcasecmp(char *s1, char *s2) { while (toupper((unsigned char)*s1) == toupper((unsigned char)*s2++)) if (*s1++ == '/0') return 0; return(toupper((unsigned char)*s1) - toupper((unsigned char)*--s2)); }
int strncasecmp(char *s1, char *s2, register int n) { while (--n >= 0 && toupper((unsigned char)*s1) == toupper((unsigned char)*s2++)) if (*s1++ == '/0') return 0; return(n < 0 ? 0 : toupper((unsigned char)*s1) - toupper((unsigned char)*--s2)); } |
03. 字节对齐设置
GCC:
struct unaligned_64 { uint64_t l; } __attribute__((packed)); |
VC:
#ifdef WIN32 #pragma pack(1) #endif struct unaligned_16 { uint16_t l; }; #ifdef WIN32 #pragma pack() #endif |
大概就这些了,具体的C89和C99的标准可以参见这几篇文章。
http://www.kuro5hin.org/?op=displaystory;sid=2001/2/23/194544/139
http://blog.csdn.net/ustcgy/archive/2009/12/17/5024944.aspx
http://blog.csdn.net/phlexii/archive/2006/06/30/855263.aspx