Skip to content

Commit 5dd54ea

Browse files
committed
Make audio/layout pure
1 parent dc51a11 commit 5dd54ea

4 files changed

Lines changed: 102 additions & 84 deletions

File tree

av/audio/layout.pxd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@ cimport libav as lib
33

44
cdef class AudioLayout:
55
cdef lib.AVChannelLayout layout
6-
cdef _init(self, lib.AVChannelLayout layout)
76

87
cdef AudioLayout get_audio_layout(lib.AVChannelLayout c_layout)

av/audio/layout.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from dataclasses import dataclass
2+
3+
import cython
4+
from cython.cimports import libav as lib
5+
from cython.cimports.cpython.bytes import PyBytes_FromStringAndSize
6+
7+
8+
@dataclass
9+
class AudioChannel:
10+
name: str
11+
description: str
12+
13+
def __repr__(self):
14+
return f"<av.AudioChannel '{self.name}' ({self.description})>"
15+
16+
17+
_cinit_bypass_sentinel = cython.declare(object, object())
18+
19+
20+
@cython.cfunc
21+
def get_audio_layout(c_layout: lib.AVChannelLayout) -> AudioLayout:
22+
"""Get an AudioLayout from Cython land."""
23+
layout: AudioLayout = AudioLayout(_cinit_bypass_sentinel)
24+
layout.layout = c_layout
25+
return layout
26+
27+
28+
@cython.cclass
29+
class AudioLayout:
30+
def __cinit__(self, layout):
31+
if layout is _cinit_bypass_sentinel:
32+
return
33+
34+
if type(layout) is str:
35+
ret = lib.av_channel_layout_from_string(cython.address(c_layout), layout)
36+
if ret != 0:
37+
raise ValueError(f"Invalid layout: {layout}")
38+
elif isinstance(layout, AudioLayout):
39+
c_layout = cython.cast(AudioLayout, layout).layout
40+
else:
41+
raise TypeError(
42+
f"layout must be of type: string | av.AudioLayout, got {type(layout)}"
43+
)
44+
45+
self.layout = c_layout
46+
47+
def __repr__(self):
48+
return f"<av.{self.__class__.__name__} {self.name!r}>"
49+
50+
def __eq__(self, other):
51+
return (
52+
isinstance(other, AudioLayout)
53+
and self.name == other.name
54+
and self.nb_channels == other.nb_channels
55+
)
56+
57+
@property
58+
def nb_channels(self):
59+
return self.layout.nb_channels
60+
61+
@property
62+
def channels(self):
63+
buf: cython.char[16]
64+
buf2: cython.char[128]
65+
66+
results: list = []
67+
for index in range(self.layout.nb_channels):
68+
size = lib.av_channel_name(
69+
buf,
70+
cython.sizeof(buf),
71+
lib.av_channel_layout_channel_from_index(
72+
cython.address(self.layout), index
73+
),
74+
)
75+
size2 = lib.av_channel_description(
76+
buf2,
77+
cython.sizeof(buf2),
78+
lib.av_channel_layout_channel_from_index(
79+
cython.address(self.layout), index
80+
),
81+
)
82+
results.append(
83+
AudioChannel(
84+
PyBytes_FromStringAndSize(buf, size - 1).decode("utf-8"),
85+
PyBytes_FromStringAndSize(buf2, size2 - 1).decode("utf-8"),
86+
)
87+
)
88+
89+
return tuple(results)
90+
91+
@property
92+
def name(self) -> str:
93+
"""The canonical name of the audio layout."""
94+
layout_name: cython.char[129]
95+
ret: cython.int = lib.av_channel_layout_describe(
96+
cython.address(self.layout), layout_name, cython.sizeof(layout_name)
97+
)
98+
if ret < 0:
99+
raise RuntimeError(f"Failed to get layout name: {ret}")
100+
101+
return layout_name

av/audio/layout.pyx

Lines changed: 0 additions & 82 deletions
This file was deleted.

av/dictionary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def __iter__(self):
4343
yield element.key
4444

4545
def __repr__(self):
46-
return f"bv.Dictionary({dict(self)!r})"
46+
return f"av.Dictionary({dict(self)!r})"
4747

4848
def copy(self):
4949
other = cython.declare(_Dictionary, Dictionary())

0 commit comments

Comments
 (0)