Skip to content

Commit 213ff6a

Browse files
committed
Make container/input pure
1 parent 9e09e3c commit 213ff6a

File tree

1 file changed

+80
-61
lines changed

1 file changed

+80
-61
lines changed
Lines changed: 80 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,74 @@
1-
from libc.stdint cimport int64_t
2-
from libc.stdlib cimport free, malloc
3-
4-
from av.codec.context cimport CodecContext, wrap_codec_context
5-
from av.container.streams cimport StreamContainer
6-
from av.dictionary cimport _Dictionary
7-
from av.error cimport err_check
8-
from av.packet cimport Packet
9-
from av.stream cimport Stream, wrap_stream
10-
from av.utils cimport avdict_to_dict
1+
import cython
2+
from cython.cimports.av.codec.context import CodecContext, wrap_codec_context
3+
from cython.cimports.av.container.streams import StreamContainer
4+
from cython.cimports.av.dictionary import _Dictionary
5+
from cython.cimports.av.error import err_check
6+
from cython.cimports.av.packet import Packet
7+
from cython.cimports.av.stream import Stream, wrap_stream
8+
from cython.cimports.av.utils import avdict_to_dict
9+
from cython.cimports.libc.stdint import int64_t
10+
from cython.cimports.libc.stdlib import free, malloc
1111

1212
from av.dictionary import Dictionary
1313

1414

15-
cdef close_input(InputContainer self):
15+
@cython.cfunc
16+
def close_input(self: InputContainer):
1617
self.streams = StreamContainer()
1718
if self.input_was_opened:
18-
with nogil:
19+
with cython.nogil:
1920
# This causes `self.ptr` to be set to NULL.
20-
lib.avformat_close_input(&self.ptr)
21+
lib.avformat_close_input(cython.address(self.ptr))
2122
self.input_was_opened = False
2223

2324

24-
cdef class InputContainer(Container):
25+
@cython.cclass
26+
class InputContainer(Container):
2527
def __cinit__(self, *args, **kwargs):
26-
cdef CodecContext py_codec_context
27-
cdef unsigned int i
28-
cdef lib.AVStream *stream
29-
cdef lib.AVCodec *codec
30-
cdef lib.AVCodecContext *codec_context
28+
py_codec_context: CodecContext
29+
i: cython.uint
30+
stream: cython.pointer[lib.AVStream]
31+
codec: cython.pointer[lib.AVCodec]
32+
codec_context: cython.pointer[lib.AVCodecContext]
3133

3234
# If we have either the global `options`, or a `stream_options`, prepare
3335
# a mashup of those options for each stream.
34-
cdef lib.AVDictionary **c_options = NULL
35-
cdef _Dictionary base_dict, stream_dict
36+
c_options: cython.pointer[cython.pointer[lib.AVDictionary]] = cython.NULL
37+
base_dict: _Dictionary
38+
stream_dict: _Dictionary
3639
if self.options or self.stream_options:
3740
base_dict = Dictionary(self.options)
38-
c_options = <lib.AVDictionary**>malloc(self.ptr.nb_streams * sizeof(void*))
41+
c_options = cython.cast(
42+
cython.pointer[cython.pointer[lib.AVDictionary]],
43+
malloc(self.ptr.nb_streams * cython.sizeof(cython.p_void)),
44+
)
3945
for i in range(self.ptr.nb_streams):
40-
c_options[i] = NULL
46+
c_options[i] = cython.NULL
4147
if i < len(self.stream_options) and self.stream_options:
4248
stream_dict = base_dict.copy()
4349
stream_dict.update(self.stream_options[i])
44-
lib.av_dict_copy(&c_options[i], stream_dict.ptr, 0)
50+
lib.av_dict_copy(cython.address(c_options[i]), stream_dict.ptr, 0)
4551
else:
46-
lib.av_dict_copy(&c_options[i], base_dict.ptr, 0)
52+
lib.av_dict_copy(cython.address(c_options[i]), base_dict.ptr, 0)
4753

4854
self.set_timeout(self.open_timeout)
4955
self.start_timeout()
50-
with nogil:
56+
with cython.nogil:
5157
# This peeks are the first few frames to:
5258
# - set stream.disposition from codec.audio_service_type (not exposed);
5359
# - set stream.codec.bits_per_coded_sample;
5460
# - set stream.duration;
5561
# - set stream.start_time;
5662
# - set stream.r_frame_rate to average value;
5763
# - open and closes codecs with the options provided.
58-
ret = lib.avformat_find_stream_info(
59-
self.ptr,
60-
c_options
61-
)
64+
ret = lib.avformat_find_stream_info(self.ptr, c_options)
6265
self.set_timeout(None)
6366
self.err_check(ret)
6467

65-
# Cleanup all of our options.
68+
# Clean up all of our options.
6669
if c_options:
6770
for i in range(self.ptr.nb_streams):
68-
lib.av_dict_free(&c_options[i])
71+
lib.av_dict_free(cython.address(c_options[i]))
6972
free(c_options)
7073

7174
at_least_one_accelerated_context = False
@@ -75,22 +78,34 @@ def __cinit__(self, *args, **kwargs):
7578
stream = self.ptr.streams[i]
7679
codec = lib.avcodec_find_decoder(stream.codecpar.codec_id)
7780
if codec:
78-
# allocate and initialise decoder
81+
# allocate and initialize decoder
7982
codec_context = lib.avcodec_alloc_context3(codec)
80-
err_check(lib.avcodec_parameters_to_context(codec_context, stream.codecpar))
83+
err_check(
84+
lib.avcodec_parameters_to_context(codec_context, stream.codecpar)
85+
)
8186
codec_context.pkt_timebase = stream.time_base
82-
py_codec_context = wrap_codec_context(codec_context, codec, self.hwaccel)
87+
py_codec_context = wrap_codec_context(
88+
codec_context, codec, self.hwaccel
89+
)
8390
if py_codec_context.is_hwaccel:
8491
at_least_one_accelerated_context = True
8592
else:
8693
# no decoder is available
8794
py_codec_context = None
8895
self.streams.add_stream(wrap_stream(self, stream, py_codec_context))
8996

90-
if self.hwaccel and not self.hwaccel.allow_software_fallback and not at_least_one_accelerated_context:
91-
raise RuntimeError("Hardware accelerated decode requested but no stream is compatible")
97+
if (
98+
self.hwaccel
99+
and not self.hwaccel.allow_software_fallback
100+
and not at_least_one_accelerated_context
101+
):
102+
raise RuntimeError(
103+
"Hardware accelerated decode requested but no stream is compatible"
104+
)
92105

93-
self.metadata = avdict_to_dict(self.ptr.metadata, self.metadata_encoding, self.metadata_errors)
106+
self.metadata = avdict_to_dict(
107+
self.ptr.metadata, self.metadata_encoding, self.metadata_errors
108+
)
94109

95110
def __dealloc__(self):
96111
close_input(self)
@@ -141,19 +156,20 @@ def demux(self, *args, **kwargs):
141156
# For whatever reason, Cython does not like us directly passing kwargs
142157
# from one method to another. Without kwargs, it ends up passing a
143158
# NULL reference, which segfaults. So we force it to do something with it.
144-
# This is likely a bug in Cython; see https://github.com/cython/cython/issues/2166
145-
# (and others).
159+
# This is a bug in Cython; see https://github.com/cython/cython/issues/2166
146160
id(kwargs)
147161

148162
streams = self.streams.get(*args, **kwargs)
149-
150-
cdef bint *include_stream = <bint*>malloc(self.ptr.nb_streams * sizeof(bint))
151-
if include_stream == NULL:
163+
include_stream: cython.pointer[cython.bint] = cython.cast(
164+
cython.pointer[cython.bint],
165+
malloc(self.ptr.nb_streams * cython.sizeof(bint)),
166+
)
167+
if include_stream == cython.NULL:
152168
raise MemoryError()
153169

154-
cdef unsigned int i
155-
cdef Packet packet
156-
cdef int ret
170+
i: cython.uint
171+
packet: Packet
172+
ret: cython.int
157173

158174
self.set_timeout(self.read_timeout)
159175
try:
@@ -169,7 +185,7 @@ def demux(self, *args, **kwargs):
169185
packet = Packet()
170186
try:
171187
self.start_timeout()
172-
with nogil:
188+
with cython.nogil:
173189
ret = lib.av_read_frame(self.ptr, packet.ptr)
174190
self.err_check(ret)
175191
except EOFError:
@@ -217,8 +233,14 @@ def decode(self, *args, **kwargs):
217233
yield frame
218234

219235
def seek(
220-
self, offset, *, bint backward=True, bint any_frame=False, Stream stream=None,
221-
bint unsupported_frame_offset=False, bint unsupported_byte_offset=False
236+
self,
237+
offset,
238+
*,
239+
backward: bint = True,
240+
any_frame: bint = False,
241+
stream: Stream | None = None,
242+
unsupported_frame_offset: bint = False,
243+
unsupported_byte_offset: bint = False,
222244
):
223245
"""seek(offset, *, backward=True, any_frame=False, stream=None)
224246
@@ -249,16 +271,12 @@ def seek(
249271
"""
250272
self._assert_open()
251273

252-
# We used to take floats here and assume they were in seconds. This
253-
# was super confusing, so lets go in the complete opposite direction
254-
# and reject non-ints.
255274
if not isinstance(offset, int):
256275
raise TypeError("Container.seek only accepts integer offset.", type(offset))
257276

258-
cdef int64_t c_offset = offset
259-
260-
cdef int flags = 0
261-
cdef int ret
277+
c_offset: int64_t = offset
278+
flags: cython.int = 0
279+
ret: cython.int
262280

263281
if backward:
264282
flags |= lib.AVSEEK_FLAG_BACKWARD
@@ -271,18 +289,19 @@ def seek(
271289
if unsupported_byte_offset:
272290
flags |= lib.AVSEEK_FLAG_BYTE
273291

274-
cdef int stream_index = stream.index if stream else -1
275-
with nogil:
292+
stream_index: cython.int = stream.index if stream else -1
293+
with cython.nogil:
276294
ret = lib.av_seek_frame(self.ptr, stream_index, c_offset, flags)
277295
err_check(ret)
278296

279297
self.flush_buffers()
280298

281-
cdef flush_buffers(self):
299+
@cython.cfunc
300+
def flush_buffers(self):
282301
self._assert_open()
283302

284-
cdef Stream stream
285-
cdef CodecContext codec_context
303+
stream: Stream
304+
codec_context: CodecContext
286305

287306
for stream in self.streams:
288307
codec_context = stream.codec_context

0 commit comments

Comments
 (0)