其实是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类型表):
一个大坑:需要注意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