其实是python后台程序常用方法:

C开发完成底层的功能,python直接把C当做python模块进行调用。

需要做两个工作:

python能调用C语言的函数;python通过调用C函数,并注册python的回调函数,C代码通过python回调函数告诉Python当前实时进度和状态;

1,python如何调用C语言

主要就是应用ctypes这个模块,too simple too naive。

python代码是这样滴:



[python]  
1. from ctypes import *  
2. dynamicLibString = './libcheckVideoFile.so'  
3. mylib = cdll.LoadLibrary(dynamicLibString)  
4. ulHandle = mylib.VideoAnalyzeInit(videoFilename)  
5. if ulHandle == 0:  
6. print 'VideoAnalyzeInit error.'  
7. print ''  
8.           
9.     mylib.EnableBlackDetected(ulHandle)  
10.     mylib.EnablePureColorDetected(ulHandle)  
11.     mylib.EnableFrozenDetected(ulHandle)  
12.   
13.   
14.     mylib.EnableMuteVoiceDetected(ulHandle)

C代码是这样滴:


[cpp]  
1. unsigned long VideoAnalyzeInit(char* szFilename)  
2. {  
3. new VideoAnalyzeManage(szFilename);  
4. if(pManager)  
5.     {  
6. int iRet = pManager->Init();  
7. if(iRet != 0)  
8.         {  
9. delete pManager;  
10. return 0;  
11.         }  
12.     }  
13. return (unsigned long)pManager;  
14. }  
15. void EnableBlackDetected(unsigned long ulHandle)  
16. {  
17.     VideoAnalyzeManage* pManager = (VideoAnalyzeManage*)ulHandle;  
18. if(pManager)  
19.     {  
20.         pManager->EnableBlackDetected();  
21.     }  
22. }


就像C语言编译出来的.so库只是python的一个模块,直接调用就可以了。

2,python注册C语言的回调函数


其实也不难,python的函数本身也是python的对象,实现也就简单了:

python的回调函数:


[python]  
  
 
1. def OnPyVideoAnalyzeResultCallback(ulStartTS, ulEndTS, ulDetectedType, ulParam):  
2. 1000.0  
3. 1000.0  
4. ''  
5.       
6. if ulDetectedType == ALL_BLACK_DETECTED :  
7. ': All black color detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'  
8. elif ulDetectedType == SIMPLE_COLOR_DETECTED :  
9. ': All pure color detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'  
10. elif ulDetectedType == FROZEN_VIDEO_DETECTED :  
11. ': Frozen image detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'  
12. elif ulDetectedType == AUDIO_MUTE_DETECTED :  
13. ': Mute voice detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'  
14. print outputString  
15.     WriteLog(logFilename, outputString)  
16.   
17. def OnPyVideoStateCallback(uiProgress, uiState, ulParam):  
18. global videoFilename  
19. ''  
20. if uiState == DECODE_START :  
21. '\r\n' + videoFilename + ': video analyze is starting......'  
22.         WriteLog(logFilename, outputString)  
23. elif uiState == DECODE_RUNNING :  
24. ': video analyze is running, progress: ' + str(uiProgress) + '%'  
25. elif uiState == DECODE_END :  
26. ': video analyze is ended'  
27.         WriteLog(logFilename, outputString)  
28. elif uiState == DECODE_ERROR :  
29. ': video analyze is error'  
30.         WriteLog(logFilename, outputString)  
31. print outputString


python 两个回调函数:OnPyVideoAnalyzeResultCallback和OnPyVideoStateCallback。

如何把这两个python函数注册成C代码的回调函数呢?

python部分是这样注册滴:


[python]
  
  
1. CMPRESULTFUNC = CFUNCTYPE(None, c_ulong, c_ulong, c_ulong, c_ulong)  
2. CMPSTATEFUNC = CFUNCTYPE(None, c_ulong, c_ulong, c_ulong)  
3.   
4. iRet = mylib.VideoAnalyzeStart(ulHandle, CMPRESULTFUNC(OnPyVideoAnalyzeResultCallback), CMPSTATEFUNC(OnPyVideoStateCallback))


应用这个来设置:CFUNCTYPE


第一个参数是python回调函数的返回值,如果没有就是None。

第二个及其以后的就是python回调函数的参数类型了。

CMPRESULTFUNC = CFUNCTYPE(None, c_ulong, c_ulong, c_ulong, c_ulong)//创建一个c函数类型的对象工厂,该函数返回值为None,有三个入参,都为unsigned long。

CMPRESULTFUNC(OnPyVideoAnalyzeResultCallback)根据Python可调用对象生成函数。


mylib.VideoAnalyzeStart(ulHandle, CMPRESULTFUNC(OnPyVideoAnalyzeResultCallback), CMPSTATEFUNC(OnPyVideoStateCallback))//设置回调函数

C部分是这样的:


[cpp]  
    
1. int VideoAnalyzeStart(unsigned long ulHandle, AnalyzeDetectedCallback resultCallback, AnalyzeStateCallback stateCallback)  
2. {  
3.     VideoAnalyzeManage* pManager = (VideoAnalyzeManage*)ulHandle;  
4. if(pManager)  
5.     {  
6.         pManager->SetAnalyzeResultCallback(resultCallback, 0);  
7.         pManager->SetStateNotifyCallback(stateCallback, 0);  
8. int iRet = pManager->Start();  
9. return iRet;  
10.     }  
11. return -1;  
12. }


C部分不用管。

但是如何确定python函数参数与C函数参数的对应关系呢?

python函数参数与C函数参数的对应表(其实也可以叫ctypes类型表):


python执行c 程序 python如何调用c程序_python


一个大坑:需要注意CMPRESULTFUNC(OnPyVideoAnalyzeResultCallback)这个指针函数是有自己的生存空间的,如果生存空间已过,会被释放,C代码再回调的时候,就会使用一个过期指针。

这里建议使用一个全局的python指针。


[python]  
    
1. CMPRESULTFUNC = CFUNCTYPE(c_int, c_ulong, c_ulong, c_ulong, c_ulong)  
2. CMPSTATEFUNC = CFUNCTYPE(c_int, c_ulong, c_ulong, c_ulong)  
3.   
4. pResutFunc = CMPRESULTFUNC(OnPyVideoAnalyzeResultCallback)  
5. pStateFunc = CMPSTATEFUNC(OnPyVideoStateCallback)  
6.   
7.   
8. def main():  
9. global pResutFunc  
10. global pStateFunc  
11.     ....  
12.     iRet = mylib.VideoAnalyzeStart(ulHandle, pResutFunc, pStateFunc)


见官网的解释: https://docs.python.org/3/library/ctypes.html#ctypes.c_long



Note


     

Make sure you keep references to CFUNCTYPE() objects as long as they are used from C code. ctypes doesn’t, and if you don’t, they may be garbage collected, crashing your program when a callback is made.



Also, note that if the callback function is called in a thread created outside of Python’s control (e.g. by the foreign code that calls the callback), ctypes creates a new dummy Python thread on every invocation. This behavior is correct for most purposes, but it means that values stored with threading.local will not