1
2cdef object _cinit_bypass_sentinel = object()
3
4cdef VideoFormat get_video_format(lib.AVPixelFormat c_format, unsigned int width, unsigned int height):
5    if c_format == lib.AV_PIX_FMT_NONE:
6        return None
7    cdef VideoFormat format = VideoFormat.__new__(VideoFormat, _cinit_bypass_sentinel)
8    format._init(c_format, width, height)
9    return format
10
11
12cdef class VideoFormat(object):
13    """
14
15        >>> format = VideoFormat('rgb24')
16        >>> format.name
17        'rgb24'
18
19    """
20
21    def __cinit__(self, name, width=0, height=0):
22
23        if name is _cinit_bypass_sentinel:
24            return
25
26        cdef VideoFormat other
27        if isinstance(name, VideoFormat):
28            other = <VideoFormat>name
29            self._init(other.pix_fmt, width or other.width, height or other.height)
30            return
31
32        cdef lib.AVPixelFormat pix_fmt = lib.av_get_pix_fmt(name)
33        if pix_fmt < 0:
34            raise ValueError('not a pixel format: %r' % name)
35        self._init(pix_fmt, width, height)
36
37    cdef _init(self, lib.AVPixelFormat pix_fmt, unsigned int width, unsigned int height):
38        self.pix_fmt = pix_fmt
39        self.ptr = lib.av_pix_fmt_desc_get(pix_fmt)
40        self.width = width
41        self.height = height
42        self.components = tuple(
43            VideoFormatComponent(self, i)
44            for i in range(self.ptr.nb_components)
45        )
46
47    def __repr__(self):
48        if self.width or self.height:
49            return '<av.%s %s, %dx%d>' % (self.__class__.__name__, self.name, self.width, self.height)
50        else:
51            return '<av.%s %s>' % (self.__class__.__name__, self.name)
52
53    def __int__(self):
54        return int(self.pix_fmt)
55
56    property name:
57        """Canonical name of the pixel format."""
58        def __get__(self):
59            return <str>self.ptr.name
60
61    property bits_per_pixel:
62        def __get__(self): return lib.av_get_bits_per_pixel(self.ptr)
63
64    property padded_bits_per_pixel:
65        def __get__(self): return lib.av_get_padded_bits_per_pixel(self.ptr)
66
67    property is_big_endian:
68        """Pixel format is big-endian."""
69        def __get__(self): return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_BE)
70
71    property has_palette:
72        """Pixel format has a palette in data[1], values are indexes in this palette."""
73        def __get__(self): return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_PAL)
74
75    property is_bit_stream:
76        """All values of a component are bit-wise packed end to end."""
77        def __get__(self): return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_BITSTREAM)
78
79    # Skipping PIX_FMT_HWACCEL
80    # """Pixel format is an HW accelerated format."""
81
82    property is_planar:
83        """At least one pixel component is not in the first data plane."""
84        def __get__(self): return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_PLANAR)
85
86    property is_rgb:
87        """The pixel format contains RGB-like data (as opposed to YUV/grayscale)."""
88        def __get__(self): return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_RGB)
89
90    cpdef chroma_width(self, int luma_width=0):
91        """chroma_width(luma_width=0)
92
93        Width of a chroma plane relative to a luma plane.
94
95        :param int luma_width: Width of the luma plane; defaults to ``self.width``.
96
97        """
98        luma_width = luma_width or self.width
99        return -((-luma_width) >> self.ptr.log2_chroma_w) if luma_width else 0
100
101    cpdef chroma_height(self, int luma_height=0):
102        """chroma_height(luma_height=0)
103
104        Height of a chroma plane relative to a luma plane.
105
106        :param int luma_height: Height of the luma plane; defaults to ``self.height``.
107
108        """
109        luma_height = luma_height or self.height
110        return -((-luma_height) >> self.ptr.log2_chroma_h) if luma_height else 0
111
112
113cdef class VideoFormatComponent(object):
114
115    def __cinit__(self, VideoFormat format, size_t index):
116        self.format = format
117        self.index = index
118        self.ptr = &format.ptr.comp[index]
119
120    property plane:
121        """The index of the plane which contains this component."""
122        def __get__(self):
123            return self.ptr.plane
124
125    property bits:
126        """Number of bits in the component."""
127        def __get__(self):
128            return self.ptr.depth
129
130    property is_alpha:
131        """Is this component an alpha channel?"""
132        def __get__(self):
133            return ((self.index == 1 and self.format.ptr.nb_components == 2) or
134                    (self.index == 3 and self.format.ptr.nb_components == 4))
135
136    property is_luma:
137        """Is this compoment a luma channel?"""
138        def __get__(self):
139            return self.index == 0 and (
140                self.format.ptr.nb_components == 1 or
141                self.format.ptr.nb_components == 2 or
142                not self.format.is_rgb
143            )
144
145    property is_chroma:
146        """Is this component a chroma channel?"""
147        def __get__(self):
148            return (self.index == 1 or self.index == 2) and (self.format.ptr.log2_chroma_w or self.format.ptr.log2_chroma_h)
149
150    property width:
151        """The width of this component's plane.
152
153        Requires the parent :class:`VideoFormat` to have a width.
154
155        """
156        def __get__(self):
157            return self.format.chroma_width() if self.is_chroma else self.format.width
158
159    property height:
160        """The height of this component's plane.
161
162        Requires the parent :class:`VideoFormat` to have a height.
163
164        """
165        def __get__(self):
166            return self.format.chroma_height() if self.is_chroma else self.format.height
167
168
169names = set()
170cdef const lib.AVPixFmtDescriptor *desc = NULL
171while True:
172    desc = lib.av_pix_fmt_desc_next(desc)
173    if not desc:
174        break
175    names.add(desc.name)
176