File: layout.pyx

package info (click to toggle)
python-av 16.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,684 kB
  • sloc: python: 7,607; sh: 182; ansic: 174; makefile: 135
file content (82 lines) | stat: -rw-r--r-- 2,563 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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