From 1e57c100d264d3b872efa8b0e5d8a1d7928aef4d Mon Sep 17 00:00:00 2001 From: WyattBlue Date: Wed, 13 Nov 2024 04:05:05 -0500 Subject: [PATCH] Rethink container flags design --- av/container/core.pyi | 37 +++++++++-------- av/container/core.pyx | 97 ++++++++++--------------------------------- 2 files changed, 42 insertions(+), 92 deletions(-) diff --git a/av/container/core.pyi b/av/container/core.pyi index b031fb4b6..227a7d32a 100644 --- a/av/container/core.pyi +++ b/av/container/core.pyi @@ -1,9 +1,9 @@ +from enum import Flag from fractions import Fraction from pathlib import Path from types import TracebackType -from typing import Any, Callable, Literal, Type, overload +from typing import Any, Callable, ClassVar, Literal, Type, overload -from av.enum import EnumFlag from av.format import ContainerFormat from .input import InputContainer @@ -12,22 +12,22 @@ from .streams import StreamContainer Real = int | float | Fraction -class Flags(EnumFlag): - GENPTS: int - IGNIDX: int - NONBLOCK: int - IGNDTS: int - NOFILLIN: int - NOPARSE: int - NOBUFFER: int - CUSTOM_IO: int - DISCARD_CORRUPT: int - FLUSH_PACKETS: int - BITEXACT: int - SORT_DTS: int - FAST_SEEK: int - SHORTEST: int - AUTO_BSF: int +class Flags(Flag): + gen_pts: ClassVar[Flags] + ign_idx: ClassVar[Flags] + non_block: ClassVar[Flags] + ign_dts: ClassVar[Flags] + no_fillin: ClassVar[Flags] + no_parse: ClassVar[Flags] + no_buffer: ClassVar[Flags] + custom_io: ClassVar[Flags] + discard_corrupt: ClassVar[Flags] + flush_packets: ClassVar[Flags] + bitexact: ClassVar[Flags] + sort_dts: ClassVar[Flags] + fast_seek: ClassVar[Flags] + shortest: ClassVar[Flags] + auto_bsf: ClassVar[Flags] class Container: writeable: bool @@ -47,6 +47,7 @@ class Container: metadata: dict[str, str] open_timeout: Real | None read_timeout: Real | None + flags: int def __enter__(self) -> Container: ... def __exit__( diff --git a/av/container/core.pyx b/av/container/core.pyx index dab7c865e..563c79d21 100755 --- a/av/container/core.pyx +++ b/av/container/core.pyx @@ -3,6 +3,7 @@ from libc.stdint cimport int64_t import os import time +from enum import Flag from pathlib import Path cimport libav as lib @@ -11,7 +12,6 @@ from av.container.core cimport timeout_info from av.container.input cimport InputContainer from av.container.output cimport OutputContainer from av.container.pyio cimport pyio_close_custom_gil, pyio_close_gil -from av.enum cimport define_enum from av.error cimport err_check, stash_exception from av.format cimport build_container_format from av.utils cimport avdict_to_dict @@ -27,14 +27,12 @@ cdef object _cinit_sentinel = object() cdef object clock = getattr(time, "monotonic", time.time) cdef int interrupt_cb (void *p) noexcept nogil: - cdef timeout_info info = dereference( p) if info.timeout < 0: # timeout < 0 means no timeout return 0 cdef double current_time with gil: - current_time = clock() # Check if the clock has been changed. @@ -124,47 +122,26 @@ cdef int pyav_io_close_gil(lib.AVFormatContext *s, lib.AVIOContext *pb) noexcept return result -Flags = define_enum("Flags", __name__, ( - ("GENPTS", lib.AVFMT_FLAG_GENPTS, - "Generate missing pts even if it requires parsing future frames."), - ("IGNIDX", lib.AVFMT_FLAG_IGNIDX, - "Ignore index."), - ("NONBLOCK", lib.AVFMT_FLAG_NONBLOCK, - "Do not block when reading packets from input."), - ("IGNDTS", lib.AVFMT_FLAG_IGNDTS, - "Ignore DTS on frames that contain both DTS & PTS."), - ("NOFILLIN", lib.AVFMT_FLAG_NOFILLIN, - "Do not infer any values from other values, just return what is stored in the container."), - ("NOPARSE", lib.AVFMT_FLAG_NOPARSE, - """Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. - - Also seeking to frames can not work if parsing to find frame boundaries has been disabled."""), - ("NOBUFFER", lib.AVFMT_FLAG_NOBUFFER, - "Do not buffer frames when possible."), - ("CUSTOM_IO", lib.AVFMT_FLAG_CUSTOM_IO, - "The caller has supplied a custom AVIOContext, don't avio_close() it."), - ("DISCARD_CORRUPT", lib.AVFMT_FLAG_DISCARD_CORRUPT, - "Discard frames marked corrupted."), - ("FLUSH_PACKETS", lib.AVFMT_FLAG_FLUSH_PACKETS, - "Flush the AVIOContext every packet."), - ("BITEXACT", lib.AVFMT_FLAG_BITEXACT, - """When muxing, try to avoid writing any random/volatile data to the output. - - This includes any random IDs, real-time timestamps/dates, muxer version, etc. - This flag is mainly intended for testing."""), - ("SORT_DTS", lib.AVFMT_FLAG_SORT_DTS, - "Try to interleave outputted packets by dts (using this flag can slow demuxing down)."), - ("FAST_SEEK", lib.AVFMT_FLAG_FAST_SEEK, - "Enable fast, but inaccurate seeks for some formats."), - ("SHORTEST", lib.AVFMT_FLAG_SHORTEST, - "Stop muxing when the shortest stream stops."), - ("AUTO_BSF", lib.AVFMT_FLAG_AUTO_BSF, - "Add bitstream filters as requested by the muxer."), -), is_flags=True) +class Flags(Flag): + gen_pts: "Generate missing pts even if it requires parsing future frames." = lib.AVFMT_FLAG_GENPTS + ign_idx: "Ignore index." = lib.AVFMT_FLAG_IGNIDX + non_block: "Do not block when reading packets from input." = lib.AVFMT_FLAG_NONBLOCK + ign_dts: "Ignore DTS on frames that contain both DTS & PTS." = lib.AVFMT_FLAG_IGNDTS + no_fillin: "Do not infer any values from other values, just return what is stored in the container." = lib.AVFMT_FLAG_NOFILLIN + no_parse: "Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled." = lib.AVFMT_FLAG_NOPARSE + no_buffer: "Do not buffer frames when possible." = lib.AVFMT_FLAG_NOBUFFER + custom_io: "The caller has supplied a custom AVIOContext, don't avio_close() it." = lib.AVFMT_FLAG_CUSTOM_IO + discard_corrupt: "Discard frames marked corrupted." = lib.AVFMT_FLAG_DISCARD_CORRUPT + flush_packets: "Flush the AVIOContext every packet." = lib.AVFMT_FLAG_FLUSH_PACKETS + bitexact: "When muxing, try to avoid writing any random/volatile data to the output. This includes any random IDs, real-time timestamps/dates, muxer version, etc. This flag is mainly intended for testing." = lib.AVFMT_FLAG_BITEXACT + sort_dts: "Try to interleave outputted packets by dts (using this flag can slow demuxing down)." = lib.AVFMT_FLAG_SORT_DTS + fast_seek: "Enable fast, but inaccurate seeks for some formats." = lib.AVFMT_FLAG_FAST_SEEK + shortest: "Stop muxing when the shortest stream stops." = lib.AVFMT_FLAG_SHORTEST + auto_bsf: "Add bitstream filters as requested by the muxer." = lib.AVFMT_FLAG_AUTO_BSF -cdef class Container: +cdef class Container: def __cinit__(self, sentinel, file_, format_name, options, container_options, stream_options, metadata_encoding, metadata_errors, @@ -248,20 +225,13 @@ cdef class Container: cdef lib.AVInputFormat *ifmt cdef _Dictionary c_options if not self.writeable: - ifmt = self.format.iptr if self.format else NULL - c_options = Dictionary(self.options, self.container_options) self.set_timeout(self.open_timeout) self.start_timeout() with nogil: - res = lib.avformat_open_input( - &self.ptr, - name, - ifmt, - &c_options.ptr - ) + res = lib.avformat_open_input(&self.ptr, name, ifmt, &c_options.ptr) self.set_timeout(None) self.err_check(res) self.input_was_opened = True @@ -304,37 +274,16 @@ cdef class Container: if self.ptr == NULL: raise AssertionError("Container is not open") - def _get_flags(self): + @property + def flags(self): self._assert_open() return self.ptr.flags - def _set_flags(self, value): + @flags.setter + def flags(self, int value): self._assert_open() self.ptr.flags = value - flags = Flags.property( - _get_flags, - _set_flags, - """Flags property of :class:`.Flags`""" - ) - - gen_pts = flags.flag_property("GENPTS") - ign_idx = flags.flag_property("IGNIDX") - non_block = flags.flag_property("NONBLOCK") - ign_dts = flags.flag_property("IGNDTS") - no_fill_in = flags.flag_property("NOFILLIN") - no_parse = flags.flag_property("NOPARSE") - no_buffer = flags.flag_property("NOBUFFER") - custom_io = flags.flag_property("CUSTOM_IO") - discard_corrupt = flags.flag_property("DISCARD_CORRUPT") - flush_packets = flags.flag_property("FLUSH_PACKETS") - bit_exact = flags.flag_property("BITEXACT") - sort_dts = flags.flag_property("SORT_DTS") - fast_seek = flags.flag_property("FAST_SEEK") - shortest = flags.flag_property("SHORTEST") - auto_bsf = flags.flag_property("AUTO_BSF") - - def open( file, mode=None,