From 1f0c02eb6c3ae0735006c53db2a258c8588e7a53 Mon Sep 17 00:00:00 2001 From: Rattus Date: Wed, 8 Apr 2026 16:40:12 +1000 Subject: [PATCH] comfy_api: Add datatype for ImageStreams --- comfy/comfy_types/node_typing.py | 1 + comfy_api/input/__init__.py | 2 + comfy_api/input/image_stream_types.py | 6 +++ comfy_api/latest/__init__.py | 3 +- comfy_api/latest/_input/__init__.py | 2 + comfy_api/latest/_input/image_stream_types.py | 48 +++++++++++++++++++ comfy_api/latest/_io.py | 9 +++- 7 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 comfy_api/input/image_stream_types.py create mode 100644 comfy_api/latest/_input/image_stream_types.py diff --git a/comfy/comfy_types/node_typing.py b/comfy/comfy_types/node_typing.py index 57126fa4a..18eba6dc5 100644 --- a/comfy/comfy_types/node_typing.py +++ b/comfy/comfy_types/node_typing.py @@ -51,6 +51,7 @@ class IO(StrEnum): BBOX = "BBOX" SEGS = "SEGS" VIDEO = "VIDEO" + IMAGE_STREAM = "IMAGE_STREAM" ANY = "*" """Always matches any type, but at a price. diff --git a/comfy_api/input/__init__.py b/comfy_api/input/__init__.py index 16d4acfd1..8e2374aaf 100644 --- a/comfy_api/input/__init__.py +++ b/comfy_api/input/__init__.py @@ -2,6 +2,7 @@ from comfy_api.latest._input import ( ImageInput, AudioInput, + ImageStreamInput, MaskInput, LatentInput, VideoInput, @@ -14,6 +15,7 @@ from comfy_api.latest._input import ( __all__ = [ "ImageInput", "AudioInput", + "ImageStreamInput", "MaskInput", "LatentInput", "VideoInput", diff --git a/comfy_api/input/image_stream_types.py b/comfy_api/input/image_stream_types.py new file mode 100644 index 000000000..b52d0c76d --- /dev/null +++ b/comfy_api/input/image_stream_types.py @@ -0,0 +1,6 @@ +# This file only exists for backwards compatibility. +from comfy_api.latest._input.image_stream_types import ImageStreamInput + +__all__ = [ + "ImageStreamInput", +] diff --git a/comfy_api/latest/__init__.py b/comfy_api/latest/__init__.py index 04973fea0..c0493b3ca 100644 --- a/comfy_api/latest/__init__.py +++ b/comfy_api/latest/__init__.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING from comfy_api.internal import ComfyAPIBase from comfy_api.internal.singleton import ProxiedSingleton from comfy_api.internal.async_to_sync import create_sync_class -from ._input import ImageInput, AudioInput, MaskInput, LatentInput, VideoInput +from ._input import ImageInput, AudioInput, ImageStreamInput, MaskInput, LatentInput, VideoInput from ._input_impl import VideoFromFile, VideoFromComponents from ._util import VideoCodec, VideoContainer, VideoComponents, MESH, VOXEL, File3D from . import _io_public as io @@ -131,6 +131,7 @@ class ComfyExtension(ABC): class Input: Image = ImageInput Audio = AudioInput + ImageStream = ImageStreamInput Mask = MaskInput Latent = LatentInput Video = VideoInput diff --git a/comfy_api/latest/_input/__init__.py b/comfy_api/latest/_input/__init__.py index 05cd3d40a..3ec611879 100644 --- a/comfy_api/latest/_input/__init__.py +++ b/comfy_api/latest/_input/__init__.py @@ -1,10 +1,12 @@ from .basic_types import ImageInput, AudioInput, MaskInput, LatentInput from .curve_types import CurvePoint, CurveInput, MonotoneCubicCurve, LinearCurve +from .image_stream_types import ImageStreamInput from .video_types import VideoInput __all__ = [ "ImageInput", "AudioInput", + "ImageStreamInput", "VideoInput", "MaskInput", "LatentInput", diff --git a/comfy_api/latest/_input/image_stream_types.py b/comfy_api/latest/_input/image_stream_types.py new file mode 100644 index 000000000..04af3562c --- /dev/null +++ b/comfy_api/latest/_input/image_stream_types.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod + +from .basic_types import ImageInput + + +class ImageStreamInput(ABC): + """Abstract base class for pull-based image stream inputs. + + Consumers request up to ``max_frames`` frames at a time. Producers must not + over-return; a batch with fewer than ``max_frames`` frames signals EOF. + """ + + def __init__(self): + #Subclasses must call this init for future core ComfyUI change compatibilty + pass + + def reset(self) -> None: + #This API is final. Subclasses must NOT override this for future core ComfyUI + #change compatability. Override do_reset instead. + return self.do_reset() + + def pull(self, max_frames: int) -> ImageInput: + #This API is final. Subclasses must NOT override this for future core ComfyUI + #change compatability. Override do_pull instead. + return self.do_pull(max_frames) + + @abstractmethod + def get_dimensions(self) -> tuple[int, int]: + """Return the stream frame dimensions as ``(width, height)``.""" + pass + + @abstractmethod + def do_reset(self) -> None: + """Reset the stream so the next pull starts from frame 0.""" + pass + + @abstractmethod + def do_pull(self, max_frames: int) -> ImageInput: + """Return up to ``max_frames`` images. + + The returned tensor uses the normal ``IMAGE`` batch shape. A short + return, where the batch dimension is less than ``max_frames``, is the + EOF signal. Sources are expected to short-return at least once before + exhaustion, including returning an empty batch. + """ + pass diff --git a/comfy_api/latest/_io.py b/comfy_api/latest/_io.py index fdeffea2d..3fbd9e40e 100644 --- a/comfy_api/latest/_io.py +++ b/comfy_api/latest/_io.py @@ -23,7 +23,7 @@ if TYPE_CHECKING: from comfy.samplers import CFGGuider, Sampler from comfy.sd import CLIP, VAE from comfy.sd import StyleModel as StyleModel_ - from comfy_api.input import VideoInput, CurveInput as CurveInput_ + from comfy_api.input import ImageStreamInput, VideoInput, CurveInput as CurveInput_ from comfy_api.internal import (_ComfyNodeInternal, _NodeOutputInternal, classproperty, copy_class, first_real_override, is_class, prune_dict, shallow_clone_class) from comfy_execution.graph_utils import ExecutionBlocker @@ -420,6 +420,12 @@ class Image(ComfyTypeIO): Type = torch.Tensor +@comfytype(io_type="IMAGE_STREAM") +class ImageStream(ComfyTypeIO): + if TYPE_CHECKING: + Type = ImageStreamInput + + @comfytype(io_type="WAN_CAMERA_EMBEDDING") class WanCameraEmbedding(ComfyTypeIO): Type = torch.Tensor @@ -2203,6 +2209,7 @@ __all__ = [ "Combo", "MultiCombo", "Image", + "ImageStream", "WanCameraEmbedding", "Webcam", "Mask",