Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions av/video/format.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,20 @@ cimport libav as lib


cdef class VideoFormat:

cdef lib.AVPixelFormat pix_fmt
cdef const lib.AVPixFmtDescriptor *ptr
cdef readonly unsigned int width, height

cdef readonly tuple components

cdef _init(self, lib.AVPixelFormat pix_fmt, unsigned int width, unsigned int height)

cpdef chroma_width(self, int luma_width=?)
cpdef chroma_height(self, int luma_height=?)


cdef class VideoFormatComponent:

cdef VideoFormat format
cdef readonly unsigned int index
cdef const lib.AVComponentDescriptor *ptr


cdef VideoFormat get_video_format(lib.AVPixelFormat c_format, unsigned int width, unsigned int height)

cdef lib.AVPixelFormat get_pix_fmt(const char *name) except lib.AV_PIX_FMT_NONE
84 changes: 45 additions & 39 deletions av/video/format.pyx → av/video/format.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,62 @@
import cython
from cython import uint as cuint

cdef object _cinit_bypass_sentinel = object()
_cinit_bypass_sentinel = cython.declare(object, object())

cdef VideoFormat get_video_format(lib.AVPixelFormat c_format, unsigned int width, unsigned int height):

@cython.cfunc
def get_video_format(
c_format: lib.AVPixelFormat, width: cuint, height: cuint
) -> VideoFormat | None:
if c_format == lib.AV_PIX_FMT_NONE:
return None

cdef VideoFormat format = VideoFormat.__new__(VideoFormat, _cinit_bypass_sentinel)
format: VideoFormat = 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)
@cython.cfunc
@cython.exceptval(lib.AV_PIX_FMT_NONE, check=False)
def get_pix_fmt(name: cython.p_const_char) -> lib.AVPixelFormat:
"""Wrapper for lib.av_get_pix_fmt with error checking."""

pix_fmt: lib.AVPixelFormat = 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:
@cython.cclass
class VideoFormat:
"""

>>> format = VideoFormat('rgb24')
>>> format.name
'rgb24'
>>> 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
other: VideoFormat = cython.cast(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)
pix_fmt: lib.AVPixelFormat = get_pix_fmt(name)
self._init(pix_fmt, width, height)

cdef _init(self, lib.AVPixelFormat pix_fmt, unsigned int width, unsigned int height):
@cython.cfunc
def _init(self, pix_fmt: lib.AVPixelFormat, width: cuint, height: cuint):
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)
VideoFormatComponent(self, i) for i in range(self.ptr.nb_components)
)

def __repr__(self):
Expand All @@ -64,54 +71,48 @@ def __int__(self):
@property
def name(self):
"""Canonical name of the pixel format."""
return <str>self.ptr.name
return cython.cast(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)
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):
@cython.ccall
def chroma_width(self, luma_width: cython.int = 0):
"""chroma_width(luma_width=0)

Width of a chroma plane relative to a luma plane.
Expand All @@ -122,7 +123,8 @@ def is_bayer(self):
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):
@cython.ccall
def chroma_height(self, luma_height: cython.int = 0):
"""chroma_height(luma_height=0)

Height of a chroma plane relative to a luma plane.
Expand All @@ -134,11 +136,12 @@ def is_bayer(self):
return -((-luma_height) >> self.ptr.log2_chroma_h) if luma_height else 0


cdef class VideoFormatComponent:
def __cinit__(self, VideoFormat format, size_t index):
@cython.cclass
class VideoFormatComponent:
def __cinit__(self, format: VideoFormat, index: cython.size_t):
self.format = format
self.index = index
self.ptr = &format.ptr.comp[index]
self.ptr = cython.address(format.ptr.comp[index])

@property
def plane(self):
Expand All @@ -153,22 +156,25 @@ def bits(self):
@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))
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
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)
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):
Expand All @@ -190,7 +196,7 @@ def height(self):


names = set()
cdef const lib.AVPixFmtDescriptor *desc = NULL
desc = cython.declare(cython.pointer[lib.AVPixFmtDescriptor], cython.NULL)
while True:
desc = lib.av_pix_fmt_desc_next(desc)
if not desc:
Expand Down
Loading