Skip to content

Commit e15007e

Browse files
committed
Make video/codeccontext pure
1 parent 6232cdd commit e15007e

File tree

6 files changed

+96
-81
lines changed

6 files changed

+96
-81
lines changed

av/audio/codeccontext.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
@cython.cclass
1111
class AudioCodecContext(CodecContext):
1212
@cython.cfunc
13-
def _prepare_frames_for_encode(self, input_frame: Frame | None):
13+
def _prepare_frames_for_encode(self, input_frame: Frame | None) -> list:
1414
frame: AudioFrame | None = input_frame
1515
allow_var_frame_size: cython.bint = (
1616
self.ptr.codec.capabilities & lib.AV_CODEC_CAP_VARIABLE_FRAME_SIZE

av/codec/context.pxd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ cdef class CodecContext:
4040
# TODO: Remove the `Packet` from `_setup_decoded_frame` (because flushing packets
4141
# are bogus). It should take all info it needs from the context and/or stream.
4242
cdef _prepare_and_time_rebase_frames_for_encode(self, Frame frame)
43-
cdef _prepare_frames_for_encode(self, Frame frame)
43+
cdef list _prepare_frames_for_encode(self, Frame frame)
4444
cdef _setup_encoded_packet(self, Packet)
4545
cdef _setup_decoded_frame(self, Frame, Packet)
4646

av/codec/context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ def _send_packet_and_recv(self, packet: Packet | None):
386386
return out
387387

388388
@cython.cfunc
389-
def _prepare_frames_for_encode(self, frame: Frame | None):
389+
def _prepare_frames_for_encode(self, frame: Frame | None) -> list:
390390
return [frame]
391391

392392
@cython.cfunc

av/container/input.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,11 @@ def seek(
236236
self,
237237
offset,
238238
*,
239-
backward: bint = True,
240-
any_frame: bint = False,
239+
backward: cython.bint = True,
240+
any_frame: cython.bint = False,
241241
stream: Stream | None = None,
242-
unsupported_frame_offset: bint = False,
243-
unsupported_byte_offset: bint = False,
242+
unsupported_frame_offset: cython.bint = False,
243+
unsupported_byte_offset: cython.bint = False,
244244
):
245245
"""seek(offset, *, backward=True, any_frame=False, stream=None)
246246

av/video/codeccontext.pxd

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,11 @@ cdef struct AVCodecPrivateData:
1616

1717

1818
cdef class VideoCodecContext(CodecContext):
19-
2019
cdef AVCodecPrivateData _private_data
21-
2220
cdef VideoFormat _format
2321
cdef _build_format(self)
24-
2522
cdef int last_w
2623
cdef int last_h
2724
cdef readonly VideoReformatter reformatter
28-
29-
# For encoding.
3025
cdef readonly int encoded_frame_count
31-
32-
# For decoding.
3326
cdef VideoFrame next_frame
Lines changed: 89 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,70 @@
1-
cimport libav as lib
2-
from libc.stdint cimport int64_t
3-
4-
from av.codec.context cimport CodecContext
5-
from av.codec.hwaccel cimport HWAccel, HWConfig
6-
from av.error cimport err_check
7-
from av.frame cimport Frame
8-
from av.packet cimport Packet
9-
from av.utils cimport avrational_to_fraction, to_avrational
10-
from av.video.format cimport VideoFormat, get_pix_fmt, get_video_format
11-
from av.video.frame cimport VideoFrame, alloc_video_frame
12-
from av.video.reformatter cimport VideoReformatter
13-
14-
15-
cdef lib.AVPixelFormat _get_hw_format(lib.AVCodecContext *ctx, const lib.AVPixelFormat *pix_fmts) noexcept:
1+
import cython
2+
import cython.cimports.libav as lib
3+
from cython.cimports.av.codec.context import CodecContext
4+
from cython.cimports.av.codec.hwaccel import HWAccel, HWConfig
5+
from cython.cimports.av.error import err_check
6+
from cython.cimports.av.frame import Frame
7+
from cython.cimports.av.packet import Packet
8+
from cython.cimports.av.utils import avrational_to_fraction, to_avrational
9+
from cython.cimports.av.video.format import VideoFormat, get_pix_fmt, get_video_format
10+
from cython.cimports.av.video.frame import VideoFrame, alloc_video_frame
11+
from cython.cimports.av.video.reformatter import VideoReformatter
12+
from cython.cimports.libc.stdint import int64_t
13+
14+
15+
@cython.cfunc
16+
@cython.exceptval(check=False)
17+
def _get_hw_format(
18+
ctx: cython.pointer[lib.AVCodecContext],
19+
pix_fmts: cython.pointer[cython.const[lib.AVPixelFormat]],
20+
) -> lib.AVPixelFormat:
1621
# In the case where we requested accelerated decoding, the decoder first calls this function
1722
# with a list that includes both the hardware format and software formats.
1823
# First we try to pick the hardware format if it's in the list.
1924
# However, if the decoder fails to initialize the hardware, it will call this function again,
2025
# with only software formats in pix_fmts. We return ctx->sw_pix_fmt regardless in this case,
2126
# because that should be in the candidate list. If not, we are out of ideas anyways.
22-
cdef AVCodecPrivateData* private_data = <AVCodecPrivateData*>ctx.opaque
23-
i = 0
27+
private_data: cython.pointer[AVCodecPrivateData] = cython.cast(
28+
cython.pointer[AVCodecPrivateData], ctx.opaque
29+
)
30+
i: cython.int = 0
2431
while pix_fmts[i] != -1:
2532
if pix_fmts[i] == private_data.hardware_pix_fmt:
2633
return pix_fmts[i]
2734
i += 1
28-
return ctx.sw_pix_fmt if private_data.allow_software_fallback else lib.AV_PIX_FMT_NONE
29-
35+
return (
36+
ctx.sw_pix_fmt if private_data.allow_software_fallback else lib.AV_PIX_FMT_NONE
37+
)
3038

31-
cdef class VideoCodecContext(CodecContext):
3239

40+
@cython.cclass
41+
class VideoCodecContext(CodecContext):
3342
def __cinit__(self, *args, **kwargs):
3443
self.last_w = 0
3544
self.last_h = 0
3645

37-
cdef _init(self, lib.AVCodecContext *ptr, const lib.AVCodec *codec, HWAccel hwaccel):
38-
CodecContext._init(self, ptr, codec, hwaccel) # TODO: Can this be `super`?
46+
@cython.cfunc
47+
def _init(
48+
self,
49+
ptr: cython.pointer[lib.AVCodecContext],
50+
codec: cython.pointer[cython.const[lib.AVCodec]],
51+
hwaccel: HWAccel | None,
52+
):
53+
CodecContext._init(self, ptr, codec, hwaccel)
3954

4055
if hwaccel is not None:
4156
try:
4257
self.hwaccel_ctx = hwaccel.create(self.codec)
4358
self.ptr.hw_device_ctx = lib.av_buffer_ref(self.hwaccel_ctx.ptr)
4459
self.ptr.pix_fmt = self.hwaccel_ctx.config.ptr.pix_fmt
4560
self.ptr.get_format = _get_hw_format
46-
self._private_data.hardware_pix_fmt = self.hwaccel_ctx.config.ptr.pix_fmt
47-
self._private_data.allow_software_fallback = self.hwaccel.allow_software_fallback
48-
self.ptr.opaque = &self._private_data
61+
self._private_data.hardware_pix_fmt = (
62+
self.hwaccel_ctx.config.ptr.pix_fmt
63+
)
64+
self._private_data.allow_software_fallback = (
65+
self.hwaccel.allow_software_fallback
66+
)
67+
self.ptr.opaque = cython.address(self._private_data)
4968
except NotImplementedError:
5069
# Some streams may not have a hardware decoder. For example, many action
5170
# cam videos have a low resolution mjpeg stream, which is usually not
@@ -60,20 +79,20 @@ def __cinit__(self, *args, **kwargs):
6079
self._build_format()
6180
self.encoded_frame_count = 0
6281

63-
cdef _prepare_frames_for_encode(self, Frame input):
64-
if not input:
82+
@cython.cfunc
83+
def _prepare_frames_for_encode(self, input: Frame | None) -> list:
84+
if input is None or not input:
6585
return [None]
6686

67-
cdef VideoFrame vframe = input
68-
6987
if self._format is None:
7088
raise ValueError("self._format is None, cannot encode")
7189

90+
vframe: VideoFrame = input
7291
# Reformat if it doesn't match.
7392
if (
74-
vframe.format.pix_fmt != self._format.pix_fmt or
75-
vframe.width != self.ptr.width or
76-
vframe.height != self.ptr.height
93+
vframe.format.pix_fmt != self._format.pix_fmt
94+
or vframe.width != self.ptr.width
95+
or vframe.height != self.ptr.height
7796
):
7897
if not self.reformatter:
7998
self.reformatter = VideoReformatter()
@@ -84,73 +103,74 @@ def __cinit__(self, *args, **kwargs):
84103

85104
# There is no pts, so create one.
86105
if vframe.ptr.pts == lib.AV_NOPTS_VALUE:
87-
vframe.ptr.pts = <int64_t>self.encoded_frame_count
106+
vframe.ptr.pts = cython.cast(int64_t, self.encoded_frame_count)
88107

89108
self.encoded_frame_count += 1
90-
91109
return [vframe]
92110

93-
cdef Frame _alloc_next_frame(self):
111+
@cython.cfunc
112+
def _alloc_next_frame(self) -> Frame:
94113
return alloc_video_frame()
95114

96-
cdef _setup_decoded_frame(self, Frame frame, Packet packet):
115+
@cython.cfunc
116+
def _setup_decoded_frame(self, frame: Frame, packet: Packet):
97117
CodecContext._setup_decoded_frame(self, frame, packet)
98-
cdef VideoFrame vframe = frame
118+
vframe: VideoFrame = frame
99119
vframe._init_user_attributes()
100120

101-
cdef _transfer_hwframe(self, Frame frame):
121+
@cython.cfunc
122+
def _transfer_hwframe(self, frame: Frame):
102123
if self.hwaccel_ctx is None:
103124
return frame
104-
105125
if frame.ptr.format != self.hwaccel_ctx.config.ptr.pix_fmt:
106126
# If we get a software frame, that means we are in software fallback mode, and don't actually
107127
# need to transfer.
108128
return frame
109129

110-
cdef Frame frame_sw
111-
112-
frame_sw = self._alloc_next_frame()
113-
130+
frame_sw: Frame = self._alloc_next_frame()
114131
err_check(lib.av_hwframe_transfer_data(frame_sw.ptr, frame.ptr, 0))
115-
116-
# TODO: Is there anything else to transfer?!
132+
# TODO: Is there anything else to transfer?
117133
frame_sw.pts = frame.pts
118-
119134
return frame_sw
120135

121-
cdef _build_format(self):
122-
self._format = get_video_format(<lib.AVPixelFormat>self.ptr.pix_fmt, self.ptr.width, self.ptr.height)
136+
@cython.cfunc
137+
def _build_format(self):
138+
self._format = get_video_format(
139+
cython.cast(lib.AVPixelFormat, self.ptr.pix_fmt),
140+
self.ptr.width,
141+
self.ptr.height,
142+
)
123143

124144
@property
125145
def format(self):
126146
return self._format
127147

128148
@format.setter
129-
def format(self, VideoFormat format):
149+
def format(self, format: VideoFormat):
130150
self.ptr.pix_fmt = format.pix_fmt
131151
self.ptr.width = format.width
132152
self.ptr.height = format.height
133153
self._build_format() # Kinda wasteful.
134154

135155
@property
136156
def width(self):
137-
if self.ptr is NULL:
157+
if self.ptr is cython.NULL:
138158
return 0
139159
return self.ptr.width
140160

141161
@width.setter
142-
def width(self, unsigned int value):
162+
def width(self, value: cython.uint):
143163
self.ptr.width = value
144164
self._build_format()
145165

146166
@property
147167
def height(self):
148-
if self.ptr is NULL:
168+
if self.ptr is cython.NULL:
149169
return 0
150170
return self.ptr.height
151171

152172
@height.setter
153-
def height(self, unsigned int value):
173+
def height(self, value: cython.uint):
154174
self.ptr.height = value
155175
self._build_format()
156176

@@ -160,13 +180,13 @@ def bits_per_coded_sample(self):
160180
The number of bits per sample in the codedwords. It's mandatory for this to be set for some formats to decode properly.
161181
162182
Wraps :ffmpeg:`AVCodecContext.bits_per_coded_sample`.
163-
183+
164184
:type: int
165185
"""
166186
return self.ptr.bits_per_coded_sample
167-
187+
168188
@bits_per_coded_sample.setter
169-
def bits_per_coded_sample(self, int value):
189+
def bits_per_coded_sample(self, value: cython.int):
170190
if self.is_encoder:
171191
raise ValueError("Not supported for encoders")
172192

@@ -194,11 +214,11 @@ def framerate(self):
194214
195215
:type: fractions.Fraction
196216
"""
197-
return avrational_to_fraction(&self.ptr.framerate)
217+
return avrational_to_fraction(cython.address(self.ptr.framerate))
198218

199219
@framerate.setter
200220
def framerate(self, value):
201-
to_avrational(value, &self.ptr.framerate)
221+
to_avrational(value, cython.address(self.ptr.framerate))
202222

203223
@property
204224
def rate(self):
@@ -213,37 +233,39 @@ def rate(self, value):
213233
def gop_size(self):
214234
"""
215235
Sets the number of frames between keyframes. Used only for encoding.
216-
236+
217237
:type: int
218238
"""
219239
if self.is_decoder:
220240
raise RuntimeError("Cannot access 'gop_size' as a decoder")
221241
return self.ptr.gop_size
222242

223243
@gop_size.setter
224-
def gop_size(self, int value):
244+
def gop_size(self, value: cython.int):
225245
if self.is_decoder:
226246
raise RuntimeError("Cannot access 'gop_size' as a decoder")
227247
self.ptr.gop_size = value
228248

229249
@property
230250
def sample_aspect_ratio(self):
231-
return avrational_to_fraction(&self.ptr.sample_aspect_ratio)
251+
return avrational_to_fraction(cython.address(self.ptr.sample_aspect_ratio))
232252

233253
@sample_aspect_ratio.setter
234254
def sample_aspect_ratio(self, value):
235-
to_avrational(value, &self.ptr.sample_aspect_ratio)
255+
to_avrational(value, cython.address(self.ptr.sample_aspect_ratio))
236256

237257
@property
238258
def display_aspect_ratio(self):
239-
cdef lib.AVRational dar
240-
259+
dar: lib.AVRational
241260
lib.av_reduce(
242-
&dar.num, &dar.den,
261+
cython.address(dar.num),
262+
cython.address(dar.den),
243263
self.ptr.width * self.ptr.sample_aspect_ratio.num,
244-
self.ptr.height * self.ptr.sample_aspect_ratio.den, 1024*1024)
264+
self.ptr.height * self.ptr.sample_aspect_ratio.den,
265+
1024 * 1024,
266+
)
245267

246-
return avrational_to_fraction(&dar)
268+
return avrational_to_fraction(cython.address(dar))
247269

248270
@property
249271
def has_b_frames(self):

0 commit comments

Comments
 (0)