File: format.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 (169 lines) | stat: -rw-r--r-- 5,557 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
cimport libav as lib

from av.descriptor cimport wrap_avclass

from enum import Flag


cdef object _cinit_bypass_sentinel = object()

cdef ContainerFormat build_container_format(lib.AVInputFormat* iptr, lib.AVOutputFormat* optr):
    if not iptr and not optr:
        raise ValueError("needs input format or output format")
    cdef ContainerFormat format = ContainerFormat.__new__(ContainerFormat, _cinit_bypass_sentinel)
    format.iptr = iptr
    format.optr = optr
    format.name = optr.name if optr else iptr.name
    return format


class Flags(Flag):
    no_file = lib.AVFMT_NOFILE
    need_number: "Needs '%d' in filename." = lib.AVFMT_NEEDNUMBER
    show_ids: "Show format stream IDs numbers." = lib.AVFMT_SHOW_IDS
    global_header: "Format wants global header." = lib.AVFMT_GLOBALHEADER
    no_timestamps: "Format does not need / have any timestamps." = lib.AVFMT_NOTIMESTAMPS
    generic_index: "Use generic index building code." = lib.AVFMT_GENERIC_INDEX
    ts_discont: "Format allows timestamp discontinuities" = lib.AVFMT_TS_DISCONT
    variable_fps: "Format allows variable fps." = lib.AVFMT_VARIABLE_FPS
    no_dimensions: "Format does not need width/height" = lib.AVFMT_NODIMENSIONS
    no_streams: "Format does not require any streams" = lib.AVFMT_NOSTREAMS
    no_bin_search: "Format does not allow to fall back on binary search via read_timestamp" = lib.AVFMT_NOBINSEARCH
    no_gen_search: "Format does not allow to fall back on generic search" = lib.AVFMT_NOGENSEARCH
    no_byte_seek: "Format does not allow seeking by bytes" = lib.AVFMT_NO_BYTE_SEEK
    ts_nonstrict: "Format does not require strictly increasing timestamps, but they must still be monotonic." = lib.AVFMT_TS_NONSTRICT
    ts_negative: "Format allows muxing negative timestamps." = lib.AVFMT_TS_NEGATIVE
    # If not set the timestamp will be shifted in `av_write_frame()` and `av_interleaved_write_frame()`
    # so they start from 0. The user or muxer can override this through AVFormatContext.avoid_negative_ts
    seek_to_pts: "Seeking is based on PTS" = lib.AVFMT_SEEK_TO_PTS

cdef class ContainerFormat:
    """Descriptor of a container format.

    :param str name: The name of the format.
    :param str mode: ``'r'`` or ``'w'`` for input and output formats; defaults
        to None which will grab either.

    """

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

        # We need to hold onto the original name because AVInputFormat.name is
        # actually comma-separated, and so we need to remember which one this was.
        self.name = name

        # Searches comma-separated names.
        if mode is None or mode == "r":
            self.iptr = lib.av_find_input_format(name)

        if mode is None or mode == "w":
            self.optr = lib.av_guess_format(name, NULL, NULL)

        if not self.iptr and not self.optr:
            raise ValueError(f"no container format {name!r}")

    def __repr__(self):
        return f"<av.{self.__class__.__name__} {self.name!r}>"

    @property
    def descriptor(self):
        if self.iptr:
            return wrap_avclass(self.iptr.priv_class)
        else:
            return wrap_avclass(self.optr.priv_class)

    @property
    def options(self):
        return self.descriptor.options

    @property
    def input(self):
        """An input-only view of this format."""
        if self.iptr == NULL:
            return None
        elif self.optr == NULL:
            return self
        else:
            return build_container_format(self.iptr, NULL)

    @property
    def output(self):
        """An output-only view of this format."""
        if self.optr == NULL:
            return None
        elif self.iptr == NULL:
            return self
        else:
            return build_container_format(NULL, self.optr)

    @property
    def is_input(self):
        return self.iptr != NULL

    @property
    def is_output(self):
        return self.optr != NULL

    @property
    def long_name(self):
        # We prefer the output names since the inputs may represent
        # multiple formats.
        return self.optr.long_name if self.optr else self.iptr.long_name

    @property
    def extensions(self):
        cdef set exts = set()
        if self.iptr and self.iptr.extensions:
            exts.update(self.iptr.extensions.split(","))
        if self.optr and self.optr.extensions:
            exts.update(self.optr.extensions.split(","))
        return exts

    @property
    def flags(self):
        """
        Get the flags bitmask for the format.

        :rtype: int
        """
        return (
            (self.iptr.flags if self.iptr else 0) |
            (self.optr.flags if self.optr else 0)
        )

    @property
    def no_file(self):
        return bool(self.flags & lib.AVFMT_NOFILE)


cdef get_output_format_names():
    names = set()
    cdef const lib.AVOutputFormat *ptr
    cdef void *opaque = NULL
    while True:
        ptr = lib.av_muxer_iterate(&opaque)
        if ptr:
            names.add(ptr.name)
        else:
            break
    return names

cdef get_input_format_names():
    names = set()
    cdef const lib.AVInputFormat *ptr
    cdef void *opaque = NULL
    while True:
        ptr = lib.av_demuxer_iterate(&opaque)
        if ptr:
            names.add(ptr.name)
        else:
            break
    return names

formats_available = get_output_format_names()
formats_available.update(get_input_format_names())


format_descriptor = wrap_avclass(lib.avformat_get_class())