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
4 changes: 0 additions & 4 deletions av/filter/context.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
from av.filter import Graph
from av.frame import Frame

from .pad import FilterContextPad

class FilterContext:
name: str | None
inputs: tuple[FilterContextPad, ...]
outputs: tuple[FilterContextPad, ...]

def init(self, args: str | None = None, **kwargs: str | None) -> None: ...
def link_to(
Expand Down
2 changes: 1 addition & 1 deletion av/filter/context.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ from av.audio.frame cimport alloc_audio_frame
from av.dictionary cimport _Dictionary
from av.dictionary import Dictionary
from av.error cimport err_check
from av.filter.pad cimport alloc_filter_pads
from av.filter.link cimport alloc_filter_pads
from av.frame cimport Frame
from av.utils cimport avrational_to_fraction
from av.video.frame cimport alloc_video_frame
Expand Down
5 changes: 0 additions & 5 deletions av/filter/filter.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
from av.descriptor import Descriptor
from av.option import Option

from .pad import FilterPad

class Filter:
name: str
description: str

descriptor: Descriptor
options: tuple[Option, ...] | None
flags: int
Expand All @@ -15,8 +12,6 @@ class Filter:
timeline_support: bool
slice_threads: bool
command_support: bool
inputs: tuple[FilterPad, ...]
outputs: tuple[FilterPad, ...]

def __init__(self, name: str) -> None: ...

Expand Down
2 changes: 1 addition & 1 deletion av/filter/filter.pyx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cimport libav as lib

from av.descriptor cimport wrap_avclass
from av.filter.pad cimport alloc_filter_pads
from av.filter.link cimport alloc_filter_pads


cdef object _cinit_sentinel = object()
Expand Down
20 changes: 18 additions & 2 deletions av/filter/link.pxd
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
cimport libav as lib

from av.filter.context cimport FilterContext
from av.filter.filter cimport Filter
from av.filter.graph cimport Graph
from av.filter.pad cimport FilterContextPad
from av.filter.link cimport FilterContextPad, FilterLink


cdef class FilterLink:

cdef readonly Graph graph
cdef lib.AVFilterLink *ptr

Expand All @@ -14,3 +15,18 @@ cdef class FilterLink:


cdef FilterLink wrap_filter_link(Graph graph, lib.AVFilterLink *ptr)

cdef class FilterPad:
cdef readonly Filter filter
cdef readonly FilterContext context
cdef readonly bint is_input
cdef readonly int index

cdef const lib.AVFilterPad *base_ptr


cdef class FilterContextPad(FilterPad):
cdef FilterLink _link


cdef tuple alloc_filter_pads(Filter, const lib.AVFilterPad *ptr, bint is_input, FilterContext context=?)
5 changes: 1 addition & 4 deletions av/filter/link.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
from .pad import FilterContextPad

class FilterLink:
input: FilterContextPad
output: FilterContextPad
pass
77 changes: 76 additions & 1 deletion av/filter/link.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ cdef _cinit_sentinel = object()


cdef class FilterLink:

def __cinit__(self, sentinel):
if sentinel is not _cinit_sentinel:
raise RuntimeError("cannot instantiate FilterLink")
Expand Down Expand Up @@ -51,3 +50,79 @@ cdef FilterLink wrap_filter_link(Graph graph, lib.AVFilterLink *ptr):
link.graph = graph
link.ptr = ptr
return link



cdef class FilterPad:
def __cinit__(self, sentinel):
if sentinel is not _cinit_sentinel:
raise RuntimeError("cannot construct FilterPad")

def __repr__(self):
_filter = self.filter.name
_io = "inputs" if self.is_input else "outputs"

return f"<av.FilterPad {_filter}.{_io}[{self.index}]: {self.name} ({self.type})>"

@property
def is_output(self):
return not self.is_input

@property
def name(self):
return lib.avfilter_pad_get_name(self.base_ptr, self.index)


cdef class FilterContextPad(FilterPad):
def __repr__(self):
_filter = self.filter.name
_io = "inputs" if self.is_input else "outputs"
context = self.context.name

return f"<av.FilterContextPad {_filter}.{_io}[{self.index}] of {context}: {self.name} ({self.type})>"

@property
def link(self):
if self._link:
return self._link
cdef lib.AVFilterLink **links = self.context.ptr.inputs if self.is_input else self.context.ptr.outputs
cdef lib.AVFilterLink *link = links[self.index]
if not link:
return
self._link = wrap_filter_link(self.context.graph, link)
return self._link

@property
def linked(self):
cdef FilterLink link = self.link
if link:
return link.input if self.is_input else link.output


cdef tuple alloc_filter_pads(Filter filter, const lib.AVFilterPad *ptr, bint is_input, FilterContext context=None):
if not ptr:
return ()

pads = []

# We need to be careful and check our bounds if we know what they are,
# since the arrays on a AVFilterContext are not NULL terminated.
cdef int i = 0
cdef int count
if context is None:
count = lib.avfilter_filter_pad_count(filter.ptr, not is_input)
else:
count = (context.ptr.nb_inputs if is_input else context.ptr.nb_outputs)

cdef FilterPad pad
while (i < count):
pad = FilterPad(_cinit_sentinel) if context is None else FilterContextPad(_cinit_sentinel)
pads.append(pad)
pad.filter = filter
pad.context = context
pad.is_input = is_input
pad.base_ptr = ptr
pad.index = i
i += 1

return tuple(pads)
23 changes: 0 additions & 23 deletions av/filter/pad.pxd

This file was deleted.

10 changes: 0 additions & 10 deletions av/filter/pad.pyi

This file was deleted.

90 changes: 0 additions & 90 deletions av/filter/pad.pyx

This file was deleted.

6 changes: 0 additions & 6 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,12 @@ def test_filter_descriptor(self) -> None:
assert f.name == "testsrc"
assert f.description == "Generate test pattern."
assert not f.dynamic_inputs
assert len(f.inputs) == 0
assert not f.dynamic_outputs
assert len(f.outputs) == 1
assert f.outputs[0].name == "default"
assert f.outputs[0].type == "video"

def test_dynamic_filter_descriptor(self):
f = Filter("split")
assert not f.dynamic_inputs
assert len(f.inputs) == 1
assert f.dynamic_outputs
assert len(f.outputs) == 0

def test_generator_graph(self):
graph = Graph()
Expand Down
Loading