Skip to content

Commit 311e182

Browse files
committed
Make sidedata/motionvectors pure
1 parent 0caf320 commit 311e182

File tree

5 files changed

+142
-113
lines changed

5 files changed

+142
-113
lines changed

av/sidedata/motionvectors.pxd

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ from av.frame cimport Frame
44
from av.sidedata.sidedata cimport SideData
55

66

7-
cdef class _MotionVectors(SideData):
8-
7+
cdef class MotionVectors(SideData):
98
cdef dict _vectors
10-
cdef int _len
9+
cdef Py_ssize_t _len
1110

1211

1312
cdef class MotionVector:
14-
15-
cdef _MotionVectors parent
13+
cdef MotionVectors parent
1614
cdef lib.AVMotionVector *ptr

av/sidedata/motionvectors.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
from collections.abc import Sequence
2+
3+
import cython
4+
from cython.cimports import libav as lib
5+
from cython.cimports.av.sidedata.sidedata import SideData
6+
7+
_cinit_bypass_sentinel = cython.declare(object, object())
8+
9+
10+
@cython.cclass
11+
class MotionVectors(SideData, Sequence):
12+
def __init__(self, sentinel, frame: Frame, index: cython.int):
13+
SideData.__init__(self, sentinel, frame, index)
14+
self._vectors = {}
15+
self._len = self.ptr.size // cython.sizeof(lib.AVMotionVector)
16+
17+
def __repr__(self):
18+
return (
19+
f"<av.sidedata.MotionVectors {self.ptr.size} bytes "
20+
f"of {len(self)} vectors at 0x{cython.cast(cython.uint, self.ptr.data):0x}>"
21+
)
22+
23+
def __len__(self):
24+
return self._len
25+
26+
def __getitem__(self, index: cython.Py_ssize_t):
27+
try:
28+
return self._vectors[index]
29+
except KeyError:
30+
pass
31+
32+
if index >= self._len:
33+
raise IndexError(index)
34+
35+
vector = self._vectors[index] = MotionVector(
36+
_cinit_bypass_sentinel, self, index
37+
)
38+
return vector
39+
40+
def __iter__(self):
41+
"""Iterate over all motion vectors."""
42+
for i in range(self._len):
43+
yield self[i]
44+
45+
def to_ndarray(self):
46+
"""
47+
Convert motion vectors to a NumPy structured array.
48+
49+
Returns a NumPy array with fields corresponding to the AVMotionVector structure.
50+
"""
51+
import numpy as np
52+
53+
return np.frombuffer(
54+
self,
55+
dtype=np.dtype(
56+
[
57+
("source", "int32"),
58+
("w", "uint8"),
59+
("h", "uint8"),
60+
("src_x", "int16"),
61+
("src_y", "int16"),
62+
("dst_x", "int16"),
63+
("dst_y", "int16"),
64+
("flags", "uint64"),
65+
("motion_x", "int32"),
66+
("motion_y", "int32"),
67+
("motion_scale", "uint16"),
68+
],
69+
align=True,
70+
),
71+
)
72+
73+
74+
@cython.cclass
75+
class MotionVector:
76+
"""
77+
Represents a single motion vector from video frame data.
78+
79+
Motion vectors describe the motion of a block of pixels between frames.
80+
"""
81+
82+
def __init__(self, sentinel, parent: MotionVectors, index: cython.int):
83+
if sentinel is not _cinit_bypass_sentinel:
84+
raise RuntimeError("cannot manually instantiate MotionVector")
85+
self.parent = parent
86+
base: cython.pointer[lib.AVMotionVector] = cython.cast(
87+
cython.pointer[lib.AVMotionVector], parent.ptr.data
88+
)
89+
self.ptr = base + index
90+
91+
def __repr__(self):
92+
return (
93+
f"<av.sidedata.MotionVector {self.w}x{self.h} "
94+
f"from ({self.src_x},{self.src_y}) to ({self.dst_x},{self.dst_y})>"
95+
)
96+
97+
@property
98+
def source(self):
99+
return self.ptr.source
100+
101+
@property
102+
def w(self):
103+
return self.ptr.w
104+
105+
@property
106+
def h(self):
107+
return self.ptr.h
108+
109+
@property
110+
def src_x(self):
111+
return self.ptr.src_x
112+
113+
@property
114+
def src_y(self):
115+
return self.ptr.src_y
116+
117+
@property
118+
def dst_x(self):
119+
return self.ptr.dst_x
120+
121+
@property
122+
def dst_y(self):
123+
return self.ptr.dst_y
124+
125+
@property
126+
def motion_x(self):
127+
return self.ptr.motion_x
128+
129+
@property
130+
def motion_y(self):
131+
return self.ptr.motion_y
132+
133+
@property
134+
def motion_scale(self):
135+
return self.ptr.motion_scale

av/sidedata/motionvectors.pyi

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ from .sidedata import SideData
66

77
class MotionVectors(SideData, Sequence[MotionVector]):
88
@overload
9-
def __getitem__(self, index: int): ...
9+
def __getitem__(self, index: int) -> MotionVector: ...
1010
@overload
11-
def __getitem__(self, index: slice): ...
12-
@overload
13-
def __getitem__(self, index: int | slice): ...
11+
def __getitem__(self, index: slice) -> list[MotionVector]: ...
1412
def __len__(self) -> int: ...
1513
def to_ndarray(self) -> np.ndarray[Any, Any]: ...
1614

av/sidedata/motionvectors.pyx

Lines changed: 0 additions & 104 deletions
This file was deleted.

av/video/frame.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@ def copy_bytes_to_plane(
158158
for row in range(start_row, end_row, step):
159159
i_pos = row * i_stride
160160
if flip_horizontal:
161+
i: cython.Py_ssize_t
161162
for i in range(0, i_stride, bytes_per_pixel):
163+
j: cython.Py_ssize_t
162164
for j in range(bytes_per_pixel):
163165
o_buf[o_pos + i + j] = i_buf[
164166
i_pos + i_stride - i - bytes_per_pixel + j

0 commit comments

Comments
 (0)