Frame filtering

Source and sink elements in a Savant pipeline can include a filter function. This function is called for every frame, and can be used to filter out frames that should not be processed by the pipeline (ingress filter in a source element) or frames that should not be passed to the next pipeline (egress filter in a sink element).

This is useful, for example, in the case Conditional Encoding is defined and as a result the pipeline produces frames without video data. Egress filtering can be used to filter out these frames before they are passed to the next pipeline.

Frame filtering functions work similarly to Python Function Unit, with a couple of differences.

Filtering function config

To define an ingress filtering function, add an ingress_frame_filter node to the SourceElement definition, e.g.

  element: zeromq_source_bin
    socket: router+bind:ipc:///tmp/zmq-sockets/input-video.ipc
    class_name: IngressFilter


Ingress filter can only be configured for zeromq_source_bin source.

Likewise for egress filtering, add an egress_frame_filter node to the SinkElement definition.

  - element: zeromq_sink
      socket: pub+bind:ipc:///tmp/zmq-sockets/output-video.ipc
      class_name: EgressFilter

Defining the filtering functions is optional. By default, ingress filters out all frames without video, and egress is bypassed.

Filtering function code

Custom ingress and egress filters must implement BaseFrameFilter interface. The interface defines one method:

def __call__(self, video_frame: VideoFrame) -> bool:
    """Return True if the frame should be processed, False otherwise."""

Default ingress filter provides an example of filter that drops frames without video data:

class DefaultIngressFilter(BaseFrameFilter):
    """Default ingress filter, filters out frames with no video data."""

    def __call__(self, video_frame: VideoFrame) -> bool:
        """Filters input frames.

        :param video_frame: Video frame.
        :return: Whether to accept the frame into the pipeline (True) or skip it (False).

        return not video_frame.content.is_none()