__all__ = ('MTGenerator', ) include "includes/ff_consts.pxi" include "includes/inline_funcs.pxi" from cpython.ref cimport PyObject cdef extern from "Python.h": void Py_INCREF(PyObject *) void Py_XINCREF(PyObject *) void Py_DECREF(PyObject *) ctypedef int (*int_cls_method)(void *) nogil import traceback cdef int sdl_initialized = 0 def initialize_sdl(): '''Initializes sdl. Must be called before anything can be used. It is automatically called by the modules that use SDL. ''' global sdl_initialized if sdl_initialized: return if SDL_Init(0): raise ValueError('Could not initialize SDL - %s' % SDL_GetError()) sdl_initialized = 1 initialize_sdl() cdef class MTMutex(object): def __cinit__(MTMutex self, MT_lib lib): self.lib = lib self.mutex = NULL if lib == SDL_MT: self.mutex = SDL_CreateMutex() if self.mutex == NULL: raise Exception('Cannot create mutex.') elif lib == Py_MT: import threading mutex = threading.Lock() self.mutex = mutex Py_INCREF(self.mutex) def __dealloc__(MTMutex self): if self.lib == SDL_MT: if self.mutex != NULL: SDL_DestroyMutex(self.mutex) elif self.lib == Py_MT: Py_DECREF(self.mutex) cdef int lock(MTMutex self) nogil except 2: if self.lib == SDL_MT: return SDL_mutexP(self.mutex) elif self.lib == Py_MT: return self._lock_py() cdef int _lock_py(MTMutex self) nogil except 2: with gil: return not (self.mutex).acquire() cdef int unlock(MTMutex self) nogil except 2: if self.lib == SDL_MT: return SDL_mutexV(self.mutex) elif self.lib == Py_MT: return self._unlock_py() cdef int _unlock_py(MTMutex self) nogil except 2: with gil: (self.mutex).release() return 0 cdef class MTCond(object): def __cinit__(MTCond self, MT_lib lib): self.lib = lib self.mutex = MTMutex.__new__(MTMutex, lib) self.cond = NULL if self.lib == SDL_MT: self.cond = SDL_CreateCond() if self.cond == NULL: raise Exception('Cannot create condition.') elif self.lib == Py_MT: import threading cond = threading.Condition(self.mutex.mutex) self.cond = cond Py_INCREF(self.cond) def __dealloc__(MTCond self): if self.lib == SDL_MT: if self.cond != NULL: SDL_DestroyCond(self.cond) elif self.lib == Py_MT: Py_DECREF(self.cond) cdef int lock(MTCond self) nogil except 2: self.mutex.lock() cdef int unlock(MTCond self) nogil except 2: self.mutex.unlock() cdef int cond_signal(MTCond self) nogil except 2: if self.lib == SDL_MT: return SDL_CondSignal(self.cond) elif self.lib == Py_MT: return self._cond_signal_py() cdef int _cond_signal_py(MTCond self) nogil except 2: with gil: (self.cond).notify() return 0 cdef int cond_wait(MTCond self) nogil except 2: if self.lib == SDL_MT: return SDL_CondWait(self.cond, self.mutex.mutex) elif self.lib == Py_MT: return self._cond_wait_py() cdef int _cond_wait_py(MTCond self) nogil except 2: with gil: (self.cond).wait() return 0 cdef int cond_wait_timeout(MTCond self, uint32_t val) nogil except 2: if self.lib == SDL_MT: return SDL_CondWaitTimeout(self.cond, self.mutex.mutex, val) elif self.lib == Py_MT: return self._cond_wait_timeout_py(val) cdef int _cond_wait_timeout_py(MTCond self, uint32_t val) nogil except 2: with gil: (self.cond).wait(val / 1000.) return 0 def enterance_func(target_func, target_arg): return (target_func)(target_arg) cdef class MTThread(object): def __cinit__(MTThread self, MT_lib lib): self.lib = lib self.thread = NULL def __dealloc__(MTThread self): if self.lib == Py_MT and self.thread != NULL: Py_DECREF(self.thread) cdef int create_thread(MTThread self, int_void_func func, const char *thread_name, void *arg) nogil except 2: if self.lib == SDL_MT: with gil: self.thread = SDL_CreateThread(func, thread_name, arg) if self.thread == NULL: raise Exception('Cannot create thread.') elif self.lib == Py_MT: with gil: import threading thread = threading.Thread(group=None, target=enterance_func, name=None, args=(func, arg), kwargs={}) self.thread = thread Py_INCREF(self.thread) thread.start() return 0 cdef int wait_thread(MTThread self, int *status) nogil except 2: if self.lib == SDL_MT: if self.thread != NULL: SDL_WaitThread(self.thread, status) elif self.lib == Py_MT: with gil: (self.thread).join() if status != NULL: status[0] = 0 return 0 cdef int_cls_method mutex_lock = MTMutex.lock cdef int_cls_method mutex_release = MTMutex.unlock cdef int _SDL_lockmgr_py(void ** mtx, int op) with gil: cdef bytes msg cdef int res = 1 cdef MTMutex mutex try: if op == FF_LOCK_CREATE: mutex = MTMutex.__new__(MTMutex, SDL_MT) Py_INCREF(mutex) mtx[0] = mutex res = 0 elif op == FF_LOCK_DESTROY: if mtx[0] != NULL: Py_DECREF(mtx[0]) res = 0 except: msg = traceback.format_exc().encode('utf8') av_log(NULL, AV_LOG_ERROR, '%s', msg) return res cdef int SDL_lockmgr(void ** mtx, int op) nogil: if op == FF_LOCK_OBTAIN: return not not mutex_lock(mtx[0]) elif op == FF_LOCK_RELEASE: return not not mutex_release(mtx[0]) else: return _SDL_lockmgr_py(mtx, op) cdef int Py_lockmgr(void ** mtx, int op) with gil: cdef int res = 1 cdef bytes msg cdef MTMutex mutex try: if op == FF_LOCK_CREATE: mutex = MTMutex.__new__(MTMutex, Py_MT) Py_INCREF(mutex) mtx[0] = mutex res = 0 elif op == FF_LOCK_OBTAIN: mutex = mtx[0] res = not not mutex.lock() # force it to 0, or 1 elif op == FF_LOCK_RELEASE: mutex = mtx[0] res = not not mutex.unlock() elif op == FF_LOCK_DESTROY: if mtx[0] != NULL: Py_DECREF(mtx[0]) res = 0 except: msg = traceback.format_exc().encode('utf8') av_log(NULL, AV_LOG_ERROR, '%s', msg) res = 1 return res cdef lockmgr_func get_lib_lockmgr(MT_lib lib) nogil: if lib == SDL_MT: return SDL_lockmgr elif lib == Py_MT: return Py_lockmgr cdef class MTGenerator(object): def __cinit__(MTGenerator self, MT_lib mt_src, **kwargs): self.mt_src = mt_src cdef int delay(MTGenerator self, int delay) nogil except 2: if self.mt_src == SDL_MT: SDL_Delay(delay) elif self.mt_src == Py_MT: with gil: import time time.sleep(delay / 1000.) return 0 cdef lockmgr_func get_lockmgr(MTGenerator self) nogil: return get_lib_lockmgr(self.mt_src)