11import logging
2- from typing import Optional
32
43import torch
54
6- from comfy_api .input .video_types import VideoInput
75from comfy_api .latest import Input
86
97
@@ -18,10 +16,10 @@ def get_image_dimensions(image: torch.Tensor) -> tuple[int, int]:
1816
1917def validate_image_dimensions (
2018 image : torch .Tensor ,
21- min_width : Optional [ int ] = None ,
22- max_width : Optional [ int ] = None ,
23- min_height : Optional [ int ] = None ,
24- max_height : Optional [ int ] = None ,
19+ min_width : int | None = None ,
20+ max_width : int | None = None ,
21+ min_height : int | None = None ,
22+ max_height : int | None = None ,
2523):
2624 height , width = get_image_dimensions (image )
2725
@@ -37,8 +35,8 @@ def validate_image_dimensions(
3735
3836def validate_image_aspect_ratio (
3937 image : torch .Tensor ,
40- min_ratio : Optional [ tuple [float , float ]] = None , # e.g. (1, 4)
41- max_ratio : Optional [ tuple [float , float ]] = None , # e.g. (4, 1)
38+ min_ratio : tuple [float , float ] | None = None , # e.g. (1, 4)
39+ max_ratio : tuple [float , float ] | None = None , # e.g. (4, 1)
4240 * ,
4341 strict : bool = True , # True -> (min, max); False -> [min, max]
4442) -> float :
@@ -84,8 +82,8 @@ def validate_images_aspect_ratio_closeness(
8482
8583def validate_aspect_ratio_string (
8684 aspect_ratio : str ,
87- min_ratio : Optional [ tuple [float , float ]] = None , # e.g. (1, 4)
88- max_ratio : Optional [ tuple [float , float ]] = None , # e.g. (4, 1)
85+ min_ratio : tuple [float , float ] | None = None , # e.g. (1, 4)
86+ max_ratio : tuple [float , float ] | None = None , # e.g. (4, 1)
8987 * ,
9088 strict : bool = False , # True -> (min, max); False -> [min, max]
9189) -> float :
@@ -97,10 +95,10 @@ def validate_aspect_ratio_string(
9795
9896def validate_video_dimensions (
9997 video : Input .Video ,
100- min_width : Optional [ int ] = None ,
101- max_width : Optional [ int ] = None ,
102- min_height : Optional [ int ] = None ,
103- max_height : Optional [ int ] = None ,
98+ min_width : int | None = None ,
99+ max_width : int | None = None ,
100+ min_height : int | None = None ,
101+ max_height : int | None = None ,
104102):
105103 try :
106104 width , height = video .get_dimensions ()
@@ -120,8 +118,8 @@ def validate_video_dimensions(
120118
121119def validate_video_duration (
122120 video : Input .Video ,
123- min_duration : Optional [ float ] = None ,
124- max_duration : Optional [ float ] = None ,
121+ min_duration : float | None = None ,
122+ max_duration : float | None = None ,
125123):
126124 try :
127125 duration = video .get_duration ()
@@ -136,6 +134,23 @@ def validate_video_duration(
136134 raise ValueError (f"Video duration must be at most { max_duration } s, got { duration } s" )
137135
138136
137+ def validate_video_frame_count (
138+ video : Input .Video ,
139+ min_frame_count : int | None = None ,
140+ max_frame_count : int | None = None ,
141+ ):
142+ try :
143+ frame_count = video .get_frame_count ()
144+ except Exception as e :
145+ logging .error ("Error getting frame count of video: %s" , e )
146+ return
147+
148+ if min_frame_count is not None and min_frame_count > frame_count :
149+ raise ValueError (f"Video frame count must be at least { min_frame_count } , got { frame_count } " )
150+ if max_frame_count is not None and frame_count > max_frame_count :
151+ raise ValueError (f"Video frame count must be at most { max_frame_count } , got { frame_count } " )
152+
153+
139154def get_number_of_images (images ):
140155 if isinstance (images , torch .Tensor ):
141156 return images .shape [0 ] if images .ndim >= 4 else 1
@@ -144,8 +159,8 @@ def get_number_of_images(images):
144159
145160def validate_audio_duration (
146161 audio : Input .Audio ,
147- min_duration : Optional [ float ] = None ,
148- max_duration : Optional [ float ] = None ,
162+ min_duration : float | None = None ,
163+ max_duration : float | None = None ,
149164) -> None :
150165 sr = int (audio ["sample_rate" ])
151166 dur = int (audio ["waveform" ].shape [- 1 ]) / sr
@@ -177,7 +192,7 @@ def validate_string(
177192 )
178193
179194
180- def validate_container_format_is_mp4 (video : VideoInput ) -> None :
195+ def validate_container_format_is_mp4 (video : Input . Video ) -> None :
181196 """Validates video container format is MP4."""
182197 container_format = video .get_container_format ()
183198 if container_format not in ["mp4" , "mov,mp4,m4a,3gp,3g2,mj2" ]:
@@ -194,8 +209,8 @@ def _ratio_from_tuple(r: tuple[float, float]) -> float:
194209def _assert_ratio_bounds (
195210 ar : float ,
196211 * ,
197- min_ratio : Optional [ tuple [float , float ]] = None ,
198- max_ratio : Optional [ tuple [float , float ]] = None ,
212+ min_ratio : tuple [float , float ] | None = None ,
213+ max_ratio : tuple [float , float ] | None = None ,
199214 strict : bool = True ,
200215) -> None :
201216 """Validate a numeric aspect ratio against optional min/max ratio bounds."""
0 commit comments