Voice et bot modif

This commit is contained in:
pi 2026-06-16 17:09:34 +00:00
parent 189d56026b
commit 7333a22bcd
10774 changed files with 634644 additions and 933308 deletions

View file

@ -1,2 +1,2 @@
from .frame import AudioFrame
from .stream import AudioStream
from .frame import AudioFrame as AudioFrame
from .stream import AudioStream as AudioStream

View file

@ -7,10 +7,11 @@ from cython.cimports.av.frame import Frame
from cython.cimports.av.packet import Packet
@cython.final
@cython.cclass
class AudioCodecContext(CodecContext):
@cython.cfunc
def _prepare_frames_for_encode(self, input_frame: Frame | None):
def _prepare_frames_for_encode(self, input_frame: Frame | None) -> list:
frame: AudioFrame | None = input_frame
allow_var_frame_size: cython.bint = (
self.ptr.codec.capabilities & lib.AV_CODEC_CAP_VARIABLE_FRAME_SIZE

Binary file not shown.

View file

@ -1,8 +1,11 @@
from av.audio.frame cimport alloc_audio_frame
from av.error cimport err_check
import cython
from cython.cimports.av.audio.frame import alloc_audio_frame
from cython.cimports.av.error import err_check
cdef class AudioFifo:
@cython.final
@cython.cclass
class AudioFifo:
"""A simple audio sample FIFO (First In First Out) buffer."""
def __repr__(self):
@ -22,7 +25,8 @@ cdef class AudioFifo:
if self.ptr:
lib.av_audio_fifo_free(self.ptr)
cpdef write(self, AudioFrame frame):
@cython.ccall
def write(self, frame: AudioFrame | None):
"""write(frame)
Push a frame of samples into the queue.
@ -45,7 +49,6 @@ cdef class AudioFifo:
return
if not self.ptr:
# Hold onto a copy of the attributes of the first frame to populate
# output frames with.
self.template = alloc_audio_frame()
@ -60,9 +63,10 @@ cdef class AudioFifo:
self.pts_per_sample = 0
self.ptr = lib.av_audio_fifo_alloc(
<lib.AVSampleFormat>frame.ptr.format,
cython.cast(lib.AVSampleFormat, frame.ptr.format),
frame.layout.nb_channels,
frame.ptr.nb_samples * 2, # Just a default number of samples; it will adjust.
frame.ptr.nb_samples
* 2, # Just a default number of samples; it will adjust.
)
if not self.ptr:
@ -70,34 +74,43 @@ cdef class AudioFifo:
# Make sure nothing changed.
elif (
frame.ptr.format != self.template.ptr.format or
# TODO: frame.ptr.ch_layout != self.template.ptr.ch_layout or
frame.ptr.sample_rate != self.template.ptr.sample_rate or
(frame._time_base.num and self.template._time_base.num and (
frame._time_base.num != self.template._time_base.num or
frame._time_base.den != self.template._time_base.den
))
frame.ptr.format != self.template.ptr.format
or frame.ptr.sample_rate != self.template.ptr.sample_rate
or (
frame._time_base.num
and self.template._time_base.num
and (
frame._time_base.num != self.template._time_base.num
or frame._time_base.den != self.template._time_base.den
)
)
):
raise ValueError("Frame does not match AudioFifo parameters.")
# Assert that the PTS are what we expect.
cdef int64_t expected_pts
expected_pts = cython.declare(int64_t)
if self.pts_per_sample and frame.ptr.pts != lib.AV_NOPTS_VALUE:
expected_pts = <int64_t>(self.pts_per_sample * self.samples_written)
expected_pts = cython.cast(
int64_t, self.pts_per_sample * self.samples_written
)
if frame.ptr.pts != expected_pts:
raise ValueError(
"Frame.pts (%d) != expected (%d); fix or set to None." % (frame.ptr.pts, expected_pts)
"Frame.pts (%d) != expected (%d); fix or set to None."
% (frame.ptr.pts, expected_pts)
)
err_check(lib.av_audio_fifo_write(
self.ptr,
<void **>frame.ptr.extended_data,
frame.ptr.nb_samples,
))
err_check(
lib.av_audio_fifo_write(
self.ptr,
cython.cast(cython.pointer[cython.p_void], frame.ptr.extended_data),
frame.ptr.nb_samples,
)
)
self.samples_written += frame.ptr.nb_samples
cpdef read(self, int samples=0, bint partial=False):
@cython.ccall
def read(self, samples: cython.int = 0, partial: cython.bint = False):
"""read(samples=0, partial=False)
Read samples from the queue.
@ -115,7 +128,7 @@ cdef class AudioFifo:
if not self.ptr:
return
cdef int buffered_samples = lib.av_audio_fifo_size(self.ptr)
buffered_samples: cython.int = lib.av_audio_fifo_size(self.ptr)
if buffered_samples < 1:
return
@ -127,31 +140,35 @@ cdef class AudioFifo:
else:
return
cdef AudioFrame frame = alloc_audio_frame()
frame: AudioFrame = alloc_audio_frame()
frame._copy_internal_attributes(self.template)
frame._init(
<lib.AVSampleFormat>self.template.ptr.format,
<lib.AVChannelLayout>self.template.ptr.ch_layout,
cython.cast(lib.AVSampleFormat, self.template.ptr.format),
cython.cast(lib.AVChannelLayout, self.template.ptr.ch_layout),
samples,
1, # Align?
)
err_check(lib.av_audio_fifo_read(
self.ptr,
<void **>frame.ptr.extended_data,
samples,
))
err_check(
lib.av_audio_fifo_read(
self.ptr,
cython.cast(cython.pointer[cython.p_void], frame.ptr.extended_data),
samples,
)
)
if self.pts_per_sample:
frame.ptr.pts = <uint64_t>(self.pts_per_sample * self.samples_read)
frame.ptr.pts = cython.cast(
uint64_t, self.pts_per_sample * self.samples_read
)
else:
frame.ptr.pts = lib.AV_NOPTS_VALUE
self.samples_read += samples
return frame
cpdef read_many(self, int samples, bint partial=False):
@cython.ccall
def read_many(self, samples: cython.int, partial: cython.bint = False):
"""read_many(samples, partial=False)
Read as many frames as we can.
@ -162,8 +179,8 @@ cdef class AudioFifo:
"""
cdef AudioFrame frame
frames = []
frame: AudioFrame
frames: list = []
while True:
frame = self.read(samples, partial=partial)
if frame is not None:
@ -177,18 +194,26 @@ cdef class AudioFifo:
def format(self):
"""The :class:`.AudioFormat` of this FIFO."""
if not self.ptr:
raise AttributeError(f"'{__name__}.AudioFifo' object has no attribute 'format'")
raise AttributeError(
f"'{__name__}.AudioFifo' object has no attribute 'format'"
)
return self.template.format
@property
def layout(self):
"""The :class:`.AudioLayout` of this FIFO."""
if not self.ptr:
raise AttributeError(f"'{__name__}.AudioFifo' object has no attribute 'layout'")
raise AttributeError(
f"'{__name__}.AudioFifo' object has no attribute 'layout'"
)
return self.template.layout
@property
def sample_rate(self):
if not self.ptr:
raise AttributeError(f"'{__name__}.AudioFifo' object has no attribute 'sample_rate'")
raise AttributeError(
f"'{__name__}.AudioFifo' object has no attribute 'sample_rate'"
)
return self.template.sample_rate
@property

Binary file not shown.

View file

@ -2,8 +2,10 @@ import sys
import cython
container_format_postfix: str = "le" if sys.byteorder == "little" else "be"
_cinit_bypass_sentinel = object()
container_format_postfix = cython.declare(
str, "le" if sys.byteorder == "little" else "be"
)
_cinit_bypass_sentinel = cython.declare(object, object())
@cython.cfunc
@ -18,6 +20,7 @@ def get_audio_format(c_format: lib.AVSampleFormat) -> AudioFormat:
return format
@cython.final
@cython.cclass
class AudioFormat:
"""Descriptor of audio formats."""

Binary file not shown.

View file

@ -5,7 +5,7 @@ from cython.cimports.av.audio.plane import AudioPlane
from cython.cimports.av.error import err_check
from cython.cimports.av.utils import check_ndarray
_cinit_bypass_sentinel = object()
_cinit_bypass_sentinel = cython.declare(object, object())
@cython.cfunc
@ -27,6 +27,7 @@ format_dtypes = {
}
@cython.final
@cython.cclass
class AudioFrame(Frame):
"""A frame of audio."""

Binary file not shown.

View file

@ -3,6 +3,5 @@ cimport libav as lib
cdef class AudioLayout:
cdef lib.AVChannelLayout layout
cdef _init(self, lib.AVChannelLayout layout)
cdef AudioLayout get_audio_layout(lib.AVChannelLayout c_layout)

View file

@ -0,0 +1,109 @@
from dataclasses import dataclass
import cython
from cython.cimports import libav as lib
from cython.cimports.cpython.bytes import PyBytes_FromStringAndSize
@dataclass
class AudioChannel:
name: str
description: str
def __repr__(self):
return f"<av.AudioChannel '{self.name}' ({self.description})>"
_cinit_bypass_sentinel = cython.declare(object, object())
@cython.cfunc
def get_audio_layout(c_layout: lib.AVChannelLayout) -> AudioLayout:
"""Get an AudioLayout from Cython land."""
layout: AudioLayout = AudioLayout(_cinit_bypass_sentinel)
layout.layout = c_layout
return layout
@cython.final
@cython.cclass
class AudioLayout:
def __dealloc__(self):
lib.av_channel_layout_uninit(cython.address(self.layout))
def __cinit__(self, layout):
if layout is _cinit_bypass_sentinel:
return
if type(layout) is str:
ret = lib.av_channel_layout_from_string(cython.address(c_layout), layout)
if ret != 0:
raise ValueError(f"Invalid layout: {layout}")
elif isinstance(layout, AudioLayout):
c_layout = cython.cast(AudioLayout, layout).layout
else:
raise TypeError(
f"layout must be of type: string | av.AudioLayout, got {type(layout)}"
)
self.layout = c_layout
def __repr__(self):
return f"<av.{self.__class__.__name__} {self.name!r}>"
def __eq__(self, other):
if not isinstance(other, AudioLayout):
return False
c_other: lib.AVChannelLayout = cython.cast(AudioLayout, other).layout
return (
lib.av_channel_layout_compare(
cython.address(self.layout), cython.address(c_other)
)
== 0
)
@property
def nb_channels(self):
return self.layout.nb_channels
@property
def channels(self):
buf: cython.char[16]
buf2: cython.char[128]
results: list = []
for index in range(self.layout.nb_channels):
size = lib.av_channel_name(
buf,
cython.sizeof(buf),
lib.av_channel_layout_channel_from_index(
cython.address(self.layout), index
),
)
size2 = lib.av_channel_description(
buf2,
cython.sizeof(buf2),
lib.av_channel_layout_channel_from_index(
cython.address(self.layout), index
),
)
results.append(
AudioChannel(
PyBytes_FromStringAndSize(buf, size - 1).decode("utf-8"),
PyBytes_FromStringAndSize(buf2, size2 - 1).decode("utf-8"),
)
)
return tuple(results)
@property
def name(self) -> str:
"""The canonical name of the audio layout."""
layout_name: cython.char[129]
ret: cython.int = lib.av_channel_layout_describe(
cython.address(self.layout), layout_name, cython.sizeof(layout_name)
)
if ret < 0:
raise RuntimeError(f"Failed to get layout name: {ret}")
return layout_name

View file

@ -1,82 +0,0 @@
cimport libav as lib
from cpython.bytes cimport PyBytes_FromStringAndSize
from dataclasses import dataclass
@dataclass
class AudioChannel:
name: str
description: str
def __repr__(self):
return f"<av.AudioChannel '{self.name}' ({self.description})>"
cdef object _cinit_bypass_sentinel
cdef AudioLayout get_audio_layout(lib.AVChannelLayout c_layout):
"""Get an AudioLayout from Cython land."""
cdef AudioLayout layout = AudioLayout.__new__(AudioLayout, _cinit_bypass_sentinel)
layout._init(c_layout)
return layout
cdef class AudioLayout:
def __init__(self, layout):
if layout is _cinit_bypass_sentinel:
return
if type(layout) is str:
ret = lib.av_channel_layout_from_string(&c_layout, layout)
if ret != 0:
raise ValueError(f"Invalid layout: {layout}")
elif isinstance(layout, AudioLayout):
c_layout = (<AudioLayout>layout).layout
else:
raise TypeError(f"layout must be of type: string | av.AudioLayout, got {type(layout)}")
self._init(c_layout)
cdef _init(self, lib.AVChannelLayout layout):
self.layout = layout
def __repr__(self):
return f"<av.{self.__class__.__name__} {self.name!r}>"
def __eq__(self, other):
return isinstance(other, AudioLayout) and self.name == other.name and self.nb_channels == other.nb_channels
@property
def nb_channels(self):
return self.layout.nb_channels
@property
def channels(self):
cdef char buf[16]
cdef char buf2[128]
results = []
for index in range(self.layout.nb_channels):
size = lib.av_channel_name(buf, sizeof(buf), lib.av_channel_layout_channel_from_index(&self.layout, index)) - 1
size2 = lib.av_channel_description(buf2, sizeof(buf2), lib.av_channel_layout_channel_from_index(&self.layout, index)) - 1
results.append(
AudioChannel(
PyBytes_FromStringAndSize(buf, size).decode("utf-8"),
PyBytes_FromStringAndSize(buf2, size2).decode("utf-8"),
)
)
return tuple(results)
@property
def name(self) -> str:
"""The canonical name of the audio layout."""
cdef char layout_name[128]
cdef int ret
ret = lib.av_channel_layout_describe(&self.layout, layout_name, sizeof(layout_name))
if ret < 0:
raise RuntimeError(f"Failed to get layout name: {ret}")
return layout_name

Binary file not shown.

View file

@ -2,6 +2,7 @@ import cython
from cython.cimports.av.audio.frame import AudioFrame
@cython.final
@cython.cclass
class AudioPlane(Plane):
def __cinit__(self, frame: AudioFrame, index: cython.int):

Binary file not shown.

View file

@ -1,12 +1,12 @@
from errno import EAGAIN
import cython
from cython.cimports.av.filter.context import FilterContext
from cython.cimports.av.filter.graph import Graph
from av.error import FFmpegError
@cython.final
@cython.cclass
class AudioResampler:
"""AudioResampler(format=None, layout=None, rate=None)

Binary file not shown.

View file

@ -3,9 +3,12 @@ from cython.cimports.av.audio.frame import AudioFrame
from cython.cimports.av.packet import Packet
@cython.final
@cython.cclass
class AudioStream(Stream):
def __repr__(self):
if self.codec_context is None:
return f"<av.AudioStream #{self.index} audio/<nocodec> at 0x{id(self):x}>"
form = self.format.name if self.format else None
return (
f"<av.AudioStream #{self.index} {self.name} at {self.rate}Hz,"
@ -13,6 +16,10 @@ class AudioStream(Stream):
)
def __getattr__(self, name):
if self.codec_context is None:
raise AttributeError(
f"'{type(self).__name__}' object has no attribute '{name}'"
)
return getattr(self.codec_context, name)
@cython.ccall