Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make PictureType an IntEnum #1634

Merged
merged 4 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 38 additions & 22 deletions av/codec/codec.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Flag
from fractions import Fraction
from typing import Literal, overload
from typing import ClassVar, Literal, overload

from av.audio.codeccontext import AudioCodecContext
from av.audio.format import AudioFormat
Expand All @@ -11,14 +12,14 @@ from av.video.format import VideoFormat

from .context import CodecContext

class Properties(EnumFlag):
NONE: int
INTRA_ONLY: int
LOSSY: int
LOSSLESS: int
REORDER: int
BITMAP_SUB: int
TEXT_SUB: int
class Properties(Flag):
NONE: ClassVar[Properties]
INTRA_ONLY: ClassVar[Properties]
LOSSY: ClassVar[Properties]
LOSSLESS: ClassVar[Properties]
REORDER: ClassVar[Properties]
BITMAP_SUB: ClassVar[Properties]
TEXT_SUB: ClassVar[Properties]

class Capabilities(EnumFlag):
NONE: int
Expand Down Expand Up @@ -46,25 +47,40 @@ class Capabilities(EnumFlag):
class UnknownCodecError(ValueError): ...

class Codec:
is_encoder: bool
is_decoder: bool
@property
def is_encoder(self) -> bool: ...
@property
def is_decoder(self) -> bool: ...
descriptor: Descriptor
name: str
long_name: str
type: Literal["video", "audio", "data", "subtitle", "attachment"]
id: int
@property
def name(self) -> str: ...
@property
def long_name(self) -> str: ...
@property
def type(self) -> Literal["video", "audio", "data", "subtitle", "attachment"]: ...
@property
def id(self) -> int: ...
frame_rates: list[Fraction] | None
audio_rates: list[int] | None
video_formats: list[VideoFormat] | None
audio_formats: list[AudioFormat] | None
properties: Properties

@property
def properties(self) -> int: ...
@property
def intra_only(self) -> bool: ...
@property
def lossy(self) -> bool: ...
@property
def lossless(self) -> bool: ...
@property
def reorder(self) -> bool: ...
@property
def bitmap_sub(self) -> bool: ...
@property
def text_sub(self) -> bool: ...

capabilities: Capabilities
intra_only: bool
lossy: bool
lossless: bool
reorder: bool
bitmap_sub: bool
text_sub: bool
draw_horiz_band: bool
dr1: bool
hwaccel: bool
Expand Down
77 changes: 34 additions & 43 deletions av/codec/codec.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ from av.enum cimport define_enum
from av.utils cimport avrational_to_fraction
from av.video.format cimport get_video_format

from enum import Flag

cdef object _cinit_sentinel = object()

cdef object _cinit_sentinel = object()

cdef Codec wrap_codec(const lib.AVCodec *ptr):
cdef Codec codec = Codec(_cinit_sentinel)
Expand All @@ -15,34 +16,14 @@ cdef Codec wrap_codec(const lib.AVCodec *ptr):
codec._init()
return codec


Properties = define_enum("Properties", "av.codec", (
("NONE", 0),
("INTRA_ONLY", lib.AV_CODEC_PROP_INTRA_ONLY,
"""Codec uses only intra compression.
Video and audio codecs only."""),
("LOSSY", lib.AV_CODEC_PROP_LOSSY,
"""Codec supports lossy compression. Audio and video codecs only.

Note: A codec may support both lossy and lossless
compression modes."""),
("LOSSLESS", lib.AV_CODEC_PROP_LOSSLESS,
"""Codec supports lossless compression. Audio and video codecs only."""),
("REORDER", lib.AV_CODEC_PROP_REORDER,
"""Codec supports frame reordering. That is, the coded order (the order in which
the encoded packets are output by the encoders / stored / input to the
decoders) may be different from the presentation order of the corresponding
frames.

For codecs that do not have this property set, PTS and DTS should always be
equal."""),
("BITMAP_SUB", lib.AV_CODEC_PROP_BITMAP_SUB,
"""Subtitle codec is bitmap based
Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field."""),
("TEXT_SUB", lib.AV_CODEC_PROP_TEXT_SUB,
"""Subtitle codec is text based.
Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field."""),
), is_flags=True)
class Properties(Flag):
NONE = 0
INTRA_ONLY = lib.AV_CODEC_PROP_INTRA_ONLY
LOSSY = lib.AV_CODEC_PROP_LOSSY
LOSSLESS = lib.AV_CODEC_PROP_LOSSLESS
REORDER = lib.AV_CODEC_PROP_REORDER
BITMAP_SUB = lib.AV_CODEC_PROP_BITMAP_SUB
TEXT_SUB = lib.AV_CODEC_PROP_TEXT_SUB

Capabilities = define_enum("Capabilities", "av.codec", (
("NONE", 0),
Expand Down Expand Up @@ -287,21 +268,33 @@ cdef class Codec:
i += 1
return ret

# NOTE: there are some overlaps, which we defer to how `ffmpeg -codecs`
# handles them (by prefering the capablity to the property).
# Also, LOSSLESS and LOSSY don't have to agree.

@Properties.property
@property
def properties(self):
"""Flag property of :class:`.Properties`"""
return self.desc.props

intra_only = properties.flag_property("INTRA_ONLY")
lossy = properties.flag_property("LOSSY") # Defer to capability.
lossless = properties.flag_property("LOSSLESS") # Defer to capability.
reorder = properties.flag_property("REORDER")
bitmap_sub = properties.flag_property("BITMAP_SUB")
text_sub = properties.flag_property("TEXT_SUB")
@property
def intra_only(self):
return bool(self.desc.props & lib.AV_CODEC_PROP_INTRA_ONLY)

@property
def lossy(self):
return bool(self.desc.props & lib.AV_CODEC_PROP_LOSSY)

@property
def lossless(self):
return bool(self.desc.props & lib.AV_CODEC_PROP_LOSSLESS)

@property
def reorder(self):
return bool(self.desc.props & lib.AV_CODEC_PROP_REORDER)

@property
def bitmap_sub(self):
return bool(self.desc.props & lib.AV_CODEC_PROP_BITMAP_SUB)

@property
def text_sub(self):
return bool(self.desc.props & lib.AV_CODEC_PROP_TEXT_SUB)

@Capabilities.property
def capabilities(self):
Expand All @@ -324,8 +317,6 @@ cdef class Codec:
auto_threads = capabilities.flag_property("AUTO_THREADS")
variable_frame_size = capabilities.flag_property("VARIABLE_FRAME_SIZE")
avoid_probing = capabilities.flag_property("AVOID_PROBING")
# intra_only = capabilities.flag_property("INTRA_ONLY") # Dupes.
# lossless = capabilities.flag_property("LOSSLESS") # Dupes.
hardware = capabilities.flag_property("HARDWARE")
hybrid = capabilities.flag_property("HYBRID")
encoder_reordered_opaque = capabilities.flag_property("ENCODER_REORDERED_OPAQUE")
Expand Down
59 changes: 35 additions & 24 deletions av/sidedata/sidedata.pyi
Original file line number Diff line number Diff line change
@@ -1,41 +1,52 @@
from collections.abc import Mapping
from typing import Iterator, Sequence, overload
from enum import Enum
from typing import ClassVar, Iterator, Sequence, overload

from av.buffer import Buffer
from av.enum import EnumItem
from av.frame import Frame

class Type(EnumItem):
PANSCAN: int
A53_CC: int
STEREO3D: int
MATRIXENCODING: int
DOWNMIX_INFO: int
REPLAYGAIN: int
DISPLAYMATRIX: int
AFD: int
MOTION_VECTORS: int
SKIP_SAMPLES: int
AUDIO_SERVICE_TYPE: int
MASTERING_DISPLAY_METADATA: int
GOP_TIMECODE: int
SPHERICAL: int
CONTENT_LIGHT_LEVEL: int
ICC_PROFILE: int
SEI_UNREGISTERED: int
S12M_TIMECODE: int
class Type(Enum):
PANSCAN: ClassVar[Type]
A53_CC: ClassVar[Type]
STEREO3D: ClassVar[Type]
MATRIXENCODING: ClassVar[Type]
DOWNMIX_INFO: ClassVar[Type]
REPLAYGAIN: ClassVar[Type]
DISPLAYMATRIX: ClassVar[Type]
AFD: ClassVar[Type]
MOTION_VECTORS: ClassVar[Type]
SKIP_SAMPLES: ClassVar[Type]
AUDIO_SERVICE_TYPE: ClassVar[Type]
MASTERING_DISPLAY_METADATA: ClassVar[Type]
GOP_TIMECODE: ClassVar[Type]
SPHERICAL: ClassVar[Type]
CONTENT_LIGHT_LEVEL: ClassVar[Type]
ICC_PROFILE: ClassVar[Type]
S12M_TIMECODE: ClassVar[Type]
DYNAMIC_HDR_PLUS: ClassVar[Type]
REGIONS_OF_INTEREST: ClassVar[Type]
VIDEO_ENC_PARAMS: ClassVar[Type]
SEI_UNREGISTERED: ClassVar[Type]
FILM_GRAIN_PARAMS: ClassVar[Type]
DETECTION_BBOXES: ClassVar[Type]
DOVI_RPU_BUFFER: ClassVar[Type]
DOVI_METADATA: ClassVar[Type]
DYNAMIC_HDR_VIVID: ClassVar[Type]
AMBIENT_VIEWING_ENVIRONMENT: ClassVar[Type]
VIDEO_HINT: ClassVar[Type]

class SideData(Buffer):
type: Type
DISPLAYMATRIX: int

class SideDataContainer(Mapping):
frame: Frame
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[SideData]: ...
@overload
def __getitem__(self, key: int) -> SideData: ...
def __getitem__(self, key: str | int | Type) -> SideData: ...
@overload
def __getitem__(self, key: slice) -> Sequence[SideData]: ...
@overload
def __getitem__(self, key: int | slice) -> SideData | Sequence[SideData]: ...
def __getitem__(
self, key: str | int | Type | slice
) -> SideData | Sequence[SideData]: ...
66 changes: 40 additions & 26 deletions av/sidedata/sidedata.pyx
Original file line number Diff line number Diff line change
@@ -1,33 +1,47 @@
from av.enum cimport define_enum

from collections.abc import Mapping
from enum import Enum

from av.sidedata.motionvectors import MotionVectors


cdef object _cinit_bypass_sentinel = object()


Type = define_enum("Type", __name__, (
("PANSCAN", lib.AV_FRAME_DATA_PANSCAN),
("A53_CC", lib.AV_FRAME_DATA_A53_CC),
("STEREO3D", lib.AV_FRAME_DATA_STEREO3D),
("MATRIXENCODING", lib.AV_FRAME_DATA_MATRIXENCODING),
("DOWNMIX_INFO", lib.AV_FRAME_DATA_DOWNMIX_INFO),
("REPLAYGAIN", lib.AV_FRAME_DATA_REPLAYGAIN),
("DISPLAYMATRIX", lib.AV_FRAME_DATA_DISPLAYMATRIX),
("AFD", lib.AV_FRAME_DATA_AFD),
("MOTION_VECTORS", lib.AV_FRAME_DATA_MOTION_VECTORS),
("SKIP_SAMPLES", lib.AV_FRAME_DATA_SKIP_SAMPLES),
("AUDIO_SERVICE_TYPE", lib.AV_FRAME_DATA_AUDIO_SERVICE_TYPE),
("MASTERING_DISPLAY_METADATA", lib.AV_FRAME_DATA_MASTERING_DISPLAY_METADATA),
("GOP_TIMECODE", lib.AV_FRAME_DATA_GOP_TIMECODE),
("SPHERICAL", lib.AV_FRAME_DATA_SPHERICAL),
("CONTENT_LIGHT_LEVEL", lib.AV_FRAME_DATA_CONTENT_LIGHT_LEVEL),
("ICC_PROFILE", lib.AV_FRAME_DATA_ICC_PROFILE),
("SEI_UNREGISTERED", lib.AV_FRAME_DATA_SEI_UNREGISTERED),
("S12M_TIMECODE", lib.AV_FRAME_DATA_S12M_TIMECODE),
))
class Type(Enum):
"""
Enum class representing different types of frame data in audio/video processing.
Values are mapped to corresponding AV_FRAME_DATA constants from FFmpeg.

From: https://github.com/FFmpeg/FFmpeg/blob/master/libavutil/frame.h
"""
PANSCAN = lib.AV_FRAME_DATA_PANSCAN
A53_CC = lib.AV_FRAME_DATA_A53_CC
STEREO3D = lib.AV_FRAME_DATA_STEREO3D
MATRIXENCODING = lib.AV_FRAME_DATA_MATRIXENCODING
DOWNMIX_INFO = lib.AV_FRAME_DATA_DOWNMIX_INFO
REPLAYGAIN = lib.AV_FRAME_DATA_REPLAYGAIN
DISPLAYMATRIX = lib.AV_FRAME_DATA_DISPLAYMATRIX
AFD = lib.AV_FRAME_DATA_AFD
MOTION_VECTORS = lib.AV_FRAME_DATA_MOTION_VECTORS
SKIP_SAMPLES = lib.AV_FRAME_DATA_SKIP_SAMPLES
AUDIO_SERVICE_TYPE = lib.AV_FRAME_DATA_AUDIO_SERVICE_TYPE
MASTERING_DISPLAY_METADATA = lib.AV_FRAME_DATA_MASTERING_DISPLAY_METADATA
GOP_TIMECODE = lib.AV_FRAME_DATA_GOP_TIMECODE
SPHERICAL = lib.AV_FRAME_DATA_SPHERICAL
CONTENT_LIGHT_LEVEL = lib.AV_FRAME_DATA_CONTENT_LIGHT_LEVEL
ICC_PROFILE = lib.AV_FRAME_DATA_ICC_PROFILE
S12M_TIMECODE = lib.AV_FRAME_DATA_S12M_TIMECODE
DYNAMIC_HDR_PLUS = lib.AV_FRAME_DATA_DYNAMIC_HDR_PLUS
REGIONS_OF_INTEREST = lib.AV_FRAME_DATA_REGIONS_OF_INTEREST
VIDEO_ENC_PARAMS = lib.AV_FRAME_DATA_VIDEO_ENC_PARAMS
SEI_UNREGISTERED = lib.AV_FRAME_DATA_SEI_UNREGISTERED
FILM_GRAIN_PARAMS = lib.AV_FRAME_DATA_FILM_GRAIN_PARAMS
DETECTION_BBOXES = lib.AV_FRAME_DATA_DETECTION_BBOXES
DOVI_RPU_BUFFER = lib.AV_FRAME_DATA_DOVI_RPU_BUFFER
DOVI_METADATA = lib.AV_FRAME_DATA_DOVI_METADATA
DYNAMIC_HDR_VIVID = lib.AV_FRAME_DATA_DYNAMIC_HDR_VIVID
AMBIENT_VIEWING_ENVIRONMENT = lib.AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT
VIDEO_HINT = lib.AV_FRAME_DATA_VIDEO_HINT


cdef SideData wrap_side_data(Frame frame, int index):
Expand Down Expand Up @@ -60,7 +74,7 @@ cdef class SideData(Buffer):

@property
def type(self):
return Type.get(self.ptr.type) or self.ptr.type
return Type(self.ptr.type)


cdef class _SideDataContainer:
Expand All @@ -85,9 +99,9 @@ cdef class _SideDataContainer:
def __getitem__(self, key):
if isinstance(key, int):
return self._by_index[key]

type_ = Type.get(key)
return self._by_type[type_]
if isinstance(key, str):
return self._by_type[Type[key]]
return self._by_type[key]


class SideDataContainer(_SideDataContainer, Mapping):
Expand Down
12 changes: 5 additions & 7 deletions av/stream.pyi
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
from enum import Enum
from fractions import Fraction
from typing import Literal
from typing import ClassVar, Literal

from .codec import Codec, CodecContext
from .container import Container
from .enum import EnumItem
from .frame import Frame
from .packet import Packet

class SideData(EnumItem):
DISPLAYMATRIX: int
class SideData(Enum):
DISPLAYMATRIX: ClassVar[SideData]

class Stream:
name: str | None
thread_type: Literal["NONE", "FRAME", "SLICE", "AUTO"]

container: Container
codec: Codec
codec_context: CodecContext
metadata: dict[str, str]
id: int
profiles: list[str]
profile: str
profile: str | None
index: int
time_base: Fraction | None
average_rate: Fraction | None
Expand Down
Loading
Loading