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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
cdef object _cinit_bypass_sentinel = object()
cdef VideoFormat get_video_format(lib.AVPixelFormat c_format, unsigned int width, unsigned int height):
if c_format == lib.AV_PIX_FMT_NONE:
return None
cdef VideoFormat format = VideoFormat.__new__(VideoFormat, _cinit_bypass_sentinel)
format._init(c_format, width, height)
return format
cdef lib.AVPixelFormat get_pix_fmt(const char *name) except lib.AV_PIX_FMT_NONE:
"""Wrapper for lib.av_get_pix_fmt with error checking."""
cdef lib.AVPixelFormat pix_fmt = lib.av_get_pix_fmt(name)
if pix_fmt == lib.AV_PIX_FMT_NONE:
raise ValueError("not a pixel format: %r" % name)
return pix_fmt
cdef class VideoFormat:
"""
>>> format = VideoFormat('rgb24')
>>> format.name
'rgb24'
"""
def __cinit__(self, name, width=0, height=0):
if name is _cinit_bypass_sentinel:
return
cdef VideoFormat other
if isinstance(name, VideoFormat):
other = <VideoFormat>name
self._init(other.pix_fmt, width or other.width, height or other.height)
return
cdef lib.AVPixelFormat pix_fmt = get_pix_fmt(name)
self._init(pix_fmt, width, height)
cdef _init(self, lib.AVPixelFormat pix_fmt, unsigned int width, unsigned int height):
self.pix_fmt = pix_fmt
self.ptr = lib.av_pix_fmt_desc_get(pix_fmt)
self.width = width
self.height = height
self.components = tuple(
VideoFormatComponent(self, i)
for i in range(self.ptr.nb_components)
)
def __repr__(self):
if self.width or self.height:
return f"<av.{self.__class__.__name__} {self.name}, {self.width}x{self.height}>"
else:
return f"<av.{self.__class__.__name__} {self.name}>"
def __int__(self):
return int(self.pix_fmt)
@property
def name(self):
"""Canonical name of the pixel format."""
return <str>self.ptr.name
@property
def bits_per_pixel(self):
return lib.av_get_bits_per_pixel(self.ptr)
@property
def padded_bits_per_pixel(self): return lib.av_get_padded_bits_per_pixel(self.ptr)
@property
def is_big_endian(self):
"""Pixel format is big-endian."""
return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_BE)
@property
def has_palette(self):
"""Pixel format has a palette in data[1], values are indexes in this palette."""
return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_PAL)
@property
def is_bit_stream(self):
"""All values of a component are bit-wise packed end to end."""
return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_BITSTREAM)
# Skipping PIX_FMT_HWACCEL
# """Pixel format is an HW accelerated format."""
@property
def is_planar(self):
"""At least one pixel component is not in the first data plane."""
return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_PLANAR)
@property
def is_rgb(self):
"""The pixel format contains RGB-like data (as opposed to YUV/grayscale)."""
return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_RGB)
@property
def is_bayer(self):
"""The pixel format contains Bayer data."""
return bool(self.ptr.flags & lib.AV_PIX_FMT_FLAG_BAYER)
cpdef chroma_width(self, int luma_width=0):
"""chroma_width(luma_width=0)
Width of a chroma plane relative to a luma plane.
:param int luma_width: Width of the luma plane; defaults to ``self.width``.
"""
luma_width = luma_width or self.width
return -((-luma_width) >> self.ptr.log2_chroma_w) if luma_width else 0
cpdef chroma_height(self, int luma_height=0):
"""chroma_height(luma_height=0)
Height of a chroma plane relative to a luma plane.
:param int luma_height: Height of the luma plane; defaults to ``self.height``.
"""
luma_height = luma_height or self.height
return -((-luma_height) >> self.ptr.log2_chroma_h) if luma_height else 0
cdef class VideoFormatComponent:
def __cinit__(self, VideoFormat format, size_t index):
self.format = format
self.index = index
self.ptr = &format.ptr.comp[index]
@property
def plane(self):
"""The index of the plane which contains this component."""
return self.ptr.plane
@property
def bits(self):
"""Number of bits in the component."""
return self.ptr.depth
@property
def is_alpha(self):
"""Is this component an alpha channel?"""
return ((self.index == 1 and self.format.ptr.nb_components == 2) or
(self.index == 3 and self.format.ptr.nb_components == 4))
@property
def is_luma(self):
"""Is this component a luma channel?"""
return self.index == 0 and (
self.format.ptr.nb_components == 1 or
self.format.ptr.nb_components == 2 or
not self.format.is_rgb
)
@property
def is_chroma(self):
"""Is this component a chroma channel?"""
return (self.index == 1 or self.index == 2) and (self.format.ptr.log2_chroma_w or self.format.ptr.log2_chroma_h)
@property
def width(self):
"""The width of this component's plane.
Requires the parent :class:`VideoFormat` to have a width.
"""
return self.format.chroma_width() if self.is_chroma else self.format.width
@property
def height(self):
"""The height of this component's plane.
Requires the parent :class:`VideoFormat` to have a height.
"""
return self.format.chroma_height() if self.is_chroma else self.format.height
names = set()
cdef const lib.AVPixFmtDescriptor *desc = NULL
while True:
desc = lib.av_pix_fmt_desc_next(desc)
if not desc:
break
names.add(desc.name)
|