Skip to content

Composite Mixin

Composite orchestration mixin for nested media toolkit processors.

Composite components (segmenters, keyframe extractors) delegate work to leaf processor families through get_processor. This mixin tracks which processor families are used, resolves backends per family, and supports global backend remapping without requiring contributor-declared routing tables on each composite subclass.

How backend resolution works

When get_processor("VideoClipProcessor") is called, the mixin resolves the concrete backend using this priority order:

  1. explicit backend argument to get_processor or build_processor
  2. per-processor override from set_processor_backend
  3. composite default backend
  4. global remap from remap_backends (e.g. gstreamer -> ffmpeg)

Tracking and caching

  • Processor families are tracked in _used_processors when get_processor or build_processor is called.
  • Created processors are cached in _processor_cache keyed by (class_name, resolved_backend).
  • Cache is invalidated when backend routing changes.

CompositeMediaMixin

Backend-aware nested processor factory and cache for composite components.

Segmenters and keyframe extractors inherit this mixin so leaf processors (e.g. GStreamer implementations) are not coupled to backend selection. Nested processor families are auto-tracked when get_processor is called, so contributors only invoke self.get_processor("FamilyName") inside orchestration code.

Backend resolution order
  1. explicit backend argument to get_processor or build_processor
  2. per-processor override from set_processor_backend
  3. composite default backend
  4. global remap from remap_backends (e.g. gstreamer -> ffmpeg)
Example
Homogeneous video segmenter
segmenter.backend = MediaBackend.GSTREAMER
clipper = segmenter.get_processor("VideoClipProcessor")
Heterogeneous video + image orchestration
segmenter.backend = MediaBackend.GSTREAMER
segmenter.set_processor_backend("ImageTilingProcessor", "pil")
clipper = segmenter.get_processor("VideoClipProcessor")      # gstreamer
tiler = segmenter.get_processor("ImageTilingProcessor")      # pil
Global media-backend migration
segmenter.remap_backends({MediaBackend.GSTREAMER: MediaBackend.FFMPEG})
# only processors that resolve to gstreamer are remapped to ffmpeg
Inspect used processors, then change one family
await segmenter.process(video_attachment)
segmenter.list_processors()          # ["VideoClipProcessor"]
segmenter.processor_backend_map()    # {"VideoClipProcessor": "gstreamer"}
segmenter.set_processor_backend("VideoClipProcessor", MediaBackend.FFMPEG)
Propagate backend override into nested composites
parent = keyframe_extractor.get_processor("CustomSegmenter")
child = parent.get_processor("NestedSegmenter")
child.get_processor("VideoClipProcessor")  # ensure child has used this family
parent.set_processor_backend("VideoClipProcessor", MediaBackend.FFMPEG, propagate=True)
# both parent and cached child composites now resolve VideoClipProcessor as ffmpeg

Attributes:

Name Type Description
backend MediaBackend | str | None

Default backend for nested processor lookup when no per-processor override exists. Set by build when the composite is built through the registry.

build_from_registry(backend=None, **kwargs) classmethod

Instantiate this composite and store backend for nested resolution.

Parameters:

Name Type Description Default
backend str | MediaBackend | None

Default backend for nested processor lookup. Defaults to None.

None
**kwargs Any

Constructor kwargs passed to the composite class.

{}

Returns:

Name Type Description
MediaToolkit MediaToolkit

Instantiated composite component.

build_processor(class_name, backend=None, **kwargs)

Create a nested processor by class name without caching.

Uses composite routing rules when backend is not provided. Prefer get_processor when the same nested processor may be reused.

Parameters:

Name Type Description Default
class_name str

Processor class name, e.g. VideoClipProcessor.

required
backend MediaBackend | str | None

Backend override. Defaults to None.

None
**kwargs Any

Constructor kwargs forwarded to the nested processor.

{}

Returns:

Name Type Description
MediaToolkit MediaToolkit

Instantiated nested processor.

Raises:

Type Description
ValueError

If the resolved backend is not registered for the family.

configure_processor_backends(backends)

Pre-configure per-family backend overrides before any processor is used.

Unlike set_processor_backend, this method does not require the processor family to have been used first. It is intended for builder code that wires routing at construction time.

Parameters:

Name Type Description Default
backends dict[str, MediaBackend | str]

Mapping of processor family class name to backend key, e.g. {"VideoClipProcessor": "gstreamer"}.

required

Raises:

Type Description
ValueError

If a backend is not registered for the processor family.

get_processor(class_name, backend=None, **kwargs)

Return a cached nested processor, creating it on first access.

Cache identity is (class_name, resolved_backend) where resolved_backend follows composite routing and remap rules.

Note

This method calls MediaToolkit.build directly, not build_processor. Subclass overrides of build_processor do not apply to the cached path. Use build_processor explicitly when custom construction logic is needed on every call.

Parameters:

Name Type Description Default
class_name str

Processor class name, e.g. VideoClipProcessor.

required
backend MediaBackend | str | None

Backend override. Defaults to None.

None
**kwargs Any

Constructor kwargs forwarded on first creation only.

{}

Returns:

Name Type Description
MediaToolkit MediaToolkit

Cached nested processor instance.

Raises:

Type Description
ValueError

If the resolved backend is not registered for the family.

list_processors()

Return nested processor families discovered or configured on this instance.

Processor families are tracked when get_processor or build_processor is called.

Returns:

Type Description
list[str]

list[str]: Sorted processor family class names.

processor_backend_map()

Return effective resolved backend per discovered processor family.

Returns:

Type Description
dict[str, MediaBackend | str | None]

dict[str, MediaBackend | str | None]: Mapping of processor family class name to effective backend key after routing and remap.

remap_backends(mapping, propagate=False)

Remap resolved backends globally within this composite instance.

Only processors whose resolved backend matches a source key are remapped. Processors pinned to other backends (e.g. pil) are unaffected.

Eagerly validates the remap targets against already-tracked processor families so misconfigured remaps are caught at configuration time, not at process time.

Parameters:

Name Type Description Default
mapping dict[MediaBackend | str, MediaBackend | str]

Source-to-target backend map, e.g. {MediaBackend.GSTREAMER: MediaBackend.FFMPEG}.

required
propagate bool

When True, recursively applies the same remap mapping to cached nested composite children. Defaults to False.

False

Raises:

Type Description
ValueError

If a remap target backend is unsupported for an already-tracked processor family.

set_processor_backend(class_name, backend, propagate=False)

Set backend override for one nested processor family.

Use this for heterogeneous composites where different processor families require different backends (e.g. video on GStreamer, image on PIL). By default, override applies only to this composite instance. When propagate=True, the same override is recursively applied to cached nested composite children that have already used the same processor family.

Parameters:

Name Type Description Default
class_name str

Processor family class name, e.g. VideoClipProcessor.

required
backend MediaBackend | str

Backend key for that family.

required
propagate bool

When True, recursively applies the same backend override to cached nested composite children that have already used the same processor family. Nodes where the family has not been used are silently skipped (no error raised), unlike the local propagate=False path which raises ValueError if the family is unused on this instance. Defaults to False.

False
Example
Local-only override
segmenter.get_processor("VideoClipProcessor")
segmenter.set_processor_backend("VideoClipProcessor", "ffmpeg")
Recursive override for cached nested composites
parent = extractor.get_processor("CustomSegmenter")
child = parent.get_processor("NestedSegmenter")
child.get_processor("VideoClipProcessor")
parent.set_processor_backend("VideoClipProcessor", "ffmpeg", propagate=True)

Raises:

Type Description
ValueError

If the backend is not registered for the processor family.

ValueError

If the processor family has not been used by this composite instance.