add read me

This commit is contained in:
2026-01-09 10:28:44 +11:00
commit edaf914b73
13417 changed files with 2952119 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
cimport libav as lib
from av.frame cimport Frame
from av.sidedata.sidedata cimport SideData
cdef class _MotionVectors(SideData):
cdef dict _vectors
cdef int _len
cdef class MotionVector:
cdef _MotionVectors parent
cdef lib.AVMotionVector *ptr

View File

@@ -0,0 +1,27 @@
from typing import Any, Sequence, overload
import numpy as np
from .sidedata import SideData
class MotionVectors(SideData, Sequence[MotionVector]):
@overload
def __getitem__(self, index: int): ...
@overload
def __getitem__(self, index: slice): ...
@overload
def __getitem__(self, index: int | slice): ...
def __len__(self) -> int: ...
def to_ndarray(self) -> np.ndarray[Any, Any]: ...
class MotionVector:
source: int
w: int
h: int
src_x: int
src_y: int
dst_x: int
dst_y: int
motion_x: int
motion_y: int
motion_scale: int

View File

@@ -0,0 +1,104 @@
from collections.abc import Sequence
cdef object _cinit_bypass_sentinel = object()
# Cython doesn't let us inherit from the abstract Sequence, so we will subclass
# it later.
cdef class _MotionVectors(SideData):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._vectors = {}
self._len = self.ptr.size // sizeof(lib.AVMotionVector)
def __repr__(self):
return f"<av.sidedata.MotionVectors {self.ptr.size} bytes of {len(self)} vectors at 0x{<unsigned int>self.ptr.data:0x}"
def __getitem__(self, int index):
try:
return self._vectors[index]
except KeyError:
pass
if index >= self._len:
raise IndexError(index)
vector = self._vectors[index] = MotionVector(_cinit_bypass_sentinel, self, index)
return vector
def __len__(self):
return self._len
def to_ndarray(self):
import numpy as np
return np.frombuffer(self, dtype=np.dtype([
("source", "int32"),
("w", "uint8"),
("h", "uint8"),
("src_x", "int16"),
("src_y", "int16"),
("dst_x", "int16"),
("dst_y", "int16"),
("flags", "uint64"),
("motion_x", "int32"),
("motion_y", "int32"),
("motion_scale", "uint16"),
], align=True))
class MotionVectors(_MotionVectors, Sequence):
pass
cdef class MotionVector:
def __init__(self, sentinel, _MotionVectors parent, int index):
if sentinel is not _cinit_bypass_sentinel:
raise RuntimeError("cannot manually instantiate MotionVector")
self.parent = parent
cdef lib.AVMotionVector *base = <lib.AVMotionVector*>parent.ptr.data
self.ptr = base + index
def __repr__(self):
return f"<av.sidedata.MotionVector {self.w}x{self.h} from {self.src_x},{self.src_y} to {self.dst_x},{self.dst_y}>"
@property
def source(self):
return self.ptr.source
@property
def w(self):
return self.ptr.w
@property
def h(self):
return self.ptr.h
@property
def src_x(self):
return self.ptr.src_x
@property
def src_y(self):
return self.ptr.src_y
@property
def dst_x(self):
return self.ptr.dst_x
@property
def dst_y(self):
return self.ptr.dst_y
@property
def motion_x(self):
return self.ptr.motion_x
@property
def motion_y(self):
return self.ptr.motion_y
@property
def motion_scale(self):
return self.ptr.motion_scale

View File

@@ -0,0 +1,23 @@
cimport libav as lib
from av.buffer cimport Buffer
from av.dictionary cimport _Dictionary, wrap_dictionary
from av.frame cimport Frame
cdef class SideData(Buffer):
cdef Frame frame
cdef lib.AVFrameSideData *ptr
cdef _Dictionary metadata
cdef SideData wrap_side_data(Frame frame, int index)
cdef int get_display_rotation(Frame frame)
cdef class _SideDataContainer:
cdef Frame frame
cdef list _by_index
cdef dict _by_type

View File

@@ -0,0 +1,52 @@
from collections.abc import Mapping
from enum import Enum
from typing import ClassVar, Iterator, Sequence, cast, overload
from av.buffer import Buffer
from av.frame import Frame
class Type(Enum):
PANSCAN = cast(ClassVar[Type], ...)
A53_CC = cast(ClassVar[Type], ...)
STEREO3D = cast(ClassVar[Type], ...)
MATRIXENCODING = cast(ClassVar[Type], ...)
DOWNMIX_INFO = cast(ClassVar[Type], ...)
REPLAYGAIN = cast(ClassVar[Type], ...)
DISPLAYMATRIX = cast(ClassVar[Type], ...)
AFD = cast(ClassVar[Type], ...)
MOTION_VECTORS = cast(ClassVar[Type], ...)
SKIP_SAMPLES = cast(ClassVar[Type], ...)
AUDIO_SERVICE_TYPE = cast(ClassVar[Type], ...)
MASTERING_DISPLAY_METADATA = cast(ClassVar[Type], ...)
GOP_TIMECODE = cast(ClassVar[Type], ...)
SPHERICAL = cast(ClassVar[Type], ...)
CONTENT_LIGHT_LEVEL = cast(ClassVar[Type], ...)
ICC_PROFILE = cast(ClassVar[Type], ...)
S12M_TIMECODE = cast(ClassVar[Type], ...)
DYNAMIC_HDR_PLUS = cast(ClassVar[Type], ...)
REGIONS_OF_INTEREST = cast(ClassVar[Type], ...)
VIDEO_ENC_PARAMS = cast(ClassVar[Type], ...)
SEI_UNREGISTERED = cast(ClassVar[Type], ...)
FILM_GRAIN_PARAMS = cast(ClassVar[Type], ...)
DETECTION_BBOXES = cast(ClassVar[Type], ...)
DOVI_RPU_BUFFER = cast(ClassVar[Type], ...)
DOVI_METADATA = cast(ClassVar[Type], ...)
DYNAMIC_HDR_VIVID = cast(ClassVar[Type], ...)
AMBIENT_VIEWING_ENVIRONMENT = cast(ClassVar[Type], ...)
VIDEO_HINT = cast(ClassVar[Type], ...)
class SideData(Buffer):
type: Type
class SideDataContainer(Mapping):
frame: Frame
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[SideData]: ...
@overload
def __getitem__(self, key: str | int | Type) -> SideData: ...
@overload
def __getitem__(self, key: slice) -> Sequence[SideData]: ...
@overload
def __getitem__(
self, key: str | int | Type | slice
) -> SideData | Sequence[SideData]: ...

View File

@@ -0,0 +1,116 @@
from libc.stdint cimport int32_t
from collections.abc import Mapping
from enum import Enum
from av.sidedata.motionvectors import MotionVectors
cdef object _cinit_bypass_sentinel = object()
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):
if frame.ptr.side_data[index].type == lib.AV_FRAME_DATA_MOTION_VECTORS:
return MotionVectors(_cinit_bypass_sentinel, frame, index)
else:
return SideData(_cinit_bypass_sentinel, frame, index)
cdef int get_display_rotation(Frame frame):
for i in range(frame.ptr.nb_side_data):
if frame.ptr.side_data[i].type == lib.AV_FRAME_DATA_DISPLAYMATRIX:
return int(lib.av_display_rotation_get(<const int32_t *>frame.ptr.side_data[i].data))
return 0
cdef class SideData(Buffer):
def __init__(self, sentinel, Frame frame, int index):
if sentinel is not _cinit_bypass_sentinel:
raise RuntimeError("cannot manually instantiate SideData")
self.frame = frame
self.ptr = frame.ptr.side_data[index]
self.metadata = wrap_dictionary(self.ptr.metadata)
cdef size_t _buffer_size(self):
return self.ptr.size
cdef void* _buffer_ptr(self):
return self.ptr.data
cdef bint _buffer_writable(self):
return False
def __repr__(self):
return f"<av.sidedata.{self.__class__.__name__} {self.ptr.size} bytes of {self.type} at 0x{<unsigned int>self.ptr.data:0x}>"
@property
def type(self):
return Type(self.ptr.type)
cdef class _SideDataContainer:
def __init__(self, Frame frame):
self.frame = frame
self._by_index = []
self._by_type = {}
cdef int i
cdef SideData data
for i in range(self.frame.ptr.nb_side_data):
data = wrap_side_data(frame, i)
self._by_index.append(data)
self._by_type[data.type] = data
def __len__(self):
return len(self._by_index)
def __iter__(self):
return iter(self._by_index)
def __getitem__(self, key):
if isinstance(key, int):
return self._by_index[key]
if isinstance(key, str):
return self._by_type[Type[key]]
return self._by_type[key]
class SideDataContainer(_SideDataContainer, Mapping):
pass