File: format.py

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 (142 lines) | stat: -rw-r--r-- 3,569 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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import sys

import cython

container_format_postfix: str = "le" if sys.byteorder == "little" else "be"
_cinit_bypass_sentinel = object()


@cython.cfunc
def get_audio_format(c_format: lib.AVSampleFormat) -> AudioFormat:
    """Get an AudioFormat without going through a string."""

    if c_format < 0:
        return None

    format: AudioFormat = AudioFormat(_cinit_bypass_sentinel)
    format.sample_fmt = c_format
    return format


@cython.cclass
class AudioFormat:
    """Descriptor of audio formats."""

    def __cinit__(self, name):
        if name is _cinit_bypass_sentinel:
            return

        sample_fmt: lib.AVSampleFormat
        if isinstance(name, AudioFormat):
            sample_fmt = cython.cast(AudioFormat, name).sample_fmt
        else:
            sample_fmt = lib.av_get_sample_fmt(name)

        if sample_fmt < 0:
            raise ValueError(f"Not a sample format: {name!r}")

        self.sample_fmt = sample_fmt

    def __repr__(self):
        return f"<av.AudioFormat {self.name}>"

    @property
    def name(self):
        """Canonical name of the sample format.

        >>> AudioFormat('s16p').name
        's16p'

        """
        return lib.av_get_sample_fmt_name(self.sample_fmt)

    @property
    def bytes(self):
        """Number of bytes per sample.

        >>> AudioFormat('s16p').bytes
        2

        """
        return lib.av_get_bytes_per_sample(self.sample_fmt)

    @property
    def bits(self):
        """Number of bits per sample.

        >>> AudioFormat('s16p').bits
        16

        """
        return lib.av_get_bytes_per_sample(self.sample_fmt) << 3

    @property
    def is_planar(self):
        """Is this a planar format?

        Strictly opposite of :attr:`is_packed`.

        """
        return bool(lib.av_sample_fmt_is_planar(self.sample_fmt))

    @property
    def is_packed(self):
        """Is this a packed format?

        Strictly opposite of :attr:`is_planar`.

        """
        return not lib.av_sample_fmt_is_planar(self.sample_fmt)

    @property
    def planar(self):
        """The planar variant of this format.

        Is itself when planar:

        >>> fmt = AudioFormat('s16p')
        >>> fmt.planar is fmt
        True

        """
        if self.is_planar:
            return self
        return get_audio_format(lib.av_get_planar_sample_fmt(self.sample_fmt))

    @property
    def packed(self):
        """The packed variant of this format.

        Is itself when packed:

        >>> fmt = AudioFormat('s16')
        >>> fmt.packed is fmt
        True

        """
        if self.is_packed:
            return self
        return get_audio_format(lib.av_get_packed_sample_fmt(self.sample_fmt))

    @property
    def container_name(self):
        """The name of a :class:`ContainerFormat` which directly accepts this data.

        :raises ValueError: when planar, since there are no such containers.

        """
        if self.is_planar:
            raise ValueError("no planar container formats")

        if self.sample_fmt == lib.AV_SAMPLE_FMT_U8:
            return "u8"
        elif self.sample_fmt == lib.AV_SAMPLE_FMT_S16:
            return "s16" + container_format_postfix
        elif self.sample_fmt == lib.AV_SAMPLE_FMT_S32:
            return "s32" + container_format_postfix
        elif self.sample_fmt == lib.AV_SAMPLE_FMT_FLT:
            return "f32" + container_format_postfix
        elif self.sample_fmt == lib.AV_SAMPLE_FMT_DBL:
            return "f64" + container_format_postfix

        raise ValueError("unknown layout")