From 99a3695c603f90c0c0bc7c8eeb7ad0edf3683446 Mon Sep 17 00:00:00 2001 From: WyattBlue Date: Mon, 23 Jun 2025 20:22:51 -0400 Subject: [PATCH] Make audio/resampler pure --- av/audio/{frame.pyx => frame.py} | 0 av/audio/resampler.pxd | 5 +-- av/audio/{resampler.pyx => resampler.py} | 53 +++++++++++++----------- 3 files changed, 29 insertions(+), 29 deletions(-) rename av/audio/{frame.pyx => frame.py} (100%) rename av/audio/{resampler.pyx => resampler.py} (76%) diff --git a/av/audio/frame.pyx b/av/audio/frame.py similarity index 100% rename from av/audio/frame.pyx rename to av/audio/frame.py diff --git a/av/audio/resampler.pxd b/av/audio/resampler.pxd index d3601403d..20b74186e 100644 --- a/av/audio/resampler.pxd +++ b/av/audio/resampler.pxd @@ -5,9 +5,7 @@ from av.filter.graph cimport Graph cdef class AudioResampler: - cdef readonly bint is_passthrough - cdef AudioFrame template # Destination descriptors @@ -17,5 +15,4 @@ cdef class AudioResampler: cdef readonly unsigned int frame_size cdef Graph graph - - cpdef resample(self, AudioFrame) + cpdef list resample(self, AudioFrame) diff --git a/av/audio/resampler.pyx b/av/audio/resampler.py similarity index 76% rename from av/audio/resampler.pyx rename to av/audio/resampler.py index 69d790bad..d56ec06ed 100644 --- a/av/audio/resampler.pyx +++ b/av/audio/resampler.py @@ -1,12 +1,14 @@ -from av.filter.context cimport FilterContext +from errno import EAGAIN -import errno +import cython +from cython.cimports.av.filter.context import FilterContext +from cython.cimports.av.filter.graph import Graph -import av.filter +from av.error import FFmpegError -cdef class AudioResampler: - +@cython.cclass +class AudioResampler: """AudioResampler(format=None, layout=None, rate=None) :param AudioFormat format: The target format, or string that parses to one @@ -14,23 +16,23 @@ :param AudioLayout layout: The target layout, or an int/string that parses to one (e.g. ``"stereo"``). :param int rate: The target sample rate. - - """ def __cinit__(self, format=None, layout=None, rate=None, frame_size=None): if format is not None: - self.format = format if isinstance(format, AudioFormat) else AudioFormat(format) + self.format = ( + format if isinstance(format, AudioFormat) else AudioFormat(format) + ) if layout is not None: self.layout = AudioLayout(layout) - self.rate = int(rate) if rate else 0 + self.rate = int(rate) if rate else 0 self.frame_size = int(frame_size) if frame_size else 0 - self.graph = None - cpdef resample(self, AudioFrame frame): + @cython.ccall + def resample(self, frame: AudioFrame | None) -> list: """resample(frame) Convert the ``sample_rate``, ``channel_layout`` and/or ``format`` of @@ -60,30 +62,31 @@ def __cinit__(self, format=None, layout=None, rate=None, frame_size=None): # Check if we can passthrough or if there is actually work to do. if ( - frame.format.sample_fmt == self.format.sample_fmt and - frame.layout == self.layout and - frame.sample_rate == self.rate and - self.frame_size == 0 + frame.format.sample_fmt == self.format.sample_fmt + and frame.layout == self.layout + and frame.sample_rate == self.rate + and self.frame_size == 0 ): self.is_passthrough = True return [frame] # handle resampling with aformat filter # (similar to configure_output_audio_filter from ffmpeg) - self.graph = av.filter.Graph() + self.graph = Graph() extra_args = {} if frame.time_base is not None: - extra_args["time_base"] = str(frame.time_base) + extra_args["time_base"] = f"{frame.time_base}" + abuffer = self.graph.add( "abuffer", - sample_rate=str(frame.sample_rate), + sample_rate=f"{frame.sample_rate}", sample_fmt=AudioFormat(frame.format).name, channel_layout=frame.layout.name, **extra_args, ) aformat = self.graph.add( "aformat", - sample_rates=str(self.rate), + sample_rates=f"{self.rate}", sample_fmts=self.format.name, channel_layouts=self.layout.name, ) @@ -97,22 +100,22 @@ def __cinit__(self, format=None, layout=None, rate=None, frame_size=None): if frame is not None: if ( - frame.format.sample_fmt != self.template.format.sample_fmt or - frame.layout != self.template.layout or - frame.sample_rate != self.template.rate + frame.format.sample_fmt != self.template.format.sample_fmt + or frame.layout != self.template.layout + or frame.sample_rate != self.template.rate ): raise ValueError("Frame does not match AudioResampler setup.") self.graph.push(frame) - output = [] + output: list = [] while True: try: output.append(self.graph.pull()) except EOFError: break - except av.FFmpegError as e: - if e.errno != errno.EAGAIN: + except FFmpegError as e: + if e.errno != EAGAIN: raise break