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:
- explicit
backendargument toget_processororbuild_processor - per-processor override from
set_processor_backend - composite default
backend - global remap from
remap_backends(e.g.gstreamer->ffmpeg)
Tracking and caching
- Processor families are tracked in
_used_processorswhenget_processororbuild_processoris called. - Created processors are cached in
_processor_cachekeyed 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
- explicit
backendargument toget_processororbuild_processor - per-processor override from
set_processor_backend - composite default
backend - 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_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. |
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.
|
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. |
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. |
required |
propagate
|
bool
|
When |
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. |
required |
backend
|
MediaBackend | str
|
Backend key for that family. |
required |
propagate
|
bool
|
When |
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. |