diff --git a/av/opaque.py b/av/opaque.py new file mode 100644 index 000000000..7d295699a --- /dev/null +++ b/av/opaque.py @@ -0,0 +1,63 @@ +# type:ignore +import cython +import cython.cimports.libav as lib +from cython import NULL, sizeof +from cython.cimports.libc.stdint import uint8_t, uintptr_t +from cython.cimports.libc.string import memcpy + +u8ptr = cython.typedef(cython.pointer[uint8_t]) + + +@cython.cfunc +@cython.exceptval(check=False) +@cython.nogil +def noop_free(opaque: cython.p_void, data: u8ptr) -> cython.void: + pass + + +@cython.cfunc +@cython.exceptval(check=False) +@cython.nogil +def key_free(opaque: cython.p_void, data: u8ptr) -> cython.void: + name: cython.p_char = cython.cast(cython.p_char, data) + with cython.gil: + opaque_container.pop(name) + + +@cython.cclass +class OpaqueContainer: + def __cinit__(self): + self._objects = {} + + @cython.cfunc + def add(self, v: object) -> cython.pointer[lib.AVBufferRef]: + # Use object's memory address as key + key: uintptr_t = cython.cast(cython.longlong, id(v)) + self._objects[key] = v + + data: u8ptr = cython.cast(u8ptr, lib.av_malloc(sizeof(uintptr_t))) + if data == NULL: + raise MemoryError("Failed to allocate memory for key") + + memcpy(data, cython.address(key), sizeof(uintptr_t)) + + # Create the buffer with our free callback + buffer_ref: cython.pointer[lib.AVBufferRef] = lib.av_buffer_create( + data, sizeof(uintptr_t), key_free, NULL, 0 + ) + + if buffer_ref == NULL: + raise MemoryError("Failed to create AVBufferRef") + + return buffer_ref + + def get(self, name) -> object: + key: uintptr_t = cython.cast(cython.pointer[uintptr_t], name)[0] + return self._objects.get(key) + + def pop(self, name) -> object: + key: uintptr_t = cython.cast(cython.pointer[uintptr_t], name)[0] + return self._objects.pop(key, None) + + +opaque_container: OpaqueContainer = OpaqueContainer() diff --git a/av/opaque.pyx b/av/opaque.pyx deleted file mode 100644 index 583ea5577..000000000 --- a/av/opaque.pyx +++ /dev/null @@ -1,50 +0,0 @@ -cimport libav as lib -from libc.stdint cimport uint8_t, uintptr_t -from libc.string cimport memcpy - - -cdef void noop_free(void *opaque, uint8_t *data) noexcept nogil: - pass - - -cdef void key_free(void *opaque, uint8_t *data) noexcept nogil: - cdef char *name = data - with gil: - opaque_container.pop(name) - - -cdef class OpaqueContainer: - def __cinit__(self): - self._objects = {} - - cdef lib.AVBufferRef *add(self, object v): - # Use object's memory address as key - cdef uintptr_t key = id(v) - self._objects[key] = v - - cdef uint8_t *data = lib.av_malloc(sizeof(uintptr_t)) - if data == NULL: - raise MemoryError("Failed to allocate memory for key") - - memcpy(data, &key, sizeof(uintptr_t)) - - # Create the buffer with our free callback - cdef lib.AVBufferRef *buffer_ref = lib.av_buffer_create( - data, sizeof(uintptr_t), key_free, NULL, 0 - ) - - if buffer_ref == NULL: - raise MemoryError("Failed to create AVBufferRef") - - return buffer_ref - - cdef object get(self, char *name): - cdef uintptr_t key = (name)[0] - return self._objects.get(key) - - cdef object pop(self, char *name): - cdef uintptr_t key = (name)[0] - return self._objects.pop(key, None) - - -cdef OpaqueContainer opaque_container = OpaqueContainer()