82 lines
2.5 KiB
Cython
82 lines
2.5 KiB
Cython
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 |