上一篇中我们已经了解如何在Python程序和C模块之间进行值的相互传递,现在我们来进入实作阶段,看看如何将一个C语言开发的开源mp3编解码库LAME包装为一个Python下可以使用的扩展模块。
首先去http://lame.sourceforge.net/download.php下载LAME的源代码,然后切换到root用户编译源代码,
  1. ./configure  
  2. make  
  3. make install 

安装完成后你可以在/usr/local/include/lame目录下找到lame.h头文件,我们在后面的demo程序中会include它的,下面就是一个非常简单的lame示例程序lame_test.c:

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <lame.h>  
  4.  
  5. #define INBUFSIZE 4096  
  6. #define MP3BUFSIZE (int) (1.25 * INBUFSIZE) + 7200  
  7.  
  8. int encode(char* inPath, char* outPath) {  
  9.     int status = 0;  
  10.     lame_global_flags* gfp;  
  11.     int ret_code;  
  12.     FILE* infp;  
  13.     FILE* outfp;  
  14.     short* input_buffer;  
  15.     int input_samples;  
  16.     char* mp3_buffer;  
  17.     int mp3_bytes;  
  18.       
  19.     gfp = lame_init();  
  20.     if (gfp == NULL) {  
  21.         printf("lame_init failed\n");  
  22.         status = -1;  
  23.         goto exit;  
  24.     }  
  25.       
  26.     ret_code = lame_init_params(gfp);  
  27.     if (ret_code < 0) {  
  28.         printf("lame_init_params returned %d\n",ret_code);  
  29.         status = -1;  
  30.         goto close_lame;  
  31.     }  
  32.  
  33.     infp = fopen(inPath, "rb");  
  34.     outfp = fopen(outPath, "wb");  
  35.       
  36.     input_buffer = (short*)malloc(INBUFSIZE*2);  
  37.     mp3_buffer = (char*)malloc(MP3BUFSIZE);  
  38.       
  39.     do{  
  40.         input_samples = fread(input_buffer, 2, INBUFSIZE, infp);  
  41.         mp3_bytes = lame_encode_buffer_interleaved(gfp, input_buffer,input_samples/2, mp3_buffer, MP3BUFSIZE);  
  42.         if (mp3_bytes < 0) {  
  43.             printf("lame_encode_buffer_interleaved returned %d\n", mp3_bytes);  
  44.             status = -1;  
  45.             goto free_buffers;  
  46.         } else if(mp3_bytes > 0) {  
  47.             fwrite(mp3_buffer, 1, mp3_bytes, outfp);  
  48.         }  
  49.     }while (input_samples == INBUFSIZE);  
  50.       
  51.     mp3_bytes = lame_encode_flush(gfp, mp3_buffer, sizeof(mp3_buffer));  
  52.     if (mp3_bytes > 0) {  
  53.         printf("writing %d mp3 bytes\n", mp3_bytes);  
  54.         fwrite(mp3_buffer, 1, mp3_bytes, outfp);  
  55.     }  
  56. free_buffers:  
  57.     free(mp3_buffer);  
  58.     free(input_buffer);  
  59.       
  60.     fclose(outfp);  
  61.     fclose(infp);  
  62. close_lame:  
  63.     lame_close(gfp);  
  64. exit:  
  65.     return status;  
  66. }  
  67.  
  68. int main(int argc, char** argv) {  
  69.     if (argc < 3) {  
  70.         printf("usage: lame_test rawinfile mp3outfile\n");  
  71.     }  
  72.     encode(argv[1], argv[2]);  
  73.     return 0;  

编译步骤:

  1. gcc -I /usr/local/include/lame lame_test.c -lmp3lame -o lame_test 

试验准备:

首先需要一个test.wav文件,先安装sox来将wav文件转为raw格式的数据:

  1. sudo apt-get install sox  
  2. sox test.wav -t raw test.raw 

然后执行lame_test来对其进行mp3编码:

  1. ./lame_test ./test.raw ./test.mp3  

好了,现在我们要在这个c程序的基础上将其包装为一个Python扩展模块。下面的pylame.c就是简单地调用lame_test.c中定义的encode方法,然后通过它对外部的python程序提高mp3编码的服务

  1. #include <Python.h> 
  2. #include <lame.h> 
  3.  
  4. int encode(char* ,char*);  
  5.  
  6. static PyObject * pylame_encode(PyObject* self, PyObject* args) {  
  7.     int status;  
  8.     char* inPath;  
  9.     char* outPath;  
  10.     if (!PyArg_ParseTuple(args, "ss", &inPath, &outPath)) {          
  11.         return NULL;  
  12.     }  
  13.     status = encode(inPath, outPath);  
  14.     return Py_BuildValue("i", status);  
  15. }  
  16.  
  17. static PyMethodDef pylame_methods[] = {  
  18.     {"encode", pylame_encode, METH_VARARGS, NULL},  
  19.     {NULL, NULL, 0, NULL}  
  20. };  
  21.  
  22. PyMODINIT_FUNC initpylame() {  
  23.     Py_InitModule3("pylame", pylame_methods, "an simple lame module.");  

模块编译步骤:

  1. gcc -shared -I /usr/include/python2.6 -I /usr/local/include/lame/ pylame.c lame_test.c -lmp3lame -o pylame.so 

ok,现在lame扩展模块已经封装好了,可以到python程序中进行调用了。在pylame.so所在目录下新建一个python文件lame1.py代码如下:

  1. import pylame  
  2.  
  3. if __name__ == '__main__':  
  4.     inPath = './test.raw' 
  5.     outPath = './test.mp3' 
  6.     pylame.encode(inPath, outPath) 

编译执行: 

  1. python ./lame1.py 

你会发现生成了一个test.mp3,打开听听看是否是你想要的歌曲呢,呵呵。。。