python如何調用C, 如何註冊成C的回調函數(python後臺程序經常使用方法)

實際上是python後臺程序經常使用方法:
C開發完成底層的功能,python直接把C當作python模塊進行調用。html


須要作兩個工做:python

    python能調用C語言的函數;ide

    python經過調用C函數,並註冊python的回調函數,C代碼經過python回調函數告訴Python當前實時進度和狀態;函數

1,python如何調用C語言ui

主要就是應用ctypes這個模塊,too simple too naive。
python代碼是這樣滴:.net

    from ctypes import *
    dynamicLibString = './libcheckVideoFile.so'
    mylib = cdll.LoadLibrary(dynamicLibString)
    ulHandle = mylib.VideoAnalyzeInit(videoFilename)
        if ulHandle == 0:
            print 'VideoAnalyzeInit error.'
            print ''
            
        mylib.EnableBlackDetected(ulHandle)
        mylib.EnablePureColorDetected(ulHandle)
        mylib.EnableFrozenDetected(ulHandle)
     
     
        mylib.EnableMuteVoiceDetected(ulHandle)指針

 

C代碼是這樣滴:code

    unsigned long VideoAnalyzeInit(char* szFilename)
    {
        VideoAnalyzeManage* pManager = new VideoAnalyzeManage(szFilename);
        if(pManager)
        {
            int iRet = pManager->Init();
            if(iRet != 0)
            {
                delete pManager;
                return 0;
            }
        }
        return (unsigned long)pManager;
    }
    void EnableBlackDetected(unsigned long ulHandle)
    {
        VideoAnalyzeManage* pManager = (VideoAnalyzeManage*)ulHandle;
        if(pManager)
        {
            pManager->EnableBlackDetected();
        }
    }htm

 

就像C語言編譯出來的.so庫只是python的一個模塊,直接調用就能夠了。對象


2,python註冊C語言的回調函數
其實也不難,python的函數自己也是python的對象,實現也就簡單了:


python的回調函數:

    def OnPyVideoAnalyzeResultCallback(ulStartTS, ulEndTS, ulDetectedType, ulParam):
        fStartTS = ulStartTS/1000.0
        fEndTS   = ulEndTS/1000.0
        outputString = ''
        
        if ulDetectedType == ALL_BLACK_DETECTED :
            outputString = videoFilename + ': All black color detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'
        elif ulDetectedType == SIMPLE_COLOR_DETECTED :
            outputString = videoFilename + ': All pure color detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'
        elif ulDetectedType == FROZEN_VIDEO_DETECTED :
            outputString = videoFilename + ': Frozen image detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'
        elif ulDetectedType == AUDIO_MUTE_DETECTED :
            outputString = videoFilename + ': Mute voice detected: start(' + str(fStartTS) + ') end(' + str(fEndTS) + ')'
        print outputString
        WriteLog(logFilename, outputString)
     
    def OnPyVideoStateCallback(uiProgress, uiState, ulParam):
        global videoFilename
        outputString = ''
        if uiState == DECODE_START :
            outputString = '\r\n' + videoFilename + ': video analyze is starting......'
            WriteLog(logFilename, outputString)
        elif uiState == DECODE_RUNNING :
            outputString = videoFilename + ': video analyze is running, progress: ' + str(uiProgress) + '%'
        elif uiState == DECODE_END :
            outputString = videoFilename + ': video analyze is ended'
            WriteLog(logFilename, outputString)
        elif uiState == DECODE_ERROR :
            outputString = videoFilename + ': video analyze is error'
            WriteLog(logFilename, outputString)
        print outputString

python 兩個回調函數:OnPyVideoAnalyzeResultCallback和OnPyVideoStateCallback。

如何把這兩個python函數註冊成C代碼的回調函數呢?
python部分是這樣註冊滴:

        CMPRESULTFUNC = CFUNCTYPE(None, c_ulong, c_ulong, c_ulong, c_ulong)
        CMPSTATEFUNC = CFUNCTYPE(None, c_ulong, c_ulong, c_ulong)
     
        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部分是這樣的:

    int VideoAnalyzeStart(unsigned long ulHandle, AnalyzeDetectedCallback resultCallback, AnalyzeStateCallback stateCallback)
    {
        VideoAnalyzeManage* pManager = (VideoAnalyzeManage*)ulHandle;
        if(pManager)
        {
            pManager->SetAnalyzeResultCallback(resultCallback, 0);
            pManager->SetStateNotifyCallback(stateCallback, 0);
            int iRet = pManager->Start();
            return iRet;
        }
        return -1;
    }

C部分不用管。

可是如何肯定python函數參數與C函數參數的對應關係呢?

python函數參數與C函數參數的對應表(其實也能夠叫ctypes類型表):

一個大坑:須要注意CMPRESULTFUNC(OnPyVideoAnalyzeResultCallback)這個指針函數是有本身的生存空間的,若是生存空間已過,會被釋放,C代碼再回調的時候,就會使用一個過時指針。

這裏建議使用一個全局的python指針。

    CMPRESULTFUNC = CFUNCTYPE(c_int, c_ulong, c_ulong, c_ulong, c_ulong)
    CMPSTATEFUNC = CFUNCTYPE(c_int, c_ulong, c_ulong, c_ulong)
     
    pResutFunc = CMPRESULTFUNC(OnPyVideoAnalyzeResultCallback)
    pStateFunc = CMPSTATEFUNC(OnPyVideoStateCallback)
     
     
    def main():
        global pResutFunc
        global pStateFunc
        ....
        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 survive across different callbacks, even when those calls are made from the same C thread. --------------------- 做者:IT荒野獵人 來源:CSDN 原文:https://blog.csdn.net/sweibd/article/details/52679213 版權聲明:本文爲博主原創文章,轉載請附上博文連接!

相關文章
相關標籤/搜索