diff --git a/av/opaque.pxd b/av/opaque.pxd index 808f6338e..5a0a423e3 100644 --- a/av/opaque.pxd +++ b/av/opaque.pxd @@ -7,7 +7,6 @@ cdef void noop_free(void *opaque, uint8_t *data) noexcept nogil cdef class OpaqueContainer: cdef dict _objects - cdef lib.AVBufferRef *add(self, object v) cdef object get(self, char *name) cdef object pop(self, char *name) diff --git a/av/option.pxd b/av/option.pxd index 9087b811c..4c8eaffbf 100644 --- a/av/option.pxd +++ b/av/option.pxd @@ -2,20 +2,13 @@ cimport libav as lib cdef class BaseOption: - cdef const lib.AVOption *ptr - cdef class Option(BaseOption): - cdef readonly tuple choices - cdef class OptionChoice(BaseOption): - cdef readonly bint is_default - cdef Option wrap_option(tuple choices, const lib.AVOption *ptr) - cdef OptionChoice wrap_option_choice(const lib.AVOption *ptr, bint is_default) diff --git a/av/option.pyx b/av/option.py similarity index 68% rename from av/option.pyx rename to av/option.py index 604d81a53..6a20af14f 100644 --- a/av/option.pyx +++ b/av/option.py @@ -1,24 +1,27 @@ -cimport libav as lib -from libc.stdint cimport uint64_t - from enum import Enum, Flag +import cython +import cython.cimports.libav as lib +from cython import NULL, bint +from cython.cimports.libc.stdint import uint64_t + +_cinit_sentinel = cython.declare(object, object()) -cdef object _cinit_sentinel = object() -cdef Option wrap_option(tuple choices, const lib.AVOption *ptr): +@cython.cfunc +def wrap_option( + choices: tuple, ptr: cython.pointer[cython.const[lib.AVOption]] +) -> Option: if ptr == NULL: return None - cdef Option obj = Option(_cinit_sentinel) + obj: Option = Option(_cinit_sentinel) obj.ptr = ptr obj.choices = choices return obj -cdef flag_in_bitfield(uint64_t bitfield, uint64_t flag): - # Not every flag exists in every version of FFMpeg, so we define them to 0. - if not flag: - return None +@cython.cfunc +def flag_in_bitfield(bitfield: uint64_t, flag: uint64_t) -> bool: return bool(bitfield & flag) @@ -43,16 +46,6 @@ class OptionType(Enum): CHANNEL_LAYOUT = lib.AV_OPT_TYPE_CHLAYOUT BOOL = lib.AV_OPT_TYPE_BOOL -cdef tuple _INT_TYPES = ( - lib.AV_OPT_TYPE_FLAGS, - lib.AV_OPT_TYPE_INT, - lib.AV_OPT_TYPE_INT64, - lib.AV_OPT_TYPE_PIXEL_FMT, - lib.AV_OPT_TYPE_SAMPLE_FMT, - lib.AV_OPT_TYPE_DURATION, - lib.AV_OPT_TYPE_CHLAYOUT, - lib.AV_OPT_TYPE_BOOL, -) class OptionFlags(Flag): ENCODING_PARAM = lib.AV_OPT_FLAG_ENCODING_PARAM @@ -65,7 +58,23 @@ class OptionFlags(Flag): FILTERING_PARAM = lib.AV_OPT_FLAG_FILTERING_PARAM -cdef class BaseOption: +_INT_TYPES = cython.declare( + tuple, + ( + lib.AV_OPT_TYPE_FLAGS, + lib.AV_OPT_TYPE_INT, + lib.AV_OPT_TYPE_INT64, + lib.AV_OPT_TYPE_PIXEL_FMT, + lib.AV_OPT_TYPE_SAMPLE_FMT, + lib.AV_OPT_TYPE_DURATION, + lib.AV_OPT_TYPE_CHLAYOUT, + lib.AV_OPT_TYPE_BOOL, + ), +) + + +@cython.cclass +class BaseOption: def __cinit__(self, sentinel): if sentinel is not _cinit_sentinel: raise RuntimeError(f"Cannot construct av.{self.__class__.__name__}") @@ -82,34 +91,41 @@ def help(self): def flags(self): return self.ptr.flags - # Option flags @property def is_encoding_param(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_ENCODING_PARAM) + @property def is_decoding_param(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_DECODING_PARAM) + @property def is_audio_param(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_AUDIO_PARAM) + @property def is_video_param(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_VIDEO_PARAM) + @property def is_subtitle_param(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_SUBTITLE_PARAM) + @property def is_export(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_EXPORT) + @property def is_readonly(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_READONLY) + @property def is_filtering_param(self): return flag_in_bitfield(self.ptr.flags, lib.AV_OPT_FLAG_FILTERING_PARAM) -cdef class Option(BaseOption): +@cython.cclass +class Option(BaseOption): @property def type(self): return OptionType(self.ptr.type) @@ -126,45 +142,52 @@ def offset(self): def default(self): if self.ptr.type in _INT_TYPES: return self.ptr.default_val.i64 - if self.ptr.type in (lib.AV_OPT_TYPE_DOUBLE, lib.AV_OPT_TYPE_FLOAT, - lib.AV_OPT_TYPE_RATIONAL): + if self.ptr.type in ( + lib.AV_OPT_TYPE_DOUBLE, + lib.AV_OPT_TYPE_FLOAT, + lib.AV_OPT_TYPE_RATIONAL, + ): return self.ptr.default_val.dbl - if self.ptr.type in (lib.AV_OPT_TYPE_STRING, lib.AV_OPT_TYPE_BINARY, - lib.AV_OPT_TYPE_IMAGE_SIZE, lib.AV_OPT_TYPE_VIDEO_RATE, - lib.AV_OPT_TYPE_COLOR): + if self.ptr.type in ( + lib.AV_OPT_TYPE_STRING, + lib.AV_OPT_TYPE_BINARY, + lib.AV_OPT_TYPE_IMAGE_SIZE, + lib.AV_OPT_TYPE_VIDEO_RATE, + lib.AV_OPT_TYPE_COLOR, + ): return self.ptr.default_val.str if self.ptr.default_val.str != NULL else "" - def _norm_range(self, value): - if self.ptr.type in _INT_TYPES: - return int(value) - return value - @property def min(self): - return self._norm_range(self.ptr.min) + if self.ptr.type in _INT_TYPES: + return int(self.ptr.min) + return self.ptr.min @property def max(self): - return self._norm_range(self.ptr.max) + if self.ptr.type in _INT_TYPES: + return int(self.ptr.max) + return self.ptr.max def __repr__(self): - return ( - f"" - ) + return f"" -cdef OptionChoice wrap_option_choice(const lib.AVOption *ptr, bint is_default): +@cython.cfunc +def wrap_option_choice( + ptr: cython.pointer[cython.const[lib.AVOption]], is_default: bint +) -> OptionChoice | None: if ptr == NULL: return None - cdef OptionChoice obj = OptionChoice(_cinit_sentinel) + obj: OptionChoice = OptionChoice(_cinit_sentinel) obj.ptr = ptr obj.is_default = is_default return obj -cdef class OptionChoice(BaseOption): +@cython.cclass +class OptionChoice(BaseOption): """ Represents AV_OPT_TYPE_CONST options which are essentially choices of non-const option with same unit.