Skip to content
Merged
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
76 changes: 43 additions & 33 deletions av/format.pyx → av/format.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
cimport libav as lib

from av.descriptor cimport wrap_avclass

from enum import Flag

import cython
import cython.cimports.libav as lib
from cython.cimports.av.descriptor import wrap_avclass

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

cdef ContainerFormat build_container_format(lib.AVInputFormat* iptr, lib.AVOutputFormat* optr):

@cython.cfunc
def build_container_format(
iptr: cython.pointer[lib.AVInputFormat], optr: cython.pointer[lib.AVOutputFormat]
) -> ContainerFormat:
if not iptr and not optr:
raise ValueError("needs input format or output format")
cdef ContainerFormat format = ContainerFormat.__new__(ContainerFormat, _cinit_bypass_sentinel)
format: ContainerFormat = ContainerFormat.__new__(
ContainerFormat, _cinit_bypass_sentinel
)
format.iptr = iptr
format.optr = optr
format.name = optr.name if optr else iptr.name
return format


# fmt: off
class Flags(Flag):
no_file = lib.AVFMT_NOFILE
need_number: "Needs '%d' in filename." = lib.AVFMT_NEEDNUMBER
Expand All @@ -36,8 +42,11 @@ class Flags(Flag):
# 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
# fmt: on


cdef class ContainerFormat:
@cython.cclass
class ContainerFormat:
"""Descriptor of a container format.

:param str name: The name of the format.
Expand All @@ -59,7 +68,7 @@ def __cinit__(self, name, mode=None):
self.iptr = lib.av_find_input_format(name)

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

if not self.iptr and not self.optr:
raise ValueError(f"no container format {name!r}")
Expand All @@ -81,30 +90,30 @@ def options(self):
@property
def input(self):
"""An input-only view of this format."""
if self.iptr == NULL:
if self.iptr == cython.NULL:
return None
elif self.optr == NULL:
elif self.optr == cython.NULL:
return self
else:
return build_container_format(self.iptr, NULL)
return build_container_format(self.iptr, cython.NULL)

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

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

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

@property
def long_name(self):
Expand All @@ -114,7 +123,7 @@ def long_name(self):

@property
def extensions(self):
cdef set exts = set()
exts: set = set()
if self.iptr and self.iptr.extensions:
exts.update(self.iptr.extensions.split(","))
if self.optr and self.optr.extensions:
Expand All @@ -128,42 +137,43 @@ def flags(self):

:rtype: int
"""
return (
(self.iptr.flags if self.iptr else 0) |
(self.optr.flags if self.optr else 0)
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
@cython.cfunc
def get_output_format_names() -> set:
names: set = set()
ptr: cython.pointer[cython.const[lib.AVOutputFormat]]
opaque: cython.p_void = cython.NULL
while True:
ptr = lib.av_muxer_iterate(&opaque)
ptr = lib.av_muxer_iterate(cython.address(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

@cython.cfunc
def get_input_format_names() -> set:
names: set = set()
ptr: cython.pointer[cython.const[lib.AVInputFormat]]
opaque: cython.p_void = cython.NULL
while True:
ptr = lib.av_demuxer_iterate(&opaque)
ptr = lib.av_demuxer_iterate(cython.address(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())
Loading