diff --git a/av/option.pyx b/av/option.pyx index e58c4c13f..604d81a53 100644 --- a/av/option.pyx +++ b/av/option.pyx @@ -1,6 +1,5 @@ cimport libav as lib - -from av.utils cimport flag_in_bitfield +from libc.stdint cimport uint64_t from enum import Enum, Flag @@ -16,6 +15,13 @@ cdef Option wrap_option(tuple choices, const lib.AVOption *ptr): 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 + return bool(bitfield & flag) + + class OptionType(Enum): FLAGS = lib.AV_OPT_TYPE_FLAGS INT = lib.AV_OPT_TYPE_INT diff --git a/av/utils.pxd b/av/utils.pxd index 9aeb4a2fb..60279e513 100644 --- a/av/utils.pxd +++ b/av/utils.pxd @@ -1,5 +1,4 @@ cimport libav as lib -from libc.stdint cimport uint64_t cdef dict avdict_to_dict(lib.AVDictionary *input, str encoding, str errors) @@ -7,6 +6,4 @@ cdef dict_to_avdict(lib.AVDictionary **dst, dict src, str encoding, str errors) cdef object avrational_to_fraction(const lib.AVRational *input) cdef void to_avrational(object frac, lib.AVRational *input) - -cdef check_ndarray(object array, object dtype, int ndim) -cdef flag_in_bitfield(uint64_t bitfield, uint64_t flag) +cdef void check_ndarray(object array, object dtype, int ndim) diff --git a/av/utils.py b/av/utils.py new file mode 100644 index 000000000..3516be0e3 --- /dev/null +++ b/av/utils.py @@ -0,0 +1,86 @@ +# type: ignore +from fractions import Fraction + +import cython +from cython.cimports import libav as lib +from cython.cimports.av.error import err_check + +# === DICTIONARIES === +# ==================== + + +@cython.cfunc +def _decode(s: cython.pointer[cython.char], encoding, errors) -> str: + return cython.cast(bytes, s).decode(encoding, errors) + + +@cython.cfunc +def _encode(s, encoding, errors) -> bytes: + return s.encode(encoding, errors) + + +@cython.cfunc +def avdict_to_dict( + input: cython.pointer[lib.AVDictionary], encoding: str, errors: str +) -> dict: + element: cython.pointer[lib.AVDictionaryEntry] = cython.NULL + output: dict = {} + while True: + element = lib.av_dict_get(input, "", element, lib.AV_DICT_IGNORE_SUFFIX) + if element == cython.NULL: + break + output[_decode(element.key, encoding, errors)] = _decode( + element.value, encoding, errors + ) + + return output + + +@cython.cfunc +def dict_to_avdict( + dst: cython.pointer[cython.pointer[lib.AVDictionary]], + src: dict, + encoding: str, + errors: str, +): + lib.av_dict_free(dst) + for key, value in src.items(): + err_check( + lib.av_dict_set( + dst, key.encode(encoding, errors), value.encode(encoding, errors), 0 + ) + ) + + +# === FRACTIONS === +# ================= + + +@cython.cfunc +def avrational_to_fraction( + input: cython.pointer[cython.const[lib.AVRational]], +) -> object: + if input.num and input.den: + return Fraction(input.num, input.den) + return None + + +@cython.cfunc +def to_avrational(frac: object, input: cython.pointer[lib.AVRational]) -> cython.void: + input.num = frac.numerator + input.den = frac.denominator + + +@cython.cfunc +def check_ndarray(array: object, dtype: object, ndim: cython.int) -> cython.void: + """ + Check a numpy array has the expected data type and number of dimensions. + """ + if array.dtype != dtype: + raise ValueError( + f"Expected numpy array with dtype `{dtype}` but got `{array.dtype}`" + ) + if array.ndim != ndim: + raise ValueError( + f"Expected numpy array with ndim `{ndim}` but got `{array.ndim}`" + ) diff --git a/av/utils.pyx b/av/utils.pyx deleted file mode 100644 index 190bbf4d7..000000000 --- a/av/utils.pyx +++ /dev/null @@ -1,78 +0,0 @@ -from libc.stdint cimport uint64_t - -from fractions import Fraction - -cimport libav as lib - -from av.error cimport err_check - -# === DICTIONARIES === -# ==================== - -cdef _decode(char *s, encoding, errors): - return (s).decode(encoding, errors) - -cdef bytes _encode(s, encoding, errors): - return s.encode(encoding, errors) - -cdef dict avdict_to_dict(lib.AVDictionary *input, str encoding, str errors): - cdef lib.AVDictionaryEntry *element = NULL - cdef dict output = {} - while True: - element = lib.av_dict_get(input, "", element, lib.AV_DICT_IGNORE_SUFFIX) - if element == NULL: - break - output[_decode(element.key, encoding, errors)] = _decode(element.value, encoding, errors) - return output - - -cdef dict_to_avdict(lib.AVDictionary **dst, dict src, str encoding, str errors): - lib.av_dict_free(dst) - for key, value in src.items(): - err_check( - lib.av_dict_set( - dst, - _encode(key, encoding, errors), - _encode(value, encoding, errors), - 0 - ) - ) - - -# === FRACTIONS === -# ================= - -cdef object avrational_to_fraction(const lib.AVRational *input): - if input.num and input.den: - return Fraction(input.num, input.den) - - -cdef void to_avrational(object frac, lib.AVRational *input): - input.num = frac.numerator - input.den = frac.denominator - - -# === OTHER === -# ============= - - -cdef check_ndarray(object array, object dtype, int ndim): - """ - Check a numpy array has the expected data type and number of dimensions. - """ - if array.dtype != dtype: - raise ValueError(f"Expected numpy array with dtype `{dtype}` but got `{array.dtype}`") - if array.ndim != ndim: - raise ValueError(f"Expected numpy array with ndim `{ndim}` but got `{array.ndim}`") - - -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 - return bool(bitfield & flag) - - -# === BACKWARDS COMPAT === - -from .error import err_check