1- from av.audio.frame cimport alloc_audio_frame
2- from av.error cimport err_check
1+ import cython
2+ from cython .cimports .av .audio .frame import alloc_audio_frame
3+ from cython .cimports .av .error import err_check
34
45
5- cdef class AudioFifo:
6+ @cython .cclass
7+ class AudioFifo :
68 """A simple audio sample FIFO (First In First Out) buffer."""
79
810 def __repr__ (self ):
@@ -22,7 +24,8 @@ def __dealloc__(self):
2224 if self .ptr :
2325 lib .av_audio_fifo_free (self .ptr )
2426
25- cpdef write(self , AudioFrame frame):
27+ @cython .ccall
28+ def write (self , frame : AudioFrame | None ):
2629 """write(frame)
2730
2831 Push a frame of samples into the queue.
@@ -45,7 +48,6 @@ def __dealloc__(self):
4548 return
4649
4750 if not self .ptr :
48-
4951 # Hold onto a copy of the attributes of the first frame to populate
5052 # output frames with.
5153 self .template = alloc_audio_frame ()
@@ -60,44 +62,54 @@ def __dealloc__(self):
6062 self .pts_per_sample = 0
6163
6264 self .ptr = lib .av_audio_fifo_alloc (
63- < lib.AVSampleFormat> frame.ptr.format,
65+ cython . cast ( lib .AVSampleFormat , frame .ptr .format ) ,
6466 frame .layout .nb_channels ,
65- frame.ptr.nb_samples * 2 , # Just a default number of samples; it will adjust.
67+ frame .ptr .nb_samples
68+ * 2 , # Just a default number of samples; it will adjust.
6669 )
6770
6871 if not self .ptr :
6972 raise RuntimeError ("Could not allocate AVAudioFifo." )
7073
7174 # Make sure nothing changed.
7275 elif (
73- frame.ptr.format != self .template.ptr.format or
74- # TODO: frame.ptr.ch_layout != self.template.ptr.ch_layout or
75- frame.ptr.sample_rate != self .template.ptr.sample_rate or
76- (frame._time_base.num and self .template._time_base.num and (
77- frame._time_base.num != self .template._time_base.num or
78- frame._time_base.den != self .template._time_base.den
79- ))
76+ frame .ptr .format != self .template .ptr .format
77+ or frame .ptr .sample_rate != self .template .ptr .sample_rate
78+ or (
79+ frame ._time_base .num
80+ and self .template ._time_base .num
81+ and (
82+ frame ._time_base .num != self .template ._time_base .num
83+ or frame ._time_base .den != self .template ._time_base .den
84+ )
85+ )
8086 ):
8187 raise ValueError ("Frame does not match AudioFifo parameters." )
8288
8389 # Assert that the PTS are what we expect.
84- cdef int64_t expected_pts
90+ expected_pts = cython . declare ( int64_t )
8591 if self .pts_per_sample and frame .ptr .pts != lib .AV_NOPTS_VALUE :
86- expected_pts = < int64_t> (self .pts_per_sample * self .samples_written)
92+ expected_pts = cython .cast (
93+ int64_t , self .pts_per_sample * self .samples_written
94+ )
8795 if frame .ptr .pts != expected_pts :
8896 raise ValueError (
89- " Frame.pts (%d ) != expected (%d ); fix or set to None." % (frame.ptr.pts, expected_pts)
97+ "Frame.pts (%d) != expected (%d); fix or set to None."
98+ % (frame .ptr .pts , expected_pts )
9099 )
91100
92- err_check(lib.av_audio_fifo_write(
93- self .ptr,
94- < void ** > frame.ptr.extended_data,
95- frame.ptr.nb_samples,
96- ))
101+ err_check (
102+ lib .av_audio_fifo_write (
103+ self .ptr ,
104+ cython .cast (cython .pointer [cython .p_void ], frame .ptr .extended_data ),
105+ frame .ptr .nb_samples ,
106+ )
107+ )
97108
98109 self .samples_written += frame .ptr .nb_samples
99110
100- cpdef read(self , int samples = 0 , bint partial = False ):
111+ @cython .ccall
112+ def read (self , samples : cython .int = 0 , partial : cython .bint = False ):
101113 """read(samples=0, partial=False)
102114
103115 Read samples from the queue.
@@ -115,7 +127,7 @@ def __dealloc__(self):
115127 if not self .ptr :
116128 return
117129
118- cdef int buffered_samples = lib.av_audio_fifo_size(self .ptr)
130+ buffered_samples : cython . int = lib .av_audio_fifo_size (self .ptr )
119131 if buffered_samples < 1 :
120132 return
121133
@@ -127,31 +139,35 @@ def __dealloc__(self):
127139 else :
128140 return
129141
130- cdef AudioFrame frame = alloc_audio_frame()
142+ frame : AudioFrame = alloc_audio_frame ()
131143 frame ._copy_internal_attributes (self .template )
132144 frame ._init (
133- < lib.AVSampleFormat> self .template.ptr.format,
134- < lib.AVChannelLayout> self .template.ptr.ch_layout,
145+ cython . cast ( lib .AVSampleFormat , self .template .ptr .format ) ,
146+ cython . cast ( lib .AVChannelLayout , self .template .ptr .ch_layout ) ,
135147 samples ,
136148 1 , # Align?
137149 )
138150
139- err_check(lib.av_audio_fifo_read(
140- self .ptr,
141- < void ** > frame.ptr.extended_data,
142- samples,
143- ))
151+ err_check (
152+ lib .av_audio_fifo_read (
153+ self .ptr ,
154+ cython .cast (cython .pointer [cython .p_void ], frame .ptr .extended_data ),
155+ samples ,
156+ )
157+ )
144158
145159 if self .pts_per_sample :
146- frame.ptr.pts = < uint64_t> (self .pts_per_sample * self .samples_read)
160+ frame .ptr .pts = cython .cast (
161+ uint64_t , self .pts_per_sample * self .samples_read
162+ )
147163 else :
148164 frame .ptr .pts = lib .AV_NOPTS_VALUE
149165
150166 self .samples_read += samples
151-
152167 return frame
153168
154- cpdef read_many(self , int samples, bint partial = False ):
169+ @cython .ccall
170+ def read_many (self , samples : cython .int , partial : cython .bint = False ):
155171 """read_many(samples, partial=False)
156172
157173 Read as many frames as we can.
@@ -162,8 +178,8 @@ def __dealloc__(self):
162178
163179 """
164180
165- cdef AudioFrame frame
166- frames = []
181+ frame : AudioFrame
182+ frames : list = []
167183 while True :
168184 frame = self .read (samples , partial = partial )
169185 if frame is not None :
@@ -176,19 +192,15 @@ def __dealloc__(self):
176192 @property
177193 def format (self ):
178194 """The :class:`.AudioFormat` of this FIFO."""
179- if not self .ptr:
180- raise AttributeError (f" '{__name__}.AudioFifo' object has no attribute 'format'" )
181195 return self .template .format
196+
182197 @property
183198 def layout (self ):
184199 """The :class:`.AudioLayout` of this FIFO."""
185- if not self .ptr:
186- raise AttributeError (f" '{__name__}.AudioFifo' object has no attribute 'layout'" )
187200 return self .template .layout
201+
188202 @property
189203 def sample_rate (self ):
190- if not self .ptr:
191- raise AttributeError (f" '{__name__}.AudioFifo' object has no attribute 'sample_rate'" )
192204 return self .template .sample_rate
193205
194206 @property
0 commit comments