Skip to content

Commit f72c83c

Browse files
committed
Make container/pyio pure
1 parent 4f5480e commit f72c83c

File tree

1 file changed

+81
-47
lines changed

1 file changed

+81
-47
lines changed
Lines changed: 81 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1-
cimport libav as lib
2-
from libc.string cimport memcpy
1+
# type: ignore
2+
import cython
3+
from cython import NULL
4+
from cython.cimports import libav as lib
5+
from cython.cimports.av.error import stash_exception
6+
from cython.cimports.libc.stdint import int64_t, uint8_t
7+
from cython.cimports.libc.string import memcpy
38

4-
from av.error cimport stash_exception
9+
Buf = cython.typedef(cython.pointer[uint8_t])
10+
BufC = cython.typedef(cython.pointer[cython.const[uint8_t]])
511

6-
ctypedef int64_t (*seek_func_t)(void *opaque, int64_t offset, int whence) noexcept nogil
12+
seek_func_t = cython.typedef(
13+
"int64_t (*seek_func_t)(void *opaque, int64_t offset, int whence) noexcept nogil"
14+
)
715

816

9-
cdef class PyIOFile:
17+
@cython.cclass
18+
class PyIOFile:
1019
def __cinit__(self, file, buffer_size, writeable=None):
1120
self.file = file
1221

13-
cdef seek_func_t seek_func = NULL
22+
seek_func: seek_func_t = NULL
1423

1524
readable = getattr(self.file, "readable", None)
1625
writable = getattr(self.file, "writable", None)
@@ -21,70 +30,81 @@ def __cinit__(self, file, buffer_size, writeable=None):
2130
self.ftell = getattr(self.file, "tell", None)
2231
self.fclose = getattr(self.file, "close", None)
2332

24-
# To be seekable the file object must have `seek` and `tell` methods.
33+
# To be seekable, the file object must have `seek` and `tell` methods.
2534
# If it also has a `seekable` method, it must return True.
2635
if (
2736
self.fseek is not None
2837
and self.ftell is not None
2938
and (seekable is None or seekable())
3039
):
31-
seek_func = pyio_seek
40+
seek_func: seek_func_t = pyio_seek
3241

3342
if writeable is None:
3443
writeable = self.fwrite is not None
3544

3645
if writeable:
3746
if self.fwrite is None or (writable is not None and not writable()):
38-
raise ValueError("File object has no write() method, or writable() returned False.")
47+
raise ValueError(
48+
"File object has no write() method, or writable() returned False."
49+
)
3950
else:
4051
if self.fread is None or (readable is not None and not readable()):
41-
raise ValueError("File object has no read() method, or readable() returned False.")
52+
raise ValueError(
53+
"File object has no read() method, or readable() returned False."
54+
)
4255

4356
self.pos = 0
4457
self.pos_is_valid = True
4558

4659
# This is effectively the maximum size of reads.
47-
self.buffer = <unsigned char*>lib.av_malloc(buffer_size)
60+
self.buffer = cython.cast(cython.p_uchar, lib.av_malloc(buffer_size))
4861

4962
self.iocontext = lib.avio_alloc_context(
5063
self.buffer,
5164
buffer_size,
5265
writeable,
53-
<void*>self, # User data.
66+
cython.cast(cython.p_void, self), # User data.
5467
pyio_read,
5568
pyio_write,
56-
seek_func
69+
seek_func,
5770
)
5871

5972
if seek_func:
6073
self.iocontext.seekable = lib.AVIO_SEEKABLE_NORMAL
6174
self.iocontext.max_packet_size = buffer_size
6275

6376
def __dealloc__(self):
64-
with nogil:
77+
with cython.nogil:
6578
# FFmpeg will not release custom input, so it's up to us to free it.
6679
# Do not touch our original buffer as it may have been freed and replaced.
6780
if self.iocontext:
68-
lib.av_freep(&self.iocontext.buffer)
69-
lib.av_freep(&self.iocontext)
81+
lib.av_freep(cython.address(self.iocontext.buffer))
82+
lib.av_freep(cython.address(self.iocontext))
7083

71-
# We likely errored badly if we got here, and so are still
72-
# responsible for our buffer.
84+
# We likely errored badly if we got here, and so we are still responsible.
7385
else:
74-
lib.av_freep(&self.buffer)
86+
lib.av_freep(cython.address(self.buffer))
7587

7688

77-
cdef int pyio_read(void *opaque, uint8_t *buf, int buf_size) noexcept nogil:
78-
with gil:
89+
@cython.cfunc
90+
@cython.nogil
91+
@cython.exceptval(check=False)
92+
def pyio_read(opaque: cython.p_void, buf: Buf, buf_size: cython.int) -> cython.int:
93+
with cython.gil:
7994
return pyio_read_gil(opaque, buf, buf_size)
8095

81-
cdef int pyio_read_gil(void *opaque, uint8_t *buf, int buf_size) noexcept:
82-
cdef PyIOFile self
83-
cdef bytes res
96+
97+
@cython.cfunc
98+
@cython.exceptval(check=False)
99+
def pyio_read_gil(opaque: cython.p_void, buf: Buf, buf_size: cython.int) -> cython.int:
100+
self: PyIOFile
101+
res: bytes
84102
try:
85-
self = <PyIOFile>opaque
103+
self = cython.cast(PyIOFile, opaque)
86104
res = self.fread(buf_size)
87-
memcpy(buf, <void*><char*>res, len(res))
105+
memcpy(
106+
buf, cython.cast(cython.p_void, cython.cast(cython.p_char, res)), len(res)
107+
)
88108
self.pos += len(res)
89109
if not res:
90110
return lib.AVERROR_EOF
@@ -93,16 +113,24 @@ def __dealloc__(self):
93113
return stash_exception()
94114

95115

96-
cdef int pyio_write(void *opaque, const uint8_t *buf, int buf_size) noexcept nogil:
97-
with gil:
116+
@cython.cfunc
117+
@cython.nogil
118+
@cython.exceptval(check=False)
119+
def pyio_write(opaque: cython.p_void, buf: BufC, buf_size: cython.int) -> cython.int:
120+
with cython.gil:
98121
return pyio_write_gil(opaque, buf, buf_size)
99122

100-
cdef int pyio_write_gil(void *opaque, const uint8_t *buf, int buf_size) noexcept:
101-
cdef PyIOFile self
102-
cdef bytes bytes_to_write
103-
cdef int bytes_written
123+
124+
@cython.cfunc
125+
@cython.exceptval(check=False)
126+
def pyio_write_gil(
127+
opaque: cython.p_void, buf: BufC, buf_size: cython.int
128+
) -> cython.int:
129+
self: PyIOFile
130+
bytes_to_write: bytes
131+
bytes_written: cython.int
104132
try:
105-
self = <PyIOFile>opaque
133+
self = cython.cast(PyIOFile, opaque)
106134
bytes_to_write = buf[:buf_size]
107135
ret_value = self.fwrite(bytes_to_write)
108136
bytes_written = ret_value if isinstance(ret_value, int) else buf_size
@@ -112,19 +140,25 @@ def __dealloc__(self):
112140
return stash_exception()
113141

114142

115-
cdef int64_t pyio_seek(void *opaque, int64_t offset, int whence) noexcept nogil:
116-
# Seek takes the standard flags, but also a ad-hoc one which means that
117-
# the library wants to know how large the file is. We are generally
118-
# allowed to ignore this.
143+
@cython.cfunc
144+
@cython.nogil
145+
@cython.exceptval(check=False)
146+
def pyio_seek(opaque: cython.p_void, offset: int64_t, whence: cython.int) -> int64_t:
147+
# Seek takes the standard flags, but also a ad-hoc one which means that the library
148+
# wants to know how large the file is. We are generally allowed to ignore this.
119149
if whence == lib.AVSEEK_SIZE:
120150
return -1
121-
with gil:
151+
with cython.gil:
122152
return pyio_seek_gil(opaque, offset, whence)
123153

124-
cdef int64_t pyio_seek_gil(void *opaque, int64_t offset, int whence):
125-
cdef PyIOFile self
154+
155+
@cython.cfunc
156+
def pyio_seek_gil(
157+
opaque: cython.p_void, offset: int64_t, whence: cython.int
158+
) -> int64_t:
159+
self: PyIOFile
126160
try:
127-
self = <PyIOFile>opaque
161+
self = cython.cast(PyIOFile, opaque)
128162
res = self.fseek(offset, whence)
129163

130164
# Track the position for the user.
@@ -144,18 +178,19 @@ def __dealloc__(self):
144178
return stash_exception()
145179

146180

147-
cdef int pyio_close_gil(lib.AVIOContext *pb):
181+
@cython.cfunc
182+
def pyio_close_gil(pb: cython.pointer[lib.AVIOContext]) -> cython.int:
148183
try:
149184
return lib.avio_close(pb)
150-
151185
except Exception:
152186
stash_exception()
153187

154188

155-
cdef int pyio_close_custom_gil(lib.AVIOContext *pb):
156-
cdef PyIOFile self
189+
@cython.cfunc
190+
def pyio_close_custom_gil(pb: cython.pointer[lib.AVIOContext]) -> cython.int:
191+
self: PyIOFile
157192
try:
158-
self = <PyIOFile>pb.opaque
193+
self = cython.cast(PyIOFile, pb.opaque)
159194

160195
# Flush bytes in the AVIOContext buffers to the custom I/O
161196
lib.avio_flush(pb)
@@ -164,6 +199,5 @@ def __dealloc__(self):
164199
self.fclose()
165200

166201
return 0
167-
168202
except Exception:
169203
stash_exception()

0 commit comments

Comments
 (0)